From ecf90ff382344b706a123a5db417869a5084d9d6 Mon Sep 17 00:00:00 2001 From: Hypatia May Date: Wed, 15 Jul 2026 10:51:38 +0800 Subject: [PATCH 001/368] feat(session-query): add SQLite full-text search --- docs/architecture.md | 1 + docs/capability-seams.md | 13 +- docs/config-catalog.md | 25 + docs/cordis-catalog/services.md | 16 +- docs/core-data-structures/core.md | 2 +- docs/core-data-structures/session-query.md | 82 +- docs/module-graph.md | 5 + docs/rfc/INDEX.md | 2 +- .../2026-07-10-session-query-service.md | 12 +- ...026-07-10-sqlite-session-query-provider.md | 57 ++ ...026-07-10-sqlite-session-query-provider.md | 51 -- packages/README.md | 2 +- .../cordis/tool-cordis/src/api-catalog.ts | 57 ++ packages/session-query/README.md | 7 +- .../session-query-sqlite/README.md | 35 + .../session-query-sqlite/package.json | 46 ++ .../session-query-sqlite/src/index.ts | 765 ++++++++++++++++++ .../session-query-sqlite/src/query.ts | 312 +++++++ .../session-query-sqlite/src/schema.ts | 127 +++ .../tests/load-path.e2e.ts | 60 ++ .../session-query-sqlite/tests/query.spec.ts | 179 ++++ .../session-query-sqlite/tests/sqlite.spec.ts | 594 ++++++++++++++ .../session-query-sqlite/tsconfig.json | 30 + .../session-query/session-query/README.md | 19 +- .../session-query/session-query/src/config.ts | 11 +- .../session-query/session-query/src/corpus.ts | 21 +- .../session-query/src/documents.ts | 74 ++ .../session-query/src/extraction.ts | 93 +++ .../session-query/src/filters.ts | 132 +++ .../session-query/session-query/src/index.ts | 92 ++- .../session-query/src/sources.ts | 25 + .../session-query/session-query/src/types.ts | 96 +++ .../tests/search-helpers.spec.ts | 209 +++++ pnpm-lock.yaml | 25 + scripts/gen-doc-graphs.ts | 14 +- scripts/type-equiv.manifest.json | 8 + tsconfig.build.json | 1 + tsconfig.json | 1 + 38 files changed, 3181 insertions(+), 120 deletions(-) create mode 100644 docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md delete mode 100644 docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md create mode 100644 packages/session-query/session-query-sqlite/README.md create mode 100644 packages/session-query/session-query-sqlite/package.json create mode 100644 packages/session-query/session-query-sqlite/src/index.ts create mode 100644 packages/session-query/session-query-sqlite/src/query.ts create mode 100644 packages/session-query/session-query-sqlite/src/schema.ts create mode 100644 packages/session-query/session-query-sqlite/tests/load-path.e2e.ts create mode 100644 packages/session-query/session-query-sqlite/tests/query.spec.ts create mode 100644 packages/session-query/session-query-sqlite/tests/sqlite.spec.ts create mode 100644 packages/session-query/session-query-sqlite/tsconfig.json create mode 100644 packages/session-query/session-query/src/documents.ts create mode 100644 packages/session-query/session-query/src/extraction.ts create mode 100644 packages/session-query/session-query/src/filters.ts create mode 100644 packages/session-query/session-query/src/sources.ts create mode 100644 packages/session-query/session-query/tests/search-helpers.spec.ts diff --git a/docs/architecture.md b/docs/architecture.md index 8dc7f6f4b1..e7b6f25ac3 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -35,6 +35,7 @@ A harness is one [Cordis](cordis-primer.md) context. Packages contribute service | `ctx.workflows` | [`workflow/`](../packages/workflow/README.md) | script-driven multi-agent orchestration | | `ctx.sessionPersistence` | [`session-persistence/`](../packages/session-persistence/README.md) | durable storage for session logs | | `ctx.sessionQuery` | [`session-query/`](../packages/session-query/README.md) | live-preferred logical-corpus and exact-event reads | +| `ctx.sessionSearch` | [`session-query/`](../packages/session-query/README.md) | SQLite full-text search | ## Event diff --git a/docs/capability-seams.md b/docs/capability-seams.md index 13af1cde1c..189b910149 100644 --- a/docs/capability-seams.md +++ b/docs/capability-seams.md @@ -19,6 +19,7 @@ flowchart LR pkg_agent["agent"] pkg_session_persistence["session-persistence"] pkg_session_query["session-query"] + pkg_session_query_sqlite["session-query-sqlite"] pkg_subagent_inprocess["subagent-inprocess"] pkg_invariants["invariants"] svc_sessionPersistence["ctx.sessionPersistence
Durable session persistence seam"] @@ -26,6 +27,7 @@ flowchart LR pkg_session_persistence_sqlite["session-persistence-sqlite"] pkg_acp["acp"] svc_sessionQuery["ctx.sessionQuery
Exact session-history reads"] + svc_sessionSearch["ctx.sessionSearch
Full-text session search"] pkg_system_prompt["system-prompt"] svc_systemPrompt["ctx.systemPrompt
System prompt assembly registry"] pkg_tools["tools"] @@ -108,6 +110,8 @@ flowchart LR pkg_session_persistence_jsonl --> svc_sessionPersistence pkg_session_persistence_sqlite --> svc_sessionPersistence pkg_session_query --> svc_sessionQuery + pkg_session_query --> svc_sessionSearch + pkg_session_query_sqlite --> svc_sessionSearch pkg_skill --> svc_skills pkg_skill_local --> svc_skills pkg_stdio_agent --> svc_userInteraction @@ -146,11 +150,13 @@ flowchart LR svc_sessionPersistence --> pkg_acp svc_sessionPersistence --> pkg_agent_loop svc_sessionPersistence --> pkg_session_query + svc_sessionPersistence --> pkg_session_query_sqlite svc_sessions --> pkg_agent svc_sessions --> pkg_agent_loop svc_sessions --> pkg_invariants svc_sessions --> pkg_session_persistence svc_sessions --> pkg_session_query + svc_sessions --> pkg_session_query_sqlite svc_sessions --> pkg_subagent_inprocess svc_skills --> pkg_tool_skill svc_subagents --> pkg_tool_subagent @@ -179,9 +185,10 @@ flowchart LR | ctx key | Role | Owner | Implementations | Direct consumers | Companion plugins | Note | | --- | --- | --- | --- | --- | --- | --- | | `ctx.llm` | `seam` | [`llm`](../packages/llm/llm) | [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`llm-replay`](../packages/support/llm-replay) | [`agent-loop`](../packages/core/agent-loop), [`compact-basic`](../packages/compact/compact-basic) | - | Adapters register provider implementations; the loop and compaction call the provider-neutral stream service. | -| `ctx.sessions` | `core` | [`session`](../packages/core/session) | - | [`agent-loop`](../packages/core/agent-loop), [`agent`](../packages/core/agent), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-query`](../packages/session-query/session-query), [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`invariants`](../packages/support/invariants) | - | Owns append-only Session instances and emits the durable session event feed. | -| `ctx.sessionPersistence` | `seam` | [`session-persistence`](../packages/session-persistence/session-persistence) | [`session-persistence-jsonl`](../packages/session-persistence/session-persistence-jsonl), [`session-persistence-sqlite`](../packages/session-persistence/session-persistence-sqlite) | [`agent-loop`](../packages/core/agent-loop), [`acp`](../packages/ui/acp), [`session-query`](../packages/session-query/session-query) | - | Backends persist the same SessionEvent vocabulary; apps choose a backend at composition time. | -| `ctx.sessionQuery` | `seam` | [`session-query`](../packages/session-query/session-query) | - | - | - | Resolves live and optional persisted logs into one logical corpus for exact reads. | +| `ctx.sessions` | `core` | [`session`](../packages/core/session) | - | [`agent-loop`](../packages/core/agent-loop), [`agent`](../packages/core/agent), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite), [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`invariants`](../packages/support/invariants) | - | Owns append-only Session instances and emits the durable session event feed. | +| `ctx.sessionPersistence` | `seam` | [`session-persistence`](../packages/session-persistence/session-persistence) | [`session-persistence-jsonl`](../packages/session-persistence/session-persistence-jsonl), [`session-persistence-sqlite`](../packages/session-persistence/session-persistence-sqlite) | [`agent-loop`](../packages/core/agent-loop), [`acp`](../packages/ui/acp), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | - | Backends persist the same SessionEvent vocabulary; apps choose a backend at composition time. | +| `ctx.sessionQuery` | `seam` | [`session-query`](../packages/session-query/session-query) | - | - | - | Resolves live and optional persisted logs into one logical corpus for exact reads and semantic scans. | +| `ctx.sessionSearch` | `seam` | [`session-query`](../packages/session-query/session-query) | [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | - | - | The concrete backend owns source reconciliation, ranking, snippets, and cursor generations as one lifecycle. | | `ctx.systemPrompt` | `core` | [`system-prompt`](../packages/core/system-prompt) | - | [`agent-loop`](../packages/core/agent-loop), [`tools`](../packages/core/tools), [`tool-fs`](../packages/fs/tool-fs), [`tool-web`](../packages/web/tool-web) | - | Collects prompt sections and model-facing tool schemas for each step. | | `ctx.tools` | `core` | [`tools`](../packages/core/tools) | - | [`agent-loop`](../packages/core/agent-loop), [`tool-ask-user`](../packages/ui/tool-ask-user), [`tool-bash`](../packages/bash/tool-bash), [`tool-cordis`](../packages/cordis/tool-cordis), [`tool-fs`](../packages/fs/tool-fs), [`tool-skill`](../packages/skill/tool-skill), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-todo`](../packages/todo/tool-todo), [`tool-web`](../packages/web/tool-web), [`acp`](../packages/ui/acp) | - | Registers capabilities, owns Code Mode transport, and routes calls through pre-policy, monotonic guards, around dispatch, post-policy, and final-result observation. | | `ctx.userInteraction` | `seam` | [`user-interaction`](../packages/ui/user-interaction) | [`stdio-agent`](../packages/ui/stdio-agent), [`acp`](../packages/ui/acp) | [`tool-ask-user`](../packages/ui/tool-ask-user), [`stdio-agent`](../packages/ui/stdio-agent), [`acp`](../packages/ui/acp) | - | UI front doors provide the active human-answer provider; tool-ask-user pauses a tool call on the provider-neutral ask() promise. | diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 24aee5adc2..3a802231d7 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -590,6 +590,31 @@ export interface Config { Source: [`packages/session-query/session-query/src/config.ts:9`](../packages/session-query/session-query/src/config.ts) +## `@deepseek-ai/dsh-session-query-sqlite` + +Requires: `sessions` + +```ts config-catalog +/** SQLite session-search configuration. */ +export interface Config { + /** Dedicated derived-index path; `:memory:` is supported for tests. */ + path: string + /** SQLite journal mode. Defaults to `wal`. */ + journalMode?: JournalMode + /** Page size when a request omits `limit`. Defaults to 20. */ + defaultLimit?: number + /** Largest accepted page size. Defaults to 100. */ + maxLimit?: number + /** Maximum snippet length in Unicode code points. Defaults to 240. */ + snippetChars?: number +} + +/** Supported SQLite journal modes. */ +export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' +``` + +Source: [`packages/session-query/session-query-sqlite/src/index.ts:58`](../packages/session-query/session-query-sqlite/src/index.ts) + ## `@deepseek-ai/dsh-skill` ```ts config-catalog diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 6f8508f5ee..fef691aae1 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -208,10 +208,11 @@ Live-preferred logical-corpus and exact-event read service. ```ts cordis-catalog listSessions(): Promise async listEvents(sessionId: SessionId): Promise +async filterEvents( sessionId: SessionId, filters: readonly SessionEventResultFilter[], ): Promise async readEvent(request: SessionEventReadRequest): Promise ``` -Source: [`packages/session-query/session-query/src/index.ts:35`](../../packages/session-query/session-query/src/index.ts) +Source: [`packages/session-query/session-query/src/index.ts:83`](../../packages/session-query/session-query/src/index.ts) ## `ctx.sessions` — `SessionStore` @@ -232,6 +233,19 @@ fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Source: [`packages/core/session/src/index.ts:590`](../../packages/core/session/src/index.ts) +## `ctx.sessionSearch` — `SessionSearchService` (abstract seam) + +Abstract full-text search service implemented by one concrete backend. + +The implementation owns source observation, reconciliation, cursor generations, ranking, and query execution as one lifecycle. + +```ts cordis-catalog +abstract searchSessions( request: SessionSearchRequest, exec?: SessionSearchExecContext, ): Promise> +abstract searchEvents( request: SessionEventSearchRequest, exec?: SessionSearchExecContext, ): Promise> +``` + +Source: [`packages/session-query/session-query/src/index.ts:54`](../../packages/session-query/session-query/src/index.ts) + ## `ctx.skills` — `SkillService` Registry of skill providers. It merges provider catalogs with stable first-wins duplicate handling, exposes sorted model-visible summaries, and loads full skill bodies on demand. diff --git a/docs/core-data-structures/core.md b/docs/core-data-structures/core.md index 5536526aec..e632b36f4d 100644 --- a/docs/core-data-structures/core.md +++ b/docs/core-data-structures/core.md @@ -19,7 +19,7 @@ Everything else is documented on a **sub-page**, not here. The rule that draws t | [scope.md](scope.md) | scoped registration identity, dispatch carriers, and the owned `Scope` context | | [session.md](session.md) | the full `SessionEventMap` variant catalog, `TurnTrigger`/`TurnEndReason`, `deriveMessages()`, the turn-enclosure invariant | | [persistence.md](persistence.md) | the durability seam: `SessionPersistence`, JSONL + SQLite backends, `session/flush`, crash recovery, `SessionHeader` | -| [session-query.md](session-query.md) | logical session/event records and bounded exact-event reads | +| [session-query.md](session-query.md) | logical records, semantic filters/documents, exact reads, and full-text result pages | | [system-prompt.md](system-prompt.md) | per-assembly context, tool-provider results, prompt sections, and cooperative assembly | | [tools.md](tools.md) | `ToolDefinition` full fields, the schema DSL, `ToolExecution`/`ToolResult`, tool-presentation UI types, and the guarded execution pipeline | | [user-interaction.md](user-interaction.md) | the UI-backed human question/answer seam: `AskUserQuestionRequest`, answer/options vocabulary, provider API, error taxonomy | diff --git a/docs/core-data-structures/session-query.md b/docs/core-data-structures/session-query.md index ded8ca3f7e..27ef9959de 100644 --- a/docs/core-data-structures/session-query.md +++ b/docs/core-data-structures/session-query.md @@ -1,6 +1,6 @@ # Session Query -Exact reads over the live-preferred logical session corpus. The [package contract](../../packages/session-query/session-query) owns source precedence, dynamic optional persistence, cloning, surface classification, bounded windows, and typed failures. Full-text search is a separate proposed SQLite phase. +Query vocabulary over the live-preferred logical session corpus. The [interface package](../../packages/session-query/session-query) owns exact reads, source precedence, semantic extraction and provider-independent filters, while the [SQLite package](../../packages/session-query/session-query-sqlite) owns the concrete full-text index lifecycle. Source: [`packages/session-query/session-query/src/types.ts`](../../packages/session-query/session-query/src/types.ts) @@ -30,6 +30,79 @@ export interface SessionEventRecord { } ``` +## Provider-independent filters and documents + +Session and event filter arrays are ANDed; values inside one list clause are ORed. Ranges are inclusive. The event `text` clause is a literal Unicode case-insensitive, whitespace-flexible regular-expression scan over extracted semantic text, independent of full-text providers. + +```ts type-equiv +export type SessionResultFilter = + | { kind: 'id'; values: readonly SessionId[] } + | { kind: 'cwd'; values: readonly (string | null)[] } + | ({ kind: 'created-at' } & SessionResultRange) + | { kind: 'parent'; values: readonly (SessionId | null)[] } + | { kind: 'availability'; values: readonly SessionAvailability[] } +``` + +```ts type-equiv +export type SessionEventResultFilter = + | ({ kind: 'seq' } & SessionResultRange) + | ({ kind: 'time' } & SessionResultRange) + | { kind: 'type'; values: readonly SessionEventType[] } + | { kind: 'surface'; values: readonly SessionEventSurface[] } + | { kind: 'text'; text: string } +``` + +```ts type-equiv +export interface SessionEventSearchDocument extends SessionEventRecord { + text: string +} +``` + +`ctx.sessionQuery.filterEvents(sessionId, filters)` returns these documents in ascending seq order. Messages, reasoning, tool calls/results, blocked prompts, todos, and failure/status detail contribute semantic text; structural events and stream chunks do not. + +## Full-text search pages + +The independent `ctx.sessionSearch` seam has two scopes. `searchSessions()` groups the corpus by strongest matching event; `searchEvents()` searches one session. Requests bind an opaque cursor to the normalized query, metadata filters, and limit. The event text scan is intentionally absent from provider metadata filters. + +```ts type-equiv +export interface SessionSearchRequest { + query: string + sessionFilters?: readonly SessionResultFilter[] + eventFilters?: readonly SessionEventMetadataFilter[] + limit?: number + cursor?: string +} +``` + +```ts type-equiv +export interface SessionEventSearchRequest { + sessionId: SessionId + query: string + filters?: readonly SessionEventMetadataFilter[] + limit?: number + cursor?: string +} +``` + +```ts type-equiv +export interface SessionSearchPage { + items: readonly T[] + nextCursor?: string +} +``` + +```ts type-equiv +export interface SessionEventSearchHit extends SessionEventRecord { + snippet: string +} +``` + +```ts type-equiv +export interface SessionSearchHit extends SessionRecord { + bestMatch: SessionEventSearchHit +} +``` + ## Bounded event reads The request addresses one raw seq and optional neighboring counts. The result carries a `SessionHeader` rather than availability flags so a known live target can remain independent of persistence health. @@ -59,11 +132,18 @@ The closed code union distinguishes request validation, missing targets, malform ```ts type-equiv export type SessionQueryErrorCode = + | 'SESSION_QUERY_ABORTED' | 'SESSION_QUERY_EVENT_NOT_FOUND' + | 'SESSION_QUERY_INDEX_FAILED' | 'SESSION_QUERY_INVALID_CONFIG' + | 'SESSION_QUERY_INVALID_CURSOR' + | 'SESSION_QUERY_INVALID_FILTER' + | 'SESSION_QUERY_INVALID_LIMIT' + | 'SESSION_QUERY_INVALID_QUERY' | 'SESSION_QUERY_INVALID_SURFACE' | 'SESSION_QUERY_INVALID_WINDOW' | 'SESSION_QUERY_PERSISTENCE_FAILED' | 'SESSION_QUERY_SESSION_NOT_FOUND' + | 'SESSION_QUERY_STALE_CURSOR' | 'SESSION_QUERY_SOURCE_CONFLICT' ``` diff --git a/docs/module-graph.md b/docs/module-graph.md index 8a1ad9239d..6fcec53dd4 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -84,6 +84,7 @@ flowchart TD end subgraph group_session_query["packages/session-query"] pkg_session_query["session-query"] + pkg_session_query_sqlite["session-query-sqlite"] end subgraph group_support["packages/support"] pkg_acp_snapshot["acp-snapshot"] @@ -195,6 +196,9 @@ flowchart TD pkg_bash_sandbox --> pkg_bash pkg_bash_sandbox --> pkg_bash_local pkg_bash_sandbox --> pkg_sandbox + pkg_session_query_sqlite --> pkg_session + pkg_session_query_sqlite --> pkg_session_persistence + pkg_session_query_sqlite --> pkg_session_query pkg_agent_loop --> pkg_agent pkg_agent_loop --> pkg_llm pkg_agent_loop --> pkg_scope @@ -372,6 +376,7 @@ flowchart TD | [`workflow`](../packages/workflow/workflow) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm) | | [`tools`](../packages/core/tools) | `core` | [`agent`](../packages/core/agent), [`code-runtime`](../packages/code-runtime/code-runtime), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`user-approval`](../packages/ui/user-approval) | | [`bash-sandbox`](../packages/bash/bash-sandbox) | `bash` | [`bash`](../packages/bash/bash), [`bash-local`](../packages/bash/bash-local), [`sandbox`](../packages/sandbox/sandbox) | +| [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-query`](../packages/session-query/session-query) | | [`agent-loop`](../packages/core/agent-loop) | `core` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) | | [`tool-bash`](../packages/bash/tool-bash) | `bash` | [`agent`](../packages/core/agent), [`bash`](../packages/bash/bash), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/ui/user-approval) | | [`tool-fs`](../packages/fs/tool-fs) | `fs` | [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) | diff --git a/docs/rfc/INDEX.md b/docs/rfc/INDEX.md index 54e59f7aa1..a3eb41b7b0 100644 --- a/docs/rfc/INDEX.md +++ b/docs/rfc/INDEX.md @@ -11,7 +11,6 @@ Generated by `pnpm run gen-rfc-index` from the RFC tree — never edit by hand; | [Pre-tool input rewrite — a consistent design](proposed/feature/2026-06-30-pre-tool-input-rewrite.md) | 2026-06-30 | | [Claude Code and Codex subagent backends (out-of-process delegation to external coding agents)](proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md) | 2026-07-07 | | [Interactive side sessions and merge-back](proposed/feature/2026-07-08-interactive-side-sessions.md) | 2026-07-08 | -| [SQLite FTS5 session search](proposed/feature/2026-07-10-sqlite-session-query-provider.md) | 2026-07-10 | | [Stream workflow progress through tool calls](proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md) | 2026-07-13 | ### Simplification @@ -77,6 +76,7 @@ Generated by `pnpm run gen-rfc-index` from the RFC tree — never edit by hand; | [Repeat-tool-call guard plugin](implemented/feature/2026-07-08-repeat-tool-guard.md) | 2026-07-08 | | [The self-referential cordis toolset](implemented/feature/2026-07-08-self-referential-cordis-toolset.md) | 2026-07-08 | | [Exact session query service](implemented/feature/2026-07-10-session-query-service.md) | 2026-07-10 | +| [SQLite FTS5 session search](implemented/feature/2026-07-10-sqlite-session-query-provider.md) | 2026-07-10 | | [Configure subagent persona, tool visibility, and depth](implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) | 2026-07-12 | ### Simplification diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.md b/docs/rfc/implemented/feature/2026-07-10-session-query-service.md index 7e13256669..be496311cc 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.md +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.md @@ -6,11 +6,11 @@ Status: implemented Session history exists in two places: current `SessionStore` objects and an optional persistence backend. Consumers that need exact inspection would otherwise duplicate live-versus-persisted precedence, persistence lifecycle handling, raw-event surface classification, and defensive cloning. Durable state can lag the live log between checkpoints, so persistence alone is not a truthful current source. -Full-text search is related but materially larger. Designing provider registration, extraction, synchronization, invalidation, ranking, and cursor contracts before a real backend exists creates two speculative state machines: one in the interface service and another in the eventual database package. +Full-text search is related but materially larger. Putting provider coordination, synchronization, invalidation, ranking, and cursor state into the exact-read service would create a second state machine beside the concrete database owner. ## Decision -`@deepseek-ai/dsh-session-query` owns `ctx.sessionQuery`, a small trusted exact-read service over one logical corpus. It exposes `listSessions()`, `listEvents(sessionId)`, and bounded `readEvent(request)`. It does not expose filters, lineage or provenance traversals, text extractors, search requests, provider registration, or derived-index synchronization. +`@deepseek-ai/dsh-session-query` owns `ctx.sessionQuery`, a small trusted exact-read service over one logical corpus. It exposes `listSessions()`, `listEvents(sessionId)`, provider-independent `filterEvents(sessionId, filters)`, and bounded `readEvent(request)`. The package also declares the separate abstract `ctx.sessionSearch` contract and shared semantic extraction used by the [SQLite search decision](2026-07-10-sqlite-session-query-provider.md), but `ctx.sessionQuery` does not coordinate providers or synchronize a derived index. The service observes the optional `ctx.sessionPersistence` binding dynamically but retains no persisted cache or invalidation listener. Each cross-corpus list asks the active backend for authoritative metadata, then overlays a fresh live-store list. Matching ids become one `SessionRecord`: the live header wins and `live`/`persisted` independently report source availability. Immutable header disagreement is `SESSION_QUERY_SOURCE_CONFLICT`. @@ -31,11 +31,11 @@ The service is context-wide trusted infrastructure, not an authorization layer. - **Put logical-corpus resolution directly in every consumer** — rejected because source precedence, conflicts, optional-service lifecycle, cloning, and surface classification are shared correctness rules. - **Query only persistence** — rejected because checkpoints can lag the current live log. - **Cache persisted metadata and listen for writes/removals** — rejected because exact reads can ask the authoritative sources directly, while cache invalidation adds lifecycle and concurrency state before scale requires it. -- **Define a provider-neutral search protocol now** — rejected because no provider consumes it. The first SQLite FTS package should own one reconciliation/transaction state machine; a smaller shared seam can be extracted later only when a second implementation proves the boundary. -- **Include lineage, provenance, and generic filters in phase one** — rejected because no current consumer requires them and canonical logs remain sufficient to add them with evidence later. +- **Put provider registration into the exact-read service** — rejected because the SQLite package owns one reconciliation/transaction lifecycle; a registry would split that state without a second provider to justify it. +- **Include lineage and provenance traversal** — rejected because canonical logs remain sufficient to add those higher-level views when a concrete consumer requires them. ## Consequences -Phase one has one source-resolution state variable: the currently mounted persistence service. There are no provider queues, fingerprints, extractor registries, observation generations, or derived index updates. Exact reads remain usable in live-only deployments and deterministic when persistence is present. +Exact reads have one source-resolution state variable: the currently mounted persistence service. There are no provider queues, fingerprints, extractor registries, observation generations, or derived index updates in `ctx.sessionQuery`. Exact reads and semantic scans remain usable in live-only deployments and deterministic when persistence is present. -Cross-corpus listing and persisted exact reads perform backend I/O on each call. That is deliberate: correctness comes from current authoritative state, and scale-oriented search belongs to the phase-two database. Full-text search is unavailable until that package defines and implements its complete contract. +Cross-corpus listing and persisted exact reads perform backend I/O on each call. That is deliberate: correctness comes from current authoritative state, while scale-oriented full-text search uses the separately owned SQLite derived index. diff --git a/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md b/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md new file mode 100644 index 0000000000..d620ece108 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md @@ -0,0 +1,57 @@ +# RFC: SQLite FTS5 session search + +Status: implemented + +## Problem + +The exact-read `ctx.sessionQuery` service deliberately has no derived index. Large persisted histories need full-text search without scanning every event on every query, while current live sessions need an overlay newer than the last durability checkpoint. Search also needs concrete ranking, snippets, filters, pagination, cancellation, and rebuild behavior. + +Splitting those concerns across a provider coordinator and a database implementation would create two coupled reconciliation state machines. The first implementation needs to own source observation, extraction, SQLite transactions, generations, and query execution as one lifecycle while still exposing a small provider-neutral call contract. + +## Decision + +`@deepseek-ai/dsh-session-query` declares an independent abstract `ctx.sessionSearch` service without changing the exact-read `ctx.sessionQuery` key. `searchSessions(request, exec?)` returns cursor-paginated `SessionSearchHit`s grouped by each session's strongest matching event; `searchEvents(request, exec?)` returns `SessionEventSearchHit`s within one logical session. Both requests require `query`, accept `limit` and an opaque `cursor`, and support an optional abort signal. Session search accepts `sessionFilters` plus event metadata filters; event search accepts event metadata filters. Results expose bounded plain-text snippets but no provider identifier or numeric relevance score. + +`@deepseek-ai/dsh-session-query-sqlite` is the sole concrete owner of `ctx.sessionSearch`. It depends on live `ctx.sessions`, observes optional `ctx.sessionPersistence` dynamically, and owns a dedicated derived SQLite database. There is no search-provider registry, coordinator, persistence event, or agent-loop integration. + +The interface package also owns shared first-party semantic extraction and provider-independent filtering. `SessionResultFilter` covers id, nullable cwd, created-at range, nullable parent, and availability. `SessionEventResultFilter` covers seq/time ranges, event type, surface, and literal semantic text. Arrays are ANDed and list values are ORed. The text clause escapes caller input into a Unicode case-insensitive regular expression whose whitespace runs match one or more whitespace characters; it is available through `ctx.sessionQuery.filterEvents()` and is not delegated to an FTS provider. + +## Search semantics + +Each semantic event is one FTS document carrying session metadata, event metadata, surface classification, and extracted text. All `current`, `shadowed`, and `log-only` documents participate unless a surface filter narrows them. Metadata filters compile to parameterized SQL before ranking. Session results partition matching documents by session and retain the strongest one. + +Ordering is deterministic: BM25 ascending, event time descending, session id ascending for the cross-session scope, and seq descending. Provider scores remain private. Snippets normalize whitespace and are bounded by Unicode code points. Opaque cursors bind to the service instance, scope, canonical normalized request, offset, and relevant generation. Any corpus change invalidates cross-session cursors; a within-session cursor changes only when its target source/generation changes, so unrelated sessions do not invalidate it. Reopening creates a new service instance and invalidates old cursors. + +Queries are trimmed, whitespace-normalized, and quoted as one literal FTS5 phrase. Embedded quotes are doubled before binding, so MATCH operators such as `OR`, `NEAR`, quotes, parentheses, and `*` remain data rather than executable query syntax. Phrase matching follows tokenizer tokens rather than arbitrary substrings. + +## Tokenizer choice + +Both persistent and live FTS5 tables use `unicode61`. The implementation experiment found that this tokenizer supports the two-character token `AI` and produces an index about 2.1× smaller than the trigram alternative. The accepted limitation is token/phrase recall: `AI` does not match the larger token `BRAID`, and arbitrary substring search uses the provider-independent text scan instead. + +## Extraction and reconciliation + +The shared extractor includes message text, reasoning, nested tool-call/result content, tool names and arguments, blocked-prompt reasons, todo status/content, and error or terminal status detail. Structural boundaries, stream chunks, request headers, successful completion markers, and unknown declaration-merged event/content variants produce no document. Surface classification reuses `foldSurface()` so search agrees with model-history derivation. + +One serialized operation observes complete persisted and live sources, computes stable fingerprints, reconciles rows in one transaction, and executes the query. Unchanged persisted sessions retain their rows and generation. New, changed, and deleted persisted sessions update on the next search. A source or extraction failure cannot mark a row current, and a transaction failure rolls back so a later search retries. + +Persisted documents survive restarts. Live sessions use connection-local TEMP tables, shadow the persisted base for the same id, and reveal that base on detach. Closing the database drops live rows. Unmounting persistence hides durable rows without treating absence as authoritative deletion; remounting observes and reconciles the backend again. Conflicting immutable live and durable headers fail rather than combining sources. + +The derived schema has its own application id and monotonic schema version. A recognized incompatible version resets only this derived database. A database with a foreign application id or unrecognized user tables is refused, which prevents an accidentally configured canonical session database from being reset. + +Cancellation rejects queued operations and caller waits around asynchronous source observation without committing an aborted observation. Node's synchronous `DatabaseSync` MATCH call cannot be interrupted once it is executing on the JavaScript thread, so the service checks the signal at serialized boundaries but does not promise mid-statement preemption. + +## Alternatives considered + +- **Add FTS tables to the canonical persistence database** — rejected because a rebuildable index must not share the authoritative log's schema, reset, or failure boundary. +- **Add a phase-one provider registry and coordinator** — rejected because one implementation provides no evidence for registration semantics and would split one reconciliation lifecycle across two owners. +- **Persist live overrides immediately** — rejected because live events are not canonical until the existing checkpoint commits. +- **Use the FTS5 trigram tokenizer** — rejected because it omits useful queries shorter than three characters and measured about 2.1× the index size of `unicode61`; literal substring filtering remains available through the scan path. +- **Return BM25 scores** — rejected because provider-specific numeric scales are unstable across corpus changes. + +## Consequences + +Search has a small provider-neutral API while its only backend owns every derived-index state transition. The separate database adds configuration and a reconciliation read before queries, but index corruption, reset, and tokenizer changes cannot endanger canonical logs. Persistent fingerprints avoid rewriting unchanged sessions; TEMP live overlays preserve current-session truth without making uncheckpointed events durable. + +The chosen tokenizer supports short tokens with a smaller index but does not promise substring recall. Literal phrases make query syntax safe and predictable at the cost of excluding boolean/full MATCH expressions. Cancellation is effective while queued or awaiting sources, but synchronous SQLite execution remains a non-preemptible section. + +Unit coverage pins extraction, filters, both search scopes, all default surfaces, metadata-before-ranking, snippets, literal escaping, deterministic ties, complete pagination, scoped cursor invalidation, dynamic persistence mount/unmount, restart reconciliation, live shadow/reveal/reopen, schema safety, rollback retry, and queued/in-flight source-wait cancellation. A keyless real-Loader-path test combines the package with the real SQLite persistence backend. diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md deleted file mode 100644 index acfdf23bee..0000000000 --- a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md +++ /dev/null @@ -1,51 +0,0 @@ -# RFC: SQLite FTS5 session search - -Status: proposed - -## Problem - -The exact-read `ctx.sessionQuery` service deliberately has no derived index. Large persisted histories need full-text search without scanning every event on every query, while current live sessions need an overlay newer than the last durability checkpoint. Search also needs concrete ranking, snippets, filters, pagination, cancellation, and rebuild behavior. - -Splitting those concerns across a speculative provider coordinator and a database implementation would create two coupled reconciliation state machines. The first real implementation should own the source observation, extraction, SQLite transaction, generation, and query as one lifecycle. - -## Proposal - -Add `@deepseek-ai/dsh-session-query-sqlite` beside the exact-read package. The package will expose a search service or extend the family with the smallest API required by its actual consumers; phase one does not pre-commit a provider-registration protocol. It will depend on `ctx.sessions` and optional `ctx.sessionPersistence`, own a separate derived SQLite database, and reuse the canonical `foldSurface()` classification. - -The implementation owns one serialized reconciliation/DB transaction state machine. A transaction observes authoritative persisted metadata and live snapshots, extracts semantic documents, updates derived tables, advances relevant cursor generations, and executes or enables the corresponding query. No second service maintains parallel fingerprints, dirty flags, live-id sets, or invalidation generations. - -Persisted documents survive restarts. Live overrides are connection-local and shadow the persisted rows for the same session, then disappear when the live owner or database closes. The derived database remains separate from canonical persistence so index reset, corruption, tokenizer changes, and schema churn cannot endanger durable conversation logs. - -## Search semantics to decide with implementation - -The implementation must define both cross-session and within-session scopes from executable use cases. Each searchable event is one document with session metadata, event metadata, surface classification, normalized semantic text, and a bounded plain-text snippet. Session results group by their strongest matching event; numeric backend scores remain private. - -Filters compile to parameterized SQL before ranking. Query syntax is treated as data. Ordering includes stable tie fields. Opaque cursors bind to normalized request shape and the smallest relevant generation; unrelated session changes should not invalidate a within-session cursor. Cancellation must stop caller waiting and interrupt SQLite work where the runtime permits. - -Tokenizer choice remains an implementation experiment. FTS5 trigram supports substring recall but rejects useful terms shorter than three characters and increases index size; the proposal must benchmark that tradeoff against the default Unicode tokenizer before making it contract. - -## Extraction and reconciliation - -The package starts with first-party semantic extraction for messages, reasoning, tool calls/results, blocked prompts, context, steering, todos, and error/status detail. Structural events and stream chunks contribute no document. Unknown declaration-merged event/content types remain non-searchable unless a real extension consumer demonstrates the need for a public extractor registry. - -Reconciliation may use stable fingerprints to avoid rewriting unchanged persisted sessions, but the database package owns their calculation and storage. It must never report a row current when source observation or extraction failed. Provider-schema mismatch may reset only the derived database; ordinary source changes use transactional upsert/delete. Mounted but unreadable persistence fails affected searches without affecting canonical writes or known live exact reads. - -## Alternatives considered - -- **Add FTS tables to the canonical persistence database** — rejected because a rebuildable index must not share the authoritative log's schema/reset/failure boundary. -- **Reintroduce phase-one provider coordination** — rejected because there is one planned implementation and no evidence for a stable multi-provider seam. -- **Persist live overrides immediately** — rejected because live events are not canonical until the existing checkpoint commits. -- **Return BM25 scores** — rejected because provider-specific numeric scales are unstable across corpus changes. - -## Acceptance criteria - -- Restart tests cover unchanged, new, changed, and deleted persisted sessions without rebuilding the whole index. -- Reopening preserves persisted rows and removes live rows; live rows shadow and then reveal their persisted base. -- Tests cover both search scopes, metadata filters, surface defaults, snippets, escaping, deterministic ties, pagination, scoped stale cursors, cancellation, dynamic persistence mount/unmount, and recovery after a failed transaction. -- A schema mismatch resets only the derived database. -- A keyless end-to-end test combines a real persistence backend with the real SQLite search package. -- The RFC is amended to the measured tokenizer and public API actually implemented before moving to `implemented/`. - -## Risks - -A single owner is simpler but initially less reusable than a provider-neutral seam. That is intentional: a second real backend can reveal what to extract. SQLite runtime differences can affect FTS ranking and snippets, so tests must pin only contract-controlled ordering and presentation. The separate database adds configuration and lifecycle work, but preserves the canonical store's safety boundary. diff --git a/packages/README.md b/packages/README.md index d3dd6818df..f494b12222 100644 --- a/packages/README.md +++ b/packages/README.md @@ -25,7 +25,7 @@ Packages are grouped by modular role at `packages///`. The group dir | [`cordis/`](cordis/README.md) | Self-referential runtime toolset: inspect the live runtime's plugins and services, mount/unmount model-written plugins ([design](../docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md)) | Product — stable surface | | [`hooks/`](hooks/README.md) | Hook bridges + the shared Claude Code / Codex wire-protocol library | Product — stable surface | | [`session-persistence/`](session-persistence/README.md) | Persistence capability family: the seam + JSONL/SQLite backends | Product — stable surface | -| [`session-query/`](session-query/README.md) | Session retrieval family: logical corpus, surface records, and bounded exact reads | Product — stable surface | +| [`session-query/`](session-query/README.md) | Session retrieval family: exact reads, semantic filtering, and SQLite full-text search | Product — stable surface | | [`ui/`](ui/README.md) | Editor/client integration surfaces: ACP bridge, JSON-RPC SDK server, app packages, user-approval and user-interaction seams, ask-user tool | Product — stable surface | | [`support/`](support/README.md) | Dev/test/example infrastructure (invariants, replay adapter, subagent mock) | Support — lower compatibility expectations | | [`util/`](util/README.md) | Low-level zero-dependency utilities shared across groups (the `Branded` primitive) | Support — small, stable, harness-dep-free | diff --git a/packages/cordis/tool-cordis/src/api-catalog.ts b/packages/cordis/tool-cordis/src/api-catalog.ts index 06bf895e96..2859353cfa 100644 --- a/packages/cordis/tool-cordis/src/api-catalog.ts +++ b/packages/cordis/tool-cordis/src/api-catalog.ts @@ -157,6 +157,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ methods: [ 'listSessions(): Promise', 'async listEvents(sessionId: SessionId): Promise', + 'async filterEvents( sessionId: SessionId, filters: readonly SessionEventResultFilter[], ): Promise', 'async readEvent(request: SessionEventReadRequest): Promise', ], }, @@ -174,6 +175,14 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ 'fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Session', ], }, + { + key: 'sessionSearch', + summary: 'Abstract full-text search service implemented by one concrete backend.', + methods: [ + 'abstract searchSessions( request: SessionSearchRequest, exec?: SessionSearchExecContext, ): Promise>', + 'abstract searchEvents( request: SessionEventSearchRequest, exec?: SessionSearchExecContext, ): Promise>', + ], + }, { key: 'skills', summary: 'Registry of skill providers.', @@ -787,6 +796,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'SendOptions', declaration: 'export interface SendOptions {\n source?: MessageSource;\n}', }, + { + name: 'SessionAvailability', + declaration: 'export type SessionAvailability = \'live\' | \'persisted\';', + }, { name: 'SessionEvent', declaration: 'export type SessionEvent = {\n [K in SessionEventType]: {\n type: K;\n seq: number;\n time: number;\n data: SessionEventMap[K];\n } & (K extends SurfaceEventType ? {\n sourceEventSeqs?: number[];\n surfaceOp?: SurfaceOp;\n } : object);\n}[T];', @@ -795,6 +808,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'SessionEventMap', declaration: 'export interface SessionEventMap {\n \'turn/start\': {\n turn: number;\n trigger: TurnTrigger;\n };\n \'turn/end\': {\n turn: number;\n reason: TurnEndReason;\n };\n \'step/start\': {\n turn: number;\n step: number;\n };\n \'step/end\': {\n turn: number;\n step: number;\n };\n \'user/message\': {\n content: ContentBlock[];\n source: MessageSource;\n };\n \'prompt/blocked\': {\n content: ContentBlock[];\n source: MessageSource;\n reason: string;\n };\n \'context/message\': {\n content: ContentBlock[];\n source: MessageSource;\n };\n \'assistant/chunk\': {\n turn: number;\n step: number;\n chunk: StreamChunk;\n };\n \'assistant/message\': {\n turn: number;\n step: number;\n content: ContentBlock[];\n usage?: TokenUsage;\n };\n \'tool/call\': {\n turn: number;\n step: number;\n callId: CallId;\n name: string;\n arguments: string;\n };\n \'tool/result\': {\n turn: number;\n step: number;\n callId: CallId;\n content: ContentBlock[];\n isError: boolean;\n error?: {\n name: string;\n code: string;\n };\n meta?: unknown;\n };\n \'steering/message\': {\n turn: number;\n content: ContentBlock[];\n source: MessageSource;\n };\n \'todo/write\': {\n todos: TodoItem[];\n };\n \'request/header\': {\n header: E /* …truncated — full shape in source */', }, + { + name: 'SessionEventMetadataFilter', + declaration: 'export type SessionEventMetadataFilter = Exclude;', + }, { name: 'SessionEventReadRequest', declaration: 'export interface SessionEventReadRequest {\n sessionId: SessionId;\n seq: number;\n before?: number;\n after?: number;\n}', @@ -803,6 +820,22 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'SessionEventRecord', declaration: 'export interface SessionEventRecord {\n sessionId: SessionId;\n seq: number;\n type: SessionEventType;\n time: number;\n surface: SessionEventSurface;\n}', }, + { + name: 'SessionEventResultFilter', + declaration: 'export type SessionEventResultFilter = ({\n kind: \'seq\';\n} & SessionResultRange) | ({\n kind: \'time\';\n} & SessionResultRange) | {\n kind: \'type\';\n values: readonly SessionEventType[];\n} | {\n kind: \'surface\';\n values: readonly SessionEventSurface[];\n} | {\n kind: \'text\';\n text: string;\n};', + }, + { + name: 'SessionEventSearchDocument', + declaration: 'export interface SessionEventSearchDocument extends SessionEventRecord {\n text: string;\n}', + }, + { + name: 'SessionEventSearchHit', + declaration: 'export interface SessionEventSearchHit extends SessionEventRecord {\n snippet: string;\n}', + }, + { + name: 'SessionEventSearchRequest', + declaration: 'export interface SessionEventSearchRequest {\n sessionId: SessionId;\n query: string;\n filters?: readonly SessionEventMetadataFilter[];\n limit?: number;\n cursor?: string;\n}', + }, { name: 'SessionEventSurface', declaration: 'export type SessionEventSurface = \'current\' | \'shadowed\' | \'log-only\';', @@ -831,6 +864,30 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'SessionRecord', declaration: 'export interface SessionRecord {\n header: SessionHeader;\n live: boolean;\n persisted: boolean;\n}', }, + { + name: 'SessionResultFilter', + declaration: 'export type SessionResultFilter = {\n kind: \'id\';\n values: readonly SessionId[];\n} | {\n kind: \'cwd\';\n values: readonly (string | null)[];\n} | ({\n kind: \'created-at\';\n} & SessionResultRange) | {\n kind: \'parent\';\n values: readonly (SessionId | null)[];\n} | {\n kind: \'availability\';\n values: readonly SessionAvailability[];\n};', + }, + { + name: 'SessionResultRange', + declaration: 'export interface SessionResultRange {\n from?: number;\n to?: number;\n}', + }, + { + name: 'SessionSearchExecContext', + declaration: 'export interface SessionSearchExecContext {\n signal?: AbortSignal;\n}', + }, + { + name: 'SessionSearchHit', + declaration: 'export interface SessionSearchHit extends SessionRecord {\n bestMatch: SessionEventSearchHit;\n}', + }, + { + name: 'SessionSearchPage', + declaration: 'export interface SessionSearchPage {\n items: readonly T[];\n nextCursor?: string;\n}', + }, + { + name: 'SessionSearchRequest', + declaration: 'export interface SessionSearchRequest {\n query: string;\n sessionFilters?: readonly SessionResultFilter[];\n eventFilters?: readonly SessionEventMetadataFilter[];\n limit?: number;\n cursor?: string;\n}', + }, { name: 'SkillCandidate', declaration: 'export interface SkillCandidate extends SkillSummary {\n readonly rank: number;\n readonly locator: unknown;\n readonly path?: string;\n readonly metadata?: Readonly>;\n}', diff --git a/packages/session-query/README.md b/packages/session-query/README.md index 8b0c06a30c..0622858294 100644 --- a/packages/session-query/README.md +++ b/packages/session-query/README.md @@ -1,9 +1,10 @@ # session-query/ — session retrieval capability family -Trusted exact reads over live and durable session logs. Phase one contains one interface package that owns `ctx.sessionQuery`, logical-corpus precedence, surface classification, and bounded event reads. +Trusted exact reads, provider-independent semantic filtering, and SQLite full-text search over live and durable session logs. | Package | Role | ctx key | |---|---|---| -| [`session-query/`](session-query/README.md) | Logical-corpus and exact-event read service | `ctx.sessionQuery` | +| [`session-query/`](session-query/README.md) | Logical-corpus reads, semantic extraction/filtering, and the abstract search seam | `ctx.sessionQuery`, `ctx.sessionSearch` | +| [`session-query-sqlite/`](session-query-sqlite/README.md) | SQLite FTS5 search with persistent bases and live overlays | `ctx.sessionSearch` | -The family is independent of compaction: it reads the canonical session log but does not participate in compaction policy or execution. Full-text search remains proposed as a phase-two SQLite package rather than a speculative provider seam in this interface package. +The family is independent of compaction: it reads the canonical session log but does not participate in compaction policy or execution. Search uses one abstract service and one concrete owner, not a provider registry or coordinator. diff --git a/packages/session-query/session-query-sqlite/README.md b/packages/session-query/session-query-sqlite/README.md new file mode 100644 index 0000000000..1f3344887f --- /dev/null +++ b/packages/session-query/session-query-sqlite/README.md @@ -0,0 +1,35 @@ +# @deepseek-ai/dsh-session-query-sqlite + +SQLite FTS5 implementation of `ctx.sessionSearch`. The service searches the live-preferred logical session corpus, groups cross-session results by their strongest event, and keeps provider-specific BM25 scores private. + +## Search contract + +`searchSessions(request, exec?)` returns `SessionSearchHit` pages across the corpus; `searchEvents(request, exec?)` returns `SessionEventSearchHit` pages within one session. Queries are required, trimmed, whitespace-normalized literal phrases. FTS5 syntax such as quotes, `OR`, `NEAR`, and `*` is treated as data rather than executable MATCH syntax. Metadata filters are parameterized SQL predicates applied before ranking. + +Ordering is deterministic: relevance first, then event time, session id where applicable, and seq. Cross-session results expose the selected event as `bestMatch`; both scopes return plain-text snippets bounded in Unicode code points. Cursors are opaque, bind to the normalized request and service instance, and fail when the relevant generation changes. A within-session cursor survives unrelated-session changes; a cross-session cursor does not. + +All three surfaces (`current`, `shadowed`, and `log-only`) are searchable by default. Pass a surface filter to narrow them. + +## Source and index lifecycle + +The service requires `ctx.sessions` and observes optional `ctx.sessionPersistence` dynamically. One serialized state machine observes complete sources, extracts shared semantic documents, reconciles changes transactionally, and runs the query. Stable fingerprints preserve unchanged persisted rows and generations; new, changed, and deleted durable sessions reconcile on the next search. Source or transaction failure commits nothing, and the next search retries. + +Persisted FTS rows live in a dedicated derived database. Connection-local TEMP tables hold live rows, which shadow the durable base for the same session and reveal it when the live owner disappears. Unmounting persistence hides durable rows without discarding the cache; remounting reconciles it. Closing or reopening the database drops every live overlay while retaining persisted rows. + +The database is disposable but reset is guarded: a recognized incompatible search schema rebuilds in place, while an unrelated or canonical database is refused. Never point `path` at the session-persistence database. + +## Configuration + +| Key | Default | Contract | +|---|---:|---| +| `path` | required | Dedicated derived-index SQLite path; `:memory:` is supported. | +| `journalMode` | `wal` | `wal`, `delete`, `truncate`, or `persist`. | +| `defaultLimit` | `20` | Page size when a request omits `limit`. | +| `maxLimit` | `100` | Largest accepted request page size. | +| `snippetChars` | `240` | Maximum snippet length in Unicode code points. | + +## Tokenizer and limits + +The index uses FTS5 `unicode61`. In the implementation experiment it supported the two-character query `AI` and produced an index about 2.1× smaller than the trigram alternative. The trade-off is token/phrase recall rather than arbitrary substring recall: `AI` does not match the token `BRAID`. Use `ctx.sessionQuery.filterEvents()` with a `text` clause when a literal whitespace-flexible substring scan is required. + +Abort signals stop queued work and caller waits around asynchronous source observation. Node's synchronous `DatabaseSync` API cannot interrupt a MATCH statement already executing on the JavaScript thread; the signal is checked immediately before and after the serialized observation/reconciliation boundary. diff --git a/packages/session-query/session-query-sqlite/package.json b/packages/session-query/session-query-sqlite/package.json new file mode 100644 index 0000000000..de5677fd68 --- /dev/null +++ b/packages/session-query/session-query-sqlite/package.json @@ -0,0 +1,46 @@ +{ + "name": "@deepseek-ai/dsh-session-query-sqlite", + "description": "SQLite FTS5 implementation of ctx.sessionSearch", + "version": "0.0.1", + "private": true, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/types/**/*.d.ts", + "lib/types/**/*.d.ts.map", + "src" + ], + "license": "BSD-3-Clause", + "peerDependencies": { + "@deepseek-ai/dsh-session": "^0.0.1", + "@deepseek-ai/dsh-session-persistence": "^0.0.1", + "@deepseek-ai/dsh-session-query": "^0.0.1", + "cordis": "^4.0.0-rc.6" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + } + }, + "dependencies": { + "schemastery": "^3.18.0" + }, + "devDependencies": { + "@cordisjs/plugin-loader": "workspace:^", + "@deepseek-ai/dsh-session": "workspace:^", + "@deepseek-ai/dsh-session-persistence": "workspace:^", + "@deepseek-ai/dsh-session-persistence-sqlite": "workspace:^", + "@deepseek-ai/dsh-session-query": "workspace:^", + "cordis": "^4.0.0-rc.6" + } +} diff --git a/packages/session-query/session-query-sqlite/src/index.ts b/packages/session-query/session-query-sqlite/src/index.ts new file mode 100644 index 0000000000..a6cba8d866 --- /dev/null +++ b/packages/session-query/session-query-sqlite/src/index.ts @@ -0,0 +1,765 @@ +/** + * SQLite FTS5 search over the live-preferred logical session corpus. + * + * @module @deepseek-ai/dsh-session-query-sqlite + */ + +import { createHash, randomUUID } from 'node:crypto' +import { DatabaseSync } from 'node:sqlite' +import { Context } from 'cordis' +import z from 'schemastery' +import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session' +import type SessionPersistence from '@deepseek-ai/dsh-session-persistence' +import { + SessionQueryError, + SessionSearchService, + assertSessionHeadersCompatible, + buildSessionEventSearchDocuments, +} from '@deepseek-ai/dsh-session-query' +import type { + SessionEventSearchDocument, + SessionEventSearchHit, + SessionEventSearchRequest, + SessionSearchExecContext, + SessionSearchHit, + SessionSearchPage, + SessionSearchRequest, +} from '@deepseek-ai/dsh-session-query' +import { + type JournalMode, + openSearchDatabase, +} from './schema.ts' +import { + type NormalizedEventRequest, + type NormalizedSessionRequest, + buildEventWhere, + buildSessionWhere, + makeSnippet, + normalizeEventRequest, + normalizeSessionRequest, + quoteFtsData, + requestFingerprint, +} from './query.ts' + +export { + SESSION_QUERY_SQLITE_APPLICATION_ID, + SESSION_QUERY_SQLITE_SCHEMA_VERSION, + type JournalMode, +} from './schema.ts' + +/** Default result page size. */ +export const SESSION_QUERY_SQLITE_DEFAULT_LIMIT = 20 +/** Maximum accepted result page size. */ +export const SESSION_QUERY_SQLITE_MAX_LIMIT = 100 +/** Default maximum snippet length in Unicode code points. */ +export const SESSION_QUERY_SQLITE_SNIPPET_CHARS = 240 + +/** SQLite session-search configuration. */ +export interface Config { + /** Dedicated derived-index path; `:memory:` is supported for tests. */ + path: string + /** SQLite journal mode. Defaults to `wal`. */ + journalMode?: JournalMode + /** Page size when a request omits `limit`. Defaults to 20. */ + defaultLimit?: number + /** Largest accepted page size. Defaults to 100. */ + maxLimit?: number + /** Maximum snippet length in Unicode code points. Defaults to 240. */ + snippetChars?: number +} + +interface ResolvedConfig { + path: string + journalMode: JournalMode + defaultLimit: number + maxLimit: number + snippetChars: number +} + +interface ObservedSession { + header: SessionHeader + events: SessionEvent[] + documents: SessionEventSearchDocument[] + fingerprint: string +} + +interface Observation { + persistence: SessionPersistence | undefined + persistenceRevision: number + persisted: Map + live: Map +} + +interface IndexedRow { + id: string + fingerprint: string + generation: number +} + +interface SearchRow { + session_id: string + version: number + created_at: number + cwd: string | null + parent_session: string | null + seed_length: number | null + live: number + persisted: number + seq: number + type: string + time: number + surface: string + text: string + score: number +} + +interface CursorPayload { + version: 1 + instance: string + scope: 'sessions' | 'events' + fingerprint: string + generation: string + offset: number +} + +/** Concrete SQLite owner of `ctx.sessionSearch`. */ +export class SessionSearchSqlite extends SessionSearchService { + static inject = ['sessions'] + + static Config: z = z.object({ + path: z.string().required(), + journalMode: z.union(['wal', 'delete', 'truncate', 'persist'] as const).default('wal'), + defaultLimit: z.number().step(1).min(1).default(SESSION_QUERY_SQLITE_DEFAULT_LIMIT), + maxLimit: z.number().step(1).min(1).default(SESSION_QUERY_SQLITE_MAX_LIMIT), + snippetChars: z.number().step(1).min(1).default(SESSION_QUERY_SQLITE_SNIPPET_CHARS), + }) + + /** Validated and defaulted backend configuration. */ + readonly config: ResolvedConfig + + private readonly _instance = randomUUID() + private readonly _ready: Promise + private _db: DatabaseSync | undefined + private _persistence: SessionPersistence | undefined + private _persistenceBinding: object | undefined + private _persistenceRevision = 0 + private _lastPersistenceRevision: number | undefined + private _persistenceEpoch = 0 + private _globalGeneration = 0 + private _localGeneration = 0 + private _tail: Promise = Promise.resolve() + private _closed = false + + constructor(ctx: Context, config: Config) { + super(ctx) + this.config = resolveConfig(config) + this._ready = this._open() + ctx.effect(() => { + const fiber = ctx.inject(['sessionPersistence'], (childCtx: Context) => { + const service = childCtx.sessionPersistence + const binding = {} + this._persistenceBinding = binding + this._persistence = service + this._persistenceRevision += 1 + childCtx.effect(() => () => { + /* v8 ignore next -- a stale optional-service disposer cannot clear a replacement */ + if (this._persistenceBinding !== binding) return + this._persistenceBinding = undefined + this._persistence = undefined + this._persistenceRevision += 1 + }, 'sessionSearchSqlite.persistenceBinding') + }) + return () => void fiber.dispose() + }, 'sessionSearchSqlite.optionalPersistence') + ctx.effect(() => async () => this.close(), 'sessionSearchSqlite.close') + } + + override async searchSessions( + request: SessionSearchRequest, + exec?: SessionSearchExecContext, + ): Promise> { + const normalized = normalizeSessionRequest(request, this.config) + return this._serialized(exec?.signal, async () => { + await this._ensureReady(exec?.signal) + await this._reconcile(exec?.signal) + assertNotAborted(exec?.signal) + const generation = String(this._globalGeneration) + const fingerprint = requestFingerprint(normalized) + const offset = normalized.cursor === undefined + ? 0 + : decodeCursor(normalized.cursor, this._instance, 'sessions', fingerprint, generation) + const rows = this._querySessions(normalized, offset) + return page(rows, normalized.limit, row => this._sessionHit(row, normalized.query), cursorOffset => encodeCursor({ + version: 1, + instance: this._instance, + scope: 'sessions', + fingerprint, + generation, + offset: cursorOffset, + }), offset) + }) + } + + override async searchEvents( + request: SessionEventSearchRequest, + exec?: SessionSearchExecContext, + ): Promise> { + const normalized = normalizeEventRequest(request, this.config) + return this._serialized(exec?.signal, async () => { + await this._ensureReady(exec?.signal) + await this._reconcile(exec?.signal) + assertNotAborted(exec?.signal) + const generation = this._targetGeneration(normalized.sessionId) + const fingerprint = requestFingerprint(normalized) + const offset = normalized.cursor === undefined + ? 0 + : decodeCursor(normalized.cursor, this._instance, 'events', fingerprint, generation) + const rows = this._queryEvents(normalized, offset) + return page(rows, normalized.limit, row => this._eventHit(row, normalized.query), cursorOffset => encodeCursor({ + version: 1, + instance: this._instance, + scope: 'events', + fingerprint, + generation, + offset: cursorOffset, + }), offset) + }) + } + + /** Close the database after every accepted operation reaches quiescence. */ + async close(): Promise { + if (this._closed) return + this._closed = true + await this._tail + try { + await this._ready + } catch { + // Opening already closed a partially-created handle; disposal only waits. + } + this._db?.close() + this._db = undefined + } + + private async _open(): Promise { + this._db = await openSearchDatabase(this.config.path, this.config.journalMode) + const state = this._db.prepare( + 'SELECT global_generation FROM search_state WHERE singleton = 1', + ).get() as { global_generation: number } + this._globalGeneration = state.global_generation + this._localGeneration = state.global_generation + } + + private async _ensureReady(signal: AbortSignal | undefined): Promise { + try { + await waitWithAbort(this._ready, signal) + } catch (error: unknown) { + if (isAbort(error)) throw error + throw new SessionQueryError( + `session-search SQLite index failed to open: ${errorMessage(error)}`, + 'SESSION_QUERY_INDEX_FAILED', + { cause: error }, + ) + } + } + + private async _serialized(signal: AbortSignal | undefined, operation: () => Promise): Promise { + if (this._isClosed()) throw indexClosed() + let release!: () => void + const gate = new Promise((resolve) => { release = resolve }) + const prior = this._tail + this._tail = prior.then(() => gate) + try { + await waitWithAbort(prior, signal) + } catch (error: unknown) { + release() + throw error + } + if (this._isClosed()) { + release() + throw indexClosed() + } + try { + assertNotAborted(signal) + return await operation() + } finally { + release() + } + } + + private async _reconcile(signal: AbortSignal | undefined): Promise { + const observation = await this._observeStable(signal) + assertNotAborted(signal) + const db = this._requireDb() + const persistedRows = db.prepare( + 'SELECT id, fingerprint, generation FROM persisted_sessions', + ).all() as unknown as IndexedRow[] + const liveRows = db.prepare( + 'SELECT id, fingerprint, generation FROM temp.live_sessions', + ).all() as unknown as IndexedRow[] + const persistedById = new Map(persistedRows.map(row => [row.id as SessionId, row])) + const liveById = new Map(liveRows.map(row => [row.id as SessionId, row])) + const persistentChanges = observation.persistence === undefined + ? [] + : [...observation.persisted.values()].filter(entry => persistedById.get(entry.header.id)?.fingerprint !== entry.fingerprint) + const persistentDeletes = observation.persistence === undefined + ? [] + : persistedRows.filter(row => !observation.persisted.has(row.id as SessionId)) + const liveChanges = [...observation.live.values()].filter(entry => liveById.get(entry.header.id)?.fingerprint !== entry.fingerprint) + const liveDeletes = liveRows.filter(row => !observation.live.has(row.id as SessionId)) + const pointerChanged = this._lastPersistenceRevision !== undefined + && this._lastPersistenceRevision !== observation.persistenceRevision + const hasWrites = persistentChanges.length > 0 + || persistentDeletes.length > 0 + || liveChanges.length > 0 + || liveDeletes.length > 0 + + let nextMainGeneration = this._mainGeneration() + let nextLocalGeneration = this._localGeneration + if (persistentChanges.length > 0 || persistentDeletes.length > 0) nextMainGeneration += 1 + const liveReplacements = liveChanges.map((entry) => { + nextLocalGeneration = Math.max(nextLocalGeneration, nextMainGeneration) + 1 + return { entry, generation: nextLocalGeneration } + }) + + if (hasWrites) { + let began = false + try { + db.exec('BEGIN IMMEDIATE') + began = true + for (const row of persistentDeletes) this._deleteSession('persisted', row.id as SessionId) + for (const entry of persistentChanges) this._replaceSession('persisted', entry, nextMainGeneration) + if (persistentChanges.length > 0 || persistentDeletes.length > 0) { + db.prepare('UPDATE search_state SET global_generation = ? WHERE singleton = 1').run(nextMainGeneration) + } + for (const row of liveDeletes) this._deleteSession('live', row.id as SessionId) + for (const { entry, generation } of liveReplacements) { + this._replaceSession('live', entry, generation) + } + db.exec('COMMIT') + } catch (error: unknown) { + /* v8 ignore next -- a BEGIN failure has no transaction to roll back; the common wrapper still reports it. */ + if (began) { + /* v8 ignore next 5 -- ROLLBACK failure requires a SQLite double fault; the original failure remains actionable. */ + try { + db.exec('ROLLBACK') + } catch { + // The original SQLite failure remains the actionable cause. + } + } + throw new SessionQueryError( + `session-search reconciliation failed: ${errorMessage(error)}`, + 'SESSION_QUERY_INDEX_FAILED', + { cause: error }, + ) + } + } + + if (hasWrites || pointerChanged) this._globalGeneration += 1 + if (pointerChanged) this._persistenceEpoch += 1 + this._localGeneration = nextLocalGeneration + this._lastPersistenceRevision = observation.persistenceRevision + } + + private async _observeStable(signal: AbortSignal | undefined): Promise { + for (;;) { + assertNotAborted(signal) + const persistence = this._persistence + const persistenceRevision = this._persistenceRevision + const persisted = new Map() + if (persistence !== undefined) { + try { + const headers = await waitWithAbort(persistence.list(), signal) + for (const listed of headers) { + const loaded = await waitWithAbort(persistence.load(listed.id), signal) + assertSessionHeadersCompatible(listed, loaded.meta) + persisted.set(listed.id, observeSession(loaded.meta, loaded.events)) + } + } catch (error: unknown) { + if (error instanceof SessionQueryError) throw error + throw new SessionQueryError( + `session-search persistence observation failed: ${errorMessage(error)}`, + 'SESSION_QUERY_PERSISTENCE_FAILED', + { cause: error }, + ) + } + } + const live = new Map() + for (const session of this.ctx.sessions.list()) { + const observed = observeLive(session) + const durable = persisted.get(session.id) + if (durable !== undefined) assertSessionHeadersCompatible(observed.header, durable.header) + live.set(session.id, observed) + } + if (this._persistenceRevision === persistenceRevision) { + return { persistence, persistenceRevision, persisted, live } + } + } + } + + private _mainGeneration(): number { + const row = this._requireDb().prepare( + 'SELECT global_generation FROM search_state WHERE singleton = 1', + ).get() as { global_generation: number } + return row.global_generation + } + + private _deleteSession(source: 'persisted' | 'live', id: SessionId): void { + const db = this._requireDb() + if (source === 'persisted') { + db.prepare('DELETE FROM persisted_docs WHERE session_id = ?').run(id) + db.prepare('DELETE FROM persisted_sessions WHERE id = ?').run(id) + } else { + db.prepare('DELETE FROM temp.live_docs WHERE session_id = ?').run(id) + db.prepare('DELETE FROM temp.live_sessions WHERE id = ?').run(id) + } + } + + private _replaceSession(source: 'persisted' | 'live', entry: ObservedSession, generation: number): void { + this._deleteSession(source, entry.header.id) + const db = this._requireDb() + const sessionTable = source === 'persisted' ? 'persisted_sessions' : 'temp.live_sessions' + const docsTable = source === 'persisted' ? 'persisted_docs' : 'temp.live_docs' + db.prepare(` + INSERT INTO ${sessionTable} + (id, version, created_at, cwd, parent_session, seed_length, fingerprint, generation) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + `).run( + entry.header.id, + entry.header.version, + entry.header.createdAt, + entry.header.cwd ?? null, + entry.header.parentSession ?? null, + entry.header.seedLength ?? null, + entry.fingerprint, + generation, + ) + const insert = db.prepare(` + INSERT INTO ${docsTable} (text, session_id, seq, type, time, surface) + VALUES (?, ?, ?, ?, ?, ?) + `) + for (const document of entry.documents) { + insert.run(document.text, document.sessionId, document.seq, document.type, document.time, document.surface) + } + } + + private _querySessions(request: NormalizedSessionRequest, offset: number): SearchRow[] { + const selected = selectedDocumentsSql() + const sessionWhere = buildSessionWhere(request.sessionFilters) + const eventWhere = buildEventWhere(request.eventFilters) + const where = [sessionWhere.sql, eventWhere.sql].filter(Boolean).join(' AND ') + return this._requireDb().prepare(` + ${selected.sql}, + filtered AS ( + SELECT * FROM matched ${where.length === 0 ? '' : `WHERE ${where}`} + ), + ranked AS ( + SELECT *, ROW_NUMBER() OVER ( + PARTITION BY session_id + ORDER BY score ASC, time DESC, seq DESC + ) AS event_rank + FROM filtered + ) + SELECT * FROM ranked + WHERE event_rank = 1 + ORDER BY score ASC, time DESC, session_id ASC, seq DESC + LIMIT ? OFFSET ? + `).all( + quoteFtsData(request.query), + this._persistence === undefined ? 0 : 1, + this._persistence === undefined ? 0 : 1, + quoteFtsData(request.query), + ...sessionWhere.params, + ...eventWhere.params, + request.limit + 1, + offset, + ) as unknown as SearchRow[] + } + + private _queryEvents(request: NormalizedEventRequest, offset: number): SearchRow[] { + const selected = selectedDocumentsSql() + const eventWhere = buildEventWhere(request.filters) + const where = ['session_id = ?', eventWhere.sql].filter(Boolean).join(' AND ') + return this._requireDb().prepare(` + ${selected.sql} + SELECT * FROM matched + WHERE ${where} + ORDER BY score ASC, time DESC, seq DESC + LIMIT ? OFFSET ? + `).all( + quoteFtsData(request.query), + this._persistence === undefined ? 0 : 1, + this._persistence === undefined ? 0 : 1, + quoteFtsData(request.query), + request.sessionId, + ...eventWhere.params, + request.limit + 1, + offset, + ) as unknown as SearchRow[] + } + + private _targetGeneration(sessionId: SessionId): string { + const db = this._requireDb() + const live = db.prepare( + 'SELECT generation FROM temp.live_sessions WHERE id = ?', + ).get(sessionId) as { generation: number } | undefined + if (live !== undefined) return `live:${live.generation}` + if (this._persistence !== undefined) { + const persisted = db.prepare( + 'SELECT generation FROM persisted_sessions WHERE id = ?', + ).get(sessionId) as { generation: number } | undefined + if (persisted !== undefined) return `persisted:${this._persistenceEpoch}:${persisted.generation}` + } + throw new SessionQueryError( + `session "${sessionId}" not found`, + 'SESSION_QUERY_SESSION_NOT_FOUND', + ) + } + + private _sessionHit(row: SearchRow, query: string): SessionSearchHit { + return { + header: rowHeader(row), + live: row.live === 1, + persisted: row.persisted === 1, + bestMatch: this._eventHit(row, query), + } + } + + private _eventHit(row: SearchRow, query: string): SessionEventSearchHit { + return { + sessionId: row.session_id as SessionId, + seq: row.seq, + type: row.type as SessionEventSearchHit['type'], + time: row.time, + surface: row.surface as SessionEventSearchHit['surface'], + snippet: makeSnippet(row.text, query, this.config.snippetChars), + } + } + + private _requireDb(): DatabaseSync { + /* v8 ignore next -- callers await `_ready`; this guards lifecycle misuse */ + if (this._db === undefined) throw indexClosed() + return this._db + } + + private _isClosed(): boolean { + return this._closed + } +} + +function selectedDocumentsSql(): { sql: string } { + return { + sql: `WITH matched AS ( + SELECT + pd.session_id AS session_id, + ps.version AS version, + ps.created_at AS created_at, + ps.cwd AS cwd, + ps.parent_session AS parent_session, + ps.seed_length AS seed_length, + 0 AS live, + 1 AS persisted, + CAST(pd.seq AS INTEGER) AS seq, + pd.type AS type, + CAST(pd.time AS INTEGER) AS time, + pd.surface AS surface, + pd.text AS text, + bm25(persisted_docs) AS score + FROM persisted_docs AS pd + JOIN persisted_sessions AS ps ON ps.id = pd.session_id + WHERE persisted_docs MATCH ? + AND ? = 1 + AND NOT EXISTS (SELECT 1 FROM temp.live_sessions AS ls WHERE ls.id = pd.session_id) + UNION ALL + SELECT + ld.session_id AS session_id, + ls.version AS version, + ls.created_at AS created_at, + ls.cwd AS cwd, + ls.parent_session AS parent_session, + ls.seed_length AS seed_length, + 1 AS live, + CASE WHEN ? = 1 AND EXISTS ( + SELECT 1 FROM persisted_sessions AS ps WHERE ps.id = ld.session_id + ) THEN 1 ELSE 0 END AS persisted, + CAST(ld.seq AS INTEGER) AS seq, + ld.type AS type, + CAST(ld.time AS INTEGER) AS time, + ld.surface AS surface, + ld.text AS text, + bm25(live_docs) AS score + FROM temp.live_docs AS ld + JOIN temp.live_sessions AS ls ON ls.id = ld.session_id + WHERE live_docs MATCH ? + )`, + } +} + +function observeLive(session: Session): ObservedSession { + return observeSession( + structuredClone(session.header), + session.events.map(event => structuredClone(event)), + ) +} + +function observeSession(header: SessionHeader, events: readonly SessionEvent[]): ObservedSession { + const detachedHeader = structuredClone(header) + const detachedEvents = events.map(event => structuredClone(event)) + return { + header: detachedHeader, + events: detachedEvents, + documents: buildSessionEventSearchDocuments(detachedHeader.id, detachedEvents), + fingerprint: createHash('sha256') + .update(JSON.stringify({ header: detachedHeader, events: detachedEvents })) + .digest('base64url'), + } +} + +function rowHeader(row: SearchRow): SessionHeader { + return { + version: row.version, + id: row.session_id as SessionId, + createdAt: row.created_at, + ...row.cwd === null ? {} : { cwd: row.cwd }, + ...row.parent_session === null ? {} : { parentSession: row.parent_session as SessionId }, + ...row.seed_length === null ? {} : { seedLength: row.seed_length }, + } +} + +function page( + rows: readonly Row[], + limit: number, + convert: (row: Row) => Item, + nextCursor: (offset: number) => string, + offset: number, +): SessionSearchPage { + const hasMore = rows.length > limit + return { + items: rows.slice(0, limit).map(convert), + ...hasMore ? { nextCursor: nextCursor(offset + limit) } : {}, + } +} + +function encodeCursor(payload: CursorPayload): string { + return Buffer.from(JSON.stringify(payload), 'utf8').toString('base64url') +} + +function decodeCursor( + cursor: string, + instance: string, + scope: CursorPayload['scope'], + fingerprint: string, + generation: string, +): number { + let decoded: Partial + try { + decoded = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8')) as Partial + } catch (error: unknown) { + throw invalidCursor(error) + } + if ( + decoded.version !== 1 + || decoded.instance !== instance + || decoded.scope !== scope + || decoded.fingerprint !== fingerprint + || !Number.isInteger(decoded.offset) + || decoded.offset === undefined + || decoded.offset < 0 + ) { + throw invalidCursor(new Error('cursor does not belong to this normalized request')) + } + if (decoded.generation !== generation) { + throw new SessionQueryError( + 'session-search cursor is stale because its relevant corpus changed', + 'SESSION_QUERY_STALE_CURSOR', + ) + } + return decoded.offset +} + +function invalidCursor(cause: unknown): SessionQueryError { + return new SessionQueryError( + 'session-search cursor is invalid', + 'SESSION_QUERY_INVALID_CURSOR', + { cause }, + ) +} + +function resolveConfig(config: Config): ResolvedConfig { + const resolved: ResolvedConfig = { + path: config.path, + journalMode: config.journalMode ?? 'wal', + defaultLimit: config.defaultLimit ?? SESSION_QUERY_SQLITE_DEFAULT_LIMIT, + maxLimit: config.maxLimit ?? SESSION_QUERY_SQLITE_MAX_LIMIT, + snippetChars: config.snippetChars ?? SESSION_QUERY_SQLITE_SNIPPET_CHARS, + } + if (typeof resolved.path !== 'string' || resolved.path.trim().length === 0) { + throw invalidConfig('path must not be blank') + } + assertPositiveInteger('defaultLimit', resolved.defaultLimit) + assertPositiveInteger('maxLimit', resolved.maxLimit) + assertPositiveInteger('snippetChars', resolved.snippetChars) + if (resolved.defaultLimit > resolved.maxLimit) { + throw invalidConfig('defaultLimit must be less than or equal to maxLimit') + } + const journalModes: readonly string[] = ['wal', 'delete', 'truncate', 'persist'] + if (!journalModes.includes(resolved.journalMode)) throw invalidConfig('journalMode is not supported') + return resolved +} + +function assertPositiveInteger(name: string, value: number): void { + if (!Number.isInteger(value) || value < 1) throw invalidConfig(`${name} must be a positive integer`) +} + +function invalidConfig(detail: string): SessionQueryError { + return new SessionQueryError( + `session-search SQLite config: ${detail}`, + 'SESSION_QUERY_INVALID_CONFIG', + ) +} + +function indexClosed(): SessionQueryError { + return new SessionQueryError('session-search SQLite index is closed', 'SESSION_QUERY_INDEX_FAILED') +} + +function assertNotAborted(signal: AbortSignal | undefined): void { + if (signal?.aborted) { + throw new SessionQueryError('session-search aborted', 'SESSION_QUERY_ABORTED') + } +} + +function waitWithAbort(promise: Promise, signal: AbortSignal | undefined): Promise { + if (signal === undefined) return promise + if (signal.aborted) return Promise.reject(new SessionQueryError('session-search aborted', 'SESSION_QUERY_ABORTED')) + return new Promise((resolve, reject) => { + const onAbort = () => { + reject(new SessionQueryError('session-search aborted', 'SESSION_QUERY_ABORTED')) + } + signal.addEventListener('abort', onAbort, { once: true }) + promise.then( + (value) => { + signal.removeEventListener('abort', onAbort) + resolve(value) + }, + (error: unknown) => { + signal.removeEventListener('abort', onAbort) + reject(asError(error)) + }, + ) + }) +} + +function isAbort(error: unknown): boolean { + return error instanceof SessionQueryError && error.code === 'SESSION_QUERY_ABORTED' +} + +function asError(error: unknown): Error { + return error instanceof Error + ? error + : new Error('session-search dependency rejected with a non-Error value', { cause: error }) +} + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : 'unknown error' +} + +export default SessionSearchSqlite diff --git a/packages/session-query/session-query-sqlite/src/query.ts b/packages/session-query/session-query-sqlite/src/query.ts new file mode 100644 index 0000000000..fd2b5156e6 --- /dev/null +++ b/packages/session-query/session-query-sqlite/src/query.ts @@ -0,0 +1,312 @@ +/** Request normalization, parameterized predicates, and result presentation. */ + +import { + SessionQueryError, + filterSessionEventDocuments, + filterSessionResults, +} from '@deepseek-ai/dsh-session-query' +import type { + SessionEventMetadataFilter, + SessionEventSearchRequest, + SessionResultFilter, + SessionSearchRequest, +} from '@deepseek-ai/dsh-session-query' + +/** Limit defaults needed to normalize a search request. */ +export interface QueryLimits { + /** Page size used when the request omits one. */ + defaultLimit: number + /** Largest accepted page size. */ + maxLimit: number +} + +/** Normalized cross-session request. */ +export interface NormalizedSessionRequest { + query: string + sessionFilters: readonly SessionResultFilter[] + eventFilters: readonly SessionEventMetadataFilter[] + limit: number + cursor?: string +} + +/** Normalized within-session request. */ +export interface NormalizedEventRequest { + sessionId: SessionEventSearchRequest['sessionId'] + query: string + filters: readonly SessionEventMetadataFilter[] + limit: number + cursor?: string +} + +/** Parameterized SQL predicate fragment. */ +export interface SqlWhere { + /** SQL without the leading `WHERE`. */ + sql: string + /** Bindings in placeholder order. */ + params: Array +} + +/** + * Validate and canonicalize a cross-session request. + * @param request - caller-provided query, filters, limit, and cursor. + * @param limits - configured default and maximum page sizes. + * @returns normalized request with explicit arrays and limit. + */ +export function normalizeSessionRequest( + request: SessionSearchRequest, + limits: QueryLimits, +): NormalizedSessionRequest { + const sessionFilters = request.sessionFilters ?? [] + const eventFilters = request.eventFilters ?? [] + filterSessionResults([], sessionFilters) + filterSessionEventDocuments([], eventFilters) + return { + query: normalizeQuery(request.query), + sessionFilters, + eventFilters, + limit: normalizeLimit(request.limit, limits), + ...request.cursor === undefined ? {} : { cursor: request.cursor }, + } +} + +/** + * Validate and canonicalize a within-session request. + * @param request - caller-provided target, query, filters, limit, and cursor. + * @param limits - configured default and maximum page sizes. + * @returns normalized request with an explicit filter array and limit. + */ +export function normalizeEventRequest( + request: SessionEventSearchRequest, + limits: QueryLimits, +): NormalizedEventRequest { + const filters = request.filters ?? [] + filterSessionEventDocuments([], filters) + return { + sessionId: request.sessionId, + query: normalizeQuery(request.query), + filters, + limit: normalizeLimit(request.limit, limits), + ...request.cursor === undefined ? {} : { cursor: request.cursor }, + } +} + +/** + * Compile logical-session predicates against selected-document columns. + * @param filters - validated ANDed logical-session clauses. + * @returns parameterized SQL fragment and ordered bindings. + */ +export function buildSessionWhere(filters: readonly SessionResultFilter[]): SqlWhere { + const clauses: string[] = [] + const params: Array = [] + for (const filter of filters) { + switch (filter.kind) { + case 'id': + addList(clauses, params, 'session_id', filter.values) + break + case 'cwd': + addNullableList(clauses, params, 'cwd', filter.values) + break + case 'created-at': + addRange(clauses, params, 'created_at', filter) + break + case 'parent': + addNullableList(clauses, params, 'parent_session', filter.values) + break + case 'availability': { + const availability = [...new Set(filter.values)] + if (availability.length === 0) clauses.push('0') + else if (availability.length === 1) clauses.push(`${availability[0]} = 1`) + break + } + } + } + return { sql: clauses.join(' AND '), params } +} + +/** + * Compile event metadata predicates against selected-document columns. + * @param filters - validated ANDed event metadata clauses. + * @returns parameterized SQL fragment and ordered bindings. + */ +export function buildEventWhere(filters: readonly SessionEventMetadataFilter[]): SqlWhere { + const clauses: string[] = [] + const params: Array = [] + for (const filter of filters) { + switch (filter.kind) { + case 'seq': + addRange(clauses, params, 'seq', filter) + break + case 'time': + addRange(clauses, params, 'time', filter) + break + case 'type': + addList(clauses, params, 'type', filter.values) + break + case 'surface': + addList(clauses, params, 'surface', filter.values) + break + } + } + return { sql: clauses.join(' AND '), params } +} + +/** + * Quote caller text as one FTS5 phrase so query syntax remains inert data. + * @param query - normalized caller query. + * @returns FTS5 expression containing one escaped literal phrase. + */ +export function quoteFtsData(query: string): string { + return `"${query.replaceAll('"', '""')}"` +} + +/** + * Build the stable normalized request identity stored in opaque cursors. + * @param request - normalized request whose filter ordering is canonicalized. + * @returns deterministic JSON identity for cursor binding. + */ +export function requestFingerprint(request: NormalizedSessionRequest | NormalizedEventRequest): string { + if ('sessionId' in request) { + return JSON.stringify({ + scope: 'events', + sessionId: request.sessionId, + query: request.query, + filters: canonicalFilters(request.filters), + limit: request.limit, + }) + } + return JSON.stringify({ + scope: 'sessions', + query: request.query, + sessionFilters: canonicalFilters(request.sessionFilters), + eventFilters: canonicalFilters(request.eventFilters), + limit: request.limit, + }) +} + +/** + * Build a whitespace-normalized excerpt no longer than `maxChars`. + * @param text - complete extracted semantic document. + * @param query - normalized literal query used to position the excerpt. + * @param maxChars - maximum result length in Unicode code points. + * @returns bounded plain-text snippet. + */ +export function makeSnippet(text: string, query: string, maxChars: number): string { + const clean = text.replace(/\s+/gu, ' ').trim() + const characters = Array.from(clean) + if (characters.length <= maxChars) return clean + if (maxChars === 1) return '…' + const foundUnits = clean.toLowerCase().indexOf(query.toLowerCase()) + const found = foundUnits < 0 ? -1 : Array.from(clean.slice(0, foundUnits)).length + let start = found < 0 ? 0 : Math.max(0, found - Math.floor(maxChars / 3)) + let prefix = start > 0 ? '…' : '' + let suffix = '…' + let contentLength = maxChars - prefix.length - suffix.length + if (contentLength < 1) { + start = 0 + prefix = '' + contentLength = maxChars - 1 + } + let end = Math.min(characters.length, start + contentLength) + if (end === characters.length) { + suffix = '' + contentLength = maxChars - prefix.length + start = Math.max(0, end - contentLength) + } + end = Math.min(characters.length, start + contentLength) + return `${prefix}${characters.slice(start, end).join('')}${suffix}` +} + +function normalizeQuery(value: string): string { + if (typeof value !== 'string') { + throw new SessionQueryError('session-search query must be text', 'SESSION_QUERY_INVALID_QUERY') + } + const query = value.trim().replace(/\s+/gu, ' ') + if (query.length === 0) { + throw new SessionQueryError( + 'session-search query must contain non-whitespace text', + 'SESSION_QUERY_INVALID_QUERY', + ) + } + return query +} + +function normalizeLimit(value: number | undefined, limits: QueryLimits): number { + const limit = value ?? limits.defaultLimit + if (!Number.isInteger(limit) || limit < 1 || limit > limits.maxLimit) { + throw new SessionQueryError( + `session-search limit must be an integer between 1 and ${limits.maxLimit}`, + 'SESSION_QUERY_INVALID_LIMIT', + ) + } + return limit +} + +function addList( + clauses: string[], + params: Array, + column: string, + values: readonly (string | number)[], +): void { + if (values.length === 0) { + clauses.push('0') + return + } + clauses.push(`${column} IN (${values.map(() => '?').join(', ')})`) + params.push(...values) +} + +function addNullableList( + clauses: string[], + params: Array, + column: string, + values: readonly (string | null)[], +): void { + if (values.length === 0) { + clauses.push('0') + return + } + const concrete = values.filter((value): value is string => value !== null) + const parts: string[] = [] + if (concrete.length > 0) { + parts.push(`${column} IN (${concrete.map(() => '?').join(', ')})`) + params.push(...concrete) + } + if (values.includes(null)) parts.push(`${column} IS NULL`) + clauses.push(`(${parts.join(' OR ')})`) +} + +function addRange( + clauses: string[], + params: Array, + column: string, + range: { from?: number; to?: number }, +): void { + if (range.from !== undefined) { + clauses.push(`CAST(${column} AS INTEGER) >= ?`) + params.push(range.from) + } + if (range.to !== undefined) { + clauses.push(`CAST(${column} AS INTEGER) <= ?`) + params.push(range.to) + } +} + +function canonicalFilters(filters: readonly (SessionResultFilter | SessionEventMetadataFilter)[]): unknown[] { + return filters.map((filter) => { + if ('values' in filter) { + return { ...filter, values: [...filter.values].sort(compareNullable) } + } + return { + kind: filter.kind, + from: filter.from ?? null, + to: filter.to ?? null, + } + }).sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b))) +} + +function compareNullable(a: string | null, b: string | null): number { + if (a === b) return 0 + if (a === null) return -1 + if (b === null) return 1 + return a.localeCompare(b) +} diff --git a/packages/session-query/session-query-sqlite/src/schema.ts b/packages/session-query/session-query-sqlite/src/schema.ts new file mode 100644 index 0000000000..1c9bd98791 --- /dev/null +++ b/packages/session-query/session-query-sqlite/src/schema.ts @@ -0,0 +1,127 @@ +/** SQLite schema for the disposable session full-text read model. */ + +import { DatabaseSync } from 'node:sqlite' +import { mkdir } from 'node:fs/promises' +import { dirname, resolve } from 'node:path' + +/** Current derived-index schema version. Incompatible versions reset in place. */ +export const SESSION_QUERY_SQLITE_SCHEMA_VERSION = 1 + +/** SQLite application id protecting unrelated databases from derived resets. */ +export const SESSION_QUERY_SQLITE_APPLICATION_ID = 0x44534851 + +/** Supported SQLite journal modes. */ +export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' + +/** + * Open, validate, and initialize persistent and connection-local schemas. + * @param path - dedicated derived-index path or `:memory:`. + * @param journalMode - validated SQLite journal mode. + * @returns initialized database handle owned by the search service. + */ +export async function openSearchDatabase(path: string, journalMode: JournalMode): Promise { + const actual = path === ':memory:' ? path : resolve(path) + if (actual !== ':memory:') await mkdir(dirname(actual), { recursive: true, mode: 0o700 }) + const db = new DatabaseSync(actual) + try { + // journalMode is a validated closed union, not caller-controlled SQL. + db.exec(`PRAGMA journal_mode = ${journalMode.toUpperCase()}`) + const { application_id: applicationId } = db.prepare('PRAGMA application_id').get() as { application_id: number } + const { user_version: version } = db.prepare('PRAGMA user_version').get() as { user_version: number } + const userTables = listUserTables(db) + if (applicationId !== 0 && applicationId !== SESSION_QUERY_SQLITE_APPLICATION_ID) { + throw new Error(`session-search database at "${actual}" belongs to another application`) + } + if (applicationId === 0 && userTables.length > 0) { + throw new Error(`session-search database at "${actual}" is not an empty or recognized derived index`) + } + if (applicationId === SESSION_QUERY_SQLITE_APPLICATION_ID && version !== SESSION_QUERY_SQLITE_SCHEMA_VERSION) { + resetDerivedSchema(db) + } + ensurePersistentSchema(db) + ensureTemporarySchema(db) + return db + } catch (error: unknown) { + db.close() + throw error + } +} + +function listUserTables(db: DatabaseSync): string[] { + const rows = db.prepare( + "SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name", + ).all() as Array<{ name: string }> + return rows.map(row => row.name) +} + +function resetDerivedSchema(db: DatabaseSync): void { + for (const name of listUserTables(db)) { + db.exec(`DROP TABLE IF EXISTS ${quoteIdentifier(name)}`) + } + db.exec('PRAGMA user_version = 0') +} + +function ensurePersistentSchema(db: DatabaseSync): void { + db.exec(`PRAGMA application_id = ${SESSION_QUERY_SQLITE_APPLICATION_ID}`) + db.exec(` + CREATE TABLE IF NOT EXISTS search_state ( + singleton INTEGER PRIMARY KEY CHECK (singleton = 1), + global_generation INTEGER NOT NULL + ) STRICT + `) + db.exec('INSERT OR IGNORE INTO search_state (singleton, global_generation) VALUES (1, 0)') + db.exec(` + CREATE TABLE IF NOT EXISTS persisted_sessions ( + id TEXT PRIMARY KEY, + version INTEGER NOT NULL, + created_at INTEGER NOT NULL, + cwd TEXT, + parent_session TEXT, + seed_length INTEGER, + fingerprint TEXT NOT NULL, + generation INTEGER NOT NULL + ) STRICT + `) + db.exec(` + CREATE VIRTUAL TABLE IF NOT EXISTS persisted_docs USING fts5( + text, + session_id UNINDEXED, + seq UNINDEXED, + type UNINDEXED, + time UNINDEXED, + surface UNINDEXED, + tokenize = 'unicode61' + ) + `) + db.exec(`PRAGMA user_version = ${SESSION_QUERY_SQLITE_SCHEMA_VERSION}`) +} + +function ensureTemporarySchema(db: DatabaseSync): void { + db.exec(` + CREATE TEMP TABLE IF NOT EXISTS live_sessions ( + id TEXT PRIMARY KEY, + version INTEGER NOT NULL, + created_at INTEGER NOT NULL, + cwd TEXT, + parent_session TEXT, + seed_length INTEGER, + fingerprint TEXT NOT NULL, + generation INTEGER NOT NULL + ) STRICT + `) + db.exec(` + CREATE VIRTUAL TABLE IF NOT EXISTS temp.live_docs USING fts5( + text, + session_id UNINDEXED, + seq UNINDEXED, + type UNINDEXED, + time UNINDEXED, + surface UNINDEXED, + tokenize = 'unicode61' + ) + `) +} + +function quoteIdentifier(value: string): string { + return `"${value.replaceAll('"', '""')}"` +} diff --git a/packages/session-query/session-query-sqlite/tests/load-path.e2e.ts b/packages/session-query/session-query-sqlite/tests/load-path.e2e.ts new file mode 100644 index 0000000000..c20a501964 --- /dev/null +++ b/packages/session-query/session-query-sqlite/tests/load-path.e2e.ts @@ -0,0 +1,60 @@ +/** + * Keyless real-Loader-path smoke for the SQLite session-search service. + * + * @module @deepseek-ai/dsh-session-query-sqlite/tests/load-path + */ + +import { afterEach, describe, expect, it } from 'vitest' +import { Context } from 'cordis' +import Loader from '@cordisjs/plugin-loader' +import { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session' +import SessionStore from '@deepseek-ai/dsh-session' +import SessionPersistenceSqlite from '@deepseek-ai/dsh-session-persistence-sqlite' +import SessionSearchSqlite, * as searchModule from '@deepseek-ai/dsh-session-query-sqlite' +import { mkdtemp, rm } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'node:path' + +const temporaryDirectories: string[] = [] + +afterEach(async () => { + for (const directory of temporaryDirectories.splice(0)) { + await rm(directory, { recursive: true, force: true }) + } +}) + +async function temporaryPath(name: string): Promise { + const directory = await mkdtemp(join(tmpdir(), 'dsh-session-search-loader-')) + temporaryDirectories.push(directory) + return join(directory, name) +} + +describe('dsh-session-query-sqlite real Loader path', () => { + it('unwraps, mounts, and searches the real persistence backend', async () => { + const persistencePath = await temporaryPath('canonical.db') + const searchPath = await temporaryPath('derived.db') + const ctx = new Context() + await ctx.plugin(SessionStore) + const persistence = await ctx.plugin(SessionPersistenceSqlite, { path: persistencePath }) + + const loader = Object.create(Loader.prototype) as Loader + const unwrapped = loader.unwrapExports(searchModule) as Parameters[0] + expect(unwrapped).toBe(SessionSearchSqlite) + const search = await ctx.plugin(unwrapped, { path: searchPath }) + + const id = SessionId('loader-path') + await ctx.sessionPersistence.create({ version: SESSION_FORMAT_VERSION, id, createdAt: 10 }) + await ctx.sessionPersistence.append(id, [{ + type: 'user/message', + seq: 0, + time: 10, + data: { content: [{ type: 'text', text: 'real Loader needle' }], source: { kind: 'user' } }, + surfaceOp: 'append', + }]) + + await expect(ctx.sessionSearch.searchSessions({ query: 'Loader needle' })) + .resolves.toMatchObject({ items: [{ header: { id }, persisted: true, live: false }] }) + await search.dispose() + await persistence.dispose() + }) +}) diff --git a/packages/session-query/session-query-sqlite/tests/query.spec.ts b/packages/session-query/session-query-sqlite/tests/query.spec.ts new file mode 100644 index 0000000000..0faced72e4 --- /dev/null +++ b/packages/session-query/session-query-sqlite/tests/query.spec.ts @@ -0,0 +1,179 @@ +import { describe, expect, it } from 'vitest' +import { SessionId } from '@deepseek-ai/dsh-session' +import type { SessionQueryErrorCode } from '@deepseek-ai/dsh-session-query' +import { + buildEventWhere, + buildSessionWhere, + makeSnippet, + normalizeEventRequest, + normalizeSessionRequest, + quoteFtsData, + requestFingerprint, + type NormalizedEventRequest, + type NormalizedSessionRequest, +} from '../src/query.ts' + +const limits = { defaultLimit: 2, maxLimit: 3 } + +function expectCode(code: SessionQueryErrorCode): Error { + return expect.objectContaining({ code }) as Error +} + +describe('SQLite search request normalization', () => { + it('normalizes both scopes, defaults arrays and limits, and preserves cursors', () => { + expect(normalizeSessionRequest({ query: ' alpha\n beta ' }, limits)).toEqual({ + query: 'alpha beta', + sessionFilters: [], + eventFilters: [], + limit: 2, + }) + expect(normalizeSessionRequest({ + query: 'needle', + sessionFilters: [{ kind: 'availability', values: ['live'] }], + eventFilters: [{ kind: 'surface', values: ['current'] }], + limit: 3, + cursor: 'next', + }, limits)).toEqual({ + query: 'needle', + sessionFilters: [{ kind: 'availability', values: ['live'] }], + eventFilters: [{ kind: 'surface', values: ['current'] }], + limit: 3, + cursor: 'next', + }) + expect(normalizeEventRequest({ sessionId: SessionId('s'), query: 'needle' }, limits)).toEqual({ + sessionId: SessionId('s'), + query: 'needle', + filters: [], + limit: 2, + }) + expect(normalizeEventRequest({ + sessionId: SessionId('s'), + query: 'needle', + filters: [{ kind: 'seq', from: 1 }], + cursor: 'next', + }, limits)).toEqual({ + sessionId: SessionId('s'), + query: 'needle', + filters: [{ kind: 'seq', from: 1 }], + limit: 2, + cursor: 'next', + }) + }) + + it('rejects non-text, blank, non-integer, non-positive, and oversized requests', () => { + expect(() => normalizeSessionRequest({ query: 1 as never }, limits)) + .toThrow(expectCode('SESSION_QUERY_INVALID_QUERY')) + expect(() => normalizeSessionRequest({ query: ' \n ' }, limits)) + .toThrow(expectCode('SESSION_QUERY_INVALID_QUERY')) + for (const limit of [1.5, 0, 4]) { + expect(() => normalizeEventRequest({ sessionId: SessionId('s'), query: 'x', limit }, limits)) + .toThrow(expectCode('SESSION_QUERY_INVALID_LIMIT')) + } + }) +}) + +describe('SQLite search predicate compilation', () => { + it('compiles all logical-session clauses including empty and nullable values', () => { + expect(buildSessionWhere([])).toEqual({ sql: '', params: [] }) + expect(buildSessionWhere([{ kind: 'id', values: [] }])).toEqual({ sql: '0', params: [] }) + expect(buildSessionWhere([{ kind: 'id', values: [SessionId('a'), SessionId('b')] }])).toEqual({ + sql: 'session_id IN (?, ?)', + params: [SessionId('a'), SessionId('b')], + }) + expect(buildSessionWhere([{ kind: 'cwd', values: [] }])).toEqual({ sql: '0', params: [] }) + expect(buildSessionWhere([{ kind: 'cwd', values: [null] }])).toEqual({ + sql: '(cwd IS NULL)', + params: [], + }) + expect(buildSessionWhere([{ kind: 'cwd', values: ['/a'] }])).toEqual({ + sql: '(cwd IN (?))', + params: ['/a'], + }) + expect(buildSessionWhere([{ kind: 'parent', values: [SessionId('p'), null] }])).toEqual({ + sql: '(parent_session IN (?) OR parent_session IS NULL)', + params: [SessionId('p')], + }) + expect(buildSessionWhere([ + { kind: 'created-at', from: 1, to: 2 }, + { kind: 'availability', values: [] }, + { kind: 'availability', values: ['live', 'live'] }, + { kind: 'availability', values: ['live', 'persisted'] }, + ])).toEqual({ + sql: 'CAST(created_at AS INTEGER) >= ? AND CAST(created_at AS INTEGER) <= ? AND 0 AND live = 1', + params: [1, 2], + }) + expect(buildSessionWhere([{ kind: 'created-at' }])).toEqual({ sql: '', params: [] }) + }) + + it('compiles every event clause and empty lists', () => { + expect(buildEventWhere([ + { kind: 'seq', from: 1 }, + { kind: 'time', to: 9 }, + { kind: 'type', values: ['user/message'] }, + { kind: 'surface', values: ['current', 'log-only'] }, + ])).toEqual({ + sql: 'CAST(seq AS INTEGER) >= ? AND CAST(time AS INTEGER) <= ? AND type IN (?) AND surface IN (?, ?)', + params: [1, 9, 'user/message', 'current', 'log-only'], + }) + expect(buildEventWhere([ + { kind: 'type', values: [] }, + { kind: 'surface', values: [] }, + ])).toEqual({ sql: '0 AND 0', params: [] }) + }) +}) + +describe('SQLite query identity and presentation', () => { + it('quotes all caller MATCH syntax as data', () => { + expect(quoteFtsData('say "needle" OR *')).toBe('"say ""needle"" OR *"') + }) + + it('canonicalizes request and filter ordering in both scopes', () => { + const sessionA: NormalizedSessionRequest = { + query: 'needle', + limit: 2, + sessionFilters: [ + { kind: 'cwd', values: ['/b', '/a'] }, + { kind: 'parent', values: [null, SessionId('p')] }, + { kind: 'id', values: [SessionId('same'), SessionId('same')] }, + { kind: 'created-at', from: 1 }, + ], + eventFilters: [{ kind: 'time', to: 9 }], + } + const sessionB: NormalizedSessionRequest = { + query: 'needle', + limit: 2, + sessionFilters: [ + { kind: 'created-at', from: 1 }, + { kind: 'id', values: [SessionId('same'), SessionId('same')] }, + { kind: 'parent', values: [SessionId('p'), null] }, + { kind: 'cwd', values: ['/a', '/b'] }, + ], + eventFilters: [{ kind: 'time', to: 9 }], + } + expect(requestFingerprint(sessionA)).toBe(requestFingerprint(sessionB)) + + const eventA: NormalizedEventRequest = { + sessionId: SessionId('s'), + query: 'needle', + limit: 2, + filters: [{ kind: 'seq' }, { kind: 'surface', values: ['shadowed', 'current'] }], + } + const eventB: NormalizedEventRequest = { + sessionId: SessionId('s'), + query: 'needle', + limit: 2, + filters: [{ kind: 'surface', values: ['current', 'shadowed'] }, { kind: 'seq' }], + } + expect(requestFingerprint(eventA)).toBe(requestFingerprint(eventB)) + expect(requestFingerprint(eventA)).not.toBe(requestFingerprint({ ...eventB, sessionId: SessionId('other') })) + }) + + it('normalizes, bounds, and positions snippets by Unicode code point', () => { + expect(makeSnippet(' short\ntext ', 'absent', 20)).toBe('short text') + expect(makeSnippet('abcdef', 'f', 1)).toBe('…') + expect(makeSnippet('abcdefghij', 'absent', 5)).toBe('abcd…') + expect(makeSnippet('abcdefghij', 'c', 5)).toBe('…bcd…') + expect(makeSnippet('abcdef', 'f', 2)).toBe('a…') + expect(makeSnippet('abcdef', 'f', 5)).toBe('…cdef') + }) +}) diff --git a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts new file mode 100644 index 0000000000..77d1e0125d --- /dev/null +++ b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts @@ -0,0 +1,594 @@ +import { afterEach, describe, expect, it } from 'vitest' +import { Context } from 'cordis' +import { DatabaseSync } from 'node:sqlite' +import { mkdtemp, rm } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import SessionStore, { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session' +import type { SessionEvent, SessionHeader, SessionId as SessionIdType } from '@deepseek-ai/dsh-session' +import SessionPersistence from '@deepseek-ai/dsh-session-persistence' +import SessionPersistenceSqlite from '@deepseek-ai/dsh-session-persistence-sqlite' +import SessionSearchSqlite, { + SESSION_QUERY_SQLITE_APPLICATION_ID, + SESSION_QUERY_SQLITE_SCHEMA_VERSION, +} from '@deepseek-ai/dsh-session-query-sqlite' +import type { SessionQueryErrorCode } from '@deepseek-ai/dsh-session-query' + +const temporaryDirectories: string[] = [] + +afterEach(async () => { + for (const directory of temporaryDirectories.splice(0)) { + await rm(directory, { recursive: true, force: true }) + } +}) + +async function temporaryPath(name = 'search.db'): Promise { + const directory = await mkdtemp(join(tmpdir(), 'dsh-session-search-')) + temporaryDirectories.push(directory) + return join(directory, name) +} + +function header(id: string, createdAt = 1, extra: Partial = {}): SessionHeader { + return { version: SESSION_FORMAT_VERSION, id: SessionId(id), createdAt, ...extra } +} + +function messageEvents(text: string, time = 1): SessionEvent[] { + return [{ + type: 'user/message', + seq: 0, + time, + data: { content: [{ type: 'text', text }], source: { kind: 'user' } }, + surfaceOp: 'append', + }] +} + +function expectCode(code: SessionQueryErrorCode): Error { + return expect.objectContaining({ code }) as Error +} + +class TestPersistence extends SessionPersistence { + static entries = new Map() + static listGate: Promise | undefined + static listStarted: (() => void) | undefined + static failure: unknown + + static reset(entries: readonly { meta: SessionHeader; events: SessionEvent[] }[] = []): void { + this.entries = new Map(entries.map(entry => [entry.meta.id, structuredClone(entry)])) + this.listGate = undefined + this.listStarted = undefined + this.failure = undefined + } + + create(meta: SessionHeader): Promise { + TestPersistence.entries.set(meta.id, { meta: structuredClone(meta), events: [] }) + return Promise.resolve() + } + + append(id: SessionIdType, events: readonly SessionEvent[]): Promise { + const entry = TestPersistence.entries.get(id) + if (entry === undefined) return Promise.reject(new Error('missing test session')) + entry.events.push(...structuredClone(events)) + return Promise.resolve() + } + + async load(id: SessionIdType): Promise<{ meta: SessionHeader; events: SessionEvent[] }> { + if (TestPersistence.failure !== undefined) throw TestPersistence.failure + const entry = TestPersistence.entries.get(id) + if (entry === undefined) throw new Error('missing test session') + return structuredClone(entry) + } + + async list(): Promise { + TestPersistence.listStarted?.() + await TestPersistence.listGate + if (TestPersistence.failure !== undefined) throw TestPersistence.failure + return [...TestPersistence.entries.values()].map(entry => structuredClone(entry.meta)) + } +} + +async function liveContext(config: ConstructorParameters[1] = { path: ':memory:' }): Promise { + const ctx = new Context() + await ctx.plugin(SessionStore) + await ctx.plugin(SessionSearchSqlite, config) + return ctx +} + +describe('SQLite session search', () => { + it('searches two-character Unicode61 tokens in live-only sessions', async () => { + const ctx = await liveContext({ path: ':memory:', snippetChars: 20 }) + const session = ctx.sessions.create(SessionId('live'), { meta: { cwd: '/work', createdAt: 10, seedLength: 1 } }) + session.append( + 'user/message', + { content: [{ type: 'text', text: 'An AI helper' }], source: { kind: 'user' } }, + { surfaceOp: 'append' }, + ) + + await expect(ctx.sessionSearch.searchEvents({ sessionId: session.id, query: 'AI' })) + .resolves.toMatchObject({ items: [{ sessionId: session.id, seq: 0, snippet: 'An AI helper' }] }) + await expect(ctx.sessionSearch.searchSessions({ query: 'AI' })) + .resolves.toMatchObject({ items: [{ header: { ...session.header, seedLength: 1 }, live: true, persisted: false }] }) + }) + + it('searches all surfaces by default and applies metadata before ranking', async () => { + const ctx = await liveContext({ path: ':memory:', defaultLimit: 10, maxLimit: 20 }) + const parent = SessionId('parent') + const events: SessionEvent[] = [ + { type: 'user/message', seq: 0, time: 10, data: { content: [{ type: 'text', text: 'needle original' }], source: { kind: 'user' } }, surfaceOp: 'append' }, + { type: 'assistant/chunk', seq: 1, time: 11, data: { turn: 1, step: 1, chunk: { type: 'text-delta', index: 0, text: 'needle raw' } } }, + { type: 'user/message', seq: 2, time: 12, data: { content: [{ type: 'text', text: 'needle summary' }], source: { kind: 'plugin', plugin: 'test' } }, surfaceOp: { op: 'replace', start: 0, end: 0 } }, + { type: 'turn/end', seq: 3, time: 13, data: { turn: 1, reason: { kind: 'error', step: 1, message: 'needle failure' } } }, + ] + ctx.sessions.create(SessionId('a'), { seed: events, meta: { cwd: '/a', parentSession: parent, createdAt: 20 } }) + ctx.sessions.create(SessionId('b'), { seed: messageEvents('needle peer', 12), meta: { createdAt: 20 } }) + + const all = await ctx.sessionSearch.searchEvents({ sessionId: SessionId('a'), query: 'needle' }) + expect(new Set(all.items.map(item => item.surface))).toEqual(new Set(['current', 'shadowed', 'log-only'])) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: SessionId('a'), + query: 'needle', + filters: [ + { kind: 'seq', from: 2, to: 2 }, + { kind: 'time', from: 12, to: 12 }, + { kind: 'type', values: ['user/message'] }, + { kind: 'surface', values: ['current'] }, + ], + })).resolves.toMatchObject({ items: [{ seq: 2, surface: 'current' }] }) + + const grouped = await ctx.sessionSearch.searchSessions({ + query: 'needle', + sessionFilters: [ + { kind: 'id', values: [SessionId('a')] }, + { kind: 'cwd', values: ['/a'] }, + { kind: 'created-at', from: 20, to: 20 }, + { kind: 'parent', values: [parent] }, + { kind: 'availability', values: ['live'] }, + ], + eventFilters: [{ kind: 'surface', values: ['shadowed'] }], + }) + expect(grouped.items).toHaveLength(1) + expect(grouped.items[0]).toMatchObject({ + header: { id: SessionId('a'), cwd: '/a', parentSession: parent }, + live: true, + persisted: false, + bestMatch: { seq: 0, surface: 'shadowed' }, + }) + }) + + it('uses literal phrase tokens, stable ties, and bounded Unicode snippets', async () => { + const ctx = await liveContext({ path: ':memory:', defaultLimit: 10, maxLimit: 10, snippetChars: 5 }) + ctx.sessions.create(SessionId('a'), { seed: messageEvents('😀😀 alpha beta BRAID 😀😀', 10), meta: { createdAt: 1 } }) + ctx.sessions.create(SessionId('b'), { seed: messageEvents('alpha beta', 10), meta: { createdAt: 1 } }) + ctx.sessions.create(SessionId('c'), { seed: messageEvents('alpha middle beta', 10), meta: { createdAt: 1 } }) + ctx.sessions.create(SessionId('d'), { seed: messageEvents('alpha beta', 10), meta: { createdAt: 1 } }) + ctx.sessions.create(SessionId('operator'), { seed: messageEvents('needle OR absent', 10), meta: { createdAt: 1 } }) + ctx.sessions.create(SessionId('only'), { seed: messageEvents('needle only', 10), meta: { createdAt: 1 } }) + ctx.sessions.create(SessionId('quote'), { seed: messageEvents('say "needle" exactly', 10), meta: { createdAt: 1 } }) + + const phrase = await ctx.sessionSearch.searchSessions({ query: 'alpha beta' }) + expect(phrase.items.map(item => item.header.id)).toEqual([SessionId('b'), SessionId('d'), SessionId('a')]) + expect(phrase.items.every(item => Array.from(item.bestMatch.snippet).length <= 5)).toBe(true) + await expect(ctx.sessionSearch.searchSessions({ query: 'AI' })).resolves.toEqual({ items: [] }) + await expect(ctx.sessionSearch.searchSessions({ query: 'needle OR absent' })) + .resolves.toMatchObject({ items: [{ header: { id: SessionId('operator') } }] }) + await expect(ctx.sessionSearch.searchSessions({ query: 'say "needle"' })) + .resolves.toMatchObject({ items: [{ header: { id: SessionId('quote') } }] }) + await expect(ctx.sessionSearch.searchSessions({ query: '*' })).resolves.toEqual({ items: [] }) + }) + + it('binds cursors to requests and only invalidates within-session pages for target changes', async () => { + const ctx = await liveContext({ path: ':memory:', defaultLimit: 1, maxLimit: 5 }) + const target = ctx.sessions.create(SessionId('target'), { + seed: [ + ...messageEvents('needle one', 10), + { ...messageEvents('needle two', 11)[0]!, seq: 1 }, + { ...messageEvents('needle three', 12)[0]!, seq: 2 }, + ], + }) + ctx.sessions.create(SessionId('other'), { seed: messageEvents('needle other', 10) }) + + const eventPage = await ctx.sessionSearch.searchEvents({ sessionId: target.id, query: 'needle', limit: 1 }) + const sessionPage = await ctx.sessionSearch.searchSessions({ query: 'needle', limit: 1 }) + expect(eventPage.nextCursor).toEqual(expect.any(String)) + expect(sessionPage.nextCursor).toEqual(expect.any(String)) + if (eventPage.nextCursor === undefined || sessionPage.nextCursor === undefined) throw new Error('expected cursors') + + const eventKeys = eventPage.items.map(item => `${item.sessionId}:${item.seq}`) + let eventCursor: string | undefined = eventPage.nextCursor + while (eventCursor !== undefined) { + const next = await ctx.sessionSearch.searchEvents({ + sessionId: target.id, + query: 'needle', + limit: 1, + cursor: eventCursor, + }) + eventKeys.push(...next.items.map(item => `${item.sessionId}:${item.seq}`)) + eventCursor = next.nextCursor + } + expect(eventKeys).toHaveLength(3) + expect(new Set(eventKeys).size).toBe(eventKeys.length) + + const sessionIds = sessionPage.items.map(item => item.header.id) + let sessionCursor: string | undefined = sessionPage.nextCursor + while (sessionCursor !== undefined) { + const next = await ctx.sessionSearch.searchSessions({ query: 'needle', limit: 1, cursor: sessionCursor }) + sessionIds.push(...next.items.map(item => item.header.id)) + sessionCursor = next.nextCursor + } + expect(sessionIds).toHaveLength(2) + expect(new Set(sessionIds).size).toBe(sessionIds.length) + + ctx.sessions.create(SessionId('unrelated'), { seed: messageEvents('needle unrelated', 20) }) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: target.id, + query: 'needle', + limit: 1, + cursor: eventPage.nextCursor, + })).resolves.toMatchObject({ items: [{ sessionId: target.id }] }) + await expect(ctx.sessionSearch.searchSessions({ query: 'needle', limit: 1, cursor: sessionPage.nextCursor })) + .rejects.toThrow(expectCode('SESSION_QUERY_STALE_CURSOR')) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: target.id, + query: 'different', + limit: 1, + cursor: eventPage.nextCursor, + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_CURSOR')) + + target.append('user/message', { content: [{ type: 'text', text: 'needle four' }], source: { kind: 'user' } }, { surfaceOp: 'append' }) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: target.id, + query: 'needle', + limit: 1, + cursor: eventPage.nextCursor, + })).rejects.toThrow(expectCode('SESSION_QUERY_STALE_CURSOR')) + }) + + it('rejects invalid requests, filters, cursors, and direct config', async () => { + const ctx = await liveContext({ path: ':memory:', defaultLimit: 2, maxLimit: 3 }) + const session = ctx.sessions.create(SessionId('valid'), { seed: messageEvents('needle') }) + for (const request of [ + { sessionId: session.id, query: '' }, + { sessionId: session.id, query: 'needle', limit: 0 }, + { sessionId: session.id, query: 'needle', limit: 4 }, + { sessionId: session.id, query: 'needle', filters: [{ kind: 'seq', from: 2, to: 1 }] }, + { sessionId: session.id, query: 'needle', filters: [{ kind: 'surface', values: ['future'] }] }, + ] as const) { + await expect(ctx.sessionSearch.searchEvents(request as never)).rejects.toBeInstanceOf(Error) + } + await expect(ctx.sessionSearch.searchSessions({ + query: 'needle', + sessionFilters: [{ kind: 'availability', values: ['remote' as never] }], + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + await expect(ctx.sessionSearch.searchEvents({ sessionId: session.id, query: 'needle', cursor: 'not-json' })) + .rejects.toThrow(expectCode('SESSION_QUERY_INVALID_CURSOR')) + await expect(ctx.sessionSearch.searchEvents({ sessionId: SessionId('absent'), query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_SESSION_NOT_FOUND')) + + for (const config of [ + { path: '' }, + { path: ':memory:', defaultLimit: 0 }, + { path: ':memory:', maxLimit: 0 }, + { path: ':memory:', snippetChars: 0 }, + { path: ':memory:', defaultLimit: 3, maxLimit: 2 }, + { path: ':memory:', journalMode: 'memory' }, + ]) { + const direct = new Context() + await direct.plugin(SessionStore) + expect(() => new SessionSearchSqlite(direct, config as never)) + .toThrow(expectCode('SESSION_QUERY_INVALID_CONFIG')) + } + }) +}) + +describe('SQLite reconciliation and source lifecycle', () => { + it('mounts persistence dynamically, shadows with TEMP live rows, reveals, and hides on unmount', async () => { + const shared = header('shared', 10, { cwd: '/work' }) + const durable = header('durable', 5) + TestPersistence.reset([ + { meta: shared, events: messageEvents('persisted needle') }, + { meta: durable, events: messageEvents('durable needle') }, + ]) + const ctx = await liveContext() + await expect(ctx.sessionSearch.searchSessions({ query: 'durable' })).resolves.toEqual({ items: [] }) + const persistenceFiber = await ctx.plugin(TestPersistence) + + await expect(ctx.sessionSearch.searchSessions({ query: 'durable' })) + .resolves.toMatchObject({ items: [{ header: durable, live: false, persisted: true }] }) + const live = ctx.sessions.prepare(shared.id, { meta: { createdAt: 10, cwd: '/work' } }) + live.append('user/message', { content: [{ type: 'text', text: 'live needle' }], source: { kind: 'user' } }, { surfaceOp: 'append' }) + const detach = ctx.sessions.enter(live) + ctx.sessions.announce(live) + + await expect(ctx.sessionSearch.searchSessions({ query: 'persisted' })).resolves.toEqual({ items: [] }) + await expect(ctx.sessionSearch.searchSessions({ query: 'live' })) + .resolves.toMatchObject({ items: [{ header: shared, live: true, persisted: true }] }) + detach() + await expect(ctx.sessionSearch.searchSessions({ query: 'persisted' })) + .resolves.toMatchObject({ items: [{ header: shared, live: false, persisted: true }] }) + + await persistenceFiber.dispose() + await expect(ctx.sessionSearch.searchSessions({ query: 'durable' })).resolves.toEqual({ items: [] }) + await expect(ctx.sessionSearch.searchEvents({ sessionId: durable.id, query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_SESSION_NOT_FOUND')) + }) + + it('restarts observation when persistence unmounts during an asynchronous list', async () => { + const durable = header('racing') + TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) + const ctx = await liveContext() + const persistenceFiber = await ctx.plugin(TestPersistence) + let release!: () => void + TestPersistence.listGate = new Promise((resolve) => { release = resolve }) + let markStarted!: () => void + const started = new Promise((resolve) => { markStarted = resolve }) + TestPersistence.listStarted = () => { + TestPersistence.listStarted = undefined + markStarted() + } + + const search = ctx.sessionSearch.searchSessions({ query: 'needle' }) + await started + await persistenceFiber.dispose() + release() + await expect(search).resolves.toEqual({ items: [] }) + }) + + it('rejects immutable header conflicts between live and persisted sources', async () => { + const shared = header('conflict', 10) + TestPersistence.reset([{ meta: shared, events: messageEvents('persisted needle') }]) + const ctx = await liveContext() + await ctx.plugin(TestPersistence) + ctx.sessions.create(shared.id, { seed: messageEvents('live needle'), meta: { createdAt: 11 } }) + + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_SOURCE_CONFLICT')) + }) + + it('preserves unchanged persisted generations while reconciling new, changed, and deleted rows', async () => { + const path = await temporaryPath() + const unchanged = header('unchanged') + const changed = header('changed') + const deleted = header('deleted') + TestPersistence.reset([ + { meta: unchanged, events: messageEvents('unchanged needle') }, + { meta: changed, events: messageEvents('old needle') }, + { meta: deleted, events: messageEvents('deleted needle') }, + ]) + const first = new Context() + await first.plugin(SessionStore) + const firstPersistence = await first.plugin(TestPersistence) + const firstSearch = await first.plugin(SessionSearchSqlite, { path }) + await first.sessionSearch.searchSessions({ query: 'needle' }) + await firstSearch.dispose() + await firstPersistence.dispose() + + const beforeDb = new DatabaseSync(path) + const beforeRows = beforeDb.prepare('SELECT id, generation FROM persisted_sessions ORDER BY id').all() as Array<{ id: string; generation: number }> + beforeDb.close() + const before = new Map(beforeRows.map(row => [row.id, row.generation])) + + const added = header('added') + TestPersistence.entries.delete(deleted.id) + TestPersistence.entries.set(changed.id, { meta: changed, events: messageEvents('changed needle') }) + TestPersistence.entries.set(added.id, { meta: added, events: messageEvents('added needle') }) + const second = new Context() + await second.plugin(SessionStore) + const secondPersistence = await second.plugin(TestPersistence) + const secondSearch = await second.plugin(SessionSearchSqlite, { path }) + const result = await second.sessionSearch.searchSessions({ query: 'needle' }) + expect(result.items.map(item => item.header.id).sort()).toEqual([added.id, changed.id, unchanged.id].sort()) + await secondSearch.dispose() + await secondPersistence.dispose() + + const afterDb = new DatabaseSync(path) + const afterRows = afterDb.prepare('SELECT id, generation FROM persisted_sessions ORDER BY id').all() as Array<{ id: string; generation: number }> + afterDb.close() + const after = new Map(afterRows.map(row => [row.id, row.generation])) + expect(after.get(unchanged.id)).toBe(before.get(unchanged.id)) + expect(after.get(changed.id)).toBeGreaterThan(before.get(changed.id)!) + expect(after.has(deleted.id)).toBe(false) + expect(after.has(added.id)).toBe(true) + }) + + it('drops connection-local live overlays on reopen and retains persistent bases', async () => { + const path = await temporaryPath() + const shared = header('shared', 10) + TestPersistence.reset([{ meta: shared, events: messageEvents('persisted needle') }]) + const first = new Context() + await first.plugin(SessionStore) + const persistence = await first.plugin(TestPersistence) + const live = first.sessions.create(shared.id, { seed: messageEvents('live needle'), meta: { createdAt: 10 } }) + const search = await first.plugin(SessionSearchSqlite, { path }) + await expect(first.sessionSearch.searchEvents({ sessionId: live.id, query: 'live' })).resolves.toMatchObject({ items: [{}] }) + await search.dispose() + await persistence.dispose() + + const second = new Context() + await second.plugin(SessionStore) + const persistenceAgain = await second.plugin(TestPersistence) + const searchAgain = await second.plugin(SessionSearchSqlite, { path }) + await expect(second.sessionSearch.searchSessions({ query: 'live' })).resolves.toEqual({ items: [] }) + await expect(second.sessionSearch.searchSessions({ query: 'persisted' })) + .resolves.toMatchObject({ items: [{ header: shared, live: false, persisted: true }] }) + await searchAgain.dispose() + await persistenceAgain.dispose() + }) + + it('recovers on the next search after source and SQLite transaction failures', async () => { + TestPersistence.reset([{ meta: header('durable'), events: messageEvents('durable needle') }]) + const ctx = await liveContext() + await ctx.plugin(TestPersistence) + TestPersistence.failure = 'offline' + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_PERSISTENCE_FAILED')) + const signal = new AbortController().signal + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' }, { signal })) + .rejects.toThrow(expectCode('SESSION_QUERY_PERSISTENCE_FAILED')) + TestPersistence.failure = new Error('still offline') + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' }, { signal })) + .rejects.toThrow(expectCode('SESSION_QUERY_PERSISTENCE_FAILED')) + TestPersistence.failure = undefined + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })).resolves.toMatchObject({ items: [{}] }) + + const live = ctx.sessions.create(SessionId('live'), { seed: messageEvents('base') }) + await ctx.sessionSearch.searchEvents({ sessionId: live.id, query: 'base' }) + const db = (ctx.sessionSearch as unknown as { _db: DatabaseSync })._db + db.exec('PRAGMA query_only = ON') + live.append('user/message', { content: [{ type: 'text', text: 'retry needle' }], source: { kind: 'user' } }, { surfaceOp: 'append' }) + await expect(ctx.sessionSearch.searchEvents({ sessionId: live.id, query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_INDEX_FAILED')) + db.exec('PRAGMA query_only = OFF') + await expect(ctx.sessionSearch.searchEvents({ sessionId: live.id, query: 'needle' })) + .resolves.toMatchObject({ items: [{ seq: 1 }] }) + }) +}) + +describe('SQLite schema, cancellation, and real persistence integration', () => { + it('resets a recognized incompatible derived schema but refuses a foreign database', async () => { + const stalePath = await temporaryPath('stale.db') + const stale = new DatabaseSync(stalePath) + stale.exec(`PRAGMA application_id = ${SESSION_QUERY_SQLITE_APPLICATION_ID}`) + stale.exec('PRAGMA user_version = 999') + stale.exec('CREATE TABLE stale(value TEXT)') + stale.close() + const staleCtx = await liveContext({ path: stalePath }) + staleCtx.sessions.create(SessionId('live'), { seed: messageEvents('needle') }) + await staleCtx.sessionSearch.searchSessions({ query: 'needle' }) + await (staleCtx.sessionSearch as SessionSearchSqlite).close() + const rebuilt = new DatabaseSync(stalePath) + expect((rebuilt.prepare('PRAGMA user_version').get() as { user_version: number }).user_version) + .toBe(SESSION_QUERY_SQLITE_SCHEMA_VERSION) + expect(rebuilt.prepare("SELECT name FROM sqlite_master WHERE name = 'stale'").get()).toBeUndefined() + rebuilt.close() + + const foreignPath = await temporaryPath('foreign.db') + const foreign = new DatabaseSync(foreignPath) + foreign.exec('CREATE TABLE canonical(value TEXT)') + foreign.exec("INSERT INTO canonical VALUES ('safe')") + foreign.close() + const foreignCtx = await liveContext({ path: foreignPath }) + await expect(foreignCtx.sessionSearch.searchSessions({ query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_INDEX_FAILED')) + const stillForeign = new DatabaseSync(foreignPath) + expect(stillForeign.prepare('SELECT value FROM canonical').get()).toEqual({ value: 'safe' }) + stillForeign.close() + + const otherAppPath = await temporaryPath('other-app.db') + const otherApp = new DatabaseSync(otherAppPath) + otherApp.exec('PRAGMA application_id = 123') + otherApp.close() + const otherAppCtx = await liveContext({ path: otherAppPath }) + await expect(otherAppCtx.sessionSearch.searchSessions({ query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_INDEX_FAILED')) + }) + + it('cancels both queued and in-flight source waits without committing them', async () => { + TestPersistence.reset() + const ctx = await liveContext() + await ctx.plugin(TestPersistence) + + const boundaryController = new AbortController() + const boundary = ctx.sessionSearch.searchSessions({ query: 'needle' }, { signal: boundaryController.signal }) + queueMicrotask(() => { boundaryController.abort() }) + await expect(boundary).rejects.toThrow(expectCode('SESSION_QUERY_ABORTED')) + + const readyController = new AbortController() + readyController.abort() + const internals = ctx.sessionSearch as unknown as { + _ensureReady(signal: AbortSignal): Promise + } + await expect(internals._ensureReady(readyController.signal)) + .rejects.toThrow(expectCode('SESSION_QUERY_ABORTED')) + + let releaseBlocking!: () => void + TestPersistence.listGate = new Promise((resolve) => { releaseBlocking = resolve }) + let markBlockingStarted!: () => void + const blockingStarted = new Promise((resolve) => { markBlockingStarted = resolve }) + TestPersistence.listStarted = () => { + TestPersistence.listStarted = undefined + markBlockingStarted() + } + const blocking = ctx.sessionSearch.searchSessions({ query: 'needle' }) + await blockingStarted + + const queuedController = new AbortController() + const queued = ctx.sessionSearch.searchSessions({ query: 'needle' }, { signal: queuedController.signal }) + queuedController.abort() + await expect(queued).rejects.toThrow(expectCode('SESSION_QUERY_ABORTED')) + + releaseBlocking() + await expect(blocking).resolves.toEqual({ items: [] }) + + TestPersistence.entries.set(SessionId('uncommitted'), { + meta: header('uncommitted'), + events: messageEvents('durable needle'), + }) + let releaseActive!: () => void + TestPersistence.listGate = new Promise((resolve) => { releaseActive = resolve }) + let markActiveStarted!: () => void + const activeStarted = new Promise((resolve) => { markActiveStarted = resolve }) + TestPersistence.listStarted = () => { + TestPersistence.listStarted = undefined + markActiveStarted() + } + const activeController = new AbortController() + const active = ctx.sessionSearch.searchSessions({ query: 'needle' }, { signal: activeController.signal }) + await activeStarted + activeController.abort() + await expect(active).rejects.toThrow(expectCode('SESSION_QUERY_ABORTED')) + releaseActive() + + const db = (ctx.sessionSearch as unknown as { _db: DatabaseSync })._db + expect(db.prepare('SELECT COUNT(*) AS count FROM persisted_sessions').get()).toEqual({ count: 0 }) + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })) + .resolves.toMatchObject({ items: [{ header: { id: SessionId('uncommitted') } }] }) + }) + + it('rejects queued and future work when close waits for an accepted operation', async () => { + TestPersistence.reset() + let release!: () => void + TestPersistence.listGate = new Promise((resolve) => { release = resolve }) + let markStarted!: () => void + const started = new Promise((resolve) => { markStarted = resolve }) + TestPersistence.listStarted = () => { + TestPersistence.listStarted = undefined + markStarted() + } + const ctx = await liveContext() + await ctx.plugin(TestPersistence) + const search = ctx.sessionSearch as SessionSearchSqlite + const accepted = search.searchSessions({ query: 'needle' }) + await started + const queued = search.searchSessions({ query: 'needle' }) + const closing = search.close() + release() + + await expect(accepted).resolves.toEqual({ items: [] }) + await expect(queued).rejects.toThrow(expectCode('SESSION_QUERY_INDEX_FAILED')) + await closing + await expect(search.searchSessions({ query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_INDEX_FAILED')) + await search.close() + }) + + it('combines the real SQLite persistence backend with the real search service keylessly', async () => { + const persistencePath = await temporaryPath('canonical.db') + const searchPath = await temporaryPath('derived.db') + const ctx = new Context() + await ctx.plugin(SessionStore) + const persistence = await ctx.plugin(SessionPersistenceSqlite, { path: persistencePath }) + const search = await ctx.plugin(SessionSearchSqlite, { path: searchPath }) + const meta = header('real', 10, { cwd: '/work' }) + await ctx.sessionPersistence.create(meta) + await ctx.sessionPersistence.append(meta.id, messageEvents('real SQLite needle')) + + await expect(ctx.sessionSearch.searchSessions({ query: 'SQLite needle' })) + .resolves.toMatchObject({ items: [{ header: meta, persisted: true, live: false }] }) + await expect(ctx.sessionSearch.searchEvents({ sessionId: meta.id, query: 'SQLite needle' })) + .resolves.toMatchObject({ items: [{ sessionId: meta.id, seq: 0 }] }) + await expect(ctx.sessionSearch.searchEvents({ sessionId: SessionId('absent'), query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_SESSION_NOT_FOUND')) + await search.dispose() + await expect(ctx.sessionPersistence.load(meta.id)).resolves.toMatchObject({ meta, events: [{ seq: 0 }] }) + await persistence.dispose() + }) +}) diff --git a/packages/session-query/session-query-sqlite/tsconfig.json b/packages/session-query/session-query-sqlite/tsconfig.json new file mode 100644 index 0000000000..ea16cdbe96 --- /dev/null +++ b/packages/session-query/session-query-sqlite/tsconfig.json @@ -0,0 +1,30 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib/types" + }, + "include": [ + "src" + ], + "references": [ + { + "path": "../../../vendor/cosmokit" + }, + { + "path": "../../../vendor/cordis" + }, + { + "path": "../../../vendor/schemastery" + }, + { + "path": "../../core/session" + }, + { + "path": "../../session-persistence/session-persistence" + }, + { + "path": "../session-query" + } + ] +} diff --git a/packages/session-query/session-query/README.md b/packages/session-query/session-query/README.md index 55f9b32fcd..6f9e9bbd7a 100644 --- a/packages/session-query/session-query/README.md +++ b/packages/session-query/session-query/README.md @@ -1,6 +1,6 @@ # @deepseek-ai/dsh-session-query -Exact session-history retrieval through `ctx.sessionQuery`. The service presents live `ctx.sessions` and an optional, dynamically mounted `ctx.sessionPersistence` as one logical corpus. Matching ids produce one record: live events win, while `live` and `persisted` report both source availabilities. Conflicting immutable headers fail with `SESSION_QUERY_SOURCE_CONFLICT`. +Session-history query contracts and provider-independent helpers. The concrete `ctx.sessionQuery` service presents live `ctx.sessions` and an optional, dynamically mounted `ctx.sessionPersistence` as one logical corpus for exact reads and semantic scans. The abstract `ctx.sessionSearch` service defines full-text search without introducing a provider registry. This is trusted context-wide infrastructure. It performs no caller authorization; a future model tool or UI must constrain which sessions its caller may inspect. @@ -8,11 +8,24 @@ This is trusted context-wide infrastructure. It performs no caller authorization - `listSessions()` reads current persistence metadata, merges live records with live precedence, and returns cloned records in deterministic newest-first order. - `listEvents(sessionId)` loads the live-preferred raw log and classifies each event as `current`, `shadowed`, or `log-only` with the shared `dsh-session` surface fold. +- `filterEvents(sessionId, filters)` extracts first-party semantic documents and applies provider-independent metadata and literal-text predicates in ascending seq order. - `readEvent(request)` returns a cloned header, the full target event, and a bounded raw-seq window. `before` and `after` default to zero and may not exceed `readWindowMax`. Persistence is optional and may mount or unmount dynamically. A cross-corpus list fails with `SESSION_QUERY_PERSISTENCE_FAILED` while mounted persistence is unreadable. A read targeting a known live session does not consult persistence, so durable backend health cannot make current in-memory history unreadable. Persisted exact reads list before loading, and reject a metadata mismatch rather than combining inconsistent observations. -`SessionQueryError.code` is a closed union: `SESSION_QUERY_EVENT_NOT_FOUND`, `SESSION_QUERY_INVALID_CONFIG`, `SESSION_QUERY_INVALID_SURFACE`, `SESSION_QUERY_INVALID_WINDOW`, `SESSION_QUERY_PERSISTENCE_FAILED`, `SESSION_QUERY_SESSION_NOT_FOUND`, and `SESSION_QUERY_SOURCE_CONFLICT`. +## Filtering and extraction + +`SessionResultFilter` covers id, nullable cwd, created-at range, nullable parent, and source availability. `SessionEventResultFilter` covers seq/time ranges, event type, surface, and semantic text. Filter arrays are ANDed; values within one list clause are ORed. Empty list values match nothing, ranges are inclusive, and malformed ranges or closed-union values fail with `SESSION_QUERY_INVALID_FILTER`. + +The text clause is deliberately independent of FTS providers: caller text is escaped into a Unicode, case-insensitive regular expression, and each whitespace run matches one or more whitespace characters. It is a literal semantic-text scan, not a full-text query. `extractSessionEventText()` and `buildSessionEventSearchDocuments()` define the shared first-party document projection; structural boundaries, stream chunks, request headers, and unknown declaration-merged variants produce no document. + +## Full-text seam + +`SessionSearchService` owns the independent `ctx.sessionSearch` key. `searchSessions(request, exec?)` groups the logical corpus by strongest matching event; `searchEvents(request, exec?)` searches one logical session. Both return opaque cursor pages, accept optional cancellation, and expose snippets without provider-specific numeric scores. Search requests accept only metadata event filters, because literal-text filtering is the scan path described above. + +The package has no provider coordinator or registration protocol. A concrete backend owns observation, reconciliation, ranking, cursor generations, and query execution as one lifecycle; the first implementation is [`@deepseek-ai/dsh-session-query-sqlite`](../session-query-sqlite/README.md). + +`SessionQueryError.code` is a closed union covering request validation, missing targets, malformed surfaces, source conflicts, persistence/index failures, cancellation, and invalid or stale cursors; the exact literals are defined in [`src/config.ts`](src/config.ts). ## Configuration @@ -20,4 +33,4 @@ Persistence is optional and may mount or unmount dynamically. A cross-corpus lis |---|---:|---| | `readWindowMax` | `50` | Maximum `before` or `after` raw-event count. | -This phase deliberately has no filters, lineage/provenance traversal, extraction registry, search-provider protocol, index synchronization, or model-facing tool. Full-text search belongs beside its first real implementation; the proposed SQLite package and its single transaction/reconciliation owner are described in the [phase-two RFC](../../../docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md). +The package deliberately has no lineage/provenance traversal, extractor registry, search-provider registry, index synchronization, caller authorization, or model-facing tool. The SQLite ownership and tokenizer decisions are recorded in the [implemented search RFC](../../../docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md). diff --git a/packages/session-query/session-query/src/config.ts b/packages/session-query/session-query/src/config.ts index 2736f68cbd..296d3830c6 100644 --- a/packages/session-query/session-query/src/config.ts +++ b/packages/session-query/session-query/src/config.ts @@ -1,4 +1,4 @@ -/** Public configuration and typed failures for session-query. */ +/** Public configuration and typed failures for session-query and search. */ import { HarnessError } from '@deepseek-ai/dsh-llm' @@ -11,14 +11,21 @@ export interface Config { readWindowMax?: number } -/** Stable machine-routable failure taxonomy for exact session reads. */ +/** Stable machine-routable failure taxonomy for session reads and search. */ export type SessionQueryErrorCode = + | 'SESSION_QUERY_ABORTED' | 'SESSION_QUERY_EVENT_NOT_FOUND' + | 'SESSION_QUERY_INDEX_FAILED' | 'SESSION_QUERY_INVALID_CONFIG' + | 'SESSION_QUERY_INVALID_CURSOR' + | 'SESSION_QUERY_INVALID_FILTER' + | 'SESSION_QUERY_INVALID_LIMIT' + | 'SESSION_QUERY_INVALID_QUERY' | 'SESSION_QUERY_INVALID_SURFACE' | 'SESSION_QUERY_INVALID_WINDOW' | 'SESSION_QUERY_PERSISTENCE_FAILED' | 'SESSION_QUERY_SESSION_NOT_FOUND' + | 'SESSION_QUERY_STALE_CURSOR' | 'SESSION_QUERY_SOURCE_CONFLICT' /** Typed session-query failure whose `code` is one closed taxonomy member. */ diff --git a/packages/session-query/session-query/src/corpus.ts b/packages/session-query/session-query/src/corpus.ts index ebc3d92577..c8ddca3caa 100644 --- a/packages/session-query/session-query/src/corpus.ts +++ b/packages/session-query/session-query/src/corpus.ts @@ -5,6 +5,7 @@ import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek- import type SessionPersistence from '@deepseek-ai/dsh-session-persistence' import type { SessionRecord } from './types.ts' import { SessionQueryError } from './config.ts' +import { assertSessionHeadersCompatible } from './sources.ts' /** Detached source selected for one exact read. */ export interface LogicalSession { @@ -45,7 +46,7 @@ export class SessionCorpus { } for (const session of this._ctx.sessions.list()) { const durable = records.get(session.id) - if (durable !== undefined) assertCompatibleHeaders(session.header, durable.header) + if (durable !== undefined) assertSessionHeadersCompatible(session.header, durable.header) records.set(session.id, { header: structuredClone(session.header), live: true, @@ -80,7 +81,7 @@ export class SessionCorpus { { cause: error }, ) } - assertCompatibleHeaders(loaded.meta, listed) + assertSessionHeadersCompatible(loaded.meta, listed) return { header: structuredClone(loaded.meta), events: loaded.events.map(event => structuredClone(event)), @@ -107,22 +108,6 @@ function snapshotLive(session: Session): LogicalSession { } } -function assertCompatibleHeaders(a: SessionHeader, b: SessionHeader): void { - if ( - a.version !== b.version - || a.id !== b.id - || a.createdAt !== b.createdAt - || a.cwd !== b.cwd - || a.parentSession !== b.parentSession - || a.seedLength !== b.seedLength - ) { - throw new SessionQueryError( - `live and persisted headers conflict for session "${a.id}"`, - 'SESSION_QUERY_SOURCE_CONFLICT', - ) - } -} - function compareSessions(a: SessionRecord, b: SessionRecord): number { return b.header.createdAt - a.header.createdAt || a.header.id.localeCompare(b.header.id) } diff --git a/packages/session-query/session-query/src/documents.ts b/packages/session-query/session-query/src/documents.ts new file mode 100644 index 0000000000..f58029ae67 --- /dev/null +++ b/packages/session-query/session-query/src/documents.ts @@ -0,0 +1,74 @@ +/** Shared event metadata and semantic-document projection. */ + +import { foldSurface } from '@deepseek-ai/dsh-session' +import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session' +import type { SessionEventRecord, SessionEventSearchDocument, SessionEventSurface } from './types.ts' +import { SessionQueryError } from './config.ts' +import { extractSessionEventText } from './extraction.ts' + +/** + * Project a raw log into lightweight surface-aware event records. + * @param sessionId - session that owns the log. + * @param events - complete contiguous raw event log. + * @returns one record per event in ascending seq order. + */ +export function buildSessionEventRecords( + sessionId: SessionId, + events: readonly SessionEvent[], +): SessionEventRecord[] { + const surfaceBySeq = classifySurface(events) + return events.map(event => ({ + sessionId, + seq: event.seq, + type: event.type, + time: event.time, + surface: surfaceBySeq.get(event.seq) ?? 'log-only', + })) +} + +/** + * Build first-party semantic documents for one complete raw event log. + * @param sessionId - session that owns the log. + * @param events - complete contiguous raw event log. + * @returns searchable documents in ascending seq order; structural events are omitted. + */ +export function buildSessionEventSearchDocuments( + sessionId: SessionId, + events: readonly SessionEvent[], +): SessionEventSearchDocument[] { + const surfaceBySeq = classifySurface(events) + const documents: SessionEventSearchDocument[] = [] + for (const event of events) { + const text = extractSessionEventText(event) + if (text.length === 0) continue + documents.push({ + sessionId, + seq: event.seq, + type: event.type, + time: event.time, + surface: surfaceBySeq.get(event.seq) ?? 'log-only', + text, + }) + } + return documents +} + +function classifySurface(events: readonly SessionEvent[]): Map { + let folded: ReturnType + try { + folded = foldSurface(events) + } catch (error: unknown) { + throw new SessionQueryError( + /* v8 ignore next -- foldSurface throws Error instances */ + `invalid session surface: ${error instanceof Error ? error.message : 'unknown error'}`, + 'SESSION_QUERY_INVALID_SURFACE', + { cause: error }, + ) + } + const result = new Map() + for (const node of folded.nodes) result.set(node.seq, 'current') + for (const replacement of folded.replacements) { + for (const seq of replacement.shadowedSeqs) result.set(seq, 'shadowed') + } + return result +} diff --git a/packages/session-query/session-query/src/extraction.ts b/packages/session-query/session-query/src/extraction.ts new file mode 100644 index 0000000000..96a0af247b --- /dev/null +++ b/packages/session-query/session-query/src/extraction.ts @@ -0,0 +1,93 @@ +/** First-party semantic text extraction for session-query consumers. */ + +import type { SessionEvent } from '@deepseek-ai/dsh-session' + +/** + * Extract searchable semantic text from one first-party session event. + * + * Structural boundaries, raw stream chunks, request envelopes, and unknown + * declaration-merged events contribute no text. + * @param event - event to inspect. + * @returns newline-joined semantic text, or an empty string when non-searchable. + */ +export function extractSessionEventText(event: SessionEvent): string { + switch (event.type) { + case 'user/message': + case 'assistant/message': + case 'context/message': + case 'steering/message': + return contentText(event.data.content) + case 'prompt/blocked': + return joinText([contentText(event.data.content), event.data.reason]) + case 'tool/call': + return joinText([event.data.name, event.data.arguments]) + case 'tool/result': + return joinText([ + contentText(event.data.content), + event.data.error?.name ?? '', + event.data.error?.code ?? '', + ]) + case 'todo/write': + return joinText(event.data.todos.flatMap(todo => [todo.status, todo.content])) + case 'turn/end': + return turnEndText(event.data.reason) + case 'turn/start': + case 'step/start': + case 'step/end': + case 'assistant/chunk': + case 'request/header': + case 'request/header-delta': + return '' + // SessionEventMap is merge-extensible. Unknown events remain + // non-searchable until a concrete first-party consumer defines semantics. + default: + return '' + } +} + +function turnEndText(reason: SessionEvent<'turn/end'>['data']['reason']): string { + switch (reason.kind) { + case 'error': + return joinText(['error', reason.message, reason.code ?? '']) + case 'aborted': + return joinText(['aborted', reason.reason ?? '']) + case 'rejected': + return joinText(['rejected', reason.reason]) + case 'disposed': + case 'max-tokens': + case 'interrupted': + return reason.kind + case 'completed': + return '' + // TurnEndReasonMap is merge-extensible. Unknown outcomes stay out until + // their owner defines which detail is semantic rather than structural. + default: + return '' + } +} + +type SessionContentBlock = SessionEvent<'user/message'>['data']['content'][number] + +function contentText(content: readonly SessionContentBlock[]): string { + return joinText(content.flatMap(blockText)) +} + +function blockText(block: SessionContentBlock): string[] { + switch (block.type) { + case 'text': + case 'reasoning': + return [block.text] + case 'tool-call': + return [block.name, block.arguments] + case 'tool-result': + return block.content.flatMap(blockText) + // ContentBlockMap is merge-extensible. Unknown blocks do not become + // searchable merely because their payload happens to contain strings. + default: + return [] + } +} + +function joinText(parts: readonly string[]): string { + return parts.map(part => part.trim()).filter(Boolean).join('\n') +} diff --git a/packages/session-query/session-query/src/filters.ts b/packages/session-query/session-query/src/filters.ts new file mode 100644 index 0000000000..c7a7b40dd4 --- /dev/null +++ b/packages/session-query/session-query/src/filters.ts @@ -0,0 +1,132 @@ +/** Pure provider-independent predicates for logical sessions and event text. */ + +import type { SessionRecord, SessionEventSearchDocument, SessionEventResultFilter, SessionResultFilter, SessionResultRange } from './types.ts' +import { SessionQueryError } from './config.ts' + +/** + * Apply ANDed logical-session filters while preserving input order. + * @param records - detached logical-session records to inspect. + * @param filters - clauses whose list values are ORed within each clause. + * @returns records accepted by every clause. + */ +export function filterSessionResults( + records: readonly T[], + filters: readonly SessionResultFilter[] = [], +): T[] { + const predicates = filters.map(sessionPredicate) + return records.filter(record => predicates.every(predicate => predicate(record))) +} + +/** + * Apply ANDed event filters to extracted semantic documents. + * @param documents - semantic documents produced by {@link buildSessionEventSearchDocuments}. + * @param filters - metadata and literal-text predicates. + * @returns documents accepted by every clause, in input order. + */ +export function filterSessionEventDocuments( + documents: readonly T[], + filters: readonly SessionEventResultFilter[] = [], +): T[] { + const predicates = filters.map(eventPredicate) + return documents.filter(document => predicates.every(predicate => predicate(document))) +} + +/** + * Compile a literal case-insensitive, whitespace-flexible semantic-text match. + * @param text - caller-provided literal text. + * @returns Unicode-aware regular expression safe from regex injection. + */ +export function compileSessionTextFilter(text: string): RegExp { + const trimmed = text.trim() + if (trimmed.length === 0) { + throw new SessionQueryError( + 'session text filter must contain non-whitespace text', + 'SESSION_QUERY_INVALID_FILTER', + ) + } + const pattern = trimmed + .split(/\s+/u) + .map(part => part.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')) + .join('\\s+') + return new RegExp(pattern, 'iu') +} + +function sessionPredicate(filter: SessionResultFilter): (record: SessionRecord) => boolean { + switch (filter.kind) { + case 'id': + return record => filter.values.includes(record.header.id) + case 'cwd': + return record => filter.values.includes(record.header.cwd ?? null) + case 'created-at': { + const range = validateRange(filter.kind, filter) + return record => matchesRange(record.header.createdAt, range) + } + case 'parent': + return record => filter.values.includes(record.header.parentSession ?? null) + case 'availability': + assertAllowedValues(filter.kind, filter.values, ['live', 'persisted']) + return record => filter.values.some(value => value === 'live' ? record.live : record.persisted) + } +} + +function eventPredicate(filter: SessionEventResultFilter): (document: SessionEventSearchDocument) => boolean { + switch (filter.kind) { + case 'seq': { + const range = validateRange(filter.kind, filter) + return document => matchesRange(document.seq, range) + } + case 'time': { + const range = validateRange(filter.kind, filter) + return document => matchesRange(document.time, range) + } + case 'type': + return document => filter.values.includes(document.type) + case 'surface': + assertAllowedValues(filter.kind, filter.values, ['current', 'shadowed', 'log-only']) + return document => filter.values.includes(document.surface) + case 'text': { + const pattern = compileSessionTextFilter(filter.text) + return document => pattern.test(document.text) + } + } +} + +function assertAllowedValues( + name: string, + values: readonly string[], + allowed: readonly string[], +): void { + for (const value of values) { + if (!allowed.includes(value)) { + throw new SessionQueryError( + `session ${name} filter contains unknown value "${value}"`, + 'SESSION_QUERY_INVALID_FILTER', + ) + } + } +} + +function validateRange(name: string, range: SessionResultRange): SessionResultRange { + if (range.from !== undefined && !Number.isFinite(range.from)) { + throw invalidRange(name, 'from must be finite') + } + if (range.to !== undefined && !Number.isFinite(range.to)) { + throw invalidRange(name, 'to must be finite') + } + if (range.from !== undefined && range.to !== undefined && range.from > range.to) { + throw invalidRange(name, 'from must be less than or equal to to') + } + return range +} + +function matchesRange(value: number, range: SessionResultRange): boolean { + return (range.from === undefined || value >= range.from) + && (range.to === undefined || value <= range.to) +} + +function invalidRange(name: string, detail: string): SessionQueryError { + return new SessionQueryError( + `session ${name} filter ${detail}`, + 'SESSION_QUERY_INVALID_FILTER', + ) +} diff --git a/packages/session-query/session-query/src/index.ts b/packages/session-query/session-query/src/index.ts index 828fe2ec88..243c86746b 100644 --- a/packages/session-query/session-query/src/index.ts +++ b/packages/session-query/session-query/src/index.ts @@ -6,13 +6,20 @@ import { Context, Service } from 'cordis' import z from 'schemastery' -import { foldSurface } from '@deepseek-ai/dsh-session' -import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session' +import type { SessionId } from '@deepseek-ai/dsh-session' import type { + SessionEventResultFilter, SessionEventReadRequest, SessionEventRecord, + SessionEventSearchHit, + SessionEventSearchDocument, + SessionEventSearchRequest, SessionEventWindow, SessionRecord, + SessionSearchExecContext, + SessionSearchHit, + SessionSearchPage, + SessionSearchRequest, } from './types.ts' import { SESSION_QUERY_READ_WINDOW_MAX, @@ -20,17 +27,58 @@ import { type Config, } from './config.ts' import { SessionCorpus } from './corpus.ts' +import { buildSessionEventRecords, buildSessionEventSearchDocuments } from './documents.ts' +import { filterSessionEventDocuments } from './filters.ts' export type * from './types.ts' export type { Config, SessionQueryErrorCode } from './config.ts' export { SESSION_QUERY_READ_WINDOW_MAX, SessionQueryError } from './config.ts' +export { extractSessionEventText } from './extraction.ts' +export { buildSessionEventRecords, buildSessionEventSearchDocuments } from './documents.ts' +export { compileSessionTextFilter, filterSessionEventDocuments, filterSessionResults } from './filters.ts' +export { assertSessionHeadersCompatible } from './sources.ts' declare module 'cordis' { interface Context { sessionQuery: SessionQueryService + sessionSearch: SessionSearchService } } +/** + * Abstract full-text search service implemented by one concrete backend. + * + * The implementation owns source observation, reconciliation, cursor + * generations, ranking, and query execution as one lifecycle. + */ +export abstract class SessionSearchService extends Service { + constructor(ctx: Context) { + super(ctx, 'sessionSearch') + } + + /** + * Search the live-preferred logical corpus and group by session. + * @param request - query text, metadata filters, page size, and cursor. + * @param exec - optional cancellation control. + * @returns session hits ranked by their strongest matching event. + */ + abstract searchSessions( + request: SessionSearchRequest, + exec?: SessionSearchExecContext, + ): Promise> + + /** + * Search events within one live-preferred logical session. + * @param request - target session, query text, filters, page size, and cursor. + * @param exec - optional cancellation control. + * @returns matching event hits in deterministic relevance order. + */ + abstract searchEvents( + request: SessionEventSearchRequest, + exec?: SessionSearchExecContext, + ): Promise> +} + /** Live-preferred logical-corpus and exact-event read service. */ export class SessionQueryService extends Service { static inject = ['sessions'] @@ -68,7 +116,22 @@ export class SessionQueryService extends Service { */ async listEvents(sessionId: SessionId): Promise { const loaded = await this._corpus.load(sessionId) - return eventRecords(sessionId, loaded.events) + return buildSessionEventRecords(sessionId, loaded.events) + } + + /** + * Scan first-party semantic event documents with provider-independent filters. + * @param sessionId - live-preferred session id to scan. + * @param filters - ANDed metadata and literal-text predicates. + * @returns matching semantic documents in ascending seq order. + */ + async filterEvents( + sessionId: SessionId, + filters: readonly SessionEventResultFilter[], + ): Promise { + const loaded = await this._corpus.load(sessionId) + const documents = buildSessionEventSearchDocuments(sessionId, loaded.events) + return filterSessionEventDocuments(documents, filters) } /** @@ -110,27 +173,4 @@ export class SessionQueryService extends Service { } } -function eventRecords(sessionId: SessionId, events: readonly SessionEvent[]): SessionEventRecord[] { - let folded: ReturnType - try { - folded = foldSurface(events) - } catch (error: unknown) { - throw new SessionQueryError( - /* v8 ignore next -- foldSurface throws Error instances */ - `invalid session surface: ${error instanceof Error ? error.message : 'unknown error'}`, - 'SESSION_QUERY_INVALID_SURFACE', - { cause: error }, - ) - } - const current = new Set(folded.nodes.map(node => node.seq)) - const shadowed = new Set(folded.replacements.flatMap(replacement => replacement.shadowedSeqs)) - return events.map(event => ({ - sessionId, - seq: event.seq, - type: event.type, - time: event.time, - surface: current.has(event.seq) ? 'current' : shadowed.has(event.seq) ? 'shadowed' : 'log-only', - })) -} - export default SessionQueryService diff --git a/packages/session-query/session-query/src/sources.ts b/packages/session-query/session-query/src/sources.ts new file mode 100644 index 0000000000..00b08eae4e --- /dev/null +++ b/packages/session-query/session-query/src/sources.ts @@ -0,0 +1,25 @@ +/** Shared immutable-header checks for logical session source observers. */ + +import type { SessionHeader } from '@deepseek-ai/dsh-session' +import { SessionQueryError } from './config.ts' + +/** + * Reject incompatible observations of one logical session source. + * @param a - first live, listed, or loaded header observation. + * @param b - second header observation expected to identify the same source. + */ +export function assertSessionHeadersCompatible(a: SessionHeader, b: SessionHeader): void { + if ( + a.version !== b.version + || a.id !== b.id + || a.createdAt !== b.createdAt + || a.cwd !== b.cwd + || a.parentSession !== b.parentSession + || a.seedLength !== b.seedLength + ) { + throw new SessionQueryError( + `session source headers conflict for session "${a.id}"`, + 'SESSION_QUERY_SOURCE_CONFLICT', + ) + } +} diff --git a/packages/session-query/session-query/src/types.ts b/packages/session-query/session-query/src/types.ts index 5c49695dda..d0de0dd48a 100644 --- a/packages/session-query/session-query/src/types.ts +++ b/packages/session-query/session-query/src/types.ts @@ -58,3 +58,99 @@ export interface SessionEventWindow { /** Last seq included in `events`. */ endSeq: number } + +/** Inclusive numeric interval used by time and sequence filters. */ +export interface SessionResultRange { + /** Inclusive lower bound. */ + from?: number + /** Inclusive upper bound. */ + to?: number +} + +/** Source availability predicates understood by logical-session filters. */ +export type SessionAvailability = 'live' | 'persisted' + +/** + * One logical-session predicate. A filter array is ANDed; `values` within a + * clause are ORed. + */ +export type SessionResultFilter = + | { kind: 'id'; values: readonly SessionId[] } + | { kind: 'cwd'; values: readonly (string | null)[] } + | ({ kind: 'created-at' } & SessionResultRange) + | { kind: 'parent'; values: readonly (SessionId | null)[] } + | { kind: 'availability'; values: readonly SessionAvailability[] } + +/** + * One event predicate. A filter array is ANDed; list-valued clauses are ORed. + * Text is a literal, case-insensitive, whitespace-flexible semantic-text scan. + */ +export type SessionEventResultFilter = + | ({ kind: 'seq' } & SessionResultRange) + | ({ kind: 'time' } & SessionResultRange) + | { kind: 'type'; values: readonly SessionEventType[] } + | { kind: 'surface'; values: readonly SessionEventSurface[] } + | { kind: 'text'; text: string } + +/** Event predicates a full-text provider can apply before relevance ranking. */ +export type SessionEventMetadataFilter = Exclude + +/** Searchable semantic document derived from one session event. */ +export interface SessionEventSearchDocument extends SessionEventRecord { + /** First-party semantic text used by scan filters and full-text indexes. */ + text: string +} + +/** One cursor-paginated result page. */ +export interface SessionSearchPage { + /** Results for this page in contract-defined order. */ + items: readonly T[] + /** Opaque continuation cursor, absent on the final page. */ + nextCursor?: string +} + +/** Controls shared by cross-session and within-session search calls. */ +export interface SessionSearchExecContext { + /** Abort caller waiting and interrupt provider work where supported. */ + signal?: AbortSignal +} + +/** Cross-session full-text search request. */ +export interface SessionSearchRequest { + /** Full-text query interpreted as data, never executable FTS syntax. */ + query: string + /** Logical-session predicates applied before event ranking. */ + sessionFilters?: readonly SessionResultFilter[] + /** Event predicates applied before event ranking. */ + eventFilters?: readonly SessionEventMetadataFilter[] + /** Maximum sessions in this page. */ + limit?: number + /** Opaque cursor returned for the identical normalized request. */ + cursor?: string +} + +/** Within-session full-text search request. */ +export interface SessionEventSearchRequest { + /** Session whose live-preferred logical log is searched. */ + sessionId: SessionId + /** Full-text query interpreted as data, never executable FTS syntax. */ + query: string + /** Event predicates applied before ranking. */ + filters?: readonly SessionEventMetadataFilter[] + /** Maximum events in this page. */ + limit?: number + /** Opaque cursor returned for the identical normalized request. */ + cursor?: string +} + +/** One event full-text search hit with a bounded plain-text excerpt. */ +export interface SessionEventSearchHit extends SessionEventRecord { + /** Plain text excerpt selected around the match. */ + snippet: string +} + +/** One grouped cross-session hit, ranked by its strongest matching event. */ +export interface SessionSearchHit extends SessionRecord { + /** Strongest matching event for this session. */ + bestMatch: SessionEventSearchHit +} diff --git a/packages/session-query/session-query/tests/search-helpers.spec.ts b/packages/session-query/session-query/tests/search-helpers.spec.ts new file mode 100644 index 0000000000..e9cf857608 --- /dev/null +++ b/packages/session-query/session-query/tests/search-helpers.spec.ts @@ -0,0 +1,209 @@ +import { describe, expect, it } from 'vitest' +import { Context } from 'cordis' +import { CallId } from '@deepseek-ai/dsh-llm' +import SessionStore, { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session' +import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session' +import SessionQueryService, { + buildSessionEventRecords, + buildSessionEventSearchDocuments, + compileSessionTextFilter, + extractSessionEventText, + filterSessionEventDocuments, + filterSessionResults, + SessionSearchService, + type SessionEventSearchHit, + type SessionEventSearchRequest, + type SessionQueryErrorCode, + type SessionSearchExecContext, + type SessionSearchHit, + type SessionSearchPage, + type SessionSearchRequest, +} from '@deepseek-ai/dsh-session-query' + +const id = SessionId('session') + +function header(value: string, extra: Partial = {}): SessionHeader { + return { version: SESSION_FORMAT_VERSION, id: SessionId(value), createdAt: 10, ...extra } +} + +function expectCode(code: SessionQueryErrorCode): Error { + return expect.objectContaining({ code }) as Error +} + +describe('session-query semantic extraction', () => { + it('extracts first-party message, tool, todo, and failure detail', () => { + const callId = CallId('call') + const messageContent: SessionEvent<'user/message'>['data']['content'] = [ + { type: 'text', text: ' visible ' }, + { type: 'reasoning', text: 'thought' }, + { type: 'tool-call', id: callId, name: 'read', arguments: '{"path":"a"}' }, + { + type: 'tool-result', + toolCallId: callId, + content: [{ type: 'text', text: 'nested' }], + isError: false, + }, + { type: 'future-content', payload: 'hidden' } as never, + ] + const events: SessionEvent[] = [ + { type: 'user/message', seq: 0, time: 1, data: { content: messageContent, source: { kind: 'user' } }, surfaceOp: 'append' }, + { type: 'assistant/message', seq: 1, time: 2, data: { turn: 1, step: 1, content: messageContent }, surfaceOp: 'append' }, + { type: 'context/message', seq: 2, time: 3, data: { content: messageContent, source: { kind: 'plugin', plugin: 'test' } }, surfaceOp: 'append' }, + { type: 'steering/message', seq: 3, time: 4, data: { turn: 1, content: messageContent, source: { kind: 'user' } }, surfaceOp: 'append' }, + { type: 'prompt/blocked', seq: 4, time: 5, data: { content: [{ type: 'text', text: 'unsafe' }], source: { kind: 'user' }, reason: 'policy' } }, + { type: 'tool/call', seq: 5, time: 6, data: { turn: 1, step: 1, callId, name: 'bash', arguments: '{"cmd":"pwd"}' } }, + { type: 'tool/result', seq: 6, time: 7, data: { turn: 1, step: 1, callId, content: [{ type: 'text', text: 'failed' }], isError: true, error: { name: 'Oops', code: 'E_OOPS' } }, surfaceOp: 'append' }, + { type: 'tool/result', seq: 7, time: 8, data: { turn: 1, step: 1, callId, content: [], isError: false }, surfaceOp: 'append' }, + { type: 'todo/write', seq: 8, time: 9, data: { todos: [{ status: 'in_progress', content: 'ship search' }] } }, + ] + + for (const event of events.slice(0, 4)) { + expect(extractSessionEventText(event)).toBe('visible\nthought\nread\n{"path":"a"}\nnested') + } + expect(extractSessionEventText(events[4]!)).toBe('unsafe\npolicy') + expect(extractSessionEventText(events[5]!)).toBe('bash\n{"cmd":"pwd"}') + expect(extractSessionEventText(events[6]!)).toBe('failed\nOops\nE_OOPS') + expect(extractSessionEventText(events[7]!)).toBe('') + expect(extractSessionEventText(events[8]!)).toBe('in_progress\nship search') + }) + + it('extracts meaningful turn outcomes and skips structural or unknown events', () => { + const reasons: Array<[SessionEvent<'turn/end'>['data']['reason'], string]> = [ + [{ kind: 'error', step: 2, message: 'boom', code: 'E' }, 'error\nboom\nE'], + [{ kind: 'error', step: 2, message: 'boom' }, 'error\nboom'], + [{ kind: 'aborted', reason: 'cancelled' }, 'aborted\ncancelled'], + [{ kind: 'aborted' }, 'aborted'], + [{ kind: 'rejected', reason: 'denied' }, 'rejected\ndenied'], + [{ kind: 'disposed' }, 'disposed'], + [{ kind: 'max-tokens' }, 'max-tokens'], + [{ kind: 'interrupted' }, 'interrupted'], + [{ kind: 'completed' }, ''], + [{ kind: 'future-status' } as never, ''], + ] + for (const [reason, text] of reasons) { + expect(extractSessionEventText({ type: 'turn/end', seq: 0, time: 1, data: { turn: 1, reason } })).toBe(text) + } + const structural: SessionEvent[] = [ + { type: 'turn/start', seq: 0, time: 1, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } }, + { type: 'step/start', seq: 1, time: 1, data: { turn: 1, step: 1 } }, + { type: 'step/end', seq: 2, time: 1, data: { turn: 1, step: 1 } }, + { type: 'assistant/chunk', seq: 3, time: 1, data: { turn: 1, step: 1, chunk: { type: 'text-delta', index: 0, text: 'raw' } } }, + { type: 'request/header', seq: 4, time: 1, data: { header: { config: { model: 'test' } }, reason: 'initial' } }, + { type: 'request/header-delta', seq: 5, time: 1, data: {} }, + { type: 'future/event', seq: 6, time: 1, data: { text: 'hidden' } } as never, + ] + expect(structural.map(extractSessionEventText)).toEqual(['', '', '', '', '', '', '']) + }) +}) + +describe('session-query document and filter helpers', () => { + const events: SessionEvent[] = [ + { type: 'user/message', seq: 0, time: 10, data: { content: [{ type: 'text', text: 'Hello\n(AI)+' }], source: { kind: 'user' } }, surfaceOp: 'append' }, + { type: 'assistant/chunk', seq: 1, time: 11, data: { turn: 1, step: 1, chunk: { type: 'text-delta', index: 0, text: 'raw' } } }, + { type: 'assistant/message', seq: 2, time: 12, data: { turn: 1, step: 1, content: [{ type: 'text', text: 'replacement' }] }, surfaceOp: { op: 'replace', start: 0, end: 0 } }, + { type: 'turn/end', seq: 3, time: 13, data: { turn: 1, reason: { kind: 'interrupted' } } }, + ] + + it('classifies every event and omits non-semantic documents', () => { + expect(buildSessionEventRecords(id, events).map(record => record.surface)) + .toEqual(['shadowed', 'log-only', 'current', 'log-only']) + const documents = buildSessionEventSearchDocuments(id, events) + expect(documents.map(document => [document.seq, document.text, document.surface])).toEqual([ + [0, 'Hello\n(AI)+', 'shadowed'], + [2, 'replacement', 'current'], + [3, 'interrupted', 'log-only'], + ]) + }) + + it('applies every session clause with OR values and validates closed values', () => { + const parent = SessionId('parent') + const records = [ + { header: header('a', { cwd: '/a', parentSession: parent }), live: true, persisted: false, marker: 1 }, + { header: header('b', { createdAt: 20 }), live: false, persisted: true, marker: 2 }, + ] + expect(filterSessionResults(records, [ + { kind: 'id', values: [SessionId('a'), SessionId('x')] }, + { kind: 'cwd', values: ['/a', null] }, + { kind: 'created-at', from: 5, to: 15 }, + { kind: 'parent', values: [parent, null] }, + { kind: 'availability', values: ['live'] }, + ])).toEqual([records[0]]) + expect(filterSessionResults(records, [{ kind: 'cwd', values: [null] }])).toEqual([records[1]]) + expect(filterSessionResults(records, [{ kind: 'parent', values: [null] }])).toEqual([records[1]]) + expect(filterSessionResults(records, [{ kind: 'availability', values: ['persisted'] }])).toEqual([records[1]]) + expect(() => filterSessionResults(records, [{ kind: 'availability', values: ['remote' as never] }])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + }) + + it('applies event metadata and safe literal text clauses', () => { + const documents = buildSessionEventSearchDocuments(id, events).map((document, marker) => ({ ...document, marker })) + expect(filterSessionEventDocuments(documents, [ + { kind: 'seq', from: 0, to: 1 }, + { kind: 'time', from: 9, to: 11 }, + { kind: 'type', values: ['user/message', 'tool/result'] }, + { kind: 'surface', values: ['shadowed'] }, + { kind: 'text', text: 'hello (ai)+' }, + ])).toEqual([documents[0]]) + expect(compileSessionTextFilter('CAFÉ').test('café')).toBe(true) + expect(filterSessionEventDocuments(documents)).toEqual(documents) + expect(filterSessionEventDocuments(documents, [{ kind: 'surface', values: [] }])).toEqual([]) + expect(() => filterSessionEventDocuments(documents, [{ kind: 'surface', values: ['future' as never] }])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => compileSessionTextFilter(' \n ')).toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + }) + + it('rejects malformed range filters and malformed surfaces', () => { + const documents = buildSessionEventSearchDocuments(id, events) + for (const filter of [ + { kind: 'seq', from: Number.NaN }, + { kind: 'seq', to: Number.POSITIVE_INFINITY }, + { kind: 'time', from: 2, to: 1 }, + ] as const) { + expect(() => filterSessionEventDocuments(documents, [filter])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + } + expect(() => filterSessionResults([], [{ kind: 'created-at', from: Number.NaN }])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => filterSessionResults([{ header: header('x'), live: true, persisted: false }], [ + { kind: 'created-at', from: Number.NaN }, + ])).toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + const malformed: SessionEvent[] = [{ + type: 'assistant/message', + seq: 0, + time: 1, + data: { turn: 1, step: 1, content: [{ type: 'text', text: 'bad' }] }, + surfaceOp: { op: 'replace', start: 9, end: 9 }, + }] + expect(() => buildSessionEventRecords(id, malformed)).toThrow(expectCode('SESSION_QUERY_INVALID_SURFACE')) + }) + + it('exposes the scan path on the concrete exact-read service', async () => { + const ctx = new Context() + await ctx.plugin(SessionStore) + await ctx.plugin(SessionQueryService) + const session = ctx.sessions.create(id) + session.append('user/message', { content: [{ type: 'text', text: 'Alpha\n beta' }], source: { kind: 'user' } }, { surfaceOp: 'append' }) + session.append('user/message', { content: [{ type: 'text', text: 'other' }], source: { kind: 'user' } }, { surfaceOp: 'append' }) + await expect(ctx.sessionQuery.filterEvents(id, [{ kind: 'text', text: 'alpha beta' }])) + .resolves.toMatchObject([{ seq: 0, text: 'Alpha\n beta' }]) + }) +}) + +class TestSearchService extends SessionSearchService { + searchSessions(_request: SessionSearchRequest, _exec?: SessionSearchExecContext): Promise> { + return Promise.resolve({ items: [] }) + } + + searchEvents(_request: SessionEventSearchRequest, _exec?: SessionSearchExecContext): Promise> { + return Promise.resolve({ items: [] }) + } +} + +it('registers the abstract search seam under its independent ctx key', async () => { + const ctx = new Context() + const fiber = await ctx.plugin(TestSearchService) + await expect(ctx.sessionSearch.searchSessions({ query: 'AI' })).resolves.toEqual({ items: [] }) + await expect(ctx.sessionSearch.searchEvents({ sessionId: id, query: 'AI' })).resolves.toEqual({ items: [] }) + await fiber.dispose() + expect(ctx.sessionSearch).toBeUndefined() +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 456ce0896b..997f00ff5c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -778,6 +778,31 @@ importers: specifier: ^4.0.0-rc.6 version: 4.0.0-rc.6(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.4) + packages/session-query/session-query-sqlite: + dependencies: + schemastery: + specifier: ^3.18.0 + version: 3.18.0 + devDependencies: + '@cordisjs/plugin-loader': + specifier: workspace:^ + version: link:../../../vendor/loader + '@deepseek-ai/dsh-session': + specifier: workspace:^ + version: link:../../core/session + '@deepseek-ai/dsh-session-persistence': + specifier: workspace:^ + version: link:../../session-persistence/session-persistence + '@deepseek-ai/dsh-session-persistence-sqlite': + specifier: workspace:^ + version: link:../../session-persistence/session-persistence-sqlite + '@deepseek-ai/dsh-session-query': + specifier: workspace:^ + version: link:../session-query + cordis: + specifier: ^4.0.0-rc.6 + version: 4.0.0-rc.6(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@vendor+loader) + packages/skill/skill: dependencies: schemastery: diff --git a/scripts/gen-doc-graphs.ts b/scripts/gen-doc-graphs.ts index 05eaaed337..413917aa9a 100644 --- a/scripts/gen-doc-graphs.ts +++ b/scripts/gen-doc-graphs.ts @@ -93,7 +93,7 @@ const SERVICE_ROLES: ServiceRole[] = [ pkg: 'session', title: 'In-memory session store', mode: 'core', - consumers: ['agent-loop', 'agent', 'session-persistence', 'session-query', 'subagent-inprocess', 'invariants'], + consumers: ['agent-loop', 'agent', 'session-persistence', 'session-query', 'session-query-sqlite', 'subagent-inprocess', 'invariants'], note: 'Owns append-only Session instances and emits the durable session event feed.', }, { @@ -102,7 +102,7 @@ const SERVICE_ROLES: ServiceRole[] = [ title: 'Durable session persistence seam', mode: 'seam', implementations: ['session-persistence-jsonl', 'session-persistence-sqlite'], - consumers: ['agent-loop', 'acp', 'session-query'], + consumers: ['agent-loop', 'acp', 'session-query', 'session-query-sqlite'], note: 'Backends persist the same SessionEvent vocabulary; apps choose a backend at composition time.', }, { @@ -110,7 +110,15 @@ const SERVICE_ROLES: ServiceRole[] = [ pkg: 'session-query', title: 'Exact session-history reads', mode: 'seam', - note: 'Resolves live and optional persisted logs into one logical corpus for exact reads.', + note: 'Resolves live and optional persisted logs into one logical corpus for exact reads and semantic scans.', + }, + { + key: 'sessionSearch', + pkg: 'session-query', + title: 'Full-text session search', + mode: 'seam', + implementations: ['session-query-sqlite'], + note: 'The concrete backend owns source reconciliation, ranking, snippets, and cursor generations as one lifecycle.', }, { key: 'systemPrompt', diff --git a/scripts/type-equiv.manifest.json b/scripts/type-equiv.manifest.json index 7b83f1004e..0d0a0b871d 100644 --- a/scripts/type-equiv.manifest.json +++ b/scripts/type-equiv.manifest.json @@ -49,6 +49,14 @@ { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventSurface", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionRecord", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventRecord", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionResultFilter", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventResultFilter", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventSearchDocument", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionSearchRequest", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventSearchRequest", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionSearchPage", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventSearchHit", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionSearchHit", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionQueryErrorCode", "source": "packages/session-query/session-query/src/config.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventReadRequest", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventWindow", "source": "packages/session-query/session-query/src/types.ts" }, diff --git a/tsconfig.build.json b/tsconfig.build.json index 7797998a30..d2470e0ff5 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -19,6 +19,7 @@ { "path": "./packages/session-persistence/session-persistence-jsonl" }, { "path": "./packages/session-persistence/session-persistence-sqlite" }, { "path": "./packages/session-query/session-query" }, + { "path": "./packages/session-query/session-query-sqlite" }, { "path": "./packages/core/system-prompt" }, { "path": "./packages/core/agent" }, { "path": "./packages/ui/user-interaction" }, diff --git a/tsconfig.json b/tsconfig.json index 778a26ff8a..c62cc70518 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,6 +30,7 @@ { "path": "./packages/session-persistence/session-persistence-jsonl" }, { "path": "./packages/session-persistence/session-persistence-sqlite" }, { "path": "./packages/session-query/session-query" }, + { "path": "./packages/session-query/session-query-sqlite" }, { "path": "./packages/core/system-prompt" }, { "path": "./packages/core/agent" }, { "path": "./packages/ui/user-interaction" }, From f88ca85ffdd5c3b86ff859bda2c9f05967ade11e Mon Sep 17 00:00:00 2001 From: Hypatia May Date: Wed, 15 Jul 2026 12:10:24 +0800 Subject: [PATCH 002/368] fix(session-query): harden SQLite search reconciliation --- docs/config-catalog.md | 2 +- docs/cordis-catalog/services.md | 8 +- docs/core-data-structures/persistence.md | 19 +- docs/core-data-structures/session-query.md | 12 +- docs/module-graph.md | 6 +- .../2026-07-10-session-query-service.md | 2 +- ...026-07-10-sqlite-session-query-provider.md | 16 +- .../cordis/tool-cordis/src/api-catalog.ts | 20 +- .../session-persistence-jsonl/README.md | 1 + .../session-persistence-jsonl/src/index.ts | 40 +- .../session-persistence-sqlite/README.md | 3 +- .../session-persistence-sqlite/src/index.ts | 24 +- .../session-persistence-sqlite/src/schema.ts | 19 +- .../tests/sqlite.spec.ts | 17 +- .../session-persistence/README.md | 7 +- .../session-persistence/package.json | 2 + .../session-persistence/src/coordinator.ts | 4 +- .../session-persistence/src/index.ts | 19 + .../session-persistence/src/revision.ts | 15 + .../session-persistence/tests/contract.ts | 22 +- .../tests/persistence.spec.ts | 12 +- .../session-persistence/tsconfig.json | 3 + .../session-query-sqlite/README.md | 10 +- .../session-query-sqlite/src/index.ts | 326 ++++++++++++---- .../session-query-sqlite/src/query.ts | 151 ++++++- .../session-query-sqlite/src/schema.ts | 11 +- .../session-query-sqlite/tests/query.spec.ts | 65 +++- .../session-query-sqlite/tests/sqlite.spec.ts | 367 +++++++++++++++++- .../session-query/session-query/README.md | 3 +- .../session-query/session-query/package.json | 2 + .../session-query/session-query/src/corpus.ts | 21 +- .../session-query/session-query/src/cursor.ts | 15 + .../session-query/src/filters.ts | 121 +++++- .../session-query/session-query/src/index.ts | 62 ++- .../session-query/session-query/src/types.ts | 9 +- .../tests/search-helpers.spec.ts | 27 ++ .../session-query/tests/session-query.spec.ts | 67 +++- .../session-query/session-query/tsconfig.json | 3 + pnpm-lock.yaml | 6 + scripts/type-equiv.manifest.json | 3 + 40 files changed, 1315 insertions(+), 227 deletions(-) create mode 100644 packages/session-persistence/session-persistence/src/revision.ts create mode 100644 packages/session-query/session-query/src/cursor.ts diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 3a802231d7..e8a06e469e 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -613,7 +613,7 @@ export interface Config { export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' ``` -Source: [`packages/session-query/session-query-sqlite/src/index.ts:58`](../packages/session-query/session-query-sqlite/src/index.ts) +Source: [`packages/session-query/session-query-sqlite/src/index.ts:67`](../packages/session-query/session-query-sqlite/src/index.ts) ## `@deepseek-ai/dsh-skill` diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index fef691aae1..e83b96bd11 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -195,11 +195,12 @@ abstract create(meta: SessionHeader): Promise abstract append(id: SessionId, events: readonly SessionEvent[]): Promise abstract load(id: SessionId): Promise<{ meta: SessionHeader; events: SessionEvent[] }> abstract list(): Promise +abstract listSnapshots(): Promise ``` Types: [SessionEvent](../core-data-structures/core.md) -Source: [`packages/session-persistence/session-persistence/src/index.ts:102`](../../packages/session-persistence/session-persistence/src/index.ts) +Source: [`packages/session-persistence/session-persistence/src/index.ts:112`](../../packages/session-persistence/session-persistence/src/index.ts) ## `ctx.sessionQuery` — `SessionQueryService` @@ -207,12 +208,13 @@ Live-preferred logical-corpus and exact-event read service. ```ts cordis-catalog listSessions(): Promise +async filterSessions(filters: readonly SessionResultFilter[]): Promise async listEvents(sessionId: SessionId): Promise async filterEvents( sessionId: SessionId, filters: readonly SessionEventResultFilter[], ): Promise async readEvent(request: SessionEventReadRequest): Promise ``` -Source: [`packages/session-query/session-query/src/index.ts:83`](../../packages/session-query/session-query/src/index.ts) +Source: [`packages/session-query/session-query/src/index.ts:96`](../../packages/session-query/session-query/src/index.ts) ## `ctx.sessions` — `SessionStore` @@ -244,7 +246,7 @@ abstract searchSessions( request: SessionSearchRequest, exec?: SessionSearchExec abstract searchEvents( request: SessionEventSearchRequest, exec?: SessionSearchExecContext, ): Promise> ``` -Source: [`packages/session-query/session-query/src/index.ts:54`](../../packages/session-query/session-query/src/index.ts) +Source: [`packages/session-query/session-query/src/index.ts:67`](../../packages/session-query/session-query/src/index.ts) ## `ctx.skills` — `SkillService` diff --git a/docs/core-data-structures/persistence.md b/docs/core-data-structures/persistence.md index 7bf102924b..9535686f86 100644 --- a/docs/core-data-structures/persistence.md +++ b/docs/core-data-structures/persistence.md @@ -2,7 +2,7 @@ The **durability seam** for the event log. [session.md](session.md) describes the in-memory `Session` — the append-only `SessionEvent` log that is the source of truth. This page describes how that log is made durable: the abstract `SessionPersistence` service, its backends, the flush checkpoint, crash recovery, and the metadata header that travels alongside the log. The event vocabulary the log carries is enumerated, member by member, in the generated [persistence log event catalog](../persistence-catalog.md). -The seam is a textbook [capability seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md): one abstract service ([dsh-session-persistence](../../packages/session-persistence/session-persistence), `ctx.sessionPersistence`) defining create/append/load/list over the existing `SessionEvent` — **no parallel persisted type** — and two interchangeable backends that pass the same `runPersistenceContract` suite. See the [session-persistence RFC](../rfc/implemented/architecture/2026-06-14-session-persistence.md). +The seam is a textbook [capability seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md): one abstract service ([dsh-session-persistence](../../packages/session-persistence/session-persistence), `ctx.sessionPersistence`) defining create/append/load plus lightweight list/snapshot observation over the existing `SessionEvent` — **no parallel persisted event type** — and two interchangeable backends that pass the same `runPersistenceContract` suite. See the [session-persistence RFC](../rfc/implemented/architecture/2026-06-14-session-persistence.md). ## The flush checkpoint @@ -78,9 +78,24 @@ interface CreateSessionOptions { Replay/fork is therefore `ctx.sessions.create(id, { seed: seedEvents })`; resuming a *persisted* session into a live agent is `ctx.agents.resume({ resumeSessionId })`. +## Lightweight source revisions + +Consumers of derived state compare a cheap opaque revision before loading a full event log. The persistence backend owns its representation and changes it transactionally with append or mutating load repair; callers compare it only for equality. + +```ts type-equiv +export type SessionPersistenceRevision = Branded<'SessionPersistenceRevision'> +``` + +```ts type-equiv +export interface SessionPersistenceSnapshot { + header: SessionHeader + revision: SessionPersistenceRevision +} +``` + ## The backends -Both implement the same abstract `SessionPersistence` (create/append/load/list over `SessionEvent`) and pass `runPersistenceContract`, proving the seam is genuinely backend-agnostic: +Both implement the same abstract `SessionPersistence` (create/append/load/list/listSnapshots over `SessionEvent`) and pass `runPersistenceContract`, proving the seam is genuinely backend-agnostic: - **[dsh-session-persistence-jsonl](../../packages/session-persistence/session-persistence-jsonl)** — an append-only JSONL log per session with crash-safe atomic writes, the interrupted-turn crash recovery above, and a read/replay path. - **[dsh-session-persistence-sqlite](../../packages/session-persistence/session-persistence-sqlite)** — `node:sqlite`, one row per `SessionEvent`. The row shape `(session_id, seq, type, time, data, source_event_seqs, surface_op)` maps 1:1 onto the event, including optional surface metadata, so there is no parallel persisted schema to keep in sync. diff --git a/docs/core-data-structures/session-query.md b/docs/core-data-structures/session-query.md index 27ef9959de..d1ed41b775 100644 --- a/docs/core-data-structures/session-query.md +++ b/docs/core-data-structures/session-query.md @@ -58,19 +58,23 @@ export interface SessionEventSearchDocument extends SessionEventRecord { } ``` -`ctx.sessionQuery.filterEvents(sessionId, filters)` returns these documents in ascending seq order. Messages, reasoning, tool calls/results, blocked prompts, todos, and failure/status detail contribute semantic text; structural events and stream chunks do not. +`ctx.sessionQuery.filterSessions(filters)` applies `SessionResultFilter` to the complete logical corpus; `ctx.sessionQuery.filterEvents(sessionId, filters)` returns matching documents in ascending seq order. Messages, reasoning, tool calls/results, blocked prompts, todos, and failure/status detail contribute semantic text; structural events and stream chunks do not. ## Full-text search pages The independent `ctx.sessionSearch` seam has two scopes. `searchSessions()` groups the corpus by strongest matching event; `searchEvents()` searches one session. Requests bind an opaque cursor to the normalized query, metadata filters, and limit. The event text scan is intentionally absent from provider metadata filters. +```ts type-equiv +export type SessionSearchCursor = Branded<'SessionSearchCursor'> +``` + ```ts type-equiv export interface SessionSearchRequest { query: string sessionFilters?: readonly SessionResultFilter[] eventFilters?: readonly SessionEventMetadataFilter[] limit?: number - cursor?: string + cursor?: SessionSearchCursor } ``` @@ -80,14 +84,14 @@ export interface SessionEventSearchRequest { query: string filters?: readonly SessionEventMetadataFilter[] limit?: number - cursor?: string + cursor?: SessionSearchCursor } ``` ```ts type-equiv export interface SessionSearchPage { items: readonly T[] - nextCursor?: string + nextCursor?: SessionSearchCursor } ``` diff --git a/docs/module-graph.md b/docs/module-graph.md index 6fcec53dd4..7ad4cd8c70 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -151,6 +151,7 @@ flowchart TD pkg_web_search_deepseek --> pkg_web pkg_web_search_exa --> pkg_web pkg_web_search_perplexity --> pkg_web + pkg_session_persistence --> pkg_brand pkg_session_persistence --> pkg_session pkg_llm_replay --> pkg_llm pkg_llm_replay --> pkg_session @@ -168,6 +169,7 @@ flowchart TD pkg_session_persistence_jsonl --> pkg_session_persistence pkg_session_persistence_sqlite --> pkg_session pkg_session_persistence_sqlite --> pkg_session_persistence + pkg_session_query --> pkg_brand pkg_session_query --> pkg_llm pkg_session_query --> pkg_session pkg_session_query --> pkg_session_persistence @@ -361,7 +363,7 @@ flowchart TD | [`web-search-deepseek`](../packages/web/web-search-deepseek) | `web` | [`web`](../packages/web/web) | | [`web-search-exa`](../packages/web/web-search-exa) | `web` | [`web`](../packages/web/web) | | [`web-search-perplexity`](../packages/web/web-search-perplexity) | `web` | [`web`](../packages/web/web) | -| [`session-persistence`](../packages/session-persistence/session-persistence) | `session-persistence` | [`session`](../packages/core/session) | +| [`session-persistence`](../packages/session-persistence/session-persistence) | `session-persistence` | [`brand`](../packages/util/brand), [`session`](../packages/core/session) | | [`llm-replay`](../packages/support/llm-replay) | `support` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session) | | [`sandbox-local`](../packages/sandbox/sandbox-local) | `sandbox` | [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) | | [`bash-local`](../packages/bash/bash-local) | `bash` | [`bash`](../packages/bash/bash), [`timeout`](../packages/util/timeout) | @@ -369,7 +371,7 @@ flowchart TD | [`hook-protocol`](../packages/hooks/hook-protocol) | `hooks` | [`bash`](../packages/bash/bash), [`session`](../packages/core/session) | | [`session-persistence-jsonl`](../packages/session-persistence/session-persistence-jsonl) | `session-persistence` | [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence) | | [`session-persistence-sqlite`](../packages/session-persistence/session-persistence-sqlite) | `session-persistence` | [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence) | -| [`session-query`](../packages/session-query/session-query) | `session-query` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence) | +| [`session-query`](../packages/session-query/session-query) | `session-query` | [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence) | | [`invariants`](../packages/support/invariants) | `support` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session) | | [`user-approval`](../packages/ui/user-approval) | `ui` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt) | | [`user-interaction`](../packages/ui/user-interaction) | `ui` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm) | diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.md b/docs/rfc/implemented/feature/2026-07-10-session-query-service.md index be496311cc..10baa3e2c3 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.md +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.md @@ -10,7 +10,7 @@ Full-text search is related but materially larger. Putting provider coordination ## Decision -`@deepseek-ai/dsh-session-query` owns `ctx.sessionQuery`, a small trusted exact-read service over one logical corpus. It exposes `listSessions()`, `listEvents(sessionId)`, provider-independent `filterEvents(sessionId, filters)`, and bounded `readEvent(request)`. The package also declares the separate abstract `ctx.sessionSearch` contract and shared semantic extraction used by the [SQLite search decision](2026-07-10-sqlite-session-query-provider.md), but `ctx.sessionQuery` does not coordinate providers or synchronize a derived index. +`@deepseek-ai/dsh-session-query` owns `ctx.sessionQuery`, a small trusted exact-read service over one logical corpus. It exposes `listSessions()`, provider-independent `filterSessions(filters)`, `listEvents(sessionId)`, `filterEvents(sessionId, filters)`, and bounded `readEvent(request)`. The package also declares the separate abstract `ctx.sessionSearch` contract and shared semantic extraction used by the [SQLite search decision](2026-07-10-sqlite-session-query-provider.md), but `ctx.sessionQuery` does not coordinate providers or synchronize a derived index. The service observes the optional `ctx.sessionPersistence` binding dynamically but retains no persisted cache or invalidation listener. Each cross-corpus list asks the active backend for authoritative metadata, then overlays a fresh live-store list. Matching ids become one `SessionRecord`: the live header wins and `live`/`persisted` independently report source availability. Immutable header disagreement is `SESSION_QUERY_SOURCE_CONFLICT`. diff --git a/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md b/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md index d620ece108..fafa7f3569 100644 --- a/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md +++ b/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md @@ -10,19 +10,19 @@ Splitting those concerns across a provider coordinator and a database implementa ## Decision -`@deepseek-ai/dsh-session-query` declares an independent abstract `ctx.sessionSearch` service without changing the exact-read `ctx.sessionQuery` key. `searchSessions(request, exec?)` returns cursor-paginated `SessionSearchHit`s grouped by each session's strongest matching event; `searchEvents(request, exec?)` returns `SessionEventSearchHit`s within one logical session. Both requests require `query`, accept `limit` and an opaque `cursor`, and support an optional abort signal. Session search accepts `sessionFilters` plus event metadata filters; event search accepts event metadata filters. Results expose bounded plain-text snippets but no provider identifier or numeric relevance score. +`@deepseek-ai/dsh-session-query` declares an independent abstract `ctx.sessionSearch` service without changing the exact-read `ctx.sessionQuery` key. `searchSessions(request, exec?)` returns cursor-paginated `SessionSearchHit`s grouped by each session's strongest matching event; `searchEvents(request, exec?)` returns `SessionEventSearchHit`s within one logical session. Both requests require `query`, accept `limit` and an owned branded `SessionSearchCursor`, and support an optional abort signal. Session search accepts `sessionFilters` plus event metadata filters; event search accepts event metadata filters. Results expose bounded plain-text snippets but no provider identifier or numeric relevance score. `@deepseek-ai/dsh-session-query-sqlite` is the sole concrete owner of `ctx.sessionSearch`. It depends on live `ctx.sessions`, observes optional `ctx.sessionPersistence` dynamically, and owns a dedicated derived SQLite database. There is no search-provider registry, coordinator, persistence event, or agent-loop integration. -The interface package also owns shared first-party semantic extraction and provider-independent filtering. `SessionResultFilter` covers id, nullable cwd, created-at range, nullable parent, and availability. `SessionEventResultFilter` covers seq/time ranges, event type, surface, and literal semantic text. Arrays are ANDed and list values are ORed. The text clause escapes caller input into a Unicode case-insensitive regular expression whose whitespace runs match one or more whitespace characters; it is available through `ctx.sessionQuery.filterEvents()` and is not delegated to an FTS provider. +The interface package also owns shared first-party semantic extraction and provider-independent filtering. `SessionResultFilter` covers id, nullable cwd, created-at range, nullable parent, and availability; `ctx.sessionQuery.filterSessions()` applies it without an FTS provider. `SessionEventResultFilter` covers seq/time ranges, event type, surface, and literal semantic text. Arrays are ANDed and list values are ORed. The text clause escapes caller input into a Unicode case-insensitive regular expression whose whitespace runs match one or more whitespace characters; it is available through `ctx.sessionQuery.filterEvents()` and is not delegated to an FTS provider. ## Search semantics Each semantic event is one FTS document carrying session metadata, event metadata, surface classification, and extracted text. All `current`, `shadowed`, and `log-only` documents participate unless a surface filter narrows them. Metadata filters compile to parameterized SQL before ranking. Session results partition matching documents by session and retain the strongest one. -Ordering is deterministic: BM25 ascending, event time descending, session id ascending for the cross-session scope, and seq descending. Provider scores remain private. Snippets normalize whitespace and are bounded by Unicode code points. Opaque cursors bind to the service instance, scope, canonical normalized request, offset, and relevant generation. Any corpus change invalidates cross-session cursors; a within-session cursor changes only when its target source/generation changes, so unrelated sessions do not invalidate it. Reopening creates a new service instance and invalidates old cursors. +Ordering is deterministic and comparable across the persistent and TEMP FTS tables: actual FTS5 highlighted-match span count descending, indexed document code-point length ascending, event time descending, session id ascending for the cross-session scope, and seq descending. Snippets use those actual highlight positions, strip the reserved markers, normalize whitespace, and bound by Unicode code points. Opaque cursors bind to the service instance, scope, canonical normalized request, offset, and relevant generation. Any corpus change invalidates cross-session cursors; a within-session cursor changes only when its target source/generation changes, so unrelated sessions do not invalidate it. Reopening creates a new service instance and invalidates old cursors. -Queries are trimmed, whitespace-normalized, and quoted as one literal FTS5 phrase. Embedded quotes are doubled before binding, so MATCH operators such as `OR`, `NEAR`, quotes, parentheses, and `*` remain data rather than executable query syntax. Phrase matching follows tokenizer tokens rather than arbitrary substrings. +Queries are trimmed, whitespace-normalized, and quoted as one literal FTS5 phrase. Embedded quotes are doubled before binding, so MATCH operators such as `OR`, `NEAR`, quotes, parentheses, and `*` remain data rather than executable query syntax. NUL is rejected before SQLite execution. Reserved highlight noncharacters and NUL in documents are normalized before indexing, making inserted presentation markers collision-free. Phrase matching follows tokenizer tokens rather than arbitrary substrings. ## Tokenizer choice @@ -32,11 +32,11 @@ Both persistent and live FTS5 tables use `unicode61`. The implementation experim The shared extractor includes message text, reasoning, nested tool-call/result content, tool names and arguments, blocked-prompt reasons, todo status/content, and error or terminal status detail. Structural boundaries, stream chunks, request headers, successful completion markers, and unknown declaration-merged event/content variants produce no document. Surface classification reuses `foldSurface()` so search agrees with model-history derivation. -One serialized operation observes complete persisted and live sources, computes stable fingerprints, reconciles rows in one transaction, and executes the query. Unchanged persisted sessions retain their rows and generation. New, changed, and deleted persisted sessions update on the next search. A source or extraction failure cannot mark a row current, and a transaction failure rolls back so a later search retries. +One serialized operation reads the provider-neutral `SessionPersistence` snapshot listing, compares each opaque revision with the revision stored beside the indexed session, loads only new or changed logs, reconciles rows in one transaction, and executes the query. Observation repeats when listing changes during a load; this incorporates a mutating load repair's refreshed revision before commit. Repeated queries and unchanged reopen load no full persisted logs. New, changed, and deleted sessions update on the next stable search. A source or extraction failure cannot mark a row current, and a transaction failure rolls back so a later search retries. Persisted documents survive restarts. Live sessions use connection-local TEMP tables, shadow the persisted base for the same id, and reveal that base on detach. Closing the database drops live rows. Unmounting persistence hides durable rows without treating absence as authoritative deletion; remounting observes and reconciles the backend again. Conflicting immutable live and durable headers fail rather than combining sources. -The derived schema has its own application id and monotonic schema version. A recognized incompatible version resets only this derived database. A database with a foreign application id or unrecognized user tables is refused, which prevents an accidentally configured canonical session database from being reset. +The derived schema has its own application id and monotonic schema version. A recognized incompatible version resets only this derived database. A database with a foreign application id or unrecognized user tables is refused before journal-mode mutation, which prevents an accidentally configured canonical session database from being changed. One service in one process exclusively owns a derived-index path; cross-process writers are unsupported because generations and live TEMP shadow state are connection-owned. Cancellation rejects queued operations and caller waits around asynchronous source observation without committing an aborted observation. Node's synchronous `DatabaseSync` MATCH call cannot be interrupted once it is executing on the JavaScript thread, so the service checks the signal at serialized boundaries but does not promise mid-statement preemption. @@ -46,11 +46,11 @@ Cancellation rejects queued operations and caller waits around asynchronous sour - **Add a phase-one provider registry and coordinator** — rejected because one implementation provides no evidence for registration semantics and would split one reconciliation lifecycle across two owners. - **Persist live overrides immediately** — rejected because live events are not canonical until the existing checkpoint commits. - **Use the FTS5 trigram tokenizer** — rejected because it omits useful queries shorter than three characters and measured about 2.1× the index size of `unicode61`; literal substring filtering remains available through the scan path. -- **Return BM25 scores** — rejected because provider-specific numeric scales are unstable across corpus changes. +- **Use FTS5 BM25 independently in each table** — rejected because scores from differently populated persistent and TEMP corpora are not comparable; actual matched spans and document length have one shared scale. ## Consequences -Search has a small provider-neutral API while its only backend owns every derived-index state transition. The separate database adds configuration and a reconciliation read before queries, but index corruption, reset, and tokenizer changes cannot endanger canonical logs. Persistent fingerprints avoid rewriting unchanged sessions; TEMP live overlays preserve current-session truth without making uncheckpointed events durable. +Search has a small provider-neutral API while its only backend owns every derived-index state transition. The separate database adds configuration and a lightweight snapshot read before queries, but index corruption, reset, and tokenizer changes cannot endanger canonical logs. Durable revisions avoid full-log reads and rewrites for unchanged sessions; TEMP live overlays preserve current-session truth without making uncheckpointed events durable. The chosen tokenizer supports short tokens with a smaller index but does not promise substring recall. Literal phrases make query syntax safe and predictable at the cost of excluding boolean/full MATCH expressions. Cancellation is effective while queued or awaiting sources, but synchronous SQLite execution remains a non-preemptible section. diff --git a/packages/cordis/tool-cordis/src/api-catalog.ts b/packages/cordis/tool-cordis/src/api-catalog.ts index 2859353cfa..7322698cdd 100644 --- a/packages/cordis/tool-cordis/src/api-catalog.ts +++ b/packages/cordis/tool-cordis/src/api-catalog.ts @@ -149,6 +149,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ 'abstract append(id: SessionId, events: readonly SessionEvent[]): Promise', 'abstract load(id: SessionId): Promise<{ meta: SessionHeader; events: SessionEvent[] }>', 'abstract list(): Promise', + 'abstract listSnapshots(): Promise', ], }, { @@ -156,6 +157,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ summary: 'Live-preferred logical-corpus and exact-event read service.', methods: [ 'listSessions(): Promise', + 'async filterSessions(filters: readonly SessionResultFilter[]): Promise', 'async listEvents(sessionId: SessionId): Promise', 'async filterEvents( sessionId: SessionId, filters: readonly SessionEventResultFilter[], ): Promise', 'async readEvent(request: SessionEventReadRequest): Promise', @@ -834,7 +836,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'SessionEventSearchRequest', - declaration: 'export interface SessionEventSearchRequest {\n sessionId: SessionId;\n query: string;\n filters?: readonly SessionEventMetadataFilter[];\n limit?: number;\n cursor?: string;\n}', + declaration: 'export interface SessionEventSearchRequest {\n sessionId: SessionId;\n query: string;\n filters?: readonly SessionEventMetadataFilter[];\n limit?: number;\n cursor?: SessionSearchCursor;\n}', }, { name: 'SessionEventSurface', @@ -860,6 +862,14 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'SessionId', declaration: 'export type SessionId = Branded<\'SessionId\'>;', }, + { + name: 'SessionPersistenceRevision', + declaration: 'export type SessionPersistenceRevision = Branded<\'SessionPersistenceRevision\'>;', + }, + { + name: 'SessionPersistenceSnapshot', + declaration: 'export interface SessionPersistenceSnapshot {\n header: SessionHeader;\n revision: SessionPersistenceRevision;\n}', + }, { name: 'SessionRecord', declaration: 'export interface SessionRecord {\n header: SessionHeader;\n live: boolean;\n persisted: boolean;\n}', @@ -872,6 +882,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'SessionResultRange', declaration: 'export interface SessionResultRange {\n from?: number;\n to?: number;\n}', }, + { + name: 'SessionSearchCursor', + declaration: 'export type SessionSearchCursor = Branded<\'SessionSearchCursor\'>;', + }, { name: 'SessionSearchExecContext', declaration: 'export interface SessionSearchExecContext {\n signal?: AbortSignal;\n}', @@ -882,11 +896,11 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'SessionSearchPage', - declaration: 'export interface SessionSearchPage {\n items: readonly T[];\n nextCursor?: string;\n}', + declaration: 'export interface SessionSearchPage {\n items: readonly T[];\n nextCursor?: SessionSearchCursor;\n}', }, { name: 'SessionSearchRequest', - declaration: 'export interface SessionSearchRequest {\n query: string;\n sessionFilters?: readonly SessionResultFilter[];\n eventFilters?: readonly SessionEventMetadataFilter[];\n limit?: number;\n cursor?: string;\n}', + declaration: 'export interface SessionSearchRequest {\n query: string;\n sessionFilters?: readonly SessionResultFilter[];\n eventFilters?: readonly SessionEventMetadataFilter[];\n limit?: number;\n cursor?: SessionSearchCursor;\n}', }, { name: 'SkillCandidate', diff --git a/packages/session-persistence/session-persistence-jsonl/README.md b/packages/session-persistence/session-persistence-jsonl/README.md index 990ad2fcc4..0be2c785b3 100644 --- a/packages/session-persistence/session-persistence-jsonl/README.md +++ b/packages/session-persistence/session-persistence-jsonl/README.md @@ -25,6 +25,7 @@ The JSONL durable session-persistence backend — a concrete `SessionPersistence - **Append-only.** Committed events (at or below a flushed `turn/end`) are never rewritten. Subsequent appends are line appends at EOF + `fsync`. - **Crash recovery — close, don't truncate.** A crash can leave a log whose final turn never closed (real events after the last `turn/end`). `load` PRESERVES those events (a turn can be huge — they are real work) and closes the orphaned turn by durably appending synthetic boundary events: an error `tool/result` for every `tool-call` the crash left unanswered (the loop logs the assistant message before running the tools, so a mid-tool crash leaves dangling calls — and `deriveMessages()` would replay an assistant tool-call with no result, which providers reject), then a `step/end` if a step was open, then `turn/end {kind:'interrupted'}`, returning a balanced log. Only a never-fully-written **torn tail fragment** (a final line with no newline / unparseable) is `ftruncate`d away before the closers are written. See [session persistence](../../../docs/rfc/implemented/architecture/2026-06-14-session-persistence.md). - **Contiguous-seq.** `load` rejects a mid-log parse error or `seq` gap (unloadable); `append` rejects a batch whose first `seq` does not continue the stored log, and rejects non-JSON-serializable `event.data` naming the offending event type. +- **Lightweight revisions.** `listSnapshots()` reads each header and returns an opaque identity from the file device/inode, size, and nanosecond mtime/ctime. Under the append-only single-writer contract, unchanged files retain revisions while append, repair, or replacement changes them without parsing event lines. - **Format version.** Only the current `SESSION_FORMAT_VERSION` (v0) is supported; `load` rejects any other version. While the harness is unreleased the on-disk format is pre-release/unstable: a breaking format change is absorbed at v0 (no bump until the first tagged release) and non-current logs are rejected — there is no migration (no persisted user data to preserve). ## Write path diff --git a/packages/session-persistence/session-persistence-jsonl/src/index.ts b/packages/session-persistence/session-persistence-jsonl/src/index.ts index bd31e0ae47..0aea7927d1 100644 --- a/packages/session-persistence/session-persistence-jsonl/src/index.ts +++ b/packages/session-persistence/session-persistence-jsonl/src/index.ts @@ -11,7 +11,7 @@ * (the `session/event` → buffer → `session/flush` drain, per-session * serialization, write cursors, fork-seed persistence, HMR live-adoption, * crash-repair sequencing, dispose quiescence) lives in the backend-agnostic - * {@link PersistenceCoordinator} this class composes. The four public + * {@link PersistenceCoordinator} this class composes. The stateful public * {@link SessionPersistence} methods delegate to the coordinator. * * @module @deepseek-ai/dsh-session-persistence-jsonl @@ -19,12 +19,12 @@ import { Context } from 'cordis' import z from 'schemastery' -import { open, mkdir, readFile, readdir, link, rm, truncate } from 'node:fs/promises' +import { open, mkdir, readFile, readdir, link, rm, stat, truncate } from 'node:fs/promises' import { dirname, resolve } from 'node:path' import { randomBytes } from 'node:crypto' import { - SessionPersistence, PersistenceCoordinator, - type PersistenceBackend, type StoredPrefix, + SessionPersistence, SessionPersistenceRevision, PersistenceCoordinator, + type PersistenceBackend, type SessionPersistenceSnapshot, type StoredPrefix, } from '@deepseek-ai/dsh-session-persistence' import type { Session, SessionEvent, SessionId, SessionHeader } from '@deepseek-ai/dsh-session' import { @@ -179,20 +179,44 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi /** List all stored sessions' metadata (header line only — no full-log parse). */ async list(): Promise { - const metas: SessionHeader[] = [] + return (await this.listArtifacts()).map(artifact => artifact.header) + } + + /** List metadata plus a stat-derived identity for each append-only log. */ + async listSnapshots(): Promise { + const snapshots: SessionPersistenceSnapshot[] = [] + for (const artifact of await this.listArtifacts()) { + const identity = await stat(artifact.path, { bigint: true }) + snapshots.push({ + header: artifact.header, + revision: SessionPersistenceRevision([ + identity.dev, + identity.ino, + identity.size, + identity.mtimeNs, + identity.ctimeNs, + ].join(':')), + }) + } + return snapshots + } + + private async listArtifacts(): Promise> { + const artifacts: Array<{ header: SessionHeader; path: string }> = [] for (const dir of await this.listCwdDirs()) { for (const name of await this.listJsonl(dir)) { // Read ONLY the header line, not the whole log: a session picker must // scale with the number of sessions, not the total size of every // conversation (the log persists every assistant/chunk verbatim). - const first = await this.readFirstLine(`${dir}/${name}`) + const path = `${dir}/${name}` + const first = await this.readFirstLine(path) if (first === undefined) continue // empty/half-written file const meta = parseHeaderMeta(first) if (meta === undefined) continue // not a session header - metas.push(meta) + artifacts.push({ header: meta, path }) } } - return metas + return artifacts } // --- materialization / append / repair (file mechanics) --- diff --git a/packages/session-persistence/session-persistence-sqlite/README.md b/packages/session-persistence/session-persistence-sqlite/README.md index 082b60af88..6e6006dc6b 100644 --- a/packages/session-persistence/session-persistence-sqlite/README.md +++ b/packages/session-persistence/session-persistence-sqlite/README.md @@ -6,7 +6,7 @@ A SQLite durable session-persistence backend — a second `SessionPersistence` i ## Storage model -Each `SessionEvent` maps 1:1 onto a row in an `events` table `(session_id, seq, type, time, data, source_event_seqs, surface_op)` — `data` is the event payload as JSON text, so the row shape is the event verbatim (including `assistant/chunk`, keeping `seq` contiguous). The two `TEXT` columns `source_event_seqs` and `surface_op` are nullable; they store the event's optional surface-metadata fields (see [session surface](../../../docs/rfc/implemented/architecture/2026-06-18-session-surface.md)). Out-of-log metadata (`SessionHeader`) lives in a `sessions` row. A `sessions` row is written only by the first `append` — its existence is the lazy-materialization signal (`list` reports exactly the sessions that have a row), so no separate column is needed. +Each `SessionEvent` maps 1:1 onto a row in an `events` table `(session_id, seq, type, time, data, source_event_seqs, surface_op)` — `data` is the event payload as JSON text, so the row shape is the event verbatim (including `assistant/chunk`, keeping `seq` contiguous). The two `TEXT` columns `source_event_seqs` and `surface_op` are nullable; they store the event's optional surface-metadata fields (see [session surface](../../../docs/rfc/implemented/architecture/2026-06-18-session-surface.md)). Out-of-log metadata (`SessionHeader`) and a monotonic per-log revision live in a `sessions` row. A `sessions` row is written only by the first `append` — its existence is the lazy-materialization signal (`list` reports exactly the sessions that have a row). The repo's `engines.node` is `^22.19.0 || >=24.0.0` (Node 22.19+ or 24+), matching the LTS floor required by the installed Pi adapter dependency; `node:sqlite` itself ships without the `--experimental-sqlite` flag from Node 22.13 (LTS) and 23.4 / 24 (Current) on. The range deliberately excludes Node 23 because that line is non-LTS/EOL and still has flagged runtime features before 23.6. The database opens with `foreign_keys = ON` (so `ON DELETE CASCADE` drops a session's events with its row) and the configured `journal_mode` (default `wal`; pick a rollback-journal mode like `delete` on filesystems where WAL's shared-memory files do not work, e.g. network mounts). The table-layout version is stored in `PRAGMA user_version` and checked on open: a fresh database is stamped with the current `SCHEMA_VERSION`; a database written by any other, incompatible build (a non-current `user_version`, older or newer) is rejected rather than opened against an unknown layout — there is no migration (unreleased software). @@ -14,6 +14,7 @@ The repo's `engines.node` is `^22.19.0 || >=24.0.0` (Node 22.19+ or 24+), matchi - **Append = a transaction.** `append` runs `BEGIN`/`COMMIT` around the batch: it materializes the `sessions` row (if still lazy) and INSERTs every event, asserting the contiguous-seq contract first (the first event's `seq` must equal the stored next-seq). A mid-batch failure (a UNIQUE violation on a duplicated seq) rolls back entirely, so the stored log and the in-memory cursor stay consistent. (`load()` already balanced the stored log, so `append` never has to repair a crash tail.) - **Lazy materialization.** `create()` records intent in memory only — no row is written until the first `append`. A created-but-never-appended session has no `sessions` row, so it is absent from `list()` (which reports exactly the sessions that have a row). +- **Lightweight revisions.** `listSnapshots()` reads the monotonic revision stored beside each session header. Append and mutating load repair increment it in the same transaction as their event changes, so unchanged observations are stable and no full-log count or parse is required. - **Interrupted-turn close on load.** `load()` reads every stored event ordered by `seq` and finds the longest seq-contiguous, parseable prefix — INCLUDING the real events of an interrupted final turn after the last `turn/end` (the loop only flushes at `turn/end`, so a process killed mid-turn leaves real, fully-written rows past it). A single turn can be huge in a long-horizon task, so those events are **preserved, never truncated**: `load()` CLOSES the orphaned turn by durably appending the minimal synthetic boundary events (an error `tool/result` for every assistant tool call left unanswered, a `step/end` if a step was open, then a `turn/end` carrying `{ kind: 'interrupted' }`), inside one transaction that also DELETEs any never-fully-written torn tail row. `load()` is therefore mutating — after it the stored rows are balanced and the cursor is truthful, so the next `append` continues cleanly. The boundary (last `turn/end`, torn-tail detection) is computed from the `seq`/`type` columns so a malformed `data` in a torn tail row is never parsed (discarded, not unloadable). A parse error or `seq` gap inside the committed region (at or before the last real `turn/end`) makes the session unloadable. A session whose only turn never closed keeps its metadata row and stays present in `list()` — the same as the JSONL backend, whose file likewise survives a first append that never reached `turn/end`. ## Configuration (schemastery) diff --git a/packages/session-persistence/session-persistence-sqlite/src/index.ts b/packages/session-persistence/session-persistence-sqlite/src/index.ts index 30387b4837..3a1c7ffbcc 100644 --- a/packages/session-persistence/session-persistence-sqlite/src/index.ts +++ b/packages/session-persistence/session-persistence-sqlite/src/index.ts @@ -11,7 +11,7 @@ * Like the JSONL backend it supplies ONLY the storage primitives (the * {@link PersistenceBackend} hooks below — INSERT/DELETE/SELECT inside * transactions); all the write-path orchestration lives in the backend-agnostic - * {@link PersistenceCoordinator} this class composes. The four public + * {@link PersistenceCoordinator} this class composes. The stateful public * {@link SessionPersistence} methods delegate to the coordinator. * * @module @deepseek-ai/dsh-session-persistence-sqlite @@ -23,8 +23,8 @@ import { DatabaseSync } from 'node:sqlite' import { mkdir } from 'node:fs/promises' import { dirname, resolve } from 'node:path' import { - SessionPersistence, PersistenceCoordinator, - type PersistenceBackend, type StoredPrefix, + SessionPersistence, SessionPersistenceRevision, PersistenceCoordinator, + type PersistenceBackend, type SessionPersistenceSnapshot, type StoredPrefix, } from '@deepseek-ai/dsh-session-persistence' import type { Session, SessionEvent, SurfaceEventType, SessionId, SessionHeader } from '@deepseek-ai/dsh-session' import { @@ -181,6 +181,7 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers const [surfaceSeqs, surfaceOp] = surfaceBindings(event) insertEvent.run(meta.id, event.seq, event.type, event.time, JSON.stringify(event.data), surfaceSeqs, surfaceOp) } + this.db.prepare('UPDATE sessions SET revision = revision + 1 WHERE id = ?').run(meta.id) this.db.exec('COMMIT') } catch (error) { this.db.exec('ROLLBACK') @@ -209,6 +210,9 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers insertEvent.run(meta.id, event.seq, event.type, event.time, JSON.stringify(event.data), surfaceSeqs, surfaceOp) } } + if (tornMarker !== undefined || closers.length > 0) { + this.db.prepare('UPDATE sessions SET revision = revision + 1 WHERE id = ?').run(meta.id) + } this.db.exec('COMMIT') } catch (error) { // The DELETE+INSERT cannot collide (a row at a closer's seq is preserved or @@ -230,6 +234,16 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers return rows.map(rowToMeta) } + /** List metadata with an append-only event-count revision per session. */ + async listSnapshots(): Promise { + await this.ready + const rows = this.db.prepare('SELECT * FROM sessions').all() as unknown as SessionRow[] + return rows.map(row => ({ + header: rowToMeta(row), + revision: SessionPersistenceRevision(`revision:${row.revision}`), + })) + } + /** Close the database handle (awaited by the coordinator's dispose, post-drain). */ async close(): Promise { await this.ready @@ -250,8 +264,8 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers */ private writeRow(meta: SessionHeader): void { this.db.prepare(` - INSERT INTO sessions (id, version, created_at, cwd, parent_session, seed_length) - VALUES (?, ?, ?, ?, ?, ?) + INSERT INTO sessions (id, version, created_at, cwd, parent_session, seed_length, revision) + VALUES (?, ?, ?, ?, ?, ?, 0) ON CONFLICT(id) DO UPDATE SET version = excluded.version, created_at = excluded.created_at, diff --git a/packages/session-persistence/session-persistence-sqlite/src/schema.ts b/packages/session-persistence/session-persistence-sqlite/src/schema.ts index 2dacbe04a0..2f238b0131 100644 --- a/packages/session-persistence/session-persistence-sqlite/src/schema.ts +++ b/packages/session-persistence/session-persistence-sqlite/src/schema.ts @@ -15,7 +15,7 @@ import type { SessionEvent, SessionId, SessionHeader, SurfaceOp } from '@deepsee * layout; orthogonal to a session's own `version` (which versions the EVENT * vocabulary, stored per session in the `sessions` row). */ -export const SCHEMA_VERSION = 4 +export const SCHEMA_VERSION = 5 /** * A row of the `sessions` table — the out-of-log metadata ({@link SessionHeader}). @@ -31,6 +31,8 @@ export interface SessionRow { cwd: string | null parent_session: string | null seed_length: number | null + /** Monotonic log-change token incremented in each mutating transaction. */ + revision: number } /** An `events` table row: one `SessionEvent` mapped 1:1 (`data` is JSON text). */ @@ -67,15 +69,9 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' * current {@link SCHEMA_VERSION}; an existing database whose version is NOT the * current one (written by a different, incompatible build — older or newer) is * REJECTED rather than opened against a layout this build does not understand. - * There are no migrations: an earlier layout is not upgraded in place — it is - * rejected. v1 had a different `sessions` shape; v2 lacked all of - * `seed_length`/`source_event_seqs`/`surface_op`. v3 is SKIPPED: two unmerged - * branches each shipped a DISTINCT v3 (one adding only `seed_length`, the other - * adding only the surface columns), so an on-disk v3 is ambiguous — it could be - * either sibling layout, neither of which has all of this build's columns. v4 - * is the merged layout carrying every column; bumping past the collided v3 - * makes the version check reject both sibling v3 databases instead of opening - * one against columns it does not have. + * There are no migrations: an incompatible layout is rejected. The current + * sessions row carries every header field plus its monotonic snapshot revision; + * the events row carries the complete surface metadata. * @param path - the SQLite database file to open (created when absent). * @param journalMode - the journal pragma to apply — a closed in-code union, validated by the plugin Config. * @returns the open handle with pragmas applied and both tables ensured. @@ -105,7 +101,8 @@ export function openDatabase(path: string, journalMode: JournalMode): DatabaseSy created_at INTEGER NOT NULL, cwd TEXT, parent_session TEXT, - seed_length INTEGER + seed_length INTEGER, + revision INTEGER NOT NULL ) STRICT `) db.exec(` diff --git a/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts b/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts index a6eda72685..98924ca691 100644 --- a/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts +++ b/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts @@ -258,11 +258,11 @@ describe('SessionPersistenceSqlite: durability and crash semantics', () => { it('rejects a sibling v3 database (the merge-collided version) rather than opening it against missing columns', async () => { // Two unmerged branches each shipped a DISTINCT layout under user_version 3 // (one added only `seed_length`, the other only the surface columns). The - // merged build is v4; an on-disk v3 is ambiguous and is missing at least one + // the current build rejects every older layout; an on-disk v3 is ambiguous and is missing at least one // of this build's columns, so it MUST be rejected, not opened. Stamp a v3 // database and confirm the version check refuses it. const path = await freshDbPath() - openDatabase(path, 'wal').close() // creates + stamps user_version = SCHEMA_VERSION (4) + openDatabase(path, 'wal').close() // creates + stamps user_version = SCHEMA_VERSION const db = openDatabase(path, 'wal') db.exec('PRAGMA user_version = 3') db.close() @@ -338,7 +338,18 @@ describe('SessionPersistenceSqlite: durability and crash semantics', () => { }) it('exposes the schema version constant', () => { - expect(SCHEMA_VERSION).toBe(4) + expect(SCHEMA_VERSION).toBe(5) + }) + + it('keeps the revision stable for an empty repair hook', async () => { + const b = await backend() + const m = meta('empty-repair') + await b.ctx.sessionPersistence.create(m) + await b.ctx.sessionPersistence.append(m.id, oneTurnLog()) + const before = await b.ctx.sessionPersistence.listSnapshots() + await (b.ctx.sessionPersistence as SessionPersistenceSqlite).commitRepair(m, undefined, []) + expect(await b.ctx.sessionPersistence.listSnapshots()).toEqual(before) + await b.dispose() }) }) diff --git a/packages/session-persistence/session-persistence/README.md b/packages/session-persistence/session-persistence/README.md index bf7da03757..32958bfaaa 100644 --- a/packages/session-persistence/session-persistence/README.md +++ b/packages/session-persistence/session-persistence/README.md @@ -12,6 +12,7 @@ The persisted unit IS the existing `SessionEvent` (event-sourced model — the l | `append(id, events): Promise` | Durably persist a batch (from the `session/flush` drain). Append-only; first event `seq` == stored next-seq after any repair; rejects non-JSON-serializable data naming the offending type. | | `load(id): Promise<{ meta; events }>` | Reload meta + log. Preserves an interrupted (unclosed) final turn and closes it with synthetic closers — an error `tool/result` per unanswered `tool-call`, then `step/end?`+`turn/end {interrupted}` (a turn can be huge — never truncated); only a torn tail fragment is dropped. Events contiguous (`events[i].seq === i`); rejects a committed-region gap/parse error or unknown `version`. | | `list(): Promise` | Lightweight listing from metadata, no full-log parse. A zero-event lazily-materialized session is absent from `list`. | +| `listSnapshots(): Promise` | Lightweight metadata plus an opaque branded per-log revision, without loading event logs. A revision stays equal while that log is unchanged and changes after append or mutating load repair. | ## Invariants every backend must honor @@ -24,7 +25,7 @@ The persisted unit IS the existing `SessionEvent` (event-sourced model — the l The two first-party backends were byte-identical (or same-algorithm) for ALL of their write-path orchestration — the in-memory bookkeeping (per-id state, write-behind buffers, per-id serialization chains, per-session init promises), the `session/event` → buffer → `session/flush` drain, lazy materialization, crash-tail repair on load, the four `session/created` adoption cases (new / HMR-adopt / collision / ownerless-claim), and dispose-time quiescence. Only the STORAGE primitives differed (write bytes vs. INSERT rows). -`PersistenceCoordinator` owns that orchestration once. A first-party backend composes one (`new PersistenceCoordinator(ctx, this)`), implements the small `PersistenceBackend` hook interface, and delegates its four public service methods to the coordinator. This keeps the duplicated, correctness-heavy orchestration in a single place (it used to receive the same fixes twice). +`PersistenceCoordinator` owns that orchestration once. A first-party backend composes one (`new PersistenceCoordinator(ctx, this)`), implements the small `PersistenceBackend` hook interface, and delegates the stateful write/read methods to the coordinator. Lightweight snapshot listing remains a backend storage primitive because its revision identity is backend-owned. The `PersistenceBackend` hooks (the only seam between the coordinator and storage): @@ -38,11 +39,11 @@ The `PersistenceBackend` hooks (the only seam between the coordinato | `list()` | List all stored metadata. | | `close?()` | Optional lifecycle teardown (e.g. close a db handle), awaited after the dispose drain. | -The `tornMarker` is fully OPAQUE: the coordinator only tests `!== undefined` and round-trips it to `commitRepair`, never inspecting its value (the JSONL backend uses the byte offset to truncate to, the SQLite backend the seq to delete from). The public `SessionPersistence` service shape is unchanged, so a third-party backend MAY still implement the abstract service directly without the coordinator. See [the write-coordinator RFC](../../../docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md). +The `tornMarker` is fully OPAQUE: the coordinator only tests `!== undefined` and round-trips it to `commitRepair`, never inspecting its value (the JSONL backend uses the byte offset to truncate to, the SQLite backend the seq to delete from). A third-party backend MAY implement the abstract service directly without the coordinator, but it must also provide trustworthy lightweight snapshot revisions. See [the write-coordinator RFC](../../../docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md). ## Testing backends -Import `runPersistenceContract` from `tests/contract.ts` (the public-API contract) and `runCoordinatorContract` from `tests/coordinator-contract.ts` (the shared write-path orchestration: adoption, HMR, collision, dispose-drain, crash-tail repair) and call each with a fixture for your backend. Every backend is held to the same append-only / contiguous-seq / lazy-materialization / serializability semantics AND the same orchestration, so a backend's own spec is left with only storage-mechanics tests (path sanitization, fsync rollback; schema version, transaction rollback) on top. +Import `runPersistenceContract` from `tests/contract.ts` (the public API, including stable/change-sensitive lightweight revisions) and `runCoordinatorContract` from `tests/coordinator-contract.ts` (the shared write-path orchestration: adoption, HMR, collision, dispose-drain, crash-tail repair) and call each with a fixture for your backend. Every backend is held to the same append-only / contiguous-seq / lazy-materialization / serializability semantics AND the same orchestration, so a backend's own spec is left with only storage-mechanics tests (path sanitization, fsync rollback; schema version, transaction rollback) on top. Three backends run these suites: an in-memory reference (in `tests/`), `dsh-session-persistence-jsonl` (append-only file log) and `dsh-session-persistence-sqlite` (`node:sqlite`, each `SessionEvent` one row `(session_id, seq, type, time, data, source_event_seqs, surface_op)`). All passing the same contract + coordinator suite is the proof that the seam is genuinely backend-agnostic — lazy materialization, crash-tail-on-load, and contiguous-seq hold identically over file bytes and over a transactional store. diff --git a/packages/session-persistence/session-persistence/package.json b/packages/session-persistence/session-persistence/package.json index ed6c80dfd9..8b7140e221 100644 --- a/packages/session-persistence/session-persistence/package.json +++ b/packages/session-persistence/session-persistence/package.json @@ -22,10 +22,12 @@ ], "license": "BSD-3-Clause", "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.0.1", "@deepseek-ai/dsh-session": "^0.0.1", "cordis": "^4.0.0-rc.6" }, "devDependencies": { + "@deepseek-ai/dsh-brand": "workspace:^", "@deepseek-ai/dsh-session": "workspace:^", "cordis": "^4.0.0-rc.6" } diff --git a/packages/session-persistence/session-persistence/src/coordinator.ts b/packages/session-persistence/session-persistence/src/coordinator.ts index b1fc118a21..7857b57a3c 100644 --- a/packages/session-persistence/session-persistence/src/coordinator.ts +++ b/packages/session-persistence/session-persistence/src/coordinator.ts @@ -14,7 +14,7 @@ * {@link PersistenceBackend} hook object. * * The abstract {@link SessionPersistence} service's public API is independent of - * this: a backend IS a `SessionPersistence` (its four public methods delegate to + * this: a backend IS a `SessionPersistence` (its write/read methods delegate to * a coordinator it composes), so a third-party backend MAY implement the service * directly without using the coordinator at all. * @@ -146,7 +146,7 @@ async function settledErrors(promises: Iterable>): Promise + + /** + * List materialized sessions with cheap per-log change tokens. + * + * Repeated observations of an unchanged log return the same revision. A + * successful mutating {@link load} repair changes the next listed revision. + * @returns one header and opaque revision per materialized session without loading full logs. + */ + abstract listSnapshots(): Promise } export default SessionPersistence diff --git a/packages/session-persistence/session-persistence/src/revision.ts b/packages/session-persistence/session-persistence/src/revision.ts new file mode 100644 index 0000000000..41378eb3e4 --- /dev/null +++ b/packages/session-persistence/session-persistence/src/revision.ts @@ -0,0 +1,15 @@ +/** Opaque revision identity for lightweight persistence observations. */ + +import type { Branded } from '@deepseek-ai/dsh-brand' + +/** Backend-owned token that changes whenever one persisted session log changes. */ +export type SessionPersistenceRevision = Branded<'SessionPersistenceRevision'> + +/** + * Brand a backend revision for the provider-neutral persistence contract. + * @param value - backend-owned opaque revision representation. + * @returns the same runtime string with persistence-revision identity. + */ +export function SessionPersistenceRevision(value: string): SessionPersistenceRevision { + return value as SessionPersistenceRevision +} diff --git a/packages/session-persistence/session-persistence/tests/contract.ts b/packages/session-persistence/session-persistence/tests/contract.ts index 789aa72c91..d1699c58a5 100644 --- a/packages/session-persistence/session-persistence/tests/contract.ts +++ b/packages/session-persistence/session-persistence/tests/contract.ts @@ -102,11 +102,16 @@ export function runPersistenceContract(name: string, make: () => Promise snapshot.header.id === m.id)?.revision // load PRESERVES the interrupted turn's events (a turn can be huge — they // must not be truncated) and closes the orphaned turn with synthetic // boundary events: step/end (the step was open) then turn/end {interrupted}. const loaded = await persistence.load(m.id) + const afterRepair = (await persistence.listSnapshots()) + .find(snapshot => snapshot.header.id === m.id)?.revision + expect(afterRepair).not.toBe(beforeRepair) expect(loaded.events.map(e => e.type)).toEqual([ 'turn/start', 'user/message', 'step/start', 'assistant/message', 'step/end', 'turn/end', // turn 1 'turn/start', 'step/start', 'step/end', 'turn/end', // turn 2: real events + synthetic closers @@ -173,18 +178,33 @@ export function runPersistenceContract(name: string, make: () => Promise m.id)).not.toContain(SessionId('empty')) + expect((await persistence.listSnapshots()).map(snapshot => snapshot.header.id)) + .not.toContain(SessionId('empty')) } finally { await dispose() } }) - it('list() includes a session once it has events', async () => { + it('lists stable lightweight revisions that change after an append', async () => { const { persistence, dispose } = await make() try { const m = meta('s2') await persistence.create(m) await persistence.append(m.id, oneTurnLog()) expect((await persistence.list()).map(x => x.id)).toContain(m.id) + const first = (await persistence.listSnapshots()).find(snapshot => snapshot.header.id === m.id) + const repeated = (await persistence.listSnapshots()).find(snapshot => snapshot.header.id === m.id) + expect(first).toBeDefined() + expect(repeated?.revision).toBe(first?.revision) + + await persistence.append(m.id, [{ + type: 'turn/start', + seq: 6, + time: 7, + data: { turn: 2, trigger: { kind: 'message', source: { kind: 'user' } } }, + }]) + const changed = (await persistence.listSnapshots()).find(snapshot => snapshot.header.id === m.id) + expect(changed?.revision).not.toBe(first?.revision) } finally { await dispose() } diff --git a/packages/session-persistence/session-persistence/tests/persistence.spec.ts b/packages/session-persistence/session-persistence/tests/persistence.spec.ts index 9c766d4b66..00e9863bb8 100644 --- a/packages/session-persistence/session-persistence/tests/persistence.spec.ts +++ b/packages/session-persistence/session-persistence/tests/persistence.spec.ts @@ -3,8 +3,8 @@ import { Context } from 'cordis' import SessionStore, { SessionId, isJsonValue } from '@deepseek-ai/dsh-session' import type { Session, SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session' import { - SessionPersistence, PersistenceCoordinator, assertSerializable, seedCoversPrefix, - type PersistenceBackend, type StoredPrefix, + SessionPersistence, SessionPersistenceRevision, PersistenceCoordinator, assertSerializable, seedCoversPrefix, + type PersistenceBackend, type SessionPersistenceSnapshot, type StoredPrefix, } from '../src/index.ts' import { runPersistenceContract, meta, oneTurnLog } from './contract.ts' import { runCoordinatorContract, type CoordinatorFixture } from './coordinator-contract.ts' @@ -109,6 +109,14 @@ class MemoryPersistence extends SessionPersistence implements PersistenceBackend async list(): Promise { return [...this.store.values()].map(e => structuredClone(e.meta)) } + + + async listSnapshots(): Promise { + return [...this.store.values()].map(entry => ({ + header: structuredClone(entry.meta), + revision: SessionPersistenceRevision(`events:${entry.events.length}`), + })) + } } // Run the shared contract against the in-memory backend. diff --git a/packages/session-persistence/session-persistence/tsconfig.json b/packages/session-persistence/session-persistence/tsconfig.json index e817086a6a..84c6f5ccb0 100644 --- a/packages/session-persistence/session-persistence/tsconfig.json +++ b/packages/session-persistence/session-persistence/tsconfig.json @@ -14,6 +14,9 @@ { "path": "../../../vendor/cordis" }, + { + "path": "../../util/brand" + }, { "path": "../../core/session" } diff --git a/packages/session-query/session-query-sqlite/README.md b/packages/session-query/session-query-sqlite/README.md index 1f3344887f..001ea87d7d 100644 --- a/packages/session-query/session-query-sqlite/README.md +++ b/packages/session-query/session-query-sqlite/README.md @@ -1,22 +1,22 @@ # @deepseek-ai/dsh-session-query-sqlite -SQLite FTS5 implementation of `ctx.sessionSearch`. The service searches the live-preferred logical session corpus, groups cross-session results by their strongest event, and keeps provider-specific BM25 scores private. +SQLite FTS5 implementation of `ctx.sessionSearch`. The service searches the live-preferred logical session corpus and groups cross-session results by their strongest event. ## Search contract `searchSessions(request, exec?)` returns `SessionSearchHit` pages across the corpus; `searchEvents(request, exec?)` returns `SessionEventSearchHit` pages within one session. Queries are required, trimmed, whitespace-normalized literal phrases. FTS5 syntax such as quotes, `OR`, `NEAR`, and `*` is treated as data rather than executable MATCH syntax. Metadata filters are parameterized SQL predicates applied before ranking. -Ordering is deterministic: relevance first, then event time, session id where applicable, and seq. Cross-session results expose the selected event as `bestMatch`; both scopes return plain-text snippets bounded in Unicode code points. Cursors are opaque, bind to the normalized request and service instance, and fail when the relevant generation changes. A within-session cursor survives unrelated-session changes; a cross-session cursor does not. +Relevance is source-comparable across persistent and TEMP tables: actual FTS5 highlighted-match span count descending, then stored document code-point length ascending. Event time, session id where applicable, and seq break remaining ties. Cross-session results expose the selected event as `bestMatch`; both scopes derive whitespace-normalized plain text from FTS5 highlight positions and bound it in Unicode code points. Cursors are opaque branded values, bind to the normalized request and service instance, and fail when the relevant generation changes. A within-session cursor survives unrelated-session changes; a cross-session cursor does not. All three surfaces (`current`, `shadowed`, and `log-only`) are searchable by default. Pass a surface filter to narrow them. ## Source and index lifecycle -The service requires `ctx.sessions` and observes optional `ctx.sessionPersistence` dynamically. One serialized state machine observes complete sources, extracts shared semantic documents, reconciles changes transactionally, and runs the query. Stable fingerprints preserve unchanged persisted rows and generations; new, changed, and deleted durable sessions reconcile on the next search. Source or transaction failure commits nothing, and the next search retries. +The service requires `ctx.sessions` and observes optional `ctx.sessionPersistence` dynamically. One serialized state machine compares lightweight durable snapshot revisions, loads only new or changed logs, extracts shared semantic documents, reconciles changes transactionally, and runs the query. Repeated queries and unchanged reopen load no full durable logs; new, changed, deleted, or load-repaired sources reconcile on the next stable observation. Source or transaction failure commits nothing, and the next search retries. Persisted FTS rows live in a dedicated derived database. Connection-local TEMP tables hold live rows, which shadow the durable base for the same session and reveal it when the live owner disappears. Unmounting persistence hides durable rows without discarding the cache; remounting reconciles it. Closing or reopening the database drops every live overlay while retaining persisted rows. -The database is disposable but reset is guarded: a recognized incompatible search schema rebuilds in place, while an unrelated or canonical database is refused. Never point `path` at the session-persistence database. +The database is disposable but reset is guarded: a recognized incompatible search schema rebuilds in place, while an unrelated or canonical database is refused before mutating journal mode. Never point `path` at the session-persistence database. Exactly one service in one process owns a derived-index path; external writers or a second process are unsupported because generations and TEMP shadow state are connection-owned. ## Configuration @@ -30,6 +30,6 @@ The database is disposable but reset is guarded: a recognized incompatible searc ## Tokenizer and limits -The index uses FTS5 `unicode61`. In the implementation experiment it supported the two-character query `AI` and produced an index about 2.1× smaller than the trigram alternative. The trade-off is token/phrase recall rather than arbitrary substring recall: `AI` does not match the token `BRAID`. Use `ctx.sessionQuery.filterEvents()` with a `text` clause when a literal whitespace-flexible substring scan is required. +The index uses FTS5 `unicode61`. In the implementation experiment it supported the two-character query `AI` and produced an index about 2.1× smaller than the trigram alternative. The trade-off is token/phrase recall rather than arbitrary substring recall: `AI` does not match the token `BRAID`. Use `ctx.sessionQuery.filterEvents()` with a `text` clause when a literal whitespace-flexible substring scan is required. NUL is rejected in queries; reserved highlight markers and NUL in documents are normalized before indexing so presentation markers cannot collide with source text. Abort signals stop queued work and caller waits around asynchronous source observation. Node's synchronous `DatabaseSync` API cannot interrupt a MATCH statement already executing on the JavaScript thread; the signal is checked immediately before and after the serialized observation/reconciliation boundary. diff --git a/packages/session-query/session-query-sqlite/src/index.ts b/packages/session-query/session-query-sqlite/src/index.ts index a6cba8d866..dd1ddb532a 100644 --- a/packages/session-query/session-query-sqlite/src/index.ts +++ b/packages/session-query/session-query-sqlite/src/index.ts @@ -6,12 +6,17 @@ import { createHash, randomUUID } from 'node:crypto' import { DatabaseSync } from 'node:sqlite' -import { Context } from 'cordis' +import { Context, type Fiber } from 'cordis' import z from 'schemastery' import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session' import type SessionPersistence from '@deepseek-ai/dsh-session-persistence' +import type { + SessionPersistenceRevision, + SessionPersistenceSnapshot, +} from '@deepseek-ai/dsh-session-persistence' import { SessionQueryError, + SessionSearchCursor, SessionSearchService, assertSessionHeadersCompatible, buildSessionEventSearchDocuments, @@ -22,6 +27,7 @@ import type { SessionEventSearchRequest, SessionSearchExecContext, SessionSearchHit, + SessionSearchCursor as SessionSearchCursorValue, SessionSearchPage, SessionSearchRequest, } from '@deepseek-ai/dsh-session-query' @@ -32,6 +38,8 @@ import { import { type NormalizedEventRequest, type NormalizedSessionRequest, + FTS_HIGHLIGHT_END, + FTS_HIGHLIGHT_START, buildEventWhere, buildSessionWhere, makeSnippet, @@ -39,6 +47,7 @@ import { normalizeSessionRequest, quoteFtsData, requestFingerprint, + sanitizeFtsText, } from './query.ts' export { @@ -78,19 +87,30 @@ interface ResolvedConfig { interface ObservedSession { header: SessionHeader - events: SessionEvent[] documents: SessionEventSearchDocument[] fingerprint: string } +interface ObservedPersistedSession { + header: SessionHeader + revision: SessionPersistenceRevision + loaded?: ObservedSession +} + interface Observation { persistence: SessionPersistence | undefined persistenceRevision: number - persisted: Map + persisted: Map live: Map } -interface IndexedRow { +interface IndexedPersistedRow { + id: string + revision: string + generation: number +} + +interface IndexedLiveRow { id: string fingerprint: string generation: number @@ -109,8 +129,9 @@ interface SearchRow { type: string time: number surface: string - text: string - score: number + marked_text: string + match_count: number + document_length: number } interface CursorPayload { @@ -149,27 +170,32 @@ export class SessionSearchSqlite extends SessionSearchService { private _localGeneration = 0 private _tail: Promise = Promise.resolve() private _closed = false + private _closePromise: Promise | undefined + private readonly _optionalPersistenceFiber: Fiber constructor(ctx: Context, config: Config) { super(ctx) this.config = resolveConfig(config) this._ready = this._open() - ctx.effect(() => { - const fiber = ctx.inject(['sessionPersistence'], (childCtx: Context) => { - const service = childCtx.sessionPersistence - const binding = {} - this._persistenceBinding = binding - this._persistence = service + // Attach a rejection observer immediately; callers still receive the same + // rejection from `_ready`, including when no search is ever attempted. + void this._ready.catch(() => undefined) + this._optionalPersistenceFiber = ctx.inject(['sessionPersistence'], (childCtx: Context) => { + const service = childCtx.sessionPersistence + const binding = {} + this._persistenceBinding = binding + this._persistence = service + this._persistenceRevision += 1 + childCtx.effect(() => () => { + /* v8 ignore next -- a stale optional-service disposer cannot clear a replacement */ + if (this._persistenceBinding !== binding) return + this._persistenceBinding = undefined + this._persistence = undefined this._persistenceRevision += 1 - childCtx.effect(() => () => { - /* v8 ignore next -- a stale optional-service disposer cannot clear a replacement */ - if (this._persistenceBinding !== binding) return - this._persistenceBinding = undefined - this._persistence = undefined - this._persistenceRevision += 1 - }, 'sessionSearchSqlite.persistenceBinding') - }) - return () => void fiber.dispose() + }, 'sessionSearchSqlite.persistenceBinding') + }) + ctx.effect(() => { + return () => this._optionalPersistenceFiber.dispose() }, 'sessionSearchSqlite.optionalPersistence') ctx.effect(() => async () => this.close(), 'sessionSearchSqlite.close') } @@ -179,17 +205,18 @@ export class SessionSearchSqlite extends SessionSearchService { exec?: SessionSearchExecContext, ): Promise> { const normalized = normalizeSessionRequest(request, this.config) - return this._serialized(exec?.signal, async () => { - await this._ensureReady(exec?.signal) - await this._reconcile(exec?.signal) - assertNotAborted(exec?.signal) + const signal = exec?.signal + return this._serialized(signal, async () => { + await this._ensureReady(signal) + await this._reconcile(signal) + assertNotAborted(signal) const generation = String(this._globalGeneration) const fingerprint = requestFingerprint(normalized) const offset = normalized.cursor === undefined ? 0 : decodeCursor(normalized.cursor, this._instance, 'sessions', fingerprint, generation) const rows = this._querySessions(normalized, offset) - return page(rows, normalized.limit, row => this._sessionHit(row, normalized.query), cursorOffset => encodeCursor({ + return page(rows, normalized.limit, row => this._sessionHit(row), cursorOffset => encodeCursor({ version: 1, instance: this._instance, scope: 'sessions', @@ -205,17 +232,18 @@ export class SessionSearchSqlite extends SessionSearchService { exec?: SessionSearchExecContext, ): Promise> { const normalized = normalizeEventRequest(request, this.config) - return this._serialized(exec?.signal, async () => { - await this._ensureReady(exec?.signal) - await this._reconcile(exec?.signal) - assertNotAborted(exec?.signal) + const signal = exec?.signal + return this._serialized(signal, async () => { + await this._ensureReady(signal) + await this._reconcile(signal) + assertNotAborted(signal) const generation = this._targetGeneration(normalized.sessionId) const fingerprint = requestFingerprint(normalized) const offset = normalized.cursor === undefined ? 0 : decodeCursor(normalized.cursor, this._instance, 'events', fingerprint, generation) const rows = this._queryEvents(normalized, offset) - return page(rows, normalized.limit, row => this._eventHit(row, normalized.query), cursorOffset => encodeCursor({ + return page(rows, normalized.limit, row => this._eventHit(row), cursorOffset => encodeCursor({ version: 1, instance: this._instance, scope: 'events', @@ -227,8 +255,12 @@ export class SessionSearchSqlite extends SessionSearchService { } /** Close the database after every accepted operation reaches quiescence. */ - async close(): Promise { - if (this._closed) return + close(): Promise { + this._closePromise ??= this._close() + return this._closePromise + } + + private async _close(): Promise { this._closed = true await this._tail try { @@ -287,20 +319,20 @@ export class SessionSearchSqlite extends SessionSearchService { } private async _reconcile(signal: AbortSignal | undefined): Promise { - const observation = await this._observeStable(signal) - assertNotAborted(signal) const db = this._requireDb() const persistedRows = db.prepare( - 'SELECT id, fingerprint, generation FROM persisted_sessions', - ).all() as unknown as IndexedRow[] + 'SELECT id, revision, generation FROM persisted_sessions', + ).all() as unknown as IndexedPersistedRow[] const liveRows = db.prepare( 'SELECT id, fingerprint, generation FROM temp.live_sessions', - ).all() as unknown as IndexedRow[] + ).all() as unknown as IndexedLiveRow[] const persistedById = new Map(persistedRows.map(row => [row.id as SessionId, row])) const liveById = new Map(liveRows.map(row => [row.id as SessionId, row])) + const observation = await this._observeStable(persistedById, signal) + assertNotAborted(signal) const persistentChanges = observation.persistence === undefined ? [] - : [...observation.persisted.values()].filter(entry => persistedById.get(entry.header.id)?.fingerprint !== entry.fingerprint) + : [...observation.persisted.values()].filter(entry => entry.loaded !== undefined) const persistentDeletes = observation.persistence === undefined ? [] : persistedRows.filter(row => !observation.persisted.has(row.id as SessionId)) @@ -327,13 +359,17 @@ export class SessionSearchSqlite extends SessionSearchService { db.exec('BEGIN IMMEDIATE') began = true for (const row of persistentDeletes) this._deleteSession('persisted', row.id as SessionId) - for (const entry of persistentChanges) this._replaceSession('persisted', entry, nextMainGeneration) + for (const entry of persistentChanges) { + /* v8 ignore next -- observation loads every entry whose revision differs */ + if (entry.loaded === undefined) throw new Error(`missing loaded revision for session "${entry.header.id}"`) + this._replacePersistedSession(entry.loaded, entry.revision, nextMainGeneration) + } if (persistentChanges.length > 0 || persistentDeletes.length > 0) { db.prepare('UPDATE search_state SET global_generation = ? WHERE singleton = 1').run(nextMainGeneration) } for (const row of liveDeletes) this._deleteSession('live', row.id as SessionId) for (const { entry, generation } of liveReplacements) { - this._replaceSession('live', entry, generation) + this._replaceLiveSession(entry, generation) } db.exec('COMMIT') } catch (error: unknown) { @@ -360,21 +396,39 @@ export class SessionSearchSqlite extends SessionSearchService { this._lastPersistenceRevision = observation.persistenceRevision } - private async _observeStable(signal: AbortSignal | undefined): Promise { + private async _observeStable( + indexed: ReadonlyMap, + signal: AbortSignal | undefined, + ): Promise { for (;;) { assertNotAborted(signal) const persistence = this._persistence const persistenceRevision = this._persistenceRevision - const persisted = new Map() + let persisted = new Map() if (persistence !== undefined) { try { - const headers = await waitWithAbort(persistence.list(), signal) - for (const listed of headers) { - const loaded = await waitWithAbort(persistence.load(listed.id), signal) - assertSessionHeadersCompatible(listed, loaded.meta) - persisted.set(listed.id, observeSession(loaded.meta, loaded.events)) + const canReuseIndexed = this._lastPersistenceRevision === undefined + || this._lastPersistenceRevision === persistenceRevision + const before = await waitWithAbort(persistence.listSnapshots(), signal) + persisted = materializePersistenceSnapshots(before) + for (const entry of persisted.values()) { + if (canReuseIndexed && indexed.get(entry.header.id)?.revision === entry.revision) continue + const loaded = await waitWithAbort(persistence.load(entry.header.id), signal) + assertSessionHeadersCompatible(entry.header, loaded.meta) + entry.loaded = observeSession(loaded.meta, loaded.events) } + const after = materializePersistenceSnapshots( + await waitWithAbort(persistence.listSnapshots(), signal), + ) + if (!samePersistenceSnapshots(persisted, after)) continue + if (this._persistenceRevision !== persistenceRevision) continue } catch (error: unknown) { + if (isAbort(error) || signal?.aborted) { + throw new SessionQueryError('session-search aborted', 'SESSION_QUERY_ABORTED', { + cause: error, + }) + } + if (this._persistenceRevision !== persistenceRevision) continue if (error instanceof SessionQueryError) throw error throw new SessionQueryError( `session-search persistence observation failed: ${errorMessage(error)}`, @@ -414,13 +468,50 @@ export class SessionSearchSqlite extends SessionSearchService { } } - private _replaceSession(source: 'persisted' | 'live', entry: ObservedSession, generation: number): void { - this._deleteSession(source, entry.header.id) + private _replacePersistedSession( + entry: ObservedSession, + revision: SessionPersistenceRevision, + generation: number, + ): void { + this._deleteSession('persisted', entry.header.id) const db = this._requireDb() - const sessionTable = source === 'persisted' ? 'persisted_sessions' : 'temp.live_sessions' - const docsTable = source === 'persisted' ? 'persisted_docs' : 'temp.live_docs' db.prepare(` - INSERT INTO ${sessionTable} + INSERT INTO persisted_sessions + (id, version, created_at, cwd, parent_session, seed_length, revision, generation) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + `).run( + entry.header.id, + entry.header.version, + entry.header.createdAt, + entry.header.cwd ?? null, + entry.header.parentSession ?? null, + entry.header.seedLength ?? null, + revision, + generation, + ) + const insert = db.prepare(` + INSERT INTO persisted_docs (text, session_id, seq, type, time, surface, codepoint_length) + VALUES (?, ?, ?, ?, ?, ?, ?) + `) + for (const document of entry.documents) { + const text = sanitizeFtsText(document.text) + insert.run( + text, + document.sessionId, + document.seq, + document.type, + document.time, + document.surface, + Array.from(text).length, + ) + } + } + + private _replaceLiveSession(entry: ObservedSession, generation: number): void { + this._deleteSession('live', entry.header.id) + const db = this._requireDb() + db.prepare(` + INSERT INTO temp.live_sessions (id, version, created_at, cwd, parent_session, seed_length, fingerprint, generation) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `).run( @@ -434,11 +525,20 @@ export class SessionSearchSqlite extends SessionSearchService { generation, ) const insert = db.prepare(` - INSERT INTO ${docsTable} (text, session_id, seq, type, time, surface) - VALUES (?, ?, ?, ?, ?, ?) + INSERT INTO temp.live_docs (text, session_id, seq, type, time, surface, codepoint_length) + VALUES (?, ?, ?, ?, ?, ?, ?) `) for (const document of entry.documents) { - insert.run(document.text, document.sessionId, document.seq, document.type, document.time, document.surface) + const text = sanitizeFtsText(document.text) + insert.run( + text, + document.sessionId, + document.seq, + document.type, + document.time, + document.surface, + Array.from(text).length, + ) } } @@ -455,19 +555,16 @@ export class SessionSearchSqlite extends SessionSearchService { ranked AS ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY session_id - ORDER BY score ASC, time DESC, seq DESC + ORDER BY match_count DESC, document_length ASC, time DESC, seq DESC ) AS event_rank FROM filtered ) SELECT * FROM ranked WHERE event_rank = 1 - ORDER BY score ASC, time DESC, session_id ASC, seq DESC + ORDER BY match_count DESC, document_length ASC, time DESC, session_id ASC, seq DESC LIMIT ? OFFSET ? `).all( - quoteFtsData(request.query), - this._persistence === undefined ? 0 : 1, - this._persistence === undefined ? 0 : 1, - quoteFtsData(request.query), + ...selectedDocumentsParams(request.query, this._persistence !== undefined), ...sessionWhere.params, ...eventWhere.params, request.limit + 1, @@ -483,13 +580,10 @@ export class SessionSearchSqlite extends SessionSearchService { ${selected.sql} SELECT * FROM matched WHERE ${where} - ORDER BY score ASC, time DESC, seq DESC + ORDER BY match_count DESC, document_length ASC, time DESC, seq DESC LIMIT ? OFFSET ? `).all( - quoteFtsData(request.query), - this._persistence === undefined ? 0 : 1, - this._persistence === undefined ? 0 : 1, - quoteFtsData(request.query), + ...selectedDocumentsParams(request.query, this._persistence !== undefined), request.sessionId, ...eventWhere.params, request.limit + 1, @@ -515,23 +609,23 @@ export class SessionSearchSqlite extends SessionSearchService { ) } - private _sessionHit(row: SearchRow, query: string): SessionSearchHit { + private _sessionHit(row: SearchRow): SessionSearchHit { return { header: rowHeader(row), live: row.live === 1, persisted: row.persisted === 1, - bestMatch: this._eventHit(row, query), + bestMatch: this._eventHit(row), } } - private _eventHit(row: SearchRow, query: string): SessionEventSearchHit { + private _eventHit(row: SearchRow): SessionEventSearchHit { return { sessionId: row.session_id as SessionId, seq: row.seq, type: row.type as SessionEventSearchHit['type'], time: row.time, surface: row.surface as SessionEventSearchHit['surface'], - snippet: makeSnippet(row.text, query, this.config.snippetChars), + snippet: makeSnippet(row.marked_text, this.config.snippetChars), } } @@ -548,7 +642,7 @@ export class SessionSearchSqlite extends SessionSearchService { function selectedDocumentsSql(): { sql: string } { return { - sql: `WITH matched AS ( + sql: `WITH candidates AS ( SELECT pd.session_id AS session_id, ps.version AS version, @@ -562,8 +656,8 @@ function selectedDocumentsSql(): { sql: string } { pd.type AS type, CAST(pd.time AS INTEGER) AS time, pd.surface AS surface, - pd.text AS text, - bm25(persisted_docs) AS score + highlight(persisted_docs, 0, ?, ?) AS marked_text, + CAST(pd.codepoint_length AS INTEGER) AS document_length FROM persisted_docs AS pd JOIN persisted_sessions AS ps ON ps.id = pd.session_id WHERE persisted_docs MATCH ? @@ -585,15 +679,39 @@ function selectedDocumentsSql(): { sql: string } { ld.type AS type, CAST(ld.time AS INTEGER) AS time, ld.surface AS surface, - ld.text AS text, - bm25(live_docs) AS score + highlight(live_docs, 0, ?, ?) AS marked_text, + CAST(ld.codepoint_length AS INTEGER) AS document_length FROM temp.live_docs AS ld JOIN temp.live_sessions AS ls ON ls.id = ld.session_id WHERE live_docs MATCH ? + ), matched AS ( + SELECT *, + ( + length(CAST(marked_text AS BLOB)) + - length(CAST(replace(marked_text, ?, '') AS BLOB)) + ) / ? AS match_count + FROM candidates )`, } } +function selectedDocumentsParams(query: string, persistenceVisible: boolean): Array { + const expression = quoteFtsData(query) + const visible = persistenceVisible ? 1 : 0 + return [ + FTS_HIGHLIGHT_START, + FTS_HIGHLIGHT_END, + expression, + visible, + visible, + FTS_HIGHLIGHT_START, + FTS_HIGHLIGHT_END, + expression, + FTS_HIGHLIGHT_START, + Buffer.byteLength(FTS_HIGHLIGHT_START, 'utf8'), + ] +} + function observeLive(session: Session): ObservedSession { return observeSession( structuredClone(session.header), @@ -606,7 +724,6 @@ function observeSession(header: SessionHeader, events: readonly SessionEvent[]): const detachedEvents = events.map(event => structuredClone(event)) return { header: detachedHeader, - events: detachedEvents, documents: buildSessionEventSearchDocuments(detachedHeader.id, detachedEvents), fingerprint: createHash('sha256') .update(JSON.stringify({ header: detachedHeader, events: detachedEvents })) @@ -614,6 +731,49 @@ function observeSession(header: SessionHeader, events: readonly SessionEvent[]): } } +function materializePersistenceSnapshots( + snapshots: readonly SessionPersistenceSnapshot[], +): Map { + if (!isRuntimeArray(snapshots)) throw new Error('persistence snapshots must be an array') + const result = new Map() + for (const snapshot of snapshots) { + if (typeof snapshot.revision !== 'string') { + throw new Error('persistence snapshot revision must be a string') + } + const header = structuredClone(snapshot.header) + if (result.has(header.id)) { + throw new Error(`persistence listed duplicate session "${header.id}"`) + } + result.set(header.id, { header, revision: snapshot.revision }) + } + return result +} + +function samePersistenceSnapshots( + before: ReadonlyMap, + after: ReadonlyMap, +): boolean { + if (before.size !== after.size) return false + for (const [id, first] of before) { + const second = after.get(id) + if ( + second === undefined + || first.revision !== second.revision + || !sameHeader(first.header, second.header) + ) return false + } + return true +} + +function sameHeader(a: SessionHeader, b: SessionHeader): boolean { + return a.version === b.version + && a.id === b.id + && a.createdAt === b.createdAt + && a.cwd === b.cwd + && a.parentSession === b.parentSession + && a.seedLength === b.seedLength +} + function rowHeader(row: SearchRow): SessionHeader { return { version: row.version, @@ -629,7 +789,7 @@ function page( rows: readonly Row[], limit: number, convert: (row: Row) => Item, - nextCursor: (offset: number) => string, + nextCursor: (offset: number) => SessionSearchCursorValue, offset: number, ): SessionSearchPage { const hasMore = rows.length > limit @@ -639,12 +799,12 @@ function page( } } -function encodeCursor(payload: CursorPayload): string { - return Buffer.from(JSON.stringify(payload), 'utf8').toString('base64url') +function encodeCursor(payload: CursorPayload): SessionSearchCursorValue { + return SessionSearchCursor(Buffer.from(JSON.stringify(payload), 'utf8').toString('base64url')) } function decodeCursor( - cursor: string, + cursor: SessionSearchCursorValue, instance: string, scope: CursorPayload['scope'], fingerprint: string, @@ -762,4 +922,8 @@ function errorMessage(error: unknown): string { return error instanceof Error ? error.message : 'unknown error' } +function isRuntimeArray(value: unknown): boolean { + return Array.isArray(value) +} + export default SessionSearchSqlite diff --git a/packages/session-query/session-query-sqlite/src/query.ts b/packages/session-query/session-query-sqlite/src/query.ts index fd2b5156e6..9654f6ae70 100644 --- a/packages/session-query/session-query-sqlite/src/query.ts +++ b/packages/session-query/session-query-sqlite/src/query.ts @@ -2,16 +2,24 @@ import { SessionQueryError, - filterSessionEventDocuments, - filterSessionResults, + materializeSessionEventResultFilters, + materializeSessionResultFilters, } from '@deepseek-ai/dsh-session-query' import type { + SessionAvailability, SessionEventMetadataFilter, + SessionEventResultFilter, SessionEventSearchRequest, SessionResultFilter, + SessionSearchCursor, SessionSearchRequest, } from '@deepseek-ai/dsh-session-query' +/** Collision-free marker inserted before an FTS5 match by `highlight()`. */ +export const FTS_HIGHLIGHT_START = '\uFDD0' +/** Collision-free marker inserted after an FTS5 match by `highlight()`. */ +export const FTS_HIGHLIGHT_END = '\uFDD1' + /** Limit defaults needed to normalize a search request. */ export interface QueryLimits { /** Page size used when the request omits one. */ @@ -26,7 +34,7 @@ export interface NormalizedSessionRequest { sessionFilters: readonly SessionResultFilter[] eventFilters: readonly SessionEventMetadataFilter[] limit: number - cursor?: string + cursor?: SessionSearchCursor } /** Normalized within-session request. */ @@ -35,7 +43,7 @@ export interface NormalizedEventRequest { query: string filters: readonly SessionEventMetadataFilter[] limit: number - cursor?: string + cursor?: SessionSearchCursor } /** Parameterized SQL predicate fragment. */ @@ -56,16 +64,15 @@ export function normalizeSessionRequest( request: SessionSearchRequest, limits: QueryLimits, ): NormalizedSessionRequest { - const sessionFilters = request.sessionFilters ?? [] - const eventFilters = request.eventFilters ?? [] - filterSessionResults([], sessionFilters) - filterSessionEventDocuments([], eventFilters) + const sessionFilters = materializeSessionResultFilters(request.sessionFilters ?? []) + const eventFilters = materializeMetadataFilters(request.eventFilters ?? []) + const cursor = materializeCursor(request.cursor) return { query: normalizeQuery(request.query), sessionFilters, eventFilters, limit: normalizeLimit(request.limit, limits), - ...request.cursor === undefined ? {} : { cursor: request.cursor }, + ...cursor === undefined ? {} : { cursor }, } } @@ -79,14 +86,17 @@ export function normalizeEventRequest( request: SessionEventSearchRequest, limits: QueryLimits, ): NormalizedEventRequest { - const filters = request.filters ?? [] - filterSessionEventDocuments([], filters) + if (typeof request.sessionId !== 'string') { + throw new SessionQueryError('session-search session id must be text', 'SESSION_QUERY_INVALID_FILTER') + } + const filters = materializeMetadataFilters(request.filters ?? []) + const cursor = materializeCursor(request.cursor) return { sessionId: request.sessionId, query: normalizeQuery(request.query), filters, limit: normalizeLimit(request.limit, limits), - ...request.cursor === undefined ? {} : { cursor: request.cursor }, + ...cursor === undefined ? {} : { cursor }, } } @@ -115,9 +125,23 @@ export function buildSessionWhere(filters: readonly SessionResultFilter[]): SqlW case 'availability': { const availability = [...new Set(filter.values)] if (availability.length === 0) clauses.push('0') - else if (availability.length === 1) clauses.push(`${availability[0]} = 1`) + else if (availability.length === 1) { + const value = availability[0] as SessionAvailability + switch (value) { + case 'live': + clauses.push('live = 1') + break + case 'persisted': + clauses.push('persisted = 1') + break + default: + unknownAvailability(value) + } + } break } + default: + unknownFilter(filter) } } return { sql: clauses.join(' AND '), params } @@ -145,6 +169,8 @@ export function buildEventWhere(filters: readonly SessionEventMetadataFilter[]): case 'surface': addList(clauses, params, 'surface', filter.values) break + default: + unknownFilter(filter) } } return { sql: clauses.join(' AND '), params } @@ -159,6 +185,18 @@ export function quoteFtsData(query: string): string { return `"${query.replaceAll('"', '""')}"` } +/** + * Remove reserved marker collisions before text enters FTS5 or MATCH. + * @param text - extracted document text or normalized caller query. + * @returns text with reserved noncharacters mapped to replacement characters. + */ +export function sanitizeFtsText(text: string): string { + return text + .replaceAll('\0', '\uFFFD') + .replaceAll(FTS_HIGHLIGHT_START, '\uFFFD') + .replaceAll(FTS_HIGHLIGHT_END, '\uFFFD') +} + /** * Build the stable normalized request identity stored in opaque cursors. * @param request - normalized request whose filter ordering is canonicalized. @@ -185,19 +223,16 @@ export function requestFingerprint(request: NormalizedSessionRequest | Normalize /** * Build a whitespace-normalized excerpt no longer than `maxChars`. - * @param text - complete extracted semantic document. - * @param query - normalized literal query used to position the excerpt. + * @param markedText - complete document with FTS5 `highlight()` markers. * @param maxChars - maximum result length in Unicode code points. * @returns bounded plain-text snippet. */ -export function makeSnippet(text: string, query: string, maxChars: number): string { - const clean = text.replace(/\s+/gu, ' ').trim() +export function makeSnippet(markedText: string, maxChars: number): string { + const { text: clean, matchStart } = normalizeMarkedText(markedText) const characters = Array.from(clean) if (characters.length <= maxChars) return clean if (maxChars === 1) return '…' - const foundUnits = clean.toLowerCase().indexOf(query.toLowerCase()) - const found = foundUnits < 0 ? -1 : Array.from(clean.slice(0, foundUnits)).length - let start = found < 0 ? 0 : Math.max(0, found - Math.floor(maxChars / 3)) + let start = Math.max(0, matchStart - Math.floor(maxChars / 3)) let prefix = start > 0 ? '…' : '' let suffix = '…' let contentLength = maxChars - prefix.length - suffix.length @@ -216,6 +251,28 @@ export function makeSnippet(text: string, query: string, maxChars: number): stri return `${prefix}${characters.slice(start, end).join('')}${suffix}` } +function normalizeMarkedText(markedText: string): { text: string; matchStart: number } { + const characters: string[] = [] + let matchStart: number | undefined + for (const character of markedText) { + if (character === FTS_HIGHLIGHT_START) { + matchStart ??= characters.length + continue + } + if (character === FTS_HIGHLIGHT_END) continue + if (/\s/u.test(character)) { + if (characters.length > 0 && characters.at(-1) !== ' ') characters.push(' ') + } else { + characters.push(character) + } + } + if (characters.at(-1) === ' ') characters.pop() + return { + text: characters.join(''), + matchStart: matchStart ?? 0, + } +} + function normalizeQuery(value: string): string { if (typeof value !== 'string') { throw new SessionQueryError('session-search query must be text', 'SESSION_QUERY_INVALID_QUERY') @@ -227,7 +284,44 @@ function normalizeQuery(value: string): string { 'SESSION_QUERY_INVALID_QUERY', ) } - return query + if (query.includes('\0')) { + throw new SessionQueryError( + 'session-search query must not contain NUL', + 'SESSION_QUERY_INVALID_QUERY', + ) + } + return sanitizeFtsText(query) +} + +function materializeCursor(cursor: SessionSearchCursor | undefined): SessionSearchCursor | undefined { + if (cursor === undefined) return undefined + if (typeof cursor !== 'string') { + throw new SessionQueryError('session-search cursor must be text', 'SESSION_QUERY_INVALID_CURSOR') + } + return cursor +} + +function materializeMetadataFilters( + filters: readonly SessionEventMetadataFilter[], +): SessionEventMetadataFilter[] { + const candidates: readonly SessionEventResultFilter[] = filters + for (const filter of candidates) { + switch (filter.kind) { + case 'seq': + case 'time': + case 'type': + case 'surface': + break + case 'text': + throw new SessionQueryError( + 'session-search metadata filters do not accept text clauses', + 'SESSION_QUERY_INVALID_FILTER', + ) + default: + unknownFilter(filter) + } + } + return materializeSessionEventResultFilters(filters) as SessionEventMetadataFilter[] } function normalizeLimit(value: number | undefined, limits: QueryLimits): number { @@ -310,3 +404,18 @@ function compareNullable(a: string | null, b: string | null): number { if (b === null) return 1 return a.localeCompare(b) } + +function unknownAvailability(value: never): never { + throw new SessionQueryError( + `session availability filter contains unknown value "${String(value)}"`, + 'SESSION_QUERY_INVALID_FILTER', + ) +} + +function unknownFilter(filter: never): never { + const kind = (filter as { kind?: unknown }).kind + throw new SessionQueryError( + `session filter contains unknown kind ${typeof kind === 'string' ? `"${kind}"` : '(missing)'}`, + 'SESSION_QUERY_INVALID_FILTER', + ) +} diff --git a/packages/session-query/session-query-sqlite/src/schema.ts b/packages/session-query/session-query-sqlite/src/schema.ts index 1c9bd98791..8e5c85f676 100644 --- a/packages/session-query/session-query-sqlite/src/schema.ts +++ b/packages/session-query/session-query-sqlite/src/schema.ts @@ -5,7 +5,7 @@ import { mkdir } from 'node:fs/promises' import { dirname, resolve } from 'node:path' /** Current derived-index schema version. Incompatible versions reset in place. */ -export const SESSION_QUERY_SQLITE_SCHEMA_VERSION = 1 +export const SESSION_QUERY_SQLITE_SCHEMA_VERSION = 2 /** SQLite application id protecting unrelated databases from derived resets. */ export const SESSION_QUERY_SQLITE_APPLICATION_ID = 0x44534851 @@ -24,8 +24,6 @@ export async function openSearchDatabase(path: string, journalMode: JournalMode) if (actual !== ':memory:') await mkdir(dirname(actual), { recursive: true, mode: 0o700 }) const db = new DatabaseSync(actual) try { - // journalMode is a validated closed union, not caller-controlled SQL. - db.exec(`PRAGMA journal_mode = ${journalMode.toUpperCase()}`) const { application_id: applicationId } = db.prepare('PRAGMA application_id').get() as { application_id: number } const { user_version: version } = db.prepare('PRAGMA user_version').get() as { user_version: number } const userTables = listUserTables(db) @@ -38,6 +36,9 @@ export async function openSearchDatabase(path: string, journalMode: JournalMode) if (applicationId === SESSION_QUERY_SQLITE_APPLICATION_ID && version !== SESSION_QUERY_SQLITE_SCHEMA_VERSION) { resetDerivedSchema(db) } + // Apply mutating pragmas only after refusing foreign or canonical files. + // journalMode is a validated closed union, not caller-controlled SQL. + db.exec(`PRAGMA journal_mode = ${journalMode.toUpperCase()}`) ensurePersistentSchema(db) ensureTemporarySchema(db) return db @@ -78,7 +79,7 @@ function ensurePersistentSchema(db: DatabaseSync): void { cwd TEXT, parent_session TEXT, seed_length INTEGER, - fingerprint TEXT NOT NULL, + revision TEXT NOT NULL, generation INTEGER NOT NULL ) STRICT `) @@ -90,6 +91,7 @@ function ensurePersistentSchema(db: DatabaseSync): void { type UNINDEXED, time UNINDEXED, surface UNINDEXED, + codepoint_length UNINDEXED, tokenize = 'unicode61' ) `) @@ -117,6 +119,7 @@ function ensureTemporarySchema(db: DatabaseSync): void { type UNINDEXED, time UNINDEXED, surface UNINDEXED, + codepoint_length UNINDEXED, tokenize = 'unicode61' ) `) diff --git a/packages/session-query/session-query-sqlite/tests/query.spec.ts b/packages/session-query/session-query-sqlite/tests/query.spec.ts index 0faced72e4..f9c0a5d19e 100644 --- a/packages/session-query/session-query-sqlite/tests/query.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/query.spec.ts @@ -1,9 +1,11 @@ import { describe, expect, it } from 'vitest' import { SessionId } from '@deepseek-ai/dsh-session' -import type { SessionQueryErrorCode } from '@deepseek-ai/dsh-session-query' +import { SessionSearchCursor, type SessionQueryErrorCode } from '@deepseek-ai/dsh-session-query' import { buildEventWhere, buildSessionWhere, + FTS_HIGHLIGHT_END, + FTS_HIGHLIGHT_START, makeSnippet, normalizeEventRequest, normalizeSessionRequest, @@ -32,13 +34,13 @@ describe('SQLite search request normalization', () => { sessionFilters: [{ kind: 'availability', values: ['live'] }], eventFilters: [{ kind: 'surface', values: ['current'] }], limit: 3, - cursor: 'next', + cursor: SessionSearchCursor('next'), }, limits)).toEqual({ query: 'needle', sessionFilters: [{ kind: 'availability', values: ['live'] }], eventFilters: [{ kind: 'surface', values: ['current'] }], limit: 3, - cursor: 'next', + cursor: SessionSearchCursor('next'), }) expect(normalizeEventRequest({ sessionId: SessionId('s'), query: 'needle' }, limits)).toEqual({ sessionId: SessionId('s'), @@ -50,13 +52,13 @@ describe('SQLite search request normalization', () => { sessionId: SessionId('s'), query: 'needle', filters: [{ kind: 'seq', from: 1 }], - cursor: 'next', + cursor: SessionSearchCursor('next'), }, limits)).toEqual({ sessionId: SessionId('s'), query: 'needle', filters: [{ kind: 'seq', from: 1 }], limit: 2, - cursor: 'next', + cursor: SessionSearchCursor('next'), }) }) @@ -65,11 +67,39 @@ describe('SQLite search request normalization', () => { .toThrow(expectCode('SESSION_QUERY_INVALID_QUERY')) expect(() => normalizeSessionRequest({ query: ' \n ' }, limits)) .toThrow(expectCode('SESSION_QUERY_INVALID_QUERY')) + expect(() => normalizeSessionRequest({ query: 'bad\0query' }, limits)) + .toThrow(expectCode('SESSION_QUERY_INVALID_QUERY')) + expect(() => normalizeEventRequest({ sessionId: 1 as never, query: 'x' }, limits)) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => normalizeEventRequest({ + sessionId: SessionId('s'), + query: 'x', + cursor: 1 as never, + }, limits)).toThrow(expectCode('SESSION_QUERY_INVALID_CURSOR')) + expect(() => normalizeSessionRequest({ + query: 'x', + eventFilters: [{ kind: 'text', text: 'x' } as never], + }, limits)).toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => normalizeSessionRequest({ + query: 'x', + eventFilters: [{} as never], + }, limits)).toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) for (const limit of [1.5, 0, 4]) { expect(() => normalizeEventRequest({ sessionId: SessionId('s'), query: 'x', limit }, limits)) .toThrow(expectCode('SESSION_QUERY_INVALID_LIMIT')) } }) + + it('materializes owned filter values during normalization', () => { + const values = ['live'] as Array<'live' | 'persisted'> + const filter = { kind: 'availability' as const, values } + const request = { query: 'needle', sessionFilters: [filter] } + const normalized = normalizeSessionRequest(request, limits) + + values[0] = 'persisted' + request.sessionFilters.push({ kind: 'availability', values: ['persisted'] }) + expect(normalized.sessionFilters).toEqual([{ kind: 'availability', values: ['live'] }]) + }) }) describe('SQLite search predicate compilation', () => { @@ -120,6 +150,17 @@ describe('SQLite search predicate compilation', () => { { kind: 'surface', values: [] }, ])).toEqual({ sql: '0 AND 0', params: [] }) }) + + it('rejects runtime-unknown filter discriminants in both SQL builders', () => { + expect(() => buildSessionWhere([{ kind: 'future' } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => buildEventWhere([{ kind: 'future' } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => buildSessionWhere([{ kind: 'availability', values: ['future'] } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => buildSessionWhere([{} as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + }) }) describe('SQLite query identity and presentation', () => { @@ -169,11 +210,13 @@ describe('SQLite query identity and presentation', () => { }) it('normalizes, bounds, and positions snippets by Unicode code point', () => { - expect(makeSnippet(' short\ntext ', 'absent', 20)).toBe('short text') - expect(makeSnippet('abcdef', 'f', 1)).toBe('…') - expect(makeSnippet('abcdefghij', 'absent', 5)).toBe('abcd…') - expect(makeSnippet('abcdefghij', 'c', 5)).toBe('…bcd…') - expect(makeSnippet('abcdef', 'f', 2)).toBe('a…') - expect(makeSnippet('abcdef', 'f', 5)).toBe('…cdef') + expect(makeSnippet(' short\ntext ', 20)).toBe('short text') + expect(makeSnippet(`abcde${FTS_HIGHLIGHT_START}f${FTS_HIGHLIGHT_END}`, 1)).toBe('…') + expect(makeSnippet('abcdefghij', 5)).toBe('abcd…') + expect(makeSnippet(`ab${FTS_HIGHLIGHT_START}c${FTS_HIGHLIGHT_END}defghij`, 5)).toBe('…bcd…') + expect(makeSnippet(`abcde${FTS_HIGHLIGHT_START}f${FTS_HIGHLIGHT_END}`, 2)).toBe('a…') + expect(makeSnippet(`abcde${FTS_HIGHLIGHT_START}f${FTS_HIGHLIGHT_END}`, 5)).toBe('…cdef') + expect(makeSnippet(` x—${FTS_HIGHLIGHT_START}café${FTS_HIGHLIGHT_END}\n y `, 20)) + .toBe('x—café y') }) }) diff --git a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts index 77d1e0125d..f4904e17d8 100644 --- a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts @@ -1,18 +1,25 @@ -import { afterEach, describe, expect, it } from 'vitest' -import { Context } from 'cordis' +import { afterEach, describe, expect, it, vi } from 'vitest' +import { Context, type Fiber } from 'cordis' import { DatabaseSync } from 'node:sqlite' import { mkdtemp, rm } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' import SessionStore, { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session' import type { SessionEvent, SessionHeader, SessionId as SessionIdType } from '@deepseek-ai/dsh-session' -import SessionPersistence from '@deepseek-ai/dsh-session-persistence' +import SessionPersistence, { SessionPersistenceRevision } from '@deepseek-ai/dsh-session-persistence' +import type { SessionPersistenceSnapshot } from '@deepseek-ai/dsh-session-persistence' import SessionPersistenceSqlite from '@deepseek-ai/dsh-session-persistence-sqlite' import SessionSearchSqlite, { SESSION_QUERY_SQLITE_APPLICATION_ID, SESSION_QUERY_SQLITE_SCHEMA_VERSION, } from '@deepseek-ai/dsh-session-query-sqlite' -import type { SessionQueryErrorCode } from '@deepseek-ai/dsh-session-query' +import { + SessionQueryError, + SessionSearchCursor, + type SessionAvailability, + type SessionQueryErrorCode, + type SessionSearchRequest, +} from '@deepseek-ai/dsh-session-query' const temporaryDirectories: string[] = [] @@ -48,19 +55,36 @@ function expectCode(code: SessionQueryErrorCode): Error { class TestPersistence extends SessionPersistence { static entries = new Map() + static revisions = new Map() + static nextRevision = 0 + static loads = new Map() + static loadEffect: ((entry: { meta: SessionHeader; events: SessionEvent[] }) => void) | undefined static listGate: Promise | undefined static listStarted: (() => void) | undefined + static snapshotEffect: (() => void | Promise) | undefined + static snapshotOverride: (() => SessionPersistenceSnapshot[]) | undefined static failure: unknown static reset(entries: readonly { meta: SessionHeader; events: SessionEvent[] }[] = []): void { - this.entries = new Map(entries.map(entry => [entry.meta.id, structuredClone(entry)])) + this.entries = new Map() + this.revisions = new Map() + this.loads = new Map() + this.loadEffect = undefined + for (const entry of entries) this.set(entry) this.listGate = undefined this.listStarted = undefined + this.snapshotEffect = undefined + this.snapshotOverride = undefined this.failure = undefined } + static set(entry: { meta: SessionHeader; events: SessionEvent[] }): void { + this.entries.set(entry.meta.id, structuredClone(entry)) + this.revisions.set(entry.meta.id, ++this.nextRevision) + } + create(meta: SessionHeader): Promise { - TestPersistence.entries.set(meta.id, { meta: structuredClone(meta), events: [] }) + TestPersistence.set({ meta, events: [] }) return Promise.resolve() } @@ -68,13 +92,21 @@ class TestPersistence extends SessionPersistence { const entry = TestPersistence.entries.get(id) if (entry === undefined) return Promise.reject(new Error('missing test session')) entry.events.push(...structuredClone(events)) + TestPersistence.revisions.set(id, ++TestPersistence.nextRevision) return Promise.resolve() } async load(id: SessionIdType): Promise<{ meta: SessionHeader; events: SessionEvent[] }> { + TestPersistence.loads.set(id, (TestPersistence.loads.get(id) ?? 0) + 1) if (TestPersistence.failure !== undefined) throw TestPersistence.failure const entry = TestPersistence.entries.get(id) if (entry === undefined) throw new Error('missing test session') + if (TestPersistence.loadEffect !== undefined) { + const effect = TestPersistence.loadEffect + TestPersistence.loadEffect = undefined + effect(entry) + TestPersistence.revisions.set(id, ++TestPersistence.nextRevision) + } return structuredClone(entry) } @@ -84,6 +116,20 @@ class TestPersistence extends SessionPersistence { if (TestPersistence.failure !== undefined) throw TestPersistence.failure return [...TestPersistence.entries.values()].map(entry => structuredClone(entry.meta)) } + + + async listSnapshots(): Promise { + TestPersistence.listStarted?.() + await TestPersistence.listGate + if (TestPersistence.failure !== undefined) throw TestPersistence.failure + const snapshots = TestPersistence.snapshotOverride?.() + ?? [...TestPersistence.entries.values()].map(entry => ({ + header: structuredClone(entry.meta), + revision: SessionPersistenceRevision(`test:${TestPersistence.revisions.get(entry.meta.id)}`), + })) + await TestPersistence.snapshotEffect?.() + return snapshots + } } async function liveContext(config: ConstructorParameters[1] = { path: ':memory:' }): Promise { @@ -175,6 +221,44 @@ describe('SQLite session search', () => { await expect(ctx.sessionSearch.searchSessions({ query: '*' })).resolves.toEqual({ items: [] }) }) + it('ranks live and persisted matches on one source-comparable contract', async () => { + const persisted = header('z-persisted') + TestPersistence.reset([ + { meta: persisted, events: messageEvents('needle needle', 10) }, + ...Array.from({ length: 12 }, (_, index) => ({ + meta: header(`filler-${index}`), + events: messageEvents('needle', 10), + })), + ]) + const ctx = await liveContext() + const persistence = await ctx.plugin(TestPersistence) + ctx.sessions.create(SessionId('a-live'), { + seed: messageEvents('needle needle', 10), + meta: { createdAt: persisted.createdAt }, + }) + + const result = await ctx.sessionSearch.searchSessions({ + query: 'needle', + sessionFilters: [{ kind: 'id', values: [SessionId('a-live'), persisted.id] }], + }) + expect(result.items.map(item => item.header.id)).toEqual([SessionId('a-live'), persisted.id]) + await persistence.dispose() + }) + + it('positions snippets from FTS5 matches across diacritics and punctuation', async () => { + const ctx = await liveContext({ path: ':memory:', snippetChars: 14 }) + const session = ctx.sessions.create(SessionId('snippet'), { + seed: messageEvents('long long long—café,\nnext value', 10), + }) + + const page = await ctx.sessionSearch.searchEvents({ sessionId: session.id, query: 'CAFE' }) + expect(page.items).toHaveLength(1) + expect(page.items[0]!.snippet).toContain('café') + expect(page.items[0]!.snippet).toContain('—') + expect(page.items[0]!.snippet).not.toContain('\n') + expect(Array.from(page.items[0]!.snippet).length).toBeLessThanOrEqual(14) + }) + it('binds cursors to requests and only invalidates within-session pages for target changes', async () => { const ctx = await liveContext({ path: ':memory:', defaultLimit: 1, maxLimit: 5 }) const target = ctx.sessions.create(SessionId('target'), { @@ -193,7 +277,7 @@ describe('SQLite session search', () => { if (eventPage.nextCursor === undefined || sessionPage.nextCursor === undefined) throw new Error('expected cursors') const eventKeys = eventPage.items.map(item => `${item.sessionId}:${item.seq}`) - let eventCursor: string | undefined = eventPage.nextCursor + let eventCursor: ReturnType | undefined = eventPage.nextCursor while (eventCursor !== undefined) { const next = await ctx.sessionSearch.searchEvents({ sessionId: target.id, @@ -208,7 +292,7 @@ describe('SQLite session search', () => { expect(new Set(eventKeys).size).toBe(eventKeys.length) const sessionIds = sessionPage.items.map(item => item.header.id) - let sessionCursor: string | undefined = sessionPage.nextCursor + let sessionCursor: ReturnType | undefined = sessionPage.nextCursor while (sessionCursor !== undefined) { const next = await ctx.sessionSearch.searchSessions({ query: 'needle', limit: 1, cursor: sessionCursor }) sessionIds.push(...next.items.map(item => item.header.id)) @@ -251,6 +335,7 @@ describe('SQLite session search', () => { { sessionId: session.id, query: 'needle', limit: 4 }, { sessionId: session.id, query: 'needle', filters: [{ kind: 'seq', from: 2, to: 1 }] }, { sessionId: session.id, query: 'needle', filters: [{ kind: 'surface', values: ['future'] }] }, + { sessionId: session.id, query: 'bad\0query' }, ] as const) { await expect(ctx.sessionSearch.searchEvents(request as never)).rejects.toBeInstanceOf(Error) } @@ -258,7 +343,24 @@ describe('SQLite session search', () => { query: 'needle', sessionFilters: [{ kind: 'availability', values: ['remote' as never] }], })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) - await expect(ctx.sessionSearch.searchEvents({ sessionId: session.id, query: 'needle', cursor: 'not-json' })) + await expect(ctx.sessionSearch.searchSessions({ + query: 'needle', + sessionFilters: [{ kind: 'future' } as never], + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + await expect(ctx.sessionSearch.searchSessions({ + query: 'needle', + eventFilters: [{ kind: 'future' } as never], + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: session.id, + query: 'needle', + filters: [{ kind: 'future' } as never], + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: session.id, + query: 'needle', + cursor: SessionSearchCursor('not-json'), + })) .rejects.toThrow(expectCode('SESSION_QUERY_INVALID_CURSOR')) await expect(ctx.sessionSearch.searchEvents({ sessionId: SessionId('absent'), query: 'needle' })) .rejects.toThrow(expectCode('SESSION_QUERY_SESSION_NOT_FOUND')) @@ -280,6 +382,37 @@ describe('SQLite session search', () => { }) describe('SQLite reconciliation and source lifecycle', () => { + it('owns queued request and filter values before waiting for the serializer', async () => { + const durable = header('owned') + TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) + const ctx = await liveContext() + const persistence = await ctx.plugin(TestPersistence) + let release!: () => void + TestPersistence.listGate = new Promise((resolve) => { release = resolve }) + let markStarted!: () => void + const started = new Promise((resolve) => { markStarted = resolve }) + TestPersistence.listStarted = () => { + TestPersistence.listStarted = undefined + markStarted() + } + const blocking = ctx.sessionSearch.searchSessions({ query: 'needle' }) + await started + + const availability: SessionAvailability[] = ['persisted'] + const request: SessionSearchRequest = { + query: 'needle', + sessionFilters: [{ kind: 'availability', values: availability }], + } + const queued = ctx.sessionSearch.searchSessions(request) + request.query = 'absent' + availability[0] = 'live' + release() + + await expect(blocking).resolves.toMatchObject({ items: [{ header: durable }] }) + await expect(queued).resolves.toMatchObject({ items: [{ header: durable }] }) + await persistence.dispose() + }) + it('mounts persistence dynamically, shadows with TEMP live rows, reveals, and hides on unmount', async () => { const shared = header('shared', 10, { cwd: '/work' }) const durable = header('durable', 5) @@ -311,7 +444,7 @@ describe('SQLite reconciliation and source lifecycle', () => { .rejects.toThrow(expectCode('SESSION_QUERY_SESSION_NOT_FOUND')) }) - it('restarts observation when persistence unmounts during an asynchronous list', async () => { + it('discards a stale list rejection when persistence unmounts during observation', async () => { const durable = header('racing') TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) const ctx = await liveContext() @@ -328,10 +461,140 @@ describe('SQLite reconciliation and source lifecycle', () => { const search = ctx.sessionSearch.searchSessions({ query: 'needle' }) await started await persistenceFiber.dispose() + TestPersistence.failure = new Error('stale backend rejection') release() await expect(search).resolves.toEqual({ items: [] }) }) + it('retries against a replacement after the prior binding rejects', async () => { + const durable = header('replacement') + TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) + const ctx = await liveContext() + const prior = await ctx.plugin(TestPersistence) + let rejectPrior!: (reason: unknown) => void + TestPersistence.listGate = new Promise((_resolve, reject) => { rejectPrior = reject }) + let markStarted!: () => void + const started = new Promise((resolve) => { markStarted = resolve }) + TestPersistence.listStarted = () => { + TestPersistence.listStarted = undefined + markStarted() + } + + const search = ctx.sessionSearch.searchSessions({ query: 'needle' }) + await started + await prior.dispose() + TestPersistence.listGate = undefined + const replacement = await ctx.plugin(TestPersistence) + rejectPrior(new Error('stale prior binding')) + await expect(search).resolves.toMatchObject({ items: [{ header: durable }] }) + await replacement.dispose() + }) + + it('reloads a replacement source even when its opaque revisions collide', async () => { + const durable = header('colliding-replacement') + TestPersistence.reset([{ meta: durable, events: messageEvents('old content') }]) + const revision = TestPersistence.revisions.get(durable.id)! + const ctx = await liveContext() + const prior = await ctx.plugin(TestPersistence) + await expect(ctx.sessionSearch.searchSessions({ query: 'old' })) + .resolves.toMatchObject({ items: [{ header: durable }] }) + await prior.dispose() + + TestPersistence.set({ meta: durable, events: messageEvents('new needle') }) + TestPersistence.revisions.set(durable.id, revision) + const replacement = await ctx.plugin(TestPersistence) + const internals = ctx.sessionSearch as unknown as { + _lastPersistenceRevision: number + _persistenceRevision: number + } + expect(internals._persistenceRevision).not.toBe(internals._lastPersistenceRevision) + const page = await ctx.sessionSearch.searchSessions({ query: 'new needle' }) + expect(TestPersistence.loads.get(durable.id)).toBe(2) + expect(page).toMatchObject({ items: [{ header: durable }] }) + await expect(ctx.sessionSearch.searchSessions({ query: 'old' })).resolves.toEqual({ items: [] }) + expect(TestPersistence.loads.get(durable.id)).toBe(2) + await replacement.dispose() + }) + + it('retries when a successful observation belongs to a source unmounted during listing', async () => { + const durable = header('successful-unmount') + TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) + const ctx = await liveContext() + const persistence = await ctx.plugin(TestPersistence) + let lists = 0 + TestPersistence.snapshotEffect = async () => { + lists += 1 + if (lists === 2) await persistence.dispose() + } + + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })).resolves.toEqual({ items: [] }) + expect(lists).toBe(2) + }) + + it('retries when the snapshot population changes during observation', async () => { + const first = header('first') + const added = header('added-during-list') + TestPersistence.reset([{ meta: first, events: messageEvents('first needle') }]) + const ctx = await liveContext() + await ctx.plugin(TestPersistence) + TestPersistence.snapshotEffect = () => { + TestPersistence.snapshotEffect = undefined + TestPersistence.set({ meta: added, events: messageEvents('added needle') }) + } + + const page = await ctx.sessionSearch.searchSessions({ query: 'needle' }) + expect(page.items.map(item => item.header.id).sort()).toEqual([added.id, first.id].sort()) + expect(TestPersistence.loads.get(first.id)).toBe(2) + expect(TestPersistence.loads.get(added.id)).toBe(1) + }) + + it('retries if the source revision changes while live sessions are observed', async () => { + const durable = header('live-boundary-retry') + TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) + const ctx = await liveContext() + await ctx.plugin(TestPersistence) + const internals = ctx.sessionSearch as unknown as { _persistenceRevision: number } + const originalList = ctx.sessions.list.bind(ctx.sessions) + let bumped = false + const list = vi.spyOn(ctx.sessions, 'list').mockImplementation(() => { + if (!bumped) { + bumped = true + internals._persistenceRevision += 1 + } + return originalList() + }) + + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })) + .resolves.toMatchObject({ items: [{ header: durable }] }) + expect(TestPersistence.loads.get(durable.id)).toBe(2) + list.mockRestore() + }) + + it('rejects malformed snapshots and preserves typed persistence failures', async () => { + const durable = header('invalid-snapshot') + TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) + const ctx = await liveContext() + await ctx.plugin(TestPersistence) + + TestPersistence.snapshotOverride = () => 'not-an-array' as never + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_PERSISTENCE_FAILED')) + TestPersistence.snapshotOverride = () => [{ header: durable, revision: 1 as never }] + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_PERSISTENCE_FAILED')) + TestPersistence.snapshotOverride = () => [ + { header: durable, revision: SessionPersistenceRevision('duplicate:1') }, + { header: durable, revision: SessionPersistenceRevision('duplicate:2') }, + ] + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_PERSISTENCE_FAILED')) + + TestPersistence.snapshotOverride = undefined + const typed = new SessionQueryError('typed persistence failure', 'SESSION_QUERY_PERSISTENCE_FAILED') + TestPersistence.failure = typed + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })).rejects.toBe(typed) + }) + it('rejects immutable header conflicts between live and persisted sources', async () => { const shared = header('conflict', 10) TestPersistence.reset([{ meta: shared, events: messageEvents('persisted needle') }]) @@ -358,6 +621,9 @@ describe('SQLite reconciliation and source lifecycle', () => { const firstPersistence = await first.plugin(TestPersistence) const firstSearch = await first.plugin(SessionSearchSqlite, { path }) await first.sessionSearch.searchSessions({ query: 'needle' }) + expect(Object.fromEntries(TestPersistence.loads)).toEqual({ unchanged: 1, changed: 1, deleted: 1 }) + await first.sessionSearch.searchSessions({ query: 'needle' }) + expect(Object.fromEntries(TestPersistence.loads)).toEqual({ unchanged: 1, changed: 1, deleted: 1 }) await firstSearch.dispose() await firstPersistence.dispose() @@ -368,14 +634,20 @@ describe('SQLite reconciliation and source lifecycle', () => { const added = header('added') TestPersistence.entries.delete(deleted.id) - TestPersistence.entries.set(changed.id, { meta: changed, events: messageEvents('changed needle') }) - TestPersistence.entries.set(added.id, { meta: added, events: messageEvents('added needle') }) + TestPersistence.set({ meta: changed, events: messageEvents('changed needle') }) + TestPersistence.set({ meta: added, events: messageEvents('added needle') }) const second = new Context() await second.plugin(SessionStore) const secondPersistence = await second.plugin(TestPersistence) const secondSearch = await second.plugin(SessionSearchSqlite, { path }) const result = await second.sessionSearch.searchSessions({ query: 'needle' }) expect(result.items.map(item => item.header.id).sort()).toEqual([added.id, changed.id, unchanged.id].sort()) + expect(Object.fromEntries(TestPersistence.loads)).toEqual({ + unchanged: 1, + changed: 2, + deleted: 1, + added: 1, + }) await secondSearch.dispose() await secondPersistence.dispose() @@ -409,10 +681,27 @@ describe('SQLite reconciliation and source lifecycle', () => { await expect(second.sessionSearch.searchSessions({ query: 'live' })).resolves.toEqual({ items: [] }) await expect(second.sessionSearch.searchSessions({ query: 'persisted' })) .resolves.toMatchObject({ items: [{ header: shared, live: false, persisted: true }] }) + expect(TestPersistence.loads.get(shared.id)).toBe(1) await searchAgain.dispose() await persistenceAgain.dispose() }) + it('refreshes the stored revision after a mutating load repair', async () => { + const durable = header('repair') + TestPersistence.reset([{ meta: durable, events: messageEvents('before repair') }]) + TestPersistence.loadEffect = (entry) => { + entry.events = messageEvents('repaired needle') + } + const ctx = await liveContext() + await ctx.plugin(TestPersistence) + + await expect(ctx.sessionSearch.searchSessions({ query: 'repaired' })) + .resolves.toMatchObject({ items: [{ header: durable }] }) + expect(TestPersistence.loads.get(durable.id)).toBe(2) + await ctx.sessionSearch.searchSessions({ query: 'repaired' }) + expect(TestPersistence.loads.get(durable.id)).toBe(2) + }) + it('recovers on the next search after source and SQLite transaction failures', async () => { TestPersistence.reset([{ meta: header('durable'), events: messageEvents('durable needle') }]) const ctx = await liveContext() @@ -462,15 +751,18 @@ describe('SQLite schema, cancellation, and real persistence integration', () => const foreignPath = await temporaryPath('foreign.db') const foreign = new DatabaseSync(foreignPath) + foreign.exec('PRAGMA journal_mode = WAL') foreign.exec('CREATE TABLE canonical(value TEXT)') foreign.exec("INSERT INTO canonical VALUES ('safe')") foreign.close() - const foreignCtx = await liveContext({ path: foreignPath }) + const foreignCtx = await liveContext({ path: foreignPath, journalMode: 'delete' }) await expect(foreignCtx.sessionSearch.searchSessions({ query: 'needle' })) .rejects.toThrow(expectCode('SESSION_QUERY_INDEX_FAILED')) const stillForeign = new DatabaseSync(foreignPath) expect(stillForeign.prepare('SELECT value FROM canonical').get()).toEqual({ value: 'safe' }) + expect(stillForeign.prepare('PRAGMA journal_mode').get()).toEqual({ journal_mode: 'wal' }) stillForeign.close() + await (foreignCtx.sessionSearch as SessionSearchSqlite).close() const otherAppPath = await temporaryPath('other-app.db') const otherApp = new DatabaseSync(otherAppPath) @@ -479,6 +771,25 @@ describe('SQLite schema, cancellation, and real persistence integration', () => const otherAppCtx = await liveContext({ path: otherAppPath }) await expect(otherAppCtx.sessionSearch.searchSessions({ query: 'needle' })) .rejects.toThrow(expectCode('SESSION_QUERY_INDEX_FAILED')) + await (otherAppCtx.sessionSearch as SessionSearchSqlite).close() + }) + + it('observes asynchronous open rejection even when no query is made', async () => { + const path = await temporaryPath('never-queried.db') + const foreign = new DatabaseSync(path) + foreign.exec('CREATE TABLE canonical(value TEXT)') + foreign.close() + const unhandled: unknown[] = [] + const onUnhandled = (reason: unknown) => { unhandled.push(reason) } + process.on('unhandledRejection', onUnhandled) + try { + const ctx = await liveContext({ path }) + await new Promise((resolve) => { setImmediate(resolve) }) + expect(unhandled).toEqual([]) + await (ctx.sessionSearch as SessionSearchSqlite).close() + } finally { + process.off('unhandledRejection', onUnhandled) + } }) it('cancels both queued and in-flight source waits without committing them', async () => { @@ -518,7 +829,7 @@ describe('SQLite schema, cancellation, and real persistence integration', () => releaseBlocking() await expect(blocking).resolves.toEqual({ items: [] }) - TestPersistence.entries.set(SessionId('uncommitted'), { + TestPersistence.set({ meta: header('uncommitted'), events: messageEvents('durable needle'), }) @@ -560,14 +871,38 @@ describe('SQLite schema, cancellation, and real persistence integration', () => await started const queued = search.searchSessions({ query: 'needle' }) const closing = search.close() + const repeatedClose = search.close() + expect(repeatedClose).toBe(closing) release() await expect(accepted).resolves.toEqual({ items: [] }) await expect(queued).rejects.toThrow(expectCode('SESSION_QUERY_INDEX_FAILED')) - await closing + await Promise.all([closing, repeatedClose]) await expect(search.searchSessions({ query: 'needle' })) .rejects.toThrow(expectCode('SESSION_QUERY_INDEX_FAILED')) - await search.close() + expect(search.close()).toBe(closing) + }) + + it('awaits optional-persistence child-fiber quiescence on disposal', async () => { + TestPersistence.reset() + const ctx = new Context() + await ctx.plugin(SessionStore) + const search = await ctx.plugin(SessionSearchSqlite, { path: ':memory:' }) + const persistence = await ctx.plugin(TestPersistence) + const optional = (ctx.sessionSearch as unknown as { + _optionalPersistenceFiber: Fiber + })._optionalPersistenceFiber + let release!: () => void + const cleanup = new Promise((resolve) => { release = resolve }) + optional.ctx.effect(() => () => cleanup) + + let settled = false + const disposing = search.dispose().then(() => { settled = true }) + await Promise.resolve() + expect(settled).toBe(false) + release() + await disposing + await persistence.dispose() }) it('combines the real SQLite persistence backend with the real search service keylessly', async () => { diff --git a/packages/session-query/session-query/README.md b/packages/session-query/session-query/README.md index 6f9e9bbd7a..917984f0cd 100644 --- a/packages/session-query/session-query/README.md +++ b/packages/session-query/session-query/README.md @@ -7,6 +7,7 @@ This is trusted context-wide infrastructure. It performs no caller authorization ## Reads - `listSessions()` reads current persistence metadata, merges live records with live precedence, and returns cloned records in deterministic newest-first order. +- `filterSessions(filters)` applies provider-independent session metadata and availability predicates to that same cloned logical corpus. - `listEvents(sessionId)` loads the live-preferred raw log and classifies each event as `current`, `shadowed`, or `log-only` with the shared `dsh-session` surface fold. - `filterEvents(sessionId, filters)` extracts first-party semantic documents and applies provider-independent metadata and literal-text predicates in ascending seq order. - `readEvent(request)` returns a cloned header, the full target event, and a bounded raw-seq window. `before` and `after` default to zero and may not exceed `readWindowMax`. @@ -21,7 +22,7 @@ The text clause is deliberately independent of FTS providers: caller text is esc ## Full-text seam -`SessionSearchService` owns the independent `ctx.sessionSearch` key. `searchSessions(request, exec?)` groups the logical corpus by strongest matching event; `searchEvents(request, exec?)` searches one logical session. Both return opaque cursor pages, accept optional cancellation, and expose snippets without provider-specific numeric scores. Search requests accept only metadata event filters, because literal-text filtering is the scan path described above. +`SessionSearchService` owns the independent `ctx.sessionSearch` key. `searchSessions(request, exec?)` groups the logical corpus by strongest matching event; `searchEvents(request, exec?)` searches one logical session. Both return pages whose continuation is an owned branded `SessionSearchCursor`, accept optional cancellation, and expose snippets without provider-specific numeric scores. Search requests accept only metadata event filters, because literal-text filtering is the scan path described above. The package has no provider coordinator or registration protocol. A concrete backend owns observation, reconciliation, ranking, cursor generations, and query execution as one lifecycle; the first implementation is [`@deepseek-ai/dsh-session-query-sqlite`](../session-query-sqlite/README.md). diff --git a/packages/session-query/session-query/package.json b/packages/session-query/session-query/package.json index 9f78d4f1db..449610a5a4 100644 --- a/packages/session-query/session-query/package.json +++ b/packages/session-query/session-query/package.json @@ -22,6 +22,7 @@ ], "license": "BSD-3-Clause", "peerDependencies": { + "@deepseek-ai/dsh-brand": "^0.0.1", "@deepseek-ai/dsh-llm": "^0.0.1", "@deepseek-ai/dsh-session": "^0.0.1", "@deepseek-ai/dsh-session-persistence": "^0.0.1", @@ -36,6 +37,7 @@ "schemastery": "^3.18.0" }, "devDependencies": { + "@deepseek-ai/dsh-brand": "workspace:^", "@deepseek-ai/dsh-llm": "workspace:^", "@deepseek-ai/dsh-session": "workspace:^", "@deepseek-ai/dsh-session-persistence": "workspace:^", diff --git a/packages/session-query/session-query/src/corpus.ts b/packages/session-query/session-query/src/corpus.ts index c8ddca3caa..4a27c34e58 100644 --- a/packages/session-query/session-query/src/corpus.ts +++ b/packages/session-query/session-query/src/corpus.ts @@ -1,6 +1,6 @@ /** Live/persisted logical-corpus resolution for session-query. */ -import type { Context } from 'cordis' +import type { Context, Fiber } from 'cordis' import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session' import type SessionPersistence from '@deepseek-ai/dsh-session-persistence' import type { SessionRecord } from './types.ts' @@ -18,18 +18,19 @@ export interface LogicalSession { /** Resolves a live-preferred corpus against the persistence service mounted now. */ export class SessionCorpus { private _persistence: SessionPersistence | undefined + private readonly _optionalPersistenceFiber: Fiber constructor(private readonly _ctx: Context) { + this._optionalPersistenceFiber = _ctx.inject(['sessionPersistence'], (childCtx: Context) => { + const service = childCtx.sessionPersistence + this._persistence = service + childCtx.effect(() => () => { + /* v8 ignore next -- a stale optional-service disposer cannot clear a replacement */ + if (this._persistence === service) this._persistence = undefined + }, 'sessionQuery.persistenceBinding') + }) _ctx.effect(() => { - const fiber = _ctx.inject(['sessionPersistence'], (childCtx: Context) => { - const service = childCtx.sessionPersistence - this._persistence = service - childCtx.effect(() => () => { - /* v8 ignore next -- a stale optional-service disposer cannot clear a replacement */ - if (this._persistence === service) this._persistence = undefined - }, 'sessionQuery.persistenceBinding') - }) - return () => void fiber.dispose() + return () => this._optionalPersistenceFiber.dispose() }, 'sessionQuery.optionalPersistence') } diff --git a/packages/session-query/session-query/src/cursor.ts b/packages/session-query/session-query/src/cursor.ts new file mode 100644 index 0000000000..8ee2a6660d --- /dev/null +++ b/packages/session-query/session-query/src/cursor.ts @@ -0,0 +1,15 @@ +/** Opaque cursor identity for session-search pagination. */ + +import type { Branded } from '@deepseek-ai/dsh-brand' + +/** Provider-owned opaque continuation token returned by session search. */ +export type SessionSearchCursor = Branded<'SessionSearchCursor'> + +/** + * Brand an encoded provider cursor for the public search contract. + * @param value - opaque encoded cursor value. + * @returns the same runtime string with session-search cursor identity. + */ +export function SessionSearchCursor(value: string): SessionSearchCursor { + return value as SessionSearchCursor +} diff --git a/packages/session-query/session-query/src/filters.ts b/packages/session-query/session-query/src/filters.ts index c7a7b40dd4..91ae640615 100644 --- a/packages/session-query/session-query/src/filters.ts +++ b/packages/session-query/session-query/src/filters.ts @@ -1,6 +1,12 @@ /** Pure provider-independent predicates for logical sessions and event text. */ -import type { SessionRecord, SessionEventSearchDocument, SessionEventResultFilter, SessionResultFilter, SessionResultRange } from './types.ts' +import type { + SessionEventResultFilter, + SessionEventSearchDocument, + SessionRecord, + SessionResultFilter, + SessionResultRange, +} from './types.ts' import { SessionQueryError } from './config.ts' /** @@ -31,6 +37,66 @@ export function filterSessionEventDocuments predicates.every(predicate => predicate(document))) } +/** + * Copy and validate logical-session filters before an asynchronous boundary. + * @param filters - caller-owned clauses to materialize. + * @returns detached validated clauses. + */ +export function materializeSessionResultFilters( + filters: readonly SessionResultFilter[], +): SessionResultFilter[] { + assertArray(filters) + return filters.map((filter) => { + switch (filter.kind) { + case 'id': + return { kind: filter.kind, values: copyStrings(filter.kind, filter.values) } + case 'cwd': + return { kind: filter.kind, values: copyNullableStrings(filter.kind, filter.values) } + case 'created-at': + return copyRange(filter.kind, filter) + case 'parent': + return { kind: filter.kind, values: copyNullableStrings(filter.kind, filter.values) } + case 'availability': { + const values = copyStrings(filter.kind, filter.values) + assertAllowedValues(filter.kind, values, ['live', 'persisted']) + return { kind: filter.kind, values } + } + default: + return unknownFilter(filter) + } + }) +} + +/** + * Copy and validate event filters before an asynchronous boundary. + * @param filters - caller-owned clauses to materialize. + * @returns detached validated clauses. + */ +export function materializeSessionEventResultFilters( + filters: readonly SessionEventResultFilter[], +): SessionEventResultFilter[] { + assertArray(filters) + return filters.map((filter) => { + switch (filter.kind) { + case 'seq': + case 'time': + return copyRange(filter.kind, filter) + case 'type': + return { kind: filter.kind, values: copyStrings(filter.kind, filter.values) } + case 'surface': { + const values = copyStrings(filter.kind, filter.values) + assertAllowedValues(filter.kind, values, ['current', 'shadowed', 'log-only']) + return { kind: filter.kind, values } + } + case 'text': + if (typeof filter.text !== 'string') throw invalidFilter('text filter text must be a string') + return { kind: filter.kind, text: filter.text } + default: + return unknownFilter(filter) + } + }) +} + /** * Compile a literal case-insensitive, whitespace-flexible semantic-text match. * @param text - caller-provided literal text. @@ -66,6 +132,8 @@ function sessionPredicate(filter: SessionResultFilter): (record: SessionRecord) case 'availability': assertAllowedValues(filter.kind, filter.values, ['live', 'persisted']) return record => filter.values.some(value => value === 'live' ? record.live : record.persisted) + default: + return unknownFilter(filter) } } @@ -88,9 +156,47 @@ function eventPredicate(filter: SessionEventResultFilter): (document: SessionEve const pattern = compileSessionTextFilter(filter.text) return document => pattern.test(document.text) } + default: + return unknownFilter(filter) } } +function copyStrings(name: string, values: readonly T[]): T[] { + if (!isRuntimeArray(values) || values.some(value => typeof value !== 'string')) { + throw invalidFilter(`${name} filter values must be an array of strings`) + } + return [...values] +} + +function assertArray(value: unknown): void { + if (!Array.isArray(value)) throw invalidFilter('filters must be an array') +} + +function copyNullableStrings(name: string, values: readonly (T | null)[]): Array { + if (!isRuntimeArray(values) || values.some(value => value !== null && typeof value !== 'string')) { + throw invalidFilter(`${name} filter values must be an array of strings or null`) + } + return [...values] +} + +function copyRange( + kind: K, + range: SessionResultRange, +): { kind: K } & SessionResultRange { + const copy = { + kind, + ...range.from === undefined ? {} : { from: range.from }, + ...range.to === undefined ? {} : { to: range.to }, + } + validateRange(kind, copy) + return copy +} + +function unknownFilter(filter: never): never { + const kind = (filter as { kind?: unknown }).kind + throw invalidFilter(`unknown filter kind ${typeof kind === 'string' ? `"${kind}"` : '(missing)'}`) +} + function assertAllowedValues( name: string, values: readonly string[], @@ -125,8 +231,13 @@ function matchesRange(value: number, range: SessionResultRange): boolean { } function invalidRange(name: string, detail: string): SessionQueryError { - return new SessionQueryError( - `session ${name} filter ${detail}`, - 'SESSION_QUERY_INVALID_FILTER', - ) + return invalidFilter(`${name} filter ${detail}`) +} + +function invalidFilter(detail: string): SessionQueryError { + return new SessionQueryError(`session ${detail}`, 'SESSION_QUERY_INVALID_FILTER') +} + +function isRuntimeArray(value: unknown): boolean { + return Array.isArray(value) } diff --git a/packages/session-query/session-query/src/index.ts b/packages/session-query/session-query/src/index.ts index 243c86746b..2c2155eebc 100644 --- a/packages/session-query/session-query/src/index.ts +++ b/packages/session-query/session-query/src/index.ts @@ -16,6 +16,7 @@ import type { SessionEventSearchRequest, SessionEventWindow, SessionRecord, + SessionResultFilter, SessionSearchExecContext, SessionSearchHit, SessionSearchPage, @@ -28,14 +29,26 @@ import { } from './config.ts' import { SessionCorpus } from './corpus.ts' import { buildSessionEventRecords, buildSessionEventSearchDocuments } from './documents.ts' -import { filterSessionEventDocuments } from './filters.ts' +import { + filterSessionEventDocuments, + filterSessionResults, + materializeSessionEventResultFilters, + materializeSessionResultFilters, +} from './filters.ts' export type * from './types.ts' +export { SessionSearchCursor } from './cursor.ts' export type { Config, SessionQueryErrorCode } from './config.ts' export { SESSION_QUERY_READ_WINDOW_MAX, SessionQueryError } from './config.ts' export { extractSessionEventText } from './extraction.ts' export { buildSessionEventRecords, buildSessionEventSearchDocuments } from './documents.ts' -export { compileSessionTextFilter, filterSessionEventDocuments, filterSessionResults } from './filters.ts' +export { + compileSessionTextFilter, + filterSessionEventDocuments, + filterSessionResults, + materializeSessionEventResultFilters, + materializeSessionResultFilters, +} from './filters.ts' export { assertSessionHeadersCompatible } from './sources.ts' declare module 'cordis' { @@ -109,6 +122,16 @@ export class SessionQueryService extends Service { return this._corpus.listSessions() } + /** + * Filter the complete logical corpus with provider-independent predicates. + * @param filters - ANDed session metadata and availability clauses. + * @returns matching cloned records in deterministic newest-first order. + */ + async filterSessions(filters: readonly SessionResultFilter[]): Promise { + const ownedFilters = materializeSessionResultFilters(filters) + return this._filterSessions(ownedFilters) + } + /** * List lightweight raw-log event records for one logical session. * @param sessionId - live-preferred session id to read. @@ -128,6 +151,18 @@ export class SessionQueryService extends Service { async filterEvents( sessionId: SessionId, filters: readonly SessionEventResultFilter[], + ): Promise { + const ownedFilters = materializeSessionEventResultFilters(filters) + return this._filterEvents(sessionId, ownedFilters) + } + + private async _filterSessions(filters: readonly SessionResultFilter[]): Promise { + return filterSessionResults(await this._corpus.listSessions(), filters) + } + + private async _filterEvents( + sessionId: SessionId, + filters: readonly SessionEventResultFilter[], ): Promise { const loaded = await this._corpus.load(sessionId) const documents = buildSessionEventSearchDocuments(sessionId, loaded.events) @@ -142,16 +177,27 @@ export class SessionQueryService extends Service { async readEvent(request: SessionEventReadRequest): Promise { const before = this._readWindow('before', request.before) const after = this._readWindow('after', request.after) - const loaded = await this._corpus.load(request.sessionId) - const target = loaded.events[request.seq] - if (target === undefined || target.seq !== request.seq) { + const sessionId = request.sessionId + const seq = request.seq + return this._readEvent(sessionId, seq, before, after) + } + + private async _readEvent( + sessionId: SessionId, + seq: number, + before: number, + after: number, + ): Promise { + const loaded = await this._corpus.load(sessionId) + const target = loaded.events[seq] + if (target === undefined || target.seq !== seq) { throw new SessionQueryError( - `session "${request.sessionId}" has no event at seq ${request.seq}`, + `session "${sessionId}" has no event at seq ${seq}`, 'SESSION_QUERY_EVENT_NOT_FOUND', ) } - const startSeq = Math.max(0, request.seq - before) - const endSeq = Math.min(loaded.events.length - 1, request.seq + after) + const startSeq = Math.max(0, seq - before) + const endSeq = Math.min(loaded.events.length - 1, seq + after) return { session: loaded.header, target, diff --git a/packages/session-query/session-query/src/types.ts b/packages/session-query/session-query/src/types.ts index d0de0dd48a..a223084f56 100644 --- a/packages/session-query/session-query/src/types.ts +++ b/packages/session-query/session-query/src/types.ts @@ -5,6 +5,9 @@ */ import type { SessionEvent, SessionEventType, SessionHeader, SessionId } from '@deepseek-ai/dsh-session' +import type { SessionSearchCursor } from './cursor.ts' + +export type { SessionSearchCursor } from './cursor.ts' /** Whether an event is current model context, replaced context, or raw-log-only. */ export type SessionEventSurface = 'current' | 'shadowed' | 'log-only' @@ -106,7 +109,7 @@ export interface SessionSearchPage { /** Results for this page in contract-defined order. */ items: readonly T[] /** Opaque continuation cursor, absent on the final page. */ - nextCursor?: string + nextCursor?: SessionSearchCursor } /** Controls shared by cross-session and within-session search calls. */ @@ -126,7 +129,7 @@ export interface SessionSearchRequest { /** Maximum sessions in this page. */ limit?: number /** Opaque cursor returned for the identical normalized request. */ - cursor?: string + cursor?: SessionSearchCursor } /** Within-session full-text search request. */ @@ -140,7 +143,7 @@ export interface SessionEventSearchRequest { /** Maximum events in this page. */ limit?: number /** Opaque cursor returned for the identical normalized request. */ - cursor?: string + cursor?: SessionSearchCursor } /** One event full-text search hit with a bounded plain-text excerpt. */ diff --git a/packages/session-query/session-query/tests/search-helpers.spec.ts b/packages/session-query/session-query/tests/search-helpers.spec.ts index e9cf857608..8ee9cf1ccf 100644 --- a/packages/session-query/session-query/tests/search-helpers.spec.ts +++ b/packages/session-query/session-query/tests/search-helpers.spec.ts @@ -10,6 +10,8 @@ import SessionQueryService, { extractSessionEventText, filterSessionEventDocuments, filterSessionResults, + materializeSessionEventResultFilters, + materializeSessionResultFilters, SessionSearchService, type SessionEventSearchHit, type SessionEventSearchRequest, @@ -177,6 +179,31 @@ describe('session-query document and filter helpers', () => { expect(() => buildSessionEventRecords(id, malformed)).toThrow(expectCode('SESSION_QUERY_INVALID_SURFACE')) }) + it('owns filters and rejects malformed runtime filter shapes deterministically', () => { + expect(materializeSessionResultFilters([{ kind: 'created-at', to: 2 }])) + .toEqual([{ kind: 'created-at', to: 2 }]) + expect(() => materializeSessionResultFilters('not-an-array' as never)) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => materializeSessionResultFilters([{ kind: 'id', values: 'bad' } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => materializeSessionResultFilters([{ kind: 'id', values: [1] } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => materializeSessionResultFilters([{ kind: 'cwd', values: 'bad' } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => materializeSessionResultFilters([{ kind: 'parent', values: [1] } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => materializeSessionResultFilters([{} as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => materializeSessionEventResultFilters([{ kind: 'text', text: 1 } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => materializeSessionEventResultFilters([{ kind: 'future' } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => filterSessionResults([], [{ kind: 'future' } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + expect(() => filterSessionEventDocuments([], [{ kind: 'future' } as never])) + .toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + }) + it('exposes the scan path on the concrete exact-read service', async () => { const ctx = new Context() await ctx.plugin(SessionStore) diff --git a/packages/session-query/session-query/tests/session-query.spec.ts b/packages/session-query/session-query/tests/session-query.spec.ts index 3b50feee45..e1432722f2 100644 --- a/packages/session-query/session-query/tests/session-query.spec.ts +++ b/packages/session-query/session-query/tests/session-query.spec.ts @@ -1,9 +1,10 @@ import { describe, expect, it } from 'vitest' -import { Context } from 'cordis' +import { Context, type Fiber } from 'cordis' import SessionStore, { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session' import type { SessionEvent, SessionHeader, SessionId as SessionIdType } from '@deepseek-ai/dsh-session' -import SessionPersistence from '@deepseek-ai/dsh-session-persistence' +import SessionPersistence, { SessionPersistenceRevision } from '@deepseek-ai/dsh-session-persistence' import SessionQueryService, { + type SessionEventSurface, type SessionQueryErrorCode, } from '@deepseek-ai/dsh-session-query' @@ -59,6 +60,14 @@ class TestPersistence extends SessionPersistence { TestPersistence.afterList?.() return Promise.resolve(headers) } + + + async listSnapshots() { + return [...TestPersistence.entries.values()].map(entry => ({ + header: structuredClone(entry.meta), + revision: SessionPersistenceRevision(`events:${entry.events.length}`), + })) + } } async function liveContext(config: ConstructorParameters[1] = {}): Promise { @@ -94,6 +103,38 @@ describe('session-query exact reads', () => { expect(older.header.createdAt).toBe(1) }) + it('filters sessions symmetrically and owns mutable filter values immediately', async () => { + const durable = header('durable-filter', 1) + TestPersistence.reset([{ meta: durable, events: eventLog('durable') }]) + const ctx = await liveContext() + const live = ctx.sessions.create(SessionId('live-filter'), { meta: { createdAt: 2 } }) + live.append( + 'user/message', + { content: [{ type: 'text', text: 'live' }], source: { kind: 'user' } }, + { surfaceOp: 'append' }, + ) + const persistence = await ctx.plugin(TestPersistence) + + const ids = [durable.id] + const filtered = ctx.sessionQuery.filterSessions([{ kind: 'id', values: ids }]) + ids[0] = live.id + await expect(filtered).resolves.toEqual([{ + header: durable, + live: false, + persisted: true, + }]) + + const surfaces: SessionEventSurface[] = ['current'] + const events = ctx.sessionQuery.filterEvents(live.id, [{ kind: 'surface', values: surfaces }]) + surfaces[0] = 'shadowed' + await expect(events).resolves.toMatchObject([{ sessionId: live.id, surface: 'current', text: 'live' }]) + await expect(ctx.sessionQuery.filterSessions([{ kind: 'future' } as never])) + .rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + await expect(ctx.sessionQuery.filterEvents(live.id, [{ kind: 'future' } as never])) + .rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + await persistence.dispose() + }) + it('classifies current, shadowed, and raw-log-only events through foldSurface', async () => { const ctx = await liveContext() const session = ctx.sessions.create(SessionId('surface')) @@ -267,4 +308,26 @@ describe('session-query exact reads', () => { await fiber.dispose() expect(ctx.sessionQuery).toBeUndefined() }) + + it('awaits optional-persistence child-fiber quiescence on disposal', async () => { + TestPersistence.reset() + const ctx = new Context() + await ctx.plugin(SessionStore) + const query = await ctx.plugin(SessionQueryService) + const persistence = await ctx.plugin(TestPersistence) + const optional = (ctx.sessionQuery as unknown as { + _corpus: { _optionalPersistenceFiber: Fiber } + })._corpus._optionalPersistenceFiber + let release!: () => void + const cleanup = new Promise((resolve) => { release = resolve }) + optional.ctx.effect(() => () => cleanup) + + let settled = false + const disposing = query.dispose().then(() => { settled = true }) + await Promise.resolve() + expect(settled).toBe(false) + release() + await disposing + await persistence.dispose() + }) }) diff --git a/packages/session-query/session-query/tsconfig.json b/packages/session-query/session-query/tsconfig.json index 7153dae8bb..1a254e5379 100644 --- a/packages/session-query/session-query/tsconfig.json +++ b/packages/session-query/session-query/tsconfig.json @@ -17,6 +17,9 @@ { "path": "../../../vendor/schemastery" }, + { + "path": "../../util/brand" + }, { "path": "../../llm/llm" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 997f00ff5c..902c362355 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -720,6 +720,9 @@ importers: packages/session-persistence/session-persistence: devDependencies: + '@deepseek-ai/dsh-brand': + specifier: workspace:^ + version: link:../../util/brand '@deepseek-ai/dsh-session': specifier: workspace:^ version: link:../../core/session @@ -765,6 +768,9 @@ importers: specifier: ^3.18.0 version: 3.18.0 devDependencies: + '@deepseek-ai/dsh-brand': + specifier: workspace:^ + version: link:../../util/brand '@deepseek-ai/dsh-llm': specifier: workspace:^ version: link:../../llm/llm diff --git a/scripts/type-equiv.manifest.json b/scripts/type-equiv.manifest.json index 0d0a0b871d..ba2d75a8ff 100644 --- a/scripts/type-equiv.manifest.json +++ b/scripts/type-equiv.manifest.json @@ -45,6 +45,8 @@ { "doc": "docs/core-data-structures/persistence.md", "symbol": "SessionHeader", "source": "packages/core/session/src/types.ts" }, { "doc": "docs/core-data-structures/persistence.md", "symbol": "CreateSessionOptions", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/persistence.md", "symbol": "SessionPersistenceRevision", "source": "packages/session-persistence/session-persistence/src/revision.ts" }, + { "doc": "docs/core-data-structures/persistence.md", "symbol": "SessionPersistenceSnapshot", "source": "packages/session-persistence/session-persistence/src/index.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventSurface", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionRecord", "source": "packages/session-query/session-query/src/types.ts" }, @@ -52,6 +54,7 @@ { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionResultFilter", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventResultFilter", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventSearchDocument", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionSearchCursor", "source": "packages/session-query/session-query/src/cursor.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionSearchRequest", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventSearchRequest", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionSearchPage", "source": "packages/session-query/session-query/src/types.ts" }, From 35edf2a825b40e4bac80d3e38d7c5334dbe1dd85 Mon Sep 17 00:00:00 2001 From: Hypatia May Date: Wed, 15 Jul 2026 12:32:18 +0800 Subject: [PATCH 003/368] fix(session-query): qualify persistence revisions by store --- docs/config-catalog.md | 2 +- ...026-07-10-sqlite-session-query-provider.md | 2 +- .../session-persistence-jsonl/README.md | 2 +- .../tests/jsonl.spec.ts | 23 ++++++++ .../session-persistence-sqlite/README.md | 4 +- .../session-persistence-sqlite/src/index.ts | 35 ++++++++--- .../session-persistence-sqlite/src/schema.ts | 38 +++++++++--- .../tests/sqlite.spec.ts | 59 +++++++++++++++++-- .../session-persistence/README.md | 2 +- .../session-persistence/src/index.ts | 4 +- .../session-persistence/src/revision.ts | 5 +- .../session-query-sqlite/README.md | 2 +- .../session-query-sqlite/tests/sqlite.spec.ts | 45 ++++++++++++++ 13 files changed, 192 insertions(+), 31 deletions(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index e8a06e469e..aa37295146 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -574,7 +574,7 @@ export interface Config { export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' ``` -Source: [`packages/session-persistence/session-persistence-sqlite/src/index.ts:50`](../packages/session-persistence/session-persistence-sqlite/src/index.ts) +Source: [`packages/session-persistence/session-persistence-sqlite/src/index.ts:51`](../packages/session-persistence/session-persistence-sqlite/src/index.ts) ## `@deepseek-ai/dsh-session-query` diff --git a/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md b/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md index fafa7f3569..b77279949b 100644 --- a/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md +++ b/docs/rfc/implemented/feature/2026-07-10-sqlite-session-query-provider.md @@ -32,7 +32,7 @@ Both persistent and live FTS5 tables use `unicode61`. The implementation experim The shared extractor includes message text, reasoning, nested tool-call/result content, tool names and arguments, blocked-prompt reasons, todo status/content, and error or terminal status detail. Structural boundaries, stream chunks, request headers, successful completion markers, and unknown declaration-merged event/content variants produce no document. Surface classification reuses `foldSurface()` so search agrees with model-history derivation. -One serialized operation reads the provider-neutral `SessionPersistence` snapshot listing, compares each opaque revision with the revision stored beside the indexed session, loads only new or changed logs, reconciles rows in one transaction, and executes the query. Observation repeats when listing changes during a load; this incorporates a mutating load repair's refreshed revision before commit. Repeated queries and unchanged reopen load no full persisted logs. New, changed, and deleted sessions update on the next stable search. A source or extraction failure cannot mark a row current, and a transaction failure rolls back so a later search retries. +One serialized operation reads the provider-neutral `SessionPersistence` snapshot listing, compares each source-qualified opaque revision with the revision stored beside the indexed session, loads only new or changed logs, reconciles rows in one transaction, and executes the query. A revision identifies its backing persistence store as well as the backend-local log revision, so reopening against the same store reuses indexed rows while switching to an independent store cannot collide on a session id and local counter. Observation repeats when listing changes during a load; this incorporates a mutating load repair's refreshed revision before commit. Repeated queries and unchanged reopen load no full persisted logs. New, changed, and deleted sessions update on the next stable search. A source or extraction failure cannot mark a row current, and a transaction failure rolls back so a later search retries. Persisted documents survive restarts. Live sessions use connection-local TEMP tables, shadow the persisted base for the same id, and reveal that base on detach. Closing the database drops live rows. Unmounting persistence hides durable rows without treating absence as authoritative deletion; remounting observes and reconciles the backend again. Conflicting immutable live and durable headers fail rather than combining sources. diff --git a/packages/session-persistence/session-persistence-jsonl/README.md b/packages/session-persistence/session-persistence-jsonl/README.md index 0be2c785b3..2043967cb8 100644 --- a/packages/session-persistence/session-persistence-jsonl/README.md +++ b/packages/session-persistence/session-persistence-jsonl/README.md @@ -25,7 +25,7 @@ The JSONL durable session-persistence backend — a concrete `SessionPersistence - **Append-only.** Committed events (at or below a flushed `turn/end`) are never rewritten. Subsequent appends are line appends at EOF + `fsync`. - **Crash recovery — close, don't truncate.** A crash can leave a log whose final turn never closed (real events after the last `turn/end`). `load` PRESERVES those events (a turn can be huge — they are real work) and closes the orphaned turn by durably appending synthetic boundary events: an error `tool/result` for every `tool-call` the crash left unanswered (the loop logs the assistant message before running the tools, so a mid-tool crash leaves dangling calls — and `deriveMessages()` would replay an assistant tool-call with no result, which providers reject), then a `step/end` if a step was open, then `turn/end {kind:'interrupted'}`, returning a balanced log. Only a never-fully-written **torn tail fragment** (a final line with no newline / unparseable) is `ftruncate`d away before the closers are written. See [session persistence](../../../docs/rfc/implemented/architecture/2026-06-14-session-persistence.md). - **Contiguous-seq.** `load` rejects a mid-log parse error or `seq` gap (unloadable); `append` rejects a batch whose first `seq` does not continue the stored log, and rejects non-JSON-serializable `event.data` naming the offending event type. -- **Lightweight revisions.** `listSnapshots()` reads each header and returns an opaque identity from the file device/inode, size, and nanosecond mtime/ctime. Under the append-only single-writer contract, unchanged files retain revisions while append, repair, or replacement changes them without parsing event lines. +- **Lightweight revisions.** `listSnapshots()` reads each header and returns an opaque identity from the file device/inode, size, and nanosecond mtime/ctime. Under the append-only single-writer contract, unchanged files retain revisions while append, repair, replacement, or switching to an independent root changes them without parsing event lines. - **Format version.** Only the current `SESSION_FORMAT_VERSION` (v0) is supported; `load` rejects any other version. While the harness is unreleased the on-disk format is pre-release/unstable: a breaking format change is absorbed at v0 (no bump until the first tagged release) and non-current logs are rejected — there is no migration (no persisted user data to preserve). ## Write path diff --git a/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts b/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts index 757ba03aac..6f5aa81ee0 100644 --- a/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts +++ b/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts @@ -147,6 +147,29 @@ describe('SessionPersistenceJsonl: durability and crash semantics', () => { expect(loaded.events).toEqual(log) // chunks preserved, contiguous seqs }) + it('source-qualifies revisions across roots while preserving same-log reopen identity', async () => { + const m = meta('revision-source') + await ctx.sessionPersistence.create(m) + await ctx.sessionPersistence.append(m.id, oneTurnLog()) + const revision = (await ctx.sessionPersistence.listSnapshots())[0]?.revision + + const reopenedCtx = new Context() + await reopenedCtx.plugin(SessionStore) + await reopenedCtx.plugin(SessionPersistenceJsonl, { root }) + expect((await reopenedCtx.sessionPersistence.listSnapshots())[0]?.revision).toBe(revision) + + const otherRoot = await freshRoot() + const otherCtx = new Context() + await otherCtx.plugin(SessionStore) + await otherCtx.plugin(SessionPersistenceJsonl, { root: otherRoot }) + await otherCtx.sessionPersistence.create(m) + await otherCtx.sessionPersistence.append(m.id, oneTurnLog()) + expect((await otherCtx.sessionPersistence.listSnapshots())[0]?.revision).not.toBe(revision) + + await reopenedCtx.fiber.dispose() + await otherCtx.fiber.dispose() + }) + it('persists a forked child seed through the existing session write path', async () => { const source = ctx.sessions.create(SessionId('persist-parent'), { meta: { cwd: '/workspace' } }) appendClosedTurn(source) diff --git a/packages/session-persistence/session-persistence-sqlite/README.md b/packages/session-persistence/session-persistence-sqlite/README.md index 6e6006dc6b..e45f1d2371 100644 --- a/packages/session-persistence/session-persistence-sqlite/README.md +++ b/packages/session-persistence/session-persistence-sqlite/README.md @@ -6,7 +6,7 @@ A SQLite durable session-persistence backend — a second `SessionPersistence` i ## Storage model -Each `SessionEvent` maps 1:1 onto a row in an `events` table `(session_id, seq, type, time, data, source_event_seqs, surface_op)` — `data` is the event payload as JSON text, so the row shape is the event verbatim (including `assistant/chunk`, keeping `seq` contiguous). The two `TEXT` columns `source_event_seqs` and `surface_op` are nullable; they store the event's optional surface-metadata fields (see [session surface](../../../docs/rfc/implemented/architecture/2026-06-18-session-surface.md)). Out-of-log metadata (`SessionHeader`) and a monotonic per-log revision live in a `sessions` row. A `sessions` row is written only by the first `append` — its existence is the lazy-materialization signal (`list` reports exactly the sessions that have a row). +Each `SessionEvent` maps 1:1 onto a row in an `events` table `(session_id, seq, type, time, data, source_event_seqs, surface_op)` — `data` is the event payload as JSON text, so the row shape is the event verbatim (including `assistant/chunk`, keeping `seq` contiguous). The two `TEXT` columns `source_event_seqs` and `surface_op` are nullable; they store the event's optional surface-metadata fields (see [session surface](../../../docs/rfc/implemented/architecture/2026-06-18-session-surface.md)). Out-of-log metadata (`SessionHeader`) and a monotonic per-log revision live in a `sessions` row; a singleton state row carries the immutable store id. A `sessions` row is written only by the first `append` — its existence is the lazy-materialization signal (`list` reports exactly the sessions that have a row). The repo's `engines.node` is `^22.19.0 || >=24.0.0` (Node 22.19+ or 24+), matching the LTS floor required by the installed Pi adapter dependency; `node:sqlite` itself ships without the `--experimental-sqlite` flag from Node 22.13 (LTS) and 23.4 / 24 (Current) on. The range deliberately excludes Node 23 because that line is non-LTS/EOL and still has flagged runtime features before 23.6. The database opens with `foreign_keys = ON` (so `ON DELETE CASCADE` drops a session's events with its row) and the configured `journal_mode` (default `wal`; pick a rollback-journal mode like `delete` on filesystems where WAL's shared-memory files do not work, e.g. network mounts). The table-layout version is stored in `PRAGMA user_version` and checked on open: a fresh database is stamped with the current `SCHEMA_VERSION`; a database written by any other, incompatible build (a non-current `user_version`, older or newer) is rejected rather than opened against an unknown layout — there is no migration (unreleased software). @@ -14,7 +14,7 @@ The repo's `engines.node` is `^22.19.0 || >=24.0.0` (Node 22.19+ or 24+), matchi - **Append = a transaction.** `append` runs `BEGIN`/`COMMIT` around the batch: it materializes the `sessions` row (if still lazy) and INSERTs every event, asserting the contiguous-seq contract first (the first event's `seq` must equal the stored next-seq). A mid-batch failure (a UNIQUE violation on a duplicated seq) rolls back entirely, so the stored log and the in-memory cursor stay consistent. (`load()` already balanced the stored log, so `append` never has to repair a crash tail.) - **Lazy materialization.** `create()` records intent in memory only — no row is written until the first `append`. A created-but-never-appended session has no `sessions` row, so it is absent from `list()` (which reports exactly the sessions that have a row). -- **Lightweight revisions.** `listSnapshots()` reads the monotonic revision stored beside each session header. Append and mutating load repair increment it in the same transaction as their event changes, so unchanged observations are stable and no full-log count or parse is required. +- **Lightweight revisions.** `listSnapshots()` combines the database's immutable random store id and physical file identity with the monotonic revision stored beside each session header; an in-memory database uses the store id alone. Append and mutating load repair increment the local counter in the same transaction as their event changes, so unchanged same-file observations are stable, independent stores and file replacements cannot collide on a local counter, and no full-log count or parse is required. - **Interrupted-turn close on load.** `load()` reads every stored event ordered by `seq` and finds the longest seq-contiguous, parseable prefix — INCLUDING the real events of an interrupted final turn after the last `turn/end` (the loop only flushes at `turn/end`, so a process killed mid-turn leaves real, fully-written rows past it). A single turn can be huge in a long-horizon task, so those events are **preserved, never truncated**: `load()` CLOSES the orphaned turn by durably appending the minimal synthetic boundary events (an error `tool/result` for every assistant tool call left unanswered, a `step/end` if a step was open, then a `turn/end` carrying `{ kind: 'interrupted' }`), inside one transaction that also DELETEs any never-fully-written torn tail row. `load()` is therefore mutating — after it the stored rows are balanced and the cursor is truthful, so the next `append` continues cleanly. The boundary (last `turn/end`, torn-tail detection) is computed from the `seq`/`type` columns so a malformed `data` in a torn tail row is never parsed (discarded, not unloadable). A parse error or `seq` gap inside the committed region (at or before the last real `turn/end`) makes the session unloadable. A session whose only turn never closed keeps its metadata row and stays present in `list()` — the same as the JSONL backend, whose file likewise survives a first append that never reached `turn/end`. ## Configuration (schemastery) diff --git a/packages/session-persistence/session-persistence-sqlite/src/index.ts b/packages/session-persistence/session-persistence-sqlite/src/index.ts index 3a1c7ffbcc..546f285824 100644 --- a/packages/session-persistence/session-persistence-sqlite/src/index.ts +++ b/packages/session-persistence/session-persistence-sqlite/src/index.ts @@ -19,6 +19,7 @@ import { Context } from 'cordis' import z from 'schemastery' +import { statSync } from 'node:fs' import { DatabaseSync } from 'node:sqlite' import { mkdir } from 'node:fs/promises' import { dirname, resolve } from 'node:path' @@ -84,6 +85,7 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers override readonly name = 'session-persistence-sqlite' private db!: DatabaseSync + private storeIdentity!: string private ready: Promise private coordinator: PersistenceCoordinator @@ -98,12 +100,29 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers } private async openDb(path: string, journalMode: JournalMode): Promise { - if (path !== ':memory:') { - const abs = resolve(path) - await mkdir(dirname(abs), { recursive: true, mode: 0o700 }) - this.db = openDatabase(abs, journalMode) - } else { - this.db = openDatabase(path, journalMode) + const actual = path === ':memory:' ? path : resolve(path) + if (actual !== ':memory:') await mkdir(dirname(actual), { recursive: true, mode: 0o700 }) + this.db = openDatabase(actual, journalMode) + try { + const row = this.db.prepare( + 'SELECT store_id FROM persistence_state WHERE singleton = 1', + ).get() as { store_id: string } | undefined + /* v8 ignore next -- openDatabase inserts the singleton before returning. */ + if (row === undefined) { + throw new Error(`session database at "${actual}" has no store identity`) + } + if (row.store_id.length === 0) { + throw new Error(`session database at "${actual}" has no valid store identity`) + } + if (actual !== ':memory:') { + const identity = statSync(actual, { bigint: true }) + this.storeIdentity = `file:${identity.dev}:${identity.ino}:${identity.birthtimeNs}:store:${row.store_id}` + } else { + this.storeIdentity = `memory:store:${row.store_id}` + } + } catch (error: unknown) { + this.db.close() + throw error } } @@ -234,13 +253,13 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers return rows.map(rowToMeta) } - /** List metadata with an append-only event-count revision per session. */ + /** List metadata with a source-qualified monotonic revision per session. */ async listSnapshots(): Promise { await this.ready const rows = this.db.prepare('SELECT * FROM sessions').all() as unknown as SessionRow[] return rows.map(row => ({ header: rowToMeta(row), - revision: SessionPersistenceRevision(`revision:${row.revision}`), + revision: SessionPersistenceRevision(`${this.storeIdentity}:revision:${row.revision}`), })) } diff --git a/packages/session-persistence/session-persistence-sqlite/src/schema.ts b/packages/session-persistence/session-persistence-sqlite/src/schema.ts index 2f238b0131..caf1766f22 100644 --- a/packages/session-persistence/session-persistence-sqlite/src/schema.ts +++ b/packages/session-persistence/session-persistence-sqlite/src/schema.ts @@ -1,12 +1,14 @@ /** * Schema + load-time helpers for the SQLite session-persistence backend: the - * DDL (a `sessions` metadata table and a 1:1 `events` row per `SessionEvent`), - * the database open/configure step, and the last-`turn/end` cut that gives the - * SQLite backend the SAME crash-tail-on-load semantics as the JSONL backend. + * DDL (a store-identity row, `sessions` metadata, and a 1:1 `events` row per + * `SessionEvent`), the database open/configure step, and the last-`turn/end` + * cut that gives the SQLite backend the SAME crash-tail-on-load semantics as + * the JSONL backend. * * @module dsh-session-persistence-sqlite/schema */ +import { randomUUID } from 'node:crypto' import { DatabaseSync } from 'node:sqlite' import type { SessionEvent, SessionId, SessionHeader, SurfaceOp } from '@deepseek-ai/dsh-session' @@ -15,7 +17,7 @@ import type { SessionEvent, SessionId, SessionHeader, SurfaceOp } from '@deepsee * layout; orthogonal to a session's own `version` (which versions the EVENT * vocabulary, stored per session in the `sessions` row). */ -export const SCHEMA_VERSION = 5 +export const SCHEMA_VERSION = 6 /** * A row of the `sessions` table — the out-of-log metadata ({@link SessionHeader}). @@ -70,14 +72,25 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' * current one (written by a different, incompatible build — older or newer) is * REJECTED rather than opened against a layout this build does not understand. * There are no migrations: an incompatible layout is rejected. The current - * sessions row carries every header field plus its monotonic snapshot revision; - * the events row carries the complete surface metadata. + * persistence-state row carries an immutable random store id, the sessions row + * carries every header field plus its monotonic snapshot revision, and the + * events row carries the complete surface metadata. * @param path - the SQLite database file to open (created when absent). * @param journalMode - the journal pragma to apply — a closed in-code union, validated by the plugin Config. - * @returns the open handle with pragmas applied and both tables ensured. + * @returns the open handle with pragmas applied and all three tables ensured. */ export function openDatabase(path: string, journalMode: JournalMode): DatabaseSync { const db = new DatabaseSync(path) + try { + configureDatabase(db, path, journalMode) + return db + } catch (error: unknown) { + db.close() + throw error + } +} + +function configureDatabase(db: DatabaseSync, path: string, journalMode: JournalMode): void { db.exec('PRAGMA foreign_keys = ON') // journalMode is a closed in-code union (validated by the plugin Config), not // user-controlled SQL — safe to interpolate (PRAGMA takes no bound params). @@ -85,7 +98,6 @@ export function openDatabase(path: string, journalMode: JournalMode): DatabaseSy // `PRAGMA user_version` always returns exactly one row { user_version }. const { user_version: onDisk } = db.prepare('PRAGMA user_version').get() as { user_version: number } if (onDisk !== 0 && onDisk !== SCHEMA_VERSION) { - db.close() throw new Error(`session database at "${path}" has schema version ${onDisk}, incompatible with this build (${SCHEMA_VERSION})`) } if (onDisk === 0) { @@ -94,6 +106,15 @@ export function openDatabase(path: string, journalMode: JournalMode): DatabaseSy // constant (SCHEMA_VERSION is a trusted in-code number, not user input). db.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`) } + db.exec(` + CREATE TABLE IF NOT EXISTS persistence_state ( + singleton INTEGER PRIMARY KEY CHECK (singleton = 1), + store_id TEXT NOT NULL + ) STRICT + `) + db.prepare( + 'INSERT OR IGNORE INTO persistence_state (singleton, store_id) VALUES (1, ?)', + ).run(randomUUID()) db.exec(` CREATE TABLE IF NOT EXISTS sessions ( id TEXT PRIMARY KEY, @@ -117,7 +138,6 @@ export function openDatabase(path: string, journalMode: JournalMode): DatabaseSy PRIMARY KEY (session_id, seq) ) STRICT `) - return db } /** diff --git a/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts b/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts index 98924ca691..5b85f65908 100644 --- a/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts +++ b/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts @@ -1,7 +1,7 @@ import { afterEach, describe, expect, it } from 'vitest' import { Context } from 'cordis' import { existsSync } from 'node:fs' -import { mkdtemp, rm } from 'node:fs/promises' +import { mkdtemp, rm, symlink } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' import SessionStore, { SessionId } from '@deepseek-ai/dsh-session' @@ -245,12 +245,12 @@ describe('SessionPersistenceSqlite: durability and crash semantics', () => { dbNewer.close() expect(() => openDatabase(path, 'wal')).toThrow(/incompatible with this build/) - // A stale OLDER version (e.g. a pre-summary-drop v1 DB) is also rejected — - // we do not migrate (unreleased software, no backward-compat). + // The immediately preceding layout lacks the required store identity and is + // rejected rather than migrated (unreleased software, no backward-compat). const olderPath = await freshDbPath() openDatabase(olderPath, 'wal').close() const dbOlder = openDatabase(olderPath, 'wal') - dbOlder.exec('PRAGMA user_version = 1') + dbOlder.exec(`PRAGMA user_version = ${SCHEMA_VERSION - 1}`) dbOlder.close() expect(() => openDatabase(olderPath, 'wal')).toThrow(/incompatible with this build/) }) @@ -337,8 +337,46 @@ describe('SessionPersistenceSqlite: durability and crash semantics', () => { await fiber2.dispose() }) + it('source-qualifies revisions across stores while preserving same-file reopen identity', async () => { + const pathA = await freshDbPath() + const pathB = await freshDbPath() + const m = meta('revision-source') + const a = await backend(pathA) + await a.ctx.sessionPersistence.create(m) + await a.ctx.sessionPersistence.append(m.id, oneTurnLog()) + const revisionA = (await a.ctx.sessionPersistence.listSnapshots())[0]?.revision + await a.dispose() + + const probeA = openDatabase(pathA, 'wal') + const storeIdA = (probeA.prepare( + 'SELECT store_id FROM persistence_state WHERE singleton = 1', + ).get() as { store_id: string }).store_id + probeA.close() + + const aliasA = `${pathA}.alias` + await symlink(pathA, aliasA) + const reopenedA = await backend(aliasA) + expect((await reopenedA.ctx.sessionPersistence.listSnapshots())[0]?.revision).toBe(revisionA) + await reopenedA.dispose() + + const b = await backend(pathB) + await b.ctx.sessionPersistence.create(m) + await b.ctx.sessionPersistence.append(m.id, oneTurnLog()) + const revisionB = (await b.ctx.sessionPersistence.listSnapshots())[0]?.revision + const probeB = openDatabase(pathB, 'wal') + const storeIdB = (probeB.prepare( + 'SELECT store_id FROM persistence_state WHERE singleton = 1', + ).get() as { store_id: string }).store_id + probeB.close() + expect(storeIdB).not.toBe(storeIdA) + expect(revisionB).not.toBe(revisionA) + expect(String(revisionA)).toMatch(/:revision:1$/) + expect(String(revisionB)).toMatch(/:revision:1$/) + await b.dispose() + }) + it('exposes the schema version constant', () => { - expect(SCHEMA_VERSION).toBe(5) + expect(SCHEMA_VERSION).toBe(6) }) it('keeps the revision stable for an empty repair hook', async () => { @@ -354,6 +392,17 @@ describe('SessionPersistenceSqlite: durability and crash semantics', () => { }) describe('SessionPersistenceSqlite: edge cases', () => { + it('rejects and closes a current-schema database with an invalid store identity', async () => { + const path = await freshDbPath() + const db = openDatabase(path, 'wal') + db.exec("UPDATE persistence_state SET store_id = '' WHERE singleton = 1") + db.close() + + const b = await backend(path) + await expect(b.ctx.sessionPersistence.listSnapshots()).rejects.toThrow(/no valid store identity/) + await expect(b.dispose()).resolves.toBeUndefined() + }) + it('append rolls back and rethrows when an event INSERT fails inside the transaction', async () => { const path = await freshDbPath() const m = meta('rollback-insert') diff --git a/packages/session-persistence/session-persistence/README.md b/packages/session-persistence/session-persistence/README.md index 32958bfaaa..d16bfcda40 100644 --- a/packages/session-persistence/session-persistence/README.md +++ b/packages/session-persistence/session-persistence/README.md @@ -12,7 +12,7 @@ The persisted unit IS the existing `SessionEvent` (event-sourced model — the l | `append(id, events): Promise` | Durably persist a batch (from the `session/flush` drain). Append-only; first event `seq` == stored next-seq after any repair; rejects non-JSON-serializable data naming the offending type. | | `load(id): Promise<{ meta; events }>` | Reload meta + log. Preserves an interrupted (unclosed) final turn and closes it with synthetic closers — an error `tool/result` per unanswered `tool-call`, then `step/end?`+`turn/end {interrupted}` (a turn can be huge — never truncated); only a torn tail fragment is dropped. Events contiguous (`events[i].seq === i`); rejects a committed-region gap/parse error or unknown `version`. | | `list(): Promise` | Lightweight listing from metadata, no full-log parse. A zero-event lazily-materialized session is absent from `list`. | -| `listSnapshots(): Promise` | Lightweight metadata plus an opaque branded per-log revision, without loading event logs. A revision stays equal while that log is unchanged and changes after append or mutating load repair. | +| `listSnapshots(): Promise` | Lightweight metadata plus an opaque branded per-log revision, without loading event logs. A revision stays equal while that log and its backing store are unchanged, changes after append or mutating load repair, and cannot collide solely because two stores use the same local counter. | ## Invariants every backend must honor diff --git a/packages/session-persistence/session-persistence/src/index.ts b/packages/session-persistence/session-persistence/src/index.ts index 84ab0f321a..b647befeee 100644 --- a/packages/session-persistence/session-persistence/src/index.ts +++ b/packages/session-persistence/session-persistence/src/index.ts @@ -34,7 +34,7 @@ export { SessionPersistenceRevision } from './revision.ts' export interface SessionPersistenceSnapshot { /** Detached metadata for one materialized session. */ header: SessionHeader - /** Opaque token that changes whenever this stored log changes. */ + /** Opaque source-qualified token that changes whenever this stored log changes. */ revision: SessionPersistenceRevision } @@ -172,6 +172,8 @@ export abstract class SessionPersistence extends Service { * * Repeated observations of an unchanged log return the same revision. A * successful mutating {@link load} repair changes the next listed revision. + * Revisions also distinguish independently backed stores so backend-local + * counters cannot compare equal across different persistence sources. * @returns one header and opaque revision per materialized session without loading full logs. */ abstract listSnapshots(): Promise diff --git a/packages/session-persistence/session-persistence/src/revision.ts b/packages/session-persistence/session-persistence/src/revision.ts index 41378eb3e4..cb037ffafc 100644 --- a/packages/session-persistence/session-persistence/src/revision.ts +++ b/packages/session-persistence/session-persistence/src/revision.ts @@ -2,7 +2,10 @@ import type { Branded } from '@deepseek-ai/dsh-brand' -/** Backend-owned token that changes whenever one persisted session log changes. */ +/** + * Backend-owned token that identifies both one storage source and one revision + * of a persisted session log. + */ export type SessionPersistenceRevision = Branded<'SessionPersistenceRevision'> /** diff --git a/packages/session-query/session-query-sqlite/README.md b/packages/session-query/session-query-sqlite/README.md index 001ea87d7d..d2f337cafd 100644 --- a/packages/session-query/session-query-sqlite/README.md +++ b/packages/session-query/session-query-sqlite/README.md @@ -12,7 +12,7 @@ All three surfaces (`current`, `shadowed`, and `log-only`) are searchable by def ## Source and index lifecycle -The service requires `ctx.sessions` and observes optional `ctx.sessionPersistence` dynamically. One serialized state machine compares lightweight durable snapshot revisions, loads only new or changed logs, extracts shared semantic documents, reconciles changes transactionally, and runs the query. Repeated queries and unchanged reopen load no full durable logs; new, changed, deleted, or load-repaired sources reconcile on the next stable observation. Source or transaction failure commits nothing, and the next search retries. +The service requires `ctx.sessions` and observes optional `ctx.sessionPersistence` dynamically. One serialized state machine compares source-qualified lightweight durable snapshot revisions, loads only new or changed logs, extracts shared semantic documents, reconciles changes transactionally, and runs the query. Repeated queries and unchanged same-store reopen load no full durable logs; switching stores, or observing new, changed, deleted, or load-repaired sources, reconciles on the next stable observation. Source or transaction failure commits nothing, and the next search retries. Persisted FTS rows live in a dedicated derived database. Connection-local TEMP tables hold live rows, which shadow the durable base for the same session and reveal it when the live owner disappears. Unmounting persistence hides durable rows without discarding the cache; remounting reconciles it. Closing or reopening the database drops every live overlay while retaining persisted rows. diff --git a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts index f4904e17d8..9897331549 100644 --- a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts @@ -926,4 +926,49 @@ describe('SQLite schema, cancellation, and real persistence integration', () => await expect(ctx.sessionPersistence.load(meta.id)).resolves.toMatchObject({ meta, events: [{ seq: 0 }] }) await persistence.dispose() }) + + it('reconciles colliding local revisions when a derived index reopens against another SQLite store', async () => { + const persistencePathA = await temporaryPath('canonical-a.db') + const persistencePathB = await temporaryPath('canonical-b.db') + const searchPath = await temporaryPath('derived-collision.db') + const shared = header('same-id', 10) + + const first = new Context() + await first.plugin(SessionStore) + const persistenceA = await first.plugin(SessionPersistenceSqlite, { path: persistencePathA }) + await first.sessionPersistence.create(shared) + await first.sessionPersistence.append(shared.id, messageEvents('alpha source')) + const loadA = vi.spyOn(first.sessionPersistence, 'load') + const searchA = await first.plugin(SessionSearchSqlite, { path: searchPath }) + await expect(first.sessionSearch.searchSessions({ query: 'alpha' })) + .resolves.toMatchObject({ items: [{ header: shared }] }) + expect(loadA).toHaveBeenCalledTimes(1) + await searchA.dispose() + await persistenceA.dispose() + + const reopened = new Context() + await reopened.plugin(SessionStore) + const persistenceAAgain = await reopened.plugin(SessionPersistenceSqlite, { path: persistencePathA }) + const reopenedLoad = vi.spyOn(reopened.sessionPersistence, 'load') + const searchAAgain = await reopened.plugin(SessionSearchSqlite, { path: searchPath }) + await expect(reopened.sessionSearch.searchSessions({ query: 'alpha' })) + .resolves.toMatchObject({ items: [{ header: shared }] }) + expect(reopenedLoad).not.toHaveBeenCalled() + await searchAAgain.dispose() + await persistenceAAgain.dispose() + + const second = new Context() + await second.plugin(SessionStore) + const persistenceB = await second.plugin(SessionPersistenceSqlite, { path: persistencePathB }) + await second.sessionPersistence.create(shared) + await second.sessionPersistence.append(shared.id, messageEvents('bravo source')) + const loadB = vi.spyOn(second.sessionPersistence, 'load') + const searchB = await second.plugin(SessionSearchSqlite, { path: searchPath }) + await expect(second.sessionSearch.searchSessions({ query: 'bravo' })) + .resolves.toMatchObject({ items: [{ header: shared }] }) + await expect(second.sessionSearch.searchSessions({ query: 'alpha' })).resolves.toEqual({ items: [] }) + expect(loadB).toHaveBeenCalledTimes(1) + await searchB.dispose() + await persistenceB.dispose() + }) }) From 9eb49f61a9334429837325849d34979f95fdd368 Mon Sep 17 00:00:00 2001 From: Hypatia May Date: Wed, 15 Jul 2026 12:41:46 +0800 Subject: [PATCH 004/368] chore(knip): include session query loader e2e --- knip.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/knip.json b/knip.json index 825980f205..03fcd1b30d 100644 --- a/knip.json +++ b/knip.json @@ -45,6 +45,10 @@ "entry": ["tests/**/*.spec.ts", "tests/**/*.e2e.ts"], "project": ["src/**/*.ts", "tests/**/*.ts"] }, + "packages/session-query/session-query-sqlite": { + "entry": ["tests/**/*.spec.ts", "tests/**/*.e2e.ts"], + "project": ["src/**/*.ts", "tests/**/*.ts"] + }, "packages/code-runtime/code-runtime-worker": { "entry": ["tests/**/*.spec.ts", "tests/**/*.e2e.ts"], "project": ["src/**/*.ts", "tests/**/*.ts"] From f1426511be657e9ca45663f9724678ffe3a79ca4 Mon Sep 17 00:00:00 2001 From: Hypatia May Date: Wed, 15 Jul 2026 16:35:17 +0800 Subject: [PATCH 005/368] test(hooks): wait for SubagentStop marker output --- packages/hooks/hooks-claude/tests/coverage.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/hooks/hooks-claude/tests/coverage.spec.ts b/packages/hooks/hooks-claude/tests/coverage.spec.ts index f376708688..9632d075dd 100644 --- a/packages/hooks/hooks-claude/tests/coverage.spec.ts +++ b/packages/hooks/hooks-claude/tests/coverage.spec.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from 'vitest' -import { mkdtempSync, rmSync, writeFileSync, chmodSync, existsSync } from 'node:fs' +import { mkdtempSync, rmSync, writeFileSync, chmodSync, existsSync, readFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { Context } from 'cordis' @@ -612,7 +612,6 @@ describe('hooks-claude coverage — hook runs in the session cwd, not the server await waitForIdle(ctx, handle.agent as ReactLoopAgent) expect(existsSync(marker)).toBe(true) // the marker landed in the SESSION dir - const { readFileSync } = await import('node:fs') const where = readFileSync(marker, 'utf8').trim() // `pwd` may resolve symlinks (/var → /private/var etc.), so compare basenames. expect(where.endsWith(sessionDir.split('/').pop()!)).toBe(true) @@ -643,9 +642,10 @@ describe('hooks-claude coverage — hook runs in the session cwd, not the server const childHandle = await ctx.agents.create({ agentId: AgentId('child-stop'), sessionId: SessionId('child-stop-session'), meta: { cwd: childDir }, agentOptions: { model: 'mock' } }) ctx.emit('subagent/end', { provider: 'inproc', id: childHandle.agent.id, stopReason: 'completed' }) - await waitFor(() => existsSync(marker)) + // Redirection creates the marker before `pwd` writes it, so wait for the + // trailing newline that marks the command's complete output. + await waitFor(() => existsSync(marker) && readFileSync(marker, 'utf8').endsWith('\n')) expect(existsSync(marker)).toBe(true) // the marker landed in the CHILD dir - const { readFileSync } = await import('node:fs') const where = readFileSync(marker, 'utf8').trim() // `pwd` may resolve symlinks (/var → /private/var etc.), so compare basenames. expect(where.endsWith(childDir.split('/').pop()!)).toBe(true) From 069e0ecdc9b0acac254602e3535a2fafb999f332 Mon Sep 17 00:00:00 2001 From: NI0317 Date: Wed, 15 Jul 2026 20:57:51 +0800 Subject: [PATCH 006/368] docs: refresh top-level README + add dsh-arch-diagram skill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the 20-line stub with a bilingual README pair covering: - getting started (`pnpm run demo:repl` + Node ^22.19 || ≥24 + pnpm 11.7) - editor integration (Zed / VS Code / Cursor over ACP) - programmatic embedding via `@deepseek-ai/dsh-app-boot` (with the two failure paths of `boot()` vs `installFailLoud` spelled out) - writing a plugin (`echo-tool` grounded in `examples/echo-agent`, with the runnable command `pnpm run demo:echo`) - Packages table grouped by family, including `session-query`, `context`, and Support (with `invariants` called out as a runtime diagnostic mounted by `dsh-agent-core`, not test-only) - deep-dive links, community, license Bilingual pairing: English and Chinese sides share byte-identical code blocks and mirroring link ordinals; language-asymmetric community channels (Discord/X in EN, WeCom in ZH) sit inside HTML `` tags that the pairing gate's structural signature excludes by design. ZH side follows `docs/i18n/terminology.md` — first `agent` occurrence annotated as `agent(智能体)`, plain `agent` thereafter. Ships an in-repo skill at `.agents/skills/dsh-arch-diagram/` that owns the two architecture PNGs (`assets/arch-{en,zh}.png`). HTML templates + shared CSS + a `render.sh` that renders via Chrome headless. The renderer is portable (auto-detects Chrome/Chromium on macOS + Linux, uses `--no-sandbox` under root for container envs, discovers the local http.server port from Python's own startup line so `lsof` isn't required). The 12-card capability row uses `flex: 0 0 auto` so adjacent card backgrounds cannot clip descriptions; layout tuned to 1560px page / 96% row-width / 1820×580 render viewport. Consolidates the four review-response commits from the initial round of ds-review-bot feedback; each review round is documented in a top-level PR comment for traceability. --- .agents/skills/dsh-arch-diagram/SKILL.md | 158 ++++++++++++ .../dsh-arch-diagram/harness-arch-en.html | 66 +++++ .../dsh-arch-diagram/harness-arch-zh.html | 66 +++++ .../skills/dsh-arch-diagram/harness-arch.css | 220 ++++++++++++++++ .agents/skills/dsh-arch-diagram/render.sh | 97 +++++++ README.i18n.yaml | 4 +- README.md | 240 +++++++++++++++++- README.zh.md | 240 +++++++++++++++++- assets/arch-en.png | Bin 0 -> 681579 bytes assets/arch-zh.png | Bin 0 -> 677426 bytes assets/community-wecom-survey.png | Bin 0 -> 5508 bytes assets/demo-acp.mp4 | Bin 0 -> 4675786 bytes 12 files changed, 1069 insertions(+), 22 deletions(-) create mode 100644 .agents/skills/dsh-arch-diagram/SKILL.md create mode 100644 .agents/skills/dsh-arch-diagram/harness-arch-en.html create mode 100644 .agents/skills/dsh-arch-diagram/harness-arch-zh.html create mode 100644 .agents/skills/dsh-arch-diagram/harness-arch.css create mode 100755 .agents/skills/dsh-arch-diagram/render.sh create mode 100644 assets/arch-en.png create mode 100644 assets/arch-zh.png create mode 100644 assets/community-wecom-survey.png create mode 100644 assets/demo-acp.mp4 diff --git a/.agents/skills/dsh-arch-diagram/SKILL.md b/.agents/skills/dsh-arch-diagram/SKILL.md new file mode 100644 index 0000000000..86306a3faf --- /dev/null +++ b/.agents/skills/dsh-arch-diagram/SKILL.md @@ -0,0 +1,158 @@ +--- +name: dsh-arch-diagram +description: Regenerate the DeepSeek Harness "System overview" architecture PNGs (English + Chinese) that the top-level README embeds. Reflects the current state of packages/* and docs/architecture.md. Use when the codebase adds/removes/renames services and the README diagram must be refreshed. +--- + +# dsh-arch-diagram + +Produces `assets/arch-en.png` and `assets/arch-zh.png` in this repo — the two hero images embedded at the top of `README.md` and `README.zh.md`. + +The pipeline is HTML + Chrome headless, so text quality, layout, and connector geometry are **deterministic** — every rerun produces the same output regardless of model. + +Aesthetic is locked to the DeepSeek brand: light blue gradient background, brand-blue Cordis bar, sans-serif everywhere, no serif / no italic / no hand-drawn feel. + +--- + +## When to use + +- User asks to "regenerate" or "refresh" the Harness architecture diagram +- User points out `packages/` has changed (new services, renames) and the README diagram is stale +- User just added a new `packages//` or a new `ctx.*` service and wants the diagram to reflect it + +## When NOT to use + +- User wants a different diagram (Code Mode, Workflow fanout, agent lifecycle) — those belong in `docs/` and need their own skill +- User wants a different visual aesthetic (dark mode, hand-drawn, editorial-serif) — this skill is locked to DeepSeek brand + +--- + +## Workflow + +### 1. Enumerate current services from the repo + +The diagram is grounded in two lists that live in the docs: + +- **Default Services** — from `packages/core/*` and `docs/architecture.md`'s "Default Services" table. As of last refresh: `ctx.sessions`, `ctx.systemPrompt`, `ctx.tools`, `ctx.agents`, `ctx.agentLoop`. +- **Capability Services** — from the non-core capability packages and `docs/architecture.md`'s "Capability Services" table. As of last refresh: `ctx.llm`, `ctx.bash`, `ctx.sandbox`, `ctx.codeRuntime`, `ctx.fs`, `ctx.skills`, `ctx.web`, `ctx.compact`, `ctx.subagents`, `ctx.workflows`, `ctx.sessionPersistence`, `ctx.sessionQuery`. + +**Do this**: + +1. Read `docs/architecture.md` +2. Extract the two `ctx.*` tables verbatim +3. Cross-check against `packages/`: services live under `packages/core/*` (defaults) or under `packages///` (capabilities). The inner package dir mirrors the npm name without the `@deepseek-ai/dsh-` prefix — e.g. `packages/session-query/session-query/` publishes `@deepseek-ai/dsh-session-query`. Never assume the inner dir carries a `dsh-` prefix. + +### 2. Diff against the current HTML templates + +Read `harness-arch-en.html` and `harness-arch-zh.html` in this skill directory. Pull out the currently-rendered `ctx.*` names. Report the diff: + +``` +Default services: no change +Capability services: + ctx., − ctx., ↻ ctx. +``` + +### 3. Update the templates + +If there are changes, edit both HTML files in place. Each card is one line: + +```html +
ctx.somethingshort description
+``` + +For a **new** service: +- Description is **short** — 2–4 words (EN), 3–6 chars (ZH) +- Ground the description in what the package's README or its `ctx..register()` **actually** does. Do NOT paraphrase from an abstract or invent capabilities the code doesn't have. +- Add the card in **both** languages, in docs order. + +For a **removed** service: delete the card in both files. + +For a **renamed** service: update the `.name` span in both files. + +**Do not touch the layout**. Rows are: +- Top row (`row top`): exactly 5 default-service cards +- Bottom row (`row bottom`): 12 capability-service cards + +If the capability count grows past ~13, the row gets visually tight. Stop and ask the user before shrinking fonts or wrapping to two rows. + +### 4. Render to PNG + +```bash +bash .agents/skills/dsh-arch-diagram/render.sh +``` + +Default output: `/assets/arch-en.png` and `/assets/arch-zh.png` — the paths that `README.md` and `README.zh.md` already reference. + +Pass an alternate directory as `$1` to write elsewhere. `CHROME` and `PORT` env vars override the browser path and http.server port. + +The script: +- Spins up a temporary `python3 -m http.server` on `127.0.0.1` (needed so Google Fonts CDN loads reliably in Chrome headless) +- Runs Chrome headless twice at `--force-device-scale-factor=2 --window-size=1536,580` +- Writes two 3072×1160 PNGs (~600 KB each) +- Tears down the server + +### 5. Verify by eye — mandatory, do not skip + +After rendering, **open each PNG and visually check every item** in this list. Do not report the diagram as done without going through it. + +- [ ] Top-row card count matches the Default Services list you extracted in §1, every name rendered in full (no truncation on the longest, e.g. `ctx.systemPrompt` / `ctx.agentLoop`) +- [ ] Bottom-row card count matches the Capability Services list you extracted in §1, every name in full (especially the longest, e.g. `ctx.sessionPersistence`) +- [ ] Every card has a description underneath, and the description matches what the code does (not made up) +- [ ] Bar reads `Cordis · microkernel (vendored)` (EN) / `Cordis · 微内核 (vendored)` (ZH) +- [ ] Number of vertical connector lines equals (top-row cards + bottom-row cards) from §1. All straight vertical, all parallel, each reaching the horizontal center of its card +- [ ] `cordis.yml` sidebar visible on the right; dashed arrow points left into the bar +- [ ] `deployment leaf` / `部署清单` and `picks which plugins load` / `决定哪些插件加载` are readable and NOT crossed through by any connector line +- [ ] Chinese descriptions render as CJK glyphs, not `□` tofu boxes (means fonts loaded) +- [ ] No large empty gradient area at the bottom of the image — if there is, tune `--window-size` in `render.sh` + +If any check fails: fix the CSS or template, re-run `render.sh`, re-check. Do not report "done" on first render without visually confirming. + +--- + +## Design system (locked — do not modify without explicit user request) + +Colors: +- Background: `linear-gradient(135deg, #ffffff 0%, #e8effc 100%)` +- Brand blue (Cordis bar + connectors): `#4a6ef5` +- Ink text: `#1a1a1a` +- Muted text: `#8a8f9c` +- Card border: `#dde3ef` +- Card fill: `#ffffff` + +Typography (**sans-serif only** — never serif, never italic): +- English title & body: **Inter** (Google Fonts) +- Chinese title & body: **Noto Sans SC** (Google Fonts) with `PingFang SC` local fallback +- Code labels (`ctx.*`, `cordis.yml`, `vendored`): **JetBrains Mono** (Google Fonts) + +Layout: +- `.page` max-width 1560 px, centered +- `.bus-row`, `.row.top`, `.row.bottom` all 96% width, centered +- Top row: `flex: 1` on each card (equal widths) +- Bottom row: `justify-content: space-between` + `flex: 0 0 auto` on each card — cards keep their intrinsic (nowrap) width and adjacent card backgrounds cannot clip a description +- Bus: `#4a6ef5` filled, 60 px tall, 8 px radius +- `cordis.yml` sidebar `position: absolute` at `left: calc(100% + 20px)` of `.bus-row`, width 130 px +- All connectors: CSS `::before` / `::after` pseudo-elements, 2 px wide, 40 px tall, `#4a6ef5`, centered via `left: 50%; transform: translateX(-50%)` — this is what guarantees pixel-perfect vertical parallel lines regardless of card content + +Rendering: +- Chrome headless `--force-device-scale-factor=2` +- `--window-size=1820,580` → output is 3640×1160 (aspect ~3.14:1, wider than square-ish so a 12-card capability row fits without truncation) +- Local http.server on `127.0.0.1` so CDN fonts load cleanly + +--- + +## Files in this skill + +- `SKILL.md` — this file +- `harness-arch.css` — shared design system (colors, fonts, layout, connectors) +- `harness-arch-en.html` — English template +- `harness-arch-zh.html` — Chinese template +- `render.sh` — Chrome headless renderer + +Templates are self-contained. Fonts load from Google Fonts CDN; no local font files. + +--- + +## Rules I keep breaking (and shouldn't) + +1. **Verify the output by looking at it.** Don't report "done" and move on — actually inspect each PNG and check every item in §5. +2. **Ground service descriptions in the code, not the docs' abstract, not the marketing copy.** If unsure what a package does, read its `src/` or the `ctx..register()` block. +3. **Don't touch layout unless asked.** 96% row/bar width, 40 px connector height, and 60 px bar height are all tuned. Card counts grow one at a time; once the bottom row starts to visibly overflow again (adjacent card backgrounds clipping a description, or the `cordis.yml` sidebar falling outside the render viewport), stop and ask before shrinking fonts, widening the viewport further, or wrapping to two rows. +4. **Never introduce a serif font or italic.** Not for titles, not for annotations, not "to make it feel editorial." This diagram is DeepSeek brand: sans-serif, upright, only. diff --git a/.agents/skills/dsh-arch-diagram/harness-arch-en.html b/.agents/skills/dsh-arch-diagram/harness-arch-en.html new file mode 100644 index 0000000000..117f606e97 --- /dev/null +++ b/.agents/skills/dsh-arch-diagram/harness-arch-en.html @@ -0,0 +1,66 @@ + + + + + + DeepSeek Harness · Architecture + + + +
+

ARCHITECTURE

+

System overview

+ +
+ + +
+
ctx.sessionsevent-sourced log
+
ctx.systemPromptprompt assembly
+
ctx.toolstool registry & pipeline
+
ctx.agentsagent handles & events
+
ctx.agentLoopReAct control loop
+
+ +
+
+ Cordis + · + microkernel + (vendored) +
+
+
+ + + + +
+
+
cordis.yml
+
deployment leaf
+
+
picks which plugins load
+
+
+ +
+
ctx.llmLLM provider adapter
+
ctx.bashshell execution
+
ctx.sandboxprocess confinement
+
ctx.codeRuntimeJS worker runtime
+
ctx.fsfilesystem + policy
+
ctx.skillsreusable skills
+
ctx.websearch & fetch
+
ctx.compactcontext compression
+
ctx.subagentsspawn / fork / ACP
+
ctx.workflowsdynamic orchestration
+
ctx.sessionPersistenceJSONL / SQLite
+
ctx.sessionQueryunified log reads
+
+ + +
+
+ + diff --git a/.agents/skills/dsh-arch-diagram/harness-arch-zh.html b/.agents/skills/dsh-arch-diagram/harness-arch-zh.html new file mode 100644 index 0000000000..ca2da1b4f1 --- /dev/null +++ b/.agents/skills/dsh-arch-diagram/harness-arch-zh.html @@ -0,0 +1,66 @@ + + + + + + DeepSeek Harness · 架构 + + + +
+

架 构

+

系统一览

+ +
+ + +
+
ctx.sessions事件溯源日志
+
ctx.systemPrompt系统提示词组装
+
ctx.tools工具注册与执行
+
ctx.agentsAgent 实例与事件
+
ctx.agentLoopReAct 控制循环
+
+ +
+
+ Cordis + · + 微内核 + (vendored) +
+
+
+ + + + +
+
+
cordis.yml
+
部署清单
+
+
决定哪些插件加载
+
+
+ +
+
ctx.llm模型适配层
+
ctx.bash命令行执行
+
ctx.sandbox进程隔离
+
ctx.codeRuntimeJS 运行时
+
ctx.fs文件读写
+
ctx.skills可复用技能
+
ctx.web网页搜索抓取
+
ctx.compact上下文压缩
+
ctx.subagents子智能体
+
ctx.workflows动态编排
+
ctx.sessionPersistence会话持久化
+
ctx.sessionQuery会话日志查询
+
+ + +
+
+ + diff --git a/.agents/skills/dsh-arch-diagram/harness-arch.css b/.agents/skills/dsh-arch-diagram/harness-arch.css new file mode 100644 index 0000000000..97ac526b8e --- /dev/null +++ b/.agents/skills/dsh-arch-diagram/harness-arch.css @@ -0,0 +1,220 @@ +/* DeepSeek brand — bone-white + brand-blue, all sans-serif, no italic, no serif. */ + +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap'); + +:root { + --bg-top: #ffffff; + --bg-bot: #e8effc; + --ink: #1a1a1a; + --muted: #8a8f9c; + --card-bd: #dde3ef; + --card-bg: #ffffff; + --brand: #4a6ef5; + --brand-soft: #dbe4fe; + + --sans: 'Inter', 'Noto Sans SC', 'PingFang SC', -apple-system, BlinkMacSystemFont, system-ui, sans-serif; + --cn: 'Noto Sans SC', 'PingFang SC', 'Inter', -apple-system, sans-serif; + --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace; +} + +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +body { + font-family: var(--sans); + color: var(--ink); + background: linear-gradient(135deg, var(--bg-top) 0%, var(--bg-bot) 100%); + padding: 40px 64px 32px; + -webkit-font-smoothing: antialiased; + font-feature-settings: "kern" 1, "liga" 1, "cv02" 1, "cv11" 1; +} + +.page { + max-width: 1560px; + margin: 0 auto; +} + +/* ── header ─────────────────────────────────────────── */ +.eyebrow { + font-family: var(--sans); + font-size: 12px; + font-weight: 500; + letter-spacing: 0.22em; + color: var(--muted); + text-transform: uppercase; + margin-bottom: 10px; +} +.eyebrow.cn { font-family: var(--cn); letter-spacing: 0.4em; text-transform: none; } + +h1 { + font-family: var(--sans); + font-size: 40px; + font-weight: 600; + letter-spacing: -0.02em; + line-height: 1.15; + color: var(--ink); + margin-bottom: 88px; +} +h1.cn { font-family: var(--cn); letter-spacing: 0.02em; font-weight: 600; } + +/* ── diagram frame ──────────────────────────────────── */ +.diagram { position: relative; } + +.section-label { + font-family: var(--sans); + font-size: 11px; + font-weight: 500; + letter-spacing: 0.22em; + color: var(--muted); + text-transform: uppercase; + text-align: center; + margin-bottom: 20px; +} +.section-label.cn { font-family: var(--cn); letter-spacing: 0.4em; text-transform: none; font-size: 12px; } +.section-label.bottom { margin: 20px 0 0; } + +/* ── card rows ──────────────────────────────────────── */ +.row { + display: flex; + gap: 12px; + justify-content: center; + width: 96%; + margin: 0 auto; + position: relative; +} +.row.top .card { flex: 1; } +.row.bottom { + gap: 0; + justify-content: space-between; +} +/* flex: 0 0 auto so cards keep their intrinsic (nowrap) width and + neighbouring card backgrounds cannot clip a description. */ +.row.bottom .card { flex: 0 0 auto; } + +.card { + background: var(--card-bg); + border: 1px solid var(--card-bd); + border-radius: 6px; + padding: 14px 10px; + text-align: center; + min-width: 0; + position: relative; +} +.card .name { + font-family: var(--mono); + font-size: 13px; + font-weight: 500; + color: var(--ink); + line-height: 1.2; + white-space: nowrap; + display: block; +} +.card .desc { + font-family: var(--sans); + font-size: 11px; + font-weight: 400; + color: var(--muted); + margin-top: 4px; + line-height: 1.3; + min-height: 28px; + white-space: nowrap; +} +.card .desc.cn { font-family: var(--cn); } +.row.bottom .card { padding: 10px 6px; } +.row.bottom .card .name { font-size: 10px; } +.row.bottom .card .desc { font-size: 9px; min-height: 22px; } +.row.bottom .card .desc.cn { font-size: 10px; } + +/* connectors — pure CSS, guaranteed vertical & parallel */ +.row.top .card::after, +.row.bottom .card::before { + content: ''; + position: absolute; + left: 50%; + transform: translateX(-50%); + width: 2px; + background: var(--brand); +} +.row.top .card::after { top: 100%; height: 40px; } +.row.bottom .card::before { bottom: 100%; height: 40px; } + +/* ── bus row (Cordis) ───────────────────────────────── */ +.bus-row { + position: relative; + width: 96%; + margin: 40px auto; +} +.bus { + height: 60px; + background: var(--brand); + color: #ffffff; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + font-family: var(--sans); + font-size: 18px; + font-weight: 500; + letter-spacing: 0.01em; +} +.bus .dot { padding: 0 12px; opacity: 0.75; } +.bus .vendored { + font-family: var(--mono); + font-size: 15px; + font-weight: 400; + opacity: 0.8; + margin-left: 8px; +} +.bus.cn .core { font-family: var(--cn); } + +/* ── cordis.yml side box (positioned outside bus width) ─ */ +.yml-side { + position: absolute; + left: calc(100% + 20px); + top: 50%; + transform: translateY(-50%); + width: 130px; + display: flex; + flex-direction: column; + align-items: flex-start; +} +.yml-arrow { + position: absolute; + left: -30px; + top: 50%; + transform: translateY(-50%); + width: 30px; + height: 12px; +} +.yml-arrow svg { display: block; } +.yml-box { + width: 100%; + background: var(--card-bg); + border: 1px solid var(--card-bd); + border-radius: 6px; + padding: 12px 10px; + text-align: center; +} +.yml-box .file { + font-family: var(--mono); + font-size: 13px; + font-weight: 500; + color: var(--ink); +} +.yml-box .sub { + font-family: var(--sans); + font-size: 10px; + color: var(--muted); + margin-top: 4px; + line-height: 1.3; +} +.yml-box .sub.cn { font-family: var(--cn); letter-spacing: 0.05em; } +.yml-note { + font-family: var(--sans); + font-size: 10px; + color: var(--muted); + margin-top: 10px; + width: 100%; + text-align: center; + line-height: 1.4; +} +.yml-note.cn { font-family: var(--cn); letter-spacing: 0.05em; } diff --git a/.agents/skills/dsh-arch-diagram/render.sh b/.agents/skills/dsh-arch-diagram/render.sh new file mode 100755 index 0000000000..781f79b9ef --- /dev/null +++ b/.agents/skills/dsh-arch-diagram/render.sh @@ -0,0 +1,97 @@ +#!/bin/bash +# render.sh — Chrome headless renderer for the DeepSeek Harness architecture diagram. +# +# Writes arch-en.png and arch-zh.png (3072×1160, ~600 KB each) to the given output +# directory. Default is /assets/, which is where the README image references +# resolve. +# +# Usage: +# bash render.sh # writes to /assets/ +# bash render.sh /some/other/dir # writes there instead +# +# Env overrides: +# CHROME=/path/to/Chrome # non-standard Chrome location +# PORT= # override the local http.server port + +set -e + +SKILL_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$SKILL_DIR/../../.." && pwd)" +OUT_DIR="${1:-$REPO_ROOT/assets}" +BIND_PORT="${PORT:-0}" # 0 → kernel picks a free port +SERVER_LOG="$(mktemp -t dsh-arch-diagram-server.XXXXXX.log)" + +# Locate a Chrome / Chromium binary. Honour $CHROME if set; otherwise probe +# common per-platform paths so `bash render.sh` works on macOS + Linux out +# of the box. +if [ -z "$CHROME" ]; then + for candidate in \ + "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \ + "/Applications/Chromium.app/Contents/MacOS/Chromium" \ + "$(command -v google-chrome 2>/dev/null || true)" \ + "$(command -v google-chrome-stable 2>/dev/null || true)" \ + "$(command -v chromium 2>/dev/null || true)" \ + "$(command -v chromium-browser 2>/dev/null || true)"; do + if [ -n "$candidate" ] && [ -x "$candidate" ]; then + CHROME="$candidate"; break + fi + done +fi + +if [ -z "$CHROME" ] || [ ! -x "$CHROME" ]; then + echo "No Chrome / Chromium binary found." >&2 + echo "Tried: macOS default, google-chrome, google-chrome-stable, chromium, chromium-browser." >&2 + echo "Set CHROME=/path/to/binary and rerun." >&2 + exit 1 +fi + +mkdir -p "$OUT_DIR" + +python3 -u -m http.server "$BIND_PORT" --bind 127.0.0.1 --directory "$SKILL_DIR" \ + >"$SERVER_LOG" 2>&1 & +SERVER_PID=$! +cleanup() { kill "$SERVER_PID" 2>/dev/null; rm -f "$SERVER_LOG"; } +trap cleanup EXIT INT TERM + +# Discover the actual bound port from Python's own startup line +# ("Serving HTTP on 127.0.0.1 port ..."). Works whether the kernel +# picked it or PORT was set explicitly; no external `lsof` needed. +PORT="" +for _ in $(seq 1 40); do + PORT=$(awk '/Serving HTTP on/ {print $6; exit}' "$SERVER_LOG" 2>/dev/null || true) + [ -n "$PORT" ] && break + # Bail early if the server died (e.g. explicit PORT already in use). + kill -0 "$SERVER_PID" 2>/dev/null || break + sleep 0.05 +done +if [ -z "$PORT" ]; then + echo "Failed to detect local server port. Server log:" >&2 + cat "$SERVER_LOG" >&2 || true + exit 1 +fi + +# Chrome/Chromium refuses to run as root without --no-sandbox. Rendering +# a local static HTML doc under a headless browser doesn't need Chrome's +# own sandbox, so passing the flag when EUID is 0 makes the script work +# in Codex/CI container environments that default to root. +CHROME_EXTRA_ARGS=() +if [ "$(id -u)" = "0" ]; then + CHROME_EXTRA_ARGS+=(--no-sandbox) +fi + +for lang in en zh; do + out="$OUT_DIR/arch-$lang.png" + "$CHROME" \ + "${CHROME_EXTRA_ARGS[@]}" \ + --headless=new \ + --disable-gpu \ + --hide-scrollbars \ + --force-device-scale-factor=2 \ + --window-size=1820,580 \ + --virtual-time-budget=8000 \ + --screenshot="$out" \ + "http://127.0.0.1:$PORT/harness-arch-$lang.html" \ + 2>/dev/null + size=$(du -h "$out" | awk '{print $1}') + echo "[$lang] wrote $out ($size)" +done diff --git a/README.i18n.yaml b/README.i18n.yaml index 790812344d..0a718b627d 100644 --- a/README.i18n.yaml +++ b/README.i18n.yaml @@ -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 -README.md: 53dd3896eb15800125673e7c44f7de02daca9376 -README.zh.md: ab826f62658248249ec18c57b35c0065c0f909d1 +README.md: 3380558e6c956cdc7f1b748b9ea8d3d455f781db +README.zh.md: 9f415af0a6582c455fdb8e8bb5400dd28b42a161 diff --git a/README.md b/README.md index 53dd3896eb..3380558e6c 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,240 @@ -# DeepSeek Harness + + +
+ + +

DeepSeek Harness

+ +**The plugin-first agent SDK. Every capability — including the loop — is a plugin.** + +

+ license + node + pnpm + typescript + ACP + Discord + X +

English | [中文](README.zh.md) -The **DeepSeek Harness SDK** is a plugin-based SDK for building agent harnesses. + +[Docs](https://deepseek.com/harness-sdk/docs)  ·  [Landing page](https://deepseek.com/harness-sdk)  ·  [Community](#community) -## Development +
-This monorepo is built on the [Cordis](https://github.com/cordiverse/cordis) framework (vendored as source under `vendor/`), microkernel-style: everything is a plugin. +
+ +

+ DeepSeek Harness — System overview +

+ +## What is this? + +DeepSeek Harness is a TypeScript SDK for building AI agents on top of the [Cordis](https://github.com/cordiverse/cordis) microkernel. **Every service, including the ReAct loop, is a plugin registered through `ctx.*`.** A batteries-included service registry ships in the box — LLM adapters, sandboxed execution, filesystem with policy, web search, sub-agents, dynamic workflows, session persistence, and more — and a `cordis.yml` at your project root chooses which get loaded. You can replace any of them, add your own, or leave the shipped defaults alone. + +## Getting started + +**New project** (one-command scaffold): ```sh -pnpm install -pnpm run test # vitest -pnpm run demo:repl # REPL agent demo (needs DEEPSEEK_API_KEY) -pnpm run demo:acp # ACP server agent demo (needs DEEPSEEK_API_KEY) +npm create @deepseek-ai/harness # coming soon, not yet on npm ``` -For humans, start with the [development guide](docs/development.md) for local setup, hooks, environment variables, and quality gates, then read the [architecture design](docs/architecture.md) and [documentation graph index](docs/graph-atlas.md) before package work. Local context lives in [packages/](packages/) and [vendor/](vendor/). +**From source** (read the code / run demos / contribute): -For agents, follow [AGENTS.md](AGENTS.md). +```sh +git clone https://github.com/deepseek-harness/deepseek-harness.git +cd deepseek-harness +pnpm install +export DEEPSEEK_API_KEY=sk-... # optional — omit and use pnpm run demo:echo (mock, no key) +pnpm run demo:repl +``` + +Requires **Node `^22.19 || ≥24`** and **pnpm ≥ 11.7** (Node engine and pnpm pinned in `package.json`; `corepack enable` picks up the exact pnpm version). Node 23 is not on the support matrix. + +**Heads up:** `demo:repl` runs real `read` / `write` / `edit` file tools and `bash` in your current working directory — best run from a scratch dir or a git-clean project so you can review the changes. + +## Use it in your editor + +Harness ships an [Agent Client Protocol (ACP)](https://agentclientprotocol.com) server. ACP lets an editor drive an agent from its sidebar; [Zed](https://zed.dev) supports it natively. + +The ACP server command (from your local clone): + +```sh +pnpm run demo:acp +``` + +Zed side — Zed's `settings.json` (Cmd-Shift-P → "zed: open settings") takes an `agent_servers` entry: + +```json +{ + "agent_servers": { + "DeepSeek Harness": { + "command": "pnpm", + "args": ["--dir", "/path/to/deepseek-harness", "run", "demo:acp"], + "env": { "DEEPSEEK_API_KEY": "sk-..." } + } + } +} +``` + +`--dir` points at your local clone. Zed launches the agent as a subprocess; each Zed session maps to its own agent instance, with chat in the sidebar and tool calls (arguments, results, file diffs) rendered inline in the editor. Configuration details in [`examples/acp-agent`](./examples/acp-agent) (including the snapshot-tested surface). + +**VS Code / Cursor** — install an ACP client extension for either editor, such as [ACP Client](https://marketplace.visualstudio.com/items?itemName=formulahendry.acp-client) (`formulahendry.acp-client`) or [ACP Pro](https://marketplace.visualstudio.com/items?itemName=duclvz.acp-pro) (`duclvz.acp-pro`), and point a custom agent at `pnpm run demo:acp`. + +**Other ACP clients** — same launch. Feature-by-feature support matrix in [`packages/ui/acp/acp-feature-support.md`](./packages/ui/acp/acp-feature-support.md). + +## Embed it in your own app + +Harness bootstraps from a `cordis.yml` via [`@deepseek-ai/dsh-app-boot`](./packages/ui/app-boot). For library-style integration into your own Node.js service, the same boot helpers apply: + +```ts +// my-app.ts +import { + boot, + installFailLoud, + loadEnv, + resolveConfigPath, +} from '@deepseek-ai/dsh-app-boot' + +installFailLoud('my-app') +loadEnv('my-app') + +const ctx = await boot('my-app', resolveConfigPath('./cordis.yml', undefined)) +// ctx is the Cordis root Context; every service you mount in cordis.yml +// is reachable via ctx.* (ctx.agents, ctx.sessions, ctx.tools, …). +// The app plugins loaded from cordis.yml keep the process alive on their own +// (stdio agents hold stdin; the ACP agent holds an RPC connection). +// To shut down programmatically, call `await ctx.fiber.dispose()`. +``` + +`boot()` returns once the whole plugin tree has settled. Two separate failure paths: a module-import failure rejects the `boot()` Promise directly, so the caller's `await` throws — handle it with `try/catch`. `installFailLoud` covers a different case — a late plugin-init rejection surfacing *after* `boot()` has already resolved, which would otherwise become an unhandled rejection and die silently. In `cordis.yml`, the entry-point app plugin — `dsh-stdio-agent` for a REPL, `dsh-acp-agent` for an ACP server, or a custom one — sits alongside whichever services should load. Full helper surface: [`packages/ui/app-boot`](./packages/ui/app-boot). + +For end-to-end examples, see [`examples/`](./examples): + +- [`echo-agent`](./examples/echo-agent) — a minimal setup with a mock LLM and an echo tool +- [`coding-agent`](./examples/coding-agent) — a full coding agent wired to the real DeepSeek LLM +- [`acp-agent`](./examples/acp-agent) — ACP server, with a sandbox composition variant + +## Demo + +Harness driving Zed as an ACP agent — chat in the sidebar, tool calls (bash, file edits, diffs) rendered inline in the editor: + +

+ +

+ + + +## Write a plugin + +A Harness function/namespace plugin exports `name`, `inject`, and `apply` — cordis's Loader reads those separately. **`export default` breaks this shape** ([why](./docs/postmortem/0001-acp-default-export-drops-inject.md)): the Loader keeps only the `apply` function and silently drops `inject` / `name`, so the plugin fails to load with `cannot get property … without inject`. Inside `apply(ctx)`, tools / LLM adapters / services register through `ctx.*`. + +The minimal echo tool from [`examples/echo-agent`](./examples/echo-agent): + +```ts +// echo-tool.ts +import type { Context } from 'cordis' +import { defineTool } from '@deepseek-ai/dsh-tools' + +export const name = 'echo-tool' +export const inject = ['tools'] + +export function apply(ctx: Context) { + ctx.tools.register(defineTool({ + name: 'echo', + description: 'Echo the given text back, uppercased.', + parameters: { + text: { type: 'string', required: true }, + }, + async execute(args) { + // args is typed: { text: string } + return [{ type: 'text', text: `ECHO: ${args.text.toUpperCase()}` }] + }, + })) +} +``` + +`parameters` uses the [schemastery](./vendor/schemastery) JSON-Schema-shaped DSL — one field per property, with `required: true` for mandatory ones. A leaf `cordis.yml` is a flat `EntryOptions[]` the Loader iterates; this tool's entry looks like: + +```yaml +- id: echo-tool + name: './echo-tool.ts' # your tool +``` + +Alongside it, a bootable config also needs an LLM adapter and a `stdio-agent` app entry whose `config.model` points at an id that adapter registers. The minimal runnable version — mock LLM + this echo tool + a `stdio-agent` entry wired to `mock-echo` — is [`examples/echo-agent`](./examples/echo-agent), launched via: + +```sh +pnpm run demo:echo +``` + +LLM-adapter and UI-plugin shapes: [`docs/cookbook/extension-cookbook.md`](./docs/cookbook/extension-cookbook.md). + +## Packages + +All packages ship under the `@deepseek-ai/dsh-*` scope. Grouped by family: + +| Family | What lives here | +|---|---| +| **Core** (`packages/core/`) | `dsh-scope` · `dsh-session` · `dsh-tools` · `dsh-agent` · `dsh-agent-loop` · `dsh-system-prompt` | +| **LLM** (`packages/llm/`) | `dsh-llm` (the seam) + `dsh-llm-deepseek` (hand-rolled) and `dsh-llm-pi-ai` (library-backed twin — same DeepSeek endpoint, different internals, kept for design verification) | +| **Bash** (`packages/bash/`) | Shell execution: local + sandboxed backends, model-facing `bash` tool | +| **Filesystem** (`packages/fs/`) | Filesystem service with a policy layer, `read` / `write` / `edit` tools | +| **Web** (`packages/web/`) | Web search (Perplexity, Exa, DeepSeek) + fetch, model-facing tool | +| **Sandbox** (`packages/sandbox/`) | Process-confinement seam (bwrap / Landlock / Seatbelt) — wraps a caller's argv under a per-call policy; execution itself lives in `ctx.bash` | +| **Code runtime** (`packages/code-runtime/`) | JS worker runtime that Code Mode dispatches into | +| **Sub-agents** (`packages/subagent/`) | `spawn`, `fork`, plus in-process / subprocess / ACP-backed backends | +| **Workflows** (`packages/workflow/`) | Dynamic workflow orchestration (worker-thread execution) | +| **Skills** (`packages/skill/`) | Skill-provider registry (`ctx.skills`) + a local-filesystem provider | +| **Session persistence** (`packages/session-persistence/`) | Event-log persistence: JSONL and SQLite backends | +| **Session query** (`packages/session-query/`) | `ctx.sessionQuery` — unified logical-corpus reads over live sessions + persistence | +| **Compact** (`packages/compact/`) | Context compression / summarization | +| **Context** (`packages/context/`) | Opt-in request-context enrichment (e.g. `dsh-time-context` — dynamic time-in-prompt) | +| **Cordis toolset** (`packages/cordis/`) | Model-facing tools that inspect / mount / unmount cordis plugins at runtime | +| **UI apps** (`packages/ui/`) | `dsh-stdio-agent` (REPL) · `dsh-acp-agent` (ACP server) · `dsh-app-boot` · approval + ask-user primitives | +| **Hooks** (`packages/hooks/`) | Hook protocol + Claude Code / OpenAI Codex hook-config bridges | +| **Guards** (`packages/guard/`) | Advisory loop-hygiene plugins (e.g. `repeat-tool-guard` for repeated-call escalation) | +| **Timeouts** (`packages/timeout/`) | `timeout-policy` — a zero-config `tools/execute` wrapper enforcing per-tool `timeoutMs` | +| **Todo** (`packages/todo/`) | The model-facing `todo_write` tool (whole-list task tracker) | +| **Support** (`packages/support/`) | `invariants` — runtime diagnostic plugin mounted unconditionally by the shipped `dsh-agent-spine-demo` bundle; plus test/dev-only helpers (`llm-replay`, `acp-snapshot`, `subagent-mock`) | +| **Example bundles** (`packages/examples/`) | Ready-to-run demo compositions the top-level `demo:*` scripts launch: `dsh-agent-spine-demo` (default spine + capabilities), `dsh-stdio-demo` (REPL), `dsh-acp-demo` (ACP server), `dsh-jsonrpc-demo` | +| **Utils** (`packages/util/`) | Internal utility packages (`brand`, `timeout`) | + +For the full module dependency graph, see [`docs/module-graph.md`](./docs/module-graph.md). + +## Deep dives + +To understand what makes DeepSeek Harness different, start here: + +- [Architecture](./docs/architecture.md) — the service taxonomy and the microkernel structure +- [Agent lifecycle](./docs/agent-lifecycle.md) — how a turn flows through the loop, with sequence diagrams +- [Cordis primer](./docs/cordis-primer.md) — a working introduction to the underlying plugin framework +- [Tool execution pipeline](./docs/tool-execution-pipeline.md) — how a tool call passes through permission gates, hooks, and logging +- [Capability seams](./docs/capability-seams.md) — the extension points each service exposes +- [Code Mode](./docs/rfc/implemented/feature/2026-06-15-code-mode.md) — the model writes one JavaScript program per turn that chains many bash / tool calls, executed in a single runtime pass. **One model round-trip per multi-step operation**, not one per call. +- [Dynamic Workflows](./docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md) — the model writes a plain-JS orchestrator that fans out sub-agents in parallel, joins their results, and returns to the parent — instead of a chain of sub-agent tool calls. +- [Self-referential Cordis toolset](./docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md) — the SDK's own plumbing (`cordis_inspect`, `cordis_mount`, `cordis_unmount`) is exposed as tools, so the model can inspect its own runtime and load new plugins on the fly. + +Docs site: **[deepseek.com/harness-sdk/docs](https://deepseek.com/harness-sdk/docs)**. + +## Community + + + +- **[GitHub Issues](https://github.com/deepseek-harness/deepseek-harness/issues)** — bug reports +- **[GitHub Discussions](https://github.com/deepseek-harness/deepseek-harness/discussions)** — questions, ideas, RFCs + +Real-time chat on Discord. Release announcements on X / Twitter. + +## License + +[BSD 3-Clause](./LICENSE) © DeepSeek diff --git a/README.zh.md b/README.zh.md index ab826f6265..9f415af0a6 100644 --- a/README.zh.md +++ b/README.zh.md @@ -1,20 +1,240 @@ -# DeepSeek Harness + + +
+ + +

DeepSeek Harness

+ +**插件优先的 agent(智能体) SDK。每一项能力 — 包括 loop 本身 — 都是插件。** + +

+ license + node + pnpm + typescript + ACP +

[English](README.md) | 中文 -**DeepSeek Harness SDK** 是用于构建 agent harness(智能体框架)的 SDK,采取基于插件的设计。 + +[文档](https://deepseek.com/harness-sdk/docs)  ·  [Landing page](https://deepseek.com/harness-sdk)  ·  [社群](#community) -## 开发 +
-本 monorepo 基于 [Cordis](https://github.com/cordiverse/cordis) 框架构建(以源码形式收录在 `vendor/` 下),采用微内核风格:所有功能都以插件形式提供。 +
+ +

+ DeepSeek Harness · 系统一览 +

+ +## 这是什么? + +DeepSeek Harness 是一个用 TypeScript 写的 AI agent SDK,构建在 [Cordis](https://github.com/cordiverse/cordis) 微内核之上。**所有服务,包括默认的 ReAct loop,都是通过 `ctx.*` 注册的插件。** 仓库里带了一整套开箱即用的服务 —— LLM 适配、沙盒执行、带策略的文件读写、网页搜索、子 agent、动态工作流、会话持久化等 —— 由项目根目录下的 `cordis.yml` 决定加载哪些。你可以替换任何一项、加装自己的,或者保留默认。 + +## 上手 + +**新起一个项目**(一条命令生成脚手架): ```sh -pnpm install -pnpm run test # vitest -pnpm run demo:repl # REPL agent demo (needs DEEPSEEK_API_KEY) -pnpm run demo:acp # ACP server agent demo (needs DEEPSEEK_API_KEY) +npm create @deepseek-ai/harness # coming soon, not yet on npm ``` -面向开发者:先读[开发指南](docs/development.md),了解本地环境搭建、钩子、环境变量与质量门禁,动手改 package 之前再读[架构设计](docs/architecture.md)和[文档关系图索引](docs/graph-atlas.md)。局部上下文见 [packages/](packages/) 与 [vendor/](vendor/)。 +**克隆仓库**(读代码 / 跑 demo / 贡献代码): -面向 agent:遵循 [AGENTS.md](AGENTS.md)。 +```sh +git clone https://github.com/deepseek-harness/deepseek-harness.git +cd deepseek-harness +pnpm install +export DEEPSEEK_API_KEY=sk-... # optional — omit and use pnpm run demo:echo (mock, no key) +pnpm run demo:repl +``` + +需要 **Node `^22.19 || ≥24`** 和 **pnpm ≥ 11.7**(Node 引擎与 pnpm 版本由 `package.json` 的 `engines` / `packageManager` 字段锁定;`corepack enable` 会自动装对 pnpm 版本)。Node 23 不在支持范围内。 + +**注意:** `demo:repl` 会用真实的 `read` / `write` / `edit` 文件工具和 `bash` 操作**当前工作目录**,最好在空目录或干净的 git 项目里运行,方便随时 review 改动。 + +## 接入编辑器 + +Harness 内置了一个 [Agent Client Protocol (ACP)](https://agentclientprotocol.com) server。ACP 是一个把 agent 挂到编辑器边栏作为后端的协议;[Zed](https://zed.dev) 目前原生支持。 + +ACP server 的启动命令(在 clone 的仓库根目录下): + +```sh +pnpm run demo:acp +``` + +Zed 端 —— 在 Zed 的 `settings.json`(Cmd-Shift-P → "zed: open settings")里加上 `agent_servers` 一节: + +```json +{ + "agent_servers": { + "DeepSeek Harness": { + "command": "pnpm", + "args": ["--dir", "/path/to/deepseek-harness", "run", "demo:acp"], + "env": { "DEEPSEEK_API_KEY": "sk-..." } + } + } +} +``` + +`--dir` 指向本地仓库路径。Zed 把 agent 作为子进程拉起,每个 Zed session 对应一个独立的 agent 实例;编辑器边栏可以直接对话,tool 调用(参数、结果、文件 diff)内联渲染到编辑区。完整配置说明见 [`examples/acp-agent`](./examples/acp-agent)。 + +**VS Code / Cursor** —— 两个编辑器都可以装 ACP 客户端插件,比如 [ACP Client](https://marketplace.visualstudio.com/items?itemName=formulahendry.acp-client)(`formulahendry.acp-client`)或 [ACP Pro](https://marketplace.visualstudio.com/items?itemName=duclvz.acp-pro)(`duclvz.acp-pro`),把 `pnpm run demo:acp` 配成自定义 agent 即可接入。 + +**其他 ACP 客户端** —— 接入方式相同。支持哪些 ACP 特性见 [`packages/ui/acp/acp-feature-support.md`](./packages/ui/acp/acp-feature-support.md)。 + +## 嵌入自己的应用 + +Harness 是通过 [`@deepseek-ai/dsh-app-boot`](./packages/ui/app-boot) 从一份 `cordis.yml` 引导起来的。如果希望在个人 Node.js 服务里以库的形式集成,可以用同样的引导方式: + +```ts +// my-app.ts +import { + boot, + installFailLoud, + loadEnv, + resolveConfigPath, +} from '@deepseek-ai/dsh-app-boot' + +installFailLoud('my-app') +loadEnv('my-app') + +const ctx = await boot('my-app', resolveConfigPath('./cordis.yml', undefined)) +// ctx is the Cordis root Context; every service you mount in cordis.yml +// is reachable via ctx.* (ctx.agents, ctx.sessions, ctx.tools, …). +// The app plugins loaded from cordis.yml keep the process alive on their own +// (stdio agents hold stdin; the ACP agent holds an RPC connection). +// To shut down programmatically, call `await ctx.fiber.dispose()`. +``` + +`boot()` 会在整棵插件树 settle 完之后返回。两条失败路径要分开处理:模块导入失败会直接 reject `boot()` 的 Promise,`await` 处会抛出,调用方用 `try/catch` 接住即可。`installFailLoud` 负责的是另一件事 —— `boot()` 返回之后才浮出来的 late plugin-init rejection,如果不接就会变成无人处理的 unhandled rejection 静默死掉。`cordis.yml` 里的 app 插件入口 —— `dsh-stdio-agent`(REPL)、`dsh-acp-agent`(ACP server)或自定义 —— 搭配想加载的服务。完整的 helper 表见 [`packages/ui/app-boot`](./packages/ui/app-boot)。 + +完整的组合示例见 [`examples/`](./examples): + +- [`echo-agent`](./examples/echo-agent) —— mock LLM + echo tool 的最小示例 +- [`coding-agent`](./examples/coding-agent) —— 接真实 DeepSeek LLM 的完整 coding agent +- [`acp-agent`](./examples/acp-agent) —— ACP server,含一个沙盒 composition variant + +## 演示 + +Harness 作为 ACP agent 挂在 Zed 里 —— 边栏对话,工具调用(bash、文件编辑、diff)内联渲染在编辑区: + +

+ +

+ + + +## 编写插件 + +Harness 的 function/namespace 插件通过分开的 `name` / `inject` / `apply` 命名导出注册,cordis Loader 读的是这些字段。**`export default` 不适用于这种形态** —— Loader 只会拿到 `apply` 函数,`inject` / `name` 被静默丢掉,加载时报 `cannot get property … without inject`(详见 [postmortem 0001](./docs/postmortem/0001-acp-default-export-drops-inject.md))。`apply(ctx)` 内通过 `ctx.*` 注册 tool、挂载 LLM adapter 或暴露 service。 + +下面这个是 [`examples/echo-agent`](./examples/echo-agent) 里的真实 echo tool 插件: + +```ts +// echo-tool.ts +import type { Context } from 'cordis' +import { defineTool } from '@deepseek-ai/dsh-tools' + +export const name = 'echo-tool' +export const inject = ['tools'] + +export function apply(ctx: Context) { + ctx.tools.register(defineTool({ + name: 'echo', + description: 'Echo the given text back, uppercased.', + parameters: { + text: { type: 'string', required: true }, + }, + async execute(args) { + // args is typed: { text: string } + return [{ type: 'text', text: `ECHO: ${args.text.toUpperCase()}` }] + }, + })) +} +``` + +`parameters` 是 [schemastery](./vendor/schemastery) 的 JSON-Schema 风格 DSL —— 每个字段一项定义,`required: true` 标记必填。leaf `cordis.yml` 是 Loader 迭代的一个 flat `EntryOptions[]`,这个工具的条目长这样: + +```yaml +- id: echo-tool + name: './echo-tool.ts' # your tool +``` + +同一份配置里还要有 LLM adapter 和一个 `stdio-agent` app 条目,`config.model` 指向 adapter 里注册的某个 model id。最小可跑组合 —— mock LLM + 这个 echo tool + 接到 `mock-echo` 的 `stdio-agent` —— 见 [`examples/echo-agent`](./examples/echo-agent),运行命令: + +```sh +pnpm run demo:echo +``` + +LLM adapter 与 UI 插件的写法见 [`docs/cookbook/extension-cookbook.md`](./docs/cookbook/extension-cookbook.md)。 + +## Packages + +所有包都在 `@deepseek-ai/dsh-*` scope 下,按目录分组: + +| 分组 | 包含 | +|---|---| +| **Core**(`packages/core/`)| `dsh-scope` · `dsh-session` · `dsh-tools` · `dsh-agent` · `dsh-agent-loop` · `dsh-system-prompt` | +| **LLM**(`packages/llm/`)| `dsh-llm`(seam)+ `dsh-llm-deepseek`(手写实现)与 `dsh-llm-pi-ai`(第三方库实现的孪生 —— 打同一个 DeepSeek endpoint,内部走不同代码路径,用于设计验证)| +| **Bash**(`packages/bash/`)| 命令行执行:本地 + 沙盒后端,模型可调用的 `bash` tool | +| **Filesystem**(`packages/fs/`)| 带策略层的文件服务,`read` / `write` / `edit` tools | +| **Web**(`packages/web/`)| 网页搜索(Perplexity、Exa、DeepSeek)+ fetch,模型可调用的 tool | +| **Sandbox**(`packages/sandbox/`)| 进程隔离接缝(bwrap / Landlock / Seatbelt)—— 按每次调用的策略包一层 argv,真正的执行由 `ctx.bash` 负责 | +| **Code runtime**(`packages/code-runtime/`)| Code Mode 分发进入的 JS worker 运行时 | +| **Sub-agents**(`packages/subagent/`)| `spawn` / `fork`,以及进程内 / 子进程 / ACP 后端 | +| **Workflows**(`packages/workflow/`)| 动态工作流编排(worker 线程执行)| +| **Skills**(`packages/skill/`)| Skill provider 注册中心(`ctx.skills`)+ 本地文件系统 provider | +| **Session persistence**(`packages/session-persistence/`)| 事件日志持久化:JSONL 与 SQLite 后端 | +| **Session query**(`packages/session-query/`)| `ctx.sessionQuery` —— 把 live sessions 和持久化层合成同一份逻辑语料的统一查询 | +| **Compact**(`packages/compact/`)| 上下文压缩 / 摘要 | +| **Context**(`packages/context/`)| 可选的请求上下文增强(如 `dsh-time-context` —— 系统提示词里注入动态时间)| +| **Cordis toolset**(`packages/cordis/`)| 模型可调用的、在运行时查看 / 挂载 / 卸载 cordis 插件的 tools | +| **UI apps**(`packages/ui/`)| `dsh-stdio-agent`(REPL)· `dsh-acp-agent`(ACP server)· `dsh-app-boot` · approval / ask-user 基础件 | +| **Hooks**(`packages/hooks/`)| Hook 协议 + Claude Code / OpenAI Codex 的 hook 配置桥 | +| **Guards**(`packages/guard/`)| 建议性的 loop 健康插件(如 `repeat-tool-guard` —— 检测同一 tool 重复调用并升级 advisory)| +| **Timeouts**(`packages/timeout/`)| `timeout-policy` —— 零配置的 `tools/execute` 包装,按 tool 声明的 `timeoutMs` 强制超时 | +| **Todo**(`packages/todo/`)| 模型可调用的 `todo_write` tool(整表任务追踪)| +| **Support**(`packages/support/`)| `invariants` —— 由默认组合 `dsh-agent-spine-demo` 无条件挂载的运行时诊断插件;此外是仅测试/开发用的辅助包(`llm-replay`、`acp-snapshot`、`subagent-mock`)| +| **Example bundles**(`packages/examples/`)| 顶层 `demo:*` 脚本直接跑的组合示例包:`dsh-agent-spine-demo`(默认 spine + 能力)、`dsh-stdio-demo`(REPL)、`dsh-acp-demo`(ACP server)、`dsh-jsonrpc-demo` | +| **Utils**(`packages/util/`)| 内部工具包(`brand`、`timeout`)| + +完整的模块依赖图见 [`docs/module-graph.md`](./docs/module-graph.md)。 + +## 深入阅读 + +想理解 DeepSeek Harness 为什么与众不同,从这里入手: + +- [架构](./docs/architecture.md) —— 服务分类和微内核结构 +- [agent 生命周期](./docs/agent-lifecycle.md) —— 一次 turn 在 loop 里的流转(含时序图) +- [Cordis 入门](./docs/cordis-primer.md) —— 底层插件框架的实用入门 +- [工具执行流水线](./docs/tool-execution-pipeline.md) —— 一次 tool 调用如何经过权限校验、hooks 和日志 +- [能力接缝](./docs/capability-seams.md) —— 每个服务暴露的替换点 +- [Code Mode](./docs/rfc/implemented/feature/2026-06-15-code-mode.md) —— 模型每个 turn 写一段 JS 程序,在一次运行里串起多次 bash / tool 调用。**多步操作 → 一次模型往返**,不是每次调用一次往返 +- [动态工作流](./docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md) —— 模型写一段 JS orchestrator,把多个 sub-agent 并行 fan out、合并结果、再回到父 agent —— 而不是链式地调 subagent tool +- [自引用的 Cordis 工具集](./docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md) —— SDK 自身的插件管理机制(`cordis_inspect` / `cordis_mount` / `cordis_unmount`)以 tool 的形式暴露给模型,让模型能在运行时查看当前运行时并按需挂载新插件 + +文档站:**[deepseek.com/harness-sdk/docs](https://deepseek.com/harness-sdk/docs)**。 + +## 社群 + + + +- **[GitHub Issues](https://github.com/deepseek-harness/deepseek-harness/issues)** —— Bug 反馈 +- **[GitHub Discussions](https://github.com/deepseek-harness/deepseek-harness/discussions)** —— 功能建议、设计讨论、Q&A + +企业微信讨论群通过腾讯问卷申请入群,专人筛选后邀请: + +腾讯问卷 · 企业微信社群入群申请 + +## License + +[BSD 3-Clause](./LICENSE) © DeepSeek diff --git a/assets/arch-en.png b/assets/arch-en.png new file mode 100644 index 0000000000000000000000000000000000000000..4a84c5e590a4b219a9a2cfdf343f1bc8eba839fe GIT binary patch literal 681579 zcmeFZdr*@5-}k%hq@`)5rIumlTA67IQh5ShElXEFO)D!kO;S>qX_=7;%E8J*DM@82 zmclAavxCR-l!Au@6_m>IkOrO*4HX0x5XI-}{_T5a@0mUOkG=0_?q|=l{$j?_YrevD zeR+Rg@AvzA=eU>q#tqvx{PN2$8;|~Z_~b9YXxsnt%bMF7tAL+8HYl_B<(Eyr96fyK z6gqDzZ}`#cmtB{6Q-Z;jeFE&hzttXW(tmfcq=Ph7?)K^X^TQucbuO=vjm|Dnckk8u zIGo#|`IYSByd1_e;9_kB*e=}_?-)l58oldkvlU4K!t$=Zq@ifzbW<}z)=Ejv{W!lK z`iPy+IWrPE*WG!?b;&vSVeIYDDp*H?bQxz=$#=0szDh-@)_Ki`E_Sv-(&Fr+|0wiM zZ-ux?_w;6n49Z^H4HGcI*^%jd5i%6#k?;pS<0!&!QD{}l>|w!#qz1-3wZ%3-r4)9y z50<*DEYTF7@peP3-uyw)Me60dLP&T+Rdf|?3Q@(oT!@1Esa|B>E=6y*6}!;dLWLTr zm+N?OfeVK?Im?kl0(-=v5}R1oWc(+b|7F&J`NHt>r2tyK@HT?ny|+j{S16qWRsWd| z@93nBzNe+mv{v-WU%k$^d>krjmQY)o@E(rY!2f^g!8+Am*4dX0^~c}GJJpofeJ?$a zS=lW-7Uu6ko#J&daJ!di%+5g@?DXay7&P1I=<_&;&?%b}n7z^`cpu#!k&PpmsG~}5 z{ALwdvk=4^-KXu$^Y`yr2%ii1wykWbuI}oOV?B-M=EEx4*(-4s<-G5>9r=TL)jY8H zW@vW9{qe7`-tVgu=VUQiE^#JF=~ge=y-_=*a`9a`#mH{^$ETQvRZ z0}tv4sdkY7)zU%$D;$YPxiDp*Bqx{2IbmxZ1KS0m;qW5Lt4YrVc->s`Ui}pCjdSa#oZRPH=xo*-}uoUtkm^`u( zO?#92N_E~Sdqw8z^^9*Lz95YHFc5u)Vs|7P`6#bhCM&n9=wQi3TSo#11FKeN_e(n8 zRtFIViS7C^Osp*@S!ipfCl*d^q9mp3_vppNLk;WkhJp07iKjJ0#P& zU#vXif6hFv{LFSwKUt-e(DC z%(ifj+{S~)Yy}?6$C+0-YoZdm8{PduY5eak%Z2gEBWdkIubI$nde=D30)^3eW25Kt zUZ<-k9Tz+hP>U_XttN}S8-{SeQDA7jfDzk~WXjAir z{mfnA^=5QfaZ6YHmmPBQ6Ft7&b=FvXr`mD5-0?AG4w6Ohh>E{Rj@20sR;1@$Y>@@K zHJZCMT6(I{dmj(`qh}h<2QkOcdys#b^pncrYnQ6D^;dTzWeL+8;l>2;DrfSO_!8KH z6vL_Scm1tI zQNe;$5EvV#EkD1TS!r81?<{Tffx1ZtF5RC#YSg_LNsP_&`t5|B+Lw$^&{fWCV=?B9 z82$~?dPP(`dmPpZU!}4?t*kbJ*?6t@fv;ovjdwxQfBPT~#O$YRAsu`S()D)b+_hT- zWw}s{+@0GFzi|BZkqLBF5HbzY1v%xNt^S4j1{UIctX6bC9XS<@@pJxQEDn9sM_wDi z6?_gBFCE#<$rOK4(&#bfW?v~nb?lsV6au`-dy6|STKJI za}qasQybf9AFnT{pNMUgod%)T)YlB3=dZh+4N=F2aC1F5uDrSZ7rjZ~we=IxX#7Uk z*-d!17}iWo&f8lhH5R)s6S3{9z16%w`;0!3gMAuB%ibKH17TgF`7rcrW|&=0bYk($lTSdP|#XW_Z$IB&v-`{%7- zc9dfvy~%*$(Iy5?H0TA&X8kZN8ZvuOX9~DilewinL;JL*~)}GrCL(&DRq~PRrgu=ea2C<8zqgdnEqb1B;-Mo&omc1XfhZwu$OPP&?!Gg1!W73toI_ z+pD-XtG~OCHYQ0EAeUqXW;{wg#^!8{w;a2tMCMJ>VnsHE9C(XG6lc>dN}UD~d3VuI z{Ob8{pI>N*!yg@1zq)}ZOWwmgHEa2SlTJFvd@2l>%p~eet=5ru+>uXh+(|RW`!_V8 z99?Wi^rB`z-^o!H@Re}uI%?q!nrNja_PwKjH2sR%$=kwZRlYg1w{i;e=EZY^dIHmO zsM;kP7vfLLc3){~32@$VSMUxhvspO3TM3el&-LPXCdqudnfpOQmTY?ppA!YMlfSNP zhYv6W$W1u#HOP z$1K&FCYRXt@*euIy_8O~Tg>NZ>kW@-i3XJFREnZyv2`FgFzzbhVRzv4V;rwVY!`|m z3^q%;*DhKPDhm*$R(SLdDXVCaa4L)H^}S^fy_FIU_w`hxlDi;lu_L1|t8l?lWnoNPfWNJBscLe{-Cmd| zb3pu_TEx{XR66vMgtGZ3^9gsSqcD#lEWh^K5NenwSjN^Q@3kg5nR)BcuIw}$`gFk- z_wY!H_-|8bY$?_1EhRae2kf=)**?S`AJM1yy&Rk?oqR)Lg(>6THz3nQ_g_wI9#!i) z4G*J)Y(P_sC01BssF$#@(I;mgFKkVHk8gz5oc2+E`LCnrVO?c4T`<;b+kB}NjFYf! zaj=0`DTo+a+ntmuo~YZJ?LL{ofG08kAU!eI{)4iSqXXVM9{cm7ig#;t@}G<*!vAG+ zZNeLDJf1+-E~%KV9lmtO1pR0sHfZcVWwgTdt9jR!Ech`++AvxRZi`IVJPRKOu7^Pw zBDs4nu$SyBTgyGwylpcD?XoYStX?Da7Re@t?5~E-Hm%`L=)b2E*o(-2xw5rKua8H1 zK9hOBKz_?j7Ig4FXvjZIO`@OQ(DxR4F<$A&x1ATX1VQ=n#E^OYK_V#V6- zO0jJACVPVqd2;twBiO>7qd|=(hRQl@77I6~U&I5C%`wl|isIJadw+F*k$k@@#qUgX zu&U4EoF0ezF_S$%ZTeOdKh|xNUpwRw7bO}Swa8#~;{_z|9>i$0#Y55g+T8Wj_>4GI z?csHK_{78JIT=OWM)c)f-<;YY2kpMS#~kvC>EbmHAmZ$YD*~8 zzFn~sF*Lo;Q&JJ1>EGig^w^kG`qXDh)8_NTz;P6Zv^$#a&~*tve|2fg#Om@FQR;xK z8AqRU8Dn{WNPy|lyRkps;(}n%`$h64XTOCSf4tz}^`=DR?e4UDTX8Y$-!Fex{!prN>cmFhbB=#~Aoo*uwIEa17GVeS{ z{}K>@@ZfdWhAr>xJNsMCf~%wsT)Cq&#vkovTjwK>=vI{``A2&=kbST{bIz!nXJ%Wc zsDB%A7hWH+()lDQ@@jeK3TvU?PRTpP(hPd<(sdQARDR#9+A_PksoF*$>93mqcCk=C zrzfD9omzHzx!AN7#e%V}7oPSECx;MQt>`To`6qDE-z85(m1b(-X z`@q7l>d^Rc))YP!cWkRcaMJ9yqG)=k4cX7|KJY6@PaW|>^qK44FWt|YoPjpi=g)k1 zoey>+$J|uFq(RZ!q<`%Gt_N?@M^4pWicP?IC1{w0y+$TsPNa;=ymi;OhF&*BdFp^4 zdqTKXi#hgR*=ti+_RMQ{eL9nJdm;JfUx(z@+HS(X@40Rg>M3m|f(3gwNItWJxoNnK z-DkTDKF<1Ly_-$uuLoxQYW;4&s8TCacib@!)LbA_tGd-v4^D`CY8(c-0v=t{ZOd>> zY5h_`nO%coVl%>RG3>%r@o`-17pOktl~#Ifcn_|VZoH1Y8Dad0Kaczo`IYy(x80Bik=90Dj7Z4#rGC?o5Jf}m@0_=9WK zS7Gsc1KXO2D0U2^r`R5LSm#+8e~TL#wXwd*IEf)6qQXx>+|?6uINAMZ%uB-YGpkUj}X^~0WZy-=Hw!>K1T`NS@#;P z;lfgI2oYs|8*$FL3O~O0RYj~Weov9OfwS_prh$9LJDS7Ooz=TEYrxmvwzBd5l4@9@ z`r=FHcWl?Iy?&FP97>t@7JMNP#dy(YNnKtQLxakmeBtsJQsq6iT)8PLXME1L!1-K~ zt~IkFV}<*%P03Dpysz1|R5EPr0uMJ^F4mxvMJ^lZ_S-Ypen_Z}`(QJ!udCWJlFDS3 zL|b&_aD1%>W&7r+@!xS@-aeD3bT7bXgL}U}!aD;+%&1H5mGvP5{&_xft^o02*D0hoU!MnQnAQ9`V$)&K z<;7-FQX*65)9sq~6k?r>h76>0_(vnYe^U*XHnOlA(pQ*)J2*`v$rsrc95v2oR9mL_ z*P!W!HdxcOT+*v}b`3*Aeu|8YmS!iXj?BugK^FFn-Ym^sty+_L0ZmC^(*)N&`&`l2 ze%}AEVN=+`QHuCroI$1NkRo1WgT^O040UQ{76+5D7G^W3-t{3`jyl7@MOtKkG52tT zLFoO+{iIP7G@8=-X3&C)uN;Z)Pz+GjcBl7-CMhnsg=zG_FJG7gb-Wrx?@>8cjy@sY zS!`f@FgMAq4LRFRmTbZY1Rf(r61hIYPYG0uj&nV5O^&Ham@)gxa=&MAiR~)<4zo5} zpKvVww1%fnDBGWu$m>z-m3CDLED(TrFKOH<(A?882NKk609(1;hOji`8M@*=`q$w_ z2e(GiyD`iuWEgC{cZvCMJ1}Cw7BJqR7^5GxczH_ zr@5gMsu9Isy_9-lcUFu}fn*a6d_6^6Gj;<-Of(=eDo0Mp_Kz9jlU~7u)1JXyxmZS@ z?@vutB9i2}k3K=~=Z1TNSAo9F!}oJC=nO#kEsR}xnK^QF-or?Dyngo-D28Ld_`=NP zd>Z%^-Q>E@O6+cJG;PXZ2(@gimHE!oI-Pw16DS75lTw9hwZ9T!XGtxm;Ce6EYA!8+ zzCvoFn~cSv%r5=$3T8v226VF-`-Pzz58{nBE`8+OdVR-6xXtWw#+Amn2JHcZLU8vn zHc}_&XwX}e&C11uEQivrmz?)Ejk__{E>lW}aa^y7vLfaV#Nq|+9l*|PtyZpEy|T** zty&Uxzu!G}=&XvSnb2dY*Nq7^{fJE)K_M9P#L@Ln7JB9Avz5!U>lYh&Oj00bWs4Ww zomYC^t9s*Imv~;4O%6*nnLg8fCa2D0GTGn8?iB0&cCo*6Z7|_E?}dqvLMcZ-h^wuy zbow{i87|<5DH|?x6bWdhPfE_a6AI&V%jBR7-RaxJ*Z>{h*mHU#}omJOkQ26XFdYYhDZ>IXbz={ zbGPmAS=FKJgj_x|FG+OZ@@0>GUXad;5^bA=ZCN>bX847U!!*82j!Xn|P;CZykH8~0 z9rS1pM;P_mx_q=-$9~6ikxQ!S)@>|m|9u$Z;t=Pr1C3Ez%q2Ve zOy}Al>qRE{n+xYY4WKWyj+APYLcd?COl>_)eIu3qcX1tQPfmo9TpwwZV9>gvqpBVH zQEyL4E+wy~b-hh%mwq8l!VU#a*9pSdeceg!qtzi1uy~zTvmq2@1K~#K^#-sNOmkFm z%9oZZSf6Una-G)$pvjJ>!rC1La+TBMZG7}kWfEXJ0dLp5I+^?ia~)gEmPGsSrwaEb zRKfNFLw+HhF=?j+DG*exhOU|+)UnM;sXtnXz`k-~Jkh19ya6Rp6mWO`@R1(kI;CVF znx4gPkXJZ=;hmhWA36!m1o55TWuyvp+!_nM6Q8@U{P<0$71e0Y{Sh@JjEeuvJoR%U zDGu%do*}-?)t4K2sYYs4L$y+XK?Oypgb&xsZen(10-NO%+yxiLg1&gb@wk>J>AUEi z-Q1O>CJp)dlpnQ{zREc(tvKW^=e$~E*E@kCy?#Ygy~zMJNqJ`e-6WPD-&BcjEQ5W4 zyue=CBtG`(4#He(6^-<*65S-ubr`ypYs~2&_bAz`y*mv%qpOcpnTL7`OCdcmj#-Dl zuQ~4I#?g?2QH_Fk&A@K2-_lUTaGlkcX~;)UP4mLU_4dDc&Kp`GbDcO=*_&EW{7>jJ zuy0ZEhhZDxcHD`CQz~?rv0|s*lOOl~!n1+F&w^pkJP!8<9Vb*tZY%clY3|k;<*EE& z#U@l^&btug)+h|sBeh9tkPGu}_7N#njC|s$gc1|+r}t&JP7V2Edw4-;6_(4==Jx%@m>MSB7OsQq?tTG> zH|vX^(uWlXv|3%|kQS*1bnDfZeO;(VlX?kj z)2e;~siD(~U|+D!rL4x6zG^6fNNTy)Id$$IGe@KWOHa>-9*Baw_U|vqC7tHZVW<4W z4GZB`1ffviymyN~J@4$j-oA~6t_+&X|wp{3U4QGjaFna?xq=s}xKZHn@CvLrepYE*+D{ zXTwXkyqmiz6QS2GEify*tysO12^Tb)Ra7ure|=olO6$158|CJy>O{(dvZc7OwslAa zzNKs__pV?aHTGa__<$U%^;E}AY2FDzl(XM>4=eE&RoLZj??uE|trT}!r^4hjhJO}b zJ>55rWsPQBGEWvM|q69-#VblyMzz<*dJ0UrNFel7v)hR{d6>axa1WD%0SoYoUVN4IIRbPB((%7fb z+_~i9fPq^h_57NjyNVvD*@kzux~&X)m7>e6nO zk5fuKk5GE8hY2vF`^3avLnqfVKBwZr6EMAF>dMZ{(b^G-5k)Ww(it}WK?rzY3Ft@h zhJx@7@=Hy}s<)XpfOiQg$pRGcEOVoc&Q;ZCTMQMm62UU4qg$hiao6!&16yN&f-8~R z>oaSE0o)>8dky`g;d~txwOoTon4G2e_H|`f8&wjsh=$S##u^l-KCyU2QUjIjAJ$X{ zmUV1*x4ZuZ4V`Va2-#x$A3}fh0xo1tJqwt`;Paq2MUp|gxpbpFoCoRwAk2+PC8#*f z8Uh*${E8g60C-aFUQRR9Z~U#c7A&@3a>=bR5|_pJU3Bjh$ir5fF{+g=WLL8Hb~|vI zrS(NmINz1<1j@P~@G-OosU$KO^Kj;`L07cZoMC+VlbL?;(k}%eK}_JIDh^*$pP8j% z^cBqgk*ZqL5=={-9NIfT+0M`kD%>fdP0*Di(oKTLry zhtn8`<5!X#3-kTaB}>PMiQYsCM$N2CUyR$B)7}{K^jH|gsGb{1y!DC*&hgAB&0WQ1 zFItTKoho)7-DXDpW{7I!fJ4{lS%_8a%~7^lc+rE~fO+TwSG0L&9RDw`*@&f$ z<*&KTOXWUwyD2VD%yWeUu74RUwG|;8QBA0sK5jeH$2g~Gxyyw5n$F;z+{0_S3e|I- zHx`Xwy`yEn{L39L>mA-jP`vWU+qiqksLOBTq&M?M^61Ic^to*&-V*DaxTSR~4R@|` zol{w1R~|?Y(HaK=$YY`NyDMLp_vCETKpZKO8w5SGsAUT%CdasVRNlbS55C;;qk71R zerC~~<;4r60qZQ)33)hOo-G$4D^_AT0tKcH}>q*@B znl~fq{Vs=~_0#_8exRp(?|finM5hpRH#!t&8`NJXe*K z<;>=8{!bPFC@)K|-o8v@_C&4?O71izsI1X2BlgB6 zorZfWTgbpQ`Y)u-R(+*^C=Rm*2QnNABl9lqX4hv-u0d{Lv9oT72i{dF_aGk`ge5un zp17A2rY$`)6-n;7N=wY3k0fkXy{I0&`fE(__bzfMnF#K!m2Ltx=#=d+9#8Inug3>V z6K@%rld~Z`5UaxMd7?SlX&eR1Y)2jhMp0WKO8^rT{F3 zd%^+S^1y=O$08%mG6hc(G!W#uWSwegYA$XZTx3r3l?U=hE!0bB%20<7>I<2T#^>(^donkw)g?8ui)+F7a!^XSV) z=PS_X+{oTx7gElDA9ZsRJ*n>iq;o0M3DiM;!He|7O77=c7G@DGbcU;2zs}V#CgATt z4YJ&)gQ4Fm#m16gMw3=AwNrl_5F@>in^w?RhAbetaqc)HZ(ajXyjS3&s04~+3ow6d z&;p+1r=Fsil2^a9gd`bO5)(y+YNX|W9VJx20}Aq>xE}~(WQxb)H&cuO42IMhP5^~p zC0i24mI~ho6tx1D>o=-ea;i9YUo`kBVCy7$tLui&RBPRSzy?T7T% zE^@S>oT5L}4ep9;p3#*N3rLQV)rA_a^U7emc|`a~qJTwN?cB?00{gSZD%w1=nQL{r zUC}k5dmhbg1@rcvU!gZTjKxquVmXW_8nD$wkV(&A>x4l~BG?SlOia@i?~o=jXJ1bG zMD>39DBY|Rs-=$Y6_(+GH$cCCfGucLvVXN1PemdKrM7~v{__~$dq_tPKNaV~tQRdJ z5eKayyVt%eJ)=VTrSN$fq4VPv>}&!qzBdW>CyN&s%!v;TaV)i3^T_)Ic7|0$iGi7Z zQ32oVkyS3vhfL&3`F%?fy}4L0q1?irT=;v|T{N)3zuNDD`-J=U<7Avg16asUxrm8d z?aVT_n<|~#K9Af>F!{GKxNctQ_hH|P1NQA;6uo!afuIvj=nz*N+)FKZWzwA<6@Owi zC0aQA(gj%B%JMzE2!-aL%l4p=X*)~K<6SJsF<>xJ`fc^+hc3lw##mpr9#CUNDZ;)5 zl)B6Si=L+hk6%C zu7-Tz1m(6>F9{?+O=v_&fA<8|0`js>qyp;n;NPkutOuRT zC+{wjjVm9mgkaGO*%JG^Xm9Z-4o{OXJ z{TM8j-=`>g%%b_*=*ywxnu8`bt z9O~puZsMirZSp-V*Yf&=8s4dB`kxTY_x1+1q_=<2F4S7|WIl8xT-M~DedKzCOV+IA zpySlMyR%2o{I{#zMcaL=sUcH8198bKzN$(`8}+#VGRTuKVJ|&5FZBtry;%>KKusBYth>4~rqz;&Fn?+I>c~%6~fgM2Zr+?qt zPk9J=LudFgCr@pT)%$(g5a7)%0B`Qyz$@6{qa~wk(`oe?G#euMydykrl8!tCe?^uN zLuX)>et&3jvfM}gXaB04)ScZwH;66}oluPC#*E$aOnT}1Q~@y?I#6ghYV10H0rUHE ze}~z4_d_M9)}8^%PUX9@)et>tcm2!wIO`qjI0(QWTkqWG`gZLzmlOXo z0?^uce)}A3?wEJM!kmUrW4bCu&Su-c$`c&OGj%HBIjFHE#wGqaH=+`zb!wgWhZzt+z>hKplEL1&G7+z8QX!;gF>( z-sLA_A9sxhqGyBgTPf!_&8X4h+1KbMeeq32o;j;~xH|TC>42s>C;l*;s9GOZYju&5 zT48@SsJ&*$15z%2N-~A%6Cj!G7vi<$4J8W{Mw=jh04@X_@>WCG)8}=x&YWrKfj&G2 zeFS)H$2iQ4wY*3ILt;0sPZJ?~R?A-c;vy ze^PM6a}j-IbmzzOyX#+6?{A(v9adb9o8f5$p3Rm3Lo5*Rzqivt$W@*IbUR#_?8Sgx6y$xcFhW zXPbJJ%TC@IrQ!Y3vnM=k&?_0fjnM=v<%bIFK9cHIYBknz8z(Y+1~K)@a{)fnIa#Wt zxolt&+%uxU*&;hFfS;o;i~Ykh6RPfVm^&BGza@M&mTqAUE&?me31RiREI(U0LUH2x z&hJ#3=KGd>MGa(p@2ZB)^j$wGr;!jw-yr9rOXwCwom_qo!ZaRtj0EWK?3SX)siWFqbLp_i9g@2Q(F9xp2TU5{UdU5wr01gf9az4i9R+ zTn=a3db*K?gBT4GSG`YLTiQJJ{mxY~rm=~r=gBe@8gBJr#WVESJERVj_A$s~0CCK3 z@!=ddEVZ>7r})c$6Kr$pn`2ernowi~sE`79SMB=9*P-n4`|Z+?@FW}0#pcw3+!nSo zirlTov-}U*R}h>w`{}(sY#Rc~MY=u2u=VE@{hNO6lPHR>n5sj&AWWlxq7m^X_`T+A zU&G+81LAckGA6u^@e90b{}{ldJ8M7R)FSDI!5UvfAJ>NtR~A?B)pM;1vpgY;h{8x> zi&b!vk#;G&_+i!Fy%ZnpqhG<@W}bUdEU{r4kPn_U?SbY4zZvPzG9Ev5 z!voFV_sc5U_<6=X-LN%FpS5xthWy8S0Gla(D>wW)c~ua&q2($41U5$pVD!tM@ftml zQz^~q(B0(IDb1SD{PUEMlQ0n{aiU_xbm=r`-cd5JeD8euwneP1w7i2lCK2vhI_@=` zKwWtilhE*n!lls7M$EtcOt9=%ZQrF>Zs9K%m*QDjcDt`muOVmx$$x5B@rvQ_GWR(@ z*5T4!UFY2H6NHb9C2E^8+;p!E@J;N7tJ5$G%n04F((vTIELV0gASpD6-{OFe?{Zu8 z(Zxe}gl+hkgS$0v%Pxy-cj4(`V zRi*vUY!m(Vkrxa~hXoB8KWgx@74gs~FP}_;Z|v0;8bl|Z@Kjv4ZL}GmT;AVW`n!vb ze0#P+Ke8ir)rf~S#P`WiY-NedLg?sbVP(Rf)5bd=Fcu8+j+_AP>ZVYRnaWCk9I_**a-<9^X@O=h4{`*Q>?u@|PFTLMa#>@i_qDKAEl=(oQvK8X^GcrPY z^=%0Pz(ZCE3N$3P!>`ZkK$? zc*2$OEc55ffi3S>fb255Hbp5aUtie6F12+sZW}|F)L>Htm^!8_`rUK8!vACew-YK`JfMy#3vkQXR~otj{lj)Ad--RiQau%VYCKsB zxK5v{Z=LAEW%4Sn0IRlx5^qDE5d^xF@Oo2wL_==AJW5of9N}wzOIqTivE-Z%0HZF&(>!=)S%61Pr zzesa``P74`Ztpu!#-v#c;R-t{#gJ@=H>+3w4ADH+6`w^shkSJUHH-Oxcx%?aWyDcx zRoQW^t5OUTMNFV%cn+oLhJhzws1^v%`hlK1Z38gBCOjo5>P5mqm`mdea_`TN?T3+? z=)!Y4WMNOk$0sgLSIDAZ$C{2RK}z*+_@Rhzy_oy%@foa?Q&fB3Qw#g~mMNoy@^Os*rw83@XqP!;AZsQ z?rL6zfu|L*?NO>2QmBqr+F8Cg|7!L|=ao?~*Go3@WD#t}wr|2xFr{{PF{YU_cPQu6 zAlJE7bq&r%@FX2*52U$%Ps^;bNaN-cTPLDJp*s0kp<#5uvPa&<@l`FMdB{3Oaac23 zNcIAsDQ5>7Y0%F_z9-ohVt|eqYRg(o#5g#*m6j5*PoOy=x1^a5lj5DM-8bianU9oq!&i@|S_8;2?5?(+O>;jy=#Vi!eg&XbHLK&q3d;MLIK~xv((6+wMeYyRM#YaL zBy;BBl#unKW457fGcghIXt=@v#`@_y1#p^`Y;B)L&B8dpIlDBG1nB%cLwwU|a!lzs zj*elhsRUkv3-#DOo@s(*qfO_|z>?@4vqA2i3NT1}>#HXmbD$)?bkv$|-K@jcr^yub zZPmR4KPIOYPP_0=_o<%d{V_^6eZX@G^yL!FE)n)8T)nwixNtY`+cQz=e zyT@=i(_zQF`X%hB-Z5u%b0xfda>UY_4y(lfl|K>5bnRGv-gPE0vVW0+xbO z#|%*M)w-&dw2{&>655l*Z(B zxAs*7t$yHi20hOQ!#qy*fe#%uz^0L&>c^-gL)RG z1WTS1YdGi3Z$l{h%+~6wMcBp8G`fW#ny`*+6_lep zo@tb8>L;tY|0!Wl=~dw510fqQtatyAZPTM-FN~)}{D$msm0yZE055^Wd%tlP;R^S} z`OBQgvKoDlttvs8* z_jD)Z3HLUZ8JaSHs<@L|BXZ?Ts!(7E9C-0SaN=(6?60s|N|HGf)hO+Al~b6x#^W6( z4)n>Ho``by##;;FzYm*Y!&uvah@C$0jvY$Mok9K$LxMneR~~QuRPZ}bb_K`d8U8fo zQymKzwr4DpBiaVPRP}WFjUP31w0&`)Bvm{Ft&iImV%+%={x_+~Oe_5aW@}*xZO93T zyl}Ekc)#bIi~riK`Z4Xf!8PkY}K(d z(T9zC4d1uh{hmT+XrP}tr}Rag5&y}7fS3{E>!X-vX1Rs!8H8d6q1ca3rzEg)dUlltNdkO`*~v={pJcDB_eUFr&;_8!s1iq+po`OPR0lKur_{`%&fy^ zdtdHDOxpbbdN$6^l(BQxqA9Pi^4kF_l>D#SethWwN(JJo9u9|II_2!{>r!aYKlgMU zjMvk0noy?2T2Y#sf0h{35DwP=&p)8&r$J5sP*LTci;t;sw>_&oRT&~WhW zWQHXC`mdavZF1<@&eyZHKf^|%PT7H#*1a|y694gO)Qy~U6{K*1gL+mPf~hX87@iJv zKC-Z+GL8NkE?mOB{>q3eC*~}dKkdhlj+mL0COaTFB?1W(#_5ol%+H7RDod@X-gis5 z`ajQ-O5;3Y#Chkn+Hw}hpAACQ2DtmhC$dvRFtRK3VlMuEh@>tPsHT-x)<$;(a$SY2 z51g4>l~(CfpYeM~eQRR-gd}Ws{f~G2`uWha>zrHrSlnbjP~~YeSDECj99A>{#Uml$ zIKjM^$z6IMzLq3hW)R`W(EIUD(|6s0!DS8B+HKgTj9p@ok{likqyFfSiDARy3z!%9 zn*cR&y#}vF>hlOX-zDa>SD^Nh5RY{Y=9oj)4P^&788%tDE0=EkK%EQaWV`b%hT7+P z?SW&+%vOY%PkN0Euq8)t0tId|(C2Xm!fecgRdF*g!k6ubaTlH25||%nEy<^VG(}J9 zV!+FMgTRYnp9`=>J+oqSxO{E`(J=M|tu6l$kiQX|f6RN4+<^!^2tU9E@!pAtSl%g4?!&R^7TW_>N2*9z?>hB=?X zbW6*TO|oy)@};{DK&^;8zY;PR8#>#2Y&5*JR&zjN^1$ct?$_W^blP8p=lps0v`>G% zw|TE@ImzD{43q=+xo;2#U?0mUu|mwshgUOk9(10XaRUqK*~Yy3Z5vJ}MtEub+BKTY zf85~UR4FH{VZF_deRsjQ)44)y9eRUa6yhqTRSHolKi!Y^=GGg$sWBhhx#;|#ECB1Q z->WQgPvO4<+`_Z8(o-zn!`>Y;HeGJ@$E~B<}x`Y+U<`SMwlOCQ}L9x!1!ms=rN1uH|t`=}WV>9<^^fpTvqj+B5} z6w*YbW(n`U*>)mdxv@nOevq;q+tYtVakxsNFg$ERT=0H`q=n=LP@84TC!-XLMbtTZ z8%m&j3A*6&Oxp1-{_;TifFhf@W55eI+Gp0%)u~X}Id8|;uk2QNVO!TXM6YtwYf&z! znu@|zfC{{B2plLO{&Y5uH8^=kf|nmEz?bcm`jrT5Z~R5*j{5X zK!JiJ9DS4{Ce~m9&t6lZY7}uvV zc$-*1_OVTzo=1)-^x_}X(%?zgn@HHj=THNfAY(co3u}$Rd=o9rwl795?Ms&Iu(E>= z`*3D2Tj#VTcI(`m82dbX&2h9EaX3NUfidouU}w{2(WMALD?I>r@K@1Q3^Q8Hd%Q<5 zjjD-SXYOD!rdi*Rd^G4xv@L5}B(C^|`1G|j!tjwt4_Me4#iy}pJ7#TXX;21z6>jI& ztm#A`;A~tfOvNgIvlhcg;vRYDS8>wAcT4oCJarbxjwKpoloZ=xHv1|FRGH`?yi>3U z@{UOu&a&G-bnPK+#W={{!#08TrIGsSqU++kF?$luYqxme&4%MCu=%e;tbij*<^wZjPXfL8i0{7(4-KhSxgDkz{+ zpNbFZlqHWeWEifHSOEO-P5!^eeQxn(J^M@+ot=P#?uZWK;9h^A{BgI`{v6W#D!3q= z#vT@xQ8^>Kh~S{nx#{YuwR*sDT;rx#;-nf^)!8v~bpB6a%SAVGb$3GoaQ>kN)C)`v z=L(M@gW8@YJT(W73(Bv4bGeig0UUQhj3t6?I<73KEN-5E!PZ7*Osa)tS}+FAtZXiN zRNHvPNI))$d6^5AIu_~?Pg_BK*EL7?ew!&EMg);{#{-WX3VP(g4k#}TKFd<9a#W>> zj>-$T8Layso?mxDW(V6g2MW4e(R0p?*RPNb!bDyVTiC0Ce%1N2K-jsAe6|NlIX^?@ z%zEx7^#g;?%TjWDN;5hu7$RfW**Ns}H5DSVr!^@pKu>la$lDwRN@@F$8FxJ?sWYb7 z;LirmgI&g93jkiB$b*JaI8u?}Mjs-H+X@_e^k^0Yeac1_{>|Z}>}<;BcqeN*kYh3& zy80Zqq^3^X(66d*)&P!awIjE%ow^UKn}{hi6`UK7=*rr90Zjyts)gnEkL}Z>9?RP2 z(slvz<^phx5cC|-pQ$CuRo~W<^Ta-qS@1#-%B_px~3a0V&MmKpi(j zr<^jW1;m_LXMx(;hCm>Ito9!P4PdgI0a$(vis}Kw@wANCR@8VU7JWc? z8sJBLi_XwE3QJY5%?18Rp8kV#G;SOd%zGv2nDAKsld4{k2`pM?e?<3BMjS9fzI{5$ zL3}J6z*=lyzvuFAQ5z&;$wYE6w^57DOYTp2Oszm0ih9;`J(y(%&GM0s|VDHv5nsVeI~rOY`C z?pUOHYyV1r!-`njrm`Z6)NL+R`30D4I+}}&Ih+haW9QZr$FXbJ#=1b-pF5v>hfQwY zc;k7&ohAzQ9sb&{Lsk7=SL462^mhNnl_^Y-%KY-ykTSd%>SACGZgtBt^PdwNB#Ln{rT@ye z%a@<|FpuF`Ez>Y){ z){RN5`LR_rCN~mP#I8~-l%@hB2{kxm%sp6BaM@wTIK5B?=%#vRRWGkkm;=Tnem*k= z^M(Lr#AFR|grM)9E*0~-cr!$qt3kr)9;CSr4JF=Bb$o}kmw~OEKdY)>yg8Tf8cPaR zVbU;9HsuoaqdJl_#P!cl?=nx6*WCA&m>?T?j8qwzAn3_pD;6@i!rnOswhSiXt2QwLSv7|{*1jSo z4qii_Bd_`U>L(e}F_wutpYl~JM}m=SSeK{ES*shsj61gHJTYKgIT6#NqcBA{*te4P z99IZAN~#RsxVgL%aWoFty^xfH)7k?q=xoq^2l*gha4OQqDQU$*vZn59JuG;#X!2hE zImTC2ss>B33AUo5yt{WDVeEW7-Y)rKxBB>7`q`1G{o$>NntKGeiwCFO|1S`H0)8hN zF4`|&`>zl_o1Xl4|A$BTnBh;ZzEBvBTl%n(nP;bp?h%$q48O>mkT1B8sCaR4_T}Xt zTwoDXl`zoc!>Ywi*ho_S(=nr;B{SFNOIubxL_XTmYPx8i9s4O|k4y7!$-Q8pQ&45O z3Yt%L{Lbw{pCOEc_6DbZ*%}leh-bh23<^Oido%EjM;y_4kX`9HEh_dSz*XN*wEu|Pk647l6ef&nE=B$!_)tGNwx{#TwckF`1h&j7sJ?}-I|{g zFN)-)KX}I)s(I6sW4nF~hDrGwmk0oDDeKi9g2F!J&j5q1w!%5=_^%>z-fq1GFv$s0 z&?x6degK(BWc%Z;o#%cuK zOrGlfgXvSkJ#TE#JGfxOJpdr4h&AeL1BS&nHESC|Tgol%_J?#tf{s2|PYj#CB}t+s zTL5E6Han`u4pw5p!{>u6Q!Brn+c~Lw)v4}~W_0$e6|4I&%8)@q`^M8Jfi!6H6ptum zw)e@0Z^Xtj4AZ8Jz=c-L1eGmq$o%N6gfzXxDrbM~L=9MGZDq1Opz}>Y9mB}0I@sUI8paPa4W~A)mu%j| z43BM(yEX7Pj-SguCpTNoxpBzwE%1d^ujppI0g5>ocJ88>J?(nB6ZQcZ{lm(LD?lgZL>~8hn2$hQY(~h|dL?aTA6xXZg zsz=MYjFldB5{ScC$RvuiCuhGx_u9ID}u(5qcc}GUKu-2MLQ&SE` zO_bL&-J8tWtk&$Uiu*UggOIWBuvEfag2hYq)jmwz+qS z=SrY(JuSX{%Zr}`75|<8n28IjE?gb+A*+HVy^)S~ek*&ebaJP5Zfk8hV_XI<%#{Na z-G-;pild@ntCD$sSzx&T#V)?(pzxRsT{Q9$fCfIbnKTtwUW)}r4Sy`UKcyKhz9@;@ zNNytLs-AKsfX8kb|L8RnB)MVqsglC*JNl83wi*XXe{ulOHk56Gu-3vvPFn-5WE#U} zHKewV(^rO9hR#dO1nyM-vH_D0ps#2Eg!Vas+C)Rr^{~240L}5-ESm9#z1%Ka?T~fKb0*XV@im3BZ5^h!H55KOp`!$fy16`&rMjRe0)#C;%xx`0)iJ zB&_8z@PFrV?ksb97~sPJ2(4qExi6-JI+iEa0|Os!!4P`3BPgbQ1H|@|kczy}soNEqUczGqKM}th!z!HXIXsbXFfssw zDT^S&GPhipLg0S!%dCqEgabn)AvtaV9%$QfK0;PtnmFbIn@V%Yise8{J%_8a8oqW*nPO%1@L0eZLr zD%wu|b-1Yhd)nG@(djMGnPgwoSUFn<=y0g})AvVSu=v5%vXkd&eyxpfbYl7Es|)1; zJ7o=BBI*!Yb2j^J2&irYU`SwH5dQ`^!s?}+e(B%V3A>-33^4VLo39B_!X*;IS!HU{ zDmPq$YL}EZ1FKFH)g47uyuQkd)2{$-syN0;T`PH0=##O>{|G?;83iEMO+%HPY3KWm zPs0FY4VkSs*C(l5Q|7VuliM$XQg$M%hnIH%ww{OB#_8h$u_2QB9HdZi_!jmbi1YvW z5a<7!;O5|jiRx&6f%tl>DbkIuz(Rt;N{|*}nw0DPozNU@edQvTo`i$M4GK6~~)h zquuw)ybU&F3^h{2ltTxI$|PO>mA-jtyrn3}$6?BWS+-g&)T&Bf@{rwRPOkC{+DrY) z6@J`wm_flwS*{~yb-%*2#AkM9t9BaaYr8=+>b8TO%K3f1VvJoMlz72`?mi3MMn5yp z%|A<4Bc8k|66F+Rj}5@L#-r5UDALS%R~sSK=~=7Celzw5*K4FZ-dt-CMn65ZZADD4 ztZq0=4wu9nAvEMvi{llNRXASvaDaPcZ#o?@=RQ)%x&_%Ls5B9gb}TJ#0PPnmK%u_v z=MF_51QzgJ*^{6Eti1-Uq9gPL#})lE4$Q6n6r37g6&|jkB@m~IYzSPqcscSifB^yy z0&E8)8uiFLI8-FvYtx9IQuIARZ;I+^xp`AJcti7t(_%%WS~|H!pthnpDssdKlOP2U zCY^nOM)vKR-sIIuSxqZ5B}ofVoo7VOv{zJTfQ!CAQ}b#$39$Lk2%|B^3#tlCv%;$hgr-ar8m+&Z$YNbMMBKTVyl3Y{0}KM=U^D~GUR<>`D! z;%wYFFusZdT*p(0$iwyU7|hA~B_MulpGETDR6l@~94y=Ry{Ydeaj(XvmhlhSW%UMB zraulKmN^Td^RUl$)Y?91EWm+81aZJu4N8JM28_@zb_uF8gfQuP+~Wl2>NG{NZX88o zR;?lhN?9Yq|JTqKt2a4%GRa!z8scakTe1N zO!AqDgw1g4J!Wb;8un6>^Z`(IdI-EQu@xDESH|&!0FwP<{S!$qV@zhflD|0bOVAy4 zmQbgAlYvMXo)N?^e4X9OcX0{0vExh0V}Koteh@ctkDA?=mzlwk1GPyAt>*Q@H~uaG zFmobwFL|8E*qwsY;t}%yW$4RH>p$DfS1Pm4{(lm_&(G5TL^EHANy_4vOGn)Ptp)7d zng0T?1~G(n^)!W7IriM4NXdYAz|-n`Tnaa0w0L0EF0#(y0p4C!fS*!_Hs~&3j$!J? zTG_X@{s1sJ;lKSon$Hk-KowI^td)LjV`HL#Ka~B#&L8edka0Mxxih%0n^Dn5IEQNk zis$Kkul07K$#$=TQNE_is$JY4V}MT?NRPqB>yF~w-Izm|?N2(d*1NE8xzQODR%)LK z`-r*1%Vl@<{=basvOpamj+$~$>rZcgQtIU=Ec1j-Wkg?|at(Rr`Nn+nBK$Bbu#3>h zA4VYqHlj(iWmEBpGYIX{^f0LMT%o=q;(l;cK{WOA=^6QF1L{DSOgNs$ApaQAL@!HX zVV8iD{oUjTINN1MJA~1w2>;UjK$0|sK^44|ASmGgj(jJIDm(t@cln|*EtB1>Inlz0 zKX5Pn3I_oIP=WrKZrDsK``LO?f(bcWk*oj2D^g!sm=q3Bx^s_76+Iwr*j*GL)U-?j zOPW8R04_Lv81UYDh8qc;cQyV&YnYZiS2V?e`JxGc`S74a-!kB^BAkVOQMLd1JYUiT zH=Zh9EwoB(*OAU0+S92)e+DJ%#Z6;=rx1+ir$qokWlNBf4?hE{!$}f$c?A}Y zz674_Pw6qLm{G-1Q-2r8Q7{UazuTF{d}$)D0dsgbpWT6zb6~1RK%~AN=rH0+A}E2; zWCWb$r@_J`vxKo8BlKT)W!UF9KfJqSM^AcS{)*1Po*h(A%Qt^HtB@=Y;pV?zo=FS} zwHlE>G3qLW0(QhjLHV}zMl#+2$?od61$;)>l5){3fKh~00!_Cj3xJpeIM?=bbfJma z^`5iO=w;$UgymQM5?i9=CpKLWVWd}aRjgNSlB46;Rj?6|li(;1OtVO{0_^AYqhct_ zr2#$qFMxZJ=^2TAd)wPUOW{At1>~K+C{aYKln$!l`JXki3%+=8c8sI`%0Oa1{d_aF zQKQTNa3_82V=qGur-Ne{9o&2REkV~939idSrHC@lIhrI*UY*R#K zZ>6oi5%s725h)+Wo!<(9QZ|7qa9%A>uiUWhQQk^BkqKW-DJ(bifUiyO+d8(e)tPT4 zW>^)yHYJP5GmD(bqmACSjbsbTJ|st4yL46+JTXJ57agLnQ1@BAN$cLtc@ zlbCBA38o^@CznmTFW>k+WMb~ME@;%Tzw|Ap=Ek$3giPJW>_wf1LVtcvv-$Kp^!7`F zQ=X@AhCNF*J!qP|pHhwpPyj={>5Ju0 zA!!|}^WvQ&m!k{HJ4f32pSb9KF&ph(9-N${iTq38S67jGqYup0n`hTgIs}~> znZU26(Jiv)Ipg@(kVXc#wy?RKtyfmyI&+iIaBrK&*s8n<<&+bfErwv|DM7)1#co*j z#F7cBS}f<{fww{WeBS;PzbA)gI_@+$On6Jx+hWUUg=3j^29HYDK8_5m-(R;(RG;Om z?KxXs436y$#m_&CCe?YzcBa)qQ&xiI$o{r%wW;GpSzNqm@f%gt&L8cpQs;Aym{*C0 zKF9N9#wE9}o}c`1AI2Kk@=6Tpr!g%T^Iw4v5Ce6SD5YO}Ej1gn)2%sy8R+~8kjf73 ziyZZAmL{-zJ0{ZL%^eTc{wu`uKUn8~u+INGtg|%J$L>L2D%3;`NM z2MptP6RUPyhG3pK*<}potJT+~faY;1YA5Vk(9UB_@JtTv$yC&9JH1+39WYCf?LA{? zjIQx}gt0fbMZAR4pLT(Z)pr!w+cvM-Zg{Wf+)h`iJCKC1X%6;$I2lNuS3rs^p2r6Bvs8)ovzYN*R@mYK5x9RaN`0pdEP;72WpX#%VWjKAT{ zMWvq<{_QZNLE}62YcQ){bg^bVV0Mj9$MV00cIK%6N28rDhyH_h{s-;+--CAMT!?Fa zr6#z_tbODVOvMtMJ93I<;yyP$C6I(Sf}%0B*~Q`yK?t$^Cv&!~L-ZwIwcn2t=bI~JV8BEAFQAov1;zoU6^^~YQK``TH=n~$ZjCb4dsC2X{tyS|A)W0TTyy8 zOA0p)|K%(WvwjG)s7=_|&(94ryUE8@ivU;B(g@apVr{xtySj z(<`|4cuSVDfacVeXC6zU2<;IlN*&>Ay*+F8Xn!Ct@QH%M6oBZeWq?o3 zl~KpkBy*i=VoXM-WuLOY`Nt``Dlcd7lASxx65UGZLaiv6-;VX_XT0dASH$)2w_LVv)X_ zcu=@)EQPKCe&p_sJ!gM6@oTTn@g(EcjMlXwdN|OC5kdpeK>SD)gK_sHW z_kK86P4D4RPx89Z%-Exj;|)(lZv=IF^p(DLT`japfqarvMbB;ak(zQTewnL5;)K|K^NiS{+AYMMKzrpc?Z zp4={-O+N`a0xr;N7HVy}(ouzPuYo(HkDo49i*8!z^&H`s7c>4qKUozuy$7^y`rQn!ArGak_9fECY_P985|5Fl9%?$1*c$VkMJ?A3P|8f);)by9U8it=BLtdIJ2-zmTAt9F)zua&#S(ENF6n7V)0)&Qko0#bu!KD*!J9glGz`uI?>aH3plN2B+ zcrLsR?-rS0rrl(13>J@d*#!_iHwCYL(<{Q4cetVan*EN#$`-uN7}q&XAm<$yuVKj- zK$^K^clk^%7Z^g5V=@o%6{;6R_je>)o)r@=;63tv@>m!?P*6IgpA6A-M?4ei=yEb7 zNxuvHC@HBGhWFZoN-J-%IK;deFGss}Rz1q8P~8&voHFV_J^2%><>|-s_inRN*W`wM zK%rl#`iUm(W_-XDnuT#x1{z?EjWqcGIv$2sPb_iLtUM%LC#$;m0ZUy<^kx_y&N33c zm#4LWGzY@HKRb`jl8?!Uh?_OT3y31v#E5X#+o0e62by-N(;=cV^p)EIpb=jdjx+{Aejwbfc3a5E&b=Gl8ZnRDOx)~(~!+YdF zA36rXCO7S0wHZ;XbGj?ze%8Tln-mofKC?=9zS7y<+Y>n^OW&>>EBxx7 zw!eYn;u(QU&a+u9JPfT$n_Hz1th37x^KgTBwmuX56nw1hDi2i7j~9#TF`LLK3;Ro1 z$m%rzxcvhwV?mnpA^~DG5Bl&7TEIbq!Ih?rxFw~Ux7LNdIG9!WNU!aTt4u5|d4YO= zb=`DBa1bVXCtv5AiRcCsCu-T#+*Bl0?I;w#^QgMUtx_kN{`0u^ql+_BBGiu2r(YLl zvHfoCcM;*&dsUjoO42{c5id;-4DfgtR>B8S_N9p8Kh@VrraWNvN`^(R3jfm5afg@i zkrMSO1Z}id??rw?jkCC_1mv}ew`#0jvNq?5Wtrrl1TQn%WH1SHeJlf=O0zExZ0j3E zph6sKPfKb+Z_+Cm#khVWv=gXKmOBI(Wa%M8W2DqHvX3yE5fD_zxtuIWOg^I_7kSF_ zdSA7J&x_w7WTU~;!>9kP1)zZ=ehT;yc+>&zfj%909yg_G-UW%cQGRcvx^Ud@`pztr z$KrLf9JxwkO!9>fPDZjkoP9orA+>`USf)hKEi7l4R^xF<15n7{&7|KBjvtuNP5%rFAO}1P>F4D zV-fd7%|TBnQ5XAq6Q198OqQq?2%$*u;?}HW?$MgnR?8DzK)2IDKvr>g9P93)8*6Cg zumQvOPN**X#=3Bt{YAkQHS|xc@EOQUt{r=SSVDOOoaG@)Hrr4?yr3?QYe)x+6&OFq z4rk7AmZK7BZFWnyHX4HJNTSt<$-MZz{iJ; zfi+P~-f?796BQ!PO|XO(adVcwWUqA&uU2FZ=5kBuN)tNIJ>N0^O99w65UP23|^vzEo9y zdgyJZbD!Hz;je?FAa4M!;>=#%)5VZGxW+54^0)AU#BewQ*6hZ5(Ld^Hb}A_Ch){zkSBgtxz=v@;J-L4`yD8tHIatz_p8$W(%B5czSU%|)p@iRESRv? zlo&xa8!8)*E66nB?~$869zL!5KWC?2-e-3oM4!t~{igaM{R~rdZ3|reCwW1H^ry2gIQ0tJyw+))v}S;4eg9j24cvx(tGMHYreV31#jtKPTUCMVQ|Az z(EiA&Ad3%kaUWcLY5;92qRNdz`*Y4!FUdUwnTUPTXOT}^Xb6%5!$Tf5MqdDtdf4K` z5uwUK^D-MDr&jRWDLYHHyYKr2EpwF{H|Fl^kSgw1*->9rLDa^}ZG|QaHmBK}DcNsm z4Nq>$ax%z`$KNfjtv3;rdlVvwwH`{d+fOAN|59Aj(!A3ie*A*Y{r1R34P^T1VdtEU zWXj+fRW7tuA(OsGm2c}KbWWI(=#vnepO<6yT`$}-#x-a=)TFp0ac#>wCn}<`P^Mp1 z_I^K9x@u}xOLK!$KBHS@(_W;pX&Z?H@h(c{tz zDSMOYSz%>`L-Dcs9t&5$l#%H785jjdVJxkq5o3W`75FU7NAv^D0n=(Jbc=o!ejSgg zMU#;m9?Jud3G0uokB^j;Cb^2srRRGVZ^ES0-&$?XON9%GWxdO;g3=F;yY=cT1P%}` zLXH^Dzi*J`-hv2>h-b2-tWn+k^>syRTFja63%5Bh8!cLmmSxO%4c#5Py$4Jd*O)(V z7)+=unrl114Tx2k{3&Y7v0Kd0*rJ`gRh_TIET0s?XrRxoyU)SO7shs0OsTVxf+M}B zFQY$=kXs~pJ(1e0<#}rPL*1KqJP$8_#>i5X!j2gNfNCce9Q!Kx<2y`k2I``Iou`Wu zNUKIo05t8Stj{*l!JHuojx64F76dzY#*HYjZSfI=BdB2`bo{2VZ^>;gDy&v7tX2v5 zroFbcMXc0-S_lxjl(Cdi?mUt`*E*W*bwc8(KFY8cM$H@-537|D{laKLm;;3Bj&4l#LMs%eO}RJh?^Tb&Xb<8cT?VhPZVyz`ijthjp`TG zO2wTeBp7_o*VKW?1)evw7faAr47^hlr5-(;ce+hz&&R-}m$fN)!4cdsA6zk1Ej8de zKvL=V@ct8;y4LJf#ti8J`9Fd*HXb|twKUFiNSy~nI z`taAc4~gw+=%`j;_WzcC0^~0P9ribjU&}0rcwqn}hl|xwm%>UY$)jrJ92no~ZUMi; zh43XdMBC8n6Cb~CmdojqsacS{_W5J zOC4d8Y0YT7&o^Vx78YI`!7pT~^6a5RQLP>w|M_?MbevXHAN6vw04&$DYf~Z&u#KkN z<^Y9mVNM^ps8)5E%04MY5FmWW240>h`H=KpLs!CkgTSD?vKP%4jGNR}g+?Cms^R6%It{*+Ag86IZWQ`Kl0FU#%((R|_ zgYE!do#|E#!{WvzYsv=Y<{y`9Bzg3Fnx=xBjS><}G;_u5lr;Dzmr~y{6!wK@yh-R(1IR_cise-^v7HR`<4mAD3 zgsL9v$S}EdE0>lXgyn+Ba8FXjMKc2oNO)Q` z#n9IW+#O;k+*Y<6NrClyu9@zjr6sYMEe_(ci{k0}9F!Z3M5 z&1Mxcm4|)_5gB|-v`DJnfpv0H8u95hY z-zR$uV{awn+U(#)cN)DL#`LP*We5H}!1m}`G_ZTCSBgw+9o;&{;#G~j24vM%b<~f> zY$(PcTU||gp*H*K<|x2xx#pX0hK8^cusJd5SEY^;$Oq$Ud;8NbMPv{0XKnTOLc1vw zMl+1#Ddm%-NLbUguqcdHW{9pc=*Lm7@57HUGpy%=2SZF^?=D%29UQxSlRgil*<1rk zR3D}UuLE+y@dM!ruFK*(({;U8;AKE-=nYWNv({dHyJPN-($50#mEkLs1&AF-F=8W4 z8p9WUvf`1g*#|>F+`@VL7VQ#G2oI{aEB7j)57!i47o> zoNv&9_-tI@!+hVk;CXF1I`Aq6YH#3p7xE57P#=EXwR=ID{lOCMgtH&ov5)CT24e*X zPIuZZhAk51zzSlyA^t0fTUw&9}oj$e!s8NSJ{UL4${~QR|Cw^D@vsS>?h*QV;+ValFqEjM8usl;vrK`@>RCp zLn-x&zaDV^IHFWuJe0PwIvx5DcDdBc>-}&F-v`&(O%+HrkbLoXDcI0F$`KY>8JvEc zEMQqkYmsFwiCn~3SGUG%C9dD%p%*7B6FV~<@Q6GVy{NZ0SzYFmkI^qlY!tuH`x{7EnQrdT(< z@wnnrZDOLzSyIoeRMd^k$)C%I4ON!ROai5O2?>#I;)DTs4eWlwNLZn|z24XQfMl8T zZ*)+Be9Nr!&Vr8RujOi7ble6Tw6OiTH$h#o;t=1UIV7ToQF$9{)4=zzYU8mA)7>IJ z3iZa1BEbnbxpBYwWWVQ^I;+jE(%~I)Sz3Td@*uGW-b{Y5R=FIjvqg|WHC-|W7vU$m zfQNHj)|b(DvOl>6uT!+9GdF9I`ckZ^vu|s?{qK}|;3H+~GS9MWiZptJ!!jo~=fjp}pRvac=N{ft#JThzQ$@xU`${hSol4pDQpdhdqv_@-X);*kVG zI8JYZjEZOvYM``p56blq%^zEI<}WVfnZdu7mToMbZs*sQiY zEp3k+KK*@i%YN*VwtSEJpd|HrePzzpCi;#@XlH80zYf<@8+EGMn(DO zWiy-9G=+fpGI2m8sD52IDP<~`6$6|(mn`?lMge%T`(aV6F_`f+t0Ps^Z(WYKJA9qdpD+7L+{tCX*Lxmx}mI|8=)uV_6QiD5bs;nGzEel zzHcjOswM-9lJ2rHHm$tQ31AytQ0~!rL3y%x81zfnUbyzcF4+3<`w$!C8Hn1W{odjL z+la__CGkx-%eJ4`Q}7&)GL*a(v$f#e91N25hT*Fs*-E-qsiDI0z!IO9p8pkw092Sf z`#B?LTIa5e@~#P}O2*G?Cow9CtFk7<$0wRWqY-r)0b3c=uZH*0L|;>kUB&0lIwh+6 z^1+*ANZPB%~|*$6yYikFSAeebz}@DW2n_X z#E7|N7M_Kd1`UQhv-BM)uoV+tew2AE9#7q#EKlAep** zMpRS2;$7x$O%F6)s9F&%X%IhSZyWHy+!uI=fhr-=@{D}2?xRsz6c;-)fP7AXO+=`X zE42a4wG;$x(!$@<;$RbGCFCco?LB$*2_F>&>zL6-NY#%HFFxGRfGPqrPMnbL6-7h{ z4lf8~E<1HWwD7Y8ssT!PECyg)4|xM?SF-Sva8++#jb8mM&KdUU&22KTgV|C15#tyg zxw(=2i5I@wsG0`fAQxA%Rsw()}Ea!X)ZYn#ms zA=EieM^g-ScWdCZrpdt&aI;#WS)17~^w^8{;lG@}hSx$TE_HLrND8n#YNH*V8?Pw5 zO_)Z{&9?nGqiz-n3#)Y&2x;ETiT=VwNNn2O(87I!;uOX{&zPdWptaE+0SD5(^*+~0 zugPtNcc`TC21r0268VmT>H<{O_SLryHL9V@L{M2<5(l`+5hmjl;Rx%@OT>lS%WLb# zBu~IZ@+r{K5I$Ije@8ZTcg>Nkha5Dz@#2of@?lU_7~>wll&xq5-;%+F1DOr4ApD~0 zo-E0t+K7$oIobUi_W;cG=I@376?3h_iB&^i8EH~eKdT(er}2hZx=`@El^m}rK#X-` z1qIf(^))3&)$BRD>MjrxZrgk~E^5ZrOi4nssMdQ@5F2eNpHLty%LZONs4!OFGD~^7IYS`X1b_L}RFFGV| z{m%6_RBAE6Ggy-qOdvmft2CW4_YwMOb+WT1U5I4KZuV$gmu%CxvHd&T&n!;LhMn@= z-;wJ-^}`7!dEh+rJ}byRYeteJ^XFXI;*&DV6_UN*Pm6BU7a{FGPUg&>6gG9y})UwFntx2&CIP7Py(LkX~7?i1K-^ z`L~m|v3dSNo|c?kfgMY5x^H>S+bQoa=W=u!naxd4=Zl3Vy!`B5BUjd)vgf?_WR-s& z`>L!196Kc-W@f&yyazMVTAn*u=Iu2SFKJ*jQ~#Wq#us2C)}OU@x0F;DWsBL2;l|ol zYo}%#NGFE*eVv~gxY`Pc3g>FX#i7^6B&{~xWx|DGKhqVNahMku27M@|>8061xCUtD zsl^ukqrxHF#xt9|i8jl1-&o3K?Ufhv0=gjZ#k=fVfqZeb&=l+C)Ro)VZM~&f3fk;V zT)X5XVe()e7cSX zCTvuY@D%zhZXv1Si+^o3vGxq+Q{dsXz8|A;??qJ=1OyB`3!E1()drw|L)?QX1>SLR z_CQ}>e;8Dud^X_D`iCGXgmk67X}rvy>l?ohhUjQYRe_aeK#$TNT;Rq75TrQ}Z_V77 zwO#=&Ro{aaLwxntC_29J@Ew*k<}~3L?tBDD40@CDS~WM|N>I788%9?2gDEM+85^ju8kP!?OTvr_Hc@Bsd*y>H1F2j!%k0F{0jSD&=N`$%s z;{}C7#Kom^?e=u4p+fw~niiejR0Y@L1=%5Ll2z8UPiyJ|jYg~5nRGZxz{#or?;PSV zlRagm4UvSHLSKiEw*%r{esB-uYT){&o#%d>S7aodrKlQSJ=eKnxA^S0>>d9r1kr!N zj|`OKPSt-7XI=VqarFj0%sD5#*2s>1Y2GNvDl1R}Jpbwo^T7-&)$mPMj>Wnd2!r1f zg6mICmV6PgWmmRexPe4AnRu4fV%uj&s&DR)(`Xv@_gfPNrmcDWZp zn*GuszMw|1L`-QYEU%d>u8ErVD)T9;A<84JITTJVPcG%<(kjzzxodlsF!g&EmJ$7T zti>C%b@OeqM}S$;K)P#EBgJYDX<+JC^Q8N9R#Szrcd*uQ4^RdnLGU^v%O+Q6>}qv6 z=qmUg{Q}dR@Z)8nuq5a+Mk?K~WQv;B%fy$2d`sb`+*w{8mbGnljcR;o&BlC8+%(tq z@KzlhK&i$bflg-~&1WPy+*#cNylxqxXEv_P1MS58w7Cl?8Cu;%(|~&O$022Nuc(AQ zbM<5UbIK;>I;gHIJa*$5e6S9jTsp<8XRXU8cVn~tMp91NvTy&F_B*d8wstjp9PUZ` z-$0}_9T=}+HJ%%dTuX$oRYB2H!#!P9rHs60pM(w{Tp$2&9cI|xW{b<76E$mPh#I%% zSU~-FN>}5C`{CIK=Yy$k91)UPwX09MaHAa9aO3TE;TpnnD95}5 z$5u1ppn%earHAwiO1~41Ti?6YHv8bhcLs$AwZXM)2avWf}q?>!2vu-xF~K zV2i8A~+6lMo5?FHlH!>hE_Mi_;%w$Z7Y;RwuX3~Id21uJ8#ubk|Q40hrV+<*E zssdt!L4%uTG1oV4EpTWFEB>~1qi|D+swUtGxDj+t>0s#EC-O1v)At}I(!}~4%m9#Q z_G&#nY_bIa^;Ffh-~~n;rab^t)NUJc79s#DPd{RlSe59+ikCY<-rjvM`BOyCaxNJ+ z0t)?>hTuYLs+uG=4cHx`+o~T7qz7)@-GUf=2+AwK-yo8IBO{&qlC3l^CVSKOnu&xD zrX^+zf&1R7p--D$^+d)T26Z`&EG(ym?n=AdXgKR0UB!4tk$X)ah{?$UlP`Twvim+c z#+Qs8uD{nQ-?X>S$|t2fq7?{dh;bfsSEfes2tsWVvG3H-?)Gx(Kdr8v!kv5_>h;+8 z^~59$mGCGHc)n>C)Q#>9U01?!7@#&Ez`1q5pA@k)nFrM&{xYFP9Q5gU!QfFlMfU=( zQu33qTB|!Yw1)vNOMYfK)P7Q9))zmHM^X+#jj;6=WjOD*;gvW}*j;9yRXn$AO4hhB zb9zjYns#k?_k!edpLfzf|2aVBb5Ky<&)_=DhAz}TyK;vBDk0a`mo92;`V-i}Pj#of+ z%(_pHCGKqTT&2`8n|Wf7$!k*0m5&Uqv;eP{5AVXA9Pq_W)Z^a1mQ*P|uRGSC-?z|8vX>68 z+#;*ea=}rm*E8${665eJk9IFlq3mlR!=l%6Cx1Qh8<@xze~;PU-_-cp*Aw(M?<=R0 zwPbEGF=b9{8xsYGPzCIWGO_Jd z3)=-PRHZ@P_Dn)_(tiJE+MnE{+{}8{(L??%`)MN069nJ#6s!4Cs%yCJ+Z^;3M1uYu zX3&A0OZJb`^NO$8#%#M&Gcdyy%^4T;7wh<3{#DI^05GjqP;9+kv8Vm z4H&C$tsp7NCY@=#h!g?;wYX4UUR8FpTKk>ih(3bM44re833sabEQ4*NjTfL}g5;$T zY9!h>1nS%7uzzbx5JgB6aUv7fPxf*FJPwN@qC)Nen?os&mmHZ{u(6!NeepU}-t4UeTQWpj|Tb(D9-6HYXpFQ#@9>Qbo zkzN9t!q@L^Zl2qPWFIpIQ}-rEm}wKT)@2KF@Pd(N5i(S5Uo8X*)Li^R{SESo(}~Te zdF>-@zv<5pYHpm>VE=T|gf<$4JyPBfeTYe_P#8<{w>398l0C2x2{Vp?(=TWO8|eU^ zB&ih4gPy!A{p6ts2*>?YwWbTkuN9H{UI*xr7#Z&A?&Js%;FK4!=(r_ef{ai0Mh%BA zX_Y?i6eh6`Qc(23UJ~PxAw9 zO^Vr|#9twrTKyD_aFoL%W8)||O8S|NvkE)DEW9BJt>b54(d%H`Izl}HpOya-MDIgSw!BLUObN%GJeSo@lV-K(Z zG+l{P7F+*3tb`FY8>-KhmehfsizC1?YvBKtcv<^a|f@ zNZNy6hv+KujU24-D`kL_T~-+Q6~R+a4$}C`W2LgYd;eE+nDJVIG_0eJ?|SbHv4hgv zd;#SFx*`P?HOWuBJB8+1Ot3;K>$op~*fT>}_jQzTwk~WfOi%uZkk> zhK|;KG_vBWLB{JfObo~GN9-^qr}~_MV+CrA^e1G|w{RlGb(X~VQ($OAa4Fk=B&`eXHGgWZG=geA zS0$zCSs~t6m$d9Vb5rc$VE9IRvB{jx<_owpAs8Sgtsj;QH~*Et`KMzm%+TL{%HP5B zbH2|t;NVc#u~~(A9k+m+*Q!T;fNsv!7@Aw#fTbuNOK)^MBfbT?lhe@#&B5Jk&U;svwAMm?J># zE0upzU9loznBJy%Twn+v^8lvSg>98cOUZ7PF-yVd<_tyx+Jj$n<~#}V5r8Fi2wxw} zjubRNX|EnLi@nY1a>@%Z-$(|UMSw8$gdzhhQ3fqCL~^m(r+M`>lNg0DuCw;4knX<%i+uqO=xAF}I{}=Y& zG_1*NU;C`uR*3@;XF!ycg$OD$3JMvlq7)T03JT%?B9kJDikJjQQWgjzC^8d)qyPmO zBmyb|ArT@V5QvBnkTDDiV+aID$oQ_*-uv`9-RHc0-tp@0t3UY#;YsqWCu`lm`@a89 z26}1c!sbZ-RbB9VKBIcgxtRcq+69AikN0BmEcoNT#P+crvVHHjz~5QiK@~Xg zr<`2doWY>93@WkIJa>}4i+J$3w(LMug0HjRB))LnCU`R9I$RyURjrWZZyLs*UteA; zU9+zYdB51H(c9B)<&hY#D+`wD2ybl|*E8e{4$2tfoiD`xh6@F!jX;f|XV{@yS#zXHLFTyqu@aH~m{c%1d zz7U*R&g1t6x7*Kbl&>qUBjc#?L547fCBoGxDM!l^d(V=X_2-1^VU%@r@azjPfstr4T;xq^2^Kg z5~TP|}wWj~&(4Fa#I&o(MO@Qf$W&eMq+B>kYF;5U{9aX9S+V1u-tFJAGZuEmx`x{TaG#R{HW_|`4bkA9NdxI`4XbJeg@LP@~ynVhW z)@KhkP+%0gD!x!{^y%mMqwp;oUl9)hTZSHhdfUru*ZM_JEGC@%G=uxrYx_lcr|Ya| z3|VnC=Fm5tim!Uw&N$#-+*+Z=92 z90O-DX{mA9rv`wXY1=XI*Z36<7At$ev%8wEoOB&!95#4_JHS_3A% zJHoMf%`E(Df?B{p=k5Mn?&{e5#OO&opv-*xSO|QY!@|MrwD1OR=gh#ipF}%RpFHwB zSev1HI+Xo?>y%c_lN|LD3?uS$1{?S(Q+kRZ^1hn3?jhWX4Uy54t*XO{t6v0pYK^e@ zQmfhG%G2a$HuKag=jQam0JW9ShG?-{AyI2vKwgKwEbra$Y2jLc&`&me(I?zZiXQG6 z+Kvk865QSbpTPZ0PpKT=?bQVy%uPW)Zn_~se%e&9v;oQquGtJ)S1YxcBk6m9qwiT5 z7uQTuJrMu+rQLfecxFF*50Iv)7TKXsVBBOdL9IBxJ|oG>&ogX4J)z0!hakc8utd^b z`q#6aYx#>B06fn`d};)Cq)l0vgI<>f*jRY1+L{3%4OtWnyH6xZY=aptUmS!TzNdSV zz8Eg{YL9f!9M75l?$kF2ls1(Je3R!+i;hZvU{tE?IzA$Ev9DVz-R~u~)G>V+q1|9< z#WIe1`Umfm{#-HUx%Z8MM5qvnq!`menu5SivHAqTBYuP6yi}F@+Utx5Zn*%hc1u(?O~LK zF4dbvd_>AXxOY5+Z;xyms+SyTjaM}&Rp{)8fW2+?qgI%%%o%9{E#rVQRw!^^1%WdW zR$k8CJ=wwIh3>_~dHbkGps)w0edFKp9;y8XP57cepNSbKJ&)##yoj50PJ$}EUps3( zEp1>I;OctAiE07R`D)9Vq~)s)XK-pR(LCAd=N?&KDg>Weeo*bdJ~G$!P4TKsFfVbg z2I?OBy5Lq{cfnhVLsf3^vtU0qyc@iqwSetmv+@)3>ro@WbMw`<@E2c)Zt6mPZt*%* zgf)urZrU58f!MThtyz~vWc0AjuFc?;YT!$XuqSfIa5b%@5J;|Jgz9T;;FEbdS^eW` z_XQe$6G3rXr}=A-YO|KZ^KJOG|9X(iyj>npI4V2{aO*AQfmvpKUa(gU&Aulmg;~z? zhKVKan&&Pz+|f#)`7}*6OZS^oRAbmNp+k>?i z%u@UQ3$RnIJ-rn3&36aM!>;Ex)0XxiBylM!YiMOq&-#4$_ubKqwXQ*pJz4qeX|?ws z?IF}ms3U?rQYd&YirKD1UCL{-O!TFq{6 znK!|XdcwA~RKF^~-e6sdpW2f(r6P}Au#K(-liZ{ z)caFc?Nvoy4_7~x7z#{B&_|94{L&7&uduO%pBwsgY6sD+tuv(KB=#VEw6yWf2oS?& z%G6t4RSy*6^Y6YAy@uvrdbqu6@cXOVwMqG+jRSDGYNOb{hL@EI9rJp^Z3SNHA$0Sw z?7-W^S<}xgb^Y|Qk+U%n*pto{hj%o~-I?eyjS`R7snjxT1~4X7@D4$fYV81lEQ6>6 z8@sus`hbNkERteQxqR1Zmf^z@CZoAOa$l)OsHJ-5vQ?=%$LYqeOB|S10T!_;W5Y_Q zm4R_NIO^}$t9u`M6&p#Xe_0p@quVQ^A6IhZKk6TSJ?xGdV3iBjMm*rXLnR$2eL*Bk zW#|_*1F7bia~oDtEc~K|5P|WY_ ziV(TI(WRRI9Kxy-+5!_IKmWH>1B!tT%y;#wa-=?Bh;`h^X0Wva|IwH36cJ`==(N() zpYS&m(jBw(C4W!kS!6tnE|5fAK638mj}EmN%c`(2)*TW8ilx}rWz-#`+j4j05Cb@V$h*`%F1Q_2U)Y@Z$@}OPuWgy9hYwVyx%-~yxnuaE zuM7A^eA~19C@m+jCD*_3)(9KfdAd4UpgrEcaOKym@}cGL;vUZGU)A`h7J%IbKC!=c zjc2-SzUg_HyqRz_-vj((Cfj^_g6lfg4GO-_jBFd_@JFaSI_;J=kHJHhAD*7O8j5MS zYv?ReeK=FN%WtrSPpyTuM8`l!OHAUi{iqO?+Ld`u+W_J1>O5FKb{ZF`BY3Ksy10slNAtBdr;#t!=gW zo^4TQl!w~O1=6|SeIBTIW9$zV@G@X}E8y&YWwkNzkg#- zQuqIQ4G2oxN>*q#7=|2$5~kJ25+>uxpd{6%FLcVp{7pPzxEv|tBz?J96S`P$M&lWX zYQ`Ii+^X+2v+0T%7GbWvQBPTG#V+X&=4FZc!q`(D(n8&v@3R$s*I5W@LVUPv8f6yR z4j0k6DFI{@fy-&slh$gu1&L#zgxDopo?%As(~Kb6@=Q?JDLc+w8dNSWXOmh<#=VtD zr8Wici@)Moy)^Bhm>ij}6rPV8(WMNC+tAb=sh}@&`Jh6kMO)~k;6|kJNc>_{k*E*H z!+{GuO9_22fb6Ts&FBt>FSJvlPI%o$HwrI7ci|g*2k(wNw)t7;89ut#Q^~Dp6E_Yn zadm^LZZ8FsXTy0?2u_h;Wos7zepy;LpBWFE@0>Wig|KvOwno~PMqQw3i9?IFPdn84 z8!cix<7?&(ME$+tSyP$7x;53>nrs(*AY|(_>ChE}wAAVjJ!H+g*1eysO;5fF6aIep zM%Lhie6;OWGxYpfO|n=UrV)H#|B_q7^`4;7^%%*jELib?PxDqs+{^EU?x4o$!mCRA zGUALV4sh05Ja9^iu;WvOMgV_b=8@@oLQ* z7w2!AdN+Q}=!?mfEwY+Izi}}C<4W8A4s}g``9%Bica)HAiSoP>-wFpq+P9Eh(A@_W zy_YWye7xy-4%2}jY*2_$E1$UB3_7X|JMcp)g1a`^SaEOBwr!rGkR%b7v3eNH zqiDh#FG!Y3FwI!Xt)RsgXTcYSwff}>x^O_NW?avRZXPSH9t@ivRMx7|WhoRxvpdoo zX5lOrRro3h`}$7Z#p-)AD+mi@mMwj;HRymcyReIw3zdG&^^{Du+6*pioW+z&Z2if# zH$GiL4=CPM(C$Z)D;DAvqh|PpT>sAjL19x76zt;Od0fbhyYispOzMT3cwRicl2!o? z6(=ag_mOgi2#O*}%hG6KEdr;Xg6YA%;E`r}CDp8%6G7qqk8M0!JvrHC;dAV2AsckDG851&!Ea4uX$i5{KM~>Q_J#q6K&hk^)9@%){uGeGQX;zRDYLS z;~O4Z?261ksh}3IQYNU^$WqfOlM^C~MoDa=mu*0BCg0$T!Ma(vW6;o@a>~Ruqs3m| z$7WV-r`&EJuJB>uB}Z+(UB$b*CFJKVm>em~!`4kN*?*k3brFw$V+K*A zpz6kdY`l2FTDT+e?va!o2U}2hZuYH%zoYPz+2|V8ZF&0SOmoU!@SMpXF(ijdVhr(^ zds_)38H3BOl*?%495P(#$ggHEMq|KZ2){f=#@JW|0R%ZX@-%i41%%ZZmRn6{Q>Uf@I;wnuM(&Ihg-gPbLY&li-Nz$5Ht z-_OX%IE|SH6$8h6f{%r_W!$Wqd#6SF&b@jpH6u-N%MJ3!FNC=?f{>0AFoKokqMC`k z44SlNR`p1Bqc61%O2~>Cq(Y6pROnU{&NmZI*Yj44enZow@^b22Ls7-xQr&oPCcS8W zO$&aDo}Y4VdA- z?=-Hs8j`nWHud7zd1o_yPz3%$#b+4AUcIxLj_Z#!976dmt+t|oPX%bR_P$2puOo?^ z02avVGO36jrb`*o{%5ORT*UW#b3bY`|CO_n8UCkw#mEf=CZ~A@SZR-^V|{YscaM1I zSF?ptFM!Pq`a<)F4TGuOl591BI6wINP!94C$oE|-6#SBC<&o6QY>`C8K+-bF1b~m_4Lxbo?Hb%i|-y#j#0wpbB*K!y%%P&B0Hs+0bQ2Z(BxUO z;j^Ub*@f#m$xG;r6Pzl}lU`4;r@Wl7Pnu5(mFN@XF-S#6JZ$-E$6t$vu#A*!)BH|DmyqRsFD&E-SF98 z9TxqU$8$Yz)1BcXC=} z2JiK*&7?0e%gM^&TqR$G5HR0fS1LqE!K1W6wCECg7wfQ0LSK#_Bs9)cwBkLk-FQvc zHV(BpXAHu#xA-=&5a$$T}P4sJ=2;f<{dh2r)x*}Q&=|3pP_sHvk_IomAwL?^JP z8863r2BnOK%X;qnx^i1r_*xGp-1FG>%!Z7s^n9rr%6gQ)Ma1jdsi&9K&ce~ zx>Ee2yJh44qKXG2p&jy7sq7%5;?tkb+xilwjW7CF*{6#V@W?hb+TB%-d>uy0^Rj#G zQ&y>>iw1-;5n9Wj|8$8|-knZc8TGoD)6MRJKdEn!Ry#L;Lp)wgeY5g7{^F&xlP9`9 zcr3d55ka=n$BWi0g`GcWc#`s2@P}{n+l0~6gyM4D?(Wyj*Ms{=Q3`4w{uiCNpajs?)__?S*P2V0PYr*s}_ioc9qHk&%`p_oFH zyvWgF3>-JhpGsscaZXOO-E1|xzDbThm;xEgWrXnakq7mGjn9i2*rftT$h96jnW3^>h3X$i!4wsViigg5#c{baca+ zJ_0MDZB*@A?#HBI`E9bsgq~E43YW;pE;!EGn>aR#+A6=00#$zHT_hXX6IQL5$dAXj zysD5*R}+T8zF)wEE5sWI39{7$-`$b}3KUcwTqmlv6rPxt2xW6`5$8NM4mm?lo5T%K1~7~%PqdOko#pl0dn%f3ej^MTUOa6U zb}2OKae<2eP?5tX$lpP)#2Tv#`6|Coz+^0btGpLO9Xb`3HK5b(FtF=tz|T^h?(O}h{Ff#(CtyAe^e*0TVH$FZEh-4UIJ|p%)DPK-HE0Z=^ZD()mu5+Hux-`*n$UuE4^vR zpIgeT^6!$~Vh(TGEs=v$>PMG69NEn}1y6(h z3D-(+D0{L#;KE{etG)QD`Qfk8k@4x);yCaM{31|9b-Z5*h$;pDrR9627B3UCLx0mN zgx0>c=)^Whp(b60370<+|EUE4s58u%)(MDm7hqKK{sse7D0$+<8$=OI9bs;sam!?5H+CVM_uH)~Zkv&6<8j@$O(Q>kv!1@Tpdpl$3NBz0yn2*=D zmc=i;$%wba07Ktk<^E_@IMWZHq&b{#ZTZOA0k%)Ow--rgWjv6_72ap%ANf_U_yvG2 zU1NgSYW(nCCk+;8?%37O81i3gteSK%KNFvrHo&Z!VZ;OJ0v(7|0r!D_Of*uYE*02Uur=Yu$wTa2VZl4EUyjnH^n}Y99rbRXZ1}1 zt0h@yGx(UfBrLS^AK~|oynI#o-4avkQL6m}_#(SPf%80QGm>)n47Don?<9d02ksTM zM%0 zEd*daq0DY>=$gmNVCSSXAC1gV-zySnK7I!){nAL5*x7NH$f9Y1vwDYu06ZN_5&9rtWbO zObGq{H%7X~fCbCxFzWs+dRl8 zy$7{&IMO)O6S-Xx5T>{sK}Mbv50s3{)A#$gdLw7^KNrTIgwJZd6FrfPaJbW3 z??|)W+4yHXUxcaR=I@Xceifac(C?j0WdixZ5e1ho^pN><;yMf~u!$EYMn5G%?IYb#^-ZdeI%tQ(rzwqdi%pnWJ{ z<3ZrBuDBuI(X`Tx=6;{QT4J;Bi$h2+k3;3DhU8&%%lWm(pyV&HQ{TV<7Hw2r(!x>r zYUtqRL;l*-)Ih-lsZl)|i0MsPoV!jBe(B;}Uft<3YLUONQ{5M5JdnBk?FStyDNwLp zf6=83bT4>>)6Vbfi|r^G&z<{C5|gifao+VvJ>y^b-3?WK_gxXtr)L&2Es97#vkC_@ zf!nhQxIL}K#wu6;vvFZ$F~k{lbfdXul0cLQCuw*%DZJp%hicrdLtlY50|+6_ZT|Vv z_c;P|go*SFg3RDlq4@x!K}Fx7iMzY-ddD0^|NhgGDr5+z-p zcyi6UIJB|j+30j-i$mNa;6+b=h7LI^dKvl^mbwNVw;|r?3tWflO*BC6>=|<3#fGur z{_gWllBinH2{(IG8drrkj^&y>hei89Hhfyn0vA^`A zLe_fy_GJEA&gj9Jh(4a(%h3veRNObL^yEFgIA>8_3pon-XznnGe+Qk^re1v>_VddV zp^5H`$)Ouag`hJcs={K5bZ}zCC6v1}7GdQLlH}%xS{c|;+UsYh=O@7h@fe;>BK1F2 zOE;3`X7!Y~VrP*P@D*$2X&@Z6VJdaMXDD~lw-fk|Nm>w&#W&B@qLVk1+3D&7x6^lD z|BuYg9k=S47r-uL+Vl?%v=&+R)!zT^SaS+kn<@T^MGEe1Z#7vw%1b4+xI_0c;+BPc7w~bsau0M(If@+emPIq^Uh$68Fmg{(RZi(-fpcuYVYsO^Z*HK zG8!2^Z%od-!{w2}+R)D=<(TcMl&4%lWa1&>Jbm|wiVN+XLg|ZDTe-b)}L%S@! zY_a2GI5<(i@Jm{sqnlB21P`u-gubn}U%2~r2URSKZKU3@DDAHM6g|6PI3Nawl)Rvb z1F-dunQ4@f0}}OhxIIh_2t~twj0&xSXYTJ0wx;h2>Q!eoP zHRFjZMLs805qrfC=V4ff zO0VRRwT0#fT468ql8V?pf~^hmCf?k371LZc+VMul-{HBr3AT`u^q(VW%e$pu6yTxw zJgtqBnLo1BF8>A`6aZ|FsYg(rm(kjnR$b3NLI2~l*Ff|&j!_F~BPmK8m46e;`w4=E z@-zwtN-0LO1*%o&(7~|EvrDLQphpYN&92C8b$RfH2x+@`?#-0Q5=z@16;9(s`%|wY4!nEO3d&14>bHHk*xN0vMLvBTh0RgVcOu$ippvl5^mL0 zTha2w)G{`rcBH1^+=1ii2X~%TojmKmqIc-RBPmwzEMz5bK}`#U0fNq0_3{L8>~e=5 zuK@?AENvZzMZf^aEk+JLIL$GCE>U|#dN3HTwsWt_Uv+Nh`x&rar;hE1G|?=tJHOAQi!(=>-+;8hR|YJ#-Otm}q~W_fQ^FDwr5qmHh>Al>X~<1eIe}aZ7m4@xd^D@Gh9T|8r)mc{8I20u{aUkrm(L$!OB^#B)QX0 zP9`Zjt{uuj8X&wir@u8KmwQmSBg>h}XixbC3Snq}nUaZu-KOR8-;cbz5L9V^J;7?( z^IdGUyxXiu9Y+3zW}T_#2KKaX5!qXg<6fUxt1nh9-nH@JVuE)s? zHOvHNieBaFWd4V+*~%%p%nZ*s`<75*_sr_Lo^>9>e8Oo@IiCor4fH-meYAD5yw@IM zl^bpG^t6vbwt1_+|2g^W+y&x3O`g~~FNFzqdU@-o1Ag+}ma^8ZX}3!Zkjfupf6R?O z?e(zQY`831AieGOtMArNFF{10Or&*c-yfBqRPT3Xd`F7@cwB^eX!rInnyQM7YoH=y zxBnhXiqBne42&J{ylCg`tJg5@wNN^ElsoENG_(Wubmq^k9ko3gFOO*2>t9uPn20in zH{y1A>$YOO(Ce;MDELb^qF&Cd>G?i~Z?0;=r2@q+C5b!hua)xL{GlQapwrZbcy_ z?N$)@!m44#wUaYpK=4sYf!-=qD(aPDrHr6ND;JSUsA7}>Jt(XgxFZab)p)M%v?F6k zLqf`Ve?AK(Yh3Ijp)sG}8U=o3f!DXa$tBAbpz{;F` zsYM&=lI>@FLJSI%-YfHyVlV$w3y7DOt+b%L`@qf+7s&3Bge^fm z#{QJVkI}64@n*tKgaqU6sXmoB?{w^`oMCK9_k(|3BD(eElmDPZG-kHrCu&N2>xzwj zOJ{vXvzz=#k8tW8=avjV&zpvz>dY43Wj@(?@@>CPP2A56=50S$!MxD77Np~LH#Izn6iu|f+iII!dC=VfM_KWR29o!8hqg?LUWeGrR3 zmx{tz0|!g8Rgd;wV3RM6LzwRDgx!U3RwN+=UT8n7V4(8zpUfKlRUjJ|+0@YTt$sK` zoPHaoIra1g*E*?P8fO1=C{cudu%ajZTw|cW)85Uo(dSmIzBs>z!KAHxQXA+;BEGXY zq~;$`M)uWgrG1Hu+sa@b_^!O|;^^)NUjE492I*`B|Y6 zrcIW}w~ha`a{?$_et8k*1AYWPAO&t0vVF@8wL2q%@5_@+xQz?^#$(Fute7gPB7zpbLJi zK+Jti8k8)d`;C9Qa>6U53f<-LIJfiBhnD;kuC{q>0gkKn7avrr3VWq#!K;?17yjoT)et^G5t0w1!(2N196xyZL$i^^N-O3zf0Z2{U}k+Qs8Ro`mG z%%Tl`dc<+>W^uQ>LQk{K8=q{e-LG!tZQM)GeN3Bs@P7eu-_AQc_;)}YRhG3;3(kt? zgYWw@e&7zV60U(*nRU!;@ksIE&bgm+%MZ;iWIku%`zMn@;J*h@eAV7lN?MEwf2DKN?`n z;rY`cTSynO)zxz-UX2+p~+z$QZRB9vTwqoP05k0z2gDrIKKdw%>%UI`m6 z*rV)wonuRXqI{m+uYBe%*y0Fn)z7pGLH_PrvzkC$;qt`90JLVt zO&){}K8F~~?>%8PcDGC~wp?^s%x8eQhGF&vgM(1QJ2dkx-K3wSJtKHA}ZV{S#q<2#Sg&~MOzu?^Q=JG}3vi2r-A*tLJbV!x_{ z?k}^A%OBD-y_(?O?-S2-nTFyT=1E1Ps3iqI=eb=oC=Au@V1HPbx__JWTUBFeH-_ML z+`TuybRe+{AgiLH<26lNyNd>zfuDjxHfEy3$PRmXA15|%^?2=6X`Kk0j1RfD;wL$N z+t@@~#5z%8{?v{xqvHrY!t=pqujhr!=7g9KNNe?tuX1aWM_CfX_E@W1_jXDZ5@r_i zW%lh>qviF+W=h{nO)Z4}#hcN{nXiH#6MX3Df6oV1!CoMTa^vVv+vr0N{SAB5>f4?aop z7Px+978>5i(><1D`ko4LBQk7>HmfK=Q^kix#%v2tNGfD9sz9uAs}MS|*2WgbNq0JF!~=ajEa-#U)|82xQ(q3t2!kpswR84fgmf;-25(ia_-FRw}hwG7r_g&5+r>mPm* ziJsu-9o+-!I{}NV_P!+g!wYyKlkYnYY!{8$R(E9l#fm_z2E!+U{CTQFEM8$g2 zbbS*JGF0~ciCo56{TxIouO9|vHYnH9C*G3#EdvqS9^`H0WS~kJtn0yUEgw zXhHksM=v3(p%ym;I;t12l57cx&_$s!jQ5vj&Ma3y6-4t2kGzcKGGX)*NaV{4J~qM|Bu56e=XtF=@IT%mCy9 zp5nektO6l~FgP91?cI!_8*zF-$*)~|1Zag1+53E;6W45@zJfr37cKa@rmACt`N&~- zMB4m^e`67q(v;I!2eVSwJ4}BpZ!DC=^oLyNcc~BZ{*peWcMV$amcEsABd*k`D!P_6 z9UsyefBB`JfmsLZx`tVL{kpSDM}b89Bj|J;ex>T|UJu)%?=1TLV#n`833{8&I<#s7 zRm)!mP+wcTQUTN+x>qZRUxEJb`E85$C;M-cE7=)3V5zDSBTTpuQP??!0iEfB0V&x5Wl02?rm}3?x(-S z>S9mum;9LmhW;Er@Dc0|1jw>!Nk(E|F`Ing#c@x6)(HC{1s*_pjoE{JNs9o@xhFt) zL25L>Ce`{I3zNu-zBi3?17zid=kl0H)@-Ki%cKiPfZVmEsrLS@?Zlzed;LExJuqIwILGtrzaQ;rw3#p*qyH(L#ZCNsP9*h#R@ZsF(_*^(V%UlJN713|^Yaan zlLzP1T|&1+l_RzUooq|T&2-9+>|(8>)+T`_-7j)yx3gyN**1WfzlHn^)zuDnzB@b? zdB2utvSh4hgkc2=8lFG$2dHd{sew8MZAGOW_C*~he+}}E^RCz%Q?}yJH7MLm09L%n z`*6Sh%tmz{3FHow0Q*h5w3)WQIP_oAL1uKg3HIN17MFiBT)NVq%K_xA^R8Ad`g&)NZY`(DTu%e^Hereump<`s>E<`@m&QS zn1Knsx;)tgIka(wh^+K1CCp5LoiLhCq5Um!i);l2*SXh2k!Te@&T*hEj8VLZtfi_po~wzaEaIb zw-1PiR+RgXEo#joo8J5wKwuW-Y@{zK+&pVS89KPpTqt3jW40k@^HZcEi7uOD)38U( z!X{#8-;dn;4PCy8c4=MMAu%`rcabr?3oM1~<3^N%7atxtVMd;Um?uV<5Z5C7OhYX( z=hbyoJ$2Cfj;-WfX|R0U0a50^sQv7NJ3&c@w(R$>yY2v!!_8iSeWHd(c=_M@H!cKS zeI7sgj>W*T_Ji2Az}l}rA_;+bp~ZfyK_*&|A`K_NX%#`+`+J)?#-wLxt?2Y46(&lw zV@#y4i6~~(ZYa!G)tevFZdTQs3*WA`!~ia%e`GS>2Q*nx#o=$SzSqjX)b216v#=4R z^M3S|ic1+DHuN~DtsOpa1vPyC4-wcV{!}o2(AyP$m~@(I@eLH`{Z|lO%72LH?qAd` zkc#cj?<8$fwNZJ8KbsH@KBExwNtD2I>_cmsRcIa*%Ng7YZsA~Cw_*dR@_dQ$0eyOaFK(S6tpaG>#})npusPsHD&X7z&Zv_T zaWd&(Qw~725Y7(uQ^H$%m1f0$$Jmwr4+c|DIp=)XRo=u*p9JTKnL)N3J*P5puyv|92HZ!xi{ z5ozHiaX>7tB*?1?;xK|Z8#v^HJ(nlhNC}%Pn;Be|BbUqLGvRkTPT0^yS_9ijx_ep) zd!L?l6!4t${D<`T@{GC?kcJW~-3C4Ld2=~8$P zve?(Gp2K37{iCXBdh$`3@$$Zc(cLrlmHEbDH6~ty*E`icyg~oH0X;P(vMwA{_Ub0? zA?bURq__M#NxL+5@f6j(^}6pC5*w=xwtRQ{!>(Sd>^;p-J}$Z@H3$9>v%r%tnJa(; zi*tIZW#49S>RnnfZQUeY>#xeYX0AKrEo zeV$|+e%ZcmC}HR3nv}!8VooJttJ&x+&LHjD4~8#`7p2>i$x5%{HUknSCwAmao8hK@=7cN)JW)x4JOa=7Hk%gjeU2 zWy!ezzpUy1RMrH>Wt5wf5+p?}izU^5U$hy-%~4tMH`skq%}0r@=2gVd^hV2X)7J~? zwLg3Xr5;RjI{szo;-m(pM%met>s5GgL=DKpkKF)5yv|0#e8X*<4K%MG;)6+1b+ee> z3=rVUBZ$JF82&*8IOgM)$g=MMtuaxKLuKE9EuKy3jN&!G+**cN3e_T(F90=84I$?E zldxQra$27*s~E5%+mu|98*0pm6hrotnz9}=UFbh3-`E~}495O&S9@31G2bq@a7X$L z^+#@};eRo&1@o1bkBWD0%3C(}p-TowDlD&UYlyz#v=>0M5GVca&O;3c_GpzPy5wyb zS?9D>xaJ5Xw{9KU^P?|B1-&Ah_x(KqJ8PDF^@reuf@rL9Ff@O!!)F~euZ7ok&$q`V zsOxqF98q&=JLBWgG(K+((~{ra7g1^n@m?^ObO-GWzEf~kuukvOy;F}ThNf4Z(T~nv zzmGskm9{dik0g~oE}Ggo?zQcA-p2R!6X@P(-~R|St{NErZ^MjSP`~=Q#^RSSD;Z`p z?7ZIQJU#AyaIv?#x|~0?eFx2~Y!aSt+;YSQz*s=5AATz_*SLHay8&^A!B1sx3)=;T>^LTtB#9r_^;_B6=DQs3*0ZB8D{lqHXPA+R1osdmDg#KLBfg zVhnk^ZdkM8&Z}HD#p_Ksx%st)jtacLc>)mS_%Uz99#oHCvbMesJZ^KG-jN54Q&Ui* z&<%Jb|F|o0rKKAHH@>s8I@f;aW!n}4ecw{>tPuu>fj{}^dsZjoRWnAS2!0X#QOo55%D^o~M9_OBUEJzPXo{VEK>m>zva$Ax)^E67ikJ%e#8R&( zW{DS%pLQ9P4tSSGkFU7y{gBtCss;;r`ERPhOmC?^rhhcflX#CVX@j76d*j{jxIZU7 z&M#0LoeuC@k=uN(@y+8)t?9%@i&vN9t`N5o#R!eM3p)KUb5N>v_=w)KKyE>IqxoZB zkO-f37VQM%gjyz!4xj1GYHu;J{6A2Pw-to>EyXB<2#Vi|FK=zoZUk_o*if@J(}FTW zdcGBu0%2Yvt~Bec8F?AEVejDUvj6us&i`+1ng49vu$6l&d)uy49!F%FO9b<|`=G6X zA{4$YO~*}zf4n<$1!^mOf>6>^2ur1nr1wkH<>*0NW2f%T1B&mp(I2#1E`3}I4U;&q zU`ySQo9{yz{pbNcKSPQ%W}$I&4o|{4hlVHe2@Bo8mnmQ9P(80fU{u;!WRtEbsP`k* zC_YbgK}}$u)z4w3{a>$gQYPL>B6o3lhua1pyoBxRuRdR6x7uXeJKt?&!k?)WD^^S3 zmehmI86C8+E^CqN77+iW>zej{>vBJI^LVM?|Dg@_n~UGv`==K0KiF1(npWQtP1}H9 zKi$T}|2tLn+q?fWRrOXT>H%Wil8cof&g*e^_EHDsOa!D!&Fi0yV}VWJ`*!ZIS=AIs zz#Ry?vS74^eZ{`^_?slcv=6T>(ZJ1mBa(Oxxv~z< z1+D}kODE7-aBTR?+3s_t{*pI^^_?imUPyPwg} z70Lg;2BKMKWbrer?l-1xctfCInD%Az+7dp+V{sp{$}Xwy6cO0MTdBaMn@|A?`Pamb z-jB9Y9flPlQ@hQorB=QivLa&F2o z-)RQ$p+UfCA(%Dx^50V=#ebzpAkfI%>BX^~R?_FTxih(OU>r%Oe-AGKW26^Dv9bk| z7n{4_`~C}iZyMF~y0&@l?F@pb%pxG741z+4fRO-hQ4jCJ7(`2}43uW*H-pFeeh`!QBu0)amN(Rja%DeXCZjb?SWb1Fn#ef1cd` z>%Okv#SpFEwoAf6@8tC+~_)qH4 zqm8r}i9OknU=Z#RtM%^0b}hoewxn@Sc2Qt*7mMTZ7BW8GJu(SJ4D;%Dps*_3#W2I{%~uUsfy5 z_q#d0$hXAOK{?Pts21#vtPg!O43;^6bdcHmYc#1JWgFPVSsTc?n%TxFjr$ufaoXM0 z-6vNr6sHM$wc09 zILFaO|FT-yd`ZIxH>0C?r1#o>7ysxX-~0hpz%~pMdGoaMd(TVGG7>)rPw!o@`*jcdiw^c3Zq<1SYZfdwL9_MHFoe0-Ow#3%Ta_t+ z_s)N z3%D-_RDVYs|0g5(xT)`+(#>P@RfoY=yY*T>`!`dxRimT5A9!r-mE+w5NOTd8oP@S- z^=JPeD?>x0x}tZE=m;&Bsg{}X3VhNcr79Oz@;R>U_#s2U=07om0R4=RjLL z|I7pQzf1C_9*gT)JQ}j;*_z_EI3(Ktqn$|V8{Px)kwI3hG3<9PTlFRTxt$a9clIZ6 zUmUITJi|-q>1po$b{W|p5|(?{Gx_L8nIF_h;?x^_<0n#L!W_j)XSVmMO3#3WR-Si$ zAV!Gv$na-#A?Jk*kyZGIs&?tP?HpiYS4F91mbX4~Sa?Y7z}NcF)T9Gr+>RFW)YGJ zyG93$J3Y7HcdixP*YE4XMpA(U@{sVt> zjq>0q?oTy-aMuxit@77x=Gym@6L+Wb4EGnCR(30%h3KmV{5o@KB4=v2dwR(DHnZgP z*y`ra^3dm4XB4S~W;vX-JVdIft}NpoLjN^%r@yD7V@H716F|3rZ@&r}a>&nTS6ScJ z7pf2LTnXQ~RX_|@4778q*;h07i5tj(p;d00XVq~;I=c02-{KDxV*^i%W zDQb~Jl8&s2LO&3J6Bw4pSE%ulLEih^h^23~2EcvvgZ5-&L%LN`^*n42v3yWwyD3yR z7^JJ#js>r3bW&baQ18iHCPs{8_m4h(eB6qnw2&7uv~fc*My~~E5CDw-(Fioti?X7O z0PlF;{rXq)_D*d@3-c+W^;YXH_m8BTz|Xj{Qur7Lfj7RTMK{?9_S0fBi1j4;8x?dK z3y*|iSTUX_a@!47J@1?j@j;9euj2=M358j&=j}0CSSZ5Pu)Eky1D&kCdRIWc{S~ci z%UVt;L!~F`E1!WO)NXMLulWuwF(3&y{dRSY|SVl(*LHe8Ps+_rQk-x zpV+sN*CjX9kAqAO0<{lsCSylc$244ltH}J!h?;HO%T&UJfz-5KLC5V4CHd_NL;Gdy z2^nCHoQXXU)$phc_^Q#sTIt+y8~3*4UDBxWl7XZcN?(B{6U4CVv2?6!aCdzZK0N#C z*VqXy%~U}78)B{23w@)OAkc6_s6{SkA|XUo!2$XJ)WYcsNb%029*NWT zxFEg}Xh&I9^6E4Jsyg&IsH>z&Z}Vt4-|xw2>Iwl~MM;B)w=_}~yks3nr7pmNy@jZP zTpB8>p>ZUwJM5_?0!T*z(Zzr0@Zd9*TW}Axu#2A+@rJ+d*;OR!2aTzlbN+9Ai0NC% z-h;(Q(`kx|=+^(aJo_n||8AcBz5c4_`L-Rk+XaNZ)8YE5m&LIC#QMm--k>uBdjL6W zyd>Ybe(3R*mL6qK=M(9>@YJFSwa{AWpvvcdq@yi~`p4QqY2d)@r6KPur_|KGa=+BT za!hsJAuRS*6T0$f3u3KvVw<#F|9B$9kYzx4s(E$__)&H33(dvC{xNN+H(jt=@J7A* zM<;WJuiczWj4Ntc_pgge0pMvnJxZtln5 zetw#_QEDS4{uHTG=3@AvEc+a$z1JJH%tm*kF{BI+WB8NNY!jBU;A3+aQ(k$ z5ea0Q6+wD5{f)9Qma2&RIf?7+HX|r3T_N6jg~PGN6Y}W7Sjm9e_7H zVcd^)UXa8a2Ny>EF~2)Ev!ECKIl67}e&vOwy7%BfFdAHRa_^tt^g<}3blM&c^$9rq6(u^h$tQ|6(G6-fUcWRA z=udA_L{=KqQwdlUBtqo>0eIOzBa`4VFX=ekaw*2<%GnXX=x=rh2&*^X?Xbv}!uFAM z#sh_1j{4$({VX$GP%llixvHo5^=Ua;50>~{OErk5647V_MRb_U8K8yiPI@7}8-e&K8^C=cM# ztQQ9tTQdx2L2dLNwH|G+Z~=p#2kYo>u<4RJ`)~NL`bX2&J=dNI0>r~NE6^kh1vYsxAgtR9;#lv(r!4~R04#cFL8b&t*E`->zWeH8&0%(;Qjqfp#*{tG0&j&p2Ns0?^g2ew(HH8WZB-kQ{>;C zLHVw%N88E>oSZv9R$_L4PGj{K|1GEZ4Pznv%iW zKM@pNBV}daq6C{SBU~>;1@m8jX#318Im{_0KuRrW|6QINf(n^iW%U?03;FC6!dx@( zS>E+R_CT;*ZBafZ z)zU)WzIiP^s6Y0aI}~m2Z3-xS z^f>f~({ru4@iZP<=BlaA_Iog-K{E=h72Uenf62G9STX3*qcgp~1IF3bVqF8>>b_k~ z>3mC8a6owS&@4Uk=SQPvwPX?xAr5o7`JyJWCbVhnM!YRNKBe8r@Fu~%qh|AWaWy-% z-d)Vq5Z=i)Js;I6toiEfntI0SFhnGLhe4|artuA^Ui<`qU`ZznBt=z{$WVqlW4m=7 z9_PG#1=COvJCWX8tCM~C8rGTborcJ;2frOF%iJU5hg@tyG(>1+MI~2e2}GZlzd-O9 zT*JP@SzJ}P8i0R1XrS<_grF1f$N`JlF}8_!?HL1RPOHVLNUq1ejSr8 zRc?cEJOpC1qScZ3FKo$FIrt8th#8sk@X70<=m(|ecyI-i;%tkiF6e#+(IqB_8+8b( zeQS~+qW9jlS5o50`F7Rwj|MhG5VzC}=x3}NHca`m=~D{s0KbcDhDZ52NRueN>i1}! z=>zI2gl|Np?@<^1(?!DN44c$r6Kx@IA*Q&iNS|QAa%7VXs0%q(b+AT05@UPAlS7j^S=R;O(`JR!=v{pR68~(hu zFR1r-m9eRFh`lO9B&%_T6g^x$O^z=6CytWA1ler#C zwnsZ<3@K|+Sc2Q~Rh3TB&!PA?E`Rjg4SIPqL&{yabMyFM*thSPswB0tjpmurIW^{Y zUv!_@9^rnO@gr3m{3(Ng6Q8On7Gk?|nsoax$57ccjfR3f*BbR>gdE^Gm{W&#-2CJ0 zsewZ_DB(c(eL?q*2fh{tg?MkbN`j*10PC~Y`GCXb*?WhM+P2SB$NF0NmmP9k3(MZ{ z$h4t%_UPJtWU32|YaLh1_?|czkFkG#cR1EAjj*-8&L*rV$WNqUx!!I!a;QSbtp}zNtrD5{n_&j-ot?oe0d>lV(q;sN9-s6 zL-D`mt4XU|drD^T2dwjz`kqpgis4QotX$a4IF~X3ot>0a&30s9yLqz~&?6et z>D{yJetter^v;U5N^SnDXh~TI zXxE@-FehQrD=Gu>0DB(o;;+n#GW9h7z^@>k%l3OaGei1rfYHpAHlW98@Ynq%`iFWV zZMUIxCx1H0^!$9@x@KtsK{EC@;z%c4OEVYcM?L%C>k}l3abb1dX{I*Sk}e4C@_Bcq z)eQQsT4h6vPAIpTFTuA@U7&D)Q8$(EQr=isn5X>nPZL3Mm6C znU`)%O>cRH_<-!Xt6 z_NZmu!Mo#Z*n)vp zFLwOxnK=mgEy{t}8{l#b*Vc(VvflQcT_*DZ|8Z;eXo6qPoGwmO<^*Dc6K zDmJdasbl_pm;oEJ7b&c~J(pzOtr{FzT65{=5#oIY8gwF&@0Z?nptdXl*x_o+Tp8hr zCLEHPJN)AD8h^sZ$i>9Lvzg}IA?U+iebQHThJRf|)X@gjNS<~q8|UXsbf_lH$P*KX zT|@Q76RZ_QJdra74p&;@e);OQj^+C?C7551|K zt==@&fEQ+@bzQ3BwZbch;#*HoRn*Jw&9amAW}p@q`Yks{@-~L-;C-0}S83H#Z&Dpi zb>c{m%hY&&lNWCw-nA(N8Lmv5cOB)t@Nx5^`uKp4ZQ+oek^7TY=WC}han&Junx&2} zGR4WlQCMN$HlzEW;-r9bRk48ZsrwN1`H%U#<_9yOun?QtmUOBGhIfM+MyyeVAC?)2 zgU%Z?3vi$+o4XWRm9R&UXK)89EphwspdPu2r~*`}kycSX##!~-gSk3*IAEeM3c3BU zs#c#`777JwE8kr^IB*PnXvXy1lXWS+hryun@hZ2O~ft3ujceuC^ZA-03=xzdO2^lhX0Qq`BJ*IP$Z}M!AmxgM|?-7 z7IG_gr1+R0JKee7*OT%v0r5tnTp$uJ!H@q{5dX3mp%m(J^`wx0<`HoJ^EHWU%`N1@ zK}{-cjKEJL%9d??`}*1nAr!fHY2{Cf0j3?6?RuN=PJ-Y6z(x9pqdVti(A<5SL6tzh zYMKEJy5GSIKAs$9yylxoS(Jy_JT z`h=QU372jrCXgzq&sY4#%Fb0>4sINRnTOF(Yxx@WEv;`V^`a z;b^z6Lq7{ds=3=>YU*;3G{j=F^KZyacoe0v5E0X=Fm=^bSVEUXA+bftaSnMW5Ry@B zaONxuFd^+bJ0HhASz3_kr0yaSQkWaRc1S@`erluf!1M^CiJw8z zRUsE;KS-Fc&O82;mds0MCV)`RWuRfX(&QH#-bQU|(Ssb6 zL{tV7BBJN^o-5%@4-p>1o}I3KY~&_ovwFKoo+F)<;VH+uE2N3{I0ZRt+L;~#Uhr^Q z%9exyz0v-{hqO73m?C<5b@mc9Oy5Ijpz4W`^U@}(BsR+>xFj=Q97#Zj&kYSIjQ_#f zR7K(XyPFixD=aj$X7LoVDrYn5CaQwAQy*3+QE|7L$rE)LlI66tY}fA7JTosS4GgnB>?pl!Pe9- zF6bwMzJ>Wl6QXcqea}Yz&Dmi0H6O1_OR3!UQjN^MLO&<}#tA!?gY4Nh4e2j*GkNFs z1&e?>OqEW-a8To=39KT!EGwJQkF`RrNMGcfuM3hXMB2NPSXPoXkuyf&n+Yq4=rFHy zLbWrghy2|Jf%_>7->cocc|A*4E^_5sOGy21oVy-X*r?#DpGV<0FuUr!pL_yG4@QZ6 z+K}l{Lc9DoK{=URFji*ND!j)WhJRHI?l0yKJ|#B#9@Yy#pv#u`OEPoW|EO=jp{7+4 z`(bd3=U)}arhISOGhjlDB#KoJ13_Y!MQ_a{S!SbX+zJIgiu_b}EEuUBP?4M&{;jr~ ztwP&fjLOC1;h#%J9o0|jf|*NpGv8WXt*_hkbu=!oV$^bBrvdZOb{AuKV5$*?M3I`G z_G#LH%_!H#vDq3Py1QwfAREMk_IDZfzmw$mm*CF^Pqc1W12C8R_OpUacjKG1y8I>m zlU81Fht7=(l*!a`y#2d!NB2fiRG^7OUA*2^2IbC&xaN0IBU;6>Nw`81avzbY4CD@z zjhy#SobMFLx{kvW2R`xY9#HmPRt!=U5Yam@Lc++6ohE_D5QQsN@P!euO;#mlZNX`m zvF49`FY4pJ#+z9kzASx#sWl}KX$w^$ORKcWFts}F%qnxQV7}p$HosVJbqbtR%ZO+l z*+aKuwLqWBofzxq?Sm`ADOpQjFh`b-uF^h6v!ij%kYe}a7?l&s`W@glGASMsm#~=3 zyRcA8jPA%hqlWAIA+gee9Vb7rXAaqYh3xNG)2I=RO3Vhr`3d-EJ?9a-L|3okNh6G1 zO$#nNhr7SD+K80J3pyhOx5Y*fBZ8e4Eie&8xVbUM<_{w>L!w714_n&vploF!CYthe z|AA{xzga?2k=is}s~+APp`Np$<|?k&F{O2u3%(M3LQJaUNg>T#xy&bVaFtC9eZ=s@ zA#;A9W{oCry%Zujz4}*)WZ&sf7k^27(DpSTCp1J{kyvr!{@G{fKE=cyfPW*tGWxF8 zsFCDx4ha2sZtTUi!hhJ$e^KSMPeAA5^B*R{^O+-gga$I$;o!3d(80{j50XWqgqT2~F9r5GhXUgipW)>!kKx zufw^HItUdRp|*CF&+aKtG;+H`Te}3l^#2R7Sf1&DYSTdKs)V}OZe=v5S1$G7uHlq) zl|#vO5LSwS=0NL(tY`NAGx^`qWV3NW66NafFMRm&>v4hSEBjHxNLizz5%EW#RUKK< zy>XeMSyeQ?ut6nQy6U5g*Oijydj^-EGV5F%DPEoO@h%-qu7-){1fK5UC9V_bg#7~ z%#mT(qrwZr$Q6^;8O%lzLeGaB!pNGA_)OMKeyOI7kIgdQ{q(Ckd(4Es78y{}I22cq zqn3O$xZhOShNQDwxk04`=rLz5RmX|fL{?!-OUKfKLJ^f2`XRTZFrUyz+(?SQZQZGA zoc7hFS7UQHqer#pFfe^qD4goawj#OqQ)P)YPDO>4LrPJ32M0E`PuLY)^|;mL)3u|& zB-J80dbE(nvQYH!wKpGr{}&LJwjPOxoBtr(!^y+v71fgkBDG`rg_!$k!V=xIc6CpT zPP-0IfaerN+1c1RiNr^UXSLbIdk)s{?8lSYDJ1~@7MAxXvSaODp0W%jJw$?c=YGA$ z^tOWGCM3;^sT7Yr*1*TeA7+dGQwyN*0*H~a5~^_ghPqXURh8gpz3}%RdS*04WHNyM z0tty4&B|_j9J`C>K-gc{V$Gc`-4HAu_ml)#;^}&+L|wq_{UIEiZp@q$ofc4wZSe#Z zjc0`-jb>|NmDr)Dz~PfZL=^}Ns zajcj#RU`B6ttKm=lF%$xyFQxSdgd(m6Q1EN5Ss!GnDuy%yry9Wa-+StBTFdFz?PHd z^3LF>*oVK}eVom-F#=LuZVvU0xUg3?lxX{jn?3+hCc8e7w&`7pmqhXQI#CfQU;xg)$H?7uWeN zo9dFdvulxHgqDDycSaG7nPW$So|BD$hNB>8rFDWy}HOo zDNgdmeo3Ec=mLs<*E1-;WnZTDGrQK;%=r(^!8$L)ciU6@9|w8*Ju@@qJ-xGH>^;W3 zR@X8wRs5*3KEk__?y4W+KnJvy&q9Y6|6vhT5*yeasG@zR(q^;-R=M&`u5?|;_l z&cJBiy3)b>@9qBj#>dExVAgea$k*a=Fy>!cTuK4rQro%a1<9aAfmB8jn>>vTdLt<) z8A$V5Mz-4$Dw-_sCyQj!77^ zcI3u;?xxu*NC#VOW%PB?1Pl`(ah@`n8J5sWM8>DvpEXDx$3lbOFFCirVMR%LRor+r zo=4~&6vav9Rrr{{U|O{iBV?z2&q*6+c|C=CN!mwcY#jwHb$u%5WD8kQ)%Q-ed9i?A zXnM=5`8Kr$5}DOuw;SCAkMq_@NhblZeM&bkJ>gbiN&+ID&^e5BMC|kkBW39`?SYDK zMSF!X1?tXsjp=hq1>*_J2ZtfA_v)#36r#>R-}MjvEQ-u8!WBL_q&@}aAPM*m4z!0V zaGG~6>D$0IJT$8^I8xA_0Ex3_Oxm22LodpX-uR$XiP~Y5m=Btoe?=Gkt(Ft>#iFKyrXM!nKST! z8)?fD&NrY%5z4JcHB4e7Jebv^H?lg;M&_VCOjx5dGx>cer`3Lc!PQfN8iJY_iZ)#- zK)EV)dx(i9Myf%@(?y)si=scTNAWCW0Jwe8tk>X6e1iLls=MIOO-vY#A}FZaLQcY0 zR{o3$pct%H7rM-(H*7D$Zp$F}Ng4JH1Al#GG@U>pTmQ#sOFdjaKRd*H<+Bsobe2{5 za8|^TAnLdH%K9(qYS5K-pChT&DYhPAJX1lQCubDd-m!pmCh8R7a_a1+gQ09NYCzL|;boV|5`(=(74t@`CIXI{JUbSUEo zUsPoE{o$*3R!$xdk}}rc+;y`-qj$Y$=G4Y|$W?5S!NL*JTE&s!;Idy)z6E>*Jt}=K zpUiQnzbp1ozmp_uLxV*As+L_KVe}_m72=ESgYxf)?xRs?P@jD~l6V1(L#U@$1IlvWlDRbeg?47ZwXX1rL zn-ZC7MXsM4IL7cw83+p^G93E)ZZ`YOetZNqXe@T)8KiN8#;^atSi^*9NN5MQQ(fS) z-qu&yU~Kpr91zKX3JM%qne32fByroJDxq5P?IP-Ba1{g2+*{!$EfC(KRtZTW@pm#K z)YS2qT?4P+gCl9lx=*iG8xPOInBr~AQ|7y^;s=m#ux?REFbu1<#ONL_4gj+_kFa0n zvG0evV#v?-Xyh`uUf;qaID2{vsc^$t<;9pVf^oa$HJljnhBI9v-Ez?iTF~Eau^J?B zvfVU6dE@=XXG>Rnpxp+{n!7J1tJ!4sDGmf^92ZUw2w!RcpjQ$2`qns*XHFY1<)bLM z_uuAD&Pec&^j>dm9LQ@1lG5S{xF}o&j>qkjgb@drA|Jc%f!96$} z(BUEBz&aI0$$Vr1Jx%?yhI$mfqkibLTigz?_WQcM+6_O0?vbyK3fCrE4X8|f;N;E2%JH|(4e7Bg&Vx2yE=hHG8tbTdkS9swVI$VrYJL~mBSXvm%xkSeacMJp)UU~=w?*n>G zICMb$FOK5Jp<8SIXb6H4Y%9qzy*I?tgm}jOPHojCt`DY+W9ouPldVG z#B;8kD zCxqVmq!AE4BGjJ%(|=Uk-n=$A2V2%?_k9RH?P&;mcVgPz&!?L{+Esx`f|VuoQFn1_ zKzf8Rrg>D|>~_pjX)L6EY{s{oUQwMh)sp2R*Iup4ruN5_ncux*pMenWR-N(U2ADPS z$`DOB_Pz0so2-DpXjTmjkf}R_wf#F&hY3R%gG`;hK82;!9*&l9d(pb4488u3ZB~Zo z*xwpgXl2<7R>uL`uLqNj%@8CXU5xe(tqTrtgwJvf%RjLbBsGZq(X*61s zw-4@ykBFuWfIQuvcBe&33HJwKoIuHg;p?UEDsy~f;#*ooRAl^GbDiM@_#TgUn=J1v*o57U_LjFlYjIq?VPL~X_) zh=_B0Avf%1j!U)5TF&sXY3M}CV6lW)=>EJ{ijl!%kN!&b8sA-$QLuQ2(Ip0Yt!^p7 zDXn%PO~oAxS1>l1#+%RMF!~<4uPc9UIBPT!_f#CkqVH@EeK!)nm$DBEI4)CXf}= z-{aiMa4!>RfWlwv8k>9Scis59|NWADY?e`g6lPf4V)eyj(|p7O3YCcyQ*$RHZ7|5Z zhwLV;95pB&!(U;%HeaU1Q7$!`WJA7}dYZg^vr}nM;du_%3l&+3xZE#4*en^ZyIY3O zJVYo`HskI6jGXbyN$P6@FC^QKZu_I$;W!x}a~pvP>WFzRac8#u3U~7k;~Xo+beDhR zi3zGCf418!iD*4c<$(R+%#v`B4 zZdYI}JInmEz}#(Uc)b6ZS92jZs@kJ1L}sZWBZ}jB(v%-Kq)h4r<(YDu=W@q$P-oq( zN)tRHWv4x8HSizCOydxK_+e-IEAH01M{820*>ld!>9Mcz;2O{y&l%v!j1l+C92|&I z)rB)27<~slM;k~x)Pg`XD8YI^eM^mC1ozezk@=Chx7D{r3t440UK^#f&Y#E6`1x*M zSb#}(<7qYFzeg}|8|^UC>)R|}O@Ad2Dc<18h;_fh&=A)Jvl#fKF=1R0%r#8IEAB&V zMt)X)L-5#zwqP{@r7qz zy3L1wY61V&m;UwjB?h(ucToSGpZ_xt$UpU^1P|h;Hz?;Qs$YJYNw`#I0cI z5{==$Grq#_{J%V={hDyi_9pjxVl>jy=bp?Z!UsQ>)(qe`x$W!UG5I2G9k;Bq6STeK zuaa~w8}^YOG?|hnCOw8=ZkW%DSV!vvB=bphidxop?%v6=*3zZl{ zqz zV#R#vsRQQll}N+BqsV^$1C@m*30H@^KUElaM=j3T6X?OtiDnjECP(z~`DOw$Kl*1* zOTSMZQln#?JHI<@ID9Wq&F#VOVjH&R&Bz5gy&=R;_X)y!Rp8@rPaZ4ORE&@Rw`1wwj-~&oV~Hm){7VRCP<%X7 zX+y)s^3ms6N0uf^Sf^%YQSkYgbh6p2bjaXkpJryj{a*HcB*Wu;neSeXNNROY@%hXp zBf*v4Gjf&fD7_wTlTW-uV@(&$ZV*KYJPjcePX zVf7@cH{I+urt+XRTq`IP3IQ5V)2G_O3-tx;A;Z9@kDq_>(NWZzC3{2tGo)$Ep^$;a zXS>hO4{f2UB02W(h7$D^299sO?oyMV{8V)I3l*?`9|^gMbOElr;=n7;2(1yD#*J$| zBPFLb<+?+5J6e}+ZJir!TDQY#4O z+ar!Qv`V2LZSTKiZM(OubWn&)*J0PW=JUs`OqT<$H+a*!c?FM$b_|h6pR3a{Z(HfD z@AMlyxbUz%MHaz(tqISyTyA0aL-09VR_=eqrR2Y2IcmH*K@io;OhEEW*b`H7R)V_u z+@wI^AYw2&w#*3Jf{CXa!5{iwmzn2WZFBy`M>*lYoWEUHFo9e zin%w*Jhp{#udJ@owzunGN={#$Xw<-&o|e2JLkWK5-Gh*kUls{zs-wM{P|64U*HgtP z0h-c!0ikOasT8Ucm59u1Ne;7>YY90~L72_~i+PL1LG&;>WhGs7*ycsz9N#OXgY3Y^ z>*@glqPeL#+(QP;uln7Vi-7`>9Pfg0rmq#?Go1o_CVrwQk*XVk$HJ{1^z#fVT+V;I z=QRt=I=^HrF#G&rY^cC#w5S1-{>K|aD&o@+;(*M9k$JIF!v~n5+{v+}IEa24Y$jo_ zc||&Y<8GcM>qUjtJ4rf#IvebX%$t;hWB6CziJk93z0!R)yhp`#T!QG~3TH{`x!GXu zx)dyR;VNccDw}V;dkQ@%VVnmXeO@wP79;jTtYddPr3p&fyEv?*gZ0bbo2Ei;P?$k` zI(0Ix_P4fGtUzS6J@sIc*|)TG1@#bAqz6L^hmA5AFnS*{mM6$}pz;#XIgapsNdLHUi&RlM@p{ z&RA0T$h+Nz76z9@A@{3;(Xft!X6HrPn2eVU!`kh3dLCp6yx>|jl?_N##vu(Avg`Nu z*^bR$UZ1)(SA@l*{`>T#wO|^T>M0x9NRuKzhcTS(6IiHMDCAGTP%0ah`W3%q(QKZ$Zs>>pul)yYZWU zr|rOHdlIDWP+R}-M!Uv5P+;fNuAJm}-5Pl1l^2(0?9?y;g0(7Ixd!OZw1xWrqPmy+z7Gq%)UPJ~fAyu+QXNV?fi zi9^vTaK)(mMJwhteVmqs{;rtm)66skQmfQ{sA@Q>y_8n2cRLw*{zYb{Avtv-XFT-h zo#5-Wb5W1mw$pYn{cI9Q+s*4l3AY{+V(7;Z7pFA^%yFA0E{|I?z zo6__X?*BFO{25#_+?AWmyRyy?947}#Ct-sM%rW*CwB8S`{>5_jnA%&`(C&~k7+b=! z|Ng|`o|L659v7|*M{dEjaA$CR^?H&^p3MUO-igQHiOzHof+|MZtk%8%QaqTlY2klx ziLhWYZ!56BZnqT(8P)u3xNoAl@bD(xI;6_OYro7%eRUBTrn{={4_goH3AhTG`M$$& zd%^l`0JAMwTYbs`;b)kBl9_LEZ3ajd-B8<6S)Np>aci*7{E^z&>hJk_c=x z`5$Db-%jrCT|Z>lAzv*B=SV4qTHJFBrd(i-0bj1T#xVHoX;?L&-7>$V0X<~*z^l+; z`{b46K7~b|#9ZImla^h-i}(TfDn^q;87O@@d&qB0fJy|CwPI~FMaZmMpKh`6(l~w7 z_e(4?9!`?Dr~zzLz+od#vloiXw`4qE6yh-9RUSuqCJGNLFD5RGZTk|YBswLG&0#_( zMrN>+g@JaE}6IdBs?Oz{3&@w zlE407ChlxI%%5G>fKD-*G{#Ub1J}Z2D=&G`PxM~XMyzX`TZXu|v=UAY53FoeqoYl` z4{8Dpym1hU)WxsgGHYDP zEv*=JeKmZGG~POp*Risc`tx5k6sJN?RJPj*5&yz+u{NXq^acKEd~OftX@gtpXVe2=IoEnz3#7OW%b0vk%QQ0V$bb0xb~^9wYu4t)>LKQQbJrJf zllU5+Jdt<(&mSg_{;iIQzZ`6SI&^W6+}C&4RHv@gkuIxSA_yOa36}N?{~3O6&~>ST z$QmSn3BD7b8AQ&KMe7mAKJW_qOJ>J}7&qVB^bGik7+A&3g>6gt8?{ag1us*b@B9^; zMhTWh)wD`^JL~s2)l7PRT3DzEtR7m1df2*#p|q?i3o~{M zdwJV!CZ5OO1l*)!*IhCKhYf)~kHoVz`tb34AVtz|$+c+sI0|r1v^|ypH*KgdQ)L@n*t6Cs(Z&d!*b{Rgkb19`q zJF9}(q!wj{itCLi%7*Fh?OD7jQ!97`WJ#UH{1uMu${hywc$xF8L;h+Ke>@ZhI_U&_ zzrMO1MrOq|FDw6!)RVAHC(oi@5VJeGtvN3WG{E#zgeCb{ zHthS_CvadmZBmqgBvA%bx+I+?5<0;{dID9sFIdvDW6fG2GGA#YMU?@LYWWVZeisyOhak~SEj`u4QUCG?UMPp-UC7R20OP@F$@8pMkjO}{{ym90 zALK!^iVQAnvB2yilsUH_H^6*R;)Q1WsYZa`SEdd8kRYF3= zW4w>y)Sl&@!2&hgD`%(aUenL65)H|>-hwCo_3h=3#-jLX5TY@_TdFB^>3P75|71cc z5!W$|f3G8jXQakt{7&ENGQTB~p5}U_uN}+yJ=kC~Cf|$0Hk4uMbsRAXX{>lzm=6}S z{4%*Rsb7a4C+mVoq~7C5j1AssImc@wpbOi#lpYq`Da}cntl}nEv75QvsQk?Z6{=jwc4%UMUmvw%0TJ5t97) zhuZHBg3KY*w6yZCm#5bLzcO&kw#)pe8n>DgLcw=u=a=R6H_Pg@hLt1BpnY8)iuU$L;Ex5CgW%J|!@ z(kRRb%Q>WFWWSu*c-q^T^$#z4xm*~|2E}`x<}NH!p4iM7^Av9Uh*=J~8m)p{xr!$C zeyHfFOAR{J{$@$Oq1v)+DkMf)+$%5le9%tDCBv?W%$~Uo6Ze@SWfjt6`t)%3Sql{+ zp02Lw^1ervRkX2-Gg>sg6nj}M#Y{-fe_gQ2wQSWVN{#e zw%By6*1K%iY@(Uq8%gi6F5VQy2>hH3>_vlHbQ6y9lxuTzkAP+{eFz5@d^x}nMC=&s zb$n7S2QH$bhsM;&>dfi&^}^+Y&h*<<3v_PmL(cun2V+m5A6Qa9>|m)T#n%*soB4R5 z_T;vtH=o6u(ccgTz|#JM8=)V1uui8pq!?+9ZUpY0Q`ZAJX^ri#g+Q-YMuGGhFbVle24(?s_7&VdPWrc< zvSJ=K&@@7~&-`i+O0-65b{?7F03V_{cCQ77Q#Hsygh}d?NKaH>-Eb!8M8r{Mg*OY|7 zF}@D8%-hr}8ixnZKxSv({XyoUJJ zq6d9IGgcolXZ+{#Z}`9SZ~xV!q{1u6&kCUM`TuH5`)lpt{xemrW_}^>T-H*I;6Kve zIW3*~mCCXj(|uJ7o}uo&8>nbn*OhKYnhycDv%auvE}+IYFC#fW`Hz^$ls+ zA-ysm4jrVds1k44rEjoncLlo~cdJZTY&8EO3KsPKweQP{iz}0R&z~rUWct5jhAGbY z_oZe$^QwJ#`fcB@@S}I!!U}aWzqWfA{k)$!AB^~U%m2V>2s; zMqJUU%s$DXclwrS@}siH1=6Hax;m#M2qB%Itbl_RjB2u`*Sebg{tx!vJgUib-S#aD zEy@P5M?k`|P*G6nL_`89ixO->L_nlf1f*9YO-M+}4wNp^NF$h(qM*_$LVysW^bkmt z9s`NAp$iEF(va@H)LM1V+H385_TG2gea1fb>@obyfdOK^?|Yy5%=w#lg59|`J15S6 zIG`zAWfJ@&;?vhQ>^o7X8jikyEkj{GhnNC%C#|Oc7wNeFuOwmcImLU*#pwFfvg-9{rW#!SAeBCQ`I*%!ZhdEa^-0|F%5+hb&L;XKbRE z_C-JP`##s#F_K?%mtaRpyMC~q3%wtafZGlAL3pZJ4zJPT=5V=vN5+oUY~hC%(R?qK zbzJgEKK+;-L zEW;=!tlI!q_wwqVXiWbJsW|KMFrvcu0b$8V|9wu|rR&LAp%5eJ`;}K+Wx6K;aUXJT zzW3bY>wi0Gl+~^Gd7x+T3TTZJmB#wr8|p6@fjppf`*uiufpf?UGpv=l$^5Cn`gNK` zVPhn(i$;eUpmWbB=FjboiSbjjr(KBb7r%e6>GfK5cUfJA>Ac?Cr}x;p7Lh%??0R4& z8u}EBb58?~{ql&A?8k~(ys}KTcV8x%Ten_5H?PYgd@^#E;Uti8RpFUP`I`S5^39VzBQyTG-vwywyl+K@8 z0HcZ5AyTD9E~~rCkG~vI>#J;9X}g(m=Ty(RT*Snd9;BRrvP@#xPlCS)!pu7K>W8eo zYYMm0=nwr5%$%e~*(vPR?5%f&fyf|JU>Sa$O7rA|hFU}*lSu8M*?$3A|M=w{SuAhY zTkGE)-f@_|Io*_XFIYKxIlNiGi&RoPw^i+0^g*w7jxfq4s4OV>#&JWI69AG^M7NH< zn6=;Knm*D0t1+cot;V&BTQj?Jo?)s{b(mZ=xI!W+y9_Ahj3-r>EmQxB~d!G{n3EOmwdSCP72p=ci>N)UC=q-4kpyxauu#DCG?-&@f+ ztDJK@q;Itu?F;XmUkEi3I3tlVgAP*!d zKMVirm*Ez!diz$q%izdd1i9IK4necrXnH?3|C`fLu-QHe{B3V@`7_>hAl0tbkX3V( zj(9yedaH2Kev}TLRj%oy4%Ft{3sjSqg`>apwrBdg;%AP1}4ezV8ULybTarSkJQh>JawJl}BHQf*WYBO|n#qP0Ga4 zbb@!5B`5D$imlt-tn-@>-boN1L+SN;)OhRjd%f#QQh7@6{Sx2nm9?87)8V(wn|Fl_xTN!PxeIFTBH{fbL9ZA6=waDmHsv7CrjkrISn72+HPGy3L)A;`AarsU z3&~{4{0|I)ACR+zOb_~&dT`+`znFYkxGjFNFq;%{LemFfisuzn zOG-5O(2_&)Xk(gb(P&w;kPxo!}JIGXD`NbLmg zo4|n?$#A`H(X-)qFNK-X+T={m#TiI8im5{2rwF36(?^%TbklzsNOan(sd2UmdHL1g4;-jp`_iMgUJacSc)Zb^-#!*+^XkA4BO}PKYtpbn*xPLv)R~;B!jR&&Mh$jLs~=jvWi@-UHQYyc^b^Ylm+3Ppl_>aeh)iv-!0Y;Z!91z9brv8sJ#at{4hE$$>h!N%713t z5#z0iiJS{9f6oZd-TCyFKn~amw*IO8l)5R~iRS7HO?Jtq(-*>jd8NdixN*j!CsYiQ zzT?%+?*~v(1I^a&y6vM1TA!}n#~NL$#mYYiT_0JH%hY>CX#V+2mzRGDYMP={F5cZw-zLD99wvqRJ{d}yj8W52lc-AjS81b0 zVmzb$WF{xYAC8(R!`&j(D`$(+rX5ieM))ehW)GdCka_;y&3ldwJ4d=x%eV^n9B2?LRk2?9 zNeG}y4JT^%)wsn$<{y7F^r|3kpt%2VYrWepB2n6+OfJ-;Fy%7AVe;(4*ijeec$-u0 z!W~6O<;05tlm2$pU#&_-1qS~lEXBHXZvQ*05_t@iv~^|F>=gB@U9RQ6(&G@A=pmDR z5l*GQFk~-^hmOV$UDr=$pD4aVEV^AldRBn+ZJ9Hs`zD6HC6pLA;iY8T zKJnVPCR@EXQ+#MoYbs9*A}du!a}`cCf}4*JC%`Sj(0oiKyMwS+;CZyS)GR%`M*5%$ zmBn@_N%0OI?{Q{A?eFE<88`nQ}yt8C!?Rks_=e*yN$DLK9LY$ucrQ!s54U|XlMM9K1*-3cgU(4#b zZ)gJhJ-qCa{&=NZ%u{Wj%Q4?RG~Z3=*P7Q+gsg?(t3b@eYDTQKm5jRVgZ0yaaYTBR z1A5Yn(3iVze?CErX5jntFR}Tj<`nhQ`ImcbW7Ypls2B&0<+~r?ZW>&ij^grdU-7*dy32{}MOvH?2m>H}==@dbv#o2(tz zAc6}ZZMns={z&2*-~G_pXy*YeAmf2>qc*p9zLP-;)Pc>z6c#_=9{x&V%F2Pq(wTGCu;tDEBfsCm9VV~cG7dyF-HiPvMnDIP#--f#%MU|Zyuc6|pJcIoqTsle!1!oDk~i}%L9k1F zm2JiuAn6xA&a0`~bhO~?#Dgm#32!EInr{XJb&C>6TC0;ZY1SFBEo4+Q4uF&qC=r7c zf|AZKB@^W1GlgaRxgnylA#)*}5Y=gqi)z^&n;A4n2hK3f<1ho3bO)|v3xOM0q6ywAeqM=H_jn0)Q)%$0^z8SOr zt8v_N!x2-Mx0MdUNrAr4!6>Na55=-wHTO~Pl^=``>_zE#5pGIbu&@R9&|+I9*7JxV!;$j|$g1#U9sp`(dc>7! zzvMF3I&+*T!%tcw=3;OrX!gtWg#dhAc+lpe0~WnpBjiK;LcucRUS+k0)DVb~5F1;Q_} zwTgaf(3qj#)uVIubJB?Cvdbd{?l^oQ0~p$Ol>-fN zM_FJNAdr8U{=fZU+n9KsCTma@P9QCIo?VYG17}`y;U{H8yO$=i=w69K@SLrDG~a_a z?G*h@LGx#WVnjy(E__+Lc)`mltLLx2GU2Pxe@R+rMiJ&bE@@O)`@kqSYfHm%|7|b( z-^X6IuRZd)psyoRxxt7d)tEg7g4DSHO7cB#wUsf?@SNJ*atxr3|6_1*MP?MsXzsFw z1^c&(8n-`tNP9eBtSXwh@Y_9c#Jm1`V_=!FqXfa8!HEZ1FLn;W-Yz%ENbUe`gg@X3 z9M{kM;$rplAWf*|;?OwA&a8--b&C}d7|pH7$xQ1SlIQBRHjz7U8N7p%kDkMb!Pu-& zTwTz9{yh9uxqHTQ?&s_KQE`AM$C6yKxxOc}ug%r-WZqq0>`+MLURw%a`r65d9?t@3 z&1Sr3!?|@KB^P`nul~9M&B#aWhhAfP1H_Vj);8RW4L_Da!NWuHaT?fCEUi9SMvh7K zl@7P=(g!{<_Sz$naU{A z8Sj1q5X9?kQHSC;44=qt=S5e)+XM_36o&q`+7{QwAI%#f&$T0%Ce!Lh-{$rzQW5>D z_PGo69gf7m`@X`#oa);6lIy*XR>nP^K9HcGwZf;m8dI0w>+t=(#dVKZU-o!;7Um>- z!QhABDSl4@mxj^x+N9u(O+Px3ZU zHbL$v)`elOz;3^ZtNM632Lajos?T=+wdpJno6u_j56OpF>iUc4)@k;Y&TQDA^vrw5 zvrp{kID^uR=RO&4zD4hQK%2O|^?j$M(9jD~f3zscc{pI_@d>~7pv)(Ls=Y19^0~=5 z;4#*^w$rM$V1?%qufJ|K=92iA-ZC!b*1h(%D{+Q{hLM9>ZGhW%Y2k68ZfaiS)0Id2 z!31DwT*oNyElOiX{0N$K~c-8C>f*MtqOPTm<x0c;z3&Y(SVYGfmj>M*-BHIf1QpM16Mfc(FuqI-?3P|>))|0IUpjiIdTZpul>tb< zgWJD{;C}FGrUg+ly_~NCxXEEJ9 znexGEuPdt}FlC*{Gf|oI&y6i9`(p}R>MqFl{)u|W|2^t`uCAhl<_|zM3E>-zP1^Pg zWlpOt^7nv{L;cjLkxMQ)c9a%Co@1@huH8S0 zJi)(srEBNN>t`n$dVOziWMyWRbYSdulTN1Agr95bn}!^~H9pNTXiQk`Rg|y`-k!rh zOjlDsHj_OrSxfVu@XoxpPs8gcKo(24YX<0kLIbhDcdJ90?vz$97l0ptagND2u z5`H_~T>rK4+vZ68I}4v1SmEH6+b_TYD5XO0+e(h$pE_?!M~ zK}xS=7+0nYl?;?1lRbwk2kWYOz6Ii!#oe7u4h+sLm7$LNGIQrkHWkq^OLRX%#}V8W2po=Gy|lnCvf_oNl%kDmo@wjIJIiF^DJgMA3d$( zV(e4Ad-j~_!XNR^fDZ5@R29$yASiCRYjiPNJUc`IbG}K1jJZm27SmJUCSC3$GaO2y zjHQs}e+Y`UeiQ3nLp0N=>%cNe#Y~>E1XDY{@{?grM9od9XVcdOpm#NXke_f zzUABjKqWi+d>CW~xc&X}9Ss0Gzga;Lsvyn7MX2{2+86#y89S%HlvmtQ;}@>%`T zYg3m@0?(d5Rqp<2heIF+w(;0Ii(XvE2`25}Te0@3K2Y$P8EW-RkWz zG4%Pt+a|{+=Vue!eq4Z>tGxE3IX-Wwc)`Di~p1 z*^Cb*7ppXtn9IF{+OIvu;a^UwjPvC^7|}FvRHoK0;g-|#bC7ccxWbT3tjX=nAO(`8 z{A^wh6OI?>l+i5AOmf_p-a17OulM-iOT!Jj`5ZdHP@hcEbPZje%9jtdYGW2s@y7&% za2iZ5q3DraAwxjpj^ut)l-KD=>e!r{v1W{68xz@-x;9^R9!Tx8uQJ?q$PU9`vlBT8 zrjCVHZMtlWQSVX-Mw)NV#wK(XR~uq@IdH~&65-iW3EWdu+Yx zNhAl!M1qB2>WUoPX2rnBr7I6`=By8Sak3dY5!FYm&HJI2`#=vR46#^zt{lxh>#=-s zFcT*2f<=$nS;M}qB8RgBJdmM@#I|9NQ-WT?FTcT8 zgA0osCM1wLf|SYhp^eABeJ91?m%G_U8?)@^ev>Lkwx0E&EOMV4hA%&+UTG=A!3SLehl?Lux6J6Y%Qf zvDqTr*Q8%Uz{8sZdfFoziL=b~&1>weUP91JoXi9qZlzOm{E9^5Z_$Ufz;7%Wqp51U0J4k4Tf zfz*r-v6YA13BCpr7OKBbjj5k)cX+rXqhjdnM?-h_FXO0Et7P7_{`C@9n{o%-3L-0H zqi&x|`@3^Ii->1OMp*9)_cAG4jo%XPNTbe*cN{EXUMIC44Dd^pR>LQbcip~PlekE^ z1?4`lynIt{s(8=n(qn(kcQvdwk@G>gOcu2u-TIgj3Q)Y4Tx}|*qo^PTkz&u6fjJ2Z(i-;q)Z0-w5e_^em9PG2Y>lEZ+ZSq~G zUb8!65V2{*Jrr)p%g2NEyst!JBd(huoy<=ES#H@c{NzKU&CqeLVu%(ii3x#@$Vy` zG|JK@LSl_QMU+S)>%MEBsih`NUth5r4oQqhGQ2>HEXr!67R#UWuAHiq?ypz{q})D@ z;3HSkSESmtaKOI(D~*m4kZ}t$I0}gX?r*Do=ml_h(S-2^8qixb9`i8^+BA80zC{*Y zZV6dX7Z90J!W+8Gl!oBXHb@NQJXZcq5%$~hV&M3c&ecO?>g4&)Kr_EsBgbKu^FtPa zWqDKC=suIGR%;obv$*C%*s+kv(HU^vW3=$vx(%xoca`=;H19&rCWc75o=VTwO4-3Y za5FQnqMI?t4`W0bAt`h+3(N}>MmQPRVJnI%ryWYbo!5f>Nf~`=4vr9K&6eRs?fG)H zwZ+|c{UKy2FaXL$%``OilcHuq^^9yzO?N>Sa@LPylY5m>J^3P@u~ZyUJEbQdX*Z(X zKU^Hm4v;V3(_EM#%O20Tvc7(CxEqiUvGySKnVH5A>ZV&=E)CdqCJe^FJDTPSliIAw*R|(67BV9IPAuv;RM+eys?esbQ zQEAWsBf`r?kO){!DM1@H{ze%o^fZtJkzZM3xNFpmVjqG*OPvgM4`UANla53kyjuqC4In$Y}b3-DZX?-_i(E zQ#{eU+1;n=JZS8bh8~P>=NT4PKDey1K7;)uNYI@iu!2E-;`4u3k432QpFI}Kf8S%_ zEg;&o{tM#Z(7#R`R3>X}Bp;{{42Pt*dgu;C=pyli+$S0ARNkl810N|TF#Sz}0$V9Vp7R7#Q^6W1BIeXO~J#<$(ook(wHk=jk=XqneEi}{~Qs2CArQ}FuV8O z?{KKsdCqfgIH8W_nHB#>7wZ88SST>dFH!%g#)1JFSNr4gaTe9_wogA}yk`zAaBX^K6 z1f+Z}Fvjf)Tl^A^%zSsvbCeu9;e-|wAj{x}Fv+p8sG0^xlw)9^GpCXW7@miG z$veYif~~2L>%FL3wL9K4iMd3LfS~)`uolZL;Jk3J&6iR!(s@=dT1;n#_Ynt0{az4J ziF~=_lLhg_o{_mDY z?6hsvNKr6?mv1rNx}1NBFtTzV#Mh2Bf^$d-s5erUFJzDddmV;SOMZ*KMz^phKEbf> zX!#C4;vn&Z7M=;BBA*j%E;56iqKf7mFh-`29u8 zP+f3@n)!w1=H^d5L6k<&%s7*|5aDtkDLin0KSOp$8Tz)SYvt-M?R#G@IADO3HKf{r zSC81VX1cFrxQ3E|$(kJK!jaL=*b5Sg74P?8s@3RMJd|vVDkZ1v3 zlqJ6sy7H^~QX6QB1f3!tK9Kpes`7P)>u_7>_tB7CjqJQVamRnF3+hx| zSK{LsY38`nHkC8nztX$$QgA`|{LON{>KXSVYg5TePv5mC`(8hhI`pR&u*33HQyEBQ z*hJnpoq0ZgWZIOQ12`zxhP)bdvwj>tetPWR1Vf_8vbBWpPax6#cVtNG8A!b0V4MFZ zEEhPF1s0Y7Ob^HUn6lWeM?U3x_E6C1V4WPlIS}X}H^Coi@=wB)}J4Z$06tEw(r;_=U z()Kacjpp|iU3)&c8)74SqxM4^_9~~)9|yJF%x*y{*#Si9cHF4b=H;<8i&z);eScKH zf!uOAC^Aa04$VHTx=!zI7f!YHF%G~eKnEPC_Njw^I{>mUcTW$m;T^FxwY>*QxY9W8 zJ1cuFXOf*^Ck_!$6pbbC+y%EtHmE0FyEfc-JOd`q+1Z%DK21fCNfPi>$ihagxiA_zs>{P2HQ$)I&4tyX$dJp#Ljs1Td(K&k3FIXH`I0`W@u>dzu zB(}28+~)YyOHX-yly2E&Lb-0mI4L*?&Ok814Ls>0%791%v(>)wJlSVO*v%>L3_kOO z2ZLqQ7Bc7OD(TiZ`&73gMTZcl;laeovd#mK(3i_Di~TZcHS z_+?Q?m%=Bnz5?P+Dqhksj?~L=B8-rJERKSS-q^Z^4|qQyMb9M|9j+Z4nOvv-sK9pu z9D;Vn-I{zJo5hYrQWo7-bpk2}Ae^*EU#fEgOAnOO)Z7LT(vrMTJ#C9qjEN6fO@GX? z8}Bi7&;H8;TM+%iZjSOn{&I}=j`gXz;ADrn{@m`eMU9AoThsv6HOdc^<7{SacJ4>* zs#PiTq`K^T5c2rIjOjI-s0ApN2{{i+cUNbXt&n={K!I&!kkvEoU+I5Yysxj&c6Cee zlU&g56i-=2fTYa#ZcsGu5d-)@9rHxAZEMgb`NUJ6EabzF(7jO5jC5nPewR%4Y+;<) zU7y371{iJt1JJh|wx7|tbHXQV&E}GWE2T((X$SOLe8!tG=U^{*#G7BeZBN>2F)-8v z>;cMN8fXV`T4@I{)?yKB(qiibD#>mqpP-_m_6=>r(OynWfeSm+3;Wr~F)f+5Em+}! z02GnzTPgB|))SxZLHeZ#q=3=i6qU2x^^8qZPgHQ5FMKY1LWB4zA`-UT#;1QBlC-{`frcVg?b zz#@MS2~c41$xAP}M|J{a7Gaasn4?8|3t}VT#O&w~Z6X9%H367{hfhY;w`d>mmIJN{ zWDRydOEL?nwI}>+?_WP<3#hdZ0JQgo_OM^WOlB9(w7g1?p>YVkH3RHa zLlICQ2u5-8NQMFy+F68cM*f};9d9i`jq5JT&v}|!fH4ZbXr~P2)NsC5Pap5pzY;Ux zVxne+`m}~6Z?c4-z$Dl-E0hVy@)m0uqf9Pz&hS91&bDQkuV?Gjf4pSTbhbi%vZshK zC@zha&iQG|kLipSg+x=VEf$7la6RJed%5(rHEC2Mr1@o~WPyU0ywpa^c=B!3!`HD7 z8r3Er2asB{pGA%+%wd=zXkK=vhKdJjzFw10#4L}f1j$v*wi3_GWQkg|&dNJky{ZCm zH~B?cez(BkAqc4o%ka`b(a#X!N3Br-A3?Oh^aK>7 z$?o!Km`O{BB;Cq9Y*tHiK8GclAE(o>8~ae{#31h5FGOhQ!1uR~6B*x>X&92F3F+j0X2@mTCaOY)&pyM0Rf8pQj&z)l^Y>zP3ia1jx z{@}e60NfNEefI#q{yNZiz=`#PpPu*)^hXEU7JjmyUDLG?IFmmqp5MI~od~c@2&+T6 zdqKfXmffdapnrLxlKez-{?hRHq3%=vc4u`6XVdoD6;vGyI{V$$5@e>%)5goI=x-su z#n(Vbb}Gv`QiHPLVq{z>HP)FosL+Ie^|Mdnn*HYW27CXlMQAA@+>U#*AU6thHGKB! zj$d0&Q>E#8MgsXBurdBdq(Yn5>4awqxzcvm2s-cHq{}?rpNR;O>XZp0bgQudS&#VFOth53}w%Hkx1r zSyopTeR%~_vsf?9`l2&y+OQe3RN%{CF|2byKJtbN5LF8xg8t^Z?o6}vU91-%A|eV3 zLDCP%xyqT_Y$GMNR9tV~c|+?X%ffQyGraLiaKylxPizL`fxxrrCwr%LJ{tA&3=-0V zdlzOpk!hVE<+SuQo^@XsVIqa~VD+-4?0q1tZ@xF5DX0~gftATRjDq3R zIC&H61aLYuY!;l5pKnLH$)>Y>83GII9L5KW6~l~%ptAXE!4Z?I`G`G{1;+?@kM0L9 z0TbdOj?C-4v^Mzjd-{w>%7MKpr5EMZ_HDM_6jQLD(#WmIKZqCg7;z$)S~f6Jn5~B3 zvdh^`P6ZmwiC#k0!jlr$NU>i&1}b3u1_OFk5;_YU5h^RGd5;aaQ~6IIg=C)FTs0GC z9*Q)#k3)Q)8)N7Bkf=9O6ASj?4pu2|cISds*8*;EZ>Yk=L3<^*%f#`GPDzh_3h&$1 z=bhEv2`D>xfU=X9d4K{`rs#B2l<-&Z~WQwiAh^&ob2)G^lQ) zUkwyDL7M|i&2H3rz4i8QO}iG{a;ZKQG>A9-m}zMR;01?v9?vt(T|<8wp}V2ZzAYYE zj{_Z}TI?sPACA-~IZ?gZb3b0Hhdy}jfqpmMx98gU*=03Hnzd_mQ`|#^w zePho{h%JoKOB1``XMHrh)@9qD2N0i|_V=Fxn}wz+^^)g7>ZN*DpUF(C%&>$W{a31| zCysdS-JqeIF&%u7T?yz&#`XYV0xI8tvt;Mv0F83=I4w9<;`T9#{X>g=X zfbqjvqtJx(1huBsR!X@agI|~HT{mA#-sJ>J&Wx`gj@*IcF&IV{*8_IOHr1f4nVqY& zIzDX4Q#&dM-kz|T;q~;3yV9|ke;J3_SNQagZm5YZgx2f%-|zK$fC3wot8%Hp+5pG@ zkT0D8n~5Cxv3znwSk_No{*T^fuJ#xOTSNNLoV(CabNRF4$}?{aTy|&<@{ICZ#*|G& zH8rfHD^WRIj9VGzYo^X)9<3Q!?;)%M>y7*uxYnFp_AhhrZ$Llbyw=hbhRFFLH#9hr z&2$g(*S_2MYkIlY!VBD{D#udJ%6Kq6)Epd__~sS}Vbw~!^@f(yF!Cl7_r*FD&+tIw zZg2*GW+vZhSm%{|y7?wbGG8Jo%OG!9-=GK+-m#YBVY73G2U*7%%ZvAvEri7p<{!A> z@TMg?MQ|pD){eB*vG{34Y#jA>BECg9Jtj=^CUeu@()vjJa{3X8&*QPs&lGol{)JfS zUWMC<0q*b*Z@}sMm6U&w5sd|-8P1= zchi2$jtjy()su(U^ck*{ID9VSdQW_xTDLxLsq`}QrbXMmSnlK6si+^nf=AVA6Y6VE z8^Ep6?^->flXssbgKV<1iTn|ku@siVjsn>?S&H#*UuQmZTK}pgW~&ozz5e6hbk{{XCEb0DK(7%MNkBE zxaIV%Hj_3E{&)i}*ebXQ_o=u?4j+);j3dh5amL?C#xb&mEMJ^+KikgQe7}fsR*y8h zR}XE_bZsV^xqOs>-~ySxaugz;Wq|@Pj9hsRBUh9R(xiiv>hjrfJ=kaht*YE96aK+% zQJf}bX~U*Yvz|rZCZu4k`YjP`Jw0UOE1${|B{!%Ti!bjvF=RbJE9b>|XZFOog4q}r z*)v}Pl}mUATJ11>QCdFqO%K^-83U9`U@&MXURDZ7Q!S>+L0V2SqC(mf-{^R+X2y+k zyR5KfD2xUU>TkIWw$WS~=3{AR29+yHpy6(T1?RSKBv^qian>!^<6NEai&<{{`Vio>wm^uyGp>%c?Zh9G9)XwHCDAZ4 zxC%xtmJ&y#nP#nBaq?p`GBF3!Y&Nu3N;3F;{0*qE1N0(Lv=-^D>VH(F>q;;n;C7Xv zl^%>=p&grXN}iVfsBpz9=}YEwADA^b-}2W{72hCE4h$t>d2L2z#HrheT*8mZeQo_X7yEJ zZ_L=Z(Hq2`6~yr#=-wJYC#1sV(yE}pDDqP*`j zTs3^*plB{28#$VytQtO%IT9W2=DYwOSV8yR87KmN<(ZRLiZT%G+4V;)-YON%T;)Bl_w04F!nKJ8wq4;STPTb ze7b`3Hqfc)2=m2a2QkWa9&gW$hjgga<7#;z`ir8p6 zw#i8zto*yZt@-#~J;Z$e0=AqzL=Una zL#-qR`a{NYKv-%?=#v8ex!^V7@jzP=x5=|-UFK6kf`QC4lQX57+<-pPTp0f|#6Dz2 zWvdl7>XC+*O3daP1VPd4y3NvIO_{9O0=@jC1hr{UvtZv3ZVRyFH?&UddU?7>q6!omjsSCOI5YO96M7 zQFTaY%ah{UugYXgAeJF6w2fX!T{#WtF^jVFBZ%%Sb5Vv38$k~9vt%q~hElaVXJrr8GOCqMKU zx|lD;m?Q|gbHT(=5j72xQS1C?LAE$x*pfi))kDw6gK>m>8D|TV&0|k&Uh!Dv%jdfy zD(f}g9K++#%To`YNv2B}%hOK8<4qIIraYhQgRGJq4|9;l8D2JL6Oh`2K5wlt9%+JL zNIMd#xU)UGR&)B-QF9++-NgkWG<7KLg^#_Gx8^&IjyOg~fL3i1TlLanaqv)^O{eAH zjuLuV=B`kS*?`25%#QsT+=;XFIgMZqH6$W6nFoO3U*oUpap9&tj)-&sVJ4dvx`r4u z8+M2X!#W@0Deu!!u=BpI+-w+NIo;WK;odU$quc$1?b(=QqM{(oV)l-5Wx z!uIOPyBH;}3RUVEzv|`B%-hOVjM#KP|nfQ__YUDrXbrJ_&XsfX$zj^q9Lx&UaByP4Ku@tUhcmrnu4X^7nOEbge2d;YIFAWO5Fi0Cr5-T++jx8%NsbQ;JZ)eau_f#Jg z+a2Al40guvYQnQ-Ff%5aQK5^MJWPWl>(v=NoSbI^(&~qT(eZ4>N3(?!?%_)Q)Q|5? zoMJm+0$^1b*Y!viPZqeb{e4k$JVnS&&kvgT#-(v~FftohoG>&tmw*vR;6#PKt!$-` z#+6N9M(yIOL3QP0-+lv^b9t-=`ZC$P0g1GjyM>LWxY)F?uY>6TI3r;2q5wDDz5(S* zc{EHqWy@m7?yA&+t)1q}gHOTzq{fmH#R53J??jQ3tvF$6thwZ)f^s{X#gwsULB3v4 zdqLvSfd-HF1teL}GAO75Rt9^tq^|*(4M;4Q+;%Q9-;8+HpNIz>x7ZRPIM$DB$K)X@ zyBbzZPvAgCRy*`%2WG`;^=Um0IJRtbIAg$6FuLMmXzXF# zq*{Pq5IL&ujz^9HNiK_qmVw{pAtQT)tu=(C(-`ZR@Z+lZ7v~v{95v7*R z)4X|G$xy8M>_>%?v}}WlXs66DP@smlt4|sXQ3Z$Voo08PPXRmkSc|<#ttXfL! zJ4$5*)874orQhmJ-bML|SCgO{yt}ut4pi*`Ow4EYb6e(|@ZXcFZ1nbf^fyR;nDXC4 z^5-I+rQjPw&uc9dw>Lh`UYxIPP6^bu(-Hj*p1MilJk>TU`3zd9aZ7mq9Z4Bec20I> zs@7#dT%%D`6Nt}Iw(9u7edBWd(OPilU7OeI+v_kAh8?dI_uOnSLM}b#{j&!m;J=Os z0tE*ih_d&HM}s@l7WwRda6tSkkxEc6Cwxf1-qlz47yezlj!QG996WE3B^|Ss?eQN0 zUQY{|&}n5ikCw48{MWfy)D)QNTW!$`os`4n#!VHSgYd=uk#Q0`YfU%dWc=akNpRxe z*o)@}W>qBvG<3y^4G68=vjGl|pTfG%0kg%9MoS>aO z_MUPWN#m1u`{RGRU4C3YZa2ZYfh+BjPx?LZrEG+9KRVSc2)(f8j?h;+d@sFn;SVO2 z!!C^Fij_oXOLIXIOg0j)w~_yGTd!WD&bP%(+0zCuPt|1qtYrVEZ$W=}}liK-2EKJseMa+)2iA|Tf?HRyI^3gnC zhF?L#YpqN_O+{e(v6t1#7iFY}{bNN&#S)m6{G%e|fc7^F*yxnjlE}9ND$8Uq*QB5_ z25jZJbxPp=zm>62;gUAPb7=NJwKhuG4-p|w8KEa5p@8Wo#`7Q90uLA_G~Q)sTF0r% zpNubpkiYhn@O8;i0lc)gi}Yq3wkXeHDb0S2U%}WQM(bh#wMjK#I=A|HU$And>yN~i zU#$ZE)B+MwCEt9ZQmj?f^!8@JILNJ_eU_2((5so;A55Ub_mgo^O9e^fv5~W{$jK$a`=hrY1-d*kfkd-$Ske7xTpr&m`v}d z)iiDze~?~gdX>Fc{ZL42&^HA0=iz%Vwi37guue0U(-@e+t9SVJ+Q~;J(k5{0 zvLWwbetVGv;Di5v+;UJ$_E29s1L-}ofX)HPDj-#;X-yqq-5EogD?c-FbLW>f8q6j0 zS`gdI>I5_Rn*nOBeD84G4SQjrqWpAZTy)LcyFK+qg*zmmM^o*8(xa(p`)nV{<$%V# zg=OKLa|_qZS9^2DH!D9-QQ4JK`P~bj_H`kd$h<<9oo1n*5a(F;l6x&WcZ{yT1yYAK zIs@^yvOKz79pNZ^j&7=8$7NihOB)8vDT`24u)?f=ZlkZ#VK&5DjI$mczRbBOVXN1lq^Ye`N$bd{F{8 z=DWyopSANBO$QeYSFPie8Rq)_SiBTHe}oq79*jGTHbNC8+yY4!MGDUta4!pya<7+wd)u_Xsq;Zr{3Iuh-zdbseo; z4nxXUMOr(sq@x_$EvJ4o?%wp+ecOpC(*64{wjJ=Rp7}cD5Ygk{bdqqTVlpo5kQgbm zXw%`_ytCVKGUdX_pItXQqJI5(@3sTa$9ZI?sjrVkKGk=EN@6y2AW#hP!jid>0O?C@ zH|16Jh3s!lTP)=ERKE3BJI_cWw7~~0r%n&oFI%NL8FmM1E8IG*3`z3-K(0 zgMN=Gk0qkvecy(>E6hcvwC6W88mOq=b6JK<8XOcsP}BxSl<^N;HZWFD2(aJNz<4-t z%_XbnNk*WzlFCV2{B9w`pq8HvJT*?Wh~ixUGby&K@SJ)kg@YOukVoM;aYdpIns%r25)DM#%hkb=`XEi zME@1Pznt{fVL<$ff=_WJo)b%|m~20=<+q64vGn@!ifN^G7g~QuBX^}nrjA@!x4NH+ z7i`X~V!DX6^226W`r!@}iBI508M#aOJ2AN_{rw7#Uw*X$mt9r5O;J$KvA$-wto1xU~b zc{%Z7hdRiOaqkKLK~t|#1pAe)$J5H0|c~G>ju1fI(-nNki0(ydT}&MHUj^K_-RvFACm+v@z+N| ziL%5_Jnem8c?P!Ev<6W7Z;67|xX=CxwD5_z-Cm- z8#CXYlCHC>7Hae?;9P2oo_sh;eG|kodR_(cK}@j}JjL4Xy9@_^MnJLLqTu z?Dq+evk)>%pNwv8s}A~xU+G&>)hAsonW!F3^87U^Z*5S&ejee+S7;x8C3=0D{;EL% zT#g`c_FjXKJ0#S->|?g{L3FwOi&`J69A>o|OJj05&KMmM4Qh!`#cm)?W)R;%^RaIr zw`$m~Mi>UPFG%Xu#@hs;5>qx(=sY&<7}~iYwfDjk{GX`LFE%uG#6<}O)8p1&&I#!H z%HrUVppez!wYR=Nq;*>W>=W72t-DrZ_c){d(Mr+lOZ2;QjmP5F8?Ot)?Ju6e&q~To znIeN$ud=LNfO17$(ZkLKHoQ}H(+;$Y#n~VcJ3zUSCq&M!Urd<74KG^j`69()6~*^~ z71{D-O32zN|IbO$>)njthLG~QI9HEj`rGc}(Ns&RW3RZB-Q$EOjkc5QPw`!2gWk>X zgBy`kyE}Bi_vc#xS|RMJ^Q~gvcb2%P#sEZ_)}Svvrb?xNY@$f`fRDwogL880LI;2N5W<+$CxKVAOeIgO59}3y-DQQL_t7Ea(-l3%*1J_8 z8(OlkqD?S)4}ZAPHs716w(zycuSJ2hvxHJoC~kBtsAY611em%8`Hr4AdkHDcW8xNt zIPgIT<~kokn#CSovR)Iqzic2`=fBppvxaU?oY@vt;%=ojC*O%676wRF^4;If9jtX} z+rURrH^P7SM*k8s`Ssj`drW%KQ^PGHzOx6i6|dCy#v^GMvaXqzTTL7GUPn2stf5le z3@UKStxZG86|vRV12SrngGY_<6UDgFaj(%Y(rBO5Lj5SRrssrEEl8;Fu|h*TaHZd_AAHE;a+Q?m82#xkNx8R4E=uQPpGsG zthwt!QS#VFx%NInF?EcjmnPHSC+~r~Ty5b%1_G^i)%LW!f9hGHpb=&oS^9$Ts8?ih zdP_PrSQrTC1mDP?W`o*BlyrMr*d(YmJ}Hj1Cqg;Ow@+&4*CZp*3A4Zizi@7p#THSz zeqLazd(M)pDfR&=ttNyzxAI68#vzcNh+gUx9soN-TY5@nb>L$65`u7Fix4w4CfU&$1V14k1H6C86NlYE<~ z)=B!Rb$C*0U{XhVxOXC(V&a-|>q7{6Bb>~+^=l!4z4n}P%UDDuA1G)UV?E*DN)J{i ztNlF1863SK5qQDZ9!av)I@a)y$NR5Tb?04QU zP0kc&BYaE3li)`bg|DZwuv;lib$9aX#_h3JH zSDlf!pE#&X-Oy69ZVu>tf5_rQ2$>Y&8!^tC<_l~{*t z_oUSuh+G{Ev#eSy0F%g^<**VlV4or5H>b=85VXTds=)b)7rg`#NViaXt2E4tAQfl* z8NfEl*{K?-@-)DZO?3X*UTgK**4eTCbNoo#OUjwcR7r-Vde=Q091_z=&8aF8+fa7Q{%u)JThQifYJcsKUpDU=aeI!=MPNRaLg73O4jvy`41co)Fx<2E+yl^=GEt>Qm>Iow8+x4YePRpPS$y)V?5I_U6qs%J=d?n{Y-H6X1o_}8;kC42fC5XreV>DkCig2+^Py?t}#YFT9{Li z<4iYN?s!SdJh>iUuKJi(nUqo69b?pDXT#hwEPr}Ly!l7}iLsxR#3nUj-_NDuo$QVM zmlYvYXQ0-=axKf^n(9mGJbzKe%{tnW1$i>cH2fu-5->InjpGZ@DJ!2&MS=Fm+loL- z0#AdKS=Z)h_2I0{;M@i&>&oJjW{H36z?SxNHtp71#Y-($8h%O8x_B&smc$z6GMzIZ z!JH_ z2M$P5fEcE^kqxDiI2B$b{=!78zeBzB_ZGAvH_@sSA<0IXdBETBGS9PwX3DAQBxXAY zgsNak_eFqT@6iiK>sGcRRl~Z4z?&aSJ15XMlRt29WnTU0yPv+H7uCrH1nVQCDAk2G zw9-h?G;`RSPkH}^1yH=0qgYUv&+2hY6J2g`n)*=BYDt8Yr#y)bhjJ|^^e-Vhm3@3j zmJJm~iKh}nkX>#{>Ruv`B?Ti0`yF6s_h)R@?e5kct{c{V-{?|Eiz;*I&#BuQFEhJ8i^{x?Iu>!@htlIMS9k)<-oo=F6 zGgniGy}llT^?%kg;IED*asm9anRrt2GM-$uTI*=bARh3#O-F+#v2}MbX`qYG9=f-Z znR-yY=^7NOWc*aaz$BvP`BeF|<=VCf&YM$ASUr!p;(olVPy^+!Rjy&EBbvw*uaNBfVq!OTJx^ zLrIQGc3_dV-+WhOw|myb?r0;(&`5k%@Nl`zmxN4qp6w#=E=)%K6~CW&J@)szZvk4K z&$F1Ol*$X*%lhP(3aT!5_4S@ao6@qQdn8)W=JumL2 zNXGf_+NXjF&Hh@-)0G9G-ANdYtl>!h>-3~NfsCyX=1d<B$1 zg9r&guT#{Y>sA<#TbnRPskeCYrfpHHI}+fxl{oB>E=XP9T_>PLS>MY3s%9Yg9cWSR z_kZ5HP#PVhr`YhgnD_1n5Wjwu>D z!Rc&zcnx_~R0f%|bUx@4(x!rVM>(7G{+HPwgZ2aHCz0PP)b{nHdY>kI23tkTTOiYd znKiAY-v%iX=8@NPhr@rERS=KFD7Lnrqdy^U_!WkV&R#CJ-2#W0S`>MslM9qnYQ#2v zuGL{&afFbs`WMnJY_`0W;Z%7?nBEsSzg2z5i0%7@>u<^ge$FbX(5th!4Z5vCr5!M-sc*XB*r z&Keek5SC-V`2jc2}$Fd_OGAkBDQKpHc=v8-D*#oDZ|K<{Gd&*{O9>EShwTNOIZA3l;0XJ_=m41s%6*I>(fqO#3B| z7lU4vdOJJMLuT_A-SN8(`Ol0^T+-9KY*02!E+;1>bB7%PYw$^{`eqySqNeSoYfDas~ zmRaF9Yh0r_1-XLT6;l)>HnD!2?Sn~TrF4Z5oL-sPT(%C|;A#U;aY-?^`Rfw_FKB6A zH>)Do(7$d4WO0Z-Q*pn3?IO+N{&)SG(qE_FiPee+WKoT55yJa?9%~==+Ocpg@}kyHyXI7&S$JZ>fAtj_n^4{zOq^T~7EDx1qC-`M*&OE36oZ5FY**`Mmf zer+}IfKy2nIC>N*_+(Y$TtdiN>JBSPEU5ExI>!=!s)V(nN@fa9OL=QRlX8i|>?VSL zrqR#b#wEmc>NLx8vZyv)fJQ(Y8aHmESRJ5hx+%gP*U%}gq>Y}@jLg@_Iv4tiF=2&>0O^n(loCyu^mV?lEERxFOf(J!t$W*(EIAlS$A zsB8V2U`}K2Pi)4&*IB9UI^wi;tq^%bqXyQJ*l&`K%T|L(jRq!F3HBW=Fg>uqimt0A z@^|J}3km7@ygI;NBPK5!4+N%>d<1ARU5t*6JI??G~Ze0cHIlz z@BG`RkYc7IY0HU*IG7xJr?>KU)p)Qf z2dB)v$4kqUDhj0DXv@z}-zpp8FYW&wX8e6qQb94-*|c`$`=aC_=YH9!3%Jl0`O%N8 z9#h*YJHs#M3#a|J&`6}88G;jEUp96}kv`^FXwR+Tv0K&labH^{P>CGKx)I_#-1DXX zjA{W=q;_k>aXo}lVLf|k_13prOa20*7Z;1!J3J0M_uX0uANI*E#yrRgZqjTbv2#Lw z!Ff4WoG@mWCJ-rmao*aeS5rp+(WOdKjikiTdHL!0cjH5qUS2NA#Q82PI2K6nt{G4h z>z+hRu8sr~PyR*i{3S)xR@Ayj-nG7ABzQt_^_@;&x>~xnAwYcc1=A6RDO+Rh3IK{% z`#UDPVAU=`FlxC%S6mmA*xynn9}8|6#oUW^ZF#)yAUXq2QFI1t$p};(Hy1Z}6o*i+ z$_Uve@S11te;NOxcL-`u8HqYa9riP5aP4HiMd6wE7HMctJw=2ZAqZP-t)CzEbT(=sJB2)PEcfNXa&=xzxXB9FtX33 zW=m)TQ|B2m+|5#)2(j$;<&7u%FQzqEQ~_KB^kj>H4UKE^!C}#s(PIJv^Kv6CG~R?h z4WL|xwViQYgg$G29^O85;&B6{<*`p(DZyb=)jtwUc2)*HUe&LK9(SoO9fodw^-=?v;5`yGo7W})?uZZ+2>|2#uf1|9Ya zSO?V@YjvYbZE@?I4FdC5K}Fd6@<2hzM4Ge~;kXX)Mm7GD@CJ3z^?6je4B6PE4mp>L z|4vXo5B@lmOHi72EU9Et-eGg>omx8Nrr+bm2fH!qggg8cBt%L^XomB0hKmNfGT9Q} zv0fYc3Ax>QX5v)`Blvfq_aZlo(w7u0;j}~jW1ot}^f)?~vQNA^`6k5$*swZrnQz6; zv-by2LIpOoq=77S{hHyUuO|zUDsT*mhp4KpLp%0uipP3d5}uQGIYSQWln5^M;XD?9>eoh5(m_0RUwBG&0e}lU+;F&)d zOnWo5V1u4U1knUX-1avMymciA~xT@nE;A4)93Z&D|@umX#Y!0GB(qQmkZyu zO1?!cnM?NXjbc{Rmo13kvQ@Y!@NKK5M`-jX z$C)<=a$N^j`T+_p$9JPiB;}`^gNG~Sb%ff>K=*ZuUqWzM!=#Aj6P@D`cjwEl1NW z{nOeY9dVndcE7Hkb=vY5zhASLf_v!NaV=$owho*5L_IpOPSyHqIT7FbYN4-`-QtM? z-O?)(k`QugvT%yxwd%$@fxr}VbTy#q_a-IfDE`cH+&a#rD@M*-;xjZ-t&a|zJTsN8 zCs!jz6EfQc<~xRqd0?Hdcj=P0d}7h-Y^!?J5Aw8yAVFeWSsG~57K9W!a;pexiT^Q5 zLxat6tRZ%`CMkI781*T@ru+tqrNY2sI#Xy}V)?=vK>I#8eyEG4@>VoXm69roxalW1 zk(l&mmSxR>@-}34e6~Fh)tFk%8>=3bRB3es9)p!Ft1}qja2jw%YlA&SFI;YwOb^{= z)_a5EO*7A^2x%~MB6<$c>)-mOS8FH~O8L}_y6D(LCSn`(=H({I=vxAt)0jADDGL|< zWuEzD~*YWaff;!>LNK%0G$e>7gZwsp^ZLv|kOWhue0ciIDr)tyl}K*9>v+PrN5=Y$$2Ylr z6GMh1$&A}5YCY$zZ>ysynGiNWx7Nn+BK@C_#bD#?&wmMSc|Wt=wln1O4in4mQbD!{ zfl~|inTk8pv4duq<6#CHsx92rg zWct;DtOkNz`U+|f_g4{HL)N{S+EFgMtpZWZ@;2Dmrbi$93?K5FZzR=$6t`M8py5i( zKBD>X`%9>khg?(xV`tjZK7Ar!@(?oehjHgf16L!hH2dKlnOQFbm-{`3()*>Y^^`4+>n9LYCZneyc2apyvCNMAnYcHI&OXP)(YMe7O_uQgUS0lVbUjIm0|n|l_AvCd zs)5ySU`B6LlTyS#+vw}7-*)n7axPvjtLb!mcj;wHxjH>l690*wZ0d z2y()4G%TIxOn1Ynn4)Atu56+Q=q zZp{;YnlqA}rRO}T^=swN`}=P;R<4(s?^*Td=x3W-Jm+$ea5Si+N3?0k1$^<79Wn0m zPJ0BJ-)Yl7hfd9E&Nr5RTuNI@9dM0yl&;d^mM5$nR`}P6_R^6zW@@T5-uMJ_G?!FE zk{2rr?zcsJfncLcRlu+rFaugQ4Yrf2H4O?F#nD?@@9c?hijoCkI}(!3e&!jK$w4hf;PohcxvOXrPn%y(1L@q7RfU~jfIM&(sI%s>LDZ@xSdtD_AVe{wlmeN)^A426ju(n)R?J9@a)i7Um_ zs@1aHt06q@w0=W1I`A|_nfbPT0Y})J8p=4rWPN`XBA<>8sdw=nb@r~>yU94lwt`}8 za;@&uJveU5o^>7pkPl|~OZ@o*>x0FWs#R={x)A=wx(5(ly__^oXmY$O$ds|AS!h7Z zHaIQCO{}Jr57$j3?t~4AJ3oi>`TVXoDn{xQ`CS_R_4>doH%@!?)VIvk(Z>bw)Bok(6!3@5>-X5CTXEXlba~i zXoYv~6V|<@eSE4?U%a{3u!pwXmkO3JDb46X6A#bEPo&-XrAUv2{io9Ok9)f+MJATPLTjs%oNG8D0?1)6*uL5T&Kx@>!!bt+vE{fL&)Luqtxa+7Z8 zI_?|pGF-tkrUE78f#a^Wa5>`298}vm-Z)$uOhNq@eR!)P{@TZVf z1#J6};{S@B&yatH>gt{ITl@KhE7G^IEXEa4engmkqFxZ3B~-LyY!L2H+9{cEHhLl( z9k6e<8Gd4IXNZz=vvR9Pih>31Gk`}w(nXN31%|{6^Jz1$3Qzsft(Ly|9FB&bflL%n zvCx8z$fl}2;4$y~p59auB+kFPj^&>jUVZZ`gz3gi$Rk~!o@;E1L|gafDsa$O=AXO@ zmjtBO-Y;+s5tF!6-GYd=PTwO?;b@3^Gbqu5C?0Id*z7bD^tWIDGQZ(pa*!z&hKiKH zOd3!OKwJZaCnzU#s52J)I@xcxFYmFVBZw(4*@oB(9v}uAl z71ixy+|ug%x&ptATh>08Sxp?PFQ!g%eXaMHBX0}O{4^drcRejAgvv!ZA3o5TX4&(# zu18ZG0$8}?+AMkK@2BKGa`NgGGo9etfM1HF0Mwx?Re{cTu*L_>W9#fU3w>v+NVGf@ z;_P>?#r$&Yb|YU7{ak;YGU-S$6) zK-WR6C$ntGj%(WbLPR$_x^`NqyRs>)A6GGN^e6G z#;(EmAlY?dt7oN#ZnmND!{Ara1WQf^6nSBFVrr1guujFA+ z-L0|&_FQuFMHVH;fxOPH0N~*qk*mFIZKZUU<5rgw20-ny`zOqOx=$pY*MK>L$ZM0R5qV$1TzbJtwyy%u8|ey)q#Q zJ93hn$LIH5%aD5Rx|I>fMRvI0dXi&7*Iw7gEPjq=h_Jr%f5U~#-HQ77Z!SEfenfBX zMDN^iBtEZj1yWns{Ip3Jk1Vm>Yy)E}vc%$iBF4hK!f(uey{{oY58N-+>FI;t9{e!A zJ(CzhUwd<6;>b@O{E2ErF<_q1nm=&{qVvY(FhDP*eNU`p zk8PMu zh(IDN*m_7g*VX0hGY;N{Fu91*8?*io$ZyF2GzWq$~vo^QD*OmPE#a5-u3Gvvw| zvD?QSCV45HXrR9aNxKuZ(=i=ga6KAb?Z{As*#7b6xH0UTwdil)HFG|q!c$Fr+pdGd z0wpKFh_?a&2k~ZDv_o!$^vGOEFV4^aMtIP=1|ph(X}LV0oE*$;RpCWM&{MognIOa9 zx|kms4~)&Ood-IGX1Xbk$ZMkq;;6dmo(WI-ctX0gEX!9J%~oHdG6|h={7;|AU5(=S zM{)(1<#rwQ_vHwH)pn4ZT&)!H)_o;JP5q5n<^qkdukI^J_&I57Bfcdp`VmaDp~y~l3pvX=}<)C2Q%ujz5{8%N^J|& z>~KAlzhUfEcW|`j+f1=ZkXfEKWe^G&Q=pflKEPl;=>30Wt0kX0T!#lTy*?IaeOV!y zJ13^YSRjjGlJA_aT%TusM>2TIDfPHBr}giJKV2rrW+&574pv*kdwo0Dzs8ier90(S z>%zTwh?BoZFy~*|-aKk?nIhX%e z-VJ@v&s%I8lfz#p{)(A$qkBw4N+eo>263kGB{M{s1eH|10;?hmMfhk#*eq$OuQ zmos48lDMp#Pzk;kCF=kID4J&Tz=O}gAswFtL^5e9{C(jPU;W#V89z5>_8)^jP()6aGtf9(5})7zvB_PtNu;zRg8qa z(~9}PS;0%HHh{)Hu?h~Cd^=Hx6(Hhu7_(Xv?F=Mo+vRosMKyZyyQk5;1Zn>j4{h~j z8`?tuQT=Pyg1G@-?Z&dJ(%Mhf?0hZ6a*3w&aK!?o$T==kD|J1`u*QL!u{G{(zS)ia z>NI?MBkFK$R?)aKvY#`u*eak*$teKO=lA;$4PDIMTFaFjpR8Q##7pz$QN&-Uq#Cw% zxBk{)^V|h(d(|eD*8&HCp6;w3P=%oe_Uj+2wsE^wyCG*G8sSWtb<@k`69)jA(sWj+ zm;{j{m?!!7EjC6R3kiGHn_&F39LT$66Og#0EYY(y#2VFTU`-e<6e+GWpa~T@Gm*d} z9H8huk8Vpi3RF4QgTu1s%44FEWrvaRy<$>(UCU5etn{Nt4gZA&_+)gZ9`Bd0muStFL^b?4s@e0MbL){?c zM;Y4@5CN0{Y&Nmq33nhEl6?pU z;YM?=EUpi5(VHDbHd4tfLucug$6q#7|+jEm5QD*nJVi9-kVpM_h++gLf?OcATv(il3JqKP&QnraPq2npk;?9 zjSAVKUsO)i?t(1g30cWCPkfI5@}hZev&g$5g3IlrgJ$fz+tu&i4n9blD0JwH0RqxEO{<)ADRM6(IBG>(z z#a6|~>9kaGQ^`k+rmhFQZ}9QcK3lfDLjF?vIc7U9(31Y&gcc77)(TWam}yEKIm;wADJ7 zbEV@w0x#fC7d#%Gh!6cSSM&Ovkl=NXIEnMBfjYpykrqM)0*&Foe{Pm`Np+~f3O=)lSeh!jX+y=vF33 zf1&_Vnx0};&vx|nw&`S?^0>Jo^@&26{#5xOt5V~9C$;vKv%hkEpoB#3KZLq0IJL=f zcz1Gg2*dfIGa|QE{hKe4Kz!nPjhN_-zSb1_5?u$3Y(He+rq6*sT_<(=k|N;=ENhq} zK6DYNtzb9(Bqy~Ujp;sNJ&4lY+pnVw{kg8yYt0T)0n4R>>1N)=1ZjooUyWfCqyEUbB!&>5&?oA? zM4V{sMdD}SD2A{+g=N0CA8>cMr|pUCnMZ&EXkBH=vdLLgxSY{utx&)g&ZgXC*YS88 zv;=SAeoc=`u+?6EBnQdV<_6>aKrA(GEsr|3bk(nwpw5MC8MF_u&zT@SfU`kqu)nDn zNbc=IoX^1M6(r+&k8nr+WCde7=6K^wUuOE{BS3%eYo~gY9p50w&{A^Z<;0pI-dyA+ zMV&K;bvijOggRc!{pkRD^4axC=v#XIQ%>RFDI?Ah^eH~^o7FxAeZD#H(eHMhdbHkX z*nLi&jJKd+ya1p+EsLBYs=@c&qr%f?!Haua=)!`SgNWB|R_D9gaWzVaSabY!T8T%Q ztTO=1?dGP*0X0{c5qWs+4DPR6dT|n$fx_3XEsL|k`Ud1b^oqbg^a{D?Ypk=sygETz zm}s}9B@ZBp#Wzl~WV8w#jz^VP+<@Q6!u*7z_MUh0auRToPR;7`!V4H%yM$%Lr}bYL zRZ}(R^>Z4RRr?HGN4XDOF5ZMgmW{~E+u2;|k=JdFuIaT~pNdKcD*#zo-#e zDOQ!l|HzU5>A9UvnAC8%JzJq}k;N7K2`PKTd>H%mDQWulhAn1wdx$}!74xWf^97b4 zfo`t13CW1Qv6MJ#yM*r&fF%j>zumDb7@R}~E05{+BKK=nQod^mwYS}VIHls0GMQWu zt4l&LlT8JK3KOa%*v!N+IR0AMCr`M;FyWmF!=S;rJ=Ww_{pIQ;mbE3c2b>#mA91sq z7o)B%HHb6SmM}*=a;@nfC;BbdS(I<}XaM9mllS^Z%* zvDB%>0Ka|OpzQ(IoW|}TSnrh{v&+CLOZi?z=WF~|&LX0_T|#&_-h=@#Smz3IaFn)R zrFf4tkR)@vGO~yGBHm`3os_Q5{Jzy9mFfR|_)*I|pYYV+o-e3pP~Z zk!1^=zq?{QLo0{fxiO`~*u7kvCC@!m>RLuSf;&^aM&|K{d$XUD3(abL!Ti($RVZHw z0DHfI+j)s*7G10DLmc|x*zF6LqGY2AleFGw zHD1rQ>k|+KbI<-TU`F}1SxH%#Hh+THs;K1FNJi2_eQj4IP;h?#*Rv^tt4ep9s#6C! z&qSGlfBBm#O<2FP^6yPU$ACWuC!)0rR?a_n%dTxC#^`E{|B&t9!%>mZ>u)z-QAL6q zn7~bE@+IA0A-KViy*#1N0Heh>xX}s+C~a*@$A!JPChH6D*BT}GQy5G22R+RKz*CsA z^`7ZAS?4g04HsiZc#FA+dq~8IRaT#1`12^;0bS3;a3in3ZkAwLMVswl)Ujlw?T^q_B@&$cw?TE|%{Ed1|S zT>t;W;{N~5;<96Z=q=s15h7VWMGl;8Y$z6&i(0r8x7CWiw=6uvLc0a1cAs}fL@fSo zd9F+lqym3Uf&IzJPaNR`8qNrmpPXbZmq?0*pU1T8 zpR5Q?sc(ZD|J1M-AVsT2o8=B6Hiy4MI@-CcCi}%|remIHiyY)HTOpp%3%T<5!59dV zY3ru<`L=)bd{L@c%Sb+o*Q#05bWKtUIJji&^oJ=1>|_(`6q!#sISGT3hN${5|2RXB zB;Yz7?P~^xuOCxUN(OY)R%JrPQ}W{4NeRU?#X*%5@A*ehDq<{NA4puvebw1jk>eg? z;jw&{b>p>VvoQSnTtm_ovlABR7*^CI!ey@ zS$~TGaUbsKkWA$eefpI4g7xEF!c_4Ru|F$g0e0+P=K%7S`Q0kn@$R8?XRY~Hac_?* z&^4y+vuoluMZ@Wj|3B3fwBvHV_U+^M+nyaJqNZ0b+w zM>-WgD_!6yCtdae2`R^9hF|F29xO!`z!?cslbEUnkz%g^AYa3-$8zh6$pa<$10};J z8eCBi@W1WVX4J`=Gxrpu?juBiJ1Ht$Z8KYH=0j)}>Oa(v*AeyO{==!otP9d+!}U6Z z%0~b8@p#y-uZeBV@3PugU{l$8HDwBNr%$F1rHVh^{#t3)X(sHN$ZnPxx5hI+wF~!n zBXm6KZjnl}UV7AOi1lU*}QLr51Yn}Ki9*@g_D?pEgS$K6wM5Zbcr`?C(5nF(sGi&qI6j)B?I>Tq(Bk^70 zGfo%!)@9LWuKI`pQjonIlz8L6uz)0lE>yVC%3yolOh^2z)($+LJvfCgMtBzFeF1$M z=k>I_Jfz>TL0UwKH`f^@erclJM?F%PZRxB56sR#Db%D@*KkdlOEV10b&yj53CaDUE zIqpP-~RQPl)z3J$Pmd$pH*G$zhk0pZK>;{Gts((_odWN;dj^9{Fsx0Qc&uhyO?~lz@XlFZioG zgtUMT1o}0^B=(MIEKg%?2=ylhb zTyVNL2lFu|tJ>|m1ZPAEG?a0A#2u~IfmU&e6y{TBCU?~TY^2Ebv{GrHD0;xQyd1x(fl4YPCCC~7TUCbs)8Ge5-Z z%XRDjhlPIUaDO1}dqnz?t5uBRS(T%;#@Um%yP@dU{9q><04}k|Sbfh+&Wv9R%Di$j zVAr`E@3$WMpnT@0!AeDABpI3`G@T-b&dgj6bgBYWv1ULQrAuMe9cae$O)4e7$MT69 zZpz|}G)758kaq_&Wx(kS%p2 zHn~1=NCKh!L3{Xeo)Y$(24Meq1AY!&Lp<&5q8=D*K>Nfwnu5T1Q6Lfr2XuN@VsXu~ zww2NoZe5>?!3&C?Tum+k4Y`+NS>f`iZHo<;!JVWw!Ug&+t_P*!KVg7izzNbbK^BU(GsW@ThkJ z=SNW)<*+)8KJJ>ygP+Mf6$7Zo4ktUa!=JM^-(p_VxjF&!o}|#%ahqebrzcbZ5AOpD zlTS96|6$(eEI(3fP22a(-@yFs>XtF)OmOI530aIY%X8%Rvk-JA?XhAv({6sQ>j6G4 z6vG5FF4cYBBT9*+DDiQZ@244Nr4npMW9ZpbvsuT&nr8Tg@%7$hy#OPx_BdfL{7Zab zMb!11ev@({lg5Cl^ve;&GlK*A-UC)0?MSr`J+b0!o83O1!KJ5lw~v@b<_V6r29LSQ zEz8m@Z^#|YESBHD{{F|5^=H7CNv^po*x3eU?~MEbhJh4?~) zAO7zx;6;8n{yWEf0k7E%zrTBBuTyGfoM=Zzhxu$Lfu~f+viF2F9XJ=Sj0@IA>uq^o99w!+ zyNj!eb~bjY{4%etnYfddBQyS@cXf5YW*!X&n{iN;n2jTvulo%>lpl@O@Pa>z%5m?W zj;88mYRN7AQl0=5)$SWUv$f0s#=SeGKs9zL!I{8L@%Xm0KP)Lank#Zx+RA4h!0R;A zv4twaLqT`zxz(&WGdl5Fe_`@Sw1Uk0p^vXc2X5?4h(F^1h;_8wb%)Ehvvj=Fz%-?KMNiQ`#h z$U5xhd+z4hsKO4XTvXTB*mHzM?f!&7lb|cBO%H>JikPcCAq+$Bz4px`t4N}<|JLgu znlGY?^ewk2Lx#(=(SGHcen7{xTcz|e#oBQay+O&uemOiCCPMwEyYJ#13oE5ZECHlq zb;5i#pn=I*ymAaXy8H%DdfphNR|t$*Os+*ud0s?lQ6GF+1sA7Fv`@1<&Ky)|l=@bZ z-r5QlM@eC3y^bVC;|v~!vFyj)6H8DfdhOZxdj?SbrJ6;wcJ8FzO4AOGtc0bV@Ms-7 z7TY*8r4^fbsn+I5HgWxW&By!qd>#vIP!+LXe}hNa251{s>=+9pW6mJ_%n@`c29C>O zt<9FyNU~`79>R5BS)%!e*Ap37IY`-u$4(uk?BAikI;jm5PWYr%#EsfVuZ|)fAjw%= z)~NI$O_vTH+Xae|kIQOycd~;+s+{&YGx1XD1?b&={uvzuH5%Z7)uL3z1p7o-aVH^y#GY~ZCEg@vp?HUq3?yQ0p85?2;uwo`^ai1PdoTb)j0qKMrHtGv zAG0dphFO_*N!2MC1$U_N`oBO5ahSef>3k}(OYfZaI6y?tnHTYL|1rB|15tK2#uwKa z^iPlwHthZGXX}n6C4h%bj5jWOk-ZEly0w5v-v*VamdNtn3{3^bob|t64@tM51yal< z)cj0*^1)3*QS%yK&xKMDNZRS(H}b)NP^!epN|P+~T(j_FjCxsyxf$tw90Llqrd}PP z+XFXbG318M4pZ#TmnPlUh0iJ_y|ak$+>y+A?YNmeOdg~7X`2L}=aUsJ_q8UDyPJHx znA~Yo?@>U3dq*8S)JD+y0El~M&SRez4Z7H?mdl8K6j<&)Tke$()&O>?0m0hv4!_28 zGFQ4OM5X$rke`Y-fl5a@oLL#}&ytA<h<`JsI%p>e><%^%?$TK#}0VoB#9O$Cp3beUmOkR%^+RNz*_`qQKL_-WAW4 z4H+1e{}zr-9F>5prr3*WI1j%Vr@{IECC^t(IKa&khc6b z&?LE*{cFS7f3+ptk*13+o?tyI(8EB`N6yY~1p!}FLDi~A^V3Scc=dWQ4VGsN77Fus%5`b+%n%a_{F<)Zu2Pj6$vK zm_FanJ{7j^s_;3-S!eZXJLnmlL(lq) z6pv0tCM&F=!aKmb_*OTb_lVR82-pM_Td@83+onki9(!vWWh5l`kCjT_8*T&@ocn^k z=G2Bn@vY?U1j`cZu;dU~U&q7x!^b)_@6_4G#TT{PT+fJO7PLK1nVO9~iT~NAO}3t{eo+D5}9MfnkfO z?=Os@yF_GP9_^obH2IBNF71{;+vDQoS0U6>HLrUk`p2v(2A}gN8ESn0gT42TYC7%L zy=TTzEFdzVh%^-h5s)q*0aOG;DFQ0er3I;>Lx6x4RGRdjh#)I|+JI;8RXm|lTdBiQmx7l@G?%5oWwkE=9T^l9{7meR zWYwv`XSH;OUBgs}YitvC$w@n&vc-05oI> z75N$~V-LFcBy~=PQ8X4`7E*8DIP~{jfby%*tp=RhH-3ShH*O%XieX60+Dl(2-igfA z_#e6b9?a{Zc8DUIqai7)wl`X(Y9$MjsW!)*&I>$|vF7G_krP*N>W{?nr^)|BQC5r( zumfHlfAUf=Eit%zJ;VRwNw}LS1L|GebU?w}TLGQff=fpuYA(}+`2d}opP4d2POW>V zs&ft&#wj7<+GjEMLd0b8^2wQJ3=6X;0Bp?)tL}Bk*H71A755hPrj`|jQRU8yrM0YS z2l}d>gb0#mz*xBhBUTg=?SgUYQ7LW0f~`Az#l7>B&n7TlBZCj@orCi$?V2SkWNfbR zIq!l}i0zmBf%MW(_txuRr{AKWWz))eJA>u&b!+9y=yP^2dbLrb$t%e^KX>*zM znq~$#bql?zC`wV#J}`dnh*v?bOPSHG`K}S6tb*Ile)AnNtjb%T-C}`wG0D#txB=n} z7bzx6tH6C0u%fSmD%brl#+g$z*;)Rvw(a*o_0ySf93yIv3)Wa3l0C1m*vZH%E9@9k zAIBV8i#eO3E~nN?xYwrq-sTP;A|{19Mj8_-JPiO@e!Bj}LDxOzj{?UM5xA5ln$>#A zUP{cqcMUx0$+@50x_;oiqu7LjuOw64S0}f|X7igFLO1V+G~3w*BR67OmTjbTNAnv= z5O;jKb&3z^tC)J9q!2TsZ7kGHxci7~JBYk28ndKIWG*(N~LpE-ybnvlwvf9#PUETzwj6xx=V3(&Du9LW_2y0#y1 zAEWG-(iQs(=P#1AmHk1We`o>-*+_Qrq>tf8qr??^IILXT8^E8YL1a0P$t89_=fcZ> zE`nW7k`#je4bhj6DVjt*U(BBx{WNje|hicis}sHDQJWrQQ2)~ePF8ohgRcs2!GRRTGjjxJshz; z{rTeiK7mNcjDuc)iI)*z*zHIJxi8x#3e(e;WRS#g8nOb#t7@xh-Yj_b^4>eqV!w7# z3!hoG(ABDSm3wC-0y|Y{gv6%(PYg)MTVdqc{aw&{s0uZGLwis#m5U8VxK&O1mW|(9 z$$1h}F#dsd;M-JX({1)ptkN5CuN7S0RKH0t z9J_;}f=&%Ly8XKEmVPLG&dGxIRxi-Gee*P{^8WkDp2PEwHhuH&x|UcE{}gFXmDyXkAG&UBumd;$KO~ zw5>PW?uh5Tjmde@quk?P95rCbR~grDHg@|Tom#D91B}4VvD*`eh$?4K2(-IFP7own zrw>72SLvm=KprAp%w^~E7@Xw8UWXFAnNJI}UIe7G0nKH;qfY0<%8&_jnj4+JQc#^UnnA z@_XKDAg_Cm0e8zJ<5=r&V8Q<&kI<`^qH0?V%C>+eCf-C_g+;ppGh^uF8Ee(Uu!P<1 zcn4pQOE%UXEr@NaELL62iiKj5qQ|hnszRUFfjw@Z=ntaWDn-EI$gQ&1O-D_10|GUD zz2$_&ZesA>!lf|IwKD8r6R6+`8BaJ}uFWoY({+9Vxnf#E@$^z!Tc0Zl9y6L?8t7KI5UjojY{Tr z@mk8u`LtabxEC*KRIE+gg4?Ho0Mp>=-2$Xnp7kP=ky#kgIOyH^9ku85?x^7XU>gF- zl8NBi-GUJASTLG!(I5Um>a9PnKitIY87_~kA&M-jHCVTA#)~G}pCp4w+AlR9|DZ z@*5k<>*SM{r--t+#=IQ8u*Jk1xB*RdH7R_t5(Gi+1{B;hEra%sG;Kc=96KhAyo|is z<9_M;&YP`cNY9jd`tPSnK9ON6lln8q+!X%9F>J1<+nF|5K<__a|1M(##1<|X2{=qe zW^6oc7oSHD3#O?QFGRz^4m?n?^TMu3Sm*ikg#Z2wHkO%AI{4}-r(y`G4{t!IdaYog zb2~hDA&$v`Y^vG-w(jX1Yr9LWW3rUfLIMkU^XzuOV95X9xghPEU!Kgg~x zCLmKFn$*WppY?tK_IP)djq7wb$pWOTfAtf?9Jf?i9zCbt0~&cpz|x_XVU>aCv9VTV zU!dO613-fWOq{TBC-z{#Gk){6>HbYQw^XUpF?qJ4ZSB*SK@BWvSy8KOCj6LVY@;@ML+ z$fOVJ3ut#~029n<0Rr3N%Y6Iq!b|#e*+m`E;z13)2EW^s_bp-m>Mq}bqB=MX3}M6s z;zRL^giN`JIM!uuokr^|G|$eHD%Oj5n6EZJ1sEzEpw z;XY#uIYVCCTY2yei(g)iCcPRn>=9Tpl@tjio+(4pRM=ofu;cu03_Myc^DPNR?8Cor z*TeRmF!t-XySkXpq9wI9pv~)LhCnmoWf8y1$yE@Mc&g z^I)Tul|f*Rb_HcbD4-*uKIVrcxv)($0RuV=zolV2&KIy|Md73u)jOWRd*BiPmZ5&* zMZh{u`H%52#q1x+GV-9_*7E)6a0O8AaLM-Cfu!N_%A{}gOW%9tr}jgdf+j(j!yq74 z(Q_VL(%P&|eYRsAK1$!|O&gD;kqZtuCRuM5{^1coppa7iO*>B<`L@C-Zj#0iW!MJ7 zEVpv1rh@9yef3vaUMx0JA2omuz`apyP{Qc&P@W-uU&6v}{n}h*h~05jsXQ@ldhC{w zdBtY__Z_;nsRA*5(_fX`RcMJW-U~;8bMGEVaMwDOC{qh%)^>+^hl4Pc?Z)gVQ4X-H zR7JFMTTIES==oGtEFY1r_z)bfxY$kbP%eLJwQ0KBo}n8g>^J>FeHCYgA+z7v)JdTA zo@K8G*q%f&2L;0ueb)(KyZ^4Iv(wSE_0;|#>R>AZ_Ov=S&26CjAm!`<#qYf^M)g8P zEDRtyGSYVW9OX{7CzT*sw!eE~e@<;2fFwL0A|8YVW1V?<3+ ziD)7Ruo6t4rF~J1yWM>3e3Kp|W5W?#a(3R;hfd|l@__R0i^wg$*L42?*dpmJ5@l()TI%*h;kT!orQy) zNXHxhyYTb1MT86zL*!fe@pStRJgXk~stPE=`RCN}3pIt1+5Pw0iokODvz5|unaj>j zj=)`AY@P+E(z|S5;2LFVn?6?yfPr%Zw265D2>o<`2SgoV%2+Tm@Y1x0&RomfTJ-=cd^wCh5r3=J-X+1 z`>6?>5#ic2+v=c5#>PkY2^oR0Ec;|*1`bYf+1PIz0!M*}02k}JtiZspH`J~P0HlS>3i`C}>Q{@|eX_5Z|uRh4jx$_~8vnnlLgAp#B zd!+m9v_Sh%bL_@PlW20TtAImPp=Mtge6l#-5E3H0d{EDdk}?R&Iwm(h`}Gy_B?#wf z{h1{6IH=#-3l5wpXLxwiJn{Zt0sOfgZRvy0QALm+8chLJZKtRfM$Rl)2Mij(TqgK7 zktT!pLxUC8zT4=+*E|!%O^>Jt^cK)dgF<#<4TFI9z-yOH^S1A9MM;nx+2|hdN4FW5 zRTheJ_=Jc)&fd6fh$N*gT$}{)l19$@C&2aBWZQc#gcRpAZ-TBmnBffGZc(Ly@{*X* zVE|~HvI^zZ3BF-gad`bKHT%IZAE0U(HO|bb()WVVF8m-@2CR^FEW-zBRSkev5Z4EpAfIph~$fd3n!s2hbEH zah`+t6_ePs+fN?%U0h68ue!nx!pZh7HFHf33k{=*>D3fnh!tLSzm*XwYN{Ilh;LmQ zjzX+t(%o02G|ds@;XPXYws*-Cu!Lf6ehIj2oV~!RwEu?JcS5SRl^g6}?9d4s!R5f2 zp?a@ALFcwb^efecw0YuQy{xv^20eY+&~DH6C{|!bGvy8N8Qhm>oF-rB%#8on+h8MVq%bo=0U<6@|L5>I^he!VUiw zwx0U-85!Wl82Em*q%?WLmGx+H7ko%y0zmNW4JKk+xD%2$8w5om=-IS|`USv}E`a@+ zGCu<*)!0*f761n?1+HUExA~(7T8Xp3JsOAw1RrkbYhNxcz2kZnH}RZ=Gc9jc(A2ka z_D!s}`1wA7Z%}Jm3k>s+#BMIenuzr+@S=D5f%vPMFo%WgyMT+gQ?~?Vmb-Vrhz_#x zEEb(SI~WW8)B%}*(}$fW@4M|`CPJ+2Ig}G~0;Ined!;6!&&@rpfz+AT|9G5I zrEFY?@c<-YJ5b&O^B+Z999L&phMG)enI}Pq<9mUq>oGk}IS;QI*W0#l&J|g>_J3@* z#v}$ffo;rgI|EpO^qYA*qOT2dA4@008hnE`i%Rlm9HF?};ncQ5VBqyN6zS<*If-@30t{pbU@t#=a zmqx(=x$6;!OC}z8uE?Bkae#`C_^GyflH77Q?3=?% z#-dKjl=$^)P}lN)s_Mq{VSD-XyebrF&6m?26fjnS^L^D`Z$b-nFTRzLyR(|?zle?} z%@>M8Swh-|jm!_Lrz!_*%OJn#5zG`p4S*^sne@R4<}Am$#>xou=nO(s4Rt*J==6}dw?PDS0FXp=Qy&UGUxoQ1DKpicCJ2YcJ9K`%Gg_2f7=iT_ zL3I<&BwVVK2!HH1Io20pznEz%W8?3P7|e!XsS`K!fG%$y_8X8 zcp&IY^#3#7Vc0bMCNBLx+`ZK+kJ5)M%VXvTHVrBiC{13ysq_ z4_c05S!{ccZ2*=_JnEX%*g~B~_KY51LKM{Jb;=L#jCkKn;umQhZsDE5j^GE|prg;frS;Pd5cW99-}zk6dNO^gPHq^V|lVPD~~Tb7bS2WCH8nfN}_L9y1y zz#5mT$!$PoNS5|?Bu*{Sp6;sgQ@(;#5dRP(5zipN1ELiZO$Zx+=VDaGB#%TOcL6>Y z^puUQ1D3_DRG)7*nGiJYsdsB6+CrlQrJ}%AJy;Gj}-0x%#7R}E(wYs+a6q? zjnuu>W|RR1W%OkF~(Q~S(I{oZn+pf8{J z=uv0lizKdVfvZNS9(d!Y`{LjBmxD40OE04D_JpT|uX-v}e!ZHI*vaP^cQ6O|R;8Qy zPDe(}2gTTSz*kbke~!2tI8_4;)U9_Va=)JieSA8}>nu%6!zJ+X@q=p>F7F-=i*A66 zfx8)6tzjnLsdC&$>1vdf@mtsVnod3%@Kj4zEa(L-)$ftQ(BI;I?@6tgWet3?Wxs@2 zx2*R2f|&H$%bL*(+|Q(Mm(V|sl4dSpgV&o-VVg5zolV%NVv7cP8FCNozU9{3+|(^S zSEH)N{GG~Nh|Bkta1oadqvLEaJKOSlg(Z|3viOL?_0_8RgimEcSGNo8RoN5s95Uz0 zhrF1Ja;(O`_Q)3TQloB8!g*Cs#df-kQCcS!KNlffAi|~Wz9=TNVzIbrLb*VaD3uGg zd47A2zFV_zvGQHfeCOz>v!w1eU?FlkJ|SHt1+7l2bjD!PBs#yodKaz^)Hu)YW)cfrSTd`_~GV~nt25+fVgI!}v=jeq+d{&b#aCl<<_%N5%(KMup4 zs8s0!f8i42cMfWY>E~=5Km=!U4@KR-HtuXlJGmX)dtd5A2==8sNXK!bKx&6#WcJx@ zIxf!;Q|Y0a5KU;J6pS#g$&?Wj;Fu|Z<*fm!6jXx-Gm&b^W{Vp~xSb#Gdk^?9ZoEO8 z-NNs<-%aYZmjuw3!I*v{yinYDb6-6y;d7qgnG=}zG7-1wo8xJUeXD4T>(MSEJ$qAy z2bNFn2mz4AudE?kOe(w6Eb zQw9<1E;DQy6pov2tCpbclV7rjSo1v`J5%vJTpq=3;$f;Qz38`)?&Ip48wCss;=|VC zZ(EJmG}~EVr7JKEk8n%sSTri{byy+?Q&L;4Vkc=Hl{>LVB+bi&NjX3<&p_PB9h8|k z`1t*J&g4=-#tl~rZfDwUwM&mmooYOLD1JoR#53yeS=&dR?y)~Z83FW1v@3AEmJvcx zqpX&hqkw(6ogiqYmH|$+3?sMNFMx;MBUwS)N0(KG_>*~{3;lh&1#$J)4;xoS*&~<%_b`A!oFx5y7r+oKtHsOK!9=Tk0%hOFm}paY&X6Mp zn2f>Hyckdv`ax9#@Ru37WoG!%our}XHKz^RJju*&&I|Chu%am@ou`=P#=D<|*mzkz zlG*9xz}?XJ3T?Y4E$!@dZayr3xO_r1Hf1s#ev}nkm!|WGA-{%;9cni0{K@_&Pnwz~ z#u^(;nwR(8y=FUJ2^?&}^JS>;xqr}%-_#dsO^A9n7i?rqbC@&;8X zU-VW$6WZCE+m$}=i%B1^QNw*hQVHnlPms1k64parKwJ@X&Lh!kd@D^jr;K> z;7RuRS<#y$MQ8;e3UI;vG%xk3@cx2A$_dV^xTc@rTD2Kau$(W2Jc~k6TXH)Vh$K9@ zI5=dtTtM4(Osl5yXv~;&pxy%>Wf#-xr|w>-53|TOXyvGCZp*m5bXY*qUmI%pWaIaW zeVIg|f{zBS?TmTq^{)B@TZ1OQx9nRNEg>GhiNOy~N%Po}Dwn(e8_D!<6+FA%kOYPP zPu1u}t1%*Tg0QPM&Tu-E{Ye)#o>r37(&#f3@Whu*X@arnx2X-UX3*88=^bObD?5U| zTBCiBG9&G-d`#7UUWl#-s@7Ex231`E&Ak_Bt&Tqe+xeAuSn5f_xc31#)N;g^hFs%ZJ>~bi|5FCI) zLyLMpNl$q&pyKF7s8PY(#0{NfT1Csj{W2kd1f`#lplly7@jOG0r73zgZVs2A+~auT~qGDL$ z-z%)@jSpXxk#@2>V^Q1{h4Q^cIAB%TeXqkLWA13jx-j~qx+Y&DzYi6BaR__m|B*bm z48JI-d=XI#GEUBN7glR#$`>BttpKfBI$qlwq1h@6ckYaT5pA7&)&*p(7!cs$=szLA z5uegR2Xi8TJ!M(TuLtz&xo)3QnVkoy2EuZAlWerv-?Z*u|B=?s^-r{JtI3yCk|6W& zu}vME+OF$VL~j0>>o}qRrsz3j{7P<&6i=qK&#!SCtw8;;OD{XuppUXy`kI?`8p&Jo z`ivUpGDqTK& zpxv;Q1lKqb((>{}ttQ5^gS8XjnN~zvp=oi*kBvqlA)|QqE36InL*7F|Q(v>JZX?K* z4a9Y!FD;~R44D{}5fxS z*iSRj;lLlW_mba?_=0m^%lP1DPA^iKn#oW5&e^#82{3rdf+lOP->08!ED`01MBOqx z^YdWs2avY&UFL$eAYH(py+pFyH7IEEN^$^?A-w?f=pE*?sGsyH>#cYg{y0DR@|GqK zd=?ad_dg0YB6pzn+brs=QIdq5AAdf+w3UUigCg8h?v+{as(P~r%_!>Cr;o3iG?SI=D*eYDXFy*8TRhP#{FUSFq8egfd@*v@70dj zI5*LdhlwVaE!pN8J_fe9EAyy!0fA%-blVrtd+PyC_@Mm6XQcd!eo^)7;Nb!bTJk~1 z0;86*s$mtj`m?;k#wY2D>(iTbg|f)$&5l&(iJAM@q_y=>YYg$B$+nJ0rTPmd`=us- zh#^0vOA(Zoa9j)+xng;*IHn-J!ERblA!9ErAH=Uz8d1-fIvsZ=eVq2E)WNIyq+T#( z5M5JI0cUe8dO8cn4PsR!6N}CjPFF259jd_-tcj$KM|Hp1ZdP4BH(nr9|t| zK$P@s!njL_-Y#XWW0s}%OBn!c!6}ROKS2}k3nI%Ig#h_8XGnATZ2yJ4cw-vg29?ak z+AQ){T>RxfkBi%f(BZ*9YR;iVSYK;`n;g&1u%~r^#*k;vp)W4eyH_s!Q@Pnvx}#<8 zAF9ppd`L`Vnlf6dRjfK#!f=}i5?Dl)_OLdJ*XI4*nCCrlBi<8+u>e-F%(i{3-W(;r z=YtW4!0`nRT`Ipsy*8dk+bf%9-hrbsHm-wqufGlkk-rXxMF(4a_W%gRlhX4PL191% zG!nE=A&RyAu1$20OC@jRCWD>?0YFKoI@uwbp_2)qm9tfBz9vq$iU=W6z#%Sk3LIWaS5;cJ!a074U=ED`>ulw3fK8q<;_OOIto~h-vp_)*k+(?18)=a2I|XaYE>| z1l}4~HYGf>x}-CGXid0V_i+5ppNB!`o+*~gGE$p3%jKt3{N~d!WgflfQ;y3;coKfc zVt;j=$9t>aqhhG2H$`q4jF!CvcB%?AI5xKAA+DD;)x6_f)VveMDIc5+1N)R5RFJ=| zs@pc#PDq%VHhW#l0a!!&GH;&mh`b798GgY3;REN zPTM2lKFTWU!+IVMr7*JZ$XGX5%k5PUFL5?VTZ~npU7r%NDeS%)E=fJ9`Yu4#s z87CnCA{MPqeUn?=XpPzh?{s3jL=b!#V96{B{GPfQ_`OnPp@CCTwxrPwY$vTJX>M{c zgLpUhGh+ORt^P!_$}Lz34+^HZa9l4*78b(%w*b>G@0}pOLXdbrI}I7UU!1hu_GJ ze-rN1?->zo*C^5M@r&FdB9JxB>@!i1EG`m620C|Ir6@L@m*2i%zY&D;yEQ!wx=hwj z!&#g392B-@0sCc9nWItV!CX#=vBb$^vExh)UocBzG2vbnAN34~a2#BXrV9ul9An`}T9#K5Axa08tAPtK%m z!mo-lE2;___Qh^+P-3LcXc!y!?j9+2;&fP-<_Nm&jO-W7sZU2cVv9gzyd^OWG%V~Q zdGz!xAKmA!N1u{=r)x2E{r!&aHNVUCkKNpCf4$uR&S0zJq!=W3gVCUya>Q$`X?29a z0@dm^mWEMbKYo8H8d>S;CJ-J+u zB?AYmY(SsijV(42WgaY2b0T)@4YmKXwg)qnujSBO?n`rNc|RPu?X|@)^{d#jewq^A z=zHEpIioEO2~~Z)o@q#toLFEqqnAqSOZ{F&9cJBKd>@wIP@r)7rhS_^9Sf`#77IZEEt;a|jF84l( zpLg6np4={;ldmt>U~5t)BsI7HMfOaYGqUr2_8j87LC~rrkMaDj3gog#Q$m)5R1;|O zW01+W2JZc>i0H;7*kWSYbrswHNA{>?_iLM1{`5J_d8%>DOY1vTG=Hmq`S2o18XZy zXOus(YuuIE9)KsoM2!loL0O-HL~XwYH*a9q1u)|(w%-sFE2)_YHAc>48ughVlTGdPnbmVQ&9$%1yNW z1r_QZHh2vz*)$Bt0p{(DnAuhf=fNn*yDPs-ZBLQY7l3l0PL%h#KwJa{I3ek4@M_9n47tCy&vERmqEcB;8YU7r(5wUA=^swO98CN_r5emqvGnZsVGF)oFiXkQ{bW< zqjgn!eWspH0fC2J^-2e5;(Xo08yUZ4-FtiFB5XGQWs$1`+9HoU;oSzW{`}Y|oU-H3 zDdKfTdl8Z}q~+n$(fkm0jc7Tkz-su(XHti?n{Yb!Ax1RQIt zmywQl5h1PuS)IaBu8oSjPj>I=Bcb+q=4HNPsvouc zqSWv0;SPDxzVaeYtQ(2&kq~04fwoTa+JB6gQ&{Xd3q|;EHN$<^836|6By*$I^R%XRp~p>{eyDW&KP%Dvumc#x(Klu z0FB%2_^x1_?A-v3n=tyb)x+F(5;(NHfbV{iN)1>SKcIh52ID`lQ;vZvK-HLIK~Yso z*G-^@FM6O zV$g*j6`9B>sDNN5!(RrR-vw_c9MKIs{uBU#V07_aFn=yb7=^@TL6#2N^s++S=n}#3 zPTr<{6n$?_f=Qxj@rNB)UgHu>f&Enl7|ymt410nXc-DNC%ODChRr^~BmQ#Dnbw^g^ zoA!Fmn`)@Vbw^akJka7y0Z2I~P%vZ9@AESQXo+1Q7pCx$SgB&C0*I^(V@XLcjef+Q z0B{vNZ9nMDvuTP-m{IWhJwmtd z(2XKMY%pOtccJEwMU!`Fm(X9*t(5pWy6EV6CC|@Pa&LI0ca*LfKJVQ3eOGtB#v=o5 z?f1xS$tFEdm#<{bUL!b~bHg?tjU>W;cnc6h@8hnIQKH?X5=SXoGUKt)WEa1WB1x+} zBQdKU=+t z*mL+T+~?W~szw(!gkj25v5~D7&uR<)UlSAW97<(*VLajEI331oZ0R-d`7t6gG2qT% z?OwDS@osEK{?fxeCB2h+`+v;2n+7PDOY4I;ZtU0gl5a5q+%W06vm}J#ks%{}VT&n` z-n5tuW8EBOw=ed}RK>hR0_E51A-KWME>G-IaFOH6N9O$geHBcvPr4FC6k@fuJcvS# z21)p=Ocbq2UHwl9V8n0agx@-Q+H?Gkky&FVbQ=eAyU{U9NJn0sEod1HuzV`RTS3_D z7>s7)X{lH(r++D*^;?dQcNiP<_V4t3Mwz)F6Z~wtPdJ#m}ow2`)W%8E&ZF#TcjHiR+>u+_!4js=@0H?W;25oq<{1R;UOKi>^ z(z9I^SvsM?4nlAOpnY3rz-9WQx?%SH2JsJbGj2wF`XzvH%9~Ut1Fmiz69S;uJmRHR z=MPG-_l0Uuw(h7A%q+JP*R{K3_hV}kPm6G{g0OU|*c~Ye^ zp=(i~)=na!JM#HPd&MKTc&6M=5@?K7zq=-9+}r+S{ZE1D{{Iw+c>b|KgqgS-H;iE^ z{Ew91D%wU;rB}}uC@uz|w+>?+0dnIt5Qj7Yq1aMGNmpOB09!E%lgZk^x{hV>^uIY>c=^w^wQ$7y&F?$}Ih67wE7BL7A-v19_g6#ft{ono&q z{*0*%ns8W(I#-OlsJ>o*jm_&s0(id6jrMFxs%D*dV}zx8VFlBw$RX9w5stSUmrpzEw{Medq6Ela z4n`*$%&v;;!zO8zYnvT?JSjH1I+`vuQ4To^vf}Hc`o_f+$M6VI9aDMTl7m}1#Ora{ z-pW!=t5#>%T#8_^{eQgdzAAhg@^;i;Mb3rxi#hdN$%!iXAcaeXB0oWT{{956F_1mg z(xkPOk3&3^T+UJFaPk>`=l*h%btAV@e;1DgI?W1zHleTAzY20G>P2AS*dYE2khun0 z#m}056Dkz$i(dE}EjQYB^Q;!%l??I}^`Bwy*f2QKg_Ku2qIXd@N@a zh{Qih=FL{&DuTR{a4pt~nm(H$JSDIN7ZPXU0#WCJ`V@T`f#o`(yiu*ofx*m|&{3?<{d%d~o&)uhDUhcNx~@c9#Rc-uHVjwbVuV=h?OE zkFS$gGB!ReaozuSDnEsF!*cci{m#$Al>Ssf{5ZZ zso!H$L~Jhy3K>rW5Hk8~q&`>OFL!sRK^)Jp^Hi+P&_dF6$t%#;_MM`Bzg1}KcRXd( zV_eF#J{pw)`4*9}@nRYt=~pesG8)?1qFYH`6qFm!f@F>=Edn@AA!})RDEM7$1S0!i zfNvW_R7h!HQ|J3cHlXJ-m++^Y-1YbjtIC~MJ!aMr=J5 z$N*T-@mpO8JF4qf)!2`#f`o>jC?zmfM3tk= z+=o0PAS|?D=9;#X9goM^l_K?3FH{F96r*qhjR(IsG;=qC`z**)QvuriLjM6FlV6zt zx7VoBAwDjyr;9r~M#86<^i~wN%!Vrl8|%%gi{E$D8y`(wirKqq3S;gWy}Z;e$4w~~ z8}uK1fhwjpe)t?k(Cj3~1}31Voa4k`Ga^mfpUoGcfKpet*Y8F&I402^a)c$0wyb(c4YF=PR8A_$pbz zH`y?_M%^VuE{77d{91>mZ)o$OakC?P#B2E0%I#~tZ?*TNO4HB=jmZ&R)UyHT0ghB$ z%3O7RL!pDhiJmLizwZJpkY~TFN(y_F?vJ7ECKVS#t&Ind1}b9IS#&6$8>Q}^A$MoN z{<8R3z2VmB@lB5QXr!baBHQ!P0(?{rpF8EtHksn$9N&%J#~M5(y-p z8k$o>!079sbRHEarxP8fZBdbb-hj>t?|l9A7;3uC8`q!q%-Yp)!z2L){&|?M`8n8f zs)Klml49bg{f)FVdAo$Bm+NTuDIY#(w8wiEIaE(&(2rVi1U(uX(@OciIXOFRy(QNNNVc@s$!g;+D9i%J{7=CkIjCMvt#FW^qNW0SQ}dcbpde^_QEb~_84uODRZfYs-@fCxS=OBoJ}*)_s9R;z6pi0{w zL3fG|I8Xk`&lFT{M<^GUTDX}`eZ2#}P5nwNe%=!BQg=o7?B&4kX4n~~W3YdV&n(fy zaH2n!=iK3+V(t7H)te!BT=$nf#LThRMlz!H4Mwxd`zoKNzr})+Dr@KdF6F+INWFrf zwk!Wuhx8$=nCpdO|4RafwQ~d;u4B=C+wF>=)D-6a?pc5XiC`ngZQk%Q?NnRn6~P94 zZ|+}--n;`p4U~+XcQ1_HdO++&^54c@peuHWLn9So{~>1PklZ`h|GW77Z&-YW*aYi) zPdbZ1MZxk4I0PvI>VEGV3^!8@Sag9~p9kqHD zK6!|W-*TN2z4_xuJ|#zy8q>FKgb&cLGl;<%s7klHZ z2JG_QJzS_kfWb|b`qMe}bz}t^1&TGtD-mwu)PCcy zc~qyPwCEAkW5Y2R=>X@iB)3XVnnYC<^6RJIw#)T&O@&YX{Hc3m@a?ptzhxM!9<{2X zQOD<=nXgAsT+V2+d~2;{OVs69l1;xsBl#C|RX5G47V5)yoq_ylR{qg3me@A$#GuyE z!%jV#c>Lvty-S;T)yD&MFqOG}s}53wsXWQ)q==>KRGB2$SOO=5eV8cHb5pC6$MeB~X}+oRm-Z7D8^0+9&H9e#@#ue^@^@ao0J+7=>-n(I9nUqjg;G=5HXMT#{5!Yy;~mM&r{(=I( zBX4Vu|3^ye^40&{(z=j8@45oy2xwI4nX#WrlG4DLnLpZHZXXq98u&5?hwnu~FrI00 z9ORJIH>F4ucxW{7>DK4)87;x}e!QBW*UqKPyNcX=~7Dh&KdqQz6im zr+Z?{H%dc#0y0% z3-5^~HW6(%+9dS(swzU!-5&(T{PnB85kASawwR+O#e&h)8kQ96(yGRw2esX+lq{H)~lKT$)a~ff6 zb5_jeU+m_Ea#87Z!^$1)2d|9|Zm~Gy?eHba6AO=Hl1an%+`qJUgly5uqvomD)sy6fA6`?+-B^&te$~O5!j>^mpX$PiZEneI^zGPL83f4a?Bl0SnN7_ za(c{XjQ-ffqn_N;BkQtyy@8;313`SBta<~)I?DX5_s$qL4uUyc+-I7sGd`=O18=7F zMY$L!@9h;!Sg5|~{N^`X<+c;&FX}Qi0 zgSz!1?|Bh+?RjMZ?Efr8OWje`eI#^iKEs&CyS?U6tR`nOps-Ezn*RHuEpvCO6L_om z=7UH6SP110x=c?r%yhv6lm@2i0eb!OLbbv~yyj2=m!k&L{2FH1FAPxmICgFmo(xD` zxq7B@c-MLLLVZd{%b3V|$=%EGrZ;fElj7Bg|sqa*)r9^P%G~LC=Zjk*7BsBj>9P8q8;nE68 znPg@x6HceO7S8j@RQ+Km=Xpq!oj1uJaMABb?eXY^zf^p(*5MN4fzblRVdRsBU2i0X z;-jrkCjX}iZh^5alS_OAYd`JlK$@=jvkFW~4b3oPZ;zf5RG3>ew2A`DJ{z3OySwVE z7aY%D$_adx0aZF8^wJpc5Lh~YiAc|jUKNvZtrXDd?verxdXk;Vv1VBtIECa*7A+Bg zU-Sy^({7b=96X`c+vSFG2r-a)cNhD-WU!Ew%j4}HMagl@{vxTKjL?W=BZ@)n>)#Qy z%+ES%H1XVfRL1qZ!3}lqmp>!M0&2bYcP-eB`{Z2F3?w-M3yMEwv;kX1C{!JhxpfoA z*P=$TSibNx3Up0XFWf#ce_5bKS;+f|YdZ(gO!?5oE)ei*Ed?K{-vNV8`or{DbI@i+ zlX@-pp6xT&mxyrYOo5WsV12o%$CySqvQ1XJeOY6W|0hR@nuAF=7um2)uyGP*8A!C; zZx`*)b^$3ePK&M8(Xy(0g+`&O&CAEp&dZ(Y*$27Pj;k}C!4C5_EWX;LV!3*i03Mq; z`wRMOa=itP4K+vQ%o-C9{AM^EH{q297MIW~=mNuFzuIdggLB9>9-7tTsoKhfLtWY; z;6G(`T9=t-Oz^ldYO2FzDE7KLfp0P*$faQomp^DdR_pd1mtL7*?n}d@LYZ1OD8$N2 zdBq#4h`sv79XI7Lm}GcT!Fs^4t3hv{p>+pF_-|G{Np?X@dB>}6``>HCT>yK<{mOF( z1TEU3@m!&-N{i+*51mz2w-pTdmr=cw=((5{Iu69H1Yj$e48{2&ub~8Ll8?VGxYb~n zQ;YLDzE=;FdlR;nB!>R{L5;AN;rK$P@jyJ}5|>I^@i1tPO)6S29K^AHt0*DXx~0k& zp{6r~Tb22b);w87%YWJXBnMf!+3)dK@7|Zx`Con_uoWkh4Kcn@;jy+~y|~o;68~3& zFrzXL^fT9U`HLe`@}T$2PzstzfWriPjqckq-8O>o+}kgkW@FYfbr=D;#Kx_7@OzS( zaxEuBoKKPt2TTCr85s->AMCwrRFe7o|2t-7rDcxhAr&g8 z%+fqnoMYJu(jS zu~o~oiTXu9430dsdFmH}<5xA1ni)lX=BqCDJ#=U3o}CfJr~O_|%t#VEzEfx-wzKeh zY2~w*Q^_H*k@tyvi*s=n+T7ZXFY|SsKcLm1CK>VR_lO~YaTAAiwrH`*J$iyYW+QCd zTbB0mowA^`=J}JI1=4kkS4^)#MbT)IcnhLgxIrt9n)1}EoEPk`mfo?>7H*`*v0VjH z)H(;d(bp|DGHm z^M{EghHB(ZJDAtOX7;I`Jgj%-k5m7M&~;Q%3~t#E-sf)WtJp|SX6_HadO2tkZV8~d zrbeH)vfYuhM#GKzw%PC>pbzvBo%D_u5KUj(&{y)<@)DkO@+{NgMuJZe&xT1=A^q zWvJNW4{X$wo+C*vLiF&R3fy{+=GzU_48g!0o8V*9Niy+{KMg5OwlHfgV5bh5%@_gp zf-wy*o%9J=+tmqLZ@U^RAF6>VBi|0I%zGd4fM|)=1Qln@UW0DSPkrDy8B2H>xhmIb zB+}4UfMBXw6V!)cpNOr&3v~uIt+@7e_Io^3}xLmUE7;Rl; z(l@3@rQstU_=R+a)@~M#3Mx(CGV@}*(UVeo;kQtpfr(8a;SRe3_h4l)5uNaD*kOnH zC$VQDo0w#j$-sfGqOIqeEL5(W1bU+Qt)VWl`V7eA<74&0)zRp_X3s#-J^oOe z@>!w+Fl9}8&j8|FuYhWSKxx0RHcw6f7eoYx=P&pgaa!NBgTfVc!R8GnKN5&|r=3XbiJs-`0Vh?Jsneh7BV;D9yNBcxKZQoR znnsGlQ7@8jS&Ue)9!}Sr7A>mKKl0q>&Pk7Yvme|1Xgcp@-;a(;#>qP z&y#O4@_wG}sDyLORwi{hD+=rib}jAsl8@@Wo7`bVfL*+?GPANM&%3;$_&9g4qcLNm z4F~)>PYF^ulN->&UWsSZq0c3P+mstxrnFnfqC}T2z+R9nwO_aeq1rLde5&WZ?1~J2n0zy$IluY>Og|b$KAzDcF(5*KC>qhv8yt5A zT?U^0*!VW7XWimsM`%$*4Q80JiRBA=W6srV1gYVH$;vV5b4};j1H2!n3M5b2Y8-#m zh|cV2`t4lfZD%`8X78dR?V#F8eSI&W&{nK6viQub=w>J*GXx zX|wZymF>YDKKlYc`dT?=cbTljGo4?3zGCZHYWW!k=ONp4#-Z1Pa?)}*?%U}~LEQSkTeX4XSfqI> zyL2?@j>sUUG5ZMHVc*a)_hu7UEtGgiHvG#dgPZYXFsfLh+>w0CDg=<;R2SvR_{^D- zOaF)zZdZrOy!!_ozTeRsO{8Ik@8_g}3zWY;f6^SL@wUtkf*GzAmZ1#c#@ylNlA<}v zK?JR$+-^Wt=TJhMQK)uXt{6F0wggZ)HkMd8uf8R+aAT&=X>Bt8(0t3qm1jDQa;RmBAt7T(cz zxnB4~D^A zgB;ZYSjAbH#jd!mu-%riEB8m;RP>capOq@?(hb0vyfP(H4PfWWRbOb!`75861~Lo$ zH)dviDdB(0d(+^By(H?c|SoO!5@WSKePRvrc{+y?qtSQJlQtoHMtY3STk1XdM%Nqb@W7O^% zy3um}%i5UaG3T=s|JIr3UFRx4*R<7xKx4G8$@#m`Z@~6&1*oL%^%-?<(Fx%s^uA6E z_Ogyk(?hgk&keEHxummA@1I}I12Sf4{=CEG#HmUuxu9|>CKM_|( zd==a~o^LR_urf1tCdWBH6Co+x>_;xsxg%_ML5|925F|y}5aSJNoJqZRn<#mNu;x6D z6-kCJ)JPha4g46F=S?&a_smfzAZ}00okWpCpIM9Z$8+$p4S&o;++j_8f*uk%c#Ed} zmMzl6MwX)SG@&Y4xprTES4yAu^+qIUKesmYq4MDF*3lVBV90&n0!i)cLVif+lNmo0 ztDH-AI3<`)`g)a^>IfdwM4~lwD6faZ^A7YcomS_*`k{wy%e?;QzN+uuz-M^O`!2{2 z$>yv|+NPg7opRf$!-NH0i(2OD&N-9riuRKq)yOgQViH!d5#IruD;)lx7lDJ;0v5O{Af3Ud{P z+!8ud8@;$YhCE!q{B-!+(%GdmdA5@pE&Y4y-+}*TrxB+wW;0q5e}6o|Z7f{i{0eWf z;-B}P3n`Hi*Prb$sB$}GPnizP3;;dl`Mve%W>{I3 zU^`@MXsoje_;G!-4}~uvPYfqpwBqt(mllE+ZdHjY1=}&WaW&QZ4D&BBI6lrMrmqS8 z!j-ws-rI&8IXrm+7Si<${nVUrLCaP3C2a(y&27WQ<7}+EuR%mx&^Bk_8MgHKU#i~g z@vgkW>XbaHZ@y+EB$UOzB-%)vi*<2+miGQ@TVvSYW{Pl^LI^s7;3J1Z9yu|CD$2vo zGUThARri2Z&qc%8j0f${6I@_I$8hQ}!87(7C2mmJ~|5u;0tpHPIl$lNZ%FNzjP^*{?}TKDc^) z4JLU{a90Zs!Hn(fFLi_*)_(Suzr}-q*hsnM#H84tgQb8Xx5f=ekOaY(4yDuA*@Mpa z6Hg3R&JLUz5a0IF@B6dZkhj0@KxbHFpRQ)<)6XIp_PKsFn7qw7?4XkUO{i@_k>5PzBOT^EoJ5*C- z@8Sh?SRrjsX{Rvx+S=Uh%1_Db`fbmow`SV!BKQH;O#8y~qzk7ZB38>O~i&wH?vXQD{~rry{$hV z*fPi9Ve-;MZ7_;=xD47tZna}Al^`bEJdm^#UHA0=qXpc!ggWP~h)wkoT>q@25~LmY z%T@Cf>XJA1z(n5>LvEbqBKhP%QWq+0I>@fEl6t+J;cOz<{XI`^xwssiUK65iW z2{jz;`Po%g`9p1(CfbQa>zd{t`UD0a@_EawN{$cZ*UEyHLo&t;1oKzTmeFy`H>b-s zUh3Cygx!${=^OVdE2IT~l|Ryyu1r!^I;UH{fF^8%20vPse@)OA>QQBK3G$rd|GdVIqB)gWhe`K-%Hn*4@Pz7o!ma!MJjNNA2$%>qXr>xn5Mad2(~6`5(h? z%fx2hG0v_2<~zHS+& zj3$6hN-_v{J7!PQu^4+(t*r_&;xqDBRk9$(!QQJlJxu%@S7*SnwT68_t;1Ku7*Rc4 zJmxk@nv0BzP!F-8qiFrwxDpK2Xi9m)39GPg4xekl*^rrCS}hIqEZnd=D%V)MBQ!Dr z=)q6X*n~R!F6NfLKRX|0%npuTP7H?4lg{FY6<()iDuMaZCb~*$CkbNrR_qhVHGY#WT=K$ z2AP(TVXK!zj*~nOz=1&UvBY0VCM-1;Oq+`aMaB{KV#k(?8-q$ZKx*3G$UjZeM5`D; zd-lbp_-N?B8}K*9I23ZfO8D*$Xw4EeWAbNd8X9pB`q{Rcb8U+5_H*MBzd?o67lKPzX~M3wCw3N~ z)(m;qI^-GG&ULmX`a}aeFOd|w&nAtS=+W##RCkp*JjF%fhQ^GywS~e~Lr#O;qYu86 z5xi{@1S!I9jYW+juRT1F2Y)*zY)Xq8`(9mWsAg@L71>cVbE(UAd7VG1e~{Q(U@ym2 zl*jS6LxMScCw!;-+(inDaDFx9#U%P7$rPI2R1e~*i6t|Y=wC!JKO%} zb3`!_L@S!lO_7LqV7vAwaXvwEh5c)J0ihQm595^Vc9lg0vm8mAFJrUtB?kt<h zFWmyt`B-e1?j^Zq@X)~!;k1J+1nyM)-U5RKGj_b9;AmI3_jdF|xSS_iaS9gtC-E+T zaAfUx-q}{C9A;#;GACV_de;+;7vz(lmtt>f(LS1NQ zg*ZJZ7mFCr*;Df4mgud8))D&>FMg6Kvs?n_%}=uVJS%DC|k{6^KD+L%o-$TpbyeUHhg> z?5Jr$8BMCL$oH>8f_j5Oy&26VhUkIDw-^q`P~P~JvMsHAUl(e{vR1jjheLlJ2PywD zIDdoHJ4e3aai5A-=%%55_?jv}Bp*5v5(s)pKEDCkZGQoMmA;$00&3v+OUV@N|-lt1<-bu1yED8g2Ls(q26DIIH!V!>-XbqKhCHO`>%@ zH2SZk@?S~ie?d|)UGDyWC#meOr;2wkXSkk>1$#B)xq#1hy~3{evDEqeu^Z&A17u{c?%c5P?--}$w~6SU>(tP8pSK;yeJJ0-Rvc06 zN9F#F^GPf8H-lf^Co0m7AN&z4l8GQrR96OxeeY~yi{b`lRk8v$V4la1l2e|1GG4sC zpTvgGI4t<>Qh;QFd3F*9oW^%E^E_zCkQt}*Sf<&}d%!9by-K{Vyx+T*JyCy!epMI*x)JRH$SU+&t!YA;1Do^Emq}V+ zw|jd1NHRZv{Q{CR%t0m!fV}zgO}vI2MG>Uu3w1yS)x!E7l+mp$-Ol~PX>D>_l6H?~ zux)9WaAxk^*r5T9so}S0L!2lsNr}4D81v&xOCwfzU6+u_NowFA;w?rl?{HOGv-g^B z`y^Y;p}IYWFC#A(hEX#tT2cEvnEpm;_<5_5l#J0eQARS`tfYFl0i`IdLl> z86+0lgIb>@8p^Yd^Xov8pEcwiTWt(AZ1wuTfVFutl)mcx+gZrMm0b*9m-Ivqw)}cO z-EI}=0WO7Y=;HpC&#L_Ui4E=H0QdJ@bVLU~xm9u~g-!BE|s zM$&Ww0o-QDFT~ zo3Ch1pR!<*E>$djSZeA_sG;-_B3_5L6MTT41ua{)iNyoA7Ik&x0|<9+c{ zsIADB{oL)4hO#vNsfMChZEnQ}*pH6%hR8OFI_@6I)VJBZ7!b6*|5`GJ;Xi4bF6nAz z$U()oUqz#@B7;UXNX1Eo2B>Gky6B_QyNDwZKEBiojv#kD^DF5v1`qVkvBL(PgxU>8 z_HMn=v6jBgIm|JX7#cqyj_+)F3rU@Wo{h1$1Nbh`MFprz<@kI%JR{aca$wgdh52XO zX=W>e9|II_7v`CohOxydqNut8Efd`_S=%@J;Q^50cBcfAuBJ6L+bS3^w54V!Z#xf_dhsq+s1EI3&D$dEW? zXM7EX>9bX3JAFQ8k6CK~-u$+x^g zh0=`}9?oFEul+4KL`|u!wRz8&H~|lYy|F&9nR?HA&Vh2YWXz5+eO)bv=G1#7d7Qs! z^+Dspsew(vKgXQ=4!chWyXutlh>PBm(o1L>QgE0wDp8yt;KAhwYAd29PI!;*Sy9x_ zKLiUAN%)ewrrB=et^YGCD}TL{2&G}uZ}KEsjB??5Z;{;F`_Pc(k>vxfwYHRd*0P|3 zn1>AWo`bX(wKdc{*W3u^(xJE2f9{*k7>f^syFB7m&K87U_g%bNqO45~j5+Q^@TIWF zli;`hn(LVI`Jfep?%$D@aZ&EucWrtzYu4fEcAuC0HRVI#NGF0)d36gmbMfZLU_L+* z4JKYW;EP$hdw^qbPv%S-!@P)e>iJsBS5#xg&?MrU`=U+xi4OXIv;df?88g$)goW+^Y2^-t zF>RsE(RLlk!HLlJQuscb;7+IFsDjJ8n3QZ_lD&n&%)L1~SY4yo4SQq&Pj&J?bw3}z zN%GfJ6rmp&>SxnN(Z8x*)biqfi!B}MB}5Q#Htc%IW>Ay%TT>H3+CZZ&-$s&h+sK@d zXWMUUS)3=unG;+D2uRL**g;^u;l$oz(i5AI?zaRqd?>#lYU+HSHDh57D@=eUBmxr6 zZ@##SJX^ZQE|$A&Gu38X6MQvtlf8l&=Iw*A=KlQh4LADY@WUP4kBg7yoZ*Lwbgx5X z^2S5AtjOdI25~k#6GTBp{GLtPAJr|QQE7n4rCxr1lfB4`ZTJtJm|k#$SmNY=_CD9P z6{kUnhv(E|+F-?H%}5yjJd$*-_kjIPlWyWlks|=&=;`+ZtXY*I{#c zP1%|_8(~jMnQgC429a$mh2A%I^qacRwYe&^;*I}LEfPuwM4EtQBOUU^Ot;-79|*CK zBNRGUtorOv<98dI$4#$S=>aWtOx5qO$Q7Wq%26 zt8{z^?wV6x{IVq7V_1k`8;2A9<=3)(SOZ6~ds?lTGM_ew-p+8f=Tcvv`8%BoiK#KWOhyOJ z|03eZex)?s&1P&H$K(Go4-f>>8p_3k3ajLDcd;fSu~tU~by77auz@8B>IJs#atSXz zSM@c~`;~uB+R{q=FqXG4a#>qScr$%5&p+BF6S0A#Sk4May*yP~Flz4|v;0T(;_bM5 zRpx>#CERaeNxUs#dcM>`tyxXUeDb5wpnpUL%j+4Kdk6TsZX+GK+hYR!UQO52t9XMxR}tzN=3Lb+im_=Wucw_m4*H*3;q8s3vu*gzqrkXo*9xU zf&$?TQO1NqfjrT5``z+R0cNneeXn`3Bslr2%;Fv^$%t*AZJr9?Exb!T3v}}z>R7N_ z9AD|@C^bo<-NGg#LEShX4b6TjzmqLQ8n%o$6k>sansYL0a zBy@A=^c)I*}ql9Xs|j8k{Lpm(BpDxw$HT@3B|Q zin#FuXw|O_l85j(F%$G?J_*b7)>j_u({?m{F5+Zt*Wbz@4?KX-ur)V%_IN32l6B_f zV`zy?pm>D6kee@o$>CpuNBB>%xKgFWWc*dY@bs%_q)Wcf1E3^nE1IZ^SGo3I=2ZoB zW-2S54kYtN&A{bpPNA$ap_mR~b&J7LX#`t=wC#A%rFMsShMRo4Daov3EZ$sZ#|Vu?a30oEGWzp%-5RxfD=jOJD@t)O-2Sj~ zH*ui&B|A^jpWkOUYtb39u+NesbMR2@J7|5B`${uz*o|?;?F4`el$x-jqz9ElRn?pz zMHSZAfp%uGt28@Fn^nSNV*A7=m8*T5eMvfl2tdwO%05_OM;j*|6qGrHeL%Mm;E$wJ zixlT=D}$@P2phUdR`_n9h#oJGUFxBFs@Uf4<@Wm)gL77MpDfuF!B%4)I*rI0T8HZ; z%co*COH1Y3M5gZa^7E&mYcPS}iI~!akZYyHV|a1lS$dm9!)!#-_NuG32rKM17mI^hYBMqj>eSa;jH}Kw6v56~fV4G+`jwOjeAP4I&%Pm)Dfr>E=_rq8PW!l# zRTWcB|u43>-{efB)s9ogl@B z>5?;!`tg|LF+HwRoMNEd$SM!p4Qj<3kvs_%_kBAONb0H=5>%w9~0w`(^~h&=x&}ppkbeoJ`zY{zu`W~b^=Bp zI|5|PlkSOm1Ja*W);R#P;+4+5Mz-k9-jWxXGy1r-@xMz3H8og?hoLytdU(C%Wl~0^ z&xxfQ(v_88(*{jB~*az>|0)c7rdjA z^%%5c-a1ZUX-0J4!-~CD<&js(-GZb?!5o=6Q+!hwGRcm6_SUtd79|R-b(I<6Z52%n zuFNH+=mrY6ULN4Bs1Pwo(}L^QsWRZy#!Buc>XKeHZgix+WX8LmgQTsmv970#$_-bR ze{|L6IEaYVIoBSuGDZ`ziQxeun)R;^h9`5Qd`#1?PW5>4U$PHIf4~+#HwjT=@OzwQ&vprGQ`!G;gjPV zG0t0AQT8%p#h#obJQ}eyNfqH+#pDNO#yGxWW1BegAjufhKk#<(H|eb0@Guy+;PVJZ zy+8~ix5|{KqvcB_?Mgl>%#D(MuYuJ{tne;1g#Z%73rbJ$Vn3dY>9&CT zD56HqcFj|DZJcc>F`^g zM>xQ3V|vX-J}Rt=7^m}i^fLZzG3I!r6xj9Q#ScD z8F_N*7ZUduk8vYmJk+t>(b{F&`RN@ zku`m(8M8kc^z%H&vpb=w^gr-V42&m88(G>mdj#=bYGlIC5n!$gfzPx;d>dNTCt5Z+QgeXWfz-zy0o|-k^fAinM=Hf=>*fxX(pR+R75^We`l}B z%B2Cq*xirz*5})atElDNIJ;|J@7`N_uPv8t<&EqyWA4o1MHQzwRJo>^%x@l!42F%B zX4z^i1M!}iY}7`?{bRDjLxz`=E^JtQY-nm`3jtpMh;mNrwK~gE`I^3}S=rnz<_2HF z_%3}T$O54DNxeuJW5LAhoqa~3k$qJ*M4j1dn2A5mkkT9o-ix0&PkVJ}|Iq?czH#0{ zhIqCM#_RzxT)!#1QI+{pk<<(W=24`v19Qu%r0}vBZ5f2uXFVjEQfJn~(B@#D*kICv z3l>wUvQs_$L$2j59gu%UP#!aO+KtSsANDlQ&o1dRqA8zF$<9T#)6K@)DBDULg)!V| z>n0rD9F@;-NnW!;xoa0AYKyRUd@tV?+B_IU7>khZs(M|~pTBio=#i2|Q-Nn=8mdvwO76r+pep8{)pCZwx zI>w`n*^8Kt@kR33c@Gwb*v1KSBlpD{!YR0FQHdreqQ`yFuumN~&7tf0y!2eUVfD%= zY`7RLI|)q708Gb~MPWbgr2M?6d~7-lU1A(+&`I9F(r@@{SSspNI#1@Kv)Vl(!4To4 zZS&a6cDQEA0KkPbwen-L$G4U|T5n$tb8ZRfutP*_TTXa0?b=NcqyYe`pWfJWVjE?P zVry|VASUz57fGpZ6Vr7+^P6hz;YPd6nDH}!xFu4L*2qAGEzBHtVnRmFcdjpvz{P82 zmPSB%>jl|z6IQsGa6%iX5bu>n?#AWYSqeyjvYo=ME??&vl}RlK0&uR909EF_9_)1l zv*N*f$p>J&hu2bT#vrkc>53rq>2i)Q26K289&LKOq8qWu{Zu$5+vt?Q*7t)j(*6E< zhOneH&4lSlH;Ifcyw~PF|NDlZkg!xIcJp3B8`Gulz}g?N#oLAF1ebbq^}~@k8=e}x zaA3?zlYAoA%B?Hh_D%RbTW^3bGJ&r*V_ri>ct3yVcWUmt+^j?a+2dD&HYrahg2GM{ zgVO0I0sT5#yMi>XWyTC(oE6xVYzPKw7qx$Dmvo$s*+@RTZfXt7u9lQ0?5~=2t!e{m zmGJ|XOU4~H&kAy)qj+{Gm%x zAWFP#DcJ+=of~&D9``x2m?l?UTI?JkSpM_w`QgPhrz5Gfv_%0>N(9}L@FhB$vLsDq zW5|t|__L=mt?!b&DFgAfaE=#kWCM0`ddOY>$JcyePr~78gmorpM5ze5RqOCE*626o zoX-4ez=q&2^Gin4Iz;hDlf%442U}_8bnw@iZ};IzDfa1(*yQhTKY@c-m!vQ2Pp;5< z6*1pI!P8GbRn?|F;(J#jW4*a(GEFD*WEM2n7t=YO75YLSd(u00p`9|lKiK7U3}pxI zLU(PBT5=d^*vA*6Ij_9s7Dn``D8`HeNXm|}jgx!aM(2yoF!86KewX!GmLVRc)P;VZ ztTS72q8<<^pf;8b*XWjYeLOI3jFCt~%ov&a32;@-vNSDOi-ZbB94=e)d3Sa^j6%tbaW2H!l? zYjE=6cznU+p60iP+dD1IMqE6aVJm-SOakZ(js3UqR2FgWH%L7x)truKmV9+zB+-c` zf^M)AZG5KxQiW&p?S;tS0Z0nYFvjhc=$Vc59ZDt6!2W^2K%lG@C#$EPH>o1-5|w5v z_9vduj`x~&Fj3g{-LEgb^5$^`Gsot7_{peXZEi~>QgpW6@zE3X@8H{>hWbTfORo-0 z%MHNAMA}+y0@IaYT@&)rU^PYkGzKI~xMb z4$7?Eysa))da;_SWp_?@UB)TYx=>)|h71-rJ9#u~ zdH^li3-s1FEw@%bk~E>%M(E`Vn|c)t?8af=K=l^QorG)^+3zw`)1FuYJ&L4Wz*F~BneSQG8Ib!&dqup4#;;gFy30*Lmtxw*R{{HN){3Gy6 z$UY?Drw=S8_*W0m8+zDF()u%k6mnQQfdybu=Qkno$09c%26!RO>+F9uW4qvJkD)S2yKMNq+j%AMyl;&W|0 zX5B%|5QiY`!wvmb_EU$iJ@Q@rq4V{!^~)KB@{MH`U*;}WCQ){c9XhM}6+xXoJDRK8 zhuY^hrO@jTQgM?;blpDysb%gRT*1?wze&S`>&2=)1&P_z&=xmZy{tYiICP(ZtMju* zJ`Sy=jSoWz()Z^%S^KTa28PKI#44YUO-u6RqGT_=h{roN%oq30gzIP4@i`fi!ZN@= z0Tqh4(>_Ka{T_V8btx?I!3pcj&5|q7V5tV6 zc&GK8sPEtN&K6vF6miZpWMTgvYaiU=z+Q8)pDL+-{t*;=H^Qe#@|<}@`vh>q#+qlU zo{ei1WPg&0+BR!u@mW(xfofu~d5%a=WJx3UyyzkIp(RN@ZWY}Oc?G8G^1j))k8Yix zRjBNFKTFYq-$5XByQGW6p>a=12b{6ssOq^uOJ0X6;A1o`cJ2Y5-C9r{$wtUwq{s+4 zerc(4Qt6q;YV`1rxktkT$TYgJlkHv50l=Q{(=$$LgTwo0PvvD?K*_GTl@3!MTo5

Vk#$ED|Mr5G=z;or9&f05}Z`okECF)BQ12xIGWVEOUvql@_i4?|W zScAs~Kz`5~ClQ%nLoSvp>ds^fs}moqW(KZsf?kyo+!VFf`zDDIdH@^ zmm4`5Mrve3wQ`#^%ONr8k=%OOEtF{v?+NZnQn*{^g5K<)^GPi){E(>HVgA~3%euw$ z=@a$huT}GwS~p-jTnp-9z12c_rWbMh;w|%`ocU*pqOxFXWWTmyUWW79-13d9s20w1 zlc|TAWv9^k)`qTt)?<^y3pDCWB%?-3jf&*cHC+qOaF>(^I-R|Jk9{uu)#(0@zY#)#yifpV{c8AN6w{ zoFXyZp4X*8T<4c@SOW8CjsiGpr}T;U;*_PTTu)|+?+kiu)DRs2%G0*hzy$6+2ye-g z)n7M+V1bJ1H;5Fl;eCI9v|6~N25!Us z6WZ{PdZ>LisKd!R(R4N`R|BMGebq6bUhQcF6X>mO?CO(zaDZlg>oWtG=OtrOXxm9h zD%c)^w}EXhxi<~bSU%-u7AkHAq`-OL6S^|>X3;Bsk~3LE3A)J$GzqjcBSEg-jnlRZ zQ^?q#C(Q}F zAhPnO(uus}H2>jU+eV@`!GWH*D!DwU&D|6M7?Y2@ogqF+pSP@(T<3HNBKLpCI7+&?h&v%a<}TjuAKMt zCbQ^s)6lF3ENKn8A9{Zh3zb6-b5F}kDqX}&(W7%GD~lL_jsU7zQF-;V_g8{(8T zV^h!#eH{910Q~3Cy3}$ZUn>6>!3j_`-O3#-=$GYOkUPA$*kS(KhKIa&5&N7kWlsAJ zP<(O#hBh_O^%~&vJDaW7U$S^m1fA>`y7Fw{v>Q&#$r{(@_u*}~gBh3H7Lo?4h6=KK zWv+~9d5r6+m{vr5ts31wx4yR|v&5!lVQ0QS1k59YP2~w<0kkUN*Q*lw$zYKWUW*ac za^b)`OlWBy&7$1pJHUD)p9E0&@1BSE@PGX+?O(H)!BZ38j@r!}>)`~`%(9r^26>x0 zx=o#Grz2`oYtL`fepSo%5-N@?uMVQjw=gR0`=ja@g6R)X_r8nN(0f*)EAu%jWBGSE^`*vu z_BbW(4QVi8DuK$6rPt&D%oB$3A$vR#0U*~MQBmW&wpoV=1onHYxNpsp)ptcvXt`xF(p19m>0*3*vaQjzrWZ?UggwXD(Yuj>o z^`miaTvP)PPIPC9lQ-7wj?|*G{vfV$<-D+~$p4QP@FZlm_0G>ak%d|fNu)(w9}u4f zj`n@(t>0Nc4ArpL9Ni;Ax~@S|Gp6xZX1xXJ79&Z$1|PVkvRmWHy;9y%Qqo0b2+SpD z7|yi&%kBcR#7LJ3m8>eh$KdsL^`%;y008%Xq8B*g!FI^SF3iwmP8!hkOexyeA@fo9 zJ|<2;&-(D|V}2OepCs+nu7QYG^~s>8x175GX|8`sXZiw?l)WD*4PU{$WNL_&se)G~cVts_-07+oW8d-iFccYw@drI#8_U)P4G>y_t|t zh~R_ImfGu|R+dc*3K7c2Mb*j9EvKCX5-Bh9iO_YaH_c@f$9N$Vm;+a%bN8 z08r~9=uNE=5%BtGze~agVhcWPu4=0*lyB7?SL#j>65xQj*1;CA2PX>F;2eFMWe0-2 z*Jj^6NbGn&A`O9=1V^OShsR-h^k(7xCHHTGS``534ym^NPhD6Zw#jas^upNvjgOZa zR<{WDTe{F4*X_O-WVk7R=KK*|mM^Lzj$CDva|=(2&k#o^#MJ^Cp%4W##Ff{Qt5;|C_Nxi{JgE zLZJ}5E9X@~Sw+qP16x6LU^*4=ty=Yn%8)*zfHHjD{UW;%Xhu1RM&(ywRv z_M`$lO5yp}7l`$Co0A*+6TlH(l2(9L*|S0Xi5WJ0FKJ`nS>UXg^9Q!ffTan+*}v_p z9yF@b%Fz)x-}p&Fs@2?Xqu8KtJT-xXt^p`hpIxVOddKHV(%fnU9g`hthhhS07AKQB zKHKYc9yiiQuwE!FY)F60XW%U+4eQw9o+4S+tRGc z0ZUfY$QD3XDIDLbKJVCfA6SmOU-+k{9mIn$_e)i8v^Xz~RotBi4zDEqW!GU?LM*f0 zRF$d&ccj>roc{Lm1#)KjL0=Lm_hlb6+rP~VZ&S*&YJ=?tgmHRC0PA|X4*Ye56@uWq zW*;}V_Lp^wk8T^edjMSfar@wfTaiS76#D5YBM*daK(@?p)mLVXHevvBa~zN%-)29t z(+erEZFvp65XM(a^m0Z~*tLiAw`g)90ql&SxuISDKa2OXn6QAJ>vd6-SdO4rQ~(!kiUFd zsZV2Xm!~;34X#@unPAU1M!7$ds`VOE+2C07|@l}0Eiz@7~HeDXTkAayO@SbbUQI; z^+BeoN{w*scqG0Ho*lh=-{JMERhwBO>1a z_vjvC$BwIV85dJBxzu!(B}XF_zUleZr{pH*l!TD*zRaz&m>_L`Ws9BVio%_Alo2{I zQ8VWp1Bg*}4BHdHcv}&mAIOhbj@OLccXi*O8qh2W-qnU+zn3ZxB)6#b-Mx!6Wf;ow z<+YI|(@AD=JFHf=F`AfSn0Kpet3&N`{SpE^&_5#|n$^wFHA`OTzKhAlhVE;EvqCQn z^!>nCAU?Y1{M%bUb-T2rR#G&tRM@ot0h8Oi{4JER4qn3uDuxkC;)csr!uerLsKn>B zI4;?e^ZJn{C3qfhTa5)48E#=TCgpAf)_qu13S}|KGf6eQ9QxTS7<~q^!tJm9gE7IF zFQv&&1HPo}i^mG}_t-CX0a5%ZA$ zBw!f&-3JIPct)VijD^7ElhHGe?eb+Gmf}VuWi5euM-nc%<<41scb<}Zx*iXaev2Dk ziaWd3wc{&eIF0|)(aGr$tg*nvAL>;^)=!sQQn>;{Yt)-(;JHr#tP8H)KU?rH(RY;Ug~Oet z&zSqN>?b^bn^K?^f2}R8J>z0s_nG<3Q||qS$CU#qI&!XGIQJth@xA*TkQ7tvY`p0F zm^5#jOY4qKyiADK=7z~L3of_G!aSORG4);`7zPN00Rmf_&WF&)kh@_Q!2|dT=o-L5 ztEb)vlcA?KLQSwXt6T|B63ZY9mQc;MA;KN)$Qc4+`u||>%)^>K6SZC3KtYg#0xm(t ziYNjhDq8|=QP7G+1qB2_2#bn}EJ{{_%Ayd7ib4=bswjvHh$xFf!VZ!^RFsG)VKIa~ zApw#Q2;YmH>~b%;`C2<~wJ;&%b*0x@<2KC3%0(`#krJQLJ?dRH1k7lB`4YEADOL zs8Yx0#_?_?{lE*p5FL`>JZ0^>L`Zl`tyPUy99{LK1RH94qu)YPE%aKT!st?sevoR1f1d zas0+C&~ka&Hg*xc9DAzlwdCH^D9cjx!}=fJt$95K4in2=NTEr$uutGWD^Bn<#r@ai zkW$M!NJ>1EC)egr1}2g(x?hYLDj@ogU*odF%lTC zU`%b`NX%1ejOh?|9{dpUhT*$ZlfDWLDa$dmIni4g@54LiSdq9w{otwSqk15Z>&<*Q z1|Qpl%$gWe0hyK}j?XdE*66BNV}tv!hFm`zwi59zyCD@W)E2IreT5pZ`BNP;WAFp0 z-r1n8-g-6@Od+?N!jTX*kR_Eyovzt~I2qqV@rym?Ge}2~ooURsrIbGS<3mO)cR^pqJdHo<4{8=^}dm#vM8{#lCuh47RR<^yz%FX%yUc$Q+ zcl7J}C6ELL<)yzlVs_(*L!v&1mk(3VkblmJo{dxW{bQ^`7IdHALdc^XV^33>4SSjrCV|4&*M<+W0jXp9NC9*5OB2V|c*eW3@uc&hd{@C#`e*H{ zS_fyl+)o*AMA+Vm+!Gx+FUJYQDr0@ie-wg;=#aDU*DT;Gj^}>{$Ag?eDDD_~cQk+e z_BZ_@3(T+mp_p5yfPHH-Z28J0~FAV4`SR2gPoWSx4WgLD;dBJS@vdy6L8T}{J&yhPflE2ea z?g@>nJ=5zEc%wf9V7@zAUgew`xQal|1>9CpOyE3w4F4%|%g7q|GOSwp`@NDA=&0y@ z(0tS)Y0X>MoQ{`25m7_?u(#}q=ex|f)e)y}oMbN!**#U!@-$z(mOQpHb#bn3Xx_b{ zV~uWV^{Bq9dhN*<1yI2nc(c4pSA1{{s<%FEb5g(}^fdrLqvx1-(wi;8?SUEHaqy%= zpbEKe?ny4HRX=A-&5+rtAbQ<)>`aVxcBTh9Z)(qMp_PhJGHBKo5*DW>pF`c=6Bufa zF6ZbfyXpCwq^2o_CBPt~VSs?Lit{XLq{N zGLeY-7o}cn=Q`Vc9}yAOkG9SnZ8vR<;+}E9!>`%0RKpU&70WslZ4OuIcK{h zvGHt0Wrkl8A94Y%5Q1YKyC(7`a!-5DR90>E**NAz|OT$++yhIa8Lj zK^(kx7+fs8if-9AsUV;OHoqK_O~cey(t_Nh5X#|Lc4XM1fk30~{L#|OT?g=`+$UXG zUbe@IWIM{AjXxX9HAb~+oPTs6?3mrUd{tQc>y@do{B>FBRgpHsjPF=j&&JA(?s8`V zOzUZaX&~`@AiBM9Spj@IlXf#MI369x&|Hk!zu6Q$tgvKO4hbS3NIh#b=5gs6%%Jwx z;0I~lEy#y5`rb0m=sLbVf_cor?wsj(W7WfV*Q)vry=#N>i|p(elAvo=P3ON>hQ3yY z{zzr0kd-~-n4tJ_5|K|%Rb^ClvoA`wdxAV9wvNYFRa`7ia%H~t1P@cVYM=Zg^R_a221wn8_e6Lt*hR$8LsWtr z@^^$A+>Ve@+^TCnl$IBlg@Tu(%0(}>-SN=xB&}(t>03M;t8WcIRDRs#?M%K{v7%Vn z4R^2p#7W1(GQW0@3>Rq!Kcr@@D+M;!e~07LRQT@m58*1O)^LD4ff+;$Ady_m6+Y1a^DS~x{X7M9mF zoy@H@%Jyh|*9AI4B2mpnT6x%7AJE?0o!=%-b)VQ`?bGNr_Ug{;WA&3h@k$!zp~Q=reg4CcRk;P1Go|&QEJL4Z@t}8(sm?UYX_&^}=~F8@ zOPqesqrpe z5A;W}SRlDsI?GuiMyYP&+l$>!d@4=wT4jb06Sja zd&e@!^n+BmHd~2?eo%NWzp#H7fP_C_W#`0sNR~iS7!A4G@cMy(=P<7faD_ot1w8t6 zsDgrRQoMQG#MNotc9)8f!SA7Fh_eh%$E)g5uu!|8cc0&gV!tUg`*``1^mK2M6^F_< zH4ljERHa5B-z1NapNExqdf0(m;Q?J&`Zg75c3(}t7Fd)y4ttaxk+N0_E1i;p0-Od3 zz2|ZQNxjAGYul5}v&T8QgO+=~+ZQ?K-m0vid3cIdr}$78?kOsvtHY(|7CHepZwh(< z^l!3bav>K2jKle9wcq-o^We+b36AM|$QN^N@#|I)$c_4J638Uhx~}@Ri433{&{|!- z?tMe%+yVAM2$berD!7`68uG=s+Zr|ycK(_L)T|T+JbF)=@7ckB<13unv7VhQd@G-A z!5O@x4l3ivOiuW~0J6fFeKc(|P4c8#eBE(ym$WL+u_9~S6|%Me9^P4~kpQM{6F3$h?m<-tz1f>wZ%cHm z!GP}=(u^6fPYl0a`&#r<-F%;fOR+ixwXR#z#5AY%EwkmeXOb-rww(464~YsWwaxzM z{NO+l2d*~R*}|VpoA^lX$AkLqYL}L|ucrtZgN@_u*9s*YoQV3>sQvJC$P1*#kIi4# zW&b~}%Y^C#vR(f!N-@m3_BSn}x>Nt-Euyc@p|8!MzuFw)PeM$JXLcMgktmTv&2rG! zI5lD|?6p!l;-i>^WJE9uHBLW2G{WmKN@BJ|@yW+WO)L-6wX|hFp2Dj4j!^}lwcj@Fukq;#Us3%)8pa5y zb}YreIU!EO1`h`JyLi++)Su`1;PacPo!&ZuMOjuRs_b137O{e}ABejt<3-oM)Vw=_ z)*oH!!&1y^5*7t*_QPCEvD*qBJ4e-s2Fpcv4tWbdOoygiXyXbFjuv0kSD_QEQrSh1 zI0s?1IW%`M;npm!yg445(n5-w<1=t0*5ko{mX)l&G}CaY z%@9BQxq3AzwP03R_TnK%MIVKYE|`{6x_6E5oXHE=YQSob5J2v0z^X`EEPk2<+d|O+ z<+Hwp*}5qHaNXH__OX9sP){k0&L6qQQb#5AD+MMS)wLg-S?jzt{9KoLGxTteD{OYH zWT^YVJupu#hMV{7lcQcsnVA8rG~s;NmT*e3pHKDE6p$cKE#)Q)9m`jx8eG~ve74TG z+CQeWd3IPsh#u}VGi7yTZir6hyZJYE>P%SU?JCY;h1q#lm# z#x4Ak0Uo9Jfm4n;xsF5PKn)t>HrBeJneeRBh}V zqob|T*8#wo@nEIkjMtIb`zk;@iUSPoq+G$dj}^Io@oIo`hDvE0Gb@#U zX)sI1LCYq#mZmv+sR(d&7F{l0v~+5+nm3)BAH}?3;r#i7)|3%=#2{MdC{QsHTxtpj zXdoP={?3l8xzp|(Q7JE9fnfRtf#GaYXc%}5$snhfgy=6@iW=DsJ&6=G5 z%$h6;^}JKubVLx+C~K!Ftxx0x#K`=?Zo{@xez>b+;}AvxrLo09cdxLtq|g zwPnL&xXavHdX{HN-eSi(f)c_~&wyH5L%g0c%!|0qg#xXAxr19*z1M2 z8UUe9#dulaFs9KBtOPchHOS^9n3pGoAD*wf%%Fx60074-=ppXF>FJdQosvT$_a0<_oE>8uUP%xDqX4ibVES<@DR(*!Wf!>I+~V1zGq4oQw{b~o$1elft5i*JI8oOT z7NOCH5~@`DfmL)a#Z;PP)ma-J@U~^dO0r`sQvRSAW~6pw*XR;kmLr(8i=Yk{yB;@` zUGc@{3qsEsvA*00f#nuMGr$Wqw4VEoo?^K{=haDFzruax^%3U_V9Ibe+X_3~fc<(B zvyB>Es^F%Lyc=Q(UUlWHN#_jGKB>#Gq_ME0S-UsmWe|yQW0OW#*Q5y>vjvji*h8qB zXVCe>VXnP+NE*yC)I}lHbF7W1u8ixNzRkf^BbpLY7TH=fH(SMiT<&Wz?i17<&1X{Q z+H%;HW**GXPa2$3>gQ{;*rQ7zS9Vu5WQ|)oy@QU&n`*=Xup%M3GSn+ zuCIe%jNVc(@atVj?m5ts^FA-@7XLdy(p8t{aeU=pkb{^Z&EC-UWKCaduxg(Jk(II} z1`d?hfbF}`WO{LBT)uooVbsln^qOa&ra4^%G&uv5542v|%H)p(OJtz>!75!f+ zL;rG=p@J<=tAi~BrU%g?b==<^9jR`@_ERnX*e=;~Ds!(usX8h%=L6WL1XWb8I z;L8Bx1$`i@E6;lzIRYoXU9p{T+_nK%|7vs-#T5w(F!7U~_cL|8jt9QU!soP(3TFpk zQ^Ji;gnd5cpKqbnr8S{ylY0l&5mSx&8uq`9vHf2_#SYti1>~2rh*h+jYvRCLR{aDxCnM zEF;)FAK@L`HEIO$?Tx|t>`A3+(cb!>MbCbyu-IW3m1(9TwLQ-6o?jgV`Xhm1@J*;g z0+i}wYWvQ#EIiNCBrE?ZUFpqK?lLvO|M05t%z0R`a@5rA^&lgn~bk;6b z-emFpQ*e2$C2sb|LMF3w_TjKGMx8r|)#6}Xu~@ihaDKf4xW@}unrf?@2NY4ByR z_rAI;1=DFYpebBZ4BuP7m)dyNiT~iz>FIebF?_{=r{165_y=gq@6Rf1Iwx>ax{ z7<~`r95Am8d}+eoUZDn@MS$^s5Ct`(=uu)VPm@FSQvpzGh-?{3m^J0 zuU1WJb9>8!K23fMg4Yd6OyaqMZ<0EA(Dk2DpzuvM#TBKuyq0wYrEQ*RG91{0&Kud* zDZOvbkwuJZuYXVfEK1;`ro>qWT<4CmpjPLqleYQ^gVX(2eKDKeAI7B!HoX&B@Xo}` zFBfW>Y9|(F6kUH<>UI8(a4slc%YVF%x-VVUEw63QL%klqyxW3^J`#eia9iJ9ZV@dF zllqQN-0a6QF4B%9rc%+Rc8BQPp4;+c%lqUCvS;ywtQbh|}NqC?UNvlM}a8X&u& zPYFGOs=JflR`XFy2xcGbjwQ(w0!|SYaV5J8c!RX4H$(%P4cBdawR}ycTi(0y_M}hE z#qg2$XZK6#B$5{HU7T&As0ISUrbMpbA zP=M1_WSPP!6Ld{Zlh^)M|*iPMZdM77NvthQ=Z>F1VEBcR@rjm0kO_1_TJ6jK;9`UDJ_yswW zL-+x!4lqyEJ3Xm%J1cp2eM>)y8?|pjo(JphxjN?i8$sC@+9WV|5<9l16-&CF=w*Dy zUoq_*-s~iLf=%{lbsyZlI41wL%hY1iH%6tbFq^{_?IB6w={{JiDAloZ?yg01feJMo zF46rw8jq|QM6ai};E#XkFr`{u&5=&ox=)mNL^Yipx`|CrE@_;JGC}a_WwZR5Q>JC2 zxCOr;0yYKj3S{ttx3GhKB<=9&74kItj`neDr_i@ZIXv}sX(O_JE| z@+6Ry4R|=iCKuv!-IfJDO3`+<8{J5sZVb+U)Hu_|IO7>OY@!}G#!9uCS~VfIIvnp? z$8?uRJr^DZsA@7GN55APoJQ|p?+`gpZff?PeE#K1&bMx1ub71^KgLo`i$IRe0|;mF zS=0*-|0$qz)LA=FbOJ1+W`Mi?H-<8r5oYOEL)pKip{yhm$~=LkINdN!Z(?^SiWx7< zp~{J$IDD}4T1IrJG5pZ2(P*@#W8*&IpvKqs&_AR-WD5oDq1UtRq1&+kFeTd8vr8&Z zo7=%MOIsfIGS$4>8=qQ6`T-2k>gWN0KA~G{!R)d1#fDY z{Y`T1pm`PE+yFLj5Mp7D)!-dC1t^)BZGbhi9n8JEn^(i!oHpsXK&nC#AM}S_evLbh zzzSeHN}11tx~x7|lP>7x*`*t?4mecgqvm-84v+-Ji_Z1mB3S{%M7wn-wxewV&f5gg zJWF*yF9JNGEKNesl0+-iB$eEHTKn}%i#z5Xt^pI7_gS*gSaAi0d5hK84 zy!6eRx++c|IhDB#HxGW4xIi0H6;xDKdC?pRCL^o1Q~GTeG{SlT9-h{+7OUMShvdyx z^Jl5Cv&EI_0)5!xwDb?H&-Iw_h4zjMp49>2FFsC^w}X_W_gr}lijMJxZe&-vvUKpk z*415VK5$HuA-{byXZl@xns!{{9khymuYp15KAEmT&1rXk?*_ASj-;eQJ8(cxN#L(8 z{m8v&o(Daf91^WYysRnQNl+_jyVn6YYVXtLQa9;$>XXcKNw`_pLu>&orv5vP4Ai`` zBU`9T$_G*y| z4C7rg0r<_Q@uC@jtFPoDuI{ztDw&c?%&p1k$LW*#u+R!|0O&jn@{dp+284O|uV?n0 zj|VBamqx>PzMo%XS7r~SeGeX%^&CjDmEjetz0nd%M7CKfVq`wxl|dJsFN^*)3#cL` zXbM+}W9mom_q&|nynZGARwF=78P6GfO!zW3hfk=06tDiGStjZOKod-P^~yC3SVw2M z>8XmiBh{Sg%N}-3@Aq_nut(pE@~qiB%YaH1vx)m|Fcq1tHxg$dMAI#QTp+IuhVIzd z>33HD--D^YxYPQ}W%OQ}JC8TzPWRZVgD&mUM;)JmJ5Fv)iIi_#(b3Fv@n;LT!h4e^ zG8yD&AEd@9qkhDPM~k>6(uVqA-)0V=rc6QEg-@m&352$Bg#nX)IO~B$Ew}zlZ@DMf zu-PvyhyXK^WJI3~SuWkcv@a;bmC#&6xI3YkPcOlAj??zhBEUp&Yn)fZ9=T9xoH+C* zYGaRQ$(i?qWPD25z%yRiIPa+%KA|ABT$MTd;LAvCQr#~dIG-V5hqWVHrU+ge>&1u4 z_YfsRMS@48u`9BUfsiP^5S__@$0?!uE$>qYJ^Y)*1}huEPBPaw4a|V7d)7GJkH5+V47kDBB@>pc zE3PnreYKT+wUzzTZDnad{@pstzCTgSSXJzBZ2WmcrPs2TeDt1&nGaW_4YpS!W)1cd z8~Ham4|v|c*Otu`isOQx+=sUhXP!~yOd;A{%-{0;x94vkY$_HRaNM){M!q#TdcSv4 z{XavluKQD#R7niE&1&bLZc}p(vu)7%_qO|)s=u_|yP4Me{Ca6pHgUJ)`D;g3Ev75|uIQK<}Oa(BPwATH{t_Pg4AWVpb1mX<^0; z>IJKEzKzxVGlklt9O=h8;j&+B_o>L6C!=y_?Pm19X*WBTGwrjmup=eREJymVMb4V{ zs5`NZ_Oo8c#KRrN8m~n;*OyJ)8(N zEbp(1^bjwxtsDCWC6_>fSNW>qF!Q(rrMSNX0sOHsKpe(~3C6Rbra+JPS_>3rn%gfA zd(&DVRq=X*y1w4myQI@D^D6hIt*TquGMBa9g*21>dGr5V(P-m;Np@caB2grCdA6>8 zc_L^uZ0$k(A(L4MFo8v82dlm6ak6iI!D`9aw7Eg3>svRMWnK8vbD3@WM$f1#FZ~XI z@moe9aLcp4b)a+!8#8`7_TYARso2q3f^og?EV1-n3`11iF)vml-vTDxRr-E_Kj%Ox zNO=Z4YfDRF+&bobVJoWX0aSu%)9E%`j`0X znZJs!uEo!6nd&~_v~2H({cETEzz)r4O%xhG^ve#d_R9_}m-ERH?9jMoC%Ibsf8L=n zu=24#vO^=5bGs$h>lj~lXpH0@jT4b4cNW@K=-Fr3*`0FlCqLpp#lG{pH@idA`71j# zpFi!;xWDYse7@|^^uO%TbV6eGImynNSD1cr-RFOAXDVIsM_l(rqnT7{o}`rNbQHcg zjldqJJO<^uSynry%3g}!$HJudA9?k@Cxr75v5;sNUXiZ1-lf`1wtvgRsH4AT0S+G% z1=muc;6JN>U#tf1owLyKn9kRv*YHM$=_n%6v(&|wt2Uv?&R|UI9eIL2>_9;V`o|sl z)Z^eFxK-A8Ilem|W&=3X_qf4MANBlu6OMg{0t~y8p<5AoP%QG1qkxdTA#zr08jq)h znpKYn!D36nQRNJ2HPb0`bo$^LGsJah5MuVm-HUD0PR+sBf`ZPR3xGzyp#}HPqFCGf zFQr&l|4UG;kHqL*(hPJZMGGi~@FcfAG`|-~anw{mUa{iI95NF)rczq@?vFUsfoZ$e>n(+l@&Hh6$>&-Kz zUf3ooqvlD@YuWzZ+wtoOTy9D74&s}!xz3LLa<=cq*g8?r*>&Ku>SU*sh5E&{h7FwVOJ&3b=I-m%=L1bV1G@hk8cQTaoP^ zoBoK^tn}^IE!sbDi}p1|`rno!*^fKcac4k|gst$CEVUzq0JIw56?y!bR}}vTctxK0 zbP4s$U^s15w~+f{WfWtsB{sF5a)k`K;&S>>+bL&9K8^-BbEdR=7G0&!+oO9PG%Jv#} zgniimq&IBgwW=>dHr0Jex!rCTX*&8Zl6G(`Og>F@og;KA`J`QBcYM>$>`HytZqp*e zXxddSGewMs5uf52^*bajTV6?~^@~rr84eEXoZ7x9w4BQjf0j-f7~SieDgL*iA4@$M6TFiJhRH`Nu@iTYi3Lg>?y4b%3Pd? z+^<0+|1eg0bmop#@1~T}ap1N$txd@%PVSmX#E;;8-dz}qkMJ%%$UbRv)`lx8LACD! zZ+KL|Zy7~eKG0i|%;?vbx(K+L&i*vJhdyP0t8PU6uhxxBIhzbSU&tY66sCxM;fJ0@ zHitv~=m4a3CuC>=T-(&0SwcQG#2hz%(ks(c2QBZWx8Q4w1Irv;vi@ClLkNiS$0=Z5 zTkc50bY4ySPob;>&RSl1IqDT!N)rNO)f)Kr>5$!FyfyFz-o9f_N;JVcvmKPfI`B;^Xy8k@*O{Z+~lZGXbE&lY8@s~dW zHtPfdEQFcx+M|eZ&}$TZv=~d&+rYl2>z6}v6HK6xPOo>UUZd=2NgB9EtatBy zs;&kHUip)N)lIlj_r2hXD`dC1dR>oN;vlP#wXwyDT_rBdxrO}n)&NIc;BB@CtwPQV z_QhNuIr`BaZ9JxnEx0w(CY<^v%g?)BTX-oqXkJC74xcn>GA!Y8{4TX zI#Q(Pa*p}%cR>2BOjhhCbbIYu7ol#e1NDP$cm>5Z|!Coc_}y5=9_L6s7x8Q?-v#kq z*rTURQX8UMG?uK&^s=Tp2Te^RKH)}YYU-2kXo$~ebZ0PPiy32pY9KO6jhtFAQx4>2 zv|r_Bf2D4u`n$SO`AXva$?uIfwkrYSs}&WeCXzA@yAjk&+%2@5MeM{N=g&sA42=}T zsTA&?F-1h$Uzwuu|AQ%-=Wj4YcRM~z9-2Iu0v%MYY~5J;RR0<$Hf{K560<7&+Uq@C zIhhm0Uol06e;ZRo{CAilx4(}mV*CbE)Y09ZUpDdK`RAE-#@$5tg?+!P8wEck{I|^a zf3n>(hzYB8Hx^b?z@n|qKVg)6y{z_s&UPQ*&O#K9>~7wA_Hln|fc!k)OpI_s08Aq= z&bu=yD1&7FEu4xEWh_>s7#5#K0Ol}5y4%0=n*A|;^H z4`RSVM|%Wq!!WCYTmqOH<{nO)zz(j(iK83uQKbS~>7C|cbn<{JJW|onZ%h8^T|cD$ zfp4}W#kDu33#!eoD(ta;7-U_o0&9JeV#UgJK5lmY*DPR8s<6@Xn=h5=H3lpd>0Lb& zTxB5(WJN&1QN|vctw>|z|B<`2w2eO7(yimCz?o!e!{Czgn=bBCt17#<@mKzm7I}P4 zivYFgACeZ$sLB{)Z#VZw)cj41HH7#gaQI)TaMS?`^-6KID$qbZ;M1A|kr!Kg*#Yoq zc?z6-oJBJ1dO5xhZbh9-t%p=e;LV@S+!PJ6J(0!EiD1j{)Nbw~jV_pH$C2%6IpBLx zeJv|Oe=bi?EIc~JJ*J6RG)BqJQCxbtc0;n;!3@#k%!K!H3 zR^vEp>t3sUnmefruX?O|Bgl7SuPPm-jvn>W8-I#xChTi!Q49<_EwT^T50B9hU)2=e z!;>`qERDgbhSD*J^E$E!HcpC;G*`xtglyO2=)QPq@qHYl4jj&GPWq=)k10b583of!@R z5#4Jv4O*#!-pi4^g4-yTix<|tPp-~&21WtXfbA6V&BwSJL{DE<(p0oj)!yl-_j{%} zX_lR`C;Vvkc(|EUt9hxhc``4wvU+R@Bv1MCH8Y@}R(Bb9`WdXqzUWS^I_HO1;GC>o zC`^b1cnx=w%(B4NuO8kNT6TO=yZy|Tv9cO_y=o=yxb+F2S!N-WjHm*CB+#`^e9Bos zwX{o>Mb)UlzNq-_GS<8oo*|-Ik+8GLB|yh_A6V~!#M?zK*S#+Yp(rGF9fB2ChP=cLH~GfdaEt9^#l=r-WE7l@1K{B z>O-{_Pc2daCq4T{&tzDs@b#K^_~)9=pYD!TJwz^$pSptyZJJORGcyPYBku%~7308G zuK&v!;jCeyd(Gw;A{zyy2r4fvaD<1uEq z$F4KtI(=qkocmGm+~O#jQnY~^D0nN7j8WF-NP6WrXZ&uYiczw_cV3;m+eA|Cw0LFz z1NV;M2Pe=rsmQAc2C+J8pzw^sw)J?=3->za-&38rrLc4UtU3$Itc(2XJtMAb2;=Yf zjNJZPJ)`z%BCj-)$tnWYUyQ>EHt0!8xc0?Umjw46!=87<{2-W*x_PX%utz))Jr$zr z`bYDjuh#po*8BhWtoLZAgdhM(AFu1d-J{kkq;~f^Zho1e5fA=(hPLJp%+Qwo(HR=^ zZ_dyp|M3hh@o&!1mUi=N>;G+rrvGJzR`_Lx7BD{191-PRgM3`O8(H>Ie=}DQ`g(fH z;xWQZ{iF7GFR}926<2@s5=aDaE4nR{%1Jnct&~TW&54qu+6+^8!LqVjZa6WGqjnte|v`J^V=DkpvKLqk6?Ht!Vk^uutQ^eH3oG;;zK{ZoZd(6JGGasDKwK;K3yI9)7XH~>OqQ+t$A-_P07g6+_NF>oAXz8WZIT5MyOzA3wu=IBexkpPKTcDVXDp3#B7;N8=ecyR;Q7H_-MSyZk9SzI%SKo&L$lAnSIz(1?`5)4uSoXb;Tyh(47_yJ2@+1!e{$wZ<>1+uD`_HBAD2a^-lKEAYbtE82U-`vn63QsD%O-T!uPVv<8tC#1zU>>c_-_PQQrX_`%P%&N8oY4UjiQ?!S_h3&H;-X5CiU8 zrdM?#j>Rdr^*9RhCpr?G!oXSZQBDWopHby;QP8n7H9<5=MTC#IX#l^tlH z$U*}XQE79i{s8$V$YrMF!_?z=Ye<6E*z~JQAL}@$%l)$s?DZL*Gu;XbUZ%)((DX+nRfD;F9h-?Xh31njO?7=$W6kbXIX| zY>pm!9l#t+gKNAjHSZ_o!064{LB8e&on6wmvG?GrA!eDvy9}jg3}4{CLk(Hv74n*Z z2dW_HR#>WsaFpn}!#n?&33@vMD5^ z;hCY-)4kVYCc=5TUPT}=*_;o2s!76^8A;YvjIzgdjp~m?Z!#3e-{vHmRq@TAy)#tdDT|7h#-UMTondIK#TLqxcqX?Po6);_^^!DPHn2uAd?Ss_h*>W^4&`W zo_%)X&*k@8u63`-9>#T7=e^h}51gFuCUpy;L7seHPltyT862nKJjT8ea3$ZCm0wC? zuI?w3e>McaJI3>TQNF};$~*qEPB^w$QxO?9b#6Fs@v&BAOVmX%zkczi>4Nc$gZVdA z$7jxT%ydt59@iMBJQ_Zl;&#F&F?F&#a@|)Gd%W2utrG5PQ#ASKB%194)q0JNf;G!hd3r)D7#G&Z)>UixuBk#=YjiH5!D-Q0dvZZ^A+7C zmFRH4Gex}uzqBAk56EpCM%Bd?S$bKR>qMV!+_K`Z96Vib2v}N)a#)4`=yQ@8jn$x5 z`Mmxzsly&~V+Eil1f2zhjeQIbr3BW%TH5kc-Sv23d-rjy7ix@ph}fL6b{PHgStPYq*?dKAN_a)y8+dVod>i&CDh0w1X7k@)fqm2ftAnq`?4jL zoCDFm&>u-24i%B4=z7H?bq*UkCo2CtcGhxO4;Y>y79x}Q(fopVA%YCEV%@L{i)#7w zsKt*Qtvt+*29+sRiiPgJUL%K!oC_+jPxaqp>frF@Gm(e3lji`dEReRKKIfaK&*E`H zEGJOeYrTJDyz(-C{3^wp~CrGj`y4P!eS41(dnoa5o3U zFg4uARs58JwMnkpn+9|`)p&3*wNW1xqpP0CQq{|rOhR-(Gy*6fnScT!U$L)lYuzc) z;wxSGAlu3%ui3WZ9S(rkY{DzTd2^@Y_pQGXssW4;bhEQ@!jjMD!U6J>1a#B;BwIe~ zM#VgU4-Px|HmBk1-n-5EK=K5l3`fA6-O>RtVsjvG#}QlDNsK!DdFaIF)Ay4BDQ>qO z5D%^&f`qayC+`{99Z4{AW$2%EnK`pw9ZeqsZ}s#_wd7|`CW$P6jF-?1IJyUwO4pI# zhsf2g2(5c8CA;d2P#Q?SDpv|2$$*daq`v&05{@N2XK8XRNT{5VlDGzDYJ_!EkYc(p6bf1+Fi}ZuIc@PG?TKSzq}PCs-5q zEZ%$7m6?<029DVT*B0{jVHTmyr?)yY+9VA#lm2~Y>gLmeudRlIPBXZTCWFM&+wHwg zB-L(U@on3!`k%{DebS{)_j9662koafziU=C*$V65M|T-SqZLQy;iJ$?J zyMe}WARv$S1+BWhvJa~}({F1roOS2n^`8Zep6`MIC=JYtdIS1MlBP_(3BAcZm3RW# zNNM#!J?z^O5z{(6- zw)-M5A;#6kJHAq^11vjLE&|}J%Ottt^7MtTUpyu>sYuf;5m^C6 z_ztEz+XeE-uuJs?&>6M5@OF*gRkapw?djW>A->H~;<{lvHHF=A7jCRreW(t|<1j(y z2n|9@%RK}F;J|M)x@23`05lO=Emnao3%mcmIlMxD947is13n+VYxWgZ1Dl-04uO0} zv6{8Y6(j+H9i7+nv>k$CCn?wHUcKwcD;<4>*roA_TW#(VPy$xR8xF+dnQ-CCaTPS+ zr`d^C?=eOZ>26ZorOTs#Qqp-@NIWA3fI-?LB1FN+OE<#bw`tU?=nZ`CZO0e zTEEPD3>p*PZ5n6}Xxsp%{;s1%SLPM+BIuJrAGp&8=09aU-{$mlC9C()27^9?+hvO{ zS#@4;+M}^uED6oq#0lBm+>vEAO;9868a;s>qIaP28t=rI{2BcNNWL~*P%WY@efY8W zDV?UxB<^(9wDOJBt9RKh-vo9>r)Z76gqr}~XUGzr(}E9j!tOk#*A`<09>um2Ju*~Y z&g_!dL}x`}NDF1|&hi2QlRDfR5kZ%D1Ttqtm#|vY2QL;|((kj**dB(*E-W%FE$f!) z&P?|;6en8<(w-%sPG`q=V~JRQcW>2Y4{q_~KRuh;gZb2@=sr=STHC!jXY+T#CaJ59 zzL?kOOL&xxQL$3YXu+U+1fl0mlRo6VGDLXel5}YCYWm73kMeR@CQWBl>%{0AEmMgj zQ-bq~u-h}2z?}&lJbUIzM^u-?oh2Okv<)&TpZ$dY>~@N`P_ZgMnyYZ1xD+5eWE*mC zOv!fDW&X1?xsH5eGJ%W>pB$tM$W4PDS zMuAAV&FE4sEO()9rfx^EM1x9|RZrHo`+7x&5wGWzez1_!`XZi=$G+A{py1WpDcoL>M5pnjQ2TT zZ1?mRg3!$~ZioUg82lR$P!^rH(3OYk2u>)Uyr8RF+2qq33_63e;{t$%yq^?rmJ4x+ z>e+9VH!D)_L-+v>0c)N6s4<+&_mEzwtP;O3PBTUh>kbfR%HMeCGgZ*r!C!XNkXmJm z9rLHSswr@%f6gh1pTL}s;rBx{y4DO3J+A?lB2>62D`=4vACIk6HJCjO+VVApebXr* zEeHmY#&b25a65nqo2u+myMb9#4UA_+c14voX)8cY2b=`sb2?PBpk(~kIPUWB z2~0Ya>HZR&Oah(EBrH|RMia7)0aA;8dbL64YkzaX^&N4-pVx@bw8QJ{Jp3_)rl+Fc_8A_=r{cP5Ev4C2(n!<%WUh+bIu$ALba3- z*c|V{2U`|k5W!q7HIb$9l|AR~?iLl-=4UJ_?I!G~j#W)~2GJ z?9jF=16urqMrt;`_B1>Wl2(AYB%O`qddf^m(2%9(fl(Q4-R{}ZhG{RwpK$|Ec!Q)1 zz8IAr+|v%w;1?c+znVY+Z*h3M}oYE`j8gOZ{*gfj3o!^{+b0yYx>f3 z%(|VFxSZ2gdY0=y_%AcOz`A?`=zjWJwosY4GVDVOn(ekhJ zv86WtmZWyQf18hCTH{6Fr+F*&cV!@>uVtWrR2j%;L`=MG^Udfwa<_*tMqL?89UYD zD#5LMD?`==F}Tx=#OggJHUNb3ywfmb@I&yPhHO7 zscZW3hMwgp3)zAOAxBq<{I-5c`sD#cwiYSVsIHf6WUr_)J&Y?yP&}-!ozoUkp-mG>4MvBQ9a!T`uVX|KI}Zcs2wEgl~Q}h7U8~>ct4EfG$Xeo>Z+gUc`|rI z@(W8t8ofH~2bq^>pOk|{7Y{Vqb z8@apmrCGDcUkymJAxgG z$}hha-=pCGf*V)%je6?cAm5S|TBBX8RpEIEpnz{wtJHz_Q|}ml(m%t)0=am_V-PXi z!=GFt-1GX9kD=NeI{8B(x>A@10)VuYY!LRyS#yz1x=kU)JBkc}yeuEu8hZ1m+avS# z+BmRPq-Nn2{AX2?qxIU=vcEv!7~vm0on|8MW!gfr9FcC*=B}u4Rq??SBoCwFIsgn z4;4UFi^|w{t2&?##YIUw{Lb)2KPeSsAlfaQAvZAm@rg zKb#~N1l7;=BQ?Cq5`9GXQSZc$2z=9W%|C(y==J;d^Z*Dt2|EuCKxl8F*K?k%YLOjZ z>t$EDrK^;<^pRWf*rqbkHYFvWa5G>Npn_HDa&U>@qNikf{tR1f>z$yq!?T0@Hek)R zpn@`|4iLgo*qA5qRbUgng;9Q5_|Wlfbsz0W3iEa^WVguC1kNI;mS_KdJ*u zbIRrej`?xHF%mwn_*3DC<`@u8gX@Y5z-iL-z1Nj&_Bd>~RKG9$t^iI z28+K766~XZAie$$dK==bPY9eIKOnnlidfX&G?R6o_O%7{Uv2@lD6F)`ZS^noU3jh7 z70z-q4j%;Xrcc6VpP8{_g^ui_jDBCaO{2do>=Cv7?9f>{FSNcWxk^HqYJ8Q{j|~Uc zXthJfh=z2(9|bl_Sz6Wd2}NZKjOfll+mHsGN64ZrZt_5`#B6F$+eiK4$5RpK6pJK^ zKF+2@eee1y(N(D1`noeg`j2td$1yzN$XNd#DLvD;fAB&v+<6F;Rpfyu*_9$5Uq?Rn zg+(1HL5#edxs>!xH|WMp{)L-tUB0j2*DQd&Hkhj4wb!A7FYpy}*Fq4I@TenAM#gZcsbR<6L^EwoM16khZPf$)31^P7n& zH`HQf2Lj{gg3qI+sq%$vu>PsCe>+pO&J6@3ol70q+CrK7_<0=%|4*P`)C>|E`Q|KU z3dejt{EXg`-Y5r9_r6fAw^96K9GI4!AfC7oX>Q@9BnYQRt0T*GoFw6S`W(Ta{h(xd zdz)w*Dy85WNG6&nM@B%Tali`_=|EkN@A@9NLSFh$Zb($?`oX?;(3@ub6tLmBh7J`k zST3Yi7f_tp$R^k`DCb1Rn8&=UIuyF#>ixcNdz6|FAOfiX&ri!08RJO-&VvGV`^jSyLbibdXB)GAD1-4nGek~#l~11A=Rvh-EMX_wbd&upaRLLpm$Cw`-lEP8kg)F5dk-(Y6)wiHJ^$ItSnA;g> z;BWn`R@-J#E`KevLraaiDUs=udETf1epz{RMZ1@ydv|uc{+CWTa(U48ef-^R3a2C7 zmQ187sHo{fRo#w2DjAjjMcUbdh4cbY$G%8iB8CO5QG||v&S#BT<72uValtioMeto& zpof#?`lI^(1!ONqSeuDP#`%wor(i^=Kd#jBVZ;--ypE9%7E@3cz{gb|5dp99xk!m` z$}(&zj0wjN_ofVmj!W3sQ_4}$>Hy?N4s=|D`bXQagYBBx{*Y~*f2b*I`J%8ln&2F` zg%m1pO?|nqK~gZ!&(HN{N>eH|zvj5}>2;{p>0Qo<8#c8b$*sNf+9QL~TBrJ06Ic$723ZgQI9n@w=@>! z$2piwz4)Q_zUX?{R_Yn6AjdWM#5mt2=7Y~>wtOK`6aIok9s64nHR-<~Q7`|7M7@R) z$$H+>tcBJ}$(%xy3nTjD@B)JvQdJ~8t6z_bh=0z>TFUUKx0q0%&yO2qkOBJCYBE&k zk)msRW;p*KI1TembAi*!T2gDu#21mRUbTXmpV5o(2%B&zRnN!nQOHBlOunt`0t=52 zg&=Dgy;N)c>C~Hr#!b|P(G+8HaJ*f86s`qKCmy@uiVapomNti|dRX%+!8fATl95KL zYx}i`<@DnX@^6OiQMQ$;VmgDP} zaY598n&xa{=x&*NPg$!iu|dnrUMhRG<8t(OVhop?a13mNa-OZLa*tA!(d(zG`#DUU zd3Z*!OFh;98#*VqlJCT;9P*`{qw#CGbaRASvH186k( zzz#uO8MF2R6r$tJ1~Dc_J61X&m(Ge+^-o19N|3fydFUd*%2^u<%o%)~3J|GUbDnq^E)2d;PO`Fc@7vqIgDMe(#_JDA@gqnu%eQz`wk?aa zcC2?poWDu(xha0MC8&zFD4oLD3;YvoX&?5YwJLRcgjt>PUhetl8tgAAa_N=Q8VevXqQqSi`!!o4GLXT zf`F>;(Pv;;O^z5_+#`F*&gFlkU*DsX*wAeaWH|a8s!(pgP)Mff&VW08y8Gby^`#dQm)VI;8$% zBA0I{S%z~p*uE@L*W*?B#8#x@CGc0{A}CzgNBwJ|;L9F7K&YX~sE%Lo(;jy>|Gy5O z{$~sJf8!R+7hA;tG$}=&5jvM_pVv~X9n2s3I~h>;fGu`DTJ;-PP?_g;xP3xDg;i-4 zbA;DxX?!lFacKcuaiH`@PxbazVS#qgxMqnxiQ)GSlRXuIg4UKgwtq;cy2%z!vHgkk zb0Vig_7tp4q*+Dz_yCoV6KSoR-@9iyg7_rn(X@+V@(kYs4>oEYeJ_Sh{Yb_9+2Ey9 zC_J{tf#os9(0Nr{RD4Dfkh4?i?O~#TtnrqK%kwkk1wn3Zp;y*mkXqmdotbqM zfM<5MspPLUD!jiY3+w4%ACm%$ucOGRMUK~9MN!aOQ=AIex_JZM!Ngm|pYQAgcDwsfMKN`4Z4sLJFTBN zP7Au1>xL}M&F>s^gzp)L1|5}2o+VCiO&-oS|6yCJpChW9`CO0P|6$B=8q0QYn9d*) z2f}8OSiJ1FO{rZRri;z6L)LKH)dEn5WLVe1G+bI!7s2aB4r+5CLq<)lx`(ZuLIZUR zrq1o)AHY$aRAOT3bMjTs|C$Ae{bX~)u=a;LXK^uwwjMnA z0ibD+^AuDp#*g`!96rYAYAxeGK0y%1k+Gt77FVcJ@wOCN6NS>w620ep&_aStO&LP) zxrY|)E?-P*YFni2e6+`uuoYjqpf$zO2@E`DB7?hIYg75ukNb-1*%kri<}d^8+=a1C zZ$={SAD_-F8}dg7?C84eHk?dPzPUYR|MgXo>$12J&Q}7hSCjrVRW|YdoOTH@ptnax zW?;U|MBQ%G_@Wig(xk`j?YIV7?8M?1h~BFy!VH!WwzY(id4b58DLPkb>flH6S37*A zUo@SrL2mK-z&n0uzb;}X!M?%|tu1_&kJ2F+9hv-&kWj<>NEO9KB-IkhH;vSF zw)N6exe;a#jV+RX$h7yv$DR50AMux16q@dMFUc`C?L22F9GW^Kmp*UwcY)A9A<#b| z(Eq*=Xg;_LRLz)TMXWDRYFUt?^vKrhPZ&W+aQF8|o3NkC><)KAf2{N)Z5BqfC=L(r zoz&BPt=S+rfe`KoXNR-8dOt2Bbu(|=#Bs-^#59?ah3)N?8+9KU;XLA>6W{He&@!zi zaW|yjq-Yn?7nX^7j0*)#lwtdyWM19PSMk@&!ZM4=>o6qLhIS@y;s7t(TUdtZ*^Tew z30*!gJq78l@3)VsYXl_C@QX)psj>kBDXXZQTc@8$5OJ~kVc69m(WPAUN#WeiYcm($q z3RlH&H7C%|DR`FEeB{$FbMkxEqvCocYQ{P4fJvbyDot*R)AOU3hXV<$l%b6t!K=Oh zfV-2pOs0W#i%Tz5YAuIn!J=dgoAoQpHdhS`v!pKGF))iW$&|z%$W)j)P7}*bYjBH zwpy)B`8XKo5M3)3lx_w>ZQ*yVFI}CmBN1%~~HGCLd$P^r;D_UNOMnF2c=~E-p9$H($NA+oi^& z$Jo99h%)4^_%~HB*jiXMK$=Qe1KJ2e1dN8+IZuw8Zi}ceW^aVXMHK zGYNUUJWVU)wZB54p(p5ABxa9z6lC)r6JD1YYEm!uqGz^nLT~-L5ERn0kc2KOGaqa6 zD;}x2>KJ~JblC$xX3Ktuj^jph8b?af#+gzCYVQNJDaulx#{+M)bb&k6GNMFE%`w44 zWv2Yj4ZaCuY>`9HQFt1Y9<-y8aE%))nD(Bi{(#l~>Dm3=6V+)OD!~l|cjEn+PPJe} zaP6{?czN0`w-jTlqe*oANYsE2l$z)zk4Wo_Gk)NJ6s-B>E zk3B3tIOEI~>H5m#j32~&_?X~{tbS2ooW(7tk*@4{P=l}2Br->9bdSW6HfI@!yTL=& z=BPC5wo7GTM+Q%wcc#*X-q)NjL^^Sew0WA%w``}*%iBhkxt?TMrL_k~<=T9IOBi{( z`kam23Vv+33JC=RVbEd_1}*&zi?RZOu`rq(q>>%$*3fD#d8y{Vg9f@ma))!ZeOWdF zl;L|}s==XKwO!{FUE#PJiWkpeloZQjMzo9|*GLTmfERo>GFLyq>pE^rW>TD{OlM(r z(`Zr6XV`N{IUjfTlLt8TQ66!vdAY2GP`|22ORb|t|Dv|xxf=e7%N3&sYtqJ~fUegc z#yJy?A6X5KtCuVbB%Z%(%?ZeP^j(!(ltKYO6oc}N=!8lR0d$6)_T#O#d)5G1eb`F8 zGEIW!F4Gwf@e0IlL3dAOmY&F}hDgYKBuHG2;o@}s^zMSgpYyhovYsWF3nOtz#I|Y9 zvn!B=lf;;QakE~mlzylGoZ&w}wzlZWeDU13#=y4n&5d180$@>+gwApwS>}(?LlP0o zAg;&a>I(E$^AeXLM+VCT0}i}@ETdsv7C;~L zhyRFILB|UgxDV8J9?<|a{}h7_ROEs8ur7SS=pn1fidC);BFzUfr~9pyxu_4|S3PN> zpzecnT!X6}De7!_*JrzEpsfxfe}3VCw0bR1Zw}1zFFHme@mJ zPvMT|8ar)|xHf3IHq5E(PF&}CPMFFIUC@3?#gZYe5U&vh*~}noGqsKz1PaO=SnhR# zDhM5oj1^}lN=W+sS&F6m9K(SC$}hHvbtfSk>=&9sjjTU~`-)a)&hX7G1wI~cPte52 zK^Ug4KD#w%lT+G{^gkSfxuYwUK@IunuBizO_UfX@h3x0q!^MG)&RgZ-ruS~!8dYYO z-g3f@)w(d^x9R45XeW5!3T)q&Pl_TlBCS~*CUajqYouZ5)Ee+w%wu@zIbhuZV{tv6o&-wz$FX@Isdhm zE_23reM5DbGPPO8yW)=S4;;UBAcjgBaXnVlsl-H`JZNIDF8B&!Ck zB(@Y4>pVBE-bN`gEgSGY;)GWiF0i-hJ~16sJbD|3zUpC{!Mji0BXeMqND9!1oxayA zDK?xEs#YwGXVC`sf}^F@ieVf%Ot(Op-aXoma^^Wd9tn)pW<0*Vw9Ii7qyHR@SBqFp zDUC>4?#CX{%xB{sg+2X`Dg#Zfju*~cpPbiQ+F5M14r|tP{!f=+Gh3Ug{>PVKPPu#5 zKtzvHpsRq#5Amqr0_eBzQ?(O3qGo1AI{>(9GU;{p4wS0r0u&&Vg0WI~xg!2DyL~A* z2~LPHh#tQoQfRfS@ax~HuLlbuwY0yf8U_*5CB=vAI(J%Qf!?S1s}ue`2_`LgV0HJ1 z?pTTswrxxt!juG-cQ}~49E0>J93k$In#lb8Dpzii1jB03q0D81s?2?9o!|xPKM_3_ zvVcpnuysRgqCw_Zi$cHgflY@(=RHu#@LGVvnso4vcZNT6zt;K1Iu`5KwDW5guwY96 zD5$MuMrA`Td1wc*an&o`5IImWnk@AI=1SHbc8yX5rcRX>r>1&p!x5F0^%zBoT>WYV zw!%XV%KSds4-kEVO)=+2towi~@)-OdcJ%)~b~LI!1#+3~jfT8~i8yGo)5-SU8~1-6 zh~Y~w6;93ZqY-AU7sWH7KeW~V&tZaSp%u3Osr2Xw)DOGMY2n^Z6}#$n+ohQ$iNXwMeG~BmAGQo_w}VgC(KbK%6REP?d~&R=E2c%CggQk{x*E{- zL2{t|>2W8MGP8&jM>9gLirQ-43vp*83!N+76)i&FZNWSYF0^P{s%3KyIWx{viz z#|As`UZ~0Y!t{vq^rk>vRoehZ{J0rLw3zot>#$p)-)p5w9ssDIw?u=Q3B<+-tbF$> z_LNSU=>9+TpgB?fzgG{UZ6A`Emgx;&*&E(fpgb)t6r|-;=`puA6A4>UDcfZ_-9feI z1zOb(nhoh?Jb&yNg-ji4vls*6O~6F~l;`BPmiI69HaXbKRqg|2ZSRN1Oa|AZuz3lx zJ$n=r80LFcEKB;}N(H|AGX~WYe&4ru9Wj(w*veF0N7p$<3m7;-ZSRCAR;Qn3y8@URs)0 zInZ`B5R0sM87F5=QRr7#V@CmP}(j5Sop9*wSCYMAbVcRLK_(9VC( z2es^@34GJ7dX;HL^MUWIN*TO4@Ax}?JC5X8L|1)dsy~qKCEDEsHZ;ng4J`Umm)GMJi~^fhlYb~5<>z{#W_ewvFh%^X)s5MjMve|q<#x&BzsJ_S>Q z2itRExE+RNp*n8L^>1K5VP2{&i#>!~lj%n60FR>bw4_6}rR-1gP0+#I_J(_UN7MnO zLQfR{8SBUj>!YhSfQEB#Igz|DQ_qej1vD5H>}kte0r7dMsQITRe83r9pZk@1%P|Oj zaZQ6Va65cA<9chK$EPX);M0vuUk}}i>`+$gSeP;V81W9a+$37HQ;Qa6W`_+@C+LqK z1^C67{!%FWEn+hyp06kucV6;bgiL(_GgqJB5(hI$>$`_IEIMo%WsD>;06M8^(x~4_gM>2o2YVtRi9~_chbs&wjY3^l({E!tHx)?;k@^1RHijV ztuh#J3Ku{}f^ZxwfS3lpdpXBRrHjj*`9_|iZSF=_!M)*~$+NPBVEOW#gt;?06n!J;8CEYLdU323jaS@}qUI?yUCEh+!Ts84J=g^`*sP$IhRq;q!=Tlf%i z%KRR$?s=GRYhJ4$nXJ-kvxLDP-eO^v*yH)_<28 zjUwiBZ_fm191c%=>ZMC3a-h{ZIV)t@7;(m__c6v}0d#{nA`Xdmp%6SaS-3_fedye& zP7bPOMON~HF)`c~VaiY=Prbt0 zf(MoGo`u${Q^@HzvKBiVUzg?nXn=#)ZLmPRxh^Pa(O4?pZSuiLYAbJ5#@M^?XZX4x z#v5JFpP>68XOP_sGdbb+v`Stf&IcXE;IaUx+Up^7sj54UZmP!xJFG(R1CAYCJHOoG zFjBkLSOH_GonuHdcx256GhiM*8XjTP{~DilLEai1#%A;%KL)vPwicWeEQLioop}(x z18QFJ0C3_KqCoFJf^+IVNq>BE`I|fDFa5C`SJR@p7wqW5O_3emA6t+&tilo~(MJfz z_D9CIv9?4r^+#XF4eooz7i-#*qptTmr*Pf7#U+b z)C{Anm=|7f^!qV(Yu!S?IlZ&{hH~`3ROk)bQ2S|h%L)xkTG@G7fNmm2Q)(;p->MfF zE0(qU#9ew6r`>{Foyiz&(VvLDsW`Dt5~qM@}5}FCzPz1%Y%ZQ5m|@> z{>6Ed!9A1X{xn0ls8Q4aujoBpoPx+Ur>>75yhA z>dZE+Zn&flRAN6mE4rhgH{sN!f!Bhj*R)SJf_q1CGkjQSimzT*79pKd-?5Q>33Z{c zP_LHKcfixZ{fX}O6~t>c!@6aAv$_o^gTWGhB$I}-kz;{Vt3S`rdvHb)RC0O{L;A0o zx`ZoygnA?$b^0S*7jJSSYhnt1Y`n-JlD#A3KzZ#xN7hWlRv3#6en6(CuWs2$^rE?A zy)8cbJb??=wPONWHPUZ_rH2y}?G764mqo|Z&MxyCW<^q>F@b`6A9_;4eENNQPdL;( zR$Xx7QFmkHUMG3a7a1m7m(uoG8eJxYe4I(r>p!bGJLE5?S-;UDVnvH@cb=ske>Ji~ z2Ynj!4!RVl_iXFl_q?p*xsa(XSwLbu>2j7eUx5+^ZY7*Ok^98+nyqXK>KcBGie@wHS#tDQ}gU zF*BL22x*Dl);~W@|CNBpj82+FkMS8W#WlqHO z9_@c^A3tIH_VQ4c*K8wamLlGu2S%4&VL6r)%c~-9BIB{HcF}Rhr+nUx2}I2JdozQ2SjRWRdfK zDh`TfHmozWx89;?2dVUnebgHe|2F(IER18gr#SDjMoH|!{WBQ*KQ$OzetW0M*DT=KpSyUg5j=tPD$TDn84+;zz#po_z(G+^2Zwod;V{$OO?~ae z>NI;?4ZAKNqS$fb^Yzp4HmR(k!(pz?8kZuB8q112!_mne4e&kuKE5!1Qa_1=!Dt{; zC}yRJ4%%JGGs+F2B{_`#@ibCQp}7abK`Dv$wh7a_XGi%130mQpf0L?q)yPcbYf$)E z>e#l!i9Kkb?mlX3vXvU90HY{e9g0tV2ko+bf!r$qhdNjn(Kg zKD8+s7T=I!AP?KtD`xR(PbOxn&Q*{tw6`Uj7pNg4XU@zgdqMikse#ss^l)B8Jvy(B zBFIA(oZiX}d~06wZW@^|dQ_V;eso7!Iwk8h-Yci?;=oSk4T}#SI4k;f6-(C`CHx)74PToc|3s^&e_NVSEW-mAsPOq?XfB=Pk zl_)bzxaV3ez+reKlNx%6nn6gJC%PJuA*yK}4yRJa?G#CsPpX{I-38r8b9LBHbhA7< z?BdD?P97t2{Nkogo^iTfX)oVhhE8scyxqeAG*f&_-`UAhufhnwc->D5<$W#NhS(G4 zuQ_)t^uo*3v-%Gxj5_IM;yhty@LcKFGcR_Ip;P)gKa4y8^kCfd+APLEcsDx2VAPa( zk+yvw5ZB2Vnp##^fi_(3mVtCLn(El1LxkJE;s)KBPCm_Em~tC8x|xxE4hlu<&4cHX zHY~+VH|>X9W1qJzYx+>p@?rEIm>nMVq}x?J2E8|mbN3M?qKqLh#>{haT{2PLzKm8G z#97EQRVQ00S_of9#tmwA6rTG@0ShT*`1pP9oVX;*eYvbDh?VEn>!2`Hvm0d`L{9Ue z0pPNM1$UusiAL`}zSYTMC+=faU=KdGOv_nm0m?48t7Y+}^PG%vZ6`gHr}Tu2I=KLJ zgW$XhJ3~ue>)9KF`xNPuK5^&LGH*UGlX#c#7Q7}T+E}oE!KzHL&OEe`b?`=^fy7wc%l^x<5hD*#z6L=^wl16-1!zz^$uFr zl*p18^V%{qlNS^n`=qOEP1|ig+N^ZGxe3n|_B6a9!WXZlAw`4p@53nE2@0?tmxtJ!he;amgAE|PSpWF)Wc1bxi3+`h^e>3-Bp-GYy zLjM?_dN5{Gn?5FPYM%rb2s0a`|1Vc@FACB$DD=)k?Obk5_w{`ChDj&q3!~B$WUJT$;Jr!l5yQu5pwul^p zH%+u7-Igk$dg^r8y4xg7(8=P+)WC7b-gX&=X6*a4+U;tZ>Ku#l?`~ApRsCh41?N^d9N^Zs^!v z)3D-2wvkE0!e| z1A-WVw=fvdSME|m2oe=V5>$_qTHZG#7b+ISC4nHryJkTUNI+F}2 z-9O(@Y)!nv(dVp(HV7*fct5On?;+!K5;lRXXrtIMwx7~+_3zWAe^VTi{)Q<8h|=8? zw>3NJ-^r|(ghlaz4_EN!cSLEWKVk}5XA8bK#%kx7LW==W8hnt{@~)?CNo+uvGW)mv zwRAq&i1#Hb68w;P!7GL5eB?m*Q`^^Cxr&aykKyUXMA)aGnk?1dI>z1;^qiS~nzuL| zM+oV*Fmh?J`{&FS}|S$;8PauhDWZdBmr(LVev^-lamXJenfW?q^LI z&*EkVFWWo4IZt;2EC7UuPVMN_G-Oc%-%y)`zl3w*rKc@AXQkPdJ6wFZQ-}D;?*sSH zR?fE8sl$F}BXlCRP=Is((i4Y3Z}W|`rG}KZ$|+ab8#BzJW|N{>u#o3kF<8iCCm57X zN`gVzb}%SA2?k|V{%7TBT)*8h(ClRSvXF>0mdj*+o7VK|;rW;R2o0=)v;EIMSP%D_ zHKUw1xA!A%@^bL3;N9Oy=gq!I=Z~{&S&qzU=uFIL@e(GlH;8Z)bE-tTDh_zXP$k@x zry-SOEX3u^3_KHY7}iMgaj2K#g%pL#G{q>o)-3MfQNzofcCF;vqzl~E=P!ht-EYgQ z&lQIftIAdj*JeHk!7{UO0v~1GH&~>+&+#(}59sx;uNQWilM&lr^hjAyO$p^tFc7jYEJ~&#|^Rb5x zP|p9N6?-*T8;YW||4D5qCWd=G(%XDNzk-%UXZ6)NtkAt*#$;NMN@o@#mkEs1Nd2FD z;tZ*-pe!FD)4j;%H(2TS?@anNZicE~7A$H&9~z@e&J~7m(V#FSH#I#p%M|MVnJHw_ zPiXjgMrPd~5M}H6v0rK?&^113^>NmHT%^yeR?Nd0XvLO()r#eebjGRT3)DmpfmV#K z8qF{^Q(wASM^iRZpMHg#yTTlW8kkD15zol33W-<0%*eb^Rjxw(Y(R9*P;`DaAX5F} z6+7_`&d>iW(QeM!gb0^aNr}H_-hL79f-8tT=ge~E6i$>&*XnwPJqKPf193of@k>A? z`VtTo%mzee95i$MWz*U|{S%b8+PTL<)_AQY@&!h2YDe5{J=QV;!kDvQY40?czG}Ea z&S0}&nf_O(P*w|ln;0r|iR60Q)*Xn&LJ`9kt{XjmG zb`?iY273GKHq4YF?}Asrme4wO>dSVj%Aaj%`AGUZ88irdUvrPe{WiNX!J{{(f1K;mc2 zbnaSR$iZ|9iC@vuslQW;?fn&68We~8{s=8ifT!LM|M;z1Y~#;p>5*R-hk(ZmtyWi5 z^Zo!)!eDAUaD9yFzjDh6!}Kn22X9CY>impe-93XLS3v5M2e(s@6sSLtu3mhL_yO97 zkNzYs4tbTQuj)zbHmo7m%~|IE&X~;R*JCoqAQ+Qv{MIbCF=dazFTEj~zv>M={%vo_ z{s5sSL}fWl7hDCu9g}Gw&nd!3J*EA2JDj3Hmn{?Rv_xefgK(#TjWAwPTjXA(( z)>pXi)5yWXZ^vX|nN(=^O@Z#iO#74SwpYS0tiJTyMVTif>kw*)QiKnHt_P`$s;$op zaBgJsE7N>~;eKWitBB~h6&1X9JHa=~E>tsOHXhpkH6HRLSn_90^Q}jw;j{M9+yNU; z{i|TY^$lS=8IdOc!b#y}Jm?Xs$YneyR-ULNU-A$)t*=v&?htk%1hKy0f>f ztN8pp?fg2*FzLjVAZAa#%2R8KQC9ibB+~|He*Cx+S%EI5nL%-xh$=~Ed z+cF)Rn>xXKY-Hrs6;65JhQCzJKT8p-=CNYc{2rj1ZwGf3V%2a}17mT8b*R4LT4J`%z#Zv~f0t1m%M8t=&=`9qtot3@c zH4^3$u0|}HmjQrjuZW<7V!-rAF<`pX4H+6L2288PgMcV!HXtg|EGUa^PLVS&m2Sw_ z&fnjktqcO97}(5fui8gWsSPKbZ73C4`s4Ybt^)Bt$5p3q9}c-PdrJb^h#6EMZ(2Rxkj}=0U3y?!FNx$R zm_{y4?9=R^OdUjj|D1Pmf4z0sE!sO%2;N*lg1~mXQJFE*w@Icts6wN??@R}{x9tVj zj#fc$wrexEnpwJm50^7y6eS1>61jQ{r=0wvy*i8e7m+H7%sXc+gvp{EVzzY8Z`jgu z;x(DAI3juh)?|Ty6%i?YU6WzNYcjx=o|yBBB?7kejybQ`*=?k@H6QS|&K^g{=OxhZ zZ0xi7?s@CytLJ45B~kb-C`?GITM_>qVl%!AB7s&GXGAek+3f%>?FlAitA3u4{hf>` zd|qyDO6h(R6h;u&rmPwaDsaE5YrnH+4~TEprcuoc;hr}Y(ALTzsOaT zK+9!$J)oUeRqFh@5WH#&}G@BT_OOoiR47(QOG-}!*)RKfq==vHTE0(zH z0rZU6P<1-*jS(#VBPd8q=uRr(ovRK)qf`x{7(Ms(S=R=kl2eDw)tm!6G&}Z%orbPb z^#n29OfT}`3mgwD`yl-Qh}v-iZc{p_KR$ric}DGU*b%&vOk3jU8xc%9QLE}n40mU? zY4?eq3+xA06&9aHcD6;2+&NR&i#oS%4lXSgi*5ZyEavtzTzW^=N(tRXKrGgG9q&={ zXJWA(GCxKND_<5s4#{MoFFI^Zyv@F2osew5@>{W(`d`AOtAB<|Gkzx)v-`DJ%xP9E zw%s{w6+TOZ^dE3v)`*&peMkVm(R%N4;{)?&)`OJAr@i5(3of}OakeQW{X3M9{HZL=UD?|rqmDVz2#F~1HXDc#-02eymNVoY~--e&+iPBs6OC-bRu zi)2@U{P~IC39(?lbE-_%{N);5*l=LPGZd+2PYeCo9gfi1w=Kt}xz(>|jwFQpmLwDh zNJ6A9Bq4b*NoX99gl>SyWL7O^C<=>Lgivud$Ypcc~wYO$9$ ziS0-V^VPMM$r8Wjab<01B0A4@h8@OQfC^`>w(-|Zp##5b3T1;HISsi08b;bw@~kX*75Ckyp9S-BKLe$; z{}3q6`>%k~8#>-@6c>foLw|gYYU`K$FN#8oEfM!y0&f1!EJlZdp3r?(>+TAlh@_gG zoa;v*`&UXb1EQ)3t_zHdD<>dN3Kendp=)KHMPMAzX^kriz-~jZR<2hh*M|-91d>Q2eQ;nA*0V6q z*sg-V-O*-I!u+!av57DH%WI5_zK<&2XhQT{f-oGjc)d%eGoog@CH$Fw&v}CDD=bYv z*Hzk}7yqC&`ZxhQ5A==5dzaB-6hQr}P)~WQ-RbEsGO_&1Rh}hR_go}HPJ*jx1iF!3 zch3;tFk$-FEukz{J#>yHy`Pxm-GO|4Z$g|-gs?Wimp8`| zireF1*5Q(=PY%NDf}jN#5a7^+qen13Lok|a2$>#h{<$G^siwPfvmKZ2~;uoN_O+mfx7ofCqL8RXM+nZ9xEk?@p3Y6;ua0nZN z5{n7%ERnOKXSoi`B@>Vy`MCMduIXl?&wCj-as;gnjxia>O)XJ76rPtY*o^f}mAeM1r=GJhcnHEbVB2@u3N z2x1@p6Z?qgV*fF*kM~EJ{;yd8x9-Gu3sChh|38U)32CV|Omv!QT+MYNV(PfG%Nnyg#FD#+bJ%d5Iv5*cC&*@^J{M&#J04%Koz|toD_WYyMW0A3p z{_9h2nf79q5L4z%sLtL3c!i=x8pGW8STE)Yds}#ued+MJ0pQ|tidde{M`{Z9m=38hTIHUJYs z#mK8lA*)L2FvjJdrJP}#=g87H={d6WNRDHReJ%RX^SUFUFTRn=GeQc+H%^JD5`OA) zPWj!RVre&1&i?F_FOBa~>A7H45Z`md{8td6o15!^QGPepR{iI_7_kn>dUFlUAay%_ zYn1Q)l~MjMXavWgumO5iV_u1sj+^F1s;Ip-$TlQ0v=(H>)5|skmi8IsC0P%=+XB?bt9tZ^Ww*SjRT;zRtUaTf-;C*_0G8KM{JeI@*G{;c z97)}F%J=k%eot-Q#$_stPsjJKhfXZxoQzelk}HuMJv3xKR}hBCCPAAEpbO`U~zR86P523E15SXzwHOLa@8DJj|&qk z(-Or(c?Trm{e+tQjky@@H*>L4@m%bc1T6&ye$#|YuKCH``FqtV%!@I-081qETGO@r zZJ2UqA8scYcPU!N36z5>miCk)b79u{1ksM_Y_VrxM1o3V&I|ZP)gY;dk37z~_B5y-aBp&#?68Rm^{66@(hcB5p3)#FVlRU)# zs1#-_mecFq3Cn?w-@;$+^i91YqY+9i9*3fDXc{hX=H3gxi4R7RY1yo2@nXm*`=pZd%@Y&Uc{%&7fy_>pOZr?Oz3+?~Gb zKSlxBUc2$brBdxWp^1$)yVpu^SVLRHQMh-;3?9V009Y!kIHHn zU#*JS zJD->v`0sh-fA11Y{X>uZjt#%^$p4{B?CfUMx{%Zcd&$Z%Icqt*F!%0Q-_6L&_U-EH zI(($nL!vtzNG(q~@Aw9RvkbSVL%2KAy$+fEVnatMAV<~MF&&04YIZE-nb;<0Rr&GG z_Y~?XL;GdN^d>d1EQ4$$q^|o%x(ET=Ek{7m2DI)XK>7~+Jo?9N%Ym^F%3m&WTU1xj{W94K?-J$JnX3=!aBOn#(FF2( z9B`bIk9ppfT!b%qhDwzJ9jZo!&nh?T-1l|O8pLeAb;(bjX}<9%%P{Q+;cM}#E=K@Y z6~rxLapyx1|JESZ2wd_zs%KsD^2mGaqBDEPt_JP#um!*bV~7QY`X0XZdK;$(>2TA@=LMz+fVVO-}d#yYo zd~ssgD`GF&ifg4fz-*DE-jvt=RcWHI5EB@xBSHq0y~qIBIg>Gq30r1aNri4Ip-3i0hieQKO{)U{JBdk zsNRV{2iR4`eg#*jTmDniTQ9miph~+Z^h$UpYSy4*x^--}2VLkiXwW~&JYp#Bm1rnD zI;L*FsM4?H<4{JNw-Z(>DCh1v-2>9R9|nA|&44_cz~~BJIsKrJ8MrYZyR8B1fsNB^ z`7nnHf++V~?)`!adbK#yBktU?*lZ8j7nRt}KLALd%E`NQfTTUR6kkQ<>x}_a&%R6r zcOCbH_>D9R{tBXAubir{m$adf>S|+)%H@ikadFX_HCCK1?vJQ?1V-^tkG|a-wwJ|q z7YaM8^0KmZntOub3!CcB^*NC1j!(z(9z9+|aJ)oVn)hpD67qJ?{e_AUH7eq~ zgVzq^en1Lp9J#ddcP25zul#6hKJv&z8@@5|cl_u^MN4d6^7C%JtR;@1p)4`mP`0qd z%5wM1Z4JNVg#+y9pneAg;RC2vz8sZ~owgi42?4yM$@`)ekKG?EyDYDvJ_`y;w9&KG z*TnO^b_Qo7ei4aP|D{OG&5r$;u(utzsz-=JW%h&X<Lwx(oZnU3PB3> zMxM+ZGp^Jy96T3=E`C~5x8%u4qcv%66qc_GMqvxTj>3RPtVV|R;YQ?9FbWgORQaW; zBrd#_d<#^7ymwF7Ur~j_Ln8MxQ36!;s|d#Kne3J}tMue;#LlM?v{{i@2`;i?RwVXy z6{d5V5biMg9f!bQSyp}}fnwRH>bJ}GDb;~gk~@;iKQZML(=BgU{t>Lg6vZO3U0+0E z(_chlAH*WD86Xl15O$niK8Ah5`Z3vF+bq^_IYT(5lqdTzFUugFV_ZJGw5dzCZd(H$ zi-CcJw%@2-!BU^qTKgRdOYiqyOPVJtd&$tN&l1nV%*rNqzE)~J8u_YskJUuquB(9z z+k&Eo;P1L319F)up{(+VB$9OWxcpH&nD0qU+t1+W$kv}FVtTl>(X}Zn19aj0onGt$ zi0K;q+Gx&O-wZ?yvg7TU3}iPAD+7%^QEUfiEE}KByvOx=56ID1^$6CdqFvgUmX@45 zs3awsYGC1zRtE(M z#WOkAOrgSN8W!N(XKZ3WANr}!KJI5oP|1PcY2-J43kf>#8Su9JBV%V zUe)6o^? z(`ue~FF3zMdU~UBlv`3Lmod`WJ@okhhrM@?XZrvD|6k=5719|IuTtqCr#ai9UWyKC zl}aLuIV2&3&1O?MRA`l)HLp^HvQP=Lg_y%wrAQ8Qn&r4Lv&~Mwr+U5L@7MeNd4Ip3 z&*k^|9zLJ<_jS4SXQ6p+&&TtAzum6a%VUO5jOg=TFG%*8>YbN3j8ghU`!~vWaCBBP zlSWG>x3E%rn+&!Ex8PT>ZO?Ub!Z2;jx^9vw`B_pk`+Ey4)BRI4yF2pDm|7~(0+Zd* z|2U)mrZRxs)(xMkcC0v(>?f2#Q}>@nTgxJpg9E>dt^3>y!ldc-JsL7gEF|ndN#Y^kL2j;e~%nJ_njQQ1|Ua21IW=#fE-N( z$k9%L?Ou@q6p|?D+02aa3?;){9c4YL3%tgEtbtYiT@5URJVDTGozqg+MPqi;MUml< zG{gw{be{Yv$*8Ii?=8ZPeH%M6EeJMl7d~qjPF)2oV$XtBELg-`7c62S&IX*R1&dhF zV-s|5(<}N+XP29$cWUSR`H(^1&Kj50{o#I)lp*Ig{1@yW9{Khk9(l6{_c=p@?;}`4 z3!?)AMam(4u$BPW5uPBpK%3#uw~%&~bwkS=)B_XU`TiROW!abe>wOuwn6fg=q)}l5 zl(FJ}Z`4QBGR>9LEER&wZ>`ml{?Q_zKYEb)AGXMAeJ!6TFM%upqK#`6+K~dxq$)&v zp=6eR4C1VVImD>FTz=$Te6sC`8-_@2ysvr92=x(i5MBuzYvy0`l}392?~~tVUhREr zxnCcbZM;;7`$Vi)SIGge^y$N>)35!i8DQ?GOSz)S*Nt&@5yp9t^sTy>s(e z*a0&bpj2)EQpd=rL<6;_Ojq=uRj>a>RWIbRw@#dbnS9x!v5K1JfTQE}ej9{pO=bXR zKK#>?mX~B=4>YA!d<9_WQ{KhA(ZL;#FQS@e)-h;8j;jL&g5p7$i(o8X z@tZyvIOL4GmVu95iy-BqC@Z9QO4iV|%4lsux#QtO9d3quPYAC9vB{`S%>jkeyWTOh zbZrUy*_MXAl7ZV%{VNdGD|4!UdY4~kR8$_Zg3V46{xFA)=d#4+hLyxT)hMPsWIQ~q zv=3Le@$Ro~903DtO@X!$J8zu@T=Kr;#W=BdmwqbCUqt@xqmuBYC9(5%5A}<4#ssD( zYqVTUVJf%a9qiX@v-bZNI~!yQ%?L z^eRe_TIwvn%~ePLG`XWQs_ZrUyl4hcpv}WNcj@<6iFJa!$t2II5~Jaq861m8@dk>j~m9AzZkH8wFr*Y~v*kdNAu42Dzk4R<5-SH!V4C2~GQ zX5H1S&7I!UElB6ncBq=zCU$3#Oz!r<9s-oc^~7EHHG2JPa(&(3-T?4Sh&q;6zt#J{ zQGxcQAHMh99>4!rNa0^*0Zy=(znJ9hw2;4V0C^imeo3CXSsC!p2tlS#MvT&lu~dTk zmLG(mEvN~g%f|NZ%Ih26 z`)}Al*A%nAAKU;oP##+#FuqLA@euK~>9d)fVY8>UhZfjCyZ_1tLg)XD4RqTDrg5qD z-eK`3w0pYC?U6T*V13QrO_G=GGLlMJUuwwr)0vpQ=xn`uJ8Tb#{M;qs%+wa|HDN&#+!ZtEdN9RoavRJ%%-WOwvu;>vT7h=U$HJrPL$Ec{Fo-P67X0HDfKyFbo(m zHpXizf!y#G02^rYcYj#2&5-!{ujeDTcYpVX>HG)$VNQSZhrMb|)E{W#Zvk5q6^JyQ zS^@azfnn_LmjV!bD9v%@p=k9k9{m*Lj11awaj5Fd?KG)LZWnH7 zP%nrSYmHzOvu9esjOJNgKHs}jOftxUZ#-AMLk0!9?m1x_n2^isTeA7BdlyJR{tG0a zDd6k&E|7qd%(jtiD^gu#Hd*6&^qCE35l1BxHdZaAjfT(jLnO<~b><{LMDjL2MDh(^ zTKZyH3no8i{m7CX*s#5AV&96%d_Nh~Fl7k+ye|)i3GZfi2y2r*6yc5x;ZoPEAPXm4 zrn~WqQ0e|tUnx($D*Iyga+V-7{W{8qcoWf*Amx+)0Ecd(ILJEn?MNU)VF(LwghJ`S zx>*+pw^bLvh?oN7KWXiYx(IE=(B4n)NM{2lHL}TWTAO>b+(rw?v%}{tQmDlC}&91ZSH+dA615ltYw2w)w z25}dmp=|I&-sq}nv)LY0F6X#tC?k0Ix?@bC-6N5SUcY&s#*nrh-wVA*+SjZ%(!N6g z2?$J+ww}{c7vT@3*-u3t>tm^Wgzf*tZ;=W72R(= zwu-y59DJ<&A$EIrfDK~f(oVSX5!4j*R!7m{`E~B-tmtTxb@~@gU_R$w9v5HPTCneJ zLQSP_oXun3jAAyR;Ftiy2U>6du%rxh>ga5+3vmUo@W^CRE_0tbe5(7Fb3V1@@d$c* zaxN?7-4evDo3ZLqDgzIN2?w_&k6QN&D!*bj=;e$D2%cenhAhD@s11HuXxXn+e>@s0 zb;L{oJv5+U_lr}z!UsuI_INYD`+k{VyCYt=4tWBcrBg*x*J0Z6|LP3W7HeEzOpF9r zNV0#M0rJs?ubL$MIR*L`p8|;)_axSb_Sf zik>r3Hlb0NH|#_Q%FIx9aVkcHx-~TOlKBrh`J&lC!?ececFPISfdTS|7$$DzBnX+v zdr-q8|I%*74jP!WtZw+e`&&n?!5cl&E@upsYGef)&L20ObKDS?u#i5Qg`VT;;33>buq7k%;&lc(u7 z!S(FUn$m{W8Qby_|FI)F?@q~>?2k^k>;=X6;9Tu4qYH2SjH2Y$01CyzI;6MTi1kL-vi zTa?|aplu<>Qhwk%`7PnqnsPXMrt3BT>!m#5>_&g6(OOOzxC!md2(fv@e47^O?a^`Z z;K1z0py^3xcTB+Znf#FAU}|EEFI}bY_1f$hwj9_iFiV1=^#WLFVZnSy=ipw@E4xJLWY3n4BG&v?fEWu~_yyVi- z)t5w)lW*=^zZpsoZs;hm0`F6M{DQU4K0Q>GT%+yNmr-o8hX7KwCYi!Ri(mdyhm6rw zGajdJ3)%tr;ncmYq_w@i)#pdf9ZWqS0>DDS)zUkjh2rX+Vqp@c)9M|Eh_hJ0yB|9FkIP1OY^&$VRBjlqQyU%0oFE|bNlWVcCWX31sI0}&9XDj{{1C%}GBnk~r z6Xa9ow>tM(-Svla%Yn>|{7PPtO|7^ZNEVttr>%l!_>lmce60ED(-%_GeCD4Y&oQiB znil0k!y8=~j%tgj-kVy{91p^w+HTJlZI*cU;WcnW6AL!^$AC@VQSZA=e!7I`x`Exo z-nDH?yloy{Jp~GitfS`4H9yxB^ z>Ta$+Cg+glN!?1${!eL_b~}`jJ-b}8{e*pN=8dFdNstsjENwIi@pL`@cwX?_JM0AT zc6FsrHyGdA!91!ctj~6bw+q*OW2?&I{GdtZtToJmdZl0cUKG#h9W}D4byoY`C!eSA z!zWMP#hEO+&&XebV#rTe{>(}q6?s~x+by`{|EG~4inmZ_(&AP`x{^+-MW%x+QS`R# zO^Pjx*Lt24bZ9v~?ty`O+EQNAJClUTXPBPGZ;<<>5P+>YPQM*rdgLF(VHOpCCl31r zQD$t?_0gtZmUcZhcD@;npe-$R{0k`hQfP-B@O<=^PcEB8H#-9lEW3;wMT>8lR?{kq z7po+!@}!#r;_{!tbMUY?IG_-Q*^SouYykrDK%Ib49<>6cgIUVtSv7eSOYVyHN0c8; z0Gb6aVG7ID20*TT=l5mg1K5u6&Gaj}3M@??_kx7!XRT4IHwZkFd^gDlT%-3l6^CfyVv4f);V05V?=dvQJ9hzsuX#f@(D<&;orWT>0THNT z&O>y##C&8;Vu^md(}T6}LPYZoW45)2;0C7QgTqGABBz*#^HJql^Q2^}eo-kqn!yh> zcI>$4w!X;=?Z!0*$R*>8thXkD&l2iRLe@N`FM`$GFv&r#K-Fk-b&}iGj+8c3zg-Gi ztw(>Vv508`M`qc(Jhnaz^l*>%M!P{zZ)P>f?U0zGvwG3e}Jlg*Co^l$)k1WOa) z0Mpo6!24bEgu3YqHw=&LfP=!5-^>B5H71b3vFpv76PTQ2_8JFsD){3Wro21wt+8kZ z5cdG`Kz?zvY3aOx&ecXoUyfE_%Q)@Zp#pC=h81z;MSKz=-@NV(?kJS2wX)kcrC(_MrnKYvdIEtDj?|A*tCjoaV7`^zlgM?eU3e^>ML zKe)rDAmbfu=uk=P4|mvkc*&7Q8gN#l82P`>^5bARWsWWKnSIsE7@vC;wGpRAY;p{V zwLf>K86c*yiE>KVaQAgf4sRpZ3Cg)OF0IpxXT7TNw0Ma{6r@sjbWTnIiSFrNOHeH@ zAA14*pDnSvjb>P;`lFt_4b)#HWZ*1!<_d1;W2^4e7o{m~io$f4@*b>>q%;!4zKrX; zk#jyFjfkp%o~0m$9*z5beJ_w2l?OWOk55|mtlII8kCW4rhsMh$(9fSfQ77XYcJ-Gd zQlmUwD5(tPol((n%n*9A5eU|#G*M{P8MrErxcY@8!prMw36^^PjEr6zdYv(kBHf70 z5$v65o~FYQ&^| z$(M&#hb*R4ai&iErT4OfHid*j5qGC*$D8dwb67S?9!*#0OpFm-swyqaY0cSWn87}vFwtdWCQr5#V4`sVh+D# z-&?(VKxMQ9^s}qXVArx((J7yJg@d=*w_2nz>`@)SNj!$nx(A$MOt{N)0dW;JKC(tx zZ-E!^!ytATpa<{X(O+CSraVN@_n=e3UuGKDBytTT<_!wjMUixHJy1z=Vz~%4TK*(L z|KA}(|8*j?TnH(rK5b@gQx<~1+ru;oSQgFt+-||l^jaFrkIDnW;fNu);cd>)0utJJ zsMpQ#?xOslFTQvFBtrjhBSPae(-`TRjZ(*~Qk`cI`q)U^sElmpZ72!VspNUuyCYsdGyh9wV6aNMJX%1>jkyn$Ya;u^(cVBGPAXs+EJ{ zGonU}^Ytmt!Ua#9ecjrj+=yV58O4W81E{p=JHGMCHXV4u;yDfcx?_PqXe4uzP2K`cb5*$Nq2267RDum~`r&Gf>y$)!?&g(R) zX73DdybPENeSqvma>0yuNkM1_d<(~MIZx^cb*f9}HOl0nz*uOyX3&DI4NO8FPKW=z zgi5U9}%w9cCC}mu=lzs}DJzWjl_(Vm6;;g9no);f= zT^W9Jg%!u-c(ydC2m0o$9mL1qI+L}orEL%hKttvBmtrnX6gUpq9u1QG`bwB!npCDg zf>f(}1sEbM~L$ z4+Cxd-5+)i9fWv-h3Mu9ya(g#5ebE2&GJ(9jw1;0Z9v*i`r1nrX-GQ($@S6;FYIe`d}vD=?ZvV z(#{*Y@>QS@Z%O^&GBc?2?eP}Y$JSM^;Fh)bi5BI5HpKqr8e$->tI>YJD7z!a&Tc-T z@P4t~Zyt`I*2r)yapN6%z|}Fi;pe(C)^YT5l&RGGD6C7MrPm+Uumn+z1(rVX3(p$= z6Cm^sgt%9~%irkDC;DTD463#oLpL#+5n6O$-~*n2FMiOve@#%B1ve~{I2*7NpVBq^ z$#@*#TFj_he~#nSB}T&&qn*ONc6uAc+hbx338!}U zy|0^A((AvzY{40pKWm^8(G57mDv)ij*rEi-j7`F8`T(o=u{gKb%?Q<@rjZ(7srnaZ z7;V8B<}m4kt>I=^_g_DF+ZTugiRlV(V5ZLuOt=IG_|VjbGqllTtHbo8zXr_idm9hb z$r$S>4pm1?dN2Sk86HfChOPK4^HXFb*wvm)$3|fOG7AX0?rl&8D8!ckMIm;iU2o9u zTg9|JGj|5a#5XEsEIk#!kB78>>kpLXt>ea;W}@e-Qyl2|PE(lSK@H3qom4e|^p>&9 z!lx!xP;o^ApdK~xwt)G77p|x2z$^CrBHe1`?#{$$>dki0S)Ug6s|hZc^&xUKKv*1(RbP-^4BZMUaD~8>= z`Mq-*m~ikfuUGAW>|`Xx1EH*MGM&_eDFYpLsNYU*oY~EL8~RDFe^Vg(w?I45vDe*K zC^jpLa{v--4}RTq=d{^fmOTim)SxRQqsDXYL!qfN?=;8VMMn0eJe}h2z&Rh6mc&^BHqJLG7Y<+T6W)c}kB& zVyn)S@$wzMoa5<0{g(C^WdR9C7=bDAW1>tW$Z|%z3~V)LqPPUi2L_;*2onW!z>J8m zw5#0uxq7}|KWs}oH>$OJ)mj5U6%`^rX~7A0dy>b2r?V9FQ5_`K0gtGJpiquWIaHuY z2$;j9)pd6A`VMAuOB}~bI4zlzK3{E_V&ETB!N-GYL&M4!(VSB%+VT_fjcew%wm5@z zhp0gtMRWbX`{b(zBjwyi4|Kqbbk*HV=R#Icb6AyF%h!Q?%%IP7_YRlPik}Y-C;=f% zLG1SOf(AhJ5rmxpuYbUNbA=agJ9pI<%i4pTTf8!71@&29pLKSQ<)HqT!6*9e#e`H& z=bLYlnHIBA@|Ne_pPM4ZsuBB^2Ujy;ykX(I0mgmT#nC04oayDl$u#erGpQsN@7f{V z{`NkUyKRWv6X9LT2@c9*PKj|w2J(%XF6RxHMjC*fk=xT>2JPGRsE-}BGRpWX)9<$E zmiKEY@FO~vu*NyKk8*ox1cfxVch1g+<5;=HXP%$M^5Q+E;VEtr}e-7lm-&V1~&4MJz1nLdjUw0=7W8WA6)C$#EMCc2;X}FsN zc(1~iEe(a`B7c_D48;6ZE8p@@wepgGPbrx;`M7IV|DiBj7X7w~= z1QJ6-BQ%hGJH6-U|p&K;Vrh$-qA1KV5qM^yK0e9-_*}{M{2umt#!MnjQ}kn zXUuOJ{wi_z=f20HUO4E3?^*3-+1;-=%B~b6fd&Om|Iwt-zAyPXtT`K*owO^Q-0+p%9?LnwTM2EL z{Rt@+n0$e4e1?9E?<~z+H8OemJFBraaSffFA&6{GR|nwZ-unWEd%sKNoBk@55AA?G7|l%N;y52? zD*x|0!^98&`{1H~6vx*0w~G*C#NV*@AfSyZ8^i&Y{_t8RL!0YU>vd6M8{*KrYM}wT zOYuQGS3{h-K$O_t=b?i#>%O2P0*xpz22W4jXINgZrta7w(F`v|o!d;;Uqdr^T{ac0 zmn%5-e;OE#KB^)5U&D)LonK10vEZr!p5+$&RB=d{&jwS=SI@&hsp!>lw|{=sz+b6@ zjT02_Pt0A`t1xeYit#W3aDpf4>R6gKcd){A%ufK^_bcCyoBNN8 zH1ytGKC{KhE4^IXaN^^PXQ{he3a;)*gLHCOC18pJe|&7+X8-njB_)2OYq~QXZrniBJ{oocT!7o5SDVd_>D8OkbkGeOR&rbwHzw!} z9HSl`jApkG6`-Ar8e^BkAud~zS-~}RfF7|}Y52Y|(BN3%#CQA+Ks&1d`!;}#y(IK4 z#?i(py=8*{&;lMvG|mP1+cfY%F!uAT-=)qE?|G}$ytP&ci#t8U-(3;tiB%)P_h>ha zA0WSKE+R*=%?#f?J-9E6*kUP$CJlxn8u*Dr%O1`F>W8yskU4$& zRVu+3E+K3@>U^K$e3|I7A!iqj&k7kGx%M?*%i|C{t6SYC%Jhq~UTcE?Yk{we&z#>C zgcL_TPCdfn{J;q|PkF6Re#3&r^BxqB3o0RO&cLLzrhA7yi}!7eHoN(V(Z#pC0Eio3 zsl`Kt$NxbduP<=V>&XMy8$aan+6(e{%Rs~KMJ+G?Adi1hcV!T0n1>`vIy<||;wM8L zhWDM7?M?O1V9~N;IOc(Yhj$-EW_q97=sst*(+Hj@?AxV3vs+%_7THRqzAMfDAUZMf zD1O^_;nIHm$61A=m{BpqT6@2^J0LU`R7IAGet=&RcLqqG7I2%S_3Be#P23~a`o>fc_Y9i z-~Km~eApF!o=|L+?uYI0!wTNI026XcB^Ghbi|0oabiFHfrA9;uvc@JYKcT zK=iX$_UPh`uPQmQF`xKI>I~L>dr8#_)QNSMVy*msq;uyzN2DhrH%s0I5IDq z5%E-=Y`hsD4e+c9(GHyQeQBwk_ZAZ?e~zih0n(ka{>#65yEk424ndOyZ|>2NxE=jb zKsRKdKyYmo*Tx^3kHTG$x+85}`+Vr8r%gTS`I>9!z}zG6R?ARZV|$E|_JNbI5c$+v`d^xBaM?YD$lEZLV<~Dm%&nDP35HaFqYl%6;v#+p{7e6&3~< zss}Y?N#E}1f1bJ4SxhL?cEne^)>Aj*&T}W*E3mHvsx7j1K%;1x4CQ*vMtDfy=d$eE z-z>RL++EUNojqX{MRUc9Q###UizEfv{yj!RGn%05<-3>YubLb6-57CbA0>8k09L}A7dWrr+cbQH(jX#K=yya zrT^c6OUIe8??UP|t^tw2OvMCOqScS+(3PM679H|@5loGodW_Qp;1zJ+iWM|6v+5<; zusu?HAUR{srk3h<2I(Dp8ts?I+`u2*oOrn_EleV~W)I{`JGHzrim+Bg@$88M)Sb0P zBhvT*%eLE1iw_+>1Td$~HcNKBQ`6P8r9KI!U@4x1l%PlQPvcX$M-OjcUj9Py#eNAZ z_vv+n^)ClHLhbPe?@NprS(EEuF{%wBqXjxo|NB+SyaQ8sh_S-^?v6gI6EiEO7o1{p zS|63_8sWyT?vEfxhNXF*+udEd+qD#1UK6b_dMA3*rY%?3{IcvIapX?&RC0E^RF~fl zyCSeYNYvkCy=i#(*VVuDs0eS>C~g_|)N;KS&{XPuFxBf|u7G&Toc*-r=>~J()>m`5 z>T#iH=7aC&ub5VAhf}RCmcNZx zalx;@MXsHH#y1xF={$`jx(Iq$dOp_$>n?b~qMtd^kO*hRxCUdBNKM5Y6O}&3vfWIY zv9KcbqR#Og9eAzN=Vb25=}X+6xs_0M_=#BSnZxsH4|;7>=ZsPBB@03`!83HMhxe4H z2HAEgs2!&g<4dpCo6b-3_E@TxK+sgArnvC8&)t;91TcLrn(Dtg_qA1Htcn!3ft=cmg@;OO#8TB=NUc!*`Oklu1t2YCiU+2DLxL z{u#%YzSlOF)d-9)0l`F7cVjJVQUTp-J@wSnWa?OTe`YsK$yF#8X_mX6t&qf*p1M$ho6gFZSLP7fRb;YGaG_FsJF%Fo%6 z-@Gqmb4M!GidIRIRGnHtsroTrf`(XrM+E6P##%U7haqAWRw4EM7*W9u{}q!6l- zhNV07^)5}ue9dnneTJ85)+|48v7^m+VqoJW@#o@I&NWKO-B+ubk;mJau{ z+>g3<<@uBV>Ed-aZL+F-rTA-`clY^>Ot>Lttc74(!fbG`I)65J^KDw`D@g^ZypH&~ ztlL2S1W(DUBGr%5dh}D&&E)PAN$19WT$~fqFdOcssoRqyT4KSeK`-QWpG}qnDg}?72Z_L>Ui0;i0=k5|QQ=%Ze zxZ9G6<(YT7y`H6=P{_|a2~w30DjPkJG`I$$cP~wmnR@4J>GdrVr^CCq8!-qY$u6PM zY00vW`g4FCo^orXNW62+RNDZl(VU_E`TB@p=tMxaQR-wPF5|-$STHvgM#|_Suz_Ds z%SEDcJM}ZI&QQQE#kO5+8GGI@Kq4!{UmFeu!?PPqF;O8W<|=+_|N4o0IyL^0Xl#I( zA6a#wIP5lnNAknj76Eu9uI33{LoCPU3xG$mc%EN+Zf#)CtjGa+IFSEj6wDteH6!~6 z7zqr`ayUURCGO8w92m%5)WuP28O5D#;?N$3T%?=~%A&+u%wqh>0}bDv;^+-gMz)tw z)4gT=`SNydyZfQ8svIr6+U{<_Qf3HIU}=i4cqu7{Pgk7E!TX-(sb{!756t0IUhK;b zymBzL0PVlN;f3kk$LZYpgh*TU(c*Kx?9kgIN{_LLcg)*o=ufEl_Z`9IL6smEf#~xn zU!DKj1M-}glH+ieW54y?{B~NJYv;!>r+KnPDZhBY@>3T5!FVfk)cpg_pv5ujO!!60 z73Gl}o0UOV&9Hr*M#P5UtljW1*Qss%E55l?;|5MV=8+vi2{XyXq6a6A#>dfa#2G!& z>cvEsTb>lO)I8@8x%iCqPIpxMRzQ~ywDp@67k|5^}=XWq9 zBuNf+{)rJ}Zp5-z+79Ed5f$agav8EI2WaF>yG&Q!BEJ&(xC<^6>dUxl(D|n1w4*kk zNHZ-)REc~ZFAuu#N=^O^5h05zNL3pR{ynxV$G=Jjsb-Rx#1?CL)JWi60y3B-u}_dB#9y8f`rm`P2AJd;STs zD}DLUQQ-y03f*KvRiV+dLmvs=86^mv{41~rMHACS!`9lI+t4FuTapM8BrkWw+$~R) zr)0Xuh2bumQ>~?D$M}ybIzb#GY{z2)ZtrLHv5RMQmCaM|==ha%qHIW}dC*V}a{ zs;8pf&m*IfIT|-wRnqsG<&8%Sa&~(9Tqh)}5KBK{9cufLBQf3=DcR)S+(GH~kf?oQ z?l0(t4!uT+i5}eMa}gs={eC81+$}1*qm~mpgk~5Gx)iMQfw^uN>TjfLcT;ydMA0!KyIF9-SA zChCy=!~|SuZU5aZMSabexGtN4JHPn{_A(dU$HY6^&S!5M$k~bkYmv`LnmV%vt6f$^ zJ_k-RYV!N}=$&)Z2NmIW9R>^f@8*q}G~`!IAiv?d(%ysB=bs(5K((FV`2k;e>pB7C zw~6@Q$kdY1%ERu0J(-#DBc1Gz?l@LT5R^x6lIujxDwFWiaoh|^`X$M-ccs0^OuhBs zD26vu6gbKut_k3rorA3B^|N)tquhma$_NP$h98Fnc`!kfjA{L~Q7@g*=oE$c6$R?j zl8N${-7kGw#p~`>Ovxv%#^ZS9(3$34q-@EZqTG-!udG+(h)tTjz(?xf6r!plA*Fmn}bxANp<`AiE5Je@)!N;v)q z@mIur0<7`mSJs#8_uwZ{=eetrYXn^p(mjt*EPM2DosVWSTuUm&%$l?c0Q!3 zD>RLuu}cI_L(X>t%q_uGE+o4W^OFv0QVrmlXz2PyQ$waTykSBnB zvQU4ZVBy+lWY13TfP~&FWY9H$(xJ*R-esK%=Wx)|lFm(Q6m#JCOisogRp{C^%XBA$ zyrNd5x_RwHt;czM?Jolkz=vDYl2xIF?uL;|2|c{QP2jm{oNn%zv=7%+hW}hL;xw|3 z7^}{RR%KMg*RU}gN@%s20+s8!cOFM>F>n%m&U(xTuHu8GW6$a447aH!&9WNTHK(bP zgu;Cv+6uO^8I`*b8Kd?S86K9~POU&vYItW(fL|n*FAvo?ES`xtRsEoZ&d!Fsxx@Ra z_a!M7860pa&@sZIZ9|T{atv@?J$Jrvsd!Gh(x+|5NO3DJ8(mLK>%PC%5+urXE zmewlwrPY1(@S$TaD_A|tQYAKg*g2=y@@}xp>V>Vdp0#7Q9>gXs0qHXuUQjFhr5wfb zdZOL&sxH_{-y*Ji(X;uox_o_{LKRZGraki&C}&`UDo6j6;-)@jJ_sk0OO#-8P^VjH66whm=FrP? zmHVhdWtgtmi84P{l)&)kRmo`bamHbe@GG}!MgWy21>yKba3Wbi5%vHhins^Sn zC2PEM=|giw^}bmA@vy1A7fuSF98QzvBP2>?Xx3+ESr<&+nJ&BfC4xG>v5Y!b>Hh)Y z$Hd8E5%MG^ROArgN~OX?^Hi3A`6Iq{=~e z+TMF2?Qlh4*bgEW?&Y|thYl3Zb=^He$<*gHxNi>~;JA?{43pc?X@@#n*ojDzRNtmf z)5~Rbc**B91dcVsD(VvxBdDU*Ao6$^2{`1kkM103$Io`Li5MA7LX*#g!o*I%Yxzn$ zYw+OMOX)CNCOk)~0%=m6Kb-nn){PhQnONYReiS-KkTt3S^T&vDVWWlmL}9Zpl$Wmt zn-Rh0b72+YDNFJs5%ZC4B??U}_#|0{F4T=J%hYUZFz9HyOlicrsjzGOS*ByB?8*5L zOGxnwGsoww329Sa1b%=$heF%A0(9znukSA29OTY=IQ8O6=eZMez0O_9n6WYP=dA28 zdy!%e!64_?ip~$?5grk~wo-cqal&yvWI`t=la5Oo_d6niyOPfxNwrov zDloHL=lP+^aezM}#c9PR4pc}JI6P@i3jF-LVk zVmKbJO&Uz+-(5@k|_uLL>=teB<2kwVkpT{F%>!nziLe$&&vu_VcaZ^xZ2yEF~oq(HXfu* zg+)+!GO-R$$OG1&_79|=>P7a64J;tt6~;9FCXq@G@dVHHf+i#kQRi1Gir+@Q$a-W-SA&_@`?_a=C*EMp9841^baN zD`!UBG;Fo}nZh^$I#As&muXRXGcEb@ya|M~M7KiFhjDv=z)U`e&0dFb=R28vU3oh` zYJN0GGMWPsR_mg2NS0I|lh$1-m+SbQOjP8tmBe>Edqe%WyH$(;vv zZovmewlOdpT{U_WbsEmtXKlJzRcjXgfpt)L<8adk-T~k`Rjqos4Y=}SShaMkpTvkR zpF-ns-!YG3&?QGzAFUx{M{oPP6?Chmbqy`Mv1d-|PYG7`(NB8nG#U%jm2WQA`#S!O z@2|0Y&Q8-}+jWk|7hvMSH!dO`q632MZj~gHdmrk~)O_Cyq~lLHU}ooofLfxsZvt$w#1{2($8qz-KsVa;HcE^opv>SiJrHLZ#vqh zx6I)~mZnd`@)15gv^phS$uy-p>T!U_P$Oex6(Xm%&os?DG5AtWuF}?>#QL-Kp3j>r zUgtd`jQ&L5nVjU@hg9{TZZ7scsX3nhx}-=G#Iwps+}Ei@_qb-`(CmzOZe#UTeuIxr`YYSx79h(n z>1S%p5>0MDGB^(s3x($>nuzxk&S^9)9 zM1o0Ykpx)q#{oOt`Tp*yYNeJnOurn=6uKSK?u!BLg!csVzIN2}$l`&n{KVMa449u~ zFE)3!(>=76A*D0tt6+k5rns7u4E05NZY+CXGI`QK$5U;~ixFiNka&ZYVp#^-=WByU zvDFr*(mMK6ZsV0F z!x1h^9B>EAZ#g}!ETzp9E?lGgNA4d-t_3SI)&&iQeB2P1VUl{d$tQfBRg6R5;)m);J{q4M= z>2k2K-;z*ury8C_<%WT>PHm94*qx>rmm&4s(+#{MTIoaSGmtwQznr?1eB5KA?VI;$ z$jQ9M`1);a?##Pj(7JSiZy{)FB2y|{eo3IJ_zd_ENcR}A0;vt$#VCv?(Xqc>A#7U@MLlYs^a7C%rK7zb5q1nA^D!N~ zxF_-4bi|Vt_Lg;Yjh6eMl&Av+uO`p%l@1gdJ2>$tAt_xq!NI@I2HzF)8B^Kti7 zc`8Ej73&^_1Ec}}v;=gB6G+*KEo8pvDNj3aOdIEv!7)3;8=)+=IMKv(BhBUS6}4i1 zcM9vSNDZ}EClA}iz;9;6eq)frotT=0ck_XN$#WYBS`X=^kh~z_W_$rXmNuT8jv{oF zGZ3OaB!1UqIKYSou@gH>ux)<3nD2PY;wbmz%kdzw1%GYDS4)QpUX|I)%rMgd8eWaI z^wp9`UcBsIGyb^WKQQ`J;o*|?#R2t&hA?m`7B^Hg=Y&@&knlx4nUp3fM+&o$E-UN# z6OU@PwmZ-G4)A}Z4^|`Q=8&P{q?B>DrZ(`YnI-0CY5lz)Ov`qIvm?&UEnQ#GGS)T| zeEg>R7E&p0Ey}a$i;I`~J^LYX-|YfQ)MaSB#+-qZ5*l&*94WtLulQ^;TG*WKj7r7c z1|Wk~{aNwZ$y3eT#~U6mKfSeW;%tyNalHFax+6Q@)^*1JRi?1Id7)vE{#T{{PXrIKT@@s#(e)gsXxp0;fuwbIeS5G!(0z|KTa z;AKR#eWt49o<_-fGmtiS*!C)_p3AtwyZ)E=DU}2Mr+RDD`v3kJNw>tj#kah|W#c#0 z)(`MbEVZQ%f zaPV-T_)vsKZbIB4h?dBa#KItB1{|gmBu5jI;zcbw@N_CE$tUujd%94Q^1n8>6WAA% zymZ+g|N8Pf%1WcrH=MH&{@JH?;WhX(V@e?z-u`J>7QSe9lF&{+ETUM=&!A)pc0 zB{V_1x!n?V_NKp?m;pwk#XwdlfulaDI(~3r`-(5?Ttx1ihF=? zbnB3gh^P~p0BBv3U6T5*u&q~SX%ZquOs60OGvzNK`Ed8=J`@~#Y|j~N3+w3k*BAwy zw&0GS>PoTr<1vC$-JF#Bft%gX>@RL{qGU)b+%a>f-3f|$vWzLb zjV$U<{<9qXG1em66y;Ve{NZOuOFFnr&AYSOYz0enD+USa?|X&`OM#j(vY9}KBr>~V zKS4b1G*RQw!FGu$*Z-nwze@R> z=`lb&>0>_N6-#@!;^TeSd7@1)kEs#E>PZ|7WP|tkpMk4s(Y8gyHeJS@!^o`+95&O8) z+2iv1Nf!1I4M+0Df6z|=F0b9kmu~HL`&Esdp3kv14b08`pEn$$x1UAd)+${0(ou8o zKIl4Bx`ks{)g{ZKxv$g@n)-{-)j2J(jzQ0~NP4XJs^hyBp{ z1xlFF$zSF9+-WLu#NB}U)yGiA8gbvUzWTh5sjHs5EI3@w@d2nUNs)ktwz>%E;|TR~ zl|2P4;tTB7rDGVSh9RTqI!Wcrafyl?Y%2K_V!(LMloF2F7WmC!tl?7hjANqlNu=IrYheKaXm7R3FHO0SrAvv#hWgZL}u$qvo8@PA?Lb7Cidb|B( zW3m;6e}I|7uas+qo z6(aeW+^`AIsE!r)3{ECbSwqEC^W9vG1b?CV zg+8xL*-@5~ZrPHWIDfI3vOI@lg`&EU%Ndl#LfFbIOI#xl4f~nSfD676@%*uH&55z> zWdyHQG!WXa`64vf_Bt~J;D)95Pcxh9?Qf!K`jp+PbKfon|h;LDKPN_S{H{(iey&;j5 zKKJPYSe;hrHQ+*U=&rf4-QgK0A=D7F0g&;r6@~$*d~4ptxG!b$V`RDCi1V*7q}t!n zO0%TrU%Yr0VER0|KaxU{>J?$@ZUD7}F~c6VwWgY5BnkyRv5(c~tgrHc3@R!~?5+84 zEa00b)^VZu%;?)m-v`z&AgasMp1S(mW0l|)^NAEKT$mHM9sjH>I{GiJ6SRgd!l4h4 z4NP}dGK-i$MoO{R&}SXG`l6x1x9`-DqN*15>hkZzpS4%-!?e{cG0D_~@oV3ff9I&xbfCtc zv~Q|Zj=M%S#AOGnKdU?^n8lh<9(iwYzhv|tobYO4wYAp~cHIt@sIdyeLh=@N8IhBC zn3f>j;Ix2_t}~CWQ%+SR6q|xkIRjS*f1D3Q28kB4sc=5C|W<4l^UeK=Pwd9B)hBjfu=F)11toNvSFbt*fc6`wD-E-z@I^IF$HO z32CRI0*F?|$hyxsbR@u*0c(<7+dja1Hm@z7e1B4O{%7LS&A2-=cKhsuf6xhRPA&>HM zCq5mNKoi`_s+XBxjz0)Kd8)Qee{oAlE4V{i6`P;Gwmd9__`h-_1eKf!lp?Aky0aB z1FBZy%KhN6)Z+*mAycF<7A1WYK6jc3=db%D*?aMN2_a&B9pO4nI89q%$Uf7+K{LWy zE_7cCk|NZs-M$YaiWPulrh-d^};q^u+7v^f96@f7|FN1Hq4cSyEKlqQ8Q zio%7GTG84HW@u}yOjzN*n25vyzbMrDjxFtps3MjPd+1;ANeH$zgmKx>Y&=gT3Wq(EPjv=LO0`&pCWz<9I+SfwP+#0l5G-( zyDTxg&hK2-4QwdyZUAW);b&(ohtUTn6U9G|pU2BP#7rzZX4ihm_8(5DSP#IX_*l~J z4?T>aLd;f4(J2+`HE?rknM^vPy91}3F~wkLRzk&2+*4j1ntQMva9u*0{3$}H$FLiu zFs3a0p4+CxOKn;DX4h+<^bT1Xl=7~^0CKY2xHrjW;RY|zwGFpJmpi@jDkOW%W8RA= zUa@LbQ$-6OMW{R}5G{1hnsF1cpartZ^#WfZ0>Udt`3fuQa}x6 z{lun2a9fR00>PF3eibj?Gr(GPSWxpGHt`QAy79fGRwc>cZ~vjJU`CoiqcA=;3*E+b zI?`jE%~{u46xt=N{{k+4qe8MGdAp??s{U(7-jHuRD$$tX3v0LV>6^Z}J~C#Nu!=TR zI86*g`!D_ydrvcx(PQ5Ru`$8eaZCbGLvMZ9Syi)wU0A2{g6E5z*X(~Ywr&GGCSmAC z%ocLC^^^_fA$h}D^#7c)^{F-e^Zy&pwt*$s%54ky>W5!#81vw54y8ntA?6``3u^Uv zAQ~XrykVB2*4q1QaNY-%)deP}p_Jr^I{6>Czjz~m8<)mscDnMbs8*smjE}x^cd{c#wm@0YI3Axxf%jyG6XpSz+YO6lMNP7}E=w`e z&0)8eCeEXfTWI_oJtT*)ve7gncx9=Rh2b}suGO5q4rOP2T zoX3@#Y>LvMuQEQ0@CRWs&ENbl)Y+DiAFj1w-8Qw${DT}MnE0hb@=O_XDPZNXgezTD zPAm&pgqhe9rZl?R4Ktk61PdP-s}a$pZd)uIHYrDbDm3)}Fg!n9iLwwc)E5r%t2dWQ z#7IGfjO`jSXw#f#vhUGK^R33$6-=P%n3p2wEs?y}J{0`?H@z^nQTS3k;JTYp_@(IS z5}Zt)>Ch|H*F22!1)E+!ft!1^2(gincc%h3`Vp9I`j{UK6w0=I_+{8W3tH_#Fsv_wD)-WSqoLTu3QkZTlfASW-WQ^+X8>c zS29pf*cJO!;m%v++$Wy6%o&u|K~8Q3^U-I(w)%s6=-PSVad2GNpt~JF)fa?rA@5)| zf+NHRM(Hrp%wM9%0Ut>H8e_;r0?ymiQt%l(5hD-TCbE4l2YVQMpAlm8gtT_AGHC-j z%01O&QOAS#1w5u#B(Wgn(JBT(1=$;TDy!*L=)F|bInZ1-rJ+bp7%-o#HGxk+1g*7gQMbzym8aedu!jXXdfHW&`u@9#mEnbyXnK zw}6vipE|NX1#jjXAEV#dd^418uB=NWtiofxscKNN&F#8!9+l!VtSqO%xJlXXOYT7Y z=Kb3(mFC8`bn`da-cX%8ST}S~ty@$4J57C9Qe}N~(cs40pFn0V#}@_}ekakr%c|I> zVwPCfit7w=OJ&y>Dln!2d0r`BMYaefU)LJ_X|uk5h5^nc+8Z-_FX)$7nBO6TdaXlb z`ufDWo<7L)&kme*ohvibc~cYO-3x*7ZAIA3Z>=iLZwyM%cl9UeYg6}ZBAV->b|T*F z_TZg-dfwkVVKcPLi^*x#RLBPd2WMx)P$AtluFC;5j~f{HGsx5ko=)W(_OPbPutK*3T_#N7^sG2YV&od@!nO~=fm2k+w#^&>dhAJl^fsr^o!@os~+kZFYaUvwCaTa z`fDqm*r~U!N=6+|zMRcqwbqv}nx!?}_2&tJmI;8(cu9X=#v-ShwM$YxQ4LsIz6Oy{ zS2N9$N!-CTDx-vZw}6hkw^<&F(W39=U^fT4)rN_)8y@M^>|O4d$l->`=gEHj+_z|K zI{)J1@EYk2C3uN@63W3PqTagYH3imD95OTtcUsf5u8%4+F`M zQW8Yzh0TqPxl|noO2wLYqC+rK%#*RpZa6`+pB{B_1WYL|cUYtS4BFzD0~lcz@{}NS zWLwVxZQTB62HwkQ>9;~<5|%&^&h>GZEmhkQe)!1df7yc5p4FN0e`~QzXiz{{msL-N zbk^HXk(J1~i_v+vU=zELZ9(NPUWUvZY{O0Q|HvBoHqV)w}#=XSIoX0DF2`WXQrqqSOfGg`yrT{-P-utURg1`phlBu zW6p6wAFOHBcsmZXhI=5xA**y!KA@Azd6K!m$9`Q!CbqA? zh4ac62b^oOEGx0SH0m2qbXd@d^HG5xV9x$^oE+tpdSUSmEn;LPn(YfCzNZ|qYb&h0 z#qw0o`r^zlw%y1$lbfb_K$IQVJoGvi0m;T6(yfTNHK%RR-P^XcK9Cj?)YlNU#x3}l z)RX$>{_nZrgGQ&pPY%7x3{RJb?LJ-Dem>ktwDj6`-*!K-Ty7HGr15C(AM_DBJN?Hk zEv^AA*#?{H&R=y~<;Z#$6oX#key71g_C2&+s|sl17r2m7HvIxRDL)3Q69@~e*D~5v z|I;JH##}{1)g-q&Zc}cCjkjC#PreSkkWiIYcaanW=0f}oFN{^=AEbxm4O#9DyJ#`lBa`?`S37#z94owuYw{cHdTh!i@9p^O%O5A8 zEAueCF#FeWhFNprA@@+pJeEvYQq!aHTb8dI{fRSL4%_yh8Q6^5|8)j7r{RCfz`hRs zf181o(NAi8D3kAKP-z`#I;rBF8>zqW1{XYir3h#QqK%G%OQhvu^T7D1TK-UZ_BMJ$ zYG~>-eSH>V?TvxyU8NzV4?ojhZ790>|BQi^3KP)(Vqlx3s|2k7%lNyLKxf=9I28!DJ3M~g)9<4PQTr%nrxI!$d-sQ z4nqpSsy<4ZphWf#LZQxso^Yij1*)__o$;rN&xBCE0CfY3!0+s!@KR{Yy`w-rHP&50 zo!m&DgMOh4`fR8X4Ir28M19xL>EjT@BF`GZ|At)rsX0OVw17<#$ChM3>oY@`k1K^Q z*Wt|m{$h&tWrnjv;X^+<{nJJ?Xrehbqf)klL;WNH7GNQdHaFqEWN1gL3WY6~r*oCQ zmwjyIKEi*w>|Z^;(f^3l+7`J~ibC+eWX%;~<^}GH^~$un{HcB}uAfSrBJ60EZnq!4 zin1Knq%CzdlVm_VHOr;)13D&JQ5j^hIp@PH-_fa!dwu_RgMQUcyU!!Lg~xvNtNo~7 zUJ~J{pHA}0y{XQ=Z)s@US7I20cK5ZiiuXXP|6NHh;yuCSK4FG1vxYF#i5hHne;BLh(#QoM&pEp4{8`(&#=q{IShU&P-GB z)$}-UMOx{VPrWcafzUCzBV2ksM#}$4MLJ|^d(2}oD3eCH+6?Bvf~F(3>3&Ow{&~dt zva-NG#QW;*88cc7gZ$B{ss~f6Qgbvf#a-bN$sR86NXF0*rzxQ3Xn-%DePg&4I>{Z$ags%c7G7aQH4a))Zce9KnuX$AEgjED2S>MQIRuy~g zDXB*@9ec_o@T3>I+F$>Q_qDh>MWZGX7RVaaF8X`1*XH03m-6bA9B+ZIbF8OpDB*2Y zVdjJ7WK$gwD7SndNWThbEiUF}>Ybe?B#GOYEhO*KA6HqyT$S z;}dH5xyZRTe}bTDy2LyJ3{~lWeC1OL%v{=IpE0C&;y9| zr*&reKE(3Z!W2r?0JWvZ}*OqJdg)ts53 z9OH-m%?cG(PRgokHkrPg+h{s)d-6bi88PC)ABTcQT5-FK!&x<=4E1_t+4AYtOG5+( zt{T%Cc5WhSrK^Vm0N@pH3(4x6^(q10Y)SR2jm<#H%2}b?396U3_p~~>?_5c87#Jm);b{UCk63bN+|U>?B8Q)5#Z8D2e<K7h-4Jie#_ja4=IT;bMj4>zJS|&sS`k11wm*n%nzdb? zDQDnE62ljNYEY0C0)K*$n#fjheZ02!JpadilGA>FbcM$C(I;Qx2Gua3R}Br7Rb#Gf z#Sly~rhJBzV*nUU?*;{$a2{P?XamZcgy*BbE1{to01Zl5E%d5${OYWG8no=oug%T_ z2_H6Sb6^ry!vWw`*C#9zd2bi9@+8lmc>rBe+(*yjS0h^eV4)T7R><*&z+{Nh7N zK(r3#!NsGUx7mi}q`bFA8|U@^srGt$q|#2?f2tj5clAT&zTPMGH-l=-wUNCPQxvWwycO z+S9bmag1#Z-3{4ubC9wV=<)^b{z+qDE0rTXZ5ppbHZtLyu~22)qEFA=n#-f7r_oal zOF1~%Z%2UdDCKDB;)A?H8^i0=%yf358>yywlDLMW7X=>D>x&4X#;YmIK|{9B%s|Yf zNnE~X==M$;yVLLH+}h5zfOTBNTN<@hx8n-&cDei9@04=R=eH?~uU(Eh9c`Fhb3xiS z+^O`P|9ewedlTF>JDSx}mV8xD{`v)fg{FlILXC?|T61Wkw%??V#4|5|61!B})SiI~ zo7|cVH;OiIu4kU;r@UXS!1$s;yhx2OQbJe+a*ID2UEgy5U`nP6m%)r8^Ij2Fute`E zi?Oga$|QSJ)WN3~EQ|TC8XR4Kb}*?j$CN`gfLX>5MKJIy33}A|6!$82n%`4I%7Yal zN;Ve01QhBsrJ4wdW_U0kDPCVf8?K_Pq$BV2>y~sM@Iri)y}tW*_=HdR)Iv#kCZ8$Z zbtZ{>)OTeqH=OH46Lw`03BxGaOkJYPHL$I_B;&o)p#Ne7Y>{cok~S_+93!lR3rqM6 z@Ot}8r^BU98x-JdzvBU-Q7QNjV0bo)63!8`BvK-6T-U$q?&LYR@`>g4kO5HwOR}WV zSz*S-_g^ll3R_=BEE>+KA6$QMfpkE)>V2tLVY>suh_9wc<&EUY7J+3gF(y#ZRw7ml zA8jhBWl!C8(d#DsuzR>0xvj@Fd=R-}Ez^f_{ee6YIlmUR+}ng)_~cZ(v?^J23HouU zX1*h2pqf)T(Z-V0iBc#Fw{u08%Z}PFn}D*)CLE^0tVdnvoa_!vyLwO+$CLc_yqe}J z7>+Yf@~@}%cgnAs6nPdGhinZ0a37NluZCVF{w0`O){tHRlHInLg;w3Xf{><*!hXzB zLZ-UV=6Y>CC$w8SjLlCZxEK7=M!bTR=uMwuuB6~yP8TS5GEXs@H+nYvOx(`9n^irQ zV)2kbQyjMx{|q=IQS5Y`_IhcteNuUoXxW(6&^e1q?<={JIWt`_l_iZIzvQ=a&y+tO zz60U8efmag6Y7~am)uqV;g#fLKNaw8__4$^He*KM8t)C2AdCtVT`%Uc8SqOcw4SPk7$`X8ZMFs-xcHP^cSU=Q#ztUC%DBDdJU8A#WM;7)L6^}8B2M&%D+!kAB${S zrQcPksDRO$pY}h?zc&mGF22U5Ig5;d0Rs4EjELTcaO?osV`s%by17kX;T!O~sIh>; zZvZ6CH$Gl55)yQJAB?l(kA+wZF1zxlHs3?nQh30#xMnh|kf4_JF?;oHFRv@->_%mb zlu}R0p$bfmTFCbyt<|`)gY)YhuKdvCr;|1^Ga1p=U3oLEnLnXHFwh|#Oq@y(4R@h> zg&L_3fsZZ7l?`Jm1N>?f#6q zG}T(c3htLj@R;D#x{xi=j8Hq{zIYm643HyBmaLAo{F-GURs_%UwVD-#tna1xAJv|x z$!10PF%g1I_+-wZInDn`%`?yw2)GJ};=lOg1eMr*PH{(C4;#rSVSa!;HOyMwY6tg=Cj zxKdzxdn|cABwe^EmZqK}WBVRG!DpMUdb>>)-w=$$NTqc#RZ+a(p=2{4*qC9jy539) z4yd}AbhU!To3`uZ)Zi23jpQK68~v7A`5cLwqrb<|K?S!)Y?@%=)#Av+p`}OjP6~cf zL;hvpqAfbL>Y_EYHu~$^M35se$Oa$UGNhys)zaUCQuOzQxa@`zyQX%Ai8te(@Mi)NQ`}#_?_V`VE0x(uOv`l{GseI$* z+|9zFkh778mjiD5NioSJYzQ@o>s(CyA~MhZAGv6`hv#$|NmcIRu!`|Y?kh2{i>=Zl z)X7}6l4{P6a$(=~1rx^yqfYMlg=zP2VBsmL6|;N3&ikjeAPm6+RH6Ka7gUifU?B|z zIA@1n)WDGCzp((fz)oW)_e?~SFLk(*J0_Df8ZoHL9jz5i;g41)S59bIe^p5tp5}eC z#&<<4D5&%nRMUg$0Cn|r60Tt^@`v{8s}ks?P5xBbG@XuGbR zLTi`Q&eWC_zYyG;?c_G-?KynAA}C_em0dqK=+l?d86R_oIjHg-PbkmFhA@tH0dwob zV4gOYw1>-1TXs9O6xKBx$Sva(-|ckGC5S4s*?IvdYSvS@=X`6c3g0oS>y%QTOP&lT zrB%#LUcQX5z)EZV)jZ2ZG3OQ*IyKVSr{h20cqOKu1HY!n<^zx3zwc8xF{+*Qx_oBt zPyR0*@2VII_QKd7Cw7x-g3%KO)64AZ9RXK-cz;)9JSeYO)0@{2c)`EPEYqi?Pw!2m zr5@DD+jcp;Yd zyhD}8xdxo!?BY-Oq;@XHQmmt$GcUEhUuI^Ygw4O%Sa$hWFo^yre<%&7K)@Th# zFC*N2!-lX$Ziuplq*y}^SPjm6bG`O91{W&YJ%zAv?r4%P!4_SdI|t*Y=ioM_LAbD) z!Ei_X@UI!%)q23YpBTMXcUpR<)?A^XB4=FG=_2)FB_}iIa^9pjbb3JVommg$Wm`Z$ z2h`>ekKD=};HoVf|Hj=74}hozHb_c$H(hN0Po&W^$;g9Q{`>oN4NrmE!V~@b_vK56 z_HLkCdl$dioj+nWavNzccuS1oZC*g0X$F}Z*A{=(@G-=M$5eqOi)Ay;7`F+)ibPI4uwx6BpDa~2 zqQ6stNIlN0H`U4LXlfw)7u!E#nlh8~Ho0dYW7mX)Ib%CBi^w@*v z$UbB>r7b#X5j9bp3!@*yB)eP`@c!AdXwvvguTxNZOUq_r# z3G;Q|XQ0J>avW;8MPYPEF@AK+jlHMyC<7q(dAT91wo7H~{NZ&DF~Efpta}*gO#uW&=(Prp0{>ocy!4nff9m)7TATOJ<)AFkFbc|t| z+oRdLZ3i_Ljy4$Gw;qYO%gXA}OX>RL0%ZKu_}CVS<}-sfuqbpa1O&Huj?veu1n-Yz z_#JUk)X@Y0v~pyVWQ*spmIwRE`8k8cxi(JYA6ze&_FcDF0Qo)jk8 z_`zS#-6qRFXnJ;l^%Xul`c0_Rl#ey;nZ*Iag4td*s6Q=+1m!E@?ggW^lP5sKDRN@C&jM?)x7!i$BqBWBtghg z2oG*E+c(90zOqje3I7!ZdyyE^oo?&wnGZ3(0zFZ<__8~#dT+Y(p}e)2rRHEe!K;S3 zm&YJq<&thj#!p^?i7e#07c(diK>kMck+wp+{yx8$$|r>w=~0#MAKVZiJS{aeQS;6- z8sBV28HZ`h0SLEfD$18Fb9?Z#K zFnJa~`J=Cj8e{fn76z<2KMO(meczQF^GfWP=h45rc=!?eCjaGiH(u{TX-d4aJJ)LN z#2>KdbDY)uv@>{LlYNaQkhq0wyJs^*+x0&CJHTYZ~We;dK5^ z=2MDFgDRSACz`RJM@N%N?_n(jF8=%25w_l_yT9*Ovm}VZh5={Y7I#O{2y*KD^0L!! zby|i_DtKG@D;G#N!a`3y{#=YU(JzP#vhDBfjw4~!J2y0HB{wHT@H#K1*Cc&wTdRZ? zI(m)0XhxGC;uSkD3fEo}>jt6f^%mYMT5qwu32;(N?^LsPAnG4uehl?Ag3y0tYNeCZ zZrB!G+0m%d^fmR|A9OA;$>rijV@LC7#NCStCW*;pl4JxthF@v>DFI3hi#;4Rg0;x#` zqZs-d!wOOy6RCFZH$NtF+a|C7k-ccm&W!wKLXz2G$tfel>xxFBYv|tSq`a-nbS-1n z$&OSj!#wM&m8vR-JZwLHY1EAk&P`x2s%>}iFvQf|Ro^aA ztMjP@Wd0aM(M>#n4{+R8m7%)2e5>xN63J&6Q1LQcZ9=ETUuupV%qfy zKj5tDZ1|zU&>O=^laGJYE1SJ(tl!`|_F|Gy*j@eSwc*=3ql@!v--TsLT}u+YAM@F7 zDdcx;(gO-G0}*ng^39vmI=d>eFD^cqOpDUnFc(*0WKOGmUmMo``BM$+c=&~;K~j}Y zab`?sFyV))T8QWOGorQcc_(Tz7xpW>oox`He`p8^dXE6n31ZYHExpu_+90`8ZrFIXG~#B-y8Irs-mF+Di>P#Hh8XW-iu>$<{v)8PRUugM zI8_>-fIDRo;O6 zf&G??8T~ff*kAM}k#~cq5BD|<{V6bd&fCl^XK#y6s(j?ZIDB-^pu|js+LN( zHES3;*eu5tnHI&}jO$xe+XW06D)0eB^u-$wYa8F*GcZzvTQfiAUGqL*DD*fEt(R{E zi*wT9Z$LkDF9CB1^9i@33 z5ulylvWIk-xDg5>++KwqvspN^g{oLt(^5>2cL`g@VL};*hmq&Qdz{gtZ1a+ zZL+vcU1<8-K?IZab73&9@5p0|`_|u3i67YZGfEPv$_dJ#{vD3l!YBzInCP^R^e@!h zTd!04s9?swb4c&n6{~=W*Vs+|#gaEW>R7${@8F);zaB_U+{oYW62qZe&=SW;uI}o~AShH3MNJs*D+~l`4YMW*BSVGZR@2@{av`}vuMm64R(1gfsUD!T^34i$3oGuii2pPpaZMI?c7P+h z*`{yeS6e@ahRe=Skare?BTvn~to&{ULicmUvqd0uzrp7u{sXUO`ifrbo_-LzA8h~O zPUi$ntW(*Yk}K$nY3<+@zpELj{u)+G`^LwW9^Dm1l=Gq?b@C*>`)IJ3mVEKKnxJse zjSBATxoEYltR(|AQO(So;m;wAdz2Ma0}7|@%_ZDgws?Dk<(XPa==?VpAeJjIR|=v< z>9tYxGVWX%{wbL$hA2xX&$`0>pb46hn%(}MqQq&!Rh55Wn}pS1J+u`#bq#rVO|JE4Jw>3ee+Wd6W;s3{N2WdJ*kf^hJ#KCOUckSq22ZlEL3z`< z9J>`b3mc=sn-uw_NluQkHFNP!{l_7}cHDM7EhcdN803#se$`wEVn^qJ&`MOriK@K6 zC|&-Zah@RuV#^ec`BDPvhuY|J+=+)E-BMGf-D1`D6by-Ux9eWM8J(t_cVC+m>7iq^ zx}4D-ZVd$rYip4F_}QT|a3l#&{G!K*)Aje-bKHFIJ{FJ>$2NlHSvWC35e~AnlhC;52 z;@Hjtg6?H_2sRr4%PtG6>d!r>6R_Yv)evYM+}3Go@AR=j>pq@7=1xOhl-jNx;DCON zMW3@U#h2y%fjjzpV%;NYd>X7l3-db*-36z|Ma_!~RNmc9-95)FR$liC1nHv(2J z3B?#?PeC9-P?W*r1c2m?kC#nDZ!-R^JvE!t!aaq0(;%(cUv7hjadW|@mE_9dz9|nL z2;$cg?hZfDi69Z}j(3OX2VvUXPfR^Jy|f*QO`P5my@!*!R6MjUWfXucp+;{; z9LN#^KI}Y@cvS$z0&~y6X82& zu`ZD_Y~ct`cJkm|?ghv2h}`T)(7iOlGqvjs!3=0eX<4#Jwl7#J%CEf*tM2|6kYvVn z&SMfuIgBuF*&+rWfba_-qJo4K@x&Dp=gcDWWxsGGeh zuUxl|^!fP&L(AL!XF?eL^1*TtOl$0seucmBN8vsT!5N)cVVd+;Klpt8YOtSphmR}D zwW*2`UKw2d!`WZ?^$(q>BTNPhTd??VR0$s5)H;;s&aUxvu1ymu9LW5I`#6_<+J|#$ zz-e+o)N4BEUm{u7IvkGZDEoK~;jVv}h92&#!__Rmeh|PV{y7u*Z8-&P#{d|DXzmN}ivq^Mf9|K<#RhpeM;{QEPUPB$R*x6+Klg$DFOGXFEi~yZTye8$jmnt#%3*2m6VIYCXAF~3&Qpktns|>&TosMC;O~42#$K);@~{Et zgn`j-egs|RE$i4>hEBZzrcl50f$|FbqsbEUV2P4D_Qeu&I4mN;NR>*n92|=J!&#^U zFA?Zt#t5f?YV+LFI)~)H^(97z(RF$^?6#8R4G(~GR@7?vK{F6&Z-T&RIQI-!_ZBHx z%3s0~PD))ojr`nv<_)b3Z_o=>chb!SYjPh9MxN|d*T zRvjfckfeJcP+4Q)87`Y#AL!l*LGOZ}K2(HVTyF)kywpb5%oJ9&4SWV4mkaO@ljKQu zL^MEeDEk#_-*F)ScVWjdud{0uy{Qfy|lZ&{@qz>pBa%c=z%fEHPfy z+tVmz3`>mS{57zxu{|GySfg)9xZjBj2>l;$$CK&eA^MK~r;22+ zb8QZT4#{amB?U{t=3Jn%&Ky<+M*m|~+;7t|cv21zc=#^d8srIu7Qdf1F_4kCpO z0@%MOnkUvx7^@$WOICVq_~=pHC_c9I_A~v!lLd>Z%|qQFhRG!KcXyu~o{J8CfC+&{ z$76R2RL~j@eM;VVtp$LTguGkw_exr_jX^l!5l2QnCb}+bWbn{&P)t$2Q4oom7RUb@SvYr15^eeN;f)rg?_NA8-;wpCVgvMX&>Ujce!4k2pOI< z-5H;vDLxQ`3R6T#HxE-YcW!!AcSL;le;N)Eo0=9Kxqyk}G3Zl}4WApN2{ zHDMY3y#@>WQ6pO6nh$AKaq9a@L*6M{lm#fYyl9V@S_}QS_7~u^c`69(OqK{`4 zgQ{6=)#qHcc$0d|8+NXqaXRHNeNziOS9uT?5_r#QuCa*n97_IP^rsHQUQlS)@ZQp;LAmY6*okiH zQ0cU%o?3Y=Gk)aJ9>lTH!Ms56jr66C8y9$-ou0LNUaaXOdnJ~xt(-WrJoBv+nte`p zTW`(iMXKb>>89^mv;z_oPR!hLX1gKEVx75%kmKVlJi07uvg`L)JlDH6prJjSqwja@ z_F^qI?LYE)I`1#G`!}QFh82xadAL<8Wdr?U9hHnNuGk_t1~AN{za_@+rr~ODuS%&K zLEbV5=OL^dymw_Q>0lfpcddS*tqHV^O;grzJ(HgNY-kWEoyfCDz`>+9!?ti7G zlq8RywR_e^-)OS`g8oL(Rb8{yPEm@v(w^FL2X!vq8SHR70W%nn`*rk{V!WBpA<2{4 z#_boRZ@T2+=_HXy3qY5WY)wGY66~OjF|iC}S?9y&JVMY$fth`DPApf8dW$uBHtv3N zV=MFXNWx<39XR?Tso&O$OWFA6J!39qgM67m>Epik)Zhc#A*J$LE(+E~lkgkWBY}hv z#M1n|slCgK)}o$<&rwx1jwan%15{2e4jZ^Uf<{d+|X6~ zjN?|g55XpcV*O&O1=?DO1_Ix0BnPW_d!7#5i5lB#;|F4JE*{#K-sd>98H!c-r_Z@& zNC)wRX|Doa-_cujh|1{m)y9EcGATdu_#lY>!F+G<^j6 zU{~9941v+EG9AqCw4_ez1=E8Sni+LAsQ z;-oK(;u1|5qC?um(-qLm81Jeq0R3z#Dt+^pGWJ>(>-xg2&6kd-w;n-AkLkMmg!lM) zk+P^}vw1!@18FVw)^sVV0rVh86~5?dZ%16MLJvRs3qCqaZ}%^Ltw#woxWhI5M(Ms2 zl6&Zp-^B3SOiFNL<6vq~r}S^#FnfQWn&w|`N_bR~@Iei$_2pU~RsH~GX|rmKT?gv( zR1L{nxb#hOz-fta8ed|`|DzLsNx|LBH~dP!-=9+pa>8p@Wunph3KGxJzBV@l`4*X9 z4eeUB>ErKTca*z0n>x7?OfR}SBTdl!-bMWgI!Ww7Nxmfiq z=69~MU_(R8z-N6-$Yyk|RONR@>LcqBlwNE7X6W{Rgf8V%tH8$k{@S)KFT3m2Z_^Fv ziTZE%Y8g91hU@$=%y(}}jqQcUDj}Qdzp5noc4yzX!X^a^W4GxX~7!o8iGr@`@Bm)GjodG~QU=_++HQKoNRt zb*JMAch5_8sici$4gVpBw}#tPCHlYuvlh^K#52%~P5PL+lW=ADh{eXf7)ZUnFw~-% zj>vDnCehMZ&HZo|V)sJV5kK{)?o^DF_m)8SF}Bg-vFoyC^XrT4?&ZCNwY<@nn0W}_ z;2O(_KlmH>D`fqgXt0|?+FgyDXak`fJ&gLZmCw$5C)lPn$w5Fm*?EgydH0j8r%F?= zF@8JoZ?n#SWADAgn%cg#(d}l7jUp-{H7Z+CK%}FTprU|)AiW6zLaz#hngkIALCQwy z0+Av;ASHByh;%{=BorYaLVyrjXd$3?A$y#bzBdGwPzx~-!Wer@i43}8jTRlN1fRB3%d05Rvu;JV^xfZxOl9;5Ujex{(l zYyu)c`K=$s(a@BAJ>N%0Th~I9V4a2VG%9N58j* z=Ff0Z;$|sGBP*?)P%IZUtf}1z}|cbM2q#6`}8ecHkT`) zK`O~O>opftcFV;yXRFw*Bt1x3cS2~5vAXsuoM~p_#bUX$^5_4<1n|d6 zN@LXjgaEz?Hh7`u?zo4;&9R$7PT#*+`#h!K?ghykaP_9BeFIA0HpYhczSW`tz{h?c z71CD>JkyX201W$z)zKp{g*kxU-{zxD)pQZ;*L?*R?p*`6ktzeJ>o*3qa@BUmH=n8D z01#-)t5AI^wz0M&YZ55S*MSjMfV68T;^KZ^jyUl|rRQO@a%F{4wQ^EGsLq1@XuIOo za1{U-zMPnSqQwcY0aF5J5#Bn?$~dN`TN_Dxj{+aWL_p3lduW|eQWNmf=>7DV(DoGv zNC=lSq>$RbaX*vu6ApZx-igdFEa3V=;bp;P4Ihb(VPyedm0z8H9^6E}wkc})upTh^ zP`wtf44nl^H>=Kl)N7RcD{q|_;CvF0Xj?KkWyke&06g=&X`c(&%ek)^BAyzkp?Exf zQGmHIwSYdxB6D5)nEsa|%_jD<$t`Cx{r;r@gcqO#l<3f!AScO@$^ZJbhZGC;vn{}f zJfq|!a0M&3_QBt`gCc;vF)9E^b3f>22F*rfyGpkBaYk!#SRFrrTWDw-H$0F zh1u!Z-T-37qlQOvPU*Pvd)URc+qn*Ghl9CINXH!#(Ml?!YsEijgi<*w0AG z9&}w17L!SK125_hD&l%W+&rLvH0dt^M`LRxT^I;0#kZ*}*%SNlQmY$4rCEZe_rw9M zKduYq>e%fGbX_q-5DXyIG2;tuW!Y(Jd!QN3XHKZ=JCmM_b62E~rAE@GqPFY)lOUS$NL|?7A;`L>R z?e%pK;hutzerwtz(2QL)0S70ktSY>(1#3T`jUNust!7lgu>;#5X(kPDTZ+hOyD#%c z9yM4G!KYR>*OycV5dme{G3=H!lhUsM0as3Qi%%Lfp*&poqhROL;Tt4|K$`{w8`0YT zEOEz9C&U01l&D1`++BAY%-PxyWV8pIMwo3}K00{sr1Ax5zm8}+zv6(-`F)jfqwIVv^ zk@}gWn9fJmDuAu}JcY~zYIy-A&4r+p*Fd<_zj9c$$9CmA8!UuN)fVW%RNn)r$uq73 zg7TVxz`E(L|Lu}@ANGrG|HYDb(`~m%rVk|xvR+(3g?%!RiX1b^d3%IsztuyE`1Sx+ z!{*_{g>c2t-_N!-ar3lwG<4s~fdQr;sqVKAd zcm7kkcjWy2?4^A&8G-T9k!EngZ8k*8#Z^<%@AZ8d9oRmuCLhqy(u3tdA6wuem$q6sPhJ&fDS< z-JGf*{GlYn%e<)c*U-|!WY$PwK*wFyM+OS8V}LY&gq^4D`CVy(y@#DQ?c?)g1Se25 zS(cn@18SB|*!#r{sX6{;MYG{rbL{7bV}M%5L+*d7CYu=UW-9j)>a?F_<~=Qv6e`gw zA)OP~6|N%g&`qfp%5N!$JKu8v+o(ps^uqFR6p5H+b!Fy0=0HG1f+_(-7aTs z^@g5rO4-tR!8DR&(&p-*rNH?rY?$d-5goXuVVR?wTvXWi>=EVIJwu-IkCV1oO9eFTUdaqSx$lE;$~HKLukArSP|t zBD$|;wO;W%n=Uf(88G&M%&=(UYuuvnoXOky_c%<`kHg?iOgH|#R8AA z15_hpUO+wqC@?q&4+hYT0DYi?K@AtsRX`X}HJ0A$X3PPUsFWkmf)^whHJd2{oQ>iv z6G>MBq7`T3(qBv!#k9PABV`W>lxd9ZkowJI#Q+e0jNj8UHoRUXk_fD~2-Xl7X zh3sn@qeS*qo~>?d0f39*h!P9(rXj70+u1VpR8BQ}XlZx1)T^s^SNZ(+yTUpZ2%Ob< z&>K#+K@I;+TKdN(Esb$I2DSkvms8FgNNU%{_{-}*+wY5*3Xb0h6wNZ&Fx5v)fqe>r zn!DaQ9j}RU?FJCLCW<~`x4P=bR(L0->b-dk1za>Tq4`LjK?&-suCWsw$sqa1djU;3gO0If0YTlpne#93rN)YU+4tu)?N8r zPV8A!v`-@qFQ-?rFR}=%B%FRy$@L4v+plMVdLx&%D8o2R@SA&)NXeR|$@J8w*G9uo zKRl^EnDPlRGmPo+C-taCn!)O-VKH4#SM&Pta#+&tdRM)#XqPb!dHcQ8-u`rp*0zo|9>D{TK1!nJGZ5KBV{*znZwA3=11ilPv|txJJu_97~h0{g|5tp9VJs2ADgfk zl_|FiuB>y&`doP{X#`rgHO_lnh0V^h;IT2x6qC#_za1c6BVej2>4N;u%bd{Y;D}V@#Uo~wMr1mBUblEm!%j4p`q7YG&yUQk zB-*FNR8+}g6M96t2o&BZjH%}w@+FEZAR!CPcDh$X)#rHcs9mF8ikXMXNK$bcx+^g0 zv~+}={oZdID;4&vHvTVDATXXv{;xb(N5bXn1+#}^EI@%HNgEsPXCP-*5AiI6)4CkS z1{3YepZPAIqaiK;?UOEyfELVr9M%tK3yaoN83|8I5k)xYrM01Q)MLt&lD*Tg(4~y8PJ}sfo1t*;K6Se>D|b zER5>vW=if%pF61~8@jth|FkFY=`Hv4IeUS)ylr~P(Pz50#o{|jY#)mxN4D4F_+DAy zT&@0XJ29rI+)~-V|K0t>W>aexRd#sHO*WeKKr62H6Jb{!fR0x{VH%VhQS|$eVkc0% zlC$&?o!+hL9)LcBh&{8^R>5r zmbX`cj^>*veil%-!f^qlADPE2_5jPgBI=O*4gEKJ!d{O5_dT~HqHOl9)z(|8% z{thYqVE>>Td3~Tc-AcME(7Wy7^e)7JKk+}TkrVj4M(%&GMs8PN9x$?1a&f?QBIRN7 zsnE{1r+k)u)6Val2V}k6P?CT4k&)Z)Bg6iKpB9?PS<}gQ+w^5Qj&{Xa(n(RwdNw}X z?(Ex|#Zp1Rtt<7N;Q&S7q1f-tjtRgzwjpeGbKuog6T?>U-wFa;q2JQ=V!jZQi&E`? ze3R>%ee0*l0?1q2+5dm{g`zQ|BzWuniYo$A8W`?IBlz8gC9T7%vH6o1>XQ?Jmd9(d zq2apLv5J3W?2KaDm@iBHES)cFV(hVsKzX6E-QM?@md0cr!m5>n6GF0&T_v@NUs8{I0<em}dNNzz`bc;K)SbVSXK&iv+u?mEp{ zXagiv+C;MldIM1$tn(ge6qKo7#z8~EfU1uIfj{)`bO~;lXjM2oyI9_|CGOfyNn*7W z=Y>b*ciYZ>Xyp&Kwg-5p9Q#@@ODp^Re_Zf4oC5@aTFGW+6csiH{>gK84@{~_Gk}@^ zT`zGgAz?vcg^aV!-RjA#$ircKtW6OyTXF#iIjC$jbiW)4|9i3j8OCR%vTDDBoK|X} z_MYG6-Y?$_@7oI`Uy<@u9r4hLQ*2l}&LG~ket!7M_TSLb|Mv2@e;{ZH+mo2%@q)3O zt9DiCBGAU;FHJM?ZAoZ|uVUKBNY)%KGSYg*$Uelk8~I440h*BBHPP;6XS{nfCle@G z>%727aGpIJmNLJt-Z*Btl1B$R%OKr3uPUw?%lQKxYwD--dwBk3%bKv2zFk!xjPBOI z*Re(gX!a8W&_r_m&!5W^C`Y-J%Gix%VjT4`{T&^;k!s<`-eeM@@FiHI#gTwklePi*}@BCTfX z>b(9M-Ys@1AE=HSJ2yR?rjfb$>%-C9RB=B*D-CGAwG_K~EYwQ}Fy?Q@n*`i4Pr7raH&*Ry&17uOg7xa)da9ooKrmeE9$r(ue5XQ1Z_O>VDKW`4 z5*C>$gkx&iQWcP07V{r(=29C|q4m{=k4!c{l8`t-fTuOHsQ_48f&Zy=Pt>x=Bk*2ww9@t_PlCf8$`sh zvWIZV@ja?OlxYp{U6ULx4|(B*fZp-BApj41n3PAChy*H@-BfWvtIYOd8>wFA#zCE~ zFjqeyZ=VhrOgSl_jnWTO+L?`c8o(hFm_7%n!s%Oz)h+dJK3aV`C#V;2H~n-B&>Tp2 zlkq_-f+bhr6H~^*qz3@gp#_-PpLB)TfYx#)ssGr-i36x7JSb}>YCqw3i$#5i zu`|D!y46t+P`L#4%Z})+F-l7c3s5lJ0svE=(yRC7161 zf$GL0>DLK#o0u1v&{=@ zWkoe#-n{KR$u@sEzh6&#gCy(qXtH30OINN?35lUFsp21W#So&bROW;oH0cga=@l`g zDa=$iH#oYyZFnf1K5*@-rPsM<29r!cAu@_9bMZ6=pr!``)O09;9<{gR&-mCgdC21? zheP0@4?1DwqKRlP`CiL%h*cEO^S1`<42Db>QSvD!TlDKhcVh(#HPi6z`;%=9x`GZT z2r`p$ofEVEY!CUeL#MGju&oR(v&>~6&osgR0GHVFCBC|3pk}$$qn2d3Mb~xw4$rm= z?uTQo9Fe$B_CtZLx1IH5OnWAL`k{wv`TGOERBSOuk2s;Li_{ zNtf{TG8_nA%sgVR9b7hX7iHAY(Ny0GStA*uUQ_>3B$w)r#8&<-x%3Yzxx}8`(XJGs z^j09Faym$Ns6^V<;YYI1%*@s3W;}9MLfKj%s+oWLaEw*en%#a)+z8R|)jzQ0(oMSj z{9jnW|I6}AGe49A$%oFXJ$e75#HcX!(r>5kpSl>H>LuR#&5A|#Nb4kD&q(WcD5|_S zT!BoZ_sl>3Xcf}It<`f=#%`rQwrLt6x#46 zz75#RXSG=193F*<-mIv(=R2Q+^6&5}6mB#SHL5PrQd3HE=XZ5-f_^}FK~l}s z&_P9SmIh{C+qvBvGSLa(K-b>#RW(s+6jScYdlZ5WY2cmh*W%a8g3xNEWU)zl*<(0ttb%}C3ok9pS_yef{+)MOcDG_){! z%pfSv6=I6q^D9I}cghc?6zdu^7d8=Alh&;1>I@dDS~={61m#Vhy-QkFGRLKg0|La$DQ7K;m--EPj-mZ(E$i|a z>f2AEmhe1}&@_zA4yNV;&_x*OW@M6KuNsF>Dd8{>UH}*IsOKTDDj{f>wp+fAID-5@ zfdp%w7*W`mSf*u68I5fnY#*?4@eU@qqZ{O3CP2Jw`pM+GGx!1xv>(rVjI&nOl0jw@ zp}o&g)$7V(HQhN%93*DeEB$zkd{xX2WW)>>ZlsNV!(+teB4S8*&3L3p2_o zWByj~!zqgywO_<{tL;_4Ie(BjhkVbGEPuknfRbHu4I+eaqmP(5IJT@@L)WUAZ$$O! zwA8Y9g;9;o*l)vlv{}Q7Z)83t?0*$6IAz8)&^bkMWP54gz5QWVRi=^9|CHIB_&OLE zVU8Jtt}Hd z1dE@r^ynyt4cGE!`B(Cd2VM;NL@0W0Fz7IsVmm*&G5y?Uu&sb-zaBw(`2L6C1XoIQ z^h}>98Zn=jSA3Cbz{fg*tUT-YA-c3UB9!14NEa&5sd^|Khkynwx;rk~9UBiOTNNNu zZRgx0U(oVzv-PEixxcWUc!-;74r=0DKFVNnF+`@z>ZD}xj$eJ0R-8-sR!rglxFu2y zQ+G9Tb+@>*r~{o7&bnEwSL^d=WE4Ch+9(2r-y1TUxibIlt{?Df{9q~^@J1upGYqR9 zSQJD@>IsgidGdy#GGNg$pJl~B7y%j|34BqLj$sdRYP>HY|H>1yHotIjxYqVA;>@dx zF}2e&17NIb`oqh@Xs8Ja-)XXqnw>@m;NJt@34ax&(F(R_}T+!9? zoa5L^IBso(2ZoNFPmGE{LpfL)qa)K^_ z=0;MF+5$%6^H2f9n_6w-xGinMa}U_#8X;4}*5`_iNzBbL(eFh;rEU@1ooj|UC87|! z?UX4B9F%|}&~@z``Dv8W&1`*8n($`RN=D|*cQegvE~Df?>1trJTW!zY`+#vyXa024 zeq8O-GTeNDCxJa0M6}wD+TYq=E-xLCB=rJEnew@mT3~Mg$nWZI9F6yuM3{iRx%myR z`K9nqZ64Z^ojb*fQtc)toW|E4QhqPfTs0g22yzcQkMm>*@3`PGo{l##p4%VbmBnh} z@XzpcW=%mAb6w-Ssg3dl0anKrf-t&iMJm&N8?(b~oFx&}o{#utZ9B?I9G)Z}8t zasT;87B5`rRU1$n4YsG7&~^#+aKf#WS9rR#5Uisq%&e86{Z=lYrGb}7 z`4zknw6PO9so1#zy9DMNa|}flz_#}uic}gs7?39&F(<3Vzi;XmNs6qwsGX15c&zr$kc%N+ z-Z(KL0$mvS*d<%$3o?WQ42pI$Pzx*GQ`lL7%ChwqyF#+SDlZvP^E>A44B zSFZ|w1oEq!&d$=j_7@K=-{uoWmwfJSIlWbEoQbI_9(PmX>fxQI)jb@m=_Zq1ptcOL zv~80GeCVf9aPb1x0{@b}$qOB?jFl^^+f6TQHuFj#{ZZ+{b5&Wf8_knK&86_-1~I=E zlSyrheQTgizX>ZV9M32fgy%ZMb-Vgv@d0Q)l1pJqzPrPvV^nIzT1kC^B9$Yv)xyQPrsUN${Yo^^K|CQdQP^k#wc$-D$^y& zqzdh=xOJ?u(ydmC9&#ey?RJ$P z+C!=DWrfXlCq*s?r{us0W^VR%k)Gt`UuQ91LvcnIL){Q+dsOA8FN^e zYwuYp?CYEt2?g=7<%E zcCE`IAriY*d`J2H5O_T`^KLa$DC)*sQC&Ho_^$L5h)z6H8osXzt*-`AM-hq^*xk8Wi_G;7gD*nY2|G;jt`xKKwe86LRhq`4HzeY7PLSt zp!<*(_{@5vj$bTh`;{M@DL>TM@06r)_l~Qu=3@nQ*AO*7Y9Cg z>nh8;D}htT;v%fJ&yG@EScNJ}s7dob14@UT(KXm7V_>P_n!qHSEP9N=kfA**zQ^4AOWq>HMD%_O!Ji7xp-rd5@43zkM7AtDK`4l z-^2Patac)%0CVFH)(4{Kj*s#e8j#fOtBaI%*{dW++)A?9CFk?Ni39=~yPc*#P7htF zN7AIrDm=GGDS~U$;X-3!cw!XYI_hGVaX(y~M0UCoS~7qI&fRj>Y#|G1qw(34TyZcQ zmCvzd*mhZ8{kZ}UV6zCbG{J0Jq657#C897m$*wGL&qH z0%&3EF3Ms7xeI42zr%szdI0X(Y)(z%=14E(Mpjm4^(LBp^(%+-Gb(~vlznWC$Zy{W z4IW1-M@~V?;OR^CPU)yG{w;f>LX*X7F4r&Ndnc4+!K4?JswyZHSPy}GV*|TxeC5QC zTdVWu7e>{ZJ`$#`=JC~@$hZyxE50j~5#sxxTbV&y5^= zs?1k8yh>22DMs*DLtoYTT-mM-DemhI8LiB~D@jUm;FATl;5fDQ!H zO~ql^@U|K=G3s^~9Sp*$D}=f#NAZOskApmtk#90H=Ef$JDn7HhP4ND))jD^jVQX?+ ze-{XWqsaB;w5&bZwl(|OrK#1oXBy}dAIV(cTQeWs!1Jq}xpjVgU0}Ft1pno9TF;MX zQpz88;B8$lIUebED^XueD?vf4V9+H=%Yhgo?zPO3T`cR}zpwxlXaZ|P+7-e3)*nJ! zY|Rz7mlSS$i%wnI3wWU7zvq2DxtFZ^xmMR}Z*&#v0R?#wWc}OTA|#FHtA=)P2o4tI zV#7OQ{p7kV;pt}2XQh{j?A|A7@H1Qcx7A6fv}s}wD}&FA4xADi+>H)nb)(CZbW~?( zhMv6fn`sWN7f@VHD^1~mWr|X79soBM`P{uxv1Ejnk`@H4WSjT4Kd_5&tJd@n(Lb!z zqv;>u-?rJJDvVefH;-Wskvxm$HUS&%2|foNK%R_^0FyX5n~n32nrPEx^mteri$^%L z(ISKGE7tTC#)kB;7W%ZA#ICD_Lhu4sgOOl_BVwk7@G-4n*&u#s>?R!xMU$yEa4!w{9dBxu9Z3e}Mv%=f%(cYN1d-!-!>bHun;QXI;9;P6{bc&bJxo z&(Yp+u#gOm@85WAtZoAq4$pJ(t_js?%MvTV=ofkd*940%fIFPW6|{*$X0{WI4#Q2r zdWI)ZpwBkIeT8$UeFOcR=Uz-n-7Uc!7|cupo@HnjGUaer4IxNUGdY3V&~&tQ9OpwX z$e-QAYR_4{>|HgqRu&Lhvz~n-qjnRK<)UVQGk&p~q#7Cn^dX3{y8N1&Rn6X|=C3^1 zPHf_MT>?vVq2lZF&SA^40B=xPqSsGu6I|c{gA(3Q1?L$u&O8Y*&)I*c2;AG-G4C7z zu#kB(xtw@UqK<(^p}I>KQKIoa4-3gL8&iBMq=d6s2h=?EHh3p`)7hQQh~0zeVe3Qr+TNKebLQ#3;__%}vyv>IwTYGy%T$ms@5cp=9*ewy+K zT?T*u#k?TShy}%~+kHfD?EE}aM_%ma)E7zOkp=91r(+P9x8vY|!Y7t*eHikffd#5% z{&6L0jRPlM_aF@Q@t$$UgIP`bR89XQ3x(pfikjQf&z|$>s*-n_`12iYzs-*dg%lGx z@2cEvyejXP?T+6_hUc)Mp7_r72yrY`rDrwUKGY*x+RDvMUOh7y&+p+=5mTBC5@1>^ z&x<=-Chl>+c~m=>b8a%7F3(-J;T^|RaUyT-1FpZ@@k$OY7yM}at3oEjo5NNvanwyI zrr2LlbAHWVy!**L*cLnzJ?mHQYh#F9CR#tJ>4MeNsu|CJ3+Do7{2A|h$G5%aFW;Tx zVO}6g!I2v&+&C}y9ND}<%dgu}^Pb@ub>7Vz3AcRm*-E4tFu5T@fpUVG;nYliL&-;&Z;ek!f zb^3cB73lTS$g|bM9tFKs-WYmmo_*^g+&DfVr20hP15gjO#%;hi%ASq%B{Kzi0g28M zfl=Ql4B5w2K6B4AY9$myJ2G(BYBlBdx;4|y4e9S~NDOQ@Aydl)LjIV?8 z&U?@_??iV|)5|b(bk>(e{zd@EQxGglha`d=4T_rxO_s0VHxQM~=2_1PGcc+n-W@P0 zom7z_PP0|%i~NyX{i~+Ke?x+QLxTTBNHBS67Zv>=C-3F1&%!TzG_ z-{YXz7n^WP98#v?{#a=qX-Gm5v<6!rxs+e{>N3d7yW{0(O-jl1lQ)DyqN_={PjhQ@ zbd+~`U3B2>lfT`b`}K+@3Yf*2pa?_G%}r4N^QFrI!#gruIc)LrVf>o@#pKhK6HmW+LH-)nvF_IIJ~+rJHip8@?JKL z$lKa1KL%xt9TcQxi%B2cRUEXx{C-n+f3#qEugrz+2n3^Yi#leUZ_}VNwPitrDUK@H z^EEz}-ui|=^_CNN&oNqz6E-N5o?951hwzZiaA}K2Q>SrjbqdT5JFU?V3b+GvM*{2f zNWZx?X0efI#a^lxIenZRwm0e1G>+x*bvmab16~df=Txnu4Uu^tBnl*=P3k;1d&NIDM^h^iDz($&*` zgmI=WU?`V}BGW4OhHrO)*O$?DJHG(b-v~ifR-U3^`5Gx0{#QG?KjOQp z0$UfxsslPwGR6@uK3W^`@sthMyP8Gf0Sv<8gnC`rwQ;HY-rkO0p9ObVcq&UrvGi{X zKoH^ss_iW)2~L@o)5%gtVdq>ec)29^ge%7N&9|sezK|&^>>cGIOXd#7RQ7v_KqUiI z%uY@6CVv2~HtIxTk)*GT<1L8Bm!=@^d8tt{uvE|b-g~NMo^~_a>*6K!ZKfj|lreYN$&zFH12@rp9^}^Bp zT@{X@D9m0rt0~Q*(dJe%m_pf>JkY_;ZK^~)3rxV?0O#w|hi{*Jp8hKBbQl}Axb4Fq zmvLu}OH3Q#GiHCzSJ+3JPtxz>yI@>rxC@~eQlsISx&IQpO1-|myUoPRHkZrql4Ep| zh_+~Sjyl*xWE=A5Lre_zIZ}~-W|mGjSuP`}sHVUE__w0wl-+lK)W|w-fHXceq)~H8 zGV|t?;C@TZA+oP!&+>5g8@D2#ioI&>AcsN$1Xf{mZ}!sOQ$FPv#HxVW!nMMoe9N`7 zn{Om`qwjReL8CAa;BE%KI&QAJGu!d$7IbK_KMa8PE58(GAT6m`}dO!K;=8rVjR= zJYUP~G-UX!#8PNLu+SA+Zcp8@6Z!K@@+%0j@k@%&bsZz#e}S=g)*6$T=XDJluVw8r z{_`pFz*7{H^lV6y#^zGfI~!>(`F9SMupC&z^BUoMJNJU_Z*XzTjl|B=rW+jM>3JpE zb2R?sn*Jdcx!!h2bAPT>;N!Yn-^xkhRN(F~bj^)XKaG3WXNY_&TiEldNa=0FigSFQ z&pLf6uXFoDs+DWU1{42hMNkU>k`I9W0L%yD)eLTX1O)cuiV$<8g$j_x+Ipi)hsS?W zeUBh>o41qiiNhaXJcrd39LSqzpS|G3g&WIXN$MyLlwR38?9_^wFZBhB0dEnG4oP;6}2!6;hQh^y(!ACUhLMAB{I+G^%I9xZ#UFQ4oB`}u-{^J4eX^DE%a)L2AP zPebL?1rkLe4L)iA^gEj$NNRH^TY-hC#E`8yk?>>gc|PDh8ve4`z@OVRVyP;jEP7M6 z*BKF_Ld7N+`#%jj4EQAp3pip{t)e%hFSXZm-C6+yUetM=QzlSpPy;rIpC`zdCKN~v zBWrVF^Koocu{78rto*nUMVi>plZPX|G-5m?@LYIukg9$FvYu<6FP9nSxl|!m;-dD} z$HgMU$Q_bj+!v7>YsNmrhk5~QJM*kV6i2AI;q)Ozh(UgLFsp)-jit=7Q9} zuz;@qko$o530|w*EPB6yUzv+$YfwEn9eQ_fK5=u<9wgMCdI4)-9;ne`8^3UH?9eK4 zr-^9Nx$e`=80H0+=Yz!iht2i1A5~c%{HX@;r-02)0#j z$bGImyy=H2!Y*p=-Lf#mVJlw7oNGx3ZwazQ+hC)2Iu}g_ub+fv$E#3gUEJF z!l+}H?RmZqv=0CVH|$^=488Qccu6w8$m4^ze6d9%$ARHC5(JDg5p8TAA8dwcte3SY zIQTi?;(p}h_Atk1^zozXKTn+F?aWm5aM6X+AwyEL_`h=d{4wo=7H8s#NA!LD4U*-R z*NBHift0o}_Y^_hrFw5ETHWV@8j>7Q(B#DRYTw4JEQDU%#*SC9=_m)DRQb1=OA=B| zYIl_5;Y7?gZe=@gOJ*nEoL1m6l%ahF z=KWH&8&ah``!kx<)awf8eV~0;QMK`u`A5=+KX=6Iq||Eb>DD|QmZx5624f|#*w8)b zVIXalw}rk4}1&|js85^kha~skmNwzpuOYw&ZqA)Z79NmUwE8Yt4LPs z8^@W_u`<6)OYT_`?1;54IQcLGR<-fJglc#s_c22J5`YtD=DN#lpLMYxk5*(Dq-^c76%aKA1@iZdN! z5DVl_eb>>efxUfCW8Ud>EP(LQSV{h|%S%~K;8bh`{pCjdNWb@m93p@%L^;j$^|3&5 z5x5l$smhtllC&fN-HviOPl}O-gTIV@-c=kwyFq=SH2VRdj=T-**<@l3T_!kwl&dA| zMa_MAyzLql$J|VI#;qu+F-yjr>xpd}Oclf)w^&@n>`gvak7jcs4ZMufcO?m&Mu5xU z@k%`@RW9$~OnN{B?3K;Y9=+5J4NH5UHEgi7XeGdy1z7?~&Je4x(2B6#eu)rr#cl-B{4eMy?S6pR8ZiJ zZ=Blqr58?fQ&(ux2gdT+%lOmdFwSgmpDz{p`UjT*v*;^A!sR=+L<^oXg?cPKIGDBP zXD^$>{pSxB@MckJUeQgfYj^4pY5RHmHxf%kM&Bd=arTpqPsS6~?i89pl6%AO9yf$T zQHvMx07?lJv>m{@PiTyFX$|~B>cZ<5n^ZL|&Tux|9@z{}B z!~C=c@||Yf8TAR_nZS2_JHJ8HS&FYPF7k~&Lam zPEa+cF-Qq3}Sjqf3piP|9`cc27HTZF+Cfai^4`gx4GOO)xq~hd%5$7ag+_`8HKTe%woRe}&Q7 ze;jdfy4L`JonR01l&t~+!#*RZ< zS9poHupp;xcy(1c-413x*c;|Z9Z;?CCztKr3Yn^t;aQ0)h6M@A%khED1>ZNV)R;-Z zdt-yU1w*~QNyw02mfYb|2y|1v!S^~#Wwc7#X8O!nRoh)ujHq%@>VudTd)uFfEJ1b5 zCEv`9K`=oxUeXV?>Su!9P|v7(cNn#K^XE>+^ly&-cBSMXz=~#DK&8F}GF?W84S$-t zly}W#6VO@waXNBvE1oK+vvJGh@*e~`8Sji$%CmsrfRZ~0mL%*wfcQ45V3mcMAVolptQiE(W#js<95PtXlO zI(TEN+9yhQtSb5f^=4%S+2q@H2f*CacF)2iYwIfVdS6*>Pu>;Zb!F|n;>vg&wRkYU z=lYx$4~0BL_ILL+?Mzuc`9Dp%R*5r$?OgGLNx+BvX~%i&codJ{Bcgx4{-M%wM6 zy%(I3_LM}N_pRVYE~pE`vORku29ra-jl6v3P(&o(>#1ha{uUV`MiofJ_||JX0ekhf zqrU<5tvH=0+3e?AN)5pM#(MAPFWkJviTDju>xzlsu9A}er|N14J6HNPL1nMgUC$-w z;MhhFL38x>>^T|#&J{RWghja5?78rJ&StXe8Cvk5toqI^$y!3RXpQ!zhg-q+^!1p{ zyk>UY>;AfKTNxtn(~$3CGy1&&hcv>Y2prXwiUl6@7qgofABLIl3xXn*+cbia&Nk`_ ze1g^a=U8C|6|)bpvXCFE2a|Ft^1reOGrTD;aIiCV2@%KWJeI6KKm6p(BT9DYz6*mT z{AqdmtiuD8^BS0i|D_jW8tpGkh$wgt1lxvpDXwXcN=~-G-%VI__RSfwp6Rppu=SEr zvNazpeC3G1XUdxtHZRa&^kCH)9#;#>aW!vufW`4=GG+Mv6ruJG^=4V!Y@|&(J^x9z z5B%)rO{l3xmVBDB*iT1Xcv_4@;M@;)+L3V{j2-7|0p`DlBni*OXcT# z;){B0XkdJ|SoOi5f9Y*bVD#A_T&(67v1Rs@PkT-PH@eWUo2Uy(2Ef#Pj;_lk@c2KG zbX}wF9b7Eu2hEb(@l;IVcWbU19RQ6_huy9SjQYdOH>V#AA^u3A9(ZHnY-j_OAd!J@ zQ>#)#mgH_85JSJkB>8jD4>pg$o4!vTxpBmU^HW^_vdjEuehl`mc&e}e%LmKrm;?7F zeLF{l`%qw%;lXxW#7b(a?Y+zRPkFPTl9U<29T7=y^FAqK^Wf$MIi3IKJ7T)8x)g9c z#Ae#+1d!Y#^?zXj{p(O-V9xuBWl^;FTHCwV5`3U3Zn>LKY4e{8+jaUI#>`C9<-?!h zg*77Nw9?qYI{@)_Z+vnI&M3y6bwTE36v6mJEoeXY+xuf{Ru`S^7%Ko5=U{*CPYwvO zO_(;YhS@+`I~Cj=kmnBSar+7|T2cXaXE;`JDD2c;9pX2z>LOcWhAa zQ262fOU>Nj-ymP-x*e@OPrv~8R(>#L=~7a1Dfw;Xa#5g(?(6**+IQk8k>hqn59>*Y zCa36MXKH|wExgZcF#XfN-8Q~tkjaiFxE<@QE%@ap|4ndCzig+iBCABJtumb9n8Kc0 zVgt58*!i%)sV0!?04pqBMMVmpwkgw0M1uNyFdT0G=2jOf^A%}6NIvr7*U@?};QrgR zGS0)gtxBwI`-ICSeN_dop?>c6L6d5>xRbIx)uNw5DoR zb+TolT6k9P?o2g4xqiBq6^@Ky-6GBq7YN^J(VjZ9SFGT9SPwtl++sz6qZF|r`5S+h zIOW z=CN|TmeAkKsl5D}e~uPk@Bb{vDaR~Hojyy(6XIM+fP!+Je#v0?Em!^IT?{LptCY~s zBxoJhS15y+HlJ?!Yc_P!X~<1OBdOnik^vwS2Fc)Pm4RhX{i)4GnEmRm5NU{|jGhJL zVkuZ#DTrp%RM9p6_pj7_VP(U{jl;{_o~lkEy-{p)1jWv;aa4y^;m+hGFZ6!BoNC)2 zcz<9N3LZHXJo0MV&2)%9EhLdjBGpW~Po`@_8;E_Gu|Ogbo$1Fa(Wu#!+r6r*q*KhC z;BJuDBY3M<@rs01gA}h@E8~-!b_^a4+aKOGObh)v%DIlH*Tqg(hEBp0J&_ZQLawJN zKC;R#f;J7vcCYF`N*`3-KX~`(G%aYnCZ({@5~1r@Xm`wupWSgXR1}7xnoBJ8s#8{)m6{qp<6==1xjq>uk!%24PvojdoE( znoW`m2Xcc}%Xq3vXB2aRj+Rbige@nw^veK8+XbzXGGs?-g053-xu>Ch_drH${)ZJz zR`)Plj&^qR-xW%c{cLKzu(R;F)8bTW%k}$Cm3XTo-N_TK|5(f$79w^!dBRt@>O)sl zM}$21EL9Zo3k*HezIp$UF2U(apR&{J5L>b54b+5q@_&=;4(hoVrWC4{i?uFry8m;K z$jN*vtcNrdNKT#N`|3Yk78e)?lSGnAUL$GRT>{cV(Sy;wU#0B0)Ex8*cda})P70}4 zR4i53QN|!EXPz_+2CazDXVt8T56pjOJB@#2JM;2awvIFQr?FILF$3!9WocaLIdvp> zI*76en*C^n!?W5-qt$yEE{z61O>PTD?6TFg-mKRrNO0Kka4c27GBj16iT$GOD)2qrV-tJ4^N86=KSkQU7v_* zysRlsYY25&lBVi6ME?|SqD;^v=ZCo#2omT|$}<=T*1Y{cc$V+FrXFem>Rv<@Yw zA!Y4tCgK(5nS8-=PSGc+a34ml0$5*^lp`u7W6{*<>y+wXGQVw_`wPIf-G*0Y9t!E_xaZD0CD{~Yvm+WSN0 ztEMBUMNn<}pFS5|?_M#2g0#ey8g!v#g=CdXh_SzA_~lko2PJcu0>}RdX8H@<5~N!_ z6QTt+)Mfdq;o{Q&GNYviu0$aWIBUz}XlVZhEQF*72s42J|^l|y&w`UW~ zQzxn3Nf)HE`XWX3)30)0ThQxc{)9O(nOcy|q)7n?``wTJ28@r84t!YgJq5c@lRwTc9d$m(TR`T3CMe+b1_MEPI) zv^tDE5}|4m2>k@-cP(7lM>h{$+G8Xy}LX87|K0T%` zPl5gxe-61dOJCh83U(~v>DY`4ImvhuGD<8Gi-@mXgq4SLn63=L+12V1r5RJn2Xz3Z zb?J&J|1iJxZ}{X34~R*B=+K{r72n2H90^+Q@&Wj9!OMwM&vGzoA7~fLYaJDu{&#RP z6Rq2|QEH{^8_kUsy(;R@4-m7sF?3btG7tB{#?5O|cY!|Bv{`_7Osb#RH+tned0-#G zGfaMx1#DBF@&d$fHJQ)qdVKKK3=T6u;qi9TYs|R~5+FhNP~bXz)JU5Z|2iJ5|9VNr zWBfj-rJXf%e0cc$jR#)>&&5dXv4yL|v1nvS&`x~uZrY!aKA0k_87S1sH23;xb9}fh zz51CzOB`D@x$WN`%622Vgi?ovSav0wHLoyinXw82MQ6MBN{V1DeP$CbFnR!dV1%OQ z$g!f)7Qq--B6`#VFQH zf&@j~FO_DRxcX&v8fI_o|5lFfl5`}N)QixzK@Kf5`pKmHa_=q!W4aoX^ny~?u*rzH zMrx5~1Mk2v<;Uw^>89a@i`wMS^CM>N-R1t9oRmoxPz+xi13@;I9;`quGDdRi$Lkw% zJz|SoU<=A5Pj}_9=#GsQR$af79XJuEC8hERXmJS6UwTe{$8%vYCg5QDmeg*$mOs|X zQqH>%iL7`!tvHq)AVu?}{dUqgSiYu%S>Ca+G32Y)WZJT6XEzhOOhT{Yn4q%I2=t^( zYS|{s`#c$`OC$}{`rm}k63LSE=ek)g%Bl=3wZgV1wp;04gRWO`rMpW|``Zyr&C1kf z=HDPP54-eL|I1q|rAh@#@}NmILtL`ZH4W;K{KZ4t?!je?YQ4b}m`ykSndfjS26;eF znsHhBmDhro{)&@&d8p&^#O!~Q$+wbiFu$c9*|F#Xgf^JYf}0aTEbAJ49#X$0>OR+1 zS~H3WI6fi|>LzgJhuhj)gMJnYW}5u>K0KW!*E3}2p7dR50BWX&<@!Z~a*M+@=_883 zKDDREHIa-~LZr_e8A06BteJ!^k_GHEBc&leGqLQt1^39I?3LcmEmK8hPQKGH0C=23zZ00`;0swX5n_pBrXnxJhJ?{wiQG@oJ zYodx;zf&Q8;oa+EPGBoH($L{-^&w_6AWZ)k6~j z+R8Fxr?)0lJosm$F?;eQJCup;aHD#}!gu83WHmT;;>#bbz=i1+5pXaOE!l?G%Ea0L2GVDX~xH~$qk87?s^B6avC4GFb!K@gWeD~?^ zsZdD9j&?YB8tjmvrO@8yh^0uN%cJ9~HzsDjGsi^MfIwiV+{eiD?AMDe^HTGVTSxmV zB75lEnB|djNJl>sxz;B~hP3KV7f;eW2J|Dgez9zSr756QW3D@OdnQh+ap(6d@NUF@ zJtwG{@EVJZatQ59thDR3X!1V>S3n&=q#gvjzs4$4{BY)b?3TGk3V-l<9m+B1T1L_(`{&f02KNh+g`9>1&ylb> z^fUH9)8zd!Y1#;L$BK z(#Irqh#P265q2Kst{s>4-4CMD46D()WdtD7DqMQL*v~9m@95{i{Cr zRNI~;k!%c$_j_YONg>boKfh;bq(t|V-oD&n7SC8S>d0yRCN)D<4kFB^)_)NFe&*f7 zW_u~+kCJN_mB^uV1{&1GXfRD*v>(_8CSrX#GP=~K8{Iak z8zifN(jo>`4FB5bMffwgrDQa}P(x6Q%Q%Rz0~_~?gNY>*A29OHn;?wEXm8&pCT(W_ ze3dciW5HjqvgB2?G71!MY%COHOcFopZc846H2s6s zf+FIuzgmJ)@0Q?hY)4I%yFElFf&HXdArqNjwH5zLuKxaC1Y<&&Vlv53mQNM;=LJplHd2FaikToQbLA zQW)bRWl6+pB$$_!a8_D;b~R`r`(pD2sns)ZgP$zjK8;74<(W@gX=B}|qePC-O46$1 zTddN%D!&c%90j3$Su&Z&2lEb^3i=8N)=_~X$nj3w@rLxV+;8(0=*ZJH#?bfoht@kS zkJck;1t^a|yf_A5ys?$Pm}v`L2{_&_R)3r-*i?_}R~vAG>u4ur921a9yk4#SX-hv! zrpM|$(~hqe1lctn@0M5|MtBjK^)0P&TJCnBj*q+rLPh!rQ(e|;Y8$#I-^}&nT;62a zJv-W+4_MI6yxDdTK1l>susrxpgZ#ls9n^YpBR%C;UX?5T7>%$MPt(DAISlKh$5*96 zC*8E$?dnoDn;5&1dAytH;mQ4UEXE&~yCvN#vC(zBSANXDhg5>(%Ov1ytb>oJL!MFF z)8FtZK+&L8NT*_Cuu>w7>Dy zK`6w32T@X%6QGmNx0bHX(XLZw_U^$8XMD?qo1v=f<+`cKqQQjP$k^_J3vuoZuotGu zmM7T;#LDe@G>4FGbvsz3{iyYb!`HWag@dxeOq%lyymhvYSnp7hUGkvw53W9Vb@{9L z{pYZ?Z!}GNL*DUm%4fHc}Oeq;y$FT1$@qir|*I|kJxt?$jwS|Bpl`vhxP z?=ZlE@K2qzd9<@Sg;UiM!`vd0HKxPzRa$9FFEq*aK#Mk=1%1;8TdO|0c1IUC@*lyA z^&Nmh+7$(dMP2`CXpmCID4HU*Ae54avMu*TEVSKb@XuO=&H6)V{jKPDq8>xqof-T? z3`C_U$37g~o7<}Y}_QUvTSQ>*0ucEHVwa{NG2zg1)j5;Q&pYyLc|9e>o_JYtu2=Q9f< zSi?b8xZn$}-0P5~`X1vq!>p~;BYZ}2pi>lNGfD-0IJ#fHNBz13ljlsV5`6Y&fmWtw zqwzv`l#RX!Z2#uu~iKX z6GU|5MP7+)kyn3zCE*o>WqNe4fOP%JkE236Hl9$DhkE*cA}Ct7QAb#mdJ+d|rQi>^ zEjZek_JAo8%dncr;px0_>&6(S3jaf>`%kykUtjQ5%Z!K+DMb@VHN5rcn;l#p`A_i8 z*3Pe&p_gc7eN+1*1QK*#ym>Q-Da@P%XX>08$EW4S{bk!((Y<+d?}=|defF5A^Tcnf zqwA^G=6IrBxScR=V;_nv+s6M$A^~n z;p{xRDano>R$wc>-E?GzW=|EMzEItwJhd36+h!f5(uWwWB*Gre7f}dcjn`D-sATVzMSoV3T_r)vW*k4TVt;Hnv`8d)O9n;)z519 zt+8C_<*2k&mwF6%Kos&X9TIA&6fs6fH-TrFMApHi_OE@=7NxoOh-xP}>gnYX;&yuj zjzD6vd*qA2D3~JzU2|~TV2y7z7F^Rt-?VB0?{EK=XZ44*cuMnYYfXCNtDjlY=pR9vg za)TrMH&b9Bpm0LWDFQDM_iEdn3}%89rAxqw(y@oaGML9}YqXKQo%N%hZexD4RY8_( zOt=)p*#GEmD$^^h{cc%W>U`RR-Lgy^}R`oFr%+M*fN64r`!3;WYDCrPGRuU_ETQ$3eW`N*NPKtF`6^J4By zOLwdY%5T8zS#GDEhfU7`$3QuV#*E(M6kj^5w`kVz6@Vg!ea{@x$=fupX_~n|KA(f# z-&|Bukkfs3SR1e}qD!B@HejYY9&mhE{5f9S4|(w z%z?hiwY=DC(r2FbDd?C+z1_Aayi;w&wInz7_6@J>I)te+$=^GUoy~2R61Zc|T5l8X9tu-*w^lw#xS ztdc+Fi*YUUpc0TZtHfW)?N#0iy)A>*w)b@oHu)wsm`&EX?IeTNG!fjUsI=|g z183Zl5~#DYe_ox9w#$SiE+iJ53nh*WFK^V%7J?cGQs=nMlJI_d0&)f(Q|Q?jsVfIP zqhNa8F8ghExU&E1ONjja=7VO)(d)*G)DjMA91%L%Z&=K5s!>`SPG7_nYo4U#uf<%^YAO)znSZ&w5|Se4HSd}pqmc< z<-3AMzjB=;hAUpl`o!_5-Za{OE)~^BQYa~>^h%^c&Nh%XNpJs1H3Jl73s& zA2qyWxeL2K5t@j@G6{sBKAc~N6#(0z&FmYUF~EpHVj{zWUWl4x=l>aQ*&7{rpN~xX z;7(xvi2at0zl{TE4Rcju>)_RofAVwi_s@`jF(k`%g(z~f#Ib5g&AgW5Uq&6wP<3A_ zHi0e_7g_`yZhC|g*@kZ|RS_bSR;5;7kjYC6@!NJKqX1wsrxk9Qm*c}6cyV4yYCZP5 z1n5XH;o2|O!&x)3MqO~<`p`Y7%`)$lK(4?QUH@55OTN-Owi@t$En9H%VyetdJl6qA zK_{bdW`q7Avr=?kNpclyvEsc=T|^Oln+?=1s{|V#z-AJ0fMa!oK_v|GZH)ho5;W)= zRKp4+z8qfzwoyi!*KV`AL?@>OXGQyfq^|J|0jD=z8a-9xT~O3vj-TZ;h;tw?`K%N)~uHuZPgPB#XFa z_{7^!=pno(L29xbidP2j*Vb@s+6S6-ehO(9(RvoW*Hs# zm(5M+<76(uzp(%=-IhqW0W({6a{fy;Q>3SHy`q!fUZjje7|)pkNN|}koXL#CQpYwg z=601GIoFK)=Q9`XW?nPLJa%#t;9UUqeIWbIfp2>C>P`ng&&=%}?6gS>*NW{gRkp=I zTuBO69@1otK=@5xuV~^IEqj0hfZlqbegG4UGTyZ$yKhb zj-!@vD(x+~_;)_P5U;HjdrJwkS-)mJPE^*iAGNM*$#QnPJyd{xj|NzwGQ_=$FO&(& zb~|>c#E_LGb+(_1YP4jop36q7GEp=z2Ev-@x9(g!VVl?+PMLolC-~L)AvwUKKlpus z$)FWM7`d_I&pdG>9Aqr+y|U}G@9`~z;2EVmLlORbDYnkY@&G?jhl@z_$i%g{2JDYv zzAcb@eCbIM2*u;qGL>#t{a5w}G66@&Mz{}Zny%3bJhl{Q?#KeuJC`qz?q!Q3=>%>6 zI|{*!eroL7w&*6tx;pSpR7+5(?Nb^sUWkH_-qV$W=iM;U zz?!1=u68?;>zQ}gZqwaZsLMWE1Y-|mTKoJQTQkPPpKAymf7+&il?sW|6l<4|{|UZ9YvuHBXPdNRwt?k<7G^QbVE6k#0YQur(=VscVyCg@CY z04uyrSVuNB;-%Mb=k(B>c_BIPm1#}D?{HQfjX1Zf30-~HJklR$!nSU#%}XDrMC5JE z_p%-imHP`#q#9ijnAD+O0VkpY46xX?n)qd{2M3pg9ACwR`bB_oMyz9eg=YSSpKL(f*N4ZOxoxV$Up{#8rJi`}VuCIy;9M z2N^aQHJS$jxLk-f&ps&JU05H{P36u%wtHRlBuQB-e94Lp8p{`0w)j(P4g_)G#qWY| zIwL3>3T@fb!q_TChbD3a#)|vwvnzP!}emRq(BGegmis6vxnq* z59T999Lp7x?EmQ(kzV&TYyGW4kq+>*aFOSOC_BH*BfFLBgjK#<+qLN!nXGtyXoceHlPF0k62(L0~*IL2a^8WoOO4>?>wp z2|l4$beQ{znWZxNx?Z?(+c}v8fwjVy1ozJgl8S?XTK?g81PGGf?&4drT;6kub3d$N zgrpJspu|3!OLZ;qnTr-*R{nM$;abpSbFD!Kepx|U<`GmQM>_USwKgHjavX3Ic0Fmk z0CvDOY)|5hJ}$i{Nzr?&zEYB-RlsJedH3Phpcb0F?l-PPiMN$ej-iZR%7Q=Tbyam$ zg|EQ!1Mgp~*5q||h(~^%3*mLHuC7k7c*b>xng^o;u_^Oh95(kH(w|{)`+fs*v>J-M zqxW90E&EuUswXCp)9%ElVP!6#h%tXfqm2Vn0DJ6IT)jx z6W7|T-A7xwh(cKkS?lAdH1AH~OW)p0RdJYpejA86XMoOolYx`$R`|CS2cgENm1VhCT(SCE}Rr>WhJncNdX;}A_WusrjaU4%etU4n^)=KCAan}ve7r! zaRJaAYz@L-2mem3fC%-Sk{{v1hV;Qp5WHboJO}|#&g-M19@kcx>5w1Hquwdp^K&VbX~6^1F!4J z1|M2=N7-&ItUJNd>VR+tSGw7O#_G#8kbRikHdCgFnd7pr9oBNbHM&^(weoTab*ZP6 zqxt-0OIF{0*xy5vV#8x)@s)-RbKbshqhv0X0tcp^j`L z3R@(%#|3=19&fxNBVEtf{xlCFOTOsTOERguHXZRIlh3Tc3&!2kD}kZ2L&3ojJ%qOCG14;Pq6+IM9E#?FtxmYs%sLq&ADSM2`h+ zyRHddYWOTiCV3_B-OnjR&fNtL7gYTPnIC=*{nnM9*^yfNGl0r0(7KFg?@P)X>+O*@ z36ma6Z`bt#e#{i#7=vkl%97y-qo7&lskUnME5Y3_ZD$&rz^@6Y1w-nl8Ka$V1b8VY%Ng!yR%8WjXRGB^->v&vWU;5?4 zQfD&7qcs3%vjEWR$NoV>zit_EY5 z&Tn3Ey_m{u9#_-27UlX0EY2-2fT95OApHC)z?0VAfg4Gv)!~AexHEZ4T*hwTKOWAo zN*jNAwg&Q@n&Edgm7nyW82fp=206xSE$Ci{l0jVj$vGO*9OdKsU;o5<&{=pO6{76Y z%7Q41C^WjWk>)mc1AnoCJ41#+@<5-9(_lezY8-o5&B(J~G*8I5OnL`TeHX&;VD=k9 z*y;|Ty~G}T{)0mFl_`16JP3$zNjCwgw&L!&DcG(f79Z$EK%DZ$XfpisjL;%fSoVjgFX$1!#rVC ztkGc1Uis@vCPx^3w*_l8A9mTa(h5<|_0w|DkGtY48f#j)$W+|;9^vuqP_najZ}`Cf z*?HQgZVNJ@I$;hsP|-&@d=SLjSU%mM1@n8#kEhoOQda&9897bM7W_lH#%O0gUh9FE zu2E!&(n`rfK#1}yQyksiE;ZGx&y-v<)ZaLltqS0I8iCnlNnfwuT6(GCe4j;cPs?p2 z;<>Fkk}$nF0j!YT`vU-FCBvHY)sl3=@6)7QOoiM%!na9BqCiZ8)GM(lXe@j%@>B+JkZL1c&cSUL0IfYb{jv>^TR| z0Lnjh1Y!ngPgN+VTce!(8r(VDQ-{27g0M%y42WwoneR6czMqZB&Wz9mF)8t;KDNC_ zW6;eR#bQqpO9cy&A;7TLUrlcKtOdVF#bO4wtrDZ>mB6bv;U===P^Ky9t-ei9DI+=+ zZlVcAtsa=*k*>A}cC@;usV7y$b?R#{QRDoDQrp*mV*wAmi*G7xVX#V(*B0pQy_x=IYgBU%v z4P@7sfd=t82SCb)YUj2o#tKS@dF>~))&5M4)nwRU?bY`GCsWc>e7b%AIyB~0|KHrUoDw=_UrUr5-Fq%b( z52AXqT%|)*5grl+e)~K@-I4aQ33%Xo3zSt&Qk#Ri@h*Fti}RnR03!Xc1t9B$(jHOR znYqXSeHg4_s&w6bxRiq)oVdUPd4|Xk&1{L|WKGn#g1Bc;2+*Ww^AB z9dV@u2kCc!o(qKIA^D!31UHAUI@6p9e{f<(r4m9k&K`EV`oCnlXznCvMS_+5SU3+3 z%pKo?SVB4(Z%-hXQ8>#6h1chM(w%r7x>OGtP_d|o9rS}^^5GeXj?Dy;IlJH2 zl9~=~uNA7Y6bAN5csw#c|4xXq@wx}Sr0}*zx>$l6D#b3N4s3c>F}+Jj?;C8W+i+uc zNzoO7g)@7ApV|VP|M-E)cc4gH1EQsT5h--m%Px%1fQHD=BM>_r=+xpm0HL&De~p6( zbjg>#)E*9WCMqd&>!Ek;OSllF?~Cwm!bGwv9n=p}Uf$`r`oJN+pdJl6;P=Nz`^O80 zO>Qn!`2rj!qxkrM>39I$2hu?wK#~y^Xya874v1$zZIaRfgXJ{*R>jo}chkyYCzE*R z{!QWEpo6JCTr6*zB=T+80IhBq5P*(bIOF#o9}0^C`2MVJ{e3$8H1PjDG@N<@4f|yb zvo}dL*gA5EfsF8O#I!mGRa?a<0JGlr#G4MpIAJ$|HzbaIZg-e3PqHm>i{TZ6G;MY7 zNV~JgsFruq)lDCYOOQ08kj&C4+F)l0CRVb|^)9jOHvnR-WQE^OxDJ>k@BYV6+8Dj_ ziswj0#vhdZKqkCHiw6rM>F(%-b6oD)?J1BIZbEcct`6pVoaiV2g@Z`PBI5eQsP1lrLOMF@z31sBkv zps4|cwz6+>#6%TeHzkE1W?+|zkNt#^QkN~suZ9oDMz_VgqJrP0;NydCex%|k9s`(D zJJ8$yB=q_5gZb<9s&)kltIQx}0f5I<^>quNi(O*e^lk}xw&E#lTl@SV1?DZz@=vk} z#t3sANkQ1Wo_WLX2+qg?iiD5>@BpF}-2m7^XLKihXaAD!(XTSy7E?Gn3$p2he)2%| z_{I&;ltWXUYqB5P_r&6$e}&|TBJVi#-$D=#Bm&{}HV~CG0 zyKsYp?Y4yOeZp}Xgeh>IbS8if$HUO@OchiWWNDu(JtM~{6d!L3HPaoB-?aip0H_l$ z+%!6v17f2>8s(=z&j;XSbdh#0T89tY)yCx8wWK&Nq#%R7DDMQh{(&jnp8CA?p7LH` zUlguuTuE1SgV6q~vOpVXntc zT9OHG9#n~-8?ub+kbu-S2^^)i_o^GDIhReCPx3BJ=9&%3I}r7g>f(oiwi5rQEsr-X z2iSS(K06R_6g6U6U4vns>M7m3ZSxkxLc z8D(}kO;m?N=0cEfh_yYFwpuT;rac)pwnJVZtDgd#p=Ln7#4~_@U*A;yk~*b$iAiGT zV57HCi>PXYefk*G+)X-2{NQl+QsCgwNE;d_~YXXLz$w-BfKUkjN?0DZ{IUZQE!xjie@HcUVU()%%AR zAz}7SdrbuaK7?VxvHS)IAaypsTf%$j`!BU!*?er@|A@GtrQUPV{;Qn38lk0r;YIx_ z+63lqx;w{PuE&Z3^|fxt1!wnnh&>~uo^(i&cJ zH2QR=&n(IDePgiWc~UxgDus{l&Cn-e6rB3&iyBf65%h;~8NwQ)o(mBq4dOt3aW3Hv zb134kx%sLha=dP!d2$D@v2s?&S#M2vquhW#h3;YN+a9i(ZiD9LUbpo4;mUc>qqH87B&7MvG-`n0Oa?lCpLwMo~ zQc!rDXY|zjnD?g0+)(JgL&ACe%5~yE-d8JC1Dcrmdq*JcRkXOaDBZXH1nAxLfE-qb z1t_i$lxtO$+ZFbjkvpKMIXqkmkbbDchs3>?zwfX3}Xv;;6(? z1RkmMre#P=ifm9yfnRYFV3K&0Cf*x;lWi!PVkw}*?E5rc2@E#T#bc!~LR=b#9r-Zs zXuuFCtMC*lQW{?~bL`yQ@!{2V%|CqpfbXx4N?b*dR9c^O0FZ;-uVys(3YvMVVz11d zpS<-;szauhXS?w#w9Cn9cfGpq7)&s0^_l}W7Ib)g#^bqyLR&3i=esY38+7VN;YLrs z-|NK&0Ko&5adKt`<$XFg3%>jbYR~Z_02=MY9Pf~!B>Nf@Ruq7>WE@pnB$Gk=X5hJ3 zz!GLcrMC-)I@+oY08j?4Mr8(&2Og`qx&sX<9FeZ!6@khrvY1nm%e)@9 zXn8CqDHz@e+wbo}13nvt|7eP(yFZ9bOEhYAF)Rs4L!9$v&?n;IwU-yjq8Xr`x&`Vo z3x+^b@oS`UONg1WuPSthRf(l|ydknZJXi6u?wp9T2Ct@ZgMGUjaClPH zF8iyKHV8nE#W~kt`WZFZP;=0U0)(e9-3#8pa4BjR=hqrVucX2O^X$4u`=0;g-6uvUHt~Nm5|Nai2US6PEE$t9lZMB zC%HeqBN}DdD=e>98@Y*bSNN^Q6>R$f$(cW>E}|mQ0ycp+z(D$61z*1c9G0el{>eyv{HHD4wdNpvcfBf1!ThN2n?_4%jTUfoMx+v`1t@mHL!HiiY z=D*qxOHWY;!}QdS&#IZfW-lJjZ3>u?a}<=8Vu41r-LP>zpi&-$rlRGsyxtJ~_sKwk2jrbk_uDSq9bV~&;p z!g_Vu_=T4}>nM=$imoY%*wFF;dh`K^f#?l0tt@ta?*raAw^Cdu3%Jc`(u4fHZ#&p&}8qeuGK zZ?EOiBy^Nj&#Ay$G?%o99FN;I^O`KZhz##~j@vm~8|V6+Y5cd!Nm( ze8p4GhRh!&iVt)BFm)c0HA?-G@I-yq!4+v!uSrYi&rLMTX863DF^Hc1v(9WcSC{CM zU-#gGqK4!^K?4v_ofq-_e1VPn9jZ!9KDTbusmiV1qg@5Hd-g4HfN_9oCD3KL(*_*8 zM3&lU^UKg4L%_Kd7iQ3z>*VqCHhcqma35&#W{!Ya^XgPHfaawY_g^^viZ^PH<~?1^8Os)S~SA~eF|_v+ygo#;=i!~O>o263upkVT&^jY<@?fi z&(I#QS3|2#%Mpm#o2r}d_WisrS=u%7PEQNf%)$d2wAFZ z${A2J7k&Q#pj@#+AMcE2pa;Id ztaDm!)q8B-jyZDQRtIN*h|U`5JNO(2iz0nI9q?2En`%{#CAAv)PE^En7 zz9Mwo(?V(AvbXV-bpXy@0`rhMvGIrpXcsW>pgukSqrys*UN?|tu$#67i+D6D6;yF)QSNph z!mF(?%oj9ji=pblx+-sFnFkH^oU@YN?%5-%d76gXQc6BbsG>~DBPT6{Myd&}^nc5B z<<`&DS5nH}kA}93SHKA$H7fiVNT1zy!Cxz9*fx5tr7xPVwzKD^zV^1AKyN)yv;gYO zqY}K$0%DL}zvRJ|M0>dG$~=ggVgL@sG_PJ3U&1S4<4`xdCsAJ0rQ(TW#)0sg(8&_xJ?fy} zZ^0N6$W@=VMx9gwR(w$#rSd%Tx9Ie55K%vL`yDpboXmMm^|8U=(k4S{pVHXd43l0F zt3QU+%STId_H6Us)h=3PRtvtY*H-T9kNPVyHqM*RN6NQ@X$jX%X(`Csq(-LYi<(}M z&LpFURpOSNo*lwD*lYCP`mHLkp<=j`+34Ae8xIm|@cs#beT#Jqh?1@^0ie7FhEf*F zk6nH|KN%HIEL^2#29AV%rTE_$FLTTdz(aRH2&tIqJ?R5xEYCbzEQF)#Nrzvr?|Dhf z{=)lkvH;X`4br$!duiZ+d}1tT&ZjB&&539g8yJT zy%*A9!U~KjwzGHr6j3Hm)N>l6#zGyH4%Owb3?x<9|KP@v1o`d<=!Ee`oy&i0sJ-^! zQ>llTyNkc^8q@NunANWKRf@eQJ7QDr;D)_7QjdUv?i>Gkqqx=B)zjC4G$<_AdO1ZR zTRtDbS$5~^!LRu1L=DkJ!{Exz@e_|GgF*vd(sGJhLLW@XgLobRc`=ZZJsFjrjn{1i zs1$gE?~C3Y6ff3qsTEqFqBli>3(M{&FfoGh5QgH=__t{4TulvpKn&hA*n!)CATpV6 zhNKG^!9@Z!8ska>;A#Ns4T?q1N~>Rs?|OxR?FeURi0zIT)+wa?@LwG)Mi#I6OCzP{ zR;MP<7wNp5D%=}3lX^7v0fzRvJEA@-FZk&)=QD5%xVS!_d$8LvOegs;AH@yk6cs`w**zS?2JJt`tMOXZp7-fF|_%#$@ z%5UIq?QLOw`&C$De}J*G8$`1g7q4M_ie|+Zm{d;3)zd$r>^eU+lAF_jaY6HMAP;n> zeZOPhmjzH_1_0>-DbgL_i1Zx9iflHbv!Mi+?`CObN+}M6c2!ulEq|Dfw#)FD>&uqA zap#9yCwKS!nNe5rAO!n_wtDs@#QZlfGO6N0Ib}x;GS(a)B7`U2e!qk&1T1Q)%OktAM z6>CY;BA6wP!ETJiB0NCYOD1i1m|u*@3*W8*CxYyuWIiYMZ_YJz(HzN=TBm+v2z)KC zE+qPN`Ru7}X9=+FOhz{A1XPr1zB@ekDpBtAgK+Rc$C*2NUw+^I6E(igv`{pIOSm0F zQtf8Sr_jKD^25Y{xakw>o`1a;=SG9HZ=9tfFe!HA$>EV3Oz$CG|9ABgcKls0UlO>B zRHSz#(Q;&Kp%FM&wHNs{s=DO%H*Q37&-|I(M&&Oq>iy$N9GYD(64#M_yP1$B!p2DT@T2()y^Pu26GaM8+q+70UoJ|**@ejha`IS-tR<|Z=LGvre1udT&A)qZUoObu$o8}`p+<_C zvW{>9p-qu@62D-*{>UQzC3D2Gw$aN%{W8Ue6CqGn-VR_{w0X%<>EWoI(>ozx#Aq=x zX^#D0EvQ=1zyE2?V+-0Os7og|`jk4#m7FG`M;pWsW~_Yiriw{F3%^ZP zf~nm9=yD9`dvBSl5u;%II56(4x~zbYhUsPCj)uxT***H{DOfd@v%N@b84nWR6~G^J(z?@n_eYZ@7X-=wh# zZ`XjksUD&0S&Egg+b=@xwUkq>J ze^6ZXqrL-eTtabTHXPI&>YJKuS?(LZaV7+^D7Ud2<~+T%DEV5YiBY?$uFTnRr0Cxa zr~bvB!zq2`A45LQpd95BYaXjz?ztLflYR#gL>5}kaB46j z@zDS6A@c~?#)FQN?LW+dc=5x8X8UB_hQf!mNu1FL@g z74iFz+$7Uli;fGs@uDb+XFYa_bD+Zcw-kJ?8B>xR16*Sn2`mdokpJc!e4)zSS$^!) zIads!V7(K5#1~4oEqpHl7$5*%Y&{nJ(0zAPNa&3}{X)a%C-_?&oh2RrYi2B}yn#4R zF|_LR0>?3{oL;5GOzED2wnyS7jX;s{yLrkfhV1mDv2hMFB+QC012!CA^N|oO(i1P& zhqfv8|A}pS`wvTfsLCe5UOF{aTbIAB!^oR-HR{B9rvC@bUcu8=3x0YjUMbT%Gl-_8 z$XuJ@xcj~j=N{%OUBpyLRr$5X_5FMGWZalBN!v?JPf1(r-ab z+0z+0&x|>Zl~x7{)sH?v17|}=&MoLFC7tZh0lauHOy%0XC%okPv_aUW6+;>uQ z_fy8|;Ug@g(a11keGTa!o87zZLidHzN^No~cfN25E$ zrVid^oO`wNx(t8J896*E({}ijU0O9^#!^ik+WGOglPdu8dFDC+r zVza2$D#W7jps#;y`Iq70+~Mf2Reu{vl{I`EE%gi@b+`8Jru`62~Y-RP6|J$cV)@xB38HlfHD?{*>cj7=|MCAL?Y+aAOuM!3nQ;^wqQeN%RTL}~rAp1% zKv9f}fPfGc=_S%jNTQ-5(o}jV5fP9Ysi7tU0#ZT|A@ooaAdmoQgtYH=Wm!uHX3|^j|nY|D}`|r`>A?ppXCN|Ju1aj{Hjth>*Psxahsm zMGEc^`d3-ND^x4>!7CD00i)>xMX)sNhKG2KMkV-vMoQ719fDjND*c!&BIzA|HSnA5C8o5#*b^mng0ihRP`KTv)`ugkVEcg z8*jqWPH5%u#TRZ_cfM@ArK{@xYg~o$b6h1%Ri_n8TDpyB96VqN3T|?rFRDy&;$W*}RhTge{Oaz}@>B5yaf*$&$jo{1-y8SJFDg z4EN8$6`wU!!adyLB?=NRNU??jvEjMXgTYXDbSXE_1QemO`yt0c5$1X}4LUB29Y zi?4W)JWy$){4W|}nF4^q*SePbs}jHvLTIBCM)Z8~Q`?rev7Ct!|XymWRHv{@EAhl_*{PORHn} zyqO;sMFl_CAN25O@ylA9Y|?reCw6H>&rivcF~hX(F)snQWlu4K)Wy92GOjUJ2h_&@ z#A<~hc`g1WQCe#hOzyqK&!FuPz`epOs^f2=WPKrdH69m#D9d{*1Rwp7CPAILsC46h zz#y(y+dloV_=XK!PSys_3L7o22UF9Y;k>g>d@PNLVnCcP67Adey;!LqYHpqUml0vi!7%d0|ya}I0HVBvdyIxsgE?cLf|k5u5S=q2sbcIXTq--h^#u1F$?^`ElS0rt3fUs49lcXE)F@%hNwz%jwu} z6QHxdA^VUS8XfzrKZu!mg!#4u4PS|-yxc3p#3&g^n<=kZ_2JC`aUh@*MzwI+4uzMi5_<+@g-g}LB{4~MHx4Z8I-ZfzL_qZ{WsRpsMo zWIU2b94aO{ZH`LRR98PW87g|C@7CAEn=&VB-o2jc4GbsxeR~R9H4Re*cuY?3lx z#^zpabrr>QQI&J7fwfF&UDB5aMjL|PdSLp747-VAO?fu}7x@1$zey_Y)|2`-Y06ol z^V^1VliNS-OTf)DnFzq+^njPxH8w{7|92ouRv%{i1C+crl8{6~!yd>2ySD8_+khc} z)_v32$lY_Ycq+U@02I(s?>?p1>PFN9gspa0-3=&ywH7eZTG8<^7O6PaAt{vXF_h&#fePUdyfIEEW z+u|+dc3<6>!g2qeMVD^d#xtzsaUu5?LTQyoSfkI_M@XjL-vX<8`3&t>ZBPLFC<$xS?Iv76CTK^X<>5XMX#M-3031 zgC*u3#Iu1#`M1iUtb$(=q)Dh0)x_(%mxJ<*7+T^^LtPxq(K_4gK%BRDHh?<_wGWE3 z@h#1?Z-AFJT=2?f$Evl#!D2o&z;EoXMka+^vK`(J`65&OY}6vDO*8CqH(x z`<92iAX#SvM*5G?k#r*-d-Yl`M1*L~#FG26wV}YqFgy4k&)+qAcZ0l+ZEGPgIDT|{ z--qjA>qBu03LUuBegS(lPRQMotHd;thbh_U;rf^&z~KoM|I{+$6tC-be?xg0Q@PPJ zyCAt$`uT2y^;%`DA~tV;`F5qWZcka$I=T-WmhNg2rBI>yngRSBz%B18X)7m|L0XOBkqi-+E5+#=>A_+@8;Dz<27y$y8jhfz~J@wr`gzz z1%9p0nc5Ruzr(>H!QN>1;6HQg)Qx&J&GWw)BA7{Y{((pnlyXnM{N4|$KevF zGphtW?~%`s-_8}U0gy3=2497Z?9b4U(f)f)xz3VBPfj&vqRus)fK`3~_-T)C?FA+% z&mUDN*+>{-yI%Wg4;Ahc9$B^2Xy903U*mmw76VM>1;vkNx*hVVEWBcqH(wpm))g3k zVuh% z#pgTpWm7j|o(~^NGda1K^32U`xVJl5M!WWpZLCwlx3B!ga~sUhB(|j=11y00)30Jl zzL{Lg@QO}X*u�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�YY`+%o{}=&w@NEUrs))5d&yu{?CCFuw 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î#wU~F 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 z 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 z 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

w8xKS#y^m*2w{ov!o-YvJ>C=CUKt(aPC9W1 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�-tRud3p&l6vFTt;aB8~aCNehT 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%0DgcyZo(v9DZ^b{JM#!$zjX+Og>^Fp9+| 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 literal 0 HcmV?d00001 diff --git a/assets/demo-acp.mp4 b/assets/demo-acp.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..b5a67deaec424fe2849f82460d49fe28b5678d23 GIT binary patch literal 4675786 zcmZs?1zc54*EhWBRO#*x>5vvl>FzE8rMpWSr5glEk&^CC=~haR?vw`M8?Nhqe((J~ z@4NBOTC-+m_3X1foC84+#Tyq-2Ww}0TL^-M9w`8)iJKXRtphg)1ffOQ+S|K95M*QP zW@QfOe_e3f5G4K+f`K0Y{h#aqHvr=QH5UCpEB{{{ECiv}xj31;1C#nL@BXm~_g@SD zqYc>o-`D@L^Z&Ao6aYc+eE)2uu`qXW1{{fnjkC*tQ~?eD(ff}sR90JaYZEX>VQc=s zV;2I7upo_|e|EB1ncF!1M+f9)ZEo>D{3F!_WBb=8cIGw~k84ooY_09y00zg+_8+DH z?KX}1zjGw!P8N@A9EG;9%&I_-fFJ^Amwz(2WFa!7j z06qX<2TlaYfF0Ntzylj_(tzIvdVybXykI{C&;xRh6bXC+HpuQFh~^A}SVzGe@C)H_ z?@s`r69)JJlK=p6i3D^ZfQE)m0%H&Z4A=_;`T@op$dUnQ0pA2D@Z+C79)Q~Z3)l%@ z8{`va4ImA`6|7SR6!gYF{8vD)0ZM>89MCX;U;vPJm;kUB)E{OGpc~8+0q6ie1yGRx zfAW>}Z=5hUKn`@k!~z5YfEpl3fw&&^27xii0}O}*#uLEqU%=LYITrvzFa|k;0lHur z0e$oh+!0_O^N9)I1>go`tpL%0=LR$m&V80e=Nh08j|eKGwM&;8Eve%wa$-0BAg* z&j39J0DbnDmw)v80=pNWA2vZBErPxTIe^~+yfomkAqWHHnXnpyB$psa1nkw22LL_l zU;#l=LO=%kfCsG6M~5IWaP9>_kMLpvxe}0r`fw*e5Z`ME(gk&S1#15am0v$l(ioFcyR$wocIFJHXF3 z5Cj1|$kQMWO%N04dl+N@ejo?&L!h=$C>Vn}!5{#>0|4Y4Y6b`Z2mx`T0X>!=Kb&9< zJCHr*hZWGzKqLw7C)OY*2Vg!A$X5Xx0D#YrX9dOv*nR8)FTg+cL?(b4z+?T50YJXs zKyF}V0sq(!4ggL7X#j=*$^hTMJPn{AcQ9Q5!0*S}!p;GJ-2HP#?tvcQHw?%DJS^aW z-bWp%z$c`~8v6jS0X&{l&`U5@fPd^EkbfAEZ&+MFA9J7s_(cFRz=PVsu>g7v@TlYQ z++YLV6VQABe}Kol-~oX8{nM*TfCl|X4)Oxm4S3)i3|Rk|f7nR?N5DS=v<%2||IIJb zHjrU~aVnsuU@i$D1E2!PS^ysHF9Ey)JlGHW9RTS5Cl8N)$pIetgZviMLkNQ0LG4K+ zK`-q?5H0ZOIjB3&dkE5g37!EE!TlWtf_!_y8n6zO2IAp?ASQ4QlrTZx0((v(5bO|$ z!vy5i6r7hgix71E2lONZcv%BElL7wHf_TW%L7xpkPy?t((*y)rgWl8}1m^)BteJu! z<_{1=0cxQ78>ANGmj43uEbucB^p_%tpA*!TksrL)f!N7G4iVQt9KcuT7pNQPEqGw> z@jSvMf*7d*?+0XO5aikoLBv4s2e3C1^vf>jIT^5S7sRU`4oai~!KgDqFiOCe_w^8r zSSSR;I}5>(jzKVt$qDPQ!vlO*Cj~Jffq39Ryj>tS$l$dR^a(B@ z@OcY>8^i?i0fP=G@Cj-H0P#NFXP`MifgNZ8pcbGGjQaqD0UrV42K9nb1$;1|t$@-v zyO`Mn`gkFL*W+dg1FZrg-$;d6+h8H#I8Z0Z#MRsd^fjboYw-_#Tub@iPln)W(#gcZ z!RB$|f3D}&|2}@we08yZG(ci*^3P_N#|82xZf|(mS-Ds_*xA7l`Hho>1thJ2ZwnTI z@&ENa24wL6JdlAdL`2|})|6e;mluDTc+`t2G$CFDbizR}AYE_}94w4dWdOL#{4)Z- zgV5n3XkeZ^fGYrkK335-P#`@V2XkWIzq2ptINz}`l%4sZCDQTif-W_UdtzrV@Jij; zzIL!!!@o??Z8f^O)#a?%-dw%&vwqyu*gKDt-%q*?cJ39hNVSt+v0a-dp==_NNk<6H z8;6C%Ft_=8k6l}JWf@$>1h+`-718&nRLSIBJjvF8j=l^niZtLoLzv*1e-T0}oSl3e z6tHt9cwEHaD~h|~rI1_M(jS3qAF_FEERoZmj@3sxa;h`7@{FLzr`!|xMjb0Uk^ZW>-WQh+Y)Nt zZ}P%{-1L&3-WuKfY`MX~GoGPTgsx^OX@!M)AL zFZC^7Y7_Bd*l)wpDlHH_sx2{8%6EUh!I>dw%gZ3@`(5u?TO+M@>cSwqKfUnFpE`^~ zhfQ)@mBx}d0zJ!g#99tEk!$6R8xg8PnR&qwK`?! zv$Z2%1jz=pBITYo{0OB&pW3^i!k3y!?#(Qcy|PaZe(H;Q#R=~j+y=PgcPP?w=Bie2 zOAl7Dt|awlJ)aqcsQ5d5k&+`C`3K68U zJ5{6UwDcs)p_f?G#rL5rg=JCVjvtu{VhDbMD`mCVAe+LV6oOlN53Zd`60 zB04qvlC|HZ4o~%rYd(sL42gIWW1iibRK>m}E7COH@jl0vvgiJT1gyN2lOX?_9h(@( z;AYkEN-d0Df71s|^XUR`#zP#oEbzq0Pc~p%wamG5&3OjcxhZl^;MU+Aj`?| zV-P#7iO1yP*G+vsH(B&XBFp6(gTqvx6uFUSbV8z@=}UssaCi0S9TZccG;)4A_MTmi z=w+qW;nCb#%nGT~FRin+;oa(LftClQH+m=JtyWi74HPUIRq!Sftm~^QsF(UHSI5(@ z@~7Dy9sTOR_S;?^w-UZNWwGA;@?tw9vhVit$L@1iu0l*4lKFMdfeZwZ83Ha_hMgZ5g0cO4Y{oZ2a~2&p>I zN*T9{?c?%=$?3^-;d~mK@Au*^?>5Kpq2)nv1noESbUz&GIce*u@<|iNs@avkmEZ zro;8byPJsxzIEO9E_8~LvpJUpSLIOJ`5s)_r~(t9{e(E`qM!3G1VjQp)ewI+{<(mOSy zYI56&Dz+9PvOM0NA-3ZS*cX4g$Px^5ML%O%ixzetq18Moo!}ZL4^1GHXykwWCztRv zkh}j_uqKPUZMkI(=e8y8H!{+*Uq*7|SmIBL;ZaDz3DoLVNLpX}0-U`0BKJ z&8g;(-l?V2(YOw6>Cl4$WXcNfz9JkVhAzA8{3Uj16p3ZzaEusKW_8VZ_=&oa8V!;fxou(|=AkUFe(&ccHFj zng-X;?$48N*h=6qMU)wT1oeh;;T zacg1dyJqkgd_riGgg0sk-zPVJHWc$C%7lyI)ORF;yX&u+DK>)dSo-H*H^RSkVBHq> zw~U$0*7U+7_<0$PDq4W#&d@;ijOjOl4F+XKq{DB_5bd-_n zFt@y&=S(-x?e$w@PK&0Mo{JyD{Z>l|)^F?EE^M_v&O&QFfo~`AL=hcc7ZdK2LUg5> z_cFS~mrPXmsNTAJv-w7UR(K`)<@_YuJL}kyBdOm!`R`hzWC=vk8Qh*R|Gq%?OKc%o zq3(dTqg$NzUx#^)zNvJ#ga5%uPB8Hy0{4e6){OUWna(+y{mr}`^&@`lM)X7VD!%#g z5yX0j!{kvJ>IZ||z_fLuj?DM>%PH208##0Xol+~WB`7~nu8i>_tsvdAt;kC!mH)6K z(BRvqFSN$3V5mKEEpakQ8KZ*=sV609e_=~h_ifw?*oQ_tePW*&KD43xcxLuLk6+~G z!VJeO^~8M0Y5sof=#lb&QvQBg&1ZdR{%yv@sAu%BY3Y*a;MQayO=f7Rz@tXs5&tI-W53Be-wt_|g)FUXybK{$1%GpCgP~lPr{v z(Qt2^(U}xDlCW`mLth~tQ(=BW5G!Lu;fotxoN!IMY1_;G>_!|BMGo_u- z)1`bv@!F!@{_|~_f9%z?u=YHI-78CsbE9Y&*2JA7oKhx%4!sq#ij`1oeae8r!nz8$ z>{L<_wHWKFCF7wS!OzGK^>d`0{AfJgiF}Yk46MxM!Kw7a<*Kou=N!u$CF=G5S9f&G zDV4^9CI>3%l^pdYdYk(zVg8I3Chy=m^uwRLe@K6q8Ur6x7)9%D_E(AElV)sg{YMks zuaYuFLhnb>eh;5a2DWbyt1u*XI%{$dJJ3r|e08kWX!T-3&c~|SW_!~+G03oA3yUc7 zeh-5I=EXKbHeYtgrhHAw8@wglc-KLew|M^OMdEA282-&WL!p=FPltk&-&WZy=fds8ARX)Lg|2mm_twwnhL`q}LAK6_8rTgF`}c%&Y~Ih_MrJlo z$-_@Ts-7tv+aGYL10Liy{gReXqDs*%nZ`~A;)&%0tpnDd%4^LXWq0c-#`~B#pV%49 z2nlZUeH|~g=`_vy*hVh?{5Jj)QQ6hb1vi{Wl9J$02w`)*!Ul|1=d;7cIXw#ZgAylF zbuI4yOSgz&bC{FZFTzz?eV(`%SG(LDtUV8YFZkUD<%a01X|Po$=3!nEQpP&N zwrePv_#ZO+CAX|6yi8sABbsvuMYaNsR()3LBaDC8ZCcM_xKI#y{UykGGS{2!Gqs+M zgqBdw_S2G#x^MS-;f1rU5`8B6xHh!nfPPKBMya_E$UpGKF8b2oev>0W| zXSsvUJV8999?zkPhC?+n-OXo%;U8=CHzO_2Vl+d4Vm)a$wH)<1LSC-bpPK0>6J=9fi>`T|*eOaRFyaM= zDCWO3r#?7+zfuM_K#A|yh*!)HEiP~>@NPcx*kSFdLn7|-fpA4X1WLs-Z`bO&xhr&Q zo>P`*9BT-uNtyqZvkw`T*OiEpt78ZZS1O{x9ktgqDymj_7PdhGZESuVx{_}Z$-66x zBUI>k_r7u1OGnbW{dOT5Inx@(mdkbKOD7FVV~Go<%SrK97BXXwetfSP_~g*F--PQr z$FBOP*_`)8W~^h7!Km9+$k#k zK2oH^c<>+Sqo73NUz>=+Dt|>cXC!zUaIx6a)3n?;e5{Ex@8Q_HYUbF6gZN4}^z`vv zO*ja*Z+3CGlPUk=?uLAn*+tGAT~`zRfe?i+2UT4w^5szEeMzHnrNqjfb+}37w5P>e zKZ{I>=;b3arxt;v*=ZwE)hwBP)4(SJ`D(m_9nQWpf?B$cH3Uy&!%*9OevudMr^~_} ze|#(N0{0^zPK2Q@Ei+k4aw8)a?VV&)9+o(Ta))-rNp; zo4|}(;b_&i?vu%sQiF#@ZP6Y*NlTKZT+z|2er|j-PqeltZ&g@J6>XaOb=2~&x6~6} z_`EdCL3?S>@!kluf}f@123Td*PG4@`a`N$Ezs*G5-Qzq}CfM+pK5K-PzdoWSd21&B z5?vqRBHVzTid6B*C0xErKg)|v>I3{2l}?*JFIA-SSi^@PEk`}^Y8*29xuVG&FQDL*ae z36EYi)wjyl`fvQseqG^URQ{28P9^&;yB@krY(X|1K&(+z0)H!G>!oU4TBA$DrgdpP zUUa07$slZWhV}xA*Y5w68MYx&_R?BFsDp~}Oa{m!t{#|c{GNP40bN^vM zRNQ;t5R*qu=Lbh>k7#tz$Ano2l6W2@PXyD%LgQujiwx2mT5^t*U4kPlu9v=~x14Af z#}B#sENXrJ<1_XgeBssP^Y@xHhYLHMNyGOMZE6bi_mxax<*KYl4-bkBPICvANpbw= zW4ih5X6MF*jZcqkcUk_zJ1Z!~?KnlZ9mDqUKSfR}*X>C7aX!1C_NC#eXY=7^=DyL` z+y?WYIm`U_mWT|mLT%%c^aJqTEGb82<%gZz)pL`8w)evDQHnz}Qt}DOly=L+|*)RRU=#Du1 zt*!otV-f(KRa#HStUI(g>J05PK$$+=#0eZ-Ibwk>$WL1jr~J#kAPP& zX`E}%)U;$`VEdhHiGsF$SDH;8rBFX*V|+FZoFTnG7U7e4g(3;wc2(~_p#zH9DU52( z&EfL?6;+7?jA>T57Zj8*mS;tDk^%CjrS$D)+nJSI5ls9Q$&p!D77J5MzKHkP0}ZFv zq&zN}J)2M-UM9Vq5;d1%Fn`&%QgM7oUdqY#=tBpjrqJ8c6$1XK==WRlqAn(phJE(F z`Wi##PTm@bFB2&8Jll32FrSawc73G)Y8=ln);a7@i zH9l-(1}6B@yNo1q9rrn>HP!}dK~8V?9Y$QYh<9Bli1mA>xf<~47xBG3Y@JgUnm^ci zF>XEtTXRgRF5{eu{6evHq-)YRe)}3zquTE~uZUt7P4vo*nOIb#9r|v?0Y&2W#{isN8V=Cj-(r2>y;5O(YVF|49{1B!sN`1UvkPx9 z2bpb5@$!A($Mm*p2K)m@H!S0JUW-mWLr04_w6MFxOzLr_i1UJtOPE06gk?nQDb)V8 z&$@Wj+?=}owwtq0DwC?u4|+HFa`fok^xuCI^MV4Du$A8l*7%|QCzj>Rgw?E<`R6ksx=nhQWt>9ae-3dT2k81|8-MSj zq~83AlaO*XcYW?kpujyJBxv6D$}nYbl;mMzm@C@iZ%^ zXd|&9mM3~o9ty@C>QGlDQ_UScVJ;qsP$%Qc;eQ5S!-XC`?oLRrGClw;X2<^y|mLzLT2qSNrC_CedZSn4-eZUI(C-G$5R=N=M8etlZ1eM3N+%{C%$Ae9_b zHJdBOc+fyXy5jXm?paZf+>6XF6o*ZN=2@C8r;Bj5@NM6=+VEUL0{R5#2E@h1MTvQ( ze5m=yD5`(BAT}<3;PtIULTj_QUGP+;7ZvrXE5Vl;-yLv~REs}GWVw+$m2Pg(v)C7> z*Vbe_8m8B<6lxo!GVCE4y24H`37PQGt7fu68>!{}f@YVaxX85?xmzHR)oCNiH=^zL zTfP{lAW6)`>hpu6wyL2f%|-scVEJKJn21lfW-zLM)e>8KphlwcQyXGlQPRU-z}) zCZ!NJ>|V6Qm2W0Hi*HloNBHH3`&m>2X0*JiD& zE4)%;xHESljD6S0);_eiRvYi5s0f;mCH?mh%q#AxAE+qlHbv0YQMs8dJ1BMgQAi(l754F8<7Nkq=?&uxh-R7gzFrbW3HYEF z<2b#**9R-yh+FB;o{~5=@;i$y(x>?~^I-fQj+sb(i;$182YP+RNvobx6@9-g!I~iI z@~$n}JIVa`#lqC1U&A7fWr6g2zf}jeGdCsG=mopT9OoK|46pp()EB8f*uo&9bC}S= z+Uf_yYIKPDskG(DGOxQCTsBg~cIdV0g;;bDci1qHsH~kZzlQY7Bjs!yA`%z+O*Mt{ z^;P1C&=exAtlQvzxL~}8y}^5O_UXH z!+eY^PO7g?nR)1|hx+_4mqKAP{96fGbysJYtT*!{YTc{ekDH~jvxz#wUSNxETKZ|` zIZa%*ee&79R-Y+wSPHZmLwKpBIs4#(OBv1lbZpcgh)Ju6ev`m0{t6*qnWn=mxB2?8 zQkaunZ4-Z%CMAe?x#tS=acl~{*ttfsHrzpqL6Cidk32#=M4iz{e5R6e%{Asn^j%r^ zFQ3wH)pQBFoYDS?zO(ZP)sbxX9jo=|{b+1h;Yb^~y+;%#lU#8yN9qocSf|7MmC|eXNygkV7jW$o+weTQH^Y2 zjgWKW4JGST{-uf?3skR{?V&$JND)h*>)km2IhDfZ)g-vii}ha1N#bdnj{1dzz3zze z?cSo)Jgyi$w?r`V`GyK(c{1u#Jmu^XIOld_i(BE(3Cr!a3QyeB3~AOS>%SZ5N|?19 zB(*}--Z%5=(J+=eJ81HWQob+x|BxyZo^>EHKbKbfA{a(UjfK>%-G9f87Q^%m2}VKr)k%KNaZ3@MUN-MK1Aguc5i5uvl0d) zHl%6HCS_TD)b(%rILyk?HN%i52dI_yWXIPL%74E6A!bT%EiS5+c=~ILc_qtc-TzyU zB})Ox2h}k|p`miU4@DgVrGk-f(u-T(qFb$f;m-2bX%=DRZ-)hqtB^#03#u@TaVf`QF@5G4uv^~r z@1!T~)rAd1TQv%4CS=%28MPlLi@AEktmm2XJ>BBLL3?)cTUh_T$@!v^-|pKnwf^;{ z)r6RvO6S8s8uRoq0fJV3IY=#~?S(lLPGlzdD=!>`$&R7J{F<=MeeJu7|3i%+C$6jU z%XJHGoXy|bR#*W(0?F<3Y4YsXZdK)?1BTB&;oCG%g}a}PJ11bWx9{rqcxtu9A6|uu zx;+Vq3`HWN+eK^*)ET00L&8ajXnK!zy(rn$d}nYIt~Zp{tPs(`x$|R!FKYK)M8Bdf z#|ORIPFXCz*8UHP!R4v!{BPTJ_7syh#yCz%jLR~m%}8?hrscU%blE=j_&t4C)W2NP z!-E!{C@HL9w5b&<8m4oH9A}xx9;C3Z`Ce@2(&aoa6dZ%f>*O!RdzWSL9>jgqi zuC7v>^fQX+i`;gtZ-`_$H1U00DI6OtCA7CEmn;5pA4@M3`>|?n7SdO#UdolJK#Fyp zsA0Y1*H}CE{=ZXLX;R0YnKEmB=MN)eWd4RRXOf=5eLwa5GLI}W9xZw3`H_@#&Q5!^ zBl(A7@3ACI)Y^*4yoz)Ad$s+lamVJpfA~edG z=J-ZAIhFNB7b3z&=$oDtD`s8c=4zC6r1hFbF19brB|$1B#CxORs&<`U^32>)qt2d} z+*xQ9)mPuiac#-|j!6R>Z)@$LJ}XD#Vmr$sdhyP9!BVl3#KnhacgurB<_SsEeR|zH z`YwAcVz=f+?2L`I7bg9$O=rLHY^-})>bKVrCU%BC-S&FTG^A$sI^gCy0Lk|vNo9xN zH@2v35F4U@{tiOpctl(nx4MiQ*~Y-PFSadB+J_q@Qe!BwgOnedC5@RJ2Jn8p?7!Rk zSfk6!BziDr90!JtMW{LNamV02}^JTsnAQSB#H zzzF+XbMyv$Km5$So~qF%3v;u_|$3f$P2 zr{?(Y=F%#*2|A}J5tKJXKZ~lpNqgGdV2HL#wb_YR@znKhMi@7K*U_k3%{#H41u->0 z!W%mJi+ST+{MprsFaF|tG54JY`^k;XM~!TI)CkF}WT~AmYqx)dw?ZsmiE5TmZMr?& z5}qTR7NpZ+*JlwM+&Z)_l$vUj*Z6%czFJ%KV{Fn+98ES;@LDg|XxggyVm2SO5CA?_ zlh8!5UiwEPt^LmbRarp+#%K@usmb^^XqaPGFhl$%Nz8i1;PRc-ol${EBVGT)!zR{J ztIeLlS-bcuE2X=`X}u)2UBa>X5@axCPEX@;TO|NA~`N!C7i~a{9Q4p z*`j)fHzm)g_8R2YeJVX)_P+|lW06!)@-LG5kSel!Q`~;8_T|AyK@W-Ros#;qktmqi z;VUw~EnlhjmIH(AA*`R%Oxf=?*79sG3HFp@CkZF}7C572rhoA4IclIfJm9ibRkG2C zeJR>)q0z>>f+u;CEo#`UDiRlhxxcprSqs(H( z(fgL+^G1kt;jG<=g<$3L;-V4LX)4@vW>{i}40ZHVeT&MB!v1xthrc(>R0%hCyCIF$ zxVp3@^#XoFp@PwwhPZ?KSf`?&n&g`$7A-SR$egdVw7NX#EcUi-Zriu)(ySl8kP0Lo z^R`r{E4%EdhevO_{jG@_5#1OMK$tf8ZR!3#VvI;)*HsDmxy=#9mob|YIRE1o>MFzY z5M)jAa1Py&l%MYi(n(s(scjW#l%>|Y4JVX^eh!+3#eYxcs2OYyJrHdDGp(ADfF-3y zD6yZ1B`RS5_O{IbxlE^g_Q=}0^-A9mf3L=RJ2t#9x1_slAr=!$-smdFeR1H>^7ii_ zRg4}Q5jvXc2m1bBv9Vin*XFN?Lq)dTNyi%mz%a=u_X^MPqplJ4U%2I+?X6ZL_v6tBM$vza+ zihfDv^LqCJoxne|o-vQ9*eg)xB0BUvhJ$dXuf$wGjUh`pY~oEZtaS6qa&t(@%g(8# z!ds_b29!qiiw8_6tyz3tMb|wZf|V4sjPlDrml#tEbZR|;6SC!YVc zSXbPPOlfCAJ|_5!E>euSszF$0lIin3|L>&NoqmthLG%=V$F{TAA>*mkWA3wlL? zmTPX~FDWo27_(7YWeeG-wdvc!m%Y*0<6F#neGFkX_TK)4Isb7lKW_|kyth3+Wi#&? zzA%B2#jQBU>myM2iJDwV5Ro`J8%3wfqoAGb!FRI0{1vV4tNF|jFDxC*SJu*ozm@iX zccm|fJNGN94(|TRgxMJ{l%33<3o~g^6T3_nC2%|+#NzyXpRacKVZ-rj-0I-vX(3jf z7m6!#SY?@13OYJZ{j-M!OZjj?r+ABeq=!vbUVHJFXL%JwUF_+-TaDwn)|z}z)w-#V zhd$u^$hPGUI{JQ19CfaSb{{jd6;q0auW3Z@!#qH675wtA{~_C%Aob{>`Sd%94n|v+$x>5! zyl?Vq2`=Au75pjweov7TC(ujqB5JaR$0hSHk~G0wZ^_>-PO#mMle%cNp-q1`W^;2H zo1)vfJ}+AAU5?&@-Zd+&pTs#Io3AU3C*Hb$iJSbx>20`?xQOHR(k5J2_oo_lQ!(rNheoa(S!+uNYTt@Fsh7Kxnblv658hce&eXwg5A-{TDBcggdmV^N>qf zxLD(@1DWb#JVxCkv;zW2du0e8TvkH(l3IjkPXf7dii8DKTALTcW=llt-QHFl8T7f+ z2T9QG*f)D@dKn4*){B~cms8I@_G{wW10`1`Cj6`OvAfZ)2a2KfyMOFV7FIFCtdu-#cIKdNUJ$b@!nUJs%2uxnw z9HE#MW?ZgGwk(QWbW3axv=bSOoTytjj1($WCTkmW+8{~aIg+^e?wQ>hASfF$!(F$2 zn3FGmm1?m89o!mw7e*OMAhAwd{A}ysRBRBeVh zJlk(NAIaFgI(py$JN5H7GXas#)XzQ54ux>uE#0`OIvMlS&P=sIn2YJt-mR@1g#LDZ zQQqE}1q+?j0iX7|oU+e;KDp{bSIsUsgQ9J;S2MGsgS2B8V?EWkU}yM3jD1=CW9M(IB#S4e;cHd!U&ZU`9fd3-Fh;HusNljO= zCw21C5)X5_ked>I>^Wu_KYkwQoE36TtCSh`RY~#0;CqI=aPEzel#8lbWIm;fAz#<% z#0A>?*_H?qqvv!Cvbf$6p#u~1i#zXH;ims$XhBy@r?#Wn4x**IWA+ENY6zL-`rNG@F)^R4Pp>0&Q#Vpgp-YA^-UUUmUlhrtv^Qa|PaP zE21I?fhEUZw`tEqvJ~`VhD}P|al9pt;G?w@&dL6Q5`h&@PHVVzD198|+loh|jUzXe zo7B|aq za=~Q#So-dC{ItY3eoE=gWTQ&R;rbU1aRRkL8>0AABoS_GMe~w&gk+~mGg8ASUs752 z=_YTaVZxrhRnDiH0p*JI@Bj9wH+G6j#!Vx*XV!gfh|1b_u(~F{uuf^)&Oa23!S?k% zA}l}6pJC1Uo<3Zc)&spPZ3CaXhl4O)q?$?@I==0L`#CR_7?EH1RvO{uy(x{e1Fqcz zrP%eH7*Vyp??y38APeC$K~?4!OKaUoOojp&8v3>>xfe56{pHn0K_eHHi!aTR;Rz{LCtB-MRMFciU|SDqSZF19izeY=5>WP?AS{r|_x!qm5wCk*yK?@M z^Vj`WL4pStfiBo119$EU?q?hB!M_?Cv1PjCJ|;xSYSEH3{9oZ}e^EHU?ji4Jc(6<;^z2j8gG!O^sNt+c+lLv>l6z9eC>U-P89 zjy(w~-kOMpQ^u(nh!7$9%3c4N|4?xCo$YYdn=6qN)WKp$iNh0P&R@BcrRBRpyFjrC!bX43THEsxZ%oWGfuuR?53^u+ z4RN{d!kXV~x5MzS*Y9(NF$3T{{o?x6M{Z6Uv}0ig24}QV2^+Jh{nsUx3ap-LrAf(P zDB!^|@P5%l(D4)C*C4cV6!3fBWN4-CrXSl;c|#_m71mHlG#$TDqF+@zOuV*XZ!P|k zKEF^eKj3-mnptP+wOZ8AQWpb3S~nC@BeL1{>Pq4`RQ>h0k|brKS-OTaT8r zX7j7a6w=a9D>XLIjoC|U?<=@eAySf;^qqCpOsblEHuz&#_lNq)`{qy1INF4h^NBdO z_E|R86C(Rjc8vVN1P!G`CKZO(pNzqm88uP;v=Xn#Pef~r`R}OR?#(CQg|#m;BUIq` z%qO+4o5&qAEi=hS7ejeoyzEA=QcJuEZ=t-WR>MRj{Sx}5*(e1!dVv`xYIJWP@!2Pt z(O)-~+2op~lT_9}FI-`2=n*2($q~k5V)}@OwR*w|N_4~dnyKor5H*|%cA0+_)|h-u zBvk#&`vueI3vtq%?8f@R0*ux#6IUjPsMD2DQ=w$3IQ%7(K&~wotxuXVOY3bzTkl(| zQS4BGhY)09C3rorJdy5#U`^VU@0HD50;&5 zQv2Wq%D?5efu)0F*jcfd#zx_G9vg+kGc}%|)v3xHlJ!JI%;#C+ITPxqD%os4*~_q6 zp1gP3M?I2=_i4@b+jj4k5ir>^v|nr(=UjSj7LE)J2~3;GqEv15n8YOd246inMI8O+ z5gI`1HRoHTUO%FQq-TGno1-H4v-(U)w(ixc%G6yog}=D*-{*2nxFq*S%%Em)kjk$w zu}3ewO^VRykN4lUG4%bmz`1jh!qcyp~{_}b|T}^i8XrS9$%qcwMlf(pzw-z}( zUcVwNGGl=1m!I3tzrIV<6?7{s^Q5hGSf6nUvt>vvs4)|E4ux3(ds5j9iGC#IDX#?zE`Llc%;)MJW zC%4(OR8VL;3ojK=Ni9`}MV;}uhCg^SUoo3mEvtsUPcPuzmF;>R=W^N8DSCROysCVv zOEApf>DHx&llrmj7K=s)tI5gVouNQUK1tw~7BL4p`skNNF?{(UxBeBwhrXQ4rhC&l ztTSxl=L5oL)8_G6)XDmt%B#jV0k)ghleK=D4kdWlmBYSqoWiIN2KA}=zoaPNr+Ww& z_XToF;{U$O#ph2~laA&eW;*}=F8#K_zmEi!&GnL8qoLtkf9|!pgijbT?^lhEZvFY~ zt-uFVbq7JApgNkDAN=tdh2E%?GQV?Zed0OB&=6PTSp@;gFo@&iJ7H^@eDEZ%@^tx?%75 z2aDfvtNGcegbp{ll}4z1tZu<82_zfmwzgk!jc@P#Th{}VA<^_=@jr8MRbihIbKpxT z;w#mdmH4t(`6)R4w*$~Of~_`|Ip_-DY?SDx20pDBvE`Fim11o`JcTJ+Co+(TUN#x) z^#)QMc3w_HP)GP@t;ita%hwj`qE718$iqJcF3QJyn1??;*Sb@Ckkn-QOq{gIuS9Pp@2E2E z?07}$Ne#ssG`@0p$b`S=IlW}|;G&Z6Lsl7Gl;wUZrSdH`IX(~ z?Pbu&k^uXjaUcCR+fj3RflcZ}5=erY#*{)ry)C)P&Re$Maqm|9m;I{M35i zgB0_z!60ix%j_t&THdnl5O0k9D)8Q@ZjLCe(IoB~94;1(K6a0mu2{PRh;HLwrM_nCL(>=;~Y^ijK^?PdQECZ%^&}22xnE6PeJ#>hAO%mGD$eecx{Ay>YBA)sA=wjt_;4{};a866mOul;mRP#H^60TB5?9X=X@Oh`e2z>f) zeBzG6OIXx)R3n^mZ56i5rpe!wiSEQ|;+j`r43&}8G&FWJLQVSVW-wYv5EPvS&tL=cU+yoWM-@5y)LkXwyY*r)QbjOoB5elf9|-*s_b`HMD6Cg@+@pP zT$FbyxxJGJZaeNRZ4VYC7w%2L(v-%_%4}l$fa@NU6;PlVil7DS608jS?I4%G+`eSe#RHK55SB4?y_JiyM?qb}H^hz20^Dt8p;WmubL}{+w)S$t3}u_o_bh8aPeQ zB3s$)&W>bH;#q`mmuJ-pjdq@SLL=jF@cNJLqrfbBWSgg;QAXzI;_;d{H3&_R@SRNk zjq;(>zzTw`{7Zdd6BO&jM&a$;YWaYb@zn`Y_FzYMK%}7|B9lM_t|BI2TBgVY4+Sw# zFuK<$HbE{)87F!g$s31wU`S44kW^v<`z?`bG5HqgImX1iso5jDFU6S z`T+1vLNfyt>KK7tJRp{HBiaeIf!<(+5QL5(_%>_ZR3MH05FL$hB3F=gd%n7e8=QEl z;+Kxk+`oj+jc>N|SR!e+Nu)eyzob^>TC2yPDE(}Of4)!%+O;0tzTfGVm5j%Mi6|4N zJJRbl*Cls?2(Evc_yxto8E#?@;YP%q9(Hz_QNzx`akCrd=ey~Oqdl5uZ36Ve!93#N zsXwTq8vm3C2M8suGTnqhB(W>0Y000932=~AFXss*B*@6yC z$q%hlH_gz+0j6n~xr`t8&qYw)^o@+(!G&fJhq@Z4aI~8gOp<+SGCP0y6|T({XozBX zm)qM{UFyQ=?uxjR$g*V8~Wmkuqc zx_h#3uVerJ6#u)A5tCe`Zrgp&nxn^E6$!SzfJ}K{{i0EA4i#1ulB|y-5YipQlS`4j zmUbY;1fm@#CR_)DXil&%)n4m(?_V88+KNN)G>qX(Qu#3{o9wU*;A?~Q6#Zi=e)-`M zR7$BF$<(?BR=~&Zu&e+II)zWG?WRnJGx7p7J!db52P_R6O+6>G(0nWc%y!Ee+fh&2&V4l}?91_}w+a{eSRt0g4v&MI z2hh5bn$(hSHJ@?q@8|EGT(u=yEDej6Q4p+eoz6AaM|<8qPyqEJ0Zw?ByMWnqdxW~m z48e+%#{d8W02`_UO>Y6M^h31HT?E?9;w&s@XM2+a9IG+A2qZPU=Vg2uFt}BoeP7-H0Ug-a3jp*ADBUf2Ie*(9ONT zmjmj9WUy41WO|Zv6kcatxfBal7uNI>Xw@%}rvb&2%qk~zJ&qa6$R}C^wvLe-K63w@5&NVITqNq~Evdt}{Y_00095`5s^#yp`L>x=58f zPLIgHpHR(Yx;5~1=Bq6VD~AXzM{Wae?In4k#y5!ZH1l((>er|!vFgzsgM+L(jn4Rm$3#Wve_p1=_Fo(!u-OxAaL+~5C(<+$^GX~cVhRR(BidsJNf8-U z>(=HVtWqbSJ1qUFdAD&2mhn>!g@LESLuL3SDr9)VUahj#+^B!29*->UCWg>*DM^CH zWna%CQ_k~?)D|DE$ER2dgbF_)jJJE=)1dOYp`|w54qsRpP~tF&gfC!OW(h&l5A#6o z!(kBpy2aCwDj|kc`}NKGsJ6FRX!NFEi0}+c0=l`I$KF;O(spPB2XLTedHDvUN|?8hzmlj|~kUKtWR({plc&7%?K1A<$-OItH6Ciu| zwg&(J0|07x?&itO8)eo6$?-N@GF7@_EZufN5r23IuHOWU!R0s=EV69 z;DJ-RSk3h>_o1A^)WTa8g91U5FR?50m+2HrdXeUSiQ>gwHKcysEp3Y2MuUf;O=X9) zpPfZ`Ks@KA8%V1ob~@r{m`hqv_+4wo$w9jEd-YoDC`(o_q&0h8^Gt|9xYJnMqq3oy z#hq9Gt1P9*e6}GC8#~HL&qqu!>kL_$O5SLS)~oHv9e1c3_s#eO#E z#S~$e2$1@Dh}!y3?`rrW!CMIEI;B}+SYVer6Z*0f8!mdRL-GI*pxL=SjC)d9p|OGc zmv-?)D)Oa8+Y#n&nJ)dzQqA!>u;B~k2@t~6ycK4-c2NKT0{{V*?l6w+z$B$YaQYS{ zC&TO@wq+Il0>%tNtUC*96dn-FBGDrd#Z{%IZ8PAmKGnf>*juP8vH$gohjQcwtBtiX z*1HB?oH)=uyLpysc+4wX_85jJq*p`1F8@z$ozi2u2@m54fP^VmIN-v`tWq>RRtx%} zc6H{TItQ!L!o7PxbL|yxp_SdBqq%wy3Qa5`DQE_0^!KKlh3e`D(6}|lG_vq}ntbGG z7aTwAvRa?eXxP#E6|()$j3-D{H=@#JxSW}&98%nY*6vU8-hr(k9P~QV-3*9YT~8nP z-QeewFh&a?+$WrzYT|))&)DrcNLhaBrpdo=l1?x=ak;rn`!(+(#~n`42y@T8264x1 z)$qu{I{+UO&oRI?t@i&iuH0;*Kwq(K6{QO1fSBhGGY9KwLZVTK z{3V+{VP#R{EoS4%e<2KMP(kqbVd6L0+#-8e+*ShvF69XxJA$2v(XS^%X5rWEdift~ z%eFWt;GEKj!6AN{SAAO#LZv<}cI872IYioHHhjsj00093KW~Z=p|_|q5Y)SZ4nuDF zu{{Ub6_i)5)fF7MHh!(q>?rE*mZnJH)?ZK}sU_xH-#&_ldkOBp(-D4kj_wQH8Wx1= zJN;cvRI;6h&Nocz#u!{RJ(#^X0f&F2eNaBYSE8)wWbLo;a#&BYP!wC zC&%SAS3_wxT3**+!vAH5yHT}i2!bvRSM>S>yZ-04W|@F zOlAvb_XOnv2J*eA6;h3TGUrB6I8vV{z(o8I1m8^Hk2a|u>E|ro#ofq(sfEP5$BY4% z!sToT%*eUFsx(Mtxk9f zE|kTzho$eqo_Zrj{)9ObSl*KZT@UJ-y#<8di?r^i>~HX!9EUOjhyVZs00CqxrG>I&jjN!qJaeiqoER ze=j9l^6y|VVQ`5-f7!~vfg&kLLI*3uI9-|h;o{~x^dRKOW3+WT0ZW!*v7&<2Iibrc zx92zCr+iz}J^XruD3@8^FFJv~VufX~_$0;C$32{I4q>=#r)YWJUG?c*ig~fO9wUJ1RP2Dn$ll4@=>}D$q*FjN|P!)KmY&( z01!~jw>7w806?+l@~n#@s?v{ z;s1xzU4Dk5hZqe}QFHHnm8fKx3?mGY1IpLdb%QHs(zWoOD%E}4l8_5|DYoSnkRk8P z(Ko>9XzA}Jw=u_p`ACHzMuWYvjb)G6R{Tu6L!GS{aQ{v^i7Rpq6Sbl1=BIR9U9YOb zgW&=6?f0WPj*Xv+P|ps~cjMHx$6|)Ua@MuIOWJ78Xasdr5Gift+|uX`X*lM$@UX#Z z*b0tw0$Cl9Z>d*Up{oXd#=XY^0y|^%EM3FPfK)BBeQ{p&_B*6r66r0sr^=llAUkMd z`vCNS!eWqAYMZnMI!#eIb6oB?e}t-M$Hoz;?R0#NH1AG_{6}VnhAK}vP)|cE;fvhaq|8CKPU~MIrDH+h?r)9-XF1zfKU?6*>xUA}MsfB@N~@r&9&VwPl4(sTSFf|X-K{9N`+O2odj?I z00RIDL0I~Efmk=ssJj=+NX&u%j+{3eu7J(2S8YUHPj-eF%^`M*XtDmK935R)=_(4t zrWMe>UwXiuIYTmDTdJg=Y+LL}>ixGzN|2=%9NhwJBfD z^8>Cb6J14h28)0YFoZhW7pgWPBrW~@r@8*AcpwzHBM@_v*TbT`+XB-d*qAtER^*@DXEb5YJ=$mdw)!t zKydFG^?^FyV5{GI^rF%naJOYvbr62D&iy+F0h8L(gsKG<^k8WR7p=d3cZcqpNad3d4wAvm4I1nwtJR3PgAmWxD;GekrDl|C_$@3++y(cK?wI>dNtH@LA&`E& zfOlu~&+Vl6V;}=6pMGV$Vk;sI8T)T`+vmJdb}O$v{;WCX((Wf|Y*P_SuSvG}PJUTr z^}MqPwoy#VZWj=o>nC__;(K%cD63^7SE_@&gP2q{qVXms?ip0y8Bd5aOvqFYrgWCL zrV#g6F4i=~Br>??#&mQ!U2bg?;Cgv!-d3IG8;y` zz8(>GpezuG*|3H-d*6TW-cwFM$fdx0IF}Ehw!hy94ZA_K@?v0V2oKg)NhJg@ZVGBXS3>68Ef4dNRDV%Gg$bh6O7Gx9Tos0);0 zSdG)xZ^#=v_N{NM>MUd^~eNj>pe zf3rB8GOvdDvb>Ujw1$SoLCb$0xm|*$BJ@biTV*grLj=MRwEDa0Ow4P5LDMRIP6K^3 z4F}9Vxep6I%>_R#cyHq<#rLat4~X1R^#|1wZ(0w=hm6#=jwX1upM0p1disI1RtJw1 zWASW)f6HRIJ$0*f5@hwm0KhwjK<<-L5k?2h_-YHUZxUPpK7ZyCK+yJIasY%w7A-ea z_pwK?;Q)$P&}_ZS;W?uSb`sB;I~sX3K^#~+T0@doU2Ac$!=xaA)0{`?7*OoXWTbGP zEZ3fE-~IT0hcB+xVeorSh&kS@aDWF#I&dE>8&8P2l7oBdh9F_91MC0*50I z>k%S6G|lFbvFZRFS9i!j51JQtmg8kP102Y#{EJLTS!J{a&C2@P^ap2`c}7VmAB6PoxD8%lIRS>ADtu#<--g zH3cM>(hqF0aX|08j>&6WOh4l55rn6OB>Hiy;jyJdiFfuU_XR(T2HLRi?gP|YCeQRo zYw)kWp8*;`000LY4tG_BcG7_@{}DB7G|~99*Tp_ss|K_NKn^|W2-FhGa*}$RAG@}D zU&}yf0Cc@JH8;oY1n!<*I92OKoKk)lOsm5i*w!;CTUlO^e^YF4$#PL=#t0iJ83b@? zyMp+JS|MumVy`NtVn6NU@u2?z2}@!9&}X{+0lxC&<{TBc9g@ND(%z2jivX>%ib)*= zl+b?6n@~}<)4`{>7(VqR-zPt}+N%};9dF>0cajgamIQP*zPCt4l`W-d9S}K=?yN#m z&-us|V%l~=6gay`qymE&;Y!;p|_OHf-f%Q8L%hF<}!acM*j)`Vd_ z{`!v)Y=`t}Mod)~aVw1ZD9q+&#b>;iIC=QL>Y27ER-SY_L#4=6Nvs*gn6SANTH^%e zi44m(_wCMK?!M)e8#^z9>1b^!V}gcD`>ycCVbOAvf2U_=-^buXxivv2ih-<+Ee0Le zxwFh9ypWnDUY3P9&5vzqpa1|0iErjllX26&c4!)WV*QM!E?*p3O+Pu;!T05ifvL4S zVWXFFjqF-k-)hm2Q>T`fNdv z0mOG?5&dXzuh$p?_=5+IMfMH+ z3W(-xNJy7!0F`%I(=}RR<#1obWTB}5_ePg4S($Z(y*A(cZ!jlZ3X}!l?z4I+pD26Z zt##c?&hDLbQ6HcLr!5DRf6>FftNx@xz!yuljmhnAEf78Iqdbl@;_ z>sJX^RTQ6*-}ihj8m07Yyy^`F>aWquZiB*MIC(fKOF#pbrB=;+A6w3as8tFhlZE97 z{>{0G=?kfTJznUJ{nG8s4q}3+%uUV`F4>t>NPs^dD%!H;Ch+4a{aDCVKwe#Ak5MTP z?l!~b&5n3DlvEVhp+gQ9b6mq%MR~&Mlp!djfjCF$Rn89%*C0-IIW0SxHDF&(sZ(2CR}P*Fzf|jhF*BOB^h$wq zMZX7tTYVcy?^(UV~8W!`^F?wdTv{y{3rkN<=X|6zA0Z4WoZ$hn3g zqKUW1Q3T+sb*@FlN#tC*C+f zQY#&%2XiDWl(QM-yZHna$!}E|#p)q~ne|2@WocAqiy4yrj&8i2cDflg+l~N{a)O6Z zI-I%2PpPB2NMxKLV)LQV^2X?yt)mf&XlLUel9Pi0h2y6U_nIG?(LhzVKHjNo@JL;vNa2D%Rd(qNwE0gKg>FNXb{ z!>=#X^bc$K{`_#g2>db5y=+gD@8?g>vP|g<(@5F0@0OrYO--Ru;@Bhu3kJ}zu4Iyv zu%#)MDqr4}RZ~N;wKHIu6*g2_G+1x|00RI4)fivKm5{&qs=ZeOyto3650GSWVkV(@ z+&v#z9tJca5eTMZ+W*n2SFP_QAO7fYHmLQdE!9|0e7SZAM6`H_8Zeh2BWymLN* zhr|2wp^vC6@N5Z52lVKWTex^<)s?ZyB8K7xDPO*kr1QG6JgV6oMB+0O;Ni=+7%VfjTyD%Dr3~-3XIcO0Oo+tUF5|C6yt9xr=Nl(iM%=1p5WBDRfL!@t zU2$O^ovoqJN^uX9+;ootv*#XWEEn?Qv+mQYQkBfrFRmqIXT$x(cW;bvdgTMgp09_m zw{+k)0(95nY^CMuD0nrBTpb-1Onb1FzOM|_If!3LPw>KLhA+I*NS$Qw<^pg~PHDr^ ziQSPOFtDAa2X|RhuOd~n&~9QWJ?BEZTg#U50U@r#U|k%j8Wdh zZBzLt%x=pxZK`pE*z^C62<>*L^74(f2|6N+IC`bR$;Qr-?vu)Z8{1q@XlBZ^NAvvz z6c3N)7uAibq4{eEj+v?NKP_c5Dtxva%TCXj=W?hu7E4 z(K@x~yeEQ;#ykzgh*CCs+~i?G7AIpTZdF(S;$phjcCwfZ$VMB&W^~lvhnqUpWzj-d zh|Y_#}V8Xvq8H6sb*GzFaz7)03N#d{45#Q|k?-;*5VB==vbqR7LWH^{HJia1Siz*eYz4;$f-6GZIkl|a`7xk z&X*j(bRKFgcHDvkJ9K_pvF1pxm@MkhM{Xy?jlwsK8&0hc*LSLmA(b78r5sivPeHEJ z_H7C395+9snh*-n+@BOK!HANv+4!UBWGX7hv$hT-rUUnKJW3Pbs(`czY6y z8psIQ29mcwEC7K300RLreb>liweTAFV&z%6KZTnJvlC801R&u~a%wEnu+Z8en8v?v zHr9_?|Nrxbe30hF*red5L&&gDXbLMt_O)ah$pcZsMIlv_O>jJ@bx6BDz zT2eBQcSUV8ORD7qV=u0!NbIA}_(Cxk%-KAfJkRYlBAzB5Y^)i8mWheiOQ@(1QcXo{ zX7Qoc3VB1LE%py$%*!fHePJF-El7gP1SX5uV(eprcWIjAn>@^Z=Qyl)wfx9I$8|)5 zaU4M!<0l5v_UXzZ9@narHdieo+tZ6Q1jH({5bnzZ{qs>thv`&(&r+x`H{wF%#ExwV zLL}o4AYfB>7@6~u)gABXTr}gTUIGloR+#q_TB^%%vmfxT*`mi2R~mv2HZrtw&Dh$% z&@*cbgXL-DugGv#y4meYHO1$Vl=jd3WE(qW{=CLSU#LEUun5k72}&2&)e|*$9B&&> zQ?a?Q8{Ow7ll4A78ERP=pU*bN--N|d5aeauV)n3~m0M$j49~RUE8S<>{h*WEn(cg# z{K;_rvNgoxMIvcXj73NU000961~$}Fze99I(7JNXuA`n9P4k`#Xow#s5pV54Q8SRS zF(ljCddSZlme{3Xd!TZp#S`9hFlpi>CZCa{T4Psl2v+w{*4Tdk{^{ziSA%c>00RIg zN%{QAK+}J?wM|=Xk)Dx^Vy7GZzuVZ>T*!$~{!WoVWWte?B7=$3+C8W)E$l`FrTYh4 z#DCR2y17D8rmv(O=Y?bI%V{cSj)bW=N9=RU7hcy}v=j^hlU)&HhdlK-s8fSjX9ro` z#qhv2xtb|BSI{etbiQW?x?Svig2!sbm3E3Q{h@h^)nXdrLMLM97Qs*s!CWrYSW5N; z#AJFIUrOsg;nFc|T980UkY)BCOkSHSDAR08p0F+H?8(d?3Ybx-9vujlM0mi}7^JzP zGv<}vlLa8ezPX{LbFydr+ce^G>Tpc$fXN#bs5*}pkXClNRGSWqgQ`X2j$q(?r|wUU zasNGt-Y9G|mV*rU z%eYN*Zk&1t{6@tTjDBKQ+kxjm+wtwP!{Ofhu4Q}F`pbqF)G(>K-9cwa%TZF55xzet zLFPrOzbohCp+pDZp!x%s2UQ8JJv1J?k@25HV6U|2E?=`KFX>vFyfUCK122}6;BYCw zk*ojvJbFwfS@54)$PU|Md+vj8FcF$lTH;8!!A)_xm|-?pbxaa?6(tc>%)`}#MvFzt zRzt`EEDw*5s9d%HC-_50V=PcOksOf0=-&$_Sp7(bg%C>RF#rj zMMk((YBGv0w$w)wdc2q?GJBsO000`XrAy=1>D~$YvtHd_oc*>FyQ+8nbO+Ke=iV>) zG!@cw9`{QdTxJ>@`o4ztSsdDLM~D-CbwL+PCFbrwrFowN@D&$kDR4^jzSX^4o%UhX zBG&0;f-R?yUCzb(k0hblgmVQe{BesM70mNnTn2}@WHr@F^t6aSA&e-S|@Fs?t zpKqL<7<|+4oSC^6cq#C9V%Y)mYZXta11TYkhSsqMjKyT$ex_E z)VXVs243(!w;|a%kW;agKyr`t*GWBomY}I}_;$ucrWbpB!nt0z358@|`hzlD2b}#A zx$d0EY>4WtZNFr64@5Wq+atv$iPq*7SM2Ih;JY7V9I-WOF>FA4;Vda3JPf3N-Lg5> zFP}ImPb9J-ohiRB;zM$P7*sk6e1pBmErSOJY$qX}IzowlCBf$WD)S9HEt7XvPA#|z z%0FS&I~Up^FapML0{%OuZo)4%wNryCP*w`q+R)3CW3a&D9PuWmDNCkkX0Flekg`vK zT{cK=2_ac;3uE-A7|EFTAfB*m!d_|9jKD~}< z@_Ou|jz!pIj0`UN@9&ans&9CV7=fP-@jvicrUxDkGd}dcWuY>Wmt>|$c)2z-NrEBs zD-C$}*uMDky~o=iDu7RrcF}nRd{{6l-xK&c#`*>9hywf(*i;7Sr4gd4O05Yuz zYjoHYU;qFE000H;@E$nzD8{_^T9o4*fsmP4=$>3b=+y-uoMm5a*vDe<{e0XWSO`fE zeKwxFR8Oxen4F&}eCjw;li=8m-E^?6`E@Ax+PqyV#D|ncj~#X>``kfiT6BCEd!}@8Df6qRAEu%Fg|5{PRU_9Q+R|< zO-4ci@!0OHy&&UyalDfQ+UkG**0jli~5ow1m0z%DLiAVsBnc1&a ziP@MRw~|HlmqZ;)y|{c{$OvXlVs-f#Ek0$;`%(jiPSrJg9Q}(baLf@DM$8;POg6H0 zS~l_m16;$ka8>u!Z(b{!?4uQ+f3@OH?vJp4u+?Zote=|*VMeO%DGDyAVakn_9)~<2 zVH?T9WdFSif^^rWS$Xuei)OP7H!?0IuuMLY9KYW#DGm{KeQd5}gC%@QMO-Xnfv0S6 z!v0;APHf>8_&Z;IBEki{rg^-}$d~%8;;-fIZN)B4Cgb2l-9b7#nD}nIr4H)Kt}l`Z z_ar<5a59@R%0A9|zIJGu5tz9D$-vA0RIAF;{$RY+_Y~}#inoV>AVywhH#RTj{xX}w_i0}cpjEg81%Ww~f$cTl9gH@<3u!9N1BZb4FGG8f|F2X$+ z-3P@)zHy6Rw90NpFm*t{oate?i!f|x??p3a7>^i@n-X3V{iImpN8Q~Bqg14D2mo@} zhxAz7t6wiIfm4U?*GP_w@FEtcDWW2BTSofigC?7fN}ZF`Tyyif|5wrt$L zA{n}R{pcApS$h1(nT@%1z;h@l9Yf#?y_>TxjHd8k505}#dR^<|;=0+0=&y#SDIf+p z@b((7Ev6L+*ez3@Gr~Qi+BP$I`(o2I8EF-V+#nV$bL>%{lCuzCuMm6(I3CZ1W~g+b z$QBK{X45V0|{=+|fp9gM5oVfnd8Uqv>Q^>FZ9n?-A!&7_{ zPHotTJF1L7mg}Q-tNTg3QZDn0>cS`( zY37rwY%E_$4<9#KKf!p^dNpRkoo|`TPVuyttPVvnT9DuEL3e2U1GOySE{X#FA0_`y z2r@Z3?sz92P8*RHF)4jL7Z7D@(X-z?-?N~3!DIj+!l_^|O!YjR{TvuLyYVc|*Pk^7 zyX~HK>N1MB000CdZwH4JWSf?OA%%24I1@ox~@jW#wvlvq}Pu}NJGO#N4%RUP7F zFr=tC7Zq}ASx!rGuB5?nHW&f{gX+2%p;+4kg>HssK=6Z6TKZU&)7p@ku@0j)J-U^523IG5D04yS4u(MH{6Z^t{G}|aMb)HPWk|gx` znG2qES?zoqXXP>yflhx!|M%}4<{`sM6DPfwT0CiKgL^YBZ__F8Xm~d#(F}hVjY0w- zx`j?+eXCOVpxZxzH&&}(;Z9mpf_LvwL_VLs|9uPtvzQKhVvFpq(CF>*QRZX{YB^{s zRGE`H`w~-9vT!{|l~16>M*b{a`yylhx{2eT ze=WSN&>)xi)ry23y1=xuM3u)69DGRn1NSZhIb8rfvz}jKjeP^LcM+p;0Jq)>)rp5%AsBrskDO|Gg z`thO1ZTwFYkH5_6Mia6HGmOf%M&4TFRB0wmHaGh!)>|txWU;>rr9Y{?2OBWT+K+^t zJUWgFgMnt%KR2N9JpPfQew2An?PYnovD4B1g51Ku|11Z@RjrI&ybKix^>z?8WPAkK z000937_Wvev0@Ullh_VVilfrt(cZi^EFi~h9i5~>KYP&h-uzxpOLu|%0VtX%m&lj{>3ZYQrVOI=m{+v z(B$1|;*>Y{iW!kmq!BbiY>$Q`zKG`4Ashe-Xv%aQN@yN&=JqqB!vB7{Gv<-JPV0JvkoT}KAt#kMaxHypD} z&^8TDkMnTnCE8p3^`NW_khRqAX2&P3)D8PHdxe}OmlNn5?V#Y0A*##MpHP5wY?C0h zwm_+nZKp1fFo74VTqt;ce3d^g$<1UBaey>txS?0qFt5Mdp$CxYzIp1Cp=sv)D3B8t z#ukG(rr>jk1H-TrZMF6QaR$shA3sk|U{=Ds&-6+}bh_P7!|c|5(EI@GfPJjHd8ZML zeAqH{ALIVFYr`K7yqCUS>Q}B}1l`bo9~NtaVc8IF^_e3Ai=+Sm0{~k*yrTWLnVHkD z<~L%k*^+0nrj69pu@P%lT&@eDwpH8zVWXFgQCY)qk;K6kP zh5xrJ$?0})YYuhqq1!B~vTL9flk~mp7iV->L>-U|?bM9pHAEu1ayeY@|Ns7iqwcoe z#A#g5EE3_XzKrq7$~{JjL12iCdRX$%$vM~@n?i1@8}`w+x=cv6yl2C{2UZM-^P6bDT^9Cq)a1*6b$4x zWUiE}m}PW@o|iI@yyKW!C=U z7Y!&M;bID*V&sW9g|{38YAE6cG`=oc@Tr{5?)bkMsaZ7Y~) zO?G}Gd?TUgN^G#pq^kq#KeoG^RBqOSx`cCV&RBea%2P;uE7a)Z>*s*@zK__pQPcv= zTWF%+`?D|La-s(&X4vt4tK1GU#J4WjCOmKG`1u}_ZlSFU(}GuA?eZ56(OceviOW>! zu`O0|fSSfHhk*ynDQ|U|G#)>i_$|1x{=XPdKnhI#*)gk&Q2x|*bjfKLx1VhiQ^>i4 z*+4}<-ZRJl6whcSx8RPD=xSbP>W-$xy?k^fsegnTx2&ST}b z7(~X0*o#k>LvZdb+VEIKV{?Rc%RK)Or+v$`tjsN=JSK{wxr}f zBesXYe1KYA@JXXK)7}gt@geajNjAufWM*gb`mjnUy(v6s`rQ5aOrOWN7sWC*=RJNp zj@eeb5~l}=qZ4FPC^ZxgZUVvTN%7f0VL${%cemSBNzAuUCmi=04Pk^6*~Lp5S$h+? zO6Cbw2{>m3f`P#Q{Mz-yx1Bt3hXTZ5vc<$>#Bh9WwCt88|L~0wx&*aIpt5DLLNNw?auF;iq>LFz4Ty>)7{E}j#!9)Hao*564b@T@0OPtY2@Mk9C1m^n5 zP~HqGtlO4Exyc@+sG~Hb>8o;mia9i6r;G&{D=n;R%+q0wn+YGwZM=nJ?5{c{40~mzV#j6Ae%TKmkA5Q*;lr zI2;HoTj4Y-b)Kz9_k>JlMF3$me1RF{zE0aNH=}o z>_G5)Es#6hrnMZ0$qcp}$~8@`kI@=sgl67T2Vi!NRy&Hsdy#}DU`xxVu}%sMHD`z&B0_GwKAkzKz~_WyECxO0 zCan!T!(-&UGszeL+l?nIhx4zE_Xlj><}KLw;0XAd^Tn5OJMf2FImnQa}CtNc(ay!<<85}}GCc2pQ6wu`Q4Reob$8>OzD!neSJ-Q_Qb{i(Pd*MfzCz+T%BuxG~#sh zaPPOBCz#xB`UaDhb$W}2 zcU4A+X1vurhwzAPTh1&F*6Um1{gHYNXE_=c?nfzTFSP{eLUPZX!Z=KC;Q*_QH{+uj zZ!!Eg8|qRvi_EOL?(c+S$76^F4X&Z(QmbMxl!(3d#Crd-m+({~MsWr!o#8L8N{fVSelw)A?-72QQ5TNAXWmYvW`Y~X z5*wRm&7m`%G;h===&<8*Js`UE4`c$m*>cWS*vnh%kpMcj|0(_)$**J$$d@Or=PLh^ zx+iSegz6VO5q(kVg4q)BMCvQG*cdCVm`0?7*MtrE_i#TC2$!1g%Q9{>4dnVE zd{GK257&RrTOLE+PAmV-iUT?xu%==#@d$#>s2Hn3T`>p?zWLTz*EcAd?cvY>00RIR z-J#cjm3NI4+b}50k2%4?Q)oMjm=wj%SL~4q)5%8?K>oBsP8Ld8DW4HAE1?B7-Ew2 z3XN2`wI{Y2>re;{(tmmc4$)Cn*Oxmb&E7u(lN*HhvoOd+q7I!5`<>7u70d~{>gKwH zb_~^iyNYdZHQSEq9%p+uDjE96A7E11f>owS8%|Q{Y^j^^?dw7RSMpssR=!ea8`~8a z8%w2)@AfA(2%7JK07pQ$zurPOIsWkz4bwp;-m9$ZbO0k*w0mK?O+TPfWhp}OhxEGX z#XFFRs^6_@S6{!TMh|8HiAnS-L%7_sd#to z>$Qt?ezsqhXr7HQJ1iw_1e!F;K%L@D54B@K85{^K{6oyWQZY^gAc!HNiiu9?E?sNa z3$8gR350QAycy7$jQc`{UroyFPPg%?opSAT@Fm!WU6CH_cXT-rv{!Wo70E2rYjW{!#&wWMT%iyOqw8kxrMi3jp5x8f=Rwj|sQWe#UYjm^3hP1J|* zg*ldud8pd#I>w#|p_pl(3}-%%%xjJuJ7W}bT-2Cz2C#X@&gHn!542zWAdDFk=kJQO zYsDhGfH4ICNyutR^a~4ZL%tsY0Vgw^*Tj6(*)55zi;!giUQNlEY|RBRnJREe!k3{J zjIP`0#0U+?Zp=O1^k94fMHgy^U3_F{=w@Do9}by%Xl;QoG#D)-A=VLSQ)%@UgH!g}$GxWo#^mTX`uS zi6u~vcB7*F2tJuXHnk^*I?-VSdg^^@X2#dgbk<=f%Pb{y*7$D0Mmlq(eFyDlD-5)BZp2qEO8MK1~()Mem5TxBE534Z(Xgs3$i)~A+gcAVOx245{S2J zjZ_#X+E0(x`E7tgLV5nNk+aTwAt~R%oIu)qmbQT)$O>~}AKDtQhVF|PWt`}IJ2`h~ zO#o>6u345udGYzyy{OHY&jJNQKlA%!GGJ7h#JO zYd)lJH|61k(n!7R*Bm?0}wQGG_!|fwaa9tfCuhiq5 z;jM!N!^17_vm~%BS2@(0m-6Di8+t4P&%ztIll7U;+$ZCk2~?s30FOp~&|>HM13K;+ zG~|vN3A$Uz*9HmNA)!e3dyM9-NNYwKs9V<<2g&z?IWl*bA2S{&d?S{JxFIT(*(aAg z1>%zHa#zRDIb@d|ZtN(@cJ6T9tE!{Dfw_yos&lC2M!we8t&QQ_g2rxViik5=>;>(g z$eX0!WN@%1n;4f5G)a()nE1{V;HkbydE}-&ODzi$xl+S_ol|=y01HRxO_yBfS08bz|mgw*X= z)8YOq@);27V=QjrU{?rN-&bBI7lCCBvTRk5V^7M{&07ZPL0OFG&_{FjR6q>Oi`o)R zys2nsJz=b>uVV3S1-KHmb6Y;6vc_-)c^&`h&~0IznjjOEM%>LEQcisKova9|2Ot2& zT;RKGPeT^#+7tlMx4$`)gCHEQjdIaNX3*_ZwnLT=Qja=#5s7OOD`8^cbIk(vZ$Wjfv=VY1p-u;qTl;_4C zG0yF`^neTdjB)OEHzX^Y27Q2W>$q&Q#{Ti+8hs3tBB8xe?%Mm-wI%Hu6?R4Wcl|jH zAQDJFTejt9h4}>XZ<4J)e}>9Jvt+51ntK%HU3+<+{<{sL`}!UNZ)aO$2N)Mf2X?g% z9~3uve~Rasl_iA@c2`@QkJBcZ>odJCa+hIz^KSdDDmNU`=IeNvyTil#HAIqW6k@sg z!GA#VSL4L0O0O*BpKNX=F&%A%b$fR(t)03c`*8Gte-V6HZqcWksFxq5yK=lW6cMUf#Y2C zDJ$=U<_C|7O9%<@6Nkj{Ia5FK1tbS0M(D%!r3k)-e-fa?U>JuqvZhWal<$#+ACWpm z|58v(`oC$*Thh7FDXm5VB#Wgrs(T0#zU(>Gw*x`NjFqEJf1gu_fCEci>NnPwYMOVT zrO#D!3zo@t!V3=|0A)`ul5_rc`!8vIWWC^03CjN}`n_=1(x8bq#e4t-*^54l6^SLF z9=q{JSk!3OTue4>7wC+}L&kUNH@q~8u8`V-OBr1U7VTfz#a|R!EORShO(JUObr)|Q zi?U0hY>>pgx-{PnATfFodqUr%7ArUr&Y-SWt>&4Yy|L-3t;jl3E9ZWW9KKU))4cn- z6NCDWNatq$-wNSdj$?O%;Rtih=>=e+rP=FaD=#4zkG!lI8P7GaOo)TwDu1SgCvkBB zanbccRfSj*#&$B5cG0fvW{(n3E?RHa{~8sdnt;}`*)R1^{_Bp}qO6F-&5Nctu&g-N zqIbdFy5=57qM)u3T{a)0u$L1L2Q05S4zm)(LEL4jJB>`94jnNq83$$>>0r-fvXbm{ zY9mk1;!Bm@nwWS1d456FYt{g|vI*l*KbaSZnKM@DLy>=y63A6!@?d`F>3u_b*vzQ1 z_LpEsi|H};m3dAtS@rBSW*FRtQls}QPy*frA9T+0&!A3abcI;AI>nxe|BM3zuFd8& z{t!pf_K<;t=LvQ!^{I%1(UvBo>U7UG!%2Zk>e+|WxE$%qwlvnw`l>js6+Oik&%s7J zC(CQ5Lu397mD1CiqvzUrhg#vt0d7BIv>er&x;;9$r3p;^htFp3Ia~F|DGt{fpLlx?36A^{q;d?UarEOs4wJj4}Ez1i1}2=74IF-6Q16Wv-Lx zxYj4FU;iV7(-Xbuppa_nGyb|$9{fVsHjW!fmJ zr;Bq6Hbc)9^;irKb94%XIR&QHUbhtHqxY1aw93?V@o7-UPTkIjwP3rKV%L&y^Wu|2 z+6U<4N%WbkNQ{_>@;B{>p7a*&i%H1DXmDw!i$*Um(i|fE<0;_a2S*uj$ars0_TL1g zIW41r^ulH}?}C(Wwu6wZl#I1lL&TE+Qhzmv30u1Zv?h}Y8F#F{axawgEp~V4H?ei_ zxU=SVP#W!w{X`VLa3=d;UE1m~ymWA#%QO8)F>MNhV}Z&ge^dlFm?_g*&mJ_)&saTx zV#d2Kw6Wv2`p+o8BzZiI`y*cZ7W}#<0`p69e?R~L0{{dJ8OYDv%l;oXjyG+i1k-0m zywHDA^Hi_j1b6lyAi08V2h^D!q%b*N&$3D^j-$dUA)$!~%-;$)$`B(ib<*p6ECRLw z*$uagXjOk|NhMGQB^e_RvtpFOw?@5XpORS zCG7sKuTIePWojW&3NCZF>qn1krK6Z}LFAxGSN<6uyD}Qf31u|!B^{hy6%a-@?l^+# zihT;kyINN#EVVKpZe-v~(iYePo7O_kp5iD5*Nu~j5Lk-xpX-9XQLbZ;_Hf#2G{vb< zK6>Z771>CYQq4K1hpuN48-Qp{6uxbAjX_>O3(yjQ`u-3Twj1-KSQvv>unDD7cHO$W=<2H$G5+d}XGEMi2Dx z)i-$CpKWaahzZ4ezvJQ-Hd9H;9S0>(tuYle=c~9%7Rp3MK0}xTl=);e5~ok!A-jz$ zo;_y(fA$N5zU_T?Qy#fm7}@YMz4J*7VIeV zUxiu@m&N{6Tu0M!at=<(>e@d-`h||mQ_K{{zLkx zAhgoy_2&&t&)qNP3~Cc7?VQN%S}rmTrSF)gGi%Oiq1+DnW)z#P7>WF$v9v}o9#&o;@E{%%Ynh+Kdmkj`L*L&^|!d7m+d zY~pwm`=USsx;sChJn7B4FelfBfc!P;iGBIv->F?~>xcU>+8SQo*0>GS;d1X%qP`R2 z-sDrx0tfFB^>T zw>l*_b77DA{Y1NQE+7Ui^Qs-2r8Wp*HOLrsrG=JaAT&1t0SRdMPI`Q|u3@yD=ibmS zw9n8flGyJ9UU*#NlHEhH`%grkMOh%3Mnj`stvly@{G#=`50^WK=P~(4t_lZQA`BQ> zXlDQa@Pm0xZhW_UcMm$au7bS6ZFS`#u*tarfB_ z8dlVXzBlCArN~u?01bU8Z+CWt3lDGa$17-P=SfUl4LZ?6@lWBP{TIGeKJel%o`lpao zWKGH8iGTcEg9sctzTC-6kDWnnX;B(J5!LG=WPW5?u{TL2vOM4Agz&e6eUP;xb|F$p z=18>co|67d7b1Yv5No8hW(m8C3*QFu3u!}c43(O#vtoU=RF*-;*F62?y=uwV+WvsDvO zuHEzs%cuBr<=W-O&TIK$jmf1@Rn*GQK6y6!_12a%b*ag3|LFrdHKmTsJ*$fi=MOOS zsO`^bTPwdO5_MH8^02sZ4c!Oa-l75EVXs=lU~fP6c(~NIDtOr#$dkYD!4zm4_d0FKo?5w;e$zS@q1v?ma>K=DdP`v2=`W6`P%e@JYG|x@+8*~Gplgt^G67I% zpjj$Zq}`1Y2GlZ0upGb&7*i6HvEuwvtWh<<^t)yw%}QxJOQ}DelxwpyQd?DQ@hxF( z@Y%0$vOU+DWd8k&mV-g2ngh9Iq<70nT7g|C+|}_X&A2)yr`@a9J-9m}6TUt1Y6( zJxKUd*vWJQHY5-!s$m(j<;E{iTkmQ&I^=8l$&z?KeV~gnwnlM$L-dIzJWGnRv=5tE zUH}vQ$>)&@2`-vWcSubkqCB^V!gBWv2q9dX#*l=m#tgigJ0tIzKg8L{UH9L!1((fz znwD}QQ364A#`{8&dOv8y1(+;tT@%B(9XlXu@(F>rLIXut`y=?I}D z#u#@SQ}?@EQ0#l#4G%vuAgQo8I%~=TUd>kxyf3K{PS(@vF@nY=xmopG!ZAUA&@B)${(wjl03^`OPuD1V^}{?Db^riS1R>!BME}MD;oDc>W_D+RKtx;*OtNNce*c(jb!B2S zXQbtcMKLc5pGfCy!*l{{c$)=!e|?1OX)&Uxu1nWYyyGtn`LG);M;FYN#)<{a++LmH z0Hy;sMhwa2^q~5)e&SEh6ipu?4o4vWpTTp*=n9c-G+gtvF}xcsaZ9v3X5{Ms0VlsL zyN*;9!x40kvWS|V@IgTiO{ad!g~6_V$V&{U%3$w*r{PSN-7?9Ot4AecOp5j6z?c1> zhdS_Ttbo^W`7cbmj(KQe@w{xVcGCz7s~oTJGB*m=P=`pU=M1EgAKS!*>6-hE&vC)L zO20pE4@7FBf*hTSZizRi=0qT9T&_&R zm{A&QBGwQ6SqJKy!$dF0X^GQwlw0H+_OZn?;Dhay)Jqj|8aovISX#SrIvl<{gClZH zjE2wA7P<*ec_U?|c}+zu<(oHCt?i7Z;$3&3xBaR32!oflh`)kS@>Kpmr=<*OrYY|K z3k^7cybB>33bd&Xg#y|XDBrR*m2bo7t4R`xSsKvw2-Oof9VOAHMS8Z;nW~$-Vm2gc zXZ)hsuz)E&{G&G^w;MU@xvI%}L>VSpIJ*i={vV7Y;dH-fN0Oi=yc!AyEA>zi=`UFg*OJ|L8C2n+`b>yj?vD=6J^apR|ZJ#*w6?~(y@ zaHk~a0)@;dYhBea3O@wjtcVzfx?IDdPQIZPkw3A$LjpJx0f0Q{#mg3|Uxjit#Su~I zW-@TN)<7d$eX#!CH*giBi203 zXOFn%ppMn%*XI+7iItU?m;f^PReaj5tU-cm3xpBk-PbZ_S9_{?ttC}1{dw39tOEtu!o zXp!G$uLeXTCESPVc}W=H8K}E5*nO@h7-e;nNQ_(jP;<@ucyiIQ62bJ(*&0t#A(^;> z2>RdZV8Ba~z69HUeE-`}V8V!KC3UfxveSri4c^ZD2oaJrzlSYK+|hHOX{;H=s%FO( z9db#G;Gu%_S9ko{^J~yz6lhnAIBo4E91_2neruYyh~c?=VIhQ1;y~8~NY~A1R`QP_ zr4aRZW!XamPRuR5ybY-hoQ9HWAWO|%+g?gnnDG)T55j6ZG!uBp<@f{(A$Yh3V#7Ia z)SO1EI%Xhl*61<7BFK1H=@h?3eqM;AGnt3bX?U^tcx?p+xC(#FB_noc%`@`k77}2< z_|bL_X#t#iv=GZx(j8BBhH&RRc%H69;{>pb=uV40uLs!jJqo~HGg8A*u{T1G1#wLl zRXcMx=bZ)pgj-Fo+r?w6xt-G~$NdC8y@cF7I>#Zx(i|PH(8L@S*o5)hhAXP*8j4%{ zRz*qthhFJb?a!&UU9e2;uDX$vA86Q=9Xsb<-IEM4VHE;PA3=FtEg`zA@-ajt2J+_R zTVH!A$WYrkIrHIG2P~1&_r;UsG~E}pd7=F)(Ol>*{PA_k@``*E!!4gkCac=J3}RDe z*Y9-rU)1S3Yx7mfx{;B^&!{aCSxJXby9qHH_wh1CRhYNx)~BeOh3!1_zWA#)`+$_S zCC^7LFtq=rO5r$SFI00d5}{wPLr6-C$k`M6Ku4>MMvKjQb?h|=H1+RhF1Jk+`iSCE$S9`v5|6xcely3mA zFCPrY&w+~?5#}LslOyV%jE2XaDYkq{>Xv+*eUBx<4=cFz0N?I^wh-f-P_^YL8y(~k zS6av@8Y*bq>Q8rJZF9*E#hbF+Nr|bg8Wb>QNohEXY0^LP({2-+5`du_hS5T4nmxpC zeJiiTRn`$oa96!np6@!&j1?_D2zG05yS6vX{nu0JnA%;NJ{a`?4(fB5^z__hRb6MN ziQ)d!gZif3gn}Jig`JtzB~?{18^^nL=w~gOQnr*lWbkF=irw#Mh)&MBLL@O}+p5m9 z(jor1SH<&Q9FYEWxgx3MaeXW=PEPPTY1ON2jfAk9Jyvvr_r|a$W>AxnbZWYZ_7jvA zHLjM280uNqek)pcntiwM^|3@mt}G2Z7WM}-6#V!ivpNDkjpbupnY87|5*c|XyMG91 z%C@Sxnl}2B`z&0GyeY8+U-8Y*?H$S#H3Yu)&)X-}7m$NF5L)-y}+ zl1W1Z9$@0TS(3{XNFwLHVc2Q4^HL)mQeR*!|Mm)FsREJ^EY)n2x?alV^$83(%~Z=3 zk6Vq5;N6G|OYC;5dX4D^rL(m~BUy~1891(9UcPnwnm|nX?K#=Y8ei8J=<7+|^AiUy z*|0009306I(@vTg~0 zHs}C|i?&j_aZUqj^lodRi%}asfk%b4wzmon;Z2*~92I^wp@+;ck7`cIH`K0m@|02C|?yb?q57RxRA$T^%WzSgH zbyeF^tChNUgL@{Y05N3N7zlIS;wN^;BR2tkXt|BAAs!$ z0h%Y^Zq`x;(3w#s{n>s(hsC5WCnat34frW=5X{Q0iq^p2E~WEx35couWGhO%Jpq?^ z(HtATHw2$EL=bLkQEAhQaKW$Id#pP++j z(q8$sH*?1?iNhhw*9=LP{@-wc21R}?%m3w^;s$&0T)&)s=ISFL6mb)U6(t5wH5@2> zf#3w`{2&%JAZKTmj>4{~tVpMXd#qNOtRX=$90zJEt-`sWVMN}%*Z^o6`lQvZ&VT($ zozsp9mxG!B5xnjPiBgDW!t8hkN|$}ld^mCAUh)BKTZOlAkx{+cD+4P>b5mOIY=TA& z-4ctKyH@)`?VA@pR6Re{a{f;&taD1DW~B`IwUj0q>J)$ZC*6lBb~QiV@4SA$6WmCg zJNN%D6R|bX78w=Z4MD#XMVRs0$G=|y4l>!IjJW_oClr7n4K7OU-fm0Q3rfd1hOz;7 zJ8AP=@R}pprcl*gaSJ~cnp?h4a_;(8>z2aW7gvu%*gi_R=yx~_Lud3aKC`^vLX@Ky z`hmfJ_9i?2CEe@~|4gBfLOd{kdhz<8B+`6&AUATl_RPO0!7E!@7MmV(g1WUS;OBmG z8#~7&?{No)|MHHfSfm#a(Q`1@^%InK>PNKy4m)`ayodEfhVu->-7-N@l=$6oV|mdT z43#?(%$V!}7T+;^h=^?*@;u>hJm+Edp;hwd78y7Y2`&%>Mx3=8GByAW+*YXT^}$y` z6|e^Y0RRo7R7q&xKBbI zq^JD!kOpgbyjWyRCtFM&Q_brO+Zi^Px$t#+iDPRjePuQJN?zT1(8_<*n)sraCj1S~w^b$3z_eXCs19NXsz;Xl>IzWMbiLYNGiNi37Jjj z^Dfp(3Iv@7VpKIPA*J#=E7;dIGm}8C7I&Dm^{!ThE1Ow2ZSl=~1Jcsz@e^eB3=W$b z^qKEYzKy?~BAlg_*=cgp*> zpP)sZjQ=~?=-|3K7ngEkHmq$X@OZO?mf8@g0rxnD@8NDPBmJKc7Vh19>2Sj}DiPel z34)nRLbYjBYZe}((B3&BgOqZLT>4C5`d0sfZ13--Z1F(epcZV#+F-IJ>L3tw5AgOf z!G@X38fX0LO)2S;G|%EJp#irq#pX6IuV5Dl{^Sm*z=eXtjTC4n59|;Y15rV3mu!u0 zL{bcKuflodls1A0t13{}U{M~BzO_JAWLet%bpXBR_6bF@d^@@AWI?#}1(>xez;i_2 z3}UecSXueblJl6T3IG39*JfsA`naGkb1Z&^-jbSwGe@8=+{F z|NR0Ql+9-d-n%8wl5KCi5MW1#3fU(XDB{t0gQzP!KEr5iVK3d6`Wfi#^hz2(hrSO| zPbZG~rmNh4>WxU4c*DwJsQ$Cz<$h7kxo$voXe+l*fD%jS8hDEGUCZ}E22&>UCBDD# z0U8Kcd{=tB5u82Tyd$GTkbz_LzY@p!_^ey#MOq7HTxzLF_C@+;rkP*_@zN6kHwHvV zDblCQ(dGzP(-omPf|`$D+&{v0;!}h)jf-Q$q;tpN5a+gVhx!gD8< zViZvbQGSwb(c=q!!Cw6n#BqjAkhM@hb48}zs?&t1*AD%{|RMq#cF>aSS4Wuu-D5kR(|?u}8i^XMsZirgPB6sTP*aoDA2)3F?Xfhe&<4GvqwcGMUS8f<@>sZ1@^ih*~gFjZe$3rLA|J>LO$6O$h?mKY)89m~h!d@T__J|;7a$By%YwN-x>zqw&$vdl_T0KXP10?Sf22tM zMFS{MtzXLokXVDX`#`Bc;bRQDSkv^F9jDxv#CjbRT$DqzjH}{Fe0i{zx z$2syGOZ9k7x2)h$UR#a*tgr+bB4qSd>5ZsDTP}rBelfv7KL2w#UQtFnW(Bue>A`JyW|eTZCk)t~kyMn5r`rE@8QMZv-?bLtz_PcWdF z2E=wX!#<6ADDZuc?6OAYX2=s+sdZG~w1I@Np_dsV;ivS3!=~Bv&-qz`0 zS{K0lxQ{_RGUS^aA?yTyb$tMc$9_s~>-;TQ6onI@CC{97=vRmh*H8(S?OpohyM(kl z3Do=Jf*@DPJ|rTpH9>xSG8P~=`?;AlKaX0MsYI;eMie((+4EwRI;@5G9N`)s1!kwcc%X?d@s;ucKIXdCWLe!gL>if=RX@ACvyz|q3t5o5o9vOLrvkL zl$M5ysG2ie$?t22R{g_#rdYa(=z+3@G$AQ4zniJy#`B9A&=qYaKh_CQt6SFQEr0gT z^B6pATdNA-KL7OX6ndj3-vldHcs61iNB~}Us$**Ic3fM-(oUC|ck=WqBY54!k|avJ z%P4>>yabD$bRL_c6CtVXrcY3^!N4tpaz*GIkJiX6R0_ROKwQke&# zvmp2bWHmKO**ueuYn8;MH#2lmi|$S|Uq9&#!n4Y`yF?5wP1jda*)1T7aF_$fTbJb0 zk&0bE6-V^(sBy(})}I;5vYAWsEq1E-$oC3l5oZIB z7X-t_GW4fwg&b-=U`Z$=($7IkW)c5mkhl6zFZ)p0u5G!NpY%ZHq%5i-FiNL}WQ6wk zig#+NCFN%}d9j=Ee+qPcc{?K(^O?Hvy!$HHsUA)1u{wS7t+*U8#b~$rF(BKeMgN4J z5qo>x2yr#vs=^(B0ncQVA_oM?lbnF@w7aprvM9R4*y0cdY2kV%tDQXR7xNZ_aG1&$Y}8yzba>QS1WIU{*RUfX$8)1mUg06dC|exohZ+shHbR>CvusWRSJ3 zvYIjKoK1REVsr`VH16@gR5kzbykSlH_q7HLA!|uwm$H{nGDaLpFSDxK%}dky7Kvkc z8IbMP+BmVD-KNcG^-8iyH6>ZGm!On&NS3vf&VI{=R;yxI?#LSk%|!Vlwf>AuQCeeY zRzm3z5dhL5BHlfbU`MVh@ILG8~0f2!hCD(mkT(ogG&t)ubY) zSiW(frse=p9Y0>rE908$u?lPP?j<6xj6K3M)=TPk2)%DkEDT&9!|nrd8RXCWWz}wr z;P#XlmAOz$RL2g>L^90DVAqXHCcLnmg zu}i%7*+)+k4R5C4v6Q6|3u@fq=oI8>zbB}+~wnMuVhn_9D z2j4gK%(K@B>+p?HPt)K=Z4A?Kqmz5QnlX(%5Kjt>Uo)o5T3G>WkKt`qK_&+gSbK$(N8<;UaQUH)Z((}iJm1ccsnEnc7q4u5LlfkGzmPDpZ&=jZi3IrVP`K3F?0IK17U$S z=4IP%c@Vj^cZg2aZ8mj9jKLn*3AfP4&S-Q=HR;5y8|DLnyp~Ggh##%8Ad}=;Z_6i6 zjP2u;<47~dE@j7Dr)|tIqf1RW4Z0MTobS6rO$^3Nr9{Kd``5$W)D#3t8|S_CS2F=a zPWV#3PdE!bVk`P<`9OM~y~?h#B1Iwhnm#8iBK_rYPH?p8xjq3%z7qNp%TMvD)9h5L z3Z7^8Gm39%0FZ=8v!~wTG~i=iyEr0c2mlOw)~+(q!7QMgM>H*&>f9Y7hDh@hy2CNV zhdLL>a4}nDPw6w@D2air7li^MjzPXaQcD}tUlMir%FPmd+&H$v?Yhdl=;CY~^GVc< zSG6&3o7u0Oph@6ZbMhQI7Gk-lGr!L7u|K*QTyfKTjgIaRvcO%nJiN!HP3P@}(;X5^ zv>)K4WoOtFf~-+qhQ5+Vv+G#j0^&ax$E?}Rz8h115?`58dp#I!v z$ayh27ob(LiUtPvmNF5T0Hlpa54QPc&q?z7!B13ce~=)=;BmZPQhHp zbg&(mQ?Yez+!Z>0T!+A|Az|R{R4#Z2EI109CldW@pfeeWPo!`Bkzx z{cL|BEh{juY>!B$eDQyWzA5Hw(N)=MQk5Go;&`BFU#Q_YR41BHI^>~#xbYI3>dsC< z818flo*q5%n#4*dmkzszz4qF#n~+J&$eKa zBfnxs_flv`0^r}vy#39MF2T$LLbOPLeGmNERzgRQ5(Z+DCy7jLd5d_VLONTS?E|_E|zbTVF(0?=*3B_^tl#+d!Y{8bjq#*Pm4u{Z%qSfV`$Q_YPq4gglFF&(YAVm{P-74BrHoAgv?$z5 zbsofrek{Y5{o1_gFZR&Fi(P=>l!oKuYc4?QKhrB7lMQjwp0R-E6RZi<;i=;+89omd zd{77+yZkaGrMrH0Y-VDUKr+t~w0|B7t%*HGE&Js1*!^}y2{jSlIcU+Cz?orS2Kc|weW6Ac{2kKZ zw=aN6GA|x0U0v6<>GT{uT~WXcK@a-)g=Q&V)c{rBkbcZde-qF7s)2^rXC|iafkLn$ zoS@Vdxt4ziX^+~pCq8YM{)pi+1R7|HGMCuY=2E@u=oyM`?&%Q+97F6hNQuCYCwZb?G+TF$NUm(<`iSd88E$DG$ubkH(k+7xIsuhitJwnxW#k?SGi+XD4=HI&(o;5C> z9|`}Oa4yBffV(@c!Y+Chd z?~)W){Jft?gfm;h;vMn|VXcu>39r>_7p+l^v$+JlEOdEI@o~A_J=ii5EzYMp2gw%Bwc?O6i zSh^UkuJ*{--vLM!R)2^`{1>s{y{Un>h#zPM`4bA0LuC|+sj?5>zB0obp6weCUZ4D> z>NS&H?}!qUSi1{mH&LmqW3aZ5oF1sT)do_|r`Pa@0>k`3;u5?uQ&u=WZ6b*yK$;}| zu-w*fianMNrr|@NvmE7-y|r1Y*m5L1PohSlj;WjD55Il zC0@PfhDScp&^7Wb+KY+b#nm9SGjNi`90UX@mJ5+phx~eu<1OHGQzC65wqi&UD6L%} zMJf%EZ5B_BG=7la8NNBe{j3A~jd%VNYD53YNTt!IJ*?y)?%QIzPJFeDP#9u?oZqF= z<9lR;FAXiIkTyAd^=xN+HOXdJe3Pr50!E|d4Zf_T9!s4d_vliPY!v39!ShMB z$_-L@O*_IB9tqAufZR)IbVOnLV6 z`-0EgO&{3AvD1GX?t?c)zC9^{uo!XL@6PGUBR82ciX4A0<4#k$pD1fC34_0yQ9>dX zCZ^2mRAqMxbau>EOo>G~*&qMtCFt}3M0GH@Zu5)N=_Lu;Jj25-@OQ|1a@27SryF>4 zg{xiAChQf{D0)+gm?sV7GYVc3blx5!Hr$6`&_P{1`597Cvf^9*6@+SQYkT=QKgefI z;Bl+1fgsgd8s8Oq4WxM|rY?JU3k1~9E24%eln_Y(Wlfc02tqGTc>t)eznz)2#a&br zKUB;8z>$m@K1)qjhQ_PHGiC^cRG z)KSUJSKKG>B}Sd%r{mAyu1q?+L*w)mx28I#!t!7#Pw;y!nN2!?Oi^tW@p8>HZXT6wZj!vgWZVEAf0aN>!pjk{8U zJ?m-*?pDvlmBbytBP6A5?7+gV%j&IEW**DTePylNX&8NC zw>lTDQIb&O4Gt&c(ENkHYo;3QfT?Nf=g&_Ky8`EwA`|&b2DWqur|waE=G0qPWo0kp zro|PB_8TeXDc`raSq@5+MJqIJsM>5EcGKzekD)&Vp3^AOI4)3NYPnO}&WqdBNplK%#1kUZ}W}w=F)REiT>m?X)Ix1Tuy%O9z?$S&Thjw>I>Vzs?&1n7CD zVWWfY=R}oM>p0K+h0AlK6+P~}DKJ6a`xzcfG!|pe1k2iqNxBw+@V|vP`B998wbpk% zU{F(G&SX#GTP)RMg>A)~;Lrv2TZw0JY3^WWikYKBas@d)LKD;K305C99nohw?`-cecljt@1 zrvt7(&;Y8_L7M83zP(aD>zb&cgXqfm{B~(#JlB}pyqtyC61TrqN8h-$5hD1yneoOl z4pFbU^uEzq-abK>#Cgs{b#;px5OZU?Z#~&XNro&cLRVXu44#b0g{vX?)PX15o;m0M zuu&H|9tJqQ=9FQA=BhM(%iUb8xSO8o9#zDY!MV;<;gxR=GE^k;9Xgf9&v<&7WwvkCDTuo;16UV9356 zsCX(IQVzce0~t#D$PeJaPBogtlf0n_ z5jslG%0kLk=R1VfAq|-``KESZ0>g}Q0O{T}yH6X;5SdRay|t)e%Lx?~gK^2hu{m4i z0j`eO#)L21YxV2|24SfkCF80!bYds9+8_Wx&NdvE!F1B|Jttsc&U)YKizssYxaMUN z>7Ch;UnRuFPz`+ZagZ5mD;c6up!ISgDc|}~nS|;t>Zf1(a~&HWeBEPnCR~(;(b#^% zj&0kvZQHhO+qP}nw%JL?b~10x_nE5mFZQ{wmG)}(&lg?zkzdmmY7h?@ymNGzJK@tr z6B4_gtsJdJN8+x;Ew)qBU-sxqo;n2yjUw@8hqk5esx}4Ci?TcURefX=%x3NZ99=d5 z*73Cj4mvSAaZb6&OsfdPqvs|wwP-Y31vN>NZ}E177wZiyPD26Q$L}eO&mpVP(IM(| zV~G6oqA_yoi7s_r(P`z@QePsZnlww+NZ(T3q�QsQ+%A`-h+zpE$baO9ARD@V+|i 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 } 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 #E-l}YaHTiA`y$r#7Y{4-lz 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

rj~+V>(%9J5f=#+bqYOw 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

uLEXJa!}6OB?4UxyK3 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%0Du2QsEjX9 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

k=dTeR+sOt;T?3VsHA|!6bcj*C1^E;$N^H z)h_g;4^l!Fu1!tqFgUU(K{R1h(zK;{iG4Hk{^r_M42?;w{oBqH|3=@R#wv*iPTp6{8aJsn`6*7 zdh^jZ<_|sA;$zS#X$^(=L#|W7tg2=`@U`KP@cYeRM#Rq8vW?rPa~8L6oyhE53dzT^ zA#N3Qh4EW@gwp8TM^t~j9HxSFOhSPhW^!KP zh+;&Ja5P$LX7>Y}!zS2dF*C7}Ti-GTmM1`}xV~P>4Oeqb`L?yG$c0XQ3u;IOlSU6= z82+({pNeI1gV(>Ez&~wA+ipHKg6>`!{-?E0d`Uw)fsT8fnUl~&HHNM)Ia+f=CS~7n zDT<0WALzx108Xj@+3NIP%}H-9BeDYo8SdaXT-v#}x-R5|>AL@ey|-?v`{}ntad!(2 z8+QqA!QBb&uEE{i-GUR`A-D#2cXxM!yWE}MbIvm}f1H|ot5Q?vR?RD*=(WDRyFb0; zdexIgaIef_W%+M)= z72G8xVJ8iQaN&=aOneuYx3Mx@R=Kau4FI2kHS=~9fu<$)W^Bco`@1Q0d{%)?Coh#pi3wq+W z&WS7@axiPMhr03*)mo=tyP=+;Ge#WQr7}T^h?!d*l3v2UIL%~S#N#dV5eEZkmK8vr z6_ZfTW67A8Vc|PVdqO{3Y)WN0-6ax5kCe{W(;XSmhqQ9ZYAcqtnSuCNG9XF?o0ZQC zi%yx~(v@TBOSi8T4dMHR<^^rGHmAm_TJb=Oo-Q8s6!7O4m!B^%`l6U%>2=oxp6dZN z6v@!JGT;0GfoKBmzHcqbWO-$KS6-Q2{LgZ|B#4iD)~EK~H-4FNa79BWuE@fsT$S!%TJ2jT_F^5Ud7Prb zzx7TC1e&OQaL*sP-qt@_7BMC|C*k)#y7nvCq&^If zoR!TSodNIm7veU7XLzBMO~I4fI^0^yZ7O^rBQ>631f)|FY~kw6i72Pg@ z17gs7z$x9|{fz#{v?luvpU5l^t%d~cX9t>tIP{1DfokZB1OpCVtTwGAQck652#>ls z-DP5YfgP;(30WU3N*WvqzC~aZyX63+Gls;OV2-={Ppk8c)EK}wOnz$4r z)38aEcHAy=y^GBT_aU%=!U?4c4R^~LBkK^@6p`K0VqP8nTDurD9o-z#b*3)ml#zI0 z*~q;W34Jmv5hO7743P#?#uIx;7DH*xSo-fPvy)-M687lXb9ItE?sYsArZ1Ie?6*bc zL*@=Ri+Wl_!5X{|(}xjSn=;xQX>03Lr_U3K(a~6m$VKGZnel^N$G^;F$n7+o!!O}4 z=Vz!CZ0eK85oUw7p=L$gPab>l`d58w<_+_EBJr|!$=Bcfd#UJJ%3i*!Mxi$>Ud}-7 zYd6E5iTiMZ&VV3lR+>PfKl{!smPQ}cij zjYOSFCX-pg6&=jT=VACZ_OQ;um2fU0ef>xVUtM3mBSNZCBR{WBh7zIOyUX~F{%|Mh z(LrWqj(sfBKo`{gBwLSQ#nEVEae;ljCs|dUk?v%@LWMOt@|Gj@xRi10N3C*P1o?!y zWxba|R7*r>5-smm>^4Be=1{CjRAT=C;>8qn>D7Qf^&%k!tTE`R@8LM zwmxo{#p!8E0Vo*7OPzm9wyGz?-#_nn|U{V^2~swluY>tBWn zIIEYE8C%2dPzq28H%xf^9@-D9OsO(Lw!sO#;~`T73UsGg4;!E5@>S36cNo$*Ky}(IzKR@$^NkZ+}gGuj8nIGf=C&qkXHb|gJwNLx;B7@k0 z7p8C-Rl~`mVH+o9!gP2b=s&-b+MxmsC>ck3*FFa}JJCCL2;k>ny@c*H^feU#&mN%O zfD6vQi^sn=&HqvYhr~TJ5E>h;6{_ePDZbPuUHAJ@PEj_@2H-86_6W>0JyD~o`D0m2 z{4?KH1kSfJAR?ML`UC#4tOWrrYZY%i!G%D}+P6!Qn7?OP!=XzNkpTfK7}|Ce{Z`_{ zpKHf6rt(~tOmVF1v_}H2b??q(ChP%|#FJX~ta&}mhJ)ciY=5COK!{7Vbp~H{sY4pb z+FNO080S;lNto)jJH9|rGP`}$t|D&bUW4@y0P8>i!jN^UUR?GI{{sLsz;E9F(*XSU zeAbk6kJyI&(q10VACeRj+p(@}V68G>yH;4s{*>qwK1JjC<0{kzPO6RD=YiQdtOt)* zi!KCt!FGS9TV3=h?yK`c5fi4#%AJU4X9|xQ&V#g$ZESyrRmXaZ#lQ9*NFl(bz~5c! z5=oZSh0_3xyWeL+V6=d;F8%mEp;2bKIy3`Fsvq}Fan!nY0_bv8Pw-#(7A^sBakeEs zw34OoBnV;8zff0C5ew_kB{5!~G!ugC5LpDFJCQ+l)4Lb^)dIpX9f_;=kY;~zl2Qj_ zOfTshen2FU{J@X3m@5bo#TwO#S6(JcfFCH}0;L9lyvSQW$%UnxdSLtk38SXv+*_Xo z)prM3FkrNr&wVFdl&0ddR9U{0{i0`5W!>ESPGgLvP{`{agywngs2=Birx&2pnl00E zI*a+`i-AA@vdE$Sfg7=nCNk244iJSth6 za^iyg@3u^5c`ja=`++`{9Zjq6erWC(sT?gMaWL^$i6Hzgm57^n7{1PEmnO&)R#jU? zn-SW}+H}dxd2^@sQpqo9NrHtc(~{AJ-4HPB4BkQLt!Kk z9@wfwd8OAJsNv}?4FBOeLKr7guJxI(NHB4Ah$=Zj_USI;>lV2DG!pT>1%;2E49)DZ zPqT{yZeXDtJ#t_4D+R1=BfGHClwNW$rv&>Yn1z@B?_Stc2|U~VatBItdSKC zLY2!T!Y1qlgxW9}aUB-6*G_h;{irV9Xs{}3z%_}=TMilJnq{XbS%mXzfRBLX)d^Pi z+EU|c75$NN82d%6ua%VAKSr_NU$ckjpy{Maw($2;Xk(c-oYtY;D&pI$1a44DE=26( z8$8v?ZN@+pJW+!0N}hkj{hL+=cT)rNsyRzzvWVJX>*ND$bSQ3YgEUj*g-Gjp3{}_6 z9M1Rn?z-M-8OjdZWO^Z-F;xDhw8iREKCz6@edrz$S7(X&`MwEcmY4cjj97Ns6|>1v z-TbvfA4!=oe)z6f@9dZB&e+1xuLLYk7TCP8`^zaLvpUP`b~Bl4oGpAzO2yF%OL>!- zJ!+raJRQz%j=Of6Uc77SEwH5Z4*4NlCt&9$JsfOPtHi!wkCI**+o#aW&^O))>AE_3 z`63(8jU7fk{J2dmQeF6v(AvQx1tr~UQr>xLG{`eJ^Fh4p7$2j}KC{?R5{r?O)FmePeg^Q8 zLYeW~mHd2OtGxd}zu#d@sEC0>>9sT^8|7FJS6hOD9`Kl94=cW=W@3v^R`7u>b$Q2_ zUZ-2TDrI5$u$Ioo@KfTB&d#PsWqupm;4ql6?|F;I95l)u8^dhJ{IwZ4t>D*Yu9MjP zGp&%CFYii>T?*im+%vkf{byPMQ4F{e`MbMl@!MsGAvv@oL1J#WEJcx>l|TwUm;-&y zD~S9ixKD9Wl9%ZA)fBt%tT)Ae#2^nl@2x)>w;-7vJ#tr?YnuZnQ~?_(|1hP8v&?GX zyuV8-G>NJM507|mU#vFAJ<=EYtn!zo&+AiTu&$f9c}p>xvpW z4*RVce-<`2(~*{kwT;Y{$n?1u*BxFq4{}YO;7VbSoeCfDK=$Mlx-X+tiLaPE?u#S%qrRjl$a}N`^j;Cf2`fx13+w-~4?1&a|cf^ArZ0 z!LGz?^mpX*6`a`ilT5M5aI+;jfnTzxyg6cf%XA474RWdRZLaO))T@SU*~^Nsc4v6p z%%Z>8^&+;78r3V?wd$L+McLf>p$|4YNiAWnhd}v=c4e6!zQh0|OrhzCaU&y|Hrcu_ z?v-o8Ko6;X_QvyIQ&Hx{F>g&bqadHBov#P>sq7Z)?wJ&#t-2^h8T%i zZbI3I912JtKUXHmSnVVw*xpMhsmW32rMor73~PAQ3jla(XnhxHtxuR&9e7MAd#cG* z6G%%%^p`&6Y(2eOd&TzncM2af7>Py+*>p+X% zMSr3@^=lp^1dH_{g^twfH?2|)Fsrqh!9S-r8Z|fN)M8CTW$0^-`C{3~D?`G&*O6d=)D*7M zqJl>G1bmm^uTRx}&`UEZysmR(cDNp;(g`Y zF}%3KSx3I*hfpG-%be>=k8y&94$Vot{=i4W)6ZCjtZlRc}%NrIKI;&|8OY@v7U0C%g- z3yJ_(K#qyQ)0!2}TVhIF1hY(MSQv3XX8*FyCO=|-!99Us#?VMspx z`@T*)=jRtZP=S1J@F>k@O&qZzez%%3n$ahy$2KOc?Xzbs0CyqH^Re|3FbtrMgLSMD ze%1@ppH#@D%*)?)U2<2lV{*4G^2U56)!L76?gdu|>Ik6)<#!PG}p zvfq1jksOTPN(`L0W{od+R^SpTKNjxn#N6Pam92#BJ7Cu>sXXG6G%A zNYn>+%!8_v6F=<1cz-b;EzHP>TW^zO-@svfQ>fmGQjZ2Vw73eE_S&j7@-9uhKl$lC zfNP1ryH))&SZ$e?{LB&}kcsdeu`q@Q&X95ZA)G>e3?NHbgfr}In#>q~hY`WH1YwIW z#w87b7kBhyoxv&R`8IF^GS787Q%LmX`mVNFq5uSS1*v(S+h|{z`HH;*^t+lGN>jWW zJFpM6Vic@ez@5ByGr2f1$rDPiLKrrIFi(gaRKd$C#4}~r?=JY{`SjE<&=WV zo(ghIwIQ)rX!=eeJV>9-NC0`G!K>gZ&Bpw>s5~7PXqh&1!bnx;rNeKBRaxZFcukEV z?VlYQGNo5Pc%~3XL0r_^DYPvU{KSCYXLgyCL8!gShs(@(U;ZPcwp;G=ZDyVf&@$F; z&Z<=(Y3FkT`MhHTiQ9_!0lNL`s`#g~nU-!5=@>pj)js(u6At#QA$~nQ^B1~sI4yS0 z>2M5zgp^kNY<`C-n_$NnQ_w`xZ-%a$JKxDt3w1tWbGJFNT+sP0y7AgEtFgjU*%FY-)E^m>k&qTzihNsEOUc>-8SsM&|D_ z@ZZ;KU_O!+0Y#k@%n1ZEavX`s;o7Cf$M38+)ekr&U_eqs_&pU?gB*!raN}hd#1Ovv z!u^TohlGfYq;H>&+6GIPs=6DPhl%nsqgzak3~!;vUU&mCfowwuX&mfpoPYa2Sv^*63Xn~2X%m8Tm@L;$b>(fcWcB6E z)Rk#Zh6nCo$TY_%mF43n87<})unSJ)*w;GaO==-u%Qn|bGrH(jkS@m!yG!$jvmHcI z4lRyVb3BA_g~K!NqeV#%1rtU=C`o?0Shtp@f5ycR@!?pwHc*w9PgSdyE;a=h=RkSq z{6r7ix{sj5ZSRj;7xe?P{pDoG9RbC5>f;{l{XV8Us-rEg=`EJ3Z=%$n>qtU(gsw4L z5&%ZZ8~Jk#)=?cZhd~=0=CM}%q8BjudhFFD+yi#AWt2mv%qt`Kh=2Zbh1w$;#4bGo zD{g@Ohdh^gSvK9*EWzp^qPtKDs>_Pb2bydu@~)`@pq&OZ4REXQcX9qBLH*y3wbHvx z%~1DGVNmyGT1#{;>j$Y6EBaHHl=kavazHjy#(!PQ!7~NFf~r=OL{Rf_|GYHIY!^n9 z*2ny*I`2|Zz81tX8W#JEFyif;PB#UW@(5mT6hF@+eQmMbGt*&Wto5;+ACQ7|;BBf5 zQB2`->Q;j2iMEi%(M4DDFv%PMlsEiiGDJeTa3}p-*PQN!?i;Yx>J-lehmRIcza>v< zQSF{bL2t^-{B&F`;?gvZ-p?il`kv)Vn|OD3+v`R(2(0gZt5FlE^+_TqNw~Q>%OC-L;fz#OGqvMCVGOF{)3~zX z7}h%S9HI!DK9cCPY$(3K!euNDNYjJ$OZ`N01y6b>hlu z8|I#QJMEufYG5E1I6q8R>r!I5@H+lC5k{^4CVwJ~P)z?b z!YF>;1r9(Y26Q?5ol+3zq6bD816|Iw|C7tv?;n?Q|I>2;c!7^T*C$X5Oc68GESzcT zxrJVo$D*mEjDbAHc)ZP`fDEpWkx?@6^QLo#8TR$KOlkPh+_qx0aEXXrjW8onRh{ai zK41=V)4y_%A+G&B&sUQ_p=~7mc?GcqJZS&r)ds$T{ExUrYQ}RpBv1&l*^s-^DzZGNMLss2<_mntx5pt|xWC*#)lp-ggjWz{D zL29`4)}Y$%Pi%;J&n#-~p^re0=%5N~j3)H~&z9AINBzIN+MdRXFlCX*fSoV8;I=bF zlCYz>XyOjv>8jxyC-nw;h=<>=y4mQU!srEp<``c8JemvF2Y@k`ft(RR zQrmfLnM{derKaH%wFRhPHXXvzA%wqF(qHL!O#vi7Mp zaxYfNjYxA`kPHSta9up;Ow>NyclS1NZ-{zng)s{S?#Z-;Adr)NX(@$) zisc?vZcgkB8^gYzipL67=O#YRLq76;M#Z9xIuXl_DDP;xEtmxC%5V+xC{bA0mxgqf zFkB!zl2`z&B#lI*mx==|l$_gUs3s9=@W?H8?x7A{7{(V>RtKwOrj&%^S_TB15oz0X z8uj~5Z|HmWT^H7FcLp^0gCo@Ya8D)A$#e7l$4A`Ui@`~BBZEF{>MaD+z}W*)>{hs6 z!h|lzv3;wr=8tHMF_sV8CHRmOY|U6k<*Pu?)67pkElGtuJJl9b=6)2`OfnKiNlC*a`=|>rdop z4XTGG6C|JwU$ed-s)(ZB9i%tlBs#|>xNz=}rjJ;+2y$+`;`)v6)<5&_sj<~sR<4>D zyz)`B&~##}l)iro3lL7lY|wx*Pt(=f^wN6@->5UR$f7B!zIY@Re|vCIphvQVd`C{2 zXqD(E%$|8zoJ$tH(zJJyqI%-If&G*VRy8CTz|NXTK;J2#yE^J!T7LETqqF&ab+&O z>1w)qZ(iu!+qMbxDQR{LKD4OwZ9;*oT@^2poIlg&wloY9dzjq79?qZx4VoU91YD<; zf?$B#cj=&r6&c+cC#7L6xMMcRs^o>^!1^97d`33*J7$>PXLDSM;g8f` z!hqRT^hjof1F7cpqu5o6l$B3(#O{8vW(?A5Z;SX-gE0fu89B&DlkCcNH{9P2BP(Fp zZJQ$mAU{z(p$4oUA$~F&#!cgR_@tvCu|hcf#)>2eBkJp@&>F3@^R@g99l_t63zPA;|Qg92Q`++x5UOcf-!jwRqIogSUy+gcSw45pzyj;@U~9{eLt^`=?m9+`lg z6OeP5fM@f+&AI>OWSl7a#RUX1%&fWcxXc5w%iZdOqk|oE#tXVy)MV z#&_yP{fwVsHL@|J=~E)DJ9tI9rVMOKZq8vu*!w)T`Gx5+`mcxIphOh}g;&d(HvwK? zc+zz~3_%i=a6hIY?4^mOX5Uh%sCy#-Q*FKX4!v#X8u)a{<*7%|#V00W-U!y6G+IgI zj2emsTMG<*$YvD(^IomkN$-F@idsK(8`51@uEyD%?mWN1lUM&)BZt+woq z@`PxPLU1k>sPWo7w}l7wiD4Vom0$hft^4mf=CVs2-=F>*4x0fl-~Ki+G*TmVxuj&k z(V>)fCdElRI5g=6`L%nLK}OY_R(j?!m>8@c3`!JE2No${>iNL+-j~uzty6-AH5hrO z)!MM~>x~~(qsoNGsZ~*8G{1VzxZuy`a80Odr<_t-7E*KikP?-g>Tg})}y+9D!|%SrjPT&Fh$hqsFUX~I4+n$@sJZIAT2@&S*jX#h4aVrG1T3L#dh9)pG%wjvSo#?P{!8iU0qPZL}fS_^T&hi-$ zv5XIpx3~40V~0<{?%z)sbP>)z85~xrWUdeNS`tM_2rW>xK#+ra#tW4p1^1{{sC%YZuQh@;Hct{pWHepC)WD6H>L7D8O^Gvx z-mN<6Yfoi!c^>DL^?NWhTMO4zlETownr%>p^Rn~mj|DAzj1w1C4@j3e)IpF~aDJIF z`NxR0vbHrzDw_Mph-Lo=p+^xhXjVMGHc1f@oxqQXUsC)%j*F~e{Dd2P3&p18-YNz% z&)R;UNWb`KFfb{30A4t1Vz+Lwm@{<~_8do9G<@eDGz-?%8nE-Ff7oOeZK3!ULEV6_Vm3Pgo(ivzBFe@(y0k8qy@C?pIRE_2 zlLOwI{w_NI9yZ^pO* z-{cq5%qoKy3{t5P2owJjtS!G=jJJr_gsrvmsF;u5l2&JEv*7ye>neP19HE7usO?$F z(m{iG6nE&IWpxQeR&o&MlEjQM_ypfqDbRz^@5NmfuoJ?_84-iI!av;?RDVo80Q)ht zo((EM@3`b_DhRXH*A|Xga7xQU;aa7bKQCabEYzCFw2nFBQc}DfXGc|R^K2xiN^Vep zpPpeVctHMrjOzU=rcXNtbAPSQZ;ncU5ZfY4%6_DkQu{C*Sjd>^4xaAa5B!WH0q<`A z$BFXaF?$I}6fCk_G4xR;i$Y-@qC&suL@RgDA(-PXxm*6ru*8w_pr3h<@NZY7#!con z3)8X8JPu(9cGljuchByulxitEF~_%A>lBl{cQLTH>*Cg^#8rZ`KbJ8tB0%Rj1oIbD z@(j5!$cf1$_)_J1;y_>vOxM<(I`nv%*q?Ld70HDDY1*{`e0cqzhU34b6e#irczIWv z494}F5^$-G4uQ13QD-N^*?4t5+3wcj`@*Qw_%^01n&h@}d#P|p-K}D*ZdFJ>XF{s7 zG(1sV(2N&hL7Wg)#g-ZZR0OReefy&ba{osW6emxG2vh|9hZ+%#8?fc~cUQbbk`!~; zRO6`vagd{ASM9;G^3#HOHE!#u9|+2YXz#XswtiB7y_#Q|qDB~GY{n7X(Ai2y%+Ojw zCkp8~0g?`+ER+8JDHZ&3@ z&P2(gTww`yt)^HD)w=dr zoAF3q5@u#XjP-N3%$C}!CSnvc+I?}>2&7R;XAo&+grE;acBK=b?L?^6_Ls@pxiZNF z@L|h2bS5t}lEu(?x`-gr9K~O9?W$Ko+yZQH%9KK2@X90{1f8~ZP45zdh-rsE5b6xB z3dSX#yfH|}l?A~VwI31!#p(kLIJjE7j^zUgxC4qUYQ_>c*;cuBB>?uIY#K!9+7Sc*b_bl>B}~Zd4a7n9(Dxi+F2OZ4}VM#k|{p z=V2lECwBr7upRVw*;D*>JTWXHI7CJ@K#JK(oZ{8ZWyzu;o#!jS z$$scMqf)9Ivp_8N!mf{PhiYy#On{OafHkT=g*bE#;Vc9SWn^pzM@Ci`E_PWpp*E?Sztb>W%Q?s+kT2s7DeSIAyQEX8MnMLQxbjSP^pns=CWNp3QedlLlmVGTfb9*-u%x?d%751BC2ny z(cy{GFsSk}r-THW_9=K%h3+rihH+xlT)K+5;BbXiW$mO;o~-t}Cr8Pl6NR{T6v9##z*_{8M6 zLwp*7H_&~6UH6Ctm{&8NeZJ4Q0!HVzFP*e+YkX1Dj4MK5gDh~kT;&Xv>d%hC4As9W zs^q_T%2D60B`4H{V#kn)uj9$&y)gf5wSSAnQGpCR@Uh(fPN|ulY@Gx0-B%4;N*eAH#`$UibUlFEeX&@gW?cY zy|+(5Lbw2S!u~QL{@sQmOc1ST^VO@~Ivb6Ry5L}l$~<;;OylLZZhd12mJ&RvK>zRI z;mZ$5)C59G0vb&XK7!wMG`s*+(FAbB%kGJ=oJuR>ulIHfV)CZSEISh0zpNMlOs@!- zer6+b8GEE+c(C~MBI!38Z!QSNfmpB_#&b~a!y*3>>EE5}#W&hKN!$pRb(VOq1&s9H z`7-*AxjRE*wt?xk-;9gXflWT?L+aGP)gmRlOir|FQ4s}eHT)%bc79h(n*ZpK&;)dk zY*9&iHI!z}yFejcRWN&DJU8`AY=sMc9mIDRZXeEpflAt*#Xb)g&nzUhy_DLG5w3YY z5SP6#tE!!a)(V^p6+}<*h36e?NGGbhtC<#$ad4qTt~xr=yGpPZ*gK_FC5f=H&!QFz zv&<7zga}9`8*C0=r{C78Eh#)ph_+~kO3!p3nFQc7G=#dXkv3zf0$;ct%aO?8Cd1!c zynf`AXW(7NUW#R&x-;4P3@24jv-UIb^kiQIUaOC;N#zi1zmec5j12 zzLhL(jeL=Jt9mXa{+}Lj(C1>KgdVo-qsvJPFb#dNB0%Oj0CuDPzc4RhpRAt1Fh(qm z+l=sb91E8Cg#hjMqH4Iw*9^O&QhPoTbcOrjDpVCLye;vHS3x0OJB-NZB$)4~Q@Y<= zi9kulckLFLInkoKmGZ(}?p3A7=^VntEbu(o!TdKJ@J7Xg6ujiz`;1o!J#u@Ik4pv1WoJF$uhlH=a+%2F4*^OXkYahCA{q34}0zxQ}lXNKz$y}=z(f_ z1<{%=cDcOH>@jXcT20;xMyKWSW=lgiSTiIY-T1SEOWW@*1v+ynzxi8jON%-xL7x2= z2N}C*E@lnL88bV!q$nX|Zm-PFcI=Nq7lkb}?yQ`(vz3B#c7aHAc*>Bhh1B)IX zgXf`&W$vP9-HQxGxkHNKUmZLatS9ze`47_u<^;b8h@ICDiOE>Q;PQ1j87K~DeFCxS zSdrP)ElEqPbVW*zSmU)bV-;V4vMGg?i1KJ*6naq!Xb)Us5W{SwB+qV2UQE*;wKW#I-jyA1;hJ}z48`B59PLp&VD=Z!O&qa49 zSP`9S6H7|l6PTmH1?v61VYb;kNh)6Oa{Owyh|G0ue1)x=&-(`Wo5oK3HmsRc-nczKeS6YLRs@+I%01Oc5 ziq>&@Xs*j)lC{dq>zlfU7723lSDiHz7# z{4;-x0PH9IUGV!##8|`wwgM7x?UV zW3r|gKuIX?Wjoj~UvK3(Bi}N`1-E?Ic#Nco`WWsvO`5gK45yJOg48^;C^o(fKNTa% z7oo@4w{%lMA56_<%HJF=>98-+Ne{K{;kll`a;PGp?`Hg8z8mOLD#`9$4L-cs2xpp# z)PR4=p;pPU#tY1Q{%j4`|0;({SwzO}iNz#fq$pme_{H`XEVesCHNE;KAN$ZOj-vk^ z{|Kh*l>gwDeF_3C^0e_AAB$oo#;4N8am^91$E6Bu^R{t|AJMrZlS)bNHkAGPAko-t zx0CT&m&uUC72-&R8z66oN1D-m=n~-+u}hIOC0($bQNQ!6e$LrvHEhaIUN*=5lWxZZ zI7t1!X#7E=4}=UQ4C=UQI$`G*SD3GQ6RO_DOy_5D>wVlVbr=k`yxkhghaoEmS65Ypy95GLNP^9u4 zymQCNDA({tIhCkzALOBr?h(b3a2TG!BebyZ(Z6}!? zO%l<&8TfSrn(~9VNj*vr2Ja7NXpM1=HKVW#XTW$~>7AEl$Qc#0DgTI$q5+4Qf0r|g zUiHdJX=%;OUWE|3X#M0@^vDrtC359SlE3Vb`)e#`BCmeG6Txb%*7usPKFU$vmFkSzo4Y|Ui!tqBxd`UW=|>&XrH3k9qb4DCyek%F#j`;`s^Icsl4KgTEgQ`3 zGLd{4QB&Wm)Ia-y7jU}RI7hiH7+1nICkrU>;5Qg6$^*gJ`P|~u`a^Mmz0(`zM{@#> zA~4n;Y#VTt^LGJJh=T%rB_M=pvEi*n;XWMYBs{@%0==%Om6$nOh5Hs787hPt5GoAe zx|vJeuBuR=hf4ybmjT`F3^*8x<&wpZF?3A*p+~_N04YEPSv9pj2}NK$`#m`iPQ;zl z5CI-u4lGwJwodhm2%_hm@LTOyPEzaE$D%X=`k6_-2x#L53o*1(jI5(t4%0S`X%C`k z7kh#PaFD=lg2=aZF-oYOd>fTwQ3)L9<@;y>tDiAy5SExqE`jmz;bjj$PQ+p=IfPJZ zL&QJl2>+_rQE?Te8y(Ykx5I6h!D(~hx#H%`_D_XZb>k-D(S4Db*f}T7VRbY4VyRTP z;tG?k5w(ji|51x#rb1Qd;QN7Ic1tdo`L0e1`P&)LCyR-TClkLaha(|6J@$y+ev#mO zWcHcrEeZH<`84ItzM`?JkVS&O4ah{FFxwgr+hfjRD4r8@$;~CLOmDXvnwjT!x4hPo zAx0~LAgt`U_C&s+a2@*YQbIpk(!4!kuHe+0R(V`+In5xm z_t4KJbhu>GVk!B!k=XDna(T ztE(@bCcqCu1azMxVzauoxWsffJ$zd~V`HC?#!EAgyISb;GQx&pRJsR<3$B5>99GJ! zz|9YfoJJ}iHk`16-WV%*-#A}sy*rWsWNEi46@EH@tT@;=b=-oslt^{H}Fdic%h<#A?Sdv*bIpqxN4dDu0Wvo(9JM-vb%C`LXz1>AMs0LKM? zm*nya~n>juyp;+Ao(z)5e5B0Fc zcb_V$KD_qGgla5cvR8jw3qsS^B=1`xn;+x)Nmi7T)qWRSM=xp&H$v_(1J`8vD^Z_J z#GZ&En=o{=+_sUuo68Ei5C<|vn&(3P@vKw>aj>a;Aqo_w*wq*NJkQ!R2aepzxw_ncqLr&2A*Yj*SdFvyC2_x^XSpEz7gv(rGc1 zG0-k)e7o+eGl$SuyNc)2Jr1sX;jH&fBszrreev4(JKVHO9Oh9pq#`WDkGq*fbH32im5-@=%vzKi@LqTcZ|*r6)^xKadhq=SwR%}Xq5@D@T4p{fjy#t6 znAS}lVhtWIZX@;hTdiVt9EqC9R+-Qe@xE7{a@)EYCLUKWYyBY=N*P z>jkjy*UB&3oU@{bz0g+=ru+D-QoT7wj66o$uIU+39@{G6qQPJ}%Y)*JZuh3jz|sS| zd*vNI9rDr4f&sgG?O}l3y%IhDb9e76VCVF}Fy~QwcX!-uH{Zm%P5V1o*))cJC9}2q z?Mzt*IH=nqFO4b%&-8`I-gY(~;sZb*_jV>X^QWko53#9&YsS-v38|386_VLaMecCL zkAp(+0C5}U(qC0JQLrL9e1VPxb#So<+XJ$ySUm<@{BFftGdl+K58Ll~OjdJJZF&0Q zq9(!4*SFFF(2|vn5#9S#i^AWOjTaUUIn0XcY`u(55}QFNmI|F{xK)ab;w?IxT@`ep z+EPPz^74q{LK&&ww&-^743F1>1Bk7;C4CC^l&(Uu>`%2?{2d_s$4*Jlrxb!1@-4bO zhO)|`73nWIq=*G(&cqYTSJKFRvJ71O+!pR6cuDKbUs<}WwfI;f!I`tHER9eTvt$k! z=3ebv0v}Nc3=zqe@7;b9BFtyyCTB;A$m|@Q*Ga|+SRNfJvk)q=F_p$Qs-+;^8ZP*) zld&1o(DZaF-CWjyU*|`jjtP1YrF+%r!=`0Q+0wqyNQi>|x!)84PAmQ{O%?9b>-(eL za7j+7xcERT;wpywb3U4TGMXhEgVuszm}rb+YWHT!tG_45%^_dVK2#e!aNVJw=7}@y zVq0ijBDUCrOHJamp`z}QmpI?~ik1rA`gH`5Wqf1MvZmmN2987qMluTptCm#$j6@>o zfFqIR@ihbN=Rf?klew1Rhjdi|r&(Tn5;3fO`_)KZcqZM0MUD~|2(Tw6utd~Hfdr64 zN1I$*$pQr?UIfy&oSfN{))-3LT=z+p(+(VMbIIfgr!+mDjrwn|$&g3Yp&hz@`(o5= z)65|IUp^IIR*nJZ+FVZ=?56RimA&!NnP7g`I*>OE{22UNN6>UJtc)wiF|>f8M&5_R z-hg4mnQuKvNvIicAe2O05iUwfOI4z@CX3%)dEYjQG@P7wG)*Zd&sV+zs z!3%|E4eUYj7;7UcO5H9uLb&>bJLtq4fxDt#bU|iUi^iOMU=%3cy)|mVqY9j~x zf9nV~J{v(BQ2})X@@B-C8u&mRf$<+5K@d+X5p{Cafb>PC-nb7#MMO-!EDYlnG1yM;TJwWDn_GZ~tcJco*o0&4DrN zIu)?^!Iq1bqla@2v;2^Xp$)8y&*OqWj5AS_ zq|Z|+RM(1xSZGT2qA>LF!u+O`l^0{+`en|2xL&=S?r{A!8(!vY0jmRFhFb0R?Kd+F zMIh#&-vHuJ|w{rF^Hy`8NXP1jK_32-$5ncXXyE)KGJqges4Ua8Zh3I z(TpVR{n5_&Dn{hD*fTWw<&)azsjWtoF1hJ>K5P5;?uioxEydWVUBjbo6Z9mn(E<#8 zJ>pN)7EU?;vEEjIi{}5k-oX3*r^Aytq%5hVbE~1ny^f7%G*0y74=UamW&LU`!Bwx@ zvOK&`vwVY0bbh!7W6}JuRbi;dNDQrN2kR@^zed(q#VkDO1GDCG8uN*8miwoBMkuMC zQY5IlIs~|tW{w`Q4D)h;^mYdP{`Gg4TS0_FsO|sN7Q;O!?84>aBWS{G(7S4-N4UD3 zvW0`YCnjeW5L3tFS;?rE^>GL{u$mh?16DMBm9R@A^M-|LP$u`07pJ?hQu6rTRl(sSeg4~k6qHNvI&f%T2p&p? zplMR73{d0EvgQaj1X_eYG<%tTFlkPninS=I^r5WmgW39sG zz3E;*vma(c9!auXkw*~gOP!`sl~PD^8TrYYIup^8G_Et+M99R2(o$?8w{`o$CGcxt7GFJ=11gOCdLuB}&+}c$TyP)~QgnMxen##WcG8{rWhPyAwjhb5e1VXfkP z_LidxCzW99Y&ptYvrs@)-aTq0j%D4yxaP+`3-rJo7b-NMRJsuQn2sjXlC!R69=7|D8i+oj&+iEfvq~mf?yR&x z&ZPma`u;NKL^y>D^$yCp_8|?lLD;g^bu>J7@$8FvrQ{y3s7H}RZ-&))U9)3;?8TBT zexdpL2mNn~C=3 z$Z&|D4G1mCYah@>WvP2#L*H$ll2B)sTuqgnf_EGM{@q4Je;Np10TE%gCUd;vj_X)A^6_BE6Hl&FIZPxIbspDnc)>iydjCm*vj;X<4 z`xiI9gGsFYaTlq{Anghuw#WAvP6xTcy?RlZrq`Tz zThGT?Ad>|y`gc?#1n*|I^BgAJEWgU(es-6f2-)84T&AgeHF=^C?P!PXo!Q3m>iE^9 z>^&p>{P^Lhed`ESBsiF=os3Obb3ilBigu9bBeIh1!x^?f5?@|JxqdKI*JA(CLvD8- zlMMquu->*BWkoI-OP)V=6)e^=# zsSX}yJk>Zv(7{uNz2vb%Re>&q82C%H3Ai5myW|AEnK6^aSb!*i{U{}(8S%S`$->vZ zQ4+D6vSkgN`&pG%R$UB!maY#YVU@4KOqwXEhdjW>tl%!vjnipwt`$Av=PH#+0T0nwMT{du zwgpfx>rk+`NQg?f^ozq$6J%@n07T==wE81fgF8sGG7^Us+7pTw$B}9(Tm^DaX!o;=Bd7-! z=?6s`k^8qnrd^qaB=UA+HTB74tug1?jTcV8+O8z^`=?8tdZ5+(2Mt$+CvbB&o9n*j zsE>1206a01YA31?ho@2KTXqCU&@iMO74=|Wz)-P418UnTp142vHjS7nfFyKiJ4!xQ z$HpnaK};$ga0z3FP=U<5qLPA*t6(^q8g=`Kd2~(O2`4DrQ_OX4j;`D44*5-)`NSCc zQ=W*wuopWC1p@5~ZNfqOFT|k)57Yl`h?^DX1sN~oSd#SK(mt_{yC1{Z0lV_T%VBo& ztWWddz+GV#G?%<^q(JYL3H2^k!?lYn_?aKszpmP(T?cW*735D|$-5liBPQuRcfaKu zY}(Ubi7D;$FsU1h=M)Ukpo*{G$&YM&EAeFagG?_7TTl=On`V-?cy^Q#nn+#GH!30; zF)pPp5)dlXwq*bwLF@8yY+;Szieszz6~F_j@?g)!H0YlovayxOTH0Kx#uq$QPdonX zkxC|m`633mJTMKe5EP-hHHVI{jOgd(i12axdM*g;Auur3rjQCa4eqpa?RNK99UU_~ z&_oP+@(hA@FTwRR-`ufA_|5Zq{y$lE7{TNGe;bJ=2DBCdZx%woPq4!O88V1^xbmcww-Av4 zR^yqA9&ONF92UXeh-3qnkJ#~Ae}`a*Ut}!oWu}bbc*m(pzp{yC1!sVrIBm3j^&P3? z8azU$onY;k{KIPXgiq~+vrf&JV%?yh3Z!SdNW4U&Sc!5BCR)f$7hb$kMvPIQ{1xv_ z^1GvYoaB)8Y1Y%)v?*&G)dU6pLdNiOX=r;E_O7$)7s3K4%U~|p}goBONdm zjA&hDV4vlKPYx7NK*;_^94Z8SS%!on0MXfyi7lx9m7(&X3jw4(GUBQbuo2~D%!w)r zNtRW3pp91u@D5cjDOpg+RuK86V}OVVo|gZ+Q2d`-V7lZ^Q_Vx2V*b-}GkWL3Gp20Q z{?|R##`(qfS;GIxfX~21zpL$^22+wQejjHc!vs0yNYb+CRE$ni5~=z0Eh;j&(uxgY z{wJ41qOr@7<~=d+ky|=(om_cgqE*~cI}#rj{a2o9yPHT(r*M#_x8sR@_s3nZ^=(ar zL#u7c|K!-*Y~{((?R**EO9_?~BusnrU?ZY~E>(U_ z15gM;{YHV0Jx#4D-=UOIK^_{&w63=|AV#3%^Tt4hLdoBQRNpG1(^h`Py*Binavj^rU^|8>8OeFD*SIpYn7QdiG9R0NpE6PRpYCn9k`y!_LBk51VH(+j;N4#rg8e=ERA zsjPBN6i@n}@)>lR;AQK-i;8@rC{^OAS3i0+UgzEr?7%491%PwZvMHhLwgpE+vicFb zDLyx>ZsesCB-B?O$k7Vr(82y{e7<+=d)I#N1O+n_=w%WD9!<*|wF_YN9I+f93Wbj# zAm@%XKb+aCPltG2D#doCxQs~r9Brzbos8uGokss%BO17~5fB$pWqmLP*6}ZAEX4*TiGd6n)*I-Up5QJyf2*cIs$$Sgkft zTcD=tpXHsaY(MtEca;i&%ABR)(%z;X317KS&AMZ24={`Y^3j+bNz@i%Be1(OdtMsy zLVhfSg@A5*nXx=#M8dI@t_^!$u6@V!i6Gb9LYWC5%Fw-r;25~__p+qY(!)v(fwpI@ z(-RfIXLxg_@jK#fZcS;KF5xp9F{(xw5@zdHe-wTGIq+5*ZDB8KdEso`sZD3tNvF#8 zt?{=eEX!fOw#d4l!8_pb+6gQLQH}4(#`10NO2dl4SJX)TAtW6zh?dzlqqOyUlD2sERs&MHH zHbt*Ai8%==91gB6bJRf1b^%}{IHL1zB^~rMhK~d4%x$MgYJqu$=n8O_Y}5v)<+|1W zg3NZ*vHzwIc;`I+IIz#n2!v?*(EWp(6_$VZ8R0ghns6Qj@~dUq=YGs_I)R|b5YV3% z_Ey{@Kf0r8Q@;W&d%0moM5R_&)fiCQjf|Eaz8}w1Y`^-`9zVVY;a~Sj`qr>&97|Qo zz29Pa8boBq!JlX;@m{YXKA~hk0TFz}4TgV<8#q79vlwb=v3y6&YS8M}o|bC8QVSH- zcV)wPxx=RticcK{{>d1S;;dGMsa}YV6fl*Xw&5AGRx;0{M;wMI{o6XGIHjjwZcyGe zM*0_FS8V}g%2*iaX8Ui5<3gz64{8tt7OZl{fBbNkw^m)~l-T^L5+UrqG~_@OO6A$l za5TPBh8a{7gEq6d0QVc|B@Qmhre>gRjsvvVS4u}`!|V%) zTR~)n&}y#_W$r};sZ`X{mV?~*=_Me2Qy1NV2hW;UuRKt=!dMH~7x8O1rPI{K!UXsz zmrEh)@Xd~S_ensqX}%Bf&I1?>_K$DV3Ds9dFYyAM`TujvbG;4n%=^GZKoDiPe_fDU z3YRfFnpl?3gmjd~vMShwCdAIq()I4VpagQ7KtMX^wF9&*?`XW}2^!%Q+V?6?WGl5k z_YC@no-D<@jo0d7WAB-0lR_Hhi0zVJTxinaP`Az)sy9H~TjBnPJQa;r2F$_wLAu5K z$TBu6TyhoZNH0>qvEm=H~c#G3$2cK+TZv&jG+Kf=(2VEYvYgqfZxJ-kp}|SfR32 zm^EK)Nt~1I&)Af@C!n0?K;4UmBV-O45|3(_c%?hW)`)YmfnmW-Q&Wj#f%D7Xe+nmqwdF|1D2yHf2Q{dU!)= zA)TfqDV;)>eq5`0ATHkDO9@0WKd$P9PwvSZPnN zheb<5j^H}eZlInn9mF=j>u-fV>S&BT=QF{THBP|IZ_}YRu#p8asBC8eg&0Pg8`OQQ z++`9j`l<1j1873$A-ZTf!d%xzk;sQK3DJDgc79C^2gMd{@K?!L(tdv0D{hu}Y&y~j4Zo>rw(w^YP zV;kqAq`~MrEX4t8-%vk43sQ$#Gdefkvw1<<4p4g&#}Ir^qy)GjIaO#zG){I4wTi+2 z)NgfSn%?R-8jQ{m5soY+91@}DB38ZR??(Oq`{RNJmkRDLCvWN+Fx4)JvUV?DCu?L zrbo@%$iz5_le-Zy#@M9%2o{Y7Do&zwl+c}7m`-Zg7_dA8^1DUQjhLya-@E5A0vKV_c?->t}_#7Vd@+zfBpHio&2{*s9Tn~2_pJ1-H(zI5W zP`uE{1$~tVJW0EA)(^)^syp>Zl|{vKfdwfh^~Fq$No^_{;L1u`Pw60S%VV{H%aaM~ z(uIkZ??)FJmV8|2v&0eeES(NbdTM@#1I~G73nrQq|Ms{BJKGvPl{}@K9M))9n-&% zqL>|eb>Hrga>xp7XB1P%CXerbPrYK{kw7;l-^vyK^{q^)YJdGxmbRa;1IRg}*MrN_ zzAd-BO;@4lUNbi^JAWl&d^~vz+%cir_E&UPFVQ=0Nm2o0{FsRCD;WvZ19HXK&9cI^ z5Z*w15*IW#&F$XQL2f~u5T>5dfO|{E>Y7K; zzpp)Qz+Y8K51~Yx2zhCpSzdM=0};TXgcRJ*yB|_)g&x^v?mpvTVDTFb<4w4l7qN~X zXj^lHTUIo#lWqR4z=9jNc?}eC{-)YMsRVC_|J|ecKl~txQ)MCmK;;eQ8h|q=w(H%x z5~5$)-ZoS}BImMbJM`U~RX1#9b#OK%sPFKG6F{mkr`sVkT+pN-#L!l&l9vm<$6!bc z&XIw$!2+LQQag>L2kkuHUwMLsE%15SN&)YWB280<4~6m@Z)gGCERCEq19pAA3uY_q zS$`2VIauVGE+ z>Tc+1^rf7`KS^UdknWh+tY>Ir_l$gxU-oar!ae#pw=*>U#R+$yWcq#&c*?M^5Cb`Z zx{xF(dnPo2MR!9hnxb;P*~BcKLuNCaq0K1+559A z*$hkQZ4%}DUMqp^?PI8{3>ha=niN-uEDoKC!^6!~0dr}}@ zmymLq{VXtx@fUk73&#|sUqo)yxkG~2RQfpD8a%NgBdR*JH|g12To(6$Zn~!?L<%N5 z5rB>44^Y=oPi?z5mZ#(axcmrgRH%yLf1Ho`L)nus@js|?wHlLvf<1^mI4qNb!C%c%w_o8>VSXIH^c`R& z!N=u)7kv46@W0H!NgTn5_(IyDih6&uv4J3{^f}y9*o8M@kAt2;1Ju8AZw1Q^@gdot zlokqE$Un}y%W=aLBgl+sLMtW;!U7vn`?|i}y%p5)A%jHIS}&7qf(x1?M~x1sc3_$A zP|fzDKSko*oeXjQn{nN?>6^f_DnsbfA=IQV?whS7=HFrESzYLLGwwTO6W-;t{^wt z2SU?h5|b-xYolM)&k5stG%AeWPha0TGxVQ(L6^W8lnKK69&k{ z;^qY-8Ns;2Cg--g!@HA<9{2`KLMklv1fLMX*^5?--8Y{*k5g3J2NVS(F zGO7{ntVXG*0$}IEF7Q*qa<9KTev0_uImU?R&_IfGo8tp2$-cuHE>b@d!?sR5uDlUw zHvb=27vyJxugCu`0Kd05eR2i?`~PM%V-TH0M4W(}Dbo{GLHom>`CCg_o#?sK4cbpS zOxSY;26wIG>RlSK=>Uk1Arvv#>SxOcfpX{PJEifR7V;%$Bk~OjYU=WB-2%C)c0E^F z=>oVW`<{?vVjwPtc<@iJU$DPs9i-&CCqk>lVmQfy5Mq(r$YCNbY6>NZZV1ky%CDW_ z|NYgN`<);0T(>R|4yKup`k=(21GT5CA;&E;&oGnvI$8w_D7{d;%G^&Y#Hd zC@uXA4%h!3se#`S74}mcac^$ud`<}!uLavTZz5`bw!1xn%7wC-$Q( zbtsI=hNAM@dq90OhnSL=OdFqL(g3riIdYGqO8m=Lpy7W&PWP!fk9N0}2L?2Z9}NRJ zJ^62db8t15=M1nlTJ%`(h+O)0LH?4*l@yJz!FH{?K~79}$)c0^gAKaPk#hTodX4t9 zs3IP}qc2M5=~N9jw%CmvvNy!}Bk;;5oCHJqk9$}zo&`fYMd&t`@Wko;pRDOXNH~b1 zX<=H{{TW_FKuJfo{Sw-*BfuU(B+Xf0BR=j*#7Y41BY-Vx$=F70`hxNJ`a(0vY zzqAZwh?bw0>8FJcOoA&obfZ@|sH|;OsC%36(Y z+tnfipWWD!9_?DT5IRwKzY?bT(=(CTY3boc{l1^@6?+?cK2B}29=TS zc*+S&_SRJ4TNrcl^L|9jkgypmR3CGQbmT5*JEFKjBW7|;-%-m%Y_ZQgcV!M+Z_T@b zTxz_vi@Nj(lTm@vXDR#S%ki+LV<++~^D@kS7_;N`w>A-tPXae*_z@({8`A}(Ldvt- z5t_s5=y2Cm5=Yq)!VBY)JhyASiS*}@sVPP^5X@a2kyBx;LLPw0^is^w0`mtk__jS( zOluWCX%I1TJHtbOlDk6GVcCn}7uFhjC(LcR9qg0iSPk_Sh}7Hz)*!?1D}G3GSQxx7 zb&v-D1aE(<7UdnXxC%V&k7{^;rc{8Mk)wKsUiiM0C9`g@bIa5kJLZ{;5goh8j)7QI zSQ8iZeQs5#hWQz`PbzI!AbPE31AVXqFDU#NbRM}gHVxDsn*vn7vk<$A9BqTRpoGz&z;>RPr7hjp9n1cHxzIhKu(;elR zn{n@T@aHvjYT)K~HBc`ktF~QoRzc|{8cQ4MS_&>v2sHriBDOSUItWwO{ONY)bctLV zkf(O6@NR39D5yxt_R~fb-$Mrn)KZq)&s48MJVI7=bx3|!MvB|eT)3CB9LBI*k!bV- z{g92y#2K^1V4Fn3I!`^xIO8Haqh6>OpBezs%w|_5+FztWxDb(-d}RTlEV~+bTU@C$ zm6wR^4u;R?l(T{LeUkIJpP~5kX*9>1)3wo4_?U^j@ie1(^xJ-aWaQs}mZ|dTZ5X%m zsyn3YYE{SrOKH=f1s`pHkpSk8VAg(&`MVct!@e(nP?)sP6#Xk5N^w3fD! zC$@Jf`%&6xm=?!IAUx&WO7%sHdSH8zy^`ZW^vA3cC=Nmt_U=87T=6G`*pO$INC1$( zoY3wiHU^ZdOCQ3v(dq2brcion@+LItf*1kw5Y+;ZXzZrl3~k>UlU_M%Mdo#+4v(k(O5xS z!5_iK;d#Ak+@8N<)=?TzP_%hN#pY}4a9PmvEvj1fT9Ds6-UIG5JdB#4yh3;ZK!d6v zBs|Lq)cZO?dlcR8Mg@5`F3w6XE=t?vlymoIX4WlOVb(m>v~@Y8S9a%?-1HvB zUPjAVNGdjBJ=~XEgBOrrwn6bp`H-uVjUu_p`c^|UuSP(NF=?Kh$p2WL1lG*X7Qsut zeoHQ@yzRjlYt+J{l6WxKitJ_Vv3U68?xTK)Ty#m26&pfIYMcxdkds>O(;CC;=bmNk z*1qdG%v>+8J*TJc2aUE^d0((i*i*o;M@*d)C;5R%%J(qh5tkryfWGM)toov}b&pS| zM9M{(yqRW$v&T%~lThH6hGOVsLq5n%ES>RAGg z{7RIKx_69)IPT}?&NXB0H`H0gNcOS6*YEJHv_KPBVm9C6lu8N;#iIir6mr4DENT~= ztal-t?8zC;%7N>pXwZ43*mpcBz`J>|>AoJbw zd&VxMjCDQh&~S?f*cp_5f<>efadQ3vr1`Og7rr_5cRDv|=JZCK@Ufk<6|yU*$D&a3 z>Cv`Nv0y_Fpvjs^6u}poyZ#yulYJfAL6uO$Q$1c`kq)xmsy>W)j3_)XY?XdLJzKkaiGssliwZkgu zPq+Jx$)BHZK-Rr0;b=W+`%x>ZB243NO^-(=ulNE9*(-z&7ZoA`yLG%Pp3WN00Y22W zb~|nimM!ESP=HC#+!TC9xHqy&Kh3glJjBwG1jV|TwqfaaC#@y8kYpCezc--ZlZK0* ze1>uoO94XWN@?MH?h}+xC7EKV=82ANGg2SN-5_+^M*_Hn*U-4duNU{BHwyE@5(n5~ zkc+2vyLZ{6X5H-&GB)wmMgo?SuACO;1&Egn`JF45;z;i1GYjekEyRo@e#;Y;0$Ofh zyO()y?q8_E$vUMmQJYwGyYC|FSY1oGYw}irS623PQ~N*7%-$S?<=@xyPLX}s3$T#0EqqX;}0}@TuxKgKwS+T%`2*hhbYc; zuPS)2Lk8sb>k&XOAyYOp4ey+5^oBXH)l_J<8{EhSLTRc}l(do(c48Rxd6Ecr)JL5z* z*4f=s=E`1hR3H7xs)NvYxhzMGY2$j;7ntj80a%BWnq>fQWi_t~!}1BV&~Lg}pbuOo zARS;R9o2XMrwV<7ABgAB<=lKrW;rvvna^)WxBUs8|MEOmKcoU{>(s|CS&>@^$c}5A zex?Xt!ZgPrm1B;OYJech^ZeQUY7H;{L4<_Cx>P=zRED9gMsFL+>Iffc zQy259SL$#o*>7~Md|w;X*g~g3MZc@AWLnRY!_6>Rh4fwL8{WY8#kuU(BDfgxRqqcnNoR#VC2ZIHdMG43tFxp64&69oJz9TTH6qe;x_rPIR3 zLXqn!Y&qz{e76CCMdZyW<0Q~lw${#}Ew_F?`+XBVcBoLgvniFb)G%GI3?B@s{VAXk zX|UM}fGJ`?rH>G~mbPoRxMs>F#)qE4ZP+-Rp0E?VF=>k+g0s|k|k9Pu^3W*{zzK?MD#4A7p0gA zdwT9SV>g@uDqpI3=%hM!68Z`M*snLo#qaA}u{R0I&bL^tlsKqL9cO?810v?|YuvdO z7GAspmcj!41MmlA#*+pfRG&i^LHI^BGQ{2gnYqJymy|$t+Et(|Fv}{RvG_~`jhPF1 zMC_~8_WPOhUj7=g@Fb8G_m-lzbY&Dwb%igMGBSK<&Qo*M91Evr>i}rv?tRc{11TBP5tEOwDb&2|>e} zZCNJK9Y=AA7QL8bR&mioa}d`;I#3;LMrXRzu|;Fuv;&Q&f2}%mk-^RSUtpQ`u@!+A zzl7|K0Xu*jNb&2rUZOd&m6N0-O{~DFQFhduc$OfJ)`;|FOR=6d#rr4==hTQYGbG>|G!OOY5^#>Ih$_-ZvIDi@avwKD|=6ruF z6C>@8!hCj->QFl4YpZo8cFYXw>GR+Nau)tGMa`U4(We~_TrJj4%c%1jf}v?3JdQPPYPU06#y>N*;1 zJa@d*Kv@7?r~&0D{-Y?B-j)WmMFYhehk@V&iWSS8$VI*U7Hl~_GmI2g&K3O-8W})$ z7b;vEzvgS{_|&*~7+ePK{6Q~k*~Y4z?{mI;5PPcM#=LFQ&ePc$;MHHpCRqjmeAaM+ z)_lKh(JwGKboJEGxN1lrlmx4v2iD|)P^PM?&&ff6M`{k!yYDh6<+o5g=M}?IZy$+A z7t&Au04)%vB%-tVtk_ngz9QXG(cgPqn26Nb2wFxSwM&z1@`7?U`zH}oug%Rz=2eB> z?Sgj}g#2wLa#0HMj^0)31C@$|FgAQNg4h>wu;xz?7hP$6Be%gOSW*@f0ep)uDlf=| zW$!T=0<51-UutHnbBS3Uo&Mt5r8f2!SbiZ>^K~L+B?b^>lIfXIHx$?#(K?C>HfUn* zOn9_%9Z|B;ZbFSpL$-$-DbtA<=htxm00kpB7`AR~6$BNydqhBKBkjy(ULoPZz+&Df zAtx{rN?oIg9}M&==Vd712*58v0RR9ILGb-5_H&CNiMotW_A;3j3iFp3*!ISBaw)yF zR><-Y8K4bpMqvfpjVgm#YpSqLvkq##<%Ju0yugUB219Ozi{-rQp+?~H??{11o9-6f zzZ8BFz~Q??`dcm=wyvK<$zrMdj1McP`&ZnL3KZ%+nae8 z4%m7~7WT zhAMvO2+{c6i5_ER=tIXM;22Q8KlyYlkWC@DvkRo=g$Kx4KL{Psd?`JPZEMB?TtOBv z0I*-;&{HXDfrZc7>DO9_dH1O=?8R25)%qubwXVY`-FmkmE`$_iOQP;#UG+!3#d|qA zsa#2C@B#117Z=%;!5c6GyQSqW1|mAW0i&z4cvJZq>;LiZ)!~~g)Q|`&fwA^Lu!A)% zg%fPD;1Ju3)-O?9-UhAYE(G|ugB?0`_I2k7VonIjvnW{cXrU!W%+Nc2(U@ZK==it0 zF~Mak_Z0~i$O`LL6rmh&H8RaM-<6|PPf4bc%jkK7n?!EIC6vn&!LCrza%xY)YIa38 zUPVV}g&Xpdv}gS?Y~j3-iwAIIFPXgGZTMAy$mdt=sw2DDm8cj~L%P`rU&KUU0p$}L z3miV~zKFVj<9cya4%`!&uzc6@*}3Xf1QayEBfD%w(E3F!-&k;Z@422N$|bURTF%%F zdz*UhA?}1udp>;$IZ@_t#ifw5V8jUP~agEgfcq+A+$yrRlf?h^=;`~CBg!lJHUHN&5Siz%Hk-_V< zhn9EjgdOgCrE{X^l9Tx>Lk7m9Y9B{|y2{<4imS#rjW=D{ucltb-ZJiBGM9At2s_lX zb&w9*$oh2k9kFI8UU(y_0S7a;Sw36mERH;r0f~SjyQ63Dx;rdA!b>q|@L?BbipZYQ zN#?>lNL~C?ZZvu{ujXH6>il}#Bax;3qjkUoGR|6#ai9D1JPz-6C={P~|Q+oxIo%c(s=6j(XMhx`cir~GXu zBL~wx!b2RVoNehgRrJ13Z4%q7ybOwHl)uhb+VbqL>pL@xNthJzLgF!jS!p4Bmg1xG z&w&C6obsa9Ao@QP<|cO}?a`jiB?8U(?5#XGhdQAQXJo=KQ{w&h1DSxjiMHLeuP-oF z5uAwn!>^VyFJed?U1NJE7YNAU@9M%}v4VmQA}?5Eu5lwt{>vDR5jxm#jc6e#j<@U} zjRigH0=T3#d18a=emDC|rb6yd@lHSLl=3D~RC(V%Kv<1Z#PRb-0Vo&2N~CWN%Ft(F ze!M%xlQ05N8qz^UDVy=P-1SQhrKKV6z-p$3Qt(MgsHt8N6RJHhcP>9iT!WP?R;`}C zCe)S}e;9XPl6wMyJsbbJRco>My#=M%FGwI6$i@RykMPz$kJRROX;Np;_GLA@yv3sJ zS{`C<>Y~<=m#39q2nNXcu6<@%IH3M4nrF_B!LbPjdsMviN+7*fBJ3abO$Q|&xRmrxBAEji1=anJM@FvPrYAjw1W;q0#9Cl{Ckmh8i4 zg{7F{U9}3G_Ot3x5`q%thbKQrz6jt5+Y+_##Ytgo*qi-x+5l3>9iZpjPoFtFo6fk{ zU&WY?`8>uux8{kH210OME9a&F81y3@wYd+YAO>NZwS=mUv}Qjyky8tFebk@ZXsg`i zx}89xwkWj9RcXykmJ!D&BH&7u$+!qb`0u(QIlG7NA^o67eTt^106WcEubjowdyL)HP=s2X1= zh`j=PP?}b6vnvlTnK91j_v7KJ@mK1l?Q{Xf4*|28AkI&Dtm+nba@aN>!9#w%BM}36 zm~Mb7ONERC)95>%`)`NJEc*K1r<<=kEGw_G0Oslh&*xi-A&4 zb4?=wy3+%#0jCvw{y{ENQ(AHTZTLRYvDBt|a(p^ZRfkh_q?C07U_@5G39YDU9KCL( zn*(uPC2hIj0X?BFx4c)O>$|^qKoPR#ut}vzR8tI}$dtmf@Np{EwFAsla>Kcb$$;~} zwQ+9tW6szh@qI8ek~OKoFU~)AY=_kGu(0+{5Z|7ekuqf#+S@4EGrk(|a3|Kw47B`9 z!pWm-SvL>620^TS1QtM-wUXjwLGE2{j{gzpM8YQc`4r@Hip0kK}JiQ}jt9LX{8(h*M^%4?9{9a;lvo25wq&jTKe`5r?OuiYwIhf!cvGG;|z z;UaIsB_d_gF_S8v2``@tm8_}p5^&x9 z*&lJG1+Vbu58$(#jqb_eIIqY35OP7LEzaFB_B8Sjb%T;OTu;#zoBbx)H6$j;v z9U7X_oHgGCI+5bw?k9{+rNEQAf#pao+FWnc#&%on`rMEglkGMkHMrI;z!|uIuyaqGnIaIq z$$=f6?YAjr|2i!9l5=VHe-RzQqu>esz~5*qh-|F39&QP>CV#VMi)wCghb}}Jf@_(N zk=R@+$77R`_JSGjAgcx?=K*0D7fw(~j5U&Rsdn?kf|#^u6Fw~Sgz7MLsS)C;b?qXM zsG*1wL$@gDSA}Z0;<49=9Ab&n@S|ylUF0%HsV2j5UGVRHU$=#;4;)fH%wu=rk!zvB z5odtHIVMKSoADw@k<$4f1gwIFv@@Zgv147QBu_~rySOnVTbN)clY`wJmXIWknfV?LtWc!L(c10Rs)CylWXLmLZwejQ z_AX$f&%~u?CyMT5U6N3N+n{OXbxml{vN@-krs0ccL4pR)fT6tHYdyU5@sYCX=_^h) zzwTaBuwv0FGwK^SIiPE=Xko2n(jtlV(;N!%>@Mp_yaN1j0r7+8?^8!0kJ%cmyIAXM zxMkDm5=ACQv=~z3I^d5J0$h&tp-^OiqSz+NK#nS;C=(*&(O-i zl{CJ$Q#VjwVQgi%V1;tH1e~bitph?N7HY-cr&PM0^A4R9XHObguRIO#oom|M zU4KjKxZPEBAZidp6XWI9J8u!VSgD^k19uh2DAi29k&nm+==m{04HVdbdIz12V#|AK z4T{#sgj}Pgc$Vuex+rIiUhHh05Ztf3a0p@_9hBu6o^M~1&}Am)P%+x3^tsv(TBCW( zyM8uxXZ(5SsYNTvG=WwK0drCbvQg)nf2D92#lpAYFq!M;Oa+I!dtt(6#!qac^;&ah z0K3-tx3|g~qVlbXeKvjybG1GKA=NN-v%I{g8Q671_SwY6fa=la9f!Ox#z8hc-tGm2 zfrnVIAMCeV>m=EMJ8_=Cs{+2nuNX|+%qBIZW@LI#?oV|m^xu73!pyDL$8@4ZmC{gD z#+lpLA6|yYKqc-?L(PWY?tpCymeVI%V~oi|D5=>TH0$?U#2?^yYsoMOg%Q@ha!x_t z7#DND{li^D-kJRxXm$u;VKxKhwSUSv**#OnD5hkXD~an}z4e z#DT++OYY$e_;**X**&7H`2+4Vfg${Ad8#PfdWN#+;!NNo9P5D;`bX#ud_bLEj^P|& zw*B;wcl^s@MHWEMR@04F48L=`#y2OS2w%OMX5+}FRM)CrJeq6}Xd4C5oaKGxB|f;! zC?7k(_fv6_<9>V|WRL0%K7+`y@%hlpeMyg_RWU3N1u*v-<`whw{oX&vVff)7KeAOxTMe$2i{cv!E&%vx!4gWb)oVLkD*6;VCD=7-! zlW4y78c0S8R}J+{I0p%Lz-AGgv$2xV$ZWsGTn;L=A%_2RN?zZOdf)DeffDVMj}mp$ z&Mpq-8-}97Dnw6Y!~)^f`^ycF`IUAiB5VOhOekQ@@PZLhxv-1@HO1|%a8e02Xq?s` z2hVG0eU1W?%n&5~Q3jE3KsZycZ&4n#(xQ)E^#Cx;z2uFV3&1&+o5t|9vctM;=W^Va zv)t1#wvCoZ)?oeyMf@ja+v&n{ob#8NBl&KK#RfV?cdPnITxSmq>k{ZFOR<UBs=5!T8*J3T z()K^u8(-yb*>q}rrj>c<-R$<4A+pIoKfx~rx)bXz(S1ZTh8van9+9_ z+9<;o`cyHcy2({?_`o-y5HPdlVm3^?6WFqP8o(MsX57qM@7V--lYw;miJn&O*6dx3 z?Xt1G)awRBWVqlrP4NmY)*WTXL^bZX3U3J^#xHOOOa-*UIP_ zLZXf?yc#Lo_1XCSe%InmIisH!T3!k~fz+kvM>lh=uI^j85D>)zhl~%evqH>a?ec?t z=0HI7X>xz#LwPg-A%W)OLa$Fg^bZcGaHdTTI4VHxKUl?0Qlrj2ctmV1Cm37fcH zOEL%fLzqgz@C*UdPFY6Ihd{ooqzdB4XHV;~uHfh~`kBbOK{Z+{nl`7Yf(+xC?)lD+ zIpcnnkkmM8M%@m^*adT3_`pTV?M~~*^(RDgKx)45Z3?wl8WE@&um@m`Jv2>7AShFM zASYX)?xZf)7k-VBT@4c|58%sYI}-=1XlXlRklT0mKq6Yx#K!aT>$4Ik2u(JrI%Sjs zxnIg7?E#}TBgP^T>D1e_7<^??=n#orh@2l{>9PoW^C+ccIN%dc{M?gD@hgBT%@qO z;uoeK9Ph#w{JkPDmO4By0dk3!S;I?Z+cmYpF>(aP`Hw)0Ur^HNko0O)R1BTU^io=| zybhjg0yZpo*YEg*iA1LO^re%1Mzy$Q{q}9s7?;%TiC95%kP;sM|6=Z)n?!B8F3+-U zyH45GDciPf+qQYiwr$(CjZ?O#?x$xuI$|dJkM8@8>9278_R73guAR9#zOAIr+a?ES z0;i)sL*zqb-;V<^OXi-D3y1bezJ zEC_%n>C3JhbhJ5`XQ-Z}6YkOx#_hI|vBd3!f>ZF%r^F2%2S>9)lnJ7oz?#gX$mzsN zp<9CUNO!&5k2jF5SQM-X4ta~kU%VDmiw(Z1H?x`~y?t1g)5C<)=$!dX5*lbj4>c8d zJrFT-DEkRJ@EEcW2 zpBYuD?HT{-Fr=Z>YP!5%wH2=NRvi-1A$!h6z0YbsbE9aQvno_RB#a;CsEOHT0Z8wX zrPB}VAHX?>rXm{IAFCahXRbf>R&fFDbi?e_*b>FCrLisg79?iqJV+=8P`?oDPAhzaXQT<#P5-o7#Jwv~rkmi%^;7uO;R4Po^ma(LZ>Ex`2r$967R*rYpJuaQFM_y-fEr}?j^|; zcyC+ps(BwukFj|)7nlerf#$yY5Ytxj-dop7Igz2(C3^*KwS%`(j-4?sXlvWRY2)R` z)`#jeKJ+pXtu{z@tz%<79yoC3ZM(TiXNDhKMR@efT2YJCq}# z%&YlrqXQw(z>JbIvadyNn9L0G{QW%~TrW9ttyp;8?|4Jzf3{k_ElMS_+jb_)n3fNN zcy~J2qYuKHp*Jtfv13^&Cy0K6+TdtjDhxvrx%9;ti=_p>?LtWZHwi#|zFo&P;>bmo zZOx+x(@uB#H6kSnb;_l>WSwp+IcXzh>rgDvHUK9AzW-}YY=3_WHqIkMeS zcMvrFV8jlKRe}{CeC`6fT*uG#Zy6X?{K@wRdnmSD5}#@+b<}TwZZk)d>=l=+vxW%; z>kRwY>MLmw7Bmq4zD~{{`++y%v;6|ieJjlg9-w(nfhU9~?A1GurPaNf*!{MB4%I2H z)j1m&iFrFs>8Tj*>wg1QD}&o3-Q!PV@|#>4frszGWu95Cmwz^*S@V?dwv#X$JU(UP z-Jl+<9z>eM{Ya=a^aw;cwlO-&%Tq-9nZ_A?Boj&EM$0qNHPQSTBu!Zgn6@5$*yA z_}VulU{&Wq!e@>k7@5M&_{@axYR=95O3vW67 zC+GqO$fL(JBry6alIjrQG4EJ;^MkOjdNS~?0lL7?f`swYO!dYveDwhv5Y6f!u6Sj) zO-kTGE*d|-M$3*XRRbrCaR{F;$4w)JitRa+c~*S+Tv%#-vanG317H()ma}F|KD-ps zb!M8Axj=im?)ql}_?NPZSzU!N`LMHYafrVh;yzq_j+>ZrN7S-Mx50{qFJH3>AKrK0 zNH*za;?Uh*aW;6S5~k%9ZgIUOc4c*s57Z)NLNtuRamm6|wkC$fAS*|G^)lTd3;6Wf zEmSiF>lg+7&GDqfn0~l#??KBm6od-a_P(51faY{ag5=K|6_cK0pw4%zHCtrcwce3( zPg{&u6Ef^uW;bCcU~EX_*q_6C<)i0vi8OA8NbdO3RJ>SRyHWc`&tg}@Kq2Tcm)H0G zzWu2_#}=VOlud$eqOn0Io*HR`KnM}9l1V^mki@isg}LqMmS9HGmSh5=*7(^a*G@^? zCfSJ2H0{m6_4Jc=?h8h@j=n;PSvx-Lssr8d3|+Wa$RMb3Bai3$zu@JTPpRs(Qcq~E zw4fzm)vTKK1G*>Nrb9WC5^?-$!hFtoCvxscP2Di_`)k}JPypSC9~$mRK1G56k<*0A zUJY`a=;0Xhzf1H;}BLywHxt1 z94g)Q9kn(d55U&O>BF2nAZ<{<(qr2rsLSFclt&Huce8{okG6Q84eW}vSToxLnCzuI zFYUnJ#$SQT3D{J=eiD+_&9vFo5~tnyp&(Kw~VdSoBDGZ)fsi;&iNl&19a0_Hx)i zldW7irA^2+)W!$_=g5q=^e=nYPSgJOVd~;aI8f4k^gyqh&Z+U+_>!9jr+J}%#;L=m zuh#63Vc;PH8@5f{mtk`LP&qgfPUYitH|So!i&D*gEKHvHltHeNRHQKKXHnh4dR-B%z7F*F# zuCBNf`Pp?^I(!`@A3MF`+t&VW5luL-8IHlr5U9%a$2+GD+_wnTamFt9@ojU!&-hJ} ztHX;tbycRzK8pOi4uxiD0vK@eXXKMRD&<8Y{<75EWUAvfyO}e5ldnHR2}(6bn79S@ z{I!|f;iChuef_+2T$vB_iFo@Xj+K-5YGt~}s8HoX-aCOVdE#8s-m@FOe4(PPWSoDq z9?QZ4K{XMyQ1Ss2K_R$)fb;X~Zf6=y&=CtIqV91@C$oAD+ZPQ7MjgEDU($GbIg!bC zIKKH>#)7Sg9jp8T(adJSNy3dk<)6u)?x;qq8&#=dA4Ux3HsUUzo6zTBA_u53j5?${*!ABw@us+`63( z^@@9UZ9jjys&wP8A?d+Q{uLUm+{WU6&J?BZ3>Lj>K5Z7gY7d_ci2YaL^v1#G?c!~K>YCD*{z zC4YP+L9}tuPvJNo%juIc^pFszgM5k?@<+B9@S7ps$*vMa0U=q0_co!gVZ4YTgd2p* zh%}i8!ZZ;3IVO8VcJb?F7pVx`*_ekUJ5SwTBSJ@L3F!@Y?KU*NEK2??__PK-!q+1!MZivD~Y3}MNLGsX=*MzoFLOv z7~A9nWn`euTw`=rLrnsV%8no?j>i!jr9Y*IpzgHZ5>vnOL5=^6tay)8ob7tjO$rqi zHx2(yu6FnOj{N4WPQR3$YHO*iQs6s4v(lhn0DCXd`^z=mOo^AOlOd3A#MaBw268IBx)aGe8QrdBN$h&XaOhW@ph*&znJ-F1i&%xPFBTbUqT zFBTfs_n>U6jK;QjS?=%eX+#Q}F{89fh7-WOUN-6SMvn34_N}n!wb_ViG2i2bmVQF3 z7bg5?FIQBS*)pPXkk>KarQtCVE( z-BH;^Lm9hAAUdrjUd+B2||2PnbUzRqWlJQ|lX$^=8KvMCkOmD1P543}nnndz#Jy z84LDZx)rss7#oM-JoDSlG26l(A*l{PW0#^wLtZoIliJNj5N?HB;F<5r2%c7J$>b`3 zdI{)z(eq@n5MDY{5S5}8Yh2<~YLQ=={FOH13|L0h-=#?N{9?pvNq8`k{1n6*z^%(3 ztF8P1M!hu=GN}-o4%DW~t8BGolMgF70a2FVF{PWa(FwOb80IBp92V^ebq_wHW*;#> zbzV_&u^P})?O+NY2z>wCLCflSrSLVWCl3Ozmwyw_F@NFx9Ex{`(Vjaoo>-dE$3tH& z5ad28Yy=hc7<@Oo7&=#spZEAhs7m`+;rE-Y@yBo=zk9k^l2PLt#yk{<0KGo^#+y*D zMJ;B#zw={^)OPGePyU#RBf7`o(aDSpN{sgVi3bpW!0O4<(2=}B(Uz%sv;}#&wbat< zi2gnU5wz4BsdR>NgH$0L&Rm$2%j!qmS%0ae#E@XgkSg`T{mq~sMV&qb?BCH(tqNIl zxnl&IYWd1jwG{NU-NLWvgefmnS<9Oy=Z9#tYB4#5Tb@|cv}EKhL@k>xt8_#z(ep*r zEZm3Nc@MWfB0Cz~AW$iq{w;L8`YmEyq7uzMGMLTRRF|$~E%5`|^!qas8fw#2JfY4uZL&n36K zEA)sSoGGJ46jv+>R^)$P7onZ)f=q4V|XY;WTnaFPL< zlRyFxnWmMq2yKRimxr2QBii1$aIfUKTU{VL2CD!tLpy5>4n+MBG^uX9bVreJ=C#sM z1saz1Q6mIb8XoJr#lrjjB+~i1=4W^~&h6SUwum;n8N?G@r!ZBy{d3L3MAjhDuKE-^ zIIV&OOiZtV+)sF$t3TlGATd5m%e5ctSI>^K?lHq`@Hw1e-sfY}h5S;T2xwnA&qa~S zR)i*7gjdiPcRVvBu~RX7&?M}Y|4^j$RO(!abi=U&V+qL9!fgMOnMPLHEl?LLB)#%( zzRD}YQPL;>Fu#ww$1-d}6@Ch#WO1)21(qI!MXZ7jFSyNy#QPn* z@c`nzT`_u-%T6B_jafGw%kM&N#sqbXUF#+gq)G2$aKJWEqx6ASm%uk^H`rCv>fwwJ z9`E|R{ARVI6nJLrn_wlfj7p1b2p(=^S+?ng@8{plYsYZxMy%RF5DBXwNK^^Jl|YB_ z6eRxi`Ws8WM3A>T;h&}s6-%#_Jris<2-_Cu$Ii}VEc#w>LGrAaj02#1({rZ!XOgYY zQ-&6}*qVRBAeFTe1lClTV2;O+VQONrnD0(o;hKZB4f}?r5c?8WN<^8K3Q(nZNieIB zNiIhjt2NU3E?NcQSmiqC)4|g+q%WXo7z8p;bHBI^>Ci#KE}xfaxV}p|r=qZa*ufSy zd-+OyG=F`M8dzqso7wm)sz;g&FV0gD!x}ogB_t4)DyP%yYw;Doso{fY=6(&!Q!>Uv z0vC?iA$WOEOiG18uy>1ZB+90RS*@<2tHr2C7S+y(RD-M9 zT}o%pQUaWpo+vw=kiSeE;PtRhhPQcFz+gC%EDwX`w&7!enKNWO#}RTC>#l2wIu z>f@>xM$MH<$v|fVSZ>!=Fu&doiHTQ=ML%frDlZqS2pwrVt|G68_f2Q;leL=D<~8n}N#q96ZfM7Qjd-OXkmonMKLrjMC+8R(bo$1W#R&~@;yI6xY5J-(z*Hp> zPHB6eu#UiMz_DOv9COyKvW*kfB^6 zwJ`7*PnE{!rxP18>HY?(5JD%|>vL#{&o26c57!}>S$PK~3$g?7PdFaC#^1E^K@z6P z3**?va&kX_76P<6^A(!)#e_&lq5aGA}3(k)-M*RU*ZZLy53A#p-_FHDplW zUVfRP6vaV1xQxNRY{!Fa?nQ1#p#(=fRvFRV3nG4QfnPVN^xE2cD#{>@#^_$pGWWaC z_ixBma)s>T_hfSZ z^`L{VEA+E{VI{xFFcgT26(qDk=dh8eH#~S zzIasmc6qS0ay>(EPp;9R3T%_{P!S)&%?B>Z%kg&PBf0UaD6Ti`k*awD`u!JavGb_B zc8l?Pe10A;8YSEV`JX;}(0<@&&*xN{P}mFGfl9CyeRG{xH=#$QcUPgg>!^-CD82V_ zk5x8eSFZ@$mDIpqptWr_L63z;K7jQ)eT!@AovBU$3Pla{s&~XmBrqprbZt?d62%GY z>ry}K|G9*$j;BnH1wTq`&OlUg;GQe2RmpSaQWRT8H8-qm%EiogXxzgIp9{kx6%Shw zA%pcwYKAW12gVL(>>#OvfAyEzkyMVLvb$%>-px8LV42kC!qlj&KGoW=si#x|V|*bC z0JAa5yu(NMo;ZJZ1vD7 zN8WXRK8-CA?c9lSJl5?pN~b%tEOFqH;lA|IZsYP(z${<4cnm&+ir9|rx3$$lTW)ws zj=?J9AxV*^MTi|LLVzbutMfQQncUTczd1nlp7HTFP~FDt*rlzW)5^-D1A@=Tb;q0GZrZ83{4d4sF_RC*ZXQaWB ziohMmV2^4^KZO!}YyLDK14`}Nd@u_EIR$K6lDh<8BX!3R^{4%wOHK~I1~}rp<*YWx zHJ*aP^yE>;$R5`aSv7fkb4A{9J0XT8j9AKBKU^D#2)L*1V?PRBGwmBqCvS^`?m$Gn zW0fSCb@Ji?W`sJX7h7?Cy*-ANmn3GHv3-ul9xb`e?a#NB*7OM@j^un&^9hobIVYbA ze|2xke0xeYa=t~>zY9q%Ba^}oqM+vH|-a|(=QHG9B0I%G2BrN`%2=$m$h zoc{&V)d`g`r% zyW~OL7ldg@#VHM}v`;=g_w}eN@Y6d7*h{z%@jtEQraw~tGLK6G1r^T}EAaLX39rgs zH|&+sznzwOUem1*!_UKhZI8QWY6|%q8KO2`rLA{c&+$ZVj~;H3?sz@j(RQ+SFhu9J*jj#|AKsUuC59 z`w$v?AO+zWhorL*kuezC*zZlIZBsi?8D%0+8}O#9cMDAPuXnPj9G2*Us)0fpf&OM= z0sJ!)TJHWU+wx@>08kEFt1nYMcLNBpYH>Ln=|t5(p+2htrda$CGo)82!QEz}l9uE7 zc#L{5O0tBP_tv<*$c?~n^kYScbpUE30Z-=SmgV5!eA=6>cGkBQjJJ8_3Fp+95kD*N{&YRAX6x<`oep?THU>B?jl%eVYnqism)hbMy%!nW`R`dRWfi1<@)^KIm_%|?!#ns;j4=`?ugju4!C)O$^(e|^(IgrZ9 zFkNzY4IwMzoFO|-X4we!n~cd00g>zRWq%mCu>T}SF3XLqn2!Jb>m>4V*>`Fpa%4s1 zhq}%0)}mbyX{-+n%eL8C;I0M`PO6fW=e4LJNQo)g4F=oUOyQnzV8d^8WX|R(!r!Fc z4#}bbWuuZbOqCQ;*J4;n*GnkTA3ML?}4+XyB#IjuV1Fp}K;dpR>_hTnF;Z7Cbrp z3hyAeN;D#D^@Ash@DSnO#bW@0W^GcmoAQiP&Zq>|a}m0Ov}5vdUr#+77p8xP+?5JA zJ_Fc6RR`tfcni!M0MEDIg$(g{MPJPUFVL-xO^bg|BTC5FI;xF zuJPgIW5q_vg9BN>OS~5>E1Zh*cMoo!Tt(Q(MTQaXKpV#8uep^E>l3c%yYO?@*2tqULIcjlzjCbzf1TzGAI0?N&g$cLG_zbvt734%&Ns}~Vr*Yz0|KzR&i#{@rhBo;IqTd<35ifB_6 zn_Vh@Nmq1B;EtJrw9K7XL+72ee4Cg{bSnu(SK>J-_g-{glZNFUKw5`JC_I~%)vh}OBQ z5H-M>rZTw3;bozT_hoUKh7AMFt3k8Y_ktcG-DM?tl7)>07n#T*rkfv3b%e(l|1PF~ zRW{WTGUS;F_}i;h4t8$e^8ti{o%2B~|Ao@1R@?v=I|Scr4zQI}?y+hnzo_d%T>Ex8 zcBQB=ZK+V&Tt;%)$qVZv(0To%CYr@KD}~*4nv;R|T=ED)cyj{ufsEl@G_StK>cPa9 zF=gJk(mPpXd7Hm*;t+WYRCb2wqB4s`Do<#Unhy`M03)7k^>cDWxO& zL1pJ&>}W+!cM3hvcrNnAp94o0(Zk+F@Te-pAroguz=!^fzRhesMrorJx9rpwFwv{b%#_MG03 z!9NTiw1?YjN{u8AyAGOy1Qy672s#9(HU!ay7S|L?vZdMMRmHqp9{fQ?azf()fIv~H8_#)Q(|!lXX?#~Ris&W`ElfPVTCSyq*&T{1Gdt-N0tum__VFhXAN(VOGy zc|+Xt&zxJXJX7T{NMg0e7+G4>eq?86=fXSJ@3?{X%%FVh$pHj!AbxS@9fMbvgTr_9 z*GCgu=E^TWGF@Ouux5ug*%|4`l6wr~Geybc>qiW)%zQdlMj)R?qiiE7n9Eahh|_e+ zbtelcGE%w~m&~x}kA!f0_I)>pb3BydELKXyXUA4_%j6l%=Ttptn<(~GLrM`-G(-n@Xte}wP12z`WTX# zZSe=#8=a0@VnXzT$TQE+z2hXzJ5Hw{ah#(tI^~9HT*HLe0`n-TAFIyAwUb&Wq)9Lj z_6PY?!=DqK9*PbPEe19U;kNdPzl8_1L_e^lV4;9qSLV)Cr1t%s8vq#*o)Y|93i)q8 z+|B|o#2lgOZyXtpDhd_j%d4^}Bu1pr!l53hXaMG4Vrx?h4}cMW{d8?Ye3PE!r&|<-Ni7wO(mFowe(jdf~!Y;m|yS=+lXKnr|y6xVIkV zl9d|#xw(G~j7C!LfN~9tej=7eHx{a7e!`KFgwy&Z?*8^-unLO{__GXX+sK|ugvhFK zwzE31$29*7_wX>wJNSSpBS+{IS^n77CUBM6i=y^x}kW z+c9Wj+g5E^wtDAn%U*^=aB)Ah8Vl}x>(zu<90b!nvR$)H9oyIjMEsYwm=^ayo2c>_ z1EKOq(uGnk*>TNQa6zaUkn0{wOqE(3CaW{mp}fri9_nAZQU4@MWeMm;^$e ztLqm3`|1hYFE9IUsGnQj;B%Y+5>Or;wTqB`vW&Bp4<7*VFePMFp-)TX+|(xeBh&sQUDNX~A2uCfaP{}sJN($H>^=?>^kM7PBd&?a&&9M|PL#w7os|3^adSkTU;{g;{M|F90%? zcSdpqV*?a}cV>+I2?8b0Yw6`4!p=7#l%A^ynK)cyeTvrs=bAs!RZp(XwxmFxqGPWb z7b72$Xo+~9h1UUN4{N5$A&&6dx)BqeHLes$r}VL68CkKlfGX_&;8wV19xetCOf?6Fhs4r-wS1V(mH8h_(26=*AB^HL_w~5dg>lU%Zk1$Xo^&8+(6Pael`P{cpjZ5SZ z=mjP}D`tY^Vv5I1Nh<{WUPs^o2DygK5K0eXEu_((ZPO$>#8vrYO^Ix)CDq?>`!M&^ znldVS7gJjZEzA{diN!`5h}<)wQcBR@LpmDOkN+q4`j1|z|1~0$VnpO%pwiyFq^j-2 z&oTm-KzL66@8UIpNKP5vy~O&g_L-B{A%v^ck_tvlDNcWbUKbOhe~1)yoHGjPJlJB+ zyg%Cqn7I;`?EG_^K0_=<^6a3&&`D!w5&F``4`PP<0kS2fBC)Ct@|1jwV=*(Q)HdM# zc9(_Bm?2h>HX@HvHR-Ge04yBaLt0P~o0h#u+-0Y2w*hxxgU_Q=ng7dRX1`k7xFe^c zJHRRJfs7VINHa>A?oKWh7D?I03_-wCzdY)vE4(RJy~; zz#%_P8HYUn!+w(tCrVu(w{#xTa39RcqdaFlSaKcOh?=~#@?$D*qh@D@m{4*Ugi1C%~^cJv+k zN6yVHi)g4bP%6bIx51TiZUS)|t=3q<Hp8k!0PD~v5vW#JuPQoCh1Y5WkB0Cv zJ3+Z^$nTS8_m_vvsiq0~82EB9{f!sihmc0(5p$DRrnUfyx3dtunHOorye6&0?T(?> zucxVP0ZK2urkdaTr$5I38^jGz+Q8}VdtkDZn_DK{V4J^Kl2=Z>BiZaI=rS3lNP(t0 z#{e5`{TtZi;0A&kY%kyxOo||Z)65D43M4hT^4m?s9~tF<7W6`nfqXGm7463O;v#X@ z?kN^nf8^*F<+w$3W9>;4ZjH%Dw!dEZOhR9Kc-%Q~NQqOhemph>!ao~_G-hnMkBo-cz~!8@GzWE| zyQp%TiA&!)6-8gtHJRXPWM9(>GObas=Eq#$t3dvkYmI-*b`dGv$vw`$>$(9bxP8*%8qK&*c}%FmLZ#>m0Z)&if?Ql{)UPpGG%XEV*;b*g zi8J=yV4Grf#_?=6S}6tBxFbtrd1`C9G-{-wnk)p}@U@bW2N<2>cMsGyLg@FDm&PK+ zEd0!T~OT$=XfDEUTH_DU(zShd1^YNp~V!|u-|C5UY z>cN*k&u66+74dY@Nluf1-hIZ0$tIIE7zG*$fIiN(apnekKegAPn}oYJ@b59`^#VdB z&qz?Il&k#bE2xEJl$RQg}3 zp0g}@KMh&z9jj^mMpo1*CR<4_8t1LQ*&ePo=d7&DE!y^hE<(3?_6oxxu!+{~etLK7 zwgQASzDSL4*4hT*V0qFzGYMD~A57POALJfci?c_1e`E~b1ks80*&Nfqo33J4utrzS zP2}g$L;fS+=>>c~Da$!WL^g z4-R{?RvNj z&O$|@99n&wl;<~76N1h^&*4NpG)^?C;DcGFG9c ze9%x+TY$F*?pw*!@Rst!w@#2`#y!rl?+q!P%X9XmDvrpq2x#dPV5G@^C8E+)>-L9a z9L|qil;8sk-S21UjRVKY6T#J#tC1K@iQ!Uc;dI7pap0cTzu6@sn`**DaF1=Oy$+H9)^1U$7Z7w-thgq75X2W9a0ho@rJ%N z6(e&ffMkwt_xMtDy+vQL$0ZB0(X!R+oy7PzYUz%y)?4@K6Y=TLDPVnSu0?2+I!QJh z2p&z^Kb7|TOwBlNP0R`2kbmcuJx_b@<|gIoK} za88C{uL$|4Kgu?8{LgpfFGlK_CaBZ)qLL+aFYFK!-?;fT$6Iv1GTsX;vEe=rzLZ1a zMn>E(%)_Q$lUu6U>K1H*+vI-O!_>lKfE&iZ0bKPD0rW~1HO=2DED9HPr*k^c75B!V z@@5*l14@(Rm?y#z=jDSzpw`IOU`rxW!IphuEX}t;TL~NZEpxcx-8NN18~3AvpnJHI zsshaC3r|DzI4sssaNQ&K^1jy5 zxc*(@&N-_a58o6Ece_6Y#4&u}FMxkz@pciLrtqSQOMYLJ*OGu<)V~)mQwPKdgHZA`|D_FWvMq&F5bMq;IMID5zlQdEu)^ zeIGEOYG*m=o4vF06n&uhJoNRJc@?C*6aJ5NdLXt5Cq!%;@u@x)KTCszzm>1IvuckWC+am6#mybP&AN+RqHv-;LT4F=JQy znL#`D=Gt>;=u>JoQM=b{3rIu9XZ9&$GOj&(hw^`Td7Mz8_ zB#8*8#`P^H=sXPpkaG4cuEr%Zecr$#el@yew1$&@^f9FJpeC;cat)7ZL4_PhYx40+ z4F0?>A6b^x-MM7=5q5E)Flo~soFK&+i9Wl0w~=^UPVU{AMfu2f=- zxYx%9S@dH0nM>uGWr_kiG|iOUVu%Ryt)aM!Vm^;Ym6(qFs8wbEp~8HpOK%!Atc$W{w*2&87*$iaf0@jLa>n(5MI zRDm+q$Jqg8jsj)F+rm3hklzl6RMS+XN{1Nsi!h_F{K);D3-^OzsE2;g;*!{2ST#(z z07<;tfv58$388?J-nkxjBWV=p0`tOjs$PXw!ZpStMg6V6e&uifaL*&W6Z@CB*T}Ad zzL68L_;9KjxwJS~yiUNCPu@r9<#|!-{YF9Zj?1y94{uL*!yqQ-KdqVSO3X-sBfRy0 zr;;4k+s=9QQDhUv)g`fDmWMF5$;(hN#sW!#iSkKa;5!v$E?(EGoU>jk*P;zAV0pV>0OE3W?AZp`wFQtAY&qxSJerN zD5I@%K)9D$cml;7zGUmSlcnm>s5CsYF+q>2ghwW6h?VvYdO0yd(?jZ+@NknI7nZ>> z2Pu}7WTz1Sw$$~AS8&&xR-XFL_@#Wpd#QgJQY%ZIU<*2^D^b126?D|-%8LHLUk zw}tsIUTB8-DA|hK3%zC*MZU>!^vkaPlerhqTSyDmo8vvKpWHP5^N8S|+_Xd5Ylv&) zKe=hubee*kQ79dqH2B>SwHzlUyttq&tQL3Y?ZDs}8qFb=QNtr>#?Rd#HF)J=%nIH1 zAf2U!w!6P@1gu*bm1}0dcApnJz~G`H*?QM!Ju9KT6zR%TU90r~lIg;}otH_Gl&lZ+ z*=}33(|EtPgkHOcB!~VuRTx#2Ds9rY*IHdx)o6fIqYKQIFJ0xRM89G)K<%cr|M`bf z2H}I;zf7sRq%8#M3e}i&8yzek8e~6|dar+;KsPF8xRy>P520_K>YWxuZDwqw&75r~ zsdk!)FYc&o`Zz9t4`x^_x8I8 zL?G0?2*Of16driq<*N@Vr_a#*Y-Z*bavy2gRz9m=>jH{_v|~KZ)9{w29jN~jGng0$ z0{Y!Fi@w;s0^|^Vkp^oN|3=pjWtmJC|6PqZ_`#=vmd6?NLg1(UqfISF%~`9Y`Sq!8 zhx2RK4X@`iW!>?z$GG2sV$Redy=jP}inqDY^ZpX#;*TUQFw`N`s^n&EA&0ZfLF7aL z4hxUMt}qLj@#v$I?(WXA7}wvE6yl6wv72SL2-&&ZM8z@@qRHF6zyMw^h_LcdzM3rR zWX6}hke}&FOn2(W@zY)XL6>|wb5RdEQe5&?%$3;?Zb`ClYp+J-&TnvOxj1zFKg1FV zpVa=(C3cwjpJWp2tNOYO5;gygMkNXBF6Dp zT^Y9$IMlNZH#;(<+?sdi=y|SNz-@&UI>@Z5>WK*YqW>M3PPTXIU3Qe?M4*F>OrccC zHG<`NzHdH<=rRtbKzYW`Gy~EeyU+p6RGfA(3;j@c1lvQ`lS-7N1+QW}_$CTfX$S8i z#wzm^BZ2X9HAg;kIgHhJ8cgIjDP@L$+9s|QWB2FWC&Gv6|M=WrgwI<4E|wn`K_vYD zxQOTzmuK64P3w)Fzx;|>M1-Mf68S%4NWZ3j=4L|x&njTmg)a{Qh&|G8pPkyqpYgYz zqxhWFoz0zxv8T|Eq0u)dzzqnPjnmu0+Hb4Cxhor18J3c%q@h;6WdQXRYGGWZm-YB5 z6c_!p0&T+@sN2CQNW9`4!B8TwXxt2AlAE6|JG)eD;gV%I-TxgSjOo>|UCMbz1c zIGr=-AYWTGLFRkLUTRNqf>HyCVxR$mrtZv>i%%-)x34qqLN-2ks?X&|r>dze z#7-r^onf<-)BB1Sv1w+a#cxFAh{W9&K?kc~HQrm^lC_C#t~kkVQAYaA(P+c^>L*n)ZpQ#kNn>T1|Qr`%(_tk0FKqmvNxS;&b0bZo>2QRb|g5Rw=XN|blwZ8IBr2^AZxPCb+%eM}c>UIJIF&a>Z-fQJZQ^#1iq zA?ElWDy1T)92oVqr^FA?GVL6Y@OQ_d330w9zflzUM`8J|zC(IO5Wr3HNrP?)(LB#{ zn6rF!5H<2)X7hJp^JNg`r5h)4z8g$ z!&NEa_IoY&&=6AG?|ECC1TA1t<}qa#C_I`e^nK6r1s`%N#gx5cUH~9KC+awmpnP?1 z^3pH#qCXAA2DR0dGSMhj?fuP}K2~w~J?^Ha`PXKE>47G8=7w%vGV!vH>li*&K@SBo9c z@7HVdS}sP)Db)qH-c=@cV_BlXHxXs8!vp0`v(>DkGRp!%7ZMI^+hykECfJ`&h=tK5 znfRnCxzp3Q-+Zc*(z$}fAm&kA-XkGqYLv!F)g4LpGB`Agl+_RCd2SM)wFO4-dn;W< zc0pRk%@0liEfzpG69dPX19{R;a;t@pVonYPXLDeqZYVh zPGZd0yaVU6zA4}>zgecZ%WzR`49d+OYhFH~6h?S6%-h#q3pS}4ozG{eo1{rH>gf19 ze^#LCwD*im)MiGhRt>}-xSie(Y}bc=I0h4g6O7dWI2AfXP6Zd_ROo5%dw=OB?5dWK zvR%F=VnXy^|5@=Ci~E?&l)Y4;Z*byQ8WjvRF}&}Rv_GBDo8EZkQ}Nv9Z_fT{eXZ!A zCUbJgk$J^hn=Czu+Ike4?};-A_1Os)+nS_fH%HO&{|H~7U+?%mY}(canzEsmS$%BaraJ?!OMlWR9Nu|2~cc&*hoAjZ9?bN>SfukgMB49$F&O0+Mi(s@xx zMxd#+wZ|-nUOQT_N^Q%YXsl89==E1>glX>2Zze0@r_+BChX1~J{jYS0qjj7CfcI$` zKCbI6oqh!heAYzNKNKn2E(pOFj;IhEi1{owYMT$uK*0E9{01bZ5-mm&*Gm5FBXx_S z4;m30Q0Md&jleigrbEV=AA>Bk0_8S@l+%?x7u8G^(YG_dNJp4ewLAeuN8&k7;9jsx zW0HOw;TroNbEo-Z?jXzGe#{-_Kju#KznQxa?(x9?@$94R=j_8dWK>tN7p*i6uP0_` zKYRqqaY6`g$9 z&#(ywM8CSjwG)w_(A41USDB5NRGijDG2kDnt~PByhB2&exzyO&SJpGM9_X7pEsrO& zJ~Xnfr>{n2X7!^Mj-!O=W(S@QEKbMHUPFC}^u9z0E9IMf)W$>5C9?`e#z^^yZtQ)` z0~}M{*QFquE>}Wx{7}i@VtUh1;vmAE^tBnV>el+hM`<|LfDaL;|BJbIitaUfwgqF` zwr$(C?PSNcogF7T*s<*$+qP}nPJTD%p3&XU-S>aS=;!Zk)i+nwtg1C95q9ET4?Y}a z?eu6h`v!u8lQbyzi7H~Rj>&itIbPdkokAh`&AmhyI-Z*nJv+(hCGD z2pQtc(wJcKEiQbJD>WE~upy(8R})eLs_~#_O)hNQ{DPV5um>3Y*;Oy(4UJkxGm-ZA z)B9iJ^#4!0>Sv|ruZisCft@v6Y3yG_r<>nyAGL_rh#ow9Bf~3f0ma6h69V#GlzQk* zd&T5?U<8^VIB?3vI@0uxr2E3)E^80($YyS%v&CUYRL9X`MOeCp?bSHnFy%|K@R$(O z>&x%E&V8=*FxAEm{SH4FE^*_u7Hvl82g|U;0N?*?MA88dUE-tvsz6l53Xal`IBuXn zrAdic|Jv=t>$iYl%FEj+t=6X0S7i3DROfBpt-K?=M0DB>#x&%nQy~It!w3V#k&6s7 zO+Udd;gj(Fa;zT9+>aVv&~ixwo?(}qe;rpnl!m<)E%gKsbNpq}IU++InmRuMPfdcQ z&w(&0AJD)jn41m*x>87mOSJYIE0?y=IJxq}gv^&t7vd$*8q zZ)T&Zm+GCUx4{JFhaqmNvYgqJA=6Dl$Q3T<@nj*@wp*3&o&KhtCmZniHBpMgkx(e= z1gy5J01)om+dTd;I?W5nWfQQh9?85E)+)>3h@2%nSvDFMe z^Jm6ulGq7+x;X|7o@97QyT$$K81iu`evfS$13xSKY!41l^|b~PmB`)x{0m5X&WcCW zfz{V&G%}9T4?r)8cLV>kzr$Z3At*L$4;k2Lek1e9-P0}%_zXEOAS0ot#5F!1M`&gI zgEH{mw94c~%eLZc36T^mMvH1^B)zA|SSTb#Q9*L+l5Jo=M5XYYOUbJ{BZ;tW+IZX*6_9V#m4L6o z3kTE7-GKM2swvkIxRoxPrV-s=nIx676L0NA)zFYVX^${u@TnN8l#K}Vk!#+6U*q7? z{qtUjzflj{ZteFyX?f`N7Sdo6`f$r#31(}=F7srU!`n6cxafYAfdPVS%M42Gj zNX?vljhN%Zb29%fRy@8oYsN`;HPE^hk@@sNzP%GTYi0ula|uE6QJdo8vVFaz756DF ztcMe%-@aYIoag_EcL(ua=zlie|2KX7?+dvE4;2gh*zHd|8dah0CAKR=eFx=gE5%z8 z1)`Wa7(W)`bm>vB-Ks<(4w(BT>e6?%8C+-FJ!!ar=MC*|NZ^k4w99{oYGzBtTo~oD zA#*zY9$3hV?Fnadl32#eh4h<7d^n*5Se>?SsVY7o0-tsJB5jUsh~t=ppc~Lj4d1xw z+;rb>7?6~9L}vp%koJG75^1JmcUuKUO{Rpe z^p0;@octGYEdFoe_*yjZLmU^1=!s&V);3(;`UOKgWK={`)S$DCaUs2HXxtCTj#PpQzU2wQRh z(~qCog+u=Yi(y-0q-{>Ia~WOgRa8XhD92d#q`}B{k6|D=DO^QRk|BQAfh}s>@-0)NyEiO_rxm0jxkojp`XwCe1 zOF;%_sQ@37rm?;QfDBX^!h;ObawP%*WYN`EFu7px@WMiF?mp@udDVZV*tTVSuAo=# zENRv1kxE^{SPQn57*#$mtlh47ob*B>EQ-oQC_^PR8=`>TI3QK6Y`%cA2Vp`)ltZnS zgkK^vix~DtO58?#Em#(n5E1=#MRLm;Fqit0O)8|RQY$9?(w)bzeggwp+LN~VEzuF% zr9MO6(8#KQr~v%vVqECRd=eJU6wX;$4dd{C7=XS){@)%*Sx_PadIX3Ba;Jmjq~y<{ zq+Z@(H=}QGmq{!CyH5UDuRVzQABqmCa|RP*p!yydP2;@MpWJlLs6J!J{X#0a*{}*3 zxU4W8^v&M0pqe9!#oppVqLI}Rg)xno09yT}LlsAu=k-!*0Otp$cx!=Sx69bu6ps7M zVSgTIlh?fmBkn|WYMAL#KZS<-bM|RNedWO7X5pF%3^38{(vKi?L-tAsA$4I`M)tE`w@K~~r3V4|UOkbcPO|Rh27iK< zXn_1g-vwunS{V6mhVAnsESree7xtXZZMV2qKS;%g4^n~$eu80o4TG>Q4^qR<57>N5u0cJa037_$$l!R^z;`V#|TZu%8oRN2$t^*~?F(QjC@BNuzb|0uDj zC0x|ib!#zWl08TXf>gHx88VX0!wfAo=9e(KZIJJCFCfZG*0le>$AezPhY9~far!?; z(V>~BCOZ+_-6GezW?qCxsYmTg?F0gTMA3CBL%#2@#KKwb%|7cOdEF06!k~W&QH7V3 zyq`i;@4q(l&@W>gi5RcKUHdajDsK`DmBD@h(s%ve06E{yz?}PpYkgY86o>vOu|Kln zHsb$T(Mr6d2>pDL9Ra5hc9{a|R582lOJ z(b=ek!VD}Ep97Rb*bDkS<62pnP`l%A@fb}9^Ics${JbRI{`*hSD1$AgQr63F;s)CR z-XwzCvmbx1+*yCMnE28f;7`Hq)MKhPi3=vJGalhB=}&drcXYfWY5d+NO(4bRh4yT} zuD?WDvaa~KsEx>crD=CpO23|y{Uq!XhiI_inwia1&1zJJ_Ie8-CBpTVEalG2;n`B_ zSq|+*p3K0}vAs!}&W7sp@T2P;gx}c{+S!Qca}XN3zF+Uc?iVZV_1t0JggQCQK~)MOIQ6>;EnV_8zP%2^k$ zCKWS}_yR<|09^h%Rp9!f?6E0NN_ddPww|U=q;CB119ws}(cOL3QAw zScKDRKK9!7b*3cfr93Q#3~Xpm-sgPvJ3AQPg0K)l`12Iw8x69$zO!kVndyXduhWwv=Mf*LmkE7-F>njw~8 z0+BKe*M%PTofd*W?nt58B)p~RjQG~qph{;+VpT$)XaJevGk>)R>c+CCQ(xk~VG z8#yM0K~l`q5FSG0V?v)PrIOI(5<^=4uyAGsB@%0ML7pb4P}>+${?)rF-R$yc)5`eA z%C=+FXM7>UQC|z5(?v3~!tP(}VWhn#T{0;X#%^**6L%59@-;7oF##v1=iK@k#{1L- zbtHT&_!dR-w{>E4wPU2QmC{fhZ>{1-u`b5hKJkGuc4VF6Lu*obRNqi z%ET<@?~2gO3zh1i8%ua_MtsTj!g#(xInZY2;1((WcGW>fU8wagcKam63m=Mo5^G(N z7lEb}oP}|UXgo#CNgSCvw_H^y-~V>A+Z|ey*yq5thR|-lwrc++h&~l<|Fx`tWab+S zOoB03&_Rv``{#hO;hJxy&Z`Uqza@M z5N&ha2Ay5D%Mv;pp@3U zp0XftfI?RU$U0NK%`~uls@+AekYs2l@*>eTE|Wb`m^n0~3% z-ZNrBfD*VQO0aUZ0k}cp@$6o_ApTe32-QXm+z@zgpc(r7AF*!XS>R?JL1$b`aW5o* z1JgqtV-3k6p-y5ghYQt}1M%AgRYh0^@q2%!XYTjX zh!W_@3evOP*xlvW-?ifT^rhy%&I~4?u6_fuCp$~fKI6T0Z<_R z#IOq#Cy;f-DX3HoLiY~sXS!l`sLh2S*s>zRG=+Y5o{*fIH_}|Z0x!MnCWa3zLMWIw zM6KgN$1_7)j3WM|kJHNEQ$pJriP#r>fx?>@nA+p#q{Dn)-&gmxf;jWz+CCq#!nFtfI0DYQ+VG zFfIPUjl{(vL5_IbBCAqBXQDSsgInQG<)3gNvX~?I31cx8$I*l5X`kjK_0H4p_;#uk zqHKEY9?^y_ErV1uKE^aH=z37eWHTkR;jTNBn|6dK>QURHpim0_h|lk*(`z83)Rt}c z_9(40i4+cN*-=5;e-!NdT6B++L0w|>bg_3yo~wy$G?yauJtCf_-Opg4ln)MHWIi|K z_UzTFR2&8&!uSSvUnIP59=>r5N#NP83T~otyh{A(g?!d2b8#*uf*y}!{Dng}kZfte z#qCpl#yc)jC1ytfP$XfnXu}JbhSuC59TL0jTk=yfc**U!_0XVm^dxNPVF~*frsO*y zOcwdUCJM%3({4Gv5A$^NEAlI+_Bh4SY?82M#M&cVXbt0Vf4e=B&v-`|kLM`H+Lt@o zNaq)m=RU28q1-*`Z_MAzgZ>(aW28z}Db~KTH4N$q#q)nk_XvgFD|CZZTTXg z(!Kdmt+NgPAQ-16qYeT?7SR;{&9cCOY7;1DhR^K*_ECjU*x_&(N6Kch%>ti}M1tW4 z!tQo`wRJ;VbV{!TX{ zfA_ulUb|Gjk?lhzDOl_~%Mm9N?wX!bx{zBDQ2!i*3<}&0c)9K&#qTUQcj3BH=V^ek zN!ggLqI}pX=ai2C7xWq>eTrkK4zOw`Xf+T|MJbq@$f zD*Jq3C*ZVgzr_8Rq%6+}B|@#HK-6*rB54KJ2cAMqjVddgdq0^NC`(&%0>$~X!Jk?t z1FQJJ@x?BlW2eDJ*Eys2xnju;SmU+O^EiJ^mR(Tk&I*sY*7Cipw{mMu4UkBY#unsaGoG2 z5@MM{zpHI#^*n@VZJm;S1ZWK)XMjdjNyP0t*?dTT#8jNTuy^tzYb1R##(eTo#$Z=$ z8UAdt3;n|1rFn9JpL#Q%4oD{1g3<~jCA9wpS_H!11RO7_Wu`((cPX^(f!|7TOKj#uq8;0Ldb$N{E;q`U7 zf)rhx^Bp9GqiHm;^;J1}JzLNt-DGir? zI`8TNazx_1W#$Ln#mVyuLJ>2vMYL99(gS)iFB|*zV2}3~aHpAQeSAj;U03JoLh)d$ z{VJE2xWuY&;*TiXqHZQlKR$O6ghzZTP+ZoT&X@CPpYoa~ToovDK~7)>6!(!I-J@HX@q!gp zzq2hy_9Er5!fm`k#Ezt!2RwqLF^)4A6+48>JR{5RY6TtZUHdg7>%Q@*c`AnITQVpE z6FY2Rksr;bv`nX12lZ|PVC3W`V}2IJq|?v-&Q_D|J9v|0{L-pvrKb2ORoYlWQxduj z=7fe;!CA?J=rFTj=|@l%8U`7yv{F2{bg_f%UTc~KjnqXW8ybmNS}}W?g_x_oesht& z0stgLn5{&YIg9|Ap)9Ml2WaS@0VcG}R%DAfmC67OGcRW27S0dxOQ5Yc6f-Z;$d`zV zs*@qCEtZg$UlpcW@(4J{ZNzSge##IRA)^Sv=*I|6G6b9Sn$vG4M`}z;NphcgF~7RD z-fNh-=%AFvZAAgxEsDV8Q75(Nwo{EY#e+yMxmA+)h^)U!A6UG-u?N&nm=6*BUkrtD zv!cdTIW-#Oz^K-v;d)dBB0-5$>137PGvZN~jrA2Pm9lgx5mtZ|jml$e-qMifDF14; z(7YQ&^nomVxD?Szlk0OjW9#<{q9h4yqhV)+RkGmxSW1aSl*9k+oHO6W3v`~B8A!<| z!c6Gr%yvZP)th0~s^8W+xPd=yPsv|dtF2y$pWGy6s^d&(LJEd~^8%em>S-0wwcvnnZ{abb%=GtE=AXz+@a)bV{HLdhnxP_DQuh}m!Qv>%J$eajmr<`#rjc| zzo>8euv<%=+T!+{PJT>0%ZKLtRa6bh1jkl^E4w2AHf+owk3c-+gd8ZD32 zf~d!gR|ed@vw*m|z?^?(b@bJ^hf5Tw8n1H60_`F9;S6&g7Qb@1`3>RyygTLzj@EV| zZKfI;!dNsyPlXOcUKFg8zL{%>=!Es3W9FKkl%W;b%k~D@n|*O-X`Fk|X^oCv;aaiK zs_KfT?pb-ogX9~5-6|ko$QqgdDA5+r?%{}p?;1x5dDOjY}XTOVx6yLOJKf1^RiW|LtM%mD@#HV@x>D>16 z!4&wv-(+pB9$x<@PmquhvUNp3MfAB58Mnz7cI1efn>BNymRX1H6>H|#hPVRgsKLmq zI2{!X1y_dBj>buz^+oI*_b1F*1{$&#%^phE?hQphVcJ=z(T^Y@trO}Ig?e*auHZp&otZKBB2Y zGz_ta>hyiFh0YJTDXg3ID@#pY!<_7Ene_+}YIVw1X5xV0pBY9oX_yYPf#HdRi7(~| zsTTyQ(ulKvPh}&={rmV_2ZtBIDor|bCA}U%MT;Y;Kfl5$BJ3w}zU6robrFiRx52+eWz0n0@mxNR>&X*At%h7w(KFgaZ|$3l!-GuT$kJNXIwpuo+RYUnb^xIiJhv!IFhfb>|8106%_VCl4cwfEI+wK z=7XE7W#=x%5)ISoc|gANX670sru#eM%I}G9&ZLRWw)?CEA@t2#vlPF*-ta|SWU`t1 za2ZAgOnxpDtpdOn+fw20mApNq@_4` zlN0==dZ4)6R$D&FOYn6(Yq6l!Gj`#*^`4#`X`FZIL!D!C}1VJX+0w#sIZ+W(QG2~ku z^A)r#7?iWPL)|grHkcYhRj6uVtt|}t99OK#B3nviRe?vaS?Z8H#T#o%WxkHP-(>yCQRMq zahoG}+iS7f%-N?)Vj(HnBn!A?mOWF;PA8+ZyIPuvlx5(lzwa7sxSY!+AqhB_c?qqJ`>fDgo%9|Ny1^O!&x19_(Kl*<_ekMawHkY&9 zI3-VjxzRVQCCb81i>5O(J~4O%CqON+pR52^GES~$lb<9S(^Z2nK+P~K&v)tA7r(+B zei;M@^=b8rF%p)ONMOtFNS;V}egWb0`Sk~d$+91GZycx^BWEH4^RHr*;kg2bAKFM{ zLNrecG=|sI4sAN|Cwx7{OuDS-{+ZbNC~11_zcifvFa>esW63NF;NzhHBA1f9sP+W5 z>z$5U9%RARH=&ut5Q{%-Fj7g3B&0weE(d|fAyitss)}Od?{%A!Zg`VzrJ~JbP5s6P ze{CBNyp>)g`BqL<$#ZtR#Bu2bqsURN!=EGMH)K!?mALGf?MjzZV~Mabe+V-D$}w3? zreHn_9_O_&WQY{x0fKD?zfra0CR*kOsfDzU1lfmW%&OTAgZB*X?p_VBQ|s)`a_nq#Vu#!a%65Qok0+i@`!7#+BSO#-&@r)j z=3_!C-mz3c1K>XNihc8LPX`ppJ)RQRC9*CSBg2R9fg(`&)1yD@w(f~p%Q9M}Bw~v} zH5hl_0n~8=v$$D_=#WP(7YY%)UyC=ZQliqiPRe662Smc$E1^=srDzsbYOz(w$-5o( zcI8Wn(;Sy!W6GK)?AQbJSZ+Y!LwGl{wtcr1RJKz3N@aA=?4i@sd&Vztkk}#@?0coU zVj9H67qr^rj(_|>oRTB@YxmNR#`qcgyKIl|Fb_78WU7{v`!%-JesxRSZh5Xqtg}BS zOEsYMV*h>Zs3N8Q6eJpHkXj2ug~H}ev~kzAzTl)OK1m1I7GWMTLm zSk+gOi#f^Qfmp&LEMJ1HO(p9topR*eN&I#BxP_b3kN%PtQOFO+Zol~)@+6H8UOUB* z<47Ky2+=^Qn`HvN7y-wW{=C%Y&Kq^^)I9*e!W(G(lCS0^QuWsf(}I^4Y=t1;D{+m> z=5=_lA0c8CuWi5Y5+~}^YPog?;9C|ndSav_HfaoeHAmh$5>JGED}51@a{TaVPM{ZX z1voSO5ZzWs-&J(`_0LZh5ufP}a1-f7T^+m~0HD?fKPEHC0=zPbMvYhRqBpVGb4CM= zIDEN2clW38?Ked(6BN*CZwIW$ywP@G_tvShQO`4*%Ho@16Tl9hS<2H9KQG){D6O5) zuAa(=iB^`BYr?uMKj8mVZRjjf7nMbX+XOL|0Ig=gjCj+=CuO1+=W#s zip`=?-Fxoi#ly_5PfOjX(SU@wLZ{?V9;G*^BtBxY-kH$xW44{%+O>UWTath$UCj>g z%6}1iSDhR)AQYeaoAqV;eREkq6l8|Q`k|v4vb=H#$m$_K-0w`W$B`sQ71?Il;@ktD z(kI|KSM5&?9p7bJmkU7a+V>iI{$;dbm4wtEprm><4thiY? zxfwy(Z%sC#gr!|$65Rj7TbNZ4N2b+WJ(K_jR;P(^FH*-3O0|Lv#rJNT%=aT#y8WDw z>cZX2ZTI${oecp)QTzyA*$)J2?MaLX1ak9mr2H+vMRxApICiUZ+xUOsC8h0@-TJJ+%O{#2TvrbLobkzIzHLFRk(4BcHrKg3@B^J&n{V=H@&L!C@D?S|1S*xaGm;<~OCqN<-s1& zsW{zN_+oz*RPMn95n6|(Gou0Az=n!Qe`aA%fXm~I!jVh8{%v52+f8A8-wohT| zHVm^=o*V{yK?C*GKrbs6>-!Zarbg` znRg!$7#LEgNrcUQl(BEw+PlT?fXCr)p#xWO^L81#Fy!x-zc)U=eH?pNQ{)s}Ik#0x zG7-tdoxzo};Z#5#$pp}3-1$;J5dfPjJZO@&(l3rZch@}f=W~IhzO~zuoxmp@Q7fv< z`*m(`gy*Hzm$}Uen;}mK98Td(-Zj)O8Fw1ahye@&ge8{-VUYdBpbm;n^#NtiK*_jhRQ~`KtK*}C@ z+fWG7sDe7rGmEOHJ++-kIO%qpG3#-yC)floV9`jBjANYFD5K~q+HO26u zgP%>&+U(BgMPOPK^zAYDTo45}%{}QXr~Jh@_@Ns7W$B$GKNz$Kjnf%`8jK=s8P@{h z=>~@tkm^O>sl=>l_~uCL{x&MXGafAZQkOSZH^31Bj$qzJI7?MBrVwdOu_1c=`--oh6Ye^`d5iX3=xa?WQ@;1Ms zv9%KnE#ckQFZ}YT7|}^7dh)<@?D+ zwEnVBj%0yezV!_s=7CX`;FaxK=IXSO=KtB5jT9BlKdagUvl;g?0mf`;W~AI(!3!p2 z!y@sQh<7M`xZaX;t2Fbk=6t@s;=-tyZT!0@v;%|eiGWs5xPD^uaR-?!a`=5 zTvZf>deF_aQHlmA67y2YM$?B_R*mQ@iOXfYvZHS_-w6ghK5qOIx+EzDS84B3Hg)A` z`98Q2IW+L%4-OSU0%Gy^86Q-d)>6fMCttvV@3Yd5X#(v4H)UD=d+J@h}s z&f~>!vt+)|5Z#Q|lyxJ&@OiCDW{*ID0OE^L&MQ*L$l|+E>0O!J%We!P9&Y2*2^_O`;I3Eci2dbrd{d~c_!i363@#bYmB;Iyh_&`a0_$D9+W4>;1E8 z5NxBgZoEY#8U^bjHM{JyPMVMWbA73DBWz#!!ta@*O_Q`Go(6Vpb9kXqsQubwD6(oD zS$itIt*pK!6Y%W^=ed0D@`T2-vqY?1H>)OUnc@xZdP8c;;P*}>g+}ip#|Het5sQ8k zOA*YSKKAaVpcT&=fzCbhT{(*yS|V#Um4E^M9nD-1-vAqu3Nu8XFQ~Vt?3a; z>3$8WE(lgHNDA_8ASgVyr(fNUrZlRsg${1KJdH|H0f;vRXX2O$q0)v-!#Fz9>9%7 zl;Rz5LbjmNHwVdtw>;-Vlv6j~uclm-fHmP_uAqSLf(($J?HEVqWB<>bn!-{@Kzi|Z!)nc|$XN3{=#GVH`LR$}=Y=`jv?=v%N8`f~?>i0Ji|%Xm{FsBEVq}0Fv`i`u zMbf#VG)>=2t4W=~apm3=3~(4$6G3OM(L?7qrPRkdC-qY8o05KSj1i%b`2aR!#-tcr zfK6AHFmGx>`!KJK*l+daQpERLI+WJ%6C&Obk&GBv()9Hjo^Cm!a&kqET)nRX13p>k zl$cjrtn=^<((DCw>A*Bc&+u)Iv?o$%GHMKIOWcjrg{3JKE&`e&ppyn>AP49n<`@bt zP3OUqSg~meokGaj>VAlSl41}CgWq%M-cQKpgL7{pF2kI5JELOy5bn;t4LoYv&m|!f zaqOI&zK(%hZc6ohjO`s&`es3Y*Bi)U|MkN-Ew$8ORcj*J4uNZ_oTS@e%y}%vsKra3 zYH+A68prA9NX>qZ{#xfLibkmEQ(jg_=6PAi$urHN9s_zo)apZoLctO3Q58nHbO(8K zi#;@HeR@NBSUL9e60{sXyd?SolaLGWN{d$AwosYc?_;a?C{9`@?BT}-L3MC=+Nyn&34(`*ql;6d8|{Dc$?7w;z`=E})O+1A zt_(66{SJvT5XMwBo=;yarGAHhI%xyh{}0olg%sZW`@I_X_ln7=;4 z@>V3Wp1H*!TZ6*ToroV;LD%>9I?&ZyJ+sGnSV4B9p<7zbbWN;Wim;$^O*3B79HrE& z*iuK`Yas4PDVY+F*P}H|@5O(^S<~K_Buy1-S8HOFJz*pXI`vQ|D1I&T4}K!<*dKxy zy<+L-JydQxQIMY?^@_nmXfX8|D5VjZ`-VT#>CgrMq`YsD4o8lW$%h(l%{R0)muD2m#=s z_;s7kt@j5jy$aoEjZU&~SQ65_F5qjVi64r+C+k>(Eg3@)lvUz~RcdY!A#((Yo@oHo zMbfBCk2hc@4C&6_xWa%uB$OXVf!rVlhiOaHM`gE^#<7O;IG z0Z!&>2mqeA8gt@?6U%D~gh#pAk?R%s3CUC$sVr;?Q;k$umSt*qE;4%y;a4ZMk zxpys#l`iuFfx=sdIJ5qdU>*P96wL0WW>Z6;O934p>n%`sBKedb9fzT7)mt%;tXgJ*@z{y)(-3Sf|cqLvpx z18VMR&fw3tnl_#h-w!QNz}XA%xGdoL2~4Mdi;2#ogX~1y1yP!UlZ!Ycg|9)W|A>Pg zWh)cC_w0D2DnJo912?E3?kc_cjqhAb#68}BS%BR3QM#*II8pmHdHn`;aG%QIDGKpI zZ|0twLYvt2w*vX-7&X~qbdu9PZD^*2etfH z*b2B6aK7~9U#R<}`(WlVy{ELi_D#JQDtv%*W_6JG8?K{0gMBT+h`w)S^54J6B;u{{ zNI=SQV%#&y%$bFZ+>wr6sBN2~1TXH+iD?GeT2Je%zbIm=w;9{<7p-|)43Hp z^=(|fs|gZxmE}*m>)aNP?P`^*wpC^`T*J1LxC_vcS?IcP&_uB3iUmU*3w-)WRq!^ z6-iMl5JTl!{qonOo#@+I(PumepS|fdxjTPPGm5e1#b^d$5r*=QPIu&~yngumZ^khP z3q?aOQ0c=U6Hv=wEXRg*;QedAe;5d^hg2@mE%Uc_-Pe76w>zTzGHl-Hdf~xiOD(BB zrP}0Rj}*f;U{E&ywEqoG`izT8D}Cs4Hq2`YV#>DB=#sy&i)q8u*&NQVVmB&5etS14 zLjrv|Cs_h#3)`J_5LjkFq;>>b>GD7djxIcFE72^#FLBZzY(DS7-vIXR(e zS|uJx=$bVQo|}4e7V#F~G0DbZM<$@-*7-aS3=zTj+0rdCT%Ua{p@A!vR zN30V@Gu%2rfE?Q$)BNJIZdF@CGN!k>|~3H--@W9U3G2T^LWiQ7^Fo`cpg z{KwHWr6~M<8>gJL(d?&R1O$xv$^N#oELq*dQ3q~7MVUs^{#GsyM3IF+sF0k7NT6Rna{kuh?7a1^3M_yG0Seu?&XlJIM}@XO zF4b17gn+=@Lpo+u>_4ey5InY4aj~z_;ADM8)rq+PF7UKM&`H)9di7{Ske7(|HfMTZ zqks^W+HmE~f38kQ69M99Oi z>B?+#bX)x;zr(#G48f?O6ehy*L1+fSb4RHA8-!E5IXw}o>H+-M#LCRT-imq|u0*BQ zTU7w57X9>vkXAdu;sR{L5)qdcUmZp>($IeoKyUblt$IKN)h3X%K7` zkSN@DoKmWTJ?zx(oCQDY7t{_ne_osbL7x-Q_YA~{*&S0{g6D<5U7n^0xmKx-u8DDM zK5?RE#A6v4^5M8cTJzinbPw&t&%KP=6_RQ*U*=6De>y|yXJb6@&JYo9P&!x$ysm2; z@s`2^xyo${EsHfK7zyvNo(vqV1~I}*E3w2j2CZsYVoGrP1i`;MY`31u%2dV09Itw`XN8Z>2^CYY_+g@_7WYRpUg#&F?vLqw z$jg#?HQ)}AAPG`C>czbS7^j9|9*Ax}z3e1-f~3vok!&Di-x(z6pJ$QslKzO?-FS6m zhP246(l+Lx$dIp_R(>*sDPe+?a3TN5kGMttla!YjW1rT`=ary{1)dy_Gxcf0-d*-4 z&rTbKxT$zv?xe2-Au}*BS@#>blK1%>?Et&ZOeSucGTCpW%G0CqzUKe3m%WS$IoUDh zpfVJUOh^!8=^#wS`EAo7w{P6xTkfKw>W@;i`P%&C^nAM?&|F5|DioxRGy5;lA*YUu z;3y$e{NsI|Z#vgt?=NRI?sG~x*3eTs7IOb z_bp=g)n6VtiFq=W(>&zI3}~+ld^=p+GBp}H@~$koo4HC1#0zN{~1A36;W3rYX3<{0@fk&0`-`i7_I{mQ?O^YB!CKt%wl9g zP5IsU*-VCX{1PkGz6Cer7{^;FuO^=kndybw=zDB+z;3@4=#F`5F68oPRNG6yDb(@kD$dvjN zh-x8HHptcK$aBjjegQTi>|fDOcX2#L<@3+Zqd^8M(T<>b7MX)KNK&V3TcTy5B`dL! z&zL@tLwTw7$1hStZK4Jf$-WEmx@#v`srv`|^stQ_LHg)G$d<5y1OLtvs4c=!M!57k z$&6)6qr_~Cd*F17?KjDbdme%Y)Pq@PWZm5J%6lDsSi@>B+OQL7v>|bmTw2x5$v7-%en<;MmEfX*`7ohR&Qy{{Ght#+i4Ww1fO#3rJ z4a_nadoS>M>$7b)wHPWpbW*_7Kw${krNK><2E0YH5)=KcA9_z0iiWr8=qI})HbaBi zgq9}lL;oih&Zj1?MAq%!=a#PDNO^I`Q)}Ord_>po+^m9sGK+lQXC!buFCf zR=a-eo=(4oO3b~pep&DPfDB<1{1K8#MAv3RE%*YU8?zgqbbJT-`GR6ry*;=f(|*=% zQuNNces?B|5j(UIb6bflp>;XE*32Phq^83s&Fa8*5;S6qDs3MTYMcr3WcsfV#mn-s z6wF}f9al-J*9db+)&AEx$4fzAz z6?o&^G_5Cc)Xt}gkMHA^hE7_hZgPtZWP&tKBRlPnFoxZph>ko4SmVfords zSAmO7@}^zlBQxVN9OTf8$c%4L$1V(;YC>FZJLR#`gX`Crf0%8-@F{z=8!O@W@u)SN z*L4JRuL}{UIFyGXiiaZzcT{Bh^9VJY^P-BfWF_GbzX1$-nFas=4|AvCcYrUXjulD@ zNZ!Q^YvC-4oD$ZBS@SFhfS#oT;BxGJTUlr01jt%U@lkZu5MYX9-r}tFS(6IpS?(jismgMESn}FF?@0o5{uy zOlaizV^_K^jS}}DLrDA6030N6ve#CJZi}|v;|Yrxt3YI2zI4^KIKvXlP71e%d8_Mj z=rmSP?X1*YW^~)uz#nO5hQt_JWw#rkFksR~jS#b-S|Gs8(~9Fw6F7<~qorM87}WxR zHvJ%QZdw9}`3UaRO)U(j&nWUQ#P{X{)<(pTXa%ae^xsrTq=(G-m z0`Zl4I)(%1HCVCPSpf#iv7*>qP_0oyPLr>#zUl{ICix<#}| z-r-w$Uve}{%cQzK-t28M0XRC>+H{hwVGo+UR#iT&kH#d>{V z$=YP1_hjI(%wII|Cx+>*tEWeqB4cLrrm$$wEcv(PLoe(EaX=aSCaYzX7&oU%pAU)) zs-HpLsPwxgVyBdCMRu%srtnD`n5|Gh_-+5tcmMq`-jJjH1ArxDnaFe%+dlvEA0AD> z4r*IA>?+<22VWP;NT@CtJ`)skRc>;f=V_zeeR|@6G^wL1Sisq?I8aZ<+Y*J&126u7 z$FTijm-=I|<7ESht&_BT-kP^+_s;PCFT+Qaifccdp_Zm&Tcm=nn%oE7@#Hd6PC44J zKwtrvkcG&OcpXqFiAh>52lIuTOcydqJ-YJ$2qFn*bZ>lee!+B?s!rYQLn0W5_*qvRDYlyq%wK!f0mS2<+T%iydwFDS}0nO z(MCK-)Oim;XVqJxCIu@>09pwi-bsaCD6gL%&9S9g7sleHbdvUv)kudj&U(=!}`BjU(R!hr)FH4H`5{d-pDETVNNRq6R&;VgtDP^;7C5=+h zBUQWV?ud&dD^Tw>*^2mi#QE=|_{stkO~DT9YM;P7On4D<==!6hNw3Z+P7 z<@^MZ&LH491*SxB`j@MVygq<^ll09Ok968}`J$PpTlkQyIVF>I9C*GnicRnQ7<8fw zy4#|`u0VcTJJ%?s^{tB9HK0ltT|i~=MQ$Zl z>U^%u=0Ks~_9}DNFaJZcZij;Qqo{$)rexG4_QY17N~H^J6OPI*sV5ZPK-Gg*jGOWD z?2^62XV{W(_x-CHjfqfCPlw+Gs)PAf|B2jE=U|c`IjFv)j$xuSN>Ay|l80~o#bDR7 zzvou0#o=^vpufKvX@}Y4`2gTodm_WXZqf26!G-#-8-M53Y@P0ob61s%IhW)#X4gcP z`L--+@;eE?Y8!mLkg)rHv>vXD)(b-3UMe6a&d`*WZDNZ2mVg2&n02gy4s4&V`u3p2 z`|n1R_KpqrwnJZ(g>khQTZRg;D$fdm!$b;J#H)I{A_yQ7!JkME{7_|k+}53MiEo-irVjP8=P!ZhDGi74X5;_m~MyYekKl zYg!(SgQXjFEr4Aj&q3Am$bEB5@Va>NTk~4lhYyO}r3lyp%;m-eM2F4rKL)r*>*1!a zjP09BW5!w2bw=O@w^BZ9Cfz3$%84}F=RgELSdAV&gAe!Zo)kd+Csa9BDv~C^P67p& z$NS4W!T(%0hCtE=u|iizqyF%>Qt7&a^Of;~RDDXR3p?g7od5p8pD~>=HLVV7j!}5O zjX3D_E~c9UVU6S(FdTDhaYlWBxjv|G{^!3JGRTPUal_yM02!|#?X*IFakG*duAvDJ zoXU09v1p>ru^xl2Q)2L$+BxD(?+HRj7;>;LhUK4U&gY@1!t39|+S6D700RINCIc*F z44>1*THxb9qtXXBdgFbVpKHLn$LB&rAQt81J3Co{r_&ZcNW=X2#EZhw=)=vsLzDA6 z+t@|^b9Wy$SWVg+ovuo*RjNGeO_XKEHB5U|_UyTsaAtFd;xt7oDexEzP5 zU8lHP*hvsuG`lrqDVE^u5~T>;LqpR6KF3zS&lTvj46#rD!DeNS}%h=6ZY+N zOs~vFI#M3^XeWaG7n#d|Pv?7b@d8VcyiLWBBR?|9;r{M>=h4vC{zp9X3Ype;lu zEEB?hzdK%a{#9vL$(Y|i#-tTQ>F{tE;pV8J+TAus8l?CmB3G?T%wLg2{b$7|%WT)A ztk9#R(qD_^w9KT)IiOo=!petl_=qM17ZFJiM=>^BT(FOZ1W?#}3olqIIJtdLc&9cj-A>?{AMYQI5gJ7(vHbB{>D3E5|oCEYML^ML^8X)?nK(NQf zX;N8>iN!<4{c0}-sd?TbgHlvJHt;yvw+8mWkcD6x)Wr+Hz!I$$7!NB-_3ja!&QMjB z1SPc?`taI@e;!A%;qtw{23Hh@FLC+{aL)UJd}Jk``6jy=%i4c7i)?u&d2w;SaF-CM zQHcHv8L5Rd6rDU{P}^CX`v=Uetx;1wl_T88EEaT;--8dVhghs!`9`dMZ9Zm&WyE!1 zPVD?A0FD74L_~|yM&+t26MCC2*cCY(nmOmkqtcygPdi6`7Kq6j;b6Rq&s*_EhG!j+ zPzdHYDR7yT<0Ogfa&FZ=_<4WHvf7Kh?Ci*yg7d;r5i)n=V#DS(p8L0>KZ@(X$V8+1 z>(*NI+HIVw&rxHAvBTK-HlA=2KVJlO1K(P>gbwWE$esD;bSmP+*Ba>D$r}}`@LJXx z_zpXZT$4@JPeJOSWqVPwZW)73L+bY1Gy4}qkt1UOCk8ACs;PyK66HWgHoQ@N0rF2O zqZ>}F@|guqpDOY5WAPv)ulpU8Ibd;5!uPfLE8J~9RQPL#$tSor{%`eO`ylp3{VUl& zJ*bm|?I79oM4^p@60Ag3%?3F_?-~1Y=KmnscqI~z5=}vC-c+QG)HuCNrw^8w_>IMx zf9hl|G#MT#*T&~stC>XYULoji>Ryz>?;gPS5u-8014!H-TI^q_`GK4R&BR=%7#E^YjG;QSaZw{s-mu? z68Kro-IpiLuN3&OtE7;FOP`51icY_pR&;r$U9SqaZ`fA>r9sn9|5pe|?Y+vDsiIu=eg5~oSYZbCpaEJPouXp^&<%wVtTJ*Ed3trzn>@szJ^&<(o6 zIF}Lq&>DxlIoE4R?$3b{=b#BI0ZiE?f%y|;NW~aoKu_fxq8lM`?7rY)YZh}EwePQ3 z^!;syIa8s>qBdgP)i40!+T+6?U zx#X)K2sKZBygR#gF2XqH=wCr=2W<0C3biKoj3Ga7UVJt_ZXDsrp-GS=BTw zv<36VT)%>Bys~dGF_|@eoKdX~kdAy;0@0ubw_mseXKlQ*YX~XT2o$0FO*g%n zHf7-5!oE(kt|kDsnGL$hIsbAN8QSN5?o5ErZaJo|mp{u&Cc~fduEgae>IhymxFj)* z2-q_)A}o>2DD@QyXkJELaYrSl3~6|CMdQ?dK>k#4KonNeg(%Ze40Hxvul}^oHbVM$ z$grhejHWwQ{4!12*~9LG9}Hn3amt1oR_gN2Gepn7nh>5>?rm$5%9A?Znd3OyjtSRN z_~{>+k#WyBrzSZ44J<#a`U=)j66fqmGjDjjEo#Ue84lyc7DJ60u}wsP{tSt!PUCL` z$*hGv5u@05O>&bkI5BY#?9#(K z)0ZH2GtvMmn|R1u2dlNG&I=j}JJ06D`9H?ocUaJ?Y&m+h zHp4mc3xZ+#o45W0iO1na=z1u3UUCk-%TgwJ?yGDb2HiaRe!-rL2=A0S%KdkQ#POdY zALmD25W+-@@3bt)DgqvTdD51>gmEUhFk;!`4sA=}i_!gC@uD1qJL@@#h4(ga$<_bJ zerd#lwJ>m-VwQwj*eb~g4p!y=1jq~+oWQ7It|yq< zASs3II>Onv$qW$GQfG*xgVd81SRy`0y|3c-_0OvWs+`?LKrCj7bRzI)`OP2y|NogI zzyJ7dDVM4L|8oV${SW*p8BhC(ySuym4AAAN=V`QnXNwPr38Rh1U2qEj>U6nBn69~q zo%m;;|M8Rmdl;8U)_rbfl&A(vD^18(8HtyNd0;Md;ZI_33XK2j_xIApR;|AfiM&qz zAELZMj7Au47|=R_zL2QAwAC;qlY^tI2e_oL=|8QK$>kwY0w*am0H0|TYkHOzl zfAh=&M;oz5M&0WtD@h;u5~C;26e!iozNe@hd{hh6p>5{ zav}{@aU7plCdq=Hq3l=%3(<@j0|5eftcQ7J1{;0>*QxOQ+a5MY#^lC>S56ULGETUL z<`GI|hWvP#gnb;D?R||Yf(K+aGr%aKv&dZED_9$?3=EPF*KuuNE2CL0gly^q&Q`S! z*Yj=G@(QLb3Y=N^qX5aByqORf2ZiiD$_a;v72-Z%vAS51x4l|z$?+1By%!TBkdVtp zzvB8zTb-K4mSzACzphkoaNl+K<^$H$2T#Rbh& zp!S{pgb*06vtb1f+GJkvg9vM%#BcY=L){+5(4`6@@F?nn11+!n904Vf#}KWB<3ZMy ziF8lr1F0Z%!1dXmoB##AG%AMEcF=L@ZX=RCQfQ{)!~Ak17P2>}IP#Aq>FVM&(nG#y zgwN9zdI|AcG4DY{TK5M{kZA)L{FC=sE8L3NN`mqAHjQ9$Ej>zq3y+R5hiMgj15U71cYX zn&?CG(6+PI)$E5*-laYsQr&$G1l{o|deZhm3LE5)SD%GGz!=m1U~sMLYU44@bw&26pVTUVNcVQx(0eBG@F}Afjrz;4uK~x=XJKC);Q{db zoG9H>{tOzdhU0v_d=uq=3d1~tB&MIlnDE?1#qh=Hry@7)D~$M4cIo&?y)9p1vRf*bl>|aKmTLozkG{bWD=BD9l8HH8W9ILh&HMdZV~D^w@dKu zHeuKU&d|?E*!1pF006N;oGh`Mz9&bk0m^*g5iocAvf4i@WzY|k1W&VMj`99$oV{C9 zu}#@0^5O1NKvt2;Ehj>J_~MS6-^y>ypnBI`ZRl<=mdvBKCNs^6`Csc&ufgQH%@zdN zeh=K`@aAJheYWt;M*_j^RKbQ|BINaBT@L&$*rvoT!#XcZI3K+3n8&Ay=kK0G)KY=e zibROh*GW^TTk}pt7&gjsv+lFRj~|FIkpt-ZkC^Ph98;V>QVBBiCUjU5g%=zB=*Mq> zb15R&SsbK{9DzPxAS#L*B?Fk-%r0m(a1?LD(!6VxDf`4454VyCGQxODf6O$eFfn|4 zbW02)EMplPSqcg+37go+guHRtBrx|Ixwgry;K;l6@z{pYHs1)DyTwRZukL(6ywf;%JG$coyq@B3-d^7 z1=dNd-VAjOr8~yvEmc&tI=iMG!;L7AN0$NsiZrEoGjYh?Fp(M1x{WXT7X~86u}nd$5PHkNrCII-xnM5nrofTw>)$zMJ$f4aicPq~%54+0 zWl9uZlQheiHsS{CE-5Dbc@GvETdawckQ#JD10-8{CUf78uQfeh^_bLVFE&u9A0x>Z z?gRyHk`^fBNG%$;9wFSv$If=J8ks?E?n;mAM_}ZQH1t!_X00r(==pg(o3Ran=?HtM zFJLC2kd}shc{+f7m*qFko4_Ln9a{IZA^W}Uh^PlV(HhNXilZKI11KBiAN1}!;f{Yb zvu@>}%}!|j!cj8ITbFJ%e{F4jgdIcf0Dds9sKn<3`7{yxU7OrNh?$!F`0zc%P0^3s z=e4{_oRYKAvvH{-E~Lsi3e9hLo^*E+5D06%q6+@eGc6F=U1mHcaPYpdbrMI3ID}d zVvP6l!%kgRpnbqvxM%;^5cs1yPwOs8dh63W%q#ybRq!>j=xx1c`C)lvFO>o@8xOJd zU}`ECJLfN2d=)w{lRQDio$ZmSSzW}M_M|Uay?88Z;=u=(jLz_33*h&`Iz!|`J?6A`31Q?tui2FTHi*X;Ayyfx$LUbDVds780p}m z8=f`2$Ab=Y#^-vG3X#8uj5y78B`UYY`GH5^^dD`I+8$j3b-PVZZe-vXl5m+ zZYAUDc4klft$4-oMVo&QmGW9DxLUw&g7hGYdW&;L^!&S0)rU7dr(g1eH>0;D;3z;^dH80mZq33b?| z8FKiP@NY!|mVq4{p4ackMzQpfh^oEq5h^^Wh}`!pNg+JG*>a!>d}!#XAKobDsE)QU zW-tJPj>Bc>*O6p#8g+Dtu9<()bJ8e`1Mv{gTi~p1VpD7<+ezjKoS`{72()(dNgMk*r!lJ*B3~$wzayH>H8P<&a^ir67C# zFqmu0SN8ONPOeN_(-AoI)&qPrPD>~AbmB}5>res1Cb+TJ z`2DP|uY>PfYy1Vq2Gp=1#@7K*eUC+fU5jVA1$QmiyvInJ0aw1>aE4HPF}W^c3F=~v zRzmL*c-KJn-;P0A=_PWh6&-YStRqt8Yw6mU6M1VXUPhC;_L3J7fwNH-nZLFYTgJ5| zn0#n=;_B!DE8gE@MKaN7SFW{VyEbH!#KphGUOb( zAV!2ylmY>i9y<}MW#Ol$W6?cA)AshqKAXV&L^!L}oIzBJYb%)FOcakr`wIFgC|5)MDeV_2_cVVJ2$PgEVbY+I zTD6}cnUm@-(zzR*5}E14Zw4bbt-^GY&}0)H2jH zS1D=O6H3qNI>6mBKoELH(XwrJ)Dt207qBUKCn54$zhX~45|~VMI93V>000930L50J z9e?}}?kEXdM3Nl@yD+zQ0V;JK2z2HCZW6H~eOZ(>HzxCm|8VNE`8GC15dFV+4%!H1 z0;K~^yG_mbt$Lnjh)(xGO40NX0-sj#d`JQ}Lt*GBFx)@R;GTeANozXmx322>dQu(8 zb@<>RF=p5-L8;2Zqj5EvRopmq-Sy{B-9VZPh>spt;o{majNyr8fyv4anLN6}-~# zAWI_Nv)V5B=0#jRxJERtRh&-d8}>LC-FAM3cgC>VDv&u3H>w33&fDz2v2Td+1|JCp z$^jX?SbA(c_qwOJL6b(rBDfZfuEO{4H*{TU^kCll(%&N*Uh)CQx^cxHJ1{j_$qzsS z#e4RlJ6q3SkBOaSK77)|M@KBdKesn7AOfF7x|JkNgd{U;0BNr>^7D#$$=PAPmseQb zvjC(u;>?jve0&v{5+t%=o55LIJJBO$oVun3s+Uvk(W(H02^DU>qNH||CkG~Q?)f`{Bd25F-^ouHl0DX{g?eD5rt{5|8c;y6uB5F=u@^8xNY_o zRMbjNg|y+PqT223YQ}P}4?z3>`J5{R9nH4-*w1mxO50`#Em=fBYREzJ-9XQpC47C% zPzG|HlAVS+o$295ZO`Yz_Uw(PBafKZ;V`qVFHv7qLjc2CgarFYRP4hyn-3|R8y{yC z#}?RpFWI~qS?UajY4fQ*2xI6#CVX;#vK1|@Tb-b_;jS+-%O7?Bp?XsZe!$N}$c!)< zx%Qr9q@6|8tJc4LgRd)kJuE!Ja@hpBd0|YU1%6j)5Q)Usa?~Jd*1qR&n2O@3YCfW| zRXaWW^e+A@{XzEf)%KpJ&nX=M#CxNY6h_)55EePWerh8#czD}%Q9lqS_bzSXM4$;G z2`6NHnP*C&c84t=viRU$5!LK z5Vg03e)w~c`$QO&Y-bE@Cn1j_sVo&=_ds{(46I8y+7?~RS7?8<|BTZ7%r0yoaSGWT zk^Bu>V?n*bYlY$2jP2$eUx9M+Q5)loU=;2$&Q(a0B448mfx7q1rXQqfzBe!-zS{;2 z-z@kW{L~lOEC)`13a61~L3lMD2||MO0O@vXH$-nE=Vez3;DOH?w`}@OplBdl9)-$ z!w|6_3qQ$lDF>Xf0@O6^=2UP(diV-tt6!7NT5cQ->+ot{nZkQyl5D(~>*W%&>R+aX zmz(It>V4w+%)DT}WN4fE3?Otd2iVwp!Z}cZvN<2hjuVPQfJ=BqW#2h|p}FKgB9iN4 zxti<5r6WZiGwG%)W|uYEVs*Pp8&EaURg@Q}>@JFa*tUYoz*4dto!M0v4K{32{&9}z zjycCOpxSejtB4Qk6AqTAFQWWE&CxEmxJ6^>%d>H=KG*OIxRtlW(MCm+EX)DfiIM%J zS%R%NsCa$IFRG6+TlEzKSmxcW^ygdLz#EEq|_P==&TWL5%dg+SdNesH^ z2z{y{g@eBI$98F}~4NDPT0sB7#MZIzumSNM*w03##?e<7odZKVX*y|sA^cz6kc5hVLy zR0QJ_+kYt8_(B z(TP+7B9D#It3UkQuu-+?9&X&+Uglo%mH*6P&PGl`eU_59Wsk?R3JbbU5;E7=i9Bqd zzteAbP#gIJCwNgz@oK9dx0qfxI7jB;qA%Uh?QRafA|<&?H#5KupzxNCW2+Pn6cwv2 zF%n5H1+$m`47<;>!UAiQ`en4BPi%1DWJGI@S9#0PC+2kSJ+GE&>#k3!x-1zubsig< zN30;QbnZah}m4dyo~%Md`6PsyXnMJOp7?qcqs2S+M{AwTCk-J=ufr`?8r>nH^O4 z3bQ#P^ALZJ$A5*zN!DXM&i_>Td2+kwY@ExN%er{;gmZb<&>MQ z#(Mz^IP}X{-w4qmwC>MUJi^RS$C1&meiv!@fGhwD?O;Bj4QSGrHDw1Mb$3wVvo4>g zPdDj9We*POwQgwT&tG4`60yUaH2<^3FGI>tba&;m_C$ZGxupukgRQwxX*9uSUPBtY zKeF*HL!B#sS(wlQ>x&u*uw`nMK;k7HL+P+q7Bq+9o<(nFVy29o;Wrz2p=roa zrSWn$^=IeMwTFYyq}ouw2c-xsCvSp{e@|yy%`DUdd8EBdgzL1_1R*J;>VZmTDP>sc zFU|!!q-o!YV?k0NmX1W<&M&%e8&OBi0%RB>zA<(FY(1MjIM>_-2TAplQ49}QE1Npw zuOwqHZTm3Rj^Gk{B%{L$H#5cJ^vwrFqQV1!0k3;B)!g^&naNq z4HIfP#~c05ZXIp^oPlHzOS2DIX1_y`O1?$fn9oItpl!>HKTc3OgSA0GomC;_^xwGp zZh9(mIKGZNC=n(kwUIQgWeouyIIiS42y+vCyMWAhJL+T7@Jg1l76Vh((ehGZ^af%< z-Q-MlYnCS#l^Z|sW>tQR#=C;F4cV&=K^mSpUa!t%?NTH1E9|c-vdfzq+L#h;6*g6{ z6E_|78-x+*wG8$OaN)+931odDYo1)O&IMV{UIQ$n`e1?^8L<~7HzMBBkhCha8ny?r@6QT}JzIs5$B{HZLRgKVO3KL`j3%Xc z&55hia>m0{wX2>A?$h^-T2&`^=!*`%2V|1H3!p|}~y*?-THJqFibAj0$5?Z1U|;KIS~(36|@8(7lD6 zMOWY3t?`<2!SOIsB0}I65XFC$(-964C$c-Q&?K<|=yTVA`M`FOyyR}7lN=}4Fnk6w z(w>r$nn^SwFDkY-STe;HGxPX%oa@z7OlSI73#`(j_S$}x2ou%R62pseoX!Cbuh@B3 z6}7_prvJJU*10XLY_;KWEH7(sC@lfi+(%YsZ%Rj{#_*|taz4^K zCcuf@(^!Ew20fUfc@hYfE54kiC;W{XBfAVBcEqhQ<2idv!nkamp|3EbAcS%ivx6@; zfKgmxP5Pp;xzGOtA}9qaLD0%Soi(IR((IwuG0+3(%g%k3y9DdGQDTaC7FOE34$ND| zn8)}adr1T|K>=7T`r=wV=fT}B2qrP|Wjt8jl(gRvkN_6%ye^)z64D{UO+yLlNI5&; zvW=kW{eKqIH8ZR(ynQRSJPlOaIP<`0B0*cM;16KeWa3Wi8W|Q%p^Ivq?)=@G8dLK)DGEmGvVk%6)xxB6$d3MMgHN@^-<&kV~$& z)KPHPIdmqfeELT7R#)_J(c^T8r&CIK1-J4N8wA4e|JAaUBwj1iRmc%*>9Z1a`F&nY z{tnh$+HEk|Z!orTuGs!}KhBQky;)LLD^7wmvPzQWGNj4QDiW2yPTO#o;PuQMs1aEP zo+==_KBn429v}PfNv6wS#0f8dGbCpv0Gb$`j-hl$=9kdV3l?|QadL$b_FdMRq1;%` zG(8@7&WsSdG`$|PMhkooA~CRHo`O_oixM6+ah=tw7AntAeE)zO6wh^vBhwd)frY-m z)9%GPLLz{RjkVxY>K`pYu(IiSDA9m*;OnMS zp9i-T=a<=$Ci zeF_bFE_}}43V~`nxFVaHI%bI|6PutC*t;qCRX&2OH&@X?_ziL4C7_9O17<%FVifvU zIO!TnJ-Q+sQXJwx$`t?Zr^x`z(Jvn zt%sCuku(bL`4O_Zyo5U{Pzb-ommFu`0edm%07!khB2Fkt{`ha60EO6>0?UU~+3p{U zc6B+lI!I_S3$L4J8 zT!X?JniG9iY42X#hcsWxZC9ibzJh`cb#nb2AJj#49NnuX8-W3oB2ieMN2xlZC z!-6JFVa<>*LlJM2weT_%rZErehv5PYKQTP1_LtuiR*yzfRg+|SpA=<^87eR;+;@wN zY8xjcT*5<+DWv~PR!!cd=o4_i@dq7d9(xz967*1$X`U$*^JEDh9w*W(g4Nn0JQ&41 zrMcL2TT`_i?-uAN2%d8a)qQC$5^*W{8ML8lpYtF@b|C^df`@7hS&=KFyPM5zi~l>J z-$0^PSo!-FIO#mgwR~GsIhgl2w7xT>y7u6W>DD`X%vY^r(S!a7V>=9&J4q{Xf` z;V7c*&MTq0QUitM7#W`yz4rD<`+FNJQS;3;_k6kfbry;MRH=L`G*x1^pR#c;i<4l5 z*%M(aSuMhf1hsLh=gCbCVHeb6y_js1sqpzl3-L{_Bgu$}8$LuV*t~}+QVSwSBPHzT zCVHtJ#qIHiPHxYwx=l%L_Bs$$(rFH;9Vr9hvfzq|H7pVmAuWnxm_F>u z#SJueo;_hIibOlqn6B+-$c)@BUriIq(5$@DE9x1F^>0|?{J*Fq`l%+mlS>=TXk|3fWQgF zMgX?c@TvzJ#ODAi!H9LEZ*OVqJQz6(vUA`TJNou=~+ zmgC5Gn9tH@3r*jq;{qssIKK!qqpMQvSNDsz6z4pZj7PZ{zJ|?K7O#Wp;0iZhuE3;H zk_l-Prk1V%f5wv(_>s)|G!H8C?bbw=}72a(c)hWkPsr4kf|&n`jp^e_gqS4!BTk8Yk!E60qO65}!|N$T z<%EPdF&WDFrvk^6weoLiUKFzu<@_tdq#~Yg)(^j9?!`MZ=~Vt_-LU9TyFDm|yNR6M zI5iC$G+*s}kMQeH4RQHFtB#+yJf#@yEap?jC4AE#p_u^IU+B05>gtB+{{_`_{1dO_ z$a&6L&I46SuRu}}=eoE(2u5u-HfHkc^=>JQ&>D1i#02V6Nl#}!6j~>wgi=Lh5GwGy z*P$qwr*qQ*u zSomv_=JR~-fYv2peY{aLYMdbjZ|jea!DcnKV<3Fkf45dBbz$>(pt_=8CQC^oUtIrI z@Lx~pJEY&pXQO{jHHq&tH)I_12?r_9o_NJqKaf*lgDk|F#ntLg3wy-VtpBF%bHgVl z3;owRHWr&pW|Pzq0ULMM^D7KkBD!#fmMEHyeACzlFv_z|T<^GmVw!k-%Uf+;fP-Lj* zKh=7kq5Ks++2P!C)J`dOn{|+GuzAb}|Ddrr8k-Q-WFqv{9TC4%l{=H}MoEbw0tf)* zo`R4dUqxiIIK^20iVe{57U>JK#rL847u8xPrYZBm5h%%TqCnNRH|G?Sa~V2O6{d?q zqpH3}>8T1-P}v4PNFvx3a5|Fkk>hVu^7)z`Z3MClWktRRtSU~Jt$i#pX+-Z zaRuD0^U|&cfRk@b1uE*q!-fT)&vul>^WR&Ksp0P@EJoQ%@g=P2afel%xT|zJRCm>Kvkk z-N%3wZR~wUUjP6muoy4B{AFMoZlU>wc-SL4;LTeMJ`5X(yBfq zXXRk^*OIcg=j=bC)ckSQ24|G&48ee0}M8ZpMAd=w>9Y#Z9;DrJCI zcB_F%zgjvesCC^JF2{rqxL^Y6P#4i2OnF^zlCfrCwF;rH{sR#tRPZG@F}4Zfnk=fB zMxkxBq#p?NWO`{k0Rn=v@-xl0lTBnvN4=QI+^2A}k?%cJjv*1qG$X*@;%kMBeSyOp zcz+Xb72S}?@!%gt4wAhC7z+c#o>J|FwT;VWXATf4wsn6pM{4^>W<$B+dDAtdxQhF*iC{9Cbk9`snMt{ofplwo2|$c?Dto=K?{QFN#?F1L6as1YsrJyZo1e#W!66#O8$ap6B^wiwJRm?8mrLlM3N^ zqw;)7!#eK!2e)gO2p|uSH`H6nTd`yi$A>6ak&8`$1#Glfd?N;RP~d)z9WrDww5{31 z(IGk(l-^&d{}7t)D?zbRqVK0ppj)23^|P)=ShkxF!`xr{(_`0G&gNuJ=OrS0=FE&kxeeP!6NTS~ix*YYVlX|g62GHoIm7UN7l!5 zDd>hV7t?DLYzNfxN9LpX&a)j#0%oLRxMDv8{Lg(NeQXT+R|~0;4^!-v0C2*U(G?X2 zx)H0DraVqw5X9sj*tA+u+*cRsThYT+u?3GID|`W`N2W_24(orER%76HAK}!ghea)G zzMlgh;!RG@n|KmXZ|5TZ^OpO`130J)d~p0aPFi|)vHz#j;`5Ow%6ZmV$5qLpO72_8 z@slW+LuP;vKQclq&uz=ZQ4npp-DLt>l!2Or|l}qdc;EKtK6R`m~C3LyP26 z+!1uJaXgFig-6?F_+bs~qcVsqi!IQr5^)YxJS;@py`RyOjw`7&(C`G(o!not=&V0u z$G+Wk)_lYR@2(G|ZGwgkl8g3SY-qaF$T3rJ+xEVv7XCU(?jMGJ_{9o)v6Mk}SR|g| zh^+-PD@Ap|rRvP|$iaU0WO9Yzd_%#1EPf}dQFPdDR?b6F3L(lrsmIhz@iS(RgiNPv zDry&W==e)|Z^6sp!XmFj$#jq@BFbe&Dfxzj?9TPJbf*71!Fy8~zaLWbxpAS|(^zRX zd{=S^eTwZMz#ZSYhU{KCM_ga+;<$6o4Ef)je?l4pOGoEJHsFQL?ka4uKBd^D$R>>& zuT4jP5y)xW2J-CIDd(IRk=IQ&2?Pd6l6SLFwmBiY{FdpQd_R(xiAHmax7B{_HbdMV zfzkbIj-L{yGW(45^%!RNP5f3ho^TFQvGEEg8rDznv?9C=R>y)%R+YcMVuifY*z<-B z?#6hT+HI0sn@cf5j)$v8fICunYN*!cS&<3-?tiEjT@e0H_S;Q!M_uf})~x|5P%Kgx^vHCqMwH$EC0*IHyu`5?+TAnHf^r|BZNZs}UkwqP7)JLoSb)AS^qfYyf z`i}v_XjKK@7udiU^1s+KISNm|&6ks4mt~!^f-nT>@U-+lgLO`Je1EI{(!ajSIZBN1 zNBXsYpRW$kn&P^8EC|6Uu}6OEgg{M}Oq|uNwAR1TMT10|Pesz~+0tXgN=21x1;6fH zKJu04SbMvM3(I$%#wVt!CQ`69?sl*kpifkpgCy`v3R{!S4{c<^C3SchoARfmHPR|; z0UF-DXQ}RYsl9_mn!9uwRyBjTXB^40Z`|yzQ{~$k-#y=^l4$!z7AQ2~H3PWbG*n1O z#d7NEs@;#NeW3HS2vaO~XZ+zfSC;7|w1f)4q{RcVNwcsA!JMJkay;wHjR{r&NkF#0 zOQuY{!b(|ZmWzv16IZw)GxK4Jd+yTswfbAU{sGdo-NiInleOTNLD<@Vb!D}+by?)H zD0TO}I4juz&}0JAr=>{%t0VEGj%-pG;)yMj;#2jsh`F#wtYRE5y^`HWbuIqf3DhtbGV*lze)YQx`JST*|IAvK*e>2JC`Gel z_4`9^Wt<<}{w=#p2My8wR--3giS|0|Z;#Z=_>l3ixvPspmLpdFxyuEEG%1;LV4hN= za6-%uLI_wn;_cKnZHS8N!=vljOT$_bv8>t8LD?E5F3Z^bu9?mj9{OJhm{$|}cYE=& zVmV#j z@XQ!gm|NT1A>y1qB3R@+5hY?|v>&SwbyvtPEIgnzgkkfivnlJ$LuD3>Y9PoE`7~^? zj}A<=mc+Ou9HC6ByK1eEy1PPGId@eY$i6-_w*6#P6Xw!v zZL?`qtHNxHh;6SeE)|-@^IYpHlgi}wO#~_q88J*$tNu#f;k6Kq04}p`|NsC0|NsBf zt^V>i|9I)jeP8Rr^ql|ypoO7-|NDnRfB*Advu%3E5C4Pb5X^X`|NaOl_zivr2!_8DIjN363W5owWe<*pG2E;B?{BV}%%@A@@?b@)j7Id7pv9kI zcG2A)^ELg&AiMYq50buI=@hUz7WLw>%_ZGT=4paVwni?BFZZPIo6DMjJW1Udic^|u zR!U`jV>N7!(K(;u(=GKAIJ(M|*Jh~yHJS~YZ-x?E%uIkA1BSm4GbycN6wU6^KV2XP zAR6JNvV6&;7u`ON^mtyta4hhTAYKSg8i2e}$4wh~2#B4Xw$^Y}ao&W2q!lP>ycPe} zxK-hsM!Q!vDf#IvQcHbY_2%@o)6M4oeP;X*LW_fe08YVG!ksF~*l1tqZ>U7(w9lMC zq2T8PCYOfTi{Z?v8f^tL$QZ>F@-6eA+VAiP?ppuw_-$;6dMdK$(mh69#>*47Ui#MP z9l{f;nLYraj(=*on zq>n+JoVltyauf@X!qB@#c+G{+>kaewl&F%7H;zj(S}o15=l^lX2s$^$xRn(rcwj0% z6Y*T>2LrrIh*r@#%130hhny!fY`|$NSvc!7t(;dzenqAC0hu0URN$jq!V-eRWjyZiEk7FG4>$_!g22)@z0L7YF|f&dLw;5uWx+9t*~+&t z3L90Oj}6)}w>xz7pQlB=PQuAMx1Ts~zin=UCp+`G&SmmO&eBx{0-nT4OTuY<$& z)yWLJV^gh>8ywYr9MSp#t6G*Q5o84qL6xJ%K`nyD0ko`!SsiEzOOv~OG`5rE zfk?fz*(oBqH`H;sgOlS_m`%yJMEU??taeEO8$H1|sZ73vNCHF~akbC9*L>&1B*_(i zGU(dJ2kCYZcV^&M$yA5=rTLB1-B%_GCbz*b{8a!hQ^wC6W`+N>NC|xqB@1%2TnX1Q zK1fA8IjI$47^qj)*kzUcip84ct|n2C+4<9{k6?w%S>^(rM!3Z-xKX_D+!k=WsCKtTbFQp^>0nOUr6TRyS>5-@ z%s#xW5k>X1A0*V%HG2>S`uvaIb&x5lNou^-~uS&d*RHDDdm4mP46+ z91#r6_AW(AGg4VcP5pj$c{RVVaRRN?)JPdvOy!tp_#wm#V2C_X`%)r=`no838ldx{ zbWIV3yq22rn5hFkj+K*;CTT4n4uh}^<8-ezoS&MME6_1MIH1w3TT>*%p!ZS1Ked3e z=H2mB9g4;L`yQa+lVowjoA0_0GIR>TbLo%pSfxIY7)zeh>ZdWchphP9GvU2CF?7^z z?0>r)1JP$26`tWE-l5AXyexlM7CQ7d2lv)>Rm6u)ig(qDk{9HCrCq3Heyw;AVy=2j zh8xI{jdqSrKV`x$nKCz02Jh{}mq}(negX4n{3x)i1)nsuA~>rB*SpC|2r|Jo!UT)1V*1LzXr1VBz(oclD7f zfX~2l@!BIU@)hshXR`E)%Db4v>XPUiUh@Qv+_1nIX?_6k8&Dg2H+x4b57Pc@P`21s z=}}YpkMy)lf2J?rHEU)+`9@A=9w1daO*jC`m^l6V`RzIYWY-oWU4@tXrQD3e$$Ktg zaK6%X+aYciB`h(_y6p*wj#z43i31SMm@cikl)9a;{(@38BP!Y?=tSstt zOzYdj!<2jo2{mjsBy~17o5PfVJtjzODYKUZN4;YM9(lpc?dJ?Qdec@Jo0=y;nCYpMm2)}+E(LludtdwB|5#MQh{0Ez@67HB>Cz~m-131S)2JwB9 zVYnP zGK5(A7Cp=btHeqz`X5VT+AyWMgxn>ly|i?4uaH5S=nl=6+1WD7XO4~V$J5)O&asYF zpVt2lvwP!aCSv@hwI+`jC;I~}&M73AQg&C?Dgp1rP0PpG)s5$gS(w;BWPyEZOiON< z?(ZVBW$j?G=X2ec26sC`=qZ8*lbH9uOnw+l8+)p7EC$w#v}F#Q)YRGNOGeNNWFN`% z3smeh$@tIjDf-ifTe}2eFqMfjSOmCeee2}DA*%?OC)5H-rAWf}4?M%WJ@rig`D^}Z zAm9(+AH~B;um^~jStyXmjMU@*B>Tqm+wXqPpMj!BtW2!TFy=4?yqgG2A^*y4XUAGp zqo;qMXa)kE=>K@jGnE-}8OiV*p6CoJ63w=btDRC#sv&69&S~soSy73H%D;TrRz+XJ zQVB3lh?U4dTk|~2<_r%yy`@!?HuXZm^Rc&BxiWE4R<+(7IE0WcP; z{};_^*t(2nC`~V7%rmCiGkPLsYgewu@wnUxL@YDwPNPbW=;j(;L7e^kdm{){-;dr2 zAxWy4LCCcToRM2{(zXw)nw{$TaVtICD13!CtVqU9t$FcKenn4N+m$$)+9h9yv**3cnNc#^Cpw9rW zW9knyM-Bhb!^5WLj>enCQc9h>Vd{r#ddkv^WFhh8-o6K5q_0bRM-LK2UTMXaL>Ns@XHJJ$xx*CRwTEYNNQee*^CYOW zrn|a};%2G3oN~fnalwmOHRAPz5XhK^AM^XJI2>%ehntlF)Hlns8Flf3IQxbdKU?5+ z=LRn|6cZnnRbw1l`pCw2cU|Bj&)tb|8Wr0p)i(>m7g!xJM2(QG0Yw^*%rdA#pfGXU$-^pV+wxJ6(}&!>?8ZUwYXZm59$@k8nG8J~F}wIv*to zqBXTm|Mi`F3boGV$y1(*&gifLgnhPlBHRqvSSUr7o2{>TFcd37@r9HCmbNa(ts$Br zle5!FqVF0@mbcdo;9le_SIdXTN}yXm^#F+mxcdpiaNv&edg9+71AHx5hQ=L45E_)q z^B_)bq){A8tOq{sv@Nvk#j_G>{YV5-Q|KI-X_r~O}@r6nH zzDCMowQS_XjkSsy4+xoGv>T0h$t1Nev%#)Qeh0pD&f~C`<)SwHuU( zF^M4M>~1Epq8`e1NjaLRlsQ375?J)vyvpionQ;IvQOi_kIW-sZP=hWjU$-(=fA*pX zO7rpxLq^4&7fi>+%!4y`{+veg!S$!ungkF(!UMJ*?Z_M<(i0oScqZs=N7780ks#08 ziqZG>D~*iv;&eUD(U>FHIT88y(pFSY$XQ2Ru+JKN z>GrN{MstZ593#4G?nhI6%)UkPup8dUrY2kqc5cIambEl0TI7b*fl=vl zP2$wUP5;55%eBIl)XzQ-ao8;DskCU{ro4t{oyl^>vu{b$mmyTrrrKgOf|2xK=vO*C zUZKo#W*PAiDHi4WZv2o@UP&HJ#?2eP1qIze0cVIpvxeCF*!`l)xqknoTQ8g4aQpbI z5XtqQOH*w5YUVH9)+BFL%dg2R37Ar!QKA z`M7_OGP;(l44t1#Oc>0A8LKudx|$iNpMtZNjFH*8hbGNq#W3zd8fWc=mucq$4&HsL z9Gnw}OED-Ph@F9keR52)3n*Spve(F5YsVVfsBi(dDiN+m6WRp^*h=)p)yC8E@iZ*@ z=jd^ok`nWP&XUjA0dsds?fNUNO|$OJvn|*dq4{ovFZfZ@??{;rw-5}(+hsF#qvpR> zE7hdn4lJm^fc_?Eg_A#>+wc(dA7Wu^47oV>UD1rZ;{PCA0Zb$TuGYrGP$M|RLT_3p zr))uc@6X~AP2bYP5dt+xV%;73pvuWnI0j+{yv%I;!p}zK(K{*H1cAjDJn81_ao)Wj z)ILm)o{W_nD)!r&*3$eDIk!}O(t{KeaU(K6Q+mFEgn2 zb&tg5F+tU7M8q}0v(N&Oy-^p%Qn@bh&j~J^`+m9*DiR&1BIP6$sd}cgk8RRrd|ksV ze$Eb`g>aYFI#ch%=Xk&r_YQ=C9fmdgCa2hI|1f` zu{%zo3l4u*r9mHsdE{Yyr(IhomDei`RRDx^!h)+kh|&a^__5K^=A*DpFkXcD&8^nC zU`2D4HYhl}7!I#URxPwIc;xZ73+6TKuE#%%PuV}*%(DWQ@F}0oJhW$4$Z&~k~mb z*HPz0ZF%h*9J0}_UIZ;i;Ir*~(OsK^Qgt_Ay7=2I%-eLWW-=*Y6R_uKYd9GX4FHOD zoZuZn%V=f=08hh?6E(6ke#9;-2{I_MVu}3ThU`QXPUO@_Z(L}CF%0&~Si;OsB62VH z!e3xKxJJJ*#3vcS@lzW)FqQr0q;<0h2V5NZIqeD^N4=Te6x&P)1*`)ujT^M-ZM!bxRV%nc)esn$S0%q?!Q087=`aX`;)PYIG}BJZ(UIckNAonF4GX z23~_7vVQnk61;8L++#}1)^L(Uhy(iPM06=B%gj<6H3Fsvd$)O-@Rc6oPzB)8%ed4Xn(F z^Sfl^XlA@yL1~pzY0<}E`%%re9897KN5fr=ev_NllfR{urzJ7_6gE|a{JkhC{mSl-X`15Of>BN=9TL@~U= zT!wU+ZNkb7J~eWi=lJodR^p;*nby_}6MNwYgtHAc5U0J2W=bv&q$RShn7t7VE4io# zx2;bgR{0B9dgl`LP=v#H2Q1SS996C4vgVn0HT@#awu=H2jeTZzXM=x5 z=E0MY@wxEt&}Z0{Ki3k83>NyC60E@&c5ha)l|1jug`Goj;3KnAM-=ZVbfp^z(2j@q7Z)t(1={;7^FCHvP1}j zHu20J-a7XAI9=gT>^#7KKYa8bs*&DW!!F`i?1!Q^uK1ATAsXuCPB7)& z>7b!2B=wOMQ$u?^Q`fNaCi_PKYle3%+<8Y^df9Wn7PoLElw(-S?3onz5!H3Zn6Z0` z#V;>@SDSVQSwd3tdaGMd7ocO{*uCLFYZ|N%L8DG8Hn9pt z8zm_D)Q^*@!r@o7oFWx-|Hbo76D|QB0fH_G_PeU=!~C3!Z!^*?iG$`e(b}Yo=RewYB7`-JOt6RIE~NF6 zrGZ#(bF;W{I0DFpD3e|0ZwP<09T$9`m|!pmlbh^6(jG~P`}H0SIIT|Yxx@Y>>cqP) zpVXy4#^cOD(5%9ZD^wd1zqR!V4XO)?!a&8VQ7(V1Gi-YWHhI(*VKn7jQR&xj#)KEZ z4H0k|fSB1(xFOF_w%#G<`x0`~hoq*!nX2zk8vHEkK%7PGVEh4N0DlR-$VX^!gO)Pi zFz^BHpR#E8;dH4OHWd&dRvxEdRv~b(+QFZRndlzTsilW?BJ5EMQ=_P`+`9A3nvlf1 zk$);H9417*zEax|inlLh=+nqaH(fJ!|G2Jo%8MAV zL-8?mz4Xcj^&kz$;e$C{5KvL{CAZ}Z&e0BSx;RW-8!j{3rFzj1QRlEEK`4rNQco44SL@f&lTe{S0-Y_kla2%wfmva)v23*3Tk)#p%LG zFN~W<$qY3|IwyDM$0@AQN5dykzflb>!VLdZQDaMFyVWR#l9UvHoOEMU?4y>#fCuim z3M1qoJ5(gO6)=KXT)kjMqo7Lzu&OB&uH_$5HKG zQn%ia3%`Hcj8xPwkO9Cn))TeBX951P0iq7nwi+ec#~oX<@CWP%K8EJYXW&HF2%(xf z>M)$!%}dWqXx5=VcRJuQSelt&=~Leklav78WxhTY56QUMkb{~@S36DU$`j6N&1~>=?#-`>%6sAhc-bOV)0zOn<;0@6e2nA_EgJ9J9W`nX%&~Oic zYdj8d`=Batz9~gdfDzbn)CK?mRc>Gk!|bKpr1^P`P<^w;$zJdd(2~EQ8Ut&jk1Sng zY77iC>-WYZj;al@kwV~JnRpRkm4X~E*9-M@YE}kt<%+k=Z!D%#i(vDEpR0zQRy(XV}hwk4go(jenc$fOkCiv zu7)g?qAZDD?D$7bv$hyIoELaTmd&sv$|tQn zii`5*Pr}U#qOT{mCl8m+a*#fB($~8v4dEbuDUjFX86rg)Wv~)XpGeBHhB|ktbzO|u zz2KcNI;C(>`aTw>3@SLRjVh*4YqgrkBaTetumAvOPcmpV6?{5*t{AUH^{L_|s=0)r z_}G1EB(L+ao9aZK!qjT$^hBV)$ErQ)_h-%dsi9dBTfG(W5_^W*;3j&96})Rk{7)ZZ zx`PU*f^ck$L1!6;mb8^&$F5TTFEcnH&T<-j)tN&UAbfDqJ5{F)NB|I#)Y!yZqD;=V z!PfPG$Wxt(A0xnu_l)*NiRh9T@HK|0m~{7)foi;$ail#p3OC87a12x2si|4rf8U=1LQngJb@T2 z1jj-gJ`td#M|Dq;6()f7Cw#c8>Zla2J4+ehW<`zZeUb}ic3V+9%?Y;(r;4 zj2Ex2SI81GWz!Pqh~F{EL78VeHqAURUBCbU0{{S{s!S4bEWC8s?J({O8@$SzV&yN` zGO_7J)}p;x>D0)SCo~g}B7QN{Et#CSAjn=PDy+cz483RF*&dnL0AyITH*ehIi{P?2 z?F;{#7ioUu`Nsp*&;b)d0sTZ3`iQwU2+I4Xg@3y?B~kwUX$(Dd`WB)%uIjn<4>9EO zjSw^WigZe z#bM%D8d$;q_l9QM1TRmj!m|fId4l;;yr!^NtkPge+Fbrw;>510Qt#G4Gv99h%djj* zaGzA-@PTJ9YuIPs?}6xkm0N>9Wxe-lHlBuhIBNA_LUFrPI88s!KGO+!u3>d7#ic~{ zx>s%hd?vKuXIFSt;Z|Mr-oXJRo}vDc9>uMZ!W--)~rOA7*+#%`(v zXUDHNS-Uk2g zK7I{SesJIo6f7(OC6~cseX(bIk>{N=&Uj{)`1S@ubT?%1bETd-26jDv0s3fNzi?RuweTkk9&K~NUwkr5}1}|(ZRVu>D#)a zf?9xOcZCY`tQeE395h$1+qKag7$c(ZROBP$VPH}&VKnsvSmT*v$o;J0s^AK3Le znCotYB!MLi({s-q*joB0a8ZC_(bOpq+D*Bl1F;b8*jDf>hqSJ}4JB|d*S>Mg0mkmH$#uLDtiv2TqVha#$p zu6sOfCEMC+-UyEKSO5S%>>=;GLjQloX$@#mcMlX=m7@YxnR`h%D9lT#@q3%1AOQ~x z_=_|s7EOU7b^i!}8NOBnVgRJLlM(<$P;TL^7=|e1ycU@>4wZ)Wz&1ar2&7=X7v+Q2ky_Qp)AFzG@0!Ut!iab`*kQ|HFTjH!0H$%XO4%y}Ax=Hp? zJ0v$NH|hH_M@M=v)*u2`9P-;@6m^*sZ@O0yWlPAQS8&(t{$7Q=_{@onfx&1S+wr~t;vawHnSKwrz)d(7iO zOKVaJ4~3{t7;>!PDF*Tq5d;{{s3q!pu3qYD(XeMB#glSM>}a{k?#0s{G}rBgq2die z`T`d6wnM*5X+<5h)wpNVIjie&HUw7>lJ|R zOGe7VCLaOUv{u-o@7FQwD6p^FW^(5xc2k4oZ5+2RQ`atY&hdCHou4#xFcy{yu z;hHiUWTIDJd;;$YG(T#m{IocwJ%72(HHYQgXfw`h6vQA+vv;c9Ts*Uzvlrz{b zT>rOsaQ$eSAM%s(Oie_e!Sr=#$Idb3K!p=p5S zYxCdGV(FNr_E9=@XCfY2Gi^i&L8A1aTR0NI+JjsMTy((L_pK?-_`g=)#P@XgvsJk| zXRaS~83j?u9L9ak5{IX!aAVlowE(^a`@_jA7QvZoReg7?(WJD`!6Wc?5KV-$=V>YmS9iWb*$5INSM{)Ogw zd^0KI>!0UZ-nFM8>-UM0tO)^pd7SeF3y4Tso?4UkBqFd=2uvGOKp_pmipxA-Eq^e= zQMpmT<|8}4oU1oYu4e{_7(&r5z3Ry+$$@WhrLgcTJQi5h?rHT&2ZX6g39CHG&mFaA zEvzXzl*b5@3Y+}Ly2~oPPnW_or`x_gg~a%RqN*oi3n|+9tu`{}P7BR$ABE@uCT3v& z1ea+O@KOB`h#A)H{~s-YJz14-5qz4#Zv^6zSrC$5u<3NPEtn>>qgRHBm)PCgQu&PY^QMc79mJ?{$m;%7=}O@jJJTx~yV?@bH;fbb z7$aUl1{lZ#xJvIFD~a;ucw~u|0^>k8$MT*G8PifoW2dZ+PJ;leOTh+H0K8?}>)t5f zg-Iz+q)~8L?|9lc){+#)eWsEYzqm31DSK{H-98h|nsAcE=V6Gc?ueW(T891FfKUi} z8Le_%A?17FPI^B6H@Qv+4;^@}YoHANWiONOaozr=8N_quGSKibmWRk1>nZN#AP@fy z*G(*M<;Eh19OTv#KoM}P{2sdfFBt()st^~yNwI1%yb~7UCa)-*X48G9H#uQmqQSmR z6o88@VvB%=|1t985vrlVm@&Bc*m~eh6{<=vd#Plx%;-(yoniQNmNYjF>L%SiMGz;D ztl*um2vus@8}2ff1+PdS$=zTzJqBA)5mnxJQoT&|hyXTHQU zDgfuY)^)&Z%v^KWwHHkD-m(AB#D`U9=PmfF?iB!+Zt$|mRUQsUWzZ^6W%yaIqaQYXlz5Mt73TR1i=F*OA35>W%<8Sr?8GK?yh{U zy{hd=rQqEfJGfOaWjrzyV55~X7rBwD2DBywHvc1Lm#z<12im6SYHoFv9xI(2Oc_m&ROr8ZyUT0V;v11M?Rb6DtK70{-p7!5JUL2<-?#YNox| zsTP}w4`PT(dG80T6DCmO2wK-^2SaM!SYJ_4mC{#O|3YMj&ip(n3FdP+E%JYBB{tA|@-zPj1C#benti zFirMF{cDIvFx?1wi(UTuMK81wul>f@%dj*qErg1rH{G83apNQ3IUy0aQ~`Ra<9Doj z23-?k%T%L?SpQ@c5fq5mwjktRsHmhaUvKE4s`YV3DQ+r?FE!L=(1Kt^EbiJ4b-0r( z6r~`tEi0>ah)$0V>-@vGWlQfFuoKGfpLZ@hywgt7nO{p(IZ?)vEM!}1|AR=4gx&gD z7Ic0Lts4NVj{<2)ayVQ$?W^zN1 zQti3TdRF*@D7QA_(b7%(#?*GAilFlf*;JF~$eFeH_o6Ms19y%SlbXH=FMGDYc3!59 zXvW33R|AK?{z&4Ac{?VC-d81!n4QJ~8T5m^v0FS6gByKhu;+CjTOT!`U~0kX1?z%a$|u< z)#ap@X`BHz4qxQn3D}R8V^rP4&>z3OtCC>y>SwZs+qK1XZ&9T5AeRbt4Va_UvZ=Xb z{CZK(Q;>$7GnyIifOZRe)V_wj;(@8@ZjkZ{D*n!=`_fq8`Iy`_)Ca%thQj+`i2IASz@xSCD-0hTb2^& zez3YP<$x?sDFr2@B}9u}!zaejg(`IAxn>d66%DZ24D}oy6RO$qG}0q~s*`i|>R}-J zEjS&Qe`v>}vZm*7+E_b)mKWSC_v5+n@CfRy0Pb{{CO?WQP$KY>`JL(u0Yu7 z?4waj(ujOtK-KARjZ*v5{%r0!+h3h{ml50Z91XoIE}*s-!B}ZORY@JuK9l4O?pKO8 zpDo6+FBAPht3PJt44WckO(CSg=f5*0ao-!-hWx4FMG5odBf%Ua${a}f?$_SuTdF;B ziQNI&g*`{Yrg_VFr$FEI@PUgmr`jukpVqZI?DT+km21sS2A2mjA--2dvk&&I*lxqT z{k@O6R0y0hNpRJx0gG1QX)sn=Grl7eGIIKfYUai}TUh#3YpwCLmM_{=l$h z6&4~!P=RivD;6k!_cjxZ@Ri^Xrb-34P*v6mQkRA=qIx3nJ`4os7yfKn5GJ;17qA*w zh6>Ep!j3yy_1J?>7)VtPQ2kNRY>6#saE}Bz&x0(g`p|E~V&)s<6`OnBNs;a7VjGA; z2e%`qZ-b}@u4kQ)qH;nAPwUM`r;O%;TW@&Akcv0}_lNE0ciaffcNMtEUrdzhoqGh9 z=t$BKtu3Vwxr#KdKR7Mw)lZ@l`|sTSyj?|1Fq%#G@E{Vfc&-=DFxDY>js#7lpoT2w zz9oHtZm`eN0F>5o+yhOREwhy9LjcSW66m5zSV=}Tl3ofQmTTVRL_Oy}Q4 zTtBR6|D z!w@)LfM1FOIKGLNy=(60ZSOk7K0sgbUIdiGr*PE63j$g{#GFRnorbHiBgLzm6-z5w z;t7paI$v#fnO=)%GU{`JWK8eK5_EJ(hhN)4kW9QvCqO4{whdfL)~4Cz&X^@{n6bxVRJwP2g6j==!8n^I|xSH-T*kBn`Wcv9)O5;@h*{X z!kbZYnLKPu_>(?v^tybc_aGSa8bXaephKP&EAubqVX-&~tH2ojI_;@RaZNCDrFmi^ z#j1zsMr8QulnsM-_uh{Xt->uxCC@V$dARKiQw3m_%uWaYC(``Bmx-p*U(V9vDsnsDK9* zNu*I${lp$T|L7}S9lEN$$|2|XjsxK#%KklR34cl&UnLi)etJ<;4m>Dv(A~GP+9e}N zg`!!B>%{{FH4JLsFwd7?0*TwVq(LYR_utt*#{J>@u>P?M-i7zG1{%uDX2>KgO zOAVR`(pfqlJlg6jz`}vFa>Js@(XoORc=ZbBNoRi5)XRmVgc20I?*OVnxE5p_ohczd z1)R65I-Fgo3e%i^rsj4SGh@ncOEKBj*Pd2cm)2bib12eU&cL;KYEec5``zRr!_2SJ zmNqL*oG(_`qIo*y*71f!vZf5+!6?}rOfvWUm(6#JgWwZtu;?C{#L`&9u3**h)`>!w zs5El6(79oZ++uC)vpISk&xVyIF1|*ToZ+t^Lr|Q}`|BxrW8Mw}0{!QIxNbJS=C<scLqm^*t{kM52m>p`jIYdsi`H6iFfV^W3CqR1G)r9Ra~IOsel3L4vCK2oO4rB82F zcYoxU=ec|n7vieoSzS}OeF>a3>j*sXh3w&;Tt(4<#FRv?48cKBuUR}m1sZpjmwA9> zj{MRzh-8ZiQ-zbAuAm&i9@)U7^PLOAqX(hvNyUX8e7HK&|3PuTBN~C^g&2(4VzFOM zdWtk$5J~7!CIPrg7!*|DPaUhcz;?QRS&ixa1MBDm4Hn}5)q}mi1?Hp=MOnY+OCTjM zG8C)~jXYh*`vm~*VMbxRbs z(W7W;@DcM@e^LiW`z*Avksv$r-pHbTahV&IkaWF;zO z`h~8AO;C|ct{(hLbQ%&~Q_0_2_RjuGc-)V|NON)@e}v4`XUR9Eo8XyBYG?`rZ#vJD z-;~^FrJ6BoI=cCsYu7UYU;AUO+(c08fbNl`f_EL#a*zWh%65oEMX^j5)pOn_HKy=~ z-8t{OzZy4~we18nP(SV2FrotrW)H%lb;XZ6NT3DZW@Bl){W3}}h(BgT@>4JHw=FNn3%j!(#hA5#IjRjw=WhTQWOH#3PD0e)dgTL3|O$ zcu9Wn$K}ZUStCuHx!ou$g>Yk!mR@i3Ow@pc1FboYgv(cjng2XelW4SW>i6m~fyn<^ zqnFFUoE4o(>qszoiINv336Ks!#wU?Fqra=w`%Ph;*k;bO-|V3Lz_XX-qh6Zdg``tG zv4$QtLPYN-CS4sbOAD90?yeUE`yBg2Y3{FE9LvhNAzsoU?{8A{ZFJ6M&+Azo9iJC_ ztg!#*7@44AkLRBppr3{9_dU&mwFK|On=vg>tWA7qdcJV0rK+T>C@>2#$^9TWE5Tod zy_*Gr%GJ0KRKw?xEIf}cuK5|f54{Nuu0MvY!}pXod}Wr3j5ajE;jv;{-YR-W=G@0Q zIFdHbXuoO)$bT^}$M$M9I*hOsXdpTir&`8Z6z)z2!WkkqY|{;dRkAGx1j@6Ns`7|zSIkC2AXl=BJy21B(JL?eESQL#af$bL}DHE ze)JuwSWZO_+}bz4#BY9cc3Qes9$YRy>1E4W1eMg##U|1EDN9#e!xHqR6w~`^WA?O< zbSi|AH(b0T1&EsLI+N;$>0%?p;D01dcD#A84f2TT|NnLoyymT7E8gB-XOC+O3ssN* z|BL_p?gUixSjxrGfUgnUr~h0DettVQyD@pz*|NLjr~m(Wa4Bt05TtXaimCm>{F-f> z{2N)*CiZc#jNZ2SoohrRfW5;f%HQ1u;V0G~-pLg6-MK8i)&5Z_ZhWt#gLO-kK&n`D zWAER*E~ejVDJ9gGj0h@0_(8*glvqkpg=E3OY^qTw4|M);-OcqRrWwqmFnn_Ne~k{Z zlIkttb!%Y^XN+NiaQ+iBG$F~%0H#(2rsDjs#{#->JV>Drr|K(vc-bUE(W3qL9m$2$r zE+`jt_md$fPrP>OtUPQ;4(5L@u@9ugqZO)8u%>a9j zh5uO;`(A+2nc6oCpXJ-|&Gq>8>oo{-64*4c;E1sRnfak=2gfTI(0acOLdX1qYN~PC zVK-fU#Bt;U?(#_K6bdF9*+QOeMJT(K$&|MfdSU{TX~9Q zf(|p(t6j=2_Ya4IxVSJ`HNR-&sMjVy9S8;XKY%y+APK_JI3SR4)m$jJJx`HOlG?%1 zUXB|iF{ir1{4;NGY{Kq@c6u)0V<0Jcv6ZC_ZhzymFi;*Mz&k_Sl)|9&SRxJ9CAD_= zBI-?DPsbj1O|$^=`dZ2y@do^?U=CU4)D%?3qZAq#5o)*8=*xuXym>iR6;#YoH+A)N zR`GYL-z$@Vs`6qo79SS$z1hBcUeh(c!wls*SWyABYTlZIgkBy$QY7QBvLq`eIvmDt z@4%`vzT?qJBXVajO3V}{V2w2^_Z5)SP*YK-bIkw${*vRlgSNei7PIw^WHm|N`55h9 z?Nvv+-UP8%MJ~%(0c>%&U3q4OBSv#iWH)i&GjWdBP%U`_sX_uF1(O^_i(FUw-klDP zd{~yZ2gl(@p(eaF7{z^5<(ZBh;E5S%pd;4s^XyGjZUYA1lYG`GJvW_0#GXhAB4!hs zi}dNA1jtb1GA5J}Y{>1Nzx+`z@d-xZSg`>7JKXS^?qIA^@x0R^Nx?vioVD!) zyC=bls;dELIhxi(g z|6xKVSo?oR#z=TU-*FU|OBFTPd3TfEf)M1IqigKC|4(k8O$t4X1~L{gGIJG(9_H2| zDSX?BS3An}59bvhOwdhwNdn^ebYg}fqUN;p09Q_c+UAFupW`ztov8@;?JKIO=(D?5 z_e8dTCi&J zSLv00(K~ar>nkn4Zt{A2bCMynQ9XuNvVxtI*`}D64@OE(*BBw*CmF-wPOyfBC2qHX z^P+R^YmwH7vaUSr$Bzs zfEVy2p3ZiP1q&wR8!D?Z)+#0@-KdM2Z>;BxXt{v!QDA*}88^WyLY!+VKT!F?5RSb| zz*&}lsZQ+iFNY3!WReat+7G*>yI4x2b-AS7(g>S2dO5yS&IvjwwG*^CBE?i(yykU7ln)obmDE5NKV+%J{yR`4sD*pxHjSE4z$u!VMprM?4<{d?aYGq=- zEB+~P1b|#W5`3ZT_sTYcrl`U2VUiu{-JJTvst-A6wV`yJPA6Ttx$SmHgr5Tln5K_$ zx>3+=2Q|?lJLalX59!EU@pSF`{i#31i0$oKiam__!F8>pkH+<|8|;c%AmSg>XG@)x z#!lokh`uNrh@f&0tc84NSb65|&e7zYb+Y6F!4#g^<5~w(TXlOjPuAvC?qHae{(UEN z^l&|mmR@^ngLO`Z^H2(_nITOB2FwS|!OCp{fBY*LusUzC#YL4LGP}> z1C6yCMJ-JAhki`!qXR}06-6C{3Xtzjv$?r|!lNoSn6k5fv1SL{mlIYYb9ym`x)@2Q z6V6oBw5b`f`h7!89C0z^h!Xe;jYzUSAB5vjg)Y>fK%C%_kzqvR0ILJGByhN$&&T$M zN_L^IMnn1f%c=6|G@Lo|7WfQ{9hq0*FQ@y~I5kiOUDA%6TaMu3A)Xx%EkKW=NO8o{ zAOd?-u9na5$+{Zhyz>#*?CVAad71}Zg3@G-`^(T5q5qUEFKes1RJ47RO6IBN5#f7q zFLO#Wz1U4G{x2qL+0rnbtQs3gff8<)ic`LB_@+dtka)<(J`{)Ta&RN~#FM!)G$k8J z)WajwoCj!hdfIICT*CuuDM-u39P-`rrQSVfs;LT8=?ak06SQUZkJ`^ z)8C7Dm`dh$sj2BCG$F$hDLDm(H(0zWDQ5n7e=dapEX=T}5zKTx6n;go5$_E|arFPl z-WU9gPx2CoM}s+2MWgbQVeJEwV9N^yzJ;7uyn}&4TvSqDqqw6q{-=T1hQmiS9DOn) z%DlTsBc^xkYQoAE)cohFmdrKbUi*$S{PXy(7JLHWA&9ZBsklwcOtfNdwL1m&V%})n zAJ3a87DTuh<(jzV&r7#JPEZ8c#baNh#w?UD94gm3fvu~@sVtW+6axRL)@}dZxBs-J zMrTp|@F1dirc`3iyTevr=LvijT)Yro{uhMw%(%QWgv}h^t5N~9^&UJBspb7BVGrb% zJGV>%6u4WXp8U09=bD?mcd?T3p9uhdztxs8Bsi*76MT_#Zr@lA2UDMPepcxIhU$h+ zp4TZb7YH3*3hS${3^?X@9CjHsI82}hYC1I#I0|NyjN|a;#`dB}CAk_HI}#1bZ`FY! zk&X4lwjE2L*(NTdiJ`X)?K~e8W|Pi`pXnr+0Oz??paIHVNWb36OyL0Fq(q3jgfXJsU@fZrG;R-q$b zWj5w7kB%E8h9uXS#S(ww{K75G5jbYO5|0j}c#7pmZAEr(&4CIiJE*M2LKGlRNI?8{ z{tzU5`p)q5gtdw0_)ua}?d?_}*k=Bjtj=q6C>s{`JYKz;bLmrc@K@pP@qmw~PUc_p zDkbmoysu_G06q2_V86fX=)3#2zkIkA{=dI>o8`X0UKswrHbbjVE>1s(vgUUtWxWqB zl2>m(U3U^oE`0Q$K%Ew$Z)mYarx$Kc8FwR${x&^-pbh}h<(G&A2VdJ81xj>X^IGbU zcBVrIG4_|CRxzc9milHoq-i;(3wT`*b<2E}&A2%b6pP%wDj#E|Oin_o0T=gy4V`*d z^KY^&RX=hx7@k7nKB`f+;-!povhr3F>3bYBA}|-p{13}7vK4m#zL8@*^bDm+QB19` z5OrpNG5;)*qPS>rgu5jj3#LWU{fnHu_a-#^l2DmUGzX4Y(W@+AE89aEBU;@-6c{iM zOEp{yb>BN_qVe-Wq+#{a-i$c%siUs{K5S(bQqu4aI`3-Kw=9=z~ZPUW|t1_u%SDC?^I zUFiqDmz0YiW8lM8m2$DmU<_xK(v$X$S~;uunw&V)7<%e)Ulzb*%^;SD&xJZZX50yJ z!1C&TCqwloDBhI3vs`R7BGm{4kizLY!y=BiJt+1vzr+PL^Ad3=%U*#?3_Um-{-Z2? zO6#m=XCVKLfmOR(0a1I8CdSlJU~DaeVs;p`MKR3xjVLZlF>&6BfZpM2bb31 zj@pd+y85w`o}|ic-I^$^GAtV!J{YJeSTO;-h?+xXEWDr4x9X?CmBl8MMlXE#cR0K? zem-LMbwb|PI&u5nIdKi^?sp@4Tg3e#zOO?S9DwSedq3S#9-N!9qF{O%NiFp}7SO@{ z_Oi*X5B)PD2EeQ*WAlBSaeoI~41RcuYdLJo^Ee41qi2hcjn=s69S zrPyIPUGY^JEp}ONC|#=mc(f)lDS~P%C^di{yz?y&+^=5)sqiPW=zm`Mq3&vfLg#~4 zoB#@^%KyoC$9W>n-qn=Gu~UJ^qeCU@`RqYucC9humRIR&JtHJSRsMr&ekDb9ahc`+ z8jsRG>i}tqR(*ot7gXEJ$EzC#Czde?v+UkO5(&J?M(+D2c}kFIeaD|yj)t|9o|xO( z3;ab`vMkCmlz2A;%H^p<f?G0UiUo+2UQ1G)5v=PE1Hi!|syB{IonV%ArcziK^u3^v;QuPeZgHF@+E zV}Cwi?hBXF{H~gzB&g_7xXq}ZTUc&4=Jh6aN$OofQRJzT{uvI$l=RfL=(eTmLMmUt z#;?FKfI)Wj+!`zn;iAK28tL8u^?m7-hi0L=IuvxkiEOslyG?BeiW_aHQHyBVo8uv) zIF)7P`ukmzFrg4=L>!&5aUSY53dN)QOL)=Hp~v*?>~lI6|sOI@pniW4M^GeqDWUbGH4q%qIIp*oRS)L zHqZz`4#2rMC62tUxTNTDs7eC54c0<|DM-R+X)4-*fXnt$lCBGq*edqvAC=kVQ(t z=N*85AG#gCPlrEpGv7DQMsL2@Vk&6*-y1Q|?WO-7ujika=mke~+;p{v-7K!HNY7jp z`>D)uhMKUR=N#KF)a)~!4^&T-w`BsmRroM0$iR}HcgF>Y59}#MnhTQM&iS;dJyi}h zm!;rQZ8Mm^SH%UZJJa^_ONXs)VMqSYU0lcgT@`CaBj_>x}OJ z`tl&?qVTmub!yX$32gGqW-A9pU!TW~eM)DX`9_r-py@Apvbaku!OA0%J{zMl3#Y3{ z-R==52W;x$1wDx>)mm7&B4`0J5eJI1R{Ky?9*o{MT66`mYs1~i@a{FmY-&&VV2}wB zmy06BgUS0QU;WTIuZ)()V(UV@CVW(n>%X4V8ig+14{8E`8_Bxx@NBlIDdTfz!A<+))n z0tuuf`*6|*$Liqey11hcf3Qm+2zwy4*n8(hNKQv)$$cazt*HGe7&nfMi{`+WovAva zFWhx)+n$$CHdec@YUF$a8>e^5cRdhY;nU<;n+?06Iosl12|Mi<%k=%QZth0fhuo=w zK%w`NtE!dJBzWFeap{fxpCbpoh>ql}`rVu_^MC(L;1+>~^=_1F4$pyJCFt@W+~dG$ z*6~dj-M^_Dm=Aj8Xq0Ltsi&?{*TA6mD5vX`JD9O>ti5bL-slmu)^tWr0iEBxU^g;y zQnoO>Jjyzz0tWbT<~zzArYQfSv9MrGWC}eGyM=oSG;pHo!XL=IVwD9_I~P5t?wYO> zzisnw&TJGh)sgJjy(?*|*4qpLg$w6%9rz?p=;t)({td9VXKgtey(k_c=uFAWPkeNT zwE>kmnQq4i_BOFid!c=;bR2z3vw14M_;8g6BQByeKGJ{*jg$#8;ofMpwqI~(R*g-- z_&`IZJ-04hf%&4%z#HZ$z8hFIuJo_Q7xdfs*!t#8#6X?~L`;g@?=)PsJ#&7yxEXfx z)rOvY^~aZ0OSnP$H}yB6@!fq#d8GfABz|T(;U8rfcf^53kfP_UQ!A#8SE6>E_J7Rd z=kOd`IX2(>?&q?QloAEbl7*8?(mx#RfC5{M`FS3w{hljh29&s`*y4l|DX5-B>8D_N z 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%0DpKO9?vxyzG&v5mKeDV~a;EBon- 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� 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 lnMw=b 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 z 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

  • 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
    w#KR8big7umw;LCqy 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 QI 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 z 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%0D9W);70W=)UQLmIMEK-IU%YyK@a?QrD! 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 z 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 f%%e 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%0D^+thq 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

    H8@{6kVU(difX_NICik2#(UGbI*XJCl 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⪚pV9R{~Cm$kcwD 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

    LsjDjPp+3+U)%df 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�T@e|i>z&CzIJ znRx`jidy;UnT)L{709933+8D1^Q`3Yas$W7|Crn#-_F0OB%M>A)uULgR41=frJ z00RO(;G5}u{MLm?(%F$y!oAnd(MP9zqA2i_$4@tsx03bjn=Am`0$)lpEro+V0QnCP z0$Ai3pXF#o;pQ+8c=i0Iz7BKo5$Qca*%oR+l$T@L9A|6^00093KG$D;RLcNcGp6^X zkpF?4jWN~;G3FZ6dYGPVkN&3w54DWmz1f1PU%TU(5GtHsTR8o)7*dNgm$W4 z$21dHUf#V#fv^U_Z!-UTO@IIY(cIKEWB&6oJHOA_vsYMID3AZ;W<$NAbBx#j{3dII z#r~>~4&{jFW%~MiXf%g6u#y3HZu z3`0Nt@c<*r?tv-V^-2(MBBccnarZ4hndHlW%>TasJo$g7Z-01z2qg+G(ePu(JN%>S zXq$w7i$cyKPax(=gC}AG#Dq2nKrz-~fC57*{LH(F$)+=6CGHCw#Y#^MZhLc_(c-u zIO?ASayr(I|GHvF5HLA>5*sr@kI}HSGroL+W+U7~Zb?`CWzjmy0eWc!(zY_d5@)v=h;(N z?Pt{ZLRI#U>&?W*q^w4@Ta9i1#%BlRg1S9JWvVA5$iH7~jAqnWl>k>jlYxnf+Scf? zF(blp>{PoxM9^ypNyCz$dSb|Mim#?8!%x3`VGeO$RP*`fFE)!oLVEKD74N70EB522 zl8-(mm0KJ1RbH-YX*0Un$c$^j1AyJ!H?{Ty(JVmuSZ3Ys&`TInip!2wb$3qpIBhv5V4r$8sy z3;_pSQ-c+y@Yy4GS~pKVLxlj^&8Gn_EzJ6qXUY6GR&(UJx3q09PxPtr*HeLC>DDkc z1R#o@4ewJAQIsiKMl$g_h*EJm;o+;pkpnfQJ7XjN-)0_n52Ja@sc2cwGxDO6h@#zl zm&oE0Rkw`UN>y&uh9UX|8<%V-a&tJvyQ`l?cmg8HrLlnEcp3xJPhJ0Gb3-%n?otC7 zSnH=#QHE+Rfv2xks-n9+-${ugO zU9R84xwe_-ZzksD*m z(m+QS2)>rTp=a4GlfO`vBKtdxPEW5;_!*n(e!5TZV}M^D7%W$mUEKo&h@NUWB2d28 z6HQq^+CZ%_h|zs(yMeNNUUDPbEN_(Vcyuqt4MX66T>AG5gsyUO>pC4^vO9PTZR2t1 za0154& zv~%~Xk)}yY(wfHv3hB`=w`Oo~2&|G9{_dpS(#9NrGJ7+nF6C7P(T^sBj5N^X684G0 zp=JM;HGsx;^X-{80hRcSS_Qrdq-JI*%T$Y^^`)}{Sulq>eBH(wE|DYSWQvF2IRS#5V zu={#uooThD99;$b&1)$Y4iE^Hw2fDceTc4M#n?5XvXNJ2j?k>X_^s&~#8spC3|n1c zAL@-wXN9{Sb@EFTb68;gwh87vPEK}YWg@tY%@`*t3WTP z7YVG>>}?qz79B!fqp=Pu_Bz1Y^sU>7RXpvT18b~Y@yn?CR$VgQw$~d6ZIYS|#qvNd zm?(_1aqFHj#_4N|3kxri{tl`HBBkXfiU@$(Hsbxi7QqTMnEHZybE7`Dl`6#Eq(zQy zySDiJ1E%nDhxfN~tq+B?s(;Nj`e4#nq8p1H&Y_0e>-x7Sas#Wh5kq%Y=oi-Yg9`f< z=0)ii2+n;v*-aA(VZ;QOMT=z=fT8>_?j=w$Pr%Ns8E%=!Pzw>tX_Cwt*M$_m@44O- zM)ih1q(9_nc}jgKEF{2~AS07s*pB0r*xb%#n(}wwi&uNItCE5I76MjQ}fUXus35 z;SO4yj{@=MK{E%>r!V7j4-69zD+W(ape|UAmCMiSzL)=K-NgRW@9)%duUp$n*Z<}8 zqwW9xx34_c=I`|0Xpjp|5B^=%a>O|2We5o=%_U3@sGSahUzGg#63BLb1uH6kw?RfQ}LQwk8D#+y}tH8uEMk z1@WdH(B_b9p6(8=&^5!45NEwbKtS z0{bm9G5fn_%?vQMocs7Hj=TaN91{&Ln_n<9V!@A~O(Sv`vg<^{UoLToD^mgw8kONa zlFOH?bb8HeHoQ!mJhK70?(C<3gF?4&d2Rp!eD%_&QsRj~Gn52*$9)COL2s!~&Cp>{ z!}{+1rD)tG5K`D_O!=Og6ElhQ_eub$^}TgTD79CYktyGW)z}Z6eA935>j@8HwI0H9 zF<_~3#RTQgfKAR&>}%I&7uCHZN~6N;P}{31sBq?>Xs2eht`#1JGq3=a`vOI>{|*Im zOG+~QkkRAj9NN>}xQU!Th9lx$*^bGFE4ESjAw-!R7YKE7ZPuXBNuhzchSz&LE@pNU z;X?7gIW|7y|CNWA{1l=tp0l)9x%6ur#9eUxXDHk`7S>0)uPotl@U#IHdv6(8_naMf ze32#FwWf)>ViGacm@$q>n=skhc)oRc!41F(hi!b6JQ`-Qn*`=N9VgJ`vV;CS_N91GJ=)0e|OpO~kjMsg)#+_D^Aoi5o^ zSJ1s;<$Ic$%%Hy428& z(j`p+yXaQ8da}Ye`4W%j@*Qcg^E`7-)ukev?b1t!$)fudjy5=fp@OPLegbQM!5Mj@| zXByr+N$LkMyr9JM{GbG|#ge^|2oIRHPr06$gmD3>@2wi1V~_^AOx z@v+Fi1pl-*@ogq?1%_<<{f$|u3e~QQVO`9uEYg7YnSn2;P>HuDN-`TQasqQ)D9Dnw z!wimVf%Jj%wdWjdi@KHP-3@U3D_gl9GiCY2S~2FJ8CMpOdkt@ZRMqw5*PvIv816aB zR4E!cF0J3hou`n>y7d0pJwcUnDw$Tj8F^mX4zp|kCs1!pytp9%N_ofn*{g-u(!Yv_ z@FC0x6CHA*=vgOYi>0xpEPM!7XMbBOT+kGt*$&MwqnHqMSWsT>c%?PyZ%ncU^L@_n}&OTm3H?GJe*OP|LG zkQ^R&NWNJwxclDNXa!(I_1);!BLzkQAgvG{YWOTc0KdetObp-` z%&}!+h)2^Yq4bqEYQ2R&I&Hm68LZvGXR;sfQGYO4n8D+PMwc8aGf?^68i1;aTg`k>d^6`M@P7Tm zZ+TgD>V{F`9u=q3QG-63@4LAdbX3qkx{Xb=Uys&r1o+0rf5!zhBiwcQBpF59+}{m? zp}H8~WSRem@PZ_gJ;NGZ_C%J~;cnx~C|dJ8UG>2bh?i_8H()7YQ2P?PCn5iV*N88x z0l^}?$mTlm->Klso89EsL9PQr0eI1gleH_`vxhneK%+Q+6NCkKWpbvF<1fl%zw4m^ zgs;jeMq89-fmwF~<@0*m8}XPpL8%B(W4a!VB?jTil=KsJ>Ix6LX)iUo1yvH#YoQdLk z?BZ&=wXz8P=xRn!OF6jI-+u5G`@vN7UJ6e3cdea!ky72iUNkYpun!}cTv1`2=VaBU zXGx@X3QEohi82So1~nZ1An_>h15FJ$=Asm}QtVvu7^ER>XwiJgAf7Jo6cSONB2#ov zWDhH0Sj9`gvn?6fcP3ZW$Gu|FhM=Hg*R>hEw4LV}a5~9)c{DhY<7ocjZ zER5R%8E9L?;*ddC8-Y#z;-Uvg-t^%Aw2s6d=XkfN&GZkg;Mdp}eWRJS5|%ld|B)q2Pr|`6@k|0Og0Ho$H2SH%B;RNOj$9uWkeY|ARz$Obb#b9!6 z!6?(kcz(@-%Ow*wRu|7{J}UHbD76ce7!|+x$o2{?C)pC!zOY?oZ=h6|`yXb!N+U)O zSz?&>{XHcKdEUlC5IG!t=)s7K&Z@wMa^V>5Qy#5(vmG_Nt&#t_W%2mj$LE? zY;mnKGn51n`1_IY(yjIgU$@{CP;p*yjanePuyM$JNzq~pAXnV5}fj^oP=uU3BjOP|J_l^{$&nV-bPo?#ud+Js|s+W>4H7 zxGs7Qpyz^*k5Rdj84g%jRqtuU*;d|90VOve z4`7m`s?@prWznsB{^PmY;{!kj-r}uDoUs+q%T&9f&&pgHhw^pE;!cM$gk=exN>yco zhukgKBSC2B+a`aie+py03n;f03Lty)o!l!bi6l~Zjpe7`BG-wfuHW;=u64p�haf@K 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�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ξ}H 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%0DE*LoY=I}e&}Xs?G4dfEGZHco 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

    =6N%UE)wbLWEM+?7KaS|;%Cl*7e&X3;Q5 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 z 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

    < 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

    ~w9D&q7RBTuEg zO3JP98o5Oew-ycH=IsJew8lNiq0PK&zsbd`fG{P}Y`bt

    j!RH9*LKcTLTo?8n51 zvN>_s+T2mI4mW**WCo9ar+{(Pa|3>ZZ##lvmoEfBg7YS*xM(iaYjN_F-{tr)_K-#| zAoEpkZSGxyf!O+Yxnqo?0U-^o!DX_8I5jFTf+gxjtpB7#*Yh78)ry=iv*I33qkH%p z&a|=cjrKC-qMw&s7KDt^+p_`YkA_kbVsbmUBzlL^@A05?{@OI`(C&<$;&Izs86sk4 z!{|!QLllbDq4ua)i2VnA(C-;l?h~R#=>RluwDMtp@V_hQMT7f)CAud77Oe?c!EO^? zUH5HDeMB!In+z|MeMCP3a&fKR{ zT6AZ!4UglM@;d(PPb7Emhqr43X$)wS992TM1u=`SXkwJ zLL5$nMwLh8jzC>T-7dn0=Np~|n@}q8M(wGU?$3V>EF_XPcL)kt+`hZzap1eH9TSVZ zx~cygTGT6|qSBdEB?NPT?j}h8(ic$81+5=pvSg$#$oY%vpEL|Jg&1yD5c9LT7V6$L z+QS3;O0XENL4sk2zx+%xZirIry!;-zB5a{R*hh@Ah8;Dc#kn7A-} zAt`e#RcrljgOZ2@sWIgd}%HhMgHn|CDrD9&8jD1zdR3;EdG>tD+y&iRq z&7u{ch@^LfSaP{+c*RqLn+f8fu~rO~c0l=Q;sx_l$|2Kk4_NZL-_H9G|LO`}R^NoRT+W$bhqt!sZ))c(xxLCEyP9dB z(#ZEumoi;RtslJE7C5r?Bn*XkW7>xnl?2Ua0=K!tqmhWPrE7lJm=O8G@0wC86oH>^ zkI>Q!_uYoB;UEjWLbMs|6WYEvXVopYgl4@F*dis z{AXQn?tFkuDqnPdURM&pCyj1CEt4I2w&sqykz@0Zx_u zB+I&gQqy<-a?^@Os5mU+64zv_(vU1Iz4k73`8d8ts!^3~LUfo3LcHWLU~L)cyC1gs zx1nx>Fd>9LYyQcr6Y#XRG*n;8uT1%$*x!|A@*;h)FAX{Vc!NCB!Ts@7CgM%M);_%WZ3~geib;|FJ+!j znuCvP+6MS@$nOTQ=k3Un~yig2f&54m%NXT*io+=hh`ws&Ph{jK&pQSeDvYh$}} zH>=-o*RV6SugNS=be^bTTHxCSrJa1RFJ3=Vy_Aw|fMqp=x#d{F)$Cf38lFRtg8fwW z(U*G{zevsJ(&#wiEUjDIXeh3&?Ys82Pg=U!^0m5LK!qh81mWGx!Ew z1;WED6+O- zU)P>JN&qn58SKbEdh0P0W{BAl4DXYOMX1Sc0#d3k=sS@2s(a_cRh-xQZXNv!?tfIM z_&!EL*J`^GuQ3lyUZ`K9*Uf6|In9)DuZBLLazT>$@r<`VmGtN$BP#3&COw0hqH^+e z0~|eX)b+ftgk5L>*QLDn-{w^oUIw+|%*Y{J4(B0SxpiP0m)u>8Oce+aK`rTyqRa4O zN6j6qPG%^5QFeg|aWZ+VuqQ>{v~Z3|CTNP~m}Hd;l#iVxolA%XIMJWDuMFPNG`6h{ z!D*{Hq86!&!-WGabcz3-Pb2HPJUy~p#|JupgyU`_Q1zs^qv~pQj~&N^!FxxnJRWg+ zG4++%Oy-Xc$io;iAK zJO5PJK#A)BK|sF0m3_FYVpFECZg5O*Law3yZ;8714V!Twe88#=LJS%Pn;+~=A5x&O zv)JhzuTl5V2%Har_gkbsRXZu6ez&Q-6ro5C-7SCqgjf#W;j7*e<%#^iqK9qw2K0tL z@S|va9V@XvgL6~*MH}PI6u_VuYyLL=ZpYHYS9TiJ?b^@IKDHqSQ4sazl5-F5a|A$7 z(w9D~0$x`QX-oMDR}LysK}bq6Jm+0*#JU`_;$Xr(=c@K~X*jKzq!ZCv?;6mK7k)MO zZ%Qk~2-%S#=bzx@hH|aNXD$g{aj;E}r!PhE%@^6wjp6e~*~mE_yG_IvPf%LFH06ER zksXzy9^kvUCq4bUu~E)1lTipVAM&DunfoTtMNrTsTh8E#lnjCoMSd2x^B`NYkr1-% z6gOSZ)#X~P)P>|taf%;Q4f`2MQAbsQr>Tc~|Nbf?m3Vx6Q>IZGU67UxHpo4+#a}9C zH>MQh7?WsNa~GvK84aN&TodGN6hO^x`9?e`Y5kO-L<-dubC^Zx!E%Ye|M|z?&SU!H zLRARtRHr&hILqAX3_bV~g*p(kczv~haso%S3q#lAfp-EWnwSAI zAvZ4wN8B#J(k8-}?= zkVpgpG0PiAje~q?dq{^y9z$x~R#MZU3m(@`8B|kx+ESWO3kaW{|WGDH?_E6pBn0&{45Fb_JE03q<+iW5Z z*Ygj9Xz|OFX~j|bGWpSow^%bgDV@3W7MBeyB7vg8RAhF~JA2OJX}1xOL|H<@)Y5Zp zIhuCy%MVLV81MTErOFf7{cY?HyE(xoy?1HR$(G>oZckTA-Y$3CyK+jJr}YD z_LuRRdqMNd^y@4l*;Aka6EXPBsq=<1Q47V%_Jy-Ouu@-K_(+Am#DN6dXZEj&S1joE zvFgj^a%!vXj3ap(J|wT!6SvG4*rEl%OmM8Ya2IM{2FkyrWuM^_{Qzo<5dy?5f>*;vw`>RZSEee`QzA`naMnx5Q)3R`Rp05Z>w zX+q@AB6v+JdTgP*=6|8nR`G@I-jSYoK8^bIK%IYXQ#0dYs~Gzo@nPoR82HEfZhQZ? zh}N)t`j~=j6{f1V8ACndtCFaw&MD0!o7R@p55Et{iNrhjhCR#5hDwiK-_x(J_1b2D zZ5x>w44fS-QA+VVyk`M=FVG!1eZ6u;4hgI$U*_%eBhEdKpy5fAi|u$XBJQC~dW0W;YsNc@#!p4_`4Ai=rK5p&(4U-(rLXvwJw<^y^^OO&8!H(A(90dThBk>J>% z^fk&3H$R`98*5je6ABK++VL9(9jFp~XEnX>zHh*ghgTXeJu=xk4Es<~i~oyql<~&p z@@O~}zB)+}4a@;Wo4+|ZDPJz9wOs&T_)2#;*ILxSJYqp$g#l9bA9<2287mIXN0X4` zxDcD8ny9-x$zW$y*vrU_(jvJ&(Ky|lKhBk-eMtMF`W=iGM%pGWh7|6|Vvioaeb^2@ zxIR{v&^!ze8y_JH>iKI1G~!*v)#6}VqlQa)%-C^m*l1u_Z(bYf`#{q z2H+q#ucYFr{3XxCZEQVCmr{NLW1#1_bnXEer-60Hz^G{_YyVcHihONgNuv#8)f7jF zh45}IB$9JkYuuI$a_`rr4*0Lek2>^+AbDrUM_pSgfZbz!u^;$%Z*E~#;c`k;;^~or zk#}#sT)O2(@4@hdle75? zR+drwte;O>@(jo?hmliC!3l73BYl#WHR*Lm!?*n%9x1;hIb6*2RzeO@SVdF}WY#6h zpeZU%4K4Q-t0_Hpj`;3^3uFt!J{G}aAMPf1R@5+~l&a&xs~!%H!)gJHIN;GmGVCx- zL@FRQ#G(vXhoL9jX9cXIm77o~z$UJpG-aQb4 z1~TyJ?&BAe3_2lpJ9$$nzh-Wcu!i}TheAXzclOcRY$z2QFP}Y*mS9hE0r9n{w zpZTt^(NLOqP$paEa==YpLjKbAewK)*YCusFP(=LZ6-^_%NyGssKwmm;5J`88qYnWu zHVsCJxV=5K8AQRz|0E6ezQh< z&ge2V$Q1Us2dz1w!?i@qx^8(7=k^BPN3uQS#FJPfi9_m~fn}<0$=n?!fZHd+bk>nn{eA+a$IoGjDM> z6ZS4=&rW?TiWR#x#gk0;q}Mj*bPBWs&s13jz=OC|6FH3?d~RLfvSWgnt_c&mpr6*qrAd*;|1%WhrPNMhfMQZ50lTEEWid3X?LX19M4 zbMniapf0so`)Y#d28|EGECmJVoOI|73lT1;o(;haxmtTnkU_ijshd7NwdZ_S7LjrZFn_m1hyZiI%91Pb;Su zBcQyl1lycI1niH@e=nj&s!@G~0Vt;w?gI1T05!oB+_n z3EDAX9?s#Hj@+Bg;#iy+D{k(gpc-SsO5bS)UZK1y*ONR%FL}EVpuPq%%C4P~eVVN- zdi|R@+Y!I?Qf1ypO^~yP(0KS!q zb4TZlASvo{*nZ24ip8y&9sv5JcEg>zVczWF7>%7q(p*~#KT^$l4n(-aZ;-}L5aSfC z!p4trm3r2+a}zy}&4iwF-Iy5k8H(>Nb+0a;Q9UBim*pGK$)f{Q>|=L?s|V0LLt8?T z-ywA5MJ%C&fhR|CCo?*$*QXp(iZHF~+kf)Ldr-W+PaFQV6NF zgXeRCx%#o9bAYR=M;Oo=FNnRepcA{j#Sb0jY7z$zjKTp!(Fg-pq=6}Qlhd0utc;&X z@&SUX8Jb%jz@(V~&_JuStJ*&N$U-((t4T-h_5K%DpW}#^%DFBAX0H~F&fmVnCH%QF z^rAAjr1PE}LPtjyDrl2Ab%rVXS8jgz4R}I#r+Z20?>W}DTjSNx z;o(R{m=5(pUL56ZCdG7zT}ojV> z`8_kVAr(k!*HNDZ9iqGt4b@UTEeqb&wV((qShpVY6xHBZgxRpQI_F}oek+0$8{2${ zt6DICqBrDkkbnVb6=aVdreFGAF9YL^#YOLUmxCuEwq1*oZ9-4!G)YS>7c7C>D{5(l zka1(QsYX2+xws)%B3U^|L2C`Tv9Ltp3|?1?oCv1d*&~*8>bq=-AIv1Dl8XHbajil% zJ35>0<`)TiXVqDUi0lrl6^^7&y&w-pVd)UuTw=&l~8q zeCDDG#tlrq$1h%sP-zx?7p-kFT1l4M|H~Y4MssZY40l%?N9^GM(tW~~{jl!fqFec$*|#yz=L6P0^e^b8M&nev z&I?X+B%EbrI|_G6Ph{eU@(xTetd9q3PAmRMMq{v{prm#bzrtnDWulE+mTeAXAdF!i z3$dPJ7AQD-Qs1Kv-bXic$YrN%NAI=7&t9NmN%1`|u}S>jiyKe^rejTrM(#0p{Sxa= zmg+v0dCQH#438W6Q)PG$!*kaN*p%gl1&gWZuM2^ZjO_n*=VwUM{)N$2Sev(q1Wb}z z*`cim$fi7)FE}O;}l2Dho0|LRG8oFT?7c!ivsZtZ6p#oIX$%iPgxMe?=ogL z8fAdJjkiaQiQB&1)?K~Ia2TkqO`vHmG=iNs-U==PGqlF~n(j~gx_T9vUrxv$u zaI9U^vueIX+LJG2H@TmSZtP+rvm$HX*lJ{cX_NHMm1nO_)QS z+Y36NT<-$>Yx31SKEJ=M*MMj3;~ z?tSbRd0sLU>a(BIMu)9|28uIUJpWD1&j!e9%OGi03~mnf8o4tz#1V$8nsd-Q2DN>B zpj{>V;3mVnfia|nu<#^>mmcXE;@XFLH`ZO;&C;xjtP{~cAc()@rwG0xu-3u*f5fpJ zkDg%(<@j`Ls2eZW@P0Mf_B=93G?sL2_-{PyRnfY~8%jk?O*W%{K7+`n7OD}WHU|mX zf@Ip0A<&sVb}4mw{X&z_e?YR-^%N|T@2CV}`K)Rh6M;-8?MBHcc0DsoWM(7&(eD5v zz^P(cYFH?1BI?#q?3dNu`d@ys5eHXF(t506PUeG_M?5m?Mr#T`2N?hnZ*^T^5Rv>uBc) zJe+Vn(WV?z1z}z7tvnJDVK<}9J?R*hS)Azq7@9gjXdz@e_lH*W!7&5u5wfcLSMc^e zhvy8hYel4zPH67=1xByFYVXD~u?zS_7hcw~WoD)eeoCtQQ{eR3{K3$V8Tc8MI8a9S zpMSH>`EiZV()-+Wr)4dyQ`1ff!~>)J%J1-7<@z%!(%`cbh#`1Y^^KR}*E8Qs$v+OT zvKTs*)r%6X3BWb?EIJ0p3dK|ZMky1_)=*lJ2n=w;Kh4^&I7Dndu0s&k<`%rwH<*WXi`VEVWiRI!~$rTVz67I$by;QcLIEsBbIHd{m&NI}%si?IMMbkXu$!p!!LQZV=6X6~o)kf!lTA?F}nz z7o*^Qbc*-=HNZ`!W9(j?iV#%LNWC#bNPmSZZFx#J(8E|Nv>UxOu#{e?@an=C6`E)> zD>Pb@iL3W>maya!n=~ZW16dS_36RrQQUB)1=I0EyK~qPqjf#Bqc7bI zDo&$hhn2~#M)Vm^ie}!#N0HZ^21yBNVILj3aBE{TNQp7cVhV5nTi!l?Kg~E{m@AR| zv`X_(nMLx5be>Y;E+?)eBqdZ@Qzoxygy2qamSS|X= zjL2sP9(i~qh>m`yKi{U@wcYCH|3JQb*RwC-IHkxUiDL&Whbf?ZqMWLo`(>5qvg7@5 zICN{h@tX6^l7AS@3=#S7gOjap?pVb!DuVPb&V|sseHrjA_%XakW-#HJptDSH3&{m-lN+o;pD5V#|B0f zc(gj@k)jGr^d7tPxVDV{N_4ISww%rYUN6n37r9et0H(??S%Q?PqrB(Jrpk_d&}D|U zYY}D?S;k|rXy{X;{p_V+FqrLnUl%}F^6EA^hRxoZlT>fe4u@LSaarOY#vRyi zWLmFzywX?zB$^DyD5@S^C(H%v{Rtucyyclma89P$#*B2tM#yn~k3101L*&iL|5^LU zJb_?^XVX%FoWF|eWix!qPID5Z1>glg#YaH{;^&Yz<KQE;n@dL_sHTE8z9^=Ney5 zAx(H!0bA0b3jZFp_%qE}Tx{{1D=(MC9(Kj1miMXc2Q5<%Qau1A7dv8frtApfN%|g9 zcaz$Lo5uHe{=4%Nn5MGtOw>L$x?P4o%6`wD4QZ8tqOxzZtIACl%!-4v@y%1Lu+eVFR@^ULUD|r;jkrGqw!D|0&(=1iNE3ubl zs~Q(+q}f-3r4iPfYct=jqSq&=0^uaL0%|d_S#qEXiO@Xd`-h9xK+?W;>(Psx40QpR z-`pxPVTD)sYFn;NS61l{9|bb7&Pbgh7uu1AJCI3HM}e(E5bw33Gf9`Az%jtZI};rzLtnlZB&ijG6d_)>cQ3 z&KqS>obksUp6bfPe{i&P9S^f(&p6BSWle&D>pTzzOEf=V6dFD+5jq>zY)^N)s(TS4 zK5wL@wg4$w15$|e2?rNDUUK(F;7$^nE@CWE7{>L>y3Yzs)oY`aYI=J|_E@}7b@$wS z-eFVsojVwh*6(g@e?@gH#HHpY?a?`PqTFKZPE>lw8n|HWAK(jDDwJnQg%8>RK5d%L*+ z=7qn+XN zjluRca$X$X^zj({#_MiXc}K)nTJ9d{WP}E+fudPZ9Y(2cwV<F?Is zcx%$s6Ffdx>+(jSxe3x5FFZGoClEYQD#)ak^5W?f$CRyHrzM6;exGvu9amoz6FD_Rn45);1*RB#@EC z(07p)%qjaQmK7HNwAM>5EY1(oegn5duurjy^Dr3;Z9vG<%^3=o9-16jTD{O|QiW!Q z0O-~P1&hvLHfv4JObY>EJEFJI=?2nf8+V`JQ_NbjUJ_IGqEmv{w-0syWZ(|7nU9tV zc&V@C^3{aym6*kcffWGc!I#95tew;3b)U)ZN)N>3S-&JOcE|<}6BKvMD|W=g7bshv%U~9u5SxyV7B#er zk9q?`Hm~Xq!oMWW5otEvwk3?uX?OHbtRyFI)A!kP@n{mnsgZzXE~-Dxu2k2(NdS-~ zr)ooXKvuYI(`uaU?T%$(;#cjyj@=sMP6Uzeo09ImjDMg22k0S2Hts#!%e$Wc((I4F zK^O6l#fI$LGz4@lA_Nx0IZTUPKHyrcdY!**8UqOmnjnZzR<@(g>s1@9pq2#y-CH6( z_ax}#&>!U0pugXE6>=7a{Ho_jkjImCRxo2r7@f3bz;EcL3_6<58jQXE%}WhS(|$xv z!rFcVKURz7rkcC*?)ID}WyT$_E0#B?6qTDOpZ0D(Xw@F>*{@}Vl9kMg8cm6Cx=LGS zn+5e~epEvVmIIY~*J7ibu*K%L6hk&;#3FkaBj_f#0D?bq`nC*}g|>n#J8p8ObG6ys zWydtf0L4%3Zt&>r+H@+_=!vmhgrm<~@k?}1we7{2*uqn2+g6BHiCC;KLeM{TGavdR zOEWgn`7kYt()g_SJSZr97~JFj>ZHW?3y!tsUo#z?cUTHss)UT>24+RMA^Y^`kXp7+ z6u4Fm$p?!d;Yl&Oz0Y%Iq<2$0t^NSzx&DHv`ZG>p=$tIkAJ52?l^+2ViU*SI63I4y zJkB}1;FF%Ko&OsQFwW;y#XFqFJe?q;R%8Ys8vBGAp_*153mc!f5q!ut?CbM4;=stq zJ8C3K7N%Q>Ym=0iHpEAUOh?{qLNNV5x# zyrwF%M<^QiYxs%=o#2D0Er<-RvZ8?=>#8@=I3I9f+~7w~&yuG3czf`29J-0TtTX=V zmv6Zld<)QY`7Ca|7Y1H9901y_Y&%N1C;ILTatf4 z<;oErh&O{28X8EI9bfufd7eBp(o^MfqHlN8pGd%lGMHC+b2kUwy;^cldlND#bX`Ty z+{}`B)ORy7^!R?6A+)Mq;|tYnly7zQG1J*(6pH95Y9ye1ctF>kMxCspCP{2>ccZ?t zLX2$tRuuKKPCY=Yl4jbG4Cx&)XzX@kf&#f`a3wS}z0gu%Fz)LuWATz^oeiFg+?qHaw^%MO{|yQ&S)zlglTiPNXR1k=wC50w3FaKA=83@IuoFG}a} z3t$r?YWKwHt=N5TP@=(E%gpf(0^cy2R; zbq4uQPZMxt-i&!r67RbXZ8x;J8l5%nyWQn@dw_0SjHYZpzR+T=w2H~5fsuv~yGd&f z(ZnvvLQ%_snpQmRu&Sn$TE32Ga5H&kWVDWsrfs`%#rTc$f-<>K{(*5Avya7mEGvBR zRW+V%xq-(-u1#}CSzTL|`sBzD2WmG;z$`SJBWG9qsrI1Gh@c+qb)#-5B+A+0+Coqt zme1S@>tN+)cCdMQa;xF{J`66lln^FXIHItu1!*2B6aHa6xa{64@y zQ95}IeBVOyBFkb25$?MTpY!#*8u26=vT_)|4uELt$aN;=HU~4u$MwAua6hDG7oCf; zlKO)-2|Z7%yB_vsc#-cM3_+aiI2{pI)?malx>?2qSx2&8Z{I^y)IWG4aBxGF3f^?d zdk><>#%^8_DLB}%+cCLVI^-SsX~hihIFnXfr+lxcXzC9C8eKe?^E%x9PB1}o%P^5@JXKCc-E$SSFvhy!lOp}>d<{m=Nolg+~k&d?YHwtnXKzpRyR^ zWSC$#qJRJZ0|0TkcbzI{FNWPJ^S0dlOzGa}V$Sy%*n8SZMG|dW?xabc;Q(rA4hd(c z=UyU~V_=b>H)(oVU6J8}_SY(POVFFUJAI3^*Tu0O{Qafh@=Dl!-oGwF#QtZ9GVm0) zkbRu3Qo!Anr-c4WBLQ6g4rHHYGsKrpK>;fom4H3QH`w*0kMAaL3y~?Mujg-5z-7Gd zjw<smrH2$3agd79SWzz|QIExh)BVMTn?k;*JA zs<`M9YG18>+YABIBzW?HZr(>OL*!V^ILz(0?2$kI3p#)MKwx=z%lZhK%sGYff;&%ql56*P(Fa3A&i{Uc(GBok{D+H71`6;_-S2pT`Vi z8sPvkCU+1i<;K`uE;s$>jIl^SRXv;GzQD5B&tFcG{b>iwD*o>%^z>2( z7J1Ubsj&pcyVSANFP9*--3jV{?OzhO0Bk8qk9i0{YezjdN)ivl(DLa$!D!!E(#>}j zHy;b$=q+3BWmHwsLeVLbV0dWBD}kO9PM{}`i)ZHP;!4*Oqp=Y&zLr6~@qYMD#`M|m<)XG`!Sc#@YGP?c$`gx$I-%j|zEfGwS!-T-6Z|QxhDk0ZG6}K(%H1r$OLkb--r!q9EiWSWXYqVzm9l} zID=qX-~8MjTh(!k!E+Fx`}ysTiw9okb`RTxGGhZW0?EOnfT^cKkF5zFc+%0YB^zG@O?CL@gXMSr;9shy5lwwigJ$-G$a;n%0zWm1Rg9TYE7CowLdd+Dp|MJ zjUY?FM7EwOd%|{vW{%~0tpv&)o}Tq&+SNI81pNlL%xys)Y2e#T{aHCOPoJNOD&y-$ zpa1s{1x}cTLI&-0Ds)|OlUZX+GC|1oG+f}-gf2(v6)y2NzSfx1h+jo=7h#n9zv49Q z-o|?co$8k3A4tyi?R;9myX_T&#WTo$YsBEwO4p>V)gS>@DUMJ%IHp)hF-xnp^jZH* zUJA^x1sM<5S@diTMU-Hc(Y&_gP39q1)*so$p;K#-W=d2+7p=GVF8p{0$fuz?o?}2!=q}e!WNUm>aRnOnfn21D*(92mNMy+^>H(jZpFI5=UYem!`W7wC>~RZ*&m(I+hMne*I~Jv*ErKv+a@ z5dkV;>-@(e$@1~2fU#)^Zao*N5EqiKMGuGetmliiKo@_UXX8E5uB3lSV7AbV*Uhp3 zD2q6&JvAfSM>iWp%DFY#_KUmE|76^1pdRup&l{U{5BdLr`ARRoE_(E*7H0;o^uk3m zblS@}DL1=FV(9OlIBO{;{LBgvAt`Y4NJuEIUOl)Iq<`siZF&9Rq=SF2#ZY2?yH=d` z#x)KN@|+55T5arkXKuc5f5OnBbiu!wePdI)#ua=&9!G*1Uf+mDY3bCtDeg!24lSbi z;v6)qpt>IZOV3x*sKV_bUOZ6vM+7bFmw)Da(=uq;~+Uvu95=UsdKDz3`?kTxh;dw~f$8?d)4*;vq52XM&4FDqa); z_*d`9`KFx6;(xUb0AcP0O@uwYX~fW%-qss1G=oin1ps#gJk90s>i?J@6X_GZkZ$Zr znm{t=F>MDI;rZ_7uh;S^zyoXAo5R19Que@1d(5BbGfV*J+3>y!Ss?W-D)#a;b8gKW zd@1!SU$j_9`h8T;Ek`KgKkxi_@1f!fyGFzT-GN_}s;-BEnj%FcydFadfTUElSSYD@ z7FqjmfCfr);rUyfQRbUC3$$zHRc zLC`t+CAh>oqogxF`UA_!&#liTHerN%!vX)v;T{)gh4{QeYF?tNv$-a_(dW2ag088f z3V^2+5e+3^>?B|&-Yi8iZ}SHAZp`TRZIk@EaIH>km4@`8cY=oz$6^{!t$fwSGF{n6 zd+n~={jY3*4S%lSNL@hd(h3u2Ewz%aBBB(W#(&kva$w{XCb)81Fnv+L(U>+ZeUuH4 zd_~@zbgdsGEoa(tS)^VXtW$Wc>x;maVNS?A5i@r^T*&_9s&vSz~ zQ55UhK5xzog;o4(W2uT9NM1`L)?X7bfAXY`hk!}eyQQm2*&z5g_7_CMd_XkCW^ZYX zUFg`~urO)SA07^G%Kw<+HRGCm@gYW05N!#kDUfA#y%ip_P&edN#Jt*Wjj>hEzVIv24?(78#mSF{d49E{Y zS3)FyXMzpFx!&$r*=q33my6RN?kI@LM3(kwVfaiU2TMU0OFF}~F*C^y|7IFILTq)O z9B|(P+YNi=)-5)_4OgwvB7e)akNN;q$Y+iC_nO)eDas! zazE$6ktD&!fcJerh}}9WOvOB5JQ97r@&bOA%g>qgwBwi^0==YP77Y5?YMe`{u0vYmE@G~K!9{NlRk}?mZ*3|w znbb&R#HFVu(y&s|P(gMsKhMUh)9jPwE$g$V2lD_m^I`0~MMyx2Juvn#&$NlZ-N@L? zxjP)xMdtm;)_TgMBWFJ#ZsyzZV0ozFJd&PlW$wKuo~#O-m0fg+ENWB+tc>Uf?*@ z2(Y$EuddDYpOqtXd5LRz`&%cUPneTZ%dWq@xQazx;#%PktBxwI@t;)vv?UBNC=mE&?eutXqp= z8Ab1hMy&IwqJIFTtRXL ze-+{b`^{uc!rc2(Br9#n^0>%G&oPOG$6q4tAX!DE5i4zl2%F?m$UYs)N3T=^#N|yi zSe(NrPVCr(m{CzBMA87gE|l1kUkC)ERp!w()eQ*2m07o{Zs-l2?nA(TOl2k9FphTPI5-#q|K$g7=Mq>DEa*f>`2T-p8m!*x*52qm z=2VaSLi|fR-ryErEvNYedtZ#!k)>O-7^#5jm6uKjky9UDH`$>urj89 zpc8Ju0$-ie>`A^Es0B%Y5>tJkmHY^dB@!w_ORYjUQk--S?2Jdj-!cQEcDPA{G2AIJ z9r@7(FebScokNUJG4KEF{^mx%n2zQD2_fQ(SnQt$aOKJ$w;cAfq^@Izt+u3o6ZC}{-9o@R}dvsHh@pci(OW^H=UAEzz(E>!;(aO%jvmQtR6%ua4|oy2z>YV z93T^y$x2`DKk|RkxU8H1{4IhVndU)V!)BLob3UU)L$*W8F&o9pYydIot=sB9)8YAZ zl#MsXCY+o~t@hXePlguD)KEJo6?JQgyA14q;(i@R5xUM1sk_%;*?V56M@CYnpsiTz z=KNA;+cPM9Q3hz(@}cK0j|ORTZr`o|EZGTUtRCf9|49Yb>`9O}IG9t@%3adCtCp(5 zezbTZ{19?{q}={yS#B0&eGhC-G*2zFbN2Mez(7 z61dB-0ifE!XIi;!=;r2$z!Tbp_w3HWt948by-xJ?A1QGl@6sXepFJvwjpiav@IpFa zJ4#blo4QV9J8c?4%D%3}{$t#z7mVVQk~aDqDLoAMd5w73dDPRJn+JKNw0MS}S=_oN zZgpKG?)0b!_-SG-$zl{A-3tzX@aBUp^jKVq{_2?ftv3N#VS@%o55^PgHAbe7{x{CFr!$K^G#YOcLpx<_Ohc;8zR*@~^*XNBI>h^c%V;a|$X0N)tKbF3fu zFFU#23)JEEKgs@Jpe77IggtDfN;RoR3B*EwN)aABUKX5V zlK2W5WmS9wRWpk1VbfFyBrmFiPvcX(puv*Pbv1y}PX3F3 zog8-VyG2U}(i!>QKMvQ&2VfCkle$k>tfS=J=RnfD&dLzg6R_4hv0vC3lvjRoy#+23Qaht`v~jee`xz~+CGuiC>NFx57pcG1TPu6m6tKz`b{&s*FJ9Du||Wwln=D+60wQ9vTOGyruO3V+PcPo!=g5uhYNCzS3aBg~}Gps~LL-&6# zBuDzdk?y$lu4VMfEbHwT*8SUL?kT;P&W`~`=RW(E9YUE?S{_$o@Q=oBGetIxm7C&b zDIl+)5}`gG`tg03OyN=t^u_8~|K+(F)Pbg;=HZpjNcO|!SRpP^3`0XItPV#775w=DDbu`4=`7%`Zrt)$HiGC#bIR2A`s*S9>2C`P6+NQ3jERaP`kn~tA} zbyv(pV@rV|8vVw_JN?Y*zUm0BOnG+5VWmX0h9^Cz{pdTt$*d7pwSGOT#QJQiJ-qxW zs&!KaQ^uCyE71x-vp}jkQMqMh8_%U?X8fy92TJ+El2AbO1zA7R!uvN#uQ%EkIvz0V zkjH_#w^5GN@@C-7TBm_ng(nL$CP}GuVl4p;&lU7jxs@!*R_{&2eauN8H>2%|-VLmE zY`6+fx)xaX1>{5R88Mi&WDgC$m_5MtyUxt}OTjU3&BncpM5VBj8~0!smN!TSc7^jC zES30V9_q5bu?xn&6yNPSMCPAKUTZyCcA~HUL|;YW-O@xt2sJDjwI^k@t$Crd#EO9z z*B@AtE<8lF>k7@5ecDTCxZYl~T!A{)rS)%A#m345tSfuTzZ0KmSxZ88Ko?VSt| zVedt^CrqgZ?LJV;jEpd|ic$KWU4JkX(#lp31gZ^>UP{8LVNDPWg~)ijqX+&pS(Xu) zpZV0_Fr_JeGHS2xo|9_TZj<{#2F&yy4I^&3sOK%DNh#lHT|Vlnnct-j&2iNi_M!{d zGxIe>U>%Bv72PZz32LRBRuN>VxqCP&w~Xh`b1UM1gL~ALTB>kl*v0x}=Cm=4^;qLRQ*5mzG&k$RUMn?YPd!p$qSU zXuHAHtH&=~;e5mEag+b1)yvz>8n5jJDkaTx|D1kjGYHeGmiwYJ3;OgIy}bedX5YLB zK|7CrXXL$kRIkpy;#GukWM;i%IYScxp7Vb8_sL#!3G%AsQ?p8wDuVt4TTIXDKVTx*P+Wj-zOPCO?g1&u5uSa z&zGfQ=e7hFx+;o=&dyx-@4w~$QB>u918mUGz2d`jF3IHDl+vqp1yx$E8Z6GjiOqLW zlgg$v^ES$8q2Q0`&x-;vu~IAz6I{-4{SA?$=}je3f;BJHpYpQC(jl_>5}W&rx zOJZe7OKvXOOsC)HYJS8Xs&`|7UValu3>G{Kwb4YT)vl#;m z9jf(i=a{Ujm7R4^j*m3{N>y4GR9VFM(c?50QtDgNdC!-WX?987UQ#5#yZ4(CNyKRz zZE+^MEwDd#a^<3ROF;iJL=ch9&coe7&Q4<^C89X;LNcZrG)u$-WOP>C7j1Pffu}I$ z52<2J8;gTJpKUutPISrOk0X`1hEhMlerINm@yd5pn%(sc_5rP(;LM&^mK(;^{JTzi z|I}|Nu2`1zpt64de5dDy2Wmu(ptfjtZmWLDf=CIg8+1nT5Xh3PxGt#fnhbni@$9nBUk=o4M+-x@o&;4PXQwrXy&;=1)wVZDm9Vx+t*Z3zQ_? zUFSwUuy6HV5eQm2F;K3PO9%QSFpzsF>yOeL<;*n zP$h4^JNW>H#a5r|?>oVn&Cdf6NumRc$#|~0bd_xO1nP@$36~+Vl}>~7v94vRt6q@r z!|{u^?AMe=nPi3>+E-nUEn)PDys+-c0fTWLm-^Y1Xd?UV{&TLmVUFQwdH2bxqwlWw z1jv~10vTejI^?#$g2qpSCK*m=?LYf;B45IW1;BgGPPaD;+7I^S3)oU3o&`LzRd6Xg zf`>;3o1d$jW2;SVn%$Bi>86palU@59z+H|an|WsMUrJhlx;^g0m?A^*GzVwh51gr2 z9Go9on|#nsD3M+YAu~WZ!#9D$aS`#E2q52+!FPI2pf8x@%IjjovAP_10tyekcE)bF=XQr&(7y_D2mCc9eg5 zC+Z~?exRi#&B;gZy8ZG}7}FXPk%JW-Hhmp=wFRVmqZQl*M`m_&jSo=Sg#`;PQo( z45rGt;$YT_J8U6AqB^tkE2ab`ehP{-@pwR5s_x`RT20uZq`g668xNGH&bTS&J!ki5 znDeR@`U=W90|_W#Igq9qkd2r{Cr9Qxm!i`Nl}s6{J6{dL<#I;f7b^S4P*Y2-ML5lr zP4<%fu~HPfMM^*}sMYwUv5>A#D7&?FV`E%D$N*`Q`?vWV1eIDa9J7{Zp< zLQe%Dy)4l^15tdO2cQpa$*xCT8=XQ!aa0Wu82?*7C&MC+q;a2U%sj+weThDi-TwQ` zB_U9Sre5M;xyL}Bm}pE4|E#1!=&hC91#;Z^r|)qHo9&kAs;9xK0-PZ7N@e2F0y-gp z+t*UOb=?;x;+~L>nLY2s$=?rL1qGa}Zg^_;M9Gs=+Q~z7!Cg0XYdd9P3qgYCMREF+ z0->odblU#|Z?p6++dJP^Q@!!oK^-6KeA5C6hE7a*a7up*O#e1ExtU!OylKVI0;D>) z%F2<9{#!zX8qtSnN;=&2kvkqf#Q~?U`5h&w_bWXOfdeo?96OXD%B~K0zRrvk5+YO3 znq|0AR+Kcth*}R^x+HZL^Sr3)Je=t(nY;RFpgB^Uk|cC3c|L=95x@s>HVB51{sR0J zGDCRrCJLsAAe|izr!x26F3Uj0;#xn{$a5?+0WWz3FDu0$Xza@mT~0Sjuqv!B7#9p% zZsMmLS+=03CrU2Nl5$!~E?O2WAFGMN;klR{LXKU6+rha($x4E+Q5%-nstsmt^^SL{ zhH1yW&O19}8W&3dprWJ!(KFfqDo56wkuJ|P;7Wrab8{!D`MC+Buw{f_0 zCi@^pbDPVOKHp0eL39}?PM5cOM|-a2oz{`6#n0koFUmz(LKWUae12y~8wX>6R3g#6 z8;C}VY0pgg5!W67k#G|#z!#EFC-BgnA15~c%8AH$WVz9-t&*E^{JC=-75gd4ds$PNLI+X!WvlT@Wf9Wis1x+zDj5=46vjy`D^`e2eZ6fY zs03N9;~^`qF`M;)p&WyPnR_|2nh^nx&rV?JFR&pL5sgp}bo`PJbvM=Yg5~8`dNB31 zm(e3YshP;Bd+|>rb}ksXaNs@Sn&i)$Wy_z%zKCdsLdxqjTcj9u9!eR$FKuZ0NKxJW zz0|j27zNJ?*53|$R1m4hN6;^DuA7!jGl^!wf$nEe|8YqXs%sab>8S@x`1jTWHbYj~agt_j-Tht{nL{#x;1*8V;0U}1Ga0DM6>#M-#)*0W*&Sq=v z9nP;u;a3})TEnE5%{QYD%aG;?GrwW){Hea`IG1<2u6n9v@;Bp3MU>nN*KAv3X$7aC zSl{1VO!g9sstR)` zKsiVsNt^XFvtru>g>z;}Nzr(%4iuUtoF(KBoddT+G4a;GM7Ej|`^Aze$}21sQf53P z$s$c^vpja5Phc)SIPU*sgehwhEX7hb^myk)5dDijj6uC<8V#f<}Fy`zc(E+g~~sY1qy?$F7Q_;qdgz`cW#sHc zLD))Uv(aPQ$9|{nvP4Qjz0*S+j0MCXf1n3q!o0V!uZ$*Dn`!BvEICw+q}!G8b$u}; zc0VsA$p4AI39D0xnZOp5)$PUlFkIkTgo!rR6=@^XkVkrj@8EdhWeeDv@lHl!|E6}m zdj-oLu>q25p1>t~(5FK+TcIq(nPt3qGJ98 zz5$O-&LKHYZ~ft$p&%N>%lnTVLykI_gseTbv-K%veL2Hh_fM8OL9-u3AC}9LyE~WI zxqX>jQKX<9kr!5x@EEtwWJ=fe=7+$*dXyAoQ5F^XZ#|F5K22Enzeq=|*+r{R$uEl3 zK?@W856=^QyRUuIrUQ~k2lt`4V>gUfi^wQg1dGk7);RvAbSZk2;g~TlR_^7>y{*vb zY6!_$l1p!Rt(Wf`APlg9bR7mz{+0wJ{1d)S3ak+laR zq`5lwt>kadqRR!wWs_`EaX4l&qjJJkS#}}Cz}OEll}db#QSEphKNj=1t+w{A4GzD9 znbTPNO429(XZmAS+hJVhLEy*ULmGjDUdxQ?!{$_G<}dDl&(JoaPeDl~VVPC=PtD_F zwY>=UKzTO@)E5qgN0}WCUe7>$rF}cMaeppn?Czv(eE!*V5@x=jo=q7Y-USpwPhw^M zk&{Pk4!Gn4t?zMcP~$y#xs40{&i$UgNeK5+V^WXSvGNUOFx)v#_De&&>BEpXxGG<( z(EkO|Et`gKDa*CI%hVoUQ7GaEnSHS_0fw_gM0U*=iCYr;&fH#u(`RX`2sZ)*;(!xt z6vnQkFASPS%xhN7V07L;oeTK*3x#03NFR`B3V}V>g|*F3Tj4B`!hB72)cxm>IcmNL z%-#pl{nN+O@(ZK$h}B3Zg(F*$pA=+((<;vHDo1EaNez@T#rFa2ep^y?`wgFU1Qnz* z$sp9)CfSA0?0VF{cck2>v5Kgwn+Fg&S`W9IA?%E2w5^neBof0ddYaTRV8AHf!*FS) zW?1U^VzX4`YX)AfiIFxF@_YIST{r{aa84c%g=IFY~Y4B?P2I+1EUOiQD`RqNtfr&__{*7RrqO|`GXGpHna_AV|C4EUguwP4s0VDYVo~SNn3PIpGM3xdA4F7>Kmz4=t^g0@3+Zk2it7O83t~G!5H_Lp9q;hciR0 z&}~_MP_0p7!-s#Kmo8!eA>>S2c6Q((VwnAPs#5dE>e*8g^}G`F|m}M>#&sP7*85pVhK#25^psmQam3J+p z(+m7CN;+=MW#AT^Al88kA~7IzcASxS^XG#7a=SR)$vNbsis>TB50KF1hl5d|Of`p> zZX=#as_)-NEo9k8|1)g1qgA5xMX6%X7&23j+cq``<*$HP=DmG&{&Y|8LO8-3sx_wzl@&8)1Up0&|E(sN_A!MCh zEk>Vir+00%lgkpQ`wm1F4N7QgRDyT2JZJU&Bsi7W{W2JbaUt1eroDG*t35)0Yt#IQ zThKfRHI9@-c=!u`m5|c6XsubMmpwV3HDcMcf3gcB^0f9HTB&ZWB278ql0&wXU+y-o zqWM>p7L2~dx`Ke5q6`3wPl(Q3J3wI~yZ=gCxpyV8Src&W*=?r(VNSAK5Fmj#S{n-r zmR@mcbj>`^$KyE_0rhX-NQ_u(Z>$MGa>El0f&H|B-i{+A#h-e2sM|7ta0fOP?pe7% z`W~xZXJ{S<-BjD)NGA}Q9R6VFNT%|yy{{wEnanTB17X8=p{eFI+^|;VW5!=ls{s>H zb2N!cR!x%BtVgeEObVREOqsudy4U1^N0S`CcxDxC~Wl;uAX8qM+3{aZ*{_Z&Uox*64ZgY*C?%(Z; zQ^{l-RrA@(C#Q=YR4fy``?@0UOppl8X<#x6x%P+x!3P57ugFA%$-{;9P3Y4n<2sC3 z0(RW;B2@ER!7JMo$@>hyQ1Z28?w50)BNXsFm1=i^a6|oLOnnw5wBO;saHvk_%sP zUA;n7DA{YWfv^sKuB4sr1@Nn3B0P1i4Ix5IWE;)LX7QCfnXRGMJA4qxgjCP2G+9k8 zd^d`b_x8z)@9^Qj|E&D)i;6tY-YAR#Fe1on#$S4kv6%emQdO*K!A~~SNoFa)zm$DPaC~KFus@m z4;ZzaMT_T7iB-F}HT*>ubU_V0)$eaXfh-TSwE+Yrn43W2DB>D{3{Fw#0|lJrY+N@h zJwrRKnF(BFmr?o=^=Fa4SsS0UVvLZ$le@7f1`1Q2x@?sclHNe~3#;j$q_I2{uP8P- zDNIj-UEmflyeBUsc9f&b?*>4^tbRDw2mBT#n&rLEI1%EMEW6Jd(gb+2Kt{-@0J*~6)l7j%L9Q)yaa-siA$rNdkRznfVcnct7bee(F zBtGEE@xVR!del}95-8OHID&Tx(WKdb>kLbabjxKtX83DfdjHo#zQ!5@=M0d6)_tja z<5VL4AaT$yMYj@gC!^XrzcAMERa51y85kTExXHjOKF`D8J}v3tbT*0a&uBz6`(-cm zZ0M8`Xt7bZJ8~C^B(=9LgwX8X@15SV8m=3Dj!316+NCxiJdR*!2A&YW0bB!&4cAQB zo2%V@Mztv}rmMO2z}nhUpg#Mn4U%Q~E({j@#^iS*Lj7dBLI0}i^QOn^rw8f@!Bv>3 zJs)l2YvCrZ+(U(m8o;=&9UAS?_@SrTJaa(>>IhBB0#3S^DccRxya~Om9FM6<5cIfv zPr{RVxbkT8uiRCl`iu`-s2!>5U5C(v!z4r|?uPF+ArSQ7?N$X$+tnRCC)BN?|9oe= z4RS8rUPUPn6jMq1ibhQb^t-QdJ)dx6UjYZ(DX+LXM#`80u}t!i9TvXjOk1KI#)6(c z$aWn~DY5qE<0U1%ztX-8T9Dr4qh|}5-CIiwL-Y3e@6Gqy7jzPjNZEK|a8z595cizI zhR9fwBc*riC>~CGRXqiEx1bvYl%u5Ty6P)QkC3ezpvWF@NT8DCPHHwiHMpU54*a29 zYPV^O!vUl76rad3mr9jXIq6e@+T&+>%wRNY#isKNmY&6hmbiqkp}z{M&B>=Mpj4>R z3INfrg$bs(dvt1^T;=;n2QWYIBe#RIxc(9LGi$X}m`(hA?f+hlFxheTs<6uwe! zzlEcuFCV0^x%!zO-H0Im*AT`TJjLFye?X(HU@EcN-bdFJ&I@tslOXB#{;8{0@hJ!q zLIwqu$umT%D)(89iuH>6xflcMAFScT`EM7EIBa(!N|hD96S$Td12+9(Pz3Fh|Ewik zky~^nq2HJj>?mU_v;N_ZIXflDYs)c`_6v`MvpvoKa$qtDYX-tw>k!(m8?u!*(s*X8<^dSufkRfdJUsZuNPV&BiDa z7{XQ%q@C`j+Mz?(Y)001)kKB(@HOB>hRWps_X2OspiMo_(r-eaVSk?^Km%}$Deg}} zY_F}OZww0FaNi2#x}%>{jIaG;IjAcgm7JM9MX)z9$;EcH-!#$~p63eD;EcmuNTW79 z)7yJSg#>|qz!dQbgVdgYbcEZ05YUqDDGCoo;HbEb+E6AfhX{Kvv@hgJtG?bw)5Uj??}BMGxALx8I3JF5lEnVT}6otedt1C(cxAL zp20O{1UZfyg{1+~K@Filk%$U+W74LhcF7V%szSSA_sT43w@OE&yK~PYhgKMY36^dg zw1f{-l1RRuhvS~$dr5EkFnaoF$KEF&iaf6H?Gjj|vZ2NduLGG~a___3pB6HX5vSr2 z*&N$ThR95S@_@0gpHE}_oFfAy9Wecj2TWw=59aQhgIfyco=BioZeX~U8*+)>M9G9K z^??;MCm&>lDri7j5D*?KA@VQN8KIQvvvV-bwo#l4Bjqgk@BqLE_lM zkedM#h6FeOH-6BWcBwDHQ4E^XOqGv6LgA~d?Yvv(B{qN{aZC46>tt(QI3qi$CQtHg zBDa10PoY~KhJNjjf+N@lm6|A^x+s-X!}9(yDap9A5)ezDSuy zwU|LpQ1KS>`y84&j9u&@At|fWDATD~RiYq%@cO@7z)C!SZRyWtJtD&cFW?Z9OI>H{ zlPzy_(ei2pPxQQNa7O~#3^2rRDEZ14KQJ^7k3HB9mwNpsJ)gV3JdZ3#Ruy)Bm|JVB z=72WcO|+tt()^LViS$F(?poA5?V)AUm>M80qmjQQo?M_^&keQa>r2aD3`FGX1^Xl0 zM6Aq9_b`%4R9T2FmaDVeUvTmxI5+*m(24+S$s;dtH1pMD)d67 zh$EhJCvHKp+xsH3yT@vZ7ftQgw?nj~*>6_w9WgWhZ+0CW5r1;c|BA}vl8Wj`iJU6^ zX1#s?PMNVe?dGeLTZ>$>DTpQbOM%)W%HwHuPTH(7>6AP9=ONUtMn{O3J(+>KP6@^! zE7`QM{AFgk3uU6-EmT?3WRVevGd~W@rc%IKf$L}U04K?7W#DO1ti&r z3!Ex#C(SKq^FX8!y3(^?`K8R6K>J`#WwJ~wX>UOJ%kA_QOZxEsp3~c(Z5G3bG1@El ze6I}j*eObf`~CiE>0)8##j0Th?XLXh6_#cdyq?t6=xi4Q2VZV zcw&)L_WH<9u;5VpoE-eSCK@MuqU-ufa3B#b9C!Jz4*K>5!c z!dn!Js?*x4Z?gWy;uLazfIq%pVKW z#TUMUtWR%PpsTR=PBF+D00J6x84mjn>PQQeaaPtaqX0iG)k4}SquQ7H`yj(g6yKXy z%`z9Ma6?-R5!b(ejBI$f!odJKXwKf!nz3gI1Qs|o5-aHxjQvZ@i!!UnmIv*8!nh< z$Lo*-meptE!aBomjfu7S=Q+!tg82L>lLhgi4~Fg9|gzQ1k%<+8015om}qmsX3nB4#3oy-H$gfSk!O`PCpsN6OP`Q z!r}6P6P)>r+dvh#eiP-K&S&SiW5+xY%LYZH%tbU*c>m^!xFBRZ+{?f-#I4zP;>M-y z*PlXHud6UeKPa)zI$B%I6K|8VK{4yVy!wc}@StKWYUJQ3+Y}(blZn$Gzm!m@qj-B!tNR1*g@_$${-xJs|Je~MPeF|M@0LwUlsmQ2Rd*o z%#UyFmCugq34D|CLp6l=5HfX#WV`F9A{O#ncihrbF9s+_#t@U9n9tu+$vkc{<4v>; zDpg~RHz=n^_QrsA%taX0tZT$DM>Q-7aj*-EpMS|^7`@5a_15=iDG;p`*%B_5fg&)j zXGLDyP&k9Abnd10Odd0#KV5%Y7MwX-A*Eer434D~4xD7M4zGi(V$g~oJuA@5DlK8u z0NTc+4~sFesVduy(okS0{ZIn^*dlkInfuTyCric-hD9GmZ{V!QBaq*RTAmKa)mY}f z&m*zi$Yb7aB|<+PTGL^#i`r>+*cf)r7h$c*?yahmTEn=(JL9JE}tzofXfn-l|K)NbR|xs%YEvxqgHs?_(-5)2?U>L zc>6W$PnnlfIR=N#!^ocPJXnjn3IPT_9FmAfkO3{j(is$Cdr_3;n^_x88hqgzC8A2R zLB=MbPZ*fk>>*Ub-CktdYQ@Ds^>^9e?YpOu_*BYTG>Zn8p}1+8HWL*$VdfDt;ZB$k zU{w@o&|HC0-P7{B=OFv*TNr|;E#&CX*CV79l2Tq?&eE4MqGF#bV5FkET657SFDcF- zQhjEzTA=XlG~&g2e-RLZcG^7tfQ5`Db_3#L>7O1%H+8IvR54e{BX7Zd@rP~Y$JKfJ zKvHHaZseD`b>=M|o?<>#>jq~Il?-9x#P*ph;cs;4x16*;xtLnM>!H2QiQW~tZg=HjI9kk@+nlarz-?IP!t|sA=-D^IF=oFYvt9J_S#LV zTX@dU=%T<3IZ5yjxTW+A9)%hEy-(^%}3U9$}5?y4>!^1sp21fUsMvlSs<`}_I zvh-jVs$OPS+cAP+7D71P#5ScwA7`+AxT_5Y`v)nNF~A{-UgF5Pp$2%6T7#!(3VVgJ z0-FqV{oNJml-|}5qU15VA?d&P3_nPYQ?Rig0eJIw7i-u2VKMg`G5UA#BUh2BU92)j$&Wj|J5U5tW9MEZ< zOPiq)IUk57F`nHKH%IsG^5Vf3uIff-F|QqD^)OH5HIpxwzTNVwH|}_~a8JfSuj7T9 zSfL>!%HbgspJ31?mtf*+epcwIpn(!pdyxzR90R5{-VOt%P$M>-H`&9kxcTFKY4mmR zx&;v)X*e175sWf%o6oB6atR`HUy3}{hhgN~9?s@j_dsMb3vwu=f-bvft*Ks0$W%ge zYP+J$>c4ZU6D8k+68X#i`_H70*Y%MGk6Y{bz})p$uuybYE$@j#?nbA0W%>5%)6jYW zyV-{(OU~zf+D$kbN&b!g0CIN+5Yfk<;Et>43-BXG&dVV5sTx!_bZKiV5`>+0?42Sd z&3Z67(xkLp1KS$dF!GmKgVRSUBgu{QI?hMOmv&N5tx;Xa0xxPa=37OW|TLM{~{YO;A}`dub~>TLw%^7xPH7Ldk6Zi4A<~Sk|g=F=PBW%!vlo zTQ`^+Mi+JL&jw;N&|X2=G4v8ntd>Jah=GY5ZnaIek9fR>yLz7ZITy^@I?u$^TW!q`f!X*UUFo>p^rBY8kaLTec8$M~ z@%I7}HJ-#d)LsRYu9WCL>R$+N#`{2q;6Kl@Q5>&hfWI5ZC-OtXT+U@1WfdT=#8ApO zN}Q@qVI{Z7!UZU=i^Xgf-M~98DL<2Uqxi8k7W=O4db8tFBx7*9Y#qqWkU>hAeoK*6 zlbs){9?-iJ2hVq{;den{G#MYSPQOwKfGZhPE0OIa;+8o!C&xA^+!}$?R@8|bCwH;J z^lZp&eP!HtT%b!+LI@_G`=oH#Mqz7BUgI&f*bRU(Gk1)#bhquNBMm|m5YR4W@9uWbtC0suyC25+ zP8f&&NekGw*rzB|jzIe0hq#`6K}1<2qLAG7^zHIi#v`O?H1N9ChhlZOO3a)N{_Mbz zTOm|BPCuS{FD5@?w=WVMBYd4c)8DwG*olga6-3Zc{h8^y_^?S8* zNi+9l{p~q1#*@-=X@&KG`Uwu*0!A)3*)soG7q>iUbR9Nk%jf7+cNJ8@-=a_3Mwcb7 z$_X{R1T5`xsCf+i@$b{5tc;cTkCN>9wCWb89xajE+9cx%CqxlYfvUZliFGN=o+D1O%31i4cy*cO_4)1q77v_Fxy|`IRWh)Rclm%~pVw?{_rRf~=Bqs# zN{8R_urTPsU`Qtsi!BCeNa+Vox8jm62l63d@PoN3%hl} z@{d16)I=u3&BMiuv}YnWcVT9-(!oz2QeLnGpX$uGmFh!&%g zI7^THf$C4KcM9a8;KRbSwR3R;^m>-K=QCzgY?z3x^75}a(JqNDOVwr`vtv7B30xpFT|@oVl79$Dm1Q_;j6*aclz@2ksBcx%6!%|h`4Lk$6v!AQU%-(TXYtPE+i zPf4CgU^nie8;ief?c+n-Jvz&1Ea!nhEdw-|Drn0i`)@yr?Z5o~*Gj+t`pR~Zg5Z&Z z_|2~+{udrSR^2h7^%;jg9oR`>-rUgt@ji(5w`BA^2rRu@iPvKa7*0ejW!*KB>%e{Bj6+GbnMRBJw1IyX)P9Juo`1dT~6}a~Ic7RMeZ9M#NN@cMZGHx+q zyU~F{o~;Y+-EOdf`*b1$PCva`@w3myOjh*bm-AC8`-VTnrdFpxyq|KbxEn`<+E+v0 z2+VV4>D^abg+b$EzCSoSLw^tf65y1p?w$;Z^>J_?5MA=Y4c)7QhsE93K0xxvmJ(^f zQb0!7#X&MgKS;IH&7RF5nR8bzWzA$PfXldkxKpl&f^8E`AOMG13D$v(Gm0|f zfuy@vCJ@6qm>C|*S+WKaJxx^Zt?|)24F5SF)XZt5UF4Fe*Pb&0>olFzwBQxv;*BSE9lb zu2$!y0N1=D*NQT1d>0FP6c>gV0DNGpX;LY_kyx|Cm36)JBdXYxZ1)wd#vR|&qLbYl zzVPHQ`{tzvOtiw(k}-jUJakv8<%*<=uLLRA`{kt@9zen*YOwfl#Cvx#>6SL;66MU_ z1m>wJzxD3=yY%U6FkH5tyO@PIUm+@V-nG!D4+0XqFQhDU<`c1;61Sm3jm57lRuON4 zlUd{TPfb|_qF^;~%(N zbf->o^d+ho89g)l)5QOeR)_@1!noP@3p_<=1xXR2sH8Gp~CAK z>{nnDhha(ZM<}sHM(o-3LAz|=O9|sK zB{3jRufU+|jI(-3LCpzRInf;g&rt5o^113J&U<=F6adm8DWuhi=l4Y>wfUl-daQ0D z1vt@J#X#*=rqK{lIcG=iiAzrjB2Y^c(>$4aBM zaJIm>%x)l4_Bm1dyvuLrh{mS)yw}h~$;)%K!}62}FKiXG5v**_y z)RYj;ZSzWvWpXm*GVVW!-5-02?>@JTZ(>@wgVzDXJ9JBL~8(ojQOv}~c zF0-U=!z`^h!=8Wc(Fv9mw*E-`ukS%Y$45d(XIpnQ zSl=HFrwGTEL`Etj8zrgG*2P2ltuYO?nu3Q zH%(`tWaIgociKHJ{Kce35l5YaMlYFkTb}|!nF8zj(v5Eu(6&P^GMn8*kG$vs%KP~IvEM~6tc0i4_V8-NG z_vHMbjYC~Oe+)CprCvR58W~$f1Vt>z1Z(fAPqmpPQ0^naAcOKmEhpu+{*PBuUZ~U` z)t&gn%bAb2%l)9lpDgtUq_a>rk}Y2@xLhHoUyxyQwZQ6bC0c^o`r@7mT86VXl8LwW zR;AmZwUeZrSEKO>AVzP`3ihjpHV?I_jT#|aa>lNIqV>y}bX^O*-l2#hP-m6GqP+9x z)wcS*G4C2XNO`kVm#oMU(8$aE!Ht5R3*vn{L+L->9NP`yQmjMNee~cL09s7aOzx+o zFAGs?NNh3g@Af%$mlEv`8Nao;vFG!7$+axH{%((p{<6nbf;W9;mh5myh$?>|B4t=f zobG7c1BI+w`tE#qK81Mzq!k1s0S4v^Y`%ZogLd7`%~p$A1Q{WVpPNM3!pg}?TAob> z@LZY3F-fg~xL@**QjL2auNc4St3Zrqa7HY@+6jjW&BU%ri*ju?s_Jw*x?7IEoXm~V z3s_Wj>|UaydGY?-i}$2Yh~oE#!%6tnYf2ETdBLC_{pCV4aDFDLp@vCf`@jGTp7%I3 z_0dufu7=anv!2M&l$?YN^0EK@SP}vH%9X~6W=AkE{Q6s1wS)!z5g;;&0nD*SNGumLEQ-22vt_UQ~U zq)b!TLS=%AsR1P$u!huo^n7vx{L7~r_-5-}x&U6rFD(WXUCyHoL(8ccWj_=gYl_Q0 z7Sjq8Z6v56OJ`ndAOiQJ0^~gD){dIS043@Hr!md`_Psa+;E72P{#a53t~?`@lyO!a}qn_R5W>9P=~VCJA@d_=oG98LYaTI9bJ zxYc!{k!5*~BjpQxA1Ejb`iLu8F(g!kmoy%%{eh`V;$Ci4rr{KJyffiLMqQa8=m`ch zJZVy-pzFy>P6d&kzEb6Fwhk*CCnt3l3sMkKUeGX;yV0Q|z(pa|!};pX|1nhC9do4%lU`PE^3 zG_#H4Oafu_v0uRe@DL5We7-VFdr%tU(e2jHi`>W88E$~jcf;z=51{OCW@YC!=?4CE zXZoA)+Nz*KFUpR1@mMhEMdU8~O^i4ojmR4IvStM0cGs+VI_B6;OME$(Psi!pzC9?P26I@_Qm zwrlCGy|`bI+1rqXb9#P-9<_>oZY@L|S$OSrmrh@X{U!$EAg#`?-sat6%x|^a!8Alk zq-VmRC2fJifKh$P2@LXpq&A{uJ<7x8Wh{o#d*!--qQDZjGIrPBb9^_7|bR%I#5fg8Q^k0EI! zhz^${@&DQ=jXi6jalVkngT&n%eUzFphY-z;p#gnM@nE&z3w5(RZU1h^oA_YIuZfb> zs((qdfBDJ(|FEJOOsbA74(Yw|pzT+wmOq|>BmxkVghUwVm!oTa& zc%m+I6&Addb%*M?0ae@Jv!A|D#Zyb|&X9ld+>_PzQv$+$M4CV3^&^OQwg zPYeu4HlVVo$|?x|%Afo9^fP3P70Cp&JheAWmk%LK17g$ zopY-YNLpTMq6Z<1WVEOS2Pl1pTD-n49H03$W&Ahr&^gp8giIxglPPRD#8Go@p|O3;b{9shy;8EcPJi5UJ)QmnF;ntV+wd^bmH(mLd1yfBg3DnW06SNi z3E`o7s=RK4!u?oXd;@Rau30zifk3<_xsZ7DAcZM*=~i z($Oj8*2upapmtK78HY0M(-?B%cKp-{eP^eZUl=Hu#>@B)esP< zc>Q)C@ZI^aJKV)u0+@*vv;X2%q_BaA)oURll_Vl$7t4Fax^Lhz?>sM(A^ka_Wj4W` z3G2}6{jKD4+%C&PE5RqT3~l##>D^N8ZBM)Ph-nT8FN!*6Xd#VU;sSB<7#)W`1`1Cn z_h%e51V)JoS#qYtR30%-!ri6jAt$L;-5P?2$CN0T-OJAp^~0&xf33Qx`1ID}LB(DtzvJ~}_NevBlgm>%Bt$??TtZ(;d6s;T{>gl>q0XD`e}b-2 zfdN*dS&w#pY&YK;=WpJz{$Qq+aIw3_C@Jbn}=PuJNM z(1Dw4T2-{AkBXhB68*0>&_xZ>!-w+{Qs^jT?a~{`UgC;1hj0tbR`*yo+d2jLOZzKH zP(UUzb=_gs6WpjXi#j&`Q#VpzBy#3Tf8BPfiVglAw?Mi`Urb7=qgg#yw0V949T1tl za}9I-Cz$%z5S7E$nxNtyr(VYCPFTc3%%d?MIw#>2he$1EA#yP;UfbvNZV|Dx((wuy z@~-Gy#OOZlECo4tx`Kn*txM;L4IuD`0;O9=4m};&4T`cE2L3(L&toMlrVxcCoRZf0IKXb;41-k&CLr2apdv! zA3Vi|8C-pk;=!$~eg{TNnCOM3l#l&WNm|&mp?pxlu%|8(~J*Qfu}ZiE|UCI)fEKhDwI1pn~8zi3GW_y@ZrcDWuqm&KRi z%ylAQF-KzdUc>lhvCsd!Jkaa3h`-lDRgJ~C{$Ds@=w8%3kkf`eu>$ooxDKBJ#5HCJ zqO+2-{Z}E$?P-MCDJiU9NAnz(ki5U;U)`g}rwUoh1oA5-R2cxmxOeCxCCCfXZN{;7 z8bXw=l99EX3B({LmLTy{z*%mRhxs}xWA~$C!bN#jw+Fo0AAtesxmJHzA4J* z9Z9TKPua6~sXE~v&4zxcH2G>U_S;T?6d-H!EvDjQU*HAohaR4t!f44m&7?TT3DcW! zDx}uYmPii*WDro=B;`kVNd^6BxVU+0)$@kh687+4kkGjsI(w#uW4DQ)gMbYht}jl1 zLC8d%{G~W;0G&V?!F2~=Cxa*)(NAHej}@!K?*?dV)TVCU>OMN^BH4;Su{Xvt`)9kc z>WJ2&ChZxkYl|+|-8*;+OdZ6FbqT7oqize7@wfS!yEPXloa+s~O4R@str$*g;)md< z0c~W*k6hkZQmSCLe_hct*w&yiH7(d^>i}%?!!o%WXajCOqy2JUo&&DO$X7(+s_A;4 z1NK~B2MHxZoejGgenY>Ot}#h%a$&0@Xb;B3K=3;kMGeN*yN$dycgqQ66K!5R>wVJ^ zB1X?XZJOuS$NN!_WQR*Z8PD-dezjodwtP#~!W<_*7Zq6mNX2rdV%Avy$GhnG0LxU% zSrkw?HS1g=Y{3MYJI;#&#zMrS~H`_>fY!yh2iAIuBGE0LmE@wb8ra z=r2qy*;UYwPndPwu?x&R{%izDpSkc2>?e@y^}~MlHd?L(uvQaXsw?vqJ3wadX?&2G z;^O=4g{9dxS|^!D&sTpAy>Xl?t*3%w*;VrNX0ZKYOniTi${B zOAyE6n~Xo^Cgl?nXdnC!a^9lu`^E_?VCh@BWi+7>)l1L?hzMD>h91Ju3Wk#yrd$g9h@KI;XmCNZ-c(*_4q85n@YfV}a7jK55E{ zBaPnr2JMMSZY4FXo{t&n{2BQbL&tZ7ax?MC8Mj4o`ZcO+-G=PM5D2D2%tz0rJ72FQ z#DtJME9ne}(b98VzHa*vpH|Q_ffF%jpaYEC^E(ZTmv(RBSc(A;wQP5IHa*L_2T-W` zy8X7Fz*p42v(8-6H#MQn1D2Tj@O+z@!?4t764DMEPOWA>36K^|7pm}|_)q&2(*8i|B1<6NB z@R(-mC$WJ=91tj)$^vR|4gr{D4MLTXVZU^S6VV%1y5r1hl#}QL?mM~l7jOv@O;(SinVbPmpA99r z8H}^|SuB(Z8__HrL-HS(Zdw;GRxQ<60lC|3A6@_2P?+bdi0oHf;S53i^*E^UAVXBG z#6k&yA=ZCE5fs8xhJ(T3GkV_K={%pxa`|p1XW^c074t@5s2Z6K3R)O6^FdD|l<F>|d)_TPQNd9Yp}hso4m^G!C&3hS-3E?5Q?*mrv)#u3NGz%Y-!E`sN%B<5ev z`z^S4dh}2JMzRbhtOBd%P9xexx)UK7!~6HT_N<%PI!|@TQ4%fCw zNOhC2tvCNw_Ete5kQV!ScE-B4QjRsV8M1x!6nt8p3R{Dk;|92Oy_f0nb&CVyOUWEW zr|X~vk)QNQDKjF`(rw3*t3}P#AC$~3IFeZ+ETXREy5CKOPMxAFPG5iE4fnYOuLq! zKv8M0&(*Ff|7lqWExJDYQ{6!yd5R8URUMyGKz^jv?kO;^P*%FD0YOfNBTk$`JILk8 z<{^;tu2FrvF9F>AjlIip1Ppr7Hcrbf+CLWck%OAwm7?=ZKS4wq{t{)}jEccOzAd}LXmO8eOsR3>wF8d*D$%eQ&qvMH>n!6*$f!4It2v7Oh z2a^cj{Y%My*$lSQ+rqj299NuQC^TENJh&&rxcI=Vc-O_|)HNum45$WUV`|j=$yD4l za1GE!xhXQxSP7p)bR8wb1q7UL;ly%L{ux1eL#{d<8~;Tjr#)6IV0P7OI}lExDjIJj zd6}{{*@=1tz{=8G7!S<;Z53&V4j0RzlLYWRpe6(iW^^1;;doW=AXaoGp?|~e3&Q(f zWZ4;)(myRiDhTl4!*jyA31>)7uoHpe2q-uPT@DN~a#W4|hR%=h7goOE`Digx2xIY| z#q)*dW%Om;uoQ=Zn!_$15Nd{&Bqk!3zt`HxUp=^mP&nI>amhn6k4x&sh&bM)B~UX+ z8|0`>ZkMls&kD;v=0ewrt73n0gOlALcWo3%2*7BtK-v}aSkeW4PRUd?=rkUuyw=3G zYRMPt9=R)W&sYu>a5`RVI;B-kspG{PVS%U@%xQKo_$-x~Yb$4Y~uf?8z;u|)#hQe!zrX8)d=8^G@e=&V`< zp%07WAv}LnH3l#JHISP{yw>ptn*nP^KH3=ciEtg1Z}NwFFs!*WL5vrDfg#VQRPOc@ z3x#NT-0**?Z2%I*Z4gdZ|Nf2mFN|whwWPK)pVLzItzaLqb^Lf6`zQw+(a%&csKWqu zX^eCnq*2wqk!bXU8BjyeUe^z~GQHHclc;!JniPFQZk@W(%i;kuMBkp_OstThWA!Rl z=GaN4oxnr>`C>aGn*#y<2M0x=Ib#)HW*iY5Qod=F%+M?`Ey-dJjp!>_P|k7YK-)nB zH9OC^15`ujJF{^lRZ=XHWAgO16EK#zxN$)=+F~yer}|j)!}R6?X&jX>Jy^L!6^WvZdDEbk)Rfc8zZG+?KVrJQ#FV5AfSiU(GSY;P>+hwXDV@ojF$-|r008nf zn)B~f*yGz~N5G8}B^R&cTQD~a{OM=|%RQSB;zm4816zh z@1dmZz)sjy;%ha7YRae1aNS0RJ-*5a^*(kKjjg{>>`&1aVVoV!+sNH; z0G5(oyC47uRCP?8%YRg8){l)eb|C7O(7&JV{06EK8xbx8_F^UU| zT*L`k408h_ppeYLJ94jg5f$JUrS=wu_+ew|L95d*dKUM;%+1BQT1X@*@AarSlk^8{Y*t80 zy#ZtCznLjw+Ph4}peH-xU`s+$_y;h5KqOnUlB#ZuW|btA3|+e-;zj!#IA5N;v~*VS zzc1rlA2tVhO;_CAKi4Q#_(jlNVb?id)aP#A36%9t&vaa6;^AUh900sjx z@YaGC%=PWpO8k#^B;dnvc3p8=8C zIl7L|#P0$b$1W)(&d~GD8P45FGKm@3-`#VG&Ke28EL-yZ5}WQD`sO58eIMkeEm3lM zmDY*=%j&_Ws+k8NWoPQuf`ADzXK~ALT87EG+Q39@dxuVtTRKvooOdO z|4ul03`z0*(d>GCbjX^zP;#NZYmmHJ#Ad#eRyPCIF9K|1wr7Q`7>5joXu4@krr(yW z|MP1wF-~0rlamSvGaxuWG;J|8BbdikB!G^Lava?pF+MRyIj$7bZ%$ui&C`g~E!4}@ z9N+WZDQ=;q`QnF{vSjXeSp*R{l%kKHesR!m_DHB7xd^F%2U&=Aa>bj!=t7z;|N9ks zVhX@zv6LTqSvGPfgV$ZJ*^!ym{s=&`VRxS(W@{h=VGt=;Ud}z`TmF6fdFI6)a0t+u z-Ybzf(Oy-3F=$pCYLS4B#-RAee0PDJjgb@VgVBQkNLAVD6kB&hEf63f1{v^; znC&F^i)g*$&qdKHdzmC&D4Js;Ms1QS)02+E=$-1<|1gE6t<`0ceT!QgJUB}Ya+H= z@73(tMJ@Jui5Lyd5$6Ar_o!Mb3PK~(dvN%ugl#^eUT@MRI2L9w(X6>|h)CpbtW#9ipHTQ2gz~NQfBAuTwXLSrD zEiV2Al{}n8w5YX%Gy1DxW<>bq)FL~*>jJ7d2jlGq{*}knCz_*8F!w+C{~Mj=JJZ#u zAf|U>r=D5L)i3S6O(W=V&!>+0`$+)t3BMzbkHLH=EZyEjE>+tF@lalIVTFtA2{o$A zmn$6v5NsIDvjgjLpbd$s5~whnCf4u2e5wOZ)! zPx)?aAw_GI%Mt{YG#ex8(QFiZ~Wu;q778QfQRf zJ0raLTG$qnBu3==CBGCNpq|~DHijN3%9>NePG4_R877vV_*+`Lb*5{HN)uA%aKCK< z8?XrBm9$sbFSU`hxi z21OLxh%?_Tb(If z-?m=H)rY;3{p%_W@#CiL-B6s0a5OSA4Z5wX8=mdAf9KUX40gs{6~bw!7vB6OYa)p1 zRQ{D#|5seY!gYWzGLqCo!yAMX34VHq5x)(vAtw;yCKRx|R)}Ri&Cy5(_%V_!*$%qP zKkV=<`GJ8BHo}xzxQhMV^WOUp zPJdQl1osJ+q(xM*$0|X^SGuQvXB5h>bpAZOti$Fhll|O-|K%}3%@x%2>(M_RH0d_X z9&Us6v)iDe{(?} z@I-cMOuc8y->^QPL$a~26!%X7b~XL2b=)W+ozCCx-x12nBMnS_+BT5Z9Gst1LU4gf zX2Euc1_HZcKmVgTvs5tn2r+swbsBsz=~rxxPP?K|0O@SkGdv&fHYF5t* zoaZ~*bgOLr{ol>QS~MsBXh-OBb*OPNiRI>#zwy}ho3_xf=Qc$D+92}Z$|P5kXgG3_ zK909^EDbnrA&~XI>gq1)QKGHO_frV*>s+JjdK>0nm6cFgGOqVd$91~dlqib@E|U{! z;fjgZ{d*DB#Gg^?LD_HIN%i0m18#*&<+VP?Oe2o;pAt3E^Y5N3cr<5s?!P6Sc%g_k z$G1}Y$Z(+6*Q>eqL}AkOkAQ{HLwP!e3EQ@rdom&SB%EGil!I+TYEK{wwBvw${(Kd9 zs9G=fMd6FIq=@YJ1d8b9lis-~k9+}4J+0l2HW&H?JLzsZ0_6GCM*pxYfB4IW>|(Q4 zV(f{&>g1Y=b!6d&&2m7W%P&>FO;PH9PFN-Sda@s`3|?>96p9l^9j%X)f(|p~Li^9! z;7@fT&~kDizRk02?D^gEOb~YsiP8Jldid&>x2DH-Ce4GplT8suPqikmmF|;Tp!69c zspM?0_y9KadH6>8>sMvXvi>alq16*GjcJ3Q`&0Inc2i4aA|xhH%^8N5R?kBJM*F9 zfFJ6tUT%qOF9}R5?@7S+il+J@PZpdJdiyl9&Q8=v1(YEh0V#fkLz|*)KR=5{7CXXRbH+(szC}uUi!yqfRfImboAmP;Wt5B+aNwZtugh)XW!k2}OxJ!+DfYV?Jy;a8Mvo1}^9C z%zO=2cd|LfSW+0VraQ85-S{Fa9hjQ}Z_0DF5i`p1r@* z3hEl*y@)1Uz_TNq`@wy#7O8hc zKZI+rcWsmB4?R7A#yI8!0*3!E`9D6sI^^1|RN-6FY^G*Ixw8>uZJy~;XGSe@ErSya zP46wxWM)QEzj0zxPn+*d&pxAJWVcluwxvcf>@5S;y-M&$8lKJnGwd-%jSH(iZ*n0~ zxNAqXy5HzWyb)*p4ra(;PP(*%h!TP2C)OvPAxxq}(>L$Ck{>?^AN^q%2?m$n>LDz> ze<$J$m7|*LNH*8?(Y(406rKkPnh6iEFfel9(UJ$@l)`c2Yx4!T#JWb>&xJ{fr?!l; zSMXtS9nQ$$DCWInln(H%3Q+W>z4m}DqUN2-qiosC>S}vkTjSkpfosPchEKhR-e3d0 zPwCDlc+<7HyM+<6l(tNOhVMs1VF@|RoD0Plw!BgQuKpb7Co`oITekjyo?>Dvz^!?Fuk-GZ%lAv?o80hHz;6lq*hpO9QImZp4N~|1G}NSECWN08jPvScl9k zRX{9Ie%|btA;+exPegOHnq+VokB;x6`ipS40>+UE@DFYTP(a#P;1Wd8UqR*v?ukqt zN}pAWK<1>^PJgdJ=`!1@iG34EG4QAwHa8;wjzF6ZU5?Wi#{r9WZ2$H*O5hDH5;}Lh zhXNdOO=Bk+R}A}~E#->7yF6mdI^Q~UYx+($PXX&M`;`g(E?BDH7}Rs7r(S#lPN^W0 z%G1HJjw($!MC3_GlD3?gIQ;jr$>dXX+R!d?wPWV^uXB zX+GK%jIUvVG$@rK&t4-{XigPXL_Gpv*5$XYrvh*P4CE<@=-rL@6K@d;6r1;uT{)YQ zJE_jok>tCqNaq7x$F5%L=&YchS&s}+`ivThk8|GCAYj!T?<)ksHGM^+=Tr|OSimeA z5%IwzU82q73dBr!wc*`KSAsKw3!z}%<<^fIfle7u$K7L(q;nEkF0V0EpfEZV=%#Tr zE#6EEK;9j_gcXcCBD8n8VHqo1n+Rn5`IQ{WnPF2Z1%KI!0kJlm#q`J>gx{Sf#G}Ru zE89mp!pQf3(Nr^1HZ~KSj6qtO)F`0H_RxK?OX@0I0X(gPY25xGyrEt09ajJ;pvBT| znv3&+)^WaaPJ6c`T$NL;OCQoS%f4`Y!2GI6!nvqn|6|}maXUa1z(=s zr?XwJYaBoj-E$!i(Ro9!bO$q%K>%B}xSGFs(R)n8UT@DCzop{|!^Ii$Y1C>P$0WSLvFB3ueu`|GOIM?PT zOwh)r%(doL_jlAs_RAX}5Cgk#RMway`Ifc=nsAb2>LdtiRhKtwuS;H7*(~FIjNbRB z{jT0=7EGcn(NF0R(Tz} z&@xpQI-JpyT-Y+EZf3M4fW8VkcLV$Pc53M^bVXDgZ-up*P}cSGq|e9=zS0R5@Tq(4 zEd`8(Se<-Q9{6@(2ks91RR(AJQx?*%ERukj9U^s0Y}3l)TkJkMjQf3?q%)<2c5}vK zSfO51;Floy*47d1kCanMWAh6iZ11=|wt76Ma$ z#u#m*ryLw$+)VHRRu~1j;1XgBdMstVaQ@`Uc6KxJkdpG7NRmGPX23|OXO3O#P>7J1 zxr6cz$_BN)-%STDP^h`ccqs$<4iQNO3Zy*ul9!fc^))4yJJ9-+mw)#FRfZNkTzIrh zt(-*`<1gUPLl1j6n9j-H6G8`i6z46uV=kelkMokTNXHPDkYs@a?MnjUJP80}Pwt32 zcND7=v?^ctQVP6Cl_x6qgWZVguHzfygF(xDs+ysSKY6FH$hNPEN5_KAtp7a7$jJbA!YkRu zUtG@2w(N!bJh=|nU`*2~%2211V5&S{yPZ|i%~yG)frERdEcJDR<0utDO*4S=!6IIz zmKYnocDo(F<6sr-MVdN@R(<%uaF{?inthUMfTWi=c8zE{J#j4aNQ^Gey@^${aeyP1 zS>|kJ44W%01JuL!Gl8Cz2{{=C`p2Mu2@pfp85IN+;K-afFGuAh5?aj)^@SO&iF^v1 zh(gQyg5(`OzOe0+%!J-|LcH-?Q1llvut(f$o=d^!D2b@FtkshuWp`+G(7TEWEdrN) z?z3`vX{17s_4hVu|FGUQ#DLQhRdq&%hyM-<@@gL^l^>t3$a z%^=FWQr!eOTDf@az+;02zqA`FIOqfG%trc9lBvBghn`=R2j~<6h+oU*9;GbSmukPh z(}e97?G!{D;$f(!tm1#U#+6H5iUuko5n^eKf@J79m5)TzkUQ|xx|Wz_u3|77l%e01 zb$jz4T%`IT*GHvWz;7@I-BtD6H3{dB!|ED*;5Ed3B2va9p6+gcd@l|AWL8&z*kDB6 zfSaEaYTN{IXmmWKWj9^`We6+4D~G4<>IGh6o}IOJvP~Gyf+bBh#!w2l`qBe=dCU<` zMg-$5oxn4})ni$?OXF7;-M?+2^UJ0JgC@FMmspe!u+DJjjuahOcKG6}yiGSJu+_$+ zH!3I8h9Fw2p^UW9@93(QRyvCxH9+(??o|_{I#U2rX(R8 z+Wn!KGT|9}8C~4B-t2v_W0>e{cS)BAO+H}Rg_DD-O(_0T%$cWw&0H$~O%P%QDJMl* zt*T*m?w&C=TqZERrpfy8-o@}3vf-wE2pD$<{%i3r8r9D$FOF2SB(i7=vNg?H5)^3} znEz)!b;q6HFy+5FiC*S90Ii|q@*$9nZj4hFkc>MiA#C!*i zHj@5C-aPK$sgj+&kDny7&vvybMe^72kry@mR4_g@V~muN>{-L3gMcUq0r`o2!^y#v zUIAPv+nYblx)ZfF_73jKw^>41+j)Bi-6v2i;12fX6dgK?Wv?$L4eAYlCYaz0dg+UQ z56)OX-)ky{u;TW$$Ka^g=k|y3_OgrkHB%kpR02`I6}O{&{)z`owAdx*!%i(YmSbyx zllx5R1du;+kE@Ijy{4D{38t3fKlV=XjGk=%Z|FOPPH1YOep+fACUHvGd3hg5Uz`|1 zNG6VM)~mjGm-3;c$h=%~|1_Z1|98Fx-OhrRW#=IAHGk%SZ zJ5d&gLp`Mf6sMLA1xKqLQ%!ZneP*)b$Lmt;j8H4tM{d!){$}83rz5N=PI^sJdLw|2Fo2(&(A)Zes-! zYCHvhY?=5^8ly}gpJ{Wk3RXA>W=mIsg9wTd9D%sn(vctgJf9~lN*V30VEkSiK)*Bq z44~O2P2zPvDI?F2_`HackI&hL?@iNy=d+&fKgE5reMz+lS+J-(q4?}HQG!yx)M8^c zFpF9i3~ASP9<2gJi$md~JFFgAA>fmPMAOs7Bq7j3{4n(T_G(T$UQp+$G{`xM4;QuN zb>%Mi1h$>m_Z;t_zYT@yhqaNB_^1GxYNFGzkgwrH6dK*WioV6}86kvw2QbDA#Iybh zI$kafHnD5g69i)5bJn_Fm|h%``^K{ZlP!9V)PnL%=>PJOb}43fU1WJ7Yp#9EPSXSk zQu@8QZQfQ-lw=MvS5w82HtGr&_5@{EjXFtq89q&oNU7&Dv?_FP@F-EsoKpv=C^XNu z;ZMxni4RC8jpY=_q0Bs91Z%;n>GOT=B-6vI839avu1T*FaFD+xMbpeQRm?c|Xo zzmat|ld8c0Ax|SXd6iVaf-k0>@&`Z-`nMt{k1R{NdPPVP3YXXFADn+;YhW!RSsi}q zBpZqf8IVSREY*90N_^KSHAy92D|HWNbEiTw5tqkYFI&)N5FZ{6xz7 zPgY*`E}LcW96Y_8Hf;#Qo3hUr5p!D3Zg2;DQXk+YYe5L%8mE}QyZHmXw-kj(ke(ZL z3gKoZ$Idy~(i%OrOhgkJ6(4_V(=Qtud<=w`>(^|Q!$7$jq_jr-sO&WfnIKBri z>kv8-?ehX#XJ8^_29_WJo%*9Xc0r=baGA`1dQ&Cvh{yYLz>P4)Q%z{qUCegIx~$oD z@{r@Lip@}FFTky$hGrMu9D&4v14B?CQX|jV@C5yol0dP1na*B`qkw3VTeWeSC-n{e z@1-j{@W^Eo>6>K#=O@h?ArM|twdvK;tDQl)nqYKvs2gxt8n=6vIL6cQz!z?UEf=;0 zhA}BH|4!z)pb+bhf?k%Ac~Jw3LgFa}?I(UGysaowHT9XuKObsN(wwP`M^4)mPQM`sv6!T2$VYPY`o2i?A%4EV zgEGLFg-~4gtc+Z;n|sa6Q$WdH-Z7<-q~HBr6S6w?XuCU0Pcp(A zgq9%BD@~xAuT)+*2d*LeGZ+7c!M{7M{bx!1i|#5)W(2KQ#}DeRWT#ptsSZmc)e~3E z{N}CK?Q2mfLbd4XW@fW;VIWB{;S)-sIe>S!iKm3s3UzN{axHx&%XHB%OQbkqOR!+c zvK@&PvuQ-~XsDqhLiup!$WT26`ZhR~PxTlAmG``scBa+w`D9UIkhy zP2p*ynsp~p@+EcP+6sDK^;>qz7)0>+{MpI}416-lmVvLLA$P(Yu6y zTf}$Ko&gSiqacq2>2jU(bsU^neY)t%n3$1NUN@*A-XX;J%geu^8isx!0^8&qRGa5` z?MF02C`Rd0xt>>sW8Y_aPSWx^PIiE^+4SBR5;@*GWPoNS=t(i7OHZ$}god;FO>eH1 zJ{!HUFDGM)`jJq;796PKLjC<0B7LcB&;V!pc~RXkGWfO#H38g-jpqJL9MTZs+ODOy z=z9lL*UI@4h(PsqhfYGd304a5Z@egZMgNrmWyiFxC(bDjYG5yzBKOlUEWbCAmcL@S zD{};Xks&c02d8FryXC(PBlgzK9dycK%KoONuO?U%P7`KPX+(gpa}4h&ov2Z@@)b$- z;?}K_{<>#nBAD{)smY9Afk0{eG^J*KUH zg*$@?L=f0+#>C>v50ukQG&F*LXmtB#-;SlDk5&q~s7W3=cX>gli+C@-G%K7nULBZS zy4CEL{boP;ul+WEokuw2v$lAKFHT4V-6!9zu z2$X%>zU7P4T4ZWV-T1)c!SXlAEA2=E?Mz=$Ii zz=Xc2rb{fNr z7c=@AI^R@90yK`q^CU%!`=}J-xQa1x{SIqaKM{%RzbCi<|Nr$eO}%aUc{;i0u}P2t z2G5P=*r_$Tc?<;ozQcgTAKiYd3tx*8H;S!RVAvYUN=AGhun9PCjMet+3N}_A zL-K9eww$%w%#;ffh!#`gHc<^AJcBF3)vG&Vt~fR`x{(#CC8vsmpFq^g86qkwow9_R zO_cyZ83?yAMwz-Kv zk9ma|TVex2e(*i|zWT1qw}um$RU(I6xgM>=DPCG<~U57{FkiEAa!Fq zUYjLAe2~tFFvU7B=oXUm#l`a8y%2M{@^1SaG4MEK1vt#ETc}6l@G-_6F9R09Y;vCy z>%F%H8_p*NryV2w5B$1b9}SMT==gR{QIW~41M!*h0eNCJMgB-Fill z4-obp2i#ebgtICCany}x#4=t2tZTAXV@s_AW5&it5ut7$PWOfTg5)sL2nWcG&8h~; zkmZVxM6zrohKFT`|2?F*ka{)y$;$5i#MVcG2uiOR-;wRI8YuG@ar9-1mpl#X5FDEF zq;meFfCQhJfQ;idv&6s!8cH>>xKG9PwOb5Ww25m8L5{t>6Y=Vh*gT1hAr*u1wdwA2u&;KImb znQfOX1-IxLkQ-Y4jIhfqWWg~y4dHoJ#G>79QiI)mWV>-kKPpNGFn3B1RxKF@N`q`8}l|mDs z^JfACTi+OtkjDe`)mE4={0~b_&DJD|&JlKo zqwWXxSFfMI_v-+zPMMO1t@Hd^2jGh&MI2qB9k=5bw2Nyx>EZ*$T#$2{bag~0#PIjf zgyBYxqu?jB+}ex5NT%GSkvf`Ozy0naO7L-#1>%)nOYV6XNbw#Se9S(xgbCI7ojpP` zn;7J>%KT%BUZ+4a|EODiD|^7VQ>lLkn5rYi z_i$ft3TE{6HKZ<6WO7%w+)Gs87bKwBP3M)wF&bf8@!hNukac!irSdsj;*HJ^=>)+& z;su2{cSOPB?(-@*=@Do((GQE{%yA1F&z^={Pny11>GS$zttfwVQUX_Dy2iiiPS1 zOuwNWhx2>lFw36`3y{@d8F4$2rR=tamWciJm%ltpTYxAGma%$f#=9Bm*L4s_v&=57hO zl%L6{dFiu({%j~OWNpG*_70t342H|Zb*1jHoD+cNfGi#4x`aUC5M8SsK5pzO0WMN_ z@XcpbcUGe8Upk6Ety;tv^H12ufo=8C*tkE=f{A z!O@Z5))}vgx1D4vhYM|~Id-O$30~qf#I(4!7c?L@0)6KPl>jRJdxm)AAqZ!vglsBx z#_41WP@Q*vmVC7q0ka1l+RQGG*XJA)BK1BbU$dE+-NQP&en8v_%%ghZHR>5MuXWF{C7e6j&g&I}UHTGNl4qdR-2dOFu z4yEb?vWl9iBGfVdZ}^HAdRZ9+z=oNsz-J=|N#X*q=8~$#+faXXs@|%h+8_VSA7}d= zJ=;Md@GSe9sYGlIN#+Jeyvsr!QUOrUu5fo2g~JYIl@v#?!~|dvRB3KB6M!NqKRQ8q zb{Qv?hAlSjZT+&s_+01;6d-9dw_38l@+(R%|Kf&K*|np{`N$ey|Ngje1}$*N>~_=B zy^fDR@V`BK_}`h8KaZ@Cpz?A@^my4K7F{3)lAM?p!v%USF=0=fB1dJeeMj>x&I|?t z%hzQHd&$-(mz)ug-=ZbQkfN9g3142 zqlbvMAkOm^AvX2veS%%`zr%fSFT@++$E%Ug)js%r|L4|8@*OA>>VRg5lm&0%eTzLD zu@+pGiZ{SSYO=f&&p)5Jw*~fQ|2|=OY}5Fqqyj02%PNfsy%_!W)T9d(p0xvFxRJv# z|MyazQYCJ+LyPB1B2gT`pCv6{LzQKe7$@?0oBdIR6{>>%#vTV>ubvfJ&+mv_&y4P# z+5!XUwrfCYDaXsMz~R37BW#DCHj{*-{_F`EKlpzWLc7i`N33w6y5jSj-iLYn`g8Xz9ilESJ~&cgu?W<;kLaSeBW3vSg`_xXM+;3uNNo?jDU?Xhc>JaD5HLFA4R&!`q5m4ghfCl4t< zPJPvJX{tJ6lTMzVANdR61?$m^=Kug;_f^-WiGYvF&&~c_=OWfs%S@^*VK7@&ODYVv zv{5>6Yh-TSdvRFg8~Ow@ogt$(;JE;J4`InN)(`Xxe!yIF^o_X|<)LKPmSz;gyxVRD z6fInvbSkFU;ag6d&UJZGKU;=-U~t=^dhunv|8~(;BY|%tSIQjnActSv)m6=B4+7MU zY%49pC0YnorN*TV9t%x{+Q`Csha{n@T|cnF;o?cd^L7NwIFG@YY`56jpxN)oe+p*# zy#Wq?H#7XpWYN2$;zG(&`@S^+9b&5XgFQaQEeSv;0F{c0Iub#^3A4 zMzc*%pbgaCAWM9sv1~{_wp2VBd{db^^9SwTGH3Ur|Y#9`&h;xO;qwn$*w-s zRhXHg)Wk|&U%RnixkRaNDR*T4KG}MPm)&!|xT$a{PO=X(LjP_PNQZ-75(T7n8l6k+ z5EAJ1eqLhF)viP7qX@^)9th5;kl}aBlC+5LAnQ_%?N~_0`z1&npP_lDQ7nd}Z5(iOrtgyg`-sNmci9&UZMuv z^s3P-M6@^4=1+~iwt|*TXf*~B`oPqj;^0$IWBnDkH5%w4UDxJ~*YqQ37*OJl^>H9jI)Y8RY+ya+=NIbSifVf* zQaiLHfW@L&4fo)=FL(Lkgr|@$L@pLKJ1he|^?z?{kZP-DTDj58-;OGlO;0yi%)QGU% zYwhs!^e;%r>s%0s=!ZE_S-b61JgnG#GuR0v0rX=9Mo|D@ztjcw*B}|K2k!5<1H&5@rvk#ncMhgbKLtpwXI(U0dFOUPpXs# z8&J)CQ}}8xBV12i8aGBgeQB2(XBWR9D2IWdc)qQZa!!BJVV?TYqNQ^#hJnMrn6RQ9)p)g z2o$lv=YdK>9D=}u)%_MJRHC|V3pXJ(H7AT!%e)^2mZbv4@&ek9^T;#;g>}5s|2sZ1 z?DAl7W~C5PMbuve{&t?LPpL8)5GH6|zoX*VKt?GrtVyrbt;@ka0+(A@KG>kBamw`9 zfr2Xf4_yG;F`a?bRQ`?k+2~HH!~J2j5aD<2-Bo|6ZCO3Chv;P3k^jvT;9pP8C&!5O zjuVP5Y85!jk6#*b5R}^LtG5MHl9KK%bmoks$_STa9%55?TfO^eJ!<=n{~0PSsshyz zEla2IRLipg812pXzOr|gv-i1kvz#v!r!F9BR^FZ0FWw`ZuU|j@&+{&ZkagM9xlu$_ zdpc9iT9C>%{)i@)Q&wx`--exE_YpWGa=}1nzlUseUj^Ek5EG(`D4^!i9~Ncn6qP+? zL2(&Od$Pv0gRcR0OvDx+v=Mv$>mb$v))>|wR06ofuZcHytN5@{Bc0K$JLm71i~hGI zm4ARk>v`Vu9HrY6gU3CbL@xxLWs#0>g0pyiRP1;l3t!&`Zii^RI0i0l#xy95;*jza ztS{Wc!99pANh$(fE*=WHMWq3h_W^wgu?miY&NHfbIq^S@$A>9b)RdLWA&V6I6?c@4 zqbTHj*ti6vQX^@g#`_&68_@BZRtzFPIWFXGqjT-N0-WbY#oW&@hi+grFq{}Cc_)Ym zjkv~iVTJ{yEH=5+CN%!c{{6A_ga%#kt*VZ+Z3w3lHK-?V8vxHluLx1f!(BXnv9pi8(!F&1kp`}@1@ro!g@1lkM9(gEmhz0Xs*`}3>`JsaRrKxJA# zHpNnpbiAnlV-k0cUhE3GN;pj(R@wfr zh2Yrm1jYRZ-v0X**B1;2u^0N3m*XCj^hoaG5x)jUQ43H4TX?6A1y}Ha;v^rx6CBEI z7up#s&_2sm`h%^Z^!VrTce#`O`&-8lkJ^NXh`cz zU)gWwFBswc}`r3k1ha@Ze39tu_aNWUz@*1fUy--}qKoiH|cVbSD^wR>DdWm_1%~j)EPJleo z86S_YMl}S4%Bl`oF~|)7ta|P?x0G#>afS~O=fn*s8D`>KeiM1}nYN~d#_!?67BD|y zwirZ(c>9>wL51HFB%GKPhBeA2nouQWW@W5yJZ=YI@u4f|FwJ`5Zv;A1jvjSK$u|y|=Je(D28v%M2xrj*Wq^SC z2*GdI=3B9=<;<$G>p5mjG`)cUML@d0%hTqdK7T!8^a*}Jc!5Ypg+{gK01Wmw(upKK$aSDoK8J1FR?;4vKO!5|`Q z;fQn}{)K9%_h(#oPbm{TtnJVp&B zl`th>__uVpH?f=-C3?#U?j>fIpZ}Gy6BaVPY;>U%Tg8c&dgIwDeoB({?L|7|-aF^p zuZ4lM=s?#|;Mrui%3E5%g4P}OnErn5rhn8< zGUyJ{X;ziM2fDj%oM%e#&7(iK-65vwLLDA5_poF{N*`iuI}&lox}&F;56FAI+}X!4 zjv|KBu);Y|wWp_0Nz4vT{->9ModwIpDqYnu7omhD=P=qAL4ig`a_*BVp^&YDi+-)= z_^_w2Vvq4{UD-fW=ZlY{X%xMQc#|bPc!c}$reTsH(#HGN(iF@C`axrb7)N#AENTdP zfIprGB|rc9nKQ2GA2i=zu;zG2*S&SWHRj2BKvtd@kL2E`Ze8tX8~n_V=GGY zyvzzyLhk=wK`2LrU3Zgg_v7`!Ut9wCDWSW?E7SI7isb1I5oo2KJos=(f!IoaVq5~) z4}*7=t<4d+!Q|>KA6Luo?#OHo8xTv5%ks?@uj5vfZ@S6=ZvL}P@KF6{c`ey8%LOl0 zWCoi-y>fvBi! zPW~qKE%=?vW;i6*l^e9~Q7(-tCcfI;RN|$)f$lP|RRpIXzO5Uan*gLw%sc{jc34xM z(&cTbH}l1i`Sy=h+Mj*Q@O*%GomvL4!f+i<3j|sxD0;9#-BGU68jDcj8zZ6@O?}< z6fhWsrn(+Ph>?YGH>L5uvLD7<34)l}P){=EJ`1}Jt}nvFNl+$p_;Y*x(?V3?D5AsO z=1J895>)<<2XKqycjI90y=F9pktAX>vBXI5p2k8j>yj>>?EuGX^t!pFWlYoK#BXVs z{a1+Xmg>r6-r}?nY6zV+eX>7IMwVrcBXv?*Q*r~m(!8Cdp>!D2>N!>6`eCjiXm;Q@ zKe~yigP&MTlw!(HJ~jKTd!cZA$aTOtJ*tTRvHm+XbBc3jziLWa>dr|m*t!|CcuS6!_-?{{8(3hW5_?Dxjz3O%w8Te3xPZ;{=XY?gWLiyUrgkN3dmng&Jz=>w6Iy zl@f-+``U%sAzrn0GliE&m}yOq?P0n^2rRkEksEORqxztdSk+ujJ!5%itw}DMTNbii za_2j^Z23&1W`}!5FDebJ>ZU$;?|y)_&zQW$;|}tvz7Q|;GPV|$io|>XQHXBj@;HPA{1J38=)*2;^xGtouX%82Z5e( zMY29U?aGM4ED>EEW5fhA2rNwE;Y*J6LLfGW{;udPAq=)3F@_G%_2i*VoKAUABYRtwH|SKpz%)8>-@xQ00F+*}1+lJzH8q z2XMt47BnkA1w|tX)8SD%{{P_hFPdWe(uD(D_Iv@z>-mjF>|`I8sjBc_Wm)g+WA?`m z%8)!*YjMA8k)HP~miVAAbd7Z^O)%s2DDf_yhcgiQ!Kvc#OV0QKy2ib61X)(qEHSm4G z&M1y&VM=szQ#lz@@LZgD>3<=p@)xuSP^o5lo2cZdYgH5Zu9c2kHOfk=9qV?2KnkzrVYv(+B;XTu-l+JOaZO-E?hD zl1NB+InUVN8bI4&xdM>`)+^P&?^39f8OlPtwC#wT9lxxOkyw!Kc!*x_lm}a~MMJR+ zxjvuhS40zT36%b_mR;NO7HE#o=zdX0YJdv6o28By5o{yo1&;sLkuKk0mX?p^K7^2K zg}**>R^Oq*REd}G5)7U^YZlR`NKA6%g4Y%qc4u`jdPIx3j)dX&>f~Ly0y?RJ9vV23 zbKn)*V4mLV0%OLkfSS`=I`J5%+!x=-k(S@(Cuy&V2$PKIzGNHOCW);bSTau=+%9T8 zyoD;~1|=H>&E=M)9%k>BhMa?3`TdasDnPCT{xD-@}h3xGRp2F%?A zus>a$!94}D0Mr~90EW;^kaCJ8uayY675n6BdE9W5`UV#ifVYV&8jY~e_UcT>r$YM5-n}eqa= zrvmUVUATGIF@ zZ}~1oogRV8O>r$7-p+FiP+~du34&{^k2LR&QmjE*`UgXqP_)R4Ek|0vt2o)%&$t#% zg>C}m>XWao9bZbIX9i@D8dv#EQ0mkun%H;lM|G9CcaK7mVYsK??>{(!Qp1s zPaMwDn?7mw7K_V-r6^_Hm;C0kfw&FT^8ee7?dQ zMKwL4r|d_7rio;n2pdCA#*B9IOn;8P8(sW&@Yp<-3P}$41r4)A$BzW-^?sY7cXywU zZ>TW`pcBk3qb|jTqodCrjv+EEwZhirVqCTK1Bd4dI~DbiPgCmxn6GbZvq$~se%Daf z8gC<+O1+BUQ7{jz9CTD3{Ju*{6_Q`Y3Dx%L4%PGdiRIm;lkS?14ax&^|C#73*kNPO z>>-6aM#e@qsRx(mN&42QoJ+rbHsy2^94x|#$Oc;E-sCW*n22cP0+_RY#>cXBgt^bvrcoHqdZY~M{!~EAF5S$uq z)?1eLV-v^~(YzQfXQCD%g)I6>t26msTD7t%eMKfYx@@hPtY#rT&l_9`l9-AZvzGc~ z#{#Stt>z@f{c?}IYDPP>hy(1^S)Ic-3x#-T$5}$0MQi1^cxIMMP6H+vq1RMyL75Gz zfdW9ACW}oQFLegWzSCPg!YpR7!#`v1Bakdmq0E35I@UdM6qmo7I1$e&xif%UPm-6k z;W2W~w73lB%xDR=8sP63|HySmcEtr9ND(da&>m`65<{!E^!Klp1pJO?Z%IrVOm(9A3|DbA2sP_%Q{IanWxjNSl9C0u)?x2Hm0!Lyu1v8i6~Z%&uT4L zI-Bzkic)Uwd8^|$rQOF(yh#zq@8HNc`(iP%1k^@tj+!;yHWCBEd28+-H#&YFHmg(W zF`=gEgDT;2;z475Y^|{|;XV3im^@Fbjad@BmP3WvLVX#fkQUYfFxz&sq#q{iTqh;4 z)7=>jHav&mMu=)a{hzNt=c0d;VzpMHf-#Ufz*?AFOY|&F?=8`&Av9tW2f|rxq2hGqyx-=a z_dKVC@fJ;}LeqxYvn?`2`!sK<_H4Yp2Y+XTGYoZdLX0gJu$O^^)t0?rK6Uyr zcS%c9^*Jqt4LxW8JWFFR6PNPV%wvAq<0Y$vh`sO^&y!6z76N1V2?v( zt7w}od#VKq1|kv(Mo(wi8vPb1!N;1oc^k4q{;}q2Y_oBuopRG#-Gj#NAt~RmN2Z zJ?62SFXeLJ=V-fuM5&wKi3J1!m6+Xhs& zf^}9mYt>ZU!mK^*zEJW6a_wx9kdCG=3;{H<0?9DM8nGq7T8+(Zgs_r^lLBU3fd)>s za;5QUG%n)zQMw^Cs;BCFvS6fl@WA9-0l7r)MshOq&Fq_sbz!}+CWat$klLPyhb!dh z$_r}vHLgmFTwSqf!P^IK zwEgwJO#i!^<3M!sDpsNL!>ETB4oSuWdk2y;1Ok`uB(d>Vlq&OzYu32d3&>0_$SQ2p z%%bTx_^xVw%HX0CVDk$Oqs=Z6g*4^>;4~lRv>zfwg$*}s>2euWUQ@XpHflMBfg78R z+USI8`)7X>XDt=oi{?oO6&PbS6OsgZAe#Q~!%E{;8^%8zA45KTx4Z)!D()`I1B#Un zA3oTBo)<0#yB)hQ<};LrCJsTcNw~ZK0LStfkr|DTTLvkPL)QijJ^u&SNwkR12hH7wf-2JzT=rUN zQDDRihUyHQ4b^fuL;&suB^#`2F!y`~P1@Mc&1b;DveY-}EZ0BM0+}J*!CHCV%9lDr z%L9OF#r-YV7bQ>Nwy0|0-Ijw3EtDJTnda7N#Z!-eiZ?QUZ8Z}BiTuWiik|i#WcA>o z-tT|uNR~JV;JrU7Ld?twnUg*@Z5~DjrZ5Lg7m5+ns7$V6>wR^FCb0D5od)>{YJx!o zD76l8Ccmjd7O;*(THvXMd6^&DhX7^fM~))oaVJ!-$ZD*Tz+~e(jcU*S?sxGU!WTrn3+Wu%Wrx_fl;4 zfb4ZPMKID5%; ziW^(d(p58f0y@?kwFaJABh+Ku^vuCmnb)uvZ(U_ctF_CmP=GNPR?zro5*`czHZuGGor)81jnL}dzQxF>J8wL$ZMN7KAG0AnZcwQa>7 z+8TI}ym0U42p?TD@Og6>X2Cj`Y^OX4kKdQ^8IX3uTO*GjlVi9JrdQGV#I->u9u6aG(m+AF7Ioa~!}GH&b`%t`RbgqnloWF^mJ_-VUn*E$Q!zFrH} z1k_#g3itTN*2_=i)ps@hk;3we&TI;?yfMuuZmQF;rwYVeCvk(&3Wc$ z7(nH9=A?asRRE5urZTvq0MJD-WCj<}$;6qH{q*~N7R=@=Lrws&zm);7kUjmjTKdql+41*M=0|hy)@|uqE2#6c zZ(6U8Ii@Rr4dUdNq2cv#Bt8vcJO7$FEAqc>nyDl#IF=CU22~DXPm9!^WP`ZePUF~d zHyW{Ya$u$<`hU=^#J4UsBoKKkp$=x)#dT;*~@`K$$$C z&=ou+P&nPtUT|f&`a2aIP`B88>y#D79L;Euqt_ijaKu8KDIfCyC{Trd6i z4F{Ob9>n?)CAE3tE*OS3% zt#CGy5CoANrbrE7*C6Qm?TVOveZ@DJ4N>TOupA7Yy;L)(p|~{31*_l0BI(2zdis8c zicwS91pQEG(xAM*X4Bd%Vo{fV;W@17Oh5~5bxyxPPL%BkfvFc`4Cmam*;1_C03n9NLNJ1=-XF;s*w zoTD$K1f(B}@n&;&M5zH3F=UGsWR%R?ZAGZj*<+#hwitxggi@#C*+y`~_+nZr0pkRd zUqZV@I{D#lgAy2iPvm#Z;3WZL0VU^AMoUnj0dK-Ez<(;HrX~lb^*>Zgzf{fSTXP^F zn{x7yM<;Ki)WdU*QBSumTIZ4W&ZfdNsu6!r6QT2Ej8)zq?g-t9#lrgheM(WgyRf-y z3Du~ulG!_i4K$KEAl>O4bq(G&&;TcSD;-6)R#P%xU8mfX#JeT}UgppSYwO>vHKAZ4+FXmOAVIV}~^02WZJdkymkmOmMTw4T&o0ew&S$q&z0?^E2Qq%f}*!JJ(F9(Ih8-64ARWz342`qA4q zQ2i;(jg{I|IOx?pX{%4lABj$%7=tN>dlBav7_uP%{u3%1>MppYbo*DNh_$ zUW4wlHkyG+8f|Ij7F`XFMtOkp^P=}Gt?e`Fq*;JIs8QCH>WvYdu zjdi(9&f<$`6V{nGfKOgclI2T(p)r( z^fv)W}C~-cG^db!oqE^>>?r>B7|idbZq&+BJ>UUe&xu4?s(<{daegV z35Dg*kfk~U66xRNh>kT(##V5X#kIA6p(~MJSnGIfK~;V2_7Lg_xjSL4ND10yRLm`H z@u4||xlM|iWqGBKETlhs%kqA6Q_zCr*M z(Qu`rsUQSukOTREaiDGg=JKE8kKtPvWd0}Y#hbVCUWK4CD@-8|vXdw$1{wS0S+wcp zJAP#QKIEflV@Waovdi6VMm08m3$|?KxjgPmI_17;$z!TlTN@Lg5h6Nx0l4}B=#q8n499;UYZP75*FaLu(e1#t{QQ%t zU11}lWb!F4V0&i4gG1C=sc24y1n<06R0!#9767Bq9J>g~noyWZx4(Q~R`-alOz+6wE}Qap?;{N6f(RK3 z_p_AvkyM)deID%kKpLwX+kAhviX>#LkV)S(GdY|A0p>0p94Ngc?~qFUJr_CU0}hR` ze-U?SHd9V~b-$le5Lr!-+d(tyTnsfeA`Z?vx42Jaj{ak&Hn-W_C6x+y zw=r?O+u&^oZR|Is{Z?Je>#ccpOthOzmu(`bpr~z>(8v=wpiiD$!=YWsbYi~9^)Z}t>{ES4 z4E?w=aRIp>dQ>X~$YgZeM&!b!?2h>Yy)Jd{b+Z1*j%*1lM6S__<=rREN1x@3a)PZnYzCh|jd=EnImw6}6$4UqQaw~@`)4y7b1KJgF_#ahT$za;s5UY`x(Q^Gerd*!hDZ1= zbRbg%x6D6SVXLd>aJy$5@>ut`8Aa)176U{#n(hgNy)V|ewUk1ohpLIlwOhOxNIHDj z`0qC#k?{xIZPtS%=No6>Mp0YL{Jqg;Eep45n*xH^nKGer$Nv1Jf7tRg1JCV7c)Crx zS*UP8izZ=@%^A;BOc`qGpsx`|IfAyP(?6!L_x~QfDEq!J0{>9i5nRB?`4KNASC?E! z!Ym~%SDapWCZf^*m%t)*MR)HpZHnt1Ut&J*iyo~GPj`NT?NPA#o99);iZP>3c1eTI z3&6AkFYPihY}X+1Lp#AW8tnFQOX>v-$|O7>p2PN+9fA; z6BX0NY-&8oAh4QhcyJ$WDV+YTiN9(lkDu=pS|l8d7_w0;-hX-JHl{Ts+c z@IRu)?^975pI9>cFSX z(1!8K8X@Pv;kz!D9av$-P+h$DCpD*-1$8-k-A&f%@3B^+Qd-0Y%E?95R5o)=)7%%9 zoP<@^ML_>QW;w1OfQQ)a2zzxN_Bsaeuj@<*S7jTLV?3}8{#!(_W@G{5^Ry2T@{Ykd z2yq`P*@IRU8#UTuB=jQngIcJ3S2+q8eu`Mex3<^+>GllC1)*?k)ItLU9nVZKbFY9l zh7cwExYB7b^qzu#mq4RF?sM?11#|+rfvD6AgZ|5Fd6O|ssL^8}+^to>bgyZD%udyn zN16dV=7y~*Yd?sm+G#-lZE)l}Z7))FQ<1z%zeu8O|733@6lH7;n&~ zD=1tM&A0r?TY$6dYd&_yX7K?2>W`$4Nv~IR_nGdhbA0d}KbB@J$`BikyR26RNkbma z&d%UsvzyG;()n>$l%XXXhu{$+D$&QYB&y?KRzraq`vQ?}`8ad)J#P4~XMrhaE(y$8 ztpr@+eNMpnMaK8sM$XC~5Hl{Usf~1|Nvo<{U`je09v1+U3%ZXObe}3aY29Pf5foC% zZvpw5K(0}Rrxo;xLF!oKp_^T&Lt`^t|O*A%>Q+$2R#AP75XHLK6MCyMim0zpS=sBf(Hl+`fgrYad%y4)HTr z*pqgy)^`b*9zttLf1XJe3jS9Mc8tH_O7F=Z|F*;xm6GxEGDfs!TTCkuD`J~~66Mot z*L9Hj%|cuLr(3o7R@IJFqI~7BEC2JPWCjLlz0ITch0+7D!`u)$wc^h~Z75cL>r-S; zopxyhK`TS^zW0;y-k0`x0CrpmeZfcAWayDaQKeLsC(+gQF`_AgN$&HpG4EpRDXuBP zC(aZe*JWeRtox*WV>JO|%rbL9WcxGE8U|mfUpqXHT;^A52+QsFCVk6DfqTBDclGVW zrX%EB1#(tXg72s_nKIlE1Ro?}%Z5?$1PU2aGFEJs0)fJ{Mnv3=N)V}Gb^eJKp)6Mb z7gFh71(%puTAM}`XpIcFbmgC5v?_<&jfuukE_zvjqrWIi-q0!LHMN?}n`&FH}oI*b^ zksEe2BRWD&2JPG#^Kj6|rTJ(9TuQfVb$+L-GSm_XZLb1L(jl@L*{`*m2NHFybl>S( zGxTcRWov`NtE=Rx=c75VVVx{j*2SCg@}UMQ)d!V^p0*~In#ZM5jMampUgg*oN#FJu z4PT}b>oGAE*rR1BW2bb;kEGID-a8KuoT^yi2{f;lY5n`*_l>f>It339@bL6bRcsNP zg3LqvPty#qM2-6d5MB?b7d4dehTbUP+}qntxiFt<0JW`K^Us`(yqTTVkxiS-41v4lLCC|4GKuG5r6L-Q;^^Ehos^x?`D$Qapkx-A28u zVOkoq6Z*6lQsJO*e({_2VD1(!w{#vk!^zbJ(S6S#Z0_|>A0(*{h0)t8)|@~n|JT>d z%SM_C{m!#=K;iX_%TH9tN7Gu9r0uWG-d%qZ1*n|gsS=?$Fxroz=-fzjCF~zZl7`Tl zcuhEf@AMttSmoP}2MNg@>^`Bt@4jfO$R*0(^{cuE)Bhg)gaJBLxj6XD`tiWfZ>QE$ z06So@)jk100_Fd{#EG;zwHb$mJ=HLtJ^e9H-L#UBqSu#Cs3~GVyR!;jUkd)WuAeFA zi|foegp9qD`N>3P4q{>?f_;c4z=xHe)9aYArrRUBN8M?steg)djipdy5|lJJ`sQ6^ z_)|02`>Fq_-$bqy3*6y>#Z%1|wwQm09uekc`#wLYBn94tW4UMc=cefxtndGl7*;pQ zQ2BI?tM+^acL@7hX5Mu#Q2ny~3Sf|Bxcx}ckC2|Qg%OS?D^w}nQgKc~wJl*+pr7yP zZT(jvVa3o2W2IA zr5e~p2x2KuoLn5RME8uexW|0p9M#~*DgE1ELXk8{tXXwIo8Yb~Wxz%o%F}(jF;#9} z#_=G!1`NLEeki@DiCDS?^YH7@h8YKuw88%Q9N+ z7Z^FZ`{{_-IKQnjRf7-H)(&(f>jfP+pj^l%jXHS<-{K*K3zv0xW`;Z58|!EE1$ob- z%Q@A`nEN`dA@yZ!vP_)X9mc$(CF&1f_V7E)jI|ReENhD^psz}pI!Q6yec%Vm?u=S4 ztN8y8XIUGG^Rta1E&Pzn5ut!g5e_=Tf2!;1HObAk^0hv z>xpc!{zm5k$uaSDXbraH9HzPUIqfQM(?!MGXyW@!g0<sy;mfiO~S3+(|>1FbT zDwHGa^4xql+1igdd1c%RnI~I!^^>=6&c}c#E2o%(VcgbFW?Of@IAKrMCFBD0nEYj% zeag?uP5okG3DbgLDW~8F|4664qZup^d9?#+BbU$LV6r`NI4Tq#iv86pWJ{C-QVHUy zD-IYOZ!8RE#6uGldnOY#OFWLyhN&}ki^m&ZPXZ)RPBIBh58-CT8!j&VcNAn|Mq+e6 z6Bk4P()3!=?%qp+_={n&Rcb|TYDuu76o>Y%4^t~1nqt0V!aR#?srZXNbGQ-XxDJn8 z+Kn7!wtE!wxEEMs)c88G|6!d(U;qA%r~@4boF;a$^q!U<+8`%`faUA!=#`z{-Lb@^CwPB411&a!9ik(j_sxp<|`0V*#fQK1hq`w z@TEN(nq^_{i1O_XA^!ZBl5@y_6hmt&bVOn$O4eIpTZp$j` zZT9P0$BXw=R5)HFXRvgk+W4po5C%-i?#~RrL*?(IW5F4II3E}UH**)UIPWL^NhgbY z_J8@QtwSp}{7g|6iZDLfw37cbA+HgTq2E9+-SeE;ABboU%IM5;;HYj%6i;Ay) z2UeQzkDoic9Xk77&w?ZaD*>1MjHs22q4+c)nI*Vq-{QWGzb~jKjc*3%zDS46$N{Dh zW4s{DJvt(rU6c!CfX+T)T^UT`8st`WHZTHmhZ?=_t^{E&NjZHLIcEqANMo-*r9l5( zc$Nn`=)Nr~s#MB;L@{-n1CZy%xO`@5w=tyM8^Ju*E2g^XNF^I8Rh&hdD%LzlCT_4= z_N-^`T;=War3d*eN?BctetFRi*P;I5_SK?~ybeec#+6$bKSYe(>u8`xEAiK*P6X7Q z6DoM^Up0m*oM&AkyVrYIs-dT|fF>LI2fSZiTeIP0n$kyFF%})>eWYI$3nwFa16c+O zz&OIU>1q%~u>jkY!hAm$&fJgv**hDc&tf2E#UnaSYPr=GlaL_A-reD1S57d+y@IS;|>HIL^ocuj5hde^W{M?vVg97YO#tH{uM-^ma zv&rhE3XGsv@Bzm6l@XUg2tEyVW<;u~PPBkRP}}>H zfso}t*-{*0M2!=K*~cp~X`1pPp_l;u5{{Wf*%UAWW+rI1{H7LJCfbe+s5=r1EJcJ^ zN#Exj89Pe2Hw^E4rE|W!5}k^}1A{cGUu$0^2>%u=99qeoEP(BNIZDCAo`31(v?)b~ zD!M;$8YUR&7Yxg(H*@s4?UU}N??Q>1^on5U#RTV9DZ9Pi~o9ErTO1!LvOXu>w*4H=C6HK zsSd?V&B2uKLMJi*`^P2dR!b%^hTxx<;VK`I_O4c*LP5|S^}pXBf&1B;FyoWf+Mk4^ zr+1O1bl(yjIVGn@?mnlgCdd$UPB76t+)Fl~?;F_08EuuVg{8<9HXAb^XX3U=LP9m| z-2CR%D_S79-e>m92%%3CO5lM&n-)LKc5%65Sv0e~+jpw<6_(?}qa%20Xt^a{E8jJJ z>f!6Wyr7T(9OEkWm)zfAqaP@BptjCcxdZi_1V9AA_SOq{yG^5qcQL#PaJV0guiwDi z3-XIws4E1)x_qJ!p=bVB)~LiCeAxK;)KL|BfmO9siSP)rNbp^sw_>K*%Xgc5&H@Ym zJjC+*zXR@B4B!h@ZAex`>0CC1$yI(CP@laHSzQ{9pCRFhO&#QT<4)&?b^&=eNsCv7 z9;V^F^)K^60VYt_FJ)iJ8>_m8_Qg!GcP{xRhbB%4m1gq$%%md@9A}pl>KVBIveBEb zRYjzpFFs4t$d#A<^2`*PQl~aqVf_KgGxbG@7t)Po(vy6l^912|4&l7S@;A6ZYM(JQ zx%hwY%b?`n!qYA~BfFHYCMciS?hCb)oBxmkwIq@)!$PK?@tp3es^*0VCP8jNM;}ex z93>z1*W>jcyfXP%V43;5`!*ZwES21Oqx_Go?l>=^E9Wv{G%by>_FCY3;I8d?c6Xm5jnTF-lqc{1BFsz-2RK66P&jUe18%-w`)w+0B#QWs!OGk! zVEiD<%9oT0#^O+XM!1*0>JZE<@C|{W0l0xS`qNT2r~X0y(}=QDj(rnaJ@WAn?a$P~ zMs(SBuNPi#^_|BckD+ooR>+pmT0;{go}h~v0<9MWe7yS_esbZcyGif;@TPrZt1LFD z%X4p?bl1oLkVuIPotG-BfrI#4I)c-%Y8=IFc1lEcvKscxr5#fa(5kT3h$oT~N{x9tL3J7T zIK{9lYn*=UQ_Iziq+AL~Eb34c+&UN&eaxD)!-3+>TTh6v<2hH_{-FnOo6Zs z_f8)CX7n@>e4GPq7-gdNcgvCQF@&j@&jLda7yshts~6>3JGo!DPw}_1x-JFI}pKclaO!oLzDv$nY>i{ErdIZE5V8 zdoEz3M+ugPUU-0}Oe0aOZw$2(OV=slmL00{RU>*xvkos@oBIEgxdpKRUwIojhMuv% zbZGtCR;qY;3pR7Os@*#?jV;_0)Sl&T`5NG^!zZTM!P%i*N7ul4FZ>W8@I5dvn#8RX z5@oO>kR9)ynIMu%n@_l3=y;N1+Np6A2%=#-<-26~ybB`zYuZsIYg!mZBmR>gBE3Qq zD+oMp{m#n}I#Rab|LJp#<1%Mdto(R3{K3`C>L;Vm4e?MnHp3{U<5_4-DzeCHJKI5G&s2h9n zGWnj;YF3h^9&&?Tqvf`R|HmN4bV@eW5Yl3O^A^SlUrZv)%tOf~x%wW@-jP*7=Fk!z zc(P$jGv&qoUyQHapv;pu(2mtK=nDd97or3K&@Q2gpnr9NuHQT!&P_ck8KMwNxCLu! zaW0#aFly1J%Y)Sj&)ZrJfO7vsly7b%4W~{qgbFEjO57E~aKdbOT1{9zU&Gn^wT1U$p*7Chhr|?8U9OaEk5% z``Id;uFPobywjy(i#~~M*HM8;)vA{{^b-sOhSSSm8Th^u0`_gE&Oaq$Nti5_ELt_+ z+pN%WnB$oWo@VQV^~N#j4Y{WfT<5pzg7zHN5rLwzZ=tL0(PJG!6Dr- zj(+cPe?5StWC4CI$EGOZ;QUz*bB*w3Ra#Ed8|^8|^wB6QZquWsBqA#jDsGSRHdIUO zVD?@Mp!{(OoC?#a;0_biMFN`?y1i$6Si86qf>Ygl^(@$_X?&dH*M+xr$Jg9s&XF&F z9@CaqGXKbU!ZX#*NZ(V9yc}#}DMLw;JkJW-kO1Hwj_|K@>hoxxS=i=W%zH8^GeTdq%swvRx?Re2`<6YS@b2; znC>tMN0X|!2cHSmP;W?GqY{Bfl5%lh(A7gt(9A4zs zW8=SHY;I7Ao+09sho6k6GW3(sg$pneQ3)%alVZ#d z4UEfuUf8ZuV^*l@7$hLHX7@g@8}Tl$9ek<)kgIafo8LHT>z|!Y%LA3=$AE_c17!Oa zzeNYmk^-7qcOD~@SENTU6Wgf3CbEFO7Ae$_Kcm1I-N|jbB0orad3I*{Y!Y9ni&L4? zE&q$kiUX>-TTvX^cFM4?|X#X~2ps3!e?E+=naEI!EL_sk3}1g3t#$sV2%lsj>2 z$-00`U&%PrUn2|yx5N}gA24zXd!Bz`ls26+^)t8Ztch}3M&^q%VRMoGG#TrOS8nYT z_?;u`v>;dTj{i-)6ijk)5SzC&T#^@{cjFW{oo4z|Zv#iW81HWU94lS+H|Ij{hV z3iCioHOv$6D<()pI#1HZxkfwr9KW;7IMF})S64>IEn2f&hBmI!I5XrfFM2kj9Rj01 zw);Ot%*BUPcehFoLc`otcA*Q?gfi%{V1|S%<_IcW41*4pa2U1Uy5eNh=ZQyf_AX(<41Pi$@g$Vb^uR6u)j4D zVS(|*fTOgx*Uv+46rsVdqsaR+O|2pctL>JoIhhS*{pmyE z7`o?xq&CrRf4NKIhl50+W}q2C`w-T&plp-v(jCEld84?8k0Ka7mYU{@*Ug{XVu3ni zMzx8H(UJcjT_=)imUHz~+!Z2WDqM4Hgr0{2$HoM#(=)Ze1jj^@XxgO+74MzaXUt3x zSrSO0kKOr>YO>?zhPfAdVbf8B9*^j#{pul2jkl{j`stL_l^ zB@XL1qV(1$qYqNM&(Y^R2bXzAtVm9C>?^2tT!O2_+s6KaY=m@7v)nUt6@VkMVpgL2 zshDKw-;tOuWzp_T&K~q^a|u#^QjE7mSy}Je+6(7h1qQsi+?1 zRb5(yJNxJWv?@R2S;x)>6r`V0EWXmBiZ`ONQy~c9 zfIrP>DSo#+1u}mScT9-oO5X4i0Z}chWK|X1lhYw@SmLS&s*1QeyIB@8L7sCYt>y)M zy?=P63|^u(&{k2 zQ1a^QUNc%*r$fCTn*3v*3TmSy<&fW4m0h9DT6yvW8a8B6k7svD6L`}9VI&A=giZH4 z*SimPeemj#kCBgjZ;93kdtkr>T#UqLXVMTO)W8I|?`h8@?5g2t2iyq1HvhEFDfiq< z-?`kfAQDK+1p2SI9{@({gT99u1@ z?2gmEydZF8HN++xcyyKo3UDCK6WI)q;&kUH+2YUg-OLbS^^H!=mf1`|rcLxEZW&^l zR_z{~rCG3Zr00MHPW)@v^I4S$2b_{(ne7-S9uoi^4DC_9IEM(&o`G3!sq4#1VpG?3 z_sdrxTi^nhasiY8dBoAFqS`>96wX!hh$3h}cjuUZ5>m$KCw^7|3y*s_S5gJ{eT*Q! zMHhxph)}wX;pT@nU-Q}_Hl0AaP2AA-@4A&9jLmn#u(VqWdjek`JXI>t`4Vrh8iK$$ zP&0Usp?li32@RtL5-+P~&~yb!A?QNiN{Wkc=dy~)au{m*r(v;F$y`cvCiSK4wJSI7710036JxjVKnvBl z@ZG};u3c<&N0Z!)(=ssnNY8$-X;S}N_^RY_JrTWQ_%{>%Rd_mK-$5h$1SOFjH@4~AzU<2$-51+K$@*R``m+4u91+IPcN+0G zE9HVOw9VYfncaFO|Bq^xk8tWJj|JNuN|-#=j)Ai*M-@Pn(1&=@h61ws34H@Yrl%vUaLfI066*yS zXv8)G30O0T-cwnHV=Sz5%gu_s44r^knOtW4{NBV2|Cj*xLYF z%_3weqG_1qfv+CBTaiDWV*3K2x4#TRR8u5g-ksu4t{9m{%_-We@mwiBXTwiGX~@># z3r3>!dk+2?J&t+=&IBKuBQu`na}fO3b96S zBKHN0#cFNCG1jvtH>U+nYOA9q6&XrNRqg4Z2v{H01Z?35u4zBchz6K8)dg593mtt^ z#6Of#JAOjT73mAULIlJzxBXfnu4nZ;(#39m%7$)ERgek_Z*rw_P+fBt=R^D2I3EcX#U9(RoW^0R z+LxYGarMmn(9~6@623^}9V$=Gzz#?M?E{lg3BbOJn-8K`Z%7hXaD+QHC^r6*L!_!J zqmdE!yJdYu-f!Yp=KqMUZ2$k`PtJyWk!sbHlUoR=-*FXa1jXy8_eJ{@d8!1KE(s$& zwFrmUw&R=Lm-I;lu^(mETXTF-8hDL0j8FDe=0p2mPs(#3pSA~qtD;^9X9&ns&T z!clc2A$3OQTKQgN-ixDN<_~@k1thh17>bsrFg?{-VX+m+CXYHUqq%6`3~YH*mA}9S z82=YDQ~2iRZ?aAB5NpB@a!eNCsJSv@!Z?qmyar#HlxLl8x1&5IWZ>=y>dW?J!)VJfr*i z#l;j86sFIyremjNK|NYDy^&5v-v5zY3-x{`Jwq!KPwzpvD?Ol|fb1#Mp;@h{Bi&HC zbRL21(CjoIO)U}<975m&R9cF?TUg_oVT3j*30XhHb_=Ke4&fwf?zgoKn+rX?a_ z3>(K(f11O=?F24CAmML3*D)I7T8*#EC_I2;4$Bo0^Mk|_=_%+}prX_Drobpki=^B6 z_@bY@1%L0J{^wEf)ohD0j$ofv5N&91D~Tr@c`SavfZ?{vtM&NSALCu=DFTJ&J^@CN z)vMu9PO7-GQg%6#{0RuZD(Edmee3!z z;_~8`uaP!RhW`MmvT85>;Jm|9xtB(uCls&z;~wj3f!?AF!hr$-_OMYOfL+$lu?M-+ zH0w>LDg&hzG?Qxw8r>Y2Gc$fW0ZXrYl9vlILkP9$UPq@H9S#?o7qTurfQ%)hao^@l zF^1K3rMnI`8_DRcXqHb@sU9pu>;NEgK&CI9@_2~=1n zu}_BNQf15ZGB@bYwWdAQJ&uAz`TtzthtjE2x#V zgrz;|4%a)$^pn^D6u=jJpBX|u2v2zAm{&2+w))Z_Vt>DBTQ_@J9SBsWE6-|7n!4bB_xHl=W2K z%#_-CG2jmjMDSgGQ};TdYB)92)ZF&J+1K0bSR8l4bjwIO9*o1qG6NdZXaD%3Qg`~s zwfa9)jt!G_iJmyCRdly{K6^ajRC417750`g3%l+>c*U}*@QDD5<|SLNp$8tgLk)s! z^p6}=6TDCuJOwSN6a7SmpMtrR9UjYNXgy-hfaG7{C)8Oc;na9eMjh`P9F$LMR|NM_ zq4hnRTNp@E-Kkz?dS&G~IyaR5Uwps>#qD(J21Zq3=9K=n*~R0-I}B;CvoGdmXdPTb zyzey!$-Iki{I_+jeEuX%dygn~P-;nKpA+^!|Mc?9v%f}t7AoZ)eX3>4ryP0YEKgx7 z5pOc&@ZQ|bkM^GabdXwo6yVCe$YfSFDnIa(flS2#Pg!w~b3=O1Ms_&VF9sAtu>{W? zI-@Nqz@!rL7;BuEJIjk_=W_w2Kb-%A(yvtk_&rA*JGFepGAO0Wrk)ojv$!7U zy6MZz6Eylp)GJOVrj;3S3`2?Q^bzUd$|kE+!PVzJk1~a*uez%qnPtQKuFfEZC$K(> zng<<8{$sf-YWiB!F=?;Y)gNZG{aTpU)jCYJXJZw&*pI#z=@Rvfv%m|VtC36#YfnyZ zx#prN?M-6kOAYu;-4@NKIv`_LtS$!fP;$x4|4M&nGh#|c{E~{-n~-9f!_!&cQC2X@ zTbQm^i2viwA#-d4rqvZ?(|jA_-%?+ti)QhcW$@&pG@+m#Z}@3R$jjV?)8d;LB&5k& zFm|`mCnNdkxaLHfni*w7n&?ZU>Y;6xN#$$VE=Ou#R)=MEMXvVgE9}!Pzeucf=e(QlKcypfA2Mr@}k37x*b9 zdVJbiKkI0$!)t_MuxTm15hNUacv_qc#qDG5ghaOLlpI;2h$H9|1$3c~$?{Uxdmk>^i z(-7To3e)>=1dFnT>20}qk{WKIYg6k~<->D5z7EZHU0BdC7utu)><=(0^6wrPsT>rT z(L{2N!8vrpI>k5&kxQ}0_^6pbCt zj|U$nS4O!y)9n@9t(W)soB4eB9E16rLUyAH=Wo5~h{_HQ4*4FyPi($7QlIpYIh!nF z@7_WkFF}bDMhqr2(}W9qH89cEBA>ucHJ#092E7?}Hk4SuKAaSXEk~hc&6`+>?10qf zU9#|I01|hud+<)VHnP7a06+(*Hsy`S>)AGb0wOp)IiH25{+xDjYCsw1^^CqTCJD-@ ze7?fOVt>FQN_|_6Gp1*k|9`lKFvc2I^y1reDftD`;6siN@@_}%@t>T=a339{l-cn{ z+xoxbz}OZQYEe}xn_U}0nRujG+vqwpZ{fP+YTYi?cXPEX_IAw0-=hzEaT?{|KPZmo=Ow8H zdYqM^Be^e+LyXvXqR8~-kNr>xS&R(rX|2L-bYP&ugpI`Qw`E#d#nL7c%?!95hfU-h zS{>t7YCW*88zRRCmZ5RHkOp+Cca0+QdIQc~Wzr}cf7X2@+;j;xyI;K5GkF=8QLPeQ z9Dtu(3A4x3of57On9=mO)(;VVS^Bkp1jLauF6o>XL21ia*-AQ7U(L-t$Plk8hk-jy zwr}YtFP&Uc=M5kJHQakI?!LMkolvXMKmYl!nIL9oCEX5)faLuU6mu7Bs4I?ec0+%> z{_F<(@?1i9Pz}srGN=8)%-J+wB+_pPd?$1xe6(cqSGqYq4Rr_V0!80liy68@V2V3G z6dX3$R<(4VUxiuJ_DPN;SoIm8MrOaiG82WJP;#ZR!6#NC-SU%9*c8O!Wwu4O}=vjaUPg`a);uw6M@`k~; zoWf03@ed>JMTAu>6{h-IOihMNCr5>OnSg=-zq2U-u7q`#(ujyPKvi0$uMu3ijTG_9GOqR?)RRa6|*C_tYGLGOcWh83dkMFL)fAwGTBUw z;0EoXz@`UaT@TXvbvu_)l@AMpq z6!dZ4e9r)~$mv~R4N!5ddi^_XzH~`1mjK-S(9Xa$P-qzme@$Ha{K5bK?g;4YIH*@f zAU05jQWXQZ9#~C>7uF_bK1+-*ek=343^r9|M?=bdpepn>ROsz&JpPvT!GdyT>5jN( z^qK9&f3AEg4?_KYHMGee^*@+#M4D``j&nvGbAyAS{VnO+~CyxHHZsCt3> zv`dRb<%AGw-WbNKxV^{Id9g(~0B+*1Df-=Ncu49fAYS;-mGKq96Go|Fj}~N}0)Tv7 zeL%NhJ(p-P3Pk#Pc`?y{Ns>*@Wb1z`*&60v0cw`=tgXwmf7PsJ3!0&H9Rxr{0KnD$8ewV*z0HD=~ojX2m zjnYzY_Yzm%+5=I)%gvK4Z|K_@JW;fa=Qkn}K1D@IKkyUFcz3Rk@Zx(`9(|-B|G5Cf z)c4sWn(?%b;bcr}YKZ^)4YjIV6pP5Ey1eWQuCsyumnFy01wX_wk*-gjfkyk^Hg~0L z5O_d*#44-j)Zf$cZMAM(4{qc43ubk@^>EnA?p&%VplyzpTzd#*wgu%>Is3J=w4YuZw+F!GWh;n>wZld)9)yITtJXIOoP)a7nKd z!pYk%(ON+&#X!A7Qwbq0&ecj)liG7fggf`z(iCL%WINrUFz=r7h6K>Rc58)EsbSF+ zLwU&GQj)sD?dg-V;7OLTHxETx?Edn1C-Lt_dt%t&z3@JqnZss@%>Ha38(#3n5N*qo zO^4+Ewm(9tqovK%uSe%V@I#7$TB^y-m)Wwv@}vBp-_Sb^KXeGaW+b46&$o`l5#lC z6pk{|Okp+zI3{;DwotlyY)|-;P#PdWrds<*m?mj4O{}(m{hOLm87hE6jw3h2)GGCy z?bWEA6e&?*IZ*ux>T<0V#SUN#G~jnKccTD5|M**f&K28D|NqH?`yWyF|FF4Gv}iZz zVuQqB67P^Bh=1vSu9h|nS^N{vG|^|ENT-y*z!voQeN~E>XNDx6TGM!G*z7BC2S3!` z4?x@x6TQ+k(_-Q|zya~XIAH~(pq16;C_es+BUIUivA$0H*vH$(gdL9 z+oAdiSz!DoyWv%M6?>99ArHW_$jo=`eTbnQQQ`Lwl(EauR(lEexnTybb+kT-+#Uf* zA>z1$B4eJ`aN_EJ=jALTOq?t!=X7Mt8TKuIT4oo32+0$5)`ms%(BpW4(t_d{knnsU zg1=ozSao_1ur>`O002q5A>)if|NY?r6mPads@< zMR}Mm!@M$p`=hnXitbc6?9vHxg{;~c7t({1CpIQq4N&1c!4B_Py<~$h7` z1_#$nJZrJdNWUqLq;AFsxFaOJc0&!zTk`l@gaPMEa2D3{zLOU7BH@UX+eV;3l{f;H zgQwTY{-B^hO-}J9Dm=@>9iLf05|EWN_f(6tymq%fGSf}lV&Qk=`a~qAT_WUuLzI}O z4qaa6X}#3>JZ2i|(bTF6aTfmDIn`i*b%Y@A?-GnNoZB8Ubpb^$(E&y#12HZqMGnfq z)awRW+p?>m&c&W!h~Y0o~P_`1??&RtpLjIX!U$EF13t9U*xZm zDei-+E7#7052B;@H3LR)ZP+moR4DUcB@HbK$~e7bK%x8|+&dFox%ECfSK@pUx+XkV zV{|DI47cFKQ;+=A0|jXx;@(`mD#bV7U=AFKnCmed-ca5!*r1nBKhnkaNGhA%`YRcN zamAz5MXN@U`7p9V5o-VUO!JgTIrWE7F(&tVL_a}F{S#^Sdyg2>=@>pKXT7xoJ2BIR zx229s3fWS3A92E>t5o`_tA@xiu#yH}`aVLOh+WVKuCM4hbZ|`KlBCk3V71`SEw2h09AjGca?JL&UiOzyjFkZu{2P6*Jz1CbI6g}rJIGTS$@}DD0Z{0>`JsDjc#u=NAt`{-Sm9rx9+a$6R7>WLpN3TX0Uo+12!1~PbSL&gyVB~OQ{K+J_O&Et*Gz7UTJP$P|< zb6iZ1585Q~#GkiCdfWhA^Xz;DA|RR_T8lURcW3hohR~l{A&zhkVcz2=h3TP6$WO^% zu@e|OIiKC*iCjYrRTjY2J43Z;Gm61tkC9?YyY*SxpA`?O^M(da%RqLR0JPHyYg~$* zauhE1s530yboRMSvSQ@S#}}st2Gc`T7vOIm7EqX`M-vt-r?E-oy2V74bOB)%Ma}9> zhz&Yy+Fs{z5Q*qs63brP?nTQ5ZS8)Y{@%(_*kHuPJ->WiHk`=RA`#qp%#vJg`Tg7f0QJuR-o9s`Q8MfpQC5LCg@gmz^WL00T= zV{sJxdLB5seK%X96Ys%^w}@14taOwUoDJrG1Mly2x-TCFxwVn_^lV+5_}va+w)FPY zMG!mJbf6N3yvWqDXk}p2D)**nri4YXXBh-1y>2~(HXhEz$b5A}ebb%Z2>G2X;1Gq9 zi95+M$wb9pEOXwNLL-zze6XAazG=56BVm3V%hSr^tC;L#>l|32i7Vb4r4Gxi+;&I0 z9X_t1<5z80DNE+(%=_(-yd&gWWQ|1q*Ak>mUV0DXfN6ZCvVd1@ssv;3m>z1EL&FUL zQ!KMG2bbF+_9uuazl+}-{E;`HE9Glf5A#pX9mCdLUyO;?RXdu2`&0a+R_4_~fyPop z&^k)nERoqEBz>zsR2qb4c(tfpD8F4UhegNsorX%c{0dx3P9bryao)BJ)Y?0>UBEj% zBy25JyA)p2gRRYPxYPz0uznx6ssa#W>4SOPj}%jTTQq+yPdGei$M#nbQP%U*nyG5~ z_xp_aI!+G1O$$N%iRB<)KOd{|*VKwLTNJuL@~NUBP9gFd3}{vk99o_xg2J8anD zwT_W{_0dKdxD4Ed*~pkWi|)XpU0Y5~(pBj?LGbig>uvlLaud|9?yMw8v~hhQ6VM3K z6Nz3a@{wKw$i`V?!ztoPa*VEm)b&z{g+lfVxU3E2j8E)3V~`W3olzaN$^1C>fLe$W zc;d`wcM!#lSL0d$xHyc6k>Y6ufD&5e<=p9Bq)uJVtDS~m2O5Fs%!sKlt8G;`aRe-! zAmAE?GZ3RU9h7|~QNB#cNNX~B1aBZo{FbW_ZXv{@FY@Z7#^vWqC0X&4kqI*qyt$`XP4{8E%4MSH5vbES#2sXX= zKo3XJCko9guFEKr3c?P{CA990)CZ?9yjoSuo+XdCbVk(E{HC5-rPt2fO1XR3Gd(kr zF*gVHs@pIrYgw|)pfw0Jjo`~2L;81i8kz?|M;5Uuf;1pEw>(M?Y7a(6eY7$`(ZL%P zPU2JUDfmiec6KYSOlR)DgWOkJyj+E;*Xt=|NNAfBYw~G&=h?eSWbc!RMQWda<~V)m zJS&UDvJhGWiGc+%z0F`oc$g9`&n(=>`&kfwf>s{C3lrTN2&a%}_R3MSd#$kdAIGr^ z#K9IQ@v#V_t0Y2G_hxHByx%416d$tVz@qy`HK01W>lpn-V-!G|)|6~lRt-~-EePVO z-lck$%}%qo)QB-qtibNqX38hVjNq6eQgje>2wDLlpwR&qfZ?$1c18I%7}czL@pnLR z0C*q%``sTg2mxT1RT5IULG3{NosNSfRz819~vn_k^_<}tWiO)QAXNs3^?~H z7rj`cK8yq{ji4?sH@_G1__7l7Ud)e$_!h*uIr-!^i`6Po8cj2#96Jr9aGO z#z>hm1DYA(bJ8-WvR!ht6kMopVFgLSmQ|w`2;E9R^Xr{Zfvr}v6w+&<_;<-E2cNCP zQITir0N%w}y2Ui>2f{YUE5Z-U|b{IhupXWh8raUhZKn zE!;l=Yk|Oy63l|=kn|8Jk)9_vzg4|IP1hcv(99nOhX`!RIu)8igrfjs>Gf*bfxqK3 zSqvT+MI<#0|n4JPZ*EP6lVH>fm1D6wq1L^Lx#F8a>zh$HLr}kvn*PDD=m0V)e`zg|DKm)SJ9G)gv1OePIFUNuFp} zKL)$tFHxUJWsH~|cUOGxS}439=pBVo?z&AL_(}F*?;Wy(-mk+F3BMw#G1r(IvJVS* zGSxZlpLMHj;Ljz$;WgwWXmzx)cQu&GB3!UIpV5 zA40>d92nxZkHL5t>3*e&)jM#QN&8m@_(;Y~R{;G|wFqNj(Sm`2BCITpuTSP~UUO66 zqLI40#UUg;f3NI334lY13YKMLGLEmk;C@-l2fKqG;xr~)jZ_z@q@av27K2<|#S{Wm2DT42;71KgOJCRcXIXQ z+K_oRS&J9g5A=rdvV)P?2n3~<))*l0&Zp_WnimY>bbT)`Qk)+QhSh}Xtj*3J^bgAKFq|9s)W_0pTdbj!Q+n%ghqPt8J7U zb@t{|H*l!cx&@Ri;Jr~{<*zi&$CUu7a zsOmMdKNg?C_Tb5rd)t^K5NamPTz~4k#NPsRFqi#BB6C?ccc5>t6+1V!^zj3_8+?OL z%7EUYmvk2`{|j&iuVme@UmI+vQ)StVH=Nf;L=%-7)C!-0Klt_ZK?C1|T^EDS8TO?} zw%xNX(F)`&D*bDy=ov9ca#2%aSyUTeNhajD%eq`Ij$D&R`p3RwrX&8l-77!p`uFw7 z%kl2FI}b-zs`z0S-BuBzE5tp>XDf23wp+Mu31_NZ^z`!*1A@{5-YhUcvK7-H;~hCCWu%lJ;=&RpJ&>@DTsM_(_K4TqC}spj+0zM zX`UUwNZ~{yUHn46sW~ruz6Z^MtO$ykVPGCXVp<5mu?rF=ZM7eHj1V=_Kf_q+O+i8$5(sJ6>DxllQ zv`L24(7r8)TmnKMCms@e04ZZfz@&B4yB9Q`p`Y$Zk>NjZ8LE=kMHauFYB=}=vWkS1klbf0 zCD>gKoz+%9-m+suS>;MK?$7M?6t)JdttF8L*&Jg8c%UnxQ4CE9c12!Mq}=iEK($Us z7VH<0&efBrngQgM$^Q~PB_Xqxge>hNPnxhjUawubKJdI4zPXOV6+zbXLAn*m9nr?u z`j2HDQ-%ljOqi`nTDBLC%wuP&M{g)ateMs*L=r?+tP_^La5(Cqv^_<<0p-4-#a*Xx zQOmjd-LUfM)Nj$=r7q6~agR}5=^P|bcKc2IFgS8s%!Ku6iq_JUorNYz8_;rq>T;zV zNHWnOO!?x2Nj{_F=u8jKj}JL_mFRh$9_5?%w~59Zplc6M-J&(Pe3Zvgt6(rTxLsow z{i!+Ixp|Nxs0%miC>BXcSD=Aze>im)*UgfhfX6qe$PtI%LEUqm>|jlx^{(m{IOPaK z2p>a4Iqvpf=g}Y`!SXwC!SbSP$mHvUFz)CiA7k%nqL8F@))|D8^Y1{i^IznxBVi*e zEjL%(K+--3Q;;Y;h5W|F4jm-qt-sltIQHHFVNn^QLXA%k@z+vFIGdcm_Hf~3LHq{I zq#Nbq1s^$AUq?rqK1HN1aEDP=v zeJ5P!AZ+e4CN-oD5R_q!wa`<(7_OJ@0@#0Z7x z&iz1W*!+D1RPXOB>WDMpXM5H&#dG@6y0o{jF>aXjRdr&>fx|6Y2YI};CSmw*7tI0! zGJM!I%Z{!?E^Ksvb&_&(B3591IcQv<x(&Yv6{aG`YKDyf;R98(t! z?SfmW{A1djqNIoWh8farK#ju4!C}T8l7p1yS~SmnRX|se?oph< z|2dHbef{H>-^4pBFsB1E9!u~qPV-pfU(g@86@pDrr?^kRxY;y^sH_v@_~)ieLm?K* z*3I@xlVYvcjdqELsf1q-{UvvdhFeExQxESJFNo>;$clF%2xqZE?QO&NjeI_FFzf21 zy?!ZdF8JY62Mr5ML5i{4@d#Q{8$WQSs*j&|9X8QEKIs zwIQ30*9EU|h&tk^KrTFSfYegh;t>SygqF>2yiNpg`c_YhR4N(yS)g~RB3y)8Jj zQQ~%Oq|=jKfj=@gPWcgA))PF*WwsMh92ZpTXJL6~gOu3XJBym@!aw2NKUaNW0%`n zW}T6JW(5c!{bprVdXeQ#qPxjB^D2-#Ox{k$-+kuYl3A0V?d0hm0aQxodfuXdl&dIk zdQgl6ey7%;SOsfh(&LCwQowoSAE9oC8*p6-TZPJy7Wh|O!88r`6I^dQ{E3Gc`5>W9 zZ&pM_BD*wE8P4Lv{l$WNCI_Wm-2H#V7y)Wu2ALC|p#0Ej%N{BtmS}H1br|2HV40_% zI{sUwuWk4-0#`(#g5vq?5^__Ho>|lvH8Bu9_4YwV2xTY^V@RqD5ek*^68hRw3|tS514`gj6f< z@(Q4#J0T{M9j=VBv!LTJVicVkMB+z(17L+s4BFM4%1z&AzZMua&TYpcmBKfP}h89!OVu1l(ycPK~R2{x~x;;T|Wd08qfFG#$b zow5+a4|b`n6O9OFjiq=tf)n_e$(vMiWb0@F8GRn@$;7y^G6LmZ6^%3Ng!5zCt0(bGEnZ8#m`#oR8`A8|UUgTKhN zN3dl#@rIpK2u|s{dT)WVxYliTUrr=wbrQM7=xCvu!h_oW*sBo+#*Q~aVgu@gGXzw5 zY`a|X;=)6kCi(IiU8b4x1!zryeSFK4qH!{Ch-Cs*+wX0`T&9_(5iL_L{#axWHk3qX z`g3qL*~GTJDBi5%PDXPx&S@uW5`ZcEOEtGUF+j(_E0+m4Dn_w>rtJe{Y^R*tLUW>g?QqNHW-{aFu$yQb?8?Bi#sezi@gy`d#pCp zKZgJ02?`%Uq01qs2P?NqXUMwuEzQG*-#20dxR6Ixd6_I%-%rp%z3Y>*_+0Reg{+KT}|p^wZ;a0KcnE$A4! zfhoB&-hD$XIRBws1B6B9s}Zg$w>^%|nEo|bsrEl4cIi(ixE9&4Y1t*S^5wk}Yedsl z)>V2RB4+eh_vW9l7b`C-E3C5oza-tgR5A;mq`D-p}HpV&oDw&5($`l&(D z?P-&wK~_!M^y zRC*>L@M6b74>W(vM?ka0V==uRpq)u_r<6Is!wV*z`5*R7ITKX3#kbScDYmv3u|EYMGo&-o{#BufEG*bPdU-Q zms!gfw4vARamlBZiHsQ@^Fty&y{rvH;L|q9L!0?H``XqS(#GRtK)e~~IL!esx~bH* zi?AhVGXmCEWi!swJcceDiQ-bYB&_m;i) z5yUfd_UD8kbr|M5NFJXqx&@$8pc5H0EZJDSbx-1o2^p>g-;iGy8k5qXb5P~EW*i%H$(o`AnV6=6EIdl&(p_~PzOlIk%C#|5 zy89588ezK&OpllEnj$cDzWNuke3legQ-;HIl#m~G<9kBth2v60RxfwUV%A}1Q~4e% z|B@(uMTI;{j|dxzp6RaSQULoL8?j8|%)QkH#*>lL53J@|2ZIr(Rg8Q_m?OqInmwsy z@~bhK#a-R-s;Ug^H{y0(qBL}Q(PbsUKgidx#n+sf#k^bIda5E2_9e{!$iLX;^w(z& zrlA#Be2nef!sREegOcY1;Yb9 z-N!wILTQG+FM6`bo`fi+^``z!F$lO%j1sOal;(ZQ*qDxm z%p~=#*o(f;0HJUUAfOJiH*DpiCUaA(U{3OYTlDrJl?Y=9E!uW_f4eqvx9y3}RIP9s zQwm`c?HHt%5ErXT_oOdYpaxYjYHdt??b+xtMEyUc6Q*QS@1h%Fae28nUS2R-5<&4Q zt!E4tc<4b@t8@!&&8=b351EmnplWRWP;>*2U}0XUWc2b+@MgacbgtRg^`&lkLtX}x0)jsSo#v{ck>ngyDTr=%@~%IX8G zRKC@DTRen+Qlf08OtiTJhF!?G-$_R;&-}T+mBKBrnm{IEhOgdDCQE>1jzT z7%E$lJE~{2Z>v-F6NtLc7FDdK)a7K}z$sC)ekkF?g2a0{^4(Z7+ifCA&(*R;n-$qX zn*wsJcf7lqg379@DXA&ixFibHgivsQnZH8mOf-=`BH{Kh2$SDc-efCZIR+_3JjP9J zFKM+cZ91lO*CJx})uU*5Omu#Lv-RjVu}~=n$cN~IFl%$x8gaIUP8+_@Gf?08CW^4m zz;|Y32h0Fh!66iTH2ws6#=w}1$kI9WK_0hdkN{#poxct#QQ_({!InhvaDAR6H_2+X zSMiRC>R2SxGb(cW@EdWv6fDoWO4f!_QtI3Q>Z|uiz6%?pHUO$lR#Oui+}{=~V{o<% zmI}iX9f7>hy^wKTgBvASLo;0FeRl6M$LMz{7cRHe9rJT^@v}53{{i4l-j>>Qsn4zv zFumTy@Nn`C&LmYZCxy$?LDwk0%u3aZK-~&_OVBiV<{@L$u3(Z&)n&ze*E)YY5p}Z| zx;vK`vnu?gO$Jgfcwd-47Pxpftk6BMT&_nmWqVRoOP0Y0H7ugZE0*`WLUI?*kt;Z+ zI4tb6&eS$Nm{)d9#rP5qkDuM+@-tgf#58ETZ&>F|{Gu1HRV>N5x>?bj64ewh!h+On zexdUO4S9c0X*8c1uWhGD&ggsRoxmo+64SdAE^%dm|69hD)!C5Q6$*gMmqm6^0e;e6 zmoia$OwR1}J4n(;ulBIGfhwJllin`rqB@No_WEl7azoa{UJitpbGfPQk z3o3Nv<4E~98TiODijY^R1JRc2j!U;ZTYdq~7{ zw(c(diPPFQ8l)dHAYhdSl(cy(=)hC&oktDXER|;82nx^b>Z>bLS+8)7rO7mp$2M2q z*=D9n2?cQkL7b<@(F>LY`$N4s4=#s$OkuxEq8@~os66QP?nte0aY;_|S)z?8$fDTO zOzXhMkA)^l*Rx$oqc%H#w{JJdJE75br#b~kk)S)}AX?PK34=5)!MC$mCtD^JYB8$c z&q5rj(f}^8bh>506MSth#?8i}BP<6G92q6&$BF^*Ww?mj*d_5A9ml{9#q~b%m((qV zhP<8q&hOM^!T?l%R_2%gV%N4TTY^Gmn$fdAvSGi;JYXnJ zVhQQhzzbiUY(E=sqSiLPsI@sbp8!tt=2JM7!R|+xG6}=X3@mD{_7mV_Iy*Xm283-<3JLdB_F7$}k)^j-zIMKX907Z~Lq!BF zxKOwl4Eg6LhAS`LixZy{xQ~kJ_rm7b&EjbVBQC-n)Y3VC>-jIK2Eo#7L|R$$m>L{=-(x^Qmb^7Po7AU z6D!VnmzBI+Tf}-YIRAkgRoI-FMqz4jllkp&W^Z9>{K@;$mFJ!6inX95nu$V8-{7!- zwRBAawG`OHIFu+k``##Eaf;i|x)Q|RR3NRMjStG{;Z}K#>A$ynYnU@uqcwl2Gk2v5 zY-+~54Mm%?MOq<`UrMn&KM1DBj%EjeshN^EHSIcjw{oxnF=W6<_)WdZamu!t@D;}lgW_d> zGrN%i{I%_9m)Nk~|G|R5%5rTw7{&AHVytOF*kcnsT+lUbeB-zT)aAi3yh?%X!SX<3 z_oS1~-RJMdr#R-{i$S!Y4sulAU*;moc_~}Yp3H0T2`kZ}4f60hR@nti;d~51CD4s9 ze{tM~DjGNE7U7!=GC33esF0TU^+jSJk9v4Q0PxkM$AASTD<(g6D5yHGb+hG$^^ZP~ z=}N8npa3cn{1;&qc2e_k718(uH`9>yvGuKw(NF=8Pvsq#y*ZG}UZ%mTypHrXP;UR9 z^~FVV)cejwZ0jwe4_0QBp`q$Om|GRt@hb~N{K?!m&7Xn}<*Jv!9E+%m{5n6PBD|7# zOva~Q-DhWAf|ITB&(8k1K8A2+CU}b0`frHxV23Z61a|`z3lfQs9lgk>o;sgHlRmO)?920*Y=bztyr_EeWAN_g#dbZ6 z(Ye$PS)z=cA##dWBnR?ro;K==u1{W&gqF9>l?_^AVB0vbr1Z)E|Nqj#$}Z8;sj#UV z<2I*I*pejb$NLMmPepgYn||z*JJs|*|M}PQSk~|Z+JoqUJY}Q}4f282<9{#sLl!Wm zIdmijK|+m5BwoY&Hf1s2KSU@~9>mHF$NiL8pMKNO;7=gV@9ea#6iA;$)9+}oJXCK) zrig)}wXnMthJzNL&C)Ac&RR=9{j{7$@HMwz@D1fMFvWRBObl_$Mu5F|2w+hO&QYXX z5hwHf_e6ZULNiTq5~RIGE8brvQf~lXPWE!6oUKC3iZb-4I3FMHhCqhB3-!darI6mN z$@5ofM%EkqtcKtK9a5J&*<9@dQ&A`YX=J>QY;x$ngOl^XFS zI1XT!a8}?i_?G!Lgm%e?gi7>>1DO}CqX$4h17S9-nxv8r57!XmV<_Z20_oj?xebRDaaSPW85 zL1E1E`^N@jd#xF`Vp==W$U|wq_x8S5Niw!V4Y`4u2@-qnwFV>iX#@ExvOC@?{kGG% z$z(Bf_Q$IUc8~$;&(dlZNe0T3YNM(9Bh3H9XorGtEibjN4*Hvl4ThqB*A+In0dh$4 z;<9m3L7@LSYuIwDrB2;*ZvYqjl@?Nl+(7kvQaH9UC~9WGzWP9|dWV6)GdSJv4aa43 z8U(5a(f2NzN3dyB69(%n);`c70*2#ylh<^2=&VOE^U>^x4FIW&I9J_NO^fZs7t5u7 zCQ}q|BO~Bc4CFcW=V8`wj=P0D-U{ z+5FE$(x6#b`PP}f=Rm8@U!U~aq{VsYr?N-^*82_=snA*CLtI!5;7wz4f z5r!~+s={)k8Exf>8jlU61$$zjog?PTGa^eNP6EhO^Jj%;k=T6cTud>ithJo4**9iF z7M6xG-DC>^bS=3dtE+PvjUOxJ`EZo(Hk4Pw$W2xd?P~ujSUeRGQ+PWglmF7*#X;?= z0v0!~jk%r0Fm^-DzxYuiqSqfe|Lw##i-LB)5{51>|Nrz2adevhBV!O$f;=SBisQ?l z$7l!u;rW;Sanwn4{II(T!ZaMl*s2RW^4oSGfTHmCw@~?0`MSiyLyT5g zC*DYj)TN9aEK03=YOFw4BAc0*IhmEjZL`fX7cYVnrf4KW1i6x?PzjrTP7UZwJ~r?J z&RJ>@MMYJ(KLaA5XoAsE5MLx6veD@`1H6}2+IG%il=zwm!9?uzzE0TgkdM~7f${W+ zftI^2ht}9|4^_{JF*%Q^a1o!WJr{=kpc{{SiYQku42hM@ zzH|a;xfoP~0r z7^eNRU)jVivRUM7d`x21Zt0mWM>LW2hQqe&kUx1YiA$i+rf=O_C$JS=zp@Z?xW z&8wtmZ(?pG4Ac-|lpzwU@?Z7{{SjiRy5ftIyR>ZpIkHNhLrvlkAy^%kG=C+QblpT6g)Ri^m+!qISlOIkleBc0PRi*KFi0L zC9h1DJq*@y=6V3-pPgMyH<47K$uk@I18H=FM3CKacT&rSHuBt9Nx*9!YAquxKY@|u z+SiWG1Wf!8bE@0qR1ZgvtN$_I06FU8KcqXIlGTM>lR^howVX9-u4TIINeDjpVLqCE zd>+%8)Gn~wcgbtTULvEks+5tG zK+C(!1HvAtHx&g*y0kd5-;47P$A{4qp;B1Pu>86vP{%WyENpl3nb)34@1Jita1fY= zl8B$_41)%so+D3&1kNysh|Rld5`142xMeRSZ<5U7@dR`NX$UX6BaSE79i@I1kWxgA zsnncYJ+OsOnTamV$i~y;nSPF+R@X$tmG`_M;crh=MIYbd6@1v9ha%H)^QK~F>p$I2 zkE|;)_?V8w{CRsS7AZ3C^8iB2C6IbKP-Q9kLf#d1JY?rfTk2*54n7n*gJQo2U-BHO zSiNl*tU}NU!<1MKCp+^*%d>JgYjP_UGIg|f|INCX+qH=}!%zis80Ra`_UBLkx;ZsF z#BN(~ZutvIvo7{@q1%xx5Kfv3L^OW}0kVJp|3YwH)y?mCGF_;|dEUGf56^Y+-0W+n zz1(ae%1t+@0J{>JjW4oM1c%z{PGtne9mk4tN|XIjaAm$$3~~AQKZsu3>Aj8L5u6zP zE#cW(@AUe|-xlcVRtdK3#Jq%uMI5|Q;rh>N;NA2y;d`8F86{@=jQ2u0(aLI!$n(4! zOh&x_oU*Z5)?p@Windw4w7ADn%Ee2{*7)B*URKUgHt_)_D)7{Ydph1P%JLdZMyW{D zk89Xp$9yhleEh*twT}G9JBr&LuJ#}c+h&-9(#Ez>G)LUrloozbZi%TEAmX!fCi{Li zeQ>b$>l+okTttY;@J8~&h=z}i=7m#5i#Vs0Z2C3M2eB?+w_lqc>&D83>f`hN~aLT38aRvvF(sfJRt6zqfpN~uh-{q>l48?r9R?!!l&pk9_A`an9fkX{lW5Yq%0%_dW2^FH4WdY!4Uph zoT>?L!euG)Zu9{MY5T zpavC|a3ltp?(&aB{oEWZ)&K5>n(yMB|+1oT64SZgEe#! z67!qC`kKZrDm%eu^C~Pkn9YV!EXy>n#R*wBtPn3Wn#2(g{7rJS=Y%C0%rzmwME(g;Xj?c`{YMW%#lRyCJMxSP(Ks=b9{T=`KPq!%= zzy22#SN(!8Thob(fu$qsa))&wmL+52UdOqofc5Lf4uaGis1nQTvTetDK|=tE6G>9tfbd z{UNtHj7Rh4kPl)cuK4x*^s44|sk7@0Q1&eBfC{V}ZGI4C6WQijC@t{vIffRPQCL$% z2bkd5QDM>&LvLw6Z8VqD)u@H)Wos*4+IXJrdCQHEO0oZtyWjOKt_iE?`Z};B@i)QX zfN|hH)5^swo5d8DV@T3X?ooCJ9@L=R)H$|UC&KP5M}#FH0}^JNn}?Sd_*q+EKG*;I zlX0ir>%A{JCI5Z`+CVEoIWJ2~04ittWXj;vEL)4$!i5^+@y1V{v3e`O(_1+%(~ON} zpZA;d#~-$cHcjsE&t)uuomNtJZ|e_80jleT4yK>lk3`Nz6n(Omty|{{|Ncgk;3@<1 z89-T4HfCYlv)`;OGS85q71Zg;B&95Wa>wKFvyL3A zVa^8;OQVkMN^Mvtd2v`u@n$W65QR&Crasg>LCQuG4^3~65dyoHduB3U{e>HtfulFr z+-Qa%TyfH2Hj(CwTm(XRDOLG7TVye|Z$)AE`hilWG-g_^PQysR>hTG&La2?ZeF2ZXlM3mbP^j=6b+ZcgJIOT(F&v;Jv1aTgT(w6 zrK0cEG30)-W}INdDhlBW_-u}SN84cMBQ2bwO4HDP+5O9bx4k` zI`n3l?Z)z_61vP2A&@N_X?sv)2Q@Phv~tqSAz!TL#`ZfS)u+H{O4b{eZ;+d>>(2-z zMLlk9fM(99u9sb>EIEy7b@os@`M5hwZ?tjUweg}j;P;ukVHkM04Tf5$mQ7bX`X8(c z(E$z*3<~WaFcui=FcWFFZ890 z;PH47Slw-u*A20>kN*@&(5lAs{Q-ltz}W5m&GPqJPx;>aOyX9&Nr;RranNhI>nNuZ z#u06^@AtE76jKccd@c}_(k`a2zuUP{>tg@rT#FozJ*pk~*mVPH6?L&FJ|8=p;I{&d zSgOV?8jbs#vwJI|e5;J++(d``y4X;c)Ve?XdH-C5tm$&hRj^vF^~4VR3EP(8hg)~i zjeZT(*;IN zp{9O!LFyT0m?0l)LGuK&&SP@(Vc$pnysUU;cc5@%DkRISzeO{}V2T^Bob8ktU-PLb z?O@vwOtI9k%efJ@&65LZ+68y3zT|F%O{#d96q?Jdjz5vFh)m1eW;P-9n-xOo@Nw!c zgqK~rNq62W`2w|^{$xo;k@TXOR1sjZ@G$if)G zL^Qn^xQZ1nB^HYyT!ACD-2chXzC8dKXwB!KkWzn9ZUm{OyH4_87WuqLgMuX^a7!yq zbsEHH-=w?z@s1Ye9|ET1;&1QTNtCR_h5FyZ?M}I971EWH4B-_^jJcptWIPEhVX^6N~JZP~G zu{9{viefs1ONvQ)yJ4iXsBUl{o*|^(tTv`K@E4=5gH~0zS~M%|_V4;ML1%6rw=4BX zqrc)<0Zt7}1DWX^%PKr2R_QI&?0Hb4d3~HkrC|v+QoN=}2 zI(HMZg#k?Ga)Iu#`*FuF8f;@sW(H}!BPwRrr3@&xs5PEz*7ap}_8g5P4jn-nEaDBk zvjyyDtfCIVmwu`jkB$ag_9JiIwk9tOa=T@HPT9E*g*sU12)UFhD&<1koU;YY%exVu zpsYt*QXO;jmaqd`Y~yUBXBV(m!C=0Y{@gX&iHaV7ukR9h*M8g*`c3bg^W!-Ac%jx;NiHz)8o`R=Vi9z25jYb zySdE_|6Q|1(yj+qu1ntU^@#f&rzSE4z}ssmx|Y)Tun}ReSAtuy&*9U$_j9h+pvK8A zQhsgCsP+^8_^ea2MaJ-m2tLf*Z$blXkqc1oYJlHN)_K)Efk3;sEpUkep~60J*hu{7 zOASZ?dN8pvHl?`dBl$R0{n`Q;wBuN6E4o&gQ^OH=l`br{S04Pn!9=LCQx~*om zvlDeZdL$eVv2q^r{wCfSfe}CdJ2mniWp$+S%0k{Ydv%efiHFfFeXsPrKl^huhYVl}Kr&5;ugrNv-EfTl@ya#oN^2 zdQ3!Ej98`3rIld6k- z#pL9|>~{X7TlXaT`<5Cv&y(2j(J=*=vzcG`mmXENw{r75L1-2BDXz=?0A@07N4v! zU2&}>n}95|52{8)$wICRD`qIAPqx2%-Z{$a{|U#*hJXM3OfztJ>*o@O2pZ6J__YA}C^O^^7l82BE8thiOs ztBUc@;e1na8P%l~CBAhS{P%<8&-P#uY8|odp+i3(2W(nPIhpv60U3*Oz?u7~q!B#^ zUC(?vvyALXwo8OG;wGD5i(Q3=FhQRINfRiO{l@^QP#P@;gRB4eOXyzRz0;e8Ejd_W z7ZfQ17-i-VdCqSQL8f7P$Dm9~;CfYCNGt7o8M$n^4RX&#D%UajNct)NLqXr^umAtU z5=}iZE~fcY%4-4E^*#JY2sAVfnP~>ksu^}VT)vsUEFNBG5~ThZ^?g+wQ!DAn$CLXz zqhL2mmHN8OwUlF@zM$NpW{a?)pZUYAmkJl%#hduY`ZQv)h%^ZiTJ=wGL7U^*M;)XP z+0Oe`eZK`c>IVvu*_7I z04+?rGZB*iTHKY(VDa9e{1%LzF`IhIP#HQWYHevQ&GsEuko!oQb+FX{3gc0wZ3bTD ziyx{LNat>gcx$m{&KvuJxC9`lXxf8;qSfXd{LA-A z@88vD|5Y^k-I7{Z*}`{D#KQ_C6hS#XYhW&IE1puH2NccYL3KyO$+CEFPKhTh(V%2$LwWIb^9l3g8=$M4SLgIu#ur8+kj?`UH?w$e5>8Q9Cx<=+xKC9E}unqrP7@Vhx=uK2)XcC-q{7 z-(BQhS)Cu{S|rXMtOsq_Gd1R512TQgG9$cEV%VI6 zp0C|FI7{}u-WZb;B(4ob))F3ik_)f=N~~S$)UMqN%&jRJ2&9{So;SlAC+yEc&mED}aL(`*I~ieTZ0R`I|KF=HCY z{S*r}8<1|3G5e5QNa-Z!1rW5j%I0ewq1C0-L&SapoC|Nhno|9(n-n`jv{5An>6XFmdFl9yK^ z1z-Qs?pjYr?J#glF!YPM*?a%~S^xT}+goUw+{F0kD9vId*VL4vS_AahxDacIC4b{bRaP!{rxVg-sD3^|iJ!xd6!s_7 zXfv8~#3DogH4%`yLohmTAOPY>$Y=h4yeUwI0Lt}{+6o9mIPv8Zr1!7=>8Pc`jydQ~ zy`LPQYx#K<8m3gulS#N>eanSUg8G+5xqKFGnSK1WBhzIE`~8Ydo3gbj#ZI$&ym>+Q zQsfKO)mBA*52>1_SS>9n+9$^x008RfA>@!lKmG9lBg*c9Dcbc)5O5$#>Gtnu7uup% zmx=pnswQWq5D_(0NI3&CKx+M@r2o<_ZCd~j(XOQ6yQ3?)R%2#e2C_ub)~{j0^6+Bl zg4L6%bn33YJB2jr$9*)IgZ)V4wV5n*xjAp)0fC3+VvA!F{=uW}jh&vU) zyCx58a679Tyfxn3@(y-HSA6N{KRXEH5{)27jA1DBBn06Qv$!*z1IYX7V1h{y4=7R3 ze`M3zSE<$98zg{Y+mHaC7nj_3E|kJ9^eW>_snpi#HsAs6Q7kr??b0b3e<=KswUTyo zIwexX2i+1TPcciWGGTzPm|&&nSap{|i-VWn@`&4z5&=Ma5|$E?KL01^lr&U7o=jbj z$Vc~M3SXn~CiQeLo|~c$K|mvgEvSBvjD6fN`?ms7PE?K@>`fGskjW%eG#cBG&9f;^ zf#ygJR{tIPWG2$GiVW%bFkg8gZjedGyEuE1u7@R~2L<3*9ZyUKfibK6V$)N*F)Z_(>o(V z?6D+&u9O!U>1_h`?sJ^IDBe3E`0xhM&t#UE2_uuX9Mj8udX;5w%NNLojfSjfU2g)u z>=CFs-b^BaMqJ-PPgZ_c*6H=PBgub^Ic*zz5F?z0uDxC>6}HR#yFmowR1eF7l7Ag_ z@viEcu;{;Ny(!PXjF55h5}=0b+UU=`e<;prRxx6xm*|f&NOLk*y^l~R)ppfaW~a!- z$$9?aaTRaELVoYy&=>8J1fj2QrMon36tzHf2~pYlg~`$fzz7LFVt@br_uPgn&U}a! z&xd{tDb8urW-^1l2Gz%2pMQjV-n0t)CNx~Vk9pE3rnfPAwBj_w4C#saY126TJ&M)y z&~7(^6ISwo`CTE^z5{RnTNE?Bs23o#q6opc*VjV%C8-JFXmE^X0g}jO;G`AL*Jr#F zZ~6<-A0^=gGHsxs+Q6zpGU=pC$NjI6f2yd{WYueon*be$to4aH!W5RMqH$nx2u&G_ zJFu60)9(Vkz|yfkkY8^au;@d9*xEzPW}t_9TY%o*@bt`sG;_Iz6W<`+5w0eebi-aZ z%v-M$_P{KmscqEo|NX*TbcDU%+=mtY+BZ`b^G^Vv_5lwar7S8j6|3W6oJ8wHK1RDV zwSOl7B+?EK1PMrIBjzT*k)6u?fxZF-uM4;+vgOGvvwIYjD_F4t;Rp<4czsj zO~YzA9c7)3tLFi8*Qcdj1AcXitHBcya@FfnR5njE6f23Adxf_1`2YxIYX}4%<)re(@v^pObZgxs?WDeq1t~_pDd{X;s9SQ*e=MJ&=Te$G~oqG$!0uoSFYrhRD0z&H5nWg5`!0AFm z#fhG+P(SUp*ft*tJm^n*vjZ%!`TQEx2<=A&e-*&Z+$Jb#f+zeeCJ1}MRmckKa;rnr zk$|FPH01^{yG~5%YS!K%eemrc2AT668Q7NdW!ebEJ9oI%pRF}l^d3lf2L_K@U7iv* zfB&@WhSBL2oV;$J|NVRW14(jIASr9Esy79I*mig&a3RA(yb|qMk+G$x^!``VfO1{@wdd6I^d${2+W})B z-8`y?3(V5$U6uaXlhRf5%|Rv2T{-7S7=|BkhZPbNTYljO+JJ7WZNa?{Kmb9E`g)xm zNcvp7TWe82+S*g$n}<`rZP}a;mHw~nMC_zThF-SZ3t*hoB=>;Jy+*=u6wMoNcW-6F zjqj}Thka74`NCO)2p>a6mtTjK0N*J*Leobmw#&y|vRF}^1vhJv(Cl-#l(418);I{z zXdAluNFhbiwHTg^All~7`+TGN?njv@T=To_srYI{EYJY|{o?wcmX)Y)bU}#U@$9T| zXN=D5Tri7`qB8S!suTMaZM}hBNO{ z!Iy1_3SU0Ve}0(sA{*!5_;P%a$!TE(;-g{I9%*G#REIUMrJOCrQJc?;l9*Qz-c%LP zo;%j;L&TpQfW`vqz%LO=hxNgn0*`C&FNGbC@~z4gi;)SI2Urg%<1=d2hxr1A73{N&h7O2gRWKa9R&4hP4^!bfyRd&s4XL z{huP)q5>!}B07DNT_P1rM*#aA`hY_<9=5;`aqhg;1*ngtFxbl=YGnS(`xCg~t4bAA4`!rXGWGVzc{!WG=@FX0nA=kU0y z%EO&C*i@rh#k-(rTcuF0Qq|jVDV;Hr2-?+2a5n#06DOQ)uJ(4vPQS5(MgAT&E`1m+ zw2`TKlejP&q9zY^5fXkZcev1R;kT~WdiAr{`T~ccu3bKfNU^q))H50*vf@CcVY4I* zN!?Og_ZVMUku=w4)fViWTJe}vpMLuyaA;^Fp${5Hp7#0Ae>z=ah8Iv_91X=8J%y^t zZAnjtWo_X=&|)9x5?r4BOITJe>F5+law!$$b}~Sa@D21TzLvDraohP<7pSKml68rB zOc=e5Pk5tz11DKrB*$#(xdn`fUfL<4U&GrOWcQMnJxi7joiq#@OFc;;+TL&I0Lisu zflWq(ol($E>Eu;zL(cK zFM*NUQwed#9%hFCnYu?QQ@jGQgof|MX}Nuc^!4*~28%>9 zy!StcFwFlr*VllqK`L4%3w{JM?(o>5d&VXdB{g<0*^;s}JhWcw5ltTGl_&G^{=j8wFO3V+ATMp1o z52Yy836mKg@)hL!G+i-LM?7$+wCVXz;%Ixk@B1vuutdlJ2ik{@Rh--0!!KsUAOhD0*7I9rkdN@ z(ZQ{wj8$N7Qvg*m7rd6LgvJ4N=*S1VnV{nkJZOUz==B@CVQZ>ND|&Izjjs*`TubBP zkvjs~UZi7q6~@QOUCoN2C|-17Jh4jL;$ZI7nCozreN}Y@>Jd7caoF*VlOr*_&9Q4_ zp}rE59ue6<6k5+6{}^q$jTd-)Av?O?{uKO9(8XCqB9pXnlSNR-#fWW#?sf^0?X#r< ztqCE!p%Zl?_yXl=qX*{$6I!?Qv6O-3tyEkForTNwkxRuFljk^{(v`dKJwcD z%vXG?G@BXoZVUzZ!5tN5Dd>J#>NRzs%z%FP#KvxrwgHZ<>nUZKqJo0lg+@bYmD}UH zlWm;nMI@mP6R&Sg7w`$K*zRn_kgAr5+4)NWqh=$Gf)1&2;(`h1dzQg5+%N4fL8H&miV-_{i@%4aS7<(Dsb@@1#S9 zjt%Ez(6(86n?+Db$FhDGTSUi`op-Qek911MF%f?PD;(!2ew5(Wku^C`C)|v822bu%m^ZS%yZx(JB%cMK z?l$yHCoZu+QNIPj#C2tjQi788lr3^i7nG#RvF1*-7i4N^rSg+mHR0e@;KSn>qsx-p zIacBx#~(k$^!$4W{D9!XnKBNvB!?X`y7xTXzMpX47Hzd}xGydJH=PLWZFog6U`9Q9 z!r{r`@EZZO5R};Z6 zR{^bm?SH0hqXC4yfey;TDdDz-x)jDHY`&Kn>j?s5@_jQHcjbuTb!>3dQt+c7gCl?S zT54gwFysrAn*6fpi{D@@2#e=bzEGQ>+Z3~q?m#W#1D>%p7d6kGyWfmMdBU!SYZsoU zy?hKiB~4SE%nc1>j5jrB0+Y)aVqxTyJDBb`i>)~g-XQf1wwMvQaJOujg}`G(QJu>g zV*Ai$+Pl&jr%ZTr$(`NA2Jr@3?}EFc?v*dp)u_x)qx=$BRCaDJBueLau=hBpNcC+u zz-zi@Mj(sA!IdSo*w&V&3}Vh?QCqQq^=yzKfRXu);Q?pi>{0Hv*)Vnt0a`*manb9p z*svxyo@Xd%MolxzZNsuSedf(xzo?esHw&7;D5lG(3*y`~!t%%=P;g&?9!fUgmAqv^ zVs-Ym_@(uw`B}zFKA0LHlRA^fQw73HV!VqmGm;Ze2%i5>X2cvdE3-h`SOs;g^{?}#r`aMCQW zE0{Cy#hqlrAb*~$*QblO(>Q2cTYinJmzBK@4GZtPAMsfqzNQl@N${>P#)8G^^hSN| z1R|sP$=v;Q`~xzB#~pV_3_@Kuf=pC0RTrb_452w0Ho;oA}NCrPXlbr@)}N)bD1hP z-LKAcfiZFaIpsM!6MPrFAiU62o2!v_N`b?P(`eHPI!Qnm<_p&tThiq73IPrzk4PnF zIWs%2`^*g)&|4grk7k9?Cua%WXMp^g?r7_57eHbnUH}w__3Bm%0`0zw*+xsZLlXLF z@c2T?Zy0)Jb9P#XY`=V!6&XZghVY7z-uj|~x?PwQSwu50X6vQxshhJA7yQ2Maa%1? z@h7%2@m(k*HSB@h0)gs!?l3(OYi-|i5hr{>8GhF%P=8vM(Mq6IR6>gcF^|sh$_+S- z>FE%r3_o&~wc(XHwilOI)iY6kZu4|DF$+-luA!NL0~=O@5ns(V_*S?GWhvO8t!?8u zt%lgoAK*>@PVEy>)>q0l3t0)#o&UxE?B}8oGbwZY%@qmxSzX5^jKfU@b{AcQ9KN1{ zFg$8r$TUzyOAN_%8&UrM4?%;HqJT(RQta)bUC?e zL!WxEDE^MrSOTb@pUT#ukMr6Z zH(d@pt8NBjEA}pxd!kFt8QiEXcD@l;o@hlRAOMMF8-e3*dCX(dFLI}&$JA{C{W)us z$p_-WxVLx$ys#-|${+6UEjmne`RU(_wQR4d^rYNzGX7mWC4!epxj6l3`8p@TG z%ei+-ZL-OSC}410-nTo*>ib1}rrxufC+E^ZN{a@bmy**y6I)2D4r5)gpXc&iGTw~XJzXD0=3nCuL33D=ioxBj}qI1>Y5y*7ltkSGK zh|DH$zqi|qQ2tU2PHAZx7#G%3T@m4Y18xUCK(Nk~a#gpgG!$l_XCNK8!5wNIzfyl2 zhzor7daviQD&0k&FAJ!hh0U<-V={y3RFyn0W{U$vVq`PsC0s&yE884U*^lRkm%b$psv>=hp zAx6#(Ot}~17Q@I?v<&FZk(p;fov;s+kZ3B!@+t{E>&Uar3os^(g_2!eOQr(h#8}!s z3Vp7A4Po46n%$j?JURzdRD+sUo5e9lI8=~=ru&P{?TS(PLRL|8t>nPhDpXX_5~aJ{ z7)MPdA%a;w_Et&H7dMuf#0n8ekVE3qkI%x>o^NtpgGr@j!7WD=<%dSkbhYtgitGk7 zCt6oW7M=bLsxqsK?4>-bv!cJMM6K{n!nPA!@tsS5?3cVPX7eTa;K?q))!@oq9-wm5 z2-Fz7qD8~dde|uFd{aUQeB@IX4$*orgJ0dvWW@Gr=HE`44#K`{r(NP;Rpepn{-=Ol z`eE!o6e*HZO5o#46AT+*s##HjY%27YSgjYuuBRtuC>A{| zt%r%~U+i=>nqP3)3cXT_&wwHgaL&7$&ZDT%)_@Z(eI%2vT6+11Mkfa&f9r9VkwC$8 zR@+!d`sdk)1Ro}jnk($aldsSBBw-fJ(jCUMDx~lYYWGjsi9kwRK%)fPm5ckXV3>PZ z7?gbb|CUoeM0V<*C+0^duJ}8Qs-@B3!nlxIsMDgu8$r2?Nm>8AiP^KR#{yox2Ad(~ zvtJ;MpB`N@WxiC|A3~?0f3_&ih=F_1yf7L*J=yVW)NBFbZcKFrz2Ohln!uW z=`ycY((S3yqgZQNmfh*@k1QGWq@BV7z4FAX-YUDm!nVdRy&?^Zz#$XJ>?UEe-+~i(?HR*3?gl z1N8Q#{qGAGV=Gtq0-T;U9b0#2Jb&q>3KX|Y6B>>{e*#1Q*%qrAT3AS%YvtMPQ4wFZ zpAuUO6}0F?-}nFj_9vV_C$7ipHYzQY8Y0KKk>0pq1EEvQ^%#t8=dar-qbzU00;vXG z|DEUMjsc-+^5eOwtTbNOwA0%H%Gg|z`?x@b-PN>_05?F$zj}6`0?unoJWLSSSgIs{ zL&1|@-sSr(;)nyw*{Lvk$_NJ5+Hg47Wyd80142qFBl+MbH14GLnX@?1UN0ho8WKZ1cs7 z`j~!bWPkjP&f<9~nJ#Fa%Ajs7DMKUGjDCy7R&v8m8F9$zk6GE>G8*Z@D37%Ek(3rYyuzbxcaU$EGWKWb;E4Vv=c7mYi@Eh z){m|zL*>R1lz=+E1V7=?T67JJkmT!ypn=IM*dozC>h<@4uEFdXcGI({K(5?9eRk8S zRD`Aa~k;$TV=Zt8SFR$+P=-OcY~;SYATGg9Z52D%E9Uu-Xbj8O*|Kei91T z8T|iqA;UBI%q2}vlZ&EydhA00G?C$?0LD(+3-aAbK;H zRk9CSk0|~I-1*WtOT}9@#1Jm%J)q=eG6t^aLunz$d$(t_y}{=P%#NJH&G1$690&nr z5!{2#@jAZS^zV$=L9NTcV|J#UKb~+iaagUN??`+HvOdwrF8*LQ5V{BVP4nshv2r+rPMvWk3A|&Aq$a_ zX}Shh`@iC;?H;=kJI&a-8)+@mET7UXCI&`VLL32=h+U{H<9~#f=M%+YGu@u5c5`5d zZby^CE#29a^=OQr=0z^i)1s396+$Yg!}=$Gx(b8zTYTdv-Cs~{8?Xiqf1I1JIxT;M za|JfQ?x=9I;!QOBhy$?`Hjx!e*35u%6G=D}Knw9=S;W3m+*IReyQCi=Rg-=yQpDcx zo)=g7&DV-ZyWq?I^*0kpSuS7c<5}r`@JJ5DHM%z4QvPb?J04i5{0oQj_SCLjCWZ9q<4f`d8wz5+0lnwyZN`XQgXzxW2F{BdQ@ zCN27=XGY^jT|Mq>HY7OJxg|Yv}jC)ZP&vw9P*>rlQ4?LJECQ zaHhH9d$n0EfmVQ$C*<-}X#UYc3-3bd^BxT@R%sTtr}PB5(htG$XQ=&*72;lb*f(p_6|S)!!#%Z4AS0%3<1?C$vLT*f#~fne&w$UM5t1hW0BH1C6BE_6?|W=4>RW!M2JK}M&8 zC?+cBrw_kC1P7db0HN`6q8Xy+KV>>P6O4kN5nGm}-F`r}ebTh7U%cz9`)$G@5$4

    j!7O(9!AqB(0WfC>$I7!zb}l zt{U^TCyL;OHhGyR4fW9*$m@yRaC!{|r~?}-!3J&1U?>NGBux8 z>lY~0DU90$&qxTx<7sd<1{m-hvj#gv*0H)fX%f&ilFq5t_SKx!f_Suy z0arLm%>**G<~v}2TC0$kgo2@uIm7?eoJdR+AI&KWJgl5Ot!?dR$)4*L$NfMwTeR4m z-!cV^ppoHW89@n``^?k+Ur<-|)%NA*@>;6PCrX<+7fQ1_gcP~VLFX@k3hEdcdUr_1 zyk2h3#~n4-=tZSbE$O=}7=Ug_cvg!0_glaanJ40-puKk7|%s&s4>ekyN*}98fQe58nzI1$1 zohFMYpp8v%pzWCRM=Z&H$Z3FP&^*W5^WBil^K?&m)N6+G>dCjPq zQp$tzI5mG;uhNL>Wh3K>T^~(qfWe6|g@%>-e7&bS@oEJMqwxFL&#PZ8z%!Te{jP_} z5tNcGx~)nb4f|g*UZCr!cDjd)%_KqlW9kBtt`?Wl*0z|9fqVTp`Vr+;dC>TXBga#9A}rf- z;sUYu%hTLK&0__1bL^cIW6I|?M}VEBb8`4HO{ML`q){uC1KFVR#^4z-dD&W!6x}aWXbeEPWROti#Z0E@^Vx*jLvC!V{^1pAFu`WG*Tn4Wic_6t(r6>!Zd8DSnk^2p|o8Ox+p^fF)9BSN5%-)piE6HJ>{o;Sm9c^Pcr69-bEkPws;}!&D$1D zg|`}RFl;0+2@z!QIA^3$aS9Sxg(XrA1Xo-^xRw>SVBdSBlXf%XPnCZUvNaz#HF!WX z_FZuL7e==HLPuX1dHNp*c~Iv;d7CulIZ<(L&5s3mkh_*IK7PA6jf74govLe#@pW2+Cx>rT(Mi0x`_Y9Xyjqpl z8wvqaIEk&5Wl!|mtUX%ab)GZ9r*0Q)U~pdX{kj}%@i=S)czRx(;^`Mq`O@9Jkmw~5 z2T+#PrQ?{U&E$$gAqjUVVL`^>I$8H7mWt9E9MtTjF>p%v_PP1aN?$6Zsu#qgq|=P* zCHmgpJMT4fmFsuhlD=t`+vZmX~$tN%PBu%71TONH1cP#yWW9SH8(|WMpzjBG@MBdJ>kN{flgqP zV4ypBHb$&Mf--XfF04vDe2o|8i1{r8<5qHoTS?OhjyXpH*Qki!jWDApKoc--QmOM2 zkqEFnIW4|pchwmZ3Rk)xuduS)joUw8Aw~ZOHR1X+Y*nF7q&L;17zrFFfhh>wqi%+%aJf__6{eUm?sCW?1N~bzGfre3Rwa}sioIv zRoa}iHw=sxr`S5PU{*%B)1lr9+@6o5K!)8VD{g?6}~nKhM

    UOXPJZIHrU3wGrUCws==LOI>@sIc6@erSip!uP$y7D@Q9i zZ?K~8ddzEJ`hwCHLe zTcxKkO_R!aUCtyVmH?~H>e%Egk-s-RQYrwcM3_S^x9cYKItv$Ki-sy7rw)ML=+(tc zuZ6dW!FtLVU?|$lKNe*TMuZ@=!EKRGy!<47<6r#*3CphpgeKn|Fx!B%(-!av_@Mv_ z=9$WVOe_%3z*PMAAv!R`SI_`I7AI168O< zr;Nb7WTRd7)p^ta*@>!a7hu?k>};%aj6r?%xOaY{2rF96|KuFW`*yOAqx(*==53M+ea3nS15xP2ExO=yo&mF>qJy(R$?eGE=yBcu+O|$dw%T?g zG+{%qY)EJhFRN0b1b;iHG1n0BL7fdKzvh9G7%2o zoYwQ3{k1X+V=s2UKx6$`GrY8vpYK91?nVFURea3UXj9&mN=H+!gH`zVmYief8r`&IG8`++{&*SX*qR5 z)gRkGI=Wjh_sDlk6|*XknQhJoAu8+PsiLsA=UB5P&Hqg-|wI> z^3Cy1gB+piy|rtmxIvM%AOwv=K|W+kheY3GYc)u|5(>;O0RpHL*cIeu)?;1b&B>p& zr}k7MshCsSHF{VYf)I{t12fWC>{Z!m*irO#;^;SMAP; z9h6<@?&h9HlV)quh9}7i?`PzWQ2vJe5-a9Ku>1)u8Fh~ucI~}#4FVLjmq{g*uL+_F z8;2I>(+2P?&JtFD0SE`_9W9z-W=h#$u!2)2?xVBP{=}sMB)3cQD@S=RG54;KT96#4 zF5LoEN~UWK!>wG(k-7LGM~4JGLEET(>Z~cAUL%}%qV)}C?t|gO6K-_TeF)QLnwX*P z5nlCs;pOQtk_?n7rbhNKVyZ))s~lAWH3#X#1c?Mcemm{|@^ z*nJMd{i`Nu6wktxDQ*cs^1^;k9l^0q*@gc4fUqOywa4u!kMGTRZ0#2B9@5I1?T*mS ztF-ToqhUWpymzBhB2r0H3KR}kq$sAz$=_UZ8_RQFgIR45mGQ*TS80hSFc7&hF64LT zN2|sIoKy8iyH`&*5+@94+6$@39B*7l@ z`@{HA^y0P2Qv_9z$Sd8U{Pu>ur*Y?<7)d1c}-#nh(;i-E+>#sNg901KfLI@N(lhu zeR~7#87m|?u59Za|!Bpx~tsxm1LAB z3wprV6k7DTyAl0;`s?iD*%d&+k`I|nj}HP`cDP^$#3iZzhE^T%(4N*gjIia9ezHqP z`60W%%uC0JM?hV$9hmx2B`7%zZOyWBayJ=~$tf%5t$gqsPiE~r1}(0xmrkDCszV#q z>GuyvS_^R(FGw_5vx{#rihM$NPluK7+c9uLtBhjqMoAhh$AMw)#b_`$by9~3syZnt z%P!tY)aWN0hA!yZR2Wn19M$UR~bRRVrk~)gh7}*G~%U*HQDw){C%H zd6DBIk{hdz#;nQhR*#&#^2ISdefbzyR@19Zo&a4^+9PA-Q!N-aJdtkg>}(KK@ry#J6)z@ryFjpVk7zHD&0 zFdYsslu?EINOK?uA-BX3O5a=}a?~8-9oEoU0w{uXU81-?vH$HSL42y&zv`K*TzX}q zW7fH;;=@(ng#0rX&n?Jj!BV8F-IRyNJCH@atqq0Em1JKi z^4CZw46r#1S3I}jMOkA{m@%Qw+oNvuZQzHnQxn2fZ692AppGlz%_W(gf@lc>jUygI z`l{mN?l(K`w?kl?$25*SAMYO- z4fLN#a=(5-C(Wy+)?0s}eVHs!8O;?DQIPOXHw$j!hdXYQ`E$nj(oy&+jp)A*8Mw;$ z8>gaJeWN$%NT`IXqdr+m>s{Nciuh-Cp!(wB+13-{m4%$_?)>(`>8*3G=zd1l5tF2~ zUk1=nJg!E*$ORb#2S$6woFLhklD7@lkaap8EWnz%n~k7$VS;gK$9GjY(QqL@ulmk? z7F#V>15gE$5g{DS(c(hIka&-<@RSG%H6|U(#eMtm_MM?DFRH-jzjcL!BUxtU4nO9F z=i>DxDxiP-D1c4f8^a^BTdbaX2*(6d?8$@(l^TE?aSOh_WfS%{P`pv&btZ*Po2rE+ z6>Le6&T}?_=y4H)u%Ud$iLRKsc_mn?1qf-w)jdFBuI5&MP22SX7h>?xs$K$qA8@-URJQ({(Ik12Vq7O4JFG+b;kK>mbt-+f{M z5j^~aQB?vH)2bA}6##`|tpH!;v}_qS9-F+CRb)tDTe*FKVr2(dU=4uj1u1I89^h26El6#`PALQ?Gsfh@34AnXVQP+qoa-KYiZ^=$8mexj^ zM!0h+4|rSkj)ur)3l}gNGdD-N@e$6~|M%C6*CwaE*bGO^`hQy1LKft+8+K!wp1Q4+ zEGlG9lzSMP*kgCi$uZve1E5#)>@4$|9o*BBlYmNvf>tD;Jt45%z-Sl*J7a54A(^^z zTd4dEI<=g~HdeEEpcqr*yg1^^>iO!~nY=$0>}lofNoz@G<3ihp;M~%vdjkDCgc-U{b&KmM;2gttxDI$h&JEf)Db-k$%DlwZ&BvzZUz%Yf?h02XN0i*1eD zx)B!%+&SFIFWzyT*m~dL;KUP6Z0G!+=L%HHw#Cie63#SJHMyn(aQ8-$%#Cra6&C%j zyc7X!Xdj?P+Wb-9m_Xbo93tNdj~?RNYaIur@9BfDxmig&Ar?wMu9p+ICh^*2Y{0?| z{pCB6Zp*lUS-Qr{y(}Kt^vU!L*V-V)X=Tc9N5m>_f-EQ;8pDMyk!q0Qe$Qgs$`e&z z(YZ0Lpd0OU?MJ{-i6HEUifLOMB`WPo+nyyvH;DNXj{iK9y%h36Q#v*{QP|~W7~jd~ z;4gNaDnMcIShX23L$0>fFQtR~;iP|8W zd`_T@9f^S}B&c6Smm2NSLl#m(PTLR}_- zjTgJ5ch)$G5M*?W(=H1ZJ>Xo zKqQ)WusNsz)Q`^$y`@7hf7`NZCGp?(ilf^)YuD+JU*Zp9qKAPJ!nHq2zVDnah=A8( zP(oX$27e$}Qp>S-*f&!L8AQn^c$Z_B%CW}2Q}o-ojH{>f_?F-r-f&1zwUGCp&nx*O zJ>=5tI9BSv<6Xc|GS9IJk#pgL$F(QH8h~J_z{qb(_$5G2ceqXT6!%`ob#$?Cat%-o zAeS9AVu^dad?l$92Yho9$}bTnKo&9UCFvYWHQV*qw5yU^M#g4f62dKrh5|*=eaUTgbQ*XNzJ708O zz%&5TApNukK-1<_o?}BQ=&wEH>wqrGyL(kclsjXr`gaLAtz~jrIpi&uHMG{?C=}m$ zC%7Hg9YFFQgWt(FpYnu8ICa_o9jtsEzn=8&2`j!RdftHsa#{!c{U;MNR_wk6N6vQ56l0tp)xd z{dKC0u3sJHRNX|c3P*Q+lbI_UzEq``5xZDW0*4KTurudeY1eVbL+OI<3(6@7qi^ST z^v^l^005>^J|{9P9Gk16rWG@{@>OB{P|pWf<3xpMi^Z!#|Gc`iw+$&Rb-bck&V5hA zb^MMhxvwA#r*&p$gU|VQ|F5>GazNo7@|u=JM@gSt^(K<`IC#id3HR=6fj0Hi-mAZp zDrp+awK>J(LuoH_ve+Ws(v=oyamotGgdhYdT& zy^}de{%s4-t2A;;T0zXvD172YCaf5KPuc4Jmwfxvs!sHth9YB%@tF0a^6y&+c7I$D zv1Z_G9U+7@_#X2+M9Dpk(=krbdZ(7YISJ+0j_iQ>tRZz|x>I&jiXHRmLYF*!;k>vf z)b>Atn_*LrhJdX~89duazgSthFl|E}vr)B_lv5J+cxWXgeO|#nz9+QB&Vc1`F{^b) zw{>8gdlFTM{(ka3IiSMH`s7pg9WVxCgR!4R?0T})w58qW{o`fKr}Q`NV6k}9JZ6B% zWh*E|XH5FVt%=2h!_gz2?0wLAePk2PjL_b%5Q2$i2-;k>amZ9Z8I8L!4=DRznezz+ z&@Q&?3gY1AE2PC4!$xMH6^UyRk^8h&Up~Ks!RW~S#!0d=yswYy$8mZe|Nr6&W;eZV ztM&!NkP?r3!hwbP)P&oV(0RaON?-+KNV5{$u6%07d7yHAaX%YFk(We~4k-o-Q;3Dc zF!^_*HQ=xOBUAc%0Alvy3$TR<^yERFnG)g-bxNOZ)yDohM?Y&xRi{8DjTf}Ll!Cq= z5jMRf>5l?|LW;9*{(JZ|b^KVi`6&AIL`9b^Fs{rDpNFCLW$Y{!DAz>=|NbcmBpY!N zjAtmHXN+by0QR3Lb%_-NZ7at|e!Q*^a?V{JOQ6#d))z`IF%<7zcroH|ZO-#i(|;=W zzCXo#Hr3u=2Y4r$Ee!8+7YC_df#9)WmITfvytTP*LeT0pqVCY6TZr^fZj;7~kOOf{ zu%M)`>aU-g#VkyK^hpl0G1COFTq_l=#gGG z?&c3l7@eB0UmVg0TZ@P^W>X-D8j8T!xR+b#J`o1{9OX;o;j+(!?;uf>jl_D&@s83* z)5l4SyJp_Ni?PRU5DdmS2ZM@^ii+}q$nf+?U zGfco*PNHHvuAgvZCGy*f>SH2#BjYf8SX}gbCm6$+gdKaTS@rxA5~> z{A8n~waYI&NjBF|XvoT5l8G-!pwOPYPjZQhVz3-L3=LzjjY8dtH-dK)8I!wUfB$SB~Odhb((Tn#CK@oJ3J*Jfy!(u zbBTf18~nU5__9mOlZG7oVE6!Fdw3padJNo_{dD_7mS3a>-7;$BO6$1%^kv$yg2Jdn zG^}Z%ZznPOUDQEZ8TPUfr(8o#zqrgwRC|<59QE&R>~T7Ad(GqLnvOak7+4Q-H1Z*% z2Y2vnZGz?L%#6mUS2LacDc+qh!@5C?rfVB!2N0yie&Z~AmZ$OH_4`424T)UsL5f1s zAVDpQIpf(rXTf$8EF$~`{=Idazwbi&L&&=Kk`85xYxHc!9Y9BjTBm^ZX=nkL%&^{^g%M*W4=(0<1?1u(ntrzJXLP*9ri0gxwE9h+8 z4`;0fyH)ab?Ks$4X8`iggZ+5q_5G!*ziElbbQG7wktEenvBjQUSMsSLi?nSSZ*AI7 zqW5VYv3pdhBmcC3fEE)d2VnshXvANlVruk2jmc}b*>lrB`Q3p4I1AseORFzZLK<)F z0HnUe4q2*C33*_AjPR4hdkde10&0Zn!6+m2M~N)PiKy5P|2R?vq16N4V&l-HUk;B= zZv5N>Y+=dgX8vM!M-{;6DoPa7BwB#Cycu|(1XG3r>E3jHM+1@jBhJ|AFWflOg}W|! zjLME&`l2wc3*ydAPldas=Q~?2dB{2i6-va3=2*fd7b(ZiOiZG-m?-tJ3e7EuMM7N7 z8h?^xn=dCBwNMkoO7Tv#a@#ei2uG1=S-2gi_U^VAd4t)5x*%1;jC*y(bOtqyLC6f1 z_~ad3Rk)yQbzu7hEe0gQqKh zO4CKzIFzE$HiaEBQ|256nK;{~^psBgQ(%+jiF zTY@c(+7oFcw+1kOhrXB$$}5lQ78bFwVXn^ZiIaq=Y_?siC6d1Qn+$>a=2v6co`~Zd zh%e7fc5i^cbMPzW`OVO6s@VpO)zfCF)tTG|nSCob{_&E-++V*0cPTr5ISv z2q{2qKx7S!i{zb|u$oRRe4h_m=4(hqGcIhq<=zvCtK2HXvdWOH>0p;tRSwyXahOp`hKiIBaP$#zGStE#SuIt97900yGjec;VX zLDJH#a#qZPU6O)a!R4(&i%e!5zxO#~ZNUhTUSIVTPo+dqdCpb|er`>=-lI#vN9^}u7o0MKZG`?bDB7B3{~zngp`^jfx0g zDGzG84r6aTbxyB7Q~1$?y4m{UE03U>UZyZ7$@+7+ffzCP3N$4B2 zdK`_^TvD3*qQHdgDa@t3;kbat%feItmeCi-Z>&SR81i?#y`+Vp|1R(-TDdOuX%t@~ zMRbp3p~rW?O7lr#HS4tggqNuGGA=we7w?EjQLn<+BK!@L%=id#=|q*oS`14==Qz9! zNdCQ9#?Ws3{|l?2!}Xy*zeSGJgv-T;wKs$>Ru)a1X1F~LrL(?XwFc=eXbN58EG#-tnaf?y)H zbNIu$bY!hb(P3Ur=qE&8vjZhPDtlV!4dJioj`{uVW^;84a3G=*>kK^5wl`+}o6d1k zNU*@!X2zbO9B(R@C#1H9e*&^@b3nWduO8pmAE+<=rmKrt)VsI8cA_^iH($ufvtve0 zn)CsZ&T`6^rHfD2@0`{@`R;!@Pjh9U?B2Kpn*tlTI}QSdDJMum`1l93UqJ*DI@AAl_4(=`dLMctwqrz5p5~wS`JN`m06N%reAhprhB=4v6fD)b{ zm@$$si)UJhSD_&IpxHW?KOdLcqlH?OXwV*wReEFP_-bb>fs=S zvD!M6b1Zwo`%k0s@f}10;sP}|Y1172b=smi-_4T4SYrNFkYLzoE(_yu@0u4D-B&9i z3FBHbR^Ud(Y2a@?3~Q5?HMe}K!6tv%_UQcZdBkHu+H%%p+sTz&z6PXXsDmBHi@eXk zdTsQ_4F5kiJ0e_L#<9E7v^liOH`cc1w$1~qrY{Ip@GMQUq8ryrx(79Q*}p4ayso=h z5l^%g2*ugs>kE!L9BH%wS4q$@;ZIJTgtl?r(SqxHy6>78Zz+56-PbVoG&5$zXa>G0 zBb8G!qBjYQXc|;yi4Sq-#%o+Zb;`X13gd^;BK&=%ccNRpfmWB{K~t3uGibMMIpD?| z3qJg)lF!EVxB!TXN`R{rI@+pT*_k+wCCGQ!b+Rwf!sf07i(j1suBT+6kX* z*02|wj#~F;Ry{jL88hfVzoL5tuEqiH{tO)PESIjq4}3LY##xK`hxzB6i1n75;D~Y} zw_S_Hg_<>}b5GdjVEY^aWh8GeK(j=0gvo){&OtWjTGe)A5<)v>aTd1_CwF0zhXLuu zjQbVF?fUqpf3T&3hJz|hMg=g)MF^KbZ3GbUbzqj(peu23x&hD<7JDNBY1ZOBKkUGBE%}<=DkbRl(7< z^-a6b$G5ucKjhrk4;A9_#^=)@8?BM#d5O2f0wSp{4* zTA?^{2QWS&{y1NNRC_G$@Zjg!+0>;Ii%jptYI$v#!5RfPDeSX6zPF{hmYx#^&t=@Z zk=8bV+iXf3+rHnC%Vxh^hx^QJUus{MyXx4BY|8cIpHzztG5_pf z@M?#?O<&6BB;}3ZjJGR^Q^zDGcHD6(gR2QkGgi?j5R46rr3_WS&GHu}@m0jm{sxuv zwpBSXzW%IP~6lBzVd?m-Ti?NJ=0obe3A+eceH(Lo0CRo*&LS~ zK1sIgH@2>5pcEd-au3XB6DOs=it(KkC`}Xu4>EsiJy8jK*}f85?(()lFGdI}@J6>{ zONI(L9P*~Qr_)dV!}p2_XcsSVp9)h*pt8oI2%D&gWR}`=t+w4ft=<>|IaacytmfS^ z6FcL#&o*_ng!7+eSHsAqbCB#Qye#YaPQ=-gRXE2qaowsaNmqN)tfVT;baeh2-WHp) zNhw%K6NSpP#I#1~ORay9@($@#FkY_;fFIuR0xN>V0)!?}es**uUpi<#<>>qPEqH?7 z>S#YO&A7V69BCsg>P+`gzz^SM4-=E81tMx1p49BpR~2k@0)D+Vq(x7L-1(N7GrOFI zn{q9nMhca%k$WTknIG!{K3-zHw9B6)ZcS0tq$V^O6?F+>F)1*SKPByF%Q8<`s;sb5 z`bd#toqrUqsmk2T_1+T~qHJ#E9sp#BA2{0rV~zeyEl~MiLPlwwm)XOZlwK~a<)K*i zinMrzFgu|_Yg!5ChsFK$LEP(i#tkHwHSVoU14=P0zUX!UvfK+|u%lsMh9FV_8WcoS zK)?O}Cxx&xt4>CZar|NfH@;GvM{;yt&#xQDt%4|x&k7QUi=u-3;o)ff4ztKq=H^)# zJ^{DuChqt0vrnDu&!zzcBshI!u(tu=m`mo`AKI*lEUr~MxlUU0L|T|4FRf zcqV$TrU`l5K-<+s6!N~@zqdLT?WlD9CX8@wsjZQoe5)pK)8nEAN(7)gPX};>TwPS? z##FWzUQEmkY_R7qztQuJ1;CUF@&r z4EDk2Pj8#!fXWd2re&}a?~fPwa^-tUF3{~E+(9nd)pmPGtDE=cUBKrbRVM48ScuuNc zQIJ~;`uKR(J9{dDR;MFwqbUuebT^-6!<~UyNIbyW*ba!mC$J%7RUeO}!(uOp+4JJs z;*F2NuPLZ6yA+4vM6Ed5MK>$cEm@b)(hET#x%N6(#I-wlB*;F?tkE>3 zJa8t!SKXO%FxUr>mtY1mv1?{`JadWzO~Y-#8I7(NBMT43P_80?`#raaE+%d^Eyo(n zIl2`9y9zm2F*fHmRwReBZGeyi;gIAGBKDtmuvNM+XV z#s?cblIt3@OKSH1#PdkO3W1tsmMdI#W1}EfT+2$+BfcN0uKg5yo}=3~{h#MZD}rnU z0l&b7J6)hVm{am$S0wM?S|wEQpRvVEe3bGF(E=kKa-Q#V7)^-f+a;+~%0MD6l=p@e zj5k~O_K|3~#K>5h3cEcw4Sg%7jDd}3+jLtcii|LXnOK2P)K;x?om&*-!aRiA1vGvf zp3i~*H_*6(ksXSc2c@rZ1$zK6Nn^Mv-Nd8;i;sv16Hmqm1q{&buxW7FzumX9-C<-hvNYgTZ84J*7;yaUyjNI}oL&$n8%$dzrGj zUwh}YzyJ9pWE(D?_Ylav0G6#m&1trR?z1n(ya%*&{yQ=TAS%#r(yfAkckJ$sQT$L zqkKsR>SEVv_rT`ty&&Y$#gz6V2b~kQGZbKUw!pI-i=8Ng@b>P(U+H4U zLl|JpI(0lB=nQC-go)MCP?Pfu>Yzj(oK?F9vuFxgqF^G5@byDST1t=T-CGhHR9E+aIk zN4%P1w{0Uc(PA&<1!HDeK_>5bY>fTI$^*{^FXXynB9Br#13}~sOEO!(Q3u`Q=B5Be zFhF9;j$mLpbl20{|M8kmq?KS9&HgjA;D`I4&ApKc8w8pNHB@yoP#qZiXjgT`^hZdg$ zk4T^&6V%IbAW*cRbW*t+m8Ed=vh(mdjD8}$NX1f+rMa9xW4}L;lNkc6luM934M`}? zB5F*;Uz0t*0r#y*a$O4hq`lOQg~0yzuT?D%@GcF^3!9rUH=i^#4I=nC3cz23K1yFI zjq4amZiZdV10)i2>1+hFqBFQMq%lPrWu-}bJnV(@n#gf~>l+1;DZ4 z?P~$j5g(aL?6A{L?vwc?9<2@;ll6{aWa;T_$tZG5MNa9I!_5ag^N{i z3$fPma*t8u&=IgWCWAZSqx6DcEY@b~KmY&#-1uqfP=JNcq9TZ?tHq<$eRC^PdObkl zwp6$S)xhFeTgqcLD5vk`1BY#zR=a`y|My+LbRe)l+ZR#tZf9BVJ-xD`7e8o9E(D?- zTHi{Q{f9k%<}}otayKx7Fx8=Hx?I9XGxoZsG$g|un z>|*xsZHlBh#x6CaB{Xm43H-$Mky}FX-z?O}n(IoJ)~@3nAB)f0hB|jW{9p5ew$P#I zJkHa{o3q7n29(F!)nuD{1WhhCx89|=Opnd35OMv^Ax!#1nlqB^y0luNM3F3CaS~jf z&){2mFEt@%qg=$stK5s8h}!}xSQk3SOQzK~ZQ}KA#}}%I%&tD@5)bV;5hX8y;gD8& zpB4MD2MPSRpJT<^FMgVXP`Ej??Ep@_rXJqCyNVE8y`NcgA|}DNT%-r2sh77arXZpX z!Kxqi&56|J?GM$S0;qVkI9FN7>aplAW_jRZPdPwV=h!1Hl7 zc>8S~lpr24Y-M|_p8|gDa!szDzd(Hn0;~KBcWSvlMcbj+mV}A-pl{xu?)t|VyT2aN zp~NSUX+f8hMa>mL`REbR-9-_*3uUQEfyTCK-9`sl^FM2`;OvvC)!o*)>&?fFJ3s^J z#+C`yP&Y8}ifB2UC&xnTOE(^>(MuY>SMXTOr1*loY+yllQRc8`69+k;1X>KHl%FJ6 zChjF=GLDgA43v(D#Llr^094N&7en}6UGmCAP4{(%2%6_mN*yce0%Zwy@^m?bF|f8O z)l7N5ZB$*gvzz1?qMvYpP-bB=?qSFtTQpA=Zxph|;oS(rpu0}wF;MwCB+rjHqMz>{ zOLBoKy))}$-Tnu)m#A1iYIsMY|5usURSgXs>Swgf0f72XDFx;Q_em#b=nx9RYEPC} z4xQUOrIfRE`40|WNDnG1l|)cA{Ds_`llJcOu)Rw{X9|k^2j+X=__D32S%MO^yY)A= zr@hq49>jnl((pWtnn4EEHIu|Y@_`AjaghTXLn&f_a&=!$!5L`3d82o&F46sr6r4Y4 zmM_7$(=h`+qTEc*kv09WXgN{7P<&5hb_1d;r8G5%2rIpoIY3ay7#}%fd5VuGn|=L| zG|@n}1r}7}p5DH@ez!!`F}kKzHf}20Vww7aa{wk}x}IJSmi2(=9YCVt2;?Vbux1*r zET+e~6plV2@DQ*I9fHoe(li7ek*`jwwBB-ncF#Qo3q za{!?zpsM~$y(kVqO0D3ldHvWDt$28f$WzZ^G!XJzCYh+~P5b;U+sx8p07XE$zn+VE z>Zy_PXpguezzPndDqb?tpgdjwU(!IyLiW>67GeSDB4DjMjZvSLAyhx&k@Pd47iI!k zpzbsB)6>A1qD1Qyn(X_@ARDeR>@E~*e3e3TqyjG#)A!VC(^%C;-Uv@o039+SH8}Iz zgqco_a=f<4Gmjrafw#iP=Wr=*rjXAWoyG+p?B%$aC3KO(YBUlXJ&)VkRohWrY{*Pu^ z0qgo!>$Yvc1M_nKa%f|mwhaT^@;0n0s@B*z~q*Yj0ijhC{_AS~RDi((Ed~ zzsW_32ftpi8o@M{^StJK|BS4i)pPk@W19-zbe6j;wSZ;%(i{(dVHVuutKaLVZogp1 zyDhOcI`}??SR{g1F~xu`3Kiclp62u4jSbakXc~~{8a|8Vc)i|M-jLcUPu3Uz_|I2Ly8VXiOTwCo zG3U`sZYCvdI3dHM=T%63>UhfLy@7U8WRnT1*l(|FC_8ScSpS;3|C9xhhtD+7{X!=n zvDUyjUd?Yj(%t(dt!WjPj){Hp)%ojeOnw9Bh-n2+g`(~R(H-0Erwbq#Ah_f?wxKwC zNU2)V;_(J7eRtlCkaD&m5UZ}A5Obtzl2~tkv`B(ZSfZN?yoX@aVVZfJz&AV79d;3K z9pRB3X-u=Ab8~Bm$k6asWDF1do7wAwm)%xXPQ8+HjS|lc^J=DdqqMYEW{swne z+V4^m(hX9up0I;olW&Ci8_x-Q4O|w8AXv+2m>lpf5#%Mm*!SiFOzE%J!4y)hCOB7q zd<^M>nfoH^K^k~~-q}h+`p{r!=4Sr1DzKo};|IZRsoJ)XRs7+h zIszAWm;U!(F4ZyMP~zm7(`I8eN&N&FGe{`J53ul}6h(Fv#o*jj5s710e;BN>GO?*4 zG5r#U4>T8}s!r0Q+N84WXa)kI%kKaygD| z&(v)c@DqL%KZL-f#6K_Cr=DODa5`Ijv~aRhDfsSpxhKtU_r@R9W18LG(Xn(X|EHe7 zpYo=4e=y{}kU=?uT=A(^b!&{IAN0=TU|TUB0xp~ znA|v_1h6czg74By0WJQ`ZrC-eqfP7rW47Gx7;>=@+RWhWOX|C6^S}L(=)hkYS(97v822KY&}7XOf>lg z!?*^cN2Qz<{oN}lJ`m%Ccfjzi0a6=cD8RQLb+C7l_vkPH7iM4ci)q^ z-T^faglF}C$=`cCS|&+#+n0woVlK?-@fNoR$yXXZ1wRj%HJ!$!6CGmJ6wF@Gb;h6? zJ~P~9w^(=o4R((C7}ojvWHB@~z)3f$OEfQ!wxFM#oI9n5elnV2->S-$9FO`B(YV7* zQVZ!1Kp8q%KwZ8C2FS28$+9b7OF6;xkczJJ62nQEchetRZr8su?6u`4wMQx8Bo0@h zSc_h0rkzpRem2Vnt0QH~yabMrLo<>?0q3hKBw?PF0?xqlT75Bkkow6^jCMUhmNhm~ z+(}-32$C@&Qbp!rj)o}+7_zSGuy-XqZNvn@R`uj0F{)KuH~-x-2#$CZAUf0T7DNQu zkv6leV^I#=TcgF@-TBs9s5|09l#lOlZecv+2a)C(P41r{@m!1C-aHx#imXJZUIq!PVP4-ij1K97d^}NfkZ?AAM|F*nP|LLoomBZ|@ z#LmUL!bVlM8p}mNR=Zj;yLDFqf|*XwOQ=h`;s4Nw#JyI@inKY(A-B7ipCP#~h#1V5 z>xo{kI5wcmRR{~SC9WS{h~zh#l#hk!RDM8QsM|;JS-(mTv96(!QIARr-h=;n`lB{X zbE)f0OLIJ(PgBRIZ2HCPPt6;bgcye)+iZuw+5RkKWY|r=VfpO&{Zv7PWE&zx*QxBe zeSf}IjKOO?fD$&|nHevivla&oL3ueLLlrvA9;}3BOS9y>*+v1ADgKIJq`$vg=qx4L z^3g6&!*?dH?wTz%|1W5fv9w4eS8?M>7$-7lMzmOu3wO^@@a{Y)%RdUcQ#ID_Q0O4R zE<})$hwW1H7Lv%m7D@Mh<1DIyKtTkL;|<)yZkf+M);0VhVxb&q!%_Z<0&J6-Kf)Sf zhQ;3;5lCvxX;iR3A9sG7J%eDGWc<9<=Y#DKrCvu)e8yVD%0^knz zeiI%AkI2W$%rTyIergt)m}>>ncNt&U-DhbfV7MQ8r;2+SQO%P=ct{z~>%@m`Z;%s} z2dygZ`%e3@HX^h;P#`uE2K66GbgVA9p=HkoYYoCj$8HU<(ONDS$W^M-LD9 z4M0yC`X=#)l`0k!u%{aW_p@5ZxNRmRHedJT4bQ^u|We1*@EfJWd|@L5^)0Y zhmMCC&wAeMw72oSppNDO;?W9waQISVz0!d)jF6j+`Y=gu+G#Ns_{|JaG^CI?r0sLK zopFU`3H|L!&)70Ne-u9iIJ!ILQ-Ogv$al1hn{jclm?uVo<-9QP4>B~J8otK4Gn2ko zwbTxo+nEnPN?0_s%h+Q829$#Dmh*tTp5<0NynxhxmC?(!INfijtP?`@9wp0`ZoqQH zG@=(3`oYHdU(fGZn9bvpCex9lC>u`{9^*T-vwG20{s+!oFfJPT3Fa_BI{5rQNv7s& zXET!~;iqFSV*7r$$GMK6MR@GfC5}l|_69Q!JC%-D?AC=j`)3}R(2Id!mwNJZGY11f zQpN*3aykW16t0bRpvReA%)663sN(AN7fBlGwujz)R#Fi)7I8u@aDriolJBs9TqQwG~ zsQ9anIe^~5qY;+AvV=;GXb~k{(+^$%F6b%UCC}^K8>+_$ki5C8eHGY>2#9xl7J}x6 z=>`w$$w|OS=7?!@%Jv=gQ1(NeArYSfB5PaJh1Xb>(S7oJPwOQPhH6sqOFe?1ti@+8 z%_7zikYMa*@>b#-PR&(Dy9(e6xo8zqQrkQopZ_}4t1sRJORI_SZ2e-oTWD4z+MGnb z5^MLgNGm!_hs9#CL3{yQ;x@_>5BzTU5@!NCEo-cnG~x9v4Dww>>*tunyR$XLnw|zx za73+LUt&c{EhanrDk&J(e%+_?JddC7Waw^!a)CEWE6^degBoe z4Ccb@dO{!G&u<^1bT@hCxs1X;&LDYcCnj0>_<%Oqe$FKw%%^PZihY9jyE{q(+Q{&Y zC&k~y(qnl@QXhy;)M>S}4-XryCijUnjERb8e>QWUMJ3Ri72Pb9LApB3S=aZvt=6QH+i@*Bj}}L~v>ntHqVY zf=9?TmUak2dYmGX^acHIKqM-pf(YY{UUzfh=gO+dhXi$_Dho%vdqpe~!w zRLo!L%3}XNmSGsd64#GH<~zC($6V$k^=i|)U9*x1yWqEed>#+>YbxKAe$6uTOp z@>Nyo2b>0Vw7YHSFFNp;o(+(h->)=oNdo1ntsk}9d5NpFm&mrqeurL0Eb)r#q4Zc%L~mLi4%X>q zLPrmXK8R?1Q5Lwd+QFM8g%# zCnx2cmLipSc{s2|3X8#uuzT`4PN(kDr>60&6MeClIs(9r2!RLemHEyT$L#QM5%)h| z$xZXt>b64OMdxyw7GHEDh)9Lcgr(pS;kxJL(bO4C7}Ihodz}GXsDUZ(w2u|Eq3nfXgnsZ+*PF*C@v&^=gBc>;?eI`ld(>c zw#$r9{;D0!9Q$=FAZ6eKg2RxIqKUY@Ry*{!^W)}MT?wAzw1yjI(M__ZCy}JL6 zn5i<*l!&0x5(R_~uru)Mh;3(3s+hFabh^WE0>JFrXsFq&m+7_mfan_w#c0ts%q#s3>OZa*GF zW;vZ)K1;{HzfU)#rJaQ2S&;u-X=>r@@~w?XLci}9ZW`Q)zs<-;r+a%J!gu4a`hYZI3}^)m_n>Bg_90M z;m}`+Go%Ap&9|_=;vRnoH>^c|L_E-=H6rzu@9l*cW}SyoXqA09RRfupqdp_2bJoO2 z^U6yZotnrc=?^dEA_)14BGoJ8Nu-kfd^PakZJtEVYGAix2Td>89(7Bfg;A#cL zade>%zS_s#&dc&s;!b%kar&POMOJm5-I|Rycq)H*cY4RRCicFLeIr3%s|ab60Y2LnaQCeA;s-nfvqInJFDQOEpR6lf0|h`!LXQLIWp(eq+o8=q$4=5x*o5BP$<-g ziU@gUH8-NT87{QR$qkCg)~7_2h&ofE&hzCO6<6v8G`M9W)9ny0(C;v*PlJj)4rC%fv@=$lJt)vu?Bnlx z-Pujc-Xk5whg)sJbhO&vtyJqsf2mdfkZe8JKtoeT1A9h{bn_v!<<;!Rk^{DbOB3Su z>(nDUakZ;gFE!9?w&|&l-+iNuS@f#;$p@qu9;}taUiHMwD%ttFJxTQI~n zUbtV8ColMilK{Ce!4W#QxkHUdN5(D!mY9+;T$PlWG*;Pe8|VK9nzLSnk;{(oLS)c= zc9@ZuB^_LSJDh?RUu;BfKfMuctXxHxe_hUHVzFz1&g#j=_?9nEm4d+Fwkc21m3Exg zq&F~Fl*@aZG%ejmRC7#@UG-D!h*GNw=Ko0C>oNu5(F%Ju0xRG&8qfwnyrEu_CY*D? zRGJs-Iru{f8L~lR;0@PXT$==sxuJn*!~v%vT{4gFH1JVXS~yTp+(3uD^i}Z$2s%F7 zZ{U3E<0q!V@r`b)l1F?=>Bex+f{u`|2$+)1OAG=EFoTUuNFytYpBHeMBU~Qi_dcrC zc%zKGXxGaI6vr|3(tfiYv!3TF_O)G0HcT~P!nLCycgiFzf-+6&Aq;pb4ugx|RiJan zJ_KvlVHN@u&nmy?~mZe1v8 zxGYROb^+QQX7hy@Wd6T72~+I1uW;Hh?qb`Kk>={}vVPQ~pfN28Us=s1)66T(cY)qJ zMNJ{1!A8Xr132YszR}Ital{914Gjko3_4)eHW;+7eptZLIg`G7ua;``Nn zKh|fNl9l_^>jz6DJ*7n)QhY>+CepugF?`q+50<^{mE=<*&4TBJooe$04iqU#IMWSX zkI@gdY5acbsnKQPT;}TwmgV1Ppqc8zr8O8f!(xNn%OLbfcK_8f2EjT+x3uHhwW?j(uf@S@oool6h5Rx`|9Xc#%a(>$UsN*hkf_C zO8C-EfH_9X6HTN5!c~%i5f3-?C`JAsg{Of!iFge+sv_a$DJpWwq-#W$XX&c&4 zPcjE>r%8(Jpa8JmebY7^hkvV|4}@W-R1HC}hr`{`%ZYic>2*0w(i7RlLjgt=Fdv1USOFk1P57s&k#g1=kc)VN9?^fJi@fPHv~l293PSS-w+okbYi7Gw_%CayR3{hr4V!SWAdTqm#$|$oN(b)9S^|2Fpm09f$eLi7X8;|; z;_PrcuuULl;W{9PL=afXOvVhkEH`TPqFqXvNp;QXxCmmM=>9UAcy>xNg#MaY?utBl zdMlSH$}dDG+&pM>;;$s77E63-pe88;Y~ZBJl|Uos7`C%7A!S6Z>IVDn83^350qFwO zxx|?~@yQx+`uVLha*Wm3@tOF4wtoD$p;syBSZV8ljUTknq}l9+PLp8OO{IRB1lJ6df|{Sb^NUdKotY zce~;>jI@$M$%j*Ja>xJwo!O#1_P0=2gwz?zO$5`CuqGa?t-DO&+0rqX+{+;5aPo7xgU?=tJ$9sHSe%UPi8PRi{hC-Af4F?G=pE?DBbypiC|h z#o!eSf-G7;ZsNi?YHtxF%l2a|eaBD2RQ#+0QcQAeU+}o%sTT9h!d_OsDyZOoLRTvF z9@#4c3kd(;V_MKP6!5~mK5VC8aj64k#bUtv?L1WRBqWeL z%@XeKL&XNYLO&@BxNM`tbZ&LeXqy1vCN_jA{X%NH+hX_hziBpre)cq0@IW3(JWVT& z$I(H~*d(->;4GXUXaD_`?YIB`)4b(0S7R1X*(!+3<_jd-K2E^mhAJ3mazNg?iBsXO z{6si%td_OOnwnt!kK_ShbUOJX-p0$O$y`xOtkPt@ZTL*N(SO6#ec6mQB{uyq49!#1c` zU*`yphu2bH4!h{L(vO}h|Np^$z)dlagsBecV+KC~eHX8L?XlSS;gNHNi#li{$%yMi zj@o@*t6lQN(#qy}_mMAMH1>8ry3X>p;D2IV@)2_s&Z6^#xFCWwg}+AvGJIFyS2%?3 z+sV0-KR!xEJ;^Ode+snWcB1m#Iko9jHJg~WiqOM%n7pqrc5=~_j#3T)0N=t8dz{88 z?$Bs=WyN{!3+}gvU>&f7c$HE$V39uc{|!Cw&(W2!Xu(ttBeqF#_&{#k8w!IU8#>iv_k4Ua{1G;DL}kPyg%KM||iRMe7^ zRQjV(eZRpHv!#JYpB3=<37H*9JP6od$B*_%Z{0F`$_V4mc5pJ9W$A)0_%cUg{bXVd zqA*?)`~d7SLG#So93t~qO|gWqK^g=^R>P!yc`S5tMpVZgb@FI!@yw>bYUL7&oE1v% zL;l*r%6XXy&lDd118vtRZ?S}BFrU8icewhjmtpkkDU;WxmSAKj#EPuqL>anWBEWxP zb1{la1H8&fLazmJJuAGvSCb#i=w`9ihC3{g5zde}r3pLG?5~Y?T*@=;-}J|A5iz)b z$_esSTC^10Nwaq=-ZEklez1a3ZpTx~G?b`yFpc7%+|^!Q4MdxaTT|0`WbdkvJDJ66 z2_+}?2Cis$j4qE+n4?HTnaJ4qz4{ixJ+6_~9408=$D%q>Ue_@wX2<6L9F6M&LiI^~ z-2iwX8X=8QBRuq(YDVK9Odo00?Z}G&3)9$5@``uNT5b&_&4vu&__*}Vcgd94lGOo+sT5h~mxjWeOhc5KUu1bt}Pbx&$Qv=p- zz!)+?hZN|+NQL@^v~Mn_X8T^InoAX}frC23KUzGkK-OAvPDK{dMt%7OX_CQ1=@V%h z!9^^bL-G_J<^rzdkJA7jKlJDT&Xo8fa-H${+Rj1^nJw1|^%wg2n|B?eJ12$I4yltc}@7GPDVidxTq5IDeHVmi{(gC%fzt8)L>{j0X z{379ccW?2LI?qWHdFK0`KHM*V``Xyy|Kz7g$xmbmHSzGr8+CMbQH4eUXJwdFCpDM0 z;3z~LEF9z8Kh|+cvoLR+OVu?3L%@{Eyo}OBdpN+oA-k5$Zy0X=!u&x2#2-%?(!@VR zbw6RckXjLs>TJ++!2iRH4#&xI({NFQ7C`c(GcV$qTL0k0qV^?WSS#2zJ5{dZ8f}!q z7EHIPX1^cMZWpvU`En+dibe@B&r%c#MrNZ4&OkO$y6!hjT*%%}3H~xhNeu@L!q5>MoFwU~#wx>q0UYV;4f5z=+->(+o z@Zq&{)XST^Z+=f*AgBY+8v@+O#S)0dr^;iSK=f z80MMt_jK~^#bSYCS|&$C*uz#48JsXjBxF}_CaExi*hu1}CM;JfZ%H|(cS@$EWjdjdXp|3%OB6j_$^tOV+a>;|C)fx7Tvi+~p6VbFTT-rRhLL7-nG_Ja(vf=nezL3m8zSwghbjKs4(6 zhpqtm2tlE8sEL+lB4Yw^R_$~-x^hMuM{&w-8nng~M+z6>HjGlV#zinhV>vo`xXgBR zWs;!)ub6D=D%S(*y*vr+n4Hc1ulW5pU_q`vi+6c#AAQnBWoZ^(*_RPscd)?Hxf6=J zJm$xBxj(peMWya`_p_bO@}Gn!ym0ctyrIJC1_226~)Sr~ywl zA5xx8LOwu*-=87-&IxWgnl>3f;M?L$%U=`AFG+_S;hyzTcG7@8RDscIA(%4e+6!_} zb+MKgKf5efW@~rypi}L*i26n!t9ZpXg4xR*%c6LDMn^os_k8VGmn*5Vp6$ zYnr(BcV%Yx@5^lliGQ23kJsiu{0)GHyt z)Ci2OaS@&{<#O2Uu6bom!4V~r!i<0(P*Q7mz!DRNjWyAZlbLG!H#e)?@Vp+Zq(b#c@fMWpr^2z(c+y-Sx>o6`f{W(4yKZq6f+4V-WSkg|5s^cAjU%3l~ z*(b#bROf+!hz8N|tIY8W$;cR!WY4F=qej;^h7d}4!Ul$6zIRO~X4#XBo+P!QgT&fh z$k+a(1{88V4fz{IAr7IbJMTaNHdhp#;FPsU=HNI(pKFBjcN3?^)<}YkxNY0#z3rd+ zaHmdzJ%VilFw>`^g_Q2X?7jA}STzZ$UHugBiLd1_v56j5SY%{P?p!)Q2a17sEfWKR z=N%l4i-lh*hU|v#HQ_7ZFv;2e0pY-pRz>|49|Zj%GgVyy%zR z7QJzAwPPSz4#ky=W|~1M8k`pDcrGMK#H>wPa~=W?iNcNMUMHai^G$Pwy;2ZKud1TDtO$s8|`GN+Y- zsIM$_k(`e5FsGv{g*B%frnJDX)OR#yyb7l^5%w4Z|Nk}NererB=P`ghqyo6f)x?{$ zt$J4BsM~;3Pd&L%uGk_%>W5^h@zP##IzNEWZZ+()ZQMvB&x7H3^AeG2swr--!~m;s zUwk;6m(|A~iJ1w-GH9+8Y3|Z7>uyej0{Y}}Y*0i!;|J{wQt^HIq9jJV$+(G5^1&>R zv`ysr>kN}Y>}k-`ejv(LWGrcSDfoZA6jT1F>HYt=RNem)#+OJUxe+ao=~Ia(iIU@u zs_45vXXN_LbY@q_ZVfV(Ey8K&e7dTO-2*4t+M010*7VaUT9Hs`hTuHxE2@DM94pP{mb=78VtzzYKeV2%r5m zSQD=Q<}C%yWa)r<5sa9GO)QN_z^^J7+)=TE%?;09_EUh`iR`$SMnY~9QnKcFG-zT} zTIa6Sz`#lMC9Iq!=D^ed*@D3zHVycD4RVz24!_|KCDnX2_Z0d zW698lPrK3%cV|SRK~6wF2QC3|nreWUoBvcU4cwkAuQt+>NV@VfzBrlD<+PURD~mwr zDXb`0*n>3~Dr(z!&|adhIMKp2FfWAM2v;GW*@OcbU<{U5 zm_~vW;sj3Xo`kfO9BuBFei%qnyMYd>`u+(Le?xxu_}@dH|IlhUC+0HQhlZp_E58o8 zXpSG(#0&DfhorRL5HlqBOUJ3kN#(00j<9YhVWbBx{4#v4RS79+O&7dPP=?jYViI?a z0E0=r%=;WqG(#s1lMjwDye{etp3dhu%&0^?B4GhdyF(A7;Tn%6M0Wdn!&&N3%bRRr z2YXPJ>&^U@&F`IDk^R^cj>Li^8a-M62b7Uj1h|AmP*>op3$iY$U(529(_tPdsz>TQ zp@1P)L*;ICrcqF+-S2){#oEergL{`0J^L?Iwp~IJ_m~0EYnWVdI7Nr%VktD~#9!tT z=eUzpGjO(Aj=G)aHYH(>l>=?kzWfq}z0Rhx@-^S4 zNyR1gtOo7G%u^^(K1U%I=Th^HfNDy3xB3NF8XT5j{c&Ex3M2!g;AP~_dFLOF1^{Eb z?Sz1zdjI~9REtBc(NH#oMF4j}q(bI8MSnRS$Uy=&3AHH>xOb!tup1?VEp?M+$nyms zdt}7`l8%MVYWXB!CL@8xbZWq|_kH^P3Sxw8%k0(9B-r~!FkLUTq-BiI1n8}wu*J|5 zf81q6->MLapZor*JGt;p<_RXf4b$T{|NCbze2Q<@Z2)Jd0}OlTZ^^KZjhfn zgYzSQxqWqSx;J&IjWu=`yo>CzG)4>!P9jc|)HM)8HfcQ0Oku#2yeo&grf?A*rdGlI z4v`ss^Tn$58s)O9UUKWI>ZuQ~2VW1s>&u9(@c{HYMv5oVrT2>!S)?`XQ=GG_KQWGF z8tDry4kHb$;&OHEn_{LyM-?buxTS?w6VotXodcW84>d|nk;ky)l!uMt*5HT<;CR+n z{FOcYlvta%Z7@iA)ezovdxO;u8GdJC5a)2$4}27A3SP5FobpQj-SJ0y z^_#n(Ke$-PbU%QgCFD%-s^RoI^~R*e-fSuwtiHnuONI^Oo5Gg**^?+Da#U$I9i;&i ztX`#dq!pwfVKDGm`8Hla4NbnuP~=c+!5WRK&qzkuJI^YTXsxX-PB49QWL{UCbW^eG zpVBa%4S$$xK*J&WEHPLd>Z3hoBvVz_cokr`tb5C~pU$P@(+Lq62@)r6b5~@~n`nYx z5!c1>xjD_>qZ=ir1>d?&MmnwLh+a0ZmVM(gXsLRGVGsXchqTWfz$C}PUXl}RLKG}D? zI_+q;^uI1}9DC9zglW5$&lh8D+X?AIXM7i?;hk5W(F?YV5jTw&pi-G4Q*2eyLjcka&+nq4mKAtFF1Aq_s}bMK4w z(a{o{B@*oFBlTm(kW4XpZop-U>#^f*fW`>wxlO)`9i+rQNO;NuPuZNf*@J`Ak)>|S z{CrtwqX@GKZ44Xk%Mi~>aevQ|JD>aG6})CaN*l`w>ZM^_63Z6TWA^nP0` z;r-E%r9k*^4!d_h;4nXY{^rtn2Vxqq6T2@=fByv%^H$xYfUkRQbMYeHNa}~GV`}?I zA1~@;V(tX=fBEo5VbnQEEv}dGK2;7vtf;kb_CCx}amJaafD8s3m?o007%_F?3Tg2u z{jtnTBa8px^owH`cr*}nrTijX=`6hO+)&na5Yj@M%jlk(Y(NOk$y<6GcMLrjWe=W% zPH%y)lXl}SOQ@8Gikae$tp2A=|2ASQ%!U=#d5sJ){=JX#OK zCc@G#W}=uNVyW@s(mF;6+^auiigrI!fTeJu_N5AOzej4%}JP%N7go4?eO`)6HsJjz-+ zRr=JD`$KVY86GwGKAh-lM+?8je{Yj>ZW0g?_2y2nDtVB%N2iISz!urUs5}47wD8JE zT^H~9kT03pUX|ywwRGS(59JVk@RJ!OK5@RaP*18@iGn83Bf8PUkeCXlx_>k>-t4yj zKp`B!Q+8u{<`rsfddouFOX3u=i!?B4@f;0;amlIEk`O)CYuFoSs}OK*pb@*57+oBZ zl^s3}3{qiC*@Lh!^~u^J+u$n`qCPTeIC%OTbN&Ulv~r4neJ$9gM{|;0!>7)fQT;m4 zK@pa7yCHwqxez;|m4%`SY$ny`&#`2X+tD|^79WEAM%R_!EYii-1OkcoEN3w^D8V0& zV4Y75u^_&#MsHmUiw*l+YO)B|WSA8Y|6BQ~9b}>KEPk#Btn`KXnjQE(7Hii@wHnm@ zmI`rbKZQ28k(!z!88lWMiOC?mgJ3y@FS=rUO-}d zJNQinr}`C(7uB6^5TxsQe6o>GpX*|F%-Tc(u)5tDcsoPn4?ilqqmBjn`X8%YpFby)oSRf!p{Kshc^F?u^{wwYo-?!y^&)r2Lczq1#A*;e7gO+WA}}%cf9Zc4V5k@fN|{_Jam0JxX+_QBnHAEko5)Og<&y zr*V5bi7Mh%-#{~%e6e5u|A>LAA|#xN1`MD}pEls=kop8@y*5Tlg=MApLIstZhekz& z5vA!Vz{3zlsPMFppR)iRe}JCRc(@=<6p T(YrAnO(@eSI7q<@uF|+3+gtdhH~h1zxxlgi!W}y@uMdhRcM@pooHa#UAVIx zmM;-)NTUyMMp0gt=`V+dqrA<=h~QxF?~VfEvU7{Xl3qMjT61PInmyf{0xi;75S9(P z*Wd){*{y@x+YwOV#P<4-F*jEk?8743dA4!Df@=!h7D_47@FH;GEU$P$9~cjNLYO@~ zgJcUNPj1UEWL|adNC7Dh`EFmwd=kLl77TjwsV=pFBCGMKK#fAzZ#N*xg6PFN*NGUj zsy#%F<~ZmEn+H#QO3rn}1)-|zz+2KepkSLgLYlpVwLY)-&UGY8s0nd6fIfR-b9ljL6o?)VI_|V-Yz9x`(Iyse0LWB-W;sG!C&nBGwn?3j6=eV1EsN`El?m093)%L2S7ln=$HISN zV$BCr^$+!x`8(e4fB*mg`mEIdu!wS42XSkMul{ZEyPw`*5?7nYL|}uJUSTa1s8G7x+Ralzyz*=g}LU3`Fs>9rOo-Q=#cB!a1O? zFMsINKcBziaI}$0{6{tG$QqKc~^dc zsL9gsZ7Hm}(b1V6MK=p7bTO`Nv*tmDD*@kPNzAsT(sT|yC-Uj^w>;v_6M1P&(gLAD zvEIci^GS_pC)VB|ieAI(DCp;{&k9;NSPv4Zx>V7rno8O?3b@0geXR^*8$4eP;sZ2v zLr_^y!%P4pJzq08lLfvY8<+5SauL@xTb^HZnu+<;Ti$z%KVSKW!M)2ij7 z!@JW|Q?CE@2jVnL^K|Fql+03x02v5&E7z_ZgK9&o5tMRRidwcS7DCwr-yty(Y|)?Z zhm)c+18T4AI!f& zgf z_5O?xYWUyvqF^OM0mXT$`gyCBf59-p!V+TtuN0u{ZRx;Ij#6yyqibE&e3q9%1D^`d z<)ODy<#H9L=y(N}BT|N#8~2hmA}SHohoyTDvZynmP*COL44=UylxX~6reDk<`lyWH zP_!DX)=(o3i%{RO+LtQu8z%caE~RkFXsPcTm%iZ?pW{)j7A^2HMrp2hHhC$bcr!qG)% zV<5R0jEiH0{?r)WmoW{Vm7%Ihg#(kF+0*CVim1@#&HNyetQ;A)!xY*bikSp0C~2df z-N-Orf>Z~NG+O^y9b7)NhjqQBGsXuKUz01=l&mbJV)%am5Ok?ya`1yw?ciIdM+Tq} zH$D7D>28dq&IZoOv{tK%IL)-^Kf2K}$9?t9u`Pg}9jCx6jc)~c(+EjP-eoZs z0S(pBUWq0wym-~{&kc|)Ciy2!Vjc2#>UV2{|CFy?FBvxIU-#da`(U%En;nvl-cp(b{+~JO5;rJ!<-4#6z!D6?4$J7AbJ$YP|H~YvZ_#N# z|Mj!A?gq>h;o`%wAOG9VD7qiV)umtu!n(xf*C=!lui8W<{>Jg@(eb;Ys9g;6;*CueZ=>>vGtI1 z-ni2Ij%Qoz(m=`|zp(xfno>oBbs_jcL3wJXBmVNF?MolvBt_o;$CZ20GLOQ$$ByQE2s z0Ya7c#-oJ%hm;}GQ-v0Q4z5YBXInd;EhSTLdKC5T{84Xcg{H+1q(W7{2)fztE4s{J zJZE=p4?gX$QCvZCsnAH&+?cgl>{FXLRN6ien5+3E)~DnrqhS>7Zj0SGofo+SW-`g; z)GKS$?P!H@xhh_C^+>yJL8a}9m9`@8#|4>HvZo9d6cVB9-XU&bJI=JW`||%4r*il` z`kEzrv1W3TXjXurERsF4S(#^YPqJi?02(R0Q+rg^>CItTH=RJQAzIAQ$oTo6Riq$! zC8t2%x`mt)eX{~+5d;XseTQ?vmG!lR5T_#u0?quk&08eVb zm`J&vWc;*SRyZg8>wgaYG3y%%;V?!KfjXmchFz0U7vmnZi4OF%>&jf=pN)B&QW+Vf z;lE9&4_9tw{KCXZ3j0uaGV}F10}l2ZxDwTp{pOc>)xF|QHma?#z1m>hOqnTYxJ##l z2S8vgFZ@Ct5DbN#`?S|GO+A{5PHQ>Q-|Ri2!6qeP&CH;+hZSZvXE&FsZXEtKW5dLm zH=y#e`7zV}!5Qdi@}7xZhG}wjZ3KBNw&;@rTf-$~HT@;RF;LQiDev#G?X_x;LtXH6 z6Re*-klcTqQ$K|l-cd79H>Fho?ZK&Ak+7V*)fx(FS0zULK8ahbg*Cw;RiCr3*-E{6 zptW5H0ngm`?s6p!Vv54YQFdO(4#L!iAt<$0<^sc<`sg{`(|`f{qfBwDtRvarXem zSz`b+Mevt9PZu)zZkZH3p{lvQ9^54Wn!i<0{#Anka}6 z@a@b4Hn7k}ayzPXsd4eDD{AIeLKtdjlZX7yKUBnB77!f9J{?%j&2Rn!uWi%tLaW3h z*0d_cKsSL9-6uJPXde&Bqxp;O9@^AVD^+Zel(wfQU1kbqqAt92K!At!{M9UuWUVU} zBGdxzBw$yyR1uHoXb(a`*EGYD0U6n>bR^ah;br3^vZRT47;qR_S6~eA$LHOQT8hM*a?&Z!W~Uhsa!rnH%hmWk6f*Nml(p3h77Vh6Y% zjoPaMu%DJ;%_R0fvRGO-o9SK=ru%b^w|kVD?IIWC^EBxp-|dvNmzRv`<=6HE_IT)* zIacM|CE@@6xZ$BtD9wCrc*D4L0+7{5)*W>mVg->hs0?j5G{(h*PNyXNxGsgAUq2;* z?+5Lerxi$U&eAu9jcQ?DVjTc06E3V~+75Tes&2987p_N;IX5Y7_g`uLpgp_hD<|L{ z4cdlM&N$K0N9>=ozzLawMa4%qvvMLoLxK_D$ThBzpZS)LN!s0oaI?R5{4L_(zxg%*3N7G3eE#{;@18ik*U#;zC}t2 zCT=138=tx8=4d!IEi85&!l%>XoZXo$pBOeSjbnB@PYv3ph7vI&R(EHyMIKA8kPi^c z2`#l{Y+u`xQjpEIhpC$6s(L|4U-)*}ydNyiC?H%bIJ|7uRG-Y4$$Cp-=wE}`5HcPh zBK18!PMK1YIkI#BXryAPOkhP{&+FqOhcU{mgz%(9^XklR=(8ELcTaR}FpuwOHeY}0 z)qdhck8IfT8<}m*uy^fMPgn_rc{(546zl6nse(It7U84EAno$8X%KKnX>@EP$RQfP z43DW|&72^uI?HWlWIUBS|0a!-R~cHK{|TaDEpWBiR}uFz*1Wx<3)+A6>&5StvyC^! zx*Gz7hqX#EsX^b2mN6fs`?AVG_=i$d&H_egf#SyL2ocm0J^Y0^D);rpY6X)EFgv>% zOuu-qQ89XLf{BAJgxijsDo=ARLNBl?cfUc0P4kGSZ66%?#1ifWX=>r*_9tCQT2VFvV%$`ROw4ay$W--#XRTXH61_B4g8%vRCN zA>+h@pwSOvoX{09Ph^oBJOwkPY*!EQ6jcp!@6J3xR{J<0@>i+v59Ez*a~LJRJ4S*&H}D-ks)X_V(~JH%&~ ze8)p~X^A$SA=-e<(|=cWfC_}qpf7D=LumZ+pGwlTvI^?MvmQfHr`aeD%)tT3^NDIOdyx;%s zmYV=))q`nbd*AvrlAI-8Syg9Vj<82P@xSvFN2xq-fovp*r zcc*&oAm8v)Xsz%6nPwFE^~IBLDFLn*GCswJ7jt>v*>f0RIKeZlxO!3KGNs8s;&Vlr z>|xF9+-t|2Gbt+&IasdTZFhDh0LMSqHe^UK9No@hsEcO)@b>1zhvcqcqZNxk{)n>@ zdz(mL9Jgu5ev5B8OBSFxQH~)EL9Lb`2N};P5nq~*ySw_Sypl$XkzO??(;XAqiCvG` zir4o&DRpSjmdFj?8T}4D(aljB2p92?kAzU=p@K(a-#5=ngtPX3e^dYa>_dr3m%{<6 zLDmJCdSo`>(sLsENY>;rSgrZHwIYcX$`Be!N0Zc!?MGbT6%dd?h>wo{&Da*s)(TbO z2bGbrjF{J^ROvQQwjL0)P!mR;1m7lTZ^yR#77>jGdH;brHq|lKHZWhDJdX_WMGIke@0U)uQg=hme2rlF^HRVe8ZvOQpDW!kvZfYMWgFoU$yJih34)mh-_b3P6uWt>SUN*zW{*%JKi#3OpIcJ3Rp=wDsQb z-*}(Zao*?Rg1*OMd-avHNAgpRd4X^!LANlaXXn6v1RDq>|5f*F(D2g_`*hd}4#5_} zdqx#qu@GD0yIFK-JplAn!l@SzWRk+49uB*~b3z~#GlbEwb)1dadf^4>tGp^B^frRF zeGL+#nuadVL=&#GA)Uk3f&z&g;rAc6^D3W`yFkSPbC-)n(sL@WI4UvlWtUTXBrW&k zD;Z|tJ6%WbD*LS&j-@X!MbiK`Z@h{H2qxG#>%iKuoX0kQbF$+5qYQl1&V}lGcC}0@ z3H=vr&BxT_9v9*B{1syr)VcMlSCU{CP8Q>?kGS=RU#Y{{fnMsJZN-TsJg&VI=}nt=lH1cN_s-c=dP!nonSeN!SOH4+y2XHI{{R~J z{jK1lUQNXvSIEFkVEMtuu0%=#A?IIEj^2Y4A=U~)#5mJSr*Sz}0k`;vw!iy~5QZ-^ zzueWZJ3vU>3jHIeDsJ^k_+pvL9qOySPl*s{%~2^h9xGKcMw+9AH+TiEN3!~N9WLDoFS zUcAj^AZe){!+1--#X<35w@hX|ZT-Hm zPhF%~`U?F=qqn-@EUrGdL}Gx;BQ3gm;V`9%$BZ}bE;ZA6M&0hm4ht>ZoKdY0^7L-! z-eV-q{uk&vs&i(2j&zpw84|>u7AHn_?-p4AA@%jy%~J)iq&=nCLaiIq8)OH@k^*ha zi6)4V@-*ulaGByQA-1ljY2|kmyf1T=sD+`C7l5{6Uk|6j z4OeU59CVdaZWhaH;FGJW!uJHi(kPYqKASdfq#AYmTEXF-CwIAMB7<;lqDM4As?!`9 z)eM1%MZ8|2I5C7K@e+8;f&~n({yY!2zdG-;GuAyPz%2eQlFcit{!1W(l2W%$)a_n? zk0W$`K<;Ud4RyygB8~a80`F%?C-#x z3Q})2#f(zuTm6s?WsKnExyqsre|Y*euoY1_i;R;}xyg>1F{JCj)x)}tF^DA{`NRuE zSJ#o^LsN2d@hw&Mt@!nyG~NH?>wA4ZsJ15AJBf=ge*!%mMAnh}bl0qbw*SlCUeg+9 z`u{yM(SiXd(a<8Ely*H zJjkrwUJhqW&Wmv~e~9u6TR$t1P5g`Imic!i`{^7gGfmb#9N(fE+9azvFf4;1@SWW+ z-%e8NJ!w(cy%^U+#EC?{KTg~a4Ko;3bAm{=-C~GGHFdJa8M-{=>%tHHfy>kX^a(pL zxaZ*Z$#pzfTZ!Iv7=i-39?uKvusuCvo*g49sM8LlMWuINxit&$5<_~?z7D&ZI42fi zd4$neMPp~ZV1O@+aeq}UmYQ)})?3oZaFY?8LB;#Dw*8*p;_5>^69nXD5QmfGM%bpLx$#-SWOKqPeWklp z|CKAS5!?r~Kw5ybwS#vLU?|*woD$#(+W#uRG_oDJ&U5KBW!<0uR7b={qUZ?1*4;=( zrt92b`FL=K$swdf|eyqQZ8Bu1N$2iH0=+q3+&n;mZE_u6U%Uw%*ybIG# z-j>(|dJm~<$H8ZV{}^549-0KCS>Vr>s1QQ?R~s9Xa>P0PpG24C{&j}bI~c5;q4@X5 zCr{(!N`>f5pv~ZXFi@3l?y%z%I}ev<4-!?w+j>XWiw`^#Q~-hyj|kIVj9?H5>{s3D zD=~Y=9rlE43dyV^W>+K<^O^(cVH5T1@k)RL)UUfw znUWFKV^mFRFZsrA#BEwW3dIptAkgUvEp&l8xjhO^A%ACD#U5FP^I`UHen2BKusWU< zq9XvmI_BwrSvwsPq1+D4xbzH+U)+T81#6w8RtPJoW&nKK^2g=ywG#aYW+Xl1ij$-| z8>L`75iZ)=F#q z`=bW}hC{$jMA@dUpO(18wRw=_Z|S_9@VhZv!jiMtU1*r5br$2LJR$RFH5qij(z%p| zrPS7r2H^=1xb#g`?1r<6gmaBP2E4W}!Nj6G&dE|>V)JIUSr55`aN~VP=pa znmdSc$e!_k(qXDdA7@?;EEc&rbIpBNwwqhJ;#T#e38&Y5%x<1q?M0_!!tVsU0p`8CmZa>g@3?`BhJoM=k<-|s!US1c{(FJX zh9hX`jCNTp)=4JcoY>A;xrZfT|CK8Hr4f#Kp>3tg3S&(|xm zC2(&M+NIwpc1*}HmmeAOls8{5JD?D3%XRU!j}5|#msI}XM_`cweNdT??ftZ=$k}uN zj}F))`kQ?-Ps_`hEnN%wKm96sz8ai|93~K0RFbGI6R18@awjU%Ilc&CD#a8}iB$FZ z2S@fx+O3G^oH9N$w zD2DG`DT{Fl7(ZF&WY!%xnmgD7)UhaYpZ|P566&yS?oDuh<6LZ60;Q>z z!z5eJd9$qpwU+fS13pmqcH|9kczP-pV3D1NtD;YwA5+Fp{=XcA%^Jrt$_Qp(8Bb_zHFY+Lqs@xOs|pB(Cn|;(>=Vbl{Rv)De*WnjKdIUbbAy-; zz6&9pQS8py=Z%hTRg-uu~mSTsFpg$&gJpcETsOEj0QA#<7M+|p21 zN4*UQCCIb1`pc?69aH{Nu3Wq{E_$GX25V|WGk@D2XWfOm8GhD@$&tFr4h4T{;E@V1 zt&fcKmf6WK!9ERmiOB{JthIdqHNi`1dqY5+->bwcI@9&Uc+qZbZ)b=!JaO~mo2S=+ z%0B?rMVSQ;0P16vEqn*)(_B0+LNf%pTrAw<6hTw!%-oFgGUk|ovUt|ijOSNJN3e-* z3U`Q9>m(!hEa!yiDjw=MPEe0u=El`UQ0!n^R6WOl-$Slk9srhZA*Ni1wE|_mGXB4v z8)xZfXp2)2rb+O<fm-=Ph?n|n`b$;EnTrwU<~nW zR?PJo^@RyaOk?I!|5H>7Wj1&f$SL6@zGK9t4+1fpj&!^n8RfRng*0LV&VN3t0KfwnDi%pvnxT>$` zQW6kSjitJLmXLn9d#5jhoCz;OE^mc-pj$>e-%2QrQZw<2-aq_B(#C4$1p+t5_1)J` z+&Jh=ZD}C2%KbobXm<#Q2K4j+F0G*A4Po=x6?FiP8g!`7oRx^~*EuG6ZM(+rP*Nhq zp3y*Io8sMy(Ra%8OS%^Sazh3iB=m@vY>fIYH}e2XcJUqUaAWyJ&c;qn zzGCN#z!eh~2HxJVY@oOj)Nh_938lH}J@9XXfjDcM322amFTaSPC-+^d8gZCsXmHDLnM+e=M*2*sv2o$uJKN>y)Ix@PmT1%h zh8J=X=)%#s0pHmd2fD@F-L#JjMbkyi6u#%|rWW;mBjO z=I69_NiPv7>~+2$wPE-a60SaJ@TpQiHMPK3eYFUG$eRkN?<~Dq6>eOgNWG8}QcH6a zk|ji)-B$1BR0JOPt1=TwB>URb@%y#~toTQ*5u`ztc-FgghOOs`T`t#JbloaMis6wK ztM+dLqM4#0aC0lI<^aIJq|(+;s4jeSIHeYPjPXsF*a=LVHFjITiE&Ekvl=uWegFCh zt0*2ry}K7T`7#cla>E{Xdj9{}ftT?cdjYp+Z;$jz8R^1PNU6>k$0Sf{;TaokDRlFO zGg2T;=m1O{sLZu5pZdQVp6-;dB7quo9oI+h?Aq;LX!oX3hKIz~2Pa%RC&Uuo8am-g zJjtrj_0D9**3pH{6=RjnPB|c77xk%bhrSTe9ysifv-!`Ort$tISpb7AY$k$N^v1zI z8ZBJ=IJEv6ut>5nAXy_&3L4EDlGwvRAS@;j6HSZb4W zmUGK72mkDMvooELV_YwDCTd7=u_$ulsvi?>*O#D_b;j8;ock%yc$9pl0BVk!XNH;J zt|&F?sEZc6nn34t7U&>;r339;wsJtnik|2qKqo$C=v^cFD5c{z@7+HnhbmQ43L>da zoz=H>N(xiUJsYtK(EaaSfz`1Fo&8G5jg}G0re(PxU>M4%WfO406!F+`Cx#aB)z;hQ zr!!jFLf3H7=N+0=bTwz$d2LMS0O=4v|NOWAKg>Cd7RnqK7wtu>U@Oik_+um9_P4^EaPOB11APgw z;B6{s8g2g@0Bm)Z;T(F7D1wu7F1e&1Xn%k}v184?$W$SZu102kaEtR&fgNgHpJuc+ zkN@|JdLQ8AqV+D}-cyH7JLX8!8|x`ZDvP~I(8Fqb5iolBBXX|Gr3KWN2t#ffw=7s1 z*plLW?+Sq&^8P%{)ZCOq{!*<)6p-N35N{spn|(-}kIM(|V|j)El^SY=tyaMw9YeSq zv^M1Y*U&j@-wgAw8eLM2{!;mB#eXJAR37NLPc)uZNHi`IiUh#VC3cpp^cF>U6_G8C z{Dr^4ufv_J2px!_86KUL0j!4Ya$=}QO*q~QR?yhs@>ytg#{4BuVEntqX|h01uCuOa z{Tv;K+KnaxMVZG4Thxx>PE~_3&x(gRGlqN>pQC*EOUjM^(!!hZH~au(-o2n~+PO<1 zZR^905%k~MaQ8`x*U+@acQEKa*cR5W9Xu?}lNIli*|Zml;60*_2AGt{z1upXw;Vls z_yNag&CUCD44bC*?5}3r0RtIM38sVQr7_@S1P#3b4fbDGm~4t=WY3Ry?l^Slm)&iCY% z2s)M2ALlHM^2I~o&Jg+W3J7+@BRzbfMPU>FB&q=}^W`@j%tn0ffIVz8XWsS_@U-EX zYPJ5}O+gRxPj(?$l>TL326h%ZdC$8?vn0^pE7cc+HeN1Qr?oCSrLD4+p;|5%YPLW#b_os^GdxNPa}3>4mso+xn24OIs;c{(8F(@VN=K{Lw|4h^PNFagMVd#-+K0}b*e}vc}Btw zu?hP2m=1f&lli(Y?9Pi$$ohKw0npeE1|JaQ2bg}ZXHIG4(Y z=L=b>MWjmJ1IW9nKP+JuyE1}PYq(JAJ|URZ7R+JxhkpW5aG%~|Nf|rLjD_h}O2c^GbRtSjBUqnGv-ZK_o2Snbdb4@#awAzV)2+J^vYT8=;f+ zi%lPp*VP`6KHeu)R%id|GLrYwePnU(=1y_M1gL8VIlVr6_D-;1>^0rG z*I-Rx2t}Lq?{&X4)cD~Rt`=@F_*2MK&WYr%a05~|R`2X&vvcJ=%DOLd&X_3)twQ?8 zi?XKW1pQi7uN`EMv?8rc0p~VPS;jjvps@VW0}Y7KER>ry8>ByE3Xc#aOgc*z>D;+q z99Y-MKLVOp;;_aLpKk2DI%Q_;fr8@?9P0MYKv>D!$~)o&!ENJ_)PdHx^wj_80N176 zeq(4P(KFbntBMM$b}K(YP(&0ZfMu+8xD*xnX8b5H=yyA)F>%L>P(G|bdKp01q)AvV z0G{NT4WLK42LoF~H{ojy>{K@7=kQ3F!iv$w|I!gq8kTM#TgXu?ZMk zZGZ)M!7oZyWKDHzKhWW6h5Io>wuwNqN9{w3(So~&-^X0#;!Ur<8u*2T4z`G}qBq7y zYC9uN@6(g1&_zB!ZwvPo!C2g$nUEM3N4@auDw$GyL~&ukZc)0;06Td0(O@v%a|;Os zg1?h@o8*5@4eY~5(Ay?GhSUxl_5}TUs z?C2kAfI)|y<>`ACSN^`qiyAM{qF+*J|67Jfj)I=raIxxFW*4%2`~}<*mZ@DEoTQ2) z{U97}6@CDKpW9mu=f)oC5tTTA^GUNnM|@-TOTgVXBU+oV#XU>PdoX!T2U>Cz!8(1@CFe1P0g+4KejHzdbf>i3 z7?%A+7i$)hn1yWXAM$Imnva(je}!h6E|D=rjlyo)2AKyw-Jg>kYVc45z`uGl9P{wm zuafWcS}ivd+N_^qnhJ%NX=K7FSm(Lp;Y88Jf0_W4St(Ph?F#)#`(y5~j_%xV`M^e( zRj*OaSd)Y_rI9a_D{Hb#=1Z{x=l5pC)5gnOkbt|wlJi@s;0UorF^Bas>SRhT*si6p zM2Ex3rsGJ9k7Y@n1i9jdz`kUDaRiUBWFz(fW~lBl&9NnT+=X2Tssr^F7*ntra+?vm z!O*g%;Qi`I+lyn|gr5eVZ`1g>+)7|;4T6AV?VjgwXfJg`Xxn8|Un}sZ>3V&UBWngd zMOhHr%ia0I)r6JJq;XHslpd4AXaNwD=v{<&Kk;BbBc;BKQ33xCBibVnNbttVe0^kl ztQiDk-KhtMQ=gH_@fOAzGGIV3^d^5E%#*u%<3IfzEGoK}etGQr_ZTPe&7(yNP9_eN ze*HQ>$>`$Ly@H>sL0qWG*3W-Q6;HUVEZz7>?J{a?s+1;vI*K_OmGsGi;Th=e(T>O? z&B3Iq=5?6lZ7=#iITMjn(yRUUxRtT1B2&`Ae=dml!%}Ss=~7xPSS9ImH>-@C@2D^Y z+YQpt*nT;{zk*Y5lVIUr54&HNx*2@&nmVoqjKb=6nuakSs&*AZD-0@{sTwgMNMc2V zd`z-ltrtGZNg9uZbpN?xeuS3>4^dgMo0L^NVL+i4HQrT7;8id)v&u9g8tN7t5WWeZ zDO4FCYfCWjV7S=%W$M(IeN&YW$|=~AJWaTQ4gJ|0ao}L~gw-8b^RQ=S0`*P*+#j2e zS(5b}G;aQc5enL995y-Wpy=0?hX1oBL&=-UY4y8FXwnKG2RxiuI9J$E8)tyd@)V6X zR~>TPTE|_{g$8J#5YCNGDIR;JzyI&^AnsrP|Nr`~s}y>t@|%x0-OJc|@NX=LFQr7x zKhrP1sR#5#OnM4FHu~*QQ)d;6Ppm9lxzrm{^Y$BGU>bmVyMDL!g53?T7|U0YZKy9S|v2ls>osJstf1!cm4On#LhV&l0?e|Ul$LuL)1vfsr~<#@{G3iA`}GZyF)jb zx1VV|=nIn-cO`-BAbcNf)`M0hd!SOOoV*2$uB=E6qxYoeRKVV$or}9j$u5;)eCA})a zun??}wM5}0P}O?`f!ufcltP?PNo0gKe_GeiDHVv1q^fx1I_Sw zI~(M!i8wOaUQG#lNGfJEms1n%S6kfEsK7Wa{LKl48qdcX3$`82$(r(w=yR((JcWB4 z{fen_Z__ogdMp33XQiqby~@Nt*Aw?@W#%tv*v$9?H>j(d4uDxazu`n5%uVH8G3+5b zaW&kPbo{&{sN-WV6H@4w-5H|??7N=b9xWfJJuDZEQPg*z@y*HtHBSR`vIhI$8a%M3 zK%uass`TyW_xlg8Z-?IeaChE%m%oGo0srh02B1Le~g!mR+K}bq>*Qm)2)7vyzeTJUp{p?OXAt6T3q)g3Ae1S)FEKE8ezOyn^L6ix0dq^b zF}&Jc+iR(>B`#)e(ulZe2Utbw-EL+iPsNV&`+ zvbnXA#7F`ZFLi#3`fQC{2+?+p*h;$LpLcerS~_F|Ae+Vy)8&+n3d(g6V(c2dS=@S`0Yhf=8a_l;tEAgg`t6mCU%5e_U9TlaeQlOkh(+x@QG=SQChH z&(XJ$)WBQI^_OvCj za>^}!$OI*`?R`V-iKMbc5e4nIthRfD9g>u1*h?(e=92d3c+Ksw8$bFiYS9cSwe71F z2lWNZDh^u&T?jYw<;!fRwz%cJlgRrDbC(t;t|l!X(0Bgs=tj@!i$PiU~ zipM+DE!LjF8)WTQrXa(?SE;gsgJQR=o7-GH>)6MvDZ@;H*J37jlaK-&Ma*BNDzyMa zQ{lj#IBXO)FXGHtM%9z-KRPe6LK6UOp}vSKLsFZ{c0Sn9!6KU2?YOG&AUJZA$2yYZ zpj}3?K&P&`In~>bU}_PBr_%Qc1uwZb|E77G<0Al|HYVu7rZ(6l8?1@LOdtpsd(eW7 z9U$taF)nz(?}^K6qM^+M&S_s$LNJRg-XleDl>`R2DVWzgw%;bD+@l3S5>w7P~q>(cOq3 zFN13xC@dP^j?II`ANcHM*;#4ytn|Hs!{_8f*RFCSZDlr9?S_UYt}gruL*tCry&tCT z1D=@(k;q{-etx_s>2YOmc1t^^3Y`GDUr>in(^;W8f8LvWfA!O4jS-FKqvxYEO$QM7 zBp#YQ)3=%iAX)RWa$~Y%b#@jdw7SwFYY0j5QLh+_@VkE0RUq$5PBH&)%=8aq zKgvE09!>DQ&p$2-_^6eI7}%+Mg^a$lJ2-S@wR-+txb#lcQ^d?0%R{MPFqK8aH~Th` zWd|KZ|0qx90qEL#zrDE|p2aWbxDRZqdWk zw&;}^r)P>7^3$Jr^EKl|epl9-znfj*i^s9wdda6^>m8jMyTAdDR~pf)inlIhE89$Z!|7Uz5YZ3XmyAx_&`<_ zcyZ>cK?Ed)HW9j^N5dx#&V+T~jC8SE`D^5co%C0Vg6~zXR!jG>MeqmeL%6O{9MW}t zOk}y}u{czKFrG;vx%ty?tF%I=N(hzXpI0y2pv=e>GQ)a=ANiY2tZj>gIL7PuQB>(I zMX!tFbun&4EGiVzsE#!FE?XrnvgCUFExnz!0R_t~IlFz7$C~?4D=JHQjM_ycB*D=| zhXaY;Ro7wOn(XFv7J)FUy#V}j6CzaUWONJ6VCmIRD=Pm7khQ_A|CS6R zdoq=xa0-lS!W~LGytwcwcLmX@pj;5+mVC~)Y&PPZmCY@n<@<3mPH6H#N_Tz}8x#G6 z*OezX4K~s?^5I%y2FUQt$F?JT^|B8wS6(~rV~L%*gGVPi#9nywY-^NiBYlejxpfD5 z9Kq*Ny4!*s?5)ioJY^n8`y`@AJDp-$mD%K5XnBya#ZE6$L)>U^>}14}fBRFRS>LGN zU+t4VnkQz*pd&=muR>7f@Nkoa--y%eT~MP-OX4@=+;>eu$A2ooU`I4Mc{Ms}C4p+d zB~=Az#g-sy69dVs;Mk5>3M|IxJ7Kue@u(Fc&d*fPt#v&~9g4tRV+%u!msXen8DAlo z9>9!%aox|rT`nl;-W>Lm%0I=SWvzeeN7m1rC?fjRLqad_@<+3!_2>LFy?zYHtp~DCx zA)?MD7HjrZeVRw11a~2yp)PCQYN$YAtMraw!dRxP-q{jKT1-<6ESVN_G{PlR%n_8V zWa&ut9y@inQ#(HYvw(#!#xxK9n`YZ6_b~#Z(?;Gn-U3Yz%K9LPhNy6nDF=k~8pl~Q zWvf&DrqR-I%z{e<*Pg>}*qTV0=pDGH>4!Fbhay4&C=Js}T2u$%?5?!`3Xe?*ft}L~)C)kE(!@*jmhy@`zu~8NJ)FG6(=6 zVZGsV`fOXsJUH`z0prAr>vQA>o^7nja9|aYc&WhEwg2#`f|jR4NTy-;*bEkVh?7_45iev-Ml?4D%mNCs zsUGh4{6+Jb+!r52@!Ct>O34YfFb1_!lb?NP`|1{n0xcN+(+E#nQjWiV~ zW4{tplJqk^`SIrtPIeh6cTUWDQKNXi7y`sCz!Ey-9?_}-((av0dbyPOp@Z2k3A2V< zIyhT2RS%czXIkvE1YppOC)z)}X^U?I5l71qMLE7eMLOj2KAN zD}pcMj>P==@VA9wHL`lLAE}@FlYX-Q#5+&S&YL!H_V%wued{Op>BLiEV9oK+=Bklm zRY$Yo%nu54!ZNCJke_?UgfGhYq{7ULSMSt+=RnqFI*htR|O_)(182?A>8Q4s)lbpG=y>cw&0^{0l8k51BN7-K_aFv7;bmqjMXH6##a&^ z=@%^jGVSo=RY_JJum*xDDz)wR^cMfTV=3k_&w%=^)%fE8Ak}`mxVm|7y3-eKignN* z&1-txlT`?l)7X>mn8Zh(s+VMtEE5V>iEzETIfIoTHt8TS>@X4cB50J1T%pqfsW zXvBTiCs&k(z$aP69&fUTS3i=hNeyB^YNHIYGgatMQlAH+_}Kt3U%E_pZ$7#PPdE5t zE4j>UQL}cVD;8JE}^x z58q}Tp`{5Azz&d|ZN?#N8#=WJewrlY3F0XqZ6imNRr76=owVk`VBFHaR#VVrUP6`8T$NKR)9PY+VmrWs^k@~#?;r~2g0y}s<@EBVsMp^}gLb6{( zFS-aN;U&kDbpa=^B9+BN$R+UV0DcRS&ItGEf%b*KvC%O7#%tfYb|Q?Qxo!CdK+2}% z>&uR12Oa+%$x>Iw$CT!;f zfyEFy3x^>4G?;}x3o|=Q9VQUG6it^NN3cR&T2i^J2S!*;|D%DFN3x6nIr z1(dE&qDAR%cV#L^J)ZXoTvozpXS%6a)@FFDevlLxw#}qG8q#vD!G9Y@IS+p3U=#^2 zi0jky1SkgRum0xoM!}{+)}jxdk=udI+kmXPg;)RAM<@fPa7KPC>@M}W!5{E@)xILZ zWvcuH3E^ex`GPlR3O3Q8o>T?49@OaeD@Bb@T3 z^HYs{qJPwZ2rGH*ug@aJq02(PFfLS9gyY{_pHAPEgb6HcEL8w|`)f1)q@ZUE{a^q8 z*@MqE4>he|)FR`af+9E|A5EqafOV{K1z_~+v=Ig#JefZZHr^d;(e32L^t|*fvx{K- z8K2m(T3>Gw>T*;{;401c2eq-CJhqAJ0LogRyMw^BqrmjX8#z-n0DaW|@Z+`{3#x5$ zn}2S_9L*6QKab?i>xLLi$|WgDj~5;}d&Rx?g(~2{z7;-q$$3F*{Zwr{o0fTi*A|#Y zEIZc!Dt#G*z5O=zR?3aeb)btTqWmhyZ`?5g)5(AzT_z*K{}RY6$u)A{$hW+_1$IQ< zlhgeQe{lDO09LyoixL8QXrnDYr)S?M{5Tii{up)T@QA}|O&3+R^an)ZqtO|?9Af1S zOiX}aJ`Fn{5;F5ebiO-Nld70`(ca8y;C&MBACGiTW@^0Zk0$SEJdn_iK9$iL5aA!+a2s-Ud zbO5O(RrO3Vd57>lnek8E!7Is>^po@b70qPvV6A>YtggSUF@P$Ehf<$xKoL=v(F`G~ zY8m7ex+c5LWBH5>nZIC1dPwk(%==L*(P(z7)kxopvgK-N`73ir)_Cg|(T#M0=%q*| z3}8S?Doy_I=(gD@_1hx6BsQrlAJrfyk*ECitpk=-z48|hMA#~XcafBuYhc4AwML;O zU|Uhum*H_(Ow?Xi3UcnG=@qA)%lKo4s4n@8qI6+Lj`o~J@<@M+QeRccXUd74&mCfl z99YD-M~fWVz9{E`S5=djF80iBt#~o~-Hx0#WBpM$2w8?ugk!)TiXciht>BO??nb7g z>6&bCm8Z@+nE(I!h)5jKbv5v~tJ6FOP~=9jF&6cS%6pXI)&qNmYl`eaZ*nJhLWZA#t5VA;U)@UIl3wU5tJtVso zet1-H^q8O(_v0N^bP9E(~@GC~@e*0`+b?SBb?E%4G(jRbbNc%pBWk^jA zS92DOqaJu<{v6Y?oO{@2`+|cra`FXG1Ux> zwCk|e<73Ja|BV&eUzATlX^i2&@CQUqXYV-(>neGG0?+`UU+4?lBUBH^4z zd<5ROxeK1`J@Y6;3GJ1vf#cZwt9`nUZ8F5rLFl+yu>{L(v&2Ns+o@+AkCiQvk&zCk zXr;Pwjp@Tq&i*wf2w@5^DGGB&;R_z6X{&BNcBx&9iTCz+z0_GUxdrdHsbgrxz!#`@ zT&=mwb!)m8IlV&koQ#q{dCVin1xsGY#Dcu}A(53|KVQcIi~)~FGXe3iB8Bl(F^rP9 z0Mn723In?X@Sml#yjav_@CEwAa0J3b{1~!ECAttY!Mz>B$oB>n*@a%(AquGhCFn>W z;jwa5?7iY<(j~n8Heh}0Yv7(S%mxfnZIzRL8x7j~#idbLOdtMIfRJtss~rh+9w%qvfh3*V*l&MgwX4y#cJRP$ID3+P}kAu}G}iQ6#P&Qg3Lm~<4v1rnll zaDP*TNn-vGbsPsEJIj+gN}pOFWM(d+h1QLl=XkPB4Eby`qRYXadX*&uJ9iw^_;)E; ziS)YHn+)n;8J_UCncG9ZJ>Pzi9QqD9<7Y%j#3^YOlf+2RzM&2>%Hd)IP7-H0=U}SM08>D$zuG$I zHGs3vV_8RQmT~m%l@zB$ufuHpVVUleUyV{Ndv@VxVp%5D7boh|P+Q6$3EtE$V`3T) zgSTM>KOaB-rhT{Z*-MKFrx zJcM0m{%I9~ZwcHv7J$o(UnE3&%bPCiYX0g}Wa3Ju;`XfodQvzxD|8?IoJ{AwExr6X ze+vg!qph(X1>6o5a6N*;OmY6i`O2dt*-ob!+T)Gd zB|V#AN7n3h36~{1ERxA-+Pb$(sOce=AhRUpm+DN|=ae~N$KNG4Y$d7k@muLE9m{yE z8(Dh&s6rG}S8dN-6mU+YZb?ge&hz?Vy`6s8?>@QI8<|G%_{r%Uk9y!qk{fOuQFL*? z<=Y&35(+6OaZkoBnACi2r;Q6k^kkITn?{l<4)>?KB@^8}f(18tG-9v(|U^ki|n`3)Na&~qs~0DTURKf%0gUg(i#*i7C9nN4>X6a6m@h1WoKO@iWRX2F?2pDj}#Km2tH$lmOl6mbr{g$-(x-Jhs)4T(Xj7 z0_8r@&ChK1&$BvU*$K8Mb_q&a-IUws< z{i<9-flnWcle=}TB{Nq48O1vBFP-jIo)|DdDlheOi21R)DbATp8mKB%pL;qp^4o>X2T@cgyP~Jp7 zDUCpB7ZF7v9rf4EuuGw}(AHl?12kN}(LRK)&Wp%{a%hj4fA-wfr>CTI=GcHFpi`gy zAQy4Yz3aYrWu?MBV+M0*C=YnqBcpPI#{(f|d+x?5$DSarL-Y2DvR8ur$`^3t!qVdg!vKR$jSO%R?+PD zXeL~CtHcz+kEiJ_mMJy!yhNfrcxFJ*q_7qa0M}LHX2svy zYP-g&KXqWF`X3NGd~)Xde-#p;r3;&?T6fcAH@@L}T|Afjw6cM}PBMQ9U_Td{K({kx z3*)wq@4Q^)9c`1lKlYu3yf9)xPQ$5>C*+k)DzjLI9tc(?q`xyKT|N*0|NsAX)mHib zOZDW=KmS?!-N)Ur%Z|gf+@4Qv!ALSSQ`(@*b%Sqij zw&-&3CY})ESHL4NR!LjHLc6I_m>(@kY@?o)G_Z@%uuQmxWj2vF0sba77|d!GAUgGB zS9lj!Rz{U*jiN2nYVp@VyjbD~7iVcT@um}3mm&55i3d~Q26A1z@$dreMH|1V@t*m` zMb7|p8A#Ffgq<@693C81@RuMrf_{`dHkk23pYkW>mX(MU=AS6`t4bd>fzvB){7@wv zBW$TTkaka0*GV37qKZ*YsR0(#v7vnB_k(>IG}s{+aL8FRHh2Sg83^jED$-pIrekSlw((86v zokY=jhyqhJr0@`v0r3hlD)Py~6m*9$3?u}APu*3C_q?>MPfrY+CcamIVm`BI&|j<7A)nUa~v>BO55Zpha~g z_+sI>#?Vb?%)*Ct8<%tNS+!6PrN93iVi}E?7D@vGv7T4rP8mBI^8f=dF3z}vx^emW z7`RgW?HI$b<~G@)Fo3VvpN>#dGxUw*5KMZb`3@<&3xf3krsqsMJ3~%>TUHxW!7U7) z4;?%3l;<@FYkp<{vegT8juQ3@xFspR9L*i)zk)ysS@Y>Qfdm*|t{@`qdr6$2uV|4V zG(}&`cS3_WJBl2`bD2&3$eVxxNB6H!me^KGQ@~}6VJai#oGu9HK_~wG-|W6s z_UOH$;yi`+5cg;F#|=e|uhcw&wDS}A$f`{-Fiw_vYEx0%%|${{O@7`bcfv>eC9*(> zgSAheCV!UY&YP7m$Ci2g!=2U1gvhVGkk+JX?L-v*uRQIn#@yeTU%d=)B>)SqpOv6( z6bj!_kkp-?RFy!1DP{Yt)EccT>PQDZeo6V^X*F8i$DvGi#ft*ZhNnbwp)z$2CA2@S z*>#_pxjC~mcZ4paEieW?c+dlV?}qxn7bLxuK~>rcTOGsV?VazLo2bJ+k^Z|?8loxO z=QnqO*)%5RN@};)B*%jfO!vy_lTFjcAXA6XF6J{!V(a2>-1wl>7!+2_>yw~U@OZul zEf#hoalu)AnxqLPxoQ@mz#&JS9@qxbM$#0L=1<)a_28wnU7*0`RYNqH(UvwT&DJpw zPI_Of8200n*Gu9K6)Q;|ClbNd{Q)26ebd6HwO6JJ4azf2j37N=XJS3gd^w=5~x5n&W3w~5tI(7QB&m?F-W-4lFj^LZzK*>M~X4gRcrN-5)| zG6r5lh7yYrM5L872|1pt)?SLd7{QLkovm1$52K>=5cDv)&jW7LcY&;p{w71>o!YN@ z%#&%&;sDXTK_6r5d@B^A1$Z#Q0ba6Za7HKq%n}g){sC8^?m$FyK@)M@^&_{AQJ!|k zuE;g{x&BEawZr~Y135Ap0?)(isBA}m;4#QAEeD{o8qQNBapGRRTrK4@CJu&{3wiKY zPP6x4^Em`y3EcuO&qz`Y&3$GaAA$Cy3^~yS#1p^irBs|hisbN% zK%-Rt!a+!1E5Tf3?ZXl$K69BI@}B6H=I-kKv`(#+a$z|&N(ZhxGg{#d5{ zpK0UmSiKH78P@t(TDmToe{Jh`8?o`yvzn~ z#;};S(-3;z3ZW<9K(|<2G_wBVw6KG_>OOSat`Df`O->*wFH%OJ_@;7k)z2p+1T4gx zmTCGVz}n~UIdablnnO>*Pv2*^9vEN2Cgkja6l|nb*;5%f`ggQfI%S{?AeKwH-m8~N zTIfu`16wBS4P_yWcMCl#%{*_buF#f}s_)8lz3pP<5Go*85EN}Oec^OwB0+z_a>^tr zQn@mst#xPTSdsKe@nZK|rgX_Pku|d4W0ZLar^?92fg|tMf{LyoRVy7J1OG~GUT$TNewI{nwIGQ*ehEg z@wzTaeux1QUOKW-mRb6?4e~h#RLbXI0y_{LHN0Q7yhk2VESm-N@YSmK0B??d>qqWu z7DXw*Qj~0mzR=EdmcvUuJj4Z$*@)e+B#K?Zln`syS`~EMI}6C_m_Th<8`)!bh9?jPI?m5;UcWTLLU&4w{f*93%RW? zYslFPbfFt)d?xG)w%T6`Bxcty$#+Q-6D=$+49tnWhca}dcA9%%k7ck2t{zc*A$Imb z(q(iGfg$D@$LSp!P$WKaJ*m>t^I2cpZB;=0#Ej?BM8fZ>J*Eo;=$SWQ;|bEAofL&4 z=0PFB_0nw-GQ&nyWu`-Vo4Py(WAZ1|Cp-mFycox|^;*l~rPE8>)Sc7|oUQT*lU(ZEfZu*vo0$JC^e zo`!|1;~?nTLpv$9`stByT@^bJ0x7!f)AEdRvS)AK^^J`)I9H5#oRZcnnB({cTTh6L z`~g$$9RX;9K=_EXvN3!VDPcam48cEx1dp^8g+TUc%vr&p@P#vpT+(THRT@Nc!kGDzL z(wImDalji`nWZSEQ%~DY002~kA?1`qfBrZ?9>}I)K2iVW!u|7ZGe;`|A1sDO09aWi zb~5MMJ3E9MMt`{XS&gv#B>m)NZ&5LlZzu{yyik?8$@cm9l+m}iRM!GGL=OQZ;>*R2 zR~~x?T)S2lw=uE@Vd4hJz1hx%L-rG&*hlX`)RDLE;%icYA%mmZQ979fQM|DKm#ZK5kwQy zoN$z_Z4&1h+LGu{N5;l0HU)s9D!^=a?$_p{nv!9S$eF;amxazc-^QI^O0Nu7OU^sb$|NjzOOas*uob2!<OH`^PRGo8;$}_afZ!v#`iZmi#Jjj|opa ze?w#ne|wWn$1-nf(RKVF0NPj}{*~qcU-`a+nW-eyx3IreS{wXKDQV{~ibEd|vDbUe zV~ek|MO^1c0S#Ne;eA{L(S8wlt9l4EgBCGrO>JqARu=rSXAB~BHt`G{Z^6f=JE~iN z)UZb3?nhy40};xkm#-P%?7O7Pwc_H!mAvBi)luu=aGoa!4oIE8asBN|A~tRLCSaXp zDI;7s`K6<(kI%y_G%|$*q)0O3sZ~sg$yiZ7|BS#BQ+YjY>JJxUgl1&gZqn&L5_>p8 zHGh+q%I~f8x3a~QZ(xuZI>EJvfiVdnK(c=;i! z7+G4}5Zh;PD^y4FF<;3?wvb`0DzeThy_*cU_lIJHI~@o<@CtCmqj4oxNI}#jTKokp zH-gotTB2FhX>=6dHd$aQ`2-m5@bY)jolTMpffY#bnUM(#n5g19wIynU;tE5tp*ac6 zGPl`{Y4Os*OyUWORcb?W&$-ql_u9BgC{Uw7zkkmq$~0uu1r|OYZR!yE`NC|YnpG=$ z^s@ICd)fesd}ph;F~cVjdb1{db|uo;Ne?oA)CcpLZ0FMmrpv8e$@ z+oEmN@2~HlSIoT3Xs;MUPtjyc{ts!obi;ab&JkhvF0W=!#E$%NRd! zaUFnUKM@sn3k zQo_*yM%>Z!CjV;ml!jv<1MeG23LyC>_kh!CmI+`o(GzqM!ViJdUY5@>U7@SCDFpVu z8I@J|Kw?Z^0+5x0Gc(61`W=;RD*a3OGlZ1)7ztHp{oEdVO)cV_>3pQH2HQ2>tE1R4 zhs!Ir>k~EL`?M1irGa}FM!kw9@+H((Gmzu)O8MRWcXpl*#7r!DG@(}=uR5R6zvMmh zyrT`bQ;C7o7KyJC)d^n!DM{@0-clC2r99bMQIuayyJu3G;~ok9Vk0hy#HjvT38;1M z7woy((R|KoUM{F1$BbwTDA06s7h>Qc(vaA5X+e)*{kW9m+Nd=4o!hcr(O~_YcOI8v z@Ze`rZ|rX?XHGR|DIfbBo3=##sad19DEKI-$-_A~9cFQB=^={PqDHJ{(W8&Y(OI{# zJ0IL9mH+L}gdWm+XC8lV_asNFwo1{nQ=&KfhIMtF3M~6I=C!=OKpH&xb7d$w8!-_S3TOH%OCZj|JNw2Zx=xlg3bWRZK6?%OKywq{c9q%9Y@y`3@l@%|BC#mnE zXGM5{_gmnX2E|Q@mUQDU5&qkX!6BMqE6O}aqW2Zk+WJtZJr@C-z10vMOB zzn-s|)1VlfC;ml;F7PQn?J{u&_`jZK;s}Mz50`>V6zI_Q8}yAP!>hI-c{GMS=LnaV z&4D#7VxqhP*h#-5z10B#e@Y*p*iHO*wp+7ts=5>0(KT~bv5nirEImE=cp?V!LEbH;x4l*+C#j^eN#DhK-87k%ygC|2^Jy(51Zm{xrZg@_;{!PQnbN zNpPj44zlcX5H!&1WdnJqxRJWW+fHO_Z=vN@FyuQg z_B4K5gK2t@c*=IXaz(f)(}o&rvhugR>QdzNTl+12@`CFp?oc&Kt^GllR+V_HsUP5U z)J@lxr~a314K9+pAMGm}-$qWB=C>qN`Eeo^I~kPdw&(ndEt|hbp)Q|yMi5$Zpo)vI zu>_RHy&qsw*ax8X6<}F|gqk`IP1aow|5b(2I8memGcG#h1-!pvu~aC>hde?;&;3-O z5n-y1_tCi1^0+f*+iJO`xv~kGaoqiITa8;qrZ}7zPTXyKFubvEg>2<=V&P$Q`gW88 z9P3c&VI}}`!5p^5RJ^fvWuj0kZhD7*@0lZzf@VrkYkU43ry4$#s8>)7RBB6R0dluh zJ}!2SeZ5xG8N&C~p{_74^+IBx^3_o&7x7VTlSNVu?>&oNZcmGt9t7;fNp`V5SDeLKabsA#M(Az!{;q zvtvpQR{N94k)SiYCE(hvTS0Y)pU9&9g^d zf(&%naI8$!FP-FsbH}+*ZX&K6vkFikX`&}KKaAlEK*o{m)FYktadx;JwE3J=Yzo(f zCQ+OwCehIAxv91eWBhX91sq`Nh)9NELg`F_w(uBF+jeePi9O~-aXp~cO8C~RhsK!W z6;Ff`yt{0Pv58eYAK4LJ{<6v?mPP8{wsZj24=InT0y4rd z!!=6d%Ow7_0$ItVvsocL-$G+TaF$?n7qx7YrrvqLd9)xh49LDW=N(y)$)d87&KXMU z?^T}9Oo+xL=sKk6!2hMcd=Il0^k9QjTwtv5BRf#juEqLHhjG+{#o}^3+w{vlwDQVw zm(^$IUl@e?MFM`j!^(5+tDJE)N4V=D8oa{k99PJ~RxsYAxXovwnuB{0QFb`fK)w7g z%X2rTbt5)9t#~hpk76F@Wj_@0vrjFiQslGbpB*z?md;1njJQoOlg*IQZet6U7st-paH*V`OhUqlFJOu`DcCz9- zuLuXuTV}LcfBp_)%S%TDs{IDgHgQ@9F0X?+V&L5*s)L)b9dNoAj%Z&MZOCUFw2=*3 zwY7$qJVX|MFi}#81rc~EMjc0`l`WCY#6rFySrqhNJ*&2REbblP#=c0Jom$z!JrkU~ z1W=-xIyFeZ_z@f{OuC%Y@vK-+*bb5os;2=nv5D*ZRFaMidK@Hkzw}EvMHYZ9Tv^i9 zb7ge8^B+;qrI2DP&w%Kk{=PdO3hjYIx(;A62I438F^Pg+7atQGL(y>s%cN7fXaDN; zGSqM4=OSTzImR=c-%^z()^LkhcOhC&rw2zzFaKtj-K4a;``Z{SZv(AC;{+*K;GkBv zM!aZDnyVmJRVAKLjWXT9x=u-S6LUels^e^t=%H0joQS>3IF3@J#vc>SOMC+%qkqXF z-MJCcH1&Q9cG9?{+Vy5L;QGl2*2I%1qP8G~+TAY^i~+)3-?v!>ag`LtoOkZ@H~##t zY!)$pI7RO*XC34IUdB1JS-y7ivPB>db_4wHswz*BKD#qK$|a{inB za3d&d>&o8PQ5iorxgFOQVgj67(Sfvp10)U9L}Ch!184EA--{;}is>DLSX^;WBdSG$0Y+nV

    !_NvS*^X4K;+xHhUsx0*ZzB2q@bSFMjH9xkZ{f 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%0DJUObb9gC-EajM=FqF|r3cxnxqI4);MPhDL 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

    4Km`y$(5hw;&3kk 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

    f%%ndOpF4q4E-+dO%{vs)uu2PVMuj!^zhEoPRc5 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�)cNFpw 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

    mA9;&kyiAZ1J40+;i1{=5L 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%0Ag1R*il=2xo!#JYFy3 zfUu0ZT)?E_?F<;$3HePiKE|l{CezNW1Jh_uRD zi4C8WmwHP(l9Q76f%#kb-o1^?8HVcFI>uI(BGHYrf((4dgj(xAbEL{km69}B!6cQ*W@b48*?Kk>D+Nccl#Nn1~-bj*PWEb zZYr(UHvD=Soa`d5ly`{m^DcIG`^uV}{QP%GQS}ankWzbBcrFiqkzE$KRdpo=8Zd_A zCTu#j_}2|F#cOe>rW6i5n$S$vh}X()b=*2k?+?#3nm?iS!tzr#+%vvAa+0ojCA1lH z_B)U7ENYXWqFM(^3iul8mMPFV-^_?v#se?B^w>0mYtItPsWpndSp8mFi~3#yoEZge zlrtzdwQatW9@2I2dY|wX@JHR+7s5$k`~OUGl`zuha8EiH4s!JxQRMN9vOIG^UO6~K zJcD3)HOswD>;Bapc6f+qGge>P-k*CTLef)8faq#srEa)sZOAEF-p5XRwxwZT>+ecD z%Mg<&bOEt$_Z!Jb#yEG*`;ArwJ$!>TSaxG~Yc&d~9gfAjf+~2CSz{l4f|oEb!8;sd z_F4QEe*w)1_K2%cB484hUAfMF2!n&7-!G`FizKGCo@k87yOI9a*){Q)rsy`rto%f+ z5!$1f{xSvt6e6L6y*qO>H^l`T{gR!N0E6i)FIN|NDsOB&)l^riK8G@oRhR77P`0Of zMTFYk_9&2p9WqULN7mC%3ao^1ekY%nC+~DHpOE;e!^tk{nj722>|NR5E z-2ghoPx0&Y^uhmPDN!;Xoj}WXoRx$5Y$kwKtRSyq7}z9U6-Q)w0dMyD{Z#?E`Yv4;?Qxj_p!Z0ngf03UIR@j}Up&@lsr@H)qR{rv zQf%364~Gz5BiXDjZcS~CJDoHA(Q*)#qhCfYG0cos9UV(+@EHH z7OFaE{4O1K)d;|;6H~2_vn*)O1=(Z+PfEf$1V(ohs^_Xeio66Wc7O_o%3($CbWGoT zC@8rx^P@KZwzY9`?vy7MOn|Ozhz0*46Y>}Dlr+60GeL&>?92r2b4Nf}#aql@f*dW6 zGTg1pzLP$N1x{{}1W4&tfLdSe5c?*_{Ul<|@5QbF@|{`->Sx4x`lEa^y*v`(!QxFr z%`X7D)gyHDZw-2_BuI=DzrjogHDCRL3cq4=)?meni0x)ne)3QZ-_oq-WdiGd2&ny7 zvx_1DGyOdsTVVe`rudA^OTR0)LH5)cn%JNAA2-wQOr%ko4>2*4_=w<-ytD<;bn}SP zdq2E^u$A5__t}#={`-6B{nNMU6`k9R!HNH51UtNceRYVzmF&=kOfuJ}`(dr$3fMc* zqcb##Uiu?*!Uz4h1o?S62+LX5K5EPmM6vQMX;gEE*69uK?0C{a27p=J(KABy0z|!` zRq}qs`aq;i79r(a$1TY*$mqwIG(&~g8fwd3Al0u0us z?NBS2NdklY;xKTgYA$=dW5rf0i3z875~`1qY^A>;HFsBo)ecAT(mMj(#+Pmv<>zmO zLZHG#+f2q$M@+ocxpdoOtwQJye5CnN^Yyu7(P+afrI&14H{trWB?$fKA!^UNE?9Kx zA*YjFvF}}w&m8hV=^eVhm=J-g*&zs+&+n1Axyv9(WM(f}CVWn057*+2Ss z`Fj-d`B{d&)f-C8>nCMkwlg&qCwD!uZkX^Qf_}ZEEb>%%0vI@|JFNlFJ>Ded6T9R zYu|Yek8zUQZ>}~CQ7+}T(~#x=>XVm!U+UeKc9AZW+vy6eHI_!5*N}Pd;sJ`1lmsPi zOE{^yWOUtS3+4dUBjIM{uv|C(oBfPWRuYpDBuIe0Y3Nwco*?`^KCa>0D{!zCQISsq zXdZaMCzl=o0);#<3>j6b;VvK!VnC0q4753`u|)9b3;E4lJ8^oB-QcflBM4znZWgyr zkH+(s+mG0&@jx(e;+1JnJqgcRY>>xFE%Bt=?zeEfG}M30gr1NyMTF}c-IB~PgF})U z3WK@E6#(Y=8@d2~_S>=P!WX^g{M#}J>6K_+vj4X#f$K0@&baXx?6$lOT4$?vhA5}g z&3<3qKQy#}opx+Vm~|j49=B9@@qCAjTYYjk;Hqq3V~uBHnzZb(Y@O;_NkHg(unl$U z1Ift7L7pc;lsvij*bEi=tNiU;Ri29Q(itcXkTPY04Q{j04$uj*tFIsA{`Ff~AqJ?{ z>6-f?4xTYNYvCsHKtl4Q+td{GAoH8BxC6)xw6V@@<3 z_^s%S-`?6hqcEZN3v5E~l1ENSB?t$BJh-h=o2Q)vD$a=rd@d0TlK)!hS_i9*Nv^~d z4vRmazK+;OD*;~^V%VV#Xg&Z{?B^%HlA#P?hx9@s0(z?Ls4NswT3{P0Bigw8Ft%N% z46&kF<<9%-;d9$>d&dg-9!mRfT{sp}rNu#s4_W-sefvPvp3=d<5(t*pRWKeZJ=Ld= zH3a_r7ll(T-m(yl-k#$hbyusQZ-z5wTCHToXVuh6STkGa|vu>mYy#fgE zXnidAdvuR-I{eJO8Li~d%&)>;a-(~yZhjMyx~C8kKrTMmn6)GY!Un82-kG(UsBQ)< z`Xo+gbX#f7&_stgAY12wv@=8&4LSb+gCgu~WQ8u)42+2B9#UAfCO@gwC?N=g?IV~H zzB3I^>H`dwdB;%Lbly0n(x%%>ABssciQg~KM1dQd0iZ#SQcuMLGW6W9HW5Ur5Ltz| zz*hnIY-OS2h8;)!-b$V~!?@-j9@GuK5F~@(z&$N&ugNzG;5Q1JpZs=&TvYwhgYyp;wbow4^Z!@YR zN|uAwW!!>bR@d~$U5DoMp7#ejitnX|1;Gp%lFhcsTq8F4`Sn9SgWu~k6nI2AY7MqG zs_9rY=~~9!X;&BxU4M7P+&)5wE&cCWa`Ro`A;*8v$%CE3%I{*BY3=*86xz&-GhlQU zKpa0yISZZ}iz}*^Eq{E*9U~IpLr=1dw5m>-8b?%s)f!8ilAXV5$v(kCS;0FeGnPgQ zZUlKvnc>DFl`}JFLJsfXZ=cO*u53gWA%Nr5-(6qwH}zX(YF33Pb%oN4l>zt0?ib{p z!CNJ4I{7r2%P?SaMcBuZz@Z3R|<>tMqu@0s&K$i#DEt=)K^E9&> zn}9Qst^`+=+<8D@d4^eqFPI3-^u5^Wep6$)EN5zqqyyG~DwznWIf2AY1mw8CYq9MJ znhey6rnIC53SVnpX}abbkXsvMm$_>CzGX=j#O+1mTWPJHJS!G#m3C_r)CM|BkI!DW zRAt#{jDCI(NI&%${M+x?Ocg3u{=?=?6KL`>e3E=zXJ~Ov&d3r?#MU{}R#^)FHHGO= z5s;}i^#6cPbfQB@b8%)+(CC|sr>w@iwAfqdrB)fqhQR8Qe|-E>o_{C>_e7 zv1Em|Pr6-Yycu%_x})Q)k$*izvVu}1*otFt8`B;if8zTE#eF^_t%1z)m+uf#!DGOy z!c1#?cR}9j1|a_>I%s<(t;z%SerHIp)W>+u8OO>QSO3tsHJ6=rcy8Yx(;iARwaZn| zl1plO81H>KJy36CJK_L_#$bTb09!L)7z!h#91Pv2>cf(abD%?|i;*BLcb^Jjst#F-&&EU@Oj}s^yB& z5UJQR0}V+}EQ|Lc4C{@4IUiG9g8VjJJ!Rw8Kx|iUw&D|+ z1H73uBfX@{L_SXxzIX=*P*^#PXB{|)-4IEQ5Twm&h8*%Be}P=+)U-A`UY%M`O5bnN zJuiq0Y$}xq_U10x%-3|ANp3vCMU?pweB&y$h1K7NNpW1*iQAR$HLHOO(5!wfAaNMX zI<&GR*mJCrr#Xj~78j7)Y$3$~7b{JUtP7u0(fBRlr?YDY@@IWUGa3cl=!q!x&-@`} z?pWBmu>BWxbCY1l4L`G(WL?qW%CPF3*J|Nmx~D&#P`#iRBdVxaiXFBM^bus!UUww^ zXe9>fVEBbcR;UawV}qWFC?p&KcSR%OJESMpda&4) zB9NRC*8}x=sP~ z&TOB>8~$d}Z@4;bC^g8YtSuJmv9F{bXY#)4lReHOE{APm+5D5vw97uG_O7cBBdDG^ zETI+b$ZjB24kAvD7&sET&gN867P>?I5ulYIp8E@?j(^!TMt&Sw#-;1D`xKLT^xi2s z12#}a4KW^xjVGvxm>uzekN58(#h1C^MM9k;yiwuN8-tdyoVXPgu}#&=hB@>CM3@yZ zzMDThX{K?pFI}{VaRMrnKnGC+#Dpml(>4MOCv;&FqEOEpGH*- zCs)4$Ciu$}mBg;hqa`p9E{?e9~7|c#X4UZVeeYYYS=oRU(=DYxqX|x@xK2jk~;;h-(_j85`U!mLeo-mi{6G`~(na`>`OBCN($ z3-C{ocxMHap!A)|cHI$4ChBfCk_%LMtcV^C%l8z0wQJPIZSD!BtDg-zPl6awiD%UD zX)e!{RH(Njq}rBT?tmY{f{n}HXTyng(U|SoVIS+_*R=<%dd!THIN$!2&oz;$G}M{( zwPb-df|PPScOEhRspQdz!uTFLR zkQzD`tt+n(AQG1vK$8WMPb}4bejN##*16Qkwkg4d!(@F*KEGXYFtYcu5k+!{Yi$=5 z`9a(zR7pZ5S*QtnD#kZL6BW&NuvR^n4N~|y6rL(W>AD?W{b)iV;(fnK+cZ}-)VP4_ z(ks_XpOoa)^$~|e>7TriibyQ>JSS_t@6e`Hz(y_*#W9pj%^javfLsm+l(7qqMkiR$ z_$hV3rWU7H4*GCq$f)weCdOT9p+bi;ZEOcyx1!KBETaFO$5W71+j7i773|sB)bsiQ-9T!H3 z9g8_b8f8FC2Fb>Z-9>+481F=KQyecXqao*oEA@EAL-c%Uwz5aC>mCDC$FBx=rFySst zcORd`4Uyf$%yMU`CZoiHBMz16&u*bK7g#heZe*VOZh;nvFXV04CLAbj7nSxcd8E`H zELS(vjdplerj+Q+t!g=C&8=78pGau{O-zQNQ5eJkauEp1ukncB)~ASVXD&iV#x47S zAY`os{YH*IlR0toPiM_PRMt6ET-&uU#TIjDku-MBp3~2eoYo4ng;d&|BOp3b56YQP zE;I>)XODr9y@l)$2nsV%?6L6;Nd(T)SYT8reCsAp?``dB&rn%1dr42Dr$*CUXo&qU zI^O(0jgh(USfRorgQgv%T=HOKz|v;~hb)UN?m#wMetM-ZFh>R|3;dUQZ!R7n6W1{c z68}Pc$_?y(BEtG(SG(gP17YlcCJ0cwe^1Cq4U>bH`3t12?WI(SEGegU@Wj4k~-B%xxZD z{(z?}QPNZa;Yha8x2k>m#TXj3<_yW#$>Q{*iCek`@{(dzQBJVgWfFk&E7q3~|% zj4;crWgcR7(!DD|g^taO^w#5naLP2}YRn9iqxU77i#pP=^RfrzB_m85!G>wbUCb>n z?ZxiP4lY0S^ZBiw{8xLKVEQITxn%K6lE=~1i>~f%qkYUp^Cg8j&PVrXsq2A8&psK| z4azK)=O@P4_*BYDcYyKbf7{9wMnV9)J*UN}kHA|~ym^1}YnuXh+Vr2m>U*!w(bpXn z2|I= z7Q!j{ReQUY$kQF%j-pwgl7-TX4tU5_xjf2|zf~|&H7PnacV%>DWu`=1N@dWcpqa--`)eNhunhDbW`xgdq*ZX|N42Accs;OZ<=dKEyZjU~Y}& z#z{#kF3xj;7?+9-^Zk2q&Dg}BkK#2SoVvS)rzXnmLc8h&_$#7ggj$kf8B}ZLkP+q6 z|E`Q``VWg4v7P|pf4nXlN}{Q|HVU7nPlNg>`J^TfK{OAp=gQG^i=vHA-lv>am=vlK zZc@H*Q;g{>Y05Kd3&QTUfBe;ftgvKYG50ZQ2k3OV`6(x{G*Wq-!?C9Lo%RU(O@6a zA|5>9TQO;nALfvkV7^re7y4tq5)b3!%8cN}Qg}+ywfWo49K&n>}{8Bsw4`b zh;BH{L3<9S8r!JkK=>;L(a zStp8m`$!KJ9Z^xdWks;sw}>g0GX$qf-);q58&Eu#Kan%PR>|72#ndFuKLqaDJ@nT3 z06NE=>Jj?0GG=|k3x7n_>IhOyjrc;9d=z7tM{^&VB8g!8;;t?CAly)_>w_e{n=~N?rn%N%bEaBrXCr*QH|$=1syefBl&o}kxpPNB?FATw4*&8gEG&gl zf2?To3v)l1%5si8a$=xvbN8BzC+q+KgR>#&q(LA0B<}#*omzc%Z(Rq+_+4g=984bqH7hdJiu-5rwJh^Mq2b zQsCKoRRe9x6|4Ao9IX{s$l>Apd?E)3AX%2L1d&{Q3}Z?g&Ht@VX?%>m%^X7xPIDqeqAv?${4`1O@?@tFC}MYN_G+110iUo z8*lnZk*}&tVTHe`XrSBK9 zLHy%6CJXLL_i)!6Yu7KR}+>0{8&FNa~ZUF3f13M1?S4YRD+#Wdid%ftM;V?StzT_aC9>xvq!~&Y2u!W zAx$00bQ~^j1k{2=5XW2ALAC0A8!)%i_hX8zzt+*f5IrD6V0PH7(*%j+?Gk{BQ5Boe zgqJ+Nf|{TD&1lO-IYQ6K+`G=HqW$(l)R-EAR02|p*s(DJ?&ZFGlTaX0hhi6y+2`FN zJbZP1{ONA{1K-p?K3IS2fzi(R|6!2nu&tt#m>owjEAnLDGMj?uw;@^_qkU>;!~cr< zRW+rF-g^=+&fle&xWyO^oyzcJa6lQ>fRz)tq($WrCrvgU4MZ1~oWbKADi8e245T^M z(^Wz`&GjuYu4pvG&2XGR?qub58I6Cx-=Pg5`6g?QAGU|fCkKp_*@yr&zpD*r0qI1j zA8~!lVg39x3C)qga9(Y#-Nwu*ZekIq^JMu;=?~7(LDh8WvNt}205?F$zfV<$jewa6 z>E|-z9<_g_`4UYKLRj`DzSnunYtlUiN$-I(1p$pRo=C|n*lj5mwF#p;U$macLzRec zrY*{-5$yVxns>kn2I>5C*H8~v=`Pi3KaZF9)Tt)>sb7rnx%;u|D1CPfz}ImtJe*o9 z`(=DaTqE8B-yBcUPr9D6ujvlV;b0&#$-KQ*jSf}TT|vugqSlxItxT23%r>uo3>9QU zORG$ry`L(I?1g3!H4i`HUzcM=*vgQ6B0QH-O=HqR(qQncA8BIE&NL!nmEKHaawSgG zk}>e^FwJ~j41B(-_u){|d^!#-v?7__3BM#Q!@Bii6`S#d{N*v{o_W`;KG*246-@jx zEqJcz#;$%^$PoEG|2Fy2!Ij(_AJgTv0(nc)fvnGwt zsvwQzey=?a65<)Jg&ie0SurPNs$ic3aFzsb>hkS$ltS z4(F|Wop!ws+mm9|Ensx+RmuwzS=}Fs`x-xOUS6B=6J^!xhys6j^Q_V)e?rC6eB zyC2f*3&cc@cDe%HP}SD&9X>tY3)A5?wBh!)@~gYX-DmRFGj&2$*)zr#M8;B{zzT$u zyq1}lHaOG)^*yJ`~UXFQr7yUjMq%=hN7y}FKF(PV6lG-CMUW4toO2C+su+&AB_ zsc%0UyFeqmJGhNr_Qo5yy#2IZG{BsGw-J-&IPIvc2z9mJQ z(fB+jc4-T?U{PPw=0{6a4vq=^vtPm$j!3_Wf!OT#MmNJh<342|+95Ig?;~m-6%N7; z)ac1#Z&ByG1Yj`nn?OvEDr^-LI+iFDeCCW#hy+wHuUQHNxzI~lFGotw>#5K0D|`62 z0S#sHTd4M>R>@w?4H{R-ilr=j#zFF%x6>m`*FWG9P)_(C>^8{9>S|FJfZNI6>CaU2 z@f+Z-AAG}H;kLqL7dbvKcf7Zc)<~HrEK}jh(!#!vH+eml62Q8nAvF`74$$O9x}zcz z7Z?_6>m5jZ&`Ez7?V!MvOZM6-cpn z@WOWb@&UX;9ZHaJ{r5G(g>_mM===mW(h$A0yH@)KkZj3rfQP_hMvUYPXrsoS>K&hpRvR#I z6#rpCdC2M-02k3j;E4PHOMNzz=j5|eRImYf-J|LRJ|Pik9`4tr#b$@1(t%uDEeR?V zO9%Ex8Ni4gqiac-)*+gy9#08Y$U}-R4`Riuka{BR8--d0A56-2qkTTqN5jrDg%i4P ze~P!#;d@>uB6=B#=o<0&Yi}WVisb|? ze4$n&2qCYh*7K;Uvx|-3%fga7)6CrbsS}}sq!4vIRe3_*cKa}M!g&HmF&bckDIz@X zL=!t-sX(Eoi2tA+2Y<-;4J2P!x9zx$`y#lPtDzN$v}jFX`%9i996u zo)~@}4fYaT*$NAi8d5E*gN!ssr$>rcfE>2I{ug-bqDZ(XEPrmeZd5!@s*6(6_-NB2hk1=YC~Bf^~#(0>=3!lo8;C9mZb)R@pJ zDz}r@3J5+ZMM+yMmZn7Xv_uaty&*cm-0obtS|txZGMe0MNPZ{QspmM+w?Q-2 z0c9Zg(Qrlis7af<@({SFkJifIWiDV+_zmQpZxBx0-X+@>Z&AT9o0Ilyl!#2nqteT| z$ref%t1AN33nQ0Jd~qXh5rKA%iK!&u$zu*-1u3@U(L?) z4Vu`51#2s(VY4GD(IW$AA@jO&FJ1X^h7ld^6-)SCeA3&~%Q|oSJr)#XPNFo*l z0xA{8XXv$SMK0%NQw{)6=+E%NhU?-#Z2#hShX!@j$Zza{5Nhf(Pjnn}Y2i>xAHvy^ zK7Fb_Py^{FWH*hhXGWoUg^(~W}+Lp)By`FK$}5l}69kh1dcl2%rtvzsvh z@oIP#3#_~rx`3we7?`_~q>o4%vhK5irh3MH!g#)X;SArgpJ~vRsjGO<6d6Fa>#Iuk zX&yE`sJs3$2ksQrL<}G0H?39zwbUr(DNC@`DevAvlJ7M9>U!YLyVAK+X~$NgTM zJwA?}-t?OwU79a7Zq^B<7a+q4cYQ*&97du6t|;VRW&+#S7go;kSE(^kimJSvIr+=8 zfhbg!z18nbJUh@H!Yh5qY=R$(?+e~j@U1w8kGs*a7KI0026LOa3d`KZi**Fe+)y=x zJf7p9woH&wP-==DH$J1XK%8$Tv?HCoqiN|k5U6B<*^7Kp0@C8V?DHfPr z>(L&;VgPHEtFcV}HcL?$1l+tHG+i|i5A@S9sWmd5$|yy&>0kQ5pZ)T+sLACB>!c!boK`&P(QwuLfw-^r<$3X zLpU!6%zB1+#Ta!jK3b*fb&9H3ooX^c!eDtu7N*06i+GV@W3$dX*&-@%d=L1NNT){- zcrk=SYF~sq7-1$}^p7iaaObuSjOcuz^+nr3!ohTAdl4{P+5#HZ~V|*itl2UKyr6{F8q7|3#8`tqQ#1KaTH8 za;{TU@%D~=`aTp|&sHb~3$qFwl=l7%Db+ki6*p_&J((s`lElj4S+|AN@dEVpsmKR4 zQtArd#B}9)@E_qjit8^px4TY|SD4(^-0*_Sg#;+<4fWnwa6$G}jyI?L;5PG{D2vQ(8z7s0?ioG|+7f{aa0UypD;m~`& z;9fw-Gdm<3kq7-Oo(Z;3GDbZIOf6@BL|R@xnPIWKXK1n7V;H1E^ud6$NNUGVarF&{ z9f=fK(Jt(uEuBFMyuOd^wiuAJz>WI8*`vIbMe%QF>I2KoW@i zQLvs{-b+6o4Ig3(6xP2ae(Zs8t8#(=xm9i&=vx7ngGeSye4C$Vyd7LFhIHY9Hw3p# z5=r;{Fgv^eWXm;kIIlI*34wv)F>a4y1bYA|9|w86{sXiDz1O7B89>m3LO*_d|HrA1 zR6GQ-Fq;0@Kfim(@GGAQpQ@&QOx2t7JTEW4w-$cY+p%Mt2W-!=2UJ1FD-_auOgwt8 zrWq1IWhGr_Yp2El6OR#eF;qhkZevX;Co7F_7`aG{p-6dio;!6kWR}Cu`BHK=SYfs> zE1(ipxsdCxKm)aBFF}7leBCQq%cuc~5Wc;vh6E0K72d9$^3&)p%awfR1iVM~^v0W5 zpbg~+0f}%~&fi|-#P*%wg#Ei=DcDpA(ZQiCdm=}QCk?pg3_jkg9jkN3*dCbT-No&l zJW43p0-xtT38z)G^`)vSIq9>4b?4{T5(WHsPKy64QALHViC%Uszbi+|pdz%@mqYFs;aL&7iUMBM)s^D3M5kE)PHOx8bJaNv$Z= z!JHE=DYc3il*dxMm_alRaTvukOzsW~^Wml66cNN=7E*g&-3XpO*zxATuFOJbqfxIH zTN3mhV{B_S21{a6Qj`XwIlB`bjtH*05_wwXzRxc!rm5f;?y6zCDkV`!|HcADHxw(+ zW9TN3#)3(zQBX*Z(Po|}oo-h=+4?sG|I8sWRqCwCDjQ^-2je1^zWOxwaH3U!YBTlk z5>4Eb0;SK*U2^{K4sw_^^T7uhZE_AVh??c_tLKY&kDm9kz>TlJE$J-;7szG)GI*jX zBpNblif$N1>cApB0X*P)5Xw!-n7P-zSa<*pWk;MwoOxQg(&dkbKF2pky$ArwSn!!% zXCz@St-BpGE?{Mqfa9)ViaV*Srd4kB4#3@BRVf}5QFK-8epvnq)}gj| zgXK;;c&yB2#wlMWa##U0#7(E^6x@!6&AH6pX~YoM;Db-Al)<)IU$)Dg>Bz;jtgv>U z6E{XHr;?>w?i$`JB!z~XwlDIeR0Y|cTQz6vhhe7((`B+6uIJzva+w@gYA+b39S&pF zLJWdrb*ObJ7Fn{yN@c0qm$?T;CDJW!&{26*(U;2G{u|V2SR354;@S{G-nOr1h611t zXz!;JEo5AQ6THz4oHewG-p87>;s_^M zsbd<4vk1>@?fvibtny;AF5y{zY){DYVxcy-JOH4->BA_xI1z!2*iwS9m;-p1J7kB= zSeBd~uwzRmE;bV-72#r(&gCZsVRuxGe;Sl)$_H0FK(7c|{T*@ZIvX_T= zU&>v|!Q7_tZsBOnexaqz#OGhA-wZxYozE4o*%*ZLC=hSdxPa}_jY0wS=q0_b>icM1 zQP>&P^J;S0MYL+7-cXTmP;ZmAfyb}Bk>bOuuMa#4Z1Lq2bGCZO$|^zkR>L~*;~(d zmyYUJ@esyvumf>Kl8@iZy5kn^54P~&iAPcG+fMhGDJ>EHEOH|VS#WZ#hc(L%0mg~# zL14psYyny)sS?A32H7eH*=e5&*-dnzklg1HrZ)ut!)f6z5U0@Ot{)0_h82Zq5}pDZ z>Z9w#4CS1o2zoDTMGJ{3hXju`Sz|Uw_e3@#vueX3_Ax)tQMN^w9IZ7P#T ziS?gVolSul98y?8=Ch8he@CA`63j9pJ^Gc&qa4QvEUnC&uQGhfu34cM@;7QHV^m&{ zfXgfod2LVPsl?)3DpHkKPL~380f5_Y2ye5OpxPX_a z_es+BNLLwc#Y6$%KGf_vgvJE1w-s4Uq=?Ki(IOC(MzS|6hH*6V4kF}1QOBqTkB3`t z`XEvpX|B$q#)9DT(kQwJ`g0wz_znRbV)oemo~sUcBwRW^uStr(W1Vnd=t?NkyKg3b zWRNRD?5aq&X3a8VIw)rS_^A~!@k0Ltqfb+%0Txk4@f;6K63o~YGyemXp5q#xmchTp z);E6sxEPtRGHzbXZqVAFi$JrzcI;qAqz-08QL|v^CNg1>+L$`*2o#`f!eN0MY_oy* z(`Q9p;6G`VGrbhAqcRJn)D7aB##-Vrt9O6~%J;Qli0<%4Myf6xv1`>-KVpd*SwgSo zz3bm-X>2Z#cEt1Psm`RetMVE*m&&2dh!c6j0UE2wkD!;f;0&$RV5Qe374Ad?h<2di zD_bO*AGQcSgaN{Vx=sEvzl+njdmRdJZse%(Wh<9lEr5-gm8`Nuwc9?sFw&fRq zHQNx7inzmrh@iL;+p;lD0+w3Ot$7zFr_v`a@WAG*+AIU!S%^r^>j0qY2W2gOUD3(b z1{AdHmc62uV|C&@eEX$234J}j-uYJh6Vz{$7E!IaC!7A=4P+q9yR`4d}0vLZft^F@xT@4%0H?h1 z475XwW^-^ijxD-5Fn!d2>I{n<|L$}l-u`vqd&W7i4$-fAuTdd(} z9^c4Pwf>rN#k^tmxCKh2-AP_PLJnaI;j|=@j6@(XYWuk|eYjF9EB)j@%|1>Wl+3L9}KB}@ti{N;BXfqPp8NfuR?UCDx7=_y_13@1tMld$T+86(P zYQ%+g@hcwaI(VuQwC4#{R|n3mIwA&A9cIIo#V=w~v^W|3q>@8#Dh*-6!tmNn7P=W$+y20`X1jvCO^i0(Y9X=la=5K6sj?L|+vgxuJ2F9m;C)UB(3|;w9)t#SU4?Gdh>1YpN`)NB5eIh%ho}>02 zR!$~4Wq`s@xw135J*=2^MMVtd|0W;&H2f;42cCo%(R!6}17#dl+Y_ z)6f(sk@hmAp;zt96W^{B6Fh)64I)+@B=jeyHlc6o;1AF-M5fJBt`8%@CSBcq#&P zdsN-!mDKUc*r068Ob`Clp5fX8+xJbw*9Z60b#Wgr zZ?yvuiQWIO&Cx+IX&#BOU@pQz--x^o<1oF({f%&UiTvSUJ>afIePb3Sk~)mEh3lG5EM}{vRPsX37+e2=USFU^FW3k zSceOeEyLnSm-BVaQTsPIJ4Y3R5)(VygvxvwJ2Ou8Q zJ9P;e1&wnAtNyDc?(Z;M>Ww^96XsW05ux0GPBy`}jclGDFcSX|aqFohP=n*)(ip<0 zQ@(>unvBV&3CkAFY|xyLfXA`De_R#kgP?Ze|J@z={%cjDE5x$yj;$59m1B&8hx-)< zsHcAFezrik=oWjFF+g9*H=CazJD_|+g_Rs5z&;3!6YwN+=x{(#!L49NcdH-oajsYU^rhV#4{W(b@6WA~dY1W)S<*tdl%WO)mAaU+`gD_PsgonUF&n zUEt}A?Ao_p?}imkY`<6qLi<+17{g0RB#$Ry-BJkANjBA3fjf#q0#$TvU7f|Dv2OHm z#Vr-jl~DWBH;pDCFF|Ym&2E=E@!7-itU4=+UE$|oP5XE%$WrW*zCEy(_%?PFUd*Qm zwScLBa9)ryA(+C_o_lUL+}H*+D94(V`2uU3@w;5V-W7Nalbg}rL+d7s`T(4ahuUNW zc-}av@~Ra`alJ$%M8(Oa2>pFq$6ZqgzAI(?C|XEwPVOr-E{@#FpO>WLnP>P38K4Dw zBRBBH?pJ`ry+6(u9ePbA6P&0pOQX)qz#$AzwVV0;b4Zt%qk^#QqyFjx9Z8(y4&6Hb zF(+L1i4QAl(B5I)HH{k$N$-iLMjw(Ryp6MSDpzU6Vlp@dUzZwskWtGM>? z5yk6?&+o^k0$v1JF;SjSnuTP*TfE( zvbq-eLm=qsy;K!~L>G!HAfgCi-6FM-L%aJ=fk(kHik#SOp2Dw8 z*I6E{<(Lh1B+Tn+W#uY0GK^}H6+%t17t<|FyVfHUNfSzoB~0*749W3OzW`za9w7fa z&kYXsfDo5?IR4BxG3KC07F4Rj{GO#LHkAm_mY?qZ{Z#Ys z6l!h*anNOLo?&9drer%1I9f+^FWdDI4VpJxiIbw5{uEnamnb!=dRp>5o6so?EKLQ* zNDk@VhBS-dAr)Qse{70#%zPCJk6F`+6Pbuk+NRD7g+S8V`~Bu|sCMt-ujNN#zY4Ev zt_s*vS2`?zFea{cZdJFtFQ{g(1X{ad)QZ+bjE~A_Fq@|*&NI!#J@f)B0A#(_T1Y@T z2Jf1H{~hA;lXQ~Lhbdqh;qZqyQavA&BD^zMayhc;& zqhCaO>O~@M0Bpo5-@VhQX+kf~WyWJQu4sKxeUWRJ{*&HXS8uG%6dBJa=#7 zAcl$VF_%z5#Krtg*Ke-hjF7lN0*SNqb$>w?^;;?pd%c+ZITWW&$mdcQpY{x-W#t`>X zLBiQhJyE+5AoL`8r%Nb;g{~4D(X9=ikG?v&o_(@ug;=QFniy=|0p`0YekZeC3IS1q z?PtefZKn9c${{Sa86x)K1U@=}F}@;$8YuTq{=#m^?ocar35Mz`5Li6f5Hi}@Xeuxo znnKwV*Z1c?wxBW3L_6YMh{&!ud0W30#8Vg9Wd<*Z$(^)*Be{U$c)AC@|4ek3G3uV3 zsmKPsa>!sJBIaJe$6v@m+bepP1t&xC&unrr%X9s|t5W{llFZ;qA!2>&b^Ok?K)r zOhhV#Q)|+U4L#brJWxy&Oz{%s{9>o+h$Ralm=Z*va3a{V>FgZJQ;fw`aO;MkR1quHA;1Yq(jRp=#JOIQh^l9(kEy6e;Yj|}aXFaclp0h+U zuX>bv+Bb!#M&36m$9QCKAD#r zD+E?ycdGhQV zZkR*YKE1E(4`(H}SF*(O$p9$OoQs12Qozv5wgRf7Vj8(X@Q3?swGxvoH_A$cYeM|M zD+ShO6`6TvLpdMjU2_&1;KlmzhJtgGDK3S}9>(s_2?~9-SQ@xiogFGh;MFv5$~3g_ zXYl?!Cb7UBv94^qfbnp}+PMEO5AJRrK2H#J8*gR4n9YuQMA2aUSQ4yq@wLzCbEu$2 z+jiQW-o=$I4-p)0k@`wQ48lRi{A~;@X%&xviHS`I6Qc+K#Q+7JE*`C)Lgn$d{IcP(1Hhtics8<=^Cz$;vtfm~y z0Rag^+e;O5v=I_U5`TpzIE`2TR*7VU&i`Bs#OQq}*5d*t*GO1pobomqM{4Rt2@Yr7 ze=jxrO|6zMi49g-r0s2PdaL?lL}42vQ78PeS-ILQGa|+_KdaqvzJX*8v)V5@t@$??uVf2uYT};P>sycZvS$lYupTd2@D_ zt34sOV(og{_Cy3}-#|jpz6pk_Qdt+~|DB|TF4!t|+H*Q^sZp!OKF(j2&Qk-TlE#CB z3(vcw3E-MDEYP{pJJLu)N+CJ)^M{!|a`MtM8lw-YL3a9M4$11S=cPIozo$~^|b^1Hkb9i!iI z{m^!Qu9c~;n$v#*v9#{EL(NZg&LW)^rNdbG;L7{Rld_uXyN!-IGfTBdK98W=5fo}e z^6;dF?XE%ByV4L*U@Pi_Bc*LP7m$JjQ0=Z}0?pl$3l+Yc>1`grV(+Qm)_pDW z=0^gDQ|aB{FnRa0REls*hSA2rUzh+8LVocYm!nyfMv@ztB1;tlHbG35g`T^35}>!3 zI!tQ%?qN-Hs;ovgsBY2{6v`^4=No52U@QlBm&slK`rEh=h|Gwd(djAl1b774$h2Dkg`(J40pFh zHl>)G+u_a7sZUQ0)RdbK9l3T+rS;umn<$v|-vhLv7!W#+zuSl>WtwNI`ZebokbY0v zXElW9*>Rz<>ZCcGbuH^DDa14hNpr0l%J#n4k&c$!SIcy#nbI2>7wVRNsVbwM9<+VF zQcgE*_nC{CmVHb8s9_uwACVN`1&eD8Yes^i?hBA<9Uc1EXq54_TjHmsKq@!rusIL!v^lJX!&x_pUjK3 zTIr)#umGg=Qb2#2ycMy$Q-`Bp_Ehsp-WE-w&q%94TAJ~MC|D4<8}Gldb{V4Mk*2UV zm4?kDcD*vxC`qNP)veO$aYB|E7+YyoKBPp?v~rmqD-)iip?p+lm_QHix9#ic4|$5+ z1hb1jIjx6Zck!nSachQ5VCGYBW#biEb9sKbN^Ej+5QQdpzbRi)O>XPGy6*E(Z%V%^ zn7u`}v?5`?NcNhlAjPFY$C&7<(VOrMmjK;FHvdF{hjUZRvug(KNz2sH8jCQ7JSfZ$1Ol1F$R(;R#P{)9<&6_ar zm1<0LtwRs=67}SgPNkMyIB$4>XoV1E_<=FPf0T_gth3dS?Ovfb2;8g{1Y-&lQ@z(u z%U&89MwX$wvc#rPqThkiCW#Mi9M?l>H!x)WXYHa(Zi%To!xmC7fv$eqgx@Ow3Y@z} z1L<}7YBlZ0vbCwEF>Tit$B_T%v>S$oToqs4K9wbbhg!cjXL+WyZ>na==_i#+-7%Ie2=OaX}MM(+<-KOr3= zDvo`C@qEmf$!6p7juMxBXPkMbS`=aVd`};Z2iHye+Z!sucMu`>fg9nZhxO;2t6vbp z*SW3p_?p~?G%R}5bjb^l*t}OeaeiYaEj@1qTY;Tlbxtpy64l7tKgj62OO}G;p|aA# zMH8~^CT?ta<@sHoQIvG6jhXIH{3pTRr#eNzWn>60(BdeK;J_V_{RC~KGYH-10=!C4 zN%s&p^ge&c@rNuM;jXIkPlUQnn`bP0l$0xAOx>5z@mN8{ZlSbu=D6aTbO~{-91xoZNxFo)JPT)Q?V9t(SQf zV1a*~ldjV7r76Iz&Hf~(z3Xj}jNP@WUR|*zXGIaG+nX*pnU7#5ts)Ba9`>N5uPCMj zLmo$Fa`aYp4jfcPc>By`Ex`?=5Q|65SAO4U$O7;r_%opo_@O$MGQ-0WHIg;gukNw#qk?|k26(!ya~b-B9#hMs(ja}+={L`H@z$Pt$1Bl7ijIB@mSjw9#UiTcvf{> z)?x{%9h@p{PBDRfv8o~HyQZ2A+U$)M;NJ1#=2Ri4+9#sWtHXBIOl~M`|CU6e3-xtM zl>lR;=mdl!X+H+N!dHLEk=9Ts{oWQTXK0q6{hs$~m25xh!Af-{U&I3o1;%2L@HTX2!I*G=wg)nvgrd2F20r0~)Acyv91q)SV7e zaDgMFcoV6S3IO{Bqtjuh&c|}nWAx>1%s>}!5eRTdb*|qfscmpDC9KkpXb&b*FUQl! zPzAM;Tm+I@nx|wzdHq`udaZ2AWk^YK+8hbJm*G0Bpmg`3(1`oYj`(@1(#(S1cGzJH z9o!Hdoh}|y2n6-n_B|2*JT48sxTug&rZXxe!V>(3F)TPINMpE3fJg%;i6Z-a`FKrM z8-2z(-6;SH7iqR*uoq2fs$Wofm@TnaN!ixMzBRAYNDnrCP#PNvW)^tfa-!G;1#@ys z%KAi5z!45PAX06u*C(=A(f~RnOJ)-kTAvda(>I31ea07 z%zXT#n)Ex}*=e`i_h*nboQhmB?zVW`W$njT*NPdG>`nCYK$0=yT2gYq_NR%WJbz4* zU4SR~f>!5{@MbvGlNG6S+)L7(`{Og5H7*H?bZ?!7PR&Qjz}&}>CzoIGk`eUSa)jtr%L3LEnHwmuG9BGhxC}r5|a$^C$}=D)y=Uv(SGx( zbTXRKHZV=JT8k=JMa`k5JiFOxrXt#_glLN!5p9rsaGyuJI5f3Ef<4Y)!siq*#+X#^ zWq5V^G-N+5R(!){gh(D(FDVgLv+NX@trwi8&3EXFK{1p{AnB|z9 znWRqZblfC^Y{F@Hk!e{Hi%0S#dwfBg0hwdAcBQF+H&e0ycYC&J$+Yg%-_;lhrqy-F zNP;jLp=VhWq;c0BmoO8TjO>4?z7J^t;S-#!pr4WZp-}~cPi=)FQ;GBr%~v29lG5-7 zg?q933fld|Ev=p8)>_9*j%Ex+pi+}Emw~}Sk3T)yE*0@NHLN%5>j4U{AaZ@pLj7e( zx)x*Mrfu3qHa_NxqM&NT;{^dTPLivss7 zR}jajtDqUX!Qp0%3@Cy(n(~RNes!v2)WycuL4P3ZosV{O{bd%Gblhe%uKybWxJL1R zEP}v0*jmNcoN!AC>V)e>zVOg_0|f}PSBK)l51yo_8od-HgPS*(Ci4p_WRl8G z(_bji)WGA))K^&1`GH82s+kKU4vV$&Rr6}Zsy_MTYdtxZlK_Kpa_Pi$zFDr>%mx)N$|-DoWyo~N?QHdVm& zFp$vvyLE59*E%Ckc526kI`BvN3-uBtMF{n?oc)ytxt4{D1R_^Mv1;WmWJus5`Y;iw(LfeH+aR5Lut*&;@*GaokM`eP<9p%l%@V2wd8nKG#QAyFeRM5 zWpG3#@q?ur10&RsaNK_H{I1piH$7b4Qt>}OB`$pDae`3HQ2GJL=gIEx-Wy4u;H_Yq zNFuzwI};3n!b85_d%D4>{pQR_N^GO#afgYxaOii#QA!uboeKIO3yej~p*=NL(|MYA zy@5@+gEUBvrA1@fL)#${*Z!W(#SC%<^E&qeYxzBlPTeFS(z`k2SILv_2r=c; zx_I${t&hc|*MH~Dj`h(I-0rR_yP1VOjt(7=d<_&|4XI$nhK{@ZDgPfb+y+;8|KZdT+#PK5j(5Rvw6)U4f6E^*!V%hkI z+wQnL`6be00V*6%xXA~-3RLU+hj_d{eK?Ql>IgZa3r4mRSZm?#hSyb5)TCBhqt?{b ze8F@|*{tt=89mm4^PvScLj)sBSlx{a&703HQp85U|D!HQ6IOUjV zIVpU`33!>Qr4*?m6;ooVu_FCCmanvYqC%QV9QNC#4aLM$_=65+Mo!D^Ns8!!GBCD@ z;(f&Xn)sf?0S}8y!>K2JGRC%I91cOdW@0}`%Ypdl!h7E+_S~59GZrWfsA5YN)Ie*o zXvVk8o#lVw$CjGf@yG`ap;BUcX2m-*u#4JaqOE^zkmA!pdY)PA;lgT2f_qIbaw=2M zX5a}lZm2p0wC)ojN&z-n=Y=tQS;$Y}7mh5Zc%foXW|TgQPi$x-NxksKq_cJN@BiTGZA$jcgFb^nf*M4zzo@v(w zV7qtv&}R%_Nov%EY8OAFi!By$?**s{8Mxrqo*T?mj(1E^u(Tn2+ZIl!+L~WtW6JI{ zKOM`DZ~abS&?Z~d6QV?(oh$&{S^Ok?N`)*H;+?Rd%05A4TD8aEZ_ai;V=FhGzgO1( zSD1AHw2*ekskw{_%2(dxu8{=(p<`@1a+FjJ@yh^|5wj&apcfA0?Pf+lMj3+euI978 zu0mFV{|Dx=q0h09qka!Ro8&vYbk3_Vh~WGirl;r?2gAa7U)o}wzzawMa^j}g@&)Ew@p8rS647=Nz z$=V z-Wd|WH>LHWGwxq?%j9Ov#X`b0=xnhGM8$JAuww0T0`YJUrGrocW8|CN=@wc65E=1WLjwKGXh<2est*IciZfgd+DqqkTV4MlQ z6K7^AI{Lv~y44|If|)KiQTIlY*@#0fQYR3!+R4&`c^ruU*yNY@CjzUu{^COU`yOtm z0gx0Y{X}G#Rn|$?I3=XPo@W{je(aI4YyK7*|<1QZc2L z(_eN2m5;8wiz48-+}{a+n#MX#tJyj;nbXnDH^Zxw>uq>1SZ10 zi`P=9Wy9LT6(Ed1O+<*N(EJF2Rm7aCnn0=k_*~-j_kH>5OM=?Y#Gv5y-+Pw69>QGO z*bg~deu0k2Z%wjnZ(mo&64M(1)~|cY;DvJTxNr$P#Ud=mmea9#PaU_jH5mes#2r5l z;n?-R_t*s5;Tv`R$Bd#Sy=++iZ4TX_(QYHv{0S_0HU3j})9!FKMo|NDp`GvPt~K0fBBA9(yjjT( zJqJxSPgggpYU}D)%YrKwLpklXTXPZQ7~@vaT)$;Y4)=sKo3X{La^@sncj?LcP5yE3 z<7X8_Zmn$bRCl_0`~+k02V>4Bt;^V>J}7wHfy=A;Z(xEhymU8+hhU@+;GoN&|NYV6 z08K!$zh4N0k4P}WbxlnJDynd4lMKPK40cBrfbWip6`iGyjSjykR3C5XAg1l!m1 zNlM#?rY)QAEd`KCl=MY5t5sUG4A5AMp!~q%V*-^TKCnzevsZtiL!+m49Nd`+XaAGJ zGx2S0nvbh%#wB~ytXIlel#VuB77443;SeSCR_O22d!}+6IX1);MQ4@-SlBr6FE0#T z3aDvzj#?l(#tujPo)neKPxdR9@sS2mmcHUa(0x7-4?smwuCbpyUdJF${YzBOmkc9* zv~j)p-X6DlE@oyvZILQn*#G_2RjE6sng&s6+>NEinmHHZk!-WUo@~MN3bYCZK=c#LMkhVMeD6#TzfABB;4vdA)SDc;KmR2VM4fiZiQoD+Fd3)h@p zOHJWT-ZanG$12V2q`FoXD$wEgGJ?}Rh!?w5qCoZYbi75@-1TOcoeQ`r^Ziy_-GFJX zyr)3kr|$k{G|$S1nUzy^2l9 zaT>@hd4J3;Iz?m5-+HRxv<`nI?sr<&Mn|BAPEYZ-mkr)%ck) zg+S&ruw|vdaco>TZnLV3xamRw>e9_tFEd(w!>B-!dnoyPemGIzn*t#P{gPkqO+bS*9;12P7V=4+ywYKSeCHq?>!WPI;Jfhc3+7-HH+BgkA z$1|Fxf!f+{;{PWvayhAlJRLq6`S^BcNWG&r1AT~hQ%*;u{agY=vzS+cL7F~OLLO&4 z3zYa>1D3(SFT1m&r$a|=&^a6G9!}$?r#2i^h03ZYY9qL@sx<6hvs|F(T|yw$;}6=+ zd)JyQ)8y`)5tlfi=q9XE11=%z`ca9zY03crpJ=!rsmK@Ej2}&HAdUo~G`m)7Tnk`mW z2*|HCu>w&)@J${4-WLo@;A;(hh%3>P=Ic3>2Y6@teZd`L0Yh`o2RUDEjR@D-_APFI zzgB4Zaxdw6N8{H_{GO7~n&%l+%k6dh=v)5v3zuN9oMc#A;V&S>O)a8c%GLyv2TNOH z6yUbhaBCZ_m-R99gt)e8f)oNOBSWBYq)t^N+}uH!GraYrH+|er6$M)hi_i$Ywiy4K zP!D1f>4t8l>4{rcax!8*dD)_Jpg5tA49^mZL z3{zjE!6?5FL}L%jrC#<}C|CMe=NA|C%PXxLPVw=nclS!X){z)3QV?Y@WsYh?xOb+8 zO6{6mqSuNr%`#Bzas1J02|i4*oWLnqgsRcYd7wfCTd7pV4io@ibx_wp^9uH=j;)e_ z0d5$~5Sza%^d?~M0pRc(F#TSZDs}R=EWEiHF2*6#3rN9N)~7hA1CVGo(hreD?`$ik$jk(=8~IRvE1f7keqv3c`-f~<9;AVF50-6Tl?UM=ug0Bbg!((VPg z!yR7|wH@A5rmU8aayVZB@|**Zc~)LnD*jZ6tERnm2EK*tx0nXG(PB${;Wz&)Sf7PK zHF(M#{0-SwrIV3ALH{b+tQdnc_!Xhk;bJ6XwCbBT1iT-wLx z2TVF4Osu$4#$qVtOiw5V4}dZsAc5{G>1yYOjsYRXnQg?)P-3kl1|VL z|3T>$_zS|ET+riCbr@%Td$H<;AyH{6-bTXEUsvt51!X8i3z|y}$3T8Ld|8B^gfOI6 zqO{(#?3`}V!4vow<1AnH&V~6nBap;o%|lQ&$gf~vPS|{iywo3GejB=Mwh<_0!w)kbw&PNwV_NW*TZ(iiOSFy!5~T}#1re6g~eJ+%Xkxz)RZHPhKV zM(i7z#n@uxorKivfFxUxLo*HM+^#BoLXhR&b4|40j)5LcKT#~E#%D|m-73uU2R-o* zWSHm0?3HJ-$bJ4w;6eK)cdWctujue*4m1rc8KsN`Dkz)H(Zz7}PrM5vPwyzbh?ZiV`SNphSp@-asz=vo!Up;{=#p6y^50Ul-%{+JwD~Sm z3B@6c9N2pzzBZte3=uz1^xOf=!ocnp-whj*(k!#jOcdgeD5CwhpXROxt;N%{^w#bn~Jj{0q@@b z`gGF0lZvYGmcD^81YYDJvQLR{pMqvsBgXpyhlGk%O}q|9k|zO|(-Y{T;EXzx0}E{* z|FLX?1D)ag^G^83EDA}vs!2K``e!f0H{u@VwL2)OcoDk^7OqK|FrY%xZbw5F3Oj0B zddk{O@Ncw77r`uTh0tx^q+5BiEPBgNzIFDT60b}y5<&s}%oQ~jP|Rh}PGMLM!a5E& zZV2#9@A9d{!$+QgiRwJD0TNR?Ej(^9sQRicBI>cjr~08YF{~Ba_K(^` zn&%Vpz8A$)VJQiFM6N_)Bb(_7ie0am++}ah?>0G<{&tGAuuk*{IG1P}lF>izUGYdg z_{@nAfs~=Ti0W4~Q#)2_EqtjvBy96~wn-`bz1V$;ZewujHfOmVtSE2d4`V*j%nxYJ4U0iG_NZcwJq7CCEdsMp_x-y7v8 z`ldYm>_q(mX;kZ^1A3#0Pi*1E@{V~mq|de&d8Prrz)ILwLj@w5 zQ{of^1hPz&V*t6sZ|mu^+S0vNhj* zjY*V4yp>{C>LLRZruy@y`e`j8zl4nRO*gIGUA|{fCZ#gaTdS?SZM65aTFP6rMQ?Rz zIPzkE_L04R92KmqFG78vO4+ZzByUI`o(pLVBvq58o2xhq&wY2aHR#|rkm|G0ad770 zkO=3_-rPO$ksz!)K-pxwy^;&d{0mW#o;^}JcpDBOEZIe%Wr`YIz-Cz zGPt}Z;6F?BRIx`)d>a7o!)_K|vBR2Q|9&TRZ(ku%Y&MzVdto;Zm&5p|_I=)jp-M1o{%@ zVVf+D1bmQ!q;RT_s;QM5Nxf4rfFO4kyNZ$fbq9d7o3}is_kqRCVF!!5a($-ChIG{z z-6DPYRte<>Ppgdhh5rjt{4no5R99XN9;-=Dhc>)?pzV8T_&OmF>^1j4CcZW0cj!Zs z_u$#I;!P{v)nT`V{6x}ukfaXMC$2j zszPHB4v`q*F{DhIXlraE@~fa3r3|d4^4gWRj7YoJ|E1`#*n$SKY@xML3Oclux40gv zH>L9^W`@7<3K$KH_fCi4l*OFQE!e~C)b$(tckGtdR-M1UWm<^{J-ef0Z>+IGaMwzY zAtqxMf6>^502yyc54yai=}2Q51MW4zV-^PT)^n*8(DO#wI*aYD*gY8gijg*bp2A4F z{9C;gYw~U)PE)6#dXEbF8ia6)AjsXkYXbSEamPLG31U}j-2SQ@J(>D7NfcX9E>-~j zFHn+)5n952)=se935Y1qzM^J^aIw8Cs(>F@>~%%1X6BF9nR&>F1bFjrt5&SEt2M^_ zoXOje$mXjPGoT-?C!G-7@4e5$KM{qX5}1{ps0q^hQRlGjcBRE zu~Hh>=A@}lM8^W*lDZ((hp$FuA3lh?WbRuyLJuBiMjCPJvKuzB8*_MU0VJ7z5o#U7 zIOBzOI8gNHI7NwBFv>7p$9r|gzg|xK z)9YF(8FLx}uT!eUE6+?|9(7W5bYwXe8%UL{%t-6ZkEeUmRyBGQ9=qq(vrZ#9nlA>{ zjc%EO1B1{K;SUXw7#DN1a>-Q^l352 zI42qt5a5K-IAC|B5ol9mj^Kv)X{D9|rzUppizas8DUf>5TgMN01(E8ej#1%{n?&Hp zr&{|MlNrcAvrnntzuQOGHo83@Cdm5-QcSHN{Hr^I};ThWF$UObF*3$cJ)WXzNZ*n2xEOTN1ed{H9}30#A<6Iq0hN{Y-|=Hg`6$P=qYGvfBXmAbWq2+x zU|FHRC5w`)G5u9}FZ#z1CXm;K%mB@-rHg1>Oz2&l1FLU@oB68%r0dw7J`3SzT@DNspT5S64(+|WHE{Tv7j-F z16(3G_e)|129kL^CLxvw5PJ-ogqJUSR&+cvh+}HyNs2QNhulN4?i-X1J2Wlm(lZ3G z9G+jDmi=XpUAfZni#k>v`$aQIUM4ug9}+RrrFN;kZ#={>k+e}E!{e`*1zPnFF`70l zpG2>*c@#-maJxVK!wQHdf~ZBq)nQz85|0K3GPczFn2}|yqQ-+^vB(qDPv*ElK=}i$ zdwo8TQ>jMm>@4qydiJ%uq1qS|*CI=^$aVZK15WX60^@cbi(NTn0s9cY2mq}oOPg?I zosd*3s>|N$el-+@rzUA5#vjdlgwULF6x$rv*6mCNh(rznMR^zaY{D3Hv0HaH6KxbN z@Tzs&EY@veU%&F5vjkxMF_-* zS7)?mzVyh{8OF*kj`h>vozY&(Yf?ob`!8 z>mzB`xH7^l4^Wk(yBAHbCYV%8JhFEeQujk<^5=q@c%&o-eN>(_q|qk5%sG%_Fukv! zv1L_&tj=Y9Ur9RgB$oQju3=}syKXRyN3x1q*`(SkwI(xkdA=^Dl9p#j(w%?(4wj;H(D;l`y57ci@$ z3tRX}VzpUfH=RWuvw=rA@nc0rDA&fnhVCM47We)~*GPZayhB?WC-u$}tat16NRdZ( zn&yJKy8MhMu!zg7tv>F5ZTQL2;;(;!Gh49Ki*xS|aJ1(vNC#qDi-fO#b{17`7nlOX z^W2>zh5S9Gg<6~k%7Z(svOkxKJ%hgc^$~4_>ko~8UGTWFjNJ_@n;z-htLCA|OG^e# z7t{i#6|zb=$Hr6aai1#*M4_v9DynMHuk`AQhTE-v6f`T!-k1+_6vyEyP8Qem3Ral3ib(3~8qqn;TKiIzhf8Pe2a ztSt@ae-sdE|5yB;rxef^df`ylb_qvx5v>l~ph#3S8T4z+a1^l$O|J4z>*Z&wz&n!u z*6Uaa+1oY`?w-X{kZH^^7bRzYwj-eKSE=;NyUZ<}zAw6C_ki`6Xy*P}Z;HP(W;7FA z4nKR{sHRt%-`Luyag6`)h0eZXU$~psNg#MM-}>*Y4~~;Yk397L+F0U@4FCt^Kpt?2 zc;t8f%`31|4{28ih=StvOeHqi~)dg%%FtJvGk9L=O~MpxE1xdOgD>> zt$cIcf3@R7a2D9Uye#&$tPnoso(posvJk$5l>L5f^dJU|3Kcz4?MQ0=V_BJ@c_;JE=ENEl9{%{3kl&t)`{~d)1#& zlqom{R4XZ%<1c?wfG@x-d&JpdE3vEA;!c7UP6)4l;cK3Zc7hK*9R{mrE{e}cRa5Yu@CYXcNPg?HJBM2Nj z>AAbsF`D-XkpMpKLB~^(oz2`5J#2)4UdP`~F&?c=?VRKt{C2V*YQMAKAaR&$g%{@h zvV^<}v69B>cG&&?Rj>W}2oi5n!OA%O&<(YL5nGo}qPTG5rf!MXUH}7-Dr+b+e6TwI zZbIg$E!r(V<6_wLCh~tL9vWv&yb+PM;_C|pW{mo5c6IYZVxa~4L%e%icWP#`cQU zPL>{{@&UiU7usP?!9o~w-#I@U)0oL?di>s9pdixJxL0*-2a^W>tLOkJeSH_1Ktv3` zkd*cq210lTq05+*76C{SUD(B}&@bjlAnM|RBlJh6!PkHUHKM121(*GB;DKa<7Q*`o zudwW$-Ej+GM(a5QpUg-0tJ+a)bajC6~2D+|`A^^aQlydusC3ySdXK{(y;Gct9m_FDO;|iw=#I z!1BSUD##`%FdWN+6e*4B)G>A>mi1CF5B|mAG{VTbMT0;ieaY2}bSBm$>MOe}Z3kCj z%=$}-&J+u%Cy)Bh2Va1ywH4G>UDGR=GE}2*t;=JC1e&2LQ?`CavhHNf|f zxcg8+1~xm>x3N5elk(h6A$&?T3}j`rk*}F)C+rN+Eq@4U;z$(-_r@;4UTMqEg`ZEN z&Q}%jt;7wfW@CA3!H(>#vnVC;otgU_dI=Btf;54XD%8^ab163L?DhCkyT@Z#(BqUU zXnMTn;9>?;YBs%dJqwXA%7p-~=fE2*M(!sh6P)c}!-m9f{)2W*`7gIU1OHNeU%?9Z z{3qD%-LI0v|74b`!^knZvN2qf$W4tQg@Kv*-KN^NG08PA))jn9s(!s9LKG2;x4P8r z>b3B>DJSD&@7|=^awPU9d=u~%yi?;oJoTYR^zPubV>P$E)s7UYKl1T1LW`X8m^eaS!x7}*UT`rhmsR?c*Ig418@`MYmV_m zGd^3*zS9hMYwN;<28;PF{ zXCIxHKFuSiK)EmdX6k|p>L)jf6VCkUSi_i;?nCY;zS=pnbFJDmC_Ow*A9h6wu4peC zjgiGS2YIRy26{)2y1nuHl=2FZ>5;6o1qK{1aWz!Z5|=cGR8e(ngQ~;Y;Qv{bgk!u0 zNn5#?hKj;^+IHWCpKAVg+q;MUByl^fb>W6`;@Yushr#H#SC$eRl2y3%rR}5z2M1*> zGj3<_pF`xGI|(`@X$6b1U*Ae$H-0G816%{wHPpp1U6XmRk;KT+s49>4_AF;@_(g@xtbpLtPc&#t>{zi@5 z$ab%WR%uUQv{q6jT{uARgN%yTh(nKt43IHx7(F#P=6wKR{xr1z|M*~CO^jj>qb0p1 z+88zmf0R4G_9cj`fWI0}@F~*EUZ(|cB{yQ%%>m=$1U)t4msA)mY!v58y2OD-{Y})_ zo$wo!Rukh8>nz?UQP9x&_Fyvw06*tatr$=-UP36?Z5jo1Fis{PkRe-#v4EirgCOD= zg0C~pUlb%UOp95T1ba$UT{C~VN9tSOM)6jZ@0i0XLW!9S^f5yq$hjC7y=c~nH~r@Q z{lof~0KUCbIy(jeZ;X@W`F~EBzSHKoHt9~{9r9%>_nAA4FY`&)|In1cPcUX4BU-AI zb&$Y1%tf+xofDD0nx_ z@v9%@c9gnZ6}>p;z2a2P@koE2eyx97Ev5*z7wBnzrEBQCS_HUy9}DR-Q9PO}P(J|* zdmMA9a6>|Ic7wkA`yCv_T~aC5GscH#VB{d4dTWs9yGB^yi!x)t^qMWd2{){rn2~J0 z0(43zu|ov~BtOTmealC=A&$1ZB5Mt~HSy7OODFI7kC+SW;eOUwfMLJCQ|RVVdVdeH zt)5Jfa09sPV_N=*Z$U7^KSU5V1Lj(&TDg@-Uql zlTyJk)%e;VFbKwup_l&p<%s-hoUev@`5DX@jgP(ENDv&JXB9VgaYmP=7P57G#lmJ* zV=xOl#S(ixoIJc3BOlm!()%1E76k;jGN)t;EcrlWS2^R4*w5d=Wp4Q}PNG`%GZH>I zua?}cY#MQS=}sc~QI+5=ep!S%;~2sBmkxEa#D5Q6(AX0hg>&Pc{x8(T{@obyeoSD* zFg3|f2hzpXR>EyQz!>Eb8JOo`b~aID)78t`CeA6BJc&5m#%h$f0r`z%KTCP&|Nrh} zzbq`Z)$$m;$GzVi5`d=JUH%fXih1|Try-;dRBjSeX1&hWj2)u^+ ziKEkkF^Wmyr2|hsZ_E~SB-DjgvE94p}WP=5ZupWb9TM_QFm-j8CMTtB2pek;**t0s7EOs)i?<*PmN10jK?tr?UvkMs-&M|T zGu|Gn+_$b+jq^$T1{lAR_wsikzcgP5d?$;WIKTxH5_$$ioTS6r%uhQaTYlG4VTb=n zwDbcyINhDdlQxeJ5gdBl0ntgQJEisrQw%R_)D{Uu`8>P=UK~-}gyP=acZ3YPDMbH( zqHOY`eTniOPydsdZ6Q{lbNmFsEBq6`@n5qKa#7BALj{pSkbzwQk&qV&Z<+3GINQN^;Hi;gdLa0G%yBq82W3YYk z6=_=oPCBv~{R0P=VNqf1EThY?P`sKLFnP6l!v3i(De*rZbsW(+tz_e*ZnIksHH;`ZJ3gWZ>4G03E?HWE+NovwvN1lD&EE=0*?fO zZIK7Ci0m)b$8EU1KGJsgYGhm7+?U7?B-_l&dCW7&!a)*0gw1h66bXb=Y$y5Z;Wi z*>V7A>|N|LIwN28%tP0Snk)W>g3!Waa71sPfN33{%#B0yM_11*HS zfXv0`Q%kWKdKS<6na`%wOD~cRLSk_e1BL^e9nc3)TMB-&V~{8`NA8Yw2GW#~KMCck zXUe3y&=I%{>+IybJ&7Dez5+w-mtLi%hBsOatU|)M1ugxfiZBJ05n0#yaFV9$*xIK% z&p?PehjFxBADbtjIvEWH0e;@rVcJ(qR4&=fFZ9#$fq>^+7C<%TS_B6&@-^-b>gr#i-j4>kb%t*`0V!1 zOKtol@^yrrQcwl>OwJ3I1M(0u3IEJb_UbF)%J~2Zx-(+2h@1kfC#~31TQ}ePq4^lb zL~`CC4*uGuYr1*FPY26(x9KytUV%35P%H%F!f0FUJmvd%EGx+atIwv+(p*2HwI@QI zF4R4F%twy_ZptSo(;rCC6HuXpFpePCQHn_`@3ItkK5N{>^GbK2fya^r{Ud|+zrWxP zPXwC&>Wp~N7_k#*aCY~Dk}|=3U#yyxT3#T^_mY)xZS=KFcON#KJsuycKh=t@gbR&x zx?Q&wsvD?$_q*s&0b6LUvxuz{a@LzPUwKnSIToAqtA-{$*3{^4qE#0ywY}1<(LsXD z9Tj#~i5d9dWpjQfET_MD+$4+KoeQCRoG-};zt|#isob8`V^iYlwG9J``RDKG?4TsG z4MUU@rk_ioZX;#8-AAkK2y*+Lb#$wsE-=c)gur4-Et#K!mx?E(sC9moa$9OR&+qUY zQ)@dA7oE@j1nSYl-~|_~Sg>vLqBueYQ~&-KQ$!&RBwTB%Q}|Y56oY-&6VPw-QX?8J zJr&L{(MC;L=u$!aZFfI?^T2*Ttp2>~h1bp;fB*ih^Z)*yJD6?NJec3>=6sVO4J|xrKsPGhG7SBsEAR^r#&|>+{P}S9bf)CENfl0 zA_=f^7H*xdz5VjgJQz2Za_bMwd7>5!xThxPQ& zZ81=a(cs-5rY%!t@%o?*&vffr=4Dxyc90Khs_8F*mT0zF{}CXPEn+}&GXMza5k_45 zn%+*-X^B&wBLF{RezsSgi;S*6hj)~<6~8x}E$h*ldt@qpG{VYi0~0@JB>LTXrxHHV zv%kjM$w}GR!QB5`oZ9n84rALl7cL7pY=Y@j_b*q(AD_t=hT;kTFl1Q9y|&6kLReC2 zBACN4Eljz|W$yJ7^GP<809T&h|NHT4068YX;3ezux~UCi*;U&Ay>3=^cx&@KKTX&T z1!OA?vvh%b%$gX7d^6iHf3_Njv#J|U`rK-pnjj`P4lFw6*c?0Nw9KIj9QJtx5G6X0 zNQ##;;I>dwwz-Q&PO?eQQ}3vCzgCOu7z@!?e7T+jN!t+)6ZkUi-Ahg(XM@zlD2_PF z>T+3r#T|e3+XxV&HS??3k+K4))fE_>ugDRySQ;;p@C@E;xy~y5EmP#{Q1p~L!}Mto z1a+j;7H{EIJ!8Vhs~k+$e4^%U0zps$1nPh);gZ z_(s+9pO9?)CU50uZr&H9y8rF!AqD(iJU=D{j~|tctIwzHtZ1#2c%`oAopB@jVdLlCzonKzWu>8sN zJ<*^Ie1fA$CJJjY_^;j?Q#+;uvWEN(gu$n3IQ0lLoTC;KT6L{gw8kZ4?1D^#7j=!f z;%%Ju*rebc0ljV-Bw%yxr)_9_%qnk`he3DVg-|$+J$Y+|!6BMSr&-Er;qQ#3V^8Z|KE1W=V`MZG9}d zJ7H$AoL~FhWKLoSl?dT1|J z(<*=F?w~kAjiA(OZtD+lm*QtV8E^t62wUb#njRuSTsq+EKW?#6Dy6F#(Fc=$mNw4uyZ__;987wd{(Aqi~KSNXP@y_ zi4sEp8YA0zKjDp;V_RC^@JSP1Tz&shu`X2Y5CZ=x!N(Qic0O%gtKuYj$$7iJcIUmn z*kn2Uxv%LL^2B^3%cPFomgh)Iy-+GC(~t>$uGmM&v+4(>`?l`1q8Jq)mY-UyK%?HLOCnNiW3pM96w<=~DiKaSQeufH<{pWZ1N%Km$V!$31K z^4i$Egok|($zDSwi`#iMDpnOwFgvzPTv9jY7Eb~#P(qP$D112Vt6`o84x~2T(?UBb> z;H(?1HsK`cjxKMV@30R6vL%W_fa#xWua{ga83|P1+s?H*gM`j~Hr`_{DZ7CpKaR2B zLh&zO8+!1|1l>jnnsjwlgUgOb4<9Rv4RF5EJcGoN21Yil^%mff_DQFYl$cec4%D28 zUbjgE2cPu2nw%|`ZbgJ$D+a0M0}&Wbfjw*J3UktP21zj$Sfletfcq7FOh*3RrlX?f z3E#}C*W}5?K>us@s`S(=ZvCaq?lwNa9lZS#o6DYbNDJV>>FxI(Tsrg43dqg*`A!)g zl!P7{8|!G!w|1h%HHB7|+VAn)YA5tG<@ieGDdvjSPTC*%Yz2X1T%ffUAn(h(x(j{S zSw++(_(uS378l1}#@nAEPkixa92zX=RqZcDvkzG+O2?3y&k@*2cK0#vtZn%)H5K|z zZFh3yHS6!+9vHfifWJWDQBk{`z9cIW4*i&PJ*A_ywn1x@nffPnu1J4K**Hz*~WP~rwy4e6~l zF{zWGLJjT0thDKOz8y=n=_@I3PK$(2)_NHTi}k}bUIBXf- zH@Ss_&b&e4H&V8m#=3_e=!;ye7n#-$yK>60FF8h(kG(G1RuXvd7-2}@tLoPluRm!` zk)*pW#Z)#Js#Jq`buTDLBtYxzF5S>Sky4z~s99m{FE#|?R-S|3g5*qv>?8!T5ptXA zLK1lUKYNIbZwRgQ_FI9AiQKG=z}-cmi|Qa!re4#c1Kiwl$N~(1=_9_mRY|c!JmkGm z%))N4njDTF1Z5bMKwDM>?(8fCw^hh+CX7t42L*0AWL^aTm&E>vWzsw5`NK2fp1 z?A@_8Fy=ClJBn6!D%>S=Z$RbIIBc9+Hc9;<^=JG*+-QR;w6;zo} zIu}-fJ`}(uc$X4b<2OYnp>nWJTR}x{{&JGlT0=!GcnP9|CKB8Hwj|>bkEpP;d?o;2 z;mKGhIH=~<+u$4axMourZO0|{hsQKs$Jx2%k0p>o(LtE|gd8WMA69XAP-3?)I@W|~ z;7(X>#wiJ|hqxXz5)LEfd|(0wCKOfSk;VDZLwswPvm{TqbkG9lZ!Rc*#W?M5s?|cH zjM=!7%}5+A)r!$HND3vysT)nHM7(3t$xE#TG0Y|jUIA~&-$Vv$uON4k$PG*3@W{Ix z2;Kr+;mvN(^x1&g_A_J*b>)kj$MM1!JO}R&`orZRP`L>hY|6abyC8Xc?H1F20dkj@P*D>H zl`5tzn0WEOOJUC`)L*7NAd=@7* z2x#7G9+gDlHHDDMc$6QZE=34ud9DfvWT!o9VLiKUj>ms?RJ9#sB#WaU?iI$K1ObRE zX`~gs^PXgvzf3awnBePxh^loB&a14HYhF{LUK^=Z+f=boNKZv>6XXhq@ACu`^^keI zpb#7Fif;Q+(PQ!5_>HLi7?=u?=3HNO&zFvvK`tmhcDh_SBE#5niZ9D#dORXZE?DEy zfou|X)M1`lTi3R~rFGknKe- z{x<0DWBmtzssHE;Myi4nxgPN$U0_zPK|4VaLDLBKFCR$(a(+47O}LB19+HoGAfl36j){8pRdj>LUAEelxQ9w`L(kDIBR{P8ZZDY0qj+M2FA|u9~nv8Xjo! zt!<+?zyM!0BmaR1i>G!iopT1r9f}uZGNzXZP|CED(Z1_rc$bft07Nn5z|!j`;zT4s zqL^_=^`(c_xlB$U?*D_-h(@Pu%;4i}V1{>a-t%cJ_teW9ggsnp(a`Iy|PQrE3i6wj84~eC{?ne6vz?h&svz&uCoNGv~zf zzRdYV$%8Rc_L74Ef}L0fONnL82E}4qguQPU9%rwr;oR_Y0wQ)A`MxhI46)J1tqT|E z{SDK<4}q#3<23RR6OkjTeU{MxAAw`c@w2d#0}Vjtji8c#6Hf6y0ipVmLu7LPrne6T87Y8ytTP|EP_4t&di2#_ z^};Z!J~G>)To)=1Knfg`ydO&EV6e=Us@bd_Mhx2K*7GA|b*|;L@IBjcz^wB)tWn;d zCBurpc)(TDUgp+y1q2k;Vo=;7<+WGvXQ!M?!fy@dTC|1NCn%1R1$d&ZnutILv97^! z0DfYN7`EqFfx32%hJDX;{)17=&vFbvJLbF+qxOsMx$o7ERjRf-R5XNb{B*2|0M%K* z_>C)X-$F>dpglFS4P)Io@}dD^hD4LJoV%?v1oCSTHJl-fSqIjleubzII_&NG5{X6- zVX3}9W0v#Vpwz00Db=dCjSnkYJ#N1g_^(SI7sU0qs5|Y6FD>(7dsNY#uV~!pJ(&;G zskGQMqhbnj1eE#2$$JnsY}rek#@JDxRz*>nRZt5mwIY8H@y*fc#NkYvTb22~E#Ea$ zPBm2>mV#xdwg@|ekRW zx!MT2ejw9*pQDqdQJ+S&7b++oWmZH845j2`%2?eG(LbsZr~r)Dou`t&Vl2tVd?PKO zf5T$CZlJMlRI^_#O2T@S-AlAV09~so9`-08^xVGO(SW#wNIvateuoA-2JwRN|CwI8 zb_%=~LhU4BDjdyo&bLF9lobq+-e~hgo%DHnj~k?Hf#llqCHr@Bg0!3HmiFUu=*XHh zuWldiivqJ#JUy2~-z@yr4c}m#$g$icYD$<0JW(z)D)FnXr-pk!jKEgy{dg9`RZvZy zUfmubDuiDP)Cr!mE~oG|iVU;FzT{?NS6`c{_EXmQrH4ZYGsL;ei~+UmHteAHRmwtg zE5flIeI6->Usg&0$8TwSTMG0N`fb^Np^r543Q4#8292VwI96f)V^oY+(I1?HSW{r4 zOtFR_#MehpT@`(zkD2F)W>nki6H?Z`6@X-C@L^?WY*jJCtA=L)rbUxSR}yC!4ww0p z&m{J7>|$cT;e~(fKBU(HOx<_UacX`ERCjFMh$$OS*iScTUR@=c&$|3Z^baFn^a`nk z7g$L?=n~0s^nOp;AJdUO+1sA2zR-5C{OgdzB8AnE(|)aSYWR&1XmeL6V!OiQEf4VA zgwj6!x;_v7mdISqp&;j7)$ek>6TXw48(m@$cuQJbf^uY??!{fX7`{y{c>|a=LMHC% zr)$nZO2KP@r-pVKDO$$$=QZb{{=9V^qqnGL@bt5%>E9BS8s)rZdRIxZd8iLN88hhA zz#>}R=If2~RqP>@{s_=LqT-($lL%j<3@AbcnoCrsJ9zLgz;c95&cfcAdG`8K4@C82 z=H2Xa(8J!j{|!KQ{BOp|9wg7e^+Q0CV1O3->vECBKVAp?%WT^-A!VMCw3tvQ@sICQ z^Mq=dt4Wtm_e4LayAb*yP3z|v;@=Ynt|bj-AI|)-$1X3mRs=nsQS$VOR*ijMY>sD0 zh>oDGguQk(ssoD^?%s?8*ArFWuFS!)F*weNRtojbtNG5#DOedzp3*8PmOc_aNjF~~ zG5ILyc~>5D4OOEZ%Mk5=hD^(TrMX2l+r_hOwvm~Fp=t&*D_s>MP%*%>%%Qm%5v0-| z5&}B`)6d9`fc_`)r*^+kKB?fW@rh>vW%8tD4^L#&5Ad?HyUgQ$o7O_myt{;I!MjCQ zQ1P9k0ruv|=wT38ql9@bz#w>|*~uHsrOuo|?5wl;hWa7EEcYCUyCy6jq~8_!8;UopY*5%RBzD2Z!&y-fGQi(L0)s!DDa{A^EZd4* zBx8M=sr}k&$9u0swjJ{Uvr z+LKn4?c>pQf|rI$D&Kd=;MolcQ9Wz#w}IY+=QCAEc#Mb3$ZC`XfHpwF4FPV6(Lrn_Q~TPK}jrm;lihno+F$V|!K<|G@&v({}|YiOLZndt$82^fv6?K#^($>p|zZY9i$_H!8#6 zT*g1BGU1&eyHZm~v_;CIKwuH_A00ROP>fAmXQxv(HZp0E{Y^Fc}o*E6z6LlZ}WSGKf zbnX4HF(ymN&$A;k3b%{^iNBmha_a4N-(YJdPSNU2sUkJIoZ?tsj8YL4r7mWJSty<-;)z8Qod-nH z6ODf3L$-Zb?|CKTSCpMQ3^TBw@wi-Ex=LYE@h3eda@Er->jD(Bfs^jkhDa-;_M@A6 z;OlKvB5;r_g@CeGOELMhs;t;;l=TJOl?>Qn_1>$GM%1wh_$4SxOo9A2=h^C$gYzVt z+2x+oEDV-D9~126MOpxfc9u?gu|y zdif)k#wNBK>MW3c&%g~O)Xh{WwA+>8+Q+Z%N5tKg8)A@#rYX`(E?Y>-Z|buB|ELawF;WvI*h^Dlfkx1dz*s)_wkG0 zZLEQmtd5u{d@b?>clvBFOVE89gD3a7&|M;qvGGmMh@$`;mJU)8HD+oF*2XTc)QgGg zZ@L+1k@*2|qu3webfiimv<)e|VQAT*% zK{MuSEPu-MjHyqW1<;6R4CyS^a?luiao$Ze%4L9)ghLCMKxf4^5#YouIFxloZ>IKD zPGF-Mp73K>$t&J>%sn03nY-H}hy+t#YzEsa;rq%Nv;1vUJvTrs?fo~T-MhdAW>*Ta z0_&IE+7Hp#i#gK%i)+`8urgmcHc_aWOwmLLu!C?u@BCB4dVj~6Mokap&56)xNl5ibsN4Smyw@!{2 z7D?sS6jpqB62J=^@&jV=hDHkcqP08F3RXfYB@dZ48?08E`OEM-H~3);taEPPLy!6x zzC1W?I!1wJ@kJklpDNj&=oFB13YanN9*o$$R!vqspkd)OIS55huPXaGnWu;XrKQ{pp$STfT^QIqr|O$zp?Q!|PfY-j1?DVEw-N-U z8i3yoi3Dlc?=$NX=qTzmJPmv0QnL+&I)?Dt@8g&bby{K9B#h0fPnBo}9o|p5&3O{R z9}%wEo*b*@B#?Lc={a9zTv`?6phA9kJ26MRa zg1475Lt%XNZhcnLHCyyT&QM^ndOBygBI2__zXbZ|jf@K;;TEwuuZJ>Du3iD6l6e0kBuy3v;*}vwRY+dsWrKL0(U17 z&qzZkUS_aaPFzb|=aUXZVT$@_>Rta{BV_QgX|*l$K|c6ceRJ&yun+VLZGn{s3u zxkB_&jG`q)3jp8;*+cYd6CBPb?+NMn6M{4v?Iy~e(5i$_p(FWtrlTT>jO;R)lu2en7-ssC-!9mQ4xOq!Wt!f=4z zu;PP4U~ZUhWIZme&A2@#O3`YJG*iQ#!S+9kO;wOaYPdLElji%isZ;<%t2cY`$&r9d zzPN~Rk~z}DH@(RDDImmJc=>B`qP8IZS6K4%X)AZVLzr@e*rIyEF-w1H;y&{GIcz*{ ztuxdC#jN!`uKlCMvplGAwn%?`wT&x;Y0}wO!XS_?{%wrI5!0b;I7)2Bumkw4%8qQa z-`Om(8axR78S7Le^QuzB0Y+ORObK{&rlMRfbFm&%bFLsEEd`Xv6hkxrw88s(4O2WO zKs@B0LJ5E49J@-ezKRAzM$zI9b;tp`V?b9Jn(b$qw=zLtv2%6OMjepqSpWLNQMb}m zrv9zBNyN!L3Wt;QSP`Ip!YmyqJwJ_&Phf6K!`iQ3^ECOXHkI=f-ji7m|QX2&H|uF*h(8L8F-u3r`NUy`{;#nv)&gj}6PTblDZm=?+4D6z;6 zMXMIOC-vezoc(@IGNBxzlga%7!mYA%b5L7`0`fXtggejDvioEolTIg)eG9r}ld0FzyOvucOs1Z7lLvGqrb#ovuSAHEDSi1FDCz{0JdVV45`S(@6lPg{~ez6EiZ?y!N^jt#GU{1Ws7K6RPNaE zD2FaM!~03@n)u5%Ava)TYG^_g$H8sRs)m6_m6-%Y)>`AY_luO}3w5N|{=V2)eKksc zSIgPZQlH|1nVZHHGYa^Tw_z^YKguqJ2+?%C{}wtI5u6ecT#k+9sby;Fjd`c(@I z<<~7-FFz8TFKCY7sp7kDd&#$2qIg1W`=L#%KDVgu>$0LUV>V(&KGgSct}%)iC~@`> zpw8ioJfcCIEn&fl%qjk%IChlU?N+ys@=e?KykEpx!bzbCM^re+RLi=y&u`{xB-^hK z2?srpCc93>cx>DK1mJ8_KZ-L?0pTODfGn2gOJke@n+4Z|^T#wf?7y8?|bAnrHicze8U{Nh-UNmJz z-~AxTuL_-yeh!788P~@iY40p+MJ%jg1qun%9ranec(o7SLV_TR5eXxMPoK+*>0;N3 z{C{3uy`wtmJ=}H{?`2Cl&B!CK?MU&{E*u~+YGQk*l7e$>!J`G3Z1n{0e}O8&&a>5j zg-%88Mmju@6si-~$%nb1SlRPV<@56TYbS=2=XjTwqwKn$J2gomE$|zX;=HX>c3y46 zz?AzM|Nl5XS9>WQYnGFV&E-$aQfv{sn~@KBn?c6?+hcUE_;bL%7QBvnKj!JM40!mS zMkV9B9Vw_Qur&|!2m->t|Nnpgx%ztGban!fnvke5nr&^Xqy6m`Am^N!2KFalm8}{9roX&g% z-0<;-S>Z-FQPJtXOatJOtlF8td>KbujmkCTuzBfA?tS9o%H@k?E%Mn2(wRO5(`=RX zif5_u@woHv1DSMvR`%&enXO)7eu=^$iw9qCBBQzzS-G;rwQp@4@$1FVKpWf)J#N)qCf!4K@juqsP>Pu)x`o5lyJtHIUX7CKHe zTLRF);ynwj`Z!0G1cH4AaL>5YrH;xbhYXTy!-_uZnE5yaS^!H3?U1g`=o47avmn8e zn_xGF%gL+<5FB?=X#7i^W^Iusxl+kcCA|qs!f~Hn=LP8G?NgZKV@2|#cH~;oN{P_E z5V{JGHj1^}in~{>Su*R&E}t;zSdc(8EnVcuvHg&F zC?0at_+S>!wf$G5U%dyZ1}=HpD`MPzsIHbmtp#M7%h!iPiLy?g@guqZiC8Y`Ibx|T ztXr&@u??RbA@|D8oE*VDA3i6f<;Nu8xf}|w)dxUCG{ZIO3Je|L)HeA z_V)GPmzM05NZ+1tb;l_zI+SS?5+mKa*|pI7X@kMMe;M3m)1Paf&hdDhgxGUgdQ>7E1A&@2HLlf0@Ku1nypWH$SLLy2(F0~ zy&pK&YYWA;kLdu^iY@9&3?#lnpB$wX${;RWw8GVzz_?DwQdnZ!cH#G^f?6D0QfD{& zjD){oBz_y0A`!jXkL_FaF4Va*=(Xs29a)gn>Hx~i?Gz)B8Av|!+0!F>)XgL1;+ssd z7Tak2n?`jWTi^-Lw~Lw^COx!?4(3fD-JLt|LfFk+4=uy(xRN9df%}@;yu!vq;bQSy z%^9E)gYbRHJ?Xh#mi29r)zCeV$qXey$D0ITNFVS82MPf-eqzuEE#u-kPE7AW0`#3< z7jSVO2zdIU)f2}hx4aIb%o3+CN4$d&AXy>8l#9%mdWf9KHx|53zWcfAfCRgpL>HOj z7P80=^e1_K3lA0(Bb%5pWVZhURw_KYyYgZ=WZ72L>+)haAms7qRo18@-$vu@^*>?$ z$Zvok@t}~%!0vEd5{%CTa=sFQIF}&AZqTw#el(^uqe7(FOWKpL19OgXz^L-WMnI@q zKh+VW1K<)|;<=|A%%kO?^2FFvShCT9arK>ilofJqYQ?vBQ}`^j-O&! zhF5W!o{R*Dccj4}MVPvFA!Zbqde}z+$G)JLDk7NhPx4#r+HZ8XC9N+R)S zARdo&l}-tr(N1hhPAb>Bug0~xv-R%H`bBaGNc<5`qzv&2yDn6`W-;QhKEIZvVh;kB6xBKDuJ9`JsCj^sd=u zvzs{7jQ#p-h#~3dI^kDa$el*i7f?OtTkUUjps(;ImFJbWw0t0iHhVBse+R^SQ0SIy$O2fvfDqA0>Ih4)*Ux{lbW21sY9>?w)mgV%SFq%s z9{^NJJ8SP*A_;Ba1eEhsc?&awdPJwEwtpc3k^NC5@CzC>xn9e%Jpa1|cJyzjmVGN! zvrboseu}kpf_tIn^bF zbCQVsw!?y6MxYojY~RNdQn#NX0QqF* z*dC&ZueTC}uch_*tAOTi=R)DP-n@#G2Ola}NC5}5f8KR<$)D!_09V@Q3sE3iW-#4e zl>JZY>~{$)#4i+`Y3WY5?~oS-;J!|Po9f|rP5~kKzW~Whq-0y$>NWlGxl=#|gqfaK zj&=#(Ymuo(SEGJsj#HA-ef!w|3869a_|1}Pkey!saA~s72ze{wTu)}_I~a`Dikch< zFc0^CZ%5Gr{gn9WoTMacIok$LN)E)rD+$;k;9du3P!lK*oz`}AVFr$Hw`GCYoC-Wv z>cHYzt%{2MZ_k7+ewGiRtf(>S_a(@R3e{wqrl0f1=ro|@@89{6S*xPIU_dH2rf}`A zxx#HR#&z4d#uM+fMnav@NXU%HeQdg#cg+ZoxGo=J?)pclTL$^u6~ME5lp5gPri^d$ zy(O@Kk`DsV)vWE%&hQW99F$T?XaSh6y1KA<;WY*0+jIa^0t{_4TJZd(l$>KtwU5o$ zwXS`)9S9{+&an~7uUi424BmJR&#zhD28j*o2nQmYP$g^oB;KvTP?0qx2yni@cCO)% zq4$^hIfYe<4VL}zREJ!B^9)Xpbg?|}LqL?5AH&N6qD8f^S3&ggGnX8=D| zitM@v_*516VAW3aKrganH*&TXU~y?UQ+EZ{qxez*m$EQs!~rEnfOU+mylE}CTW?8? zQ3yBuGr~wGGZzOh*wwK8YP<`>N6(q z@n~d{A!g#DEV9R~AmVx!v;cd|;zqa}dCysLc3pKYsAbrdgi9cNoaYh4V1+kyetrNO zfLy>94Swh{4UMk7eh64+EaDglV!T4|=WT|yaJ%*51=gLDHKwZ^FAk=DA z2ct&|Nc==>XoSrKkpiCgR*@N&9dOZ- zcc87Y{gskl1!wKoBOnf%LzGiDNI(pP942fx3-8mRr=e^^2JnVA`W?gUnc^!S;7rqU z4)y^gZCu<$F){Gw+J@Z-9x{tWwcLzF{XeT?TLeF~)dy$auDBlOaoE_JMX&sL`=)R* z*emAVAq=WQ=^cFKl$W#jeGw*8l|x^r_f+`eWgzy*$H~Old4f2NIx10W4j3)8Q0q$- z=%e(C?M3;0`c7RNdk~tGd|1-H32~lUoi^5=!`>(X>MwQ5@u|%3a5|9_Oe>%=^qZEoyq} zFMG`2LK@7<1+!SJK8**O9AVYn*tP+D`zblA`f?x_lpS=*C1NQ*FU*x^qs;Il(3j*L zW80o{mI)%z?05wums2>;Oi@r&76J&Lts*%SkxQidqaz_1da`dNUzc{=l+Z zG_2}t-*zo`QU=!HK>lJ;Zb@iL#+Tb3?;h_D43Yl*;(-!?y;U%%i5Uc|Blricr6m9k zQ{UUTU1;~%;y<644PtFc)dG1x6)l6SGxjv@`hnnz`Vcy@%V<-mm(;Hd%pnT3% zer3sB-UXBc_5tcKfa;x^n+O_S;u-b|Gnf^M&@U=(AJD4^-omVADC3;bCgP!o&z%Zb zk2He;bsstoXK|~t!sv~4;Cb?w%V|z){}Ju7lbIdw*<|K=Iu0luGnscrISewJ5eq%D zZ;@mmeuh7ru&3Ljjkd&_9CLago(kfad`tmBO30Y2CHJ&}IX+Du_80a)j*dcR|8m!n z{yN;Yy{r}hIj}3dV@IU^>tU?%RJ=+!Num{V^;`lbhcn?yN*h1qek<6Yl>Zc9VCG(@ zERis2?KO6{BM;y?L#MlbD<+&Z=pLsTY+|5a`oD2E7~qa!eK!IDRog@5j;Eq=eD&mu$(!T%MiWM<qOgHN->zz@CMtWryyEiZ*)qyrd1 zrg=?cmIb9RP{QwT$>0gxoePl*+(Mg8^#d#-i7^6~RY@si7xK_p$9$|hxvJZw!oiF^ zU}8u{jRrCh=d4*m7Gflia-{-W$Q%|YM{7?StUxK!wxiJ3!f(gUZ+fQvEP~1r z>V*&e_iAMa9nZ9%weLm9x~@J?R9|O@}%Ot92j^+>KN>*{cLlE@}kSCg>gVV=XXS4t@&Zu-wS7qh-9@+0IoY5hvdw zPv$Oyj6_{(n)H$^jdo=yzwt3qWAP`v%azw#_x+{DY<^t#$R8_hf(}mMM5AJ5Vc^uK zn<9OoQc!9E$D|V&#!%*c?IC?_39N3CPL2$(M48TqXs{Ypnhy>b#ym zX1}%pPteOctiC8ptXK>YIo}0iQ?zECQNcXb{V#Y0G)sL#&d=Kb0@D_*I_>CQ6hKAh zuxjwQ3RhEd-9t`2917I21fI2u4i2zP?|Z{Y4udtK0<+WCc)V5F(LUPfx{sORyz68{YlX?CcWx{P)xvyzT&dI8xJ&>n3h%tb8CE`>Dv7ha5VVg};7# zRJW8&TO?rrNMOe7vQItHflm_?LyDNbuuULA;d&9g*j-H#D<@YJPU5G7bGjaXo|brk zJ(W%{&3@&~=N8b?uwd&OqjM`f9{b85$~p<5xISGDh& z*DKV4WZI2;bE#LO?)(x#lgzcZf|@=KF}Y(tttpsxw9TG!jH*S;#rADk>uSZ|0~|{r zO+c{c;xKuJhrG4RJ>W z(leqNRHwh}j8#LDt$&zabWK(X8=cl1#@ja5zl4oko4kO%U>|fp(bu-c=Ig`$>0d6+ zuOGQt`S0T)hv|!{B)>W|hgTfND9D}$R|nDMOr5xS4KcrK%2Ur;7C284f3VJh15`-R zq@@GqVZ>B~Bvr!1IZgV?ygQD!6oDavaY&^ukE+K^ zW_yMFGq}kzdJ}F1v~v(7KL3oEW#HM!mmZOE8>SRNJSLnP1Sg7EmjePJG+>Ll=SJSw zki%-ozVu+q6pjeoq6>f>N$uWp(}Kmo?{JrzY13K;G1oMO#_^Xg@i?BivDx1sTfH{{L(w!&d+#xvO%7?+N$>fdl!$yV?(I zJRiP}J-1Wu+c7_fvLkn+b@~j+P!30}qn2TGt_o8+(PDbgi0Ux+rfqLmNk(Jy6tU6v zO0*!jXH@`r409z`{49{ng>Blcs_|{&PJYQK9zG6+K;PQEYO6&NlEJ`_xmHLe! z8yd`$o@pIOMz!|3&_$y*mgplRfIe11-&FM$N`rccmCE4kds?MTgh5Iwj|N{Ci?Sa_ z4|hlDb}6s*<`y)UoDMB~kARM_v#Xw-m*)>h7V`NieIm*(*ROX#Cs~b?xHo_5KrLpD zA*-Md4sS^6Hw%_%Jmg~Ywo?GI68goIx{d`CzRJ;TBM6Q~KfHTp>7l`dB>|BKb5CuJ zTnYMSnLH>0lAo&~bv+dXBCqz^USLNC&OE8?5z>;y>R!z#7q#$YDvgLQN~#Lyfkt6f zAf)T5uj^ZMK?-uKoLNr{c^f*e(F-V$K%NWiAY0$x zX!WVb;)gPgDhjPjy;pNo2!v+mQwnmLaHnD^#4UH{7^adbp5?f}1WmKa)M-YMv{`4X z$Qs<9q170c(XVh9RGlH--VEPyteVe0Ne9TLil)&yhtfs08Rv%L(<=}?Nae~tj zGI$~u+&HD>&vPpv2Jf!!``GuNmHO5)adfCTh#z<+jKvX1@}p$3U+2$C^CgiUpaMa%2Q-l)=l_6s?9 zP)_Zr$$8GQ>9$$M9QhcbXE7t&v3ST_BJQ)<&6cd1;URjCaIZHD0qJaM6El$u%6dBC zLM`}WS3s<|`KbGgA2e$#{i_Fmr;DnQzk`?ZhKk;dWq#7~P}89w^{iRBDe2(nz27=R zN~}APw4q__6Pd*bur0q>EeHs}NTsWPI1$Ga@pbH$Z1<+;SfY;UXJOA{Tx~@xQ2 zSmcMTw~gYpL5{U zQbVt}QD{E`)1{Me~&2 z&epvZO3F`RYs=jmqJfW$qp(Xt4rCfTKN+x1$><>d1iGK>qXY>qSi$TP>FnTg zo)o1iN5B()?ZVLG_h>z|qy2)G$TpwS+9d!l0s%OT zDTl$(6?i9wJRU=nzQ34vruO zqG;WjWE)=_5+A$!kg#+MjA5egxoB0=hfMy3afzgSwnbtLUI+YmM%2{7ac3}SO#^#E z$A%+6!?puG#u=^+0WJ$PN)O#SqSP?037S&iUYQLm1o&ktC;Kr zT6g#!%(CvU#cdHu59nvuI5gtKMN*6kcV`)VUNuJh$$WSSK1M(!p7Q7sYW|3Uo@!N=p@Y*ikJ8V8Ni7eoqCTAvuBHh9iNFQmk~BKE71N3 z!Ooc!Vo`5Dkt)%~RG`E82lE@?B;esJKkO<-P{L1d|uiyFl*KX@teP9_UnDce@x$bGVz-(%4TH7k(MQ<|XdLsOv z+ERloR^xLM05~}4ao4)gk>CB!-b>rU?nZ~Mb$$@2`P$RXpue!E;>6%juO#cc!CeJ@JIY_Mn8{(7oF zVxgPQz45zjdd14~WJ0BTUyTm0XY?U)ic=#&lvQf+I0PAYO;++fW z$8AFH@FKWa`k#)do0X+O&E1Y<3gK&<5jS5S%-1}w{=QtNK+2R6hPT#-7EW_7<)TO) z=Uhd*_RkPcPSg+tA*g`N=dBCHIlmd#7n&2eJ8s72hNw3@_R{M8<^6hLvF90X0Ro9K z`o(1UEQw=V!&szV=+2Tv&jZ(Ol>sqn_)nklnh_F}4?Xm8!cW#pkSA)ymPEqy8pT?T zMMP|WJT$!7o;K`I@9v&~0W;(R`YDzV>v$eD1;T(nqy;(i0TFO?SY8{mtSK}90z|a) z>~8leM3w~0GU_NBk{DSP9Ags1prmHhdsXj@KmBk4v%e-OkiFy;c;1_yjrCO^pc@OU z`9p*d(c3ZMkzut_di5N=Sq5Xjwo)ibsOYd^`{q(n!(|wQnDsmT-DQy*X0h=lCUo-x zTD5#bXpwJ1Hn4AHXm8j;Ug;kje1C=eZ!wYYkSp89MUS?tAKwiHh(YgfPs z-J2cmHrg%+nVuSgZgk(ap!HoLyfpqiyEnF1v_+ zwq-)Qs;9790E%k(*EM87ihv6!w6x`1{k&i7EI7-;zfOZi7};G5pX?@i2ZNIjBo(d8 zY$}?ol_Ffy%}-W31I)C;S5m^Si{j! zlE4%dD|yC?r7>ty;|nI<6Eaca4&&~`S(W+(;)%t$MdoF8>uIic9w(dW$N2_`hAILR za!9d_CRGfx;mki)!;8nao%vS{(3q$XORI-#&kdDPRVJ{N%{lZ%i=#J*jhgLn1OB@@ zEeC1RClkfE#XMbr;1*Mjqh4E@i8|m<^I4TjrN)^pL`aS=`lN-B`RdeZ)C`4>=dR3Q zf~7kmtY?n6=8r8qGFVS#Zvdn*-#jp*vXSoXe8ZhCmsJr6(+xZ`4hMDr@*n*;PPPGE zQ`+6|M`lboOt&W5+ZBpPK~v~klaQSS0+j8C+clh9;0-i=N^T%_^F}#PUT%xszW`fj zx=phso122*zRn?VP;3O`r!qOY7iJD=nHEacRhhr@Gi;3}7~4BqO69~s3<>c8#AN2s zJnV5udz5I*FymVzIzv;Rf_u_J!#T3JcUaM7Vw@@ua=3{{|9npsZuUTO-|e>Ry!t$h zQo^4VOii#2Xy~ZL4N|_sw9o6ru-r6A3y~q*MSxJ&Mh)1W*SDVb;5> z?nkxk0?ikK_FxdZ%8O?mrAn5?jf8<+!;}U^H?8zo7A<01?av*gbkZd8a@m~+3+_xy zt3U_!FqSh3TgU@f%rw#mjQ~Jc9jOQ%Wpb4-2 zcxMmZEpXr@Dk^5~E=VK8+@vcv_`lG-%&s$^4be)aeai|~&o{I?j!Io2p@MWkQ}f~v z#T)-9u3$g^|NndO2}ko@0A#tg5AjMTz}Mvg*QKy_0{#7?uU*?)>wd=4y}ooIv0QcF&nT57wW^*2%v+zE0$HF z7+DfRArKjonyfnZuy614PI9$;9ik!x1qZ2Ds`SG`R!+qP@A9PeEC>4`?l7G3>k?L7 zN4w7Pm^qy{b~Wu!!1OUj?Nhx^wRNch5urFJM>H9l&*bcJD?L$$fFF~L%UWmXZ$HA0>X&3mLRu*Oohka(0d=Jemqk4L@ z7-OTm1RpCz0r~VhfB*k`DT%Fa6D$c<_fP-&X-H#Nf7xU<;o0!opYG3P2c7jV`ZQ8! z$tiFCFIWpek?Zy-m?7`&ZPWL!uOs$A)u8^WUn~z*l7Ms(i;@_O&qNZcBqnR4wi{o% z`g2H1)>NMafI^TRe% z9ct39xwU4|xaXNCvC4sijnxs_DQP$iz>hfJi1EkHKU^Fd&~h~*a(JcSAIvOd zv?K8Nj+TqRO=l8g;3H_7`_P!S2~&PHz(XB}Y1i-!?HKa@Du2`m;j-3x(Ff3t*;u;89hZZRJ7F#ipsFVjA`#olC+O z5kc%U7~*L3Wvcj!aCJi+^GRg5wtRUk09AVnQJ5_{HH{ZiQICFoWWDYO1Od(dSdnXZ z4FBn{gtVmnT&a=u=)pFO?GbCgNaX}E7!ur%LgzFp_r6Ymp954ZD z-?Y==8@kZ81_cmdc7@-WR;0>@WUv4Y5L+f7=Hx;NNxvfWBc6f>yyW5;NBgFkkU3O z655f+o;?6x0!c4Qkp9?F;j=iIbW%c)g3z!m6*?Bq8%~};Bdoz&2r|rlJm)>JTRfuK z#^H^uz~si@!zKUSyciA#6EI=9UQyhjP`bbipIA^(kvkv!gq@y_!P1R!%7uVR|{Th?Nu>oIZ>h~2zxBG7}rL)ao z7FLRAakOL&DglaO0M{ibgSp~5$#CxB;jIj9%2oC_YQp%x&7}2=kMq&l!fCURfCKOE zTL{yZ@qql3-Y?tA&_EG1m#jH#_)ZVNROlrtP&TeygZQbJv#y(SI(E+o*wXTfm_R4t z^}ZMAjBYw5GG4|Z>=Eg(82`osEd=vHF5XrVjP56J`{mBsvij6weAi;=cd`?n3aN2= zxhY37B2tc=>KxEyBo;xLT_{pKQmw_D#FmBIXYW~7bVGuwD39|$z5Lj-K)G##u`xNA zZ^{qscv8*{D=Xo^rX^yI1AIpCPFMwzNI%Xeltkupz$#43JMo3(DD8#88kq9}?ld}pbVSP|a(@k8-UF)$-tLqn z92+5Hq0rK&KH2ewT}-(c7)3@eLgY~?8Y27EV9n6uE#8}Po#i>wB;~Xg-;kpM3bxR; z5=HVhNB+HWIPl3|}r7 z5$!#5l!s_WcHX3=Ts5J}HkVilpcBYqW zIHpXFf11g$o*;6?q5Ha&55EDO$t zA-Xojpo=OL31!uJdPf(QROqi)HAJB!6YMPh5S0-)dqeZF(O=q7hrDwPH)0(gV`MbA z5Q_d)2ju+|#;#4iG)E-Y8vIPhk06|928b`}+&a)!Ba@8Rafav0HNHXMM@T)U{})(v z;{cxbF`~bIg*1Y9;f=pIou(r{GmeXYz=09X)#beke~O8Tz87z^Gjsh*AgNE1ur(9u zTVF~NL&eGI@4;QwO&tw9}KP3*1ov7jRXOw5W)B};m3bU zCR4dPnSUH`v zcSe1K=OCm!iRi7S?>Vd{idbRPL(927_an}49G znV^R5i6Ju+WB=`rEHQqt8bQpr+GS_0H(O9Ozt*-2=)dUZ<-UMzX&mF?4D9NMU91DLsaq^|tfvZsCby~pM^MYcs zZBpYKzgq@jy-3j9(s5@B4Hx2fyBfTs%BWuojIm;RX^yW`Y*ESo|f@BHDxL-~1ry7X$-+XtEmL@MHOOau5Zw%xMa0Z8zY$ z`CE`&oJ{`kKRF`V759NtWcG9r$Dcc6TDN*}6%xlv8)>+~9xLnlKvYIab@2t8e8s4a zN8~9>6O=&3jmt>}i&<7oZ`>}|ZRK1=mbYY+86%)%b0Tx1lj5=+(>>_dEnek$$I-aE z8^9!s=SRrGysTYy6v427?5@W2k29EGJZCi(QC^7j+GyfeVxYl2wCEE!|5+V`?gt)* zmMC={$PJroz_vScZ28WPH=R}>ZD4m%c}A!dma_s?e|+z2Qmcsegih5CSXwAp@KCOE zi>y^_SVb{Z18V0!9Ok<~v{O6hyUhkzr}JG66D4$elKKZ5KBfQvI_9W^XMiQ_1_6;j%U{S215PjLUW+OTFYj@Y>kJs3GhR|ty`hKjRdq1F zg#^m<&1;&&UcUfNbYpDGh-p5jy;9{{mWuw_EG@oK=?)10*isbYc$5^hrV&I zRmvDE42lkH=hBKfW+o=mWZ9qzxO$O7Gr*qPJ4R6RSa#~^IVg%{ZZ{|`Cw%4`5ojfh zLZ~56LMG361kOkrbq8HTVHYEw!FcHW`S?GC?>Si8c*AV|=#wKt4d+R1Jd?sMJz2+S zbcbar7%U!kTWpfZMxuaF6S8#s6NR1B&Aij<8wo1R{&v1G3%odz;NR^|V|o z{=ND+Z~{H`>Qs>rf~v+}zbX#2lGO8K$#pmK1xMf8e=|%PmcXe0!DA4r_jpfHgj39B zB=l_AwgtwpwTQ%zWT-5AvtaDkDn#ha0K*49(|^l$7tzUcc@FvEh=&Gzk^$7f61kC4^>W~AB}If7=}!f`+;G$?A!y`K$b$z! zgSA<-i>~0Hi}Y!GJa{FC&WD@A?)reb?F}wJ78EnqE?@a3X~LBaW@^1QOEP$K_v&gj zk9#9O1O< zZ(_7R>0fXuFX9jv`7W-}t*v_ItiUJIg)=17|RUi6P!(BBnLQ~DIfetg-ItmmA0 zuR)wsRT;JPP8z;tf*wAD;j#fFr8T*?(e1kk-zl`|1tt%W< z_#o|n&**$0*svmpmvj&UIF9m|9FX)__t6a{mxUopNdFf`Jw{)%G$MD(z#m+Jnj!Nj znHwf7-LfR^Nzdtf*Q)V#mDp-5p=an8jhN(0dX8 z{?vdp>b=W6*@{)Z&Lvr^a#Og@#Opi3@49It^_b)wB({yIw}psZ&Qek3|M1O zl8OE27DXOTAoAQPp;%-b=;;z7uVJ|8#hSnaNv|yn*no($?+y(UzMsN&IXHvkF=6+6 z(7BL*|I8*rNeYoA{0;vT?(_q8i`9=;OyI*fV!pc+u_vA{4IYQhdw!P-bJjy=QR|US zWN^Smr_(af+zPzGr2O34S1Cv|eMQKZ^Ltf%rO3}2>rq{P+ zl|yz7|72XnMHbVmeXoHz?@kZ0A%Bzawv2FsAdg^vvqukC2e%!NgmztRV^LIRyhSP) z$ssGZAyf9f3gciirFMA7(uZkzKfLQsAuU zIv=|y45N1}BeE(m3yj2*14hCB=Bbc1Lp|86b0_3bxaYFM-dQGTgtRX^R030DfGUYK z9Fz_%U7APtSM6wdD9$P3!rN2zOtYL~#0t-ak;!Ug#nfg@!R`l)f@--#zvh8EV|;!* z<3Umeiv1aA$Ba!YN5K;-{eVO_`qelbX;5DvIOe~!o{K(S#XKpDWr|vkSF3a7Xt>N& zN9h_}mg%yh%vN)_n*kXOoSm9wK4Vo?#~-EIC)@4%Gh$9qZJy?z<@x9~J3M!}U5#oW z2yWZlBKT^y{7Rw3+v^y9EX=CZ0a zgNRd%Q9Gl*%~F%v_y=NA!ksO19Y8vY%zyHJ@f+t4X5Ge?lQoDoh2=~NE;$rim3#p+ zN6r-!HZf>g@OE#vuv)d3pp&`MvZsDk1zjw@RKa$yAde}Bh8hd17w+ea$bAh^NJEI& zAs0p&1cYR}h^=2Ogpfu*vK_qd+HKZ=9DHKF-JVuceIkgaX@1ZGcCQ>>yvUUAH63|@ z^mD9}pVU&MWr?icZx!SKofQRF9IBvkKIkHnzd&yAfAUEf8s0AAv6u_cUrs1|Rx6SO zP}9@WGYYo9#%l1ah!Z&nmaM=v1BD?ln2RmQrAm0q3Wai&eyV&y%IW?1UBvBl_#Qd;m*{9C?S@!-30sAE}*0lfs$K$k*pZ=%^LHfco zAWE+8oiUQQ4cd6%{PILhi2KB3^lJ5`#7ih=jY48?A3N4x`gr`+MF}EhH9sf4MNL$J zKqw)B`e=t!fU+W&#s;^ZlWzb`SP8#f^;(Fg(2(?kjZf|v-O7^y%{RJgm+dC#)SY@W+{y;aJJKt!#HSZQvh&6$d~vGNSB|G=bh4KD3VRNg(oRXm{~t zYN1Z!&A#b}eYo~vw3~7lxx=EqAsuamVkw`!Ve=>B<*5XdHXlYvyc)TIL;2_bnox!u z-BHtD=r+lV_z@wP%LUN6&a-y!znQk~P{%pv`cZTRPZvtG%45x+4|bk5$XQ!o59z`( z50VxWF$e9xWjB&Qx@%&Lj6NR(4qV3sQ~|LfvnmleS7UQgPS)1aQgEv%BY7DnD1t9` z#|#Tw*=O9))vdD_qE3h%r7R?W#jRo~Ih!a=e{ZwVmTOj%uERgH2iEhVC+|Rf0f|1I zRy!0eB=cbZ2?O10r`1cNvn2p&@r5t}x@-ysgZArB)w0HXE%w3T?^(b--D{@5Zp<%~ zgcGYPz}xs~b1}_6)#lLnnh19o;rE9b(N=gV?eccc1Pw+0U@F;HbG{{TiDm-o?MC^D zw+2V#+TQ^j@poPa&8>c05uRdkgnEwi(6Eaiz%8KG86bj3?U?m8|B0QvU~3daXjQso z;hxVrQ!_1i(1Kx~=P7|huFap|w4n@we~LQSZrBqrSk*dGl%;P9!#nhDKA)UC+W$Bx z<^QN+ARL+|Y;(^vabXW0tT#{FvWaK@8tC`2dz&LqM?_rdU`9-!T{=#?6(h6sw`tkn z-q$-Os?C@z!bp<@q@bNe2PGS>q{ldZfpCt~SNz$Bv6(WWeeIPDD9QBg)vT`&>9z+g z0zd4YFAl!P234Ugu-a8%55SggS%y)&Y@SwZvsO!`BLI%T9pb>|E4nzkl?3-dRdd1? zU|cW%n)4{d-mPMAh+VCRVE|U`gO&y3_)$(su%W!MzoA!RcXg;1qDry-C_y1B6m!rh zuPagrRQQn$lX~qZ$lpyy0->5$4(!{|NN!l1C;=Fo7g?m37$ng!1dM`;I+( zxG9Z>ntGbRV_v<7t7jZiHRV|p$5_isF=Mp@Tfu4aQxEW?t~r;@ug>fTA-PEz8D4lb zq;F$bwMYC7KW?p&UHBsl4~`w7kpjEqrj?%ofNC4;_PcuWRU+_8Ki(T_vU(fp7Y_Q= zhGniO6FIRY(N*0Z)c7~bv_JV8^6fMr;ky2C|F8yE2=9ZlB1?b>Md&yd2;Htw1kXg3 zdi`6W@|LFOsmp=WW^95Z5H*rhZ-8Eao^gPpFDQ#7|A3@nW6jrr`f!v_#EsuIae>%# zwKl@J=4PJ#gpD>>9o98w8687c8=}3RQRfG{P08S1;8l}5^JHqwT|{-L0VX2LuMw&G zc9RgQ35-tnQ_8-{Xdxt$y836JdN*ZM?$VR98_#?n!YR_B5^bCENTEC7TWFpMBuwdW z$0wW69zL(>64;PB!)DiGS=V7rAL%;C9qvUeTz~^(6O&8lz&yNpj=iENN*63I9|_DM zmc@JkF8c9c$>7P8yRYh{hne{4mM>29E)A;KWLf>NI5UjUXeymi6esS?p!#N`eeE3| zL#CTn2S%cqf?BbkDFthHqkgjMLV@F`l^R7^7S#o3MV6cv%{)E0Bs73R&(+BY7sa_Z zf*a*^nxk~(uL*#Fe57dH5~UMv@CY401y|1z4k8&GBDWT&W`L%!jXT^zLh5c3JpA7lt?TaelY=ugr^M)|wuXs{nYES?jLcLyG(%v`t6K60rn%_v#o; z>tqxER)|8~-UT60jv*Y;n$xY3B!&I0w|!Mxerird9RKXX#9M4SHU0$g)SfF?C55?l z&w7G)YVKf4#r6<&8)`R4>9B5*-mHJNHdr)c2idMfSL?8w3sKl>t|^panq4|Eg)AaY z8jYa8$-8WBX&#$DS{?R1#EQtliI3-0H^&&&7rIk7b-qfN`_R4owb1twaXY>K<$k%G zoMoi(t)YlIxA0$&wENRJscqB;8i!eU4v<@klw-rFp1y8*A_|WsQQd6iWmZ-b!=FuF zq2NUtP$^DKBsT>(FBKQYJKt7~*gG8Dit$%s`kYPTCv24DgS?Mskd*jx6b0Ng!{eLS z;4Ad`?EC9kC0x(5Jz$#WW(ci93*f4F!k68L#@5LA-W?aH{X##wZ52}UY%5wwUu#4K zJ;VI@KTPG1h-ZIPTmU(uC(LG!n2!GEO7Yg7|2o#J@Bk@>LT{DE-Bw84hgKuu=37@# zl(7H^L52NcBRV)QS7`?xo42jxF<1UQwk8I7T#z_+HT(|fem32Q?Y3L`6!<)uPfw}K zdh8z|RraJY*qXzbn-(RTELx6Cg)TX+Hz>s*-ylbVM!m=MPlUN)<&V%zW!-&#^8AyN zj_czCN(J5ac9xDaf^3moFE&g6VaHQ7Z>a$X{-5nf``7*2Vw1|BH?K!iXoJ1j%Ee7q7?hCx zPk}e#%51!(5 zUg#?6^Y#Lq!p@Mp%rS1(FrxgQF?47Q9`(vu;dH>kx&1t+*$_jWj%0NWh`k$;r2Mx(?bFYEL~n*5wRJ z`6^kP9e~&!G{1e=UJ$wr+VD0lfcGbTf?Q=c{0OVH~yxhGn9;B zWgr|Dd^;uMj#792?*}%tj=c^L0 zhHX~6by2a|pD%o<&)Ljkh|Ae+JLnOYBPXL|nd0AFx|HLoA-@A{7p55Our;XKE`eks ztZ_5w-4dDhM-h30EIhlli+C@1A4a6Jnw&^PFKi|+pey|;0PCGSN>-dF=P=gKlsN#n z?a>)Gr+@|RxiPi3(uvw%*3|@x4B*eUj-cY=^{^X7;BRFufYi>l6nkFm5)AD*`AZv5 z(3EOal*8BGhX88BrxL$fvFFmRWvhrnjRspl_a;V-8)frD&^xqx;;1#dw6xK`*c|(& zYST;n?J6dq193H^fp2gdnl=K7bZFa>xbHxiR$tw9VaMSq2B2M6r8F#EvSRyDDY(Ky zk(UA*9<^HQ@mTN(B;(ITx-qh$OVM4e|JUDn_Aq#c5q)w#BC$;Z-4Gbsmlot9N-jD( zYR+XQ+ zgyw7Y^4I`SNp& z%=}?$`s<;8HaH`NM2JBD%iT1ay{Bg;iyW&&dl>B5G-3~}3`L2Za6@|TTlP3_9MvNQ z(5#pokU!xh3MP~WVno3~6*z<{<;8C&!=`frn3uD39>t&NP&bSK3bYlCvX*!q zmQ{wesBh_BkDSVRMUY;l-|yIdRMX`319zT+!DH2wVIMLKJ2nW1PdOk zv8SHNmO7+5DL1P|%r9HlJ$O+@H4FCN@Hx!#Gzr@`(%?KOe5>Qbp*21#i^z~>i*umu z;iAer?Z$T>rtK?}4n=GTunBrUu>}{AB$}3GL-&cS^=AMX6bZL}+`pg0BtgYkitxwA z+kY6D(#8EXO=__Fyc%eAPO;-RD(PJ42r1UPCv&H47?*^I7LHIza9G6>KDS_RZ!7o{*E%1Mu-dVjciVQ+A0M{cukB>!dc9b^}s!^5QL8<%J^bEG`|- zyp+i@g1!#p$sb-C zVFq5zZi+;ZjvG|a8h@3a6v^d&vw@B?O5-mIKC)Zhoo>SrzPdEG4~0Z!HM9)~2hXDX zO@P0+#OULISCe-7%bZP<{VbE=BSBdf>!L3PXsLZ*^&c6Vm-|)8kTwH9@|4Q`3S3O? z8+}GQ&f;iy&ft8CS9ayoWuMe(lw2F3F2L54!`o3`QB!Fz{x}QXy|QZOzx?)e&APBT zSn+kTAuve~Q2j!zPG`n4@saOs_OR?*HTYVX0Th`U>nB&{@SIa z7he(&jHVAVx$@~sCJm!m*^~_-?5hP!@s_5(#V!;P`8yQ zuR#iQjYn^a=Gwp^rbEmoiwcsH5Zak%2fZc<<_sluW5_=l&-m!x`qhg*NHFV~c6>`SchNO>>{;&FFF`odteyIT%1S%CWP+OsNR z&u1XN^u)7tMi&19ghu^fciXeO(qweqV3(bc1y!;_=p2Nvi1;^$`<9Qb)K&Cv!FE>+$dj0#Ud)ie{0pnPAz#KaS?xC@SM5U+Q{ zL&LQ=R4)LM7L?bqU!Hj442Q05$pgE@80x-_XGCVHRXb?1u1QQV?@;7XYh0FkXsX)wES5y4OjZBkNud7^!ZBvBzF} zX#~|(AD+gSj|HQ|vp?v?mUiE^sOb3)EqZN!0ud2Wu(KcKY|-Z_DQGCs@1Lh{^~eQN z^5~_;hYK0Ubqn}zCYzcAxhMNhr!HCmM80s##D|mihk`{!T3t`}WyXQ-}fQfzmyjoj^2 z`&Av7u@~8mPSmIbl?nsrp=?lNi(FO`PjmSyVauAS#{dMEpF~S-oI1grCQhkstN;Gh z=`CtbQ}Lp9t{Q7WJN(k=i)E*vrq{_*L`|0VmS6w#sq;@S>WwH}05;)+$3A6TH#~*N zoOso))4j+Oot?bzMPUeGJ}6D9g&ge!C_uU^wozzs@MpP!1kSePVDU|GkKRt*(RKdS zdIfK9`r$sufV5MpNj=YSg_E?&}askRbn;98&qw zmR>;I-karZztyl5lAse2Cx<}H`w<1J$17s%!~J+a+5u&qQ3mqd%Rk4`2LJXAz9un< zAdzUsQy31ExtX-0i6a6Xs~~grVqF`yF`3!3MGZP?NW!`>0O8Cka@7MHxPvV?#n;R3!abPFB-ul$<562dd>5kP!7 z=jAiZ?V|_XA}_o7U6uVmQ6zA!uY@C)WdvjzxTIs0yH159Zhe`Qy7-2(v>$NQ;X_%1 zil)^yk0)eSRq|I!MXHM}rcw&-P zi^m)FG;Bp%bqrgZfGmP~ju8W)QV9`rg|lD6LV0HMfVyf2)nu$6eoshl`mhVugREuZ zDTfLXe09gZP>69TkzQC89`uH{`=l_N6=61R8BU%5oPdhJh0 zkVZuq)RAk?KQE<7zqm&DDrx}saDimgo&QDcBHQgpQfu2eNyQb&iF(->ShsaTo2a{5 z(E9yhpEXjy!^@IIyf)Kg9cMs#ZR29j?JwU;0ehxBHN4UOQn3AS6W9ck>~P5TU15Yf zDGX%@QG&)vH#}j(x8x6V2tPE+ieC|PZyQHf=S+q-eeH>F*mv!IK*MB#8bF24g36;P6cpR8Qp%b{eRMx=i_h z7B}{bNQuEy2e!;UHvF`M!3&P?P^{w|P!)170f&$%-|lWp0u75jO>NRa@<1+(FV6yu z05={KYcCz{VkH16vX^Ox`%5i3&d4%glIwJH%*rZ1n})m>wgQ55N6;}(O3gWUcGCD$ z_eR|zDCFAX_}3=B{bv84b1>*u=v@yGe2wm&Fp|Ns26CB?0=ANt@L z>+@xPSG3}t>w_o#?AO%pVM!axV-ZPD0F9Y`gXH*bzzyf&fU;jT?&-UAy#B9o{3Baf zLgF2*6=yyD#;G&(B7L$w?_rC$0K=7?DW)sG7PM7$dj$V5gYLO1JwI{1@yY79s5w4E zYAAxc-TqIT!CV^_;o;UhHF%BT)oeqR+91B?FMhm+A63mk8L=dJ7-V~429DvFuTzsc z$nD;LQekVo>!C~7IDK{=?nx>o-Y%xi{m^!=bf9Jr$cjsyBAK!1Yi_5BRf5jZ_0o*$ z9b(ynod{8~7_RFd`xJo!-RZJov+boXa#2_-wT@~R@ivREl@0IHh5)^m?+#1Z_Nk#5BkhDkr;=dvq_BJw-XHLs&6`{TjBZT97_)5sfyjb;;VvNFlqU&kgARcooO9oSl8BGhk<; zbL}AZaj3}zPi2Gv;&vf@artUT^SVmnQ0fGkxOvQFZ59rcJV;C@I(|H|4_{%2A?gFl z5?;#__Q0Ed0)gkzxBq`DT3?-cGA)o*f=ot zSwd#YLsMGvC5kV5fJV+*n_1_*Bf^p5#pX2{Ee;zx{=yXf*-jn^S4k5s z*&R5(TsYc}QVX*1yt_01l2enY=MUlCu zDy>a^c^E4f7UD5;P81>HO8ah`pDriY3;Odx4pinkZ#Ob^>?2I^B-5-i<8|7?DL!nf z^_dF4l%X?VqD)6YacUun{LHiJl0<_;LQnsJVDdVT1`9R_x7Gp$fZ&L0jWbq=`+Q|7 zSMuGRhc+p~yAsCtBbCLj~3WE?bg<3qr zG9Bic!L>Ri{`$#~A@oLGzHq!__f4@QV;82rK7eUND?y2SW+#h|c;&M*p=g<35ubQ$ zEPFP*1D^_oVb4{$KPQ(H3S}It>W^HgepwX@_grm9XPWD|Uk;w>T?q+nd#Pc#-802H6M{S=Yca9pNInByT9#5CD_! ztq3onrVhb}^^u3wi^^AGp8x1=HLoXM&g>jp==S)N9AAwwO&iBe2pSS1%p5XkY5gaGMi#qRw{BXvv;wB-2g#FxlE{RGHQ(YREuJ70?l2)#sGWM71~= zdu5%6=Z$}1Sg2i=c8dq-Nmi+ru9g+qM5C!d;Y-5@qYr5KBLovoo$zQ&*IJKze3<-* zUG@8E0xM4}h`CUkJYb-N;Dhf~)Q?TTMzDL0{ z+U;R8m*49;soT{HSW!JrE>Xf-SXp%+RzeM31!YmXRQk_q(yMlkGbWPFO?7U;!pfsG zir6lV*!ToNuS_n$Fw+S!%S;}~sSG8mYFP!Dp<1l>*h*U#tex0x*&{=cfoPjq95PxW zPz!nB%CE?-&OY)QC)+&fKmN|fMHNQ|A1tTWkO3$y|0%&pI}ycYPeUSoztW!F&36&J zx8|BK>jSV}XsF6*mIl$o|J^@(`{C8H0yQ@67Og)s-0MJspSd`s=IiLjYYyN4jTb?R z(cRt48|&hrWl!axNLd51X@RHmxwqIGU1#KMwXdJ=M&IBdVWQeB^$qed%tcGJQa7q5 z*P1u)Uv`mzjk^5jBksjLy7uINlBU0yXnPcwahB(2E}%Z@HKNgfee*V=)xnq0#ix5- zzW;K$9;TDdH=`kol&vLarUrFTeX5@ebb^tz=O%rUWlH%y|93()-=(mxINT>4Tw_rK zVBTUhX6a#?>~OCVJTszc~q=Q6&XrySD0_XEft{_ zqm|pIvNd9Xc0~};UEh1eFE!;`9wUDF0v0*gLyJ-}&>*e^9AlT=n=BqN`EY4YDQ76c zEy9O$l@ix5-9tjLDPE^Ui|W6{OUgklo5eSyjF;*KZLJChM@v4B5EaQj7{eaaxwB1e zqPpVIt}QkQ!Y8OH>W4}Nc#`ECT`j2o@djoZhv@`N`A@{Gd?{OD2hySI*||1A=DL*` zuRvN^LTSt%ut~xE^Cu915XE}y7+-0^aO~uz_!&p@HL@M#ZL)zWQ+4qA|NpC<@XZc$ zdkbr`_SA=#UP=UBF+Y2(9o^k;+1lSnF7)G+{~Jf;6xLySobG(P=B?v9%iuPAU9M$y zEn~AXLxW8!8w;=i}Uc)`oi^nGU*aa0Lj|* zq|-Xb=YxjpW5e~OR_lOyR5&e>p;2?1#odPrAJJ4S7ko50OSXX0zuc}Ecn{iN^p2*%IXyxtFiB#aw>*{fZu=Xc36}4Ye0L}oiT|s-E#ku{21dv zH!}r~72ubCF>FoCBhF1~1LpaUsx`O3x4)@QiF&J@p968ACn2BV!?!g0tT7j9(~vv3 z45Wq@)$yZG-cKvprTe9^o<~Y9xar7nybxC={idA@Sf0n19}}$kbX)UO=!!JDzb+C;!Yg%a_H-IVeXYpgf!-4 ztKu=}M3lhBlxm+ado<6yr&mGNF)^ur>BE&`WI89rmVo^K_8I;nr#Rs`LG4M{9H^DM zF5V?d8;KX+EDN@GxuI|VeAYe8gmF4paPYb(D7x}reisJ}qMHz%dXMawHVEEY%6t8_ zGr39W{7wN9?6Ba)p97~+%ZN2&x2u-)l2gFXKUZB`<(>2-+J$t$UNW!-jQ`c>B`pzY zT?C;b=5I}jRJ0xx^)XNW>UGJuTw8!{?VeurGXm-6%(P}2M7Wa+HuF(S*!$>^6)6dLDHJO~;m=s21pp%J^OntVivpK5ufGgWk6ICvcGK3f za++#uiJu<0(GJw+rEd6wP8&^Gt}fHSNYy;*0^bl{Wr0=^c8V>?>0 zbtdgp1EMRG^yp6#t(kXTJ#VbK!0>6(Mbc2mqE`)tr~>ztmWj;y( zvNV|c)AKStppA^{Pg#d0*JQ-LW5M&Qqhr)FRB**LkeAb7D3#8@xeBvhT?JQv4Ma&P zy&)mDqITDqlV5LN1F4phK?u;Q1F50qtVP<{4XV~8 zfLvFC?lr}J;1j`;LE7T>pVEU>;a5aA5D6i-0JUNqG*))Foi{=y;??OvB#)mfVJ(W7 zTu>{fQ|j7R2n^dPAbZ7Do^lIwtpcw45k$0UfE98t9MEt*KMQ{|m$YenhYtDqRTZ+p z$=OVmKFisob9%p@)Kk~FW&~y71ef$;Xh2NWrUa-(18F*sM=B=THzFxIJm&jrn4Ws| zE*;H82YwiR=4y5n1dFlbuvxNA3%Em`V98fnAFr73#jc_$fM_s@e1PsxD=6%Gf(BLK zqtd|KoY@8E>deBw3nade;3Vag%)iW0miXaAL6G6e>ijWyS2(Kz>fO#=%va~*2sK_T7xVeF-rr_~4M zH{K?i=p~OgJqx^pv2jGb9Ja1DepioL%%&lYWmDq9oNu2l?qmE*oQJHW?aSm6Tn}KW zojc;QpS+HN%`RXWm7fu~pmB=C$-w89c^o%O4`tKnp=`AH>b$P`pT6A z;qKf%3?VRkA2OJ#uulopvga5YKELIAQv`!+^+aLiq0~{v4Bge9!Gb<|I4oq(}c1NN>UXum7ZVeC<#HP~{D4r;7 zVJCPqw_=GFGiq#>Fwx0!WPkHNB^B1oK7z&wJq4`#P^I>*(DrA?bBVm;)%u`Hp;-c> zoVp7n33w^^mv_wrCGiX;Ak14R7bK0+wMPv@xFD(S0?bHQgZm%x^QCG&a1#55>MeTi{!o5M>mhlWRK%eFVywlmt9KLm;g7Yw0iLcDTk5mAZ= z^Ps2DKez4m)t4{r^po{Y$E_2_8tu>A@ZAB$#N*_L^n<^V@u1hB_KDvPRM#igpfB^< z`l+VkQ|11}&RgJ4rNYBMtI+{WDI?Ox(0CMXgNQ+FzS@X)=r6BFRC6;d%PaOB5m%)KMwkHmv)^=jd;)%H_7##Zt% zF*ThBq?>)}&l~;q>ZfwS;PiSXt2kW#B^ESv;V`<6Nh@Y5>C^zv8$Z}h9Z8d^95YBKVFlU4v_8W~O?~o5o~X+pDLWLQ)(I_w zBJ^!vkC`#)cgyCbn8z`pi`ly}3R*fE(~J059#S1f3=l|6K5N)nk>%LiqjfhumuwOK z9O*?>scD7Yi`&w>@_ydg_?)9W$ZKI_ZLXMw2mEFf?2G^O^@mF~PK+2vNF8?pk&Wj* z>)IfabU+g4uL$=&$A|fcIu587E1nV~$$*MWM^xK&QG|dgwh>!4vS*!`R4Jp}4vY#k8L%{j&=L$rw~9n-JiIp0OGSrX zfJ61IG4SxIIshC$f+MC6Pnv(Ov^7Z-n#H^*mQgvb_e(P3JhJFh)uk5;AE|Z>07s&X zSmgum?B1yy7u*)0INCy#rupkKYt7{xB55O^7nXn*8N~6lB0^ZWI8ZVmF7b1=UNU&SimkgMAw&Ho$wEycEW_Mq1 z8zp|T-Ll)b&H+U*lsphnCFjvgON?n81}RQmPgl;YS!|*wJ4#<6F7$Rs1PR#1CQtnWYu=-Bz$9@mt>xUicj4wwf@> zu29SuT-yaFgeWP@5V0Bw6E@R(VXFf_Ivp{t*9S`JjNV&Wj`^=t_GFlk>-}*=z%HDI?(##sM=(AyvG4is%e0Ev)YiJX=bIw5)o>*=GtPe)kZ*Hh=g?FdXy-!8mo;P`an zWay)1Wgq*!5QxSUMXYM~WXIvSE_G+esCx2s>A{?0pUg- ztt&GWz#ZacpJI6m3;C5?z|QeFTc&ia9r4ku&X`2?cBdy*%Zi|$(tqaj@35JvLP#9F zCIb&{UIFlF8(&^4lxJcFYFtr&L_HT9-%2ZTU&9AFYyM5&bl9>O+Jgr@|AE!NyW0|- z|H}96gX*TtZO=VPs1Mo+D6|KQ7-$*?RWL!jQ_g@^OiglMNXJ-Cz4D@|hLOHGQe3K_ z{0~A@*?z$v$6t9?oYm`;I^5ns%NFl@CnK?dcZeW@qYV$Mly=xWoWoupDL&ria4LcdA>(4^ z2Uruj1VJkgs=A6)_%IX5QC&^>A#%*E28|+B7MBhJPknd*WuG#2_6lC0wO7kdKASD) zRrS3JyKw`U;2L?^ccX`=BQm~bKewYt2Rji?CM_U!oa0;X(gG@&cI>K;)zAUBZ@Obf zdJXiF2Y5Zvx&Xyq@FLl&hB;zSxPcPb&lYwji=%oYN)Cbd)e1%WO#;S6d86!sVfJPvgKR8YK=(*uHS#$xv)`RPXT_P}{G>A^;6ynVR)P3sdc?DFM* z5yuYEO{gA1`Df)Pq~JbIOy5AoclNlQyD;LZw>NglF9QCRFhkE2ynO&b@qfw6^}>AP z!qI=@PU+}3%X-2?T?`;+I{lIv`ktoG!65t`OYqzWZLX03m{L{*EH?b6|8<*j;1Q^e zb)8N~wHaw=oCiH0I_oHnXVNG7g%s*iBS+^+`l0o5>h)`Xe`3fGg`j*(gX|%p0pK05 z{)m?jn!LdKEg>LVkmlmrQl6FHTgtA&miLMf%bMobo-$}f@v`f-aLQNS?~mX95@X&D zZLl2i??0U#8&1W5c<`l-K zjtkpt@U5%U{HANaM_nG+c5>fJo>}06ih(^An;8?-zK|`uz?a5!0SN$)73Q(eLW-qbfDY zbx{(5@se8uAsLR>CBt>{M3Km)AyML+XpY`P6jJSC`D5O0<- z_du+zN%vkXM1wx*7rC<-DE|pA^l}bOp z+du#R`7-~zr^{UGT{@)uU(oxh?!Bg%=H(1`2$rdL22Zg) z)e_qI=v1bAAnus{`hV5Vm2Szt`bJ^c3jIN+a@zw0Dxdz3$0-selb<$+nw?j_i*~7s z-BusBNQB2&(joKr-*=u~lxt9dG=hxV`)<}m47_tQob4bFdt!?!2k`PuB_tT%7wv0) zp>Xo2_lT%d`_JUYYh8@(^9Z5%>>VmU4py zVbCjl%8b0qP)lbZ_QtbC?L?oW*?aV}?1Lo(P1b`#DGh?*Tq%vnS4_)*&?7ZD#qti} z*(KF{7q{3&N?xGo`zInTeP_x8XdQ<}ZRNtJ5rsFy zF>}^ii)HF<<1mU`0p)&-%Gjs)*Ek_QQL=Ox!M!1?jKAT`uP377MsiJzSkUJWJE`gM zgus)bsFQQ=imbkD;DI4lgR>JXA6y!v%%N^cj>D#nXnFHG$B-r%2kkZ}V@*+lfZaaT zY4xZVfl8%--WVvzgPTgGo_t(#ymUrmm_Qy4gZ}dJG$S~D$Y;KP;fbLu~_^-~M zFC|p~vaZ(@08>D$zkC0F>I3ypeSJ?)$M1W);(Zdr>TK6}vmOl=m$sxll&F@?=zrY~ zgW4Xr-4vsVAk-;x*H!acHZ%$5*2uhYnc{=OSMhGbj%#wnTbAYZY#+muT)WmWrzkZy zmw_8Y2nbQiUXU)?@u6?zgg=}*eVhOO@>($d18M*Mq|4G3LUT=3X!Za{j|LRm4d2|8 zQP%4)lm0rfQs`GCTmMWX*jjfKe0LJp`ft2v|LD=dE6bT8!lxG!3SDR-6xf3NKfldG zr$vZX=4AhRnmG-ki6Ae?XL*bOAKZHQ5DySfdOxDRd6tJHFIf~}5E{Fl4Ut$d_y5-m zaaq0~Xpgld(UZOR=jN?%`M8{xI&9<--@CXJ*3bDW`KnwB7_6SET|&ul_r~oMBoY)f z9Bjy-Q~%YA&Uv$c_cMjWbL|A}=oGl0LrXTx4Lff~(l#JzBeM*TU3C9}rH(4u8{pg`^$1K1yUvX#)#2(42Lu^6SGoG|N~FG5&1- zCj3xJ)f7o&&i4}A{9|mvUXXmO;%#uRWK#+7G3JN==B|K7lFkRoiL%HFU3(L;3rssiG9LK)QaMcs7kjPe3u^#|vjjIaDf0$@ zw96~cyC0>E+C=5bpiG!5$n8AVv^}AsakfXzo|8@EbbZnh<5~o2<{WVa+NLsb>Co0? z)J&{yoTglEg^6K51BOg9>i%G`JlFi&teWn-)`*&@9)ozm&L4;JDzN7VqE|n5xZaD2 zk%9vSIE0IJ4z3ly6YNEAqi`1;!bd_8+(B##=w3sUp-1qMpnJQ~8v1tW^>^5BePeS3phbk)>NK?xw^F0@D_E zfNwIl6#T6zy^A)9;QC+ALda<2FuK2FN5uW8oxk*as&vOq_TVSi>Aw~2%W(upkfX8@ zz2{4%?uN$&w0aLMpPfOcxd?xXJPU!ck=jkgI%f8hO|6(Hc^+EQPg$Z=uZmN-6oB10 z2aU$_q@T<;lM67z#yoN%Cl04>kB5VJ7DYL^+GWxUqTHx@<4aP-AwxmNc9oW}16WQB+eH z${Mc=X2lTD~VHeKMPU#2vbcXQf{|h=pCpR6yYkgT_ zy~`yko5BI(`{=K{05@C_^e+Wq&KXZ8tWU{o%s$e+E*KQEz+Yw<0a?4+948Gj50X5Q zu|>Bm5efF&fJZb!={1es1WA1m!Z&MRxBw2A&S&C9-*U`dyiCh*pI>7L8b-XRCD1Jn z&Y~inXm%UtjgM77?e{}tzEJ!q4eqkb#gza3cDSFr)?d=kJuOh!(}OSI`eh&cs+a%y z>VH-r7E@}(56`i&zdDuO^_EvBE&h+BF4M>f01g^S0BC)KLt85l0yx|P<+g#ETZyCV z{iS8#SrSd{*0uNVI79Gv-z5Er@b}|=O`^>ktxd3)!vB^U_3^Uz1wVZlu{y?hguN#% zzKx>lVh@m8lppJWN+i|IV}!ZxCTVDWxCE!?@nb%}rnB<|vYK9;y~Yw3VM4L2oDkan zat3{2Z)Tb~u=VuYj6=Sqsu)^^1%~4uSIQIs(|}u`r>o@GVMY0 zFx@PREo-GA8H4&U?iwTL(O=0&Tl3I}=__GHk-D!Ic5)_~0G`t^)hCs*UshLI?afT#{4AWs2K5v3@rO#jU+F$i zpA$X#h&mqFksIhURgevU)R;UjTxfRd2qQR_F^MNTOyIV9(`eZU`ZJYY(cdjr)}OYUaDslOV%a5gKKxM|BC=$8LY*q5MY*X z+d)l^tXDtjx2svodF4ywoTOSKIuLL}NWG%w6y3t(x1*Pv+ObC!_0PQ32`~bgQLnZ5% zckGMwZW~rU|3C{V)z3}Pi}c;U=rxHU&^V-P-WCaBuxtElva9v|e%EJX!@s(I(@yRW zyXA0Z;TUPjI0``H9G80W#f)37u@Xbre<=WgIblawHJG`SA8cU!alA_tHU(1{$?7)E zVz$)0qjG12+u4opMV7!bqIj#0Zn zt4EByAy$2G8?d(*u2d@EGv@n#Kt3$|6Ho*kd&ln<*`z+QlY+YaR`IA!^He-*#qr#YoAq&2xWIU@ z&UpL-F0TDQjFUox+)!ZShn9?gsC}mujMX7}#uy_@Cj?01fOI5p@2r;eSmnT+KJfk+ zoMgc`uH>zYJXDrFJjppjb92O@p4Z&1XQK$ti%+y^>G5SAJuB6}?^iW_dx6*Hxdw^% z$~_jWUR#$U>(otDB%{iJhgJq5*)rfcQPlf0!W<3H=)eo=%JKxjgrGJ>B10?t+-$$% z!8B|%}9q{?_zMWKDd40-Nv!IcR-mG%COoL!Nhz)tYYF;HlYk*WK zLMfc&c`Ndt8E<)VWsY+_AewJ?K`g>BX`m4)y-Ra(o{pcZ4-<$eW3@V&EsnHT!WMa1 z$JSNESQ!94tHos!SF3&UXN*7o^8f$ij8MjZW4CK11fUfE|GtH6GC%a(32#7t3vE&A zWg2q7&Nb56=k)vkiq!wRa87L3s--c~i_9ypi8=Z0(Ql~sURcA&>Zxg%mzzoNfFU+O zC0Bz4N6!HKPey(-ZHE2*4iR40sPi|;N)GZ6Lf62AjzteswMdbK=LI2`)7*Z_9R|!N z!>Z=Au9!gw#{u-U>SCa~0L1v~tU~`s7cb##_0yA#c#>96(Mr~=Bn?(B%pqt89jR0r zfxfk6j%Jm0OsGRd`SXnsV-f)5EJPae3~Mdx+*vW^g#bLG;%XyM3aU*`1W5IjXt`^a zP6nUk*J$s3W3RgmQrC`h|9hDu0mYc6cSl)cpY`Jc!7%(1_12Csu*Q{p{o*ki{qhr@ zBRD7lAMFk}S5)Lt+BdlMWW2WlM)_NiY4X!6zsZok`WG5|o1)O3Is>&KN9hk$U)I`9 z{dfE3P^FZji$4$L->c(zLsa+Y1wzRBWqF9>69?Y19EzC<1D6KXQ=rF{{%2N{r9q`c zf&REo>!P3Xai5z+)L^HmZL42zv@BAj!{dOC;e^JU%J(7}g;?lACOA?UGmE?;*Yb*C zmbu~z(rP-)`zkp>h$cFBWOOrvuvS|a;6pJJhNbx35qR(EQQsP01&M~_%i0#(XmixL z<;(Y}?J4 z0jZ2N!{qD*fzqIBm1dsPFkjMc0phRFn-OzNvM_ngBMvcflBR2G9!rXYZ~i)qcT?KBdEIIj}VbKYvhR5qe+ff%9h|=L1!3JzqS#2 z@3Lw9?HvcL;~XA85N(Y>A&hswA(9Fv#%svdM%$tf7|0XP9UHbbI?2How2G*BZw4m^ zLUbEmKPh6Q>#gzc-nO-Gnw`yy%)JCQmbYH%`-<<;V@Lu70hv_>dttE@bffbMvhkBs z`Tb@dieWD->l@n0k%!aki_ASTpBGP+opHTcq_&J+NjnP5D4Yd^lbiQam#RU}E)}9! zZIAUY8_-1s-k#mAvA?A$u3WrH+1SK|w8!7)ed~&Xrz`IPLX3c_Rw|_MeMkDYbi%xw z$rboz-ZJ973&GQgbXDBF2gM!mf;zU+NoE{;RHh@mKmi|+?|8%+s*v#w4_!ku8M07N z_ECKXbz%BR%M7AdbjUGAAd?Ham5KWx)+LRdo9}L9H!aEw=X!6|A797 z&i>-zEA_G0){}vDQ<7SGvbJif1ng1e7P3nfnpCJS6_kU=AJz$i>sPr0GBS~Fd!bhZ zqnh`0kHvm;_LAOX7V+1mt+$gTe1 zRa%cDqZRNxgOyP=ScmXICJv}wV9lIr8CPNtn$Ke8ZJpql8cv}WkE=j#Fa$gGNiw&? zR~^u_@%6)Y0Q7S6mBwP_1_TNiWiO#{Wfz`e4#b*nCdrPp+)50>x%}LZD6G5rOp1IWJAXU+VAshv-XEq|*gMdAuYui(mA=SDW zMntOfTTY5U39$q<1{`pLE^%76nX1N6YaC*FgaO2IggwKx1&Lu^wBUqemS|7E)6PSs zwApUKk&0GuQP0=Mb*zvH*;(D`rMW7Fk<{j?q`5^FLe8jiccn_4*k%;P0g0 zUIUV1B3yjHHYe;1X==Dr0MNMxYer;F0R$4k@ntm67T)MbIf{Zdft^bdgH)!NgM*si z80+Rpl=DwP6Ji1I6Dl955x5{0dzxn&sVB4qvj$9m1!e|N+%fgLNx{S@`U`8GhEs9Y*=lEsOj;PqU-&h2&@e>?PEC1uF9z(39 zHNIn1glsL(ndONf7eDe1R;gOiYlM+j=1#W~w2OW%iqV-KzsWKUlt&wj_|+Po*}6l4 zjWn;?STNJ)6W#Iu8L<_<4n?kGq-JaiTfZ*l05EmLm00u4kLswHf0Rm}2tQ5V0tAC( zZW;h;H{DGBw8$FxMtbmXdr?5XPiRz}&CW8GUC$>X41%uDB$DlmaQ!`)Mkq>LYSJN4 zTj%{qlJCzZ|Ar6%(39TI%Cq8mLl-C*B+-qVXHyxOzNRO;2~R_(^uZ~@#BoHfDh}Aw zqfC!yM7}HjZ~&(j5}BGiBx}8@{}-Yx@*&5ouP>KHb(K&fa4obs<|W(iRMZhv8l>AD z4*Y@RHRICy9WHDwmKMnV@cYE@$*x7G)bNI*lPZ%U!qD22m6egjEAN5#c^-x>2oKYS zbjc$cwxkkcRL)kL^{Tn~TH>{NvJ|At$mGkkHMtTW8M99i3jRQQhQkCza{2gi6^nj< zM}ovfD=TDVN9~u{U%dZ)P{rJwJnt)l+I> z-c!&XqHmE+R_(D-$^w~29k2s)EN!fG3icMk5OstkPNiufVk*yDWlI`+6dY2lPvo}u z5{0B#b0GHZ1b!HLeEdFm<5!Jd+cF9}M`N7wIfakV$KP+k3tccwKc*0)0%te2%^!wK zyOmhq9LT($w`4)HPjJcJ zgX2HoUq=f%!IE)NYyd)SG3M0J0AEjv`mBAA@BAZzC|K|m;%h2;3dgq=x>%2hpWpH1 z0I096Afd}fjb5 zQc}nu%JS(u7W;lOZV}8rBb)QkpV$Aw`|;lg?o_uP$TmdiG)nvoA+Z58Isp1GB;HXh zU~4(kZm|t{q199%wev2NyLy(kuGDUxSxIb>I{l4w;t3N@BT@R1He-<;pQ-fEa5xOu zy#cDDxrM(_;fMG7@9v8u<{cq?-4JcG`DuYJ} zzX=bFQ39~A&R{Meq`%V}JNdW)4lJkj+uau~g_s%r=&rsum`y3_Fu?;R6deKT{{>V9 zqK%%FuE-28xT}nXs?!oA<=*K-UA|HtsK3TnuNc4qyf%oa&GoDP70Jj<@w~|0vBP5q zH)>Hmd@?n4rJz_nlU8*Sr@UjYD4CDNy_z>Owt~S0t!ftN2;ZivdTEb^Ma|hQW+P-o zO?nmY>>}V9$|0K(b`iqm=z`(8hs^w8(tAl-?Nm5((V%Fe&%D z7b4^1I142a2;&m&-3g_v^Rbo3bq@hw16ga&us@}|?pMi|onuP{6v1YR)Jbj8IE70; za*Yi}9plkeLVj=Cqmb3Viipo)t~s2w6&HD+M^Knucq{URk&4p?dZ*zXBkC|ua=-_Oxn4;>|#^=4k=Nm4a z$x7*S|NmuEY(hVL&x;GE6x^jP&PCJHRv&Z z&i24HE#hnp%V2T(hie5-wVUA;Pd{}pv{LAh%p1!8tz22yTVjiDo^S9ktxP|LpabB{ zV%l>8z7@%h;C{-3y*ysJwP3}YNvj#uy9$|S%E&%1=`-kL_145TaZNo3!8j=`t`!iY zZ0+1}A49W^dI0E-%*D*o-QSPoS?RMs1B65W)i!@P;wTS*Hfoj`sL772 zY9q1*`8Oi3{N&7=nO>AVqV*TwS`WNJhJqUyqF;;!%~frsb@j>r<9a zCQ_~AVaIVp+Qbk{<^{k_oeYtH@n{pD5sJ`h{R?Ese5bUmmPiD1_o;9T`WGSK&_CSs zv!k1GF*-{yK-fS%{!at%kSm#g<@^lbEUO^Ls~~$_eV+(_azzH|6{Nv(-tEu2V9fLE zbufYHwqDsbkqMoAH@Vvo#KV^atf)xzpqogLILNu=V;_f0nB#F^_ zYfnmb9|&Sx&g)>N(a6(bz9Znw>2b5D@y!dfDd`UXcEv&JvJ~o^bNIk25;Bss#I0mr zSL`F`4bSX1a}`5I5Ch34kgQC1>)@IKPdtt z6AL0T8HplNS8rSo_sO(sz9*)`$y+|i)gTw$&#-6c^23;d6Q2MMtz1g`gBtuhrz%t7*95k@^HJ>S0gZi^GJ z58C^WYRx3_12co>Ug+vEt7Y*;bl9nEEi`S+i%LL2ZBc*6j1+MA@9zT}GK@ zpzJOJ0H5~qCrG|!%&Z^0H+6)h(}Y1#RiV;vYEd0_YlA$x3!f`}&3W7`@q^*(m;{Tb%FYq!!F74oYNA`l>5@OV%jNIDjSiNZPFBOo&+Q5n--)-C zOcOP2-%x6Q|Neer&Hg`E7Gk=p)S`%?mb~`a4yz2=Q9$47ecC@zssNqaGa684Q%Jh) zXzB9*|Nn3>je@_7<@5l%Yj3yoYnZ%$yavHnnX!{(Vytrm$09uZQ3fhA8@||#S;*NE$$Vn#-BhzmVpjU!f+3@N=_-b=kknX{;n@_w#^oy!u2*_YOu{u)WUxg4 z!_(-~kCxRmC3rmzR_ItazZcnTL_Kg4l+&1*B3vQu6KuE0n%3n_ecAz7Hs;lQhh%?Y4d7>o_oz8M6*@5Nv6l7ak{R5htE#8^DK z4@F61oqV7_M&U_HSx?#EVhy2 zohhYLhOvYWKmx2|s2v=2-#>Afr*<>EyXV=vnASmWMEY+|E_8SkSyC zag9G;ukW4f9O7_C?2(!D{$fSbWk2aA%@b7{ByIoEGSgCy;Up|6bH;~F8fL~@v8X|1 z>%uG>KVNQ#Xk{pcctuteNsQo4b{ugJ6ogqcn$BjV*aKj^nu7rb>dey_ZU3DJPaiXn zZ2}ljLA;<<&SWiV$UA{S0i_SfYkH)=L{1=e74Q3N zNc}jl<1N@dzl!^$Or!yfLer_F6l?vX-{VDLmk`A-Nc1gR#MWc2=NWLsd-=bOp#c^{ zO3GlOp?JAG(0nt9elQIp?n=6|)HX-sb&x{AuLF9Y4Ah+_bhhHoW{TAok-_lAu3TW< z6F*4QX4i0S#O};rAl_d>E*mO23xh0C zJ=q>^btf(&8-CM4PD(%%9;8G?LojhFM;jA7nsQt{h5Z` zV*!Viy!+Ln;YGoB#$zC#pgvBqEYy9eXIUH*od|k5kN!+T`EI~d`WYWVe-+8fXX_Va zkU>W1S+#;5N_XJ59>|Wk^W58a9Z55fMv6HC8m=FMR$zs8T4ZdB{as@--_UMG%v;Z= zTa=ZpczDv^=%}e~@>RvSiyLt;3856^6*qjwKkJZ@{N0sA=^a*IGIN?JcZGi#KbBmj z$+6+4ZP&84+|w7*xVEzJ-uZ1QVFC|GuJTMhR8MGa`Iz~xkBI`4$H;+pG@4ru$imdd zXiZK8=JP7ShOd6rr0NGbd*25H!V7q^c_}>%z?-r-{!$33Sv$1nsU5R_Jy751>d``N zOi9vRSYbD|H+fjj7cy38e2}ztgXFcD#4sGn^_ro*n1wHst)NT%F_B zziUn|l6n5Qz}IFQRN`(t7-aa{$D}SJTgya+_w0LRjUJXA{R_~aw>-{YA?Y$$qkMV| zY-Q!-jg)%xa?lG)5$~eQ=sCc>-Xm@IcVIt!q~Wb9XcHUur@mX1Gp693lJyo&n)Zab z7$Z90TEYKz>umY!jc83oob0YG|C|g8n(i!K36%-Jod5p{rkO>)c^R>L239Y5X|aS# zd&`ourlCJ(r*#bntkfl#=0R%;zjr<`dJ>Zu$+n<4WgVViKrhJfh1;YspOTu4W2M;AjKMA@EMHM!BivR4v$7xH-HU(2`M6+ zd}Kki*tAZKk8B$YusD3}PSe4fr!%8Xe>szR+=!Xer*b{c2)bjNKeh@3~&)5sPw2p;ZOckJ^_>_Rs1_zE4 z*34GGSHB6=xOe7x6XUtdEu%HOLLZMg zDk1H3*kn6pMq-*hb~M=|>)?$4fZrei)|NSH#A{v_*odw@1lDmP|7tgP)T{~l3oKF&cC1`RhZK>)prfcY=`qY&>K*CM#G7(YOe>&#>ib)(2fzyF!zZP?`zSl#O% z$+bfYcj9czrC{t(K&*$m4-AEF(4shbub*RU6I_|);mn=_?LAJ?Y1$V#yYNp|>jA&@ zrm;LjrKW1i^jmYtvWGdM$&YeRh;gck{^KX2x@sY_c*_ zxOpR5dIz_}C%nX#xzX-J9U)gpu+`L`@8TuR*3UdLk! zND6(nst1m#b3g;UW2_7cO2$Z^S((6Hy_I3)V6~w3Q^Z@P3MN&~(+Kt81jw~Ma6N%4 zg}U8dV)aqB_*czJ4KS`p_!bkIh%udP<`9}ZyB$#E5TjvgY0iQ~X0mIa_gtf34l_oFA`3-sOw z)oX@`MJ8%^bu6sVx<}`0i1^e*`Q5Es$a3J&Bpnt^Ze5f!^>Yd~?v6BL1xoIgoiZG` zV8%B_G|MLtGd>rhq!-@Q>e3-SNd#o8PuHgth$%_n`?#p&n|I9V_crw8xiqV#d)edc zI|xg`rRvyP>PPhI$mTW2H}siLDG(QgmqzN=G_}F5qq9_oIaRS=k2=bXDKxqdCDmk# zzrmeM4}351mU6&wN=0qM(J9dTl% zNTRrj7dQ=1`SfYvR@T~Prf`>=Wkg{g{M8BpF51h7b=+C8EoZg?yAjNm2B-AG810{M zNI`dtW??r(RbAsnbyELTP)I!sHj8KvBs?+(HJJ~QQkC(;Rdwf zrJaLpwS*TOLnIo=J^vlUSNb`jE*MS0WXt}4nDAn-xybNuT!A-&m?(;qSk0DRDyLEb zYQDpK3NNK~ix|BfXKy?!eY=rOq|s{(KlqpnRbi-C`S0>;_Y2W=wRgvAG+t4Mxv5d4 zxjO;MJi>E+mw>AOrV%(^XpO^w7H-^W&-+Smlqdl47R)x*P+ELbP#yQi_RL z+PWdQ(n$peB|r=F$8PW($1$Zm*EOugY1FAS?PI7?DjERwLAA*@U5Ed~`i)&ko&2>l z%Pco(oC)_9J7W?foWg}Zla)(RAek+dK)2RyCR&4zh4`ohxk)#dl4II$Py|W)Db_x_(^0r!upwx$vVvAjk8R-(zMtws z{U%A)98&8ww0C#@*zjUeZ=D=WHNyp4%7DYB2@$XutAp9NB1wP$>KlLV7zOkHiCNwD z|83R-`wv>@qO_x^j`-yTgHjV>vw0+nny4s5q0;&G_ZSdgwpsxg-<4f zGlWG0$seGsCND4`zXI$q?1W9U3R4;UMC&0Dd4BG71)Nm`4}XwTS`N zApk+_Jk17%k-@jSvpz_!oqS0ie+jGtSk+*cB|8DR)VLbAI4#N|xYF5XncZ2~;^B8B z$x}cjP;hqhx!60r9wz3of~9;M`i|gLL{L`_d{7;E_d_~|+QwQ|H#k1tj5XPlaOoH^ zg>hCpI4de3E05P%#`!wC})vW7hG=ZX8F=@#y!^R!38!10aho9ZA!G2qK@DjREj$7i zxjHHvfKD1lDHbcKBiXz4-T1%en!^qu%d;%Zm5^+k)XVL}VLDqW2SL$ci5{xsO{e}9 zneTZ3(tcRv-ocR8Twh3#2<8)a*70&`!|h6-3HCs+&5Na0q|EiGX{>I24^B#cGlrhj zL=d94hD^RaV+$AgYJ|S|$XcUU#8n0}Fdz$z=stn3nMR%^8XnOtK z^sT6=Qf+egMyB`FY5cSCagH-8hVGKxbb~<2yj=r$DKHZ(zG!TMaBkIze$`vtqC1NM z2ii0X;Z@WBrNM>5arBjD5EVKZ?bUeAW|h>mqY6t_X7b>yKo2)sk3$)SBi*_Yo`+2Fj5$ zFhX1)r0jlcT6fLY?)dqoYy4c9Ho}YfXo^;%t%^T`X2gK%wO!4!c&WHN7~Uk_GA z7YILUbr+ny;8;7iou=to)Tb^vLyJrRGp%hYqXVJp|17ibCZ=9}wX^pJ;fVt>goAQ! z)93tWx|9n)-~M5kDN^N8saAPS#UZ|0#$N7@{kiihH@LsG(|vKXwz7GDG1?a-sQrK= zn^7T9x8dp30wS4%7Rvd<=kfeFn_e6^tzqUA?X4@Hb9!V4zQ;^G5|>8pq@A(ix|U%s zT7vyo>0OF|TFbOnM625n+L)oHwbTD->?Xyi>e`WlC7FH^=icuG*f9#B@X!X6s^>`$ zSU4$&{l}of8O$sdr4Em|JoqS^*x+*?HzRp=UFpz>TG$q_j9r3BPjmY5t_0 z3r}t07d!+MeuiIl75f4mwB7f-1RljZ*ad*(KaYw0pz{8o<3`CiCFHW2*u9UL2o;%Id#& z`3JlF()ytn_Z)GcxvjgT2Wz5b10#W zbWWzh7urxX+U@)xG$e2A@5+;Qu?|Fh`!rT#_|qsfghJ@H`Oi8ApT?`CPQ{V2N$r5k z0RTc#YoU0P`6~q<<2Y>Up}_Ho0fPW9SyCo*&A$%XJ)#CXg|(*L?e(f* zQeN|x)B~V`RL~BX@xrnFXQ!PD` zmGbvCKGo9%eX8P|wPosTD3$>}f=`_ubAuaVh~FJt&8}BFc6I9fIC_Z44xo43iStg= zsH%rlxStOn$L^kOJ;>yd(?J%GKfJpYCN#FS;X%E(#`UA2W?64-iBiPR1^GiZ%@=mj z$micVSwW;dMTn9`jVRhLO%3$KSY+yWW`TpQt2ojogCHo~Ri)!O?N+(>=~&5Qt*=pO zv<4;{08Sy#60PQ+!v_z&lFhs6dskj0iCLF9{Z0_C#81TFO@;gb1wML_4e0TE*~WG= zuhjK2sA+%uniq+olwDJKesdFT>@8zWh~k(pkemD*=vGqx%5-RMd02E0jU8~}U$yMn zMwuI|BbI0?Cj7Aj{~vtgf9K)*{^vD{eX(K2&sVYkASF*N)}cd^ybq?Tm+U2BZ}?aA zyL45P$%vhkd>^pRDVc6cvq#d3L6B2S>4Ba*|B_;*(`(m0AX{e1Or%gmTf4BMGHrZ; ze0>Lkjf)kgkmn?M+?V^{{5!GUWJ zK1g<3&~T{^3@t0a5&4XKNZn00%VtzsmWZJ(tn7fb2GB*CHkqhgnn>fpS-lb^aA`)#^{pvMTdpOrqUnN?{{p~l*GE#nDQWvhd%{CKt2z3^0 z42qJ(YT9T z=~n}Savh+?W#IX<+MzASCQ&OLKh}Kv#_|>ZA-d^Dpv&BaIXj_H5rO=#>UuQMuxSmf z`pmV4YkH%jz!Y17ZuYnO@>?a`wmpyD30eXHx~Gb8#9t3@deyk;i{}OVO8JJL_|7q= zQkr5DhLE;>U!IbN$7p;xxv`KOE`I*2vn~ty9;j$@D#^O$1(P7BMBulCVc)M6*%cM+ zDMMm@_7SVQ8^Pv|howk%#s(@ZB!)##mRUA1#VH!dAi1OAYx#$Qt&6NK+B3a_ayy?d zJlOmB>3i6HbT|i}2DsFi_Y{60n~Y<9EWL13ka(^8treE}W2#C3pLMdlCls;q(2o*} zESN8&U(&Oc0%X9oY!B_V#t(BV@2lB9ym=x3wtDZ2c~nk6&WKwh!;?K~?=HodueCK+ zC+@KcZ#=uIMu?h%Ku;@T?-aX^K(_8T zfJh#94kz|l((j+kE9istDPHB?k=H`9y|J#9hvfFzA-Nx4n%;Uv=S^&mCWE*5JGI3n z0XnE=9LvKuvXaK==`01R_7Nr0Va7>H(MUb+|ne~hfWu-qUIt(!& zf{6@cl+0t^**e{Elw40jMgX(&VD0vA)%`~+gCMo+jP5$v+LzvIrtcYf_&a6_+}7sh zY{!~NO4b%Pqw-v9`ZmNiCyLqA#>uUPClQ8$vgaY!5NM6+S8kpSYHoaKpZ6B(BHSg& zfa;9ScJ7H<@U!?dQs!&B6Iu7iGhb$UVL-{CM-{|;KY9;?dZLmROqY0CFsN;a4#c_l zwXxW(6;dGj0*cP=Hn961eR8(A^c>4p)n9CAuE^{ChJwtt3Sv@R{~aYZYb)_v$2NC; zK~L@rY+p&-NDe%UkRL&y8p4a{_XrVWi?58~wf(6@sE=-=S<2Y#=TuoGH4Z>x3dR6T z_n8=H|Vm4FUZ#8JJPE|j}yt5_S zG1pmxEJVkPQHvVIn*=`Loo#E#SlWt;8qwR)R)fpD2#x}7pICXMHjr1+ragCrjQy5# zj&b}vLQWy|SxJ@LGjCQB^s5p-eE1KqY8}}D<4v6OMnd)TPNYBM^QO-jgaNxVtZU_B zua{X?Ib#bbo;^eIz8T*_LefPC)vcK9*M&!#kybp98Zfh^s-m(GOu(i+#S^zhP zNZUJAGy8}M%NEPfw$}x7K}e?VFa^%rXq+(PFB4dMXxIm&OG2aKA$w36IDlpLr6F`Q z?SC*7<22Ch_%Rcf4Y3GBF6GA)1}3$267ldm-EK1dOhsj{|1?99RT7F`n;igd{`+dI zVOMO0n1eYAxASdpkIaKtM3~sZ2!B>X(Cn9QrHoc)SjZ+42IVN9iHu=I7kjPxxsjis zA8fz)^i>YP8L#+k@jBlgtl&!@%SLPMncT|@y)$KVC{yea2Tb+ybR?W|0|#Sr&TUH;;z8d?Qjk( zFRMp$+Xjx(ngb0bnl=_}p`Y&@1EMQwPCI{*U1a1`NUt@xG(HO)vzq zB$?n$GHO%eK_mk_kaVoR(^eIQG+DU~i^O9b@6AlY7X{gjYBm{E>T3-h2I65MmXH z1@6!6ePJI8u6#ZhF>W6Te<5MG;K)L6?|T{NO!IFk!SxS z=U#BX{FZzCK*AZQK0r@6^{ca{Or7_4#j-1c_jaHps!Mx?{gq5-nKRz70DdVfpP`x_ zs&iEy!QKX6Y_Tl<{%d4Mqc(}2`Kc=$(x=TVgt>jMj{O%U1hF0jeL6Xz{N_3{!4S^^T1<+1I2@qP{!uw`ZG0Ck+>yx3l> zqwyhol|QYk1%?z%l`EoINb+#c)rYscx-`PBfZBueUIU)6vq%1wh{QF?mZfMUYJaV_ zHS1#JwowBZ$#I^A1m6+AHLlgohT%rM{@}c}w(aQePU>i%U`z0o>!sUlfa4kTqw^;c zUR*&V$+;JH$>+WSauXyZ%)h9+Y}SiWl1Hi~QdaZ|2JSx|$00LuE3DAYUlXqrBUw>5 zdVsU76Vd=V#`i4oj1zF$@)f+E`VU+tqzeI zjxLdO>rHn4v9~uSxG)%l!KE@i1-!zFIDPf2uFmpk0U(-suHL!qFa50Pq@OIC3zSym zT>hpBZ0R6^{wS}ARC-0-($hrkpRo||-sgddsaq@DG793o!Y1*<@Hcflg^&*_$wRTfIbS-+zB;Cdy=F3y74_ZZU7hBAeu3 zUDP8z9fa@csz8{pb}~{jGO?D$6u(kk5-`8{cReQCIm*={rRwuB1H!dtOPs zN?F*iHxjCsl`N&e0}{Dxpu~~{DG(LVfMqfmq>CFogN!=*=`=X0EoClxCm+Uocy-3- zk($r1&Q{{tR%E(nZNZ>6y)(B;0k|PxyHIT>>2DwxdF-BFj1?Ob zo_oV8S#>Ggu{nU~fXT`*d?)k0PZw(eV7D(j0tA8GFb2&zr+<(Eh!}ilppGY#6xh1p z=daaO2VpU`qrgfL;Q-_mM)vB>{1?2_Fu?&2GUI0gbfcOG$Hngco@vvX98$dnq3{F)|>W+RW)o2XI6wW_uC|AjQQG!L%~082o$ zzYrWPpGpw02*%!mh0T&?e@tf@t?nUSZ7FaY1^b2OIW8H3qzgZsRx^XniN8?8k}eS9 z>64LW7oBRwjYZFxL;Q&U8shSPG{=5tuE&4;C-!cycz4Rhl!s_R~mh^FIsQ`D*+|HYd`Cje;NST) z9bo|%tz&)XX3@F9|D%-HUsIF{5YwCN^5s2-LSF3P>knn2_tC+xA{MiS*su<`xVWU} zxZ9=~uKPrV4BG=b;(m2p@PNWNxUToFK!%t>c4h|VuRE~4`SB4LZ`_gozJ-2p0{FHvj&%mS=t`ud)yHbEVf(H1c@#9^fy+JHMj z5Pe-obgGtOGG#+mz`vLO{Rf{6_RLQtWMoE>E39{J{^pU=%Ky5(v!^L~X@V=Kl5jES zNq!o8|5@egp_oKuC;OI*62r}3LTb_!0b@77cqQ7ATk@59`)JG0*lyA?0QKXFJcaSz z=iTi2ul!56)FEfpSUIzIL*y#|o`0bema$f{ zDz}o?JsxVdj0F`QbsdKI)tboa*2c{pJ7vSLCD{$1YhG~hXFV37$#iiev?VhUh#Nqd zT?Q6;?9*IP2LY%v4jN%LCg~|>_r--6@%}FR(ic(R1n5k)Nq&HuZi$<1#|l_CI-)y+ zNqCo2%Za_!jUi5s3*00d&Fyl-07J(1lOKaLG=g5m2F(lgV!4?}qQtuB*WK#eK;z1O zA98Hz2gydF_R2&Bl%P@f!;%BFdN=OBoF=N0LgmxvBM}aqy_X0KuCRQtF6YGQz*lcZ zPI(vT59j}_Y!x9fUb=?rcD%}~S~^eGt7wZh0=e6StGpYl|O-#7wt{pH4}s@BxR$tSE@HXvvQzy z**ATS#A2p)PmdjiWFnL#tOdT&jc-Hb4v2dkDH^O0>0sELjPK;ZfUlo=VFT2mPorY4 z_gq~d*TIy97#zAzgEniQYc<$)I!S`PAJY9wNRt@h-&<$aRx|cSS z{6dSL3dO==*vhqnlp`81KacwRH=hrc4P4ocCAC$4$>tIl61Rq@@&(-=LsMi3cA$Wg zn1H~#Z4u`mbD*M-%m+hq0r!HWd*bgtS9kZ=YQwD)?!1dq9i9VEZ5ULmxmn@glUc-7 z=0ICCd1UdK^VV+z=ly;FEC5eVAL*Cl!kh+x-Bi73&&g$;E`K2pAOVYu%ShWo{xz-C zkjF+G6O@sK-=@Apdcw_X0hKiOMfhbtm>T7q06D=KvPionj7B1z1pb3lsYJ!&;aXMI zcmQXY(sMkrvp|#-?EHn)!P39TXJ}gSBeFHL=D%UKX0^_KaQ<#1t6U749OIskIk$P1 z??3Ph4OMr)J)}{dA)@#HwZx&WjgJ|D&z?bP+`d5V;w^)t-kOqWM=+{$zkl!&pD+yW z?Ug55i8~Ux;QQ&F9**DGyJg8y*bZuG^hCLr&<_I8wH<^53AhW)j&q=d%H@^-a?$^# zNJ^O)P-b8lwL*>g+G}R|Wyb8~?eW;hn)-jH3ga)x)gsmGj;OALCR4a1? zci?tVKn1o^T8}peF_)wuBhesof@#sWs(7obq`dhxSCc&{Z+j4-_1o`R8k%AMdxQ=s zy|e^c_;FXd<}hv3>^xQcbr4)>gqWJtPi7GVUb(OZQa+0MJ7SZ|(<#rv19lK^^fL>} z!3VW>Qy)#((%if?z1y5XGc!raCE7v}Ho*I2o?ySnPPi0y$xbex(+r)zTKV0YiU0_| z1R216IXCpP+2}xSm2zJLKU5;s@@otlB1X8#520g0vRs-9tJxj`H_2Xv? zU2A%-yoY9xT*Sg7F-?;%-#_euK{bN8IY)pu`bS5uW(K@VsH3HoZ=lRr;4 z%Om4SZh)xbIuPG)>@U*Fhw}0%hSdzVolJ<&coRUTLGW>CYUk{o&y__)*z8;}pl^J9 zZD$t@2vF|CVfH}cp%lk0^}h|7wJv-mowa^Mml^m$Gf0B%KNae*co6*>U$-d-U<(MW zzxuL#W$WG`dm=ZNmB5JP3*BYR|4eaq{wPXqHFDF_T2q*Juqp~-TQ8=VdC#*3mK$fm z?F8^EO|y>Y)0q=0yJr8mJ+?Am8?TRATPsnUG4@WCNu~e#s5L;dI1-sLN-dq-z`&B~ zV8&5mfoM4&cJ}@2TpG}$X|0)yAvN+sGIi7tvzMoz<9oQbU!ELv+TEs(6I*->{>;@POndI^M)C?a5Cwbbq-D=pKM?P{JK8hNqt5cxRbbi#{6zM*K=^$nKT z8%`tD-sLSdghmQiPQ@uW%CnTV@b^cpz}TT*exhaRRkp{tyEvh2s3@~5rZ~=NY{j$C z7A~^XYLy<%j@(4?{Q|Vy*7|r`#VQ_zca|axJP5k*1d@=ik^)%-=$I*ME zv(6rj|3Oi3wbG{NDrQ&o#}}7>xZLELte@>VO!ecCMYEkD8$em8-+F-@ zhQ2Imo8+a^suzy*0QM>LajIv1UUp{;poG^R4gg(8-iPtDX*jLSEab;+rX$|>DK`N2sn|{59&xazBuZEO${(;T zE~m2CQ$T9gSSwG4ZT+$~Onw9R*C2&j*g6JMs3a7Cx7;!Z$iZnMUNjhfm(i-0T@){4 z3n6{BV$+cu9{0_Bo@37dlv+g6Xf^^HY?(>DX~h z$CDmBzUpc_1Oxe_9QRYI`vR{-8@a0W%$RRa@hcJ>MKy(e+Ir%zrTfZgyd0{&Vi4O7 z#JZRg_O7GQ=9t!O_DDlmC=I`irtgvFB*!=-J?CsLa-SOr=kse~24NOgMj7&~q;QGs zlW3cVXjQpnQ2{OR`qRrq4frhb8swsQMlK~iUDv*|8N@(4wO;=tL`!-13hb#e?(k}_ zNQ0f5{1IF$LH2X47hm4qIt>bR4nT-^MA#nC89E}Xg1HydFZudf?6<`Y{EYX{EW57{ z*J&E!vA02P&K{3{6vowE(g}q8>OcbIgJ{a9lz2HE{KtCsEsM%qd#TBK-H3%jV{=m z9=mjtlTS z-CC#s+o6sh8H7DU_}J(+yO$5`OR4_ztyLkS<2jgyeT@Bx8`svi$!T`RXBvpsR=BV7 z9i)!okO^s5x`Wa^cfbGKHGHLy(Yq7!R(}e@82%EWS-ex1?7`qX<}UC5|NgBrwnm<1 z*jmDeQ6+x-^a)9e5i|7O{5gBplaE1s!@So-%N=;+dY*iFpS(@eZRZAwBafI=HkvOu z$~$4~BKeLjDJOLa2majTql@6u_aPR;nXGK+6EdFrbpe?8&me*rG6&cJ`mb1v5Jk*L z$*a<>x$-Wo*;DuPEW0bhgDs;Zc&3( zQYU(-rm=Jx|0I-Xr*nV)y#e~wHvj)96z>D=%ra~dTcKXKLjC3;v0{rG*T_tB*%Eve z+O<2e17=n^c--oHO0mrtGdh!gkP}uAtZl1^+s8G!nk{$3+1cwYJ;jS(HhWrOjZN9# z=kZ9q#J#Z44?Q=B`E48}`PeX>+c9X4=*&b}_j(B1>D+PAEOvFG_l1?>+>1e~-3;;r z=26&E+$30Phcgq4eOxr_q9Zvuoi~l$NuT%RlWhN&HP&N>V}AGH5F}LQ1l?om6>nI7P6B zr$XE#f}gL93$JMm%uxresm+gT;|0I25<}-CFqwO`loNZbaG=V|U~*z;np`br(wmG$ zFELV_IvD>UJ1_pD;GG%(G;sAUs}-F1%LBk8)}>3NK9#Wg`#>d#$~?qvYtxJ#sG*)&(0dkr%sr<1de1Nuu=Yh^Y9HJeNPS0 zu4g5Gisg4?mWuY7o2=zoSHM7!KsDgMw#|w@315XQcrVACggqGX-5ZA@IWE`q8rva| z2yi@IvlU7FPtjpOzYJ3p+`R3FuoDYPyBoZOj zGZA48Z3Z#F5%;CI@}=WJKL9G;oc_qS_;INi@>P?(z#hvcNGo)`n|o=d%semp5Dt(0 zloK95oRSCDe|?<~n8zl-%9M%?iLjz_ftyIV=CCyM^=ImzX5{2ha%el2WtaaArTauQ zND#K&_@h_?nShq)>jLLd=S8dSX0YT~eH#U>n=z!zy5mt$6SwiH4-ia$YfE_S)l*m{l*h^Jq^pE1gvtC@F-fJ zTO;CJ?~l6s+x+svf*-6VU1jy&<3m-uwQc4lcOx{RcQO3>9v-Ks6?GSHb4WqzR-@Jb z{d0+^sS_98N}>WwjsP-9i2ghyQ|JWx3ETd2r@^iK-^mAIL_f4BSB&Mtk^L zgTU|)+w4Zu{V?ZP`-xM$ApSlw2;E9Gx723Zx0{%(_CF$pjw~^2v6B%6X<`tBxru1RZ zHR2a40zZ-N7Fv%%oe*u^Qv_MApPHo}<(wyziled`eWaz!6!2|74#cLjTs2T+-}-ae zblwAlSnYhHJQE2Cp?vO90oPQ@TO~KnC`+0JK3?J-U9|7>{QjtAAHD>@FV@9$km%Y- zX1&;RFfPc$lzgOj@G`unr)`lilCA7)FJg}kV+C2%i5)5V1-ZczF|`(U-TCraRI;c9 z*bV178buuv?Aj_tzO8__XAvHtygAbeYgsTAG9-O!sEvi`oeZnJxhL%sU2yDHBD$*! z8bzu$lbxm{w1L0W00EfN>)i~&rJ){q2uO@#-KxnGKkaERH)d-$;_fkc)YMydCth&6 z;Si)$#?m6E%@*$Yxu(=m-snoA9RB`o`}#>l@?VJ0PtLtN4_5Vs&5Ov;mM;!`f1~Qi z##eoKF92%G9qM^$!CI-R6-nC@xS}OWzw5Z2LQPq~u>UPg>IO5nFzZ2Qe@T&3M}j*4 z{RfOi4*^qEg0OMJUdMcLRQsr)4t;V^{lq5)M>gS3FVSDu8N(q!74Qg|=Tc*Nx9!bh zAYNsIHa^={k?migjUVE?QQ1jRI?F`7Vh`1eq@jHi)#X4ozw$6^~ebSHuA$(i=DR0Ku{5WbW0%yN6e2DU)c|fQDjFb=>A)*I^fGvJeC8~#Z zqNkwvv~vRZj?nEzO(FJ!?p0Bo7gAKgfPZ9Kb%$Vbn$u_BLXJ(Z@QLZs5L#}X2jx#Z znqo#pDWx7-;65qro--+TNNt&6F-U*h`EO``!4$pj$eB{kEl0B7cmg4}@67wvKYwUjFgze}6um z|NsB;mbYKd0|Nfe!)H|sD;(0+iuXaY z?n;c64$2yD-7^_^7TgKbaL2?p&_KgF;OLe+v6dm8_fA5Y^%owoBezN}RVtS|ncP69 zJf!c;S(^Cw5;)?U2pvGqfK9npK(u5ENd~Y*3NFR!}d~ z|Hd$Ae-G^6la&2$^}j%E_KTLN4`I@(XiqWUC-{mmgi0ca6vOVZR7JS`Ld~5rriy`2 zxTT8=r&c=@KV2s(LDctDI@{YtcD<*Pi2ElGP}P3w)U5*yW5hr$yYTPh64S3ls0HC5 zzBM@``K#n-}oQfa&UGqo5) z$%R4$8cy>Fv=*?W`}j<)gAT>i6#T%$B4>ym4u(iz+s+;NM*6UADz9;%RvAC^nZUA<`*xTTG+2sshqMj~^=@WA{L&F!+`1_b5$s8{L;33+ zg;(}}l6)||#Uo&cmCQ4Ri!1Bu)opW7GHm^Mzmq7_vOxz@Gek%Y7Nf4V!wEEAVcgaR z_3KgwsstQi|I-mKR{XEz886GrU*oxDcLhXwChvj6%HDsAL@YKvof?hdrC{m<50Cdz zZxBi!`aDu{+rKX|)xNThym)m@TR}|aE-W_hdd+X$DLiTONim}?HtnQD=8!&d=8y-_ z%GaaS$tynuN1G)Lr|jNm#UxE6K8zD-y`Kc0$&bgPfAHTM3PtA6R0*wOp4uf(ac&6I zdtQ!ft8M(SSly*)Q`kjwId+9ub~%lc^N(WZ%AUMMg>%*u7R9| z?!e~`X~?16e?!yA*_-kET6=X9SXE4w?{-B){Y;NgD>Ceg^4V8>aBo7fwS*>MfYz}C zW1YX3jd;nWC&QzioFv-q6Hi4XP~6hL7Kb#ub}SJjjgP8^VBOf5wjqGBm%A zZ`r&^hNglS;CLpBd?+Jk%pGxN#Dg{g@ud?SEFe#k>(t{DyTbBNy%m?_Ol{<8;iqXj z1;EM$157?YO82w$kQ~zD4*mNoDxP8S5~-2)4%)E37=?kJPF*5d8fY?;M~UeQZ2Z206H$6g!X#e+Kh#n?Gv|C!#;(AA z;2w+~W1ZaP>6IN~_;FD88epmZ5_!5khr4~}-MC2FNX6#u>K2F`70mcE6E=;j#dE%gvdY3TbUQ4ntx%e#L)wptiTA$BH5Xgv3MgDalrp@W z{(#p+LV#acoVc3|+qW39*>pq7s)`ll%PSYU3Gt46TyvukYBG=tBV9&1eiakO8Rg6K zaY8?>2YsiLs*5Y z{*RR+0R6af`@pat))MP|_aX=%J)rLG?YlIyY1$7wgM$qJo5@xVQWD;SMK>$4BmN@YkK^kds(WuR$dIE$8f^vFx8x}ts94*Sm0u1IK5xJ8`f`@56 ze2LM4T;d66vipHK5^3m%!z)V^7gRuh(I_E5`Z&BbDAUpd@!YpdpWouT-nZfJM%X1V z6H0$b-|vRCRiCCL*CX;^iQeEn@r&!+kM9VDnWd(;lKqY!QjaZ<=b8Y4%!{A(iL~{QGnqUG^h6k#r#Kfrakg4-0KQV-_(f&#Uu=BGIK89_5;pPO7 zD3%&eG7nd#1%aiJAXa0sPtdzRKh>W|@RTx}K*#0dv^Zw`50NkW+)e~0px$`KRmA0b z;Cr=`4~oeA2~7jJl@92!v3PuK>lzc$M!^?u{)HAKV1yC z^NVSZez&yx*^yQRYfgkpQ5Xg%ro0#he4e%ptQ)R;8T56rI*4Fkx5X2~Bo_h*Vz%{~ zL3mQguB7ZbY?>cNy@nR|A%N)d`Q1O8w`+6pU!^=1#R9+nyoDf*>p?J{k{=KPv9=KJ^MV*5t! zUhGffe@xd6s$MTUz~Dh_=zhvu>0sCB8ZB@;6~j#B-o)}#QPZ!-W3mJ0R?1ZNFQ{7i@;V7C$(~E)Ws~^p`E@cH*SuFZzz$QN`sawB1 zhirKY4bx{BoAqa*S>M95=9|M6H$gI6AOHgRH<618{xBd^ap@3)hI9bFgKG^gJ&~Y0 zjXReL@(KyE6~w_OKWY#T$QSKQslx+-8CenYeFprVtZtGknGljiah&E04gR|v0F@xZ zaitv2kNkD%t+w(4Kd*03V@?<4{N>!V4^Hl%CTpgNgy=qPh`_}3`)^b_(PMiKf=g>z zo9v!P+hElo+FoA+R7aAQ4@%qf;CS>F=;6;g zNqycP&8K<){}OKf)@1?!5Eq^Clp&2@1dynV@P|6MJo8usJ*c!HPbEZDh_owc(Vsw( zOu7tH@}?hfi)LV{ei+hpnQXqj5~8q%v?t@PtxrC7nxG~RfMP;S zvE@2xFuuRp%*WHrW7IVF!@`yhWR9{l##m%_E}I5wqUO19LVS#H7o9YEcR;StbIQhS z^~|IeUek-BwOue)eEkVVeV;9<*d+xq<{gqWcKpjm%Gh5#b|_|c#gJW;Gu|WwPy#;o z(R3Ym*MKwTMm;Yw;9E}5mKnTiHK+d9jYucf#Gdi#7!t`Nf~C9fy#==EnrHJ*{&o=- zza_rwMj-E$#)ht!SX?`8Qa^d|_mDS225CpTTysHA6M_y2lCBIC~-O_cz zUn;D^>{PXIIz%nBE9Y*xi3SIIrJSk@SIBUM@35h0X!7Sab1uu4R{ zvb>%>6)%?Rk2NSE(5%jK3_WRYeDB5B9jNTm>J?t8`K!;AOc14xeC37 zM98)^sWwlCOmbds1WlOGDnSv?j#o&GG-4~hS1HdS>5WX}(+VsW_2W&41TRt+9y)Sw zY!}mR+Ks%a#fYn)RXOBP^9|C$csnE^DWSvHm9JUz+@m5cGW)mMvRRxX$c|@GczK91 z$xqcpT~xaL8ML=jq{`El#I0MCJPCe_H)%{T5&Vd$4NnygmOHjO`5IEWIs9(-=85@Q)-LC+({{F5ci*uH?8#d#6af;_9A zx3BYjD6%%SqztIW<1}rd#(xJ_Hq<(VAxnp1>S)Q9gh~?!ts|>C2d~7qAMHS9Qwjgqx&cfFS>dBe}DY0d-BjmlW z^e5kG|Dg!K^!c|;;QoYDnp%)tsA(~y{MtOOis;{iJs`t9cMDw=2EkgOUAyBo^e@^6 zW}-`LS&&=oG$&sBzby|{nMU^9^FBcFsvMUOi0}y>#j&}%A6y0MautKPP)es~lWNkB zb|4IqkI|FlkbBeaqA-H>O5X0R{_Sz)xcZxP0z<298qzG8_r~2Zfyd-l`oVdLp4)#f z>f*%UD4xrPR;F$oKoFVFsWT=S+$}x`3BT>9z-8Juuc%)56miPL+NvpG~NUT zLifVm%HfwrLA%sNs@QwEMTw47lkyUq{^`JZXwt8`BVjB$M%6g=u$`uekn8z*6Fk_Sb-Gb z6*uS}w2^-4`3fhiLBMie#2_3ST)@m9sW&u`O8Bal&9`J`rHs7)_mF*_GX0~&=?(?OyaahqtQP_Do8RBdiKtgqIZ+S9?H9divoWHWZEq(xs6Z;-(e+0%H6+7JnTRpH3 zEpg&pmy}ZU_t^&b@vGN~HpkZ?ehyGI1#P4vXsKK`o`^aU7`8#e5To+AY!GSZ;u*h zNC&2Trd{@rs(M`Soj|*zg-MAY{*D)>n#bGluwika2z2tz|n_5p8#fQjJH&14i>nW5c;Y!;v1gtVdLwVsyQq?S?dpUpxug~h>UH6 zt{O%wp>pyRt4n%Nv?LM z7pib{9SlGS%!l_as$^|mG<@ahy=%K$dfhG7@atVG<@_;~${n@is@v7^a+;UGs+r_6 zB}9vtd_0X8&jIj^d95&1g5$}RWe!Sw4rWugpMhf$D?A6^@n2MBy$W`#pw9ISZU_;U zSF3lI>183I*?9=K!qLau`!jLFO1SN#K z5i3f!{a`?qyD8t#`!2@CpqRhVc>!1tnD`=Th05drUY@FNR;ogSIe*mXjTFkf7VOkfP1O54}6%R|Fl#Qy7n78fE+zKWK;e;8%*gw-GX z5ZqHf68j~B8!aB;5nC2g!}syN)*cCl5fD;Cxz)wJD81?tr67+$ql+N3MCQIcKWb7} zu#u`ownilzq0Ik1HzW>?paxAckjeAxTofoRzY+TXolFJZO2O_8JWHp_X&1J5BOvzKyFV17u(A8rc)OMjmn8HuxM@u)VX zOP_J?Z&sX+8#)J~8BIcmZ#EVMKlj%?w+$$s!n^oc&g<~DUSTPlyeD#L>;s2mpik&( zwl?23a9oKkYoZU0Q2p?>nHcNxufGTG^VK_3v^_4gk9<>+bRVksuhVvp?U^y382o^+ z#`&%-COhA2hzXFB(@6=V(KY%3b^MvCCgEOMy3-?gCV}Y>8TE}XzrMw%_v8x9otabG zLW{@aud_a%>cC%G4M`@AJa>}qAKN8I=TR1HP9de-7YeWXn(CCOyd|P`=Iv*AjJ1#0 zHt(}DC0|5zUWLYSWTZ-4$B*00!V}rVP^Ua9p$rE=&#rcHpDodjQo{Y{9k|@eBNrsQ zI%EOs#1%d`8LfP+4pBZmTAC$HkrmWv&fL>aqZPH~w$m;?;fl)oD8=P+JU9jbe&^AT z5K{tMB=SR6l!lxQKAlXh7fr+tSh$Dua;WSvye-7sbmfD$-83+&1TgJPmcc#k%GIs- zf|#B6oOMR)Pp1ae+IN>nCjjqrsbUL!k)aPJXV+sYFd!i~%K7j#^H4$O1DrlO?k(2| zN+Yhkyy{<@Ancl0t-ErwTJP^(au!V{qzaWC|I66&ux_@lw;jBv;WxB7AZJ@~v`V`7 zF+2tSKr{$6DOe-!OncFh5#8>L-#QB1HNR2s;v??>KvHc~iVmL@(y-KKMgv5+s@l$+ zw&pW4Y^ro5un<@c8%~G59P_G*doa$Hx`z!TUqV+sU5lPu3UD0Ymr{!UN~?>F^}K`) zFgv|{4vN8h;ic0ViW-j*cVrZ-r^-b2o*#yJUYBiBhvwoNXye`3y1N?wtftkwg#VYF zHT5FJYOmWRof8EQOQhfe!w)8`hRqdDQStp7Dcr73OP(cnk$4p!$}k_GM_>VK>0$8b z#^jvds5A8y%F$Y)O(qFKQ^|K#9959XzPBIX_zbNIZGlKVgZGQ*(~Bt1J>v57J{d;m z4N|k|7X6;s{b6{7098j0+b*y8@cV@=fJIJnRt>*E!pp{D5XoPr+YW}t)u_Dzcd-qD zm7s%`r+~CYg@IkjK3tK$$X|pTZtMFhewlor>&-;p!IE>NHn{~7`J_R5zV9+nhx7Zv zqGsuyY=mv@WFdPHd)3->C3v`irGtRuGwFalba49)r5g^QcdW@*xtOG1RpCKjS z+5fWoK@4D}HpVMNQ;=@+=N~yh1S;|M+Sh2|Tz}-2l}D5T+PEmT_`E|1xp2ED#wP|{ zP&}x;|GIXTz~TkFfZVFzf!a8*3m^(PcyTzJ3pmtosYrffCQ>w5jwxYaG z&pzR?)@!?#kfE=Eq@fdn8f8DIUsJ`GX7R@NTN=Qf>Si2^%KL={$|SzJ@Im}!m==2$~5;qVzGPekd>|XM8?KHWKiY^Q#T|=oAHc)BK3StAA5fT zH3$Fz_6^kl7RG%B;15w4YYsWiLdk!Tb|6sZb5Fc&cH(ItQVXC2N|-Sdlx8(l3@wm_ znE2SVzsgnm_5!2JNibemdGmVM=hGs^fj?MOjg`;)I=*9p&yjr6WwgN*(+uW015n!m z|JAmIKm@0{&b;JDOj`q=MTv-{l~T<+^U=#$j?Rj*^n}3xkjF|tJPhF(NuYPcT8>?jEyw?qRmJQ{eb_VYpV|5V7~x9 zY%(*mONP!3I+(#mn(w<>*Vrg*F>|1v*_)CJw9D24#NaDHS6`E_Sp@B*HLIeahAXo+ zbhC>bQbm8{J{uYel@HucVT5pAm9f0+qo0jrpy{ZVsN|!dETC149^KNvq1~7o%D$Mr zQky$(y`n^M5qae7tMX8gef-po?IJ*0l2o9;b(@irQAUObb`_Dw!n#a?C0=_t6n=*H zVl$r3ZZzy3*5Vl_fZU-h(eW0F;SK@9evhY{FE`OA%k}EvfUtynL~B8DB-n|9{DFSG zj#X5k-2FQgk^z<4k|rf)!}HfVi2XKNN|kH!)GS7W=7#7nR&|FWnbZpLbjk5=Q&ujLEnn3R)VwGTvVYXdNQWO})% z1!zlSbf9sT2-$N*clBAsxXYi3iv@wtot8_yFsl}Lu(=hMvwC{opD_9Dq)&3=O8OUh zw(!GyCsVMj*rcS?F<$@vqaXjmzTfuFqhIu6u9dhJ^pf0Ja{`<-Bo$#Gif!Bb_i~+T zyP52&H0}&4L%QUBxeOD3!A(xP*w2c-HlP04>Z)X>2m5^T+H>nUYu)3bk`+}mw`L3b zlHXtmpw(VhPrNOu=_%;x^cMz^}^!P%BzmBVO}_S$*5am^V|(H+R^%b zKMfnIl9ZE26W)HpRJA7j#JZ_-C(jlT;z$AM-9>4{nmo47c{30vlIVX2h(h?l5;0R; zw01e3#;cVIn0pj;;C9x*vlKzy1?XX39p{7|*|)lQuYgbQGObz0!MxaIsxM@l-kwWI z0JXVjBkB&0JP!LFtLG0K3?{Yf zd3-NPrM>=?{1` zf*l)5F9(b0pk6Ktt_Rtd|M&bX=Tx;HNdk4+x`eCT$lgpZImzL!!_W_N9<>1&RX{o zhyjN{JW}iRh!I`Hd{@<4W-zme5?EoyKGnBR-OuIAQA{j$#R|Fw*kY|fqFS1R(cSEm z2}vP<(zoK!8NnUFVUt9|#W>|;Q*J;s0v}6e)5sM9ih!E~Xw|5#;t;uHj=CIWS?o4n z$+!5Ci*dHk&;sO2=%VPAEpEsE(MznEoVo_^s_F(ysmDU?G|IFHL$^Ua?Xvz1bC)qA ze^`)z;PWu|+XYoQoafVoXQd^aV2u^U(D$h~zMVByk%-mTYCv#Jq_i9;_~re3$ncxG zuDLqicBTh4p2o*b^M`NZU`znh4&YoheORTDOjOOynz?=zR7p?2sr+Hftb8ZvhN6&Z zkl*3!|M~~O6Ris=?BOM8a%J`|fh5wt%(_68w1XCS^|-MG*0gX? z#f3)tw#}Gkx`C~Zhx}0KS=i3~DgYVh`XXFNs7h^%UD(@zPUv}_YJIdna|@nq$>+!P zQ2Yd@{GZv{a0El$C&8yZv}@q~2Yq>p2AJMvE0lV#bEVR~JlsFBYQ?0Ath_*-HO4K# zJd&y{RN|p2Y-3q-^;&=EV7=Zl*zpd}iF~IZVZE3PwF!;<-#@-gHPS$IVk5-Bvi%}k zMlIwX2(aSb1D6%m(jS7z)zu>6>?FO%_A>a9kI)mzg5jHKkd-fO%NZTmn8WNaijTHb ztURGb2Sh@5*3K}`NvEs%KH~@zNVG@&PJfYTY<8to2~G-JmyKATc(VQf0dQHZnxYwi zlw9qlTR^-~icT3kt45bC(xT(2Mw+f?0iMwy5thjDM79lUx}mG4SBB=Sb(ZVq-B)O) zUx`;eA2VQ0p6y2?i&-zRZ$ok0y5V<@^kU?tlDSH!!&p1r}a491r@x}3>6Ln0L?QX*LKT2 zgZ%38)lS5PQ}tLm{c3R=<3v;VXGbLbgmYLiYy4}FxMtF#Wy4nTdD;ARJ-O;Zu=C-} z0y|CSR~ao>ooTh!rc`m*u|rK(p4DiagPgrqb7NccY{tceQC@+FW^*jq9B z`MnGdfv*$TTKy>MTW%X-RS+>gdGX0j$r4<<;^dTB?CRCwFP`Gd!%y(ew`W$`2Z0c+LZ@E-p|PX=kP*SKNv7J z?-6OrgK&R*=d#d=$3JMVhbKo7$b12f$W*DS*5CXBPvo3qJu{!xSJ+Le*3f0lQTYvQ*pQW_n91Vz{h@HgqhO^ zL`-#}2{R7`B{S$2T|U^uk_fhxBfR&?RU4}3tt5HfdvDjAdQ~S;nGI~+{wtl0i^*+d zdM&NZal$hLR@g8LUK`2IdSlZrs<@atBFom5{9SPPpbnG2-PYJ)#fM0$ChJWUnHnr% zJTzRBb)DhPs&{~ec46j8)SZqMrYD|GDI(NcFMkRFLJd0*b~K$!b5&1sjFL_la{vGD zh8iAi5{mKac8vR^y4~7i?8ch)x@7Z~+|4qHst=7O>EwN@{n?dKg&ZqX45Hzt=6^KU z&Wz@n7Ju^d&;S2u;wshv6+nQp5)zAimaEa)#=aHz$fg#Z7wds7lhDEHe5-8>PReGg2vfKdL7S+$kICgRbFUp$eZxdTAnsr6}&-T$4Ln2;FIrYWF zlfDKz^a89zl%+&ns-O_|Ev|7oE%Ck`@vAdC_u9j1Y9rQ(t*d%}hC_1v@Er+Aj;hl9 z8&7nSNFTy%!;jh^S!BJZQ^v4AVA&YaN5}#A9}`9BFMT9xu~VXh{y3A7oUD9G!v3-a zzwiAAx3h>#RFoJs-fR(8u-+atG|}#DqU`!SokU`Xll`;Zt+jO_WQEdn(nyq1X2T+Ub&| zSMO0_H|ZAfcCHrA97c^UEn964LH+Ae+#)tKLdt{RT;x89<+420wO!1d7Gp=UB^Zj7 z=K;gnZ(f4c7sblaePu7u4xV>G={h7li7FF#y!HWn+WLe(>A_De73W0BnwvvmDKLuD zvy`LAzdvS+>-(2yBVu~Xiz~EY)QSY$2!7?$f@6^D*O-NrZ{#OSp^%KmCY%!waT%87 zqm;U~5_!;+;lg30_#Ag%k=$eEK|&%kIvwRAN7lqnLi|&b78h@J{~VDRFZ-nTQ%=Xk zSC(R!bsugj1xClOp~uYQV|w_C#_tI{ipf=@|4fpy?QaScy}ncQL->Sp5H1Cz3JMKR z9zcs*L0-hQbuu{_aZI@(WE98B9#Zp*FCrOC!}RwiXJtie_n+H)8JNbl!3HrCQg-Sz zg46?+;I;eCAI0~ASC+Apunh!Z#|C^DXD?po+>-RG`Vkt~pQt)N5r?M1_2ZjC#XLs* z;0~_-Igq8DNq0$c(2i@J{&LSN+uR!Tid&0GphDWA$V(`Gj*;)T^Prf{Efi*f*1ik0 z>VS@F2EYFgWno^p;=G~!P(fDfM+wFY=r%@>*bIPD(jzL-Tolf_=a>w34=jY-=U&$6 z&x!FAHlJ#?EdQx9RvxN=XCo4lSHjulO4GF=54rB{EJl(}O0nzh3@#1U8$F2!P@dT; z+bF-X5gU$nl^aaR*MW{P?--oUK(sY8mOEqSY;|QMr5Z^jc6S;+j#{+|A<6aAaQqw! zXv4hqnQ5NQ#^I5N_kO)Oc<1jJ54py~OmKU-4ORWYUy*7XF>~(D`nPwn7*G1u0&4&A z)2G&&AQ&D!H!J-Tfq=2MAEv?qqrpZbQ~0%p%>r|DmLrQ882op(JP@t9J~KqQoH<{s*!kx<%AVDg zl0LxWlW8gE3{_C?qzqj>0=2>Eu3>T(R_ACWXW_jp(D-Bzm1PP*rild11eMo+75;L` z`csCmF&g3Fft9VS{k_oLJF?4&*M9wua*i;lXw?=!3etT;V=Ph{DH( zyKPHO!ok+O_>ULe8X;xy3P&mASVrgY|23Cjp)u$?$ zq{VJzV#pS}%yHnjbo~V8J+^k?kqSz;eP=)?zyCR^ajg4pLiBp~8?EdD2mSkAqo~)T zTfXs6YW)2j*gL~}#96Nct$(OaZ+S*0#AyO1ElityepF3<6*XrectSnoFyt-Up_ea7 z+oOuRn1A@0pm1#8D`(6(f79H(rV*%o574O+jGy~0pP#dtq`F*O@`TbjerxkEG#am@ z>1;nf>$N-adX$h(x0+(3EMLj^WU)rXcIy6bz`*6%L4?;{4uMf5j;Oz~(!N>jdi zU{=E15ncb*_Ga8SIz>7+ED8h%Jr4jV?+4@Aqv_Cq7hm{lh^p~wQLfK}X&H1uSpyn! z6B>Z;b89>v!uI6isSLH0lUk4GV03Z`-7Zqx=$H9JjQ51IZ_UOXd&W@c%_x$K*i3!# ziylyrD$qJR=B}HG!oUCJgf_xR@~EnQ&Eb#hAM+^#Odw!5Fb`!n7uOe{Dh6UfcKdtQ z^gC8jRt)lZMjsFuio?%s(~clXZFgcEc;Xh(nU)3`4Sw zKF*{Ae}1Vu_wG5lYut!U6T)QJ_;MvtwGaJOMX^kpSk-}w>f_bS!xfgSj6?Q!#9`4I z>Ch|5Cp&CZ_t-Aadn}fRf5skrL?r5&Of>zb8}TpEua}Ls_=H59W}~BD7Y;!9z0GLUczU#ykTH&jh!?OLZ@d zhsnrA8>2O}PzMpUc_gTRf<%tB)KUDvNY6IKE~sqrKC$JH^^<}uBoTf+N;dO|F7HZ0 zRyXpH36W&s+iE{pXg=40Lq*l&nYmp3wauQ{OY(Q9(|tZlB17iI<{ElTLSN|_aesc- znk|B;1^t;H2^DCsR)z9e(o7T$n1AN@X~&Ut-NxW*yZyD&o8F*PLY^+)(4Ftw%_beB zH2q}MroHp0nKWK6n*X__ba)Ce%KI~_ImC`A@m57>%BuVydP=Ap#hEE;_j1N!(yyXT zNV(*qf5NUq1O7<9GAJ|xPg*~(1>7};X0STBP*qJ_Tq-n#1hLkozw9Xeu2%yQ#_K_f z)i3BhsTm97$d+rU2)FO6PfdP>bk)(+#Ta?jDYwk&c9=~-sxIC2&B?@zivF7*(M($8 zHhWki^L+m{V#G z6k2*1jLEjK$VEY!Hd);aCnbrJMm?f@>5lQN7p6sYvY&;d!S*?KJ5SL+1p}lc3Ld#8 zt4=V|fj>h-!ApdEGoFawb?R(JZAyoMX&Hc?CQh#fDc(+!>O()8q ziBerR^gT*Jh+E=+=c@Y)jf5Y1F59H_rc$qceo>18WAIS zpG7L}*M;xq4f#;hml$$zUKPpoevhkOxM(Wy1kuJsNNQSypZFaww+C}6(AW$Sib{Uq z4lJf}sV4~Y-}xI42E9z#2#ex~X`%luJRA7R_eh$z{EB~W($7HojfhnHG+*;Tvq6F3 zJDAUGCE|Lbp9wK&`>x{{A67-dvI%HDZ!>!)7XiJ91iBL-Fh_1bBVJojrFD;$c>qa) z)hpPauEn#SX~G7$rVTM;R<}nNWwl-$C@zOCA88Y)wfVK*E8{I`KPuctBGc$BNy_?= zXuBJ=Qh?;sE(vF=jpQhj6Iw9psW`NhJ)X|);9*M>EfXzFxw~=uIoeU!|xTEa~M6`Gp z1P=}!VEW7OEh$H;CsrIJSH|Tt4`jpE+n$lsZmlCrn?fzVqd7y-U8o$LFCxkD`velz z0X0KzWehVWZRX~n9G_lu0bTpHnhRQVoXAwv@g%qz$m%h|J={p;T%U z5`b1ul$>y0e_dl9JH$5xl<;lXj~##%cjn{8;B)gmELRkTpPytemJ|T}LV9EhJ`lH&p)j-> z+cznY0!PpgZFsrmp}&e+qbH@F1fJ5?1G1YPoCdq!{I{|-hCRGvR8KkSDUkKC3f&gr zhEK)mo|;3|n@lBSnRN~g(8LzLaw}WkQ*}9;$uw1OhL;9;z0ub0hM|Mh9_|b&cCRy? z#OE3$WP0{`A-fu#gD~FMx^VQox+56?sCwoVCd)B>htI!Fot|9c&ks9no%Ux?w;LCZ zcNI|Dy4>f5X0U)`+`~cGb~a1pg>rc$XVCw@#m_VH;yV|wxm@k#&yN{MS5{cMgX?>w zDCHJCWa<89r0TZ2UZ*TV66xJn%m$OvDV_rc1CGyALX(3IRDi+4u;`n>*SL`v7d|oj z-HSjn6{#4Ru{4IW=4SG3Zg!7sWw_r)2`vt0d6c+A!GgZ(OSiRy_O8j+ikqvJD=t~3 zcmebEhb7BUd6){Ia>gYa=KHCa4-_7_kuro((vkp`L)g&NhGR>z3Bz+Y(DY}GDdWL# zd9?$Sa(?394r+WQKt#y2q5cq>->03TKuc}t2>u?E$Sc~2Y+nFo%LtA`l?%1Fu#yBz z?VrJrd6~AdtsQzJx6i@sdhGnf9}D#NN$egSLM**_-!0$xE?X|^1d z4fWLh8n>H(;M^gV3J(TK1VhC@>b5&Hx990PQlp%j4G1eW%jYOsap|~#ss&GEX;qec zrflf%++`e=V>u!3~>T>PJ9BVl< zb6-Kr`EIPG+PD|>3H9uxjsJ>7ck3=~=QAXFhmGg(Qnrw7M&-(=o_9S^oma9L01P1& z>_ugd$_NBL1Ih-KRdb?q$K_!>w~C#crWJE&sD~ruJOaP}vdkMSN z)Z{i6Ug9=&A#LkCk4=P z^arZq+DXE!fQ?^qcNXR5wduUu_N@ASHjHF@Y(h8Fc^vfIMOR37KHD=q!peigdhzMm z>3fKRJGk6r`dy8(Ni%P%u0Jx;^E<+&VVv8!&-C~yvlDpm`WTYUePGPosG!8J;*n*m zoI7zvQvjBw(sXPs!(%cL@@n!2fMB4_(zXphwG+fuHU|BfNtmtCjkMDR)s0`f*UkZA zB~;I2bW8^Vy3Z+>)rcR|DmMUsw}DYc^?lkz-G2TXHmj)Xlv$WJyI>7#SF z=FYJb7>Powc4_>x6}BK7Q0vQy6l3fK9q4OFk;O%{8)bNKKVXI|O`M0C?2d((9|*vT ze$+P-K{X>#su7*QIs!12yjBPUYRh(PAqTK7=Q?!kM&q^0b|H-(F~4Y2zdo<{fGPl$|y+ zqs~$fPk?IQ_nEu{7tp*&E(D?f(mP4oz~NxM66jF+ZqO2ev;FLJUM^|30VhPuH4U5C z-rY_M3jEKdqNW0HR@WO*&2z47{-OSp8Hn)>^R>zOf1%g*>PfMzL;1!R=T`8qtk6D)cNPzwU_!)jkqp}x z*&5(2+gR*dJMP4-|FiX}5o3zu92*Vi2g*Lip4%*qIfNdcWTdanPG0*n>81-mvYT&c zZ%4~N_F|lSzW*UTK5UoBA$PKmrI_n$r#)>@`u8%}@)vCuhiOnFu7cSQF5$ye>NoDvUvb1r%~-qZ6Fq6p0j@ zZQjpb0*$AhM3v2XQjHp;Jkf+x#H-C{1+%S8+|}ajaCEJPEJd+s=d-K!2Nn+3$g`Q# zit}q^jgsS#VmD1sRn;htqglRwaJx362OT#wlO7VsA5A(^tnWnDpcDy2p2haoy${A1 zCn{=Y8zGxGUM`}su|WWEU9?W5C%&@p+k|Dv16H53a8H)KqVhDJFIeutjAu{uC&vpD z`E(|qd8(vAp4QSQcm8?Jie_!E!Hl^!wTZ2{=RuQwOf7@LDg4$LrP^+t2-!8V#6^p~ z+yXub@|zyO($!Wf>PON(dxmlZD|$`&S&j9cN_`Rks`$pR@SxO^VEwZK>Tt-qez0OC z&HGqCu2a59PsZ6O3@%V6v^Sh%AOQ(|GJ41v(}yX7!(@u+-ZgUl-DZA6L=uOnA+52H zcSHR6FItD~wb`K&ZYm|GT*IN*cX{_jmbn1IYMjS$9MweBw~g)}w}Id%|7=Uf*2>3l zE+49a_vp-;%*gsgk=Q_zk!aa;TaFWACFnbAZ7FOCKLYI&iYBKLX5P7Fr9EvyU{GXc z{w#u`GDjSX@iU`!9p;#>BDWXPs@8A+{Ng58(mPGgHe@L3V|W z!@D(kBQ6TBRO~iJhyeNngaXm~AF+~%fRb4}J<}7bt2oxiwmS%{*v0EZ$JlgGwsx3; z&GH_t(r5SsRV*$JhX*>Fqc%plAM76IgoP{*hKR>K71K_OzObb*05oI8WLkuyK(dFg zkW=pj?m5_}4+sKi2@+Z&W3;5@5RKK)90S2Xpmf=*2wFCcb`q6_Mq|?dAn^FDA^O}Y z0}pZ$ZI=La<6}=Dw$``ba=Cti zS-cOj+)e}s&5v70IS2*4+0+R8SdA$Fs?nB%kc6DdKf~2(Zys3FiW&KH2Y5Fv=k$X$ zyXKSb9g>>otSL}J``t(cjre;o@${)j>dG$Bi1}QH@6E{XuRiCb;5d2O!zMb|W~=%- zMF0QdnaD0Mgqv5S5=$Ov$k90VBPKI3|Dy2#awJBbm5S@SZ0FU~@tkT@=RL1SKk~T! zQ0660@ZFOQaG9e{DKV)BK;%#f2Fh_Bj4`h0^LAXh<2OpRU;4;he2asjT1Igc9uO7r z+U)&vJ=_+B!%BL~paRi)U5MCO?LN~QO*P;@j z%{}o8q=l%icSBeUkYgYHd2C2Qz7F{hjy-_#W|A8H!Z`Nc$H9a|VPPfb3|p4W2fh{E z7vSGSNwp%dUh6!CMa>*vf%0DC<*Sj>hALzbX}P&lb4>~YkEy{`h;^Gh$xHw)pt#`G zGN2?b4Ia%bmNN(+3(8&ZvqSqmm3Y*BVSu||aNIP5XuVt{dgeExeQ{)N^!hf+V>H~j z@0()&mGTn6IFi2c;U?%M?cZJW`hV5`@|tbnh+L5`jpzXVJZJ^$$bvIU z#xsXrfB4NluEjNNM;Lf}qDyBwNJ$7`{Rq@(j9qfENf*`Cm)d?KAK=8;&1U%XWIXd% zhI&Lekm69pNn^CNCYSevt~%1FV^RFsz+lu)oe|DYTS`vr>@GBZd+_|zybPUz%sHXj zIlrV&0J#6I6r9jP>{JpiO>%aDdc8M@bQh+cxS0DJR1vyiTr5a?i!yz97jIseShYg7 zCiB9T+l&}kRc%zB17&O=M70{E(%TuKC{G#9zjM~CJn(NfYTxm-}LSg@G-X)3w2}g3@Vr*0dSH%VAAl)d)1ylY37@g!) zQs4EcGg9z^M%n5D8*5nnh?^9_<6(gP%icBs>?JH5&rJzO(Ue_+3d!N>N03^6AcZpE z0s48*{t#xf4yA&X#2)LxB+a<`p7T5775N_?R_XQX{ zCM-{NLf6yY&?)DU4eUgGA$$Gvk@g63F@59VSULrgn3Eo5YZoIfq`@(RCC=~clXW6w z$L6ds6$gwmsB*8PBRkjSG=7FmaYTO7#r1kOnZzV4@Ds$!ZiD?v+y7?&_Qj$Pt3n{Q zdH>g%ewU(QFFRb|(e^#hG1q)erKr}jD&=EZZUI6*O4GCPha#0oI2hYC)3!Wb=f!39 z@Q{KW=Hl%)WR!VLnUQH^pJ1M2l!Lc`Hku zZV_^1#$j1UJFs=NUy{T=B#;p&qP|Y4f29zzUSu&wS2?ZZ)AoB9Y#cI6ttlMw{%a#; z?}*ra2eGX0ZkKb1Uh6X3d1%cAn(dqb zPrc!;QhtJ$;#uD$SS@sB`w)qhz%1HD>ei8AXL03wSF{*sQ+&e)y6-Nym_ zq%JPyidUV6fz4W`FPhb0+A=>j&z(YNeIfx?(o~om8w_Ps6uu|22hm$5Sq|~JN=>X2g!3biUoE& zcYnhp?A6f{r#g!lcD9d>8GovUiLgI!Xg(XWxNbL4LW%?j7E? zM&JNqJFjJ`{{J!Wn`ghwm zqQ>YEt#C&ji|-3N>*uAJ2*n1iIp#Ly`SinE7b?{ph6j>U7?2ggAkW)XV7DW1!<(|q z=F$FJgc#Vet4Iph_CA^=vcg-1COPsR7;I&Q#P1aEL%jl!II^|0Ot42rF>umVs?Eaa zNjj34+&;4yyT(%?*n&yKms*K_S&IV#8+glxY9eyodOO)`Uc@Zz!PX{%VCa6RkacZ2 zrV@}=FwKv^yxRJ)GHT1FZ(gb`OgN{wBa3kpF0yoyay8;+I-#e@!I@Umi~E|n9>ew9 zL0!W>8wiLmL&roqh=+Kvn-`oEIPJ5u8~Tm@ishYIe7apqExRk1=w*bzQ~M9moIw^SA%wo7q8TyY!;>5N5m`SUu zCit)0R2-SG%ZwLpwrJmru~6Zwrc5C{o$k-tYgH+=iP6)PrXK{+V&Dej>9p6FX+))F zg1OC|SaK%{;l7CJ*ok4Pt%&qS4*`j!m zqQ|;iIo(oMkiM2ope5=Q32SlB#F}fh!l8!2!u%{pTFFc%&y*z!5gXCCI>z0?oIAk8 zF0rp2Q!JqF^U`OY7rq}s_-p4C8Ft0G>NsZB#mA2?#1<;NL>Q|n?b{u?v`(xp9vDS1 z1PXu)4m>;{x5BI9;PJPQnPtTjK}sNM%{w5c97K{lBoQ?=-^>+TDECC+$)U?M54Q&< z+XV`>+E{G1e(NRQ4XefTSMNE%KxZC5%MWn*X3|C==f=e*wafB3&k&}0dsy>%RQ8`l zIB9i6+y~P!>+Dm8LHh7X!QZ=Awf)cK!x5BPvd9TwMclIbpb8D|G$4l@f|3KpR4io+ zRbD{gtQ>W$Lc?19g=m}kKel!dD5$SH&-yx%%EpFcw_J+0_j@qR?7NyzBF8$l&vh89 zP>I4=eTJ(MxU_al8lPB}+fW?ia4LyRI|S|D$nr2fJ*|kXM6<_4U_LgD)e(%BqX-(o z2nBvi(zTN!IBQN>3OJoAy&r5IeY_8_;%8PG{#r?MlZUGRI%XaH)+?OK)HDLpgEaUZ z!s+|h$YCrP7^gR>+j%KP!ynrXmAKj~&`8J$1EX z{irTo#U?!bIJ0Xpq$2?pgeE&WZ{Brq@%H6mtnT=;y4j+TX24sqc>b17Na|_V+zCZv zf_V)iR$~)lB$CKBN}?+|PFDcMSgEQH$Tbee7zx>cfAVWtiXT-v8Fvrq<0ZaQP!Px= zh1A1iNT%+?W!OUi*nXT$Yjvg>ELScYSG=!}p+~q0j0-2fzV_%3WPQAuShW0H>9aZ_*@)~emoj665nUY_qp zixtxwcI*(fP||Xrp~+@1afYNQW>^2^y8Q}^Gm9{c4WLVYaA)CI_M}z*T%&xMX6QJh zTj=Q-Q3RZg|A;leoR2q_{5owO)`u9T*md_OGg3aV_FqS`gY%WN1w(WoE-(VuRGRDI z*Gyk_?5pyj?DG3`gqD}a`|I0-PnKqAV6Z*1x+MDxsfz(qGh9OU^JiEVmYQ|w%?h0gtt}Ga-*`7z0 zB*oCo+UwBrMQ&GMGePvt2DOi$*g~Y-)F#NYC%QNf12@WbVMOg(AGJ;LBSlg(Yq1K# z7f7N{%v&jM0hgCu@9)+b`e_E;GfVe%^IKKtz)|KPQYZ55gj zEz&ogFuRh0v>|Yi*^~B(u5Mfy3%-zKg9>(gjB8~r_acx@5hAr@-GG#x8t1~ZLp6Lw z;q=f(%2mbM3MmO7MJnT0!QJy};bkd#+*4+Tn`KI37LxO0c5t)WMgSdOV*^gkqy?w?B;ML4NKur-mpU-KmYgjE)jA;TkgblSh4xX zA{}9EgOGX6`*%jJ2GngN6$_&-$m+I(x6ipZ=~bb2;rLUpn}3IsS^!)owldQU%oX8> zaskeP7FUv>%}?t&ax<+28QRpC-B^0U-^tPlRK;O5Y(q9l1YSmH^b)bI2mzS<NLAN{=U6Uuq&%dWBQ?O!vyBItSX;tmW(fpFTqYIj6x@g7b#C% zX72JZkR#RPul6qw?rAgYhRnhfi1I*HK?oPo2Kiq1-sv3=3$0jM)(9X_388mVxu=Cp z$&9OMW3CqmuSaOfC(kst5uxA>C4WXJ&Zr0BF3T}j;ssoV?uOfC><+Sqk z4nojf1b6L7a*NZpwu@v1vRT_B|Ns0%&rzeWPq>qioh(do9FhpmD9EDsYC1QnH|E1} zciIn$JeQTB{_#YLO%M6pv643xDZ-jFOPU*)k4tbvq6|Aqq3XEw&@VTY&P1Xr@Y=p< zc=NXIlu(Me|DhaI<$i7qd+rO5x)kcrl*kq@Ua}>y%{m;O;*FPe%|)mP!y_gyCy@CXZYg z*A1{V^5$bODoSBTmTFQHbzm;wASm3K6l$WH1<(nQ3t|BIv_(#*Ef2>VE!Zw&RA838 zJ@&fAr2+QnbJ^^Au09Sh_vfS%OBi2o2FQ8xziuJhLQn;2g3_y5Kw$+W0I0ZBB{E$C z9KR>pw?yDBRFPznu<0id;ag@aoY+^;?=!}D5>Kmh7FUxD-gb>il>h$(h_ov{rT^^8 zoY!|?xT}mV^V8BC4WiJ@!+5lvkk_$;hED7hBXGikRN7edvT?u?eP6(tEuRG!L)2fk z&CY%<^dmLZ(>ngRH_onh$)qd^#~KJz%_X_}UOSXc1gTod(1!!`b?Cl#!+Yo? zt%onQ!3;TyQwwvpZH;l7r$qp1`FheaDleweb&o$>(Ypk6TR0hBF;&)j6badjSkU8NZpwIql29X1K@GL5lI{d_smOjzq%f8$bqZ{ zjTU_m&F;~n>a5xeA!Lf&(Rn~V<5?hKM%3@Qb8^yUMM=ucgLAWR6WGuGIUWt$=eQ4C z{`A<%rEu%R#HNyHl26Q8T=>^CNG6AF3uR>uxeK_TU6{9wL&WyYN?HenGorP=NirVh zL?rL>RtZyHR=j)VNRo{{G8o zP3z$ivceO$|GpBV<2x`>7XF1WFRAe~HTps3AuytqPVXCN`Z-@=(miB0X}n;tF2rHZ0LPYTyDmbKx6v6pV(eEMQ=l4+>(#>}+PRM-3UuV=*rlkLDHSNQ&Limw8$;YMj@6W|d4mW zpi}r&GGInT@Gw+(gGfW*SjqB?dnnzx6n)-SBA{apOml`66kajUPF7%$p7OPam6A0}A~LN(D40(+Eo zsm5m9f}{~W@yfFSy4d`2O_$rb*4Z@i{7fI|%08o8E#-M__51cBT1yxs%`NvW3drc` zzsQFjrXyT#-K)eVL=Ba0O17nIL3tT6ktv>MP$p&VstV7)wdu&J;h|8B&NUJM&a3h zm3)%yyV>6n9V9*E=|e@Z(K1tZyAU%yRMx1|E>Lup>HIs-(7OkO z^VEU7I-z>8u#WbvIe!J90V@~$-1ptbttCVJD<4V>Bd(ij`g`@H7JT`AQT3@5N5^;& zY}!(#H@5AF%c|#n>F8JW3Fu{Eu}D{bfU81dhU7ImThJxxm)%PCGW}=Qur;csWKi!x zGd~7!sjc^;CX;5k2-NvzfKVa*;Z@vVe>(rLTF2O!{7yUTWafUy76VQiFg&|9ZC*Yb zhR@9AU5WJQ;ZL@_M=?<7YKfR3@T6sxJ*WMmrP`;cmHoptGg?zi?F+y1)w@z<64NG< zA-rcFci*b4c-fXLW`H0CwzMUQ8@5WzOaBpW(38ARK8I*Ex$KIuF5>&ACKHK7-SVlu zU!|OPrOm|B_*G25F~f0^I0?WNQ>q~kRSH)9I|-uilVI+?U}_*_#C3hx2Eoo$2`Ciy zg0}^Q^PxOimI9&{NV;X?J?VY~$h#c+;zb?;{I4fBD*L1P)8#2@YWb@=3SKndC7AMr zxNO%jl}l@g$h6K0_kTYxDiXtruM63!wC=KE@g1pLqpJv?J*CcKaPV_2Im=bWNi(&s z3{MYoB4kBK#7+F21(^#%6MMO@JXX)-3GIIFFXd2zgq>OYhb94UL;z6yr{H#nANMNE zyJSsDPF@4$iiYgXsQB%J>T>XlIdRbZip}L~jE6@@49DoniSB|jFj}9!6}u63sgaLi zb>iqLx)X0v3F);m(OGO#V_pXsG@%3NtM5Uw%s&J+bU&yNiWdI_?Lj8(kcd7BUk_qf z(~Bj%Pv5Uc2aVFHpoxlR-9A38F!Mi=52$K-fChiAk2KMad>cU3TSggb33?nqj=@?Z z`a%M{drq6ze@D#m#`pm>8;iB0b`_Fy!UVBp$;p+!ylq=5%r}*tJ-20tfe4?8yXa}W z?VQr)oqk|Ap&0R~fb#uKWBb${p`0S5GApoyK%Fd>KSAQ^ba)NOrT zdpjggeo!C|`CdjVCm7x;@f+9lsUmyh^2A$$LhM~)0>uFmIV`m6XOyq6{Rz5Zo^5c+muD5_O;q`~3MxS`DzE6m)*Us4?JAPs4rX zn$ZKj_eFlYB4jQpqf~Pso;mX_OnwQi6^ay5LDFMBb}LK&tRR&2=dPxbsIphvOmdMb54g( zs2oNGR@io}mHTN>SrFyaLP{Q^dQ#BjUd^n~YI!z)WityiEV7{kVwZeI?qHc5nEi;= z`Lg3j-!E(N)?)ABGz4;q8BCYLFw7o<_c=HkhK?A#21)nVj`XiNVn;zB4Eno3$8lL8 z{z8!CuhlVOi=gW=2X5BbC;7m-u&COD78eEfFFx1B??n}!f_$|zmd_cP!(xo21kV~B6nvsy>dvB3)+5OE+M?$!8&%TF*SLezKS4{%j zTI~`%z|8YCp%D;CS}Hz46E$d5aE<_4MoBd@cHX%8 z@=uun`ePmy&=}&LrZmOM4rx;Ip$g-^bJaPNPw{~wqpeMgx-z1ykkg$wcj3NfYmAtY zt3(pWG8zNdiZ#n3Mu`d@&0X;*c#y6|egw7!f^b+V<+1A#Je%L$;Z00wR`Xry=qdT}aJO_^UTP>qRkYypI+Ji}4SF>tbftJzMq` z%H06Q)1g5BP#PW*dHtrEOrKMfEd5%h@p_{j@+RC`1SRWJ9>yM0W^)jmJ!`xkV`E0` zGgAya3!C`8#a=AB(lo-i3%JnFr)mt{lHqvfv&7NO<+MMgkb$dW5Y5`mU-# zt=qy18O|}K3VMJqGU|W~%26V;`KV4kxaHMt$sZ;a1lZLXQ_gqzWiJQlTotsn67Iv0 z2E_G{A5^afpNiUS(tO){wR$N9LK)zs+JWbKqTB1(0&YA$l;u}v(+4%84p3bD|@^6O9j`a3(eyQ83~Xwk|K zmj7CsL8Oj6L=@4Tj6<@IaXC=+vj|>{l3*jnd{IbV8|0^LO!?V_XK4TGvJ1Hq1fruw zr!Nk=o23x5+u{VCpav7LPz&^dm))nso8*D7>w~+>($`gseR@ZMIlT@aw=g5Rb%s|v znfHI*2B5>yM1Cu*7r})#gSAoMD8ymALYVOiK7VvogX^AUvP$z>`(EQ}pI}d?F-q4h z_DWhg%&iRu1$R7CGlL^v$QkeeT(8KOt9(XXh3$~57n4r2HaL4CO_3sDP@@ri@#@`R zif)Xyj@k+}?=6)pEm$TB7Woyn*Yr^U1FBL9LP)ovRlY77fx-{r zp%8!j#n2YpcC0QZm4+Y6w>>uzme)1n?XDr% zfv!KI_A+)`yBwU5AE-LSV+r&DI!(>@UKP7G$oot|`F7HqDgD&;QF0|^Q~hic7zKYk z!uOT+e{Y7FEn1)lY}1K|2I#=99ofclAiH@pNLNr9ZD1>tu4-a_d4BoES>i&ni87nG zA8tg_gqT_r(6_KJMro=wQ$7@?fs*{`8Mo9I*mESgx+feG)bX7(ku{ZzP0j!p@Js8K`eDedkO zK_Y6{@@MbRAHKol9^loDIZsc}{w==Io9PA-F6Vqto9gCLgCeVHyJab}+PsjobvjVzZF z$-$B8cAOMZ%s_U5DhPm(43vbMKAGZvh{J6@+w)}?yIF0nw2+V z|8mMb7y;iQAH*NpJm;hRcI8{#~j?9x7YYGho_g zu1t{9{pbBAdL3m2DBc@d#WGVDwSsjTPPm_u+8iH`sr|`@8J`N9H)-f_*-ml|XGA?n zBjjF@l*RH0eLhlhSZsl;L0lgz*B&NNl71#}^X0_65!1_-4;<{(Oyj(hfnGfXQ6)01xPK!54zhhKGN~~w(&Pj6eR5_9Nc|8R=mS7cMsq@A~$S@ zT>0fh`|5dTa?6fDtI3Hj_{%zc^xc+3C49}%O6QrqeMH8Dnj%1}f=ka6A&o}Jwlm>A ztowErg{EQtn!1dldGx-JMNN87!aFR8vVCIUc;!ubS#>BcLzL%27!1^`3I zdPEN6KuPLl6R=vSUZz46PHFu}*em<$Hjsf8tFE?MBmqH<~$KTC5HNBTu4$#N9= zgmy^#3L7&UtP~$lnrbn>4ZW0JZht}V{r_Om)pv2YE)Xpq93bWfEMKU?s5eG3;`h}Y zn&#KZDiYsJ2_nLg;T@-_GJ&71qm zQ7nLF79ZmQp%$#M1YX=+==*-Kq>jkGn1=mS%L4#cmL2r87E#94`&&bG3whejp)EzhTLd|P=ZuAjk5-mE zzufL1Hy0#rRu1L}u4xgNTPNF;J%4ZRCGo4U#j_l7IGO+iJt3&X*33@fbujREtRBM< zh0(#U_)_h^?*)_hNdkQ7y_4uKN6ZiRq2bCzQ@jckIJl-LA-PIfRW}R?Y?oq(f(VYx zuXLp_frj89uZWgt6~God!!@xffF8kc5OAfg?b0V3p_D3=uiirY*Ss%{cr8_hoIr;6 z_3|yIl+3THIl#5`H76L;dMhIu=BX#~$xI#U;OFfi(&_SzO&DxiVmkm)K(4<^nA@A1 zxF8o@RQsscyRd~YAVJ!!7Ve&oagr{&J*t?+^1%qtF#apHRJS+eJ&0nbtmK8LS-^Jr zk6^xdDR4?*HzqILLxp@a-IdRVUuCJ&Cfyb%EmYb~G^Hes&CyawAskGU=>c?92$yC`3grCW<99ja-{gq!u^4l>lV9DlakDJrt)Y^89S*_93k1vBrcaS( z+fPH*wl&kx48JlK&=s!Dh>B2LQDg)F0XEbj>#RW!_;CIKwuH_A00ROP>fAmXQxv?A zn=u5KTPctLCx(M_1l>pg8745ARoS<81|-ROIrd~`L00jA5jXRQu3cTO+=$w=Wx5N& zRZFW!AnBxAQO$@2&7!jytx0@`->2Oc11wi)%65|KVrotUn3Vj&YihVeu)P?hA}LB- z%?0qTq;VUqk-W-9zv*z zXP52)4?yMoYN`32YVL(|Kt$yHQh#@Gzv^v znRfJjG5J++vBBdb)tuu+RC}emGCf@v4|%j6Oi?Jmynsh(3aI8rCBLD*W%K)%7~X5t z;tP>*>vk7`Ahr*aEmpSacGKRMSj#BHqZV#CbAPI3CdIl&KK+x+Nt@qMWR$ z2PJAUWBz4u2mR+8*PX{_(>-i^Wi4jsdR0&`SEd%n5-^x0_l10BD|+)+c_;4u&K9lA zz8xD5o`8Pkgm;0{15rac?2?{by4Pax56!wudq~OcjAPbV77o_3_Pbx|0Q_yCz#DgT zS?e)zs0UqxJMF^MXk#HT0p4dtFd3=rid6nTK2|lD?qMWuNeNnQO?0&2#Rj0X%?{Qy z3-L8manpOX7qz!Y-#6n`u;$^v|6@&Nt0>-qLrzpZnigh5kFD!JrIaT+5Q5mui2Y|wh2nl72G3tat@63yiAo??$sG?36$*X4Fp}*Bdj?E!MREm&ZzYk z%x-he{-dP?Aoot8zz3l784pxp=mst7y!z1j@1ARrrqaRL154Esmzdm=^zMkmnGco_ zaj^4@P9(C2a~(xb$S+2hsS-=+gR`XvUCFxrC%l3V`A97ArfrSWK20tv*>{u6PPLg0JW-F2kA!2`ndnl19Z>s#4}&5c zRLl(9Sk8pVn}f#@xK3dnCFIxtxJP=uPV)>f8@t_>_)bz*#^@m0JaNuo|3XgJxc5@s zl?tl!Xk}9O;2q|MMf~<=Pkz>)uPw0vFeC5!pE$xB^5u8NJlr0XcjD~QUh-LLey0>g zNQbcQ&!c}dHeitVCfU5G0)Z8YplvNat-upCUBBHFk|>I@ud7~ZdbcJE8jkr0>do2n zL`*xG6?h4cqb?SbNt&h4p_nCyIoSf7R*a+`67$3~e<;}(gdjXh5Vp7jk>22?o{>h4 zBj0~957D)C9<146Z@i5YX^fMI{Mbyh1j;i^4wm;lMZjEJZ9A&>rp=MM1wD4&`B;Yh z%*y4M6*)hu?v}l{-bZIgHm9Z%Nd@6Gpr|1DFFM|?iUydbUUG6(8*$^?HJfye=ncN% zuWTl}%=wx7-R7m(2b;oOoSXYImPZn+`}XD01WgG^MsG37-^!9_PBr{8Ys-OIEl z@)H>pxjz%UdwR+iD&wWShd#|ttf4}vm=*XIDeQbZIdY--oq*NK_ni)OqdAHZ~r>~9fase|NC~@Y9q$6P9QjyjLVlFy;N_hXN4gG zl6A~6=7qgzHBVd`A~LmP<@`@xE(d6q?#np29eZGX@6I*YDmZuG>8K6iP6Jh78Q3L^ zh>7-4CtfS6q;~QvO9?LFk%&6$F#suCjC#tHA@bqU|5yJp>yge1sl07MuG zok5jt+vf-0K}G~k zXOCUN(z!g3*6t=`{H*K*eN3Wz9LlCXVZQ7}Y7buq?I~cRyT_hb007ROD73TD{DjHH z2F@&;-k;7F1R3`L1-PwsuiU~@7=Vo*VeS!&J{L13k8S2g@~6<^#(8&SWrCT)l~;n1 zAPz3xc=M+Up9DP$?2b-=00V5)?67%j<5#=uI^hVW97u1HJ0=o3iLj4zX+Ns{S5>@& zi~Vg!pq8`uvynBW$~Zs)xP|DOq2c6sguEkI7V8WV%?ZiwW`InnUKUYhz(Sm^Dga=2 zgM;q6+HLR$Fs>B4D{o18PK@*^C!0;}*tq6R^n@y5Motm~XIyh&sb&jCpv^a6HTX2v zVsPk+F3Ir#)k`sq89hcv-fT7!w|y@g?z+y)?H+D3cR1Df7O>P8mE7TJ!j%Aiw#csjfDwU zpAa#%+zO(i@vgj+6|g=>==y@0;gA&LoI#6&pm&jp=8XVINo*hL7zX zpl3bxQe99M-7)WTIC}0Dxgqf3!Pht++h6lww+AO&it&eGNOn~9#B{l5Vhy7B@R3Se z7f{9D040q4T04$5#;j3$@QunESrAK~R%Eu^afUdf9;!ERpv|D`FAT9{O*(J~Ur(|{ zxr=FE!z7uAN+t1 zR%RgH;Iejz*WcD78QyBU|J>YZl-bEKA+}AiAFt^n89EUlUIfeUGZ>$^zIOJ*@bJn>1t%{ zw9W3;I0bx@Ai_xi<8S|8*S}-M%fgn04%_QmB8Wx;g=pGLHFG-5DSS+=WAqp(1)e)z-J6kO=yWqw(%H0q zlIEN)5HKa|SeJ_3ddRA1Y^xHL;RY5BXN-@s$+21Ddu99{#;N_jjq&yZJXxt=^b5^t zK}xTr^6U`ZVl}~HHN{YYBXYDX6UKZf3H|dT+2{80re2 zWUCHC9HcMZ{7?q7m8NjE)8=3Z<;E)q?o4jj`U>%~MV7(^DNBV$`66bdQ{Za%3V5wa z|0{pKdEpfeHO%D_NUK{P<0Z*JD=73#j$}pSbxnm=!jUn|l%I_Q)vTt=-slH^|91g&4h(c`jr0wl(v4_Y<|!$J6)zct0BQ@Lpv zE5@oNU+X8VMiRC#lDdKA9@bMkFZ_$Qo{B8Es7mm1KtJ(ILYV*Pai*;Jx(`QaU?B(5 zy5-YI`7Tcolr!A0FiWBF#+@C;!E5azdCU4>&WVgV^!McKzyJQ%*+Z$G7Ik%`yCRZ7 z3Tl!*X2N3cftNI~)w73UGRhW!#Sfea`BmGyUXe%X9GT0|oosYSkmZ#DjkjNUSrFpa4DM`Pyk#Xv z#@RZk$vd+M&qW^irZI}T+8_NUui6qgvH~yGT>uJw0RkoDZIZ&R*p+XhD%%ykE)|Dr z5aKdU>=O!*lLdTQq6Tw~Gu1j{fQ}j;$<2M?>3f*JN7OC7qPsTwThe4I*fY1@;Y~XJ zZ(N02iJnn>m#R6mKTKoIGyQUPPDrH^#)Pkfj?>|nOIH#? z{m4K#BOufXP?tle#VIM8D^QYtfSii3aZG zOJddxVw)WD(^JA3n0O+^AV;b`xs3xa3ERKO@q9EsrD>_YXK^OnWTII2J%PkI?=MAi zKs<{%dRon4`TcFhR(p~1Cqsqo%QgAcjR=N`YsqMp*ugIMQzr-^Uyy)^7?u~f%Ea<| z!FEr0ELIlz08Qc@RX3u7Ctc#Wv*DwJd&~zJ{G7GYGSXg1_#CRd)w#-T2df`J^mIqC z%`>0h6+{LX{lL5g9@+b~KrK<)TXTxAygSgvr|3pK3Hll}wU6_Lu{rxCR1`HPR@nA= z%x=YkO7z=ORWrKF=RDBnmr#5}ZZ&&Um3b2UFz>;7y;g6C6+Jo_KxHQWqz*(x5#3D&uM?8S z)E9FvhRRIUu}|`i$D;nO8f1n++7e^c zWcej**a;e{t@|241c)ZM6ZbT`0h@W_yLDl}gw*|}NW&Bt#A(pPPc2Y;9^N*+r1w?e z%IDqUm!2L&aK$L0Hu?)_re{2Vga<;Iy`5&J1JCvZ>ms?Kh@-g30vKO*cmb@68@n(I z$aKEW*geMQ|6Le`nW}uwCCj%H5`o0qT4n;fX^q@{DML-4SXq&NIQ;kI)9Han47PTk zDk$;Q`6p+ev}?_mPA6u zh~kaw$^H0kgz~q$K@8o0=#oxHmHkuNa74tG4R|8}d1b2*9}q^lmHnLEuk`w{kS|%; zC{0wHD_*l2x6)&(?8AgScgDkZ{f(&(^KUQmQLFb+sN)4}l&!2h+nqi~G$sO;Ku@aH zasT^v=uo&KbO0(efTx!@%4KT)A^;9oiIL>lfOx!UWaH1MeB~o_X8+P%6bvTe8wfG| z=vx@bO4+PJ!=fgvpRt2O_*@6}E$;lGnSH7NEn5$@X6c$kfnucZi`ciVCkjorv zZE2jvdmuuouQfrhhG^vJ%Vp2vyDH5P>@46t5E?`?QM71%8NoW$iPRHYu62J?fj;W% z)xD&21IAQ4YJm*g2ukhZIxBR58@M!%!sVRQIn6J~39yKFsTqU*jLO(-I39DM9WYgO z`IoBDhjR9ZA`wLbA+&>T=24FbFY5HSb%)Vv1J!Kx8qYs`-L`c!DY+_jpu7Jw>esU! z9tHK2I7PK3Em$seW)N7~F)V*5J%Pfl>*#IBcaKl=xXH$QaxRd$0!E(Q-wSm+P3gzD zfP5Al+R_i$;5CF-jis}rxN@V(Sc*zWLJ>l0GdmujXANJ*3G9YeH>?LDmVd9a%PK+Z z=4*nm5e5m4iNw}^l3?S_y*vH!sYZeAc)jPKQJ;n!D_1Qhi4PMWq4z+YA|z!a)P%)` z9`dquV<-vPD>r4I@VQl-*~?tb2mF(1|N0Ba@0fs?D>0MQaj9vyerVv`AwqyWz_y9u zwiUz?7;41Wftx{ZT_Dw28okp?DH_=!SU4V7)YT{~=xCl!dvw&9B`7NQ{lJtG_fd1)4)LV9!`nhtKhpD{+M{*}1&9G5YgyZ6`7BAwhwEYiEY z3=L+wc}@^vi5ft9D}%q5OJ=#F{YrJM!%l^6U)K;-Mex-N^9T5q!_-})HcCgqQIowH zOG0L%Z$A4^+ZZ!JA3l)d3J+SnKlB9WYE?_zWJaz6Gke}xQ8hD z{s0O%%Xi?U0w4ANBh_5$lw$wX|Ns6ht`A0gO9Wo?GyT`#xu1QnlmAwr-+G>9w5LKe zLW2^rY4s3AE4VOP3Y`|o5mV2vYNOz$ea4FZj{syL7$jO3FR3+CU(6E?*cSU8it8Gz z%uwXLv+ohFVBgNKMIpixczIqz(*PLQXE;VQj!n9zb`qx}~$3tnuy z1aD~({JHvMBeQ_{b}14(fueA%rqr^(*#++hKV1tM0Zf&v5YeUy4`6_;eYH zNJ{!SmVL3x@U%ZH(~wZ@IH``u2@ewn85CZF9jQ60%_dHyM=>JL?b0!5g}S#UeU zX;BbYQ##|1fz7iK2a;WTwDchD3T@fSCo1Y&4^!scE~B5S!NiqV0Omi@fCatm5gi z@_Wje@F1$mj-lXPWbY)!>^H4Q(k(ro+f{hEKpu#>MK^}lh6D_RmwM!OT*sbP$c6QH z3Hwh2d@D1h}wjcj9|Nr~0S}uO#DG&dwyRg_y{7s9d3E_7IANC*||NrgxHK=|= zJDLZiT0q&_@krkQi8KLKa!o0PfeR`9o;peYJql%KF>t6K$h8mu1y^IU@#v^z2-Z|V zMEQYI%R>&-JMS^)UMR>Sk(uM@P=r+d-?1qse~-WBP6usRym-$4IikdG?ceMKtcQjHe}P0`I0<$KCKV`&q$>B~G^E#JQs<&YpCXbT)EetR z=rT-Ay<+iFy4Q*|hU1Ld8$cz4=&S@_Pb@;w$W`Rd(1KoNnk3yr>235e5T{rj*IHYe zHCmS%AZMFu6Qqab;`^mbwL15X7?#Cjr*0g^`~;a{_2!A40zTu}B}!wG=Q1DnvlGy@|zIqz7+E_oFRoA3RUE}(se#P5XR9@|)eQEdwb#(+_XoNe2m;WB2b;_&gTphqF|;g>L+flz;TWWF zyek_X+97HJxM%4zgEh9?rdWa@b;&0c#I{nxG*&DGmgSzhqWy7FnF@>fmXG!4y_5?O zJhKyIj#9UV3n+sZl1>&Kdsq1P8dkJ^RYw9Vt8Unu@6{$ST;8B!RnYqPt9iODl4XcR!s1!lF9&cU zk&I%!&NrPR%|8Qc&JXIRB4>JcqjhQ6K!(Rpd({nUbYUo#{)11MLEWOI>^z2@1w+PxdzwI@tHjaLf~kLUQI8`_ zM(YsvHxd=<+{8EPmp24B%BFNP#6B7Kg_9b%{w3a25S6+!_<#& zch1qzlaBR*4Pqd)S-x8a=$Vh+<=(nh0B#3lT#PD|zC1n5PI1FQEVgi-plIi(_;~U5 z%ppvu+6#mRI?SqY!b9|&V!<+Elmmbs_?0HZ*O3c zmoHRgpuavL$CK~raE3w?vB8-JSf~JpL78}RNq6jC)q6QJYR9Zsk9j?K5SKkK*Be>f zqX>eOUxOmY1`u*p$ELfDqMWLAqx;#B#1S7I;&I{{R-7>Z#dO`jna0hN7v!3ePpp8b zsx9066CY(hQq$LoKStUv!!!=8teUb2+C5I31~Ze@y`5%dhlgiQgg-FU6B2uyD7)nM z5M&Z{XXp`*UcFj(9!KHG-#a%`JaX5v!8fH0YlI0>ANeoMB@YdFZ0r9JgtslcaIdSD zA&p4ZhLXa=#;zmC_a;yI^FG|qA8M6pcA9oU73(e>w}nTP+71q@DjKKkE;@i$0Ftu7 z%M^#(yXOs(#=+xID_oCNak2OpA0?v#9Ik0eC5ygi?V?qHZaTCq!(7lcIU}*EpAE9T zBl**lGt*`wtBTrErnH*L1{=o66cS|Fj(+20;4;*EX}wp6L;~aHn`Nkb1X0ulT8W?} zrzulxm3o7Y>i;%P#nz(?KRT8w^nMI7>?tG^a!1k!NTa*EzM6FMqm&F?|)f`m9#7T#jm>B!72$ zDPz`I8xgBnX)m`MyZqEnWwk-Za6G>%;i^xx{wjmlThBXYs{pFh?x(_-o8YQ|{@eFI zB)t;~EVi;nL$=HnXDWQ>hhHBYabm}Q;9fb^a-kk{hKy^>vSa_ZXB$}p$n^fSpY_#% zKPaMl0E*|?Nl04_Zz3&W9DY;(bhvO$NP*;n_o{b3ntf5%UA=Y2;9iVi%|E#)Im zsn+=ulF2QlGGRA-1a!%3U#Z)N0`4oA<|Cb4_budSa@N8-pMy;=73r}GY}L5x6+j7q zAZFtNGkcLR0mDL<)sTA^@jE&Q2c_ta@T{BGG;Fu>gR(RHfW?fMUUbZ|SF9)s!GP7a zuHO>Gs$sU2cUu@V$p3o{wN`04aX9hBV@mY7k?fl97|0iO7XX;+Zw_C4Fe%!GEEvhc zq0>V2+P?!p0~HzO6dIE9&B!Ql8`xYV&%ThbTn|P_lpwJYSH9M1AI*V>0z3v$a#~Zo zTw<4`EoiQG4pUrARBi2<7$CILidmkB|@~ z_o{h3k?$8=ztDR7e-VuMy7=K#WFgOE5y`maeUqoxe`%$uQaHPgfF3ayXyQ4hx{L zJRD49&=7XK?Iz!TcD^F@Oa7XP8dRVDu*wzvf-a}3AVPo2x*(NaXl`GA2YoeWN}{LP zT2(G75&Yp&STI2HkR_(64MKNMN$?X8j~r*Z^=-^r>`C2QXp1CXoov$r1kz+*WIqSM zhDCLr*)jKFGmg&S4I4vSv92Iop0IC8}H=_0trJL0MvL$qi9Qo5W$F`}h z8T>R&AZwEyDo4m7;okj<&lyy6SJB~rRWlh@$1zH(+jBm!j`fS#2tmK*yxj4DU5C>H zFk{n@C@G7^DZLynK)rZnx&!e|S!|_kc{y=_yFhS??ZOoDk^dX6_Nz|e{3;}W*2pz} zBcKca{G3SzcH6%>`WdXOt<&^03+567%iPd482CVWo96>CGbMoBbKUE5(dc!S*MEXL^+W|8s+>)=4!9!27c;4bpjY{ zR&5n2mW+y|?QtQ2zNPE>%{;;aRz+;Ntf8}%%^69#>MCM-OY&Hon@YUpA$xBZ;Ke$rX&q2@D0qr_7FS5Cb3rft7vM+@iVk|4i zf?A~Ux_$*MZ|Sdl-+$@4)|u15PXR*D!Hxi+I_Lh9qD<`dYRbIY+>fJ%oXbljxq0w* z`IleLS2wgfEZWcOHMqG+J$EIJENx0O?wM(bg=kS}gt85!=_4;=!&V%0rcbN+3fyFf z9W6i`qn;zKF^b{To!J~T_T|AIeq*bLr|LWGfm5`lP3^-isdb@l;1ipitjeI{sTzOc zf<5olf6<$wVsr4&`>?bPRp zl7~!OsGTmu%5oUy#6{=aj^Y-lW6pGSO>ZqST$VbFSkL2|#TMJcQD5$A;p|JQlTs%1 zqC86T_1l-&bxnf7QV3k0^EZn)@xrV}sr|wr=LS1$!B)!McHfUs5gQ9%daNX=7BU6= zw1UFjc-;DwrZzg{5YoywAgt0t>gkDWtN~3oWrVg3uX=*zRqFq(ebBwLaubzeT*y^# z|Ci@LdfjBj(jtp5e{v(B{V=y-L~1=B>PX^+6Lvs%Y}Cx5JX7pd#t{&PiVWn>2VmA?|3M5B&jlFDu<#k*T6RTm@`W(OIN%W(;7}-(e#vA@(+>T{TPTy0@ z-e7yrd~x_*$BL?r?VU(iy}eZ&USW6noFkfrdHWzGICs> z8bCqRbBo2N`>Gck2BtlMM{iF)XCJPN!w`yY3j58YK_(?qzLKt3HPP?i4vCD1e3HBv z{0Oj0D`Rwx={oQjXEX{YY|=V%w|{N{z`MS zi(Z7+fos{}s2@aPsU>H{?Hh)67!~e`?vyCNP^kswwg>rvLk5=n2ByG z?pMA)(30JBBvQ0-ylofv)TsN1hUFf9nY*_%`{E|P<`rkX!IF_-RB0IFYBW7qxW6J;KA(rTG^yUQwAyfzQ^kS6-pK&E#L70scQah_GD1< z`8s~3r44DaDQD!AtPdGMTec6P3MFhKcl^SpyI~3QmGI%jc4^jyXAbmk?0pzVO{XN@ zPb8hc8IM8*ClO|^ci-R^02?K|FZ@VS-W7?3iS~dpIWBUzvu*3=7MXztq+`)N+W%A( z!cDhVFoNQ-Ax91d1OydawL`-%s2C>wKy^v}_m3v_DKC@c=?nH$qdr=mW0T&|nMe5I zMd4^F4_eGPNrLQXs;YApo4!@|FkdWo<<5)Cf*}e`HpY2CD}PiMC@#&#B1Xl!+_jLR zN`^$6{6BDZISdCZ3S2rcMS_G-zAc_Zul~AFf4*wCNkv(=2StZlt#JrrAX|I%53}Mn zaK2d}!f9{jTyaF3IcuJr9JZ9+)%icjksJgb-OK++P$@BLg=$pZTEw#&xz^}{%xee1 zEMIq5Vz1#I@$0_hB(O@kkfTIz3PnKxBGjdkhNJB`)@YD*h;H0aMUTQV$Duwq4zUqD z=ui_MLKXFSr8ceRN5DbTXiCg1Ad*18QHhlThPRMfKfm^3Ihs4D`w8JlyU5*T$Pyms zXY!^a2oz@hpicFxhc(T75lluD`zuK?F#i-)_>?arG^Q&+!yH&^tgp@r*^nUK=eBv{H z9_v|YA)k#|CSp?C^1koF&gIzA;yu}=X6{}p@2lxVFTM^>zps}7W4l?&kih<)ZPjMNf@op{4iEZ#FTZMtybY zGTPAh_fRj;%UXyeylwbW#>@C?Rr;^J&<)jlrmxqF(_l9E;l?;3$kQ;;f%y8iYEpsZ zQ*|qOMMD&h;AQKRYFf9sYFjt`4T~>!yRZqJ1knJK}&NA#+S2&TC zbrld?STl#q_tW)F*HM#!Of&bZ!leN}*6N-}e!@MI!Q}3`F74CMR|#&RJ}mlY%#>Cq zm4oBiz~|V9q}^>cISJJmWJc% zp)!<0YF+syYoVB0=aXU~^pO`79(Eyj6-SiblP@HRyN0;hU|QcngK%xtXU59biY!t4 zE6_Qdfzy-%Y52}f= zJ!a&l&tWP;P7sC?#kXcDL1g*lQ7v{@wXgfRgHOGgE+x^5#|z%kcIvf1yW}tAk>;1Z`x?u zWW;SR8$`d{s>n7eF~@sfTsg6!;t|f(0qPo0VI*pVi36p+vGe5;;`w3xGl(>Y8CejLF&8F|iV|gbh{*tnQ2|?r3gQa+O6$0Nbdchcgw}9k24}OH zuO*p{+zDpm&8mLa(`w=JsM8aj#QKIqOyL<}X_5cIm~_cIemsQkxTZvCsf9Xni5;l47wmZ+w0`@eQfIZ3xcM zLk|R!iwN$8*E-WZ6X8J(Lhqk}eBF0=s@v*Etgl(xJNWQ?wy2RYB&FO4O@t7txVTUK z(5|gNGp(#@CS+O;Xo3gZaBktN#@#xnp3taF{4bu48Br=5K(+B>vCEx_%(O5_dmDI2 z6JvLu^}l8F##eIBxr_sGC}=-L8>#>yj1KJ1jlW!9l~4b|%=UDM_f}B}it4XAo$m>z zk#hqn#cSam92jhxr-{lE4+XBmcua=VaE9+JD}y$-9Lku6pa7X)3vcW3Pq3N+jQ=@b zg9S0ZVi7{^Oh8yqRWuREg6l2j+dU)a3i(YF^#O`|{a#81lw^KQ!2k>IW#r`dM@+|@ zhoc>uk}o|BHN9!Y=np2zv>0Idr^$aD3GH`hA2uc?)Xahr&Ss-~RL6@> z6_>vV-3O%G?vjEjeskAu=I%e078!KGH=F2%c~BI$`W|dDiCF5j7ai2c3VKd@P*yf?*ZT`e#J7ISx`V9`nZTuz z>BWLJ{QrwKq{!^2gbPYa40|7HdRJLbMYtK?%_Ext%6H?ClqT0>oJ1XMH4vB>3FoF( z)xOLjX;wgR1Kbsr^jaOl_n;QS|EW^*o>DaSrvWK&Tf2KcyZ^|mWAYYPH#g$wXu}9V zmm3EZeU#9sn)E%KlVV7DpugKZctvb9!k2k*X~}o$=?VbBv5)l3S^h&MiTBb18@5o( z+!tXR_bUgVPk+iv0a)@2;YSBZZg(E%Wf=}W3{Hm0SbH{e|7@W^R}Qu*G&H`j2yl%z za}*zk?~>c72=qr9?F%z4i*bt!WMx476E+mrk4+Zi$jnPiVp&VeXJ3x%g`7}oMFK9^ zBBv-@6M;sVNmWll#e+$*<2JuqgMIv;-~K>-2!X&s12;e10`+s_(sg3?IZJE0l_>`3 za~S({+#TIEW#Y{oK@fy5twb}DOpcsWnG;Sk*E({!TbRr z7ls=7m3PcmZK<`bI>UpQ?|61tqT&R!5f9+BwD;jTE!IzoWU6ssP9-XOCvcJzTa>v4 z;z^*l;+`yj73-SDp+9d4Q!O>NS`B5O#h9~hocMSK6z9tYwNSsEyN^Jo8C!v0t4@@Y zT07s31w08ln^Wrm=UbvRDmly=`&vvWKKaYS6Atk=jnGYDl)lf!DowNY$0g%2^+Bed z83A$$&ZSd3MSp67fQ)bN%NW*pbS0WHt9BQL&Vjfia7^0ULpg8!ua!i_$Ee|j*4ARX z7_=yA@c+>&DzY)^N+UW0MheDlenqBGb;wkiCr#2Oms+E718&UrePcB1Sso>z3IIv6 zL3oG5T_I+oLM+@)1Go&65vg8HJfT&nxr`-hZT%3RbNeEKYfYd|&t%++bl40f!S`({ z?#&+cd7E_~;%|oqS`Bf8MAIg5=+%=6T|mnqJ#Zx#$Dnv=*tyzl{5uhkmZEzPDI%Om z6QUuZ`~jSYRe--d&_n?M?~M<6tki^W-jgNE0{LUklWgQ{?26fTFII0TR z$t9s`X?BrTiKxwh{MuK!-GeL1m~Ut!*%ZJa>MFC10RA8z*fZr;an}~1>qN$0&{d$k zMiVT)NofV@@so7`#us52To^+>0VcuL9RjhB9rAPsv66pUo4`dNQwv6O;HcJm2z;pHrEPdMzoJlK*;tn#;!2t3c zV|JFA?AOj6X=PO#!v%U5bF$DvV0a3r0{51TQMBrpo%ncT&V89zo;B(xmlgzmxA8yE zOq69kt)FfxtKwhw=rG42Du+OIn}3Z)X`nA|0{W=>ecNT3Q!Bbb3$D%lhCpa$y_YFP zOh2#`OC`96-?&6+T;a6c;g)t0gh@BRnIK!H#okbe_u|ip94(-*#?UOWUf-9%hU9k^ zqQj)8!tZQ$y`yFpM9Q?ny9Augj{pACTp72AP>ms{GAnk+w(Iv4dBwsvVMud^F$3Xt z!Hoj`jOr*s=VY>y6Wer_LgoDXerLxK9N`UG@a+_?4gSAP0vf|re+ja~!gCde&;%poaHzRh`xylNxbF{#r9Hi@3Mf<@lcROIR#k z-jxXeYp;YZZ(AD2mSM%zlo}J3c;$}1PlrU&S*?~T{bqSDWGrv2$?yci1tKA9XAr2o z-j_{UVbPPJ_>7O4Na6Ig2)dTOSX}MbP>l{Cm)qn)lhjta{%HrerB_q?8ay?8f2lZZ zU9T$(&me&%Eu&O7?Z+?9rpbVYgctv)h?>5Xc!HKJUA)S8LOO7Z`V5xu>B56TQv{!r z%+(hLmzmUn4f~^LRd~QTPS-P8!e{}q?mEqM_`mQ`a(9f0!`x7arErL(U*sQr1_DEUDs)P4^~<|PL{Ow&1V)wsuvwuLrP1Nn;R~ei5?nr9`v*Y zJT2%&Ggw$Pos{N(P@!{Rj{Z6CzaOgE{t?=T$w1M~9p1Q2F)vO1#fB>b5g9o65>2L+ zIKLrB*>oj&V=y`RFF5_gM+Aw*QsRdLb&~4Iw{JjS3?`cF=GSDXGSN4PXaBdOi1M3Y z{1C8flqDhTI~Or(B{^p?1d+n}wE(XGYAXFs3IL?-JQp#YVvdVlg=vMAR9g$%qtuiJLXeyudM9+5|y=_->X@Lon| zZB920z7_nB;g~|A*3BV(lYe>Hebo@%_wll|z6`CA!Qh8rXIQ35valRH(}F+G z{rh|X18JOekj0(xmiZ$-ceKkt|LQxzDdXd-#LH5=$EY%_oK9D@7x@BJfyiM7%+{nD zPQ}nf6sv%?yZnQ(hWc;oz$Lg$@@Zu) zhnKZtVpkHTj1XJXu8I}4`76{(7VMY5;FEQ_Z>7VDJ!E#u?|Cz?l(cJ| zsBh}QQkd(jPhECOmzLSM$_y_GAKs^)nF9$Lb+cFCyGwG-{*=~CskBBQFn+-PXR;h_ zR7W#3M&MmNb@dy3tBC}=x9Mw}T8Tlf{4@^)ybe4dStlc~k}Kh>((OtT zQeQmVG%sh-n~-H9(arHIRZIk%E8gBp=?U}l?CXP(TY1in{~zB{oPDajQl>>TBe<8V z&xPW5bgR{c5HmYz8o(M_g=8AVUMNry`45n4hav-QVmA4D9EX^G&`|9Ji2#Z8DImQsX5viGhdf3a0<($I1f5?<5!!{(4Z_ueRk z9{DzHe6<|o>48USpX>BJNFZ3AGfMgN0!!5NLwG|3rqPy$EZFIk)(0u6H5JA1DUO07 z$Q0X2lgjl`)MK;G)-x6dAIkP?M2Z<7q-Aw1g~q3XuetApXz!tC;H@`sHJJ)5aGVez zzTUmih$tD=Js7}zQ|U`)=Qkwc5J-Q1(Oq)?7aBEwdVU3$sQMB(u^V!qN&{B zK*aw5HZDPDNW0Ali9)6HhiUQ8eCWjA~|LANMz`-$|Fkg;?oW%mx1zY+fx8|7<; z(>f%mt-MSVN?q~)Hobl7O(&dP1?gzw)X)gi08>D$zp33CKYIP^qrmdN+_Sxz2$y70 z=v3_v!}i{hb7*J71@w79Y|ZXsMpAIFF0+hedfK;(P42`^=O*nG%_~=ZYi|Vv#t>)6 zYXM%3m;Wm+#;^4cn9o)Z&F|mHgo+l{3dfYn+9PyKBxm=IVXi8tdHOs6Nl25H#Q&L_ zKd`z!!bork$R;hbj!-vIqDt({K7F`F^5Bm;r)1WMEozYfTIdJX;wu&Dz3 z5u=XTO3%9K3x3LsowB3?_9^ndjvJ&>YY=%?tP?31@kIEw4Tw|sFP1uM_0ARf7)@0F z*ie}FZzg_zDa(|W$-vfs zS7Jnj)H=kf?v5@{fn$;>oV_K1e#Ta9G5MUQ6ip72!t zoqw#wCtYQy;0OyWE8V1s+vDTWmLY5gT$uITE}i@DQldkzhPEYtHV)%g9VLb=i~?%b zjw`{=y%A#YEh0+|yGdmi!^IiN1(+SpGf3jGC)L#bmFrQIcEQk4{ts2gN2Grtka9vUwoS0s#s}Nh zB}}VsT3nuKSnf}tHY!pHmJG@k7f+uxT=!zJMw^{IUJOy4b;{sBa@u{rwWX1aXQZRH zHbSgWQ48pFpN}&RMk$7E!ECBXN_U4Rocx{5gCGWfIT<;y_yytcQ5)yIOZ|juVU69PD2SyK z{dEpv9KQ=)R=Fxq+I`5-@Y9$22vsUTYtHZUkzs4y?Y|aR3u!vv`F2z4FN}mkzugO9 zRqHf!6rkPz{%rG&-r?(n{xwmSsr3q9*cuz zh{R(=^Z@3dulR1)U7<*M)mTy0;Nrx)Ab*LiWu4h!!9LY1T0OY?(sVgg-sS8|i!3Uh zyUPb!S<4K@-uG{f9XJ~|!vt3F5CRC2Xl=X=v&M)3uyC9}Lr`)v_gx+l-IcMji%Z~c ztl&_e3eXL`0s&#>KjM7rNmSx|&vQD6*?nXGD`iy%nZbWbD0QWFoh9CRgjUcRl|fy4U?~bSsKT4q`F}+YACyAt4ui3STPUii@d78Eea3fD07VFC!xfuY z9|y{QIauz!)D3MNn`=SkO!%UY#&7o4LPSZE=E_}jNs=DZ=alvZvvdjM?Srf;k(J7+ zS+=H{dhHr8V!siXOLuu`0e-shl)wp@)9r9j6gijTfmf^k?3mQe5u(=Ht{@;Bm~dk^ ziN-$bZvN!j82CBPh+mf{U@#HO2@Z*ak~F6^9Acq-BuILN^lMA;5yV+ zH*!zcnxnabL9W0n&j0dkkN1F?zgc-yeat^EXu0>t3Wcj`gwntMf3M7@kz(p-!RPU4 z{I%Tps-Zuef=$eeI3y4O`@|b&g$GitXL}S&Bx~E^PRkB_#cKA}88v^g5wFFTR0|8C|#WT6QDB|-Bkc|CHlhF#J#81sfA8-$5!&y z*Xgt_>*s8MZ%EL(g8(S=bv!&GW8qWzLUk{w zJq$(SKNbct*pFIj*U3heb;vBM-*hiVFd1HR2s!fNh^p_TW^8m4U$<1~6UBU8Mk&xn zb=wO!fmV0xJIQg}&M1oIyZSGLs8=3W0qQzrp#=noOE1s5E@6UA6&WpsttDnL*3rekgN|rzpYd2xrTv;}TomuK% z*l{x?0;b$_X0bd;PX#*n(5c&vzli&7S5T)uwaz3?$4NZAp&ZA|lvsBi>!JclsI&mys_>^&CG2XBke zLe}be(RrHXzVNl{e(0{})A0x_p0L(KRy8Pl(J&dAcr9@?fLwO#y{u#uvFh;+0M1n8#h4AMc?IKaRUE$fQte%)ZIFF3SPv_A}s1%MN+hk-1Gy_JL*qzh2>i9}MwX^U$<}FkiDNwD%QKL=`|kBsAjt z*b`2)FmL~(Jz*MnFo|RtK)RFQtwFTW@H7cD%^a^>U}5B?G$4X66VFu1g9M=ZQIV1e z7_P7AoPRF6VNhcg^*fhz?(il#cF&&oU-trz%;OcTtAEGp9NZ>jF1%|VpFyoEsL!Mi z#A+dwFh`LSmuNJ;=VMfk4wwBmRnfV2at{77P3KirqkeCELB|}hhF&tMp%T8NeBCyU zD>UsLEc@GWgAJlG$9{UtjN4#gZpx%sw0@B{;F=E+O+j|1AVOtcq+JugHrXe7`_^@H zX|l3(%Pl=Qv66olo=}=ru8Z*qbs!dhJe8%7J?4MtZ{S89o=Y(Ozb;rdlA~u;-s=O! zV(Bi%5@>v!uanXD$@A42e$ct2Tjs9^*qjkX1NS7R6FP6?tmX}J1&7J(PBTAyVoa-U zWTl$Qi~V(%c500~e%(qFQ_4hOAmFTca)VXmPC--pK_5GXnezZcMw!d^qSR0^kqCzJ z&Y4>|&t+CFl@&H=P4LXS8-9qcv^1pWU9zX(V>dV;im3HY-;2 zH4`oX)h1{aI#U4B#tzMSODW=}UZpCz=H$zvO&h=#TZfnCcqUP|WvAeGL=lxJX+bAc zmru->!=ylG_dWEA*3`cGSTPJV-@4Tw%KPl2(56&4%;WBe^bBho1ZiPyc++80s)VLA zR)kR7G{apRe%}zttvkEAh8@qV^9dCr9Z_6Q|*_H{0GVkQup6e3=^s)WOHIU=0Fp5@R|U1yb;&`1>}T3$Hk z*Dc5RS;24nFr|6WFb|8Wq9Ft@uTqbnASrrag9Mb7G6C9_3A4%y9QW0S+Fand2y;P* zTogy=H#Pj~oiTe^)f1THv@pi#;SG7A+O&7}=MLiIU zqDWJHDL9-Uz*;Q^^a)s?LqW}WxzMWBhs&9UC&OtCEh-GEv>k03V|G69;z%lZ3jk2y z00T9^@&oyW>)9XWN2??ZFXwz*RMo8r_crwV%#(<#mg4aj?Fpsl=}64Op%HbZvPhFZ zTajle`tHm+^q2(FH~k-_dBwi_sB1Y$qF6?NG{>!dq}50n;^qfm_c0E}K+F z3Eh(nzI?DvTj{8ShZN~?Y?Mj@SG+8P1RqP?!&VxUp^)`2_Cg}1$sPZ7GbaOLSMvmx#(fm>s{wB?y@$7q19qVFutXy~qz zOpNPFE^menswUITWwXSjH=8lqQ5?xy6hG5gN6V(z%cp`#)LAr*!OL6ZPe;vM%Y$fq z0?8i{{c4d*t^d#eeCz41+Mr)1o3Wn9?2A=Ke5_xw2)!x)&G&%r8a)}k@sV3fQ~bPg zJ?)(^V>mLexSg{~22nIp$t@3_X_WvnUw>^VAM(V9J@@Pf!E&iM1`I|DakH#3okI}k zypQq!|NpJi3I6x--5$u_&Q7p(s7Yt)-vU4CBACYu-iM;QZaD2$%01S$&Exg*j2UtmSQqC(dyCEZ(K${x2DV6|7KA7HftPPqt z>oDD#Hw;Gx9;5rj3zvy^5gGkIQ#Z|Mi#aCNgN2j1m%_q~&jL^Gsr;I z8w$>NF+2+gnPCUI;7-ngVVh61$UTqa%X4a*{##a?oWuQ*OPs1As|<{8LAJG$~w^Oj|L$~W7c8=^98f* z???FzNBobC@Ck!Hmu>Z%=8L$Ou@Y6LQMY=d1mdN-DMwH1JBrfrG_<^Aabr$ITQ-)% z0$f>n!mkiE&_yopipAPImQA|Pme7dt8!t9xKjF%~xr{WDiKIIFXW$~e-H232Kbfr2 zPrMo|0r%ZD+E+VMzS`#uM3N(W@M$$ExdDEVc!*xu?f~!z^j=AdIWU!GlHD7ts^0-* zRq!zcKLI$mc&slq=3{}=;Dir?rofmCj#m)4&rh`Y?8WuW1>e2nGmdoysXdewt1dnf zMriAk?Cyo>9x6J>(`K&|1lFfB@DEw9CLm|p)v)!>)=pzj*lxonWBJk4V&X@|NnXx? zywgJO`xHP53U`1UnkW39&qOjq(;}^YKWLneoVr`hBn-Wo8!SXWhjtyvxMV8##RwoU zVBLb7#ysqi4osdDvj&M6X!l>6-BA+OWPeZ)%Lkt32X57TVyFK7BvqfodbXJxdRo^a zN4RX2`c|)<7hCYk6@Zb0%6_SjSFEDyYoCl`1q;kDlAAK-8~@)bZkI4umiqs_3Y!wD zs&y74D zq&|E4qz>;;M}_2GY{j*n*;*fA%Q08uZdLmCu3RbRKL3Y68)7rhQ1>=1@a46^g7APb ztKqCyFvLk@kx8Qz!A8WGVQKa0>a0n*PQWs@Gj;nekg`%wrnkr*eM4?>B7M_zMu%#B z`bZ^UumBmPuGd@oKmS%%2-PJbYXGd8-gaYNk6~w$86#m{P7(PoS_|^?i@JsLD8}#&a(F-AR9}F{bwX zH5sw8Lcl(Uum~=FVf}ATOZq3(_{YJt9jznsOU?&?UcdC|pePx9F7Y@h_rJz=zNm2| zN9Vh$AY;I7^=0Ze81gVy8AH2OgE+~#8CD0dusG2u)`S4lhl3gX!NUbKi`+V;Va3un zmsYI)erftAoOCcUR&-!f6L+9EtAsI#VU~v0BW(2YrxZOQ6~$#*{`^v;EmzO+a2xEr zDG0wWVn04L+$7K8ud3XDFbZ>;6XK?gGe7_|tj`%^QF%e%uSPVJy7}o1ZRi@!A#(*8 zEAS%ii&>nMX>cT`D@qH$pHMrjv0hb;N9|;*x35eNJI}v&<9TuZi((NTJ#X^=p*pV? z(i9e3iZA&RnJOt0rscBod5kA6^QJmO2wHUAX`#x*ggd=~we$G!GqMtd@MY9YY+ZyL zP(fQ(vg~L2X&3CRJa;JJL`thG$Fg!aSNjV+;TUru1#pKON%BHC?!iVQ`;X;Fi z^ptIpj?44eKfp2(V<=6n7x%MUrhDDHxsCr}XvN8ZV?{{fd?L*2Zw@e9o497CqS^PmKT`9+gKamXXS4VNJ%nTHrq$y=etn|% z?tM0tKklnGdf_UoNV3TwoQfZ%2QHx2%JHYa+hMSKE<69s>L39PIMfv)I z@&TcC)j%8OER4^}^md7zIWV;{2f0|2iylPI%FGn0XvRn_RcT9LxDn+$>k7|ZA5Uav z1wpCoRPQYz<-k=BXD0x5O$Hon({^9ZFe=OD3Th5*zm`+WgrC%$(~4`{p9IL}9#nRP z)QNr|lu>A$bO-9jZ%W(9Ai~&$)L80XtroNY|Np{p=oRXa?uKdj?_H|g{(k@zA*IHB zSO&223j0r5qFn2gx1T(FZ6~Dc=CWbp`jd^J7kJ+$W6+u2DfK}oCv&K)Kv~KPx%QqP zS`=9mR7X0=Gx+ZrOuprfz`arQ3DD+tnU0yhSdT>mu&mB_!%b&FW*&MH`Wr7Rw&}y`XS35Q;Zx&92Y*U4+d9&HrJA zROh~k?)hKu$Ze`O(Lg&}!ed7JrcYA)(=Ayd!rEZR6R}24PUW;H`7N{pA5$5M(IabN(k)puWjnh?M=a!(gQD`D|i zCLId^4T?|R@M0~?90U16GLtMQcQBD(3I+Y5B4UESL(?W#923pXZ9$`Cw2_urgP>*RSgo49z-ZDdkShO?o&y<`yxMZmQ~&?$ zgph@EXvCc(iE2~8NVXxJvW;S_f)p6agXaPDzq8D0dZKp8V$T5x5bG+P6Zqs?TRQk< z&l`?aq%+zy#nnY)T!W9b&pdC(n|Z#LvQ>5IBqJ*3W2QRVhXB#vaBa50*|XecJSX9o z!tB8@p9tGRZK_r%S86C%U&nQ*i(i$8A0uP=3Edm!dx5;M%=-}%UOD7=RWv~=q%95q zKDm~92XQh8u;WK(eqkA%fX6invRqdGezlwu5b%gj33yQH5?{(aKA4H^{iwa|mP)4= z^k|8#9#N~$+v;^Nar{981^R`O+3Whiei>)W=7D*d`C^tBi~q1q)##!x3uh7dwcMKm z`c{9H)5pnpJ_!p4cm2?xmkj89^_W~uH5|Ivqm*U!Jee2JXd<4wde9z()cX z6gvL!h+_;WGBad!iJVs&ODvy1h&SzFR8ZM@Q?c1-FW{Z3B*YAq6!jJES)@TT%-w}s z4J2`}Z&)`MHGX4rVuB$f3*o`EV4v7TfwFVt4Qp4TP9Hz@$AG~^{F$+OpF;Rh&msiTqdXh!hW53KPv(@Yf1a&3(@tEh zM&pi&fY^9UmTYLKQ~`QrO_(_KCMW&ovk#+TF+po#P5VW$6wnY4u@G)s5+Wy$k9a@j z*K8YWfW~H)1xAHxg8;|fYL7yK2rb2NGnfh*I?BYr*9E& zdcx7Tg9R0ib%PW-LTZ1zk3^UF&4-02Y8Kf^2dvOMmp&O66`DB3-Fo7gBkb-T*?WJR zS6I=&Wsh}<*?rY=>-xDfM6m57)5);Dng?v!p)J|wRZpRja)&6{*XTR-Ai}={c>*_% z;EcD;{71&TBiZb2-Q*vfJB$WI6<7$oVLx`=IdK)O4jptZx;^>Re?mUGLsTD&z&y3m z^1RxvHSup>4zWq?{LE|ZZ?nMC5AGH3Uq&2;o~7j3dhPq!@-uFs3(lliU>=>ET&VCI z2A(3=DXbl|sJM>E(DE?97M}RUTIIfHuALby3O=HFCk zQ7wf}qWA=cUA~L-1!c8R&{mAh~8*$#bFm7lGKD3}+$Ig2Gkc`1dI2{gADU4xs0UzO=Xb*K2JQ?Tj? z{&F1y^`XtTnZ-WpV*#@)G3h#;i1+wf)(D0q(FnIVtHz$gs)WtNWazk(cg>-yqoPCI z)svTHzscuPRjfvtx{h3o2)(2Uqg;<@R_zv z2)s^wgj|J6dd3Q(-vcxh7BP(}=7%PCekNP#>V45+B3=p7Zyahe5k5NoUr||So6_lR zFTPINvEGTG&?(bqmPD451uHVIgu*Xa-^u>&@TI%;mNObNNC z5Rh})=J{uus1Xfp6?I$T=5?r!ZmH~t5hoH7urE+FZBFmu5liXC(s62pja4~jLOUxd zXoA|BvEA-O6E%fs9-+1j zk5#dbJ<*+ic(SELa5xDO57^?1N0hU+@vggwn53qSL?gNZr_i}5|5n}97LM27j9RFm|I}kdJ zG!A47>qTZDd{JP2Cwp7wys;KuKnIvYfe09(9U^YNx9<d> zrBCy8d81O5*c9rbt0HUXsV+l*|5<@g_YLX?4L&KKSR~p?gD~6QV=oCp6-7R(&Vn^s zp0VG|wW_r=fte}v#$r{pyKe~HW-yteDFC^VVJw`nwm@;cXpN;qp{>l zIb1>>jI+UM(ecBqKL2RvvihKKT^5Y;hB3cTFo|6d>p{wa=FrKS+ z1Ytn4Qw=s1QWuDI2yj*Vo@pA*8FPqGFE&0?1k<-ny-G?Wi@k8VS`IEA7r2f!aDZOEL2e$=)_8Na9Rq;EvtzN5< zK7~44Sd3{Bpr}+_@f5Dx@DT^kc=JNLgG1 zu>5nQ*&Fi1fsc=x+pJ(omB%BTAKm@hxW`gB;_1 zUn%zMLKPR?;Z8wdLHB%?nR`i}h9*$ zy>y$8HVKSQfZkwG;`z<6E3K+9%sfIIU0G-^CWHFKIf16t00Lx^=7Vdb!pe*3tx5hZ zxpXEhctyPDi(#IdWPAWyea8nWvSvM$olnXa;gSo(8Xa(~S}y?#R=LuSk!_-oeVMKx zdbpHp#6G*B&}ZmcAPuov8X-A^<87$aHs6@J-pHP188*EljPY90-}E;Y0E3FGpj{k{ z!?F55UVsPfwC6P8vDu&XRk&YqKnl3mH}>H9mHe6$1-suv03(cU!z}2V+^*|O7fu(q z|NWkjimu!{_d)w6sbxC_#n{x87dKbX^N+i>xx=fbYfCE4xCg7CQ*&nwm!lVx$3n!% zee2PTXtItk-atXU0>;}%p+q5|MH)7vqNzyls^O6=Sx`<@rpSCk+!GtuRQ5?dyZ99!oT`7+1CEUnd+qqZA%BGGv)h^Qsk`qm*ol{Tbm2 zWMLd8lmwN&wKpqLs%ItZNAoR9B~}x%M-A@=)i{ZJ{E%itI<*Wri^;o3=Wy9vQv3m~ zchZ}S`JQ#6p`v!sZpe^NKT;b5{{@y5Z5OV-oD~TQGGIpYm}@;a6imiS+ILsXA~wQX zAFoVbyHCanoUkXdJf9`O^X~qbx;D%8##07E4{JU`U$EX`k|z9h*OyNV-)kL;`gg~xkdx5S;(D74*{ZnHqkTEgsHr$I}J6ctb``QDKQZ2 zB~4N6!~^NGNj`PL^|`V`(sr5xaw;Js+ZX?6APw{@$SdK>d+-0UUe2rZB+nU}#Q#ZU z;Vk_i0KZ>v;+9_qlZlW*s;stxXj1XC?#giB%vlf}RG^@93*gTBN z^0ID4+vPR-QO%)~lNg+8?y&3XKm^A~R3cz1vvPmtJ-9((9a6R-W3s z?ObKo?&Q{=!TZ+$U+lVk*rfmMMH2^X`ZEA4*~)it{Sb?|^_=6JyP;VZL2dY;iwZbL zEtpuI=cxFQeC7YEf6|k##U+3V2`um-HnR<6AaEKZ!zr=M--+`>&*GyVc&NusV{!s+ zHCTRbiE;)E3nmv|HA!2DP{jycoPmw%!FWwLO+Jd5rJWV%u? z()5k(WyPh8Z@*~%Ugo6?(H=l-A@{ddqyh>1m$ckblSgU^frI4kSLz?Z`-^2Wa{jhr|kQ~K2g6=CO-;+l~=IJ5SH z(woG1_B3jQZ%46CH|p1P67>rhZtht(V=0GFaNmRL1}*j{bqhpdo$D+ppw zVgzq-12^*UWUV8ZdZ$T%zd6gXckL6X=5YRVNJ&#Ill*`6azw9B@!xQ zO|KIC?@eVi!)6AdCo^tx_5R2j6LGh{vYO-gsLw&KQZDP@YQ=Q9r6`}ETfpD{^5U4R zscaz(R%WSpR09HTm;)gj|Ni;`I`#JfK7q(z|M)x<+;X9t+6%Lf{XcVtsQ%ea;G~u< zI?|WvGV$YbgE>>y0az-Ea3=~;(c0*pWdEI>J0{3D)z-7*7k|CY+>}52_D<2>H@rB4JW?HDbS=7jqJ3dqr*QCaO{@dSdtbC2mYE;3NhAl$_cwx2>c;c&!!{gsYo*LWl->&;3E( zs`EgtNv~6a(anYt-#pVi0+%FTw7shl~~7=b3q}Q1!U){a7rk( zydtYmC$xshc|Q>ZNdM@a!6thVZq;tu^sPLe2R1Gg4{Hu3qg!@3r&ROem(4AECHl3` ziBtVsTPOatYJ7IGzY%UyKSACLvAdc2fH=dFVaWj~F-Pt!N@beX*QVGw>5i?R)~*6s zW;Ik;74D$dHSK*1y&~+pWU85m^j>tId7o!f*IWQGCwZKT9bnM0{`Lw#sOb5ezgb{- z7d^X)d1VQf)^priwTjwKZB45}J<5imAMF1GM>54QUj;MktUJEz4J89+k_)w7h52GT z($xkD$DOb~^_`16lD?-5RaT=BhQ6;zVZ(?Xj8)oOQQ#yP_?zaR8Z^LoLbtJ@fv( zZETVjI!?82ed-RY?t~HgQzri#2kw~?TDGpqMJQh^n2qOyE6#rB*>t5x*>@xrFX50} zJzQZdXJ_Kf_YiAED(>Xu#{#{K?wbWFBH1{iXJuek+mLyP^Jk>o!M=Byo+Hu=JrYJE z8S$=iIm`aMY#ovvlR>}S0#@XP@78c8VJCwg&A;@s=!MhKg{nqhRamz`s~S{Tc@L`d zHyLB!GJ0L;P5n$FrcefDr#WU6_4BMk3%@j*G(7S80|5P2KWhUYTD}w%i^XV{=Z@P4KmN60KZ<|0=F}sMq(yF8 zZXj^@L;r~($LZyQU%YdWcH8`TXVy(;E$GzE8@|s=DhP4s_BeYu=g{l94-;AE)nqg*9 zm^aUX+IshLm+nPxt(1By^w3-suGmF%X1zK{WLqBcc_J-|;hvEMm~Y95QOOWbXnx~* z*5hnJAE)^WyCpNc{QQ`>99^()W<$Cx4(K!!L}l9NUm(DLI!N07FaJlMN|24{WB=fS zoIwX;jYtZKA=y7w;^B-dcEw&;Z7kLb7J}X-h(ZLbWv54lfI=uFJI8jnwCsgcx4&Ig( zUulwwuXoD-2>2UjHRh+9-rhx7i#`OCT4ue@3Qi0F6th1cRxQc8{?X3*v23zNIw+}k z5ah>xtMEuq>H&qGwpHMdv64*F@mo zm_VhhFT)Hmrg4IXalAQD8*Cw5xk%Zp#muXIFZZT>r3Ji}Hf#gp>a9JV0EF06d519! zV3wCYXOr_$0&P}?OPjIhBx&_2-_e9Uez8RZ6R9kLs7R=S#Ai0dK+PjK7tZbT_qj`{ z!I3Szb8cP^n|=8gW=1V1$B`aX`|q5{`=*k-bOIzS8J8vcI;WhHIjZ-|cp3eIoJw%q zKp8^E8k@tQDSwFDx0TK^oI)KgnPAVl?#N9n-=wj`=26a)E-8)OL8<2=5s8dDKP$^T(|f1f1q#;s{xLQN@}1PQl>#c=5_5=OnVCOKMyD zu-DxPsHZ3PrmpO2efe;$P|Bn*=B#N7TE8m6hrn1sq&Wr%4>y+zk)gr6*|-G?0iZ%c zwU|KgKu%P+ZdxMvy(tq^h*DXgF{Sgy+l-I5<$3&A%+dBj4OTvp8dX=}QSqGYwS}kZ zKlDI*PZ$+Lq0s-3nxqv?TiUkl=ycJ%-Xog@%M%u^U?Im!rB!4@ONSvWOOzjEd9h`ker;N{UKZ~FP#gl30rp)4sqp4dXzop&2U>WaBqz_!_l%y% zcO`$|_#Y@)8|SvCKonI%Q5nwS)X(@@&5pHN7W8$i3KIU(biS=(-J$Y8(6jl~T!}U< zM+y)Jw0c<6-P^NkRyhecSqgA&JEq%9R%ni;57jRIbbZYgwfkv|&U+tr*75c#{_nqR zR(8YM!y0z#qFCDD{j)K~~A&dSMge z!{QtY8aKu_Gh(0kHS8pec9&k6unwn9libAq)sR^0O#v(1Z7_WIQ`eK5<8Em6xec4GD4!V7-t# z!w3@bC7nt-uE0nZ#{jUpSAMl=H|&F?nUstboTd0=17*cYr8hl+zym-m0?S61RycFc z5;%X_4~b9ek6)iy{Jxl(I>}g{Xd=g)7~muI^u>5~r_Le~*AK{x^|jV~f`NoIuFjj^ zVm*OPwfL6%1uq!T002MCx6Ii=ld9>M4(zYJ-2Qj*a_eSDTHWD5)y^<8`^P{%oRs&cJlm=Ms*_cTdZWn3M zLUx5nqmb9eu0;qmzipAH6-M1fN}{Mx!V@l`R9B>n0#q0ncMGYM&t)DM%+NR*_($P1 zAL_CMQo1Y3R2h=Mbl;Dhz&1XHn|wWeDcCy!-ji6hJ($ZJpz4++Ul|!I5MNiRqP`s* zsbQoW8oR1jhAP)?1luY91u6B-1m|IM3nwPE66}Sy0NHaU$r95Oz%aB&5oUhr&{8pZ zB!Is%NxXc#x)TrY6)mBQV=@+S{Jl`Z?hDnWLZjO`p8ah*ZBh6h(ekY%$)=)pV+2Ti zU>SJkST2Kw8#7ksgp+{$M?HzP#uOG>9xXK3$YYMapuKDIRi{%fU*i&GbA6iwYSslo zvcM2SN@EleP0RoG==qUPVfM}bek+E?MT{hWxR3z-Cq0F z`H=0uc5C&}nF^h~cB!g3dGtAohFX05rJ9$B3_(1@~SJR{9FEb zGfHBnp2PhUeBg8JbIj_ZK~f*T-BHJ`d8oJ`NQY+VY-#`IGpFB8ir`;T8ZnfUuR*^M z6L2;)kHj}+?-LL=Yd9{0F90FD&fD+ZdIq$AX3E-7l@fP-ut7284pSIZC07pHj~+4n zy$oV|v~MAoKKCq*?nT+EL%iGGH;sc9FV3xg6u@Pr!69-1n{6b(0wF7Y!J9P~>es-R35Wtl(|J|BBcb#EwSLiR&r%n#)eNEHN7N zo``Ed|NsB#CdpSsb#Vo;`h&4>i~iuUaCCN8uzO@X^nv>Ud>VadUT#XG4{+mjjJiKe#W+Vi(|hbL0MlswCpg z-^koyO@A@dx->Qw`zSgL6R6lxxJwa718V!A3^Xc?{u`pF=f?jN5-GUVVztq=pP}Rj zIH##*P$Gv$+D)Q>4AE2`2dpY20*9Fse(BFbkF4B?^LH~aHcG?Mu)$_*z>dauueQ3& zLye%qXX3!Yao_wA!C!(PtwH6#Rb(s`?E8<;@F=t>`g{3I-}Z6gUTzD70LlyP!in^K zk&!Pjh;A2_g&Css*3Usx!8T4>XfEm*U&7SsmMHdOms8C^Jv}F4g~BqMTd6*7Ony0| zut6S?Po7#;oAuZV3^!yPr#Xc4dtW1kl*wrP)|!ssT>Z9B)W82%wb0EsUi(Ytm5cqd zy4b&R4H&0UbkXG!lVb^&6sSi+pCk)$q115Q6$F^<#NIl}IkxJ>Hi1uW7FLcZ1V5t=;o9aEQv~;$8l?foG+V%f&52&TFnHztJNcsgho6PXK?0 z_&OxRwfRKxZe9#mP;SM*Ds{093P{UPTnxVsE}N>WTL$DJsMq8Z6ZC60r_uBEITXP< z5TBzu-xOUvy5-hGyUBgf!BlNc(q7bXm3lQrV21bjN z7K0+F3~GbQDRaOJ?TG9O6){24MQ7Cp^%bLQMD4IQw^*tW$)9eL9-OV~C~p6AbK^nA zasx+vKHTw9zm$0S0AbP#${^J`5y^f}SyKW3FSHn-;WqT+U)Y-N+CQ`-(j(J-Cb3-B>YYny>L6&`)j3FdSY3_0ht1V{@s8BkE7Y$;kFtu z=UKO1#fPAP-cOM>+P2_de6@&=m5k4Yskg)b{}8MH^eM7xpTMx0&2*occ^mBe(&A%E z75KQfRSJ*!v=Ze^**qtj^Fuw#Gz6lW=P;$_f2q$x1pB-VO$0$eWeRFkf~jD&l%W)l zv~B^~^eEG03lUI~1EGU^C|A{};pjaIXIN)thpxHTn%R`yr~Uqe{+(F6lyliW2C4sV z(jk#S1y>3@S&u*9#B@T9H?tl5m~wmv_+7DKE!3E(yGcM@?-iOVqb201b1w*8NRUE1 z!VjD#j_vLi-Y^vpd0*+N%uiAkhB<4~7FxTXrm}w{*~#1|7ZEqPD*Fv+lHCe>XEW{l zH{*G7iC5K%IQf$q*@7aYlmL$j?H5xh{4$f~hzC2@%p7f+o`yo)oC_4kc=ggXfF^ls z5u~2wdTDl8jGYZ5a!x<$>~8Zw;$+$n>w-`mrgDwQYTUK3>koVvV$ms2l{f?()=f0W z&{^<19YQFjoXIFIxPov}07XE$zkoq@boGBzH%ZZ@p+Sxin^ZXfgNPV-8$9#sVX1zt zy|%9tk<+vcO!F-wqV&das)HTH^2_2rwAehoDu{mzWsfx3TSz;TLrc?C$E+;932}Q? z50{7!1>9340V$qs`=%lIv!B^fcEyzLiK0>tp?@+Ka{Iv21o!8o& zVXbc{RaDHegbi$<(1qiLSw$aCD%}H>l^mpf&I1(^n+noz+3zAQf?O}_u3_OKM=q%# zZ%KP1Qy!vaPcn1%Y|jJhviOL9d?fU2bG7&h>yq&i0yB%pvc!x{bEd=8mYsu;6q-b= zodz>KV}~)uOvvP*9&`Maf)|~bTTA|_CYk%?1_`rJ2MIwQ5!g-0aV;C3A2X=Q1(qyl zh7b#)Sm!9Jg9XsVu4<}_2$Za#uwn|##chImde!P>7IM#lz;ae>?EkOjic3oYu$=6PUMhS|YGeTqj zlmg&hA;#_w6gn`XtD^*opJK&DVjE^AU$EAor*l#0Ymz>B*0(l<`BVAoATtM`g*p8f zY-As%#^)x*7N0{ltDy|Dnp!J$<9qT#rO0tn=|&+5&;fT3?nqHF7l8Dq939v7eUT;- z^4H25zX24z3_Vl3clyRfV&&iO1nMP@>QE8mz9oy2&*9v})ho}jRPu5wcZY7qC6`GI z`|zmQX5zZAoi&+ZpvuPfd~t6YM4*F`wKIn$@r$m&mx*KmwUl0%%D(T=dS;iR0B7jg zq@9=l=p81tb)w3;+S{QaWb-&jPGF)e3uc716bx&{wn?9Vi)M*&?T|h;Bi4UDax*ya^)jh2}=YrPv)@kRZK-_D(IaD$Bj|^ZuD0Jd|CvHiuQ{KICYMV+f( zC~~f%QxQRzP*vT7((U|H>+HccDa~4nT+eAdqi_dkL6}1Kp_2Q*bT3MaQ5ZDwiCk>O z$L)YuxSVhAN1JSkCnR{hb?zn?l*66KnzJjizfep!G?Ed3L}#apz-wYuNLW-^KI*2) zIWDZ`2h-?|`@eKwW3;S`S4)U_b-)nvyH|31TRsb$QIE#~_lsA(G6q{MYciE|y z^7TS8%BppYg!hPvav}A>%5pn?Q|py$4}a#B2<4rkz6)WL_i^Ih&s*zaG~qS!xl7WY zwp6J;|#sC0Q_2+ML*IKiQ_JWg?o6*3N&VDX~m#b;)y53x* zpi*CSECucx5&0nb7Z~GuEEFbefyKtVh+g@*{V(3B)IujE$Y>d4svik*!CYKmw>jyR z|B0xZ38iirv?I2KJ7w%xg??e#84%_4U!GCB6;i~NBhf+IlyHy+-5Z+pm4npb_abIM zN3Io!llo3ZLH2Uk5g32d(53jqZiwt=Jj0^0KE z>Hh&a5nDj?dHeMW;q5-f9f&Q3wrj=Y(+7XE;qZ+}vUat6FJh15d)1O_FP0D=)q1Ey z9CcjMx(_GsTptqBpe@T!Z}+Fuqp+xMpHJ>63KJ;AkAQ8ci^9R#sWX4p+*05 z_3VA5L1KDk7-GW3(l9bH^6B4yH5SnUIXA?eBif5)&;(go#CAiV+qkgO|RoNy8(pijqw1v?(M$YiiiM*7+e#ulg63 zPC9jeZYy>;(wg*R9ry6S&!lI!v{)PNs99~cM~g`7bHgKoXSlE7H)~O-3nf|%pcyAB zN15Cde(%}U2H|WJiDPZw(IyKG&^(YM&Utj#&N4uW{;Nvhf=~TonF&CaNvZe{ zICN&rg0!Lw_#iL#<-Jur3#lTLMcS5DT|4mHDI!04x`63%jjYUmPh}z9v_=tDVB()} zbtsfACR{ttcnZFk(H9~CN5Zi=2m4MoJY8bztb|X0QfKMF`X{w9Qq7F%_rZk`ROG#{ zxQ>^_7wW6gptaib09>IQs*$L7_|X4}*z4-VNoM`P2`SS@ZPL-WB%Sb6)P(tzTx_uY(SBprCx!pQQ`r_^&lY@#=%NfT@71BK>&?PtXmtn1Sl$yfz-6?E~nTsj{u4*@&Xv-pzno3=JKVgR{ z52j34G-zf(4IHKa9ft>%pJt=I%>Y63C7-x|A9`|eaX+gs;4T2(HhW@8QgV05P)jZ; zfbv}YzL|U|pa$A*pJH&ih62V~6>oxRA|Ti5FoaNR#x7LW-M2WCy_g2+PkPwDL|`IG z>(SL)#gQY+$~l4G@OB06g=bE|U}n!u`VjM(-C~GjS=7)R53m(9b)#&+U0pg3(>6|R z;By5AowsK$T7h$ju6|!mW8LlkZAh4S38PMid%)vq<5b|uC>AJ4*VuruTmW9>!}wd- zqj^vAes%NytZr5x^*=Q3sJYEm8E-6yXI#v^=yqg|g)?ijI(ADfK0-HmjE^G80qbLC z4j_GsmBa=41xa9%FB3Vxx3q@ZU={TH?G^vCrHpB0=s03wg<4W58qJHVE^>H1@Fv;a z_@GmXy>?8Vn!R1bm(w!JHcTntZuQ@3)}&$pcm(pWVT9-TROPp5mc6|R?{U?X`~C*g zLnhE5+XQymDgkh@^wce)YN~MU1k_}BdbEw6l0sy;z)l`0D-8y~DcUd|KIu~cG0*u$ zW0lKc2Ek?k;@rUA zKSQh^U>WrZe#TZU$B3A}36_&^#Aw?Fp*Di8#I}L$U^IS7{5R_C%w(b{UCSM_wUzi3 zX-3(o?e3^eK>bGeTkXq0nrVs!AgI=sR*1-ek(RJa4!pbQ4I7}Qb*yfmTzH!dhwn+? zb2<0jTIrOATLbzspqiEsgIaYfJ2|J1A4k7Ws!nma;N?d@b42NDn>NeaKcAv?{B zR+i_ArvH*^KuxR0libiUpwqGp!pcYl?NV1^qpS*&vn2Eb)2ohv;ld{`$2Ue?v705G z2ppjy_w-~^mr^5|y%{033D1o?m}(ygJ-AaJ5II;yEbm(Kexv))5}8eq;pM&^psx2yU zf`OX-3*5J^8!Vb)64A}S!Nbh_GZdcQOHNtu`84Y-y*U;vrm&ILKAkdltXg+|_R#es z53iprJD-Q7de?2Ms(>8G*4^D+bo z$9^8x?%Hx#)H+nlef~A9AGu&B5>@j2>n(k7+KnpFx<4vI4{TZ3-jX^2y6Wfil2)HG zT`p(a6NrakR5hUX0OQw#^x+!b{thcCyOk;%S_drw@9IYkU7Uaa|MYVcOCT$|&k`s$ znXp6?d{9H(=_i`Fii;!g5yo#wApLMYeh*pXjN`grSbGUZqVne-?$)3TSoHl)cM#de z6;rj=w;t|#HMlcS%2q&t-Ma>fWFpT+4Y&DSBJ{NdV9>=zi#ujW*x35WflR$)mFMwmOWpf?yo*mK zH4uB*V7#l=-R55ku3wBejc@(%DJFX|V^>F4&N%&Mv4zb$^YQ`}FGcfqswri^ivslgY1w8&y5Cc0=Ptc=W0hm9 z8i5|0jc=Pyg{3;oDKw7d7jjRwzmYO74;-l1w0Z(gA+&E?ocP~5Mr)7y#kY0%JqOnpij?Ton?2UV zx5w16bjVk6YIh@lF?pItCaJ{{J61y=C(9s(7szT$>^~h9X2{K{9UR<*Y<-zSJ+8n} z`MOd@O)eNoB(CH~wjHOJzZTs#*r`&EFQY&3RQ zqFnCO-}}fu-H*fKVI)=PsrkeM%SwJwG=(m<>Vd>tR1k#UEgmT*Jc%^Ea71B_X7{l} zfBP?x0}4V0vYU;LRNH|8m7?xL^9w3jbvT~77wT3U&)fy&Qd*xN--)0JB;;mTTbYoY z3wLgI{Nb8E-Pqw)np_!jTu${M9UtJW1$eu~P5d71{~>lN{3H;Mi(& z%23qqzCZ;Yg2Lu&|No^V9~o?-|3?-0Mg56L1yh)A?xDa;EygAyo

    8vegmJqor$b z{PIgpXPciBItyqj)HU8Xw+S7x>s3`NJ0)tjAs-6Ys`j6_82)EIkchl&x?(i zR0@QGVCYZnN%jQCY8Ons>FNEL&mnt26yOPc!0@wst`*=j=!R{CurO|9V$vASq#!T< z{3?gc&x)51@{X{h4AB4H#;RDx|2c{?68}=Bq4}HQ&?F33YT4;wsq2MlH)j+;NHHcQ z++QZP{lzqb2p$2iDc7Z~wpnKxIusv>?rKKg~Z3Q?)%Hpd^yLB$Q}J0Z4zBiV8yP zxy9jwksh)}ZR;!k8#%Y>Viw?4oIWvyH*+`^Gsj~mZKC{2(czh#cMDMe{?gA&|LP#G z|NRlgMV7+XmbcULvb(_gV`AM;DRwS;K9QxIybNKtqTwCU0q&#a zefx@VO(jQ!`d=GvQh3_oaduY!_q1?hUsQMX)Wymvs!F62G1!K%W6_U*iFqlX+tk`c z$|m&PfP;cwsqO?!|Nfr_l1e}-=Vo|7Itt?su6sZXYWrF05Wu=eRmO0i$ItFlryrIL ziD?J*wA2)NF8^`&K}^@JvVDNAeYc_dQ`v8e4F8FCRYZEb)e-H(udBGbreN&L6@)#m z@nB8Z(WTN&3WH|$ul;cIVyPCPMY1mn$CU@mkvgo{zH=hA4dq(9^V^^qRuuXS^cQ@KBK3yUK_PEa4p^?oaj z_#!hLZ65Lnr7+Ezu79dtkZIS~uV0asYTy2nmN8wAqC7&TsG!}~UsI5sc;Vwjy5Y z4_xhZy#D714J7oq!Az=h`k`bSyTWzDqg+u6ue{w+9_u3(nQr_8anza0Uq=m=?j236 z3i47PS+*N5NaUx3K#{v6=pSW`t`Gkt%yJ3sno2$Rnq}_SbOs^6^Ag`vt1PBAbU(+q zZ2M1Rsh2sOu*jt^KL67`OmPg5h&?Ap>pR0%Ghpo2tuaFiP}-_;KsC*E*k2n~F`>)jE>Zk}5s z?$5>*4u6#eyZ9Ct?Tr{uF$Rc^LikbV@qPX$H^ytPieaET*F?%YoqddJZ)GhGFB;^# zwe!;KE^Z&H$nioPm3hTCHLZMTVA0;rTkno#kx>QN2ICBL_gGOz1E~HrhP(%VPw3gh8 zZmRdX37!islJ|sha=sw}wj8ucckKtRN3?LEBPgWr?Tn=;P2oYF%!2NWup8b<6suYc zTjh4vOFy*T&dDq^9+vGbw5*O9KaziwmHVEctto)D5Z0Rqf`YMK7nCNBLsEhkvGxHZ zTlRl5I1!a3_^g#&1SP6`MD7UIXxG$0DsTN{01`>Am6+;9$X1&k|6;Ut`POJa4n8P{ zI@D}q-Bc{3AC-~PiL9;yody``Ub4`kw=H=_L-4Ht3oevEJN$+`5(2V3#OS|6U;f?f zUK}T#BEp$Q+E1*w&dixU3vV-a!iYV{KiF(hWJ{OizEq>z1vZF~#&5(^#3lv(4c7nM zF!s)kPS;FbN~?IOMo~cH6B7Tis5Sl4v3C2XsP$^#8Waa?*{e9GE#D5xDfpAH7UPdn z#FCctEv%pw{+g?`+Or2qX(qp@+|_xBKn7fu{C^nz21~z7MU17P8_VvJemFak1vjS& z$Zp`HpJlSj5gufhI(M?KN#5LjRLtM0-{a~N^z;uuw3MTRNr zh>k;0NJFDBQ2X^3z!YmS3&Da${elm+q{}WnlF&N-aeyyjnW@z4qC7P&5pM*yLz`TW zqK=^QVke}$(oEzOX20L6E;U3)rHViBFb3~|-_OaG(p=h%TZP_c7=(x@zqtuq&BLw=kncw8 zs(C2=k%${|p`bnLbZ)@W;61PAG=Z1LeVTWPZt)6P7HpOMuHz*b_UhPHTQp4XE_3Ia zuuK(AB#_V!Me*AVe%G(wD?=Nx+EVzj#e&%MpJ*>KmX=mGE&Y7!vZ=7Q&A7`uWvRj8 zUWi7e`K^^pRv{7Uz9EpP>{MnTart8LjE=}%bb@nS(HN3gA;QKn44mgFGN(X5v!KUP zeUI->)E5_|Ed@q&)CY^#GpbGg<^Qu_>SY|kAG7{XCixVUxFOMwoR!pF2St3dM)9%X z-qkUVLy$46nffkKFinT?Jjqo_n`A|YPU_LtiJnfJ*Z*wkpY!-}5F`Cc_l+@yJXBY@ zHUIzh&p-eBp3;&m^Gr=_vR!AohijP-zI!6y7<&JYYnfH3s4cwIBm|dg0F+?_97w;~ z-~aqLfBqMN9*?UEUR;#KdDo&n9U9KT)MSd9n%k0+HB^6gkdRgc7{z`=vAx(qt+06C zOq#Aj8ut`i=8OafTC%eKVqE>u2|0t`aK2QizMVpcR?oT9mqiJn6z1y6fsI$~G4hUB zN;(_q3G0R9qdj~9T+FUY;vN@Bz~$jMVdWAK<2-FbohsvBe!qZlunt5Hs*n(1_d$)} znjRKLaFUHZ-b?*X64xGx=C_?%@GUk-1McR*_d$~y;gI9^y3S@f`YfW+B7?$bYQy%B zaTE8u!w2=UB4`x=dGMKUH?nnoAIqdGhMIjp`upK=&-EMWi0^~7I=ors6 zz1cu8*K+rDfuIkd5t&SfvR@lYL-xfP+f5JPUa2M#%K=GWRMXwT+oo|%AT=6l{# z6QR#p1R#D>xW?@Uy1Ww0hfT7HpmTe*`XDu8I-cOWb!)n`{|a_Rxhr7WoJ@Y={8!Vk z*pEnmD+!9=`df5j(zkLiV_9!erEnwO>Us~n>2%YoVKZGGi%%+fp$v&Oiak77-1l&Z zlgNL;>boBI$I3?q9 zXq*;x(uf=U;gzHkZoYKI^Kn}2>*pxvAwqJVH8p)znCCvGo^uPnb;@uo93 z!u|G%ZTOLKkB4EB33nFa`O=wJtn*tA?%@au?=4T|w3uTpD@^C1;1|@qG=}Gy_``{O zzC@`C;deHQUSBy~JVR<>&AyR%r^tME*|KB*J_(beMj7bdSK=y#Hg?d5c(gPab@?Q} zKi;GU;~nrgv}2E#rh(pnfmJ;KR{D+FxTA!e)@UMxft)YE_2s-i-aE6a@X*5A_2(0v zApl2yB(RKDc4;>J9dwwq8Tq_hwdOOmDU?#f_k@)scg6r~eIvKuk{>w6eERp{_^(b{ zo2&zfx-^lpiy?V>(cLq4T052e=`=QL`^CV&53}tIB&E{`Kb_Taavf9i>fb_WuKvX4 z{Hg_$@`RGC4v0{437K7De7crrQA$1*+W@LwiN3vywuKa7hw^ep)^Gc6A%#xN>1bZ( z`5e_*+3*A|DN#w+33tj;o@~dbNsfCGq>u9Eg$j4UJOiccHx3K=xz0r4p9!_tEqJ0o zjz|w~O44r1LXmNWDQ3#ye!lwuy3GUZHZqdpY);uVn=FCkU$H&GFb z8n=%|ao}0(6Ep8Fn7l^_x}cAc=30v^sqx_^!AgLvah~0B@H%7#j3!CO=j-6HumF&~ zMw#*J5X!p!RowL)*8S>WrN|3-5h(b?M5*n^7ab9}T4W6KuaJE3&ET#BP#JyHDg5<$-5q{$j&LOQc25n48yx|m7 zxzjJ+N0g+P0Dk@^&dVUg`R#uiQ)6XNqWhFajoOEyU&=mH=bs@9+f5KR4#%2)BSDjY z(^y}|GbvDoEsjj_KPLLVwE~m)+I&K&8@%^y$>SzLR@zYKP6#Rx>{mN6oogDVq#NiO ztKId&BC0Bal;nFG;8T7K&P}6oX=Z-DzKpE#7zXALw3>482FCNX>_VAHzsi7+!HI+puWOgl{OIKkpBQWWTSTe9*f72NbzRO!yM{>9KK zj&A@h1cciP&!fYfuws9C8diWg>R&+tM^QadqyTF$w-fv9+eM-MP*<{APG^){4*#K3aKpt4gj1aomI{D7`hbAWGi&>c?XZRJt-hcc@EXoz5pskqou?O>;3u zF(~|&on}A3ycsKA^6i$Et;t5k21k8{9(hm%7Xd9QI1Z)TU%1)WHOo%&TIz>^O=giE z4Q5vO0{2Voaa5qu%pzNz1#Q#G(1`A$o{(wpv3g^Q!7;(Ug~C~ok4^I{MRt!cr$_Qi z#kYOJd+C2E#n(<`oQX!~Wnjg?AOZq2Z}kdp!zux}eUA+j-DL}*R%z+Xa2OTzB6Uk= z*X-G)PO|X*D{AA)Fwj07A(hnhl2PcF1*CRZ6Ry2CczB(mBt%^6tBt<^l$Ygj;fi6aGW% z4bL(|_gFm|uhq1o^Z6}g>${xFgOQrZQZv92-AB;(>_y>?Lnf9ad;5f@(aZHKyKfC# zz}e)kPP&&Vs21*nZSuf8|0=ZW7#MQ|TF5ab*?!}WbIlQck$4HEHb2w%;)_SD9r7_O zT4W4A*WIusgy6dnfR#~qpPW&!I()29*J(Q@z>hvTCAGGgETjdMl@1JvZNiwwfOY6e#50b@+`riGme;drgqZg|K zed9MzL|inu|JH#w#|daM_oLB+voe_;Fft$`{HRV$R;oPHV-w=_is&e~KB$<7y~as! z9zsw+-$ZiK5Mwaa8*9!rK-ZG0yC2(#+FePht!Q7Q8n&(;hfUg-Y{i9s*&B^lgi#w0 zbc`F*{R**}=av@meAM_?`xlw^rw(E2HH`nSUHRrf9{9z>eRpV`CGh;*1#k~wl-L#@ z0W?~7Fyb$-@K<|FluVoqFu^Morq5dce)By(W{=ERvwGG9crG+3D=sxHZz)5mUczt3G= z7g7~`yW^`EZAh<}n{JzsQeT$gG^J~XN@E`UsnUYOypW&44O2vhB?F-nu&U$;(mV#O zxOb7>4RPNVvg{N0AH6tPHt>n`c9uAM&KTZ-@Bqd-Urn_U4ITDlx-CCMS{G#RzUSuI8>wVxOMkm=hb@rtNEGw&3GG$ad z$EU<`^1e?~mh$Z>?;^8sq&=BZK)v+5m-!f|M+i_J^JI!cW?%>1G4PBDSd?)5Fua^F|#4oMp&O7pGb-8DZZJrW5X0A@~ z0wy$lK(axnMkkCiQT#W|N17=U!Yp@4{1j*H$H*~Fq@`j4iA6~45~{d(ZHE4W`*bi; zyaLb%;@NnsfI6#+aMSwX8Y!Ca^Sp`!V13{8B*A|>fVusq+})E7CV~LLKeEnMQ<&}> z6AQ+QOhz$aAnMSCsj1bir51bVD=Ny4RG~@z@*u=Xi@#LsgxgS!dmde7RAW(DS+|;- zp1%E2sAwK2QV@Dbpxo0QO1*ls#~ifX%s{8Qtczw!NM7!J(a%Xq>PC0u#_=0rAvYLy zBZ^m|zZNz5pRagu9iOyoyow@jsgIr68)?RAnEmL}_ysHhm8zfl)d!y--s)u1(pNMp zi~;bLfkyHd z;?g+N`AAO*MCRkueRR{~+RcMmI}d}k=-tbLo#Q6muLDhNg{m0rr~u_FiZVqOf#!A% z%_nyQXw)!jOq}Br5+N;(z|GWQUF)F8h}Zk`IyaNnJ%V~V%UVGbRwht-o(79(+T|9c zN|$8Of+Q{Di}m}V0j_rssqcq`r_3M z|ASjseg1#=(0|1Qud&Z-*iMvrUUlLv*q5hMo1B^aQ+vcS$&PwMwNnN2qOMzez^UBT zSFb(b-$S-~nPY;OHDRaSF>E9p=LZ!hN##v@%()*xC|41_|7WY%=34zjgf?OyR9I8VqYf+pXliK*eu=``KM z0*ok!P-sY81L2pL|CkAHV8oU!6Mb>Nm)`RD%sbhpIr zR>PhWGYNrzPM!Qu!P7-+bSCmCuoIldi1WZ7?z#mN(bMUqM_@K_z*oP@8*9pnWz_o* z&8`i3&kmy_UxF?+O|0G0wTcV+LpYkJwVZk}h9A+tKy4PB+Vmb#CAnIfale68;o=>p zown@snMCwmJ?s^DJI&;ERJc>a+Rlj%0|Yx|C?cb_*6R`$@~d2;krG<0*FN=aYooi7 z^#`(KtOkqjIV}^miu-JD_!?5ydb-AKmnS?y;bQ*TDyW3@#a0T!UR+*7w<%#_* zLYXEMeQs zUwIb^!jx6_aLwUtP3ELN2Mx~P$S5g+XuTkP3JDYUu;tY)R@KzVB2wfzsjDS_oSv?0 zH$wNa{h*!2{n9?j!Yos?>xMyuIw)ZONJPi7M^eA`dZ=Fh9^L{cfUGp6Tj} zsABeksYVBBsZ_ejBy&iG)W6?=tw~M`caqJ1>jg-Cbe)bo79p%=0&*NbGlvRhiyJ7Q zsJDRu)|k&7hQkck_w>o|{-dXpl0T4}eiul{{7oUc?DRjyiX(4GE$p&vW2ayvvcToW zos8rzK3VCB3o0O=(pp*RaauEFrGvUk(vmb*W0x7Qiuxz?;^odvqq`|NU3E9S&@FwIUgdLAgYZv#e#j&l8Fb z0&M+tZglJhPojwB$CB^;ITiOlaPiNOTweu8KF}ng4_|=Z>?BKoNa6*{`dSt>?QJXL;5b<6W$^kl8D2V zMoGlCo5+X^+9!85!QZ=B;?``ZcDX(5{5nR+v6D4TWGM>xoE5~g6zjmsjg7maZ%!~< zM2de0#qT>m)zsVdULXk`sf^svCj0+uMz>CrW9*vXE|6(Nr~(R|*JrWhu9SAEF4Ry{ ziX4>U&()_?fKoT_lThoRGb%%lbhKV-J~EU_2g{wg8&Z{fxobYJg~in(*x}CU7_q`7 zQIiI)qsAkjt_S;Z*geAiCK4C?Qzz_cY1Exz5Y@Y14I<__xF7-4y+<0OVqPP-RDcY+ zR4VFf`qp2`H33f{po9PlFJh{$T@L=Sm(sZDNDPI~jTD?n7DrUd&fgCf7q&H!p1OS` zA~>!KaGHR@E$|o%1AL8Nl+Tu?vftsyf}d`$T<ydkt~$xzFbrDK^e!617C-^xCeCH7A#fnojOK4 zXovaJSXyaV3p=G@mmRQUeQpV+*^-g>$VDtoS#!8RbW*E(2nqpsYb_BHt4Hw)wD?D` z(iy~X#JWCtSGyTsVPJ&C+SIPrB2CYF(GCh9gZEkAAE6X703%R#l)vbSHSt5Qz^^Kik-fT`(ec6Y`f69Vjxd|2F4Mi3r^08pikjvbzG$kqt`dnAQ%u2@!6N z)M~keV>^=Xk=N+**p0rCAJ@7w65Gn% zW$fZvY#kH&no7_ER?>++U12fdncg?8JUbqal@p-59>=_19+zlt19z!8s)p1{GuUzs zEXJoHJ8`AnO)xeUMwi({_&aE;Wlob6>rf$NfaoXQMO!wL&Mu+`_fT|0`PTn-yTCpv zg}-d)SgxdAH!RTc;Iv|q+lmlgwe`Je&XoA(rSG!;{c>yfvK9XQYHGF?9OQY~p|P|U z;GS$y^*Z*D4OQH*aBpVuibo47ZXn)sI!)NXj-wghb~XEVf*#)MFDzpM!6g((awD55 zl~@1&!;G+7-rkNVC)?qjsQ|-m_Al|CE+)IW=B<*G|4kmi0AYcg-%?t^qfdktU`UXu ztC;ajaLg%p|KeP7w#vX~9HWXa*|}1TFDdG`JilA~xwF*T&9W-2^Lk~n7?ZaU?&Xh> zUs!wQV+z;!01@oq!7lz>A?k=3MY;J?G#IT%>)$dCWD2!s;Cat8+4;B6=Hv58q*z8h z$vt)vvrE)I2sLHUR{;WWHZvku_u>^R(|`Z}cVAp1Bl%F$AwF~hQq#j5hsB|neve`n zfUJ%LD9)VGJB|IZ?RA(Kf!~hP1MS_k4Ne5@pq)xrxEhMjjGsl*f?4B1&|`ia z6|fhjtNj^eeGGN~oTwq=w@<_=u?h8j^QK;cxPA}^kX5dbWykVET!wZgUv&_-R8_g1 zD#$e=srk*v81L@}Q5nk6S;~!R@B=Qzljo`;yqy0G;8@D!?~nm)iMw|?Q=pSh;5o?@xTPL~ z90bcLs`U=2Rah@t1zL$+b??pO>h;8(YU6`ZX+0DttW8@l$p7ypv?zRu7dJwE_ztb; z%kE|U9%*d+-DhO=ca^*x{f${Sr<@NKm`tXXr#rks{eO!)W0}RwQhg}5p$5=`L$CL@(_KH|qUJx{2S937vA=`2>sO{O{mk*r~a@F#gWtD=s@ zh%#Z>zq);rX;>dt$|IZp<|_>oHbdCCC}j|)rE8Vk0Y(dk?mMv67(0Bp5Er3eT`Y>f zz@~G>%9*3T_~MGgsGTx*e@H2IVl!s|0NyR2$Ne*&=@qTBK;^_I^pu}v&HK!FtxWws z^o4`q#VldjPLCFWURJ`>%pINEx8T9mQzG%)SP+YNhn|BO1mi1Y9PmEy#7Q)C-S43q zzwy@5j{#WdFmtBT(Uv((_a1Fs_rcqZO4Os)Bv6%nZ#q%-$jSaw^OL`-E}Eb+L=b>i zVsI6sPKXTwd-P@g&HLg4VY@H0BZf+!$`VO268+tOBn+yOMJAnW$S2?pb+`r!=Omp3v^?a+z2h;2RW&JCkunF6jRZhTUfxpww zQV$lT{I(`~$QQOh@-nxiq?R%W|&#K zfiiP33Tk42yH0hz~2_C`%?EXy_O%NtuD)-DCxq)&F)D)AACDo zTJbnhJf^Tb4DS+N7;^8L3P?%4S2d;i(LDY=p`Otac0itQjqbc~KY>8fiNSYXl}v%g zPvW)_L!t%!GjmQ*;7i6iQ75T7_9+=P;IgFcEj{bwY#%j+Lz6~fbm&jZ@VQIpM9%;0 zuHWRJi!8kvxUQ+hPb|;#{ewq4VjW^ zPXKL9SE7A8C0unzw)QbZ&<(y(%puPr*`MQ#H?S{iaFzX5p!vu3`C>S~5{K3GS(5l< z>tRCl$(b)O{%$oCRX#WL53uO$M{N(@bi7zycoWx6?q|P^lJD2;B|XQP2^pW)ci!9w zl@@wX-ga+Z^YS1Z6{L`OG(fdo!!)a|--bTaYikRC#)X<-RsW~5X(+sM@unq9z-k={ zQS$mkz)d?_gHZe}LIWKf4{-DaEv3zDo-EbX)^ri!1!9F6o^D*V+z$7AY7)!Jf>vtW zsGMwbqsNY&^o-|2U-FaHohqw?f?J%o%}&-qwMiDNGrp@_o*hi`xh&)z%h{5eW!n&2 zTVO}38aQJIcsouihhCRdXxmM@fANeJ;p;L&%eo6=aIWa^Y06TH2`SS@!qZkdV1*meWx3g6}oU(i2>bXrellm+k7MYnhWnMo(= zlCwX02r1ZFwY;gLSAYL@AsT;QU;|)NaQvxxi|&CD!W2Fmp<+--NOG^O`%$}}Zh=NU zN+8&--xJbcEWMDUMrsP)i0S1B3$IEc=RK6eRSVl2ud}21JxZ!cGEw#r%&886s!_`NypI_Ev zmQTJ8{Q9xU4Js)ARSNB&l0FE;rBk0#-%c5$;3)#te}ws*J4K)NIXq`^LqsXyEIHbez_{Icx@TSzr& zIFu2yJ}=~LkXHPt9aa$ArgymUuN1rcGk@t#dVYnW6k5+tCprH75SFe;eq|$mi1V9E z*8l6J**>oX;#8CH8h3F|8be!8t-F^K%1i$wq%2Iq8{C}EqWQtk3u|vO(~_kDe1vwV znGH{9UydkBeX6{6x#&fze#izN?rQzcD(aBSmNKVK`jqEu#ReDm7ffIOu-FDE6X0Hx zdS7;0ctuzEG(wN{-bCaKtJz+D2>f$AUjj1`(ku0or(m3TW(E&>Bi_$rH&U1%9lC@72sZ|dryGrmHS_W>D2psdJvvW_wh_x&jXY(R|wn znK0=l8VaEPrOu=5#;F%@<1lL^Tj-F0a^$6$0}_?NKq4c z70;bLf@*qt7AUd)NV-AU;)DF>9ru5>{(pfH| zgg^T*sDACbu&uZa{ggpopA$9(*My4Ch)P*DZ$CsxRU?aKk74&npHwd8-8KcJ`^~?twWXh^5wNn|jt;WM+$bs!R{r|{5Xi_Z+sWaWso@2h!nobfo9u3& zzS&m0bU+hVD(JXM=97;k>>}_M#td{M;Qez2WjF?E?8^Ie>4m=jx zD0|w#SsN}Xvi~T_DeCg9?+RGt;;WDU@=c4g;hi@ZvRb5WrbgJhP_WubY{uJzU5p|r zBaL!6-&ev)=QE4=I>(Itv2c)ySUYyWb*J+&^irQO3Ym&ep_kN1c;eO`rL|fM_JTc! z=Sbfbt`4rD?0s)Dleh|mb%8X+A7^~WMU8x$EonKr;o~?yBP$%kG@}@0j~oJ#<^ym& zW3$@{ykUsYajLxTsqJzht}jhUtV6iHe?N>(mG~6tM#U0j<}?qf#Yr0F z{Vf&m5`J}Hh*@)LAI1@IlyaN`Ot86UMpW3wc{@Wi$m=FU6_rw=+nCOd5C4GfdpmRD zNc-L(g;FAfTJ^*t%PIx8u=;$)QZT@j?_}t7t(20W#Gd8(vQIErk9hzxK+V6QLZ0eX zG=);~_U>fOIreHqV~7@g!Sgxy5bAwON&LtE5d=jQ^gJ0O_(wlAL+B@Bc&gNUa=4VH z4Y%v-xBp8{V`iygDs36C1s7pcU%q|5YsH;L*mqy{87-#gZE zoVna@$)Igj`X@FOkdaIZj9?-jyFtB#S zRq^4ZiG6+Zbl0@t&wDAdH9ZH$r&4~DtEAtp#}BI@F~kQwD8DZAQeS1l%>M!;QZs|T^Iy=)>w? zv$>*#A@N$I8LQgM$}Xy0iNR}p1W`Vp+k>0KkV5H<;z-<4xo60UBKJlEIcLjsZ$Nl) zi2G_)$cu;?quus!WS?*&#q$@xTOnBagLWmtfjh@V5SNMRWcEv)gZ3f+w~>Jr$19O6 z$Ntf})usx<_@)YYl!ntYm8*$!?{2}~>*1ivhIb+a=p^?HcRPEh`DeU!Uzyyz+HJ7k80Lotc9)7QtHtdxUE*h9a7Pp*kKTGTEze#E6L zm~D_p_A=49P7Hd!g(62}*y)OSEY^(q+G1C}4RTfjkMqg_)+DeiQMuo`w!5MZ=?I!t zqM0kB_y6oWVO1OxO>1q=7@^C30@$mDOR4}gaBcqYBoq8HRd-HWB@siAI@}%h9a=|3 zo*7M*MKJC*xPLi&9Vah!B@nGyUsv(aVbMu1_`Zs#TKY*e;|c-|`N>Lnym}5uk%AQJU=R?8{1F(1^9G5|Bl5o3_UHciph+6k(X&cj7HSl zVg-^iE^@2ONyE(9Z=kGFj*pF~D^d)a>t^+vH-|je->sS4=={_Z({dh@+!NAfgpx2ms8FmA9S&mfGV8I2 zGMTN(;B}qxAy%VaV)<#UL3zO+8jh>45e-q!dVXB2hs)hOIQ=Kjh>cylyUU7(e9dC8 zYn(Z+7?-$EvEP$*k%!*!UnExN4NhUe`_=Q7;d(eSTS>6JCME{(K*Y{+J)v4 z1J%9M_?m14G#el@FzZhfCx{qYBQsHBbRthQIV^5n-#3z1&A^?1g6K)4Q&l|aIQ?=? zhM5{e*9HI%}c1R4O;E|((p#9^PbE`bE5WSsH=`6npOrJ8=F0eivnyF&_2f- zB;Feno0)i* z69|T|iRy*raTOF0@f_dta?CoMemr>qatwR-103@guCl-3x}4AGkH<}>@AvQaq;!%@ zWQ$7iqRmNB+_)S|o{h~wwTQ+&W1ktM87OJm{MMb+4Fz>%qD0(m9AG{oB$1wL>qoQm z95~*7t-6W9eWyF|#+~NXO|Uyy^>z~A`e?J_)WEz5mc)-<<(eMwf}1vgB-1Wt2m?Zo0{cf3QF|rQ zBHJ&y2lmBj%&qHlHg*}HVF9s+XLfW7snuYPw+&B}aZMLiY-N7q0V#O1Fr9YZ);Gb_ z$B%@pH4y3(0%nk>S6IGV+u488B7GQ z&;_%|O_TR71YYE}3+f2<;i3fD)ffN&{_F0LZ;ZuolgsKYRK`F7oC+8~`$LJ_!I&y) z#ilT^hVYunNxqdv#2wG1W%V z**+9+R=#VUOGPX;BSBPO`K~Uz4pdWnY4LZx(bKN?KN zE;bKzE99iH2qPpn91P@6Bzsn}Z$2v@PFXT8LxE5W*&ixi zuGL|H88=XQ0ptvYVVRcv`MRhJRGej^QdYNK2}$nSyP_AvZxt$ifGrU;QZ?22th*?< zZ{@%5%pCb)5BmO@Cp*E&icEVjB zHF)eUWD;F2|4sgYYEOSAAp3t?Dj2#Rmyr`kYT2b}k@K(p$KXwkotN2)f0+5_@ zbRw$cR^x4@`oKjNt#z8AO)z`1QU#$j^7fN=_mfo4MoImV7tQ-X3+D>}jxRRAMyujx z^cDdNjatAkw)N;}{nb9{Q}gmegC9q(Bc%t*5PX8I4IHUUVoytm7-~hKH8+qWpeE0e z>>EKFoTty;1HEB=g#`rM-hNL6l!U#ba2rKI7Qu$to5qiTHJd?TH& zB2u#eaNg-1vT9uH1-1>_N$~k?phj`man9vQp>3y@7K?`bQPvNyM_R&9DmA0Hs$rk0 zjtNgixfRynhN z+KgteA@4c!Qz++dHSBT0POI)W4JnjJ??W-Qfg38_nJE>WA_{?5srH?YS>J{MfaTeV zN5!L!Ffye-&Hrf6HEHovjmJj1V&ypk*lAppq%=D zX3A`!i~vctiHG}YZ5Kei6!7y4tNR5}?J}yUF3j0!yy|@Nn3b9u>6gyZcs4N82s(-5W^ppKq`$48eL0v!YePl8cqE`REo9X zwp-ZM{1EKLWX`y=u6i9IiV|0QJs72?U*=WY8g`-;0}g^^&>{R*6}VtNy0NoM0Ke)|#zz@rPU~WY=E2$9Ce@~Om>`(k z+1-&$Vc)lzAjfZ*ZIKr)gn~In((CcIo7=p!K*5{=ZKmXhyY=8k`ve~TLu;Vp2&OoN zyeO1fm{G`ZQ^#76JUMhTIB^iRpc=lcL33v>NS)<^gd8p6C$+jG8EqW|i3L><@Y{wE zjcbBOcX8Mj{c>zcLVCv?Y}Av2zep7+5hiGPLV1dTiOqW=L0j!;#Oh^F z580#HHCoFI_}Dl9_M8t+z(_rTd97G$?@)3nUwF|B$>w!Pdx5mz0WX{@(EgLc6&?mO z|2HCA|Nq=Dy^(N}FAu)MGSNj#so4o7@q0Z+KW6pJe))fjuSjPe$9S}mN#fTJ@MWH~32hY{~Bfhu}Y zB?9XoMk7+IQBFqJkYxBSVIw)L?gX}GuY>u8VhD{b!$ZZ;VS_dd-u>kHr8{}!hLr6tpT{i>HnUp4BC@Bm=3&0UOXv3ClRy7@X6OPMn2_J{|T~~}b^8X_CH;;c_;(NTQT$vqe22$a- zpL*~yjD@5|`ltq*^OX^~c#_2Q0^oA>Dh(SBx_lD{57zcKX-FfjG5i0ZliHX0^e>;2 zW&mS!$pfrM)j>^39!eB+3psetq?8o@j0|PQq(> zo*%H(eb?yzZv4K66Hs02Rv1ZH%U$F(Io#j0ZvU(EM-X+64r(`JjW>*ZT)QlKc_b&m zd*ZZ5jY_YUeBM!m*1ygai+1HsaU^~o&^yQ^womij$4Zw%N!SHyq8rFdeDwIecDfEa33V9?As0AtVCURih~1HZ31Rg4D>oJ*R+u{e(R zmP3SKurUI0{P6Q^lX*!fw6mVN1^Oh?%GK4imSEIj8ig}jau^*fj1R{sP~c+P-yU$8 z9XF(H?bP3sbg~v)!cJ^1EXOB3yb#o#raynDDF^_G2-x)X5l@{C`K%b=s*oP}M6gZZ z4^93DQDvBpfTem@K+!>t=GoA(B(eN95mb17(=C08M}aVHlD5M0CgQ6VjS@KRmt=o~ zW@sIzO-ehMl>BHV4rM*Ac~$GdIS3n>+O|JJzA347t&7&h4wSTZj_l_b$HP(4z(Nb! zlLqv!ZLSp7uBbjRBQO7`Uin>h|1lLa+NsNaLocCD67i7Wz6t!-1v^}P$g_`A6!^5| zV?XOgn@PO=wGpn;#>%z-5lI&cW~N9deEgUED)2cQH3R#|6-lp#UDXl1^WvjDf1eNS zB8%`WBPbd^!^vYgut__FNodY{?(%Bq*2L)CuH~PSStXy4HtQ!czOa6xR{tG2U$Ns~ z5{TgRx_P#MRqkQCAg00IWji`T$)AW`rSRLkH_Ymz3jDiG!U41W)w(Rqt2z!bi6uUR zO%+sBI?D>&@{e&X(FtHTd-BCjw4jOP`b(wK?!zTN_3BukI=-O}Hr8{whp*4wIGC#! zNX@ty;FB$JQ*BhVINC?%2m)TXl*Z@S=yB{pCYSeP>-=ua0Bx)pjMWp3XRkPa6Kw*K zl~_hD|5juJBHVcOtppHn*x6NzBsrsee@&Ps}ZE-arQ+a*vz11?l=3;RB99DfZp&Lmrtig z-*ng@$UFs;ODW|7Y2Kd2Ob{4G$V+@~Cu{st6Bpj6k$0Q8@SD~ntx@)T!Bt!CXIAaijle9nh&Lo_$R!zOzp*^o_}9X?F` zz#7oY0a0^JO&{3XY`cuyPKEa86hN?*vX}%mq+pWT*vGg2VCg3c$dEo!U6Mz!1_6tk zfJl<2SE2yBcDKlkYvaZ4zwW?0=$3HLaJVrcQ!}-U@N}Z+f0Rx%bo-c(NQl35X0BOt zaP~0sB*ca|A`3Cyd6I2^^Ghf+P)P4de^=F_Q& z6slvU6RwYh#VFnL)dGRjh+PtnwoCb*i%*XbMaYvJVL{ns0)IoAPtaClc`x6n$3X9M zLQ;#$#n_)WKe>dH7-Ml|Dl3*{)y_%-N*R6U)jVKLHZx~Gk>JwF@$B|ZhlUhBy9FOZ z-LQ6pD{g47-R1DQDuaGw0UdZ=YVYMsB~c{`eRk4KRtV==tHVPbE7dm5@O#=Wxe*U3 zjGj*e^`7ZZ6HGNA*ZcY_=wb~Aq$f*U+(dm>G6qYp$9~ZNqUp_XmmT$-;hd%y=bikq z42Z{lXoYzwBjxn?fj{FVoa2TQzw*xww!a)P89A#(I#PX3vzMu$p4ZTM&TtL}+|dfZ z^!^XQmJ9fYEa*7Yz-x`>ftnYgfRa3c9Ai9hwENX4KEkj>MDd4>dLtA%J|(46`?>lf z)#W57HeSuifOngEr1FTj(%JvBJHrj^!J(|BmaH+ra)gFFekRV2?wX-cfCGUiUdj9TdD;vr?Mi`CzBxW(SRw!;P7heLg0EESP+t zI^@JIRp6i(f1adDR?6Ojh8CKDZ5Tv;Sx=lX*d*Xxji|YL(A%yh-rq7q5^G#`a`RgC ztHJ77VLZ?56ik}hHq$XU9K|0oA&2DfTu~2nUBPwtg48_tX9hrRrO{QiYp&#Xy-Pgq ze&oCz`K@o-#4uG8pYta~$A@LH2oQ8%{DI;HA(NWxsPk1cRS8$UTaL~$+;(#QS6P+w zUH{>rHXT~}AzhV9z{$lv$)DRb=-e}tKgSE;jF0g}siZmHgl?+I)IPt(1fhOG=?%f= z+$RaItz55kmE^;rw~twAl>`)Jd!~2OtyBg-M&nGw21zl%#vn2k(EFshe1l%_F zNq-CzWk6gcT(I(!U+giL&0Js{It?w|yctRDx(tv`}@ z4ySQx9MJc}h>Gd5!Nw*2LBRi=|0{?wZ>I??d|?1OhP}d(135J0@a)4lu0Q|u9i2Bzh^BDUuobhHTEw;(nb*bRRw4KP{dRl7&G+16 zuq?8}0vTje7VZi0aV!z9zE<<_?R28I#fNpwBy7cW}6J=A8I%USwpgESJ zaVJ;W-{O`2Ca=E6q7TB$c#W=}#M!HXJBCzcadFvo^gR9MciX+GG!DZ zelf&o_1>77`q$VG0B|%k7x?_QIH-cfSM2pO=yZ!#YWk zUZ)4^TJe6+OUE;Rnvk$8X@>9RmHaP0fDky_t@-vqaTuUmGnFTC)7gH9UZBr*01Au0T2iaDTriWccCt#n_zYTA{bGic6V<16T$78xn$4Ml ziYte#1oewq;k-aci}NF*2xRJkL8}}Xo_8h-Pv>X<9q-Zy7Kgqn5s%!t2uUf_S2f0! z9c83Mg-`>5Wt_MehKIpUgB{IX34gnYoYoI`Y!lBh2bjvk&C^;r64oHKxLgGBf-E=Q zV)&K)?6m!CBl57|j&_QOGh=EMR`@5i>AkA_5v;LRQ~jp(DoMotOVRXv z-}oDQD?Ak8NI#8ljX7|Bhi5Bdiiky~r%x}~8NE%cXs7{tCu2PFTI?5fJ2_NzrW(r$ zUqjQ%wJCTQ(|VpFfpukmZCfIj`t|A}P+nj}{UOxW*6D`aft+ecdr>p{wrqVT>R%sX z?>Y~Y>7(A|SX6Rp_F`Y9A10rzkWRm**whPc0@6C_8JJ3=!;j@QeCzkI%VLh9+$hdC zKRv{+7{HUNv9D%TS7�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 AC<5S^8Rc4eoEw7pRP_gZD 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

    4nywA6id87_EdQmwDcOC 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 W5vZr_nqVSO-fzouOLB&Yv^2x^d3{~G|^NSba; z-zU%d{3!G1@WKwp+k7tb0~is{ZgMPEi2OSA^<&>iNM9(jc+-DdjX2-|tE}_)OE@8B zZ5Eg#8+IJ5VCaw7j;vz16d@oV)?xbZa5<1v7~WEBdOY$L{7E_NCCyX_6e~T!TBqbC z64W#=pM!n`?i?4tAwSj|_(u?~Rfjyu#(^DfD&EH+T{ zQLrpo@K8iM{T`n!969ks?F8AXl(LgMuWsBk%y|ZMhltR!%#YGij8$)axyqAw|JYhd z>bM}PXh23ob0qaY+srqihe=QAKMXzHkoE+KrPoGz~#Ann-BqsotstRhav zH>{b3xI(KvFc}gF=J=5_+#@X8@%D%4AAeov6Z&f-9KOw1lo>qCcF771V0U@+J1I7d z_4WQHQuEAAll%H1@#>{v2N3HAexa2#*&w@@0}!TNXl5I_?4XL$P?p4}-0o0f`F34; zMvN8jl&vwi)?fXtywCzTwAD5Hi)zbDoH5DGdI#SdoXwR^EanK+C-IhmcL+9JnBQ_k zTDCucHP8xM!zSI3(5#~J6)Pw+yv#Vrhv>V9X?4TZ7$HQe?7E~Ujb#f$)h-g%+&#c3 zwu)Kl+2y=1sA+zF6a5YoESX&HCRV6>M1R{ebvi*BjQ51bMTSYSxB088(fNdHM@DhjTmbhKt2qa4S!(inwws0fVW79JQZ zaQH@V6Zi*KVnn^&l^3tCfz?s4e4Q%1p`HDxgoJdAS#da_7dHjxZI{*ZH5^`Kc7Y}l zdF7GanpC$vFTwkulAC(Pk@*7*30Y^M()gCoEV_@$C&7C+(@U3zmgsX@qz}8c*eZKE zRmE5Q1^zIb#gndYkhdg~{t!`aa1>^ELAd|fUfu(2L*%T}mjyW)wbSCATOS`-_g#Mv z*p9dG4d!FLJ_fmmAH?mPOToxydo3$2>KqY4{-c*vHD^dl#JZ!5P_M_~a#k1^u=(~Q zVF;tz?e46Oev_-S{79>a5ss;B4fC>Y=}y&5sMz0^$>8tR>mF9KLKUr)v;7=EZef9c z3YZ~K&t>QLjrO7EtB>)$>@4Y?i_R=s|KW0HY+LAv&oER5=S0Z5EpmI(AriaFAMBZk zT%9^1Tmu2$j4MaiV!I9>++uZr%vxUbEFbQ*;!d`#=iXN8+2EN?3QG#yK&-9{2+*FL zID*^N+aE;-Zfc|gOLC3~i}Wn(Rn~&EQds9!IT2G9Yo`J0;DoEyaI|G@aKP+z-$rI%!N}=mTQFFWTnj;nHbwzsC zTa9B)20cDg0BjCj-OW9zG4u>QUf$GT1bfX#+*2;u_+a2W`%^DtiNICiPqe4JG(Kse zpw)2>`=4bRz8;V6BPzXAuODgKVE7y`A14H91$3Uk#0>#O2``Wsu3zu$mF7PD3W$Nt z@EvtlP_=8%3#Nb;`RzV#l|531G1NqRE=DF53jPoQ%LzTJY}f#6PX%&o04>L=d_LZ1 z*noy9Ch9C2GhlKD2I`f)flxtJ*cDV?L{Xxl+fTHmpbFJ#@yOB-zA*hJ4dOdPaH4q9 z>1p{fzU}I-1LfEjuLn_ESyJAX41T3!;l*8b@(k|_22^u*{#0q!zQ1=ZlPscBgf+qM zGIz!f)EbrcV$aL53!cikrox?KHOs8jzA{mdvIftO2|bT^P4pQaL^QVMLkD}2zy_&= zR?hf8|An`7e|FsoNBXUBL@u&y50p2sE=j zpn=xM1xo0-%0sL-?M-pS**9LV9Y_5V3e7ZhZoJ-@6GP$saTf0UapjOV+ji#-NLFWU zcXxx3(LXMI;`b*IIZEHy)T_{xw?X(JB`+gxATgcBXpLMlq!Sg4&%*z!n4-9tpG6Ty za;*fdOa}Np&XP0omZ1N*HRc;-+lHk4z$Qad(dPcd-N82Gzt{m(e_8?vYC)X&>{kxApelo!wv~I| zyqdmQP?}^b76D~A>YkN_Eg8>E`G_vrp-n8Ubc8H|tDey1b_iml-j1I|DyFLDGF`o- zY}bODQ%7f>w(Dvh!8^fx4@Ya-_y7?V44&QFjMD*Ug6i7WQb7wr>e&QL*C(Y^E%r4B z9sMj>$Gv0Jc7W+FM*i%_iKmzK8#vTf_wJMy8s0|lRcmk9gP@JZ#z4LoO_6J|RkkNgzdy4GqOzSbSFa zMGv8KlsxqhAm2vF6oRmaFrKUSC^E`Ym;Y=7ldc|kYgoK92I@zWNF&7TA%ZqLgtzz} z`0_u5DhKy0`j>XV@vT%^Waz9?xz}FbkcKP-K7Ug7u3~KQB%JF6WZGFm7pJHNpF13~1U+lk<+j|?((6dBFqh79 zq8T>I0qUjXv+5DEW;C%SJV*j1%=JZZF|(_D&(E10m-@ZQFjL*qyPBCgZbA97oU@E9 z?mq)bz%geM5YWAEeAN!FN15!j6r~Nw@gPtaG%*$}Y59c&)2?FJG#}`WorXg zBN*%R`KCU4x4j~z{}%{Kv%Ej$wTK!x;1*bjS@#mfr2WP`7{UBtpvlItVi)?~OeM|3zaKLC6t$Y*5l$q@q_FwMpI$2-+>pfzD#`N(~CiPZl%a}R;^X)&) zaA^cbZ}^A&yr231|Ns9=f>Ym9fsN)l>uG(c@ME?OfB*gvF57;8|1J@K`@Mhs(2Z@= zY}W;`6zKo|YOnwQvNC$ITQwNiKk!B99;R&g<3m|!(9(JRkB|Mk<6L6dMeG#r)0Re3 zH~3rp@m1fTUV9zE5y#(H9VXeM&NiXBbxNvBeo=u^XhZb?-szfL9{o$LnG!=O5q<-8 zF?;}`{pn%*Av;WmXFCI~JRqwA0A{9O^a1OAg2%}Eki&zj?m1Il>HqDsLY0Dfnr^VT zFEn_5D!o`p0}lt?`@1%dF&J=dg_{R$CmhEGNTP${$x8d{UPLA$21e9>-2R}+BGT_- z?g8|4)%iT!^pjvBZs6WJeA~5(_429z5P{P2YLL$;jjRau4=TQ(=VLgVFsY)HRr_gJ zlFbj+`0yXyI`x0Q*D0ty$vDaWPq*o?<>B{f`8~<7UyLj(raJt($?ULx05G0C@q+&T z0N=n+g&K_-#E-^#49g8Bn0&A2a;pH$t{Ui`o_Yxgkg zH5C2d+P(5Y!QRUMTBHHJ$9a_KzEBYC;$JvhrM=z+dkUrTWjX#LErneA#9pGpZRjb=P&3V!HA$1 zPJ1Ao_lrHYQ|wavy;(fxw^Nkp$NQm55a7U0c+%^~uSEuIk+z#3uw3Mc1qNLdlYS7w zjC_%CEfl$COIh{_9!ytbzR7tCq6R9IrTI03+(Co(7syU%nzYL*7;1$OuL5QxlOacVWSSTSOag+R^@DUSx>-MAuQvebJKvejl@6OsR5@_A0 z;GgO1-yd!pYM{y@J^##0{ny{OJqWSmSlY?~OWO+=(oQ&gj2WKi;@`kbI13 zyY8DGn(lIiiLF^6w(yJ}8I1%Nq`Mv)xR14|U*!z)y166BV6#?m|A1M_Y1y1zHP!yd zX^EP%@6vWb@kZ?qqgw{Guu6h9&Dv#-R}qHo<)M_*^1mNawhv@iKqdh}nsaywiUD;3 zT-=9L_;Im3dHcJ9GC-k~V!?!}_JH?CM;x2{dj7Z)c7R4k?HW^}tPAJy4d#KM!pyd@ z**P5>v;i$_W;}lB_PvXn4;n?0@=Jc$i`VSG$HIJ8d?#f2$wt#$Y2wX%^kCpOrF&~% zgFqE45*<#6Z~fRogda-G;CrGDf2;vSr_#}=?X8k;1ORnrsqx3W_*Od7)7j=KdXsaNEB%S2T{+KmIwN}uzq1d1y+kDc*wlbJE3I|nT4Eh4sgFaTr`mHBTHC<&)el=+C`+sL zV3`muC4rjVAjNC=iU0rq?z#Z_p&m(rt4tQW>*_AZ>`Ne4Nq6gJnQ?q7gk`|!Hb{s# zL^rLn?4#;bZdkru(^*Oqo_2{L8H^x^g`{Ln#es1DoHbwhy#94Rj4i1w!pP9WoTCpz2 z%mi!6nYKeBI>xCot@tUiwN^Cku!qn!>SYk&XvT<{>!kwUR;I+1XBWmsAW zmnUI@H6mS}L-Dy5p^eLotvsu@E}OLmRk`?6=cNK!?c8Z~>#xMPXAI8T4?o~C+mq}u z9dl6w8ulKB`p-Q@y(gNvJsrR4WB1~`N-L5iMC#7>WHXWu%Tt2I9)6ScV6Or_P-7Hg z732C3H*jP~aJ{-up4kAW|EuX7*y<9?2>k)YG6U2~n`hw6+b?BAi9iAuY=!Wv-Eric zOLvLzN?NcD3IkeIzMf3}JGFa{;kIR>zz+?&xMt$#@0c}C zD>xur_$9{eqmQNs!DQgxjL5aCVzDPTeB{ywze`<$Nc~s|`w({fY|7HUu*~BzYXUP_ zb81>R3vR`5!OzwrnM%Sbx;dRoNFdv=bstMMWiP%TGO74FhS8Hn^c9U@-|Qo=QUKCu zGCuhw+Tl9Mu{=7hU4yu_vqjYtToe}8_me;aItY@<7_9jk;iG4sTfxCVuJ%XXWad~- z_E#9?cKIrjRX8KF|NoEw{SyEG|NsC0{s{5-S&K(mC`x0-%d~(8$h{;zyxt)#ZiS4|608Eh%!@$B)!9X8J@1|E=`A3FbH2N6-x9Npp zrc#K+9v}s{k3yfe7SW&66hlneGWgDfP&Y07LQIpn+(7pknqbbYzdaU9G#wfK85RnA zMjCEAD>VrUsqYBGOuIZXn%@;L+tg}~0Y<$Sf=7A&YW{3G4iSVR{Yvvx$tl5uwBg|* z+^q_d+B$`4{xOyl7()a7?pGot6TRse8a>Xi86T6REel{35!Fcs|5g5}&2D3Nsev6O zAkJK1RXeC2#Sk`WM@TiQ*N^)I0RO`d`I;QnvKm!9?2-Tf z)B3rhMvoiIswOzU2utAbW?WqD7fS!}#V%xd{sA7pHDC@$cY4-LO1!n9;CykWEseVa zE0`~@Npy%mg!Coe&|ve+CT&Lopq}KZBq$um^Z?1|ih)giDKD8-(j6*)mhz?rT@0{U zLwgI+JM&ur^R9BODR=G7?RFDawcDkl| zZ}h*0o~i=TJMP5Ly$Jtfrs7@68I{Nnh<+#^9m<5vP|RFaxiiw_#{Z%$o^)CN!gs#X z0(UnE)mG?Z^=H?8s3OIP7)%M68O*~CL$w!c{D!XMq@`$?*($=t2J1I?E0b4Q^U=TU z;vO6U3gbg7(vG-NG;k!^8}D6x6{eghhLAv(NbV4!94W(0?gGo5Gr@Hv2^);>DLyk~ zG%BhPEpE7~qLvz-uT$P0Yxp)WTnj&~LEFc;%>?-b))A5(f~9Ux=23?QYX5OqE8)?p z!}`64Q4{Zl8kiZG^tx{EcGy$cJ54p1E(r17ea0qd>j!KIwL+5EFyYzCg? z(Q4tH$>$Zj!OSq(^p3;n;nMkM1*#1@ffhm;%L&}N?eh)fD6xH?`;RpvQT}BRzUHTo za*;dvR&8rL+Q;7$tf&lVST*ZnVzqjae&mv}sF{*FUl38)VPRLaeuDQ~x7=5cA1lr7{EX&tPC&*HA3S7j1Qe59_m^@ze$5)tAY%0cssTN>8wz zOJOT@=+VTcQut4+{^QDi_Yma@7JQOB;Yy>Jns#X(Q88k^fM45v-zoWSKKEUKK(Hasf3l_Y5oW8_Mj@$7| zC+m&5Sqwm_O4`c&w{?5Jhs5Tq(Xgi;}tuwU8jHl{;F)!RTq^cX>R0& zyl<+ezd>j6CUa-aF8nyLn`XX97nw1@w|901||7<}`$+Xoc=Xcw54U zVgO2bZB3Fmv7`-HuKsrTiJtmsYKv}|o`Bbkyj$E5G6IjGXf_%IfT(+#uj7{2=Qbz^ z`2^?lAq09&l3K%O8UoC_>sxl0fB&UPNaWtnM-AKQ0i|JNJKqVRF!W=l)D=sW_6)dX zQrY)wIl?5LlJV*hP{4%o!o_{#V`{hhTxxsrYQ4FBoPj|pW~6o^!YgvNE}5z>aBuws7F)1_~>M#-IzLL^x#R6e&1-0Qx@hyKQYIhjXV*X@#l2^`T+R$ z5XCJS|1%AOprbK?1V*NDSu<6e${d!Rh1IMPWGa{&6%!Qm$@`B(Kky5hDz^dGKtE|(yq3cnTe6ZrU;C>re1Hl&!08d$n(9fZ{nZF9te$v6GThM@Wi z{$F+qsyj%))Hb95>pq$u$IaXdK&<;zcd(yzz+1K%Bb0(7>KoG;)%ap$cFuZ6)ssE# zg!3#t%#I+$D~tAGGgK-7saa1f7AoUb=l9het{ZCHI}|@Cf4U8{Y1K1)V=hzsnEoiY zcxElTPpqI%Qm06fZ|bwFdaL<<{*Qo zqOr+(MK@{`vl_2PP3@e-R!=CC`hVzJdD;>nvZ5DP0M+lo!ru#Q@n93ir2WSS?O*fb z%x}f~h@U-aAOHXV{BCKaY7hVZ7CWX#9Enj@3DrNS8;DLx!?rJxDXTj5fAK=+|NsC0 z_M!j(|KsJLciyIM`^_qM9-w`3_L-BZgx|)upXGo3j^dzKuyQ^<;Xc`m%Npbo4r(J; zJTaQjSX}$q=xD9SB@bA8tPp61iSM`{BTk=}?pe~hypL)k1midzTeR2WR$|Sh?`7kb z2ex3mqF@^Y!iSLiu3|qO&V`u38sV<5%z5=Iad6vLghya_K3ZS_*l6Yq-J#mWGFMjkY&Cpm+SmY5$J~5LnL30N5JLUH`e7kTyf+_^ z!o;lEoPRfNHWY_9$whg-+sz6OdQi&8aSgv`PL%v-O4%&fw8ffEg~9WK(V?#y`JfQY zRfT+82nf?nRnCWhF(_;dElze_@$(mctqtl8c*&mhDqpeSL-xTypbgmbwcZ90)AM8@ zMxA|6jJHE1Pji>RtpAaSIl~dKEOLMoa_1IznTP;_I`MLe1l%`Hba(>|tB&OED?p-X zF7Rz%tPZP?JH$Wq1t zC6TJ~p$ug=aJT2;{%*Qqo5H2}luK#=?8@d-7@5_~>cc3VXAXTlT1Cg=K{}UBj#4wf zv9I;1IkNN_4^_7DN~v)6NPbMar$voO{qUQ33~?dMI|bi@QB$q?+C~)*B`>Z#iH6aE zMowb>F`v^Wek*a%RO@XyN2R=8(oMV;?a^sOhb$Fe%|v8Xk6r)IVBJ#0_O=NU3B60< zDPr$zyN)A%2=@2zST3B6rB`K&hVWUPx&7jF5C=(W)}?p_Nk6j~yq}k4e=&boetFXq z?aYs0n&u~l6aR}p@|v71m~@-Q#@TB6dtDx|+wh1a2`2RVXuhc}1IHopKmyqdp+fLY_>B(r+7GEw#S|DItvsbxCa42TXE%KvNqu|we5r1gBA#JLGm@yf_yik=RN z!@e1Z2jx7d1+QE^-!nBH2?caB|Aa-EMc?|i-~V|1AEM88H@Gkh7^%A)vW9H^k_oSC z!mLTfDcmiqaEQNRl7%jntyv3UV~y>znS1wW9ymjsMgf5PR-7m3Ub2UKr3*Ah48Qfi*?)57G(VQ(6^7_G!bVkS? zFYx6h3H386o54UCUY|>M09M_B*xL9A4wurb+)1cMfIhj>-MEq`&eZqt1r|a4`3v=X z+-=6-z<-vJ8*t&Ggenzki3)%J`XR*j?Q0N@fCWnAA*53LSwua@a(oBnNM6U0n-CNiS*HL>jQEmo)r_%ePnKY84 z+q>-xNj*XMnHDYpNB@00KNU~Wy{6b9x#IfKwBa9bgct1u3Q_%2L@n9njyZh^`*siX z9j}S^is-}tiepIo*R-RzemiT@=JYf3GSi;Spx;5oCaH&=8`0wvKVm8wsu;qaPyTCn zHL=`@ojqCqh0~Oet1nQ$Y5g{E137`cpI$_#XJ`*^Q#JSA@W10>Z4H$f|64X_9yW{> zVAgvGRahwFpwHnFt;EzJc`8bbtj3-OP6Y5{cHJpRKpgQM6`<5**(WnjF`WGgNQU$h?7@TqIFq8e?KiR6}0JU z;+f0B|NkDdg}g$w`OkN&ErPS!K$8Kn0!Ux~Ob(~sPWQK|niZ?TMPQgHAb{5uo5xgg zy@520=~_1Hfx~5GU2os7;-jL}COn^~O@knK1O*b&`z7Ce$t(Y`aW=PF<)qZH!ZnXL zB}1ApcY!_S`Ev0a>c_`hFwte)JkQc*-~Yr;ik%4f(wKpaq&mL5e(>zT=McQt_1E6T z+k6=G9LcuKs2#GR&AQXJVJe+)>0N|ua#Zd**g-C+nhKv;lUxvmy_wNN(0 z(g1t!rHr$>0!n2PvcP1Iw;oNKfG%e;cYd_;frA^BG0}M~kG13$FF=<>yEJJ4;m2Wp zJj;L{KPUuCOo0Z+ZCZMrGxCjO1yYm6DLZ<%08Bu$zcL*u*fc3lw5eC5#=ti^ck-#V$tvl*98K@(K#pbIVA+*ZY+BfOqBn!x_&%Qk zxVGUM!HRIJQ4kb;PNQ6tR<<^<^~QAz!GhmDZ}Ng#WaXW?`7y75dWtq&d8x$wrPhQA zaUbq)iH(=j;0@uZc?Qgyo2QRgKG`LmYLrVmux}-fL6G#vDpnP=sgbL3K_e~DX_^N^ z9c)>J+|a#txTNA0>5G5b$i^@hsv%5l^$&OcNoPcA^xb*Am0xUyf@EkU4@p&P-~177 z5Dt=-#1J|TU@5Qt=FL09zJ2yzrnw1ACX_mvh;^5}XlQlQ5Ah#<3-j_t*;@$>c;P{E z>P3@=F+iC~B1}kN)G;ZSE|qc{Z4Y(=FTkuGyLJt>eth{|&>_IrN&HMgwFpd=pF8iF ziyk=IG9FI=!w!Gx#8kKs#l=MZun=ql%|M`30qMV6)V0$ zl3FVz{;Jw>{$Gpjg8vaG%yL=C3~bBi3la)1+f=81k|aq%wKS*?63MENkTYRH7JCc= z@MAA~0ecVkUb0oKcWpI>6-6FKwbR)kbiWtUb7hzYNseTPgTW2$-2y?i=9SG}5Ul87 z#I?qy^2yf)aTNy#;}%|4?p~&ilBuZW7Md16$BcXvKrQ*c&l$Sq+;FI3`s1 zImBoz;adNPcgaKepLLh7PSF+ZRw>efi__r!aHs81P%G597haZaDhO1C#*H>&N*mX6 z7h!PsJ8i%!)3tlmT+}SqugOkfRV&^s!43lWF-b`H%+TWw6)o z{x)t5S>)!0wB-ED=F*37f{Pao8dTRWZbF_VQ+Or(dZ@1+q&2LJwOa zNzznCjRso$LOB!pHvTm9Frr})phw^~p8h?Yi!hstY4LvGxHlO1#qn^fr?reUU?k=nTkblTo`?5z ze%8qP8-u%D+?^8hIj#5QV~$Z;sxZ@k)ut6a6pR1KtF@EOfGr=i6T80bg z5T{w`?~W@n0!gT@?f#OwUd}m?n6H|yoH~oE@^pHus9mKkEReQM+>nL7`&})EA)s|J zHE%ywZ&3ogwkJe}5XEz=sntU?0qB~lP%a8KSsF49LIey7N;1U2#sk?yUSS2v${F0F zkBuXHcjv!R7xm) z=Zd&#aFQU1mUO7F*t=M_wbFj(mC7F( zOgYEkelf%_OMPkpjK^xrg^Q!##+W~9cJ4t(m(Z1MOAt6ukk1p~d>e&pnnYzy?HeoD zLopMt^+!vk1*RL$%PRe1g1kV{0>kRSD*7hVxyyvt`gc@?`IKoe=*pU=-iJ4V+>Z6V<$F6vy=%a*mH*i8Z5jP|NoRfVF|wSu zEfBs5->!>(Ny*6{B-d$h%R!ZT`Ed0cFs+-I%N$SUA*SaT#3N*89}&LPisiUd1ssYE zbp`AA*j6?Y3Xth?Rrm+Hcx&7;d;LPDG34jRIa>YuP>;(C3ovTjIm zU?D^ekGNWzU%8qZE76MI&fP4p`&hJvOLMUQs~b8=JCFj>9YLh*=i*CP!~iiiSR=`t z;6X0z_VAt2m&qO( zOC|w=wwP>NW+wR|WheMA;FCB#&()ZK!UBL>pKzP#$w!^-;$L7>dASOVh79{`8-1|K zh>P`FS+IJ2$or^((kLKrZnrYwn`HASRdr>`_X_?giA^wQ7P+LM!|X5~+r|^ua#Sqy zvW0&@NL?)xTS>2>jhFqyJQ2jE0^olIcYb5xy&@Yv1+CEfO&&?WDgzU5GQR&08uxODMiWQ%SnRVXz4v1?#WteIWekou{Y#a;3#z(4v-q1eqTx)VeLLXos

    D1V}}O0btVDAlTp8? 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

    0*7;$v_{nj>fWhZyce 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
    `p6qYwep5Az$mWO8|*}nXIGc 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

    imYIu)||)2OC)0CtR?lJg}f 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

    NL-qR1A&PP&p1v|8m1{;-q$>;pGzE+az2 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%0AYoNGk=Yh+9N9s5fB6(_K1V`fX3g|*o?Mc5Lmh1 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ⅅ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%0AR$`q~%jk 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
    -

    ARCHITECTURE

    -

    System overview

    - -
    - - -
    -
    ctx.sessionsevent-sourced log
    -
    ctx.systemPromptprompt assembly
    -
    ctx.toolstool registry & pipeline
    -
    ctx.agentsagent handles & events
    -
    ctx.agentLoopReAct control loop
    -
    - -
    -
    - Cordis - · - microkernel - (vendored) -
    -
    -
    - - - - -
    -
    -
    cordis.yml
    -
    deployment leaf
    -
    -
    picks which plugins load
    -
    -
    - -
    -
    ctx.llmLLM provider adapter
    -
    ctx.bashshell execution
    -
    ctx.sandboxprocess confinement
    -
    ctx.codeRuntimeJS worker runtime
    -
    ctx.fsfilesystem + policy
    -
    ctx.skillsreusable skills
    -
    ctx.websearch & fetch
    -
    ctx.compactcontext compression
    -
    ctx.subagentsspawn / fork / ACP
    -
    ctx.workflowsdynamic orchestration
    -
    ctx.sessionPersistenceJSONL / SQLite
    -
    ctx.sessionQueryunified log reads
    -
    - - -
    -
    - - diff --git a/.agents/skills/dsh-arch-diagram/harness-arch-zh.html b/.agents/skills/dsh-arch-diagram/harness-arch-zh.html deleted file mode 100644 index ca2da1b4f1..0000000000 --- a/.agents/skills/dsh-arch-diagram/harness-arch-zh.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - DeepSeek Harness · 架构 - - - -
    -

    架 构

    -

    系统一览

    - -
    - - -
    -
    ctx.sessions事件溯源日志
    -
    ctx.systemPrompt系统提示词组装
    -
    ctx.tools工具注册与执行
    -
    ctx.agentsAgent 实例与事件
    -
    ctx.agentLoopReAct 控制循环
    -
    - -
    -
    - Cordis - · - 微内核 - (vendored) -
    -
    -
    - - - - -
    -
    -
    cordis.yml
    -
    部署清单
    -
    -
    决定哪些插件加载
    -
    -
    - -
    -
    ctx.llm模型适配层
    -
    ctx.bash命令行执行
    -
    ctx.sandbox进程隔离
    -
    ctx.codeRuntimeJS 运行时
    -
    ctx.fs文件读写
    -
    ctx.skills可复用技能
    -
    ctx.web网页搜索抓取
    -
    ctx.compact上下文压缩
    -
    ctx.subagents子智能体
    -
    ctx.workflows动态编排
    -
    ctx.sessionPersistence会话持久化
    -
    ctx.sessionQuery会话日志查询
    -
    - - -
    -
    - - diff --git a/.agents/skills/dsh-arch-diagram/harness-arch.css b/.agents/skills/dsh-arch-diagram/harness-arch.css deleted file mode 100644 index 97ac526b8e..0000000000 --- a/.agents/skills/dsh-arch-diagram/harness-arch.css +++ /dev/null @@ -1,220 +0,0 @@ -/* DeepSeek brand — bone-white + brand-blue, all sans-serif, no italic, no serif. */ - -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap'); - -:root { - --bg-top: #ffffff; - --bg-bot: #e8effc; - --ink: #1a1a1a; - --muted: #8a8f9c; - --card-bd: #dde3ef; - --card-bg: #ffffff; - --brand: #4a6ef5; - --brand-soft: #dbe4fe; - - --sans: 'Inter', 'Noto Sans SC', 'PingFang SC', -apple-system, BlinkMacSystemFont, system-ui, sans-serif; - --cn: 'Noto Sans SC', 'PingFang SC', 'Inter', -apple-system, sans-serif; - --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace; -} - -*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } - -body { - font-family: var(--sans); - color: var(--ink); - background: linear-gradient(135deg, var(--bg-top) 0%, var(--bg-bot) 100%); - padding: 40px 64px 32px; - -webkit-font-smoothing: antialiased; - font-feature-settings: "kern" 1, "liga" 1, "cv02" 1, "cv11" 1; -} - -.page { - max-width: 1560px; - margin: 0 auto; -} - -/* ── header ─────────────────────────────────────────── */ -.eyebrow { - font-family: var(--sans); - font-size: 12px; - font-weight: 500; - letter-spacing: 0.22em; - color: var(--muted); - text-transform: uppercase; - margin-bottom: 10px; -} -.eyebrow.cn { font-family: var(--cn); letter-spacing: 0.4em; text-transform: none; } - -h1 { - font-family: var(--sans); - font-size: 40px; - font-weight: 600; - letter-spacing: -0.02em; - line-height: 1.15; - color: var(--ink); - margin-bottom: 88px; -} -h1.cn { font-family: var(--cn); letter-spacing: 0.02em; font-weight: 600; } - -/* ── diagram frame ──────────────────────────────────── */ -.diagram { position: relative; } - -.section-label { - font-family: var(--sans); - font-size: 11px; - font-weight: 500; - letter-spacing: 0.22em; - color: var(--muted); - text-transform: uppercase; - text-align: center; - margin-bottom: 20px; -} -.section-label.cn { font-family: var(--cn); letter-spacing: 0.4em; text-transform: none; font-size: 12px; } -.section-label.bottom { margin: 20px 0 0; } - -/* ── card rows ──────────────────────────────────────── */ -.row { - display: flex; - gap: 12px; - justify-content: center; - width: 96%; - margin: 0 auto; - position: relative; -} -.row.top .card { flex: 1; } -.row.bottom { - gap: 0; - justify-content: space-between; -} -/* flex: 0 0 auto so cards keep their intrinsic (nowrap) width and - neighbouring card backgrounds cannot clip a description. */ -.row.bottom .card { flex: 0 0 auto; } - -.card { - background: var(--card-bg); - border: 1px solid var(--card-bd); - border-radius: 6px; - padding: 14px 10px; - text-align: center; - min-width: 0; - position: relative; -} -.card .name { - font-family: var(--mono); - font-size: 13px; - font-weight: 500; - color: var(--ink); - line-height: 1.2; - white-space: nowrap; - display: block; -} -.card .desc { - font-family: var(--sans); - font-size: 11px; - font-weight: 400; - color: var(--muted); - margin-top: 4px; - line-height: 1.3; - min-height: 28px; - white-space: nowrap; -} -.card .desc.cn { font-family: var(--cn); } -.row.bottom .card { padding: 10px 6px; } -.row.bottom .card .name { font-size: 10px; } -.row.bottom .card .desc { font-size: 9px; min-height: 22px; } -.row.bottom .card .desc.cn { font-size: 10px; } - -/* connectors — pure CSS, guaranteed vertical & parallel */ -.row.top .card::after, -.row.bottom .card::before { - content: ''; - position: absolute; - left: 50%; - transform: translateX(-50%); - width: 2px; - background: var(--brand); -} -.row.top .card::after { top: 100%; height: 40px; } -.row.bottom .card::before { bottom: 100%; height: 40px; } - -/* ── bus row (Cordis) ───────────────────────────────── */ -.bus-row { - position: relative; - width: 96%; - margin: 40px auto; -} -.bus { - height: 60px; - background: var(--brand); - color: #ffffff; - border-radius: 8px; - display: flex; - align-items: center; - justify-content: center; - font-family: var(--sans); - font-size: 18px; - font-weight: 500; - letter-spacing: 0.01em; -} -.bus .dot { padding: 0 12px; opacity: 0.75; } -.bus .vendored { - font-family: var(--mono); - font-size: 15px; - font-weight: 400; - opacity: 0.8; - margin-left: 8px; -} -.bus.cn .core { font-family: var(--cn); } - -/* ── cordis.yml side box (positioned outside bus width) ─ */ -.yml-side { - position: absolute; - left: calc(100% + 20px); - top: 50%; - transform: translateY(-50%); - width: 130px; - display: flex; - flex-direction: column; - align-items: flex-start; -} -.yml-arrow { - position: absolute; - left: -30px; - top: 50%; - transform: translateY(-50%); - width: 30px; - height: 12px; -} -.yml-arrow svg { display: block; } -.yml-box { - width: 100%; - background: var(--card-bg); - border: 1px solid var(--card-bd); - border-radius: 6px; - padding: 12px 10px; - text-align: center; -} -.yml-box .file { - font-family: var(--mono); - font-size: 13px; - font-weight: 500; - color: var(--ink); -} -.yml-box .sub { - font-family: var(--sans); - font-size: 10px; - color: var(--muted); - margin-top: 4px; - line-height: 1.3; -} -.yml-box .sub.cn { font-family: var(--cn); letter-spacing: 0.05em; } -.yml-note { - font-family: var(--sans); - font-size: 10px; - color: var(--muted); - margin-top: 10px; - width: 100%; - text-align: center; - line-height: 1.4; -} -.yml-note.cn { font-family: var(--cn); letter-spacing: 0.05em; } diff --git a/.agents/skills/dsh-arch-diagram/render.sh b/.agents/skills/dsh-arch-diagram/render.sh deleted file mode 100755 index 781f79b9ef..0000000000 --- a/.agents/skills/dsh-arch-diagram/render.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/bash -# render.sh — Chrome headless renderer for the DeepSeek Harness architecture diagram. -# -# Writes arch-en.png and arch-zh.png (3072×1160, ~600 KB each) to the given output -# directory. Default is /assets/, which is where the README image references -# resolve. -# -# Usage: -# bash render.sh # writes to /assets/ -# bash render.sh /some/other/dir # writes there instead -# -# Env overrides: -# CHROME=/path/to/Chrome # non-standard Chrome location -# PORT= # override the local http.server port - -set -e - -SKILL_DIR="$(cd "$(dirname "$0")" && pwd)" -REPO_ROOT="$(cd "$SKILL_DIR/../../.." && pwd)" -OUT_DIR="${1:-$REPO_ROOT/assets}" -BIND_PORT="${PORT:-0}" # 0 → kernel picks a free port -SERVER_LOG="$(mktemp -t dsh-arch-diagram-server.XXXXXX.log)" - -# Locate a Chrome / Chromium binary. Honour $CHROME if set; otherwise probe -# common per-platform paths so `bash render.sh` works on macOS + Linux out -# of the box. -if [ -z "$CHROME" ]; then - for candidate in \ - "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \ - "/Applications/Chromium.app/Contents/MacOS/Chromium" \ - "$(command -v google-chrome 2>/dev/null || true)" \ - "$(command -v google-chrome-stable 2>/dev/null || true)" \ - "$(command -v chromium 2>/dev/null || true)" \ - "$(command -v chromium-browser 2>/dev/null || true)"; do - if [ -n "$candidate" ] && [ -x "$candidate" ]; then - CHROME="$candidate"; break - fi - done -fi - -if [ -z "$CHROME" ] || [ ! -x "$CHROME" ]; then - echo "No Chrome / Chromium binary found." >&2 - echo "Tried: macOS default, google-chrome, google-chrome-stable, chromium, chromium-browser." >&2 - echo "Set CHROME=/path/to/binary and rerun." >&2 - exit 1 -fi - -mkdir -p "$OUT_DIR" - -python3 -u -m http.server "$BIND_PORT" --bind 127.0.0.1 --directory "$SKILL_DIR" \ - >"$SERVER_LOG" 2>&1 & -SERVER_PID=$! -cleanup() { kill "$SERVER_PID" 2>/dev/null; rm -f "$SERVER_LOG"; } -trap cleanup EXIT INT TERM - -# Discover the actual bound port from Python's own startup line -# ("Serving HTTP on 127.0.0.1 port ..."). Works whether the kernel -# picked it or PORT was set explicitly; no external `lsof` needed. -PORT="" -for _ in $(seq 1 40); do - PORT=$(awk '/Serving HTTP on/ {print $6; exit}' "$SERVER_LOG" 2>/dev/null || true) - [ -n "$PORT" ] && break - # Bail early if the server died (e.g. explicit PORT already in use). - kill -0 "$SERVER_PID" 2>/dev/null || break - sleep 0.05 -done -if [ -z "$PORT" ]; then - echo "Failed to detect local server port. Server log:" >&2 - cat "$SERVER_LOG" >&2 || true - exit 1 -fi - -# Chrome/Chromium refuses to run as root without --no-sandbox. Rendering -# a local static HTML doc under a headless browser doesn't need Chrome's -# own sandbox, so passing the flag when EUID is 0 makes the script work -# in Codex/CI container environments that default to root. -CHROME_EXTRA_ARGS=() -if [ "$(id -u)" = "0" ]; then - CHROME_EXTRA_ARGS+=(--no-sandbox) -fi - -for lang in en zh; do - out="$OUT_DIR/arch-$lang.png" - "$CHROME" \ - "${CHROME_EXTRA_ARGS[@]}" \ - --headless=new \ - --disable-gpu \ - --hide-scrollbars \ - --force-device-scale-factor=2 \ - --window-size=1820,580 \ - --virtual-time-budget=8000 \ - --screenshot="$out" \ - "http://127.0.0.1:$PORT/harness-arch-$lang.html" \ - 2>/dev/null - size=$(du -h "$out" | awk '{print $1}') - echo "[$lang] wrote $out ($size)" -done diff --git a/README.i18n.yaml b/README.i18n.yaml index 020593bf20..9d14f74bbb 100644 --- a/README.i18n.yaml +++ b/README.i18n.yaml @@ -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 -README.md: 8b34d6177834e1c410b2c3ecaf32154de42520b4 -README.zh.md: cf029cc0bb8c5aa527d14753803eac4c28ab9de7 +README.md: a32ad5cddd2bcaa9468031e5833aab8e78dac52b +README.zh.md: 4ffb222b2f2bff8c41ac42c047ea034e4416d4d7 diff --git a/README.md b/README.md index 8b34d61778..a32ad5cddd 100644 --- a/README.md +++ b/README.md @@ -2,32 +2,70 @@ English | [中文](README.zh.md) -The **DeepSeek Harness SDK** is a plugin-based SDK for building agent harnesses. +DeepSeek Harness (`dsh`) is an open-source coding agent built on the DeepSeek Harness SDK, where everything is a plugin. ## Install -Install the `dsh` coding agent with one line — it needs `git` and Node `^22.19 || >=24`, and offers to install `pnpm` if it is missing: +Install `dsh` with one command. The installer requires `git` and Node `^22.19 || >=24`, offers to install `pnpm` when it is missing, and prompts for a DeepSeek API key: ```sh curl -fsSL https://raw.githubusercontent.com/deepseek-harness/deepseek-harness/master/scripts/install.sh | sh ``` -It clones the harness to `~/.dsh/source`, runs `pnpm install`, symlinks `dsh` into `~/.local/bin` (offering to add it to your PATH), prompts once for your `DEEPSEEK_API_KEY`, and launches `dsh`; re-running it updates an existing checkout. Run from inside a checkout (`sh scripts/install.sh`) it reuses that checkout and skips the clone. The overridable `DSH_*` variables are documented in [`scripts/install.sh`](scripts/install.sh). +The installer clones DeepSeek Harness to `~/.dsh/source`, links `dsh` into `~/.local/bin`, and launches it. Re-running the command updates the checkout. See [`scripts/install.sh`](scripts/install.sh) for alternate install locations and other options. + +## Use DeepSeek Harness + +### Web UI + +For the recommended local interface, build the frontend after installation and after each update, then start the Web UI: + +```sh +pnpm --dir ~/.dsh/source run build:web +dsh web +``` + +The Web UI is served at `http://127.0.0.1:3080` by default. + +### TUI + +Start the full-screen terminal interface: + +```sh +dsh +``` + +### Headless + +Run one task, print the final answer, and exit: + +```sh +dsh -p "summarize this workspace" +``` + +## Why DeepSeek Harness + +Built-in capabilities cover file reading, editing, and search; shell execution; reusable skills; task tracking; subagents and workflows; persistent sessions; and context compaction. The TUI also includes Plan Mode. + +- **Everything is a plugin.** Models, tools, policies, storage, context management, and interfaces are composable [Cordis plugins](docs/user/develop/basic/index.md), so deployments can extend or replace behavior without forking the agent loop. See the [architecture](docs/architecture.md) for the underlying design. +- **Code Mode is opt-in.** It exposes a `run_code` tool and a generated TypeScript SDK; only program output re-enters model context. See [Code Mode](packages/core/tools/README.md#code-mode). +- **Self-referential Cordis tools are opt-in.** They let the agent inspect its live runtime and mount or unmount plugins while it runs. See the [Cordis tools](packages/cordis/tool-cordis/README.md). + +## Community + +Follow DeepSeek Harness on Twitter for project updates. ## Development -This monorepo is built on the [Cordis](https://github.com/cordiverse/cordis) framework (vendored as source under `vendor/`), microkernel-style: everything is a plugin. - ```sh pnpm install -pnpm run test # vitest -# Agent demos require DEEPSEEK_API_KEY. -pnpm run demo:tui # full-screen TUI coding agent -pnpm run demo:headless "task" # one-shot coding agent -pnpm run demo:cordis # self-referential agent demo -pnpm run demo:acp # ACP server agent demo +pnpm run test:coverage ``` -For humans, start with the [development guide](docs/development.md) for local setup, hooks, environment variables, and quality gates, then read the [architecture design](docs/architecture.md) and [documentation graph index](docs/graph-atlas.md) before package work. Local context lives in [packages/](packages/) and [vendor/](vendor/). +Start with the [development guide](docs/development.md), read the [architecture](docs/architecture.md) before changing packages, and follow [AGENTS.md](AGENTS.md) when working in this repository. -For agents, follow [AGENTS.md](AGENTS.md). +DeepSeek Harness is currently pre-release. + +## License + +[BSD 3-Clause](LICENSE) diff --git a/README.zh.md b/README.zh.md index cf029cc0bb..4ffb222b2f 100644 --- a/README.zh.md +++ b/README.zh.md @@ -2,32 +2,74 @@ [English](README.md) | 中文 -**DeepSeek Harness SDK** 是用于构建 agent harness(智能体框架)的 SDK,采取基于插件的设计。 +DeepSeek Harness(`dsh`)是一款基于 DeepSeek Harness SDK 构建的开源 coding agent(编程智能体),一切皆插件。 ## 安装 -一行命令即可安装 `dsh` 编码智能体——需要 `git` 和 Node `^22.19 || >=24`,缺少 `pnpm` 时会询问是否代为安装: +使用一条命令安装 `dsh`。安装器要求系统已安装 `git` 和 Node `^22.19 || >=24`,缺少 `pnpm` 时可代为安装,并会提示输入 DeepSeek API 密钥: ```sh curl -fsSL https://raw.githubusercontent.com/deepseek-harness/deepseek-harness/master/scripts/install.sh | sh ``` -脚本会把 harness 克隆到 `~/.dsh/source`,运行 `pnpm install`,把 `dsh` 软链接到 `~/.local/bin`(并询问是否加入 PATH),提示输入一次 `DEEPSEEK_API_KEY`,随后启动 `dsh`;再次运行会更新已有的检出。若在检出目录内运行(`sh scripts/install.sh`),脚本会复用当前检出并跳过克隆。可覆盖的 `DSH_*` 变量见 [`scripts/install.sh`](scripts/install.sh)。 +安装器会将 DeepSeek Harness 克隆到 `~/.dsh/source`,把 `dsh` 链接到 `~/.local/bin`,然后启动它。再次运行该命令会更新源码目录。其他安装位置和选项见 [`scripts/install.sh`](scripts/install.sh)。 + +## 使用 DeepSeek Harness + +### Web UI + +推荐在本地使用 Web UI。安装完成后以及每次更新后,请先构建前端,再启动 Web UI: + +```sh +pnpm --dir ~/.dsh/source run build:web +dsh web +``` + +Web UI 默认通过 `http://127.0.0.1:3080` 提供服务。 + +### TUI + +启动全屏终端界面: + +```sh +dsh +``` + +### Headless + +运行一项任务,打印最终答案后退出: + +```sh +dsh -p "summarize this workspace" +``` + +## 为什么选择 DeepSeek Harness + +内置功能涵盖文件读取、编辑与搜索、shell 执行、可复用 skill(技能)、任务跟踪、subagent 与工作流、持久化会话,以及上下文压缩(context compaction)。TUI 还包含 Plan Mode。 + +- **一切皆插件。** 模型、工具、策略、存储、上下文管理和界面均可组合为 [Cordis 插件](docs/user/develop/basic/index.md),部署方无需 fork agent loop(智能体循环)即可扩展或替换行为。底层设计见[架构文档](docs/architecture.md)。 +- **Code Mode 需显式启用。** 它会提供 `run_code` 工具和生成的 TypeScript SDK,只有程序输出会重新进入模型上下文。参见 [Code Mode](packages/core/tools/README.md#code-mode)。 +- **自指 Cordis 工具需显式启用。** 这些工具可让 agent 检查自身的实时运行时,并在运行中挂载或卸载插件。参见 [Cordis 工具](packages/cordis/tool-cordis/README.md)。 + +## 社区 + +扫描二维码加入 DeepSeek Harness 微信社区。 + +

    + DeepSeek Harness 微信社区二维码 +

    ## 开发 -本 monorepo 基于 [Cordis](https://github.com/cordiverse/cordis) 框架构建(以源码形式收录在 `vendor/` 下),采用微内核风格:所有功能都以插件形式提供。 - ```sh pnpm install -pnpm run test # vitest -# Agent demos require DEEPSEEK_API_KEY. -pnpm run demo:tui # full-screen TUI coding agent -pnpm run demo:headless "task" # one-shot coding agent -pnpm run demo:cordis # self-referential agent demo -pnpm run demo:acp # ACP server agent demo +pnpm run test:coverage ``` -面向开发者:先读[开发指南](docs/development.md),了解本地环境搭建、钩子、环境变量与质量门禁,动手改 package 之前再读[架构设计](docs/architecture.md)和[文档关系图索引](docs/graph-atlas.md)。局部上下文见 [packages/](packages/) 与 [vendor/](vendor/)。 +请先阅读[开发指南](docs/development.md);修改包之前,请阅读[架构文档](docs/architecture.md);在本仓库工作时,请遵循 [AGENTS.md](AGENTS.md)。 -面向 agent:遵循 [AGENTS.md](AGENTS.md)。 +DeepSeek Harness 目前处于预发布阶段。 + +## 许可证 + +[BSD 3-Clause](LICENSE) diff --git a/assets/arch-en.png b/assets/arch-en.png deleted file mode 100644 index 4a84c5e590a4b219a9a2cfdf343f1bc8eba839fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 681579 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�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�YY`+%o{}=&w@NEUrs))5d&yu{?CCFuw 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î#wU~F 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 z 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 z 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

    w8xKS#y^m*2w{ov!o-YvJ>C=CUKt(aPC9W1 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�-tRud3p&l6vFTt;aB8~aCNehT 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%0DgcyZo(v9DZ^b{JM#!$zjX+Og>^Fp9+| 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�QsQ+%A`-h+zpE$baO9ARD@V+|i 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 } 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 #E-l}YaHTiA`y$r#7Y{4-lz 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

    rj~+V>(%9J5f=#+bqYOw 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

    uLEXJa!}6OB?4UxyK3 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%0Du2QsEjX9 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

    k=dTeR+sOt;T?3VsHA|!6bcj*C1^E;$N^H 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 z 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%0DpKO9?vxyzG&v5mKeDV~a;EBon- zVYquZml-eb@daB)1h;r@bg|s&h_Ce|;Nnhx!D85q3q0cb4Fnrc=T)Nu1ppsk%-R&o z3!_{UQGNv+Re(N(+s2FuxAw(m{VdWzj(@=w9E>hoN-0ARofsHxL&N;SuYLOH=FJ5?Gya}s7rAbeo1INv zP7f`=uHPD&Y^#aGJRw5}&0BE9-C0KE-_|_Y(T&&<p zvETu>MR@Wqxd7WUC*}T(n5E`Bc@r%|2+l10y^s|2()FCQNP{4jTGlLDRF`zwwr$?g z5b{Yv$-tmF1lNoN$*Z48gxzk#I|?H{2E6xl8ta(T{1|O}JC=B`k>G;P2bAz7)ieO6 zu|FlNKH^zU2R~k`yKu_i>+ZhZ=ldkc&TmZwh3Elzt1^NgwOrb!QuKv;1FjLke)c0m zadh|DA3DDAm9L1B3M(&R1DtpZv_6s*DI8iv)7ls;KSc#})9a2!^2<<*SJh?ixg(ue zoI8yHHbJrJQ(LD{l3n6b;Bar?UW=fq?%=i;m33+hUi{RJYy+80Z}US90>ZVLWUjkn zAU$I`UCt`&=BiyG^i*kz=VL-pdVigWpdhCTu}QW$Q=%VbN#bdrR>=D?zV5NM<8)|#gtTD;j*0G z@B(z(sxtQk>+xy-l`H-QS+o$ZrV-;1W);w5+MVd$Q)%qcw(sJqu$2@l? z2CW!KA}~?7hC1dNuvCwQwQG`0oA;$3*GBh7kTx6Kxf5w^&bxxtC>=ZQ6S`2^B>7R; zG%~OPuY3{6Z~hq;d^&uz?jvO$IaY-V(LyT>JKNiy=$EgYDV*#!u80>S@0hW-Dp}1C zWoc$I9UhlQDsAv$GR{H+K?-8&QN6p`Y0!5rP3t~MkQAynI=?B_&FOgQ< z$S@uw>dUf?X28R9Awolyr3Zud3cc%Ed4Yhb^>4quaYekXz;>MUxbf*Jqw!6=V}U5* zaen&WsY+&xfkjr}Cq&<1`ecB1zN^*dPHu*Cp{|qH7yg3Br~v?b#~|bb0HDDN0Dz$Y z03bo=186tHQDbHa4kcxcj;e72uu`09QX;cZF$z;mX)07Z#LAc}lC(Y*+<|Y>G%j0Q zjRFVxjoQTcY24|xsGKE`o@tySrend^|DqpXs0z(x98|o2r*`ta!tK`GpDiRZyKr08 zNjqZ8!V&{li*`hFz`Vq!A}WHx1xgN5m^BGLFAlxDI;G(PY)qiK(wH9U;3J7*4p%5x z<1dKD<#QvK*cP;UD>PY}4fRp2jCt@!L9TQ0gCy0tDv!d5D!Id=+ffcwl8 zcpy{0-5VL7GUPG1al~_3G#f)0ra{K@7jCKl$U7|nUITd4ESe_Z51>+}WI^>? zERd^;UJm3^vs6Dlf<{8ZejenFS{GAgOC-S@Sf>r~L-q$R;$k0Q9H{x;5Uo9f-DF=1 zMKnf0b}p9yid1xW5*L(sQk@B}yPF@5dIr|~E4!=$um(1EH$*Eq%^MoT zPG7?a4ndey)bp0Kz=4e<$6O9krBfTOStdibI%3}I@cBl4IDrC=CPH`Lll?v6ZI_0$ z4y@5jc1)za^|wc*bop1gmqd9gIf7^Q0wnxZLc5#$lN5G3hL~-YI0+|KIU}2E?xUQL zQ2K`^P-n(E+K^ANz zUsHGu+IMh*_2JU91SRv;-A)lJcS9EpX$&b87!p1woYrDFp##gO&@#>wEx%$FBKpl_KU%mO)4AwCrIa#`bN74@n&B>Uo&NOhbFU@}-3|D9qB5Q`_bI zrN9e$mXJynax-A(XwVf1nH=$prR@XbWIBB*4ocbh@voc+VlGU)rr#+h%~kX9AY$mu zLsu@izsRK5MLoIrP4msQPj5sl6YR&%y)AUnm_6hK{9D~^!$xtBgI`1k+A7WraucsU zq8r9r%NJ7IAIjY;L1niOmiXZ%XEKzCGJ;QfED8;blnp(el;N?FIH%W{$#<-A-a9x0 zKjk&{f?)=9Nr|Siy=;9-4X3mN6C?F0Q)jk7 zUPtvgl0c*+Loxh&+OmMk^-3AOnl*?>r& zEnl*UbAUpww#c&o^woL)E`zdmfRs!;pWnU-h}uHbCUBC-Zdu(wblEG)9OhChM}fXi zUW%1u5wzFkiq;w7T-YHqe8Q(59q5ojG|sOYv(gN%h>>*DW!zDB`uh8ouj~0t?)qmH zs1^fDoH>(J5b3!|P#XociK#+)-#r4THQsI64}LM4eJ{VV*m#Ctbhe^5bgnh81K=sh5+5Vf#8^n0-(G+|@+$*CUZGX7SzO z%3w?JxwdS_s|*|5O#vh^S;EFx>1W}#J7)mdZ?h;GccsYQ`fJ(#TnRi6z zx6Nm0o$VW5;sH7e5Kz7O0a;SmKmmZ~35vG|^}_gqP3?7i%cDG=Hz7^_vy_fQRBtw` z>e@SZ`+z~WzTc>}r(I1taV(-m^N;}!1lzJp)oHpzDtjS$|1U%baOifVUNetO0ci{x>DwWEwg8eZsaYMHAjXIQ@T@$=;HoH8qkt z+%P>P4MsDTzz;`(hG4G?RWQ{)mr5ShLR9z;7DQbLMkd(I%Rts6$XDQcBVGkD-Cgpc ztrO$JYGs5J47bNGOZG0%De8B=2NjS=+*wvK|MhH7w|rQIY5jYdHKtvf6Y0m#)S#Oq z)*-@ajGWbmzJ$Hx{jOZYYP@+Oy{&{cNPQl_d>PZtIvGFtddy* zT=_IAj=9mfZ%|gm#$dJ4CwsJNY5t2%bE&+?t0;9vuY7ax*!9G7eRe>#57n58XPiW5 z6G^?-H*0(msOw%H!~YZBaV_i#l~PWpN7D{m3TP16IQN3Pz3b)%mvZMI$2^3&Mz2J} z2ZpFF(SNN9ngShX{^wupns^nrv8Q*b@*5s8)Lj@xCH!CPR~TAQGi+ulm)^|KhiDR# zAX>+=-y$t~FgO!%;H)T#3`fq47g@1NjRM*{YP}(_#B10rw`pavN`3t@+67&)?LA zTj3zMK^4qXmQG%X*Kf(kgETERo?5JUhSNk>ua$6C` zh6(T4e25=QSr*$W<2u+EEd-ZXF0bF~ih>7bNRBcew>&YGGXQgS;xn$d z(Dk5EO?gkIkh~hm#mFPjOo$}N?1x+SZ*?DHI0f4$A^>lQ86 z_)9xGA}ZSh!NfA0_xhJ}rLgnor>;ze3@LEYDL||Wlw!~7j7IEAyI)~WfVJm5RW`ly zwj{N^TGbEL`8CH3RdSP|<;OBq{~L!)#qNsQ6??A6DLr7T=8p|&c)PG0=lvB%GZhqmBr-wr3thx4@jhp#J|Z@&L!=% z<_oz>!+b4~*TR>TA~Y2F8juOSEW-_IHKrJG&^dH3>BD<%$Yx6=$C{S7o}wHnYB{7O ztR27fTprQ{GbQWtO5-Sj!BT&F&{~~&FSo;+Der@DL+G_IIchrY8k{r_^>}`R zb#JXR{M3^F%Pe(WFtg9JW*g?Bl(O4%J!i2$jXZjiX&U{PT%gxpbo?1(fB-OR=+t{Ko3vh6U6hFRU?RD*Px32W&Tm%&!gkt#B$XpmDbE`sooso*(cTa2i24;d1^_MZ7^*CF`*5(QW00uqwvY#Pn;n%VWA zv@}x1S599En^@;p(b7Z-Xz?91PvwYqBv*=zZ+Q)4A#)l$-b6-Yepl6T=FX{6wje|2 z!zwNtHx8E4xIv3vyzkup_2O-UVp^~WJuxWvuZimjEW*i@;ua`E}0}Tn$yR$iKmsStgB0T3Lrf` zp}LJiHm=wVcwk8F;ozZ5r6s0xHTO*aKaEv;Io!obyv4^(esl&sEIaywsVcM%$w3tx zin!9kX6b+8k>q7z{?dq6O?-FOj&C2qu7T8Pq?yXO;L3h-^SC61B%bL{Z(W0f!_I2 zMqp+xcH%Y<4A9_60yNSDd!fw7|3YsUydap7H&&kzP3%^pO#HO_azbTk7sS}e2Dd+H zD@-!xHph$&vw@5Rw=HVySKN5TJkT9txXBNo#rPRE6LUef;%6YeAW{(*ggxj8KS;CA z?=h{7paf*wN^Wb<^e*hR>h%4+e}7+15QUEq*>!+T`gagoej7-RROIyw*tWAtENYB! z7UQy3`?TfnX6}&uUO|uLADi0fcAMURp@u%5Y>ctZP6SDy7*gxFs{%Yv-VRj=55ARH zI+m81ozmv%)1Rqk{hbxl_nls z9=zrESU0S{23O#JtsH^>-x07ErO58AW#~`aV^hi*l&SL(%onaH?bt7X3|8vR3_y>- zP(WvoiNI>r`oDIGx47??nO7JtNopL%ziXC3dg9>N=8jpj{F|R5+#u|h%&w{5)0kAW zWWAiV)b`H?D*o8&6fIqYATzI}SSa_$5iC!;=dyV^B<8%}4Gf?PH9TH?Rx=<(5%hguf5^9D{U zTP?_(V!eOHP^Y@0Y#W6mt!xeZhziGN)r@IeWfDE`sQ5N6o#1-Mw)r(fKx?@2O)t;; zqb>+8suK=fE`ngRN;H7n<3Fr+RPmAG51@ZGZ?Ow}GE$xX zToUS{dhv+vR#s%cYax?LZj9#|!Is$Hd~}?R#Eggpdgx_#o3gx=u!$6#qWyb!?8ehd z?;bQa^#__qC7OTDcPT-y3&v``>g3YC0b5HvB(%uJ97u=ksR+&4DogtErRraQfZ}n1n}oJ8e{~YKEhvH=xxMdijPDbG0h`1xvn+RRy@Oxzf|K=)XW8UO zhg*G4BLCU~{YhOhY16^H^xOZ%XT2jM0VKmQ6~&74E@tLnWS*|F5%5R5D5x7d%2#_f zvcEwRo=g*wGWdU$DrT%YPapFwaN-TT@`x~{zF=_%mc6cGx(-8J8qrsJ7_B64C!V}8 z>?I0;-$PaLRPyO##i~Q=Yfjv878>WRSkKE`TJ>q$#QbQ-ATkB46{|~=4#f`Z{fj9= zT|KuiIQZB?Yj@F2-Z%#^^CHNF zOzqhgsy3yxTaD_4VQfoIydT2bY=n1j;20s36N;0<|HP7SWVunn$s8>^N$NIk0o8qu zON5SSoa#)A^0DtqkQwIDMbj|Y@~+LFuLndiq;&(#I|ZL+MuJx2%)E5W;hCA&b~6&m zr9-eg<7{gUy#h|6f>Ycuxuh*3R$D}j+H1blQbw#KLqHN*P-l)^>008@! zN$ND5#WVJXLlAXN+uXToBgNKn?dGBHI22B=N(10;9;ZLeNbNu4cRC6M_&QF!$%epw zRqQ-AAG$4yvP+3hy#?76)WWmIEK0v9YK$@tmcv3Y<03! zs(j21E|OMSxDVIu%uJ(&{4Wb?=Im!cf>>`fx=>HDIH|#i1y7o37K3Z~h4M()jMZ>V zJO!H2)9-4`AmnGrHHo#@;z9{gR1r%N>7mAIf4jPi1jJ%iwZ>y6NR4n!XalR3Lc?k$ zs+&i}#{$R)WSH#f40`A0bK(E@p8dZGEuHK`Mn?HE(2BpUw2>g`Pw=4KyxXq9nPLus zH*yvnWxfcUMHDxw#p#*+V`6hVX=s=jF>0<15tvNX?2Eq#FS~)&Az*#%z2_3t`*VYQ zIi*;F-+29--?h`k>#-Rs&yyl?LwiIIa*G&*%q-PR9YeAo0blVKK@=u6#6^%D^we-;4SDUP-u;T@lDge^eIB%Z|{MiznzVaB2)0>T% zRI&kG!rFEf%XBBfg2(Xp^&Q{0S_pw;Lu{_gbxGP3p9#BxIYrfqsYL>q@B_hoFt?H= z#QjX7kW845y_q7FokVcfJJ&^Uzaii)7r#L^9Z;5Ei3rFGQp$-{rA%q5-Q3B)I~qmH z)yK)_0<4&(jHh{8@L73fBmq4o9J^oTKT3v1FIb*{9T0l`NG z%5u~V?tyo=ln6hiijWz8^*#(bnuIyJr1PY>dG6(&iG3~Q#lUo*fTvHwF^<#}Q>LIlpR|*pTSMdw$Ch|`l*zC>ieb_Ll6^WnP1BX6 zAjx{R)&9#MT+9Pr=wS@{w0G&?{S8ZS)18Jwr>de(&eLYUjIaq1u7L;E@&|&lJH7wF zX+{10bp0f!R2o|0s01es@en_dC6!3U>2LpIc%Qgs#I}TtJ zD>12Dm0Q|PH7#td>nqdVaX6YCX?cYrTgOu|63a?I(uSekQN_duu#EHpuB9&hloZ+{ z(I_IQmL-MJ<8xGOGwJ(Le5H*LPgKxP8N!mCPGe~eoxXB zG$(!|=>ESvDFFm7pI=U5SV|h>6#WLA5QP^J)SP7Sp!EThTom!v;?%t{sgf@_P)!YzgR_uV$3$u zU}zH8+-+^Ks_KjihT}$;b;S4Fur9f6RuB?4UnM(0!A|3S=GB2?!F8MHco^5M1TY6) z`iY_C}wZ1NcJ4^}!bau&#>8l*g8IhPV8 zfz!!V4v?z^)}X1n$2%@v2*A&FyUUZ(-9TQ%mEyz+@itTMr>+ z5`|zgJl6&koxIK=$%zCyw@?%7F=Wk9A~3q^iM+>nM^7(o{&6y;1TT>|NY^;XFU@;i zxT!%fCSzq5ekdxb7ockhUy)5$N`cL8_dBW8;#aYe$p}-l zQM`ix$i=Y7<4TaHE}V$NBAqGv z*wY)%n&MihEWnT9Ono#7RdF2Y7lo?G5OERq_}IuhKC(rlRdg2%DPXcN zm}15*#ivhNTTd&3)iM9olG_`p8{IMI&7^mCrlkz`QK9i$ko{xy-dx*i*HW&j8s3Ge z#GK;?7KYkq^rbpzFsUFeIfg{5;QEuyu$ zyXD7ABIz-^dBPR{E4h*#bjVGZtf$@95_)0=ZczL;xaDu~OX+qMp<(gO0Gp}+Bt z(}81XioWKOIzG!k)2}XTWt2GuBCN@dq#mK(z8a~}-{2{QiJJgXy=8ERSEJihoTr0v zgI47rMMS+?NSieFhz_fEIh9hhXyfG~N0eiqV<7_)Bv{NQi4YhiGq(AO*-8hTJ*gJo zYS?4Ol)4No+~3}OKlme=Neu|*7C=1tlMc#wqM>s(<%|lT-rBaHI^>MBR7htTiSk!0 z01_-c)Bib@?a~J|x3NM4S4UM`*rJbpQU0|p6(i7)FL6S4Kllq z2OD@XKf~aF=iAS`PQ� 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 lnMw=b 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 z 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

  • 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
    w#KR8big7umw;LCqy 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 QI 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 z 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%0D9W);70W=)UQLmIMEK-IU%YyK@a?QrD! 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 z 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 f%%e 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%0D^+thq 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

    H8@{6kVU(difX_NICik2#(UGbI*XJCl zf+M0I^&e(0|C6cX&~kSP`2D>73Hk^9C!^kI0$2Q#B&6|sa%=_u#~76u4#gMj1>d*A z0Q}Kpm5JLlI4(;b?Jh@PH4n!npprPG3nTzhFcX3p89~b9jmr;7XUVyr3;wZ$X__Z? zNapIf)o%c>^#nIa(egABDw`hZQbfMkJi=)|EcavIxw2Jvwf9c1=AA0!`N)y*B{WU7 z1mcPfRW=|yBgkqls#WL$^WQsmgcK=UvI&t1TL%G895uK4k(YTMou~S-7by+2$>_B|2*9!vE_m7@rfHE`sjvP| zA}--MkH!V>xrq`Ui`%$DxrY=I%9QODz_nWhePu^gm*S`#Z&~cGE2<}H(LTh2`l^%p z@MTXeiPLFUq%jIy^vO}~RE?ysuBMN+x=$;ihJs&nmLD})-v2xi^|_nvryi@F3Owe` z{dHE4f2#yb?MPbj4A9GPvC3%L<0nXz0^ z4$FynO{K3AT*c$t@)Ki3_#u*k;(Yprl-nC>p@@kiiw4>9WYR?*yq}~I z^gFGKMkWY1{eK6A_*&xn{|Yupfc2C$?3J?Sjaes;kS;p6f1@uo!FIm~^$6Q2Yx!}B zvd{hX0qZna_37{Ufu1^wB)WN##$kYpAQDGsZsrlTf`gggD_u$fO*};mxP^lhN&>BH=iT;JKxtAkRmBz4Uzd&>ByjM8%uzA1pE#|+961(vs{n-(}MbLZZ(5`ykSx|Lv=*w$W{fshf)SNA0XcvY8>LGi1JigZM? z>D)jE%UL1Kc?bOBSw%kzOSO(9SSFvQ5b|2EkBK#h+`fjqpOY6q!&N^eTlh=+l==8I zC>0J553b__RNs}Zd-i=nDjobm3o3EE)^T%!kdX5;s%3Y&wFcO#~N!sw-TzX4lvAS^}V@yKKbu_>zl> z5{GzUiqA`OEIMA1Y#vN*YS!Gp`Atz4r4$APn81FZ`njn1YR>1{O+;+2C0I1x1^TZL zn&n~6LGKJT*Gi9zxR!DBX?8ZQno()J@!rk@d+rsx2_3kZ-Z7ylr!**J?tg+hI{kO$ z13AOLh2ln*<7*uSe{{V*qsOfaJ0G`?lBlWTAeJFizK{g%4;My+VRCXhiVfMi4)vCT zYkzCjzRp;r7IC?nW2B1aE_gsrPeBhn+V$HJUuMA5Dp5q94?2BV&a^jiKmkO*02yjk z9H|K}4Hiil=%pE)L&uCXtwKj+f%(c}3sT(XM=X{1sjeGcAhF47<-tj)M6UlsKty}% z<6IeooSOGro*x}^k4LwYtb6$XtjTwEuQP{|K|f!4P!`$!!!+pJfqc4FQsN&U46>52 zhF^N0XRl8YC%knPEHd+k0$V?9Go%C>VC^d1a%*gYf~YO^Q=o_of=K42EU{6cLd}yB zv~S66rZZ(3s{i;b(Rx~5I$W8pj~wz4nrSK0$_Z;~z=r&ARXX>qt63u_WO|}oNXkLE zn24F3+p+y7DKG94YI#o~YG+Hfk<1jXHL?|hEeL#AFqHj>!&i3UC<;3(DyFD?96Dez z1=?T`) zaW^{K9A?1pEFaaNnI406i+G+`@Ha+`4})rU0$Ry6APp2;Bos%$Dd!jR2%PY~FDo_i z!yn&EkMqgv-myq$pzLV>CKe0!o_q9k+(IomZp@kqZJMhI&IgRubo7s4k_&5JWj@1W zrrPsb#Kt(U>>IUw*N+H8>Tb`Jujzb*bbW^$^emT}Q6mNG2pN2RIIj$+<+?%xfm^Z{)M#IGSr!hW+ z`k>`@6=|_2)P-Fk`wbZ;Z3)DNzLAS2^1p?a*VSipaRxw{s$E&h^To6;b@((<_|Q%K z6$fdw*Xi(FJ+q?KR+tJ@=u-zju2ON{DfO-rd?s>>+izp&|g7d0Y8;`B|L=?(x}LN&jh}nzn8E z!r{%GM2UY1U@PNQYDVNE!QL$Lxe__If7VKdylyUor97I1AJ{KSi~N5NRd@$irL{+< z@Cyq`gY?HeK0tgv&uI5*J4?SM3bKU5N?1J{J>_3b&L`>^e(Ay~Qc<=R}sultg0dTzs zNntRJu32|}h0I~L+s07XWuvM|Kb*j*KRX~;ibzsQ^V4VBj}+gkiOquQP~z`(cjLzS z`gmr^=Nh4dFU2{mQd`mXektq?HvIyB${xj3d{+v>&?nK7XM}q+z_jS|ey&|T>j*6r zvm-q+uQUJMKO0kDwPudEJces9pOdo?3dBwdR)Mf>AlYL(6pE)&kdat};2ZO?)O$2O zhN{ELZ6eBy)L|{n@AJnjVfIuBXw2?{Zm*>kWiY6p2Hg&YxfNqHlr&qKWyY0AzZjQE+^vO{xXvQRK=q4~*# zD|dmN+=%2toJ9i~6t>}^hEWq{jx&VUhsWWc3{Z8{V=~@O`3mt)?+of8Y0!`X>n+wiwxpwwz zwZr??bq|q0L)9?D5vh7k->*x|LvUevEy z^D{AJfQ?1aCh%*OFEn`Z*XZc7ew`J&DuJul>rpPen2f)@)j9-^aXF zidw-Vc$}Om;HzoPjn~by7tP^p=+#7(&jAVE4L-W&HPq zc!$+S&Ny=p$SY>&O2=T%n~9`WvF9cGr*s(MjBXiGA93M=oS^_L^0w-YY5zV4`cf8> zeVob4M&=#J>eRfU)78`(r;A@k>@wSthskt{imRS}=;bCTx~ETca<;5E_vCYlGCEyw zV94iY-y^IHQLzvD0*1Lw=lP31Q|D&qbvP_q5_sj&hI&0w6RkhnlgDf4B<;5p2iU7n z)Py6F6)bsCmL+0iXi37}s$yOh2#rZU38jBw(|(wkS0C*!#)a?+BKSO}CE}3IH^Zn( zokDC}HGtT{qMEu}08fS!yEP*eRV=I^)%yhBNnK!>JN|Cl_m`d|WUOtyZCpTJ>VZ zV6@W1hb7dO)Yk*n*Bgn?X9BepdX`XUM5PJhEV)Z@X!mJYsG=}}n0YR{a z<2bX_4ex(8>KJoy(qbhL?TVTnJtvaLBpPIGFKUIF)l9#XOP1G!)0+p0#xOB^u6SGx zCCqT@kh!vJty?`^#v)q=4-*rw761w3e?kLwQm<#`2yW=7i~sji_oYy-e{|=1frDpl zX5}C?*}rWI2UwiNgJ7(2XBuXpbygMRKSE7fe!D_Q)V9=5NnT2u9?G)@yWO0_*U0VK-N##Bm~A zi2JcFB?F(#dulyDncAIdt?Y-sHGL_|k|5s8nv>lF_DL9hcEhmHj;XsNb8Bb~b}K4& z-fHVrTxM@EF9U~IB{YX+#(~Xp0t2U*R8a5^$cA)MA3tf`hJiRJsn?x(9Ky@hJha*t zzKL@p>@~@nL1gT~JLlmey}tBCYjhq-&(|9Iw8I*l^2Fk2UI8#Jsx+LG`)hKSarh8A zsOuflYYKZii<}T1>9{zr6vFtp`EuvsI5VSk*7fh1aF#!(8*2TF8?Dso-Q@-7V zYaV=CK^SIcS(g(R)5n-KkBw5TU;3>-A2W0PYJNMR%y!Uf!~`G3^A}pa$QE)&!;Zp% zF&E)vPJ8`wqj4a2N29>?SRY6YnZQLhIpj*1oG3TxnOpz#OZHB*_|LG>Q7C<*QH|_i zv_!?P3DjgGKhDB6VQTT~Up8Ec(*o*3!S=08k(+VXLMichWxiOXbuJORLl@{3{M`Kr zz=5MkYwlz*qh$98c9O_uu3wvWiNi>s29ftOQmS-Y5o#b%jKRm#kERMxqq}T+6{Wmi zO5332hC0VA2CTsPO`FqPqY^Wmfxh=|UOlB0Z?{q3C+bzLKlb&;lP6p4YV6jiy4Ybi zDF$;v6Z!x)xAu6bAr0<~5?$2u{sNFMQW?P7B9yPlpM!Q7X(#%BDYty`6p<;-I=8oP zw1>m&Z|(6*(Jhd=@ds-4QZ){!((C_r%;E0eNWhb3!>DcUK>K(tcmIsWS1pDQ`QAP> zM_-d?8pBqs{CctwKId;Wxv%HX(-wvaVeAEwT&e5SbT}nRf{U*H<}!N$v`9-!ury(z z?%=G#XPVY=)nz(GyYR}`y#!Rnch8M}sQQ^~jppCYg$$&X4(e*zq-4jIGEtKqHP+hL z5Ax^z_!OooHM@aZCN_NFIISWwVKHDcBlVv^ROr`AzbxsVlzW=qkx;@))?zWzI2q&r z7*ZbJ@!Rb=t*)yJmW%}07I_G?O#wLYXwQ!3VBhFnw;aI~Y&vD}N0#UFgZ`f86;tZ` zEacsu!}jf?i(3b6@^qz5oj4|t+&ntuRX5Sl3(G)d$~X4o8p5B#w6TMGc(K$QGei;Y z|8vA?qI4t@6GBl29)&Hqa(Evrx8FdwP}hqiog-RD9?p2-gHzQcEdtH?lMFx6bHO*- zU-7cH$nAerO0ME%jo4~5@lo9N5kv>){3lgiEDtbHAaFz2P7mzRUC#J&<%u;3n{agK zmSWVD@m9I8o%VNnzz01N{D|}f*Z_YCgH6m`cDw+D{8|pJ_SXRRgF}4~n`&;x&=%61 zwicA5FjS&>?IqOfQz0~+N`m-p?rElH2ICLN>Xm=(HLRNudPfSTHoE9Csa4#8C5z3n z8n3p$I@SVYYt7jN0mLVS;m3#63y7NuL{mBQ$7goumcRnN@5F6k^Wf>puq=vZYW;~t za(Ix#AIa0MoBCneJ+mHFCZ(dMT$8`b?fog(@BG!Gj$S6egSS8s(V0m@xIV6O)4-72 zEdqC*w7KYlZd>GGU>_DGWW5zrg@ED)bD>u+Jc$huA37>+`e$LqyqwBiRwn)be-`bH zW5Q{j^iD-_9G8UbE5J6X6&@x3qruEk9pHP{O+LSSW{tu~lJ>_&c4GhU%reddI?I!( zR-lvjaKNrz#xrul-ud(9|EYg4j{Br`&pY#efi#c`O5uCZeWuh&e^ECC1!K}fkV8&B z*g6XjZEX1Nc48mj+sXtdp_SFGFSvU(V~J@_L`J12TMa9wkG1)gl}=Kk+(7wInJ(Oh zsXoHOa-RMp(dS+1Z9u~@3xE-3mKpk3dC+!_RPM;>Tx z{QAw$Ls%9dJ$)jDcSK1B6rN^nH#dwbiCuPr!8hihO?FJ%e8lHZ5rSLegQjqwZ%lrS z(3LN#bO`Vk*ABES05k5St25GG8z#6ND=GS<4Xt2_q@0eob4w=(wHBYX1tBZWsbpp_GiNkwc29+gQU)w`qUmr41Z-E!#23qCZpYU& ztKu{M>H2w)676f8ZMx1eztIjLx;k4Z*adZ)<%|2zc=IL6RU#oo`gn~)%?0aUKNgiYz|`ZDk3jP;qv5OzivJ|S3*vJoID7&47?3oS%*ZWCqa(aJiyKBfEsd(>jWX% zWhe8ja@1A$UK42VmZaaS9Oj^Wb9HknF61&u@uDVN4b?KZF2HOTXOI^&8-*&y3S^H< zr&oZRnAbCO6=$6a&zuq5C8~rxQAp*SF%I7djd)U5f+y_fx=$h#m$M>lFSGxw-wY0mfdzBoS7NP$v^N`7QK=74vfSo8B zehZOfurq*#-+wM5_K~im0Rj`+>RGgBt_qVHZTRC1S7Vz@)80>{cEsh>H|^LigVrY^ zWC|{E8ZbwWVB6Z}V4fzxXm(9WsuO6e+7*3}`poplb+JbZzrc~rMX6aju17H*oaCe@ zcrq6Dmj~^UQ!qL46Fvp_qY<3K%mTN)!}I#xKK{HD)-SzW&^_X4PMtlQo%DZ!K7GI4L(-2Ch>P}| zlsg-`LZhl-8s~|v1#8OoYO(}Alrs=*ALlJ@B+OrDjC)CvpbFoHUu4iUFESxIC7*l@Y! zPpm{(_IUv&=pfjUpGtY@S{o|{ansy3o!S@|66P$tqIduQ|Nr#AD7p5Llz)31(j>~A z#ee#M_aA2bHG(9Lo#@N|{X0#EjPKZhW)}bVmbSh?_uTiY;j9g2$^p>lqESM9p{?Ql zSYR+SCpr*hVIBtKypBZPU6VlhG*$1mzCuqESDNFwCUusW<@-j}agFBezbQjX+F@1Q zRl_#NHOy1Lru-){}n@w(Yp1~26 z+th#69rs(!)uWrJXG%8k?RBj+=HprEhCFsAJw=bZF(f>IRZi_&_$Gn1NW9v({Ga+c zw3%Aao}e{-$Pc(JwGamJ8-_Fp77*h7DKQJ~Q~)b;;TONqVx<@CI?1D-YNq^9Sre$( zjQc2lzsX_ulsnf&cp=PqEzrn+BP^6~0RcU(&cTPPEqGKUzRX5KrD^ARlnY!MPbsZw z9|0+KddEGjI(TfG`hB5c6_QHS)czvp^SsyCU};W`3`x4Nb&kvb=Aj*{D$(~vLm&h+ zcCO7Bb=@|pO891W2UHr2Av+Un2aS~oCi_8?pSt4p{$ga?Tjk?8nEaG!nfjN^DfW1i zS{XdJ8_TA)TOo>KFUJ;rL}o4%`SN`}Qkzbt3qfGfp%z?vGR2Ogo`Mn_`EKlO6SHo)L5u_X!^*m{^g4^&IRs4u@;l@&#Q%X z^|bg|=kuYo$+_jWZJpBtKSLg=2JHR@IfSlEJ*5ZELxqs>@j&D2Sa!u?Z7gGgN!lZ? zt5TMNKt`cg_+xPeW%#Jo3G2d;ShoZwNu}iA4l&`boBgOF(%HVe~tWCKs{$nl#7IT5g zO0X2rB5ySv3t}ok1K&2$oE3tErm*WX>^CKBZ!8(gD~i%+-vp)gQJUIysrdB>V3v7j zv3vUty{7+K3OWYIc{A8M3<{=3I205P%Plt6v5`o+;Aq+ahtx19J{tAwS9~IwnV^oX zav!hIB-T9*%yoqU%RHt>8DC0w%VdH#z9m2%hHWG4{QdY0QBNltYn+|>wSQ!PO7Ec) z7fyz~NO6u%}8wN!t*yOUcIaR`yjIg!ScS9Him4|yw#TtP=KxUCz~&j zE`OZ530_@YN&i4&yN63V;HCd}P*mY5wYCJ-%vu18gUw?(sb%=fyT#+yzP$&m1FhxE zwF0aupx4t)DBPFENy$J)?|X^#MY%P%FSuwB{=TnubuCGS6 zauGe{INgL8<%yU}xNFo6xvIWf0VV-G#1v6`0+qtDTB!peWri-(%orLlBw3>$zO;GW zN;WMG-3fq|g3?g7@SMrx(g?ipTD<>d4t!^Zy5(kF=qrU!eg5Oj#9H>7=+Efm;ve{FvKge-0XtMUhcU!@-UOmi6 z@mU#1=j*%JN@(J}GXPLF4_@cGm_%O?LRlzd02*4kq_P ze=$mfyzUxbtG4P|0rxuV6O-6U?7>!iow4QDyNh9+BwiAXz2`#G0RZ>gVrbOuPiJ2m!Pn=Q=-?C`l$e zV}*$wgSi=cW#XP~rYZf_3}R$Fut9Fc>h==h{qF|8QUT2cn^y!(D@Vy1qB#0x>u3tk zogmxDlt96@rwkL*jmDO-zUCtphgij%q*tYS=MHlhiJtD5)9`2ej)?-@^g~Bdb)0s> zVjj+Hm8-e|Y_CA!oJFnm+@i}~6U)3;Y}WH}=RRtPGI?^$U5M1%0%l-^p0OYqE5YD9 zrDk6)oFO1foiV*?tNi){5yjXXB~RAC30grVzHuS*k5xI0vIy2C7Aj3u*vx;6Bo=l+{KQupuU}E;Vs18B+HhBWYnlI zz7e%(EGKnzQ=>k`eKZf;Q81N8)OQW~3qh*HZmnm{ur%^Cp(o09OM;Xn-YoLp-DQ~E z1MHm2yR5=hB7KZdctfRUe^lwGJF8SsJt}d4>A0)-*jFuwM>s7Iuup!%_l^Fcs@Feg z+0C(Cn5FA81bcn%=8xN3WUb=+M#mr6Sv@{N>DC%scifV<+TG8yJ;tt_N7v6y>=`u- zgq#8_-d)WH_M1RRSBp=M{>n_{{(b$}@$NRwLb>)YE!y&(z_H#6xOiX&4RRCT%}Cec zs3VIFj?t3JtC@nP>Ztlez~{dMoez$EO_BJPxi^rafw^10xQ>uvGpn*lm9WXwBaZq= z$H-=P^cutgEhE1FKseO8&suPkomoVy9<9i01XwyNL#@&`;LO|3V+m;8D(Ou#HmuF; z9Bo}0=S$C;LJqAhyJn3)vi+03Xdm#_)dG|K{s`RGe2exXcWs=lTx|}6$8M<|1wBu; zdM!YBFA-DP@5Y2R4(wz?;Lh!?yqWFa+RXp_RI*qleRU=sK@2D+Y*YT4+GxRqIq29syTbw(U2y$}2 zB1P#@b$#+T2cDzd$>_Y?M}=W4OZ@Fun$#VGzdpyrJQqY>-8$*;YFSY2dmt9}aq`kNcZ<3hl{a%1@6NGM1l@s9C^FEs2R^S-fcl1+c%+wY2|U2|})<#XM~C!5J;4D2X4;J)%ne zToQE{XtJ{^mu06HG~=`mIX3j-Q1o@A9L#XaXk}WNTZXegy=n@}`;wp)&}kIp2Kmi; z;$fULX$6va;ZIB|pjsc}r8ZE{bj>_p{rJj3DS97+1aJt@P6$!4l}_<-fpcEvQ1bJ& zxogb*tJF(1oYn&QS+T{Z4Ox~AHMSp*zeK^|C*|e#QJ~lWkvR3hN$zWi1fow=*87HC zh~)Tsy40Tx{q8RA2Vr)^nkL741#hpV=ol99!Yd+fuieN*gk5UTi(`t!alvmdgsZ)L zUxF%lRK58#0a+d^%Tm3qjwBg4&CER-C*iqSqRoHi=I-`xr$dRRJ6B{`tJzP9CLd(! zE#7<4E@oa&XnL!w`LQ0K2zBmRv3|LyQE9{m$x047{>Dv16u6OuPQ3K?z%)2Mr4*YW ztuVRz(`i`Hni5`Rt0D?Fm9jAfW`6e(HD4NCj(?2zl_a+vcEh`8MHrO7?a{-v=x1Q6 zJh-WEjA+Wf4^rvmFbTsgSv)Q+V>O#fsz)gDZ5ot-fQ{1JOz^hr4A@TgHjeXXR`w|q zwiYZa6rj~{jLna7v`$pBe7BsR!7j;W;RVObWX;i0i1?3`#AQ0Lrtsn%%T0Ug;~ z34j^kHgtipoIl~1&l-NHF=c{gj|kj81hoZwR6r50Br9)I7D9~P%%!8X?K2FZAPG#l z7G7ykv8rw`$+&Xbss%w=k`Oe#2x(OzJinNMQ zc_QgMtA(obC9JjC(DN7ZdmIGb-b7!%HwtV+K^P^Tt6s16dkLh}B1W+w@%<`Wy4w(n zhK@dM7-}Ymzc0a7o8qpost%@W)&i_lWf-hM;8_1?71Wa_=n_C~(c4_L)w!HNQ=6S$Y-ORvj)|rwX36AjUBkLqoVrB|L$T-I~QZa!i7L zEz>SyNxT?k=~JYoP9MMjN7~vvBf{m0ThaWxGClc2-PcAmAT;%7UKye)`={1O)YU>e zmtBcbSCDX{rjZ~165G`bKFfrXZr&;`%aD?hPWN4r$FX}Jz={~8+zdcRL@|_X+un@L z1qjq=$W+BVJMcDd;+T&>MYVRJx0X;F7BnbH`8Kx2{$p;u!vhWB+FMp>AV7n*UsB~i zW;A~BZ^N(gDw&&mrs0Q1Gph^B^gcu86yDs1a74mzy#a1PQH$8 zWuDCIKzTrt2Q+Wh<2i-*jdvH-TY@GL`NLWMQH;qvzLJ|I$$wfRN5b@a_C7m!(KBTD5a-Xll3NJIFh!lPI}E4LYU_UoGy7W9tQpefTgO7t;F`AJk88K z3MzrK%;|GM$f9q!JRjB|3ePyL=_`_*s07kQSOz25Z`{T&Kt?dKY{-ZbS_)j_#Xuz! z&T_~C^jg~&%2$Pa%prSSH|BKHc0U4*l<}jp^bQj#{siD5;iVMee@gqs8V+&wYvMAm~LUm0>E1O1F9nR zNLA$JUNgXj%Jhld|JN4_=+svhq;94`3My@ZpA1)?p0HD9=~SGE2>JZI#0vo6(z(h; zRY9V4+(U`tTUIN?s1@wcY?SJv-+dAY1Qt~1PkPXI=ML^&7=<|O*xQX8o2qJ|tmo&c z7k$GN2pAq7uaic6_}Tnd0(0ZU1s6i@h+)2ds3BJeIPJ%O_ zvO0r@lp!~OX3PZK=1-~~P44iU4%+(y=?L<$>XJ9zZXoh&tL#0zOj*w|pMB#Lyki&Zyt11z>ex#B!8!lq<(ldtt|1mb(fYzEarzlow%~Cu zC6+k#MzARU2krW=@_gZ1M3l`^M>|7igIu?b7x@!F#;Mhq)#3SMo;$42dSdIReY>70 znfq*cJb-YLlCTuf=s+#ny{}5c^SaDrbGaU7(1MU<)~`cQQ01RSGK=+gJ@QL&HQy#HhrlHa@)9?pB&QK0;*D!RD&@HX-E) zI(?<5@|9j2x9lAo^Battwrt(gFBJBbsS{cX*HJsKnz_#`mDC}rVfQ156DSdjwHc?j z5LJ#Y>9%;D+AvD{DTk%tUMdKJkN}pelGGvc^abe)K>rh-#)28+dE7Cw zx6CJ|nWH;$q7Nz{;-viet2G%JB-Gip!vuF4sf2Kc4rUNdz#SB+6{W4?=hR6wDMx>0 zBt2__ou)NB{1@Rn9#nwlE<)A?g*^NK-eFR%b`gDI21Ss=Y`C9Yxckzel96Q+h zE&mgctgM;h!cj$8K%k3_c@X?!V&4iqaXLHkM}032h{cX!&o7BKUqUVBgc36)I}o|X z=4drbUaYi=!re*G;0Hn&bLbIBa>_PrCDq9QKFag&%%RC--Htgz7#qLzP5xHFkCKdv zm5O8y?L9ViJB`Q9FLin|muJ|V)naR7Yg)iiTrxJrWz!uEHf38t>%>eX+9#?^B^-UC z^%EB_wohB%(9gdWjb+ieMUX){+g)>_0LRbn9D)5JJD$_Ouq@bPg=PaSnSoZ|k-MW2hJ;%^OvRcKyLbVq0?_XN;IMr@hc{L8ZHm!Ra}7YO ztbAKb5-hOZk;Jeq6A(Fe_`;&zv>+o?99@56pAu`hg4$r+9zXxEnL*yc9CKalqBsi# z?VgUW%AjCypatCkr6RIM)|(AmD)mdFc)8nJ7Da=L4itu(RyTzD>$gU0dR3#ZsfT_jedKcD=AFOEM-0mKV9b^$Fiw> z0m1o6NM$&Ln5Wn1q_G!FBFa-GtrCQnTt#E?d4qdaCSu|1=xNR>`dc@dEANkPKI;xPE3l;bCFy{r9J7nihb6O(;VJWN1eJjV%LV$=VZ_ecKstC7R>-$;vKFCW=0v5t2bgsp(ZgxTK_Li{#BhydZ$OW5HMS2 zMcByJCIy!g>Snki0&q+%X?_?@QctdLjZcIK=};;J6bwdAHVFZV8BJ|wz&?>O@gojN zu_sxMX;V$}_e zYHpj8eHHvNf9u_r8_;1VE}lCE!zM7Lo5J>q+qh9!bV(-uebh6qPQQ|8vuUdf4?Rk5 z3I?eg>q(ayMaYTcVehaR%Rm$;fIy|9hyw$ac$p^`|5PMM2JQ{#-_SnkH3 z^5R57oH~5p@Fx4`9-7ymvaMl-$8=kHl`NxGm|OHcYxmRy+WO6!?reb zw(cdSqM_Q&VHl{InLaVDy=pQfRj#R1`7`Hkyh`onLxQIQ^iqxKKJh%g>nN@5f*=VR zva&GJ-q1JsTo{7CG{QzHExtStkQ}s#4yAQMc46zLijCq!K~x|>V;8@M5HIl{RJ_r7bnaVI zNQtR!uc;h;mW?EBz2LFNt@Q{G+4Jhpk_lF>cip57EKigJ?L^m6B1OpHZOt@?zp$Yr zFQw39V2Ivca?XNHy}g(Lo77HcoO~;z)8=tu(5%{94LLfp(;*tnUNn8>ccqk{K(L13 zt2vO~7Pw?>q(i?i$%jn}NhiTh{_xOv?{Mf}BX1dSxiUiiRjA=Usjub>nczImTgvi} z()t<7_Z=xSMS+-L%^0U&#S|Ez ze;ksBw#Lu>{koAM`|X}Xp^5>=#&QiiDelMG2!N6#xU_}B?MxWDm^l;y!xz}kO##MW z5uit&nz5I-!0I!oPY3`w2VGgkIy#5Eys62`N6cbvx%|V(4%fX(3gJIhH*!)Mg(hJ_#a%*4v4SCs7_CupUy?A# z=d$LYhI>b%Zs#?K^~1E0ZMbXO1MbR<$K_@$p&O7T+7+ssoKZS3R#s03TJwTfua)G0IM}c1s}}Qa$=NraG|aO)S;iYK zHi|iQd!WxREgm$w(i|DNs*_B~Sr`B@w>U)byHBy$+2=Xw-ZdS})ZaKy>~bi(9(x|g zpD;UsdJ?AZZr)}v{`(ozfkh9<9do-C_4iZz+t!HSr;5BeGM)Y_V85YB<3^l-q+kc| zqp&mP!&Uf{t;jevMaf`3a9VOfYrr)-n)8rUW%u_?zvH)%6z=*kgew0~)w?db+$_k43|Fw3Ck!zf>$7UUj%3KQ@|Pe9VbmX6Nz@!n@#g z8!2_W>1w1p12I`q^%)eW)macP<-m<~K0+O`r47Zs9AOMfuR!2R(U*k|=Fz}3W$}se zb&#ATyzP=AJKJlIUge*u!TW?p!CT7sIK!wym~>9VAWe zh;nrm`ww8)jXMpwnhsWe1WWqvMs=@F%F^>B;fbf`Z8{&TXA9Ag6I9s<(<$fP6UV?{ z_B`-hg(;{rLCRyg?zSouh4jBLhFwHWrMBz&#{LeJxb%xDU z)}+Hs25-YZuENJ-KOxGgfT~V=(2s1B%@Lx=zJE%;3D>g#U}hli_6UwX*NBlonO-fG zldB%%;?wt!cwA)NOWrRCr$7c5Xk(7r9+DrI!9VzL0O3fP$eLCTq_!zNFQ~^C1Lz!6 zLL1P=G^CeaUs)8dK}*SUs-aLJ7dU_41Ufq8b0~Jp;!uVv9JVJ~Xaqe(2@SBg$iKLQ z;UoCIcId|k+6KYBvzzdF103kF+4`e(V5BfG1z6ipm93RLEzK?*S*$?nljvei*Dq!N z_E`)W@z6B0R#9zL59cRrME+d=1d(;+m>2NUGfcc-;4}6|4rS6AMGS)Nb`0M<*jnuw z{P|ScZ0)tZ;!;pir)&7^gz_PH*U3BM!jJIvMH;Y zbm^?X;xEmW5wZR`bzo~7a(wYwER=YrS!hgq&OyAgs_%3Nf=R|8_eVcI-9Wdf-X*Hy zbeg}??~hwS7* zZF-LWGs75__Dx|+;6`NMWqUBn=D&X4L(K!V-1#*^l>8E`^m#|w+%@_#x>e-_&^}cv zPc2C3mDnZ^4Z`}$WNH!G6ai6?x4}Ez5d5ZVA zG6_}Tu0s|*s^Qio@K39Q3MR!xY(Fn=rkloKYY*Zh8)t0o#a}4gp`~`UdgjNg5fYy| zbO09TaYx6!m{UxWc@=Z$2kYQzs^N)?dBH+d&XIWZR)OLKC%R(e1V>I%S4)#g>Z6uK zAQ7SYJqawu%#nNqI0dazAqYV#I<>J&%;YADw$Pi zT*a5Kr!w9-7+MjOI^VT-LpenCQ34kZ+XqOrU)bCSI_VlXp9aHyLl>`Fn5Wf*x|0D8 zbc7fC9Hy1_UaYVfpY77x+pd?&^#6Uon8yaSo;gf--q3upI803fHudFjUW}fi_d}*~ zQFnm`eWfjIpd(`rc5r>5zOz}eAlEF;>Gmz_M;t5EA?TZl6*EWC2Wpbx7({c6x1i%unEI~evw6-*Dgd#7i+@hzyu`L#$UQL1LW{sPc|}P$Fo1!vn_$e-amU)wbTQY zrHf#pir?}uq_#>+#Wd!L!w6qJwzxr>k$sQnObF(_nvs$@H{)v*{L9n5_wTw3MuM)g z7JdHkgvCuWRQup`8U8d;R4}Gl>b7F7&X}jDoC#A+COXDu5eQ`){_v)5{Qe0fptUqK zKM9Nq=QA1TS;L9mQ=C&B4hjww!H^cmWA%pY`jI5A$u{oE#@xU#laylLC9Xk8z^xs; zo0q4!Fjc&Tcda_(jF)DM432GA*#*2X?vU!-EG!c7E*Pb{69ypCF@Y4h_I@mv?TpR( zY5i`g6=(YG8&~PU*pSYK<0)?V0O0W=qC?tZg217!W|m z`#FuL4Ys^Ni}=@>Z#(7;`3HZ29?bTLx9k}F&ijm)M}DiM#!PP_=*I@NwE2B8+5h&x z=FPy)WA)WBR-xU5mZhx}7KmBFNm93)bI-Tx@RRTl6Zv{P zfEYF``7neVRnmehINQgWELJ^rtDj(0|Jt!QM%g`FFt0iV<3z)?M1$;Ddg0J6e}x~Q z!YZtwdz(buixYt7C__#Lz2`T-D%cgF=ka}|*U zuI8mfePyN$Bi8&c*fkyGCL@z7L!xL3i^MVNE_p~+_(5tgPH?WFf2<%L2D zq=8)1QvkJxmg^w$dmQhjG5BQubAc(xez)|rJ#iEHpuhZ*6i2f>_tDPs8WnSFvnC6q zZ=zs4E=v0a{RZrobyVf9`W6fs?^6jr!*zC%mm`ghB}Swk=7)|I$-Gp!0&kU#SVXY{ z{zHFD`arz3IJnZx$v2UOmf|J!t;T|C8HAKBWhG7#7G4(DEdS{U*;XL4AE zQhq9`8i$_jxbqxF<;3x;*rH)5YI=GHDMy1l7k{pz$V7#m2=ERBq>N z{xnhYJ4mfje^FR{!sC2O=!$+?BeFX}4w66WN$PktYf{RYpZ1w`WKHL))S=v&0vE~m zfU5_aJ`_J+jLMsjpi~HpK4KoMlE24urP^qE*nKJ^v)xd-MC{PiP|SZa0?>KF>;Jv^ ztQ6#%J>?IYcOa=5EMH}I+L-YF5E6wzSN4VHZVOlaijJ=L`g>t(DTinuSUvHF7DcXh z$W@fd-)6*SY-sw#?9r2w?d5E9B2+mm8DGdSP-+T`a}rlV86I&ksYe`z+O=Saaj0q_-wLVbfxR7Q zIHecZ5HlFr=8b8C^kve2`bnI)vJpZvWqHezfVS{mboB2ZT#pnSpcHzc{k(=Z$LkoR$JK5tkiG<}pCp(SEE_!P zNXvO)SFX^AWN;~$UhTCpXf!ojpSpZqTH*?^QyR02Cic)g0%jACJpc?<+0^3TRFL$E zH*g?KP^oZzf=w<9S2z>HxVHCm0++WILr!XFj-x#Q7zF-Sd2YRB3~Tz=I=t_OYDydM z`%B8^+$mxc843q1cPJDXp<1oZq(u}N2o3Crt7&KAV9=74FSf1RSaP4ltS$v;kJ@1D zrDcbsF?$7zZ`2RBdWdg*dWFzWaJ*rdXw!Ao&|48TL$UD&WPHW=IMTBD_8-M? z_*zv}Az{^0uo;2v8rfV3sB!P%x}WGZji+`{s>9dw)!?YwBbP-IK3axN8C=pnr(+N_ z8ZidY`UOF;q~j)Yc!8bEJM(BR!B6+f=#jr6NLs0XzmIPO>pSjb_n|)374~KQjpRvP z^;gsm1@e-PT3fWL&8941XsWhS_05c|KnB1>7lkkAssP$ODgcB@(L}yGeePSOyqj$( z7~KR+IyACs^xV>q)=~~0ej!2`Tq3vwsO39*!-*MgC1l-Ta5Vz;i9iD#>|$wo7UmRh zvVxa~_T7iys7xy^M(tz@mHXM-C2{1=P7ied; zv{O4BZ&c3Laemn$N6#`^TSu?)xaPKTLqP;%fwXQC+R4ZQyq~$*y~_$I$PM^Q4FjKI zPo}Cssp+JEHXQ^ziZ`W{Eq%Vms7c^z3t_jgJ`!TA-)5_(pD>8Mq*iXJN?D2W5i-4L z7|XVIq%qcW$ib(?9KqYr_@q%1Ff9IndwZ7aFvn|}p{Yct$ z{$nrv*l{U($`(V>{hEAkODQ@qS}|JTqBd!Y>E$0=5kV_w1DnmvanP&$U>{br%?3(zrn}l&5nR6btRD$jb)lw+%yr6YjRzqV zD^!lS?rVyXVXV-nwJ*-VNv!+Agxb5jPdeTeJhOlZ*idWyeYRX3V-DSSoM-T4Pxj_q z1Wbs>F^_GzY|)Df?_Y;Hsx}i}F)N=QsZSEy8_CVh7s_u23c2>ETAY+(ZSs>5k=uIEZEXl`@74+PKKryFDevW%!Z#)+N)LqNR0 z=r@+!*WacB+_E2~6gtfTSh!Vw$|X}DYcilRiLoE#1*w%d_`fnG^?FTgtEhU)cswk= z#RlZ;Xr`>+`u^o+ScVd{VZ5`D0qTy;KC2WAMgE>_k@d^ept>+)@k;QXomWpI!Y1u+ z<&y`BP5d3O(ZHu070wR-_G!_EO$W(4%W5@r!@)+Q_vrM@{z39wiO*O1*ugC6d5N+o zjUxL@?Fw#)q(bP3Sty7%R?&A?VzKaQ*QlL}qfo^YpiGn1iRB)wi5EblKG5i@8XR_G zLHc#PAfgLA#Bd}@Ju7FjgZ^g9LK~AGd=(A!WbzIdfQ3vj76d+Rx zCi#u+{X3($Em{$c2H?hBA#i0V7%~Xho)wW!!WD>(r%qZiAk&qwAr8`@7fp*}B|cV- zH7;Qww&8JTZ<>l@=t)k}H6I9F3dV@E!(07(_S-t=CZ`V+@nJys;1!Mb0?d6W0r%?52-H&oj7?>P6DGa8N26QQnb;C~k3Q7Rf zwyDiF`NKMW5VS@Ru@rF!mfpY-@-2NE3!4o-@d;3vaOv0X2*$%|~V)184#D9`AP zRrfsZ;@Z2FhjhSLKjqCu(&9yLxc)prcx%LsqwLeaXqUQR0;h#xg#6v%zxx$;+hKL2 zE<>_wpVKt|(C4|$hwzJj8^w^)_Y@^~4vo&n>x~qH8%6&WOlAQ6)ga9v-||1}^+`u| zYRvosdXF^`8q7--=IM`P!*a%g1&0e=wJZJ2>0iwzdh=5E)mEQY!@sqd(fUcHoepr2 zDibA-pIdM}ty$CQcvY^;;ut=u74@qEr6r9=eO?}gs>>8kO%jd1Xgr{wIpK4Ad`aay{GGZ44Bw&`>h6!%Vjl?F-N8Xid8W!Ke6 z2D)psDGFrJGVQw)A8NUoj1X(;h*?@$MW_cetie1T6(6h+Y`OIJoeBsatvqXn7V3zC zc4m$AOT%emrog&kU(%l-1ax1P;vs<|>I~rox-UNKOH4y`j<)j1vcQJL9G#9F#RzSR zws;))UAznJduU(dKPoH13v$1v6||gEVfkDT53x@(6UYxErx+j<1f0YAO|g6sH2IDd z62?TKbG2h18YJsT8*kPpd#t?OJ&(x_v(%RM-dV|}BY7wcf6K08ACPAi;@!sr6}sY{ zYW8Tvx#J1oH&>_o-lRbhW)rijoSh%OE~OX|YEXdWdbX6|qF~vg$qCYXs#?`_C}RJ; zPo0&unTLKrB|$9CqEgexau5wgdnZ7bYf31K*iqR$B1T->b1++>P@EB&g@&D+Z8Ffb zh&;m96j=R0LA8uE|tp1o~Iy2pa6E3x_bJQ=4!vZaZvGNH66|XcRB-9 zudKGr&P|Em2e*)Cm#$s_Wmr8UV#W&Ao$EsO4xvoS$J7^P!Z5gGpfS^+sSX4bY$H@B zE$Wb#K4V01&)-B9l3rUmsaXFJd@=`anv4&vC!-bkoxBC0Qk9MdK`91tRhGbB6j^~ zxNO9C&Ff$&S*#!&l z#20-py~$mALK*rSsg}P}n~@oA+?(L70G9k-LNfc4(R?gblYCwP{t>hif#gfSEU1 zdr4?{CO=6lT#W(KM3VWh z#;EC}obi5I(};V^Wi}rI&(W%s*Wf5n4?f2N7cf7BBwMuF*W;~=JW?+#f$0uqp*wS( z5KuY(Su91S3XbveQ0Su7;5tW~kxDHfV*J%VbZ#0n--RN{FL;Pi= zvtIvCX@7dL&nmY20+np|oms*zcUg=P25OHFM97p|#nD-Ioto!g6`Ed|{(LB&5Umf> zYfL{gz{y%N*A;AJt~*sRu1dt(m9P|N`0z@eMNFm&YcDwm)nn-j)4 zZE!vo&L~Rnt3M-ya%fL$)LXcHMM}}@sp*JJUI>-4E>|=RF}vvV+Iz#(pDvN19aI>l z%|6_*Xcn4!hnxb%Blt%sx{FSgXE>xcPa|ahf+aS->GmG$Gt-_iE z+|_aQTIhM6kTl$KCtVX>;q7(q3sHq*(~cjSB^x007$r>uyQr1dc_z^iOV-3Xe3|e<0*_r5Kcb1x|I*b+6>7`>@R`R>C_7X z?gbjE8o--g^_>BJ8(@JbaK4GsNFkmojYx2Q-#V$uJOZtp&>HUj^ec~a(_r@Abk(nF z6%@+wA@I83MnJ4Z>3{h8jYk{9z;7c4hbZ*`N@v3Dm&#g0KaV*6g=Fh}wLciBLj}aR zsemcDRqZpXL}U}y<1$&&PR@K%C3jrse5B{aq2$#HAZp^@>HWv@5g{8y)Wi-V$qblA zsHkmx6W(y5`faP^+a&kYWvCR6>FK@G$u+5ZhRc4-CK#W6>)R-%o68EQJaz8v>SDQ$s^N57@I%#IMd-vP}BuUd4FzvbvK3+=Oq3qL40X|X@wdJn6 z4CK7RXyzo3Qfo6J7sTAWZWWi)5kC#|^iJ$~!}R;lOS-kJvjr@0>wKY6i{SyY=Y+a)gIh?3T|W8ua{{Lv zI=gqZOoC1}+NHgV;T1l!iR9f^>7ki{$yLR&S@X|#Mq_&;tVFIKEa;QJ%VA}zkrz?> zg|ePO923T_^z}TC*NK`HAnvBm=mB6G116MYmYm?@_AdEl6;`M7e^X)vibDSmDR9>i z2X_KjR<%B?uZcRR_iw`0LZG?h{e&n1eoSJlpgj=@0RzS)k zDc}~OhC=x>AU1({Qh8v5KuE&M5)AXf4aJ>^QrF*DQ%B?C0q*TjzDT%omGyS2Z!JHM@&z>So<$r3X^F2 zyz~DbggUahpbZn5Nz+r0F1%5_I?eFkr=<*9l5jnEIF>4YP9%}~wW$L7U+&s4N)NJn z2i@Es%kY6|>eIx5Dq)K=IBA^*=XYJ_&^FJ!edzJDD!QBm69ZiGV971XK+SIn8r{!M zF?XtlY4>1=38s_^XU_I%o*UTWXy2}y$Lz*vr$&87kmI)Uye$4FK*L#*DO6#PsKt}! zTQhSyGvl91o7hHvy^#!)^@rE5z8b0ke8Rk*pD2NA&T(E{f%ba;Zfh5bO zRP~bGksOg_L#1B~dY+u&IO>^umBF`%A_WCtj-4ouwvj=%NJiaFy?1v!ew)gpU?m5&{5eQwv5FI6B>T1V4TiC)(4=$ z^r&^gINEteDOkom`!vZ_;bJifZG7R}>^qnwoXLc!_axO}P-kPiNR(X78_{cSWTnP` zu_+O85Ry|R;DTSqg13ajkOQSERM%%7_EcDB(l56EPGSs1>2v)0#^QUS&?-WjNdBF) zX-M)w_{%{f7sG7HRzZ5SovL!Ycch&`<+H)xp7gu|Je)EfhVLj^a`A-)y+Rt%P-M87 zWneHia8PvAGAxrYs0$P~DL!k@Sz#FbYhr%;Hwk@XqYV$uiDbB0{3pIq)vVexT0(rs z#Jm`{)I9hXq9~WC6+zs*fG<20=BJjwU);kNXbAmRaC7<7# z?CvT}i(nXY4VkcqK?EyVi$l%D!vEL}u|-Bh&Dk!^VP#7A&>;J?gBBUEIn%86=VQ!t zG!0`GqB|IfPlA77W~wmj#$DnPBNg*89}P5)vd{gJ!9%uV-ZKeVfD2=(?cXN<;zZh| zrZ7P{(y^Hf3TU0pspN5VV=MR&I_Pv)Ow9y502Kc_G3VP>B)P)dz3m{U+4lt-g+tXB zAM>25#;_Go1=6CG)o>gCZGb_XWQh9t5DRp{${;A z#IbrztVpiOmR#H%=qzPpoAJZw2ZawV@RZo}+u@;*O*cd6&>8u7Gia_xofA{A^ir9k6!uaYe1zQkN}qbBr*qwZOc#TGiLIXtpZ0!RMt0mA;T{hI8;<55v`h2;MSW zrN>$?ZEFf!BIq@}&$g$cPp{cRkn_V&<}`@X8d()lhDR2*~`^;BQOcdT*B)a%CgVU zsoH?R2t_yb4uJ9MIj*LU5u{3(pxfk|^km1+3OUL@ENd%8W$oS;qCgJ=7QO@P5*_?n z=rWifd|0oKCfa>-cj2%k+Q9#WdX(-TIB!ZRtFwE1U6#lz_}5Kf8I;DUcVuCHl6FRW zh^*w%`0lxJJI0uL<*}pkP^V|qb16T@$T=g7+FVVyfZtj8K~61IM&sJmp8Q6v{bNEg zLw#^4G#^LqFKRU=LVdiRgJ)n=`380b|BGz~h2&-)HX&GZ!#9pYnNFVXh~Ac-7s7sI zOWXmDM+Y;9G5gYsK=F?BBx!KvMKO5;*ti(Y;!|y=^FP2N%Y?2%4dg+64XWs5l*i1Y zR7qsR&-r8;gV8H!)Ffp~0;-aK@2TEA?ewKWpASiXBcbQ5ApPp^dq*%j);S@o%m~{K z(JB6zUWFA-nnnO2>E?;a*K|_+Emjy+fW6#I12p#THB4sYPIXTNAgYyPwVu%!F~KPE z2j(s&bRq4!t<`?M_L!d^Xnk{Vq^j&}Apsh^3R2n1y@%mAEB;pql#4PO)&W(+=%}TV zZ75h5c&PpKG+z}E3P}=Mh;VfTB6{`uv<|uVUwvBWX@J5VYm5YQ3bi_26r5#0c`|;` zp<_lcWW&(9Jq2hwQ{ul8i-=5Wg!sCE!I_kqfq#sP*FaA0j@XizRoU6gC|(=lH#@sw zTreGsPGvbw!HXCB4`6cQhQLB0C!F{D<8 z7Bx9eOtT0t>KjHJPT*0gJal)S<4lHmVYeWxBNYT4zbOt0jrE@gN2-!a2DHpoO-RO` zC%YnbBtz}WlA+U2D4*x+^JRz%fD`C?mOoWXqo?$7<6H^U_%+hxCOj`17i>+kv3Xf| zCOWXYI$<7MaB?LMmWq2BOf4<*&aP+|y*R)=an^+0rXMmTa@)lnRNPW)XE?hMqViaE z)L`!r+<}IKrv5(*0S9@Z30>l$P!?k`0cl)32Pxh~;>xY;MNvFz0rI0m4<0bb=PTd( z0fSQ7usRx-4?4FI-9jn|2XQ=P+p7x*%BkVjB8Nr;(KJG^28efZ3k0n@^QDqfcx|Hce*AwfaC8jo2$8gJS*DF+yo7p+pH_azA z<^W3GR8sA$lpR$ZJ-;K+p^8NzR5F%ebkIGai%Z`}Mu<%9ZHdTsJrB%VKw{B+i3wjm zjkmx@k-oV3wu-qEb4J3!*AWWB+W6|u26J*;yl7B`SJ#qzsYJ2e&QEfa!7R%FhByj* zhHVaMIYPr)I~av#)iET7Qf2N4 zrt&i{S$qR?a}d^QgMTEMgyWCG_SCXFu+y}$lCj>&5(^17=>8WsJ0#t@i=nUa$pkS zSQZSw{vy6N;zi@jGCizRsc&g{1*xQ`k9e*9t(B`nS%q3*3*w;9;5$&KRrAgXL!<%JVJ<+Nj<)AV#vI2B~J>9c52};eXm#b4v={9&o)zPyIMG2bUfO($9$#~ z5h(<@Q@{aW9q7H9Fr_S7bX*gT9_x4YS;wImHEWd`S_azoYKwlTLLnC*8g8+DlMer^ zZQ#+_)rbAVxfNIc`+5%O>>z3mVfKfzu`PGW?Y6__Zo5?!_Gn>vdH;j7LG&t>iEYTd zA>W;^paf7)@0#bw{$E`?r5e8N={Fnhh&A#KS_6yb)bup1@h}lZc}#s@T&}QAB4#R} z2>KIEZIRp_wvuD=W{uQIopnMYVh~)t!gWc3Y<`qY1c_85brO3$&ttcD88xXy6H79N zi6I0fvPt9{#&NyF46ARMzuXz11U(C^F!RCb{xi^QGWY=#heBKSc?*chX?~TH>8v?> z1Z@R>Jjy|c# zu#gWVg_JdA@H^5{a&UBh-bEZT;aCxI4ms6Cdorqr!#J#C@Cw4^`Zb~a&ZX;x^L^;{ z79HAME@#Lm$viofqi#;Y!SDBmT}kD9cvg~5lPo(|D5>o+leP!}IvvFM5c>K)oG>Gw zD2RszS7(_9G_nh3FKp7eN4(Q->s1RZ#`kNxc@z(FpL>}Adtp!BV^qd7IhJ|-+f7p! z4M^E`Qc>W)EQ!LmaK-^G63@99w(0Vs)-%>C_Hh+{y^2Xfe3cVa$#0WG9-@)f4O|JQ zQ~^3%#G7l{B}+Zu)vXh1Lf*dPrdZg3ksB>w#r^BN`T_)NFe*`moB7U?KTDe@U06_s zmysnyw4;gDXGZ5Tgu`!-h>oLf>the>l>qbI;;%FzkL&K(&yMx_2~0nknNl2qZ^Hsjbx z2RARcCVg=27o@JUmwl88`-?&k<7xWvZSYzQy)Y4put;of&U8@9Y-OuLe(sSlvQsD~|y;@)bVZWJ5~ntE(`cloI6Et__3f z|Ke=OXfSl!J2Bmz19z}8B=}Gc3*lUMA*dt^jiR#JPe?LV5PTgw@84hvD0S<7a7p6)vrw zY5lH;AV*~2)R4m)vT-zq_bfZ@^8ro#6O~(yQKeh}5_xGNs+8Z*sOK|;FbOS4LDl%W z4YzC__d6Fho{*Mm-ypOklLq9JUWMcQq7q%tM;r5H*3?U(W}+y~G!pXX?hvp5q$*u_ z9va(@pK<3(w6ucV?)Vj8XkZ#JGMTJc$)a^agOo$epU(sw!Gb%A!r8+I^6-TcRYZIyA}vQEh2r9&(Z5cT19{*B-dO+mVdhW2odFp})b=LyhO#bU8-!TO*GZIaOM)fLz5uTKKi|&qV$O^06xcwup}vtc{vUr+ zYvQemu~k;P-Ik~^OV;nhe=YzM74Jk*H7Nm))js~~JvvyJEae0mst(J~A^3^x)uv(WoIN2@lrL9jA4FDL7-!QTO z7q3s;^~c^jWxXDoo?H4A)QI(+t_89;4G2~!O)q9-X-G5V*u_w0m>RJ{kcQ<``W}PJ zT@ki6^5@CCZ&<~!Cd_s%J0fj)h%`HdEmzS&+7Ld>#Xj3&p~Cjb5G_5}z3z#1RT&(S zADPB(${-auQB9PYd|Nif4v(~>IcCrD3m5oU{+3oOB_f+0^{94d^+#Xc`O~8ZUrXGq zxs}rr+O`B)D z7lI=Cu#Y`U-r!~aeoAeL8FZV~H+eC{0_%d0^eTRPFU?A&bA4yMvjh`R-ZfBsvTc*UrIVyia#kpCOdf zpjy{*w&TbtoVk0tc?pQKq3=3JNY5@CNj7R;4iTu@j)9`y1Wdz#bPo&5+R3aO3xK*@~e8XU3Hn291ail)By>GsDcMXjU zB%QnZkw!W7vk-1m7~%%ggyYu1jLxBOs6iV`z|c#(p#=hmafL^k+t{y_%Q6J|jLOBg z)w2@hJnZxfu*j<*`>Ri8&7n-Rq4Tj>fJ;fKbcPe}YX})?_gH4|OV|1a4D>Es(9yjm zfDn&T)we`0xGT+iOScijX(Zun>O_j$L)J!9q_1K6FrNz1TINvO5==G)klj{tnm!7@ zwhHCwH>zQlHkUbVDRAMS@6a1P^s{*n*xOsW9n&kl<4I8eg|7&0t$hmMSVrUsp7%&4KP8?4}CR6`?UhPN;U2(vcS%E!P^dOlF>o98rBc$QTMEru?ppir7mRgRj zf)GFcKE9bTgtbm5kf}?T&;XH9sJKSAen=^S4%(G1&J1Y;M)$g=E|07b4w&c{j(rB> zPK1Sp8U5CEBlQ7@NElk~oW1SCzUH}lFQ%%Tyw|mGRxFb&C+MKL{y0;oqtk{By4c5;CmVG~80D1XrvOtuuSet3? zXA3Vbb zxedO*53+pBLa>Yt!iSn|(TuXHCKp0kl!+{~I`b*b8fr+V&jOZw9L7=I?=H|@u_u1B*+&&rCU~@n^ z8Z(W+wS@Z;(o#6O1O7npPJ}5jQElGPMTVB&W9>wCa(_-C@q-yZfA@}d9Nd>VvUQwn z$#txE+h8}NQgI=cKs^s;FNPz`F0>Etg@}ht{Hik%%{E|%TRcRqtUzp#E6yhp%_Gav ze`W+^Y22-fGM11nQK7S5Te2|e2Dfealh``GQE`nl(0xaTnzC>0Ki_9cAI`}u)_Vq= zZr2j~o~^}F2p^Xh`z!DqgT>xHsdDn%@9=OLA%z30Qf#*ak(SOqP_00D;UAVGyhh}< z45bxul#MMzy%Yj++-_qAxZZ#9BA8|_fNuS=%RlG{)`QnKgOUq%!9+=j zJFptsP#K&OnK>uOBpTyBOrEHzWq?nMa6HY?e2WNy+H|OZvedx{;Ts9;NgShpn;kcm z=G&fJz$tSH)PaiG2n`=Azpisq!jQ0}OOg*lysHT@Fy&<QA!8j=Z70`k{i0w{unZ`9XZsymLsX|IsKy@vQm~nPG@l5b zLBwsSmHA*KG!=8gf*p)WCdNu677t93t&$=O6Q5oh8ty5vUX`d4bI_C(T|q0;=DEDo z_!ltc1sz|z1=0DToN25N)tJ}0wKsLJ*#*1Ng`h!`vh7`68^BlbfW4W&R*1DPJmC>7 zgl0RU{SxFfUu$G9&Y*JxCZ~ zFF|fMvq@#RelA2jwX@?d6|l`DJZPFW9$Md|*+fP}|Y$Y<^Uf*LCPj_UyWqt@Cn)Gg-;E*e){%E>rc9)0~@UN0+&(84ZB|$rgY} z28Hno4RHs1bl`P@xHOn^tczdfd0td8DVxK5jY#;K|Cam@grR0=0`s{C+TA&28XdQQ zmS$c>%Zb*Vw!C)hE3MOQ;4O4|!{+cAa2;`2{rzM@+i~lQb+BqY`h%}2gY&5+`e`Iq z4)CjpZLBapJBbd?^VUHyciQyZ!neE}Nx8mY+a4r@p?u|PaSibC#{|TKgMJ9I~JGmY?ZZBJy*iWx56TAdP?4lQui5a*JG_rs8{{zo_A0?#~4EThhiGA`@rH%2|5E!4p{pqhi!neti1YNJGh11uqS4M%KS z+V!>5Da7qP^SRJ#j!LjMjg2?`zJiijzKx00VvqS$KI9I!f(En9S5E3^X1x?_%ORMs zdA+7P{7+Qa9h3tIt7t0Mu>qTC(+|F?&!6`CV8~}2QQhO=|MK9xcfo3AZ>LRz`!U!X zz<{^U@R#DJRZyq^P=Hzv;?0^YR?wb*^9X+0cS(6xR%qq?Xj@rGg-~PV(rzf)PHX{=i~by*WXus&_)9Ieh_KvIk=vuIteR9b_tDYhWM{ zCDEJj4Q@XWl~(XC3^US3&fMK|Px;Boi_)xX4nUS6ySRv2b~x4<4e}>IuDmCSmoq-r zFzr$~+`#bZY&&+ctlR{fDd2U?=qHXzymc`@Yf8`_4h7VWROL=9 zpD24&5Z8{A*2QES;X~kQ69_>*x3_^Mhg6RCcO)SY&v zKEU|lLKnR_!1B2i*-&*;#Q4FnD2K{yYqQqCxBb7#(h$!`578+EnTQwd*po`+4I@;;0X+9Mk6w$fh%<$RXr+{Ze2 z+*7nbTJjRD!~geV)y=oA)+$w7%;3lqW?#u2G^caCOhIwBg(XBpmlr^ZqfcPUn;AXP zA)6ba!3x7Em|UL-L_(3K!L{guhj@^i&ED@xTVGhF2@0p&cx&?K@FSYE^8CvzEjf6D zPeNRND|&M0;P?6dc*@|+R_J)c@eP1(ivP`WjB_hkV=uBEet1rw&E$c)h&o5Y%v1GH z#%6OK7uFdI@j*a>5FeHxbeC_|0~qpn+(S;`H!hpVd=3X6Ld%;=4FXcn~3vsRs>=7GeuJhN)hjs;jG~@otEtk3N1IqR-~h@yB0x(Dq5)G;4#h_8K(Y zrqXy~*Y!F!??B@(PBXpjJM@yH_e8|&C1%B>zFQV-e>)nc^yG`kdDJPn<((k+k02g- zG8Jz(GdLjf+&iXHG56aKqAh+Ks&??Jh}A#{wRim~28q675eBv8k4S!gCgK|_zz$PW zC35)`&mOsaJdzQW;bOC)@CanhYLS$(s3IR3$^aBGs$rpnKwMvQn7~(%!oBxdioVf1 zY2Zjy9&+VKZHZ7XA%b<5sIg<7mqiSv#T}O+R6IhkzFqHemznByJ)R|Z8joZkB=>#p zoOt)~UlMG_HPpg#h2q-?p@YtOi>3Y{e|fyifoTI49=csDH;cQbE-1g2CNprnvZW=? zB?`E=LWB&fGE%89`K34XakJ`UI;neI_9vinpjmUcWqX-A_9IQbXWj$LF;+rlA?QAJ zLD4!~sC7!l_1D-4IAwS98&bT-M`Pb%Z&V=?-_NTC+=XQtgaQH>?&Y5X;EUScsWXH8hX%deWp?o$=?APOh>qkp&L8Z6}1-tF%d`<&o<(CaB z`7!}vQaA9u%!T=>x>^JQ!lQ0_ZB@+bPCAvg8jn4*2t_GIXXDTa$<2i}T#trzdQB3D zk;2=^JbPm>gj=}x<#9tlwANM~fa>i2m_$=JZpC;gV4RqOU?d;|m6;v2#u>knVAn9(FwR#8A z!(CB-KLm)nj0O&T2I|?*SW2(2f5;8JWb|}`!M7N3{lgnQUajyLhOST z^RId@7Zwr<12!|_w!;-p=!TTbnHiI%waZLi2Z-zn!I^VZ%*U%cqLl{5B@>MEIggkK zXSeO#&eS(=wy?tpt;oWqM7CNCM;%^?nc&TJ!S9z9R91UF>L?AAe7v69?1-@My0sW+ z=4)-H6l?e=>`lDtS>$^_%R>J^$3MluwZR<{LZvOTbxgZENwMJ28G%2q+1DFN)~ zlYw%nmA(3QCLNd0|FM&@uj{4Ee;HZt0L7z>v+M3bU1Go6*&Sw*k3y;ykhw$!%dUj# z>=^DASLb8@9tQiS1`@-J$4umf$ZD@QD&Gxa^dsoY5@jy`IKaRp|tzimM#F-s|M9^%GkG~UoCPU(0PL=8rmz3C!PAVNJkNrBj_PUW$g#WX# zY@;JT57+^Dkocgi`H$%I&%pk$RFq(S=+*CtRR(?QB2yhq-!m9YSK)fLEM!CAkxJj{ zCahyHz5Ld+qK@2}ECsW)>8qk-mc(H3ZV9o}I3zo!JH_}MWj)~<`z@J01&sofMEoy) zkaWBwT;63Dery~?l1Cv~1|cnZ%Z!S1Epj1yl4>r3k2-F?=+@S43=xgLPkdy@>1;6{ z%o=*xQZ)CLsCah~QII~FxkjlV&%WKPBXYRxKl9<*?C5U{EDrXOLDM4@E$-0;Ci)Bh zkMQ`TbovZU6~JrhF!ruI>f!v-38mzS_lYH(r7o2LBg*? zeQG7Htbs_&3M1iT|E0o~_D*v{v5(K!Y{;*T$Kzesk#a@aEtxGw&FGtcZSs8uAHdNU zl3^Go@^ZrO-6q%-H4%cUUx2d4xpc$csXRBxoxUVgUzX)d{tjx(GO1hORK>53EzZ?c z3mi&A+J{9<$iPJqlw_nsr|VxDaU3}*FWN(b1GswxQ6R}C^ZDnh$~BA$L(WrgKZs6t z!P-AR>&7c03`pfZfcTt~VapIiR6v|*mQE_c4A`}FqA4%WL1wWJ<;LV^Py~trO_EWW zF!@$tack-BkWFe9o9t0%>8W{FmioxZntpQT(p^t^&3%z);~^We?3zrSu%Z) zbPS1PEytOY(O^O`va#HtCaH^;)2QQA6YU=K5Q5e!4O%9Dk0)$2aFDYMGu z?QkJfv)3%;RZ6@Q3b1MeG3m54>0d;R$Ph2iPcfP2p%{7y^$2{E+aga*U@kN29T`ne zfxvT>K-c2yJYHGoMd>mR$NGP%kTxJI5&ip{Z2slTWoT(4gAWKyBhc)8`*YoH`9pCM zmn0rzi}Lqum4zKx%VJ_6F??5scE9|;cF(04EvJ|=UwRc`RTUPPH`TC22N`8M*4>2MbCPcHlJ>b_Z=qnDKaIWj`!SepZJU%d=eWn zc-JUuQ+K5RwGoDYszA@LZ$z;2Y%M z>lisQ2`#q||0iSj!><6R=+*m>V$+JYCpNjpGl0N+!uSSVcAIqcVOg$>z7%vjLTp{v z8tO4t`M=#Pd*Nz!no8tp=M5=j?t>;=a%L}hF~Ef)437C^gT;33q*_bC}ZehVm{D$RrKLg`-uqCs@_&}TX3#dH!IM;8;^@1 zzL1v$3}i^s7N4xr`aWzLBvb4fb;Xe3KrlLP8_-E?iG`v;U|Sfm7v13ME+I;9S8?^$ zz#7WNCq!pNyfb9~9?FJkfx|#~x$qy$6Ge*>8X%!wSmd9Q;-5fu($}J6G!l}23cP%> zp{8iM|O)@O~&&a zA2(H=)S=jXdxU3=>0rhGFES}Ti%0Pi=+zY7Vt?Pk&YN-38ye%ESe}s{SF?vrcBD?W zD#rj*Tg|^mt9sOJ{>$BRNc3BCr|0nYkoqeE`k3ZNQ1M*G(ebIHDB86V(BwiIm939k zk+Y8JU2WF!KhmJyxnF%+m-IKq8Ux%6VVfwO7W$3+NGEI3B8|I^6;Ua@5Nf0=*{v*1 zpyzr`BHv6-H@h`=;l^v#4)LSo{rxgv0!^R*B$WxM2^`QS#*XhpC}df!)us zyB#bpf}*@stYVuJvYfB*mg_^W}tGs}AQGIZ73s*Z(v{Wt&r z=pycptAYJfGh+YPB!3*Wbcdpk&WrE-k>{nhMj9)(PV8Y6n&xfF04yAF$3RaLGn(`m#;p?;s$C(NE0DoonRE3Sq)@U+dZE|G{k`bDR-HW>DimGpXs+t?MHX>;r05iqrKHCW1{F6|;vrg~`y;bnkCbvMAp&JqEGn zs_!1uc{m^OOg>%>VD~k{6*zi4O#3oENy?m!YR1;Foe*-L5(MXwc|U86Tt9o7(J4^X z+NXe?`MHJOvKXYLhuD1E)FrL^sk)f%gCfpuv5YZx68FqeQ(%vk@UjjdsJH}Qm~Nhe`2&$ z?XZz;#qH>B0IAl05os7&ca^u)tnCsm-vx0w6H$_%o@vpWg2q3(PM?fY`EHk)h#A9Z+8N{cD#<#l&xKWQIQrUGtq@#P8<9bbb{ zDPW@zs?u@zIHzi(GoQ?N@f8QM1qZmUu~^);y;w3X?0P`m&x?sY0PKgqVz>M1uiiM} z7u4z*=Cr_DaPXYL9Tm(Bn&0B)7NHDJ`6-FCUVh9#!qq_2)1&gbJckz%)%jqXrub$h z@=Y(v*)aSi@ds1)O|n);HJp1=V1?5(^x!LhkqHPr5UGM#j$}DZoGRtru$vq|!TPoz z?cm+(o;caN@b_e_VR2}{C(II-21K}4+)+0@bojFRbnp$64@hUqZDHRWks4Es-T9U& z5o=>8<#hM8+6kR(w3s=`ETPIZLR@?;__ZVi>%Xhbz9|g;G^@@%Q-;?BN6g=UHNK)G z+JqBsm+xZ?5hMS9^*~wM`0&oNr(LUyMjC7;dEW=wcG6+7Sgy<0s@CyemY7Baz{d!fZ923 z;+2+Q*v?hLWXc}eCTjiH*K;e-NV7JL z;;x--G{ek!X622S=63r>8;=<@YKQLCS7yY`bPa!l$yp7(j2I|{q98%04U;;N_30vY zF@vh(qxO$4pP1`K3S2PG4GnMU45lJ9v6_Wm-C__HJlTjNKJu6GUPXBRh!B%x5ocrj zYdQr&hPnbGX#Ur(iCD!mZY2Rn-x!RQpj`nRC7yg}3?Y6D&L0nMY!v((u7e?2%TXUr zKjRSRhS7nt782N>4gr)42I{3vXfU7S*TWz|eR5_N?zmQ80g8R7Xw*>V)b8x2eCx$~ z@<#o6#BCaq-qIVkxj|hGV$`PGuWX}N%Mat)_Rpc78N}q0W+wVYfV0Du6a>s|uLhn_ zu>;__5E{sY{#K zY1?4_@4URCVA@X3t>r8LYVCdV>W@fPudQGAxF>@eU!}F&Mq%#3qzYrg_F91s8-;Qz zW^LH@8ZOUY%P2UnD(jj??BjO;OF*>0xtlZcm=oFN_onXKAW@;`qpg5$+YJh=zA={R zyGSqD?*Kqz06X}o&0Di>V?atI<~M6n|EK$tmHgh4>6^Z`(S94$qczf3V~9Mxj(SnERx1&adb;q*P@`HRHWMBl(b1@dVJ$Q1*QeEF7- zm4ZC4ddh)JkEvS1K z&W~=wLsQ5J?09yFYLbzv-ljE)tE8bn*O+ZUf*WUuBjp(j0=tjTKYjl`2om(DOJ>E4 zUAaPQ>ZxBKY9JVDV*Ab&gm+tDsO4u0Qt0&}Y$=8#M_O=qEvngu3f5WTW z0Z9Q_0Oobty+RQ}zCSC?6kqh$8|d2u&aDtQ%nAmH)0>hVwA2I?)Mya2{#3(^;S@_0%#Di>TzJ{$i5YEzGYP>#nVtDt=d;YFPI8m@z^q(o z^6Hn7z(?V<5Uj0~SVf^)rf?yQm3OC2C^*n6oq$65qn#C8!|tf`@icjiePA}Zz046t4AGE4$fMoB-Ed8Z%8UQ|>B{=y@ zJ1|>U05d&eDtS`$*I9~v&eQ0gH@AE$AX3y%=`?vOu!%cm{cLFXPzeS_f2x4e+Avk; z92QS+6$fywqipoP=h2-h?A+*1RLGsLZf1mVhj{ZE+U*Hxam5Cd6MR4-+R8888U)bR z+6ju26t##N@#3Xv!H&GZ8j}Idm#8Uy6+GYVkNtpJ3Dpqlt30A0dnl2gbAHD7rM*`cB41Dq zCYXTKt>HR%Ds_@8Z19UvG|dxyPwxF$OFGRUEH;+G42&<}mEic^53lt~v8AC64b@^! zQ3B+ltgUIy6Roe>&pLFTY&Mo?i;K+0Zi2fF*qV0k39}SlVpUUD9af$&O(@XMm6g6xuga+ zfKT!>VOjT@b}sqgAYOVX=eBFR&rl`ev!cP}*#XxS=BS2CnY)uGU(a3$eDYTsFcxQr zB9D%Ea8XwRi*;W$+<4t7J}q~#Td{A<7+KhWg6wvik>=f-_NU#9xMm>$ZfI#a$W!QK zbPs23rfSSx)cc`vSlpc>oz*`2WKS-+A?>?yoI)!>O-#5-i?Me6{(;SSE@RlVy#cu$ zz6hNm1h7;`Jlra3LJp4SFtOrm@50s>@_G0){Mrrqfs2&1BFKj@U!?Aq%9JOZNt|BH zA4!JD@%#+O66KTATtjlrvAGB9WDjWN5A$8zrUUS^6!Ga*FW*+=xTOA~C@s?{Yr zWDrWnU8H=*57fS(RN;M&j2FGZf8(-E%|Qh2_~{x@a571OLSHUKl`ZTHDMXlfwWjPt z9zhjOF))>bEXNfZEc-zZ-3dm3K;7ZPhJkhePkT02{i{1BJ{Ie!OQ2LG31mfSyRB({ zo}pY2j+#~Q4v{`Z15xF{I?NVXmmE)hmhsRccJMSE3Ha3)2IIF_2V<8_bx-Z-J*It7 zY%~RMnfEghw2^5Fji!@r4{u@7_SI1G@p|EY3I@ET^n31>S0AlseDIu*`Rjs)XKDjC z3}2ilv>JkV_1R-7;_AGxu?c(J9O`1~EHj$H!4y)%@#Ws0vK@NK!4iXsb=940M1lR~ z_CycTJN1M6mneANgQV$J19vE(4}mqLi_A);<1n-J*dQx)SS3cjQ)i!hy5-}-=% z4CAw9NB_NIO!_-wzlC`I?6^#*a&F@mg}$*9`&iUeHO5qD;C|}KA5FdTA)wCpX_QjufTgeZu|`2Ef96#O_9~%jVUHO z4(hA25A@|(0V!@-^DGYb*?U<8mW!@INPlJ}EYTzt3`;|JPeM{sjjUVyou0?Awi*mf zg^*k2HVO!Yr6>0M%tjQ$UH{_s%Tl9s-AfW_EO$gyGOE;go1>lq__C&q2Oa7zig`dB zI3QQSo_f(`-j41VVyCN@*=$IP2g@X$9w21LI*7cF6kRm?iQKEB;CJESIpLu$LC)wAq zj)*ic@gw6)JERnA{5Ns49^qFWTD37n2r*_Qs+z}mtxD_%Z}8+TOsdn1pM|c7xTd}$ zOyBA0ied$ATkaXphZDaqY6$x@=yywymZVo;!8`2^etvo@$xq7|>zt%>I__Eb?89Wj zKL}fLjem-1{G%2j+;#&dFrO`HS<4-3<&BMoV_Oi%$(C;yB%4ssxA&w%=YhxbOmLmg zbp|i?*00FFbt5AJKWDsT1GPW4RY1Lw?DaM{sQWEl^E47Y+GEDl3fS<{=V!OKr2kgR zM%y2qY}%L9MgI;%NDyxj$iSxVVQ}LKL!oElJBoU+i#`D@Ni^Mn7=X<02G^}YxK0tT z!bh=paush^KnemECo@WGuRPza<+bN{`g>n3Bh7aZ-3!=!ZXv*Cp(AFti|7}mP4HjI z5RNuc;D;hTwzZe>ZRdGA-&k#0TRgH%hjXPy9t^NOTxL3jz#N#Jkz`c-i@I1DhK~q!@wxg4Sq`%)|=!P%;F3g45zBQ^SW^R^NIAgQ)W^AmX zZ1K6`V}4V2IDnA+r;`CTjV!e@`EzuMUsaeIDai~>dk8eFA#@2D5%!av&PB9dq4$9g? z74N5`vyUJJxrlE*m#vKCU?q`q%6=RyFz~HqLf^lLL2zkLoZ~y1QgG~{dXCUjtx@W2 z+a5V=TuYW1`AswDc_w^%%BAJSh*5v1Z@-_Z&PoDprJ!M}^t<|z9Y)gxN&G^{b-h-? znVgPOWS&HMeX!ii0!R1t8e}0VwRu{G$+>D(Rcitlb!{0uOz;io7n<*Q9F}EpdytWb zb+7wcoV=UX+0N5FSPsFsnBKO2Cif+Ab1n|ulQ~LWvwl#GJ`GtW4~w!#uI2l?AkM@n z7Eu&-vXNbGtl4pbvlRTbSltN7Y-*JLlPJ!8u4u@sTmS(1?;-o_K@X6A;)1Bi^^*tI ziLZL3eubiJCBz@Pzo*;vHNipm)7Q3p7o*P<|5AwxwNpx;3PV`JrzIacrc>_9KmZ1| zZ3x~P+?(`MXwRK2Y+E>)yL-)B*{f$A?frW*Ri4uu;RZkDhtk@LyS4EhJ9rbVY>BMw zm1qzm37^!-^Z)^)&lAl}mNr}U!*m3Q(=d#Z+-Gbw`L$@H4;e(efc&pe9(OI>>yX`l zya1clyPI;b(ag~Lv~(?tf%zL6@+@%>Z~u$>`kq7DP{Lw25;3XFXYR4wX}tpERVXoF zJmx#TR98_yU> z?UNQyO;??o3vvyAq5O(3k%wtNz;|@zs0=I?IdZqS=rG&(Ybs%Q1au6Ed<4}u=XF6D ziQlq^nnW{VB&3w!(nN`AP3YF-%}nn*;V3^~eTb6P)ZtQ)DjITBxE3MoC7Ha%0H~CS=*ROrgu?7hQ00q)ynf~6@Sbf>^YWOM^M&s3Rt z^c9zQw!OAG``6Y4e*c|%<$+IwTF?)zuOBGyj|2 zFs*zFEE=w)U=$gMf2;1rFzlRDC(l>5K5)dHJ8jSNV3MLReWALBaLu+>9rrAK2fQN^ z=hLe$MCAVl(*_Oj!xL5JKjk zXj;uOGGQT6Xx<5`Iv6_4gE$vYGdnEPmiFJMmsBAd8sIf3jIy!8N9S9$@pBc0lC@pq ze3O3YI&AhM>#s}jPKPlA0N4n^6AhAPUHLRBj?z_K51R55sM29oWtJc;o1eial#?U} zoSH8mf=)rh)n-Zw#^7R(V6JD8?k7ti%Jj~}hO8JrGF={z@v)jpgK^An3-ZtoT)jkwn}^27N@p z)1?Tl=6<6`roSl|q@YzYjkBBdfoUL1Y-^Q|Mey8V@s)qY1q#T^QuHNjOSyir1JTj7 zJq<@!&f@1%Ru(I~Y8jt}SSV6KWQS8guH6=nGnWp@soaRXn|`w_8Z+|QKtF7>PM<_M zVJ%tt3*qRv34`S7*P+77HQ|D2`%M3)UjN-#oR?z>yxraeYem;OT44i+E8~@R;@xg= zus#7`n+S7~DPu`W> z{2AwB0WnP3j%6w^8tk>gg(ZXlfjx|7ESzyc>V2Bno$9lkGqwB?cp^U@ghkY|3y`u# zrmQ!ggY-?6YgPbWMSmjzGUdw9x^FwFQh_#wuHm;|WgT1ur9)oP=0>DwTn>D?FV7p6 zurv2>GOy6?UVsWTdGwYo{+8>ires=V@oL7>ot10%i<7l#vbmd{RY zm~n3KYS(En&sWq(WRKLMwHrnuyNg&edm_u>qVJ~>e}nWeWO7Y#I~JqBxhlErC=WcLST$L?hu2CB%9P5YIAqK8EFa`n$Ri$TS7WMqZMn|* zTVg_$x5zDh&W4>zEi=Q}i7_E;`P9hcc+V>~;3Nn7zK?=L<1maKrNr)4g!vH~j*482 z)F$6h^foRGBJCn1mCm@z%nT%wCkaIk%w}j^$k#jS!q#nRq_Pjmt+4RwAa2(VdHOE> zZN64Fv~pbNmcSKIzD*ueLqPQ@_A2zFg|kK24F-GkpGlLL{nTZ#)XlXt1d?;_s2B8^ zqo2Wd zsvMmEctj$~H`H~Be)NA`Nh;-+0AjXr&(C$iNpi%lCBYou)P#rqlexFNCaeT`g z`UFj78%qg&qD1hvrqUcisov@DVmCQt!8>X}z)uh&a+3sR`)f8NJf*JBtuT}c&MY*tgvI9Gs;w>^%dB$`u}G-iYbsM;%Ig1 zhm*mrWoc{vGgx%1n6AsA(smcZ>YKr zm}!H<9bv`{0XpM+&}7?jUgQq2bAU(9IdEp@3@lr;Y{U{!p+O;x-x=Qf9*(Wj_bkDD z`Z|*xWH+|JzDkI91R&i}X-q9e>M7i?`p6=Ex~m&l@{aVU$#+i)%QVp0Wn!T7-6wkc zCj!_zWLb8pcl%QaM`fNW@>`ut!zHpB26`TETeBxr;fKJhUO`vRq|8(N=2-$a);$k2 z<)B6CRHDK9ny0M47NgI0l&dEzh^#Yl%a~{=4pL_{X4;b4$bicziMQcG14A3ISK1^{+xb%2Tgn>refglQ3thO|;^&|HdEXuz1T8gJHb zdJ65P_v6Hjpdan{|QcNB|=)h|W<~uFNo_S;)U)e3?q9CB1exKg%blqWY@5FJL_RH;aH5AHmi!nk3oxq4}0TFl=w$ZUE*WMomS8! zlmB^`#OWwK`T$K;@B30uao9oVZD(N}_XUk**p&kcRWnZPuzrt_H=a8DLXqEvs3!AZ zVE5#Qaz6mtb@nZ~HGfaTUIu5E^JwkhpJra;aci2y>jnHrv3l71-W&fqg4no-Mh-1o zfUSc*#QMqSqGH-Yq%XnOr*oXPFIS-bl9I_i+L5vWPMFUa3uoL6et%)PZx%q5v#O4K z@-727=-fN<-3L}}g=Ra4pZEG1;gqt9BCuVuF7h1_o0JWU$+5GHW?F2g1g0SA4S9cu ztTX30S6cUjVz?!kGY)V?q*3Jhp|vGY-baJ(`jRL#f?=KgMzQiFs=0oTU>SHRkeE1=mK9{8}ga@(E_P4#os`vbk;@yj9c z^7L;sE&LV@nrg;{=i}_@>HtpDY14Hod&A=rTyHkAZyc~OoAUTG>r`|W+VIWu!-x6gJ|36}%&G1b|u!h8U9 zf(;V14T8l1Y6Mp|QN!ovaR31I4f!C%KE9_iT@*sMqJNcBoXX=oR{;k16v-$_4ugn4 z%Rv+jrFbmJP%~m<8^fpseVqB{3f)kOy<%v)+|Q!!D<-<_D%xL_7vbYJLPIk8Bk{cT z0nR{o^WRy$(dI>7 z3lZ58HtJMD17F*6za*w+&uLS|ZVB0Pw)TW-2$bB9)YXY8E(*>RiB|S!9;6wCow1cy~E3DP$@#@c56r;{y+;Hl@KTjFv z$X^$UCCK9SU`$@~X`#0KYx9GYB3p-2!KPn+gbH!GSm)mea0hpGoSN|R>ID&**8z*r z`ON00xaaV;8fN<-4m%JSU9zLHYn1;jdPd8qbZw)#q{o67sgvz9tvI|(#^!Qt0y|Ys$iI zq5%iGH1j_Z5NMDLNV~v?cqofdGig+Zw=AmmEC|u~+uEt^Po&Rpe36?v~ zpGsYOvfV{-iwW+7^$rj%~FdS3_GP082J>I!kUk?+8}&>9ubUCj9e{mb-Wk6vCiv_7r38qoYP9ZZ`wOXhwYZqqpS2GB=R#F|X zXGMO|w@ovHo2MbJWC3IfesB$b?A!ll0HhW1~!)K`EzIIEh4}PKeBG{r4-}QQjn9|MNyg@)+%dIBBQ;8p&g24~A+GMf~?|BOzrLf>3zf;wIFmKf5!u z%ZybfEF#~&>!BvWzA)q1(q55?v9B*px)slNP<|wM@149HfNj_DT@PuEJA@BTcgGzw zw$BYZd3F*Lhn8KI4>=4nk22m4w%mvV7O5sTLV!H>Cm1`a1>-RLV*05dnB>tukfLdA zX4!tMo~67j3AxCZo`3ZimKYe}PUM!wXM*fNc=J+vD!!T;%l&}KL5!Ed$%awhWz?CZ zE!&Zc^-p$X469(p#0IcD@sTy*j<>1oD&tk1wSXxSM`U(iEF@_y;$SxF2O^>asPT?C zlTNlg(Y}Vjd`Rww6?qX}Q5UU@ zqIVi}Da*ckhxMpOHnN;J;#^)JIH-jp2dcIlm7}~j7Z@2EAXNd6$5OR=6S(=!e#|uI zYLeu7M03J5GUbcC(pQlu=c-=iysp!mnDee*zG&7BZONqrL63>!biR5+eg1qMF&0-N z)UgFjk|s*%iH6>R0$`RG9eF7HoNAd#jYpU3Ie41Wq~S17#S)Bp_o((}T>6(Xac+T& z(s)Lt=giWM6h@fyYXtP}(R&c3FX6^&0T$BdU&~I;G5f5_bil)A#u_A%JyHzu3!2qt zQZ_n^XEdPr$3n$b_vE9a`<1y1j<;~!=MUdmj()8*Q?vt=-N}wJLu&2vhXjul-N{|j z3SO}3^kh;C# z0GMD1uHx)-pn6XNuU@G}A@SW%F4I>z{(tL?caV|hZ#cFfWODwI?J2gq;IuQXLm;#ZPx9is?0#Xx=ILvB$2N z)WWPyp*~a#1j~rde zN2TucrhaRQUXFDt0BVhR!Le7~D4CU*PYuJ;>$r)0r-;J$j_uQso@j0XEoa6=0-F13 z4Mstf@(;k|tuSi1wz*~udqUgek%|7xS{|x{!V&chZILI%Qe>>!*|F{LfV^Kt$^9bs z!}VXTt(EpT1KrYzKJa?(+KTc~!2sNK%xe9bV_P^IOhliF?NV_k?+m9oZQ)}qbMt|F zE}M5;W;@8f`ca}i=R%#IuF76EvZE7rn26Q39V@jf7U1HBz>3DWG>``bBa~UhVkg_1 zO7b_K;hKx^0%vUDz%8Dr7A(g*Dy@$Zqx`NudxHmm0qvvNmXZLUcup}w8FpeXK?c$H zoLj6?>Tba<+q~WWVCcLPfmPJM=R6d)5BWa7jZ>n1wIF>4)jURkA-ROAOXVW@ClL7f zgkPMD=Wt%dg_spk)Yq$)Xzrj6L8?m0ui)@N890v#gekbh8rfPfp)4|)fdLM$Ib7ui zmW2?KpyZ`%lvx{@KmP+#6`-_okpkns4xk5%XW?k?<70eflI8)bAsb% zt9QB>7W;6A!KPTHzCTtyE$XJkd9CGTx8zf$5K8OrZfETzqVd1{QT}@o^?VnuV&oivqR&AJ+~tV}1D|iQm^3b30wIy^Jp||ZAPOL3 zl%8t`YnflWQfii0tzi?+h>3*h2W)1%ywpI=BmkAurz=a<{p&zOYbin(kXtkxN~KTC znnhUNKU#sL*1zVz_?qfYh2;yLEcQipoj8EonmE_X|MBpLAiTL*2$O!tAq?qK3!sta z;eK6R5&keO0KYy;)K24ZLGn-{Aekvh#?NWRLO{TL<@MtW;KJr?70?4YDR&&Afz^YS z0>^IS0W`jGZkeD_4G?_I06XO>fXmLR<3Go))(pshmLDhn#~(AU5ki^mW8^3{fUn0; zfH$Bw;iHU=F;FV>*)iUGa4?<)1AfoYKN*?E)%m@_DWhp5xNlv_OSqFn#Gu$~rwSGu;D$IrlI8;$9u*421c;=s4wwEWr zm5FES8(wuKuk{|o%u>*iHv<`7kdh4sIhX47yvrVq3aG1MPPEV>B127O34(jOr4VFz zLH|bmKN!RW3CA|&w$ec1Q)LBU6b!yN7jcFOig2DyIxM-aG&JrZZrqtr;t*NJs=bx^ zB^XC#!CK7UPkDyp5@5#OHaPsnf!$s<5x!h=(K3NZ0Bj<@apqoFLQBrs6n1Vc^j zO%rdy9jjAwDn0WmIfJO!2@AS}RRO%x-M@^O=^RUC5#1X0@Oa}{KQBMs^_Ly<#n74& z29;Ik$n7_~C{?Pw(hl|C>!lK3ayNO+_C?M=A^NDdwy`kJX~^R=%r!DhFyVdQCzITl`zjJI<+i@2C7nZ!90IxLJR zhJY3IJVUlm4Cp%8xq7}2$bJ<>@njhu9LeE~Rr6yesjbW3l|nD-wyEjzifl|&kGJrM zSj3D-G)zqBuW65}|Kh0l-(wI)-;@Fw%Gx%lO9L*3wQYRqC*-7(D*8>Lo??aFx~#;` z`9vB{ea0?*2_$~Wg9#X{+&RM6vpZmx8v|6U>JA8aA|H2r6hmxoxHR-|A;8ZKCZ!zT zF>|18rd1cK2VAz)gH9airQb+dGiOiyyebBB44QwK0q{G9j_!8DhyuXjavIRhxNYyo z2fTAoMbU5s2f(Jy0Q{+yp8)ERmPKX#!XJe$e9^`&^-Enzy%BqFoNv%r8peV24yVsB zRq=@a!Val!jbnBQil=~ostA>Gp?=#HI#~pw?-&ocK)5ON+K4QpqzEdRRRVeXMg{Le zmh1g;LOQ@3s(kWR=WsEV_d&&iP51|B2{4t@KPN(BB%xsZ>D~#gF&ZqxqPADuQyRnv zTy(r9#L|2&BjpOh1GAo3TO2)39SFIJ>oCItcD4B(w}N^9B>#%|-WNX_rK*CPQ<&TZ zv*F(rT#SwG0|?3>`TQPTy~b;1If^Us2$I=p zt{3ns+S;Y%a6zdZX335OGP|P-y#I9-{(bq;^-<1DKhu{0TZRePf#x75Y)(m&P0gw| z3tBZig~VK02LlbOxE817QI+jK0{YBGEJ>(*RZ%jig)}DfZqMiIW=u!tw+m~449_?s zYOtody!w*(*W(R`T>-auF!*F>76yg%%TU1^qu|+~DFa;7hJtnz8sT@%3= zx;Q?L+dO+a4+(!&peAEQQzlgi1F4J>G7uM3_-0~dH5>I+V|kYDbpl~1(uTU4R3)8b44KJfsU@FEHUf2$`%~>_ z0AC45e_={--^>R;CMJU}^)_oXsbr4@FPqpfrUB$?H7Xlf^5%->-s2GW7Xhr0WMw07Rj+((FM7mF>)$x42d&J5&5biv}PHGzsFfHHAQs^Ju#{7 zk^@qGTGHn>hy-5$2NbVIP@JD!D<}^dEoe4Y-rE;_XzCd7VzzK=-@OIA-CG?iFzqtg z_onPSUl6UVWSL5@%?Cxziy~#y6q1`OVU(zvurV+2=OkI{1m&@8q01GQuzk0#9?`Go zG3369hG@_o#c9P5F)AkY-HU!tm?+kMELPt#Cl&2&DL8=;qYg2{b4s_yWFO=I5-268U%;Dlst4 z%N2T2nEwF_gRc1^1RG~`A_N-NRDKlyEO(@wjeC&rHiS;&K2blBl&8~AARmFs12%zh zBP#D&ks!Y>FU7WdAnt*zt>>ItSJ^Cqnn(XFTw23!=R5Jq`H(*p`W=3}Lj#Y_2OSB` z|3tz;b68s)FOYRvreIyWRy8ECyjO0jsr380Z(}{7vsi|brTJBsU_Awy{chjnLA=q%b_J&bDY{0NMRe=OcG&Lvy_AXX3jQSzq-NRb>lK}=t1qdFc<-~2| zCi!zLACbjQ-`g*f7>YU*iFx+M=cNN(9O+{g}0$9m%=)mgl`7PA?|lmx}neO)Ac9=*kY^s5>EZA-fQwGux@e&tF+9? z)WJ1mdfg^7Cs)k$eW_y;vnxw=>8q4WdYg;eMCYr>3r%SUdyVsuxWy~vd`ER5%9!Z8 zcWU}CfA&+{6HH}k=osYRF2oo2!1a{U0cHp@z~D2p0QRsRccvNBIL`R#s9YlyFDYk+w9UWx_%yK?6F5 zAqE%~Y-BA`lE*~_fMV*}WI_RAZR~)~9x$GO|zukiV7k8`Pz}!V?X7D9mg*vr9~i7H09%PYVr*_k@6IU{%eCysi!b3>qL9ihp}_S!=TZH)S02;4peO80_1bBq#xa)T29SL1JDDk%{| zqc0>@@N<#FI)_P5i-QrGa)*$MmW3bH03V9>)T4UsQ|t_y%N%c7EC-N4DsiUyT(8dL3#cKbQo+ z`Cl-T*^0ZnhS6S&Gms6|vw+MAmE;kHRbX*n6hcM=G!K5jgpKqrT^~f5R)o##BA7=5 zCQlbS_)5E)xg!=lxHM9Z%tl#09L^x+u7I@PS?N`hlSL%nSSzq!RlY1q!PJ=l9tmWU zfKe4ne6#m5t4^WFD=h_$sX+Z->*#Xw3=g5kp3RkW>_t%}%YcAUQCiQuU_~A6sgtkQ z=h|ZHv{TNLf;$7@e@5P4@U@L17Krjf%)-*B;a=F58pC!fvYawDh?t!yOK#`sUiM3e zoXk5DjUa_yN)$@+1dSorKlLgIEev*`6sSq%%gs|ZTucxzygzvxjW(<&MiQ7DxpY#K z<$woy#A*OhJGbantD~Gm$l^!`n1b{zRttWay*5BIBM$kR1T1E56rstv$%=*sxrpB1 zx2i+9_pi$IV0w>&Dxp3-l;o-1Wa_}pDk-GKeTjJ!LbM@Aq04JS*EInIhcvBvzK^bh z4ghZreWwP&Xz_{hQ$uRqV%OL&?OF(RZiH}t5_U6O^H zgZ^m;yQN<_2eEgV_z|{OrH{f*LqoI5L8ugO^b;*OI=k##7KD4o*R>$dV>xcVQ0l1J zs+8{h;fs3~k6Q(%bH_8p03G2>i|z?1|^HfT&`vxX0ZVs|qT(;gZW;FLl z>+l2|d9R0qUVOjMrl=U_^WbrFeQWoObiU3db|EKo!74eMfK4C4K_2Dh^w1JX{}wWpqQR#f zMLekNdB(hM2sSF?@rpFGrd$Lik>W43I-6{K5;Ij2@JX$a!j{(bzDN*x)naB{`dUAR$?wQS3S zAHu@2vJxRR34^4da8f`ub|0J(8C0hXeoSz^+q~FCa6@2QyHAW2C8SR8LzMl_qL;=b zr|gp$tO-|bd@MV;$*drwO{tIn4#ant%$p4^{mWd~j4yqreERqe5|J2Pd!KVHDeYj^7bVtrbZulgO>}~lj%za^GQslHXSg5P5|-UVu&z%<=D$mrPB#M5x7H^ zk?7hNq5r_!h)@*(H+NIsd4ZIh4O#H@MO#@z%Vd_kL#n+VG@bRY%t}Fg!rNE7l2J|vHfi)S!R(9k=(9!<)g(1uz&lROu7 zv7mrQD^59gI(e8cD~h+;AVCahhjLjuC?YlDnUI*WR)6cT)fWzTyfNVwo9WL4nMcF? zM{NkCw6j>`>AIb9#(m0X*@gUpfHcGeVUjWpUT-E(foGqTKQZ=?(GW?` zC!vgi4Kg@qR1!=76ENliDPW6fbyd(Cksd64L0txG=(hR9=IQF|zov?O1#d zLq-ukk?WgOSX`bvv+;0E#Y}_)xF^rvV11*926M~LuK(j>e1MgF@XQs>YqEi-2Jq?v z7-|K~cjS>iVT2{D!76Eg*A%g5-9y?$EA^bY%+;NxXd-PeHT%Es%xi8xVqs@*Lp;}0 zPkP5A3#aqubj9!4#XMBFs29}#oBx1n{uqVCzr|1EGtn>9<~2_9$p$li%0K*&Kz&pD zc!49>N}gPL6;?JAyM~O>2V(hgD}1z)|GJ0!o(&>O6`E{Pwr%!1%1cK2@=f)TA^UZCX>^pWnhJmh!PTg^p~u1@N|1gDRtmtstd zPENijX~}SIx5ARI7yneZI=km?wAp)j+#4gu8?WjPh9hBqV=SevY&&6ZK3z~RY5F&c zASU|lv|IwDYYcuVIIj|?vjZ=VEdRRH6~@$jX`Ad0-f z^$WnY@>5GJd<7;>PWiLFvAG?F?h_yE;+?(&U*0BCc|o87Q33h0V?{8F7rmi(B5_c! zExKXtI49@7WP%`|lRCBND&H@QKFdE@T{UdvH@-41mWHJ49311?t0I2h~~ zUC0PaG;!-SBs!e#u{yc5bSwCbLgGZmVwFy`I7t3}m&CCvLMn*mMI5JlI3VNQgXH9} z^WEyVcWUe4T01fsx^MN)n8ZZ5>|d>H^1Twen0Op zrZ5#$YXwS1F<25;C8RhutRCED zyzGZ7LOVV+uZs2>24V@v2#)FIVu5ydR2@M&!qpkPS1G@~9qCbP;M3!~c~ zrqfk|2cIp`s=G)5aT9<(uSzb5X~3-RG-&$CIuM)^rv+4tt@b6uNl&e|mDtTg_H8`r zhUZZ&zVPFoU0Zg_aZXhUg$jSjFI=knxH>oI0M!mVH2t+oyR4>Zj@+^23``_!64ThT!T|?htjY8LUvz?&sI2b|B|5BcY zoqiWs#bF~u7`xJYhrrTed8f&@lY8nZbmqNut>_XRjjC7zx7B#rK08GsgXh_9c$jbi zKS030(`a%pTFEM0bEt&H(Z zUEEqEQ2L#Nji?Ml3zq=k6=nIRC3bvR(r|ajL*T>vEwkuelj^w19$#vP91o7VN#TG7XD%K#@&({UVL<~XX=K+Ls^=9- z85wF35D`!5_F(dfi%R_C)&G>z$XzCo7~xYF)D zeZiJ@ONI(a$KHyv0WBfXa9&6g3Vl^t$$J%2I&XsE_@B&3z&m2|_UT$eY!eA~92c<& z0H2oNXxutSq)_!HjVwsX;E>DlI$Q|{*dc2!8H2#RZbg?L@)R;=ns;pN%yglQb#(C& z6i#j{BeX}bClw|Ml^HzWRH{$?{GPd`XEQel#<39g{mA;t(G{I1|Avy|@&uzi#b3i- zH&HcluHn`kKwJ(fJ%LNh-St8Bdz(A_b7>p zwp?I97=G-i)021$2c!=E8ee&~ABuBv; zJNYH%GiWVj%XsQEctm&9-k1|A{v~oqi)6HK3IAg2h!cg}souyUg-AZ3Gf@!&xgIP& zGNG88szn*Ia#&4?%rd*>19ZY$VAXaYNp&Sx->cH7I}?AE`0tn{5|M~5JzPm=eNzbo zDUs4@-5}G_XG$59=6)6c_vk5Zbvakuyrc4X1{T0X=nmi;K)^|sgiM5Nq3O+`gfhQq?=(zlfxSfsMKL!vDgcYi4i~s zDqPQ`*JY}~yZLx0D6OAo*?D}25)B`81m(p>ZOHxu!z!ME?C?UUO|`obqC-74pFwFpa$MHWYS;M_MFV~~ zM9c9oMqQ*Dv<}OtqWannHTIBBuh+kp{(~3`T+x|$gmCIiyyI~|KY;FI<4U&KjCY z?A7Eyu}#$TEnNDPZ);1;6E_QtPg zWG$G{>=R$GZ}a@ocC$vslcwkC){`~A!vv&jHDU$-(h~egi~5F!C^&A-nC~Dpud-EF z?&7xK%2KWcl`23nAOvYV;q4SC5#8xhCR9cl`t%Y|_Ie9d!ad7x2^UFsmkM&=Gz=g8 zon4eUxTT@&?|Rfc`kW0dj1xN(-anxmmFn1hAB_v)iVE!y47GMOFc4m(d8n(=aU>?a zYE6Rg_$+)?XNtJK=)8G0{*6}-#hriDRKLc}G5g#@RPU;rcP}_wr0ADak0Xuh;4WD> zA!fAbL|aGE&`>P@Rlpc&DuBs3O!9ZVGEypm#~3&logZS{P8K}vEDTOoN6~!3;|P2k z6`S6Jq)fXrG2ntEd$t>>X_rZ*V)P%rLMpO8szzTq#6VW*lvzKu-Xjubr<3>Lsc=_Ih|iCl z%C&TvF_w=I+Qw+9Zn?UKJS99MQq%)URN=GSZ9;Sjt8me09|ke6c4@N#{2v#_Qy5AS z`nhg<_SD_(qC0eub(#p9IIFAo*VS>BHmMQ<7a^F99ChKZ@K!lEqwt?tfPt@YUkoV+Krx-4=fq`VxEOvefimGysJ5N#>ms!tU7(gvZoycAS7vY8iwzCj zvpPiJ1<}_|Zew6ra1(H4M3sgeaNma0_t}owfF~yAtVax z)rGjoQlI7C@+;|HJG4_bq?z6`yz$R$xe|-X+0n#8!<|AQNgZF2KZ=h6DkEi7GFl3j z&rjdJ^C8nXeD8;*uhAWvSYYL#2=|}2C8jP+kL0DeRm0XRIUnVxx1mW?zOK?0iZR$F z#%uWr*~XyJ^EYF#_)eRChGf)n&%o$n%d|0qnG_F#V6mc4WxM>`A+ zSJ=5UB(D|Z7HT;&*k6y{{x{RsV%E~+%#4`}#=dcDw=kDBCB9@|G_;jOM+eaDsN=~< zsREU&L|e{*&dW62RIN046J>v`jX7#{Wso%mSM15L#+~t6%4zO^-LnuyBg`fg1YIUA zP9?{G8@7_#`kk&YEsGp5v{q^GFsfoR)7?;^@G(;kHw?s!X^u?ZnIkr!0t2&}_s^4h z7U5;0#M7)9Bu1S>Df`SSEt4gSX&grsI0$jZo!!UTFCy0L!yJ?4jXem0qnb{WcZgdI zrV_@n@_2SrbM^JV!8qorQN>8bJADwUe3!(u!F?un#e*cCp_NsnzqDj~UojJmoIqya zP6dS-RxB78wZ=;@77~T@8>_b;b}Q}TZBY%@oKKl#k-Tb{3ufg6?3`np#7Pb1DK{E` zhwKK=_(+OcN3)>26`;nccU87SMV^?G9ESc7>|eCoOs7*Hay8lSg|f+^4B5sEtq^%N z{`0|}g)KRbp^g>MiW-iErwb-SG@jV|M0qjrrisG#RFX=4b zWLsLDEgF{2FKE&((T6G^Y?!Vbq(d^C!OVo%*_Gy2{h|QgDS13>3%>jk&<27}&|8OY zkGL})8mBH;=xq2;aQXuM-wQ2W(XuImPFpGn!*xLw(OoEBG}~g?-`(Hty?fgHsM;qM z18shfRC@=b$}iVhO_`ivhN4^xSLt#t$lJX!f2zYE0g@s&Fy_cB4d#L{F9QDIq5aA% z;)%-O(25h8;C^7Uz+ay(tx+!+d|(>E_K`f?cPmUlMx}TxD*C{} zRy%62(YdW|3*|lk?lGTEwK5o|#9CIMaq=Bal?4K2Jae#w#J5lcM3z)NPU!@vIjpyO zJz#`Lz#D$zC4(o!KZ*<46r;1^h7qyRC*2jOo9}aH!H;YMv zLdQ6C(Pt<^a-3?8Cr)gZf6BZIwlei;#S?%wb(h!IMjqDvSl1IG9ODA8sFY29Spj+l z{xD_ViCQT8XnGr|3*O+J*-GFG$UGtdtz2;y5&hHamUWdkHoA)a2Fy#J@GB9LV#Cx% zkoZR6v4kTrolzbm=&xZIA^;gl^a_Dc<6krGjmpkSLFmK$VMX$!b3Hs%mzoL)ff}-6 zf=kg#0eCt0+^La}VdhXZ)aGkjCaxYZZ7-t&Y)q0(O#^f*UAc&%p{#6=7ug_f&ML2a+fX{+ zP5BnJMJs@-$(`m&p_pMm#A%8`Z^>`d!P6Lv`ag+zy+_LLdGPoRvxM}kzEuD2`Eh?h z2(8a(R3sY?s{b+46_9OB3(&X^tU0@lEM6w1Bv0k!zykz|E$DYf_q-3pF>e~_O1PXg zYB#fLz?OxzgBox!q+>25&=SRrE?3!rL?03f`Ld%DTgb#bc+;9 zFR@PB{i&lF8euRJH~vccrvz>>mr31RJ-lx?JvE6anrQ%HV@Em*ztKbRJ=x@fdzUFx zN>7`|(2z$M!VIc`WscANe;h42-a=UZUU!!VLfAD}T(9B_K;_G$Yzm`axd|}KW0Wwt z{D-eviFjOQvU3A2A?ER-BJR5{ghb5;ksLt2%6`h`fUXATXjAHTwLXfm{2r|!3yPoM z!V<@rLQDR_?z5{8)p_JW|Ihy)aB?LyaIZu&u#d^u0!ZZ%iLxghMzdI$m3PHFzwm1a zaH{WW8k$!OWb^Oz2->i-kvCB_%>^buPPR8f#+hHhL`X=M?HtWS8mC*|LQrox+*f|q z4=iBEnzA;W#{&X!cIy3FFo9*7+b)C1cl<^PSgADfvw*h9B3ej;AW7_wIq?4Bw78fc z8VT?X(9ASkRmZeU_EE-!55vxV#qa7zy|T+~G>!y5I{eUZ+5Y`X;7^+b)M@l$LlUuP zD!N|m1M>Y$U(AFx;+FzRb}g=!?>8)8r1Jbn5e)pc>SuRW;brQ@i8O^vNh`Zc{0_*b zLKx@=qvXKo!3JAK7&EHiP{{bYnk6Qig4QTMdj4R@NKZ=Vwz>WaX+0QF3{(K=d26WZs!OifyDt#!SiA1%#T(5*M ztyrc(W@-vV@uxmB`>3pGV>0pXx|e z2tNh2exf3TC$}3yELTBw(ZISP`+@cgDn86WX37OZ1N)i;u#~Td`5($!0y@ z)GF{LSysqA3C48f`+pmQ&7Z^10FJGUJ9ia(tEgPcTpL-bjG&>neLP`wbQlSZTS>!v zC2AR+*9|*ASSF`=Fc=y2={2@sYa!hatT3-uQirb%7J8K#G$O$YtZ>r1m3P&OE7b1Xhd?V0lx4<0(oRMmPfw zgz7o!sIyiVM&-p?%TuMbw;JZ~v2didn%CswoYLr&^q*Db%dWw$S@g~lc2(giM|i>R z4D{VpPiErr6IzqbM%@w#fzf`@<%gG3R_w9)!bd=qcJ+7Z54 zr^Q28SWk6WpXageB>B| zX@vXH9_Gfc8FS?g+GY(w`99wple%!sP8;3n41C--FrQQQ?{(VRyx?-iBpWMq*_}NP zxn#F>ZM6Xpo;V36wsg!?Si||RDg%VpOtiilF@7--zveU#DNmCnd}sf}p$%L9JJ?%0 zPmHRXU0>)7kMN?*^C;$F_D(?7ix>$iL8{SS__&}10CgF^Bca6u!k28C1M*s@7G^B|=0!yndal&#o5Y%aSdhklH*GPsI`KHJO2s^C;ge+NY3BDSg znAJ3PouJ0O*X_+gAtHP}&T7>e=mX>5=IV*{-2m*RV`$sbUG}⪚pV9R{~Cm$kcwD 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

    LsjDjPp+3+U)%df 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�T@e|i>z&CzIJ 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�haf@K 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�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ξ}H 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%0DE*LoY=I}e&}Xs?G4dfEGZHco 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

    =6N%UE)wbLWEM+?7KaS|;%Cl*7e&X3;Q5 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 z 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

    < z-$gLNiJVNyTgM1tg(t*e3%B9|`K4wtXgA$0(ZAuHGos&6z z@K2S`cohv`nSg9?Em!m@{3UmjC##27|C$A?Kg{Fg<(=-{q2*}~iRm2g`ajD)>T%{- z+0q1RR2jJHZlyLDSVbjAt9lG$8iNZ+0S^pKW(9bK6nZi21oGlOH$yXvxAiG7aO39a zff1o%f0P?^Y;cfKk%rzkNidT?ggyRUr%Y5^8;>$HD#m0xr|*^Dw)FbaIv+Omz}rUL z$#4M*Zb4Dw3ULO_zD|L&J7K`mg*vARF>6js$r=0k;FY(0VMK@+%ZQ;W za83TRIh%V{ZKxb&o%;GF(@X%2cZwH(m zafXiFNfN;V8OFv|IC%cmVxB+;r?~^9*N#lmBw5%wTh7Fi^l@btxc+MA3BBN@OGHCRSeKPiw? zFgyUL#307Obuv}p>26?B?QOS(IZchbYSKer_!Sp1kY-bzmBEWo-jtGu9m-#>ND@HN zk}_!7ZM4a~b|n3(B*ku?ckri|_|uAoB)e_;oCVsK>EVfjB-njOIyK7(8!25?d4`Oj zZC6DwroNBQDd_L;^2+-GZf$<`FFj|QF3H>*(cQ{VFG-MBVd?tDl97t<}nU5%uWMm`D%C|wpua8A4a($ zw{TlaX>yffQ=#cR6e;_(bjOt39cV({BH5}U^=Fl|#==4vdy7}PZcJ0?N)4SN&A2Xe zjzcR6qN~@aFA(jTZKMvC9bEJ{`UlQKs zw{7^8r5bf@9=ue(nnqlGIX86ioxEaP9rDPHip;W^1r6@b2K#CWza18luLFW3|1wmM zW4ez`iMO_73N^v~zQW+`t!(^>CA}#-a>#e!P0drkQtff6DMNwvkoohfq|RbcnhZ73 z0!ZL`kOx^!1iMw#YSrP)KGu*;q%-{$5bH+-r-n)9DTB4fV@C|r38-t7bo`2AVYlV= znZbh$+W`6`rObwqImv6_&j~$ipzrgqT=m)5?4tRw{~kyied#RhHXJjYHGo4?5B{!; zcZ^|X&SR|fnzAur%yW_ULlA0d!;VSF|6tXk_$LNW)7HRhnFjkzO@VAB;h=Zjs}}XM zG8eK8wKP4g#}`vVxj(_iD!)(p(>kmOoaf1YShzU8)5iBwu=(%lVr;WC*{a( zJsUaj-oT4ZdT_8&w*8beHpyvrd0?{MVCvmfT~AK7mr-0o1FyGl2A{ z!)w3zF{dNC^{3$%EWRgx4vw~hjB#yq0Q&Kh?di1y&~`sc@UOZA(AZ>_4(K7xnh0o- zgz@6c$zhf;l1Ir_pan7PQn%L(W%Ciw-$9ErwTvn&Ux%wao3fn~@AEQtvGgQ|qT?E4IflV_Rf{N(}*00fI#}yyTYC`nJPs zS&_l8dVt%MhbH;{W@=pBv^S6j^CQ^XS_DT>3VdCnL6-0RJ(sDweiH^z*qs69pA2TrWRDR35U+zzNA=2UFfV7ujp3rcbhL)LYX!*QnMJ+=(w(-eA zgmB%-qJQare428%=rt*w$WRC-DjLZJpMZb1lq+5EUPg^@%1#@15W0g2Solzlz;L*i zw=VDBx0#N$NKtTiBRv~0OW=CD=su|D@G$S|1Z+Ob7E6WNn>m*J>{SG68d6|+2+!>w zfpoAzArCo9M;T6hYFu7{1x`MGAL(K!FpBCGt1gB=O26l4`P4YOd+D!BoWkikvdv)0 zq}qA-y#>VW%by|q5!}aY@m&q<3}mBin#&Q4pb-6Z)!rfhY1l@M!MajyoAh-aJQn9f zTf)($JEAfrC0igzmX$O*=#a>|Sqv5yde|8phm5n%IK`G%`w^zm&mbaqV2coy6{R=d zn?@`^{Df`b&V5KOovUzKYXtD9+z}2Mj@`Q&BzbACX%xqE{)iq%phxE}P`@PpbK`WN zF1%6Qs{DfmuDAU%NVL7-rf2x;OzFq$XT9Z{N&3j}D8fY4VBIS@3Hu=dSU z_|Bp$y^rI7jzh-=ZB2xH5aB2bg^>n{~*&A#z( zl#uRmDaNUR(+a1J9=Ys-{_v*n_WqN#eohW%gu1Ls#iW6R+?Bs?t#VqTo*Y z>u&4k)?x6CZ5x;SIbnAM`qbOYKX1GigfP_u6Gq8Vkwm@|ZS4v;r>fCetmH;bTW8rF zYq3na4;XuXnydYFRr}IOBlQ(T1n#e@#?5IaJb1M?T(Zyjd4_++L2~$%syYg6n%)EQ z8W<1=AZyrauO0r*Arj9vX21UTDKi_gQud?2F)x_Jmizz*H4rG`CG`0Qt zP;lYr@njNP9|9m}zq+>+Gp?LWuI(+<*^Py3kc!g}3B~EzNQiC<8gb~$F&k}ih|W{B zM`f5E9M-4|5vzQ3!EpBa&&SE?%XI`%Cl~z@E*R0JhMrCp#wL3_dU}mC=2V@5#q4&H zCaD&4Yh=w@y4XTV>i*3wOaSp>)LZ*SQ--m}3$$FcW|iIJipA6p|7NR5(RY>F8#A!c zr2U$EawuG3Q8##V4^Vl}xciYUFpmvP2c$0Vddj31RA+>HlfaZQm1Dw$%@b}LXBz7M8vGbO#e>1m;|xOyHLEMnBe`M?yPH*rY#e$4Eb0AV8c-5zN)GYmp0*$#C1h zwz&A7)C<;)BM4OSpcaZ~IN%8(`%|>YoOX8Wu79zOZMA)XHs%AS?wB-=*?GS#ha-{j za+Ok7kqWd=ut*!{IfVMaHH%i5fozk}kB#(rfp#!V_M}p7vgPU1US=91=+LVj7j)Bv z_^pdUnKrLnI&Oi}R!th>h_h{rNeteEKR!&ZMiVd29u%rkWHHFeM%HXZp%=x)C5?|A~%xQic5a(8fKyl?Y^!f zs)>4~OvGzQPJzs%3pSadR#r>lsM9+aN3&LfSE{cUP=p0t3avt>cBxE9N@qhARBCX( ze*v}+PXDP!>7C{tiZ1);N;IyW!*cU!`@3z~Enz5qaj)ukdcT-2ARRLz{p(UWRG@}M z!ej9>jrZEU8#eT5pJ|}5Xh8l;$pZvCoS1eyJGR0on)b=T@xdeEZY|Tv1?r$)(S@|j zF3jqt{4eO_CZI(oPpEj~rd@K~0Twki9#^X$R0o~Eo;`3FNjvxVD9SbMfGeaVvOLE{ zp0D_5HBIVchvOVQ`gV8|SDLjOR9P?W4xq$vY|J#4CCR}FaICDB^9%!(^XTw2n@#_f zVa}_FiV=72ZS(<2D|l9xfv|kIGsWI^R68o%Wuyb)i>Ncon$@ytNy?d0QKn|`Oajvd zxhEh}Mx8AuEAaHmV`(P-;J8>%)^#PF_l0n(`Um9L-6qb@RMWxX;>qnKaC_~sDkbmzgK4SbZVgl&g30ll)aMIjRW|=EcM8e z3rNJ}+)x*{UcMCDe_~l-P|tV94#Uss0_R=CzyvawFW)Z|<`VFFM&t=Z8w>o}7>h2L z?S8K9Lap|{THtG?FdiIzU3tC*Sgw-}4rXCLMp_`wvEM&8E_>p7TXpxFN3RJF z|H2ucmSc0e4qD17__=+%FIO9JhiB)(-%v+&Dt{z+tc8ei;npn_=>$u zKPB+Na=;xM+~>`v*Il|rc-fB<(Y1oi&9FZVHfxV~;7hm82wMCs7Dnp+)VV7$_k7E? zFr{%P3z$9+i%PXc{~KjV5=>!9+0}N+ITrQ+nTD~O#HU-yTngE}j(*IVqgjV2(mZJY zQCPOnjb5DPQ=TUxC@eG0nOCoEYkBNs;#%HVVyK{0b6H6zjbGmn zZ@{e2QK#BZCKcQPb4Z4+=>pzLjF#WV|4i$}iI-K%^tnis(Fdh2{M3kqcmB7lRBR~ipuY!wYv8wm z7t0Jk93kB@Z?_ffInt71@YtMT*rpohb)g(xxaad2IAu5!==PHq6=>c`4AnSnatq*>hD#(8GcE`NlG8+AInp_O3f^TVCi25SP(WV zJP;tB#kSkm1zRM8Vgtfy`%q1Tu0LjDf@*2#UZNe+_XHHx#pSunHzMB)3Bm?nvinlS z>N`Vu;wn)rgvUgQ#>`_3@$uI4T$M=6llLSr{F~jGmEZf8?L#s}ywXz97I=m7aWs|0 zD>+=t@bIq<$IMKMca0yd#mrofJXT7JXPI4i&8T;4uWVH?GXoh$e2@&rsBz#jR)NTQMQnlaH&NfGP9Mev#QZO5=Xg@S?@pJ;)+6*yXb3~C@H(wV^hlvv8ijF>RA_iSC9uXLL;z)tdaE^ZHcSey4=Hk&I|&ij5U+I#lo$Rbp!P_cx0PQF|oQaEBE;uI6n3T zmN`!wsoeYI*VDvdVt5yMGa~<3Js3tuc7qgi9H5o!&MQlc?iB&j0k4A)-PeaYy9b>W zjjlBN&E$5WrYl1;FUoaggjee@HPrf?ovWTLI^pCL6ve29hCo^v-gabC%#=CKmbLN;FpX{ys>`>3P54ae zDQ4xbENr=^Tj6r>7NZ}LJQWdV!SFSv==PZM0Lbq0ksU3GiI)Ur{&kaCV6J41Q|Dd}&I)h{~F z^jz(MF@wIjbqTPgw4Xsj)FDQ{0liO&;V0d?nBspfwI^XK7a-u0yT?n`m@|hQc;h#s zxjdQ$H*`z)ZOolf@ox}C7R$j66aH4bOy*~fY)kjXb}<~2#sxhVCDe5&BWF7+UHGetqHqvt>Pa+H_piv*?j- z`8y#?+C=loNPjAa8Ui1-(@Vab`si0$1y|Qh^$6GDw$U1+^*uLO#3~~9x%edLOu@sFA#E-Ijtg$!)%t)QK+>``?xM`=mZyP|=fLYSr=7%C%E>1iUVnB6 z7}>9!?@){nOBb(nyg(HejKCIEJTp*Rs#S~M|2e+;e?x~8fu|NK$12Vx+%ium@V{SK zV&$)Uw!c5hi1`-|EZ&a4tYhB$c@hDVgzGY5J{fHWUx)B-@exotVOfeYiVeR0?)|zg zwO@h}TzjM-qS!E`8+Yd6?K@@9DMfEu9ZCl^>;;Vlb{L*_j)DK@u1~*ae;rKBp9=R= zCL-S(`e*;08)u7#r3f-c2ZHw@|F`OVOf56^4zVR`B+if4Rl7ZXTnloX&^%eA)b?Fi z8EPOT`< zw7}VW=>5zJY`~?@XN+?}6pRi>rcmqlEZDoj*fv8`uOOPJm<1`;59wTIhWqOm9RMyk ziT#~vrbig0V6lv%R2>fU%%?FWE0w>cUmx?Id~m6 z`O~HzmAp#=acYlnmvCHItH`7mDz^|!HWRQ7mZ|D=z;6tEj4^W!R zRvoPRd#Ip%@+$#OVUW%u8f`iGIR=vRDecp`$=6{7G`zaZ!+$RU=sD9rU+&#iM6#NX zo2j8s!@UHBSNE6OfFNjj-Po-sIorIo&Gj2QC#r!!x!XPVKs&IQL9Qw+!#7*I6Pa|_ z>QIUbo2xn{)npjfb0ehO{b#=tj+oHu$}03V*)nPb9s;iz;L$>p`6neurLxtVf-6{@ zPb{CruT+<$Z6=D6{reqU!j^KXMPapy) zK?<`)i7wOi18$@0p*|xI`G_8$vItMJ#J`)@W*EOE$bP}g(H@YKSN^jh>wN&XZ;^D>((_at<8TOUwNEj z*F@wdMqSsNN>q4|Km&Js-mO7jK+Y_% zJ3>s{&)0GO6$iw&pfQtEY}U#Sxjp+kqr^cIcq9k}J~jq49>!Xy;LZR11WgHW^4H#u z*Mx584b*|>9AW{2u^D_>CTpY0OhVg^Z2Ya%1|>_CCVTk_6*E=FbTJ9oSq9(p_04HQ zcy{2;Q(y-GlbV6>4Y#@mZ(u*)+~b{VR^UE#^WbHUBoR zZdyHhnYLu}#h`GKqVpyDcm-rkl^hFNlKCTr55#TU>w%@ieddPM_&rxBXX|U_h1;-` zC^vXMgQqWHJb80_hfTWQF9A?2*20rX56;7@*h?D20U0P|>Rvl&J)o_xAh_myH4T3E*$KF%(Q3nycycWlIqCg@obf?M8}ShR9!2v`v$Gn z`Q?M;X7AD@OxPr+zLoj&8!SxzRnYB@10{D?$B%{7${HBM;g86==9TzP6f465e=Qt1 zwz^wpM%ZlW>i%3Ale$*L3_`jE^ND>K96$vI(I%0yU>=F4ILusG;5|C8T>{fU;8L+P@dn{>SLjNOXj)PqF(Xc55N}mbnSgRCtXiT6q-Kew-O@gyT*HX6a z$%Nd7&Ptl{(_!CQOAt1Sre%YBZ-2y2Kx6B;n$saokfz%Uyt z4VT>;|Go_t3+F|&njpV@C>0V104rmun-tr$Eu6MG^wsNLkygP6c+D1U_73Q_!hkSh zA$TBrg1Yp2Baq%1Tr}40OSdUOKQ!~|aTuT<{{Ui_1emAso;n=%T@>y4BFaS?CCz4Z zIqD2D4%wkSs9^Pk4qYEh+{S#OdIyxP*H$!Iuot=ly%8ZI2BGzfdS8UyjrSwtXPRa= zAw!0K`qj7Nahe1ad5`Y$xEJ0b8^r*u>ICW&f4 zi8XzB$6r%RUi>f8&S^muB}jrZXKdTHZQHhO+qP}nwr$(C?Y;X2`>W|SaqW_HZjDWyt_bO`AfF=g}c!*5Qs}U()G{6NSa`ajh9n)7keP>%( zQaS4rG;~>Ixjh%WydZ(4!dP*CN*@e?wMmr_^-nY<>gSHvy4*&Yq{dOux8&b{#$Y3a z`r0gddkB0c>$r54HTTzP$N?Vq<#OsoQ=z^nM#6Wq0|ol11kC`RsT=&Fe0itc_q$nC z*QE|H6czdywoQ?EnH9y0#Ja~tV2wHDoDoxxeg@Ncx{mYVa=&Y}6JiG+^EDu>Tq_=A zJ}yu)#zv^Xr>Q>QO=y+3uP7;Y4+e#28vb*^W<{k#Xx8P{I6l$fVyOykxUgA{gT@*5T@53yC^{6`jWp_W=MX zSO^}3h5BB43!r`Vh&M{$^w!b_vdnl>KcxI;z=pz??6oXrJ(qTV4&e_?su%0}WRcZB zDqmXLgV`ImOA&Ftfg;{@VPV6nRCn3e0iYIO9i7m(>V)rjH2kqlg)RMf2Ga|*0g{h0fSr3=BoxtmaU&~%46)*3d2*cM|czb z@wqSFfZJjWq_^jz=!upEVcgO;>a~d~K-ga7(7+ z)IYil*EKtn>3|&4`88%D_EGNwG~uTRX~4TMk7Tai(b85FMj7XUM3%F_4&gXg^_Va7K^4?+Lt|xR?->_9Ns!{cZwgb8%A3z zt@me4)ddBLyQPXD(|5%H(cl(4Ifv-Gn&dy;jZM5L-kC3KTlhq2#Kd{QOG576^K_G! zkPsuMM;TEDLyX!Ae8`w`kBu}url1zKC-uhYK#ynKo=n~5*L%)=;jSjgrMkFPAM#+& zbISU!oFj8JoM7LxHIBj#DkW7>1|bUBU%yR)aR^sng;&m$K4Sh&W&0P^k82+Q4 z>wbRXWK?Oiyw)87i%~=5InTxLNQg`BlTSugC{Z<>DD|DUU$}2`w;KA)xq?L#&Dak0 zO}br(3-Avw2$S8t1o_h~*yIZOm%nu{n=_*eT7cY(*qMFac^{lC&~?ZNfAzw4(O(|(_)%bllX+8H7B zAP~%EwH)`_d=|1su-}a1J`$s3(uLF()9d}9p-qY*a>~y6{f9&yIih9wY5}!rGkYmW z%hg(aaP==}s554yw>%iD5(+PHp)BzroQak_zr~`{T8WQgbRm%$_na^*kDO%b?AL9w zO?mlT1e;}1sYGxz1;gQEsad>8DHN%p3+nyFt=Uu$WS>4fwy6CTEYF-l8l*Sx> z+t&AM75NrWmkp{ZXLG?fHW_ap8tzvG%{%+(4tT`z+62q?X#T6MdH#?wSQ{>QV7?iW zpnHC=tOmFA)I_fkvCN`fzBG`H_#g0*2-lDq9 z5i~cwWw>hwZq~)RWwU$-39|d-!h2}pH})Px)EJ=<`v=2RP~5oq*^+xG;9iRfE-JIh zo?p|GOO!Rial780pZ>W+hczjIIH%ehcAtMn;|c?cMd-@V{9~cieD`FLAyP#bDL1}n z_()@<*`z1xR+38_#uLlzs1**pkCK}(XM#{ub2P5ZV-hE1y=dIN|evt zIi8xQQJCCOKU0Mrm8*33eDglge(_MT$mn)j@B2p-Q+U4#as5&0^DIdljY^c`00VD; z5qGIFujZqpUD>3A`~ag3`=ah;O8L9fA>2hBqJD@JOF=~}xWi`9oEXIt6`D1iP*+|XM;=t9jd7HLW6J$_(l;nV&PoSDTdlSZ$P*>w%e4fgHbUfv`}1Fz^= zJy_BkqeH)~=CkZxqY1`+Ik+cjm`69=`WiUjTJtB*{4B zaeGxd{vPDuL(5gLYOU#oEP5{DSP4yT_McV2)VY#gpe4^xHU@%jpB1Fw5V#{UGWuSa z%3JZhyQ%So|YRV8-nSGEcZliAHP*u`Iu5c~S+kIvE=(pI$Ng;YGl4rc>Z z7BuxC26{>Xsfh2p8%r@L%Lu?v0toZ_hSy-VC*IpP@M3Mm)FV{J$fCvX%%E`w3BsfW z3S@kU#v{V3lJTGu=u_TL47dVZ<(u3tc7Q^d?)x8*VFEkfxsf^EIarTZ#1`pS`S{Mv z^umMZ*uy%syz(9m=D4tK1>>SlHb2;3Qo$V)Xb$NfmF40Iip4~!VaYbf4sM?pxiXkB zvrAVjK)&l}<*1e2x)IQvDVlToD|i8^zDcgcei}173_D%Vo?nkryP%ivSUeQ4ukPIL znpftF*_v@$8?t}wRy7V?pN1}Mi7tAGtkK(>ljt{GG?u}Wp{4UWKX=_vIWTVVxZpyA zO@mzHh=CGVVwbGBP|E|O!_$W~RJWAX6SrjzPO_sR8mDMvb&btNMj?VQ2KJTkW zh8wN|i`6Ds7JKzyqckODvKcHKmjnn?XS|cK&#uEtPj%q1UAUlXuc`v+oyJl9tl0Gx zO!F(HIevHWvkc7JJ(nVA{qEFvbJ2T}lC)gW*Wfm{nw_m1WT;AU7R&ez?9*%!R4P-* zz3A@qwkB-bmx@E)WXPUPRCcko-zDZO=EsY+_=Vy5Vz)qfg5WRP%(A$H+xz?|JULD8 zIxy*xv0bh@#Or}`@tk+a1r`t7`4Zy|zL7Nf zsu*cX0a_;*^yfC#oW)Z{AHdYV^5hNgPoY-dtWPsu&oYA*r$=@e_pjP)TdwBeoT`?z zBbTl0e$EB#gydtTvx<{5;aOzDFw+%c`f6Sr38)`5tDJ-IsY8=zL*5GjbtrV-j41Dg z$nI%@By%5?qtScBmdSTLFUj968KDV)6uz2E2aSivPr&T+T z=!={14TE)psyW8oC|f~WJEl}O^35icRmKpR*?3(CpC*gHnau7ZexINTzp%ry&f0fe zzd#X+uCLQM8>BbYsTQcjQj`OUXwchu#Mtvgz~ zt@oWY4IcHyUBtT@!(#FCQ#IohS&GwCS<_^&N*M7L8=S^%FIOnjPz9Ya-4e7hHSmb@ z134g3-24i<^fb;Cr76QvYBEZv|J1n(zGzYVO4;mxp6fb>ABXd@vS}>IP>S18k0jlol7!@(kwjWeP#IIAIw|X%arvc17iBM_J{z>ms9T=iSax} z#ceX<&eY%|@UBJ`WMsLZuVNdC*k7_*v=&8kQZ{x6Hbo6641nIERO|}|k=mIaBNoMY zPXiqbTdo5+_0_tAqzb=Gfryj~w(ur1!l_JhmToK@;u${J+LG!{O>`Q!wX+#aRb8|Z z@b8E!*2TR@kyFb6>xw%0_}cU8k5EbE23RH?j#`t8^XW$u*q3Ol{dWfU)V>#Z1{=*z;%C~ zY<9#r66juTM4TYSFQMLR#5aM>q3@bBbxgacPqr<3iuAWBboGvmm^e`U%NjfZLnzH(#?iD zk9{BHO)TNvC#5A-xkfpx(M8$u)ca+rcoT-9j~XsxI|I9Eaq4O*#pS{JK+I1frJHxG zx9_(@P_C51^XGJ>SK}>$qLHXl5b>qe_dnXr4&E!V@b}arY#6|HA=Ij(9G6xuY_oWz zP%@47PVxzZh1?9~hQ#=Qg3g?YM_aKmhJ+VSg-&lI!oqZO`sc}&bdw))TEf2 zTm(SIkJC>{<~6cbrUTdhX4A?lR&U#j0=7Xv2cC}Oa%XdmrZ;0Mt#>jy{JYo=nA0(E z=dA+Z0z*Qk1VjQv_>>nT$MjvIP&Qu-+$j_AAJnK+_@8r6fp|IMG;h@)ZvG8yGX%|q zh<<$h4f{IjN;!ybjMl!Z+Db1fjxBdT!-V;3{qCa|8!tBCnNh4QHM_B_MyLQ~-IyBC z(NFp9Fsb6gs~4mA-3*ICz(XUDYU&flHzbHmqv|$H+`l+`ApBd@cfx9rOhpSo5Xfk) z0A{3pQ_ZA10}_lK9s0(vLH(Bc*vf3H&td-H#SqLGX~}98Qq^?_@&1k5aq--DWk9*? z3DZGU=VNj6vivf3{~iLkK@Ty@Y{;TcJL4WEofu`{q!yhOGd!=;~sj3QW=NuunAJ zNa%|5#&?~;_Sh7@TQkF$#Yf*OnhKJKzCC$8tc_PXY`9+{}sHX;@M zGh^WUP?{Skt$S+SxrYR*8gmf$t1O?SQXpfW08eV2lpiKbKLO8(En3I}QOIA*ab<1c zoZH*Z5WRHGj60`U|zjOQbz80ZHIBIm(lWyKxE;f^Zz znW9u~lnEJEU@&$db#5S5fQ~qE;rd^8Zf4`!UV0HuEfS~668G6OkdY_ zle`yp#QGCS--IToQvzZPScId6hr)Fz;vHx)l_1Q1Q%g*!cjQP!Tx@ESwTJm8A5_HC z5eN;jb3Uyjwphd>aeV38nJK7fRzGi*Ooy60X$gj8FWuWW>Rrmf`4@A8Fj)~8BzJxk z+<|3D8Bm17Aa-2KJQ&Tj>41*jHw=Q4djEO8)OH)!bf!AV+rExEGPgaOE|L|oU+!n= z)|(R-Nt?S5hvkl*pHQ+|ZVJA;H{-LM0m(Co2}2H@Dw2)kA95*M7+T66z#ay}biCJ@ zj&dBnGcZ1c+@AGUMmlq=sLNbXt9hquMoyOXy%e;OPa;-sDP+483Yi(-<;pD_Z07n@ zIpDrvA4z=1EMP=p>_r$U_xqnLz4*~i zVSS@iJx_Y7;ONh|iHQPkX&8`BdDKeJUr>Q*zC>{1l5U88lyA70v^d(gaaAc!Gz2-^ zEZoP|*$VwCySzj!iR4V^ zmbNdkYP(NGi5{rCYMnytRtZJ5>8%3bHY;y++wNZFC2&4c1BF%8j24M!Go1rNICM7y zU;ncJQkK`HO=f5Z!q&@>8NSFD&9q}-)$1Z+WJn)N3OYV6mYsRduX?`( zJJJ(-XdvC~u2?7x8cpP#K_zlZXWe3v$?~d75A07}xeg2e-TpARjfi=4I#q;^kLPo` zdc1WKd8=PjJPyR2Z~0-NYoXydYZHqBlnheIrXV}XhlNuCGKqCcFE0e4fn|@L8|s_8 zAX}^^DpErVIDz@&x6ThwW+$2*|KJ|Jgi_%^MfMMwy+TCjGef+4uvi*Bm(da}oNnyo zb}&%g$*2Ds#86N-qHnzfzswmfW0ziDU|Y=JbuDqFaWWe_{HV&zKG0Z6GK69C=JVfv zwya#`ooahj9>}DA0rq&6cd8-FlbuOUqsbSJvOGD89-Kq4rnzrwDz~*nUgCnR7nsq< z@Y~QQkD>W^!53zGvx(o1kG(?VB}zj3Z`n83Z7}95KpXhw9u;+s&g0fP1F?@+O{kSu zC(S)Bn&Hk$W||t}pGy}+M}|biu&UR)5DN5UKK{u?|E`~sO3GblS9guG!g!A!J~fG@ z3oc&RHrX5##iM~<9c$0GPk+Gi290pxuJ?Qb*+OHO^C&{+*-Wl%`*fd&qWNR(FC+ZD z4-PzU%hdt&JmN%KvJ>KYHj(f3%t&eKzrM{)6dfG^)^t` z|69}^n6S@dg7+F5k45@=%JN9Jm*TSrJi}E@CDfL@LKWK5d%L9Kmm?64@$9ai8+LBq zsGXIYR%IjXJcQ6B4ciZKCR)&m9LyQod9%r~wU-YM#eMIrp-$JTzGObH$qjj z;M+-d%~WG!)2lEm{ghEV2vUi*UkKp>4S!H(*Q0Lwyv@IR{B|0%OA5CMM7N)d}cp( zn*A}XxAhDXC5b_)?JxmQwAH&7FU^7cxT+yNERzU2)Ww@?R(ytd%(X1fy5M7lbL4ZA z^evdE8{8V>(t7iC2RD3M;e&IZEU2%MlZ@^keh$I;v!(+|->h_e(mHn!7wCwVf7}Dp z#pkSP0Bj!`8op7DUd)N~V>VY$gEHUIG!jS#M=~9=9rmBIPpswY39hts*OKw9u~#+Q znR;n5pKSar01ni6^kK>Xy|eX{_+(;yf_=(cVm&+YGvTZ6%R|0d>V@bFQ>fkj^74l1 zPKu9m&B8=H2mn!BdBDJ{$9y-CsJN&h&w{HPTaaggUfRY%uXQC>dVBZmd+T7jx)~zi0{?`<< z%TuNizPjm2pg{#UtW^I_$k5}(P3%R@b3bl;KlWEW+H8zk2jwX5vBZxVa$;4tkK!;QzKkTL$ z-rJAHEpqO`YxEuu1II)6o)?3{LBR8G-}*<{%F=-Xvt{XnIlK0RZfcd34*p8u|wdTzNA3`50M3Eq; z&8>PB>0xta@^)*CpEo#NH=~sDB7RY&5VdW72tPAHOudeF1rD|4ugfp7{Esw{_wFEN zOvm}#HqC_H2Nw60<4S3Z18{!~?nTVl0y?OBA!W;GJq;`EPA0?T*WG&A>wChJmbubQ zf%q^4l5*$evDMj!G83 zsrRGs;$}Pi(^@e?|+$W|Q7@F5gsPaZFk6$)R7d%YJ4g71d za#zs1F+B}QX=S$#<^YAKLK1qy95Y%nI zi&=GdN5`0pUU?1wk}eTm;-B%M1r<4p>Wzw>;djdLme*<{;YAGxP_7Ki=$10FS$aBFkUA>e;tWfy;pFmT*5ZR(2_J?TIG^Su_OLSFmcd&O*$Se@*b6Xc=s*A_O+ zg&g2Jsu5tEze#&$3?aq%x=#U2F3OQ`9)>(DU&xO@s{a;J6;?ujen(wm0E739RYsc0 z?be}V-SBmu+)&CMG1qAW>$1E5;_zKawpEPqt7m5MY5x5hc%2tzdK|IK_Z~6&&VB1P z=-6S-aE^ht!?giZrl~4=y}R&47p)MEV8_5LDLCB59OgjVM990a*N!Cy)YA_8A~bRm zn<&LOacaK^h*?f1Z!?DmX@rAp>O17=f7x(4->yEywc~=l^FGxzWsWt1k z4X?4Bok5cm3O>H1O4mitL+6M}2V9qjH@v-f)dUB7Dsux-yH8c9IM@`IasMe7*Q+1mhdj zqzYC|Zoidy^eXiB;=zzLRS*U#%fvFM!H z@I2V4Dc}Wca8{TZTzLG313D^5NUG4)U0*OOKe_3C9W__8N9ggz& z75g0QVW(?cxlk-Rm8O`NlB{8D=x0hbNBE|-`uaA%)GAch0z6yGT4&p-s$yOlS< z3MdF>a2}UMp=pTiB;Puc*IO;=nzC%5m>3ZanqNZy*KGq0=qQoD?kY2Xv?g~?TdO}qTvlY%X;|7dx14z4D+phkj4-A zD4oB0Y33(mfk`j&Ynai(6ebp22AK@ZebelR1mhA@$%0{Q*`ZCk)bhHreML&cQ^i78 z=2|O~zKVO^;NnWOnnq9PkLZpi_nr{<;SRrK$f^9@W9Rk5I%ne74!y0aeCoF4|Us zLXjnb4VNgrc!BdBE5I9Ra35jbjkv1%MKfp8+ln1?5_d4_b(08$v;azg4R-y(u&o)0 z0W6Ox4aCH0vIoEYNwPG3*~>cuf`w7GJX4!AhH_%SAL+6n?i_T!ltUUFK$Hzd?QT_Y!w;+7}N~c-!5hh9HYylX(Yb zeOJD|@FYW5j{Aiq%y}H0r|j7&C342o@DNf}fJm^i{$**>QX#(zQ$3q=)mcJZ**Wp0 zut^e3@=IADiq(+`2gOcf>rG9d$b?k-1Z|E+$H6z^z%8YRhhY)yoFoAv$l`I6^K=sD ztMsSUw|(FPj13sj8654KuhJGRF@W}yNpH+J_V+-e&YNeAzAiXht|kXQ)*E_Au}mEj zN!2~$q-{A??e{~GciZ>0bd_44F^IXsUl?*K1nEd94W#V^XMac+>V`i7wES+WfC6^H zNEl9KLGi&#LE`E9w1<45?u^Pno%c03c5=Py6^kgEi-B2=jJ~Lndn%_0p0#TjT!CT$ zqFGoWa(q}dbHI8&Nq6LCCZcsISLtSwLq})Z8!UQd=Zsx{lt*;2>0zYZ5XhXlqqUzu zvifw1V_5-B&Gs3qRm)=XUAbs(mFz3hJjJIHq~5-qChp3##qzLc+q&YiThygre62>D z#g}r@+-7>~Tk1}Nw3zAD`u>TtH);cEXqPV$!SA_*h$Ft`m0F8~oS@|K_CP03>jR1W zl!cJ1z)>E?#6TT?r{3R>DCn=f7#?V>F-j&R!)7v=0S=Q|6g;^T;S!#Z2sL=-RF}G* zcrE7(VdlxsXZnL(!mCU&2Is266gS{m5`s&+gq*yQa1Y@M#!Dws?F}=9%}?K%X0H8h zNY->^Fe>Q7Xu`vYJEZ9VxaQC@<9+3bqv5k=DhZ?-JgL`LQ^Zgudxys8D_RSSPZejh z5pCPrT8!|7q7&mtUQXvoKrr5dgE8(( zzwZ!FOo886InkrE*&;BWzXkOpIGz(Di!XS5Y;b`USsJMRxa5>XeL^^puvC{q8FTmE zZ6iCh5oDsIy&C$Iz%I5Uhiz0G?1W!f`(Ft;uu8p;}7x}?@S8u>gR zM@9h`E977nZID2TBa~wh;+@2q!i*0-n6R2H3||yuXNnxQ(Jwt3dW8RXr@~DcPB6|N z@LboW1tvxV)A1ct`ev3(z70DHM8<||z(s~F8*@wC8tSLz?1q8WaNf@Cth|!WW)7Fa z`NU;h*q@VwSU&D;7s$Br2L$ifzrJV5=0|t+dgXpL#LaM`rV`YsfAYf_mAG0;=0MBD z*C94>TEvUM!gJdAXH^I`wgRgXO&1wwVGG{kY&$(QFw+4ktQ~aGlF@ol>Lt<#Q>Pm_Yg&|GQBrHJZQ@8{%)D)# zi^al2d;iQs3xOz54)~Vz8ZCul1ci)Jl{ib#!Z7D|NGj0Bs|&;RQi}N|7H%)s2)XtF ztsAFztooaaDoRsyH%gS+PjmPqx<|{ykjfT>=G~T}a}U&oo}`xBib?H+c7zcXC!Yv7 zv(E50#8dyVMA{X-%-!(a?|G-@B=%i4)|V2Rvkk*c!ETtS%r*nhQ)*GWI;B_)|U@(rvI`0^t`_;Xwwe=Ns%0dM7Z z2Ag}7>-Teb_N&RtrS((q-7%VMU%MYH2&Ej{9_R_GOaUmeQK|_xKrZ~2ZHSD9Uk$sT zIuv=1LE>4ihjZ)0Zh$_~ZOG@>K?AbaKA2G9JYMqdD4Ah_O?GE{A5VM~5D9%*Za7w3 za$oLLE%xQ}U{de-G^&cK$ibHGi8iqoHu=wddDXuLw*Mv}H`IO8brAX%!5$sNP2Upa zA0T1@ZL*gyPy_akOjcH3W1}u3er`gdMU^_@i22fF1kcnVK|Bh(>`(;Qe&Vn^nkZ_~ z3tIOV`fhn@cK)zuJ*6{4EFINW(6J$fUU&VL72(Btwkl4HO51BML$s-3*DsGrF?e%d zqh$%f8yF23xQs_1PhGoya;pn>4!&WQ!#-0Av>xeJvmmO>I(=_fipIuaUd3-+z|?~` z$HRYr6O=F|w<8yd&2eH`C&OPkG_?T#=xv3v)3j20hoUn>?SvQy*)_y$eN6WW%zY0M z^t{jx9p0%ikJq{W3rnIWkHlYgv=(^@7mPQvQ_>cv#^!2YKF>L|ka(8CNzq*FL+#Y! zJu`@CM?LrhB&a#YizNp_vG4G`Aq1TB`vO}%52X!dL9&$qGFCpsVdA$QwRN7iCPj@Pr*1e0 z(fZtgo2i?(?W;bJ&;ORU2AoH9XCpt;Mo?Nmj6PeT;q>waB@#R_1?>VaaNcIyFIhfO zs>skV>+Lc`x?FOsL2qSkks3%Se@1Py(Mi#}s>ZF%Gb~R+>OH{#F59n=OS-46b*10Xl&=%Ayi0yOacwgKR<(o-DbbNLHL(1) zornm`^w-b#@e|de|J+0Ww;~jTi-pi9vxVH=IfZyY%TWC?w95)KHU?LmV4J6P81B8~ z;B%mX#8}Tn6@Of(6r+)(O`J=Cj8Kw#xT;y;n`iCnW|_pIIE`da9pR^sd2K$Qu$S;( zNkQY@XTYIyX}?2DttkVyD;H}=>Mw<~L%F;X;KU}a?Rsak(Qz9AeM)(DL;bM62U0Yu z0z|lQUemeHP7ls)x%35*jV2{XpFU556#1LI8;w>En&rW}CTzw2Q`)RG9g_*vFaE3r z_EXgMV@*`Jls%da&8&}>gC`%~&~ni)5+Z1|$BZzvF+5}-_K%%UmojoGtTMq2GwPy# z=7KC68~(IX#Jd2D8H82-9vY?J6jTgtkOlO36Qwq_`=>AzDrUfOtI1IJt}}ihy09(S zZ2#k|O?PN9>eG0g-DNshC_=gtehC<01h%eW_WpqNY(U=km&m$5?$J~!VOXl-KfZI^ zgVvy5(ZV~f=mR@k-9lDY%wbwK z`6V<*);d~7V3ovRk#;*O!(_I}+xfNlGy(;DcYUbdV#tlU;PcW6H}4#O)%83hZTrd! z0LGTi%rd=NO}xpR{dmq3eKlDv$VDWvl*?Uu+XrX5;>}LfFq`gxwE5EyaMQz29@a@f z29?OGIt>4BZ^S(jH>|BFE2$MsBtfDe)nL4I9s^XC$lPHR-cJ+q?x%MFQ+47%Ko-L& zVyjzhB7@W55cPk>+Z#rKklTmIDlTI~MLKhHcqWgwYXkps*s+w#nk`y3#tv9q51sN1 zUyNj`l`hKxJ&IIxr5w6R?E|kU%h8L;>n-!(+Ehz7b|0CNLNHmY!t3(z^dsP`ka?cj z6^p)gExBP*9tPKiN<~AVX$yTL@tzX+InE@3@-YP{=!}|wu>qBz>~4CcI2vtTLjprx z_U`2CpLQhFU_)D>0N?mhlX7QF{C`}HyX&3UE7`fHLmR{tbA~yMEi5rhn_*{?DMijM z#(yzmVdoB6gTtIAENjrCBmI|ygC}(?Imf4hbkQrt%mur!yjF9jm>T%JSun8IIq^`q z&SSTxJ5V=54(W}{pL67N}s(+dWA^!!0 zPH0;Y`XBmy9L>}FpiY5qG_-nEQI?KshJEXBgV|Ek_?5w5jVH~YjP(RHMnF=*BuA{I zmLu>#D;Ik_dm`KSz%#!{E?qLd%6dKVImhC!DzoD4g_bQ$g=v*)WU^I#T=8`{UgR~t zcu1LVx&J=G|Bzi=oil@aK=sjZWUk~B2#FjSg0?ntjl5r#*hv)U>oVe-UJJv`vCimI zOvnd2$2iSIf5b`dd6mV$?SJ9+Sh**W4n?okHAT)#%mmpHUBwx|1N%Et9l2Y6r(2+; z#U+)4rUMvILb3oC(E`;s@L9AM1H6f)7f3xHZ=OvCB@C1FTVXsa&L5mqFYt=#9s4bg z*V&Wc0qyn}w7|kj9|g6faBNFe(7|G;8Zp4RUW|xc5t1fV*_?bq#{5nKA{yvsZ9L4$ z3@rEie(%$7;(VDrMHSfcV z7o$gkANR6;JgH14@|SoIyN?L-a_W&Q!Fy#yo8F??s^?de^$i9grlT<+kR+v&JR+ijVi*|2i7!>`NM&vgdN`kO8zf$!ctOVIgWr9O!%6cW>S*-UJ~c(zVaT z+A7>q618P_Ud{$Ar-E(S+SrHJz?=5YATRZdUu(4ZmXVh|A4hh8Q1w4ZKI94g4sFjL zEV`|i5N0qrprBoLL|`W7vSS(RnduV4j=zl{RZyv63;q3l+<9++FXR-kv|ek$_1vAV zKo&|jKgX=9L;tshR{%O1xONLf?R`Q@}l7S)S|Jfls~vTHnfY{lV#3G~BrE-f}YqH9$`js z`n&nw63ctq?p*%0ZBFU}Cwdl%RlVD7RNW^-5XnJ@CZUXyDv-hlQ2FK`8nQGZONO56Rn9XiAiUesZCKEY6ncmCh z0Oei-6X3Qqmwfd=PL^=&swAFl5c_6$ZJ=q-vO9~Gv6N#7+OyDY3KUg_V83J6uhgUo z$cKgIZ>df1obQ-_FHf=4k)`mTOt0AnaJmc(!56NKn9RU4gZ2rdw7+fh2U!K=)L!?W zo&Wi5|9FAMKUPaT2!UZd{5!^p%92LIoh^HeJ8S~#etdKYKL2f`aBG-Ed7WwI8~Pk^;X3JMZXaUyPLi~-v^ z0c1AcPT*q85(i3cftOpoGc<_H->>flhx?l^ilng&zT4M&HOOq4%pia-^JhI>GPn!p z_32gaw2OqImd;szrL{n{>$NoisRhHx`IZCCn-!waXFrm9y6^|f-SO@O0|>g0sD`Qg z2*=ONsOxyE4X_=xWoXj3m=-Zr`0l-j-Q>~E8DT;3UmUms+EST35od5eu^JQO?zFXn zppgnBQ%9=nCn0h?*u7|S>*$|)O}rWT*UgARxlZHb*&qNC3JUJv%jHDfZq_Rl#(l@y zKDeHBK-VSl&)}}Vkhrq9(@xH5UaCQfP#vSW0(eHT{ho!oC*$FYkmLv13N?EW|Cedxvscccd~_}V>6B9!E!Ahd4> zfkG%oT&V7Twjm|4O;w*IN!=0B#FYCiQ zRD#$9saAmI-`KiJ@t;lf?Zp<6YJ}NeoUldrovJ?lnFFtTo)nZC86m38`2E!YQqWe| zQ?XpW%9;n3-e&!OcMj3^&(N0)^$D8#ic2Iy#LknvSDVI2KVDZCCXvf+PCqrVeh?Kn zWEURhX7mc89eo4G|K-LztDtV%_;Dbr!77s_&@+B9uoM&#X=gy*zN79>tl>a-N;IDS zLF;`-;6bJx7k$2%a#eX?MIsU}*^n_W%HKLBGVHVQpo|(L)+ZO%mvt)~R2f@&NH5zK zW$(MRn$mM}vZ?i`{>JInGU*1km6nEp>O8sGFf7z(5&Vo`lbT*Lg!PYOu|1B>ueO$_ zqOVHdyhF#FymGZiW$E6Rk20ZE?iP)UCKC9@=no zL)_=odx3ei1Tsp+mPFN>DYFRfbFVJ^WYtLvwv%tU1*EJH<1XE!`PfVoFedRqdjo^! z!W2dgK z0djIF6-sTyR@-Ax40cV?2%6=;_tZWSx;W#9_Y70KfNzaWBo4;5?CM zDq)Vv(0VLnT4ut?*>4a}^;o!f>X<;GLA zWzja6-@O=)c#;T^3u_CA(D8%XvteywHuSYqY}bTI8b1tC8$NTA!RA%8O{jG~V={w& z@`{cOGxoQt$$%P_!EKWCO7c9-0{4x~JE{aMwYeIqZSo=Yd*t8o==G;%91!t@$?p+g zjO}gXP2)|C_?0fn+-{vv5@P#52CJbNS)!P49@MlV-|(t+356tyLhj$tXilLC8T|uKfUv`n?VFB!L)(y%%rsSaZg+UsT z7!%HKvm7BSA>Z>^>a>|ctS!%k#MFl|#gmdI5a$R6lWv-_*}fro$=YJ73Oqqkh+ zD?E#OYssPkP647Ooc}dsDL*BFTp$xMt7L+u(_)Os?mJ6q7O4xReP5E>dS!gvMKe~V zrCw@Li}1|zH8@0K6Uka#q0SMfP+k#%rf#GRhi>0r}587Ll#zJ@b)18atOzRlPqU7>7S=8gub*IZ6 z#TYa_1<{4!U2tq%^Kjjj?L!k2x6;{MuonqH<3%df(C(ub+(1 zJidu7I2+)jOPaSAc5V912_fR?dF{2>U%7E@jh zn`kOfZc`;?RI&h9@R8gU?sUppCpN!s|2KCn!0X8@BtLSKhK}pC?>@w*K5;6Da+gE) zeHoUQmo3o#JZD7EoYLvhHe>c5a1Yzvn^+5;th%xJ;#z~1EhKEFg3}+lNYp1Qz9dsU zzJXY72<}j*?y@5TYYJG&tA3swq1hEcR$Ta7Aa0DHa(lYAr@5J)E4CB;5L2n#Yg|fz zY!|pKnHG5fOmsi8N+Sx}jb!p#LKR9cgm-30$G=Rjv*9U<=n;;!@S^>G_;WEbxao$&YBE7dl;sbhsj||UmSt;bGD%^lyr84MIz?b+>XLyCq7$Gd82@(n%eH5L{rFzq_Bn~gBw`bhRNOy zNjZCFItn4@UQiJu{ZT)H`pS*AzDMh93%g;KVdFm_h{z-}EJQZ%XsgkxS#2LEb>GiJ zn~FW-1LYj%nuw{g9)GNfBFGs3;PotxFx_TXU9~AcSm}K@tUScf@3oig&Ca@pdCU~= zvWqoP+~41O9yFHeuDjbWVc9JM&hRLy%zU1jd1tAo&}~DGW1lh=DI;wj3H!%GTb3bb zw&`KEEDr%E8A8k*^#71{4nd*-OBQY0wr$&bZQHi}+O}=mwqM(}ZJX0SVm5!av#Y3G zMnz<0WZpcNRU~I$m;8jL;Avd1jZ^5mPL_Wd*lKWcR3s`xGs6&Ls&;Ion4OfXQF8!3 z;sa3|f(&TsX8`h8-ZHWBnm(6JwOoJRYV6;W?y44{y zs*1noNsKAq^|UPy_cO^y(jEfb+&=^SS(fsT2I3Sw4dgR9;UYC4ion|Hq(F&+>ZQgr zynz(Mbm_kA=WJmW|K>)UdB2=bw>5JAZxlSoF>aOM+~#umy;)f)VBWv6;<>&KpL8-K6+$r7N-$ky z8eb~IvyW36A8^_%Kd<^7G`Upl(5wu_X`5Kb^Gk{`E8<*B$m`yA2gei+Y0v1rb{q7{ zMQyqtg@cr)DTs4_f{?OSm#a{nZ2{0@K`YG;fC4Wg2=$lmj|iw`#0fRWZ3|!nZ>l>y zVkN^y4B5VsDwt<%bcnkPunoA2ZJqj0YyBYx2xk*+QXCmOmHH9kY2|~XTQBxujiS}o zDkdNwT}=tGbe{=;YnF8nkK*#uge7NO)5G|hKHBNQ-fZ)Z8@DMl0ba%vSBga!e~E^1 zCk(gjJ!?o&Z_}OXaTT*YY!i2^a3k+${qU6wjWiZpca;Z-?IyPHy{;5^wFAfVZ6=83 zc3y7GAQPAS1DTLi9cTiIp{$JBU6yNV#)G_>jTHr^R)a`wLskGfrXzjuM|bfN??ePH z6&p69ECm^H0+!5yWDpSTy35!>IGriN0*dhP0WVXgISqp6D_Gbo-mQ=D53ehp-eyhw z>0^$=`~svb@44|H~h1tvAvBR)La-Qwp(V57(!b%vkx7Zh<}!0=ep;2(==EF`tisFY?TM|}iW9&! z{`)HUk}_&VX2G%Ss?XhNxp@c)RP)5bGB5K;nIN#Ni{=dnO?nzo(UAxmL(BfoC8$B1 zX?5)p6O}eYlF9Z zisY*x(76XJ`Jkn9lw| zb3$UL3iwXy7d6_&QpoIE&!DD*aYj#9vt8)B!&f{$W>HaTiAi#~b4p3>q@b6auIwpi zrCdd=S>(=1b+_lpzkfIOm7ZvopGBeNLf-5LA*mE~Z>tLx90Y(9I-!N5#O4#YIJXEAx!r5-pqrBWYB0@crd`{fGMXA;noa zJnQ#NMi_B4Pyc;Q4WFEy!Ym^C^K3Gkxe>!KQkAGZJFA-Eb9m ztA*P`NqjZ#RrwCpsBl=fBTT>8AfaXBZwtJ2`e#;+DUcjX)Ps6n zd5U%I)5=B;EQhNnQaq^PMxH>I59HWi&Xb-(q_Y}R)L`k>_Z?P|WpiF2TnWtM{hq(O zib`3L+-K?(QA4G^r0A^s5YfK4qO+~{+#qI+3rBHP3>5B3n5CxPgVm!(x@ypn51L&* zIe|zB7M`ic6VpNRKlOLLlPH3}sAj=xoZru#ae z_HgwU)N#x5o;TYcFX^e?P50*fH~zJexoFxLXO=t zZ`(vW^t}=JE5vT08I*bYR)tn zA^%N!`^f15w3y%aeecvSKvkeeFv>uz!P5wgh;qD03jgT4%lvsLP?5>wKrwz_Nc*AJ z#t;g5OcpO-6xz!A zMqdVd0E%|yBLzbHrFyczIi~j9&V6KE>gbXo*`|8-kK&Mh1R}%m%aJt(D=$mEok!wS zqQJFkYriKRx2#00CKAXZ2g75HqT~+p7pT<#tv0&6OB+C`-0{7sbC|sgd+)Y+*Mu*| zZzaUnjuR{qH=QDgc_7E^pfHEf#-p5w~6o-D~ zBGUE-@b{;X*ocL^wGA|0q-^?ux@^hp-`KI*IX{0Ij#; zZT53QBg+dIDKJwsx$^i2(3yrux9Wr;@=$yv^`m<9m;G9Zz`%gvOlB$FnYin2x=ZnT zyVg7;#1l=ZAC21?*EcQeL{||L8qKBz^@Y&f*)-X^0@{;&89(;cwA4QlU$|?NG?_vq zG+OC)^}yqF^@BbAUcVF$L`qP=7?$zV3_v{{*@6ju#>a-Yk^x?=xemy#f4jb}sf^<8 zq#kvg%&W#xJPd7dp0_rex1;@b=rVhKY8w7FZ~qK?8FA_{?JyK`odwU6(5u}2J%Hf8hJjB8<&-Z zciDqvY(8Mc+%&EB#pp|w^elGsfVXL%P<6h7@he^1sf!O~-oDzZk;qM6?{KQw%nwt} zM)FG>vu5VeK9sM!CQ|%zTq9lrfwP^qLP3FW(nmU(JMP@Zq>HZ9xP=^&iRY0M`Z3KD zwSs_(o;7hb+XWFHJEz~vqFym^;zwOk7P2ag${Md)kk<;0a6WR9P(Pqg1GMwB#`Tk` z?c2DVB3;Ulf-`ET0Nd2@Vy$wimL>NBV30V2szExqO{^$F%4(_4W|@oDO&gpRnifwf zDozpaNrD%*_n@Yh0P2P}5(^aM`TcuqxW;YA;$XOmUha=Poc?UL<01si(_rwK8ecF` zi}qEx9{>P;9pQuY|5Fj6HwnPHrQh{w>j$vN`h_fskLw|&;y}^zu9l7-Yh;3|Y(z3Z z$IaCtmjMR87@|kI@kKX#bQLi?$j}#abBZ{Ei3{)1S4}iXw9e0*E+1N}P)weq2YkiP zm*&oN<9lC3HwY&H#0I-NK*Es3Yb(B(9^?pYc5q4_lQ~fv{_Q7+leeZi76m{9;yw4X z<3%Ya|2&x&<&|h)aEs{^>hZN9AsMH8+&3mY*F6}ahj5C~#vwb@4%PChyUeP(00NF% z6L)4FQ=9j=5!udpaxBaw4(vbnaxBSXEasVJU+~Q5Rj{8x0%^_l<^E^Xb}B;9DtJkH z>-e|dE=V<7EjzQKx8T@PKmecqm(^)WxGKC5Dw5H*K)IC1FfEw{4ezj!SEBo^SCCIP zBSJS2iAxi%zxpei8n`NsYP{lhyhZ27SPZPq**R5)><-Bg3~kUTy<=0#3Lz=)v%Vuh z9)?rUuZAj*@znELzLPG~8KHz;GGS0Az=fngnsd;9g3@LX^e00dD{@O=_P8x(82jvh z6%lHr#v{RZ9ByZQNSZn_9FiOw;5ET^EcDiXK7o#^v~V(jDNeEztWXZCz14S5c0mZj z1dBM&hg+QMAxRv@&mfRn(}XJ~NqG2Rc|y|i!rh9d-4Uy*0nxhv=rot^+P@GlK=GxM z4Pdhn>L*0_Vwp3QWfT6!u4m1BEqt|X^9nGf>1-^`E(dH+6LTU|oL!js!qGkQ9V18k zD?+=OH<1Gsg@co5rl!keYENK12}AXR*7(5XACT51j*KiIUJ72ZrG6Nix@)L@f+;D4 zKC}g2K`7}TtyF)C!18T$lJmuL9{wszbVe}kWm9t=B_VEJ1JW7;+0E7n9oGS(zw80W zv|lbiJPq=543rWD1z(P7i7E9OorCGg;#B{a;9#dL0~>RAc4=hG*_ri^7n<2DUL8F zu4Z$~e#vz&WA-c6Pn&Sffo*)sNI&1M>E2nXWP0l>yEHR&i>#RRcPtnQgtTz$1|L~r zID6i&PAle%N#zb9C(-5HV?HAl$_}R-*8s2-In=KRgKiJF4onm)`a3>JLVj ziD-TA6?J^+r@FGz2VS(x80!K&gPSKN*grw@mI_1EiCr3j)dPeKmgtKXkz!pUCF^e? z%sNMyYuyYjywgCde?wp&o>3Brr`x+=%eW$mE~_nNHRu}0z6gybQ*5hEKBnYn@J9{s zvo9dLqRd+LKy71qzRXM|X{9`Pd5hjw@#4IO;|^TNXgcLQduc%uAAsSb>*`-In|+vUw}}PlhoRwJYW&%{&&w&L@3Wwj z27bm918N#2tt!q}7kw9gwy7Nobw?6wXugUs;af$>QQVZjEu_+ zatqN7bVb<}J` zu0ct@*|dK;Vh@A^c2O?V{1m80r}XeL22O&1XPAv518OfxG=q3f$;DbvuacpH>x+c5DcH{&_UCwbhT(C7J7|HkZkr8(RV+hTR`4KYBF!YYo7l6EGs9Jd*w2Nn zk|rEPtn(;#A4=i+a6b_z)M*fEPV4enDSUeX*O}U4A4q6MaAmTKc7^|(I4Ri7nUaUh zU*{^!2c)|5Fwb#xR~z(ip9#=PZ&!u7)qMBRzCX^fV@rUG%qB96w8V{gYm3cX$Ie7}5Z6VNDbAGh1}6ANOdn07iZQQJE<6gL4q z+V2wAW|*X-_tAt4!64q4ZZg9Z|9mH~()c;L^CJsV z+m&t{sKdkLYDkmN3@4tI!kULVFmUwkqYScA{pgB_2N8QCJ*I(Tzl69lsg&xqL@yrB zd_!z$Pu14HogVm&ocVsIeAHB9fSob`(+2{-XSu*=k)_4z4lhi20MzWULA#_jV*-WP z@#a*?Top=L!u5hVrK`QDjUn2UxmN22h&|1@Jf{N*(+D|wwqXE$Y_19Qjpl6v+ zs{DMYg0%~Kc2_d0NCrEbM<3FyUUeNv8os0rj-+J~&|XkSlpx09S<6+TGh|Rdp`V*q*C+ zRm1BmN?K6ZDYFkBzSazQ8D-LKTVdRbQk~^MhWsEgNFVjydv+c9nPE@GDDimE(=(JF*r@Vq zr%If(uQ^(t4ydG#2;zZnOnSlz2g?i=+UdqJCFw0#kRFq9#|HYN8}X& z8gTyk8JhO=Og+@V$v$|m+(>q~8_b~aA1byx+7Ki55+X#zdM120Nku}b-T~zxmPlJ~ z?9^nD#`$|7v(nnH{8$=1dBS6-XO45lm&UKq-+ zM?gF~-PA}&;g3wmaHZoV#Pl^@z63+7T%v|y8H}yYz~B;+*MYWP+cA6eYkUI`#{pE= z1-(jEQX{9^neC`{`MApUvX=n&R#~vG^3x&M81a$6ftUBWXd;!6Y%UQKEc&e<7%aV3 z+j}5kVUKRH&eVILljhk$nJ?0cHc1?+Zu$MvIzARqDVKo~h7!XO7O#@L--rJ?w1ZzB%4FOQCR$T$FC)cSAkk;ILsaSJy{pea3fk#V= z!6tzG=jhCKzt<+3jvT6gRoTQy4_4rcMV+uUH|e@XG#Nd2aA}-R&WID zzaszVuR&ORNN#hSjGu4u%>t4Lmax!H5*R9C=gON%|I9=jnKLsm{Z#4Q5P1C$o{R}~ zuRb1*fdCN1qTNjOfOoyu3&a8S**^W;n^F{W5L%kp#j_fa@bH;aE&6AXKWny8dNR;n zxJ!kaATr1!Y1wVY%3vi}IP>C8MJv4q(dxtBT0IXT@I7W>uUZuGOTg`%87x6q!e)Zv zke|#=vr9NO%9?AhE#WQWIuK$TYv-2t#94IWQUU3d#d0bIDXOA46_=F2198DUJQlVd zhWrqqTpPQ-^p|=wIpmVpf7$Q6Ts73qE~6TVVf2@sc@!O-Wvf|gwzwMfVFj2%bc&Ak<0y2RgPV0mr0(7PDZVFd;TF$Cwfhl{9pO5 zTJ6t7B30}S!}f5~D&ZB%a>i0O0Yu$kE5C#nr~>@uMl`e$8lsb;iu(pgSxDvgA0XV} z@T+TW)KIel2!-3@mQ#qF{tTL3_F>9 zVHRHq*>Y77>Q)_7(H?)WtSGN+o6_?K-S{Ze(uT9~&!^Us{i=dA;SDi=atPWJ#PQ{Z zxp*$CF=7e;uDew!QI={{IYYqIZ_Q!55=ax1%tkczm{&8_->vKRx2yJo?|CZF8|1Nn zi*@RIxXfEF7ON`MpQ(?;=evjQs8@3MQJ#3W8_3L*gnYOy*%Tysdl^TQULgJUbGx{d zzaeoS-R2TD?K9&Gb9hQ&kWF#haG?uo=jY)o^6tF;IlRVe?}P>T2iV)|g{#%ha!aTq zemDLHr@KE6VhU;!Hg_-y*=D{ELIUC^fMvc98hQARQIf?^a1lR}8ZQw40+$^j zX&#@?>&Tm_F<3w9c!W9_a~9gb`Gt9^e}9%~&46RWVp&mwuDV|05FlEW#54C=;XJ8| z5UA#K{1lr3U%>$w_h0K=cI@n_#Ncg}3ngt~IHPUC4s+utqpC^~7n`)$43J8(FEeBw zJCE<_)geCt@4D-lh(9<(`5qqdOiJ7|JJyvN!ee-&2c=-ZipFLbGP^60zi|jxb*P$b z?t^Ztx{^zPIDuz*Gp=O@4iD~%O1t8Vlh#JX7{K07;}#*zSLolqD9(fK^UYr?L}di4 zQ+Sm`>f?deoPS8Y9*#&y`Mtx_O4;D^tHE`=prlpQbiFwV0IPffSmER6eAcC`ta1so z#H4M|XTT2Y&7MfuyT#0GXabjcs_w9*L7SN!4X_dl-TO_k81I%{D4w)@M_mf;nUgco zT&A$viN*_IZ%k$f7_t3W6u=8~-r?*IzGZD$vUP>754|Z`70`%BGDA4CI4QFfPgs5o zWKA!fGE75P!3zs5F`_(uQehXw)5|fHQnq7}yJ4%K>?8sXn!X#-EXXagea@)oMJPNP zEzZ8gVnm0j;JW6$LY{~+MZP#lr82RM%z4V4`2ONl*K`AaCBP(Qojt*caQ18^dLd_j zw8TviaXS+QfWBW|LjJ-dkj$NQ!WatDPpFKrWTN`LKtEKgXHT#h$?&T#gi>I`m1udu z)NHk8>`8|Dy4_@4n@O&(s}m2`Q@Ar)hPD4Sl5oEipEt^PVmLwq(8#?|zS4oky95`8 zJcp108Q`npFK7UMW)QanPG!vZ#Fqptx{&zl_`{SB>2~`YUmtYPDNMyP8Np_b_h$WHdav?dl)!*AKa(U<%QX6K@V~FQkX1vu?be!J7)c zrq6?mez~*42D( z{V1#=DY(&QFRbBM(62yVFZ2psnXlS2y~AJr?e@Q6@gf)N^Ap@P80c3EhP421f@V>8 z);%B2u}%M&>sp{;JJx0Lu{na@C*@j+)_%s}!w;X8t<*l9Thi0hpxas&FULg{(`OrE zdGmm(sS}|(U_A0M0}szzef^Gmz6BI)Z1&3~r$>5uZFudrq*O8SaJQGDt53aq z$>zCYT~<=|59+QO>%-Q{Auu)}WgUI){P4`iWTQ<*MZ^!TK@I`io}#YHXK~v2E(56b ztGZb^^-}m5#U*MA{wHOMcU0Xhzo@~KFm7i zA+M3i3&*XJ!*npIodB$kRYiuwa4>K0DQ5VGIsiAzY*#59L0P&9s;r)FV60F%Ycj)x>wS;s z{`6Wh3el6KM8kER?ayQ6_DC)=WN=k14;{_x6VcW9egOlQ6zN9Ls+eyFV>16+YzqBL zh};Ljm8f-uchXSI?ZT4m>`i(r^~R1tPdjmRW5!UrLAa0Whms*Dq}1GYq&D0|&q3E< z99liTAPSJ6?0N#9c<;I%>xb`dFPCt`AeOB+j$bU6x@WFpIfa-ibo#y@@~nf(BOGW? z;bZfe53B+t&hLMI#YcW>{w={|=Of3MZxwW|WTfXLs6@Xt_zmJYi2K*nW4ekctefF@ zD2K`6_JB@LM#gzbpt$^0P}faoof>2Gp|r7XzR6alVMMlB5Um~Jl;5X9U@vE)Xv$#>2KtfXT#Bmx zsURz*$MJ6*B88!%`U(LXYR&d+#)0sTDLiV$!?XuX1XJm!STBQ3=UW&Gg|Rh?!VEM% zlxdR>cv|LrC+_#7|5&n@pLhP!w9BCW>`SGcngT+N$f;Nqo8OjG|EL6EaFTJU&4*pU zaiHTPV@)y)fkPM(z883^35-}yfCJRZlGEzO(WcV!+Pkegy4xm;?B%c)<3722V|2rs z?a2}V4>iH)_V-1e$(mccM@1&H`OIXs}!5`cYTiI?IcTr2p2;WjmYgo07O|8q(34GKPKbilk&sH`2{+g!L+&_x|K3pdu8ZdAW7d6E7 ziw9Ciy%<#-%dOke{o&T&sG{&PD>KX28GU!_i>OG94EZw7df%$(K2S6IsAa8tj{{7w zq|ujQ{b6cfyVTb+{DR=aKr#}7?|4SwK)hzPf^iFt=Rka6?BrlNx96>X^kz1}Wq-i75~cSeNE_DT&&$MdK{ zKNSr2K411XQz>5G$7@H5i`89F*DvOt!SZcP^A~66n8uTU7i+XQ1JM@y{kd9>c$~8) z!)4Tg5X3{ME26R?Fe?>#f-lJDCiU*}Qj`((@(G46ylO3Pk!86b5XZFI-Jin5 zj$IFObwhvJYu3wBv%QuhYZ{xMNu%2uN(HiFR!)~7x?m$$j#h|F5pBoBN|2=ABF$*B z80!(veG+cl7I$&m?+xtNDV&30@Cu=o;{$7RAed8tiCRaoC8Zx8drYIleU0n!g1mKSHv957@J2yWL!e$lpyP_-SvwP|1aJ08;}3{S&vPtHIu{Wu0=rSH0?>11RrIABj>e4F>&qxj#j=@ZD1d8Q{QAw&yQ6I+>-$r$d+9 zeHVVq2_l*?RisSHtih&YUVW_T$2wx!MSNgA!hRQn1i9 z!Z27^#yzTuL4?20RPr4*DZ3^QPG5A1eubE=TAI+1Ew-P(Mu|MOy$cTKII8?x09s%Y z=))-2?oC{lKM*j4(OtB&M3pIMk4iLS?4&yW8$0C`0&^9euQ%^<(0HI=?{#(HbEF6T zvEGu>kT-}IWL9UO41BGrrDCAP0~ldSTXqeoq>(iW_F}h^_C-rI8&aFcoqYpy^7wLI z+f`mQm0G4bQG-&N*u89sk}1wBv(a3EAu+*^ljyC$`2Pmp7^z~e9TY2%caEbG9k@>l zDWi_??IZKQmcaIacr*b2M3fH}pA{G;>)D34iQq8stj3}(tpJ5P2nQwO59)7(tulK!h;3JN1Q)+YwEy3NKjdS8qF3|2_^QdKrwrq-&RO6F2>A0 z{HzoUOkzgvhba*Q;DET`bA-hncE8p;?@B^})sGq=aqUA{-y5mdy% z#jU#a=NgukKzT@VXB5i=w$v=SuVwB)lf3z*wjlE2Q|F+_({BEuBu&@@Ae&=tu@Zlo zz&BhAIZg}^GZI$NuczZtS)OC?B#A>xCA9{1W1{QId0oBiC<#)`Z&;)v*iEn($X!`Y zK9j$3wh+v0BY|r}qHi#>4bCl9*7bE{uwrTX-VQr794dWK(w%jJ)+jOzv_EcJglqDt zU!-)4Ck6^A!9mLgFPb*D5x%e#JfVWVHc*Hv+cd=$%PiCa>yZp=cWwwC_%$WAIf$k8xv(?j|-eh#mw>DgMzfBn1N_zKaxU+J4 zJ+GQ0ZF{B%R<9}T>83I1RLv_vs}iY}1(zPsKkZN<`3A^$fXYt+TzSlTc_qGmxOit` zo`*!f>!#J7UCTgaCI+#5r?XodCbVK+L}t3}lXCe^!3$6oz>DS8W`wZchE7J1)<|R5 zlmQ8d2S#-mZhRQPeaONG7OG{a4-YiHAt@9~IM+4Dr$~XKZ*t!UFq{0F`7~RAy&3Nt z+j2R`)jG=Uj6B^U%X`y`sYkPZq(}%EV>FT+PG7dD&k2_|7kZ8S7%bz0-oJ`sF#~B~ zLNQQ#^5yV^HmeACaU+(0VUglxnz(v^&0PJv@coV~=3+@yR7H4ee>^cfes4vq*5&>> zQ>O$zL$>zn&^E0=OAI6c0Mo^Z(1@+?^gzh&qDdIn$Il*lp>I>~TC0kEjR{2F2BvO7iGYzg(+MK~&ri%IoyJ-&wb$3O>oS9|+y=kDTtSKYHa zMZj;{1=^&p3_M_W(@Mw5z75Y-)w_^hUHOVsdRuGfDU42hfPsPSigQ_HChxfSqYYjH zf>1KV`TY`S$mJjt7X@C>C?$6gR?dYC(S;%zG*a&`Xh{USqa+}8yR1_lEfPrhfV1JU z({VjH{ynZr-an0TL!e>$N;FM!a;5~2Vy2>v7E~2^<^=`ZKa;?AVO@(KJfV*WBr6p{ zIF{f4z|8L3`=baJWw>3=e}ZraMI5Z@J+Q%m@QP0+1gMK^3R0!IeG9c7P~|7cwml

    a`s(+!w-JZoPEB;@?`wtcXmd^jQp{pq3~po5KYxe|#| zZ1n2=2r_i4DG@(U7AWUOlQcPa_jE}CEpc>jMC@bnIRJYw*Tezs-grAk_iwEc%!8|z zTpTA}q=wH)NvuDPCpJ9`)+zLc!vA2p5(su5ykwBsg9|iArn>_E=n)#A7y_LK5U&t^ zDLdoAwWI>RXBb#&)i=TpvF)^2z|hr~s0Z8UjeC@G}fbN=ue>a}1!E9N-tjC>6E6vtd1Q&ZoWS0_E2n90c-d27z?=4uddwC@3n)>rmh_M<$#9bz_Cjril_f9Er@oaj`NRVk=C z(L4;^6a%MmPVUODEEB=rTDHeAJ`nKRNB9)fY0SR=b-MLYClhEU9S|qtIFEY9YVY&U z1esiYih%aVK85s;rI^)chx}FwqOnAY!Bco)e(^sDW`CkN^iVp57f2Tin{O6lS>l1> zmzIkN`{8lbV2+jmo>(g)Zr!?S!qoOyKlWvi;Lk%yHxiA`5QnBwneq2z#ms&9cI(J{ zlcJv`H4*&j)QB_t@sfXuj1+uC-evq%N^*ELq_R>r^0p#Z;cA zUJp?sIH6m098P?Rjce{jT_n?t!#$|}Z~E$}8&bxNGPJWf zW5iuZqPNDy7<_;q_@;+7cRccI6ad)Nk6MexV(ZPGE%u9X8(iPl&gS1`+?u zZs%Jq*8;V#@3*=5NKv9s1E30Fv(g3uVw^)Jj3PRSbg{d3xJT&v>&VNA`MBdszl z5ttc_$Rb!`{gJ}6-8}2S`*?s@Yup~Zgw!V1#*Y7@gijN!2Ixb{A`knzmcDA&)f6<~ zwtPR`^k$x5LnSLOlL%s_qm^TMCRn(7)RcC@pBmT<1D6CnXAD>O^YmBb)@NYwt2#K5rZMY(1LwJD$^bSc8Dyh&8+oCL+p<9jNB&G+US zbCQA8ZQ}3R!|5VP4sjKI8%B}lH%whKGAKWM{)~Nu95S+~T`)eD`lSv_uEkKDmZ<8Z zIBoSr9Q1PqC}Dv+a%mXynD-8n(H|bXNv!Xc6Lu=Hp)0#NBCLf) z1UUjJO0|RqZ_kE+JQlX0l3uBF8SsKUnF~C$j^0fzzp0~97vIB`tD{wcFx$cPL2MjG zI{c;njC@vR>V)^^L@3r&iKc=PEAz(4#OhJ8>+GUGm5y-8gZ@f9$_YbakU1gOe?^Ct zMs}hKLz(CP7V;}9FYqopNQVdtRE`TFy0zfN__k_W4N`^tJFHbp17&-15w)y!)Ra6o zy*-C0-sk=2K)fC@c1D;I(e}HqJh3n1Tew|Rtmp?H#Sb9r{Ql8yzYsK(5}j=YhWMAN z#dqHqrxdpIBH3ZWWrKdW=OH_!Cj^R^?XYg{9=QP{SlIpZhrq2N8G_d@hf%@2eZY$` z+KR#PgF>_kn@s6`B^Hm%HE>m&DTM|RhSLAV;N#CJ)6`Pi$O0Z6006)m;j_Bf&!GTF zl8+zFSR1Uqu03wEm#L?r5M-H9pqHQ+Ko4FCCX+2OZ41*}xGp9HQzf+M4J(NKslgcW zDsy@aS)39A>YWG=HEvQBiWLPhoGuxULe0C}{F5R`k*xU^!FmTjcpCt~VfvDXdSlby zOVI*5bN5!;@)Q@hd-G6a`=6UzA`zN&qR4dz)`WiqIrgI9A&)E22s_6*y*)g}j+In8 zl6_XH!!gZ}!tL?j1#-qajk)m77fG>2!oAQ+RRNK$Ze`@thuWaseQqk|Uf1DoZZAI{ zzY0olLBbd9{|e6RO#Ou#dqndO;Q$)cZ(%UTM zPP{JY?cNGFx0P(Hmo?=`$N+3LKW47y&yA*%960}q>JBVS$uj_qK`^Bib)|`rlxMb@RTw7sb+ig^3>dD)(-`&_ zdgA=??!ae%nZD=CO!8uq9$yet065%05jA2lTX_Swcx>UW`0&##-`xDpq0O=Gxb za3fQCU@v=1zNGOC{$xYG=qJDMqjliQv5l*8CuC2+9Q#Y(cO@Z?~S)T6d$B|_VGRa8Y#QOCY;rX5R~pAvDlJ}b;`8WJ@?aJ|htTvxvudZB+LG_{xP z0*0cU*`K8k`D^Bqz+79;R32Mr;t?qAW?_=bU#tFN5Rdl7`j=}x)uzHIZXOxus`Z0<+fV8IL-WWrQ#@JJ>DW0ukiDF` zrE7HDuT}I2Sy{LuSc6R$pY{h6J@2OGnOSrP8lw6QM{Z7DI1&**svgy^bvA`}uUcDg zq1|RoBHWvxoXc>5cH`~G{`^$5Uo&hMw3tQ_(&Ye*!gYbPPsEFSU^*>X56QORkyj9` zqX<+oAeBvQcHWO zKy+ddJ<3oG6|f@uwSGtN>|4m6&|r;tXRJEEQj-Gt`0~G_b?tAVP9|4&H~aL7ckWZ6*f`t3BBj<+!rJub#+j)&k;#M%r8uFK)OPKRM_?F$A? z0r}U@<3NG()bAHV<3U@NrM2J6HPF##iEvbe1!!D{r=rYX$mK(6D^2X^I!>CZLIiOYJutVc4v7&Ygl+?kq=Io<6S3{u8_1h59Z%YH~)bgWXkUQ9$ zaE$IuYrx7{I|Knf^Iw4CzylDzmCVGBUS2-+$2BY6oYnvUAS8sZ`v3Kbn!Ebvc&qjK zrYVYbD5=ScgZ~W$6#`D>pzx1vC$d*yS%>BsZT%yl7u1aB(aiq-xr6cpPE=)0lX4vZ zqR@v|&~!9#3oL`cnY-PftZt--0^WxvrMVoIF3Tls!;6MI9^@2$%hwTK+NakTE~$Kh z_`TEz^l?EGd}O%_-bUi7f*4K(jIT<2($>7T%=`A#)t{b%1AH}Y=4b$FZ>5~VM5x0} z7Ilw!yZt5LU%}{HW$I|$ghmM24>LHpxN4!9G)25rKVWtd)!$v20Ny>K%^Ju z$@y_FfR6TXh~9CJ?+&Dlt`KP$O5t(qyP1Us*^Rp)NA>DuV=r0SuJ@j$|L)$@3u@jM zS1dge8MDHh{B9=+DOd!cNkg0+F@Xgmd93o_e&PRGwlDcUGD_Rk`Rot75QLg$L}J(8 z^IqI;Y_0wx7;xo`x=S7Z*a$;Q9$P)XYg(R=~b{$ z^Iu^5haw+{Zc1$`{8ESp5YKc1G-QbO_|mG6NRn>{b!TT64Jc9j`+d;s;y`!)UC+p^Ph60SVnP+Inqs1V?o&U)R$jSYMUojf#vNt>Umou z4~yZfCtV5H)xMaJ8_@LhTnVcvCV1>*9Vdw8_iOe8K<)1BD9^z3g^S-+$a3yHR&~rd zL=cuh%qUDFoP*ToErYg;qa;1N!Z!c)KlkgRvXU$9iB3&~3q|C5CCuhRfi#y$%FYo7 zd^dVXG3f#nO(#Hh8o^lY?DLG$F)m?3&N2rWFnTHn)6$N=S8!tUNKojX{#diiZIvN= zhpcq~NqS)`(+Zd3+aMLtBDb%nD%`i(VMG9_eEsR#+lGD_B9Tcee=m2KcHs<+B$ZkK z*k(fnHs8LqFhvI^WH#rGg;v;^w`f&O_y~Osw|wEI@Uq9_;P!UB3`rb&r3F$R_RZ5C zuGcclUi05ptQ&vP7{4g(c!#lXd}NpwvP_K5^Dqr#TULa-Bwk#3q~e7BSy>ozHt2Y2 z-_f=wxIZ}#;xn2yDr*!)y;C@)@#HX7DObTiCEvlSaGP~6f8JN4s?U#2xa7}sDfKS? z*E80)bE$g_&ORi!17n;KxluU7CZQnQTf0$X%ho@2g<0`NC@8=AD^}Yoyu~Kr5*02r zS^(nGo2x1)Y#U4n;6&w!{znpISI;pz92*Nx&EvX7d!@TnXTc+vh%Axxli^+aTWkY% z622M#-#n4@rPkg2n9awdbr7%C{~aFMfvsYcb|Jc$I>Y!`ZLd2d z?+?QIm#)S7M+Yr)d9CDiWOPt0(WRk422WL3#copK?qDL^$CE#pvZx|wU+SOplkRS! z#)0EX109+l#*IxyfQ)Ig+iNO7^7|rP2lUaYRxIwuhMZR&W2pPe1J-0prQKLoBNDv)ig;MaoacKhittGx1`{|{N`5GGiVY~iwP+qP}nwr$&X zb=kIU+w8J!bNYL`nYX*^yqOsh8F9{EpPv-iMCizW;i)KrTBt<1+I+mf8j;rC&1TB9 zlGb3)%7$uak}8=&nJ72ImlRFvby}8}A;et8mM^PjAs511>**dtDMvD#b&ui7&+hZh z1i`1*xa%`yq<9ELXzFr=cvmJjTCH$n|eU( zWaJX$CyB*+GW^Ll>gd+8ia91)fWOkqxVq$)A!T(B4^t&_T65fj(_p!fww7E#YL8hJ ziK&%ZKr2)R&R=WE{qNjkaFI^ZCL7l5vB^-t-rkR(h#s7Y9bK1DujuqTS{bh|5>GOH z$bkFqUQB6v2$^sWatPGTWRG~5!<2tsKS3Jfe+%iKDMw&=`EOFh;gFYoT2Gzp=Y#L? zdZkF@2Kvii?`0_7sL*frvaN9raS!shwWolK&X#Ic9~RrpK@NyfXaO_{=%p3q9YQXB z3Nob*+37n-oO~ph29GqoS+6#yJVy9X8-x2(9E~S7gW;J6a_VcJ^jmE^b2BAqqmS97 zfI9wW-c{WFVyK4m6lz^Y)OO~QOGv1MV8QcEhf1GJ30xh|d$z!MESsHfRLN_MV+RLo z8L%?5#R|(u^K!D(j5@Qw;1OgtxG}S$@U~$(z|wiDs(|sbidtbV>nmUFYTNd%rh+z7 zrStU`r~729T;af~PbwBR;*vQOFG}5DCl)pKn#rGmtS;djHHb|JuNvj*Q25E1W+1Nx z9nH)Z93^fK)|e+~0K&z{dTcJ}7#C+pRq* zB;0Z6d;HN*8SP-M7pT>q$+Ys=io=}X$mWGFlo#F;b(Fn0s2OC01#zHH3P&U+9)RSH z^~;fUh9JxTSG5L6d_+YTQ8#ipuKmL9(9WAWj`fY6MzX-o=3WdEONA&$MBKq{QgatV zrd)i}aq9Q5wJ)R(hkr**F??}gSwoqgmsf&Du#eS#5~v$2jw!UL-JHhhx~&vAL~Lc}vhN{TvxSo{jdYj8vmX?lO@05TF0;^KQjpeC zA+_l8UFtFw9j`mI5y|a?av2hSHPQ3(sH80DMMa9-h&hY;MTxTm^Ka_JVrqRQqy)vV zQx8EN3G9|nP{E$vc=^iss8N*o_gO`ElA9%066-$=Rgnq#Vspn!`*R_> zD^!@cBtTx~dE3uWczmA#nT1l1_PQjn5H(np+5kpa-p&zNOQt@6mhQc`amn-eXduW8 zwWHQPlxh;7UG|%1dDbk_=sri+^9^{ROX@WaTPrb^tl~lPKX*0FK8Lrr>MhAW z)vBCYnEp*z8!T>6vF){G??2~5;ZBWjA)9*CTA)&N>0}@xTlL<;kV>CWM-}r!;Q1*7 zX^8#)h@z9<>yD97G_WgzMcfV`w^z|{luF>=ff9WUYRwhoroa9FqOKR=m&5;T5ja@v z+dQ2Vu7vzfm=0SBmJ8u)c`qI6iWtkBsS@fs)el)eukVG|#+m^t=5%FIh8_(J8oqOr zQsERvAfT0OyNV6|?lYK#mJl8OtRJHQ|540>AsmDyx`)YhCu;Cx3`>1e;nB34LSjVT~_J%M4T z_|}TpoY~-^uE6j~)(Q_a8KAS5VS;|IsT9a$^+fY9FwcJgwyvcbFurC~9tSw(Q#>g_ z94XO_pQ04C0yzB${8sMUK{H*tvW%8c6YB!b-}#BW62Szq4u5Mal9N_3ojI<`S6kA5 zyhi`mH$)H+vRaO4gpTHb$yv{I#lH)ZE&qZT^-8_H^T9e76f)7l;*?xgfRXGnVq&ED zIRuxd{NLR9&ljBGmB^|&xJ54F+mFQ{!K$IXYyrox4=wu<{<6QjT@@EbTmNdKJHl_5 z|5<&UYzH*F>GQLiLuwUtChNU!D-@J%x~HEQ;*OfMFxm44z&!;W5$ghq&c>_hVFs*D z4HJS?^T$*U0^RoFQXR7aoJK?9dA7kFzye&5u@axsp-Q*~p8si`tnN1&8*MW7F(YA~pae6RJ>)_DCHO55_$n#5+ zOD=t~8c=}}Rf*zEXeYi#(s?$I!HcrvOfkdKs$QE!c4F*WIOtEZ_mbNKW&-(H1}LdvlNiOJU~cydqyh#kEIap zQ!f_yLjff+QsDo(T7Z8Tr}bm8gc0+|yQbD0J_i#p>!WJUR1+;eWPouRQmAuwhz-l= z79O%bOV!0*#bKt`Yct|)9!%3Z;Is@a6#z_n!r8p=JUTa9XI=|a7jXET3UmIYh5qhD zO|>mF(Ky;Bl5hThxhOpb+Yp|1!#U-8ErFn zQj6Fg9r#gkWJb;K8U;^3&JER+FgdCi`Gl{4sF80*fxX@+F_G=IP9Uxl)B`&ei|_}` zPwR{(inVu&TnNTs8&;X^CnD<`{I!Ur-hSB`2L4RyXKM#X=QrhL_l1BctD4Kr7xj-J z8PXkQ5`uq6;0r=yTKCClfTsi)EO;nZO4Sj!?5hC9(iptrWK7cQRpX2Ygy5b1A`QEe z-W$B>uZuvov1sK{=@4HR+5Yk&*{2E`+m88_XYM(ST2a<`2IXq}vlS7j$T>krnN4q+_sqsrDkk(Yxc7>a^6BF8_zO*nb2og+?qnoa z@E5zx<@Ed4k1E|4bhfuO&PI13*`hsv zRnIbdGt?)-t`?J0IFo%c<01An^`%g7xPFRi$3G%h18IwW^;p~H`Ux{V)o%zsRAllq zz8#svC?yc>w{hqXy0WB0-v3lMG0?N#>Ysf_5pU|`_j+73PgfZ1_}>XhU3-Su3ISk# z#hd=B9}8c<4vj~F+GrPgO_`w#YeQ3nT_++Lt<0`qu^3b}@*7@WoKA{Isf)(5xK;!i2WCjCk;V2_*#UEYc(6@AYeDm|*!1^f`}&>TPun!7}~hw?HY z_x~b}Yaii{$A8^<=9T0b#svmebS2pr1f|T=4r%IkzmG0et5<1r_bM8zP}mLtp$d-> z3>brSx00ClCoN}?#i2@j;(w;RltaLW80y_up`iUQ&zhCup$E6l{`Nkzqg|_ANBWuz zwT-BiZDM8w@NeDhqsJuFlyl5_QA2l6f6h0V&GZ9E^{FQ@3YErB8fX6G98}T0G^n=- zyaBwy_FAQQi#KBx8}^R(`Za>=+Atlv6eJWnIfc?z$JfDEJ7a-{XfcRmDk>IC;s)Vgt(=$pqw600ro1+PO&^x0g#yTnv2}I}LG# zad*G_kgb`r4PlcbnoC90TVDfMMmr6z>!6+o$nnl-zv36aEm(X~%}$Mn;)6Q)z6guA zuel_C@#;~wW5_PspT7>xC6Mkx3^1Ia*1EW`53br(MtlLl5)yYkn0`+P=lv$X+v-P; zqZpJEySks%9M$6liZAdN22jiCaK7!2YZTTgYw&311`r}f_TENFOYko5WIm()j4%9L zlG{X^*88$e&M-30Gz^T|U!!rYW)z9v&6qWp1?IpvIF@k{mlC`rT)f%A4X8@jyOgv+ z@%|&}msyKm;5ZZxExt3~L8BGmHtO^@^F%P3eclD!}q$3u3$M|c>NjIJ| zcSe*xUczaptZ&m4 zTBaMU_TNR!(ElgAFKT2*OosdcsyR4} zv6LGJ%ASC>b}JFzvp&Nb7PpNqmLB?f-B(jqu;jiL`eLN(RG;V`-*x8+J5AERKLi9g z(f^doLnNSz&nGYglwC#!)G(3eD&LSv0&y-edl52YZ2ez_alw0bW*{y;S7PZH!G|xV z@Oz{)&4cls*f928{FP7Cn>Y6IacmgUIk1CId64%=$ zc$-BV9#_ARY}9#5PD&U4k`;Xhmkyjql;`Q8dXCSJ$w^QXX)8G=1Yid3Ouzn19`wY! zPLjEyxK>KUC*aGzfW6Eq%i&!R$Ub&5DO@WP1E@Hr}&5hLDh`YY;a^&SMKy${5~WPvCKF>%aX!hedARwY2F;=UDGiGc|NfK zrB@Et8%QG2Dd!3D`UZ%m(|S0QYRqH^h3(4u{@%L+jRTr)1P~9 zLD_vOn=H9yA4>Rt%xBj0VUL55wA*!7x1q65p#c{(5f5#PDDkS6Z z`9mSJ`gSd<^iwF!w4dvtX7orW&m3lSb+Gujm}_^-ChgZhl}@JM5N7WBX~3xj(aUNb zUE@SqwJDs0yx1Mi&9pnE?IK9q7CM&d)8TX-YS)>fWr)lQt->bQ}pf|>|LathI?o|y%cIy ztSaHO->$;2$*0aP!`d#awklBV*$+$_;~h0YS*#b(Hkg_pd1Uu{(LAs4PbM4vetKH@{G-U*SjUn(p`$6~pk_|~XdByzk={C0pqvGY+# zg%~dyHRcPr=X~ooNCgKTu~&ye0T46^wcWQniKOjqNO_@MqS;WMr$6gH0SK0k7HuH8 zT=dO@I+^}zugu0h$T&>w7-_lGqU^!_Z1nxMnM}^&18gCKtA@QWQmc9utf@8x9{fTRnLVQy8g(&=Tbb<2a37m#uH$z9)K?a#s%a zo=M^CuyLAazX6mXS$(OPuo=A%v1~(axc#8%%Z0vsr)%|X*l%Z^Yh}360e0@aEl>mJ zMSU*kK9Ea9m+#qHT-?oaWRt266J6Jx6-3({Glt0kO z!QkhF!Cxs?wUNDL*bomlaky~!h?MA)pHcvFpKr=4r{i{gcEY|T8IbuEe6~lg^buz* z&5|_HNAJsX2%fvEk&V;%IIE4~flcSX{)3H$1k-)X;UWy$P|i{f8)Fb#4Y(aQcCDFG#kq?SK57S9%= z-@rf^vghT^O2!79=d@ovGh7270fY4P@^LrbEUXk{82|DQIU8s{=V-w~F4fDRSyVf$ zbEL3;zFDx4Wi)46ja4*Z`!;6y&KKd^)-6xf9ke&d>)6ZdUk^5vZL^dQ_pWs=kJSCZ z{N#{dR`V3{@7t_G)-~?qrI(?yi{6b^m;Sg#qMSxJiBiU=)ICGAAvB!gHd1<@q&K0ADoqV3$?G*}kgIF{ z_M@nuEmiVr)Sk3Y_Xceb!S{VEFI0Pb0sm)j-Df+XE3x$Ni@{(4lyjeZSj)M3%FS?5@3+~F%AE^L|DnP@l%Y9BQmPi1Gn+jhX;J`?8DKzp)N zXj3Q5-=96d)u=RCztwxnjOd9b^boP?yfhOLJ=po!2j7#!8jL?C1ldGA3jT_eC-yQI zNNztK3^FcmUB_k%WWpw|p*p|)NC0O_LUSE;4&hQ=gYrC>SoNkL{Sm;?Y7Pu3tp|oM zovG@G(+lOU_kU51(*$jhX&hkW$wZ8)?ysky?FI;8)Eydv!PaG7)`TWrV!yFm_w&u! zBey{j?9SujxdmpV_Phq&PJev$OrL$8-_K_Pul85OA6cNCyN}@(YIC=#&z*EKE9h0-D{`T-PDK{TkFomM?pj2A88!GepiJEqEe831N{MDj;G<|^ZbishH}%kJf1$o=rN#b;P@zds?+?W;Kr?Ii<7xYuknt` zP`2DB{V%|vgcp;o=WoZAeof5tgr`?+4W+JTs*K%~Js}&|5M;mSQu5Kf8O?|Eo|c zhis}30~iviN{v?oY_P=3@u|g4_h1((A{eElP+$OyWNH zNf=>ielt0*m>J+W^BYcW@!B=X%+qOf4qZApVI>jI@bDTKoCTISsv2KyC;8xm5lkhC z=k&KSdyme~XHHWZY#^S53d&IA^co$r*_c>=+7m48*|}0Oyk~n|*1BJJm=#PbjpFxS zoFd(7ZJjb}%*g1XM6>BAb|3+1Z`0~oW(bCz*m9X9Wq4ijN&HkerU?%Z?IcVn1cG90 za$4KlV5E5EH8)xGds#Rj_M0^>ZOGv<1d|D6ZmJ1h{cY$>>2o_Hj_7sIyN z!l_+7eb}_Q?}Hf{@Dq>^PBWBn{e1e1bMFy&ub{#I(l9rjE{)9EsCAQ5`xU9^`3NQz zGi&s6k3e{);hF;{8$LZW6=BAuUWy}NFuZtA8udsiWQ6B=lr4{umTGN=h>(It!@3+2 z?4-=Xc%0gmaAPE;7!Ql0MB(1RA9_Q3);^7k2rTkZMUnI6D)M}5yk7VFy>Cr+fdWes zGL~sgB;bep@U68uNg0hw`OP04Mx5Ws*AC=BIyq(Y7_Sg)#A!=!-kvi|6`YFe(lq2scor^R}X9Sd|Ml3pT1X0QGj zxmW)5NFTorkZuyXE(Sh}iA~oF>p_4o=-i)v>Q7NSHIyc?KbpB8Uf!Q;M394ec9gNK zcVSWc1#4A$SjH3e3{UOj5|m*IzxXs}06TRbn^aORW@+cNmy}ZSR4j|aQ7LiG>-2Z^ z>t=o(TUIM_qB6G%&f0pG`>%3wh!HrB;+`~evGAL&$C8gv?;RMDO&aK{o!)OOP=NQe|y`+*3F$o+(H(9QGYsZc+<7ZGo+{Hgw3EDg$E2IzwXO7A${T=1$z8|l zt8M>gno~q(IK540W*S{sYO_^r4G`dN>AHUVF99!gnaI7w&zXwZ?LQpTqYZav0S_v(ElQI_$e{5$5G=yh27zm9`ZOT){03V&yDsy;h6zR2a ztKcCXxqrQg2m##QnJq-$z-Zru=WHvV4!wSG689VNI$h;rbcKcl8Zjw%P91oLRN46g zY|8qh+;`;{r~EOygMO6lA6@k=YUdmxr5P>^kLR#poHb#bD=JpmF(X8$0W$=LA0L$N zXJHWP!w*>7#z7u=5n|+lshR@8Ti86eG$l)IAE>2-gcQk}MT`@0%>+%C$iR11rz56^ zowNfYMU38Qwf0vl@PSd}PA+O?o2BUv4DJcS$8RaXQ`VdyIAUR%U2@e|yK6UfI#Tgt^>UK(jfr)UC6T;ybJSB!Y4<*J|%Y`0JXuq4&i z#lA+EfP;?^ags=LdCy%k$w`obTspc4J%%3pyY&EprEQc2?eRkKuR0{Tw^DXxuu7te zDq`H8kM)HW^J2OlR$mj>q}J6B)WSsMfPP^xYCDLQ@~h2xoM3rb3RCF}Uzg!oyjg|n z%rq%kXN=|ZkFv%R?NCSc>s4dWsQ2zShWr{F4fuiuW+Rg|T7~VkC~xS$AqYm;z|UFneO#Ml7gNQ!(Aefc-b5z|uvDV4GO0rAk6T*kLP)fxbzhzRe~}5Hq~_ zte>MONiXu^*!P23c|9-XN`u7^hOQy;=xMg?k03X51=hgTY>e_S z>~zx%GUFq3{XE~@8{WFXub{{`q-BIN>XJ2-{4Q>ufqG0L+^jRLGA?x=lFY0A0ZrX= zIbYg6rEnfZH=Dv~z#HX_Nv0i_Us#=;kh8oOI3lp65AjO-i-7Rg;W9>`$W+DB!H3ko z>V~UaFNsMK58mWuH^&=Lpp`H(|1)}q4-+)5;2ltl`1X?rD#^dN2GAz)tjhG~J;im& zI(%?KWEB54>W-)R{_9$Zx(ck$Aka-mJS%a+@5pG;B0-o2Uy)X@R4MTt{*R-p;9-Wf zhRL_<3#p0=X}^yZ)p~G8{5-JTS<6+b_60^9!ujkzBG#}SU*ueU3?ifNXH)BtY|cY7 z#Efzwpj}nq-&RYtl}d*8%7{B=!bi;#WdQ7r=M@w_?q2ve`J+#cxJqVbYs&2nsmH=E z;u93HuI3EbgO6&M*ldE4+pAfSqaJ5G0_T!pP$Bmt0{@dch1W@1ZR;E6#Or#G+ZhlI)+1wbaRI0(o$EMPXb`&O!8S&$9z zAEeDaO;Lf)z>Zk+!}PHb*O}g7S{qroY7;@%R;EpK(Qxi~<@_OH`nhZKdAjOMoTJ09 z4*oZ2=a(uz{^QKuk4oc&e$y&nIoc=s5h^E6vUL>{-CCL8RR7#YViPG4B=AE z_0K{@XOJko0}9`|A*LsWpY!U-Jm4m)PCaPa+@if{Za0F~xldgd>izxr#1n}^=F9%Z zgFxU$_*=^yq(P8n*(4^1D{ieJzot`A-Q17C7#2wHySRWpLgBXSciBtpc3?0~|1L$3 zmiG`bsCw|6vE}iVpU0JOKHuZe_i>vPc=V|O9WEFw@9!6Cll#qg%_YkX7}?Y)bsm=v z+O&DJu~Ur_@;sk8ZLj1Gu8B6_rARZgLcast=5XiBJ^lrYoAEvFZM?}MZpjs!6}(aI z_yo)Fxv*;w;Zn6*K!~hZSmG%qM*I7dTzWhbXFce}vbhT;8{UOz*dZ2Z(Oqz;W&pMU z<#wtUf}wl!wKj5p?{oU901|WUlBmaq@Q?B?w}6y4wj|2W%c21~Db=SI>69XnYfMOGHIdMSa#bz6qv)2vG85e!d%-0r`QQkNjo zk!4nWX$sp$-lOW$bC%~ok6&_ReH0d7Qq){^!1$WBsWoLtSX&x7mad4iWJV~h@{k1= z7Ovz7Kno&vt)=nKO=21Vo?(p5gv6BMcmPb=Ry#ZJMX+BSyz!CryKP$ec)mG;(hjY5 zSMHPt+g0+Qz^UvNt7sg@gu49;qt5XW2*viFw`B4D0vp$Ks&5`9#4(f{XX|eEYw@bV zyqFQ&kl09%S0LNLMDuQKSSHaRqRIa zPPy&t1+9nVhH*3xY$?ussx)IP+?P=GMunz9cbuGL>Q$QjA5&>Xr!aY5WqbbpYTzY* z0%abSmL8e4wl*%2i^K2^MLuyUQmYt~xeG#c1Y+fsQYsQe+l^xiN zb_{{B2C1TwQs>C#QFROqh{2YpYoR|-07PLr_T#nrDx8=op7|WsA<-(9_p7q>`vF;C z?@$t_QPDqHz7^NJwJn*Fx2qbj)VX%9rVXMgr{q;ccJN^1!7WZC10~p9AAHH}Zpr-h zW=^u4h(Poa-?hTdZ!?7OWx7_ttiE2lA zLc-YhJsq|JQ2pQ%h#3K^Se$V`jCfSX=9!J7)mP@a;BMWI_+HXLg;mm`*}pX~!`og9 z(=?E-54bsHcNE)0Pnr{OKw~HOhZ%KPY`FsCpt=Y2;mN4Es40!IE z;k;e=D4On3Ujov$)Sbd|V8EEmS)va-4{Kdm3xzI+X44!6(FS!F1vJwB*{(JpMq=n5 z(y5{EpjP8cm`)D|@$H@vdt!#YC{&Mh;)m**rKfq!qvio4%U6Qu zo*8YwMQIt{1y>cWh&_>Xs{@Fk*qJwCckE=W-233ZnTN^A9GEq{?YUNG9*(` zWwu_{qSsf=5^idw41fLS1qrF1Yy)`Bb>>rLWhPKcbu779PIEt0k?``SrcPE?3dMXH z$qD}|AkHm3n?iKQM@3N^&o z+aJH^mXd^`u{9t7=sg510#z-|IytyN&|!dKgwF3iP?};UHG%1@4pa^4mgKeVU^Tl9 zGjC~AtxJChCtnH?d(;2$%(+d&dfOoWt+3-9F=;U5<SpRP)^RE2wtFEf+7b_5iL4;DAF*uSN3**^+!NI4l9~j{ysb+Ye%3%AD*-QXysQy{RDg#+B-{Kd}36kIvWBKXt#@G=mSR_ac~LOTnH# zz~Vm(8+e%{Gdb33%_1-(Xd&g_4+V+h$5}m+Oe)apZyp1}rP{IFat_cM&kiDn*3$XQ z5$kfnHZDb2d{-mc%C`_%T4@lw-60FOjoTOG@xL_+@Ed;$dn4Q-xR&8hP*ekgB6$_q z(}DJ8FG(nlZ<{dQyK)D|N)cmiL)u9XQnFEavHK;rut;%7UJ8}NH7&$7NyJi1-%O38 zm3+ym4m-*jgV9{8tzAdX<=av_cJkmVo^*xoE!_EleqvroOCmLfvcll-5@jT>2}1Z6 z4~;R9?(5!5TFENOK0!R(uZ?GiQJd%KRytr5%s+S%Os1LTo(H-Gw_8JS>Oylov5QB=u?ov zCV8XEKV%Myue@Ly{2i0%ix*Ft=$cT?qy_PP{9@SKl#`{(ThZ50#`h{DYs5p-ZF+1G z@fhsjzn`%}4j&eN^HY$oT(P8wc;~dgt^Sl!um++P-x)_U_fyue{raGK&9MJfKLcIXyj6=z+j@(2FX18UoGoB+j|6jl^k1`AU^Y7X)})5o{oU)y0T zS@r6hP8R5*E$k7vqn)7Ui-x4LOtB5TPSL4WoLHDX&?8EVbI}7YxLFeoga#A72T`T&z}Nbir)8ic^R05M}oUH+3;`^ z?kziyEp6ln0dFwyhp{&&z7u;E%ZJrQYrh`u(J`xs6ls8* z;&h;*$1CdmP^|{qloh|rUV1OCIVIMBZJivx=;A`h_K|*upxSS$3_TSiOkds8Sl^~y zhWrLN6~W#ME=}G^I11#sR^vrDI6n@k5(+2n=9Vzc0?U*C7W~?R1{YNFJ&iP1wgQ$R z^ko>YYltI?$4Jz_<3Fd)iloWwjGVVNCK_LGfY}oQ-x&^XZDX(1cF)I=*S!tND?i+& z7Q$uRb5&QvKfFFZ|N5Cv;=|kfz2puZuPDKtHYcBrg?)^JmtK)<@rY2oYJ--xzAwGy zv%s_l6=Y|M-@lLfifStb@=v^J`&G#1PnO%h?8k|(UF%=07qSFtxncJVe4nE~UtkJ^ zmwm)w8`2LTGmWtbpVZ>LvNBA!qe@Q)BZ6Ab2&8d9r~ZXM{yRtqn0(Ocu&aqRfAx_=|y1u+TTzNL+v^%}H?DeOS1rd$-r&xI8muH!ta?mty;ef2EsY zZ?HWt-0HjT3xNc9g9^M*Jq7njiF+8to0rWFXRJ;fl%>>sq6$J+JigP!MO@4(Vjm$k z8aJ`4*#duj0Xx)WY0LCJQL`nJqCZ<3)D2ehX^JC;0!)R-kI2(X4*Vplg6HP*R0B8q5D)D+3!2ZJcZ zxX>o-d!QXz`DW)S0jue`re$lZ~8W?I?=l1 zlzYb-#ZwDkuxd8NHr>cbv?A4W6mzEL_`Lh1JXUk)A?=s*?Qze%?XA1Nqs%BfJ=I!a z$p#=v_`{)jEr>6?;lUi-hhHCsZdgyX;<^xCY35{4SsFp%^7@qS^(}Vbl~w`n^`XI} zW^2mz)jsE3Gja9;OW)}i>v3}0P_zMC!`mX(D!0TfPRNskm%ouO5# zze+te>$%Hvg})Y%MBKyrWx2q|TXb=gLqdgCKC-U0aX{ig<0KVKOzT%07U<)I&V8b%3kp436q!1&%1mEPy!Pa#E< zKgCzU2ocvOs>(6}<$=9(pM`%hjx2wN`dPqLG81%Gx_L<4EJ$CeJI~Juj)dQ0S=P(t zvM$ZJq$e?#8S?^HGTVcG&)&MC7fCF^*j-$r&E^b2ONzM5`krrA_1d>Jy~CQqn+ zeW{HmC=YI@veHzASeCYW@(?Lc2pqKN!J0@Ve^2VzLp_dd@c4!GlY?E@>R>6BUAE?@ zpK7#|c;!@fv=K@Q4&Wn!Xnj*xJ{kk5G0FJ8nk^0HY(8H_B6)5)jqIk)MkPmaNzj(x zd)CisQBz>OvdLcquf?|ge`EHb-&_26NT<3JbXF_akbKx#KU3toCg-BFzh{;N)p@fySmzi{k+3Q2>Y(PF**7 zM1B)D8noEEvDT$#5>st?8vZ)^bR9>S1dD2bB%_kRO0 zjRJ25I_C(iHJyqm@sc+ErMZbC*m3t8dkheR9!gV-$FsF7tJ@qK?Dy_E$NP{*?EoP7 ztk9aP@IHiVvifOTjhNG{m$&@5JiMg5AL$Ebad@~?--3|mo%jkCJV+D}W(lJU4}+@I zsWb-+d*3|T)w~+FAe@NIZJt3rDDv>P>rbfH#=kCIiS9F5`g zu;2+N)-4I{Kj6q8j-Qwq;ZReaY+pp!^da7tojIpGYk_}SNlj&fQ>HUSC+?V`rqZ}c zxP);E2Wbyk*yq>=wH;I$u_8~l;040*r;3apQ?oaXzxt!9T{LzZQP#hUsh~k>JHOt? z)=H+YzbE+RbD0(g&;a5&4jjU3-juKWj}eHNqu6xj0c zoZ~hgIG;A#DsVDctZt1irPV-J{7JKuz=yo@ofK-eNCm`m;xbyt3_a=h(%W&=>@`(* zSiSv-?3?Xbs0nj@mR_xwKZMzyMqRA(rr;4EaO`8I>~Fv1U6je$ST&<(UF~HT#yEZk zhja$8N#4?1zm9tXD-FU&7@ov^DcG@VPIN`yGvt5H6((?od<~Y_Kw+K;3nfz7*M`=_ z+Pbv)_uGfLC$9`+V`J-kY#MCx78VLIktV8cnC`~ z((DeoyucJZU`@7r5cPN5&n?4K>>vlj5>0zY82*BClc~=&1&2!@Gj!u_G&)F?Ff??Y z6Vo$~ZvW#~9V~2cIn_|hGBN#R<7Tc4OAnV!R|F%NdWj7LSeE%7tWx~I{m}XjADn(3HB^p=i{ zfyY%-^5fq^903T3mDo3A!g%aM1KjCT+@BaDibLs80vbXnx`^dV9~lNQAEU3BNQqt4 zZ6^W~;|OrS)9$*5n{*)FimtGnfTTiH{5649hox$p zp8Za$Oo2t>yPwc>bUYgshTCr6lF9*P_LSPuNF+_Cc!QaTQ)G$6JK)0ebhXj#1MK!) z1j2)L1%kP6?4x^-N!JzX$!?G2V@@BWGdbeh{K&*_iDQ0qbQ#t9oMP;xWCpM2TM>;! zeeVFkq&3G)@>L*SA;JLRUK2aGSg0l-spJG3rb&_WT>bn2CV78RakSHwMn0ld6TE$p zHQ{BtdFuV6df?qH%5&lIXQnr5jYpNX`A}|ObGn`_ozZaHoA}{_AghrUlY~9hU-DC9 z3fRH^gT+BUJnn?RkVx*emxZ_NpDTXgb=kbfs9{GH{maGeNiaH>*T=6q5=}dgmq_!n zEC!_Dov*KwY~`>G1_a<~2n}xY&v^m?Mzg|!9Wc*Q(gp|d$~mQ``JsM`LE2}bD{^zF z$#Moa4}B{bHFbkCSPz}h#ZCdtTM=N_R%tlkEReV@4{&M6+v?XutT+NzWymcp4G z>qwV2NnNX}lDBkQcb)UQg;M!YS&fjsB9EH?w~S{47kJH<%SEUR;#LT%8`gJn=YiJw zKHm>vXQ0CVbrl`!fQbaD7ruf|I~72u}QN2)6+n+GL>xu<)XLnAWfe5up(FZvz(yXl4aGKBbE=(lad zWN%w*piF-=84c|54upuSME^dfVmHeFL#__fEK|GEPnO`FIryH}y7p#dseat08bO(7``HfQvjvyW3s- zhT5QQ-JmC;9l^K_`{bk@0iF=+g#_O^!kJp+>h#(NX~YZC*;k4f7RSh7qZgPfZ|K5<$Rf!!F&m8qznuNwtEI68`8aBU`3KH%m zStSn=W)RnFwp1!y&n0yA4hU~I5N$Me9zLcoTC}u#0s|=!9CC1dqxnYBmu*B zJ@$-Z{Fy6@86%Mjrb2w>U4OcP$0j8)6*IXhHIeX}f%n`#RY_)>e|F?{bWEv``6A8P zK@@X^5K(6gELd*;`5tBuOy(2j)xHBRGyWqFLKo6QW4Gbxh8TdlLG1qXeIE0)dXwa7 zgG2Q4{nr(k1%%FMM>Y#!NmJlL_=-x*aO%i}f5hHeN+Xa$53P_`zQo+9zrtB&XoM}^ z+wGFvXKkNB4$ZjayzTG%_u_)d(jUNiRO>N*V!=sA>%s6*XOQ{m4TuNXJ^K=r-`-y6 z;i&^V8CRHZBP^(SsM6N9M{PA!{bhCylrsGK=S0Va=-Dv_tJC;HYgwEHjyks}kRjxe z);mQELoEu7SPbQkrKbxR#8zJS8>k-p5N(LTx&mP~fD z5zGRv5D4%v=oM$=$C)1{>RMC50v?_msUbf7m&XgckP@*smh&M4`tWjN=(F=D8uunZ zzes5C_wz;-H>VtQsD3U(3B3W0h&!yI<$CZ$ttnC#Y49b*>mXP?DWX-;j!~-(`i$t- zE6j;-yqZbzDuS0&EaOz!zL3lD>Jb(`H+wZp3mtCxZ$c5Y9N(c}5FjhJyc|d3a$-kG zym*NETs`uFj^RSVDGas9d`f=b7B>!m#Ua&HXjHzTSSD}MWjvUj^L$so=$^5$VXKe5 zM4)mf0OPO3d>2t&u5*l;{|l5{M|~V-@Xf)>rT1sfn_JbZeuQ{=?bKgYS~fPLIaS1# z+Eww-WtY6Vgky)cNChJ=8vYsS+^eBJ^%eAd>I!e(j3M3D_~=(MMr(8M46W?p-DgJW zE&%^vb8MJPv?K@?gI$2wi7iEH6{~0<3p0+T`W>{gYn%nS+4Y~}ek7ftei9k@x}-*U zS1Gl!8|&TvvWoZ2y+|nb2R2jqa3m)^Q)KLyf~6?zHO9^tD#?{x=goZzDde?GjB( zi4IZ+>AFy&iz&My(vc-G3vano@gj$F%m0$5(GYNP8A@cjnz8*-$mr4rT6rhuC>9A5 zvi!2Y@!D64yV)z=!W!Ks+#mS=bmM7n=ng7;h*Q}?VMq!^DgOaIK*GPYM24dmbHoPr zi4z%OX|xjlYRteq4FV{hFe~#RW}SXboAmkw^a(@;C&38;gamjAl1egDx#c=c{Z3p* zxx8nMnX)@q)*irbyQ3BWL& zgV%0Le_|4a*!(Wa&Q*f7U6ijxqG2hkFus5Ssk(zCvJ$?lm5y4VMFMI#WfwnXgZ3bN zW=#XwoQG_U_Ox0G&SFCJ&Lnn(;dam6lS4SfZ}shP8ZCXl$ZmIcty`<*N`6>q%*&7B zI>3)7Z=WDeU=%j*lMui)q}~dCC%0g-Rgtstid#KQHx4(PUn^1CgxjuI6q{)UFrC&6G`i zsBAs#LsQEW>vOxgRlBa{_ujjS>iLUj{gj0B13=o%&N>eQ%j@G`Eh#F@(&Lfpnhc$y z6!W9cC2KOgL&Ahy1#{CAQW@ki_k8$dFvT4?J4EYA9~0reO7j?4;{m0 z8%fjjqiMA4IRP3mxfX-y!ttV;l840qptfymK)kF?lQk_j>%y*K!Ga0z=E}ff7DN%D z>SUK?kA?kSZ7NqAdAu76D{twOXWk1qj^(z)4Gj5NBU=8G z(vK`1Tzi3Zo?Jin6)>KvL{uSMclg6EYRg`_;gyg$PI}pYf%q!T#zH-MLfi&#^r6CQ zQellnDUbE>CRILg`Il}G6E1%==Uk!~2Kn>l{K-aN7*|?Wj~aMYQdz z2q;&HJLH)4?F3UDAH0bt%qaarncb_5_>y#OEUd8JFLoFHk4TEzke?)iZ^83sV=!lm zgb*@H0&h50{6^N7r>AT9n92tWqBEC9f1H-S3FMK3rWRiV41XdM9y+wEHdfr4hA;6BEX6uXaJY`x3 z-{_x<)HVt@Ci+g6RuOVPyDmzFrickghk;f*qfUecNzDi>}QOp0^ZEiEPg2$&YNf5QVCu2RO(pUiAB=aYt z-Cdoz_qVK-TTQi<;mXd0{F{IWu7#IVPCgcHW9`$p8dcpfOrEQXfbmjZcn0_?v2S#? zMzww+<(q}85+EpbmRO71|2_^reKe}TnQ&|hQX7-ru%p!r`@6xRxf)Ooc>g~Ova*te z#C@v1Iwr$z#gUl_sH1{&8sgQ&f0K8eYIiWWAhflwI--Q>@;Fxfx(t zqT!#*N@w&IsEk}nMK;T$hMSs0yXwGHUT;gHRwN~tWDrhdgF-GMNGCzI(^Bk_%CuCw z3pKY%4POdaPB#N&Qci&9B-eR8Rn|qhw>fC*0e%+ZP4dl6K94oVLl|bO!t6ClR#Dr@ zwtvu_cjf|sy}3VL13wZ4wO$qssxKSousRe&PZKfbvFsaMw&0*53RNFq#NcH+9lwVX zk;+ehtV#gYrfJ~yV5_<5Yc%K5%O*UHQ7<)wUPj3{{^X$Z@75j}1!qD34ik>;8%XMF)E)h)=L z>s}4sIkDF+c}{{q3d~g{)F_9)ybHkq%rX5%?=<;~>^k~PZ{G7R7T5~0!`gBxvNFui z2r4#Uu3yQlgC6Imyi6j#)F-y!aRXFn#|BvNmqh>h)~=)@JcT3~CMdW8>=e%KUlAW5?|hP?x!F$xgDXiLj4tFHW2||~6!#%-+9nCW z45krm(c(eQUHFP3$vf%Em@0*|I~F_7?sQrC(-7bdC;%e713yg2&eyKa>+_yuh`B&C z=I&A&;jOGEm0K;Ca@!e&h5Fy5tSgF&=GLN{@=U^_x)^zDBAjb(5g76N`CYUSz+R@7 zUHFDBbi^SsO*qnrwNTh#4i9MFq09>M?%y`1wUCt{BZ_5*=J~h=!!Tr&ik3tfjaX96 zMGOPxD;rJhN1RAVEj;V<=zXtdApDHI3%^0{k3=3NBwTv}`=i!5JPCsx#+0~>vvO(d zc1iW*BEFjxz-ba#29f$C@#xM9z9K0rcY?yrke@H9H4WsPaoP64q+cuTW(`(Yow@q9~H zdunaJSpwu3T!YwBzcdD=A8g98AaB7~WuBulMO`wM(04G&7P#l9dSdFIW0XNR2(_UT zjf429iN<&%X#Z@`yh<3)9(R1Dk%(&h@e6}v^;<&;)W0z1 zFM$z!LzW8NOVEQ^dXAN(XtuYZp#+=`2tg}H1iV#^3bpxzk2cX@f|(|OKwHgttL`lF z#6mdimk#lfe+X+swEU+WDyI$;lda5n;x8};#<_Mu>bvp#@(%qtT9&O|3usdJ*KGGIiNQP*rx~34t=OJ z!5c_~#5JHThu?YnY|zO-?(1e;niQk#N*iPOF+9)6lq^vU1yk3Cg)|VhS?Or`gRcRB zZc7XMFnIF(Z@)Zd9LG6S0Jl&>zl!Vd+kh2m#-&L+rMt|s%e&KIB@?fuI#k&f?P<}^ zSAduDUIXJki^Zjo_%-HlZX{voLfIe`-Embh9JDp*`P%-cUPqz-KTJOAL!VcJ;UNGo z6eBIl*QX&X`$u*vH>DW7TOu_x7k|Q;nyKW^wOv=G2L=E_H1Y9uN|g^x5w25*;ec1& zUw}WiSVifCOS|M(b>)v@)G1O?vGA>7L8_e&K$+Ygin|wu6^7%MwXV_^PW`|F;kYu% zN}uC2HJBqQDKpS^JfViA$#gLi^+*Tn}WRICliqwcyffN;9 zwpm;fS+-LsRcO_|VqS2v`T!y3e3d5QQjCJRW|78ht zGvK9>FK%6d5dUlkS4P2u=A(XBLeIWqmn+Q*Lpvse56lTJH=)YRN;=2AMsNTAUr1ps zUNfyy(mWc_Ru>dO9U$f@AId|e;sTzGaWdT`BPjHVbeo~#W8i94m-a~K$GRui|xHq*o0VPLdLo4lm`&ewjx`D2T9vmx1vCRwUlG8|}F){H=%Wnu}Ep4ju3G+@ba*(=bbbpAu0=Iah2}9Il8KDY6)Ngc4T+ zH}Uzt^nkKp!$W&>FRTS(wXybIHQ!fOWhQeK`pkQ$&6#Bp^<%VnIU# zdZum%!}t&AP7uI$h=&2=35{AX(8>M^o@dqgOM|}0>dP}+SEz3r-%vBnlC?>wVVJ&F zHV3h1C#%vBMKj50Bp-cToZ|B9Y`aRcMVb`I}es`pPf>G%ICnC;N(7-_bmpvx?38#8gqjEm@G6l>W@fq&kOlYR2~j)%=~ zZI7uSi%{>nQ%peANRhn9);8+9n5A_ciW#VMN-Sd(GPKb1c%oqFW+=9Ubtsb6`RVU2 zq8~{iG@~doT#M{b7z{{jCnqAkW;xP9(l+5kT~{BclD-Ca=}xX~W0bbTr0rZ)A56Ag z)uEb4hPDG!9JDAfu2+-<1prx!v%wxoUjAyVSX4{_q6&RC62VjGF~{sYj-HDCXyO6X zpHA_`h8Rtdosv|hUeMp8m-HV-D&sw_j(4Q`3H2AdWUeW(@FHxIm7NY>#>GuOPYlA>XRPqw~tQx08}&D_J9L?Nv% zKBBMF8L6`U%)M|xT~Y@^X`f+3(tc-KW%5E3a};vWrGK-BG#0zJS7#}J0KQM6)s3lO zzq6EmD|}i4=YcxuAc*=3ne1Gu(^N4S%Wi(Py8+S5m=Z~&j;L_l z(9$kg?yyS%l{h)~)VEfEfS}&}eR~1nclyaFS=_zKmCTOY#jJ03(QAI192f`6ZnTxjLV+CyU$14?svo(*4}S1b1oH z+t?3>0T}kX(LbPRD#_unAKA&1* z-HLh#U_q`!mmq1%LF95*(ux%*G*>wCuNwX=HW-?&7HSr@_grIyMa<}?Y{L%M`f^Ys&GtG>E)>ANEX)K zrnEl-Qma9#1!u2@0RRYSuDto-{$;)Vc0)Q+vY3VkWS_r3z5pslr?1~4m8~ar4+tJ<* z2v<9xat9sz>!4#Ic)c9C9zGGZ2~A2(o!`QYs@$&+4yjR0>5NUQdo`ZZnnR%i()wCN z%2G@n3D#7dMAI01Br8`CX~K3og4ph+eq7%C@Vv((s5KE?nn3ytR$z{+)J;cU?ZFK? z@N46578<4WhStos5?J*D>2^`rs=`GIFq_YQ! z`i&z69or@FWU*^eX1*mcXUF7W&#S7mn#M@Td&9@hNUchf9<(3a0Tq+%Fl>QdZPsM@ zkQ(#LqIL;QC<&M`4oagwVZ>me5dKkm+HzKN!RW552 zs^fF;eZ936`&+NR4#giK?IXH5R zqqhjTef5_tmU6)3QhsB1AlaLU;6GhHUPm~4CU+MOHS@TAiTsLM*A&(aS$l9FWu(TW zHHYs81lP1`1-ba!1V7_w@es|LL|9Ul07Dl1J-MnECFC7R>g{%ys~!qPT;na;bGp@i z;5hKy6pVw5-Z>#9<&it|jaoWe>kz^{itQIu`yeneu*AX728&5)nGozuD;M~Ew!SDSVv^~dbA%x4aK+ZJtVn& zl@^xDmm*j9#aTi}Wt`{HEc~f))SU>Dw_?v~$Lft-OC<3O+<5BY?@DxPUIKMVhlB!J z13FK9D~*yRA(3IcBxcI_jwEqfycNNH=qV$<@56AGb2L7IeJv{rb(zL#>{!mj*3hD~ zxu5)Ge9ujz-aAHEW`z*lb9{GX>bkROmF^q6j!Z1 zAR^j0XcG&d#fsjd_CM;nFZ4)Lk}`%Z8ou(GGygJgf)9DAlnUhqe&OrisqyE-^^SiT zLBGG?GALV(gp0PT!DDu1tC2)I<~`mQ-3B>h2Ch9=D$0?e*5k-@wgW-4L@Lupy*h$o zFQ;2}_b6KxQw3jGHC|l2963x*%h%Jy!VWj{^NfE7{mlY#(FvEL=tzW`M6??6ufEUi zBQ~8$e+O4CR}$C$)CzBohr(S>T`I6b?1~U9qqt4mCj)19S7a|{_LKL8DByq=A7M<{3FL5|0hTC;K-Uh=L?we#3oMjFY;=b(A;v10Mq zvIE-5Qzf@y`=bGSc)k?Z;=s=lHKM%2pdWr0)q=wkDkp~%RD?P*A#}zl&x7QO+bY`* zgh1@ZAag3PZHNtf&l2wnFGJh^aBVJc$BRwrbUt%vd z;^d}hL#n9(Vn4#JutBGlD{aBWNqM-zwA4YH0+7??)Twb?Gf&F^=gZk-QFwd4{nqSD z_fVaWLy|&4StD8TfX1HN8faeT`!t3M>;w1Y>4y!e^5Wo4st%YraY`#B7~y6x@xpX3 zYp`yb8{Tf!PKuM*;IIkun>Q?`sf1wKkqWp7q8vEB%)a$f#if>Ah`&k26Fbp$JTe*h zg^(j@BK04t@h`+I4MYVd;6(JkQrREzOb5(y=d=||7yObz zWD3wUpcEPU9%nSWV>54(BP}hp0_Jg-@4vDbwXsMEgI~7W$B2kd9BokiI+ZRMIw=&d zn$exT9Z=!PpZDIq*s<%?t{{0)BSd}W)>`}&co1xF`<%xv=Q(Qu_3YXmIp4ek+EIU4 zAA;HjIkw0sd>T?{_x3ZJ91t#zr^%<~a1ASbt(ah2o96HZ za<6)dVe!cSOx;?NE?p4R6>Hb2OOwJbKWV)zIp(RT1 z^^!Hi@rZN5J5RVai}U-W{vXXqmOM6`^R^Y+euzi*1*KQ$3ciS+bTv16O)`WW;&`lZ^!X>mf)zVbOS*B z-H0!|f|46n|hd`yNe*os6(NnOAf1%8cD{?fb_CW@{7XSy z-rBp}K=P^Gk;X8a8L|&p`ha`YLTRRrB1u~H$@(&VWg4Z}9a*%T^U`qFU9rUN8%EpP zN6K_k>3SS6quE19`<<$bfyhys9{^3#n3gunxUIe;vZPa-KGg1FZ^DDrn1$6Q8w7wY zBI`Ku55v`$R$OODqs7iw?CXu6xp?ansFj~7#c0-V)?&{5S^tk8PK6(fh6-_HiSyxI z9kVSvnLQpRCYTRoa&QIk z8I**>Wr*La2)YA)?Q%`^tME<$VJ|=b_}3$HtTX-BugPuGpw~e|+yoMwX1Vcmg1KN4 zRgBr_Da~ngNON>8VUbEfiWr?4DfRA7!Q0Gs z`xpB_wK^&v(nLhEk~5L8jAjAoe&CP`m?=%^I|+SM*~Lo*>^#$@Mll9RhGk>ZGK2~; zeHh!);QRz>?Aaw%>hM^7%tH3fWM8{GXCeY-H=$lZO-^UU46%b6{AQ37knxUyQ) zN_7du1?~s%CP^iWD(0F}fj(Qr*Ra=sW#O7jojIj#grMQBSd%F zt6|&%g);+1_EraDj(yTUyr!dGu0^9){T@!=o2RrF!FOG|2eF9RV-(DZT z{O{dO!(gehh_zq7zq@z8KDA4G9VjSo@-2EMF%%b!3dXNH)a&eE>QprBqA*LRsTAMv zR@7CsfZOJ8*TuT9tO{6s!?}-lkCAegme!Q6I=DC53rnO*mp_bJ3A1bphRkdOD>`x1 zx!Mvs@9p9(G$QKWbKj-iNps2q?itBWGhZwx0#<-ef_JDCJ(u%=YfLRMnX6 zpl#VR*&$|yY!VHKgYRJ2%C!Y=liT~;lrV!F6s+L>k;Xsq|5qTNsw%u7p+{tB=@WSy zAM!QXYl8hBEKE}{6P8!#&78m6avQA1g)s$rU!@O6wAhY~l^2BX2meWPm@7I@8kb~! zY+o)%czoNb4-8g`l?H4a@MB5f{`2WEPp}Yj4!h$`!Mnb(r0E&3QZnWXf{ky|B@~y( zwu5hCoOgK5tgmhII-q3DgjwLrD1V(eQ-hl&CQaVky#K0Qs8VML5c^J=LP+Q-K)yZ0 zK6~Gr22dlvNzvyZkA@eFzjRdhDuFQX@|#s-V=MNILT-9ZbP&5Hf%Hb&J#P-u)_or} zO!0%Vruf39XGxW^6!i`rMQVfBQVM$s&Vo0M(k7jHU?>IDGK7LT<|WAAy7Ym!g0rBc zdPx@%SCt!t1igMi8(zQ+Ut0) z@%skH%P^_f3)Yk7KWp99|KQg?ca~)1Wi00NA8EK^Uct~DR@YwP9C-}JM1fkszC^13 zZh=h2I%f)0r9+*kmnlPR+4ffKb}J7iW_cJ(cz{E2t^#=ufbFDG0;#fA+9;W%5RG1_ z64fa2&U&c$;lw8pXtZ1X(J(_@5gGi+*5~F+ej0xXGNUz8e7^5LFCM44iTyO9GTyaj z2q4|!LR&#Vlv!G*m~O~vab#|iyYM;pqjtuk=^6xp+_$;OZutqfI4B;zzU;_Nf0#QS zHZA?T83@zKh47{OK2t-q2L6j*aCwQh2Bhk{U=8?-hN z0ZPSseliS-1e@5&QiDHf20qEo{ZUMmGjkpk&-fGYjiCAA>`CM4d`k4W zy_)YBS|LopG_?GAT+jH4zek@f03wA22#3s*QdG=SjHciE8LU4R03)fstji@!nCzFW z5}d72+<3xI3`~`ANW551JXVl{GsB85avJ`%(Xcy?nxQ3HX5PSD0-Wgj3Ni2-o&bue z$|jR=Jf+2wT+?@UW&MSWpvm^PLBE^*7R#{9$^kA+;a`9Kr|r0ycfsS0PTUq4T|lN2 z1S155sybRi+Dj6D7gV|}#oi3N7Stzgdv{$6ttDZFe=14A<|MXQ{>tSlmkf@e=77f%FwV}1J18d9cBmlSF)s{}Cb#lRk7el74bm#9d_M4?VWo7_(up?de+J&G+Jv1z2tUnwKWPJMZm4~w57=r?#$QQ3Q6==L6?pD27WGC z3pzrs@Tk9rxO?9LCnl&FSvah=ys&n)m}IQcLOO_av#CAJaA{p3CfkJ+DzIgTpZ{;f zklZo5<7(&=>4USutFr6=rx_U-=SjcSOW}~V*Xs@kRrDw+=m(S&wvmlT=g=f=k_DOM4sz9edjcPum{#cO-QrPx6eh7|7J$ z1QG)s?&ni=v^EnT%>iCYkbs%#!DOo$L&4@mk&03PW>p7)KKFK`$p$NOPOx>Ti8x=mI+TO2ZkNMP?Z`&`Y62JErKl%p=`xcLg! zY>RqIQ$o5rm`B_Anl^A)SE4)S)GA0ODv4cel0x<=GwwU*HUr9nP(0@_2w<%@>9LC_ zbz5@S`)z#|Zy4FAGO?d7a~@9Su+F9PcRI6*mrj$Mw_It18+L~Z1d=m>stBh5Du>aa zDnL*x52NTLN+T*Y>DN)4m@D1=LNAq&uf*HVe0D zPla-kfn1GW0!GZb(tG!QSBc7b_$7QZ!!*e1v=l%zgj;>;fEVO3L#`}!nigEavibPf ztCvUX^WEb4PF!h`OdlgS9^Wrr1kOQTS(9uqo%V^)rWvZGGYopMMvURsolsS$jaGh*2p|H9* zX(*~o8qvc)ZJr786Y+uECOb|*25S^a4`03sD5VE>Knk5;hNGnq!otMNuUaeKi#eN_ zT78x4+mA{A2*RwUjGKBS7h-=}5qG zRASP^Eq;}VO8xnlXP%*m(k@B~_y$IC(i(d@3#3ajetLmmxSIm{$d`hWlj-jajLy{y zO(nLKDjV_&b@21$cAPX;@dg;~iCdg84I&@Hhvs!oaK#eS6<{rP8)+(Q+L`>AS)ZS( zFN5EKOVRy@BYv?v>6qypOuv;}_OhM1-@TO6F9}4tQY|ufz#%v_tr{YuOjM1G!7@Td znDK_fdsL!4t9T4OASXPf?DGYWknx+JzTwxX zrFE*TEz^q@tlBK4qRPzJV(1(=;i1cg5Qa3rnvWE)4tA0WxoZ^3%<4BhVtjo1CDn|* zZ|^-rW=^%;N_$r^w#C{K$tg}s*|SiW(fY9dII4@d;QQ*7AvR1KhBI6-^`+gkBgFI$ z2{{1TRtobR9JxqAF61fQ7Q%8? z0xuNmHfgUtNFJ#HS>>9^L0pz5(9JGl+^lB4<4cJB*|0y=pN37%COXo7GGbDp%!|vt zb^_+53^0BVi9|Vw!b=VUhGuWOtccz;FzL~eWWMR=V;Kc1^U{~B(w+c`t#Tu? zeNjr5xsR_;F-M$Qv{~HsRI*ZARW;>t){g0ar{N!V0PcMn2~cjR3@_t!k_%!I2XPHp z%s-y}wTqcsk+b}L6i#I_owW)8;LGJB8fWO(Nm@C0XU;PR6~hr__uBYgT@OF)Ss`m= zH1A_^LDJ_YenV}X#FO+2`HC$7zXcv#2gsrEQXHlsS&m4XUiLPfcf*8&xy`crK!4c* z@)y7_jeGG0eu5lI710_;)O^4acinHaFwN~es;twnoyoH{@B>f|eeY*n;#!mR5*HDPDpJ=u zH(G;o9Zj*Q-$#Np>R%SY0Ms36wJ?RaeRIqN$jDk+HN}Q)N38TPk>!}f6jDgbb8tH(VttW~5iLOY@EyEc@Fv!xu%5t4c}e{<>4^_{WPxIBxL z(dP`M;LA3MI95=xZE=+oE&%oG(N>aRi3~@NPCQX0K&iamVBWAC*jsJIW8c`aabQI? zQB|KM>)7QRfMt%4vFl)lk+rJbkelTK;dJ{2a@R8q)lee|1O8GbxRZ@N_N@UOthjabqK*U$uB$aA!CNUsj#)#iNx z`4w>uBR35}Ha<7xRXk#MCWn~qfn`N406jT6dDkmqEB20wlB+#2vYM@7VFYG*)A@9` z5PCE7waO9~W$1XzS&qpYPT2>rl6;*%U+IMSj;wFx>E6e1Nv0|FY`8|b0$=PIQ}ELd zRlq~e%RAuj33ZcNN$F)93Ke2U)7bH4tYNVN8$uQ{y3H(&th07LiN&E$Y`QMKGtO3lj0YJ0kgkB$#av>u@BbYlDEuImI||R2QoT#;maF50sk!) zznJ8Ho`EFW`*2S$@NJbZgd0Og!hzks%N^RGTDbLgq8b}5TtVCdFhbDPuC@ag;cmn)Y+MxG4_4_zwTH zHlN}d+=Jw`oN`n>)(~kmI?qkSRkPM5UBV1hyf$yh^^sVj;cWCWb_*0NmDDQzy|YKc ze(H>BFQlAc|b&)a{xSMGsuVm^dw6K${Kos`RjwZV%s zA*IMRX@D77hlq=Rns`Tbz-zGLwj$cZ+Y0iF)IXxF&^X~i%*0x=QR0ohOW1|jkuBGp zZmy!Gy?Cwlix(Up3G(1(nFdBm_jYOh&3gtpqZ<}eb%PD?bb3l<&9_OD{vy{dl`p@NTCg7RU_I(6$B-p_$Bi=%IyYF~!7mZjj~*}Ay? z3%d#61#5tx@qv*0$O7x%9;GFk;uS#iwp-UdR_;b<9g!&RG0Y-M?sndZUYdxDp zw<(}OJ6PPQ4V;}06i?$aG14M7ynJ^T#iQFvP3Poc0E~iW|LUmU;;!1z?mByz_CNqT z#Jnq~!SVfxI})>u>yYXTIrCV2P4=mp{Xe}B@`K6r)Jpf^0?XM0d@n7lx%LOEkWhnC z$asx?D5$y4{<-(rwig+Ogt$^N5~5pvcWh;WL>y2$B{gAU`X&4SsOIn0<)9%5Uq6{W zpxA}BSeUn8ZKZnk9jxaYLMr?cCs0cD`rCoY)SI0h!A~?S=uTk;_;weQC1!XWYT3CO z_XA(W(X6;YRwWdZnhIM{Za7W+cu2My+QWDXT#un@jT)#;E-9zmwasP#SpH^vdo+4I zg-dqD4deatilT+VvL9}21Hawj_cKKecc0}5G=rLsq?^*{(EDOxAaUBeO}r13` z*baI;f@mK)+Pv#ns~L0BcY#2Kvy{Pm*deX~ws+SH^UL;|0Y5jaQSMvN^sbwxWcYl* zQ)k9T&E4Q~;?_sn2io2r+$&;KN(w8TzlGfTC{<$N!X%(Ij!vRwp|i|_!Gn!JLWwsU zL@nI-iV<^bMksCh)M_>Sa&q6MSy-(ixY6umnIv~))Su@Z-p(UCa|Ivci<_%Conw4P z2r~-iXeqZiW6lv7@zWnk+R(1m!pyzbpF5^)dX;=Ft`eUZ8d#($jO$;D37iS1*_5~{ z*tV#!^Jx2PLRaHqmv#G_`6{UAU(tE$PJh8|PcBvWjS)T-VBBoB9R}buxQS+rc~1M475@Y9BR?$ECJazKomY<%xSwQ(UMBR= zanr`)zWyz6(I|hF-08bHSb)*qtC1Wxxaih$YJgK07`Oa2B-tH3FD{hO$i8r1IO4P$c{cb;Irz>A?SHG;m*4)j zoAt#g$v6>(mucE_sS$1hUeMc5Vz;HFuND9xXM(NUR&$m-myTJWUVR9b44{rPBN{vM zWSkHpm9-X@#UvAFdPKGrZyI?6V<#=7yNdaT#;cUGCtuU?Z9j|1$c*IE>!W~gq?WwO`58ABa8o%;Iwdx zmYv%uol>DpNwokxXB6%BFj9|MZw@ z(MZQ(krVL630e6u7?<15O*`hf^KdK(iiDu71c|&79&Z2tK`a32{eB*7%rLmK)iHIM zy;eR5(g)2XWbHP)>*`^q^N-gxQ%p!KpqO9Ymsxwl+I+Dl0>xUhizWabv(|<_C#%*zPr8WwZUo)~3 zo4`2pr!wKmsa^thCJ)@>T`^PgD&#%|i^L^rwYoJrDzZ zr*O+@(I(-dK$4;F%^JWPb9w80eijb`ZhGGhoD@E4mi_y)9n6gLveDi;V*Jvwi~F#;*$0RuiVi%}%T;#E z(UaMg?&4yN>p&l4KsJ7~S2bqO|m?dj%JHk;56*y1oMHb?ks(1o6%)0~J1i7jbr;7g9I3pvGQS+Jr>$ zf@M5jUU+Nm`uKKJ0k}8Md$+lZp3>$SSv`|XYHqPH0D83c?TwVEa0<}~I6RTR$R-~J zSfF6XR`8JV6Z_n-S0(JvKj9z9VqcskS zb?}oyYMR{wJqpH*0-x7H{VPoOt!%~Es+@<1Zti48Z~%Z*R(9cIM5zH!x`nv{~sYRl3Ph5goV)$%<2 zj(^>FJ?!j@{bqwVibDZs)^2eD3x51x`%AF{`hknaXx}RO@cr>$?kpBco2-rgB>n=R$_eGtZa7ND=Vg zEXAWWFm^qj1#dt@qcnCp|CwKI?epksKW1Jtw*ukxU8=SJ3*S9r!jf759>OPfeMd4* zA;8yuGy;k*uz=y~gnA(U<|)T#mj#zBHw0zOc|q&#_MEMU4_PnL^Q_6W9F`oSPv zj3rC-g$!pVyyGM$Jdkd6YEHn8oVZjfLy@W$o2Gzn{Wh;|?VhHm`mYrUy+cSYlLD21 zh@*j+?krB?m+Z-`K!QUSV*?e)1}Y3o)h7G;S({7#bcC^S3pm(j$#eKRJ4*dmE*OIx zss1)Ys`OD?Ev%5T9oBVCC`Q6Y?|i2HMG8v(l6L{0W{2I=#taIS1$%Lhcr2DNg6QXs z$3FO(17g#=(WJvt1P?1Gw;VkC@vcQb_wDyN5b*{Ru)jmG1-mNa}|*A><;&{+)Sj-cX;?b1NYvSAj(GY0p*@dH423 z_&08;a8m19ILI0t{`HWO1bX4?%qeogxst0du3l zh`+3%wSk$YfGK?dRCKx;rHEw&Dx=v|Z+kh`G1*RRfoD}h<#FpI4qM8G&w2MH&aAIi zm-teRl1}U;T!3HJ|EB2ow%dSmZE3m(AXg}2v@_}D+CbI4G>w-oR#im_d7o6ev0)qn z;kp)7Hd5fk90dFPa8oOsdMkl`AI*RlO^wY|XRfBS#qM^}5ai#e3`3S+4sY@hXD}lZ zmwdCg(U^V?th7SZHqVIZ0C^11xExk|)L5Ke-WVkrp9&ebN9BPGBF4csij0y#BysP5 zOy#9!hr7~hPQFTHLp8b9uM-y8>d;xu%`kEfVf0dFEIPx$b{Acg1q7N z>Oc}RW{1hpClN>{>Qn0y><`rL1t$QrmkXN&2|E|&t<4_i1XVD4dAVKyeva8;zXwA{yE!Fa#~ zh1I_Um`#hZ^1YgMhY8e2MOx68j?d%?*;hzI-*Qe`Lx+s4*<0o36ol>0wzz0ig!^g{ z=;m%s)XF{j6D44}rABUCfVDyqMjSEV000931%(5-^Hd?>0B>L!5!_l^U5z-=dBXZv zQ3qVFQ2R3Y2^Dq2^fsIwmFW&c1*ZF(P#I z;^?ALKu|J~NfXvkM>Ff-@T*|nhS}5qi?9^E zX8;58_LBlq%&ycE0x(AIio)_7u0xp9*u3Gw|9ve-j`ci>+*^*SH+l&mPn?YfoO}QP z8=oQnd`JKDAOU@k^$E<1h7`ZEj!7=E-IJM;&5|^7FrZXYDDb_MoGgp1n+t#lFe_Nd z8))TS+rU*4!ci#IC&y;0(WbG(Eplbo^W-r>?x zml9{HXW`+TneL=G%gyb4kOrXjw^Me#xp*BsZp7G1cH4u+rE(@u*~>GBK6 zTD_5wiS^>=P0$+km2PL1nB|j|w8-}T(&nS!>LD@gNEO{rQr_yMrqo_)Q^=0ztx$~5 za1H2*!J2<$+Q*8w@V_?;2o61iDp^&0iwaKS31Np~F=Sl}wBQ&exNB8kg*!A)p2{_a z5<LLm@la@jy0^copXV<7GXKA<@M!XZ1dMX-8h8t@kQpgXbnKM z0{%ET8~e@-kWXN!5}TkIt% zx~RD@eN11a4RiGEWh&+Vo|~c6=0$9j_a;X0QDj99{25FMv1qfjT>EoXY>`mzZ?F}t zzH$ltZEp??@!+5FpZp6-klB&m?`Ikm!n7FBWJpM>uDT5_*+l`PC*AUUjgcooqH^}3 zm*q{e;72(_8^RPmyh_X=N-pz3cS&4&Jwwo6H?3n<@>r4lbFmMCv3lIN3jh#f?pb|@ z=S`>|o-UApWEQ=zuplI9;`IgCc4h1LMPnn}^oThHIez0{Rt-;QnnA<&p_X(ll+OCy zEJ)_+OlTt%akf$W%y;>3L}GVtrL#(8*CZ5Z(`e(Cbumxaw9<7S?x!T=_VVQhhBQOI z#c6s}dh1ws>0!6bvJ!hZk)v-08}Hd=nHqqJ{PIPMN}a?zy=S82=dgx>ux|CYd{E5})ePB%hgy6e(m2z3w?C&wghnTJXM00-)PdnnwL0>uoMz5Amm^t`Os zA!X{`ATHM^pVyky`c%zlj?+C}D`YBT~8KJ+`)-r{I>wa0UF_r*ygaHCpH>C^p zGPdd$8f{;MIl@e*{K^~|?;EVrxZm!V;78i$3ZN*F43>M zMlp`EtCwLB?tVZVW8rkLO#p=1`Rky#{F19eJjo zNyrvDIJ}}@$QI-Ik>>8ND@M^c;jAxJVl9Ey?FT7X=QOcJLg*7r?ZTRcYEZ~~DH z2>D{>8i^!RXwkm#)cOfiZx>a784Q1nSz%R*M(HsY%F9+BoE?toIap*RPx%_72diKG zs8o-{Tr<;jLYFc=a};V8#6})|Zo=~u*+UUt_kCi(LBhm1my|nFpVe~V2CDCGoYi6(QD-dsTN++d z?Au0?n@jQzl-wY@@jPe_b7U}jz&h|z34Q|GVbU zU031MeU7^p$uPA72KNG>>k`C*JXH-D%ht(dk@V}P>o5AOc+E;K#F3u0*A9Q1>1J=V zJ?n;8|Ix)`iPO=R3=UA_#pJxd{)^0+}{ptF?lP&J#!R)Tr5O=+d!{<7Ptmzgzp7#I%SG%#4$P_gy=bIIUu+Y~X;L zPuj)7Z*7@Cy!br?F3^>i;d8%{MHaY{Y#e~!gI3@KX;uWN%;fka(>iau=8YK?pUMz& z4DKQzAcjz1A^LC_Q** zL^$l*7u98>HZJ^*%&3TDN^m;O9m{35doLbGKhD}UMPoNX7L_|I1}1%4L0bx5YNcIl zfymRgvVRRQdoEXC?ovpoW^j=XjahI_Bq~NPk%J#RNLyTsqb8P0RI+;K7q7~-+o8Wt zSqvdvVOQrRkSKxx`(@{xCmr~EM9xAX^y`_`1Bs z8iAs=)6E0y%UGG7z=nvkH|WZ9E}+9#I#7_4G!$N- z)yN33zA(Ab6GRHK)iGT6KK{*zbNul?Km0Kxo`cAejO7CB*NSwA$7HGhJLGd^C@KFk zAj~~^wHM>26vEdb49EXFrKBYCUK%z+t)Yl=2zi`~%dt`CA4z(EB^%H4>9UB869j-277?fK~m2$=`0bF7%ALL_M`E0c-jlWg%|sP z5l=5L_^yU@2V=7DqaA^T!jcsG;HnHej2 z)7fb^P-@L?sv3Fb`}_vuYZ5~i8H3(PY$Xt1<;O}67G|My>+|McJQvb0dl3hiYyHNH zV5No4nO&V+$mkFFHbLoFW6}kQDpZ)JBV`}KofH=KtS69a^3f`1K%bZArRqMc28`lo zg_JI6atT-)aR)j4&-1rNIGO`&^2;dTc(u4Qn2DgNj1|yPKa3c@Js4P|)@|b1j>@Tx z2_pTZ$`DzVLxJ%tr8irx1L{MM6oS)9@zbLoqae`~jb@_q#-e$eKryZ1Id3*2vF+n+;id z6QR9#OL!oGc@vRjO1Mn=Sx|PxR5fz=4X#sTXto+5d^nWZqP1d9e1dvZWyy?$j=wCC z)iTA!n~06{_VzVl6a%wKduA~X_jMGdRGE$?= zH=Clf>39NR(Bxu9S*wByp#-_}_l{7b3(ZU}@M0>v=1lhumJf+ncqu3vYLbi8t%(M> zp=H;?yo)o@k?f$t!+kD|;HdnD&^A4QjABrF%NLkl04A;um_to=W({k$hiTXfB9*SD?(d*}*4N?Lzar?JY zvN?NX*+yw6eRJBX;y3f>W>r}RZ(m_J&vBIJZ*)5@v{FJPzSp5MgP~+6s|azo()ek{BXD!IjwLJ2^j}gmcFBr&-Jlx%rZSISlw^= za&~J*MS^u@6g}>%zGA{m;NXC@=?+0<7SvPSq|TQXp$wZuOrF^djqn(ILhIGCPzL~v zBIep9@tM)(f;N}$@S0BO{@I7YLZK2cM*5L=Ldx_QKtK zw=SW{rl>KnA*s+Zkp8+%oRKRTYh-e@O{q7zVVXYyHtGnntq%T2QzxFJTj`gcqq5WW zv2~rbTKFawSby#f(am6qS$o*@VBOX&FBNi7nKyl5Sy%6RIjw+@1)1&*GBO=zC+F%t z4l~Yb<=;Sv!h{49HfH32($raE3RzMDWn}AX%!}bMHg!UyREVk^8~#q|s$Z*=>g?@Cx%@nDNuyaAnzm=^^F zi-}8u^;YaL5ybhz8|Tf?hago$Z`bBP%Fsu)Qy5KiG$h@cp_rLIQHmxgPvK&9tiJnawr=M zPf)uWmo!OAL*%X67aJ2}Nkq4g*C}23>2hmM!&nnc!$0zvG$pA?a2@iuB4;&}7jf!r zv*&*fqrXtt5Jx@d_$+ueXkku*Ksj*QYCNSXRO~T!G+VeYtiVKl@#VXfWhK3QscBmw z*dN6&%%~=J(@zNb>QB3IQsX8QgjBACZ?D@_%A900_hHsBh>F;Wk5lSZM*K3z7+qN~ ziP%!<8SLX!z-7Tydp#W(o|my3FcYiKlVxX_(DJ`0{u(GCD%8>mY(lkhZ=aD`PO%Uh z&A}7X)7zy#7~rKE^{zNbjAxdw&f43S<0Zi>9U6>lVrzK2$PcRxRPBG03W+J-MFV+C z(+NUtB(}?<3kNtE)I(gZnd}(i*BVx-NLx`ZCFCx@3OX`{C3XPTUFxSqsN2+J8I7cw z?PTooETU}wB!EiAR_3QrL>qxMMKvvY#~aP*>TmZ4;9{&EK&ohU!hCMj8ym8QWJFNp z#;hh>1(B(-`6|{>(F5~p>MW-7qb{I%mkUBVlks>(ehmpsfFfT+##EbOhubn%vcPn6 ze6)teK&uSt&_2z5cRokHs|FE{wrp$87%_mTOgDmH!lZUF7jGWXe#Cc#42NK8J{vxA zQ;cAwJ9a9#+MPvB2h~s8#BoocfM?=#rwMafIoIy+&LI?oE)%!d#G9Ve-7SU#q_OVu zLk5eoN>X$}LG`a_4lhl!G;IK|gwvy$o!>O{Ze0oMh;2CnAy^&od?&fibsa{nwE3_> zzFQH|0s~do5v>&Ril@bm?#POl@j9gz5jql@^xj(5 zf`4@#EjMpae2uIB=nw4;@H_~vm-vF;l&gUzg(t;Kbfs)vfmLh)9CoddRm}r&UdHct z;4eKJ?na*12yTpsi7Db#?tXfjaTeEq7kovuIvTLz!r;#gRlcPXY!n;*ozcB>iR%tL~&8{@3{E*&;caE za}78TKeUzwL|CLoZ&CpZu|NuvBvPx-Fzsi5I$^6~`K0x-?}bzLG3H{z#kCO&SBGqp zmD+jDt8HgWu~w7wAD$o|GTJV|>ab-jB1LWg^Ta6MrH0TTS?s5Qk*BsIub+G-W2_E= zSJu3%nL&aO8$6ee1rC2>TD()|6O@obAb>J#VWm|MalT*P-^}FeR7s%~6!sonl4`5n zW)%R`=nZ&Tl?AtVB1^yrX_gIktSUEf-CaIHEt1Wf3>e}56Zi2tw33qS%0hiJ)a)u5 z=ws4@dl_f?4b!fECVq@P43J-)BesL)YMqb=wlHt#uYDv9pk>pWu1@*b1$`XzlWM|L z1aD4c=Fkpfz;@FIN^uab5y9HW_KINdmV{tE!aA%>mxj1#n_Jv`tV`G?sU(rAIq65 z#`@$!ccxl^pfDTYJg%BncIgOgls@g$OMTTAOSP=0?CHFmTg-J^oK^zqUfDr4)BHwr zzn&@}zmZ{g=6v$C1Ofgr;4l>&Vu%`y_gsfR@EKZcVz`RC38qiZw)(mCPel>;;DQ6+ z6YjHe)apJmKA`;Sd%@-FZzG9eOF zpc}}D#WX$WDBw^oK?qQZ){nRT=L?IRkiFL<7<}X>#g|j4mdJBz%=pJAyeL;6Mftoe z&=;bVriPHI4`&py|)_xg!?(Z_*~zh=}u7aymqhKHEy zCM&F}9|JTNHR(VLFc~{4YvW0R(IyIU%DQPBeE^}QObS>evF>$)MJ)j^qKvJY$hfIz zZ;mn>E{o&z%nHEh22q-Fl%SC`CYrY{EWs`23}c2sxrOZ>d3CV%dB2)759d_6Y|2In zFh~>@6+LTSE4Kk#R#0$YJyXv@MOTz@gvX{8GIE(b#E%$LPL^x|`|;VP(O!_>!1gVjapzZ*G< zO>Doy1rV32gjWYJl+>!ZQCdMIbIbnq$*yQ?SUHlxT=D+wWE1K7#Z+wa+&7ZYc9(Lx zY5cp?)g1B5I$+4m55`Fx#_cUQhK#||V9PmIGZo+~!Cg|a)&ins4KE194+8y<)2~CG zcWR*Fn`hT%-dOW0&0N4TOq!A6nhu&i`yPaH1k~@o?APWOYI!5oo)3hnW5dS!8C`>a zH8ql&oU{lURQCgm@Df7@8Br-%@RxWLMmD9C`qCbv-ri-8T-v5aWD=G&8^f!u{IiQh zsRhw;9^=L7dk!Kv%XY)R8Bf%+GnK#}-sY~|-YNI3AQ{d4O+)Dw_eFKrUqN!YszFwA zwv6w=GgXJoS2z2`>t=>#w>6xH%z}|NWoE2>RhUogf9 zkR31Or<}UOJBR&9NK7oTR1<}SDJ#=oN&fphmjJlmA{3XToX)Y6b-xoFJV}~hfS5`0 z75>8p8O;p;Qn8m{CJ8D;xV0Q$e+9)M^2sMsiGV4XSdEr*#Jrdp0cQJ}2b6uN;sNYh zr46hAWziw)B=&YQksBLDw}5&(g%xy!SsgHcFX+{%(+~`nb#?Q`jmd@PjqUs2CgMDi zF;cPx?L&JZmE}ITkh`0t_13>$d_?5W>P6>0u~V!P@UdHIlN&h~;bQFF>A>ZRkdU5eW|& zt>y3HNdm=>UWpFK4nUAs@!O{MXh8^!vQzTIK*BO>F~@1)ar`Kw*htan3|G1T^ZWpX z9GzrVs7{!>3%=D8Xgb};(mxdK_Og;kYT0K+VcM>poy)*_!JQ)(AfjmIT7}!a?i-r` z{-$WDq8S(r?WQNjI#mLe#Dkba<*-({(ULxf%X4#&PyLPL+cjO$qbsZ1`+_7#j&5w3 zfW;;cXY)uD0+wLTY{w7tME_ekRcX!1L9UDPTz!w z4aOb}KR}eQ)pD2o?9!JGJbo#HL~8EkiI$x%f*=R&w>w66sQI=cQ5oPjmjeBpZofqs zvUec%tyf~`dgNJ1%j7fCnWdD0IM&KC0apiE`TjTa?%O%Ym$zq3){tEr)!Oo;EHB(r z=7NZfw6*c@0!U{w0IiFXqnaGR_;|Ju+hv>+8acYB>~-k2Q0o5_AyS|v zCkNJq#_3(V1SzW-k*W|iI-Wm0W#4S1-m8rApO<~apMPbVo*8|jcVI~pSmYxjr8`s6 zfDQ$&K<1Ds=j(k)h_-rKywB}(;g`1rpmzQL~rub1TF7Kj)9OcHTbh>QL^` zpVSWrhDrlxSQp66%xC}m{ZTpfj)R$iS<5CvrTXbVRHG}sx78zNMikk0X)ro?Bhlzw z!8LhBk?-ioHZ38Iq1^*R$4yiM4D6hokWW+f)&k$7a?=N3LQ0PxG*jc9_0Qo4%}srj zQTd0{;6wA?#`3;6DP@vGQde@d%I8*2wV%RS+_PH8$gP6gQiXLhQJlUJui1FZ!r^^y zKmY)YH6h@DLO=Rg0Gu7rLeL{RlrT)>BDFxhNJ`j~w zACcK;ZCMQXY<67S5(`GY)_F7w*@Ln&q&PE7E8J)=Zm%m1?MTpy@5M+Q8jtD-QV%sB zg12@+fuZ05&2qGFe3^G#OM%4P4gccw$REb&NDPO~jdl}peBT;MtRMJKA&L+-I81A7 zQv<~kIs)4OY0tzLhzS8tVN7fZ2d(x9CuwCp_eGl$Id>DU6ZtYw-*)YWiadNZXm#_a zDVS?r&-BrYt^+9l#|JO`s)gdOKnw1bgg)k+R1klS8O}h&oo~UPf20M7JW~mV(t^C_+-Z|X1{U27i&h=NTF)Gb$RaE;+S#aY4l_wE`p*CH<_$wo z)w+ybR9-a#d3vAJUxZy{zN?Q*XDf4%vGoVOUJ2yIGIpAH_rfgWt5*M+-_+jcaYpQS z#5n=^b2_O2`LtdASkIlR>tQ?BX=jt~6XRcMpep)_d9ryM@AVtGwOQ5Q(vH73v7wJi z7Ire1>m{H>$=T0|`c#tgl0IES6`J>ZEZ|cYz45g%`Ba877CKfDo!0EHU%r>ex?%^1}i1SMFi*rYZkv|O-L!r!cE?0?0OrW5GDJYmiH(>sM zWvkfyw{&eavR~4~vLk^boZMcv>9K5mMo=bnXPVrn1&h@@4=3$3uuV+iSkQp!rfn1| z;`Lk6IF@8&OK3O6R`XYlhuv%zzKJVQJs(ZNlkSC6;wNBauPj;Ryb056^u*<=1;d3LN=^!t03tWn=Kacdc$=L zT~jj%;aFY^6~*GcfF|~_hX*VVNU0tix5?yBzm6*h9oWZcebL1`e+1!UU#jwVyHNPr zl#y7=gUhsljp9D~%eXyUw zzf!ek$Nns|R1_RTp=E*COvJQwN!!x$k`>NYcJqDM=k;?4=f%*&timXD-G9EOC2f$!&>m z7N&@Wg4wr%74=4mG?s!4`+#F-z0LG+Kr z^i>Hs5-oShOx1ETTjkdN$SS7kfgXI`=aCO_Ow7XH(~T(UQ7Z^+jMqK)Q74DsToO-qWf+5nFqrLo5D5G3@OqheH%_VornJ~Jvq z&?bPHNIx14)WhjjqIDWh*_Vc9eqHD^{M&pDFNNC<}5uf4XT}6rv`Xm@+W}qOAE8|m(CotT$0r* zF29M??HL=^`V_k8*frj63*n@h%2&Kiy2nKHY-iLk$cq&Wy&mWKm<0wbLr+GTd-HZj z^rocwhb@~uz)L`*oMN&gSm;Qq60LjnE)pnZjWdlIh{cRSYZv1l$e z4iq5evE}9Y%{dj-sBcz7N^7@L&C-AX0+TKeD-hJHUUdEQ>%r$v9D-&y1~Ar|#Do#0 zJ&q#P!{BEI2jubZn|XE0(7oP)#5_yl7`keI54bEX+3{FcGp<52_rX*g@e9Jc2ex-_ zl``~5OK{6;2c6IDO@)K>Y#;U7of`~g}h|S^e`b%)JT>|#T zpKuP9DX(^mH4^H~S4-jRgy`T|H_6XMIGtNcX+W+B9{W=Ln5*(b3HMC*?AHgTmF0vR zE+rlt*8TQ@`Ah0gQ?nB~k8Qdwc-C(Z$DeWcs0ejO-di=qr=P#Tq}J7?^khDSmAWh4<8&?VHdb8ztKEh2`n)4mj=f{Pe}_A%c5G$_uGkw98#tU z^sB)LqrkPtNoT&@lb7YLlM30tYx^o1HAi~^r`5&acp%VAqEI)R%Kg)=j$_Gls8y>d>dveatnmqhZ z86J$;T%?>oBeAghCO035m14dG5=XzkP}8Un16*SO?Q0#u@QscEisgMq%Ivqx`@dPq zEu`A^B@i*uyJc?W$mARly1#r4VIDB)F-YzLyT}@+z?OR_QIjE0VM$y(^%(Ry zuZVo;0vJq~Oq@T5qZ-&?@H(_y$4QdzV{%4c6iW9&xE*-YEr-TXEFDM(n|PtRDb^mY zE7-VG%@4bgvu!93F3oT|{N?=jMcqaBE_%AbCkC7uL*7Qx>N7T;qbqssX$!-7c?KN2 zErGdYVAwS+Dku!Ha@Ppr<&pL7_#ASv0SH&6zOa!-GequAb=HTYx#?wZML4VEQR`(| z9BECHG8;yGBc@bcc_F2%D%pKOSHMycQ|& z&;-9+%lsCUJqz`%8GxVJzh=svJgd)2H9iekc%i(;kHAAVzVF#!Vzor#Jzp(qdVpm zA&c3V(_#=x64X@6cX4p_hIP!X;`VN?;D4X{|DTZmIeA&V%oM(ZH4=YUOfvrMJKk6L zSlqe5Byf&#MW(3NZN%S8UU6ZFFGk%_ejH@_bI$1Do35s(_Di4!6QwHyqt&&@o0J!` z)uRmT;(j+lzecj}mgzhsB4B8`(TklbeSPU^yP4(Z{+wXw5)L@v1Si(iUhe@quWUW0 z4vsLnffHOgcRh}A=SM~a@_Z9ry|tsZIr1oZ3sa7o&F!_= z2gC(k^#euM)g?!13)C*rO|fDd*$?km%QmA0Z2s4o4J+1>^Js%`q++%zPVc7KmAjXE zBa5xz-sx;7Nydn!XTv+!VmGCyQN|}L3kTy+SlJVATck_FF0POT?~wnD<;8_Uw7pCK zca#GT&f@Aw$9(zb>20N-NdOSaa8!N;>*svdH>AONU`V-+=$crn_~|;lqF@gwEC#ZS z8t9Oq0IrtNa-Sa+Igh}7o3B{swj<=pLCQBNskq5wa>O7C@|d!U#IeLP$0xZ1x2YI7 zk>9`jBaU^52zVF8WLs9GUygxO`Q<_xvbPm7gk-KnE#De@i`LBLR?BvCrXdFsMVaHn zrS+9>rj6ViBlW1zD8t z)r?E`cAq7Lc#=RbU(|E)U0dnXrR*yi@=aK;YOn3|V zM|L&Qq%n=)aq7y^(Xh9*?%`12n`0IZhz3E=82Nc;0FZJZf{F_1${!@FfBNX^+@YRV ze14F3ZP%AEX&%DGbYJ5x+HOdbJp72)^x+UcmRsAdvRESsZzC><4fvi{kA` zWoHFos$|jmaC=D>H;ib^!75#4GCb{gX+KX^y3MsdJMuM~T#T7Cy4Q`8a8bS#@NU7MgVYG*z@F8$MA?j!do6Rajy5kHd*=rR$l6X!Ti_T!%qbeAM07W z0Hg5J$W=c1Sl+~WR^El<(%dNM{hsZ}11gEE+}v2B8}{q0f22}-BNnuh;rnfMh=9El zr#6w9WrMt=xt$8ly>S%ihHJUicfdKuYW#bTEeY$-L7eN$5evMH{I>aG2_UpSr(cDHbCq8lic*yunmy@OoXo^g{h-uvu0!?^XC-^ANEs11Wg1^ zr-5jw)k_?nD8PBofiK;FeOlDU4Eew^T~bwQmTb_IH2qKID)GAU2QP2myRVe@^0c;Nk=u`0@9C2Z!7hx0Wo94x)DDUJo&# z0Co{S{=oijl{1eCs$I4aKYJk20PClcZs1<_#5SDN@vBj8gP*8D97cj{VEC8Qcu8LO z*|_aUI?;)_L)iU1+THK&WnIg~FTPXz2u?8q!Y<-S4jCD2H!-Ovzc3eZ67>X#Sc0&=nJxmp!ZwvO4Jn0c(jhWY4X)i1?sn%4v)*~`04f-k^rURPuym- ze+u~6j|JcADi&^k2U*^w=-*NMk(XZwlzogL3Vtt~*WP&?jI5qYx&w9^O5ik>>3iTwAiv+R?m7l*l)OM$+&X)U z=$VEJZ;{OkrQN?b4C=eb-xtVClC^;D z&Ts!`$87HnkYFh@y|n+SAa?_1^EL{f-YaU5V`f2WR3fP`D6I_rCO4mg!Gm`J=b3WR505G4FrYH`*1F zuz&$zi34Ofh){Wy9g4gq+C~*@bXfdkxOhQ*sjELKN`1O;T7IPmVpqagi64Nzs``rg zy9lJ83IW_HsYtyQbGfMRTLrP%5dh07~ZW@GbM8qW3AdI-;*qk#z|eicK( zR%xNA6n1RXb(jkdzSRZ_mWz%3)+M`55rl^=RkO5~60@z-GC~AT?I3B4aNa?4x<*x} z3$fTibew*CCYA=RT3XGuD&wd3(OB~`3vrTCh%RC@m zu$T@eQ*@nll`rP+LJT6Ve~fsS!@EBIe;-M~4qsQoi%~p*$&x;az4V--$Ytp(j)^Oq z5yB)E_cTvgZ^hXUL7Y^27ffV zyMh?*G@UGc@U|Te_qR)2N*4r7z-7Dhd5u1ftE0R6b~i`mWA^7+qSEf+1ZYsD_;Bj3 za3n0(?Oijq(Igcj`M5x`(%8B2!xKk+fgNe@yw0l(-)tAB!X=D~2(YK>ZqTPI%vm9g zb!KbJ=O5x_ARxgpaF|@y{_uqRyW-TJiQHh?^zCflJ}B=&3?!P0O<8iLQ&`z|v<26L zy(x-7276W1tSm!#yp{eAct4opJjWlrVbw-I7$a^0Z7R!Dr}X4Zr< zHfPz@5y;%vuq_v>2s1{O_{lSn2O=~<2>&{tDL=L&13WuEleX7U(h*lrfd=>Hs@Ftp z$mG8Oi$L8oSiwAmL@F*V4F&__4t+LQvg7}hS! z$~iIO+EP*1JwEW4B}yT^N+2w8>LJ9SQBe!t9Kp}>NlHcGQpU9CaEm;^BycTL?c61s#57`jcQnC= zVa)mi0URD{q|qSGyp05hH6}8;)9li|gGpgWKM*i2zRk@PVL!)isl(Db1D>rmQgl;+ zNxvi)PV8V*LvIU^FADor8>=)%KiX_S^aM%^BWaE~G zcKx=cAIyCxz8xEeI6A=snLGT&uLAXD{lb5?hLshBYLd}JOY>*V1TC)lD2jd9LT0BRL( z$NRbc-kOAtiCHNp3spjrlLS-=r<^zM*<;r2{J$AHpiyk4E}!C4k7wv_-3DK2B`8%` zJqXpF%0u=?1(>hMFfy`zA&SlmQ*ao0mYmri?W?c7^IsBP@BxnCwNGnl}= z5}jpUSE=16hfG=XiMqugQ)!l;hS-~+W?iV5{pZqCM*;UmI@2s46yBIJstH)gi!XZm z2=zS?STk51P6pf1-yX%*+V9rSF4b;Oi{TR_Vo33YgET@08*%=_@^)xyJ8$l%7a9q2BsM#12&#@}&5@!V$ zV82oG7DjQtG2uN}0VT{u>v?IksM-e-!2wk3~)bwAqqWNueCVo@q231F0}9a-?>QoH+6 zsk{wy@zeFRq{qNybiZO*PhdNtU~^gI=EPwBzd2zJ+`nK{Itpa)bZq&_8!mHT)C(Zv zDN^yGX=YxUJH3v*h}(q981`8&yKjrFeH?%a?$svvWIK@up^AabUHRVHv) zds8b~rP&!58_f3EI532MUapU$RNE8(NzWTuc0IEukd0_R0!rXSS~UT3rgStyu*UYh zl#wOi9#tZ@rO6l^m?{}wlBx0PwTUok){1!Ac=V__nS8L9o>Q#ls*%y@hw%X^`R@qw zWFi>BgG>isVL!}VYbQL=?#D!+X=3JZ=GGK3V7P$tyD&|z(~J7U|32ej_3M=Lsu;^} z$fLwRiL31#D*(Zs!Lcd;_yf`2Re!A)WMd3+&v6zN64Ngl_K+z9vCl5)5v>q-dVDP6jcT->=)j z>={~H)y|c(45qV}(Nn?1V0$HEpDp1r&qXnm0G7~Z6rv}zWu$^uwQG{%OJYkF+dX5H z2}D&)^b=l8$B`h6{l;Z?ntbA0i3!{4WSU!2I!48wRTls^J&L`)$4n0TnAjCjMB+R4 z80xhR8%H8}&fwT0+Qteduwde3OK{p9ng>s~l)VDgvhZ}*bJuV3aLM`(Lbyns45KRq z#>N~VPDrnYuYT%RYWEo=v;`RY$xMKpt?2rj9hs$Mi_B7rBAF+-)n$>74cL^ zKwYVpu}gl-M2{8iCPu&SLzX~=!UEVLYJ;zV!qPycLUeILH8R56#D{AzcWB*_DDOFe zOHx>l0}FsWVW%w53~J;Ph0lUPISi#0&YX}%fAHPY zDVZ-OK|NunEHt8xbEeLtM)USx-R*O;S9D^<4DJu34GMc+>^ar}%}@Y2iB0wx{`mad z_TK}K^oJO^)MKT`A1l-qekx~iQ$L@0^$(p^0y7Sv7%uOk;oZFH?RCmQC zwx`0n#`BVil;rnO9GE_!2sMT+e0}@q0rT)EEDA6k=EmT^>|IJS6zR@;)nZ_Si{}ld z{cpyV6Ya=pBo3|RGm>CI#f_7Y=0Dci8XBT3uEpL^=ldQ&3h?c2<=gc#sKT*_a=9@d z1h|Htf>L7r_}r0x#*?%Fy-dEVahiSN7&Lu1v~ufxt*HpU<$MQR=TMhsJskJ=?;-l} zX4#PegpXR=Hn;ELV%heQhup|G%V_@Lazos?T6jZs0CATxozDT5DqFDd#q1*cfN4Nj z%aURF3!A|!DuK!KEfhSA6;FEf#qp+4+Ta&+QP-?VI$wrZMLND#Q5YyjjKoKhn~f1u z^EuTVItrN+Z93C$m4gLUN5DhxJs>Ngxb$5ZOw(N#Dh_)WqkLt98v=!6(myZ|Jg&H~ zpE{8vhzWTXao5?VIg-yDz|zH-9JFuKINWYJ(GCB!HQ2ANiz4z2<8IVkEoXrA5zh!!xL4@RRU?N*%Rf}FeVA190+SLZ|{JMFyC@q z?(9`XG~za0-&p0!!kzfspVl#%{BNZ*W)Zi^@m%`T_B*oc=Um*LToSgAUIYd1z~atZ!=?^W*z0mfp2@QyH|@ulKHlG zWH&W0*5sHr+k5tr!D5WpFoiFhEwh!f8L=q<$AtaOiN|eXj8qZV2vQPgzi2P9|{at^BL9U0L=Pw7<@l)*Pn4`l)!hKKMXSn>Ij{Gfj+ z+zUJT9$Wl-P(s2f1uZw;-8YI(&bJc0DKA1uwuTBlNbP%<277m!Km+Ckvv_v;XYU?7 ze})=WV1PsPAGL&WZ1Bb%ST4R}n}86I*q$J)it4IdEwn|!K%n%(B|^m0>shpmKVnd1 zZ)4GXox@w;CfjNP(G+b@7d| zKS7U?2eINi#xN*Vau^xK>$K+!z;(wSx=j`Wwz?_!cU<5riJ)J+%k|Yuu6t0te}$gx zZZWs=a9VcA+@IMvpX*VEEAth+?JO(13$DdLF zW%?B%yo~&-!;!K4fz--1O#G|^#tVj!wd!<5RvB~4s6Hzox)l5F0HtJuAx)(wQh=+IqY|eoz);Id8H2L@*EmytHmOtSi3g|3-=EeoDK#eIA zy~;^dZvDp%CJAcjOe3AQJQ0WrfT%kVG0r_S0)U#dv1dGfh+u*cvj@dl zFDh|*TkX%eX%sQ%j;02NDL}APKR&;QR z0nO5ODWa<`wyxJHyc8LqEd-GsSYXX0O(k0mQk;HalKfjBT(^)0p4z4l;0bG3{=C~e z>d7&st^boIg9|Zhwp%%o2!ITu*<$vt&!jF(L@3w8)nXf3lif;O^iFUlFmeo2H^?w1 z?5M0he&kWd&z7JNy5A;sU=S#e+}^46QFc?>M6Z^e7;F(n`|%ejFk{{`8jHwMpe(EP zT)P2_5wVD1_*eUK<6t!Of7QGj7;X30GE1j^Ihuj=fI4FQPDPyL)u@X>{s^6H}!EbjeVfdNKJ$t=*urFtrKK^-3^U zs)qL!2y$&SE3CAARbLB&N{_xK*aD1on$JW|n?OsPEC>~|1vjrGmVHBY*OaJ^y}NT~ zbcB#$RyfYB(4=Gy@qm245OAL-3fw51Q0C`#^{E#)1K^C`ja+bWaR+HN9b8`4QD$gJm6_l)MQh0DI7LElXe3F$WF>ftnJ*lyj*lJv4) zY|=y&SzfLuS^Suaxj17e8Adf|aTP5U)n+pXe%1yEA3HMY+^TyI^xqE`xc@x66CLS; zE=<+qSBT*~R=yd|O#?8-uB7jhKM^>_=iR|}_##UI5zLiI>sIa<9!P0YB?s^qe2&in zt#-|r?7%r~a73!qMF6j9f#Nc8g2(ZM+xC`K8KnKP=m}9 zgdFva2woqum^2$E-y&JLKk?F`a^@F=c3oY-Gfr6k9@hUSu?xW8st z{mLJhxKf6NbJ6myZW$eH%>^27IyKC%PKD0jTe4g_KQ*8p32y^D${(y0PfOx+-n5n{ z*;hPGPCT|`M5gAFz9uzk&RH+W6$8hrieY1SJ072M$C<&P|D;0B$>O9P3kE|WFs24Z z12x!WZL9(vNS-Sy9M-(F;&Qs!)?)Lvh*X#&q0U|Lt%!`6jf9vy)DmE8HmVzJ5Mexx zLcR7D`r_aysV_bdRFJCEE5z2h`kuSI@Jdr?RWsp>Z1AQ`Ufj_VqZxg%o{KA+VlLV1 zw6NB&fiXamSdl}#O}$!sC`(9VcVgf6D^2KwTx3loBQw={-jVMHe0n~NSAR4&Nbuj% zGCFzv+_0yB!vLI+V}BLcyL2{9@?1eK*E!$-o4qQd%_G$8>_f&7M6Nda86jnv!C?18 z$w2(7oiO(R-g+`vPFE{d$63`dfw?a|UIo+{VkG&s&byEENZGZTl9QDkon7}y8Je~U zRK_Me048Dux7b|5*qUvJf1TelFph789qCq-_Iv^5y2Dy@L!xQ2lhIqr7qQtYsku_Cu$>dj5*{eclvA0vu6(NSzAqnylzYWIB2xi)h zt@L^OZQIY5{|1TF+r~!ik5`F?FCCmSo&JTv+(PGl4l=&6*=6i&b@R z2-c5q-0p>*^5U<5Dr9IL|{}wJ-w7j(y{SiGGe;!URUoN9ybIb((fIfC@ zlaL}*!TN%7_bcOZ{2ec7y)c%JtNc438&l5qL!(o9X2Pjs@*}TKO*q_~R9qvJ+74P` zWcaTYq4r9@%2GSDfvPF*-J%#Je(XrfKP|Ce>QwL*&+KHV7+hzrP*#*}veqm`h8$h` z44(<(naS1l$_7}J$IRtcjZbDCaZ|`8Dy^GCm6zUk{){$y-&zF3LRJ<%SzL<~()aDkU7KDa9}tg6FX6?Lyixf7M;s z)N`aS{nb0yLXCd-=Lk}|04RN0m{;6diz2abUTR{lkdEM5VY}4%VB>Ch|D?%^O4}V7 z#8-DhW1fVxiq4#U0{a8t8OXSAB6>$Scr->wa*!?wmF4V&8wx1nizi|CtH)T! zeI=bOtbAjyCzcQhGX^@b>wf$vRnt#=K_LidEV3(E^-@Z75XRJ*PoDL83ulHPE~-?{u<92ya1?A+cL zJk2LT?!5%lib^GHtTA0NNVY(%2Q_}WabOA)@_KB$4Y}Rn{T&~R>L5f>kFIe8nF?Et zMb$iN!LBkhrMsov&w+NU9BC!U>aSgS`!7w`^SwQFwgvsmFOZFOB`fIUrZR1tt3$B+;f*;TGco%8DDNjX8hm+y+!2Np-DxaesDp)QpRg=|l zO2?k&*dSr4&4rFrYpAgsJ!TUz;g0_cGVX7>#lvKrwGI3%FREGME4Zb6<3@O(zLRR~ z4pRk*74W#FE;VX`BJhM%N?nc{3URUQcoWyXr3Dz4>Bqs?NG*7r|JN04`i zGkfJIp>qgd!{P9;y)7T}cq?km?9Ik+I8XG6$|2d=eu4WU6ITJf*jb~id0NWS?>K$Y4MhsMAfZA79a}L45_OYehlvp5-j_TyWR|tCN%iVzp#0o76 zUvA~&C3CmuNP!E3j{vi-CXWo&UoE|t%I^OU9zL#yq#Gw4^k72gO}rG|EKE5b(2C9~ z2RNtQFp~Y^kKQu*Kg=?XlmT zGbdZodnhsfd<5G9*!KoHWWM3}4_MTCTN<}2fdj+FuPiOToCJ8_d0GPdW zr*MR-|GbqQZla~H6o|OqzPfGbrkBS~>KlhT$p@ah^;zCNPg|K!DR%dz-r5-0NJ-y^ zJykPeeP?Z3U=OmWf0YM1!_QC`q+M@%=giDY$Tae7F9}DYW!EJ@yxEaT=reYN zXVx+pD&oIRGeSQ^NR2t|$-s;XimD%cbZf}P(*wwQ7{Pvgs|EN_CEppd z4M(~t^1L(Fr`QGA4TCo}YzAg2QAXIDqi*CMXmygshT^wP?#6@m{5O4aidhCF(+_J$ zJ#HBW0b35qgl2s_^LV=ANks8~pIgshH=!mN8QsQ0j?#QBv1=>^@iG4ZAw8nxr9Hkb z5vUZJ;?XXoDBOQtEMZqUc8F2L=L6nTuC#W2c@LvjJ4f3#lMrsxvGCZYwWtA6n6LWl z=>d5XHs@GMH09H-v2l8!f+Z(^t{b)`j1bsXWYTv@=GDRV>7(%V2$bh*&q8Pq0;fMs za9nJ)se;^hN>dLhiSOy7vmbr$-^zAT$1B%RalMeesrkny6R8oMd*Nw6)b zT{Cy?-nH!eC{V}SqYZE>@3&D&QBJCXw!YaL{`2eVep^j^Lw!bGPFH(sAh*kbXjSv$~p^CI;x^M^LFr_FHz zeWX0C;Zk&h)Ufa{^YWHl`CuQ{Fjf0yDmrcZK?=*!+I7=;3+l_Ak4R6s5>uK2R+iF? z*{yV|DJXHg{I^@={X<=T#NFYlfzwE9E@;V182G(=PxR+Vs6~?y%9(_r-S|(W6hi9# zHw?UAksMyf+_R$Lbiq|x*2WC}Qf9U-Fc_{wXnVwaW47O&hJH2HurG*&@mcM@|J4Ml zhhe>cX8EGOQAyo34^LBb5|bJ>RSw7&WyNI8M_5IHI=MuGlYOnMCfXz7#{)s|MbC$R zA;Xguq@K*VC;Bg6tn^GLgI0%^+m#R)fs3P^n8iGCf77pdju&2W0tB&vHt&M#=E&J*{*Qnme`##sc2UjVsFMUV<LMLYW;ZZ#!3&RoDk_E~M)7HnT-y=p@JO1kiQE{~Wun0a@D)Abd}2RoQhiJ7>9o*5^@2JD0^N#6X#zK16~oFKQmW*b2wz#>&vw zr7KUdMzJx*v4;yLvPm?zeQ&|SQn?2dx_q{rc#BMT1xsf)LZ*=qE#u%#gWtvpp#xpW z#Siqy`Y|ds&W9YOrP^yM(HWnVZ{3UQ@Z2EdV9Vorm32up#D0q7boMX)+IT;jM+yvs zXzA7oiS%Cu-!ztS0BZlo?9?xGjp%dzx=5rNz3$AXC;0>)ozMnoPwwMuDWFB2g^-)p zQPxNgbAuuRK*^{^AZ6-#dn5*iYRAZnu~^2Fa>-AY{r<4)tU_6J?ubme-PqOcpTq*% zq#c)SUo6Ly>rZa#Ujd;T!D}J$7bgt|b7pjPZFc|w6@ihRp3N6OwzdXCmV3Ke67K41 zhmlZce1`LQit0|zNX64CeL)ujS`hujqxSEs9xVz+d+1{KfnM=b{=w^3P3!To5UEUu zmTm9=(w*gyPl{^7Yu_zM6gGxuneXlRrO6?)P_Pu8#qwb9aoq)R{W3_5%qSHP%l8n! z4&A+|Wau6Q5n`Mfll;9dQaPs64xOX(O&I)sgZcb=<%R6GG=$4NL`XHub{ZK|pX*rF zirV51P1OdfsW9KVI(f<_(2|z+0~V1``+`DnCoZ&nst9_%9bV_BCuWW5^p<{09ahbl zpI#t+!(qz!<0((xRn9x@t@nX0b1Q-3U^w|$TOsStH6=O^mOCE1A3&~;)H4+>20HZ$ zEPzzy-pjBN89AATPJTo{f>D$Fb0Lw&2d&b)&EwhiNLX$u@`anvXHiD8Z?$~Syg%fG zDA%4v$7W8xGROK_&+X+P(ewH)s8ReqD%BE_sG)y6mS_KF+UI!uY?v26bqeb3yafXt3)aC`T`omR4&y@q3B16x0zV+5;$an75f(Y_Tg*BuvVSGMg5n;33}gI zgO|*B5$8UPGi`Sh`s0i+JCQ#KEru}OPJ777fNUjbE?hxqio56U4(7|9ur+QUzq8{mt1g{e#;SNKgkRmg}57MN@jVO zmL}Yfes4wLi7g@Z&bs2~re;rDbOZ7oVUojgcgemfF7I8J*@Y;^loA%#rB~QBbFoby zGu=}sEiJoKw!|^5KlS_yScXAP)WgO;&elpdvAVmI8}P#u&N<8>63T4&prvyHr_l$v zEajoIPynZ)m+P*QVP-4w&feV(30vdWlGE$4Vh*DVEk_22s#K)+Z>%_FRb($C?Bw&8 z+;qdkF*7XT>qii$#b4NrjU=RnNw_j;#_GCj$JE=EE)M+MI~mTa)efK|jJ|I@tez0g zKe3x&P3-nR8mvU^63@BG1i)7BOwAqAWqm3JmOAT()8ms8msoOFt_v5s|5ik!uy!qE zh?P@QhWns(BGQtG7U?#2Q}0wldSmTcgpgF{4e%3CzWm3jZwy3L2WR+#B`uC~L}r(i z1L1TlqMGYyz+M}#(J^oM9$71(0vtoXQ&nf}MtHv4=iSl?L&{q@CQUB~bKmG`NL)T7 zRpvpASO~w!rv@ikB<@`Skg^E|U4!@hVMpk1yRt31WHGSHP1I{$B#a*|>-9y%O2exHhIz2@DyCY6DD5u@mD~a8=gzQVi zL8eH8U{dWLOCG73@GonG#&L!&1lyh$cc@|4xkQKF=pyBG=8aZejy>nef=6A8^8X6^g75=mw}gJ7q?)`=oY$f9 zLtqS5@t%&dmiVe{))|9M+xL~4NUhdF82@50GzVgXMqw*740Tanf<3*B)*95Yf)-5b z(w2Vsh=G^L5l@l+0gC<`*%btln&c*-67Xza=>T^mv9PRpacc{!JJEYjsEmrkxj7V1 z=|7=?2HwB;_z^bsX19FTwbKR$gegVQmE*-5CszQgZ)Qq{j0k=WK)+awSAgd{2#5C; zaNBF*2c&n_Eh`TOdms%ojXNl>p0Ei5px~JY$bWqinv*pXTi5h-%+rzlKJoppa<<{+P1G!|lNQbkF5a(G>Y^0T0v&A_ zawh_>yR$9gwNMeaC{85exMSO~P;A>@{-F}BL}3d@M!*LUnWMAlx zIcMT=uYIs^N;pZ86v2@L&`SG2Cu9%tNM)wSCCakQ`#AsPI`h+|%e*(e>{!VE=%bw%` zeESN!cwM7h zJ9|va&dl?k1^VJ1GWk`-*F3kRepRQ zw=4Y_ZhUA@ncA1Wf8!bwEgk-7{|mu*@2Z*g{S8I4{I`5q%pI7qJwIM2&CI>}c=|7d z)S$Oi=1<1A10wetK5qT>e8qB_)(WWnqVHSJ%adxZ#;KjaXY=K0>+M8ZNl6P05K@4J{7$FbJlJlH( zwutY9w@O{hek;aK7gTt1O_prY7*osfp_AHUy$V_@ba8rQl)kP)RfhcD;r)NNCGCne zIhB5`3ZfIc=@b}QhwaevGrh|@+|=dA5n=?`rrnMBcSWVj6>YAi`M3C00_Z4Mv#sWr z%0JEC)STM&*nTt0{IZIP-i`Z!k0Y_Lgd8Zh?U&zI z;De%Frc}`WsG()onN$H>7Zc_!%)<8#he97gSH*5V#sOy-cI;Y5aO8EJ{aKVBYZan- zhniky(Y=ol3T@4Iarxb9AYOHBSl&al`y%t)9EjG0_EDk$MmePqrM_oz+CZdYG`$b$ z7d~e#!#52OqJeRpg;)47|GCT__PqzKE#e1ANOoY-mUPTyxNp|=G8b4vy5S?9?Bt{< zyN9+#}EPq?Kdm7tpL0 zpWe`FTkrGXghN!$zT>5*KYxHmeS(6hMzZv(-P_hYBk_b;{Rz>KrPiu)JUsAO6z+GY z?`ECXDF@#ll5j~o?S=&7jf!>pVi3wNHxkGIVQ(e6PU&wK$j+CyBJhir{7HJP2S}34 zijdP(w>Dc_=!(}rj_ndvF}`Yqc_xw_6#5ONoPGu zyNtu=Dt$rg;N!@6hmq2k?C+aaZ1x>RM8Sj59hVrqbKlO=dk>EQf995yhrbAPMaf7u zTb}UU60|g93C|y!j>65Csj-j{yjQECV%d?G;2{Y4O}IixH&;jr^DL5T_YnJW*U?ou zunOW2Mszb&fKAzp)XY^=l{68?G2=PgGwB5GmiIX6_dbCc<(eYkL3ISASDgf0O_jzv zZGYEa7iW%oyI_s9>6DYyMkj@a>GN$?&nWu|&tgoO=!JF4in|ARU2G&duihdjlGC?y zyYphLFGc+%3W%JBT=QPB)gUI$Y~c6tml*3*_R25g#gPT9Q7XgN+0LkqnI&p2f9^Sz zv^#QjCk8CfqSvL(>Sp9lmFtI82&LLa+~fmD)|#7e_?VCS0XB;BsP2V9IBToao~M zAP@mz-JpNbT9V(Vb2ne~+cfBx5T*hPOK(15mO9_2LGb*k!UoCTwzZbpS@dVp#d4&QV#bKOfZJzU}6xKV?*o%+$6mF5lk3(yL29>z;beAB7r>nJ(+ zWv*`fCkcsCNm=z}1Bm%W5X`19iJURu z#L;o4Y-B-5x))JwB>NW{)pHicFwXo08K|IVKnOhaiM|PqL9;jfaH7U=a)%jcjRSW7 z*KH$4`_dRajsKt!%%RG*DhYa_-h$E>Ch-&E6yDJ&)+{0|G~@cD0?YLJl~NFM%=B|} zE7@Nzv)s2Ix!PgZax{gVLyH(dn2ilyrT1Cq?)KXl_p~mGgnINUyRQDc$*PCFMmXBU zMTMyaEg0Q9eySd)vr;k}QwY@V;W>exdrEtfkz~U$AteU$0s3WnD6zk)cH!?3Y`3>E z>PB3!_|(=7WGf6N`wH4poahs~X^3uwqdM-p7>a}y{{MoG;3IMk6rLc6xM#vB&L|IN z{i<5`?38E;3|WGsC(Ro3;X5#qNA+q5!IYwJvX^M%B>I8YMU>Pmfxf4gl0ky6 zMg50F)>Ee7X=1@!J73wY^N)XyI=z#=U6SE5P1=r%AMg2T=HBg`s&3GaC9oz=VtNq3 z|39N8TaCDcMCo6GbSjYue6;vDOKjebh8RyaafZ`YS;7~6eqE;cY_L1Kcp2);w)x)3gK1FZ~|lj4t{4BL36R2tlGUmGI6_qV>-yA zj$wH0O^wF|?cXI{-oWbS?`_8=zn3=pscnJsz!B+y-09JXkGw}uywN;glqAD0I1rPG zS}h+I+v74($cko~^A@Pe-nkRaWs!~PA$<6pZDEuVIug+qe1MacerxQ8tJ%6xn8QPP zEzxR#0JM$U6t@aj%?`R46y)?_>S=B{gzFSEStU5vH*@99rTdXJ=s>w<<-NA63VpBT zw;bKANg-z?T{g{EOOcpd;tu6iPpX_2hr_^mz+2gk_`OeQ$2>q5-6FTnr~C|cD&)dU z56_Ohj1ma!S&=*%jN!?fbU8>oARnj?SXgCayb}p4@%Ae07q)GBTtx5iBv==TKVkTe z129fYR_P495^ll|xh7$hw0U&HZacVlELcYsw1#YCk=&$50LZzsK>_+hGBDpD2tEBS zh9wbc<29B7nspT=S4H}9kIW^@52EPphx)OXGmL_S+@NFj!;@M7FVo{~}tJAYpBGGL~Wks zs7wcbK{L+#r8)!1R2e#Vx|j0Kj+#c8bY2c<`kR*qD78=Z%Y+pFr$FlA5ae5T0P+PT7P83&2yk?1r= zP08MMfAnO!c4yeJp`@G8!D9|^XZX{dABgxH>i+O%&dwkTD_7`Ro(3J?+oybMz24!fj~<0?Qsx#b4s5Ci!n@T>79``LYa`D82&Bpu{7*zwh|cj7 z}yOOR#mO;M)Gc}jcGu@pkkZN96xax4>%IDMrx)5AMj#G!UPX8J7cCrxQpof7v zGs*WYeZ~^}fgd1{@R(|70OBC;v9JJ_im?mNrG@6&(F169|60#56;Q010spAM^6{9n2t5T1Ir$9_>iB^R%>=OT~X@OmzGSUZQF4G-_!JWP8^m%iDx zkYF+ib5EMm#!&Y82py{VvY4}U!I2AuRF&+!HDr_4x4Q{}NzDyX+J;Kkdq&?u;u z_WyznRCl{Rns)`fkOWbR!-I50tA!F8+bXRh+B2OcHoAOZUxl;$?pNha0D%2H#UAt6 z2#u$4NReDTUVOF&)M7l&Qwf=x5dy_*t=#?`*@)G>xuXco+T5H!tLdfpH$or>r8Qnb z!WD{mscIHV87utWY^Mx#h@O(0ThgrqsYTVWq)wyK6!b8Dvd)K{KT(KAQ-Lo72)v!e zV`^(6aLJQA8K92P3|XBgzM=ONs@XeNw7u?9Jc>e_21?M=$qtGpu4|Z@&;_2@1at zJ|a_L_X^7wLV7kcUL~&+^swxau&h4^aJ7YaP!{+ z67|<{cjK$D{ujH5iSFcYOmKU#eq`T&q{*S&Zlc@Su>ZQuaDCQ62|f~h+m2JmT> zm-OqESZ2r;g6l|&x0;@*uKS;|QSK{De@Ofy4%=NYiam{$u8eZKu@ueZ+KOVUyJoaw z9S~-stiGf;>g}Qoq7n@$(OcSi0YM+``-}Q>!K7wPOUKqaq1;^bCm09FY?5TAimON5 zR$dN)=l6R`yL*wZ$MfnuVBF06hUyPyFkL!vMCRw4Xd=78 zze1`@BGN)<02NISxDdOSt=Du3D|U7G36}X0&#~EdAnyrJT=s2^Zt5eHyaP-h(o{%h z)*y#lUCV0Zu`^SBNHg%&X@EEz4%*?(r~z+jb5Y4#tY)pLLzfG_;Fvs2)cD2ih)1ZY z_VNT#QXzkIpAk) zBM-_z+_G=ViwZ;;6JauaFAu*u9U*cO6GJW@BLiFxnP%>$Z`HrVd*4lt-2RIUsby(9 zeImh>J_E)?XkYCqpRcdNk8_4Obk3Y@>}Er(Cz~Kh*}7{FvauUUCu&hw88(Tfz#p}w zBmntmTI}R2ltqOBzB^12V0cLhs=g6TH8EF&2M=oxm*;C*+Qyg$%92rCahNw4_ruSD zK9FA4_tmqs0fPinU^ zI&;dLIx+U3kp;L9Scz@KqBh3LpZB&?KFvZBNdaGyEQkezR9)v?18@CePu=2zYPJs2 zgq+)6l*e1wgfuJ?HXS;o#P#eGWh+I5vV5UZX|@p>9<;;FRO6B{1$UQ!fvYha7;}~R z1!6BMKZ&dM3hqzja5|>hj4+n=#3*WF6&D2}l;k~vdm&9j6eKnjG8b-PjQU0}RrWUi zprOCt5d9b^mr z1#t#zhSJB9ft1^GcK>^*O2w85Gn%H(s&Rm~Z*tIZa008(vh%zNmce6i(r4(^%PVzB zf zRXa%%uVQ_JH=&$=SC4~l1{fFHZDqvn+dCo_)mu>8qz*lTgcuV_Ta#}QOpDC==CrJ$ z_VJ^pDr}u`z&0v6wzoM^Q5MFNMM#PAIqVR{Lu_#M?suVG_n&JEJ!_iViY+L`%x~8N z8hWV$6Wj5-dpcKD!|Ww zhzt>@UfL5Hk+r=EuxqG=yWZ13JMH3YyrPL!=;Qr@6gy{ z)G@$Tfy=v(=Um9TuV@V2*+ubx-5xAIjfz%W@`2xSK7=aWraUFTz{1c81ZV!Crn_&{ z$lSMoUICQ$Lzz!KN|W$zWsY3V01E*^3CgxHgdCI_82Uq=@G8*i%8wr5rTEDb(&hxd zqWA4q9~uR(!xvQ4|00FYNzyb^FoblA9XP0yBFUn4l+E^0%bjc@M z9u|Eoc>TflWCLafzh7s%UCLPu8DHzmBm`mRU%N2G5E0qaGXem?bBLPpW0?W~_U!ZC zSnA(Sz8jTmwx^w6x^`3(DkEE^2P0B-oHWFQB_S}2VG|>M(5$q{xiG$w0Wh4;D1jaw z5!n#&y;60AE$Z~qeqj76GSOGmua!!Z)65_p5H^q9bnl|z9E3?+|097(<6*B^xfMoO zmA`Pijj7p>y!hy4Q3Nrdy-<<k2mL)!`BD?oa0pNNFsV1Au1h@BZi~~mhHn+7 zOJV%|(5atf5qmfW+vY}f>JFCkkBYYWVTw`uzQ_w>31qx0K2S=|IISyTf>M3n%{5M4 z9Ipj6fo&So!&RGuL1Fpu76C3Of>W~4s%&~r&Z1s9cw@E)E;h0nH4 z%H-&1hY+=oRz1>w-tDH1^ zcy@jI4TgOSbBl-pFCgvuBrHXWs9^Z4KH{yUQDMmi2@vDRWe1#L7sVJ74rA|2AALIfjPT-d zpF2@Q=9yC+0X8f^;u<4pJ(h?BtS<6N_yM3^LgpM=uG>2N;A_~a%kzj+LNY0G|2xY> z7qnlf9WVut+)B?hhc_Gmh*GH;fG|!Y`jPBv)L3M6O8%# z1YhFJjz2WET5ARWJC3uz(WTI|D0;nOE+oD~Bnph12X=HwFG>dGd}f&bGlNH*-itQh zvGwt6EJvd%#oe{O)n3ijhxCw@DiLNG3vblN?e7A`d>1vtuk9&e^o)@^knm4C_Lyyu za>B?b?QE-(56za6*eH=WW$t=B(7~Dw9i@83aX*pdY5EaKwSw#qW2jLWzFbwLjbS@W zJttkfPL(=X5)il*FZ0a43VrSV3Hz4FVGaRA>fp$dUt!<`B-7jh#d#mcGS;pVSV|}e zOuz{5Tewp;yrCsYyKVtzclUe|+1bFEUe+CuKEJhg0ja)v)Y zZg%d0mnf^IMj@F0utflyhrzbq!8K&kwSq{0quDN8bgtjz<|5CuDeQ7T1Tf)+L@h$= zX8zRR=>Bd-brvd?${lFDVzJ*Mk{bec#tBC48dEAe>6d_?2;5wcsh@Vq$MMwP_p21= zHs(kHF;g(aR(LvJ5_cXWW{pcSd3-iHzy8UYFZ#QCXIB1S(xPMV)O%7)PL5e|HA=DA zOah?mYyWZQIyb*|&}NymH~;D}bw1{{CH+7v1jw-enS*gktR5{jzk_2f^O3kEJ9Sid zV{gPjkbR5rR)g=3u9|`ASt!bP_@%Yo_E{sCj*6f5QG+6W(4e&0@R!D!iyB~VT4Hpa zxNsqRp05u*0g+F;ICkuqy)=YYfKGiego;pL)1jMJl9FotnRE4R$%25+X(7-5_e+aX zF|C~>D49gS1GKz<$TAdPR=74}G4{JurU3UH9C=heIS=J(SLdi)tVH#*_|}Y}sgrLZ z>LP`J*1_(M@XONm%8f=9!tk3JidOb5@?i0)EuDM7!2=u9&Sz*t8Lv$X-@NX^X1VJI z=K!ooT1wiLbzd7k#gAMAEQ=waDpxtD4<5+heM8#VIO?hySPw;LPutLS{mf;S04YG$ zzx}KsWz*4Kl#xa`SeP7_a8<)iq@{I*l`Sz8}75_y7Y?U+dPls*i9Z%sQY_03~xbuw>{N?>7eNH@x=#fGWI2GOa zSc*XWGhaqeABfKqv)_HOoP4pA{A!2-{$ukU&b zr#0|;?oCR1nqX?L9#f?vlgJX|`f$_=7^X|wJb_V?V*iKrMsC_eaq$=95sKT22m+u!Mu<{P3?3cl6YLd*IW~Z23Yuj5@$aU1l zcQQIoUckY?nPE+1AU}t_hBOA#nCIdGLZX~Be!1QKhDXdVW+9o$K$k#tWM(2i^Gb+GGl-MCgniRqSP~3_d4}x)65dB9>XimU4zX^$p|heV?59hILNutq?WaKV&FWZaR$ zIBKU7?r0urAI#97t8so8d18|RnOodMGaMmmJJrUyGPbkw6+H@W)9f~U2{F@Zb8Xa0c805AE ze*c)ifLJ=BVHpcOn&*p`eO3ec3*f{YbnVBkUWFQ*YGsMiPPnoG;5V@}3wJGj)m>6)-XHZyXh*JMh=v#uXGcea>|3D20fZ!dFxJ;OjC42ww(p2GR5gvwP z-H3stVqpe5y>$B3YLX{4y?IDXNbKavAyIAs8s6Br$fyVvpD&uprn#|XDM^4zn(>Lwe@A`ltI99C;c{dnOP zv2#h#d1u+oC?i`0Y@6Bd8soOu>5f~P{i5sYP))>A#Zh9&?s5E0bDMMIVI-sG{6n=9 z`0i5^hDi_Pm@v1$Uzy4iDc{`Ej>EN+zes2uC6VnW_CPp<#Hf9?v|#YofcPxBd0;cEU#@`J`B6Fh`q7UCk|Vl|qZQ1A7Y{w%l3l&;l2A|&VyCawrsJZc zb=r!JsyVL|>k+%Z$fT|V)SRYJNbid%FpV;EeSz5fw-O+peg|0qEb2T@m$4#o?JrjY zssJ)L-J`j<1BdkqA~hiIEAnID!2nQO?fk72`Megswl29lR9HxG+7T41g!dpFMmM*qa;5TFjobS!E$3oh#LW4vyAX z;hl-%@!TTYsC1;coR;wKC0RE;TDRP>6NvmqMKae4Lj5GP8*?1k`tL9N;m-N-T(FXg z7eW1)iroy+j+e3up6rYUcR?bM$#UthLntWnZxtwW%QhUlFs+JW2vze-h}ki1_F-D+ zNjImM+^u|XZ5>C&hP~2c_{XyW$U=Zq-0)UpY$(_JeZpaXo7%tl&me&u4VZ|d9nrSg$&4IKW}Qdi@<7HpFgr!z$^SQB z+>FzX?|fkEHlpQJx{gF%x$<0j!qvqUO;dQ58Xdy zKJ+6HL_pd2)ulS^WDD(!Jp?Y_{be*HmPzE$wdDIU0bTbj@6WR3u;DLae=Z{6TDL{0 z-H|ETZxu605n6^h!@bq2UE1C@cY=9-o8iM;052i_hxiegL4M%Y#9f7~9;NJ7h+xzH z?exZjKVb<=_AQ|hh6YmUI&6@HVkq%f5?Zmf=|S{Asp}TJtoI1pCENREKkhDno?92e2vTp9j0QQTlJpyg!Fbs%!brmXfu z-_4Es3z>`RnS39V3iO139^n_Z;X~uQ)i1M(sB^F5ctaI~@QqtM^P5l~s43c-Z=hI~no8lnYC3?nhgks#u^(y?@1_dFp6mwm#3BDm(mJg}z*XTf! zQHk9TQ0kJ$y-$Jeytir5wg^&zfYZdeX-MfVUA;YyG;U866aVY*HY#Il_mkb^+MP{( z7m8B5M2J6qzFPTZ=TO@U?Adn>dUIQT0pFd@Uf1=?=;qa@-+4C6Y*_rsB%OL2<=%&Q z337`yI3A7;cX+SJUzRRo13uwNg6R$3LQ_=-4frd=;sMYI*DBm=*t3a_pwWwr zW*`%>V)HF`Qi*kg88}k47>lZyumV9#1%@Z9ST@eCB@4gK4Wjp&0g{E05hDV3vfuT2 z`Pn{?ncHRI)pJSs3n(#~7JW&s5~=M1o6*HvKhgkqg&}IPERE=z3jb^-sWi3Ksx;36 zI*$QHWE)542aUq-$i{mlq9rkTQ@&1E#|sxpg+wf_F19zyW}UJka>Z5za8)bnf~2c8l z4*;u;*(+><+FWB>kbmv?ci3LVMkBp=sx?pOJ9gXv);W=77Xv5-C3o`eXYEZs;#V=d z>ap^_zNK}rco*_YV!Ezq~K;Tr-l=~dWm z&&{PFO7?!`Iv!r6mg^*CS#cJE7)Dqfk*#ZnEJ&>M0;;(4(di5sN}W zSVxe}167BP2)ZY9j2?)|tbRtk=>v1_-O|!HSu@C z1QF?QHs-FTfs!NIKNhT^%l~G4I&STY(UoKrr*&mu?zQIyze3j2-wgC-rKjG-WDdlK zfF&Q$z2J9Ee6?(0=Ek8Qr|l4>2Sa?(sM8XmaIdkGntI`ptW0R_Ky<0FXroTDH9KaNfPmuJij1Px!zfJ7^oO!;yU}Qqj~7GMcEf-%;A(j}mNg7bT|bSBw_&h6m&Q*ZLG~ zy(Aupan>Jy_p`#Y@BN46^ZcQ>3Q3nv1h)Oov9WLDTfU4^3i@BA?Fcb+=-1HCRayk$ z_sd#5R~$>d7aGa@xWEFW-)rO{=+hXzC0g{hwPc9RYr2akQpKQNpnfRgu224%z1Wtu z<|(2dH9x8DFgO$#%A&+9B}7*lMmibG1{0!Svcp7I8X*IBY9+ctFGr@6Vul0w%S~Qd zehV!|gaNS27(cH`_R!pK2JZxPoB1FmK(SS6b%GZI6$u|t6C$xat)N_Y*jT)1=)Y>> zE(0ks4iy1N@6T9&g)ek&!zk~BLpAbXH<279mmM+H}`&L?2AJj zX+Cu|+_KbXe&Ibox4FX*;P8znlJjvKIto#pCmH%jX58RaWA+GfuJ=jb#V9c*8f6Yv zU|jChC=D9Z>{Zn!YK1m5)R7pGPB>s7=?J!eueEl}>=W{o_5T|37@p3^Qp}<0(0FV2 zLL;+D;<|j9@L~`p3I%5gR}1Y_v|$?~suG0;CJGMxlg3*6@~YcJXsFt(m=is#Bzvp- z88y2{-vu^to3O{YhE>x=+c^r@Rb;H7zY}h+@1%Fvmg7dJ2V!Jth>ULZpR-hf7Q(u?Lrk`1O0l5K$dO|ls?bFX}8s+ z{YaE=lkArXycgfhwlyAf(wopLep$><*6TntkFLX-Hm4>TdgwvT$aks^Wf}P-t)_;W z-o$wYZc4{-KtQTw7xjB%<2XUy&XI^d1KB6${^Qn1ANHyc_$(AyQI>&xdzvj%%Gd0$ zm~KT9Zp1d+Hz5+YCdKU3jKeRH(RcAiJ4WSBNJ;G-T2L z+ak-T`f47?%M2(08K-_xTJ%47&15EyD_xYo5TUY^O(s(d+X!VJYJ3qcEns(tY2rqk ziZ@7~gMa4yL5b#_mKR`}*b9w=iC?Z!L2LqVoeF60_1xKER)1}6{_SLEz$G-{c~Q)_ z8g3@G@lLH@kGc68#2@L!OZ?bzN!=YQI$1#cZB`QhC5&`Xe(GLkasRby{68Y$Pk8!6 zH@B;N-;C+O$-p1H$HK$^;Dc$oEsSZMXlDBq2 zxvH-HKWmKt202@RFGE(5)j*bLZi{g;k;b(%7hxRJF|bRJb)D7>;7dS*5HposhcU5a*G-x=MT zT*hi`!-Ae2sP1E*G~G|9FVr}#k1ss=_Gi`ue^Z+#eI_8vy>Z{GP@3+V5XEGC4=g+V zv7M6WrH#RQWoidS&Btt0t@MY!#CxC!JZwhWhptskA)!RK zRy9s+B(0cN2dw6btH~?mR*SGumi!N8HaP>1erK@;arao}1y(Vt7ktLPh^lmkIR~+a z5_7-UZDN;G^#irElI-T`!9WFeIA{>C9^#i5b8r4qxQSu#++_PZAu?wkMlNtd;*Dm& zB%UsgT80);)wyM+wOF9g$6Oj-_~5q38wwLfk6mJM2> zEk^5CwmH$ z2|TPgR|O-v0%$W6FHRa$80R4YlMdpLst&M!sFGu~m{wO*FXjf;iB(6cgB|)1pomKX zmu_p>zuOChNw8g1uuD^P0V9pZUopj7R#E6CP|@DvQsuw*Yd*)a z-gO6P_Hyl3uPC+5?WP0?Jk22RLQYs@%)e~<6^Ay)>`Nf zj$>y))gjHE%W~2bRk#915~jlb!W3u=L)Y_ck-VFHWs1hmoB7d0c)PlsexM;h7y!Uw z6cq_YDSu0)7%hNt#&100c;6XIY^pS{n9xp-Q5_LaR4{B{s+T);d>wv2HNo8~mtkr< zIZUG;&g&-YH&V6f8I0sPMt@6eZ;|CAO9gZ=!R}8S&?zbAX?m(8T5(&G(i#WWsb&RC z7`5$vVe%3^i;0!x$XT}DCw(2Sd~C@jX~Tc(?gpJY?@M$SpupkaY+5ZXi{=^++w0CUiVOIzs@{}w> z@M9|a9A}-Z?~g*u2l=_w3^#WipzQC5?tf16FVR+XX;9X}S6_I)bUcI*dIU?=UR{QK(lMf0TAhLIL0 zF1L4RCVO^iMY@p%{71ZJ+3FW$c6obsYgS)GXn-Uwe`)~1N+r^@iAWV^x4}@DJ7;6=JtXAX!(q3!h}KTDop?IDv6+Z3N>af=Y)MKwM@VRXQ8E&$XJ(|B^rhFbjfc_v1(wBIs?b22 zG7>#$Ao2!jJU#idZ;)6E{L-l+7#x4&gRV26hwLUqYi@r&Gq&?93i4FQ5c&|o3eE&d z$39$7uQ^+vTmyT{X(Y|jrfTI*o__i7d|@ti_pgc)2Q$m0O-Qy*LeObS3@K&m@K50J z3nSL(Pj^LI^08ettlQ$*{+&KUGIAfTWcwzkyF+NiG(Q&+4lBClk3nZjaqNwU6xfqz zTV3SwIGiLsww^p zt7weXXuq|&EVIZ&n@nWs@RG0Vh@GEp2nhw5rmr!A6@k{R(rfy?MQht6uD!B>FYs4v zUB1Tq2T;gD-4-akf?T`Pv;wNYs-_eK4ZBK8_fBK9Fo{EiDgVepeBKOqI?QlYpyfLQ z(1QT(#MJ1|tT&@y?4`2D(q*U5k<_A@{&XH@hCR6*x2~5c`_kF+SUi{?Ce(iRER7Po zeQ|P&KdZGsbwe4d{6*RH$Bd%ZB2 zb-H4*!@w^ZO%cpgT<1f(s?2sT)TiH`r6Zyt_By^Wr1=vb6eJ{iBAXK77I)@qFf`G_ z`@uJI(9bzmw=MHt*nq3;aItW@0K2?$?ue~AR_&WF`u-c*lNq6aL#C4-l%+a!T!TcN zUTik2{;Jf_O<&&_#<+*os%G#Tc)*u;x!*Rg4gU_2+GiS9rKMfBLkAuD%jVtO6n$`C zb_Ceu#+%yWmOX8>K?Du02FPZi#_=q8Nev# zs$Gd`JFMFJR{ISOW;g6d@+vrxRX-lf%pc@+V1(h&%0YeB7(a`5>vC!X27y^vajXdJ!S2Ba3s${IUBoQ9m zwU?NiFDEhqUBP1FOH4XlF@jnsgyZDpn)fp!Qhy(QNnW3&G`9aeyK{SD0Z6m-@$bGj zLylO^ydm20^mlBxh9^&V_87c3(iEiAdeyx0eq#OA$7Qq+nwJ&wo+JDI zKi=!)0Iuyngf58ZSy@)YOq#~gAC0}JMG!zHtf)rRv7F%3|2O9Y5p}M*m>~UDM_P!a zcn{~@^$5fCq)-ZPp3-NQN?=#xFoD=eJ?L0`=Ax_gZ{Wg`V1r;z9sOl z_1>4iQG%7YEp-1vf zD6DflL`c=2!0xV?in5Ppag{e@{rL$pDxvKLf^*`H?Nfldh|?j%SElhU@U{&e8(G#h%lL=c{G;p z$;gyfoY*B07);_Z1RTY(vNj|^K&1dSXX5s;`G+W~=pqmxxTeDhyWHxzK(G(a45Wg= zOi|m(ji7dOxa7@eb3rvyL>)x1wuCm}!SCZyuHDm4`o;0ZTmi(*L<)~mgKtPhtTnFu zd62jDO}_|^x2-5OalKtYrzFjS8B7}m9z?ODE%|f#GC%7-7Zc0s>#T{tNyhREQc}(d z*T*=>oO1&F>ck_})JWAnY!83-giYX0ULMo9H$Edaui{(v%2cX88wp5u>?Q--?)2Mn zO@lj3Gm2o9=u?#_(NS6@nG#%z&0^7K(}qoI@UH;*;4gj8(J%n+R(i*g$$3XQJIn)0 z#5x#TNt^XknNJyn#f-RS+Y6gxYeL5UwZEYPv?^Ac2_Ix<_+D6Vc6hHHbUk7(NL<5# zG=MbgXo2+^*NMR(<$Djsg|$>cEUBz3F)7s7Wb+x*V;aG2T4rW(ag272ZXt_GZ|ehi z{L0ZgPInFI%uL`*eMgZi&3kvEKZU&kWwO?E`s&tz(PM)jVc=_=5Z;SyC$SoLjC5 zwz7+44*byPz5ABxey;M^?_i>+ZJLlgOTG8oy$y|Yz%C5rv5S%=0U92W8uuvb&CW59 zpAECW&mz8n4`nE+AUF68YSh%?8(J!(XXeeE(&eP!iiQ2>ZR$brh|$@Z&|Nr}DB(q~I(m#vL97|V8dlx0(M+-@ktil1hqa4T?HXHty-N;OSmExRm|s2su5b;1T^3v5d9LTG5i zPOmGkqG$h$%u>=2x8noMRk#Swjv7Q!&yF{A&0fFd{oy}Q2Bi09u1kZ$Xjn1w?oWQj zmBC@BwnFWNXH|J5CeRDBlwjc8%a^ft_KxdEO45(f7D}D^0`e(k@);eoma5S+a01a5 zje%ysaYl|EBie+jZNbL|`A&hCU__&&bAk^tp8gwCe5-3oiwgeg7uQ_RWKt>df{I?} z`rw-rSUZB*hy5KjC$H4Yg5BRVy7>P41GE3yai)Wbsk9<`5q_S;N}J?ExAtOpOvnZd zW+$FK-&)t=+`Ice+h4Xm49UYwk4sE?HjHUhU{zJ?_jMgQ2IG4;P8up6?!!l)+}fqY zT*9d39k0)oL<*o*mWyg=bhInHTQfa)pe9A?0RIO%a75hDe^v3ex55<$d$_?J``v0e z|MDc;vvnm<2>Fyfr9g2>wh#@W{tK4Q<>1EEc=D4;sC9+de4ZH)4A1KV5kErmSOOb7 z~Gj}&59x{>)o7*yTwr&CyEiSQTZg`5x@QXUkS6( zvBdZrli)fo@zfS5;iSW7boP?FZ<8h)EQ|N*4J8l-!+BKI08&e^@a}uqJluy*T5AK? z#HwdH!O5d5c6PGxV8|AVfKFmSx@>hb6LJWiT9CsTV7*o*&&ji;pEEYJk4rjpUc(ky zQ+YA#7u5&TJ_$ zgXbnApRrzjBdcUVzJ4_}Jw+X5GSUUyE7H}9n=Qn29Oa4LVv5+AvMfmiO zT@s3zo|Y(n>4*VbW0otPtwkyTKkO_Ajwv!5`*O(+0F^NZ5@#srKRcdZ->}cv?1q=U zgO))Wu^(d;3YAbl+CkO9plZ>gdXS~mq;y#Y24e0aHgNl$zs<>DS`3a{-3X)UapChH zZ8=AeJS-pm#tS8y(fDP|k*$y|K<-zB&~^e7j|uRsN|mFq|FCI8vAFp;W8NfqPceR? z0dfD?9;7qq39O%J8L*xD#d+iDCvVK&woEF|Ddf3=tIIYOd|S*fZGyze#Icg^JL%Qb+-xpGvYcQCY#%k=87S`vgx~ZxMXu5VOQOgc zG*X-%fR8<|sypS}qEqMPHhkaNe*|b$W;?#)C1seD1iJXTSn$1!$#UJ4FQm=b{{Y6_ z(ZENSEBDt*`!d}1hAgTAu(rrNAzO0nh?n$}=@#&-;}#FJ`L`Ur?Zjt~z2?^b--?5Kj&vq7*dVI2bYqa8=Izs~_>= zfA&8T?^P}Cz^}rDLd|LpUR}B?#M4|u1BT=t)YLDw?%n~;eu1ha6xOCOdl3OeQz#4zv!~zxlmy=pPjiyti zq6D1qA_UqrAZ%Lwc8=kp&%Qvr^y|bL z4EEOG{LGus8}asUI@4+BfMd+*z~e+TA;!3AKtvqhfC77G-N=()9DSo&t0UY2DZ^7u zc_jM|$am%XADVpR=Kysz#*jqR5sY04G2o(%D(1p?c7-p_Wst>DIb>JI62<962I)aX z&L&r}c|g#$??D{3JamT%CaLFk7w&4A70q(g1pdbs__4Rz$4Q!WM3U!++ou-z@0&xlSsky?o7`SDs$f}4-&W7Kha8`?S?Dl7+t^(^ zLa0BDcCRTkyB+f&5B~9*MGY52NOg-HNoU<3tGov|=w1$AxA#t~UoaSm-rPH{5(ML2NIiJAS@xXl1W3Bb5 z2P_Si{#Utu?PtFbm1QhCHo=K7o!DMea7%9#EU&N5PPeR@GoSH-Ymz399)k$$}x>haY5wJ^zNsCKb{H10`imq=YD-*U$TM@l#Tb>epSjc7Eb29PAt2;PsA zL{@^xKI1fvU5oG|dLmh3Ga{oZf_`g_Rd#ef004?^A>o8VfBIMeoE`K+(4!i|NCF=Y z0CDgP7z0N{toTB#y`d38O-L!5UIu0e=`zYlxQeRaF_bb0KymbVdr*L=h{e@52Esc} znfVgUWAl&6>m8UCQfzMumj>YybPpqMC>}W~v`iR>^>oU_PLTS-G7ldLZWCb{VNNwt zozD1lZF(+H>Fq1MKht@ z3X>aICvmbJ=OVycaVjukV4I(^L2G(Z|Eg4Mx`@c1gS!>~?RdWHU4+uo!XP1ddQem( z(^l-7^EWYHm@zy|VUao9WN#ArY2iWjRQ5`_)D)X+mu3(H z6aquX$2EU7-FD<&2uk|iZToVesMrXH$U%pazCvk@v%A(t5AfeWNf+Oa(_j|00WA<~ zwN3d;;a`zBrU^V06(Ci^`YK-Fz1^E(kQxIejw0w)QT}I(W5op52K+va8QN#@epV&W z0lJMj$nt`KuNPOXANTq`@TLa$KzYoY5XG7`d?sn|uY21aDYD)b^_z@To$pr$eE2?g zu_kO)_E6m0^HkrF?>L@vkvfR)2v{APuhv}mzlr;aZ^g$IsNp<$FJ({y=R%MX%8WZ& z2bA6C0@0%huLhj~7N@_p`OaT{oCFHaM#STlggK?Rd%q)*{}&GeUX0gihdM!1B)|6! z;H(`NKLge>d3stl^Vxgox)6XopaE!XH#Azl<25^m)sN+vm+L+euAQqqRxdt_s3O>j z<}1Sz@Sq|Mn(Xv-^W9Taae}IJ!gzu3hu`i9;F~*|+d(e?reaE9lbF+UjAgc2HKw-E*{KKF4SmWh^*{q$|Abakm}vc14M`Dr4BDctI85(PVb0%TO~j>X)x(GBaatGAT0 zf@#lu@9CiK&*ToY8nBa69F{&d`P4cUf)|DOhNsOAiTH7`nuAgJAgjl`4E;OX&};aC zXGxY3w*MIxgEyQB%)~; z0?4B+uN|$H+}Kz1c=WZFLyf0pTE$tOEI32-*cSG;jaAm`5spIOGE4AVvfDT~shC)o7{r zMk4~MHN;Y0XR<0J&9CiEAdK}1%& z#(5TwdwFzOtLt6qgW`8&yBENn)a*aLOOxj^dO0im?I!Q~@1ECmmid^!E&*6*Ih2-Q z2Hk}=AoF7J!9V*b7`RGt?bz>7GG_jD*Ih-=nI}F7nG#t~2g2Qgi$G8FftQe0Eg}nb zp#P>3lwfF)ifTpsmc>D5F2E<~C@}D0%QCdWh%+PIabd}Iy}eTuZJE;?J-Kns9iJ$aM!xP{3CZi2Y_!7+{tFj9Z#b+od% zt2ZSDUuu6d4J5QCe>?-C+p%V?O0q3Xr{&5yRD!phea7$GtQDnG;*)^$ZYh)t9`PMF zOcCJUtR)K)_)$((#0Pg<-Cx0?4FuXuS&9fo9swY6A|DWyBzk z!ocN#m=j{WW(H=mu2dl=U{^=?>O*hZszDIU&d%?ajt2xpj2{1+O=CSi7k_7dYs zQNAs;0`FLWK_=5hnRfQ&;?W}l>H2Xa$4UYF41rA&r^jK`n|zOiV;=Im$r?F zSdBgC3uiJ~A)COHSU?Kuo0iMMM(majbzKoG=^LiuDMVP%;tkl1MKKR2yABHbLvIGa z?FDXvc#O}|MdmzRvpBe}uMPk?&K!hH>^Hk}vs&US9M)8MbZ@v*j5zvWJQd#< z`VeMvu(NkL+S|UE7fVs(Sh*o`C534?-OfOIY)ega-Tu~OhNN^N{%dM$NMI~Cqy?X; zqde|>%4HTkYdYWGNXWdvmEZQdleopfeVtLeOh0eHz1B`zIkO>G^s$8)?Z_Si`VYaE z9S9hdWDlMC1!K9Wt|W8irGOYVWbeSo>^ojv>fNtRCFcl{Eh~66re~M6#IwDW#_045 z`SJ5g+DDJ_N9)!ybP;x4z8ym6k0E*#*cqQcCyMhrWmlH=3kOB^PVJtZczIuVw}W?m z#|>#K9CR}QfDDVI1kjq{UB}=2k9CM7gFI-?t|^!u*t>H^aR{elh$^uTQk@HwG{H;~;`3-8c_OvB;jaPon(I(|80-Wrp1dJJxoFsf60MwnpfHv|!wC>B^}`4KlGo zt6|>v=%W8Aaj+Lp&GtosRAK)hDw@6&8W}fKHjCCF;uhcr*udJ$5da0cKAk!!121Ej zfC80%S>H(coFw|$_zH)n1j$l4b;>+>`^eb=KE)-J?YJu_V4{+O5`&xbA}%arJR99v zs2|8(Ogwqt#bN<&R*P}j5!voj+G!D~0g4qeROf(Ja3p;#h6KWLqV!p96zjp=h$bGx zMns;TG;#yS&>b&cC<`B`xR+aJF?8q?G9l97rSvHjZvtq(Cbq#39?FhO{JG#oUNWSb zR(*5Ixl`*{TO6)kseS3(yb^cd?uW(4Ko*f-?fp3v2S%cH`@F->0ogEBR6ZuWRPHxU z*B%ls+r3YXVgkLl#DxCysa|KGVo4B7;p3PD#t0zb*b7eoe+e}NhHCFgUe9?I<))(e zyVWNt7F8{>K7;zS389!jpDcz{0NFz&a2HYw{ADZIXdf7xKD^m7cuK(tu~XDwxC9(& zu4=q%+kOC_2~A)+4(28WjaN&VxG%2AzocTojJqZGL)YV#5aqsL6v%ON!X1X63E~>DtcU)b*@oTAkQU(7JfL1krsa6CVcn+0g(AY zgx(UJ>FQVgAuQk!2Jd0eZoF~a#h5bYgwj>RUE2k#;1h+y$mv%k37>31au8oKclYOJP_FsB=b?SX82 z3}#1s>)D#6&>sPBoaoS%qJ|1&H9F^M#2Ej9mCwn={}P~NLIdvNtMHUdS+U|5aIKt0 z|6ieCr+D6UDle7Ar!d#h$tI&aFCs}mUNKfGfz5~PdXGKelHOa2x@MNHKjiKo*R8Ji z7Q+kVywX@fN)&(ub;T#^k-8RS=qWB4OgvVZcyF+tr#`DTggHi1l1iP^QS zU8VT~xyZ_;-*5P?wiSYium;Qn`-d(JOeymgC)$vx__)!$ESDP_-F{{tP3ul!Tp=24 z(sEbD9pr=z&YkMm7g3<1%7hVuHUBFLQ;5=5Ff5nnGs#!vHr)|_@9oyEPuz(++&z3a z?ute_-q9Cgt9JszWY+L--t9I%ERJ?b2$mlgj{Secc8SOkIKSJR6qHU&0`{t<%e7IO zQ?ekbe$mfglE&5rJpCIdz1qK|>YE5Cm-0;I%J3{q-9S@~=B^TKx+ZfoN67u87CW2D zg4h^cLk<>><|4`lo~(iuoiVb3V{t0qjtyqOCANBXdnwRZ;M;_nArfhIj3gmHArog- z5I@d0xNl*&1aTR!c)Zb?x8Jorvtr6!hN1UGqs=mY-wkKld0RsNUrP+p7*LRUcB7gg z`hR_>u_k?RJJq%wk&d}$vFmP$q|lH3s%%TrlUNGl`7EwB zH5O=b(PQf3%upzcfEqY0G;f$_tEuKhJMfi*N^jIFCr;MA!%3A19p&^kA;JQN9``GC zarQ9Lt%j77#0LV9C<~FgAdat@_FH?@}vBCSlNH zcl*T1lJnX4`*8H=t0Cc0*8+~N5_W0&l)&=?$!#v%qakQ*%A3c38T136*q&jN{3Hu` zwvL?xDn-$A8T+}N^%R%ifH=goVd`mIHy&d;7IeW!Q3xQhoy~aiQlr6&{mQ#-)%cC=5!Ubp%&=wQ|oyfy;vb!&+_1Kv9n}+zP+Isqj&zSLB$)Se=%BIS9z1c1p4RS=qyEFOM3VW2PHl*m6 z@FD@ekw{6(ijs!F5CYC4;!+6R`at>$zPgC*Gr1^H-DlXdfoVTpCQ}>tranT@FV62k z@h$2?h#oCzVL6%$cu@ud=Xy0znIjk}+y>NykmGof*OI|f2jzDY#w45A+0cMl4b{)9UpciI+2yO|#F_b?WZW)Qg-AhP>ld zLj6?325(GWp;^c)*dXSIu6t)oPa)bja^DiC!*^hj5)7Q{J|+kug8R^%ub4Elc7f5e zaRPo7AJ$7c5Wxh(#T3Do^+EVFk}>_ci`s^Lvh$wmFnjt z=iYKG=i-{bewt;Ax_d=8u{vbb`(0&TLe7vO-rkn?iMT}SL1)P-$}*Yhuowm$v79id zlJ>v!0YZWaX1!+?WGgyQE+kBy&<&P2R-lY9{JX**fVmH=t~@28<1|2NMuFKNg5ogg zG4zUzTli)wC$yaUQE0O+Stw4?2SVSQ6=B_fSbst+{n{His&>7Dv~d|_!zH2b5#Y=p zI*IhgJkf}Ik_S_e2%!i#gbWWX8>{rEC6{1bwHc42-YvhKlT8qdxwaJ1?3NNzP7ml60icQ<;!PmGw$~0| z{v!2UFzdeooy8+*2e;60ha|R&fcgLERr_eR=@eM$q>0H37#1ApZ14&Vc|9&EvqK6- za^@_fK9RCZV_=hhY@sgZEU3)R{Fut{qX>~(2X=4>rzZ!SU>cPa+NX*g#5BV>dbd%IFdJ_;PVfhj8>MIsMwg?f4~W_fSvLZ)l}-z^86uH11$)=tG;fT1=O3KrQt)n#GJISeb1W6jBl{$jR2*O*lw5`=rH`T&r2I1SN% zuMP2>hr?yvAr{(C^to9t05TUwE#Rk0!V26r9q=?$DvR?ylj!-^0uKZ8Cf~rKSeKC0 zfxYTLdhZ_F&^-!J#w|hn6KUYt4q8|tJYZ@Yhc;UTd?~H8d61(BH%9j%AN`v0Vsv(S~;L(+kXiJ8x=3 zLHDZ?clv@;8k}M+e#5V|g8VCD(UF91n@UA34X!OFA1H85O7L6Nvj0Q(RB+HUc;%PU z&-pW!@udQ3>=U+P-_t=z+Z!U@a>F*+VMo z0!7`S!*|JL*dGefiqEeUSC4Ag16{2_?$Q?8@zUDOd|72*R!-JC_%I|t!*;0?JSG)q z4a_A@36R{|<=P(&%Mu(E6f15!>^3bJK9q8b7)wlB;eN={K+R8nO64Vtj76od%r8Hk z=-*R`O;ViSPH)buIfB)NM*)Y>Q1eyZ=hmC6h(?MPe&yrO4-o$53kpLQW*Lo{bVla% z6H$*y*#>VnZxh|s@?DC-#dnwcMx1do#R9H5Qe$FMf|q!o?AE-Q#NH4S%#bJZ47rd&}I`VsLeyBraN|E@B%M28PY zJy>&BDhFB652=;2bOwShQKrm0_J?s0awnDQdpVQ>eY_p9IgRdardK%HExFpFl*Ztu zk3OExZHwo4Is9c#z$<)>DyuG$l14k#^f9L|uN;CO(L=&2!C=_YQ2^id$p0F-2p7)k zA{4-bcrq`sEwBuXr@6CGq=h<1;2nGRwkX$)dZ7y$5hkkLtBWAox#Y!J5vnq>-#STV zxO9n(77>n0S|2wI2^Rw0eX;y~Mp9^>pY*PM7wP~)pqUScjqM4e_3Q}#%r*OIjfV==8#>`1x`f(cQqP9B7 z<5NF}aq%!tY+wJgurL!GeUNeWpR2lQ)tWMlyQ(wpGRw_2f28{8D)0_M#Tt0OYM{c;MyrVoG=uhlo4KVk->&y?9=o!x)Rl^QPHZlqb%pnql41Fil?!?SM)y$$ z39uwPEDFO%Hzs3o20A*a7<`Nb|MRu67dHTfu8^3Id3H?a+T|MGSdr0OLq!02Ouht< z1@lgt+%?q43i1g&E6bYgO%0oTJ@rAZ4F?%6as<2-$;lpy34IgWS*h@c)nCF;($zOT zmmk&(M11TSdthrHYKtJuLQ*|(@3K|xFqG^}#LbD7^KATybNX(Lax=Fwvmk*2Lswqu>CQ@^Yc4cIfaEMl0vAIbwp*i^5t2)7`&q(S z?lf+Lrl8-`jwgxYzhPmZUGFlUOvb@V9UoP)j$GhAmD#CtDGe(~k=KvAeGfUUc+!VU zq&jj(1)QQ)VdhS3szU4Yd6!KerH>S7*VI_ah-iG`mynATD_X)sNgt08UD0}LQZtgKwsZI=~C;JfB4IIDw%R*urd z-n-#7_Ef}FxBnVSpy?nhRfK=xM--og`Sss`cIal-2;lj4t4lAn86~slHzRrf&uo`W zKkP5M8JU6CPt+A;=NbHr4Ywq#RZVID_s$Tr87RPhFDLiI&p}f<=gO-f`d8^uOMHBo z3I91j@#bs+b?l$Yp>i`qjs(&5;PQ06MQ8-Z{nO*^3_UIWO;dH5^&7X&rQE^1yU4`NW_~6EOQ|Eiz_a(``X`qf!wt3|= z(d-^OYoqG?F!tx?AGr;@+`oM{|0xN9MZ~ocAV#bTC|=z9svOAecN!mCa5*K2f*rsB zcnxrl02{UXJJt!pB!}KB%`)jtxcdJ=%TKj&&~UOsM1;^9aOCEsYtoX9w?D^b~{q^DuaR z%Tmnu^2l_Wb5E~|jGy&ExwF;W_o!G4kWf1>5^wFAoDB43gnxuuc$~7qoZ)fXiEK1c zaJHlt{D^@Lywwo3=vWQZ$V+~dGTltv>ZuGYpRVh{Y2+F=nb);wOeG4>1-Ute zLi)c;VJX%pfY+*ynFW51Sn1mdIW-ToW2%CmTZEzz!iQ-Y> zO7MheFG6qVW&UOTph-(Ynb`;lQat3uJWbn=;FVsrm?%*_xeZv2yG--q5l!OY$r?d7 z{ow^jHIK~J^gIw@P1birbkwT-_iQ2}25 zS>{F}KS3~!f}Mvw?koWV>EH3$-x~3dU6=dNR$_NB{y1=SSg2iA<^u>jDg|=-DZ*fL zTCt6##U7zou12QOdbC6izZ!$!1STB*^);CrEo}dKrzj0^XSfvq90fj1%Ddg`KkdCZ z@~qyCT!d`zRo2>*AsU0K{sg$nyqxrgDxd8e(u1wU)l3W+Q>w3EkxOmvyOc&M5yf`y zq|H(1!M2wo>Cbog#1>pu|7J*InLkeV+4MzvJkBH!%tjQYYo%-wi=Q_<_9;MhE~3fD zOYIs!i;M!PmxJzCggr0?C=$ek(QNJco&kFuY8J7n?6k-l*2C020?|)#?yEeTS1CZX zt1mA{q!L!9w(-r+OK@}2Fe?m9Tg)yTRO$}W6w!1rP^K$a2EYYkq|73=Iz&&{W#FrK zk+-OW9I5N&%zOtvVqSY0n;43AjP+YjuC;R*Qi1{Ni zY14j0m?W0==iC3kwXNnuSyJ_W&NMc5=r zS*WR;QhA?hZeq>aq= z2*HSU|MCh$wU?5pL`fFOOqoF0{C-_sR`6p;!Qx2+geD0LtXP^`t2{i=z$q8xQQ7H& z0;M6r*u|S~fx4IBceDn=rUXKUs-2B|K^BxJnD4P6X%L1eG;fl1D%y&|FXa~sGLwS@ zud_|!FlJQ)x^c0)MztdK7!bLBu?3iuQP~7?WKfl z=%}nprb5XyW2ZCY0Igg*FRr53x(dHa8WvlO-Pp26xTpix+P*lsob_rXvD zcoU4+%9JP?Q}Y&$r2pMCc;SJO4H9x`V;n-J6*w{WbWSkAkN=uKB(cT;xVx;)o_F(p z4@2}pw7)-BXGK zZ*j&xl0;d3hU3T``miAF`P_R#jVeOkBoj$kRNF4W6 z=~hR`<3N%5VA?&}SrlQho|mRabuBwHhv=b3h+vA_3j{aH*^Uc6E{y|R5?!@3b=^RnR`v>CLDOe#tNB^ zdZ1WiK^2|y`Spv(Y<*t;^wCiiKk~l-s)OZtAw~>dCH-WC=CC`G`Dj8*$C#yc_Fww% z?@FmF3<%Jb7Hz}l@S{ucfjtM^Dn{R(Py|tAzqCC6NuFwtUHWD&Q*BQ=^6D`3WB-DB>F$S8qyei zqUiEtIgMUBfNpAFk_uaUjGkva#A!y+Ijq~I$u?~tuO%jzvI|!1@^_Fp)9Z?ZT9E@- z4z%u#_&;^c+H}W{Z4IbEMEFq}4S&`j&y|Dw z``3Z9qv|^xl_oQEfLX zpbcmD%?wd)Q%C9X{%zmQO53(Tgt9(l?J&c_`oZ(TvJ;FL+j|8MqUKRyLW@KG`;u3p zaw*$M9pd2m7o1Pm`TeaEp48*aHBkg zw7VQS$XLf9V|M@9g1|=qKmq5lqXdwkfOD?PTRyqPGs~u6d>&P1!D^jmmA_(TOOV_p zuLK;Jrzu=Uma2Qu$mSL|XEeNO>)GO9tREA0DQW>1fw&S}?A}3<%*C(O^m|)J5`zBm zwnpERLX1kK*x{~_3Co$FC<*210a1)SHBH=3?OW(MW_Jh%_r|9(pB5Ycat&jj`)kr* zLnO^EcXp5b%xjraS|e<{Xb-agTBq`Ep8>{dceT~a%wL0~RKxQ0c#we+h*3=2pGAGhaF_=ipV8#xQ`*%SY`)m=yXydwSjj( z>VLG5(Tgr@yTN4n9R!dGidKDo(*q#-3(ul6$b@IQm&=5%-wVPeJ@lqn*26GlR{t-a zrF0*8L;367q^*v)>Mi0&BL_lPA&VC**(^%IUZO_*5Za0*P0Hdye=O zT%xhau7!A?S=d8I|MD@NAC<jZjysB(7Dx?W2Rvemzy_kQSejw)le3Wge zZrd(5e8&z!RQ@D|Z$N;)Cxa=@1+yb&S9Njp#w}3?>eSQV4IwUc3x`z7F|8jCOQENw z;(s|g7}ZrxPBPE*5GfRNQ`4F5-Z0RtI7s{>aI+iaJr+o@G)=R}Hort~pJobRr@NIE zzUw|jqBgK)FvxWyi?0I;So)OsD9FvokuCMtU^SK|)ZSow5dkM~V1H_3;+#@RpUu)4 zT9c?l7$qiDQ=%}yq=%_da|N+O<~}UIXa9sV+o-hG3t`T6p*-|lXH+-nEOgEL@zsA< z8WnyB<=7xXT$O>|GA8Z!TpFvog@uTBZRmeX7oK|rWbX?}ywnzeD) zYmeh)l`UAg3aWYhYM`v7x9mZ$=Q<^F24v#@B(~5P*4&?EBgOQ`&Ftj4DyLPk9GYaI z+An7`PK@Y5Uvvhh{pD9LNl8a|q!Qvv-g!}a5RAlJYi|a=>8_z(#;{X->GjKe+BA}A zxN_&&1jhpKpJ$dBqEYFCos2~u02q({R#FSD+%v~g8h@MYZnyWYvUA!&16;Vn27pFk zNWU?$DS0NIA@}p(6WK-&6IuKky)BXWP@jcycS`^-_%;JCn+HI_B2tdLyN~oH{aBZK z4?SO`k5Y0blKgrR@gANLZZVhR%Qn3Hq%zQtNh0-t$;{)=sP|!OBPW>FH|r9QJbP>4 zL;7r)?1gHy=w{ZjHkI#0O9WnCyKWyCFst-VU+!n6Q1;Kh&_dL2B_}Z)jVS3rawQe! z8VN10h0?+@bn-);-x)^`7&q)o2uac6=7vNl>Ie2G-i!R{WwYGck2A(mVza@nad;k! z;ijGtzOXQlwD%RG8okUD1je^yJaKN}tJcx1nQ;gmqZW^={#Mjt1^;^x?~Vy3BN_f=e`0<_#jxI^wxV4dg)uy%;^l!$gh=C?`3{rvu==5 z1{rPuR26P8tI0}gz?6Oc)4ZT543Ayz7{ytN1!Io{ABxVJLXC{KRNg1ld3b0@Qf|fC zn~fM$uf$nJL}EE|9e%exSnrZSp$=QaNLRaMkdaZxOwlN?Jf{n|s9<$r5@`R_!Nz=% zTNjFoP1i#(sqN2S!F=Vppe}uqWjq_D9Le!-f9dT&J(zA5nk067wRx&4R-;llf#w%G zEOb?L`aB^Kp_qcmu|iI!*Qs3}c=^D&gi9M=RxXE7_$K@qjI?AsV{c+KCIj_w zV0c8v*(pZJAK1eS>K8_6>^&fH77pp=`?Vd=+lSVB4cUaa&YzKB+}evuMPeg;qoVp_ zTv3U`q(c2X107Fc6*~ig^0c4UqkZx7!!tjpGfVAqo;6|&^!Z`M_?HP^|FJxT%hGQw z`{z!4-X*&Er09q%g5UC8&ezXo|=fDG*>itasb%sl~X-_Rt z@iV%J{!aRit4iUY;0;7iDQT=;gt)VX4Q4yh%lbqjKOoW|Z4sx+XgSjF_vj${q zmu&@aC^|g_W<8FG92i6qwzOiLJCT2i!cgq5Z=KqWYn`310MX4j5kbJQjKx~51t}y8 z26?}_NpeL&m`mo0>?8CJ`V__mD9xK#P9XP$Pu;unE##}#xL^r8zDv!YyGookhJz1U zuNe}{Z=l`jD^ta%g3{5kv$^4gEljRq2DZW5n%o~H;zj>-6+Sbg9Ptzv;fdWNur&ej`XXQ=8HIm{CS9CQGj#k9K-CX_W}89 zo#U9yOB>kjjx0Clc5*xe2Z>Qyg`)J?uDgdO)sa}Wme97@{VWu3yGHYDrjSu@ORxUetclcg7A!oHd}0kg7Tl&l7B~GaQa!YG&1ch$U>9!h2dFeU zh>4w|bS!5`X`7Axl%p%G)35SpH%0R`Zg|J|@Ke9xf})M=j3h?L zH;Z4ay)G6s;jvs4AD}O?Wemq7sx4}b6&h&>L7bt!{?b>BDaS0OG7+-of!XY};Q{+# zekka)*u>Xs)}6d?l4qVGfLR;5GV!(E-Gsu@;Q{M6oKKHT5Jkg+>Z0DP6$B*|_?~_m zlKpc1Rikx0&!~F~!X1b0_VAPK8aGqav+v60=6k~_eSmY3nvk*<4$?SC22O%mG1u6a zi+OidMR`Ku&u&YZmj~r7F)H+q8^g6ueuSY$CcmaT7xTr@ex8UNh5^CQc^#-toF}rd zKNIiiAgB;GcLd5s1YS}q_ZgZCzNS5+y2~*zPL)IZR)(N~zN$8^YzvyS2eXCE96ylg z7A!)itEfvF?ofwyeIuoUZ6ivk@xvJYxjix2r~r*gi>JHaMR7IYYl$RlIdb`;rwM$w z=Dvl1{mKP<1sKbQ&*iKxA%gXTBEDwNM&F=nq5mm125adhg1Clbdqcds(Q}9CLS{D+ ztF!x6EkTC3?CPb`ICq`fcxyZn)fUcr2lAW=H8*Pu8TBhR)$5mRP4B}SX`M8sx`Col zsfw%nBm=l>$Pp+c`(Ye3HoZcE5n=gPrrr+7Z?TE!KhF0lhX#pOm{9YV`$kU8XUWa= z1rCWOva7NlN5k3D;U}r!X_jTZ9MHkzg{6{Nq1XeCo|CAwVkzYt7Qgz1_ z=gan9jF1Wk;xoMwdMUuH6UF*I6}`k(%4>O=BU!(^bgmDA(D5q+@DtW)+)ASwaXDw8 z9pmcefAY^25vcc*j6Qu+KpNQ!K{4>^o1u+dtM>z&LD=E4ptHIag>eL1trQz<%9rXwC&`9WY41p)+Fq7WNx`77Tw>k9`&W=8UNe?Bm~JXP6g;U?qdgA*2SZM zbfK64*SJA0Gna7#3|0UCltgj*VxMo1cqHFT9HBMppc=7q%+@?X z+Lj*5kgTBq?E74i7{nMpD4MKgCp`&qJp}~d)76k$%QqW?6qs$BF91`|PKz(}H*X(S z*^lEO)5}AQa$i+`&Bbq~67P*d)Ab70e0h;BlmYSje@@`KQW+k|s_CqmBVYA5i*ku4 z`zM~@{{u4f88@LV4}2Je;-AlC4-=~jH`e!(F4HpEnw7*K%hKD&;uNJ)#f61w9pd~N z=e{+_O@snm=D}_(H4|kHzF%WPI}nAC^}n_D_&TPa(@~RY}n|ak=EX zW(Pciv<<0y99>QVD=J@)ex&|m@6^oO@Ht_r(R4pU{f=hg_*n0^Rk}H9Fb>3Ehn(U_ zk~70XBjamPFFnL*sN%okX9Pp)`Z2J&Ly?UAO%*bRpsmX8xZ`L)(hDq&p6SDbex&#} zQTrC2u-8Z61xE5bEY4D`q!E$s${_q2ib=MEQ+7<^QtdNx5~}>cEtUKAtZce)OeXZa z3!ylvYnz`)78Y{yT+wwg3N^Jl^;fzi3m@mmJ#mjY`|BxKfab_GH!M^d?fJ(as!LE= zR??u$_dT2-$>pW;&a5&UwpL$OOu7*RT>hQv?1G6b*sHIL!RRn1!~xUf3L1(Ind}uH z9@xQE+mHW3|Dzkj-z2OK$1rb`I`NkCM#kf;jwm3h6a~4s73Wj&8eVbDcHgR}$Z6C%5OC2VVyT~$=RM(zw)fWjaYVQuvu z8W=`Q&Uu%SpLaZo8ZTb|!K z`g^mBkuZ3H&Wvp`g`jc*p6$gv%qRj9^>r3R&uj1zjG{9_*e==la5tRW)lNP1F_8)F z$Cv{Lc`aHl=)d6(HmV2ES^vd6ybKCnjyWNwQ+2p}smWOV-O9#Yd_XAa zs-#o8a~4)Y9z*>;KS0*0R+>m?@<&urI{|^!fY>d5UR2(V+H@Mz_REAldhyU~^);?WIuB=H#nrgNvX!yFGtA?804L_NzcM#1UD70H zhQ~>vi?Q@}&CL{Co8{6~S$+}q&OFV3f}0GUkvyYXihI+ieG&%V0RisquE^h2y{z(Re%F=c5EgeG(PZ%!w(Ge{|^-UdSbn_RoyR z6$bIXLlub`39r+W8{$rov<%|C!pN2fXUL!hbB>#|dYR+>VNF{D2#o}cwdtk=6_+LAKeK}nC2>H8gJv7{Z@ap zgPWel;PNP6;mQHI>*3NyhkO*;bIxGWCWG|FGP*7=A3^t=1b5dY$d05_`N7GOnFX`ucE?vzVZ@b{%ac4h~;IAKm7Li=4 z9MC4BD3-^xM(&aEu${m1^6BV(t~$*fT#fTLs^n@`Ff&A}6o?0GJRudeO2+&hFcs(+ z_%;)bQRjj`^a7Y;*vCEqMXbMxoig2vKRnMdFrCmyavKtvToqQT^@KPx9sLV1TS-9v zJc=>uwdb|*WfUOmu#U+HJBo9}8P@$hkRtjvW7{)=^g^_ELDN5*+uO+-IjVWm*<@A! zGt~7ILL)bF6ynfJX9;(dhk~B#Ldg~)C0<$W4dy6tcS=#=fn#+sD*a^LbJ4_|4-HqV zwN4sUa82%{`Q%515@M2|iHX_b+J_(Vk+XhjWi1CKk7}z!X>bMUIlz<|Q&^UT(j=9^ zZu%Ka75~KD6+a3lQoR7PJni$y5r})XwLos*LSu&z&by8K*&ZTcu7pS5FtFWZAA_ko zpwlYCTOGK1qR!YB{QH`KxrJ%0h~e0cscUCmS4P*Vc9o)JPIJ(oK^A9OuB~{jU&^kJ zd;Uk?6YKOb}KhQe?emb-ns3uS;V+Fli{pEQ#ByR7ZNi|@a)VaeSsd^d% zMqi4(?=glruRqsr4hq;F;ZyZG+O!U~R}Ant3kF;yZDihMOAMi-z`e2r1)>ZTipKjs zyPi`!i*_Qfg@&0>+1yo>*>bq_uZ<%$I^NBNI0}1d76IfVglSwoU{pPB)IzzT9*)Qx zh{dWMDA!VXl#u^3u`@Y)mdVvkD@s*~Yp$w6$D@NYe6dd;VPuHBAIGB?Ag?Pa93;xr zylE$MY;H_PjkIb?dwN@N_FL_g3Jf*vyv<6RB`(pi<&T^lLrFI>Qn1mKr#Q60A1@JUvjonexE6_EkRAZx@0{)4W;j@wk?5{lX@zaTO>?Es=< ztaQVguvPGQA&-U()D@R%DNOZ8njW$QXTU|Kcb2O&{*VbQ)V8|RGr+8Y-cpnx_#kDQ6 zm1VLI3`97Y_Kc#gPqXmWoQY7Lh)ME_TldXbBag_bxFUZovGkLHWUN?KuAp9z_@?|%Q;>i! zoDb*9zhwOFl{}K185Dk>a~m`tfj_PP+4ml7qTvwiX&>q zQWciWe6Z7AF`S1Zh6zcmg2KQrFT=kkI!d5=oUR5xOFCHZ^U@)X#h`k@Y=fzQwm3;_ zp6_SKPvPAe+Q+JAR!|Wic6A3RcvySfGFYU@l6I%FqZ%<)FI0p(VIdX@UFE-kI=QRI z|B#hOxf6U%;vkJYoGm(7;^JrD?7W%~#DBr7AW+KBWT@e57A9sF(qXbV(`)@Jz zvbNHL7U>rd)nfwtZy&1qHL^{ly}A`l<1{RKtZoJ@BkEG+GsLvtJr$GC190|-IC?wh zo0qgF8^|F0bqU%j7g`wGEUNQpsOc4k9~P*eIa#=h=7tr~!||pmBsr0Z`UVSTNXH$q z&uzFppl}Z*?D5A82O!dkMEWy@DeH{wj-PA!#-4KDbN=RrFHeDE=zCfj!!3`8KeH|A zBJJW*$w@OEynJ#mr|3vYcz7+p+g(}6Y7oN9){w8z;9%)2^-XdS98>N>S=;>)YORIC z5Wu8vd&(HDzb)KBb^tTu!{%EUZ>X^?cAHPJjDd*V*Z|Y45nU}WObVkv)u{hYtS25I zzTwg=lgz6K*dd_qG5t9nGp6V;- zFWDPk5O4zd@6_8+Sq_@e{Y03oE!)y|VW+7)sod5VRUmdBA($Xk&8r8HJg1*}?Ki(O zx8K=-78I9$)dmCw(){;||6df}W@;pge0bGKsE8;+bLc^pAo3Bb0w6wwKFVw`>_N&k zf^<9<&~<0DQ5tq7h9&u`0$VFjWHS3G9E@Ew$ksS;Dag z-Gjt!;#bp%Da8rdLDOxP_D>fY1XloWRIC_izt(VkO+u9MNbrxLwc2dWj4(#?6wGwA z1CGF>bDb9bA4FghKtdURT`7epDe^N%EpW>*yjvNf=1}&(&=hh?HAXdS9*6Jqs|Bfx zz`%h$TX#B!*5Uu?-X}(WVC-;+1Tg`x6hG?b3>>vlt0;2D?L@quH?Qw83-mN;kZa@0 zxIVokGB|zswQLs8;m06!6|=|q3-;>+_PTmZSUJ;IvM}4r<&KMm2*zfTo()e z%!-W7k8FvA?ja?$9`geHSI)1z9IvdWzj`}r+`$#}8Mpv;8&YD!O9OqZDr5$k6P$+* z+}MJ$ZugEe9NKOSJsa^JZOvWAr~WmoY;7di>K5@yrcq;TZEhB{sytFR;?F(tJeRC# z7Y2-j1&KF?{h1BT`tzhJWr6&}Tp=bTOmfi_PSFpf#LYa{+1)t^c?0i?)^BsAm>1mI zLUbexsEeusYJE9BjE`++DC%LE4ap`19!8f~BL{5#?h|*ZYhcJq_$@5SW`1#4(|b)q z%jRIHseSYzD6_q-s4~7084W!Q}X%!KYCxIN0fe4xUlYkWOpPnAVR6w3xN-|y`hiavWBXP z*T#YO{m+hl?$d%c>_Cyzj8Zm}Ojft_lC&~!mbhR8qe+(&26 zoiQx*Io5bN3cJw>i%mWJKlY~sqIy^MlsmJB2j2`^LhXA>2i-NR5Ngjc_ENM4;Pl^s zrci+76NG~Nt{;UP~hQakODxq0We64@D>)XnIwXbgAwVvL+X)$GuS zb`B)`-Uc>kNHd}dZ$8*>-+DPv!u_9=2#evU@d1FG>UYjHA%s5zO1P76=gBV4C{|*! zFBdYc!hEG&{2kbl#}tD3`_+CQFGfvoRzOK9voS+RB)3%&~K46m2A?Kj=O-+V9%Bo%?6*6VoV*lI?Bj z0Nm~zl-Og`4XSN%^1{AXCJ)j&1$(_2oMqr}AQz(nW!j23Fv^B0qP97{Pjy%dTuf}t z*9l+1gfj%TKO%%cV)C=$k$S~ocsa1{I2>sX{TVfV#zd#9#+s0rj>MQr_Y;_WkI#|u zruTT(qomKrmBS$(0)uN^{`2=(|4^L5zXo;4CiwgI_HUW0Gf6b(3V8R(`)P}H zWilHLq_<5J)`7aa(1r#*;E?P`E?U^UMc9Vho$ zk4B8txtye3;Pr_?Q8$?Y1{dxib2NJS@pn>V{A8lQP4S{dEwPz8ioo;k4S%vY*z+Ud z#^rEhu|oDG9_?FHkKMgA>md%Nhmgy48t<4h(@rh;gD1!#8=n_;ks037cg|5QZulLOJ^zPEQ>6GoP$0fV z$ILG9LxJlS5W3;)=SN)%PxMhczla(Buhnhor*&V%mRo4 z*v6W$w z5oo^jx;+a3)F2syv`G=3JB36|2xdIlH{k~g@Adp$VZVDUI!_v8U+%5t?%d8_MW<;D zFCp0}F)B_fs!^mD;Y+NA>^BY-1ObxQMJL7IhevxY00fBbb`@#)oVehVi#J8i2kufW z2D0cm*eG#C!|N!XBfw{~RP-(^z1d9zo+>VX|I_>FSm&}C;4%rM;SgXOQ`&wZLTL`~27`r${5VB{ zdv_1e8^gIr*ePM@a0uC5cJmv7v&}BoH>GYWwR6u;whj>Qgds&pw-21l`?D0&s4+CQ zKUy>5;L|DQNkD_(X=9u~0PQXkBXz!~_-j5MK#`4b;a z-pOLL2}P!h&vBLfx3Xx9yR1EiX(PM&l*Xqy-Joi_`)#j$-iU*i<&eqY>jPSpJb1(` zJf>+_zTQn85*-x>NjP6hw4am^zBo-q+Zi$YgRlGC4mw-}yBs

    ~w9D&q7RBTuEg zO3JP98o5Oew-ycH=IsJew8lNiq0PK&zsbd`fG{P}Y`bt

    j!RH9*LKcTLTo?8n51 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

    j!7O(9!AqB(0WfC>$I7!zb}l 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

    !_NvS*^X4K;+xHhUsx0*ZzB2q@bSFMjH9xkZ{f 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%0DJUObb9gC-EajM=FqF|r3cxnxqI4);MPhDL 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

    4Km`y$(5hw;&3kk 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

    f%%ndOpF4q4E-+dO%{vs)uu2PVMuj!^zhEoPRc5 zX4HA1mZ<&hD1TSb#{%y-0z=1R3)B4N!~pYDtL05SNe?)J^5;r`Mn$fj0VTrhGP=r#qR{`C-^41 z1U>N^X+fjlLvX?=r$h!v-<=H4j)}my;%90lxSkU75ggY5b$|+H__pQ7A#Yd0WAnqq zUgPV>3)1EH!|9g^;?*w3oM2>l?2BH1+$}sub&<9V!TC75-T#eOwXc&Fw&Eke)Ax-v zyRqpI-^CFMD_r1K1Q(%qZbCi;IlEZT5tbh|2ynO_xcJRA1J%TT{rB=5;II*SH@{9r z#_QR*JzjlB*;*FDM1zx3zY;AoJo!=c`Ojcv2`0-ZYyusDB4on4GlmNM7IVnoLC`uf z?HnX5fx<|qldEyDU;E9hL0s@Fs~skSY53lk_8_$%&bG4;zfl57djK(E)}gq?>s@7_ zWtIDnKphaPD+zv#M0|y8l`gp_>m4`H00O za`*5kAaQTyOdD@J=l0up{&NI#m&aCir>WnXvtoxsu6>#H)u$=veYb@%^9KrZc-{z0 z$QZgU8^aVx`B;DBmFy}pt-dqT$AxaZ2>mXe+A)SlQ)^~(3`0)rG}OMpYROg^s`DX9 ztX+{z>}U_N`%aGFt`hMnsZCawd*9J45z3)b#$8i^?e9lIL-#IJ2%kJZb1W~+bCm!= zwRwxIa7AWIjz*QEqy~3JiZru3KOaRDGZ!7_69NP~U#$;k+^I0tTS^q$@=L;GAPa|G zTFz*nyf-UqxwLZ)kYVsA#1D`AuSrx*={{`v1*&S>?X7r!=odm+ks1zzUfQmov)P5% z3ss=asfRJ@Co5d8>!X@*yvx65p`|BH{G#XhVSLfdTe>ap>|=R0LO3H=V)5u~9IuiW z2|US?BW1>v7^$E4BbB{~ z_1`3~oX)<-sfPofZy8qTCo2qX^+zhgaaXoOfM!ZN!N+3??(hPlXf<-*{5Go_E-FOk zO9p*GflW6&fLJ=jR=qW1KAE5=ZXpo}4?=_08AShrv|6%161wZ-=pXAY-4zJLeA_@< zNK;68Ns7eHVMPYisb(9*aTYPIZHC+fT9TmN61~A71#bA zyoI=W)Al1rz(5{G29ZTJID!mLb+`1u+n4x-A%HJSjLOm`&Pl02A8KpWdf-#B|27+l zx|T?5#=6;Jx%3%kfdc^tAO|=v_62VHnDDHbw2SZW(6%*e>G(;ax1-#?&+KT~;6%)w zI%E30i^L-o1O2u!HCL||=MykREY&48KJ}lTcF-x-*kVzk=N=KMNFQJQz<$42;=yBA z$9d=w%Rbto)WUz+M)~(*p|dRz;nxO4Kw}k5|7cKEgE(Mj4ze?NrVVXwrlSTv8;J_4 zlf7<5tkXgvyY&~@_5En?OZMQ^XU%QWpZ-Iw<{feObI^>98qiP2=j4#$BE`yZ(Yi%m z;Q$PH|DSYDddvL(Y+NWZiCmKs+Q-;kUeU@@3C z0;>6tsog~oUPfVpODiMVmNNhc6qlYrXIjF6ZpG2%|ZhHrqsgD$-Z=4 zdE%Q94U0U>{-6QBaA?TKewv-G^$&;#aH<@tEN$JzX_9`Y&0d7X^=OfZ9<(lVAgBhj zf7SFAZ}O7MzS6AIP;Fcj=@pDn%`3u=ztCq2vxq>i(-_PX>BiK7i&=yG|zTe%%leXco(ghLjry7=spaD&-2 zV@}w4EB*#eIEGHdNjT7|0TDo7VJna zxD)QX&smJ?x#F|XnvH)yGZVO5!&7?Ys3tLslU2;-vCBvQs&YNlU!}az3ud=B3){JPuO*wU6 z46{ivj7XH_Ep)cq|9QsI!TwzQG)<~dp%BUeHn=57+W_h#i&9-cGtKeg+FmsIhc1tc?Bm8ZrJG&EFnty@De576w2*Wrz;5+9&yy+?Kr) zq~weh)8;>Mc(dL-D5uB02>011 zg(~LVQ$@mNC~QMg54#suzooCSJ&eC%5m2g|ahKt?a+rUJ)vsjzj&1TTEZJwB&x}uN zJA~J$y)1dx>Hw{bt;o$siasvC!^3tl_INHLF(6%0obY853S;7cA~tFHww!V6Y#nI5 zp!0KTCF8eOfr_soTDZRE&Boh~T=|7Zkqit&X`6L9oQvK@y8p=LZS%qxE z&Sk=(h<~Q6GVc)cB_SPW#HbbPWQkWZc=`>k}*;*y{r@#TLKA-6Q`nFaYBUrsS*1x3(p|FwJgWrJGt`U3vTRoN3wUfoe zY`XB)#6lbrK=E=KZl^k7t%5?exy|O zQ@p$#R3ZOq)W;EChuvuW9^N1-K1U4^94zWj2;p`Jp|Br7u9hZ4B>5M%?+_)H2Alcb zp!^nMHPY}oSNiEx8?6WFbp4nPUDj6UJV8Ifm67&`N?rssjfh|}6lro>Ev$WrJ%~;e z0q9t}$ZqvN7ptoVhNn;bfdXU$(=O6SFx~P78$$-Bue_7S;bRzB)HVVb*Dtl*An8y< z%|ROTMeaeli* z8?5hCs|wMj{1zs17e&;RkES$}D8-NpxfrXt9-Wo=+TMo(Kvdv0j-X-0pk<1{J!J$b z94m|g_BwdQo4h$H9uXqV@~3RzD)Bt(B2DLyKE5tJz%|*vpE^x=$eVhEWX!=5fZXjf z7`7I#P@#hJu;XZsH2mm8}P@!c)QFEB>p+MD}m%JM?up&9V z%aOq(=^_1NuNm2ck}9G6;&rarjE?goJ^!m`ME|07Z{R1`(Jb(j=*WUnn+U;#Hl9Cn z?1QNzJ-RumI3hzX8EGLsKr4LQRm-3607?SBW28D+eVfvz?FuOMwMKT% z?~1L5QsplVr6Oh*e|L9jas9|g|M5Uudm?ui4UgFE>u%~;>+iLj>~3s;%HrZdTObL$#&vlXef5qQY$T6Ot}#jv2!VZR*=5 z3laLGZ+CC$vIRZgv%4IwW(`~t9(+0du-E24!H*kVcb$aLz+$Y)sW_b}^5X35LjkW5 zs8bk;+ShY+{j3c!ymNJE5o!BGJph^g4#7-Yau$ar8$VY9Rm472EA44LZ)#}jd+wXP~qKCrtC32r&}C+CD@sS z_62Rx@*J!m<(@T3>&10+7!5h*0#?Yn7Fa(TN16LT|2{@%xOaumO{wO)Hw{05S2%jCv__!b6xt7s1GjpGM z5)8m(r!ye6 zJP|txcWN zjDr6Bdw$umi@9r@=K8ONGdr}MwTR(J{Eh3#lCi`L5xeBz=X5WJ4!m3KlFWL+pQ<-I z-*8O6NyF-*UR+yF|C*AALf`2KSDgx0i(_(sP|_PvwP&bK54n|&=9k=Y{NDOqLaSGU z0d5$XpT*9_L@}2z-r8Ef)2I5kSCd>6q+H$q{hD&{VhK5TXqaM9F0*#sVytoyl_~we zS~^l^LJ%~5XU@@%3@56WFU6W);SrJ0%GbSPU{jXJAlag~xCya%r&l5$6l%t^=cU$rH874}I25L>KKmY#p{{5dW z?KA)X|L?Mj#M1k(dVDDkw{0sycyy(NGMWOJDo8N!8m#Gt&6oA)v%^A$*=Y|G^)}>5 z3=(kQ!&zJ{9^&eCAp6sKaWH|kp?g8FMcza4^GEDv4xPKq2;0+a%V&bFtud~H45&M0 zB3Kv-Bs~}D?*l^qA0_A_6*h^>EC2SAwXR?;ns@A8OgO0%GOP09Z0oLl4|F22P!#d( ztx4QoVbfPwXWu9N8w~m`HDkSqglLB_R}Pr~C0y}aPYV;i=#M)v_#b_z3^iSU z(B@VSfz9hnBSiTrSwY7{Fezs&2!?blPrRyrlW`7)#ryhg1J1SHCMm5IeZM?rEagEZ zYKf%I7tXG#7qo_gCkcSV-*P0rQ{-W@}`x z);#S=83meZa_6EE7@Q~dHvb!oPMx97%*5%zS-k82AF${ioS>)5owRnrL%(%!Z$0Dd z#bxrS63IFia;wy5n_=OfR|{|tCQ9tF5~7egCE3Ni7~q8$<-RXiWD#&LmK2E zS%_KC6Z{mf74Y{c+oAOFP_g>DB@%joYrVfOLIf?JcCfpnJCHhbM6$8!;sQZHgKq>4 zSG7oix5|MnI>L#yfIiAoMRb^P4BEWl5MzU3VA!iX!*o7R{`D*cj9z*9v?UnscT}`w zB?uk+-Tv2SuJ}V{LNGtVD9i86_`IB`cJ28F__grz*vtUQyO4-b&dQM_Qq;(-=52W- zD?B-4qi&Ldq1ov6`&Y3)_OjK!uLVI&Bp`9n zO5K&1Fv(@~Zl95kicQ1GhD)d3AqDAzB`XsEi+*98#m}7H>86Br2hxSmOoGYF#7uJ;$rtkHuq z1IbQw3KH{qRR+5CYnKxO8W@xMHQ2Qw(l$!R?crA*d&TddbEjpDXBtWXHC|Y~+1vx~ z`|SYp(g0E7Xp@QU^;fTG7|E_cq*rO#t^}Dez!2a?0Yt)ZF&q?D;o+B;`Wojh9%pm} zDU|G)&W?R8!kJLz8Nwrc3sCqAdTGVq{pwZY@c?~cWrsBY2zNY@LQ$)Ek@F!bqK$CM zq!_W7%bpHA-=9sQu(@Y$-x*R{5q|f^1j5=S7qEw?-bNS=Q1Wk*6j1L`txgT^;tnl{ zbl?Loe0=?io9(Vb2><>kJ|&(YzH|#k?0vPM8>DLR!=A}190r`9Ifc8$P5QI&lKzv_ z9SpSLFP)*t0w2soIWs~?t&Sxi?U9{xLJ^U4G{3?|o9dqvf$UufLCY{-(0xb2jW~Ob ztbfFMQjEPO`T;u2UBeaQz`)^hDD_<85LQkZdEOsLSZEhDF5mQ}R07re3RRmsOG==+ zbTr0DFxC%wowNszoxhaXlnnp)OW*HfW8sXaD=b#(M#CE%gb70UpfZG+R!J|$S?rX! z%E!I=XXO)(I7P|JCKcSb#YV`mU{=Ry#3M>%YdXCC!N@NEXYwF@|eXts69h8>K^Q>%bSO%bcadC5T?;$uo}Vpj2SmwhG^h<*bzn8jF|rH@7{!% z(9wa2s8z~+^SXML8J&LB|K^)xo)(J=0zhi~ZPzc||EW%R^Q)88l29^xm0Mi*+(G3g z1;5Cv0epzpA_zzH5}W#~hPEUzWmVm;3lHu|71@U7CgqT_)nS!Etli5DGM`lNbvY)sX z?*)VR3C|H$RE2h6Ny02%gt)6+LdOOx9Tvv7O-VHImoPRK5iW4rew6?7t0ce)*iust z>Z(uM=FgfciAvUM#QZiOW47!_X)cfPOmEKYE7Za|7JKYEsXctl`Tzh(#xIV$-NxRQ z7}*=Z%#C&S+35+JvBxC)QyOa!aOACd8z(c9`X?OOl`aZpqe=+Y zKK%>VZbSc4q>Y=T1%U1gkFr=?+afJK&XJr5JzP@d2l7B3lwhdO-y2dJ^%?Oo1`@ti z;pLME<4{@|n)+Qn3NnY-g(Jlynq)IHOc@+lvk&nANX#}v2|V~Gb+xUyM!UEeJEFzj zG~xs{exz4G_F3HumSje)U;WCx!Si`*SNbgdXRM(V*<)R8OLD9ReZo4}c*q4Ww6$DI zXBUe#`z3v?Rn2gZ50vPaF)iaFJ_oz@0BQsZmcZ+7fTV{A)nB7`xEWb`L5M;|?LML9 zv??wL0tjs?0ji8P!}REiWr+3RxxH8)V8HSX<>p5zCJt9o-))G3vK4~!cNx=R@+`bt zhmP$^<+r(4_m1z>HMfYYl-PLhTI0~TH%pzZ7x#tFu$WNBHrO876zg;m#zs2D)H>hf z7_9(-5aT)ubxVqpO9$;f?U+B_`;hT}duN0JMn87A*3Buany~Mt29*FA75f#FgU4{% z&)UEKJ)IpwfXn~?|HPuB|Mtph)su@){9w_wnBoO1TxwsMg#Z3$y)1>YFW>*@ev_?d z>%E~agN=(HpSl8BuulQCwRwS`Kju}TK5_yR;~E3G@BZu`%v;5k-BRqVpF}GeVe+mW zhq#nCg^%EIirYJAcUd)G6%;4ZaIk~#`8l9X`nSv}pGOm6ix^s^DH5@dWlRAN`k+ai z%PL&9r35mifJP7wMJbp4i$qDoF^EJj6&+%BiLtd~_vBi@01@sxXa3HF>qU=Uv{p+|K}PRcM2D|0FD1M7CZbX5;@ayfL?R~|CldjlC{r$FIiK#I z#CnlBQ*;3=^&guLOgtu#(cpUq1)S<|B}ejE@a(?6wTK`g5@vi-v?kuVXY61(ZFjUE zzK;e0rY$c7jH;(9MaP$VUhOL(R~Kt* z$ffj+Q-gV*Z&TK6==m|-t`X^8MZI#{8n(b$Ce?2^k#F&dw3PA4p+Cfg@JTpGf#VPt z-jAIX@^y+WTq2k+;1uxTg$8C+oCV*=+*dTjXu7~NuHWN(VJX;;9@}N;LS3y|u}Wos ztGK(!=Hgyfe_13No0l{Nu$4tJg=lc!2#11zS*0^AKwL)xm8^ZzIS5c~YH8d}Hc7k| zkZ@WTX>W#OKF2GzC{?F$IQ!fTP+&ddu`fPBm%Y5T=V{~1N$l4y?kds942ME;Gj5yx zROcp)i=0T^`M-_m0{9R9rHa+-1d#GqfLQB=(9@RL5DcS8h;BQ3I;T5sEq@}7pCMU0 z;0@5k&?;=Y_^j>q)#<_yx=NxYgVoj7a9;J+Z-O*%fEBO|RqR;*YtwDlqub$nIP;Uh zfVvy0RHrF>#Y~NLp@Hmt5p$`Wh#bQs?2lA6CW$`@@NKTu3HWV{f$e2|fvX-@SPGM1P zdp8L2vmN?C8P><6QOptb-ctdkCOM9Z;H+yN`-j8^GoddGstm4DUS*fVX^ilSmLXcY z-4Kwclx%8=t?O$wa3+<^pRr2x1R}Z)bC0DLkZbU)`L3h*njkwy(h=u6;r;BhWQ%gTiM^(b}>?6YhlOlo$Q7GB{g+}eiT?0G2 z42mS~R@K1=x_CB6XG4f6PU)xQ z+N%zLbh%0Xb1q1d+_kUpep*7#;Y<3yNh}wXigr{ugdU_C_vClJE{Zu3iG1&7X`hhK zRFrOb>kn00h%dP$f-qyx^cCojI!7xY+4g~FCr`haO_HruzNS_ghdRhT=2#owI# zKmV@abI2f$Qz;@H#fvl+nr-4GTH8c9PoiRj_W8>H26kL zwU!$-oXc^`^kEv!wL};P7ZNsoVIo;4+DfA!7JhveET~_;I@>h(<354X$YOPjSgkQV z5V3CN?maLZnwa4coH>i|Tpi^=S7_2#!w)E9ZQ!{?1(a@t^6%}T6e5Ea5xmUH85!t5 z9*5f}h0c*m=B%s_?80?SChCa8W|Vyh_SE4udj;dR@4rkE zR##x+TWWm2wWR&}SmLUl=C8B*ldwYS)YPKE#YPY@0?V>jE8nm#!}ftbS)Lk<&%KF(+y>Be8DYHB{!AN8`JYgLf#Z3sOLL`(@%>Hvb?go(44_Da1=sZ8 z5(>^Fyjq)J-u?^>d;h;qt7#VwLP`N!GZa?|WAr1_{jUt!VX+2*3E`F=iJUQOdQ9=z znPc>!kkaq#laW2NT)yO;fHT2=K}Sx0#~8d-ct_$n4%T2Kqkk(LaGRS3 zg44}PC8Xo<+hW>}>U#Bb5K*wHOL|L-B>Hs<6x(1zWjTnN`(Z*Sl6G1kgD zQqvR{COp%EAGZJA*EY(2LDRNYn=DmJre27YBH7sOa1J(8QfKzxT?4V|biSna`fz(S zDwMC+QK`}tu>2W&^#hnt)(5UR$&48H4+5fP=4JjOYRD%nwa{c)8qurC9KKSv#OJ(Z z2015kuXtTpK3q=K*TO+y^Sm^R;~1GA%7bxtZhF7=GB8ZkgTQ*}_F+&6c&oDH5qKKW zwc+<-d`eOvt)31$FOpqmsl(z;2JtsJP+t~TmX_gs8Tl)@iFpPFxFkxRk@ z^Vc__0gg{D!*cl6XXOuF#%z;x$IfN1|Ns4jqllM44~Djlog+nC-lFx=%}bvgr(;xW5&@Vb+(v zFU8M#;$9qmCMhUq`#L7U>VyGfhtn{hE1^fK1Pz`!YL2qKd3PvPUN zih6cHPd}?4_A#~sx`>D+Dg@wWC@Sgg(io#VW_%$$7@wK!n~(#8vNbQYp-$gAiw0n8 zEZhu|cK@bRfdpn__6=W6X(zZ%9ec3Yz@;s5r{e$jCNm!0R)@UlvUOFnBznOC!5XE zm3dFaqYkz6Ts?$5Ln%?Osm`b-mm@W$FNiVQ40kL!|I4txeIJg@0XIex+j@3iEp*op zF9io3Ru*S>;Xv>YCz%DkyZ?HJ5FVXsR%S~gG{dCWe&2^awX9HOmg8fT(mvGl6j@p%7oiA(xau? zpdCMUy_D#&&jK+n!OkEyaK}K$G(-1b9XzCL@-OBuvu!h^CA@)5SguqkiL z10824>_mQ;nix7H?=oA*>&F^3f<|RPe~baq#cJf~6>EaZgew~~PYUC}OK=Bt-`&2g zio#5dg7PbBi(zy{Z)N)~<)UfmG*4&xgodjn$Q9u}3{miEREQNffYE;OnOx5LBTN?w zJA$8E7}O``R)E~(4f~%pfuc-tN*6U`@w+6o3T<;df;`Uq<#IYJ|En z`XjQdo1V5vn=$o}SJ#*pmi{Ght-2KCXjDWE?U5((%eO$7?!&if} zq<51`bK{E12vCUXs;|FkLyS|%-zXx)4onQeSe1b2o>zEu&{I3zAHd+GceCKJ!Ck*Jvr(&2?GR8q8SVWxjQ zr8*AW3eNX~t*bAAkwoj;WV5$^350_lf||j7F6}_t!usL={k3PJZ8%6>E(4TeOB`(n zFk=URD5E*{bT}4DVCB=Q)y%2aaALn}Pt#Qd}5S4Hl_;dM2{C0*U6V<0Qwh`IJyh{Hy4W*Z>>+1J7$Z zF;LHNXc=7u3wbJf^<6A4fcepvplV(pqvd=y=>+V}a3}24rjD-ZYh&TiCJ^7{gmg1man;0I*upe_% z(I;KP+Y`V6c$dUYF~5X_C(Ed3;u!{1u&)8YmN(`%i@M$ebDNSa-=5d1fFr5N1P-_B z6>UgsYd*a`Y>x!IE>GeK((&I+P&`W88-W;|$D?^cLyp-w9aB5GCob{5u%9L5f-_uT z3+J&u&WP<|uW_>;VX`dVoi$WU2>k;|!-y=3s3Owja1vRt8v>{o03D8k)@9ikZ0SELuoOCm% zn}lp|+}XDG+QqCd&G)Sd0F~{w4ZATqjYsxA9@4Ct^SCP|zxRRUSq8;-hv{Sj^$kr? z9LV1GLsseAucP6bB3caPW5kRo6UYl6i~w{PuVxJ|()$Qsu->?wYX}24h_GLPhwm4W z1U*|+hj_ah(vHOEH1%WzWbDBXlU1w)AXN*;MVI_^v-4y2WuhD=c!pZ&!opPcd^5T^ zm&}anb5e^adEu%q=pq&wh0 zH4azEJ21>ySzR%ut-E)q#GC*cw^*&AwLRjv+_4)Xv1YFL7!qG}ri=6)TQCYQmckrj z0boMY#2B8-w)Q&IYzP$4D#p*i#98PO=-2E=m2#Q$2fG-}3{?~bG;Vy%5jTvna00;p zcQ5BAhCzy)`b1xeTMcOI!LUE~=>n@)I~05^j@#e>Sn67vwDPzvTJ>%~jY8hHQsc`z zfX`MoN#ouPA=?iWvG2|OF=!-s*Y?+fIGbsDyuM1U6~MImDAC5udEOy-{HI?s!*gHE z8E?f#JE-H2sp*q#2|wfMK$ zc}=aTmMokCKyc;78f|)z5!9LD-BMx=$-<;9w6$2hP>-p)z)PZtQbj#rV}~-y_Z=@H zik#l)#wniOu%$QjY8|#LevuOQ?9z$pBm)~QErxt)Hoj+xV1qqo48zo+#LCCUx2Tlu}5`vqvt=kCWs+F$`tF_ipgo*%mGIaQ6~ zxT3|MpKn|2OqX&N%fdAW+QSYw93(#*f(6Tp0BBmxq5I4?iMo=GhB=**>nZb>T9*1 z*K~ck(pLUles0R$$VW8&*Z=C9)?b?s|AeMp<-7^|!0xP(im&r_pg%1C@UphTTbdP# zZ1JhtO8lv9*PvOU&qed3IXY2PjJNo7H+!(NG`WHVl>8VEk^levK*PH41M4Sm&<~Hr zX+z~ELZcCq^vs^|kycV6G0S`sg_7hqO(*(P>MczrC_xr5UAF#B7K7zz_!~!Qmf_=& zywAyk%9Lj<6V;bdEg88Oh7Zll(6~B-%6F-96)aXPf8+7RrM#m%NeZ zGQ)|@lYK;8f-`229R^vJdPQr$+pX2uLa|ns!cF4>vy;Gy6A({>dn}kTUoPN)oCM^? zjSiI^z*MPsVOEV4B-d=SYCR~|(wgFbWDO8Iz($vf_0uu(B>fUk6QJ1Zif0tmV|S6WB}*@;NU*Ne};eo0w5LP`fCM z0D#Kal0^M@VERJ7NJ31t=dX$H)Dd(GQ}xK~?8z=}^{I@=gKYMHT=*{X=vg^{e1H0q z&|Ww>nS@!+wKWQ|NqeJ@&AY}ZGP$;qz$m=WWyAmf|L}lU{khV-4DuQw{)MbZZU5^^ zeitC`b{jPReAVuW*l$uWM(^Mj{D~}OOe2W;g&N#`)OK@{A`o3{@9>q6PAs?gyHLA` zR6oiGixs2GbuO4D11ApGT{VLjOS>&PwNnwx4 z&y86x;g4}jTL1$M+aJ}2kTn-ii+U0b#8HN@#tEDB1>BYs=71%b+EE2KJhVxQl5pdm2MMoE^ ziBl)>YhqM4#{ig~l?KNop14dXprXjvSkLX#-m=+0OzjDQa2A0`tYv~G1dtB~e+Y)i zqwh2O6}i_S|M7KW1x7AqH5H1ye${+v9q`)Z%B<*=sQ zFZ|$KLG>ju9lkxYFegry{+@3YPhm#%2JiJjLGWdbYz_|Q-GQ(neZ%}wEZ=|NAVgfl zGj;VYR_>)Tn92-Ej0Nf7z1q=jHJ*;f(Qp4s0(YZHmKEcV0L~A;{t$lJy{U|ynjhOM zo(S&)!O_Zjw9ngvT>kQXQCbqAsU_+k`s0cL-c+XtpPci}`+6HIFZ`^f^If(x`9mG<;f+!B#Pn!vb6q|(s7 zJ_Jqth{5MXVyxa26ZL4?iK8;wByY~7Y|%ln{wG22Q|>&VkY~dMLk|^vw=j=NA$AFb zO=EnVkFSGs)9RpA{lUR-)J!~9+`3ra!-f!uBz>aBORc zee1eN1nOvD9z?;($IS;PYcN42gS(*-M6kU3c<qQZDtcI{c9ch4K0qx-Q2WlWa57vZHW%f}ZgF;K=wkh2e?(c@OQgWGAK?~;E1+fAGNQPgUPXc~8Jri4 zX=X+dV?&`Y)eT!;XEsdSwzkk3^9-W4vP4C=UGQHbmFJ;!>bD(4N25 zH6*0z?lX3-Vn9RHw0);Qe{!GPsd?y8&(?)~!fzE$$Hb^43dH8BJx1ctaSVP5J8ctF z4sByaB%wV)w7t%>{i=c8v8WGona#I=6p1Hp+fr(I&uA&-@qR-)a9^c3Xxbyh&OC-V ztK5S$P9z4hc~cLrci=gH%jGwj+0`ZJ#BG8lfI8O#dT!?IWu^_Aw~Tt&`L0>hv?FTV zL~$>^mGMooBsEH}cP=gI795Q}w&Tx=^yPe@214bVX)qPIA_t(qjInKmOZN>1gF!(6 zn;y-%qTz~-cFkIe0qCCrdt2aKcBcR=A#2&^y6Xt>Q=qjxBlMVJSzVuQh)Cq@9>Mal zL2I~4GWX6K;7Nu;6D6@vT_L*k`?Xirh#k%_3;Vmv!X_UHKa5ro1_y(e4M(N$+iIBt zs1N@UCU)l-y+=mIztnUAZQ7Y>rk%1pGRGi|!p8_k|Hl-MR-Kqre2o-OsPbx<3ZYma zlTeK9fBanRlF-ERUWbv5wf3=QfwElU!XMj|+Jgvz<9ql7PRyjDs_r{=Aq#S_$6pXx zrwwPJd!@!50bL%?zU|7jKptNksLyl)_^|N5Q=rj*&bCFs}J-?C*Yic9i zUCM1P2avZsQFUoM-dO0H<%xJ}59bk~@dnRIHoi#l9u8E19)ER1@IfbvLD?b`!1V?y zhQ54qt6S3>SGwS%ZH;W3gE>tioAiJE-!7f;3S}Vb(l%R)hl_ma`PHrSO(shmg22nP zNh~%~4Kb8J^bpr1`AMqovleZSoP=jUr(#V`@;M454y|vv9z9N5&~1v1|Ge5Ow_N}{oZfuMxrpidwLf*{)$_xgwW|5u$RUBVz z%6j>67)7;K&oN3t{miuRPZvagAsDh_oRo!o`}zppX|#>gvY*tmmDYem{?+`E+0jtb zz^7;7sB=^$?a2lgvx~K+to5TugEfnsOXHmtH%pvTQeF~?tptj3HA@Cp55U|Iw?Di& zV&gUNd;YwYu%?+kB^u`CQ}tUFYfJkB{akqP8%62S?4hA7xY&7`(4q9 zISfWzAMLRCrU?;Dg1~zh{=PQp^|~nXGR4uXdG*rFt#>dK53KixdLa*dt>zm-k)uO& z*SD$IjepNVkm=+KB;L*Rd=fZo_RX{X3OOru3wE(! z<{iF_P>VI{zHndmau5CoxumIUYL!5rUu@@`FLW;D{+R7=WmMpv*qmsq4<=~0NGy`g z#P~_4m_^;a5UkbFa<0tOt{d^*c8~|n@%~yXO(?X=_4#10zYZdp)v2t@oYNq%|1EiU zs9aFP$QJ>Yl4;olR>gdOZ5NF5p;torbn5kry~`Z02Z4hgYE8N z^*UCv;l1@c+1ihC4)D{fr%!CgKM)VFyhS-m->N6Y3=`DbnycGMe7jBCIANQgq{lpd z#cZvf&SK*Wdz{DG#(hRk=XmsSw_z9I(%(x41O@CAcJ+yfj(6IJZ{sQU@vZN#_qju` zjLj`3$}&?P398gVsT)}fX~tYIXhR3{y9Sf*|M>r@hK>U9!lP!P-Qa2+62>qI;uc)lagTOEeVNueagmFbV5v7@RTnwg7fnO z?|+i~nyR$W=k|vBB!LwG3PMZtt)H2qETh%GFr!m?Xq}tjcs-T$On;iO&(*wHEF6Fl zF6hzUa<7n#M0&6e8$$sG3YT@PeSz^viKv(&u8uvMg1hot$i-WZkn{P6vQTb{(QyC& z6{4LXwS7?bdM{S0WVa`3H+u>yaJR?xi`^)GcO^x0RE2b?MwB1O>tJQI-z0s0ugPWOsYCzi`SR9SYJ%S_f^+zw@yu1nnd4x{4^(h+W$ zg{{1(HU_U)-C#zkV?kEr@{C|oXW{p~9tEGIF`k6Xf!}-a&Wgnx zI4==s7{6s=hVOMtpPV{xxI!`iuifg-`QObyLC`XL6-+In1hiSK;Odgbl!*-=B3Fn8 zh=?r(X#KInP%4em*{W!I+F&fG9QVzWwy4LXeHFpo#y~&seK&?NHf%?_<3n2e7(@nw z;>;B_Ml5MvwvF2xXm(Zhx}%TjR)@0nbsF7h{R}V9Pj4d<4+?X<;i=S~1 z$YnQ8RoWxaVtB&8nH4k$;NRWrk1~{@8%p88%%*Rx!P`R16`pS19n_=UFkn1xyQ9%_ zWY6c;9}M+JZKnJUe%bf~#2vR9?ZHBD!;ldb@CT(fZ8Q{7T0IxyZBFWh*OEX)yE?Zs zplsHwQphRCY>*j51BHbqRB7%@*O1aBNc#%8#I9_L0GKKWi{%DzsX5^HMy{I3Kak1* zyDSYK-F9m*{F(}yVb&foh(>PEL|F>C8I`$P(NVavZjlCadYhYX36v&CR02IaT=IF})Ws1Ga=C%le&^n0htry|UjY?l zF!t`KOXqzo>u(JM7DcS*i z+Kq*PQcE;vEUw(EP zk>JA4ZLJ!jiZ)aZZ2c`j`MY4!Tmm$<20qrT!C3Y}h`hqH|0Nq?|NonRbbrbKB?#!3 z_4X@kZB8HaEw}CGNXYp@f4Pve{ewuEgTV}RJga$!fM7SIxzmJ1-Vh~Rc|B0(=0bsv z+kA31Jx!mR#zh#X*eMjeIr+qZ3T{6YWQ74LKFUBofg@=xKg@r}=IHthi@w<5qw9DQ z6FMT2QG1>-xIQZhOo%NeVhNgGRL8(us57j%6DheHotdB5jhDFCnE48S+~zS@LC`g48858z6RMM(7c38xu9T(z-}u;e9}ZV z+=@uEESz-@DDc2M`jwh3#~Fyh)-#H*nEqss$kkctgR8Nm6#rT&%yCN0i(}8+A=^)= zU*{!Sz33;7t0hAp_du#ci^Q?gJlUdFuGaLaUyCX8F?M0DGKExK>anH&o3H4n1nX4P z2&}YN_3XL_flw>G6lao!ARxpCWD3}-jj8zI6UCq2ubwjq*=82%?P^MfikmE~USzSc zhB6o#aJG3%R$1AyVbX=w^Nz}_b{LKQN2Y3S)V!>$q7xK=k++#2&+eiFqq{{;yw?^G zbGPsroB1SZ<1X9haH=#W%*%%Ox^>7Fmm*VmF(E{wqL;!LV-AnVn(Zrs%gwrWcOOj0 zArL+j(LFzlW_<%+Q>nWC@dc;%Ckx((g+xO&tb~X&G;Z9|$eA>yeqUR-#w&UkMe`kA zT4Ih8d0?H-PaeES5b{&|ACp`_4#8cxg$x(uXRbfW;L4$O)DWaabX`MCdr6CmsQ;N#StPa|vNW$o@aS_vj8+)bC8g-S#>w`X+a?qpRQg zx16c6=3B>?z0>yB9!`bGdPK1VyFv)pzG_F7YJ_5`xY@N1ggASOwTgcfb^#xMfX3vh z8ATFXYGeTh%?=pBC&u~JC{(g~^bU@{?YI1~yGseXxW-5>aP`xIAktX;d*{P0BSv|Q zs|qm>uDNtsXBQ@A#iEb!^Y{%viSw;Rn3mYcwVnW9E5?2R24kwoD5gO#oVI*YuyEW? zFKDs)-3!a*t)tEYk5Y7c*;oM*K?s}7e6!$HmNV)QN74tD3_r=4QeV{nsgQ;4tHHDRaT=0iEw$=m#y1 z^aa8F-QAbn6$MZYu+z7kmh=ocfa^L7M@USbrJubqkiSRi*V5cn|M0JX5^{xZcmPe} zf&g#aDm-S=u!^QFKt)~8{2(7|L20~c!+Fl{XQIC?+Xw#b1&Rwl=-?*hOwZsPQDxbK ziw7q(3=H!hEa@v2o+;OC3@Xo(BZfYy{r&775YNj!p)(~a+Uk*dZtKwuSEOSdcTT$vR}T2Jf+wdaZAN$Vq&Dkg+jn9L;ccjnPtT6Ikp z`kOt2Fh(z0#Kzom3&W4EabVr1RgfRMB@CWS{Fb4v$3c0Z@O>DqSit3@wroCrpKRE~ zzpG=FC;m==eqKL`p8Z1F!m@<=>uXIdSJYSlc3F+O+%-eaiAz_2$v_F;w1`Tww{XFt zxyLa&1zXzmYmE&|BeZ%q4=0`=?5dCz&a-tVSEfG|sf=me<(`HeL(6>u$LKZ8$j4@e zehD+9tM$v0+Z_b@VRE>Ks~WPVu@%yZ6GJK?l-UJ3`epK0wdz4n0~<<$S_hrwuPw*jz_a>MMdu}`g%Y#rfk1XG0D_hc+^@2(FtuT{_-sLiMCRT+?A7CJH~|DsDZVr z-&YL*^$uQu8(x~+tB^H$EO+x*1T#8E;5{z+NX?Z$xukNAm`W|aSPtr&76yKG%_Vm7Z!QvqnNC}G1Q2;Z`OZ@{%RE(vLRXEr( zY}>ku<8`uzvL6+PwJ|0i=c7@?fdqf+ol7->HPbwR>yYHdjIyTEITE3&Wu~d+3jI<6 zdy78QJFR$(=rV0W?($7w|LYcaCJ#9C+Mn%NXrX>n%_K1t<<>gBu1^7tqM%{!Yx^tN zt*`zZif_wO?uFdRgy9gt&r+}sOVUZ-K}5;IwXMtdG>N5T6a(5}cSEgUp+FSs_=#7W z$=f2$x3h(|`}%~XX-`cY-e0W9V~fWUx&rf&DjOLiD2pkIk9Qw|g8dp+%~k#l-+Y-d zg6DTM47MTDyX{sgtL%S8;^XSOF4Q#OVqsD#Q#QA&VPs`7e zdwte~<#xHsSGtAlpCHAeM&5q)H)*mFW_j$-B(;N4U8fisGe+D(m7>>#?l z&b9>=u!E=>n2%EC@?i-a+Tr0(_><--<;ctfPicDTui|kF_7oA!9?J?>azlo{$a0BZ z^|gUy+l52Y(_H*@w|7koO7hFWDGc&5vWgj=zP`wj9m+j*6EfE2z|(9*yLo2>yPKZw zyM6j%+WJi1lAW+vult=D#yisM&Klc3L4`0ZW}6dGeK%E?-drDTvK=jzY~^u%V@+b6 zIw|VVVwx@+YC<;zAjCo?Z{VbPycquJB7VuzQ)P-FKrzY#mc4DeV6AHZVUS6Y6-@ae z-c5J^(eeURt_adeZk0D%Ph{`iaFvx72+uVoyM_rQG?*rWxdUxMK;WT^ya`&lYkvc( zLL((2{?fdadJyg>cJmCrd^}mD6^?obS2fofE4Qc^ns5Z-$1L&~!d^TNWe!)Wwlrm>|i`0TBr)gS&GPFQs z*{b1M>CCCW`QS*1qHv{2e6zfmYmF?%XL+pBv;F330QZ%#eeFKJbaQ(11oZ_pen0>J z#Nig#=Cn%_`-^0{*WA7;5K>w!Ku}#kuu>h-U1DY#N^|e}mLaJnInNkbNi*-~I*ug^k)20+(n+n>`~!lMZC_-a%j@ zioc(|2(;PNp+=*I(p=<y23Pu9`yJAQ@dID?pjbeB@z_-(c}oz^ujfC0$F0?<@dUn$5A> zKxM_5IbZ#tCVy2m2cq&RPyhd|>0@?UW|qx@-lOp{nZ_7^h9|$?{A(R9;$@b;t zQDTxHJ>4KF{jTI$&&hVd2MN8Rhp0*jH|q;7hLU@~-9^$g~|tHc&WU7>~r(0aZ4JdyPITjz%-A{IAt5U;4wr z7Q_Am(I(S-uN1X8LVH7L zlA!_$xl9QeUiUnu--qUD)l+Oe6{WfaV080U9jHWi>L|eH@Zhz9<G)2# z2AL!f>c94#P`~kr5D~@y>7ZS&^V1m8(~4GoIHnK*sr+VjU?^-EDU%ngC&oUH2ZAtj zo!dRmHUxba`W6XH*;}5A>6HMq^%^Kf(}vfOrcMhu;;&upU3dOv&J;tdD~4>Yqzn7h zLf%b(U22XMLt?X1KBUR&Ycs$4_-q{Br+978(2Jc3Z~%h(R$r?L7h+LyNL-ZB;mT$X zg2btk07pQ$zm|s<*+Lyuci|2aP`8x3^$HP^B>c5AMDj{y2lAlOsVe~=A!#YZLH<{dC-bKithAL0V?TFw18@FOXRwIfn zw%D_r9(jnkk%@-}^S#52fU<>lo}hHZ#;PeRGgip7YAIu_;?QBd21BFf95N)ztvq~Hu1@Uj_ErA z0kUW$SveG{yb#`_Sf6u7TFhrbKe;A9vQKdcMlWUh-5tRCITD< zIjXC$86HVr_5!=&mG~?SL;CFj+}?A*;2jDK!6gWx6<$ZT-#9Xye@29OQ<}X^lH+aZT}krk5zwD@1?>EgSZ7jHy(-x@QcnK zlU6(H*)riWG_MPuKIJI}G;NA<_Ct2BfDbS|JDzlBk$}x^F1yh|+YA&%aaK;_V9`m! zEbli_?%X^rd6mQF;Hizo2c}MWgc5FbnO@UVCutA~1YI-ChL%myMVVZ|l2Y#K@4!BV zJ%4ji!)OD&2O-$G$2^50+UsK$kKxv%)%>fjIzlSxTmF1?kg8D$Si(vq(d}T>lE+sG zUM+E=hlo($TT4ofqyIte={ zr0$z}yj9XB=UTPlHHHr`oL2?w+pljECA&_X>_9P>Mg}g4wBz)+0eJ<4>yqovGgwdQ z%PVxXO+J*lCT?_y=y^Q{tC_3P4D34>LviE9gfIfxnMGDd7XVl*Zw!Y9^!egNF0o6k z%M>?QWZA_|xz6ddT4rI&b*5hYyfNK2FnYlYwa66SU5Ks1y7lu+RMvi5bt{u3Ne@C-Wvf?x?k`q@kF z{oHJkmv#1064u$!HCaY=Z`iOCz?Vx$$r4kw2`D{VRq4=Sf_VJ2#q#L>zzMqk3z5GJ z_OO@Ygua{sdM@G}@nE^o$co>5TiAfS4Ng45HSP~Y9|T_6>=uSvEXY^q1$H^CZG6W1rc9{>75@guZR(8u1b{rtB;B3jvcSC_smer*ic8a z+xw75S4OPz+b5ivb&*CL4yiMrWVtkuLS%)b3s{{>oXb8IGWeQUQqLSSeiDWvT@J+b z3`-3qQh1-uR78PhswjJz5Yde|myn*Qo63qq4VRZXrpN@B|Nrh&06VMw?tibGtC=77 z{#^h5pdX9-ObP-K&$(+2*d9AFCYfeTk*J+wG*SLAwQIUx% zpl`1e3KwP)lh7uU)8&z+7jQ&F&1cu23>5demPr0yeuK{NSQ^d9Y?Xr0NmmVhYp;nt zq0&QfYHeHd1b0XXPji+ZQyo3WdXG=Jzq~f#4TVn!4bJ>T8!x%W>U=8E&0`gtTVMyU z7xadcw9kpN2A2^?O&FbwZAtRBaK_|zF$R(R%57-Ol-77uP;tgr<9)Qg8CcNpKpiDg zg9V&V7|RfnEqArbmjz4K9ifq0rgm?by6a5?>WzrGi>b?qs`VQ*%gMfcp1D=V0|DSR z)mNedXj=X5IcO|hChI#9Sh2;`(&PH<4V9+F84`vt2}ZQfg;a6U2mL14U}#KxFBM8= z3koHD6F&DHkwg%zl*7c%4&~M4+Io?}%CT*@m_1RC3?u~9S<{1*necOh*G?tWVfFIj z(j?x=L>z~b+%`H@RJfp;Kv+U$xS>TB+oS}>W}~Iw3JAC5MA`DHzg&+#5DlM~ z6H-%m`Cu*wfZN>RD+$d|$HsdJW?Sq1=<0|VyaFMJiSz?bk`D{LDWh9)?LAulTExR5 zv}#B?M?5l!GG0nUW1vPjIr5+>R`WoA8M3Tbu#sRxzx=vFE)tRX#&nxoyC%>L&42Jrc|cK z+sQ@JL)=jJe}0$Vsa8AIHaX02&z-3G-1tA5km-+x1jVIhFDnRF8kf9=~t&6rbkJ zBUu+=-diawlaO^vkZ>B>)}O;}Q7*p%hBPTN1Ub7lU+v>X4h)S3u){||cNI9h5!Q-w zMn)UOmWab5(Ex*wsJ-VQkt^F@%ukr~^s7?3arSW5(!giJWU7X{#}nW?U>?ieWbT{~ zVf6*t;yO1VFC*u!D*)SB7O=8L^!`doWhG5}9Ngw}& zp4RidY*|P5H%jT&s=DGl(*03)!kKG-D^R-+e##)_Vsq$DV^LfI>#)e2^C(__T0)Z< zc@H|4%>c@D+HgOZu8?!7^xMia$r^KOLACTuGK@&#d=KFN+WOK1ln&B!3^x7ulG*~q zLbjNZ5bNEA7}%22iY#>OD};mf!JDP{DU$P=SgINy30J`4>{or-%1Dj=auc+jes}3l z-`)6SLE&m-v6(MRlX6QxS>OkN0|L8V^=2SlA|E9U0t=fx(zpM`5F>6ELdC%>_u316 zp8}7a$Pt92ncoHHDI)=z(6nnTHXOI1*WtxGe>NgfQUVk1%ZdnV^`M1V?kNA%(TSyy zkoGbk;ZYV`&lZAm@c;%d14*Yp$?_h%)dSza-*I2&T#W$_==PUpFPf&{gTg0%y%KY7 zc&wR#(>Ar}vxo@e*^jWWY4wDT=@ut`-&+vmsihUaY+m~v%$YdqR`Gb!h0}n2^-M2H ziKCa(6@>FGH;mglDJ>#=pHw&o1AS77wxW7#7tMzweci4px)I5v{$f6sPwuu{?s%VjolSv;1y@Nw#(VfWZ?)+9d%Ie+1Y1C4rx))0xE$NQj!-*H=$4tRF z<5Cl%69uZK8z40j|Hq@?T4Pnx-|{C;o;)0x2t?TYN|P`_DsG$3R}OQFSQGQ$-ox3P z9zk(CPVyqthDRT?Vcm&ytiC%rJCrr7&rD&aX38muzpIq|AQtU9L7@*I27dC@F&Z%r zRrf=_l#8G)-?veQ&E=izDR}-NNI_$G*QWp*RnEFI7C?A`R#et*dBUH*N8)uB6~$R3 z9ewY>Xyo#5iDRCk6>mYB2y=-vx3_>1LXIg?8EoG(3mzjLmKD%R*v@uEsj_BJ9yomb zByo)4ZGQlme!-Nfe><-*Roo@%mLUCm+z(I4K$xjzU={~GJ3n46`_uzS%x!B0pV_1) zy-|$6!xSKF|Osc9z zld5%_I8vhMGYSiD_LwGz9N-UwP66qQ_IXyQw$-Ak_tMaWvoN=ingHgat{A>_NdmkLrE_Stj#zr6(QmkPe@<|RbJ#FgfB9+<4Tb4D9 zN<&uYA#9_maQLA#N!{_LEa4+vAQ}XG3K1nDaO9zr4VPleTm@y!^m$vJewFi1WJDJ! zAvx>aKi0cKxxVY|j>$MK=9^6%sYo~;+!ytTn)&FWRN87cHSNAgSyyG~%Hyl)NmqgM z*n~Ekp|p&N4q!OfU0MJC`pq~0bxYHI)Bk))wMLU-7%$0+&xm5Ozc~bqH`^wVoi6v> zivvO>wn%kVktSFQT5-VR03bjD(S_GN+WOv_zh-mi%zFB@v-+tbQXZziWT6y6xEg`J z=qo`@B*QGc8CMr${M6V=N=Zq&%UcuNN}1=A?j2l+H`_))Bf}4Xb9?IVoFne|5L$}^ zA_HtOpsOcV{~kYuC)14-^GfYEM=QSgR0$qalVp~7+!S@*Q$t7h0S93bWrzs0%$hlP zQpGiik%o_R$Oy*Fak3_UAK#Vea8s5m!Rli$J%0aOLt3bo*WaIbrc`*&+VviS)Feb2 zxAvI+0XKf7Ue=yrUm0g%%NcaGtgflKXyISsb7TMZBo*^J}vWh#Ewm=7-;-28)5+W+cHG!Z)yPpT@}tb&#wj z&k+%Jh{Wq=Np_(LgXOKrN~sRstdXi+2)Vf0vLjLgWEZ@;KZhQpx$AEPRh~f3^SZdR z9<^4yCBES!*&etU?$1!XoNxTTw=#vIX^e`Uk&Pspun^y;dH&3nZF%weI$UnZuw3D_ zX<*P_USqF4O*LU-w|Aj$#e41JIl1PqQ(pN)paIG4b@bV)%vjPEiWV`(dJDd3_FhT( zm-_o+p9zYd-v)GYloOTF$HBZL*#epv%NA;MNvB%dvquYpl+K>V z31dj05R;5p>X3;!h@E{EDM|9TWIYtk*OQ&z}h_0g(e%+(garmE}3hA_d6dPv~#~O@+ z>|1(ymz1}wP0g-)8q5R14Hq42&|rGI4DFW`)ea|2)($f(IzrTIjpG#FgW}T7Cl~9l zoIoK~?9o8qOoN-=Y#zIW1<<`H6SdQ#SfHgxYrWSMeHp#(g+yZwMZ&Lg^BaG6@gz+3 z0{$ni(Qom>#1N^%wpb)HJQyNsMU0eitGz03btRG!|Hd4P%sL2kHSHfC#h>VJd)(b!DsQ+w? z24h3UoNiZz5@FbtnItMWK|GY3w1~k*F$f!}rX@nN%c>66s&;-+8o8UlRyp=%nbS`n z`RvSOdZB_vB0Y|n%1H%PNhD-%QAh<7fGT<2UI&cX1N33}nK~&6t1fZ4RotJyOHMDu zS8okCyHu_QH)cSadfEdnP9r?`?$%bwDlXQ*9=eLM$;vHM{+Tu1pK;Ad7ZOmYqTq0V zWzOZOiN%%TiJn+KbDHcq!nD4!xckB8xY#|=W!DvC>Rl0Sx4&KOJlU=-Ti}{~sS#2Z zw^Dw=i)qCxZhc{qLFe(Jz z6ES$q`lmTnV*Jm$UJG-DprGr#T%3FTR;3QP*Lc_#pKPH70{&c+S8g@NJ z_OEqp592DV?g{-!Rz0t5F0ZD-Ak-L)f)n%{xv{K)hkYp4Z#8>8UGAMnxB-1JdvN;u zfS?r!d-I%|VF;OyxqUL;Bl2J7f9ra**=+vaB#VW~vZwyUt(qh1*-1gq;Mj|{GK32f z)-PeP1+b0Qn7#*X73S^wSnpq5qi)<)iiiX+Q4THE(HX%M>XjP&Tt>179*R_(Yw$y- zYa@(S?AtRfQGlnGFdf9AR&L~@j#>W>Sb1y{*q+EdNsREOJbxtLj5n+&H!vLdL()qS zd@!?;8=2>GybxY{WybN5{?V$I*0q8Rzt{;V=|IfBtr$nX0AOo--MfCnnhi7_WaNAV zP-^p47dF1vRt&~U{+78V42jM`SNH`|-tYwU<;Nt2Bg2cUQ1`5>R(~hmLh$3~WoVxpJ^$|R}>;_q*}V8xq_cIU$%wPYH3Af}^8^+aWa!2mU)F{;QDCz0u5d(^D!>R66u_L{40 zxy7CI#1g;7;%W1IaCT~3WFw?jrU`y=8BUM_Setg;9T^oqe;^;_71uS=#%!%R)I-V> z7_(B9)wCho^b$x)z|8gz27mYEV%j2a$@<*T1IAusWAxTBfDl?6CTrww?wkK#?l!Jn z_TW5Xg96cUzG=LA={g(}(f|kUp$tUE1Mn@ef1TD0xYJOAN5HPHSU^6;O<)zA@Rr~E zIf!9Jt-);^%@78Eg`0)R6r8AKDCV30%ASmu$Wk&1=bdUM2bdV$4+UlkwWB!g1eiw} zTj4{xBxY9=K||zD3;{>t5-1D(Bb`bY&v1v3iTE6k4vq2y*l?obwNMhJ-D?;O`e%I51yG*E5F{VB(1fQgZfgs7wcWV=>Tk#m!H$7=V$#od9`A=rlB-Sk3zSThF287k%S71#vim=%K zoQD^ya_6b&9=_T85Z3iO@lu7HQVG!_sM;d@y!qEv4k_7QVhL5Ss8K?x}=&;fK| zYRCWrs}3`$Z+beU@Eq*N=3sInZ`2?U{cAfnMeim%L@)|>LNXJxe2(Fm0jk-5+EWhP51-}rgn3obPKq;wU;wBR?(z`zlMI~pvJAvFxkG95C8_L)vqzYZIOhmAoBJZGSGgl$-jo&nolQx zxWo)ied-ANQ0Q$qGdp{71&mE(CTCdP=G!%|_}cPJU9SHb4}I1R=?YGWLtH4Brf%Q> zi{pdrmH)9MLt+@LWJsvjP`d-yj)y+rHMu<>%tM#O$e8YMR^^iO{(@?3iR7xn!=R~| zNkUQO%)6_tCP{W|2Ww_xI8}L|G~wgA;+mM7OE~E2bW8#r)uy`4Uxv9%c~$?Y7kZEb zuDf7<0q8uR7Ikk#0R-eBlVEUr^3bXhmYQww7@3B&?dHft65PdqTAV;QqCpNxus`7n zQt7PgOpLJZNs2x1Z)REo3zZ7qnhEd)&h@u{#1Ntpzs9qWcFj-0=VL0+q=E*t&*+d3 zqKiQ64u4%4gM+>E@1#irg?=pqT$OM^K5DpewR$y)&)p6>(-KpkLS}JpldtO|)J%v! zr$A&j7Kt$-&u26)yos?F&bw?T0g~cSYO7fM$ic1Dc^2KZ*LAKIdO_$l1!MVI{u-y2 zquxD`vfyohurtoNVV=(mMq|A#fAOjCsnU%>MU?$&U8qgor0j*^xeW8{gM3Km7i20= z0NltFn%N=^w0BTFKJx8nkjwHn5pK8+~h!Ab4IjRfqGvH=bN{8M}dWkpS1=n+;7 z@&;^LrUqZ1s9IHShX1lJSu0bLw6bOdfvYeV2CbteqEiMJXBZE2dTLl|308S$V;lCsD)@(ZP#n7;?K@k+{(&cVZ6I0%hh$7f_WhBtGf8pdzrJIoElVH)%Kb=;|sl-^1)sc`Hcu1aZAHww*0Q z$~DW$U7xUkas)|2`_80SEBeI51*vqkH!0-#G;i{oQm;9&AmnWk5go@+pe21E2UZIk z$zkN^td`D0!`wx#PC`Q{r2|ZD;&L(5KvuZ}q;xyO4 ze!owmHcOunr-K6l1AWUD3qjxieS{xVb5M8lKVDo5aq6|1I4wsN9@9z1a-*41a|jTe zTDU{}RRtjQp5iTMJ>s*tjnt*f7bZJ6j*;gcJ@=szE*gT*>DlpSSg_g(7yQ3P8<*!VIoB;9UV?!e2BQs-#Ph-J3n}w4x)j%dF>l?eoIci1aXSp!=n%1 zZv<}9E1vY7L}k-BL=a+HgL*gz;sM!`H3X``Pn5Q?M5pE{SK8yVuu~rRyFx69RO(DT zyqJEe_3TQ_XC2I~EyEYHcUrOdgC!3}+n!p|$0JCsp*QVuJAJzD-l|H7{S6QfTbGqk+O#B}n(eVJTmeEvLV_ z$6Sl@6ro^nCZyhy%!Xef%=NTIfBC1?_(Ao;!@$91Y)Oaho#nK%?6eRrnfde4C##ex zD@A-wy=&djT0NW{Tn!v6)^~^|Zv62%2|HD0=%pN~c$v_4$wCg3ZRi>n)PrergQ*{* zQW=H_iXOFjGOEvm$}`tC+S%ykKU<(;(m1kLTfz^aXuT2C!u=;-TZjc_^lX3n65VSa zPyZz(YvPA-{Ig3l5Q*lJKk8sI*G6l>oEQa=&yzEy$(&_K41x($v!SFa!?iL55m(?o zy8nfBKA2rQKZXvH!X33f=42-^2Z<^tw{y$i|J&h_|m^^Pk zu>Hh?0kWcCtalOcX6LnM=C^VeayPiE+lgTy-GV5WYX`9H{4c@GRmOviyBD6*#N}f! zdU>#IJUUIXWy>Pfb}$g}r;ku53aj;O2Jl++)*kB7RS6K#5pL;?xY|jvQTPkmr@_rQ zN2NHneT^Vx1g|Mh+vmxD4>}feg%EU7{A&M6abGhPa&JNPAuW&Z1@`$Bw|3**$Hkt; zdXON&`s!JYoKumQiBet#ms)b?iNzY6{K|5e5|8!^gv_%vf9LG-<(fqE9uiS+B9&{ z8@8hWr45dXU9f2ZFI;wKrD=heKMFEhs81cYx}nXK*P{0$h`dW2Btq8Lx7;@kVMR(3;C*F|P;<%z=xCw&3fUzLq zPM_lZ@-`T9tTY+X4jM7s6PIk)xoPt|?=i&A2=FO}ilv#0Y%Q@a${sJ?RL}}un^uen z(MPru%nD6`;(rk>4<(`kK-TNP$XtzS?L&pq!WoFRnFpAbdYUw2I~x+xGL5Q%3wei~ zsx4G}9g`+?qKvud_&)kG%%j^{;qzH8h_bE|{31%h6T%bhb-?2GxeiqI#YIXdR25(k z$VXWa=fdm<3T>q08jG)~dn6Ho<2%uw%08U;l`heOI_&JTc)jD+vFj|c=QNa!$qP`u zzZ=xg-~N@5>IR1N{>Kq88NpnT&D2*oLx++5^$89+eV;d>0qr*i!;)`eo)Rx?29tm+ zz;B`#^r7!#vAmLLnvmXIk(&_>gdZ-WJGHbgT^B+C#xV}x?%cyfjZGnjucJ^tx`~Vu z{SqLFOOY1vH0Z1=sty(XSKhp_wqlj&vG@TuF)4Y7-MF?3y7U$sDBk_5rSJ2Ve9a^E zjh40@>nk}+-S>Ys{11~pEzdVmF@}Gi8nLxm z4`q!?x~cpx2){sCQ{Lu|>1pwfZg90HPjJ3yi)QW$%DU8Ic6F&Rq_od$>(BQkAnY#V zx4NRFKXfcDKSDjzyB4RV9|A#I5s$1c`8F5#&-Qf$b5ZWvP9Xnj`j&A+gI zbSb8trotBJeYJ`LBZAF5<-ebudgS)8Ug>*cE6uzhSm@G?q_ZT8ltWgjWh&PqYTP2~ zlv^kGXNH|O^10y#`XOun2pP1u}lNDKl!;h6!jmwE?`A1P0Rj zdZrwJVGK~Hv${@k=W7^!Xw!g7W*8`9Qa11Y2^LbX^YVFt;X^$;*l?6Xp zi&<(yeGoJ7tV%fp*1O_u{L;kuQo#5UqPE8e^D}!(Wt~NKM?WBJSz+C-vE7;_GpA?W z9&cQ;Ol7ZSA|*nfXZug;bCN}Uw?bZL(mz04D(YBm92j{f9U%&xQaZrg z`u{JrZ-v#yx_-EJcn@*0dzQoiv`j`4?@zHyWT3o8u9mHnoUs=_Q48<|NG@8;>3#AC zDDd3Y8_eS^ugxr}RnO|iI#0;QFi$qg-#J-)&)d_mqfHcFMHYTZ6))ET=cO(eW#AT* zVmcl0$S87jql;mFjtHRnV)GiYL%!Vk$C#QsRIEo$GwA2p-@;<$VUr!*R!o=v>HBdjK!~{G!EB-x82U z;5T&YNz4<@lXre9o^LX$!XOj-_d?n=a34QjU9YNbkRg1EsPAgxw*QnKtQYwOu#=>_ zOAEqQU*jIxcFDsR61XKcZBAB2%m3z)1=-aMm{9M)!lY18@3+`;z`A0hfSISC*ytz$&&79F^3Asw6l^q5^s{-`s?Ob z*p=j-;i2IuR0_~VusGSwwABY2uL&~=_Sib>!Ya;i#HANnXBc#|{zj+)XOhKt1$0}I z3{NY%8zK=xwYP8O=8*%I2Xy5}{z8_OCtPa^`%BY#mVcu2rQu`5HNvs_-zYOka44`x z3ut!19O_mn?S8c<9*|-W|DV^cY<8i~2${RT5EHirb_$XOj)TIV0$5$`uT@Nb<@1rE zajduNlJ`Gfb2xZf*mBTmS@&w=0aLBb?$|Gx&Q?I z1pUcwVwsDM%R$dZ>E-1y73sEopNwYV*26$|M_{qHK*PM4pH<_i^^ky518fk?2mHe{#qJd z+*B%&V862hs0hL-g6JMBMzE2X|Hq(Z1i2C3Cq=}xo@QqXXg(2@c+Vtzt4`txy33-h zmX_AeSQLpr9fxv?s#*@(e|UeV=7t*o`YL^mObxlF$P~vK49Hh&pKR7zqoTTQoFVP} z+2|*x@8fFc$7C~6oQ_YUooHLX+&1-6FXWE8IhYxr%%ynk8;4JvhyRc63rZO&8@*tm z#)gIXB7gn=ZmOV&i7HHoLGbd&dM#J>{BXiAZ1l;d%{~3^)d?h1cIfUhk=+4vSM30+ zq)kaYe;Ia_kzyxv%SCR+PZwBjPqMZwHf2n{t@6`3Vr$?2wU6`hh1?p`Awa%%@3u9S z9Lj00`+uLR&H^H4nQafZRUe>RgJEjc7=ZA4mMYdwTzS1SOrhYc8Ik0HEL$X;iSN~Z z@YX#+ePOqNMqGHxQ>nViukX93+ui+O^?G^hsK$ba7_2n@wUI{uAK@ws>l7wnD<##2 zQs2}Zs2c1CKiF3Xft0Ggbm1KLmP;Bp{BEtdg{AR0qM1dqIfBGWOB+6ShjAs9yGy8(BiD@M%q)p`s2=7+Is zNxZf7#Ux{7(=ml#R^^zBJbuVnyvUAtAK`H9_ktUrWNfG!#(^sz*nN{)cpUW8KKbW| zA6Li6^YcuS>D`wXUX{8x(o$jmV?~qvJ4c}~XJs7f&uckq(#dI#E{g*Zy^M4g1GFcg z8utr80K_Z|D}~B3V!xyTfnUeUN5XE5J{_hvlGdJyU?3jDrs|Js^USIUl zxU+?;j)&{&=Nn1soHofaffY^I=>rS1x}yQi@N3YZK)Y$+1wKCWhakD500&o zB1}`zBC}a}2&D+M4t~o4Y&up9xas%T_J*QXA5FlZ*B}4>llLj5ezy7W9b5~HFtP#hY1uV`@AIz5YzqB4!%0PWK6WzC zum!G?)EDR<{zAkBw|elFlW+v$vVk|GT($uT87~-r;hSC41^@N2loZ^)p?6lp?6#Sk z$DVTpmAR2L!Pd=0s${A1YSu;lpXg^ejfUe~yf_jMjaDNCQ?Ff6+o{T~`P2+i@Oism z!f$-1JnXAL@ka9;S4O`6WhWvc551&QHlwcUZ~w5z{{xjF!IKN8^4X=M)7Lzoph``o zg0AkQYWQ#}qXffaASIN~B}JF&W`Mw(&auzO&L7JPS8-B~nDMH`urXeh0}m~jgTy^l zOZiUT=K7FAzrx589fX*c8}*Ng7J}3biN;De;|*`lg&E^N)g$GBnL%g_D�)cNFpw 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

    mA9;&kyiAZ1J40+;i1{=5L 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%0Ag1R*il=2xo!#JYFy3 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

    8vegmJqor$b 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�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 AC<5S^8Rc4eoEw7pRP_gZD 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

    4nywA6id87_EdQmwDcOC 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 W5vZr_nqVSO-fzouOLB&Yv^2x^d3{~G|^NSba; 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

    D1V}}O0btVDAlTp8? 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

    0*7;$v_{nj>fWhZyce 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
    `p6qYwep5Az$mWO8|*}nXIGc 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

    imYIu)||)2OC)0CtR?lJg}f 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

    NL-qR1A&PP&p1v|8m1{;-q$>;pGzE+az2 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%0AYoNGk=Yh+9N9s5fB6(_K1V`fX3g|*o?Mc5Lmh1 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ⅅ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%0AR$`q~%jk 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

    !<=fb9u-khEGn9Xpn3(ivh)zLMWeA;oIg7 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 z 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 z�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 From c715612928f69a52b0eb90d2002c3f14fb9b9290 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:22:36 +0800 Subject: [PATCH 110/368] docs(i18n): sync compaction checkpoint translation --- .../2026-06-18-compaction-capability-seam.i18n.yaml | 4 ++-- .../2026-06-18-compaction-capability-seam.zh.md | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml index 4edec28660..56723c5c4c 100644 --- a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml @@ -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 -2026-06-18-compaction-capability-seam.md: 07da796fdabffb8a43950ad501f5623d4474923a -2026-06-18-compaction-capability-seam.zh.md: 18ef9a8d833bdaa924324867d522399c0ad48243 +2026-06-18-compaction-capability-seam.md: a263b5e7d0245bd1279024a50e05b2f33edad521 +2026-06-18-compaction-capability-seam.zh.md: 79c883c364c9045fa2f85e7743091f83f0553783 diff --git a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md index 18ef9a8d83..79c883c364 100644 --- a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md +++ b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md @@ -18,7 +18,7 @@ Status: implemented 遵循[能力 seam Agent Note(agent 决策记录)](../architecture/2026-06-13-capability-seams.md),压缩以独立包(package)发布,使契约、算法和(后续的)消费方 surface 各自独立演进: -1. **接口** — `@deepseek-ai/dsh-compact`:抽象 `CompactService`,拥有 `ctx.compact` 键、`CompactionResult` 词汇以及 `compact/*` 会话事件。它将 `compactIfNeeded()` 和 `compactRegion()` 声明为**抽象方法**——契约说明压缩*做什么*,而非*怎么做*。 +1. **接口** — `@deepseek-ai/dsh-compact`:抽象 `CompactService`,拥有 `ctx.compact` 键、`CompactionResult` 词汇、`compact/*` 会话事件以及规范的检查点消息来源。它将 `compactIfNeeded()` 和 `compactRegion()` 声明为**抽象方法**——契约说明压缩*做什么*,而非*怎么做*。 2. **实现** — `@deepseek-ai/dsh-compact-basic`:具体的 `BasicCompactService`,消费 `ctx.tokenMeter`,并拥有尾→头保留遍历、通过 `ctx.llm.stream()` 生成摘要、surface 替换、锁、步骤后压力处理和规范的上下文溢出恢复。`summarize()` 是其唯一的子类钩子;计价与回放仍归 meter 所有。 3. **无模型配套服务** — `@deepseek-ai/dsh-compact-tool-result-prune`:一个具体的可选服务,在后端选择摘要范围之前,重写当前过大的 `tool/result` 节点。它不是第二种压缩实现,也不实现 `CompactService`。 4. **消费方** — 推迟。一个 `/compact` 工具和斜杠命令将 `inject: ['compact']` 并调用契约;它们被有意排除在本 Agent Note 范围之外,以便 seam 先稳定下来。 @@ -71,13 +71,14 @@ retry → next numbered step/start ⟵ derives from the replacement surface ### Surface 替换:`compact/*` 事件仅存在于日志;一条 `user/message` 承载摘要 -由于 `SurfaceEventType` 是封闭的,摘要不能搭载在 `compact/*` 事件上。后端改为追加一条**单独的 `user/message`**,带有 `surfaceOp: { op: 'replace', start, end }`,其 `content` 是(带框架的)摘要,`sourceEventSeqs` 覆盖被遮蔽的条目*和*簿记事件。`compact/*` 事件是纯日志记录(锁 + 溯源信息)。surface 变更位于锁**内部**,`compact/end` 是最后追加的事件: +由于 `SurfaceEventType` 是封闭的,摘要不能搭载在 `compact/*` 事件上。后端改为追加一条**单独的 `user/message`**,带有 `source: COMPACT_CHECKPOINT_SOURCE` 和 `surfaceOp: { op: 'replace', start, end }`;其 `content` 是(带框架的)摘要,`sourceEventSeqs` 覆盖被遮蔽的条目*和*簿记事件。接口导出该来源和 `isCompactCheckpointSource()`,使消费方无需依赖后端包身份,即可识别持久化或克隆得到的检查点。`compact/*` 事件是纯日志记录(锁 + 溯源信息)。surface 变更位于锁**内部**,`compact/end` 是最后追加的事件: ``` compact/start → log-only. Acquires the lock. [summarize older range via the backend] compact/summary → log-only. Provenance: raw summary, range, shadowed seqs, token count. -user/message → surfaceOp { op:'replace', start, end }. THE surface mutation (framed summary). +user/message → canonical checkpoint source + surfaceOp { op:'replace', start, end }. + THE surface mutation (framed summary). deriveMessages() renders it as a user-role message. compact/end → log-only. Releases the lock (carries `error` on a recoverable failure). ``` @@ -86,7 +87,7 @@ compact/end → log-only. Releases the lock (carries `error` on a recoverab ### 检查点框架 + 增量合并(后端私有) -基础后端将摘要包装为已建立的检查点上下文,并标记以便下一轮增量合并。原始摘要保留在 `compact/summary` 上。框架是后端策略;seam 仅承诺一条替换 user 消息承载可能带框架的摘要。 +基础后端将摘要包装为已建立的检查点上下文,并标记以便下一轮增量合并。原始摘要保留在 `compact/summary` 上。框架是后端策略;seam 承诺由一条替换 user 消息承载可能带框架的摘要,并使用规范的检查点来源。 ### 通过日志记录的锁实现阻塞,加上崩溃/可恢复失败的分类 @@ -119,7 +120,7 @@ compact/end → log-only. Releases the lock (carries `error` on a recoverab - **包**:`packages/compact/compact` 提供接口,`compact-basic` 提供后端,`compact-tool-result-prune` 提供可选的确定性重写。`packages/llm/token-meter` 独立拥有回放感知的测量。消费方层推迟。 - **自动 seam**:`agent/post-step`(`@mode serial`)处理成功调用的压力,`agent/request-error`(`@mode waterfall`)处理失败步骤关闭后的最终请求失败。通用 `agent/pre-step` 保持为四参数检查点,不携带压缩专属的提示词/前缀 payload。 - **`SessionEventMap`** 通过声明合并(merge-extensible)获得 `compact/start` / `compact/summary` / `compact/end`;`SurfaceEventType` **未被**触及。这些是会话事件,不是 cordis `Events`,因此事件分类门禁无需新增条目。 -- **`dsh-compact`** 拥有 `toolPairingBalancedBefore(session, seq)` 与 `toolPairingBalancedAfter(session, seq)`;这些带缓存的 surface 边缘检查由 `compactRegion` 和 `compactIfNeeded` 用来避免拆分工具调用/结果对。缓存按 seq 校验当前成员关系,并从每个切割点的一条平衡序列回答两侧边缘;陈旧或缺失的 seq 以及孤立结果都会被拒绝。 +- **`dsh-compact`** 拥有 `COMPACT_CHECKPOINT_SOURCE`、`isCompactCheckpointSource(source)`、`toolPairingBalancedBefore(session, seq)` 与 `toolPairingBalancedAfter(session, seq)`。该标记用于跨后端实现识别替换摘要。带缓存的 surface 边缘检查会防止 `compactRegion` 和 `compactIfNeeded` 拆分工具调用/结果对,按 seq 校验当前成员关系,从每个切割点的一条平衡序列回答两侧边缘,并拒绝陈旧或缺失的 seq 与孤立结果。 - **`dsh-session`** 通过唯一的 surface 管理器校验位置替换、完整溯源信息和仅内容的单节点 `tool/result` 重写。其不变式配套插件将新追加的工具结果视为执行,要求存在已打开的步骤与待处理调用;已校验的替换仍是位于轮次内的重写。 - **接线**:`examples/tui-agent/cordis.yml` 依次加载零配置的 `dsh-token-meter`、`dsh-compact-tool-result-prune` 和 `dsh-compact-basic`;服务级默认值使组合无需重复数值策略即可使用。 From 5ba4f77f2b2dee0e10863572182a340b37448237 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:27:32 +0800 Subject: [PATCH 111/368] fix(pty): surface pending rollback failures --- ...26-07-16-persistent-pty-sessions.i18n.yaml | 4 +- .../2026-07-16-persistent-pty-sessions.md | 2 +- .../2026-07-16-persistent-pty-sessions.zh.md | 2 +- docs/cordis-catalog/services.md | 2 +- packages/pty/pty/README.md | 1 + packages/pty/pty/src/index.ts | 53 ++++++++++++++----- packages/pty/pty/tests/service.spec.ts | 31 +++++++++-- 7 files changed, 75 insertions(+), 20 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index 96d1e06bbe..de619790dc 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml @@ -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 -2026-07-16-persistent-pty-sessions.md: a73b8d0247243cc0d9cc93f27d84a8540b3b271d -2026-07-16-persistent-pty-sessions.zh.md: b0dc4010f69206b7aaeab4164199ffd935165955 +2026-07-16-persistent-pty-sessions.md: db161a865f1c30fc3979e1a92dc6d427ecb58f25 +2026-07-16-persistent-pty-sessions.zh.md: 06c902437aee2e5725e1765840dce03ae15c30a4 diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index a73b8d0247..db161a865f 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -34,7 +34,7 @@ Idle detection is backend behavior, not a second public seam. A remote or contai There are no plugin-load auto-start sessions. `terminal_open` creates a session only during an agent tool call, when ownership and the owning event-sourced session are known. A future declarative startup feature must compose through unpublished agent setup rather than create shared global terminals. -Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Unpublished backend setup is a tracked lifecycle operation: owner or service disposal aborts its service-owned signal, waits for backend settlement and rollback, and only then returns. Caller cancellation retains its exact `AbortSignal.reason` even when the backend rejects in response. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. +Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Unpublished backend setup is a tracked lifecycle operation: owner or service disposal aborts its service-owned signal, waits for backend settlement and rollback, and only then returns. Caller cancellation retains its exact `AbortSignal.reason` even when the backend rejects in response; a rollback close failure rejects both the spawn and the disposing lifecycle. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. ### Security and process boundary diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index b0dc4010f6..06c902437a 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -34,7 +34,7 @@ idle 检测属于后端行为,不是第二条公共 seam。远程或容器后 实现不提供插件加载期 auto-start 会话。`terminal_open` 只在 agent 工具调用期间创建会话,此时所有权和所属的事件溯源会话都已确定。未来的声明式启动功能必须通过尚未发布的 agent setup 组合,而不能创建全局共享终端。 -agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。未发布的后端 setup 同样是受追踪的生命周期操作:owner 或服务 dispose 会中止服务自有的 signal,等待后端结算与回滚完成后才返回。即使后端响应取消而 reject,调用方取消仍原样保留其 `AbortSignal.reason`。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 +agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。未发布的后端 setup 同样是受追踪的生命周期操作:owner 或服务 dispose 会中止服务自有的 signal,等待后端结算与回滚完成后才返回。即使后端响应取消而 reject,调用方取消仍原样保留其 `AbortSignal.reason`;若回滚 close 失败,spawn 与正在执行的 lifecycle dispose 都会 reject。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 ### 安全与进程边界 diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index ab739db024..1f2cf86408 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -841,7 +841,7 @@ list(owner: Agent): PtySessionSnapshot[] Types: [Agent](../core-data-structures/core.md) · [PtyBackend](../core-data-structures/pty.md) · [PtyReadRequest](../core-data-structures/pty.md) · [PtyReadResult](../core-data-structures/pty.md) · [PtySendOperation](../core-data-structures/pty.md) · [PtySendRequest](../core-data-structures/pty.md) · [PtySessionId](../core-data-structures/pty.md) · [PtySessionSnapshot](../core-data-structures/pty.md) · [PtySignal](../core-data-structures/pty.md) · [PtySignalResult](../core-data-structures/pty.md) · [PtySpawnRequest](../core-data-structures/pty.md) · [PtySpawnResult](../core-data-structures/pty.md) -Source: [`packages/pty/pty/src/index.ts:101`](../../packages/pty/pty/src/index.ts) +Source: [`packages/pty/pty/src/index.ts:102`](../../packages/pty/pty/src/index.ts) ## `ctx.sandbox` — `SandboxProvider` (abstract seam) diff --git a/packages/pty/pty/README.md b/packages/pty/pty/README.md index 624b771164..2dff1cbca6 100644 --- a/packages/pty/pty/README.md +++ b/packages/pty/pty/README.md @@ -7,6 +7,7 @@ Owner-scoped persistent PTY seam. `PtyService` registers as `ctx.pty`, mints opa - Backends register one stable `type` and return an unpublished `PtyBackendSession`; failed or cancelled setup must clean partial resources. - Spawn cancellation preserves the caller's exact abort reason. Service disposal and owner loss remain distinct machine-routable failures after backend setup. - Owner and service disposal abort unpublished setup through a service-owned signal and await backend settlement plus rollback before returning. +- A rollback close failure rejects both the spawn and the disposing lifecycle instead of claiming quiescence. - `hasOwnerActivity(owner)` spans unpublished setup through final close, so lifecycle policy can fence the exact owner without a publication race. - A successful spawn publishes one `PtySessionId`. The optional `name` is owner-local display metadata, never authority. - One session accepts at most one live send operation. Reads and signals may observe it; another send fails until the operation settles. diff --git a/packages/pty/pty/src/index.ts b/packages/pty/pty/src/index.ts index 1b937b9dff..d5b4d84e1f 100644 --- a/packages/pty/pty/src/index.ts +++ b/packages/pty/pty/src/index.ts @@ -90,11 +90,12 @@ interface SessionRecord { interface PendingSpawn { readonly controller: AbortController readonly settled: Promise + rollbackFailure: { error: unknown } | undefined } interface SpawnReservation { readonly signal: AbortSignal - release(): void + release(rollbackFailure: { error: unknown } | undefined): void } /** In-process registry for replaceable PTY backends and exact-Agent sessions. */ @@ -161,6 +162,7 @@ export class PtyService extends Service { : AbortSignal.any([signal, spawnReservation.signal]) const sessionId = PtySessionId(`pty-${++this.nextId}`) let session: PtyBackendSession | undefined + let rollbackFailure: { error: unknown } | undefined try { session = await backend.spawn({ sessionId, @@ -189,7 +191,6 @@ export class PtyService extends Service { this.sessions.set(sessionId, record) return this.snapshot(record, session.motd) } catch (error) { - let rollbackFailure: { error: unknown } | undefined if (session !== undefined && !this.sessions.has(sessionId)) { try { await session.close('PTY spawn rolled back') @@ -209,7 +210,7 @@ export class PtyService extends Service { } throw failure } finally { - spawnReservation.release() + spawnReservation.release(rollbackFailure) releaseName() } } @@ -341,13 +342,14 @@ export class PtyService extends Service { private reserveSpawn(owner: Agent): SpawnReservation { const controller = new AbortController() const settlement = Promise.withResolvers() - const pending: PendingSpawn = { controller, settled: settlement.promise } + const pending: PendingSpawn = { controller, settled: settlement.promise, rollbackFailure: undefined } const owned = this.pendingSpawns.get(owner) ?? new Set() owned.add(pending) this.pendingSpawns.set(owner, owned) return { signal: controller.signal, - release: () => { + release: (rollbackFailure) => { + pending.rollbackFailure = rollbackFailure owned.delete(pending) if (owned.size === 0) this.pendingSpawns.delete(owner) settlement.resolve() @@ -361,6 +363,10 @@ export class PtyService extends Service { : [...(this.pendingSpawns.get(owner) ?? [])] for (const spawn of pending) spawn.controller.abort(reason) await Promise.all(pending.map(spawn => spawn.settled)) + const failures = pending.flatMap(spawn => spawn.rollbackFailure === undefined ? [] : [spawn.rollbackFailure.error]) + if (failures.length > 0) { + throw new AggregateError(failures, 'failed to roll back unpublished PTY setup') + } } private expectOwned(owner: Agent, id: PtySessionId): SessionRecord { @@ -383,11 +389,32 @@ export class PtyService extends Service { } } + private async abortAndClose(owner: Agent | undefined, abortReason: PtyError, closeReason: string): Promise { + const failures: unknown[] = [] + try { + await this.abortPendingSpawns(owner, abortReason) + } catch (error: unknown) { + failures.push(error) + } + const records = [...this.sessions.values()].filter(record => owner === undefined || record.owner === owner) + try { + await this.closeRecords(records, closeReason) + } catch (error: unknown) { + failures.push(error) + } + if (failures.length > 0) throw new AggregateError(failures, 'failed to clean up PTY lifecycle') + } + private async disposeOwned(owner: Agent): Promise { - await this.abortPendingSpawns(owner, new PtyError('PTY owner is no longer live', 'OWNER_NOT_LIVE')) - const owned = [...this.sessions.values()].filter(record => record.owner === owner) - await this.closeRecords(owned, 'PTY owner disposed') - this.reservedNames.delete(owner) + try { + await this.abortAndClose( + owner, + new PtyError('PTY owner is no longer live', 'OWNER_NOT_LIVE'), + 'PTY owner disposed', + ) + } finally { + this.reservedNames.delete(owner) + } } private async disposeAll(): Promise { @@ -396,9 +423,11 @@ export class PtyService extends Service { // owner cleanups before the aggregated error propagates, so one stuck // session cannot orphan backends, reservations, or owner detachers. try { - await this.abortPendingSpawns(undefined, new PtyError('PTY service is disposing', 'SERVICE_DISPOSING')) - const records = [...this.sessions.values()] - await this.closeRecords(records, 'PTY service disposed') + await this.abortAndClose( + undefined, + new PtyError('PTY service is disposing', 'SERVICE_DISPOSING'), + 'PTY service disposed', + ) } finally { this.backends.clear() this.reservedNames.clear() diff --git a/packages/pty/pty/tests/service.spec.ts b/packages/pty/pty/tests/service.spec.ts index 52d22bd4b3..49162abe5c 100644 --- a/packages/pty/pty/tests/service.spec.ts +++ b/packages/pty/pty/tests/service.spec.ts @@ -299,6 +299,26 @@ describe('PtyService ownership and lifecycle', () => { expect(session.closed).toEqual(['PTY spawn rolled back']) }) + it('reports unpublished rollback failure through service disposal', async () => { + const ctx = await harness() + const gate = Promise.withResolvers() + const session = new StubSession() + session.rejectClose = true + ctx.pty.registerBackend({ type: 'slow', spawn: () => gate.promise }) + const owner = stubAgent(ctx, 'owner') + ctx.agents.register(owner) + + const pending = ctx.pty.spawn(owner, { type: 'slow' }) + const pendingFailure = expect(pending).rejects.toThrow('PTY spawn and rollback both failed') + const internal = ctx.pty as unknown as { disposeAll(): Promise } + const disposalFailure = expect(internal.disposeAll()).rejects.toThrow('failed to clean up PTY lifecycle') + gate.resolve(session) + + await pendingFailure + await disposalFailure + expect(session.closed).toEqual(['PTY spawn rolled back']) + }) + it('keeps independent reservations and handles provider failure before publication', async () => { const ctx = await harness() const firstGate = Promise.withResolvers() @@ -343,11 +363,16 @@ describe('PtyService ownership and lifecycle', () => { const failedSpawn = new StubSession() failedSpawn.rejectClose = true let ownerDisposal = Promise.resolve() + const internal = ctx.pty as unknown as { + disposedOwners: WeakSet + disposeOwned(owner: Agent): Promise + } ctx.pty.registerBackend({ type: 'bad-spawn', async spawn({ signal }) { if (signal === undefined) throw new Error('missing spawn signal') - ownerDisposal = disposeAgentScope(owner) + internal.disposedOwners.add(owner) + ownerDisposal = internal.disposeOwned(owner) if (!signal.aborted) { await new Promise((resolve) => { signal.addEventListener('abort', () => { resolve(undefined) }, { once: true }) @@ -357,7 +382,7 @@ describe('PtyService ownership and lifecycle', () => { }, }) await expect(ctx.pty.spawn(owner, { type: 'bad-spawn' })).rejects.toThrow('spawn and rollback both failed') - await ownerDisposal + await expect(ownerDisposal).rejects.toThrow('failed to clean up PTY lifecycle') const nextOwner = stubAgent(ctx, 'next') ctx.agents.register(nextOwner) @@ -456,7 +481,7 @@ describe('PtyService ownership and lifecycle', () => { } // Teardown surfaces the close failure, but its finally still clears the // backend and owner-cleanup registries instead of orphaning them. - await expect(internal.disposeAll()).rejects.toThrow('failed to close 1 PTY session') + await expect(internal.disposeAll()).rejects.toThrow('failed to clean up PTY lifecycle') expect(internal.backends.size).toBe(0) expect(internal.ownerCleanups.size).toBe(0) }) From e35a419ba82768c6dd64dd3d2af5538721136941 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:30:36 +0800 Subject: [PATCH 112/368] fix(code-mode): keep deep host boundaries iterative --- ...-20-code-mode-typed-tool-returns.i18n.yaml | 4 +- ...2026-07-20-code-mode-typed-tool-returns.md | 2 +- ...6-07-20-code-mode-typed-tool-returns.zh.md | 2 +- packages/core/tools/src/code-mode.ts | 13 +++- packages/core/tools/src/index.ts | 15 +++- packages/core/tools/tests/code-mode.spec.ts | 77 ++++++++++++++++++- packages/llm/llm/src/call-config.ts | 32 ++++++-- packages/llm/llm/tests/call-config.spec.ts | 20 +++++ 8 files changed, 144 insertions(+), 21 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml index 843feb7a4c..38fd140342 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml @@ -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 -2026-07-20-code-mode-typed-tool-returns.md: f902aa4ff8cdaa0979f09850ea15deede5fdf576 -2026-07-20-code-mode-typed-tool-returns.zh.md: 4bdec90960e270f5be03b0a4c30d7c829dd27f6a +2026-07-20-code-mode-typed-tool-returns.md: bcaefb196d12660177ad2bbc9c20ad71f6537eae +2026-07-20-code-mode-typed-tool-returns.zh.md: 72946f4cc1ab7569fc1e3f90785debf8314f1d35 diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md index f902aa4ff8..bcaefb196d 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md @@ -49,7 +49,7 @@ declare const tools: { ### Binding values and failures -Before dispatch the bridge snapshots binding arguments as lossless JSON and makes independent clones for execution and the durable summary event. `undefined`, non-finite numbers, `-0`, sparse arrays, cycles, functions, and exotic objects reject that call before the tool runs. Successful dispatch returns `ToolExecutionResult.value`; Native `content`, metadata, and internal error information do not cross to the program. +Before dispatch the bridge snapshots binding arguments as lossless JSON and snapshots the detached value again for an independent durable summary event. Host-side detachment, immutable execution, and output-schema projection all use iterative traversals rather than nested structured clone or recursive freezing. `undefined`, non-finite numbers, `-0`, sparse arrays, cycles, functions, and exotic objects reject that call before the tool runs. Successful dispatch returns `ToolExecutionResult.value`; Native `content`, metadata, and internal error information do not cross to the program. The worker exposes the actual `ToolCallError` constructor used for `tools` binding failures, so `error instanceof ToolCallError` works. The error has the standard `Error` message plus the exact `toolName`; it deliberately omits `ToolFailure.info`, error codes, and Native content. This is an exception contract for control flow, not a failure union for programmatic classification. diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md index 4bdec90960..72946f4cc1 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md @@ -49,7 +49,7 @@ declare const tools: { ### 绑定值与失败 -分发前,桥接层会把绑定参数快照为无损 JSON,并为执行和持久摘要事件分别创建独立副本。`undefined`、非有限数、`-0`、稀疏数组、循环引用、函数和非普通对象都会使该调用在工具运行前 reject。成功分发会返回 `ToolExecutionResult.value`;Native `content`、元数据和内部错误信息不会传入程序。 +分发前,桥接层会把绑定参数快照为无损 JSON,再对分离后的值生成一次快照,供独立的持久摘要事件使用。宿主侧的值分离、执行数据的不可变处理与输出 schema 投影均采用迭代遍历,而不使用嵌套结构化克隆或递归冻结。`undefined`、非有限数、`-0`、稀疏数组、循环引用、函数和非普通对象都会使该调用在工具运行前 reject。成功分发会返回 `ToolExecutionResult.value`;Native `content`、元数据和内部错误信息不会传入程序。 worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造函数,因此 `error instanceof ToolCallError` 能够成立。该错误包含标准的 `Error` 消息和确切的 `toolName`,并有意省略 `ToolFailure.info`、错误代码与 Native 内容。这是一项用于控制流的异常契约,而不是供程序分类的失败联合。 diff --git a/packages/core/tools/src/code-mode.ts b/packages/core/tools/src/code-mode.ts index 44a9839b02..2c7f8faedd 100644 --- a/packages/core/tools/src/code-mode.ts +++ b/packages/core/tools/src/code-mode.ts @@ -85,9 +85,9 @@ function summarize(text: string, cwd: string | undefined): string { } /** - * Snapshot one binding call's argument as lossless JSON, then clone it into - * independent dispatch/log values so a tool mutation cannot desynchronize the - * durable event from what was called. + * Snapshot one binding call's argument as lossless JSON, then snapshot that + * detached value again so dispatch and logging stay independent without + * reintroducing structured-clone's platform-specific nesting limit. */ function jsonNormalizeArgs(value: unknown): { dispatched: unknown; logged: unknown } { let snapshot: JsonValue | undefined @@ -99,7 +99,12 @@ function jsonNormalizeArgs(value: unknown): { dispatched: unknown; logged: unkno if (snapshot === undefined) { throw new Error('tool arguments must be lossless JSON (call the tool with an arguments object, e.g. `{}`)') } - return { dispatched: structuredClone(snapshot), logged: structuredClone(snapshot) } + const logged = snapshotJsonValue(snapshot) + /* v8 ignore next -- snapshot is already a detached lossless JSON value. */ + if (logged === undefined) { + throw new Error('tool arguments could not be detached for durable logging') + } + return { dispatched: snapshot, logged } } /** Two-space JSON presentation, matching the existing shallow `run_code` text contract. */ diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 2f4e4cbd5f..4b712b1d07 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -864,10 +864,17 @@ export class ToolRegistry extends Service { private sdkSchemas(scope?: ScopeKey): ToolSdkSchema[] { return [...this.view(scope).visible.values()] .filter(definition => definition.name !== RUN_CODE_NAME) - .map((definition): ToolSdkSchema => ({ - ...this.schemaOf(definition, true), - output: structuredClone(definition.output.schema), - })) + .map((definition): ToolSdkSchema => { + const output = snapshotJsonValue(definition.output.schema) + /* v8 ignore next -- registration already validated and retained this schema as lossless JSON. */ + if (output === undefined) { + throw new Error(`tool "${definition.name}" output schema must be lossless JSON before SDK projection`) + } + return { + ...this.schemaOf(definition, true), + output, + } + }) } /** Project one definition onto the model-facing schema fields. */ diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index 20e9c7e223..188e89503e 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -7,7 +7,7 @@ import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import { CodeRuntime } from '@deepseek-ai/dsh-code-runtime' import type { CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' import ToolRegistry, { CodeRunFailedError, RUN_CODE_NAME, TOOL_ABORTED_BEFORE_DISPATCH, defineContentToolFixture, defineTool } from '@deepseek-ai/dsh-tools' -import type { Config, PostToolDecision, ToolExecutionResult } from '@deepseek-ai/dsh-tools' +import type { Config, JsonSchemaNode, PostToolDecision, ToolExecutionResult } from '@deepseek-ai/dsh-tools' import type { Agent } from '@deepseek-ai/dsh-agent' import { Session, SessionId } from '@deepseek-ai/dsh-session' import type { JsonValue, SessionEventMap } from '@deepseek-ai/dsh-session' @@ -130,6 +130,30 @@ describe('mode-aware wire contribution', () => { expect(sdk?.text).not.toContain('run_code:') }) + it('projects deeply nested output schemas into the Code Mode SDK without structured-clone recursion', async () => { + const { ctx, systemPrompt } = await setup({ mode: 'code' }) + let output: JsonSchemaNode = { type: 'string' } + for (let depth = 0; depth < 5_000; depth++) { + output = { oneOf: [output, { type: 'null' }] } + } + ctx.tools.register({ + name: 'deep_output', + description: 'Return a deeply nested output union.', + parameters: { type: 'object', properties: {} }, + output: { + schema: output, + render: (_args, value) => [{ type: 'text', text: typeof value === 'string' ? value : 'null' }], + }, + execute() { return Promise.resolve('ok') }, + }) + + const assembly = await systemPrompt.assemble() + const sdk = assembly.sections.find(section => section.name === 'tools:sdk')?.text + + expect(sdk).toContain('deep_output: Record;') + expect(sdk).toContain('deep_output: string | null') + }) + it.each(['code', 'both'] as const)('treats expert assembly output as authoritative in mode %s', async (mode) => { const { ctx, systemPrompt } = await setup({ mode }) registerEcho(ctx) @@ -811,6 +835,57 @@ describe('the run_code dispatch bridge', () => { expect(events.filter(event => event.type === 'tool/code-dispatch')).toEqual([]) }) + it('dispatches and durably logs binding arguments deeper than the structured-clone call stack', async () => { + const { ctx, runtime } = await setup({ mode: 'code' }) + const depth = 5_000 + let observedDepth = 0 + let observedLeaf: JsonValue | undefined + ctx.tools.register(defineTool({ + name: 'deep_args', + description: 'Measure a deeply nested JSON argument.', + parameters: { nested: { type: 'json', required: true } }, + output: { + schema: { type: 'integer' }, + render: (_args, value) => [{ type: 'text', text: String(value) }], + }, + execute(args) { + let cursor = args.nested + while (Array.isArray(cursor)) { + if (cursor.length !== 1) throw new Error('expected one item per nesting layer') + observedDepth++ + cursor = cursor[0]! + } + observedLeaf = cursor + return Promise.resolve(observedDepth) + }, + })) + const session = new Session(SessionId('deep-code-arguments')) + const agent = { session } as Agent + runtime.behavior = async (request) => { + let nested: JsonValue = 'leaf' + for (let index = 0; index < depth; index++) nested = [nested] + const value = await request.bindings[0]!.functions.deep_args!({ nested }) + return { logs: [], value } + } + + const result = await runCode(ctx, 'return tools.deep_args(...)', { agent }) + + expect(result.isError).toBe(false) + expect(result.isError ? undefined : result.value).toEqual({ logs: [], result: depth }) + expect({ observedDepth, observedLeaf }).toEqual({ observedDepth: depth, observedLeaf: 'leaf' }) + const dispatch = session.events.find(event => event.type === 'tool/code-dispatch') + if (dispatch === undefined) throw new Error('expected a durable tool/code-dispatch event') + const logged = dispatch.data.arguments as { nested: JsonValue } + let loggedDepth = 0 + let loggedCursor = logged.nested + while (Array.isArray(loggedCursor)) { + if (loggedCursor.length !== 1) throw new Error('expected one logged item per nesting layer') + loggedDepth++ + loggedCursor = loggedCursor[0]! + } + expect({ loggedDepth, loggedCursor }).toEqual({ loggedDepth: depth, loggedCursor: 'leaf' }) + }) + it('gives the tool and durable log the same immutable argument value', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) const { agent, events } = fakeAgent() diff --git a/packages/llm/llm/src/call-config.ts b/packages/llm/llm/src/call-config.ts index fe723ec162..fd6ecf9df4 100644 --- a/packages/llm/llm/src/call-config.ts +++ b/packages/llm/llm/src/call-config.ts @@ -58,7 +58,8 @@ export function isAgentLoopRequest(request: GenerateOptions): boolean { } /** - * Deep-freeze a value in place, guarding cycles, so later mutation throws. + * Deep-freeze a value in place with an iterative traversal, guarding cycles, + * so later mutation throws without imposing a JavaScript call-stack depth cap. * {@link AbortSignal} objects are deliberately skipped because they are the * request's live cancellation channel and freezing them breaks abort. * @param value - the value to freeze in place. @@ -66,16 +67,31 @@ export function isAgentLoopRequest(request: GenerateOptions): boolean { */ export function deepFreeze(value: T): T { const seen = new WeakSet() - const walk = (node: unknown): void => { - if (node === null || typeof node !== 'object') return - if (node instanceof AbortSignal) return - if (seen.has(node)) return + const pending: ( + | { kind: 'visit'; node: unknown } + | { kind: 'property'; source: Record; key: string } + )[] = [{ kind: 'visit', node: value }] + while (pending.length > 0) { + const task = pending.pop() + /* v8 ignore next -- the loop condition guarantees one pending task. */ + if (task === undefined) continue + if (task.kind === 'property') { + pending.push({ kind: 'visit', node: task.source[task.key] }) + continue + } + const node = task.node + if (node === null || typeof node !== 'object') continue + if (node instanceof AbortSignal) continue + if (seen.has(node)) continue seen.add(node) Object.freeze(node) - for (const key of Object.keys(node)) { - walk((node as Record)[key]) + const keys = Object.keys(node) + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index] + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) continue + pending.push({ kind: 'property', source: node as Record, key }) } } - walk(value) return value } diff --git a/packages/llm/llm/tests/call-config.spec.ts b/packages/llm/llm/tests/call-config.spec.ts index 6479ec8f85..a5426e815f 100644 --- a/packages/llm/llm/tests/call-config.spec.ts +++ b/packages/llm/llm/tests/call-config.spec.ts @@ -56,6 +56,26 @@ describe('deepFreeze', () => { deepFreeze(cyclic) expect(Object.isFrozen(cyclic)).toBe(true) }) + + it('freezes nesting deeper than the JavaScript call stack', () => { + const depth = 5_000 + const root: unknown[] = [] + let cursor = root + for (let index = 0; index < depth; index++) { + const child: unknown[] = [] + cursor.push(child) + cursor = child + } + + deepFreeze(root) + + cursor = root + for (let index = 0; index < depth; index++) { + expect(Object.isFrozen(cursor)).toBe(true) + cursor = cursor[0] as unknown[] + } + expect(Object.isFrozen(cursor)).toBe(true) + }) }) describe('agent-loop request identity', () => { From 2be046dcf268c2bbdc8372debbe196e14ee7622f Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:37:30 +0800 Subject: [PATCH 113/368] docs: refine README product copy --- ...-07-22-product-first-root-readme.i18n.yaml | 6 ---- .../2026-07-22-product-first-root-readme.md | 29 ------------------- ...2026-07-22-product-first-root-readme.zh.md | 29 ------------------- README.i18n.yaml | 4 +-- README.md | 12 +++++--- README.zh.md | 12 +++++--- 6 files changed, 18 insertions(+), 74 deletions(-) delete mode 100644 .agents/notes/implemented/process/2026-07-22-product-first-root-readme.i18n.yaml delete mode 100644 .agents/notes/implemented/process/2026-07-22-product-first-root-readme.md delete mode 100644 .agents/notes/implemented/process/2026-07-22-product-first-root-readme.zh.md diff --git a/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.i18n.yaml b/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.i18n.yaml deleted file mode 100644 index 5647413ef0..0000000000 --- a/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.i18n.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each -# 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 -2026-07-22-product-first-root-readme.md: 3d295d39119e9dd70af53cef68948d928a69120a -2026-07-22-product-first-root-readme.zh.md: ebfa0904536fe409873afa5dc88b76d4f7ee9dc7 diff --git a/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.md b/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.md deleted file mode 100644 index 3d295d3911..0000000000 --- a/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.md +++ /dev/null @@ -1,29 +0,0 @@ -# Agent Note: Product-first root README - -Status: implemented - -English | [中文](2026-07-22-product-first-root-readme.zh.md) - -## Problem - -The root README is the first page for people evaluating DeepSeek Harness, but SDK-first contributor detail competes with the shortest path from product identity to installation and launch. Exhaustive package inventories, architecture diagrams, demos, and duplicated technical explanations also age faster than the interfaces they describe. - -## Decision - -The root README presents DeepSeek Harness as an installable coding agent first. It names the SDK foundation, keeps the supported one-line installer, and puts the Web UI, TUI, and headless entry points before architecture and contributor material. - -The capability overview stays compact: it identifies the familiar built-in coding capabilities, makes plugin extensibility the distinguishing design, and presents Code Mode and the self-referential Cordis tools as explicit opt-ins. Detailed contracts remain at their owning documentation and are linked instead of copied into the root README. - -The English and Chinese READMEs share the product, installation, capability, development, and license structure. Their community sections intentionally follow the primary channel for each language audience: Twitter in English and the WeChat community QR code in Chinese. The QR code is the only retained README media because it is a functional entry point rather than product decoration. - -## Alternatives considered - -**Keep an SDK-first contributor README.** This makes the repository architecture visible immediately, but it delays the answer to what the product is and how to run it. Contributor orientation remains available through the development and architecture links. - -**Adopt a full marketing page with badges, screenshots, an architecture diagram, a package catalog, and tutorials.** This provides more material on the landing page, but duplicates fast-moving facts and creates media maintenance work before the product surface is stable. - -**Use the same community channel in both languages.** Exact channel symmetry is simpler, but it is less useful when the two language audiences gather in different places. The technical content remains paired while the community destination is audience-specific. - -## Consequences - -A new reader reaches a runnable interface quickly and can follow stable links for deeper SDK details. The root README stays small enough to update whenever the installer or CLI surface changes. Rich media, package inventories, and long-form tutorials remain outside this entry point until they have a durable owner and maintenance path. diff --git a/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.zh.md b/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.zh.md deleted file mode 100644 index ebfa090453..0000000000 --- a/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.zh.md +++ /dev/null @@ -1,29 +0,0 @@ -# Agent Note: 以产品为先的根 README - -Status: implemented - -[English](2026-07-22-product-first-root-readme.md) | 中文 - -## 问题 - -根 README 是评估 DeepSeek Harness 的读者最先看到的页面,但以 SDK 为先的贡献者信息会挤占从产品定位直达安装与启动的最短路径。详尽的包(package)清单、架构图、演示以及重复的技术说明,也比其描述的接口更快失效。 - -## 决策 - -根 README 首先将 DeepSeek Harness 呈现为一款可安装的 coding agent(编程智能体)。它说明产品基于 SDK,保留受支持的单行安装命令,并将 Web UI、TUI 和 Headless 入口置于架构与贡献者资料之前。 - -功能概览保持简洁:它说明常见的内置编程功能,突出插件扩展性这一差异化设计,并明确 Code Mode 和自指 Cordis 工具都需显式启用。详细契约留在各自的权威文档中;根 README 只提供链接,不复制内容。 - -中英文 README 采用相同的产品、安装、功能、开发和许可证结构。社区章节则有意采用各语言读者的主要渠道:英文版指向 Twitter,中文版提供微信社区二维码。二维码是 README 中唯一保留的媒体,因为它是实际入口,而非产品装饰。 - -## 备选方案 - -**保留以 SDK 为先的贡献者 README。** 这能让读者立即看到仓库架构,却延后了“产品是什么、如何运行”这两个答案。贡献者仍可通过开发与架构链接获得所需指引。 - -**采用包含徽章、截图、架构图、包清单和教程的完整营销页面。** 这会让落地页承载更多材料,却会重复易变事实,并在产品接口稳定前增加媒体维护工作。 - -**两种语言采用同一个社区渠道。** 渠道完全对称更简单,但当两种语言的读者聚集在不同平台时,这种做法实用性更低。技术内容保持配对,社区目的地则按读者群体选择。 - -## 影响 - -新读者可以快速进入可运行的界面,并通过稳定链接了解更深入的 SDK 细节。根 README 足够精简,可在安装器或 CLI 接口变化时及时更新。在富媒体、包清单和长篇教程拥有持久的负责方与维护路径之前,它们不进入这个产品入口。 diff --git a/README.i18n.yaml b/README.i18n.yaml index 9d14f74bbb..f7dca486db 100644 --- a/README.i18n.yaml +++ b/README.i18n.yaml @@ -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 -README.md: a32ad5cddd2bcaa9468031e5833aab8e78dac52b -README.zh.md: 4ffb222b2f2bff8c41ac42c047ea034e4416d4d7 +README.md: 366bea0b6d68b7eca9f53581d3bb727574adb5ef +README.zh.md: 0508b2c4a7a580f137315740135bf36154c6513b diff --git a/README.md b/README.md index a32ad5cddd..366bea0b6d 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,18 @@ English | [中文](README.zh.md) -DeepSeek Harness (`dsh`) is an open-source coding agent built on the DeepSeek Harness SDK, where everything is a plugin. +DeepSeek Harness (`dsh`) is an open-source coding agent built on the DeepSeek Harness SDK, where **everything is a plugin**. ## Install -Install `dsh` with one command. The installer requires `git` and Node `^22.19 || >=24`, offers to install `pnpm` when it is missing, and prompts for a DeepSeek API key: +Install `dsh` with one command: ```sh curl -fsSL https://raw.githubusercontent.com/deepseek-harness/deepseek-harness/master/scripts/install.sh | sh ``` +The installer requires `git` and Node `^22.19 || >=24`, offers to install `pnpm` when it is missing, and prompts for a DeepSeek API key. + The installer clones DeepSeek Harness to `~/.dsh/source`, links `dsh` into `~/.local/bin`, and launches it. Re-running the command updates the checkout. See [`scripts/install.sh`](scripts/install.sh) for alternate install locations and other options. ## Use DeepSeek Harness @@ -48,7 +50,7 @@ dsh -p "summarize this workspace" Built-in capabilities cover file reading, editing, and search; shell execution; reusable skills; task tracking; subagents and workflows; persistent sessions; and context compaction. The TUI also includes Plan Mode. - **Everything is a plugin.** Models, tools, policies, storage, context management, and interfaces are composable [Cordis plugins](docs/user/develop/basic/index.md), so deployments can extend or replace behavior without forking the agent loop. See the [architecture](docs/architecture.md) for the underlying design. -- **Code Mode is opt-in.** It exposes a `run_code` tool and a generated TypeScript SDK; only program output re-enters model context. See [Code Mode](packages/core/tools/README.md#code-mode). +- **Code Mode (opt-in).** It exposes a `run_code` tool and a generated TypeScript SDK; only program output re-enters model context. See [Code Mode](packages/core/tools/README.md#code-mode). - **Self-referential Cordis tools are opt-in.** They let the agent inspect its live runtime and mount or unmount plugins while it runs. See the [Cordis tools](packages/cordis/tool-cordis/README.md). ## Community @@ -62,7 +64,9 @@ pnpm install pnpm run test:coverage ``` -Start with the [development guide](docs/development.md), read the [architecture](docs/architecture.md) before changing packages, and follow [AGENTS.md](AGENTS.md) when working in this repository. +Start with the [development guide](docs/development.md) and read the [architecture](docs/architecture.md) before changing packages. + +For agents, follow [AGENTS.md](AGENTS.md). DeepSeek Harness is currently pre-release. diff --git a/README.zh.md b/README.zh.md index 4ffb222b2f..0508b2c4a7 100644 --- a/README.zh.md +++ b/README.zh.md @@ -2,16 +2,18 @@ [English](README.md) | 中文 -DeepSeek Harness(`dsh`)是一款基于 DeepSeek Harness SDK 构建的开源 coding agent(编程智能体),一切皆插件。 +DeepSeek Harness(`dsh`)是一款基于 DeepSeek Harness SDK 构建的开源 coding agent(编程智能体),**一切皆插件**。 ## 安装 -使用一条命令安装 `dsh`。安装器要求系统已安装 `git` 和 Node `^22.19 || >=24`,缺少 `pnpm` 时可代为安装,并会提示输入 DeepSeek API 密钥: +使用一条命令安装 `dsh`: ```sh curl -fsSL https://raw.githubusercontent.com/deepseek-harness/deepseek-harness/master/scripts/install.sh | sh ``` +安装器要求系统已安装 `git` 和 Node `^22.19 || >=24`,缺少 `pnpm` 时可代为安装,并会提示输入 DeepSeek API 密钥。 + 安装器会将 DeepSeek Harness 克隆到 `~/.dsh/source`,把 `dsh` 链接到 `~/.local/bin`,然后启动它。再次运行该命令会更新源码目录。其他安装位置和选项见 [`scripts/install.sh`](scripts/install.sh)。 ## 使用 DeepSeek Harness @@ -48,7 +50,7 @@ dsh -p "summarize this workspace" 内置功能涵盖文件读取、编辑与搜索、shell 执行、可复用 skill(技能)、任务跟踪、subagent 与工作流、持久化会话,以及上下文压缩(context compaction)。TUI 还包含 Plan Mode。 - **一切皆插件。** 模型、工具、策略、存储、上下文管理和界面均可组合为 [Cordis 插件](docs/user/develop/basic/index.md),部署方无需 fork agent loop(智能体循环)即可扩展或替换行为。底层设计见[架构文档](docs/architecture.md)。 -- **Code Mode 需显式启用。** 它会提供 `run_code` 工具和生成的 TypeScript SDK,只有程序输出会重新进入模型上下文。参见 [Code Mode](packages/core/tools/README.md#code-mode)。 +- **Code Mode(需显式启用)。** 它会提供 `run_code` 工具和生成的 TypeScript SDK,只有程序输出会重新进入模型上下文。参见 [Code Mode](packages/core/tools/README.md#code-mode)。 - **自指 Cordis 工具需显式启用。** 这些工具可让 agent 检查自身的实时运行时,并在运行中挂载或卸载插件。参见 [Cordis 工具](packages/cordis/tool-cordis/README.md)。 ## 社区 @@ -66,7 +68,9 @@ pnpm install pnpm run test:coverage ``` -请先阅读[开发指南](docs/development.md);修改包之前,请阅读[架构文档](docs/architecture.md);在本仓库工作时,请遵循 [AGENTS.md](AGENTS.md)。 +请先阅读[开发指南](docs/development.md);修改包之前,请阅读[架构文档](docs/architecture.md)。 + +面向 agent:遵循 [AGENTS.md](AGENTS.md)。 DeepSeek Harness 目前处于预发布阶段。 From d626b2582de933b1ce3caed1fe539e60d35084fe Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:39:55 +0800 Subject: [PATCH 114/368] fix(tools): scope canonical provenance to dispatch --- ...0-canonical-tool-output-contract.i18n.yaml | 4 +- ...26-07-20-canonical-tool-output-contract.md | 2 +- ...07-20-canonical-tool-output-contract.zh.md | 2 +- packages/core/tools/README.md | 2 +- packages/core/tools/src/index.ts | 26 +++++----- packages/core/tools/tests/tools.spec.ts | 49 +++++++++++++++++++ 6 files changed, 67 insertions(+), 18 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml index d106745e70..b81d96ba2a 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml @@ -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 -2026-07-20-canonical-tool-output-contract.md: 4099568de5dcc21a89b7873d4a6d4c7e9c62f8e4 -2026-07-20-canonical-tool-output-contract.zh.md: 01b50ef7493ea6548cd238f55e445a702e4d78b3 +2026-07-20-canonical-tool-output-contract.md: 9cc7c97c1f0c9e0753ee826c1e20a3a425e2caf3 +2026-07-20-canonical-tool-output-contract.zh.md: 183a7e6bf212e63dffca1a346aa907f66006444a diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md index 4099568de5..9cc7c97c1f 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md @@ -24,7 +24,7 @@ output: { `defineTool` infers the body return and both projectors from the unified `ValueSchemaSpec`. Raw and dynamic definitions provide the compiled `JsonSchemaNode` form. Registration rejects a missing declaration or unsupported raw schema; there is no content-return compatibility path. -For each successful dispatch the registry snapshots the returned value as lossless `JsonValue`, validates it against `output.schema`, deep-freezes it, then invokes the pure renderer and, for a direct surface call, the optional metadata projector. Renderer, projector, schema, or lossless-JSON failures are contained as ordinary `ToolOutputError` results. An around `tools/execute` wrapper receives and returns the canonical success/failure union; a wrapper-authored success is normalized again through the resolved tool's output declaration instead of trusting independently authored content. +For each successful dispatch the registry snapshots the returned value as lossless `JsonValue`, validates it against `output.schema`, deep-freezes it, then invokes the pure renderer and, for a direct surface call, the optional metadata projector. Renderer, projector, schema, or lossless-JSON failures are contained as ordinary `ToolOutputError` results. An around `tools/execute` wrapper receives and returns the canonical success/failure union; a wrapper-authored success is normalized again through the resolved tool's output declaration instead of trusting independently authored content. Canonical-result provenance is scoped to the immutable dispatch token, so returning a cached result from another call or tool triggers normalization under the active declaration rather than bypassing it. ```ts ignore-check type ToolExecutionResult = diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md index 01b50ef749..183a7e6bf2 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md @@ -24,7 +24,7 @@ output: { `defineTool` 从统一的 `ValueSchemaSpec` 推导工具主体返回值和两个投影器的类型。原始定义和动态定义则提供编译后的 `JsonSchemaNode` 形式。注册时会拒绝缺失输出声明或采用不受支持原始 schema 的定义,不提供兼容旧式内容返回值的路径。 -每次成功分发时,注册表会将返回值快照为无损 `JsonValue`,依据 `output.schema` 校验并深度冻结,然后调用纯渲染器;对于直接的外层调用,还会调用可选的元数据投影器。渲染器、投影器、schema 或无损 JSON 处理失败都会被收敛为普通 `ToolOutputError` 结果。around `tools/execute` 包装层接收并返回规范的成功/失败联合;包装层自行产生的成功结果会再次通过已解析工具的输出声明完成归一化,而不会信任其独立编写的内容。 +每次成功分发时,注册表会将返回值快照为无损 `JsonValue`,依据 `output.schema` 校验并深度冻结,然后调用纯渲染器;对于直接的外层调用,还会调用可选的元数据投影器。渲染器、投影器、schema 或无损 JSON 处理失败都会被收敛为普通 `ToolOutputError` 结果。around `tools/execute` 包装层接收并返回规范的成功/失败联合;包装层自行产生的成功结果会再次通过已解析工具的输出声明完成归一化,而不会信任其独立编写的内容。每个规范结果只归属于一个不可变的分发 token;因此,如果包装层返回来自其他调用或工具的缓存结果,系统会依据当前生效的输出声明重新执行归一化,而不会绕过这一步。 ```ts ignore-check type ToolExecutionResult = diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 61d7f82af6..24beab99c4 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -52,7 +52,7 @@ The live registry pipeline has three transformable waterfalls followed by the ob - Tool plugins call `ctx.tools.register()` — schemas flow into the assembly automatically. - `tools/pre-execute` is the reorderable allow/deny/ask gate; `ctx.tools.guard()` adds monotonic owner policy after it. -- `tools/execute` wraps normalized canonical dispatch for timeout, retry, or metrics. Wrappers may replace only the operational signal; a wrapper-authored success is normalized through the resolved tool's output declaration. +- `tools/execute` wraps normalized canonical dispatch for timeout, retry, or metrics. Wrappers may replace only the operational signal; a wrapper-authored success is normalized through the resolved tool's output declaration. Canonical-result provenance belongs to one immutable dispatch token, so a cached result from another call or tool is revalidated under the active declaration. - `tools/post-execute` may replace presentation content, replace the canonical value, block with feedback, or attach ordered contexts; `tools/result` observes the immutable final outcome. Content replacement is not a confidentiality boundary: block or replace the value when programmatic consumers must not receive it. - Exact signatures and ordering live in the generated [event catalog](../../../docs/cordis-catalog/events.md) and [pipeline](../../../docs/tool-execution-pipeline.md). - MCP servers: one plugin per server, discover tools, call `ctx.tools.register()` with the server's schemas. diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index a85b4e61c8..2cd08ed168 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -1093,7 +1093,7 @@ export class ToolRegistry extends Service { if (deferredContexts === undefined) throw new Error('tool registry scheduler invariant violated: unprepared execution') const resultWithDeferredContexts: ToolExecutionResult = deferredContexts.length === 0 ? normalized - : this.markCanonical({ + : this.markCanonical(exec, { ...normalized, additionalContexts: [ ...deferredContexts, @@ -1244,7 +1244,7 @@ export class ToolRegistry extends Service { const decisionContexts = decision.additionalContexts ?? [] if (decision.kind === 'block') { const message = failureMessageFromContent(decision.feedback) - return this.markCanonical({ + return this.markCanonical(exec, { content: decision.feedback, isError: true, error: { message }, @@ -1265,24 +1265,24 @@ export class ToolRegistry extends Service { const tool = this.get(exec.name, exec.agent) if (tool === undefined) throw new ToolNotFoundError(exec.name) const replaced = this.createSuccessResult(exec, tool, decision.value) - return this.markCanonical({ + return this.markCanonical(exec, { ...replaced, ...additionalContexts.length > 0 ? { additionalContexts } : {}, }) } - return this.markCanonical({ + return this.markCanonical(exec, { ...result, ...decision.content !== undefined ? { content: decision.content } : {}, ...additionalContexts.length > 0 ? { additionalContexts } : {}, }) } - /** Results created by the registry already own a validated, frozen canonical value. */ - private readonly canonicalResults = new WeakSet() + /** Registry-normalized results and the exact dispatch that validated each value. */ + private readonly canonicalResults = new WeakMap() - /** Mark a registry-normalized result without freezing presentation fields prematurely. */ - private markCanonical(result: T): T { - this.canonicalResults.add(result) + /** Mark one registry-normalized result as canonical only for its owning dispatch. */ + private markCanonical(exec: ToolExecution, result: T): T { + this.canonicalResults.set(result, exec.token) return result } @@ -1309,7 +1309,7 @@ export class ToolRegistry extends Service { } meta = snapshotProjection(tool.name, 'presentationMeta', projected) } - return this.markCanonical(this.materializeFinalResult({ + return this.markCanonical(exec, this.materializeFinalResult({ isError: false, value, content, @@ -1319,9 +1319,9 @@ export class ToolRegistry extends Service { /** Normalize an around-dispatch wrapper's authored result through the owning output contract. */ private normalizeDispatchResult(exec: ToolExecution, result: ToolExecutionResult): ToolExecutionResult { - if (this.canonicalResults.has(result)) return result + if (this.canonicalResults.get(result) === exec.token) return result if (result.isError) { - return this.markCanonical({ + return this.markCanonical(exec, { isError: true, error: result.error, content: result.content, @@ -1332,7 +1332,7 @@ export class ToolRegistry extends Service { const tool = this.get(exec.name, exec.agent) if (tool === undefined) throw new ToolNotFoundError(exec.name) const normalized = this.createSuccessResult(exec, tool, result.value) - return this.markCanonical({ + return this.markCanonical(exec, { ...normalized, ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, }) diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index d06ced5f95..37d4663636 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -1588,6 +1588,55 @@ describe('ToolRegistry', () => { expect(result.content[0]).toMatchObject({ text: 'short-circuited' }) }) + it('revalidates a cached canonical result returned from a different dispatch', async () => { + const ctx = await setup() + ctx.tools.register({ ...echoTool, name: 'string-output', async execute() { return 'cached' } }) + let objectBodyRan = false + ctx.tools.register(defineTool({ + name: 'object-output', + description: 'Return one closed object.', + parameters: {}, + output: { + schema: { + type: 'object', + properties: { ok: { type: 'boolean', required: true } }, + additionalProperties: false, + }, + render: (_args, value) => [{ type: 'text', text: String(value.ok) }], + }, + execute() { + objectBodyRan = true + return Promise.resolve({ ok: true }) + }, + })) + let cached: ToolExecutionResult | undefined + ctx.on('tools/execute', async (exec, next) => { + if (exec.name === 'string-output') { + cached = await next() + return cached + } + if (exec.name === 'object-output') { + if (cached === undefined) throw new Error('expected the first dispatch result') + return cached + } + return next() + }) + + const first = await ctx.tools.execute({ + signal: testToolSignal, callId: CallId('cached-first'), name: 'string-output', arguments: {}, + }) + const second = await ctx.tools.execute({ + signal: testToolSignal, callId: CallId('cached-second'), name: 'object-output', arguments: {}, + }) + + expect(first.isError ? undefined : first.value).toBe('cached') + expect(objectBodyRan).toBe(false) + expect(second).toMatchObject({ + isError: true, + error: { info: { name: 'ToolOutputError', code: 'INVALID_TOOL_OUTPUT' } }, + }) + }) + it('preserves additionalContexts supplied by an around-dispatch result', async () => { const ctx = await setup() ctx.tools.register(echoTool) From 441a17d62eea9ec1d0f556f9aea0eae23af88d1b Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:39:55 +0800 Subject: [PATCH 115/368] fix(ci): ignore translation records in Cordis config scan The Loader verifier matched docs/cordis-primer.i18n.yaml solely because its basename contained cordis. Centralize file discovery, exclude i18n sidecars, and cover Loader YAML plus excluded trees with a regression test. --- scripts/cordis-config-files.spec.ts | 36 +++++++++++++++++++++++++++++ scripts/cordis-config-files.ts | 18 +++++++++++++++ scripts/verify-cordis-config.ts | 6 ++--- 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 scripts/cordis-config-files.spec.ts create mode 100644 scripts/cordis-config-files.ts diff --git a/scripts/cordis-config-files.spec.ts b/scripts/cordis-config-files.spec.ts new file mode 100644 index 0000000000..49da2c6aaf --- /dev/null +++ b/scripts/cordis-config-files.spec.ts @@ -0,0 +1,36 @@ +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, describe, expect, it } from 'vitest' +import { cordisConfigFiles } from './cordis-config-files.ts' + +const roots: string[] = [] + +afterEach(() => { + for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }) +}) + +describe('cordisConfigFiles', () => { + it('finds Loader YAML without treating translation records as configs', () => { + const root = mkdtempSync(join(tmpdir(), 'dsh-cordis-config-files-')) + roots.push(root) + for (const directory of ['.claude', 'docs', 'examples', 'node_modules/pkg', 'vendor/pkg']) { + mkdirSync(join(root, directory), { recursive: true }) + } + for (const file of [ + '.claude/hidden.cordis.yml', + 'docs/cordis-primer.i18n.yaml', + 'examples/agent.cordis.yaml', + 'examples/headless.cordis.yml', + 'node_modules/pkg/hidden.cordis.yml', + 'vendor/pkg/hidden.cordis.yml', + ]) { + writeFileSync(join(root, file), '[]\n') + } + + expect(cordisConfigFiles(root)).toEqual([ + 'examples/agent.cordis.yaml', + 'examples/headless.cordis.yml', + ]) + }) +}) diff --git a/scripts/cordis-config-files.ts b/scripts/cordis-config-files.ts new file mode 100644 index 0000000000..9473779efe --- /dev/null +++ b/scripts/cordis-config-files.ts @@ -0,0 +1,18 @@ +/** Cordis Loader configuration file discovery. */ + +import { globSync } from 'node:fs' + +/** + * Return repository-relative Cordis Loader YAML paths under `root`. + * + * Translation consistency records are YAML sidecars, never Loader inputs. + * + * @param root Repository root to scan. + * @returns Sorted repository-relative Loader configuration paths. + */ +export function cordisConfigFiles(root: string): string[] { + return globSync(['**/*cordis*.yml', '**/*cordis*.yaml'], { + cwd: root, + exclude: ['.claude/**', 'node_modules/**', 'vendor/**', '**/*.i18n.yaml'], + }).sort() +} diff --git a/scripts/verify-cordis-config.ts b/scripts/verify-cordis-config.ts index c9820a67a8..fafc147ce9 100644 --- a/scripts/verify-cordis-config.ts +++ b/scripts/verify-cordis-config.ts @@ -12,6 +12,7 @@ import { globSync, readFileSync } from 'node:fs' import { dirname, relative, resolve } from 'node:path' import * as yaml from 'js-yaml' import ts from 'typescript' +import { cordisConfigFiles } from './cordis-config-files.ts' interface JsExpr { __jsExpr: string @@ -39,10 +40,7 @@ const jsExprType = new yaml.Type('tag:yaml.org,2002:js', { }) const schema = yaml.JSON_SCHEMA.extend(jsExprType) -const files = globSync(['**/*cordis*.yml', '**/*cordis*.yaml'], { - cwd: root, - exclude: ['.claude/**', 'node_modules/**', 'vendor/**'], -}).sort() +const files = cordisConfigFiles(root) const errors: string[] = [] const examplePluginReferences: PluginReference[] = [] From fc23a89208f73ec3001527d1bf7d634dfebfa738 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:40:42 +0800 Subject: [PATCH 116/368] fix(web): title sessions created by host --- ...-07-21-log-backed-session-titles.i18n.yaml | 4 +- .../2026-07-21-log-backed-session-titles.md | 2 +- ...2026-07-21-log-backed-session-titles.zh.md | 2 +- apps/web/tests/smoke-real.e2e.ts | 13 ++++++ packages/host/runtime/README.md | 4 +- packages/host/runtime/src/boot.ts | 11 +++++ packages/host/runtime/src/start.ts | 7 ++- .../host/runtime/tests/host-runtime.spec.ts | 44 ++++++++++++++++++- 8 files changed, 76 insertions(+), 11 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.i18n.yaml b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.i18n.yaml index 17f4515c1d..f2e0a64585 100644 --- a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.i18n.yaml @@ -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 -2026-07-21-log-backed-session-titles.md: 494187a73c58fb2313d802825c3ec9f9994d6f2b -2026-07-21-log-backed-session-titles.zh.md: cae51cca920fad748cb1944d35cc1b80850eb6ee +2026-07-21-log-backed-session-titles.md: 6d2aa2049b57d82014f1a85555a1bda9b537bece +2026-07-21-log-backed-session-titles.zh.md: 7f43832f3a0b6a28227b6a862d78be117c7cb398 diff --git a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md index 494187a73c..6d2aa2049b 100644 --- a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md +++ b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md @@ -12,7 +12,7 @@ Session identity metadata is immutable, the event log is the replay and fork bou ## Decision -The [`session-title` capability family](../../../../packages/session-title/README.md) owns title state and generation policy. `@deepseek-ai/dsh-session-title` provides `ctx.sessionTitle`, a deterministic first-message fallback, and a registry for at most one optional asynchronous provider. `@deepseek-ai/dsh-session-title-llm` owns the common auxiliary-model request policy; separate first-message and all-user-messages plugins choose input cadence. The shared agent spine mounts only the fallback service with overridable explicit example limits, leaving both model providers opt-in. +The [`session-title` capability family](../../../../packages/session-title/README.md) owns title state and generation policy. `@deepseek-ai/dsh-session-title` provides `ctx.sessionTitle`, a deterministic first-message fallback, and a registry for at most one optional asynchronous provider. `@deepseek-ai/dsh-session-title-llm` owns the common auxiliary-model request policy; separate first-message and all-user-messages plugins choose input cadence. The shared agent spine and Web host runtime mount the fallback service with explicit overridable limits; neither composition mounts an asynchronous provider, so a fresh Web session persists a title without adding a model call. Either model provider remains opt-in. ### Event ownership and folding diff --git a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.zh.md b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.zh.md index cae51cca92..7f43832f3a 100644 --- a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.zh.md +++ b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.zh.md @@ -12,7 +12,7 @@ Status: implemented ## 决策 -[`session-title` 功能包族](../../../../packages/session-title/README.md)负责标题状态和生成策略。`@deepseek-ai/dsh-session-title` 提供 `ctx.sessionTitle`、确定性的首消息回退方案,以及一个至多接受单个可选异步提供方的注册表。`@deepseek-ai/dsh-session-title-llm` 负责通用的辅助模型请求策略;首消息插件和全部用户消息插件分别选择输入调度方式。共享 agent 主干只挂载回退服务,并为其显式设置可覆盖的示例限制;两种模型提供方均需按需启用。 +[`session-title` 功能包族](../../../../packages/session-title/README.md)负责标题状态和生成策略。`@deepseek-ai/dsh-session-title` 提供 `ctx.sessionTitle`、确定性的首消息回退方案,以及一个至多接受单个可选异步提供方的注册表。`@deepseek-ai/dsh-session-title-llm` 负责通用的辅助模型请求策略;首消息插件和全部用户消息插件分别选择输入调度方式。共享 agent 主干与 Web host 运行时都会挂载回退服务,并显式设置可覆盖的限制;两种组合均不挂载异步提供方,因此新建的 Web 会话无需增加模型调用即可持久化标题。两种模型提供方均仍需按需启用。 ### 事件归属与折叠 diff --git a/apps/web/tests/smoke-real.e2e.ts b/apps/web/tests/smoke-real.e2e.ts index a51e0c9e56..4c4519abf4 100644 --- a/apps/web/tests/smoke-real.e2e.ts +++ b/apps/web/tests/smoke-real.e2e.ts @@ -183,6 +183,19 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY || notReady.length > 0)('web smoke // near-empty here means that class of bug is back. await page.waitForFunction(() => document.body.innerText.length > 50, undefined, { timeout: 15_000 }) expect(pageErrors).toEqual([]) + await page.waitForFunction( + () => document.title !== 'DeepSeek Harness' && document.title.endsWith(' — DeepSeek Harness'), + undefined, + { timeout: 15_000 }, + ) + const durableTitle = (await page.title()).replace(/ — DeepSeek Harness$/, '') + const sessionTree = page.getByRole('tree', { name: 'Sessions' }) + const projectRow = sessionTree.getByRole('treeitem').first() + if (await projectRow.getAttribute('aria-expanded') === 'false') await projectRow.click() + await Promise.all([ + sessionTree.getByText(durableTitle, { exact: true }).waitFor({ timeout: 10_000 }), + page.getByRole('navigation').getByText(durableTitle, { exact: true }).waitFor({ timeout: 10_000 }), + ]) await page.waitForFunction(() => document.body.innerText.includes('介绍完毕'), undefined, { timeout: 120_000 }) await screen(page, '04-round-complete') }, 150_000) diff --git a/packages/host/runtime/README.md b/packages/host/runtime/README.md index 39f9888180..98c860cd95 100644 --- a/packages/host/runtime/README.md +++ b/packages/host/runtime/README.md @@ -1,6 +1,6 @@ # @deepseek-ai/dsh-host-runtime -Host runtime assembly for `dsc`: `bootHost` composes the core plugin spine (LLM service + DeepSeek adapter, sessions with JSONL persistence, system prompt, tools, agents, agent loop, local bash), `createApiProxy` implements the [`dsh-host-apiproxy`](../apiproxy/README.md) contract over that composition, and `startHost` is the one-step shell seam returning `{ api, handler, defaults, ctx, dispose }`. +Host runtime assembly for `dsh`: `bootHost` composes the core plugin spine (LLM service + DeepSeek adapter, sessions with JSONL persistence and deterministic fallback titles, system prompt, tools, agents, agent loop, local bash), `createApiProxy` implements the [`dsh-host-apiproxy`](../apiproxy/README.md) contract over that composition, and `startHost` is the one-step shell seam returning `{ api, handler, defaults, ctx, dispose }`. Which plugins mount and with what defaults is decided only here — shells must not `ctx.plugin` to alter the assembly. `RunningHost.ctx` is a formal seam with exactly two sanctioned uses: mounting protocol front-door plugins (e.g. a future `dsh acp`) and headless session-event subscription; consuming clients must not bypass `api` through it. @@ -11,6 +11,8 @@ Which plugins mount and with what defaults is decided only here — shells must | `persistenceRoot` | (required) | Root directory for JSONL session persistence. | | `provider` | `'deepseek'` | Default provider route injected as agentOptions on create/resume and reported by `host.describe`. | | `model` | `'deepseek-v4-flash'` | Default model id, same single source as `provider`. | +| `cwd` | `process.cwd()` | Default project directory for a session whose create request omits `cwd`. | +| `sessionTitle` | 5 words / 40 fallback bytes / 80 accepted bytes | Deterministic fallback-title limits. The host mounts no asynchronous title provider, so title creation adds no model call. | ## ApiProxy implementation notes diff --git a/packages/host/runtime/src/boot.ts b/packages/host/runtime/src/boot.ts index ca40b9f8b3..e11aaa3a31 100644 --- a/packages/host/runtime/src/boot.ts +++ b/packages/host/runtime/src/boot.ts @@ -8,6 +8,7 @@ import { Context } from 'cordis' import Timer from '@cordisjs/plugin-timer' import LlmService from '@deepseek-ai/dsh-llm' import SessionStore from '@deepseek-ai/dsh-session' +import SessionTitleService, { type Config as SessionTitleConfig } from '@deepseek-ai/dsh-session-title' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import ToolRegistry from '@deepseek-ai/dsh-tools' import AgentRegistry from '@deepseek-ai/dsh-agent' @@ -38,6 +39,13 @@ import * as timeoutPolicy from '@deepseek-ai/dsh-timeout-policy' import SpillLocal from '@deepseek-ai/dsh-spill-local' import * as spillPolicy from '@deepseek-ai/dsh-spill-policy' +/** Default deterministic title policy for sessions created through the host. */ +const DEFAULT_SESSION_TITLE_CONFIG: SessionTitleConfig = { + fallbackMaxWords: 5, + fallbackMaxBytes: 40, + maxTitleBytes: 80, +} + /** Options for bootHost — the assembly-layer composition knobs. */ export interface BootHostOptions { /** Root directory for JSONL session persistence. */ @@ -46,6 +54,8 @@ export interface BootHostOptions { provider?: string /** Default model id (defaults to 'deepseek-v4-flash', matching the demos). */ model?: string + /** Deterministic fallback-title limits; no asynchronous title provider is mounted by the host. */ + sessionTitle?: SessionTitleConfig /** * Default project directory for sessions created without an explicit cwd * (defaults to the host process working directory). A session's cwd is its @@ -89,6 +99,7 @@ export async function bootHost(options: BootHostOptions): Promise { await ctx.plugin(Timer) await ctx.plugin(LlmService) await ctx.plugin(SessionStore) + await ctx.plugin(SessionTitleService, options.sessionTitle ?? DEFAULT_SESSION_TITLE_CONFIG) await ctx.plugin(SystemPrompt, { persona: '' }) await ctx.plugin(ToolRegistry) await ctx.plugin(AgentRegistry) diff --git a/packages/host/runtime/src/start.ts b/packages/host/runtime/src/start.ts index 44412cf184..94e5f22da1 100644 --- a/packages/host/runtime/src/start.ts +++ b/packages/host/runtime/src/start.ts @@ -16,10 +16,9 @@ import { createApiProxy } from './api-proxy.ts' /** Options for startHost. */ export interface StartHostOptions { /** - * Passed through to bootHost verbatim (persistenceRoot required + - * provider?/model?). Future host-level knobs (profile, log sink — any - * output added to the assembly MUST be switchable off here) land as - * additive fields. + * Passed through to bootHost verbatim. Future host-level knobs (profile, + * log sink — any output added to the assembly MUST be switchable off here) + * land as additive fields. */ boot: BootHostOptions } diff --git a/packages/host/runtime/tests/host-runtime.spec.ts b/packages/host/runtime/tests/host-runtime.spec.ts index 81bc4fc009..3ec7535362 100644 --- a/packages/host/runtime/tests/host-runtime.spec.ts +++ b/packages/host/runtime/tests/host-runtime.spec.ts @@ -8,6 +8,7 @@ import { agentEvents } from '@deepseek-ai/dsh-agent' import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm' import { LlmAdapter } from '@deepseek-ai/dsh-llm' import type { SessionId } from '@deepseek-ai/dsh-session' +import type { Config as SessionTitleConfig } from '@deepseek-ai/dsh-session-title' import type { HostFrame, MuxFrame } from '@deepseek-ai/dsh-host-apiproxy/api' import type { RpcRequest, RpcResponse } from '@deepseek-ai/dsh-host-apiproxy/api/rpc' import { RpcId } from '@deepseek-ai/dsh-host-apiproxy/api/rpc' @@ -92,9 +93,17 @@ afterEach(async () => { vi.unstubAllEnvs() }) -async function boot(script: (StreamChunk[] | 'hang')[] = []): Promise { +async function boot( + script: (StreamChunk[] | 'hang')[] = [], + sessionTitle?: SessionTitleConfig, +): Promise { host = await startHost({ - boot: { persistenceRoot: mkdtempSync(join(tmpdir(), 'dsh-host-runtime-')), provider: 'scripted', model: 'test-model' }, + boot: { + persistenceRoot: mkdtempSync(join(tmpdir(), 'dsh-host-runtime-')), + provider: 'scripted', + model: 'test-model', + ...(sessionTitle === undefined ? {} : { sessionTitle }), + }, }) host.ctx.llm.registerAdapter(['scripted'], new ScriptedAdapter(script)) return host @@ -149,6 +158,37 @@ describe('sessions.create / list', () => { }) describe('sessions.prompt / cancel', () => { + it.each([ + { name: 'host default', config: undefined, expected: 'Show the Web UI durable' }, + { + name: 'configured limit', + config: { fallbackMaxWords: 2, fallbackMaxBytes: 40, maxTitleBytes: 80 }, + expected: 'Show the', + }, + ] satisfies { name: string; config: SessionTitleConfig | undefined; expected: string }[])( + 'logs a durable fallback title with the $name', + async ({ config, expected }) => { + const running = await boot([textResponse('pong')], config) + const { api, ctx } = running + const { sessionId } = expectOk(await api.sessions.create(request({}))) + const agent = ctx.agents.get(sessionId) as Agent + const idle = waitForIdle(ctx, agent) + expectOk(await api.sessions.prompt(request({ + sessionId, + mode: 'queue' as const, + content: [{ type: 'text' as const, text: 'Show the Web UI durable session title' }], + }))) + await idle + + const title = agent.session.events.find(event => event.type === 'session/title') + expect(title?.data).toEqual({ + title: expected, + messageSeqs: [1], + source: { kind: 'fallback' }, + }) + }, + ) + it('queues a prompt whose rpcId rides into user/message, then the reply lands', async () => { const running = await boot([textResponse('pong')]) const { api, ctx } = running From be2080468459b6ed1ccdc544b0fadd23a64c1b79 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:48:00 +0800 Subject: [PATCH 117/368] fix(pty): keep bounded results actionable --- ...26-07-16-persistent-pty-sessions.i18n.yaml | 4 +-- .../2026-07-16-persistent-pty-sessions.md | 2 +- .../2026-07-16-persistent-pty-sessions.zh.md | 2 +- docs/config-catalog.md | 2 +- docs/event-producer-consumer.md | 2 +- packages/pty/tool-pty/README.md | 6 ++--- packages/pty/tool-pty/src/index.ts | 23 +++++++++++++--- packages/pty/tool-pty/tests/tools.spec.ts | 26 +++++++++++++++++++ 8 files changed, 55 insertions(+), 12 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index de619790dc..86c05cb07c 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml @@ -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 -2026-07-16-persistent-pty-sessions.md: db161a865f1c30fc3979e1a92dc6d427ecb58f25 -2026-07-16-persistent-pty-sessions.zh.md: 06c902437aee2e5725e1765840dce03ae15c30a4 +2026-07-16-persistent-pty-sessions.md: 689019d56d719884761407f288e1e765dd19c35d +2026-07-16-persistent-pty-sessions.zh.md: 14490137a003e2ca67b594628e506f0b74e3d4b7 diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index db161a865f..689019d56d 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -62,7 +62,7 @@ The ACP render contract is exact and location-free. `terminal_send` uses termina `terminal_send({ sessionId, text, submit?, run_in_background? })` treats `text` as UTF-8 bytes and resolves `submit` to `true` in the tool implementation. When `submit` is true it writes the platform Enter sequence after the text; when false it writes only the text, allowing control characters and REPL fragments without hidden content heuristics. `enableRunInBackground` defaults to true; false removes `run_in_background` from the schema and rejects the same undeclared argument if a caller forces it through execution. -Foreground sends return a bounded rendered delta and two independent facts: `waitReason` (`stdin_read | inferred_idle | timeout | session_exit`) and `sessionStatus` (`running` or `exited` with exit code or signal). `session_exit` refers to the PTY's top-level shell process, not an arbitrary foreground command whose status the shell consumes. A timeout never implies process exit. `dsh-tool-pty.maxResultBytes` defaults to 262144 and caps the complete UTF-8 result after wait, session, pagination, truncation, and generic task-status wrappers; the renderer reserves suffix space and preserves code-point boundaries instead of treating the backend payload cap as the final model bound. +Foreground sends return a bounded rendered delta and two independent facts: `waitReason` (`stdin_read | inferred_idle | timeout | session_exit`) and `sessionStatus` (`running` or `exited` with exit code or signal). `session_exit` refers to the PTY's top-level shell process, not an arbitrary foreground command whose status the shell consumes. A timeout never implies process exit. `dsh-tool-pty.maxResultBytes` defaults to 262144, rejects values below 64 so creation acknowledgements retain registry-issued ids, and caps the complete UTF-8 result after normalized errors, wait, session, pagination, truncation, and generic task-status wrappers; the renderer reserves suffix space and preserves code-point boundaries instead of treating the backend payload cap as the final model bound. With `run_in_background: true`, `dsh-tool-pty` registers the in-flight send on `ctx.tasks` and returns immediately with `taskId`. The producer places `maxResultBytes` on the task snapshot so `task_output`, terminal kill status, and completion notices enforce the same complete-result cap after generic metadata. `task_output(wait: true)` waits, reads incremental output, and records the final result; `task_kill` resolves the current foreground PGID and delivers a real `SIGINT`, including when the application has disabled terminal `ISIG`, and escalates only through the PTY backend's owned teardown path. If the task surface is absent, background mode fails before writing input. No PTY-specific `sleep` tool or general wake-up seam is added. diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index 06c902437a..14490137a0 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -62,7 +62,7 @@ ACP 渲染契约精确且不携带位置信息。`terminal_send` 只为前台发 `terminal_send({ sessionId, text, submit?, run_in_background? })` 将 `text` 视为 UTF-8 字节,并由工具实现在解析阶段把 `submit` 默认成 `true`。`submit` 为 true 时先写入文本,再写入平台 Enter 序列;为 false 时只写文本,使控制字符和 REPL 片段无需隐藏的内容启发式即可发送。`enableRunInBackground` 默认为 true;设为 false 时,schema 中会移除 `run_in_background`,调用方即使强行把这个未声明参数传入执行流程,也会被拒绝。 -前台发送返回有界的渲染增量和两个独立事实:`waitReason`(`stdin_read | inferred_idle | timeout | session_exit`)与 `sessionStatus`(`running`,或携带退出码或信号的 `exited`)。`session_exit` 指 PTY 顶层 shell 进程退出,不指由 shell 消费状态的任意前台命令。timeout 从不意味着进程已经退出。`dsh-tool-pty.maxResultBytes` 默认为 262144;完整 UTF-8 结果在加入等待与会话状态、分页与截断元数据以及通用 task 状态包装后,仍受该值限制。渲染器会为后缀预留空间并保持代码点边界,而不会把后端载荷上限当作面向模型结果的最终上限。 +前台发送返回有界的渲染增量和两个独立事实:`waitReason`(`stdin_read | inferred_idle | timeout | session_exit`)与 `sessionStatus`(`running`,或携带退出码或信号的 `exited`)。`session_exit` 指 PTY 顶层 shell 进程退出,不指由 shell 消费状态的任意前台命令。timeout 从不意味着进程已经退出。`dsh-tool-pty.maxResultBytes` 默认为 262144;低于 64 的值会被拒绝,以确保创建确认保留 registry 签发的 id;完整 UTF-8 结果在加入规范化错误、等待与会话状态、分页与截断元数据以及通用 task 状态包装后,仍受该值限制。渲染器会为后缀预留空间并保持代码点边界,而不会把后端载荷上限当作面向模型结果的最终上限。 当 `run_in_background: true` 时,`dsh-tool-pty` 在 `ctx.tasks` 上注册进行中的发送,并立即返回 `taskId`。生产方把 `maxResultBytes` 写入 task 快照,使 `task_output`、kill 返回的终态状态和完成通知在加上通用元数据后,仍对完整结果执行同一上限。`task_output(wait: true)` 负责等待、读取增量输出并记录最终结果;`task_kill` 会解析当前前台 PGID 并发送真正的 `SIGINT`,即使应用已禁用终端 `ISIG` 也同样如此,且后续升级仍只通过 PTY 后端拥有的 teardown 路径进行。若 task 对外接口不存在,后台模式必须在写入输入前失败。设计不新增 PTY 专用的 `sleep` 工具或通用唤醒 seam。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 2bb16b2821..3d46a0faf2 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -1383,7 +1383,7 @@ export interface Config { } ``` -Source: [`packages/pty/tool-pty/src/index.ts:33`](../packages/pty/tool-pty/src/index.ts) +Source: [`packages/pty/tool-pty/src/index.ts:44`](../packages/pty/tool-pty/src/index.ts) ## `@deepseek-ai/dsh-tool-ralph` diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index feb6fbd64b..24f0f9b252 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -42,7 +42,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:29`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`agent`](../packages/core/agent), [`system-prompt`](../packages/core/system-prompt) | | `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:35`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - | | `tools/change` | `emit` | [`packages/core/tools/src/index.ts:123`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | -| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:93`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`timeout-policy`](../packages/timeout/timeout-policy) | +| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:93`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`timeout-policy`](../packages/timeout/timeout-policy), [`tool-pty`](../packages/pty/tool-pty) | | `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:105`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`workspace-context`](../packages/context/workspace-context) | | `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:82`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | | `tools/result` | `emit` | [`packages/core/tools/src/index.ts:113`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | diff --git a/packages/pty/tool-pty/README.md b/packages/pty/tool-pty/README.md index 0857c5d3ee..8ec8601b6b 100644 --- a/packages/pty/tool-pty/README.md +++ b/packages/pty/tool-pty/README.md @@ -9,9 +9,9 @@ Six model-facing tools over `ctx.pty`: `terminal_open`, `terminal_send`, `termin | key | default | meaning | |---|---:|---| | `enableRunInBackground` | `true` | expose and accept `run_in_background`; false omits the schema field and rejects a forced undeclared argument | -| `maxResultBytes` | `262144` | UTF-8 cap for each complete terminal result or PTY task output after wait, session, pagination, truncation, and task-status metadata | +| `maxResultBytes` | `262144` | UTF-8 cap (minimum `64`) for each complete terminal result or PTY task output after wait, session, pagination, truncation, and task-status metadata | -Both values are validated at load. When a result exceeds `maxResultBytes`, rendering reserves space for control metadata and a truncation marker when they fit; cuts preserve UTF-8 boundaries. +Both values are validated at load. The minimum result cap keeps every registry-issued session or task id visible in its creation acknowledgement. When a result exceeds `maxResultBytes`, rendering reserves space for control metadata and a truncation marker when they fit; cuts preserve UTF-8 boundaries. ## Model Experience @@ -53,7 +53,7 @@ Prefix-stable while tool visibility and definitions are unchanged. #### What the model sees -Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Every complete result is capped by `maxResultBytes`, including generic task status text. Results remain in session history until compaction; incremental task reads do not repeat consumed output. +Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Every complete result is capped by `maxResultBytes`, including normalized error text and generic task status text. Results remain in session history until compaction; incremental task reads do not repeat consumed output. #### Token effect diff --git a/packages/pty/tool-pty/src/index.ts b/packages/pty/tool-pty/src/index.ts index edb8102a79..5e75c97bec 100644 --- a/packages/pty/tool-pty/src/index.ts +++ b/packages/pty/tool-pty/src/index.ts @@ -28,6 +28,17 @@ export const inject = ['pty', 'tools', 'systemPrompt'] /** Default cap for one complete model-facing terminal result. */ export const DEFAULT_MAX_RESULT_BYTES = 256 * 1024 +/** Smallest cap that preserves every counter-backed PTY and task id in its creation acknowledgement. */ +export const MIN_MAX_RESULT_BYTES = 64 + +const TOOL_NAMES = new Set([ + 'terminal_open', + 'terminal_send', + 'terminal_read', + 'terminal_signal', + 'terminal_close', + 'terminal_list', +]) /** Model-facing terminal tool configuration. */ export interface Config { @@ -40,7 +51,7 @@ export interface Config { /** Schemastery configuration for the terminal tool consumer. */ export const Config: z = z.object({ enableRunInBackground: z.boolean().default(true), - maxResultBytes: z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_MAX_RESULT_BYTES), + maxResultBytes: z.number().step(1).min(MIN_MAX_RESULT_BYTES).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_MAX_RESULT_BYTES), }) interface SpawnArgs { @@ -100,9 +111,15 @@ function sendDetail(result: PtySendResult): string { export function apply(ctx: Context, config: Config = {}): void { const enableRunInBackground = config.enableRunInBackground ?? true const maxResultBytes = config.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES - if (!Number.isSafeInteger(maxResultBytes) || maxResultBytes <= 0) { - throw new Error('tool-pty: maxResultBytes must be a positive safe integer') + if (!Number.isSafeInteger(maxResultBytes) || maxResultBytes < MIN_MAX_RESULT_BYTES) { + throw new Error(`tool-pty: maxResultBytes must be a safe integer of at least ${MIN_MAX_RESULT_BYTES}`) } + ctx.on('tools/execute', async (exec, next): Promise => { + const result = await next() + if (!TOOL_NAMES.has(exec.name)) return result + const raw = rawResultText(result) + return raw === undefined ? result : { ...result, content: textResult(raw, maxResultBytes) } + }) ctx.systemPrompt.section({ name: 'tool:pty', order: 106, diff --git a/packages/pty/tool-pty/tests/tools.spec.ts b/packages/pty/tool-pty/tests/tools.spec.ts index d6023a4d17..0466b02134 100644 --- a/packages/pty/tool-pty/tests/tools.spec.ts +++ b/packages/pty/tool-pty/tests/tools.spec.ts @@ -197,6 +197,32 @@ describe('tool-pty foreground surface', () => { const invalid = await setupBase(false) expect(() => { ToolPty.apply(invalid.ctx, { maxResultBytes: 0 }) }).toThrow('maxResultBytes') + expect(() => { ToolPty.apply(invalid.ctx, { maxResultBytes: 63 }) }).toThrow('at least 64') + }) + + it('bounds normalized errors and preserves allocated ids at the minimum result cap', async () => { + const { ctx, agent } = await setup(true, { maxResultBytes: 64 }) + const failed = await call(ctx, 'terminal_open', { type: 'x'.repeat(1_000) }, agent) + expect(failed.isError).toBe(true) + expect(Buffer.byteLength(text(failed))).toBeLessThanOrEqual(64) + expect(text(failed)).toContain('[output truncated]') + + const opened = await call(ctx, 'terminal_open', { type: 'stub', name: 'n'.repeat(1_000) }, agent) + expect(text(opened)).toContain('pty-1') + expect(Buffer.byteLength(text(opened))).toBeLessThanOrEqual(64) + const background = await call(ctx, 'terminal_send', { + sessionId: 'pty-1', text: 'work', run_in_background: true, + }, agent) + expect(text(background)).toContain('pty-send-1') + expect(Buffer.byteLength(text(background))).toBeLessThanOrEqual(64) + }) + + it('leaves a structured around-dispatch replacement unchanged', async () => { + const { ctx, agent } = await setup(false, { maxResultBytes: 64 }) + ctx.on('tools/execute', async (exec, next) => exec.name === 'terminal_list' + ? { content: [], isError: false } + : next()) + expect((await call(ctx, 'terminal_list', {}, agent)).content).toEqual([]) }) }) From b59f6ff3fa68040dd36cdc8cfc600ed5602af87d Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:48:50 +0800 Subject: [PATCH 118/368] docs: link the WeChat community QR destination --- README.i18n.yaml | 2 +- README.zh.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.i18n.yaml b/README.i18n.yaml index f7dca486db..21853871d3 100644 --- a/README.i18n.yaml +++ b/README.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write README.md: 366bea0b6d68b7eca9f53581d3bb727574adb5ef -README.zh.md: 0508b2c4a7a580f137315740135bf36154c6513b +README.zh.md: d5a631843dafaf9ff608f639cd8fc4c7d2c4d546 diff --git a/README.zh.md b/README.zh.md index 0508b2c4a7..d5a631843d 100644 --- a/README.zh.md +++ b/README.zh.md @@ -55,7 +55,7 @@ dsh -p "summarize this workspace" ## 社区 -扫描二维码加入 DeepSeek Harness 微信社区。 +扫描二维码,或打开 DeepSeek Harness 微信社区申请页面 申请加入。

    DeepSeek Harness 微信社区二维码 From a60258b4855f93020d1aeaad804e0f707f8eb6de Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:54:01 +0800 Subject: [PATCH 119/368] test(web): gate built snapshot on lib mode --- vitest.snapshot.config.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vitest.snapshot.config.ts b/vitest.snapshot.config.ts index 858a3fd9a1..6fad120e06 100644 --- a/vitest.snapshot.config.ts +++ b/vitest.snapshot.config.ts @@ -41,7 +41,9 @@ export default defineConfig({ test: { setupFiles: ['./scripts/test-invariants.ts'], include: [ - 'apps/web/tests/**/*.snapshot.ts', + // The assembled Web snapshot executes generated client bundles; source + // mode remains the zero-build path, while lib mode requires a prior build. + ...(process.env.DSH_EXAMPLE_MODE === 'lib' ? ['apps/web/tests/**/*.snapshot.ts'] : []), 'examples/*/tests/**/*.snapshot.ts', 'packages/sdk/*/tests/**/*.snapshot.ts', 'packages/ui/tui/tests/**/*.snapshot.ts', From 7f0f70ce3ce9bde7d35d50d57c2399a443aaa96b Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:59:16 +0800 Subject: [PATCH 120/368] fix(pty): retain backend cleanup failures --- ...26-07-16-persistent-pty-sessions.i18n.yaml | 4 +- .../2026-07-16-persistent-pty-sessions.md | 2 +- .../2026-07-16-persistent-pty-sessions.zh.md | 2 +- docs/cordis-catalog/services.md | 2 +- docs/core-data-structures/pty.md | 4 +- packages/pty/pty-local/README.md | 2 +- packages/pty/pty-local/src/index.ts | 3 +- packages/pty/pty-local/tests/index.spec.ts | 14 ++++-- packages/pty/pty/README.md | 4 +- packages/pty/pty/src/index.ts | 23 +++++---- packages/pty/pty/src/types.ts | 17 ++++++- packages/pty/pty/tests/service.spec.ts | 48 ++++++++++++++++++- 12 files changed, 100 insertions(+), 25 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index 86c05cb07c..426b1180b0 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml @@ -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 -2026-07-16-persistent-pty-sessions.md: 689019d56d719884761407f288e1e765dd19c35d -2026-07-16-persistent-pty-sessions.zh.md: 14490137a003e2ca67b594628e506f0b74e3d4b7 +2026-07-16-persistent-pty-sessions.md: ba8d8579c107f89f83b2a9ab40298ac876df4521 +2026-07-16-persistent-pty-sessions.zh.md: 44e66094b905560e0cd5f3c30204e46e93351791 diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index 689019d56d..ba8d8579c1 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -34,7 +34,7 @@ Idle detection is backend behavior, not a second public seam. A remote or contai There are no plugin-load auto-start sessions. `terminal_open` creates a session only during an agent tool call, when ownership and the owning event-sourced session are known. A future declarative startup feature must compose through unpublished agent setup rather than create shared global terminals. -Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Unpublished backend setup is a tracked lifecycle operation: owner or service disposal aborts its service-owned signal, waits for backend settlement and rollback, and only then returns. Caller cancellation retains its exact `AbortSignal.reason` even when the backend rejects in response; a rollback close failure rejects both the spawn and the disposing lifecycle. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. +Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Unpublished backend setup is a tracked lifecycle operation: owner or service disposal aborts its service-owned signal, waits for backend settlement and rollback, and only then returns. Caller cancellation retains its exact `AbortSignal.reason` even when the backend rejects in response; a service rollback close failure rejects both the spawn and the disposing lifecycle, while `PtyBackendCleanupError` lets a backend preserve its own failed startup cleanup for the disposing lifecycle without replacing that caller reason. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. ### Security and process boundary diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index 14490137a0..44e66094b9 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -34,7 +34,7 @@ idle 检测属于后端行为,不是第二条公共 seam。远程或容器后 实现不提供插件加载期 auto-start 会话。`terminal_open` 只在 agent 工具调用期间创建会话,此时所有权和所属的事件溯源会话都已确定。未来的声明式启动功能必须通过尚未发布的 agent setup 组合,而不能创建全局共享终端。 -agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。未发布的后端 setup 同样是受追踪的生命周期操作:owner 或服务 dispose 会中止服务自有的 signal,等待后端结算与回滚完成后才返回。即使后端响应取消而 reject,调用方取消仍原样保留其 `AbortSignal.reason`;若回滚 close 失败,spawn 与正在执行的 lifecycle dispose 都会 reject。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 +agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。未发布的后端 setup 同样是受追踪的生命周期操作:owner 或服务 dispose 会中止服务自有的 signal,等待后端结算与回滚完成后才返回。即使后端响应取消而 reject,调用方取消仍原样保留其 `AbortSignal.reason`;服务侧回滚 close 失败会使 spawn 与正在执行的 lifecycle dispose 都 reject,而 `PtyBackendCleanupError` 让后端在不替换该调用方原因的前提下,为正在执行的 dispose 保留自身的启动清理失败。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 ### 安全与进程边界 diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 1f2cf86408..db41e4e868 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -841,7 +841,7 @@ list(owner: Agent): PtySessionSnapshot[] Types: [Agent](../core-data-structures/core.md) · [PtyBackend](../core-data-structures/pty.md) · [PtyReadRequest](../core-data-structures/pty.md) · [PtyReadResult](../core-data-structures/pty.md) · [PtySendOperation](../core-data-structures/pty.md) · [PtySendRequest](../core-data-structures/pty.md) · [PtySessionId](../core-data-structures/pty.md) · [PtySessionSnapshot](../core-data-structures/pty.md) · [PtySignal](../core-data-structures/pty.md) · [PtySignalResult](../core-data-structures/pty.md) · [PtySpawnRequest](../core-data-structures/pty.md) · [PtySpawnResult](../core-data-structures/pty.md) -Source: [`packages/pty/pty/src/index.ts:102`](../../packages/pty/pty/src/index.ts) +Source: [`packages/pty/pty/src/index.ts:104`](../../packages/pty/pty/src/index.ts) ## `ctx.sandbox` — `SandboxProvider` (abstract seam) diff --git a/docs/core-data-structures/pty.md b/docs/core-data-structures/pty.md index c8dfa49460..b205ec64c9 100644 --- a/docs/core-data-structures/pty.md +++ b/docs/core-data-structures/pty.md @@ -22,14 +22,14 @@ type PtySessionStatus = ## Backend and live session -A backend owns how one registered type starts and detects readiness. `PtyService` publishes the returned session only after setup succeeds, then owns id authorization and cleanup. A backend session owns terminal state and captured-resource quiescence. +A backend owns how one registered type starts and detects readiness. `PtyService` publishes the returned session only after setup succeeds, then owns id authorization and cleanup. A backend that cannot clean partial startup resources rejects with `PtyBackendCleanupError`, allowing disposal to retain the cleanup failure without replacing the caller's cancellation reason. A backend session owns terminal state and captured-resource quiescence. ```ts type-equiv /** Replaceable provider for one PTY session type. */ interface PtyBackend { /** Stable type selected by {@link PtySpawnRequest.type}. */ readonly type: string - /** Create an unpublished session or reject after cleaning partial resources. */ + /** Create an unpublished session or reject after cleaning partial resources; cleanup failure uses {@link PtyBackendCleanupError}. */ spawn(spec: PtyBackendSpawnSpec): Promise } ``` diff --git a/packages/pty/pty-local/README.md b/packages/pty/pty-local/README.md index dd83b61c07..2167f91f85 100644 --- a/packages/pty/pty-local/README.md +++ b/packages/pty/pty-local/README.md @@ -6,7 +6,7 @@ Local `node-pty` backend for `ctx.pty`. It starts an interactive shell under the The plugin injects `pty`, `sandbox`, and `sandboxPolicy`, then registers the configured backend type (`shell`). `danger-full-access` starts the shell directly; confined modes wrap the exact shell argv through `ctx.sandbox`. The effective session mode is resolved at spawn. A change to a different effective mode is rejected before its `sandbox/mode` event commits while that owner has an open PTY or a spawn in progress; the fence is attached to the exact owner and therefore outlives a local-provider reload that retains existing sessions. Wait for creation to settle and close the sessions before changing modes, so a terminal opened with wider access cannot survive a downgrade. -Linux readiness combines a foreground-verified private bash prompt marker, foreground-process-group syscall inspection, silence fallback, and absolute timeout. macOS uses the verified prompt marker plus silence/timeout because it has no `/proc` syscall surface. A marker is not ready until printable prompt text arrives, including when the OSC marker and `PS1` are split across data callbacks. Unrecognized or unreadable process state is never a positive exact-idle signal. During unpublished startup, a fallback requires observed output; zero-output silence cannot publish an empty session, and timeout rejects the spawn. Cancellation closes the unpublished shell and rejects with the caller's exact abort reason even when its foreground process group is not observable yet. Incomplete terminal-control sequences are bounded by `maxReadBytes` and discarded through their terminator after crossing that limit; a trailing carriage return is carried across callbacks so split CRLF becomes one newline. +Linux readiness combines a foreground-verified private bash prompt marker, foreground-process-group syscall inspection, silence fallback, and absolute timeout. macOS uses the verified prompt marker plus silence/timeout because it has no `/proc` syscall surface. A marker is not ready until printable prompt text arrives, including when the OSC marker and `PS1` are split across data callbacks. Unrecognized or unreadable process state is never a positive exact-idle signal. During unpublished startup, a fallback requires observed output; zero-output silence cannot publish an empty session, and timeout rejects the spawn. Cancellation closes the unpublished shell and rejects with the caller's exact abort reason even when its foreground process group is not observable yet; if that close fails, `PtyBackendCleanupError` separately preserves the cleanup failure for registry disposal. Incomplete terminal-control sequences are bounded by `maxReadBytes` and discarded through their terminator after crossing that limit; a trailing carriage return is carried across callbacks so split CRLF becomes one newline. Send cancellation resolves the current foreground process group and delivers a real `SIGINT`; it never emulates interruption by writing `\x03`, so raw-mode programs remain cancellable. Close sends `SIGTERM` to descendants, waits, then sends `SIGKILL` to the union of captured survivors and newly scanned descendants so reparenting cannot hide a process from teardown. It verifies that every retained identity is gone or, on Linux, a non-executing zombie before stopping the shell; zombie entries are quiescent and are reaped as the shell exits. A survivor failure does not cache a permanently rejected close; a later close retries the teardown. diff --git a/packages/pty/pty-local/src/index.ts b/packages/pty/pty-local/src/index.ts index db4de5de28..b466ecfc46 100644 --- a/packages/pty/pty-local/src/index.ts +++ b/packages/pty/pty-local/src/index.ts @@ -9,6 +9,7 @@ import * as nodePty from 'node-pty' import type { IPtyForkOptions } from 'node-pty' import type { Agent } from '@deepseek-ai/dsh-agent' import type { Session, SessionEvent } from '@deepseek-ai/dsh-session' +import { PtyBackendCleanupError } from '@deepseek-ai/dsh-pty' import type { PtyBackend, PtyBackendSpawnSpec } from '@deepseek-ai/dsh-pty' import type { SandboxMode } from '@deepseek-ai/dsh-sandbox' import { effectiveSandboxMode } from '@deepseek-ai/dsh-sandbox-policy' @@ -123,7 +124,7 @@ export class LocalPtyBackend implements PtyBackend { try { await session.close('PTY startup failed') } catch (closeError: unknown) { - throw new AggregateError([error, closeError], 'PTY startup and cleanup both failed') + throw new PtyBackendCleanupError(error, closeError) } throw error } diff --git a/packages/pty/pty-local/tests/index.spec.ts b/packages/pty/pty-local/tests/index.spec.ts index 9c28484adf..31a8d99184 100644 --- a/packages/pty/pty-local/tests/index.spec.ts +++ b/packages/pty/pty-local/tests/index.spec.ts @@ -8,7 +8,7 @@ import type { Agent } from '@deepseek-ai/dsh-agent' import SandboxProvider from '@deepseek-ai/dsh-sandbox' import type { ConfinedArgv, SandboxPolicy } from '@deepseek-ai/dsh-sandbox' import SandboxPolicyService, { setSandboxMode } from '@deepseek-ai/dsh-sandbox-policy' -import PtyService, { PtySessionId } from '@deepseek-ai/dsh-pty' +import PtyService, { PtyBackendCleanupError, PtySessionId } from '@deepseek-ai/dsh-pty' import { LocalPtyBackend } from '@deepseek-ai/dsh-pty-local' import * as ptyLocal from '@deepseek-ai/dsh-pty-local' import type { ResolvedConfig } from '@deepseek-ai/dsh-pty-local/src/config.ts' @@ -112,12 +112,18 @@ describe('LocalPtyBackend startup rollback', () => { await expect(backend.spawn(spec(agent(ctx)))).rejects.toThrow('startup failed') expect(closed).toHaveBeenCalledWith('PTY startup failed') + const startupFailure = new Error('startup failed') + const cleanupFailure = new Error('cleanup failed') const doublyFailed = { - initialize: () => Promise.reject(new Error('startup failed')), - close: () => Promise.reject(new Error('cleanup failed')), + initialize: () => Promise.reject(startupFailure), + close: () => Promise.reject(cleanupFailure), } as unknown as LocalPtySession const aggregate = new LocalPtyBackend(ctx, config(), inspector, spawnTerminal, () => doublyFailed) - await expect(aggregate.spawn(spec(agent(ctx)))).rejects.toThrow('startup and cleanup both failed') + await expect(aggregate.spawn(spec(agent(ctx)))).rejects.toEqual(expect.objectContaining({ + name: 'PtyBackendCleanupError', + spawnError: startupFailure, + cleanupError: cleanupFailure, + } satisfies Partial)) }) it('wraps confined argv, scrubs the environment, and returns initialized sessions', async () => { diff --git a/packages/pty/pty/README.md b/packages/pty/pty/README.md index 2dff1cbca6..af1c3a9d42 100644 --- a/packages/pty/pty/README.md +++ b/packages/pty/pty/README.md @@ -4,10 +4,10 @@ Owner-scoped persistent PTY seam. `PtyService` registers as `ctx.pty`, mints opa ## Contract -- Backends register one stable `type` and return an unpublished `PtyBackendSession`; failed or cancelled setup must clean partial resources. +- Backends register one stable `type` and return an unpublished `PtyBackendSession`; failed or cancelled setup must clean partial resources, and a failed cleanup rejects with `PtyBackendCleanupError` so the registry can retain it across cancellation. - Spawn cancellation preserves the caller's exact abort reason. Service disposal and owner loss remain distinct machine-routable failures after backend setup. - Owner and service disposal abort unpublished setup through a service-owned signal and await backend settlement plus rollback before returning. -- A rollback close failure rejects both the spawn and the disposing lifecycle instead of claiming quiescence. +- A service rollback or backend-reported startup cleanup failure rejects the disposing lifecycle instead of claiming quiescence; the spawn caller still receives its exact cancellation reason. - `hasOwnerActivity(owner)` spans unpublished setup through final close, so lifecycle policy can fence the exact owner without a publication race. - A successful spawn publishes one `PtySessionId`. The optional `name` is owner-local display metadata, never authority. - One session accepts at most one live send operation. Reads and signals may observe it; another send fails until the operation settles. diff --git a/packages/pty/pty/src/index.ts b/packages/pty/pty/src/index.ts index d5b4d84e1f..f80089c90b 100644 --- a/packages/pty/pty/src/index.ts +++ b/packages/pty/pty/src/index.ts @@ -6,6 +6,7 @@ import { Context, Service } from 'cordis' import type { Agent } from '@deepseek-ai/dsh-agent' +import { PtyBackendCleanupError } from './types.ts' import type { PtyBackend, PtyBackendSession, @@ -39,6 +40,7 @@ export type { PtySpawnResult, PtyWaitReason, } from './types.ts' +export { PtyBackendCleanupError } from './types.ts' /** Opaque identity minted by {@link PtyService} for one live PTY session. */ export type PtySessionId = PtySessionIdValue @@ -90,12 +92,12 @@ interface SessionRecord { interface PendingSpawn { readonly controller: AbortController readonly settled: Promise - rollbackFailure: { error: unknown } | undefined + cleanupFailure: { error: unknown } | undefined } interface SpawnReservation { readonly signal: AbortSignal - release(rollbackFailure: { error: unknown } | undefined): void + release(cleanupFailure: { error: unknown } | undefined): void } /** In-process registry for replaceable PTY backends and exact-Agent sessions. */ @@ -162,7 +164,7 @@ export class PtyService extends Service { : AbortSignal.any([signal, spawnReservation.signal]) const sessionId = PtySessionId(`pty-${++this.nextId}`) let session: PtyBackendSession | undefined - let rollbackFailure: { error: unknown } | undefined + let cleanupFailure: { error: unknown } | undefined try { session = await backend.spawn({ sessionId, @@ -191,11 +193,16 @@ export class PtyService extends Service { this.sessions.set(sessionId, record) return this.snapshot(record, session.motd) } catch (error) { + if (error instanceof PtyBackendCleanupError) { + cleanupFailure = { error: error.cleanupError } + } + let rollbackFailure: { error: unknown } | undefined if (session !== undefined && !this.sessions.has(sessionId)) { try { await session.close('PTY spawn rolled back') } catch (closeError: unknown) { rollbackFailure = { error: closeError } + cleanupFailure = rollbackFailure } } let failure: unknown = error @@ -210,7 +217,7 @@ export class PtyService extends Service { } throw failure } finally { - spawnReservation.release(rollbackFailure) + spawnReservation.release(cleanupFailure) releaseName() } } @@ -342,14 +349,14 @@ export class PtyService extends Service { private reserveSpawn(owner: Agent): SpawnReservation { const controller = new AbortController() const settlement = Promise.withResolvers() - const pending: PendingSpawn = { controller, settled: settlement.promise, rollbackFailure: undefined } + const pending: PendingSpawn = { controller, settled: settlement.promise, cleanupFailure: undefined } const owned = this.pendingSpawns.get(owner) ?? new Set() owned.add(pending) this.pendingSpawns.set(owner, owned) return { signal: controller.signal, - release: (rollbackFailure) => { - pending.rollbackFailure = rollbackFailure + release: (cleanupFailure) => { + pending.cleanupFailure = cleanupFailure owned.delete(pending) if (owned.size === 0) this.pendingSpawns.delete(owner) settlement.resolve() @@ -363,7 +370,7 @@ export class PtyService extends Service { : [...(this.pendingSpawns.get(owner) ?? [])] for (const spawn of pending) spawn.controller.abort(reason) await Promise.all(pending.map(spawn => spawn.settled)) - const failures = pending.flatMap(spawn => spawn.rollbackFailure === undefined ? [] : [spawn.rollbackFailure.error]) + const failures = pending.flatMap(spawn => spawn.cleanupFailure === undefined ? [] : [spawn.cleanupFailure.error]) if (failures.length > 0) { throw new AggregateError(failures, 'failed to roll back unpublished PTY setup') } diff --git a/packages/pty/pty/src/types.ts b/packages/pty/pty/src/types.ts index 7bb3f2c711..a4985ead93 100644 --- a/packages/pty/pty/src/types.ts +++ b/packages/pty/pty/src/types.ts @@ -10,6 +10,21 @@ import type { Agent } from '@deepseek-ai/dsh-agent' /** Internal exported basis for the public `PtySessionId` type/value pair. */ export type PtySessionIdValue = Branded<'PtySessionId'> +/** + * Backend-reported failure to clean partial resources after unpublished setup failed. + * @param spawnError - original setup or cancellation failure. + * @param cleanupError - failure that may leave backend-owned resources alive. + */ +export class PtyBackendCleanupError extends AggregateError { + constructor( + readonly spawnError: unknown, + readonly cleanupError: unknown, + ) { + super([spawnError, cleanupError], 'PTY backend startup and cleanup both failed') + this.name = 'PtyBackendCleanupError' + } +} + /** Why one interactive send returned control to its caller. */ export type PtyWaitReason = 'stdin_read' | 'inferred_idle' | 'timeout' | 'session_exit' @@ -147,7 +162,7 @@ export interface PtyBackendSession { export interface PtyBackend { /** Stable type selected by {@link PtySpawnRequest.type}. */ readonly type: string - /** Create an unpublished session or reject after cleaning partial resources. */ + /** Create an unpublished session or reject after cleaning partial resources; cleanup failure uses {@link PtyBackendCleanupError}. */ spawn(spec: PtyBackendSpawnSpec): Promise } diff --git a/packages/pty/pty/tests/service.spec.ts b/packages/pty/pty/tests/service.spec.ts index 49162abe5c..1d9d1a1f94 100644 --- a/packages/pty/pty/tests/service.spec.ts +++ b/packages/pty/pty/tests/service.spec.ts @@ -3,7 +3,7 @@ import { Context } from 'cordis' import { Session, SessionId } from '@deepseek-ai/dsh-session' import AgentRegistry from '@deepseek-ai/dsh-agent' import type { Agent } from '@deepseek-ai/dsh-agent' -import PtyService, { PtyError, PtySessionId } from '@deepseek-ai/dsh-pty' +import PtyService, { PtyBackendCleanupError, PtyError, PtySessionId } from '@deepseek-ai/dsh-pty' import type { PtyBackend, PtyBackendSession, @@ -319,6 +319,52 @@ describe('PtyService ownership and lifecycle', () => { expect(session.closed).toEqual(['PTY spawn rolled back']) }) + it.each([ + { scope: 'owner', code: 'OWNER_NOT_LIVE' }, + { scope: 'service', code: 'SERVICE_DISPOSING' }, + ] as const)('$scope disposal retains backend-side startup cleanup failure', async ({ scope, code }) => { + const ctx = await harness() + const started = Promise.withResolvers() + const cleanupFailure = new Error('backend cleanup failed') + let backendAbortReason: unknown + ctx.pty.registerBackend({ + type: 'cleanup-failing', + spawn: ({ signal }) => new Promise((_resolve, reject) => { + if (signal === undefined) throw new Error('missing spawn signal') + started.resolve(undefined) + signal.addEventListener('abort', () => { + backendAbortReason = signal.reason + reject(new PtyBackendCleanupError(signal.reason, cleanupFailure)) + }, { once: true }) + }), + }) + const owner = stubAgent(ctx, 'owner') + ctx.agents.register(owner) + + const pending = ctx.pty.spawn(owner, { type: 'cleanup-failing' }) + await started.promise + const internal = ctx.pty as unknown as { + disposeOwned(owner: Agent): Promise + disposeAll(): Promise + } + const disposal = scope === 'owner' ? internal.disposeOwned(owner) : internal.disposeAll() + const pendingError = await pending.then( + () => { throw new Error('pending spawn unexpectedly succeeded') }, + (error: unknown) => error, + ) + + expect(pendingError).toBe(backendAbortReason) + expect(pendingError).toMatchObject({ code }) + const disposalError = await disposal.then( + () => { throw new Error('disposal unexpectedly succeeded') }, + (error: unknown) => error, + ) + expect(disposalError).toMatchObject({ message: 'failed to clean up PTY lifecycle' }) + const rollbackError = (disposalError as AggregateError).errors[0] as unknown + const cleanupErrors = (rollbackError as AggregateError).errors as unknown[] + expect(cleanupErrors).toEqual([cleanupFailure]) + }) + it('keeps independent reservations and handles provider failure before publication', async () => { const ctx = await harness() const firstGate = Promise.withResolvers() From e20dea16292b92545e5941993f6c74efd855fc4b Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:05:41 +0800 Subject: [PATCH 121/368] fix(schema): align projected and enforced declarations --- ...20-unified-json-value-schema-dsl.i18n.yaml | 4 +- ...026-07-20-unified-json-value-schema-dsl.md | 5 +- ...-07-20-unified-json-value-schema-dsl.zh.md | 5 +- docs/core-data-structures/tools.md | 27 ++-- packages/cordis/tool-cordis/src/guard.ts | 13 +- .../cordis/tool-cordis/tests/mount.spec.ts | 3 + packages/core/session/src/json.ts | 13 +- packages/core/session/tests/json.spec.ts | 19 +++ packages/core/tools/README.md | 2 +- packages/core/tools/src/json-schema.ts | 134 ++++++++++++++---- packages/core/tools/src/schema.ts | 89 +++++++----- packages/core/tools/tests/json-schema.spec.ts | 77 ++++++++++ packages/core/tools/tests/schema.spec.ts | 40 +++++- 13 files changed, 336 insertions(+), 95 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml index 2f7a4b1adb..a5273c9e3d 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml @@ -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 -2026-07-20-unified-json-value-schema-dsl.md: e735472ee0ac6a696462aa7598d57fce04aa9c3e -2026-07-20-unified-json-value-schema-dsl.zh.md: dd34817a6d047b14346b35ba6c4bce0290ad7feb +2026-07-20-unified-json-value-schema-dsl.md: 3e35bce6eb48afeb31c564e9b5d7b84ff91a7b1f +2026-07-20-unified-json-value-schema-dsl.zh.md: 77a20d17aab61e759de6e490510b14b5bc408726 diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md index e735472ee0..3e35bce6eb 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md @@ -12,7 +12,9 @@ Tool parameters used a small author DSL while subagent/workflow structured outpu `dsh-tools` owns one JSON-value schema vocabulary with two representations. `ValueSchemaSpec` is the author form for any JSON root; `ParameterSchemaSpec` is its implicit object-property-map form with per-property `required: true`. `JsonSchemaNode` is the raw wire form. Both support string, finite number, integer, boolean, null, array, object, type-correct scalar `enum`/`const`, and exact-one `oneOf`; `{ type: 'json' }` is author-only sugar for an annotation-only unconstrained raw node. -An explicit author object must declare `additionalProperties: true | false`. The implicit parameter root and raw JSON Schema preserve the standard open default. `InferValue` and `InferArgs

    ` derive TypeScript values from the same declarations that `valueSchemaSpecToJsonSchema()` and `parameterSchemaSpecToJsonSchema()` compile. `assertSupportedJsonSchema()` rejects unsupported or misplaced keywords, and `validateJsonSchemaValue()` enforces the accepted subset against the lossless `JsonValue` boundary: no `undefined`, negative zero, non-finite numbers, sparse arrays, cycles, exotic objects, functions, symbols, or other coercive values. Intrinsic plain Object and Array containers remain plain across JavaScript realms; subclasses remain exotic. Author compilation, raw-schema assertion, value validation, schema-to-TypeScript rendering, registry detachment, and dynamic Cordis cross-realm normalization and cloning use explicit work stacks, so valid nesting is limited by available memory rather than the JavaScript call stack. +An explicit author object must declare `additionalProperties: true | false`. The implicit parameter root and raw JSON Schema preserve the standard open default. Schema records contain only own enumerable string keys, schema arrays are dense intrinsic arrays, and supported keywords are read as own properties; custom prototypes, inherited constraints, symbols, and JSON-invisible decorations therefore cannot make compilation, projection, and validation observe different declarations. Intrinsic plain Object and Array containers remain plain across JavaScript realms, while subclasses and forged constructor prototypes remain exotic. + +`InferValue` and `InferArgs

    ` derive TypeScript values from the same declarations that `valueSchemaSpecToJsonSchema()` and `parameterSchemaSpecToJsonSchema()` compile. Exact inference is bounded to 16 container levels and then uses `JsonValue`, preventing TypeScript's type-instantiation stack from becoming the authoring limit. `assertSupportedJsonSchema()` rejects unsupported or misplaced keywords, and `validateJsonSchemaValue()` enforces the accepted subset against the lossless `JsonValue` boundary: no `undefined`, negative zero, non-finite numbers, sparse arrays, cycles, exotic objects, functions, symbols, or other coercive values. Author compilation, raw-schema assertion, value validation, schema-to-TypeScript rendering, registry detachment, and dynamic Cordis cross-realm normalization and cloning use explicit work stacks, so runtime nesting is limited by available memory rather than the JavaScript call stack. Object-rooting is a consumer rule rather than a vocabulary restriction. Subagent and workflow caller-defined structured outputs use `assertObjectJsonSchema()` and `ObjectJsonSchema`; tool outputs may use any root. Dynamic Cordis registrations rebuild realm-foreign schemas into host-owned JSON, preserve raw-wrapper openness, and require direct-DSL object openness before calling the same compiler. @@ -28,5 +30,6 @@ Object-rooting is a consumer rule rather than a vocabulary restriction. Subagent - Parameter validation, output validation, schema-to-TypeScript generation, subagent/workflow guards, and dynamic registration share one enforced vocabulary. - Output declarations can infer object, array, scalar, or null roots; subagent/workflow structured outputs remain object-rooted at their existing seams. - Explicit object openness and type-correct literal constraints make malformed declarations fail during authoring or registration rather than during a later model call. +- Bounded type inference retains useful exact types for ordinary declarations and degrades unusually deep tails to `JsonValue`; runtime schema enforcement remains exact at every depth. - Raw tools may still register broader JSON Schema directly, but unified code generation treats unsupported schemas as unknown instead of pretending to enforce them. - Runtime and compile-time tests cover every root, exact-one overlap/no-match behavior, raw open defaults, explicit openness, lossy JSON values, inference, and deep nesting across core and dynamic projections. diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md index dd34817a6d..77a20d17aa 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md @@ -12,7 +12,9 @@ Status: implemented `dsh-tools` 以两种表示形式统一管理一套 JSON 值 schema 词汇。`ValueSchemaSpec` 是可描述任意 JSON 根类型的作者侧形式;`ParameterSchemaSpec` 是其隐式对象属性映射形式,每个属性可标记 `required: true`。`JsonSchemaNode` 是原始协议表示。两种形式都支持字符串、有限数值、整数、布尔值、null、数组、对象、类型正确的标量 `enum`/`const`,以及要求恰好匹配一个分支的 `oneOf`;`{ type: 'json' }` 仅是作者侧语法糖,会编译为仅含注解、不施加约束的原始节点。 -显式的作者侧对象必须声明 `additionalProperties: true | false`。隐式参数根对象和原始 JSON Schema 保留标准的默认开放语义。`InferValue` 和 `InferArgs

    ` 根据同一份声明推导 TypeScript 值,`valueSchemaSpecToJsonSchema()` 和 `parameterSchemaSpecToJsonSchema()` 也将这些声明编译为 JSON Schema。`assertSupportedJsonSchema()` 会拒绝不受支持或位置错误的关键字;`validateJsonSchemaValue()` 则以无损 `JsonValue` 边界校验受支持的子集,不允许 `undefined`、负零、非有限数、稀疏数组、循环引用、非普通对象、函数、symbol 及其他需要强制转换的值。内建的普通 Object 和 Array 容器跨 JavaScript 运行域后仍视为普通容器;其子类仍视为非普通对象。作者侧 schema 编译、原始 schema 断言、值校验、schema 到 TypeScript 的渲染、注册表数据分离,以及动态 Cordis 的跨运行域规范化与克隆均使用显式工作栈,因此合法嵌套的深度上限由可用内存决定,而非 JavaScript 调用栈。 +显式的作者侧对象必须声明 `additionalProperties: true | false`。隐式参数根对象和原始 JSON Schema 保留标准的默认开放语义。schema 记录只能包含自有且可枚举的字符串键,schema 数组必须是稠密的内建数组,系统只从自有属性读取受支持的关键字;因此,自定义原型、继承的约束、symbol 和 JSON 不可见的附加内容都无法让编译、投影和校验观察到不同的声明。内建的普通 Object 和 Array 容器跨 JavaScript 运行域后仍视为普通容器,而子类和伪造构造函数的原型仍视为非普通对象。 + +`InferValue` 和 `InferArgs

    ` 根据同一份声明推导 TypeScript 值,`valueSchemaSpecToJsonSchema()` 和 `parameterSchemaSpecToJsonSchema()` 也将这些声明编译为 JSON Schema。精确类型推导以 16 层容器为界,超过后使用 `JsonValue`,从而避免 TypeScript 的类型实例化栈限制作者能声明的嵌套深度。`assertSupportedJsonSchema()` 会拒绝不受支持或位置错误的关键字;`validateJsonSchemaValue()` 则以无损 `JsonValue` 边界校验受支持的子集,不允许 `undefined`、负零、非有限数、稀疏数组、循环引用、非普通对象、函数、symbol 及其他需要强制转换的值。作者侧 schema 编译、原始 schema 断言、值校验、schema 到 TypeScript 的渲染、注册表数据分离,以及动态 Cordis 的跨运行域规范化与克隆均使用显式工作栈,因此运行时嵌套只受可用内存限制,不受 JavaScript 调用栈限制。 对象根限制属于消费方规则,不属于 schema 词汇本身。subagent 和工作流中由调用方定义的结构化输出通过 `assertObjectJsonSchema()` 和 `ObjectJsonSchema` 保持对象根限制;工具输出可以使用任意根类型。动态 Cordis 注册会把跨 JavaScript 运行域传入的 schema 重建为当前运行时持有的 JSON,保留原始包装层的默认开放语义,并要求直接使用 DSL 声明的对象明确选择开放方式,然后再调用同一编译器。 @@ -28,5 +30,6 @@ Status: implemented - 参数校验、输出校验、schema 到 TypeScript 的代码生成、subagent/工作流门禁和动态注册共用一套强制执行的词汇。 - 输出声明可以推导对象、数组、标量或 null 根类型;subagent/工作流的结构化输出仍在其现有服务边界保持对象根限制。 - 显式的对象开放方式和类型正确的字面量约束会让格式错误的声明在编写或注册阶段快速失败,而不是拖到后续模型调用时才失败。 +- 有界类型推导会为常规声明保留有用的精确类型,并将异常深的尾部结构退化为 `JsonValue`;运行时 schema 强制执行在任意深度仍保持精确。 - 原始工具仍可直接注册范围更广的 JSON Schema,但统一代码生成会把不受支持的 schema 视为未知类型,不会假装自己能够强制执行。 - 运行时和编译期测试覆盖所有根类型、恰好匹配一个分支时的重叠/无匹配行为、原始 schema 的默认开放语义、显式开放方式、有损 JSON 值、类型推导,以及核心投影和动态投影中的深层嵌套。 diff --git a/docs/core-data-structures/tools.md b/docs/core-data-structures/tools.md index bccb6027f4..cff9b85881 100644 --- a/docs/core-data-structures/tools.md +++ b/docs/core-data-structures/tools.md @@ -96,35 +96,28 @@ type ParameterPropertySpec = ValueSchemaSpec & { required?: true } * Tool parameter schema. The map itself is an implicit open object root; * requiredness remains a per-property `required: true` annotation. */ -type ParameterSchemaSpec = Record +type ParameterSchemaSpec = { + [key: string]: ParameterPropertySpec + [key: symbol]: never +} ``` -`{ type: 'json' }` infers `JsonValue` and compiles to an annotation-only unconstrained raw schema. Output roots can be objects, arrays, scalars, or null. `InferValue` honors literal constraints and object openness; `InferArgs

    ` turns per-property requiredness into required and optional keys: +`{ type: 'json' }` infers `JsonValue` and compiles to an annotation-only unconstrained raw schema. Output roots can be objects, arrays, scalars, or null. `InferValue` honors literal constraints and object openness through 16 container levels, then falls back to `JsonValue` instead of exhausting TypeScript's type-instantiation stack. `InferArgs

    ` turns per-property requiredness into required and optional string keys: ```ts type-equiv /** - * Infer the TypeScript value accepted by an author-facing value schema. - * Output schemas may therefore infer object, array, scalar, or null roots. + * Infer the TypeScript value accepted by an author-facing value schema. Exact + * inference is bounded to 16 container levels, then falls back to `JsonValue`. */ -type InferValue = - S extends StringValueSchemaSpec ? InferScalar : - S extends NumberValueSchemaSpec | IntegerValueSchemaSpec ? InferScalar : - S extends BooleanValueSchemaSpec ? InferScalar : - S extends NullValueSchemaSpec ? null : - S extends ArrayValueSchemaSpec - ? S extends { items: infer I extends ValueSchemaSpec } ? InferValue[] : JsonValue[] - : S extends ObjectValueSchemaSpec ? InferObject : - S extends JsonValueSchemaSpec ? JsonValue : - S extends OneOfValueSchemaSpec ? InferValue : - never +type InferValue = InferValueAt ``` ```ts type-equiv /** Infer the TypeScript argument object for an implicit parameter schema. */ -type InferArgs = InferProperties +type InferArgs = InferProperties ``` -`defineTool({ name, description, parameters, execute, … })` ties parameter inference to `parameterSchemaSpecToJsonSchema()` and `validateArgs()`. `valueSchemaSpecToJsonSchema()` compiles value/output declarations through the same enforced raw subset. A parameter mismatch throws `ToolArgsError` (`INVALID_ARGS`), which the registry returns through the normal tool-error path. Raw JSON Schema remains open by default; unsupported keywords reject instead of being accepted without enforcement. +`defineTool({ name, description, parameters, execute, … })` ties parameter inference to `parameterSchemaSpecToJsonSchema()` and `validateArgs()`. `valueSchemaSpecToJsonSchema()` compiles value/output declarations through the same enforced raw subset. Schema records contain only own enumerable string keys, and schema arrays are dense intrinsic arrays, so inference, compilation, and validation observe the same declaration. A parameter mismatch throws `ToolArgsError` (`INVALID_ARGS`), which the registry returns through the normal tool-error path. Raw JSON Schema remains open by default; unsupported keywords reject instead of being accepted without enforcement. Registration is a trusted same-process contract. The registry borrows the typed definition as readonly input and validates only semantic requirements such as a positive finite `timeoutMs`; `schemas()` materializes the explicit model-facing projection at the model boundary so execution and presentation share one resolved definition without leaking callbacks onto the wire. diff --git a/packages/cordis/tool-cordis/src/guard.ts b/packages/cordis/tool-cordis/src/guard.ts index bf225948be..aa68a1d796 100644 --- a/packages/cordis/tool-cordis/src/guard.ts +++ b/packages/cordis/tool-cordis/src/guard.ts @@ -36,13 +36,18 @@ function isPlainRecord(value: unknown): value is Record { } /* jscpd:ignore-start -- this VM boundary mirrors the session-owned realm-safe intrinsic test */ -/** Whether a realm-owned intrinsic prototype names and points back to its constructor. */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ function hasIntrinsicConstructor(prototype: object, name: 'Array' | 'Object'): boolean { const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor') const constructor: unknown = descriptor?.value - return typeof constructor === 'function' - && constructor.name === name - && constructor.prototype === prototype + if (typeof constructor !== 'function') return false + try { + return constructor.name === name + && constructor.prototype === prototype + && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }` + } catch { + return false + } } /** Whether an array uses one realm's intrinsic Array prototype rather than a subclass. */ diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 347e87c76a..749ec133ee 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -403,6 +403,9 @@ describe('cordis_mount', () => { ['parameters: { value: { type: \'json\', default: new (class DefaultValue { constructor() { this.ok = true } })() } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: new (class DefaultList extends Array {})() } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: new Date(0) } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: (() => { const p = Object.create(null); const C = function C() {}; Object.defineProperty(C, \'name\', { value: \'Object\' }); C.prototype = p; Object.defineProperty(p, \'constructor\', { value: C }); return Object.create(p) })()', 'must be a ParameterSchemaSpec object'], + ['parameters: (() => { const p = Object.create(null); const C = function C() {}; Object.defineProperty(C, \'name\', { value: \'Object\' }); C.prototype = p; const r = Proxy.revocable(C, {}); Object.defineProperty(p, \'constructor\', { value: r.proxy }); r.revoke(); return Object.create(p) })()', 'must be a ParameterSchemaSpec object'], + ['parameters: Object.create(Object.create(null))', 'must be a ParameterSchemaSpec object'], ])('rejects a malformed ParameterSchemaSpec (%s) with a teaching error', async (parameters, message) => { const ctx = await setup() const result = await call(ctx, 'cordis_mount', { diff --git a/packages/core/session/src/json.ts b/packages/core/session/src/json.ts index e1452457fd..43e9f0625f 100644 --- a/packages/core/session/src/json.ts +++ b/packages/core/session/src/json.ts @@ -12,13 +12,18 @@ */ export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } -/** Whether a realm-owned intrinsic prototype names and points back to its constructor. */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ function hasIntrinsicConstructor(prototype: object, name: 'Array' | 'Object'): boolean { const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor') const constructor: unknown = descriptor?.value - return typeof constructor === 'function' - && constructor.name === name - && constructor.prototype === prototype + if (typeof constructor !== 'function') return false + try { + return constructor.name === name + && constructor.prototype === prototype + && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }` + } catch { + return false + } } /** Whether a candidate is one realm's intrinsic `Object.prototype`. */ diff --git a/packages/core/session/tests/json.spec.ts b/packages/core/session/tests/json.spec.ts index e8680142f3..d81266440e 100644 --- a/packages/core/session/tests/json.spec.ts +++ b/packages/core/session/tests/json.spec.ts @@ -2,6 +2,17 @@ import { runInNewContext } from 'node:vm' import { describe, expect, it } from 'vitest' import { isJsonValue, snapshotJsonValue, type JsonValue } from '@deepseek-ai/dsh-session' +function objectWithForgedIntrinsicPrototype(revoked = false): Record { + const prototype = Object.create(null) as Record + const ForgedObject = function ForgedObject(): void {} + Object.defineProperty(ForgedObject, 'name', { value: 'Object' }) + ForgedObject.prototype = prototype + const constructor = revoked ? Proxy.revocable(ForgedObject, {}) : undefined + if (constructor !== undefined) constructor.revoke() + Object.defineProperty(prototype, 'constructor', { value: constructor?.proxy ?? ForgedObject }) + return Object.assign(Object.create(prototype) as Record, { value: 1 }) +} + describe('snapshotJsonValue', () => { it('copies the complete JSON scalar vocabulary and rejects unsupported scalars', () => { const unsupportedFunction = (): void => {} @@ -109,6 +120,8 @@ describe('snapshotJsonValue', () => { const symbolObject = { [Symbol('extra')]: true } const customPrototype = Object.create(null) as Record const customPrototypeObject = Object.assign(Object.create(customPrototype) as Record, { value: 1 }) + const forgedIntrinsicObject = objectWithForgedIntrinsicPrototype() + const revokedIntrinsicObject = objectWithForgedIntrinsicPrototype(true) const forgedPrototype: unknown[] = [] Object.setPrototypeOf(forgedPrototype, null) const forgedArray = [1] @@ -133,6 +146,8 @@ describe('snapshotJsonValue', () => { expect(snapshotJsonValue(hiddenObject)).toBeUndefined() expect(snapshotJsonValue(symbolObject)).toBeUndefined() expect(snapshotJsonValue(customPrototypeObject)).toBeUndefined() + expect(snapshotJsonValue(forgedIntrinsicObject)).toBeUndefined() + expect(snapshotJsonValue(revokedIntrinsicObject)).toBeUndefined() expect(snapshotJsonValue(forgedArray)).toBeUndefined() expect(snapshotJsonValue(cyclic)).toBeUndefined() expect(snapshotJsonValue([undefined])).toBeUndefined() @@ -206,6 +221,8 @@ describe('isJsonValue', () => { const symbolObject = { [Symbol('extra')]: true } const customPrototype = Object.create(null) as Record const customPrototypeObject = Object.assign(Object.create(customPrototype) as Record, { value: 1 }) + const forgedIntrinsicObject = objectWithForgedIntrinsicPrototype() + const revokedIntrinsicObject = objectWithForgedIntrinsicPrototype(true) const forgedPrototype: unknown[] = [] Object.setPrototypeOf(forgedPrototype, null) const forgedArray = [1] @@ -220,6 +237,8 @@ describe('isJsonValue', () => { expect(isJsonValue(hiddenObject)).toBe(false) expect(isJsonValue(symbolObject)).toBe(false) expect(isJsonValue(customPrototypeObject)).toBe(false) + expect(isJsonValue(forgedIntrinsicObject)).toBe(false) + expect(isJsonValue(revokedIntrinsicObject)).toBe(false) expect(isJsonValue(forgedArray)).toBe(false) expect(isJsonValue(new ExoticArray(1))).toBe(false) expect(isJsonValue([undefined])).toBe(false) diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 2105120241..d353bca61f 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -84,7 +84,7 @@ ctx.tools.register(defineTool({ })) ``` -The unified schema DSL uses `ParameterSchemaSpec` for the implicit open parameter object and `ValueSchemaSpec` for any JSON-value root. It supports `string`, `number`, `integer`, `boolean`, `null`, `array`, `object`, author-only `json`, and exact-one `oneOf`; scalar `enum`/`const` values are type-correct. Every explicit DSL object declares `additionalProperties: true | false`, while the implicit parameter root and raw JSON Schema keep the standard open default. Compilation, validation, registry detachment, and schema-to-TypeScript rendering use explicit work stacks, so valid deep schemas are memory-bounded rather than call-stack-bounded. +The unified schema DSL uses `ParameterSchemaSpec` for the implicit open parameter object and `ValueSchemaSpec` for any JSON-value root. It supports `string`, `number`, `integer`, `boolean`, `null`, `array`, `object`, author-only `json`, and exact-one `oneOf`; scalar `enum`/`const` values are type-correct. Every explicit DSL object declares `additionalProperties: true | false`, while the implicit parameter root and raw JSON Schema keep the standard open default. Schema records accept only own enumerable string keys, and schema arrays must be dense ordinary arrays. Compilation, validation, registry detachment, and schema-to-TypeScript rendering use explicit work stacks, so runtime processing of valid deep schemas is memory-bounded rather than call-stack-bounded; `InferValue` preserves exact types through 16 container levels and then falls back to `JsonValue` so TypeScript itself remains stack-safe. A `defineTool` definition validates model arguments before execution and turns missing required values, wrong primitives, invalid enum members, and nested violations into `ToolArgsError` (`INVALID_ARGS`) for the normal error-result path. The implicit parameter root is open; an explicit object accepts extra keys only with `additionalProperties: true`, and a closed object with no declared properties accepts only `{}`. Raw JSON Schema objects remain open unless they explicitly set `additionalProperties: false`. Defaults are not applied; open objects without `properties` and arrays without `items` receive only a container type check. Raw-registered tools own their validation. diff --git a/packages/core/tools/src/json-schema.ts b/packages/core/tools/src/json-schema.ts index d84b788aef..9b6ca88d93 100644 --- a/packages/core/tools/src/json-schema.ts +++ b/packages/core/tools/src/json-schema.ts @@ -86,6 +86,26 @@ const CONSTRAINT_KEYWORDS = new Set([ const ANNOTATION_KEYWORDS = new Set(['description', 'title', 'default', 'examples']) const SCHEMA_TYPES: readonly JsonSchemaType[] = ['object', 'array', 'string', 'number', 'integer', 'boolean', 'null'] +/* jscpd:ignore-start -- this realm boundary mirrors the session-owned lossless-JSON intrinsic test */ +/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ +function hasIntrinsicConstructor(prototype: object, name: 'Array' | 'Object'): boolean { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor') + const constructor: unknown = descriptor?.value + if (typeof constructor !== 'function') return false + try { + return constructor.name === name + && constructor.prototype === prototype + && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }` + } catch { + return false + } +} + +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value: object): boolean { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, 'Object') +} + /** * Test for a realm-agnostic plain JSON record without accepting arrays or * exotic objects. @@ -94,8 +114,61 @@ const SCHEMA_TYPES: readonly JsonSchemaType[] = ['object', 'array', 'string', 'n */ export function isPlainJsonRecord(value: unknown): value is Record { if (typeof value !== 'object' || value === null || Array.isArray(value)) return false - const proto: unknown = Object.getPrototypeOf(value) - return proto === null || Object.getPrototypeOf(proto) === null + try { + const prototype: unknown = Object.getPrototypeOf(value) + return prototype === null + || typeof prototype === 'object' && isIntrinsicObjectPrototype(prototype) + } catch { + return false + } +} + +/** Whether an array uses one realm's intrinsic `Array.prototype`. */ +function hasPlainArrayPrototype(value: unknown[]): boolean { + const prototype: unknown = Object.getPrototypeOf(value) + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) return false + const objectPrototype: unknown = Object.getPrototypeOf(prototype) + return typeof objectPrototype === 'object' + && objectPrototype !== null + && isIntrinsicObjectPrototype(objectPrototype) +} +/* jscpd:ignore-end */ + +/** Return whether a record contains only own enumerable string keys. */ +function hasOnlyEnumerableStringKeys(value: object): boolean { + try { + return Reflect.ownKeys(value) + .every(key => typeof key === 'string' && Object.prototype.propertyIsEnumerable.call(value, key)) + } catch { + return false + } +} + +/** + * Test for an ordinary schema record whose keys survive JSON projection. + * @param value - candidate record from any JavaScript realm. + * @returns Whether the record has an intrinsic prototype and only own enumerable string keys. + */ +export function isJsonSchemaRecord(value: unknown): value is Record { + return isPlainJsonRecord(value) && hasOnlyEnumerableStringKeys(value) +} + +/** + * Test for a dense ordinary array with no JSON-invisible decorations. + * @param value - candidate array from any JavaScript realm. + * @returns Whether the array is intrinsic, dense, and undecorated. + */ +export function isPlainJsonArray(value: unknown): value is unknown[] { + if (!Array.isArray(value)) return false + try { + if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false + for (let index = 0; index < value.length; index++) { + if (!Object.hasOwn(value, index)) return false + } + return true + } catch { + return false + } } /** Lossless finite JSON number, excluding negative zero. */ @@ -133,12 +206,13 @@ function checkObjectSchemaTail( properties: unknown, violations: string[], ): void { - const required = node.required - if (Object.hasOwn(node, 'required')) { - if (!Array.isArray(required) || required.some(entry => typeof entry !== 'string')) { + const hasRequired = Object.hasOwn(node, 'required') + const required = hasRequired ? node.required : undefined + if (hasRequired) { + if (!isPlainJsonArray(required) || required.some(entry => typeof entry !== 'string')) { violations.push(`${path}.required must be an array of strings`) } else { - const declared = isPlainJsonRecord(properties) ? properties : {} + const declared = isJsonSchemaRecord(properties) ? properties : {} for (const key of required as string[]) { if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names "${key}" which is not in properties`) } @@ -169,7 +243,7 @@ function checkSchemaNode(root: unknown, rootPath: string, violations: string[], } const { node, path } = task - if (!isPlainJsonRecord(node)) { + if (!isJsonSchemaRecord(node)) { violations.push(`${path} must be a schema object`) continue } @@ -192,10 +266,10 @@ function checkSchemaNode(root: unknown, rootPath: string, violations: string[], } violations.push(`${path}.${key} is not a supported keyword (subset: type/oneOf/properties/required/additionalProperties/items/enum/const + annotations)`) } - if (node.description !== undefined && typeof node.description !== 'string') { + if (Object.hasOwn(node, 'description') && typeof node.description !== 'string') { violations.push(`${path}.description must be a string`) } - if (node.title !== undefined && typeof node.title !== 'string') { + if (Object.hasOwn(node, 'title') && typeof node.title !== 'string') { violations.push(`${path}.title must be a string`) } @@ -215,7 +289,7 @@ function checkSchemaNode(root: unknown, rootPath: string, violations: string[], if (hasOneOf) { const oneOf = node.oneOf tasks.push({ kind: 'one-of-tail', node, path }) - if (!Array.isArray(oneOf) || oneOf.length < 2) { + if (!isPlainJsonArray(oneOf) || oneOf.length < 2) { violations.push(`${path}.oneOf must be an array of at least two schemas`) } else { for (let index = oneOf.length - 1; index >= 0; index--) { @@ -249,10 +323,10 @@ function checkSchemaNode(root: unknown, rootPath: string, violations: string[], switch (schemaType) { case 'object': { - const properties = node.properties + const properties = Object.hasOwn(node, 'properties') ? node.properties : undefined tasks.push({ kind: 'object-tail', node, path, properties }) if (Object.hasOwn(node, 'properties')) { - if (!isPlainJsonRecord(properties)) { + if (!isJsonSchemaRecord(properties)) { violations.push(`${path}.properties must be an object of schemas`) } else { const entries = Object.entries(properties) @@ -275,18 +349,21 @@ function checkSchemaNode(root: unknown, rootPath: string, violations: string[], case 'integer': case 'boolean': case 'null': { - const allowed = node.enum - const enumValid = Array.isArray(allowed) + const hasEnum = Object.hasOwn(node, 'enum') + const allowed = hasEnum ? node.enum : undefined + const enumValid = isPlainJsonArray(allowed) && allowed.length > 0 && allowed.every(entry => scalarMatches(schemaType, entry)) - if (Object.hasOwn(node, 'enum') && !enumValid) { + if (hasEnum && !enumValid) { violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`) } - const constValid = scalarMatches(schemaType, node.const) - if (Object.hasOwn(node, 'const')) { + const hasConst = Object.hasOwn(node, 'const') + const declaredConst = hasConst ? node.const : undefined + const constValid = scalarMatches(schemaType, declaredConst) + if (hasConst) { if (!constValid) { violations.push(`${path}.const must be a ${schemaType} value`) - } else if (enumValid && !allowed.includes(node.const as JsonSchemaScalar)) { + } else if (enumValid && !allowed.includes(declaredConst)) { violations.push(`${path}.const must be one of ${path}.enum when both are declared`) } } @@ -320,7 +397,8 @@ export function assertSupportedJsonSchema(schema: unknown): asserts schema is Js export function assertObjectJsonSchema(schema: unknown): asserts schema is ObjectJsonSchema { const violations: string[] = [] checkSchemaNode(schema, 'schema', violations, new Set()) - if (violations.length === 0 && (schema as JsonSchemaNode).type !== 'object') { + if (violations.length === 0 + && (!isJsonSchemaRecord(schema) || !Object.hasOwn(schema, 'type') || schema.type !== 'object')) { violations.push('schema.type must be "object" (structured output is object-rooted)') } if (violations.length > 0) throw new JsonSchemaError(violations) @@ -395,8 +473,9 @@ function valueFrame(node: JsonSchemaNode, value: unknown, path: string): ValueFr /** Validate one scalar node after its primitive type check. */ function checkScalarValue(node: JsonSchemaNode, value: unknown, path: string): string[] { - if (node.enum !== undefined && !node.enum.includes(value as JsonSchemaScalar)) { - return [`"${diagnosticPath(path)}" must be one of ${JSON.stringify(node.enum)}`] + const allowed = Object.hasOwn(node, 'enum') ? node.enum : undefined + if (allowed !== undefined && !allowed.includes(value as JsonSchemaScalar)) { + return [`"${diagnosticPath(path)}" must be one of ${JSON.stringify(allowed)}`] } if (Object.hasOwn(node, 'const') && value !== node.const) { return [`"${diagnosticPath(path)}" must be ${JSON.stringify(node.const)}`] @@ -455,9 +534,9 @@ function checkValue(schema: JsonSchemaNode, value: unknown, path: string): strin continue } - const nodeType = frame.node.type + const nodeType = Object.hasOwn(frame.node, 'type') ? frame.node.type : undefined frame.catches = !(nodeType !== undefined && !(SCHEMA_TYPES as readonly unknown[]).includes(nodeType)) - const oneOf = frame.node.oneOf + const oneOf = Object.hasOwn(frame.node, 'oneOf') ? frame.node.oneOf : undefined if (oneOf !== undefined) { frame.kind = 'oneOf' frame.children = Array.from(oneOf, branch => ({ node: branch, value: frame.value, path: frame.path })) @@ -477,9 +556,10 @@ function checkValue(schema: JsonSchemaNode, value: unknown, path: string): strin finish([`"${diagnosticPath(frame.path)}" must be an object`]) break } - const properties = frame.node.properties ?? {} + const properties = Object.hasOwn(frame.node, 'properties') ? frame.node.properties ?? {} : {} const violations: string[] = [] - for (const key of frame.node.required ?? []) { + const required = Object.hasOwn(frame.node, 'required') ? frame.node.required ?? [] : [] + for (const key of required) { if (!Object.hasOwn(frame.value, key) || frame.value[key] === undefined) { violations.push(`missing required property "${propertyPath(frame.path, key)}"`) } @@ -490,7 +570,7 @@ function checkValue(schema: JsonSchemaNode, value: unknown, path: string): strin children.push({ node: child, value: frame.value[key], path: propertyPath(frame.path, key) }) } const tailViolations: string[] = [] - if (frame.node.additionalProperties === false) { + if (Object.hasOwn(frame.node, 'additionalProperties') && frame.node.additionalProperties === false) { for (const key of Object.keys(frame.value)) { if (!Object.hasOwn(properties, key)) { tailViolations.push(`"${propertyPath(frame.path, key)}" is not a declared property (additionalProperties: false)`) @@ -510,7 +590,7 @@ function checkValue(schema: JsonSchemaNode, value: unknown, path: string): strin finish([`"${diagnosticPath(frame.path)}" must be an array`]) break } - const items = frame.node.items + const items = Object.hasOwn(frame.node, 'items') ? frame.node.items : undefined const children = items === undefined ? [] : frame.value.flatMap((entry, index): ValueChild[] => [{ node: items, value: entry, path: `${frame.path}[${index}]` }]) diff --git a/packages/core/tools/src/schema.ts b/packages/core/tools/src/schema.ts index 36fd444b64..151efd05a2 100644 --- a/packages/core/tools/src/schema.ts +++ b/packages/core/tools/src/schema.ts @@ -3,7 +3,7 @@ import { HarnessError } from '@deepseek-ai/dsh-llm' import type { JsonValue } from '@deepseek-ai/dsh-session' import type { ToolDefinition, ToolExecuteReturn, ToolRunContext, ToolResult } from './index.ts' -import { assertSupportedJsonSchema, isPlainJsonRecord, JsonSchemaError, validateJsonSchemaValue } from './json-schema.ts' +import { assertSupportedJsonSchema, isJsonSchemaRecord, isPlainJsonArray, JsonSchemaError, validateJsonSchemaValue } from './json-schema.ts' import type { JsonSchemaNode, JsonSchemaScalar, ObjectJsonSchema } from './json-schema.ts' import type { ToolCallView, ToolResultView } from './presentation.ts' @@ -99,7 +99,10 @@ export type ParameterPropertySpec = ValueSchemaSpec & { required?: true } * Tool parameter schema. The map itself is an implicit open object root; * requiredness remains a per-property `required: true` annotation. */ -export type ParameterSchemaSpec = Record +export type ParameterSchemaSpec = { + [key: string]: ParameterPropertySpec + [key: symbol]: never +} /** Raw JSON Schema projection of the implicit parameter object. */ export interface ParameterJsonSchema extends ObjectJsonSchema { @@ -109,26 +112,29 @@ export interface ParameterJsonSchema extends ObjectJsonSchema { /** Flatten an intersection into one object type for readable hovers. */ type Simplify = { [K in keyof T]: T[K] } & {} +/** String keys of one property map; runtime compilation rejects symbol keys. */ +type StringKeyOf = Extract + /** Keys of a property map marked `required: true`. */ -type RequiredKeys = { - [K in keyof S]: S[K] extends { required: true } ? K : never -}[keyof S] +type RequiredKeys = { + [K in StringKeyOf]: S[K] extends { required: true } ? K : never +}[StringKeyOf] /** Infer the declared value of one parameter property without key optionality. */ -type InferProperty

    = P extends ValueSchemaSpec ? InferValue

    : never +type InferProperty = InferValueAt /** Infer an implicit property map into required and optional object keys. */ -type InferProperties = Simplify< - & { [K in RequiredKeys]: InferProperty } - & { [K in Exclude>]?: InferProperty } +type InferProperties = Simplify< + & { [K in RequiredKeys]: InferProperty } + & { [K in Exclude, RequiredKeys>]?: InferProperty } > /** Infer an explicit object node, including its declared openness. */ -type InferObject = - S extends { properties: infer P extends ParameterSchemaSpec } +type InferObject = + S extends { properties: infer P } ? S['additionalProperties'] extends true - ? InferProperties

    & Record - : InferProperties

    + ? InferProperties & Record + : InferProperties : S['additionalProperties'] extends true ? Record : Record @@ -139,24 +145,33 @@ type InferScalar = S extends { enum: readonly (infer E)[] } ? E : Fallback +/** Add one schema-container level to bounded compile-time inference. */ +type NextInferenceDepth = [unknown, ...Depth] + +/** Infer one node without recursively checking it against the full author union. */ +type InferValueAt = + Depth['length'] extends 16 ? JsonValue : + S extends { type: 'string' } ? InferScalar : + S extends { type: 'number' | 'integer' } ? InferScalar : + S extends { type: 'boolean' } ? InferScalar : + S extends { type: 'null' } ? null : + S extends { type: 'array' } + ? S extends { items: infer I } ? InferValueAt>[] : JsonValue[] + : S extends { type: 'object'; additionalProperties: boolean } + ? InferObject> + : S extends { type: 'json' } ? JsonValue : + S extends { oneOf: readonly unknown[] } + ? InferValueAt> + : never + /** - * Infer the TypeScript value accepted by an author-facing value schema. - * Output schemas may therefore infer object, array, scalar, or null roots. + * Infer the TypeScript value accepted by an author-facing value schema. Exact + * inference is bounded to 16 container levels, then falls back to `JsonValue`. */ -export type InferValue = - S extends StringValueSchemaSpec ? InferScalar : - S extends NumberValueSchemaSpec | IntegerValueSchemaSpec ? InferScalar : - S extends BooleanValueSchemaSpec ? InferScalar : - S extends NullValueSchemaSpec ? null : - S extends ArrayValueSchemaSpec - ? S extends { items: infer I extends ValueSchemaSpec } ? InferValue[] : JsonValue[] - : S extends ObjectValueSchemaSpec ? InferObject : - S extends JsonValueSchemaSpec ? JsonValue : - S extends OneOfValueSchemaSpec ? InferValue : - never +export type InferValue = InferValueAt /** Infer the TypeScript argument object for an implicit parameter schema. */ -export type InferArgs = InferProperties +export type InferArgs = InferProperties const ANNOTATION_KEYS = ['description', 'title', 'default', 'examples'] as const @@ -272,11 +287,11 @@ function runSchemaCompiler(initial: CompileTask): void { continue } if (task.kind === 'property') { - if (!isPlainJsonRecord(task.property)) authorError(`${task.path} must be a value schema object`) + if (!isJsonSchemaRecord(task.property)) authorError(`${task.path} must be a value schema object`) if (Object.hasOwn(task.property, 'required') && task.property.required !== true) { authorError(`${task.path}.required must be true when present`) } - if (task.property.required === true) task.required.push(task.key) + if (Object.hasOwn(task.property, 'required') && task.property.required === true) task.required.push(task.key) tasks.push({ kind: 'value', input: task.property, @@ -287,7 +302,7 @@ function runSchemaCompiler(initial: CompileTask): void { continue } if (task.kind === 'property-map') { - if (!isPlainJsonRecord(task.input)) authorError(`${task.path} must be an object of value schemas`) + if (!isJsonSchemaRecord(task.input)) authorError(`${task.path} must be an object of value schemas`) if (seen.has(task.input)) authorError(`${task.path} is circular`) seen.add(task.input) const compiled: CompiledPropertyMap = { properties: {} } @@ -313,7 +328,7 @@ function runSchemaCompiler(initial: CompileTask): void { } const { input, path } = task - if (!isPlainJsonRecord(input)) authorError(`${path} must be a value schema object`) + if (!isJsonSchemaRecord(input)) authorError(`${path} must be a value schema object`) if (seen.has(input)) authorError(`${path} is circular`) seen.add(input) const authorKeys = [...ANNOTATION_KEYS, ...(task.allowRequired ? ['required'] : [])] @@ -324,7 +339,7 @@ function runSchemaCompiler(initial: CompileTask): void { if (Object.hasOwn(input, 'oneOf')) { assertAuthorKeys(input, path, [...authorKeys, 'oneOf', 'type']) if (Object.hasOwn(input, 'type')) authorError(`${path} cannot declare both type and oneOf`) - if (!Array.isArray(input.oneOf)) authorError(`${path}.oneOf must be an array of at least two value schemas`) + if (!isPlainJsonArray(input.oneOf)) authorError(`${path}.oneOf must be an array of at least two value schemas`) const branches: JsonSchemaNode[] = [] node.oneOf = branches copyAnnotations(input, node) @@ -340,7 +355,8 @@ function runSchemaCompiler(initial: CompileTask): void { continue } - switch (input.type) { + const inputType = Object.hasOwn(input, 'type') ? input.type : undefined + switch (inputType) { case 'json': assertAuthorKeys(input, path, [...authorKeys, 'type']) copyAnnotations(input, node) @@ -382,12 +398,11 @@ function runSchemaCompiler(initial: CompileTask): void { case 'boolean': case 'null': assertAuthorKeys(input, path, [...authorKeys, 'type', 'enum', 'const']) - node.type = input.type + node.type = inputType copyAnnotations(input, node) if (Object.hasOwn(input, 'enum')) { - node.enum = Array.isArray(input.enum) - ? Array.from(input.enum as unknown[], entry => entry as JsonSchemaScalar) - : input.enum as JsonSchemaScalar[] + if (!isPlainJsonArray(input.enum)) authorError(`${path}.enum must be a non-empty array of scalar values`) + node.enum = Array.from(input.enum, entry => entry as JsonSchemaScalar) } if (Object.hasOwn(input, 'const')) node.const = input.const as JsonSchemaScalar break diff --git a/packages/core/tools/tests/json-schema.spec.ts b/packages/core/tools/tests/json-schema.spec.ts index 67b5501fe0..fc29965c3b 100644 --- a/packages/core/tools/tests/json-schema.spec.ts +++ b/packages/core/tools/tests/json-schema.spec.ts @@ -30,6 +30,21 @@ function violationsOf(schema: unknown, objectRoot = false): string[] { throw new Error('expected schema rejection') } +function recordWithForgedIntrinsicPrototype( + own: Record, + inherited: Record = {}, + revoked = false, +): Record { + const prototype = Object.assign(Object.create(null) as Record, inherited) + const ForgedObject = function ForgedObject(): void {} + Object.defineProperty(ForgedObject, 'name', { value: 'Object' }) + ForgedObject.prototype = prototype + const constructor = revoked ? Proxy.revocable(ForgedObject, {}) : undefined + if (constructor !== undefined) constructor.revoke() + Object.defineProperty(prototype, 'constructor', { value: constructor?.proxy ?? ForgedObject }) + return Object.assign(Object.create(prototype) as Record, own) +} + describe('the enforced raw JSON Schema subset', () => { it('accepts every JSON root and every supported node', () => { for (const schema of [ @@ -81,6 +96,23 @@ describe('the enforced raw JSON Schema subset', () => { .toEqual(['schema.items is not supported beside oneOf']) expect(violationsOf({ oneOf: [{ type: 'string' }, { type: 'weird' }] })[0]) .toContain('schema.oneOf[1].type') + const sparse = new Array(2) + sparse[0] = { type: 'string' } + expect(violationsOf({ oneOf: sparse })) + .toEqual(['schema.oneOf must be an array of at least two schemas']) + const compensatedSparse = new Array(2) + compensatedSparse[0] = { type: 'string' } + Object.defineProperty(compensatedSparse, 'extra', { value: true }) + expect(violationsOf({ oneOf: compensatedSparse })) + .toEqual(['schema.oneOf must be an array of at least two schemas']) + class ExoticBranches extends Array {} + expect(violationsOf({ oneOf: new ExoticBranches({ type: 'string' }, { type: 'null' }) })) + .toEqual(['schema.oneOf must be an array of at least two schemas']) + const explosiveArray = new Proxy([{ type: 'string' }, { type: 'null' }], { + getPrototypeOf() { throw new Error('prototype trap') }, + }) + expect(violationsOf({ oneOf: explosiveArray })) + .toEqual(['schema.oneOf must be an array of at least two schemas']) }) it('rejects unknown and misplaced keywords without accepted-then-ignored behavior', () => { @@ -134,6 +166,9 @@ describe('the enforced raw JSON Schema subset', () => { 'schema.properties must be an object of schemas', 'schema.required names "missing" which is not in properties', ]) + const sparseRequired = new Array(1) + expect(violationsOf({ type: 'object', required: sparseRequired })) + .toEqual(['schema.required must be an array of strings']) }) it('requires type-correct scalar enum and const values', () => { @@ -163,6 +198,9 @@ describe('the enforced raw JSON Schema subset', () => { .toEqual(['schema.enum must be a non-empty array of string values']) expect(violationsOf({ type: 'string', enum: ['a'], const: 'b' })) .toEqual(['schema.const must be one of schema.enum when both are declared']) + const sparseEnum = new Array(1) + expect(violationsOf({ type: 'string', enum: sparseEnum })) + .toEqual(['schema.enum must be a non-empty array of string values']) }) it('validates annotation types and lossless JSON payloads', () => { @@ -195,6 +233,8 @@ describe('the enforced raw JSON Schema subset', () => { it('accepts lossless annotation containers from another JavaScript realm', () => { const schema = runInNewContext(`({ type: 'object', + properties: { value: { type: 'string', enum: ['x'] } }, + required: ['value'], default: { x: 1 }, examples: [[{ ok: true }]], })`) as unknown @@ -212,6 +252,28 @@ describe('the enforced raw JSON Schema subset', () => { .toEqual(['schema.properties must be an object of schemas']) expect(violationsOf({ type: 'object', properties: { at: new Date(0) } })) .toEqual(['schema.properties.at must be a schema object']) + + const forgedSchema = recordWithForgedIntrinsicPrototype( + { type: 'object' }, + { oneOf: [{ type: 'string' }, { type: 'null' }] }, + ) + expect(violationsOf(forgedSchema)).toEqual(['schema must be a schema object']) + expect(violationsOf(forgedSchema, true)).toEqual(['schema must be a schema object']) + expect(violationsOf(recordWithForgedIntrinsicPrototype({ type: 'string' }, {}, true))) + .toEqual(['schema must be a schema object']) + const prototypeWithoutConstructor = Object.create(null) as object + expect(violationsOf(Object.create(prototypeWithoutConstructor) as unknown)) + .toEqual(['schema must be a schema object']) + expect(violationsOf(Object.defineProperty({ type: 'string' }, 'hidden', { value: true }))) + .toEqual(['schema must be a schema object']) + expect(violationsOf({ type: 'string', [Symbol('hidden')]: true })) + .toEqual(['schema must be a schema object']) + expect(violationsOf(new Proxy({}, { + getPrototypeOf() { throw new Error('prototype trap') }, + }))).toEqual(['schema must be a schema object']) + expect(violationsOf(new Proxy({}, { + ownKeys() { throw new Error('keys trap') }, + }))).toEqual(['schema must be a schema object']) }) it('asserts deeply nested raw unions without using the JavaScript call stack', () => { @@ -369,6 +431,21 @@ describe('validateJsonSchemaValue', () => { asserted({ type: 'object', properties: { constructor: { type: 'string' } } }), {}, )).toEqual([]) + + const inheritedUnion = Object.assign( + Object.create({ oneOf: [{ type: 'string' }, { type: 'null' }] }) as JsonSchemaNode, + { type: 'object' as const }, + ) + expect(validateJsonSchemaValue(inheritedUnion, {})).toEqual([]) + expect(validateJsonSchemaValue(inheritedUnion, 'x')).toEqual(['"value" must be an object']) + expect(validateJsonSchemaValue( + { type: 'object', properties: undefined } as unknown as JsonSchemaNode, + {}, + )).toEqual([]) + expect(validateJsonSchemaValue( + { type: 'object', required: undefined } as unknown as JsonSchemaNode, + {}, + )).toEqual([]) }) it('keeps assertNever as a forged-schema backstop', () => { diff --git a/packages/core/tools/tests/schema.spec.ts b/packages/core/tools/tests/schema.spec.ts index b16c0689b0..ae095b5361 100644 --- a/packages/core/tools/tests/schema.spec.ts +++ b/packages/core/tools/tests/schema.spec.ts @@ -71,6 +71,7 @@ describe('the unified author schema DSL', () => { { type: 'string', oneOf: [{ type: 'string' }, { type: 'null' }] }, { oneOf: 'not-an-array' }, { type: 'string', enum: 'a' }, + {}, null, ]) { expect(() => valueSchemaSpecToJsonSchema(schema as ValueSchemaSpec), JSON.stringify(schema)).toThrow(JsonSchemaError) @@ -80,6 +81,24 @@ describe('the unified author schema DSL', () => { } as unknown as ParameterSchemaSpec)).toThrow(JsonSchemaError) expect(() => parameterSchemaSpecToJsonSchema(null as unknown as ParameterSchemaSpec)).toThrow(JsonSchemaError) expect(() => parameterSchemaSpecToJsonSchema({ bad: 42 } as unknown as ParameterSchemaSpec)).toThrow(JsonSchemaError) + + const symbolKey = Symbol('hidden') + expect(() => parameterSchemaSpecToJsonSchema({ + value: { type: 'string' }, + [symbolKey]: { type: 'number' }, + } as unknown as ParameterSchemaSpec)).toThrow(JsonSchemaError) + const hiddenKey = Object.defineProperty({ value: { type: 'string' } }, 'hidden', { + value: { type: 'number' }, + }) + expect(() => parameterSchemaSpecToJsonSchema(hiddenKey as ParameterSchemaSpec)).toThrow(JsonSchemaError) + const sparseOneOf = new Array(2) + sparseOneOf[0] = { type: 'string' } + expect(() => valueSchemaSpecToJsonSchema({ oneOf: sparseOneOf } as unknown as ValueSchemaSpec)).toThrow(JsonSchemaError) + const decoratedEnum = Object.assign(['a'], { hidden: true }) + expect(() => valueSchemaSpecToJsonSchema({ + type: 'string', + enum: decoratedEnum, + })).toThrow(JsonSchemaError) }) it('rejects cyclic author schemas', () => { @@ -143,6 +162,22 @@ describe('the unified author schema DSL', () => { }>>().toEqualTypeOf<{ id: number } & Record>() }) + it('bounds inference for deeply nested author schemas', () => { + type Repeat = + Result['length'] extends Count ? Result : Repeat + type DeepArraySchema = + Levels extends [unknown, ...infer Rest] + ? { type: 'array'; items: DeepArraySchema } + : { type: 'string' } + type PeelArrays = + Levels extends [unknown, ...infer Rest] + ? Value extends (infer Item)[] ? PeelArrays : never + : Value + + type DeepValue = InferValue>> + expectTypeOf>>().toEqualTypeOf() + }) + it('infers required and optional parameter keys', () => { expectTypeOf { }) it('makes invalid author forms compile-time errors', () => { + const symbolKey = Symbol('parameter') const invalidObjects = { // @ts-expect-error explicit object schemas require an openness decision object: { type: 'object' } satisfies ValueSchemaSpec, @@ -161,7 +197,9 @@ describe('the unified author schema DSL', () => { enum: { type: 'number', enum: ['1'] } satisfies ValueSchemaSpec, // @ts-expect-error parameter requiredness is true-or-absent required: { value: { type: 'string', required: false } } satisfies ParameterSchemaSpec, + // @ts-expect-error parameter maps accept string keys only + symbol: { [symbolKey]: { type: 'string' } } satisfies ParameterSchemaSpec, } - expect(Object.keys(invalidObjects)).toHaveLength(4) + expect(Object.keys(invalidObjects)).toHaveLength(5) }) }) From d59af9befc69029db81c5d9bba836931c347ce97 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:05:50 +0800 Subject: [PATCH 122/368] docs(i18n): address core-data review feedback --- docs/core-data-structures/approval.i18n.yaml | 2 +- docs/core-data-structures/approval.zh.md | 2 +- docs/core-data-structures/bash.i18n.yaml | 2 +- docs/core-data-structures/bash.zh.md | 8 ++--- .../core-data-structures/compaction.i18n.yaml | 2 +- docs/core-data-structures/compaction.zh.md | 4 +-- docs/core-data-structures/core.i18n.yaml | 4 +-- docs/core-data-structures/core.md | 2 ++ docs/core-data-structures/core.zh.md | 34 +++++++++++-------- .../core-data-structures/filesystem.i18n.yaml | 2 +- docs/core-data-structures/filesystem.zh.md | 6 ++-- .../llm-streaming.i18n.yaml | 2 +- docs/core-data-structures/llm-streaming.zh.md | 14 ++++---- .../persistence.i18n.yaml | 2 +- docs/core-data-structures/persistence.zh.md | 10 +++--- docs/core-data-structures/sandbox.i18n.yaml | 2 +- docs/core-data-structures/sandbox.zh.md | 6 ++-- docs/core-data-structures/scope.i18n.yaml | 2 +- docs/core-data-structures/scope.zh.md | 4 +-- .../session-query.i18n.yaml | 2 +- docs/core-data-structures/session-query.zh.md | 6 ++-- docs/core-data-structures/session.i18n.yaml | 2 +- docs/core-data-structures/session.zh.md | 2 +- docs/core-data-structures/subagent.i18n.yaml | 2 +- docs/core-data-structures/subagent.zh.md | 6 ++-- .../system-prompt.i18n.yaml | 2 +- docs/core-data-structures/system-prompt.zh.md | 4 +-- docs/core-data-structures/tools.i18n.yaml | 2 +- docs/core-data-structures/tools.zh.md | 2 +- docs/core-data-structures/web.i18n.yaml | 2 +- docs/core-data-structures/web.zh.md | 2 +- docs/core-data-structures/workflow.i18n.yaml | 2 +- docs/core-data-structures/workflow.zh.md | 4 +-- ...-acp-default-export-drops-inject.i18n.yaml | 2 +- ...0001-acp-default-export-drops-inject.zh.md | 4 +-- ...ession-disabled-filesystem-tools.i18n.yaml | 2 +- ...expression-disabled-filesystem-tools.zh.md | 2 +- 37 files changed, 83 insertions(+), 77 deletions(-) diff --git a/docs/core-data-structures/approval.i18n.yaml b/docs/core-data-structures/approval.i18n.yaml index c6bfeafaf9..583f1cd542 100644 --- a/docs/core-data-structures/approval.i18n.yaml +++ b/docs/core-data-structures/approval.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write approval.md: c9b411e38508fc7e8ac2e2dd923d9c8cc2f475a3 -approval.zh.md: ee593298fece8b2782228f2e93c5509871e15166 +approval.zh.md: 54985cd32f6b16ef90a1ddd1f6da4b87a261788d diff --git a/docs/core-data-structures/approval.zh.md b/docs/core-data-structures/approval.zh.md index ee593298fe..54985cd32f 100644 --- a/docs/core-data-structures/approval.zh.md +++ b/docs/core-data-structures/approval.zh.md @@ -8,7 +8,7 @@ ## 标识与结果 -每个请求都会获得一个全新的 `ApprovalRequestId`。该品牌类型将 `approval/asked` 与 `approval/decided` 审计事件配对,同时不会让审批 id 与工具调用 id 或 agent/session id 互换。 +每个请求都会获得一个全新的 `ApprovalRequestId`。该品牌类型将 `approval/asked` 与 `approval/decided` 审计事件配对,同时不会让审批 id 与工具调用 id 或 agent/会话 id 互换。 ```ts type-equiv /** diff --git a/docs/core-data-structures/bash.i18n.yaml b/docs/core-data-structures/bash.i18n.yaml index 168c96a10a..55ea9b35e9 100644 --- a/docs/core-data-structures/bash.i18n.yaml +++ b/docs/core-data-structures/bash.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write bash.md: 35cf2061588907dde41123efb01e453eb9cc929d -bash.zh.md: 56e5ae7b6231575a6b591093724d5560ade27056 +bash.zh.md: 2b388bd51047219ed46faa07313bb84da1dbb080 diff --git a/docs/core-data-structures/bash.zh.md b/docs/core-data-structures/bash.zh.md index 56e5ae7b62..2b388bd510 100644 --- a/docs/core-data-structures/bash.zh.md +++ b/docs/core-data-structures/bash.zh.md @@ -161,9 +161,9 @@ interface CollectedOutput { ## 文件沙箱:`BashSandboxInfo` -消费 sandbox 的执行器通过 `BashExecutor.sandboxMode` 暴露其已配置的模式回退值。工具层请求 [`@deepseek-ai/dsh-sandbox-policy`](../../packages/sandbox/sandbox-policy/README.md),把每个调用会话的持久 `sandbox/mode` 覆盖值与不可变 cwd 解析为 `BashExecRequest.sandboxPolicy`;经用户批准、严格更宽松的调用只替换模式。模式/root/enforcement 词汇归 [`@deepseek-ai/dsh-sandbox` seam](sandbox.md) 所有;模式仅管辖文件效果。 +使用沙箱的执行器通过 `BashExecutor.sandboxMode` 暴露其已配置的模式回退值。工具层请求 [`@deepseek-ai/dsh-sandbox-policy`](../../packages/sandbox/sandbox-policy/README.md),把每个调用会话的持久 `sandbox/mode` 覆盖值与不可变 cwd 解析为 `BashExecRequest.sandboxPolicy`;经用户批准、严格更宽松的调用只替换模式。模式/root/enforcement 词汇归 [`@deepseek-ai/dsh-sandbox` 沙箱 seam](sandbox.md) 所有;模式仅管辖文件效果。 -sandbox 化运行会报告其模式、保守的拒绝分类与强制执行完整度。`runnerFailed` 标记命令运行前 sandbox runner 已失败;前台执行会抛出 `SANDBOX_UNAVAILABLE`,而已结束的后台进程只能通过其事实通道报告。 +沙箱化运行会报告其模式、保守的拒绝分类与强制执行完整度。`runnerFailed` 标记命令运行前沙箱 runner 已失败;前台执行会抛出 `SANDBOX_UNAVAILABLE`,而已结束的后台进程只能通过其事实通道报告。 ```ts type-equiv /** @@ -183,11 +183,11 @@ interface BashSandboxInfo { } ``` -最后一项补全了这套词汇:当受限模式没有可用后端时,`ctx.sandbox` 提供方会抛出、执行器会传播由 [sandbox seam](sandbox.md) 所有的 `SANDBOX_UNAVAILABLE` 错误码。选定的 runner 拒绝其 profile 时会触达同一个故障关闭的前台错误;已结束的后台任务则记录 `runnerFailed`。模型会在结果中收到拒绝/runner 事实,仅当拒绝标记指出生效模式时才得知该模式,并可通过 `sandbox_permissions` 加 `justification` 请求一次性、严格更宽松的重试;执行任何操作前,`ctx.approval` 必须批准该次确切调用。完整的策略与切换设计见 [sandbox Agent Note](../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。 +最后一项补全了这套词汇:当受限模式没有可用后端时,`ctx.sandbox` 提供方会抛出、执行器会传播由[沙箱 seam](sandbox.md)所有的 `SANDBOX_UNAVAILABLE` 错误码。选定的 runner 拒绝其 profile 时会触达同一个故障关闭的前台错误;已结束的后台任务则记录 `runnerFailed`。模型会在结果中收到拒绝/runner 事实,仅当拒绝标记指出生效模式时才得知该模式,并可通过 `sandbox_permissions` 加 `justification` 请求一次性、严格更宽松的重试;执行任何操作前,`ctx.approval` 必须批准该次确切调用。完整的策略与切换设计见[沙箱 Agent Note](../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。 ## 后台进程:`BashProcess` -`start()` 返回不含 id 或所有者的句柄。`dsh-tool-bash` 将它适配为 `ctx.tasks.start()` hooks;随后由通用运行时拥有任务标识与生命周期。`done` 在进程关闭时 resolve 且绝不 reject;进程结束后仍可读取,并且 sandbox 事实会在 `done` resolve 前写入。 +`start()` 返回不含 id 或所有者的句柄。`dsh-tool-bash` 将它适配为 `ctx.tasks.start()` 钩子;随后由通用运行时拥有任务标识与生命周期。`done` 在进程关闭时 resolve 且绝不 reject;进程结束后仍可读取,并且沙箱事实会在 `done` resolve 前写入。 ```ts type-equiv /** diff --git a/docs/core-data-structures/compaction.i18n.yaml b/docs/core-data-structures/compaction.i18n.yaml index 46ebcb6c85..5133356f6e 100644 --- a/docs/core-data-structures/compaction.i18n.yaml +++ b/docs/core-data-structures/compaction.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write compaction.md: 71bbe7d9c17c6a3d35684a6c87d3072ab4f88df1 -compaction.zh.md: 173b7a7bb6e5e5a47922b0be8011e89a747c2771 +compaction.zh.md: 592e215e7efe69f0dd6099d3d510847cc732e641 diff --git a/docs/core-data-structures/compaction.zh.md b/docs/core-data-structures/compaction.zh.md index 173b7a7bb6..592e215e7e 100644 --- a/docs/core-data-structures/compaction.zh.md +++ b/docs/core-data-structures/compaction.zh.md @@ -13,7 +13,7 @@ | 事件 | 载荷 | 作用 | |---|---|---| | `compact/start` | `{ turn }` | 获取日志记录的锁 | -| `compact/summary` | `{ summary, shadowedRange, shadowedSeqs, shadowedTokenCount, provider, model, maxTokens? }` | provenance:摘要 block、被遮蔽的 surface 边界对(`start`/`end` seq——位置跨度,而非数值区间)、按 surface 顺序排列的被遮蔽 seq、估算 token 数,以及摘要调用的 envelope(`provider`、`model`,若有生成上限则还包括该上限)——写入日志后,该一次性请求可由日志 + 代码重建(见可重建性 Agent Note) | +| `compact/summary` | `{ summary, shadowedRange, shadowedSeqs, shadowedTokenCount, provider, model, maxTokens? }` | provenance:摘要块、被遮蔽的 surface 边界对(`start`/`end` seq——位置跨度,而非数值区间)、按 surface 顺序排列的被遮蔽 seq、估算 token 数,以及摘要调用的 envelope(`provider`、`model`,若有生成上限则还包括该上限)——写入日志后,该一次性请求可由日志 + 代码重建(见可重建性 Agent Note) | | `compact/end` | `{ turn, error? }` | 释放锁(摘要调用抛出异常时设置 `error`) | 锁括住**整个**操作:先追加 `compact/start`,然后执行摘要生成、写入 `compact/summary` 来源记录与 `user/message` 替换,最后才追加 `compact/end`。最后释放锁意味着操作中途崩溃会表现为可检测的遗留锁(有 `compact/start` 而无匹配的 `compact/end`),而非一个虚假声称压缩已完成的 `compact/end`。 @@ -62,7 +62,7 @@ type CompactionTrigger = 'pressure' | 'context-overflow' `CompactService` 暴露 `compactIfNeeded(agent, trigger, signal)` 以执行自动 `pressure` 或 `context-overflow` 策略;没有可安全执行的工作时返回 `null`。它还针对显式、两端均包含的 surface 范围暴露 `compactRegion(...)`。每个后端都使用包导出的 `COMPACT_CHECKPOINT_SOURCE` 标记其替换用的 `user/message`;消费方调用 `isCompactCheckpointSource()`,而不是把检查点识别逻辑耦合到某一个后端。实现必须把传入的 signal 转发给摘要流程。该 seam 不拥有计价 API:单例 [`ctx.tokenMeter`](token-meter.md) 直接拥有估算与回放,而 `dsh-compact-basic` 拥有保留策略、事件排序、按路由执行的摘要调用及其配置。 -压力压缩在串行 `agent/post-step` 中运行:此时成功的 assistant 输出、工具结果、缓冲 context 和 steering 已持久化,但 `step/end` 尚未发生。一旦压力或规范化溢出满足条件,compact-basic 会在选择范围前调用可选的 [`ctx.toolResultPrune`](../../packages/compact/compact-tool-result-prune/README.md),再通过 `ctx.tokenMeter` 重新测量,并且可以在不生成摘要的情况下推进 surface。失败请求的恢复在失败 step 关闭后通过 `agent/request-error` 运行;仅当 surface replacement generation 前进时才批准一个带新编号的 step 重试,即便后续摘要工作在剪枝后抛异常亦如此;取消仍然优先。区域边界保持工具调用/结果配对,但不保持整个 turn,因此一个过大 turn 中较早关闭的 step 可以被压缩。`dsh-compact-basic` 拥有阈值、保留尾部策略、溢出上限与失败处理。 +压力压缩在串行 `agent/post-step` 中运行:此时成功的 assistant 输出、工具结果、缓冲上下文和 steering 已持久化,但 `step/end` 尚未发生。一旦压力或规范化溢出满足条件,compact-basic 会在选择范围前调用可选的 [`ctx.toolResultPrune`](../../packages/compact/compact-tool-result-prune/README.md),再通过 `ctx.tokenMeter` 重新测量,并且可以在不生成摘要的情况下推进 surface。失败请求的恢复在失败 step 关闭后通过 `agent/request-error` 运行;仅当 surface replacement generation 前进时才批准一个带新编号的 step 重试,即便后续摘要工作在剪枝后抛异常亦如此;取消仍然优先。区域边界保持工具调用/结果配对,但不保持整个 turn,因此一个过大 turn 中较早关闭的 step 可以被压缩。`dsh-compact-basic` 拥有阈值、保留尾部策略、溢出上限与失败处理。 该 seam 导出 `toolPairingBalancedBefore(session, seq)` 与 `toolPairingBalancedAfter(session, seq)`,用于这些边缘检查。两者都会验证当前 surface 成员关系,并拒绝缺失的 seq 与孤立结果;其缓存语义由[包契约](../../packages/compact/compact/README.md#tool-pairing-boundaries)规定。 diff --git a/docs/core-data-structures/core.i18n.yaml b/docs/core-data-structures/core.i18n.yaml index 1064347edd..0cb17efb9c 100644 --- a/docs/core-data-structures/core.i18n.yaml +++ b/docs/core-data-structures/core.i18n.yaml @@ -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 -core.md: 9c6f1d88c67f60ea3c42ba2fcec07cb20ede4214 -core.zh.md: 2fee488e609166328b743e8ca035a9b207706f37 +core.md: 7d0f9503dfd4c47f185d2bcef84528145d66fa70 +core.zh.md: 4bc31681d96483a300cc7a0ccfb5e489ba34f691 diff --git a/docs/core-data-structures/core.md b/docs/core-data-structures/core.md index 9c6f1d88c6..7d0f9503df 100644 --- a/docs/core-data-structures/core.md +++ b/docs/core-data-structures/core.md @@ -165,6 +165,8 @@ Adapters emit a raw **chunk** protocol; the loop logs the chunks (replay fidelit The full union, the adapter contract (usage-before-finish, raw-JSON tool arguments, the two sanctioned error paths), and `BlockAssembler` live on **[llm-streaming.md](llm-streaming.md)**. + + ## The model request One model call is a fully-assembled `GenerateOptions`. The adapter answers with a raw `StreamChunk` stream; the consumer assembles it with `BlockAssembler` (see [llm-streaming.md](llm-streaming.md)). diff --git a/docs/core-data-structures/core.zh.md b/docs/core-data-structures/core.zh.md index 2fee488e60..4bc31681d9 100644 --- a/docs/core-data-structures/core.zh.md +++ b/docs/core-data-structures/core.zh.md @@ -26,9 +26,9 @@ harness 是一个微内核:一个极小的核心加上众多插件。大多数 | [persistence.md](persistence.md) | 持久性 seam:`SessionPersistence`、JSONL + SQLite 后端、`session/flush`、崩溃恢复、`SessionHeader` | | [session-query.md](session-query.md) | 逻辑记录、有界精确事件读取与关系追踪 | | [session-title.md](session-title.md) | 持久标题快照、来源 provenance 与异步提供方契约 | -| [system-prompt.md](system-prompt.md) | 逐次组装的上下文、工具提供方结果、prompt 段落与协作式组装 | +| [system-prompt.md](system-prompt.md) | 逐次组装的上下文、工具提供方结果、提示词段落与协作式组装 | | [tools.md](tools.md) | `ToolDefinition` 完整字段、schema DSL、`ToolExecution`/`ToolResult`、工具展示 UI 类型,以及受保护的执行流水线 | -| [user-interaction.md](user-interaction.md) | UI 支持的人工问答 seam:`AskUserQuestionRequest`、answer/options 词汇、provider API、错误分类体系 | +| [user-interaction.md](user-interaction.md) | UI 支持的人工问答 seam:`AskUserQuestionRequest`、answer/options 词汇、提供方 API、错误分类体系 | | [approval.md](approval.md) | 一次性用户审批 seam:`ApprovalRequest`、`ApprovalOutcome`、逐会话策略、审计与 answerer 契约 | | [bash.md](bash.md) | bash 执行器 seam:`BashExecRequest`/`Spec`、`BashRunResult`、后台 `BashProcess` 句柄 | | [pty.md](pty.md) | 持久化终端 ID、后端/会话契约、发送就绪状态、有界读取与 owner 可见快照 | @@ -39,11 +39,11 @@ harness 是一个微内核:一个极小的核心加上众多插件。大多数 | [skills.md](skills.md) | skill 服务:发现优先级、`SkillSummary`/`SkillDefinition`、会话前缀目录、面向模型的 `skill` 加载 | | [compaction.md](compaction.md) | 压缩(compaction)seam:`compact/*` 会话事件、`CompactionResult`、`CompactService` 接口 | | [subagent.md](subagent.md) | subagent seam:命名提供方注册表、`SubagentStartRequest`/`Result`/`Run`、启动时与运行时能力拆分 | -| [web.md](web.md) | Web 访问 seam:`WebSearchRequest`/`Result`、`WebFetchRequest`/`Result`、`WebFetchBody`、provider 可用性、`WebError` | +| [web.md](web.md) | Web 访问 seam:`WebSearchRequest`/`Result`、`WebFetchRequest`/`Result`、`WebFetchBody`、提供方可用性、`WebError` | | [spill.md](spill.md) | spill 存储 seam:`SaveTextSpill`、`SpillOwner`/`SpillSource`、`SpillRef`、品牌类型 `SpillLocator` | | [workflow.md](workflow.md) | 工作流 seam:`WorkflowStartRequest`、`WorkflowMeta`、`WorkflowRun`/`Result`、`workflow/*` 事件载荷、`WorkflowError` 致命性 | -> 这些页面上的类型声明及其 JSDoc 与源码等价,并由 `pnpm run verify-type-equiv` 检查漂移(见 [development.md](../development.md#documenting-types-verbatim-ts-type-equiv))。普通 block 保留完整声明;`public-api` block 保留去除实现体的公开 class 声明。Cordis 服务使用生成的[服务目录](../cordis-catalog/services.md)。 +> 这些页面上的类型声明及其 JSDoc 与源码等价,并由 `pnpm run verify-type-equiv` 检查漂移(见 [development.md](../development.md#documenting-types-verbatim-ts-type-equiv))。普通块保留完整声明;`public-api` 块保留去除实现体的公开 class 声明。Cordis 服务使用生成的[服务目录](../cordis-catalog/services.md)。 ## `…Map → derived-union` 模式 @@ -92,7 +92,9 @@ declare module '@deepseek-ai/dsh-llm' { type Branded = string & { readonly [BRAND]: B } ``` -两个核心 ID 是 `CallId`(关联工具调用及其结果;dsh-llm)和 `SessionId`(活跃 agent 与持久 session 共享的标识;dsh-session)。能力包也会品牌化各自的 id,例如 [tasks.md](tasks.md) 中的 `TaskId`。 +两个核心 ID 是 `CallId`(关联工具调用及其结果;dsh-llm)和 `SessionId`(活跃 agent 与持久会话共享的标识;dsh-session)。能力包也会品牌化各自的 id,例如 [tasks.md](tasks.md) 中的 `TaskId`。 + + ## 内容块与消息 @@ -115,7 +117,7 @@ interface ContentBlockMap { 各块接口(完整字段见源码):`TextBlock`(`text`)、`ReasoningBlock`(thinking,区别于可见文本)、`ToolCallBlock`(`id: CallId`、`name`、原始 JSON `arguments`)、`ToolResultBlock`(`toolCallId`、嵌套 `content: ContentBlock[]`、`isError?`)。`ContentBlock = ContentBlockMap[ContentBlockType]`。核心集仅限于每条交付路径都尊重的块——多模态内容(图像、音频等)没有核心块类型;需要的功能通过可合并扩展的 map 添加,同时提供适配器/UI/压缩支持。 -`Message` 由角色和 block 组成。由循环派生的 assistant 消息携带其持久 provider/model 标识,以及可选的适配器私有回放元数据: +`Message` 由角色和块组成。由循环派生的 assistant 消息携带其持久提供方/模型标识,以及可选的适配器私有回放元数据: ```ts type-equiv /** Provider ownership and adapter-private replay data for an assistant message. */ @@ -165,6 +167,8 @@ interface MessageSourceMap { 完整联合类型、适配器契约(usage-before-finish、原始 JSON 工具参数、两条认可的错误路径)和 `BlockAssembler` 在 **[llm-streaming.md](llm-streaming.md)** 中。 + + ## 模型请求 一次模型调用是一个完全组装好的 `GenerateOptions`。适配器以原始 `StreamChunk` 流作答;消费方用 `BlockAssembler` 组装它(见 [llm-streaming.md](llm-streaming.md))。 @@ -287,11 +291,11 @@ interface ToolSchema { ### 请求信封:`LlmCallConfig` 与记录的 header -循环从已记录状态构建每个请求。`EpochHeader` 通过完整的 `request/header` 快照记录调用配置、渲染后的 prompt、权威返回工具顺序(由 `toolOrder` 配置;未配置时按字典序)以及 session prefix。结合派生历史,请求便可由会话日志重建。见 [session.md](session.md#the-request-header-event-requestheader) 与[可重建性 Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.md)。 +循环从已记录状态构建每个请求。`EpochHeader` 通过完整的 `request/header` 快照记录调用配置、渲染后的提示词、权威返回工具顺序(由 `toolOrder` 配置;未配置时按字典序)以及会话前缀。结合派生历史,请求便可由会话日志重建。见 [session.md](session.md#the-request-header-event-requestheader) 与[可重建性 Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.md)。 `agent/request` 接收冻结的调用配置种子,并可返回替代值以切换提供方、模型或采样参数。`agent/session-prefix` 为每个循环实例组合一次仅用于请求的 prefix 消息,header 记录实际使用的确切结果。到达 `llm/stream` 的请求会被深度冻结,因此变更会抛异常;请求还携带进程本地循环标识,使观察者不会把单独记录的冻结辅助调用误认成对话请求。 -在协议格式上,循环构建的请求按此顺序读取:`system` 槽位(渲染后的 prompt 组装)→ `messagePrefix`(冻结的会话前缀)→ 派生历史——边界快照,其尾部在轮次首步是最新的 `user/message`,在后续步骤是上一步的工具结果。前缀从不进入派生历史;它的持久记录是 header 事件,开发不变式针对每个循环构建的请求精确重算此等式。 +在协议格式上,循环构建的请求按此顺序读取:`system` 槽位(渲染后的提示词组装)→ `messagePrefix`(冻结的会话前缀)→ 派生历史——边界快照,其尾部在轮次首步是最新的 `user/message`,在后续步骤是上一步的工具结果。前缀从不进入派生历史;它的持久记录是 header 事件,开发不变式针对每个循环构建的请求精确重算此等式。 FIXME(call-config-shape):重新审视此类型的精确定义——出于缓存目的,哪些字段确实属于 epoch 层级(`model` 肯定属于;采样标量目前出于谨慎放在这里),以及适配器需要时,提供方特有的额外项(推理选项、额外 body 参数)应归属何处。 @@ -353,11 +357,11 @@ type SessionEvent = { }[T] ``` -十四种事件变体(`turn/start`、`turn/end`、`step/start`、`step/end`、`user/message`、`prompt/blocked`、`context/message`、`assistant/chunk`、`assistant/message`、`tool/call`、`tool/result`、`steering/message`、`todo/write`、`request/header`)、`deriveMessages()` 投影规则、`TurnTrigger`/`TurnEndReason` 原因以及 turn enclosure 不变量都在 **[session.md](session.md)** 中。日志如何持久化——`SessionPersistence` seam、JSONL/SQLite 后端、`session/flush` checkpoint、崩溃恢复与 `SessionHeader`——则在 **[persistence.md](persistence.md)** 中。 +十四种事件变体(`turn/start`、`turn/end`、`step/start`、`step/end`、`user/message`、`prompt/blocked`、`context/message`、`assistant/chunk`、`assistant/message`、`tool/call`、`tool/result`、`steering/message`、`todo/write`、`request/header`)、`deriveMessages()` 投影规则、`TurnTrigger`/`TurnEndReason` 原因以及 turn enclosure 不变量都在 **[session.md](session.md)** 中。日志如何持久化——`SessionPersistence` seam、JSONL/SQLite 后端、`session/flush` 检查点、崩溃恢复与 `SessionHeader`——则在 **[persistence.md](persistence.md)** 中。 ## Agent 句柄 -`Agent` 是每个插件(UI、hook、orchestrator)面向编程的 surface。具体实现为 dsh-agent-loop 包内部细节;循环外没有任何组件依赖它。 +`Agent` 是每个插件(UI、钩子、orchestrator)面向编程的 surface。具体实现为 dsh-agent-loop 包内部细节;循环外没有任何组件依赖它。 源码:[`packages/core/agent/src/types.ts`](../../packages/core/agent/src/types.ts) @@ -450,11 +454,11 @@ interface Agent { } ``` -`AgentStatus` 为 `'idle' | 'running' | 'disposed'`,`SessionId` 是品牌类型。`running` 描述整个驱动器的排空区间,可能跨越 turn 关闭、其持久化 checkpoint 以及连续的排队 turn;它不能证明某个 turn 仍然打开。`AgentOptions` 可合并扩展:core 声明 `provider?` 与 `model?`(在 `agent/request` 后,分发要求两者都存在)。Persona 归 `dsh-system-prompt` 所有:agent 作用域的 `deployment:persona` 可以遮蔽全局默认值。 +`AgentStatus` 为 `'idle' | 'running' | 'disposed'`,`SessionId` 是品牌类型。`running` 描述整个驱动器的排空区间,可能跨越 turn 关闭、其持久化检查点以及连续的排队 turn;它不能证明某个 turn 仍然打开。`AgentOptions` 可合并扩展:core 声明 `provider?` 与 `model?`(在 `agent/request` 后,分发要求两者都存在)。Persona 归 `dsh-system-prompt` 所有:agent 作用域的 `deployment:persona` 可以遮蔽全局默认值。 cause 是由 TypeScript 强制约束的同进程输入。活跃持有者会把其判别字段复制到仅运行时的 `AbortSignal.reason`;该值在发布 `turn/end` 前退役。`agentInterruptReasonOf(signal)` 无需查询环境中的 initiator 状态,即可识别 `user`、`parent` 与仅用于生命周期的 `disposed`。持久 `turn/end` 保留粗粒度 `{ kind: 'aborted' }` 结果;若需记录请求 provenance,应使用单独的持久事件,而不是让终态结果承担额外含义。 -[事件分类](../architecture.md#event)拥有 `agent/*` 生命周期、checkpoint 与 waterfall 契约。Turn 和 step 边界是持久 session 事件,而不是 agent emit。 +[事件分类](../architecture.md#event)拥有 `agent/*` 生命周期、检查点与 waterfall 契约。Turn 和 step 边界是持久会话事件,而不是 agent emit。 ## 发起 Agent @@ -462,7 +466,7 @@ cause 是由 TypeScript 强制约束的同进程输入。活跃持有者会把 ## 拦截决策 -每个 `agent/*` 拦截 waterfall 都返回一个小型、特定于 seam 的类型化联合——统一的 Decision 惯用形状([tools.md](tools.md) 中工具 seam 的 `PreToolDecision`/`PostToolDecision` 也采用相同形状)。CC/Codex hook bridge 把其 `permissionDecision`/`decision`/`continue`/`additionalContext` 字段映射到这些联合上;原生插件则直接返回它们。Prompt 与工具后决策共享一种面向模型的 context 形状 `HookContext`,它必须携带 `source`(缺少 source 会默认成 `{kind:'user'}`,从而把插件 context 错标为用户 prompt)。其中的 `content` 作为 user-role 输入逐字到达模型,而 JSON `meta` 持久保存插件状态但不向模型暴露。未指定放置方式或指定为 `separate` 时,context 会成为 `context/message`;`prompt-prefix` 放置方式可用于 prompt 和 steering 收件箱附件,会在同一条消息中把 context 置于最终生效的请求之前。两种决策都携带 `additionalContexts[]`,使每一项保留各自的 provenance、元数据与放置方式。Continuation reason 则是 steering 消息,并有意使用更窄的 content/source 形状。 +每个 `agent/*` 拦截 waterfall 都返回一个小型、特定于 seam 的类型化联合——统一的 Decision 惯用形状([tools.md](tools.md) 中工具 seam 的 `PreToolDecision`/`PostToolDecision` 也采用相同形状)。CC/Codex 钩子桥接层把其 `permissionDecision`/`decision`/`continue`/`additionalContext` 字段映射到这些联合上;原生插件则直接返回它们。提示词决策与工具后决策共享一种面向模型的上下文形状 `HookContext`,它必须携带 `source`(缺少 source 会默认成 `{kind:'user'}`,从而把插件上下文错标为用户提示词)。其中的 `content` 作为 user-role 输入逐字到达模型,而 JSON `meta` 持久保存插件状态但不向模型暴露。未指定放置方式或指定为 `separate` 时,上下文会成为 `context/message`;`prompt-prefix` 放置方式可用于提示词和 steering 收件箱附件,会在同一条消息中把上下文置于最终生效的请求之前。两种决策都携带 `additionalContexts[]`,使每一项保留各自的 provenance、元数据与放置方式。Continuation reason 则是 steering 消息,并有意使用更窄的 content/source 形状。 源码:[`packages/core/agent/src/types.ts`](../../packages/core/agent/src/types.ts) @@ -499,7 +503,7 @@ type PromptDecision = | { kind: 'block'; reason: string } ``` -`agent/turn-continuation` 返回 `ContinuationDecision`(step 有工具调用或注入了 steering 时,循环默认为 `continue`,否则为 `stop`;`continue` 的 `reason` 会记录为同一 turn 中下一 step 的 steering,因此不携带 context 元数据——即类型化 `/goal` 模式): +`agent/turn-continuation` 返回 `ContinuationDecision`(step 有工具调用或注入了 steering 时,循环默认为 `continue`,否则为 `stop`;`continue` 的 `reason` 会记录为同一 turn 中下一 step 的 steering,因此不携带上下文元数据——即类型化 `/goal` 模式): ```ts type-equiv /** Turn continuation override; a continue reason is recorded as next-step steering in the same turn. */ @@ -522,7 +526,7 @@ type RequestError = Error & { code?: string } type RequestErrorDecision = { action: 'fail' } | { action: 'retry' } ``` -`agent/post-step` 会在 assistant 输出、真实或合成的工具结果、缓冲 context 与 steering 持久化之后、`step/end` 之前被 await。被取消的工具批次在排空后携带 aborted signal 到达这里;其签名为 `(agent, turn, step, signal)`,可回放事实保留在 session 日志中,而不是瞬态 payload 中。 +`agent/post-step` 会在 assistant 输出、真实或合成的工具结果、缓冲上下文与 steering 持久化之后、`step/end` 之前被 await。被取消的工具批次在排空后携带 aborted signal 到达这里;其签名为 `(agent, turn, step, signal)`,可回放事实保留在会话日志中,而不是瞬态 payload 中。 `agent/turn-stop` 返回仅停止的 `ContinuationStop` 子集或 `undefined`。循环在折叠普通决策、其 reason 和待处理 steering 之后调用此串行检查点;stop 是终态,会丢弃待处理的 steering。 diff --git a/docs/core-data-structures/filesystem.i18n.yaml b/docs/core-data-structures/filesystem.i18n.yaml index 69cb43d21d..4f17d4c4ed 100644 --- a/docs/core-data-structures/filesystem.i18n.yaml +++ b/docs/core-data-structures/filesystem.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write filesystem.md: 3c9b041da92e71cd20429e8b1549c0b8e6f2436d -filesystem.zh.md: 11e386c98e671f4147419eec587399a5a3bb0d07 +filesystem.zh.md: 04d7c63da151f7198099486106ce2fb9d0dd1520 diff --git a/docs/core-data-structures/filesystem.zh.md b/docs/core-data-structures/filesystem.zh.md index 11e386c98e..04d7c63da1 100644 --- a/docs/core-data-structures/filesystem.zh.md +++ b/docs/core-data-structures/filesystem.zh.md @@ -177,13 +177,13 @@ interface FsEditOutcome { ## fs 策略事件(提供方 seam 词汇) -`dsh-fs` 拥有三个事件,由工具分发、策略插件监听,使发射方(`dsh-tool-fs`)与监听方(`dsh-fs-policy`)共享词汇,而发射方无需依赖策略插件。它们只携带 `dsh-fs` 词汇加一个不透明的 `object` actor,不含面向模型的概念,也不含 agent/session 所有者结构。 +`dsh-fs` 拥有三个事件,由工具分发、策略插件监听,使发射方(`dsh-tool-fs`)与监听方(`dsh-fs-policy`)共享词汇,而发射方无需依赖策略插件。它们只携带 `dsh-fs` 词汇加一个不透明的 `object` actor,不含面向模型的概念,也不含 agent/会话所有者结构。 `fs/write-intent` 与 `fs/edit-intent` 是**单槽决策 waterfall**:工具分发时附带一个默认 thunk(返回 `undefined`,即裸提供方),监听方完全决策而不调用 `next()`。该槽按注册顺序先到先得——由策略插件占据是部署约定,而非强制不变式。`fs/observed` 是一个即发即弃的记录事件,通过普通 `ctx.emit` 分发;其监听方必须是同步的、仅产生副作用,因为工具不守卫该 emit——抛异常的监听方会在一次已成功的变更上表现为工具的 `isError` 结果。生成的目录在 [events.md](../cordis-catalog/events.md) 中展示确切签名。 ## 执行上下文(策略插件) -策略插件只需要足够的执行上下文,通过收窄 `fs/*` 事件携带的不透明 `object` actor 来推导观测状态的所有者。`ToolExecution` 满足此形状,因此 `dsh-tool-fs` 将其执行对象作为 actor 直接传递,而无需让 `dsh-fs-policy` 导入 tool、agent 或 session 包。 +策略插件只需要足够的执行上下文,通过收窄 `fs/*` 事件携带的不透明 `object` actor 来推导观测状态的所有者。`ToolExecution` 满足此形状,因此 `dsh-tool-fs` 将其执行对象作为 actor 直接传递,而无需让 `dsh-fs-policy` 导入工具、agent 或会话包。 ```ts type-equiv /** @@ -252,7 +252,7 @@ type FsErrorCode = | 'FS_ABORTED' ``` -目录列表使用 `FS_NOT_DIRECTORY`、`FS_PERMISSION_DENIED` 与 `FS_IO_ERROR` 区分已存在但并非目录的目标、被拒绝的列表操作和意外的后端 I/O 失败。`FS_SANDBOX_DENIED` 是强制执行 sandbox 的后端(`dsh-fs-sandbox`)所作的策略拒绝——模式边界拒绝了写入/编辑——与 `FS_PERMISSION_DENIED`(宿主内核拒绝)不同。`FS_NOT_OBSERVED` 表示策略插件没有此所有者的先前观察记录(或 `createIfAbsent` 遇到了现有文件)。`FS_STALE_VERSION` 表示后端版本不再与观察到的版本匹配(或编辑操作遇到缺失目标)。新鲜度授权没有部分/完整之分,因此不存在 `FS_PARTIAL_OBSERVATION`。 +目录列表使用 `FS_NOT_DIRECTORY`、`FS_PERMISSION_DENIED` 与 `FS_IO_ERROR` 区分已存在但并非目录的目标、被拒绝的列表操作和意外的后端 I/O 失败。`FS_SANDBOX_DENIED` 是强制执行沙箱的后端(`dsh-fs-sandbox`)所作的策略拒绝——模式边界拒绝了写入/编辑——与 `FS_PERMISSION_DENIED`(宿主内核拒绝)不同。`FS_NOT_OBSERVED` 表示策略插件没有此所有者的先前观察记录(或 `createIfAbsent` 遇到了现有文件)。`FS_STALE_VERSION` 表示后端版本不再与观察到的版本匹配(或编辑操作遇到缺失目标)。新鲜度授权没有部分/完整之分,因此不存在 `FS_PARTIAL_OBSERVATION`。 ## 服务与插件 diff --git a/docs/core-data-structures/llm-streaming.i18n.yaml b/docs/core-data-structures/llm-streaming.i18n.yaml index 22691c44f4..d22cd0c4a3 100644 --- a/docs/core-data-structures/llm-streaming.i18n.yaml +++ b/docs/core-data-structures/llm-streaming.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write llm-streaming.md: cb99c935aea2dc9cc769e3056fdb98a2e5c9eacb -llm-streaming.zh.md: 5dc270acc97cdeac8cf24a36c443d550e14122dc +llm-streaming.zh.md: 36fb640a030645861a163f6b33b3c0b60cf5ed8e diff --git a/docs/core-data-structures/llm-streaming.zh.md b/docs/core-data-structures/llm-streaming.zh.md index 5dc270acc9..36fb640a03 100644 --- a/docs/core-data-structures/llm-streaming.zh.md +++ b/docs/core-data-structures/llm-streaming.zh.md @@ -35,7 +35,7 @@ type StreamChunk = ## `LlmFailure` -每个抛出的失败或 final-adapter 带内失败都会规范化为一种可序列化、提供方中立的 payload。`providerRetryAfterMs` 是经校验、由提供方请求的正数延迟,而不是重试决策;`ProviderRequestId` 是用于诊断的不透明品牌字符串。 +每个抛出的失败或最终适配器的带内失败都会规范化为一种可序列化、提供方中立的 payload。`providerRetryAfterMs` 是经校验、由提供方请求的正数延迟,而不是重试决策;`ProviderRequestId` 是用于诊断的不透明品牌字符串。 ```ts type-equiv /** Serializable provider-boundary facts; policy decides whether they are retryable. */ @@ -59,18 +59,18 @@ interface LlmFailure { - **`usage` 在 `finish` 之前,`finish` 之后不再有任何分片。** 将两者都推迟到提供方的流结束标记,这样尾部的 usage-only 分片就不会违反顺序。 - **工具调用的 `arguments` 全程保持原始 JSON 字符串。** 部分片段通过 `argumentsDelta` 流式传输;如果提供方返回的是已解析的对象,适配器在 `block-end` 时重新序列化为字符串。 -- **两条受支持的错误路径,一种事实形状。** 失败可以从 `stream()` 抛出(传输/协议错误),**或者**以 `finish {kind:'error'|'aborted', failure}` 结束流(无法在流中途抛异常的适配器用它表示提供方带内错误)。`LlmError.failure` 携带同一个 `LlmFailure`。final adapter 边界保留被抛出的确切 `Error` 对象,并将不可变事实关联到该调用;agent loop 关闭失败的 step,再把错误、事实与不可变的先前已重试事实提供给 `agent/request-error`。若未恢复,结构化失败会成为 turn 错误,并且该次尝试不会提交正常 assistant 消息或工具副作用。 +- **两条受支持的错误路径,一种事实形状。** 失败可以从 `stream()` 抛出(传输/协议错误),**或者**以 `finish {kind:'error'|'aborted', failure}` 结束流(无法在流中途抛异常的适配器用它表示提供方带内错误)。`LlmError.failure` 携带同一个 `LlmFailure`。最终适配器边界保留被抛出的确切 `Error` 对象,并将不可变事实关联到该调用;agent loop 关闭失败的 step,再把错误、事实与不可变的先前已重试事实提供给 `agent/request-error`。若未恢复,结构化失败会成为 turn 错误,并且该次尝试不会提交正常 assistant 消息或工具副作用。 - **一次适配器调用就是一次提供方尝试。** 适配器禁用库重试。agent 层恢复会打开另一个持久、带编号的 step;直接调用 `ctx.llm.stream()` 的调用方仍然只尝试一次。 - **提供方停顿在传输层受到时限约束。** 两个已交付的远程适配器都暴露正数且有限的 `streamIdleTimeoutMs`,默认五分钟。watchdog 只在 iterator `next()` 尚未完成时启动,整个请求使用同一个稳定 signal,把自身到期映射为 `TIMEOUT`,并把更早发生的调用方中止保留为 `ABORTED`。 - **上下文溢出只有一个规范 code。** 两个 DeepSeek 适配器都通过 `isContextWindowExceededError()` 对提供方的显式细节分类并暴露 `CONTEXT_WINDOW_EXCEEDED`,无论失败以抛出的 HTTP `LlmError` 还是带内 finish error 到达。消费方按 code 路由,绝不依赖提供方文本。 - **每个提供方 HTTP 请求都携带应用归属头。** 适配器发送 `attributionHeaders()`(见下文)作为 `User-Agent` 基线,并通过协议级测试加以证明(mock 服务器断言收到的 header,或对基于库的适配器使用库的 header 钩子)。 - **回放状态归适配器所有。** 成功的 `finish` 可以携带重建提供方原生响应所需的无损 JSON 状态。除非 `agent/step-result` listener 改写了内容,否则循环会将其与组装后的 assistant 消息一起存储。后续请求中,仅当历史提供方与目标提供方当前注册到完全相同的适配器实例时,`LlmService` 才会传递该状态。该适配器负责校验状态并拥有所有跨模型或跨提供方转换;其他适配器只会收到提供方中立的内容与 provenance,不会收到私有状态。 -该契约由两个有意保持独立的实现锁定:`dsh-llm-deepseek`(手写 fetch/SSE)和 `dsh-llm-pi-ai`(通过 `@earendil-works/pi-ai` 实现的通用多提供方适配器)。基于库的适配器覆盖 finish-chunk 错误路径,而传输边界测试证明每个空闲 watchdog 都会停止其实际请求。 +该契约由两个有意保持独立的实现锁定:`dsh-llm-deepseek`(手写 fetch/SSE)和 `dsh-llm-pi-ai`(通过 `@earendil-works/pi-ai` 实现的通用多提供方适配器)。基于库的适配器覆盖 finish 分片错误路径,而传输边界测试证明每个空闲 watchdog 都会停止其实际请求。 ## `AppIdentity`:应用归属 -每个适配器都会向提供方发送的静态公开应用标识([`packages/llm/llm/src/attribution.ts`](../../packages/llm/llm/src/attribution.ts))。`attributionHeaders(identity?)` 只把它映射到标准 `User-Agent` header;该契约有意不支持 OpenRouter 特有的应用归属 header。默认 `APP_IDENTITY` 从包 manifest 获取版本;每个字段都是公开产品事实——不含 secret、路径、session id 或逐用户标识,且任何逐请求信息都不得影响这些值。设计理由见[强制 `User-Agent` 归属](../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 +每个适配器都会向提供方发送的静态公开应用标识([`packages/llm/llm/src/attribution.ts`](../../packages/llm/llm/src/attribution.ts))。`attributionHeaders(identity?)` 只把它映射到标准 `User-Agent` header;该契约有意不支持 OpenRouter 特有的应用归属 header。默认 `APP_IDENTITY` 从包 manifest 获取版本;每个字段都是公开产品事实——不含 secret、路径、会话 id 或逐用户标识,且任何逐请求信息都不得影响这些值。设计理由见[强制 `User-Agent` 归属](../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 ```ts type-equiv /** @@ -92,7 +92,7 @@ interface AppIdentity { ## `TokenUsage` -逐调用 token 记账。各计数**互不重叠**:`inputTokens` 只包含未缓存输入;缓存输入单独报告,计费输入是三者之和。若提供方把缓存命中折入单一 prompt 总数(如 DeepSeek 的 `prompt_tokens`),适配器会再将其扣除。`reasoningTokens` 存在时只是信息性细节,已经包含在 `outputTokens` 中;汇总时不得重复相加。 +逐调用 token 记账。各计数**互不重叠**:`inputTokens` 只包含未缓存输入;缓存输入单独报告,计费输入是三者之和。若提供方把缓存命中折入单一提示词总数(如 DeepSeek 的 `prompt_tokens`),适配器会再将其扣除。`reasoningTokens` 存在时只是信息性细节,已经包含在 `outputTokens` 中;汇总时不得重复相加。 ```ts type-equiv /** @@ -114,7 +114,7 @@ interface TokenUsage { ## `BlockAssembler` -`BlockAssembler`([`packages/llm/llm/src/assembler.ts`](../../packages/llm/llm/src/assembler.ts))是唯一的共享实现,负责把 `StreamChunk` 流折叠回 `ContentBlock`、usage、finish reason 与 replay state。循环在记录原始 chunk 的同时,把同一批 chunk 送入 assembler,再将组装后的 assistant 内容连同其 provider/model provenance 一起存储。需要组装结果、又不想重新实现 fold 的消费方使用它。 +`BlockAssembler`([`packages/llm/llm/src/assembler.ts`](../../packages/llm/llm/src/assembler.ts))是唯一的共享实现,负责把 `StreamChunk` 流折叠回 `ContentBlock`、usage、结束原因与回放状态。循环在记录原始分片的同时,把同一批分片送入 assembler,再将组装后的 assistant 内容连同其提供方/模型 provenance 一起存储。需要组装结果、又不想重新实现 fold 的消费方使用它。 ```ts public-api /** @@ -156,7 +156,7 @@ declare class BlockAssembler { ## seam -`LlmAdapter` 是提供方 seam:创建子类、实现 `stream()`,再用 `ctx.llm.registerAdapter(providers, adapter)` 注册一个适配器实例。`GenerateOptions.provider` 选择已注册适配器;`GenerateOptions.model` 会传给该适配器,无需在生命周期启动时注册。重复提供方路由会原子失败。可选的 `providerInfo()` 与异步 `listModels()` 方法为 `LlmService.listProviders()` / `listModels()` 提供分离的 selector 元数据。该目录仅供参考,不是请求白名单:适配器仍是权威,并可接受未列出的模型 id。单独的 `resolveModelContext()` 查询会暴露确切路由上对正确性敏感的容量信息,但不会让目录成员关系具有权威性;缺失表示元数据未知,而不是路由无效。适配器查找发生在 `llm/stream` waterfall 的终端 continuation,因此 listener 可以在查找前短路调用,或路由一个可变的一次性请求。`block-start` / `block-end` 的 `index` 关联与 assembler 共同意味着适配器只需 emit 格式正确的 chunk——block 重组不是每个适配器各自的问题。消费方 surface(`ctx.llm.stream()`)与 `llm/stream` waterfall 见 [architecture.md § 内容 block 与流式传输](../architecture.md#content-blocks-and-streaming-dsh-llm)。 +`LlmAdapter` 是提供方 seam:创建子类、实现 `stream()`,再用 `ctx.llm.registerAdapter(providers, adapter)` 注册一个适配器实例。`GenerateOptions.provider` 选择已注册适配器;`GenerateOptions.model` 会传给该适配器,无需在生命周期启动时注册。重复提供方路由会原子失败。可选的 `providerInfo()` 与异步 `listModels()` 方法为 `LlmService.listProviders()` / `listModels()` 提供分离的 selector 元数据。该目录仅供参考,不是请求白名单:适配器仍是权威,并可接受未列出的模型 id。单独的 `resolveModelContext()` 查询会暴露确切路由上对正确性敏感的容量信息,但不会让目录成员关系具有权威性;缺失表示元数据未知,而不是路由无效。适配器查找发生在 `llm/stream` waterfall 的终端 continuation,因此 listener 可以在查找前短路调用,或路由一个可变的一次性请求。`block-start` / `block-end` 的 `index` 关联与 assembler 共同意味着适配器只需 emit 格式正确的分片——块重组不是每个适配器各自的问题。消费方 surface(`ctx.llm.stream()`)与 `llm/stream` waterfall 见 [architecture.md § 内容块与流式传输](../architecture.md#content-blocks-and-streaming-dsh-llm)。 ```ts public-api /** diff --git a/docs/core-data-structures/persistence.i18n.yaml b/docs/core-data-structures/persistence.i18n.yaml index d8baef895b..76ccae0b33 100644 --- a/docs/core-data-structures/persistence.i18n.yaml +++ b/docs/core-data-structures/persistence.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write persistence.md: d4bb4ed1b65eb74ff03483bf3a71a1736300834e -persistence.zh.md: 93a418b3b06dbf0d42978900ef79a0fb86ac15f7 +persistence.zh.md: ea0bff84bb939f0eab370375509e920ea45eb404 diff --git a/docs/core-data-structures/persistence.zh.md b/docs/core-data-structures/persistence.zh.md index 93a418b3b0..ea0bff84bb 100644 --- a/docs/core-data-structures/persistence.zh.md +++ b/docs/core-data-structures/persistence.zh.md @@ -8,7 +8,7 @@ ## flush 检查点 -`session/event` 是一个*同步*通知;持久化插件会将其缓冲(write-behind)至 `session/flush`。循环会 await 普通 turn 的 checkpoint 后再领取下一个队列项;同步的 idle `inject()` 会调度自己的 checkpoint 而不阻塞 `send()`,dispose 仍会将其排空。成功 flush 会把已关闭 turn 作为一个单元持久提交;被拒绝的 flush 通过 `agent/error` 与 logger 报告——绝不会作为已关闭 turn 之后的 session 事件——而后端会保留已缓冲事件供下次 flush 使用。 +`session/event` 是一个*同步*通知;持久化插件会将其缓冲(write-behind)至 `session/flush`。循环会 await 普通 turn 的检查点后再领取下一个队列项;同步的 idle `inject()` 会调度自己的检查点而不阻塞 `send()`,dispose 仍会将其排空。成功 flush 会把已关闭 turn 作为一个单元持久提交;被拒绝的 flush 通过 `agent/error` 与 logger 报告——绝不会作为已关闭 turn 之后的会话事件——而后端会保留已缓冲事件供下次 flush 使用。 ## 崩溃恢复保留被中断的轮次 @@ -16,7 +16,7 @@ ## `SessionLocation`——可选的逐会话制品目标 -`SessionPersistence.locate(meta)` 会同步解析一个归后端所有的独立制品,而不会读取、创建或 flush 它。JSONL 返回其绝对目标路径;SQLite 因各 session 共享一个数据库而返回 `undefined`。因此,返回的路径可能指向尚不存在、或还不包含当前未 flush turn 的文件;它是位置提示,不是授权或新鲜度保证。 +`SessionPersistence.locate(meta)` 会同步解析一个归后端所有的独立制品,而不会读取、创建或 flush 它。JSONL 返回其绝对目标路径;SQLite 因各会话共享一个数据库而返回 `undefined`。因此,返回的路径可能指向尚不存在、或还不包含当前未 flush turn 的文件;它是位置提示,不是授权或新鲜度保证。 ```ts type-equiv /** @@ -73,7 +73,7 @@ interface SessionHeader { ## `CreateSessionOptions`:seed 与元数据 -通过 store 创建 `Session` 时会接收 `seed`(回放/fork 现有事件日志)与 `meta`(store 折叠进 `SessionHeader` 的存储层字段)。store 填充 `version`/`id` 并为 `createdAt` 提供默认值;调用方提供已校验的绝对 `cwd`、`parentSession` 谱系、`seedLength` 种子边界、`delegationDepth`,以及——仅在重建已持久化 session 时——需要保留的原始 `createdAt`。 +通过 store 创建 `Session` 时会接收 `seed`(回放/fork 现有事件日志)与 `meta`(store 折叠进 `SessionHeader` 的存储层字段)。store 填充 `version`/`id` 并为 `createdAt` 提供默认值;调用方提供已校验的绝对 `cwd`、`parentSession` 谱系、`seedLength` 种子边界、`delegationDepth`,以及——仅在重建已持久化会话时——需要保留的原始 `createdAt`。 ```ts type-equiv /** @@ -104,7 +104,7 @@ interface CreateSessionOptions { 两者都实现同一个抽象 `SessionPersistence`(在 `SessionEvent` 上执行 locate/create/append/load/list),并通过 `runPersistenceContract`,证明该 seam 确实与后端无关: -- **[dsh-session-persistence-jsonl](../../packages/session-persistence/session-persistence-jsonl)**——每个 session 一份仅追加的逻辑 JSONL 日志,默认存储为带 checksum 的连续 Zstandard frame,也可配置为原始行;支持崩溃安全的原子写入、中断 turn 恢复以及读取/回放路径。 +- **[dsh-session-persistence-jsonl](../../packages/session-persistence/session-persistence-jsonl)**——每个会话一份仅追加的逻辑 JSONL 日志,默认存储为带 checksum 的连续 Zstandard frame,也可配置为原始行;支持崩溃安全的原子写入、中断 turn 恢复以及读取/回放路径。 - **[dsh-session-persistence-sqlite](../../packages/session-persistence/session-persistence-sqlite)**:基于 `node:sqlite`,每个 `SessionEvent` 一行。行结构 `(session_id, seq, type, time, data, source_event_seqs, surface_op)` 与事件 1:1 映射(包含可选的 surface 元数据),因此没有需要保持同步的并行持久化 schema。 -共享同一磁盘 session 的多个后端通过[共享持久化写入协调器](../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)协调写入。 +共享同一磁盘会话的多个后端通过[共享持久化写入协调器](../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)协调写入。 diff --git a/docs/core-data-structures/sandbox.i18n.yaml b/docs/core-data-structures/sandbox.i18n.yaml index 1bd49e2273..675b9bfa10 100644 --- a/docs/core-data-structures/sandbox.i18n.yaml +++ b/docs/core-data-structures/sandbox.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write sandbox.md: 9bc05fa06f22fdc9ac9e8aacd482c1e7c2f2edec -sandbox.zh.md: dd02041dea998221f1fa7549cb829791137b5088 +sandbox.zh.md: 8db5520a125141cd043323ded4d26b92b81d1ea0 diff --git a/docs/core-data-structures/sandbox.zh.md b/docs/core-data-structures/sandbox.zh.md index dd02041dea..8db5520a12 100644 --- a/docs/core-data-structures/sandbox.zh.md +++ b/docs/core-data-structures/sandbox.zh.md @@ -40,7 +40,7 @@ type SandboxEnforcement = 'full' | 'partial' ## 逐调用策略 -完整执行策略会按每次能力调用解析并携带。它包括 `danger-full-access`,因此消费方可以只解析一次策略,再决定是否绕过约束。普通工具调用从调用 session 的不可变 cwd 派生 `workspaceRoot`;部署配置是没有 agent 时的回退值。root 会先按文件系统语义规范化,再做词法规范化,因此包含 `symlink/..` 的 cwd 会标识所生成进程实际运行的目录。 +完整执行策略会按每次能力调用解析并携带。它包括 `danger-full-access`,因此消费方可以只解析一次策略,再决定是否绕过约束。普通工具调用从调用会话的不可变 cwd 派生 `workspaceRoot`;部署配置是没有 agent 时的回退值。root 会先按文件系统语义规范化,再做词法规范化,因此包含 `symlink/..` 的 cwd 会标识所生成进程实际运行的目录。 ```ts type-equiv /** @@ -56,7 +56,7 @@ interface SandboxExecutionPolicy { } ``` -`ctx.sandboxPolicy.resolve()` 接收活跃 session;对于已批准的重试,还接收显式模式。该服务拥有优先级与 root 回退规则,使 bash 和 fs 不必重复实现。 +`ctx.sandboxPolicy.resolve()` 接收活跃会话;对于已批准的重试,还接收显式模式。该服务拥有优先级与 root 回退规则,使 bash 和 fs 不必重复实现。 ```ts type-equiv /** Inputs that select the sandbox policy for one capability call. */ @@ -68,7 +68,7 @@ interface SandboxPolicyRequest { } ``` -只有受约束的执行会到达 `ctx.sandbox`;其提供方策略在保留同一 root 的同时收窄模式。这使并发 session、消费方与一次性提权重试可以向同一提供方请求不同边界,而无需改变提供方状态。 +只有受约束的执行会到达 `ctx.sandbox`;其提供方策略在保留同一 root 的同时收窄模式。这使并发会话、消费方与一次性提权重试可以向同一提供方请求不同边界,而无需改变提供方状态。 ```ts type-equiv /** diff --git a/docs/core-data-structures/scope.i18n.yaml b/docs/core-data-structures/scope.i18n.yaml index 4067956fe6..488c1f88f1 100644 --- a/docs/core-data-structures/scope.i18n.yaml +++ b/docs/core-data-structures/scope.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write scope.md: 73a697f2843293daffff85dabf4656346f7dcd04 -scope.zh.md: b5cc21cfb3d3dbb3890d179f9a813dccb1c318ec +scope.zh.md: 5a40a3e964d2113752efba92beea4f4f333e94b3 diff --git a/docs/core-data-structures/scope.zh.md b/docs/core-data-structures/scope.zh.md index b5cc21cfb3..5a40a3e964 100644 --- a/docs/core-data-structures/scope.zh.md +++ b/docs/core-data-structures/scope.zh.md @@ -2,7 +2,7 @@ [English](scope.md) | 中文 -[scope 包](../../packages/core/scope)提供 identity、carrier 与 scoped-layer 词汇,使同一个注册 context 同时代表逐 agent 可见性和共享生命周期所有权。它是库原语,而不是 Cordis 服务;生命周期设计理由由 [agent-scope 运行时设计 Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#scope-routing-one-opaque-key-selects-one-layer)规定,registry-layer 决策由[共享存储 Agent Note](../../.agents/notes/implemented/architecture/2026-07-12-scoped-layers-store.md)规定,可调用 API 与过滤语义则由包 [README](../../packages/core/scope/README.md)规定。 +[scope 包](../../packages/core/scope)提供 identity、carrier 与 scoped-layer 词汇,使同一个注册上下文同时代表逐 agent 可见性和共享生命周期所有权。它是库原语,而不是 Cordis 服务;生命周期设计理由由 [agent-scope 运行时设计 Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#scope-routing-one-opaque-key-selects-one-layer)规定,注册表层决策由[共享存储 Agent Note](../../.agents/notes/implemented/architecture/2026-07-12-scoped-layers-store.md)规定,可调用 API 与过滤语义则由包 [README](../../packages/core/scope/README.md)规定。 源码:[`packages/core/scope/src/index.ts`](../../packages/core/scope/src/index.ts) 与 [`packages/core/scope/src/store.ts`](../../packages/core/scope/src/store.ts)。 @@ -54,6 +54,6 @@ interface ScopeLayer { } ``` -`ScopedLayers` 拥有立即创建的全局 layer,以及惰性创建的确切作用域 layer。读取不会创建 layer:`peek(undefined)` 表示没有 overlay,而 `merge()` 会物化按插入顺序排列的全局具名 entry,随后是带作用域的 shadow。注册使用同一个 context 表示可见性与 Cordis effect 所有权,在可选通知前收集一个同步 undo,返回 Cordis 的确切 disposer,并且只在带作用域 layer 的完整 `ScopeLayer` 为空时回收它。 +`ScopedLayers` 拥有立即创建的全局 layer,以及惰性创建的确切作用域 layer。读取不会创建 layer:`peek(undefined)` 表示没有 overlay,而 `merge()` 会物化按插入顺序排列的全局具名 entry,随后是带作用域的 shadow。注册使用同一个上下文表示可见性与 Cordis effect 所有权,在可选通知前收集一个同步 undo,返回 Cordis 的确切 disposer,并且只在带作用域 layer 的完整 `ScopeLayer` 为空时回收它。 `NamedEntries` 提供按插入顺序的查找与 live iteration,重复错误由调用方所有。`AnonymousEntries` 为每次 append 分配唯一标识,使相等的值仍相互独立。迭代在同一非空 table generation 内保持 live;排空 table 会让现有 iterator 与后续插入脱离。两者都返回幂等的确切 entry undo;共享的 `EntryValues` 实现接口不公开。 diff --git a/docs/core-data-structures/session-query.i18n.yaml b/docs/core-data-structures/session-query.i18n.yaml index f2f1de97ce..7efa74ce1b 100644 --- a/docs/core-data-structures/session-query.i18n.yaml +++ b/docs/core-data-structures/session-query.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write session-query.md: 27d0dccc6cf32b4dafebeaf64a3b8aefa138b98d -session-query.zh.md: 3b6d30916e7cc012859b86419fd326fadf02f571 +session-query.zh.md: 1c3abafb009cfc7376c96da4552b49959c09fef3 diff --git a/docs/core-data-structures/session-query.zh.md b/docs/core-data-structures/session-query.zh.md index 3b6d30916e..1c3abafb00 100644 --- a/docs/core-data-structures/session-query.zh.md +++ b/docs/core-data-structures/session-query.zh.md @@ -1,8 +1,8 @@ -# Session Query +# 会话查询 [English](session-query.md) | 中文 -对优先使用 live 数据的逻辑 session 集合执行精确读取与关系追踪。[包契约](../../packages/session-query/session-query)拥有来源优先级、动态可选持久化、克隆、surface 分类、有界窗口、追踪校验与类型化失败。全文搜索属于另一个拟议的 SQLite 包。 +对优先使用 live 数据的逻辑会话集合执行精确读取与关系追踪。[包契约](../../packages/session-query/session-query)拥有来源优先级、动态可选持久化、克隆、surface 分类、有界窗口、追踪校验与类型化失败。全文搜索属于另一个拟议的 SQLite 包。 源码:[`packages/session-query/session-query/src/types.ts`](../../packages/session-query/session-query/src/types.ts) @@ -57,7 +57,7 @@ interface SessionEventRecord { } ``` -## Session 谱系 +## 会话谱系 `SessionLineageTrace` 按由近及远的顺序携带已知 parent,并携带一片由直接 descendant 递归嵌套而成的森林。完整性判别字段使已知 root 与缺失 parent 互斥。 diff --git a/docs/core-data-structures/session.i18n.yaml b/docs/core-data-structures/session.i18n.yaml index d723c337ca..09662ed32a 100644 --- a/docs/core-data-structures/session.i18n.yaml +++ b/docs/core-data-structures/session.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write session.md: e07e38037e51c74886db88d24353266f6035b15a -session.zh.md: 2125f5ac97d3649aab166927b1607d54888fa9f1 +session.zh.md: 82ddaa2f53585f41fd9a343c9f710b339b2399fd diff --git a/docs/core-data-structures/session.zh.md b/docs/core-data-structures/session.zh.md index 2125f5ac97..82ddaa2f53 100644 --- a/docs/core-data-structures/session.zh.md +++ b/docs/core-data-structures/session.zh.md @@ -108,7 +108,7 @@ interface SessionEventMap { } ``` -`PromptMessageData.content` 始终是确切的模型可见内容。当附加 context 声明 `prompt-prefix` 放置方式时,AgentLoop 会依次把它的 block、一个 `## My request:` 分隔符以及最终生效的直接提示词拼接进该数组。可选且对模型隐藏的 `envelope` 会保留 `displayContent`,以及按顺序排列的前缀 context 来源/元数据描述信息,使 transcript(文本记录)、标题与重新引用消费方无需改变可重建历史,就能呈现人类提示词。`displayPromptContent()` 负责该选择,并为普通事件和较早的事件回退到 `content`。 +`PromptMessageData.content` 始终是确切的模型可见内容。当附加上下文声明 `prompt-prefix` 放置方式时,AgentLoop 会依次把它的块、一个 `## My request:` 分隔符以及最终生效的直接提示词拼接进该数组。可选且对模型隐藏的 `envelope` 会保留 `displayContent`,以及按顺序排列的前缀上下文来源/元数据描述信息,使 transcript(文本记录)、标题与重新引用消费方无需改变可重建历史,就能呈现人类提示词。`displayPromptContent()` 负责该选择,并为普通事件和较早的事件回退到 `content`。 ### `OutOfBandSessionEventMap`:受限的带外追加显式准入 diff --git a/docs/core-data-structures/subagent.i18n.yaml b/docs/core-data-structures/subagent.i18n.yaml index f7cf2d81de..2dcc46507e 100644 --- a/docs/core-data-structures/subagent.i18n.yaml +++ b/docs/core-data-structures/subagent.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write subagent.md: 97d6862c10a0757c41472f207f857c25f3f5d50f -subagent.zh.md: 1e88562aed99122750e9d137cb0b722d4c38c36b +subagent.zh.md: de0e5c89d508565b84ad1240a11f069dc3795e9c diff --git a/docs/core-data-structures/subagent.zh.md b/docs/core-data-structures/subagent.zh.md index 1e88562aed..de0e5c89d5 100644 --- a/docs/core-data-structures/subagent.zh.md +++ b/docs/core-data-structures/subagent.zh.md @@ -35,7 +35,7 @@ interface SubagentCapabilities { ## 启动请求 -工具层根据模型输入和自身配置构建此请求;服务在 `start` 之前针对指定提供方进行校验。必填的 `parent` 提供会话 cwd、谱系与委派深度。可选的 output schema、depth、tool filter 和 persona 需要对应的能力 flag 匹配。不支持的 schema 在启动时即失败;进程内后端将 filter 和 persona 的作用域限定在子 agent 创建阶段,并通过强制 capture tool 实现所支持的 object-rooted schema。 +工具层根据模型输入和自身配置构建此请求;服务在 `start` 之前针对指定提供方进行校验。必填的 `parent` 提供会话 cwd、谱系与委派深度。可选的 output schema、depth、工具过滤器和 persona 需要对应的能力 flag 匹配。不支持的 schema 在启动时即失败;进程内后端将 filter 和 persona 的作用域限定在子 agent 创建阶段,并通过强制 capture 工具实现所支持的 object-rooted schema。 ```ts type-equiv /** @@ -200,7 +200,7 @@ interface SubagentRun { } ``` -本地 run 必须在 `start()` fulfill 前发布一个普通子 agent/session,将该子 session id 作为 `SubagentRun.id` 返回,以 `localAgent` 暴露确切子 agent,并在子 agent 的 `parentSession` header 中记录 `request.parent.session.id`。运行时所有权可以把子 agent 放在 parent、提供方或 root 作用域下。远程提供方则返回 parent 作用域的生命周期 id 与 `localAgent: undefined`。 +本地 run 必须在 `start()` fulfill 前发布一个普通子 agent/会话,将该子会话 id 作为 `SubagentRun.id` 返回,以 `localAgent` 暴露确切子 agent,并在子 agent 的 `parentSession` header 中记录 `request.parent.session.id`。运行时所有权可以把子 agent 放在 parent、提供方或 root 作用域下。远程提供方则返回 parent 作用域的生命周期 id 与 `localAgent: undefined`。 ## 提供方 seam:`SubagentProvider` @@ -244,5 +244,5 @@ interface SubagentProvider { spawn 和 fork 后端通过 `parent.ctx` 创建一个普通 agent,将取消信号传入核心创建流程,并通过 `AgentHandle` 进行 dispose。移除提供方会阻止新的 start,但不会撤销已接受的 run。每个子 agent 获得一个新的扁平作用域,而非继承父级注册。深度与 fork 种子注入复用既有的 agent 和会话词汇: -- **委派深度**由持久 `SessionHeader.delegationDepth` 与可合并扩展的运行时字段 `AgentOptions.subagentDepth` 共同表示;缺失表示顶层深度为零,存在的较大值具有权威性。两个字段都归该 seam 所有——循环既不设置也不读取它们——因此进程内子 agent 会持久保存 parent 深度 + 1,resume 无法降低深度,而且每次 start 都会拒绝超出安全整数域、或高于已定义绝对 `request.maxDepth` 上限的派生深度。 +- **委派深度**由持久 `SessionHeader.delegationDepth` 与可合并扩展的运行时字段 `AgentOptions.subagentDepth` 共同表示;缺失表示顶层深度为零,存在的较大值具有权威性。两个字段都归该 seam 所有——循环既不设置也不读取它们——因此进程内子 agent 会持久保存 parent 深度 + 1,恢复无法降低深度,而且每次 start 都会拒绝超出安全整数域、或高于已定义绝对 `request.maxDepth` 上限的派生深度。 - **Fork 种子注入**使用 `CreateAgentOptions.seed`(一个 `SessionEvent[]` 前缀,经由 `AgentLoop.createAgent` → `ctx.sessions.prepare({ seed })` 传递,与 `resume` 使用的原语相同)。fork 后端传入父级日志的一段*平衡的已完成轮次前缀*——父级事件直到并包括其最后一个 `turn/end`——因此种子从 0 连续,[invariants](../../packages/support/invariants) 回放可以接受它(进行中的、未平衡的轮次被排除在外)。 diff --git a/docs/core-data-structures/system-prompt.i18n.yaml b/docs/core-data-structures/system-prompt.i18n.yaml index 8e68fc099b..15f1076fea 100644 --- a/docs/core-data-structures/system-prompt.i18n.yaml +++ b/docs/core-data-structures/system-prompt.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write system-prompt.md: 63a750c74300b4353f132d3dae9da52a10631f23 -system-prompt.zh.md: 748e9e4406fe8ca1071aa87f5926bd043378ccdb +system-prompt.zh.md: e04510dbf8b97d01a568ffbd878de691be267272 diff --git a/docs/core-data-structures/system-prompt.zh.md b/docs/core-data-structures/system-prompt.zh.md index 748e9e4406..e04510dbf8 100644 --- a/docs/core-data-structures/system-prompt.zh.md +++ b/docs/core-data-structures/system-prompt.zh.md @@ -2,7 +2,7 @@ [English](system-prompt.md) | 中文 -[system-prompt 包](../../packages/core/system-prompt)负责管理 prompt 贡献者与一次组装调用之间交换的数据。该包的 [README](../../packages/core/system-prompt/README.md) 记录了注册、排序、作用域与渲染行为;本页固定各插件实现或传递的跨包字面形状。 +[system-prompt 包](../../packages/core/system-prompt)负责管理提示词贡献者与一次组装调用之间交换的数据。该包的 [README](../../packages/core/system-prompt/README.md) 记录了注册、排序、作用域与渲染行为;本页固定各插件实现或传递的跨包字面形状。 源码:[`packages/core/system-prompt/src/index.ts`](../../packages/core/system-prompt/src/index.ts)。 @@ -37,7 +37,7 @@ interface ToolProviderResult { } ``` -## Prompt 段落 +## 提示词段落 `PromptSection` 是一份只读的同进程注册契约。其文本可以是静态的,也可以从当前组装上下文动态解析。 diff --git a/docs/core-data-structures/tools.i18n.yaml b/docs/core-data-structures/tools.i18n.yaml index 2f09ee1e2d..bc9fe6c5f3 100644 --- a/docs/core-data-structures/tools.i18n.yaml +++ b/docs/core-data-structures/tools.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write tools.md: ce14a37da33f89b8b90d6d8e70756f94e3d690dd -tools.zh.md: 869480fc38688a15a8681648903e1a4a0959c79d +tools.zh.md: c85ebe4d77d60e83eadb91aa5dbddd6009913614 diff --git a/docs/core-data-structures/tools.zh.md b/docs/core-data-structures/tools.zh.md index 869480fc38..c85ebe4d77 100644 --- a/docs/core-data-structures/tools.zh.md +++ b/docs/core-data-structures/tools.zh.md @@ -310,7 +310,7 @@ type PostToolDecision = 调用 `next()` 获取默认决策,或直接返回一个决策以短路。前置策略可以 deny 或 ask;只有 `allowed-once` 才继续执行,而未授权、缺少审批通道或服务、或无 agent 的请求都会变为拒绝。Guard 仍可施加最终拒绝。参数不可被改写,因为历史记录、审计、UI 和执行必须保持一致。 -后置策略可以替换内容;block 会变为包含纠正反馈的 `isError` 结果。`tools/result` 在归一化后接收冻结的执行和结果;观察者无法对其进行变换,观察者的失败也会被隔离。未知工具和抛出异常的工具都会变为结构化错误(`ToolNotFoundError` 映射为 `UNKNOWN_TOOL`),调用失败但不终止当前轮次。 +后置策略可以替换内容;块会变为包含纠正反馈的 `isError` 结果。`tools/result` 在归一化后接收冻结的执行和结果;观察者无法对其进行变换,观察者的失败也会被隔离。未知工具和抛出异常的工具都会变为结构化错误(`ToolNotFoundError` 映射为 `UNKNOWN_TOOL`),调用失败但不终止当前轮次。 ## 结构化输出 schema 子集 diff --git a/docs/core-data-structures/web.i18n.yaml b/docs/core-data-structures/web.i18n.yaml index efcc7b3258..0eba5d9be2 100644 --- a/docs/core-data-structures/web.i18n.yaml +++ b/docs/core-data-structures/web.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write web.md: 20d07240c9d9fea2f1f5abbac810f349a3e81f9b -web.zh.md: d4d9259db5c834349c1cf9c72ed5c74b0a02b32b +web.zh.md: ab786f83457c16202f879be58ff55885523f874b diff --git a/docs/core-data-structures/web.zh.md b/docs/core-data-structures/web.zh.md index d4d9259db5..ab786f8345 100644 --- a/docs/core-data-structures/web.zh.md +++ b/docs/core-data-structures/web.zh.md @@ -8,7 +8,7 @@ Web 访问 seam 是一个[能力 seam](../../.agents/notes/implemented/architect ## 为什么两项能力合为一个 seam -搜索与抓取既不共享请求 schema,也不共享业务逻辑,但它们被有意设计为同一个 `ctx.web` 中间层:一个提供方选择策略的所有者、一套 abort/error 词汇、一个面向产品的「此 harness 如何访问 Web」配置界面。代价是服务上并行的 `searchX`/`fetchX` 方法对;这种并行是有意为之,而非遗漏的提取。提供方注册的是**能力**(`WebSearchProvider` 或 `WebFetchProvider`),而非工具;面向模型的名称、schema、prompt 引导与展示全部集中在唯一的消费方 `dsh-tool-web` 中。 +搜索与抓取既不共享请求 schema,也不共享业务逻辑,但它们被有意设计为同一个 `ctx.web` 中间层:一个提供方选择策略的所有者、一套 abort/error 词汇、一个面向产品的「此 harness 如何访问 Web」配置界面。代价是服务上并行的 `searchX`/`fetchX` 方法对;这种并行是有意为之,而非遗漏的提取。提供方注册的是**能力**(`WebSearchProvider` 或 `WebFetchProvider`),而非工具;面向模型的名称、schema、提示词引导与展示全部集中在唯一的消费方 `dsh-tool-web` 中。 ## 搜索请求与结果 diff --git a/docs/core-data-structures/workflow.i18n.yaml b/docs/core-data-structures/workflow.i18n.yaml index cb0bf7e961..fecf373167 100644 --- a/docs/core-data-structures/workflow.i18n.yaml +++ b/docs/core-data-structures/workflow.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write workflow.md: 8d271b89e71de6f6bef548aa8da61402ef9ada6e -workflow.zh.md: 335f08cefe057bdc0d0f78a90e8301d5e457aae7 +workflow.zh.md: f603a50fc33fb9ab4260e8281ee04e892f677255 diff --git a/docs/core-data-structures/workflow.zh.md b/docs/core-data-structures/workflow.zh.md index 335f08cefe..f603a50fc3 100644 --- a/docs/core-data-structures/workflow.zh.md +++ b/docs/core-data-structures/workflow.zh.md @@ -4,13 +4,13 @@ 工作流 seam:一个 agent(智能体)运行由模型编写的编排脚本(SCRIPT),扇出 subagent。与 [subagent](subagent.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此处而非 [core.md](core.md)。与 subagent 注册表不同,它采用 bash 形态:每个上下文只有一个引擎实现提供 `ctx.workflows`;没有命名提供方注册表(第二个引擎是插件替换,而非共存)。 -接口:[dsh-workflow](../../packages/workflow/workflow)(`ctx.workflows` + 下文词汇)。实现是 [dsh-workflow-workerthread](../../packages/workflow/workflow-workerthread)(一个 `node:worker_threads` 引擎——每个 run 一个 worker,脚本的 vm context 位于其中);面向模型的消费方是 [dsh-tool-workflow](../../packages/workflow/tool-workflow)。提案与设计理由见 [dynamic-workflows Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md)。 +接口:[dsh-workflow](../../packages/workflow/workflow)(`ctx.workflows` + 下文词汇)。实现是 [dsh-workflow-workerthread](../../packages/workflow/workflow-workerthread)(一个 `node:worker_threads` 引擎——每个 run 一个 worker,脚本的 vm 上下文位于其中);面向模型的消费方是 [dsh-tool-workflow](../../packages/workflow/tool-workflow)。提案与设计理由见 [dynamic-workflows Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md)。 源码:[`packages/workflow/workflow/src/types.ts`](../../packages/workflow/workflow/src/types.ts) ## 启动请求 -调用方启动 run 时提出的请求。普通 workflow 工具根据模型的 `{ script, meta, args }` 调用与发起调用的 agent 构建它;专用消费方还可以为该 run 选择一个引擎级 `subagentProvider` 并调低 `maxTotalAgents`,但脚本无法观察或替换这两项策略。`meta` 与 `args` 是普通 JSON 数据(引擎会对 `meta` 做形状校验,并在任何内容运行前大声拒绝——绝不会通过求值脚本文本来获取它)。`parent` 是必填字段——脚本生成的每个子 agent 都归属于它(cwd、谱系与深度通过 [subagent seam](subagent.md) 流转)。 +调用方启动 run 时提出的请求。普通工作流工具根据模型的 `{ script, meta, args }` 调用与发起调用的 agent 构建它;专用消费方还可以为该 run 选择一个引擎级 `subagentProvider` 并调低 `maxTotalAgents`,但脚本无法观察或替换这两项策略。`meta` 与 `args` 是普通 JSON 数据(引擎会对 `meta` 做形状校验,并在任何内容运行前大声拒绝——绝不会通过求值脚本文本来获取它)。`parent` 是必填字段——脚本生成的每个子 agent 都归属于它(cwd、谱系与深度通过 [subagent seam](subagent.md) 流转)。 ```ts type-equiv /** diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml b/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml index bc2b7d097a..58f4bb356e 100644 --- a/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml +++ b/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 0001-acp-default-export-drops-inject.md: ab3efc880cb5290dc149b6bacb276ccf581968c1 -0001-acp-default-export-drops-inject.zh.md: caf60dc086e892af4ae3563b0bf073c7e6373602 +0001-acp-default-export-drops-inject.zh.md: 38bbecb4444eef1a7cdc4f48235bb83d597ce1e5 diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.zh.md b/docs/postmortem/0001-acp-default-export-drops-inject.zh.md index caf60dc086..38bbecb444 100644 --- a/docs/postmortem/0001-acp-default-export-drops-inject.zh.md +++ b/docs/postmortem/0001-acp-default-export-drops-inject.zh.md @@ -76,7 +76,7 @@ while (true) { 遍历**仅向祖先方向**进行。`sessionPersistence` 既不在 `AgentLoop` 的 fiber store 中(不在其 `static inject` 中),也不在通往 root 的任何祖先上(它位于一个*兄弟*分支),因此遍历到达根 fiber 后抛错。 -为什么内存中的 `AgentLoop` resume 测试没有捕获这个问题?因为它们从测试代码直接调用 `ctx.agents.resume(...)`——*在任何插件 fiber 之外*。此时 `ctx.fiber.runtime` 为 `null`,代理处理器走了一条提前绕过的路径: +为什么内存中的 `AgentLoop` 恢复测试没有捕获这个问题?因为它们从测试代码直接调用 `ctx.agents.resume(...)`——*在任何插件 fiber 之外*。此时 `ctx.fiber.runtime` 为 `null`,代理处理器走了一条提前绕过的路径: ```ts ignore-check if (!ctx.fiber.runtime) return ctx.reflect.get(prop, false) // ← direct global-store lookup, no fiber walk @@ -91,7 +91,7 @@ if (!ctx.fiber.runtime) return ctx.reflect.get(prop, false) // ← direct glob 两个 bug 共享同一个流程缺口:**没有任何测试通过插件的真实加载路径或真实调用拓扑来驱动它。** - 内存 harness 通过手动构建插件对象来挂载 bridge:`ctx.plugin({ name, inject, apply })`。这手动提供了 `inject`,因此永远无法复现 Bug #1——`unwrapExports` 只被 *Loader* 调用,`ctx.plugin` 从不调用它。即使 `ctx.plugin(NamespaceImport)` 也无法捕获。 -- 同一个 harness 将所有内容平铺挂载在一个根上下文上,因此从中触达的 `AgentLoop` resume 要么运行在顶层(`!runtime` 绕过),要么通过一个 origin 仍然解析在 root 上的 shadow——掩盖了 Bug #2 的祖先遍历失败。 +- 同一个 harness 将所有内容平铺挂载在一个根上下文上,因此从中触达的 `AgentLoop` 恢复要么运行在顶层(`!runtime` 绕过),要么通过一个 origin 仍然解析在 root 上的 shadow——掩盖了 Bug #2 的祖先遍历失败。 - 唯一的无 key e2e 发送 `initialize` 并检查 stdout 纯净性。`initialize` 从不触达 factory,因此两个 bug 都安然通过。 - 唯一驱动 `session/new`/`session/load` 的测试需要 key 才能运行,因此 CI(无 key)跳过了它——而本地它之所以「通过」,只是因为一个陈旧的已构建 `lib/`(包含旧代码)恰好满足了模块解析。 diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml index 21f7000078..19802cabab 100644 --- a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 0002-js-expression-disabled-filesystem-tools.md: 30ff9d920821a8d55c4bea5f120f1aeeca6634b3 -0002-js-expression-disabled-filesystem-tools.zh.md: d171ce7fe0fea830375f7494be2aac38630c8d6a +0002-js-expression-disabled-filesystem-tools.zh.md: 7b7c34bb77a141eaef383fd9a655caff2a484ce1 diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md index d171ce7fe0..7b7c34bb77 100644 --- a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md @@ -35,7 +35,7 @@ Cordis Include 将每个 `!!js` 标量解析为一个表达式对象。Loader ## 已添加的防护措施 -- 文件系统场景启动 `fs.cordis.yml`:一个显式的固定全权限 overlay,配有对应的 replay 配置和独立的 request-header 类。 +- 文件系统场景启动 `fs.cordis.yml`:一个显式的固定全权限 overlay,配有对应的回放配置和独立的 request-header 类。 - [`AGENTS.md`](../../AGENTS.md) 与 [Cordis 入门](../cordis-primer.md#loader-configuration)明确说明 `!!js` 仅在插件 `config` 内有效,条件式组合应使用 overlay。 - `verify-cordis-config` 解析仓库中的 Cordis YAML,拒绝 Loader 入口元数据中的表达式节点(包括 include patch 和插入的入口)。 - `dsh-acp-snapshot` 在新鲜运行和已提交的会话 fixture 中拒绝结构化的 `UNKNOWN_TOOL` 结果,防止其被提交为预期输出。 From d5f5517ec01ea3bb30a3bfc4e095371da54150ae Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:11:59 +0800 Subject: [PATCH 123/368] docs(i18n): address Agent Note review feedback --- ...26-06-11-content-block-vocabulary.i18n.yaml | 2 +- .../2026-06-11-content-block-vocabulary.zh.md | 2 +- ...-06-17-filesystem-capability-seam.i18n.yaml | 2 +- ...2026-06-17-filesystem-capability-seam.zh.md | 6 +++--- .../2026-06-20-branded-ids.i18n.yaml | 2 +- .../architecture/2026-06-20-branded-ids.zh.md | 2 +- ...6-20-extract-example-app-packages.i18n.yaml | 2 +- ...26-06-20-extract-example-app-packages.zh.md | 6 +++--- .../2026-06-20-package-hierarchy.i18n.yaml | 2 +- .../2026-06-20-package-hierarchy.zh.md | 4 ++-- ...mandatory-app-attribution-headers.i18n.yaml | 2 +- ...-21-mandatory-app-attribution-headers.zh.md | 2 +- ...02-result-time-applied-hunk-diffs.i18n.yaml | 2 +- ...-07-02-result-time-applied-hunk-diffs.zh.md | 4 ++-- ...26-07-02-tool-render-intent-union.i18n.yaml | 2 +- .../2026-07-02-tool-render-intent-union.zh.md | 8 ++++---- ...ables-and-tool-guidance-ownership.i18n.yaml | 2 +- ...variables-and-tool-guidance-ownership.zh.md | 4 ++-- ...6-06-14-acp-agent-client-protocol.i18n.yaml | 2 +- .../2026-06-14-acp-agent-client-protocol.zh.md | 2 +- .../feature/2026-06-15-code-mode.i18n.yaml | 2 +- .../feature/2026-06-15-code-mode.zh.md | 2 +- ...026-06-17-filesystem-tool-schemas.i18n.yaml | 2 +- .../2026-06-17-filesystem-tool-schemas.zh.md | 18 +++++++++--------- ...8-acp-terminal-and-tool-rendering.i18n.yaml | 2 +- ...06-18-acp-terminal-and-tool-rendering.zh.md | 2 +- ...-06-18-compaction-capability-seam.i18n.yaml | 2 +- ...2026-06-18-compaction-capability-seam.zh.md | 2 +- .../feature/2026-06-30-hook-bridges.i18n.yaml | 2 +- .../feature/2026-06-30-hook-bridges.zh.md | 4 ++-- .../2026-07-05-dynamic-workflows.i18n.yaml | 2 +- .../feature/2026-07-05-dynamic-workflows.zh.md | 6 +++--- .../feature/2026-07-06-sandbox.i18n.yaml | 2 +- .../feature/2026-07-06-sandbox.zh.md | 2 +- .../2026-07-07-mcp-client-plugin.i18n.yaml | 2 +- .../feature/2026-07-07-mcp-client-plugin.zh.md | 2 +- ...6-07-03-documentation-graph-atlas.i18n.yaml | 2 +- .../2026-07-03-documentation-graph-atlas.zh.md | 4 ++-- ...6-19-drop-mutable-session-summary.i18n.yaml | 2 +- ...26-06-19-drop-mutable-session-summary.zh.md | 2 +- ...im-acp-bridge-unreachable-surface.i18n.yaml | 2 +- ...4-trim-acp-bridge-unreachable-surface.zh.md | 2 +- ...2-fork-child-replay-seed-boundary.i18n.yaml | 2 +- ...06-22-fork-child-replay-seed-boundary.zh.md | 2 +- ...26-06-22-subagent-snapshot-replay.i18n.yaml | 2 +- .../2026-06-22-subagent-snapshot-replay.zh.md | 2 +- .../2026-06-16-typed-event-schemas.i18n.yaml | 2 +- .../2026-06-16-typed-event-schemas.zh.md | 2 +- ...6-07-08-interactive-side-sessions.i18n.yaml | 2 +- .../2026-07-08-interactive-side-sessions.zh.md | 2 +- ...6-06-11-immutable-public-surfaces.i18n.yaml | 2 +- .../2026-06-11-immutable-public-surfaces.zh.md | 2 +- ...6-06-20-providerless-example-base.i18n.yaml | 2 +- .../2026-06-20-providerless-example-base.zh.md | 2 +- ...-generate-agent-note-index-tables.i18n.yaml | 2 +- ...7-04-generate-agent-note-index-tables.zh.md | 2 +- ...assembled-assistant-messages-only.i18n.yaml | 2 +- ...-20-assembled-assistant-messages-only.zh.md | 2 +- .../2026-06-20-drop-acp-session-load.i18n.yaml | 2 +- .../2026-06-20-drop-acp-session-load.zh.md | 2 +- ...2026-06-20-drop-acp-terminal-meta.i18n.yaml | 2 +- .../2026-06-20-drop-acp-terminal-meta.zh.md | 2 +- ...6-20-drop-bash-output-spill-files.i18n.yaml | 2 +- ...26-06-20-drop-bash-output-spill-files.zh.md | 2 +- ...6-20-drop-durable-step-boundaries.i18n.yaml | 2 +- ...26-06-20-drop-durable-step-boundaries.zh.md | 2 +- ...06-20-drop-unused-session-lineage.i18n.yaml | 2 +- ...026-06-20-drop-unused-session-lineage.zh.md | 2 +- ...old-session-persistence-interface.i18n.yaml | 2 +- ...20-fold-session-persistence-interface.zh.md | 2 +- ...2026-06-20-generic-tool-rendering.i18n.yaml | 2 +- .../2026-06-20-generic-tool-rendering.zh.md | 2 +- ...26-06-20-retire-mid-turn-steering.i18n.yaml | 2 +- .../2026-06-20-retire-mid-turn-steering.zh.md | 2 +- ...6-06-20-single-session-acp-bridge.i18n.yaml | 2 +- .../2026-06-20-single-session-acp-bridge.zh.md | 2 +- ...-06-20-truncate-interrupted-turns.i18n.yaml | 2 +- ...2026-06-20-truncate-interrupted-turns.zh.md | 2 +- ...unimplemented-subagent-vocabulary.i18n.yaml | 2 +- ...une-unimplemented-subagent-vocabulary.zh.md | 4 ++-- ...lapse-workflow-to-foreground-core.i18n.yaml | 2 +- ...-collapse-workflow-to-foreground-core.zh.md | 2 +- ...une-unused-skill-registry-surface.i18n.yaml | 2 +- ...2-prune-unused-skill-registry-surface.zh.md | 2 +- 84 files changed, 107 insertions(+), 107 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml index cc77840694..95bc498102 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-content-block-vocabulary.md: 9aad01cee6083b1f380be66869af3137a07d9f1f -2026-06-11-content-block-vocabulary.zh.md: 123ca87f55be5129855a330efbfe0818d7cdbc0c +2026-06-11-content-block-vocabulary.zh.md: 1427ef1a47ee3a54c1c93885befdf580b84f6399 diff --git a/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md b/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md index 123ca87f55..1427ef1a47 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md @@ -23,6 +23,6 @@ harness 需要一套统一的内部消息语言,供 agent loop(智能体循 - 推理(reasoning)在核心层有了归属,无需依赖提供方特有的结构。 - 多模态块只有在适配器、UI 和上下文压缩(context compaction)三方协同支持后才会回归;见 [drop-image Agent Note](../simplification/2026-07-04-drop-image-content-block.md)。 -- 缓存提示与 assistant prefill 在有实际适配器能兑现之前保持缺席;见 [producer-less variants](../simplification/2026-07-04-prune-producerless-vocabulary-variants.md) 与 [inert request knobs](../simplification/2026-07-04-drop-inert-request-knobs.md) Agent Note。 +- 缓存提示与 assistant prefill 在有实际适配器能兑现之前保持缺席;见[无生产者的词汇变体](../simplification/2026-07-04-prune-producerless-vocabulary-variants.md)与[无端到端可用路径的请求旋钮](../simplification/2026-07-04-drop-inert-request-knobs.md) Agent Note。 - 每个适配器都需承担翻译成本;首批真实适配器已验证了流式输出协议,新适配器应继续在适配器本地测试中验证其提供方特有的映射。 - 跨包(package)边界的 ID 使用品牌类型(`CallId`、agent 与 session 共享的 `SessionId`)——零运行时开销的名义类型。 diff --git a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml index 8b36d4bdd1..e0fd8d2d7b 100644 --- a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-17-filesystem-capability-seam.md: cd8f8572730b1833ed1d7dbe1861d516c2d32925 -2026-06-17-filesystem-capability-seam.zh.md: a7a8d4cbc48c473b1f0669a95c5fbe25eecf94f4 +2026-06-17-filesystem-capability-seam.zh.md: fa06ecc4538258163ae17cd403d9e856c4d2911f diff --git a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md index a7a8d4cbc4..fa06ecc453 100644 --- a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md @@ -32,11 +32,11 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 第一个后端有意仅限本地:`dsh-fs-local` 基于宿主文件系统实现 `ctx.fs`。未来的兄弟后端可在同一接口之后提供沙箱、远程、虚拟或项目作用域的文件系统。 -第一个消费方有意仅限文本文件:`dsh-tool-fs` 暴露面向模型的 `read`、`write` 和 `edit` 工具,处理 UTF-8 文本文件。未来的消费方可以添加目录列表、搜索/glob、二进制安全操作、文件监视或更高层的项目操作,只要 `ctx.fs` 上存在所需能力,就无需改动本地后端包。直接目录列表后来由 [Add direct directory listing to the filesystem seam](2026-07-03-filesystem-directory-listing-seam.md) 添加。 +第一个消费方有意仅限文本文件:`dsh-tool-fs` 暴露面向模型的 `read`、`write` 和 `edit` 工具,处理 UTF-8 文本文件。未来的消费方可以添加目录列表、搜索/glob、二进制安全操作、文件监视或更高层的项目操作,只要 `ctx.fs` 上存在所需能力,就无需改动本地后端包。直接目录列表后来由[为文件系统 seam 添加直接目录列举能力](2026-07-03-filesystem-directory-listing-seam.md)添加。 文件系统权限和沙箱并非此拆分所隐含。本地后端从其配置的基目录解析相对路径,但隔离策略是独立的决策:要么由更严格的 `ctx.fs` 实现强制执行,要么由权限/沙箱插件包装 `tools/execute` 并在调用到达消费方之前否决。 -读后写/编辑与观测状态属于 `dsh-fs-policy`,而非 `ctx.fs`。通过 `fs/*` 事件门控,策略按不透明 actor 记录版本,并提供可选的变更期望;提供方原子性地强制新鲜度。`dsh-tool-fs` 发出事件但不依赖策略。见 [split-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](2026-06-26-file-context-as-event-gate.md) Agent Note。 +读后写/编辑与观测状态属于 `dsh-fs-policy`,而非 `ctx.fs`。通过 `fs/*` 事件门控,策略按不透明 actor 记录版本,并提供可选的变更期望;提供方原子性地强制新鲜度。`dsh-tool-fs` 发出事件但不依赖策略。见[拆分文件系统 seam](../simplification/2026-06-26-fsspec-style-fs-seam.md)和[事件门控插件](2026-06-26-file-context-as-event-gate.md) Agent Note。 ## 包拓扑 @@ -95,7 +95,7 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 策略插件(而非 `ctx.fs`)对先前观测进行门控:`edit` 要求 owner 有先前观测(否则报 `FS_NOT_OBSERVED`),记录的版本作为 CAS 基础传给 `editText`。在策略插件缺席时,`ctx.fs` 本身是一个完整的无约束 seam(无条件写入/编辑);工具从不与策略方法耦合。 -文件系统契约失败以 `FsError extends HarnessError` 抛出,工具注册表将其转换为带结构化 `{ name, code }` 元数据的 `isError` 工具结果。`dsh-fs` 拥有此词汇,而非由每个工具各自发明消息。错误码包括 `FS_NOT_FOUND`、`FS_NOT_TEXT`、`FS_STALE_VERSION`、`FS_NOT_OBSERVED`、`FS_NOT_REGULAR_FILE`、`FS_AMBIGUOUS_EDIT`、`FS_EDIT_NOT_FOUND` 和 `FS_ABORTED`。(早期草案包含 `FS_PARTIAL_OBSERVATION`;基于新鲜度的授权没有 partial/full 区分,因此已删除。目录列表相关的错误码后来由 [Add direct directory listing to the filesystem seam](2026-07-03-filesystem-directory-listing-seam.md) 添加。) +文件系统契约失败以 `FsError extends HarnessError` 抛出,工具注册表将其转换为带结构化 `{ name, code }` 元数据的 `isError` 工具结果。`dsh-fs` 拥有此词汇,而非由每个工具各自发明消息。错误码包括 `FS_NOT_FOUND`、`FS_NOT_TEXT`、`FS_STALE_VERSION`、`FS_NOT_OBSERVED`、`FS_NOT_REGULAR_FILE`、`FS_AMBIGUOUS_EDIT`、`FS_EDIT_NOT_FOUND` 和 `FS_ABORTED`。(早期草案包含 `FS_PARTIAL_OBSERVATION`;基于新鲜度的授权没有 partial/full 区分,因此已删除。目录列表相关的错误码后来由[为文件系统 seam 添加直接目录列举能力](2026-07-03-filesystem-directory-listing-seam.md)添加。) ## 工具消费方行为 diff --git a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml index 29c4f4724d..d1a6a000db 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-branded-ids.md: 93bab1d47c793cc4dd1f1d19fa3af22d1721be29 -2026-06-20-branded-ids.zh.md: f45f39cc3a49f7abf116e77f1ace2db74fc3de67 +2026-06-20-branded-ids.zh.md: edf5cade38b579346f34a7ed2ee0a876af7a4c8b diff --git a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md index f45f39cc3a..edf5cade38 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md @@ -8,7 +8,7 @@ Status: implemented harness 使用 `Branded = string & { readonly [BRAND]: B }` 机制,为 `CallId`(`packages/llm/llm/src/brand.ts`)和共享的 agent/session `SessionId`(`packages/core/session/src/types.ts`)做 brand 处理;该机制由纯类型包(package) `@deepseek-ai/dsh-brand` 拥有,位于 `packages/util/brand/`,见其 [README](../../../../packages/util/brand/README.md),并为每个类型提供零开销的 cast 工厂。`dsh-brand` 还声明了治理策略:*「Branding 用于跨包边界且可能被混淆的 id;不是每个 string 都需要 brand。」* 这条策略是正确的;问题在于它只落实了一半。两处缺口使得结构相同但语义错误的 string 今天仍能通过类型检查器。 -**缺口 1:bash seam 中未 brand 的跨边界 ID。** 后台任务 id 是普通 `string`:`BashTask.id: string`(`packages/bash/bash/src/types.ts`),作为 `string` 贯穿整个执行器 seam(`packages/bash/bash/src/index.ts` 中的 `BashExecutor.get`/`ownerOf`/`readOutput`/`kill(id: string)`),再由面向模型的工具以 `string` 校验并传递(`validateTaskId`、`assertTaskAccess`、`packages/bash/tool-bash/src/index.ts` 中 `task_id` 的 schema 参数)。它由每执行器计数器生成——`packages/bash/bash-local/src/index.ts` 中的 `` `bash-${this.nextTaskId++}` ``——其形状与 `SessionId` 的默认值**完全相同,都是 `name-N`**(`packages/core/session/src/index.ts` 中的 `` `session-${++counter}` ``)。bash task id 和 session id 在调用点轻易就能互换,而编译器毫无反应。这是用户询问的核心案例,并且它是面向模型的 id(模型会把 `task_id` 传回 `bash_output`/`bash_kill`),所以该混淆可由不受信任的输入触达。 +**缺口 1:bash seam 中未 brand 的跨边界 ID。** 后台 task id 是普通 `string`:`BashTask.id: string`(`packages/bash/bash/src/types.ts`),作为 `string` 贯穿整个执行器 seam(`packages/bash/bash/src/index.ts` 中的 `BashExecutor.get`/`ownerOf`/`readOutput`/`kill(id: string)`),再由面向模型的工具以 `string` 校验并传递(`validateTaskId`、`assertTaskAccess`、`packages/bash/tool-bash/src/index.ts` 中 `task_id` 的 schema 参数)。它由每执行器计数器生成——`packages/bash/bash-local/src/index.ts` 中的 `` `bash-${this.nextTaskId++}` ``——其形状与 `SessionId` 的默认值**完全相同,都是 `name-N`**(`packages/core/session/src/index.ts` 中的 `` `session-${++counter}` ``)。bash task id 和 session id 在调用点轻易就能互换,而编译器毫无反应。这是用户询问的核心案例,并且它是面向模型的 id(模型会把 `task_id` 传回 `bash_output`/`bash_kill`),所以该混淆可由不受信任的输入触达。 bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 和 `BashExecSpec.owner: string | undefined`(`packages/bash/bash/src/types.ts`)被文档描述为刻意*不透明*的隔离键,但在所有实际调用方中,该值就是所属 agent(智能体)共享的 `Agent.id`/`SessionId`(`callerToken = (exec) => exec.agent?.id`,位于 `packages/bash/tool-bash/src/index.ts`),只是披着另一个 seam 本地名称。它被用于访问控制比较(`owner !== callerToken(exec)`),因此一个不匹配但类型正确的 string 在此处就是跨会话隔离 bug,而当前类型系统无法捕获。这正是[统一 agent/session 标识决策](../simplification/2026-06-20-unify-agent-and-session-id.md)覆盖的共享 id 别名。 diff --git a/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml index 419c158b01..b2762a411f 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-extract-example-app-packages.md: b757a0099382a648a4efda4639e275ae6e6a02d1 -2026-06-20-extract-example-app-packages.zh.md: 5814704f0426707ef255a67a7aed9b79cae4aa24 +2026-06-20-extract-example-app-packages.zh.md: 85790354be8814f7563bbfe81b93067ae9c861ee diff --git a/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md b/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md index 5814704f04..85790354be 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md @@ -51,7 +51,7 @@ Status: implemented ## 相关 -- 取代 [Make the shared example base providerless](../../rejected/architecture/2026-06-20-providerless-example-base.md):一旦主干移入 `dsh-agent-spine-demo` 且 `base*.yml` 文件被删除,将 `base.yml` 重命名为无 provider 核心便不再有意义。 -- 基于 [capability-seams](2026-06-13-capability-seams.md) 的接口/实现/消费方拆分——后端和展示层保持为叶子选择;主干是共享 bundle。 -- 与 [Reorganize packages into a modular hierarchy](2026-06-20-package-hierarchy.md) 互补:新的 app/core 包按该层级结构归入既有分组(`core` 放可复用的主干 bundle,`ui` 放应用特有的前门)。 +- 取代[使共享示例基础配置与提供方无关](../../rejected/architecture/2026-06-20-providerless-example-base.md):一旦主干移入 `dsh-agent-spine-demo` 且 `base*.yml` 文件被删除,将 `base.yml` 重命名为无 provider 核心便不再有意义。 +- 基于[能力 seam](2026-06-13-capability-seams.md)的接口/实现/消费方拆分——后端和展示层保持为叶子选择;主干是共享 bundle。 +- 与[将包重组为模块化层级结构](2026-06-20-package-hierarchy.md)互补:新的 app/core 包按该层级结构归入既有分组(`core` 放可复用的主干 bundle,`ui` 放应用特有的前门)。 - 后续的[冗余 agent 移除](../simplification/2026-07-20-remove-stdio-and-echo-agents.md)拥有最终的 TUI/Headless 拆分,并移除行式与仅 mock 的叶子。 diff --git a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml index bc70afb74c..3a860dbf97 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-package-hierarchy.md: aba5fb56176ecab9dd92c61a72cb91d501a442d8 -2026-06-20-package-hierarchy.zh.md: 304bf1da3631187d09b229fb14beb54d4e9a46cc +2026-06-20-package-hierarchy.zh.md: 5efd70bf0a82d646e5274e1a164805b9c35dfdbc diff --git a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md index 304bf1da36..5efd70bf0a 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md @@ -4,7 +4,7 @@ Status: implemented [English](2026-06-20-package-hierarchy.md) | 中文 -后续的 [fold-stdio-helper](../simplification/2026-07-04-fold-stdio-ui-helper.md) 决策取代了最初的 `support/ui-stdio` 放置方式,[冗余 agent 移除](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) 随后又彻底移除了该接口。这里拥有的决策仍是统一的二层目录深度。 +后续的[折叠 stdio helper](../simplification/2026-07-04-fold-stdio-ui-helper.md)决策取代了最初的 `support/ui-stdio` 放置方式,[冗余 agent 移除](../simplification/2026-07-20-remove-stdio-and-echo-agents.md)随后又彻底移除了该接口。这里拥有的决策仍是统一的二层目录深度。 ## 问题 @@ -57,7 +57,7 @@ packages/ - `tsconfig.base.json` 通过一条 `@deepseek-ai/dsh-*` `paths` 通配符(每个分组列一个候选)映射所有包,取代了逐包条目。根 `tsconfig.json` 复用该源映射,并携带显式 project references 以保持 package/vendor 类型检查边界完整。(这里引入了一个细节:路径候选中包含 `/*/`,朴素的正则注释剥离器会将其误认为块注释——`scripts/doc-typecheck.ts` 正是因此通过 TypeScript 解析器读取 JSONC 配置,而非手动剥离注释。) - `scripts/publint-all.ts` 通过读取层级结构(`packages//`)推导列表,解决了 `TODO(package-inventory)`。 -- `tsconfig.build.json` 的 project `references` 仍为显式列表——TypeScript project references 没有通配符形式。从 manifest(元数据清单)生成这些引用留作后续工作(见 [discover package inventories](../../proposed/process/2026-06-20-discover-package-inventory.md))。 +- `tsconfig.build.json` 的 project `references` 仍为显式列表——TypeScript project references 没有通配符形式。从 manifest(元数据清单)生成这些引用留作后续工作(见[通过发现机制获取包清单](../../proposed/process/2026-06-20-discover-package-inventory.md))。 ### 新增的护栏 diff --git a/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml index 32fb4fe9a9..e72b100327 100644 --- a/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-21-mandatory-app-attribution-headers.md: a8ffe91c431cdc7907626bbc3eaf8096035777de -2026-06-21-mandatory-app-attribution-headers.zh.md: 724a828ce6a9907bec5615d1b2c3a53f2603e388 +2026-06-21-mandatory-app-attribution-headers.zh.md: 5529a42dddf4615ee1054b4d1dee36b077800d7d diff --git a/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md b/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md index 724a828ce6..5529a42ddd 100644 --- a/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md @@ -8,7 +8,7 @@ Status: implemented LLM(大语言模型)提供方请求应当标识发出请求的产品。这对提供方侧的技术支持、滥用调查、兼容性调试和流量分析都有价值。在本 Agent Note 之前,harness 只做了部分工作:手写的 DeepSeek 适配器发送了一个手动复制的 `User-Agent` 常量(`packages/llm/llm-deepseek/src/adapter.ts`),而基于 pi-ai 的孪生适配器则完全不发送 harness 自有的头部(`packages/llm/llm-pi-ai/src/adapter.ts`)。因此新适配器可以悄无声息地省略归属标识,而基于库的适配器也可能与手写适配器产生偏差——尽管[孪生适配器 Agent Note](2026-06-13-twin-llm-adapters.md) 的存在正是为了让两种实现在提供方 seam 上保持诚实。 -直接触发因素来自 OpenRouter 的 [App Attribution](https://openrouter.ai/docs/app-attribution) 文档。OpenRouter 根据 `HTTP-Referer` 加上 display/category 头部来创建应用页面和排名。这有价值,但它不是 HTTP 标准中的应用身份机制。风险在于:把 OpenRouter 的精确头部集当作通用标准来采纳,然后将提供方特有的头部泄漏到直连 DeepSeek 的请求、未来的 OpenAI/Anthropic/Vertex 适配器、测试服务器或无限期记录未知字段的代理中。 +直接触发因素来自 OpenRouter 的[应用归属](https://openrouter.ai/docs/app-attribution)文档。OpenRouter 根据 `HTTP-Referer` 加上 display/category 头部来创建应用页面和排名。这有价值,但它不是 HTTP 标准中的应用身份机制。风险在于:把 OpenRouter 的精确头部集当作通用标准来采纳,然后将提供方特有的头部泄漏到直连 DeepSeek 的请求、未来的 OpenAI/Anthropic/Vertex 适配器、测试服务器或无限期记录未知字段的代理中。 ## 调研 diff --git a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml index a2f2379e84..999b2cbd85 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-02-result-time-applied-hunk-diffs.md: b1e1884f2264f17f6fff17569d79d8352e3fc709 -2026-07-02-result-time-applied-hunk-diffs.zh.md: 091bbb6b9752238348c594a4abe39944b005755d +2026-07-02-result-time-applied-hunk-diffs.zh.md: f64d984df524f25f041a56b1f0bc287e1e4b77a6 diff --git a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md b/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md index 091bbb6b97..f64d984df5 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md @@ -6,7 +6,7 @@ Status: implemented ## 问题 -[tagged render-intent union](2026-07-02-tool-render-intent-union.md) 为 `dsh-tool-fs` 的 write/edit 在调用时刻提供了 `card:'diff'`,纯粹从工具参数推导:write ⇒ `{oldText:null, newText:content}`(整个新文件),edit ⇒ `{oldText:old_string, newText:new_string}`(裸替换片段)。编辑器将其渲染为行内 diff,但这是一个**无上下文**的 diff:裸的 `old_string`→`new_string` 没有周围行,而一次触及五个分散位置的 `replace_all` 仍然渲染为一对片段。 +[带标签的 render-intent 联合类型](2026-07-02-tool-render-intent-union.md)为 `dsh-tool-fs` 的 write/edit 在调用时刻提供了 `card:'diff'`,纯粹从工具参数推导:write ⇒ `{oldText:null, newText:content}`(整个新文件),edit ⇒ `{oldText:old_string, newText:new_string}`(裸替换片段)。编辑器将其渲染为行内 diff,但这是一个**无上下文**的 diff:裸的 `old_string`→`new_string` 没有周围行,而一次触及五个分散位置的 `replace_all` 仍然渲染为一对片段。 在对接 `claude-agent-acp` 自身的 ACP(Agent Client Protocol) bridge 时可以看到完整编辑器 diff 的样子:变更应用后,它发出第二个 `tool_call_update`,其 diff 是**带 ±3 行上下文的 applied hunk**(`replace_all` 的每个变更位置各一个 hunk),由工具的 `structuredPatch` 重建。这个结果时刻的 hunk 正是让 Zed 在文件中*原位*显示变更(而非浮动片段)的关键。我们的工具止步于调用时刻的片段;完成后的结果只携带纯文本「updated successfully」,没有 diff。 @@ -56,6 +56,6 @@ type ToolExecuteReturn = ContentBlock[] | { content: ContentBlock[]; meta?: unkn ## 相关 -- 补全了 [Tagged render-intent union](2026-07-02-tool-render-intent-union.md) 中作为非目标列出的最后一项表示差异——该 Agent Note 的「非目标」一节已更新,记录 applied-hunk diff 在此处交付。 +- 补全了[带标签的 render-intent 联合类型](2026-07-02-tool-render-intent-union.md)中作为非目标列出的最后一项表示差异——该 Agent Note 的「非目标」一节已更新,记录 applied-hunk diff 在此处交付。 - 基于[文件系统 capability seam](2026-06-17-filesystem-capability-seam.md)(before/after 是后端返回的存储事实)和[事件溯源会话](2026-06-11-event-sourced-sessions.md)(`meta` 载荷持久化在 `tool/result` 事件上,因此回放可复现卡片)。 - `meta` 通道有意设计为通用的:未来的工具(结构化搜索、数据表结果)可以附加自己的持久化结果展示而无需再改 core。 diff --git a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml index 6f93853732..10be0c15fe 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-02-tool-render-intent-union.md: c7adf8f405000ec7940f82e1e1e2406d86253461 -2026-07-02-tool-render-intent-union.zh.md: c77455b2d8c47add16e36f1b8a8ac3bb12f02707 +2026-07-02-tool-render-intent-union.zh.md: 9e9248b95acbbf9d197322acd2f38f594aef3bf1 diff --git a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md index c77455b2d8..9e9248b95a 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md @@ -12,7 +12,7 @@ Status: implemented - 哪些组合是*合法的*没有文档说明:一个设置了 `content` 的 `terminal` 调用意味着「卡片上方的描述」;一个设置了 `terminal` 的 generic 调用毫无意义但类型上可表达。类型允许无意义的状态存在。 - 无法表达编辑器最需要的文件工具能力:**diff 卡片**(`{path, oldText, newText}`,Zed 将其渲染为内联 diff / 新文件预览)。`ToolCallPresentation.content` 使用的是 *LLM(大语言模型)* 的 `ContentBlock[]` 词汇(text/image),工具根本无法请求 diff 展示。 -`packages/core/tools/src/index.ts` 中已有的 `FIXME(tool-presentation)` 指出了修复方向:「重新设计类型,让工具一次性声明其渲染意图(例如按卡片种类的带标签联合类型),而非一堆由 bridge 拼接的可选字段。」被否决的 Agent Note [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) 明确推迟了此事:富渲染「应当在至少有两个真实工具和两个真实消费方验证词汇之后,以带标签 render-intent 联合类型的形式回归。」该条件现已满足:两个生产者族(`dsh-tool-bash`、`dsh-tool-fs`)和两个消费方(ACP bridge 实时路径 + snapshot 回放路径)。 +`packages/core/tools/src/index.ts` 中已有的 `FIXME(tool-presentation)` 指出了修复方向:「重新设计类型,让工具一次性声明其渲染意图(例如按卡片种类的带标签联合类型),而非一堆由 bridge 拼接的可选字段。」被否决的 Agent Note [折叠工具拥有的 UI 呈现](../../rejected/simplification/2026-06-20-generic-tool-rendering.md)明确推迟了此事:富渲染「应当在至少有两个真实工具和两个真实消费方验证词汇之后,以带标签 render-intent 联合类型的形式回归。」该条件现已满足:两个生产者族(`dsh-tool-bash`、`dsh-tool-fs`)和两个消费方(ACP bridge 实时路径 + snapshot 回放路径)。 ## 决策 @@ -76,7 +76,7 @@ interface TerminalResultView { card: 'terminal'; title?: string; output?: string ## 相关 -- 取代 [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md)(已否决——「等两个真实工具和两个真实消费方,然后做带标签 render-intent 联合类型」)中的推迟决定。该条件现已满足;本 Agent Note 即为那个联合类型。 -- 被 [Result-time applied-hunk diffs](2026-07-02-result-time-applied-hunk-diffs.md) 扩展:后者添加了一个持久化的 `meta` 通道,使 write/edit 在结果时输出 `DiffResultView`(应用后的变更:带上下文行的 contextual hunk / 每个 `replace_all` 位点一个,或创建时的整文件 diff),叠加在本联合类型的调用时 diff 卡片之上。 -- 将 `ToolTerminal` 折入 [ACP terminal and tool-call rendering](../feature/2026-06-18-acp-terminal-and-tool-rendering.md) 所描述的 `terminal` view(`_meta` terminal 卡片约定和能力门控不变;仅 harness 侧的展示类型改变)。 +- 取代[折叠工具拥有的 UI 呈现](../../rejected/simplification/2026-06-20-generic-tool-rendering.md)(已否决——「等两个真实工具和两个真实消费方,然后做带标签 render-intent 联合类型」)中的推迟决定。该条件现已满足;本 Agent Note 即为那个联合类型。 +- 被[结果时已应用 hunk 差异](2026-07-02-result-time-applied-hunk-diffs.md)扩展:后者添加了一个持久化的 `meta` 通道,使 write/edit 在结果时输出 `DiffResultView`(应用后的变更:带上下文行的 contextual hunk / 每个 `replace_all` 位点一个,或创建时的整文件 diff),叠加在本联合类型的调用时 diff 卡片之上。 +- 将 `ToolTerminal` 折入 [ACP terminal 与工具调用渲染](../feature/2026-06-18-acp-terminal-and-tool-rendering.md)所描述的 `terminal` view(`_meta` terminal 卡片约定和能力门控不变;仅 harness 侧的展示类型改变)。 - ACP SDK 的 `Diff` / `ToolCallContent` 类型支撑新的 `diff` 卡片。 diff --git a/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml index 87ead153fa..109fbae933 100644 --- a/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-05-prompt-variables-and-tool-guidance-ownership.md: 94f5fa409e7b539b48750d12576c7a342a30c9ba -2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 2342b89ab666a7987f78cfeabe6fa90ce9dd0cad +2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 572a95c34381f6d73d1f6e053e565f30704026d3 diff --git a/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md b/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md index 2342b89ab6..572a95c343 100644 --- a/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md @@ -40,7 +40,7 @@ Status: implemented ### Subagent 对话历史描述符 -`SubagentProvider.inheritsParentContext` 描述的是对话种子,而非作用域、服务、工具或权限。spawn 和 ACP 将其设为 `false`;fork 设为 `true`。`dsh-tool-subagent` 根据该标志派生工具和 prompt 参数的描述,包括 fork 继承已完成轮次但不继承进行中轮次这一点。provider 生命周期事件使该措辞与响应式 provider 注册保持同步;其设计动机见 [provider-lifecycle-events Agent Note](2026-07-05-subagent-provider-lifecycle-events.md)。 +`SubagentProvider.inheritsParentContext` 描述的是对话种子,而非作用域、服务、工具或权限。spawn 和 ACP 将其设为 `false`;fork 设为 `true`。`dsh-tool-subagent` 根据该标志派生工具和 prompt 参数的描述,包括 fork 继承已完成轮次但不继承进行中轮次这一点。provider 生命周期事件使该措辞与响应式 provider 注册保持同步;其设计动机见[提供方生命周期事件 Agent Note](2026-07-05-subagent-provider-lifecycle-events.md)。 ## 曾考虑的替代方案 @@ -49,7 +49,7 @@ Status: implemented - **在每个 persona 中手写模型名称**:与上方一行的 `model:` 键重复,配置修改后静默失实;正是本 Agent Note 要治愈的病症。 - **宽松插值(未知引用保留原样或替换为空)**:一个拼写错误 `{{modle}}`(或一个空洞)会被发送给模型,直到 transcript(文本记录)审查时才会被发现。 - **在配置中为每个 subagent 实例编写措辞**:面向模型的行文回到每个部署 × 实例中,重蹈 P2 病症。**根据 provider 名称选择措辞**:`providerName` 本身是配置,重命名 provider 后会静默获得错误的措辞。 -- **在 `apply` 时解析 provider(加载顺序要求)** 与 **仅用 section 承载 subagent 措辞(在 assemble 时惰性解析)**:provider 生命周期事件的替代方案;两者均在 [provider-lifecycle-events Agent Note](2026-07-05-subagent-provider-lifecycle-events.md)中被否决。 +- **在 `apply` 时解析 provider(加载顺序要求)** 与 **仅用 section 承载 subagent 措辞(在 assemble 时惰性解析)**:provider 生命周期事件的替代方案;两者均在[提供方生命周期事件 Agent Note](2026-07-05-subagent-provider-lifecycle-events.md)中被否决。 ## 不在范围内 diff --git a/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml b/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml index 5d47778692..56f3e87525 100644 --- a/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-14-acp-agent-client-protocol.md: c6976ed28a254684fca62e2d309cdde7ea90340d -2026-06-14-acp-agent-client-protocol.zh.md: 711e8c2a7f7146494fa208942523e2ebfa1808a5 +2026-06-14-acp-agent-client-protocol.zh.md: 2bc6f71a8d370d65ccc3624724528a99f452bd9f diff --git a/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md b/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md index 711e8c2a7f..2bc6f71a8d 100644 --- a/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md +++ b/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md @@ -24,7 +24,7 @@ harness 最初仅通过 readline 循环暴露 agent。该接口能传输文本 工具调用的展示仍由工具自身负责。工具的 `presentCall` 和 `presentResult` 返回 `generic`、`terminal` 或 `diff` 渲染意图变体;桥接层对该联合类型做 switch 并映射到 ACP。没有 presenter 的工具获得通用回退。Bash 终端卡片使用 Zed 的能力门控约定 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit`;harness 仍通过 `ctx.bash` 执行命令,保留沙箱、环境清洗、所有权和 cwd。不支持该扩展的客户端收到普通文本内容。文件系统工具提供 diff 卡片和文件位置,桥接层中无需硬编码工具名分支。 -权限处理是 [user-approval seam](2026-07-06-approval-seam.md) 上的一个 answerer,而非 ACP 中的「每次工具调用都询问」策略。对桥接层所属 agent 且带有 call id 的 `approval/request`,会变为该 agent 编辑器会话上的 `session/request_permission`,提供一次性允许/拒绝选项。外部请求或无 call id 的请求委托给下游;缺失或失败的 answerer 保持 fail-closed。发起询问的插件(如预执行策略或 bash 升级)拥有「是否询问」的决策权。 +权限处理是[用户审批 seam](2026-07-06-approval-seam.md)上的一个 answerer,而非 ACP 中的「每次工具调用都询问」策略。对桥接层所属 agent 且带有 call id 的 `approval/request`,会变为该 agent 编辑器会话上的 `session/request_permission`,提供一次性允许/拒绝选项。外部请求或无 call id 的请求委托给下游;缺失或失败的 answerer 保持 fail-closed。发起询问的插件(如预执行策略或 bash 升级)拥有「是否询问」的决策权。 当 `ctx.permission` 被组合时,桥接层从部署的预设表中暴露一个 `permission` select。已发布的 `workspace-write` 和 `danger-full-access` 预设各自捆绑一个沙箱模式与一条审批策略;无法匹配的有效旋钮组合产生只能切走的 `custom` 状态。`session/set_config_option` 通过 `PermissionService.set()` 校验并写入两个所属旋钮事件。在开放轮次中的切换立即追加;空闲时的切换叠加在响应中,并在下一次 `agent/prompt-submit` 时锚定到开放轮次之前的请求组装阶段。在此之前它仅存于内存,因此崩溃后恢复的是持久化的折叠结果。ACP session mode 不被建模,因为 config option 是面向未来的协议表面;`AcpConfig.model` 保持连接级别。 diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml b/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml index 97e09d562e..3ac7ec65d0 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-15-code-mode.md: f403e87601aad0fda5d53ec5b94ba44452e79b49 -2026-06-15-code-mode.zh.md: b4b432a6ce2206ea4920f89275d431ed2d3d0c44 +2026-06-15-code-mode.zh.md: c119bcfc5edb3d94f80390a9c16bcb6246500ed0 diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md index b4b432a6ce..c119bcfc5e 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md @@ -48,7 +48,7 @@ Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一 **并发被序列化。** 每次 run 拥有一个分发队列,因此即使 `Promise.all` 也按提交顺序执行工具调用。结算时放弃尚未开始的排队调用。并行化需要每个工具的并发安全元数据。 -**呈现。** `run_code` 的 render intent 按 [render-intent Agent Note](../architecture/2026-07-02-tool-render-intent-union.md) 在此决定:`presentCall` → 一个 `generic` 卡片,`kind: 'execute'`,title = 程序文本,`rawInput` = 同一程序文本;`presentResult` → 一个 `generic` 卡片,content 为捕获的输出(来自 `meta`)。程序作为 title 是因为 ACP execute 卡片可靠地渲染该字段,而某些客户端会省略 body 和 raw-input 内容。这不是 `terminal` 卡片:该卡片的语义是「工作目录中的 shell 命令」,程序不是。 +**呈现。** `run_code` 的 render intent 按[呈现意图 Agent Note](../architecture/2026-07-02-tool-render-intent-union.md)在此决定:`presentCall` → 一个 `generic` 卡片,`kind: 'execute'`,title = 程序文本,`rawInput` = 同一程序文本;`presentResult` → 一个 `generic` 卡片,content 为捕获的输出(来自 `meta`)。程序作为 title 是因为 ACP execute 卡片可靠地渲染该字段,而某些客户端会省略 body 和 raw-input 内容。这不是 `terminal` 卡片:该卡片的语义是「工作目录中的 shell 命令」,程序不是。 ### 可观测性:`tool/code-dispatch` diff --git a/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml b/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml index 35f14a2678..c3ef031858 100644 --- a/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-17-filesystem-tool-schemas.md: fa23dccc7ae98a9c25b9c474a75dc1e2f8e5ff21 -2026-06-17-filesystem-tool-schemas.zh.md: 30acf26a9bb2858a9f786591b6e01626593713d0 +2026-06-17-filesystem-tool-schemas.zh.md: 79f172083fd2827eaa84489550577e10fd98c114 diff --git a/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md b/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md index 30acf26a9b..79f172083f 100644 --- a/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md +++ b/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md @@ -6,7 +6,7 @@ Status: implemented ## 问题 -[文件系统能力 seam Agent Note](../architecture/2026-06-17-filesystem-capability-seam.md) 定义了文件系统能力 seam(`ctx.fs`)、包(package)拆分(`dsh-fs`、`dsh-fs-local`、`dsh-tool-fs`,加上 `dsh-fs-policy` 策略插件),以及针对 read-before-write/edit 检查的 observed-file/stale-version 策略——[split-fs-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](../architecture/2026-06-26-file-context-as-event-gate.md) Agent Note 后来将其从 `ctx.fs` 移至 `dsh-fs-policy` 插件的 `fs/*` 事件门上。首次文件系统工具交付剩余的决策是面向模型的 schema 接口:模型在 `read`、`write` 和 `edit` 中看到哪些参数。 +[文件系统能力 seam Agent Note](../architecture/2026-06-17-filesystem-capability-seam.md) 定义了文件系统能力 seam(`ctx.fs`)、包(package)拆分(`dsh-fs`、`dsh-fs-local`、`dsh-tool-fs`,加上 `dsh-fs-policy` 策略插件),以及针对 read-before-write/edit 检查的 observed-file/stale-version 策略——[拆分文件系统 seam](../simplification/2026-06-26-fsspec-style-fs-seam.md)和[事件门控插件](../architecture/2026-06-26-file-context-as-event-gate.md) Agent Note 后来将其从 `ctx.fs` 移至 `dsh-fs-policy` 插件的 `fs/*` 事件门上。首次文件系统工具交付剩余的决策是面向模型的 schema 接口:模型在 `read`、`write` 和 `edit` 中看到哪些参数。 该 schema 应足够小,以便在 `dsh-tool-fs` 的首次实现中完成,但又足够稳定,使未来的本地/远程/沙箱文件系统后端不需要改动面向模型的接口。同时应避免从参考系统中照搬所有选项。Claude Code 和 OpenCode 暴露了类似的核心文件工具,但在命名风格和额外 flag 上有所不同;本 Agent Note 为原型选择最小的共有接口。 @@ -14,11 +14,11 @@ Status: implemented `@deepseek-ai/dsh-tool-fs` 在首个文件系统工具套件中暴露以下三个面向模型的工具: -| Tool | Our schema | Claude Code | OpenCode | Notes | Part of prototype | +| 工具 | 我们的 schema | Claude Code | OpenCode | 说明 | 原型包含 | |---|---|---|---|---|---| -| `read` | `read(file_path, offset?, limit?)` | `Read(file_path, offset?, limit?, pages?)` | `read(filePath, offset?, limit?)` | Files only; 1-indexed `offset`; no image/PDF/multimodal support in the first pass. | YES | -| `write` | `write(file_path, content)` | `Write(file_path, content)` | `write(content, filePath)` | Creates or overwrites UTF-8 text. Under the default fs-policy, updates to existing files require a prior observation; new-file creates do not. | YES | -| `edit` | `edit(file_path, old_string, new_string, replace_all?)` | `Edit(file_path, old_string, new_string, replace_all?)` | `edit(filePath, oldString, newString, replaceAll?)` | Literal string replacement; unique match required by default; under the default fs-policy requires a prior observation (any windowed read counts). | YES | +| `read` | `read(file_path, offset?, limit?)` | `Read(file_path, offset?, limit?, pages?)` | `read(filePath, offset?, limit?)` | 仅文件;`offset` 从 1 开始;首版不支持图片、PDF 或多模态内容。 | 是 | +| `write` | `write(file_path, content)` | `Write(file_path, content)` | `write(content, filePath)` | 创建或覆盖 UTF-8 文本。在默认 fs-policy 下,更新现有文件前必须先观测;创建新文件则不需要。 | 是 | +| `edit` | `edit(file_path, old_string, new_string, replace_all?)` | `Edit(file_path, old_string, new_string, replace_all?)` | `edit(filePath, oldString, newString, replaceAll?)` | 字面字符串替换;默认要求唯一匹配;在默认 fs-policy 下必须先观测(任意窗口读取均算作观测)。 | 是 | schema 使用 snake_case 字段名(`file_path`、`old_string`、`new_string`、`replace_all`),与 Claude Code 及现有 DeepSeek Harness 工具 schema 示例保持一致。消费方包将这些面向模型的名称转换为 `ctx.fs` 调用和 `fs/*` 事件分发。 @@ -74,11 +74,11 @@ schema 不将 `expected_hash`、`expected_version` 或 `create_only` 作为面 默认原生投影: -| Tool | Structured `ctx.fs` outcome consumed by `tool-fs` | Default model projection | +| 工具 | `tool-fs` 使用的结构化 `ctx.fs` 结果 | 默认模型投影 | |---|---|---| -| `read` | returned lines, returned line count, total line count, target display path, file version, partial-view flag | line-numbered text plus pagination footer | -| `write` | create/update operation, target display path, new file version | concise create/update success text | -| `edit` | replacement count, replace-all flag, target display path, new file version | concise edit success text | +| `read` | 返回的行、返回行数、总行数、目标显示路径、文件版本、部分视图标记 | 带行号的文本及分页页脚 | +| `write` | 创建/更新操作、目标显示路径、新文件版本 | 简洁的创建/更新成功文本 | +| `edit` | 替换次数、全量替换标记、目标显示路径、新文件版本 | 简洁的编辑成功文本 | 结构化结果不会重复模型参数(如 `file_path`、`old_string` 或 `content`),除非后端已将其解析为新信息(如 `displayPath`、`targetKey` 或新版本)。面向 token 的截断属于模型投影的职责,而非后端规范结果的一部分。 diff --git a/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml b/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml index 5ca5a1e59d..0852385897 100644 --- a/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-18-acp-terminal-and-tool-rendering.md: 166e52f8e659a78b1347279c61956ca1001e4939 -2026-06-18-acp-terminal-and-tool-rendering.zh.md: 924ea9fb50a77314748d4826b5c408d5243b32f9 +2026-06-18-acp-terminal-and-tool-rendering.zh.md: 1623c8f51f9a1e0aacf374d182ab1c74dfa407cc diff --git a/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md b/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md index 924ea9fb50..1623c8f51f 100644 --- a/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md +++ b/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md @@ -6,7 +6,7 @@ Status: implemented ## 问题 -ACP(Agent Client Protocol)桥接层允许每个工具通过 `presentCall`/`presentResult` 自行控制调用渲染(见 [tool-call UI presentation](2026-06-14-acp-agent-client-protocol.md) 与 `packages/core/tools`)。对于 `bash`,我们将确切命令作为 `tool_call` 标题呈现,模型的 `description` 作为一个内容文本块,`kind: 'execute'`,完成后的输出包裹在 ` ```console ` 围栏文本块中。 +ACP(Agent Client Protocol)桥接层允许每个工具通过 `presentCall`/`presentResult` 自行控制调用渲染(见[工具调用 UI 呈现](2026-06-14-acp-agent-client-protocol.md)与 `packages/core/tools`)。对于 `bash`,我们将确切命令作为 `tool_call` 标题呈现,模型的 `description` 作为一个内容文本块,`kind: 'execute'`,完成后的输出包裹在 ` ```console ` 围栏文本块中。 参考编辑器将终端元数据渲染为一张专用卡片,包含 cwd、命令、实时风格的输出和退出状态;纯文本则丢失了这些结构。命令之所以作为标题,是因为执行卡片隐藏原始输入,而人类可读的描述保留为卡片上方的独立块。 diff --git a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml index 56723c5c4c..afe78658ef 100644 --- a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-18-compaction-capability-seam.md: a263b5e7d0245bd1279024a50e05b2f33edad521 -2026-06-18-compaction-capability-seam.zh.md: 79c883c364c9045fa2f85e7743091f83f0553783 +2026-06-18-compaction-capability-seam.zh.md: b86393332592bd92f6e6be81d610370c8c2bb23e diff --git a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md index 79c883c364..b863933325 100644 --- a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md +++ b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md @@ -8,7 +8,7 @@ Status: implemented 长时间运行的 agent(智能体)对话会无限增长。随着事件日志不断累积轮次,派生出的消息历史最终逼近模型的上下文窗口,模型随即截断响应(`max-tokens`)或性能退化。**上下文压缩(context compaction)** 是对此的缓解手段:用一段简洁的摘要替换一批较早的历史,保持近期上下文完整。 -[session surface](../architecture/2026-06-18-session-surface.md) 正是为此而构建的基础设施:一份建立在事件日志之上的有序投影,带有专门设计的 `surfaceOp: { op: 'replace', start, end }` 操作,用于遮蔽一段条目并插入替换内容,`sourceEventSeqs` 记录溯源信息以便决策可确定性地回放。剩下的是那个*决定压缩什么、并产出摘要*的插件。 +[会话接口面](../architecture/2026-06-18-session-surface.md)正是为此而构建的基础设施:一份建立在事件日志之上的有序投影,带有专门设计的 `surfaceOp: { op: 'replace', start, end }` 操作,用于遮蔽一段条目并插入替换内容,`sourceEventSeqs` 记录溯源信息以便决策可确定性地回放。剩下的是那个*决定压缩什么、并产出摘要*的插件。 两股力量塑造了设计。第一,压缩策略与可复用的 token 测量独立变化:测量归 LLM 系列的 [`ctx.tokenMeter` 服务](../architecture/2026-07-15-replay-token-meter-service.md)所有,摘要生成则可以使用模型调用、模板或远程服务。第二,`SurfaceEventType` 封闭为五种事件类型(`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`);只有这些类型可以携带 `surfaceOp`。因此一个专用的 `compaction/*` 事件**不能**出现在 surface 上,编译器与 Session 始终启用的 append/seed 边界都会拒绝在其上附加 `surfaceOp`。 diff --git a/.agents/notes/implemented/feature/2026-06-30-hook-bridges.i18n.yaml b/.agents/notes/implemented/feature/2026-06-30-hook-bridges.i18n.yaml index 02ea526412..2aed6c1f15 100644 --- a/.agents/notes/implemented/feature/2026-06-30-hook-bridges.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-30-hook-bridges.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-30-hook-bridges.md: b6b0894e5551563187b1631e8c641e326fa166b0 -2026-06-30-hook-bridges.zh.md: 9b4ebfc0afaeed6e599f587d32ad2d2af43b6b68 +2026-06-30-hook-bridges.zh.md: 70d55c62f3d8e43af9deb0f847b1dec7dc474617 diff --git a/.agents/notes/implemented/feature/2026-06-30-hook-bridges.zh.md b/.agents/notes/implemented/feature/2026-06-30-hook-bridges.zh.md index 9b4ebfc0af..70d55c62f3 100644 --- a/.agents/notes/implemented/feature/2026-06-30-hook-bridges.zh.md +++ b/.agents/notes/implemented/feature/2026-06-30-hook-bridges.zh.md @@ -12,7 +12,7 @@ harness 的扩展面是其类型化的拦截 seam(见[拦截 seam Agent Note]( ## 决策 -`packages/hooks/` 组下两个独立插件,各为 function/namespace 插件(`name`/`inject`/`Config`/`apply`,无 default export——见 [postmortem 0001](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md)),仅注入 `bash`: +`packages/hooks/` 组下两个独立插件,各为 function/namespace 插件(`name`/`inject`/`Config`/`apply`,无 default export——见[事后复盘 0001](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md)),仅注入 `bash`: - **`dsh-hooks-claude`**——CC 方言。Claude Code 当前七个钩子点中的七个:`SessionStart`、`UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`Stop`、`SubagentStart` 和 `SubagentStop`。拥有 CC 形态的每事件 stdin payload(基础字段 `session_id`/`transcript_path`/`cwd`/`hook_event_name` 加每事件字段)、`CLAUDE_PROJECT_DIR` 环境变量加 `${CLAUDE_PLUGIN_ROOT}`/`${CLAUDE_PROJECT_DIR}` 替换,以及字面量或正则的匹配模式。`transcript_path` 是持久化定位器结果或 `''`;stdin 带有**尾部换行**。 - **`dsh-hooks-codex`**——Codex 当前五个钩子点中的五个:`PreToolUse`、`PostToolUse`、`SessionStart`、`UserPromptSubmit` 和 `Stop`。使用始终为正则的匹配模式、Codex 形态的 snake_case payload(含 `turn_id`/`model`/`permission_mode` 额外字段),写入时不带尾部换行,不注入 Codex 插件环境变量,不做配置时占位符替换,也没有 pre-tool 审批或重写路径。`transcript_path` 是同一定位器结果或 `null`;工具 payload 在精简后的 `tool_input: { command }` 形态中携带真实的 `tool_name`。 @@ -23,7 +23,7 @@ harness 的扩展面是其类型化的拦截 seam(见[拦截 seam Agent Note]( | Seam | CC | Codex | |---|---|---| -| `agent/session-start`(emit) | additionalContext → `agent.inject()` | plain-stdout output → additionalContext → `agent.inject()` | +| `agent/session-start`(emit) | additionalContext → `agent.inject()` | 纯 stdout 输出 → additionalContext → `agent.inject()` | | `agent/prompt-submit` | `deny`→`block`;仅上下文→delegate+fold | `block`→`block`;仅上下文→delegate+fold | | `tools/pre-execute` | `deny`→`deny`;`ask`→`ask` | `block`→`deny`(无 allow/ask) | | `tools/post-execute` | `deny`→`block`+feedback;仅上下文→delegate+fold | 同上 | diff --git a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml index 17679363d0..8f4da1a9fc 100644 --- a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-05-dynamic-workflows.md: 353ab56aaac2d0d7624ff35f03cc7073e50a1a7d -2026-07-05-dynamic-workflows.zh.md: aeb1f736c9674b37fcd249529e0f7dc4dac89cbb +2026-07-05-dynamic-workflows.zh.md: 7919fe12d1f1342738dafd8378c8c7f1dc932c0d diff --git a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md index aeb1f736c9..7919fe12d1 100644 --- a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md +++ b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md @@ -6,7 +6,7 @@ Status: implemented ## 问题 -harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`),但需要扇出到多个独立部分的工作——跨多文件审计、迁移、多角度调研、对抗式验证——迫使模型逐轮次编排:每个中间结果都落入父上下文,计划无处持久存储,每一步的协调都要消耗一次模型往返。Claude Code 以 [dynamic workflows](https://code.claude.com/docs/en/workflows) 的形式提供了这一能力:模型编写一段 JavaScript 编排脚本,运行时执行它,由脚本(而非对话)持有循环、分支和中间结果。 +harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`),但需要扇出到多个独立部分的工作——跨多文件审计、迁移、多角度调研、对抗式验证——迫使模型逐轮次编排:每个中间结果都落入父上下文,计划无处持久存储,每一步的协调都要消耗一次模型往返。Claude Code 以[动态工作流](https://code.claude.com/docs/en/workflows)的形式提供了这一能力:模型编写一段 JavaScript 编排脚本,运行时执行它,由脚本(而非对话)持有循环、分支和中间结果。 ## 决策 @@ -28,7 +28,7 @@ harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`) **为何选择 `node:worker_threads`**:每次运行获得一个非池化的 worker。vm 上下文限制了文档化的脚本表面,而 message-port RPC 将 `agent()` 桥接到宿主侧的子循环。worker 防止脚本的同步工作阻塞宿主,提供序列化边界,并允许取消后强制终止。`isolated-vm` 因其维护状态和部署要求被否决。 -宿主在发布前校验元数据并解析正文。私有枚举键 payload 映射定义协议格式;待启动记录、已发布子记录、单一取消信号、worker 死亡回收、结果优先级与 dispose 静默,在此协议上保持 subagent run 契约。这些竞态算法归 [agent-scope runtime-design Agent Note](../architecture/2026-07-12-agent-scope-runtime-design.md#workflow-children-are-pending-starts-or-published-records) 所有。 +宿主在发布前校验元数据并解析正文。私有枚举键 payload 映射定义协议格式;待启动记录、已发布子记录、单一取消信号、worker 死亡回收、结果优先级与 dispose 静默,在此协议上保持 subagent run 契约。这些竞态算法归[agent 作用域运行时设计 Agent Note](../architecture/2026-07-12-agent-scope-runtime-design.md#workflow-children-are-pending-starts-or-published-records)所有。 引擎暴露一条进程内 `MessageChannel` 测试路径,因为主进程 V8 覆盖率无法观测 worker 执行。 @@ -46,7 +46,7 @@ harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`) 输出 schema 使一次 schema 有效的已提交捕获成为子 agent 成功完成的必要条件。作用域运行时呈现捕获工具和指令,仅提交成功的最终结果(包括 SDK 调用时外层 `run_code` 的结果),在捕获变为 pending 后拒绝后续副作用,并在提交后不再进行模型步骤即停止子 agent。校验失败仍是可重试的工具错误;没有已提交捕获的正常完成以错误结算。 -`StructuredOutputSchema` 是 `dsh-tools` 中可强制执行的原始 JSON-Schema 子集(单字符串 `type`、`properties`/`required`/`additionalProperties`、`items`、标量 `enum`/`const`),不支持的关键字会大声失败,因为该协议数据会逐字成为捕获工具的 parameters。组装、提交、守卫和终止停止的正确性算法归 [agent-scope runtime-design Agent Note](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes) 所有。 +`StructuredOutputSchema` 是 `dsh-tools` 中可强制执行的原始 JSON-Schema 子集(单字符串 `type`、`properties`/`required`/`additionalProperties`、`items`、标量 `enum`/`const`),不支持的关键字会大声失败,因为该协议数据会逐字成为捕获工具的 parameters。组装、提交、守卫和终止停止的正确性算法归[agent 作用域运行时设计 Agent Note](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes)所有。 ## 测试 diff --git a/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml b/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml index 9257bc6041..905cfc1382 100644 --- a/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-06-sandbox.md: 738a1796b047561b861fc237154210659515bd6f -2026-07-06-sandbox.zh.md: 6843ef96413c00a12a2d1c6b70d2c5b90c6e02f7 +2026-07-06-sandbox.zh.md: ad7d7e83a1a17fffffd33ac09a7cc775c0eb4895 diff --git a/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md b/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md index 6843ef9641..ad7d7e83a1 100644 --- a/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md +++ b/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md @@ -107,7 +107,7 @@ interface SessionEventMap { 沙箱模式不在提示词中叙述;拒绝结果在需要时报告模式,避免基于常驻标签的预防性拒绝。批准策略不同:只有 `'never'` 被声明,因为自动拒绝在行为上与用户的「不」无法区分。策略变更通知被合并,由下一个 pre-step 递送,重启后有基于日志的回退。通知来源从事件位置推断:最后一个 request header 之后的旋钮事件是用户驱动的;未记录的漂移是运维人员或配置驱动的。 -**编辑器界面**是协议原生的 [Session Config Options](https://agentclientprotocol.com/protocol/session-config-options)——该规范对 session modes 的替代(计划在 ACP v2 中移除),已有 SDK 类型。当 `ctx.permission` 被组合时,bridge 在 `session/new` 和 `session/load` 中公布一个 `permission` 选择器(category `mode`);其选项是部署的 preset 表,其 `currentValue` 是 `PermissionService.current()` 对会话日志加组合默认值的结果。随附的 `workspace-write` 和 `danger-full-access` preset 各自捆绑一个沙箱模式与一个批准策略,并写入两个领域 setter;preset 表之外的旋钮组合报告为仅可切换离开的 `custom`。`session/set_config_option` 通过 permission 服务验证并切换,然后返回完整的刷新状态(规范契约)。 +**编辑器界面**是协议原生的[会话配置选项](https://agentclientprotocol.com/protocol/session-config-options)——该规范对 session modes 的替代(计划在 ACP v2 中移除),已有 SDK 类型。当 `ctx.permission` 被组合时,bridge 在 `session/new` 和 `session/load` 中公布一个 `permission` 选择器(category `mode`);其选项是部署的 preset 表,其 `currentValue` 是 `PermissionService.current()` 对会话日志加组合默认值的结果。随附的 `workspace-write` 和 `danger-full-access` preset 各自捆绑一个沙箱模式与一个批准策略,并写入两个领域 setter;preset 表之外的旋钮组合报告为仅可切换离开的 `custom`。`session/set_config_option` 通过 permission 服务验证并切换,然后返回完整的刷新状态(规范契约)。 **轮次封闭是提交边界。** 开放轮次中的切换立即追加。空闲切换保持在 bridge 记录上待定,在下一次 prompt 提交时、assembly 或执行之前追加到开放轮次中;每个旋钮以最后写入为准。开放性来自日志边界而非 `agent.status`,setter 不从 `session/event` 监听器内追加,因为那会重排后续观察者。锚定之前,响应叠加待定值。崩溃丢弃它,重新加载返回持久 fold。 diff --git a/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml b/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml index 6d5a63b85f..2db4756817 100644 --- a/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-07-mcp-client-plugin.md: 90c43383882034954f33b79459fac273e60b9e0e -2026-07-07-mcp-client-plugin.zh.md: 49cce88547eb731ae5b5bf168a7a0a4a785efe94 +2026-07-07-mcp-client-plugin.zh.md: 470d43ec8b4b1553304949278c26a6d1c9b9cc58 diff --git a/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.zh.md b/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.zh.md index 49cce88547..470d43ec8b 100644 --- a/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.zh.md +++ b/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.zh.md @@ -143,7 +143,7 @@ MCP 仅保证工具名在[单个服务器内](https://modelcontextprotocol.io/sp 1. 解析 `rawName`(执行器闭包持有它),以配置的超时时间调用 `client.callTool({ name: rawName, arguments }, { signal: exec.signal })`——公开名称永远不发送给服务器。 2. 映射结果: - 多个 `text` 内容块 → 以 `'\n'` 连接为单个 `TextBlock`(必要原因:`flattenText` 使用 `join('')` 无分隔符,多块会丢失块间边界)。 - - `image` 内容块 → 丢弃并 `ctx.logger.warn`(harness 没有图片内容块类型;[drop-image Agent Note](../simplification/2026-07-04-drop-image-content-block.md))。 + - `image` 内容块 → 丢弃并 `ctx.logger.warn`(harness 没有图片内容块类型;[删除图片 Agent Note](../simplification/2026-07-04-drop-image-content-block.md))。 - `isError: true` → 映射到 harness 的 `isError` 结果路径(`{ content: [...], isError: true }`)。 3. 取消:`exec.signal`(来自 agent loop(智能体循环)的取消)透传给 MCP SDK 的 `callTool`,后者向服务器发送 `$/cancelRequest`。 diff --git a/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml b/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml index bd5dda5aa4..fc808c5163 100644 --- a/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-03-documentation-graph-atlas.md: 9a30b13f9db6ceb2715517230e349cbe083850ec -2026-07-03-documentation-graph-atlas.zh.md: 438f1e6de696712d8dd2f1b503d15d1b42506cf9 +2026-07-03-documentation-graph-atlas.zh.md: d4259ea8d977d4966d6c909414bd0dc586a2d145 diff --git a/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.zh.md b/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.zh.md index 438f1e6de6..d4259ea8d9 100644 --- a/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.zh.md +++ b/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.zh.md @@ -38,11 +38,11 @@ Status: implemented | [tui-agent 应用组合](../../../../examples/tui-agent/composition.md) | 混合生成式 | `examples/tui-agent/cordis.yml` 插件列表,以及人工维护的应用/bundle 展开 | | [headless-agent 应用组合](../../../../examples/headless-agent/composition.md) | 混合生成式 | `examples/headless-agent/cordis.yml` 插件列表,以及人工维护的应用/bundle 展开 | | [cordis-agent 应用组合](../../../../examples/cordis-agent/composition.md) | 混合生成式 | `examples/cordis-agent/cordis.yml` 插件列表,以及人工维护的应用/bundle 展开 | -| [acp-agent 应用组合](../../../../examples/acp-agent/composition.md) | hybrid generated | `examples/acp-agent/cordis.yml` 插件列表加人工策划的应用/bundle 展开 | +| [acp-agent 应用组合](../../../../examples/acp-agent/composition.md) | 混合生成式 | `examples/acp-agent/cordis.yml` 插件列表加人工策划的应用/bundle 展开 | | [事件生产者/消费者矩阵](../../../../docs/event-producer-consumer.md) | 混合生成式 | Cordis 事件声明、经 AST 扫描的 `ctx.on/emit/parallel/serial/waterfall` 位置,以及显式动态分派覆盖 | | [agent turn 与 step 生命周期](../../../../docs/agent-lifecycle.md) | 人工维护 | architecture.md 循环生命周期、Cordis 目录链接,以及 session 事件语义 | | [工具执行管线](../../../../docs/tool-execution-pipeline.md) | 人工维护 | 工具管线语义与 `tools/execute` waterfall(瀑布式事件)| -| [ACP(Agent Client Protocol)快照回放](../../../../packages/ui/acp/snapshot-replay.md) | curated | 快照 harness 行为 | +| [ACP(Agent Client Protocol)快照回放](../../../../packages/ui/acp/snapshot-replay.md) | 人工策划 | 快照 harness 行为 | ### 为什么由生成器拥有文档 diff --git a/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml index aeda386ff4..caebea33ff 100644 --- a/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-19-drop-mutable-session-summary.md: 80fe043e365352b17d2a5b3efa1ab8d396d311c4 -2026-06-19-drop-mutable-session-summary.zh.md: ec98c19093369400b9b42a5c1a0590b5c6913ab9 +2026-06-19-drop-mutable-session-summary.zh.md: e2326c21681eaa7d0a325264c24f188379ec4b21 diff --git a/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md b/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md index ec98c19093..e2326c2168 100644 --- a/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md @@ -6,7 +6,7 @@ Status: implemented ## 问题 -[session-persistence seam](../architecture/2026-06-14-session-persistence.md) 将会话的日志外元数据拆分为 `dsh-session` 拥有的两种类型:一个不可变的 `SessionHeader`(`version`、`id`、`createdAt`、`cwd?`、`parentSession?`),在创建时一次性写入;一个可变的 `SessionSummary`(`updatedAt`、`title?`、`firstPrompt?`),「可在不触碰仅追加日志的情况下更新」。二者的联合类型为 `SessionMeta = SessionHeader & SessionSummary`,抽象的 `SessionPersistence` 服务为此多出第七个方法 `update(id, summary)`,用于重写摘要。各后端各自实现可变存储:JSONL 在日志旁写一个独立的原子 `.summary.json` **伴随文件**(临时写入 + rename,尽力保证);SQLite 在追加事务内更新 `updated_at`/`title`/`first_prompt` **列**。 +[会话持久化 seam](../architecture/2026-06-14-session-persistence.md)将会话的日志外元数据拆分为 `dsh-session` 拥有的两种类型:一个不可变的 `SessionHeader`(`version`、`id`、`createdAt`、`cwd?`、`parentSession?`),在创建时一次性写入;一个可变的 `SessionSummary`(`updatedAt`、`title?`、`firstPrompt?`),「可在不触碰仅追加日志的情况下更新」。二者的联合类型为 `SessionMeta = SessionHeader & SessionSummary`,抽象的 `SessionPersistence` 服务为此多出第七个方法 `update(id, summary)`,用于重写摘要。各后端各自实现可变存储:JSONL 在日志旁写一个独立的原子 `.summary.json` **伴随文件**(临时写入 + rename,尽力保证);SQLite 在追加事务内更新 `updated_at`/`title`/`first_prompt` **列**。 摘要是为未来的会话选择器设计的(通过 `updatedAt` 排序近期会话,用 `title`/`firstPrompt` 做预览)。该选择器从未实现。对整个仓库的审计表明,`SessionSummary` 的全部表面积都是**死状态**: diff --git a/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml index 9de0d532bc..12bf20b67f 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-trim-acp-bridge-unreachable-surface.md: ce0c623930192d02c8347c3956c497ee13048904 -2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: ea94f28b4802c18394cc3f6e6d4bdfa8702dae2b +2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: 31027db1f3b5f79a9566a2fa3ccda787b52960e7 diff --git a/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md b/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md index ea94f28b48..31027db1f3 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md @@ -9,7 +9,7 @@ Status: implemented `dsh-acp` 有两处对外表面在任何已交付的配置中都不可达: 1. **`AcpConfig.agentName` / `agentVersion`**(`packages/ui/acp/src/index.ts`)。已发布应用包只向 bridge 传递 `{ model }`(`packages/examples/acp-demo/src/index.ts`),因此没有任何叶子 `cordis.yml`——唯一的生产配置表面——能够设置这些配置项;只有直接挂载 bridge 才能设置它们,而这种做法只存在于一个单元测试中。每份快照预期输出——包括 hook 矩阵场景——都固定 schema 默认值(`deepseek-harness-acp` / `0.0.1`)。这对配置项还带有一个尚未解决的 `TODO(double-default)`:字面量存在两次(schema `.default(...)` 加 `??` 后备值),TODO 要求为它们选择一个归属。 -2. **`toolKindFor` 名称启发式**(同一文件)在通用回退路径中对 `bash*`/`read*`/`write`/`edit*` 工具名做了特殊处理。自 [render-intent union](../architecture/2026-07-02-tool-render-intent-union.md) 以来,这些分支匹配到的每个第一方工具都自带 `presentCall` 并携带其 kind,而没有 presenter 的生产工具(`subagent`、`subagent_fork`)本来就落入 `other`。这些分支只有在工具拒绝自行呈现调用时才在生产中可达:`presentCall` 抛出异常(容错回退),或模型参数未通过工具 schema 导致 `defineTool` 的 `presentCall` 包装层返回 `undefined`(例如 `bash` 调用缺少必需的 `description`)。而桥接层自身的模块文档明确声明了该启发式所违反的设计规则:"桥接层绝不对工具名做特殊处理"。 +2. **`toolKindFor` 名称启发式**(同一文件)在通用回退路径中对 `bash*`/`read*`/`write`/`edit*` 工具名做了特殊处理。自[render-intent 联合类型](../architecture/2026-07-02-tool-render-intent-union.md)以来,这些分支匹配到的每个第一方工具都自带 `presentCall` 并携带其 kind,而没有 presenter 的生产工具(`subagent`、`subagent_fork`)本来就落入 `other`。这些分支只有在工具拒绝自行呈现调用时才在生产中可达:`presentCall` 抛出异常(容错回退),或模型参数未通过工具 schema 导致 `defineTool` 的 `presentCall` 包装层返回 `undefined`(例如 `bash` 调用缺少必需的 `description`)。而桥接层自身的模块文档明确声明了该启发式所违反的设计规则:"桥接层绝不对工具名做特殊处理"。 ## 决策 diff --git a/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml b/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml index 3ad2200f26..00899acd09 100644 --- a/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-22-fork-child-replay-seed-boundary.md: d3cbbb1dae1d64a10973bd5895ccc47d877eba28 -2026-06-22-fork-child-replay-seed-boundary.zh.md: 7137256f0e1f34a2da928b966d170d054f18ddde +2026-06-22-fork-child-replay-seed-boundary.zh.md: 8af1ba869ba5484442a6575f78556f47abe99d22 diff --git a/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md b/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md index 7137256f0e..8af1ba869b 100644 --- a/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md +++ b/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md @@ -35,7 +35,7 @@ subagent 脚本由 [`deriveReplayScript`](../../../../packages/support/llm-repla `dsh-llm-replay` 的 `parseSessionHeader` 现在也读取 `seedLength`(缺失则为 0),`loadSessionScripts` 从 `parseSessionLog(text).slice(seedLength)` 推导子会话条目——即边界及之后的事件,也就是子会话自身的模型调用。对 spawn 子会话而言 `seedLength` 为 0,此操作是空操作,spawn 场景逐字节不变。 -这关闭了路由正确性的缺口,两个已录制的 fork 场景对其进行端到端验证——见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md)。 +这关闭了路由正确性的缺口,两个已录制的 fork 场景对其进行端到端验证——见[记录 fork 与混合 spawn+fork 快照场景](2026-06-22-fork-snapshot-scenarios.md)。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml b/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml index 479d521c97..c9f3fa8acc 100644 --- a/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-22-subagent-snapshot-replay.md: 4aad8b6ddd3e4f8b8ad5565e10b263953d81ea31 -2026-06-22-subagent-snapshot-replay.zh.md: 9d31e4d7f8e65b8442a94dee154ff1d3a5631651 +2026-06-22-subagent-snapshot-replay.zh.md: 77a4302fe3aa529972195f87306b24493bbcdd06 diff --git a/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md b/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md index 9d31e4d7f8..77a4302fe3 100644 --- a/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md +++ b/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md @@ -54,5 +54,5 @@ Status: implemented - `TODO(subagent-snapshots)` 延期项已解决:嵌套 agent 的 transcript 现在是快照层的一等形态。 - `GenerateOptions.sessionId` 是一个小而诚实的 core-seam 新增,在回放之外同样有用(遥测、请求路由)。 -- `subagent` 工具绑定到单一提供方,因此 `subagent-multi` 中的两个子 agent 都是 spawn(全新创建)。键控按会话路由而非按后端路由,因此对 fork 同样正确。但脚本*派生*逻辑此前不正确:fork 子会话的日志以种子化的父前缀(父会话的 `assistant/chunk` 事件)开头,如果从完整日志派生脚本,就会把父 agent 的响应当作子 agent 的来回放。这一正确性缺口通过持久化种子边界来弥合——见 [Persist the seed boundary so fork-child replay routes correctly](2026-06-22-fork-child-replay-seed-boundary.md)——录制的 fork 与混合 spawn+fork 场景现在通过一份 transcript 同时验证两种传输方式(见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md))。 +- `subagent` 工具绑定到单一提供方,因此 `subagent-multi` 中的两个子 agent 都是 spawn(全新创建)。键控按会话路由而非按后端路由,因此对 fork 同样正确。但脚本*派生*逻辑此前不正确:fork 子会话的日志以种子化的父前缀(父会话的 `assistant/chunk` 事件)开头,如果从完整日志派生脚本,就会把父 agent 的响应当作子 agent 的来回放。这一正确性缺口通过持久化种子边界来弥合——见[持久化种子边界,使 fork 子项重放能够正确路由](2026-06-22-fork-child-replay-seed-boundary.md)——录制的 fork 与混合 spawn+fork 场景现在通过一份 transcript 同时验证两种传输方式(见[记录 fork 与混合 spawn+fork 快照场景](2026-06-22-fork-snapshot-scenarios.md))。 - 进程外(ACP(Agent Client Protocol))subagent 是完全不同的回放形态(每个子 agent 是自己的进程、有自己的回放),作为 `TODO(acp-subagent-replay)` 记录在 PR3 计划中。 diff --git a/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml b/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml index dd6683aaa3..a6cdff0d66 100644 --- a/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml +++ b/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-16-typed-event-schemas.md: 97a7d0c3787eb5556696e25a6c8b1bb75642aba9 -2026-06-16-typed-event-schemas.zh.md: f79a607eaa723c00b00e984e1a6983d24d99c127 +2026-06-16-typed-event-schemas.zh.md: a02ff8ed54a1d8ea02690c4b6ceaeef4338d3123 diff --git a/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.zh.md b/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.zh.md index f79a607eaa..a02ff8ed54 100644 --- a/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.zh.md +++ b/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.zh.md @@ -32,7 +32,7 @@ harness 将其核心词汇——内容块、消息来源、结束原因、轮次 - **事件生产者**——agent loop(智能体循环)中 16 处 `session.append(...)` 调用——形状不变,但现在在边界处被校验。 - **约 7 个 switch 消费方**,对这些联合类型进行分支:`deriveMessages` 与包自有的不变式 companion(`dsh-session`)、`BlockAssembler`(`dsh-llm`)、两个 LLM(大语言模型)适配器(`dsh-llm-deepseek`、`dsh-llm-pi-ai`)以及工具 schema 层(`dsh-tools`)。`assertNever` 对封闭联合类型的穷举 vs 对可扩展联合类型的 fall-through 约定(一条已记录的 lint 规则)需要重新考量——运行时变体在静态层面不可穷举。 - **`defineTool` 的 `InferArgs` DSL**(`dsh-tools`),它从编译期 schema 规范派生出零类型转换的 `execute` 参数类型——这是当前方案的标杆用例。 -- **文档**:architecture.md(该模式被描述为基础性的)、[dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md),以及所有引用该模式的 Agent Note。 +- **文档**:architecture.md(该模式被描述为基础性的)、[开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md),以及所有引用该模式的 Agent Note。 这是一次仓库级别的词汇重新设计,而非持久化的实现细节。 diff --git a/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml b/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml index 08f5e8380e..a7ee5ef34a 100644 --- a/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml +++ b/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-08-interactive-side-sessions.md: dfd325babe215782c9c1cbec3fd9f874783af7ab -2026-07-08-interactive-side-sessions.zh.md: d545f65a821c6057b062300f31c415a2d7f63860 +2026-07-08-interactive-side-sessions.zh.md: 6a1d11c0566a36fcbf882daad0b26590460e1534 diff --git a/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.zh.md b/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.zh.md index d545f65a82..6a1d11c056 100644 --- a/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.zh.md +++ b/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.zh.md @@ -6,7 +6,7 @@ Status: proposed ## 问题 -用户可能希望在不改变当前会话主上下文的前提下,探索一个来自活跃会话的问题。现有原语无法提供这种产品形态:[session-store fork](../../implemented/feature/2026-06-30-session-store-fork-api.md) 创建的是一个无关联的会话,而 [fork subagent](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 是模型驱动的任务,其 transcript(文本记录)会折叠为一条工具结果。两者都不能给用户一个独立的对话,也都不能将结论带着出处信息记录回父会话。 +用户可能希望在不改变当前会话主上下文的前提下,探索一个来自活跃会话的问题。现有原语无法提供这种产品形态:[会话存储 fork](../../implemented/feature/2026-06-30-session-store-fork-api.md)创建的是一个无关联的会话,而 [fork subagent](../../implemented/feature/2026-06-21-subagent-capability-seam.md)是模型驱动的任务,其 transcript(文本记录)会折叠为一条工具结果。两者都不能给用户一个独立的对话,也都不能将结论带着出处信息记录回父会话。 ## 提案 diff --git a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml index 89414acd96..03c09bb8df 100644 --- a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml +++ b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-immutable-public-surfaces.md: c9009ad923720efaecb25e2017ceab6e3eb0dbf4 -2026-06-11-immutable-public-surfaces.zh.md: 2516450c61eab399b2cb64862af164289eb87fbe +2026-06-11-immutable-public-surfaces.zh.md: 7ed778505547fc91077a7e201a62123c8418e5f1 diff --git a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md index 2516450c61..7ed7785055 100644 --- a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md +++ b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md @@ -1,6 +1,6 @@ # Agent Note: 深度只读的公开接口 -Status: rejected — the pervasive `DeepReadonly` type flip is replaced by source-owned runtime immutability in `Session` plus relational development assertions. See [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md). +Status: rejected — 普遍采用 `DeepReadonly` 的类型翻转已由 `Session` 中归属源的运行时不可变性与关系型开发断言取代。见[归属源的会话不可变性与开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)。 [English](2026-06-11-immutable-public-surfaces.md) | 中文 diff --git a/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml b/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml index c19ca144a0..512afb19c3 100644 --- a/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml +++ b/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-providerless-example-base.md: 2f41476a487775e6f9da2f113efe566e44786ff3 -2026-06-20-providerless-example-base.zh.md: 61d9f819b530fa9a15e8ed5b9d3f13f945e10b82 +2026-06-20-providerless-example-base.zh.md: ebe97db5a6cf194131239271e2713a1b0d14fc2a diff --git a/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.zh.md b/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.zh.md index 61d9f819b5..ebe97db5a6 100644 --- a/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.zh.md +++ b/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.zh.md @@ -1,6 +1,6 @@ # Agent Note: 使共享示例基础配置与提供方无关 -Status: rejected — superseded by [Extract example apps into packages](../../implemented/architecture/2026-06-20-extract-example-app-packages.md), which moves the spine into a `dsh-agent-spine-demo` bundle and deletes the `base*.yml` files, so there is no shared base YAML left to rename. +Status: rejected — 已由[将示例应用提取到 packages 中](../../implemented/architecture/2026-06-20-extract-example-app-packages.md)取代;后者把 spine 移入 `dsh-agent-spine-demo` bundle 并删除 `base*.yml` 文件,因此已不存在可重命名的共享基础 YAML。 [English](2026-06-20-providerless-example-base.md) | 中文 diff --git a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.i18n.yaml b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.i18n.yaml index 306dac3774..0ea6f9f843 100644 --- a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.i18n.yaml +++ b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-generate-agent-note-index-tables.md: 6e5221f018942a0629f30b6e6f22cedfb9f4145e -2026-07-04-generate-agent-note-index-tables.zh.md: f299fc5c2df25064a2712fa177fdbe5b73ffc7ca +2026-07-04-generate-agent-note-index-tables.zh.md: 572b6c743b661075f37e8602a81e0ceb800921a5 diff --git a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.zh.md b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.zh.md index f299fc5c2d..572b6c743b 100644 --- a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.zh.md +++ b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.zh.md @@ -1,6 +1,6 @@ # Agent Note: 生成 Agent Note 索引表 -Status: rejected — a centralized generated list is merge-prone and adds little discovery value +Status: rejected — 集中生成的列表容易产生合并冲突,且几乎不增加发现价值 [English](2026-07-04-generate-agent-note-index-tables.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml index adeb1b14f9..034b4df2e0 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-assembled-assistant-messages-only.md: ba8135a3d63f292cfedd23de8b4b9d43b4455e8c -2026-06-20-assembled-assistant-messages-only.zh.md: 963d807afef29a3f7d8f0f57fc89ef7f6f3187c4 +2026-06-20-assembled-assistant-messages-only.zh.md: ef24a2eafbdeb71c7637f52804892abaa8e80fa6 diff --git a/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md b/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md index 963d807afe..ef24a2eafb 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md @@ -1,6 +1,6 @@ # Agent Note: 仅持久化组装后的 assistant 消息,不存储流式分片 -Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement. +Status: rejected — 高保真 chunk 重放、部分失败流与快照重放目前依赖持久化的 `assistant/chunk` 事件。只有具备不丢失信息的重放/artifact 替代方案后,才能删除 chunk。 [English](2026-06-20-assembled-assistant-messages-only.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml index 052b380049..174d0802cd 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-acp-session-load.md: 2b6edf173506929f2d64e910b47aa70fb4f1d854 -2026-06-20-drop-acp-session-load.zh.md: 8e7a4ed6d7d1ccc89da3340907c11d1cf35505bd +2026-06-20-drop-acp-session-load.zh.md: c63ac09903ecfa1aaad44d41e70e452bdcb17bf3 diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md index 8e7a4ed6d7..c63ac09903 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md @@ -1,6 +1,6 @@ # Agent Note: 移除 ACP session/load,直到恢复具备产品形态 -Status: rejected — Zed is the current target ACP client, advertises and exercises load-capable sessions, and keeps pending-load state for concurrent `session/load`. The bridge should keep `session/load` and make the resume contract solid. +Status: rejected — Zed 是当前目标 ACP 客户端,它声明并实际使用支持加载的会话,还为并发的 `session/load` 保留待加载状态。桥接层应保留 `session/load` 并巩固恢复契约。 [English](2026-06-20-drop-acp-session-load.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml index 6ead85178e..f3b457a8b2 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-acp-terminal-meta.md: 79da387ac1a7a0e6767e3bf24baa6039e39ef90d -2026-06-20-drop-acp-terminal-meta.zh.md: 5aa455959c403d7e03b36be0d4336fdc5389c52e +2026-06-20-drop-acp-terminal-meta.zh.md: e34cd0690beed5d3a1715db6bc3e8413e6227440 diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md index 5aa455959c..e34cd0690b 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md @@ -1,6 +1,6 @@ # Agent Note: 移除 ACP 终端 `_meta` 渲染 -Status: rejected — Zed is the current target client, and the terminal `_meta` convention is intentional Zed UX with a plain ACP fallback for other clients. +Status: rejected — Zed 是当前目标客户端,terminal `_meta` 约定是有意设计的 Zed UX,同时为其他客户端保留普通 ACP 回退。 [English](2026-06-20-drop-acp-terminal-meta.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml index 676d14dd4e..514662e600 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-bash-output-spill-files.md: b2bd1a04ee1524bab29814ffa7c22712a83ee5f7 -2026-06-20-drop-bash-output-spill-files.zh.md: c8c0df30eda2ab6800d1e8f814d05f8f15103fd2 +2026-06-20-drop-bash-output-spill-files.zh.md: 4a2a8e7d3b0477c0a221e9fe6abe879cfa513aeb diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md b/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md index c8c0df30ed..4a2a8e7d3b 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md @@ -1,6 +1,6 @@ # Agent Note: 移除 bash 完整输出溢出文件 -Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output. +Status: rejected — 完整输出恢复是真实的 bash 行为。未来的 artifact/blob 服务或许能将其泛化,但在替代方案就位前删除溢出文件会丢失有用的命令输出。 [English](2026-06-20-drop-bash-output-spill-files.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml index d91be8381f..b5462fbea8 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-durable-step-boundaries.md: c5c4f269a378e334c4dc509d1288146d77d9a520 -2026-06-20-drop-durable-step-boundaries.zh.md: 7724a8f6c2c51650eb9ea0a6675ece7c24a211d8 +2026-06-20-drop-durable-step-boundaries.zh.md: e98f5e479cdef43bf134e3e2d240ce0f3be7ce0e diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md b/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md index 7724a8f6c2..e98f5e479c 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md @@ -1,6 +1,6 @@ # Agent Note: 移除持久化的步骤边界事件 -Status: rejected — `step/end` is the durable indication that a model step finished, and keeping the symmetric `step/start` / `step/end` pair makes crash repair, invariants, and transcript inspection clearer than inferring completion from adjacent step-scoped events. +Status: rejected — `step/end` 是 model step 已完成的持久信号;保留对称的 `step/start` / `step/end` 对,比从相邻的 step-scoped 事件推断完成状态更便于理解崩溃修复、不变式与 transcript 检查。 [English](2026-06-20-drop-durable-step-boundaries.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml index c65ced3c8b..a5b3ffc665 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-unused-session-lineage.md: 605f1949999435b24404e0c5a72320416303ae52 -2026-06-20-drop-unused-session-lineage.zh.md: 5d37a287fe1cb2d3cf196a6779dc11702826fa4a +2026-06-20-drop-unused-session-lineage.zh.md: f49e9af0fe22be41228b058f5c700815cc7aa893 diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md b/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md index 5d37a287fe..f49e9af0fe 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md @@ -1,6 +1,6 @@ # Agent Note: 移除未使用的会话血缘元数据 -Status: rejected — `parentSession` is part of the documented fork/sub-agent seam and is already preserved by the agent/session resume path. The field is future-facing, but it is not accidental dead state. +Status: rejected — `parentSession` 是已记录的 fork/subagent seam 的一部分,并已由 agent/session 恢复路径保留。该字段面向未来,但并非意外遗留的死状态。 [English](2026-06-20-drop-unused-session-lineage.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml index 1cea1f5177..76c31d49a5 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-fold-session-persistence-interface.md: 895b868b2a80d8655284bae1364a85e19e174da7 -2026-06-20-fold-session-persistence-interface.zh.md: 12c710d2235ff25c2c961cfdac31c0c01c3afdda +2026-06-20-fold-session-persistence-interface.zh.md: 8b1d87431b27d91c9b9765055d783dea940b981d diff --git a/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md b/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md index 12c710d223..8b1d87431b 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md @@ -1,6 +1,6 @@ # Agent Note: 将持久化接口合并进 dsh-session -Status: rejected — the separate persistence interface package is the intended modular capability seam for durable backends. Folding it into `dsh-session` would reduce package count at the cost of a cleaner backend boundary. +Status: rejected — 独立的持久化接口包是为持久后端设计的模块化能力 seam。将其折叠进 `dsh-session` 虽能减少包数量,却会牺牲更清晰的后端边界。 [English](2026-06-20-fold-session-persistence-interface.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml index 8001c0937f..a95113afcc 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-generic-tool-rendering.md: 6fc610546da04e7d1e16fc17ada87483a142aa3c -2026-06-20-generic-tool-rendering.zh.md: e19907b71dcb93d325f94695c05bda23fca254cc +2026-06-20-generic-tool-rendering.zh.md: 4310e35a71fb13dfe1b00190da444a56bc8b4e81 diff --git a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md index e19907b71d..4310e35a71 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md @@ -1,6 +1,6 @@ # Agent Note: 收拢工具自有的 UI 展示逻辑 -Status: rejected — tool-owned presentation should wait for more real tools before being generalized or deleted. Bash and ACP currently need the existing richer presentation path. +Status: rejected — 工具拥有的呈现机制应等到出现更多真实工具后再进行泛化或删除。Bash 与 ACP 目前仍需要现有的丰富呈现路径。 [English](2026-06-20-generic-tool-rendering.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml index 73df65d34f..e591923f6e 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-retire-mid-turn-steering.md: a8812b3222739244d77f4d4dab60cf7c0cd6907d -2026-06-20-retire-mid-turn-steering.zh.md: 6beb00a646fd16b7bd9d987fb28429771145d6fc +2026-06-20-retire-mid-turn-steering.zh.md: c4de65bc763344ed4a060244515a403b695d7fd9 diff --git a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md index 6beb00a646..c4de65bc76 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md @@ -1,6 +1,6 @@ # Agent Note: 移除轮次中途引导 -Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. +Status: rejected — mid-turn steering 是一项有意设计的 agent 能力,用于接收 between-step 的用户/插件输入以及未来的 goal/loop 工作流。它是面向产品方向的复杂度,而非 `send()` 的意外重复。 [English](2026-06-20-retire-mid-turn-steering.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml index c4b40325a3..550a17a6b1 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-single-session-acp-bridge.md: e99de76854390a0979d1b66866d1d48aacbc0036 -2026-06-20-single-session-acp-bridge.zh.md: 1db5484c014178dfedceab20221a3d317877c35f +2026-06-20-single-session-acp-bridge.zh.md: e4c9a4c9371749f02a4a7c4f55d724ba4641e2c0 diff --git a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md index 1db5484c01..e4c9a4c937 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md @@ -1,6 +1,6 @@ # Agent Note: 将 ACP 桥接恢复为每连接一个活跃会话 -Status: rejected — Zed is the current target ACP client and its ACP implementation is explicitly multi-session: it stores live sessions in a `HashMap`, tracks `pending_sessions`, joins concurrent loads for the same id, and tests close-during-load behavior. +Status: rejected — Zed 是当前目标 ACP 客户端,其 ACP 实现明确支持多会话:它把活跃会话存入 `HashMap`,跟踪 `pending_sessions`,合并同一 id 的并发加载,并测试加载期间关闭的行为。 [English](2026-06-20-single-session-acp-bridge.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml index eae5710a9a..1861fcb961 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-truncate-interrupted-turns.md: af18618ad4c41af125e37c51b9fd971dd8eae64e -2026-06-20-truncate-interrupted-turns.zh.md: 4deebfcc7417dd860c655813230d3a79b2d98c50 +2026-06-20-truncate-interrupted-turns.zh.md: a6c7d1df32d444d301635665afb4fe3b0c4ac5af diff --git a/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md b/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md index 4deebfcc74..a6c7d1df32 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md @@ -1,6 +1,6 @@ # Agent Note: 加载时截断被中断的最终轮次 -Status: rejected — a single turn can contain substantial real work, including many steps and large tool output. Preserving interrupted turns is preferable to silently dropping that tail on load. +Status: rejected — 单个 turn 可以包含大量真实工作,包括多个 steps 和大量工具输出。保留被中断的 turns,优于在加载时静默丢弃这段尾部。 [English](2026-06-20-truncate-interrupted-turns.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml index fa0ab68ede..61d489a85c 100644 --- a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-prune-unimplemented-subagent-vocabulary.md: f99a33163b48735f9634b5bb3dcac5c24eb893f8 -2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: a1a2f35ad31a0c40d82cff00df582a488619c241 +2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: 15368b0a8abb2980af255827498803b8bb6645f7 diff --git a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md index a1a2f35ad3..15368b0a8a 100644 --- a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md +++ b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md @@ -1,6 +1,6 @@ # Agent Note: 裁剪未实现的 subagent seam 词汇 -Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below records the decision-time state. +Status: rejected — 延后的能力词汇(`outputSchema`/`structured`、`toolFilter`、`sendMessage`/`resume`)是有意保留的接口面:该接缝按设计先于实现声明完整的预期契约,使提供方与消费方沿稳定形状演进,而非针对每项能力重新协商。下方的消费方证据分析记录了决策时的状态。 [English](2026-07-04-prune-unimplemented-subagent-vocabulary.md) | 中文 @@ -19,7 +19,7 @@ Status: rejected — the deferred capability vocabulary (`outputSchema`/`structu **保留** `depthLimit`/`maxDepth` 与能力检查。进程内后端已强制执行该限制,尽管当前发布的工具尚未设置它。递归是已知的 seam 风险,因此恰当的后续工作是提供一个工具默认值,而非删除正在工作的强制逻辑。 -审视过但有意不动的相邻接口面:`SubagentService.getProvider()`/`list()` 仅有测试 harness 消费方,但 [prune-dead-seam-methods 实现说明](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md) 恰好记录了这种形态从 bash executor 中被移除后又被回退的经过——对于一个基于已跟踪 map 的单行访问器而言,测试 harness 就是消费方。`SubagentRunEndInfo.lastAssistantMessage` 是一个已记录的保留项([subagent-observe-enrich Agent Note](../../implemented/feature/2026-06-30-subagent-observe-enrich.md) 的评审删除了 `agentType` 但有意保留了它,因为它是进程外子 agent(智能体)唯一的最终消息通道);它当前未接通的桥接转发是一个待补的缺口或待记录的消费方,不是本 Agent Note 要裁剪的接口面。 +审视过但有意不动的相邻接口面:`SubagentService.getProvider()`/`list()` 仅有测试 harness 消费方,但 [prune-dead-seam-methods 实现说明](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md)恰好记录了这种形态从 bash executor 中被移除后又被回退的经过——对于一个基于已跟踪 map 的单行访问器而言,测试 harness 就是消费方。`SubagentRunEndInfo.lastAssistantMessage` 是一个已记录的保留项([subagent 观测/丰富化 Agent Note](../../implemented/feature/2026-06-30-subagent-observe-enrich.md)的评审删除了 `agentType` 但有意保留了它,因为它是进程外子 agent(智能体)唯一的最终消息通道);它当前未接通的桥接转发是一个待补的缺口或待记录的消费方,不是本 Agent Note 要裁剪的接口面。 这是[从持久化 seam 裁剪死方法](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md)在 seam 词汇层面的回响:每个实现都必须为无人声明的成员,甚至更弱,因为这里连一个实现都没有。 diff --git a/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml b/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml index 34f8bdb0c9..53028cf3a3 100644 --- a/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-12-collapse-workflow-to-foreground-core.md: 629e2140523c3ae7caf533de99821206d05f1b8e -2026-07-12-collapse-workflow-to-foreground-core.zh.md: 3cdaeebe42ca799a48c5321b70c07e6151d8f98d +2026-07-12-collapse-workflow-to-foreground-core.zh.md: 79eb61653e812647082ba6ebcb7f0636db6e0240 diff --git a/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md b/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md index 3cdaeebe42..79eb61653e 100644 --- a/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md +++ b/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md @@ -1,6 +1,6 @@ # Agent Note: 将工作流收缩至已使用的前台核心 -Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it. +Status: rejected — 工作流进度是有意设计的观测接口面;应通过消费方使其发挥作用,而非删除它。 [English](2026-07-12-collapse-workflow-to-foreground-core.md) | 中文 diff --git a/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml b/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml index d1a52c0efb..c28461d08b 100644 --- a/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-12-prune-unused-skill-registry-surface.md: 5a13effa04a6cd9954741a0a33ebc6fc3512fab8 -2026-07-12-prune-unused-skill-registry-surface.zh.md: 4b25c03d740f4fda1696629d56b88057a055f0af +2026-07-12-prune-unused-skill-registry-surface.zh.md: 6d917fadf3d408c934e88b2bd0a9c7691632f91b diff --git a/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md b/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md index 4b25c03d74..6d917fadf3 100644 --- a/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md +++ b/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md @@ -1,6 +1,6 @@ # Agent Note: 裁剪 skill 注册表中未使用的接口 -Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins. +Status: rejected — 直接在运行时注册 skill 是为第三方插件保留的有意扩展路径。 [English](2026-07-12-prune-unused-skill-registry-surface.md) | 中文 From 6ad8e4501f601d95a9b7a8df71e8c2f958cdeb3e Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:21:14 +0800 Subject: [PATCH 124/368] fix(pty): retain cleanup evidence through policy --- ...26-07-16-persistent-pty-sessions.i18n.yaml | 4 +-- .../2026-07-16-persistent-pty-sessions.md | 4 +-- .../2026-07-16-persistent-pty-sessions.zh.md | 4 +-- docs/cordis-catalog/services.md | 2 +- docs/event-producer-consumer.md | 4 +-- packages/pty/pty/README.md | 1 + packages/pty/pty/src/index.ts | 14 ++++++-- packages/pty/pty/tests/service.spec.ts | 35 +++++++++++++++++++ packages/pty/tool-pty/README.md | 6 ++-- packages/pty/tool-pty/src/index.ts | 27 ++++++++------ packages/pty/tool-pty/tests/tools.spec.ts | 31 ++++++++++++++++ 11 files changed, 106 insertions(+), 26 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index 426b1180b0..f772b6d5e6 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml @@ -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 -2026-07-16-persistent-pty-sessions.md: ba8d8579c107f89f83b2a9ab40298ac876df4521 -2026-07-16-persistent-pty-sessions.zh.md: 44e66094b905560e0cd5f3c30204e46e93351791 +2026-07-16-persistent-pty-sessions.md: 8a9ec669a064924ecdb9693fff5c4cafea59d90c +2026-07-16-persistent-pty-sessions.zh.md: 157bee408d041b5c373dd2a4d41f82de90a67e0e diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index ba8d8579c1..8a9ec669a0 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -34,7 +34,7 @@ Idle detection is backend behavior, not a second public seam. A remote or contai There are no plugin-load auto-start sessions. `terminal_open` creates a session only during an agent tool call, when ownership and the owning event-sourced session are known. A future declarative startup feature must compose through unpublished agent setup rather than create shared global terminals. -Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Unpublished backend setup is a tracked lifecycle operation: owner or service disposal aborts its service-owned signal, waits for backend settlement and rollback, and only then returns. Caller cancellation retains its exact `AbortSignal.reason` even when the backend rejects in response; a service rollback close failure rejects both the spawn and the disposing lifecycle, while `PtyBackendCleanupError` lets a backend preserve its own failed startup cleanup for the disposing lifecycle without replacing that caller reason. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. +Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Unpublished backend setup is a tracked lifecycle operation: owner or service disposal aborts its service-owned signal, waits for backend settlement and rollback, and only then returns. Caller cancellation retains its exact `AbortSignal.reason` even when the backend rejects in response; a service rollback close failure rejects both the spawn and the disposing lifecycle, while `PtyBackendCleanupError` lets a backend preserve its own failed startup cleanup for the disposing lifecycle without replacing that caller reason. When caller cancellation settles before disposal, the cleanup failure remains tracked owner activity until later owner or service disposal consumes and reports it, so sandbox-mode policy cannot mistake failed cleanup for quiescence. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. ### Security and process boundary @@ -62,7 +62,7 @@ The ACP render contract is exact and location-free. `terminal_send` uses termina `terminal_send({ sessionId, text, submit?, run_in_background? })` treats `text` as UTF-8 bytes and resolves `submit` to `true` in the tool implementation. When `submit` is true it writes the platform Enter sequence after the text; when false it writes only the text, allowing control characters and REPL fragments without hidden content heuristics. `enableRunInBackground` defaults to true; false removes `run_in_background` from the schema and rejects the same undeclared argument if a caller forces it through execution. -Foreground sends return a bounded rendered delta and two independent facts: `waitReason` (`stdin_read | inferred_idle | timeout | session_exit`) and `sessionStatus` (`running` or `exited` with exit code or signal). `session_exit` refers to the PTY's top-level shell process, not an arbitrary foreground command whose status the shell consumes. A timeout never implies process exit. `dsh-tool-pty.maxResultBytes` defaults to 262144, rejects values below 64 so creation acknowledgements retain registry-issued ids, and caps the complete UTF-8 result after normalized errors, wait, session, pagination, truncation, and generic task-status wrappers; the renderer reserves suffix space and preserves code-point boundaries instead of treating the backend payload cap as the final model bound. +Foreground sends return a bounded rendered delta and two independent facts: `waitReason` (`stdin_read | inferred_idle | timeout | session_exit`) and `sessionStatus` (`running` or `exited` with exit code or signal). `session_exit` refers to the PTY's top-level shell process, not an arbitrary foreground command whose status the shell consumes. A timeout never implies process exit. `dsh-tool-pty.maxResultBytes` defaults to 262144, rejects values below 64 so creation acknowledgements retain registry-issued ids, and caps each single-text UTF-8 result after normalized errors, wait, session, pagination, truncation, generic task-status wrappers, pre-execute denials, and post-execute replacements or blocks; its outer post-execute wrapper leaves deliberately structured multi-block policy content unchanged. The renderer reserves suffix space and preserves code-point boundaries instead of treating the backend payload cap as the final model bound. With `run_in_background: true`, `dsh-tool-pty` registers the in-flight send on `ctx.tasks` and returns immediately with `taskId`. The producer places `maxResultBytes` on the task snapshot so `task_output`, terminal kill status, and completion notices enforce the same complete-result cap after generic metadata. `task_output(wait: true)` waits, reads incremental output, and records the final result; `task_kill` resolves the current foreground PGID and delivers a real `SIGINT`, including when the application has disabled terminal `ISIG`, and escalates only through the PTY backend's owned teardown path. If the task surface is absent, background mode fails before writing input. No PTY-specific `sleep` tool or general wake-up seam is added. diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index 44e66094b9..157bee408d 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -34,7 +34,7 @@ idle 检测属于后端行为,不是第二条公共 seam。远程或容器后 实现不提供插件加载期 auto-start 会话。`terminal_open` 只在 agent 工具调用期间创建会话,此时所有权和所属的事件溯源会话都已确定。未来的声明式启动功能必须通过尚未发布的 agent setup 组合,而不能创建全局共享终端。 -agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。未发布的后端 setup 同样是受追踪的生命周期操作:owner 或服务 dispose 会中止服务自有的 signal,等待后端结算与回滚完成后才返回。即使后端响应取消而 reject,调用方取消仍原样保留其 `AbortSignal.reason`;服务侧回滚 close 失败会使 spawn 与正在执行的 lifecycle dispose 都 reject,而 `PtyBackendCleanupError` 让后端在不替换该调用方原因的前提下,为正在执行的 dispose 保留自身的启动清理失败。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 +agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。未发布的后端 setup 同样是受追踪的生命周期操作:owner 或服务 dispose 会中止服务自有的 signal,等待后端结算与回滚完成后才返回。即使后端响应取消而 reject,调用方取消仍原样保留其 `AbortSignal.reason`;服务侧回滚 close 失败会使 spawn 与正在执行的 lifecycle dispose 都 reject,而 `PtyBackendCleanupError` 让后端在不替换该调用方原因的前提下,为正在执行的 dispose 保留自身的启动清理失败。若调用方取消先于 dispose 完成结算,该清理失败会继续作为受追踪的 owner activity 保留,直到后续 owner 或服务 dispose 消费并报告它,因此沙箱模式策略不会把清理失败误判为静默。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 ### 安全与进程边界 @@ -62,7 +62,7 @@ ACP 渲染契约精确且不携带位置信息。`terminal_send` 只为前台发 `terminal_send({ sessionId, text, submit?, run_in_background? })` 将 `text` 视为 UTF-8 字节,并由工具实现在解析阶段把 `submit` 默认成 `true`。`submit` 为 true 时先写入文本,再写入平台 Enter 序列;为 false 时只写文本,使控制字符和 REPL 片段无需隐藏的内容启发式即可发送。`enableRunInBackground` 默认为 true;设为 false 时,schema 中会移除 `run_in_background`,调用方即使强行把这个未声明参数传入执行流程,也会被拒绝。 -前台发送返回有界的渲染增量和两个独立事实:`waitReason`(`stdin_read | inferred_idle | timeout | session_exit`)与 `sessionStatus`(`running`,或携带退出码或信号的 `exited`)。`session_exit` 指 PTY 顶层 shell 进程退出,不指由 shell 消费状态的任意前台命令。timeout 从不意味着进程已经退出。`dsh-tool-pty.maxResultBytes` 默认为 262144;低于 64 的值会被拒绝,以确保创建确认保留 registry 签发的 id;完整 UTF-8 结果在加入规范化错误、等待与会话状态、分页与截断元数据以及通用 task 状态包装后,仍受该值限制。渲染器会为后缀预留空间并保持代码点边界,而不会把后端载荷上限当作面向模型结果的最终上限。 +前台发送返回有界的渲染增量和两个独立事实:`waitReason`(`stdin_read | inferred_idle | timeout | session_exit`)与 `sessionStatus`(`running`,或携带退出码或信号的 `exited`)。`session_exit` 指 PTY 顶层 shell 进程退出,不指由 shell 消费状态的任意前台命令。timeout 从不意味着进程已经退出。`dsh-tool-pty.maxResultBytes` 默认为 262144;低于 64 的值会被拒绝,以确保创建确认保留 registry 签发的 id;每个单文本 UTF-8 结果在加入规范化错误、等待与会话状态、分页与截断元数据、通用 task 状态包装、pre-execute 拒绝以及 post-execute 替换或阻断后,仍受该值限制;位于外层的 post-execute wrapper 会原样保留策略刻意返回的结构化多 block 内容。渲染器会为后缀预留空间并保持代码点边界,而不会把后端载荷上限当作面向模型结果的最终上限。 当 `run_in_background: true` 时,`dsh-tool-pty` 在 `ctx.tasks` 上注册进行中的发送,并立即返回 `taskId`。生产方把 `maxResultBytes` 写入 task 快照,使 `task_output`、kill 返回的终态状态和完成通知在加上通用元数据后,仍对完整结果执行同一上限。`task_output(wait: true)` 负责等待、读取增量输出并记录最终结果;`task_kill` 会解析当前前台 PGID 并发送真正的 `SIGINT`,即使应用已禁用终端 `ISIG` 也同样如此,且后续升级仍只通过 PTY 后端拥有的 teardown 路径进行。若 task 对外接口不存在,后台模式必须在写入输入前失败。设计不新增 PTY 专用的 `sleep` 工具或通用唤醒 seam。 diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index db41e4e868..78687b70b9 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -841,7 +841,7 @@ list(owner: Agent): PtySessionSnapshot[] Types: [Agent](../core-data-structures/core.md) · [PtyBackend](../core-data-structures/pty.md) · [PtyReadRequest](../core-data-structures/pty.md) · [PtyReadResult](../core-data-structures/pty.md) · [PtySendOperation](../core-data-structures/pty.md) · [PtySendRequest](../core-data-structures/pty.md) · [PtySessionId](../core-data-structures/pty.md) · [PtySessionSnapshot](../core-data-structures/pty.md) · [PtySignal](../core-data-structures/pty.md) · [PtySignalResult](../core-data-structures/pty.md) · [PtySpawnRequest](../core-data-structures/pty.md) · [PtySpawnResult](../core-data-structures/pty.md) -Source: [`packages/pty/pty/src/index.ts:104`](../../packages/pty/pty/src/index.ts) +Source: [`packages/pty/pty/src/index.ts:105`](../../packages/pty/pty/src/index.ts) ## `ctx.sandbox` — `SandboxProvider` (abstract seam) diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index 24f0f9b252..237015cbac 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -42,8 +42,8 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:29`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`agent`](../packages/core/agent), [`system-prompt`](../packages/core/system-prompt) | | `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:35`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - | | `tools/change` | `emit` | [`packages/core/tools/src/index.ts:123`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | -| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:93`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`timeout-policy`](../packages/timeout/timeout-policy), [`tool-pty`](../packages/pty/tool-pty) | -| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:105`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`workspace-context`](../packages/context/workspace-context) | +| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:93`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`timeout-policy`](../packages/timeout/timeout-policy) | +| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:105`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-pty`](../packages/pty/tool-pty), [`workspace-context`](../packages/context/workspace-context) | | `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:82`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | | `tools/result` | `emit` | [`packages/core/tools/src/index.ts:113`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:81`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) | diff --git a/packages/pty/pty/README.md b/packages/pty/pty/README.md index af1c3a9d42..4213a3458f 100644 --- a/packages/pty/pty/README.md +++ b/packages/pty/pty/README.md @@ -8,6 +8,7 @@ Owner-scoped persistent PTY seam. `PtyService` registers as `ctx.pty`, mints opa - Spawn cancellation preserves the caller's exact abort reason. Service disposal and owner loss remain distinct machine-routable failures after backend setup. - Owner and service disposal abort unpublished setup through a service-owned signal and await backend settlement plus rollback before returning. - A service rollback or backend-reported startup cleanup failure rejects the disposing lifecycle instead of claiming quiescence; the spawn caller still receives its exact cancellation reason. +- A backend cleanup failure that follows caller cancellation remains owner activity until owner or service disposal consumes and reports it, so lifecycle policy cannot mistake failed cleanup for quiescence. - `hasOwnerActivity(owner)` spans unpublished setup through final close, so lifecycle policy can fence the exact owner without a publication race. - A successful spawn publishes one `PtySessionId`. The optional `name` is owner-local display metadata, never authority. - One session accepts at most one live send operation. Reads and signals may observe it; another send fails until the operation settles. diff --git a/packages/pty/pty/src/index.ts b/packages/pty/pty/src/index.ts index f80089c90b..47c2a2662d 100644 --- a/packages/pty/pty/src/index.ts +++ b/packages/pty/pty/src/index.ts @@ -90,6 +90,7 @@ interface SessionRecord { } interface PendingSpawn { + readonly owner: Agent readonly controller: AbortController readonly settled: Promise cleanupFailure: { error: unknown } | undefined @@ -349,7 +350,7 @@ export class PtyService extends Service { private reserveSpawn(owner: Agent): SpawnReservation { const controller = new AbortController() const settlement = Promise.withResolvers() - const pending: PendingSpawn = { controller, settled: settlement.promise, cleanupFailure: undefined } + const pending: PendingSpawn = { owner, controller, settled: settlement.promise, cleanupFailure: undefined } const owned = this.pendingSpawns.get(owner) ?? new Set() owned.add(pending) this.pendingSpawns.set(owner, owned) @@ -357,13 +358,19 @@ export class PtyService extends Service { signal: controller.signal, release: (cleanupFailure) => { pending.cleanupFailure = cleanupFailure - owned.delete(pending) - if (owned.size === 0) this.pendingSpawns.delete(owner) + if (cleanupFailure === undefined) this.removePendingSpawn(pending) settlement.resolve() }, } } + private removePendingSpawn(pending: PendingSpawn): void { + const owned = this.pendingSpawns.get(pending.owner) + if (owned === undefined) return + owned.delete(pending) + if (owned.size === 0) this.pendingSpawns.delete(pending.owner) + } + private async abortPendingSpawns(owner: Agent | undefined, reason: PtyError): Promise { const pending = owner === undefined ? [...this.pendingSpawns.values()].flatMap(owned => [...owned]) @@ -371,6 +378,7 @@ export class PtyService extends Service { for (const spawn of pending) spawn.controller.abort(reason) await Promise.all(pending.map(spawn => spawn.settled)) const failures = pending.flatMap(spawn => spawn.cleanupFailure === undefined ? [] : [spawn.cleanupFailure.error]) + for (const spawn of pending) this.removePendingSpawn(spawn) if (failures.length > 0) { throw new AggregateError(failures, 'failed to roll back unpublished PTY setup') } diff --git a/packages/pty/pty/tests/service.spec.ts b/packages/pty/pty/tests/service.spec.ts index 1d9d1a1f94..caa255ac5b 100644 --- a/packages/pty/pty/tests/service.spec.ts +++ b/packages/pty/pty/tests/service.spec.ts @@ -160,6 +160,7 @@ describe('PtyService ownership and lifecycle', () => { const created = await ctx.pty.spawn(owner, { type: 'stub', name: 'main', cwd: '/tmp' }) expect(created).toMatchObject({ sessionId: 'pty-1', name: 'main', type: 'stub', pid: 123, motd: 'stub ready', status: { kind: 'running' } }) + expect(ctx.pty.hasOwnerActivity(owner)).toBe(true) expect(ctx.pty.list(owner)).toHaveLength(1) expect(ctx.pty.list(foreign)).toEqual([]) expect(() => ctx.pty.read(foreign, created.sessionId)).toThrow('belongs to another agent') @@ -256,6 +257,40 @@ describe('PtyService ownership and lifecycle', () => { await expect(pending).rejects.toBe(reason) }) + it.each(['owner', 'service'] as const)('retains caller-triggered backend cleanup failure until %s disposal', async (scope) => { + const ctx = await harness() + const started = Promise.withResolvers() + const cleanupFailure = new Error('backend cleanup failed') + ctx.pty.registerBackend({ + type: 'cleanup-failing', + spawn: ({ signal }) => new Promise((_resolve, reject) => { + if (signal === undefined) throw new Error('missing spawn signal') + started.resolve(undefined) + signal.addEventListener('abort', () => { + reject(new PtyBackendCleanupError(signal.reason, cleanupFailure)) + }, { once: true }) + }), + }) + const owner = stubAgent(ctx, 'owner') + ctx.agents.register(owner) + const controller = new AbortController() + const reason = new Error('cancelled by caller') + + const pending = ctx.pty.spawn(owner, { type: 'cleanup-failing' }, controller.signal) + await started.promise + controller.abort(reason) + + await expect(pending).rejects.toBe(reason) + expect(ctx.pty.hasOwnerActivity(owner)).toBe(true) + const internal = ctx.pty as unknown as { + disposeOwned(owner: Agent): Promise + disposeAll(): Promise + } + const disposal = scope === 'owner' ? internal.disposeOwned(owner) : internal.disposeAll() + await expect(disposal).rejects.toThrow('failed to clean up PTY lifecycle') + expect(ctx.pty.hasOwnerActivity(owner)).toBe(false) + }) + it.each([ { scope: 'owner', code: 'OWNER_NOT_LIVE' }, { scope: 'service', code: 'SERVICE_DISPOSING' }, diff --git a/packages/pty/tool-pty/README.md b/packages/pty/tool-pty/README.md index 8ec8601b6b..a3167ab552 100644 --- a/packages/pty/tool-pty/README.md +++ b/packages/pty/tool-pty/README.md @@ -11,7 +11,7 @@ Six model-facing tools over `ctx.pty`: `terminal_open`, `terminal_send`, `termin | `enableRunInBackground` | `true` | expose and accept `run_in_background`; false omits the schema field and rejects a forced undeclared argument | | `maxResultBytes` | `262144` | UTF-8 cap (minimum `64`) for each complete terminal result or PTY task output after wait, session, pagination, truncation, and task-status metadata | -Both values are validated at load. The minimum result cap keeps every registry-issued session or task id visible in its creation acknowledgement. When a result exceeds `maxResultBytes`, rendering reserves space for control metadata and a truncation marker when they fit; cuts preserve UTF-8 boundaries. +Both values are validated at load. The minimum result cap keeps every registry-issued session or task id visible in its creation acknowledgement. When a result exceeds `maxResultBytes`, rendering reserves space for control metadata and a truncation marker when they fit; cuts preserve UTF-8 boundaries. An outer `tools/post-execute` wrapper applies the same cap after a terminal pre-execute denial or single-text post-execute replacement/block; a structured multi-block policy result retains its shape. ## Model Experience @@ -53,11 +53,11 @@ Prefix-stable while tool visibility and definitions are unchanged. #### What the model sees -Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Every complete result is capped by `maxResultBytes`, including normalized error text and generic task status text. Results remain in session history until compaction; incremental task reads do not repeat consumed output. +Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Every terminal-owned or policy-produced single-text result is capped by `maxResultBytes` after normalized errors, denials, replacements, blocks, and generic task status text. Structured multi-block policy results retain their shape. Results remain in session history until compaction; incremental task reads do not repeat consumed output. #### Token effect -Data-dependent and bounded by `maxResultBytes`; each returned result remains in history until compaction. +Terminal-owned and policy-produced single-text results are data-dependent and bounded by `maxResultBytes`; a policy that deliberately substitutes structured multi-block content owns that content's bound. Each returned result remains in history until compaction. #### KV Cache effect diff --git a/packages/pty/tool-pty/src/index.ts b/packages/pty/tool-pty/src/index.ts index 5e75c97bec..5b1e3b7e9d 100644 --- a/packages/pty/tool-pty/src/index.ts +++ b/packages/pty/tool-pty/src/index.ts @@ -12,7 +12,7 @@ import { PtySessionId } from '@deepseek-ai/dsh-pty' import type { PtySendResult, PtySessionId as PtySessionIdType, PtySignal } from '@deepseek-ai/dsh-pty' import type {} from '@deepseek-ai/dsh-tasks' import { defineTool } from '@deepseek-ai/dsh-tools' -import type { ToolExecutionResult, ToolResult } from '@deepseek-ai/dsh-tools' +import type { PostToolDecision, ToolExecutionResult } from '@deepseek-ai/dsh-tools' import { boundTerminalText, renderList, renderRead, renderSend, renderSendRead, renderSpawn } from './render.ts' declare module '@deepseek-ai/dsh-tasks' { @@ -95,9 +95,9 @@ function textResult(text: string, maxBytes: number): ContentBlock[] { return [{ type: 'text', text: boundTerminalText(text, maxBytes) }] } -function rawResultText(result: ToolResult): string | undefined { - if (result.content.length !== 1) return undefined - const block = result.content[0] +function rawContentText(content: readonly ContentBlock[]): string | undefined { + if (content.length !== 1) return undefined + const block = content[0] return block?.type === 'text' ? block.text : undefined } @@ -114,12 +114,17 @@ export function apply(ctx: Context, config: Config = {}): void { if (!Number.isSafeInteger(maxResultBytes) || maxResultBytes < MIN_MAX_RESULT_BYTES) { throw new Error(`tool-pty: maxResultBytes must be a safe integer of at least ${MIN_MAX_RESULT_BYTES}`) } - ctx.on('tools/execute', async (exec, next): Promise => { - const result = await next() - if (!TOOL_NAMES.has(exec.name)) return result - const raw = rawResultText(result) - return raw === undefined ? result : { ...result, content: textResult(raw, maxResultBytes) } - }) + ctx.on('tools/post-execute', async (exec, result, next): Promise => { + const decision = await next() + if (!TOOL_NAMES.has(exec.name)) return decision + const content = decision.kind === 'block' ? decision.feedback : decision.content ?? result.content + const raw = rawContentText(content) + if (raw === undefined) return decision + const bounded = textResult(raw, maxResultBytes) + return decision.kind === 'block' + ? { ...decision, feedback: bounded } + : { ...decision, content: bounded } + }, { prepend: true }) ctx.systemPrompt.section({ name: 'tool:pty', order: 106, @@ -206,7 +211,7 @@ export function apply(ctx: Context, config: Config = {}): void { }, presentResult(args, result) { if ((args as Partial).run_in_background === true || result.isError) return undefined - const raw = rawResultText(result) + const raw = rawContentText(result.content) return raw === undefined ? undefined : { card: 'terminal', output: raw } }, })) diff --git a/packages/pty/tool-pty/tests/tools.spec.ts b/packages/pty/tool-pty/tests/tools.spec.ts index 0466b02134..ebc2503a5a 100644 --- a/packages/pty/tool-pty/tests/tools.spec.ts +++ b/packages/pty/tool-pty/tests/tools.spec.ts @@ -217,6 +217,37 @@ describe('tool-pty foreground surface', () => { expect(Buffer.byteLength(text(background))).toBeLessThanOrEqual(64) }) + it('bounds terminal results after pre- and post-execute policy', async () => { + const { ctx, agent } = await setup(false, { maxResultBytes: 64 }) + ctx.on('tools/pre-execute', async (exec, next) => exec.name === 'terminal_list' + ? { kind: 'deny', reason: 'd'.repeat(1_000) } + : next()) + ctx.on('tools/post-execute', async (exec, _result, next) => { + if (exec.name === 'terminal_open') { + return { kind: 'accept', content: [{ type: 'text', text: 'a'.repeat(1_000) }] } + } + if (exec.name === 'terminal_read') { + return { kind: 'block', feedback: [{ type: 'text', text: 'b'.repeat(1_000) }] } + } + return next() + }) + + const denied = await call(ctx, 'terminal_list', {}, agent) + expect(denied.isError).toBe(true) + expect(Buffer.byteLength(text(denied))).toBeLessThanOrEqual(64) + expect(text(denied)).toContain('[output truncated]') + + const replaced = await call(ctx, 'terminal_open', { type: 'stub' }, agent) + expect(replaced.isError).toBe(false) + expect(Buffer.byteLength(text(replaced))).toBeLessThanOrEqual(64) + expect(text(replaced)).toContain('[output truncated]') + + const blocked = await call(ctx, 'terminal_read', { sessionId: 'pty-1' }, agent) + expect(blocked.isError).toBe(true) + expect(Buffer.byteLength(text(blocked))).toBeLessThanOrEqual(64) + expect(text(blocked)).toContain('[output truncated]') + }) + it('leaves a structured around-dispatch replacement unchanged', async () => { const { ctx, agent } = await setup(false, { maxResultBytes: 64 }) ctx.on('tools/execute', async (exec, next) => exec.name === 'terminal_list' From fb74156cf8be8ab6db6258a3d8e0178662a5c66d Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:32:17 +0800 Subject: [PATCH 125/368] fix(code-mode): generalize failures and bound diagnostics --- .../feature/2026-06-15-code-mode.md | 4 +- ...-20-code-mode-typed-tool-returns.i18n.yaml | 4 +- ...2026-07-20-code-mode-typed-tool-returns.md | 6 +- ...6-07-20-code-mode-typed-tool-returns.zh.md | 6 +- docs/cordis-catalog/services.md | 4 +- docs/core-data-structures/code-runtime.md | 20 +- .../code-runtime-worker/README.md | 3 +- .../code-runtime-worker/src/bootstrap.ts | 220 +++++++++++++----- .../code-runtime-worker/src/index.ts | 41 +++- .../code-runtime-worker/src/protocol.ts | 20 +- .../tests/bootstrap.spec.ts | 120 ++++++++-- .../tests/built-lib.e2e.ts | 16 +- .../code-runtime-worker/tests/runtime.spec.ts | 103 +++++++- packages/code-runtime/code-runtime/README.md | 2 +- .../code-runtime/code-runtime/src/index.ts | 6 +- .../code-runtime/code-runtime/src/types.ts | 16 ++ .../cordis/tool-cordis/src/api-catalog.ts | 6 +- packages/core/tools/src/code-mode.ts | 6 +- packages/core/tools/tests/code-mode.spec.ts | 4 + scripts/type-equiv.manifest.json | 5 + 20 files changed, 483 insertions(+), 129 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.md index 91e0899e44..6ffff361cd 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.md @@ -59,7 +59,7 @@ Each sub-dispatch appends a log-only `tool/code-dispatch` event containing paren `packages/code-runtime/code-runtime/` — `@deepseek-ai/dsh-code-runtime`, depending only on `cordis`. An abstract `CodeRuntime extends Service` (`super(ctx, 'codeRuntime')`) plus the vocabulary: - `CodeRunRequest = { program: string; bindings: CodeBindingNamespace[]; signal?: AbortSignal }` -- `CodeBindingNamespace = { global: string; functions: Record Promise> }` — the runtime exposes each namespace as a global object of async functions inside the program; `CodeJsonValue` is this dependency-light seam's structural lossless-JSON type, so binding arguments and resolutions cross the implementation's serialization boundary whole. +- `CodeBindingNamespace = { global: string; functions: Record Promise>; errorClass?: { name: string; memberNameProperty: string } }` — the runtime exposes each namespace as a global object of async functions inside the program; the optional descriptor asks the runtime to inject a real program-visible rejection class without teaching the seam consumer-specific names. `CodeJsonValue` is this dependency-light seam's structural lossless-JSON type, so binding arguments and resolutions cross the implementation's serialization boundary whole. - `CodeRunResult = { value?: CodeJsonValue; logs: string[]; error?: CodeRunFailure }` — program execution outcomes resolve as the `error` field. `run()` may reject only for caller/seam misuse (for example a duplicate binding namespace); consumers still contain a non-conforming backend rejection at their own error boundary. - `CodeRunFailure = { kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' | 'invalid-output' | 'output-limit'; message: string }` — orthogonal outcomes reported independently per [defensive patterns](../../../../docs/defensive-patterns.md); a timed-out run is not an exception, an abort is not a timeout, a lossy completion is not an overflow, and a substrate exit is none of them. - Two readonly backend descriptors, informational not gating: `language` (what the program must be written in — `'typescript'` for the shipped backend; a Python backend would say so, and pair with its own SDK generator on the presentation side) and `isolation` (`'worker-thread'` for the shipped backend; `'process'`, `'container'`, … for future ones). `dsh-tools` requires `language === 'typescript'` in the MVP — its codegen emits TS — and fails the assembly loudly otherwise, the same misconfiguration idiom as `toolOrder` violations (as when `mode` is non-native with no `ctx.codeRuntime` loaded at all). @@ -72,7 +72,7 @@ Requests contain every runtime input; implementations own validated timeout and 1. **Type-strip host-side** with Node's built-in `stripTypeScriptTypes` (`node:module`; present across the repo's whole engines range, `^22.19.0 || >=24.0.0`, and position-preserving, so runtime error line numbers match the model's source). Strip-only mode rejects non-erasable syntax (`enum`, namespaces) — that rejection returns as `error.kind: 'exception'` with Node's message, the SDK instructions say "erasable TypeScript only", and the model self-corrects like any other program error. A syntax-level failure never spawns a worker. 2. **Spawn one fresh `Worker` per run** from the package's own bootstrap module: `env: {}` (truly empty — stronger than the scrubbed-env rule for spawned commands), `resourceLimits` from config, `stdout`/`stderr` captured into `logs` rather than inherited. No pooling and no cross-run state: a program's world dies with its worker, which keeps runs reconstructable from the log alone and makes state bleed unrepresentable. -3. **Execute** in the bootstrap: the stripped program becomes the body of an `AsyncFunction` whose parameters are the binding globals, the real `ToolCallError` class, and a capturing `console` shim, so top-level `await` and `return` work. A lossless JSON completion crosses exactly; `undefined` remains absence, a lossy value is `invalid-output`, and an oversized outer result is `output-limit` rather than an inspected-string substitute. +3. **Execute** in the bootstrap: the stripped program becomes the body of an `AsyncFunction` whose parameters are the binding globals, any consumer-declared rejection classes, and a capturing `console` shim, so top-level `await` and `return` work. Code Mode declares `ToolCallError` with member property `toolName`; the runtime materializes that real constructor without hardcoding tools. A lossless JSON completion crosses exactly; `undefined` remains absence, a lossy value is `invalid-output`, and an oversized outer result is `output-limit` rather than an inspected-string substitute. 4. **Bridge bindings over the message port**: each binding function in the worker posts `{ id, global, name, args }` and awaits the reply; the host validates the name against the request's bindings, invokes, and replies `{ id, ok, value }` or `{ id, ok: false, message }` (a host-side binding rejection becomes a program-side rejection). The worker-side namespace objects are built null-prototype via `defineProperty`, so a binding named `__proto__`, `constructor`, or `toString` is an ordinary own property, not a prototype collision. Unknown names, duplicate ids, and post-settlement messages are rejected or ignored — the port protocol assumes a hostile peer, because the peer runs model code. 5. **Enforce independent budgets.** `computeMs` meters worker busy time, allowing slow awaited tools without excusing a hot loop. `maxWallMs` bounds total elapsed time, including unresolved waits. `maxOutputBytes` bounds only the combined serialized outer logs, completion, or diagnostic; intermediate binding values have no byte cap. Expiry, cancellation, and completion terminate the worker, and heap exits or outer overflow are explicit failures. 6. **Dispose to quiescence**: the service's own disposal terminates in-flight workers and *awaits* their exits before resolving, per [defensive patterns](../../../../docs/defensive-patterns.md). diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml index 38fd140342..a6d395a958 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml @@ -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 -2026-07-20-code-mode-typed-tool-returns.md: bcaefb196d12660177ad2bbc9c20ad71f6537eae -2026-07-20-code-mode-typed-tool-returns.zh.md: 72946f4cc1ab7569fc1e3f90785debf8314f1d35 +2026-07-20-code-mode-typed-tool-returns.md: 2f37e7b43b4dac04e6964d2189d07c7838bf12b5 +2026-07-20-code-mode-typed-tool-returns.zh.md: 1badc2231e93edd6db4eceb5de6d1eeba11b3e69 diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md index bcaefb196d..2f37e7b43b 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md @@ -51,7 +51,7 @@ declare const tools: { Before dispatch the bridge snapshots binding arguments as lossless JSON and snapshots the detached value again for an independent durable summary event. Host-side detachment, immutable execution, and output-schema projection all use iterative traversals rather than nested structured clone or recursive freezing. `undefined`, non-finite numbers, `-0`, sparse arrays, cycles, functions, and exotic objects reject that call before the tool runs. Successful dispatch returns `ToolExecutionResult.value`; Native `content`, metadata, and internal error information do not cross to the program. -The worker exposes the actual `ToolCallError` constructor used for `tools` binding failures, so `error instanceof ToolCallError` works. The error has the standard `Error` message plus the exact `toolName`; it deliberately omits `ToolFailure.info`, error codes, and Native content. This is an exception contract for control flow, not a failure union for programmatic classification. +Code Mode declares its rejection capability on the runtime request as `{ name: "ToolCallError", memberNameProperty: "toolName" }`. The runtime seam treats those names as data: the worker materializes and injects the actual constructor used for `tools` binding failures, so `error instanceof ToolCallError` works without making a generic runtime know about tools. The error has the standard `Error` message plus the exact `toolName`; it deliberately omits `ToolFailure.info`, error codes, and Native content. This is an exception contract for control flow, not a failure union for programmatic classification. Binding arguments and resolutions are revalidated as lossless JSON on both sides of the hostile worker protocol and have no byte cap. Before crossing through structured clone, each detached value is encoded as a flat pre-order token stream whose transport nesting is bounded; the receiver rebuilds it iteratively. Valid application nesting therefore has neither a JavaScript call-stack depth cap nor a platform-specific nested structured-clone limit. The dependency-light runtime seam names its structural equivalent `CodeJsonValue` so it need not depend on the session-owned canonical type; the generated SDK and tool API use `JsonValue`. Intermediate values are not prompt-truncated, context-spilled, or persisted. This preserves full acquired search, workflow, task, filesystem, and MCP values for programmatic filtering while leaving provider and executor acquisition limits truthful. @@ -59,7 +59,7 @@ Binding arguments and resolutions are revalidated as lossless JSON on both sides The runtime accepts an exact lossless JSON completion of any root. Returning `undefined` omits the completion; returning `null` is an explicit result. `run_code` exposes the canonical outer value `{ logs: string[], result?: JsonValue }`. Its Native renderer emits logs first, renders a string result raw, and renders every other JSON root with an iterative pretty printer. Total indentation is capped at ten characters and deeper subtrees remain compact, preserving the established shallow text while keeping traversal stack-safe and formatted size linear in the canonical JSON size. -`WorkerCodeRuntime` replaces the former independent log and value caps with configurable `maxOutputBytes`, defaulting to `67_108_864` bytes. The worker preflights the detached completion with bounded JSON measurement, and one host-side hostile-peer ledger accounts the JSON serialization of the outer log-array plus either the completion-value or failure-message payload. Fixed `CodeRunResult` field names, braces, the bounded error-kind tag, and later presentation whitespace are deliberately outside this variable-payload ledger. Neither stage materializes an over-limit serialized completion. A result at or below the cap is exact. A completion that cannot survive lossless JSON snapshotting fails as `invalid-output`; a value or combined logs/value outcome over the cap fails as `output-limit` rather than becoming inspected or truncated text. +`WorkerCodeRuntime` replaces the former independent log and value caps with configurable `maxOutputBytes`, defaulting to `67_108_864` bytes. The worker charges captured logs by their exact JSON-string serialization and preflights the detached completion or program exception against the remaining combined budget before posting a terminal message. A giant thrown string or stack therefore crosses the worker port only as the fixed `output-limit` diagnostic. The host repeats the hostile-peer ledger for forged traffic and native pipe writes the worker cannot observe. Fixed `CodeRunResult` field names, braces, the bounded error-kind tag, and later presentation whitespace are deliberately outside this variable-payload ledger. Neither stage materializes an over-limit serialized completion. A result at or below the cap is exact. A completion that cannot survive lossless JSON snapshotting fails as `invalid-output`; a value, diagnostic, or combined outcome over the cap fails as `output-limit` rather than becoming inspected or truncated text. Logs stream eagerly so a terminated run can retain output already admitted. Native stdout and stderr writes that bypass the worker's patched stream slots use independent pipes, so terminal settlement continues bounded capture until worker termination completes before materializing the result. When the cap is crossed, the runtime returns an explicit bounded failure with the fitting captured prefix. That outer result then traverses the ordinary `run_code` rendering and spill policy, which may save the captured text and expose its configured head/tail preview. The spill layer cannot recover bytes the runtime rejected beyond the hard cap. @@ -79,7 +79,7 @@ The opaque `exec.parent` token marks nested calls. Presentation metadata and gen ## Testing -Compile-time and snapshot tests pin exact `ToolArgsMap`, `ToolOutputMap`, `ToolName`, schema-to-TypeScript coverage, and exotic names. Registry and real-worker tests cover scalar, array, object, and null values; raw string rendering; absent `undefined`; the real `ToolCallError`; invalid arguments and completions; large uncapped intermediate bindings; nested spill suppression; exact and over-limit 64 MiB accounting; combined logs/value accounting; bounded failure spill; hostile forged traffic; and built-package execution. +Compile-time and snapshot tests pin exact `ToolArgsMap`, `ToolOutputMap`, `ToolName`, schema-to-TypeScript coverage, and exotic names. Registry and real-worker tests cover scalar, array, object, and null values; raw string rendering; absent `undefined`; consumer-declared real rejection classes, including `ToolCallError`; invalid arguments and completions; large uncapped intermediate bindings; nested spill suppression; exact and over-limit 64 MiB accounting; combined logs/value/diagnostic accounting; giant thrown stacks; bounded failure spill; hostile forged traffic; and built-package execution. Keyless real-worker integration tests pin the two handle workflows that prose results could not safely support. A background bash call returns its task id, the outer run settles, and a later run polls that id to completion; separate cases prove pre-abort creates no task, post-publication call abort preserves the task, foreground execution stays signal-coupled, and `task_kill` owns cancellation. A Cordis program reads an active or pending mount's id and `waitingFor` fields directly, unmounts by that id, and confirms removal without parsing rendered text. diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md index 72946f4cc1..1badc2231e 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md @@ -51,7 +51,7 @@ declare const tools: { 分发前,桥接层会把绑定参数快照为无损 JSON,再对分离后的值生成一次快照,供独立的持久摘要事件使用。宿主侧的值分离、执行数据的不可变处理与输出 schema 投影均采用迭代遍历,而不使用嵌套结构化克隆或递归冻结。`undefined`、非有限数、`-0`、稀疏数组、循环引用、函数和非普通对象都会使该调用在工具运行前 reject。成功分发会返回 `ToolExecutionResult.value`;Native `content`、元数据和内部错误信息不会传入程序。 -worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造函数,因此 `error instanceof ToolCallError` 能够成立。该错误包含标准的 `Error` 消息和确切的 `toolName`,并有意省略 `ToolFailure.info`、错误代码与 Native 内容。这是一项用于控制流的异常契约,而不是供程序分类的失败联合。 +Code Mode 通过运行时请求中的 `{ name: "ToolCallError", memberNameProperty: "toolName" }` 声明其 reject 异常能力。运行时 seam 只把这些名称视为数据:worker 会动态生成并注入真正用于 `tools` 绑定失败的构造函数,因此无需让通用运行时了解工具,`error instanceof ToolCallError` 也能成立。该错误包含标准的 `Error` 消息和确切的 `toolName`,并有意省略 `ToolFailure.info`、错误代码与 Native 内容。这是一项用于控制流的异常契约,而不是供程序分类的失败联合。 绑定参数与绑定返回值会在不可信 worker 协议的两端重新校验为无损 JSON,且不设字节上限。每个分离后的值在通过结构化克隆跨越边界前,都会编码为扁平的前序 token 流,其传输结构的嵌套深度有界;接收方再以迭代方式重建该值。因此,有效应用数据的嵌套深度既不受 JavaScript 调用栈深度上限限制,也不受特定平台对嵌套结构化克隆施加的上限限制。为保持依赖轻量,运行时 seam 将结构等价类型命名为 `CodeJsonValue`,从而无需依赖会话侧拥有的规范类型;生成的 SDK 和工具 API 则使用 `JsonValue`。这些值不会经过提示词截断、上下文输出落盘或持久化。因此,程序可以完整筛选已经采集的搜索、工作流、任务、文件系统与 MCP 值,同时提供方和执行器的采集上限仍会实际生效。 @@ -59,7 +59,7 @@ worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造 运行时接受以任意 JSON 类型为根的精确无损完成值。返回 `undefined` 表示省略完成值;返回 `null` 则是显式结果。`run_code` 暴露规范外层值 `{ logs: string[], result?: JsonValue }`。其 Native 渲染器先输出日志;字符串结果保持原文,其他所有 JSON 根值则使用迭代式美化渲染器。总缩进长度上限为 10 个字符,更深的子树保持紧凑格式,既保留既有的浅层文本,又确保遍历不受调用栈深度限制,且格式化输出大小与规范 JSON 大小呈线性关系。 -`WorkerCodeRuntime` 以可配置的 `maxOutputBytes` 取代彼此独立的日志与值上限,默认值为 `67_108_864` 字节。worker 会先用有界 JSON 计量对分离后的完成值执行预检,宿主侧则为不可信对端维护一份统一账本,计入外层日志数组的 JSON 序列化大小,以及完成值或失败消息的可变负载。固定的 `CodeRunResult` 字段名、花括号、有界的错误类型标签及后续展示空白有意不计入这份可变负载账本。这两个阶段都不会实际生成超出上限的完成值序列化结果。结果不超过上限时会保持精确。完成值无法通过无损 JSON 快照时,以 `invalid-output` 失败;值本身或日志与值的组合超过上限时,以 `output-limit` 失败,而不会变成检查格式化后或截断的文本。 +`WorkerCodeRuntime` 以可配置的 `maxOutputBytes` 取代彼此独立的日志与值上限,默认值为 `67_108_864` 字节。worker 会将已捕获日志序列化为 JSON 字符串后的精确字节数计入账本,并在发送终态消息前,根据组合账本的剩余额度预检分离后的完成值或程序异常。因此,即使抛出的字符串或堆栈极大,通过 worker 端口的也只会是固定的 `output-limit` 诊断。宿主侧会针对伪造流量以及 worker 无法观察的原生管道写入,重复执行这套不可信对端计账。固定的 `CodeRunResult` 字段名、花括号、有界的错误类型标签及后续展示空白有意不计入这份可变负载账本。这两个阶段都不会实际生成超出上限的完成值序列化结果。结果不超过上限时会保持精确。完成值无法通过无损 JSON 快照时,以 `invalid-output` 失败;值、诊断或包含日志的组合结果超过上限时,以 `output-limit` 失败,而不会变成检查格式化后或截断的文本。 日志会在产生时立即流出,因此运行被终止时仍可保留已经纳入额度的输出。绕过 worker 中已改写流写入入口的原生 stdout 和 stderr 写入会经由彼此独立的管道传输,因此运行时在终态结算期间仍会继续在上限内捕获输出,直至 worker 完全终止,然后才组装结果。超过上限后,运行时会返回一个显式的有界失败,并携带可容纳的已捕获前缀。该外层结果随后通过普通的 `run_code` 渲染与输出落盘策略;策略可以保存已捕获的文本,并暴露其配置指定的头尾预览。输出落盘层无法恢复运行时在硬上限之外拒绝的字节。 @@ -79,7 +79,7 @@ worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造 ## 测试 -编译期测试与快照测试锁定了精确的 `ToolArgsMap`、`ToolOutputMap`、`ToolName`、schema 到 TypeScript 的覆盖范围以及特殊名称。注册表与真实 worker 测试覆盖标量、数组、对象和 null 值;字符串原文渲染;缺席的 `undefined`;真正的 `ToolCallError`;无效参数与完成值;不设上限的大型中间绑定值;嵌套输出落盘抑制;64 MiB 上限内外的精确计量;日志与值的组合计量;有界失败的输出落盘;不可信对端伪造的流量;以及构建后包的执行。 +编译期测试与快照测试锁定了精确的 `ToolArgsMap`、`ToolOutputMap`、`ToolName`、schema 到 TypeScript 的覆盖范围以及特殊名称。注册表与真实 worker 测试覆盖标量、数组、对象和 null 值;字符串原文渲染;缺席的 `undefined`;消费方声明并用于 reject 的真实异常类,包括 `ToolCallError`;无效参数与完成值;不设上限的大型中间绑定值;嵌套输出落盘抑制;64 MiB 上限内外的精确计量;日志、值与诊断的组合计量;抛出的超大堆栈;有界失败的输出落盘;不可信对端伪造的流量;以及构建后包的执行。 无密钥的真实 worker 集成测试锁定了自然语言结果无法安全支持的两种句柄工作流。后台 bash 调用返回 task id,外层运行结束,之后的运行再根据该 id 轮询直至任务完成;其他用例分别证明,预先中止不会创建任务、发布后的调用取消会保留任务、前台执行仍与信号耦合,并且取消归 `task_kill` 所有。Cordis 程序会直接读取 active 或 pending 挂载的 id 和 `waitingFor` 字段,按该 id 卸载,并在不解析渲染文本的情况下确认挂载已移除。 diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index d73d5505fa..da87616f6f 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -321,7 +321,7 @@ Source: [`packages/bash/tool-bash/src/index.ts:104`](../../packages/bash/tool-ba ## `ctx.codeRuntime` — `CodeRuntime` (abstract seam) -Registers one `ctx.codeRuntime` implementation. Program, budget, abort, and substrate failures resolve in CodeRunResult; only seam misuse rejects. Implementations bridge structured-cloneable bindings while treating programs as hostile peers, isolate runs from one another, and terminate and await in-flight runs during disposal. +Registers one `ctx.codeRuntime` implementation. Program, budget, abort, and substrate failures resolve in CodeRunResult; only seam misuse rejects. Implementations bridge structured-cloneable bindings, materialize each declared namespace rejection class, treat programs as hostile peers, isolate runs from one another, and terminate and await in-flight runs during disposal. ```ts cordis-catalog /** @@ -338,7 +338,7 @@ abstract run(request: CodeRunRequest): Promise Types: [CodeRunRequest](../core-data-structures/code-runtime.md) · [CodeRunResult](../core-data-structures/code-runtime.md) -Source: [`packages/code-runtime/code-runtime/src/index.ts:31`](../../packages/code-runtime/code-runtime/src/index.ts) +Source: [`packages/code-runtime/code-runtime/src/index.ts:33`](../../packages/code-runtime/code-runtime/src/index.ts) ## `ctx.commands` — `CommandService` diff --git a/docs/core-data-structures/code-runtime.md b/docs/core-data-structures/code-runtime.md index d9ddc6c9eb..41009f065e 100644 --- a/docs/core-data-structures/code-runtime.md +++ b/docs/core-data-structures/code-runtime.md @@ -59,7 +59,23 @@ interface CodeRunResult { ## Bindings: host functions as program globals -Each `CodeBindingNamespace` becomes one global object of async callables inside the program (the Code Mode consumer passes one: `tools`). Arguments and resolutions must be lossless JSON and cross without a seam-level byte cap; the runtime may bridge them through structured clone. A runtime also treats binding names as hostile input (`__proto__` is an ordinary own property, never a prototype collision): +Each `CodeBindingNamespace` becomes one global object of async callables inside the program (the Code Mode consumer passes one: `tools`). Arguments and resolutions must be lossless JSON and cross without a seam-level byte cap; the runtime may bridge them through structured clone. A namespace may declare a program-visible error class without making the runtime know the consumer's names: the runtime injects the real constructor and turns rejected calls into its instances. A runtime also treats binding names as hostile input (`__proto__` is an ordinary own property, never a prototype collision): + +```ts type-equiv +/** + * Program-visible typed rejection for one binding namespace. The runtime + * injects a real error constructor under `name`; rejected member calls become + * its instances and expose the exact member name through + * `memberNameProperty`. Both strings are runtime data rather than knowledge + * of a particular consumer such as Code Mode. + */ +interface CodeBindingErrorClass { + /** Constructor global and resulting `Error.name` (must be a usable JS identifier). */ + name: string + /** Non-empty own property for the member name; cannot replace `name`, `message`, or `stack`. */ + memberNameProperty: string +} +``` ```ts type-equiv /** @@ -74,6 +90,8 @@ interface CodeBindingNamespace { global: string /** The callable members, keyed by the exact name the program calls. */ functions: Record + /** Optional program-visible typed rejection contract for this namespace. */ + errorClass?: CodeBindingErrorClass } ``` diff --git a/packages/code-runtime/code-runtime-worker/README.md b/packages/code-runtime/code-runtime-worker/README.md index 4936903d2a..8175a403c9 100644 --- a/packages/code-runtime/code-runtime-worker/README.md +++ b/packages/code-runtime/code-runtime-worker/README.md @@ -21,9 +21,10 @@ Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at - **One fresh worker per run, no pooling** — a program's world dies with its worker: no cross-run state to log, state bleed unrepresentable, runs reconstructable from the session log alone. - **Type-strip host-side, in execution context** — the program is wrapped in an async-function shell, stripped with `node:module`'s `stripTypeScriptTypes` (erasable syntax only — `enum`/namespaces are rejected as a program `exception` and no worker spawns), and sliced back out byte-positioned; it then executes as the body of an `AsyncFunction`, so top-level `await`/`return` work. - **The port assumes a hostile peer** — model code can reach `parentPort` and forge traffic, so every inbound message is shape-validated and REBUILT before anything reads it (`null`, primitives, junk types, and malformed payloads drop without a throw; forged extra fields never ride along), the host answers each call id at most once, resolves binding names as OWN properties only (a forged `constructor` cannot walk a prototype chain), drops post-settlement replies, and validates every binding resolution and completion as lossless JSON. Forged `log`/`done` messages cannot bypass the outer cap: the host repeats validation and accounts every admitted log plus the completion or diagnostic. Worker-side namespaces are null-prototype with `defineProperty`, so `__proto__`-shaped binding names are ordinary keys. +- **Binding rejection classes are request data** — an optional namespace descriptor names the constructor global and the own property that receives the failed member name. The worker materializes and injects that real class, so `instanceof` works without hardcoding `tools` or `ToolCallError`; declarations with invalid or colliding globals fail before a worker spawns. - **Two independent budgets, because the peer is hostile** — `computeMs` meters the worker's MEASURED busy time (`worker.performance.eventLoopUtilization()` polling): a hot loop cannot hide behind a pending decoy dispatch, and a program awaiting a slow tool accrues nothing. `maxWallMs` backstops what busy time cannot see (awaiting a promise nobody resolves). Both funnel into `worker.terminate()`, which ends hot synchronous loops too; heap overflow surfaces as the worker's OOM exit (`kind: 'worker-exit'`). - **Intermediate binding values are complete JSON** — binding arguments and resolutions undergo iterative lossless-JSON validation, flatten into a bounded-depth pre-order wire value for structured clone, and rebuild iteratively on the other side. They have no byte, JavaScript call-stack, or nested structured-clone depth cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. -- **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. Native writes that bypass the patched stream slots arrive on pipes independent of the completion port; settlement therefore continues bounded pipe capture until worker termination completes before materializing the result. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure-message payload; fixed `CodeRunResult` field names, braces, the bounded error-kind tag, and later presentation whitespace are outside that variable-payload ledger. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. +- **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. The worker charges exact JSON-string bytes and preflights completion values and exception diagnostics against the remaining combined budget before posting them; a thrown million-byte stack therefore becomes the fixed `output-limit` diagnostic at the worker boundary. Native writes that bypass the patched stream slots arrive on pipes independent of the completion port, so the host repeats the ledger for those bytes and hostile forged traffic; settlement continues bounded pipe capture until worker termination completes before materializing the result. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure-message payload; fixed `CodeRunResult` field names, braces, the bounded error-kind tag, and later presentation whitespace are outside that variable-payload ledger. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. - **Empty environment** — the worker gets `env: {}` and `execArgv: []`: no ambient credentials (stronger than the scrubbed-env rule for spawned commands) and no inherited loader flags. - **Dispose to quiescence** — teardown fails in-flight runs as `abort` and AWAITS each worker's exit before resolving. diff --git a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts index bb021370ca..615a0d6ee9 100644 --- a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts +++ b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts @@ -7,7 +7,7 @@ import { inspect } from 'node:util' import type { DoneMessage, ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts' -import { jsonValueBytesUpTo } from './output-json.ts' +import { jsonStringBytesUpTo, jsonValueBytesUpTo, truncateJsonStringBytes } from './output-json.ts' import { decodeWorkerJson, encodeWorkerJson, snapshotCodeJsonValue } from './worker-json.ts' /** The port surface the bootstrap needs — satisfied by `parentPort` and by the tests' fake. */ @@ -27,25 +27,28 @@ export interface PatchableStream { } /** - * Ordered text capture under one shared byte budget, delivered to a sink as - * each item lands (the real sink streams text over the port eagerly, so - * captured output survives a mid-run termination). Once the budget is - * exhausted it emits the fitting prefix and reports the limit once; the host - * turns that condition into an explicit `output-limit` run failure. + * Ordered text capture under the shared outer JSON-byte budget, delivered to + * a sink as each item lands (the real sink streams text over the port eagerly, + * so captured output survives a mid-run termination). It includes the log + * array syntax and string escaping in its accounting. Once exhausted it emits + * the fitting prefix and reports the limit once; the host turns that condition + * into an explicit `output-limit` run failure. */ export class LogBuffer { - private remaining: number + private bytes = 2 // JSON serialization of the empty logs array: [] + private entries = 0 private truncated = false // Explicit fields, not constructor parameter properties: this module loads // under Node's native strip-only mode, which rejects non-erasable syntax — // and parameter properties are non-erasable. private readonly sink: (text: string) => void private readonly onLimit: () => void + private readonly maxBytes: number constructor(maxBytes: number, sink: (text: string) => void, onLimit: () => void = () => {}) { + this.maxBytes = maxBytes this.sink = sink this.onLimit = onLimit - this.remaining = maxBytes } /** @@ -54,18 +57,32 @@ export class LogBuffer { */ push(text: string): void { if (this.truncated) return - const cost = Buffer.byteLength(text, 'utf8') - if (cost > this.remaining) { + const separatorBytes = this.entries > 0 ? 1 : 0 + const availableBytes = this.maxBytes - this.bytes - separatorBytes + const stringBytes = jsonStringBytesUpTo(text, availableBytes) + if (stringBytes === undefined) { this.truncated = true - const prefix = truncateUtf8Bytes(text, this.remaining) - if (prefix.length > 0) this.sink(prefix) - this.remaining = 0 + const prefix = truncateJsonStringBytes(text, availableBytes) + if (prefix.length > 0) { + const prefixBytes = jsonStringBytesUpTo(prefix, availableBytes) + /* v8 ignore next -- truncateJsonStringBytes guarantees the returned prefix fits. */ + if (prefixBytes === undefined) throw new Error('worker output ledger produced an oversized log prefix') + this.bytes += prefixBytes + separatorBytes + this.entries += 1 + this.sink(prefix) + } this.onLimit() return } - this.remaining -= cost + this.bytes += stringBytes + separatorBytes + this.entries += 1 this.sink(text) } + + /** Remaining exact JSON-byte budget for the completion value or failure message. */ + remainingOutputBytes(): number { + return this.maxBytes - this.bytes + } } /** The five console methods the shim captures, in the seam's level vocabulary. */ @@ -123,38 +140,22 @@ export function captureStreamWrites(logs: LogBuffer, stream: PatchableStream): ( /** Bounded inspect options: deep enough to be useful, bounded so a pathological value cannot explode the rendering. */ const INSPECT_OPTIONS = { depth: 4, maxArrayLength: 100, maxStringLength: 10_000 } as const -/** - * The longest prefix of `text` whose UTF-8 encoding fits `maxBytes`, cut at - * a code-point boundary (never mid-surrogate-pair). The byte caps are BYTE - * caps — `String.prototype.slice` counts UTF-16 code units, up to 3× smaller - * than what a multibyte string actually costs across the boundary. - * @param text - the string to bound. - * @param maxBytes - the UTF-8 byte budget the prefix must fit. - * @returns the prefix (all of `text` when it already fits). - */ -export function truncateUtf8Bytes(text: string, maxBytes: number): string { - if (Buffer.byteLength(text, 'utf8') <= maxBytes) return text - let bytes = 0 - let end = 0 - for (const char of text) { - const cost = Buffer.byteLength(char, 'utf8') - if (bytes + cost > maxBytes) break - bytes += cost - end += char.length - } - return text.slice(0, end) -} - /** * Prepare the program's completion value for the done message. Only lossless - * JSON crosses, and an individually oversized value reports `output-limit`; - * the host revalidates both and accounts for the combined outer envelope. + * JSON crosses, and a value that does not fit the remaining combined outer + * budget reports `output-limit`; the host revalidates hostile traffic and + * remains authoritative for native pipe writes the worker cannot observe. * * @param value - the program's completion value. - * @param maxOutputBytes - the byte cap for the outer result. + * @param remainingOutputBytes - exact bytes left after captured logs. + * @param maxOutputBytes - the configured cap named in an overflow diagnostic. * @returns the done-message fragment: `{}` for `undefined`, else a flat wire `{ value }`. */ -export function prepareCompletion(value: unknown, maxOutputBytes: number): Omit { +export function prepareCompletion( + value: unknown, + remainingOutputBytes: number, + maxOutputBytes: number = remainingOutputBytes, +): Omit { if (value === undefined) return {} let snapshot: ReturnType try { @@ -163,35 +164,102 @@ export function prepareCompletion(value: unknown, maxOutputBytes: number): Omit< snapshot = undefined } if (snapshot === undefined) { - return { error: { kind: 'invalid-output', message: 'program completion must be lossless JSON' } } + return prepareFailure( + 'invalid-output', + 'program completion must be lossless JSON', + remainingOutputBytes, + maxOutputBytes, + ) } - if (jsonValueBytesUpTo(snapshot, maxOutputBytes) === undefined) { - return { error: { kind: 'output-limit', message: `outer output exceeded ${maxOutputBytes} bytes` } } + if (jsonValueBytesUpTo(snapshot, remainingOutputBytes) === undefined) { + return outputLimit(maxOutputBytes) } return { value: encodeWorkerJson(snapshot) } } +/** Build the fixed overflow fragment without carrying rejected variable bytes. */ +function outputLimit(maxOutputBytes: number): Omit { + return { error: { kind: 'output-limit', message: `outer output exceeded ${maxOutputBytes} bytes` } } +} + +/** Admit one bounded failure message or replace it with the fixed overflow diagnostic. */ +function prepareFailure( + kind: 'exception' | 'invalid-output', + message: string, + remainingOutputBytes: number, + maxOutputBytes: number, +): Omit { + if (jsonStringBytesUpTo(message, remainingOutputBytes) === undefined) return outputLimit(maxOutputBytes) + return { error: { kind, message } } +} + +/** + * Prepare a thrown program value without sending an unbounded stack or + * string across the worker port. + * @param error - the value thrown by the program. + * @param remainingOutputBytes - exact bytes left after captured logs. + * @param maxOutputBytes - the configured cap named in an overflow diagnostic. + * @returns a bounded exception or fixed output-limit fragment. + */ +export function prepareException( + error: unknown, + remainingOutputBytes: number, + maxOutputBytes: number = remainingOutputBytes, +): Omit { + let message: string + try { + const detail: unknown = error instanceof Error ? error.stack ?? error.message : error + message = typeof detail === 'string' ? detail : String(detail) + } catch { + message = 'program threw an unrenderable value' + } + return prepareFailure('exception', message, remainingOutputBytes, maxOutputBytes) +} + /** One awaited binding call's settlement handles, keyed by call id in the pending map. */ export interface PendingCall { resolve(value: unknown): void reject(error: Error): void } -/** Program-visible typed rejection for a failed member of the `tools` namespace. */ -export class ToolCallError extends Error { - override readonly name = 'ToolCallError' - readonly toolName: string +/** Constructor shape for one program-visible binding rejection class. */ +export type BindingErrorConstructor = new (memberName: string, message: string) => Error - constructor(toolName: string, message: string) { - super(message) - this.toolName = toolName +/** + * Materialize the real error constructor declared by one namespace. + * @param descriptor - program-global class name and member-name property. + * @returns the constructor injected into the program and used for rejections. + */ +export function makeBindingErrorClass( + descriptor: { name: string; memberNameProperty: string }, +): BindingErrorConstructor { + return class BindingCallError extends Error { + constructor(memberName: string, message: string) { + super(message) + Object.defineProperty(this, 'name', { enumerable: true, value: descriptor.name }) + Object.defineProperty(this, descriptor.memberNameProperty, { enumerable: true, value: memberName }) + } } } -/** Create the namespace-specific rejection for one lossy binding argument. */ -function bindingArgumentFailure(global: string, name: string): Error { - const message = 'binding arguments must be lossless JSON' - return global === 'tools' ? new ToolCallError(name, message) : new Error(message) +/** Create the namespace-specific rejection for one failed binding call. */ +function bindingFailure(errorClass: BindingErrorConstructor | undefined, memberName: string, message: string): Error { + return errorClass ? new errorClass(memberName, message) : new Error(message) +} + +/** + * Build each declared error class once so calls and `instanceof` share constructor identity. + * @param data - binding namespace declarations from the boot payload. + * @returns constructors keyed by their owning namespace global. + */ +export function makeBindingErrorClasses( + data: Pick, +): Map { + const classes = new Map() + for (const namespace of data.namespaces) { + if (namespace.errorClass) classes.set(namespace.global, makeBindingErrorClass(namespace.errorClass)) + } + return classes } /** @@ -229,6 +297,7 @@ export function wireReplies(port: BootstrapPort, pending: Map, nextId: { value: number }, + errorClasses: Map = makeBindingErrorClasses(data), ): Record[] { return data.namespaces.map(({ global, names }) => { + const errorClass = errorClasses.get(global) const namespace = Object.create(null) as Record for (const name of names) { Object.defineProperty(namespace, name, { @@ -249,13 +320,15 @@ export function makeNamespaces( } catch { detached = undefined } - if (detached === undefined) return Promise.reject(bindingArgumentFailure(global, name)) + if (detached === undefined) { + return Promise.reject(bindingFailure(errorClass, name, 'binding arguments must be lossless JSON')) + } return new Promise((resolve, reject) => { const id = nextId.value++ pending.set(id, { resolve, reject: (error) => { - reject(global === 'tools' ? new ToolCallError(name, error.message) : error) + reject(bindingFailure(errorClass, name, error.message)) }, }) try { @@ -263,7 +336,7 @@ export function makeNamespaces( } catch (error: unknown) { pending.delete(id) const message = `binding arguments must be structured-cloneable: ${error instanceof Error ? error.message : String(error)}` - reject(global === 'tools' ? new ToolCallError(name, message) : new Error(message)) + reject(bindingFailure(errorClass, name, message)) } }) }, @@ -298,7 +371,18 @@ export async function runWorkerMain( wireReplies(port, pending) const nextId = { value: 1 } - const namespaces = makeNamespaces(data, port, pending, nextId) + const errorClasses = makeBindingErrorClasses(data) + const namespaces = makeNamespaces(data, port, pending, nextId, errorClasses) + const errorClassParameters: string[] = [] + const errorClassValues: BindingErrorConstructor[] = [] + for (const namespace of data.namespaces) { + if (!namespace.errorClass) continue + errorClassParameters.push(namespace.errorClass.name) + const errorClass = errorClasses.get(namespace.global) + /* v8 ignore next -- makeBindingErrorClasses covers every declaration in the same data. */ + if (!errorClass) throw new Error(`missing binding error class for ${namespace.global}`) + errorClassValues.push(errorClass) + } const consoleShim = makeConsoleShim(logs) let done: DoneMessage @@ -307,12 +391,22 @@ export async function runWorkerMain( // `AsyncFunction` is not a global. The program body is strict-mode. /* v8 ignore next -- the arrow exists only to reach the AsyncFunction constructor; it is never invoked. */ const AsyncFunction = (async () => {}).constructor as new (...args: string[]) => (...fnArgs: unknown[]) => Promise - const fn = new AsyncFunction(...data.namespaces.map(namespace => namespace.global), 'ToolCallError', 'console', `'use strict';\n${data.code}`) - const value = await fn(...namespaces, ToolCallError, consoleShim) - done = { type: 'done', ...prepareCompletion(value, data.maxOutputBytes) } + const fn = new AsyncFunction( + ...data.namespaces.map(namespace => namespace.global), + ...errorClassParameters, + 'console', + `'use strict';\n${data.code}`, + ) + const value = await fn(...namespaces, ...errorClassValues, consoleShim) + done = { + type: 'done', + ...prepareCompletion(value, logs.remainingOutputBytes(), data.maxOutputBytes), + } } catch (error: unknown) { - const message = error instanceof Error ? error.stack ?? error.message : String(error) - done = { type: 'done', error: { kind: 'exception', message } } + done = { + type: 'done', + ...prepareException(error, logs.remainingOutputBytes(), data.maxOutputBytes), + } } port.postMessage(done) } diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index 4f842e69eb..e7eae65f2b 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -13,7 +13,7 @@ import { fileURLToPath } from 'node:url' import { Context } from 'cordis' import z from 'schemastery' import { CodeRuntime } from '@deepseek-ai/dsh-code-runtime' -import type { CodeBindingFunction, CodeJsonValue, CodeRunFailure, CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' +import type { CodeBindingNamespace, CodeJsonValue, CodeRunFailure, CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' import { snapshotJsonValue } from '@deepseek-ai/dsh-session' import type { ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts' import { jsonStringBytesUpTo, jsonValueBytesUpTo, truncateJsonStringBytes } from './output-json.ts' @@ -74,6 +74,9 @@ const RESERVED_WORDS = new Set([ /** Valid async-function parameter name (the binding global becomes one). */ const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/ +/** Error properties whose binding-member replacement would destroy the promised Error contract. */ +const RESERVED_ERROR_PROPERTIES = new Set(['name', 'message', 'stack']) + /** * The shell a program is wrapped in for the type-strip, matching the * grammatical context it will execute in (an async function body, where @@ -312,17 +315,33 @@ export class WorkerCodeRuntime extends CodeRuntime { return new OutputLedger(this.config.maxOutputBytes).failure([], error) } - /** Reject (seam misuse) malformed binding namespaces: non-identifier or reserved globals, duplicates, and the `console` collision. */ - private validateBindings(request: CodeRunRequest): Map> { - const bindings = new Map>() + /** Reject malformed binding globals or typed-error declarations as seam misuse. */ + private validateBindings(request: CodeRunRequest): Map { + const bindings = new Map() for (const namespace of request.bindings) { if (!IDENTIFIER.test(namespace.global) || RESERVED_WORDS.has(namespace.global)) { throw new Error(`dsh-code-runtime-worker: binding global ${JSON.stringify(namespace.global)} is not a usable identifier`) } - if (namespace.global === 'console' || namespace.global === 'ToolCallError' || bindings.has(namespace.global)) { + if (namespace.global === 'console' || bindings.has(namespace.global)) { throw new Error(`dsh-code-runtime-worker: duplicate binding global ${JSON.stringify(namespace.global)}`) } - bindings.set(namespace.global, namespace.functions) + bindings.set(namespace.global, namespace) + } + + const errorClassNames = new Set() + for (const namespace of request.bindings) { + const descriptor = namespace.errorClass + if (!descriptor) continue + if (!IDENTIFIER.test(descriptor.name) || RESERVED_WORDS.has(descriptor.name)) { + throw new Error(`dsh-code-runtime-worker: binding error class ${JSON.stringify(descriptor.name)} is not a usable identifier`) + } + if (descriptor.name === 'console' || bindings.has(descriptor.name) || errorClassNames.has(descriptor.name)) { + throw new Error(`dsh-code-runtime-worker: duplicate injected global ${JSON.stringify(descriptor.name)}`) + } + if (descriptor.memberNameProperty.length === 0 || RESERVED_ERROR_PROPERTIES.has(descriptor.memberNameProperty)) { + throw new Error(`dsh-code-runtime-worker: binding error member property ${JSON.stringify(descriptor.memberNameProperty)} is not usable`) + } + errorClassNames.add(descriptor.name) } return bindings } @@ -331,11 +350,15 @@ export class WorkerCodeRuntime extends CodeRuntime { private execute( request: CodeRunRequest, code: string, - bindings: Map>, + bindings: Map, ): Promise { const bootData: WorkerBootData = { code, - namespaces: [...bindings].map(([global, functions]) => ({ global, names: Object.keys(functions) })), + namespaces: [...bindings].map(([global, namespace]) => ({ + global, + names: Object.keys(namespace.functions), + ...namespace.errorClass ? { errorClass: namespace.errorClass } : {}, + })), maxOutputBytes: this.config.maxOutputBytes, } const worker = new Worker(WORKER_PATH, { @@ -435,7 +458,7 @@ export class WorkerCodeRuntime extends CodeRuntime { // this point, so this payload is structured-cloneable by contract. worker.postMessage(payload) } - const record = bindings.get(message.global) + const record = bindings.get(message.global)?.functions // Own-property lookup only: a forged name like 'constructor' or // 'hasOwnProperty' must not walk the record's prototype chain and // reach a callable the consumer never declared. diff --git a/packages/code-runtime/code-runtime-worker/src/protocol.ts b/packages/code-runtime/code-runtime-worker/src/protocol.ts index 8d8ec54b60..11559d23b7 100644 --- a/packages/code-runtime/code-runtime-worker/src/protocol.ts +++ b/packages/code-runtime/code-runtime-worker/src/protocol.ts @@ -11,8 +11,12 @@ import type { WorkerJsonWire } from './worker-json.ts' export interface WorkerBootData { /** The type-stripped (plain JS) program body. */ code: string - /** Binding namespaces to materialize: the global name plus the function names (functions themselves stay host-side). */ - namespaces: { global: string; names: string[] }[] + /** Binding namespaces to materialize; functions themselves stay host-side. */ + namespaces: { + global: string + names: string[] + errorClass?: { name: string; memberNameProperty: string } + }[] /** Hard cap for the combined serialized outer logs plus completion value or failure diagnostic. */ maxOutputBytes: number } @@ -42,12 +46,12 @@ interface OutputLimitMessage { } /** - * Worker → host: the program settled. `error` carries a program exception - * (the only failure the bootstrap itself can report — budgets, aborts, and - * substrate death are observed host-side). `value` is present only on a - * clean completion that produced one, as a flat wire value already - * size-capped and lossless per the bootstrap. Logs are NOT carried here — - * they streamed eagerly as {@link LogMessage}s. + * Worker → host: the program settled. `error` carries a program exception, + * invalid completion, or output overflow (budgets, aborts, and substrate death + * are observed host-side). `value` is present only on a clean completion that + * produced one, as a flat wire value already lossless and admitted against + * the remaining combined output cap. Logs are NOT carried here — they streamed + * eagerly as {@link LogMessage}s. */ export interface DoneMessage { type: 'done' diff --git a/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts b/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts index 78af789169..a2aac6d9c2 100644 --- a/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' import { EventEmitter } from 'node:events' -import { LogBuffer, makeConsoleShim, makeNamespaces, captureStreamWrites, prepareCompletion, runWorkerMain, ToolCallError, truncateUtf8Bytes, wireReplies } from '../src/bootstrap.ts' +import { LogBuffer, makeBindingErrorClasses, makeConsoleShim, makeNamespaces, captureStreamWrites, prepareCompletion, prepareException, runWorkerMain, wireReplies } from '../src/bootstrap.ts' import type { BootstrapPort, PatchableStream, PendingCall } from '../src/bootstrap.ts' import type { ReplyMessage, WorkerToHost } from '../src/protocol.ts' import { decodeWorkerJson, encodeWorkerJson } from '../src/worker-json.ts' @@ -60,23 +60,30 @@ async function rejectionOf(promise: Promise): Promise { } const BOOT = { maxOutputBytes: 65_536 } +const TOOL_ERROR_CLASS = { name: 'ToolCallError', memberNameProperty: 'toolName' } as const + +/** One worker declaration for the Code Mode tools namespace. */ +function toolNamespace(names: string[]) { + return { global: 'tools', names, errorClass: TOOL_ERROR_CLASS } +} describe('LogBuffer', () => { it('streams entries to the sink until the byte budget, then emits one fitting prefix and reports the limit once', () => { const seen: string[] = [] let limits = 0 - const buffer = new LogBuffer(10, text => seen.push(text), () => { limits += 1 }) + const buffer = new LogBuffer(15, text => seen.push(text), () => { limits += 1 }) buffer.push('12345') buffer.push('123456') buffer.push('dropped') - expect(seen).toEqual(['12345', '12345']) + expect(seen).toEqual(['12345', '123']) expect(limits).toBe(1) + expect(buffer.remainingOutputBytes()).toBe(0) const exactlyFull: string[] = [] - const fullBuffer = new LogBuffer(4, text => exactlyFull.push(text)) - fullBuffer.push('1234') + const fullBuffer = new LogBuffer(6, text => exactlyFull.push(text)) + fullBuffer.push('12') fullBuffer.push('no-prefix-fits') - expect(exactlyFull).toEqual(['1234']) + expect(exactlyFull).toEqual(['12']) }) }) @@ -167,19 +174,32 @@ describe('prepareCompletion', () => { error: { kind: 'invalid-output', message: 'program completion must be lossless JSON' }, }) }) + + it('uses the remaining combined budget for invalid-output diagnostics', () => { + expect(prepareCompletion(() => 1, 4, 64)).toEqual({ + error: { kind: 'output-limit', message: 'outer output exceeded 64 bytes' }, + }) + }) }) -describe('truncateUtf8Bytes', () => { - it('returns a fitting string whole', () => { - expect(truncateUtf8Bytes('fits', 4)).toBe('fits') +describe('prepareException', () => { + it('passes a fitting diagnostic and rejects one byte over without carrying its text', () => { + expect(prepareException('boom', 6, 64)).toEqual({ error: { kind: 'exception', message: 'boom' } }) + expect(prepareException('boom', 5, 64)).toEqual({ + error: { kind: 'output-limit', message: 'outer output exceeded 64 bytes' }, + }) }) - it('cuts at a code-point boundary, never mid-surrogate-pair', () => { - // Each 😀 is one code point, two code units, four UTF-8 bytes: a 5-byte - // budget fits exactly one — and never leaves a lone surrogate behind. - const cut = truncateUtf8Bytes('😀😀', 5) - expect(cut).toBe('😀') - expect(Buffer.byteLength(truncateUtf8Bytes('😀😀', 3), 'utf8')).toBe(0) + it('contains a thrown value whose string conversion fails', () => { + const thrown = { toString() { throw new Error('cannot render') } } + expect(prepareException(thrown, 1_000)).toEqual({ + error: { kind: 'exception', message: 'program threw an unrenderable value' }, + }) + + const strangeStack = Object.defineProperty(new Error('ignored'), 'stack', { value: 42 }) + expect(prepareException(strangeStack, 1_000)).toEqual({ + error: { kind: 'exception', message: '42' }, + }) }) }) @@ -219,7 +239,16 @@ describe('makeNamespaces', () => { on: () => {}, } const pending = new Map() - const [tools] = makeNamespaces({ namespaces: [{ global: 'tools', names: ['x'] }] }, throwingPort, pending, { value: 1 }) as [Record Promise>] + const data = { namespaces: [toolNamespace(['x'])] } + const errorClasses = makeBindingErrorClasses(data) + const ToolCallError = errorClasses.get('tools') + const [tools] = makeNamespaces( + data, + throwingPort, + pending, + { value: 1 }, + errorClasses, + ) as [Record Promise>] const first = await rejectionOf(tools.x?.({ first: true }) ?? Promise.resolve()) const second = await rejectionOf(tools.x?.({ second: true }) ?? Promise.resolve()) expect(first).toMatchObject({ name: 'ToolCallError', toolName: 'x' }) @@ -237,7 +266,7 @@ describe('makeNamespaces', () => { const pending = new Map() const nextId = { value: 1 } const [tools] = makeNamespaces( - { namespaces: [{ global: 'tools', names: ['x'] }] }, port, pending, nextId, + { namespaces: [toolNamespace(['x'])] }, port, pending, nextId, ) as [Record Promise>] const decorated = [1] Object.defineProperty(decorated, 'extra', { value: true }) @@ -267,18 +296,18 @@ describe('makeNamespaces', () => { const [helpers] = makeNamespaces({ namespaces: [{ global: 'helpers', names: ['x'] }] }, deniedPort, deniedPending, { value: 1 }) as [Record Promise>] const denied = await rejectionOf(helpers.x?.({}) ?? Promise.resolve()) expect(denied).toBeInstanceOf(Error) - expect(denied).not.toBeInstanceOf(ToolCallError) + expect(denied).toMatchObject({ name: 'Error', message: 'helper denied' }) + expect(denied).not.toHaveProperty('toolName') const invalid = await rejectionOf(helpers.x?.(() => 1) ?? Promise.resolve()) expect(invalid).toBeInstanceOf(Error) - expect(invalid).not.toBeInstanceOf(ToolCallError) expect((invalid as Error).message).toBe('binding arguments must be lossless JSON') const clonePort: BootstrapPort = { postMessage: () => { throw new Error('clone failed') }, on: () => {} } const [cloneHelpers] = makeNamespaces({ namespaces: [{ global: 'helpers', names: ['x'] }] }, clonePort, new Map(), { value: 1 }) as [Record Promise>] const cloneFailure = await rejectionOf(cloneHelpers.x?.({}) ?? Promise.resolve()) expect(cloneFailure).toBeInstanceOf(Error) - expect(cloneFailure).not.toBeInstanceOf(ToolCallError) + expect(cloneFailure).not.toHaveProperty('toolName') }) }) @@ -306,9 +335,12 @@ describe('runWorkerMain', () => { code: 'console.log("12345"); return null', namespaces: [], }, fakeStreams()) - expect(port.sent).toContainEqual({ type: 'log', text: '1234' }) + expect(port.logs()).toEqual([]) expect(port.sent).toContainEqual({ type: 'output-limit' }) - expect(port.doneValue()).toBeNull() + expect(port.done()).toEqual({ + type: 'done', + error: { kind: 'output-limit', message: 'outer output exceeded 4 bytes' }, + }) }) it('reports a thrown program error on the done message', async () => { @@ -331,16 +363,56 @@ describe('runWorkerMain', () => { expect(barePort.done()).toEqual({ type: 'done', error: { kind: 'exception', message: 'bare' } }) }) + it('replaces giant thrown strings and Error stacks before posting the done message', async () => { + const rawPort = new FakePort() + await runWorkerMain(rawPort, { + maxOutputBytes: 64, + code: 'throw "x".repeat(1_000_000)', + namespaces: [], + }, fakeStreams()) + expect(rawPort.done()).toEqual({ + type: 'done', + error: { kind: 'output-limit', message: 'outer output exceeded 64 bytes' }, + }) + + const stackPort = new FakePort() + await runWorkerMain(stackPort, { + maxOutputBytes: 64, + code: 'throw new Error("x".repeat(1_000_000))', + namespaces: [], + }, fakeStreams()) + expect(stackPort.done()).toEqual({ + type: 'done', + error: { kind: 'output-limit', message: 'outer output exceeded 64 bytes' }, + }) + }) + it('surfaces a host failure reply as a program-side rejection it can catch', async () => { const port = new FakePort() port.respond = message => message.type === 'call' ? { type: 'reply', id: message.id, ok: false, message: 'denied by host' } : undefined await runWorkerMain(port, { ...BOOT, code: 'try { await tools.x({}) } catch (error) { return { caught: error instanceof ToolCallError, name: error.name, toolName: error.toolName, message: error.message } }', - namespaces: [{ global: 'tools', names: ['x'] }], + namespaces: [toolNamespace(['x'])], }, fakeStreams()) expect(port.doneValue()).toEqual({ caught: true, name: 'ToolCallError', toolName: 'x', message: 'denied by host' }) - expect(new ToolCallError('x', 'nope')).toMatchObject({ name: 'ToolCallError', toolName: 'x', message: 'nope' }) + }) + + it('materializes a consumer-declared rejection class without knowing the namespace', async () => { + const port = new FakePort() + port.respond = message => message.type === 'call' + ? { type: 'reply', id: message.id, ok: false, message: 'helper denied' } + : undefined + await runWorkerMain(port, { + ...BOOT, + code: 'try { await helpers.x({}) } catch (error) { return { caught: error instanceof HelperCallError, name: error.name, helperName: error.helperName, message: error.message } }', + namespaces: [{ + global: 'helpers', + names: ['x'], + errorClass: { name: 'HelperCallError', memberNameProperty: 'helperName' }, + }], + }, fakeStreams()) + expect(port.doneValue()).toEqual({ caught: true, name: 'HelperCallError', helperName: 'x', message: 'helper denied' }) }) it('ignores replies for unknown pending ids', async () => { diff --git a/packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts b/packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts index ff68fd09fe..4c6098a2ec 100644 --- a/packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts +++ b/packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts @@ -23,8 +23,15 @@ describe.skipIf(!built)('built lib real load path (plain node)', () => { const ctx = new Context() await ctx.plugin(WorkerCodeRuntime, {}) const result = await ctx.codeRuntime.run({ - program: 'const doubled: number = await tools.double({ n: 21 }); console.log("halfway", doubled); return doubled;', - bindings: [{ global: 'tools', functions: { double: async args => args.n * 2 } }], + program: 'const doubled: number = await tools.double({ n: 21 }); console.log("halfway", doubled); let failure; try { await tools.fail({}) } catch (error) { failure = { typed: error instanceof ToolCallError, name: error.name, toolName: error.toolName, message: error.message } } return { doubled, failure };', + bindings: [{ + global: 'tools', + functions: { + double: async args => args.n * 2, + fail: async () => { throw new Error('denied') }, + }, + errorClass: { name: 'ToolCallError', memberNameProperty: 'toolName' }, + }], }) console.log(JSON.stringify(result)) process.exit(0) @@ -40,7 +47,10 @@ describe.skipIf(!built)('built lib real load path (plain node)', () => { const lastLine = stdout.trim().split('\n').at(-1) ?? '' const result = JSON.parse(lastLine) as { value?: unknown; logs: string[]; error?: unknown } expect(result.error).toBeUndefined() - expect(result.value).toBe(42) + expect(result.value).toEqual({ + doubled: 42, + failure: { typed: true, name: 'ToolCallError', toolName: 'fail', message: 'denied' }, + }) expect(result.logs).toContain('halfway 42') }) }) diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index 45b45520e0..a58675d1ed 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -18,7 +18,11 @@ async function setup(config: Config = {}) { /** Convenience: one namespace `tools` with the given functions. */ function tools(functions: Record Promise>): CodeBindingNamespace[] { - return [{ global: 'tools', functions: functions as Record }] + return [{ + global: 'tools', + functions: functions as Record, + errorClass: { name: 'ToolCallError', memberNameProperty: 'toolName' }, + }] } describe('WorkerCodeRuntime — programs and bindings (real workers)', () => { @@ -74,6 +78,33 @@ describe('WorkerCodeRuntime — programs and bindings (real workers)', () => { expect(calls).toEqual([{ n: 1 }]) }) + it('materializes a typed rejection from a generic namespace descriptor', async () => { + const { runtime } = await setup() + const result = await runtime.run({ + program: ` + try { await helpers.fail({}) } catch (error) { + return { + isTyped: error instanceof HelperCallError, + name: error.name, + helperName: error.helperName, + message: error.message, + }; + } + `, + bindings: [{ + global: 'helpers', + functions: { fail: async () => { throw new Error('nope') } }, + errorClass: { name: 'HelperCallError', memberNameProperty: 'helperName' }, + }], + }) + expect(result.value).toEqual({ + isTyped: true, + name: 'HelperCallError', + helperName: 'fail', + message: 'nope', + }) + }) + it('bridges a deeply nested lossless JSON argument, resolution, and completion', async () => { const { runtime } = await setup() const result = await runtime.run({ @@ -304,6 +335,31 @@ describe('WorkerCodeRuntime — budgets and containment (real workers)', () => { expect(Buffer.byteLength(JSON.stringify(result.logs), 'utf8') + Buffer.byteLength(JSON.stringify(result.error?.message), 'utf8')).toBeLessThanOrEqual(10) }) + it('accounts logs and exception diagnostics before the worker port boundary', async () => { + // JSON(["abc"]) is seven bytes and JSON("xy") is four. + const exact = await setup({ maxOutputBytes: 11 }) + expect(await exact.runtime.run({ program: 'console.log("abc"); throw "xy"', bindings: [] })) + .toEqual({ logs: ['abc'], error: { kind: 'exception', message: 'xy' } }) + + const over = await setup({ maxOutputBytes: 10 }) + const result = await over.runtime.run({ program: 'console.log("abc"); throw "xy"', bindings: [] }) + expect(result.error?.kind).toBe('output-limit') + expect(Buffer.byteLength(JSON.stringify(result.logs), 'utf8') + + Buffer.byteLength(JSON.stringify(result.error?.message), 'utf8')).toBeLessThanOrEqual(10) + }) + + it('does not send a giant Error stack across the worker port', async () => { + const { runtime } = await setup({ maxOutputBytes: 64 }) + const result = await runtime.run({ + program: 'throw new Error("x".repeat(1_000_000))', + bindings: [], + }) + expect(result).toEqual({ + logs: [], + error: { kind: 'output-limit', message: 'outer output exceeded 64 bytes' }, + }) + }) + it('completes a program that awaits its write callback, capturing the chunk', async () => { // Node's write(chunk[, encoding][, callback]) contract: dropping the // callback would leave this promise pending until the wall ceiling and @@ -448,6 +504,22 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { expect(Buffer.byteLength(JSON.stringify(result.logs), 'utf8')).toBeLessThan(200) }) + it('re-caps an oversized forged done value at the host boundary', async () => { + const { runtime } = await setup({ maxOutputBytes: 64 }) + const result = await runtime.run({ + program: ` + const { parentPort } = await import('node:worker_threads'); + parentPort.postMessage({ type: 'done', value: ['V'.repeat(100_000)] }); + for (;;) {} + `, + bindings: [], + }) + expect(result).toEqual({ + logs: [], + error: { kind: 'output-limit', message: 'outer output exceeded 64 bytes' }, + }) + }) + it('bounds one oversized forged log while retaining its fitting escaped prefix', async () => { const { runtime } = await setup({ maxOutputBytes: 96 }) const result = await runtime.run({ @@ -634,13 +706,12 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { }) describe('WorkerCodeRuntime — seam misuse and lifecycle', () => { - it('rejects invalid binding globals loudly (identifier, reserved word, duplicate, reserved injected globals)', async () => { + it('rejects invalid and duplicate binding globals loudly', async () => { const { runtime } = await setup() const cases: [string, RegExp][] = [ ['not valid!', /not a usable identifier/], ['await', /not a usable identifier/], ['console', /duplicate binding global/], - ['ToolCallError', /duplicate binding global/], ] for (const [global, message] of cases) { await expect(runtime.run({ program: 'return 1', bindings: [{ global, functions: {} }] })).rejects.toThrow(message) @@ -649,6 +720,32 @@ describe('WorkerCodeRuntime — seam misuse and lifecycle', () => { program: 'return 1', bindings: [{ global: 'tools', functions: {} }, { global: 'tools', functions: {} }], })).rejects.toThrow(/duplicate binding global/) + + await expect(runtime.run({ + program: 'return typeof ToolCallError', + bindings: [{ global: 'ToolCallError', functions: {} }], + })).resolves.toMatchObject({ value: 'object' }) + }) + + it('rejects malformed or colliding binding error-class declarations', async () => { + const { runtime } = await setup() + const run = async (bindings: CodeBindingNamespace[]) => await runtime.run({ program: 'return 1', bindings }) + const namespace = (global: string, name: string, memberNameProperty = 'memberName'): CodeBindingNamespace => ({ + global, + functions: {}, + errorClass: { name, memberNameProperty }, + }) + + await expect(run([namespace('tools', 'not valid!')])).rejects.toThrow(/error class.*not a usable identifier/) + await expect(run([namespace('tools', 'await')])).rejects.toThrow(/error class.*not a usable identifier/) + await expect(run([namespace('tools', 'console')])).rejects.toThrow(/duplicate injected global/) + await expect(run([namespace('tools', 'tools')])).rejects.toThrow(/duplicate injected global/) + await expect(run([ + namespace('tools', 'CallError'), + namespace('helpers', 'CallError'), + ])).rejects.toThrow(/duplicate injected global/) + await expect(run([namespace('tools', 'CallError', '')])).rejects.toThrow(/member property.*not usable/) + await expect(run([namespace('tools', 'CallError', 'message')])).rejects.toThrow(/member property.*not usable/) }) it('rejects config values that are not positive numbers', async () => { diff --git a/packages/code-runtime/code-runtime/README.md b/packages/code-runtime/code-runtime/README.md index 24e1fb51a1..f8e09e301e 100644 --- a/packages/code-runtime/code-runtime/README.md +++ b/packages/code-runtime/code-runtime/README.md @@ -16,7 +16,7 @@ Semantics every implementation must honor (contract details in the class JSDoc): ## Vocabulary -`CodeRunRequest` (`program`, `bindings`, `signal?`) carries everything the runtime acts on — defaulting (time budgets and outer-output cap) is the implementation's validated config, never a hidden `??` inside `run()`. `bindings` is a list of `CodeBindingNamespace`s (`global` + `functions`), each exposed to the program as one global object of async callables returning `CodeJsonValue`, the seam-local structural equivalent of canonical `JsonValue` that keeps this interface package independent of sessions. `CodeRunResult` reports the lossless JSON completion `value?`, ordered `logs: string[]`, and the `error?` (`CodeRunFailure`: `kind` + model-feedable `message`). See `src/types.ts` for the full contracts. +`CodeRunRequest` (`program`, `bindings`, `signal?`) carries everything the runtime acts on — defaulting (time budgets and outer-output cap) is the implementation's validated config, never a hidden `??` inside `run()`. `bindings` is a list of `CodeBindingNamespace`s (`global` + `functions` + optional `errorClass`), each exposed to the program as one global object of async callables returning `CodeJsonValue`, the seam-local structural equivalent of canonical `JsonValue` that keeps this interface package independent of sessions. An `errorClass` descriptor names a real program-global constructor and the own property that receives the rejected member name; runtimes remain independent of consumer terms such as `ToolCallError`. `CodeRunResult` reports the lossless JSON completion `value?`, ordered `logs: string[]`, and the `error?` (`CodeRunFailure`: `kind` + model-feedable `message`). See `src/types.ts` for the full contracts. ## Model Experience diff --git a/packages/code-runtime/code-runtime/src/index.ts b/packages/code-runtime/code-runtime/src/index.ts index 9b9fd0d48e..bd52b9ed29 100644 --- a/packages/code-runtime/code-runtime/src/index.ts +++ b/packages/code-runtime/code-runtime/src/index.ts @@ -8,6 +8,7 @@ import { Context, Service } from 'cordis' import type { CodeRunRequest, CodeRunResult } from './types.ts' export type { + CodeBindingErrorClass, CodeBindingFunction, CodeBindingNamespace, CodeJsonValue, @@ -25,8 +26,9 @@ declare module 'cordis' { /** * Registers one `ctx.codeRuntime` implementation. Program, budget, abort, and substrate * failures resolve in {@link CodeRunResult}; only seam misuse rejects. Implementations bridge - * structured-cloneable bindings while treating programs as hostile peers, isolate runs from - * one another, and terminate and await in-flight runs during disposal. + * structured-cloneable bindings, materialize each declared namespace rejection + * class, treat programs as hostile peers, isolate runs from one another, and + * terminate and await in-flight runs during disposal. */ export abstract class CodeRuntime extends Service { /** diff --git a/packages/code-runtime/code-runtime/src/types.ts b/packages/code-runtime/code-runtime/src/types.ts index 259e497e14..a53353799b 100644 --- a/packages/code-runtime/code-runtime/src/types.ts +++ b/packages/code-runtime/code-runtime/src/types.ts @@ -20,6 +20,20 @@ export type CodeBindingFunction = (args: unknown) => Promise /** A lossless JSON value transferable across the dependency-light code-runtime seam. */ export type CodeJsonValue = null | boolean | number | string | CodeJsonValue[] | { [key: string]: CodeJsonValue } +/** + * Program-visible typed rejection for one binding namespace. The runtime + * injects a real error constructor under `name`; rejected member calls become + * its instances and expose the exact member name through + * `memberNameProperty`. Both strings are runtime data rather than knowledge + * of a particular consumer such as Code Mode. + */ +export interface CodeBindingErrorClass { + /** Constructor global and resulting `Error.name` (must be a usable JS identifier). */ + name: string + /** Non-empty own property for the member name; cannot replace `name`, `message`, or `stack`. */ + memberNameProperty: string +} + /** * A named group of {@link CodeBindingFunction}s the runtime exposes to the * program as one global object (e.g. `tools`). Function names are arbitrary @@ -32,6 +46,8 @@ export interface CodeBindingNamespace { global: string /** The callable members, keyed by the exact name the program calls. */ functions: Record + /** Optional program-visible typed rejection contract for this namespace. */ + errorClass?: CodeBindingErrorClass } /** diff --git a/packages/cordis/tool-cordis/src/api-catalog.ts b/packages/cordis/tool-cordis/src/api-catalog.ts index 118a67d554..7230fdb832 100644 --- a/packages/cordis/tool-cordis/src/api-catalog.ts +++ b/packages/cordis/tool-cordis/src/api-catalog.ts @@ -1243,13 +1243,17 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'CallId', declaration: 'export type CallId = Branded<\'CallId\'>;', }, + { + name: 'CodeBindingErrorClass', + declaration: 'export interface CodeBindingErrorClass {\n name: string;\n memberNameProperty: string;\n}', + }, { name: 'CodeBindingFunction', declaration: 'export type CodeBindingFunction = (args: unknown) => Promise;', }, { name: 'CodeBindingNamespace', - declaration: 'export interface CodeBindingNamespace {\n global: string;\n functions: Record;\n}', + declaration: 'export interface CodeBindingNamespace {\n global: string;\n functions: Record;\n errorClass?: CodeBindingErrorClass;\n}', }, { name: 'CodeJsonValue', diff --git a/packages/core/tools/src/code-mode.ts b/packages/core/tools/src/code-mode.ts index 2c7f8faedd..54c54ee57a 100644 --- a/packages/core/tools/src/code-mode.ts +++ b/packages/core/tools/src/code-mode.ts @@ -351,7 +351,11 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () => try { result = await runtime.run({ program: args.code, - bindings: [{ global: 'tools', functions }], + bindings: [{ + global: 'tools', + functions, + errorClass: { name: 'ToolCallError', memberNameProperty: 'toolName' }, + }], signal: runController.signal, }) } finally { diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index 188e89503e..a22b4a5482 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -296,6 +296,10 @@ describe('mode-aware wire contribution', () => { const { ctx, runtime } = await setup({ mode: 'both' }) registerEcho(ctx) runtime.behavior = (request) => { + expect(request.bindings[0]!.errorClass).toEqual({ + name: 'ToolCallError', + memberNameProperty: 'toolName', + }) const functions = request.bindings[0]!.functions return Promise.resolve({ logs: [], diff --git a/scripts/type-equiv.manifest.json b/scripts/type-equiv.manifest.json index b65807f78c..c8afacedd3 100644 --- a/scripts/type-equiv.manifest.json +++ b/scripts/type-equiv.manifest.json @@ -849,6 +849,11 @@ "symbol": "CodeBindingNamespace", "source": "packages/code-runtime/code-runtime/src/types.ts" }, + { + "doc": "docs/core-data-structures/code-runtime.md", + "symbol": "CodeBindingErrorClass", + "source": "packages/code-runtime/code-runtime/src/types.ts" + }, { "doc": "docs/core-data-structures/code-runtime.md", "symbol": "CodeBindingFunction", From 8379101e3b3b8ec8dae43187f89a860e2e9fba58 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:35:33 +0800 Subject: [PATCH 126/368] fix(code-runtime): keep worker helper private --- packages/code-runtime/code-runtime-worker/src/bootstrap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts index 615a0d6ee9..3b0db6b59c 100644 --- a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts +++ b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts @@ -230,7 +230,7 @@ export type BindingErrorConstructor = new (memberName: string, message: string) * @param descriptor - program-global class name and member-name property. * @returns the constructor injected into the program and used for rejections. */ -export function makeBindingErrorClass( +function makeBindingErrorClass( descriptor: { name: string; memberNameProperty: string }, ): BindingErrorConstructor { return class BindingCallError extends Error { From f8939daf0a2a75da34cb78d420def456d1714386 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:38:10 +0800 Subject: [PATCH 127/368] fix(tasks): keep bounded notices actionable --- ...06-20-generic-long-running-tool-runtime.md | 2 +- packages/tasks/tool-tasks/README.md | 4 +- packages/tasks/tool-tasks/src/index.ts | 24 ++++++++++-- .../tasks/tool-tasks/tests/tool-tasks.spec.ts | 37 +++++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md index 11425939c3..f4afb5cf5a 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -75,7 +75,7 @@ Stream reads share one task-scoped consuming cursor because the owning model is The system prompt tells the model to retain task ids, continue independent work instead of busy-polling or duplicating a running task, collect relevant tasks before its final answer, and kill work that no longer matters. Completion injects a logged `context/message` into the exact owner's session; it becomes durable context for the next request but does not wake an idle agent. -The runtime marks a terminal task `reported` when a read or wait delivers it, when a live waiter has claimed delivery at settlement, or when the model explicitly kills it. Reported tasks do not inject redundant completion notices. Listener failures are logged independently, do not stop later listeners, and are not awaited by waiters or teardown. When a snapshot carries `outputLimitBytes`, `dsh-tool-tasks` reserves space for status or notice suffixes, preserves UTF-8 boundaries, and reuses an existing producer truncation marker rather than duplicating it. +The runtime marks a terminal task `reported` when a read or wait delivers it, when a live waiter has claimed delivery at settlement, or when the model explicitly kills it. Reported tasks do not inject redundant completion notices. Listener failures are logged independently, do not stop later listeners, and are not awaited by waiters or teardown. When a snapshot carries `outputLimitBytes`, `dsh-tool-tasks` preserves UTF-8 boundaries and reuses an existing producer truncation marker rather than duplicating it. Reads reserve status suffixes and retain the output tail; completion notices reserve the stable `background task ` prefix and `task_output` instruction before truncating variable kind, label, status, or detail, so the minimum PTY cap still identifies the task to collect. ## Producer opt-in diff --git a/packages/tasks/tool-tasks/README.md b/packages/tasks/tool-tasks/README.md index f4a3475786..e3ab84f33c 100644 --- a/packages/tasks/tool-tasks/README.md +++ b/packages/tasks/tool-tasks/README.md @@ -10,11 +10,11 @@ The model-facing control surface for `ctx.tasks`: three kind-independent tools, All three use generic ACP cards: `read` for output and list, `execute` for kill. -When a producer supplies `outputLimitBytes`, `task_output`, terminal `task_kill`, and completion notices cap the complete UTF-8 result after adding status or notice text. The output tail and control suffix are retained when they fit; an existing producer truncation marker is reused rather than duplicated. Producers that omit the field retain the existing unbounded control-surface behavior. +When a producer supplies `outputLimitBytes`, `task_output`, terminal `task_kill`, and completion notices cap the complete UTF-8 result after adding status or notice text. Reads retain the output tail and control suffix when they fit; a bounded completion notice instead reserves `background task ` and the `task_output` collection instruction before spending remaining bytes on its variable kind, label, status, and detail. An existing producer truncation marker is reused rather than duplicated. Producers that omit the field retain the existing unbounded control-surface behavior. ## Completion notices -An unreported completion injects `background task (:

    ` derive TypeScript values from the same declarations that `valueSchemaSpecToJsonSchema()` and `parameterSchemaSpecToJsonSchema()` compile. Exact inference is bounded to 16 container levels and then uses `JsonValue`, preventing TypeScript's type-instantiation stack from becoming the authoring limit. `assertSupportedJsonSchema()` rejects unsupported or misplaced keywords, and `validateJsonSchemaValue()` enforces the accepted subset against the lossless `JsonValue` boundary: no `undefined`, negative zero, non-finite numbers, sparse arrays, cycles, exotic objects, functions, symbols, or other coercive values. Author compilation, raw-schema assertion, value validation, schema-to-TypeScript rendering, registry detachment, and dynamic Cordis cross-realm normalization and cloning use explicit work stacks, so runtime nesting is limited by available memory rather than the JavaScript call stack. -Object-rooting is a consumer rule rather than a vocabulary restriction. Subagent and workflow caller-defined structured outputs use `assertObjectJsonSchema()` and `ObjectJsonSchema`; tool outputs may use any root. Dynamic Cordis registrations rebuild realm-foreign schemas into host-owned JSON, preserve raw-wrapper openness, and require direct-DSL object openness before calling the same compiler. +Object-rooting is a consumer rule rather than a vocabulary restriction. Subagent and workflow caller-defined structured outputs use `assertObjectJsonSchema()` and `ObjectJsonSchema`; tool outputs may use any root. Dynamic Cordis registrations rebuild realm-foreign schemas into host-owned JSON, preserve raw-wrapper openness, and require direct-DSL object openness before calling the same compiler. The dynamic boundary rejects JSON-invisible record keys and exotic schema arrays before normalization, so it cannot silently discard a constraint or consume custom iteration semantics. ## Alternatives considered @@ -32,4 +32,4 @@ Object-rooting is a consumer rule rather than a vocabulary restriction. Subagent - Explicit object openness and type-correct literal constraints make malformed declarations fail during authoring or registration rather than during a later model call. - Bounded type inference retains useful exact types for ordinary declarations and degrades unusually deep tails to `JsonValue`; runtime schema enforcement remains exact at every depth. - Raw tools may still register broader JSON Schema directly, but unified code generation treats unsupported schemas as unknown instead of pretending to enforce them. -- Runtime and compile-time tests cover every root, exact-one overlap/no-match behavior, raw open defaults, explicit openness, lossy JSON values, inference, and deep nesting across core and dynamic projections. +- Runtime and compile-time tests cover every root, exact-one overlap/no-match behavior, raw open defaults, explicit openness, lossy JSON values, inference, deep nesting across core and dynamic projections, JSON-invisible dynamic keys, and exotic schema arrays. diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md index 77a20d17aa..00a7a19961 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md @@ -16,7 +16,7 @@ Status: implemented `InferValue` 和 `InferArgs

    ` 根据同一份声明推导 TypeScript 值,`valueSchemaSpecToJsonSchema()` 和 `parameterSchemaSpecToJsonSchema()` 也将这些声明编译为 JSON Schema。精确类型推导以 16 层容器为界,超过后使用 `JsonValue`,从而避免 TypeScript 的类型实例化栈限制作者能声明的嵌套深度。`assertSupportedJsonSchema()` 会拒绝不受支持或位置错误的关键字;`validateJsonSchemaValue()` 则以无损 `JsonValue` 边界校验受支持的子集,不允许 `undefined`、负零、非有限数、稀疏数组、循环引用、非普通对象、函数、symbol 及其他需要强制转换的值。作者侧 schema 编译、原始 schema 断言、值校验、schema 到 TypeScript 的渲染、注册表数据分离,以及动态 Cordis 的跨运行域规范化与克隆均使用显式工作栈,因此运行时嵌套只受可用内存限制,不受 JavaScript 调用栈限制。 -对象根限制属于消费方规则,不属于 schema 词汇本身。subagent 和工作流中由调用方定义的结构化输出通过 `assertObjectJsonSchema()` 和 `ObjectJsonSchema` 保持对象根限制;工具输出可以使用任意根类型。动态 Cordis 注册会把跨 JavaScript 运行域传入的 schema 重建为当前运行时持有的 JSON,保留原始包装层的默认开放语义,并要求直接使用 DSL 声明的对象明确选择开放方式,然后再调用同一编译器。 +对象根限制属于消费方规则,不属于 schema 词汇本身。subagent 和工作流中由调用方定义的结构化输出通过 `assertObjectJsonSchema()` 和 `ObjectJsonSchema` 保持对象根限制;工具输出可以使用任意根类型。动态 Cordis 注册会把跨 JavaScript 运行域传入的 schema 重建为当前运行时持有的 JSON,保留原始包装层的默认开放语义,并要求直接使用 DSL 声明的对象明确选择开放方式,然后再调用同一编译器。动态边界会在规范化之前拒绝 JSON 不可见的记录键和非普通 schema 数组,因此不会静默丢弃约束,也不会触发自定义迭代逻辑。 ## 备选方案 @@ -32,4 +32,4 @@ Status: implemented - 显式的对象开放方式和类型正确的字面量约束会让格式错误的声明在编写或注册阶段快速失败,而不是拖到后续模型调用时才失败。 - 有界类型推导会为常规声明保留有用的精确类型,并将异常深的尾部结构退化为 `JsonValue`;运行时 schema 强制执行在任意深度仍保持精确。 - 原始工具仍可直接注册范围更广的 JSON Schema,但统一代码生成会把不受支持的 schema 视为未知类型,不会假装自己能够强制执行。 -- 运行时和编译期测试覆盖所有根类型、恰好匹配一个分支时的重叠/无匹配行为、原始 schema 的默认开放语义、显式开放方式、有损 JSON 值、类型推导,以及核心投影和动态投影中的深层嵌套。 +- 运行时和编译期测试覆盖所有根类型、恰好匹配一个分支时的重叠/无匹配行为、原始 schema 的默认开放语义、显式开放方式、有损 JSON 值、类型推导、核心投影和动态投影中的深层嵌套、动态注册中 JSON 不可见的键,以及非普通 schema 数组。 diff --git a/packages/cordis/tool-cordis/README.md b/packages/cordis/tool-cordis/README.md index babf259761..1c9ccff782 100644 --- a/packages/cordis/tool-cordis/README.md +++ b/packages/cordis/tool-cordis/README.md @@ -12,7 +12,7 @@ Exact model-facing schemas: [the generated tool catalog](../../../docs/tool-cata ## Trust stance -The sandbox isolates globals but is not a security boundary. Node globals are absent or redirect to Cordis services such as `ctx.fs`, `ctx.web`, and `ctx.bash`, and writes to `globalThis` stay local, but host-realm helpers make escape possible. Mounted plugins receive a façade without framework internals, yet its allowed services affect the live runtime. Dynamic tool schemas and annotations cross the realm through iterative JSON cloning and schema normalization, so valid deep declarations are memory-bounded rather than call-stack-bounded. Treat this toolset like bash access; see the [design and trust stance](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). +The sandbox isolates globals but is not a security boundary. Node globals are absent or redirect to Cordis services such as `ctx.fs`, `ctx.web`, and `ctx.bash`, and writes to `globalThis` stay local, but host-realm helpers make escape possible. Mounted plugins receive a façade without framework internals, yet its allowed services affect the live runtime. Dynamic tool schemas and annotations cross the realm through iterative JSON cloning and schema normalization, so valid deep declarations are memory-bounded rather than call-stack-bounded; records with JSON-invisible keys and subclassed or decorated schema arrays reject before normalization. Treat this toolset like bash access; see the [design and trust stance](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). ## Config diff --git a/packages/cordis/tool-cordis/src/guard.ts b/packages/cordis/tool-cordis/src/guard.ts index aa68a1d796..646cf80a8e 100644 --- a/packages/cordis/tool-cordis/src/guard.ts +++ b/packages/cordis/tool-cordis/src/guard.ts @@ -62,6 +62,24 @@ function hasPlainArrayPrototype(value: unknown[]): boolean { } /* jscpd:ignore-end */ +/** Whether a schema list is a dense intrinsic array with no JSON-invisible decorations. */ +function isDensePlainArray(value: unknown): value is unknown[] { + if (!Array.isArray(value) || !hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) { + return false + } + for (let index = 0; index < value.length; index++) { + if (!Object.hasOwn(value, index)) return false + } + return true +} + +/** Reject schema records whose declarations would disappear from object enumeration. */ +function assertSchemaContainerKeys(value: Record, path: string): void { + if (Reflect.ownKeys(value).some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) { + throw new Error(`harness.defineTool ${path} must contain only own enumerable string keys`) + } +} + /** Where one cloned JSON value is installed. */ type CloneDestination = | { kind: 'root' } @@ -173,6 +191,7 @@ function copyAnnotations(value: Record, output: Record, path: string, allowed: readonly string[]): void { + assertSchemaContainerKeys(value, path) for (const key of Object.keys(value)) { if (!allowed.includes(key)) throw new Error(`harness.defineTool ${path}.${key} is not supported by the unified schema DSL`) } @@ -215,11 +234,16 @@ function normalizeParameterSchemaSpec(value: unknown, path = 'parameters'): { /** Validate raw required names and return their lookup set. */ function normalizeRequiredNames(value: unknown, properties: Record, path: string): Set { if (value === undefined) return new Set() - if (!Array.isArray(value) || value.some(name => typeof name !== 'string')) { + if (!isDensePlainArray(value)) { throw new Error(`harness.defineTool ${path} must be an array of declared property names`) } - const names = new Set(value as string[]) - for (const name of names) { + const names = new Set() + for (let index = 0; index < value.length; index++) { + const name = value[index] + if (typeof name !== 'string') { + throw new Error(`harness.defineTool ${path} must be an array of declared property names`) + } + names.add(name) if (!Object.hasOwn(properties, name)) throw new Error(`harness.defineTool ${path} names undeclared property ${JSON.stringify(name)}`) } return names @@ -308,6 +332,7 @@ function normalizePropertyMap( } if (task.kind === 'map') { if (ancestors.has(task.entries)) throw new Error(`harness.defineTool ${task.path} is circular`) + assertSchemaContainerKeys(task.entries, task.path) ancestors.add(task.entries) const spec: Record = {} assignNormalizedMap(task.destination, spec) @@ -334,6 +359,7 @@ function normalizePropertyMap( if (!isPlainRecord(value)) { throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec property object`) } + assertSchemaContainerKeys(value, path) if (ancestors.has(value)) throw new Error(`harness.defineTool ${path} is circular`) ancestors.add(value) const requiredKey = task.parameterProperty && !task.raw ? ['required'] : [] @@ -351,7 +377,9 @@ function normalizePropertyMap( if (Object.hasOwn(value, 'oneOf')) { assertSchemaKeys(value, path, ['oneOf', ...requiredKey, ...ANNOTATION_KEYS]) - if (!Array.isArray(value.oneOf)) throw new Error(`harness.defineTool ${path}.oneOf must contain at least two schemas`) + if (!isDensePlainArray(value.oneOf) || value.oneOf.length < 2) { + throw new Error(`harness.defineTool ${path}.oneOf must contain at least two schemas`) + } const oneOf: Record[] = [] prop.oneOf = oneOf for (let index = value.oneOf.length - 1; index >= 0; index--) { @@ -432,9 +460,10 @@ function normalizePropertyMap( case 'null': assertSchemaKeys(value, path, ['type', 'enum', 'const', ...requiredKey, ...ANNOTATION_KEYS]) if (Object.hasOwn(value, 'enum')) { - prop.enum = Array.isArray(value.enum) - ? Array.from(value.enum, (entry, index) => cloneJson(entry, `${path}.enum[${index}]`)) - : value.enum + if (!isDensePlainArray(value.enum) || value.enum.length === 0) { + throw new Error(`harness.defineTool ${path}.enum must be a non-empty array`) + } + prop.enum = cloneJson(value.enum, `${path}.enum`) } if (Object.hasOwn(value, 'const')) prop.const = cloneJson(value.const, `${path}.const`) break diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 749ec133ee..86b0084484 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -370,7 +370,10 @@ describe('cordis_mount', () => { it.each([ ['parameters: 42', 'must be a ParameterSchemaSpec object'], + ['parameters: Object.defineProperty({}, \'text\', { value: { type: \'string\' } })', 'parameters must contain only own enumerable string keys'], ['parameters: { text: 42 }', 'parameters.text must be a ParameterSchemaSpec property object'], + ['parameters: { text: Object.defineProperty({ type: \'string\' }, \'minimum\', { value: 1 }) }', 'parameters.text must contain only own enumerable string keys'], + ['parameters: { text: { type: \'string\', [Symbol(\'hidden\')]: true } }', 'parameters.text must contain only own enumerable string keys'], ['parameters: { text: { type: \'str\' } }', 'parameters.text must declare a valid type: \'string\' | \'number\' | \'integer\' | \'boolean\' | \'null\' | \'object\' | \'array\' | \'json\' (got "str")'], ['parameters: { text: { type: \'string\', required: \'yes\' } }', 'parameters.text.required must be true when present'], ['parameters: { text: { type: \'string\', properties: {} } }', 'parameters.text.properties is not supported by the unified schema DSL'], @@ -381,6 +384,7 @@ describe('cordis_mount', () => { ['parameters: { type: \'object\', properties: {}, additionalProperties: false }', 'parameters.additionalProperties must be true or omitted'], ['parameters: { type: \'object\', properties: {}, required: \'text\' }', 'parameters.required must be an array of declared property names'], ['parameters: { type: \'object\', properties: {}, required: undefined }', 'parameters.required must be an array of declared property names'], + ['parameters: (() => { class Names extends Array { *[Symbol.iterator]() {} }; const required = new Names(); required[0] = \'text\'; required.length = 1; return { type: \'object\', properties: { text: { type: \'string\' } }, required } })()', 'parameters.required must be an array of declared property names'], ['parameters: { type: \'object\', properties: {}, required: [\'text\'] }', 'parameters.required names undeclared property "text"'], ['parameters: { type: \'object\', properties: { text: { type: \'string\', required: true } } }', 'parameters.text.required belongs to the containing raw object schema'], ['parameters: { type: \'object\', properties: { text: { oneOf: \'bad\' } } }', 'parameters.text.oneOf must contain at least two schemas'], @@ -390,7 +394,9 @@ describe('cordis_mount', () => { ['parameters: { type: \'object\', properties: { cfg: { type: \'object\', required: [\'label\'] } } }', 'parameters.cfg.required names undeclared property "label"'], ['parameters: { type: \'object\', properties: { cfg: { type: \'object\', required: undefined } } }', 'parameters.cfg.required must be an array of declared property names'], ['parameters: { value: { oneOf: \'bad\' } }', 'parameters.value.oneOf must contain at least two schemas'], + ['parameters: { value: { oneOf: new (class Branches extends Array {})({ type: \'string\' }, { type: \'null\' }) } }', 'parameters.value.oneOf must contain at least two schemas'], ['parameters: { value: { type: \'string\', enum: \'bad\' } }', 'enum must be a non-empty array'], + ['parameters: { value: { type: \'string\', enum: new (class Values extends Array {})(\'a\', \'b\') } }', 'parameters.value.enum must be a non-empty array'], ['parameters: { value: { type: \'json\', default: -0 } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: Infinity } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: () => 1 } }', 'parameters.value.default must be lossless JSON data'], From 9c5224c5277045c70eba4f500de2ae4fd8a82a4c Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 02:13:33 +0800 Subject: [PATCH 132/368] test(cordis): cover malformed schema arrays --- packages/cordis/tool-cordis/tests/mount.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 86b0084484..58a403bef6 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -384,6 +384,8 @@ describe('cordis_mount', () => { ['parameters: { type: \'object\', properties: {}, additionalProperties: false }', 'parameters.additionalProperties must be true or omitted'], ['parameters: { type: \'object\', properties: {}, required: \'text\' }', 'parameters.required must be an array of declared property names'], ['parameters: { type: \'object\', properties: {}, required: undefined }', 'parameters.required must be an array of declared property names'], + ['parameters: { type: \'object\', properties: {}, required: [42] }', 'parameters.required must be an array of declared property names'], + ['parameters: (() => { const required = []; required.length = 1; return { type: \'object\', properties: {}, required } })()', 'parameters.required must be an array of declared property names'], ['parameters: (() => { class Names extends Array { *[Symbol.iterator]() {} }; const required = new Names(); required[0] = \'text\'; required.length = 1; return { type: \'object\', properties: { text: { type: \'string\' } }, required } })()', 'parameters.required must be an array of declared property names'], ['parameters: { type: \'object\', properties: {}, required: [\'text\'] }', 'parameters.required names undeclared property "text"'], ['parameters: { type: \'object\', properties: { text: { type: \'string\', required: true } } }', 'parameters.text.required belongs to the containing raw object schema'], @@ -395,6 +397,7 @@ describe('cordis_mount', () => { ['parameters: { type: \'object\', properties: { cfg: { type: \'object\', required: undefined } } }', 'parameters.cfg.required must be an array of declared property names'], ['parameters: { value: { oneOf: \'bad\' } }', 'parameters.value.oneOf must contain at least two schemas'], ['parameters: { value: { oneOf: new (class Branches extends Array {})({ type: \'string\' }, { type: \'null\' }) } }', 'parameters.value.oneOf must contain at least two schemas'], + ['parameters: { value: { oneOf: Object.assign([{ type: \'string\' }, { type: \'null\' }], { extra: true }) } }', 'parameters.value.oneOf must contain at least two schemas'], ['parameters: { value: { type: \'string\', enum: \'bad\' } }', 'enum must be a non-empty array'], ['parameters: { value: { type: \'string\', enum: new (class Values extends Array {})(\'a\', \'b\') } }', 'parameters.value.enum must be a non-empty array'], ['parameters: { value: { type: \'json\', default: -0 } }', 'parameters.value.default must be lossless JSON data'], From 7887391afe8a0168459c69b63069a86bf7836ba1 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 02:14:06 +0800 Subject: [PATCH 133/368] fix(tasks): capture result limits before policy --- ...06-20-generic-long-running-tool-runtime.md | 2 +- docs/event-producer-consumer.md | 2 +- packages/tasks/tool-tasks/README.md | 2 +- packages/tasks/tool-tasks/src/index.ts | 18 +++++++------ .../tasks/tool-tasks/tests/tool-tasks.spec.ts | 26 +++++++++++++++++++ 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md index f30b202f7d..8aaefe1e07 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -75,7 +75,7 @@ Stream reads share one task-scoped consuming cursor because the owning model is The system prompt tells the model to retain task ids, continue independent work instead of busy-polling or duplicating a running task, collect relevant tasks before its final answer, and kill work that no longer matters. Completion injects a logged `context/message` into the exact owner's session; it becomes durable context for the next request but does not wake an idle agent. -The runtime marks a terminal task `reported` when a read or wait delivers it, when a live waiter has claimed delivery at settlement, or when the model explicitly kills it. Reported tasks do not inject redundant completion notices. Listener failures are logged independently, do not stop later listeners, and are not awaited by waiters or teardown. When a snapshot carries `outputLimitBytes`, `dsh-tool-tasks` preserves UTF-8 boundaries and reuses an existing producer truncation marker rather than duplicating it. Reads reserve status suffixes and retain the output tail; completion notices reserve the stable `background task ` prefix and `task_output` instruction before truncating variable kind, label, status, or detail, so the minimum PTY cap still identifies the task to collect. The task surface remembers the producer cap before invoking read, wait, or cancellation hooks, then applies it outside normalized dispatch and downstream post-execute policy so thrown hooks and single-text replacements cannot escape the bound; deliberately structured multi-block policy results retain policy ownership of their shape and size. +The runtime marks a terminal task `reported` when a read or wait delivers it, when a live waiter has claimed delivery at settlement, or when the model explicitly kills it. Reported tasks do not inject redundant completion notices. Listener failures are logged independently, do not stop later listeners, and are not awaited by waiters or teardown. When a snapshot carries `outputLimitBytes`, `dsh-tool-tasks` preserves UTF-8 boundaries and reuses an existing producer truncation marker rather than duplicating it. Reads reserve status suffixes and retain the output tail; completion notices reserve the stable `background task ` prefix and `task_output` instruction before truncating variable kind, label, status, or detail, so the minimum PTY cap still identifies the task to collect. The task surface resolves the caller-visible producer cap in an outer pre-execute listener before policy can deny or short-circuit dispatch, then applies it outside normalized dispatch and downstream post-execute policy so thrown hooks and single-text policy results cannot escape the bound; deliberately structured multi-block policy results retain policy ownership of their shape and size. ## Producer opt-in diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index 8582d70270..e52cc1fb59 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -44,7 +44,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `tools/change` | `emit` | [`packages/core/tools/src/index.ts:123`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | | `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:93`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`timeout-policy`](../packages/timeout/timeout-policy) | | `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:105`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-pty`](../packages/pty/tool-pty), [`tool-tasks`](../packages/tasks/tool-tasks), [`workspace-context`](../packages/context/workspace-context) | -| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:82`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | +| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:82`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-tasks`](../packages/tasks/tool-tasks) | | `tools/result` | `emit` | [`packages/core/tools/src/index.ts:113`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:81`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) | | `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:70`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) | diff --git a/packages/tasks/tool-tasks/README.md b/packages/tasks/tool-tasks/README.md index 06c3e52a62..ea3625093b 100644 --- a/packages/tasks/tool-tasks/README.md +++ b/packages/tasks/tool-tasks/README.md @@ -10,7 +10,7 @@ The model-facing control surface for `ctx.tasks`: three kind-independent tools, All three use generic ACP cards: `read` for output and list, `execute` for kill. -When a producer supplies `outputLimitBytes`, `task_output`, terminal `task_kill`, and completion notices cap the complete UTF-8 result after adding status or notice text. Reads retain the output tail and control suffix when they fit; a bounded completion notice instead reserves `background task ` and the `task_output` collection instruction before spending remaining bytes on its variable kind, label, status, and detail. An outer post-execute wrapper applies the producer's cap to normalized task-control failures and single-text policy replacements or blocks; structured multi-block policy results retain their shape. An existing producer truncation marker is reused rather than duplicated. Producers that omit the field retain the existing unbounded control-surface behavior. +When a producer supplies `outputLimitBytes`, `task_output`, terminal `task_kill`, and completion notices cap the complete UTF-8 result after adding status or notice text. Reads retain the output tail and control suffix when they fit; a bounded completion notice instead reserves `background task ` and the `task_output` collection instruction before spending remaining bytes on its variable kind, label, status, and detail. An outer pre/post-execute pair captures the caller-visible task before policy and applies its producer cap to single-text denials, around-dispatch short-circuits, normalized task-control failures, replacements, and blocks; structured multi-block policy results retain their shape. An existing producer truncation marker is reused rather than duplicated. Producers that omit the field retain the existing unbounded control-surface behavior. ## Completion notices diff --git a/packages/tasks/tool-tasks/src/index.ts b/packages/tasks/tool-tasks/src/index.ts index cdcf328fec..fb40a2eeae 100644 --- a/packages/tasks/tool-tasks/src/index.ts +++ b/packages/tasks/tool-tasks/src/index.ts @@ -95,12 +95,11 @@ function boundSingleText(content: readonly ContentBlock[], maxBytes: number): Co }] } -function rememberOutputLimit( - limits: WeakMap, - exec: ToolExecution, - snapshot: TaskSnapshot, -): void { - if (snapshot.outputLimitBytes !== undefined) limits.set(exec, snapshot.outputLimitBytes) +function visibleOutputLimit(ctx: Context, exec: ToolExecution): number | undefined { + if (exec.name !== 'task_output' && exec.name !== 'task_kill') return undefined + const taskId = (exec.arguments as { task_id?: unknown } | null | undefined)?.task_id + if (typeof taskId !== 'string' || taskId.length === 0) return undefined + return ctx.tasks.list(exec.agent).find(snapshot => snapshot.id === taskId)?.outputLimitBytes } /** Validate the non-empty constraint that SchemaSpec cannot express. */ @@ -124,6 +123,11 @@ export function apply(ctx: Context, config: Config): void { } const outputLimits = new WeakMap() + ctx.on('tools/pre-execute', (exec, next) => { + const maxBytes = visibleOutputLimit(ctx, exec) + if (maxBytes !== undefined) outputLimits.set(exec, maxBytes) + return next() + }, { prepend: true }) ctx.on('tools/post-execute', async (exec, result, next): Promise => { const decision = await next() const maxBytes = outputLimits.get(exec) @@ -179,7 +183,6 @@ export function apply(ctx: Context, config: Config): void { }, async execute(args, exec) { const id = validateTaskId(args.task_id) - rememberOutputLimit(outputLimits, exec, ctx.tasks.get(id, exec.agent)) if (args.wait === true) { const timeout = Math.min(args.timeout_ms ?? waitDefault, waitCap) await ctx.tasks.wait(id, timeout, exec.agent, exec.signal) @@ -224,7 +227,6 @@ export function apply(ctx: Context, config: Config): void { execute(args, exec) { const id = validateTaskId(args.task_id) const snapshot = ctx.tasks.get(id, exec.agent) - rememberOutputLimit(outputLimits, exec, snapshot) const result = ctx.tasks.kill(id, exec.agent, args.reason) if (result === 'already-finished') { // A snapshot describes terminal state without consuming pending output. diff --git a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts index 343c6338d4..b9e8832ea3 100644 --- a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts +++ b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts @@ -162,6 +162,32 @@ describe('task_output', () => { expect(text(result)).toContain('[result truncated]') }) + it('captures producer limits before pre- and around-execute policy', async () => { + const { ctx } = await setup() + ctx.tasks.start(producer({ outputLimitBytes: 64 }).spec) + ctx.tasks.start(producer({ outputLimitBytes: 64 }).spec) + ctx.on('tools/pre-execute', async (exec, next) => { + const taskId = (exec.arguments as { task_id?: unknown }).task_id + return taskId === 'bash-1' ? { kind: 'deny', reason: 'd'.repeat(1_000) } : next() + }) + ctx.on('tools/execute', async (exec, next) => { + const taskId = (exec.arguments as { task_id?: unknown }).task_id + return taskId === 'bash-2' + ? { content: [{ type: 'text', text: 'a'.repeat(1_000) }], isError: false } + : next() + }) + + const denied = await call(ctx, 'task_output', { task_id: 'bash-1' }) + expect(denied.isError).toBe(true) + expect(Buffer.byteLength(text(denied))).toBeLessThanOrEqual(64) + expect(text(denied)).toContain('[result truncated]') + + const shortCircuited = await call(ctx, 'task_output', { task_id: 'bash-2' }) + expect(shortCircuited.isError).toBe(false) + expect(Buffer.byteLength(text(shortCircuited))).toBeLessThanOrEqual(64) + expect(text(shortCircuited)).toContain('[result truncated]') + }) + it('wait: true blocks until settlement and reports the terminal state', async () => { const { ctx } = await setup() const p = producer({ kind: 'subagent', label: 'research' }) From db68a90f415c0b905cd1b0c37d69efa8639fcb9f Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 02:14:15 +0800 Subject: [PATCH 134/368] fix(pty): retry failed lifecycle closes --- .../2026-07-16-persistent-pty-sessions.i18n.yaml | 4 ++-- .../feature/2026-07-16-persistent-pty-sessions.md | 2 +- .../feature/2026-07-16-persistent-pty-sessions.zh.md | 2 +- packages/pty/pty/README.md | 2 +- packages/pty/pty/src/index.ts | 10 ++++++++-- packages/pty/pty/tests/service.spec.ts | 9 ++++++++- 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index f772b6d5e6..c4fa994098 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml @@ -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 -2026-07-16-persistent-pty-sessions.md: 8a9ec669a064924ecdb9693fff5c4cafea59d90c -2026-07-16-persistent-pty-sessions.zh.md: 157bee408d041b5c373dd2a4d41f82de90a67e0e +2026-07-16-persistent-pty-sessions.md: fdab27d73258cdcc7382e52fad09f749d26ae890 +2026-07-16-persistent-pty-sessions.zh.md: a0cac7b835c2b5c20d6569e87d49b7fdc5b4dac2 diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index 8a9ec669a0..fdab27d732 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -92,7 +92,7 @@ Background sends use the existing task completion notice and `task_output` resul The top-level `node-pty` child is the ownership anchor. On close, the backend stops callbacks, snapshots its transitive descendants by parent PID in children-first order, sends `SIGTERM`, waits, rescans for children forked during shutdown, sends `SIGKILL` to the remaining descendant tree, and verifies that every non-zombie descendant left the process table while the shell is still alive. A matching Linux zombie has no executable work and therefore counts as quiescent, allowing shell shutdown to reap or reparent it. Only then does the backend stop the shell with its own TERM/grace/KILL sequence. Every captured PID includes process-start identity so reuse cannot redirect escalation. -Teardown reports root exit and survivor cleanup independently. It does not claim success merely because the shell exited; disposal resolves only after no captured non-quiescent tree member remains or returns a cleanup failure naming the survivors. A failed close is not cached forever: the registry and local session retain their closing fence but allow a later close to retry after the external survivor condition changes. Service disposal still clears its backend, reservation, and owner-detacher registries when a close fails. It never broadens ownership to every member of the root PID's POSIX session. +Teardown reports root exit and survivor cleanup independently. It does not claim success merely because the shell exited; disposal resolves only after no captured non-quiescent tree member remains or returns a cleanup failure naming the survivors. A failed close is not cached forever: the registry and local session each clear the fence only when it still names that failed attempt, so a later explicit or lifecycle close retries after the external survivor condition changes without disturbing a newer concurrent attempt. Service disposal still clears its backend, reservation, and owner-detacher registries when a close fails. It never broadens ownership to every member of the root PID's POSIX session. ### Composition and rollout diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index 157bee408d..a0cac7b835 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -92,7 +92,7 @@ Tier 2 在持续 `idleSilenceMs` 没有输出后返回 `inferred_idle`,因此 顶层 `node-pty` 子进程是所有权锚点。关闭时,后端先停止 callback,再按父 PID 以子进程优先顺序捕获其传递子进程、发送 `SIGTERM` 并等待,然后重新扫描关停期间 fork 出的子进程,向剩余子孙进程树发送 `SIGKILL`,并在 shell 仍存活时验证每个非僵尸子孙进程都已离开进程表。身份匹配的 Linux 僵尸进程已无可执行工作,因此视为静止;shell 关闭时会回收它或将其重新挂接给负责回收的父进程。完成这些步骤后,后端才用 shell 自身的 TERM、宽限等待、KILL 序列停止 shell。每个捕获的 PID 都包含进程启动身份,避免 PID 复用把升级信号发给无关进程。 -teardown 独立报告根进程退出与存活进程清理。它不会只因 shell 退出就声称成功;dispose 只有在已捕获的进程树中不再存在非静止成员后才完成,否则返回清理失败并列出存活者。失败的 close 不会永久缓存:注册表与本地会话会保留关闭围栏,但在外部存活进程状态改变后允许后续 close 重试。即使某个 close 失败,服务 dispose 仍会清空其后端、预留与 owner detacher 注册表。所有权绝不会扩大到根 PID 所属 POSIX 会话的全部成员。 +teardown 独立报告根进程退出与存活进程清理。它不会只因 shell 退出就声称成功;dispose 只有在已捕获的进程树中不再存在非静止成员后才完成,否则返回清理失败并列出存活者。失败的 close 不会永久缓存:注册表与本地会话各自仅在关闭围栏仍指向该次失败尝试时才将其清除,因此外部存活进程状态改变后,后续的显式 close 或生命周期 close 会重试,且不会干扰较新的并发尝试。即使某个 close 失败,服务 dispose 仍会清空其后端、预留与 owner detacher 注册表。所有权绝不会扩大到根 PID 所属 POSIX 会话的全部成员。 ### 组合与推行 diff --git a/packages/pty/pty/README.md b/packages/pty/pty/README.md index 4213a3458f..798991d5fd 100644 --- a/packages/pty/pty/README.md +++ b/packages/pty/pty/README.md @@ -13,7 +13,7 @@ Owner-scoped persistent PTY seam. `PtyService` registers as `ctx.pty`, mints opa - A successful spawn publishes one `PtySessionId`. The optional `name` is owner-local display metadata, never authority. - One session accepts at most one live send operation. Reads and signals may observe it; another send fails until the operation settles. - `PtySendResult.waitReason` and `sessionStatus` are independent. `session_exit` describes the top-level PTY process, not an arbitrary foreground command. -- `kill()` and disposal resolve only after the backend's captured process tree is quiescent. A cleanup failure rejects instead of claiming success and leaves the close retriable. +- `kill()` and disposal resolve only after the backend's captured process tree is quiescent. A cleanup failure rejects instead of claiming success and clears the matching backend and registry fences so a later close can retry without disturbing a newer attempt. The seam contains no `node-pty`, sandbox, tool-schema, prompt, task, or terminal-rendering policy. Implementations own terminal mechanics; consumers own model presentation and optional background-task registration. diff --git a/packages/pty/pty/src/index.ts b/packages/pty/pty/src/index.ts index 47c2a2662d..c7896d5113 100644 --- a/packages/pty/pty/src/index.ts +++ b/packages/pty/pty/src/index.ts @@ -457,8 +457,14 @@ export class PtyService extends Service { const results = await Promise.allSettled(records.map(async (record) => { const closing = record.closing ?? record.session.close(reason) record.closing = closing - await closing - this.sessions.delete(record.id) + try { + await closing + this.sessions.delete(record.id) + } catch (error: unknown) { + // A concurrent retry may already own a newer fence; never clear it. + if (record.closing === closing) record.closing = undefined + throw error + } })) const failures = results .filter((result): result is PromiseRejectedResult => result.status === 'rejected') diff --git a/packages/pty/pty/tests/service.spec.ts b/packages/pty/pty/tests/service.spec.ts index caa255ac5b..bca131011d 100644 --- a/packages/pty/pty/tests/service.spec.ts +++ b/packages/pty/pty/tests/service.spec.ts @@ -540,8 +540,15 @@ describe('PtyService ownership and lifecycle', () => { sessions: Map closeRecords(records: unknown[], reason: string): Promise } - await expect(internal.closeRecords([...internal.sessions.values()], 'test failure')).rejects.toThrow('failed to close 1 PTY session') + const records = [...internal.sessions.values()] + const firstFailure = expect(internal.closeRecords(records, 'test failure')).rejects.toThrow('failed to close 1 PTY session') + const joinedFailure = expect(internal.closeRecords(records, 'joined failure')).rejects.toThrow('failed to close 1 PTY session') + await firstFailure + await joinedFailure b.sessions[0]!.rejectClose = false + await expect(internal.closeRecords([...internal.sessions.values()], 'retry')).resolves.toBeUndefined() + expect(b.sessions[0]!.closed).toEqual(['test failure', 'retry']) + expect(internal.sessions.size).toBe(0) await disposePtyService(ctx) await expect(service.spawn(owner, { type: 'stub' })).rejects.toMatchObject({ code: 'SERVICE_DISPOSING' }) }) From 30bffb5642ea4bc2c56ae5a2afb3bb141f4d3819 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 02:20:12 +0800 Subject: [PATCH 135/368] test(cordis): cover balanced sparse schema lists --- packages/cordis/tool-cordis/tests/mount.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 58a403bef6..20f987f0ec 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -386,6 +386,7 @@ describe('cordis_mount', () => { ['parameters: { type: \'object\', properties: {}, required: undefined }', 'parameters.required must be an array of declared property names'], ['parameters: { type: \'object\', properties: {}, required: [42] }', 'parameters.required must be an array of declared property names'], ['parameters: (() => { const required = []; required.length = 1; return { type: \'object\', properties: {}, required } })()', 'parameters.required must be an array of declared property names'], + ['parameters: (() => { const required = []; required.length = 1; required.extra = true; return { type: \'object\', properties: {}, required } })()', 'parameters.required must be an array of declared property names'], ['parameters: (() => { class Names extends Array { *[Symbol.iterator]() {} }; const required = new Names(); required[0] = \'text\'; required.length = 1; return { type: \'object\', properties: { text: { type: \'string\' } }, required } })()', 'parameters.required must be an array of declared property names'], ['parameters: { type: \'object\', properties: {}, required: [\'text\'] }', 'parameters.required names undeclared property "text"'], ['parameters: { type: \'object\', properties: { text: { type: \'string\', required: true } } }', 'parameters.text.required belongs to the containing raw object schema'], From 2821826e2c1862f30347005150dd8e95ced57844 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 02:53:43 +0800 Subject: [PATCH 136/368] fix(pty): close final review gaps --- ...06-20-generic-long-running-tool-runtime.md | 2 +- .../2026-07-12-agent-scope-runtime-design.md | 2 +- ...19-cooperative-tool-cancellation.i18n.yaml | 4 +- ...026-07-19-cooperative-tool-cancellation.md | 2 +- ...-07-19-cooperative-tool-cancellation.zh.md | 2 +- .../feature/2026-06-15-code-mode.md | 2 +- .../feature/2026-06-30-interception-seams.md | 9 ++-- ...26-07-16-persistent-pty-sessions.i18n.yaml | 4 +- .../2026-07-16-persistent-pty-sessions.md | 4 +- .../2026-07-16-persistent-pty-sessions.zh.md | 4 +- docs/config-catalog.md | 4 +- docs/cordis-catalog/services.md | 13 ++--- docs/core-data-structures/core.md | 2 +- docs/core-data-structures/tools.md | 18 +++++-- docs/event-producer-consumer.md | 2 +- docs/tool-execution-pipeline.md | 15 ++++-- .../cordis-inspect-jsdoc/session.jsonl | 2 +- .../stdout.expected.jsonl | 2 +- .../cordis/tool-cordis/src/api-catalog.ts | 6 +-- .../cordis/tool-cordis/tests/inspect.spec.ts | 2 +- packages/core/agent-loop/README.md | 2 +- packages/core/tools/README.md | 10 ++-- packages/core/tools/src/index.ts | 49 +++++++++++++++---- packages/core/tools/src/schema.ts | 26 +++++++++- packages/core/tools/tests/tools.spec.ts | 39 +++++++++++++-- packages/pty/pty/README.md | 2 +- packages/pty/pty/src/index.ts | 2 +- packages/pty/pty/tests/service.spec.ts | 23 +++++++++ packages/pty/tool-pty/README.md | 4 +- packages/pty/tool-pty/src/index.ts | 32 +++++------- packages/pty/tool-pty/tests/tools.spec.ts | 26 ++++++++-- packages/tasks/tool-tasks/README.md | 2 +- packages/tasks/tool-tasks/src/index.ts | 19 +++---- .../tasks/tool-tasks/tests/tool-tasks.spec.ts | 33 ++++++++++--- scripts/gen-doc-graphs.ts | 15 ++++-- 35 files changed, 271 insertions(+), 114 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md index 8aaefe1e07..83b5381818 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -75,7 +75,7 @@ Stream reads share one task-scoped consuming cursor because the owning model is The system prompt tells the model to retain task ids, continue independent work instead of busy-polling or duplicating a running task, collect relevant tasks before its final answer, and kill work that no longer matters. Completion injects a logged `context/message` into the exact owner's session; it becomes durable context for the next request but does not wake an idle agent. -The runtime marks a terminal task `reported` when a read or wait delivers it, when a live waiter has claimed delivery at settlement, or when the model explicitly kills it. Reported tasks do not inject redundant completion notices. Listener failures are logged independently, do not stop later listeners, and are not awaited by waiters or teardown. When a snapshot carries `outputLimitBytes`, `dsh-tool-tasks` preserves UTF-8 boundaries and reuses an existing producer truncation marker rather than duplicating it. Reads reserve status suffixes and retain the output tail; completion notices reserve the stable `background task ` prefix and `task_output` instruction before truncating variable kind, label, status, or detail, so the minimum PTY cap still identifies the task to collect. The task surface resolves the caller-visible producer cap in an outer pre-execute listener before policy can deny or short-circuit dispatch, then applies it outside normalized dispatch and downstream post-execute policy so thrown hooks and single-text policy results cannot escape the bound; deliberately structured multi-block policy results retain policy ownership of their shape and size. +The runtime marks a terminal task `reported` when a read or wait delivers it, when a live waiter has claimed delivery at settlement, or when the model explicitly kills it. Reported tasks do not inject redundant completion notices. Listener failures are logged independently, do not stop later listeners, and are not awaited by waiters or teardown. When a snapshot carries `outputLimitBytes`, `dsh-tool-tasks` preserves UTF-8 boundaries and reuses an existing producer truncation marker rather than duplicating it. Reads reserve status suffixes and retain the output tail; completion notices reserve the stable `background task ` prefix and `task_output` instruction before truncating variable kind, label, status, or detail, so the minimum PTY cap still identifies the task to collect. The task surface resolves the caller-visible producer cap in a prepended pre-execute listener before policy can deny or short-circuit dispatch, then applies it through the task definitions' last-mile `finalizeContent` callback so normalized tool errors, outer pipeline failures, and single-text policy results cannot escape the bound; deliberately structured multi-block policy results retain policy ownership of their shape and size. ## Producer opt-in diff --git a/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md b/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md index e0de18e90a..82adea706a 100644 --- a/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md +++ b/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md @@ -218,7 +218,7 @@ A fresh registry-assigned Symbol provides collision-free execution identity with Arguments are materialized once where model/tool JSON enters the pipeline. Pre-, around-, and post-execute listeners operate on the typed execution and decisions. Call ID correlation, approval, monotonic guards, and Code Mode nesting remain explicit relational checks. -After the last post-execute listener, the registry materializes and freezes the accepted final result once. Every synchronous `tools/result` observer receives that exact committed object, and observer failures are contained individually. An outer pipeline failure is normalized into a committed error result, so observers can discard staged work against the same authoritative boundary. +After post-execute or outer pipeline normalization, the registry invokes the call's snapshotted optional `ToolDefinition.finalizeContent` callback, then materializes and freezes the accepted final result once. The callback may replace only content, so structured error identity, contexts, and metadata remain registry-owned even when a tool enforces a last-mile result bound. Every synchronous `tools/result` observer receives that exact committed object, and observer failures are contained individually. An outer pipeline failure is normalized before final content, so observers can discard staged work against the same authoritative boundary. ### The assembly waterfall owns the final model-visible composition diff --git a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.i18n.yaml index b27a40cc7f..5d517611af 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.i18n.yaml @@ -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 -2026-07-19-cooperative-tool-cancellation.md: 559012f10d41963698cc932727125de1b9ccfef7 -2026-07-19-cooperative-tool-cancellation.zh.md: 6af8e57349bba026ab22f257014c084c5c3c3f54 +2026-07-19-cooperative-tool-cancellation.md: e86c087de53fe742436bc01571394657a0a5c9ac +2026-07-19-cooperative-tool-cancellation.zh.md: 91b91b3894dbdc56d57f4819ff4c567305ecfc9d diff --git a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md index 559012f10d..e86c087de5 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md +++ b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md @@ -36,7 +36,7 @@ An around-dispatch wrapper may replace `exec.signal` for its delegated lifetime ### Pre-aborted entry short-circuits after materialization -The registry first creates the call token and losslessly snapshots and freezes the arguments. A materialization failure wins even when the caller signal is already aborted. After successful materialization, a pre-aborted signal skips `tools/pre-execute`, approval, `tools/execute`, `tools/post-execute`, and the tool body, then publishes exactly one frozen authoritative `tools/result` with `ABORTED_BEFORE_DISPATCH`. +The registry first creates the call token, snapshots the visible definition's optional final-content callback, and losslessly snapshots and freezes the arguments. A materialization failure wins even when the caller signal is already aborted. After successful materialization, a pre-aborted signal skips `tools/pre-execute`, approval, `tools/execute`, `tools/post-execute`, and the tool body, then passes `ABORTED_BEFORE_DISPATCH` through that content-only callback before publishing exactly one frozen authoritative `tools/result`. ### Started work still reaches quiescence diff --git a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.zh.md b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.zh.md index 6af8e57349..91b91b3894 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.zh.md @@ -36,7 +36,7 @@ Status: implemented ### 进入时已中止会在物化后短路 -注册表先创建调用 token,并对参数进行无损快照和冻结。即使调用方信号已经中止,参数物化失败仍优先返回。物化成功后,进入时已中止的信号会跳过 `tools/pre-execute`、审批、`tools/execute`、`tools/post-execute` 和工具主体,然后发布且只发布一次冻结的权威 `tools/result`,其代码为 `ABORTED_BEFORE_DISPATCH`。 +注册表先创建调用 token,对可见工具定义的可选 `finalizeContent` callback 做快照,并对参数进行无损快照和冻结。即使调用方信号已经中止,参数物化失败仍优先返回。物化成功后,进入时已中止的信号会跳过 `tools/pre-execute`、审批、`tools/execute`、`tools/post-execute` 和工具主体,然后先由该仅处理内容的 callback 处理 `ABORTED_BEFORE_DISPATCH`,再发布且只发布一次冻结的权威 `tools/result`。 ### 已启动工作仍必须完全停稳 diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.md index 329eaf2d0a..42af62e928 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.md @@ -36,7 +36,7 @@ Three decisions, each elaborated in its own section below: ### The run_code tool and the dispatch bridge -Under `'code'` and `'both'` the registry owns `run_code` as a reserved presentation transport with one required parameter, `{ code: string }`. It is represented by a normal `ToolDefinition` for dispatch but stays outside the filterable capability layers, so restrictions cannot accidentally remove Code Mode's only entry point. Calls traverse the complete tool pipeline — `tools/pre-execute` → monotonic guards → `tools/execute` around dispatch → `tools/post-execute` → immutable `tools/result` notification — exactly like native calls; a permission plugin can inspect the program text before it runs, and final-result observers see the normalized outer outcome. Its `execute(args, exec)`: +Under `'code'` and `'both'` the registry owns `run_code` as a reserved presentation transport with one required parameter, `{ code: string }`. It is represented by a normal `ToolDefinition` for dispatch but stays outside the filterable capability layers, so restrictions cannot accidentally remove Code Mode's only entry point. Calls traverse the complete tool pipeline — `tools/pre-execute` → monotonic guards → `tools/execute` around dispatch → `tools/post-execute` → optional definition-owned `finalizeContent` → immutable `tools/result` notification — exactly like native calls; a permission plugin can inspect the program text before it runs, and final-result observers see the normalized outer outcome. Its `execute(args, exec)`: 1. **Build bindings.** One run-scoped signal follows outer cancellation and is aborted whenever the run settles. Each visible tool binding JSON-normalizes its arguments—rejecting lossy values before dispatch—waits on the serialization queue, executes with a deterministic call id and the outer token as `parent`, defers returned contexts through the outer execution, and logs `tool/code-dispatch`. Successful text becomes a string and non-text blocks become placeholders; tool errors reject the binding promise. Every sub-call retains its own immutable execution identity and traverses the full tool pipeline. 2. **Runs the program**: `ctx.codeRuntime.run({ program: args.code, bindings: [{ global: 'tools', functions }], signal: runController.signal })`. The runtime receives the run-scoped signal, not only the caller's outer signal, so any way the outer run settles also aborts work inside the runtime. diff --git a/.agents/notes/implemented/feature/2026-06-30-interception-seams.md b/.agents/notes/implemented/feature/2026-06-30-interception-seams.md index 08edfae386..0b2f7eafc8 100644 --- a/.agents/notes/implemented/feature/2026-06-30-interception-seams.md +++ b/.agents/notes/implemented/feature/2026-06-30-interception-seams.md @@ -20,15 +20,16 @@ The canonical surface separates transformable policy, around-dispatch control, a ### The tool pipeline gives each phase one kind of authority -Every call follows `tools/pre-execute` → guards → `tools/execute` → dispatch → `tools/post-execute` → `tools/result`. The registry snapshots caller input, materializes and freezes arguments, and assigns an opaque token. Nested calls carry only the parent token. Identity remains immutable; only `signal` may change around dispatch. The log, UI, and tool body therefore agree on what ran. +Every call follows `tools/pre-execute` → guards → `tools/execute` → dispatch → `tools/post-execute` → definition-owned `finalizeContent` → `tools/result`. The registry snapshots caller input, materializes and freezes arguments, assigns an opaque token, and snapshots the visible definition's final-content callback before policy begins. Nested calls carry only the parent token. Identity remains immutable; only `signal` may change around dispatch. The log, UI, and tool body therefore agree on what ran. -- **`tools/pre-execute`** is the extensible waterfall gate. Its `PreToolDecision` allows, denies, or asks. Deny skips `tools/execute` and core dispatch. Ask resolves through the optional approval seam: only `allowed-once` continues through guards and dispatch; rejection, cancellation, an unavailable channel, a missing approval service, or an agent-less call becomes a normalized denial. Every outcome still reaches post-policy and final observers. +- **`tools/pre-execute`** is the extensible waterfall gate. Its `PreToolDecision` allows, denies, or asks. Deny skips `tools/execute` and core dispatch. Ask resolves through the optional approval seam: only `allowed-once` continues through guards and dispatch; rejection, cancellation, an unavailable channel, a missing approval service, or an agent-less call becomes a normalized denial. Every resolved decision still reaches post-policy; a throwing listener becomes a final normalized failure. - **`ctx.tools.guard()`** installs synchronous scope-aware policy after the whole pre-execute waterfall. A guard may deny or abstain, never force-allow, so listener ordering cannot resurrect an operation that a final invariant forbids. - **`tools/execute`** is the around-dispatch waterfall for timeout, retry, and metrics plugins. A wrapper delegates to core dispatch with `next()`, may replace and restore the required `exec.signal` before doing so but cannot remove it, and receives the already-normalized result of a thrown or unknown tool; returning its own valid result short-circuits dispatch. -- **`tools/post-execute`** is the inspect/transform waterfall. Its `PostToolDecision` accepts, blocks with feedback, optionally replaces content, or attaches `additionalContexts`. The returned decision is the supported transform channel; after the waterfall, the registry materializes the complete outcome once before final observation. +- **`tools/post-execute`** is the inspect/transform waterfall. Its `PostToolDecision` accepts, blocks with feedback, optionally replaces content, or attaches `additionalContexts`. The returned decision is the supported cross-tool transform channel. +- **`ToolDefinition.finalizeContent`** is an optional synchronous, total, content-only boundary snapshotted with the visible definition at call creation. It runs exactly once after the registry has normalized the final outcome, including pre-, around-, or post-listener failures that bypass later waterfalls. It may replace `content` or preserve it with `undefined`, but cannot rewrite `isError`, structured error identity, contexts, or presentation metadata. This is where a tool enforces its own last-mile content invariant without converting policy failures into weaker block decisions. - **`tools/result`** is the synchronous contained notification after every transform, lossless-JSON materialization, and the outer error boundary. It receives the same frozen execution identity and an immutable snapshot of the authoritative result; observer failures are contained per listener and cannot change or reject `ToolRegistry.execute()`'s returned outcome. -Core dispatch and the tool body sit inside normalization boundaries, so tool, listener, malformed-result, non-JSON result, and identity-shape failures resolve as JSON-safe `isError` results rather than escaping the turn. A post-execute listener can therefore inspect a thrown tool, and a final observer sees exactly what the caller receives and the session log can persist. +Core dispatch and the tool body sit inside normalization boundaries, so tool, listener, malformed-result, non-JSON result, and identity-shape failures resolve as JSON-safe `isError` results rather than escaping the turn. A post-execute listener can therefore inspect a thrown tool; definition-owned final content invariants also cover outer pipeline failures; and a final observer sees exactly what the caller receives and the session log can persist. **`TurnEndReason.rejected`** (`dsh-session`): a zero-step turn whose claimed prompt was blocked by `prompt-submit`. diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index c4fa994098..be66b14fbf 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml @@ -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 -2026-07-16-persistent-pty-sessions.md: fdab27d73258cdcc7382e52fad09f749d26ae890 -2026-07-16-persistent-pty-sessions.zh.md: a0cac7b835c2b5c20d6569e87d49b7fdc5b4dac2 +2026-07-16-persistent-pty-sessions.md: b33993d36753d3195ec52d3b38dda62746a47bf3 +2026-07-16-persistent-pty-sessions.zh.md: 6ed330d75824a4e6fca9de0d82db61a7c6543322 diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index fdab27d732..b33993d367 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -34,7 +34,7 @@ Idle detection is backend behavior, not a second public seam. A remote or contai There are no plugin-load auto-start sessions. `terminal_open` creates a session only during an agent tool call, when ownership and the owning event-sourced session are known. A future declarative startup feature must compose through unpublished agent setup rather than create shared global terminals. -Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Unpublished backend setup is a tracked lifecycle operation: owner or service disposal aborts its service-owned signal, waits for backend settlement and rollback, and only then returns. Caller cancellation retains its exact `AbortSignal.reason` even when the backend rejects in response; a service rollback close failure rejects both the spawn and the disposing lifecycle, while `PtyBackendCleanupError` lets a backend preserve its own failed startup cleanup for the disposing lifecycle without replacing that caller reason. When caller cancellation settles before disposal, the cleanup failure remains tracked owner activity until later owner or service disposal consumes and reports it, so sandbox-mode policy cannot mistake failed cleanup for quiescence. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. +Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Unpublished backend setup is a tracked lifecycle operation: owner or service disposal aborts its service-owned signal, waits for backend settlement and rollback, and only then returns. Caller cancellation retains its exact `AbortSignal.reason` even when the backend rejects or returns a session whose rollback close fails; that cleanup failure remains tracked for later owner or service disposal instead of replacing the caller reason. A lifecycle-triggered rollback close failure rejects both the spawn and the disposing lifecycle, while `PtyBackendCleanupError` lets a backend preserve its own failed startup cleanup for the disposing lifecycle without replacing a caller cancellation. When caller cancellation settles before disposal, the cleanup failure remains tracked owner activity until later owner or service disposal consumes and reports it, so sandbox-mode policy cannot mistake failed cleanup for quiescence. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. ### Security and process boundary @@ -62,7 +62,7 @@ The ACP render contract is exact and location-free. `terminal_send` uses termina `terminal_send({ sessionId, text, submit?, run_in_background? })` treats `text` as UTF-8 bytes and resolves `submit` to `true` in the tool implementation. When `submit` is true it writes the platform Enter sequence after the text; when false it writes only the text, allowing control characters and REPL fragments without hidden content heuristics. `enableRunInBackground` defaults to true; false removes `run_in_background` from the schema and rejects the same undeclared argument if a caller forces it through execution. -Foreground sends return a bounded rendered delta and two independent facts: `waitReason` (`stdin_read | inferred_idle | timeout | session_exit`) and `sessionStatus` (`running` or `exited` with exit code or signal). `session_exit` refers to the PTY's top-level shell process, not an arbitrary foreground command whose status the shell consumes. A timeout never implies process exit. `dsh-tool-pty.maxResultBytes` defaults to 262144, rejects values below 64 so creation acknowledgements retain registry-issued ids, and caps each single-text UTF-8 result after normalized errors, wait, session, pagination, truncation, generic task-status wrappers, pre-execute denials, and post-execute replacements or blocks; its outer post-execute wrapper leaves deliberately structured multi-block policy content unchanged. The renderer reserves suffix space and preserves code-point boundaries instead of treating the backend payload cap as the final model bound. +Foreground sends return a bounded rendered delta and two independent facts: `waitReason` (`stdin_read | inferred_idle | timeout | session_exit`) and `sessionStatus` (`running` or `exited` with exit code or signal). `session_exit` refers to the PTY's top-level shell process, not an arbitrary foreground command whose status the shell consumes. A timeout never implies process exit. `dsh-tool-pty.maxResultBytes` defaults to 262144, rejects values below 64 so creation acknowledgements retain registry-issued ids, and caps each single-text UTF-8 result after normalized tool or pipeline errors, wait, session, pagination, truncation, generic task-status wrappers, policy denials or short-circuits, and post-execute replacements or blocks; the terminal definitions' last-mile `finalizeContent` callback leaves deliberately structured multi-block policy content unchanged. The renderer reserves suffix space and preserves code-point boundaries instead of treating the backend payload cap as the final model bound. With `run_in_background: true`, `dsh-tool-pty` registers the in-flight send on `ctx.tasks` and returns immediately with `taskId`. The producer places `maxResultBytes` on the task snapshot so `task_output`, terminal kill status, and completion notices enforce the same complete-result cap after generic metadata. `task_output(wait: true)` waits, reads incremental output, and records the final result; `task_kill` resolves the current foreground PGID and delivers a real `SIGINT`, including when the application has disabled terminal `ISIG`, and escalates only through the PTY backend's owned teardown path. If the task surface is absent, background mode fails before writing input. No PTY-specific `sleep` tool or general wake-up seam is added. diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index a0cac7b835..6ed330d758 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -34,7 +34,7 @@ idle 检测属于后端行为,不是第二条公共 seam。远程或容器后 实现不提供插件加载期 auto-start 会话。`terminal_open` 只在 agent 工具调用期间创建会话,此时所有权和所属的事件溯源会话都已确定。未来的声明式启动功能必须通过尚未发布的 agent setup 组合,而不能创建全局共享终端。 -agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。未发布的后端 setup 同样是受追踪的生命周期操作:owner 或服务 dispose 会中止服务自有的 signal,等待后端结算与回滚完成后才返回。即使后端响应取消而 reject,调用方取消仍原样保留其 `AbortSignal.reason`;服务侧回滚 close 失败会使 spawn 与正在执行的 lifecycle dispose 都 reject,而 `PtyBackendCleanupError` 让后端在不替换该调用方原因的前提下,为正在执行的 dispose 保留自身的启动清理失败。若调用方取消先于 dispose 完成结算,该清理失败会继续作为受追踪的 owner activity 保留,直到后续 owner 或服务 dispose 消费并报告它,因此沙箱模式策略不会把清理失败误判为静默。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 +agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。未发布的后端 setup 同样是受追踪的生命周期操作:owner 或服务 dispose 会中止服务自有的 signal,等待后端结算与回滚完成后才返回。即使后端 reject,或返回的会话在回滚 close 时失败,调用方取消仍会原样保留其 `AbortSignal.reason`;该清理失败不会替换调用方原因,而会继续受追踪,留待后续 owner 或服务 dispose 处理。由 lifecycle dispose 触发的回滚 close 失败会使 spawn 与该 lifecycle dispose 都 reject,而 `PtyBackendCleanupError` 让后端在不替换调用方取消的前提下,为该 lifecycle dispose 保留自身的启动清理失败。若调用方取消先于 dispose 完成结算,该清理失败会继续作为受追踪的 owner activity 保留,直到后续 owner 或服务 dispose 消费并报告它,因此沙箱模式策略不会把清理失败误判为静默。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 ### 安全与进程边界 @@ -62,7 +62,7 @@ ACP 渲染契约精确且不携带位置信息。`terminal_send` 只为前台发 `terminal_send({ sessionId, text, submit?, run_in_background? })` 将 `text` 视为 UTF-8 字节,并由工具实现在解析阶段把 `submit` 默认成 `true`。`submit` 为 true 时先写入文本,再写入平台 Enter 序列;为 false 时只写文本,使控制字符和 REPL 片段无需隐藏的内容启发式即可发送。`enableRunInBackground` 默认为 true;设为 false 时,schema 中会移除 `run_in_background`,调用方即使强行把这个未声明参数传入执行流程,也会被拒绝。 -前台发送返回有界的渲染增量和两个独立事实:`waitReason`(`stdin_read | inferred_idle | timeout | session_exit`)与 `sessionStatus`(`running`,或携带退出码或信号的 `exited`)。`session_exit` 指 PTY 顶层 shell 进程退出,不指由 shell 消费状态的任意前台命令。timeout 从不意味着进程已经退出。`dsh-tool-pty.maxResultBytes` 默认为 262144;低于 64 的值会被拒绝,以确保创建确认保留 registry 签发的 id;每个单文本 UTF-8 结果在加入规范化错误、等待与会话状态、分页与截断元数据、通用 task 状态包装、pre-execute 拒绝以及 post-execute 替换或阻断后,仍受该值限制;位于外层的 post-execute wrapper 会原样保留策略刻意返回的结构化多 block 内容。渲染器会为后缀预留空间并保持代码点边界,而不会把后端载荷上限当作面向模型结果的最终上限。 +前台发送返回有界的渲染增量和两个独立事实:`waitReason`(`stdin_read | inferred_idle | timeout | session_exit`)与 `sessionStatus`(`running`,或携带退出码或信号的 `exited`)。`session_exit` 指 PTY 顶层 shell 进程退出,不指由 shell 消费状态的任意前台命令。timeout 从不意味着进程已经退出。`dsh-tool-pty.maxResultBytes` 默认为 262144;低于 64 的值会被拒绝,以确保创建确认保留 registry 签发的 id;每个单文本 UTF-8 结果在加入规范化的工具或流水线错误、等待、会话、分页、截断、通用 task 状态包装、策略拒绝或短路以及 post-execute 替换或阻断后,仍受该值限制;终端定义自有的末端 `finalizeContent` callback 会原样保留策略刻意返回的结构化多 block 内容。渲染器会为后缀预留空间并保持代码点边界,而不会把后端载荷上限当作面向模型结果的最终上限。 当 `run_in_background: true` 时,`dsh-tool-pty` 在 `ctx.tasks` 上注册进行中的发送,并立即返回 `taskId`。生产方把 `maxResultBytes` 写入 task 快照,使 `task_output`、kill 返回的终态状态和完成通知在加上通用元数据后,仍对完整结果执行同一上限。`task_output(wait: true)` 负责等待、读取增量输出并记录最终结果;`task_kill` 会解析当前前台 PGID 并发送真正的 `SIGINT`,即使应用已禁用终端 `ISIG` 也同样如此,且后续升级仍只通过 PTY 后端拥有的 teardown 路径进行。若 task 对外接口不存在,后台模式必须在写入输入前失败。设计不新增 PTY 专用的 `sleep` 工具或通用唤醒 seam。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 679b3e4484..5e86078a3b 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -1383,7 +1383,7 @@ export interface Config { } ``` -Source: [`packages/pty/tool-pty/src/index.ts:44`](../packages/pty/tool-pty/src/index.ts) +Source: [`packages/pty/tool-pty/src/index.ts:35`](../packages/pty/tool-pty/src/index.ts) ## `@deepseek-ai/dsh-tool-ralph` @@ -1549,7 +1549,7 @@ export interface Config { export type ToolPresentationMode = 'native' | 'code' | 'both' ``` -Source: [`packages/core/tools/src/index.ts:419`](../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:431`](../packages/core/tools/src/index.ts) ## `@deepseek-ai/dsh-tui` diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 78687b70b9..549f3b4ab2 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -1547,7 +1547,7 @@ Tool registry and execution pipeline. Scoped registrations shadow globals; one v /** * Register globally or in the calling agent scope. Scoped tools shadow * globals; duplicates within one layer and the reserved `run_code` name fail. - * @param definition - the tool schema, execution, and optional presentation functions. + * @param definition - tool schema, execution, and optional finalization/presentation callbacks. * @returns the exact disposer that unregisters the tool. */ register(definition: ToolDefinition): () => void @@ -1602,10 +1602,11 @@ schemas(scope?: ScopeKey): ToolSchema[] executionMode(exec: ToolExecutionInput): ToolExecutionMode /** - * Execute through pre-policy, guards, around-dispatch, post-policy, and final - * notification. Tool and listener failures resolve as materialized error - * results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is - * the same lossless, frozen snapshot final observers receive. Cancellation + * Execute through pre-policy, guards, around-dispatch, post-policy, + * definition-owned content finalization, and final notification. Tool and + * listener failures resolve as materialized error results; an invisible tool + * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen + * snapshot final observers receive. Cancellation * arriving after entry and before final result materialization skips a * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a * successful started outcome with `ABORTED`; already-started work is still @@ -1619,7 +1620,7 @@ async execute(exec: ToolExecutionInput): Promise Types: [ScopeKey](../core-data-structures/scope.md) · [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolGuard](../core-data-structures/tools.md) · [ToolRestriction](../core-data-structures/tools.md) · [ToolSchema](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:524`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:536`](../../packages/core/tools/src/index.ts) ## `ctx.userInteraction` — `UserInteractionService` diff --git a/docs/core-data-structures/core.md b/docs/core-data-structures/core.md index 6b5596b782..46d543733b 100644 --- a/docs/core-data-structures/core.md +++ b/docs/core-data-structures/core.md @@ -544,6 +544,6 @@ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact' ## `ToolDefinition` -The one pipeline-authoring type that is core: what every registered tool *is* — a model-facing `ToolSchema` plus an `execute` function and optional UI presenters. A tool author rarely constructs it by hand (the `defineTool` DSL builds it with typed args), but it is the contract the registry holds and the loop dispatches through. +The one pipeline-authoring type that is core: what every registered tool *is* — a model-facing `ToolSchema` plus an `execute` function and optional final-content and UI callbacks. A tool author rarely constructs it by hand (the `defineTool` DSL builds it with typed args), but it is the contract the registry holds and the loop dispatches through. Its full fields, the `defineTool`/`SchemaSpec`/`InferArgs` typed schema DSL, the `ToolExecution`/`ToolExecutionResult` waterfall shapes, and the tool-presentation UI vocabulary are on **[tools.md](tools.md)**. diff --git a/docs/core-data-structures/tools.md b/docs/core-data-structures/tools.md index a4f523fe61..3174cff8b8 100644 --- a/docs/core-data-structures/tools.md +++ b/docs/core-data-structures/tools.md @@ -6,7 +6,7 @@ Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index ## `ToolDefinition` — a registered tool -A `ToolSchema` (the model-facing fields) plus the `execute` function, host-only scheduler metadata, and optional UI presenters. The registry holds these; the loop dispatches calls through them. The registry's `schemas()` builds the model-facing `ToolSchema[]` by an explicit allowlist — `execute`/`timeoutMs`/`isConcurrencySafe`/`presentCall`/`presentResult` must never leak into a model request. +A `ToolSchema` (the model-facing fields) plus the `execute` function, host-only scheduler metadata, final-content callback, and optional UI presenters. The registry holds these; the loop dispatches calls through them. The registry's `schemas()` builds the model-facing `ToolSchema[]` by an explicit allowlist — `execute`/`finalizeContent`/`timeoutMs`/`isConcurrencySafe`/`presentCall`/`presentResult` must never leak into a model request. ```ts type-equiv /** A registered tool: its schema plus the execution function. */ @@ -21,6 +21,18 @@ interface ToolDefinition extends ToolSchema { * @returns model-facing content plus optional private presentation metadata. */ execute(args: unknown, exec: ToolRunContext): Promise + /** + * Synchronous last-mile transform for model-facing content. The registry + * snapshots this callback when execution starts and invokes it exactly once + * for every normalized outcome, including pipeline failures that bypass + * `tools/post-execute`, immediately before lossless materialization. + * Returning `undefined` preserves the content; every other result field + * remains registry-owned. The callback must be total and must not throw. + * @param exec - immutable execution identity and arguments. + * @param result - complete normalized outcome before materialization. + * @returns replacement content, or `undefined` to preserve it. + */ + finalizeContent?(exec: Readonly, result: Readonly): ContentBlock[] | undefined /** * Cooperative tool-call timeout budget in milliseconds. Omit for no deadline. * Enforced by `@deepseek-ai/dsh-timeout-policy` (a `tools/execute` wrapper); it @@ -64,7 +76,7 @@ interface ToolDefinition extends ToolSchema { } ``` -`execute` receives `args: unknown` — a raw `ToolDefinition` validates its own input. First-party tools don't write that by hand; they use `defineTool`, which validates and narrows for them. +`execute` receives `args: unknown` — a raw `ToolDefinition` validates its own input. First-party tools don't write that by hand; they use `defineTool`, which validates and narrows for them. `finalizeContent` deliberately receives the immutable execution instead of typed arguments because invalid-input and outer pipeline failures reach it too; it may enforce a tool-owned content bound while preserving `isError`, structured error identity, deferred contexts, and presentation metadata. ## The typed schema DSL @@ -147,7 +159,7 @@ interface ToolRestriction { ## Execution: extensible waterfalls plus monotonic policy -`ctx.tools.execute()` accepts a caller-owned `ToolExecutionInput` with a required readonly `signal`, materializes its parsed JSON arguments once into a pipeline-owned `ToolExecution`, and runs that call through `tools/pre-execute` (the reorderable allow/deny/ask waterfall) → registered monotonic guards → `tools/execute` (around-dispatch wrappers) → `tools/post-execute` (inspect/replace the result) → `tools/result` (the immutable authoritative outcome). Only the `tools/execute` view may replace the required signal. The outcome is a `ToolExecutionResult`. +`ctx.tools.execute()` accepts a caller-owned `ToolExecutionInput` with a required readonly `signal`, materializes its parsed JSON arguments once into a pipeline-owned `ToolExecution`, and runs that call through `tools/pre-execute` (the reorderable allow/deny/ask waterfall) → registered monotonic guards → `tools/execute` (around-dispatch wrappers) → `tools/post-execute` (inspect/replace the result) → optional definition-owned `finalizeContent` → `tools/result` (the immutable authoritative outcome). Only the `tools/execute` view may replace the required signal. The outcome is a `ToolExecutionResult`. ```ts type-equiv /** Opaque call identity that permits correlation without exposing mutable execution state. */ diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index e52cc1fb59..71b49e92aa 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -43,7 +43,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:35`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - | | `tools/change` | `emit` | [`packages/core/tools/src/index.ts:123`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | | `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:93`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`timeout-policy`](../packages/timeout/timeout-policy) | -| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:105`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-pty`](../packages/pty/tool-pty), [`tool-tasks`](../packages/tasks/tool-tasks), [`workspace-context`](../packages/context/workspace-context) | +| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:105`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`workspace-context`](../packages/context/workspace-context) | | `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:82`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-tasks`](../packages/tasks/tool-tasks) | | `tools/result` | `emit` | [`packages/core/tools/src/index.ts:113`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:81`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) | diff --git a/docs/tool-execution-pipeline.md b/docs/tool-execution-pipeline.md index 5fc21db2f5..a6646e6587 100644 --- a/docs/tool-execution-pipeline.md +++ b/docs/tool-execution-pipeline.md @@ -3,7 +3,7 @@ # Tool Execution Pipeline -This graph shows where policy, hooks, sandboxing, filesystem guards, result rewriting, final-outcome observation, and UI rendering fit without changing the loop. The transformable extension points are the `tools/pre-execute`, `tools/execute`, and `tools/post-execute` waterfalls; monotonic guards and `tools/result` are the owner-enforced boundaries around them. +This graph shows where policy, hooks, sandboxing, filesystem guards, result rewriting, final-outcome observation, and UI rendering fit without changing the loop. The transformable extension points are the `tools/pre-execute`, `tools/execute`, and `tools/post-execute` waterfalls; monotonic guards, definition-owned `finalizeContent`, and `tools/result` are the owner-enforced boundaries around them. ```mermaid flowchart TD @@ -19,6 +19,8 @@ flowchart TD fsGate["fs/write-intent or fs/edit-intent
    tool-fs mutations only"] owned["Tool-owned session events
    todo/write, fs/observed, hook/invoked, hook/result, tool/code-dispatch"] post["tools/post-execute waterfall
    accept, block, replace, add context"] + normalized["Registry outer normalization
    pipeline throws become isError"] + finalize["ToolDefinition.finalizeContent
    last content-only invariant"] final["tools/result synchronous notification
    frozen authoritative outcome"] context["Active-batch additionalContexts FIFO
    context/message after recorded tool results"] toolResult["Session event: tool/result
    single model-facing outcome"] @@ -30,24 +32,31 @@ flowchart TD pre -->|allow| guards guards -->|allow| around guards -->|deny| denied + guards -.->|throw| normalized around --> toolBody pre -->|deny| denied pre -->|ask| approval approval -->|allowed-once| guards approval -->|rejected, cancelled, unavailable| denied + approval -.->|throw| normalized denied --> post + pre -.->|throw| normalized toolBody --> fsGate fsGate --> toolBody toolBody --> owned toolBody --> around around --> post - post --> final + around -.->|wrapper throws| normalized + post -.->|throw| normalized + post --> finalize + normalized --> finalize + finalize --> final final --> toolResult toolResult --> presentResult toolResult --> allResults allResults --> context ``` -Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`, while `tools/result` observes the immutable outcome after transforms, lossless-JSON validation, and outer error normalization. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, surface denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency. +Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The visible definition's snapshotted `finalizeContent` callback then enforces a synchronous content-only invariant across ordinary decisions and normalized pipeline failures before `tools/result` observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, surface denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency. Maintenance mode: curated Mermaid flow; exact tool schemas and event signatures live in generated catalogs. diff --git a/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl b/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl index bd13d3b146..922764be57 100644 --- a/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl +++ b/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl @@ -11,7 +11,7 @@ {"type":"assistant/chunk","seq":9,"time":1783951000009,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":10,"time":1784449176722,"data":{"turn":1,"step":1,"content":[{"type":"tool-call","id":"inspect-tools-api","name":"cordis_inspect","arguments":"{\"what\":\"api\",\"name\":\"tools\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[5,6,7,8,9],"surfaceOp":"append"} {"type":"tool/call","seq":11,"time":1784449176722,"data":{"turn":1,"step":1,"callId":"inspect-tools-api","name":"cordis_inspect","arguments":"{\"what\":\"api\",\"name\":\"tools\"}"}} -{"type":"tool/result","seq":12,"time":1784449176732,"data":{"turn":1,"step":1,"callId":"inspect-tools-api","content":[{"type":"text","text":"## api\n- tools — Tool registry and execution pipeline.\n /**\n * Register globally or in the calling agent scope. Scoped tools shadow\n * globals; duplicates within one layer and the reserved `run_code` name fail.\n * @param definition - the tool schema, execution, and optional presentation functions.\n * @returns the exact disposer that unregisters the tool.\n */\n register(definition: ToolDefinition): () => void\n /**\n * Restrict global tools for the calling agent scope. Empty filters, unknown\n * names, scope-local names, and reserved transport names fail. Restrictions\n * intersect; scoped registrations remain visible.\n * @param filter - global-surface mask: `allow` (keep only) and/or `deny` (remove).\n * @returns the exact disposer that lifts this restriction.\n */\n restrict(filter: ToolRestriction): () => void\n /**\n * Register a monotonic guard after the extensible `tools/pre-execute`\n * waterfall. A plain-context guard applies globally; one registered through\n * `agent.ctx` applies only to that agent. Any matching guard may deny by\n * returning a reason, while no guard can force-allow a call another guard\n * denied. The exact effect disposer is returned for ordered ownership and\n * HMR cleanup.\n * @param guard - synchronous check; a returned string denies the execution.\n * @returns the exact disposer that unregisters the guard.\n */\n guard(guard: ToolGuard): () => void\n /**\n * Look up a tool as one scope sees it (scoped\n * shadows global; a restricted-away global reads as absent). Presenters pass\n * the calling agent so the rendered card matches the definition that\n * actually executed.\n * @param name - the tool name as registered.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns the definition the scope resolves, or undefined when none is visible.\n */\n get(name: string, scope?: ScopeKey): ToolDefinition | undefined\n /**\n * Project visible definitions onto the allowlisted model-facing schema fields,\n * excluding execution and presentation callbacks.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns one deep-cloned schema per visible tool.\n */\n schemas(scope?: ScopeKey): ToolSchema[]\n /**\n * Classify a pending call through the caller's visible tool definition. Only\n * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or\n * throwing classifiers are exclusive.\n * @param exec - call name, parsed arguments, and optional agent scope.\n * @returns the fail-closed scheduling mode.\n */\n executionMode(exec: ToolExecutionInput): ToolExecutionMode\n /**\n * Execute through pre-policy, guards, around-dispatch, post-policy, and final\n * notification. Tool and listener failures resolve as materialized error\n * results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is\n * the same lossless, frozen snapshot final observers receive. Cancellation\n * arriving after entry and before final result materialization skips a\n * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a\n * successful started outcome with `ABORTED`; already-started work is still\n * drained and may retain a tool-owned structured error.\n * @param exec - the typed same-process call input. The registry assigns its\n * correlation token before policy begins.\n * @returns the materialized final result.\n */\n async execute(exec: ToolExecutionInput): Promise\ntype shapes (referenced by the signatures above — read these before assuming a field is a string):\n export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly status: AgentStatus;\n readonly ctx: Context;\n send(content: ContentBlock[], options?: SendOptions): void;\n steer(content: ContentBlock[], options?: SendOptions): void;\n inject(content: ContentBlock[], options?: InjectOptions): void;\n cancel(cause?: AgentCancelCause): void;\n whenIdle(): Promise;\n }\n export type AgentCancelCause = {\n readonly kind: 'user';\n } | {\n readonly kind: 'parent';\n };\n export interface AgentOptions {\n provider?: string;\n model?: string;\n }\n export type AgentStatus = 'idle' | 'running' | 'disposed';\n export type Branded = string & {\n readonly [BRAND]: B;\n };\n export type CallId = Branded<'CallId'>;\n export interface DiffCallView {\n card: 'diff';\n title: string;\n diffs: FileDiff[];\n locations?: FileLocation[];\n }\n export interface DiffResultView {\n card: 'diff';\n title?: string;\n diffs: FileDiff[];\n }\n export interface FileDiff {\n path: string;\n oldText: string | null;\n newText: string;\n }\n export interface FileLocation {\n path: string;\n line?: number;\n }\n export interface GenericCallView {\n card: 'generic';\n title: string;\n kind?: ToolCallKind;\n rawInput?: unknown;\n content?: ContentBlock[];\n locations?: FileLocation[];\n }\n export interface GenericResultView {\n card: 'generic';\n title?: string;\n content?: ContentBlock[];\n }\n export interface HookContext {\n content: ContentBlock[];\n source: MessageSource;\n placement?: 'separate' | 'prompt-prefix';\n meta?: JsonValue;\n }\n export interface InjectOptions extends Omit {\n meta?: JsonValue;\n }\n export type JsonValue = null | boolean | number | string | JsonValue[] | {\n [key: string]: JsonValue;\n };\n export type MessageSource = MessageSourceMap[keyof MessageSourceMap];\n export interface MessageSourceMap {\n user: {\n kind: 'user';\n };\n plugin: {\n kind: 'plugin';\n plugin: string;\n };\n }\n export type ScopeKey = object;\n export interface SendOptions {\n source?: MessageSource;\n contexts?: HookContext[];\n }\n export type SessionId = Branded<'SessionId'>;\n export interface TerminalCallView {\n card: 'terminal';\n title: string;\n description?: string;\n cwd?: string;\n }\n export interface TerminalResultView {\n card: 'terminal';\n title?: string;\n output?: string;\n exitCode?: number;\n signal?: string;\n }\n export type ToolCallKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other';\n export type ToolCallView = GenericCallView | TerminalCallView | DiffCallView;\n export interface ToolDefinition extends ToolSchema {\n execute(args: unknown, exec: ToolRunContext): Promise;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n }\n export interface ToolErrorInfo {\n name: string;\n code: string;\n }\n export type ToolExecuteReturn = ContentBlock[] | {\n content: ContentBlock[];\n meta?: unknown;\n };\n export interface ToolExecution extends ToolExecutionInput {\n readonly token: ToolExecutionToken;\n }\n export interface ToolExecutionInput {\n readonly callId: CallId;\n readonly name: string;\n readonly arguments: unknown;\n readonly agent?: Agent;\n readonly parent?: ToolExecutionToken;\n readonly signal: AbortSignal;\n }\n export type ToolExecutionMode = {\n kind: 'parallel';\n } | {\n kind: 'exclusive';\n };\n export interface ToolExecutionResult {\n content: ContentBlock[];\n isError: boolean;\n error?: ToolErrorInfo;\n additionalContexts?: HookContext[];\n meta?: unknown;\n }\n export type ToolExecutionToken = symbol & {\n readonly [toolExecutionTokenBrand]: true;\n };\n export type ToolGuard = (execution: Readonly) => string | undefined;\n export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n }\n export interface ToolResult {\n content: ContentBlock[];\n isError: boolean;\n meta?: unknown;\n }\n export type ToolResultView = GenericResultView | TerminalResultView | DiffResultView;\n export interface ToolRunContext extends ToolExecution {\n deferContext(context: HookContext): void;\n }\n export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n }"}],"isError":false},"sourceEventSeqs":[11],"surfaceOp":"append"} +{"type":"tool/result","seq":12,"time":1784449176732,"data":{"turn":1,"step":1,"callId":"inspect-tools-api","content":[{"type":"text","text":"## api\n- tools — Tool registry and execution pipeline.\n /**\n * Register globally or in the calling agent scope. Scoped tools shadow\n * globals; duplicates within one layer and the reserved `run_code` name fail.\n * @param definition - tool schema, execution, and optional finalization/presentation callbacks.\n * @returns the exact disposer that unregisters the tool.\n */\n register(definition: ToolDefinition): () => void\n /**\n * Restrict global tools for the calling agent scope. Empty filters, unknown\n * names, scope-local names, and reserved transport names fail. Restrictions\n * intersect; scoped registrations remain visible.\n * @param filter - global-surface mask: `allow` (keep only) and/or `deny` (remove).\n * @returns the exact disposer that lifts this restriction.\n */\n restrict(filter: ToolRestriction): () => void\n /**\n * Register a monotonic guard after the extensible `tools/pre-execute`\n * waterfall. A plain-context guard applies globally; one registered through\n * `agent.ctx` applies only to that agent. Any matching guard may deny by\n * returning a reason, while no guard can force-allow a call another guard\n * denied. The exact effect disposer is returned for ordered ownership and\n * HMR cleanup.\n * @param guard - synchronous check; a returned string denies the execution.\n * @returns the exact disposer that unregisters the guard.\n */\n guard(guard: ToolGuard): () => void\n /**\n * Look up a tool as one scope sees it (scoped\n * shadows global; a restricted-away global reads as absent). Presenters pass\n * the calling agent so the rendered card matches the definition that\n * actually executed.\n * @param name - the tool name as registered.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns the definition the scope resolves, or undefined when none is visible.\n */\n get(name: string, scope?: ScopeKey): ToolDefinition | undefined\n /**\n * Project visible definitions onto the allowlisted model-facing schema fields,\n * excluding execution and presentation callbacks.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns one deep-cloned schema per visible tool.\n */\n schemas(scope?: ScopeKey): ToolSchema[]\n /**\n * Classify a pending call through the caller's visible tool definition. Only\n * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or\n * throwing classifiers are exclusive.\n * @param exec - call name, parsed arguments, and optional agent scope.\n * @returns the fail-closed scheduling mode.\n */\n executionMode(exec: ToolExecutionInput): ToolExecutionMode\n /**\n * Execute through pre-policy, guards, around-dispatch, post-policy,\n * definition-owned content finalization, and final notification. Tool and\n * listener failures resolve as materialized error results; an invisible tool\n * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen\n * snapshot final observers receive. Cancellation\n * arriving after entry and before final result materialization skips a\n * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a\n * successful started outcome with `ABORTED`; already-started work is still\n * drained and may retain a tool-owned structured error.\n * @param exec - the typed same-process call input. The registry assigns its\n * correlation token before policy begins.\n * @returns the materialized final result.\n */\n async execute(exec: ToolExecutionInput): Promise\ntype shapes (referenced by the signatures above — read these before assuming a field is a string):\n export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly status: AgentStatus;\n readonly ctx: Context;\n send(content: ContentBlock[], options?: SendOptions): void;\n steer(content: ContentBlock[], options?: SendOptions): void;\n inject(content: ContentBlock[], options?: InjectOptions): void;\n cancel(cause?: AgentCancelCause): void;\n whenIdle(): Promise;\n }\n export type AgentCancelCause = {\n readonly kind: 'user';\n } | {\n readonly kind: 'parent';\n };\n export interface AgentOptions {\n provider?: string;\n model?: string;\n }\n export type AgentStatus = 'idle' | 'running' | 'disposed';\n export type Branded = string & {\n readonly [BRAND]: B;\n };\n export type CallId = Branded<'CallId'>;\n export interface DiffCallView {\n card: 'diff';\n title: string;\n diffs: FileDiff[];\n locations?: FileLocation[];\n }\n export interface DiffResultView {\n card: 'diff';\n title?: string;\n diffs: FileDiff[];\n }\n export interface FileDiff {\n path: string;\n oldText: string | null;\n newText: string;\n }\n export interface FileLocation {\n path: string;\n line?: number;\n }\n export interface GenericCallView {\n card: 'generic';\n title: string;\n kind?: ToolCallKind;\n rawInput?: unknown;\n content?: ContentBlock[];\n locations?: FileLocation[];\n }\n export interface GenericResultView {\n card: 'generic';\n title?: string;\n content?: ContentBlock[];\n }\n export interface HookContext {\n content: ContentBlock[];\n source: MessageSource;\n placement?: 'separate' | 'prompt-prefix';\n meta?: JsonValue;\n }\n export interface InjectOptions extends Omit {\n meta?: JsonValue;\n }\n export type JsonValue = null | boolean | number | string | JsonValue[] | {\n [key: string]: JsonValue;\n };\n export type MessageSource = MessageSourceMap[keyof MessageSourceMap];\n export interface MessageSourceMap {\n user: {\n kind: 'user';\n };\n plugin: {\n kind: 'plugin';\n plugin: string;\n };\n }\n export type ScopeKey = object;\n export interface SendOptions {\n source?: MessageSource;\n contexts?: HookContext[];\n }\n export type SessionId = Branded<'SessionId'>;\n export interface TerminalCallView {\n card: 'terminal';\n title: string;\n description?: string;\n cwd?: string;\n }\n export interface TerminalResultView {\n card: 'terminal';\n title?: string;\n output?: string;\n exitCode?: number;\n signal?: string;\n }\n export type ToolCallKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other';\n export type ToolCallView = GenericCallView | TerminalCallView | DiffCallView;\n export interface ToolDefinition extends ToolSchema {\n execute(args: unknown, exec: ToolRunContext): Promise;\n finalizeContent?(exec: Readonly, result: Readonly): ContentBlock[] | undefined;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n }\n export interface ToolErrorInfo {\n name: string;\n code: string;\n }\n export type ToolExecuteReturn = ContentBlock[] | {\n content: ContentBlock[];\n meta?: unknown;\n };\n export interface ToolExecution extends ToolExecutionInput {\n readonly token: ToolExecutionToken;\n }\n export interface ToolExecutionInput {\n readonly callId: CallId;\n readonly name: string;\n readonly arguments: unknown;\n readonly agent?: Agent;\n readonly parent?: ToolExecutionToken;\n readonly signal: AbortSignal;\n }\n export type ToolExecutionMode = {\n kind: 'parallel';\n } | {\n kind: 'exclusive';\n };\n export interface ToolExecutionResult {\n content: ContentBlock[];\n isError: boolean;\n error?: ToolErrorInfo;\n additionalContexts?: HookContext[];\n meta?: unknown;\n }\n export type ToolExecutionToken = symbol & {\n readonly [toolExecutionTokenBrand]: true;\n };\n export type ToolGuard = (execution: Readonly) => string | undefined;\n export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n }\n export interface ToolResult {\n content: ContentBlock[];\n isError: boolean;\n meta?: unknown;\n }\n export type ToolResultView = GenericResultView | TerminalResultView | DiffResultView;\n export interface ToolRunContext extends ToolExecution {\n deferContext(context: HookContext): void;\n }\n export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n }"}],"isError":false},"sourceEventSeqs":[11],"surfaceOp":"append"} {"type":"step/end","seq":13,"time":1784449176732,"data":{"turn":1,"step":1}} {"type":"step/start","seq":14,"time":1784449176733,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":15,"time":1783951000015,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}} diff --git a/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl b/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl index 6a78b05a65..6ced35e986 100644 --- a/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl +++ b/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl @@ -3,7 +3,7 @@ {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"available_commands_update","availableCommands":[{"name":"goal","description":"set or view the goal for a long-running task","input":{"hint":"[|clear|edit |pause|resume]"}},{"name":"plan","description":"Enter plan mode","input":{"hint":"[message]"}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"session_info_update","title":"Inspect the exact tools service","updatedAt":"{{updatedAt}}"}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"inspect-tools-api","title":"Inspect cordis runtime: api: tools","kind":"read","status":"in_progress"}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"inspect-tools-api","status":"completed","content":[{"type":"content","content":{"type":"text","text":"## api\n- tools — Tool registry and execution pipeline.\n /**\n * Register globally or in the calling agent scope. Scoped tools shadow\n * globals; duplicates within one layer and the reserved `run_code` name fail.\n * @param definition - the tool schema, execution, and optional presentation functions.\n * @returns the exact disposer that unregisters the tool.\n */\n register(definition: ToolDefinition): () => void\n /**\n * Restrict global tools for the calling agent scope. Empty filters, unknown\n * names, scope-local names, and reserved transport names fail. Restrictions\n * intersect; scoped registrations remain visible.\n * @param filter - global-surface mask: `allow` (keep only) and/or `deny` (remove).\n * @returns the exact disposer that lifts this restriction.\n */\n restrict(filter: ToolRestriction): () => void\n /**\n * Register a monotonic guard after the extensible `tools/pre-execute`\n * waterfall. A plain-context guard applies globally; one registered through\n * `agent.ctx` applies only to that agent. Any matching guard may deny by\n * returning a reason, while no guard can force-allow a call another guard\n * denied. The exact effect disposer is returned for ordered ownership and\n * HMR cleanup.\n * @param guard - synchronous check; a returned string denies the execution.\n * @returns the exact disposer that unregisters the guard.\n */\n guard(guard: ToolGuard): () => void\n /**\n * Look up a tool as one scope sees it (scoped\n * shadows global; a restricted-away global reads as absent). Presenters pass\n * the calling agent so the rendered card matches the definition that\n * actually executed.\n * @param name - the tool name as registered.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns the definition the scope resolves, or undefined when none is visible.\n */\n get(name: string, scope?: ScopeKey): ToolDefinition | undefined\n /**\n * Project visible definitions onto the allowlisted model-facing schema fields,\n * excluding execution and presentation callbacks.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns one deep-cloned schema per visible tool.\n */\n schemas(scope?: ScopeKey): ToolSchema[]\n /**\n * Classify a pending call through the caller's visible tool definition. Only\n * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or\n * throwing classifiers are exclusive.\n * @param exec - call name, parsed arguments, and optional agent scope.\n * @returns the fail-closed scheduling mode.\n */\n executionMode(exec: ToolExecutionInput): ToolExecutionMode\n /**\n * Execute through pre-policy, guards, around-dispatch, post-policy, and final\n * notification. Tool and listener failures resolve as materialized error\n * results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is\n * the same lossless, frozen snapshot final observers receive. Cancellation\n * arriving after entry and before final result materialization skips a\n * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a\n * successful started outcome with `ABORTED`; already-started work is still\n * drained and may retain a tool-owned structured error.\n * @param exec - the typed same-process call input. The registry assigns its\n * correlation token before policy begins.\n * @returns the materialized final result.\n */\n async execute(exec: ToolExecutionInput): Promise\ntype shapes (referenced by the signatures above — read these before assuming a field is a string):\n export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly status: AgentStatus;\n readonly ctx: Context;\n send(content: ContentBlock[], options?: SendOptions): void;\n steer(content: ContentBlock[], options?: SendOptions): void;\n inject(content: ContentBlock[], options?: InjectOptions): void;\n cancel(cause?: AgentCancelCause): void;\n whenIdle(): Promise;\n }\n export type AgentCancelCause = {\n readonly kind: 'user';\n } | {\n readonly kind: 'parent';\n };\n export interface AgentOptions {\n provider?: string;\n model?: string;\n }\n export type AgentStatus = 'idle' | 'running' | 'disposed';\n export type Branded = string & {\n readonly [BRAND]: B;\n };\n export type CallId = Branded<'CallId'>;\n export interface DiffCallView {\n card: 'diff';\n title: string;\n diffs: FileDiff[];\n locations?: FileLocation[];\n }\n export interface DiffResultView {\n card: 'diff';\n title?: string;\n diffs: FileDiff[];\n }\n export interface FileDiff {\n path: string;\n oldText: string | null;\n newText: string;\n }\n export interface FileLocation {\n path: string;\n line?: number;\n }\n export interface GenericCallView {\n card: 'generic';\n title: string;\n kind?: ToolCallKind;\n rawInput?: unknown;\n content?: ContentBlock[];\n locations?: FileLocation[];\n }\n export interface GenericResultView {\n card: 'generic';\n title?: string;\n content?: ContentBlock[];\n }\n export interface HookContext {\n content: ContentBlock[];\n source: MessageSource;\n placement?: 'separate' | 'prompt-prefix';\n meta?: JsonValue;\n }\n export interface InjectOptions extends Omit {\n meta?: JsonValue;\n }\n export type JsonValue = null | boolean | number | string | JsonValue[] | {\n [key: string]: JsonValue;\n };\n export type MessageSource = MessageSourceMap[keyof MessageSourceMap];\n export interface MessageSourceMap {\n user: {\n kind: 'user';\n };\n plugin: {\n kind: 'plugin';\n plugin: string;\n };\n }\n export type ScopeKey = object;\n export interface SendOptions {\n source?: MessageSource;\n contexts?: HookContext[];\n }\n export type SessionId = Branded<'SessionId'>;\n export interface TerminalCallView {\n card: 'terminal';\n title: string;\n description?: string;\n cwd?: string;\n }\n export interface TerminalResultView {\n card: 'terminal';\n title?: string;\n output?: string;\n exitCode?: number;\n signal?: string;\n }\n export type ToolCallKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other';\n export type ToolCallView = GenericCallView | TerminalCallView | DiffCallView;\n export interface ToolDefinition extends ToolSchema {\n execute(args: unknown, exec: ToolRunContext): Promise;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n }\n export interface ToolErrorInfo {\n name: string;\n code: string;\n }\n export type ToolExecuteReturn = ContentBlock[] | {\n content: ContentBlock[];\n meta?: unknown;\n };\n export interface ToolExecution extends ToolExecutionInput {\n readonly token: ToolExecutionToken;\n }\n export interface ToolExecutionInput {\n readonly callId: CallId;\n readonly name: string;\n readonly arguments: unknown;\n readonly agent?: Agent;\n readonly parent?: ToolExecutionToken;\n readonly signal: AbortSignal;\n }\n export type ToolExecutionMode = {\n kind: 'parallel';\n } | {\n kind: 'exclusive';\n };\n export interface ToolExecutionResult {\n content: ContentBlock[];\n isError: boolean;\n error?: ToolErrorInfo;\n additionalContexts?: HookContext[];\n meta?: unknown;\n }\n export type ToolExecutionToken = symbol & {\n readonly [toolExecutionTokenBrand]: true;\n };\n export type ToolGuard = (execution: Readonly) => string | undefined;\n export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n }\n export interface ToolResult {\n content: ContentBlock[];\n isError: boolean;\n meta?: unknown;\n }\n export type ToolResultView = GenericResultView | TerminalResultView | DiffResultView;\n export interface ToolRunContext extends ToolExecution {\n deferContext(context: HookContext): void;\n }\n export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n }"}}]}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"inspect-tools-api","status":"completed","content":[{"type":"content","content":{"type":"text","text":"## api\n- tools — Tool registry and execution pipeline.\n /**\n * Register globally or in the calling agent scope. Scoped tools shadow\n * globals; duplicates within one layer and the reserved `run_code` name fail.\n * @param definition - tool schema, execution, and optional finalization/presentation callbacks.\n * @returns the exact disposer that unregisters the tool.\n */\n register(definition: ToolDefinition): () => void\n /**\n * Restrict global tools for the calling agent scope. Empty filters, unknown\n * names, scope-local names, and reserved transport names fail. Restrictions\n * intersect; scoped registrations remain visible.\n * @param filter - global-surface mask: `allow` (keep only) and/or `deny` (remove).\n * @returns the exact disposer that lifts this restriction.\n */\n restrict(filter: ToolRestriction): () => void\n /**\n * Register a monotonic guard after the extensible `tools/pre-execute`\n * waterfall. A plain-context guard applies globally; one registered through\n * `agent.ctx` applies only to that agent. Any matching guard may deny by\n * returning a reason, while no guard can force-allow a call another guard\n * denied. The exact effect disposer is returned for ordered ownership and\n * HMR cleanup.\n * @param guard - synchronous check; a returned string denies the execution.\n * @returns the exact disposer that unregisters the guard.\n */\n guard(guard: ToolGuard): () => void\n /**\n * Look up a tool as one scope sees it (scoped\n * shadows global; a restricted-away global reads as absent). Presenters pass\n * the calling agent so the rendered card matches the definition that\n * actually executed.\n * @param name - the tool name as registered.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns the definition the scope resolves, or undefined when none is visible.\n */\n get(name: string, scope?: ScopeKey): ToolDefinition | undefined\n /**\n * Project visible definitions onto the allowlisted model-facing schema fields,\n * excluding execution and presentation callbacks.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns one deep-cloned schema per visible tool.\n */\n schemas(scope?: ScopeKey): ToolSchema[]\n /**\n * Classify a pending call through the caller's visible tool definition. Only\n * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or\n * throwing classifiers are exclusive.\n * @param exec - call name, parsed arguments, and optional agent scope.\n * @returns the fail-closed scheduling mode.\n */\n executionMode(exec: ToolExecutionInput): ToolExecutionMode\n /**\n * Execute through pre-policy, guards, around-dispatch, post-policy,\n * definition-owned content finalization, and final notification. Tool and\n * listener failures resolve as materialized error results; an invisible tool\n * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen\n * snapshot final observers receive. Cancellation\n * arriving after entry and before final result materialization skips a\n * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a\n * successful started outcome with `ABORTED`; already-started work is still\n * drained and may retain a tool-owned structured error.\n * @param exec - the typed same-process call input. The registry assigns its\n * correlation token before policy begins.\n * @returns the materialized final result.\n */\n async execute(exec: ToolExecutionInput): Promise\ntype shapes (referenced by the signatures above — read these before assuming a field is a string):\n export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly status: AgentStatus;\n readonly ctx: Context;\n send(content: ContentBlock[], options?: SendOptions): void;\n steer(content: ContentBlock[], options?: SendOptions): void;\n inject(content: ContentBlock[], options?: InjectOptions): void;\n cancel(cause?: AgentCancelCause): void;\n whenIdle(): Promise;\n }\n export type AgentCancelCause = {\n readonly kind: 'user';\n } | {\n readonly kind: 'parent';\n };\n export interface AgentOptions {\n provider?: string;\n model?: string;\n }\n export type AgentStatus = 'idle' | 'running' | 'disposed';\n export type Branded = string & {\n readonly [BRAND]: B;\n };\n export type CallId = Branded<'CallId'>;\n export interface DiffCallView {\n card: 'diff';\n title: string;\n diffs: FileDiff[];\n locations?: FileLocation[];\n }\n export interface DiffResultView {\n card: 'diff';\n title?: string;\n diffs: FileDiff[];\n }\n export interface FileDiff {\n path: string;\n oldText: string | null;\n newText: string;\n }\n export interface FileLocation {\n path: string;\n line?: number;\n }\n export interface GenericCallView {\n card: 'generic';\n title: string;\n kind?: ToolCallKind;\n rawInput?: unknown;\n content?: ContentBlock[];\n locations?: FileLocation[];\n }\n export interface GenericResultView {\n card: 'generic';\n title?: string;\n content?: ContentBlock[];\n }\n export interface HookContext {\n content: ContentBlock[];\n source: MessageSource;\n placement?: 'separate' | 'prompt-prefix';\n meta?: JsonValue;\n }\n export interface InjectOptions extends Omit {\n meta?: JsonValue;\n }\n export type JsonValue = null | boolean | number | string | JsonValue[] | {\n [key: string]: JsonValue;\n };\n export type MessageSource = MessageSourceMap[keyof MessageSourceMap];\n export interface MessageSourceMap {\n user: {\n kind: 'user';\n };\n plugin: {\n kind: 'plugin';\n plugin: string;\n };\n }\n export type ScopeKey = object;\n export interface SendOptions {\n source?: MessageSource;\n contexts?: HookContext[];\n }\n export type SessionId = Branded<'SessionId'>;\n export interface TerminalCallView {\n card: 'terminal';\n title: string;\n description?: string;\n cwd?: string;\n }\n export interface TerminalResultView {\n card: 'terminal';\n title?: string;\n output?: string;\n exitCode?: number;\n signal?: string;\n }\n export type ToolCallKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other';\n export type ToolCallView = GenericCallView | TerminalCallView | DiffCallView;\n export interface ToolDefinition extends ToolSchema {\n execute(args: unknown, exec: ToolRunContext): Promise;\n finalizeContent?(exec: Readonly, result: Readonly): ContentBlock[] | undefined;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n }\n export interface ToolErrorInfo {\n name: string;\n code: string;\n }\n export type ToolExecuteReturn = ContentBlock[] | {\n content: ContentBlock[];\n meta?: unknown;\n };\n export interface ToolExecution extends ToolExecutionInput {\n readonly token: ToolExecutionToken;\n }\n export interface ToolExecutionInput {\n readonly callId: CallId;\n readonly name: string;\n readonly arguments: unknown;\n readonly agent?: Agent;\n readonly parent?: ToolExecutionToken;\n readonly signal: AbortSignal;\n }\n export type ToolExecutionMode = {\n kind: 'parallel';\n } | {\n kind: 'exclusive';\n };\n export interface ToolExecutionResult {\n content: ContentBlock[];\n isError: boolean;\n error?: ToolErrorInfo;\n additionalContexts?: HookContext[];\n meta?: unknown;\n }\n export type ToolExecutionToken = symbol & {\n readonly [toolExecutionTokenBrand]: true;\n };\n export type ToolGuard = (execution: Readonly) => string | undefined;\n export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n }\n export interface ToolResult {\n content: ContentBlock[];\n isError: boolean;\n meta?: unknown;\n }\n export type ToolResultView = GenericResultView | TerminalResultView | DiffResultView;\n export interface ToolRunContext extends ToolExecution {\n deferContext(context: HookContext): void;\n }\n export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record;\n }"}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"inspect-tools-event","title":"Inspect cordis runtime: events: tools/pre-execute","kind":"read","status":"in_progress"}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"inspect-tools-event","status":"completed","content":[{"type":"content","content":{"type":"text","text":"## events\n- tools/pre-execute [waterfall] — Allow, deny, or ask before dispatch.\n /**\n * Allow, deny, or ask before dispatch. `next()` delegates to allow; missing\n * approval support turns `ask` into denial. Async gates must observe\n * `exec.signal`; the registry rechecks cancellation after they settle but\n * never abandons their promise.\n * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.\n * @param exec - the pending call (name, parsed arguments, caller agent).\n * @mode waterfall\n */\n 'tools/pre-execute'(this: Scoped, exec: ToolExecution, next: () => Promise): Promise\nwaterfall listeners receive a trailing next() and MUST call it to delegate — returning without next() vetoes the chain."}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"CORDIS_INSPECT_JSDOC_OK"}}}} diff --git a/packages/cordis/tool-cordis/src/api-catalog.ts b/packages/cordis/tool-cordis/src/api-catalog.ts index 5635e56c49..9a810b7be5 100644 --- a/packages/cordis/tool-cordis/src/api-catalog.ts +++ b/packages/cordis/tool-cordis/src/api-catalog.ts @@ -734,7 +734,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ methods: [ { signature: 'register(definition: ToolDefinition): () => void', - jsDoc: '/**\n * Register globally or in the calling agent scope. Scoped tools shadow\n * globals; duplicates within one layer and the reserved `run_code` name fail.\n * @param definition - the tool schema, execution, and optional presentation functions.\n * @returns the exact disposer that unregisters the tool.\n */', + jsDoc: '/**\n * Register globally or in the calling agent scope. Scoped tools shadow\n * globals; duplicates within one layer and the reserved `run_code` name fail.\n * @param definition - tool schema, execution, and optional finalization/presentation callbacks.\n * @returns the exact disposer that unregisters the tool.\n */', }, { signature: 'restrict(filter: ToolRestriction): () => void', @@ -758,7 +758,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ }, { signature: 'async execute(exec: ToolExecutionInput): Promise', - jsDoc: '/**\n * Execute through pre-policy, guards, around-dispatch, post-policy, and final\n * notification. Tool and listener failures resolve as materialized error\n * results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is\n * the same lossless, frozen snapshot final observers receive. Cancellation\n * arriving after entry and before final result materialization skips a\n * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a\n * successful started outcome with `ABORTED`; already-started work is still\n * drained and may retain a tool-owned structured error.\n * @param exec - the typed same-process call input. The registry assigns its\n * correlation token before policy begins.\n * @returns the materialized final result.\n */', + jsDoc: '/**\n * Execute through pre-policy, guards, around-dispatch, post-policy,\n * definition-owned content finalization, and final notification. Tool and\n * listener failures resolve as materialized error results; an invisible tool\n * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen\n * snapshot final observers receive. Cancellation\n * arriving after entry and before final result materialization skips a\n * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a\n * successful started outcome with `ABORTED`; already-started work is still\n * drained and may retain a tool-owned structured error.\n * @param exec - the typed same-process call input. The registry assigns its\n * correlation token before policy begins.\n * @returns the materialized final result.\n */', }, ], }, @@ -1973,7 +1973,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'ToolDefinition', - declaration: 'export interface ToolDefinition extends ToolSchema {\n execute(args: unknown, exec: ToolRunContext): Promise;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n}', + declaration: 'export interface ToolDefinition extends ToolSchema {\n execute(args: unknown, exec: ToolRunContext): Promise;\n finalizeContent?(exec: Readonly, result: Readonly): ContentBlock[] | undefined;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n}', }, { name: 'ToolErrorInfo', diff --git a/packages/cordis/tool-cordis/tests/inspect.spec.ts b/packages/cordis/tool-cordis/tests/inspect.spec.ts index 4d986d4f3e..e229fe33a6 100644 --- a/packages/cordis/tool-cordis/tests/inspect.spec.ts +++ b/packages/cordis/tool-cordis/tests/inspect.spec.ts @@ -76,7 +76,7 @@ describe('cordis_inspect', () => { expect(report).toContain('- tools — Tool registry and execution pipeline.') expect(report).toContain('/**') expect(report).toContain('Register globally or in the calling agent scope.') - expect(report).toContain('@param definition - the tool schema') + expect(report).toContain('@param definition - tool schema, execution, and optional finalization/presentation callbacks') expect(report).toContain('@returns the exact disposer') expect(report).toContain('register(definition: ToolDefinition)') expect(report).toContain('type shapes (referenced by the signatures above') diff --git a/packages/core/agent-loop/README.md b/packages/core/agent-loop/README.md index 1b89f288a8..79fbbd7824 100644 --- a/packages/core/agent-loop/README.md +++ b/packages/core/agent-loop/README.md @@ -67,7 +67,7 @@ Within a step, exclusive calls form barriers; parallel-safe calls use a bounded ### What belongs to plugins Everything that goes beyond "call the model, run the tools, repeat" belongs to plugins listening on the event taxonomy: -- Hooks and policy: the relevant `agent/*` checkpoints plus the guarded `tools/pre-execute` → `tools/execute` → `tools/post-execute` → `tools/result` pipeline; exact signatures and modes live in the [generated event catalog](../../../docs/cordis-catalog/events.md) +- Hooks and policy: the relevant `agent/*` checkpoints plus the guarded `tools/pre-execute` → `tools/execute` → `tools/post-execute` → definition-owned `finalizeContent` → `tools/result` pipeline; exact event signatures and modes live in the [generated event catalog](../../../docs/cordis-catalog/events.md) - Compaction: pressure on `agent/post-step`; canonical context overflow on `agent/request-error` - Transient model recovery: `dsh-llm-retry` on `agent/request-error`, with finite code-specific budgets and non-surface `llm/retry` status events - Sandbox, permission, plan mode: `tools/pre-execute` for extensible deny/ask, `tools.guard()` for monotonic owner policy, `tools/post-execute` for result decisions, and `tools/result` for final observation diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 823060f728..07b9dde1af 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -1,6 +1,6 @@ # dsh-tools -Tool registry and execution pipeline. Tool plugins register their schemas and executors; the agent loop executes each call through `tools/pre-execute` (the extensible allow/deny gate) → monotonic registered guards → `tools/execute` (an around-dispatch wrapper for timeout/retry/metrics plugins) → `tools/post-execute` (inspect/replace the result, attach context) → the observe-only `tools/result` notification. The registry also owns HOW its tools are presented to the model — its `mode` config selects native function calling, [Code Mode](#code-mode), or both. +Tool registry and execution pipeline. Tool plugins register their schemas and executors; the agent loop executes each call through `tools/pre-execute` (the extensible allow/deny gate) → monotonic registered guards → `tools/execute` (an around-dispatch wrapper for timeout/retry/metrics plugins) → `tools/post-execute` (inspect/replace the result, attach context) → the definition-owned `finalizeContent` boundary → the observe-only `tools/result` notification. The registry also owns HOW its tools are presented to the model — its `mode` config selects native function calling, [Code Mode](#code-mode), or both. ## Service: `ToolRegistry` (ctx key: `tools`) @@ -15,7 +15,7 @@ tools: ### Public API -- `ctx.tools.register(definition: ToolDefinition): () => void` Register a trusted typed same-process definition. The layer is the calling context's scope: a plain plugin context registers globally; an agent's `agent.ctx` registers for that agent alone, shadowing a same-named global tool there. Duplicate names within one layer throw; non-native modes also reject the reserved `run_code` transport name. `timeoutMs`, when present, must be positive and finite. Disposed with the calling fiber. +- `ctx.tools.register(definition: ToolDefinition): () => void` Register a trusted typed same-process definition. The layer is the calling context's scope: a plain plugin context registers globally; an agent's `agent.ctx` registers for that agent alone, shadowing a same-named global tool there. Duplicate names within one layer throw; non-native modes also reject the reserved `run_code` transport name. `timeoutMs`, when present, must be positive and finite. The optional synchronous `finalizeContent` callback is snapshotted when a call starts and may replace only final model-facing content after every pipeline outcome is normalized. Disposed with the calling fiber. - `ctx.tools.restrict(filter)` applies an agent-scoped allow/deny mask to global tools and throws from a plain context. The filter is snapshotted at registration; multiple masks intersect and scope-local tools merge afterwards. Deny masks admit later unnamed globals, while allow masks exclude later names. Unknown, local, or reserved names and empty filters reject. This is live visibility composition, not an authority boundary; see the [scope security non-goal](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-explicit-non-goals). - `ctx.tools.get(name: string, scope?: ScopeKey): ToolDefinition | undefined` Resolution as one scope sees it (shadowing applied; a restricted-away global reads as absent) — presenters pass the calling agent so the card matches what executed. - `ctx.tools.schemas(scope?: ScopeKey): ToolSchema[]` Schemas of everything the scope can see (without the `execute` functions). The shipped tools' schemas are catalogued in [docs/tool-catalog.md](../../../docs/tool-catalog.md), generated by booting each tool plugin and harvesting this method (see [the tool-schema-catalog Agent Note](../../../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md)). @@ -33,11 +33,11 @@ Cancellation is cooperative and quiescent. Every typed invocation supplies a cal ### Live events -The live registry pipeline has three transformable waterfalls followed by the observe-only `tools/result` boundary; registry changes are deliberately unfiltered shared-state notifications. Exact signatures, dispatch modes, scope filtering, and failure-containment contracts live in the generated [Cordis event catalog](../../../docs/cordis-catalog/events.md), while the complete ordering is visualized in the generated [tool execution pipeline](../../../docs/tool-execution-pipeline.md). `tools/result` is live; the similarly named `tool/result` is the durable session event the agent loop appends afterwards. +The live registry pipeline has three transformable waterfalls, then the definition-owned content finalizer, then the observe-only `tools/result` boundary; registry changes are deliberately unfiltered shared-state notifications. Exact signatures, dispatch modes, scope filtering, and failure-containment contracts live in the generated [Cordis event catalog](../../../docs/cordis-catalog/events.md), while the complete ordering is visualized in the generated [tool execution pipeline](../../../docs/tool-execution-pipeline.md). `tools/result` is live; the similarly named `tool/result` is the durable session event the agent loop appends afterwards. ### Key types -- `ToolDefinition` — `ToolSchema` + `execute(args, exec)`, whose async work must cooperatively stop through `exec.signal`, plus optional presentation callbacks, cooperative `timeoutMs`, and optional per-call `isConcurrencySafe(args)` classification. +- `ToolDefinition` — `ToolSchema` + `execute(args, exec)`, whose async work must cooperatively stop through `exec.signal`, plus optional final-content and presentation callbacks, cooperative `timeoutMs`, and optional per-call `isConcurrencySafe(args)` classification. `finalizeContent(exec, result)` runs exactly once for every normalized result, including failures that bypass post-policy, and can replace only `content`; it must be synchronous and total. - `ToolExecutionInput` — the caller-supplied call description: `{ callId, name, arguments, signal, agent?, parent? }`; `signal` is required and readonly, callers may pass an enclosing execution's opaque token as `parent`, and callers never choose the new execution's own token. - `ToolExecutionToken` — a fresh branded `Symbol` assigned by the registry. It supports equality correlation only and never crosses a model, log, or worker boundary. - `ToolExecution` — the readonly pipeline view: immutable `{ token, callId, name, arguments, signal, agent?, parent? }`; the registry separately retains and re-fuses the original caller signal. `ToolDispatchExecution` is the `tools/execute`-only view whose required signal is mutable, so a wrapper may replace and restore it but cannot delete it. A nested call's `parent` is a `ToolExecutionToken`, not an execution object. @@ -53,7 +53,7 @@ The live registry pipeline has three transformable waterfalls followed by the ob - Tool plugins call `ctx.tools.register()` — schemas flow into the assembly automatically. - `tools/pre-execute` is the reorderable allow/deny/ask gate; `ctx.tools.guard()` adds monotonic owner policy after it. - `tools/execute` wraps normalized core dispatch for timeout, retry, or metrics. Wrappers may replace only the operational signal. -- `tools/post-execute` may replace content, block with feedback, or attach ordered contexts; `tools/result` observes the immutable final outcome. +- `tools/post-execute` may replace content, block with feedback, or attach ordered contexts. A definition's optional `finalizeContent` then owns its last content-only invariant across normal results and outer pipeline failures; `tools/result` observes the immutable final outcome. - Exact signatures and ordering live in the generated [event catalog](../../../docs/cordis-catalog/events.md) and [pipeline](../../../docs/tool-execution-pipeline.md). - MCP servers: one plugin per server, discover tools, call `ctx.tools.register()` with the server's schemas. diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 11f57995e9..c434541b62 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -139,6 +139,18 @@ export interface ToolDefinition extends ToolSchema { * @returns model-facing content plus optional private presentation metadata. */ execute(args: unknown, exec: ToolRunContext): Promise + /** + * Synchronous last-mile transform for model-facing content. The registry + * snapshots this callback when execution starts and invokes it exactly once + * for every normalized outcome, including pipeline failures that bypass + * `tools/post-execute`, immediately before lossless materialization. + * Returning `undefined` preserves the content; every other result field + * remains registry-owned. The callback must be total and must not throw. + * @param exec - immutable execution identity and arguments. + * @param result - complete normalized outcome before materialization. + * @returns replacement content, or `undefined` to preserve it. + */ + finalizeContent?(exec: Readonly, result: Readonly): ContentBlock[] | undefined /** * Cooperative tool-call timeout budget in milliseconds. Omit for no deadline. * Enforced by `@deepseek-ai/dsh-timeout-policy` (a `tools/execute` wrapper); it @@ -301,9 +313,9 @@ export interface ToolRegistryScheduler { prepare(exec: ToolExecutionInput): Promise /** Run only the around-dispatch/body stage. */ dispatch(exec: ToolRunContext): Promise - /** Run ordered post-execute finalization, then materialize and notify the final outcome. */ + /** Run post-execute and definition-owned content finalization, then materialize and notify. */ finalize(exec: ToolRunContext, result: ToolExecutionResult): Promise - /** Materialize and notify a final outcome that must bypass post-execute. */ + /** Run definition-owned content finalization, then materialize and notify without post-execute. */ finish(exec: ToolRunContext, result: ToolExecutionResult): ToolExecutionResult } @@ -540,6 +552,8 @@ export class ToolRegistry extends Service { private deferredContexts = new WeakMap() /** Original caller cancellation, kept outside the wrapper-mutable execution object. */ private cancellationStates = new WeakMap() + /** Definition-owned final content transform snapshotted before policy begins. */ + private contentFinalizers = new WeakMap() private readonly layers = new ScopedLayers( scope => new ToolLayer(scope), () => { this.ctx.emit('tools/change') }, @@ -617,7 +631,7 @@ export class ToolRegistry extends Service { /** * Register globally or in the calling agent scope. Scoped tools shadow * globals; duplicates within one layer and the reserved `run_code` name fail. - * @param definition - the tool schema, execution, and optional presentation functions. + * @param definition - tool schema, execution, and optional finalization/presentation callbacks. * @returns the exact disposer that unregisters the tool. */ register(definition: ToolDefinition): () => void { @@ -784,10 +798,11 @@ export class ToolRegistry extends Service { } /** - * Execute through pre-policy, guards, around-dispatch, post-policy, and final - * notification. Tool and listener failures resolve as materialized error - * results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is - * the same lossless, frozen snapshot final observers receive. Cancellation + * Execute through pre-policy, guards, around-dispatch, post-policy, + * definition-owned content finalization, and final notification. Tool and + * listener failures resolve as materialized error results; an invisible tool + * reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen + * snapshot final observers receive. Cancellation * arriving after entry and before final result materialization skips a * not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a * successful started outcome with `ABORTED`; already-started work is still @@ -826,6 +841,8 @@ export class ToolRegistry extends Service { const agent = exec.agent const parent = exec.parent const signal = exec.signal + const definition = this.get(name, agent) + const finalizeContent = definition?.finalizeContent?.bind(definition) const base = { token, callId, @@ -844,6 +861,7 @@ export class ToolRegistry extends Service { } const execution: MutableToolRunContext = { ...base, arguments: deepFreeze(detached) } this.deferredContexts.set(execution, deferredContexts) + this.contentFinalizers.set(execution, finalizeContent) this.cancellationStates.set(execution, { callerSignal: signal, bodyInvoked: false, @@ -851,6 +869,7 @@ export class ToolRegistry extends Service { return { kind: 'ready', exec: execution } } catch (error: unknown) { const execution: MutableToolRunContext = { ...base, arguments: undefined } + this.contentFinalizers.set(execution, finalizeContent) return { kind: 'final-result', exec: execution, result: toolErrorResult(error) } } } @@ -1008,7 +1027,8 @@ export class ToolRegistry extends Service { } /** - * Run ordered post-execute, then materialize and notify the final outcome. + * Run ordered post-execute, then apply definition-owned content finalization, + * materialize, and notify the final outcome. * @param exec - the prepared execution. * @param result - dispatch/pre result that still needs post-execute. * @returns the materialized final result. @@ -1029,7 +1049,8 @@ export class ToolRegistry extends Service { } /** - * Materialize and notify a final result that must bypass post-execute. + * Apply definition-owned content finalization, then materialize and notify a + * final result that must bypass post-execute. * @param exec - the prepared execution. * @param result - final result. * @returns the materialized final result. @@ -1038,7 +1059,7 @@ export class ToolRegistry extends Service { private finishScheduledExecution(exec: ToolRunContext, result: ToolExecutionResult): ToolExecutionResult { let finalResult: ToolExecutionResult try { - finalResult = this.materializeFinalResult(result) + finalResult = this.materializeFinalResult(this.applyFinalContent(exec, result)) } catch (error: unknown) { finalResult = this.materializeFinalResult(toolErrorResult(error)) } @@ -1046,6 +1067,14 @@ export class ToolRegistry extends Service { return finalResult } + /** Apply the snapshotted tool-owned content transform without exposing other result fields. */ + private applyFinalContent(exec: ToolRunContext, result: ToolExecutionResult): ToolExecutionResult { + const finalizeContent = this.contentFinalizers.get(exec) + if (finalizeContent === undefined) return result + const content = finalizeContent(exec, result) + return content === undefined ? result : { ...result, content } + } + /** Notify observers without exposing a mutation or error channel into the outcome. */ private notifyResult(exec: ToolExecution, result: ToolExecutionResult): void { // Freeze the registry's live object before observers receive its readonly diff --git a/packages/core/tools/src/schema.ts b/packages/core/tools/src/schema.ts index f2b62669b1..c10075a6c7 100644 --- a/packages/core/tools/src/schema.ts +++ b/packages/core/tools/src/schema.ts @@ -1,7 +1,15 @@ /** Typed tool-parameter DSL with argument inference and JSON Schema output. @module dsh-tools/schema */ import { assertNever, HarnessError } from '@deepseek-ai/dsh-llm' -import type { ToolDefinition, ToolExecuteReturn, ToolRunContext, ToolResult } from './index.ts' +import type { ContentBlock } from '@deepseek-ai/dsh-llm' +import type { + ToolDefinition, + ToolExecuteReturn, + ToolExecution, + ToolExecutionResult, + ToolRunContext, + ToolResult, +} from './index.ts' import type { ToolCallView, ToolResultView } from './presentation.ts' // --------------------------------------------------------------------------- @@ -294,6 +302,15 @@ export interface DefineToolOptions { * presentation payload (see {@link ToolExecuteReturn}). */ execute(args: InferArgs, exec: ToolRunContext): Promise + /** + * Optional last-mile content transform for every normalized outcome. Unlike + * `execute`, arguments remain `unknown` because invalid-input failures also + * reach this callback. See {@link ToolDefinition.finalizeContent}. + * @param exec - immutable execution identity and arguments. + * @param result - complete normalized outcome before materialization. + * @returns replacement content, or `undefined` to preserve it. + */ + finalizeContent?(exec: Readonly, result: Readonly): ContentBlock[] | undefined /** * Optional: how to present the PENDING state of one call in a UI (an editor * tool-call card, a CLI log line). `args` is the typed, schema-validated @@ -317,7 +334,7 @@ export interface DefineToolOptions { * inferred from its per-property schema. Raw JSON-Schema definitions remain * valid inputs to {@link ToolRegistry.register}; this helper is authoring sugar. * @param options - the tool's name, description, typed parameter schema, - * execute body, and optional presenters. + * execute body, and optional finalization/presentation callbacks. * @returns a registry-ready definition with strict execution validation and * soft presenter and classifier validation for replay compatibility. */ @@ -326,6 +343,8 @@ export function defineTool(options: DefineToolOptions): // eslint-disable-next-line @typescript-eslint/unbound-method const userExecute = options.execute // eslint-disable-next-line @typescript-eslint/unbound-method + const userFinalizeContent = options.finalizeContent + // eslint-disable-next-line @typescript-eslint/unbound-method const userPresentCall = options.presentCall // eslint-disable-next-line @typescript-eslint/unbound-method const userPresentResult = options.presentResult @@ -349,6 +368,9 @@ export function defineTool(options: DefineToolOptions): return userExecute(args as InferArgs, exec) }, } + if (userFinalizeContent) { + tool.finalizeContent = (exec, result) => userFinalizeContent(exec, result) + } // Presentation is display-only and may run on REPLAY of arbitrary logged args // (possibly from an older schema), so it must never throw: validate softly and // fall back to `undefined` (a generic UI presentation) on any mismatch, rather diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index 3eb1152a92..bddefaba41 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -47,22 +47,24 @@ describe('ToolRegistry', () => { expect(assembly.tools.map(t => t.name)).toEqual(['echo']) }) - it('schemas() drops the UI presentation callbacks — they must never reach the model', async () => { + it('schemas() drops host callbacks — they must never reach the model', async () => { const ctx = await setup() - // A tool that declares presentCall/presentResult (functions). schemas() feeds - // the system-prompt assembly → the model request, so those callbacks (and - // `execute`) must be stripped: a function in the JSON tool schema would - // corrupt the request. schemas() is an explicit allowlist, so it can't leak. + // A tool that declares finalization and presentation functions. schemas() + // feeds the system-prompt assembly → the model request, so every callback + // (including `execute`) must be stripped: a function in the JSON tool schema + // would corrupt the request. schemas() is an explicit allowlist, so it can't leak. ctx.tools.register(defineTool({ name: 'present', description: 'has presenters', parameters: { x: { type: 'string', required: true } }, async execute() { return [] }, + finalizeContent: (_exec, result) => result.content, presentCall: args => ({ card: 'generic', title: args.x }), presentResult: (args, result) => ({ card: 'generic', title: args.x, content: result.content }), })) const schema = ctx.tools.schemas()[0] as unknown as Record expect(Object.keys(schema).sort()).toEqual(['description', 'name', 'parameters']) + expect(schema.finalizeContent).toBeUndefined() expect(schema.presentCall).toBeUndefined() expect(schema.presentResult).toBeUndefined() expect(schema.execute).toBeUndefined() @@ -388,6 +390,33 @@ describe('ToolRegistry', () => { expect(result.content[0]).toMatchObject({ text: 'output rejected: try again' }) }) + it('runs the snapshotted final content transform after outer pipeline normalization', async () => { + const ctx = await setup() + const dispose = ctx.tools.register(defineTool({ + name: 'bounded', + description: 'bounded result', + parameters: {}, + async execute() { return [{ type: 'text', text: 'body' }] }, + finalizeContent(exec, result) { + expect(exec.name).toBe('bounded') + expect(result.isError).toBe(true) + return [{ type: 'text', text: 'bounded failure' }] + }, + })) + ctx.on('tools/pre-execute', async () => { + dispose() + throw new HarnessError('policy failed', 'POLICY_FAILED') + }) + + const result = await ctx.tools.execute({ signal: testToolSignal, callId: CallId('bounded'), name: 'bounded', arguments: {} }) + + expect(result).toEqual({ + content: [{ type: 'text', text: 'bounded failure' }], + isError: true, + error: { name: 'HarnessError', code: 'POLICY_FAILED' }, + }) + }) + it('a block decision can ALSO attach additionalContexts', async () => { const ctx = await setup() ctx.tools.register(echoTool) diff --git a/packages/pty/pty/README.md b/packages/pty/pty/README.md index 798991d5fd..77bc23e546 100644 --- a/packages/pty/pty/README.md +++ b/packages/pty/pty/README.md @@ -7,7 +7,7 @@ Owner-scoped persistent PTY seam. `PtyService` registers as `ctx.pty`, mints opa - Backends register one stable `type` and return an unpublished `PtyBackendSession`; failed or cancelled setup must clean partial resources, and a failed cleanup rejects with `PtyBackendCleanupError` so the registry can retain it across cancellation. - Spawn cancellation preserves the caller's exact abort reason. Service disposal and owner loss remain distinct machine-routable failures after backend setup. - Owner and service disposal abort unpublished setup through a service-owned signal and await backend settlement plus rollback before returning. -- A service rollback or backend-reported startup cleanup failure rejects the disposing lifecycle instead of claiming quiescence; the spawn caller still receives its exact cancellation reason. +- A rollback-close or backend-reported startup cleanup failure rejects the disposing lifecycle instead of claiming quiescence. Caller-triggered cancellation still receives its exact reason; lifecycle-triggered rollback failure also rejects the pending spawn. - A backend cleanup failure that follows caller cancellation remains owner activity until owner or service disposal consumes and reports it, so lifecycle policy cannot mistake failed cleanup for quiescence. - `hasOwnerActivity(owner)` spans unpublished setup through final close, so lifecycle policy can fence the exact owner without a publication race. - A successful spawn publishes one `PtySessionId`. The optional `name` is owner-local display metadata, never authority. diff --git a/packages/pty/pty/src/index.ts b/packages/pty/pty/src/index.ts index c7896d5113..f4f5ba64e1 100644 --- a/packages/pty/pty/src/index.ts +++ b/packages/pty/pty/src/index.ts @@ -213,7 +213,7 @@ export class PtyService extends Service { } catch (cancellation: unknown) { failure = cancellation } - if (rollbackFailure !== undefined) { + if (rollbackFailure !== undefined && signal?.aborted !== true) { throw new AggregateError([failure, rollbackFailure.error], 'PTY spawn and rollback both failed') } throw failure diff --git a/packages/pty/pty/tests/service.spec.ts b/packages/pty/pty/tests/service.spec.ts index bca131011d..cab879b1a9 100644 --- a/packages/pty/pty/tests/service.spec.ts +++ b/packages/pty/pty/tests/service.spec.ts @@ -233,6 +233,29 @@ describe('PtyService ownership and lifecycle', () => { expect(ctx.agents.get(owner.id)).toBe(owner) }) + it('preserves caller cancellation when unpublished rollback fails', async () => { + const ctx = await harness() + const gate = Promise.withResolvers() + const session = new StubSession() + session.rejectClose = true + ctx.pty.registerBackend({ type: 'slow', spawn: () => gate.promise }) + const owner = stubAgent(ctx, 'owner') + ctx.agents.register(owner) + const controller = new AbortController() + const reason = new Error('cancelled by caller') + + const pending = ctx.pty.spawn(owner, { type: 'slow' }, controller.signal) + controller.abort(reason) + gate.resolve(session) + + await expect(pending).rejects.toBe(reason) + expect(ctx.pty.hasOwnerActivity(owner)).toBe(true) + const internal = ctx.pty as unknown as { disposeAll(): Promise } + await expect(internal.disposeAll()).rejects.toThrow('failed to clean up PTY lifecycle') + expect(ctx.pty.hasOwnerActivity(owner)).toBe(false) + expect(session.closed).toEqual(['PTY spawn rolled back']) + }) + it('preserves caller cancellation when a backend rejects in response to it', async () => { const ctx = await harness() const started = Promise.withResolvers() diff --git a/packages/pty/tool-pty/README.md b/packages/pty/tool-pty/README.md index a3167ab552..d65d4c0106 100644 --- a/packages/pty/tool-pty/README.md +++ b/packages/pty/tool-pty/README.md @@ -11,7 +11,7 @@ Six model-facing tools over `ctx.pty`: `terminal_open`, `terminal_send`, `termin | `enableRunInBackground` | `true` | expose and accept `run_in_background`; false omits the schema field and rejects a forced undeclared argument | | `maxResultBytes` | `262144` | UTF-8 cap (minimum `64`) for each complete terminal result or PTY task output after wait, session, pagination, truncation, and task-status metadata | -Both values are validated at load. The minimum result cap keeps every registry-issued session or task id visible in its creation acknowledgement. When a result exceeds `maxResultBytes`, rendering reserves space for control metadata and a truncation marker when they fit; cuts preserve UTF-8 boundaries. An outer `tools/post-execute` wrapper applies the same cap after a terminal pre-execute denial or single-text post-execute replacement/block; a structured multi-block policy result retains its shape. +Both values are validated at load. The minimum result cap keeps every registry-issued session or task id visible in its creation acknowledgement. When a result exceeds `maxResultBytes`, rendering reserves space for control metadata and a truncation marker when they fit; cuts preserve UTF-8 boundaries. Each terminal definition's final-content callback applies the same cap after normalized pre-, around-, and post-execute policy failures, denials, short-circuits, replacements, or blocks; a structured multi-block policy result retains its shape. ## Model Experience @@ -53,7 +53,7 @@ Prefix-stable while tool visibility and definitions are unchanged. #### What the model sees -Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Every terminal-owned or policy-produced single-text result is capped by `maxResultBytes` after normalized errors, denials, replacements, blocks, and generic task status text. Structured multi-block policy results retain their shape. Results remain in session history until compaction; incremental task reads do not repeat consumed output. +Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Every terminal-owned or policy-produced single-text result is capped by `maxResultBytes` after normalized tool or pipeline errors, denials, short-circuits, replacements, blocks, and generic task status text. Structured multi-block policy results retain their shape. Results remain in session history until compaction; incremental task reads do not repeat consumed output. #### Token effect diff --git a/packages/pty/tool-pty/src/index.ts b/packages/pty/tool-pty/src/index.ts index 5b1e3b7e9d..d99a56a793 100644 --- a/packages/pty/tool-pty/src/index.ts +++ b/packages/pty/tool-pty/src/index.ts @@ -12,7 +12,7 @@ import { PtySessionId } from '@deepseek-ai/dsh-pty' import type { PtySendResult, PtySessionId as PtySessionIdType, PtySignal } from '@deepseek-ai/dsh-pty' import type {} from '@deepseek-ai/dsh-tasks' import { defineTool } from '@deepseek-ai/dsh-tools' -import type { PostToolDecision, ToolExecutionResult } from '@deepseek-ai/dsh-tools' +import type { ToolDefinition, ToolExecutionResult } from '@deepseek-ai/dsh-tools' import { boundTerminalText, renderList, renderRead, renderSend, renderSendRead, renderSpawn } from './render.ts' declare module '@deepseek-ai/dsh-tasks' { @@ -31,15 +31,6 @@ export const DEFAULT_MAX_RESULT_BYTES = 256 * 1024 /** Smallest cap that preserves every counter-backed PTY and task id in its creation acknowledgement. */ export const MIN_MAX_RESULT_BYTES = 64 -const TOOL_NAMES = new Set([ - 'terminal_open', - 'terminal_send', - 'terminal_read', - 'terminal_signal', - 'terminal_close', - 'terminal_list', -]) - /** Model-facing terminal tool configuration. */ export interface Config { /** Expose `run_in_background` and accept background sends (default true). */ @@ -114,17 +105,10 @@ export function apply(ctx: Context, config: Config = {}): void { if (!Number.isSafeInteger(maxResultBytes) || maxResultBytes < MIN_MAX_RESULT_BYTES) { throw new Error(`tool-pty: maxResultBytes must be a safe integer of at least ${MIN_MAX_RESULT_BYTES}`) } - ctx.on('tools/post-execute', async (exec, result, next): Promise => { - const decision = await next() - if (!TOOL_NAMES.has(exec.name)) return decision - const content = decision.kind === 'block' ? decision.feedback : decision.content ?? result.content - const raw = rawContentText(content) - if (raw === undefined) return decision - const bounded = textResult(raw, maxResultBytes) - return decision.kind === 'block' - ? { ...decision, feedback: bounded } - : { ...decision, content: bounded } - }, { prepend: true }) + const finalizeContent: NonNullable = (_exec, result) => { + const raw = rawContentText(result.content) + return raw === undefined ? undefined : textResult(raw, maxResultBytes) + } ctx.systemPrompt.section({ name: 'tool:pty', order: 106, @@ -139,6 +123,7 @@ export function apply(ctx: Context, config: Config = {}): void { name: { type: 'string', description: 'Optional owner-local display name such as "main" or "gdb".' }, cwd: { type: 'string', description: 'Initial working directory. Defaults to the deployment workspace root.' }, }, + finalizeContent, async execute(args: SpawnArgs, exec) { if (args.type.length === 0) throw new Error('type must be a non-empty string') const result = await ctx.pty.spawn(requireAgent(exec.agent), { @@ -166,6 +151,7 @@ export function apply(ctx: Context, config: Config = {}): void { ? { run_in_background: { type: 'boolean' as const, description: 'Return a task id immediately; collect with task_output or stop with task_kill.' } } : {}, }, + finalizeContent, async execute(args: SendArgs, exec): Promise { const owner = requireAgent(exec.agent) const id = sessionId(args) @@ -224,6 +210,7 @@ export function apply(ctx: Context, config: Config = {}): void { offset: { type: 'number', description: 'Newest-relative line offset (default 0).' }, count: { type: 'number', description: 'Requested line count (default 500; backend caps apply).' }, }, + finalizeContent, execute(args: ReadArgs, exec) { const result = ctx.pty.read(requireAgent(exec.agent), sessionId(args), { ...args.offset !== undefined ? { offset: args.offset } : {}, @@ -241,6 +228,7 @@ export function apply(ctx: Context, config: Config = {}): void { sessionId: { type: 'string', required: true, description: 'Terminal session id.' }, signal: { type: 'string', required: true, enum: ['SIGINT', 'SIGTERM', 'SIGKILL', 'SIGTSTP', 'SIGHUP'], description: 'Signal to deliver. Shell-targeted SIGKILL is rejected; use terminal_close.' }, }, + finalizeContent, async execute(args: SignalArgs, exec) { const result = await ctx.pty.signal(requireAgent(exec.agent), sessionId(args), args.signal) return textResult(`delivered ${args.signal} to foreground process group ${result.targetPgid}`, maxResultBytes) @@ -254,6 +242,7 @@ export function apply(ctx: Context, config: Config = {}): void { parameters: { sessionId: { type: 'string', required: true, description: 'Terminal session id.' }, }, + finalizeContent, async execute(args: SessionArgs, exec) { const id = sessionId(args) const closed = await ctx.pty.kill(requireAgent(exec.agent), id) @@ -266,6 +255,7 @@ export function apply(ctx: Context, config: Config = {}): void { name: 'terminal_list', description: 'List persistent terminal sessions owned by the current agent.', parameters: {}, + finalizeContent, execute(_args: Record, exec) { return Promise.resolve(textResult(renderList(ctx.pty.list(requireAgent(exec.agent)), maxResultBytes), maxResultBytes)) }, diff --git a/packages/pty/tool-pty/tests/tools.spec.ts b/packages/pty/tool-pty/tests/tools.spec.ts index ebc2503a5a..5f61dafb64 100644 --- a/packages/pty/tool-pty/tests/tools.spec.ts +++ b/packages/pty/tool-pty/tests/tools.spec.ts @@ -217,11 +217,17 @@ describe('tool-pty foreground surface', () => { expect(Buffer.byteLength(text(background))).toBeLessThanOrEqual(64) }) - it('bounds terminal results after pre- and post-execute policy', async () => { + it('bounds terminal results after policy decisions and pipeline failures', async () => { const { ctx, agent } = await setup(false, { maxResultBytes: 64 }) - ctx.on('tools/pre-execute', async (exec, next) => exec.name === 'terminal_list' - ? { kind: 'deny', reason: 'd'.repeat(1_000) } - : next()) + ctx.on('tools/pre-execute', async (exec, next) => { + if (exec.name === 'terminal_list') return { kind: 'deny', reason: 'd'.repeat(1_000) } + if (exec.name === 'terminal_signal') throw new Error(`pre failed: ${'p'.repeat(1_000)}`) + return next() + }) + ctx.on('tools/execute', async (exec, next) => { + if (exec.name === 'terminal_close') throw new Error(`around failed: ${'e'.repeat(1_000)}`) + return next() + }) ctx.on('tools/post-execute', async (exec, _result, next) => { if (exec.name === 'terminal_open') { return { kind: 'accept', content: [{ type: 'text', text: 'a'.repeat(1_000) }] } @@ -229,6 +235,7 @@ describe('tool-pty foreground surface', () => { if (exec.name === 'terminal_read') { return { kind: 'block', feedback: [{ type: 'text', text: 'b'.repeat(1_000) }] } } + if (exec.name === 'terminal_send') throw new Error(`post failed: ${'o'.repeat(1_000)}`) return next() }) @@ -246,6 +253,17 @@ describe('tool-pty foreground surface', () => { expect(blocked.isError).toBe(true) expect(Buffer.byteLength(text(blocked))).toBeLessThanOrEqual(64) expect(text(blocked)).toContain('[output truncated]') + + const failures = [ + await call(ctx, 'terminal_signal', { sessionId: 'pty-1', signal: 'SIGINT' }, agent), + await call(ctx, 'terminal_close', { sessionId: 'pty-1' }, agent), + await call(ctx, 'terminal_send', { sessionId: 'pty-1', text: 'work' }, agent), + ] + for (const failure of failures) { + expect(failure.isError).toBe(true) + expect(Buffer.byteLength(text(failure))).toBeLessThanOrEqual(64) + expect(text(failure)).toContain('[output truncated]') + } }) it('leaves a structured around-dispatch replacement unchanged', async () => { diff --git a/packages/tasks/tool-tasks/README.md b/packages/tasks/tool-tasks/README.md index ea3625093b..4072a84205 100644 --- a/packages/tasks/tool-tasks/README.md +++ b/packages/tasks/tool-tasks/README.md @@ -10,7 +10,7 @@ The model-facing control surface for `ctx.tasks`: three kind-independent tools, All three use generic ACP cards: `read` for output and list, `execute` for kill. -When a producer supplies `outputLimitBytes`, `task_output`, terminal `task_kill`, and completion notices cap the complete UTF-8 result after adding status or notice text. Reads retain the output tail and control suffix when they fit; a bounded completion notice instead reserves `background task ` and the `task_output` collection instruction before spending remaining bytes on its variable kind, label, status, and detail. An outer pre/post-execute pair captures the caller-visible task before policy and applies its producer cap to single-text denials, around-dispatch short-circuits, normalized task-control failures, replacements, and blocks; structured multi-block policy results retain their shape. An existing producer truncation marker is reused rather than duplicated. Producers that omit the field retain the existing unbounded control-surface behavior. +When a producer supplies `outputLimitBytes`, `task_output`, terminal `task_kill`, and completion notices cap the complete UTF-8 result after adding status or notice text. Reads retain the output tail and control suffix when they fit; a bounded completion notice instead reserves `background task ` and the `task_output` collection instruction before spending remaining bytes on its variable kind, label, status, and detail. A prepended pre-execute listener captures the caller-visible task before policy, and each task-control definition's final-content callback applies its producer cap to single-text denials, short-circuits, normalized tool or pipeline failures, replacements, and blocks; structured multi-block policy results retain their shape. An existing producer truncation marker is reused rather than duplicated. Producers that omit the field retain the existing unbounded control-surface behavior. ## Completion notices diff --git a/packages/tasks/tool-tasks/src/index.ts b/packages/tasks/tool-tasks/src/index.ts index fb40a2eeae..40e6aaf7cb 100644 --- a/packages/tasks/tool-tasks/src/index.ts +++ b/packages/tasks/tool-tasks/src/index.ts @@ -11,7 +11,7 @@ import z from 'schemastery' import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { TextRetainer } from '@deepseek-ai/dsh-retention' import { defineTool } from '@deepseek-ai/dsh-tools' -import type { GenericCallView, PostToolDecision, ToolExecution } from '@deepseek-ai/dsh-tools' +import type { GenericCallView, ToolDefinition, ToolExecution } from '@deepseek-ai/dsh-tools' import { TaskId } from '@deepseek-ai/dsh-tasks' import type { TaskSnapshot } from '@deepseek-ai/dsh-tasks' import type {} from '@deepseek-ai/dsh-system-prompt' @@ -128,18 +128,11 @@ export function apply(ctx: Context, config: Config): void { if (maxBytes !== undefined) outputLimits.set(exec, maxBytes) return next() }, { prepend: true }) - ctx.on('tools/post-execute', async (exec, result, next): Promise => { - const decision = await next() - const maxBytes = outputLimits.get(exec) + const finalizeTaskContent: NonNullable = (exec, result) => { + const maxBytes = outputLimits.get(exec) ?? visibleOutputLimit(ctx, exec) outputLimits.delete(exec) - if (maxBytes === undefined) return decision - const content = decision.kind === 'block' ? decision.feedback : decision.content ?? result.content - const bounded = boundSingleText(content, maxBytes) - if (bounded === undefined) return decision - return decision.kind === 'block' - ? { ...decision, feedback: bounded } - : { ...decision, content: bounded } - }, { prepend: true }) + return maxBytes === undefined ? undefined : boundSingleText(result.content, maxBytes) + } // Producers may start work only while a control surface is attached. ctx.tasks.attachSurface('tool-tasks') @@ -181,6 +174,7 @@ export function apply(ctx: Context, config: Config): void { wait: { type: 'boolean', description: 'Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task alive.' }, timeout_ms: { type: 'number', description: 'Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum.' }, }, + finalizeContent: finalizeTaskContent, async execute(args, exec) { const id = validateTaskId(args.task_id) if (args.wait === true) { @@ -224,6 +218,7 @@ export function apply(ctx: Context, config: Config): void { task_id: { type: 'string', required: true, description: 'Task id returned by the tool that started the background work.' }, reason: { type: 'string', description: 'Optional short reason, recorded in the log and forwarded to the task.' }, }, + finalizeContent: finalizeTaskContent, execute(args, exec) { const id = validateTaskId(args.task_id) const snapshot = ctx.tasks.get(id, exec.agent) diff --git a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts index b9e8832ea3..eadd4eea11 100644 --- a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts +++ b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts @@ -162,19 +162,27 @@ describe('task_output', () => { expect(text(result)).toContain('[result truncated]') }) - it('captures producer limits before pre- and around-execute policy', async () => { + it('bounds pre-, around-, and post-execute policy outcomes and failures', async () => { const { ctx } = await setup() - ctx.tasks.start(producer({ outputLimitBytes: 64 }).spec) - ctx.tasks.start(producer({ outputLimitBytes: 64 }).spec) + for (let index = 0; index < 5; index += 1) { + ctx.tasks.start(producer({ outputLimitBytes: 64 }).spec) + } ctx.on('tools/pre-execute', async (exec, next) => { const taskId = (exec.arguments as { task_id?: unknown }).task_id - return taskId === 'bash-1' ? { kind: 'deny', reason: 'd'.repeat(1_000) } : next() + if (taskId === 'bash-1') return { kind: 'deny', reason: 'd'.repeat(1_000) } + if (taskId === 'bash-3') throw new Error(`pre failed: ${'p'.repeat(1_000)}`) + return next() }) ctx.on('tools/execute', async (exec, next) => { const taskId = (exec.arguments as { task_id?: unknown }).task_id - return taskId === 'bash-2' - ? { content: [{ type: 'text', text: 'a'.repeat(1_000) }], isError: false } - : next() + if (taskId === 'bash-2') return { content: [{ type: 'text', text: 'a'.repeat(1_000) }], isError: false } + if (taskId === 'bash-4') throw new Error(`around failed: ${'e'.repeat(1_000)}`) + return next() + }) + ctx.on('tools/post-execute', async (exec, _result, next) => { + const taskId = (exec.arguments as { task_id?: unknown }).task_id + if (taskId === 'bash-5') throw new Error(`post failed: ${'o'.repeat(1_000)}`) + return next() }) const denied = await call(ctx, 'task_output', { task_id: 'bash-1' }) @@ -186,6 +194,17 @@ describe('task_output', () => { expect(shortCircuited.isError).toBe(false) expect(Buffer.byteLength(text(shortCircuited))).toBeLessThanOrEqual(64) expect(text(shortCircuited)).toContain('[result truncated]') + + const failures = [ + await call(ctx, 'task_output', { task_id: 'bash-3' }), + await call(ctx, 'task_output', { task_id: 'bash-4' }), + await call(ctx, 'task_output', { task_id: 'bash-5' }), + ] + for (const failure of failures) { + expect(failure.isError).toBe(true) + expect(Buffer.byteLength(text(failure))).toBeLessThanOrEqual(64) + expect(text(failure)).toContain('[result truncated]') + } }) it('wait: true blocks until settlement and reports the terminal state', async () => { diff --git a/scripts/gen-doc-graphs.ts b/scripts/gen-doc-graphs.ts index c93f70cf81..b01a1514d5 100644 --- a/scripts/gen-doc-graphs.ts +++ b/scripts/gen-doc-graphs.ts @@ -971,7 +971,7 @@ function renderToolPipeline(): string { const maintenance = 'curated Mermaid flow; exact tool schemas and event signatures live in generated catalogs' return [ ...generatedHeader('Tool Execution Pipeline'), - 'This graph shows where policy, hooks, sandboxing, filesystem guards, result rewriting, final-outcome observation, and UI rendering fit without changing the loop. The transformable extension points are the `tools/pre-execute`, `tools/execute`, and `tools/post-execute` waterfalls; monotonic guards and `tools/result` are the owner-enforced boundaries around them.', + 'This graph shows where policy, hooks, sandboxing, filesystem guards, result rewriting, final-outcome observation, and UI rendering fit without changing the loop. The transformable extension points are the `tools/pre-execute`, `tools/execute`, and `tools/post-execute` waterfalls; monotonic guards, definition-owned `finalizeContent`, and `tools/result` are the owner-enforced boundaries around them.', '', '```mermaid', 'flowchart TD', @@ -987,6 +987,8 @@ function renderToolPipeline(): string { ` fsGate["${mermaidCode('fs/write-intent')} or ${mermaidCode('fs/edit-intent')}
    tool-fs mutations only"]`, ` owned["Tool-owned session events
    ${mermaidCode('todo/write')}, ${mermaidCode('fs/observed')}, ${mermaidCode('hook/invoked')}, ${mermaidCode('hook/result')}, ${mermaidCode('tool/code-dispatch')}"]`, ` post["${mermaidCode('tools/post-execute')} waterfall
    accept, block, replace, add context"]`, + ' normalized["Registry outer normalization
    pipeline throws become isError"]', + ' finalize["ToolDefinition.finalizeContent
    last content-only invariant"]', ` final["${mermaidCode('tools/result')} synchronous notification
    frozen authoritative outcome"]`, ' context["Active-batch additionalContexts FIFO
    context/message after recorded tool results"]', ` toolResult["Session event: ${mermaidCode('tool/result')}
    single model-facing outcome"]`, @@ -998,25 +1000,32 @@ function renderToolPipeline(): string { ' pre -->|allow| guards', ' guards -->|allow| around', ' guards -->|deny| denied', + ' guards -.->|throw| normalized', ' around --> toolBody', ' pre -->|deny| denied', ' pre -->|ask| approval', ' approval -->|allowed-once| guards', ' approval -->|rejected, cancelled, unavailable| denied', + ' approval -.->|throw| normalized', ' denied --> post', + ' pre -.->|throw| normalized', ' toolBody --> fsGate', ' fsGate --> toolBody', ' toolBody --> owned', ' toolBody --> around', ' around --> post', - ' post --> final', + ' around -.->|wrapper throws| normalized', + ' post -.->|throw| normalized', + ' post --> finalize', + ' normalized --> finalize', + ' finalize --> final', ' final --> toolResult', ' toolResult --> presentResult', ' toolResult --> allResults', ' allResults --> context', '```', '', - 'Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`, while `tools/result` observes the immutable outcome after transforms, lossless-JSON validation, and outer error normalization. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, surface denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency.', + 'Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The visible definition\'s snapshotted `finalizeContent` callback then enforces a synchronous content-only invariant across ordinary decisions and normalized pipeline failures before `tools/result` observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, surface denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency.', '', ...maintenanceFooter(maintenance), ].join('\n') From 4afcb5c3c99da7569adbec94868bc3a101c24510 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 03:04:43 +0800 Subject: [PATCH 137/368] fix(code-runtime): capture worker JSON intrinsics --- .../code-runtime-worker/src/output-json.ts | 85 ++++++-- .../code-runtime-worker/src/worker-json.ts | 182 ++++++++++++------ .../tests/output-json.spec.ts | 38 ++++ .../code-runtime-worker/tests/runtime.spec.ts | 35 ++++ 4 files changed, 265 insertions(+), 75 deletions(-) diff --git a/packages/code-runtime/code-runtime-worker/src/output-json.ts b/packages/code-runtime/code-runtime-worker/src/output-json.ts index de7ed6f301..cc668e5d99 100644 --- a/packages/code-runtime/code-runtime-worker/src/output-json.ts +++ b/packages/code-runtime/code-runtime-worker/src/output-json.ts @@ -2,17 +2,62 @@ import type { CodeJsonValue } from '@deepseek-ai/dsh-code-runtime' -/** Control characters with a two-byte short JSON escape instead of `\u00XX`. */ -const SHORT_ESCAPE_CODES = new Set([0x08, 0x09, 0x0a, 0x0c, 0x0d]) +type IntrinsicCallable = (this: unknown, ...args: unknown[]) => unknown + +const intrinsicReflectApply = Reflect.apply as ( + target: IntrinsicCallable, + thisArgument: unknown, + argumentsList: readonly unknown[], +) => unknown +const intrinsicArrayIsArray = Array.isArray +const IntrinsicBuffer = Buffer +const intrinsicBufferByteLength = Reflect.get(Buffer, 'byteLength') as IntrinsicCallable +const intrinsicObjectDefineProperty = Object.defineProperty +const intrinsicObjectKeys = Object.keys +const intrinsicString = String +const intrinsicStringCharCodeAt = Reflect.get(String.prototype, 'charCodeAt') as IntrinsicCallable +const intrinsicStringCodePointAt = Reflect.get(String.prototype, 'codePointAt') as IntrinsicCallable +const intrinsicStringSlice = Reflect.get(String.prototype, 'slice') as IntrinsicCallable + +/** UTF-8 byte length through the module-captured Node intrinsic. */ +function byteLength(text: string): number { + return intrinsicReflectApply(intrinsicBufferByteLength, IntrinsicBuffer, [text, 'utf8']) as number +} + +/** Append without consulting a model-mutated `Array.prototype`. */ +function append(target: T[], value: T): void { + intrinsicObjectDefineProperty(target, target.length, { + value, + enumerable: true, + configurable: true, + writable: true, + }) +} + +/** Pop without consulting a model-mutated `Array.prototype`. */ +function takeLast(target: T[]): T | undefined { + if (target.length === 0) return undefined + const index = target.length - 1 + const value = target[index] + intrinsicObjectDefineProperty(target, 'length', { value: index }) + return value +} + +/** One code-point-aligned character from a string. */ +function characterAt(text: string, index: number): string { + const codePoint = intrinsicReflectApply(intrinsicStringCodePointAt, text, [index]) as number + const width = codePoint > 0xffff ? 2 : 1 + return intrinsicReflectApply(intrinsicStringSlice, text, [index, index + width]) as string +} /** Serialized bytes contributed by one complete Unicode code point inside JSON quotes. */ function serializedCharacterBytes(character: string): number { if (character.length === 2) return 4 if (character === '"' || character === '\\') return 2 - const code = character.charCodeAt(0) + const code = intrinsicReflectApply(intrinsicStringCharCodeAt, character, [0]) as number if (code >= 0xd800 && code <= 0xdfff) return 6 - if (code < 0x20) return SHORT_ESCAPE_CODES.has(code) ? 2 : 6 - return Buffer.byteLength(character, 'utf8') + if (code < 0x20) return code === 0x08 || code === 0x09 || code === 0x0a || code === 0x0c || code === 0x0d ? 2 : 6 + return byteLength(character) } /** @@ -24,9 +69,11 @@ function serializedCharacterBytes(character: string): number { export function jsonStringBytesUpTo(text: string, maxBytes: number): number | undefined { if (maxBytes < 2) return undefined let bytes = 2 - for (const character of text) { + for (let index = 0; index < text.length;) { + const character = characterAt(text, index) bytes += serializedCharacterBytes(character) if (bytes > maxBytes) return undefined + index += character.length } return bytes } @@ -49,7 +96,7 @@ export function jsonValueBytesUpTo(value: CodeJsonValue, maxBytes: number): numb return bytes <= maxBytes } const tasks: Task[] = [{ kind: 'value', value }] - for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + for (let task = takeLast(tasks); task !== undefined; task = takeLast(tasks)) { if (task.kind === 'value') { const current = task.value if (current === null) { @@ -59,16 +106,16 @@ export function jsonValueBytesUpTo(value: CodeJsonValue, maxBytes: number): numb if (stringBytes === undefined) return undefined bytes += stringBytes } else if (typeof current === 'number') { - if (!add(Buffer.byteLength(String(current), 'utf8'))) return undefined + if (!add(byteLength(intrinsicString(current)))) return undefined } else if (typeof current === 'boolean') { if (!add(current ? 4 : 5)) return undefined - } else if (Array.isArray(current)) { + } else if (intrinsicArrayIsArray(current)) { if (!add(2)) return undefined - if (current.length > 0) tasks.push({ kind: 'array', value: current, index: 0 }) + if (current.length > 0) append(tasks, { kind: 'array', value: current, index: 0 }) } else { if (!add(2)) return undefined - const keys = Object.keys(current) - if (keys.length > 0) tasks.push({ kind: 'object', value: current, keys, index: 0 }) + const keys = intrinsicObjectKeys(current) + if (keys.length > 0) append(tasks, { kind: 'object', value: current, keys, index: 0 }) } continue } @@ -77,8 +124,8 @@ export function jsonValueBytesUpTo(value: CodeJsonValue, maxBytes: number): numb if (task.kind === 'array') { const item = task.value[task.index] if (item === undefined) return undefined - if (task.index + 1 < task.value.length) tasks.push({ ...task, index: task.index + 1 }) - tasks.push({ kind: 'value', value: item }) + if (task.index + 1 < task.value.length) append(tasks, { ...task, index: task.index + 1 }) + append(tasks, { kind: 'value', value: item }) continue } @@ -90,8 +137,8 @@ export function jsonValueBytesUpTo(value: CodeJsonValue, maxBytes: number): numb if (!add(keyBytes + 1)) return undefined const item = task.value[key] if (item === undefined) return undefined - if (task.index + 1 < task.keys.length) tasks.push({ ...task, index: task.index + 1 }) - tasks.push({ kind: 'value', value: item }) + if (task.index + 1 < task.keys.length) append(tasks, { ...task, index: task.index + 1 }) + append(tasks, { kind: 'value', value: item }) } return bytes } @@ -108,11 +155,13 @@ export function truncateJsonStringBytes(text: string, maxBytes: number): string if (maxBytes < 2) return '' let bytes = 2 let end = 0 - for (const character of text) { + for (let index = 0; index < text.length;) { + const character = characterAt(text, index) const cost = serializedCharacterBytes(character) if (bytes + cost > maxBytes) break bytes += cost end += character.length + index += character.length } - return end === text.length ? text : text.slice(0, end) + return end === text.length ? text : intrinsicReflectApply(intrinsicStringSlice, text, [0, end]) as string } diff --git a/packages/code-runtime/code-runtime-worker/src/worker-json.ts b/packages/code-runtime/code-runtime-worker/src/worker-json.ts index 1688365e9c..ac61d4eaab 100644 --- a/packages/code-runtime/code-runtime-worker/src/worker-json.ts +++ b/packages/code-runtime/code-runtime-worker/src/worker-json.ts @@ -11,10 +11,60 @@ const intrinsicReflectApply = Reflect.get(Reflect, 'apply') as ( thisArgument: unknown, argumentsList: readonly unknown[], ) => unknown +const IntrinsicError = Error +const IntrinsicSet = Set +const intrinsicArrayIsArray = Array.isArray +const intrinsicNumberIsFinite = Number.isFinite +const intrinsicNumberIsSafeInteger = Number.isSafeInteger +const intrinsicObjectDefineProperty = Object.defineProperty +const intrinsicObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor +const intrinsicObjectGetPrototypeOf = Object.getPrototypeOf +const intrinsicObjectHasOwn = Object.hasOwn +const intrinsicObjectIs = Object.is +const intrinsicObjectKeys = Object.keys +const intrinsicObjectPropertyIsEnumerable = Reflect.get(Object.prototype, 'propertyIsEnumerable') as IntrinsicCallable +const intrinsicReflectOwnKeys = Reflect.ownKeys +const intrinsicSetAdd = Reflect.get(Set.prototype, 'add') as IntrinsicCallable +const intrinsicSetDelete = Reflect.get(Set.prototype, 'delete') as IntrinsicCallable +const intrinsicSetHas = Reflect.get(Set.prototype, 'has') as IntrinsicCallable + +/** Append without consulting a model-mutated `Array.prototype`. */ +function append(target: T[], value: T): void { + intrinsicObjectDefineProperty(target, target.length, { + value, + enumerable: true, + configurable: true, + writable: true, + }) +} + +/** Pop without consulting a model-mutated `Array.prototype`. */ +function takeLast(target: T[]): T | undefined { + if (target.length === 0) return undefined + const index = target.length - 1 + const value = target[index] + intrinsicObjectDefineProperty(target, 'length', { value: index }) + return value +} + +/** Whether one captured-intrinsic Set contains a value. */ +function setHas(target: Set, value: T): boolean { + return intrinsicReflectApply(intrinsicSetHas, target, [value]) as boolean +} + +/** Add to one captured-intrinsic Set. */ +function setAdd(target: Set, value: T): void { + intrinsicReflectApply(intrinsicSetAdd, target, [value]) +} + +/** Delete from one captured-intrinsic Set. */ +function setDelete(target: Set, value: T): void { + intrinsicReflectApply(intrinsicSetDelete, target, [value]) +} /** Whether a realm-owned intrinsic prototype is backed by its native constructor. */ function hasIntrinsicConstructor(prototype: object, name: 'Array' | 'Object'): boolean { - const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor') + const descriptor = intrinsicObjectGetOwnPropertyDescriptor(prototype, 'constructor') const constructor: unknown = descriptor?.value if (typeof constructor !== 'function') return false try { @@ -28,14 +78,14 @@ function hasIntrinsicConstructor(prototype: object, name: 'Array' | 'Object'): b /** Whether a candidate is one realm's intrinsic `Object.prototype`. */ function isIntrinsicObjectPrototype(value: object): boolean { - return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, 'Object') + return intrinsicObjectGetPrototypeOf(value) === null && hasIntrinsicConstructor(value, 'Object') } /** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */ function hasPlainArrayPrototype(value: unknown[]): boolean { - const prototype: unknown = Object.getPrototypeOf(value) - if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) return false - const objectPrototype: unknown = Object.getPrototypeOf(prototype) + const prototype: unknown = intrinsicObjectGetPrototypeOf(value) + if (!intrinsicArrayIsArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) return false + const objectPrototype: unknown = intrinsicObjectGetPrototypeOf(prototype) return typeof objectPrototype === 'object' && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype) @@ -43,15 +93,18 @@ function hasPlainArrayPrototype(value: unknown[]): boolean { /** Whether an object is a plain or null-prototype record from any JavaScript realm. */ function hasPlainObjectPrototype(value: object): boolean { - const prototype: unknown = Object.getPrototypeOf(value) + const prototype: unknown = intrinsicObjectGetPrototypeOf(value) return prototype === null || typeof prototype === 'object' && isIntrinsicObjectPrototype(prototype) } /** Return every JSON-visible object key, or reject own data JSON would discard. */ function enumerableStringKeys(value: object): string[] | undefined { - const keys = Reflect.ownKeys(value) - if (keys.some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) return undefined + const keys = intrinsicReflectOwnKeys(value) + for (let index = 0; index < keys.length; index++) { + const key = keys[index] + if (typeof key !== 'string' || !intrinsicReflectApply(intrinsicObjectPropertyIsEnumerable, value, [key])) return undefined + } return keys as string[] } @@ -76,15 +129,20 @@ type SnapshotTask = * @returns a detached lossless-JSON snapshot, or `undefined` when invalid. */ export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined { - const active = new Set() + const active = new IntrinsicSet() let root: CodeJsonValue | undefined const assign = (destination: SnapshotDestination, item: CodeJsonValue): void => { if (destination.kind === 'root') { root = item } else if (destination.kind === 'array') { - destination.target[destination.index] = item + intrinsicObjectDefineProperty(destination.target, destination.index, { + value: item, + enumerable: true, + configurable: true, + writable: true, + }) } else { - Object.defineProperty(destination.target, destination.key, { + intrinsicObjectDefineProperty(destination.target, destination.key, { value: item, enumerable: true, configurable: true, @@ -94,14 +152,14 @@ export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined } const tasks: SnapshotTask[] = [{ kind: 'visit', value, destination: { kind: 'root' } }] - for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + for (let task = takeLast(tasks); task !== undefined; task = takeLast(tasks)) { if (task.kind === 'leave') { - active.delete(task.source) + setDelete(active, task.source) continue } if (task.kind === 'array-item') { - if (!Object.hasOwn(task.source, task.index)) return undefined - tasks.push({ + if (!intrinsicObjectHasOwn(task.source, task.index)) return undefined + append(tasks, { kind: 'visit', value: task.source[task.index], destination: { kind: 'array', target: task.target, index: task.index }, @@ -109,7 +167,7 @@ export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined continue } if (task.kind === 'object-property') { - tasks.push({ + append(tasks, { kind: 'visit', value: task.source[task.key], destination: { kind: 'object', target: task.target, key: task.key }, @@ -127,23 +185,23 @@ export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined continue } if (typeof candidate === 'number') { - if (!Number.isFinite(candidate) || Object.is(candidate, -0)) return undefined + if (!intrinsicNumberIsFinite(candidate) || intrinsicObjectIs(candidate, -0)) return undefined assign(task.destination, candidate) continue } if (typeof candidate !== 'object') return undefined - if (active.has(candidate)) return undefined + if (setHas(active, candidate)) return undefined - if (Array.isArray(candidate)) { + if (intrinsicArrayIsArray(candidate)) { if (!hasPlainArrayPrototype(candidate)) return undefined const length = candidate.length - if (Reflect.ownKeys(candidate).length !== length + 1) return undefined + if (intrinsicReflectOwnKeys(candidate).length !== length + 1) return undefined const target: CodeJsonValue[] = [] assign(task.destination, target) - active.add(candidate) - tasks.push({ kind: 'leave', source: candidate }) + setAdd(active, candidate) + append(tasks, { kind: 'leave', source: candidate }) for (let index = length - 1; index >= 0; index--) { - tasks.push({ kind: 'array-item', source: candidate, index, target }) + append(tasks, { kind: 'array-item', source: candidate, index, target }) } continue } @@ -153,13 +211,13 @@ export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined if (keys === undefined) return undefined const target: Record = {} assign(task.destination, target) - active.add(candidate) - tasks.push({ kind: 'leave', source: candidate }) + setAdd(active, candidate) + append(tasks, { kind: 'leave', source: candidate }) for (let index = keys.length - 1; index >= 0; index--) { const key = keys[index] /* v8 ignore next -- the loop is bounded by the captured key count. */ if (key === undefined) return undefined - tasks.push({ kind: 'object-property', source: candidate as Record, key, target }) + append(tasks, { kind: 'object-property', source: candidate as Record, key, target }) } } return root @@ -192,29 +250,29 @@ export type WorkerJsonWire = WorkerJsonToken[] export function encodeWorkerJson(value: CodeJsonValue): WorkerJsonWire { const wire: WorkerJsonWire = [] const pending: CodeJsonValue[] = [value] - for (let current = pending.pop(); current !== undefined; current = pending.pop()) { + for (let current = takeLast(pending); current !== undefined; current = takeLast(pending)) { if (current === null || typeof current === 'boolean' || typeof current === 'number' || typeof current === 'string') { - wire.push(current) + append(wire, current) continue } - if (Array.isArray(current)) { - wire.push({ kind: 'array', length: current.length }) + if (intrinsicArrayIsArray(current)) { + append(wire, { kind: 'array', length: current.length }) for (let index = current.length - 1; index >= 0; index--) { const item = current[index] - if (item === undefined) throw new Error('cannot encode a sparse JSON array') - pending.push(item) + if (item === undefined) throw new IntrinsicError('cannot encode a sparse JSON array') + append(pending, item) } continue } - const keys = Object.keys(current) - wire.push({ kind: 'object', keys }) + const keys = intrinsicObjectKeys(current) + append(wire, { kind: 'object', keys }) for (let index = keys.length - 1; index >= 0; index--) { const key = keys[index] /* v8 ignore next -- the loop is bounded by the captured key count. */ - if (key === undefined) throw new Error('cannot encode a missing JSON object key') + if (key === undefined) throw new IntrinsicError('cannot encode a missing JSON object key') const item = current[key] - if (item === undefined) throw new Error('cannot encode an undefined JSON object property') - pending.push(item) + if (item === undefined) throw new IntrinsicError('cannot encode an undefined JSON object property') + append(pending, item) } } return wire @@ -226,36 +284,46 @@ type DecodeFrame = /** Whether an array contains exactly its dense indexed slots and `length`. */ function isDenseArray(value: unknown[]): boolean { - if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false + if (!hasPlainArrayPrototype(value) || intrinsicReflectOwnKeys(value).length !== value.length + 1) return false for (let index = 0; index < value.length; index++) { - if (!Object.hasOwn(value, index)) return false + if (!intrinsicObjectHasOwn(value, index)) return false } return true } +/** Whether one exact string-key list contains a key, without consulting its prototype. */ +function keysContain(keys: string[], expected: string): boolean { + for (let index = 0; index < keys.length; index++) { + if (keys[index] === expected) return true + } + return false +} + /** Return one exact container marker, or reject any extra/missing fields. */ function containerToken(value: object): ArrayWireToken | ObjectWireToken | undefined { - if (Array.isArray(value) || !hasPlainObjectPrototype(value)) return undefined + if (intrinsicArrayIsArray(value) || !hasPlainObjectPrototype(value)) return undefined const keys = enumerableStringKeys(value) if (keys === undefined) return undefined const token = value as Record if (token.kind === 'array') { - if (keys.length !== 2 || !keys.includes('kind') || !keys.includes('length')) return undefined + if (keys.length !== 2 || !keysContain(keys, 'kind') || !keysContain(keys, 'length')) return undefined const length = token.length - return typeof length === 'number' && Number.isSafeInteger(length) && length >= 0 + return typeof length === 'number' && intrinsicNumberIsSafeInteger(length) && length >= 0 ? { kind: 'array', length } : undefined } if (token.kind === 'object') { - if (keys.length !== 2 || !keys.includes('kind') || !keys.includes('keys')) return undefined + if (keys.length !== 2 || !keysContain(keys, 'kind') || !keysContain(keys, 'keys')) return undefined const objectKeys = token.keys - if (!Array.isArray(objectKeys) || !isDenseArray(objectKeys)) return undefined - const unique = new Set() + if (!intrinsicArrayIsArray(objectKeys) || !isDenseArray(objectKeys)) return undefined + const unique = new IntrinsicSet() const normalizedKeys: string[] = [] - for (const key of objectKeys as unknown[]) { - if (typeof key !== 'string' || unique.has(key)) return undefined - unique.add(key) - normalizedKeys.push(key) + const objectKeyValues = objectKeys as unknown[] + for (let index = 0; index < objectKeyValues.length; index++) { + const key = objectKeyValues[index] + if (typeof key !== 'string' || setHas(unique, key)) return undefined + setAdd(unique, key) + append(normalizedKeys, key) } return { kind: 'object', keys: normalizedKeys } } @@ -271,14 +339,14 @@ function containerToken(value: object): ArrayWireToken | ObjectWireToken | undef */ export function decodeWorkerJson(input: unknown): CodeJsonValue | undefined { try { - if (!Array.isArray(input) || !isDenseArray(input) || input.length === 0) return undefined + if (!intrinsicArrayIsArray(input) || !isDenseArray(input) || input.length === 0) return undefined const wire = input as unknown[] const frames: DecodeFrame[] = [] let root: CodeJsonValue | undefined let rootAssigned = false const attach = (value: CodeJsonValue): boolean => { - const parent = frames.at(-1) + const parent = frames[frames.length - 1] if (!parent) { if (rootAssigned) return false root = value @@ -288,12 +356,12 @@ export function decodeWorkerJson(input: unknown): CodeJsonValue | undefined { /* v8 ignore next -- completed frames are popped before another token can attach. */ if (parent.index >= (parent.kind === 'array' ? parent.length : parent.keys.length)) return false if (parent.kind === 'array') { - parent.target.push(value) + append(parent.target, value) } else { const key = parent.keys[parent.index] /* v8 ignore next -- object frames are built from validated keys and their exact length. */ if (key === undefined) return false - Object.defineProperty(parent.target, key, { + intrinsicObjectDefineProperty(parent.target, key, { value, enumerable: true, configurable: true, @@ -311,7 +379,7 @@ export function decodeWorkerJson(input: unknown): CodeJsonValue | undefined { if (token === null || typeof token === 'boolean' || typeof token === 'string') { value = token } else if (typeof token === 'number') { - if (!Number.isFinite(token) || Object.is(token, -0)) return undefined + if (!intrinsicNumberIsFinite(token) || intrinsicObjectIs(token, -0)) return undefined value = token } else { if (typeof token !== 'object') return undefined @@ -331,13 +399,13 @@ export function decodeWorkerJson(input: unknown): CodeJsonValue | undefined { } } if (!attach(value)) return undefined - if (frame) frames.push(frame) + if (frame) append(frames, frame) while (frames.length > 0) { - const current = frames.at(-1) + const current = frames[frames.length - 1] /* v8 ignore next -- the loop condition guarantees a final frame. */ if (current === undefined) break if (current.index < (current.kind === 'array' ? current.length : current.keys.length)) break - frames.pop() + takeLast(frames) } } return frames.length === 0 ? root : undefined diff --git a/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts index dde3cba5fc..002f8f1fca 100644 --- a/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts @@ -68,4 +68,42 @@ describe('jsonValueBytesUpTo', () => { expect(jsonValueBytesUpTo(value, 10_004)).toBe(10_004) expect(jsonValueBytesUpTo(value, 10_003)).toBeUndefined() }) + + it('uses module-captured intrinsics after model-visible globals are mutated', () => { + const value: CodeJsonValue = { payload: ['€', 42] } + const bytes = Buffer.byteLength(JSON.stringify(value), 'utf8') + const arrayIsArrayDescriptor = Object.getOwnPropertyDescriptor(Array, 'isArray')! + const arrayPopDescriptor = Object.getOwnPropertyDescriptor(Array.prototype, 'pop')! + const arrayPushDescriptor = Object.getOwnPropertyDescriptor(Array.prototype, 'push')! + const byteLengthDescriptor = Object.getOwnPropertyDescriptor(Buffer, 'byteLength')! + const objectKeysDescriptor = Object.getOwnPropertyDescriptor(Object, 'keys')! + const charCodeAtDescriptor = Object.getOwnPropertyDescriptor(String.prototype, 'charCodeAt')! + const codePointAtDescriptor = Object.getOwnPropertyDescriptor(String.prototype, 'codePointAt')! + const sliceDescriptor = Object.getOwnPropertyDescriptor(String.prototype, 'slice')! + let measured: number | undefined + let prefix = '' + try { + Array.isArray = () => false + Array.prototype.pop = () => { throw new Error('mutated pop') } + Array.prototype.push = () => { throw new Error('mutated push') } + Buffer.byteLength = () => 0 + Object.keys = () => [] + String.prototype.charCodeAt = () => { throw new Error('mutated charCodeAt') } + String.prototype.codePointAt = () => { throw new Error('mutated codePointAt') } + String.prototype.slice = () => { throw new Error('mutated slice') } + measured = jsonValueBytesUpTo(value, bytes) + prefix = truncateJsonStringBytes('€x', 5) + } finally { + Object.defineProperty(Array, 'isArray', arrayIsArrayDescriptor) + Object.defineProperty(Array.prototype, 'pop', arrayPopDescriptor) + Object.defineProperty(Array.prototype, 'push', arrayPushDescriptor) + Object.defineProperty(Buffer, 'byteLength', byteLengthDescriptor) + Object.defineProperty(Object, 'keys', objectKeysDescriptor) + Object.defineProperty(String.prototype, 'charCodeAt', charCodeAtDescriptor) + Object.defineProperty(String.prototype, 'codePointAt', codePointAtDescriptor) + Object.defineProperty(String.prototype, 'slice', sliceDescriptor) + } + expect(measured).toBe(bytes) + expect(prefix).toBe('€') + }) }) diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index 3a2f5ffa69..715dbb4121 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -657,6 +657,41 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { }) }) + it('preserves binding and completion JSON after model code mutates boundary globals', async () => { + const { runtime } = await setup() + const result = await runtime.run({ + program: ` + const arrayPrototype = Array.prototype; + const objectPrototype = Object.prototype; + const setPrototype = Set.prototype; + const stringPrototype = String.prototype; + Array.isArray = () => false; + arrayPrototype.at = arrayPrototype.includes = arrayPrototype.pop = arrayPrototype.push = () => { throw new Error('mutated array method') }; + Object.defineProperty = Object.getOwnPropertyDescriptor = Object.getPrototypeOf = Object.keys = () => { throw new Error('mutated object method') }; + Object.hasOwn = () => false; + Object.is = () => true; + objectPrototype.propertyIsEnumerable = () => false; + Number.isFinite = Number.isSafeInteger = () => false; + Reflect.apply = Reflect.ownKeys = () => { throw new Error('mutated reflect method') }; + setPrototype.add = setPrototype.delete = setPrototype.has = () => { throw new Error('mutated set method') }; + stringPrototype.charCodeAt = stringPrototype.codePointAt = stringPrototype.slice = () => { throw new Error('mutated string method') }; + Buffer.byteLength = () => 0; + Function.prototype.toString = () => 'mutated'; + globalThis.Array = globalThis.Buffer = globalThis.Function = globalThis.Number = globalThis.Object = globalThis.Reflect = globalThis.Set = globalThis.String = undefined; + const echoed = await tools.echo({ request: ['€', 1] }); + return { echoed, completion: { ok: true, amount: 42 } }; + `, + bindings: tools({ echo: async args => args }), + }) + expect(result).toEqual({ + logs: [], + value: { + echoed: { request: ['€', 1] }, + completion: { ok: true, amount: 42 }, + }, + }) + }) + it('rejects forged lossy binding arguments again at the host boundary', async () => { const { runtime } = await setup() let calls = 0 From 182e6a28ccc20035cb22c7246fbd67c6e0909c65 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 03:09:13 +0800 Subject: [PATCH 138/368] test(code-runtime): cover malformed key markers --- .../code-runtime/code-runtime-worker/tests/worker-json.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts index e0c8310a6a..6ef8d30a09 100644 --- a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts @@ -230,6 +230,7 @@ describe('flat worker JSON wire', () => { [foreignMarker], [hiddenMarker], [{ kind: 'unknown' }], + [{ kind: 'array', bogus: 0 }], [{ kind: 'array' }], [{ kind: 'array', length: '1' }], [{ kind: 'array', length: -1 }], From 27fe26f8d25ee2fa57f55b7edb8e1d701da6a4da Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 03:09:33 +0800 Subject: [PATCH 139/368] docs(code-runtime): record captured intrinsic boundary --- .../feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml | 4 ++-- .../feature/2026-07-20-code-mode-typed-tool-returns.md | 4 ++-- .../feature/2026-07-20-code-mode-typed-tool-returns.zh.md | 4 ++-- packages/code-runtime/code-runtime-worker/README.md | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml index 701af0075c..f3606667b5 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml @@ -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 -2026-07-20-code-mode-typed-tool-returns.md: 4e2dfd9d722d003fb2dcd3f215700404d641f98a -2026-07-20-code-mode-typed-tool-returns.zh.md: d4654ee9bff941dc98fa0cb9f3648c5f48381756 +2026-07-20-code-mode-typed-tool-returns.md: 2446f1ac87d992a7d393485796c86ee7d7efcb1e +2026-07-20-code-mode-typed-tool-returns.zh.md: daac287671f9b231855d9af0d992d8e131126c52 diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md index 4e2dfd9d72..2446f1ac87 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md @@ -53,7 +53,7 @@ Before dispatch the bridge snapshots binding arguments as lossless JSON and snap Code Mode declares its rejection capability on the runtime request as `{ name: "ToolCallError", memberNameProperty: "toolName" }`. The runtime seam treats those names as data: the worker materializes and injects the actual constructor used for `tools` binding failures, so `error instanceof ToolCallError` works without making a generic runtime know about tools. The error has the standard `Error` message plus the exact `toolName`; it deliberately omits `ToolFailure.info`, error codes, and Native content. This is an exception contract for control flow, not a failure union for programmatic classification. -Binding arguments and resolutions are revalidated as lossless JSON on both sides of the hostile worker protocol and have no byte cap. Before crossing through structured clone, each detached value is encoded as a flat pre-order token stream whose transport nesting is bounded; the receiver rebuilds it iteratively. Valid application nesting therefore has neither a JavaScript call-stack depth cap nor a platform-specific nested structured-clone limit. The worker captures the native function-source intrinsic before program execution and uses it to distinguish realm-owned plain-container prototypes from user-authored constructors that imitate `Object` or `Array`. The dependency-light runtime seam names its structural equivalent `CodeJsonValue` so it need not depend on the session-owned canonical type; the generated SDK and tool API use `JsonValue`. Intermediate values are not prompt-truncated, context-spilled, or persisted. This preserves full acquired search, workflow, task, filesystem, and MCP values for programmatic filtering while leaving provider and executor acquisition limits truthful. +Binding arguments and resolutions are revalidated as lossless JSON on both sides of the hostile worker protocol and have no byte cap. Before crossing through structured clone, each detached value is encoded as a flat pre-order token stream whose transport nesting is bounded; the receiver rebuilds it iteratively. Valid application nesting therefore has neither a JavaScript call-stack depth cap nor a platform-specific nested structured-clone limit. At module initialization the worker captures the native function-source intrinsic plus every structural and metering intrinsic used by the JSON boundary; private array and set operations invoke those captures without consulting mutable global or prototype slots. Model code can therefore replace helpers such as `Object.keys`, `Array.isArray`, collection methods, string methods, or `Buffer.byteLength` without changing validation, wire transport, or byte accounting. The native function-source capture distinguishes realm-owned plain-container prototypes from user-authored constructors that imitate `Object` or `Array`. The dependency-light runtime seam names its structural equivalent `CodeJsonValue` so it need not depend on the session-owned canonical type; the generated SDK and tool API use `JsonValue`. Intermediate values are not prompt-truncated, context-spilled, or persisted. This preserves full acquired search, workflow, task, filesystem, and MCP values for programmatic filtering while leaving provider and executor acquisition limits truthful. ### Outer result and output ledger @@ -79,7 +79,7 @@ The opaque `exec.parent` token marks nested calls. Presentation metadata and gen ## Testing -Compile-time and snapshot tests pin exact `ToolArgsMap`, `ToolOutputMap`, `ToolName`, schema-to-TypeScript coverage, and exotic names. Registry and real-worker tests cover scalar, array, object, and null values; raw string rendering; absent `undefined`; consumer-declared real rejection classes, including `ToolCallError`; invalid arguments and completions, including intrinsic-looking forged prototypes; large uncapped intermediate bindings; nested spill suppression; exact and over-limit 64 MiB accounting; combined logs/value/diagnostic accounting; giant thrown stacks; bounded failure spill; hostile forged traffic; and built-package execution. +Compile-time and snapshot tests pin exact `ToolArgsMap`, `ToolOutputMap`, `ToolName`, schema-to-TypeScript coverage, and exotic names. Registry and real-worker tests cover scalar, array, object, and null values; raw string rendering; absent `undefined`; consumer-declared real rejection classes, including `ToolCallError`; invalid arguments and completions, including intrinsic-looking forged prototypes; model-mutated JSON-boundary globals and prototypes; large uncapped intermediate bindings; nested spill suppression; exact and over-limit 64 MiB accounting; combined logs/value/diagnostic accounting; giant thrown stacks; bounded failure spill; hostile forged traffic; and built-package execution. Keyless real-worker integration tests pin the two handle workflows that prose results could not safely support. A background bash call returns its task id, the outer run settles, and a later run polls that id to completion; separate cases prove pre-abort creates no task, post-publication call abort preserves the task, foreground execution stays signal-coupled, and `task_kill` owns cancellation. A Cordis program reads an active or pending mount's id and `waitingFor` fields directly, unmounts by that id, and confirms removal without parsing rendered text. diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md index d4654ee9bf..daac287671 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md @@ -53,7 +53,7 @@ declare const tools: { Code Mode 通过运行时请求中的 `{ name: "ToolCallError", memberNameProperty: "toolName" }` 声明其 reject 异常能力。运行时 seam 只把这些名称视为数据:worker 会动态生成并注入真正用于 `tools` 绑定失败的构造函数,因此无需让通用运行时了解工具,`error instanceof ToolCallError` 也能成立。该错误包含标准的 `Error` 消息和确切的 `toolName`,并有意省略 `ToolFailure.info`、错误代码与 Native 内容。这是一项用于控制流的异常契约,而不是供程序分类的失败联合。 -绑定参数与绑定返回值会在不可信 worker 协议的两端重新校验为无损 JSON,且不设字节上限。每个分离后的值在通过结构化克隆跨越边界前,都会编码为扁平的前序 token 流,其传输结构的嵌套深度有界;接收方再以迭代方式重建该值。因此,有效应用数据的嵌套深度既不受 JavaScript 调用栈深度上限限制,也不受特定平台对嵌套结构化克隆施加的上限限制。worker 会在程序执行前捕获用于读取函数源码的原生内建方法,并据此区分每个 JavaScript 运行域原生的普通容器原型与由用户编写、冒充 `Object` 或 `Array` 的构造函数伪造的原型。为保持依赖轻量,运行时 seam 将结构等价类型命名为 `CodeJsonValue`,从而无需依赖会话侧拥有的规范类型;生成的 SDK 和工具 API 则使用 `JsonValue`。这些值不会经过提示词截断、上下文输出落盘或持久化。因此,程序可以完整筛选已经采集的搜索、工作流、任务、文件系统与 MCP 值,同时提供方和执行器的采集上限仍会实际生效。 +绑定参数与绑定返回值会在不可信 worker 协议的两端重新校验为无损 JSON,且不设字节上限。每个分离后的值在通过结构化克隆跨越边界前,都会编码为扁平的前序 token 流,其传输结构的嵌套深度有界;接收方再以迭代方式重建该值。因此,有效应用数据的嵌套深度既不受 JavaScript 调用栈深度上限限制,也不受特定平台对嵌套结构化克隆施加的上限限制。模块初始化时,worker 会捕获用于读取函数源码的原生内建方法,以及 JSON 边界用于结构处理和计量的全部内建方法;内部的数组与集合操作直接调用这些捕获值,不会访问可变的全局或原型槽位。因此,即使模型代码替换 `Object.keys`、`Array.isArray`、集合方法、字符串方法或 `Buffer.byteLength` 等辅助方法,也不会改变校验、协议传输或字节计量。用于读取函数源码的捕获值会区分每个 JavaScript 运行域原生的普通容器原型与由用户编写、冒充 `Object` 或 `Array` 的构造函数伪造的原型。为保持依赖轻量,运行时 seam 将结构等价类型命名为 `CodeJsonValue`,从而无需依赖会话侧拥有的规范类型;生成的 SDK 和工具 API 则使用 `JsonValue`。这些值不会经过提示词截断、上下文输出落盘或持久化。因此,程序可以完整筛选已经采集的搜索、工作流、任务、文件系统与 MCP 值,同时提供方和执行器的采集上限仍会实际生效。 ### 外层结果与输出账本 @@ -79,7 +79,7 @@ Code Mode 通过运行时请求中的 `{ name: "ToolCallError", memberNameProper ## 测试 -编译期测试与快照测试锁定了精确的 `ToolArgsMap`、`ToolOutputMap`、`ToolName`、schema 到 TypeScript 的覆盖范围以及特殊名称。注册表与真实 worker 测试覆盖标量、数组、对象和 null 值;字符串原文渲染;缺席的 `undefined`;消费方声明并用于 reject 的真实异常类,包括 `ToolCallError`;无效参数与完成值,包括伪装为内建原型的伪造原型;不设上限的大型中间绑定值;嵌套输出落盘抑制;64 MiB 上限内外的精确计量;日志、值与诊断的组合计量;抛出的超大堆栈;有界失败的输出落盘;不可信对端伪造的流量;以及构建后包的执行。 +编译期测试与快照测试锁定了精确的 `ToolArgsMap`、`ToolOutputMap`、`ToolName`、schema 到 TypeScript 的覆盖范围以及特殊名称。注册表与真实 worker 测试覆盖标量、数组、对象和 null 值;字符串原文渲染;缺席的 `undefined`;消费方声明并用于 reject 的真实异常类,包括 `ToolCallError`;无效参数与完成值,包括伪装为内建原型的伪造原型;模型代码修改过的 JSON 边界全局对象与原型;不设上限的大型中间绑定值;嵌套输出落盘抑制;64 MiB 上限内外的精确计量;日志、值与诊断的组合计量;抛出的超大堆栈;有界失败的输出落盘;不可信对端伪造的流量;以及构建后包的执行。 无密钥的真实 worker 集成测试锁定了自然语言结果无法安全支持的两种句柄工作流。后台 bash 调用返回 task id,外层运行结束,之后的运行再根据该 id 轮询直至任务完成;其他用例分别证明,预先中止不会创建任务、发布后的调用取消会保留任务、前台执行仍与信号耦合,并且取消归 `task_kill` 所有。Cordis 程序会直接读取 active 或 pending 挂载的 id 和 `waitingFor` 字段,按该 id 卸载,并在不解析渲染文本的情况下确认挂载已移除。 diff --git a/packages/code-runtime/code-runtime-worker/README.md b/packages/code-runtime/code-runtime-worker/README.md index a8e895aea1..ac63c0a0b5 100644 --- a/packages/code-runtime/code-runtime-worker/README.md +++ b/packages/code-runtime/code-runtime-worker/README.md @@ -23,7 +23,7 @@ Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at - **The port assumes a hostile peer** — model code can reach `parentPort` and forge traffic, so every inbound message is shape-validated and REBUILT before anything reads it (`null`, primitives, junk types, and malformed payloads drop without a throw; forged extra fields never ride along), the host answers each call id at most once, resolves binding names as OWN properties only (a forged `constructor` cannot walk a prototype chain), drops post-settlement replies, and validates every binding resolution and completion as lossless JSON. Forged `log`/`done` messages cannot bypass the outer cap: the host repeats validation and accounts every admitted log plus the completion or diagnostic. Worker-side namespaces are null-prototype with `defineProperty`, so `__proto__`-shaped binding names are ordinary keys. - **Binding rejection classes are request data** — an optional namespace descriptor names the constructor global and the own property that receives the failed member name. The worker materializes and injects that real class, so `instanceof` works without hardcoding `tools` or `ToolCallError`; declarations with invalid or colliding globals fail before a worker spawns. - **Two independent budgets, because the peer is hostile** — `computeMs` meters the worker's MEASURED busy time (`worker.performance.eventLoopUtilization()` polling): a hot loop cannot hide behind a pending decoy dispatch, and a program awaiting a slow tool accrues nothing. `maxWallMs` backstops what busy time cannot see (awaiting a promise nobody resolves). Both funnel into `worker.terminate()`, which ends hot synchronous loops too; heap overflow surfaces as the worker's OOM exit (`kind: 'worker-exit'`). -- **Intermediate binding values are complete JSON** — binding arguments and resolutions undergo iterative lossless-JSON validation, including a native-constructor identity check captured before program execution so user-authored functions cannot impersonate plain-container prototypes. Values flatten into a bounded-depth pre-order wire value for structured clone and rebuild iteratively on the other side. They have no byte, JavaScript call-stack, or nested structured-clone depth cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. +- **Intermediate binding values are complete JSON** — binding arguments and resolutions undergo iterative lossless-JSON validation, including a native-constructor identity check captured before program execution so user-authored functions cannot impersonate plain-container prototypes. The worker also captures every structural and metering intrinsic used by this JSON boundary and bypasses mutable collection prototypes for private traversal state, so model mutations of global helpers cannot alter validation, wire transport, or byte accounting. Values flatten into a bounded-depth pre-order wire value for structured clone and rebuild iteratively on the other side. They have no byte, JavaScript call-stack, or nested structured-clone depth cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. - **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. The worker charges exact JSON-string bytes and preflights completion values and exception diagnostics against the remaining combined budget before posting them; a thrown million-byte stack therefore becomes the fixed `output-limit` diagnostic at the worker boundary. Native writes that bypass the patched stream slots arrive on pipes independent of the completion port, so the host repeats the ledger for those bytes and hostile forged traffic; settlement continues bounded pipe capture until worker termination completes before materializing the result. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure-message payload; fixed `CodeRunResult` field names, braces, the bounded error-kind tag, and later presentation whitespace are outside that variable-payload ledger. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. - **Empty environment** — the worker gets `env: {}` and `execArgv: []`: no ambient credentials (stronger than the scrubbed-env rule for spawned commands) and no inherited loader flags. - **Dispose to quiescence** — teardown fails in-flight runs as `abort` and AWAITS each worker's exit before resolving. From f3b42fd738580c737fe75f1001db5d1b6bd0d18e Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 03:11:53 +0800 Subject: [PATCH 140/368] test(code-runtime): type mutated array predicate --- .../code-runtime/code-runtime-worker/tests/output-json.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts index 002f8f1fca..9d3bc4d5ef 100644 --- a/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts @@ -83,7 +83,7 @@ describe('jsonValueBytesUpTo', () => { let measured: number | undefined let prefix = '' try { - Array.isArray = () => false + Array.isArray = (_value: unknown): _value is never[] => false Array.prototype.pop = () => { throw new Error('mutated pop') } Array.prototype.push = () => { throw new Error('mutated push') } Buffer.byteLength = () => 0 From 94adb60e1a2175c54941de35353bebfc431d8334 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 03:15:15 +0800 Subject: [PATCH 141/368] fix(tools): preserve bounded fallback guidance --- ...06-20-generic-long-running-tool-runtime.md | 2 +- .../2026-07-12-agent-scope-runtime-design.md | 2 +- ...19-cooperative-tool-cancellation.i18n.yaml | 4 +- ...026-07-19-cooperative-tool-cancellation.md | 2 +- ...-07-19-cooperative-tool-cancellation.zh.md | 2 +- .../feature/2026-06-30-interception-seams.md | 4 +- docs/core-data-structures/tools.md | 2 +- docs/tool-execution-pipeline.md | 4 +- packages/core/tools/README.md | 2 +- packages/core/tools/src/index.ts | 19 +++++-- packages/core/tools/tests/tools.spec.ts | 56 +++++++++++++++++++ packages/tasks/tool-tasks/README.md | 2 +- packages/tasks/tool-tasks/src/index.ts | 13 ++++- .../tasks/tool-tasks/tests/tool-tasks.spec.ts | 47 ++++++++++++++++ scripts/gen-doc-graphs.ts | 4 +- 15 files changed, 144 insertions(+), 21 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md index 83b5381818..a5fe44f12e 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -75,7 +75,7 @@ Stream reads share one task-scoped consuming cursor because the owning model is The system prompt tells the model to retain task ids, continue independent work instead of busy-polling or duplicating a running task, collect relevant tasks before its final answer, and kill work that no longer matters. Completion injects a logged `context/message` into the exact owner's session; it becomes durable context for the next request but does not wake an idle agent. -The runtime marks a terminal task `reported` when a read or wait delivers it, when a live waiter has claimed delivery at settlement, or when the model explicitly kills it. Reported tasks do not inject redundant completion notices. Listener failures are logged independently, do not stop later listeners, and are not awaited by waiters or teardown. When a snapshot carries `outputLimitBytes`, `dsh-tool-tasks` preserves UTF-8 boundaries and reuses an existing producer truncation marker rather than duplicating it. Reads reserve status suffixes and retain the output tail; completion notices reserve the stable `background task ` prefix and `task_output` instruction before truncating variable kind, label, status, or detail, so the minimum PTY cap still identifies the task to collect. The task surface resolves the caller-visible producer cap in a prepended pre-execute listener before policy can deny or short-circuit dispatch, then applies it through the task definitions' last-mile `finalizeContent` callback so normalized tool errors, outer pipeline failures, and single-text policy results cannot escape the bound; deliberately structured multi-block policy results retain policy ownership of their shape and size. +The runtime marks a terminal task `reported` when a read or wait delivers it, when a live waiter has claimed delivery at settlement, or when the model explicitly kills it. Reported tasks do not inject redundant completion notices. Listener failures are logged independently, do not stop later listeners, and are not awaited by waiters or teardown. When a snapshot carries `outputLimitBytes`, `dsh-tool-tasks` preserves UTF-8 boundaries and reuses an existing producer truncation marker rather than duplicating it. Reads reserve status suffixes and retain the output tail; completion notices reserve the stable `background task ` prefix and `task_output` instruction before truncating variable kind, label, status, detail, or the truncation marker itself, so the minimum PTY cap still identifies the task to collect. The task surface resolves the caller-visible producer cap in a prepended pre-execute listener before policy can deny or short-circuit dispatch, then applies it through the task definitions' last-mile `finalizeContent` callback so normalized tool errors, outer pipeline failures, and single-text policy results cannot escape the bound; deliberately structured multi-block policy results retain policy ownership of their shape and size. ## Producer opt-in diff --git a/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md b/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md index 82adea706a..bc27d37268 100644 --- a/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md +++ b/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md @@ -218,7 +218,7 @@ A fresh registry-assigned Symbol provides collision-free execution identity with Arguments are materialized once where model/tool JSON enters the pipeline. Pre-, around-, and post-execute listeners operate on the typed execution and decisions. Call ID correlation, approval, monotonic guards, and Code Mode nesting remain explicit relational checks. -After post-execute or outer pipeline normalization, the registry invokes the call's snapshotted optional `ToolDefinition.finalizeContent` callback, then materializes and freezes the accepted final result once. The callback may replace only content, so structured error identity, contexts, and metadata remain registry-owned even when a tool enforces a last-mile result bound. Every synchronous `tools/result` observer receives that exact committed object, and observer failures are contained individually. An outer pipeline failure is normalized before final content, so observers can discard staged work against the same authoritative boundary. +After post-execute or outer pipeline normalization, the registry losslessly snapshots the candidate result, converting a snapshot failure into an ordinary error, invokes the call's snapshotted optional `ToolDefinition.finalizeContent` callback, then materializes and freezes the accepted final result once. The callback may replace only content, so structured error identity, contexts, and metadata remain registry-owned even when a tool enforces a last-mile result bound. Every synchronous `tools/result` observer receives that exact committed object, and observer failures are contained individually. An outer pipeline or candidate-snapshot failure is normalized before final content, so observers can discard staged work against the same authoritative boundary. ### The assembly waterfall owns the final model-visible composition diff --git a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.i18n.yaml index 5d517611af..77e3b8c14a 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.i18n.yaml @@ -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 -2026-07-19-cooperative-tool-cancellation.md: e86c087de53fe742436bc01571394657a0a5c9ac -2026-07-19-cooperative-tool-cancellation.zh.md: 91b91b3894dbdc56d57f4819ff4c567305ecfc9d +2026-07-19-cooperative-tool-cancellation.md: be237f6ca9475699bb4af76896772a1a7409033d +2026-07-19-cooperative-tool-cancellation.zh.md: 9ad212c2073063ccb0c838c08ab8f89c9285b26b diff --git a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md index e86c087de5..be237f6ca9 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md +++ b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md @@ -36,7 +36,7 @@ An around-dispatch wrapper may replace `exec.signal` for its delegated lifetime ### Pre-aborted entry short-circuits after materialization -The registry first creates the call token, snapshots the visible definition's optional final-content callback, and losslessly snapshots and freezes the arguments. A materialization failure wins even when the caller signal is already aborted. After successful materialization, a pre-aborted signal skips `tools/pre-execute`, approval, `tools/execute`, `tools/post-execute`, and the tool body, then passes `ABORTED_BEFORE_DISPATCH` through that content-only callback before publishing exactly one frozen authoritative `tools/result`. +The registry first creates the call token, snapshots the visible definition's optional final-content callback, and losslessly snapshots and freezes the arguments. An argument-materialization failure wins even when the caller signal is already aborted. Before final content, the registry also losslessly snapshots the candidate result and converts a result-snapshot failure into an ordinary error, so the callback can still enforce its content invariant. After successful argument materialization, a pre-aborted signal skips `tools/pre-execute`, approval, `tools/execute`, `tools/post-execute`, and the tool body, then passes `ABORTED_BEFORE_DISPATCH` through that content-only callback before publishing exactly one frozen authoritative `tools/result`. ### Started work still reaches quiescence diff --git a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.zh.md b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.zh.md index 91b91b3894..9ad212c207 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.zh.md @@ -36,7 +36,7 @@ Status: implemented ### 进入时已中止会在物化后短路 -注册表先创建调用 token,对可见工具定义的可选 `finalizeContent` callback 做快照,并对参数进行无损快照和冻结。即使调用方信号已经中止,参数物化失败仍优先返回。物化成功后,进入时已中止的信号会跳过 `tools/pre-execute`、审批、`tools/execute`、`tools/post-execute` 和工具主体,然后先由该仅处理内容的 callback 处理 `ABORTED_BEFORE_DISPATCH`,再发布且只发布一次冻结的权威 `tools/result`。 +注册表先创建调用 token,对可见工具定义的可选 `finalizeContent` callback 做快照,并对参数进行无损快照和冻结。即使调用方信号已经中止,参数物化失败仍优先返回。在最终内容处理之前,注册表还会对候选结果进行无损快照,并把结果快照失败转换为普通错误,从而使该 callback 仍能保证其内容不变量成立。参数物化成功后,进入时已中止的信号会跳过 `tools/pre-execute`、审批、`tools/execute`、`tools/post-execute` 和工具主体,然后先由该仅处理内容的 callback 处理 `ABORTED_BEFORE_DISPATCH`,再发布且只发布一次冻结的权威 `tools/result`。 ### 已启动工作仍必须完全停稳 diff --git a/.agents/notes/implemented/feature/2026-06-30-interception-seams.md b/.agents/notes/implemented/feature/2026-06-30-interception-seams.md index 0b2f7eafc8..22c8d7847d 100644 --- a/.agents/notes/implemented/feature/2026-06-30-interception-seams.md +++ b/.agents/notes/implemented/feature/2026-06-30-interception-seams.md @@ -26,10 +26,10 @@ Every call follows `tools/pre-execute` → guards → `tools/execute` → dispat - **`ctx.tools.guard()`** installs synchronous scope-aware policy after the whole pre-execute waterfall. A guard may deny or abstain, never force-allow, so listener ordering cannot resurrect an operation that a final invariant forbids. - **`tools/execute`** is the around-dispatch waterfall for timeout, retry, and metrics plugins. A wrapper delegates to core dispatch with `next()`, may replace and restore the required `exec.signal` before doing so but cannot remove it, and receives the already-normalized result of a thrown or unknown tool; returning its own valid result short-circuits dispatch. - **`tools/post-execute`** is the inspect/transform waterfall. Its `PostToolDecision` accepts, blocks with feedback, optionally replaces content, or attaches `additionalContexts`. The returned decision is the supported cross-tool transform channel. -- **`ToolDefinition.finalizeContent`** is an optional synchronous, total, content-only boundary snapshotted with the visible definition at call creation. It runs exactly once after the registry has normalized the final outcome, including pre-, around-, or post-listener failures that bypass later waterfalls. It may replace `content` or preserve it with `undefined`, but cannot rewrite `isError`, structured error identity, contexts, or presentation metadata. This is where a tool enforces its own last-mile content invariant without converting policy failures into weaker block decisions. +- **`ToolDefinition.finalizeContent`** is an optional synchronous, total, content-only boundary snapshotted with the visible definition at call creation. It runs exactly once after the registry has normalized and losslessly snapshotted the candidate outcome, including pre-, around-, or post-listener failures that bypass later waterfalls and errors discovered while snapshotting another result field. It may replace `content` or preserve it with `undefined`, but cannot rewrite `isError`, structured error identity, contexts, or presentation metadata. This is where a tool enforces its own last-mile content invariant without converting policy failures into weaker block decisions. - **`tools/result`** is the synchronous contained notification after every transform, lossless-JSON materialization, and the outer error boundary. It receives the same frozen execution identity and an immutable snapshot of the authoritative result; observer failures are contained per listener and cannot change or reject `ToolRegistry.execute()`'s returned outcome. -Core dispatch and the tool body sit inside normalization boundaries, so tool, listener, malformed-result, non-JSON result, and identity-shape failures resolve as JSON-safe `isError` results rather than escaping the turn. A post-execute listener can therefore inspect a thrown tool; definition-owned final content invariants also cover outer pipeline failures; and a final observer sees exactly what the caller receives and the session log can persist. +Core dispatch and the tool body sit inside normalization boundaries, so tool, listener, malformed-result, non-JSON result, and identity-shape failures resolve as JSON-safe `isError` results rather than escaping the turn. A post-execute listener can therefore inspect a thrown tool; definition-owned final content invariants also cover outer pipeline and candidate-snapshot failures; and a final observer sees exactly what the caller receives and the session log can persist. **`TurnEndReason.rejected`** (`dsh-session`): a zero-step turn whose claimed prompt was blocked by `prompt-submit`. diff --git a/docs/core-data-structures/tools.md b/docs/core-data-structures/tools.md index 3174cff8b8..9ba0b07100 100644 --- a/docs/core-data-structures/tools.md +++ b/docs/core-data-structures/tools.md @@ -291,7 +291,7 @@ interface ToolExecutionResult { The result carries only the outcome. Call identity remains on the immutable `ToolExecution` that accompanies it through every hook and on the durable `tool/call` / `tool/result` session events, so wrappers cannot create a second, disagreeing identity. -The registry materializes and freezes the final accepted result immediately before `tools/result`. Its content, structured error, additional context, and presentation metadata must round-trip losslessly through JSON; an invalid outcome becomes a JSON-safe `isError` result, so the observed live outcome is safe for the later durable `tool/result` append. +Before final content, the registry losslessly snapshots the candidate result; a failure in content, structured error, additional context, or presentation metadata becomes a JSON-safe `isError` result that still reaches `finalizeContent`. The registry then materializes and freezes the final accepted result immediately before `tools/result`, so the observed live outcome is safe for the later durable `tool/result` append. Each interception waterfall returns a typed **Decision** (the idiom shared with the `agent/*` seams). `tools/pre-execute` listeners receive `(exec, next)` and return a `PreToolDecision`; `tools/execute` wrappers return a `ToolExecutionResult`; `tools/post-execute` listeners receive `(exec, result, next)` and return a `PostToolDecision`: diff --git a/docs/tool-execution-pipeline.md b/docs/tool-execution-pipeline.md index a6646e6587..6904c31dd2 100644 --- a/docs/tool-execution-pipeline.md +++ b/docs/tool-execution-pipeline.md @@ -19,7 +19,7 @@ flowchart TD fsGate["fs/write-intent or fs/edit-intent
    tool-fs mutations only"] owned["Tool-owned session events
    todo/write, fs/observed, hook/invoked, hook/result, tool/code-dispatch"] post["tools/post-execute waterfall
    accept, block, replace, add context"] - normalized["Registry outer normalization
    pipeline throws become isError"] + normalized["Registry outer normalization
    pipeline/result snapshot throws become isError"] finalize["ToolDefinition.finalizeContent
    last content-only invariant"] final["tools/result synchronous notification
    frozen authoritative outcome"] context["Active-batch additionalContexts FIFO
    context/message after recorded tool results"] @@ -57,6 +57,6 @@ flowchart TD allResults --> context ``` -Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The visible definition's snapshotted `finalizeContent` callback then enforces a synchronous content-only invariant across ordinary decisions and normalized pipeline failures before `tools/result` observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, surface denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency. +Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The registry losslessly snapshots the candidate result and normalizes a snapshot failure before the visible definition's snapshotted `finalizeContent` callback enforces its synchronous content-only invariant. `tools/result` then observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, surface denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency. Maintenance mode: curated Mermaid flow; exact tool schemas and event signatures live in generated catalogs. diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 07b9dde1af..1517bcfacf 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -15,7 +15,7 @@ tools: ### Public API -- `ctx.tools.register(definition: ToolDefinition): () => void` Register a trusted typed same-process definition. The layer is the calling context's scope: a plain plugin context registers globally; an agent's `agent.ctx` registers for that agent alone, shadowing a same-named global tool there. Duplicate names within one layer throw; non-native modes also reject the reserved `run_code` transport name. `timeoutMs`, when present, must be positive and finite. The optional synchronous `finalizeContent` callback is snapshotted when a call starts and may replace only final model-facing content after every pipeline outcome is normalized. Disposed with the calling fiber. +- `ctx.tools.register(definition: ToolDefinition): () => void` Register a trusted typed same-process definition. The layer is the calling context's scope: a plain plugin context registers globally; an agent's `agent.ctx` registers for that agent alone, shadowing a same-named global tool there. Duplicate names within one layer throw; non-native modes also reject the reserved `run_code` transport name. `timeoutMs`, when present, must be positive and finite. The optional synchronous `finalizeContent` callback is snapshotted when a call starts and may replace only final model-facing content after every pipeline outcome is normalized, including an error discovered while losslessly snapshotting another result field. Disposed with the calling fiber. - `ctx.tools.restrict(filter)` applies an agent-scoped allow/deny mask to global tools and throws from a plain context. The filter is snapshotted at registration; multiple masks intersect and scope-local tools merge afterwards. Deny masks admit later unnamed globals, while allow masks exclude later names. Unknown, local, or reserved names and empty filters reject. This is live visibility composition, not an authority boundary; see the [scope security non-goal](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-explicit-non-goals). - `ctx.tools.get(name: string, scope?: ScopeKey): ToolDefinition | undefined` Resolution as one scope sees it (shadowing applied; a restricted-away global reads as absent) — presenters pass the calling agent so the card matches what executed. - `ctx.tools.schemas(scope?: ScopeKey): ToolSchema[]` Schemas of everything the scope can see (without the `execute` functions). The shipped tools' schemas are catalogued in [docs/tool-catalog.md](../../../docs/tool-catalog.md), generated by booting each tool plugin and harvesting this method (see [the tool-schema-catalog Agent Note](../../../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md)). diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index c434541b62..9577c8f858 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -1057,9 +1057,15 @@ export class ToolRegistry extends Service { * @internal */ private finishScheduledExecution(exec: ToolRunContext, result: ToolExecutionResult): ToolExecutionResult { + let snapshottedResult: ToolExecutionResult + try { + snapshottedResult = this.snapshotFinalResult(result) + } catch (error: unknown) { + snapshottedResult = toolErrorResult(error) + } let finalResult: ToolExecutionResult try { - finalResult = this.materializeFinalResult(this.applyFinalContent(exec, result)) + finalResult = this.materializeFinalResult(this.applyFinalContent(exec, snapshottedResult)) } catch (error: unknown) { finalResult = this.materializeFinalResult(toolErrorResult(error)) } @@ -1187,13 +1193,18 @@ export class ToolRegistry extends Service { } } - /** Materialize the authoritative commit outcome once, immediately before `tools/result`. */ - private materializeFinalResult(result: ToolExecutionResult): ToolExecutionResult { + /** Validate and detach one candidate outcome before tool-owned final content. */ + private snapshotFinalResult(result: ToolExecutionResult): ToolExecutionResult { const detached = snapshotJsonValue(result) if (detached === undefined) { throw new TypeError('tool result must be losslessly JSON-serializable') } - return deepFreeze(detached) + return detached + } + + /** Materialize the authoritative commit outcome once, immediately before `tools/result`. */ + private materializeFinalResult(result: ToolExecutionResult): ToolExecutionResult { + return deepFreeze(this.snapshotFinalResult(result)) } } diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index bddefaba41..ad2c0dca8c 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -140,6 +140,62 @@ describe('ToolRegistry', () => { expect(observedError).toBe(true) }) + it('finalizes errors discovered while snapshotting non-content result fields', async () => { + const ctx = await setup() + let finalizeCalls = 0 + ctx.tools.register({ + ...echoTool, + name: 'throwing-meta', + finalizeContent(_exec, result) { + finalizeCalls += 1 + const block = result.content[0] + if (block?.type !== 'text') return undefined + return [{ type: 'text', text: block.text.slice(0, 32) }] + }, + async execute() { + const meta = {} + Object.defineProperty(meta, 'value', { + enumerable: true, + get() { throw new Error('snapshot failed: '.repeat(100)) }, + }) + return { content: [{ type: 'text', text: 'body' }], meta } + }, + }) + + const result = await ctx.tools.execute({ + signal: testToolSignal, + callId: CallId('throwing-meta'), name: 'throwing-meta', arguments: {}, + }) + + expect(result.isError).toBe(true) + expect(result.content).toEqual([{ type: 'text', text: 'Error: snapshot failed: snapshot' }]) + expect(finalizeCalls).toBe(1) + }) + + it('normalizes a throwing final content callback without invoking it again', async () => { + const ctx = await setup() + let finalizeCalls = 0 + ctx.tools.register({ + ...echoTool, + name: 'throwing-finalizer', + finalizeContent() { + finalizeCalls += 1 + throw new Error('finalizer violated its total contract') + }, + }) + + const result = await ctx.tools.execute({ + signal: testToolSignal, + callId: CallId('throwing-finalizer'), name: 'throwing-finalizer', arguments: {}, + }) + + expect(result).toEqual({ + content: [{ type: 'text', text: 'Error: finalizer violated its total contract' }], + isError: true, + }) + expect(finalizeCalls).toBe(1) + }) + it('returns isError results for unknown tools and throwing tools', async () => { const ctx = await setup() ctx.tools.register({ diff --git a/packages/tasks/tool-tasks/README.md b/packages/tasks/tool-tasks/README.md index 4072a84205..2065ef8a08 100644 --- a/packages/tasks/tool-tasks/README.md +++ b/packages/tasks/tool-tasks/README.md @@ -10,7 +10,7 @@ The model-facing control surface for `ctx.tasks`: three kind-independent tools, All three use generic ACP cards: `read` for output and list, `execute` for kill. -When a producer supplies `outputLimitBytes`, `task_output`, terminal `task_kill`, and completion notices cap the complete UTF-8 result after adding status or notice text. Reads retain the output tail and control suffix when they fit; a bounded completion notice instead reserves `background task ` and the `task_output` collection instruction before spending remaining bytes on its variable kind, label, status, and detail. A prepended pre-execute listener captures the caller-visible task before policy, and each task-control definition's final-content callback applies its producer cap to single-text denials, short-circuits, normalized tool or pipeline failures, replacements, and blocks; structured multi-block policy results retain their shape. An existing producer truncation marker is reused rather than duplicated. Producers that omit the field retain the existing unbounded control-surface behavior. +When a producer supplies `outputLimitBytes`, `task_output`, terminal `task_kill`, and completion notices cap the complete UTF-8 result after adding status or notice text. Reads retain the output tail and control suffix when they fit; a bounded completion notice instead reserves `background task ` and the `task_output` collection instruction before spending remaining bytes on its variable kind, label, status, detail, and truncation marker. A prepended pre-execute listener captures the caller-visible task before policy, and each task-control definition's final-content callback applies its producer cap to single-text denials, short-circuits, normalized tool or pipeline failures, replacements, and blocks; structured multi-block policy results retain their shape. An existing producer truncation marker is reused rather than duplicated. Producers that omit the field retain the existing unbounded control-surface behavior. ## Completion notices diff --git a/packages/tasks/tool-tasks/src/index.ts b/packages/tasks/tool-tasks/src/index.ts index 40e6aaf7cb..d258299b40 100644 --- a/packages/tasks/tool-tasks/src/index.ts +++ b/packages/tasks/tool-tasks/src/index.ts @@ -81,8 +81,17 @@ function fitCompletionNotice(snapshot: TaskSnapshot): string { const omitted = '\n[notice truncated]' const fixed = `${prefix}${omitted}${action}` const fixedBytes = encoder.encode(fixed).byteLength - if (fixedBytes >= maxBytes) return retainHead(fixed, maxBytes) - return `${prefix}${retainHead(detail, maxBytes - fixedBytes)}${omitted}${action}` + if (fixedBytes <= maxBytes) { + return fixedBytes === maxBytes + ? fixed + : `${prefix}${retainHead(detail, maxBytes - fixedBytes)}${omitted}${action}` + } + const compact = `${prefix}${action}` + const compactBytes = encoder.encode(compact).byteLength + if (compactBytes <= maxBytes) return compact + const actionBytes = encoder.encode(action).byteLength + if (actionBytes >= maxBytes) return retainTail(action, maxBytes) + return `${retainHead(prefix, maxBytes - actionBytes)}${action}` } function boundSingleText(content: readonly ContentBlock[], maxBytes: number): ContentBlock[] | undefined { diff --git a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts index eadd4eea11..dc27e16fe8 100644 --- a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts +++ b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts @@ -424,6 +424,53 @@ describe('completion notices', () => { expect(notice).toContain('[notice truncated]\nDone; task_output.') }) + it('keeps the complete PTY task id and collection action at the minimum PTY limit', async () => { + const { ctx } = await setup() + for (let index = 0; index < 99; index += 1) { + const prior = producer({ kind: 'pty-send' }) + ctx.tasks.start(prior.spec) + prior.settle({ status: 'completed' }) + } + const inject = vi.fn() + const owner = fakeAgent(ctx, 'sess-1', inject) + const target = producer({ + owner, + kind: 'pty-send', + label: 'x'.repeat(1_000), + outputLimitBytes: 64, + }) + ctx.tasks.start(target.spec) + + target.settle({ status: 'completed', detail: 'd'.repeat(1_000) }) + await tick() + + const content = inject.mock.calls[0]?.[0] as Array<{ type: string; text?: string }> | undefined + const notice = content?.[0]?.text ?? '' + expect(Buffer.byteLength(notice)).toBeLessThanOrEqual(64) + expect(notice).toBe('background task pty-send-100\nDone; task_output.') + }) + + it('reserves the collection-action tail when a producer supplies a smaller budget', async () => { + const { ctx } = await setup() + const inject = vi.fn() + const owner = fakeAgent(ctx, 'sess-1', inject) + const tiny = producer({ owner, kind: 'pty-send', label: 'x'.repeat(100), outputLimitBytes: 8 }) + const short = producer({ owner, kind: 'pty-send', label: 'x'.repeat(100), outputLimitBytes: 32 }) + ctx.tasks.start(tiny.spec) + ctx.tasks.start(short.spec) + + tiny.settle({ status: 'completed' }) + short.settle({ status: 'completed' }) + await tick() + + const tinyNotice = (inject.mock.calls[0]?.[0] as Array<{ text?: string }> | undefined)?.[0]?.text ?? '' + const shortNotice = (inject.mock.calls[1]?.[0] as Array<{ text?: string }> | undefined)?.[0]?.text ?? '' + expect(Buffer.byteLength(tinyNotice)).toBeLessThanOrEqual(8) + expect(tinyNotice).toBe('_output.') + expect(Buffer.byteLength(shortNotice)).toBeLessThanOrEqual(32) + expect(shortNotice).toBe('background ta\nDone; task_output.') + }) + it('suppresses the notice for a task the model already killed', async () => { const { ctx } = await setup() const inject = vi.fn() diff --git a/scripts/gen-doc-graphs.ts b/scripts/gen-doc-graphs.ts index b01a1514d5..2383710b3b 100644 --- a/scripts/gen-doc-graphs.ts +++ b/scripts/gen-doc-graphs.ts @@ -987,7 +987,7 @@ function renderToolPipeline(): string { ` fsGate["${mermaidCode('fs/write-intent')} or ${mermaidCode('fs/edit-intent')}
    tool-fs mutations only"]`, ` owned["Tool-owned session events
    ${mermaidCode('todo/write')}, ${mermaidCode('fs/observed')}, ${mermaidCode('hook/invoked')}, ${mermaidCode('hook/result')}, ${mermaidCode('tool/code-dispatch')}"]`, ` post["${mermaidCode('tools/post-execute')} waterfall
    accept, block, replace, add context"]`, - ' normalized["Registry outer normalization
    pipeline throws become isError"]', + ' normalized["Registry outer normalization
    pipeline/result snapshot throws become isError"]', ' finalize["ToolDefinition.finalizeContent
    last content-only invariant"]', ` final["${mermaidCode('tools/result')} synchronous notification
    frozen authoritative outcome"]`, ' context["Active-batch additionalContexts FIFO
    context/message after recorded tool results"]', @@ -1025,7 +1025,7 @@ function renderToolPipeline(): string { ' allResults --> context', '```', '', - 'Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The visible definition\'s snapshotted `finalizeContent` callback then enforces a synchronous content-only invariant across ordinary decisions and normalized pipeline failures before `tools/result` observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, surface denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency.', + 'Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The registry losslessly snapshots the candidate result and normalizes a snapshot failure before the visible definition\'s snapshotted `finalizeContent` callback enforces its synchronous content-only invariant. `tools/result` then observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, surface denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency.', '', ...maintenanceFooter(maintenance), ].join('\n') From efa4326ff4c157f56543956b1e9bad43c1264266 Mon Sep 17 00:00:00 2001 From: imccyu <276526105+imccyu@users.noreply.github.com> Date: Wed, 22 Jul 2026 20:49:15 +0800 Subject: [PATCH 142/368] refactor: client no export docs: AGENTS.md refactor: client no export 2 --- packages/client/AGENTS.md | 8 ++++++++ packages/client/connection/README.md | 2 +- packages/client/connection/src/client/index.ts | 11 ++++------- packages/client/runtime/README.md | 2 +- packages/client/runtime/src/client/index.ts | 7 ++----- packages/client/ui-conversation/README.md | 2 +- packages/client/ui-conversation/src/client/index.ts | 10 +--------- .../ui-conversation/tests/skeleton-branches.spec.tsx | 5 ++++- .../client/ui-conversation/tests/skeleton.spec.tsx | 7 ++++--- packages/client/ui-layout/README.md | 4 +++- packages/client/ui-layout/src/client/index.ts | 11 ++++++----- packages/client/ui-layout/tests/app-frame.spec.tsx | 2 +- packages/client/ui-layout/tests/columns.spec.ts | 2 +- packages/client/ui-layout/tests/service.spec.ts | 3 ++- packages/client/ui-sidebar/README.md | 2 ++ packages/client/ui-sidebar/src/client/index.ts | 12 +----------- .../client/ui-sidebar/tests/sidebar-root.spec.tsx | 7 +++---- packages/client/ui-sidebar/tests/store.spec.ts | 2 +- packages/client/ui-sidebar/tests/tree.spec.ts | 2 +- packages/client/ui-trajectory/src/client/index.ts | 6 ++---- packages/client/ui-trajectory/tests/views.spec.tsx | 12 ++++++++---- 21 files changed, 57 insertions(+), 62 deletions(-) diff --git a/packages/client/AGENTS.md b/packages/client/AGENTS.md index cfe932ed65..7d15bfc0ba 100644 --- a/packages/client/AGENTS.md +++ b/packages/client/AGENTS.md @@ -4,6 +4,14 @@ Rules for `packages/client/*` (the browser side of the dsh web GUI) plus its bui Packages here are named with the directory prefix: `@deepseek-ai/dsh-client-`. +## Export discipline (client plugin packages) + +The `/client` surface of a UI plugin package is a contract face, not a convenience barrel. Three rules, enforced package-wide (do not restate them as per-file comments): + +1. **A UI plugin exports no values beyond what cordis loading needs** — `apply` / `inject` (and `Config` where present). Types are the extra allowance: contract types (OwnerShare shapes, injected shapes, view/toolview entry types) export freely. Implementation components, pure helpers, constants, and stores stay internal. Existing value exports beyond this line (the ui-layout frame components consumed by the shell assembler, service classes kept for `import type`) are grandfathered per-consumer; adding a new one requires user sign-off, not a matching export. +2. **Same-package tests import internals directly** — relative `../src/client/xxx.ts` from package tests, or the `./src/*` subpath where a spec lives outside the package. Never widen the public surface to make a test compile. +3. **Cross-package imports of another plugin's symbols are in principle forbidden.** The sanctioned routes are the slot system (define/register/renderSlot, the view and toolview registries) and ctx services. If neither fits, stop and escalate — do not add an export to unblock yourself. + ## Layering red lines The stack is three layers with one-way knowledge, settled in the [web client architecture note](../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md): diff --git a/packages/client/connection/README.md b/packages/client/connection/README.md index a35c9c3d0c..dc9fbb85b8 100644 --- a/packages/client/connection/README.md +++ b/packages/client/connection/README.md @@ -1,6 +1,6 @@ # @deepseek-ai/dsh-client-connection -Wire consumer layer (moved verbatim from web-runtime): IApiClient family (WebApiClient/FixtureApiClient), ConnectionController (SSE dual-stream + backoff reconnect), WEB_EVENTS. Contract: api-contracts v3 §3, export inventory in §3.2. +Wire consumer layer: the client plugin's apply mounts `ctx.connection` (shared api client + single-consumer stream-loop starter); the export face carries the wire contract types, the `AbstractApiClient` seam, and the loop's sink/config types. The platform subclasses (WebApiClient/FixtureApiClient), the ConnectionController loop, and the fixture data source are package-internal — apply selects and drives them; tests reach them via src. Contract: api-contracts v3 §3. ## Model Experience diff --git a/packages/client/connection/src/client/index.ts b/packages/client/connection/src/client/index.ts index 026fc1bf5f..b017d1c9e2 100644 --- a/packages/client/connection/src/client/index.ts +++ b/packages/client/connection/src/client/index.ts @@ -21,16 +21,13 @@ export type { ClientRequest, ServerResponse, ServerRequest, ClientResponse, RpcMessage, RpcReceipt, IApiClient, SessionId, SessionEvent, ContentBlock, StreamChunk, } from './api.ts' -export { RpcId, AbstractApiClient, resultOf, transportError } from './api.ts' +export { RpcId, AbstractApiClient, transportError } from './api.ts' -// ---- Connection loop ---- -export { ConnectionController } from './connection.ts' +// ---- Connection loop types (part of the ConnectionHandle.start contract; +// the controller class itself stays package-internal — apply owns the loop, +// tests reach it via src) ---- export type { ConnectionConfig, ConnectionSinks, ConnectionState } -// ---- Platform client subclasses ---- -export { WebApiClient } from './web-api-client.ts' -export { FixtureApiClient, createFixtureApi } from './fixture.ts' - /** Required services (none — this is the wire root). */ export const inject: string[] = [] diff --git a/packages/client/runtime/README.md b/packages/client/runtime/README.md index 01c4172902..66eb5b22ac 100644 --- a/packages/client/runtime/README.md +++ b/packages/client/runtime/README.md @@ -1,6 +1,6 @@ # @deepseek-ai/dsh-client-runtime -Client cordis boot + core services: SlotsService (Service wrapper over SlotCore + 'slots/changed' bridge), SessionsService (list store projection, scope tree, bindings, ancestry), Session object layer, ClientLoader (`./loader` subpath, statically held by the shell). Contract: api-contracts v3 §4. +Client cordis boot + core services: SlotsService (Service wrapper over SlotCore + 'slots/changed' bridge), SessionsService (list store projection, scope tree, bindings, ancestry), the Session object layer (exported as a type; instances are owned and handed out by SessionsService — the manager/paging internals stay package-internal, tests reach them via src), ClientLoader (`./loader` subpath, statically held by the shell). Contract: api-contracts v3 §4. ## Model Experience diff --git a/packages/client/runtime/src/client/index.ts b/packages/client/runtime/src/client/index.ts index 6c012fa410..5180fce2b2 100644 --- a/packages/client/runtime/src/client/index.ts +++ b/packages/client/runtime/src/client/index.ts @@ -17,14 +17,11 @@ import type { ConversationSnapshot, RunningToolCall, ToolResultNode } from './se export { SlotsService } from './slots.ts' export { SessionsService, scopeOf } from './sessions/service.ts' +export type { Session } from './sessions/session.ts' export type { SessionBinding, SessionListState, SessionSummary } from './sessions/service.ts' -export { SessionManager } from './sessions/manager.ts' -export type { SessionListSnapshot } from './sessions/manager.ts' -export { Session, PAGE_MESSAGES } from './sessions/session.ts' -export type { SessionListEntry } from './sessions/lineage.ts' export type { AssistantBlock, AssistantMessageNode, ContextMessageNode, ConversationNode, ConversationSnapshot, - OpenState, PartialAssistant, PendingInteraction, PromptError, RunningToolCall, SteeringMessageNode, + PendingInteraction, RunningToolCall, SteeringMessageNode, ToolResultNode, UnknownSurfaceNode, UserMessageNode, } from './sessions/conversation.ts' export type { SessionId } from '@deepseek-ai/dsh-client-connection/client' diff --git a/packages/client/ui-conversation/README.md b/packages/client/ui-conversation/README.md index c75077d11d..425122958a 100644 --- a/packages/client/ui-conversation/README.md +++ b/packages/client/ui-conversation/README.md @@ -2,7 +2,7 @@ Conversation domain: skeleton (header/tabs/composer/empty state), chat view (grouped step-summary flow, streaming tail isolation), ctx.toolviews named registry with bash samples, minimal details panel, scope-addressed ConversationService. Contract: api-contracts v3 §7. -`src/client/` is organized for the future package split: `contract/` is the sole inter-domain shared face (`slots.ts` composed slot props, `views.ts` view ring, `toolview.ts` tool ring, `tool-call-model.ts`); the `skeleton/`, `chat/`, and `toolviews/` domain directories import contract files and never each other; `apply.ts` is the only assembly point allowed to import all three domains. +`src/client/` is organized for the future package split: `contract/` is the sole inter-domain shared face (`slots.ts` composed slot props, `views.ts` view ring, `toolview.ts` tool ring, `tool-call-model.ts`); the `skeleton/`, `chat/`, and `toolviews/` domain directories import contract files and never each other; `apply.ts` is the only assembly point allowed to import all three domains. The `/client` export surface is the contract only — `apply`/`inject`, the two service classes, and the `contract/` type families; implementation components (skeleton, chat rows) stay internal and reach the page exclusively through apply's slot registrations (tests take them via the `./src/*` subpath). ## Model Experience diff --git a/packages/client/ui-conversation/src/client/index.ts b/packages/client/ui-conversation/src/client/index.ts index 17e9ed88a8..91b9c27c95 100644 --- a/packages/client/ui-conversation/src/client/index.ts +++ b/packages/client/ui-conversation/src/client/index.ts @@ -24,15 +24,7 @@ export type { ConversationInjected, ConversationSlotProps, DetailsInjected, DetailsSlotProps, EmptyStateInjected, EmptyStateSlotProps, } from './contract/slots.ts' - -export { ConversationRoot } from './skeleton/ConversationRoot.tsx' -export type { ConversationRootProps } from './skeleton/ConversationRoot.tsx' -export { InputBar } from './skeleton/InputBar.tsx' -export type { InputBarError, InputBarProps } from './skeleton/InputBar.tsx' -export { EmptyState } from './skeleton/EmptyState.tsx' -export type { EmptyStateProps } from './skeleton/EmptyState.tsx' -export { DetailsPanel } from './skeleton/DetailsPanel.tsx' -export type { DetailsPanelProps } from './skeleton/DetailsPanel.tsx' +// Export discipline: packages/client/AGENTS.md. declare module 'cordis' { interface Context { diff --git a/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx b/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx index 25808e17c5..fa1a780635 100644 --- a/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx +++ b/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx @@ -9,8 +9,11 @@ import { cleanup, fireEvent, render, waitFor } from '@testing-library/react' import { bindSnapshotSelector } from '@deepseek-ai/dsh-client-web-react' import type { UseSession } from '@deepseek-ai/dsh-client-web-react' import type { ConversationSnapshot, SessionId, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' -import { ConversationRoot, DetailsPanel, EmptyState } from '@deepseek-ai/dsh-client-ui-conversation/client' import type { SelectionTarget, ViewEntry } from '@deepseek-ai/dsh-client-ui-conversation/client' +// Export discipline: packages/client/AGENTS.md. +import { ConversationRoot } from '../src/client/skeleton/ConversationRoot.tsx' +import { DetailsPanel } from '../src/client/skeleton/DetailsPanel.tsx' +import { EmptyState } from '../src/client/skeleton/EmptyState.tsx' afterEach(cleanup) diff --git a/packages/client/ui-conversation/tests/skeleton.spec.tsx b/packages/client/ui-conversation/tests/skeleton.spec.tsx index ab23a64389..e5e26a889b 100644 --- a/packages/client/ui-conversation/tests/skeleton.spec.tsx +++ b/packages/client/ui-conversation/tests/skeleton.spec.tsx @@ -12,10 +12,11 @@ import type { FC } from 'react' import { bindSnapshotSelector, createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' import type { UseSession } from '@deepseek-ai/dsh-client-web-react' import type { SessionId, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' -import { - ConversationRoot, DetailsPanel, EmptyState, -} from '@deepseek-ai/dsh-client-ui-conversation/client' import type { SelectionTarget, ViewEntry, ViewId } from '@deepseek-ai/dsh-client-ui-conversation/client' +// Export discipline: packages/client/AGENTS.md. +import { ConversationRoot } from '../src/client/skeleton/ConversationRoot.tsx' +import { DetailsPanel } from '../src/client/skeleton/DetailsPanel.tsx' +import { EmptyState } from '../src/client/skeleton/EmptyState.tsx' const sid = (s: string): SessionId => s as SessionId diff --git a/packages/client/ui-layout/README.md b/packages/client/ui-layout/README.md index 6c935f4b9d..69f9d2fa2e 100644 --- a/packages/client/ui-layout/README.md +++ b/packages/client/ui-layout/README.md @@ -2,7 +2,9 @@ Shell plugin: three-column AppFrame (drag handles, concession chain) + ctx.layout viewing-state service (nav, panel widths, persist); defines the sidebar/conversation/details/conversation.empty slots. Contract: api-contracts v3 §5. -Slot declarations use the composed-props entry form (`owner` share, no full `props`): the exported OwnerShare contracts are `SidebarOwnerProps` / `ConvOwnerProps` / `DetailsOwnerProps` / `EmptyOwnerProps` — registrants reference them via `OwnerOf<'sidebar' | ...>` and compose their own injected share locally. The `conversation` entry authorizes `conversation.empty` delegation through `children`. +Slot declarations use the composed-props entry form (`owner` share, no full `props`): the exported OwnerShare contracts are `SidebarOwnerProps` / `ConvOwnerProps` / `DetailsOwnerProps` / `EmptyOwnerProps` — registrants reference them via `OwnerOf<'sidebar' | ...>` and compose their own injected share locally. No entry declares `children` (declaring it requires the registered component to carry the slots face): no P-I slot component delegates — `conversation.empty` is rendered by the shell's assembly closure, not handed down by ConversationRoot. + +The export surface is the cross-package contract only: the AppFrame trio (+ `AppFrameProps`) consumed by the web shell's assembly, `LayoutService` with its store shapes (`NavState`/`PanelState`/`ViewId`), and the OwnerShare contracts. The concession-chain solver (`computeColumns`) and its geometry constants are package-internal; tests import them from `/src`. ## Model Experience diff --git a/packages/client/ui-layout/src/client/index.ts b/packages/client/ui-layout/src/client/index.ts index e07c5d9896..ceb4ff0b06 100644 --- a/packages/client/ui-layout/src/client/index.ts +++ b/packages/client/ui-layout/src/client/index.ts @@ -10,12 +10,13 @@ import type { Context } from 'cordis' import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client' import { LayoutService } from './service.ts' +// Contract surface only (export-convergence rule: cross-package consumers +// keep a symbol exported; test-only/package-internal symbols live off /src). +// AppFrame trio + AppFrameProps: consumed by the web shell's assembly closure. +// LayoutService: the ctx.layout service class (consumers type against it). +// PanelState rides AppFrameProps' hooks; NavState/ViewId are service-store +// shapes referenced through LayoutService's members. export { AppFrame, CenterColumn, DetailsColumn, type AppFrameProps } from './AppFrame.tsx' -export { - clampWidth, computeColumns, - CENTER_MIN, DETAILS_DEFAULT, DETAILS_MAX, DETAILS_MIN, SIDEBAR_DEFAULT, SIDEBAR_MAX, SIDEBAR_MIN, - type Columns, type PanelInput, -} from './columns.ts' export { LayoutService, type NavState, type PanelState, type ViewId } from './service.ts' declare module 'cordis' { diff --git a/packages/client/ui-layout/tests/app-frame.spec.tsx b/packages/client/ui-layout/tests/app-frame.spec.tsx index dfc49be327..9fae776dc4 100644 --- a/packages/client/ui-layout/tests/app-frame.spec.tsx +++ b/packages/client/ui-layout/tests/app-frame.spec.tsx @@ -10,7 +10,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { act, cleanup, render } from '@testing-library/react' import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' import { AppFrame, CenterColumn, DetailsColumn, type PanelState } from '@deepseek-ai/dsh-client-ui-layout/client' -import { clampWidth } from '@deepseek-ai/dsh-client-ui-layout/client' +import { clampWidth } from '@deepseek-ai/dsh-client-ui-layout/src/client/columns.ts' /** Observer stub: captures the callback so tests can fire resizes manually. */ let fireResize: (() => void) | null = null diff --git a/packages/client/ui-layout/tests/columns.spec.ts b/packages/client/ui-layout/tests/columns.spec.ts index 49d351a6d4..66a785e114 100644 --- a/packages/client/ui-layout/tests/columns.spec.ts +++ b/packages/client/ui-layout/tests/columns.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest' import { CENTER_MIN, clampWidth, computeColumns, DETAILS_DEFAULT, DETAILS_MIN, SIDEBAR_DEFAULT, SIDEBAR_MIN, -} from '@deepseek-ai/dsh-client-ui-layout/client' +} from '@deepseek-ai/dsh-client-ui-layout/src/client/columns.ts' const open = (width: number) => ({ open: true, width }) const closed = (width: number) => ({ open: false, width }) diff --git a/packages/client/ui-layout/tests/service.spec.ts b/packages/client/ui-layout/tests/service.spec.ts index 85d458cf7b..d5f784fa0c 100644 --- a/packages/client/ui-layout/tests/service.spec.ts +++ b/packages/client/ui-layout/tests/service.spec.ts @@ -9,7 +9,8 @@ import { beforeEach, describe, expect, it } from 'vitest' import type { Context } from 'cordis' import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' import type { SessionId, SessionListState } from '@deepseek-ai/dsh-client-runtime/client' -import { LayoutService, DETAILS_DEFAULT, SIDEBAR_DEFAULT } from '@deepseek-ai/dsh-client-ui-layout/client' +import { LayoutService } from '@deepseek-ai/dsh-client-ui-layout/client' +import { DETAILS_DEFAULT, SIDEBAR_DEFAULT } from '@deepseek-ai/dsh-client-ui-layout/src/client/columns.ts' function makeCtx() { const list = createSnapshotStore({ ids: [], byId: {} }) diff --git a/packages/client/ui-sidebar/README.md b/packages/client/ui-sidebar/README.md index 25f840ab3d..3e1bfaa11e 100644 --- a/packages/client/ui-sidebar/README.md +++ b/packages/client/ui-sidebar/README.md @@ -4,6 +4,8 @@ Sidebar plugin: session multi-level tree (cwd grouping + parentId nesting), sear `src/client/contract/slots.ts` is the single-domain contract file: `SidebarRootInjected` (the registrant's own injected share — tree hook, current-session hook, actions) and `SidebarRootComponentProps = OwnerOf<'sidebar'> & SidebarRootInjected` (the owner share referenced from ui-layout's slot declaration, never re-stated). `apply` registers SidebarRoot cast-free against that composition; the inject factory binds layout/sessions off `RootBinding`. +The `/client` export surface is the plugin body (`apply`/`inject`) plus the contract types only — SidebarRoot, the row components, and the tree/store implementation are internal (the slot registration closes over them; tests import src paths directly). + ## Model Experience None, as the sidebar renders the browser session list; nothing here reaches a model request. diff --git a/packages/client/ui-sidebar/src/client/index.ts b/packages/client/ui-sidebar/src/client/index.ts index fab3bc4836..b395cfcd01 100644 --- a/packages/client/ui-sidebar/src/client/index.ts +++ b/packages/client/ui-sidebar/src/client/index.ts @@ -3,6 +3,7 @@ * sidebar slot; tree derivation materialized in a plugin-owned snapshot * store (pure consumer — no ctx service). Contract: api-contracts v3 * section 6; props composition in contract/slots.ts. + * Export discipline: packages/client/AGENTS.md. */ import type { RootBinding } from '@deepseek-ai/dsh-client-ui-slots' import type { ClientContext, SessionId } from '@deepseek-ai/dsh-client-runtime/client' @@ -10,17 +11,6 @@ import type { SidebarRootInjected } from './contract/slots.ts' import { createSidebarTreeStore } from './store.ts' import { SidebarRoot } from './SidebarRoot.tsx' -export { - deriveRows, formatRelativeTime, projectLabel, - UNGROUPED_KEY, UNGROUPED_LABEL, - type ProjectRow, type SessionRow, type SidebarRow, type TreeView, -} from './tree.ts' -export { - createSidebarTreeStore, - type GroupBy, type SidebarTreeState, type SidebarTreeStore, -} from './store.ts' -export { ProjectRowItem, SessionRowItem } from './Rows.tsx' -export { SidebarRoot } from './SidebarRoot.tsx' export type { SidebarActions, SidebarRootComponentProps, SidebarRootInjected, SidebarTreeActions, } from './contract/slots.ts' diff --git a/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx b/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx index db03c672dd..cdad00f982 100644 --- a/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx +++ b/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx @@ -10,10 +10,9 @@ import { cleanup, fireEvent, render, screen } from '@testing-library/react' import { act } from 'react' import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' import type { SessionId, SessionListState, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' -import { - createSidebarTreeStore, SidebarRoot, - type SidebarActions, type SidebarTreeStore, -} from '@deepseek-ai/dsh-client-ui-sidebar/client' +import { createSidebarTreeStore, type SidebarTreeStore } from '../src/client/store.ts' +import { SidebarRoot } from '../src/client/SidebarRoot.tsx' +import type { SidebarActions } from '@deepseek-ai/dsh-client-ui-sidebar/client' const sid = (s: string) => s as SessionId diff --git a/packages/client/ui-sidebar/tests/store.spec.ts b/packages/client/ui-sidebar/tests/store.spec.ts index d0bb3b386b..8ded70400c 100644 --- a/packages/client/ui-sidebar/tests/store.spec.ts +++ b/packages/client/ui-sidebar/tests/store.spec.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest' import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' import type { SessionId, SessionListState, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' -import { createSidebarTreeStore } from '@deepseek-ai/dsh-client-ui-sidebar/client' +import { createSidebarTreeStore } from '../src/client/store.ts' const sid = (s: string) => s as SessionId diff --git a/packages/client/ui-sidebar/tests/tree.spec.ts b/packages/client/ui-sidebar/tests/tree.spec.ts index 1b29d460cf..3919a16d23 100644 --- a/packages/client/ui-sidebar/tests/tree.spec.ts +++ b/packages/client/ui-sidebar/tests/tree.spec.ts @@ -3,7 +3,7 @@ import type { SessionId, SessionListState, SessionSummary } from '@deepseek-ai/d import { deriveRows, formatRelativeTime, projectLabel, UNGROUPED_KEY, UNGROUPED_LABEL, type SessionRow, type TreeView, -} from '@deepseek-ai/dsh-client-ui-sidebar/client' +} from '../src/client/tree.ts' const sid = (s: string) => s as SessionId diff --git a/packages/client/ui-trajectory/src/client/index.ts b/packages/client/ui-trajectory/src/client/index.ts index b65eb3d3ab..8c8ebc330d 100644 --- a/packages/client/ui-trajectory/src/client/index.ts +++ b/packages/client/ui-trajectory/src/client/index.ts @@ -9,10 +9,8 @@ import { TrajectoryStatsHeader, type TrajectoryChromeProps } from './TrajectoryS import { TrajectoryView } from './TrajectoryView.tsx' import { WaterfallView, type WaterfallExtraProps } from './WaterfallView.tsx' -export { deriveSpans, deriveSpanStats, type SpanStats, type TurnSpan } from './spans.ts' -export { TrajectoryStatsHeader, type TrajectoryChromeProps } from './TrajectoryStatsHeader.tsx' -export { TrajectoryView } from './TrajectoryView.tsx' -export { WaterfallView, type WaterfallExtraProps } from './WaterfallView.tsx' +export type { TrajectoryChromeProps } from './TrajectoryStatsHeader.tsx' +export type { WaterfallExtraProps } from './WaterfallView.tsx' declare module '@deepseek-ai/dsh-client-ui-conversation/client' { interface ConversationViewMap { diff --git a/packages/client/ui-trajectory/tests/views.spec.tsx b/packages/client/ui-trajectory/tests/views.spec.tsx index 41a3c0c95b..0b922d4ec2 100644 --- a/packages/client/ui-trajectory/tests/views.spec.tsx +++ b/packages/client/ui-trajectory/tests/views.spec.tsx @@ -13,11 +13,15 @@ import { createElement, Fragment, type FC, type ReactNode } from 'react' import { bindSnapshotSelector, createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' import type { UseSession } from '@deepseek-ai/dsh-client-web-react' import type { ConversationSnapshot, SessionId, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' -import { ConversationRoot, ConversationService } from '@deepseek-ai/dsh-client-ui-conversation/client' +import { ConversationService } from '@deepseek-ai/dsh-client-ui-conversation/client' +// Export discipline: packages/client/AGENTS.md. +import { ConversationRoot } from '@deepseek-ai/dsh-client-ui-conversation/src/client/skeleton/ConversationRoot.tsx' import type { ConvViewProps, ViewEntry, ViewId } from '@deepseek-ai/dsh-client-ui-conversation/client' -import { - apply, deriveSpans, deriveSpanStats, inject, TrajectoryStatsHeader, TrajectoryView, WaterfallView, -} from '@deepseek-ai/dsh-client-ui-trajectory/client' +import { apply, inject } from '@deepseek-ai/dsh-client-ui-trajectory/client' +import { deriveSpans, deriveSpanStats } from '@deepseek-ai/dsh-client-ui-trajectory/src/client/spans.ts' +import { TrajectoryStatsHeader } from '@deepseek-ai/dsh-client-ui-trajectory/src/client/TrajectoryStatsHeader.tsx' +import { TrajectoryView } from '@deepseek-ai/dsh-client-ui-trajectory/src/client/TrajectoryView.tsx' +import { WaterfallView } from '@deepseek-ai/dsh-client-ui-trajectory/src/client/WaterfallView.tsx' import { apply as nodeApply } from '@deepseek-ai/dsh-client-ui-trajectory' const SID = 's1' as SessionId From 1b0ea07bceff6a8b1be8545d8d5455841298dbd9 Mon Sep 17 00:00:00 2001 From: imccyu <276526105+imccyu@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:40:30 +0800 Subject: [PATCH 143/368] =?UTF-8?q?refactor(gui):=20slot=20system=20standa?= =?UTF-8?q?rd=20=E2=80=94=20single=20register,=20four=20props=20shares,=20?= =?UTF-8?q?framework=20store=20seat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The definitive slot model for the web client, replacing the first-generation define/register two-step, ScopedSlots whitelist faces, and binding handles: - 'root' is the only a-priori slot (SlotsService built-in); the shell renders exactly ctx.slots.renderSlot('root', {}). - register is the single API: children = slot declaration + render authorization + runtime spec in one options object; misconfiguration fails loud at load (duplicate declaration, undeclared contribution, one store handle under two scopes). - Component props arrive in four auto-derived shares: PropsRuntime (owner params + session/global standard kits via declare-merge), PropsRenderSlots, PropsStore, and the inject business face. sessionId is framework-supplied; hooks are framework-made only. - Framework store seat: defineStore factories declare schema/actions/persist; read = useStore, write = baked actions only; store scope derives from the mounting entry; per-session persist keys and clearPersisted lifecycle. - inject factories read the apply closure's own ctx (binding handles retired; root-ctx back door closed); SessionProvider is self-wired render-prop. - Rendering sits behind the SlotRenderer install seam; runtime stays React-free; ownership ledger keyed to the single entry axis closes the stale-authority window (StaleAuthorizationError probes). Docs: the slot type-chain note is refreshed in place as the slot system standard RFC (bilingual pair re-recorded); the web client architecture RFC defers its slot sections there; packages/client/AGENTS.md gains the slot and props discipline; gui-testing/web-styling notes drop missions/ references. Tests: suites rewritten to the standard (props fed directly, real store engines via createXXXStore().create(), no render machinery); load-time negative samples for declaration/authorization/store conflicts; verified by real-host playwright run (three columns, empty state, collapse, keyed session remount, cross-slot selection sharing). docs(ui-sidebar): point contract reference at the committed slot standard RFC missions/ is workspace-local and never committed; the README must not cite it. --- ...7-19-gui-web-client-architecture.i18n.yaml | 4 +- .../2026-07-19-gui-web-client-architecture.md | 27 +- ...26-07-19-gui-web-client-architecture.zh.md | 27 +- ...2-slot-type-chain-implementation.i18n.yaml | 4 +- ...26-07-22-slot-type-chain-implementation.md | 100 ++- ...07-22-slot-type-chain-implementation.zh.md | 100 ++- .../2026-07-19-web-styling-system.i18n.yaml | 4 +- .../process/2026-07-19-web-styling-system.md | 2 +- .../2026-07-19-web-styling-system.zh.md | 2 +- .../2026-07-20-gui-testing-system.i18n.yaml | 4 +- .../process/2026-07-20-gui-testing-system.md | 2 +- .../2026-07-20-gui-testing-system.zh.md | 2 +- docs/web-styling.md | 2 +- packages/client/AGENTS.md | 61 +- packages/client/i18n/src/client/index.ts | 7 +- packages/client/runtime/src/client/index.ts | 36 +- .../client/runtime/src/client/loader/index.ts | 2 +- .../runtime/src/client/sessions/service.ts | 93 ++- packages/client/runtime/src/client/slots.ts | 339 ++++++++-- .../client/runtime/tests/client-apply.spec.ts | 3 + .../client/runtime/tests/invariant.spec.ts | 8 +- .../runtime/tests/sessions-service.spec.ts | 99 ++- .../runtime/tests/slots-service.spec.ts | 393 +++++++++-- packages/client/ui-conversation/README.md | 6 +- .../ui-conversation/src/client/apply.ts | 177 ++--- .../src/client/chat/ChatView.tsx | 4 +- .../src/client/chat/ToolViewOutlet.tsx | 45 +- .../src/client/contract/slots.ts | 86 +-- .../src/client/contract/toolview.ts | 11 +- .../src/client/contract/views.ts | 39 +- .../ui-conversation/src/client/index.ts | 6 +- .../ui-conversation/src/client/service.ts | 98 +-- .../src/client/skeleton/ConversationRoot.tsx | 87 ++- .../src/client/skeleton/DetailsPanel.tsx | 16 +- .../src/client/skeleton/EmptyState.tsx | 31 +- .../ui-conversation/src/client/stores.ts | 40 ++ .../tests/apply-inject.spec.tsx | 272 +++----- .../ui-conversation/tests/chat-apply.spec.tsx | 62 +- .../tests/chat-branch-tails.spec.tsx | 45 +- .../tests/chat-stats-bash-sample.spec.tsx | 1 + .../ui-conversation/tests/chat-store.spec.ts | 94 +++ .../ui-conversation/tests/chat-view.spec.tsx | 36 +- .../tests/gate-branch-tails.spec.tsx | 68 +- .../tests/selection-survival.spec.ts | 169 +++-- .../tests/service-orchestration.spec.ts | 52 +- .../tests/service-stores.spec.ts | 176 ----- .../tests/skeleton-branches.spec.tsx | 129 ++-- .../ui-conversation/tests/skeleton.spec.tsx | 159 +++-- .../tests/toolviews-type-chain.spec.ts | 10 +- .../tests/views-type-chain.spec.tsx | 11 + packages/client/ui-layout/README.md | 2 +- .../client/ui-layout/src/client/AppFrame.tsx | 88 +-- .../client/ui-layout/src/client/columns.ts | 20 +- packages/client/ui-layout/src/client/index.ts | 100 +-- .../client/ui-layout/src/client/service.ts | 142 +--- .../client/ui-layout/src/client/stores.ts | 36 + .../client/ui-layout/tests/app-frame.spec.tsx | 124 +++- packages/client/ui-layout/tests/apply.spec.ts | 28 +- .../client/ui-layout/tests/columns.spec.ts | 5 +- .../ui-layout/tests/layout-store.spec.ts | 73 ++ .../client/ui-layout/tests/service.spec.ts | 168 ++--- packages/client/ui-sidebar/README.md | 8 +- .../ui-sidebar/src/client/SidebarRoot.tsx | 54 +- .../ui-sidebar/src/client/contract/slots.ts | 59 +- .../client/ui-sidebar/src/client/index.ts | 70 +- .../client/ui-sidebar/src/client/store.ts | 94 --- packages/client/ui-sidebar/src/client/tree.ts | 19 +- packages/client/ui-sidebar/src/invariant.ts | 8 +- .../client/ui-sidebar/tests/apply.spec.tsx | 150 ++--- .../ui-sidebar/tests/sidebar-root.spec.tsx | 82 +-- .../client/ui-sidebar/tests/store.spec.ts | 111 ---- packages/client/ui-sidebar/tests/tree.spec.ts | 24 +- packages/client/ui-slots/README.md | 21 +- packages/client/ui-slots/package.json | 2 +- packages/client/ui-slots/src/index.ts | 625 +++++++++++------- packages/client/ui-slots/src/renderer.ts | 116 ++++ packages/client/ui-slots/src/store.ts | 137 ++++ packages/client/ui-slots/tests/core.spec.ts | 320 +++++---- .../client/ui-slots/tests/surface.spec.ts | 46 +- .../client/ui-slots/tests/type-chain.spec.tsx | 278 ++++---- .../client/ui-trajectory/tests/views.spec.tsx | 98 +-- packages/client/web-react/README.md | 6 +- packages/client/web-react/src/index.ts | 42 +- .../client/web-react/src/scoped-slots.tsx | 262 +++++--- .../client/web-react/src/session-provider.tsx | 119 ++-- packages/client/web-react/src/store/index.ts | 100 ++- .../tests/scoped-slots-real-core.spec.tsx | 133 ++-- .../web-react/tests/scoped-slots.spec.tsx | 608 ++++++++++------- .../web-react/tests/session-provider.spec.tsx | 199 +++--- .../tests/stale-authorization.spec.tsx | 136 ++++ packages/client/web-react/tests/store.spec.ts | 94 ++- packages/client/web/src/app.tsx | 77 +-- packages/client/web/src/boot.tsx | 9 +- packages/client/web/tests/app-root.spec.tsx | 5 +- packages/client/web/tests/boot.spec.tsx | 197 +++--- 95 files changed, 5024 insertions(+), 3322 deletions(-) create mode 100644 packages/client/ui-conversation/src/client/stores.ts create mode 100644 packages/client/ui-conversation/tests/chat-store.spec.ts delete mode 100644 packages/client/ui-conversation/tests/service-stores.spec.ts create mode 100644 packages/client/ui-layout/src/client/stores.ts create mode 100644 packages/client/ui-layout/tests/layout-store.spec.ts delete mode 100644 packages/client/ui-sidebar/src/client/store.ts delete mode 100644 packages/client/ui-sidebar/tests/store.spec.ts create mode 100644 packages/client/ui-slots/src/renderer.ts create mode 100644 packages/client/ui-slots/src/store.ts create mode 100644 packages/client/web-react/tests/stale-authorization.spec.tsx diff --git a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.i18n.yaml index 91abd32a3e..7fba74af19 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.i18n.yaml @@ -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 -2026-07-19-gui-web-client-architecture.md: 58320570f752d4259004172d3b4527172c2cc646 -2026-07-19-gui-web-client-architecture.zh.md: 744fdaa4b89a01e2710f85b177228713189e3025 +2026-07-19-gui-web-client-architecture.md: 32ec0a371f78aff8841949b983ddcca475ed6831 +2026-07-19-gui-web-client-architecture.zh.md: 8a929a3e253d26b7394ad374dc0844b03fcd8b5c diff --git a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md index 58320570f7..32ec0a371f 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md +++ b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md @@ -43,28 +43,13 @@ Dev equals prod: plugins rebuild under `tsdown --watch`, refresh reloads the sam ## The slot system: how the page composes -A page is a tree of slots; whoever owns a region declares its slots. Contracts live in one place — the `SlotMap` interface in `@deepseek-ai/dsh-client-ui-slots`, extended by declaration merging. An entry declares the slot's axes and the **owner share** only; the registrant's injected props never enter the global table ("whoever injects it, owns its type"): +The slot system has its own RFC — the [slot system standard](2026-07-22-slot-type-chain-implementation.md) — and this document defers to it entirely. The one-paragraph summary for orientation: the shell renders only `'root'`; a plugin composes UI through a single `register` call that occupies a slot, declares+authorizes its child slots (`children` spec object), declares its store, and injects its business face; component props arrive in four auto-derived shares (`PropsRuntime` / `PropsRenderSlots` / `PropsStore` / inject), each from its single source of truth. `SlotMap` declaration merging is the type authority and entries carry only the owner share ("whoever injects it, owns its type"); every rendered entry sits in a per-entry error boundary. -```ts ignore-check -declare module '@deepseek-ai/dsh-client-ui-slots' { interface SlotMap { - sidebar: { kind: 'single'; scope: 'root'; owner: SidebarOwnerProps } - conversation: { kind: 'single'; scope: 'session'; owner: ConvOwnerProps; children: 'conversation.empty' } -} } -ctx.slots.define('sidebar', { kind: 'single', scope: 'root' }) // declare=类型,define=落账 -ctx.slots.register('sidebar', SidebarRoot, { inject: (b) => ({ /* ... */ }) }) -``` - -- Three kinds: `single` (duplicate registration throws), `list` (id/order), `keyed` (runtime dispatch, duplicate key throws). Register before define throws. Two scopes: `root` (no session context) and `session` — the scope decides the injection shape below. -- **Full component props are composed by reference, never re-typed**: a registrant's component declares `OwnerOf & StandardOf & OwnInjected` — the owner share referenced from the slot owner's package, the standard share supplied by the framework (session slots: `useSession`), and the registrant's own injected share declared locally next to the component. `register` enforces the composition at the call site: the component parameter is `SlotComponent>>` (a bare call signature, not `FC` — FC's `propTypes` static position generates contravariance noise against the standard share), and `I` is inferred exclusively from the inject factory's return type (`NoInfer` pins it), so a drifted component or a mismatched factory is a compile error at the registration point. In ui-conversation the injected shares live in `src/client/contract/slots.ts` (`ConversationInjected` and kin) and each skeleton component's props is a one-line reference composition. -- **Delegation is a hand-written whitelist with an optional declared ceiling**: an owner component receives a whitelist-narrowed `slots: ScopedSlots<'a' | 'b'>` through its own props and calls `slots.renderSlot(key, props)`; passing a narrowed subset to a child goes through `narrowSlots` (pure type covariance). Overreach is a compile error, and the runtime whitelist backstops plain-JS callers. An entry may additionally declare `children: ` — register then validates the component's whitelist ⊆ the declared ceiling (opt-in visibility layer, not mandatory). Every rendered entry is wrapped in a per-entry error boundary: a crashing registrant (component or inject factory) blacks out only its own entry, while assembly errors (missing providers) rethrow — a miswired shell fails loud instead of degrading. -- **Props merge from three sources** (the outlet does it; owners write only the first): ① owner-supplied props (identity, display parameters, frozen slices) — typed as the entry's owner share, exact at the renderSlot point; ② scope-standard injection — session slots automatically receive `useSession` bound to the right Session; ③ the registrant's `inject` factory, called once per (entry × session) for session slots and once per entry for root slots, cached in WeakMaps so a session switch-back reuses the cached result. Inject factories receive the assembly handle (`SessionBinding { sessionId, session, ctx }` or `RootBinding { ctx }`) — an apply-world object that never enters React. -- Two supply channels close the loop: `RootBindingProvider` (mounted once by the shell) feeds root-slot inject factories their ctx; `createSessionProvider(deps)` builds the single session provider — dependency-inverted (`useCurrent` / `resolveBinding` / `renderBody`), so web-react never imports the runtime. It subscribes to the current session id, resolves a reference-stable binding, remounts its body under `key={id}`, and delegates body rendering to the assembler's `renderBody` closure (slot ownership stays with layout; the provider knows no slot names). - -Implementation homes: registry core in `packages/client/ui-slots` (zero dependencies), outlet/providers/uSES bridge in `packages/client/web-react`. +Implementation homes: registry core and the props-share types in `packages/client/ui-slots`, outlet/renderer/uSES bridge in `packages/client/web-react`. ## Services and scope addressing -A service is a plugin's only API surface toward other plugins (UI components and injection faces are not APIs; a plugin nobody calls mounts no service — ui-trajectory is the minimal-plugin exemplar: no ctx service, only view-map merges). The roster: `ctx.connection` (api client + stream handles), `ctx.slots` (registry wrapper emitting `slots/changed`), `ctx.sessions` (list store, scope tree, bindings), `ctx.loader`, `ctx.theme`, `ctx.i18n`, `ctx.layout` (navigation + panel viewing state), `ctx.conversation` (send/cancel/selection/views/startSession), `ctx.toolviews` (named per-tool render registry with per-session scope filters). +A service is a plugin's only API surface toward other plugins (UI components and injection faces are not APIs; a plugin nobody calls mounts no service — ui-trajectory is the minimal-plugin exemplar: no ctx service, only view-map merges). The roster: `ctx.connection` (api client + stream handles), `ctx.slots` (registry wrapper emitting `slots/changed`, render entry, renderer install seam), `ctx.sessions` (list store, current-session state, scope tree), `ctx.loader`, `ctx.theme`, `ctx.i18n`, `ctx.layout` (cross-plugin view navigation), `ctx.conversation` (send/cancel/views/startSession), `ctx.toolviews` (named per-tool render registry with per-session scope filters). Viewing state that used to live in service stores (panel widths, selection, drafts) now lives in entry-declared stores per the [slot system standard](2026-07-22-slot-type-chain-implementation.md). Beyond SlotMap, two more typed registration rings follow the same declare-merge idiom: the **view ring** (`ConversationViewMap` — an entry may declare `chromeProps`/`extraProps` extension shapes; `ConvViewPropsOf`/`ChromePropsOf` compose base + extension, so a view with no declaration gets the base for free while ui-trajectory's entries carry real per-view props) and the **tool ring** (tool names stay an open set — no global key table; typing hardens inside the entry: `ToolViewProps.block` is the real `ToolCallBlock` union defined in runtime, and register infers the registrant's injected share like slots do). @@ -101,7 +86,7 @@ Notifier 微任务合批 ──► ConversationSnapshot 缓存 ──uSES── The glue package is the whole ctx↔React boundary; components stay framework-free. -- `createSnapshotStore(init, opts)`: the store engine for plugin-owned data and shell viewing state — zustand vanilla with draft-based updates, `flush: 'sync'` by default (controlled inputs need same-tick echo) with opt-in `'raf'` batching for frame-driven stores, opt-in whole-value localStorage persistence, dev-mode deep freeze. Both a Session object and a snapshot store satisfy the one data contract React consumes: `ObservableSnapshot` (`getSnapshot`/`subscribe`). +- The snapshot store engine: zustand vanilla with draft-based updates, `flush: 'sync'` by default (controlled inputs need same-tick echo) with opt-in `'raf'` batching for frame-driven stores, opt-in whole-value localStorage persistence, dev-mode deep freeze. Plugins reach it only through `defineStore` declarations per the [slot system standard](2026-07-22-slot-type-chain-implementation.md); the framework (runtime data layer, renderer machinery) is the engine's only direct consumer. Both a Session object and a snapshot store satisfy the one data contract React consumes: `ObservableSnapshot` (`getSnapshot`/`subscribe`). - `bindSnapshotSelector(source)`: binds a source into a typed selector hook over uSES-with-selector. The four uSES contract clauses hold by construction: getSnapshot returns the cached reference; subscribe is a bind-time closure (reference-stable forever); pure CSR passes no server snapshot; equality defaults to `Object.is` with `shallowEqual` opt-in per call. - `useInvoke(fn)`: wraps an async action into a stable trigger plus pending flag; pending rides a per-hook external store read through uSES (no setState on the render path), concurrent invocations are counted, and the invoke reference never changes. - Equality protocol, whole chain: producers use structural sharing; consumers short-circuit with `Object.is` or `shallowEqual`; `React.memo` shallow. Deep comparison is banned everywhere. @@ -128,9 +113,9 @@ Domain implementation files never import a sibling domain — shared surfaces ro ## How to develop - **A new UI feature** = a new plugin package: declare `dshClient` (+ `inject` topology) in package.json, write the browser half under `src/client/` (apply mounts services/stores, registers slots and toolviews), keep the node half an empty apply unless there is host logic, build with the shared preset. Add the plugin to the host config; the manifest and loading follow automatically. -- **A new slot**: merge the contract into `SlotMap`, `define` at the owner, render through the owner's own `ScopedSlots` whitelist; registrants `register` with an optional inject factory. Never export components globally. +- **A new slot**: see the [slot system standard RFC](2026-07-22-slot-type-chain-implementation.md) — merge the contract into `SlotMap`, declare it in the parent entry's `children`, render through the auto-injected `renderSlot` prop. Never export components globally. - **Consuming a new frame type**: sessionId-bearing → a branch in Session's dispatch switch; host-level → the Manager routing table; if the UI needs it, a `ConversationSnapshot` field with the reference discipline kept. -- **Where does this state live**: per-session and must survive switches → the Session object / scope-mounted store; private to one view (selection, scroll) → component state; shell viewing state (navigation, panel widths, preferences) → `ctx.layout`'s stores; business data → always the object layer, never a viewing-state store. +- **Where does this state live**: business data (events, streaming, pending) → always the object layer; what the parent knows → owner props at the renderSlot site; private to one component (scroll, search text, expansion) → component state; shared across entries or surviving remounts (selection, drafts, panel widths) → an entry-declared store ([slot system standard](2026-07-22-slot-type-chain-implementation.md)). - **Notification channel**: frame-driven/async = `markDirty` batching; direct user-gesture echo whose controlled input needs the same tick = `notifyNow`. ## Consequences diff --git a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.zh.md b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.zh.md index 744fdaa4b8..8a929a3e25 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.zh.md @@ -43,28 +43,13 @@ dev 与 prod 同链:插件在 `tsdown --watch` 下重编译,刷新即重走 ## slot 体系:页面怎么拼 -页面是一棵坑位树;谁拥有区域谁声明坑位。契约只有一个家——`@deepseek-ai/dsh-client-ui-slots` 的 `SlotMap` 接口,经声明合并扩展。entry 只声明坑的轴与 **owner 份额**;注册方的注入 props 永不进全局表(「谁注入的放谁那里」): +slot 体系有自己的 RFC——[slot 体系标准](2026-07-22-slot-type-chain-implementation.md)——本文整体移交给它。此处只留一段定位摘要:壳只渲染 `'root'`;插件用单独一次 `register` 调用组合 UI——占坑、声明并授权子坑(`children` spec 对象)、声明 store、注入业务面;组件 props 分四份额自动推导到达(`PropsRuntime` / `PropsRenderSlots` / `PropsStore` / inject),各有唯一真源。`SlotMap` 声明合并仍是类型权威,entry 只携带 owner 份额(「谁注入的,类型归谁」);每个被渲染的注册项都在 per-entry 错误边界之内。 -```ts ignore-check -declare module '@deepseek-ai/dsh-client-ui-slots' { interface SlotMap { - sidebar: { kind: 'single'; scope: 'root'; owner: SidebarOwnerProps } - conversation: { kind: 'single'; scope: 'session'; owner: ConvOwnerProps; children: 'conversation.empty' } -} } -ctx.slots.define('sidebar', { kind: 'single', scope: 'root' }) // declare=类型,define=落账 -ctx.slots.register('sidebar', SidebarRoot, { inject: (b) => ({ /* ... */ }) }) -``` - -- 三型:`single`(重复注册即 throw)、`list`(id/order)、`keyed`(运行时按 key 分发,重 key 即 throw)。define 之前 register 即 throw。两 scope:`root`(无会话语境)与 `session`——scope 决定下述注入形态。 -- **组件全量 props 一律引用组合,不重抄**:注册方组件声明 `OwnerOf & StandardOf & OwnInjected`——owner 份额从坑位 owner 的包引用、标配份额由框架供给(session 坑:`useSession`)、注册方自己的注入份额就地声明在组件旁。`register` 在调用点强制组合:组件形参位是 `SlotComponent>>`(裸调用签名而非 `FC`——FC 的 `propTypes` 静态位对标配份额产生反变噪音),`I` 只从 inject 工厂返回值推断(`NoInfer` 钉死),组件漂移或工厂不匹配都在注册点编译报错。ui-conversation 的注入份额住 `src/client/contract/slots.ts`(`ConversationInjected` 族),各骨架组件的 props 是一行引用组合。 -- **转授=手写白名单+可选声明上限**:owner 组件经自己的 props 拿到白名单收窄的 `slots: ScopedSlots<'a' | 'b'>`,调 `slots.renderSlot(key, props)` 渲染;把收窄子集递给子组件走 `narrowSlots`(纯类型协变)。越权是编译错误,运行时白名单再兜住纯 JS 调用方。entry 可另声明 `children: `——register 校验组件白名单 ⊆ 声明上限(可选可见层,不强制)。每个被渲染的注册项都包在 per-entry 错误边界里:注册方崩溃(组件或 inject 工厂)只黑自己那一格,装配错误(缺 provider)则重抛——接错线的壳大声失败而不是静默降级。 -- **props 三源合并**(出口组件来做;owner 只写第一份):① owner 供参(身份、展示参数、冻结切片)——按 entry 的 owner 份额强类型,renderSlot 点即精确;② scope 标配注入——session 坑自动获得绑定正确 Session 的 `useSession`;③ 注册方的 `inject` 工厂,session 坑 per-(注册项 × 会话) 调一次、root 坑 per-注册项调一次,以 WeakMap 缓存——切回会话时复用缓存结果。inject 工厂收到装配句柄(`SessionBinding { sessionId, session, ctx }` 或 `RootBinding { ctx }`)——apply 世界的对象,永不进入 React。 -- 两条供给通道收拢闭环:`RootBindingProvider`(壳顶部挂一次)为 root 坑 inject 工厂供给 ctx;`createSessionProvider(deps)` 构造唯一的会话 provider——依赖倒置(`useCurrent` / `resolveBinding` / `renderBody`),web-react 永不 import runtime。它订阅当前会话 id、解析引用恒等的 binding、以 `key={id}` 重挂其 body,并把 body 渲染委托给装配方的 `renderBody` 闭包(坑位所有权留在 layout;provider 不认识坑名)。 - -实现的家:注册表纯核在 `packages/client/ui-slots`(零依赖),出口组件/provider/uSES 桥在 `packages/client/web-react`。 +实现的家:注册表核心与 props 份额类型在 `packages/client/ui-slots`,出口组件/渲染器/uSES 桥在 `packages/client/web-react`。 ## 服务与 scope 寻址 -服务是插件对其他插件的唯一 API 面(UI 组件与注入面都不是 API;无人调用的插件不挂服务——ui-trajectory 即最小插件样板:无 ctx 服务,只 merge 视图表)。名册:`ctx.connection`(api client + 流句柄)、`ctx.slots`(注册表包装层,发 `slots/changed`)、`ctx.sessions`(列表 store、scope 树、binding)、`ctx.loader`、`ctx.theme`、`ctx.i18n`、`ctx.layout`(导航 + 面板观看态)、`ctx.conversation`(send/cancel/selection/views/startSession)、`ctx.toolviews`(具名按工具渲染注册表,带按会话 scope 过滤)。 +服务是插件对其他插件的唯一 API 面(UI 组件与注入面都不是 API;无人调用的插件不挂服务——ui-trajectory 即最小插件样板:无 ctx 服务,只 merge 视图表)。名册:`ctx.connection`(api client + 流句柄)、`ctx.slots`(注册表包装层,发 `slots/changed`,渲染入口,渲染器安装缝)、`ctx.sessions`(列表 store、当前会话状态、scope 树)、`ctx.loader`、`ctx.theme`、`ctx.i18n`、`ctx.layout`(跨插件视图导航)、`ctx.conversation`(send/cancel/views/startSession)、`ctx.toolviews`(具名按工具渲染注册表,带按会话 scope 过滤)。过去住在服务 store 里的观看态(面板宽、选中、草稿)现按 [slot 体系标准](2026-07-22-slot-type-chain-implementation.md) 住 entry 声明的 store。 SlotMap 之外还有两条同 declare-merge 惯例的类型化注册环:**视图环**(`ConversationViewMap`——entry 可声明 `chromeProps`/`extraProps` 扩展形状;`ConvViewPropsOf`/`ChromePropsOf` 组合基座+扩展,无声明的视图免费得基座,ui-trajectory 的两个 entry 带真 per-view props)与**工具环**(tool 名保持开放集——无全局键表;类型强化在 entry 内部:`ToolViewProps.block` 是 runtime 定义的真 `ToolCallBlock` union,register 同 slots 一样推断注册方注入份额)。 @@ -101,7 +86,7 @@ Notifier 微任务合批 ──► ConversationSnapshot 缓存 ──uSES── 胶水包就是整条 ctx↔React 边界;组件保持零框架依赖。 -- `createSnapshotStore(init, opts)`:插件自有数据与壳观看态的 store 引擎——zustand vanilla + 草稿式更新,缺省 `flush: 'sync'`(受控输入要求同 tick 回响),帧驱动 store 可选 `'raf'` 合批,可选整值 localStorage 持久化,dev 深冻结。Session 对象与快照 store 同构满足 React 消费的唯一数据契约:`ObservableSnapshot`(`getSnapshot`/`subscribe`)。 +- 快照 store 引擎:zustand vanilla + 草稿式更新,缺省 `flush: 'sync'`(受控输入要求同 tick 回响),帧驱动 store 可选 `'raf'` 合批,可选整值 localStorage 持久化,dev 深冻结。插件只经 [slot 体系标准](2026-07-22-slot-type-chain-implementation.md) 的 `defineStore` 声明触及它;引擎的直接消费方只有框架(runtime 数据层、渲染器机械)。Session 对象与快照 store 同构满足 React 消费的唯一数据契约:`ObservableSnapshot`(`getSnapshot`/`subscribe`)。 - `bindSnapshotSelector(source)`:把一个源绑定为经 uSES-with-selector 的带类型 selector hook。uSES 契约四条按构造成立:getSnapshot 恒返缓存引用;subscribe 是绑定期闭包(引用永稳);纯 CSR 不传 server snapshot;相等性缺省 `Object.is`,按调用可选 `shallowEqual`。 - `useInvoke(fn)`:把异步动作包成引用恒定的触发器加 pending 标志;pending 走 per-hook 外部 store 经 uSES 读出(渲染路径零 setState),并发调用计数,invoke 引用永不变。 - 相等性协议,全链一致:生产端结构共享;消费端以 `Object.is` 或 `shallowEqual` 短路;`React.memo` 浅比较。深比较全链禁止。 @@ -128,9 +113,9 @@ src/client/ ## 怎么开发 - **新 UI 功能** = 新插件包:package.json 声明 `dshClient`(+ `inject` 拓扑),浏览器半边写在 `src/client/`(apply 挂服务/建 store、注册 slot 与 toolview),无 host 逻辑时 node 半边保持空 apply,用共享预设构建。把插件加进 host 配置;清单与装载随之自动跟上。 -- **新 slot**:契约合并进 `SlotMap`,owner 处 `define`,经 owner 自己的 `ScopedSlots` 白名单渲染;注册方 `register`,按需带 inject 工厂。永不全局导出组件。 +- **新 slot**:见 [slot 体系标准 RFC](2026-07-22-slot-type-chain-implementation.md)——契约合并进 `SlotMap`,在父 entry 的 `children` 里声明,经自动注入的 `renderSlot` prop 渲染。永不全局导出组件。 - **消费新帧类型**:带 sessionId → Session 分发 switch 加一个分支;host 级 → Manager 路由表;UI 需要时给 `ConversationSnapshot` 加字段并守住引用纪律。 -- **状态住哪**:per-session 且要跨切换存续 → Session 对象 / scope 挂账 store;单视图私有(选中、滚动)→ 组件状态;壳观看态(导航、面板宽、偏好)→ `ctx.layout` 的 store;业务数据 → 永远对象层,永不进观看态 store。 +- **状态住哪**:业务数据(事件、流式、待答)→ 永远对象层;父知道的 → renderSlot 现场的 owner props;单组件私有(滚动、搜索词、展开集)→ 组件状态;跨 entry 共享或跨重挂载存活(选中、草稿、面板宽)→ entry 声明的 store([slot 体系标准](2026-07-22-slot-type-chain-implementation.md))。 - **通知通道**:帧驱动/异步 = `markDirty` 合批;受控输入需要同 tick 的用户手势直接回响 = `notifyNow`。 ## Consequences diff --git a/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.i18n.yaml index 06fed08671..b1b67af99e 100644 --- a/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.i18n.yaml @@ -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 -2026-07-22-slot-type-chain-implementation.md: b4ec761b9777f5dfbd59efde8c472f9be4c2e1b6 -2026-07-22-slot-type-chain-implementation.zh.md: 28b6e4a3db0c87322582125825492703e62371b2 +2026-07-22-slot-type-chain-implementation.md: f6c5e09d53e442c4f10f30ad03d7d50729ebba0f +2026-07-22-slot-type-chain-implementation.zh.md: 61ad6e86042bb0899604461b976ab55da037a765 diff --git a/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.md b/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.md index b4ec761b97..f6c5e09d53 100644 --- a/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.md +++ b/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.md @@ -1,47 +1,109 @@ -# Agent Note: Slot type-chain hardening — the non-obvious implementation rulings +# Agent Note: The slot system standard — single register, four props shares, and the framework store seat Status: implemented English | [中文](2026-07-22-slot-type-chain-implementation.zh.md) -> Scope: why the slot registration/render type chain (`packages/client/ui-slots/src/index.ts`, consumed by `packages/client/web-react/src/scoped-slots.tsx`) is implemented the way it is. The design-level trade-offs (registration-site inference over declaration tables, hand-written whitelists over derived ones) live in the web client architecture RFC; this note pins the five implementation decisions a future editor would otherwise re-litigate or accidentally revert. +> Scope: the definitive slot-system design for the web client — how UI plugins compose the page, where render authority lives, how component props are typed, and where business live-data goes. The [web client architecture RFC](2026-07-19-gui-web-client-architecture.md) owns the surrounding context (loading chain, object layer, services) and defers its slot sections here. ## Problem -The hardened chain types every hop from `SlotMap` declaration to rendered component: owner share + framework-standard share + registrant-injected share compose into the component's props, checked at `register()`. Making that constraint hold without false rejections forced five choices that look arbitrary from the code alone — each one exists because the obvious alternative fails in a specific, reproducible way. +The page is composed at runtime from independently loaded plugins, so the UI needs a composition mechanism that answers four questions with static force. Who may render into a region — and is that authority enforceable, or merely conventional? How does a component receive everything it needs while staying a pure function (no ctx, no framework imports), without every value being hand-threaded through assembly code? Where does business live-data live so that streaming updates re-render precisely the subscribers — without every plugin building its own subscription machinery? And how much of this can the compiler check, so that a drifted component, an over-reaching render call, or a mismatched store schema is a compile error at one visible call site rather than a runtime surprise? ## Decision -### 1. `SlotComponent

    ` (bare call signature) instead of `FC

    ` at the registration position +One sentence: **the shell renders only `'root'`; a plugin composes UI through a single `register` call that simultaneously occupies a slot, declares+authorizes its child slots, declares its store, and injects its business face; components are pure functions whose props arrive in four shares, each auto-derived from its single source of truth.** -`register()` constrains components as `SlotComponent>>` where `SlotComponent

    = (props: P) => ReactNode`. React's `FC` carries static fields (`propTypes`, `defaultProps`) whose types reference `P` in covariant positions; assignability between two `FC` instantiations therefore checks those statics too, and the bottom-typed standard share (see ruling 4's `useSession: never`) makes those covariant checks reject components that narrow it — precisely the components the design wants to accept. The bare call signature checks through clean parameter contravariance only. Components stay ordinary functions; nothing observable changes at runtime. +### 'root' is the only a-priori slot -### 2. `NoInfer` pins the registrant share's inference to the inject factory +`SlotsService` (client runtime) declares `'root'` at construction — single/root, `owner: {}` — and its `SlotMap` merge lives in the runtime package. The shell's entire assembly is `ctx.slots.renderSlot('root', {})`: the only ctx-level render entry; any other key, a missing renderer, or an unregistered root fails loud (no fallback). -`I` (the registrant's injected share) must be inferred from the `inject` factory's return type — the single authoritative source. Without `NoInfer`, TS also collects inference candidates from the component parameter position, and a drifted component (consuming a key the factory does not supply) silently WIDENS `I` to make the call check, absorbing the drift instead of reporting it. `NoInfer` at the component position removes that candidate site, so negative sample ⑥ (a hand-drifted copy of the owner share fails at `register`) actually fails — with inference bleed it would pass. If the `NoInfer` ever gets "simplified away", the type-chain spec's expect-error site goes red first. +### register is the single API; children = declaration + authorization + runtime spec -### 3. `ComposedProps` dispatches on the entry's `owner` key for progressive migration +```ts ignore-check +ctx.slots.register({ + name: 'root', + children: { + 'sidebar': { kind: 'single', scope: 'root' }, + 'conversation': { kind: 'single', scope: 'session' }, + }, + store: createLayoutStore, // StoreHandle or factory (below) + inject: injectFrame, // business face (below) +}, AppFrame) +``` -`ComposedProps` composes `owner & standard & I` only when the SlotMap entry declares an `owner` share; entries without one fall back to the legacy full-`props` constraint (`PropsShape`). This conditional is the migration seam: legacy declarations keep compiling unchanged while entries opt into the composed model one at a time, and both forms flow through the same `register()` overload — no parallel API, no flag. Removing the fallback branch is the flip-the-switch moment for the whole repo, not a cleanup. +There is no separate slot-definition API. The `children` object both **declares the child slots into existence** and **authorizes this component to render them** — a slot is a hole in the render tree that exists because someone will render it, so its lifecycle is the declaring entry's lifecycle (entry disposed → slots gone, contributions cleared). The values are the runtime spec (`kind`/`scope` drive outlet iteration and binding selection; `SlotMap` is types-only and erased at runtime, which is why an array of keys could not work), statically checked against the `SlotMap` entry so type and value are declared at one point and cross-validated. -### 4. The standard share is bottom-typed, and bare `register` bivariance is accepted, not fought +Parity rule: **the declaring entry holds the exclusive right to render its child slots**, settled entirely at register time (misconfiguration fails loud at load; the render hot path carries no checks). Loud-at-load cases: a second entry declaring an already-declared slot; registering into an undeclared slot; one store handle mounted under two scopes. -Session slots' framework-supplied hook is constrained as `{ useSession: never }` (`StandardOf`): `never` in a parameter-ish position means any registrant narrowing (e.g. a runtime-typed conversation hook) is accepted, and the responsibility for what actually arrives lives with the injecting renderer. Known boundary rider: for components typed with METHOD syntax or otherwise bivariant parameter positions, TS can accept a `register` call it strictly shouldn't (parameter bivariance is unsound by design in TS). The accepted stance is documented rather than tested: we do not add negative samples that depend on strictness TS does not guarantee — they would pin compiler-version behavior, not our contract. The samples we do pin (six expect-error sites in `packages/client/ui-slots/tests/type-chain.spec.tsx`) all fail for contract reasons. +`SlotMap` declaration merging remains the type authority, and an entry declares only its own axes plus the **owner share** — the registrant's injected props never enter the global table ("whoever injects it, owns its type"). -### 5. `ChildrenChecked` is an opt-in validation layer keyed on the entry's `children` declaration +### Component props: four shares, each from its own source of truth -Sub-slot delegation authority stays a hand-written whitelist (`slots: ScopedSlots<'a' | 'b'>` in the component's own props). `ChildrenChecked` adds an optional second check: only when the entry declares `children` does the component's `slots` face get validated against the authorized union (violation collapses `slots` to `never`, surfacing at the register call). Entries without `children` pass through untouched. The hook point is inside `ComposedProps` — i.e. it fires exactly at the registration boundary, not at render — because register is where both halves (entry declaration, component face) are statically visible at once; a render-time check would need runtime plumbing for a purely static guarantee. +| Share | Type | Source of truth | Contents | +|---|---|---|---| +| runtime | `PropsRuntime` | SlotMap entry for K | `OwnerOf` (render-site params) + session-scope standard `useSession`/`sessionId` + global `useSessions` | +| child render | `PropsRenderSlots` | register's `children` keys | `renderSlot(key, owner)`, key statically narrowed to S | +| store | `PropsStore` | store factory return type | `useStore` selector hook + `actions.*` (draft-param stripped) | +| business | `I` | inject return type | plain data + callbacks (hooks banned) | + +`sessionId` is framework-supplied wherever `scope: 'session'` is declared — owner params do not carry it. The register call site is the double-lock choke point: a component whose renderSlot keys exceed the `children` declaration, or that misses a declared face, or whose store/inject shapes drift, is a compile error on that line. Delegation is ordinary props passing (hand the `renderSlot` function down, optionally behind a narrower signature) — there is no whitelist face object and no minting API. + +### The store seat: framework engine, registrant schema + +The framework owns exactly one subscription machine (the uSES snapshot store engine — zustand vanilla + immer + optional localStorage persistence). What a store *contains* is the registrant's declaration, written as a factory so no module-level handle exists (a module-scoped handle would be a de-facto singleton surviving plugin reloads): + +```ts ignore-check +export function createChatStore() { + return defineStore({ + init: () => ({ selection: null as SelectionTarget | null, draft: '' }), + persist: 'dsh.conversation.chat', + actions: { + select: (d, t: SelectionTarget) => { d.selection = t }, + clearDraft:(d) => { d.draft = '' }, + }, + }) +} +``` + +One factory, three consumption points: (a) `register` — pass the factory for an exclusive store, or call it once in `apply` and pass the same handle to several registers to share the instance (cross-plugin sharing is constructively impossible: the handle never leaves the package); (b) `PropsStore>` derives the component's store share with zero hand-written members; (c) tests call the factory and `.create()` a real engine instance, feeding `useSelector`/`actions` straight in as props — production outlets run the very same `create` path, so there is no second machinery. + +Store scope is **derived from the mounting entry's scope** (session slot → one instance per session, living and dying with the session; root slot → one per entry). Read = `props.useStore`; write = `props.actions.*` only — the raw instance (with `update`/`set`) never reaches a component, so the declared actions are the complete, auditable mutation surface. Production code never calls the factory or `create` outside `apply`. + +### inject: the registrant's business face, on its own ctx + +An inject factory takes what its declarations earn it — `sessionId` for session slots, bound `actions` when a store is declared, nothing otherwise — and reads services through the **apply closure's own ctx**, so its capability boundary is the plugin's declared `inject` topology (the cordis property proxy applies natively; there is no assembly handle carrying a wider ctx). Its return value is plain data and callbacks only: the narrowed read/write face of the plugin's own services, cross-service orchestration (e.g. `send` = `actions.clearDraft()` + `ctx.conversation.send(...)`), and per-(entry×session) assembly side effects. No hooks, no ReactNode producers, no whole-service objects — narrowing is the value: what a component can do is exactly the factory's return shape. + +### Data-boundary discipline + +Hooks are framework-made only: `useSession`, `useSessions`, `useStore`, `renderSlot` are the four seats, implemented once with framework-guaranteed correctness; business code passes plain data and callbacks between parent and child (a component's own behavioral hooks that subscribe to nothing external remain fine). Live data has exactly three channels: what the parent knows travels as owner props at the renderSlot site; what only the component knows is local state; what must be shared across entries or survive remounts is a declared store. Derivation is a pure function over framework-hook data (`useMemo`), never a subscription of its own. + +### Tree context and the renderer seam + +`SessionProvider` is a framework component, self-wired (it reads the runtime's current-session state internally; the assembler passes nothing), render-prop shaped — `children(sessionId)` with an `empty` branch, remounting under `key={sessionId}`. `BindingContext` is machinery-internal; business components see zero React contexts. Inject factories execute inside the outlet on purpose (per-entry error boundaries catch them; a crashing registrant blacks out only its own entry while assembly errors rethrow); the outlet reads tree context as a machinery-only implicit parameter — the "identity from the register closure, situation from the tree position" split. + +Rendering lives behind an install seam so the runtime stays React-free: `SlotRenderer` (interface in ui-slots, implementation `createSlotRenderer()` in web-react) is installed once at shell boot via `ctx.slots.install(...)`; double install and render-before-install throw. Ownership bookkeeping is a single `Map` in the service — ledger, slots, contributions, render bindings, and store instances all live and die on the one entry axis, which closes the stale-authority window across plugin reloads by construction (a disposed entry's captured `renderSlot` throws a stale-authorization error on entry). + +### Type-chain implementation rulings + +Two hardening decisions in the register signature exist because the obvious alternative fails in a specific, reproducible way; a future editor should not re-litigate them: + +1. **`SlotComponent

    ` (bare call signature) instead of `FC

    ` at the registration position.** React's `FC` carries static fields (`propTypes`, `defaultProps`) whose types reference `P` in covariant positions; assignability between two `FC` instantiations checks those statics too and rejects components the design wants to accept. The bare call signature checks through clean parameter contravariance only; components stay ordinary functions. +2. **`NoInfer` pins the business share's inference to the inject factory.** Without it, TS also collects inference candidates from the component parameter position, and a drifted component (consuming a key the factory does not supply) silently widens `I` to make the call check — absorbing exactly the drift the chain exists to catch. The negative-sample spec pins this: if the `NoInfer` is ever "simplified away", the expect-error site goes red first. ## Consequences -The register call site is now the chain's single choke point: share drift, missing inject keys, unauthorized sub-slot faces, and keyed/list option omissions all surface there at compile time, and the six-sample negative spec pins each failure mode. Costs: the conditional types make hover-signatures at register sites noticeably wider; the bottom-typed standard share shifts arrival-type responsibility onto web-react's renderer (documented on `StandardOf`); and the bivariance boundary means one unsound-accept class is knowingly tolerated. +Render authority is enforceable rather than conventional: who renders what is a load-time fact, and auditing the UI structure = reading the register calls. Every props surface is statically derived from one source (SlotMap entry, children keys, store factory, inject return), so a schema change propagates by compiler rather than by grep. Plugins carry no subscription machinery of their own — store lifecycle (per-session instances, disposal, persistence) is framework semantics keyed to the entry axis. Costs: registration options are dense (children spec objects); the framework carries real inference machinery (`defineStore`'s init/actions same-round inference may need a curried fallback); and the compile-time double locks mean prototype-stage drift is a hard error, not a warning. ## Alternatives considered | Rejected | One-line reason | |---|---| -| Keep `FC` and cast at register sites | The casts hide exactly the drift the chain exists to catch; FC statics' covariant noise is the mechanical cause, so remove the noise, not the check | -| Infer `I` from the component parameter | Inference bleed absorbs props drift silently — negative sample ⑥ becomes unwritable | -| Big-bang migration to composed props | Every SlotMap declarant lands in one PR; the `owner`-keyed conditional lets entries migrate one by one with both forms live | -| Test the bivariant-accept edge as a negative sample | Would pin TS soundness behavior we don't own; compiler upgrades would break the spec without any contract change | -| Derive delegation whitelists from `children` declarations | The hand-written face is the API the component author reads; derivation inverts ownership and was rejected at design level — `ChildrenChecked` validates instead of generating | +| Separate define/register two-step API | The split leaves render authority unenforced and invites ordering bugs; children-in-register settles declaration, authorization, and spec in one visible place | +| Whitelist face objects (`ScopedSlots` + narrowing helpers) | With the whitelist already in the component's props type, the face is derivable by machinery; a mintable face object is a third authority surface with runtime-only checks | +| Assembly handles carrying root ctx into inject | Bypasses declared inject topology — every factory could reach every service, so package.json dependency declarations stop meaning anything | +| `children` as a key array | kind/scope are runtime dispatch data; SlotMap is erased, so an array forces a second spec-registration API — a definition API reborn | +| Business-defined hooks via inject | Every plugin becomes its own subscription machine; the framework store seat carries the same data with one audited machine | +| Module-level store handles | A module-scope handle is a singleton across plugin reloads and test cases; the factory form scopes identity to apply/test invocation | +| Components receiving the store instance | `update`/`set` in render code makes the mutation surface unauditable; declared actions keep "what can change" a register-site fact | +| `FC` at the register position / inferring `I` from the component | FC statics generate covariant noise that rejects valid components; component-side inference absorbs props drift silently (see rulings above) | diff --git a/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.zh.md b/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.zh.md index 28b6e4a3db..61ad6e8604 100644 --- a/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.zh.md @@ -1,47 +1,109 @@ -# Agent Note: slot 类型链硬化——五条非显然实现裁定 +# Agent Note: slot 体系标准——单一 register、props 四份额与框架 store 席位 Status: implemented [English](2026-07-22-slot-type-chain-implementation.md) | 中文 -> 范围:slot 注册/渲染类型链(`packages/client/ui-slots/src/index.ts`,消费方 `packages/client/web-react/src/scoped-slots.tsx`)为什么这样实现。设计层取舍(注册点推断优于声明表、手写白名单优于派生)住 Web 客户端架构 RFC;本文钉住五条实现决定——不写下来,将来的编辑者要么重新争论一遍,要么不经意地回退它们。 +> 范围:Web 客户端 slot 体系的终版设计——UI 插件如何拼合页面、渲染权威落在哪里、组件 props 如何定型、业务活数据住在哪里。周边语境(装载链、对象层、服务)归 [Web 客户端架构 RFC](2026-07-19-gui-web-client-architecture.md) 所有,其 slot 各节移交本文。 ## Problem -硬化后的类型链给从 `SlotMap` 声明到组件渲染的每一跳定型:owner 份额 + 框架标配份额 + 注册方注入份额组合成组件 props,在 `register()` 处校验。让这条约束既成立又不误伤,逼出了五个单看代码显得任意的选择——每一个的存在都是因为显然的替代方案会以一种具体的、可复现的方式失败。 +页面在运行时由各自独立装载的插件拼合而成,UI 因此需要一套能以静态强制力回答四个问题的组合机制。谁可以渲染进某块区域——这份权威是可强制执行的,还是仅靠约定?组件如何在保持纯函数(零 ctx、零框架 import)的同时拿到它需要的一切,而不必把每个值都经装配代码手工穿线?业务活数据住在哪里,才能让流式更新恰好只重渲染订阅者——而不必每个插件自建一套订阅机械?以及这一切有多少能交给编译器检查,让漂移的组件、越权的渲染调用、错配的 store schema 成为单一可见调用点上的编译错误,而非运行时的意外? ## Decision -### 1. 注册位用 `SlotComponent

    `(裸调用签名)而非 `FC

    ` +一句话:**壳只渲染 `'root'`;插件用单独一次 `register` 调用组合 UI——这一次调用同时占坑、声明并授权子坑、声明 store、注入业务面;组件是纯函数,props 分四份额到达,每一份额都从各自唯一的真源自动推导。** -`register()` 以 `SlotComponent>>` 约束组件,其中 `SlotComponent

    = (props: P) => ReactNode`。React 的 `FC` 携带静态字段(`propTypes`、`defaultProps`),其类型在协变位引用 `P`;两个 `FC` 实例化之间的可赋性因此连这些静态位一起查,而 bottom 型的标配份额(见裁定 4 的 `useSession: never`)使这些协变检查拒绝掉收窄它的组件——恰恰是设计想接受的那批组件。裸调用签名只走干净的参数逆变检查。组件仍是普通函数;运行时零可见差异。 +### 'root' 是唯一的先验坑 -### 2. `NoInfer` 把注册方份额的推断钉在 inject 工厂上 +`SlotsService`(client 运行时)在构造时声明 `'root'`——single/root、`owner: {}`——其 `SlotMap` 合并声明住 runtime 包(package)。壳的全部装配就是 `ctx.slots.renderSlot('root', {})`:唯一的 ctx 级渲染入口;传任何其他键、渲染器未安装、root 无人注册,一律大声失败(无 fallback)。 -`I`(注册方注入份额)必须从 `inject` 工厂的返回类型推断——唯一权威源。没有 `NoInfer` 时,TS 还会从组件参数位收集推断候选,漂移的组件(消费一个工厂并不供给的键)会静默地把 `I` 加宽到让调用通过,把漂移吸收掉而不是报出来。组件位的 `NoInfer` 移除了那个候选位,负样本⑥(owner 份额的手抄漂移件在 register 处失败)才得以成立——有推断渗漏时它会通过。将来若有人把这个 `NoInfer`「顺手简化」掉,类型链 spec 的 expect-error 位会第一个变红。 +### register 是唯一 API;children = 声明+授权+运行时 spec -### 3. `ComposedProps` 按条目的 `owner` 键分派,支撑渐进迁移 +```ts ignore-check +ctx.slots.register({ + name: 'root', + children: { + 'sidebar': { kind: 'single', scope: 'root' }, + 'conversation': { kind: 'single', scope: 'session' }, + }, + store: createLayoutStore, // StoreHandle or factory (below) + inject: injectFrame, // business face (below) +}, AppFrame) +``` -`ComposedProps` 只在 SlotMap 条目声明了 `owner` 份额时才组合 `owner & standard & I`;未声明的条目回落到 legacy 全量 `props` 约束(`PropsShape`)。这个条件类型就是迁移接缝:legacy 声明原样编译,条目逐个转入组合模型,两种形态走同一个 `register()`——无平行 API、无开关旗。删掉回落分支的那一刻=全仓切换时刻,不是一次清理。 +不存在独立的坑位定义 API。`children` 对象同时做两件事:**把子坑声明出来**,并**授权本组件渲染它们**——坑是渲染树上的一个洞,因为有人要渲染它才存在,所以坑的生命周期就是声明它的 entry 的生命周期(entry 一经 dispose(资源释放),坑随之消亡、坑内既有贡献清空)。children 的值是运行时 spec(`kind`/`scope` 驱动 outlet 的迭代形态与 binding 选择;`SlotMap` 是纯类型、运行时即被擦除,这正是键数组形行不通的原因),并与对应 `SlotMap` entry 静态对齐校验——类型与值在同一点声明、交叉验证。 -### 4. 标配份额 bottom 型化;裸 `register` 的双变接受面认账不硬测 +对等原则:**声明子坑的 entry 独占渲染这些子坑的权力**,全部在 register 时结清(配置错误在装载时大声失败;渲染热径零校验)。装载即炸的情形:第二个 entry 声明已被声明的坑;向未声明的坑 register;同一个 store 句柄挂到两个 scope 之下。 -session 坑的框架供给 hook 约束为 `{ useSession: never }`(`StandardOf`):参数性位置上的 `never` 意味着任何注册方收窄(如 runtime 定型的会话 hook)都被接受,实际到达什么的类型责任归注入侧渲染器。已知边界搭车项:对以方法语法定型或参数位本就双变的组件,TS 可能接受一个严格意义上不该过的 `register` 调用(参数双变是 TS 的有意不健全)。这个立场以文档记账而不加测试:我们不写依赖 TS 并不承诺的严格性的负样本——那钉住的是编译器版本行为,不是我们的契约。真正钉住的六个 expect-error 位(`packages/client/ui-slots/tests/type-chain.spec.tsx`)全部因契约原因失败。 +`SlotMap` 声明合并仍是类型权威,且 entry 只声明自己的轴加 **owner 份额**——注册方注入的 props 永不进入全局表(「谁注入的,类型归谁」)。 -### 5. `ChildrenChecked` 是按条目 `children` 声明挂载的 opt-in 校验层 +### 组件 props:四份额,各有唯一真源 -子坑转授权威仍是手写白名单(组件自己 props 上的 `slots: ScopedSlots<'a' | 'b'>`)。`ChildrenChecked` 加一层可选的第二道检查:仅当条目声明了 `children`,组件的 `slots` 面才对照授权并集校验(越界时 `slots` 坍缩为 `never`,在 register 调用处暴露)。未声明 `children` 的条目原样通过。挂点选在 `ComposedProps` 内部——即恰好在注册边界而非渲染期起效——因为 register 是条目声明与组件面两个半边同时静态可见的唯一位置;渲染期检查要为一个纯静态保证铺运行时管线。 +| 份额 | 类型 | 真源 | 内容 | +|---|---|---|---| +| 运行时 | `PropsRuntime` | K 对应的 SlotMap entry | `OwnerOf`(渲染现场传参)+ session scope 标配 `useSession`/`sessionId` + 全局 `useSessions` | +| 子坑渲染 | `PropsRenderSlots` | register 的 `children` 键集 | `renderSlot(key, owner)`,键参静态收窄到 S | +| store | `PropsStore` | store 工厂的返回类型 | `useStore` selector hook + `actions.*`(剥去 draft 形参) | +| 业务 | `I` | inject 的返回类型 | 普通数据+回调(禁 hook) | + +凡声明 `scope: 'session'` 之处,`sessionId` 一律由框架供给——owner 传参不携带它。register 调用点是双向锁的收口:组件的 renderSlot 键集超出 `children` 声明、漏接某个已声明的面、store/inject 形状漂移,任何一条都在那一行上报编译错误。转授就是普通的 props 传递(把 `renderSlot` 函数递下去,可按需包一层更窄的签名)——不存在白名单面对象,也不存在铸面 API。 + +### store 席位:引擎归框架,schema 归注册方 + +框架拥有恰好一台订阅机械(uSES 快照 store 引擎——zustand vanilla + immer + 可选 localStorage 持久化)。store 里*装什么*是注册方的声明,且必须写成工厂函数,使模块级句柄根本无从存在(模块级句柄会成为跨插件重载存活的事实单例): + +```ts ignore-check +export function createChatStore() { + return defineStore({ + init: () => ({ selection: null as SelectionTarget | null, draft: '' }), + persist: 'dsh.conversation.chat', + actions: { + select: (d, t: SelectionTarget) => { d.selection = t }, + clearDraft:(d) => { d.draft = '' }, + }, + }) +} +``` + +一个工厂,三个消费点:① `register`——独占 store 直接传工厂;要共享实例,则在 `apply` 里调用一次工厂、把同一句柄传给多次 register(跨插件共享构造性不可能:句柄从不出包);② `PropsStore>` 推导出组件的 store 份额,零手写成员;③ 测试自己调用工厂并 `.create()` 出真引擎实例,把 `useSelector`/`actions` 直接当 props 喂进去——生产 outlet 走的正是同一条 `create` 路径,不存在第二套机械。 + +store 的 scope **从挂载 entry 的 scope 推导**(session 坑→每个会话一个实例,随会话生灭;root 坑→每个 entry 一个)。读 = `props.useStore`;写 = 仅 `props.actions.*`——裸实例(带 `update`/`set`)永远到不了组件,声明的 actions 就是完整且可审计的变更面。生产代码在 `apply` 之外从不调用工厂或 `create`。 + +### inject:注册方的业务面,立足自己的 ctx + +inject 工厂只收其声明挣来的形参——session 坑得 `sessionId`,声明了 store 的得绑定好的 `actions`,否则无参——取服务一律经 **apply 闭包自己的 ctx**,其能力边界因此就是本插件声明的 `inject` 拓扑(cordis property proxy 原生生效;不存在携带更宽 ctx 的装配句柄)。返回值只含普通数据与回调:本插件自有服务的收窄读写面、跨服务编排(如 `send` = `actions.clearDraft()` + `ctx.conversation.send(...)`)、以及 per-(entry×session) 的装配副作用。禁 hook、禁 ReactNode 生产者、禁递整个服务对象——收窄本身就是价值:组件能做什么,恰由工厂返回值的形状圈定。 + +### 数据界线纪律 + +hook 只许框架造:`useSession`、`useSessions`、`useStore`、`renderSlot` 是仅有的四席,各实现一次、正确性由框架担保;业务代码在父子组件之间只传普通数据与回调(组件自用、不订阅任何外部数据源的行为 hook 不在此限)。活数据恰有三条通道:父知道的,作为 owner props 在 renderSlot 现场传入;只有组件自己知道的,是本地 state;需要跨 entry 共享或跨重挂载存活的,是声明的 store。派生是对框架 hook 数据做纯函数(`useMemo`),绝不自成一路订阅。 + +### 树上语境与渲染器安装缝 + +`SessionProvider` 是框架组件,框架自接线(内部自读 runtime 的当前会话状态,装配方零传参),render-prop 形——`children(sessionId)` 外加 `empty` 分支,以 `key={sessionId}` 重挂。`BindingContext` 属机械内部;业务组件可见的 React Context 为零。inject 工厂有意在 outlet 内部执行(per-entry 错误边界接得住它们;崩溃的注册方只黑掉自己那一格,装配错误则重抛);outlet 把树上语境当作仅机械可用的暗参读取——即「身份出自 register 闭包、现场出自树位置」的分工。 + +渲染住在一条安装缝之后,runtime 因此保持 React-free:`SlotRenderer`(接口住 ui-slots,实现 `createSlotRenderer()` 住 web-react)在壳 boot 时经 `ctx.slots.install(...)` 安装一次;双重安装与安装前渲染均 throw。归属记账是服务里的单一 `Map`——账本、坑、贡献、渲染绑定、store 实例全部沿同一条 entry 轴生灭,跨插件重载的陈旧权威窗口由此在构造上关闭(已 dispose 的 entry 所捕获的 `renderSlot`,一进入口即抛陈旧授权(stale-authorization)错误)。 + +### 类型链实现裁定 + +register 签名里的两条硬化裁定之所以存在,是因为显然的替代方案会以具体、可复现的方式失败;将来的编辑者不应重新争论它们: + +1. **注册位用 `SlotComponent

    `(裸调用签名)而非 `FC

    `。** React 的 `FC` 携带静态字段(`propTypes`、`defaultProps`),其类型在协变位引用 `P`;两个 `FC` 实例化之间的可赋性检查连这些静态位一起查,会拒绝设计本想接受的组件。裸调用签名只走干净的形参逆变检查;组件仍是普通函数。 +2. **`NoInfer` 把业务份额的推断钉在 inject 工厂上。** 没有它,TS 还会从组件形参位收集推断候选,漂移的组件(消费一个工厂并不供给的键)会静默把 `I` 加宽到让调用通过——恰好吸收掉类型链本要抓的漂移。负样本 spec 钉住这一点:若这个 `NoInfer` 日后被「顺手简化」掉,expect-error 位会第一个变红。 ## Consequences -register 调用点成为全链唯一收口:份额漂移、inject 键缺失、越权子坑面、keyed/list options 缺省全部在编译期于此暴露,六样本负样本 spec 逐一钉住失败模式。代价:条件类型让 register 位的悬停签名明显变宽;bottom 型标配份额把到达类型的责任转给 web-react 渲染器(记录于 `StandardOf`);双变边界意味着一类不健全接受被知情容忍。 +渲染权威从此可强制执行,而非仅靠约定:谁渲染什么是装载期事实,审计 UI 结构 = 通读 register 调用。每个 props 面都从单一真源静态推导(SlotMap entry、children 键集、store 工厂、inject 返回值),schema 变更由编译器传播,而不靠 grep。插件不再自带任何订阅机械——store 生命周期(每会话实例、dispose、持久化)是钉在 entry 轴上的框架语义。代价:注册选项稠密(children spec 对象);框架背上实打实的推断机械(`defineStore` 的 init/actions 同轮推断可能需要柯里化兜底);编译期双向锁意味着原型阶段的漂移直接是硬错误,而非警告。 ## Alternatives considered | Rejected | One-line reason | |---|---| -| 保留 `FC`、在 register 位 cast | cast 恰好藏起类型链要抓的漂移;FC 静态位的协变噪音是机械成因,该移除噪音而非移除检查 | -| 从组件参数位推断 `I` | 推断渗漏静默吸收 props 漂移——负样本⑥无从写起 | -| 组合 props 一次性全仓迁移 | 所有 SlotMap 声明方挤进一个 PR;`owner` 键分派让条目逐个迁移、两形态共存 | -| 给双变接受边缘加负样本 | 钉住的是我们不拥有的 TS 健全性行为;编译器升级会在契约零变化时打红 spec | -| 从 `children` 声明派生转授白名单 | 手写面才是组件作者读到的 API;派生反转所有权,设计层已否——`ChildrenChecked` 做校验不做生成 | +| 独立的 define/register 两步式 API | 拆分让渲染权威无从强制、招来时序 bug;children 进 register 让声明、授权、spec 在同一个可见位置结清 | +| 白名单面对象(`ScopedSlots` + 收窄辅助件) | 白名单已在组件的 props 类型里,面可由机械推导;可铸造的面对象是第三个权威面,且只有运行时校验 | +| 装配句柄把 root ctx 带进 inject | 绕开声明的 inject 拓扑——每个工厂都摸得到每个服务,package.json 的依赖声明就此失去意义 | +| `children` 用键数组形 | kind/scope 是运行时分派数据;SlotMap 已被擦除,数组形必然逼出第二个 spec 注册 API——定义 API 复活 | +| 业务经 inject 自定义 hook | 每个插件都变成自己的订阅机械;框架 store 席位用一台受审计的机械承载同样的数据 | +| 模块级 store 句柄 | 模块级句柄是跨插件重载与跨测试用例的单例;工厂形把身份圈定在单次 apply/测试调用内 | +| 组件直收 store 实例 | 渲染代码里能用 `update`/`set`,变更面就无从审计;声明的 actions 让「什么能变」保持为 register 现场的事实 | +| 注册位用 `FC` / 从组件推断 `I` | FC 静态位产生协变噪音、拒绝合法组件;组件侧推断静默吸收 props 漂移(见上文裁定) | diff --git a/.agents/notes/implemented/process/2026-07-19-web-styling-system.i18n.yaml b/.agents/notes/implemented/process/2026-07-19-web-styling-system.i18n.yaml index eacf4ef13d..9daf021e6e 100644 --- a/.agents/notes/implemented/process/2026-07-19-web-styling-system.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-19-web-styling-system.i18n.yaml @@ -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 -2026-07-19-web-styling-system.md: c80ef0d56a0e57b38fbb52bd07cbc0f69ec85912 -2026-07-19-web-styling-system.zh.md: 59013a4a950196f3a065ac18415f9b5ed42f3ec3 +2026-07-19-web-styling-system.md: b4d647924ab6ab172cd7a7e2531a10a2a7e62981 +2026-07-19-web-styling-system.zh.md: 01064d4d52b3ed2b179a4795f5113b94480945bd diff --git a/.agents/notes/implemented/process/2026-07-19-web-styling-system.md b/.agents/notes/implemented/process/2026-07-19-web-styling-system.md index c80ef0d56a..b4d647924a 100644 --- a/.agents/notes/implemented/process/2026-07-19-web-styling-system.md +++ b/.agents/notes/implemented/process/2026-07-19-web-styling-system.md @@ -2,7 +2,7 @@ Status: implemented -> Token-system update (2026-07-22): the framework rulings here (CSS Modules + clsx, no component library, no tailwind, tokens-only colors) remain in force, but the two-layer `--bg-*`/`--text-*` token table and its `web-ui/src/style/global.css` home were replaced by the `--dsw-*` static+alias sheets in `packages/client/ui-theme/src/styles/` (dark = `body[data-ds-dark-theme]` override). Current authority: `missions/tasks/20260721-1520-web-plugin-rfc/architecture.md` §15. +> Token-system update (2026-07-22): the framework rulings here (CSS Modules + clsx, no component library, no tailwind, tokens-only colors) remain in force, but the two-layer `--bg-*`/`--text-*` token table and its `web-ui/src/style/global.css` home were replaced by the `--dsw-*` static+alias sheets in `packages/client/ui-theme/src/styles/` (dark = `body[data-ds-dark-theme]` override) — the sheets themselves are the token authority. English | [中文](2026-07-19-web-styling-system.zh.md) diff --git a/.agents/notes/implemented/process/2026-07-19-web-styling-system.zh.md b/.agents/notes/implemented/process/2026-07-19-web-styling-system.zh.md index 59013a4a95..01064d4d52 100644 --- a/.agents/notes/implemented/process/2026-07-19-web-styling-system.zh.md +++ b/.agents/notes/implemented/process/2026-07-19-web-styling-system.zh.md @@ -2,7 +2,7 @@ Status: implemented -> token 体系更新(2026-07-22):本文框架裁决(CSS Modules + clsx、无组件库、无 tailwind、组件只用 token)仍然生效,但两层 `--bg-*`/`--text-*` token 表及其宿主 `web-ui/src/style/global.css` 已被 `packages/client/ui-theme/src/styles/` 的 `--dsw-*` static+alias 双层表取代(暗色=`body[data-ds-dark-theme]` 覆写)。现行权威:`missions/tasks/20260721-1520-web-plugin-rfc/architecture.md` §15。 +> token 体系更新(2026-07-22):本文框架裁决(CSS Modules + clsx、无组件库、无 tailwind、组件只用 token)仍然生效,但两层 `--bg-*`/`--text-*` token 表及其宿主 `web-ui/src/style/global.css` 已被 `packages/client/ui-theme/src/styles/` 的 `--dsw-*` static+alias 双层表取代(暗色=`body[data-ds-dark-theme]` 覆写)——样式表本身即 token 权威。 [English](2026-07-19-web-styling-system.md) | 中文 diff --git a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.i18n.yaml b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.i18n.yaml index 6b2f1de1e0..71ea20f6ee 100644 --- a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.i18n.yaml @@ -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 -2026-07-20-gui-testing-system.md: db1b47566f5aa089ffcb10d130ecde1851b93112 -2026-07-20-gui-testing-system.zh.md: 691c6baf50c1025a09461effd28ac0f1650fb933 +2026-07-20-gui-testing-system.md: fdd5c7f9d33f9a90ea4afe145265be5fe93e0fc2 +2026-07-20-gui-testing-system.zh.md: 0ae08133742711b87e9155ddc6f3104b757c1b55 diff --git a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.md b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.md index db1b47566f..fdd5c7f9d3 100644 --- a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.md +++ b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.md @@ -2,7 +2,7 @@ Status: implemented -> Path update (2026-07-22, plugin-system refactor): the three-tier philosophy and golden-path method here remain current; homes moved — object-layer specs now live in `packages/client/runtime/tests/` (was web-runtime), wire specs in `packages/client/connection/tests/`, and the `web-ui` coverage exclusion is gone with the package (component specs are per-plugin jsdom suites under each `packages/client/*/tests/`). Current test-system authority: `missions/tasks/20260721-1520-web-plugin-rfc/architecture.md` §18. +> Path update (2026-07-22, plugin-system refactor): the three-tier philosophy and golden-path method here remain current; homes moved — object-layer specs now live in `packages/client/runtime/tests/` (was web-runtime), wire specs in `packages/client/connection/tests/`, and the `web-ui` coverage exclusion is gone with the package (component specs are per-plugin jsdom suites under each `packages/client/*/tests/`). Component-spec shape follows the [slot system standard](../architecture/2026-07-22-slot-type-chain-implementation.md): feed props directly — the store share comes from `createXXXStore().create()` (the real engine, the sanctioned zero-machinery path), framework hooks are plain stubs; no render machinery, no provider mounting. Slot ownership/registry semantics are tier-2 territory (`runtime` + `ui-slots` suites), not component specs. English | [中文](2026-07-20-gui-testing-system.zh.md) diff --git a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.zh.md b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.zh.md index 691c6baf50..0ae0813374 100644 --- a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.zh.md +++ b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.zh.md @@ -2,7 +2,7 @@ Status: implemented -> 路径更新(2026-07-22,插件体系重构):本文三层理念与金路径方法仍为现行;家搬了——对象层 spec 现居 `packages/client/runtime/tests/`(原 web-runtime)、wire spec 现居 `packages/client/connection/tests/`,`web-ui` 覆盖豁免随包消亡(组件 spec 为各 `packages/client/*/tests/` 的 jsdom 套件)。测试体系现行权威:`missions/tasks/20260721-1520-web-plugin-rfc/architecture.md` §18。 +> 路径更新(2026-07-22,插件体系重构):本文三层理念与金路径方法仍为现行;家搬了——对象层 spec 现居 `packages/client/runtime/tests/`(原 web-runtime)、wire spec 现居 `packages/client/connection/tests/`,`web-ui` 覆盖豁免随包消亡(组件 spec 为各 `packages/client/*/tests/` 的 jsdom 套件)。组件 spec 形态遵循 [slot 体系标准](../architecture/2026-07-22-slot-type-chain-implementation.md):props 直喂——store 份额来自 `createXXXStore().create()`(真引擎,获认可的零机械路径),框架 hook 用普通桩;无渲染机械、不挂 provider。坑位归属/注册表语义归 2 层地界(`runtime` + `ui-slots` 套件),不归组件 spec。 [English](2026-07-20-gui-testing-system.md) | 中文 diff --git a/docs/web-styling.md b/docs/web-styling.md index d2b07ea2b5..0b6aeb55d5 100644 --- a/docs/web-styling.md +++ b/docs/web-styling.md @@ -1,6 +1,6 @@ # Web GUI 样式规范 -> **【token 体系已换代——§1 表格仅历史参考】** 本文的 `--bg-*`/`--text-*`/`--accent` token 族与其宿主包 `packages/client/web-ui` 已随插件化重构退役。现行 token 唯一来源=`packages/client/ui-theme/src/styles/` 的 `--dsw-*` 体系(static 色阶+alias 语义层,暗色=`body[data-ds-dark-theme]` 覆写);组件对账基准=`missions/tasks/20260721-1520-web-plugin-rfc/style-spec.md`。**仍然有效**:工程约束(CSS Modules + clsx、无组件库、无 tailwind、组件禁 hardcode 色值)、字号成对写行高、间距 4 倍数、代码字体栈末位不放 monospace——这些已收编进 architecture.md §15。 +> **【token 体系已换代——§1 表格仅历史参考】** 本文的 `--bg-*`/`--text-*`/`--accent` token 族与其宿主包 `packages/client/web-ui` 已随插件化重构退役。现行 token 唯一来源=`packages/client/ui-theme/src/styles/` 的 `--dsw-*` 体系(static 色阶+alias 语义层,暗色=`body[data-ds-dark-theme]` 覆写),sheet 即权威、组件对账以它为准。**仍然有效**:工程约束(CSS Modules + clsx、无组件库、无 tailwind、组件禁 hardcode 色值)、字号成对写行高、间距 4 倍数、代码字体栈末位不放 monospace。 > 状态:原「活文档」(随 `packages/client/web-ui` 演进)。视觉基线源自对 deepseekchat 前端仓的实测调研。框架决策与工程约束由 [web-styling-system RFC](../.agents/notes/implemented/process/2026-07-19-web-styling-system.md) 拍板,本文不重复论证。 diff --git a/packages/client/AGENTS.md b/packages/client/AGENTS.md index 7d15bfc0ba..08290791f8 100644 --- a/packages/client/AGENTS.md +++ b/packages/client/AGENTS.md @@ -1,50 +1,51 @@ # AGENTS.md — Web client stack -Rules for `packages/client/*` (the browser side of the dsh web GUI) plus its build entry `apps/web`. They supplement the repo-wide [conventions](../../AGENTS.md#conventions) and the [package rules](../README.md); read the two architecture notes linked below before structural changes. +Rules for `packages/client/*` (the browser side of the dsh web GUI) plus its build entry `apps/web`. They supplement the repo-wide [conventions](../../AGENTS.md#conventions) and the [package rules](../README.md). Before touching slots, component props, stores, or plugin structure, read the [slot system standard](../../.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.md) (the definitive composition model) and the [web client architecture note](../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md) (loading chain, object layer, services). Packages here are named with the directory prefix: `@deepseek-ai/dsh-client-`. +## Slot and props discipline + +The [slot system standard](../../.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.md) owns the full design; these are the rules you must not violate when writing or reviewing client code: + +1. **One API**: a plugin composes UI only through `ctx.slots.register({ name, children?, store?, inject? }, Component)`. There is no separate slot-definition call, no whitelist face object, no face-minting helper. The shell alone renders `'root'`. +2. **children = declaration + authorization**: the slots your component renders are exactly the keys of your register call's `children` object (spec values: `kind`/`scope`). Rendering a slot you didn't declare, or declaring one someone else declared, fails at load — do not work around it; the conflict is the design speaking. +3. **Component props are the four shares, all derived**: `PropsRuntime` (SlotMap: owner params + `useSession`/`sessionId` on session scope + `useSessions`) & `PropsRenderSlots` (children keys) & `PropsStore` (store factory) & the inject face. Never hand-write a member a share already derives; never re-type a share locally. +4. **Hooks are framework-made only**: `useSession`, `useSessions`, `useStore`, `renderSlot` are the four seats. Business code never creates a hook or selector as a prop value — pass plain data and callbacks. (Component-internal behavioral hooks that subscribe to nothing external are fine.) +5. **Live data has exactly three channels**: parent knows it → owner props at the renderSlot site; only the component knows it → local state; shared across entries or survives remounts → a store declared at register. Derived data is a pure function over framework-hook data (`useMemo`), never its own subscription. +6. **Stores: read `props.useStore`, write `props.actions.*`** — the declared actions are the complete mutation surface. Write the store as an exported `createXXXStore()` factory (module-level handles are forbidden — de-facto singletons); share by passing one handle to several registers inside `apply`. Production code never calls the factory or `.create()` outside `apply`; tests do (that is the sanctioned zero-machinery path). +7. **inject returns plain data and callbacks** from the apply closure's own ctx — no hooks, no ReactNode producers, no whole-service objects. Its capability boundary is the plugin's declared `inject` topology; there is no wider ctx to reach for. + ## Export discipline (client plugin packages) The `/client` surface of a UI plugin package is a contract face, not a convenience barrel. Three rules, enforced package-wide (do not restate them as per-file comments): -1. **A UI plugin exports no values beyond what cordis loading needs** — `apply` / `inject` (and `Config` where present). Types are the extra allowance: contract types (OwnerShare shapes, injected shapes, view/toolview entry types) export freely. Implementation components, pure helpers, constants, and stores stay internal. Existing value exports beyond this line (the ui-layout frame components consumed by the shell assembler, service classes kept for `import type`) are grandfathered per-consumer; adding a new one requires user sign-off, not a matching export. +1. **A UI plugin exports no values beyond what cordis loading needs** — `apply` / `inject` (and `Config` where present), plus store factories consumed type-only by components (`ReturnType`). Types are the extra allowance: contract types (owner shares, injected shapes, view/toolview entry types) export freely. Implementation components, pure helpers, constants, and store handles stay internal. Adding any new value export requires user sign-off, not a matching consumer. 2. **Same-package tests import internals directly** — relative `../src/client/xxx.ts` from package tests, or the `./src/*` subpath where a spec lives outside the package. Never widen the public surface to make a test compile. -3. **Cross-package imports of another plugin's symbols are in principle forbidden.** The sanctioned routes are the slot system (define/register/renderSlot, the view and toolview registries) and ctx services. If neither fits, stop and escalate — do not add an export to unblock yourself. +3. **Cross-package imports of another plugin's symbols are in principle forbidden.** The sanctioned routes are the slot system (register/renderSlot, the view and toolview registries) and ctx services. If neither fits, stop and escalate — do not add an export to unblock yourself. + +## ctx discipline (components never see ctx) + +`ctx` belongs to the apply world only: the plugin body and the inject factories closed over it. Components — every `.tsx` under a feature domain — receive all data and callbacks **through the four props shares**; they never call a hook that reaches ctx, never import a service class to poke it, never read a React context (business components see zero contexts — `BindingContext` and its kin are renderer-internal). If a component needs something new, the answer is a prop threaded from its share's source (owner site, store declaration, or inject face), not a hook. ## Layering red lines -The stack is three layers with one-way knowledge, settled in the [web client architecture note](../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md): +The stack has one-way knowledge, settled in the [web client architecture note](../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md): -1. **Data object layer** (`web-runtime`, React-free): `ConnectionController` → `SessionManager` → `Session` own all business state (event windows, streaming accumulation, reconnect machine). Zero React imports — grep-assertable. -2. **Hooks layer** (`web-ui/src/hooks`, pure data): subscribes to object snapshots via `useSyncExternalStore`, exposes plain-data handles. No JSX, no DOM. -3. **Presentation components** (`web-ui`, pure props): consumables, expected to be rewritten wholesale. Business logic must not leak into them; they receive data and callbacks through props only. +1. **Data object layer** (`runtime`'s sessions machinery, React-free): `ConnectionController` → `SessionManager` → `Session` own all business state (event windows, streaming accumulation, reconnect machine). Zero React imports — grep-assertable. +2. **Render machinery** (`web-react`): the whole ctx↔React boundary — slot renderer/outlets, `SessionProvider`, the uSES bridge, the store engine. The only code that reads React contexts or runs subscriptions. +3. **Presentation components** (plugin packages' `src/client/`, pure props): consumables, expected to be rewritten wholesale. Business logic must not leak into them; everything arrives through the four props shares. Non-negotiables across the layers: -- **No business objects in the store.** zustand carries cross-view presentation state only (`rpcLog`, `ui`, `connection` slices). Sessions, frames, and connections live in the object layer. View-local facts (selection, expansion) stay in component state, not the store. +- **Business data lives in the object layer, never a store.** Entry-declared stores carry shared viewing/interaction state (selection, drafts, panel widths); sessions, frames, and connections stay in the object layer. - **rpcId is strictly bidirectional**: the initiator mints, the responder echoes; business signatures see only `RpcRequest

    `, minting stays in the carrier layer ([layering and RPC protocol note](../../.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md)). -- **Notifier dual-channel discipline**: `notifyNow` only as the direct echo of a user gesture; frame-driven updates always go through `markDirty` (microtask-batched). See `web-runtime/src/session/notifier.ts`. +- **Notifier dual-channel discipline**: `notifyNow` only as the direct echo of a user gesture; frame-driven updates always go through `markDirty` (microtask-batched). See `runtime/src/client/sessions/notifier.ts`. - **The web layer is pure presentation.** Nothing that is "how to draw" (tool-card views, queue states) enters the session log; the host computes such data per frame or pushes it live, and replay recomputes it — falling back to the generic form when it can't. A new *model-visible* input still requires a session event (repo-wide rule). -## Directory regime (`web-ui/src`) +## Directory regime (plugin packages) -> Shell restructure in progress: the tree is converging to this layout (today's `components/{conversation,sessions,panels}` migrate into it); the regime below is the target every new feature follows now. - -Two-level feature directories, one contributor per directory — physical conflict avoidance: - -``` -web-ui/src/ - shell/ # AppShell + the three slot registries + builtins - leftmenu// # one directory per left-nav bar (sessions, rpclog, …) - sessiontabs// # one directory per session tab (conversation, gantt, …) - components/ # shared leaves (MessageText, JsonBlock, …) - hooks/ utils/ style/ # cross-cutting; not feature-owned -``` - -- `leftmenu/` must not import `leftmenu/` or `sessiontabs/*` (and vice versa). Anything two features need sinks into `components/`. -- Bars, tabs, and detail blocks register through the `shell/` registries (module-level map, `register*()` returns the disposer — same shape as `toolCardRegistry`). v1 registration is static in `shell/builtins.ts`; plugin-driven registration later calls the same functions. -- **Claiming a placeholder slot**: pick a `placeholder: true` tab (or add a bar) in `shell/builtins.ts`, create your feature directory, and replace the placeholder component with your container. Don't build features outside this regime. +One UI feature = one plugin package (`src/client/` browser half). A multi-domain package splits by future package boundaries — ui-conversation is the exemplar: `contract/` (the only shared face), domain directories that never import a sibling domain, and `apply.ts` as the single cross-domain assembly point; `scripts/verify-client-domain-graph.ts` enforces the levels. Registration goes through the slot/view/toolview registries in `apply` — never module-level side effects. ## Styling @@ -71,9 +72,9 @@ If `test:gui` is red on code you did not touch, neither silently fix nor ignore ## New component checklist -1. Claim the slot (see the directory regime above): one feature, one directory. -2. Build the container in your feature directory; keep leaves pure-props. Wire data through the hooks layer, not by importing business objects into components. -3. Copy a neighbouring jsdom spec into `web-ui/tests/`, keep it behavior-shaped: start from the happy path and the edge states, then widen until the component's branches are covered — the coverage gate applies; only the assertion style stays behavior-level. +1. Compose through register: merge the slot contract into `SlotMap`, declare the slot in its parent entry's `children`, register your component — see the [slot system standard](../../.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.md). No other composition route exists. +2. Type the props as the four shares (`PropsRuntime` & `PropsRenderSlots` & `PropsStore` & inject face) — derive, don't hand-write. Shared/surviving state goes in a `createXXXStore()` factory declared at register; component-private state stays local. +3. Component tests feed props directly (`createXXXStore().create()` for the store share; plain stubs for framework hooks) — behavior-shaped assertions, no render machinery. 4. Tokens only in CSS; Chinese product copy; English comments. 5. `pnpm run test:gui` green (plus `test:web` if you touched the build surface). -6. Non-trivial change? It needs an Agent Note in the same PR (repo-wide rule) — the three GUI notes above are the precedents to extend. +6. Non-trivial change? It needs an Agent Note in the same PR (repo-wide rule) — the GUI notes above are the precedents to extend. diff --git a/packages/client/i18n/src/client/index.ts b/packages/client/i18n/src/client/index.ts index b994cccace..8fa5715047 100644 --- a/packages/client/i18n/src/client/index.ts +++ b/packages/client/i18n/src/client/index.ts @@ -5,8 +5,11 @@ * Contract: api-contracts v3 section 8. */ import type { Context } from 'cordis' -import type { SnapshotStore } from '@deepseek-ai/dsh-client-web-react' -import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' +// Engine subpath: createSnapshotStore left the public face in the slot +// terminal rework (business stores go through defineStore); framework data +// stores like this locale cell keep the engine via './store'. +import type { SnapshotStore } from '@deepseek-ai/dsh-client-web-react/store' +import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react/store' import { en } from '../locales/en.ts' import { zh } from '../locales/zh.ts' diff --git a/packages/client/runtime/src/client/index.ts b/packages/client/runtime/src/client/index.ts index 5180fce2b2..8c669a20bc 100644 --- a/packages/client/runtime/src/client/index.ts +++ b/packages/client/runtime/src/client/index.ts @@ -1,21 +1,27 @@ /** * Browser half: the whole runtime contract surface (api-contracts v3 §4) — - * SlotsService, SessionsService (list store + scope tree + object layer), - * the ClientLoader interface, and the cordis Context/Events merges. apply + * SlotsService (declaration ledger + renderer seam + store axis, built-in + * 'root'), SessionsService (list store + current selection + scope tree + + * object layer), the ClientLoader interface, and the cordis Context/Events + * merges. apply * mounts ctx.slots + ctx.sessions and wires the connection stream loop into * the object layer. The loader machinery implementation is NOT in the plugin * bundle — it ships via the package's `./loader` subpath, statically held by * the web shell (a loader cannot load itself). */ import type { Context } from 'cordis' -import type { ConnectionHandle } from '@deepseek-ai/dsh-client-connection/client' -import type { SessionBinding as GenericSessionBinding } from '@deepseek-ai/dsh-client-ui-slots' +import type { ConnectionHandle, SessionId } from '@deepseek-ai/dsh-client-connection/client' +import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots' import type { SnapshotStore, UseSession } from '@deepseek-ai/dsh-client-web-react' import { SlotsService } from './slots.ts' import { SessionsService } from './sessions/service.ts' +import type { SessionListState } from './sessions/service.ts' import type { ConversationSnapshot, RunningToolCall, ToolResultNode } from './sessions/conversation.ts' export { SlotsService } from './slots.ts' +// RootOwnerProps rides the 'root' SlotMap row (both migrated here from +// ui-layout: the framework slot is declared by the framework package). +export type { RootOwnerProps } from './slots.ts' export { SessionsService, scopeOf } from './sessions/service.ts' export type { Session } from './sessions/session.ts' export type { SessionBinding, SessionListState, SessionSummary } from './sessions/service.ts' @@ -38,9 +44,6 @@ export type { SessionId } from '@deepseek-ai/dsh-client-connection/client' */ export type ClientContext = Context -/** SessionBinding narrowed to the client context (inject factories dot services directly). */ -export type ClientSessionBinding = GenericSessionBinding - /** The conversation-snapshot selector hook (ConvViewProps/ToolViewProps take this). */ export type UseConversationSession = UseSession @@ -51,6 +54,25 @@ export type UseConversationSession = UseSession */ export type ToolCallBlock = RunningToolCall | ToolResultNode +declare module '@deepseek-ai/dsh-client-ui-slots' { + /** + * Session standard kit, real members (ui-slots declares the empty seat; + * the runtime — where the subjects live — merges the concrete types): + * every session-scope slot component receives these from the framework. + */ + interface SessionStandardProps { + /** Selector hook over this session's conversation snapshot. */ + useSession: SnapshotSelectorHook + /** The framework-resolved session id (owners never pass it). */ + sessionId: SessionId + } + /** Global standard kit, real members: the session-list hook every slot component receives. */ + interface GlobalStandardProps { + /** Selector hook over the session list snapshot (`current` included — the arbitrated selection seat). */ + useSessions: SnapshotSelectorHook + } +} + declare module 'cordis' { interface Events { /** diff --git a/packages/client/runtime/src/client/loader/index.ts b/packages/client/runtime/src/client/loader/index.ts index 521c597ae4..f8166add9c 100644 --- a/packages/client/runtime/src/client/loader/index.ts +++ b/packages/client/runtime/src/client/loader/index.ts @@ -17,7 +17,7 @@ * load one by one in inject topology. */ import type { Context } from 'cordis' -import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' +import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react/store' import type { BootPluginEntry, ClientLoader, LoaderStatus } from '../index.ts' export type { BootPluginEntry, ClientLoader, LoaderStatus } from '../index.ts' diff --git a/packages/client/runtime/src/client/sessions/service.ts b/packages/client/runtime/src/client/sessions/service.ts index 2b4cf9677e..430ca81478 100644 --- a/packages/client/runtime/src/client/sessions/service.ts +++ b/packages/client/runtime/src/client/sessions/service.ts @@ -1,7 +1,9 @@ /** * SessionsService: root sessions service — list snapshot store (manager - * projection), session scope tree (mintScope pattern: no-op plugin Fiber + - * ctx.extend scope tag), stable SessionBinding cache, ancestry walk. + * projection; carries `current`, the persisted selection every + * session-scoped surface keys off — migrated here from ui-layout per the + * slot-parity design), session scope tree (mintScope pattern: no-op plugin + * Fiber + ctx.extend scope tag), stable SessionBinding cache, ancestry walk. * * Scope lifecycle is watch-driven: a scope is minted lazily on first * resolution; a session leaving the list tears its scope down only when @@ -13,8 +15,11 @@ */ import type { Context, Fiber } from 'cordis' import type { IApiClient, SessionId } from '@deepseek-ai/dsh-client-connection/client' -import type { SnapshotStore } from '@deepseek-ai/dsh-client-web-react' -import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' +// Engine reach-through: the store subpath is the framework-internal channel +// (the public web-react face carries defineStore only). +import type { SnapshotStore } from '@deepseek-ai/dsh-client-web-react/store' +import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react/store' +import type { SessionCell } from '@deepseek-ai/dsh-client-web-react' import { SessionManager } from './manager.ts' import type { Session } from './session.ts' @@ -28,8 +33,12 @@ export interface SessionSummary { updatedAt: number } -/** Session list store shape. */ -export interface SessionListState { ids: SessionId[]; byId: Record } +/** + * Session list store shape. `current` rides the same snapshot (arbitrated: + * the single useSessions standard hook reads list and selection together — + * sidebar highlighting and SessionProvider share one fact source). + */ +export interface SessionListState { ids: SessionId[]; byId: Record; current: SessionId | undefined } /** Session assembly handle for SessionProvider/inject factories (identity-stable per session). */ export interface SessionBinding { @@ -69,15 +78,26 @@ interface ScopeRecord { fiber: Fiber ctx: Context binding: SessionBinding + /** Render-layer standard kit (identity-stable per scope; the renderer's per-cell caches key off it). */ + cell: SessionCell } -/** Root sessions service: list store, object-layer manager, scope tree, bindings, ancestry. */ +/** Root sessions service: list store, current selection, object-layer manager, scope tree, bindings, ancestry. */ export class SessionsService { - /** List snapshot store (list RPC + host stream increments; re-pulled on reconnect). */ + /** List snapshot store (list RPC + host stream increments; re-pulled on reconnect) — the useSessions standard feed, current included. */ readonly list: SnapshotStore /** The object-layer instance cluster and frame dispatch entry (wired to the connection by the runtime apply). */ readonly manager: SessionManager + /** + * Persisted selection cell (the durable half of `list.current`). Private on + * purpose: reads go through the list snapshot; writes through {@link + * SessionsService.open}. Projection validates it against the live list + * instead of destructively pruning, so a selection survives transient list + * states (reconnect re-pull) and resurfaces when its session returns. + */ + private readonly selection: SnapshotStore<{ sessionId?: SessionId }> + private readonly scopes = new Map() /** Most recently resolved binding id — the watch approximation for deferred teardown. */ private watched: SessionId | undefined @@ -90,13 +110,29 @@ export class SessionsService { */ constructor(private readonly rootCtx: Context, api: IApiClient) { this.manager = new SessionManager(api) - this.list = createSnapshotStore({ ids: [], byId: {} }) + this.selection = createSnapshotStore<{ sessionId?: SessionId }>( + {}, + { persist: { name: 'dsh.sessions.current' } }) + this.list = createSnapshotStore({ ids: [], byId: {}, current: undefined }) // The manager owns wire truth; the store is its projection. Manager // notifications are already microtask-batched. this.manager.subscribe(() => { this.projectList() }) rootCtx.reflect.provide('sessions', this, undefined) } + /** + * Select a session as current. Unknown ids fail loud instead of navigating + * nowhere (the sole selection write path). + * @param id - session id (must exist in the list store). + */ + open(id: SessionId): void { + if (this.list.getSnapshot().byId[id] === undefined) { + throw new Error(`sessions.open: unknown session ${id}`) + } + this.selection.update((draft) => { draft.sessionId = id }) + this.list.update((draft) => { draft.current = id }) + } + /** * Create a session on the host. * @param opts - creation options (project directory). @@ -132,6 +168,23 @@ export class SessionsService { return record.binding } + /** + * Resolve the render-layer session cell (SessionProvider's feed through + * the renderer host; ctx never enters the render layer). Marks the session + * watched, same as {@link SessionsService.binding}. + * @param id - session id. + * @returns cell, or undefined for a session neither listed nor already scoped. + */ + cell(id: string): SessionCell | undefined { + const record = this.resolve(id as SessionId) + if (record === undefined) return undefined + if (this.watched !== id) { + this.watched = id as SessionId + this.sweepDeferred() + } + return record.cell + } + /** * Breadcrumb feed: walk parentId links inside the list store. * @param id - session id. @@ -158,10 +211,12 @@ export class SessionsService { if (this.list.getSnapshot().byId[id] === undefined) return undefined const fiber = this.rootCtx.plugin(sessionScope) const ctx = fiber.ctx.extend({ [kScope]: id }) + const session = this.manager.get(id) const record: ScopeRecord = { fiber, ctx, - binding: { sessionId: id, session: this.manager.get(id), ctx }, + binding: { sessionId: id, session, ctx }, + cell: { sessionId: id, useSession: session.useSelector }, } this.scopes.set(id, record) return record @@ -183,7 +238,11 @@ export class SessionsService { ...(entry.parentSessionId !== undefined ? { parentId: entry.parentSessionId } : {}), } } - this.list.set({ ids, byId }) + // current = the persisted selection, masked while its session is absent + // (falls to the empty state; resurfaces if the session returns). + const selected = this.selection.getSnapshot().sessionId + const current = selected !== undefined && byId[selected] !== undefined ? selected : undefined + this.list.set({ ids, byId, current }) this.pruneScopes(byId) } @@ -197,10 +256,18 @@ export class SessionsService { } this.scopes.delete(id) this.deferredRemovals.delete(id) - void record.fiber.dispose() + this.dropScope(id, record) } } + /** Dispose a scope fiber and its session-keyed slot-store instances together (single lifecycle axis). */ + private dropScope(id: SessionId, record: ScopeRecord): void { + void record.fiber.dispose() + // Optional lookup: slots and sessions are sibling services with no + // declared dependency; a slots-less boot (object-layer tests) skips. + this.rootCtx.get('slots')?.pruneStoreScope(id) + } + /** Run deferred teardowns whose session is no longer watched (called when the watch moves). */ private sweepDeferred(): void { for (const id of [...this.deferredRemovals]) { @@ -220,7 +287,7 @@ export class SessionsService { * future teardown path cannot double-dispose. */ if (record !== undefined) { this.scopes.delete(id) - void record.fiber.dispose() + this.dropScope(id, record) } } } diff --git a/packages/client/runtime/src/client/slots.ts b/packages/client/runtime/src/client/slots.ts index 5b58670bd4..8c93050cd9 100644 --- a/packages/client/runtime/src/client/slots.ts +++ b/packages/client/runtime/src/client/slots.ts @@ -1,22 +1,113 @@ /** - * SlotsService: cordis Service wrapper over the pure SlotCore (ui-slots). - * Every mutation re-emits as the 'slots/changed' cordis event; define/register - * run through the caller's ctx.effect so a plugin's registrations are - * collected when its fiber unloads (cordis-native cascade). + * SlotsService: the cordis Service layer of the slot system over the pure + * SlotCore (ui-slots owns registration semantics, the declaration ledger, + * the load-time validations, and the unload cascade). This layer owns what + * needs the runtime: the 'slots/changed' event bridge, register through the + * caller's ctx.effect (fiber unload collects registrations), the renderer + * install seam (install()/renderSlot('root') + the SlotRendererHost face), + * and the store INSTANCE axis — handle x scope key -> create/cache, dropped + * with the last holding entry, session instances cleared (with persisted + * state) on scope death. */ /* eslint-disable @typescript-eslint/no-redundant-type-constituents -- - * `keyof SlotMap & string` is the declare-merge key pattern: SlotMap is empty - * in this compilation unit (intersection reads `never`) but consumers merge - * keys in; the rule fires on the empty-map view, not on real redundancy. */ + * `keyof SlotMap & string` is the declare-merge key pattern: SlotMap only + * holds this package's 'root' row in this compilation unit, but consumers + * merge keys in; the rule fires on the narrow-map view, not on real + * redundancy. */ import { Service } from 'cordis' import type { Context } from 'cordis' import { SlotCore } from '@deepseek-ai/dsh-client-ui-slots' -import type { ComposedProps, RegisterArgs, SlotComponent, SlotEntry, SlotEntryDef, SlotMap, SlotSpec } from '@deepseek-ai/dsh-client-ui-slots' -import type { ClientContext } from './index.ts' +import type { + ChildrenDecl, ComposedProps, HandleOf, InjectParams, KindOptions, OwnerOf, + SlotComponent, SlotEntryDef, SlotMap, SlotRenderer, SlotRendererHost, + SlotScope, SlotSpec, StoreDecl, StoredEntry, StoreInstanceLike, +} from '@deepseek-ai/dsh-client-ui-slots' -/** cordis Service wrapper over the pure SlotCore; mutations re-emit as 'slots/changed'. */ +declare module '@deepseek-ai/dsh-client-ui-slots' { + interface SlotMap { + /** The built-in render-tree root hole (seeded by SlotCore): rendered only by the shell, occupied by a layout entry. */ + 'root': { kind: 'single'; scope: 'root'; owner: RootOwnerProps } + } +} + +/** Root owner share: the shell supplies nothing — the frame is inject-assembled. */ +export interface RootOwnerProps { children?: never } + +/** Instance key for root-scoped store records (session records key by session id, so the literal cannot collide). */ +const ROOT_INSTANCE_KEY = 'root' + +// FIXME(slot-parity): the engine's arbitrated persist extensions — create() +// takes the scope key (per-session localStorage suffix) and instances expose +// clearPersisted() — are not yet on ui-slots' StoreHandle/StoreInstanceLike; +// these local structural faces bridge until fw-slots lifts them. + +/** Store handle face as the engine actually ships it (scope-key-aware create). */ +interface EngineStoreHandle { create(scopeKey?: string): EngineStoreInstance } + +/** Engine instance face: the host-contract shape plus persisted-state cleanup. */ +interface EngineStoreInstance extends StoreInstanceLike { clearPersisted(): void } + +/** Store axis record: one per live handle, dropped when the last holding entry unloads. */ +interface StoreAxisRecord { + /** Scope of the slot the handle mounted under (the core validated cross-scope conflicts). */ + scope: SlotScope + /** Live registrations holding the handle. */ + refs: number + /** Root scope: the single instance under {@link ROOT_INSTANCE_KEY}; session scope: one per session id. */ + instances: Map +} + +/** + * Register options as the service face declares them (structurally the + * core's BaseOptions, re-declared because ui-slots keeps it private). + * FIXME(slot-parity): dedupe once ui-slots exports its options type. + */ +type RegisterOptions = { + /** Target slot key (the entry contributes INTO this slot). */ + name: K + /** Child-slot declaration + render authorization + runtime spec, in one table. */ + children?: D + /** Store seat: a shared handle (apply-constructed) or an exclusive factory (framework-called per entry). */ + store?: H + /** Registrant identity label for diagnostics (defaults to the caller's fiber name). */ + registrant?: string +} & KindOptions + +/** + * Compile-time presence check: an entry declaring children MUST consume + * `renderSlot` (declaring is claiming). Structural copy of the core's + * private RendersCheck; same FIXME as {@link RegisterOptions}. + */ +type RendersCheck = + [keyof D & keyof SlotMap & string] extends [never] ? unknown + : C extends (props: infer P) => unknown + ? ('renderSlot' extends keyof P ? unknown + : { 'children declared but the component consumes no renderSlot': keyof D & keyof SlotMap & string }) + : unknown + +/** Type-erased options view the implementation works with (the typed overloads proved the shares). */ +interface ErasedRegisterOptions { + name: string + children?: Record> + store?: StoreDecl + inject?: (...args: never[]) => Record + key?: string + id?: string + order?: number + label?: string + registrant?: string +} + +/** Erased core call face (the service re-erases at its own boundary; the core's typed face targets end callers). */ +interface ErasedCore { register(options: object, component: unknown): () => void } + +/** cordis Service layer of the slot system; see the module doc for the split with SlotCore. */ export class SlotsService extends Service { private readonly _core = new SlotCore() + /** Store-instance axis: handle -> mounted scope, refcount, resolved instances. */ + private readonly _stores = new Map() + private _renderer: SlotRenderer | undefined + private _host: SlotRendererHost | undefined /** * @param ctx - owning root context. @@ -27,44 +118,115 @@ export class SlotsService extends Service { } /** - * Record a slot spec (delegates to SlotCore.define; disposal follows the caller's fiber). - * @param key - SlotMap key. - * @param spec - kind/scope spec. - * @returns disposer. + * The single registration API (see SlotCore.register for the full + * semantics: children declaration, store seat, inject face, load-time + * validation, unload cascade). This layer adds: disposal through the + * caller's ctx.effect (fiber unload = cascade), exclusive-factory minting + * (`store: createXxxStore` becomes a per-entry handle), the registrant + * diagnostics stamp, and store-instance lifecycle on the entry axis. + * @param options - name + children + store + inject (+ kind-shaped key/id/order/label). + * @param component - pure component typed by the four-share composed props. + * @returns disposer (idempotent; stale calls after fiber teardown are no-ops). */ - define(key: K, spec: SlotSpec): () => void { + register< + K extends keyof SlotMap & string, + const D extends ChildrenDecl = Record, + H extends StoreDecl | undefined = undefined, + C extends SlotComponent = SlotComponent, + >( + options: RegisterOptions & { inject?: undefined }, + component: C + & SlotComponent & keyof SlotMap & string, HandleOf>, object>> + & RendersCheck, + ): () => void + register< + K extends keyof SlotMap & string, + I extends object, + const D extends ChildrenDecl = Record, + H extends StoreDecl | undefined = undefined, + C extends SlotComponent = SlotComponent, + >( + options: RegisterOptions & { inject: (...args: InjectParams) => I }, + component: C + & SlotComponent & keyof SlotMap & string, HandleOf>, I>> + & RendersCheck, + ): () => void + register(rawOptions: object, component: unknown): () => void { + // The typed overloads above proved the shares; the implementation works + // on the erased view (same pattern as the core's register). + const options = rawOptions as ErasedRegisterOptions // eslint-disable-next-line @typescript-eslint/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity - return this.ctx.effect(() => this._core.define(key, spec), 'slots.define()') + return this.ctx.effect(() => this._register(options, component), 'slots.register()') } /** - * Contribute a component (delegates to SlotCore.register; disposal follows the caller's fiber). - * @param key - SlotMap key. - * @param component - contributed component. - * @param args - kind-shaped options (mandatory for keyed/list kinds); the - * inject factory's binding is pinned to ClientContext. - * @returns disposer. + * Install the shell's renderer (web-react's createSlotRenderer product). + * Boot-once: a second install throws. Runs through the caller's ctx.effect, + * so shell fiber unload uninstalls the renderer. + * @param renderer - the outlet machinery implementing SlotRenderer. */ - register>( - // Client-context registrations have exactly one ctx shape: pin Ctx to - // ClientContext so inject factories dot services without a cast. - key: K, component: SlotComponent>>, - ...args: RegisterArgs): () => void { - // eslint-disable-next-line @typescript-eslint/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity - return this.ctx.effect(() => this._core.register(key, component, ...args), 'slots.register()') + install(renderer: SlotRenderer): void { + if (this._renderer !== undefined) throw new Error('slot renderer already installed (install() is boot-once)') + this.ctx.effect(() => { + this._renderer = renderer + return () => { + if (this._renderer === renderer) this._renderer = undefined + } + }, 'slots.install()') } /** - * Snapshot entries for a key. - * @param key - SlotMap key. - * @returns registered entries (stable reference between mutations). + * The single ctx-level render entry: the shell renders 'root'; every other + * key renders inside components through the props renderSlot face. All + * three guards are fail-loud boot-order checks, no fallback. + * @param key - must be 'root' (runtime-enforced for dynamically composed callers). + * @param owner - owner share for the root entry (the shell supplies {}). + * @returns the rendered root tree. */ - entries(key: K): readonly SlotEntry[] { + renderSlot(key: K, owner: OwnerOf): ReturnType { + // Widened: in this package's own program SlotMap holds only 'root', which + // would fold the guard to constant-false; the check exists for plain-JS + // and cross-program callers where K is wider. + if ((key as string) !== 'root') { + throw new Error(`ctx-level renderSlot only renders 'root' (got "${key}"); child slots render through the component props face`) + } + if (this._renderer === undefined) { + throw new Error("slot renderer not installed — boot must call ctx.slots.install(createSlotRenderer()) before rendering 'root'") + } + if (this._core.entries('root').length === 0) { + throw new Error("'root' has no registration — a layout entry must register into 'root' before the shell renders it") + } + return this._renderer.renderRoot(this.hostFace(), owner) + } + + /** + * Drop the per-session store instances of a dead session (the sessions + * service calls this on scope teardown; root-scoped records are untouched). + * Persisted state goes with the session — a never-rendered dead session can + * still own keys from an earlier page load, so the instance is materialized + * transiently just to clear storage (no-op for unpersisted stores). + * @param sessionId - the torn-down session. + */ + pruneStoreScope(sessionId: string): void { + for (const [handle, record] of this._stores) { + if (record.scope !== 'session') continue + const instance = record.instances.get(sessionId) ?? handle.create(sessionId) + instance.clearPersisted() + record.instances.delete(sessionId) + } + } + + /** + * Snapshot entries for a key (render-erased view; stable reference between mutations). + * @param key - SlotMap key. + * @returns registered entries. + */ + entries(key: keyof SlotMap & string): readonly StoredEntry[] { return this._core.entries(key) } /** - * Look up a defined spec. + * Look up a declared spec (register-declared or the built-in 'root'). * @param key - SlotMap key. * @returns spec or undefined. */ @@ -72,15 +234,6 @@ export class SlotsService extends Service { return this._core.spec(key) } - /** - * Dynamic-key escape hatch for spec lookup (renderer-side string keys). - * @param key - candidate slot key. - * @returns wide-typed spec or undefined. - */ - specDynamic(key: string): SlotSpec | undefined { - return this._core.specDynamic(key) - } - /** * Subscribe to a key's registration changes (microtask-batched). * @param key - SlotMap key. @@ -100,8 +253,106 @@ export class SlotsService extends Service { return this._core.getVersion(key) } - /** The wrapped pure core (web-react's scopedSlots outlet reads through this). */ + /** The wrapped pure core (invariant checks read through this). */ get core(): SlotCore { return this._core } + + /** Delegating registration path: factory minting + registrant stamp + core write + instance-axis bookkeeping. */ + private _register(options: ErasedRegisterOptions, component: unknown): () => void { + // Exclusive stores pass the factory itself: minted here into a per-entry + // handle so the stored entry always carries a resolvable handle (the + // core's shared-handle scope pinning applies to it harmlessly). + const store = typeof options.store === 'function' ? options.store() : options.store + const registrant = options.registrant ?? (this.ctx.fiber as { name?: string } | undefined)?.name + const erased: ErasedRegisterOptions = { + ...options, + ...(store !== undefined ? { store } : {}), + ...(registrant !== undefined ? { registrant } : {}), + } + // Core write first: all load-time validation (undeclared target, + // duplicate declaration, kind conflicts, cross-scope handle) throws + // there before this layer commits anything. + const dispose = (this._core as unknown as ErasedCore).register(erased, component) + if (store !== undefined) { + // Register succeeded, so the target's spec is on the ledger. + const scope = (this._core.specDynamic(options.name) as SlotSpec).scope + this._acquire(store, scope) + } + let disposed = false + return () => { + if (disposed) return + disposed = true + dispose() + if (store !== undefined) this._release(store) + } + } + + /** Build (once) the host face the installed renderer reads; sessions resolve lazily at first render. */ + private hostFace(): SlotRendererHost { + if (this._host !== undefined) return this._host + const sessions = this.ctx.get('sessions') + if (sessions === undefined) { + throw new Error("renderSlot('root') before the sessions service mounted — boot order puts runtime apply first") + } + // Identity-stable view: current rides the list snapshot (arbitrated), but + // the provider consumes it as its own observable; one cached object keeps + // the renderer's per-source hook cache stable. + const current = { + getSnapshot: () => sessions.list.getSnapshot().current as string | undefined, + subscribe: (fn: () => void) => sessions.list.subscribe(fn), + } + this._host = { + subscribe: (key, fn) => this._core.subscribe(key, fn), + getVersion: key => this._core.getVersion(key), + entriesOf: key => this._core.entries(key), + specOf: key => this._core.specDynamic(key), + isLive: entry => this._core.isLive(entry), + storeOf: (entry, scopeKey) => + entry.store === undefined ? undefined : this.resolveStore(entry.store as unknown as EngineStoreHandle, scopeKey), + sessions: { + list: sessions.list, + current, + cell: id => sessions.cell(id), + }, + } + return this._host + } + + /** Resolve (create or reuse) the store instance for a registered handle under a scope key. */ + private resolveStore(handle: EngineStoreHandle, sessionId: string | undefined): StoreInstanceLike { + const record = this._stores.get(handle) + if (record === undefined) throw new Error('store handle is not registered (entry unloaded, or the handle never went through register)') + const key = record.scope === 'session' ? sessionId : ROOT_INSTANCE_KEY + if (key === undefined) throw new Error('session-scoped store resolution requires a session id') + let instance = record.instances.get(key) + if (instance === undefined) { + // Session instances get the scope key (the engine suffixes the persist + // key per session); root instances stay keyless. + instance = record.scope === 'session' ? handle.create(key) : handle.create() + record.instances.set(key, instance) + } + return instance + } + + /** Bind (or re-reference) a handle on the axis; cross-scope conflicts already threw in the core. */ + private _acquire(handle: EngineStoreHandle, scope: SlotScope): void { + const record = this._stores.get(handle) + if (record === undefined) { + this._stores.set(handle, { scope, refs: 1, instances: new Map() }) + return + } + record.refs += 1 + } + + /** Drop one reference; the last holder's unload drops the record (instances go with it — engine stores need no explicit dispose). */ + private _release(handle: EngineStoreHandle): void { + const record = this._stores.get(handle) + /* v8 ignore next -- defensive: release only runs from a disposer whose + * register acquired the same handle, so the record must exist; kept so a + * future call site cannot underflow the axis. */ + if (record === undefined) return + record.refs -= 1 + if (record.refs === 0) this._stores.delete(handle) + } } diff --git a/packages/client/runtime/tests/client-apply.spec.ts b/packages/client/runtime/tests/client-apply.spec.ts index bb98bca98e..0baa2e8237 100644 --- a/packages/client/runtime/tests/client-apply.spec.ts +++ b/packages/client/runtime/tests/client-apply.spec.ts @@ -37,6 +37,9 @@ describe('runtime client apply', () => { it('mounts ctx.slots + ctx.sessions and wires the stream sinks into the manager', async () => { const bench = await mount() expect(bench.ctx.get('slots') !== undefined).toBe(true) + // The built-in 'root' declaration ships with this package's SlotsService + // (the SlotMap 'root' merge lives here since the slot-parity rework). + expect(bench.ctx.slots.spec('root')).toEqual({ kind: 'single', scope: 'root' }) const sessions = bench.ctx.get('sessions') expect(sessions !== undefined).toBe(true) expect(bench.sinks).toBeDefined() diff --git a/packages/client/runtime/tests/invariant.spec.ts b/packages/client/runtime/tests/invariant.spec.ts index cdfbba3f7d..708b714b2f 100644 --- a/packages/client/runtime/tests/invariant.spec.ts +++ b/packages/client/runtime/tests/invariant.spec.ts @@ -25,9 +25,11 @@ describe('runtime slots/changed invariant', () => { const ctx = await setup() expect(() => { emit(ctx, 'unrelated/event', 'x') }).not.toThrow() await ctx.plugin(SlotsService).await() // fiber must reach ACTIVE — the audit reads strict ctx.get - // A real define bumps the version first and re-emits through onMutate — - // the audit sees version > 0 and stays quiet. - expect(() => ctx.slots.define('t-single', { kind: 'single', scope: 'root' })).not.toThrow() + // A real registration bumps the version first and re-emits through + // onMutate — the audit sees version > 0 and stays quiet. (Erased call: + // the typed register face rides the wave-1 ui-slots types.) + const slots = ctx.slots as unknown as { register(options: object, component: unknown): () => void } + expect(() => slots.register({ name: 'root' }, () => null)).not.toThrow() }) it('fails loud on a missing key and on an emission with no applied mutation', async () => { diff --git a/packages/client/runtime/tests/sessions-service.spec.ts b/packages/client/runtime/tests/sessions-service.spec.ts index f3989c4532..7e0546335b 100644 --- a/packages/client/runtime/tests/sessions-service.spec.ts +++ b/packages/client/runtime/tests/sessions-service.spec.ts @@ -1,10 +1,12 @@ /** - * SessionsService: list store projection (manager → {ids, byId} with derived - * titles), scope-tree lifecycle (lazy mint / frozen survival / removed - * teardown with watch deferral), binding identity, ancestry walk, create. + * SessionsService: list store projection (manager → {ids, byId, current} + * with derived titles), the migrated current-selection account (open + * validation, persisted mask semantics, cell resolution), scope-tree + * lifecycle (lazy mint / frozen survival / removed teardown with watch + * deferral), binding identity, ancestry walk, create. */ import { Context } from 'cordis' -import { describe, expect, it } from 'vitest' +import { afterEach, describe, expect, it, vi } from 'vitest' import type { SessionId } from '@deepseek-ai/dsh-client-connection/client' import { SessionsService, scopeOf } from '../src/client/sessions/service.ts' import { FakeApiClient, ok } from './fake-api.ts' @@ -112,6 +114,95 @@ describe('scope tree', () => { }) }) +describe('current selection (migrated from ui-layout, arbitrated into the list snapshot)', () => { + afterEach(() => { vi.unstubAllGlobals() }) + + it('open() writes list.current; unknown ids fail loud', async () => { + const b = bench() + await feedList(b, [{ id: 's1' }]) + expect(b.svc.list.getSnapshot().current).toBeUndefined() + b.svc.open(sid('s1')) + expect(b.svc.list.getSnapshot().current).toBe('s1') + expect(() => { b.svc.open(sid('ghost')) }).toThrow(/unknown session ghost/) + expect(b.svc.list.getSnapshot().current).toBe('s1') // failed open leaves the selection alone + }) + + it('masks (not destroys) the selection while its session is off the list', async () => { + const b = bench() + await feedList(b, [{ id: 's1' }, { id: 's2' }]) + b.svc.open(sid('s1')) + await feedList(b, [{ id: 's2' }]) // s1 removed → current falls to the empty state + expect(b.svc.list.getSnapshot().current).toBeUndefined() + await feedList(b, [{ id: 's1' }, { id: 's2' }]) // s1 returns → selection resurfaces + expect(b.svc.list.getSnapshot().current).toBe('s1') + }) + + it('persists the selection under dsh.sessions.current and rehydrates it into a fresh service', async () => { + const storage = new Map() + vi.stubGlobal('localStorage', { + getItem: (k: string) => storage.get(k) ?? null, + setItem: (k: string, v: string) => { storage.set(k, v) }, + }) + const first = bench() + await feedList(first, [{ id: 's1' }]) + first.svc.open(sid('s1')) + expect(storage.get('dsh.sessions.current')).toContain('s1') + // A fresh boot (same storage) recovers the selection once the list holds the session. + const second = bench() + await feedList(second, [{ id: 's1' }]) + expect(second.svc.list.getSnapshot().current).toBe('s1') + }) +}) + +describe('cell (render-layer session kit)', () => { + it('resolves an identity-stable {sessionId, useSession} pair; unknown ids yield undefined', async () => { + const b = bench() + await feedList(b, [{ id: 's1' }]) + const cell = b.svc.cell('s1') + expect(cell).toBeDefined() + expect(cell?.sessionId).toBe('s1') + expect(cell?.useSession).toBe(b.svc.manager.get(sid('s1')).useSelector) + expect(b.svc.cell('s1')).toBe(cell) + expect(b.svc.cell('ghost')).toBeUndefined() + }) + + it('moves the watch like binding(): switching cells sweeps a deferred removal', async () => { + const b = bench() + await feedList(b, [{ id: 's1' }]) + b.svc.cell('s1') // watched + await feedList(b, []) // removed while watched → deferred, scope survives + expect(b.svc.scope(sid('s1'))).toBeDefined() + await feedList(b, [{ id: 's2' }]) + b.svc.cell('s2') // watch moves → sweep tears s1 down + expect(b.svc.scope(sid('s1'))).toBeUndefined() + }) +}) + +describe('slot-store scope prune hook', () => { + it('notifies ctx.slots.pruneStoreScope when a scope dies (both teardown paths)', async () => { + const b = bench() + const pruneStoreScope = vi.fn() + b.ctx.reflect.provide('slots', { pruneStoreScope }) + await feedList(b, [{ id: 's1' }, { id: 's2' }]) + b.svc.scope(sid('s1')) + b.svc.binding(sid('s2')) // s2 watched + await feedList(b, []) // s1 unwatched → immediate drop; s2 watched → deferred + expect(pruneStoreScope).toHaveBeenCalledWith('s1') + expect(pruneStoreScope).not.toHaveBeenCalledWith('s2') + await feedList(b, [{ id: 's3' }]) + b.svc.binding(sid('s3')) // watch moves → deferred sweep drops s2 + expect(pruneStoreScope).toHaveBeenCalledWith('s2') + }) + + it('tolerates a slots-less boot (object-layer benches carry no slot service)', async () => { + const b = bench() + await feedList(b, [{ id: 's1' }]) + b.svc.scope(sid('s1')) + await feedList(b, []) // teardown without ctx.slots must not throw + expect(b.svc.scope(sid('s1'))).toBeUndefined() + }) +}) + describe('ancestry', () => { it('walks parentId links root-first including self; broken links stop the walk', async () => { const b = bench() diff --git a/packages/client/runtime/tests/slots-service.spec.ts b/packages/client/runtime/tests/slots-service.spec.ts index f53a22bb0a..88d73d4ac0 100644 --- a/packages/client/runtime/tests/slots-service.spec.ts +++ b/packages/client/runtime/tests/slots-service.spec.ts @@ -1,80 +1,379 @@ /** - * SlotsService: cordis Service wrapper semantics — core delegation, the - * 'slots/changed' event bridge, and fiber-scoped registration disposal. + * SlotsService terminal-design account (design.md §11-3 main landing): + * built-in 'root', the three load-time throws (duplicate declaration / + * undeclared contribution / cross-scope store handle), the renderer install + * seam (double install / not installed / non-root key), store instance + * resolution and lifecycle on the ledger axis, and the entry-unload cascade. */ import { Context } from 'cordis' -import { describe, expect, it } from 'vitest' +import { describe, expect, it, vi } from 'vitest' import type { FC } from 'react' +import type { SlotRendererHost } from '@deepseek-ai/dsh-client-ui-slots' import { SlotsService } from '../src/client/slots.ts' -// Test-only slot keys (SlotMap is empty in this package; the service is generic over it). +// Test-only slot keys (merged so the typed entries/spec faces accept them). declare module '@deepseek-ai/dsh-client-ui-slots' { interface SlotMap { - 't-single': { kind: 'single'; scope: 'root'; props: object } - 't-list': { kind: 'list'; scope: 'root'; props: object } + 't.host': { kind: 'single'; scope: 'root' } + 't.panel': { kind: 'single'; scope: 'session' } + 't.rows': { kind: 'list'; scope: 'root' } } } const C: FC = () => null -async function boot(): Promise { +/** + * Register/install/renderSlot through a type-erased view: the typed register + * face rides wave-1 ui-slots types (red until that wave lands); the runtime + * semantics under test are final. + */ +interface ErasedService { + register(options: object, component: unknown): () => void + install(renderer: object): void + renderSlot(key: string, owner: object): unknown +} + +interface Bench { + ctx: Context + svc: SlotsService + erased: ErasedService +} + +async function boot(): Promise { const ctx = new Context() ctx.plugin(SlotsService) await ctx.fiber.await() - return ctx + // Service accessor (ctx.get reads the reflect store, which Service-class + // plugins do not write; the accessor is the product path). + const svc = ctx.slots + return { ctx, svc, erased: svc as unknown as ErasedService } } -describe('SlotsService', () => { - it('proxies define/register/entries/spec/getVersion to the core', async () => { - const ctx = await boot() - ctx.slots.define('t-single', { kind: 'single', scope: 'root' }) - expect(ctx.slots.spec('t-single')).toEqual({ kind: 'single', scope: 'root' }) - const v0 = ctx.slots.getVersion('t-single') - ctx.slots.register('t-single', C) - expect(ctx.slots.entries('t-single')).toHaveLength(1) - expect(ctx.slots.getVersion('t-single')).toBeGreaterThan(v0) - expect(ctx.slots.core.spec('t-single')).toBeDefined() +/** Engine-shaped instance stub (the arbitrated persist face: scope-keyed create + clearPersisted). */ +interface FakeInstance { + useSelector: () => undefined + actions: Record + clearPersisted: ReturnType +} + +/** Fake store handle factory (create-count and clearPersisted observable). */ +function fakeHandle() { + const created: FakeInstance[] = [] + const handle = { + create: vi.fn((_scopeKey?: string): FakeInstance => { + const instance: FakeInstance = { useSelector: () => undefined, actions: {}, clearPersisted: vi.fn() } + created.push(instance) + return instance + }), + } + return { handle, created } +} + +/** + * Install a capturing renderer, occupy 'root' (declaring `children` in the + * same call — 'root' is single, so the one occupant is also the declarer), + * and pull the host face out through renderSlot('root'). + */ +function captureHost(bench: Bench, children?: object): SlotRendererHost { + let host: SlotRendererHost | undefined + bench.erased.install({ + renderRoot: (h: SlotRendererHost) => { host = h; return 'rendered' }, + }) + bench.erased.register({ name: 'root', ...(children !== undefined ? { children } : {}) }, C) + bench.ctx.reflect.provide('sessions', fakeSessions()) + bench.erased.renderSlot('root', {}) + if (host === undefined) throw new Error('renderer never received the host') + return host +} + +/** Minimal sessions face for the host seam (list observable + cell). */ +function fakeSessions() { + const state = { ids: [], byId: {}, current: undefined as string | undefined } + return { + list: { getSnapshot: () => state, subscribe: () => () => undefined }, + cell: (id: string) => (id === 'known' ? { sessionId: id, useSession: () => undefined } : undefined), + } +} + +describe("built-in 'root'", () => { + it('is declared at construction: spec readable, occupancy open, no plugin needed', async () => { + const bench = await boot() + expect(bench.svc.spec('root')).toEqual({ kind: 'single', scope: 'root' }) + expect(() => bench.erased.register({ name: 'root' }, C)).not.toThrow() + expect(bench.svc.entries('root')).toHaveLength(1) }) - it("re-emits every mutation as 'slots/changed' with the key", async () => { - const ctx = await boot() - const seen: string[] = [] - ctx.on('slots/changed', (key) => { seen.push(key) }) - ctx.slots.define('t-list', { kind: 'list', scope: 'root' }) - ctx.slots.register('t-list', C, { id: 'a' }) - expect(seen).toEqual(['t-list', 't-list']) + it('rejects a second declaration of root, attributing the built-in row', async () => { + const bench = await boot() + expect(() => bench.erased.register({ + name: 'root', children: { 'root': { kind: 'single', scope: 'root' } }, + }, C)).toThrow(/already declared.*built-in/) + }) +}) + +describe('load-time validation', () => { + it('throws on contributing into an undeclared slot', async () => { + const bench = await boot() + expect(() => bench.erased.register({ name: 't.host' }, C)).toThrow(/slot "t.host" is not declared/) }) - it('collects a plugin fiber\'s registrations when the fiber unloads (cascade)', async () => { - const ctx = await boot() - ctx.slots.define('t-single', { kind: 'single', scope: 'root' }) - const fiber = ctx.plugin({ + it('throws on a duplicate declaration, naming the slot and the prior declarant', async () => { + const bench = await boot() + bench.erased.register({ name: 'root', children: { 't.host': { kind: 'single', scope: 'root' } } }, C) + bench.erased.register({ + name: 't.host', children: { 't.rows': { kind: 'list', scope: 'root' } }, + }, C) + expect(() => bench.erased.register({ + name: 't.rows', id: 'r1', children: { 't.rows': { kind: 'list', scope: 'root' } }, + }, C)).toThrow(/slot "t.rows" is already declared.*"t.host"/) + }) + + it('throws when one store handle is bound to two scopes', async () => { + const bench = await boot() + bench.erased.register({ + name: 'root', + children: { + 't.host': { kind: 'single', scope: 'root' }, + 't.panel': { kind: 'single', scope: 'session' }, + }, + }, C) + const { handle } = fakeHandle() + bench.erased.register({ name: 't.host', store: handle }, C) + expect(() => bench.erased.register({ name: 't.panel', store: handle }, C)) + .toThrow(/one handle, one scope/) + }) + + it('commits nothing when the core rejects the entry (children stay undeclared)', async () => { + const bench = await boot() + bench.erased.register({ name: 'root' }, C) // 'root' single slot now occupied + expect(() => bench.erased.register({ + name: 'root', children: { 't.host': { kind: 'single', scope: 'root' } }, + }, C)).toThrow(/already has a registration/) + // The failing call's declaration must not have landed. + expect(() => bench.erased.register({ name: 't.host' }, C)).toThrow(/is not declared/) + }) +}) + +describe('renderer install seam', () => { + it('throws on renderSlot before install (boot-order guidance)', async () => { + const bench = await boot() + expect(() => bench.erased.renderSlot('root', {})).toThrow(/renderer not installed/) + }) + + it('throws on double install', async () => { + const bench = await boot() + bench.erased.install({ renderRoot: () => null }) + expect(() => { bench.erased.install({ renderRoot: () => null }) }).toThrow(/already installed/) + }) + + it('throws on any non-root key (single ctx-level entry)', async () => { + const bench = await boot() + bench.erased.install({ renderRoot: () => null }) + expect(() => bench.erased.renderSlot('t.host', {})).toThrow(/only renders 'root'/) + }) + + it("throws on renderSlot('root') before any root registration", async () => { + const bench = await boot() + bench.erased.install({ renderRoot: () => null }) + expect(() => bench.erased.renderSlot('root', {})).toThrow(/no registration/) + }) + + it('renders through the installed renderer and returns its product', async () => { + const bench = await boot() + const renderRoot = vi.fn(() => 'tree') + bench.erased.install({ renderRoot }) + bench.erased.register({ name: 'root' }, C) + bench.ctx.reflect.provide('sessions', fakeSessions()) + expect(bench.erased.renderSlot('root', {})).toBe('tree') + expect(renderRoot).toHaveBeenCalledTimes(1) + }) +}) + +describe('host face', () => { + it('serves entriesOf/specOf/isLive off the ledger and flips isLive on disposal', async () => { + const bench = await boot() + const host = captureHost(bench, { 't.host': { kind: 'single', scope: 'root' } }) + const dispose = bench.erased.register({ name: 't.host' }, C) + const rootEntry = host.entriesOf('root')[0] + expect(rootEntry).toBeDefined() + expect(rootEntry?.component).toBe(C) + expect(host.specOf('root')).toEqual({ kind: 'single', scope: 'root' }) + expect(host.specOf('t.host')).toEqual({ kind: 'single', scope: 'root' }) + const childEntry = host.entriesOf('t.host')[0] + expect(host.isLive(childEntry as never)).toBe(true) + dispose() + expect(host.isLive(childEntry as never)).toBe(false) + expect(host.entriesOf('t.host')).toHaveLength(0) + }) + + it('exposes sessions list/current/cell (current riding the list snapshot)', async () => { + const bench = await boot() + const host = captureHost(bench) + expect(host.sessions.list.getSnapshot()).toMatchObject({ ids: [] }) + expect(host.sessions.current.getSnapshot()).toBeUndefined() + expect(host.sessions.cell('known')).toMatchObject({ sessionId: 'known' }) + expect(host.sessions.cell('ghost')).toBeUndefined() + }) +}) + +describe('store instance axis', () => { + /** Boot with 'root' occupied and the three test children declared. */ + async function storeBench() { + const bench = await boot() + const host = captureHost(bench, { + 't.host': { kind: 'single', scope: 'root' }, + 't.rows': { kind: 'list', scope: 'root' }, + 't.panel': { kind: 'single', scope: 'session' }, + }) + return { bench, host } + } + + it('resolves one instance per (handle x root scope) shared across entries', async () => { + const { bench, host } = await storeBench() + const { handle } = fakeHandle() + bench.erased.register({ name: 't.host', store: handle }, C) + bench.erased.register({ name: 't.rows', id: 'a', store: handle }, C) + const [hostEntry] = host.entriesOf('t.host') + const [rowEntry] = host.entriesOf('t.rows') + const a = host.storeOf(hostEntry as never, undefined) + const b = host.storeOf(rowEntry as never, undefined) + expect(a).toBeDefined() + expect(a).toBe(b) // shared handle, same scope key = same instance + expect(handle.create).toHaveBeenCalledTimes(1) + expect(handle.create).toHaveBeenCalledWith() // root scope: keyless create + }) + + it('resolves per-session instances keyed by session id, created with the scope key', async () => { + const { bench, host } = await storeBench() + const { handle } = fakeHandle() + bench.erased.register({ name: 't.panel', store: handle }, C) + const [entry] = host.entriesOf('t.panel') + const s1 = host.storeOf(entry as never, 's1') + const s2 = host.storeOf(entry as never, 's2') + expect(s1).not.toBe(s2) + expect(host.storeOf(entry as never, 's1')).toBe(s1) // cached per key + expect(handle.create).toHaveBeenCalledWith('s1') + expect(handle.create).toHaveBeenCalledWith('s2') + expect(() => host.storeOf(entry as never, undefined)).toThrow(/requires a session id/) + }) + + it('mints a fresh handle per register for the factory (exclusive) form', async () => { + const { bench, host } = await storeBench() + const factory = vi.fn(() => fakeHandle().handle) + bench.erased.register({ name: 't.host', store: factory }, C) + bench.erased.register({ name: 't.rows', id: 'a', store: factory }, C) + expect(factory).toHaveBeenCalledTimes(2) + const a = host.storeOf(host.entriesOf('t.host')[0] as never, undefined) + const b = host.storeOf(host.entriesOf('t.rows')[0] as never, undefined) + expect(a).not.toBe(b) // two mints, two instances + }) + + it('drops instances with the last holding entry and refuses stale resolution', async () => { + const { bench, host } = await storeBench() + const { handle } = fakeHandle() + const d1 = bench.erased.register({ name: 't.host', store: handle }, C) + bench.erased.register({ name: 't.rows', id: 'a', store: handle }, C) + const rowEntry = host.entriesOf('t.rows')[0] + const hostEntry = host.entriesOf('t.host')[0] + const shared = host.storeOf(rowEntry as never, undefined) + d1() // one holder left: record (and instance) survive + expect(host.storeOf(rowEntry as never, undefined)).toBe(shared) + expect(() => host.storeOf(hostEntry as never, undefined)).not.toThrow() // handle still live via the row entry + // Note: dropping the row entry would sever the last reference; stale + // resolution is covered through the cascade spec below. + }) + + it('pruneStoreScope clears persisted state per dead session, including never-materialized ones', async () => { + const { bench, host } = await storeBench() + const { handle, created } = fakeHandle() + bench.erased.register({ name: 't.panel', store: handle }, C) + const [entry] = host.entriesOf('t.panel') + const s1 = host.storeOf(entry as never, 's1') + expect(s1).toBe(created[0]) // the resolved instance is the fake the handle minted + bench.svc.pruneStoreScope('s1') + expect(created[0]?.clearPersisted).toHaveBeenCalledTimes(1) + expect(host.storeOf(entry as never, 's1')).not.toBe(s1) // instance dropped, next resolve mints anew + // Never-rendered dead session: a transient instance is created just to clear storage. + const before = created.length + bench.svc.pruneStoreScope('s-never') + expect(created.length).toBe(before + 1) + expect(created[created.length - 1]?.clearPersisted).toHaveBeenCalledTimes(1) + }) +}) + +describe('entry-unload cascade', () => { + it('kills declared children, their contributions, and the ledger rows with the entry', async () => { + const bench = await boot() + let host: SlotRendererHost | undefined + bench.erased.install({ + renderRoot: (h: SlotRendererHost) => { host = h; return 'rendered' }, + }) + bench.ctx.reflect.provide('sessions', fakeSessions()) + // The declarer here is NOT the root occupant: root stays occupied by a + // separate entry so disposing the declarer only kills its children. + const disposeRoot = bench.erased.register({ name: 'root' }, C) + bench.erased.renderSlot('root', {}) + if (host === undefined) throw new Error('renderer never received the host') + disposeRoot() + const disposeDeclarer = bench.erased.register({ + name: 'root', children: { 't.host': { kind: 'single', scope: 'root' } }, + }, C) + bench.erased.register({ name: 't.host' }, C) + const [childEntry] = host.entriesOf('t.host') + expect(childEntry).toBeDefined() + + disposeDeclarer() + expect(bench.svc.spec('t.host')).toBeUndefined() // ledger row gone + expect(host.specOf('t.host')).toBeUndefined() // outlets now render empty + expect(bench.svc.entries('t.host')).toHaveLength(0) // contribution cleared + expect(host.isLive(childEntry as never)).toBe(false) // stale bindings will throw upstream + // The freed key is re-declarable by a new entry (no residue). + expect(() => bench.erased.register({ + name: 'root', children: { 't.host': { kind: 'single', scope: 'root' } }, + }, C)).not.toThrow() + }) + + it('cascades through cordis fiber disposal (plugin unload = full cleanup)', async () => { + const bench = await boot() + bench.erased.register({ + name: 'root', children: { 't.host': { kind: 'single', scope: 'root' } }, + }, C) + const fiber = bench.ctx.plugin({ name: 'occupant', inject: ['slots'], apply: (pluginCtx: Context) => { - pluginCtx.slots.register('t-single', C) + ;(pluginCtx.slots as unknown as ErasedService).register({ name: 't.host' }, C) }, }) await fiber.await() - expect(ctx.slots.entries('t-single')).toHaveLength(1) + expect(bench.svc.entries('t.host')).toHaveLength(1) await fiber.dispose() - expect(ctx.slots.entries('t-single')).toHaveLength(0) - // The slot definition (registered from root) survives; a new occupant may register. - expect(() => ctx.slots.register('t-single', C)).not.toThrow() + expect(bench.svc.entries('t.host')).toHaveLength(0) + expect(bench.svc.spec('t.host')).toBeDefined() // declarer still live; slot stays declared }) - it('proxies specDynamic/subscribe/getVersion through the core', async () => { - const ctx = await boot() - ctx.slots.define('t-list', { kind: 'list', scope: 'root' }) - expect(ctx.slots.specDynamic('t-list')).toEqual({ kind: 'list', scope: 'root' }) - expect(ctx.slots.specDynamic('never-defined')).toBeUndefined() - let notified = 0 - const unsubscribe = ctx.slots.subscribe('t-list', () => { notified += 1 }) - ctx.slots.register('t-list', C, { id: 'row' }) - await new Promise(resolve => setTimeout(resolve, 0)) // microtask-batched flush - expect(notified).toBeGreaterThan(0) - expect(ctx.slots.getVersion('t-list')).toBeGreaterThan(0) - unsubscribe() + it('disposer is idempotent (stale second call is a no-op)', async () => { + const bench = await boot() + const dispose = bench.erased.register({ + name: 'root', children: { 't.host': { kind: 'single', scope: 'root' } }, + }, C) + dispose() + expect(() => { dispose() }).not.toThrow() + expect(() => bench.erased.register({ + name: 'root', children: { 't.host': { kind: 'single', scope: 'root' } }, + }, C)).not.toThrow() + }) +}) + +describe('event bridge', () => { + it("re-emits entry writes and child declarations as 'slots/changed'", async () => { + const bench = await boot() + const seen: string[] = [] + bench.ctx.on('slots/changed', (key) => { seen.push(key) }) + bench.erased.register({ + name: 'root', children: { 't.rows': { kind: 'list', scope: 'root' } }, + }, C) + bench.erased.register({ name: 't.rows', id: 'a' }, C) + expect(seen).toEqual(['root', 't.rows', 't.rows']) }) - }) diff --git a/packages/client/ui-conversation/README.md b/packages/client/ui-conversation/README.md index 425122958a..bca5ee9a37 100644 --- a/packages/client/ui-conversation/README.md +++ b/packages/client/ui-conversation/README.md @@ -1,8 +1,10 @@ # @deepseek-ai/dsh-client-ui-conversation -Conversation domain: skeleton (header/tabs/composer/empty state), chat view (grouped step-summary flow, streaming tail isolation), ctx.toolviews named registry with bash samples, minimal details panel, scope-addressed ConversationService. Contract: api-contracts v3 §7. +Conversation domain: skeleton (header/tabs/composer/empty state), chat view (grouped step-summary flow, streaming tail isolation), ctx.toolviews named registry with bash samples, minimal details panel, scope-addressed ConversationService. Contract: api-contracts v3 §7 plus the slot terminal design (store seat / props shares). -`src/client/` is organized for the future package split: `contract/` is the sole inter-domain shared face (`slots.ts` composed slot props, `views.ts` view ring, `toolview.ts` tool ring, `tool-call-model.ts`); the `skeleton/`, `chat/`, and `toolviews/` domain directories import contract files and never each other; `apply.ts` is the only assembly point allowed to import all three domains. The `/client` export surface is the contract only — `apply`/`inject`, the two service classes, and the `contract/` type families; implementation components (skeleton, chat rows) stay internal and reach the page exclusively through apply's slot registrations (tests take them via the `./src/*` subpath). +Per-session UI state (selection, composer draft, active view) lives in the declared chat store (`stores.ts` `createChatStore`): apply constructs one handle and passes it to both the conversation and details registrations, so the two session slots share one instance per session (selection written by conversation, read by details) and the framework owns instance lifecycle and draft persistence. Components are pure — the framework standard kit (`useSession`/`sessionId`/`useSessions`) and the store faces (`useStore`/`actions`) arrive automatically from the registration declaration; the inject factories contribute plain data and callbacks only (send/stop choreography, view registry read face, startSession chain). + +`src/client/` is organized for the future package split: `contract/` is the sole inter-domain shared face (`slots.ts` composed slot props, `views.ts` view ring, `toolview.ts` tool ring, `tool-call-model.ts`); the `skeleton/`, `chat/`, and `toolviews/` domain directories import contract files and never each other; `apply.ts` is the only assembly point allowed to import all three domains. The `/client` export surface is the contract only — `apply`/`inject`, the two service classes, and the `contract/` type families; implementation components (skeleton, chat rows) and the store factory stay internal and reach the page exclusively through apply's slot registrations (tests take them via the `./src/*` subpath). ## Model Experience diff --git a/packages/client/ui-conversation/src/client/apply.ts b/packages/client/ui-conversation/src/client/apply.ts index a600789a20..266602e1b2 100644 --- a/packages/client/ui-conversation/src/client/apply.ts +++ b/packages/client/ui-conversation/src/client/apply.ts @@ -2,20 +2,18 @@ * Client plugin body: provide the conversation service and toolview registry, * register the conversation/details slot occupants and the no-session empty * state, and mount the chat view with its samples. Assembly only — components - * receive everything through inject factories; nothing here renders directly. + * receive everything through props: the framework standard kit and store + * faces arrive automatically from the declarations below; the inject + * factories contribute the plain-data-and-callbacks business face (design §5). */ -import { createElement, Fragment, type ReactNode } from 'react' import type { Context } from 'cordis' -import type { SessionBinding } from '@deepseek-ai/dsh-client-ui-slots' -import { scopedSlots, shallowEqual } from '@deepseek-ai/dsh-client-web-react' -import type { SnapshotSelectorHook, UseSession } from '@deepseek-ai/dsh-client-web-react' -import type { - SessionId, SessionListState, SessionsService, SlotsService, -} from '@deepseek-ai/dsh-client-runtime/client' +import type { BoundActions } from '@deepseek-ai/dsh-client-ui-slots' +import type { SessionId, SessionsService, SlotsService } from '@deepseek-ai/dsh-client-runtime/client' import type { LayoutService } from '@deepseek-ai/dsh-client-ui-layout/client' import type { I18nService } from '@deepseek-ai/dsh-client-i18n/client' -import type { ConvViewProps, SelectionTarget, ViewEntry, ViewId } from './contract/views.ts' +import type { SelectionTarget } from './contract/views.ts' import type { ConversationInjected, DetailsInjected, EmptyStateInjected } from './contract/slots.ts' +import { createChatStore } from './stores.ts' import { ConversationService } from './service.ts' import { ToolViewRegistry } from './toolviews/registry.ts' import { childSessionScope, registerChat } from './chat/register.ts' @@ -37,20 +35,13 @@ function need(ctx: Context, name: string): T { return value } -/** Per-list-state cwd set (deduped, list order) for the empty-state picker. */ -const cwdsCache = new WeakMap() -function cwdsOf(state: SessionListState): readonly string[] { - let cached = cwdsCache.get(state) - if (cached === undefined) { - const seen = new Set() - for (const id of state.ids) { - const cwd = state.byId[id]?.cwd - if (cwd !== undefined && cwd !== '') seen.add(cwd) - } - cached = [...seen] - cwdsCache.set(state, cached) - } - return cached +/** Resolve the session-scoped conversation service (scope-addressed send/cancel), failing loud. */ +function scopedConversation(sessions: SessionsService, id: SessionId): ConversationService { + const scoped = sessions.scope(id) + if (scoped === undefined) throw new Error(`ui-conversation: session "${id}" resolved no scope`) + const conversation = scoped.get('conversation') + if (conversation === undefined) throw new Error('ui-conversation: conversation service unavailable through the session scope') + return conversation } /** @@ -80,106 +71,64 @@ export function apply(ctx: Context): void { () => registerBashSamples(toolviews, childSessionScope(sessions.list)), 'ui-conversation: bash toolview samples') - // ConvViewProps.slots is ScopedSlots: a real outlet with an empty - // whitelist (uncallable by type, correct runtime shape for future grants). - const emptySlots = scopedSlots(slots.core) + // Shared store handle, constructed here so its identity lives and dies with + // this fiber (a module-level handle would be a de-facto singleton). Both + // session-slot registrations declare it; same scope key = same instance, so + // conversation writes and details reads meet in one store. + const chat = createChatStore() - /** conversation slot: skeleton surface assembled once per (entry x session). */ - const conversationInject = (b: SessionBinding): ConversationInjected => { - const bctx = b.ctx as Context - const scoped = need(bctx, 'conversation') - const id = b.sessionId as SessionId - const useSession = b.session.useSelector as UseSession - const selectionStore = scoped.selection - const draftsStore = scoped.drafts - const session = sessions.manager.get(id) - // Watch-driven history pull: assembling the surface IS the watch signal - // (once per entry x session; open() is idempotent and self-recovers). - void session.open() - - const viewProps: Omit = { - sessionId: id, - useSession, - useSelection: selectionStore.useSelector, - actions: { - openDetails: (target: SelectionTarget) => { scoped.openDetails(target) }, - loadOlder: () => { void session.loadOlder() }, - }, - } - - const injected: ConversationInjected = { - useAncestry: () => sessions.list.useSelector( - () => sessions.ancestry(id), - (a, b) => shallowEqual(a, b)), - views: { - list: () => conversation.views(), - subscribe: fn => conversation.subscribeViews(fn), - version: () => conversation.viewsVersion(), - }, - // layout's viewFor value type is its own looser ViewId; the registry is - // the runtime validator (unknown ids fall back to the first view). - useActiveView: () => layout.current.useSelector(s => s.viewFor[id]) as ViewId | undefined, - composer: { - useDraft: () => draftsStore.useSelector(s => s), - setDraft: (text) => { draftsStore.set(text) }, - send: (mode) => { - const text = draftsStore.getSnapshot().trim() - if (text === '') return + slots.register({ + name: 'conversation', + store: chat, + inject: (sessionId: SessionId, actions: BoundActions): ConversationInjected => { + const session = sessions.manager.get(sessionId) + const scoped = scopedConversation(sessions, sessionId) + // Watch-driven history pull: assembling the surface IS the watch signal + // (once per entry x session; open() is idempotent and self-recovers). + void session.open() + return { + views: { + list: () => conversation.views(), + subscribe: fn => conversation.subscribeViews(fn), + version: () => conversation.viewsVersion(), + }, + send: (text, mode) => { + const trimmed = text.trim() + if (trimmed === '') return // Optimistic clear with failure restore (choreography lives with the // sender; the business failure also lands in snapshot.promptError). - draftsStore.set('') - void scoped.send(text, mode).catch(() => { - if (draftsStore.getSnapshot() === '') draftsStore.set(text) - }) + // The store write path stays inside the declared actions set: + // restoreDraft itself no-ops once the user typed something new. + actions.clearDraft() + void scoped.send(trimmed, mode).catch(() => { actions.restoreDraft(trimmed) }) }, stop: () => { scoped.cancel().catch(() => { // Stop failure surfaces via snapshot.promptError; nothing to restore. }) }, - }, - actions: { - openView: (view: ViewId) => { layout.openView(id, view) }, - open: (target: SessionId) => { layout.open(target) }, - }, - renderView: (entry: ViewEntry): ReactNode => { - const children: ReactNode[] = [] - if (entry.chrome?.header !== undefined) { - children.push(createElement(entry.chrome.header, { key: 'header', sessionId: id, useSession })) - } - children.push(createElement(entry.component, { key: 'view', ...viewProps, slots: emptySlots })) - if (entry.chrome?.footer !== undefined) { - children.push(createElement(entry.chrome.footer, { key: 'footer', sessionId: id, useSession })) - } - return createElement(Fragment, null, ...children) - }, - } - return injected - } + openDetails: (target: SelectionTarget) => { + actions.select(target) + layout.openDetails() + }, + loadOlder: () => { void session.loadOlder() }, + open: (target: SessionId) => { sessions.open(target) }, + } + }, + }, ConversationRoot) - /** details slot: minimal selection-driven panel. */ - const detailsInject = (b: SessionBinding): DetailsInjected => { - const bctx = b.ctx as Context - const scoped = need(bctx, 'conversation') - const injected: DetailsInjected = { - useSelection: scoped.selection.useSelector, - actions: { closeDetails: () => { layout.closeDetails() } }, - } - return injected - } + slots.register({ + name: 'details', + store: chat, + inject: (): DetailsInjected => ({ + closeDetails: () => { layout.closeDetails() }, + }), + }, DetailsPanel) - /** conversation.empty root slot: the NEW SESSION hero. */ - const emptyInject = (): EmptyStateInjected => { - const useCwds: SnapshotSelectorHook = (sel, eq) => - sessions.list.useSelector(s => sel(cwdsOf(s)), eq) - const injected: EmptyStateInjected = { - useCwds, - actions: { startSession: opts => conversation.startSession(opts) }, - } - return injected - } - - slots.register('conversation', ConversationRoot, { inject: conversationInject }) - slots.register('details', DetailsPanel, { inject: detailsInject }) - slots.register('conversation.empty', EmptyState, { inject: emptyInject }) + slots.register({ + name: 'conversation.empty', + inject: (): EmptyStateInjected => ({ + startSession: opts => conversation.startSession(opts), + }), + }, EmptyState) } diff --git a/packages/client/ui-conversation/src/client/chat/ChatView.tsx b/packages/client/ui-conversation/src/client/chat/ChatView.tsx index b8ea969829..24b2e278fe 100644 --- a/packages/client/ui-conversation/src/client/chat/ChatView.tsx +++ b/packages/client/ui-conversation/src/client/chat/ChatView.tsx @@ -122,7 +122,7 @@ function StreamingTail({ useSession, onGrow }: { export function createChatView(deps: ChatViewDeps): FC { const { toolviews, t } = deps - return function ChatView({ sessionId, useSession: useSessionWide, useSelection, actions }: ConvViewProps) { + return function ChatView({ sessionId, useSession: useSessionWide, useStore, actions }: ConvViewProps) { const useSession = useSessionWide as UseConversation const nodes = useSession((s) => s.nodes) const runningCalls = useSession((s) => s.runningCalls) @@ -131,7 +131,7 @@ export function createChatView(deps: ChatViewDeps): FC { const openErrorMessage = useSession((s) => s.openError === null ? null : `${s.openError.message}(${s.openError.code})`) const hasMore = useSession((s) => s.hasMore) const loadingOlder = useSession((s) => s.loadingOlder) - const selectedCallId = useSelection((sel) => sel?.callId) + const selectedCallId = useStore((s) => s.selection?.callId) const items = useMemo(() => deriveChatFlow(nodes), [nodes]) diff --git a/packages/client/ui-conversation/src/client/chat/ToolViewOutlet.tsx b/packages/client/ui-conversation/src/client/chat/ToolViewOutlet.tsx index 7fa8b5702e..9f376f593a 100644 --- a/packages/client/ui-conversation/src/client/chat/ToolViewOutlet.tsx +++ b/packages/client/ui-conversation/src/client/chat/ToolViewOutlet.tsx @@ -1,13 +1,12 @@ // ToolViewOutlet: resolves the toolview for one call through ctx.toolviews // (uSES over the registry version so unload falls back live) and renders it // behind a per-row error boundary. GenericToolCard is the render-side -// fallback for both a registry miss and a crashed custom row. A registrant -// inject factory is called once per (registration x binding) and cached, -// mirroring the scoped-slots injection discipline. +// fallback for both a registry miss and a crashed custom row. Pure props +// machinery, zero React context: a registrant inject factory receives the +// sessionId this outlet already holds, is called once per (registration x +// session) and cached, mirroring the slot injection discipline. -import { Component, useSyncExternalStore, type FC, type ReactNode } from 'react' -import { useSessionBinding } from '@deepseek-ai/dsh-client-web-react' -import type { SessionBinding } from '@deepseek-ai/dsh-client-ui-slots' +import { Component, useSyncExternalStore, type ReactNode } from 'react' import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client' import type { ToolViewInject, ToolViewProps, ToolViewResolver } from '../contract/toolview.ts' import { GenericToolCard } from './GenericToolCard.tsx' @@ -19,19 +18,21 @@ export interface ToolViewOutletProps { viewProps: ToolViewProps } -/** Inject cache: per inject-factory (stable per registration) x binding object. */ -const injectCache = new WeakMap, WeakMap>() +/** Inject cache: per inject-factory (stable per registration) x session id. + * The inner Map lives and dies with its factory (WeakMap entry), so entries + * are bounded by the session count over the registration's lifetime. */ +const injectCache = new WeakMap, Map>() -function cachedInject(inject: ToolViewInject, binding: SessionBinding): object { - let perBinding = injectCache.get(inject) - if (!perBinding) { - perBinding = new WeakMap() - injectCache.set(inject, perBinding) +function cachedInject(inject: ToolViewInject, sessionId: SessionId): object { + let perSession = injectCache.get(inject) + if (!perSession) { + perSession = new Map() + injectCache.set(inject, perSession) } - let props = perBinding.get(binding) + let props = perSession.get(sessionId) if (!props) { - props = inject(binding) - perBinding.set(binding, props) + props = inject(sessionId) + perSession.set(sessionId, props) } return props } @@ -61,16 +62,6 @@ class RowErrorBoundary extends Component< } } -/** Split component: only inject-carrying registrations need the session - * binding hook (keeps injectless rendering free of the Provider requirement). */ -function InjectedRow({ Row, inject, viewProps }: { - Row: FC; inject: ToolViewInject; viewProps: ToolViewProps -}) { - const binding = useSessionBinding() - const injected = cachedInject(inject, binding) - return -} - export function ToolViewOutlet({ registry, sessionId, toolName, viewProps }: ToolViewOutletProps) { const version = useSyncExternalStore( (fn) => registry.subscribe(fn), @@ -83,7 +74,7 @@ export function ToolViewOutlet({ registry, sessionId, toolName, viewProps }: Too }> {resolved.inject === undefined ? - : } + : } ) } diff --git a/packages/client/ui-conversation/src/client/contract/slots.ts b/packages/client/ui-conversation/src/client/contract/slots.ts index 276ae1ec30..a7001fb21e 100644 --- a/packages/client/ui-conversation/src/client/contract/slots.ts +++ b/packages/client/ui-conversation/src/client/contract/slots.ts @@ -1,63 +1,67 @@ /** * Slot-ring contract for the conversation package: the composed props shapes * its registrants mount into the layout-owned slots (conversation / details / - * conversation.empty — the SlotMap declarations live with ui-layout, the - * slot owner). Per the share-ownership rule, the owner share is REFERENCED - * from ui-layout and each registrant's injected share is declared here, next - * to the component that receives it; full component props = owner share & - * standard share & own injected share. + * conversation.empty). Terminal slot design (§3): full component props are the + * automatic shares — PropsRuntime (framework standard kit) & PropsStore + * (declared store's read/write faces) & the injected business face declared + * here. No renderSlot share: none of the three registrations declares + * children, so the zero-renderSlot inference applies. */ -import type { ReactNode } from 'react' -import type { SessionId, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' -import type { SnapshotSelectorHook, UseSession } from '@deepseek-ai/dsh-client-web-react' -import type { ConvOwnerProps, DetailsOwnerProps, EmptyOwnerProps } from '@deepseek-ai/dsh-client-ui-layout/client' -import type { SelectionTarget, ViewEntry, ViewId } from './views.ts' +import type { PropsRuntime, PropsStore } from '@deepseek-ai/dsh-client-ui-slots' +import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client' +import type { createChatStore } from '../stores.ts' +import type { SelectionTarget, ViewEntry } from './views.ts' -/** Injected share of the conversation slot (assembled by apply's inject factory). */ +/** The shared chat store handle type (apply constructs one; conversation and details both declare it). */ +export type ChatStore = ReturnType + +/** + * Injected share of the conversation slot: plain data and callbacks only + * (design §5 — hooks are framework-made). The store lines that used to ride + * here live in the declared {@link ChatStore} now; ancestry derives from the + * standard useSessions hook in-component; view rendering moved into the + * component, which holds every share a view needs. + */ export interface ConversationInjected { - /** Breadcrumb chain (root ancestor first, self last; ancestry(list) feed). */ - useAncestry: () => readonly SessionSummary[] /** View registry read face (uSES triple from the conversation service). */ views: { list(): readonly ViewEntry[] subscribe(fn: () => void): () => void version(): number } - /** Active view accessor (layout.viewFor backed; undefined falls to 'chat'). */ - useActiveView: () => ViewId | undefined - /** Composer surface: draft store hook pair + send/stop choreography. */ - composer: { - useDraft: () => string - setDraft(text: string): void - send(mode: 'queue' | 'steer'): void - stop(): void - } - actions: { - openView(view: ViewId): void - open(id: SessionId): void - } - /** Renders the active view's body (the owner closes over ConvViewProps assembly). */ - renderView: (entry: ViewEntry) => ReactNode + /** Send choreography: trims, clears the draft optimistically, restores it on failure. */ + send(text: string, mode: 'queue' | 'steer'): void + /** Cancel the in-flight turn (failure surfaces via snapshot.promptError). */ + stop(): void + /** Selection write + details panel opening in one gesture (store action + layout orchestration). */ + openDetails(target: SelectionTarget): void + /** Pull one older history page. */ + loadOlder(): void + /** Navigate to another session (breadcrumb ancestors). */ + open(id: SessionId): void } -/** Full conversation-slot component props: owner share & standard share & injected share. */ -export type ConversationSlotProps = ConvOwnerProps & { useSession: UseSession } & ConversationInjected +/** Full conversation-slot component props: runtime share & store share & injected share. */ +export type ConversationSlotProps = + PropsRuntime<'conversation'> & PropsStore & ConversationInjected -/** Injected share of the details slot. */ +/** + * Injected share of the details slot: the panel is otherwise a pure reader of + * the shared chat store, but its close button is a layout orchestration call. + */ export interface DetailsInjected { - useSelection: SnapshotSelectorHook - actions: { closeDetails(): void } + /** Close the details panel (layout geometry stays with ctx.layout). */ + closeDetails(): void } -/** Full details-slot component props. */ -export type DetailsSlotProps = DetailsOwnerProps & { useSession: UseSession } & DetailsInjected +/** Full details-slot component props: selection arrives through the shared store, call material through useSession. */ +export type DetailsSlotProps = PropsRuntime<'details'> & PropsStore & DetailsInjected -/** Injected share of the no-session empty-state slot (root slot: no standard share). */ +/** Injected share of the no-session empty-state slot. */ export interface EmptyStateInjected { - /** cwd options derived from sessions.list (deduped; assembled by the inject factory). */ - useCwds: SnapshotSelectorHook - actions: { startSession(opts: { cwd?: string; text: string; mode: 'queue' | 'steer' }): Promise } + /** The create → navigate → first-send chain, in one service call. */ + startSession(opts: { cwd?: string; text: string; mode: 'queue' | 'steer' }): Promise } -/** Full empty-state component props. */ -export type EmptyStateSlotProps = EmptyOwnerProps & EmptyStateInjected +/** Full empty-state component props (root slot: no store; cwd options derive from useSessions in-component). */ +export type EmptyStateSlotProps = PropsRuntime<'conversation.empty'> & EmptyStateInjected diff --git a/packages/client/ui-conversation/src/client/contract/toolview.ts b/packages/client/ui-conversation/src/client/contract/toolview.ts index 5271b7658c..e2f652e19a 100644 --- a/packages/client/ui-conversation/src/client/contract/toolview.ts +++ b/packages/client/ui-conversation/src/client/contract/toolview.ts @@ -6,7 +6,6 @@ * implementation files import this, never each other. */ import type { FC } from 'react' -import type { SessionBinding } from '@deepseek-ai/dsh-client-ui-slots' import type { UseSession } from '@deepseek-ai/dsh-client-web-react' import type { SessionId, ToolCallBlock } from '@deepseek-ai/dsh-client-runtime/client' import type { CallId, Translate } from './views.ts' @@ -28,11 +27,13 @@ export interface ToolViewProps { /** * Toolview inject factory: produces the registrant's private injected share - * `I`, called once per (registration x session binding) and cached by the - * render outlet. Session-bound by nature — tool rows always render inside a - * session subtree. + * `I`, called once per (registration x session) and cached by the render + * outlet. Mirrors the slot inject shape (parameters derive from the + * declaration): toolviews are session-domain by nature, so the factory + * receives the session id only — service access goes through the + * registrant's own apply-closure ctx (design §5; binding objects retired). */ -export type ToolViewInject = (b: SessionBinding) => I +export type ToolViewInject = (sessionId: SessionId) => I /** Options accepted by the toolview registry's register; `I` is inferred from the inject factory. */ export interface ToolViewOptions { diff --git a/packages/client/ui-conversation/src/client/contract/views.ts b/packages/client/ui-conversation/src/client/contract/views.ts index 611cc40341..0d91e74855 100644 --- a/packages/client/ui-conversation/src/client/contract/views.ts +++ b/packages/client/ui-conversation/src/client/contract/views.ts @@ -1,11 +1,11 @@ /** - * View-ring contract: the typed conversation view table and the props - * surfaces handed to registered views. Shared face between the skeleton - * domain (ConversationRoot renders views) and the chat domain (registers the - * chat view); domain implementation files import this, never each other. + * View-ring contract: the typed conversation view table, the chat store state + * shared through it, and the props surfaces handed to registered views. + * Shared face between the skeleton domain (ConversationRoot renders views) + * and the chat domain (registers the chat view); domain implementation files + * import this, never each other. */ import type { FC } from 'react' -import type { ScopedSlots } from '@deepseek-ai/dsh-client-ui-slots' import type { SnapshotSelectorHook, UseSession } from '@deepseek-ai/dsh-client-web-react' import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client' @@ -57,12 +57,33 @@ export interface ChromeProps { sessionId: SessionId; useSession: UseSession } /** Selection target for the details linkage channel (toolcall is the step special case). */ export interface SelectionTarget { turnSeq: number; stepSeq?: number; callId?: CallId; toolName?: string } -/** Props handed to registered conversation views. */ +/** + * Chat store state (slot terminal design §4): the per-session store shared by + * the conversation and details registrations. `createChatStore` implements + * this shape; views read it through {@link ConvViewProps}'s pass-through hook. + * `view` may carry a stale persisted id after a view plugin unloads — the + * registry is the runtime validator (unknown ids fall back to the first view). + */ +export interface ChatStoreState { + /** Details-linkage channel (conversation writes, details reads). */ + selection: SelectionTarget | null + /** Composer draft (persisted; survives session switches and reloads). */ + draft: string + /** Active conversation view id; null falls back to the first registered view. */ + view: ViewId | null +} + +/** + * Props handed to registered conversation views. `useSession` and `useStore` + * are the framework hooks ConversationRoot received as a slot registrant, + * passed through unchanged (hook transfer is plain props passing; no + * business-made subscription exists on this path). No renderSlot share: the + * view ring delegates no sub-slots. + */ export interface ConvViewProps { sessionId: SessionId useSession: UseSession - useSelection: SnapshotSelectorHook + /** Chat store read face (selection is the only slice views consume today). */ + useStore: SnapshotSelectorHook actions: { openDetails(t: SelectionTarget): void; loadOlder(): void } - /** Chat has no delegated sub-slots in P-I (toolviews go through the named registry). */ - slots: ScopedSlots } diff --git a/packages/client/ui-conversation/src/client/index.ts b/packages/client/ui-conversation/src/client/index.ts index 91b9c27c95..5605971c54 100644 --- a/packages/client/ui-conversation/src/client/index.ts +++ b/packages/client/ui-conversation/src/client/index.ts @@ -14,14 +14,14 @@ export { ConversationService } from './service.ts' export { ToolViewRegistry } from './toolviews/registry.ts' export type { - CallId, ChromeProps, ChromePropsOf, ConversationViewMap, ConvViewProps, ConvViewPropsOf, - SelectionTarget, Translate, ViewEntry, ViewEntryDef, ViewId, + CallId, ChatStoreState, ChromeProps, ChromePropsOf, ConversationViewMap, ConvViewProps, + ConvViewPropsOf, SelectionTarget, Translate, ViewEntry, ViewEntryDef, ViewId, } from './contract/views.ts' export type { ResolvedToolView, ToolCallBlock, ToolViewOptions, ToolViewProps, ToolViewResolver, } from './contract/toolview.ts' export type { - ConversationInjected, ConversationSlotProps, DetailsInjected, DetailsSlotProps, + ChatStore, ConversationInjected, ConversationSlotProps, DetailsInjected, DetailsSlotProps, EmptyStateInjected, EmptyStateSlotProps, } from './contract/slots.ts' // Export discipline: packages/client/AGENTS.md. diff --git a/packages/client/ui-conversation/src/client/service.ts b/packages/client/ui-conversation/src/client/service.ts index 40aa1b93cc..9c9ee639b8 100644 --- a/packages/client/ui-conversation/src/client/service.ts +++ b/packages/client/ui-conversation/src/client/service.ts @@ -1,8 +1,10 @@ /** - * ConversationService implementation: scope-addressed send/cancel, per-scope - * selection/draft stores booked on the session scope fiber, view registry - * with a uSES read face, openDetails orchestration, and the empty-state - * startSession chain. Contract: api-contracts v3 section 7. + * ConversationService implementation: scope-addressed send/cancel, view + * registry with a uSES read face, and the empty-state startSession chain. + * Contract: api-contracts v3 section 7. Selection/draft state moved to the + * declared chat store (slot terminal design §4) — the per-scope store maps, + * lazy construction, and prune bookkeeping this service used to carry are + * retired; what remains is the send/stop orchestration face. * * Scope addressing rides the cordis Service tracker: property access through * `ctx.conversation` rebinds `this.ctx` to the caller's context, so methods @@ -20,11 +22,8 @@ import type { Context } from 'cordis' // SessionsService tags contexts with — scopeOf then always returns undefined // in the browser while unit tests (single-instance path resolution) stay green. import { scopeOf } from '@deepseek-ai/dsh-client-runtime/client' -import type { Session, SessionId, SessionsService } from '@deepseek-ai/dsh-client-runtime/client' -import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' -import type { SnapshotStore } from '@deepseek-ai/dsh-client-web-react' -import type { LayoutService } from '@deepseek-ai/dsh-client-ui-layout/client' -import type { SelectionTarget, ViewEntry, ViewId } from './index.ts' +import type { Session, SessionsService } from '@deepseek-ai/dsh-client-runtime/client' +import type { ViewEntry, ViewId } from './index.ts' /** Mutable view-registry cell (plain object: mutation never crosses the tracker proxy). */ interface ViewsState { @@ -37,8 +36,6 @@ interface ViewsState { /** Scope-addressed conversation service (root singleton, provided as `conversation`). */ export class ConversationService extends Service { - private readonly selections = new Map>() - private readonly draftStores = new Map>() private readonly viewsState: ViewsState = { entries: new Map(), cache: null, tick: 0, listeners: new Set(), } @@ -71,37 +68,6 @@ export class ConversationService extends Service { if (!result.ok) throw new Error(`conversation.cancel failed: ${result.error.code}: ${result.error.message}`) } - /** Per-scope selection channel (details linkage); root access throws. */ - get selection(): SnapshotStore { - return this.scopeStore(this.selections, 'selection', - () => createSnapshotStore(null)) - } - - /** - * Per-scope draft store, persisted per session id; root access throws. - * Persistence is hand-rolled (raw string per key): the snapshot-store - * engine's persist middleware object-spreads state on save, corrupting - * primitive-state stores. - */ - get drafts(): SnapshotStore { - return this.scopeStore(this.draftStores, 'drafts', (id) => { - const key = `dsh.conversation.draft.${id}` - const store = createSnapshotStore(loadDraft(key)) - store.subscribe(() => { saveDraft(key, store.getSnapshot()) }) - return store - }) - } - - /** - * Write the scoped selection and open the details panel. Orchestration - * only — panel geometry stays with ctx.layout. - * @param target - selection target. - */ - openDetails(target: SelectionTarget): void { - this.selection.set(target) - this.requireLayout().openDetails() - } - /** * Register a conversation view. Duplicate ids throw; the registration is an * effect on the caller's fiber (plugin unload collects it). @@ -170,9 +136,9 @@ export class ConversationService extends Service { const sessions = this.requireSessions() const id = await sessions.create(opts.cwd === undefined ? {} : { cwd: opts.cwd }) // The manager notifier flushes per microtask; one await guarantees the - // list-store projection landed before layout.open validates against it. + // list-store projection landed before sessions.open validates against it. await Promise.resolve() - this.requireLayout().open(id) + sessions.open(id) const scoped = sessions.scope(id) if (scoped === undefined) throw new Error(`conversation.startSession: created session "${id}" resolved no scope`) // ctx.get, not scoped.conversation: property access walks the fiber @@ -185,34 +151,11 @@ export class ConversationService extends Service { /** Resolve the caller scope's Session or throw on root contexts. */ private scopedSession(op: string): Session { - const id = this.scopeId(op) - return this.requireSessions().manager.get(id) - } - - /** Read the caller's session scope tag; root contexts fail loud. */ - private scopeId(op: string): SessionId { const id = scopeOf(this.ctx) if (id === undefined) { throw new Error(`conversation.${op} requires a session scope — address one via ctx.sessions.scope(id).conversation`) } - return id - } - - /** - * Per-scope store account: lazily created, booked on the scope fiber so the - * scope teardown (SessionsService prune) collects the entry. - */ - private scopeStore( - map: Map>, op: string, - make: (id: SessionId) => SnapshotStore): SnapshotStore { - const id = this.scopeId(op) - let store = map.get(id) - if (store === undefined) { - store = make(id) - map.set(id, store) - this.ctx.effect(() => () => { map.delete(id) }, `conversation.${op} scope account`) - } - return store + return this.requireSessions().manager.get(id) } private requireSessions(): SessionsService { @@ -223,12 +166,6 @@ export class ConversationService extends Service { if (sessions === undefined) throw new Error('conversation: sessions service unavailable') return sessions } - - private requireLayout(): LayoutService { - const layout = this.ctx.get('layout') - if (layout === undefined) throw new Error('conversation: layout service unavailable') - return layout - } } function bumpViews(state: ViewsState): void { @@ -236,16 +173,3 @@ function bumpViews(state: ViewsState): void { state.tick += 1 for (const fn of [...state.listeners]) fn() } - -function loadDraft(key: string): string { - /* v8 ignore next -- storage-less environment guard (workers/tests without DOM); jsdom always provides localStorage. */ - if (typeof localStorage === 'undefined') return '' - return localStorage.getItem(key) ?? '' -} - -function saveDraft(key: string, text: string): void { - /* v8 ignore next -- storage-less environment guard (workers/tests without DOM); jsdom always provides localStorage. */ - if (typeof localStorage === 'undefined') return - if (text === '') localStorage.removeItem(key) - else localStorage.setItem(key, text) -} diff --git a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx index 540b76bda7..cf0aeec947 100644 --- a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx +++ b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx @@ -1,43 +1,82 @@ // ConversationRoot: the conversation slot's skeleton (figma Header 39:27730 + -// Tab_Group + view area + composer). Zero framework imports — everything -// arrives via props from the inject factory: breadcrumb feed, view registry -// read face, per-view render, and the composer's draft/send choreography. -// The active view id lives in layout.viewFor (shell viewing state), read and -// written through injected accessors. +// Tab_Group + view area + composer). Pure component — everything arrives via +// props: the framework standard kit (useSession/sessionId/useSessions), the +// declared chat store's useStore/actions, and the injected business face. +// Breadcrumbs derive from useSessions with a pure parentId walk; the active +// view id lives in the chat store's `view` field (per-session by store scope). -import { useSyncExternalStore } from 'react' +import { useMemo, useSyncExternalStore, type ReactNode } from 'react' import clsx from 'clsx' +import type { SessionId, SessionListState, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' +import { shallowEqual } from '@deepseek-ai/dsh-client-web-react' import type { ConversationSlotProps } from '../contract/slots.ts' +import type { ConvViewProps, ViewEntry } from '../contract/views.ts' import { InputBar } from './InputBar.tsx' import type { InputBarError } from './InputBar.tsx' import css from './ConversationRoot.module.css' -/** - * Full props = owner share (sessionId) & standard share (useSession) & - * injected share — composed by reference from the contract, never re-typed - * here (share-ownership rule). - */ +/** Full props = the automatic shares & injected share — composed by reference + * from the contract, never re-typed here (share-ownership rule). */ export type ConversationRootProps = ConversationSlotProps +/** Breadcrumb chain: walk parentId links (root ancestor first, self last; + * empty when unknown; a broken link stops the walk). Pure twin of the + * sessions service's ancestry — components derive, they don't subscribe. */ +function deriveAncestry(list: SessionListState, id: SessionId): readonly SessionSummary[] { + const chain: SessionSummary[] = [] + let cursor: SessionId | undefined = id + while (cursor !== undefined) { + const summary: SessionSummary | undefined = list.byId[cursor] + if (summary === undefined || chain.includes(summary)) break + chain.unshift(summary) + cursor = summary.parentId + } + return chain +} + export function ConversationRoot({ - sessionId, useSession, useAncestry, views, useActiveView, composer, actions, renderView, + sessionId, useSession, useSessions, useStore, actions, + views, send, stop, openDetails, loadOlder, open, }: ConversationRootProps) { useSyncExternalStore(views.subscribe, views.version) const list = views.list() - const activeId = useActiveView() ?? 'chat' + // The store's persisted view id may be stale (view plugin unloaded); the + // registry is the runtime validator — unknown ids fall to the first view. + const activeId = useStore(s => s.view) ?? 'chat' const active = list.find(v => v.id === activeId) ?? list[0] - const ancestry = useAncestry() - const draft = composer.useDraft() - const running = useSession(s => (s as { running: boolean }).running) - const removed = useSession(s => (s as { removed: boolean }).removed) - const promptError = useSession(s => (s as { promptError: { op: 'send' | 'stop'; error: { message: string; code: string } } | null }).promptError) - const turns = useSession(s => countTurns(s as { nodes: readonly { kind: string }[] })) + const ancestry = useSessions(s => deriveAncestry(s, sessionId), shallowEqual) + const draft = useStore(s => s.draft) + const running = useSession(s => s.running) + const removed = useSession(s => s.removed) + const promptError = useSession(s => s.promptError) + const turns = useSession(s => countTurns(s)) const error: InputBarError | null = promptError === null ? null : { op: promptError.op, message: `${promptError.error.message}(${promptError.error.code})` } + // Views receive the shares this component already holds (hook transfer is + // plain props passing); the callback slice is referentially stable per + // injected identity so memoized view rows hold. + const viewProps = useMemo(() => ({ + sessionId, useSession, useStore, + actions: { openDetails, loadOlder }, + }), [sessionId, useSession, useStore, openDetails, loadOlder]) + + const renderView = (entry: ViewEntry): ReactNode => { + const Header = entry.chrome?.header + const Footer = entry.chrome?.footer + const View = entry.component + return ( + <> + {Header !== undefined &&
    } + + {Footer !== undefined &&
    } + + ) + } + return (
    @@ -52,7 +91,7 @@ export function ConversationRoot({ type="button" className={clsx(css.crumb, last && css.crumbCurrent)} disabled={last} - onClick={() => { actions.open(s.id) }} + onClick={() => { open(s.id) }} > {s.title} @@ -74,7 +113,7 @@ export function ConversationRoot({ role="tab" aria-selected={v.id === active?.id} className={clsx(css.tab, v.id === active?.id && css.tabActive)} - onClick={() => { actions.openView(v.id) }} + onClick={() => { actions.setView(v.id) }} > {v.label} @@ -93,9 +132,9 @@ export function ConversationRoot({ disabled={removed} error={error} variant="composer" - onDraftChange={composer.setDraft} - onSend={composer.send} - onStop={composer.stop} + onDraftChange={actions.setDraft} + onSend={(mode) => { send(draft, mode) }} + onStop={stop} />
    ) diff --git a/packages/client/ui-conversation/src/client/skeleton/DetailsPanel.tsx b/packages/client/ui-conversation/src/client/skeleton/DetailsPanel.tsx index c59ddf80c3..ed018de252 100644 --- a/packages/client/ui-conversation/src/client/skeleton/DetailsPanel.tsx +++ b/packages/client/ui-conversation/src/client/skeleton/DetailsPanel.tsx @@ -1,14 +1,16 @@ // DetailsPanel, P-I minimal form: close button + the selected call's args and // result rendered raw. The three-段 Switch / Prev-Next stepping / See-in- -// trajectory are deferred (ledger). Subscribes to the per-scope selection and -// derives the call material from the session snapshot — no data of its own. +// trajectory are deferred (ledger). Reads the selection from the shared chat +// store (conversation writes, this panel reads — the cross-registration +// share the store seat exists for) and derives the call material from the +// session snapshot — no data of its own. import type { ConversationSnapshot, ToolResultNode } from '@deepseek-ai/dsh-client-runtime/client' import { shallowEqual } from '@deepseek-ai/dsh-client-web-react' import type { DetailsSlotProps } from '../contract/slots.ts' import css from './DetailsPanel.module.css' -/** Full props composed by reference from the contract (owner & standard & injected shares). */ +/** Full props composed by reference from the contract (automatic shares & injected share). */ export type DetailsPanelProps = DetailsSlotProps /** Selected call material: resolved result node, or the in-flight running call's args. */ @@ -41,13 +43,13 @@ function pretty(raw: string): string { } } -export function DetailsPanel({ useSession, useSelection, actions }: DetailsPanelProps) { - const selection = useSelection(s => s) +export function DetailsPanel({ useSession, useStore, closeDetails }: DetailsPanelProps) { + const selection = useStore(s => s.selection) const callId = selection?.callId // materialFor builds a fresh wrapper; shallowEqual short-circuits on its // stable members (result node reference rides the snapshot's structural sharing). const material = useSession( - s => (callId === undefined ? null : materialFor(s as ConversationSnapshot, callId)), + s => (callId === undefined ? null : materialFor(s, callId)), (a, b) => shallowEqual(a, b)) return ( @@ -58,7 +60,7 @@ export function DetailsPanel({ useSession, useSelection, actions }: DetailsPanel

    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 z zaMgiMm(BM=)B-|ljibn92HLxgyWMk*S(2wLAuM?IDmYXd- zf~<2{4m;x@dpqdPwkn&|70LiTEnGETynIr%8D7RIfrwnaKz@3K0VLX|TBCi#(-Jhu zqfbX4pdw z?>K+)o^7khL0AAd)twNl0+haHBm9?LPOgw8E}!x5Mx&Aipwsv)rRwwk&EVq*6UvkY z3pI#~{bT3Zd%7cae3&y2%22dVQG%SHbKEobCk{zW=g^I9OSuNinw1L?TlDpr?B=tk zo`ELr9H>deNhkB{e=X1p&+C<_DFm12sgi>)wBjTbWam*jgOZ_a5WFB}eZ_a6iO7^^ z=V|=SQCGCXG4J`4YgW7gVgE;im1AK$dZh?pIM_#I6fH5{;yg~dgf(4~iGXN#6@pz> z-4d-hV)XNIn39fIo$Q*>rw9;>jcQ%EOV%qBDAGr$m`y+cI2 z+4)f3WJ2bAW$!=AClKFt2r_XFzoj?><~Cz!GMxEZLQibUrtvR$M5+QZG6+$=b#WLD zHJY>$Bm*W=pJv78G-TbVk(D(e-ZaSs<5(Z>f zBFg|D^qPmiK|oNcVG?1HAm|rPXF)|cD^J9BfH4nGciJlHY)^-@*kC27dX$*@9-)qb zvnvqmFRlHIh&VEX=Z=5?;vJ%q-yOFr&^;N$w%sdi0%1$yU;vcpFh_FBMv>F0d{L?c zSz|8-Moq>#NhdJzAR$4YsWw3$hyFQ1Ac-(JYUtF~+5V)llOaGMgahQwcY?y?#Z{<>h9CCHiS*y^C=8ly*Xffg>b9|_dR9h{ zx6^cWit-rRWoJe=Q9uZZlY%5Mn4L z6L{;%l%A~7^M7IEggeooP4*V3Q{Bj`(-B0gioh5kz5crZLXI)p8hr?CRJC*2{hq1) zCs8SysHD|=8aVVPsuY}W(K+PkEDLdwZ?r!^`R$g#tH0r%9X*dj@bL?haRDjp$0f@4 zA&Nx*svFx7jI}?=E=g(YZ%%xbB6Xx=5h3Yu$K3KB;70%d_|!%#Ttg}=AG5bX&X7b8 z=~+eT`f;oL8_HIO1Re|O>AfTfYpC>I$1W|nUzNu%2k%#WBZ=@=FYElK>Y<{im{gWk z&$&GJfEks5B22IRhcQ+dnc!(xtjfzmYZ}5jGdZNkduvm-2Zmt6m zPK)sAirWLeRbL^Ks?+Osdw1{q+48&-q5lEFq94I#hRVhFtPMu-?g=~N1L>)StKkm= z3AT@%5IhCqD6@`}kfo!PyuqC6^<0gfiZsAlgs(g(b&}-(7)ohZ6Us|fD$@MOK+Y-U z!?QP^W12heEbllaT!zbK3If>59Hf|SWAXx6I z13O-!b)fZMWis~s(}d3kHb7cDmR!j`vzEHUH9T)?4Ix3CXGwcO>M)5Q+wd{6V+LSz z>@?0u>1Q1J=Vp}BwyU*qV37Y;oRv~2uaJZvj_^GUkNuAY;tTa4CKPxSa9Q{?HLv7aYISZD2GtDhEV2^8 zd=ia_m8^703!BQ4QSI_cKn77-3F~o-gm@ zYyD`?a2Y{L^uxN@-~A6nS~qFKT|C{*MftTe#5-bx;qse&X3=ZxCsb;7*4pN3In(6u;fJyH;Y$(hK`+G~PZAoI6@(8J-=odVvMVc`} zAb8U|YlTI(Ay~lY3A_LQ{xA4@q~T#|?gE>{92|H^fN4>;2$Quz)S}0RXt!$&mDqIV z`NCf>N8WM|*KJ=H+Z~X6V@L6`a|7QZ-iYF2E`a{7VDIU5KPrc&aPL^pIyQ`*63=96 zM^^QOh6_2!&^m<pd5Ol~%W=Gn zW+*2&Ga%^0KDOL`;Ttjsauj&zR=F)I$P)_U?;Dp+h&zthjS@|!h}M!RQXdE64mNOA zgBdlK)GKwp#QUZn=mN{paU=2>fAKS}8lkhYrh=M!7@6kTIJjH_@m8?LX6K^o$v+?B zH1yz^-ul9@h6lnwPB>i69h+ybwvDu|0r#skEl};ye15(Rb2mZ4#i3*qJwcC?(uAKAO=Hzd1_}Tz zlGYjL_xy_B{2{1}1wMJ9ENAH07A{aIdqyjQP}0!Ad3l2or~8XpL;<_m`he0KfcetG zCLR=)&6Y$C^PE6`2j3p<98v%v-%ca-T@=0#P5)x#I&6~5z|GOVHzL$F^=%p* z{`(aoiB1D$6Iunqd?Sa63UZNT%D+S|%plgLEpbnYtza5PQ~%Se1)%5n4D)=$O@GN- z^a2~)eY4m;bqPxKZK>T{AL3|Tcc=3&F3xfkibIs7U?llIv|LJy(C5o%4H*32;y>Th zGkpy&;k$mM?!!P(hi?<9d&f$6jl{xx5|>V@UAob32x;rk{N$kv;*<4Hui*cb4q6-A z+Ws@oi(!J9!P^Sn6nDe*Jo8-*jVRGdJB%UYMw#5cj2n#z(9u~&V0~gaG40w&h*15& zkWF;GiL91il?y8h%{nm1CL!3grQu4V^xC?u{uQjch~;7h(M&9ru&geJUT~wx1!J*j!j*n*siv{Oc5Qn+u@+Cte_ z7TxDf+^6xSJEc+_Xu8?x#4e~Y(31llbYA>G-y_rN-0b<1Uj_eUCS7N%-`QXPp2MBZ z57UzW>-(giO>`4?|Ns7}&nTmL#~=UwWszTqAk(}60K;cUy+Q7tm{LV4FW=?=Myvn# zMycl>eWv~%eV}JGl2rH&YoHKy^nwV?oC-pm0}{bvO7Y&B-1`}O5}GRn#sANmewNl> z|No@9-t3G;r0u9=1NSNwpScb94ulgEEJJY*!$!H8`Y5gf%sE|6hZ+D)A*wpBi@zZ1 z$eysKtfjB1kJdq7tnfBhU~CI@qF8_ci9*)Wu*Mxf6DMEmI zFC$O?|HDC|t07wW6-0lLrVutgKembl)>95|k?Agr!qAH5+9d6p(@0)6WINC8vxLvF zPqxC?_XdL~B_PX6J_fn(N|4(i0ZFE~cewCxgBcBK?@Ii#X%H`R)7@Z#`7)dTsy)w3 zIC{o^mH)-OBNOhO-{%N7$5@F!)9RdeC@>WJBQp2Bm5qbu6Eni3FD_BZew#l zytd3=kdd>O`y08dV#5H!SdRyt&63;{09kAE%F_@HZ`QoRx7G-oANCi{Xu!>h<_7p!{uFCuTNZ&; z8xN%)J6Ytre`6ME{1#6dA&HvOxL9HK46&yVX;pV+PZywq)e_IHXihDm0Gqu5%|=CpePxZAxj8UF`L^9su|~(D zO=<`uX8G^hLIrxZ94a&NIR*WqpP&Kvi$nk|Dtp;)nt=tWVi5Dngv<5OU zgW+E(%}D8h^YHET@p-f(P%`Y~V5#OGM!R9-Xr3b&qXYk z7v|TrxJcTcI%}ck3C`DuYyaA)U)(sbWu_EbgPVm_3!AdQ2Pw@nj{H?NPGo}JkatkVkyQnF$7@x zs=YB(D+Dx*(f(Zt&C$@r&pRgv|9K=bi4QBF0;$Q@=jL^q+SE_IK^0JQ$D(M@qCcbJ zHM1Ev#hnKIHp2Pw{0X_4j~>bl+LaIEmj1eb;i_iW(tkLAAo@Gmmqo69ZGe{#a0Ra-KR&|+hHlO@(!T4?A?v&F+n;&5h?<|0+L^%81n|C z52wNWQoi{r7yV%%#-4UoVix)|_%FPwI-^-jN69OPzTANhHK6Y~$WlZCWKBGd6ea)x z4{;&)+(ZBO_E*4crZe0M?9RBdxBC0xiJ08#mZc&lL>{h<*TLUl-sd7ZLJp`aNo;uX z*J_?Alrv>coL!p;Z7|hr+=g|az~G*8C6Vg(nPkDYoGsYvltZuYj<^*kz3XK35JT+Q z%<}3NW?5A2%9th}-ZswTdLfmr3hlCNv>Y&&(*}`pbI0pO@pR~;ghPNJ_j4bd)M8j* zzT(+y47AVy00q_#ai+RN-@I5Ld)a$Vi*A$2z9$|SoOe!W0-EP!SjsrlED`Z1Qv59r z#-n107jccdE+52wD<;VfA4Ek z&F0*u=p$6>=!(Z>G_93cVuSzpJUDk^Vh4Jy9*87TleB9&XGt5xtd_Fl(HjijU^;wa z8#AH<(mylJ_j%=}A9TsC$?KmN&b*l;pr~ADnX8>2{FkDN{A&1z zbaZD8?%slYWpRqgax*Z^NIW4CL4CNscJfbJV=(oVzddG=bwq11n;l;^8{r`8dYqTs zi7@JS6&g+XAl;#u)=snSNrNH07Oy5$&?dqA=iVY~f7?KOULW<1@_p`>R zw__51U7wH;pfT5N0z{!F_W?BKZJr~{jChSi!cxFrZewZ-0#ILN+ZhvHg8+-Jt#HY^ z9{!P54iJ<=HU2!39aLsQDp}lX7rXI_{|^6NYtV^&MatO!E5_O_j1>yF=S%C*`GO<8 z8TL)q^hkwc=T;8jjNt#ozB*Z1eNImdjONNnE18;Ia{f>Vx~CAI;VX3Q!uln(rcqb) zfY0b*&qjZ?YYSW<4h>MV=)^?B1u*$A+16&6JQ~Wl%^d{iNSOW-&+1-oRW2-2cyGJY zXuM6d1Z66Fc8c>2!xV|sm0-I0XP2z_otdn2-2wVy{-oGBKg%o`RU7w_!H66P=2SBE zZHPw7ns72;`%Jg@@+h@Y(60bSb%(}%I% z_E|eXYQQ=W!}Lr+OGCsrtImno6pj!tJpG#ehb@EjJ^TO9_!qRWfT+K{sb$|pE!~ST zGk<_CVg@I{6R0$k)ee7v_Ew!=^BXRk04NP;z`P4ca&zE|EziEjQM2*1(uXYghrXJ* zy7j~?6S{owp?v^Z$)Cc^);f*l&bx4zF?Ylgy?b8;zG^$fbulDT0G@Knw?@fhU~0}| zjth;-%tOMUOcup`3A+tb3fFCI=MIz}p^eL0pJPHRzp6Lv=}GvP-kPv?{#6sLo^Yau z8|1i|yQz0qkpepU?t}e0I08ODCXNLx#>%4*%i#wI3qNfj>gzpCn-6us3*-{weVAaR z8*?!Lc@6I&cbB!sK%BROl_7>-X6{oy=}awS_5H0g)LU6&wsb6T^}8XtobW98<4HF{ z9hw*Bpgcf$+Aslau>i%q#9R~I?f~2{d(Y=W2Q$H=U^Hl`$JO zXbBeAO)L&fh8eTfGaK=dhP~`sMh2z|^{lBE=<+utV2aUi(|GR0aDYbaT)o9fsLncq zkTxWfA_ z6)d6tMg|Lyb+P4%rYSe1Ymfi`_*jqW^PCn}fB_c#Y_Ow1W{-xpj&c)YIlLx#HS}E3 zS|6Nedxk+PJ;iOM;x(;?moq*kcoeU-&F`huLWa$8w#}tQ9HII8G07?~$Qi4{T!yR> zp0+DqA1#bdbWWc|Z|p0pd~u3Xh9cY~50!XunjYnh`>~^8Uh=K_VB!l<_5#Z!Ck0@G z4kNRXU@WntV(`84F&?j{Qnp0Gz-fk^F{?iPnkmof6&1ruyL;;#diC?Ka!X4f2RoTl zdoPOqt@Y%or*IKIKR{l^UrSn`#c%10@@l;Bf6zxy{lG?SZf$d@E-PVR5X{7zYe<_Z zBPXPRX)|K}mu%Zf_5OLi3{~?8F^5PpwsY$_a1QcVKL80a9%4EL%14-|G7df)z?eFf zzc3V!e(%j2Gp%R_L?f1?wpvz`fT-&A19Mt-_VHK??L16z3cm-EEGs-Wa*A`L=;fKeE2y~n zb3N}V^Y=&u7LQ~t|5hUFNRrS#M3+5y|2*Ks6H4=g>EBcMgFfZAW$jx&XRfIPmD+oJmh)Kh=mny93ggyFFc4<ka&-8G@V1}sglZuKBm)7?>r;Pwd~XoH?+C{L7sO>L8Ia@i0MNTv5P(_WA| zzQ>x2G1!ggGZUyw237!4J)^8e>?2^CtC_dd;0uJeYijz&H)Hp{V z`-*mxsV7@yJwLslvUF&AHP>qqXAhp*txW%zC-YzbeS`;DBmS)hhqudHpT|)}x)G$0 z!HUc{Quaf{C@K-E>9X-oiyWYJx8L1GB^0r<`?`rhy%v^M#NXyR7$0-%aj%Bac_{VV8(WST zhpjhrDt@>Y2>?#{w2X6rSpWb3cHuZl;kwQFd05cWa6TrA_5`eu78csfv6UTzFk+jr zI?Z1FoQpVP+b%7sanA;)qOc*?xyzl6Lq;%xE+#q_=rIY?S!DgopoO6kZ}<{6Fvj3v z|IH5hYxj$VJoNY^#|V2jc&nMYW`pshri5@yPKjWEEed+Pm#SkqhWPR?mC4^z>V8*? zI%%ANQIK9$f0!%ziBM;qpm;>k5VMSOna0&TG{w25$so5PMxE7tWp&c`ZOb zZ;i`sUz}zjEU{Jj1SKwyfLUO2Pm;cj@Z|IqiI?ajr~dldeU#7w(J|D8)dGyA<&7W- zjt0LA$31&Y*FNrOh#Od@euvE~1jcqb9Il0>I?U2Spx^ocTtK70Gewr4N{(9tYIDK~ z(V4-A6z)b&#`Ayzq*{PdpqI8jRyDDX3nvw^D>vmKZth+PX~~qAX?`s@B@^{loF?&! zFqa#X3JK$0%xiVur*GkY$$Y`OO_xmNgVc6xtK}ZfE3$GQO7BVt2YMHBy|5E64-KhG z-{5q8>Vfff_*$@g6&X#p?DJRpzpX9z9zrTaBAE03f*h5xxNLFGq@X48@R?u5s9pkw zDr#XlG+Xj4+_>c-WDNER@WK&ODcw|V#xx2`7(H-j>F1{VC$kZE*Md?{=2mR| zf=b<`Z=oNSJ1%!$%`D)`TBS`Zfx)pheNl8260gCWHkh@ zQ_3MQUG( zep$@b{|-_|xWCHy-UU(z50G3TOO=2R%QY;8s5Wk-t^J(;ng2j1PbX&1$dDfvU!DB_ zk{Pmtj9Z#PnVL$)^B|sR8{dY)*e1@U^DxcVcnU=`=Lxr({j&)BC$KsaZu?9)V5iwX zG|HskT`?`OO(3Q|l_Re-m&gD5AI5q$8q5+UI}enxD|jo?&+e*h>F|}cyPu$Y4h!w| zOROh+<)=imW1S{6v_VZU;J>_ngV$H-B0m^q8L|f!J8>B3!O7MPU~G4@cT5VXuSm9= zu^6U@X!O&1wL<4tINZ$a&Y%CVf3+GrRu~D|e~^r8YBV9JWv3Afq%ar{)y}=o$ICII zR-&yhL*wUx;BVUS#_*PjpYA62p_~kdrBdRBk{)MhSIAtHv$ge3rDJkn$V%RetIf@+ zm_Omya8HDd+HESn`nyVVgyuGo2_0U65E4h8Gx7+ zQ5n{T9l-Gk*$n1*nVpjYr37kXFiDK)Mu3SzwSyL9`Y-q3In#d?UoW90W>0Ly2dh*3 zao6}5pmAYN`ao&m@Gb5%6@zqAlkO}q&E2OqyirNku{)BIK*nlSJbKn>j{%q{>%C!A zwOiFOa>K%Sc(v&cosd@KuN<@6*_@%;b^&3m#DtxMAF^zFK6zP=ye;k9Z|`D|urrmA ztN357(3`d2<;GM|);CDun9H5fKyj_+hLv@e4iTYVQ)0VVi~F&=h$tI3!)2W_I1{=jW`EzF8b~oO!b#^wzWx~XvhIuqn?7okiY)2yI?WVJJ)i>e21*6g?BYV z>v_{hzcx|Za2vs;YBcEvcTsD(N!b+Dch88YwWcuYDiuZ+JGbQy%d+~NKZ_XY&;!|* z(%Y|a=TeOQm{^si&#cQuildPuD8$*LwD)-oMwi-P`C+g5b@jud^s2K75x@C|j7Zit zQ_#it;_V++|DVCCPBiIoJHUVqH!T=Oc*WgL>p;HEgGj!jH;760UtBeAJnTN8?rer#Gvc8DMUVZ6k-$ckFvp zfvl>si`@4>i{=UEl+ipU1=LgvQNwNrP`mXzeH8jq9e(rTIZ04o*X_FSBbKjxqPAv) zBRgQ9uV*j+;5nv0<$j4v1D$Qa!1Ioub|dca5YcQ~8l**8f=NEJ7!h-a1|E;PBGLPi zFl5;((*f{MKUOa4TDL=$C>zGmnx6210Blt5|1T?27T|#1@VsLq1SB;H6GANqv*p0D z{ly!clepHXlpCw;jFt8Udg9OLYNsr^$l#EE_JD>5%4d31kh|OGS(nF!)!OY9vDE^L zp@2Bm!Ub+Qf_;iC&Dn6cO!(ReAX*PkN_E3%a0o+3OSvLS)=5sy6B%Ghw;hg|1T5xy zT~Nf*Kea3As5U1l&clQ&{=y^gu+(#$rq|T-pLV7V5g*A4bd1%?_scP#R}_S$@6kAt ztzqy;pE{ra_OkawzEL1luK<8AMd}D!v?gx^oDXs`7~pU5G_Hjv(Bb*&&zpymh&o>B zv&!t_s#@6*WLC1w#4BJc0q3mSxBj}s6dJ3ch*R%9RJ3g%as4$Spp6d}>$49(w24jFd-wW*!p&VC5ZeU9gNu;1w1weV?aKC(bojo8d^nmW0BI&e#2m6Q0%ip&Io( z*Pa*pog`&?>q&*r6}#5LwNYBO1j}sV&G-1%l`J1d8c<^7^2H^ZEBlcNBHs=t#$#@R z69JQytRMSP@rOMDENjPmii7&UgZhA#7pqbXkib5zYzv}BkZXRY`7wwNfo0Ul6`gY1 z($U20Zy#s_jJ`S;?O$?%D3$pKNBaxu*%5aMauHhB){jQeeug0}n@8fpb;H`P=3y}) z)!sFQ1}WicOrRl{JXN-PR;IYrw~`03s#1NfWp_LTk`c?W^AY*;t45@8QeKP&rTrN>nw<(G_*lAmq1H1Js<)qrQQgHmx+mA@K&C} z2->DwQ!U{=7rAQpiKT6c4ajL3(E=BessIw0vvaZ4r{p2MCb}l)^5Ia8)Y3ZhhDMik z&PFB|WA9!Tpuf@2Ooq6!r4tAW4=lwJh0(od38@H21M#0dha1>pi?mZKpN^ml3v0 zywDwd3@O~-;gE@t*wIO2x<+svSJW?*?XnvBMg19}p~7$|KCvzWwOo>nTWDStxu`31 z=&STz=?S|au)7*DrgH5+1VwE*gHp5My-MUZ2Mo83WvXR3l#V+1u}s2Z@8IS?;`jy z6B$z3K8XzXvqguWhx$H?Sxip7*&?}h5BvW_tFhmsT4T35Z5C42di-3I|!KZ`-LbNf{djxuyFM7}^tYuF4@m_?Q%(r(%4UvDyvE5gTp^dxvHrYI zL!A&kuR(fWH!rhkk&PqpVEC%Ax(56?XyrI!^bC+Fz|L_}AHLQBv)Q|RBjRZ9HD9M= zh{*r!Ph3m;jq^)%aqbeHQpRVL4pBB1dlLMmlq?VbhFoas_nG6)k!$!>Qxo^eBrq6J zNAKg`IsrRc=~LPUC+Q956!RuDH>D6+gD$}_CJ(8{Iu zO-V6Ha-n90vfesxrN!DH!|Y@iZ3-`Gs?#MJPFIzq2A6aim;DmiqP?tt|Ns78UT<8x zP8P)>ON4$@Jm-U$N8qV7RlP$QStC^3NLMoq*xEBq-7REb`7E|&Zv7&@fki=9+Y04o zQwGk_!Nc#b?Lu9S_e$TrCj3B%k2RaLnW3&7io0Gkw?&z#Mt}PFXYk>*iX^4@$<;<} zOSC)Q7Q%>ZqW-3pVj1Umss|j(`W7Tp00jRQ9j}CCk+#Jf1WmTSyGn$64ZtA7>`C zUByg)R!tob+eAGJtb0jkA@-W?nIl=pR%*dX*|`Y9cdE6>OO~ z&8kMR9Me@VK=r$bGPYXhC3R?(AlR#xwe}p9NqOx=DD78ue>+h!iMXpPNylQXeik1) ze0}XWA%;}Qo7VO!c)NugmfC6lAc#yFLqD!Q>IJLWuFOZI+4byr?*b7Q9NGeOlpdPv zASWIA-2rMT3tDnLIOkOJp$!LVy($7hdqzD^a5+$zY%aQOrgum-K<+GO;ISgYfz^DL zXKhCmP3#i!75u#&nQ0T4P=I>^jc(JIa;A~nQ#I<+fB$wEw^dx9=muu;iezv|WmD@V zbdH{4n+2h>3BzmeP;1ogRF9JwC^J#v^RqBgCF=F8`4i--y=Lw`>6_Y2@7mEs6wEaF znN4VfC~Q1)>k(x-5Ug(Ycznteu1%_=Y0 z&lJHtLZNJ5H`gFyt2L`n&;S4b|NsA>+Uf%A%6SjW=d1&s(VPqM|NmR6pW0-KYJ4_t zl{wP)S{XZ)TpuslGUsnKak%I*$K0#X$n((dOju_Md!c`X=O6Ce$g=daZ%`m%yv-z5 zmR5^E63x00Fy<|mH4gi<9!e%=wc$d$Evj7 zVb?@Xxc%K?#L1F)%I5KefD4Urp;-^WL4H(JXrxZ%jU_Aa6XZ3=?lr(we<}xj-iO1U zF*oevPk;_%{uuS-`w@c~y|2(6uI&7ufM8n}a8%?m`7@3oiQ>rv+-^t`BTj_)&Y@QO zu*A7FYWB_FY@^`qf;-X==nxbI=uxygp;W0T;(+@y%~so(KYa*RRsxE`0%af}pG+6W z9)}EZh_CML1(TsAZ4sdnGoH2N>RLx3?|~l%7auFnL37lJvDyEgB_&R z;m$10+5QZa6tN=jKdmbqyFgstBLQG!xZa1<@aRC}B6;*{L?ldp~H(6j_LYB(co13JyhjEbLr^aR&7L zw^AkXNXY@*uTsudaZBs(o#2RdAasKDPnMF3MqY+^)bEKQhQEB+3n;y2pXm_QUkjhC zYppY!@v;J_aQu|-y^b9)w8;6?C7wmDCmYyC_#+}A zyy=*j+I`Qqs|rQTuSnQ_pAv;RHQZcYA&FkFNW{M`exZa3=We@rfYP@*re8|qDdnOhpX z_Q?p+ut+Cc{1eMcY`=v&YBy{9JsVLcR+|qJP6i7!Ly4=%lX^I(T}zjTrk1H% zy6gu7!$^Rl4V4Qsl!}rVf9qcC`QAcYPmj-5m$QmQ{PeFML^J)70>IHPgY{0jhw{ZL zSj{V%UXku4E6I?Sbyga2B$PDUYdd)Qc^83TE-g}>|}%Ds;v@!X|l zQZClw+c>>ymT-6HYCklW5Z-rmiZlQJ|ImESAsC2T)R~+Kcp)VN3H;uoEIaLZ`f|to zJFJubEo4mJ7e@74uTc{U3o)QUBs`O>;+!ONuA=V&)?V{5>X`{tGOy6Y&Tb+^n|aab z?htKMvn=`F+xtVw;fsXdfaj)Y3>mhXmc~P@;;QKD4@!lkdrnP6RRca@-)z|Eze}w9 zFVxjx{Ed|bJKi;V^T3_543L>&Tvy;J@&U~yQP+t>^Gf|XJSaPXwyTfFo_$-#_vAp6 z^P;e?0s<00VbL}}&!d*VKawJa#`e`B>ghgk9d*rTAb9%R{R*F!M{^*bO5FfYk+|;c`CR4rO zA8lO39g8l=iHz2d-JA~l9#6x38Xwono{1S^F4V4ST`rYxWysfc+ZTuKHd`~9&<~pb zBgxaHx8t*_8|65u1R*_()C)tL<3p4%1viH3r8-=3leM5Pw_m~tK2{ygvx~k#5B_+E zg(SXnoR5zG2`FY)YA~IinDIK%_gvN~quDRe=fcA{sD7FsR*7>|(4CFZV6tpJBH`!W zL6z$0?R>3qYI$u33!@GuBK;s7t?E=PrM=kJTMFc_YbmltIRA!DWE|_ktX8!PJLb+4 z$02Z*#iUgXTHJ?;8;I18x0Z+>cq&(&M z6})fCL&uJfNl`m0Q+L}lZz284IAOvK`-Q_Fnhj~68e{*qb*vA=NVL6@>l(0bm1G{M zB4osdWg5IlBskvX9qfN&NPd%F3%um&F)lx-)YiHmpvzUvFp2znM_5{vz1b4siU0{3|~e z2~!f&Cn^yaWn{PiQKX$t1VrG|{QsyA#TRiDFRJGko?dUPS~4jMmIa)dPBU5 z(7CO4WT$Cp(!97>V@y6VXb@4JJJRg#%DLvPJj9K-QHG!i1nNy1RWr|^6F8f#K~~;h z^HL)lLnK-87sL*J?mN+YmRr^_Fk{;;WHp||&g{AQOcexcN;f|jptieUQ>Hi;Ve$Q( zllkh;5`BBLW91mK9m?fi^Q)o$WV^2GrltEdx8UbC=mFclMx{q`jxN}gIwzE;?O(5x z3D$`Aj?ekjA5%aFRAgwpgW}mM;w2q$V1_N=iW)clH8_DJVXAgKE2uSda{1IZB~atl zSbn<|;p8Ny;1!Ju>`iK?JLSUc&OYX_$1w)aQyPx%gY3a;{r&Q1OZBP_`CH1GkgNlC zt&mUMre4`gLg`{m8g`W)Upi!R>VOlZG<=8>jMz+{2}egk!>2mJDr9(=@drxaroz#( zSS23sd}b_@bohnVsThwbD8k(1;auB#>oCNWCW}mxHyYJmqzhzQ$1s6X=Bhq7=!qi|CUF8siZa&( z%FU|r>(cW#3~0RB0=}EgXW__>&9m|n;Kp}YjynJ05ra1U9lg|0TU1P9`?)^ihE5vs z#@hNLbsv!9wkEZE{aThX12t0a7Hs5hhrXYTZ387L=cj_gB*CR%dL~)0iJ1e|&8}aLes)(Ma<|TXlf{(M z+(+Y|ixyhQ)5nCr|B-E{`OGYrrS0lhdjIZ$8E2z=gk0LWq%%(=D}F$@<*Vl%46RnA z7Ch%39P|D)w2<~|fFzp}za#y2Pem`7h%J89fxpp_>Nfz^9Euem8w1NHfK(qfOmV!9 z3c4A);h;#LgO1>Kr=<=TH`4dL73JPjCJwFhTC6`!pPu#=g8%+YwhvyzNR(-@_gNGs zKa3-{L8jH`trEx{PVID^hbGZbOR2+XY9>#6C^(Us)foCP}Thb|0yt5 za?@@F^ID8H2hIz--7n^u(a`r2K|qtS97GnP3n8KBw6jhn_QrS&kS;J+XzGZxXe`!P!{Zaugj$ToGjUrB>*wBl-B!3P+26#rp=~wWZj6J1A7& z{}jB6?nh?(`Z#P{mk>4gF-g?jUYMXpH+(_^tRPe#E->+iHl|SJ3CU8bhmf(RESZQ_ zX19NLsUvIbD-W$?*O{oDC!Dmh=QAFAw0c0qvkMn98$MLF)W8t~BXd^B>+JN!a&Fl@ z1&B#0u@?`#L%}7GA?7*PboeP_STQ1%@vM?OQ*OeP)$xoim@M@nygu0 zcDPw4GgrxL>L2b&fpsTruTV9Mfcn383GcqR8Y)2^Uh@j=?cEh_wEvZsR*R#h)<5QW_` zkeP~-C!Y4o@XbwdJ3EfZNF8Ia+|XK0rF3v%2V0CKJnrn~okb5U1xM?U!M+%{xqGim z_P-T1o9bnMwo_)`CZvuB2G={D$v#ae(DV(&|7szaOGI1B4?{{d z=ah_&oFl1|otdai{)>yv<`)X24b+dfAA8)Pgnr8Cu=;>>w! zq4{ku#tJlvR#vhx-KLmx{`?{|a9X}sd~E)Pg_`wxkTn8Ivb%1Mn|`l`yH|W8iA@OM z`1jjrE8EKBkTBa+iYGWa09p^wcYzY%N#Z%+YS|t>hAtRkCmq+c7_*j8xD;#Eg}f?O zPL0*-n{ic>iihXeNdx_DgJNo*VmoZYn-U~o#UaPHl!HA58F!Q$A$qK7Mm33n25nW; z|EqA|x3K+NN5l}WhT@Ibx+#S-vb>7 z68wZhZZ)GrgXR6WWgX}b3ciSQQ|9vGM^>xRiW$;}r8Rpr+n#hiwRJ5p1Euz!558S6 zMk<3cfqw=%_dALAg%3Vwc24|mN>7iX!;{4OYwe>qRcAgSKSmVg8GTK}v~p9Fr~&n#P=C^U;x!qx_UV_k1d6J!Hqp)>Gs( z3S?G^69YW5p{#8^n4GmZb&qnzDy3i;vw7?jWas-Jh5P3z*jk%|AqeukUM{s6Ntgq62PY{?mTY&>8U2?l%){$)_UsF%C`(3}EZSQY22y)H9YpQyAJUQ$K(bLUk38)M- zi6S%F+cu>`@vtbybi~2RT(E+8i+dmeq5=1MrHoI}crdj&QBhGG@f1ar+#CI)r9EN4 zeB6|`p4F|JUaGVL!fi^;8<_zvL557-Yob>;nGD;1zWJgRS(%IG$QKC@)mK~>W=lS5V?9Q(d*s6X zHK)!4c`9)Q;)z`wNc*{8i<_@-M)=XFPi6%u1WKMxjZ|s%u}N>P^S@`(?Fzmbt|Nm_ z`IA~Mks>Y!t_Uu;q6gAuksU;9oJdilqI~^D7i%0Dd~I%67*dKIdo_F)vO_mhe3f0% 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%0DhST1no*WlEJRPukH5MZL(0<46PDmcP{& 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

    F}ja9(9yacf~oH=aiLdF@2ItL4E5qAGH0 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≈;EXO(=xYpaB+3@GU)MF;$VW9$yG|?t% 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�a=i)qUh5kQt(5w&*#kmw6 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

  • j_oHGH6cb2hQPmeDrf6 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%0DaC!z#X=d7-;3 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∈OMehY2wKZQ2H>#^-J(Ozwe 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 z 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

    !<=fb9u-khEGn9Xpn3(ivh)zLMWeA;oIg7 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 z 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 z�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 literal 0 HcmV?d00001 From 4505c6c55a515b5eed9a22a7ae112de5de413ba6 Mon Sep 17 00:00:00 2001 From: Hypatia May Date: Thu, 16 Jul 2026 13:55:23 +0800 Subject: [PATCH 007/368] refactor(session-query): simplify persistence binding (round 1) --- .../session-query-sqlite/src/index.ts | 58 +++++++++---------- .../session-query-sqlite/tests/sqlite.spec.ts | 29 +++++++--- 2 files changed, 48 insertions(+), 39 deletions(-) diff --git a/packages/session-query/session-query-sqlite/src/index.ts b/packages/session-query/session-query-sqlite/src/index.ts index dd1ddb532a..4a510e5324 100644 --- a/packages/session-query/session-query-sqlite/src/index.ts +++ b/packages/session-query/session-query-sqlite/src/index.ts @@ -97,9 +97,12 @@ interface ObservedPersistedSession { loaded?: ObservedSession } +interface PersistenceBinding { + readonly service?: SessionPersistence +} + interface Observation { - persistence: SessionPersistence | undefined - persistenceRevision: number + persistenceBinding: PersistenceBinding persisted: Map live: Map } @@ -161,10 +164,8 @@ export class SessionSearchSqlite extends SessionSearchService { private readonly _instance = randomUUID() private readonly _ready: Promise private _db: DatabaseSync | undefined - private _persistence: SessionPersistence | undefined - private _persistenceBinding: object | undefined - private _persistenceRevision = 0 - private _lastPersistenceRevision: number | undefined + private _persistenceBinding: PersistenceBinding = {} + private _lastPersistenceBinding: PersistenceBinding | undefined private _persistenceEpoch = 0 private _globalGeneration = 0 private _localGeneration = 0 @@ -182,16 +183,12 @@ export class SessionSearchSqlite extends SessionSearchService { void this._ready.catch(() => undefined) this._optionalPersistenceFiber = ctx.inject(['sessionPersistence'], (childCtx: Context) => { const service = childCtx.sessionPersistence - const binding = {} + const binding = { service } this._persistenceBinding = binding - this._persistence = service - this._persistenceRevision += 1 childCtx.effect(() => () => { /* v8 ignore next -- a stale optional-service disposer cannot clear a replacement */ if (this._persistenceBinding !== binding) return - this._persistenceBinding = undefined - this._persistence = undefined - this._persistenceRevision += 1 + this._persistenceBinding = {} }, 'sessionSearchSqlite.persistenceBinding') }) ctx.effect(() => { @@ -330,16 +327,16 @@ export class SessionSearchSqlite extends SessionSearchService { const liveById = new Map(liveRows.map(row => [row.id as SessionId, row])) const observation = await this._observeStable(persistedById, signal) assertNotAborted(signal) - const persistentChanges = observation.persistence === undefined + const persistentChanges = observation.persistenceBinding.service === undefined ? [] : [...observation.persisted.values()].filter(entry => entry.loaded !== undefined) - const persistentDeletes = observation.persistence === undefined + const persistentDeletes = observation.persistenceBinding.service === undefined ? [] : persistedRows.filter(row => !observation.persisted.has(row.id as SessionId)) const liveChanges = [...observation.live.values()].filter(entry => liveById.get(entry.header.id)?.fingerprint !== entry.fingerprint) const liveDeletes = liveRows.filter(row => !observation.live.has(row.id as SessionId)) - const pointerChanged = this._lastPersistenceRevision !== undefined - && this._lastPersistenceRevision !== observation.persistenceRevision + const pointerChanged = this._lastPersistenceBinding !== undefined + && this._lastPersistenceBinding !== observation.persistenceBinding const hasWrites = persistentChanges.length > 0 || persistentDeletes.length > 0 || liveChanges.length > 0 @@ -393,7 +390,7 @@ export class SessionSearchSqlite extends SessionSearchService { if (hasWrites || pointerChanged) this._globalGeneration += 1 if (pointerChanged) this._persistenceEpoch += 1 this._localGeneration = nextLocalGeneration - this._lastPersistenceRevision = observation.persistenceRevision + this._lastPersistenceBinding = observation.persistenceBinding } private async _observeStable( @@ -402,13 +399,13 @@ export class SessionSearchSqlite extends SessionSearchService { ): Promise { for (;;) { assertNotAborted(signal) - const persistence = this._persistence - const persistenceRevision = this._persistenceRevision + const persistenceBinding = this._persistenceBinding + const persistence = persistenceBinding.service let persisted = new Map() if (persistence !== undefined) { try { - const canReuseIndexed = this._lastPersistenceRevision === undefined - || this._lastPersistenceRevision === persistenceRevision + const canReuseIndexed = this._lastPersistenceBinding === undefined + || this._lastPersistenceBinding === persistenceBinding const before = await waitWithAbort(persistence.listSnapshots(), signal) persisted = materializePersistenceSnapshots(before) for (const entry of persisted.values()) { @@ -421,14 +418,14 @@ export class SessionSearchSqlite extends SessionSearchService { await waitWithAbort(persistence.listSnapshots(), signal), ) if (!samePersistenceSnapshots(persisted, after)) continue - if (this._persistenceRevision !== persistenceRevision) continue + if (this._persistenceBinding !== persistenceBinding) continue } catch (error: unknown) { if (isAbort(error) || signal?.aborted) { throw new SessionQueryError('session-search aborted', 'SESSION_QUERY_ABORTED', { cause: error, }) } - if (this._persistenceRevision !== persistenceRevision) continue + if (this._persistenceBinding !== persistenceBinding) continue if (error instanceof SessionQueryError) throw error throw new SessionQueryError( `session-search persistence observation failed: ${errorMessage(error)}`, @@ -444,8 +441,8 @@ export class SessionSearchSqlite extends SessionSearchService { if (durable !== undefined) assertSessionHeadersCompatible(observed.header, durable.header) live.set(session.id, observed) } - if (this._persistenceRevision === persistenceRevision) { - return { persistence, persistenceRevision, persisted, live } + if (this._persistenceBinding === persistenceBinding) { + return { persistenceBinding, persisted, live } } } } @@ -564,7 +561,7 @@ export class SessionSearchSqlite extends SessionSearchService { ORDER BY match_count DESC, document_length ASC, time DESC, session_id ASC, seq DESC LIMIT ? OFFSET ? `).all( - ...selectedDocumentsParams(request.query, this._persistence !== undefined), + ...selectedDocumentsParams(request.query, this._persistenceBinding.service !== undefined), ...sessionWhere.params, ...eventWhere.params, request.limit + 1, @@ -583,7 +580,7 @@ export class SessionSearchSqlite extends SessionSearchService { ORDER BY match_count DESC, document_length ASC, time DESC, seq DESC LIMIT ? OFFSET ? `).all( - ...selectedDocumentsParams(request.query, this._persistence !== undefined), + ...selectedDocumentsParams(request.query, this._persistenceBinding.service !== undefined), request.sessionId, ...eventWhere.params, request.limit + 1, @@ -597,7 +594,7 @@ export class SessionSearchSqlite extends SessionSearchService { 'SELECT generation FROM temp.live_sessions WHERE id = ?', ).get(sessionId) as { generation: number } | undefined if (live !== undefined) return `live:${live.generation}` - if (this._persistence !== undefined) { + if (this._persistenceBinding.service !== undefined) { const persisted = db.prepare( 'SELECT generation FROM persisted_sessions WHERE id = ?', ).get(sessionId) as { generation: number } | undefined @@ -713,10 +710,7 @@ function selectedDocumentsParams(query: string, persistenceVisible: boolean): Ar } function observeLive(session: Session): ObservedSession { - return observeSession( - structuredClone(session.header), - session.events.map(event => structuredClone(event)), - ) + return observeSession(session.header, session.events) } function observeSession(header: SessionHeader, events: readonly SessionEvent[]): ObservedSession { diff --git a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts index 9897331549..3de325b35f 100644 --- a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts @@ -326,6 +326,24 @@ describe('SQLite session search', () => { })).rejects.toThrow(expectCode('SESSION_QUERY_STALE_CURSOR')) }) + it('invalidates session cursors after transient persistence topology changes', async () => { + TestPersistence.reset() + const ctx = await liveContext({ path: ':memory:', defaultLimit: 1, maxLimit: 5 }) + ctx.sessions.create(SessionId('first'), { seed: messageEvents('needle first') }) + ctx.sessions.create(SessionId('second'), { seed: messageEvents('needle second') }) + const page = await ctx.sessionSearch.searchSessions({ query: 'needle', limit: 1 }) + if (page.nextCursor === undefined) throw new Error('expected cursor') + + const persistence = await ctx.plugin(TestPersistence) + await persistence.dispose() + + await expect(ctx.sessionSearch.searchSessions({ + query: 'needle', + limit: 1, + cursor: page.nextCursor, + })).rejects.toThrow(expectCode('SESSION_QUERY_STALE_CURSOR')) + }) + it('rejects invalid requests, filters, cursors, and direct config', async () => { const ctx = await liveContext({ path: ':memory:', defaultLimit: 2, maxLimit: 3 }) const session = ctx.sessions.create(SessionId('valid'), { seed: messageEvents('needle') }) @@ -503,11 +521,6 @@ describe('SQLite reconciliation and source lifecycle', () => { TestPersistence.set({ meta: durable, events: messageEvents('new needle') }) TestPersistence.revisions.set(durable.id, revision) const replacement = await ctx.plugin(TestPersistence) - const internals = ctx.sessionSearch as unknown as { - _lastPersistenceRevision: number - _persistenceRevision: number - } - expect(internals._persistenceRevision).not.toBe(internals._lastPersistenceRevision) const page = await ctx.sessionSearch.searchSessions({ query: 'new needle' }) expect(TestPersistence.loads.get(durable.id)).toBe(2) expect(page).toMatchObject({ items: [{ header: durable }] }) @@ -553,13 +566,15 @@ describe('SQLite reconciliation and source lifecycle', () => { TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) const ctx = await liveContext() await ctx.plugin(TestPersistence) - const internals = ctx.sessionSearch as unknown as { _persistenceRevision: number } + const internals = ctx.sessionSearch as unknown as { + _persistenceBinding: { service?: SessionPersistence } + } const originalList = ctx.sessions.list.bind(ctx.sessions) let bumped = false const list = vi.spyOn(ctx.sessions, 'list').mockImplementation(() => { if (!bumped) { bumped = true - internals._persistenceRevision += 1 + internals._persistenceBinding = { ...internals._persistenceBinding } } return originalList() }) From ec47f2e40fdfbff3809ad1db874f9d5df9db33c4 Mon Sep 17 00:00:00 2001 From: Ziya <199893125+ZiyaZhang@users.noreply.github.com> Date: Wed, 15 Jul 2026 23:01:43 -0700 Subject: [PATCH 008/368] =?UTF-8?q?docs(i18n):=20core-docs=20batch=20?= =?UTF-8?q?=E2=80=94=20five=20bilingual=20pairs=20via=20the=20committed=20?= =?UTF-8?q?pipeline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit architecture / cordis-primer / defensive-patterns / glossary / testing 五篇核心文档配对,译文由进仓流水线产出(committed renderer + 金标 few-shot + 严格 XML 协议),并经二遍校验(逐句对照原文复述核查 + 注入 architecture/glossary 仓库上下文的一致性修复)。五篇生成文档 (agent-lifecycle、capability-seams、event-producer-consumer、 graph-atlas、tool-execution-pipeline 均为 gen-doc-graphs 产物)列入 排除清单——手写译文会在再生成时失效,与既有生成目录排除策略一致。 --- docs/architecture.i18n.yaml | 6 + docs/architecture.md | 2 + docs/architecture.zh.md | 171 ++++++++++++++++++++++ docs/cordis-primer.i18n.yaml | 6 + docs/cordis-primer.md | 2 + docs/cordis-primer.zh.md | 44 ++++++ docs/defensive-patterns.i18n.yaml | 6 + docs/defensive-patterns.md | 2 + docs/defensive-patterns.zh.md | 29 ++++ docs/glossary.i18n.yaml | 6 + docs/glossary.md | 2 + docs/glossary.zh.md | 19 +++ docs/testing.i18n.yaml | 6 + docs/testing.md | 2 + docs/testing.zh.md | 35 +++++ scripts/translation-pairing.manifest.json | 10 ++ 16 files changed, 348 insertions(+) create mode 100644 docs/architecture.i18n.yaml create mode 100644 docs/architecture.zh.md create mode 100644 docs/cordis-primer.i18n.yaml create mode 100644 docs/cordis-primer.zh.md create mode 100644 docs/defensive-patterns.i18n.yaml create mode 100644 docs/defensive-patterns.zh.md create mode 100644 docs/glossary.i18n.yaml create mode 100644 docs/glossary.zh.md create mode 100644 docs/testing.i18n.yaml create mode 100644 docs/testing.zh.md diff --git a/docs/architecture.i18n.yaml b/docs/architecture.i18n.yaml new file mode 100644 index 0000000000..9ff56c00ef --- /dev/null +++ b/docs/architecture.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +architecture.md: 32b9700b9aece988985ff932e597b537872f12c3 +architecture.zh.md: 1adb0111fb67c6e252153e2500732a320de44523 diff --git a/docs/architecture.md b/docs/architecture.md index 4049049e25..32b9700b9a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,5 +1,7 @@ # DeepSeek Harness Architecture +English | [中文](architecture.zh.md) + The **DeepSeek Harness SDK** builds agent harnesses on Cordis. The principle is simple: **everything is a plugin**. The shipped loop is one plugin, not a privileged kernel. ## Overview diff --git a/docs/architecture.zh.md b/docs/architecture.zh.md new file mode 100644 index 0000000000..1adb0111fb --- /dev/null +++ b/docs/architecture.zh.md @@ -0,0 +1,171 @@ +# DeepSeek Harness 架构 + +[English](architecture.md) | 中文 + +**DeepSeek Harness SDK** 基于 Cordis 构建 agent harness(智能体框架)。原则很简单:**一切皆插件**。内置的循环只是一个插件,不是特权内核。 + +## 概览 + +一个 harness 就是一个 [Cordis](cordis-primer.md) 上下文。各包(package)贡献服务键、类型化事件和可 dispose(资源释放)的注册:服务暴露稳定的调用(`ctx.llm`、`ctx.tools`、`ctx.sessions`),事件提供拦截与通知(`agent/request`、`tools/pre-execute`、`session/event`),注册则安装提示词段、工具、提供方、适配器或监听器。 + +`packages/core/` 组织了默认的 agent 流程;周边能力同样是一等的 Cordis 插件。 + +### 默认服务 + +| ctx 键 | 包 | 职责 | +|---|---|---| +| — | [`dsh-scope`](../packages/core/scope/README.md) | 作用域上下文注册原语(库) | +| `ctx.sessions` | `dsh-session` | 内存中事件溯源的会话 | +| `ctx.systemPrompt` | `dsh-system-prompt` | 有序提示词段、工具 schema 与提示词变量 | +| `ctx.tools` | `dsh-tools` | 工具注册表与[执行流水线](tool-execution-pipeline.md) | +| `ctx.agents` | `dsh-agent` | 活跃 agent 注册表、公开 `Agent` 句柄、`agent/*` 事件 | +| `ctx.agentLoop` | `dsh-agent-loop` | 内置 `ReactLoopAgent` 驱动器 | + +### 能力服务 + +| ctx 键 | 包族 | 职责 | +|---|---|---| +| `ctx.llm` | [`llm/`](../packages/llm/README.md) | 适配器注册表与流式模型调用 | +| `ctx.bash` | [`bash/`](../packages/bash/README.md) | 前台/后台命令执行 | +| `ctx.sandbox` | [`sandbox/`](../packages/sandbox/README.md) | 同世界进程隔离(argv 包装、逐调用策略) | +| `ctx.codeRuntime` | [`code-runtime/`](../packages/code-runtime/README.md) | 模型编写的程序执行 | +| `ctx.fs` | [`fs/`](../packages/fs/README.md) | 文件系统提供方原语与策略事件 | +| `ctx.skills` | [`skill/`](../packages/skill/README.md) | skill(技能)提供方注册表与渐进式披露 | +| `ctx.web` | [`web/`](../packages/web/README.md) | 搜索/抓取提供方注册表 | +| `ctx.compact` | [`compact/`](../packages/compact/README.md) | 会话日志压缩(compaction) | +| `ctx.subagents` | [`subagent/`](../packages/subagent/README.md) | 命名委托提供方 | +| `ctx.workflows` | [`workflow/`](../packages/workflow/README.md) | 脚本驱动的多 agent 编排 | +| `ctx.sessionPersistence` | [`session-persistence/`](../packages/session-persistence/README.md) | 会话日志的持久化存储 | +| `ctx.sessionQuery` | [`session-query/`](../packages/session-query/README.md) | 活跃优先的逻辑语料库与精确事件读取 | + +## 事件 + +事件构成服务扩展 API;详见完整的[事件目录](cordis-catalog/events.md)与[生产者/消费方映射](event-producer-consumer.md)。 + +### 事件域 + +- **会话事件**是持久的、可回放的事实。轮次与步骤边界、用户输入、助手输出、工具调用、工具结果、steering(中途引导)、压缩记录以及工具拥有的持久事实追加到会话日志,并流经 `session/event`。 +- **Agent 事件**携带活跃的 `Agent` 句柄,用于状态、诊断、prompt 准入、调用配置塑形、结果校验与续行策略。 +- **能力事件**归属于拥有该动作的 seam。`tools/*`、`llm/*`、`system-prompt/*`、`fs/*` 与 `subagent/*` 让策略和适配器无需导入循环即可接入。 + +### 拦截语义 + +waterfall(瀑布式事件)的行为类似 around 中间件:监听器通过调用 `next()` 委托下游;不调用 `next()` 直接返回即为否决或接管。完整规则见 [Cordis waterfall 语义](cordis-primer.md#cordis-waterfall-semantics)。 + +## 默认循环生命周期 + +内置循环消耗工作队列、组装请求、流式接收模型回答、执行工具、应用续行策略并持久化检查点。每一个暂停点都是一个服务调用或事件,可供插件介入。 + +**会话**是一个 agent 的仅追加事件日志。**轮次(turn)**消耗一批排队消息,运行到模型不再请求工具且没有插件要求续行为止。**步骤(step)**是一次模型请求加上该响应引发的工具执行。下面的流程中([时序图伴侣文档](agent-lifecycle.md)),带引号的名称是持久化的会话事件,事件名称是扩展点。 + +### 轮次流程 + +```text +prepare private session + agent.ctx -> await unpublished setup + -> enter session + agent -> session/created -> agent/created + -> enable driving -> agent/session-start(source) -> start driver +forever: + wait for queued messages + emit agent/status(running) + TURN: + 'turn/start' + each queued message -> agent/prompt-submit + allowed prompt -> 'user/message' plus injected context + every prompt blocked -> 'turn/end'(rejected) + STEP loop: + drain steering + assemble system prompt and tool schemas + agent/session-prefix (first step) + agent/pre-step + 'step/start' + snapshot the derived messages (the reconstruction boundary) + agent/request (config only) -> log request/header -> llm/stream (frozen) + 'assistant/chunk' + agent/step-result + 'assistant/message' + each tool call: + 'tool/call' + tools/pre-execute -> monotonic guards -> tools/execute -> tools/post-execute -> tools/result + 'tool/result' + append post-tool context and steering + 'step/end' + agent/turn-continuation + agent/turn-stop (terminal policy) + stop unless tools or continuation policy ask for another step + 'turn/end' + checkpoint persistence and notify idle/running status +``` + +循环每步骤渲染一次 prompt 组装。插件贡献有序段、工具 schema 与 `{{name}}` 变量;未知或无值的引用会使轮次失败,而非带着空洞发送。`dsh-system-prompt` 拥有 harness 身份与默认部署人格;agent 作用域的人格可以遮蔽默认值。循环提供 `model` 和 `cwd`。见 [prompt 所有权 RFC](rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)。 + +Post-tool 上下文在所有工具结果之后落入,以保持 tool-call/result 的邻接稳定。steering 在步骤之间排空;轮次结束后的普通剩余 steering 作为输入重新入队。终止性的 `agent/turn-stop` 是显式例外:它在普通续行与 steering 折叠之后运行,然后在轮次关闭和刷新期间保持权威,因此这些后续监听器产生的 steering 被丢弃而非成为新的步骤或轮次;普通排队的 prompt 则被保留。 + +### 失败边界 + +轮次是容错边界。抛出异常的监听器、适配器错误结束或失败的步骤会以错误原因结束当前轮次,并通过 `agent/error` 报告实时诊断;它不会杀死驱动循环。`cancel()` 清除排队与 steering 工作,在可能时中止活跃的模型/工具边界,并记录相应的轮次结束。dispose 停止循环、等待静默、注销 agent,并让服务 disposer 排空。 + +每个会话事件都被轮次包围。重新加载崩溃的会话时,系统保留中断的尾部并以合成的 `interrupted` 轮次结束关闭它。持久化轮次已关闭后的失败仅通过 `agent/error` 报告,因为已没有安全的轮次内位置。轮次以一个 `TurnEndReason` 结束(`completed`、`aborted`、`error`、`disposed`、`max-tokens`、`rejected` 或 `interrupted`);各变体的语义见 [session.md § TurnEndReasonMap](core-data-structures/session.md#why-a-turn-ended-turnendreasonmap)。 + +### Agent 句柄 + +`ctx.agents` 拥有活跃 agent 并返回 `AgentHandle { agent, dispose() }`。`Agent` 是其他插件驱动的 API:`send()` 入队工作,`steer()` 注入轮次中内容,`inject()` 追加上下文并在空闲时开启一次性注入轮次,`cancel()` 是公开的停止原语,`whenIdle()` 观察静默状态。调用方 fiber 与具体工厂提供方在结构上共同拥有编程式生命周期;消费方句柄是唯一的非结构性拆卸能力,且每个所有者到达同一个被 await 的 disposer。 + +### Agent 作用域 + +每个活跃 agent 拥有一个作用域化的 `agent.ctx`。其注册遮蔽同名全局注册,只接收该 agent 的派发,并随 agent 一起解除。`CreateAgentOptions.setup(agentCtx)` 在发布前组合作用域。[语义门禁 RFC](rfc/implemented/process/2026-07-14-typescript-program-backed-semantic-gates.md) 定义了类型化解析器,从合并的 `Events` 签名与 `scopeTarget` 派生载体检查,消除了手写事件表。见 [agent 作用域 RFC](rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md);subagent 组合控制另行记录于[此](rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md)。 + +## 状态 + +### 会话日志 + +会话日志是真源。`deriveMessages()` 将会话事件投影为发送给模型的 `Message[]`;原始 `assistant/chunk` 事件留在日志中用于回放和 UI 保真。回放、fork、恢复、transcript(文本记录)渲染、遥测和持久化都从同一事件流派生。 + +**模型可见 ⟺ 已记录**:日志能重建每次请求——`step/start` 处的消息前置 header 的会话前缀,header 通过折叠 `request/header` 得出——开发不变式对此做断言([可重建性 RFC](rfc/implemented/architecture/2026-07-05-reconstructable-requests.md))。 + +持久性是插件关注点。持久化后端缓冲同步的 `session/event` 通知,循环在轮次结束检查点完成后才继续。`SessionPersistence` seam 直接存储 `SessionEvent`,元数据在 `SessionHeader` 中;JSONL 与 SQLite 共享同一套契约测试。 + +### 模型内容 + +消息是类型化内容块(`text`、`reasoning`、`tool-call`、`tool-result`)的数组。联合类型派生自可合并扩展的 `ContentBlockMap`;同一模式也用于 `MessageSource`、`FinishReason`、`TurnTrigger` 与 `TurnEndReason`。新的块类型需要跨适配器、UI 桥接、压缩计价与持久化协调,因此块类型仍是仓库级契约。 + +流式输出是原始分片协议(从 `block-start` 到 `finish`),`BlockAssembler` 是共享的 chunk 到 block 组装器。循环在组装分片以供派发的同时记录原始 chunk。`LlmAdapter` 是提供方 seam:继承它、实现 `stream()`、用 `ctx.llm.registerAdapter(models, adapter)` 注册。StreamChunk 约定见 [llm-streaming.md](core-data-structures/llm-streaming.md)。 + +## 扩展与组合 + +### 能力模式 + +一个可替换的能力通常拆分为**接口 / 实现 / 消费方**:接口拥有其 `ctx` 键与事件,实现注册后端,消费方通过工具或 prompt 暴露模型行为。Bash 是参考实现;[能力图](capability-seams.md)展示了每个族。 + +部分 seam 有意偏离模板。LLM(大语言模型)将接口与消费方词汇放在一起,因为适配器就是实现。文件系统在提供方原语周围添加策略门禁。Web 是一个服务加搜索/抓取两个提供方注册表,因此提供方替换不会重命名模型工具。skill 与 subagent 使用命名提供方注册表;本地 skill 扫描项目/用户根目录,其他提供方可以在不改动注册表/工具的情况下添加嵌入式或远程目录。subagent 可以全新 spawn、从父级已完成轮次的前缀 fork,或使用 ACP 子进程([subagent.md](core-data-structures/subagent.md))。 + +### Bundle 与应用 + +`dsh-agent-spine-demo` 是默认的组合 bundle:一个插件加载共享主干([README](../packages/examples/agent-spine-demo/README.md))。应用包将其与前端入口和启动 `bin` 组合:`dsh-stdio-demo` 用于终端 REPL,`dsh-acp-demo` 用于基于 JSON-RPC stdio 的 ACP(无 stdout logger)([ui/](../packages/ui/README.md))。`dsh-jsonrpc-agent` 则启动外部 `cordis.yml`;Python SDK 在未设置显式配置通道时注入包默认值,并通过行分隔的 stdio JSON-RPC 驱动 `dsh-jsonrpc`([Python SDK](../python/README.md))。一个部署就是一片薄薄的 `cordis.yml` 叶子:可替换的后端、一个应用入口和可选的产品工具([examples/](../examples/AGENTS.md)、[可运行接线](cookbook/extension-cookbook.md#runnable-wirings)、[关系图索引](graph-atlas.md))。 + +### 新行为的归属 + +新行为应接入已记录的扩展点;修改内置循环需要同步更新本映射。 + +| 目标 | 机制 | +|---|---| +| 添加模型提供方 | 在 `ctx.llm` 上注册适配器 | +| 添加面向模型的能力 | 在 `ctx.tools` 上注册工具;schema 流入 prompt 组装 | +| 添加命令执行 | 实现并注册 `ctx.bash` 后端 | +| 添加文件系统访问或策略 | 实现 `ctx.fs` 提供方或监听 `fs/*` 策略事件 | +| 隔离 spawn 的进程 | 一个 `ctx.sandbox` 后端;消费方在 spawn 前包装 argv | +| 拦截 prompt、请求、工具使用或续行 | 监听相关的 `agent/*` 或 `tools/*` waterfall;使用串行 `agent/turn-stop` 实现单调终止 | +| 添加历史之外的会话稳定请求前缀 | 在 `agent/session-prefix` 上组合,每个循环实例一次;记录在请求 header 上 | +| 添加 UI 或编辑器集成 | 驱动 `ctx.agents` 并从 `session/event` 渲染 | +| 添加持久化会话状态 | 添加 `SessionEventMap` 成员并从日志渲染/回放 | +| fork 活跃会话 | 使用 `ctx.sessions.fork(source, boundary?, childSessionId?)` | +| 将工具、prompt 段或监听器限定到单个 agent | 通过该 agent 的 `agent.ctx` 注册(见 Agent 作用域) | + +[扩展实操手册(cookbook)](cookbook/extension-cookbook.md)提供插件骨架与功能到 seam 的映射;分步指南覆盖[包](cookbook/adding-a-package.md)、[工具](cookbook/adding-a-tool.md)、[LLM 适配器](cookbook/adding-an-llm-adapter.md)与[vendor 包](cookbook/adding-a-vendored-package.md)。 + +## 快速参考 +- 领域术语见[术语表](glossary.md) +- 类型定义见 [core-data-structures/](core-data-structures/core.md) +- 精确的事件与服务签名见[事件目录](cordis-catalog/events.md) +- [服务目录](cordis-catalog/services.md) +- 包契约见[包映射](../packages/README.md) +- [RFC](rfc/README.md) diff --git a/docs/cordis-primer.i18n.yaml b/docs/cordis-primer.i18n.yaml new file mode 100644 index 0000000000..405a377ed1 --- /dev/null +++ b/docs/cordis-primer.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +cordis-primer.md: 39d3d97b9ac43fec50cb0c832af449fc8bc6232f +cordis-primer.zh.md: 4915f665cae51b44f89190d43d147e5cda0df146 diff --git a/docs/cordis-primer.md b/docs/cordis-primer.md index d8e92dcb67..39d3d97b9a 100644 --- a/docs/cordis-primer.md +++ b/docs/cordis-primer.md @@ -1,5 +1,7 @@ # Cordis Primer +English | [中文](cordis-primer.zh.md) + Cordis is the vendored plugin framework underneath the DeepSeek Harness SDK. This primer teaches the Cordis ideas a harness plugin author needs before reading the generated [events](cordis-catalog/events.md) and [services](cordis-catalog/services.md) catalogs. The vendored source and sync procedure live in [vendor/README.md](../vendor/README.md). ## Cordis In Five Ideas diff --git a/docs/cordis-primer.zh.md b/docs/cordis-primer.zh.md new file mode 100644 index 0000000000..4915f665ca --- /dev/null +++ b/docs/cordis-primer.zh.md @@ -0,0 +1,44 @@ +# Cordis 入门 + +[English](cordis-primer.md) | 中文 + +Cordis 是 DeepSeek Harness SDK 底层以 vendor 方式引入的插件框架。本入门文档讲解 harness 插件作者在阅读生成的[事件](cordis-catalog/events.md)与[服务](cordis-catalog/services.md)目录之前需要了解的 Cordis 核心概念。vendor 源码与同步流程见 [vendor/README.md](../vendor/README.md)。 + +## Cordis 五大理念 + +- **插件是实现了 Service 的对象。** 它可以是一个带有可选 `inject` 和 `apply(ctx)` 字段的函数,也可以是一个 `Service` 子类,其生命周期由 Cordis 挂载到当前上下文中。 +- **上下文是服务的注册表。** 一个服务在上下文中声明一个稳定的 `ctx.`(如 `ctx.tools`、`ctx.llm`、`ctx.sessions`);其他插件通过 key 查找服务,而非导入具体实现。 +- **通过 `inject` 声明服务依赖。** 插件声明所需的服务后,会等待这些服务就绪;加载顺序通过服务依赖表达,而非手动编排启动序列。 +- **类型化事件用于通信。** 服务通过 TypeScript 声明合并定义事件名,然后以 `emit`、`waterfall`(瀑布式事件)、`parallel` 或 `serial` 方式分发,分别对应监听者观察、包装、并行扇出或按序执行。 +- **注册是可逆的副作用。** 提示词片段、工具 schema、适配器、提供方和监听器通过 `ctx.effect()` 或 `ctx.on()` 安装,因此重载和拆卸能可预测地回退它们。 + +## 分发模式 + +每个事件具有以下分发模式之一,且只能通过对应的方法分发。 + +| 模式 | 是否 await? | 分发顺序 | 是否有返回值? | +|---|---|---|---| +| `emit` | 否 | 监听器按注册顺序观察 | 否 | +| `waterfall` | 否 | 监听器按注册顺序观察 | 是 | +| `parallel` | 是 | 所有监听器并行观察事件 | 否 | +| `serial` | 是 | 监听器按注册顺序观察 | 是 | + +分发模式是事件公开契约的一部分。新的 harness 事件通过 `@mode` 标签记录它,以便生成的目录能将声明与分发站点进行交叉校验。 + +## Cordis Waterfall 语义 + +`ctx.waterfall` 是环绕中间件。监听器接收 `(...args, next)`。调用 `next()` 将可能经过包装的结果委托给下一个服务;不调用 `next()` 直接返回则短路。值通过 `next()` 的返回值向下传播。 + +协作式监听器通常修改一个共享的请求或决策对象,然后委托。监听器也可以选择完全替换结果,下游监听器只会看到替换后的结果。仅当监听器必须在普通注册之前运行时才使用 `prepend: true`。 + +对于单决策事件,短路是设计意图。策略监听器在拥有决策权时可以不调用 `next()` 直接返回,而仅做标注或观察的监听器必须委托。 + +## Loader 配置 + +`@cordisjs/plugin-include` 将 `!!js` 解析为表达式节点,但 Loader 仅在挂载插件前对条目的 `config` 进行插值。条目元数据(`id`、`name`、`group`、`disabled`、`inject`、`intercept` 和 `isolate`)保持字面值;因此 `disabled: !!js ...` 是一个真值对象,总是会禁用该条目。当需要根据环境选择挂载哪些插件时,请使用显式的配置覆盖。 + +## 实践规则 + +将行为封装到插件中:工具流水线事件属于 `ctx.tools`,模型流式输出属于 `ctx.llm`,实时 agent 协调属于 `ctx.agents`。拦截和策略优先使用事件;直接能力调用优先使用服务方法。 + +每个注册都应有对应的 dispose(资源释放)器:要么从 `ctx.effect()` 返回一个,要么使用 Cordis 提供的辅助函数自动处理。如果拆卸顺序有要求,请将相关工作放在同一个 effect 中,以确保 dispose 按预期顺序回退。 diff --git a/docs/defensive-patterns.i18n.yaml b/docs/defensive-patterns.i18n.yaml new file mode 100644 index 0000000000..03765e44ae --- /dev/null +++ b/docs/defensive-patterns.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +defensive-patterns.md: fda0be0d2d3b7fa099162123b3d219673eebd07d +defensive-patterns.zh.md: 60d7389db50c30e2b85fd88b320f04b43e22d84d diff --git a/docs/defensive-patterns.md b/docs/defensive-patterns.md index cf30072094..fda0be0d2d 100644 --- a/docs/defensive-patterns.md +++ b/docs/defensive-patterns.md @@ -1,5 +1,7 @@ # Defensive patterns +English | [中文](defensive-patterns.zh.md) + Hard-won bug-class rules: each pattern below is a class of defect that actually shipped or nearly shipped here, stated as the rule that prevents its recurrence. Read this before writing lifecycle, concurrency, subprocess, or teardown code. Test-tier counterparts (real entry path, world-verification, resource ownership) are in [testing.md](testing.md). ## Report orthogonal outcomes independently diff --git a/docs/defensive-patterns.zh.md b/docs/defensive-patterns.zh.md new file mode 100644 index 0000000000..60d7389db5 --- /dev/null +++ b/docs/defensive-patterns.zh.md @@ -0,0 +1,29 @@ +# 防御性模式 + +[English](defensive-patterns.md) | 中文 + +来之不易的缺陷类别规则:以下每条模式都是本项目中实际发布或险些发布的一类缺陷,以防止其复发的规则形式陈述。在编写生命周期、并发、子进程或清理代码之前,请先阅读本文。测试层面的对应规则(真实入口路径、world 验证、资源归属)见 [testing.md](testing.md)。 + +## 正交结果独立上报 + +一个结果可以同时具有多重性质:进程可能既超时又以 exit 0 退出,因为它捕获了信号。每个独立事实(`timedOut`、`signal`、`exitCode`)都应独立暴露;永远不要把一个 flag 的上报嵌套在另一个 flag 的分支内,否则调用方会把一次被截断的运行误读为正常成功。 + +## 在接口两侧都遵守跨 seam 契约 + +当接口文档记录了两种有效的信号方式时——例如适配器可以通过从 `stream()` 抛出异常来报告失败,也可以通过以 `finish {kind:'error'|'aborted'}` 分片结束流来报告——消费方必须两种都处理,而不只是第一个实现碰巧使用的那种。基于库的适配器在流中途无法抛出异常,只能依赖带内路径;如果 agent loop 只捕获 throw,就会把提供方的 401 变成一个正常完成的轮次。请在类型定义处记录契约;通过真实消费方测试每个分支。 + +## 异步状态不是同步状态 + +`agent.send()` 不会在返回前翻转状态;后台任务的完成与轮次边界存在竞态;`reader.close()` 在 EOF 和 dispose(资源释放)两种情况下都会触发。永远不要基于一个你刚刚请求的状态来控制流程——应当基于实际触发的事件/promise 来驱动生命周期(`agent/status`、`task.done`),并观察状态转换(先看到 `running` 再看到 `idle`),而不是假设你发出的动作与轮次 1:1 对应(循环会批量处理排队的消息)。这条守则是双向的:如果等待的转换永远不会发生(EOF 且没有提交过工作 → 永远不会进入 `running`),等待就会挂起——请显式处理「无需等待」的分支。 + +## dispose 必须达到静止,而非仅仅请求停止 + +一个只发出 kill/abort 就返回的清理逻辑会留下孤儿进程。请让清理逻辑异步化并 await 子进程退出(kill → await `done`),并在 kill 之前关闭监听器/通知注册表,使迟到的完成事件保持静默。测试应证明 dispose 确实等到了进程退出(`await fiber.dispose()` 之后 pid 已不存在),而非仅仅证明进程最终会死。 + +## 在边界处包容回调异常 + +用户提供的监听器抛出异常时,不得导致它所在的 promise 被 reject,也不得饿死排在它之后的监听器。请在分发循环中用 try/catch 包裹并记录日志;一个有问题的订阅者永远不能破坏核心生命周期。 + +## 永远不要把环境变量或可预测路径暴露给不可信输出 + +spawn 的命令应获得一个经过清洗的 env(移除 `*KEY*`/`*SECRET*`/`*TOKEN*`),确保 harness 凭证不会泄漏到输出、`env` 或溢出文件中。临时/溢出文件应使用私有(0700)目录、随机文件名和排他的仅所有者可打开模式(`'wx'`、`0o600`)——可预测的全局可读路径会招致符号链接竞态和信息泄露。 diff --git a/docs/glossary.i18n.yaml b/docs/glossary.i18n.yaml new file mode 100644 index 0000000000..a0765ef752 --- /dev/null +++ b/docs/glossary.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +glossary.md: 23eebc5793e8232482a796f5bde1e794f0556208 +glossary.zh.md: 7163015eeed71c96743b9cae491db206585a70b2 diff --git a/docs/glossary.md b/docs/glossary.md index 81b9b4f84a..23eebc5793 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -1,5 +1,7 @@ # Glossary +English | [中文](glossary.zh.md) + Domain vocabulary for the DeepSeek Harness SDK uses one canonical term per concept. Terms link to their entries with standard Markdown anchors; implementation detail stays in package READMEs and RFCs. FIXME(glossary-completeness): Expand this glossary before the first release so it covers the SDK's other core and capability subsystems, not only agent scope. diff --git a/docs/glossary.zh.md b/docs/glossary.zh.md new file mode 100644 index 0000000000..7163015eee --- /dev/null +++ b/docs/glossary.zh.md @@ -0,0 +1,19 @@ +# 术语表 + +[English](glossary.md) | 中文 + +DeepSeek Harness SDK 的领域词汇对每个概念使用唯一的规范术语。各术语通过标准 Markdown 锚点互相链接;实现细节留在各 package README 和 RFC 中。 + +FIXME(glossary-completeness): Expand this glossary before the first release so it covers the SDK's other core and capability subsystems, not only agent scope. + +## agent 作用域 + +- **scope(作用域)**:按 agent(智能体)注册的单位。一项贡献(工具、prompt 段落、变量、限制、监听器)要么是*全局*的(对所有 agent 可见),要么是*有作用域*的(归属于恰好一个 [scope key](#scope-key))。只有两层,扁平结构:有作用域的注册不会向下继承给 subagent;子树行为通过[血统](#lineage)数据表达,从不通过作用域结构。 +- **scope key(作用域键)**:作用域的不透明标识,按对象同一性比较。harness 约定:一个活跃的 agent 就是其自身作用域的 key。 +- **agent context(`agent.ctx`)**:agent 的有作用域上下文;通过它进行的注册既是作用域可见的,也是作用域生命周期的(一个事实同时驱动两者),其上的监听器参与该 agent 的作用域过滤分发。注册表主体事件可以在其自身的事件契约下有意保持不过滤。 +- **scope carrier(作用域载体)**:作用域过滤分发所携带的 `thisArg`(由 `scopeTarget` 构建);其过滤器放行无标签监听器加上主体自身的监听器。*无主体*的载体(没有 key)只放行无标签监听器。 +- **scoped dispatch(作用域分发)**:规则是:关于某个 agent 活动的事件以该 agent 的载体进行分发。关于注册表本身的事件(如「一个工具被添加」)属于*注册表主体*事件,保持不过滤。 +- **shadowing(遮蔽)**:最具体者胜出的名称解析:一个有作用域的工具/段落/变量仅在该作用域内替代其同名的全局副本。这是按 agent 定制人设和按 agent 定制工具变体的机制。 +- **restriction / scope-local registration(限制 / 作用域局部注册)**:限制(`tools.restrict`)为单个作用域过滤全局工具面(按交集组合);作用域局部注册在过滤之后合并。被过滤掉的全局工具既不出现在 prompt 中,也拒绝执行,与不存在的工具无法区分。 +- **setup window(设置窗口)**:创建者组装 agent 有作用域世界的创建时隙(`CreateAgentOptions.setup`):在作用域和 agent 对象已存在、但 agent 或会话尚未发布、`agent/session-start` 尚未触发、首次 prompt 尚未组装之前。设置窗口只做注册,从不驱动 agent。 +- **lineage(血统)**:以数据形式携带的父子关系(`parentSession`、`subagentDepth`);从不影响可见性。 diff --git a/docs/testing.i18n.yaml b/docs/testing.i18n.yaml new file mode 100644 index 0000000000..3adcf28723 --- /dev/null +++ b/docs/testing.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +testing.md: ddb9da0b38e5dc9cc75ede81ec157c4744fd11c2 +testing.zh.md: 6d21a37b175c8052fbc34db0fc5a9b522c27f7ec diff --git a/docs/testing.md b/docs/testing.md index d4acdc33c4..ddb9da0b38 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -1,5 +1,7 @@ # Testing policy +English | [中文](testing.zh.md) + How this repo tests, tier by tier, and the rules that keep a green suite meaningful. Commands live in root [AGENTS.md](../AGENTS.md); linked RFCs carry the rationale. ## Tiers diff --git a/docs/testing.zh.md b/docs/testing.zh.md new file mode 100644 index 0000000000..6d21a37b17 --- /dev/null +++ b/docs/testing.zh.md @@ -0,0 +1,35 @@ +# 测试策略 + +[English](testing.md) | 中文 + +本文说明本仓库如何逐层测试,以及保持绿色测试套件有意义的规则。命令见根目录 [AGENTS.md](../AGENTS.md);关联 RFC 承载设计动机。 + +## 层级 + +- **单元测试**(`pnpm run test`):vitest 运行 `packages|examples/*/tests/**/*.spec.ts`,与被测代码同目录。每个注册表都有一个 HMR(热模块替换)安全测试(dispose 贡献该注册的 fiber,断言清理完成)。优先覆盖边界情况、错误路径、事件顺序、并发竞态与永久契约回归(见 `packages/core/agent-loop/tests/contract-regressions.spec.ts`)。 +- **覆盖率门禁**(`pnpm run test:coverage`):门禁级运行,对 `packages/*/*/src` 按文件 100% 覆盖。未覆盖的行往往是门禁正确标记出的死代码(应删除),而非需要补写的测试。行覆盖率是必要条件,绝非充分条件:它证明代码行被执行过,不证明功能按交付预期工作。 +- **真实 API e2e**(`pnpm run test:e2e`):带密钥测试,对接真实提供方 API——DeepSeek 模型加各提供方独立冒烟测试(各自依赖自己的密钥:`EXA_API_KEY`、`PERPLEXITY_API_KEY` 等);每个套件在缺少对应密钥时自动跳过,确保无密钥 CI 保持绿色([真实 API e2e RFC](rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md))。 +- **快照测试**(`pnpm run test:snapshot`):启动真实示例子进程,无密钥回放录制的会话,将归一化后的 stdout 与重新持久化的日志同已提交的 golden 文件做 diff([快照 RFC](rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md))。当模型 transcript(文本记录)需要变更时使用 `pnpm run test:snapshot:record`;当已提交的 transcript 仍是正确的 mock LLM(大语言模型)输入、只需无密钥重写回放 golden 时使用 `pnpm run test:snapshot:refresh`。请评审 golden diff。系统提示词/工具 schema 内容由一个场景(`text-turn`)固定,其余 fixture(测试前置数据)中以 token 化形式引用,因此 prompt 或 schema 的修改只变动一行已提交内容([pinned-header RFC](rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md))。 + +## 带密钥策略:推理在这里很便宜 + +我们是 DeepSeek:不要吝惜真实 API 测试。无密钥测试证明管道通了;只有带密钥运行才能证明 agent 对接真实模型时能正常工作。多写:文件写入 prompt、多轮对话、工具调用、流中取消。价值最高的是**冒烟测试**:启动真实示例、发送一条真实 prompt、检查外部世界的状态。它们能捕获「单元测试全绿、产品却坏了」这类 mock 在结构上无法发现的问题([事后分析 0001](postmortem/0001-acp-default-export-drops-inject.md))。自动跳过机制的存在仅仅是为了不阻塞无密钥 CI 和无密钥贡献者,它不是成本信号。每个示例都附带一个无密钥冒烟测试,以及(除非本身就不需要密钥)一个带密钥冒烟测试([examples/AGENTS.md](../examples/AGENTS.md))。 + +## 优先使用真实实现而非 mock + +只 mock 真正昂贵或不确定的边界(LLM 适配器、网络、时钟);下游一切保持真实。手写的替身只能证明桥接层在搬运字节,不能证明交付的工具行为符合断言——两者会漂移,而测试仍然绿着。示例:bridge 工具调用测试运行脚本化的 mock 模型,但使用真实的 tool + 真实的执行器(`makeBridgeHarness({ withBash: true })` 接入 `dsh-bash-local` + `dsh-tool-bash`,执行真正的 `echo`)。 + +## 验证外部世界,而非自我报告 + +e2e 断言应重新运行命令或从外部重新读取文件;仅对 agent 自身输出做关键词探测会让作弊的 agent 通过。断言未改动的文件字节相同。e2e 测试拥有自己的资源:在测试中创建 harness,在 `afterEach` 中 dispose(即使失败/重试/超时);共享 fixture 放在普通的 `tests/harness.ts` 中,绝不放在另一个 `*.e2e.ts` 里(import 一个 spec 会重新注册其 `describe`,导致真实 API 调用重复)。 + +## 测试真实入口路径 + +- 产品可见的插件需要一个非单元的真实组合测试。手工搭建的 `ctx.plugin(...)` 套件不够:通过 Loader 和 app/process 启动仅用于测试的 `cordis.yml`,只 mock 外部/不确定边界,断言模型可见的请求/日志、持久状态或用户可见输出。不要把 opt-in 混入默认交付。 +- 一个守卫只有在回归真正让它失败时才算守卫。对于没有 `inject` 的插件(bundle/组合插件),Loader 冒烟测试在导出形状损坏时仍然绿——需要加一个显式的 `expect('default' in mod).toBe(false)` 加 `unwrapExports` 往返断言,并证明它有效:引入回归、观察变红、还原。 +- 「真实入口路径」指已发布的产物:package 的 `bin` 指向构建出的 `lib/bin.js`,在原生 `node` 下运行;tsx 会掩盖竞态、模块解析问题以及静默以 0 退出的加载失败。同理适用于构建后 package 在运行时解析的任何非 index 运行时入口(worker-thread 运行时的兄弟文件 `lib/worker.cjs`)。保持构建产物冒烟测试绿色(`packages/ui/*/tests/built-bin.e2e.ts`、`packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts`),并断言真正缺失的配置以非零退出。 +- 从临时 cwd spawn 示例的 e2e 测试需要设置 `TSX_TSCONFIG_PATH` 指向仓库根 tsconfig,否则会静默回退到陈旧的构建 `lib/`([examples/AGENTS.md](../examples/AGENTS.md))。 + +## 何时需要快照测试 + +任何影响编辑器侧 transcript 或端到端 agent 用户体验的变更——ACP bridge、agent loop(智能体循环)的可观测输出、工具呈现——都应在所属示例的快照套件中添加或更新场景(`examples//tests/snapshots/`,基于 [`dsh-acp-snapshot`](../packages/support/acp-snapshot/README.md) 套件工厂的场景表;`examples/acp-agent` 是主套件),或在 PR 中说明为何不适用。新的能力 seam、生命周期形态或 transcript 表面在计划阶段就要标明各层的覆盖方式,并验证 harness 能表达它——harness 的缺口是排期工作,不是构建中途的意外。 diff --git a/scripts/translation-pairing.manifest.json b/scripts/translation-pairing.manifest.json index 35a957e57d..ee0a35b599 100644 --- a/scripts/translation-pairing.manifest.json +++ b/scripts/translation-pairing.manifest.json @@ -2,31 +2,41 @@ "requiredSince": "2026-07-14", "required": [ "README.md", + "docs/architecture.md", "docs/cookbook/adding-a-package.md", "docs/cookbook/adding-a-tool.md", "docs/cookbook/adding-a-vendored-package.md", "docs/cookbook/adding-an-llm-adapter.md", "docs/cookbook/extension-cookbook.md", "docs/cookbook/responding-to-pr-review-on-a-stack.md", + "docs/cordis-primer.md", + "docs/defensive-patterns.md", "docs/development.md", + "docs/glossary.md", "docs/i18n/README.md", "docs/i18n/translation-rules.md", "docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md", "docs/rfc/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md", + "docs/testing.md", "python/README.md", "python/sdk-runtime/README.md", "python/sdk/README.md" ], "excluded": [ "docs/AGENTS.md", + "docs/agent-lifecycle.md", + "docs/capability-seams.md", "docs/config-catalog.md", "docs/cordis-catalog/", + "docs/event-producer-consumer.md", + "docs/graph-atlas.md", "docs/i18n/style-samples.md", "docs/i18n/terminology.md", "docs/i18n/translation-prompt.md", "docs/module-graph.md", "docs/persistence-catalog.md", "docs/tool-catalog.md", + "docs/tool-execution-pipeline.md", "python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/" ] } From de863aab9ab674a1528f575695fd62d1b151966a Mon Sep 17 00:00:00 2001 From: Hypatia May Date: Thu, 16 Jul 2026 14:04:49 +0800 Subject: [PATCH 009/368] fix(session-query): release stale persistence binding (round 2) --- .../session-query-sqlite/src/index.ts | 19 ++++++++++--------- .../session-query-sqlite/tests/sqlite.spec.ts | 7 +++++-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/session-query/session-query-sqlite/src/index.ts b/packages/session-query/session-query-sqlite/src/index.ts index 4a510e5324..1590a1d61c 100644 --- a/packages/session-query/session-query-sqlite/src/index.ts +++ b/packages/session-query/session-query-sqlite/src/index.ts @@ -98,6 +98,7 @@ interface ObservedPersistedSession { } interface PersistenceBinding { + readonly identity: symbol readonly service?: SessionPersistence } @@ -164,8 +165,8 @@ export class SessionSearchSqlite extends SessionSearchService { private readonly _instance = randomUUID() private readonly _ready: Promise private _db: DatabaseSync | undefined - private _persistenceBinding: PersistenceBinding = {} - private _lastPersistenceBinding: PersistenceBinding | undefined + private _persistenceBinding: PersistenceBinding = { identity: Symbol() } + private _lastPersistenceIdentity: symbol | undefined private _persistenceEpoch = 0 private _globalGeneration = 0 private _localGeneration = 0 @@ -183,12 +184,12 @@ export class SessionSearchSqlite extends SessionSearchService { void this._ready.catch(() => undefined) this._optionalPersistenceFiber = ctx.inject(['sessionPersistence'], (childCtx: Context) => { const service = childCtx.sessionPersistence - const binding = { service } + const binding = { identity: Symbol(), service } this._persistenceBinding = binding childCtx.effect(() => () => { /* v8 ignore next -- a stale optional-service disposer cannot clear a replacement */ if (this._persistenceBinding !== binding) return - this._persistenceBinding = {} + this._persistenceBinding = { identity: Symbol() } }, 'sessionSearchSqlite.persistenceBinding') }) ctx.effect(() => { @@ -335,8 +336,8 @@ export class SessionSearchSqlite extends SessionSearchService { : persistedRows.filter(row => !observation.persisted.has(row.id as SessionId)) const liveChanges = [...observation.live.values()].filter(entry => liveById.get(entry.header.id)?.fingerprint !== entry.fingerprint) const liveDeletes = liveRows.filter(row => !observation.live.has(row.id as SessionId)) - const pointerChanged = this._lastPersistenceBinding !== undefined - && this._lastPersistenceBinding !== observation.persistenceBinding + const pointerChanged = this._lastPersistenceIdentity !== undefined + && this._lastPersistenceIdentity !== observation.persistenceBinding.identity const hasWrites = persistentChanges.length > 0 || persistentDeletes.length > 0 || liveChanges.length > 0 @@ -390,7 +391,7 @@ export class SessionSearchSqlite extends SessionSearchService { if (hasWrites || pointerChanged) this._globalGeneration += 1 if (pointerChanged) this._persistenceEpoch += 1 this._localGeneration = nextLocalGeneration - this._lastPersistenceBinding = observation.persistenceBinding + this._lastPersistenceIdentity = observation.persistenceBinding.identity } private async _observeStable( @@ -404,8 +405,8 @@ export class SessionSearchSqlite extends SessionSearchService { let persisted = new Map() if (persistence !== undefined) { try { - const canReuseIndexed = this._lastPersistenceBinding === undefined - || this._lastPersistenceBinding === persistenceBinding + const canReuseIndexed = this._lastPersistenceIdentity === undefined + || this._lastPersistenceIdentity === persistenceBinding.identity const before = await waitWithAbort(persistence.listSnapshots(), signal) persisted = materializePersistenceSnapshots(before) for (const entry of persisted.values()) { diff --git a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts index 3de325b35f..0a62fff1b3 100644 --- a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts @@ -567,14 +567,17 @@ describe('SQLite reconciliation and source lifecycle', () => { const ctx = await liveContext() await ctx.plugin(TestPersistence) const internals = ctx.sessionSearch as unknown as { - _persistenceBinding: { service?: SessionPersistence } + _persistenceBinding: { identity: symbol; service?: SessionPersistence } } const originalList = ctx.sessions.list.bind(ctx.sessions) let bumped = false const list = vi.spyOn(ctx.sessions, 'list').mockImplementation(() => { if (!bumped) { bumped = true - internals._persistenceBinding = { ...internals._persistenceBinding } + internals._persistenceBinding = { + ...internals._persistenceBinding, + identity: Symbol(), + } } return originalList() }) From 5270dcd61df1e4f5773e6c6ac6e700c38d77b33d Mon Sep 17 00:00:00 2001 From: Ziya <199893125+ZiyaZhang@users.noreply.github.com> Date: Wed, 15 Jul 2026 23:11:25 -0700 Subject: [PATCH 010/368] =?UTF-8?q?docs(i18n):=20core-data-structures=20an?= =?UTF-8?q?d=20postmortem=20batch=20=E2=80=94=2022=20bilingual=20pairs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit core-data-structures 18 篇(core.md 因超长仍在产出、随后补)、 postmortem 3 篇与 RFC 前门 README 配对;流水线 + 二遍校验产出。 生成文件 docs/rfc/INDEX.md(gen-rfc-index 产物)列入排除。中文侧 页内锚点统一指向英文侧锚名,满足配对门禁的链接目标一致规则。 --- docs/core-data-structures/approval.i18n.yaml | 6 + docs/core-data-structures/approval.md | 2 + docs/core-data-structures/approval.zh.md | 66 ++++ docs/core-data-structures/bash.i18n.yaml | 6 + docs/core-data-structures/bash.md | 2 + docs/core-data-structures/bash.zh.md | 245 ++++++++++++++ .../code-runtime.i18n.yaml | 6 + docs/core-data-structures/code-runtime.md | 2 + docs/core-data-structures/code-runtime.zh.md | 85 +++++ .../core-data-structures/compaction.i18n.yaml | 6 + docs/core-data-structures/compaction.md | 2 + docs/core-data-structures/compaction.zh.md | 57 ++++ .../core-data-structures/filesystem.i18n.yaml | 6 + docs/core-data-structures/filesystem.md | 2 + docs/core-data-structures/filesystem.zh.md | 149 +++++++++ .../llm-streaming.i18n.yaml | 6 + docs/core-data-structures/llm-streaming.md | 2 + docs/core-data-structures/llm-streaming.zh.md | 80 +++++ .../persistence.i18n.yaml | 6 + docs/core-data-structures/persistence.md | 2 + docs/core-data-structures/persistence.zh.md | 90 +++++ docs/core-data-structures/sandbox.i18n.yaml | 6 + docs/core-data-structures/sandbox.md | 2 + docs/core-data-structures/sandbox.zh.md | 84 +++++ docs/core-data-structures/scope.i18n.yaml | 6 + docs/core-data-structures/scope.md | 2 + docs/core-data-structures/scope.zh.md | 33 ++ .../session-query.i18n.yaml | 6 + docs/core-data-structures/session-query.md | 2 + docs/core-data-structures/session-query.zh.md | 71 ++++ docs/core-data-structures/session.i18n.yaml | 6 + docs/core-data-structures/session.md | 2 + docs/core-data-structures/session.zh.md | 312 ++++++++++++++++++ docs/core-data-structures/skills.i18n.yaml | 6 + docs/core-data-structures/skills.md | 2 + docs/core-data-structures/skills.zh.md | 120 +++++++ docs/core-data-structures/subagent.i18n.yaml | 6 + docs/core-data-structures/subagent.md | 2 + docs/core-data-structures/subagent.zh.md | 101 ++++++ .../system-prompt.i18n.yaml | 6 + docs/core-data-structures/system-prompt.md | 2 + docs/core-data-structures/system-prompt.zh.md | 40 +++ docs/core-data-structures/tools.i18n.yaml | 6 + docs/core-data-structures/tools.md | 2 + docs/core-data-structures/tools.zh.md | 237 +++++++++++++ .../user-interaction.i18n.yaml | 6 + docs/core-data-structures/user-interaction.md | 2 + .../user-interaction.zh.md | 99 ++++++ docs/core-data-structures/web.i18n.yaml | 6 + docs/core-data-structures/web.md | 2 + docs/core-data-structures/web.zh.md | 86 +++++ docs/core-data-structures/workflow.i18n.yaml | 6 + docs/core-data-structures/workflow.md | 2 + docs/core-data-structures/workflow.zh.md | 71 ++++ ...-acp-default-export-drops-inject.i18n.yaml | 6 + .../0001-acp-default-export-drops-inject.md | 2 + ...0001-acp-default-export-drops-inject.zh.md | 113 +++++++ ...ession-disabled-filesystem-tools.i18n.yaml | 6 + ...js-expression-disabled-filesystem-tools.md | 2 + ...expression-disabled-filesystem-tools.zh.md | 47 +++ docs/postmortem/README.i18n.yaml | 6 + docs/postmortem/README.md | 2 + docs/postmortem/README.zh.md | 16 + docs/rfc/README.i18n.yaml | 6 + docs/rfc/README.md | 2 + docs/rfc/README.zh.md | 111 +++++++ scripts/translation-pairing.manifest.json | 23 ++ 67 files changed, 2512 insertions(+) create mode 100644 docs/core-data-structures/approval.i18n.yaml create mode 100644 docs/core-data-structures/approval.zh.md create mode 100644 docs/core-data-structures/bash.i18n.yaml create mode 100644 docs/core-data-structures/bash.zh.md create mode 100644 docs/core-data-structures/code-runtime.i18n.yaml create mode 100644 docs/core-data-structures/code-runtime.zh.md create mode 100644 docs/core-data-structures/compaction.i18n.yaml create mode 100644 docs/core-data-structures/compaction.zh.md create mode 100644 docs/core-data-structures/filesystem.i18n.yaml create mode 100644 docs/core-data-structures/filesystem.zh.md create mode 100644 docs/core-data-structures/llm-streaming.i18n.yaml create mode 100644 docs/core-data-structures/llm-streaming.zh.md create mode 100644 docs/core-data-structures/persistence.i18n.yaml create mode 100644 docs/core-data-structures/persistence.zh.md create mode 100644 docs/core-data-structures/sandbox.i18n.yaml create mode 100644 docs/core-data-structures/sandbox.zh.md create mode 100644 docs/core-data-structures/scope.i18n.yaml create mode 100644 docs/core-data-structures/scope.zh.md create mode 100644 docs/core-data-structures/session-query.i18n.yaml create mode 100644 docs/core-data-structures/session-query.zh.md create mode 100644 docs/core-data-structures/session.i18n.yaml create mode 100644 docs/core-data-structures/session.zh.md create mode 100644 docs/core-data-structures/skills.i18n.yaml create mode 100644 docs/core-data-structures/skills.zh.md create mode 100644 docs/core-data-structures/subagent.i18n.yaml create mode 100644 docs/core-data-structures/subagent.zh.md create mode 100644 docs/core-data-structures/system-prompt.i18n.yaml create mode 100644 docs/core-data-structures/system-prompt.zh.md create mode 100644 docs/core-data-structures/tools.i18n.yaml create mode 100644 docs/core-data-structures/tools.zh.md create mode 100644 docs/core-data-structures/user-interaction.i18n.yaml create mode 100644 docs/core-data-structures/user-interaction.zh.md create mode 100644 docs/core-data-structures/web.i18n.yaml create mode 100644 docs/core-data-structures/web.zh.md create mode 100644 docs/core-data-structures/workflow.i18n.yaml create mode 100644 docs/core-data-structures/workflow.zh.md create mode 100644 docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml create mode 100644 docs/postmortem/0001-acp-default-export-drops-inject.zh.md create mode 100644 docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml create mode 100644 docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md create mode 100644 docs/postmortem/README.i18n.yaml create mode 100644 docs/postmortem/README.zh.md create mode 100644 docs/rfc/README.i18n.yaml create mode 100644 docs/rfc/README.zh.md diff --git a/docs/core-data-structures/approval.i18n.yaml b/docs/core-data-structures/approval.i18n.yaml new file mode 100644 index 0000000000..f51b3ab961 --- /dev/null +++ b/docs/core-data-structures/approval.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +approval.md: 772582955145092f3d483c297f7704b2b8506375 +approval.zh.md: dc45e1c6969099a2b285b4da071153510356acce diff --git a/docs/core-data-structures/approval.md b/docs/core-data-structures/approval.md index c5fa1fe13b..7725829551 100644 --- a/docs/core-data-structures/approval.md +++ b/docs/core-data-structures/approval.md @@ -1,5 +1,7 @@ # User Approval +English | [中文](approval.zh.md) + The user-approval seam of [dsh-user-approval](../../packages/ui/user-approval) answers one question: may this specific action proceed? It owns the shared request/outcome vocabulary, the `ctx.approval` dispatch service, the `approval/request` answerer waterfall, the log-only audit pair, and the per-session `ask`/`never` policy. UI channels such as [dsh-acp](../../packages/ui/acp) provide answerers; callers such as [dsh-tools](../../packages/core/tools) and [dsh-tool-bash](../../packages/bash/tool-bash) consume the closed outcome and fail closed unless it is `allowed-once`. Source: [`packages/ui/user-approval/src/index.ts`](../../packages/ui/user-approval/src/index.ts) diff --git a/docs/core-data-structures/approval.zh.md b/docs/core-data-structures/approval.zh.md new file mode 100644 index 0000000000..dc45e1c696 --- /dev/null +++ b/docs/core-data-structures/approval.zh.md @@ -0,0 +1,66 @@ +# 用户审批 + +[English](approval.md) | 中文 + +[dsh-user-approval](../../packages/ui/user-approval) 的用户审批 seam 回答一个问题:这个具体操作是否可以继续?它拥有共享的请求/结果词汇、`ctx.approval` 分发服务、`approval/request` 应答者 waterfall(瀑布式事件)、仅记录日志的审计事件对,以及按会话的 `ask`/`never` 策略。UI 通道(如 [dsh-acp](../../packages/ui/acp))提供应答者;调用方(如 [dsh-tools](../../packages/core/tools) 和 [dsh-tool-bash](../../packages/bash/tool-bash))消费封闭的结果,并在结果不是 `allowed-once` 时默认拒绝。 + +源码:[`packages/ui/user-approval/src/index.ts`](../../packages/ui/user-approval/src/index.ts) + +## 标识与结果 + +每个请求获得一个新的 `ApprovalRequestId`。该品牌类型将 `approval/asked` 与 `approval/decided` 审计事件配对,同时防止审批 id 与工具调用、会话或 agent id 混用。 + +```ts type-equiv +type ApprovalRequestId = Branded<'ApprovalRequestId'> +``` + +`ApprovalOutcome` 是封闭的,且默认拒绝。`allowed-once` 仅授权被询问的那个操作;调用方在遇到 `rejected`、`cancelled` 和 `unavailable` 时一律拒绝。缺失的、不拥有该请求的、抛出异常的或不符合规范的应答者会产生 `unavailable`,而不是放行。 + +```ts type-equiv +type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable' +``` + +## 按会话策略 + +`ApprovalPolicy` 决定在交互式应答者运行之前发生什么。`ask` 委托给组合的应答者链,其无应答默认值为 `unavailable`;`never` 确定性地返回 `rejected`,不分发任何应答者。生效值取会话日志中最后一条 `approval/policy` 事件,回退到服务配置。`setApprovalPolicy(session, policy)` 是唯一的写入路径,因此回放能重建覆盖值。 + +```ts type-equiv +type ApprovalPolicy = 'ask' | 'never' +``` + +提示词段落会声明 `never` 的确定性行为,并用服务自有的标记记录当前策略。重启后,pre-step 叙述器从已记录的请求头中读取该标记;它不从部署 persona 行文中推断状态。ACP 中空闲时的策略切换会被桥接层持有到下一次 `turn/start`,因为审批审计事件和策略事件必须保持在轮次内,以确保持久回放的正确性。 + +## 审批请求 + +`ApprovalRequest` 足够精确地标识 agent 和工具操作,以便路由和审计该问题。它有意省略工具参数:应答者通过 `callId` 将提示附加到已流式输出的工具调用上,而不是渲染可能漂移的第二份副本。 + +```ts type-equiv +interface ApprovalRequest { + /** + * The agent on whose behalf the question is asked. Routes the question (a + * UI answerer only answers for agents it owns) and receives the audit + * events on its session log. + */ + readonly agent: Agent + /** The tool the question is about (presentation and audit). */ + readonly toolName: string + /** + * The exact tool call being decided, when the asker has one — lets a UI + * attach the prompt to the tool call it already streamed. + */ + readonly callId?: CallId + /** The asker's human-readable explanation of WHY it is asking. */ + readonly reason?: string + /** + * Aborting withdraws the question: the request settles `'cancelled'` + * immediately and a late answer from a still-pending answerer is discarded. + */ + readonly signal?: AbortSignal +} +``` + +## 分发与审计 + +`ctx.approval.request(req)` 要求发起请求的会话处于一个打开的轮次内。它追加 `approval/asked`,获取一个结果,追加匹配的 `approval/decided`,然后以该结果 resolve。`never` 策略在服务内部、waterfall 分发之前就已强制执行,因此即使后来用 `prepend` 注册的应答者也无法绕过它。应答者在拥有该请求时返回结果,否则调用 `next()` 委托;第一个应答占据唯一的决策槽位。 + +审计事件仅记录日志,不进入模型 transcript(文本记录)。模型可见的行为是调用方派生的工具结果,而请求头记录的是模型实际看到的提示词策略。服务 dispose(资源释放)时会同时移除其提示词段落和 pre-step 叙述器;应答者监听器独立地通过 effect 绑定到其所属插件。 diff --git a/docs/core-data-structures/bash.i18n.yaml b/docs/core-data-structures/bash.i18n.yaml new file mode 100644 index 0000000000..323300cc4e --- /dev/null +++ b/docs/core-data-structures/bash.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +bash.md: 7b5c779b832ef5be6591e626980f7f22db54f239 +bash.zh.md: 519a7bf973fdf9fd9d7c4be2cc6ebf77e576135d diff --git a/docs/core-data-structures/bash.md b/docs/core-data-structures/bash.md index a5efe1a504..7b5c779b83 100644 --- a/docs/core-data-structures/bash.md +++ b/docs/core-data-structures/bash.md @@ -1,5 +1,7 @@ # Bash Executor +English | [中文](bash.zh.md) + The bash execution seam — the canonical [capability seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md) example, split across three packages: interface ([dsh-bash](../../packages/bash/bash), `ctx.bash`), implementation ([dsh-bash-local](../../packages/bash/bash-local), local subprocesses), and consumer ([dsh-tool-bash](../../packages/bash/tool-bash), the `bash`/`bash_output`/`bash_kill` tool schemas). Bash is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A sandboxed, containerized, or remote backend is a sibling package implementing the same interface. Source: [`packages/bash/bash/src/types.ts`](../../packages/bash/bash/src/types.ts) diff --git a/docs/core-data-structures/bash.zh.md b/docs/core-data-structures/bash.zh.md new file mode 100644 index 0000000000..519a7bf973 --- /dev/null +++ b/docs/core-data-structures/bash.zh.md @@ -0,0 +1,245 @@ +# Bash 执行器 + +[English](bash.md) | 中文 + +Bash 执行 seam:典型的[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md) 示例,拆分为三个包(package):接口([dsh-bash](../../packages/bash/bash),`ctx.bash`)、实现([dsh-bash-local](../../packages/bash/bash-local),本地子进程)、消费方([dsh-tool-bash](../../packages/bash/tool-bash),`bash`/`bash_output`/`bash_kill` 工具 schema)。Bash 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此,而非 [core.md](core.md)。沙箱化、容器化或远程后端只需作为兄弟包实现同一接口。 + +源码:[`packages/bash/bash/src/types.ts`](../../packages/bash/bash/src/types.ts) + +## 请求与规格:`resolve()` 拆分 + +该 seam 将**面向模型/插件的请求**(`workdir`/`timeoutMs` 可选,由配置填充)与**执行器实际执行的完全解析规格**(这些字段为必填)分开。工具层在二者之间调用 `ctx.bash.resolve(request)`。这是本仓库「包边界处显式优于隐式」规则的具体体现:读到一个 `BashExecSpec` 的人永远不必猜测工作目录从何而来。 + +```ts type-equiv +interface BashExecRequest { + command: string + /** Working directory override (default: implementation-configured). */ + workdir?: string | undefined + /** Timeout override in milliseconds (implementations cap it). */ + timeoutMs?: number | undefined + /** Abort signal — implementations kill the command when it fires. */ + signal?: AbortSignal | undefined + /** + * Bytes to write to the command's stdin, then close it. Absent leaves stdin + * closed/empty (the default for model-driven tool calls). Set by in-process + * plugins (e.g. the hooks bridges, which write a hook command's JSON payload + * to its stdin); the model-facing bash tool does not expose it as a parameter + * (a model that needs stdin uses shell syntax like a heredoc or a pipe). + */ + stdin?: string | undefined + /** + * Extra environment entries for the command, merged AFTER the + * implementation's credential scrub (so an explicit entry here is honored even + * when its name matches the scrub pattern — the caller named a value it holds, + * not the harness's ambient secret). Set by in-process plugins (the hooks + * bridges set `CLAUDE_PROJECT_DIR`, `CLAUDE_PLUGIN_ROOT`, …); the model-facing + * bash tool does not expose it as a parameter (a model that needs an env var + * uses shell syntax like `FOO=bar cmd`). + */ + env?: Record | undefined + /** + * Opaque OWNER token for a background task — the consumer's isolation key + * (the tool layer passes the owning agent's `session.header.id`). The + * executor stores it on the task and exposes it via {@link BashExecutor.ownerOf}; + * the executor itself NEVER interprets it (no access policy lives in the + * seam — that is the consumer's job). Absent for foreground runs and for an + * ownerless background start (a non-agent caller). + */ + owner?: OwnerToken | undefined + /** + * Explicit per-call sandbox-policy input, overriding the executor's + * configured default mode for THIS call. Never a silent default: a + * consumer sets it only from an explicit policy source — an + * `'allowed-once'` grant a human just issued through `ctx.approval` (the + * escalation flow in the sandbox RFC § Escalation, which outranks), or the + * session's standing override folded from its own `bash/sandbox-mode` + * events (the sandbox RFC § Per-session mode switching — the user's recorded per-session + * choice). A sandboxing executor confines THIS call under the given mode; + * a non-sandboxing executor carries the field and confines nothing (the + * tool layer stamps neither escalation nor overrides without a sandboxing + * executor — see {@link BashExecutor.sandboxMode}). + */ + sandboxMode?: SandboxMode | undefined +} +``` + +```ts type-equiv +interface BashExecSpec { + command: string + workdir: string + timeoutMs: number + /** Abort signal — implementations kill the command when it fires. */ + signal?: AbortSignal | undefined + /** + * Bytes to write to the command's stdin (then close it), carried through + * verbatim from {@link BashExecRequest.stdin}. OPTIONAL on the resolved spec + * (unlike `owner`): it has no config default, so a missing one means "no + * stdin" — the safe, ordinary case — not a silent footgun, so it stays a + * plain optional rather than required-but-nullable (see the request field). + */ + stdin?: string | undefined + /** + * Extra environment entries, carried through verbatim from + * {@link BashExecRequest.env} and merged by the implementation AFTER its + * credential scrub (an explicit entry wins even when its name matches the + * scrub pattern). OPTIONAL on the spec for the same reason as `stdin` — no + * config default, absent means "no extra env". + */ + env?: Record | undefined + /** + * Opaque owner token, REQUIRED-but-nullable (mirrors `workdir`/`timeoutMs` + * being required on the resolved spec): {@link BashExecutor.resolve} carries + * the request's `owner` through, defaulting a missing one to `undefined`. A + * required field makes a forgotten owner a VISIBLE `undefined` rather than a + * silently-absent property that yields an unowned (cross-session-readable) + * task. `start()` stores it; `run()` (foreground) ignores it. + */ + owner: OwnerToken | undefined + /** + * The sandbox mode this call executes under, REQUIRED-but-nullable for the + * same visibility reason as `owner`. A sandboxing executor's `resolve()` + * stamps the effective mode (the request's explicit override, else its + * configured default) so `run()`/`start()` read the spec, never the config; + * a non-sandboxing executor carries the request value through verbatim and + * ignores it (`undefined` under such an executor means what its README says: + * unconfined execution). + */ + sandboxMode: SandboxMode | undefined +} +``` + +`owner` token 是隔离键:执行器存储它但从不解释它(访问策略是消费方的职责),因此一个 agent 启动的后台任务不会被跨会话读取。必填但可空的字段设计使得遗忘 owner 会表现为一个可见的 `undefined`,而非一个静默无主的任务。 + +受信的进程内插件使用 `stdin` 和 `env` 传递钩子载荷和钩子专用变量。面向模型的 bash 工具从其命名 schema 字段构造请求,不暴露这两个输入,因为 shell 语法已提供等价能力;测试会防止未来出现 `...args` 展开。这是请求形状纪律,而非安全边界:`dsh-bash-local` 无论这些字段如何都会清洗环境凭证,然后叠加调用方已持有的显式值。详见 [bash stdin/env RFC](../rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md)。 + +该 seam 处理的两个 id 都是[品牌化](core.md)的(零成本 `string` 品牌,与 `SessionId`/`AgentId` 同一套机制):`BashTaskId`(被追踪的后台任务,由本地执行器生成 `bash-N`)和 `OwnerToken`(不透明的隔离键)。`OwnerToken` 刻意是与 `SessionId` **不同**的品牌,而非别名:bash seam 是一个能力 seam,它不得知道 owner token *意味着什么*,因此从不导入 `dsh-session` 的词汇。将所属 agent 的 `SessionId` 转换为 `OwnerToken` 的唯一边界是 `dsh-tool-bash` 消费方。对两者都做品牌化,可以防止裸 `string`(或在需要 `OwnerToken` 的位置传入 `BashTaskId`,反之亦然)在面向模型的 `task_id` 路径上通过类型检查。 + +## 前台运行:`BashRunResult` + +一次已完成(或被终止)的前台运行的结果。正交的结果**独立报告**:一个进程可以既超时又以 exit 0 退出(因为它捕获了信号),因此 `timedOut`、`aborted`、`signal` 和 `exitCode` 各自独立为一个字段;调用方永远不会把一次被截断的运行误读为干净的成功。 + +```ts type-equiv +interface BashRunResult { + /** Exit code; null when the process died from a signal. */ + exitCode: number | null + /** Terminating signal (e.g. 'SIGTERM'); null on normal exit. */ + signal: NodeJS.Signals | null + /** True when the executor's own timeout killed the command. */ + timedOut: boolean + /** True when the caller's AbortSignal killed the command. */ + aborted: boolean + /** The effective timeout applied to this run (after defaulting/capping). */ + timeoutMs: number + stdout: CollectedOutput + stderr: CollectedOutput + /** + * Sandbox facts, present iff a sandboxing executor ran the command — an + * unsandboxed executor (e.g. `dsh-bash-local`) never sets it. See + * {@link BashSandboxInfo} for the `denied` classification semantics. + */ + sandbox?: BashSandboxInfo +} +``` + +每个流是一个 `CollectedOutput`:(可能被截断的)文本加恢复信息。截断时,`text` 是**尾部**,完整流溢出到一个私有文件: + +```ts type-equiv +interface CollectedOutput { + /** Collected text — the TAIL of the stream when truncated. */ + text: string + /** True when bytes were dropped from `text`. */ + truncated: boolean + /** Path to a file holding the COMPLETE stream, when truncated and available. */ + spillPath?: string +} +``` + +## 文件沙箱:`BashSandboxInfo` + +消费沙箱的执行器(`dsh-bash-sandbox`)通过 `BashExecutor.sandboxMode` 暴露其配置的回退模式。工具层折叠每个 agent 会话的持久 `bash/sandbox-mode` 覆盖,将生效模式盖章到请求上,并可能为一次用户批准的严格更宽调用替换它。工具层刻意不声明当前模式,也不叙述切换过程;拒绝结果会指明该命令实际运行时所处的模式。模式/强制词汇由 [`@deepseek-ai/dsh-sandbox` seam](sandbox.md) 拥有并编目,其提供方包装执行器的 argv;模式仅管辖文件效果,不管网络或进程可见性。 + +沙箱化运行始终在 `BashRunResult.sandbox` 上报告其执行时的事实:`denied` 是执行器对「失败由沙箱引起」的保守分类(一次失败退出且 stderr 带有文件系统权限签名——从不是干净退出或信号终止),从收集的 stderr 尾部读取;`enforcement` 报告所选后端对该模式文件效果的治理完整度(`SandboxEnforcement = 'full' | 'partial'`——当较旧的 Landlock ABI 仅治理所请求访问的子集时为 `partial`;`danger-full-access` 下不存在,因为什么都没被限制);`runnerFailed` 标记与拒绝相反的情况——沙箱 runner 本身失败,命令从未运行(仅在已结算的后台任务上盖章;前台运行通过抛出 `SANDBOX_UNAVAILABLE` 错误暴露同一状况): + +```ts type-equiv +interface BashSandboxInfo { + /** The mode the command actually ran under. */ + mode: SandboxMode + /** + * True when the executor classifies this run's failure as the sandbox + * denying a file operation. The classification is CONSERVATIVE (a failed + * exit whose stderr carries a filesystem-permission signature) and reads + * the COLLECTED stderr — the bounded in-memory tail per + * {@link CollectedOutput} semantics, so a signature that survives only in a + * spill file is missed toward `denied: false`. A plain command failure + * keeps `denied: false` even under a sandboxed mode. + */ + denied: boolean + /** + * How completely the runner enforced `mode`'s file effects — see + * {@link SandboxEnforcement}. Absent exactly when `mode` is + * `danger-full-access`: nothing is confined, so there is no enforcement to + * report. + */ + enforcement?: SandboxEnforcement + /** + * True when the executor classifies this failure as the SANDBOX RUNNER + * itself failing (missing binary, refused profile, fail-closed refusal + * before exec) — the command NEVER RAN; this is a sandbox failure, not a + * task failure, and it outranks `denied` (a runner's own error text can + * contain denial words). Only ever stamped on settled BACKGROUND tasks: a + * foreground run surfaces the same condition as the thrown + * `SANDBOX_UNAVAILABLE` error instead (the foreground path has an error + * channel; a settled task's facts are its only channel). + */ + runnerFailed?: boolean +} +``` + +还有一个词汇完成整幅图景:`SANDBOX_UNAVAILABLE` 错误码(由 [sandbox seam](sandbox.md) 拥有)是 `ctx.sandbox` 提供方在受限模式没有可用后端时抛出的——执行器将其传播。所选 runner 拒绝其 profile 也会到达同一个快速失败的前台错误;已结算的后台任务则记录 `runnerFailed`。模型在结果中收到拒绝/runner 事实,仅在拒绝标记指明模式时才得知生效模式,并可通过 `sandbox_permissions` 加 `justification` 请求一次严格更宽的重试;`ctx.approval` 必须在任何执行之前批准该确切调用。完整的策略与切换设计见 [sandbox RFC](../rfc/implemented/feature/2026-07-06-sandbox.md)。 + +## 后台任务:`BashTask` + +通过 `start()` 启动的长时间运行命令被追踪为 `BashTask`。`BashTaskStatus` 为 `'running' | 'completed' | 'killed'`;`done` 在底层进程关闭时 resolve,从不 reject。沙箱化执行器在任务结算后盖章 `sandbox`(分类针对已结算任务收集的 stderr 运行),因此该字段在运行中以及非沙箱化执行器下不存在。 + +```ts type-equiv +interface BashTask { + readonly id: BashTaskId + status: BashTaskStatus + /** Exit code once finished (null = killed by signal / still running). */ + exitCode: number | null + /** Terminating signal name, when signal-killed. */ + signal: NodeJS.Signals | null + /** Resolves when the underlying process closes (never rejects). */ + readonly done: Promise + /** + * Sandbox facts for this task's execution, stamped by a sandboxing executor + * once the task settles and BEFORE completion listeners are notified — an + * `onTaskDone` consumer and a `done` awaiter both see it. Denial + * classification runs against the settled task's collected stderr, so the + * field cannot exist earlier: absent while the task is running and under an + * executor that does not sandbox. See {@link BashSandboxInfo} for the + * `denied` semantics. + */ + sandbox?: BashSandboxInfo +} +``` + +`readOutput()` 返回增量的 `BashTaskRead`:自上次读取以来产生的输出,附带一个 `lossy` 标志表示截断丢弃了未读字节: + +```ts type-equiv +interface BashTaskRead { + task: BashTask + /** Output produced since the previous read (stderr in a marked section). */ + delta: string + /** True when truncation dropped unread bytes the delta cannot include. */ + lossy: boolean + /** Full stdout spill file, when stdout truncation occurred and a safe path is available. */ + stdoutSpillPath?: string + /** Full stderr spill file, when stderr truncation occurred and a safe path is available. */ + stderrSpillPath?: string +} +``` + +## 服务 + +`BashExecutor`(`ctx.bash`,抽象——定义于 [`packages/bash/bash/src/index.ts`](../../packages/bash/bash/src/index.ts))镜像 `LlmService`/`LlmAdapter` 的拆分:`resolve`(请求→规格)、`run`(前台)、`start`(后台)、`get`/`ownerOf`/`list`/`readOutput`/`kill`,以及 `onTaskDone`(`BashTaskListener` 完成回调)。spawn 的命令获得一个**清洗后的 env**(丢弃 `*KEY*`/`*SECRET*`/`*TOKEN*`),溢出文件使用一个权限为 0700 的私有目录(随机文件名、仅所有者可打开)——模型输出永远拿不到宿主环境或可预测路径。提供这一切的实现是 `dsh-bash-local`;调用它的面向模型的 `bash`/`bash_output`/`bash_kill` schema 位于 `dsh-tool-bash`(并通过[工具呈现词汇](tools.md#tool-presentation-ui-vocabulary)以终端形式展示)。 diff --git a/docs/core-data-structures/code-runtime.i18n.yaml b/docs/core-data-structures/code-runtime.i18n.yaml new file mode 100644 index 0000000000..b2c8f97ae1 --- /dev/null +++ b/docs/core-data-structures/code-runtime.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +code-runtime.md: 28152947d0853fb10228c472ca3e121e77b7b598 +code-runtime.zh.md: f12816fd5392f1efff3a1faeee232fb004142f37 diff --git a/docs/core-data-structures/code-runtime.md b/docs/core-data-structures/code-runtime.md index 9237a3cce9..28152947d0 100644 --- a/docs/core-data-structures/code-runtime.md +++ b/docs/core-data-structures/code-runtime.md @@ -1,5 +1,7 @@ # Code Runtime +English | [中文](code-runtime.zh.md) + The code-execution seam — a [capability seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md) whose interface ([dsh-code-runtime](../../packages/code-runtime/code-runtime), `ctx.codeRuntime`) runs one model-written program against host-provided async bindings and reports what it printed and returned. Code execution is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). Backends differ by execution substrate and source language, both readonly descriptors on the service; the worker-thread backend and the tool-registry consumer (Code Mode) are specified in the [Code Mode RFC](../rfc/implemented/feature/2026-06-15-code-mode.md). Source: [`packages/code-runtime/code-runtime/src/types.ts`](../../packages/code-runtime/code-runtime/src/types.ts) diff --git a/docs/core-data-structures/code-runtime.zh.md b/docs/core-data-structures/code-runtime.zh.md new file mode 100644 index 0000000000..f12816fd53 --- /dev/null +++ b/docs/core-data-structures/code-runtime.zh.md @@ -0,0 +1,85 @@ +# 代码运行时 + +[English](code-runtime.md) | 中文 + +代码执行 seam:一个[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md),其接口([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)负责运行一段模型编写的程序,对接宿主提供的异步绑定,并报告程序打印和返回的内容。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此处而非 [core.md](core.md)。后端因执行基底和源语言而异,二者均为服务上的只读描述符;worker-thread 后端与工具注册表消费方(Code Mode)在 [Code Mode RFC](../rfc/implemented/feature/2026-06-15-code-mode.md) 中规定。 + +源码:[`packages/code-runtime/code-runtime/src/types.ts`](../../packages/code-runtime/code-runtime/src/types.ts) + +## 运行:请求进,结果出 + +`CodeRunRequest` 携带**运行时所需的全部信息**。按照「包(package)seam 处显式优于隐式」的规则,默认值(时间预算、输出上限)由实现的已校验配置提供,绝不是 `run()` 内部隐藏的 `??`: + +```ts type-equiv +interface CodeRunRequest { + /** + * The program source, in the runtime's {@link ../index.ts | language}. It + * runs as the body of an async function: top-level `await` and `return` + * are available, and the completion value becomes + * {@link CodeRunResult.value}. + */ + program: string + /** Host functions exposed to the program, one global object per namespace. */ + bindings: CodeBindingNamespace[] + /** + * Abort the run: the runtime stops the program (hard, even mid-loop) and + * resolves with a {@link CodeRunFailure} of kind `'abort'`. In-flight + * binding calls are the CALLER's to settle — the runtime only stops asking. + */ + signal?: AbortSignal +} +``` + +结果将错误报告为一个**字段**,而非 `run()` 的 rejection:报告程序失败是调用方的职责,不是异常路径(与 `BashExecutor.run` 的 resolve-on-failure 契约一致): + +```ts type-equiv +interface CodeRunResult { + /** + * The program's completion value (its top-level `return`), when it ran to + * completion and the value survived the runtime's serialization boundary; + * a non-transferable value is replaced by a string rendering, and a failed + * or value-less run leaves this absent. + */ + value?: unknown + /** Text the program emitted, in order (capped by the implementation). */ + logs: string[] + /** Present iff the run failed; see {@link CodeRunFailure} for the taxonomy. */ + error?: CodeRunFailure +} +``` + +## 绑定:宿主函数作为程序全局变量 + +每个 `CodeBindingNamespace` 在程序内部成为一个由异步可调用成员组成的全局对象(Code Mode 消费方传入一个:`tools`)。参数与解析值必须可 structured-clone:运行时可能跨序列化边界桥接调用。运行时将绑定名视为不可信输入(`__proto__` 是普通的 own property,绝不会产生原型碰撞): + +```ts type-equiv +interface CodeBindingNamespace { + /** The global identifier the program sees (must be a valid JS identifier). */ + global: string + /** The callable members, keyed by the exact name the program calls. */ + functions: Record +} +``` + +```ts type-equiv +type CodeBindingFunction = (args: unknown) => Promise +``` + +## 捕获的输出与失败分类体系 + +日志是按发出顺序排列的纯字符串。运行时捕获程序的 console 和流输出,但通道与 console 方法的元数据不属于 seam 的一部分,因为消费方只渲染文本。实现对聚合输出设上限,并在输出内标记截断。 + +失败类型是**正交的结果,独立报告**(见 [defensive-patterns](../defensive-patterns.md)):预算耗尽不是异常,中止不是超时,基底崩溃(如 OOM)也不是二者之一: + +```ts type-equiv +interface CodeRunFailure { + /** The failure class (see the interface doc for each kind's meaning). */ + kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' + /** Human-readable detail, suitable for feeding back to a model to self-correct. */ + message: string +} +``` + +## 服务 + +`CodeRuntime`(`ctx.codeRuntime`,抽象服务,定义于 [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts))是 `run(request)` 加两个只读描述符:`language`(程序必须使用的语言:`'typescript'` 是已知值;生成语言相关展示的消费方据此分支,遇到无法展示的语言时应显式报错)和 `isolation`(执行基底:`'worker-thread'`、`'process'`、`'container'`;是诊断标签,**不是安全承诺**)。实现必须保证各次运行彼此隔离(无跨运行状态),并在 dispose(资源释放)时达到静止状态:进行中的运行在 teardown 完成前被终止并 await。 diff --git a/docs/core-data-structures/compaction.i18n.yaml b/docs/core-data-structures/compaction.i18n.yaml new file mode 100644 index 0000000000..a5dda25c68 --- /dev/null +++ b/docs/core-data-structures/compaction.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +compaction.md: e82cc103932ad05e68bc5311dec23c3f2c1a7ce4 +compaction.zh.md: 889cdba416767e90592359361fc0f65bcb2472c3 diff --git a/docs/core-data-structures/compaction.md b/docs/core-data-structures/compaction.md index 82bf512eeb..e82cc10393 100644 --- a/docs/core-data-structures/compaction.md +++ b/docs/core-data-structures/compaction.md @@ -1,5 +1,7 @@ # Compaction +English | [中文](compaction.zh.md) + The compaction seam — a [capability seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md) split like bash: interface ([dsh-compact](../../packages/compact/compact), `ctx.compact`), implementation (a backend such as [dsh-compact-basic](../../packages/compact/compact-basic)), and consumer (a `/compact` tool, deferred). Compaction is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A tokenizer- or template-based backend is a sibling package implementing the same interface. Unlike bash, the interface necessarily depends on `dsh-session` and `dsh-llm`: its verbs are defined over a `Session` and its output is the `ContentBlock` vocabulary (see the [compaction capability-seam RFC](../rfc/implemented/feature/2026-06-18-compaction-capability-seam.md)). Source: [`packages/compact/compact/src/types.ts`](../../packages/compact/compact/src/types.ts) diff --git a/docs/core-data-structures/compaction.zh.md b/docs/core-data-structures/compaction.zh.md new file mode 100644 index 0000000000..889cdba416 --- /dev/null +++ b/docs/core-data-structures/compaction.zh.md @@ -0,0 +1,57 @@ +# 压缩 + +[English](compaction.md) | 中文 + +压缩(compaction)seam 是一个[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md),按 bash 模式拆分:接口([dsh-compact](../../packages/compact/compact),`ctx.compact`)、实现(后端,如 [dsh-compact-basic](../../packages/compact/compact-basic))、消费方(一个 `/compact` 工具,暂缓)。压缩是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此,而非 [core.md](core.md)。基于 tokenizer 或模板的后端是实现同一接口的兄弟包。与 bash 不同的是,该接口必然依赖 `dsh-session` 和 `dsh-llm`:它的动词定义在 `Session` 之上,输出是 `ContentBlock` 词汇(见[压缩能力 seam RFC](../rfc/implemented/feature/2026-06-18-compaction-capability-seam.md))。 + +源码:[`packages/compact/compact/src/types.ts`](../../packages/compact/compact/src/types.ts) + +## `compact/*` 会话事件 + +压缩通过声明合并为 [`SessionEventMap`](session.md) 扩展了三种事件类型。三者均为**仅日志**事件:它们记录压缩锁及其来源信息,永远不进入 surface。`SurfaceEventType` 被刻意**不**扩展(只有产生消息的事件才到达模型),因此摘要本身搭载在一条单独的 `user/message` 上,带有 `surfaceOp: { op: 'replace', start, end }`——唯一的 surface 变更。关于为何复用 `user/message` 是诚实的做法而非变通手段,见 RFC。 + +| 事件 | 载荷 | 作用 | +|---|---|---| +| `compact/start` | `{ turn }` | 获取日志记录的锁 | +| `compact/summary` | `{ summary, shadowedRange, shadowedSeqs, shadowedTokenCount, model, maxTokens? }` | 来源信息:摘要块、被遮蔽的 surface 边界对(`start`/`end` seq——位置跨度,非数值区间)、按 surface 顺序排列的被遮蔽 seq、估算 token 数量,以及摘要调用的信封(`model`,加上生效时的生成上限)——记录下来以便从日志 + 代码重建一次性请求(可重建性 RFC) | +| `compact/end` | `{ turn, error? }` | 释放锁(摘要生成抛出异常时设置 `error`) | + +锁括住**整个**操作:先追加 `compact/start`,然后执行摘要生成、落入 `compact/summary` 来源记录和 `user/message` 替换,最后才追加 `compact/end`。最后释放锁意味着操作中途崩溃会变成一个可检测的遗留锁(有 `compact/start` 而无匹配的 `compact/end`),而不是一个虚假声称压缩已完成的 `compact/end`。 + +这些变体在 `declare module '@deepseek-ai/dsh-session'` 块内合并,因此——与其他子页面上的顶层类型不同——它们不以漂移检查的 ` ```ts type-equiv ` 块粘贴(`verify-type-equiv` 提取器只按名称匹配顶层声明)。上方的载荷表即为目录条目;权威形状请循源码链接查看。 + +## `CompactionResult` + +一次成功的压缩返回给调用方的内容:三个追加的 `compact/*` 事件的 seq、摘要块,以及被遮蔽的范围/seq 加上估算 token 数量。 + +```ts type-equiv +interface CompactionResult { + /** The seq of the appended `compact/start` event. */ + startSeq: number + /** The seq of the appended `compact/summary` event. */ + summarySeq: number + /** The seq of the appended `compact/end` event. */ + endSeq: number + /** The summary content blocks produced by the backend. */ + summary: ContentBlock[] + /** + * The surface-boundary pair that was shadowed: the seqs of the first + * (`start`) and last (`end`) surface nodes of the replaced range. A + * surface-POSITION span, not a numeric seq interval — after a prior replace + * lands a fresh high-seq summary node at an older range's position, `start` + * can be GREATER than `end`. {@link CompactionResult.shadowedSeqs} is the + * authoritative set of shadowed nodes, in surface order. + */ + shadowedRange: { start: number; end: number } + /** The seqs of all shadowed surface nodes, in surface order. */ + shadowedSeqs: number[] + /** Estimated token count of the shadowed content. */ + shadowedTokenCount: number +} +``` + +## 服务 + +`CompactService` 暴露 `compactIfNeeded(...)` 用于压力触发的压缩(不需要压缩时返回 `null`),以及 `compactRegion(...)` 用于对显式的 surface 闭区间执行压缩。pre-step 调用方提供 agent、完整提示词、会话前缀和 abort signal;实现必须将该 signal 转发给摘要生成。估算、保留策略、事件排序和摘要生成均为后端策略。 + +自动压缩在串行的 `agent/pre-step` 时运行,位于步骤和请求推导之前,因此它可以替换 surface 节点,同时将 trace 事件保持在步骤之外。区域边界保留工具调用/结果的配对,但不保留完整轮次,允许一个超大轮次中较早关闭的步骤被压缩。保留策略与失败处理的细节由 `dsh-compact-basic` 负责。 diff --git a/docs/core-data-structures/filesystem.i18n.yaml b/docs/core-data-structures/filesystem.i18n.yaml new file mode 100644 index 0000000000..760bf4eda7 --- /dev/null +++ b/docs/core-data-structures/filesystem.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +filesystem.md: 8bdc2323a0bf63588e01520926f093538fee4912 +filesystem.zh.md: 93ca9b26e054cadb40382391404573c95a1c8d05 diff --git a/docs/core-data-structures/filesystem.md b/docs/core-data-structures/filesystem.md index 6c6dd3a130..8bdc2323a0 100644 --- a/docs/core-data-structures/filesystem.md +++ b/docs/core-data-structures/filesystem.md @@ -1,5 +1,7 @@ # Filesystem +English | [中文](filesystem.zh.md) + The optional filesystem capability has four parts: [dsh-fs](../../packages/fs/fs) owns `ctx.fs` and atomic text operations with optional version guards, [dsh-fs-local](../../packages/fs/fs-local) implements local disk, [dsh-fs-policy](../../packages/fs/fs-policy) adds observed-state and freshness rules through events rather than a service, and [dsh-tool-fs](../../packages/fs/tool-fs) directly executes model-facing read/write/edit calls and renders windows. It is outside the agent-loop spine; alternate backends do not change policy or tool schemas. The model is **additive, not subtractive**: `ctx.fs` alone is a complete, unconstrained text-storage seam (`write` unconditionally creates-or-overwrites, `edit` unconditionally replaces literal text). `dsh-fs-policy` is a plugin that *adds* policy on top by deciding the `fs/*` waterfalls; removing it leaves the bare provider rather than breaking the tool, because the tool is not method-coupled to the policy. A deployment that loads `dsh-tool-fs` is expected to also load `dsh-fs-policy` so the default behavior is read-before-write/edit. diff --git a/docs/core-data-structures/filesystem.zh.md b/docs/core-data-structures/filesystem.zh.md new file mode 100644 index 0000000000..93ca9b26e0 --- /dev/null +++ b/docs/core-data-structures/filesystem.zh.md @@ -0,0 +1,149 @@ +# 文件系统 + +[English](filesystem.md) | 中文 + +可选的文件系统能力由四部分组成:[dsh-fs](../../packages/fs/fs) 拥有 `ctx.fs` 以及带可选版本守卫的原子文本操作,[dsh-fs-local](../../packages/fs/fs-local) 实现本地磁盘后端,[dsh-fs-policy](../../packages/fs/fs-policy) 通过事件(而非服务)添加观测状态与新鲜度规则,[dsh-tool-fs](../../packages/fs/tool-fs) 直接执行面向模型的 read/write/edit 调用并渲染窗口。它位于 agent loop 主干之外;替换后端不会改变策略或工具 schema。 + +该模型是**加法式而非减法式**的:`ctx.fs` 本身就是一个完整、无约束的文本存储 seam(`write` 无条件创建或覆盖,`edit` 无条件替换字面文本)。`dsh-fs-policy` 是一个在此之上*添加*策略的插件,通过裁决 `fs/*` waterfall(瀑布式事件)实现;移除它只会留下裸提供方,而不会破坏工具,因为工具与策略之间没有方法级耦合。加载了 `dsh-tool-fs` 的部署预期同时加载 `dsh-fs-policy`,使默认行为为先读后写/编辑。 + +提供方源码:[`packages/fs/fs/src/types.ts`](../../packages/fs/fs/src/types.ts) 与 [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts)。策略源码:[`packages/fs/fs-policy/src/types.ts`](../../packages/fs/fs-policy/src/types.ts)。读取渲染源码:[`packages/fs/tool-fs/src/read-render.ts`](../../packages/fs/tool-fs/src/read-render.ts)。 + +## 目标标识与元数据(提供方 seam) + +每个操作首先将用户提供的路径解析为一个不透明的后端目标。消费方可以展示 `displayPath`,但不得解析 `targetKey`(一个品牌化的不透明 id),也不得假设它是本地绝对路径。 + +```ts type-equiv +interface FsTarget { + targetKey: FsTargetKey + displayPath: string +} +``` + +后端拥有文件版本 token:即 write/edit 所守卫的新鲜度 token。策略插件存储它们用于陈旧检查;消费方不解释其含义。两个 id 都是品牌化的不透明字符串。 + +```ts type-equiv +type FsTargetKey = Branded<'FsTargetKey'> +``` + +```ts type-equiv +type FsVersion = Branded<'FsVersion'> +``` + +`stat` 返回元数据(从不返回内容),目标不存在时返回 `undefined`。`type` 让工具在读取前拒绝目录/特殊文件,`size` 让工具无需通过失败探测即可选择 `readText` 还是 `streamText`。 + +```ts type-equiv +interface FsInfo { + version: FsVersion + type: 'file' | 'directory' | 'other' + size?: number +} +``` + +`listDir` 以稳定的名称顺序返回直接子条目。每个条目携带子项的 basename、类型、已解析的目标,以及后端能廉价报告时的元数据。它不得读取文件内容,因此 `size` 仅适用于普通文件,`version` 来源于元数据。损坏或消失的子项可以作为 `other` 返回且不带元数据;列举或解析子项元数据时的权限或后端 I/O 失败会以 `FS_PERMISSION_DENIED` 或 `FS_IO_ERROR` 使整个列举失败。 + +```ts type-equiv +interface FsDirEntry { + name: string + type: 'file' | 'directory' | 'other' + target: FsTarget + version?: FsVersion + size?: number +} +``` + +## 写入与编辑守卫(提供方 seam) + +`writeText` 和 `editText` 都以可选方式接受版本守卫:省略即为无条件(裸提供方)变更,提供即为守卫。`writeText` 的守卫是 `FsWriteIntent`:`createIfAbsent` 创建缺失的目标,若目标已存在则以 `FS_NOT_OBSERVED` 拒绝;`replaceIfVersion` 仅在目标存在且版本匹配时替换,否则报 `FS_STALE_VERSION`。省略 `expected` 则无条件创建或覆盖。联合类型本身只携带两种守卫意图;「无守卫」通过省略表达,因此 write 和 edit 共享同一个对称的 `expected?` 形状。 + +```ts type-equiv +type FsWriteIntent = + | { kind: 'createIfAbsent' } + | { kind: 'replaceIfVersion'; version: FsVersion } +``` + +```ts type-equiv +interface FsWriteOutcome { + operation: 'create' | 'update' + version: FsVersion + before: string | null + after: string +} +``` + +`editText` 是提供方级别的变更,而非在别处组合的 `read` 加 `write`。守卫模式下,它在字面匹配之前先验证预期版本(因此对陈旧内容的编辑报 `FS_STALE_VERSION`,而非对更新内容的匹配失败);无守卫模式下,它编辑当前内容。无论哪种路径,它都应用替换并原子写入——将匹配、行尾处理、陈旧检查与原子替换保持在同一个变更临界区内——且目标缺失时两种路径都报 `FS_STALE_VERSION`。 + +```ts type-equiv +interface FsEditRequest { + oldString: string + newString: string + replaceAll: boolean +} +``` + +```ts type-equiv +interface FsEditOutcome { + version: FsVersion + before: string + after: string +} +``` + +## fs 策略事件(提供方 seam 词汇) + +`dsh-fs` 拥有三个事件,由工具派发、策略插件监听,使发射方(`dsh-tool-fs`)和监听方(`dsh-fs-policy`)共享词汇而无需发射方依赖策略插件。它们只携带 `dsh-fs` 词汇加一个不透明的 `object` actor,不含面向模型的概念,也不含 agent/会话所有者结构。 + +`fs/write-intent` 和 `fs/edit-intent` 是**单槽决策 waterfall**:工具派发时附带一个默认 thunk(返回 `undefined`,即裸提供方),监听方完全裁决而不调用 `next()`。该槽按注册顺序先到先得——策略插件占据该槽是部署约定,而非强制不变式。`fs/observed` 是一个即发即忘的记录事件,通过普通 `ctx.emit` 派发;其监听方必须是同步且仅有副作用的,因为工具不守卫该 emit——抛出异常的监听方会作为工具对一个已成功变更的 `isError` 结果暴露出来。生成的目录在 [events.md](../cordis-catalog/events.md) 展示确切签名。 + +## 执行上下文(策略插件) + +策略插件只需要足够的执行上下文来从 `fs/*` 事件携带的不透明 `object` actor 中窄化出观测状态的所有者。`ToolExecution` 满足此形状,因此 `dsh-tool-fs` 将其执行对象作为 actor 透传,而无需让 `dsh-fs-policy` 导入工具、agent 或会话包。 + +```ts type-equiv +interface FsPolicyExec { + agent?: { + session?: object + } +} +``` + +## 读取结果(消费方 / 读取渲染) + +文本读取受行窗口、字节上限和后端限制约束。面向模型的 `read` 工具渲染的结果纯粹是展示性的;不存在 `full`/`partial` 视图区分——授权基于新鲜度(工具直接以 stat 的版本 emit `fs/observed`),因此任何窗口化读取在文件未变时都能授权后续的 write/edit。读取窗口化与此结果形状位于 `dsh-tool-fs`(拥有读取的执行器),而非策略插件。 + +```ts type-equiv +interface FileReadOutcome { + offset: number + lines: FileTextLine[] + totalLines: number + truncatedByBytes?: true +} +``` + +## 已观测文件状态(策略插件) + +已观测状态是 `dsh-fs-policy` 插件内部持有的 `WeakMap>`。条目存在**当且仅当**所有者已读取、写入或编辑过该目标(每次成功都 emit `fs/observed`),因此条目的存在本身就是先前观测的记录——没有单独的 `hasRead` 标志,也没有视图区分。所有者从事件 actor 派生(通常是 `exec.agent.session`),被视为不透明且从不读取。成功的 read/write/edit 会刷新该所有者对应的已记录版本;dispose 时丢弃全部数据(HMR 安全)。 + +## 错误分类体系(提供方 seam) + +文件系统失败使用稳定的 `FsErrorCode` 字符串,由 `FsError`(`HarnessError`)携带。工具注册表在错误结果上保留 `{ name, code }`,使重试、权限和 UI 层无需解析文本即可分支。 + +```ts type-equiv +type FsErrorCode = + | 'FS_NOT_FOUND' + | 'FS_NOT_DIRECTORY' + | 'FS_NOT_TEXT' + | 'FS_NOT_REGULAR_FILE' + | 'FS_PERMISSION_DENIED' + | 'FS_IO_ERROR' + | 'FS_STALE_VERSION' + | 'FS_NOT_OBSERVED' + | 'FS_AMBIGUOUS_EDIT' + | 'FS_EDIT_NOT_FOUND' + | 'FS_ABORTED' +``` + +`FS_NOT_DIRECTORY`、`FS_PERMISSION_DENIED` 和 `FS_IO_ERROR` 用于目录列举,分别区分目标存在但不是目录、列举被拒绝、以及意外的后端 I/O 失败。`FS_NOT_OBSERVED` 表示策略插件没有该所有者的先前观测记录(或 `createIfAbsent` 遇到了已存在的文件)。`FS_STALE_VERSION` 表示后端版本不再匹配已观测版本(或编辑遇到了缺失的目标)。新鲜度授权没有 partial/full 区分,因此不存在 `FS_PARTIAL_OBSERVATION`。 + +## 服务与插件 + +`FileSystem`(`ctx.fs`,抽象)拥有提供方原语:`resolve`、`stat`、`readText`、`streamText`、`listDir`、`writeText` 和 `editText`。`dsh-fs-policy` **不注册服务**——它是一个通过 `fs/*` 事件门添加策略的插件:它裁决 write/edit intent waterfall(提供 `createIfAbsent`/`replaceIfVersion`/`{ version }` 或抛出 `FS_NOT_OBSERVED`),并在 `fs/observed` 上记录。执行器是 `dsh-tool-fs`:它通过 `ctx.fs` 读/写/编辑,派发 waterfall,并 emit 记录事件。生成的接线目录在 [services.md](../cordis-catalog/services.md#ctxfs--filesystem-abstract-seam) 展示确切的 `ctx.fs` 签名。 diff --git a/docs/core-data-structures/llm-streaming.i18n.yaml b/docs/core-data-structures/llm-streaming.i18n.yaml new file mode 100644 index 0000000000..4227258611 --- /dev/null +++ b/docs/core-data-structures/llm-streaming.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +llm-streaming.md: ffd276b4647be8d10afcab0fb3c3f6daad790d20 +llm-streaming.zh.md: 051d6f5d28059bf81ba38c348ea306c46e73d4e2 diff --git a/docs/core-data-structures/llm-streaming.md b/docs/core-data-structures/llm-streaming.md index fff329310a..ffd276b464 100644 --- a/docs/core-data-structures/llm-streaming.md +++ b/docs/core-data-structures/llm-streaming.md @@ -1,5 +1,7 @@ # LLM Streaming +English | [中文](llm-streaming.zh.md) + The wire-level streaming vocabulary of [dsh-llm](../../packages/llm/llm). [core.md](core.md) introduces `StreamChunk`, `Message`, and `ContentBlock`; this page owns the full chunk protocol, the adapter contract every adapter must obey, and the shared assembler. Source: [`packages/llm/llm/src/types.ts`](../../packages/llm/llm/src/types.ts) diff --git a/docs/core-data-structures/llm-streaming.zh.md b/docs/core-data-structures/llm-streaming.zh.md new file mode 100644 index 0000000000..051d6f5d28 --- /dev/null +++ b/docs/core-data-structures/llm-streaming.zh.md @@ -0,0 +1,80 @@ +# LLM 流式输出 + +[English](llm-streaming.md) | 中文 + +[dsh-llm](../../packages/llm/llm) 的协议格式(wire format)级流式输出词汇。[core.md](core.md) 介绍了 `StreamChunk`、`Message` 与 `ContentBlock`;本页拥有完整的分片协议、每个适配器必须遵守的适配器契约(adapter contract),以及共享的 assembler。 + +源码:[`packages/llm/llm/src/types.ts`](../../packages/llm/llm/src/types.ts) + +## `StreamChunk`:原始协议 + +一次流式响应会交错多种类型的块(文本、推理、多个工具调用)。`index` 将每个 delta 关联到对应的块;`block-end` 携带完整组装好的 `ContentBlock`,消费方无需自行重新组装 delta。这是一个**封闭的**可辨识联合类型:对 `type` 的 `switch` 以 `assertNever` 结尾,因此新增变体会在每个必须处理它的消费方处触发编译错误。 + +```ts type-equiv +type StreamChunk = + | { type: 'block-start'; index: number; blockType: ContentBlockType } + | { type: 'text-delta'; index: number; text: string } + | { type: 'reasoning-delta'; index: number; text: string } + | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string } + | { type: 'block-end'; index: number; block: ContentBlock } + | { type: 'usage'; usage: TokenUsage } + | { type: 'finish'; reason: FinishReason } +``` + +## 适配器契约 + +每个适配器必须遵守以下规则,每个消费方可以依赖它们: + +- **`usage` 在 `finish` 之前,`finish` 之后不再有任何分片。** 将两者都推迟到提供方的流结束标记,这样尾部的 usage-only 分片就不会违反顺序。 +- **工具调用的 `arguments` 全程保持原始 JSON 字符串。** 部分片段通过 `argumentsDelta` 流式传输;如果提供方返回的是已解析的对象,适配器在 `block-end` 时重新序列化。 +- **两条认可的错误路径。** 失败可以从 `stream()` 抛出异常(传输/协议错误),**或者**以 `finish {kind:'error'|'aborted'}` 结束流(提供方带内错误,适用于无法在流中途抛出异常的适配器)。消费方必须同时处理*两种*情况。agent loop(智能体循环)将 finish-error/aborted 转化为轮次错误,绝不会为失败的步骤记录一条正常完成的 assistant 消息。 +- **每个提供方 HTTP 请求都携带应用归属头。** 适配器发送 `attributionHeaders()`(见下文)作为 `User-Agent` 基线,并通过协议级测试证明这一点(mock 服务器断言收到的 header,或库支持的适配器使用库的 header 钩子)。 + +这份契约正是两个适配器作为有意配对存在的原因:`dsh-llm-deepseek`(手写的 fetch/SSE(Server-Sent Events))与 `dsh-llm-pi-ai`(通过 `@earendil-works/pi-ai` 访问同一端点)。两套独立的内部实现共享一份契约,正是它将协议钉死的方式:库支持的适配器无法在流中途抛异常,因此它行使了手写适配器可能不会走到的 finish-chunk 错误路径。 + +## `AppIdentity`:应用归属 + +每个适配器向提供方发送的静态公开应用身份([`packages/llm/llm/src/attribution.ts`](../../packages/llm/llm/src/attribution.ts))。`attributionHeaders(identity?)` 仅将其映射为标准 `User-Agent` header;本契约有意不支持 OpenRouter 特有的应用归属 header。默认的 `APP_IDENTITY` 从包(package)的 manifest(元数据清单)获取版本号;每个字段都是公开的产品事实,不含密钥、路径、会话 id 或用户标识符,且没有任何逐请求的值可以影响这些字段。设计依据见 [强制 `User-Agent` 归属](../rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 + +```ts type-equiv +interface AppIdentity { + product: string + version: string + url: string +} +``` + +## `TokenUsage` + +单次调用的 token 用量统计。各计数**互不重叠**:`inputTokens` 仅为未缓存的输入;缓存命中的输入单独报告,计费输入是三者之和。如果提供方将缓存命中合并到单一的 prompt 总量中(如 DeepSeek 的 `prompt_tokens`),适配器需将其减回去。 + +```ts type-equiv +interface TokenUsage { + inputTokens: number + outputTokens: number + cacheReadTokens?: number + cacheWriteTokens?: number + reasoningTokens?: number +} +``` + +## `BlockAssembler` + +`BlockAssembler`([`packages/llm/llm/src/assembler.ts`](../../packages/llm/llm/src/assembler.ts))是唯一的共享实现,负责将 `StreamChunk` 流折叠回 `ContentBlock` 序列与最终的 `Message`。agent loop 记录原始分片(保证回放保真度),同时将相同的分片送入 assembler;这样权威日志保留了 token 级别的细节,而派生的消息可以确定性地重建。需要组装结果但不想重新实现折叠逻辑的消费方使用它。 + +## seam + +`LlmAdapter` 是提供方 seam:继承它、实现 `stream()`、通过 `ctx.llm.registerAdapter(models, adapter)` 注册。`block-start`/`block-end` 的 `index` 关联加上 assembler,意味着适配器只需发出格式正确的分片,块的重新组装不是各适配器自己的问题。消费方接口(`ctx.llm.stream()`)与 `llm/stream` waterfall(瀑布式事件)在 [architecture.md § Content blocks and streaming](../architecture.md#content-blocks-and-streaming-dsh-llm) 中描述。 + +`ContentBlockType`(`index` 关联的块所携带的键集合)派生自 `ContentBlockMap`: + +```ts type-equiv +interface ContentBlockMap { + 'text': TextBlock + 'reasoning': ReasoningBlock + 'tool-call': ToolCallBlock + 'tool-result': ToolResultBlock +} +``` + +块接口详见 [core.md § Content blocks and messages](core.md#content-blocks-and-messages)。 diff --git a/docs/core-data-structures/persistence.i18n.yaml b/docs/core-data-structures/persistence.i18n.yaml new file mode 100644 index 0000000000..9f69617b7f --- /dev/null +++ b/docs/core-data-structures/persistence.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +persistence.md: ce7a21a5613da903a9bddd339e122bf9f899d2bd +persistence.zh.md: 07d54895ef59b99dca47142e3fde16e6d7d0d1b3 diff --git a/docs/core-data-structures/persistence.md b/docs/core-data-structures/persistence.md index 7bf102924b..ce7a21a561 100644 --- a/docs/core-data-structures/persistence.md +++ b/docs/core-data-structures/persistence.md @@ -1,5 +1,7 @@ # Session Persistence +English | [中文](persistence.zh.md) + The **durability seam** for the event log. [session.md](session.md) describes the in-memory `Session` — the append-only `SessionEvent` log that is the source of truth. This page describes how that log is made durable: the abstract `SessionPersistence` service, its backends, the flush checkpoint, crash recovery, and the metadata header that travels alongside the log. The event vocabulary the log carries is enumerated, member by member, in the generated [persistence log event catalog](../persistence-catalog.md). The seam is a textbook [capability seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md): one abstract service ([dsh-session-persistence](../../packages/session-persistence/session-persistence), `ctx.sessionPersistence`) defining create/append/load/list over the existing `SessionEvent` — **no parallel persisted type** — and two interchangeable backends that pass the same `runPersistenceContract` suite. See the [session-persistence RFC](../rfc/implemented/architecture/2026-06-14-session-persistence.md). diff --git a/docs/core-data-structures/persistence.zh.md b/docs/core-data-structures/persistence.zh.md new file mode 100644 index 0000000000..07d54895ef --- /dev/null +++ b/docs/core-data-structures/persistence.zh.md @@ -0,0 +1,90 @@ +# 会话持久化 + +[English](persistence.md) | 中文 + +事件日志的**持久性 seam**。[session.md](session.md) 描述了内存中的 `Session`:仅追加的 `SessionEvent` 日志即为真源。本页描述该日志如何被持久化:抽象的 `SessionPersistence` 服务、它的后端、flush 检查点、崩溃恢复,以及随日志一起存储的元数据头。日志所承载的事件词汇在生成的[持久化日志事件目录](../persistence-catalog.md)中逐一列出。 + +该 seam 是教科书式的[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md):一个抽象服务([dsh-session-persistence](../../packages/session-persistence/session-persistence),`ctx.sessionPersistence`)在既有的 `SessionEvent` 之上定义 create/append/load/list——**没有平行的持久化类型**——以及两个可互换的后端,它们通过同一套 `runPersistenceContract` 测试。见 [session-persistence RFC](../rfc/implemented/architecture/2026-06-14-session-persistence.md)。 + +## flush 检查点 + +`session/event` 是一个*同步*通知;持久化插件对其进行缓冲(write-behind),并在 agent loop 于每个轮次结束时触发的 `session/flush` 检查点处排空缓冲区。flush 使用 `ctx.parallel`(被 await):一个轮次的事件在下一个轮次开始前被持久提交,轮次边界即提交边界。flush 失败时通过 `agent/error` 和 logger 报告,而非作为会话事件(那样会落在提交边界之后),因此后端保留其缓冲事件等待下一次 flush。 + +## 崩溃恢复保留被中断的轮次 + +后端重新加载一个在轮次中途崩溃的日志时,会发现一个已打开的 `turn/start` 而没有对应的 `turn/end`。它**不会**截断日志:在长周期任务中,单个轮次可能非常大(许多步骤、大量工具输出),而这些事件在崩溃前已被持久追加。后端改为用一个合成的 `turn/end { reason: { kind: 'interrupted' } }` 关闭这个遗留轮次,保持日志平衡与轮次封闭不变式完好。`interrupted` 是唯一一个 agent loop 不会自行发出的 `TurnEndReason`(见 [session.md](session.md#why-a-turn-ended-turnendreasonmap))。 + +## `SessionHeader`:日志旁的元数据 + +每个会话的元数据与事件日志**分开**存储:格式版本、cwd、血缘关系和 seed 边界属于存储关注点而非对话事件,因此它们不在 `SessionEventMap` 中,也不会进入 `deriveMessages()`。header 通过 `session.header` 附加到 `Session` 上。 + +源码:[`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) + +```ts type-equiv +interface SessionHeader { + /** + * On-disk format version, stamped from {@link SESSION_FORMAT_VERSION} when the + * session is created. A persistence backend rejects any other version on load + * (no migration — see the constant). + */ + readonly version: number + /** The session's id (mirrors the {@link Session}'s id). */ + readonly id: SessionId + /** Unix epoch milliseconds when the session was created. */ + readonly createdAt: number + /** Absolute working directory the session was created in (if any). */ + readonly cwd?: string + /** The session this one was forked from (seed lineage), if any. */ + readonly parentSession?: SessionId + /** + * How many leading events were INHERITED via a seed rather than produced by + * this session — the seed boundary. Set when a fork seeds a child with a + * prefix of the parent's log (= the seeded prefix length); absent/0 means the + * session produced all its own events. Persisted so a reload reconstructs the + * boundary instead of re-deriving it from the full stored log, and so a replay + * harness can skip the inherited prefix when deriving the child's OWN script + * (the seeded events are the parent's, not this child's model calls). + */ + readonly seedLength?: number +} +``` + +## `CreateSessionOptions`:seed 与元数据 + +通过 store 创建 `Session` 时接受 `seed`(回放/fork 一个已有事件日志)和 `meta`(store 折叠进 `SessionHeader` 的存储级字段)。store 填充 `version`/`id` 并为 `createdAt` 设默认值;调用方提供经过校验的绝对路径 `cwd`、`parentSession` 血缘、`seedLength` seed 边界,以及仅在重建持久化会话时提供的原始 `createdAt` 以保留它。 + +```ts type-equiv +interface CreateSessionOptions { + /** Events to seed the new session with (replay/fork). */ + readonly seed?: readonly SessionEvent[] + /** + * Creation metadata. The store fills in `version`/`id` and defaults + * `createdAt` to now; the caller supplies the storage-level fields (validated + * absolute `cwd`, `parentSession` lineage, the seed boundary `seedLength`, and + * — when reconstructing a persisted session — the original `createdAt` to + * preserve it). + * + * `seedLength` is EXPLICIT, not inferred from `seed.length`: a reconstruction + * (resume/load) seeds the WHOLE stored log, so its `seed.length` is the full + * length, not the original boundary — the caller must pass the persisted + * boundary back. A fresh fork passes its actual seeded-prefix length. + */ + readonly meta?: { + readonly cwd?: string + readonly parentSession?: SessionId + readonly createdAt?: number + readonly seedLength?: number + } +} +``` + +因此,回放/fork 是 `ctx.sessions.create(id, { seed: seedEvents })`;将一个*持久化*会话恢复为活跃 agent 是 `ctx.agents.resume({ resumeSessionId })`。 + +## 后端 + +两个后端实现同一个抽象 `SessionPersistence`(在 `SessionEvent` 之上的 create/append/load/list),并通过 `runPersistenceContract`,证明该 seam 真正与后端无关: + +- **[dsh-session-persistence-jsonl](../../packages/session-persistence/session-persistence-jsonl)**:每个会话一个仅追加的 JSONL 日志,具备崩溃安全的原子写入、上述中断轮次崩溃恢复,以及读取/回放路径。 +- **[dsh-session-persistence-sqlite](../../packages/session-persistence/session-persistence-sqlite)**:基于 `node:sqlite`,每个 `SessionEvent` 一行。行结构 `(session_id, seq, type, time, data, source_event_seqs, surface_op)` 与事件 1:1 映射(包括可选的 surface 元数据),因此没有需要保持同步的平行持久化 schema。 + +多个后端共享同一个磁盘会话时,通过[共享持久化写协调器](../rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)协调写入。 diff --git a/docs/core-data-structures/sandbox.i18n.yaml b/docs/core-data-structures/sandbox.i18n.yaml new file mode 100644 index 0000000000..67bc36207d --- /dev/null +++ b/docs/core-data-structures/sandbox.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +sandbox.md: be8e3cd60681077ff5036915fd99520fe9685140 +sandbox.zh.md: 2e9e5aa9a65e636167e45900f169ed6da5219c24 diff --git a/docs/core-data-structures/sandbox.md b/docs/core-data-structures/sandbox.md index 6b7b212373..be8e3cd606 100644 --- a/docs/core-data-structures/sandbox.md +++ b/docs/core-data-structures/sandbox.md @@ -1,5 +1,7 @@ # Process Sandbox +English | [中文](sandbox.zh.md) + The process-sandbox seam of [dsh-sandbox](../../packages/sandbox/sandbox) wraps a same-world subprocess argv in a file-effect policy without coupling consumers to a platform runner. [dsh-sandbox-local](../../packages/sandbox/sandbox-local) supplies the Linux bwrap/Landlock and macOS Seatbelt backends; [dsh-bash-sandbox](../../packages/bash/bash-sandbox) is the first consumer. Containers, microVMs, and remote execution are sibling implementations of whole capability seams, not providers of `ctx.sandbox`. Source: [`packages/sandbox/sandbox/src/index.ts`](../../packages/sandbox/sandbox/src/index.ts) diff --git a/docs/core-data-structures/sandbox.zh.md b/docs/core-data-structures/sandbox.zh.md new file mode 100644 index 0000000000..2e9e5aa9a6 --- /dev/null +++ b/docs/core-data-structures/sandbox.zh.md @@ -0,0 +1,84 @@ +# 进程沙箱 + +[English](sandbox.md) | 中文 + +[dsh-sandbox](../../packages/sandbox/sandbox) 的进程沙箱 seam 将同世界子进程 argv 包装在文件效果策略中,而不将消费方耦合到特定平台运行器。[dsh-sandbox-local](../../packages/sandbox/sandbox-local) 提供 Linux bwrap/Landlock 与 macOS Seatbelt 后端;[dsh-bash-sandbox](../../packages/bash/bash-sandbox) 是第一个消费方。容器、microVM 与远程执行是整体能力 seam 的兄弟实现,而非 `ctx.sandbox` 的提供方。 + +源码:[`packages/sandbox/sandbox/src/index.ts`](../../packages/sandbox/sandbox/src/index.ts) + +## 模式与强制 + +`SandboxMode` 仅管控文件系统效果。`read-only` 拒绝写入(必需的 `/dev/null` sink 除外);`workspace-write` 允许在工作区根目录与后端承诺的临时区域下写入;`danger-full-access` 绕过隔离。网络与进程可见性不在此词汇范围内。 + +```ts type-equiv +type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access' +``` + +只有前两种模式可以发送给提供方。`danger-full-access` 消费方直接 spawn 原始 argv,不调用 `ctx.sandbox`。 + +```ts type-equiv +type ConfinedSandboxMode = Exclude +``` + +强制级别是一个报告事实。`full` 表示后端管控了该模式承诺的所有文件效果;`partial` 表示活跃后端或较旧的内核 ABI 仅管控了一个子集,因此要求绝对承诺的消费方必须拒绝或向上暴露这一区别。 + +```ts type-equiv +type SandboxEnforcement = 'full' | 'partial' +``` + +## 逐调用策略 + +策略在每次调用时完全解析并随调用携带。这使得并发消费方和一次性升级重试可以向同一个提供方请求不同的边界,而无需修改提供方状态。 + +```ts type-equiv +interface SandboxPolicy { + /** The file-effect mode this execution runs under. */ + mode: ConfinedSandboxMode + /** Absolute root directory `workspace-write` may write under. */ + workspaceRoot: string +} +``` + +## 包装后的 argv 与分类方言 + +`ConfinedArgv` 是消费方实际 spawn 的内容。除了替换后的 argv,它还携带后端的强制事实和两组正交的 stderr 方言。`denialSignatures` 标识沙箱正常工作时被隔离命令被阻止的情况。`runnerFailureSignatures` 标识沙箱运行器在执行命令之前拒绝或失败的情况;消费方应先检查后者,将其作为沙箱基础设施故障暴露,而非普通任务失败。 + +```ts type-equiv +interface ConfinedArgv { + /** The wrapped argv (runner, profile, separator, then the caller's argv). */ + argv: string[] + /** How completely the selected backend enforces the policy's file effects. */ + enforcement: SandboxEnforcement + /** + * The selected backend's denial DIALECT: the case-insensitive stderr + * substrings a file effect denied by THIS backend produces (EROFS text + * under bwrap's read-only binds, EACCES under Landlock, EPERM under + * Seatbelt). A consumer that infers denials from a failed run's stderr + * matches against exactly these rather than a cross-backend union — the + * union claims denials a given backend never produces. + */ + denialSignatures: readonly string[] + /** + * How the RUNNER ITSELF failing identifies itself: case-insensitive stderr + * substrings produced when the sandbox binary is missing, refuses its + * profile, or fails closed before exec'ing the command (`bwrap: `, + * `landlock-run: `, `sandbox-exec: ` — each covers both the runner's own + * error prefix and the shell's runner-not-found message). ORTHOGONAL to + * {@link denialSignatures}: a denial is the confined COMMAND being blocked + * (the sandbox working as designed); a runner failure means the command + * NEVER RAN and must surface as a sandbox failure, not a task failure — + * consumers check these signatures FIRST (a runner's own error text may + * contain denial words, e.g. an unopenable grant root reporting + * `Permission denied`). + */ + runnerFailureSignatures: readonly string[] +} +``` + +运维人员配置的本地运行器必须为自身的 pre-exec 拒绝方言提供至少一条 `runnerFailureSignatures` 条目;提供方会自动添加外层 shell 的 missing 和 unexecutable 形式。这使得可执行的自定义运行器拒绝其 profile 的情况与被包装命令以相同状态码退出的情况可以区分开来。 + +## 提供方与 fail-closed 错误 + +`ctx.sandbox.confine(argv, policy)` 返回一个 `ConfinedArgv`,或在没有可用后端时抛出 `SandboxUnavailableError`(错误码 `SANDBOX_UNAVAILABLE`)。已选定的运行器也可能在执行时 fail-closed,此时其失败签名承载相同的基础设施含义。对于受限策略,静默的无隔离透传永远不合法。 + +提供方探测在多个候选后端之间仲裁,结果在提供方生命周期内缓存。只有一个候选的平台可以直接选定它;执行时拒绝仍保留安全属性。本地提供方将 bwrap 和 Seatbelt 报告为 full,并保留 Landlock 启动器的 full/partial 内核裁定。 diff --git a/docs/core-data-structures/scope.i18n.yaml b/docs/core-data-structures/scope.i18n.yaml new file mode 100644 index 0000000000..45f21bc10d --- /dev/null +++ b/docs/core-data-structures/scope.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +scope.md: f95594329ee9ac83da2efcc31df377c53e64331a +scope.zh.md: 80b2a7355e0499fcccf0e218c57f395252416cbd diff --git a/docs/core-data-structures/scope.md b/docs/core-data-structures/scope.md index 66d5f40de9..f95594329e 100644 --- a/docs/core-data-structures/scope.md +++ b/docs/core-data-structures/scope.md @@ -1,5 +1,7 @@ # Scoped Registration +English | [中文](scope.zh.md) + The [scope package](../../packages/core/scope) supplies the identity and carrier vocabulary that makes one registration context mean both per-agent visibility and shared lifetime ownership. It is a library primitive rather than a Cordis service; the [agent-scope runtime-design RFC](../rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#scope-routing-one-opaque-key-selects-one-layer) owns the implementation rationale, while the package [README](../../packages/core/scope/README.md) owns the callable API and filtering semantics. Source: [`packages/core/scope/src/index.ts`](../../packages/core/scope/src/index.ts). diff --git a/docs/core-data-structures/scope.zh.md b/docs/core-data-structures/scope.zh.md new file mode 100644 index 0000000000..80b2a7355e --- /dev/null +++ b/docs/core-data-structures/scope.zh.md @@ -0,0 +1,33 @@ +# 作用域注册 + +[English](scope.md) | 中文 + +[scope 包](../../packages/core/scope)提供身份标识与载体词汇,使一个注册上下文同时表达「按 agent 可见」和「共享生命周期所有权」两层含义。它是一个库级原语,而非 Cordis 服务;[agent-scope 运行时设计 RFC](../rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#scope-routing-one-opaque-key-selects-one-layer) 拥有实现动机,包的 [README](../../packages/core/scope/README.md) 拥有可调用 API 与过滤语义。 + +源码:[`packages/core/scope/src/index.ts`](../../packages/core/scope/src/index.ts)。 + +## 身份标识与分发载体 + +`ScopeKey` 是一个不透明的对象标识。已交付的 agent loop 使用活跃的 `Agent` 对象作为自身的 key,但该原语从不检视该对象。 + +```ts type-equiv +type ScopeKey = object +``` + +`Scoped` 是 `scopeTarget(base, key)` 返回的不透明路由接收者上的编译期品牌类型。经作用域过滤的事件声明要求以此载体作为其 `this` 类型,而真正的事件主体仍作为显式参数传递。 + +```ts type-equiv +type Scoped = object & { readonly [ScopedBrand]: T } +``` + +## 拥有所有权的注册上下文 + +`Scope` 将带标签的注册上下文与两个拆卸面配对。`rawDispose` 保留有序组合副作用所需的精确 Cordis disposer 标识;`dispose()` 是面向直接调用方和竞争调用方的公共共享静默边界。 + +```ts type-equiv +interface Scope { + ctx: Context + rawDispose: () => Promise | void + dispose(): Promise +} +``` diff --git a/docs/core-data-structures/session-query.i18n.yaml b/docs/core-data-structures/session-query.i18n.yaml new file mode 100644 index 0000000000..53170b4ef6 --- /dev/null +++ b/docs/core-data-structures/session-query.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +session-query.md: 444f2bb2256a43df7bd8521dfe234f771eec7181 +session-query.zh.md: 4d00e5fa310d82c6099ab4f5255f09f9e253c150 diff --git a/docs/core-data-structures/session-query.md b/docs/core-data-structures/session-query.md index ded8ca3f7e..444f2bb225 100644 --- a/docs/core-data-structures/session-query.md +++ b/docs/core-data-structures/session-query.md @@ -1,5 +1,7 @@ # Session Query +English | [中文](session-query.zh.md) + Exact reads over the live-preferred logical session corpus. The [package contract](../../packages/session-query/session-query) owns source precedence, dynamic optional persistence, cloning, surface classification, bounded windows, and typed failures. Full-text search is a separate proposed SQLite phase. Source: [`packages/session-query/session-query/src/types.ts`](../../packages/session-query/session-query/src/types.ts) diff --git a/docs/core-data-structures/session-query.zh.md b/docs/core-data-structures/session-query.zh.md new file mode 100644 index 0000000000..4d00e5fa31 --- /dev/null +++ b/docs/core-data-structures/session-query.zh.md @@ -0,0 +1,71 @@ +# Session Query + +[English](session-query.md) | 中文 + +对实时优先的逻辑会话语料库进行精确读取。[包(package)契约](../../packages/session-query/session-query)定义了源优先级、动态可选持久化、克隆、surface 分类、有界窗口与类型化错误。全文搜索是一个独立提议的 SQLite 阶段。 + +源码:[`packages/session-query/session-query/src/types.ts`](../../packages/session-query/session-query/src/types.ts) + +## 逻辑记录 + +`SessionRecord` 由跨语料库列表返回。它独立于克隆的实时优先 header 暴露源可用性。`SessionEventRecord` 是一个轻量的原始日志投影;分类使用与 model-history 推导相同的 `foldSurface()` 状态转换。 + +```ts type-equiv +export type SessionEventSurface = 'current' | 'shadowed' | 'log-only' +``` + +```ts type-equiv +export interface SessionRecord { + header: SessionHeader + live: boolean + persisted: boolean +} +``` + +```ts type-equiv +export interface SessionEventRecord { + sessionId: SessionId + seq: number + type: SessionEventType + time: number + surface: SessionEventSurface +} +``` + +## 有界事件读取 + +请求指定一个原始 seq 以及可选的前后邻近数量。结果携带 `SessionHeader` 而非可用性标志,使已知的实时目标可以独立于持久化健康状态。 + +```ts type-equiv +export interface SessionEventReadRequest { + sessionId: SessionId + seq: number + before?: number + after?: number +} +``` + +```ts type-equiv +export interface SessionEventWindow { + session: SessionHeader + target: SessionEvent + events: SessionEvent[] + startSeq: number + endSeq: number +} +``` + +## 错误 + +封闭的 code 联合类型区分请求校验、目标缺失、surface 日志格式错误、可选后端失败与源元数据矛盾。 + +```ts type-equiv +export type SessionQueryErrorCode = + | 'SESSION_QUERY_EVENT_NOT_FOUND' + | 'SESSION_QUERY_INVALID_CONFIG' + | 'SESSION_QUERY_INVALID_SURFACE' + | 'SESSION_QUERY_INVALID_WINDOW' + | 'SESSION_QUERY_PERSISTENCE_FAILED' + | 'SESSION_QUERY_SESSION_NOT_FOUND' + | 'SESSION_QUERY_SOURCE_CONFLICT' +``` diff --git a/docs/core-data-structures/session.i18n.yaml b/docs/core-data-structures/session.i18n.yaml new file mode 100644 index 0000000000..9910652ad0 --- /dev/null +++ b/docs/core-data-structures/session.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +session.md: 796abebbc31a54c7c341028cf0a09031ae59cd78 +session.zh.md: a2ff9319af1425792702502e12bd287d7f3ca805 diff --git a/docs/core-data-structures/session.md b/docs/core-data-structures/session.md index d8292c49b3..796abebbc3 100644 --- a/docs/core-data-structures/session.md +++ b/docs/core-data-structures/session.md @@ -1,5 +1,7 @@ # Sessions +English | [中文](session.zh.md) + The in-memory, event-sourced model of [dsh-session](../../packages/core/session). A `Session` is an **append-only log** of typed `SessionEvent`s — the single source of truth for an agent's whole interaction history. The LLM message history is *derived* from the log, never stored separately; replay is re-derivation from the same events. How the log is made **durable** (the persistence seam, backends, crash recovery) is the sibling concern on [persistence.md](persistence.md). Source: [`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) diff --git a/docs/core-data-structures/session.zh.md b/docs/core-data-structures/session.zh.md new file mode 100644 index 0000000000..a2ff9319af --- /dev/null +++ b/docs/core-data-structures/session.zh.md @@ -0,0 +1,312 @@ +# 会话 + +[English](session.md) | 中文 + +[dsh-session](../../packages/core/session) 的内存事件溯源模型。`Session` 是一份由类型化 `SessionEvent` 组成的**仅追加日志**,是 agent(智能体)整个交互历史的唯一真源。LLM(大语言模型)消息历史从日志*派生*而来,从不单独存储;回放即从同一组事件重新派生。日志如何实现**持久化**(持久化 seam、后端、崩溃恢复)是兄弟文档 [persistence.md](persistence.md) 的关注点。 + +源码:[`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) + +## `SessionEventMap`:事件词汇 + +仅追加的事件类型。可通过声明合并扩展:插件通过 declaration merging 声明额外的事件类型。例如[压缩(compaction) seam](compaction.md) 添加了 `compact/start` / `compact/summary` / `compact/end`,`@deepseek-ai/dsh-hook-protocol` 添加了仅记录日志的 `hook/invoked` / `hook/result` 溯源事件用于钩子桥接。与 `compact/*` 一样,这些都不是 `SurfaceEventType`(没有 `surfaceOp`)。生成的[持久化日志事件目录](../persistence-catalog.md)列举了所有成员(核心与合并的),包括其 payload、surface 标记和声明位置。 + +```ts type-equiv +interface SessionEventMap { + 'turn/start': { turn: number; trigger: TurnTrigger } + 'turn/end': { turn: number; reason: TurnEndReason } + 'step/start': { turn: number; step: number } + 'step/end': { turn: number; step: number } + /** A user-visible prompt (queued message drained at turn start). */ + 'user/message': { content: ContentBlock[]; source: MessageSource } + /** + * A queued prompt an `agent/prompt-submit` listener VETOED — the durable + * record of a blocked prompt and why. Appended in place of the `user/message` + * the prompt would have become, so the block survives replay even in a MIXED + * batch where another queued prompt is allowed (there the turn does not end + * `rejected`, so the boundary reason alone would not preserve it). `content` + * is the original prompt the listener rejected; `reason` is the veto text + * ({@link PromptDecision} `block.reason`). NOT a {@link SurfaceEventType}: a + * blocked prompt produces no LLM message and never reaches `deriveMessages()`. + */ + 'prompt/blocked': { content: ContentBlock[]; source: MessageSource; reason: string } + /** + * In-session context injection (file-change notices, subdir AGENTS.md, + * skill content, cron notifications, …). Rendered into the derived history + * as tagged synthetic context — NOT a user prompt. + */ + 'context/message': { content: ContentBlock[]; source: MessageSource } + /** Raw stream chunk — token-level replay fidelity. */ + 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk } + /** + * Assembled assistant message for one step (derived history uses this). + * Carries the step's `usage` when the adapter reported token accounting, so + * the model output and its accounting travel together (there is no separate + * usage record). `usage` is absent when the adapter reported none. + */ + 'assistant/message': { turn: number; step: number; content: ContentBlock[]; usage?: TokenUsage } + 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string } + 'tool/result': { turn: number; step: number; callId: CallId; content: ContentBlock[]; isError: boolean; error?: { name: string; code: string }; meta?: unknown } + /** Steering content injected between steps of a running turn. */ + 'steering/message': { turn: number; content: ContentBlock[]; source: MessageSource } + /** + * The agent's whole todo list, carried as a full snapshot and replaced + * wholesale on each write — the current list is the most recent `todo/write` + * (last-write-wins on replay, no fold). Appended by an owning agent via + * `session.append('todo/write', { todos })`. + * + * NOT a {@link SurfaceEventType}: it produces no LLM message and never reaches + * `deriveMessages()`, so it carries no `surfaceOp` and stays off the surface — + * it is durable, replayable UI state, distinct from the conversation history. + * It is a `SessionEventMap` member riding the existing `session/event` emit, + * not a first-class Cordis `interface Events` notification, so it has no + * cordis-catalog row. + */ + 'todo/write': { todos: TodoItem[] } + /** + * Full snapshot of the {@link EpochHeader} the NEXT request is built under, + * with the {@link RequestHeaderReason} it was recorded whole. Appended by + * the loop inside the step, before dispatch, on a loop instance's first + * request-building step (`'initial'`/`'resume'`) or when a delta failed its + * round-trip guard (`'fallback'`); always records what the request actually + * used, post-`agent/request`. Anchors the header fold: reconstruction reads + * the latest snapshot and applies the deltas after it. NOT a + * {@link SurfaceEventType}: it produces no LLM message — it is the request + * envelope, logged so every request is a pure function of the session log + * (the reconstructability RFC). + */ + 'request/header': { header: EpochHeader; reason: RequestHeaderReason } + /** + * Amendment to the folded {@link EpochHeader}: system line-trim, name-keyed + * tools delta, whole replacement config, or whole replacement session + * prefix (an EMPTY array encodes the transition to "none"). The + * writer verifies `applyHeaderDelta(previous, delta)` reproduces the new + * header exactly and falls back to a `'fallback'` `request/header` snapshot + * when it cannot, so a logged delta ALWAYS round-trips. NOT a + * {@link SurfaceEventType}. + */ + 'request/header-delta': { system?: SystemDelta; tools?: ToolsDelta; config?: LlmCallConfig; messagePrefix?: Message[] } +} +``` + +### `TodoItem`:一条待办项 + +`todo/write` 事件全量快照的单元。刻意保持最小化:一行 `content` 加一个三态 `status`(无 id、无优先级、无 `activeForm`)。列表在每次写入时整体替换,因此条目不需要稳定标识;三态 status 恰好对应 ACP 的 `PlanEntryStatus`,UI 桥接层可以将 todo 列表 1:1 映射到 ACP `plan`(ACP 额外要求的 priority 由桥接层合成)。见 [todo_write RFC](../rfc/implemented/feature/2026-06-29-todo-write-tool.md)。 + +```ts type-equiv +export interface TodoItem { + content: string + status: 'pending' | 'in_progress' | 'completed' +} +``` + +### 请求头事件:`request/header` 与 `request/header-delta` + +请求信封(`EpochHeader`:调用配置 + 渲染后的系统提示词 + 组装好的工具 schema + 会话前缀)是被记录到日志中的会话状态,因此每次对话请求都是日志的纯函数(可重建性 RFC)。`request/header` 快照(reason 为 `'initial' | 'resume' | 'fallback'`)在对话创建、进程边界和 delta 编码回退时锚定折叠点;`request/header-delta` 事件在运行中修正它。`foldRequestHeader(events)` 可重建任何请求构建时所用的 header;写入器在记录每个 delta 前都会做往返验证,因此格式良好的日志总能折叠。两者都不是 `SurfaceEventType`,不产生 LLM 消息。 + +```ts type-equiv +export interface EpochHeader { + /** The conversation's call configuration (model + sampling scalars). */ + config: LlmCallConfig + /** Rendered system prompt text; absent for a system-less request. */ + system?: string + /** Assembled tool schemas; absent for a tool-less request. */ + tools?: ToolSchema[] + /** + * The session prefix: request-only messages sent BEFORE the entire derived + * history (the `agent/session-prefix` waterfall's product, composed once + * per loop instance and reused for every request it sends). Not session + * history — `deriveMessages()` never returns it — so the header is its + * only durable record; absent when the instance composed none. + */ + messagePrefix?: Message[] +} +``` + +规范形式:空的系统提示词、空的工具列表和空的会话前缀表示为字段缺失,与请求构建方式一致。`messagePrefix` 是 `agent/session-prefix` waterfall(瀑布式事件)产物的持久记录(请求 = `messagePrefix` + 派生历史);每个 agent loop(智能体循环)实例组装一次,由该实例的快照锚定,因此循环实际上不会产生 prefix delta。delta 分支(数组整体替换,空数组编码回到缺失状态的转换)为编解码完备性而存在。其他 delta payload(`SystemDelta`:公共前缀/后缀行裁剪;`ToolsDelta`:按名称键控的增/删/改)与事件一起定义在 [`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) 中。 + +## `SessionEvent`:一条日志条目 + +基于 `type` 的正规可辨识联合(而非独立的 `type`/`data` 联合),因此 `switch (event.type)` 可以收窄 `event.data` 而无需类型断言。`seq` 是日志中的单调递增位置(`seq = log.length`);`time` 为 epoch 毫秒。 + +```ts type-equiv +type SessionEvent = { + [K in SessionEventType]: { + type: K + /** Monotonic sequence number within the session. */ + seq: number + /** Unix epoch milliseconds. */ + time: number + data: SessionEventMap[K] + } & (K extends SurfaceEventType ? { + /** + * Seq numbers of events that are provenance sources of this event + * (e.g. the `assistant/chunk` seqs that built an `assistant/message`, + * or the surface nodes shadowed by a compaction replace node). + */ + sourceEventSeqs?: number[] + /** How this event entered the surface; absent for non-surface events. */ + surfaceOp?: SurfaceOp + } : object) +}[T] +``` + +`SessionEventType = keyof SessionEventMap`。由于 `SessionEventMap` 可通过合并扩展,对 `SessionEvent` 的 switch 禁止使用 `assertNever`:插件添加的变体是合法的未知值;处理已知 case 后在 `default` 中放行。 + +## Surface 类型 + +五种产生消息的类型(`SurfaceEventType`:`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`)携带 surface 元数据,声明它们如何加入派生的 surface 链表。见[会话 surface RFC](../rfc/implemented/architecture/2026-06-18-session-surface.md)。 + +### `SurfaceEventType`:产生消息的事件类型子集 + +```ts type-equiv +export type SurfaceEventType = + | 'user/message' + | 'assistant/message' + | 'tool/result' + | 'context/message' + | 'steering/message' +``` + +### `SurfaceOp`:事件如何进入 surface + +```ts type-equiv +export type SurfaceOp = + | 'append' + | { op: 'replace'; start: number; end: number } +``` + +`'append'` 是正常的尾部追加路径。`replace` 遮蔽从 `start` 到 `end`(含两端,两者必须是有效的 surface 节点 seq;`start === end` 替换单个节点)的 surface 节点,并在其位置插入新节点。 + +### `SurfaceIntent`:`session.append()` 的参数 + +```ts type-equiv +export interface SurfaceIntent { + surfaceOp: SurfaceOp + sourceEventSeqs?: number[] +} +``` + +`SurfaceEventType` 事件必须提供此参数:每个产生消息的事件都必须声明它如何加入 surface(派生历史的唯一来源)。非 surface 类型在编译期拒绝此参数。 + +### `SurfaceNode`:surface 链表中的一个节点 + +```ts type-equiv +export interface SurfaceNode { + seq: number + prev: number | null + next: number | null +} +``` + +### `SurfaceFoldReplacement` 与 `SurfaceFoldResult`:完整的 surface 回放 + +`foldSurface(events)` 返回当前分离的节点,以及每个声明的替换范围实际遮蔽的节点 seq。`SurfaceManager` 对其增量缓存使用相同的转换函数。 + +```ts type-equiv +export interface SurfaceFoldReplacement { + seq: number + start: number + end: number + shadowedSeqs: number[] +} +``` + +```ts type-equiv +export interface SurfaceFoldResult { + nodes: SurfaceNode[] + replacements: SurfaceFoldReplacement[] +} +``` + +## 派生历史:`deriveMessages()` 与 `deriveEventMessage()` + +`Session.deriveMessages()` 将事件日志投影为模型看到的 `Message[]`。它是缓存的(每个 surface 节点在首次出现时投影一次;surface 重写触发重建)且冻结的(每次调用返回一个新数组,其中的消息是共享的深度冻结对象,因此无法通过投影来修改已记录的历史)。`deriveEventMessage(event)` 是折叠所应用的逐节点纯函数,公开暴露以便外部重建器和开发不变式检查能以完全相同的规则投影日志前缀,不会与缓存产生分歧。投影规则: + +- `user/message` → 一条 user 消息。 +- `assistant/message` → 一条 assistant 消息。原始 `assistant/chunk` 事件是回放/UI 数据,在派生中被**跳过**(组装后的消息才是权威的)。**空内容**的 `assistant/message` 也被跳过:max-tokens 截断且无内容的步骤仍会记录 `assistant/message` 以承载其 `usage`,但无内容的 assistant 轮次不得进入提供方的 transcript(文本记录)。 +- `tool/result` → 一条携带 `tool-result` 块的 user 消息。 +- `context/message`、`steering/message` → 按时间顺序插入的 user 角色消息,包裹在标签信封中(``)。这是"系统提醒"模式;模型通过信封将它们与真实提示词区分开来。 + +其他一切(`turn/*`、`step/*`)是结构性的,不投影为消息。token 用量在 `assistant/message.usage` 上观察(即产生它的那个步骤);操作错误的步骤编号在 `turn/end.reason` 中(`kind: 'error'` 时)。 + +## 活跃会话 fork API + +`ctx.sessions.create(id, { seed, meta })` 是底层的回放/fork 原语。对于普通的活跃会话 fork,`SessionStore` 暴露一个策略 API: + +- `fork(source, boundary?, childSessionId?)` 接受一个活跃的 `Session` 对象或活跃的 `SessionId`,选取源事件直到(含)`boundary` seq(默认:当前最后一个事件),要求 boundary 事件为 `turn/end`,然后创建一个活跃的子会话,包含深克隆的种子事件和子元数据(`parentSession`、`seedLength` 以及继承的 `cwd`)。 + +显式 `boundary` 允许调用方从之前完成的轮次 fork,即使源有更新的事件或一个未关闭的当前轮次。API 拒绝非 `turn/end` 的 boundary,而不是静默裁剪。更广泛的轮次封闭性检查保留在既有的 `dsh-invariants` 插件和持久化修复路径中,而非在 `fork()` 中重复。`dsh-subagent-fork` 保留其已完成前缀裁剪逻辑,因为工具时委托通常在父轮次打开时启动;普通的会话分支应显式指定所请求的 boundary。 + +## 轮次的触发原因:`TurnTriggerMap` + +```ts type-equiv +interface TurnTriggerMap { + message: { kind: 'message'; source: MessageSource } + /** + * An out-of-band context injection (`agent.inject()`) made while the agent + * was idle. The loop wraps the injected `context/message` in a one-shot turn + * (`turn/start` → `context/message` → `turn/end`) so every event in the log + * stays turn-enclosed — the durability/replay boundary is the turn, and a + * bare event between turns would otherwise be indistinguishable from a crash + * tail on reload. + */ + injection: { kind: 'injection'; source: MessageSource } +} +``` + +## 轮次的结束原因:`TurnEndReasonMap` + +```ts type-equiv +interface TurnEndReasonMap { + completed: { kind: 'completed' } + aborted: { kind: 'aborted'; reason?: string } + /** + * The turn failed: a step threw or the model reported a failure. `step` is the + * step number the failure occurred on (the operational error's location — the + * single durable record of an in-turn failure; live diagnostics also fire via + * `agent/error`). `code` is the error's code when one was attached. + */ + error: { kind: 'error'; step: number; message: string; code?: string } + disposed: { kind: 'disposed' } + 'max-tokens': { kind: 'max-tokens' } + /** + * The turn's entire prompt batch was BLOCKED before any step ran — every + * drained queued message was vetoed by an `agent/prompt-submit` listener (a + * hook). The turn still opened (so the boundary stays balanced and the block + * is a durable in-turn fact), but ran zero steps. `reason` carries the block + * message from the vetoing decision. Distinct from `aborted` (a user-driven + * cancel) and `error` (a failure): the prompt was rejected by policy, not + * interrupted or broken. A UI renders it as "prompt blocked by hook". + */ + rejected: { kind: 'rejected'; reason: string } + /** + * The turn never ended on its own: the process crashed mid-turn and a + * persistence backend later closed the orphaned (open) turn on reload so the + * log stays balanced. SYNTHESIZED by the backend's crash-recovery repair — no + * loop ever emits this. Its events are real (they were durably appended before + * the crash) and are PRESERVED, not discarded: a single turn can be huge in a + * long-horizon task (many steps, large tool output), so truncating it would + * lose real work. The marker records that the turn was cut short, not that the + * model completed it. See the session-persistence RFC. + */ + interrupted: { kind: 'interrupted' } +} +``` + +`max-tokens` 对应同名的模型调用 `FinishReason`:轮次中任何一个步骤出现 `max-tokens`,整个轮次就以 `max-tokens` 结束而非 `completed`(截断事实优先于后续续写),消费方可以区分正常停止与被截断的情况。但这仅相对于 `completed` 而言:`disposed`/`aborted`/`error` 结果优先级更高。`rejected` 是一个零步骤轮次,其整个提示词批次被 `agent/prompt-submit` 钩子阻止(ACP 桥接层将其映射为 `cancelled`)。`interrupted` 是唯一不由循环发出的 reason,由崩溃恢复合成(见 [persistence.md](persistence.md))。两个 map 均可通过合并扩展。 + +## 轮次封闭不变式 + +每个会话事件都位于一个轮次**内部**(在 `turn/start` 与其对应的 `turn/end` 之间)。循环在 `turn/start` *之后*追加排队的 `user/message` 事件;空闲时的 `agent.inject()` 将其 `context/message` 包裹在一个一次性的 `injection` 轮次中。这使得轮次成为唯一的持久性/回放边界:后端可以将最后一个 `turn/end` 之后的任何内容视为中断崩溃的尾部,而不会误丢合法记录的轮次间上下文。`dsh-invariants` 插件在开发环境中强制执行此不变式(在未打开的轮次中追加消息事件会抛出异常)。见[轮次封闭不变式 RFC](../rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md)。 + +## 插件贡献的仅日志事件 + +插件可以通过 declaration merging 向 `SessionEventMap` 添加额外类型。这些是**仅日志**事件:不是 `SurfaceEventType`(不携带 `surfaceOp`,不参与派生历史),但与所有事件一样,必须位于一个已打开的轮次内。完整的逐事件枚举(核心与插件贡献的,含 payload 和溯源信息)见生成的[持久化日志事件目录](../persistence-catalog.md);压缩 seam 的 `compact/*` 语义在 [compaction.md](compaction.md) 中讨论。 + +钩子桥接的 `hook/invoked` / `hook/result` 溯源对(来自 `@deepseek-ai/dsh-hook-protocol`)通过 `handlerId` 关联。轮次中的钩子点(`PreToolUse`/`PostToolUse`/`UserPromptSubmit`/`Stop`)在循环的已打开轮次内触发,因此其 `hook/*` 记录天然满足轮次封闭。`SessionStart` 没有 `hook/*` 记录(其注入的 `context/message` 就是持久证据),因为它没有可以容纳记录的已打开轮次(见[钩子桥接 RFC](../rfc/implemented/feature/2026-06-30-hook-bridges.md))。 + +## 持久性契约 + +持久化后端所依赖的契约:持久日志逐字保存每个事件,**包括** `assistant/chunk`。`seq` 必须保持连续,因此不能从规范日志中过滤掉 chunk。所有 `event.data` 必须是 JSON 可序列化的;`Session.append` 在源头强制执行此约束(对不可序列化的数据抛出异常),因此坏事件永远不会进入日志,`session.events` 始终等于后端可以持久化的内容。添加一个携带不可序列化数据的事件类型,或破坏不变式插件所检查的轮次/步骤嵌套,都是对磁盘格式的破坏性变更。 + +消费此契约的后端见 [persistence.md](persistence.md)。 diff --git a/docs/core-data-structures/skills.i18n.yaml b/docs/core-data-structures/skills.i18n.yaml new file mode 100644 index 0000000000..8958dbe359 --- /dev/null +++ b/docs/core-data-structures/skills.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +skills.md: b0a847cec05651b63e63de96423170a0fd7ca2a9 +skills.zh.md: db196d2058cd1ede2ef7c9fda7668720ea2824b9 diff --git a/docs/core-data-structures/skills.md b/docs/core-data-structures/skills.md index 93189ba2cb..b0a847cec0 100644 --- a/docs/core-data-structures/skills.md +++ b/docs/core-data-structures/skills.md @@ -1,5 +1,7 @@ # Skills +English | [中文](skills.zh.md) + The [skill capability family](../../packages/skill) is split across three packages: the registry ([dsh-skill](../../packages/skill/skill), `ctx.skills`) merges provider catalogs; the local provider ([dsh-skill-local](../../packages/skill/skill-local)) scans project/custom/user directories; the consumer ([dsh-tool-skill](../../packages/skill/tool-skill)) owns the session-prefix catalog and model-facing `skill` tool. Skills are optional instructions, not session events, so their vocabulary lives here rather than in [core.md](core.md). Source: [`packages/skill/skill/src/index.ts`](../../packages/skill/skill/src/index.ts), [`packages/skill/skill-local/src/index.ts`](../../packages/skill/skill-local/src/index.ts), and [`packages/skill/tool-skill/src/index.ts`](../../packages/skill/tool-skill/src/index.ts). diff --git a/docs/core-data-structures/skills.zh.md b/docs/core-data-structures/skills.zh.md new file mode 100644 index 0000000000..db196d2058 --- /dev/null +++ b/docs/core-data-structures/skills.zh.md @@ -0,0 +1,120 @@ +# Skills + +[English](skills.md) | 中文 + +[skill(技能)能力族](../../packages/skill)拆分为三个包(package):注册表([dsh-skill](../../packages/skill/skill),`ctx.skills`)合并各提供方的目录;本地提供方([dsh-skill-local](../../packages/skill/skill-local))扫描项目/自定义/用户目录;消费方([dsh-tool-skill](../../packages/skill/tool-skill))拥有会话前缀目录和面向模型的 `skill` 工具。Skill 是可选指令而非会话事件,因此其词汇定义在此处而非 [core.md](core.md)。 + +源码:[`packages/skill/skill/src/index.ts`](../../packages/skill/skill/src/index.ts)、[`packages/skill/skill-local/src/index.ts`](../../packages/skill/skill-local/src/index.ts) 与 [`packages/skill/tool-skill/src/index.ts`](../../packages/skill/tool-skill/src/index.ts)。 + +## 提供方注册表 + +`ctx.skills` 组合本地、内嵌、远程或其他提供方。注册是同步的;远程初始化和发现属于 await 的 `list()`。提供方对象、选项和候选项以只读方式借用,语义字段会被校验。 + +重名按 rank、提供方顺序、本地顺序依次解决;摘要按名称排序。`list()` 拒绝时记录日志并跳过,不缓存降级后的目录;格式错误的候选项快速失败。 + +```ts type-equiv +interface SkillProvider { + readonly name: string + readonly list: (options: SkillLookupOptions) => Promise + readonly get: (candidate: SkillCandidate, options: SkillLookupOptions) => Promise +} +``` + +## 本地发现优先级 + +内置的本地提供方按 rank 顺序扫描根目录: + +| Rank | Source | Root | +|---|---|---| +| 100 | `project-dsh` | `/.dsh/skills` | +| 200 | `project-agents` | `/.agents/skills` | +| 300 | `custom` | `Config.customSkillDirs` | +| 400 | `user-dsh` | `/skills` | +| 500 | `user-agents` | `/skills` | + +项目根目录是最近的包含 `.git` 的祖先目录;找不到时使用当前 cwd。当 `ctx.fs` 可用时,git-root 遍历通过文件系统服务探测 `.git`,使远程或沙箱化的工作区不会回退到宿主文件系统边界。用户 DSH 根目录会跳过其 `.system` 子目录。本地提供方不附带内置系统 skill;部署方通过另一个提供方提供内置 skill。 + +## Skill 标识 + +Skill 名称为 kebab-case(`^[a-z0-9]+(?:-[a-z0-9]+)*$`)。本地提供方接受目录包(`/SKILL.md`)和扁平 Markdown 文件(`.md`)。嵌套递归的 `**/SKILL.md` 发现有意不在 v1 范围内。 + +```ts type-equiv +type SkillSource = 'project-dsh' | 'project-agents' | 'runtime' | 'user-dsh' | 'user-agents' | 'custom' | (string & {}) +``` + +## 摘要、候选项与完整定义 + +`SkillSummary` 是注册表面向模型可调用的摘要形状。消费方自行选择渲染哪些字段;会话目录仅使用 `name` 和 `description`,从不使用正文或绝对文件路径。`disableModelInvocation` 将 skill 从模型列表中隐藏,但允许受信代码按名称加载。 + +```ts type-equiv +interface SkillSummary { + readonly name: string + readonly description: string + readonly whenToUse?: string + readonly disableModelInvocation?: boolean + readonly source: SkillSource + readonly provider: string + readonly resourceBase?: SkillResourceBase +} +``` + +`SkillCandidate` 是提供方到注册表的形状。`locator` 是提供方的不透明状态;注册表只存储它并在调用获胜提供方的 `get()` 时回传。 + +```ts type-equiv +interface SkillCandidate extends SkillSummary { + readonly rank: number + readonly locator: unknown + readonly path?: string + readonly metadata?: Readonly> +} +``` + +`SkillDefinition` 是 `ctx.skills.get()` 返回的完整解析结果,供 `skill` 工具使用。`resourceBase` 告诉工具如何为本地、URL 或提供方管理的 skill 渲染相对资源指引。 + +```ts type-equiv +type SkillResourceBase = + | { readonly kind: 'directory'; readonly path: string } + | { readonly kind: 'url'; readonly url: string } + | { readonly kind: 'opaque'; readonly description: string } +``` + +```ts type-equiv +interface SkillDefinition extends SkillSummary { + readonly content: string + readonly path?: string + readonly metadata?: Readonly> +} +``` + +运行时 skill 使用相同的完整形状,参与相同的先到先得收集顺序。返回的 disposer 移除该贡献并使发现缓存失效。 + +```ts type-equiv +type SkillRegistration = Omit & { + readonly provider?: string +} +``` + +## 查找与配置 + +Skill 查找对 cwd 敏感,因为提供方可能暴露工作区本地的 skill;可选的 signal 为调用方取消提供方工作。提供方接收同一个只读选项对象,用于缓存标识和加载。取消在目录选择前后(包括缓存命中)都会检查,并同时竞争发现和完整定义加载。如果找不到 git 根目录,本地提供方将提供的 cwd 本身视为项目根目录。 + +```ts type-equiv +interface SkillLookupOptions { + readonly cwd?: string | undefined + readonly signal?: AbortSignal | undefined +} +``` + +注册表只拥有其发现缓存上限。本地提供方拥有文件系统根目录(`dshHome`、`agentsHome` 和 `customSkillDirs`)。消费方拥有其目录描述上限。 + +```ts type-equiv +interface Config { + readonly collectCacheMaxEntries?: number +} +``` + +## 会话目录与工具契约 + +`dsh-tool-skill` 通过 `agent/session-prefix` 贡献一个 user-role 的 ``。目录包含按名称排序的 skill `name` 和经过规范化、XML 转义的 `description`;不包含正文、路径、来源、提供方和路由提示。前缀发现通过 `SkillLookupOptions` 转发调用方的 abort signal。`catalogDescriptionMaxLength` 是消费方配置的描述上限,默认 `500`,整数最小值 `3`。其仅限请求、记录于 header 的生命周期由 [session-prefix RFC](../rfc/implemented/feature/2026-07-07-session-prefix.md) 定义。 + +面向模型的 `skill({ name })` 工具校验 kebab-case 名称,为调用 agent 的 cwd 加载完整定义,将未解决的 skill 报告为未知或不再可用,拒绝 `disableModelInvocation` 的 skill,并返回包含 ``、`` 和 `` 的工具结果。`resourceBase` 仅按需解析显式引用的脚本、参考资料和资产;加载结果不枚举 skill 目录。工具结果是模型获取完整指令的可见路径。 diff --git a/docs/core-data-structures/subagent.i18n.yaml b/docs/core-data-structures/subagent.i18n.yaml new file mode 100644 index 0000000000..b859346be3 --- /dev/null +++ b/docs/core-data-structures/subagent.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +subagent.md: eb9160abaee26969aecdc533fb9fd56fae18b7fa +subagent.zh.md: f29ebcd50b5d3a6d961583e381b81eb88ab95823 diff --git a/docs/core-data-structures/subagent.md b/docs/core-data-structures/subagent.md index 28093165bd..eb9160abae 100644 --- a/docs/core-data-structures/subagent.md +++ b/docs/core-data-structures/subagent.md @@ -1,5 +1,7 @@ # Subagent +English | [中文](subagent.zh.md) + The subagent seam — an agent delegating work to a child agent. Like [bash](bash.md) it is **one optional capability**, not part of the agent-loop spine, so its vocabulary lives here rather than in [core.md](core.md). But it differs from every other seam on one axis: **multiple provider implementations coexist** in one context, registered by name (`ctx.subagents`), where bash allows only one executor. The registry shape mirrors the [LLM adapter registry](llm-streaming.md), not the single-service bash executor. Interface: [dsh-subagent](../../packages/subagent/subagent) (`ctx.subagents` + the vocabulary below). Implementations are sibling packages (`dsh-subagent-spawn`, `-fork`, `-acp`); the model-facing consumer is [dsh-tool-subagent](../../packages/subagent/tool-subagent). The proposal and rationale: [the subagent RFC](../rfc/implemented/feature/2026-06-21-subagent-capability-seam.md). diff --git a/docs/core-data-structures/subagent.zh.md b/docs/core-data-structures/subagent.zh.md new file mode 100644 index 0000000000..f29ebcd50b --- /dev/null +++ b/docs/core-data-structures/subagent.zh.md @@ -0,0 +1,101 @@ +# Subagent + +[English](subagent.md) | 中文 + +subagent seam:一个 agent(智能体)将工作委派给子 agent。与 [bash](bash.md) 类似,它是**一项可选能力**,不属于 agent loop(智能体循环)的主干,因此其词汇定义在这里而非 [core.md](core.md)。但它在一个维度上与其他所有 seam 不同:**多个提供方实现在同一个上下文中共存**,按名称注册(`ctx.subagents`),而 bash 只允许一个执行器。注册表的形状参照 [LLM 适配器注册表](llm-streaming.md),而非单服务的 bash 执行器。 + +接口:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。实现是兄弟包(`dsh-subagent-spawn`、`-fork`、`-acp`);面向模型的消费方是 [dsh-tool-subagent](../../packages/subagent/tool-subagent)。提案与设计动机见 [subagent RFC](../rfc/implemented/feature/2026-06-21-subagent-capability-seam.md)。 + +源码:[`packages/subagent/subagent/src/types.ts`](../../packages/subagent/subagent/src/types.ts) + +## 两类能力,两种发现方式 + +提供方通过一个静态描述符公布其**启动时**特性,服务在运行实例存在之前就会检查它;如果请求需要提供方不具备的特性,会被大声拒绝(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不会接受后静默忽略。**运行时**特性(steering(中途引导)、resume)则是 [`SubagentRun`](#a-live-run-subagentrun) 上的可选方法:方法的存在本身即为能力,TypeScript 的类型收窄就是发现机制。 + +```ts type-equiv +interface SubagentCapabilities { + readonly outputSchema: boolean + readonly depthLimit: boolean + readonly toolFilter: boolean + readonly persona: boolean +} +``` + +## 启动请求 + +工具层根据模型输入和自身配置构建此请求;服务在 `start` 之前对照指定提供方进行校验。必填的 `parent` 提供会话 cwd、血统链和委派深度。可选的 output schema、depth、tool filter 和 persona 需要对应的能力标志位。不支持的 schema 在启动时即失败;进程内后端将 filter 和 persona 限定在子 agent 创建阶段,并通过一个强制捕获工具实现所支持的 object-rooted schema。 + +```ts type-equiv +interface SubagentStartRequest { + readonly prompt: ContentBlock[] + readonly parent: Agent + readonly signal: AbortSignal + readonly agentOptions?: AgentOptions + readonly outputSchema?: StructuredOutputSchema + readonly maxDepth?: number + readonly toolFilter?: ToolRestriction + readonly persona?: string +} +``` + +`signal` 是就绪前后唯一的取消通道。[subagent 组合控制 RFC](../rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 拥有 persona、实时全局工具过滤、绝对深度以及「可见性而非权限」的设计理由。 + +## 终态结果:`SubagentResult` + +一次运行的结果,由 `SubagentRun.result` resolve。`structured` 仅在请求了 `outputSchema` 且成功满足时才存在;请求 schema 不保证一定能得到,提供方在子 agent 失败或结束时未产出有效捕获时可能返回 `stopReason: 'error'`。非 `completed` 的 `stopReason` 意味着 `output` 可能不完整:消费方将其映射为 `isError` 的工具结果,而非把不完整的输出当作成功上报。 + +```ts type-equiv +interface SubagentResult { + readonly output: ContentBlock[] + readonly structured?: unknown + readonly stopReason: SubagentStopReason +} +``` + +`SubagentStopReason` 是一个[可合并扩展的派生联合类型](core.md#the-map--derived-union-pattern):后端可以添加变体,因此消费方应对已知 case 分支处理,并将未知的终态原因视为失败: + +```ts type-equiv +interface SubagentStopReasonMap { + completed: 'completed' + aborted: 'aborted' + error: 'error' + 'max-tokens': 'max-tokens' + refusal: 'refusal' +} +``` + +## 活跃运行:`SubagentRun` + +`SubagentRun` 是消费方持有的、指向一个就绪子 agent 的句柄。消费方 await `result` 并始终 dispose 该运行以达到静止态。子 agent 失败以非 completed 的 stop reason resolve;只有无法表示的基础设施故障才会 reject。可选的 `sendMessage` 和 `resume` 方法通过其存在性公布运行时能力。 + +```ts type-equiv +interface SubagentRun { + readonly id: AgentId + readonly result: Promise + dispose(): Promise + sendMessage?(content: ContentBlock[]): void + resume?(content: ContentBlock[]): Promise +} +``` + +## 提供方 seam:`SubagentProvider` + +每个提供方是一个具名的子 agent 传输层,多个提供方可以共存。服务在 `start()` 之前校验请求的启动时能力。`inheritsParentContext` 仅描述对话种子行为(`fork`:true;`spawn` 和 `acp`:false),使消费方能生成准确的面向模型的措辞,而不暗示继承了工具、服务或权限。 + +```ts type-equiv +interface SubagentProvider { + readonly name: string + readonly capabilities: SubagentCapabilities + readonly inheritsParentContext: boolean + start(request: SubagentStartRequest): Promise +} +``` + +`start()` 仅在运行就绪时才 fulfill。服务观察其 result、发出 `subagent/start`,并返回同一个 run;rejection 意味着提供方已自行清理,且不发出生命周期事件对。进程内子 agent 可通过 `ctx.agents` 发现,远程子 agent 则不必如此。`subagent/end` 报告最终输出或基础设施故障。两个事件均为仅观察事件,包含监听器异常。 + +## 进程内后端:深度与种子 + +spawn 和 fork 后端通过 `parent.ctx` 创建一个普通 agent,将取消信号传入核心创建过程,并通过 `AgentHandle` 进行 dispose。提供方被移除时会阻止新的 start,但不会撤销已接受的运行。每个子 agent 获得一个新的扁平作用域,而非继承父级的注册。深度和 fork 种子复用既有的 agent 与会话词汇: + +- **委派深度**是一个可合并扩展的 `AgentOptions.subagentDepth` 字段(顶层 agent 为 `0`,子 agent 为 parent + 1)。只有 `undefined` 表示顶层;每个已存储的 present 值必须是非负安全整数。该 seam 拥有此字段:循环既不设置也不读取它。嵌套 spawn 校验其父级的已存储深度,拒绝超出安全整数范围的派生子深度,并将已定义的绝对 `request.maxDepth` 上限应用于该子 agent。 +- **Fork 种子**使用 `CreateAgentOptions.seed`(一个 `SessionEvent[]` 前缀,经由 `AgentLoop.createAgent` → `ctx.sessions.prepare({ seed })` 传递,与 resume 使用的是同一原语)。fork 后端传入父级日志的一段*平衡的已完成轮次前缀*:父级事件直到并包含其最后一个 `turn/end`。因此种子从 0 开始连续,[invariants](../../packages/support/invariants) 的回放能接受它(进行中的、未平衡的轮次被排除在外)。 diff --git a/docs/core-data-structures/system-prompt.i18n.yaml b/docs/core-data-structures/system-prompt.i18n.yaml new file mode 100644 index 0000000000..b07308b84a --- /dev/null +++ b/docs/core-data-structures/system-prompt.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +system-prompt.md: 175f2af407e5c39a24f0f8f8e4e664063b897ead +system-prompt.zh.md: ea1f48c56f18c97203e1052d6d0eca72710e942d diff --git a/docs/core-data-structures/system-prompt.md b/docs/core-data-structures/system-prompt.md index 4b6f1e6625..175f2af407 100644 --- a/docs/core-data-structures/system-prompt.md +++ b/docs/core-data-structures/system-prompt.md @@ -1,5 +1,7 @@ # System Prompt Assembly +English | [中文](system-prompt.zh.md) + The [system-prompt package](../../packages/core/system-prompt) owns the data exchanged between prompt contributors and one assembly call. The package [README](../../packages/core/system-prompt/README.md) documents registration, ordering, scoping, and rendering behavior; this page pins the literal cross-package shapes that plugins implement or pass. Source: [`packages/core/system-prompt/src/index.ts`](../../packages/core/system-prompt/src/index.ts). diff --git a/docs/core-data-structures/system-prompt.zh.md b/docs/core-data-structures/system-prompt.zh.md new file mode 100644 index 0000000000..ea1f48c56f --- /dev/null +++ b/docs/core-data-structures/system-prompt.zh.md @@ -0,0 +1,40 @@ +# 系统提示词组装 + +[English](system-prompt.md) | 中文 + +[system-prompt 包](../../packages/core/system-prompt)定义了提示词贡献方与单次组装调用之间交换的数据。包的 [README](../../packages/core/system-prompt/README.md) 文档记录了注册、排序、作用域与渲染行为;本页固定各插件实现或传递的跨包字面形状。 + +源码:[`packages/core/system-prompt/src/index.ts`](../../packages/core/system-prompt/src/index.ts)。 + +## 组装上下文 + +`AssembleContext` 标识单次组装所解析的作用域层。它可通过合并扩展:`dsh-agent` 添加了可选的运行时 `agent` 字段,`assembleContextFor(agent)` 同时设置该字段与 `scope`。 + +```ts type-equiv +interface AssembleContext { + scope?: ScopeKey +} +``` + +## 工具提供方结果 + +`ToolProviderResult.schemas` 是当前组装中模型可见的工具集。`knownNames` 是提供方在限制前的完整名称集合,用于区分「配置名拼写错误」与「已知工具在此作用域下被有意隐藏」。 + +```ts type-equiv +interface ToolProviderResult { + readonly schemas: readonly ToolSchema[] + readonly knownNames?: readonly string[] +} +``` + +## 提示词段 + +`PromptSection` 是一个只读的同进程注册契约。其文本可以是静态的,也可以从当前组装上下文动态解析。 + +```ts type-equiv +interface PromptSection { + readonly name: string + readonly order: number + readonly text: string | ((context: AssembleContext) => string) +} +``` diff --git a/docs/core-data-structures/tools.i18n.yaml b/docs/core-data-structures/tools.i18n.yaml new file mode 100644 index 0000000000..5b2b306ec9 --- /dev/null +++ b/docs/core-data-structures/tools.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +tools.md: f8be67054cd81027d4b751329948a784fa4f0ed9 +tools.zh.md: 080d0d99decb8630525e434a8079e29591e63ce9 diff --git a/docs/core-data-structures/tools.md b/docs/core-data-structures/tools.md index 132d22d521..f8be67054c 100644 --- a/docs/core-data-structures/tools.md +++ b/docs/core-data-structures/tools.md @@ -1,5 +1,7 @@ # Tools +English | [中文](tools.zh.md) + The tool pipeline of [dsh-tools](../../packages/core/tools). [core.md](core.md) introduces `ToolDefinition` as the one pipeline-authoring type promoted to the spine and `ToolSchema` as the model-facing wire shape. This page owns the full `ToolDefinition`, the typed schema DSL that builds it, the guarded execution shapes, and the UI-presentation vocabulary. Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) · [`packages/core/tools/src/schema.ts`](../../packages/core/tools/src/schema.ts) · [`packages/core/tools/src/presentation.ts`](../../packages/core/tools/src/presentation.ts) diff --git a/docs/core-data-structures/tools.zh.md b/docs/core-data-structures/tools.zh.md new file mode 100644 index 0000000000..080d0d99de --- /dev/null +++ b/docs/core-data-structures/tools.zh.md @@ -0,0 +1,237 @@ +# 工具 + +[English](tools.md) | 中文 + +[dsh-tools](../../packages/core/tools) 的工具流水线。[core.md](core.md) 介绍了 `ToolDefinition` 作为唯一被提升到主干的流水线编写类型,以及 `ToolSchema` 作为面向模型的协议格式(wire format)。本页拥有完整的 `ToolDefinition`、构建它的类型化 schema DSL、带守卫的执行形状,以及 UI 展示词汇。 + +源码:[`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) · [`packages/core/tools/src/schema.ts`](../../packages/core/tools/src/schema.ts) · [`packages/core/tools/src/presentation.ts`](../../packages/core/tools/src/presentation.ts) + +## `ToolDefinition`:一个已注册的工具 + +一个 `ToolSchema`(面向模型的字段)加上 `execute` 函数与可选的 UI 展示器。注册表持有这些定义;agent loop(智能体循环)通过它们分发调用。注册表的 `schemas()` 通过显式白名单构建面向模型的 `ToolSchema[]`:`execute`/`presentCall`/`presentResult` 绝不能泄漏到模型请求中。 + +```ts type-equiv +interface ToolDefinition extends ToolSchema { + execute(args: unknown, exec: ToolExecution): Promise + /** + * Cooperative tool-call timeout budget in milliseconds. Omit for no deadline. + * Enforced by `@deepseek-ai/dsh-timeout-policy` (a `tools/execute` wrapper); it + * is NEVER sent to the model — `schemas()` whitelists only name/description/ + * parameters. Declaring it asserts this tool forwards `exec.signal` to a + * cooperative implementation that can reach quiescence when the signal aborts. + */ + timeoutMs?: number + /** + * Optional: how to present the PENDING state of one call in a UI, derived from + * the call's `args` (parsed arguments, `unknown` — the tool validates/narrows + * its own input). Returns a {@link ToolCallView} (a `card`-tagged render intent), + * or `undefined` (or omit the method) to fall back to a generic presentation + * (title = tool name, raw args as input). Pure and side-effect-free: a UI may + * call it during live streaming AND a session-log replay, so it must depend + * only on `args`. + */ + presentCall?(args: unknown): ToolCallView | undefined + /** + * Optional: how to present the COMPLETED state, given the same `args` and the + * `result` (`execute`'s content + whether it errored). Returns a + * {@link ToolResultView}, or `undefined` (or omit the method) to keep the + * pending title and render the raw result content. Pure and side-effect-free + * for the same replay reason. + */ + presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined +} +``` + +`execute` 接收 `args: unknown`:原始的 `ToolDefinition` 自行校验输入。第一方工具不需要手写校验;它们使用 `defineTool`,由后者代为校验和收窄类型。 + +## 类型化 schema DSL + +插件作者为每个属性编写带有布尔值 `required: true` 的规格,类型层面的辅助工具将规格映射为 `execute` 的参数类型——零类型断言。该 DSL 是为 `ToolDefinition` *提供类型*的机制;它有意作为子页面细节,不属于核心。 + +源码:[`packages/core/tools/src/schema.ts`](../../packages/core/tools/src/schema.ts) + +```ts type-equiv +interface SchemaProp { + type: SchemaType + /** Per-property required flag (NOT the JSON Schema top-level required array). */ + required?: true + /** Human-readable description, surfaced in the JSON Schema as well. */ + description?: string + /** Enum of allowed values (strings only). */ + enum?: string[] + /** Default value. */ + default?: unknown + /** Nested properties for type: 'object'. */ + properties?: SchemaSpec + /** Items schema for type: 'array'. */ + items?: SchemaProp +} +``` + +```ts type-equiv +type SchemaSpec = Record +``` + +`SchemaType` 是原始联合类型 `'string' | 'number' | 'boolean' | 'object' | 'array'`。`InferArgs` 将一个 `SchemaSpec` 映射为 TS 参数类型:`required: true` 的属性成为必选键,其余为真正的可选: + +```ts type-equiv +type InferArgs = Simplify< + & { [K in RequiredKeys]: InferPropValue } + & { [K in Exclude>]?: InferPropValue } +> +``` + +`defineTool({ name, description, parameters, execute, … })` 将各部分串联:`parameters` 是一个 `SchemaSpec`,`execute(args, exec)` 得到 `args: InferArgs`,辅助函数将规格转换为 JSON Schema(`schemaSpecToJsonSchema`)用于协议传输,并在类型化函数体运行前校验模型生成的参数(`validateArgs`)。不匹配时抛出 `ToolArgsError`(`code: 'INVALID_ARGS'`),注册表将其转为 `isError` 结果以便模型自我修正。为什么用自定义 DSL 而非 schemastery:工具参数需要的是 JSON Schema(LLM(大语言模型)协议格式),不是校验/转换——轻量 DSL 以最小表面积提供最佳编写体验。 + +注册是受信的同进程契约。注册表以 readonly 方式借用类型化定义作为输入,仅校验语义要求(如 `timeoutMs` 必须为正有限值);`schemas()` 在模型边界处具象化显式的面向模型投影,使执行与展示共享同一份已解析定义,而不会将回调泄漏到协议上。 + +## `ToolRestriction`:单个作用域的实时全局过滤器 + +`ToolRestriction` 仅作用于实时的部署全局工具层。注册表将 readonly 名称编译为私有集合,对多个限制取交集,再叠加作用域本地工具。仅 deny 的过滤器允许后续未列出的全局工具通过,而 allow 列表则排除它们。 + +```ts type-equiv +interface ToolRestriction { + readonly allow?: readonly string[] + readonly deny?: readonly string[] +} +``` + +## 执行:可扩展的 waterfall(瀑布式事件)加单调策略 + +`ctx.tools.execute()` 接受调用方拥有的 `ToolExecutionInput`,将其解析后的 JSON 参数一次性具象化为流水线拥有的 `ToolExecution`,然后将该调用依次通过 `tools/pre-execute`(可重排的 allow/deny/ask waterfall)→ 已注册的单调守卫 → `tools/execute`(around-dispatch 包装层)→ `tools/post-execute`(检查/替换结果)→ `tools/result`(不可变的权威结果)。最终结果是一个 `ToolExecutionResult`。 + +```ts type-equiv +type ToolExecutionToken = symbol & { readonly [toolExecutionTokenBrand]: true } +``` + +```ts type-equiv +interface ToolExecutionInput { + readonly callId: CallId + readonly name: string + /** Parsed JSON arguments (unknown — tools validate their own input). */ + readonly arguments: unknown + /** The agent on whose behalf the call runs (set by the agent loop). */ + readonly agent?: Agent + /** + * Opaque token of the enclosing transport execution, when one exists. Code + * Mode sets this on SDK sub-dispatches so commit-style observers can wait for + * the outer `run_code` outcome without receiving its live mutable execution. + */ + readonly parent?: ToolExecutionToken + signal?: AbortSignal +} +``` + +```ts type-equiv +interface ToolExecution extends ToolExecutionInput { + /** Registry-assigned identity shared with nested calls only as their opaque `parent` token. */ + readonly token: ToolExecutionToken +} +``` + +`ToolExecutionToken` 是一个不透明的运行时 `Symbol`,仅用于身份比较。在策略执行之前,`execute()` 具象化并冻结参数、拒绝非 JSON 输入、分配 token。身份字段和可选的 parent token 保持 readonly;只有 `signal` 可在 dispatch 前后变化。最终观察者接收到的是冻结的执行身份。 + +`ToolGuard` 是感知作用域的最终 pre-dispatch 策略。其形状有意不包含 allow 结果:`undefined` 保留 waterfall 的决策,而返回的 reason 只能缩减权限,因此后续监听器无法撤销它。 + +```ts type-equiv +type ToolGuard = (execution: Readonly) => string | undefined +``` + +```ts type-equiv +interface ToolExecutionResult { + content: ContentBlock[] + isError: boolean + /** + * Set when the call failed with a {@link HarnessError}: machine-routable + * `{ name, code }` for retry/sandbox plugins and replay. The model-facing + * text in `content` is always present; this is extra structure for code. + */ + error?: ToolErrorInfo + /** + * Extra model-facing context a `tools/post-execute` listener attached for the + * NEXT request (Claude Code's PostToolUse `additionalContext`). It is NOT part + * of this call's `content` — `content`/`feedback` shape the tool RESULT, but + * `additionalContext` is a SEPARATE `context/message`. A step can carry + * multiple tool calls, so the loop BUFFERS every call's `additionalContext` + * and appends them only AFTER all `tool/result`s for the step, keeping + * tool-call/result adjacency intact. Carried on the result purely to ferry it + * from `execute()` up to the loop's per-step buffer. + */ + additionalContext?: HookContext + /** + * The tool-private presentation payload from a successful `execute` (the object + * return form). Threaded onto the `tool/result` session event and back into + * {@link ToolResult} for `presentResult`. Opaque (`unknown`); absent when the + * tool attached none or the call failed. + */ + meta?: unknown +} +``` + +结果仅承载结果本身。调用身份保留在不可变的 `ToolExecution` 上,后者伴随结果通过每个钩子,也保留在持久化的 `tool/call` / `tool/result` 会话事件上,因此包装层无法创建第二个相互矛盾的身份。 + +注册表在 `tools/result` 之前立即具象化并冻结最终接受的结果。其 content、结构化错误、附加上下文和展示元数据必须通过 JSON 无损往返;无效结果会被转为 JSON 安全的 `isError` 结果,确保被观察到的实时结果对后续持久化的 `tool/result` 追加是安全的。 + +每个拦截 waterfall 返回一个类型化的 **Decision**(与 `agent/*` seam 共享的惯用模式)。`tools/pre-execute` 监听器接收 `(exec, next)` 并返回 `PreToolDecision`;`tools/execute` 包装层返回 `ToolExecutionResult`;`tools/post-execute` 监听器接收 `(exec, result, next)` 并返回 `PostToolDecision`: + +```ts type-equiv +type PreToolDecision = + | { kind: 'allow' } + | { kind: 'deny'; reason: string } + | { kind: 'ask'; reason?: string } +``` + +```ts type-equiv +type PostToolDecision = + | { kind: 'accept'; content?: ContentBlock[]; additionalContext?: HookContext } + | { kind: 'block'; feedback: ContentBlock[]; additionalContext?: HookContext } +``` + +调用 `next()` 走默认路径,或返回 decision 以短路。Pre-policy 可以 deny 或 ask;只有 `allowed-once` 才继续执行,而 non-grant、缺少审批通道或服务、或无 agent 的请求都会变为 denial。守卫仍可施加最终 denial。参数不可被改写,因为历史记录、审计、UI 和执行必须一致。 + +Post-policy 可以替换 content;block 会变为包含其纠正反馈的 `isError` 结果。`tools/result` 在归一化后接收冻结的执行和结果;观察者无法转换它们,观察者的失败被隔离。未知工具和抛出异常的工具都变为结构化错误(`ToolNotFoundError` 映射为 `UNKNOWN_TOOL`),调用失败但不终止当前轮次。 + +## 结构化输出 schema 子集 + +调用方用来向 subagent 要求机器可读结果的词汇(`SubagentStartRequest.outputSchema`,见 [subagent.md](subagent.md#the-start-request)),或工作流 `agent()` 调用使用的词汇。它有意**不是**完整的 JSON Schema:schema 原样传递给模型作为强制工具的 `parameters`,产出的值由客户端的 `validateStructuredValue` 校验——因此每个被接受的关键字都必须是校验器实际执行的,`assertSupportedOutputSchema` 会大声拒绝其他任何内容(`OutputSchemaError`,列出所有违规)。两个遍历器都只处理自有可枚举属性(JSON 不携带其他东西),并拒绝会有损序列化的非普通对象(`Date`、`Map`)。 + +```ts type-equiv +type StructuredScalar = string | number | boolean | null +``` + +```ts type-equiv +type StructuredSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null' +``` + +```ts type-equiv +interface StructuredSchemaNode { + type: StructuredSchemaType + properties?: Record + required?: string[] + additionalProperties?: boolean + items?: StructuredSchemaNode + enum?: StructuredScalar[] + const?: StructuredScalar + description?: string + title?: string + default?: unknown + examples?: unknown +} +``` + +schema 是一个以 object 为根的节点(`enum`/`const` 仅限标量;`description`/`title`/`default`/`examples` 是注解,允许但忽略,仍要求为 JSON 数据——它们随协议传输): + +```ts type-equiv +type StructuredOutputSchema = StructuredSchemaNode & { type: 'object' } +``` + +## 工具展示 UI 词汇 + +工具希望其调用在 UI 中如何呈现(编辑器工具调用卡片、CLI 日志行),提供方无关,使工具无需依赖任何客户端协议即可描述自身。`presentCall`/`presentResult` 返回一个 **`card` 标签的渲染意图**——一个可辨识联合类型,UI 桥接层据此分发: + +- `ToolCallView`(pending 状态):`{ card: 'generic', title, kind?, rawInput?, content?, locations? }`(默认卡片;`locations` 是 `{ path, line? }[]`,表示该调用读取/修改的文件,供编辑器跟随定位)、`{ card: 'terminal', title, description?, cwd? }`(shell 命令 → 终端卡片)、或 `{ card: 'diff', title, diffs, locations? }`(文件创建/修改 → 内联 diff 卡片;`diffs` 是 `{ path, oldText, newText }[]`,`oldText: null` 表示新文件)。 +- `ToolResultView`(completed 状态):`{ card: 'generic', title?, content? }`、`{ card: 'terminal', title?, output?, exitCode?, signal? }`(捕获的运行输出 + 退出状态;有能力的 UI 显示退出状态标签,无能力的 UI 获得桥接层从 `output` 派生的围栏 ` ```console ` 回退)、或 `{ card: 'diff', title?, diffs }`(已完成的文件变更 → 要展示的变更,通常是从 before/after 内容计算出带上下文行的已应用 hunk,或在没有 before-image 时的整文件 diff——如文件创建。`tool_call_update` 的 content 会**替换**调用的 content,因此变更工具即使与调用时的片段重复也要返回此值,以防结果文本覆盖 diff)。 + +`ToolCallKind`(`'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other'`)为 generic 卡片选择图标。`FileLocation`(`{ path, line? }`)和 `FileDiff`(`{ path, oldText, newText }`)是共享的文件卡片词汇。该设计固定于[渲染意图联合类型 RFC](../rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md);ACP(Agent Client Protocol)桥接层将 `diff` 卡片映射为 `{ type: 'diff' }` 内容块,将 `terminal` 卡片映射为 `_meta` 终端约定,并将文件卡片的标题相对于会话 cwd 做相对化处理。 + +完整的展示字段文档见 [`packages/core/tools/src/presentation.ts`](../../packages/core/tools/src/presentation.ts)。bash 工具自身的 schema(`bash`/`bash_output`/`bash_kill`)及其驱动的执行器见 [bash.md](bash.md)。 diff --git a/docs/core-data-structures/user-interaction.i18n.yaml b/docs/core-data-structures/user-interaction.i18n.yaml new file mode 100644 index 0000000000..f80530393b --- /dev/null +++ b/docs/core-data-structures/user-interaction.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +user-interaction.md: 47e0e26cd0a5201185dd252a882496456a9c3edd +user-interaction.zh.md: bddcc991fd48d475f06912b9134b331d623b80d2 diff --git a/docs/core-data-structures/user-interaction.md b/docs/core-data-structures/user-interaction.md index 4edc415039..47e0e26cd0 100644 --- a/docs/core-data-structures/user-interaction.md +++ b/docs/core-data-structures/user-interaction.md @@ -1,5 +1,7 @@ # User Interaction +English | [中文](user-interaction.zh.md) + The user-interaction seam of [dsh-user-interaction](../../packages/ui/user-interaction). It is the provider-neutral vocabulary a tool or permission plugin uses when it needs the human to answer before the agent can continue. UI surfaces provide the active `UserInteractionProvider`: `dsh-stdio-demo` renders questions in readline, and `dsh-acp` maps them to ACP form elicitations. Source: [`packages/ui/user-interaction/src/index.ts`](../../packages/ui/user-interaction/src/index.ts) diff --git a/docs/core-data-structures/user-interaction.zh.md b/docs/core-data-structures/user-interaction.zh.md new file mode 100644 index 0000000000..bddcc991fd --- /dev/null +++ b/docs/core-data-structures/user-interaction.zh.md @@ -0,0 +1,99 @@ +# 用户交互 + +[English](user-interaction.md) | 中文 + +[dsh-user-interaction](../../packages/ui/user-interaction) 的用户交互 seam。它是工具或权限插件在需要人类回答后 agent 才能继续时所使用的提供方无关词汇。UI 表面提供活跃的 `UserInteractionProvider`:`dsh-stdio-demo` 在 readline 中渲染问题,`dsh-acp` 将其映射为 ACP 表单引出。 + +源码:[`packages/ui/user-interaction/src/index.ts`](../../packages/ui/user-interaction/src/index.ts) + +## 问题选项 + +`AskUserQuestionOption` 是可选择项的形状。`label` 是面向用户的选项文字,同时也是模型侧选中后的值;`description` 是可选的 UI 辅助文字。 + +```ts type-equiv +interface AskUserQuestionOption { + /** User-facing label. */ + label: string + /** Optional extra context rendered by capable UIs. */ + description?: string +} +``` + +## 问题条目 + +`AskUserQuestionItem` 是请求中的一个问题。模型提供一个稳定的 `id`,回答时原样回传,使批量问题可路由。 + +```ts type-equiv +interface AskUserQuestionItem { + /** Stable model-provided question id, echoed in the answer. */ + id: string + /** The question to display. */ + question: string + /** Optional short heading/group label. */ + header?: string + /** Optional choices the UI can render as a menu. */ + options?: AskUserQuestionOption[] + /** Whether more than one option may be selected. Defaults to single-select. */ + multiSelect?: boolean +} +``` + +## 提问请求 + +`AskUserQuestionRequest` 是跨包请求。`questions` 是数组,这样 UI 可以在一次流程中展示相关问题,同时为每个回答保留稳定的 id。 + +```ts type-equiv +interface AskUserQuestionRequest { + /** Questions to display. */ + questions: AskUserQuestionItem[] + /** Calling agent, when the request came from an agent tool call. */ + agent?: Agent + /** Abort signal for the owning tool/step. */ + signal?: AbortSignal +} +``` + +## 回答 + +提供方为每个已回答的问题 id 返回一条回答。`selected` 包含选中的选项 label,`custom` 在用户输入了自由文本"其他"答案时携带该内容。当 `custom` 存在时,`selected` 为空;自定义文本是对选中项的覆盖,而非补充。 + +```ts type-equiv +interface AskUserQuestionAnswerItem { + /** The answered question id. */ + id: string + /** Selected option labels. Empty when the answer is purely custom text. */ + selected: string[] + /** Optional free-text "Other" answer. */ + custom?: string +} +``` + +```ts type-equiv +interface AskUserQuestionAnswer { + /** Structured answers keyed by question id. */ + answers: AskUserQuestionAnswerItem[] +} +``` + +## 提供方 + +同一上下文中只能有一个活跃的提供方。提供方注册与 effect 绑定,因此 HMR(热模块替换)或 dispose(资源释放)会移除活跃的 UI。 + +```ts type-equiv +interface UserInteractionProvider { + ask(request: AskUserQuestionRequest): Promise +} +``` + +## 错误 + +`UserInteractionError` 继承 `HarnessError`,因此 `ctx.tools.execute()` 会为面向模型的工具失败保留 `{ name, code }`,例如 `EMPTY_QUESTIONS`、`NO_PROVIDER`、`ASK_ABORTED` 或 ACP 侧的取消。 + +```ts type-equiv +class UserInteractionError extends HarnessError { + constructor(message: string, code: string, options?: ErrorOptions) { + super(message, code, options) + this.name = 'UserInteractionError' + } +} +``` diff --git a/docs/core-data-structures/web.i18n.yaml b/docs/core-data-structures/web.i18n.yaml new file mode 100644 index 0000000000..b5b4fd1f29 --- /dev/null +++ b/docs/core-data-structures/web.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +web.md: 74db18835df02ef233f78ad7fbfec5d9b26d58e6 +web.zh.md: da8dad9dc06309b6f3108148dc39bc2b66bb5d22 diff --git a/docs/core-data-structures/web.md b/docs/core-data-structures/web.md index 9d79cd96c8..74db18835d 100644 --- a/docs/core-data-structures/web.md +++ b/docs/core-data-structures/web.md @@ -1,5 +1,7 @@ # Web Access +English | [中文](web.zh.md) + The web access seam — a [capability seam](../rfc/implemented/architecture/2026-06-24-web-capability-seam.md) that spans **two capabilities** (search and fetch) on one `ctx.web` service, split across packages: interface ([dsh-web](../../packages/web/web), `ctx.web` + the provider registries), implementations ([dsh-web-search-exa](../../packages/web/web-search-exa), [dsh-web-search-perplexity](../../packages/web/web-search-perplexity), [dsh-web-search-deepseek](../../packages/web/web-search-deepseek), [dsh-web-fetch-local](../../packages/web/web-fetch-local)), and consumer ([dsh-tool-web](../../packages/web/tool-web), the `web_search`/`web_fetch` tool schemas). Web is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). A search-provider swap does not change how the model asks for a query, and a fetch-implementation swap does not change how the model asks for a URL. Source: [`packages/web/web/src/types.ts`](../../packages/web/web/src/types.ts) diff --git a/docs/core-data-structures/web.zh.md b/docs/core-data-structures/web.zh.md new file mode 100644 index 0000000000..da8dad9dc0 --- /dev/null +++ b/docs/core-data-structures/web.zh.md @@ -0,0 +1,86 @@ +# Web 访问 + +[English](web.md) | 中文 + +Web 访问 seam 是一个[能力 seam](../rfc/implemented/architecture/2026-06-24-web-capability-seam.md),在单一 `ctx.web` 服务上横跨**两种能力**(搜索与抓取),拆分到多个包(package)中:接口([dsh-web](../../packages/web/web),`ctx.web` + 提供方注册表)、实现([dsh-web-search-exa](../../packages/web/web-search-exa)、[dsh-web-search-perplexity](../../packages/web/web-search-perplexity)、[dsh-web-search-deepseek](../../packages/web/web-search-deepseek)、[dsh-web-fetch-local](../../packages/web/web-fetch-local)),以及消费方([dsh-tool-web](../../packages/web/tool-web),`web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop 主干,因此其词汇定义在此,而非 [core.md](core.md)。更换搜索提供方不会改变模型发起查询的方式,更换抓取实现也不会改变模型请求 URL 的方式。 + +源码:[`packages/web/web/src/types.ts`](../../packages/web/web/src/types.ts) + +## 为何两种能力共用一个 seam + +搜索与抓取既不共享请求 schema,也不共享业务逻辑,但它们被有意设计为同一个 `ctx.web` 中间层:一个提供方选择策略的归属者、一套 abort/error 词汇、一个面向产品的「此 harness 如何访问 Web」配置界面。代价是服务上出现了并行的 `searchX`/`fetchX` 方法对;这种并行是有意为之,而非遗漏的提取。提供方注册的是**能力**(`WebSearchProvider` 或 `WebFetchProvider`),而非工具;面向模型的名称、schema、prompt 引导与展示全部集中在唯一的消费方 `dsh-tool-web` 中。 + +## 搜索请求与结果 + +面向模型的工具参数仅为一个 `query`;`maxResults` 是消费方持有的上限(`dsh-tool-web` 的 `searchMaxResults` 配置,默认 `8`),通过 seam 传递并在返回时强制执行:如果提供方返回的结果超量,seam 会截断 `sources[]` 并设置 `truncated`。 + +```ts type-equiv +interface WebSearchRequest { + readonly query: string + /** + * Upper bound on returned sources; the seam truncates to it. Omitted = no + * bound. `dsh-tool-web` always sets it. + */ + readonly maxResults?: number +} +``` + +```ts type-equiv +interface WebSearchResult { + readonly content?: string + readonly sources: readonly WebSearchSource[] + readonly truncated: boolean +} +``` + +`content` 是提供方可选生成的回答文本(Exa 和 DeepSeek 不返回;Perplexity 返回生成式回答)。`sources[]` 是可移植的引用界面。每条 source 必有 `url`;`title`/`snippet`/`publishedAt` 可选,因为并非所有提供方都返回它们:Perplexity 的引用可能只有 URL,强迫适配器编造其余字段会让 seam 说谎。`dsh-tool-web` 渲染时使用 `title ?? hostname(url)`。 + +```ts type-equiv +interface WebSearchSource { + readonly url: string + readonly title?: string + readonly snippet?: string + readonly publishedAt?: string +} +``` + +## 抓取请求与结果 + +```ts type-equiv +interface WebFetchRequest { + readonly url: string +} +``` + +HTTP 状态码是被抓取资源状态的一部分,不自动视为失败:成功的网络抓取返回 `404`/`500` 时,结果仍是一个带状态码和有界解码 body 的 `WebFetchResult`。`url` 是经过允许的重定向后的最终 URL。`WebError` 保留给无法安全获取或表示资源的失败情形。 + +```ts type-equiv +interface WebFetchResult { + readonly url: string + readonly statusCode: number + readonly body: WebFetchBody + readonly truncated: boolean +} +``` + +`WebFetchBody` 是 `dsh-web` 持有的**封闭**可辨识联合类型(不是可合并扩展的 map):提供方解码 kind,`dsh-tool-web` 渲染它,因此新增一个 kind 是跨已知包的协调变更,而非插件扩展。消费方对 `kind` 做 `switch` 并以 `default: assertNever(...)` 结尾,因此新增 kind 会在每个消费方处破坏编译直到被处理。即使当前各分支字段相同,每个分支仍保持独立的对象字面量,为将来的分支特有字段留出空间(例如未来 `pdf` body 的 `pageCount`)。 + +```ts type-equiv +type WebFetchBody = + | { readonly kind: 'html'; readonly content: string } + | { readonly kind: 'text'; readonly content: string } +``` + +## 提供方可用性 + +提供方的 `available(): boolean` 是一个廉价的**本地**检查(凭证是否存在、配置是否可解析),**禁止发起网络调用**。它是执行时选择的输入,而非健康检查系统:`search()`/`fetch()` 读取它来选出可用的提供方,选择失败以结构化的 `WebError` 呈现给调用方路由,其 code 和 message 携带可分支的细节(缺失的 id 或歧义的候选集)。 + +选择从不依赖注册顺序、配置顺序或 HMR 顺序:一项能力要么有显式的提供方 id(配置 `searchProvider`/`fetchProvider`,或喂入同一字段的对应环境变量),要么在恰好只有一个可用提供方注册时自动选择;多个可用提供方且未配置 id 时为 `WEB_PROVIDER_AMBIGUOUS`,而非先注册先赢。 + +## 错误 + +`WebError extends HarnessError`([core.md](core.md) 错误分类体系),带有 `code: string`(开放式,与其他 seam 的错误一致:`LlmError`、`SubagentError`),而非封闭联合类型:提供方可以在不修改 `dsh-web` 的情况下抛出自己的 code,消费方必须容忍未知 code。code 按归属者划分。seam 中性的 code 由 `WebService` 选择逻辑和共享契约抛出:`WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE`、`WEB_PROVIDER_AMBIGUOUS`、`WEB_DUPLICATE_PROVIDER`(注册时的编程错误,类似 `LlmService` 的 `DUPLICATE_ADAPTER`)、`WEB_ABORTED`,以及 `WEB_PROVIDER_ERROR`(提供方自身失败通过 seam 暴露的兜底 code,包括网络/传输失败:DNS、连接被拒、TLS)。抓取传输层 code 由 `dsh-web-fetch-local` 实现持有,不同的抓取后端不必抛出它们:`WEB_INVALID_URL`、`WEB_BLOCKED_URL`、`WEB_REDIRECT_BLOCKED`、`WEB_FETCH_TOO_LARGE`、`WEB_FETCH_TIMEOUT`、`WEB_UNSUPPORTED_CONTENT_TYPE`。 + +## 服务 + +`WebService` 注册搜索与抓取提供方,以 `WEB_DUPLICATE_PROVIDER` 拒绝重复 id,并在执行时以结构化的选择错误解析提供方。本地抓取后端仅接受 HTTP(S)、拒绝凭证、限制重定向次数、字节数、字符数与时间、对每一跳同源重定向重新校验,并解码 body;展示由工具负责。私有网络阻断尚未实现,因此不要在能触及敏感内部目标的环境中启用 `web_fetch`。 diff --git a/docs/core-data-structures/workflow.i18n.yaml b/docs/core-data-structures/workflow.i18n.yaml new file mode 100644 index 0000000000..b7e831aac8 --- /dev/null +++ b/docs/core-data-structures/workflow.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +workflow.md: 1571723c172fe851e89550e4ed8588ddb14088a0 +workflow.zh.md: 9fa3b4eea4efdcdb8e594c3558e30846aea0af46 diff --git a/docs/core-data-structures/workflow.md b/docs/core-data-structures/workflow.md index 4354105e70..1571723c17 100644 --- a/docs/core-data-structures/workflow.md +++ b/docs/core-data-structures/workflow.md @@ -1,5 +1,7 @@ # Workflow +English | [中文](workflow.zh.md) + The workflow seam — an agent running a model-written orchestration SCRIPT that fans out subagents. Like [subagent](subagent.md) it is **one optional capability**, not part of the agent-loop spine, so its vocabulary lives here rather than in [core.md](core.md). Unlike the subagent registry it takes the bash shape: ONE engine implementation per context provides `ctx.workflows`; there is no named-provider registry (a second engine is a plugin swap, not a co-resident). Interface: [dsh-workflow](../../packages/workflow/workflow) (`ctx.workflows` + the vocabulary below). The implementation is [dsh-workflow-workerthread](../../packages/workflow/workflow-workerthread) (a `node:worker_threads` engine — one worker per run, the script's vm context inside it); the model-facing consumer is [dsh-tool-workflow](../../packages/workflow/tool-workflow). The proposal and rationale: [the dynamic-workflows RFC](../rfc/implemented/feature/2026-07-05-dynamic-workflows.md). diff --git a/docs/core-data-structures/workflow.zh.md b/docs/core-data-structures/workflow.zh.md new file mode 100644 index 0000000000..9fa3b4eea4 --- /dev/null +++ b/docs/core-data-structures/workflow.zh.md @@ -0,0 +1,71 @@ +# 工作流 + +[English](workflow.md) | 中文 + +工作流 seam:由 agent(智能体)运行一段模型编写的编排脚本(SCRIPT),向外扇出 subagent。与 [subagent](subagent.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。与 subagent 注册表不同,它采用 bash 形态:每个上下文只有一个引擎实现提供 `ctx.workflows`;没有命名提供方注册表(第二个引擎是插件替换,而非共存)。 + +接口:[dsh-workflow](../../packages/workflow/workflow)(`ctx.workflows` + 下文词汇)。实现为 [dsh-workflow-workerthread](../../packages/workflow/workflow-workerthread)(基于 `node:worker_threads` 的引擎:每次运行一个 worker,脚本的 vm 上下文在其中执行);面向模型的消费方是 [dsh-tool-workflow](../../packages/workflow/tool-workflow)。提案与设计理由见[动态工作流 RFC](../rfc/implemented/feature/2026-07-05-dynamic-workflows.md)。 + +源码:[`packages/workflow/workflow/src/types.ts`](../../packages/workflow/workflow/src/types.ts) + +## 启动请求 + +调用方启动一次运行时发出的请求。工具层根据模型的 `{ script, meta, args }` 调用加上发起调用的 agent 构建此请求;`meta` 和 `args` 是纯 JSON 数据(引擎在任何代码运行之前对 `meta` 做形状校验,不通过则大声拒绝——永远不会为了获取 meta 而执行脚本文本)。`parent` 是必需的:脚本 spawn 的每个子 agent 都归属于它(cwd、血统和深度通过 [subagent seam](subagent.md) 流转)。 + +```ts type-equiv +interface WorkflowStartRequest { + script: string + meta: WorkflowMeta + args?: unknown + parent: Agent + signal?: AbortSignal +} +``` + +## 工作流的身份标识:`WorkflowMeta` + +作为数据附在启动请求上的身份块(工具的 `meta` 参数;字段词汇与 Claude Code 动态工作流的 meta 块一致)。`phases` 仅为进度词汇:`phase()` 调用与标题匹配供观察者使用;不暗示任何执行结构。 + +```ts type-equiv +interface WorkflowMeta { + name: string + description: string + whenToUse?: string + phases?: WorkflowPhase[] +} +``` + +## 终态结果:`WorkflowResult` + +一次运行的结果,由 `WorkflowRun.result` resolve。`value` 是脚本的物化返回值——纯宿主域 JSON 数据(脚本无返回值时为 `null`)——仅在 `completed` 时有意义。`stopReason` 是一个封闭联合类型(引擎拥有;消费方可穷举):`completed` | `cancelled` | `error`。非 `completed` 的原因在 `error` 中携带失败信息,消费方将其映射为 `isError` 工具结果,而非把部分输出当作成功上报。 + +```ts type-equiv +interface WorkflowResult { + value: unknown + stopReason: WorkflowStopReason + error?: string + agentsStarted: number +} +``` + +## 活跃运行:`WorkflowRun` + +脚本执行期间消费方持有的句柄。消费方 await `result`,可在运行中途 `cancel`,且必须在每条路径上调用 `dispose`。`result` 不会 reject:脚本失败以 `stopReason: 'error'` resolve;一旦运行被取消,即使脚本本身永不 settle,它也会在引擎的有界宽限期内 settle(引擎强制以 `cancelled` settle;worker-thread 引擎随后终止脚本的 worker),因此消费方 await `result` 不会在取消后永远卡住。`dispose()` = cancel + 有界 settle + 子 agent 静默;它不会因脚本卡死而挂起。 + +```ts type-equiv +interface WorkflowRun { + readonly id: WorkflowRunId + readonly meta: WorkflowMeta + readonly result: Promise + cancel(reason?: string): void + dispose(): Promise +} +``` + +## 失败纪律:`WorkflowError.fatal` + +脚本内部的钩子误用——错误参数、未知或延迟的 `agent()` 选项、超出[结构化输出子集](../../packages/core/tools/README.md)的 schema、触发的上限、seam 启动失败、取消——会抛出 `fatal: true` 的 `WorkflowError`。`parallel()`/`pipeline()` 组合器对 fatal 错误执行重新抛出,而非将该项映射为 `null`:一个拼写错误的选项必须大声杀死脚本,绝不能消融为看似普通子 agent 失败的东西。逐项的 `null` 保留给子运行失败(非 `completed` 的 stop reason)和阶段内的普通脚本错误。 + +## 事件 + +`workflow/*` 事件(`workflow/start`、`workflow/phase`、`workflow/log`、`workflow/agent-start`、`workflow/agent-end`、`workflow/end`——见[事件目录](../cordis-catalog/events.md))是**仅供观察**的 emit,携带数据快照:每个 payload 以 `WorkflowRunInfo`(id + meta)开头,从不暴露活跃的 `WorkflowRun`,因此订阅者无法获得 `cancel`/`dispose`;`workflow/end` 刻意省略 result value(观察结果的监听器不得收到调用方 result 的可变别名)。每次 emit 对每个监听器隔离:抛异常的订阅者被记录但不传播,不会饿死其后注册的监听器;每个监听器收到自己的 payload 克隆,因此修改它既不会损坏引擎也不会影响其他监听器。这种隔离与 `subagent/start`/`subagent/end` 一致。 diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml b/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml new file mode 100644 index 0000000000..9e6c34072b --- /dev/null +++ b/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +0001-acp-default-export-drops-inject.md: 6a71d8d7ef72e3110a99774b180f3de7115ef622 +0001-acp-default-export-drops-inject.zh.md: 12bb3501a56c3cfef8f7a1b0d773be62db8e09ca diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.md b/docs/postmortem/0001-acp-default-export-drops-inject.md index e024f4d698..6a71d8d7ef 100644 --- a/docs/postmortem/0001-acp-default-export-drops-inject.md +++ b/docs/postmortem/0001-acp-default-export-drops-inject.md @@ -1,5 +1,7 @@ # Post-mortem 0001: ACP server crashed on connect — `export default` dropped the plugin's `inject` +English | [中文](0001-acp-default-export-drops-inject.zh.md) + Status: resolved (fix in PR #41 `feat/acp-2-bridge`) ## Executive summary diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.zh.md b/docs/postmortem/0001-acp-default-export-drops-inject.zh.md new file mode 100644 index 0000000000..12bb3501a5 --- /dev/null +++ b/docs/postmortem/0001-acp-default-export-drops-inject.zh.md @@ -0,0 +1,113 @@ +# 事后分析 0001:ACP 服务器在连接时崩溃——`export default` 丢弃了插件的 `inject` + +[English](0001-acp-default-export-drops-inject.md) | 中文 + +Status: resolved (fix in PR #41 `feat/acp-2-bridge`) + +## 摘要 + +两个集成错误在单元测试全绿的情况下击溃了 ACP:一个 default export 导致 Loader 丢弃 `inject`,一个经过 traceable 代理的可选服务查找在 shadow 边界上失败。手动挂载的测试绕过了这两条路径。修复后新增了无需 API key 的真实 Loader 覆盖,以及关于插件导出和可选服务访问的包(package)规则。 + +## 概述 + +ACP 服务器(`examples/acp-agent`、`@deepseek-ai/dsh-acp`)在真实编辑器(Zed)连接的瞬间崩溃:第一个 `session/new` 请求返回 `Internal error: cannot get property "agents" without inject`,`session/load` 对 `sessionPersistence` 返回相同错误。尽管有 178 个绿色单元测试和 100% 行覆盖率,bridge 在生产环境中完全无法工作。两个独立的 bug 隐藏在同一个错误字符串背后,测试套件因同一个原因漏掉了二者:每个测试都通过一条不会触及插件实际加载方式或服务实际解析方式的路径来挂载插件。 + +## 影响 + +ACP 服务器无法创建或加载任何一个会话——这正是编辑器最先调用的两个 RPC。任何将 agent 接入 Zed 的人都会立即遇到硬性失败。无数据丢失(崩溃前没有持久化任何内容);代价完全是「功能不可用」加上两次定位原因的调试时间。 + +## 时间线 + +- Bridge(RFC 010)带着完整的单元测试套件(编解码、内存传输、基于属性的协议形状测试、失败路径、HMR(热模块替换))、一个需要 key 的真实 API e2e 测试,以及一个无需 key 的 stdout 纯净性 e2e 测试一起落地。全部绿色,100% 覆盖率。 +- 一次真实的 Zed 会话立即在 `session/new` 上失败,报错 `cannot get property "agents" without inject`。 +- 调查最初追踪的是 Cordis「traceable/shadow」理论(合理,且机制确实存在——见 Bug #2),随后在 vendor 的 `reflect.ts` 中对实际 fiber 遍历做了插桩,并运行了真实子进程。trace 显示 throw 发生在 `apply()` 第 179 行、**插件加载时**,位于 ROOT fiber 且没有 shadow——推翻了 shadow 理论对 `session/new` 的解释。 +- 找到根因 #1:一行多余的 `export default apply`。移除后 `session/new` 修复。 +- 移除后暴露了 Bug #2:`session/load` 仍然在 `sessionPersistence` 上抛出——这是一个真正不同的机制(shadow 遍历),通过隔离修复并重新运行真实子进程得到确认。 + +## 根因 #1——`export default apply` 丢弃了插件的 `inject`(导致 `session/new` 崩溃) + +`packages/ui/acp/src/index.ts` 是一个*命名空间插件*:它将 `name`、`inject`、`Config` 和 `apply` 作为独立的命名导出——与仓库中其他所有插件(`invariants`、`llm-deepseek`、`tool-bash`、`stdio-chat` 等)形状相同。但它*还*多了一行其他插件都没有的代码: + +```ts ignore-check +export const name = 'acp' +export const inject = ['agents', 'sessions', 'sessionPersistence'] +export function apply(ctx: Context, config: AcpConfig): void { /* … */ } +// … +export default apply // ← the bug +``` + +当插件从 `cordis.yml` 加载时,Cordis Loader 通过 `Loader.unwrapExports`(`vendor/loader/src/index.ts`)对导入的模块做规范化处理: + +```ts ignore-check +unwrapExports(exports: any) { + if (isNullable(exports)) return exports + exports = exports.default ?? exports // ← prefers `.default` + if (!exports.__esModule) return exports + return exports.default ?? exports +} +``` + +存在 default export 时,`exports.default ?? exports` 解析为**裸 `apply` 函数**。裸函数没有 `inject`、没有 `name`、没有 `Config` 属性——这些作为*兄弟*命名导出存在于模块命名空间上,而 unwrap 到 `.default` 把命名空间整个丢弃了。Loader 随后基于一个空的 `inject` 构建了插件的 fiber。 + +因此 `apply` 在一个**没有注入任何服务**的 fiber 中运行。第一行 `const agents = ctx.agents` 遍历 fiber 树(ROOT → Include → Loader → ROOT),在所有 fiber 的 store 中都找不到 `agents`,到达根 fiber(`runtime === null`)后抛出 `cannot get property "agents" without inject`。崩溃发生在*加载时*,而非后续的请求处理器中——请求只是恰好触发了加载。 + +**修复:**删除 `export default apply`。Loader 随后使用模块命名空间,正确识别 `inject`/`name`/`Config`,`apply` 在一个真正授予了声明服务的 fiber 中运行。 + +## 根因 #2——可选服务的属性读取在 traceable shadow 中触发 inject 守卫(导致 `session/load` 崩溃) + +修复 #1 后,`session/new` 正常工作,但 `session/load` 仍然抛出 `cannot get property "sessionPersistence" without inject`。这次*确实*是 Cordis 的 traceable/shadow 机制,值得精确理解。 + +`session/load` 调用 `agents.resume(...)`,后者委托给 `AgentLoop.resume()`,其中读取了 `this.ctx.sessionPersistence`。`AgentLoop` 的 `static inject` 故意**不**包含 `sessionPersistence`——注入它会导致非持久化的演示永远挂起,等待一个永远不会加载的后端。该服务由一个独立的兄弟插件/fiber 提供,按需读取。 + +Cordis 中的服务访问通过上下文代理(`vendor/cordis/src/reflect.ts`)进行。当通过从外部 fiber 获取的 *traceable 代理*调用服务方法时(此处:bridge fiber 调用 `ctx.agents.resume`,注册表返回 `this.factory`——即 `AgentLoop`——被重新包装为绑定到调用方的新 traceable 代理),`createShadowMethod`(`vendor/cordis/src/utils.ts`)将 `this` 重新绑定到一个 *shadow* 对象,其 `ctx` 携带 `[symbols.shadow]` 指向 `AgentLoop` 自身的构造上下文。在 `resume` 内部,`this.ctx.sessionPersistence` 的解析从 shadow 的 fiber 开始遍历: + +```ts ignore-check +// reflect.ts get handler +let fiber = (ctx[symbols.shadow] as Context ?? ctx).fiber // ← starts at AgentLoop's fiber +while (true) { + const impl = fiber.store?.[prop] + if (impl) return getTraceable(ctx, impl.value) + if (prop in fiber.inject) { /* inactive-context error */ } + if (!fiber.runtime) throw error // ← reached root, throw + if (fiber.parent[symbols.isolate][prop] !== key) throw error + fiber = fiber.parent.fiber // ← ancestor-only +} +``` + +遍历**只走祖先方向**。`sessionPersistence` 既不在 `AgentLoop` 的 fiber store 中(不在其 `static inject` 里),也不在通往根的任何祖先上(它在一个*兄弟*分支上),因此遍历到达根 fiber 后抛出。 + +为什么内存中的 `AgentLoop` resume 测试没有捕获到这个问题?因为它们从测试代码中直接调用 `ctx.agents.resume(...)`——*不在任何插件 fiber 内*。此时 `ctx.fiber.runtime` 为 `null`,代理处理器走了一条提前退出的路径: + +```ts ignore-check +if (!ctx.fiber.runtime) return ctx.reflect.get(prop, false) // ← direct global-store lookup, no fiber walk +``` + +`ctx.reflect.get(name, false)` 是基于 isolate symbol 的全局服务 store 直接查找——完全忽略 fiber 拓扑,能找到服务。因此从顶层测试读取正常;从真实插件 fiber 内部、经由 shadow 到达时则抛出。bridge 恰好是后者。 + +**修复:**使用 `ctx.get('sessionPersistence')` 读取可选服务,该方法使用全局 isolate-keyed store,同时保留活跃状态检查。对于插件声明注入集中的服务,直接属性读取仍然适用。 + +## 为什么所有测试都漏掉了(真正的失败) + +两个 bug 共享同一个流程缺口:**没有任何测试通过插件的真实加载路径或真实调用拓扑来运行它。** + +- 内存 harness 通过手动构建插件对象来挂载 bridge:`ctx.plugin({ name, inject, apply })`。这手动提供了 `inject`,因此永远无法复现 Bug #1——`unwrapExports` 只被 *Loader* 调用,`ctx.plugin` 从不调用它。即使 `ctx.plugin(NamespaceImport)` 也无法捕获此问题。 +- 同一个 harness 把所有东西平铺挂载在一个根上下文上,因此从中触达的 `AgentLoop` resume 要么在顶层运行(`!runtime` 旁路),要么通过一个 origin 仍在根上解析的 shadow——掩盖了 Bug #2 的祖先遍历失败。 +- 唯一的无 key e2e 发送 `initialize` 并检查 stdout 纯净性。`initialize` 从不触达 factory,因此安然通过两个 bug。 +- 唯一驱动 `session/new`/`session/load` 的测试需要 key 才能运行,CI(无 key)跳过了它——而本地它之所以「通过」,只是因为一个陈旧的已构建 `lib/`(包含旧代码)恰好满足了模块解析。 + +100% 行覆盖率自始至终满足。覆盖率证明代码行*被执行过*;它不能说明功能是否*以交付的方式*工作。 + +## 新增的防护措施 + +- **移除 `export default apply`**(`packages/ui/acp/src/index.ts`)——Bug #1 的修复。 +- **`AgentLoop.resume` 使用 `this.ctx.get('sessionPersistence')`**(`packages/core/agent-loop/src/index.ts`)——Bug #2 的修复,附注释说明 shadow 遍历陷阱。 +- **无需 key 的 `session/new` e2e,通过真实 stdio 运行**(`examples/acp-agent/tests/acp.e2e.ts`):以子进程方式通过真实 Loader 启动示例,并断言 `session/new` 正常返回。无需 API key 即可在 Bug #1 上大声失败。已验证恢复 `export default apply` 时测试失败。 +- **e2e spawn 中设置 `TSX_TSCONFIG_PATH`**:子进程从临时 cwd 运行,tsx 无法通过向上搜索找到仓库根的 tsconfig `paths` 映射——因此 dsh-* 的导入静默回退到已构建的 `lib/`。将 tsx 指向仓库 tsconfig 使解析不依赖 cwd,确保测试运行的是*源码*而非可能陈旧的构建产物。 +- **[docs/testing.md](../testing.md) 规则**:「测试真实入口路径」,行覆盖率不等于行为覆盖率——将此教训编纂为所有未来插件的规则。 + +## 教训 + +- 命名空间插件与 default export 在 Cordis Loader 下互斥。选择命名空间形式(`name`/`inject`/`Config`/`apply`),不要添加 `export default`——`unwrapExports` 会丢弃命名空间。 +- 对于插件按需读取但**不**声明在 `static inject` 中的服务,使用 `ctx.get(name)`,绝不使用 `ctx.`。属性代理通过只走祖先方向的 fiber 遍历解析,经由外部 shadow 时会失败;`ctx.get(name)` 是拓扑无关的查找(且默认严格——后端未激活时返回 `undefined`,而非在 teardown 过程中把半拆除的实例交出去)。 +- 手动构造插件的测试无法验证插件的加载方式。至少一个测试必须端到端地驱动真实的 Loader/export 路径。当核心操作不调用模型时,该测试无需 API key——因此它属于 CI,而非 key 门控之后。 +- 相信 trace,不要相信理论。优雅的 shadow 解释是真实的,但它是*第二个* bug;*第一个*是一行导出错误,在数小时合理但错误的推理之后,一条 fiber 遍历的 `console.error` 几分钟就找到了它。 diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml new file mode 100644 index 0000000000..f59f7794de --- /dev/null +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +0002-js-expression-disabled-filesystem-tools.md: 43e57a6bd1b68f38c47eeda3c3abb8455024b350 +0002-js-expression-disabled-filesystem-tools.zh.md: e54431b7f4061bb4bdc22a37f0651697c6247dda diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.md b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.md index 191c13459c..43e57a6bd1 100644 --- a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.md +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.md @@ -1,5 +1,7 @@ # Post-mortem 0002: Filesystem snapshot tools were permanently disabled +English | [中文](0002-js-expression-disabled-filesystem-tools.zh.md) + Status: resolved ## Executive summary diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md new file mode 100644 index 0000000000..e54431b7f4 --- /dev/null +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md @@ -0,0 +1,47 @@ +# 事后分析 0002:文件系统快照工具被永久禁用 + +[English](0002-js-expression-disabled-filesystem-tools.md) | 中文 + +Status: resolved + +## 摘要 + +ACP 示例试图通过 `disabled: !!js ...` 有条件地启用文件系统插件,但 Cordis 仅在插件 `config` 内部求值 JavaScript 表达式。原始的表达式对象为 truthy,因此文件系统栈始终处于禁用状态。快照刷新随后将 `UNKNOWN_TOOL` 结果作为新的 golden 接受。修复方案使用显式的文件系统 overlay,并增加了静态配置守卫和快照结果守卫。 + +## 概述 + +默认的 ACP 组合有意仅包含 bash,因为其沙箱无法约束进程内的文件系统提供方。文件系统快照场景仍需要 `read`、`write` 和 `edit`,因此这些插件被放入默认的 `cordis.yml`,并附带一个 `disabled` 表达式,意图仅在全权限启动和快照模式下启用它们。 + +Cordis Include 将每个 `!!js` 标量解析为一个表达式对象。Loader 递归地对插件的 `config` 进行了插值,但直接消费了 `disabled` 等入口元数据。因此每个文件系统入口都看到一个 truthy 对象,在所有模式下均保持禁用。 + +## 影响 + +七个文件系统场景和一个混合工作区编辑场景调用了注册表中不存在的工具。它们的结构化会话日志携带 `ToolNotFoundError`(code 为 `UNKNOWN_TOOL`),stdout 则渲染了通用的失败工具卡片。快照套件通过了,因为两个表面都与刷新后的 fixture(测试前置数据)匹配;它证明的是回归的确定性回放,而非文件系统行为的正确性。 + +实际运行的受限默认组合并未获得意外的文件系统访问。一个朴素的插值修复反而会引入该风险:权限预设在运行时更新 bash 沙箱和审批状态,但无法挂载、卸载或约束文件系统栈。 + +## 时间线 + +- PR #261 整合了 ACP 组合并刷新了文件系统快照,同时引入了条件式文件系统入口。 +- 所有单元测试、覆盖率、快照、文档、构建和 hygiene 检查均通过。 +- 对刷新后的文件系统 golden 的评审发现了通用的失败卡片和结构化的 `UNKNOWN_TOOL` 结果。 +- 一次真实的 Loader 启动确认:每个 `disabled` 值仍然是表达式对象,每个文件系统 fiber 均未注册。 + +## 根因 + +实现方假设 `!!js` 适用于整个 Loader 入口。其实际边界更窄:`Entry._resolveConfig()` 仅对 `entry.options.config` 进行插值;`Entry.disabled` 直接测试 `entry.options.disabled`,不做插值。YAML 标签在语法上合法,因此加载过程不产生任何诊断信息。 + +快照框架将任何确定性的 transcript(文本记录)视为有效行为。Header pin 验证了组合后的工具 schema,但文件系统场景共享了来自默认组合的 pin,因此未独立证明其所需工具已注册。刷新在任何语义断言拒绝缺失工具之前,就已重写了预期的 stdout 和会话日志。 + +## 新增的防护措施 + +- 文件系统场景启动 `fs.cordis.yml`:一个显式的固定全权限 overlay,配有对应的 replay 配置和独立的 request-header 类。 +- [`AGENTS.md`](../../AGENTS.md) 和 [Cordis 入门](../cordis-primer.md#loader-configuration) 明确说明 `!!js` 仅在插件 `config` 下有效,条件式组合应使用 overlay。 +- `verify-cordis-config` 解析仓库中的 Cordis YAML,拒绝 Loader 入口元数据(包括 include patch 和插入的入口)中出现表达式节点。 +- `dsh-acp-snapshot` 在新鲜运行和已提交的会话 fixture 中拒绝结构化的 `UNKNOWN_TOOL` 结果,阻止其成为被接受的 golden。 + +## 教训 + +- 语法上被接受的配置值不一定在该位置被求值;应记录并验证插值边界。 +- 快照刷新是 fixture 生产,不是正确性评审。像「已注册工具缺失」这样的语义不可能性需要独立于 golden 的断言。 +- 权限控制只应描述它实际管辖的能力。组合时的文件系统访问无法安全地跟随运行时的 bash-only 预设。 diff --git a/docs/postmortem/README.i18n.yaml b/docs/postmortem/README.i18n.yaml new file mode 100644 index 0000000000..f57d280d36 --- /dev/null +++ b/docs/postmortem/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +README.md: 4dc59e4f5e70f51c4c0baa64fbe34b213f2a7c3d +README.zh.md: 7e2d05d429b2521e7e772956b7644740d4642fac diff --git a/docs/postmortem/README.md b/docs/postmortem/README.md index 743433a827..4dc59e4f5e 100644 --- a/docs/postmortem/README.md +++ b/docs/postmortem/README.md @@ -1,5 +1,7 @@ # Post-mortems +English | [中文](README.zh.md) + Incident write-ups: a bug reached a place it shouldn't have (a real user, a merged PR, a release), and the interesting part is *why our process let it through*, not just the one-line fix. A post-mortem is NOT an [RFC](../rfc/README.md) (which records a deliberate design decision and its rejected alternatives, or proposes future work). It is a backward-looking record of a failure: what broke, the mechanism, why every safety net missed it, and the concrete guardrails added so the same class of bug fails loudly next time. diff --git a/docs/postmortem/README.zh.md b/docs/postmortem/README.zh.md new file mode 100644 index 0000000000..7e2d05d429 --- /dev/null +++ b/docs/postmortem/README.zh.md @@ -0,0 +1,16 @@ +# 事后分析 + +[English](README.md) | 中文 + +事故记录:一个 bug 到达了它不该到达的地方(真实用户、已合并的 PR(Pull Request)、已发布的版本),有意义的部分是**为什么我们的流程放过了它**,而不仅仅是那行修复。 + +事后分析不是 [RFC](../rfc/README.md)(RFC 记录的是经过深思熟虑的设计决策及其被否决的替代方案,或提出未来工作)。它是一份面向过去的失败记录:什么坏了、机制是什么、为什么每道安全网都没拦住、以及加了哪些具体护栏使同类 bug 下次能快速失败。 + +满足以下条件时写一篇:bug **隐蔽**(机制不显而易见,一位细心的工程师也得费力重新推导)、**系统性**(逃逸的原因是测试/工具/约定的缺口,而非一次性手误)、**重新发现的代价高**(它消耗了真实的调试时间,而且下次还会)。请链接该事后分析所推动建立的护栏(测试、AGENTS.md 规则、ADR)。 + +每篇事后分析以一段 **Executive summary** 开头:一段简短的文字,让忙碌的读者在三十秒内了解全貌——什么坏了、用通俗语言说的根因、为什么逃逸了、以及持久的教训——之后再展开详细的 Summary / Timeline / Root cause / Guardrails 各节。 + +| # | 标题 | +|---|---| +| [0001](0001-acp-default-export-drops-inject.md) | ACP server crashed on connect: `export default` dropped the plugin's `inject` | +| [0002](0002-js-expression-disabled-filesystem-tools.md) | Filesystem snapshot tools were permanently disabled by a literal `!!js` object | diff --git a/docs/rfc/README.i18n.yaml b/docs/rfc/README.i18n.yaml new file mode 100644 index 0000000000..5bda02fc38 --- /dev/null +++ b/docs/rfc/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +README.md: 9014579f3a98be907885332a0c815bca5c96855c +README.zh.md: b51343b35aa04830b694f560ca9ae490995dcd43 diff --git a/docs/rfc/README.md b/docs/rfc/README.md index a6fe4dbfa2..9014579f3a 100644 --- a/docs/rfc/README.md +++ b/docs/rfc/README.md @@ -1,5 +1,7 @@ # RFCs +English | [中文](README.zh.md) + One kind of design doc lives here. An **RFC** records a decision or proposal that shapes this codebase — the *why* and *what we gave up*, the parts code and docs can't carry. The full list is the generated [INDEX.md](INDEX.md); this file is the contract — where RFCs live, when to write one, and [the in-file format](#the-file-format). ## Layout and naming diff --git a/docs/rfc/README.zh.md b/docs/rfc/README.zh.md new file mode 100644 index 0000000000..b51343b35a --- /dev/null +++ b/docs/rfc/README.zh.md @@ -0,0 +1,111 @@ +# RFC + +[English](README.md) | 中文 + +这里存放一类设计文档。**RFC** 记录塑造本代码库的决策或提案——代码和文档本身无法承载的*为什么*以及*放弃了什么*。完整列表见生成的 [INDEX.md](INDEX.md);本文是契约——RFC 放在哪里、何时该写,以及[文件内格式](#the-file-format)。 + +## 布局与命名 + +每篇 RFC 有两个轴,都编码在其**路径**中——`{lifecycle}/{class}/yyyy-mm-dd-topic-title.md`: + +- **生命周期**(顶层文件夹)是 RFC 的状态,RFC 随状态变更在文件夹间移动: + - **`proposed/`**——实现前评审的提案;尚未构建(或仅部分构建)。 + - **`implemented/`**——决策已交付。文件记录做了什么决定、否决了什么,并**与实际交付的内容保持同步**:当代码后来移动了文件、重命名了包(package)或更改了键/默认值时,RFC 在同一个变更中更新以匹配(仅限事实——路径、名称、结构——不涉及决策本身)。见 [implemented/AGENTS.md](implemented/AGENTS.md)。 + - **`rejected/`**——提案经考虑后被否决。保留以备查阅,避免同一问题被反复争论。 +- **分类**(嵌套文件夹)是决策的*类型*——见下方[分类](#classification)。 + +文件名中的日期是该主题**首次提出**的时间(以 git 历史为准)。RFC 之间的交叉引用使用相对 Markdown 链接(`[topic](../../implemented/architecture/2026-…-….md)`),从不使用纯文字或编号,这样既可机械检查,也能在文件夹间移动时保持有效。 + +## 分类 + +每篇 RFC 归属于 `scripts/rfc-index.ts` 中封闭集合里的一个路径编码分类;分类门禁拒绝其他文件夹。[INDEX.md](INDEX.md) 由路径、标题和文件名日期生成,其新鲜度受门禁保护。新增分类需要同时更新规范集合与本节。见[分类 RFC](implemented/process/2026-06-20-rfc-classification.md) 与[索引生成 RFC](implemented/process/2026-07-04-generate-rfc-index-tables.md)。 + +| 分类 | 涵盖内容 | +|---|---| +| `feature` | 面向用户或模型的新能力。 | +| `bug-fix` | 修正缺陷或填补事后复盘暴露的空白。 | +| `simplification` | 在不增加能力的前提下移除代码、行为或接口面。 | +| `architecture` | 关于**交付源码**的结构性决策——包之间的关系、运行时词汇。 | +| `process` | 围绕代码的工具、政策或工作流——门禁、包管理器、vendor 化——而非运行时行为。 | +| `testing` | 测试基础设施与策略。 | + +`architecture` 与 `process` 的分界线:**architecture** 关乎我们交付的源码;**process** 关乎围绕源码的工具与工作流。(`refactor` 被刻意省略——它与 `simplification` 重叠,后者的判别标准「可观测行为是否改变」已覆盖了它。) + +## 何时该写 + +当一个决策**持久**(它塑造代码库的范围超出单个函数或包)、**有争议**(存在一个合理工程师可能选择的真实替代方案)、且**令人意外**(未来读者否则会问「为什么要这样做」)时,请写一篇 RFC。对未来大量工作的提案从 `proposed/` 开始;已做出的决策从 `implemented/` 开始。选择与决策匹配的分类文件夹(见[分类](#classification))。 + +以下情况**不要**写 RFC:机械性或局部的选择(变量名、单文件重构);已由门禁或 AGENTS.md 中的约定强制并解释的事项;代码中标记为 `TODO(...)` 的暂定决策——将其记为 TODO,待尘埃落定后再提升为 RFC。RFC 永远不会被编辑成*另一个决策*:用新 RFC 取代旧的并互相链接。(编辑 `implemented/` RFC 以跟踪其已做出的决策现在*位于何处*——移动的文件、重命名的包——不是另一个决策,是必须做的,而非禁止的;见 [implemented/AGENTS.md](implemented/AGENTS.md)。) + +## 文件格式 + +每篇 RFC 遵循统一的文件内格式,由 `pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../scripts/verify-rfc-format.ts),doc-sync(文档同步门禁)的一环)强制执行;该格式的设计动机及其否决的替代方案见[统一格式 RFC](implemented/process/2026-07-05-uniform-rfc-format.md)。 + +### 头部块 + +每篇 RFC 的前三行严格为: + +```markdown +# RFC: + +Status: <status> +``` + +后接一个空行。`Status:` 的值有三种形式,且必须与文件所在的生命周期文件夹一致——门禁会交叉检查: + +- `Status: proposed` +- `Status: implemented` +- `Status: rejected — <why, in one line>` + +状态行不带日期、不带括号补充说明:文件名承载首次提出日期,git 承载其余一切,「以修订形式接受」之类的说明属于正文内容(在陈述决策的地方说明修订)。否决原因是唯一带内容的状态行,因为读者查阅被否决 RFC 时要的就是结论。 + +### 正文骨架 + +每篇 RFC 的正文以 `## Problem` 开头——动机,写法应独立于解决方案。后续内容取决于生命周期;重复出现的章节使用以下规范名称且仅限这些名称,而真正特有的技术章节(包拓扑、协议格式(wire format)、schema)在必需章节之间自由编排。 + +#### `proposed/` + +```markdown +## Problem +## Proposal +…bespoke sections… +## Alternatives considered +## Acceptance criteria +## Risks +``` + +`## Proposal` 是拟议的变更,可以正当地使用将来时——计划、迁移步骤和未决问题在工作尚未构建时属于此处。`## Acceptance criteria` 说明什么可观测状态意味着完成。`## Risks` 涵盖可能出错的事项以及变更有意放弃的东西。 + +#### `implemented/` + +```markdown +## Problem +## Decision +…bespoke sections… +## Alternatives considered +## Consequences +``` + +`## Decision` 以现在时描述已交付的现实,整个文件按 [implemented/AGENTS.md](implemented/AGENTS.md) 的要求与之保持同步。`## Consequences` 记录权衡的代价**与**收益。提案阶段的标题在这里属于规格用语,门禁会拒绝:`## Proposal`、`## Plan`、`## Migration plan` 和 `## Acceptance criteria` 不得出现在 implemented RFC 中([slop 检查清单](../AGENTS.md)说明了原因)。`## Testing`、`## Deferred` 或 `## Related` 章节在陈述现在时事实时是允许的。 + +#### `rejected/` + +被否决的 RFC 是冻结的提案:保留其提案时的所有章节(包括 `## Acceptance criteria` 或 `## Plan`),结论写在 `Status:` 行。仅头部块、`## Problem` 开头、`## Proposal` 章节,以及下方的「曾考虑的替代方案」强制要求适用。 + +### 曾考虑的替代方案——强制要求 + +每篇 RFC 都必须有一个 `## Alternatives considered` 章节:每个真实的替代方案及其落选原因,每个替代方案一段(加粗引导),或对争议较大的方案使用 `### Why not <X>?` 子章节。记录决策却不记录它击败了什么,就是在邀请反复争论——正是 RFC 存在的目的所要防止的。 + +替代方案是记录下来的,而非凭空编造的。日期早于 2026-07-05 的 RFC,如果其替代方案无法从记录中重建,则在该章节位置放置以下精确注释,门禁仅对格式前文件接受此注释: + +```markdown +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +``` + +### 在生命周期间移动 + +将文件在生命周期文件夹间移动意味着在同一个变更中更新 `Status:` 行并满足目标文件夹的骨架要求——否则门禁会失败。具体而言,`proposed/` → `implemented/` 将 `## Proposal` 改写为现在时的 `## Decision`,将 `## Acceptance criteria` 和 `## Risks` 折叠进 `## Consequences`(或一个现在时的 `## Testing`/`## Verification` 章节,用于说明现在什么在固定该行为),并用实际交付的内容替换计划——即 [implemented/AGENTS.md](implemented/AGENTS.md) 要求的改写,使之机械化。`proposed/` → `rejected/` 仅在 `Status:` 行添加原因并冻结文件。 + +### 中文对侧文件 + +`.zh.md` 对侧文件按 [i18n 契约](../i18n/README.md)逐章节镜像其英文兄弟文件的结构;机器检查的头部标记(`# RFC: ` 和 `Status:` 行)保持英文原样不变。格式门禁跳过 `.zh.md` 文件——配对门禁负责它们的一致性。 diff --git a/scripts/translation-pairing.manifest.json b/scripts/translation-pairing.manifest.json index ee0a35b599..be766dbaad 100644 --- a/scripts/translation-pairing.manifest.json +++ b/scripts/translation-pairing.manifest.json @@ -10,11 +10,33 @@ "docs/cookbook/extension-cookbook.md", "docs/cookbook/responding-to-pr-review-on-a-stack.md", "docs/cordis-primer.md", + "docs/core-data-structures/approval.md", + "docs/core-data-structures/bash.md", + "docs/core-data-structures/code-runtime.md", + "docs/core-data-structures/compaction.md", + "docs/core-data-structures/filesystem.md", + "docs/core-data-structures/llm-streaming.md", + "docs/core-data-structures/persistence.md", + "docs/core-data-structures/sandbox.md", + "docs/core-data-structures/scope.md", + "docs/core-data-structures/session-query.md", + "docs/core-data-structures/session.md", + "docs/core-data-structures/skills.md", + "docs/core-data-structures/subagent.md", + "docs/core-data-structures/system-prompt.md", + "docs/core-data-structures/tools.md", + "docs/core-data-structures/user-interaction.md", + "docs/core-data-structures/web.md", + "docs/core-data-structures/workflow.md", "docs/defensive-patterns.md", "docs/development.md", "docs/glossary.md", "docs/i18n/README.md", "docs/i18n/translation-rules.md", + "docs/postmortem/0001-acp-default-export-drops-inject.md", + "docs/postmortem/0002-js-expression-disabled-filesystem-tools.md", + "docs/postmortem/README.md", + "docs/rfc/README.md", "docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md", "docs/rfc/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md", "docs/testing.md", @@ -35,6 +57,7 @@ "docs/i18n/translation-prompt.md", "docs/module-graph.md", "docs/persistence-catalog.md", + "docs/rfc/INDEX.md", "docs/tool-catalog.md", "docs/tool-execution-pipeline.md", "python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/" From 92fd92fa697639ece53fcbc8175daf8589b263e4 Mon Sep 17 00:00:00 2001 From: Hypatia May <hypatiamay@outlook.com> Date: Thu, 16 Jul 2026 14:12:50 +0800 Subject: [PATCH 011/368] test(session-query): name binding retry precisely (round 3) --- .../session-query/session-query-sqlite/tests/sqlite.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts index 0a62fff1b3..b4a69acbbd 100644 --- a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts @@ -561,7 +561,7 @@ describe('SQLite reconciliation and source lifecycle', () => { expect(TestPersistence.loads.get(added.id)).toBe(1) }) - it('retries if the source revision changes while live sessions are observed', async () => { + it('retries if the persistence binding changes while live sessions are observed', async () => { const durable = header('live-boundary-retry') TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) const ctx = await liveContext() From 2565133af3840bfe6dae4b7284eb796718d02171 Mon Sep 17 00:00:00 2001 From: Ziya <199893125+ZiyaZhang@users.noreply.github.com> Date: Wed, 15 Jul 2026 23:25:06 -0700 Subject: [PATCH 012/368] =?UTF-8?q?docs(i18n):=20RFC=20tree=20batch=20?= =?UTF-8?q?=E2=80=94=20146=20bilingual=20pairs=20via=20the=20committed=20p?= =?UTF-8?q?ipeline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit implemented(除 4 篇超长文档随后补)、proposed、rejected 全树配对; 同一流水线 + 二遍校验(paraphrase-back + 仓库上下文一致性)产出。 docs/rfc/implemented/AGENTS.md 与其 CLAUDE.md 符号链接列入排除 (agent 指令文件,与根 AGENTS.md 同策略)。 --- ...6-06-11-content-block-vocabulary.i18n.yaml | 6 + .../2026-06-11-content-block-vocabulary.md | 2 + .../2026-06-11-content-block-vocabulary.zh.md | 28 +++ .../2026-06-11-custom-schema-dsl.i18n.yaml | 6 + .../2026-06-11-custom-schema-dsl.md | 2 + .../2026-06-11-custom-schema-dsl.zh.md | 23 ++ ...ev-invariants-over-deep-readonly.i18n.yaml | 6 + ...06-11-dev-invariants-over-deep-readonly.md | 2 + ...11-dev-invariants-over-deep-readonly.zh.md | 60 +++++ ...026-06-11-event-sourced-sessions.i18n.yaml | 6 + .../2026-06-11-event-sourced-sessions.md | 2 + .../2026-06-11-event-sourced-sessions.zh.md | 28 +++ ...06-11-microkernel-event-taxonomy.i18n.yaml | 6 + .../2026-06-11-microkernel-event-taxonomy.md | 2 + ...026-06-11-microkernel-event-taxonomy.zh.md | 31 +++ ...026-06-11-runtime-arg-validation.i18n.yaml | 6 + .../2026-06-11-runtime-arg-validation.md | 2 + .../2026-06-11-runtime-arg-validation.zh.md | 24 ++ ...-06-11-structured-error-taxonomy.i18n.yaml | 6 + .../2026-06-11-structured-error-taxonomy.md | 2 + ...2026-06-11-structured-error-taxonomy.zh.md | 26 +++ ...-tool-schemas-in-prompt-assembly.i18n.yaml | 6 + ...6-06-11-tool-schemas-in-prompt-assembly.md | 2 + ...6-11-tool-schemas-in-prompt-assembly.zh.md | 23 ++ .../2026-06-13-capability-seams.i18n.yaml | 6 + .../2026-06-13-capability-seams.md | 2 + .../2026-06-13-capability-seams.zh.md | 32 +++ .../2026-06-13-twin-llm-adapters.i18n.yaml | 6 + .../2026-06-13-twin-llm-adapters.md | 2 + .../2026-06-13-twin-llm-adapters.zh.md | 27 +++ .../2026-06-14-session-persistence.i18n.yaml | 6 + .../2026-06-14-session-persistence.md | 2 + .../2026-06-14-session-persistence.zh.md | 36 +++ ...6-06-15-turn-enclosure-invariant.i18n.yaml | 6 + .../2026-06-15-turn-enclosure-invariant.md | 2 + .../2026-06-15-turn-enclosure-invariant.zh.md | 42 ++++ ...06-17-filesystem-capability-seam.i18n.yaml | 6 + .../2026-06-17-filesystem-capability-seam.md | 2 + ...026-06-17-filesystem-capability-seam.zh.md | 160 +++++++++++++ ...nt-lifecycle-and-ownership-seams.i18n.yaml | 6 + ...-18-agent-lifecycle-and-ownership-seams.md | 2 + ...-agent-lifecycle-and-ownership-seams.zh.md | 48 ++++ .../2026-06-18-session-surface.i18n.yaml | 6 + .../2026-06-18-session-surface.md | 2 + .../2026-06-18-session-surface.zh.md | 71 ++++++ ...ed-persistence-write-coordinator.i18n.yaml | 6 + ...18-shared-persistence-write-coordinator.md | 2 + ...shared-persistence-write-coordinator.zh.md | 44 ++++ .../2026-06-20-branded-ids.i18n.yaml | 6 + .../architecture/2026-06-20-branded-ids.md | 2 + .../architecture/2026-06-20-branded-ids.zh.md | 69 ++++++ ...-20-extract-example-app-packages.i18n.yaml | 6 + ...2026-06-20-extract-example-app-packages.md | 2 + ...6-06-20-extract-example-app-packages.zh.md | 57 +++++ .../2026-06-20-package-hierarchy.i18n.yaml | 6 + .../2026-06-20-package-hierarchy.md | 2 + .../2026-06-20-package-hierarchy.zh.md | 75 ++++++ ...andatory-app-attribution-headers.i18n.yaml | 6 + ...06-21-mandatory-app-attribution-headers.md | 2 + ...21-mandatory-app-attribution-headers.zh.md | 84 +++++++ ...06-26-file-context-as-event-gate.i18n.yaml | 6 + .../2026-06-26-file-context-as-event-gate.md | 2 + ...026-06-26-file-context-as-event-gate.zh.md | 171 ++++++++++++++ ...stdin-env-trusted-plugin-surface.i18n.yaml | 6 + ...0-bash-stdin-env-trusted-plugin-surface.md | 2 + ...ash-stdin-env-trusted-plugin-surface.zh.md | 33 +++ ...026-06-30-event-domain-semantics.i18n.yaml | 6 + .../2026-06-30-event-domain-semantics.md | 2 + .../2026-06-30-event-domain-semantics.zh.md | 39 ++++ .../2026-07-02-fs-per-session-cwd.i18n.yaml | 6 + .../2026-07-02-fs-per-session-cwd.md | 2 + .../2026-07-02-fs-per-session-cwd.zh.md | 34 +++ ...2-result-time-applied-hunk-diffs.i18n.yaml | 6 + ...26-07-02-result-time-applied-hunk-diffs.md | 2 + ...07-02-result-time-applied-hunk-diffs.zh.md | 61 +++++ ...6-07-02-tool-render-intent-union.i18n.yaml | 6 + .../2026-07-02-tool-render-intent-union.md | 2 + .../2026-07-02-tool-render-intent-union.zh.md | 82 +++++++ ...ilesystem-directory-listing-seam.i18n.yaml | 6 + ...07-03-filesystem-directory-listing-seam.md | 2 + ...03-filesystem-directory-listing-seam.zh.md | 53 +++++ ...bles-and-tool-guidance-ownership.i18n.yaml | 6 + ...t-variables-and-tool-guidance-ownership.md | 2 + ...ariables-and-tool-guidance-ownership.zh.md | 72 ++++++ ...6-07-05-reconstructable-requests.i18n.yaml | 6 + .../2026-07-05-reconstructable-requests.md | 2 + .../2026-07-05-reconstructable-requests.zh.md | 55 +++++ ...bagent-provider-lifecycle-events.i18n.yaml | 6 + ...7-05-subagent-provider-lifecycle-events.md | 2 + ...5-subagent-provider-lifecycle-events.zh.md | 36 +++ ...6-07-06-timeout-deadline-library.i18n.yaml | 6 + .../2026-07-06-timeout-deadline-library.md | 2 + .../2026-07-06-timeout-deadline-library.zh.md | 98 ++++++++ ...6-07-07-tool-call-timeout-policy.i18n.yaml | 6 + .../2026-07-07-tool-call-timeout-policy.md | 2 + .../2026-07-07-tool-call-timeout-policy.zh.md | 111 +++++++++ .../2026-07-08-agent-scope-contexts.i18n.yaml | 6 + .../2026-07-08-agent-scope-contexts.md | 2 + .../2026-07-08-agent-scope-contexts.zh.md | 172 ++++++++++++++ ...-06-14-acp-agent-client-protocol.i18n.yaml | 6 + .../2026-06-14-acp-agent-client-protocol.md | 2 + ...2026-06-14-acp-agent-client-protocol.zh.md | 59 +++++ .../2026-06-14-acp-multi-session.i18n.yaml | 6 + .../feature/2026-06-14-acp-multi-session.md | 2 + .../2026-06-14-acp-multi-session.zh.md | 39 ++++ .../feature/2026-06-15-code-mode.i18n.yaml | 6 + .../feature/2026-06-15-code-mode.md | 2 + .../feature/2026-06-15-code-mode.zh.md | 132 +++++++++++ ...26-06-17-filesystem-tool-schemas.i18n.yaml | 6 + .../2026-06-17-filesystem-tool-schemas.md | 2 + .../2026-06-17-filesystem-tool-schemas.zh.md | 112 +++++++++ ...-acp-terminal-and-tool-rendering.i18n.yaml | 6 + ...6-06-18-acp-terminal-and-tool-rendering.md | 2 + ...6-18-acp-terminal-and-tool-rendering.zh.md | 48 ++++ ...06-18-compaction-capability-seam.i18n.yaml | 6 + .../2026-06-18-compaction-capability-seam.md | 2 + ...026-06-18-compaction-capability-seam.zh.md | 127 +++++++++++ ...6-06-21-subagent-capability-seam.i18n.yaml | 6 + .../2026-06-21-subagent-capability-seam.md | 2 + .../2026-06-21-subagent-capability-seam.zh.md | 74 ++++++ .../2026-06-22-acp-subagent-backend.i18n.yaml | 6 + .../2026-06-22-acp-subagent-backend.md | 2 + .../2026-06-22-acp-subagent-backend.zh.md | 57 +++++ .../2026-06-25-ask-user-question.i18n.yaml | 6 + .../feature/2026-06-25-ask-user-question.md | 2 + .../2026-06-25-ask-user-question.zh.md | 51 +++++ .../2026-06-29-todo-write-tool.i18n.yaml | 6 + .../feature/2026-06-29-todo-write-tool.md | 2 + .../feature/2026-06-29-todo-write-tool.zh.md | 64 ++++++ .../feature/2026-06-30-hook-bridges.i18n.yaml | 6 + .../feature/2026-06-30-hook-bridges.md | 2 + .../feature/2026-06-30-hook-bridges.zh.md | 70 ++++++ .../2026-06-30-hook-protocol-lib.i18n.yaml | 6 + .../feature/2026-06-30-hook-protocol-lib.md | 2 + .../2026-06-30-hook-protocol-lib.zh.md | 32 +++ .../2026-06-30-interception-seams.i18n.yaml | 6 + .../feature/2026-06-30-interception-seams.md | 2 + .../2026-06-30-interception-seams.zh.md | 60 +++++ ...026-06-30-session-store-fork-api.i18n.yaml | 6 + .../2026-06-30-session-store-fork-api.md | 2 + .../2026-06-30-session-store-fork-api.zh.md | 43 ++++ ...26-06-30-subagent-observe-enrich.i18n.yaml | 6 + .../2026-06-30-subagent-observe-enrich.md | 2 + .../2026-06-30-subagent-observe-enrich.zh.md | 31 +++ .../2026-07-05-dynamic-workflows.i18n.yaml | 6 + .../feature/2026-07-05-dynamic-workflows.md | 2 + .../2026-07-05-dynamic-workflows.zh.md | 80 +++++++ .../feature/2026-07-05-skill-system.i18n.yaml | 6 + .../feature/2026-07-05-skill-system.md | 2 + .../feature/2026-07-05-skill-system.zh.md | 55 +++++ .../2026-07-06-approval-seam.i18n.yaml | 6 + .../feature/2026-07-06-approval-seam.md | 2 + .../feature/2026-07-06-approval-seam.zh.md | 138 +++++++++++ .../2026-07-06-explicit-tool-order.i18n.yaml | 6 + .../feature/2026-07-06-explicit-tool-order.md | 2 + .../2026-07-06-explicit-tool-order.zh.md | 50 ++++ .../2026-07-07-mcp-client-plugin.i18n.yaml | 6 + .../feature/2026-07-07-mcp-client-plugin.md | 2 + .../2026-07-07-mcp-client-plugin.zh.md | 214 ++++++++++++++++++ .../2026-07-07-session-prefix.i18n.yaml | 6 + .../feature/2026-07-07-session-prefix.md | 2 + .../feature/2026-07-07-session-prefix.zh.md | 44 ++++ .../2026-07-08-repeat-tool-guard.i18n.yaml | 6 + .../feature/2026-07-08-repeat-tool-guard.md | 2 + .../2026-07-08-repeat-tool-guard.zh.md | 76 +++++++ ...-self-referential-cordis-toolset.i18n.yaml | 6 + ...6-07-08-self-referential-cordis-toolset.md | 2 + ...7-08-self-referential-cordis-toolset.zh.md | 82 +++++++ ...2026-07-10-session-query-service.i18n.yaml | 6 + .../2026-07-10-session-query-service.md | 2 + .../2026-07-10-session-query-service.zh.md | 43 ++++ ...nt-persona-tool-filter-and-depth.i18n.yaml | 6 + ...-subagent-persona-tool-filter-and-depth.md | 2 + ...bagent-persona-tool-filter-and-depth.zh.md | 94 ++++++++ .../2026-06-11-doc-sync-enforcement.i18n.yaml | 6 + .../2026-06-11-doc-sync-enforcement.md | 2 + .../2026-06-11-doc-sync-enforcement.zh.md | 32 +++ .../2026-06-11-quality-gates.i18n.yaml | 6 + .../process/2026-06-11-quality-gates.md | 2 + .../process/2026-06-11-quality-gates.zh.md | 28 +++ .../2026-06-11-tsdown-over-dumble.i18n.yaml | 6 + .../process/2026-06-11-tsdown-over-dumble.md | 2 + .../2026-06-11-tsdown-over-dumble.zh.md | 30 +++ ...26-06-11-vendor-cordis-as-source.i18n.yaml | 6 + .../2026-06-11-vendor-cordis-as-source.md | 2 + .../2026-06-11-vendor-cordis-as-source.zh.md | 27 +++ .../2026-06-16-pnpm-over-yarn.i18n.yaml | 6 + .../process/2026-06-16-pnpm-over-yarn.md | 2 + .../process/2026-06-16-pnpm-over-yarn.zh.md | 43 ++++ .../2026-06-17-ts-build-config.i18n.yaml | 6 + .../process/2026-06-17-ts-build-config.md | 2 + .../process/2026-06-17-ts-build-config.zh.md | 78 +++++++ ...6-06-18-markdown-cross-link-lint.i18n.yaml | 6 + .../2026-06-18-markdown-cross-link-lint.md | 2 + .../2026-06-18-markdown-cross-link-lint.zh.md | 33 +++ ...-20-core-data-structures-catalog.i18n.yaml | 6 + ...2026-06-20-core-data-structures-catalog.md | 2 + ...6-06-20-core-data-structures-catalog.zh.md | 60 +++++ ...6-06-20-generated-cordis-catalog.i18n.yaml | 6 + .../2026-06-20-generated-cordis-catalog.md | 2 + .../2026-06-20-generated-cordis-catalog.zh.md | 41 ++++ .../2026-06-20-rfc-classification.i18n.yaml | 6 + .../process/2026-06-20-rfc-classification.md | 2 + .../2026-06-20-rfc-classification.zh.md | 48 ++++ .../2026-07-02-tool-schema-catalog.i18n.yaml | 6 + .../process/2026-07-02-tool-schema-catalog.md | 2 + .../2026-07-02-tool-schema-catalog.zh.md | 55 +++++ ...-07-03-documentation-graph-atlas.i18n.yaml | 6 + .../2026-07-03-documentation-graph-atlas.md | 2 + ...2026-07-03-documentation-graph-atlas.zh.md | 69 ++++++ ...4-cordis-jsdoc-completeness-gate.i18n.yaml | 6 + ...26-07-04-cordis-jsdoc-completeness-gate.md | 2 + ...07-04-cordis-jsdoc-completeness-gate.zh.md | 41 ++++ ...2026-07-04-doc-tiers-and-budgets.i18n.yaml | 6 + .../2026-07-04-doc-tiers-and-budgets.md | 2 + .../2026-07-04-doc-tiers-and-budgets.zh.md | 28 +++ ...-07-04-generate-rfc-index-tables.i18n.yaml | 6 + .../2026-07-04-generate-rfc-index-tables.md | 2 + ...2026-07-04-generate-rfc-index-tables.zh.md | 34 +++ ...26-07-04-persistence-log-catalog.i18n.yaml | 6 + .../2026-07-04-persistence-log-catalog.md | 2 + .../2026-07-04-persistence-log-catalog.zh.md | 36 +++ .../2026-07-05-uniform-rfc-format.i18n.yaml | 6 + .../process/2026-07-05-uniform-rfc-format.md | 2 + .../2026-07-05-uniform-rfc-format.zh.md | 30 +++ ...-07-06-export-surface-jsdoc-gate.i18n.yaml | 6 + .../2026-07-06-export-surface-jsdoc-gate.md | 2 + ...2026-07-06-export-surface-jsdoc-gate.zh.md | 45 ++++ ...6-07-06-generated-config-catalog.i18n.yaml | 6 + .../2026-07-06-generated-config-catalog.md | 2 + .../2026-07-06-generated-config-catalog.zh.md | 40 ++++ .../2026-07-06-node-engine-floor.i18n.yaml | 6 + .../process/2026-07-06-node-engine-floor.md | 2 + .../2026-07-06-node-engine-floor.zh.md | 39 ++++ ...6-07-06-parallel-github-ci-gates.i18n.yaml | 6 + .../2026-07-06-parallel-github-ci-gates.md | 2 + .../2026-07-06-parallel-github-ci-gates.zh.md | 41 ++++ ...26-07-06-parallel-pre-push-gates.i18n.yaml | 6 + .../2026-07-06-parallel-pre-push-gates.md | 2 + .../2026-07-06-parallel-pre-push-gates.zh.md | 42 ++++ ...10-readme-known-limitations-gate.i18n.yaml | 6 + ...026-07-10-readme-known-limitations-gate.md | 2 + ...-07-10-readme-known-limitations-gate.zh.md | 29 +++ ...ackage-model-experience-contract.i18n.yaml | 6 + ...07-12-package-model-experience-contract.md | 2 + ...12-package-model-experience-contract.zh.md | 33 +++ ...-19-drop-mutable-session-summary.i18n.yaml | 6 + ...2026-06-19-drop-mutable-session-summary.md | 2 + ...6-06-19-drop-mutable-session-summary.zh.md | 35 +++ ...llapse-trace-only-session-events.i18n.yaml | 6 + ...6-20-collapse-trace-only-session-events.md | 2 + ...0-collapse-trace-only-session-events.zh.md | 44 ++++ ...onsumed-llm-adapter-change-event.i18n.yaml | 6 + ...rop-unconsumed-llm-adapter-change-event.md | 2 + ...-unconsumed-llm-adapter-change-event.zh.md | 36 +++ ...nconsumed-llm-assembled-surfaces.i18n.yaml | 6 + ...-drop-unconsumed-llm-assembled-surfaces.md | 2 + ...op-unconsumed-llm-assembled-surfaces.zh.md | 39 ++++ ...26-06-20-prune-dead-seam-methods.i18n.yaml | 6 + .../2026-06-20-prune-dead-seam-methods.md | 2 + .../2026-06-20-prune-dead-seam-methods.zh.md | 43 ++++ ...-06-20-public-agent-stop-surface.i18n.yaml | 6 + .../2026-06-20-public-agent-stop-surface.md | 2 + ...2026-06-20-public-agent-stop-surface.zh.md | 39 ++++ ...ove-agent-boundary-mirror-events.i18n.yaml | 6 + ...-20-remove-agent-boundary-mirror-events.md | 2 + ...-remove-agent-boundary-mirror-events.zh.md | 32 +++ .../2026-06-26-fsspec-style-fs-seam.i18n.yaml | 6 + .../2026-06-26-fsspec-style-fs-seam.md | 2 + .../2026-06-26-fsspec-style-fs-seam.zh.md | 130 +++++++++++ ...07-02-remove-stream-chunk-mirror.i18n.yaml | 6 + .../2026-07-02-remove-stream-chunk-mirror.md | 2 + ...026-07-02-remove-stream-chunk-mirror.zh.md | 47 ++++ ...6-07-04-drop-image-content-block.i18n.yaml | 6 + .../2026-07-04-drop-image-content-block.md | 2 + .../2026-07-04-drop-image-content-block.zh.md | 29 +++ ...6-07-04-drop-inert-request-knobs.i18n.yaml | 6 + .../2026-07-04-drop-inert-request-knobs.md | 2 + .../2026-07-04-drop-inert-request-knobs.zh.md | 35 +++ ...consumed-web-observation-surface.i18n.yaml | 6 + ...drop-unconsumed-web-observation-surface.md | 2 + ...p-unconsumed-web-observation-surface.zh.md | 34 +++ .../2026-07-04-fold-stdio-ui-helper.i18n.yaml | 6 + .../2026-07-04-fold-stdio-ui-helper.md | 2 + .../2026-07-04-fold-stdio-ui-helper.zh.md | 28 +++ ...producerless-vocabulary-variants.i18n.yaml | 6 + ...-prune-producerless-vocabulary-variants.md | 2 + ...une-producerless-vocabulary-variants.zh.md | 33 +++ ...7-04-prune-write-only-fs-surface.i18n.yaml | 6 + .../2026-07-04-prune-write-only-fs-surface.md | 2 + ...26-07-04-prune-write-only-fs-surface.zh.md | 32 +++ ...-04-remove-agent-steering-mirror.i18n.yaml | 6 + ...2026-07-04-remove-agent-steering-mirror.md | 2 + ...6-07-04-remove-agent-steering-mirror.zh.md | 33 +++ ...26-07-04-share-app-bin-boot-glue.i18n.yaml | 6 + .../2026-07-04-share-app-bin-boot-glue.md | 2 + .../2026-07-04-share-app-bin-boot-glue.zh.md | 27 +++ ...4-tighten-hook-protocol-contract.i18n.yaml | 6 + ...26-07-04-tighten-hook-protocol-contract.md | 2 + ...07-04-tighten-hook-protocol-contract.zh.md | 32 +++ ...m-acp-bridge-unreachable-surface.i18n.yaml | 6 + ...-04-trim-acp-bridge-unreachable-surface.md | 2 + ...-trim-acp-bridge-unreachable-surface.zh.md | 26 +++ ...unconsumed-skill-provider-events.i18n.yaml | 6 + ...2-drop-unconsumed-skill-provider-events.md | 2 + ...rop-unconsumed-skill-provider-events.zh.md | 29 +++ ...-12-prune-unused-web-seam-fields.i18n.yaml | 6 + ...2026-07-12-prune-unused-web-seam-fields.md | 2 + ...6-07-12-prune-unused-web-seam-fields.zh.md | 27 +++ ...026-06-11-property-based-testing.i18n.yaml | 6 + .../2026-06-11-property-based-testing.md | 2 + .../2026-06-11-property-based-testing.zh.md | 29 +++ .../2026-06-19-acp-snapshot-tests.i18n.yaml | 6 + .../testing/2026-06-19-acp-snapshot-tests.md | 2 + .../2026-06-19-acp-snapshot-tests.zh.md | 82 +++++++ .../2026-06-19-real-api-e2e-ci.i18n.yaml | 6 + .../testing/2026-06-19-real-api-e2e-ci.md | 2 + .../testing/2026-06-19-real-api-e2e-ci.zh.md | 100 ++++++++ ...e-redundant-snapshot-log-goldens.i18n.yaml | 6 + ...0-remove-redundant-snapshot-log-goldens.md | 2 + ...emove-redundant-snapshot-log-goldens.zh.md | 37 +++ ...-fork-child-replay-seed-boundary.i18n.yaml | 6 + ...6-06-22-fork-child-replay-seed-boundary.md | 2 + ...6-22-fork-child-replay-seed-boundary.zh.md | 49 ++++ ...26-06-22-fork-snapshot-scenarios.i18n.yaml | 6 + .../2026-06-22-fork-snapshot-scenarios.md | 2 + .../2026-06-22-fork-snapshot-scenarios.zh.md | 31 +++ ...6-06-22-subagent-snapshot-replay.i18n.yaml | 6 + .../2026-06-22-subagent-snapshot-replay.md | 2 + .../2026-06-22-subagent-snapshot-replay.zh.md | 58 +++++ .../2026-07-04-hook-snapshot-matrix.i18n.yaml | 6 + .../2026-07-04-hook-snapshot-matrix.md | 2 + .../2026-07-04-hook-snapshot-matrix.zh.md | 50 ++++ ...-single-source-acp-replay-config.i18n.yaml | 6 + ...6-07-04-single-source-acp-replay-config.md | 2 + ...7-04-single-source-acp-replay-config.zh.md | 27 +++ ...t-header-content-in-one-scenario.i18n.yaml | 6 + ...-request-header-content-in-one-scenario.md | 2 + ...quest-header-content-in-one-scenario.zh.md | 35 +++ ...7-08-shared-acp-snapshot-package.i18n.yaml | 6 + .../2026-07-08-shared-acp-snapshot-package.md | 2 + ...26-07-08-shared-acp-snapshot-package.zh.md | 38 ++++ .../2026-06-16-typed-event-schemas.i18n.yaml | 6 + .../2026-06-16-typed-event-schemas.md | 2 + .../2026-06-16-typed-event-schemas.zh.md | 77 +++++++ ...eneric-long-running-tool-runtime.i18n.yaml | 6 + ...06-20-generic-long-running-tool-runtime.md | 2 + ...20-generic-long-running-tool-runtime.zh.md | 43 ++++ ...026-06-30-pre-tool-input-rewrite.i18n.yaml | 6 + .../2026-06-30-pre-tool-input-rewrite.md | 2 + .../2026-06-30-pre-tool-input-rewrite.zh.md | 53 +++++ ...code-and-codex-subagent-backends.i18n.yaml | 6 + ...claude-code-and-codex-subagent-backends.md | 2 + ...ude-code-and-codex-subagent-backends.zh.md | 89 ++++++++ ...-07-08-interactive-side-sessions.i18n.yaml | 6 + .../2026-07-08-interactive-side-sessions.md | 2 + ...2026-07-08-interactive-side-sessions.zh.md | 41 ++++ ...10-sqlite-session-query-provider.i18n.yaml | 6 + ...026-07-10-sqlite-session-query-provider.md | 2 + ...-07-10-sqlite-session-query-provider.zh.md | 53 +++++ ...flow-progress-through-tool-calls.i18n.yaml | 6 + ...am-workflow-progress-through-tool-calls.md | 2 + ...workflow-progress-through-tool-calls.zh.md | 43 ++++ ...2026-06-11-api-extractor-reports.i18n.yaml | 6 + .../2026-06-11-api-extractor-reports.md | 2 + .../2026-06-11-api-extractor-reports.zh.md | 32 +++ ...-06-11-architectural-conformance.i18n.yaml | 6 + .../2026-06-11-architectural-conformance.md | 2 + ...2026-06-11-architectural-conformance.zh.md | 36 +++ ...11-supply-chain-and-vendor-drift.i18n.yaml | 6 + ...026-06-11-supply-chain-and-vendor-drift.md | 2 + ...-06-11-supply-chain-and-vendor-drift.zh.md | 35 +++ ...06-20-discover-package-inventory.i18n.yaml | 6 + .../2026-06-20-discover-package-inventory.md | 2 + ...026-06-20-discover-package-inventory.zh.md | 36 +++ ...06-20-unify-agent-and-session-id.i18n.yaml | 6 + .../2026-06-20-unify-agent-and-session-id.md | 2 + ...026-06-20-unify-agent-and-session-id.zh.md | 42 ++++ ...04-prune-dead-core-spine-surface.i18n.yaml | 6 + ...026-07-04-prune-dead-core-spine-surface.md | 2 + ...-07-04-prune-dead-core-spine-surface.zh.md | 62 +++++ ...plify-session-log-representation.i18n.yaml | 6 + ...-12-simplify-session-log-representation.md | 2 + ...-simplify-session-log-representation.zh.md | 38 ++++ ...deterministic-and-stress-testing.i18n.yaml | 6 + ...-06-11-deterministic-and-stress-testing.md | 2 + ...-11-deterministic-and-stress-testing.zh.md | 33 +++ .../2026-06-11-mutation-testing.i18n.yaml | 6 + .../testing/2026-06-11-mutation-testing.md | 2 + .../testing/2026-06-11-mutation-testing.zh.md | 36 +++ ...-06-11-immutable-public-surfaces.i18n.yaml | 6 + .../2026-06-11-immutable-public-surfaces.md | 2 + ...2026-06-11-immutable-public-surfaces.zh.md | 29 +++ ...-06-20-providerless-example-base.i18n.yaml | 6 + .../2026-06-20-providerless-example-base.md | 2 + ...2026-06-20-providerless-example-base.zh.md | 31 +++ ...ssembled-assistant-messages-only.i18n.yaml | 6 + ...06-20-assembled-assistant-messages-only.md | 2 + ...20-assembled-assistant-messages-only.zh.md | 36 +++ ...2026-06-20-drop-acp-session-load.i18n.yaml | 6 + .../2026-06-20-drop-acp-session-load.md | 2 + .../2026-06-20-drop-acp-session-load.zh.md | 29 +++ ...026-06-20-drop-acp-terminal-meta.i18n.yaml | 6 + .../2026-06-20-drop-acp-terminal-meta.md | 2 + .../2026-06-20-drop-acp-terminal-meta.zh.md | 31 +++ ...-20-drop-bash-output-spill-files.i18n.yaml | 6 + ...2026-06-20-drop-bash-output-spill-files.md | 2 + ...6-06-20-drop-bash-output-spill-files.zh.md | 31 +++ ...-20-drop-durable-step-boundaries.i18n.yaml | 6 + ...2026-06-20-drop-durable-step-boundaries.md | 2 + ...6-06-20-drop-durable-step-boundaries.zh.md | 32 +++ ...6-20-drop-unused-session-lineage.i18n.yaml | 6 + .../2026-06-20-drop-unused-session-lineage.md | 2 + ...26-06-20-drop-unused-session-lineage.zh.md | 31 +++ ...ld-session-persistence-interface.i18n.yaml | 6 + ...6-20-fold-session-persistence-interface.md | 2 + ...0-fold-session-persistence-interface.zh.md | 31 +++ ...026-06-20-generic-tool-rendering.i18n.yaml | 6 + .../2026-06-20-generic-tool-rendering.md | 2 + .../2026-06-20-generic-tool-rendering.zh.md | 35 +++ ...6-06-20-retire-mid-turn-steering.i18n.yaml | 6 + .../2026-06-20-retire-mid-turn-steering.md | 2 + .../2026-06-20-retire-mid-turn-steering.zh.md | 37 +++ ...-06-20-single-session-acp-bridge.i18n.yaml | 6 + .../2026-06-20-single-session-acp-bridge.md | 2 + ...2026-06-20-single-session-acp-bridge.zh.md | 31 +++ ...06-20-truncate-interrupted-turns.i18n.yaml | 6 + .../2026-06-20-truncate-interrupted-turns.md | 2 + ...026-06-20-truncate-interrupted-turns.zh.md | 36 +++ ...nimplemented-subagent-vocabulary.i18n.yaml | 6 + ...prune-unimplemented-subagent-vocabulary.md | 2 + ...ne-unimplemented-subagent-vocabulary.zh.md | 39 ++++ ...apse-workflow-to-foreground-core.i18n.yaml | 6 + ...12-collapse-workflow-to-foreground-core.md | 2 + ...collapse-workflow-to-foreground-core.zh.md | 39 ++++ ...ne-unused-skill-registry-surface.i18n.yaml | 6 + ...-12-prune-unused-skill-registry-surface.md | 2 + ...-prune-unused-skill-registry-surface.zh.md | 29 +++ scripts/translation-pairing.manifest.json | 148 ++++++++++++ 439 files changed, 8800 insertions(+) create mode 100644 docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md create mode 100644 docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md create mode 100644 docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md create mode 100644 docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md create mode 100644 docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md create mode 100644 docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md create mode 100644 docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md create mode 100644 docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md create mode 100644 docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md create mode 100644 docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md create mode 100644 docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md create mode 100644 docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md create mode 100644 docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md create mode 100644 docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml create mode 100644 docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md create mode 100644 docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml create mode 100644 docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md create mode 100644 docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md create mode 100644 docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md create mode 100644 docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md create mode 100644 docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md create mode 100644 docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md create mode 100644 docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md create mode 100644 docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md create mode 100644 docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md create mode 100644 docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md create mode 100644 docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md create mode 100644 docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml create mode 100644 docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md create mode 100644 docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml create mode 100644 docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md create mode 100644 docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml create mode 100644 docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md create mode 100644 docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml create mode 100644 docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md create mode 100644 docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml create mode 100644 docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md create mode 100644 docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml create mode 100644 docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md create mode 100644 docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml create mode 100644 docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md create mode 100644 docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml create mode 100644 docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md create mode 100644 docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml create mode 100644 docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md create mode 100644 docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml create mode 100644 docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md create mode 100644 docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml create mode 100644 docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md create mode 100644 docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml create mode 100644 docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md create mode 100644 docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml create mode 100644 docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md create mode 100644 docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml create mode 100644 docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md create mode 100644 docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml create mode 100644 docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md create mode 100644 docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml create mode 100644 docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md create mode 100644 docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml create mode 100644 docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md create mode 100644 docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml create mode 100644 docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md create mode 100644 docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml create mode 100644 docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md create mode 100644 docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml create mode 100644 docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml new file mode 100644 index 0000000000..67537fda94 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-content-block-vocabulary.md: 9414bda624fa6e5fc7e9b11b7a738d32b269af6b +2026-06-11-content-block-vocabulary.zh.md: 32308a5fe58f3a2e3c402982b7067811b9698218 diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md index 1c22f9b7ca..9414bda624 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md @@ -1,5 +1,7 @@ # RFC: Provider-neutral content-block vocabulary owned by dsh-llm +English | [中文](2026-06-11-content-block-vocabulary.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md new file mode 100644 index 0000000000..32308a5fe5 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md @@ -0,0 +1,28 @@ +# RFC:由 dsh-llm 持有的提供方无关内容块词汇 + +Status: implemented + +[English](2026-06-11-content-block-vocabulary.md) | 中文 + +## 问题 + +harness 需要一套统一的内部消息语言,供 agent loop(智能体循环)、会话日志和所有插件共同使用。 + +## 决策 + +自行持有词汇:消息是类型化内容块(`text`、`reasoning`、`tool-call`、`tool-result`)的数组,其联合类型派生自可合并扩展的 `ContentBlockMap`,插件通过声明合并添加新的块类型。同一套可合并扩展映射模式也用于所有「字符串化」字段的类型定义(`MessageSource`、`FinishReason`、`TurnTrigger`、`TurnEndReason`)。流式输出是原始分片协议;`BlockAssembler` 是唯一的共享组装实现。适配器负责转换为各提供方的协议格式(wire format):映射成本留在适配器中,这正是它该待的地方。 + +会话内上下文注入(`context/message`、`steering/message`)渲染为带标签的 user-role 信封(system-reminder 模式),而非引入新 role,因此适配器零负担。真实适配器验证已确认该渲染方式在当前 DeepSeek 行为下有效;如果未来某个提供方出现不匹配,应在该适配器内处理,而非引入新的规范 role。 + +## 曾考虑的替代方案 + +- **镜像 DeepSeek/OpenAI chat-completions 的结构**:对第一个提供方零映射成本,但对富内容(推理(reasoning)、作为结构化块的工具结果)处理起来别扭。 +- **原样采用 Anthropic Messages 的块结构**:经过实战检验,但规范类型将镜像一个 harness 并非首要对接的第三方 API。 + +## 后果 + +- 推理(reasoning)在核心层有了归属,无需依赖提供方特有的结构。 +- 多模态块只有在适配器、UI 与上下文压缩(context compaction)三方协同支持时才会回归;见[移除 image 内容块 RFC](../simplification/2026-07-04-drop-image-content-block.md)。 +- 缓存提示与 assistant prefill 在有实际适配器能兑现之前保持缺席;见[无生产者的变体](../simplification/2026-07-04-prune-producerless-vocabulary-variants.md)与[惰性请求旋钮](../simplification/2026-07-04-drop-inert-request-knobs.md) RFC。 +- 每个适配器都要承担翻译成本;首批真实适配器已验证了流式输出协议,后续新适配器应继续在适配器本地测试中证明其提供方特有的映射。 +- 跨包边界的 ID 使用品牌类型(`CallId`、`SessionId`、`AgentId`):零运行时成本的名义类型。 diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml new file mode 100644 index 0000000000..5046fe3a38 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-custom-schema-dsl.md: 4c4d572b15d5e474e00e99fc5e7dd89240251c63 +2026-06-11-custom-schema-dsl.zh.md: 31af594846b6b1bc8ce983b7b9d4ddd956a560ff diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md index 18923fbb60..4c4d572b15 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md @@ -1,5 +1,7 @@ # RFC: Custom typed tool-schema DSL instead of schemastery +English | [中文](2026-06-11-custom-schema-dsl.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md new file mode 100644 index 0000000000..31af594846 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md @@ -0,0 +1,23 @@ +# RFC:使用自定义类型化工具 schema DSL 替代 schemastery + +Status: implemented + +[English](2026-06-11-custom-schema-dsl.md) | 中文 + +## 问题 + +工具参数必须以标准 JSON Schema 的形式传递给模型,同时让工具作者在 `execute(args)` 中获得类型推导而无需类型断言。schemastery 已用于插件配置,但工具作者 API 需要的是逐属性的 `required: true` 布尔值,而非 JSON Schema 的独立 `required` 数组。 + +## 决策 + +在 dsh-tools 中实现一个小型自定义 DSL:`SchemaSpec`(逐属性规格,带 `required: true` 布尔值);类型层面的 `InferArgs<S>` 将规格映射为参数类型(required 键为必选,其余通过 `?` 真正可选);运行时的 `schemaSpecToJsonSchema()` 转换器;以及将它们串联起来的 `defineTool()`。`ToolRegistry.register()` 仍接受原始 JSON Schema 的 `ToolDefinition`——MCP 来源的工具就是这样注册的。 + +## 曾考虑的替代方案 + +**schemastery**(已 vendor、用于插件 Config)经评估后被否决:它面向的是基于 StandardSchema 的校验/转换,而非 JSON Schema *生成*,因此会增加间接层却无法干净地产出协议格式(wire format)。 + +## 后果 + +- 第一方工具作者获得零类型断言的类型化参数;类型体操的成本留在核心包内部(符合 AGENTS.md 的类型安全策略)。 +- DSL 刻意保持小巧(string/number/boolean/object/array、enum、default、嵌套 properties/items)。相对完整 JSON Schema 的缺口(union、format、约束)在真实工具提出需求之前暂不填补。 +- `InferArgs` 映射在一次早期可选性 bug 之后已有类型层面的回归测试。 diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml new file mode 100644 index 0000000000..ef2f73d949 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-dev-invariants-over-deep-readonly.md: dc89b5b66d02bde2f4fe2794e04b76ecdeac62ae +2026-06-11-dev-invariants-over-deep-readonly.zh.md: 02beb323df84cd442611f0c52b3c56734d6d0554 diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md index aac3991f46..dc89b5b66d 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md @@ -1,5 +1,7 @@ # RFC: Source-owned session immutability and dev-mode invariants +English | [中文](2026-06-11-dev-invariants-over-deep-readonly.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md new file mode 100644 index 0000000000..02beb323df --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md @@ -0,0 +1,60 @@ +# RFC:源头拥有的会话不可变性与开发模式不变式 + +Status: implemented + +[English](2026-06-11-dev-invariants-over-deep-readonly.md) | 中文 + +## 问题 + +会话日志需要两种不同的保护:对每条已存储事实的不可变所有权,以及对跨时间和服务 seam 的事实间关系的检查。如果将二者混为一体放进一个可选的开发插件,生产环境的历史记录将失去保护;如果试图通过 TypeScript readonly 类型同时表达两者,既无法建立运行时边界,也无法描述关系规则。 + +会话日志是回放、请求重建、持久化和用户可见历史的持久真源。会话包以外的代码必须能够检视该历史,但不能保留一个可以事后改写它的引用;从调用方接收的输入也不能继续连接到调用方拥有的可变对象上。 + +单个值的不可变性只是契约的一半。一份日志可以包含完全不可变的记录,但其序列、轮次/步骤嵌套、工具调用配对、作用域分发或重建的模型请求是错误的。这些规则涉及多条记录或多个服务,无法通过冻结单个对象来建立。 + +TypeScript readonly 类型不构成充分的运行时边界。它们在程序运行时消失,一次类型转换即可绕过,而递归的 `DeepReadonly<T>` 会扩散到每个日志和消息消费方,尽管某些下游请求处理 API 有意使用可变值。 + +## 决策 + +职责在一个始终开启的存储边界与可选的开发断言之间分离。 + +### Session 拥有不可变历史 + +`Session` 仅在一次递归遍历完成无损 JSON 快照后才接受事件。该遍历拒绝不支持的值,并产出进入日志的确切脱离记录,因此校验和存储不可能从有状态的 getter 观察到不同的值,也不会保留调用方拥有的嵌套引用。 + +被接受的事件及其所有后代在发布前被深度冻结。`append()` 返回该拥有的冻结事件,`session/event` 观察者收到同一条记录,`session.events` 返回一份冻结的数组快照。先前返回的数组不会因后续 append 而增长。种子记录在构造成功前经过相同的校验、快照与冻结边界。 + +这一保证属于 `Session` 而非可选的监听器,因为每种组合都依赖可信的历史。无论是否注册了开发支持插件,生产部署、聚焦测试或自定义嵌入都获得相同的存储语义。 + +### 派生请求保持脱离 + +`deriveMessages()` 将已记录的表面事件投影为脱离的、深度冻结的 `Message` 对象,并返回一份新的数组快照。请求组装因此可以将派生历史与其他输入组合,而不会暴露一条回到日志的路径。缓存复用安全的不可变投影,而非为每次模型调用重新克隆完整历史。 + +### 不变式插件检查关系 + +`dsh-invariants` 是一个纯监听的开发插件。它不冻结记录,没有配置;dispose 仅移除其断言。它检查需要追踪状态或观察另一个 seam 的规则,包括单调递增的序列号、轮次与步骤嵌套、工具调用/结果配对、合法的 agent 状态转换、主体正确的作用域分发,以及 agent loop 构建的请求与从其会话日志前缀重建的请求之间的等价性。 + +当插件附加到已有或已播种的会话时,它回放不可变日志以重建追踪状态。这使得在轮次中间进行热重载是安全的,同时不赋予插件对会话存储的所有权。 + +## 曾考虑的替代方案 + +### 全面的 deep-readonly 类型 + +[被否决的不可变公开表面提案](../../rejected/architecture/2026-06-11-immutable-public-surfaces.md)会在公开的日志和消息表面全面应用递归 readonly 类型。这能提供编辑器反馈,但不能提供运行时保证:TypeScript 类型在运行时被擦除,插件代码可以通过类型转换绕过。它还会将 readonly 类型推入有意进行修改的消费方。在 `Session` 边界处的运行时所有权保护所有调用方,无需这种类型传播。 + +### 仅在开发模式冻结 + +仅在安装了不变式插件时才冻结历史,会使核心保证依赖于组合方式。代码可能通过开发测试,却在生产环境或省略了该插件的聚焦组合中破坏历史。因此存储不可变性始终开启,而更昂贵的关系检查保持为可选的开发支持。 + +### 仅在派生消息时克隆 + +脱离 `deriveMessages()` 会保护最常见的请求路径,但 `session.events` 的其他读者、append 返回值和会话事件观察者仍能修改持久历史。日志必须保护自身的边界;派生投影是额外的隔离边界,不是替代品。 + +## 后果 + +- 每条被接受的实时或种子会话事件在任何观察者收到之前,都已从调用方拥有的输入中脱离并深度不可变。 +- `session.events` 暴露稳定的不可变快照,而非私有的增长数组。 +- 请求侧的修改无法通过派生消息触及已存储的历史。 +- 开发构建可以启用关系断言而不改变存储行为;dispose 或省略该插件不会削弱日志不可变性。 +- `dsh-invariants` 没有 `Config` 表面,因为它没有可调节的行为。 +- 运行时边界在每条被接受的事件上承担一次递归快照与冻结的开销;后续读者和缓存投影复用已拥有的不可变记录。 diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml new file mode 100644 index 0000000000..00e6dc9181 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-event-sourced-sessions.md: 04ff974826ffbc9052c7eb9f5794bc16557241f9 +2026-06-11-event-sourced-sessions.zh.md: a3fec18445673bc2368333413f9802f9822b9c89 diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md index 4539fb40ba..04ff974826 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md @@ -1,5 +1,7 @@ # RFC: Event-sourced sessions with derived message history +English | [中文](2026-06-11-event-sourced-sessions.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md new file mode 100644 index 0000000000..a3fec18445 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md @@ -0,0 +1,28 @@ +# RFC:事件溯源的会话与派生消息历史 + +Status: implemented + +[English](2026-06-11-event-sourced-sessions.md) | 中文 + +## 问题 + +MVP 要求严格的基于事件的 trace、logging 系统,session 完全可回放。 + +## 决策 + +`Session` 是一份仅追加的、类型化的 `SessionEvent` 日志,是唯一的真源。LLM(大语言模型)消息历史从日志*派生*(`deriveMessages()`);原始流分片被记入日志以保证 token 级别的回放保真度,而组装后的 `assistant/message` 事件才是派生的权威来源。回放/fork = 用已有日志初始化一个新会话。 + +追加操作是同步的(热路径从不阻塞在 I/O 上);`session/event` 是同步通知;持久化插件在后台缓冲写入,并在每个轮次结束时触发的 `session/flush` 检查点处等待排空。 + +顺序契约:agent loop(智能体循环)先追加到会话,再发出对应的 Cordis 事件;`agent/step-result` waterfall(瀑布式事件)在 `assistant/message` 追加之前运行,因此日志记录的是工具调度实际使用的消息。回归测试固定了这一顺序。 + +## 曾考虑的替代方案 + +**可变消息数组 + 事件作为通知发出**:更简单,但状态与日志可能分歧;采用事件溯源后,日志本身就是状态,分歧在结构上不可能发生。 + +## 后果 + +- 回放、trace 与遥测在结构上得到保证,而非事后附加。 +- 持久化仍是插件关注点;内存存储随 dsh-session 一起发布。 +- 事件词汇可通过合并扩展(插件可添加如压缩(compaction)事件);[会话持久化](2026-06-14-session-persistence.md)在日志变为持久后冻结了其形状。 +- 派生成本随日志长度增长——压缩(未来插件)是预期的缓解手段,而非日志变更。 diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml new file mode 100644 index 0000000000..00320a6991 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-microkernel-event-taxonomy.md: c66968257a5a6304f187ccb5b9a162aa143e608d +2026-06-11-microkernel-event-taxonomy.zh.md: 86750f6ece488e735f2c14f759db7c9eef360828 diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md index 8293924d37..c66968257a 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md @@ -1,5 +1,7 @@ # RFC: Microkernel — extension via Cordis event taxonomy, one concrete loop +English | [中文](2026-06-11-microkernel-event-taxonomy.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md new file mode 100644 index 0000000000..86750f6ece --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md @@ -0,0 +1,31 @@ +# RFC:微内核——通过 Cordis 事件分类体系实现扩展,唯一具体循环 + +Status: implemented + +[English](2026-06-11-microkernel-event-taxonomy.md) | 中文 + +## 问题 + +产品原则是「一切皆插件」:钩子、/goal、/loop、动态工作流、上下文压缩(context compaction)、沙箱、权限、UI、持久化、MCP、skill(技能)都必须能以插件形式编写,而无需修改核心。 + +## 决策 + +纯 Cordis 事件分类体系(taxonomy)。循环的扩展 seam 是带有明确分发模式的类型化事件: + +- **waterfall(瀑布式事件)**(around-middleware):插件可以变换、否决或包装:`agent/prompt-submit`、`agent/request`、`agent/step-result`、`agent/turn-continuation`、`tools/pre-execute`、`tools/execute`、`tools/post-execute`、`llm/stream`、`system-prompt/assemble`。 +- **serial**(按监听器顺序依次 await;bail 值会阻止后续监听器):用于有序检查点。所有 `agent/pre-step` 监听器在全部弃权时都会运行,而 `agent/turn-stop` 返回的第一个 stop 值即为最终的终止决策。 +- **parallel**(await 扇出):每个监听器都必须获得独立执行机会:`session/flush` 持久性检查点。 +- **emit**(同步 fire-and-forget):用于通知:轮次/步骤边界、流式分片、生命周期、错误,以及包含不可变 `tools/result` 观测值的事件。 + +事件词汇定义在接口包中(dsh-agent 声明 agent/* 事件);`@deepseek-ai/dsh-agent-loop` 是唯一的具体循环插件,且本身可替换——它之外的任何代码都不得依赖它。 + +## 曾考虑的替代方案 + +**专用中间件栈(koa-compose 风格)** 与 **插件插入其中的显式阶段状态机**:两者都需要重新实现分发、dispose(资源释放)和重载语义,而 Cordis 原生事件系统已经提供了这些;作为 Cordis effect,监听器天然获得 HMR(热模块替换)和 dispose 能力。 + +## 后果 + +- 每个 MVP 功能都映射到一个监听器([功能→机制映射](../../../cookbook/extension-cookbook.md#the-feature--mechanism-map)是证明义务,保持最新)。 +- HMR 和 dispose 免费获得:监听器和注册都是 Cordis effect。 +- waterfall 语义(调用 `next()` 或短路)不直观,需要教学——已在 AGENTS.md 中记录,并由组合测试覆盖。 +- 循环必须具备防御性:插件异常在轮次级别被隔离,来自任何 seam 的 steering(中途引导)绝不会被搁置(有回归测试保障)。 diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml new file mode 100644 index 0000000000..8e7b36b58d --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-runtime-arg-validation.md: 6da117643166d304bee1d368a314cc1602cac828 +2026-06-11-runtime-arg-validation.zh.md: fb67568da3bfc7f1f8fcc0429b6c68193e04693a diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md index 33bf241c74..6da1176431 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md @@ -1,5 +1,7 @@ # RFC: Runtime arg validation at the model boundary +English | [中文](2026-06-11-runtime-arg-validation.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md new file mode 100644 index 0000000000..fb67568da3 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md @@ -0,0 +1,24 @@ +# RFC:模型边界处的运行时参数校验 + +Status: implemented + +[English](2026-06-11-runtime-arg-validation.md) | 中文 + +## 问题 + +`defineTool`([自定义 schema DSL](2026-06-11-custom-schema-dsl.md))通过 `InferArgs<S>` 映射为工具作者提供了类型化的 `execute(args)`。但该类型只是编译期对一个运行时值的声明:这个值以模型生成的 JSON 形式到达,没有任何机制强制模型遵守 schema。因此,一次格式错误的调用(缺少必填键、声明为数字的位置传入字符串、枚举值超出集合)会以「仅有类型之名」的状态抵达 `execute`。工具体要么在错误形状上崩溃(产生一条模型无法据以行动的通用堆栈跟踪),要么更糟:静默地行为异常。与此同时,转换器已经编码了校验器遍历所需的完整结构。 + +## 决策 + +`validateArgs(spec, args): string[]` 对一个运行时值解释 `SchemaSpec`,返回人类可读的违规列表(空 = 合法),且是全函数(从不抛出异常)。`defineTool` 在调用类型化的工具体之前运行它;如果存在违规,则抛出 `ToolArgsError`(`code: 'INVALID_ARGS'`,消息列出违规项),注册表既有的 execute-waterfall catch 将其转为模型可读取并据以自我修正的 `isError` 结果。 + +校验器严格镜像 `schemaSpecToJsonSchema` 的语义:遍历相同的结构、执行相同的规则:顶层必须是非数组对象;必填键仅来自 `required: true`;允许额外键(不设 `additionalProperties: false`);不应用 `default`;没有 `properties`/`items` 的 `object`/`array` 属性仅做类型检查;`enum` 是成员判定。原始注册的(MCP)工具不受影响:它们自行校验输入。 + +## 后果 + +- 模型在自身格式错误的调用上获得可操作的反馈,而非不透明的崩溃,弥合了 `InferArgs` 的承诺与运行时现实之间的鸿沟。 +- 校验器与 `InferArgs` 必须保持一致;一组[属性测试](../testing/2026-06-11-property-based-testing.md)会生成满足 spec 的参数并断言它们通过 `validateArgs`(同时断言定向破坏的参数被拒绝),以机械方式封堵漂移风险。 +- `ToolArgsError` 目前是一个带 `code` 字段的普通 `Error`;如果日后引入 harness 级别的错误分类体系,它将变为子类,而不影响读取 `.message` 的调用方。 +- 校验开销相对于一次模型调用可忽略不计。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml new file mode 100644 index 0000000000..84528dccf1 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-structured-error-taxonomy.md: 2baf88a1f942215e79561e565f455276c80178c4 +2026-06-11-structured-error-taxonomy.zh.md: f4762c4e92fb94c5bdbccc5f9a61e1496dc4c66d diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md index 01e50da2ff..2baf88a1f9 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md @@ -1,5 +1,7 @@ # RFC: Structured error taxonomy +English | [中文](2026-06-11-structured-error-taxonomy.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md new file mode 100644 index 0000000000..f4762c4e92 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md @@ -0,0 +1,26 @@ +# RFC:结构化错误分类体系 + +Status: implemented + +[English](2026-06-11-structured-error-taxonomy.md) | 中文 + +## 问题 + +错误跨越服务边界时只是裸字符串。工具错误被扁平化为一个文本块——name、code 和 stack 全部丢失——导致未来的沙箱/重试插件无法区分 ENOENT 和 EACCES,模型得到的反馈也不如本可以获得的那样可操作。非 Error 的 throw 退化得更严重:agent loop(智能体循环)将其包装为 `new Error(String(x))`,丢弃了所有 code。而 `LlmError` 是系统中唯一的类型化错误,没有共享基类,消费方无法对一个通用基类做 `instanceof`。 + +## 决策 + +在 `dsh-llm`(叶子包(package),所有其他包都已依赖它——不引入新的依赖边)中建立一个 `HarnessError extends Error` 基类:稳定的 `code`(与 `message` 分离)、通过 `ErrorOptions` 的 `cause` 链式传递、`name` 默认为子类名。`isHarnessError` 在服务边界处做类型收窄。 + +- `LlmError`、`ToolArgsError`(dsh-tools)和 `InvariantError`(dsh-invariants)现在继承该基类,保留各自既有的 code。 +- `ToolExecutionResult` 新增可选字段 `error: { name, code }`,在注册表的 catch 中当抛出值为 `HarnessError` 时填充。agent loop 将其转发到 `tool/result` 会话事件(该事件也新增了同一可选字段),使结构化的失败信息存入日志,供重试/沙箱插件和回放使用。面向模型的文本块不变。 +- agent loop 的 `toError` 将非 Error 的 throw 包装为 `HarnessError`(`code: 'UNKNOWN'`,原始值通过 `cause` 链接),而非裸 `Error`;这样即使是不规范的 throw 也能携带可路由的 code 进入会话的 `error` 事件(该事件已暴露 `code`)。 + +## 后果 + +- 错误在端到端链路上可被机器路由:插件可以按 `error.code` 分支,而非对 message 做子串匹配。 +- 一个基类被广泛导入,但它位于所有包本已依赖的包中,代价只是一条 import 语句,而非一条新的依赖边。 +- `deriveMessages` 不会将 `error` 字段呈现到模型历史中——模型仍然看到文本块;结构化字段服务于代码逻辑和回放。 +- 参数校验与开发不变式保留各自既有的 code 和行为;共享基类添加了跨服务边界的路由元数据,不改变面向模型的文本。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml new file mode 100644 index 0000000000..c0625866a3 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-tool-schemas-in-prompt-assembly.md: 443e6f20115e5a76001b4466c2d756675adbd886 +2026-06-11-tool-schemas-in-prompt-assembly.zh.md: 2d23d6fd0ead17fbeed3feaf3cec864813ef47e4 diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md index 5c78ef4280..443e6f2011 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md @@ -1,5 +1,7 @@ # RFC: Tool schemas are part of the system-prompt assembly +English | [中文](2026-06-11-tool-schemas-in-prompt-assembly.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md new file mode 100644 index 0000000000..2d23d6fd0e --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md @@ -0,0 +1,23 @@ +# RFC:工具 schema 属于系统提示词组装的一部分 + +Status: implemented + +[English](2026-06-11-tool-schemas-in-prompt-assembly.md) | 中文 + +## 问题 + +在协议格式(wire format)层面,工具 schema 通过模型请求中专用的 `tools` 字段传输,而非嵌入提示词文本。但从架构角度看,「模型被告知它能做什么」是一个内聚的关注点:提示词段落和工具列表由同一批插件贡献组装而成,并在同一时刻被消费。 + +## 决策 + +`PromptAssembly { sections, tools }`:系统提示词服务同时收集有序的文本段落和工具 schema(工具注册表自动贡献一个提供方)。agent loop(智能体循环)每步消费一个 assembly;适配器将 `sections` 映射到提供方的 system 槽位,将 `tools` 映射到协议格式的 `tools` 字段。因此 `system-prompt/assemble` waterfall(瀑布式事件)是模型前置信息的唯一拦截点——工具过滤(ToolSearch / 渐进式披露)是一次 assembly 改写,与提示词编辑无异。 + +## 曾考虑的替代方案 + +**循环分别向工具注册表和提示词服务查询**——将一个内聚的关注点拆到两个 seam 上;任何想塑造「模型被告知什么」的拦截(工具过滤、plan 模式)都需要在两个接口上各挂一个监听器,而非一次 assembly 改写。 + +## 后果 + +- 一条 waterfall 统管模型的常驻上下文;plan 模式等插件可以在一个监听器中同时替换提示词文本和可见工具。 +- assembly 接口通过声明合并实现可扩展(无需无类型的 `extras` 包——扩展即声明合并)。 +- 「schema 出现在提示词服务中」有轻微的概念意外感,本文与 package README 对此做了说明。 diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml new file mode 100644 index 0000000000..25e7f01d0f --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-13-capability-seams.md: e9d417dbd2bafcaece39601b12dbb310feb1e19b +2026-06-13-capability-seams.zh.md: e5d9be803f71ef3b85f79ed483dab64612a27fc7 diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md index 907e4cd86b..e9d417dbd2 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md @@ -1,5 +1,7 @@ # RFC: Capability seams — interface / implementation / consumer split +English | [中文](2026-06-13-capability-seams.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md new file mode 100644 index 0000000000..e5d9be803f --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md @@ -0,0 +1,32 @@ +# RFC:能力 seam——接口/实现/消费方拆分 + +Status: implemented + +[English](2026-06-13-capability-seams.md) | 中文 + +## 问题 + +harness 具有可替换的能力:目前是 bash 执行,未来会有沙箱/远程执行器和替代模型提供方。一项能力有三个关注点,它们以不同的速率、出于不同的原因变化:*契约*(这项能力是什么)、*实现*(它如何运行)、*消费方接口*(模型和其他插件面对什么来编程)。将三者打包在一个 package 中会耦合这些变化速率:把本地执行器换成沙箱执行器时,模型看到的工具 schema 也会被搅动,尽管面向模型的契约从未改变。 + +这与「运行时谁提供、谁需要一项能力」是不同的问题,后者 Cordis 已经用 service + `inject` 回答了(提供方注册 `ctx.bash`;消费方声明 `inject: ['bash']`,其 fiber 挂起直到该服务存在)。那套机制是必要的,但它不决定 package 边界;本 RFC 决定。 + +## 决策 + +一项可替换的能力拆为**三个 package**: + +1. **接口**:一个抽象 service 加词汇类型,拥有 `ctx.<key>`,仅依赖 cordis(例如 `dsh-bash`:`BashExecutor`、`BashRunResult`、`BashTask`)。 +2. **实现**:一个具体子类,以插件形式加载(例如 `dsh-bash-local`:子进程、进程组 kill、spill-file 截断)。沙箱/远程后端是实现同一接口的兄弟 package。 +3. **消费方**:模型和插件看到的东西(例如 `dsh-tool-bash`:`bash`/`bash_output`/`bash_kill` 工具 schema)。消费方 `inject` 接口 key,从不导入实现类型。 + +实现与消费方随后独立演进:沙箱执行器替换 `dsh-bash-local` 时无需触碰任何工具 schema。 + +当各部分确实属于同一关注点时,拆分并非强制:LLM seam 将接口 + 消费方合并为 `dsh-llm`(消费方是 agent loop(智能体循环)本身,而非可替换的 schema 表面),适配器作为实现 package。不要预防性拆分:只有一种可设想的实现和一个消费方的能力保持为一个 package,直到第二个出现。 + +## 曾考虑的替代方案 + +- **合并为一个 package**:否决,因为它重新耦合了拆分所要分离的三种变化速率(这正是拆分的全部意义)。 +- **`@cordisjs/plugin-capability`**:完全不同的维度。它是一个权限/能力*安全*服务(带继承的命名权限,通过 `ctx.capability.test` 对会话进行检测),是延后的权限/沙箱工作(`tools/pre-execute` deny/ask seam)的候选方案,而**不是**替换实现的机制。混淆这两个「能力」正是本 RFC 所指出的陷阱。 + +## 后果 + +每项能力多出更多 package 和更多样板代码(一套 `package.json`/`tsconfig`/README,加上 inject 接线)。换来的是:实现与消费方独立发布和版本化,新后端永远不会波及面向模型的契约。该规则记录在 [AGENTS.md](../../../../AGENTS.md) § Conventions("Capability seams are three packages")和 [architecture.md](../../../architecture.md) § "Capability seams" 中;bash 三件套是参考模板。何时合并、何时拆分是一个判断性决策,架构文档已做说明——本 RFC 记录的是*为什么*默认选择拆分。 diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml new file mode 100644 index 0000000000..a46193a7cd --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-13-twin-llm-adapters.md: 4efefcf4e2f6b1d60567ba3bfed7ae1ea53a7a4e +2026-06-13-twin-llm-adapters.zh.md: 806eea84ff3e6c4de988348964429ccaea27f4ba diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md index 0ded28f598..4efefcf4e2 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md @@ -1,5 +1,7 @@ # RFC: Two LLM adapters as a design-verification twin +English | [中文](2026-06-13-twin-llm-adapters.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md new file mode 100644 index 0000000000..806eea84ff --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md @@ -0,0 +1,27 @@ +# RFC:以两个 LLM 适配器作为设计验证孪生 + +Status: implemented + +[English](2026-06-13-twin-llm-adapters.md) | 中文 + +## 问题 + +`dsh-llm` 拥有一套提供方无关的流式输出词汇:`StreamChunk` 协议(`block-start`、`text-delta`、`reasoning-delta`、`tool-call-delta`、`block-end`、`usage`、`finish`)以及内容块类型([内容块词汇](2026-06-11-content-block-vocabulary.md))。如果词汇只针对单一适配器定义,就有把该适配器的怪癖烘焙进「中立」契约的风险:那个唯一实现碰巧做了什么,就会变成事实上的规范;而抽象在第二个提供方到来之前都无法被验证——届时泄漏已经代价高昂。 + +## 决策 + +从一开始就针对同一份契约交付**两个**适配器,刻意基于不同的内部实现: + +- `dsh-llm-deepseek`:手写 `fetch` + SSE 解析,直连 DeepSeek API。 +- `dsh-llm-pi-ai`:通过 `@earendil-works/pi-ai` 库(有自己的事件词汇)访问同一端点。 + +它们强制执行的规则是:**凡是 StreamChunk 词汇无法同时为两个实现表达的东西,都是核心词汇的 bug**——立即暴露,而非等到下一个提供方才发现。这对孪生确定了现已记录在 `dsh-llm/src/types.ts` 中 `StreamChunk` 上的约定:usage 在 finish 之前发出、finish 之后不再有任何事件、工具调用的 `arguments` 全程为原始 JSON 字符串,以及消费方必须在两侧都处理的两条合法错误路径(从 `stream()` 抛异常,*或*以 `finish {kind:'error'|'aborted'}` 结束)。后一项分歧正是由库封装的适配器暴露出来的,单一手写适配器会将其掩盖。 + +## 曾考虑的替代方案 + +- **单一适配器**:代码更少、e2e 成本减半,但「提供方无关」的声明无法验证;词汇会默默编码 DeepSeek-via-fetch 的假设。 +- **mock 第二适配器**:更便宜,但不会触及真实提供方的协议格式(wire format)怪癖,因此证明力有限。孪生是真实对真实。 + +## 后果 + +孪生使适配器和需要密钥的 e2e 维护量翻倍——两者都覆盖 V4 Flash 和 Pro 在各代表性推理模式下的表现——换来的是对 seam 中立性的持续验证和第二份实现示例。两者都使用 `apiKey`、`baseURL` 和 `models`;手写适配器暴露 `thinking`/`reasoningEffort`,pi-ai 适配器暴露一个 `reasoning` 级别。未来的一致性测试套件可以通过一份取代性 RFC 来论证退役其中一个适配器。 diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml new file mode 100644 index 0000000000..3858139410 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-14-session-persistence.md: 4078487b71862791dd25cf2afcfc03255cfeb0be +2026-06-14-session-persistence.zh.md: 801632b56d2056b36dbf7869f5114d74599bd5d5 diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md index 327aa8eac3..4078487b71 100644 --- a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md @@ -1,5 +1,7 @@ # RFC: Session persistence as an abstract service over the existing `SessionEvent` +English | [中文](2026-06-14-session-persistence.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md new file mode 100644 index 0000000000..801632b56d --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md @@ -0,0 +1,36 @@ +# RFC:会话持久化——基于既有 `SessionEvent` 的抽象服务 + +Status: implemented + +[English](2026-06-14-session-persistence.md) | 中文 + +## 问题 + +会话此前只存在于内存中。示例插件 `session-jsonl.ts`(在两个 examples 目录中逐字节重复)是只写的遥测:它缓冲 `session/event` 并追加 JSON 行,没有读取/回放路径,没有崩溃安全性(无 fsync、无原子写入、dispose 时 fire-and-forget 地排空缓冲区),没有列表功能,也没有格式版本控制。没有任何东西能把磁盘上的历史会话重新注入一个活跃的 agent,因此持久恢复(「继续昨天的任务」)、持久 fork,以及 ACP 的 `session/load` 方法([ACP 支持](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md))都不可能实现。 + +[事件溯源模型](2026-06-11-event-sourced-sessions.md)将仅追加日志作为唯一真源,并从中派生 LLM 历史。持久化必须忠于这一点:直接持久化既有的 `SessionEvent`,不引入需要来回转换的并行「持久化消息」类型。后端也必须可替换——当前是文件存储,将来是数据库存储——统一在一个接口之后。 + +## 决策 + +持久化是一个抽象的**能力 seam**([能力 seam](2026-06-13-capability-seams.md),`dsh-bash` 模板),而非循环或核心逻辑: + +1. **接口**(`dsh-session-persistence`,`ctx.sessionPersistence`):一个抽象的 `SessionPersistence` 服务,提供 `create`/`append`/`load`/`list`。其持久化单元就是既有的 `SessionEvent`(`{ type, seq, time, data }`),逐字复用,无转换类型。 +2. **实现**(`dsh-session-persistence-jsonl`):每个会话一个仅追加的 JSONL 日志(一行 `SessionHeader`,之后每行一个 `SessionEvent`,逐字保留**包括 `assistant/chunk`**)。 + +以下关键选择记录于此,因为它们是持久的、有争议的、且出人意料的: + +- **规范持久日志逐字保留每个 `SessionEvent`,包括 `assistant/chunk`。** `deriveMessages()` 跳过 chunk,过滤 chunk 的方案(Codex 的 `policy.rs`)很有吸引力,但 `seq = log.length` 以及加载校验 `events[i].seq === i` 要求日志*连续*;过滤掉 chunk 会留下空洞,同时破坏契约和恢复功能。未来可以将过滤 chunk 的投影作为带独立重编号的派生视图,但它不是规范日志。 +- **仅追加;崩溃的轮次被关闭,而非截断。** 已刷写的 `turn/end` 之前的事件永不重写,且循环只在轮次结束时刷写。由于一个被中断的轮次可能包含大量有效工作,`load` 会保留其中连续且可解析的事件,并为未应答的工具调用追加错误结果、补一个缺失的 `step/end`,以及带 `{ kind: 'interrupted' }` 的 `turn/end`。这些合成结果使恢复后的 provider transcript 保持有效。只有不完整的最后一条记录会被丢弃;如果在最后一个真实 `turn/end` 或之前出现解析错误或序号间隙,则视为损坏,该会话不可加载。 +- **文件后端为规范实现,数据库后端为已验证的可替换方案。** `SessionEvent` 1:1 映射为一行 `(session_id, seq, type, time, data)`:`append` 是 INSERT(在一个断言连续 seq 契约的事务中),`load` 是 SELECT … ORDER BY seq。`dsh-session-persistence-sqlite` 正是如此:一个 `SessionPersistence` 子类,接口不变(opencode 在 SQLite/WAL 上运行的正是这个形状),且它通过与 JSONL 后端相同的 `runPersistenceContract` 套件——因此契约以相同的语义(惰性物化、加载时关闭中断轮次、连续 seq)约束两个后端,一次表达在文件字节上,一次表达在行上。 +- **元数据在日志之外。** 格式版本、cwd 和谱系是存储关注点,不是可回放的对话状态,因此它们存放在 `dsh-session` 拥有的 `SessionHeader` 中,通过新的只读属性 `session.header` 附加到 `Session`——永远不在 `SessionEventMap` 中,永远不会到达 `deriveMessages()`。替代方案(一个可合并扩展的 `session/meta` 事件作为日志第 0 行)被否决:日志内事件在 seed/fork 会话时可以免费携带,但元数据不是可回放状态,因此显式的日志外 header seam 是更干净的代价。(header 最初被拆分为不可变的 `SessionHeader` 加可变的 `SessionSummary`,二者的联合类型为 `SessionMeta`;可变 summary 后来因为是死状态而被移除——见 [移除可变会话摘要](../simplification/2026-06-19-drop-mutable-session-summary.md)。) +- **`ctx.agents.create()` 与 `ctx.agents.resume()` 是异步工厂;resume 还额外跨越持久化边界。** `ctx.agents.resume({ resumeSessionId })` 等待 `ctx.sessionPersistence.load`,用加载的事件重建活跃会话(使 `lastTurnNumber`/`deriveMessages` 继续),并在恢复的 id 上启动一个新 agent(不是 `${agentId}-session`)。agent loop 不会硬注入 `sessionPersistence`(那会让非持久化的演示永远挂起);当 `sessionPersistence` 不存在时,`resume` 以明确的错误拒绝。 + +## 曾考虑的替代方案 + +上述每个关键选择在陈述时已记录了其被否决的替代方案:**过滤 chunk 的规范日志**(Codex 的 `policy.rs` 形状)——破坏连续 seq 契约;**截断崩溃的轮次**——静默销毁长时间自主运行的真实工作;**日志内 `session/meta` 事件作为第 0 行**——元数据不是可回放状态;**将 `sessionPersistence` 硬注入循环**——会让非持久化的演示永远挂起。 + +格式版本控制:header 携带一个 `version`;`load` 拒绝任何非当前版本(不做迁移——预发布的会话格式固定在 `SESSION_FORMAT_VERSION = 0`,按 AGENTS.md 的预发布立场吸收形状变动)。坦率地说:仅追加 + 刷写对部分尾部写入(加载时容忍)是健壮的,但对行写入中途的无 fsync 断电不健壮;数据库/WAL 后端是将来更强的选项。 + +## 后果 + +新增两个包(package),以及 `dsh-session` 中的元数据 seam(`session.header`、`create(id?, options?)` 签名)。收获:持久恢复/fork、读取/回放路径、崩溃容忍,以及 ACP `session/load`([ACP 支持](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md))所需的基础——全部建立在既有的事件溯源日志之上,后端可在一个接口后替换。可复用的 `runPersistenceContract` 套件以相同的仅追加、连续 seq、惰性物化与可序列化语义约束每个后端。持久化完整日志还确定了事件保真度:`assistant/chunk` 保持逐字保留。 diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml new file mode 100644 index 0000000000..545fdae4ff --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-15-turn-enclosure-invariant.md: bf0789f21ba7bd928e023bb5fd844d9ec78c4bc1 +2026-06-15-turn-enclosure-invariant.zh.md: 9f6f69b923ed7feff51122c4e4040bff3c9db8ea diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md index e55cd0853e..bf0789f21b 100644 --- a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md @@ -1,5 +1,7 @@ # RFC: Every session event is enclosed in a turn +English | [中文](2026-06-15-turn-enclosure-invariant.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md new file mode 100644 index 0000000000..9f6f69b923 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md @@ -0,0 +1,42 @@ +# RFC:每个会话事件必须包含在一个轮次内 + +Status: implemented + +[English](2026-06-15-turn-enclosure-invariant.md) | 中文 + +## 问题 + +持久化的会话持久化后端(在一个配套变更中引入)以**轮次**作为崩溃恢复边界:崩溃可能留下一个未关闭的最终轮次,`load` 会用一个合成的 `turn/end {kind:'interrupted'}` 将其关闭,同时保留该轮次的真实事件(见[会话持久化](2026-06-14-session-persistence.md))。这种恢复只有在没有任何*合法的*持久化事件位于轮次之外(即上一个 `turn/end` 与下一个 `turn/start` 之间的间隙)时才是良定义的,否则这类事件会被裹入下一个轮次的中断关闭中。 + +该假设并不成立。有两条路径在轮次之外记录了事件: + +1. **排队的用户消息。** agent loop(智能体循环)排空排队消息并在 `turn/start` **之前**追加 `user/message`,导致一个轮次自身的提示词落在前一个 `turn/end` 与下一个 `turn/start` 之间的间隙中。 +2. **空闲时的上下文注入。** `agent.inject()` 直接追加一条 `context/message`。它在生产环境中的实际调用方是 `dsh-tool-bash`,后者从 `ctx.bash.onTaskDone` 注入后台任务完成通知——该回调在后台 bash 任务完成时触发,经常发生在 agent **空闲**(两个轮次之间)时。 + +对于情况 2,如果注入的 `context/message` 是 flush/dispose 之前的最后一个事件(之后没有轮次追加 `turn/end`),`scanLog` 会将其视为崩溃残留并**在恢复时丢弃**——注入的上下文虽然已持久化到磁盘,但在重新加载时被静默丢失。情况 1 单独来看是无害的(`user/message` 之后总是紧跟它触发的轮次),但使得「什么可以出现在轮次之外」这条规则变得模糊。 + +## 决策 + +**每个会话事件都位于一个轮次内部**——在一个 `turn/start` 与其匹配的 `turn/end` 之间。具体而言: + +- agent loop 在 `turn/start` **之后**(轮次内部)追加排队的 `user/message` 事件,而非在其之前。因此,这些消息一经记录,`turn/end` 就已被承诺,而现有的 finalizer 保证了这一点。 +- 在 agent **运行中**调用 `agent.inject()` 时,其 `context/message` 追加到已打开的轮次中(行为不变)。 +- 在 agent **空闲时**调用 `agent.inject()`,系统将 `context/message` 包裹在一个一次性轮次中:`turn/start{trigger:{kind:'injection'}}` → `context/message` → `turn/end{completed}`。一个新的 `injection` 变体加入可合并扩展的 `TurnTriggerMap`。 +- agent loop 每次迭代从日志推导下一个轮次编号(`lastTurnNumber(session) + 1`),而非维护一个私有计数器,因此空闲注入的一次性轮次不会与下一个真实轮次的编号冲突。 +- `dsh-invariants` 插件在开发模式下**强制执行**该不变式:在没有打开的轮次时追加 `user/message`/`context/message`/`steering/message` 会抛出 `InvariantError`。 + +可序列化性不变式在同一个源码边界强制执行(`Session.append` 对不可 JSON 序列化的数据抛出异常),因此「什么可以进入日志」现在由一处统一管控,而非由下游恰好在监听的某个后端去发现。 + +## 曾考虑的替代方案 + +**放宽读取端而非约束生产端**——让 `scanLog` 提交位于已打开轮次之外的事件。否决:一条可检查的生产端规则优于一条更宽松的边界扫描逻辑,后者需要同时推理部分轮次*和*轮次间的散落事件。 + +## 后果 + +轮次现在是*唯一的*持久化/回放边界,因此[会话持久化](2026-06-14-session-persistence.md)的崩溃恢复规则是完备的,而不仅仅是充分的:一个被中断的最终轮次会被关闭(用合成的 `turn/end {interrupted}`),其真实事件被保留,且完全不存在将轮次间上下文混入其中的风险,因为不再有轮次间上下文。`scanLog` 保持简单(至多一个可能未关闭的最终轮次,永远没有散落的轮次间事件),空闲时的后台任务通知在持久化 + 恢复后得以存活。 + +代价:空闲时调用 `agent.inject()` 现在写入三行日志而非一行,且推导出的历史中多出一个仅包含注入上下文(无 assistant 输出)的轮次——`deriveMessages()` 本就纯粹按事件类型推导,因此渲染结果不变。`injection` 触发器是一个新的磁盘词汇值;与每一个 `SessionEventMap`/`TurnTriggerMap` 的新增项一样,它属于冻结格式的一部分。轮次内的事件顺序发生了变化(`turn/start` 现在先于 `user/message`),这对任何断言旧顺序的代码是可观测的——agent loop 自身的测试是唯一的此类消费方。 + +该规则有意采用生产端强制执行 + 开发模式检查的方式,而非读取端容忍:未来的后端(SQLite/WAL)可以免费继承同样干净的边界,而在轮次外记录事件的插件会在开发模式下大声失败,而非在下次重新加载时静默丢失数据。 + +轮次内检测到的失败在 `turn/end` 之前记录。之后的 flush 失败没有合法的轮次内位置,因此通过 `agent/error` 和日志报告,而非作为会话事件追加。这保持了回放日志的平衡;持久化的运维诊断需要一个独立的遥测通道。 diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml new file mode 100644 index 0000000000..5d92edb79a --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-17-filesystem-capability-seam.md: c502ae712de22e97661192057d4410c7c55ea044 +2026-06-17-filesystem-capability-seam.zh.md: 01a4318237ebbd29fe3effa3f8528b6e4a5132d6 diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md index 71efeff826..c502ae712d 100644 --- a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md @@ -1,5 +1,7 @@ # RFC: Filesystem capability seam — ctx.fs, local backend, and model-facing filesystem tools +English | [中文](2026-06-17-filesystem-capability-seam.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md new file mode 100644 index 0000000000..01a4318237 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md @@ -0,0 +1,160 @@ +# RFC:文件系统能力 seam——ctx.fs、本地后端与面向模型的文件系统工具 + +Status: implemented + +[English](2026-06-17-filesystem-capability-seam.md) | 中文 + +## 问题 + +harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` / `dsh-tool-bash`),但文件系统操作即将作为面向模型的工具加入,却没有等价的 seam。如果 `read`、`write` 和 `edit` 直接使用 `node:fs`,面向模型的工具包将同时拥有文件系统执行策略、本地路径解析、原子写入行为、文本解码、符号链接行为和编辑语义。 + +这把三个独立变化的关注点耦合在了一起: + +1. 文件系统契约:插件可以请求哪些操作。 +2. 后端:当前是本地磁盘,未来可能是沙箱/远程/项目范围的文件系统。 +3. 消费方接口:面向模型的 `read` / `write` / `edit` schema 与结果格式化。 + +没有 `ctx.fs` 接口,将本地文件系统访问替换为沙箱或远程后端时,即使面向模型的契约应当保持稳定,也会搅动工具 schema、演示和提示词引导。这还使权限/沙箱边界更难推理:一个 `cwd` 选项看起来像沙箱,但除非有显式后端或 `tools/execute` 策略强制隔离,否则它只是一个基础路径。 + +我们需要让文件系统工具在成为公开包接口之前,以与 bash 相同的能力 seam 形态落地。 + +## 决策 + +文件系统访问是一个一等能力 seam,遵循[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md): + +1. `@deepseek-ai/dsh-fs`(`packages/fs/fs`)拥有抽象的 `ctx.fs` 服务、文件系统词汇类型,以及 `fs/*` 策略事件词汇。 +2. `@deepseek-ai/dsh-fs-local`(`packages/fs/fs-local`)提供第一个实现,以本地文件系统为后端。 +3. `@deepseek-ai/dsh-tool-fs`(`packages/fs/tool-fs`)通过 `ctx.fs` 提供面向模型的 `read`、`write` 和 `edit` 工具,并作为执行器分发 `fs/*` 事件。 + +消费方包仅依赖接口包,从不依赖 `dsh-fs-local`。需要不同后端的部署只需为 `ctx.fs` 加载不同的提供方,无需改动工具 schema 或面向模型的提示词引导。 + +先读后写/编辑与已观察状态策略是第四个包 `@deepseek-ai/dsh-fs-policy`(`packages/fs/fs-policy`),通过 `fs/*` 事件门而非 `ctx.fs` 方法贡献;加载 `dsh-tool-fs` 的部署同时加载 `dsh-fs-policy` 以获得先读后写/编辑能力。本 RFC 确立了三包 seam;策略从提供方基类拆出的决策见 [split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md),其作为事件门插件(而非方法服务)的实现见 [event-gate RFC](2026-06-26-file-context-as-event-gate.md)。本文已更新为描述最终落地的四包形态。 + +第一个后端刻意仅限本地:`dsh-fs-local` 针对宿主文件系统实现 `ctx.fs`。未来的兄弟后端可以在同一接口后面提供沙箱、远程、虚拟或项目范围的文件系统。 + +第一个消费方刻意仅限文本文件:`dsh-tool-fs` 暴露面向模型的 `read`、`write` 和 `edit` 工具,处理 UTF-8 文本文件。未来的消费方可以添加目录列表、搜索/glob、二进制安全操作、文件监听或更高层的项目操作,只要所需能力存在于 `ctx.fs` 上,就无需改动本地后端包。直接目录列表后来由 [Add direct directory listing to the filesystem seam](2026-07-03-filesystem-directory-listing-seam.md) 添加。 + +文件系统权限和沙箱并非此拆分所隐含。本地后端从其配置的基础目录解析相对路径,但隔离策略是独立决策:要么由更严格的 `ctx.fs` 实现强制执行,要么由权限/沙箱插件包装 `tools/execute` 并在调用到达消费方之前否决。 + +先读后写/编辑与已观察状态属于 `dsh-fs-policy`,而非 `ctx.fs`。通过 `fs/*` 事件门,策略按不透明 actor 记录版本,并提供可选的变更期望;提供方原子性地强制新鲜度。`dsh-tool-fs` 发出事件但不依赖策略。详见 [split-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 与 [event-gate](2026-06-26-file-context-as-event-gate.md) RFC。 + +## 包拓扑 + +文件系统 seam 使用与 bash 三件套相同的依赖方向: + +```text +@deepseek-ai/dsh-tool-fs --depends on--> @deepseek-ai/dsh-fs <--depends on-- @deepseek-ai/dsh-fs-local + consumer interface implementation +``` + +`@deepseek-ai/dsh-fs` 仅依赖 `cordis` 和来自 `@deepseek-ai/dsh-llm` 的仓库级 `HarnessError` 基类。它声明 `ctx.fs` 键、抽象 `FileSystem` 服务、后端与消费方共享的词汇类型、文件系统错误词汇,以及 `fs/*` 策略事件词汇。它不持有已观察状态存储,也不持有 owner 推导形态;事件传递一个不透明的 `object` actor,提供方从不读取它,`dsh-fs-policy` 插件在这些事件之上拥有 owner 推导形态和已观察状态存储。 + +`@deepseek-ai/dsh-fs-local` 依赖 `@deepseek-ai/dsh-fs` 和 `cordis`。它继承 `FileSystem`,将自身注册为 `ctx.fs`,拥有本地后端配置(如基础目录),并包含所有直接的 `node:fs` / `node:path` 访问。它不持有已观察状态存储:新鲜度是后端铸造、策略插件记录的版本令牌。 + +`@deepseek-ai/dsh-tool-fs` 依赖 `@deepseek-ai/dsh-fs`、`@deepseek-ai/dsh-tools`、`@deepseek-ai/dsh-system-prompt` 和 `cordis`。它注册面向模型的工具和提示词段落。它禁止导入 `node:fs`、`node:path` 或 `@deepseek-ai/dsh-fs-local`;文件系统执行始终通过 `ctx.fs`。如果实现需要具体的 agent 或会话辅助类型,这些依赖属于 `tool-fs`;它们禁止回漏到 `dsh-fs`。 + +根 `tool-fs` 插件通过组合各工具的注册辅助函数来注册完整的文件系统工具套件(`read`、`write` 和 `edit`)。它注入 `fs`,从不导入实现包。 + +## `ctx.fs` 契约 + +`@deepseek-ai/dsh-fs` 拥有一个语义文件系统服务。它比 `readFile` / `writeFile` 更高层,这样 `tool-fs` 就不必重新实现路径解析、版本管理、文本解码、二进制拒绝、分页、原子替换、符号链接行为或字面编辑语义。 + +该接口覆盖以下语义操作: + +- 将模型/插件提供的路径解析为后端定义的目标。 +- 在不读取文件内容的情况下获取目标元数据。 +- 从目标读取有界的 UTF-8 文本页。 +- 创建或替换一个 UTF-8 文本文件。 +- 通过字面替换编辑一个已存在的 UTF-8 文本文件。 + +提供方 seam 还承载策略所依赖的新鲜度钩子,但已观察状态存储和 owner 推导位于 `dsh-fs-policy` 插件中,而非 `ctx.fs` 上: + +- 后端为每个目标铸造一个不透明的 `version` 令牌(在 `stat` 和每次读取/变更结果中)。 +- `writeText`/`editText` 接受一个可选的版本期望:省略它则执行无条件的裸提供方变更,提供它则在后端的原子临界区内守护变更。 +- `dsh-fs-policy` 插件在 `fs/write-intent`/`fs/edit-intent` 上决定该期望,并在 `fs/observed` 上记录已观察版本,以从不透明事件 actor 推导出的 owner 为键(通常是 `exec.agent.session`)。 + +授权基于版本新鲜度,而非完整/部分视图的区分:任何读取都记录目标的版本,后续的写入/编辑只要文件仍处于该版本即被授权——因此对第 100-150 行的窗口读取可以授权对第 120 行的编辑。已观察状态存储是 `dsh-fs-policy` 内部的 `WeakMap<owner, Map<targetKey, version>>`;`dsh-fs` 不持有任何此类数据,并将 actor 视为不透明。(本 RFC 最初建模了一个带 `full`/`partial` 视图的 `FileState` 缓存放在 `ctx.fs` 上;split-fs-seam 和 event-gate RFC 将其替换为此处描述的基于新鲜度的策略插件。) + +路径解析是显式的,允许异步。本地解析可能只做路径规范化,但沙箱/远程/项目范围的后端可能需要 I/O 才能将用户提供的路径解析为稳定的目标标识。 + +解析后的目标必须至少暴露三个概念: + +- 原始输入路径,用于诊断。 +- 不透明的 `targetKey`,用于过期守护和文件状态查找。本地后端可能使用类似 realpath 的键;远程后端可能使用工作区 URI 或文件 id。消费方禁止解析或假设它是本地绝对路径。 +- `displayPath`,用于面向模型/UI 的输出。根据后端不同,它可能是本地绝对路径、工作区相对路径或远程 URI。 + +读取和变更结果必须包含一个不透明的文件 `version`。本地后端可以使用 mtime/size 或类 hash 令牌;远程后端可以使用修订 id。`dsh-fs-policy` 插件记录版本用于过期检查;消费方可以展示相关元数据但禁止解释版本令牌。 + +提供方返回已解码的文本:`readText` 返回整个常规文本文件,`streamText` 以流式传输相同的文本语义用于大文件。二者都负责常规文件检查;有界行/输出处理不是它们的职责——行窗口、带行号渲染和总行数统计位于执行器(`dsh-tool-fs`)中,执行器通过 `ctx.fs` 读取并渲染面向模型的窗口。提供方负责 UTF-8 解码和二进制/NUL 拒绝;它不知道行窗口或视图。 + +已观察状态记录不在 `ctx.fs` 上:成功读取后执行器发出 `fs/observed`,`dsh-fs-policy` 插件为推导出的 owner 记录 `{ version }`。没有 `full`/`partial` 视图——任何窗口的读取都记录版本,新鲜度(而非视图完整性)授权后续的写入/编辑。 + +全文件写入创建或替换 UTF-8 文本文件。后端在支持且有文档说明时可以创建父目录。已存在的非常规目标被拒绝。`writeText` 接受一个可选期望:`createIfAbsent` 创建缺失的目标并在已存在时以 `FS_NOT_OBSERVED` 拒绝(这是策略为未观察 owner 使用的路径);`replaceIfVersion` 仅在目标处于已观察版本时替换,否则 `FS_STALE_VERSION`;省略期望则为无条件的裸提供方创建或覆盖。策略插件根据 owner 的已观察状态选择提供哪个期望。 + +字面编辑是提供方原语(`editText`),而非在 `tool-fs` 中由读取加写入组合而成。字面匹配、重复匹配拒绝、CRLF 保留、二进制拒绝、可选的过期版本检查和原子读-改-写必须一起留在后端的变更临界区内。`editText` 接受相同的可选版本期望;过期检查在字面匹配之前运行,因此针对旧读取的编辑会报告 `FS_STALE_VERSION`。远程后端可以将编辑实现为原生的 compare-and-edit 操作;消费方不强制本地式组合。 + +策略插件(而非 `ctx.fs`)对先前观察进行门控:`edit` 要求 owner 有先前观察(否则 `FS_NOT_OBSERVED`),记录的版本作为 CAS 基础传递给 `editText`。在策略插件缺席时,`ctx.fs` 单独是一个完整的无约束 seam(无条件写入/编辑);工具从不与策略方法耦合。 + +文件系统契约失败以 `FsError extends HarnessError` 抛出,工具注册表将其转换为带结构化 `{ name, code }` 元数据的 `isError` 工具结果。`dsh-fs` 拥有此词汇,而非由每个工具各自发明消息。错误码为 `FS_NOT_FOUND`、`FS_NOT_TEXT`、`FS_STALE_VERSION`、`FS_NOT_OBSERVED`、`FS_NOT_REGULAR_FILE`、`FS_AMBIGUOUS_EDIT`、`FS_EDIT_NOT_FOUND` 和 `FS_ABORTED`。(早期草案包含 `FS_PARTIAL_OBSERVATION`;基于新鲜度的授权没有 partial/full 区分,因此已移除。目录列表相关的错误码后来由 [Add direct directory listing to the filesystem seam](2026-07-03-filesystem-directory-listing-seam.md) 添加。) + +## 工具消费方行为 + +`@deepseek-ai/dsh-tool-fs` 是面向模型的消费方。它拥有工具名称、JSON Schema、模型边界的参数校验、提示词段落和结果格式化。它不拥有文件系统执行。 + +第一个工具套件包含: + +- `read`:检查一个 UTF-8 文本文件并返回带行号的内容与分页引导。 +- `write`:创建或完全替换一个 UTF-8 文本文件。 +- `edit`:通过替换字面文本更新一个已存在的 UTF-8 文本文件,默认要求唯一匹配,并允许显式的全部替换模式。 + +每个工具遵循相同的执行形态: + +1. 校验并规范化模型参数。 +2. 调用相应的 `ctx.fs` 操作。 +3. 将结果格式化为面向模型的 `ContentBlock[]`。 +4. 让抛出的后端/工具错误流经 `ToolRegistry.execute()`,由其转换为 `isError` 工具结果。 + +该包通过 `ctx.systemPrompt.section(...)` 注册提示词引导,通过 `ctx.tools.register(...)` 注册 schema。工具 schema 仍通过 `SystemPrompt.assemble()` 和 `ToolRegistry.schemas()` 流入正常的提示词组装路径;无需修改 agent loop。 + +工具包在后端变化时保持面向模型的契约稳定:本地后端和远程后端内部可能以不同方式解析路径,但 `read` / `write` / `edit` 的 schema 不会仅因后端变化而改变。 + +默认部署要求在用 `write` 或 `edit` 更新已存在文件之前先 `read`。`tool-fs` 不通过检查名为 `read` 的工具是否运行过来实现这一点:它分发 `fs/write-intent`/`fs/edit-intent` 事件(将执行上下文作为不透明 actor 传递),`dsh-fs-policy` 插件推导 owner、对先前观察进行门控并提供版本期望。任何窗口读取都能授权后续的写入/编辑,只要文件未变。用 `write` 创建新文件不要求先前观察。 + +根插件通过组合各工具的注册辅助函数来注册完整套件。它注入 `fs`、`tools` 和 `systemPrompt`。 + +## 测试 + +测试遵循包边界,而非仅覆盖用户可见的工具:`dsh-fs` 中的服务 seam;`dsh-fs-local` 中通过 `ctx.fs` 接口的真实文件系统行为(解析、符号链接、流式传输、二进制/UTF-8 拒绝、无条件与版本守护写入、字面编辑语义、行尾保留、结构化 `FsError` 错误码);`dsh-tool-fs` 中针对真实本地提供方的消费方接口(仅 mock 模型/时钟,从不 mock 协作者);以及通过 `ctx.tools.execute()` 在有无 `dsh-fs-policy` 两种情况下的集成测试,通过从磁盘回读文件来验证世界状态,而非信任返回的 `ContentBlock[]`。已观察状态/owner 推导策略在 `dsh-fs-policy` 中测试,不在此处。 + +本仓库曾踩过的防御性模式类别被直接固定: + +- **原子写入临时文件安全。** 写入/编辑通过目标旁边一个私有随机 `0700` 目录中的独占 owner-only(`'wx'`、`0o600`)临时文件暂存,失败时清理,最后原子 rename。这与 bash spill-file 规则一致,因为可预测的 world-readable 临时路径招致符号链接竞争和信息泄露。测试断言权限以及已存在的临时路径不会被覆盖;此原语是 seam 的常设要求。 +- **通过符号链接的 `targetKey` 同一性。** 两个输入路径解析到同一 realpath 时共享一个已观察状态条目:通过路径 A 的 `read` 满足通过符号链接路径 B 的 `edit` 的先读守护,通过一个路径的过期写入可通过另一个路径检测到。 +- **并发/过期竞争。** 两个并发的写入/编辑操作针对同一目标确定性地结算:一个成功,另一个以 `FS_STALE_VERSION` 被拒绝;成功的编辑刷新记录状态,使同一 owner 的下一次编辑可以继续。 +- **HMR 安全与 dispose。** 释放后端的 fiber 会撤回 `ctx.fs` 提供方;后续提供方启动时没有继承的状态。 + +## 曾考虑的替代方案 + +- **面向模型的工具直接使用 `node:fs`**:工具包将同时拥有执行策略、路径解析、原子写入、文本解码和编辑语义,耦合了「问题」一节所列的三个独立变化的关注点,且任何后端替换都会搅动 schema。 +- **单一合并包 `dsh-fs-tools`**:seam 之前的形态;出于与 bash 相同的接口/实现/消费方拆分理由被否决,且合并名称从未成为公开接口。 +- **已观察状态放在 `ctx.fs` 上**:本 RFC 最初落地的形态;被 [split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate RFC](2026-06-26-file-context-as-event-gate.md) 取代:沙箱/远程后端不应继承面向模型的观察策略,因此提供方仅保留版本令牌和可选的版本守护变更。 + +## 后果 + +**`cwd` 可能被误认为沙箱。** 本地后端的基础目录是解析默认值,而非自动的隔离边界。如果需要隔离,必须由后端契约或 `tools/execute` 上的权限/沙箱插件强制执行。 + +**接口可能变得过于本地化。** 如果 `ctx.fs` 返回 `absolutePath` 之类的字段,远程、沙箱或虚拟后端会变得尴尬。契约应暴露展示元数据,而不要求消费方理解宿主路径。 + +**接口可能变得过于薄。** 如果 `ctx.fs` 只镜像 `node:fs` 原语,`tool-fs` 将重新实现二进制检测、分页、原子写入和编辑语义。这会重新制造本 RFC 试图避免的耦合。 + +**编辑语义天然易受竞争影响。** 字面编辑是读-改-写操作;守护是后端的原子变更临界区加上可选的版本期望,因此并发编辑确定性地结算:一个赢,另一个得到 `FS_STALE_VERSION`。 + +**已观察状态不属于 `ctx.fs`。** 记录执行上下文看到了什么是工作流策略,而非原始文件系统 I/O。本 RFC 最初将其放在文件系统 seam 内;split-fs-seam RFC 随后确立:沙箱/远程后端不应继承面向模型的观察策略,并将其移入 `dsh-fs-policy` 插件。提供方 seam 仅保留写入/编辑安全在存储层真正需要的东西——后端铸造的版本令牌和可选的版本守护变更——而策略插件拥有 owner 推导、已观察状态和先读后编辑门控,通过 `fs/*` 事件实现。 + +**`resolve` 后操作的形态每次调用多一次往返。** 每个工具可能先将路径解析为 `FsTarget`,再作为单独的 `ctx.fs` 调用发起读取/写入/编辑。对本地后端而言这可以忽略(解析是内存中的路径规范化),但远程/沙箱后端可能将每一步变为独立请求,使单次 `read` 变成两次网络往返。往返开销重要的后端可以在内部缓存或折叠解析,同时保持可观察契约不变。 + +**已观察状态持久化被推迟。** 已观察状态存在于内存中(`dsh-fs-policy` 内部的 `WeakMap`),因此恢复的会话保守地要求文件在写入/编辑前重新读取,直到未来的会话事件或持久化机制使观察可回放。 + +**错误码成为 seam 的一部分。** `FsError` 错误码使过期版本和观察失败可通过既有的结构化错误分类体系进行机器路由。代价是 `dsh-fs` 从 `dsh-llm` 导入共享的 `HarnessError` 基类;该依赖是有意为之且仅限于错误词汇。 + +**包拆分的代价前置。** 三包拆分在只有一个后端时就增加了样板代码。这是有意为之:文件系统访问是可能的沙箱/远程边界,在面向模型的工具发布后再改变包接口代价更高。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml new file mode 100644 index 0000000000..85783f6ea4 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-18-agent-lifecycle-and-ownership-seams.md: a70e7db8d809efd68ae770995795fc7b3d1b83d2 +2026-06-18-agent-lifecycle-and-ownership-seams.zh.md: ac42a09c70e9570d3def0f0bd056bd571b923315 diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md index 665063399d..a70e7db8d8 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md @@ -1,5 +1,7 @@ # RFC: Agent lifecycle and ownership seams +English | [中文](2026-06-18-agent-lifecycle-and-ownership-seams.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md new file mode 100644 index 0000000000..ac42a09c70 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md @@ -0,0 +1,48 @@ +# RFC:Agent 生命周期与所有权 seam + +Status: implemented + +[English](2026-06-18-agent-lifecycle-and-ownership-seams.md) | 中文 + +## 问题 + +ACP(Agent Client Protocol)与 tool-bash 的若干限制是同一个缺失 seam 的不同症状:插件可以通过 `ctx.agents` 创建或恢复 agent,但无法独立拥有并 dispose(资源释放)单个 agent;长时间运行的 bash 任务在执行器内部也没有稳定的所有者。ACP 在断开连接时中止并等待 agent,却无法只注销该会话的 agent;`session/cancel` 无法取消已排队但尚未开始的工作;`tool-bash` 将任务所有权保存在插件本地的 `Map` 中,因此一次 HMR(热模块替换)重载就可能让旧任务看起来无主。 + +## 决策 + +三个 seam:队列感知的 cancel、`AgentHandle` 释放器,以及 bash 所有者令牌。 + +### 1. 队列感知的 `Agent.cancel(reason?)` + +`cancel()` 是唯一的公开停止原语。它清除已排队的输入和 steering(中途引导)输入,中止正在执行的步骤,并设置一个在每个轮次边界检查的轮次作用域标记。因此,已排队的提示词在取消后无法启动,也无法吸收后续输入。`whenIdle()` 等待取消后的静默状态,ACP 的 `session/cancel` 映射到此方法。对空闲 agent 的 cancel 不设置标记。 + +### 2. `AgentHandle` 异步释放器 + +`ctx.agents.create`/`resume` 与 `AgentFactory` 返回 `AgentHandle = { agent, dispose() }`。释放是消费方的能力;仅持有 `Agent` 的观察者无法拆除它。调用方 fiber 和 factory 提供方也拥有该实例,所有路径共享同一个 memoized 的拆除流程:停止循环、等待静默与 flush 完成、分离 agent 和会话,然后回收其 scope。注册表条目分离后 ID 即可复用。由配置创建的 agent 归 loop fiber 所有;ACP 存储并 dispose 每个会话的 handle。 + +拆除顺序对持久性至关重要。会话生命周期与循环共享一个复合 Cordis effect,因此 LIFO 释放先停止循环并等待 `agent.done`,再分离会话。如果使用兄弟 effect,它们会并发释放,可能在关闭 flush 之前移除 append 钩子。释放通知被隔离,不会中断拆除链。 + +### 3. Bash 所有者令牌置于 seam 中 + +后台任务的所有权归执行器持有。`BashExecSpec.owner` 携带一个可选的不透明令牌,`ownerOf(id)` 读取它,`dsh-tool-bash` 在启动时盖上调用方的会话令牌。`bash_output` 与 `bash_kill` 拒绝不匹配的调用方;完成通知通过注册表按会话令牌定位存活的 agent。将所有权保留在任务上,使得这道围栏在工具插件重载后依然有效。完成监听器仍然是 effect 作用域的,因此在重载间隙到达的通知仍可能被丢弃。 + +## 验证 + +- ACP 断开连接或会话关闭后,不留下任何已注册的 agent 或 session-store 条目,包括 `session/load` 与拆除竞争的情况。 +- 在已排队的提示词启动前取消,能阻止该提示词运行或吸收下一条提示词。 +- 重载 `dsh-tool-bash` 不会让另一个会话读取或终止已有的后台任务,因为所有权保留在执行器上。 +- 由配置创建的 agent 仍归 loop fiber 所有,因此非 ACP 的演示无需显式管理 handle。 + +## 会话所有者令牌在存活 agent 中唯一 + +bash 所有者令牌依赖 `session.header.id` 在存活 agent 中的唯一性。并发的同 ID 操作可以私下准备,但 `SessionStore.enter()` 拒绝重复发布,失败的事务会回滚。`tool-bash` 拥有比较策略;bash seam 存储一个不透明的 `owner` 字符串,不对其做解释。 + +## 曾考虑的替代方案 + +- **公开的 `BashTask.owner` 字段**而非 `BashExecutor.ownerOf(id)` seam:否决。一条读取路径即可,无需冗余 API。 +- **为 agent 的会话生命周期使用兄弟 Cordis effect**:否决。fiber 卸载时兄弟 effect 并发释放(`Promise.all`),store 持有的 append 发布钩子的移除与循环的关闭 `session/flush` 产生竞争;单一复合 effect 的有序 LIFO 链才能在两条释放路径上都捕获关闭的 `turn/end`。 +- **在 `cancel()` 之外另设一个仅中止步骤的 `abort()`**:最初发布过,后因无人使用而移除;`cancel()` 是唯一的公开停止原语(见[公开停止接口 RFC](../simplification/2026-06-20-public-agent-stop-surface.md))。 + +## 后果 + +本变更有意触及公开接口(`Agent`、`AgentFactory`、bash seam),而非作为 ACP 的局部补丁。简洁的同步 `Agent.send()` 人体工学得以保留;异步生命周期路径是增量添加的,供需要它的所有者使用。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml new file mode 100644 index 0000000000..0e2a4891d9 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-18-session-surface.md: 31297166b735468147850a81d7fd43a8fa30a1e8 +2026-06-18-session-surface.zh.md: 9e2933a1e564b3dbb7719d55b5264f670c3b833f diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.md b/docs/rfc/implemented/architecture/2026-06-18-session-surface.md index 6ba0df41c4..31297166b7 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-session-surface.md +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.md @@ -1,5 +1,7 @@ # RFC: Session surface — a linked list over the event log for LLM message derivation +English | [中文](2026-06-18-session-surface.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md b/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md new file mode 100644 index 0000000000..9e2933a1e5 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md @@ -0,0 +1,71 @@ +# RFC:Session surface——基于事件日志的链表,用于 LLM 消息推导 + +Status: implemented + +[English](2026-06-18-session-surface.md) | 中文 + +## 问题 + +事件日志是权威数据源,但历史操作此前没有持久化的共享机制。如果没有这样的机制,上下文压缩(context compaction)等插件只能通过顺序敏感的监听器改写派生请求,不留溯源记录,且每次新增操作都要修改 `deriveMessages()`。 + +## 决策 + +新增一个 **surface**:一条从事件日志派生、带缓存的链表,由「surface 节点」(即产出 LLM 消息的那部分事件)组成,通过事件日志中的 `surfaceOp` 标记维护。 + +### `SessionEvent` 上的两个新顶层字段 + +每个 `SessionEvent` 新增两个可选字段(与 `seq`/`time` 同属结构元数据): + +- **`sourceEventSeqs?: number[]`**:作为溯源来源的事件 seq 编号(例如:构成 `assistant/message` 的各 `assistant/chunk` 的 seq,或被压缩标记遮蔽的 surface 节点)。溯源是核心设计原则;没有它,replace-range 操作在回放时无法被验证。 +- **`surfaceOp?: SurfaceOp`**:该事件如何进入 surface。非 surface 事件不携带此字段。 + +### SurfaceOp:两种操作 + +```ts +export type SurfaceOp = + | 'append' // normal tail append + | { op: 'replace'; start: number; end: number } // shadow [start, end] inclusive +``` + +1. **Append**:在尾部追加一个新节点。`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message` 使用此操作。agent loop 在所有此类追加上传入 `surfaceOp: 'append'`,并在适用时附带 `sourceEventSeqs`(例如 `assistant/message` 记录其 `assistant/chunk` 来源;`tool/result` 记录其 `tool/call` 来源)。 + +2. **Replace**:移除从 `start` 到 `end`(两端含)的节点,并在其位置插入一个新节点。`start` 和 `end` 都必须是当前 surface 上有效的 surface 节点 seq;`start === end` 表示替换单个节点。该节点的 `sourceEventSeqs` 必须包含所有被遮蔽的 surface 节点。被遮蔽的事件仍保留在日志中,但不再出现在 surface 上。 + +### SurfaceManager:基于增量,而非全量重建 + +`SurfaceManager` 类(`Session` 的私有实现)维护缓存的链表。它跟踪 `_lastProcessedSeq`,仅处理**增量**(上次访问以来的新事件),而非重新扫描整个日志。由于日志是仅追加的,先前事件不会改变;种子日志只是在首次访问时折叠的初始增量。 + +无新事件时增量处理为 O(1),有新事件到达时为 O(新事件数)。 + +`deriveMessages()` 在存在 surface 标记时使用 surface,否则回退到既有的线性扫描(向后兼容)。 + +### 持久化 + +新字段作为顶层 JSON 属性序列化。JSONL 后端无需任何修改:`JSON.stringify`/`JSON.parse` 透明地保留一切。SQLite 后端的 `events` 表新增两个可空 TEXT 列(`source_event_seqs`、`surface_op`)。磁盘上的 `SCHEMA_VERSION` 递增以反映列集变化,并且按照预发布的 bump-and-reject 策略,由其他构建写入的数据库在打开时被拒绝,而非迁移(没有需要升级的持久化用户数据)。会话格式 `version` 固定为 `SESSION_FORMAT_VERSION = 0`(「不稳定/预发布」立场):可选的 surface 字段被吸收而不递增版本号。 + +### 崩溃恢复 + +`repair.ts` 模块在崩溃后为孤立的工具调用合成 `tool/result` 关闭事件。这些关闭事件携带 `surfaceOp: 'append'` 和指向孤立 `tool/call` 事件的 `sourceEventSeqs`,确保重建后的 surface 有效。 + +### 不变式 + +开发模式不变式插件验证:`sourceEventSeqs` 引用(非空、无重复、引用更早的事件、引用已知 seq)以及 `surfaceOp`(replace 的 `start ≤ end`、两个端点都在被跟踪的 surface 上、范围在 surface 位置上不反转、`sourceEventSeqs` 包含该范围遮蔽的每个节点)。 + +每个 surface 可达事件都必须携带 `surfaceOp`,否则它会从派生历史中消失。类型化的 `append` 重载对字面事件类型强制执行此要求;`append` 和种子构造函数中的运行时检查覆盖了宽化联合类型和加载的日志。无效种子在预发布格式策略下被拒绝而非升级。 + +## 曾考虑的替代方案 + +- **逐插件的 `agent/request` 包装**(surface 之前的历史操作模式):监听器排序脆弱,不留持久化的变更记录,且每次新增操作都要修改核心 `deriveMessages()`。 +- **半开区间 `[start, endExclusive)` 的 replace 范围**:否决。surface 是双向链表,端点自然以节点 seq 命名,单节点替换(`start === end`)在闭区间语义下读起来更自然。 +- **脏标记触发全量重建**而非增量处理:在会话生命周期内为 O(N²)——每次单事件追加都要重新扫描所有先前事件。 + +## 后果 + +- **`packages/core/session`**:新增 `surface.ts`(`SurfaceManager`)、新类型(`SurfaceOp`、`SurfaceIntent`)、`SessionEvent` 上的新字段、修改 `append()`(第三个必需参数 `SurfaceIntent`)、重构 `deriveMessages()`(以 surface 遍历作为唯一推导路径)、surface 感知的 `repair.ts`。种子构造函数拒绝缺少 `surfaceOp` 标记的 surface 可达种子事件(见「不变式」一节)。 +- **`packages/core/agent-loop`**:所有 surface 可达的追加传入 surface 选项。收集 chunk seq 用于 `assistant/message` 溯源;捕获 `tool/call` seq 用于 `tool/result` 溯源。 +- **`packages/session-persistence/session-persistence-sqlite`**:`events` 表新增两个可空 TEXT 列(`source_event_seqs`、`surface_op`);`SCHEMA_VERSION` 递增(bump-and-reject,无迁移)。 +- **`packages/support/invariants`**:surface 相关的验证规则。 +- **`packages/session-persistence/session-persistence-jsonl`**:无需修改。 +- **`packages/session-persistence/session-persistence`**:抽象接口不变。 + +Surface 是未来历史操作的基础。压缩或 tool-result-prune 插件追加一个既有的消息产出事件类型(例如一条携带摘要的 `user/message`),附带 `surfaceOp: { op: 'replace', start, end }` 和覆盖被遮蔽节点的 `sourceEventSeqs`——新节点取代该范围在 surface 上的位置,而插件自身的跟踪事件(如 `compaction/start`、`compaction/end`)则不进入 surface。回放确定性地保留这一决策。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml new file mode 100644 index 0000000000..566ce4ae59 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-18-shared-persistence-write-coordinator.md: 3fc30dc2e1382fd983d050433123f46a2cd0ed19 +2026-06-18-shared-persistence-write-coordinator.zh.md: 6c8ccef8dd5603d837dd0a9884adf9c1cd8a17d4 diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md index b1773b480d..3fc30dc2e1 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md @@ -1,5 +1,7 @@ # RFC: Shared persistence write coordinator +English | [中文](2026-06-18-shared-persistence-write-coordinator.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md new file mode 100644 index 0000000000..6c8ccef8dd --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md @@ -0,0 +1,44 @@ +# RFC:共享持久化写入协调器 + +Status: implemented + +[English](2026-06-18-shared-persistence-write-coordinator.md) | 中文 + +## 问题 + +`dsh-session-persistence-jsonl` 与 `dsh-session-persistence-sqlite` 有意在不同存储介质上证明同一份 `SessionPersistence` 契约,但二者的写入路径编排是重复的:per-session 状态、`session/created` 接管、后端特定的前缀读取、write-behind 缓冲区、串行化 flush 链、HMR(热模块替换)种子注入,以及 dispose(资源释放)排空。纯粹的种子前缀冲突与可串行化守卫已经迁入 seam 包;剩余的编排仍然是正确性密集的,并且相同的修复被应用了两次。代码级 diff 表明两个后端在**所有**这些逻辑上是逐字节一致或同算法的:四个 map(`states`/`buffers`/`chains`/`inits`)、`installWritePath`、`initFor`、`onCreated` 的四种分支、`flush`、`drain`、`serialize`、`adopt`、`adoptLivePrefix`、`assertVersion`,以及 `create`/`append`/`load` 骨架。唯一不同的只有存储原语(写字节 vs. INSERT 行)。 + +## 决策 + +将一个后端无关的 `PersistenceCoordinator` 提取到 `dsh-session-persistence` 中。协调器统一拥有编排逻辑;每个第一方后端组合一个实例(`new PersistenceCoordinator(ctx, this)`),实现一个小型 `PersistenceBackend` 钩子接口,并将其四个公开服务方法(`create`/`append`/`load`/`list`)委托给协调器。 + +组合,而非继承。协调器是后端持有的具体类,不是后端继承的基类。本 RFC 的风险点——「协调器不得迫使非常规后端与继承层级搏斗」——由此规避:后端只暴露钩子;它无法触及协调器的私有编排状态,且公开的 `SessionPersistence` 服务形状不变,因此第三方后端仍然可以完全不使用协调器、直接实现抽象服务。 + +### 钩子接口(`PersistenceBackend<TornMarker>`) + +六个方法(五个必需 + 一个可选生命周期钩子)——协调器与存储之间唯一的 seam: + +- `name`:后端标签,用于 dispose 失败时的 `AggregateError`。 +- `loadStored(id)`:按 id 读取已存储的前缀,扫描**任何**存储范围(JSONL 的每个 cwd bucket;SQLite 的 id 全局唯一)。用于恢复/加载,以及通过 `!== undefined` 实现创建冲突探测。 +- `loadLive(id, cwd)`:读取**限定于 `cwd`** 的已存储前缀。**刻意区别于 `loadStored`**:HMR live-adoption 只能接管与活跃会话**相同 cwd** 下的持久化日志;同 id 但不同 cwd 的日志是冲突而非恢复。合并这两个方法会重新引入跨 cwd 接管 bug。SQLite 忽略 `cwd`。 +- `appendBatch(meta, events, isMaterialized)`:持久地追加一个连续批次,在尚未物化时**原子地**惰性物化会话(物化写入与第一个事件批次必须一起提交——崩溃发生在二者之间时不得留下一个已物化但为空的会话;这就是为什么没有单独的 `materialize` 钩子)。 +- `commitRepair(meta, tornMarker, closers)`:使崩溃修复持久化:截断撕裂尾部(当且仅当 `tornMarker !== undefined`)并追加 `closers`。**不要求原子性**——JSONL 合理地分两步 fsync(先截断再追加),SQLite 在一个事务中完成 DELETE+INSERT。用于 `load`(截断 + 合成 closers)和 live-adoption(仅截断,`closers = []`)。 +- `list()`:列出所有已存储的元数据。 +- `close?()`:可选的生命周期清理(SQLite 关闭 db 句柄;JSONL 省略),在 dispose effect 中于静默排空**之后**被 await,确保 close 失败不会掩盖排空错误。 + +### 不透明的撕裂标记 + +保持 seam 干净的唯一设计选择:崩溃修复中的「撕裂尾部在哪里」token 对协调器是**不透明的**。协调器计算合成 closers(它拥有来自 `dsh-session` 的 `interruptedTurnClosers`),但它只测试 `tornMarker !== undefined` 并将值原样传回 `commitRepair`——从不检视其内容。每个后端选择自己的标记类型:JSONL 使用要截断到的字节偏移量,SQLite 使用要从其开始删除的 seq(两者碰巧都是 `number`)。JSONL 后端将其 `committedBytes < buffer.byteLength` 比较**折叠在钩子内部**,因此返回的标记已经是 `number | undefined`;如果不做这个折叠,协调器就必须了解字节长度。 + +## 测试 + +共享的 `runPersistenceContract`(公开 API 契约)继续为每个后端运行。新增的 `runCoordinatorContract`(`tests/coordinator-contract.ts`)覆盖写入路径编排——接管、HMR、冲突、dispose 排空、崩溃尾部修复——通过 `CoordinatorFixture`(内存参考实现 + jsonl + sqlite)为每个后端运行一次。各后端自身的测试缩减为仅覆盖存储机制(JSONL:路径安全、fsync 回滚、bucket 列举;SQLite:schema 版本、`scanRows`、事务回滚)。每个真实后端有一个 through-coordinator 的 torn-tail→load→`commitRepair` 测试(通过 `corruptTail` fixture 钩子),确保协调器的撕裂标记修复分支在 100% per-file 门禁下被覆盖——契约崩溃测试只产生合成 closers 而不产生撕裂标记,因此无法触达该分支。 + +## 曾考虑的替代方案 + +- **后端继承的基类**:否决,改用组合。后端只暴露钩子,无法触及协调器的私有编排状态,且第三方后端仍然可以完全不使用协调器、直接实现抽象服务。 +- **更宽的钩子面**:每个候选钩子都被折叠掉了:没有单独的 `materialize` 钩子(物化写入必须在 `appendBatch` 内与第一个事件批次原子提交);没有单独的创建冲突探测(它就是 `loadStored(id) !== undefined`);`list()` 也不经过协调器透传(列举不需要任何编排)。 + +## 后果 + +协调器增加了一层间接和一个不透明的撕裂标记,但将此前每个后端重复的正确性密集编排集中到一处。其钩子面保持窄小:冲突检查复用 `loadStored`,物化保持在 `appendBatch` 内原子完成,列举绕过协调器。新后端只需实现存储原语,无需复制事件-缓冲区-flush 生命周期。 diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml new file mode 100644 index 0000000000..52a3ca3b01 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-branded-ids.md: f6d066857d8904ae5343f12310266663806a0ae2 +2026-06-20-branded-ids.zh.md: 14f82c395cdf43e2f5df5b2317dda3d45c595a64 diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md index 9f83e46b24..f6d066857d 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md @@ -1,5 +1,7 @@ # RFC: Branded IDs everywhere they belong +English | [中文](2026-06-20-branded-ids.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md new file mode 100644 index 0000000000..14f82c395c --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md @@ -0,0 +1,69 @@ +# RFC:在所有应当使用品牌类型的位置推行 Branded ID + +Status: implemented + +[English](2026-06-20-branded-ids.md) | 中文 + +## 问题 + +harness 已经为三个标识符打上了品牌类型:`CallId`(`packages/llm/llm/src/brand.ts`)、`SessionId`(`packages/core/session/src/types.ts`)和 `AgentId`(`packages/core/agent/src/types.ts`),使用 `Branded<B> = string & { readonly [BRAND]: B }` 机制(由纯类型包 `@deepseek-ai/dsh-brand` 拥有,位于 `packages/util/brand/`,见其 [README](../../../../packages/util/brand/README.md)),并为每个类型提供零成本的 cast 工厂函数。`dsh-brand` 还声明了治理策略:*"品牌类型用于跨包边界且可能被混淆的 id;并非每个 string 都需要品牌类型。"* 这条策略是正确的;问题在于它只落实了一半。两个缺口使得「结构相同但语义不同」的 string 今天仍能通过类型检查。 + +**缺口 1:bash seam 中未打品牌的 ID。** `BashTask.id` 以及所有 executor/tool 边界使用裸 `string`,尽管生成的值与默认 session id 具有相同的 `name-N` 形状。模型也通过 `task_id` 返回该值,因此混淆 task id 和 session id 既是类型正确的,也是可达的。 + +bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 和 `BashExecSpec.owner: string | undefined`(`packages/bash/bash/src/types.ts`)被文档描述为刻意*不透明*的隔离键,但在所有实际调用方中,该值就是拥有者 agent 的 `session.header.id`(`callerToken = (exec) => exec.agent?.session.header.id`,见 `packages/bash/tool-bash/src/index.ts`)——即一个穿着 `string` 外衣的 `SessionId`。它被用于访问控制比较(`owner !== callerToken(exec)`),因此一个「不匹配但类型正确」的 string 在此处就是一个跨会话隔离 bug,而当前类型系统无法捕获。这正是 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案所称的「bash owner-token 别名漏洞」。 + +**缺口 2:既有品牌类型的侵蚀。** `CallId`、`SessionId` 和 `AgentId` 在注册表 map、公开查找参数、ACP 会话追踪和持久化协调器中退化为裸 string。在查找边界丢弃品牌类型,等于废掉了它的核心保护。 + +## 决策 + +纯类型变更。品牌类型是零成本 cast;运行时行为、序列化、比较和协议格式(wire format)均不变。工作分三部分,全部遵守既有的「并非每个 string 都需要」策略。 + +- **为 bash task id 打品牌。** 在 `packages/bash/bash/src/types.ts`(*拥有*该 id 的包)中添加 `BashTaskId = Branded<'BashTaskId'>` 及其同名工厂函数,从 `@deepseek-ai/dsh-brand` 导入 `Branded`,方式与 `SessionId`/`AgentId` 完全一致。品牌原语放在无依赖的 `dsh-brand` 工具包中,正是为了让 `dsh-bash` 只依赖它就能为自己的 id 打品牌——永远不需要为了获取 `Branded` 而引入 `dsh-llm`(或 `dsh-session`)。将品牌贯穿 `BashTask.id`、`BashExecutor` seam 方法(`get`/`ownerOf`/`readOutput`/`kill`)、`dsh-bash-local` 中的生成点(在创建时一次性为计数器输出打品牌),以及 `dsh-tool-bash` 的校验/访问控制面(`validateTaskId` 返回 `BashTaskId`;`task_id` 在模型 string 到达的 tool 边界处打品牌)。 + +- **铸造独立的 `OwnerToken` 品牌。** 在 `packages/bash/bash/src/types.ts` 中添加 `OwnerToken = Branded<'OwnerToken'>`;将 `BashExecRequest.owner` / `BashExecSpec.owner` / `BashExecutor.ownerOf` 的类型标注为 `OwnerToken | undefined`。`dsh-tool-bash` 消费方在边界处将 agent 的 `session.header.id`(一个 `SessionId`)cast 为 `OwnerToken`——这是两套词汇交汇的唯一位置。bash seam 永远不导入 `dsh-session`。(理由见下一节。) + +- **阻止品牌侵蚀。** 将既有品牌传播到缺口 2 列出的 `Map` 键类型和公开方法参数:`Map<SessionId, Session>`、`get(id: SessionId)`、`Map<AgentId, Agent>`、`Map<CallId, …>`、ACP 的 `SessionRecord.sessionId: SessionId` 接口、协调器的 `Map<SessionId, …>`。这是 diff 中机械性最大的部分,也是让*既有*品牌在查找处真正发挥作用(而非仅在结构体字段上标注)的关键。 + +示意形状(工厂模式与现有三个品牌完全一致): + +```ts ignore-check +import type { Branded } from '@deepseek-ai/dsh-brand' + +/** A background bash task handle (generated `bash-N` by the local executor). */ +export type BashTaskId = Branded<'BashTaskId'> +export function BashTaskId(id: string): BashTaskId { + return id as BashTaskId +} + +/** A bash task's opaque isolation key — the consumer's owner identity, NOT the bash seam's. */ +export type OwnerToken = Branded<'OwnerToken'> +export function OwnerToken(id: string): OwnerToken { + return id as OwnerToken +} +``` + +## 曾考虑的替代方案 + +### 为什么不把 `owner` 类型标注为 `SessionId`? + +executor 将 ownership 视为不透明的,不应依赖 session 模型。独立的 `OwnerToken` 保持了这一边界,同时防止裸 string 或 task id 被当作 owner 传入。`dsh-tool-bash` 拥有访问策略,由它执行从 `SessionId` 到 `OwnerToken` 的唯一转换。 + +## 不在范围内 / 可能的扩展 + +遵循「并非每个 string 都需要品牌类型」策略,刻意保持窄范围。以下每项都是合理的未来品牌候选,附有推迟理由而非承诺: + +- **`ModelId`**(`GenerateOptions.model`,`LlmService` 适配器注册表键)——一个真正的跨包查找键(config → agent → llm → adapter);合理的下一个品牌,仅为控制本 RFC 的影响范围而暂不纳入。 +- **`ToolName`**(`ToolRegistry` 键)——由作者定义、人类可读,且很少与其他 id 混淆;候选强度最弱,可能不值得打品牌。 +- **`ErrorCode`**(`HarnessError.code`)——封闭词汇(`ABORTED`、`NO_ADAPTER`……),不是逐实例的 id;如果要加强类型,用 string 字面量联合类型比品牌更合适。 +- **数值序号**——轮次号、步骤号和事件 `seq` 是 `number` 而非 `string`,`Branded<string>` 不适用;可以用并行的 `number & { readonly [BRAND]: B }` 变体为它们打品牌,但它们是位置序号、很少跨边界传递,收益低。 +- **带校验的构造**——品牌工厂是纯 cast,无运行时检查,且每个边界(ACP `sessionId`、提供方发放的 `call.id`、`dsh-llm-deepseek` 中的空字符串回退)今天都信任裸 string。一个在边界对畸形输入抛异常的 `SessionId.parse()` / `isValid()` 伴生函数确实是缺口,但它是一项*运行时行为*变更,有自己的设计问题(什么算「畸形」?失败时怎么办?),应在独立 RFC 中处理,不应捆绑进这次纯类型改动。 + +## 验证 + +`BashTaskId` 和 `OwnerToken` 定义在 `dsh-bash` 中,贯穿 executor、本地实现和面向模型的 tool,且未引入 `dsh-session` 依赖。集合、公开参数和导出签名对 `CallId`、`SessionId`、`AgentId` 或 `BashTaskId` 使用对应的品牌类型而非裸 `string`;来自提供方、ACP 和模型的原始输入通过品牌工厂进入,而非散落的 cast。 + +## 后果 + +- **两个面上的机械性改动。** 传播品牌类型涉及 bash seam(接口 + 实现 + 消费方)以及 ACP session-id 接口和持久化协调器。改动面广但严重度低:遗漏的位置是编译错误,而非静默 bug。变更可观测地是纯类型的——无快照或 e2e 行为差异。它与 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案相邻(两者都触及 session-id / owner-token 边界);即使该提案落地,`OwnerToken` 出于上述解耦理由仍与统一后的 id 保持独立。 +- **品牌类型不做校验。** 品牌类型是混淆防护,不是正确性证明:一个*错误的* session id 只要仍是格式良好的 string,就和以前一样能通过类型检查。本 RFC 不关闭这个缺口(见「不在范围内」)——它只阻止传入错误*类别*的 id 这一类错误。 +- **「在哪里停下」仍是判断题。** 为 `BashTaskId` 打品牌而不为 `ToolName`,为 `OwnerToken` 打品牌而不为 `ModelId`,是对哪些 string「可能被混淆」的品味判断。合理的评审者可能想要更多或更少;`brand.ts` 中的策略是裁决依据,本 RFC 倾向于面向模型或用于访问控制的 id。 diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml new file mode 100644 index 0000000000..992793d609 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-extract-example-app-packages.md: 3a0a0f5d4b329afed72bd3c00bf880989e24fe54 +2026-06-20-extract-example-app-packages.zh.md: 9de9f79369ebad387778a0418b75dfde96b285a7 diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md index 0582515c62..3a0a0f5d4b 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md @@ -1,5 +1,7 @@ # RFC: Extract example apps into packages +English | [中文](2026-06-20-extract-example-app-packages.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md new file mode 100644 index 0000000000..9de9f79369 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md @@ -0,0 +1,57 @@ +# RFC:将示例应用提取为 package + +Status: implemented + +[English](2026-06-20-extract-example-app-packages.md) | 中文 + +## 问题 + +示例目录本应是*薄*的:只包含演示的可变接线,而非演示的机制本身。在本次变更之前它是厚的。每个示例都携带一份手写的 `start.ts` 启动引导、一段基础设施前导(`timer`,以及 stdio 演示还需要的 `logger` + `hmr`)、三个共享 YAML 片段的嵌套引入(`base.yml` / `base-core.yml` / `acp-agent/acp-tail.yml`),以及每个示例各自的 `agent-loop`/持久化/系统提示词配置。真正的应用——每个 agent 都需要的服务主干——分散在叶子配置和那些 include 中。 + +叶子配置还拥有一个耦合的前门。ACP 要求 stdout 纯净,通过 `session/new` 创建 agent;stdio 需要控制台 logger 和一个预创建的 `main`。防止错误组合的唯一手段是行文中的警告,而三个 `start.ts` 文件重复了 Loader 引导和生命周期代码。 + +## 决策 + +每个示例现在**基本上是对一个 app package 的调用**,沿着既有的[接口 / 实现 / 消费方 seam](2026-06-13-capability-seams.md) 拆分接线:**app 包拥有组合**,叶子 `cordis.yml` 只拥有**可替换的选择**(哪个 LLM 适配器、哪个 bash 执行器、模型、提示词、持久化根目录)。 + +- **`@deepseek-ai/dsh-agent-spine-demo`**([packages/examples/agent-spine-demo](../../../../packages/examples/agent-spine-demo))组合无提供方、无执行器、无 UI 的主干,并转发 loop 的 agent 列表配置。它对具体 loop 的依赖是有意为之,因为这个包组合的是主干而非扩展它;替换 loop 意味着提供另一个 bundle。 +- **`@deepseek-ai/dsh-stdio-demo`**([packages/examples/stdio-demo](../../../../packages/examples/stdio-demo))和 **`@deepseek-ai/dsh-acp-demo`**([packages/examples/acp-demo](../../../../packages/examples/acp-demo))各自内置了前门。Stdio 包含 `ui-stdio`、控制台 logger 和 `main`;ACP 包含 bridge 和 JSONL 持久化,但不含 stdout logger 或预创建的 agent。叶子可以追加插件,但安全的组合现在是默认产物。 +- **`start.ts` 已移除。** 每个 app 包暴露一个 `bin`(`dsh-stdio-demo` / `dsh-acp-demo`);`demo:*` 脚本调用它(如 `dsh-stdio-demo ./cordis.yml`)。Loader 引导尾部、`.env` 加载和 fail-loud 守卫位于共享的 [`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot) 包(在逐文件覆盖率门禁下有单元测试——见[共享 app bin 的启动胶水](../simplification/2026-07-04-share-app-bin-boot-glue.md));每个 bin 是一个薄的自执行组合,基于这些辅助函数加上自身特有的生命周期逻辑(ACP bin:快照模式选择与 stdin-dispose)。`bin.ts` 文件本身仍排除在覆盖率之外(自执行 CLI 入口,与旧的 `start.ts` 类似),由 keyless Loader 路径测试驱动。 +- **每个叶子 `cordis.yml` 精简**为后端 + 配置:LLM 适配器(带 apiKey/models 的 `llm-deepseek`,或 `llm-replay`)、bash 执行器(`bash-local`)、stdio 演示的 `hmr`(见下方修正),以及一个 app 条目承载 app 的配置(模型、系统提示词、持久化根目录——作为 app 包自身的 `Config` 暴露,由 app 将每个值路由到其接线的目标位置:stdio 路由到预创建的 agent,acp 路由到 bridge 插件)。 +- **echo-agent 折叠到 `dsh-stdio-demo`**,将 LLM 后端替换为本地的 `mock-llm`,并在叶子层添加本地的 `echo-tool`(加上 `bash-local`,由主干的 `tool-bash` 注入)——这是「替换后端、保留应用」的干净示范。`mock-llm.ts` / `echo-tool.ts` 作为示例本地的教学插件保留。 +- **`base.yml`、`base-core.yml` 和 `acp-agent/acp-tail.yml` 退役**——它们共享的主干现在位于 `dsh-agent-spine-demo`。 + +`bash-local` 和 LLM 适配器保持为**叶子选择**:bundle 提供 `tool-bash`(消费方 schema),叶子选择执行器实现,因此沙箱执行器或回放适配器可以在不触碰 app 的情况下替换进来。 + +### 实现修正:`hmr` 保留为叶子条目 + +提案将 `hmr` 列入 stdio app 内置的前门集群。对照代码验证后发现,将 `hmr` 内置到 `dsh-stdio-demo` 包在两方面与 Cordis 冲突,因此改为作为**叶子 `cordis.yml` 条目**交付: + +1. `@cordisjs/plugin-hmr` 是一个仅限 Loader、仅限子进程的开发插件——其构造函数在没有 `node --expose-internals` 和活跃 `loader` 服务的情况下会抛出异常,因此只能在真实的 `demo:*`/bin 子进程中运行,无法在进程内的单元/覆盖率测试层运行。 +2. 进程内测试层(vitest)甚至无法*导入* vendor 的 `hmr` 模块(其 class-decorator `@Inject` 形式在 Vite 的 transform 下会失败),因此一个 `apply` 静态导入了它的包永远无法满足其主函数的逐文件 100% 覆盖率门禁。 + +关键在于,`hmr` **不是**像控制台 logger 那样的 stdout 纯净隐患——在 ACP 配置中误加 `hmr` 不会破坏 JSON-RPC 帧——因此将它留在叶子不会损失耦合论证所关注的安全性。**logger**(真正的耦合)保持内置:stdio app 包含它,ACP app 省略它。 + +## 曾考虑的替代方案 + +### 为什么不继续用共享 YAML include 来接线? + +旧的 `base*.yml`/`acp-tail.yml` include 已经去重了*配置*,但 YAML include 无法**封装**前门耦合——它只能在注释中描述,并信任每个叶子遵守。它也无法拥有 `bin`,因此启动胶水只能在三个 `start.ts` 文件中复制。包将「ACP app 绝不向 stdout 输出日志」从行文警告变成产物的属性:叶子中没有可以写错的 logger 条目。 + +## 验证 + +- 示例目录只包含配置、README 和测试:`start.ts`、基础设施前导和共享 YAML include 已移除。 +- `demo:echo`、`demo:repl` 和 `demo:acp` 调用 app 包的 bin。 +- 每个新包有 README 和逐文件 100% 覆盖率;每个 app 包还有一个 keyless 的真实 Loader 路径 bin 冒烟测试,用于捕获 [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md) 中描述的导出形状失败。 +- ACP 回放 transcript 保持不变,因为插件集和加载顺序未改变。 + +## 后果 + +- **裸插件树教学法。** echo-agent 的内联 `cordis.yml` 曾一次展示所有插件;主干现在藏在 bundle 后面,因此查看完整树意味着打开 `dsh-agent-spine-demo`。app 包的 README 承担了这部分教学职责。 +- **多了一层间接。** 「这个演示加载了什么?」变成了读一个 package,而非扫一份 YAML。 + +## 相关 + +- 取代 [Make the shared example base providerless](../../rejected/architecture/2026-06-20-providerless-example-base.md):一旦主干移入 `dsh-agent-spine-demo` 且 `base*.yml` 文件被删除,将 `base.yml` 重命名为无提供方核心便不再有意义。 +- 建立在[能力 seam](2026-06-13-capability-seams.md) 的接口/实现/消费方拆分之上——后端和展示层保持为叶子选择;主干是共享 bundle。 +- 与 [Reorganize packages into a modular hierarchy](2026-06-20-package-hierarchy.md) 互补:新的 app/core 包按该层级结构归入既有分组(`core` 放可复用的主干 bundle,`ui` 放 app 特有的前门)。 diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml new file mode 100644 index 0000000000..9f89c454fc --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-package-hierarchy.md: faf5815222b20699a32f1af489e625ba3e891230 +2026-06-20-package-hierarchy.zh.md: 4b71cd41826e727eea19d305635c6485e18393c2 diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md index 89b50eb3df..faf5815222 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md @@ -1,5 +1,7 @@ # RFC: Reorganize packages into a modular hierarchy +English | [中文](2026-06-20-package-hierarchy.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md new file mode 100644 index 0000000000..4b71cd4182 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md @@ -0,0 +1,75 @@ +# RFC:将包(package)重组为模块化层级结构 + +[English](2026-06-20-package-hierarchy.md) | 中文 + +Status: implemented + +## 问题 + +`packages/` 原先是扁平的:18 个包全部位于 `packages/<name>/`,一个包的位置无法体现它是核心产品 API、可替换的能力 seam、提供方适配器、产品集成,还是示例/测试支撑。package README 带着 `FIXME(package-hierarchy)`,`scripts/publint-all.ts` 带着 `TODO(package-inventory)`,标记的正是这个问题。核心包、提供方集成、能力 seam、示例 UI 支撑和仅用于快照的回放支撑,看起来都同等基础。 + +这不仅是外观问题。因为每个顶层包看起来都属于同一个公开接口面,未来移除更难;发布/lint/文档脚本不得不通过注释或手工维护的静态列表来编码意图,而非从布局直接读取。 + +## 决策 + +按模块角色分组,统一为 `packages/<group>/<pkg>/` 两层深度。分组目录是纯容器(没有 `package.json`);每个包保留其 `@deepseek-ai/dsh-<pkg>` 名称——这是仓库结构与维护策略,不是包重命名。 + +```text +packages/ + core/ (product API spine) + session/ + system-prompt/ + tools/ + agent/ + agent-loop/ + llm/ (product — capability family) + llm/ + llm-deepseek/ + llm-pi-ai/ + bash/ (product — capability family) + bash/ + bash-local/ + tool-bash/ + session-persistence/ (product — capability family) + session-persistence/ + session-persistence-jsonl/ + session-persistence-sqlite/ + ui/ (product integration) + acp/ + support/ (dev/test/example infrastructure) + invariants/ + ui-stdio/ + llm-replay/ +``` + +### 放置决策 + +- **能力族使用同名嵌套。** 一个族的接口包位于 `packages/<group>/<group>/`(`llm/llm`、`bash/bash`、`session-persistence/session-persistence`),实现和消费方作为扁平兄弟。不设额外的 `adapters/`/`impls/` 子层——每个包恰好在深度 2,workspace glob 保持简洁的 `packages/*/*`,一条 `@deepseek-ai/dsh-*` tsconfig 通配符即可解析所有包(目录名唯一,使 first-on-disk-wins 无歧义)。 +- **`session` 留在 `core/`;持久化自成一族。** 会话日志是核心产品 API。其存储后端构成一个平行的能力族(`session-persistence/`),与 `llm/` 和 `bash/` 对称,而非嵌套在 `core/session/` 下。 +- **`agent-loop` 在 `core/` 中。** 它是 `agent` seam 唯一的具体实现,但作为 harness 的默认产品循环随产品发布,因此与核心主干同住。插件仍然依赖 `agent` 的词汇,从不依赖 `agent-loop`,因此循环仍可替换。 +- **`invariants` 和 `ui-stdio` 属于 `support/`,不是产品。** `invariants` 是开发模式的契约检查。`ui-stdio` 从示例中提取以便复用和满足覆盖率门禁——它与示例耦合,因此与 `llm-replay`(快照测试回放适配器)一起放在 `support/` 中。`acp` 是 `ui/` 的唯一成员,因为它是真正的产品接口面(编辑器驱动的 ACP 桥接),在结构上不同于 readline 演示辅助工具。 + +### 去重包清单 + +包清单此前在五处重复枚举。统一的深度 2 布局使大部分可以被推导出来: + +- `tsconfig.base.json` 通过一条 `@deepseek-ai/dsh-*` `paths` 通配符(每个分组列一个候选路径)映射所有包,取代逐包条目。根 `tsconfig.json` 复用该源码映射,并携带显式的 project references 以保持 package/vendor 类型检查边界完整。(这里引入了一个细节:路径候选包含 `/*/`,朴素的正则注释剥离器会误认为块注释——`scripts/doc-typecheck.ts` 正是因此通过 TypeScript 解析器读取 JSONC 配置,而非手工剥离注释。) +- `scripts/publint-all.ts` 通过读取层级结构(`packages/<group>/<pkg>`)推导出列表,解决了 `TODO(package-inventory)`。 +- `tsconfig.build.json` 的 project `references` 仍为显式列表——TypeScript project references 没有通配符形式。从 manifest 生成这些引用留作后续工作(见 [discover package inventories](../../proposed/process/2026-06-20-discover-package-inventory.md))。 + +### 新增的护栏 + +两道 doc-sync/hygiene 门禁保证结构及其引用的正确性,使本次重组所需的人工检查不必再次手动重复: + +- `scripts/verify-package-paths.ts` 标记 Markdown 或 `.ts` 注释/字符串中的 `packages/<path>` 引用:如果该路径无法解析**且**某段命名了一个真实存在的包,则视为指向已移动包的陈旧路径。如果路径命名的包在任何地方都不存在(前瞻性提案),则不报错;因此该门禁对 proposed/implemented/rejected 统一适用。 +- `scripts/check-workspace-constraints.ts` 断言 `packages/<group>/<pkg>` 形状:分组目录不含 `package.json`,没有包扁平地位于根层级或嵌套更深。分组名称保持开放——新增分组无需修改门禁;只有深度 2 的形状是固定的。 + +## 曾考虑的替代方案 + +- **第三层(每个族下设 `adapters/`/`impls/`)**:否决。统一深度 2 使 workspace glob 保持简洁的 `packages/*/*`,一条 `@deepseek-ai/dsh-*` tsconfig 通配符即可解析所有包。 +- **将持久化嵌套在 `core/session/` 下**:否决。存储后端构成一个平行的能力族,与 `llm/` 和 `bash/` 对称,而会话日志本身属于核心产品 API。 +- **`ui-stdio` 放在 `ui/` 下**:否决。它是与示例耦合的开发支撑,不是产品接口面;`acp` 是 `ui/` 的唯一成员,因为编辑器确实在驱动它。 + +## 后果 + +本次重组在一次协调的变更中搅动了 import、workspace glob、文档链接、构建引用和包路径。这种搅动在发布前是可接受的(遵循 AGENTS.md 中「基础优先于爆炸半径」的立场),因为它阻止了扁平布局将支撑包固化为产品契约;而且这是一次性成本:通配符 `paths`、glob 推导的 publint 列表和形状门禁意味着新增一个包无需再做额外的结构编辑。 diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml new file mode 100644 index 0000000000..c69c49d2c7 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-21-mandatory-app-attribution-headers.md: 4fa773e089b3a4b682e42269a66d85aeaf5c18f6 +2026-06-21-mandatory-app-attribution-headers.zh.md: 3660b8e7de977c01a19f9ed9ac9e73409f69706a diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md index 102a29d613..4fa773e089 100644 --- a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md @@ -1,5 +1,7 @@ # RFC: Mandatory `User-Agent` attribution for provider requests +English | [中文](2026-06-21-mandatory-app-attribution-headers.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md new file mode 100644 index 0000000000..3660b8e7de --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md @@ -0,0 +1,84 @@ +# RFC:对提供方请求强制携带 `User-Agent` 归属标识 + +Status: implemented + +[English](2026-06-21-mandatory-app-attribution-headers.md) | 中文 + +## 问题 + +LLM(大语言模型)提供方请求应当标识发出请求的产品。这对提供方侧的技术支持、滥用调查、兼容性调试和流量分析都有价值。在本 RFC 之前,harness 只部分做到了这一点:手写的 DeepSeek 适配器发送一个手动复制的 `User-Agent` 常量(`packages/llm/llm-deepseek/src/adapter.ts`),而基于 pi-ai 的孪生适配器完全不发送 harness 自有的头部(`packages/llm/llm-pi-ai/src/adapter.ts`)。因此新适配器可以静默地遗漏归属标识,而库封装的适配器也可能与手写适配器产生偏差——尽管[孪生适配器 RFC](2026-06-13-twin-llm-adapters.md) 的存在正是为了让两种实现在提供方 seam 上保持诚实。 + +直接触发点来自 OpenRouter 的 [App Attribution](https://openrouter.ai/docs/app-attribution) 文档。OpenRouter 通过 `HTTP-Referer` 加展示名/分类头部来创建应用页面和排名。这有价值,但它不是 HTTP 标准中的应用身份机制。风险在于:把 OpenRouter 的确切头部集合当作通用标准采纳,然后将提供方特定的头部泄漏到直连 DeepSeek 的请求、未来的 OpenAI/Anthropic/Vertex 适配器、测试服务器或无限期记录未知字段的代理中。 + +## 调研 + +- **OpenRouter 的机制是提供方特定的。** 其当前文档说明应用归属通过 `HTTP-Referer`(必需)、`X-OpenRouter-Title` 和 `X-OpenRouter-Categories` 追踪;`X-Title` 仅为向后兼容而接受。其 API 参考称这些头部为可选,并说它们使应用在 OpenRouter 上可被发现。这是一份具体的 OpenRouter 契约,而非 IETF 或 OpenAI 兼容 API 标准。 +- **在 agent 工具领域,`HTTP-Referer` 是一种 OpenRouter 感知的约定,而非通用 agent 约定。** 它足够常见,以至于 OpenRouter SDK 和示例直接暴露它,面向 OpenRouter 的框架通常需要一种方式来透传它。但 ACP(Agent Client Protocol)等 agent 协议在自己的 initialize 消息中协商名称、版本和能力,而模型提供方请求仍需 HTTP 层面的身份标识。因此「在 agent 世界被接受」意味着「被 OpenRouter 集成所识别」,而非「可跨 agent 运行时或提供方移植」。 +- **编程 agent 在 `User-Agent` 中标识产品和版本。** 公开实现在环境细节和提供方特定附加头部上各有不同,但产品身份是共同契约;不存在通用的精确格式。 +- **标准化的通用客户端身份头部是 `User-Agent`。** RFC 9110 第 10.1.5 节将 `User-Agent` 定义为用户代理软件的身份标识,说明它用于互操作性报告和分析,并说用户代理应当(SHOULD)在每个请求中发送它,除非被配置为不发送。这是唯一直接匹配「哪个产品在发出这个 HTTP 请求」的标准头部。 +- **`Referer` 是标准的,但 OpenRouter 的 `HTTP-Referer` 不是标准字段。** RFC 9110 第 10.1.3 节将 `Referer` 定义为获取目标 URI 的来源 URI,并用大量篇幅讨论隐私限制。OpenRouter 则要求 `HTTP-Referer`,将其用作应用 URL 标识符。该名称和含义是 OpenRouter 特有的,尽管它形似标准 `Referer` 头部的 CGI 环境变量形式。 +- **`From` 是标准的,但不适合作为强制默认。** RFC 9110 第 10.1.2 节将 `From` 定义为负责用户代理的人类的电子邮件地址。机器人代理应当(SHOULD)发送它以便服务器联系运营者,但非机器人代理不应在没有用户显式配置的情况下发送它,因为存在隐私和安全策略顾虑。harness 可以后续支持运营者联系方式,但不得凭空编造或全局强制要求。 +- **请求体中的 `user` 或 `metadata` 字段不是应用归属。** 某些模型 API 暴露稳定的终端用户标识符、请求元数据、标签或项目/账户头部。这些对滥用监控、内部计费、仪表盘或链路追踪有用,但它们要么标识的是终端用户而非产品,要么是提供方特定的 body schema,要么不保证能通过 OpenAI 兼容网关转发。它们不能替代静态的应用身份头部。 +- **SDK 遥测头部标识的是 SDK,而非应用。** 官方和第三方 SDK 经常发送库/版本头部。这些帮助 SDK 维护者调试客户端,但除非应用显式提供产品归属层,否则它们不会将 harness 标识为应用。 +- **pi-ai 有一流的头部钩子。** `@earendil-works/pi-ai` 的 `StreamOptions.headers` 将调用方头部最后合并(覆盖提供方默认值),因此库封装的适配器无需包装或上游改动即可满足与手写适配器相同的协议格式(wire format)契约。mock 服务器测试套件对两个适配器都断言头部到达了线路。 + +## 决策 + +在 LLM 适配器边界,提供方请求归属是强制的,且仅使用标准 `User-Agent` 头部。规则是:每个产品 LLM 适配器在每个提供方 HTTP 请求上发送一个静态、非机密的应用身份,且每个适配器都有测试证明 `User-Agent` 到达了线路(mock 服务器断言收到的头部;对于库封装的适配器,库的头部钩子喂入同一个 mock 服务器断言)。 + +本 RFC **不**实现 OpenRouter 应用归属。`HTTP-Referer`、`X-OpenRouter-Title`、`X-Title` 和 `X-OpenRouter-Categories` 是 OpenRouter 特定的产品展示头部,不是提供方无关的模型请求归属。它们可以后续由 OpenRouter 适配器或显式 OpenRouter 模式提出,带有自己的隐私/产品决策、测试和文档。在那之前,即使请求指向 OpenRouter,也只发送本 RFC 的共享 `User-Agent` 归属。 + +提供方无关的身份由 `dsh-llm`(`packages/llm/llm/src/attribution.ts`)拥有,而非各个适配器。`AppIdentity` 仅包含构建 `User-Agent` 所需的公开产品事实,默认的 `APP_IDENTITY` 确定了提案中留待决定的值: + +- `User-Agent` 的产品令牌:`deepseek-harness`(与 RFC 之前的线路值以及仓库/组织身份保持连续性) +- 版本:通过 `createRequire` 从所属包的 manifest(元数据清单)读取,绝不手动复制常量 +- 应用 URL:`https://github.com/deepseek-ai/deepseek-harness-sdk`——计划中的公开主页;`attribution.ts` 中的 `FIXME` 阻塞发布,直到该仓库实际存在 + +默认值是强制的且非空。白标部署向 `attributionHeaders(identity)` 传入自己的 `AppIdentity`——覆盖 seam 就是函数参数,在有消费方需要之前不做部署配置管道——省略时回退到 harness 默认值而非抑制归属。没有逐请求 API 让模型、用户提示词、会话 id、cwd、用户邮箱、API key 所有者或本地机器身份影响这些字段。 + +线路映射(`attributionHeaders`;代码中头部名称为小写——HTTP 字段名在线路上不区分大小写): + +| 目标 | 映射 | +|---|---| +| 所有基于 HTTP 的适配器 | `User-Agent: {product}/{version} (+{url})`——括号中的 `+url` 注释符合 RFC 9110 保守的 product/comment 语法。 | +| 直连 DeepSeek 端点 | `User-Agent`;除非 DeepSeek 文档记录了等效契约,否则不发送 OpenRouter 专用头部。 | +| OpenRouter 端点 | 目前仅 `User-Agent`。本 RFC 下不发送 `HTTP-Referer`、`X-OpenRouter-Title`、`X-Title` 或 `X-OpenRouter-Categories`。 | +| 未来提供方 | 仅 `User-Agent`,除非后续提供方特定 RFC 接受额外头部。不以类推方式复用 `HTTP-Referer`。 | + +端点检测不属于本 RFC,因为此处不接受任何端点特定映射。如果后续落地 OpenRouter 支持,检测必须是显式的:要么是专用的 OpenRouter 提供方包,要么是显式的 `provider: 'openrouter'` / `attributionTarget: 'openrouter'` 配置,而非任意路径片段或模型名。 + +## 验证 + +已落地的契约: + +- `dsh-llm` 为 `LlmAdapter` 作者记录了强制的 `User-Agent` 归属契约(`LlmAdapter` JSDoc、包 README,以及 `docs/core-data-structures/llm-streaming.md` 的适配器契约章节)。 +- 共享辅助函数(`attributionHeaders` / `userAgent`)从包元数据构建应用身份和标准 `User-Agent` 值,适配器无需手动复制版本常量。 +- `dsh-llm-deepseek` 在每个请求上发送共享的 `User-Agent`,其 mock 服务器套件断言精确值。 +- `dsh-llm-pi-ai` 通过 pi-ai 的 `StreamOptions.headers` 钩子发送相同的 `User-Agent`,其 mock 服务器套件断言精确值。 +- 本 RFC 下没有适配器发送 OpenRouter 特定的归属头部(`HTTP-Referer`、`X-OpenRouter-Title`、`X-Title`、`X-OpenRouter-Categories`)。 +- 没有应用归属字段携带机密、本地路径、会话 id、提示词文本、模型输出、用户邮箱或逐用户稳定标识符。 +- 适配器 README 声明了 `User-Agent` 归属策略,并明确避免将 OpenRouter 应用归属记录为已实现行为。 + +## 曾考虑的替代方案 + +**现在就实现 OpenRouter 应用归属。** 本 RFC 否决。发送 `HTTP-Referer` 加 `X-OpenRouter-Title` 可以满足 OpenRouter 排名,但这些头部是提供方特定的产品功能,不是本 RFC 试图标准化的提供方无关模型请求归属。支持它们应当是后续显式的 OpenRouter 适配器/模式决策,而非隐藏在第一个共享归属辅助函数中。 + +**所有地方都发 OpenRouter 头部。** 否决。这会把一份自定义 OpenRouter 契约当作通用标准,并向未要求这些字段的提供方发送语义误导的字段。还有风险把 `HTTP-Referer` 当作通用应用 URL 字段使用,尽管标准 HTTP 已有 `User-Agent` 用于产品身份、`Referer` 用于不同的浏览上下文概念。 + +**仅使用提供方账户/项目身份。** 否决。组织/项目头部、API key、云账户和计费项目标识的是谁付费或谁拥有请求,而非哪个应用在发送流量。它们也不暴露公开的应用标题/分类,不帮助 OpenRouter 等网关构建应用排名。 + +**终端用户 `user`/`metadata` 字段。** 本 RFC 否决。这些对滥用监控和客户支持有价值,但描述的是请求背后的人或租户。应用归属必须是静态产品身份,且可安全地在每个请求上发送。 + +**仅配置 opt-in 的归属。** 否决。默认关闭的设置正是适配器持续漂移的原因。策略是强制默认归属加可覆盖的公开值,而非可选归属。 + +**以产品命名的令牌(`deepseek-harness-sdk`)。** 曾考虑用于 `User-Agent` 令牌,因为产品名是 DeepSeek Harness SDK。`deepseek-harness` 以连续性胜出:它是提供方已经从本代码库看到的身份,与组织/仓库身份和包作用域一致,且在展示文案承载产品名的同时保持线路归属稳定。 + +## 后果 + +**提供方看到流量来自 harness。** 这正是目的,但意味着此前混入通用 SDK 流量的部署变得可识别。缓解措施:仅发送静态公开产品数据,并允许 fork/白标部署传入自己的 `AppIdentity`。 + +**应用 URL 指向一个尚不存在的仓库。** `deepseek-ai/deepseek-harness-sdk` 是计划中的公开主页;在创建之前该 URL 是一个悬空承诺。常量上的 `FIXME` 标记阻塞发布,使其不会在未解决的情况下发版(见 `docs/development.md` 标记语义)。 + +**不同客户端库的头部支持有差异。** 手写适配器直接设置头部;pi-ai 封装的适配器依赖 pi-ai 继续遵守 `StreamOptions.headers`(最后合并覆盖提供方默认值)。线路级 mock 服务器测试是守卫:如果 pi-ai 升级后不再投递该头部,套件变红。这对抽象层是有益的压力:一个无法设置强制头部的提供方适配器无法完整实现 harness 的 LLM 契约。 + +**OpenRouter 排名尚未受益。** `User-Agent` 是提供方无关 HTTP 身份的正确基线,但它不会创建 OpenRouter 应用页面或排名,因为 OpenRouter 要求 `HTTP-Referer` 才能实现该产品功能。这是有意为之:公开应用市场参与是一个独立的产品决策,不是强制请求归属的前提。 diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml new file mode 100644 index 0000000000..7a69d33245 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-26-file-context-as-event-gate.md: 6e78e2df5f7969b5ed9b74c0b597e2fcacbe8e82 +2026-06-26-file-context-as-event-gate.zh.md: b0806fd3e1d61a9bdaf20a728dbfcfc945013b78 diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md index 486d9aafb4..6e78e2df5f 100644 --- a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md @@ -1,5 +1,7 @@ # RFC: Make `dsh-fs-policy` an event-gate plugin, not a method interface +English | [中文](2026-06-26-file-context-as-event-gate.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md new file mode 100644 index 0000000000..b0806fd3e1 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md @@ -0,0 +1,171 @@ +# RFC:将 `dsh-fs-policy` 改为事件门禁插件,而非方法接口 + +Status: implemented + +[English](2026-06-26-file-context-as-event-gate.md) | 中文 + +## 问题 + +[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 在面向模型的工具与 `ctx.fs` 提供方之间放置了 `ctx.fileContext`:`dsh-tool-fs` 注入 `fileContext`,并将每次 `read`/`write`/`edit` 都路由到它的方法。这使得 `fileContext` **处于调用路径上且不可省略**。工具不经过它就无法触及 `ctx.fs`,策略层拥有 fs I/O 和读取窗口化,而一个不需要观测状态策略的部署无法简单地移除该包——否则 `dsh-tool-fs` 将无法解析 `ctx.fileContext`。 + +这把三件本应可分离的事情耦合在了一起: + +1. **工具做什么**——解析路径、读取窗口、写入/编辑文件。这是工具的职责,只需要 `ctx.fs`。 +2. **新鲜度/观测策略**——"编辑前必须先读"、"写入/编辑必须基于你读到的版本"。这是 `dsh-fs-policy` 插件的职责。 +3. **观测状态的记录**——一个副作用,永远不应阻止工具正常运行。 + +因为工具调用 `fileContext` 的方法,移除策略层是一个破坏性变更,而非优雅地失去一个*附加功能*。策略对于工具的运行是承重的,而非可选的收紧。 + +## 决策 + +反转控制流。**`dsh-tool-fs` 成为执行器,直接调用 `ctx.fs`**;**`dsh-fs-policy` 成为门禁 + 记录器插件**,通过事件参与,既不通过工具调用的方法,也不注册 `ctx.fileContext` 服务。 + +```text +tool dsh-tool-fs executor: resolves, reads windows, writes/edits via ctx.fs; + emits fs policy events; renders results +policy dsh-fs-policy plugin: listens to fs/write-intent + + fs/edit-intent (single-slot waterfall) and fs/observed + (emit) events; adds observed-state + freshness. +provider seam dsh-fs ctx.fs: text IO + ATOMIC mutation primitives whose version + guard is OPTIONAL; owns the fs policy event vocabulary +provider dsh-fs-local local implementation of ctx.fs +``` + +该模型是叠加式的:裸 `ctx.fs` 执行原子的、无约束的文本 I/O,而 `dsh-fs-policy` 在其上叠加观测状态、读后才能编辑、以及版本守卫。因此移除策略后工具仍可用,只是不受约束。正式发布的 agent 配置会加载策略;裸模式的存在是为了在服务边界保持策略可选,而非作为正常部署姿态。 + +`dsh-tool-fs` 不再注入 `fileContext`。它注入 `fs` 以及 `tools`/`systemPrompt`。 + +## 策略由提供方 CAS 强制执行,而非由 `dsh-fs-policy` stat + +`dsh-fs-policy` 强制执行"你必须基于你读到的版本来写入/编辑",**自身从不调用 `stat` 或比较版本**。它将观测到的版本作为 CAS 基准提供,让提供方的变更临界区检测陈旧: + +- "你读过这个文件吗?"是 `dsh-fs-policy` 在本地决定的唯一事项——一次 `WeakMap` 查找,无 I/O。无记录 ⇒ `FS_NOT_OBSERVED`。 +- "你读到的版本还是最新的吗?"由 **`ctx.fs.editText`/`writeText` 内部**决定,在执行 read-match-rename 的同一把原子锁中。`dsh-fs-policy` 将 `vObserved` 作为期望值传入;如果文件已变更,提供方抛出 `FS_STALE_VERSION`。 + +这是刻意的设计。如果 `dsh-fs-policy` 在其 waterfall(瀑布式事件)处理器中 stat 并比较版本,那么该检查与工具实际写入之间会存在 TOCTOU 间隙——文件可能在两者之间变化,因此该检查只是一个虚假保证,提供方的锁无论如何都要兜底。将版本检查放在提供方的临界区内既无竞态又零额外 `stat`。所以 `dsh-fs-policy` **不做**任何文件系统 I/O;"必须基于最新读取"的保证由 CAS *实现*,`dsh-fs-policy` 只负责选择基准(`vObserved`)并对先前观测进行门控。 + +## 提供方契约变更:版本守卫变为可选 + +为使裸提供方不受约束,其两个变更操作上的版本守卫变为**可选**——有则守卫,无则无条件: + +```ts ignore-check +// writeText: expected is now optional. The FsWriteIntent union is UNCHANGED. +writeText(target: FsTarget, content: string, expected?: FsWriteIntent, signal?: AbortSignal): Promise<FsWriteOutcome> +// undefined → unconditionally create-or-overwrite (bare default) +// createIfAbsent → create only, reject an existing file (dsh-fs-policy, unobserved) [unchanged] +// replaceIfVersion → overwrite only at the observed version, else FS_STALE_VERSION [unchanged] + +// editText: expected becomes optional (was the required { version: FsVersion }). +editText(target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion }, signal?: AbortSignal): Promise<FsEditOutcome> +// undefined → unconditionally replace literal text in the current content (bare default); +// a missing target still reports FS_STALE_VERSION +// { version } → edit only at that version, else FS_STALE_VERSION (the current behavior) +``` + +`FsWriteIntent` 联合类型本身不变——第三种"无条件"状态通过*省略* `expected` 来表达,因此两个变更操作共享一个对称的形状(`expected?`:省略 = 无守卫,提供 = 有守卫)。这对 `dsh-fs-policy` 使用的有守卫路径保持完全向后兼容;只有之前不可能的"无守卫"情况是新增的,且它是裸提供方的默认行为。无论哪种情况,变更操作仍在后端的 per-target 锁内运行,因此无条件的写入/编辑仍然是原子的(不会出现文件撕裂);"无条件"去掉的是*版本*前置条件,而非原子性。`editText` 在有守卫和无守卫路径上都将缺失的目标报告为 `FS_STALE_VERSION`,为"此刻无法编辑该目标"保留一个统一的编辑失败码。 + +## 事件词汇(归属 `dsh-fs`) + +事件定义在 `@deepseek-ai/dsh-fs` 中,而非 `dsh-fs-policy` 中。这是解耦契约所要求的:`dsh-tool-fs` 是事件发射方,因此它必须引用事件类型,且即使 `dsh-fs-policy` 不再提供方法服务,它也必须能编译通过。`dsh-fs` 是 `dsh-tool-fs` 和 `dsh-fs-policy` 都已依赖的包,因此它是唯一能让发射方和策略监听方共享词汇而不让发射方依赖策略插件的归属地。 + +这些事件携带既有的 `dsh-fs` 词汇(`FsTarget`、`FsVersion`、`FsWriteIntent`)加上一个不透明的 actor——而非面向模型的概念(行窗口、行号、渲染页脚均不会泄漏到此层)。 + +**两个 `fs/*` 决策事件是单槽位、先到先得的 waterfall。** `dsh-fs-policy` 不调用 `next()` 即返回,因此在默认部署中它占据该槽位;一个注册更早或使用 `prepend` 的监听器会取代该策略。权限、审计和沙箱关注点仍在可组合的 `tools/execute` waterfall 上。 + +actor 在 `dsh-fs` 中类型为 `object`——一个纯粹的不透明载体,提供方 seam 从不读取或窄化它。owner 的推导(`actor.agent?.session`)和 `{ agent?: { session? } }` 结构形状完全留在 `dsh-fs-policy` 内部,由其监听器将 `object` actor 窄化为该形状。`dsh-fs` 拥有事件名和 fs 词汇;它**不**拥有策略层的运行时 owner 结构。 + +```ts +import type { FsTarget, FsVersion, FsWriteIntent } from '@deepseek-ai/dsh-fs' + +interface Events { + /** + * Single-slot decision: produce the write expectation for the next + * ctx.fs.writeText. The default returns undefined (unconditional create-or- + * overwrite — the bare provider). The policy listener returns createIfAbsent + * (unobserved) or { kind: 'replaceIfVersion', version: vObserved } (observed). + * The listener does NOT call next(): one decision, not a composable chain. @mode waterfall + */ + 'fs/write-intent'(target: FsTarget, actor: object | undefined, next: () => FsWriteIntent | undefined | Promise<FsWriteIntent | undefined>): Promise<FsWriteIntent | undefined> + /** + * Single-slot decision: produce the optional version guard for the next + * ctx.fs.editText. The default returns undefined (unconditional edit of the + * current content — the bare provider; no stat). The policy listener returns + * { version: vObserved }, or throws FS_NOT_OBSERVED if the actor is unset or + * has not observed the target. Does NOT call next(): one decision. @mode waterfall + */ + 'fs/edit-intent'(target: FsTarget, actor: object | undefined, next: () => { version: FsVersion } | undefined | Promise<{ version: FsVersion } | undefined>): Promise<{ version: FsVersion } | undefined> + /** + * Record that an actor observed a target at a version, after a successful + * read/write/edit. Fire-and-forget (plain emit). Listeners MUST be + * synchronous, side-effect-only recorders (`dsh-fs-policy`'s is a WeakMap + * write); the tool does not guard the emit, so a throwing listener surfaces as + * the tool's isError result. No listener ⇒ nothing recorded. + * @mode emit + */ + 'fs/observed'(target: FsTarget, version: FsVersion, actor: object | undefined): void +} +``` + +`fs/*` 决策事件是**由工具分发的无绑定 waterfall**(类似 `agent/request`,由 loop 分发且无 `this`),而非服务绑定的 waterfall(如 `llm/stream`)。分发方是 `dsh-tool-fs` 插件,它不是一个服务。 + +## 工具契约(`dsh-tool-fs`) + +工具保留其面向模型的 schema(`read`/`write`/`edit`,逐字节不变)和 prompt 段落。prompt 引导仍以策略为先,因为加载 fs 工具的部署预期也会加载 `dsh-fs-policy`:模型仍被告知在覆写或编辑前先读取,任何说"后端"要求如此的措辞应改为说 fs-policy 插件要求如此。裸提供方的回退不改变 prompt 立场。 + +`dsh-tool-fs` 获得了从旧 `fileContext` 方法服务迁移来的执行器职责,包括**读取渲染**(`read-render.ts`:`buildWindow` + `formatReadOutput`、`READ_MAX_BYTES`、`READ_MAX_LINE_LENGTH`、`FileReadOutcome`/`FileTextLine`,以及 `read.ts` 中的 `STREAM_MIN_SIZE`),这些现在是工具的渲染细节,因为工具拥有了读取操作。这些读取渲染类型和辅助函数迁入 `dsh-tool-fs`;策略插件不得继续作为工具的类型依赖。 + +`dsh-tool-fs` 是一个注册全部三个工具(`read`/`write`/`edit`)的单根插件,与 `dsh-tool-bash` 对齐。它注入 `fs`(加 `tools`/`systemPrompt`),从不注入 `fileContext`。(最初的提案还将每个工具作为 `/read`/`/write`/`/edit` 子路径插件暴露,以支持聚焦部署;实现时已放弃——没有消费方需要单工具部署,且子路径发布迫使引入定制的 `tsdown`/`tsconfig`/`files`/workspace-constraint 处理,而同级的工具包都不需要这些。每工具的注册辅助函数(`applyReadTool`/`applyWriteTool`/`applyEditTool`)保留为根插件组合的内部模块。) + +`stat` 预算通过让 waterfall 惰性产出期望值来最小化——裸默认返回 `undefined`(无守卫),从不 stat: + +- **read**——一次 `stat`(类型 + 大小路由 + 版本),然后 `readText`/`streamText`,然后 `buildWindow`,然后 `emit('fs/observed', target, info.version, exec)`。旧 `fileContext.read` 中读取后的确认 `stat` 被移除;在路由 stat 和读取之间竞争的写入者最多只能使*后续*有守卫的编辑虚假地 `FS_STALE_VERSION`(快速失败:模型重新读取,从不基于错误版本写入,因为 `editText` 在其锁内重新检查)。 +- **write**——`expectation = await ctx.waterfall('fs/write-intent', target, exec, () => undefined)`,然后 `ctx.fs.writeText(target, content, expectation)`,然后 `emit('fs/observed', target, outcome.version, exec)`。**工具内零 stat**,无论是否有 `dsh-fs-policy`。 +- **edit**——`expectation = await ctx.waterfall('fs/edit-intent', target, exec, () => undefined)`,然后 `ctx.fs.editText(target, edit, expectation)`,然后 `emit('fs/observed', target, outcome.version, exec)`。**两种情况下工具内均零 stat**:裸默认为 `undefined`(无条件编辑),因此工具从不 stat 来制造基准。如果目标不存在,提供方即使在无守卫路径上也报告 `FS_STALE_VERSION`。 + +工具在每次分发时将 `exec`(工具执行上下文)作为 `actor` 参数传入,这样 `dsh-fs-policy` 就能推导其观测状态的 owner。工具不知道策略插件是否存在:它总是在 `next` thunk 中提供裸默认行为,而 `dsh-fs-policy` 在默认部署中会在 thunk 运行前短路它。 + +**`fs/observed` 在操作成功后触发。** 其监听器必须是同步的、不抛异常的记录器;工具不对 plain emit 做守卫,因此抛异常的监听器会在变更已成功后报告失败。异步或可失败的观测需要另一个事件契约。 + +## 策略插件契约(`dsh-fs-policy`) + +`dsh-fs-policy` 是一个插件,不是服务。它不注册 `ctx.fileContext`,没有公开方法面,也不暴露 `read`/`write`/`edit`/`resolve` 方法。它通过 `ctx.on()` 注册三个监听器(每个返回一个用于 HMR(热模块替换)的 disposer(资源释放))。它维护观测状态的 `WeakMap<owner, Map<targetKey, { version }>>` 和结构化的 owner 推导(将事件中不透明的 `object` actor 窄化为自己的 `{ agent?: { session? } }` 形状),但不注入 `fs`——每个处理器只操作自己的 `WeakMap`,从不操作 `ctx.fs`。 + +- `fs/write-intent` 监听器:`prior = getObserved(owner, key)`;返回 `prior ? { kind: 'replaceIfVersion', version: prior.version } : { kind: 'createIfAbsent' }`。它不调用 `next()`:完全占据单一决策槽位。 +- `fs/edit-intent` 监听器:`prior = getObserved(owner, key)`;如果无 `owner` 或无 `prior`,抛出 `FS_NOT_OBSERVED`;否则返回 `{ version: prior.version }`。同样不调用 `next()`。 +- `fs/observed` 监听器:`record(owner, key, version)`。 + +一条观测状态条目是**先前观测记录**:成功的 `read`、`write` 或 `edit` 都会 emit `fs/observed` 并记录 `{ version }`,因此条目的存在意味着"该 owner 在此版本观测过该目标",而非狭义的"已读取过"。这使得 create-then-edit 或 edit-then-edit 序列无需中间重新读取即可工作:变更操作将记录的版本刷新为自身的结果,因此下一次编辑的基准就是它刚产出的版本。`FS_NOT_OBSERVED` 只拒绝完全没有任何先前观测的编辑。owner 从 `{ agent?: { session? } }` 结构化推导;dispose(资源释放)时丢弃所有状态(HMR 安全)。 + +`dsh-fs-policy` 现在是一个纯策略/记录插件,没有服务面——它只通过事件 seam 影响外部世界。这正是从 `dsh-tool-fs` 移除方法耦合的关键。 + +## 裸提供方行为(无 `dsh-fs-policy`) + +这不是预期的部署姿态——加载 fs 工具的配置预期也会加载 `dsh-fs-policy`。这是工具不再耦合于策略方法服务后存在的无约束提供方下限。在 `dsh-fs-policy` 缺席时,每个 `fs/*` waterfall 都落入其 `undefined` 默认值,`fs/observed` 无监听器: + +- **read** 不变(它从不需要策略;只是 emit 了一个现在无人听取的 `fs/observed`)。 +- **write** 无条件 create-or-overwrite:`expected` 为 `undefined`,因此 `writeText` 无论文件是否存在、无论当前版本如何都直接写入。无读取前置要求,无版本检查。 +- **edit** 无条件替换文件当前内容中的字面文本:`expected` 为 `undefined`,因此 `editText` 不带版本守卫或读取前置要求即进行匹配和重写(`FS_EDIT_NOT_FOUND`/`FS_AMBIGUOUS_EDIT` 仍然适用——它们关乎字面匹配,而非新鲜度)。缺失的目标仍报告 `FS_STALE_VERSION`,与有守卫编辑路径的"此刻无法编辑该目标"错误码一致。 + +两个变更操作仍然是原子的(后端的 per-target 锁是无条件的)。简单地*不存在*(而非丢失)的是 `dsh-fs-policy` 本会叠加的策略:观测状态、读后才能编辑、以及版本守卫的写入/编辑。加载 `dsh-fs-policy` 后,其监听器返回有守卫的 `expected` 值而非 `undefined`,从而叠加这些约束;裸提供方本身不变。 + +## 取代 + +本 RFC 修正——而非撤销——[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md)。四层拆分、提供方契约和新鲜度*策略*均保留。改变的是**工具与策略层之间的耦合方式**:一个强制方法服务变成了插件拥有的事件门禁,fs I/O + 读取窗口化从 `fileContext` 上移到了 `dsh-tool-fs`。split-fs-seam RFC 中关于 `dsh-tool-fs` 注入 `fileContext` 以及 `fileContext` 拥有 `read`/`write`/`edit` 的描述已在同一变更中更新。 + +## 验证 + +测试固定了两条路径:无 `dsh-fs-policy` 时,根工具插件对 `dsh-fs-local` 启动,read、create、overwrite 和未读取的 edit 均成功;有策略时,未读取的 edit 返回 `FS_NOT_OBSERVED`,未读取的 overwrite 被 `createIfAbsent` 门控。策略做出决策后,后注册的 intent 监听器不会被触达。陈旧编辑通过提供方 CAS 失败,而策略不执行 `stat`;工具的预算在两条路径上均为 read 一次 `stat`、write 或 edit 零次 `stat`。面向模型的 schema 逐字节不变,因此快照不变。 + +## 曾考虑的替代方案 + +- **保留 `ctx.fileContext` 作为路径内方法服务**——[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 最初落地的形态;否决,因为工具不加载策略层就无法运行,使策略对基本操作是承重的,而非可选的收紧。 +- **策略侧版本检查**(`dsh-fs-policy` 在其 waterfall 处理器中 stat 并比较)——否决,因为该检查与工具实际写入之间存在 TOCTOU 间隙;提供方的变更临界区是唯一无竞态的位置,因此策略只选择 CAS 基准并对先前观测进行门控。 +- **每工具 `/read`/`/write`/`/edit` 子路径插件**——实现时放弃。没有消费方需要单工具部署,且子路径发布迫使引入定制的 `tsdown`/`tsconfig`/`files`/workspace-constraint 处理,而同级的工具包都不需要这些;每工具的注册辅助函数保留为根插件组合的内部模块。 + +## 后果 + +- **事件间接层取代方法调用。** 一次 waterfall + emit 不如 `await ctx.fileContext.edit(...)` 直接。收益是移除了工具对策略的方法依赖,同时保留默认策略插件;代价是多了一套事件词汇需要学习。通过将三个事件保持窄小并在每个事件上记录 default-thunk 语义来缓解。 +- **策略事件放在存储 seam 中。** `dsh-fs` 获得了两个版本决策事件加一个记录事件,尽管它"只是存储"。这是解耦的代价(发射方不能依赖策略插件)。这些事件只携带 `dsh-fs` 词汇加一个不透明的 `object` actor,不含面向模型的概念,因此 seam 不会沾染行窗口/观测策略类型和 agent/session owner 结构。 +- **单策略占位,按约定先到先得。** `fs/write-intent`/`fs/edit-intent` 槽位恰好容纳一个决策者;先注册(或 `prepend` 的)监听器获胜,其余被短路。`dsh-fs-policy` 占据该槽位是部署约定,而非事件强制的不变式——一个先注册的第二决策者会绕过它。这是可接受的,因为第二个 fs 版本策略决策者是配置错误,而非功能特性。如果未来出现*分层* fs 版本策略的需求,那是一个新 RFC(可组合的值传递 seam),而非在这些事件上静默添加第二个监听器。分层的权限/审计/沙箱拦截已有其归属:`tools/execute`。 +- **移除读取后的确认 stat** 使后续*有守卫*的编辑在读写竞争下偶尔快速失败(`FS_STALE_VERSION` → 重新读取)。这是丢失的 UX 便利,从不是正确性漏洞;提供方锁仍然阻止基于错误版本的写入。 +- **裸提供方不做读后写入/编辑检查,也不做版本检查。** 不加载 `dsh-fs-policy` 的部署允许模型无条件覆写或编辑任何现有文件。这正是保持工具独立于策略服务的刻意含义:安全纪律存在于 `dsh-fs-policy` 插件中。省略它的部署是有意选择无约束的文件系统;这不是发布 fs 工具的配置的预期姿态。 diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml new file mode 100644 index 0000000000..041271d286 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-30-bash-stdin-env-trusted-plugin-surface.md: 72aae03361cbc088cf64f3548a43ac6253eb21eb +2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md: 5c708cb6bfed28b2164cbd1d0b1c7368bf3e1d07 diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md index de6428fb64..72aae03361 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md @@ -1,5 +1,7 @@ # RFC: stdin + extra env on the bash seam +English | [中文](2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md new file mode 100644 index 0000000000..5c708cb6bf --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md @@ -0,0 +1,33 @@ +# RFC:bash seam 上的 stdin 与额外 env + +Status: implemented + +[English](2026-06-30-bash-stdin-env-trusted-plugin-surface.md) | 中文 + +## 问题 + +钩子子系统运行外部钩子命令的方式与 Claude Code 和 Codex 相同:一个钩子就是一条 shell 命令,通过 **stdin 上的 JSON** 接收事件载荷,并从若干**环境变量**(`CLAUDE_PROJECT_DIR`、`CLAUDE_PLUGIN_ROOT`、`PLUGIN_ROOT`……)读取上下文。harness 在 `ctx.bash` 能力 seam 背后已经有一个完善的命令运行器([dsh-bash](../../../../packages/bash/bash) → [dsh-bash-local](../../../../packages/bash/bash-local)),具备进程组 kill、输出截断/溢出处理和凭证擦除。将它复用于钩子执行,意味着钩子桥接层无需重新实现子进程管道——但该 seam 此前没有写入 stdin 或设置额外 env 的能力。本 RFC 添加这两项输入。 + +`stdin` 和 `env` 不构成新的模型能力,因为普通 shell 语法已经能提供这两者。环境中的凭证由 `dsh-bash-local` 的子进程环境擦除机制保护,而非靠隐藏这些 seam 字段;模型工具参数是静态 JSON,不会展开 shell 变量。因此这些字段服务于受信的进程内调用方(如钩子桥接层),它们需要传递结构化输入和 `CLAUDE_*` 变量,而不必将其嵌入模型可见的 shell 文本。环境变量规则见 [defensive-patterns.md](../../../defensive-patterns.md)。 + +## 决策 + +在 `BashExecRequest`(面向模型/插件的请求)和 `BashExecSpec`(`run`/`start` 实际执行的解析后规格)上**同时**添加 `stdin?: string` 与 `env?: Record<string, string>`,并在 `dsh-bash-local` 中贯穿:`resolve()` 原样传递,`run()`/`start()` 将它们传给 `runBash`,后者把字节写入子进程的 stdin 并合并额外 env。 + +三个刻意的选择: + +1. **面向模型的工具不暴露 `stdin` 和 `env`。** Shell 语法已经覆盖这些需求,重复的参数只会增加接口面而不带来权限隔离。工具仅从声明的模型参数、signal 和 owner 构建请求;受信的进程内调用方可以直接设置 seam 字段。 + +2. **`env` 在凭证擦除之后合并,因此调用方显式设置的条目总是胜出**——即使名称看起来像凭证。这是正确的,因为擦除的职责很窄:阻止 harness 自身 *ambient* `process.env` 中的凭证泄漏到子命令中。调用方显式设置一个变量时,它命名的是自己已持有的值(而非 ambient 密钥),因此擦除不是对它的约束。`childEnv(extra?)` 的分层为 `scrub(process.env)` → `ENV_OVERRIDES`(面向模型的 `TERM=dumb` 等)→ `extra`,后者优先。 + +3. **`stdin`/`env` 在解析后规格上是 required-absent-OK(普通 optional),而非像 `owner` 那样 required-but-nullable。** `owner` 之所以是 required-but-nullable,是因为*静默*缺失的 owner 会产生一个无主的、跨会话可读的任务——这是一个安全隐患,显式的 `undefined` 可以防范。`stdin`/`env` 没有这种风险:缺失意味着「无 stdin / 无额外 env」,这是安全的常规情况(所有模型驱动的调用都如此)。因此它们保持普通 optional,与 `signal` 一致。 + +`dsh-bash-local` 仅在提供了字节时才创建 stdin 管道;否则 fd 0 保持 `/dev/null`,维持原有行为。它写入字节后关闭管道。如果子进程未读取就退出导致 `EPIPE`,则忽略该错误,因为命令退出状态和输出决定结果。 + +## 曾考虑的替代方案 + +**可配置的 ambient 密钥擦除。** 否决,属于推测性需求。受信调用方可以在擦除之后显式提供所需值,无需削弱默认的 ambient 保护。 + +## 后果 + +钩子桥接层通过既有的 bash seam 传递 JSON 载荷和钩子专属变量,保留其进程组管理、截断和溢出行为。模型接口面不变,bash 工具仍是模型调用请求构建的唯一入口。相关词汇定义见 [bash 数据结构参考](../../../core-data-structures/bash.md)。 diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml new file mode 100644 index 0000000000..557ac2bab4 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-30-event-domain-semantics.md: e05c238c52052454d3e01e82767cddd9af316a9d +2026-06-30-event-domain-semantics.zh.md: a5453824183aa3f71486b5dbd24ed8c056d9c854 diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md index 4cf055179c..e05c238c52 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md @@ -1,5 +1,7 @@ # RFC: Event-domain semantics — session is the fact log, agent is the live surface +English | [中文](2026-06-30-event-domain-semantics.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md new file mode 100644 index 0000000000..a545382418 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md @@ -0,0 +1,39 @@ +# RFC:事件域语义——session 是事实日志,agent 是实时表面 + +Status: implemented + +[English](2026-06-30-event-domain-semantics.md) | 中文 + +## 问题 + +harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环)(见[微内核事件分类体系 RFC](2026-06-11-microkernel-event-taxonomy.md))。随着分类体系的增长,三个事件域之间的界限变得模糊: + +- `session/*` 承载持久的、事件溯源的日志(`SessionEventMap`)。 +- `agent/*` 承载实时运行时信号,向插件传递 `Agent` 句柄。 +- `tools/*` 承载工具注册表与执行 seam。 + +两个问题促使我们明确固定这些语义。第一,若干轮次/步骤边界同时以持久的 `SessionEvent`(`turn/start`、`turn/end`、`step/start`、`step/end`)和镜像的 `agent/*` emit(`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`)两种形式存在。消费方对同一事实有两个真源,每次生命周期变更都必须同时更新两处。第二,即将到来的 Hooks 子系统需要一个统一、有文档的订阅表面:插件作者(以及基于其上构建的 Claude Code / Codex 钩子桥接)必须无需阅读循环代码就能判断应该监听会话事件还是 agent 事件,以及为什么。 + +这套词汇是拦截决策、持久的 `hook/*` 日志,以及 Claude Code 与 Codex 桥接的基础。 + +## 决策 + +**三个域,各司其职,一条边界规则。** + +- **`session/*`——持久的、可回放的事实日志。** 拥有 `SessionEventMap`;每条记录仅含 JSON(无活对象)。每次追加触发一次 `session/event` emit,加上 `session/flush` 并行持久性检查点。它同时也是实时 transcript(文本记录)流:想要渲染或响应已发生事件的消费方在此订阅,因此实时渲染与 `session/load` 回放共享同一路径。 +- **`agent/*`——实时运行时表面。** 始终携带活的 `Agent`。两种形态:拦截型 waterfall(瀑布式事件)(`agent/request`、`agent/step-result`、`agent/turn-continuation`)可修改或否决,以及瞬态 emit(`agent/status`、`agent/error`、`agent/created`/`agent/disposed`、`agent/queued`)在持有 `Agent` 的情况下通知。轮次和步骤的**边界**不在此域——它们是持久的会话事件,从 `session/event` 读取;token 流(`assistant/chunk`)和中途引导(`steering/message`)同理。 +- **`tools/*`——工具注册表与执行 seam。** + +**边界规则:** 持久的、可回放的事实是 `SessionEvent`;实时拦截或瞬态/活对象信号是 `agent`/`tools` Cordis 事件。轮次或步骤边界是持久事实,因此存在于会话日志中、从 `session/event` 流读取——不会被镜像为 `agent/*` emit。 + +**将规则应用于边界镜像:** 全部四个边界镜像——`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`——被**移除**。没有生产消费方需要在边界处持有活的 `Agent`:ACP 桥接从 `session/event` 的 `turn/end` 加 `agent/status` 结算;唯一的 turn 镜像消费方(`dsh-ui-stdio`,一个一次性测试 REPL)已迁移为从 `session/event` 渲染边界,通过 `agent/created`→id 映射恢复简短的 agent 标签。step 镜像先被移除(它们根本没有消费方);turn 镜像在 ui-stdio 迁移后随之移除——见[移除边界镜像事件 RFC](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md),该决策由它拥有。移除这些 emit 也简化了循环的 `closeStep`/`closeTurn`(各只需一次 append,无需配对 emit)。 + +## 后果 + +- 循环不再 emit 任何边界镜像;`closeStep` 仅追加 `step/end`,`closeTurn` 仅追加 `turn/end`。`Session.append` 负责 post-commit observer 的隔离,因此抛出异常的边界 observer 无法改变轮次结果或饿死后续消费方;acceptance 或内部校验失败仍会在边界进入日志之前逃逸。 +- 之前通过已移除 emit 观察边界的测试现在观察持久的 `turn/start`/`turn/end`/`step/start`/`step/end` 会话事件——它们所固定的行为(边界排序、步骤计数)不变;只是读取的流切换到了权威的那一个。那些测试「抛出异常的 turn 边界 emit 监听器」的用例被删除,因为该代码路径已不存在(没有 emit 可供抛出)。按照 [AGENTS.md "tests document behavior, not golden truth"](../../../../AGENTS.md),行为与其测试一起迁移(或一起消亡)。 +- 循环仅在 `append('step/start')` 返回后才标记步骤为已打开(`stepOpen = true`)。内部 dispatch 校验在日志推送前运行,可能在不打开步骤的情况下拒绝;post-commit `session/event` observer 的失败被隔离在 `Session.append` 内部。因此该标记精确代表已提交的边界,该边界欠一个后续的 `step/end`。 +- 本 RFC 的完整实现是[简化 RFC「停止将持久边界镜像为 agent 事件」](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md):全部四个边界镜像被移除,所有消费方从 `session/event` 读取边界。`agent/steering`(不是边界镜像)不在该 RFC 范围内,由其后续 RFC [移除 `agent/steering` 镜像 emit](../simplification/2026-07-04-remove-agent-steering-mirror.md) 单独移除——它镜像的是持久的 `steering/message`。 +- Cordis 事件目录(`docs/cordis-catalog/events.md`)重新生成以移除镜像事件。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml new file mode 100644 index 0000000000..fc9d825dc0 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-02-fs-per-session-cwd.md: 00643955d918dff87241f4b240bb7e6774d21a0b +2026-07-02-fs-per-session-cwd.zh.md: ca37e1f41af53c43151ac82e1be1b76eaafdb97e diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md index fad851265d..00643955d9 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md @@ -1,5 +1,7 @@ # RFC: Resolve filesystem paths against the caller's session cwd +English | [中文](2026-07-02-fs-per-session-cwd.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md new file mode 100644 index 0000000000..ca37e1f41a --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md @@ -0,0 +1,34 @@ +# RFC:将文件系统路径解析基于调用方的会话 cwd + +Status: implemented + +[English](2026-07-02-fs-per-session-cwd.md) | 中文 + +## 问题 + +ACP 桥接层为每个会话提供独立的工作区:`session/new` 将编辑器的项目目录记录为 `SessionHeader.cwd`,`dsh-tool-bash` 将每次 bash 调用的 `workdir` 默认设为调用方 agent 的 `session.header.cwd`(见 [`packages/ui/acp`](../../../../packages/ui/acp) 中的 per-session cwd RFC 相关工作,以及 `dsh-tool-bash` 中的 `resolveWorkdir`)。因此会话 A 中的 bash 命令在 A 的项目目录运行,会话 B 中的在 B 的项目目录运行——一个服务器进程,N 个工作区。 + +文件系统路径解析使用的是插件加载时的单一 cwd,而 bash 使用的是会话的项目目录。因此,当编辑器项目目录与服务器启动目录不同时,相对路径的解析结果就会不一致;快照测试因为让这两个路径相同而掩盖了这个 bug。 + +## 决策 + +将调用方的会话 cwd 透传到路径解析中,与 `dsh-tool-bash` 对 `workdir` 的处理方式完全一致。**调用方**(即工具)提供 cwd;提供方不读取会话或 agent。 + +- `FileSystem.resolve` 扩展为 `resolve(path: string, opts?: { cwd?: string }): Promise<FsTarget>`。`opts.cwd` 是相对 `path` 的解析基准;绝对 `path` 忽略它;省略 `opts.cwd` 时使用后端自身的默认值。使用 options 对象(而非位置参数 `cwd?`)为将来的解析提示留出空间,无需再次变更签名。 +- `dsh-fs-local.resolve` 使用 `resolveLocalTarget(opts?.cwd ?? this.config.cwd, path)`。`config.cwd` 仍是调用方未提供 cwd 时的默认值(非 ACP/无会话场景,以及 `process.cwd()` 本身就是工作区的单会话 stdio 演示)。 +- `dsh-tool-fs` 的 `read`/`write`/`edit` 通过共享的 `sessionCwd(exec)` 辅助函数获取会话 cwd(`exec.agent?.session.header.cwd`,与 bash 的 `resolveWorkdir` 一致),并传给 `resolve`。非 agent/无 header 的调用方返回 `undefined`,后端则应用其默认值。 + +## 曾考虑的替代方案 + +### 为什么由调用方提供 cwd(而非提供方) + +提供方 seam 不应依赖 `dsh-agent`/`dsh-session`:它是一个文本存储后端,沙箱或远程实现同样满足该接口,而它们没有「agent 会话」的概念。工具已经接收到 `ToolExecution`(`exec`),其中携带了 agent,因此工具是将 `exec → cwd` 投影并向提供方传递一个纯字符串的正确位置。这遵循「包边界处显式优于隐式」的约定:基目录作为显式参数到达提供方并由其执行,而非让提供方越界去读取它不应知道的会话。这也与 `dsh-tool-bash` 一一对应,使两个面向模型的文件操作接口以相同方式解析路径。 + +默认值只存在于**一个**地方:提供方的 `config.cwd`。`sessionCwd` 在没有会话时返回 `undefined` 而非 `process.cwd()`,因此工具永远不会制造一个提供方本来会自行选择的基目录。 + +## 后果 + +- 在 ACP 演示中,fs 工具和 bash 现在对每个会话的工作区达成一致;编辑器可以打开任意项目文件夹,两类工具都在该目录下工作。 +- `FsTarget` 的标识不变:`targetKey` 仍然是解析后绝对路径的 realpath,因此 observed-state 键控和符号链接标识不受影响——正确的 per-session cwd 产生的 key 与 bash 目标一致。 +- 向后兼容:所有现有的 `resolve(path)` 调用(均在测试中)继续正常工作;新参数是可选的。 +- 单会话 stdio 演示不受影响:它不提供会话 cwd(其 agent 的会话没有 `cwd`),因此解析回退到 `config.cwd = process.cwd()`,即工作区本身。 diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml new file mode 100644 index 0000000000..b5dcdf42f8 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-02-result-time-applied-hunk-diffs.md: 81ab8b9827ddaec39d63e2a3f8fbb864085a9ac9 +2026-07-02-result-time-applied-hunk-diffs.zh.md: 3914bb872025d7116a047dfaf3455f527e35879a diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md index 218cb29297..81ab8b9827 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md @@ -1,5 +1,7 @@ # RFC: Result-time applied-hunk diffs for file mutations +English | [中文](2026-07-02-result-time-applied-hunk-diffs.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md new file mode 100644 index 0000000000..3914bb8720 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md @@ -0,0 +1,61 @@ +# RFC:结果时刻的 applied-hunk diff 用于文件变更 + +Status: implemented + +[English](2026-07-02-result-time-applied-hunk-diffs.md) | 中文 + +## 问题 + +[带标签的渲染意图联合类型](2026-07-02-tool-render-intent-union.md)为 `dsh-tool-fs` 的 write/edit 在调用时(CALL time)提供了 `card:'diff'`,纯粹从工具参数推导:write ⇒ `{oldText:null, newText:content}`(整个新文件),edit ⇒ `{oldText:old_string, newText:new_string}`(裸替换片段)。编辑器将其渲染为行内 diff,但这是一个**无上下文**的 diff:裸的 `old_string`→`new_string` 没有周围行,而一次 `replace_all` 如果触及五个分散位置,仍然只渲染为一对片段。 + +驱动 `claude-agent-acp` 自身的 ACP 桥接层可以看到完整编辑器 diff 的样子:变更应用后,它发出第二个 `tool_call_update`,其 diff 是**带 ±3 行上下文的 applied hunk**(`replace_all` 的每个变更位置各一个 hunk),由工具的 `structuredPatch` 重建。这个结果时刻的 hunk 正是让 Zed 在文件中*原地*展示变更(而非浮动片段)的关键。我们的工具止步于调用时片段;完成后的结果只携带纯文本 "updated successfully",没有 diff。 + +障碍在于一个 seam 边界:`presentResult(args, result)` 是 **`args` + 面向模型的 `result`(`{content, isError}`)的纯函数**——它在实时流式输出和会话日志回放时都会运行,因此必须具有回放确定性且不能做 I/O。它看不到文件的变更前/后内容,而 `FsEditOutcome`/`FsWriteOutcome` 只携带替换计数 + 版本,没有文本。因此既无法计算、也无法传递 applied hunk 给 presenter。 + +## 决策 + +新增一个**持久化的、工具私有的展示通道**,使工具的 `execute` 能附加一个结果时刻的渲染载荷并在回放中存活,并用它来承载 applied-hunk diff。 + +### 1. 工具结果上的 `meta` 通道(core) + +`ToolDefinition.execute` 现在可以返回其面向模型的 `ContentBlock[]`(不变,常见情况)或 `{ content: ContentBlock[]; meta?: unknown }`: + +```ts ignore-check +type ToolExecuteReturn = ContentBlock[] | { content: ContentBlock[]; meta?: unknown } +``` + +`meta` 是工具自有的 `unknown`,core 持久化它但不解释。`Session.append` 拒绝非 JSON 值,回放时将存储的载荷传回 `presentResult`;因此展示无需 I/O 或重新计算即可复现。运行时校验避免了向 tools core 添加共享的 serializable-value 依赖。 + +这是通用形态("工具附加持久化的结果展示"),而非 fs 专用——任何工具都可以使用。 + +### 2. 工具计算 hunk;后端返回变更前/后文本(fs) + +按照[能力-seam 拆分](2026-06-13-capability-seams.md),存储后端只返回**存储事实**,面向模型的工具拥有**展示**: + +- `dsh-fs` 扩展 `FsEditOutcome`,增加 `{ before: string; after: string }`;扩展 `FsWriteOutcome`,增加 `{ before: string | null; after: string }`(`before: null` ⇒ 新建文件,或已存在但不可 diff 的二进制/非 UTF-8 文件)。本地后端在写入时已持有两份文本;它以原始 LF 规范化文本返回,**不让任何 diff/UI 概念进入 seam**。 +- `dsh-tool-fs` 将带上下文的 hunk 存入 `meta: { diffs: FileDiff[] }`。成功的变更始终以 diff 卡片完成,因为 ACP 结果内容会替换 pending 卡片:新建或无变化的覆写回退为参数推导的全文件 diff,而编辑使用 applied hunk。失败的变更不携带 diff 元数据,正常渲染错误信息。 + +### 3. 桥接层渲染 `diff` 结果卡片 + +`ToolResultView` 新增 `DiffResultView { card:'diff'; title?; diffs: FileDiff[] }`;桥接层结果侧的 `switch (view.card)` 增加 `diff` 分支,发出 `{type:'diff'}` 的 `ToolCallContent` 块(与调用侧分支对称)。ACP 的 `tool_call_update.content` 在编辑器中**替换**调用时的内容,因此结果 diff **取代**调用时片段(并防止面向模型的结果文本覆盖它)——两次更新的序列(先调用片段,后结果 diff)与 `claude-agent-acp` 完全一致。 + +## 曾考虑的替代方案 + +**手写或 vendor diff 算法。** 带上下文的 hunk 有已知的边界情况,因此 `dsh-tool-fs` 使用带类型的 [`diff`](https://www.npmjs.com/package/diff) 包,并在一个模块中规范化 `structuredPatch` 输出。本仓库的 vendor 策略适用于其框架源码,而非每个叶子工具。 + +## 后果 + +`tool/result` 事件现在可以携带工具私有的 `meta` 载荷——属于磁盘词汇的一部分,由 `Session.append` 在运行时限制为 JSON——任何工具都可以附加持久化的结果展示而无需再改 core。diff 卡片在会话重载和快照回放时免费复现:从日志读回,从不重新计算。代价:覆写操作在内存中同时持有变更前和新文本以计算仅用于 UI 的 hunk(`TODO(overwrite-diff-bound)`),且 `dsh-tool-fs` 引入了一个小型、知名的运行时依赖。 + +## 非目标 + +- **实时增量 diff 流式输出。** hunk 在变更完成后一次性计算;没有逐按键 diff。 +- **对二进制/非 UTF-8 覆写做 diff。** 此类文件的 `before` 为 `null`(没有文本 diff 基础);写入仍然成功,结果渲染全文件 diff(`oldText: null`)而非带上下文的 hunk。 +- **重命名/移动 diff。** 仅对单个已解析路径做内容 diff。 +- **限制覆写 diff 基础的大小。** 覆写操作将整个旧文件读入内存以计算带上下文的 hunk(在已持有的新内容之上),因此非常大的文本覆写会为仅 UI 用途的 diff 分配两份文本。后续优化可以设定预读上限,超过阈值时回退到全文件/无上下文 diff;以 `TODO(overwrite-diff-bound)` 标记在读取位置。 + +## 相关 + +- 补齐了[带标签的渲染意图联合类型](2026-07-02-tool-render-intent-union.md)中作为非目标列出的最后一项表示差异——该 RFC 的「非目标」一节已更新,记录 applied-hunk diff 在此处交付。 +- 建立在[文件系统能力 seam](2026-06-17-filesystem-capability-seam.md)(变更前/后文本是后端返回的存储事实)和[事件溯源会话](2026-06-11-event-sourced-sessions.md)(`meta` 载荷持久化在 `tool/result` 事件上,因此回放可复现卡片)之上。 +- `meta` 通道有意设计为通用的:未来的工具(结构化搜索、数据表结果等)可以附加自己的持久化结果展示而无需再改 core。 diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml new file mode 100644 index 0000000000..4c8a1f1b63 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-02-tool-render-intent-union.md: 8256f09f9c297658627d0c3d9e99ee1c5424b254 +2026-07-02-tool-render-intent-union.zh.md: ed46bf0a8bea1cbfbce4287e5dc48be21c8d8fb9 diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md index cdaf152d73..8256f09f9c 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md @@ -1,5 +1,7 @@ # RFC: Tagged render-intent union for tool-call presentation +English | [中文](2026-07-02-tool-render-intent-union.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md new file mode 100644 index 0000000000..ed46bf0a8b --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md @@ -0,0 +1,82 @@ +# RFC:用于工具调用展示的标签化 render-intent 联合类型 + +Status: implemented + +[English](2026-07-02-tool-render-intent-union.md) | 中文 + +## 问题 + +工具通过 `ToolDefinition` 上的两个回调 `presentCall`/`presentResult` 声明其调用在 UI(编辑器的工具调用卡片)中的渲染方式,返回 `ToolCallPresentation` / `ToolResultPresentation`,并带有可选的 `ToolTerminal` 子结构。这些类型在增量演进中变成了一个**可选字段的大杂烩**:调用侧有 `title`、`kind`、`rawInput`、`content`、`locations`、`terminal`;结果侧有 `title`、`content`、`terminal`;`ToolTerminal` 上有 `cwd`/`output`/`exitCode`/`signal`。职责划分含混不清: + +- 调用侧和结果侧的 `terminal` 字段重叠,bridge 需要将一个 `content` 块、一个 `terminal` 块和 `rawInput` 按调用拼接在一起,靠临时条件逻辑缝合。 +- 哪些组合是*合法的*没有文档:一个设置了 `terminal` 的调用如果同时设置了 `content`,含义是「卡片上方的描述」;一个 generic 调用如果设置了 `terminal`,毫无意义但类型允许。类型允许无意义的状态。 +- 无法表达编辑器最需要的文件工具能力:**diff 卡片**(`{path, oldText, newText}`,Zed 将其渲染为内联 diff / 新文件预览)。`ToolCallPresentation.content` 是 *LLM* 的 `ContentBlock[]` 词汇(text/image),工具字面上无法请求一个 diff。 + +`packages/core/tools/src/index.ts` 中现有的 `FIXME(tool-presentation)` 指明了修复方向:「重新设计类型,让工具一次性声明其渲染意图(例如按卡片种类的标签联合类型),而不是一堆可选字段由 bridge 拼接。」被否决的 RFC [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) 明确推迟了此事:富渲染「应当在至少有两个真实工具和两个真实消费方来验证词汇之后,以标签化 render-intent 联合类型的形式回归」。这个门槛现已达到:两个生产方族(`dsh-tool-bash`、`dsh-tool-fs`)和两个消费方(ACP bridge 实时路径 + snapshot-golden 回放路径)。 + +## 决策 + +用一个**以 `card` 为标签的可辨识联合类型**替代可选字段大杂烩。工具为每次调用/结果声明一个渲染意图;bridge 按标签分发。 + +```ts ignore-check +type FileLocation = { path: string; line?: number } +type FileDiff = { path: string; oldText: string | null; newText: string } // oldText null ⇒ new file + +// presentCall → ToolCallView +type ToolCallView = GenericCallView | TerminalCallView | DiffCallView +interface GenericCallView { card: 'generic'; title: string; kind?: ToolCallKind; rawInput?: unknown; content?: ContentBlock[]; locations?: FileLocation[] } +interface TerminalCallView { card: 'terminal'; title: string; description?: string; cwd?: string } +interface DiffCallView { card: 'diff'; title: string; diffs: FileDiff[]; locations?: FileLocation[] } + +// presentResult → ToolResultView +type ToolResultView = GenericResultView | TerminalResultView +interface GenericResultView { card: 'generic'; title?: string; content?: ContentBlock[] } +interface TerminalResultView { card: 'terminal'; title?: string; output?: string; exitCode?: number; signal?: string } +``` + +`card` 在每个变体上都是**必填**的:一个真正的判别字段,而非可选默认值。bridge 执行 `switch (view.card) { case 'generic': … case 'terminal': … case 'diff': … default: assertNever(view) }`。该联合类型是**封闭的**(遵循 [switch 穷举约定](../../../../AGENTS.md)):第四种渲染意图(表格、图表)无论如何都需要新的 bridge 代码来渲染,因此一个插件添加的变体如果被 bridge 静默丢弃,比编译错误更糟。添加变体会在 bridge 的 switch 处中断编译——这正是我们想要的信号。 + +### 为什么标签联合类型优于字段大杂烩 + +- **无效状态变得不可表示。** generic 卡片不能携带终端输出;terminal 卡片不能携带 diff。旧的大杂烩允许所有这些组合。 +- **bridge 按分支分发,而非拼接。** 每种卡片一个分支,各自精确产出该卡片所需的协议格式(wire format),而非协调五个交互关系未文档化的可选字段。 +- **`diff` 成为一等意图。** `dsh-tool-fs` 的 write/edit 声明 `card:'diff'`;bridge 发出 ACP `{type:'diff', path, oldText, newText}` `ToolCallContent`(已存在于 SDK 的 `ToolCallContent` 联合类型中,此前 bridge 未使用)。这是本次重设计解锁的能力。 + +### 生产方映射 + +- `dsh-tool-fs` read → `generic`(`kind:'read'`,附带一个 follow-along `location`);write → `diff`(`oldText:null`);edit → `diff`(`oldText:old_string || null`,`newText:new_string ?? ''`)。这与 `claude-agent-acp` 的 `toolInfoFromToolUse` Read/Write/Edit 分支逐字段对应。 +- `dsh-tool-bash` foreground → `terminal` 调用 + `terminal` 结果;`run_in_background` 和 `bash_output`/`bash_kill` → `generic`。 +- `dsh-tool-todo` → `generic`。 + +### 终端回退的归属 + +`TerminalResultView` 只携带 `output`/`exitCode`/`signal`。不具备终端能力的 UI 需要一个围栏 ` ```console ` 文本回退;该推导移至 **bridge**(bridge 在无能力路径上将 `output` 包裹为围栏代码块),而非由工具双重编码。这使 bash 工具的结果保持单一结构化形状,并逐字节保留既有的 capability 门控行为。 + +### 纯函数性保持不变 + +`presentCall`/`presentResult` 仍然是 `args`(以及 `presentResult` 的 result)的纯函数——它们在实时流式输出和会话日志回放中都会运行,因此必须具备回放确定性。每个 view 仅从 args 推导:write 的 diff 是新文件样式(`oldText:null`),因为工具在调用时没有旧内容;edit 的 diff 是 `old_string`→`new_string`。 + +## 相对路径显示标题 + +`claude-agent-acp` 将文件卡片的标题路径相对于会话 cwd 做相对化处理(`toDisplayPath`):显示 `Read src/foo.ts` 而非 `/abs/proj/src/foo.ts`,同时保持 `locations[]`/`diff.path` **原始**(编辑器打开真实路径)。我们的 `presentCall` 是纯函数/仅依赖 args,无法看到会话 cwd,因此相对化发生在 **bridge**——bridge 已经将会话 cwd 传入工具调用渲染(与它用于解析 terminal 卡片标题的 cwd 相同)。bridge 仅对标题做相对化,通过对已知 `locations[0].path`/`diffs[0].path` 子串的精确结构化替换实现——对文件卡片类型通用,从不特判工具名。 + +## 曾考虑的替代方案 + +- **完全删除工具自有的展示**:即[被否决的 collapse 提案](../../rejected/simplification/2026-06-20-generic-tool-rendering.md);其结论明确推迟到两个真实工具和两个真实消费方存在后再做这个联合类型,而该门槛现已达到。 +- **可合并扩展的联合类型**(`ContentBlockMap` 模式):否决。新的渲染意图无论如何都需要新的 bridge 代码来渲染,因此一个插件添加的变体如果被 bridge 静默丢弃,比封闭联合类型在 bridge 的 `assertNever` switch 处引发的编译错误更糟。 +- **保留可选字段大杂烩**:即「问题」一节所剖析的现状:无效状态可表示、字段交互未文档化、且完全无法请求 diff 卡片。 + +## 后果 + +新的渲染意图是 bridge switch 处的编译中断变更——这是有意为之:渲染代码必须在卡片种类存在之前就位。无效的卡片/字段组合现已不可表示,bash 回退推导归 bridge 所有,工具只返回一个结构化形状。第四种卡片(表格、图表)的门槛是在同一个变更中编写其 bridge 分支。 + +## 非目标 + +- **实时增量 `terminal_output_delta` 流式输出**与**命令分类**:终端渲染 RFC 自身推迟的后续工作,本 RFC 不涉及。 + +## 相关 + +- 取代 [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md)(已否决——「等两个真实工具和两个真实消费方,然后做标签化 render-intent 联合类型」)中的推迟决定。该门槛现已达到;本 RFC 即是那个联合类型。 +- 由 [Result-time applied-hunk diffs](2026-07-02-result-time-applied-hunk-diffs.md) 扩展:该 RFC 增加了一个持久化的 `meta` 通道,使 write/edit 在结果时发出 `DiffResultView`(应用后的变更:带上下文行的 contextual hunk / 每个 `replace_all` 站点一个,或新建文件的整文件 diff),叠加在本联合类型的调用时 diff 卡片之上。 +- 将 `ToolTerminal` 折入 [ACP terminal and tool-call rendering](../feature/2026-06-18-acp-terminal-and-tool-rendering.md) 所描述的 `terminal` view(`_meta` terminal 卡片约定和 capability 门控不变;仅 harness 侧的展示类型改变)。 +- ACP SDK 的 `Diff` / `ToolCallContent` 类型支撑新的 `diff` 卡片。 diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml new file mode 100644 index 0000000000..25679116f6 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-03-filesystem-directory-listing-seam.md: bb8d9c4deda18b320b85d548bbd5bcb32f1c1d72 +2026-07-03-filesystem-directory-listing-seam.zh.md: a0332fe6cec576ad1c5b4722e2decb87344aeee1 diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md index 451cce45d3..bb8d9c4ded 100644 --- a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md @@ -1,5 +1,7 @@ # RFC: Add direct directory listing to the filesystem seam +English | [中文](2026-07-03-filesystem-directory-listing-seam.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md new file mode 100644 index 0000000000..a0332fe6ce --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md @@ -0,0 +1,53 @@ +# RFC:为文件系统 seam 添加直接目录列举能力 + +Status: implemented + +[English](2026-07-03-filesystem-directory-listing-seam.md) | 中文 + +## 问题 + +`@deepseek-ai/dsh-fs` 是文件系统访问的提供方 seam,本地后端与未来的非本地后端共享同一个 `ctx.fs` 契约。在本次变更之前,它能解析路径、stat 目标、读取文本、流式读取文本、写入文本和编辑文本。这对面向模型的文件工具已经够用,但对于需要枚举目录而又不想直接导入 `node:fs` 的非模型侧消费方来说还不够。 + +直接的压力来自 skill 加载:读取单个 `SKILL.md` 已经可以走 `ctx.get('fs')`,但发现哪些 skill 根目录下包含 `<name>/SKILL.md` 或 `<name>.md` 仍需要目录枚举。如果只在 `dsh-skill` 中添加目录列举,要么保留一个直接的 Node 依赖,要么在文件系统提供方栈之外发明一个一次性的本地辅助函数。 + +本决策只添加提供方能力,不引入面向模型的 `ls`/`list` 工具,也不改变 skill 发现逻辑。那些消费方需要独立的 UX、提示词和策略决策。 + +## 决策 + +在 `@deepseek-ai/dsh-fs` 中添加 `FileSystem.listDir(target, signal?)`。 + +`listDir` 仅列举一级目录。它以稳定的名称顺序返回直接子项,包含: + +- `name`:子项的 basename。 +- `type`:`file`、`directory` 或 `other`。 +- `target`:已解析的子项 `FsTarget`。 +- `version`:可用时提供的轻量元数据。 +- `size`:可用时提供的常规文件大小。 + +它从不读取文件内容。递归遍历、glob 匹配、分页、搜索、文件监听和面向模型的渲染均有意不在范围内。 + +本地后端通过 `readdir({ withFileTypes: true })`、`resolveLocalTarget` 以及元数据 `stat`/`realpath` 探测来实现。结果顺序是确定性的(`name.localeCompare`),以保持未来消费方的提示词/列表输出稳定,并提升前缀缓存复用率。 + +损坏或已消失的子项可以表示为 `type: 'other'`(不带 `version`/`size`);它们不会中止整个列举。列举目录或解析/探测子项元数据时遇到的权限或后端 I/O 故障会以结构化的 `FsError` 代码使整个列举失败: + +- `FS_NOT_FOUND`:目标不存在。 +- `FS_NOT_DIRECTORY`:目标存在但不是目录。 +- `FS_PERMISSION_DENIED`:权限不足。 +- `FS_IO_ERROR`:其他后端 I/O 故障。 +- `FS_ABORTED`:调用被中止。 + +## 曾考虑的替代方案 + +**在添加 seam 的同时添加面向模型的 list 工具。** 否决。其提示词、schema 和渲染契约与提供方原语无关。 + +**让每个消费方自行枚举目录。** 否决。这会把 `dsh-skill` 等产品包绑定到 Node/本地文件系统行为上,绕过策略/远程/沙箱后端。 + +**让 `listDir` 支持递归或 glob 形式。** 暂时否决。skill 根目录发现只需要直接子项,简单的单级列举是未来消费方可以安全组合的最小后端契约。 + +**跳过元数据解析失败的子项。** 否决。API 承诺返回已解析的子项 target,因此解析子项时遇到的权限/IO 故障属于契约失败。损坏或已消失的子项是例外,因为它们仍可在不声称拥有一个活跃已解析文件的前提下被表示。 + +## 后果 + +每个文件系统后端现在必须多实现一个提供方原语。这是 harness 尚未发布时有意为之的基础工作,但也意味着未来的沙箱/远程后端需要定义等价的直接子项列举行为。 + +该能力仍然面向提供方。在消费方落地之前,ACP/模型会话仍需使用 `bash` 等既有工具来列举目录。没有面向模型的 `listdir` 工具是预期行为,而非接线遗漏。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml new file mode 100644 index 0000000000..8ae2221209 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-05-prompt-variables-and-tool-guidance-ownership.md: fce9d555c8843b99fdbfa7b652b46d0b88053935 +2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 5af4fca19649d4ee458eaa6a23ae7374abdd89e4 diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md index 854807c109..fce9d555c8 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md @@ -1,5 +1,7 @@ # RFC: Prompt variables and tool-guidance ownership +English | [中文](2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md new file mode 100644 index 0000000000..5af4fca196 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md @@ -0,0 +1,72 @@ +# RFC:提示词变量与工具指导归属 + +Status: implemented + +[English](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) | 中文 + +## 问题 + +组装后的系统提示词有四个缺陷,同属一类:harness 已经掌握的事实在别处被手工重述,然后漂移。 + +**模型无法知道自己的名字。** `AgentOptions.model` 驱动每次请求,但没有任何提示词文本携带它——也不可能携带:`dsh-system-prompt` 中的 section 是上下文全局的,而模型名称是 per-agent 的,且 `assemble()` 根本不接受任何 per-agent 输入。 + +**工具指导是叶子 YAML 中的手写行文。** bash/subagent/todo_write 的使用指导存放在 `examples/coding-agent/cordis.yml` 和 `examples/acp-agent/cordis.yml` 的 `systemPrompt` 字符串中——两份漂移的副本(ACP 那份已经被删减)——而 `dsh-tool-fs` 和 `dsh-tool-web` 则以 `ctx.systemPrompt.section()` 贡献的方式持有各自的指导。加载或卸载一个工具插件意味着手动编辑每个部署的 persona;两份 YAML 都带着一条 `FIXME(config-comments)` 为这种割裂的症状道歉,stdio 的欢迎横幅也手动枚举了工具集。 + +**Persona 渲染在工具指导之后。** agent loop(智能体循环)将 `agent.options.systemPrompt` 字符串拼接在已组装的 section 之后,于是模型先读到「使用 read 工具……」再读到「你是 coding-agent」——与身份优先的惯例(Claude Code、Codex)相反,且在 section 流水线之外形成了第二条组合路径。 + +**Fork 工具的描述是假的。** `dsh-tool-subagent` 硬编码了一段为 spawn 语义撰写的描述——"a separate agent that works in its own context … it does not see this conversation"——而 `subagent_fork` 实例(其子 agent 继承父级已完成的轮次)拿到了同样的措辞;YAML 行文在带外纠正了这个谎言。小问题同族:`PromptSection.name` 文档写着"(diagnostics / dedup)",但重复项被静默接受。 + +## 决策 + +**一条原则:提示词中的每个事实恰好有一个归属方。** 模型名称和工作区是配置/会话事实 → harness 将它们暴露为变量,persona 引用它们。每个工具的语义和何时使用 → 工具的 `description`。description 无法承载的跨调用习惯 → 工具包的 prompt section。harness 出处 → 静态的 `harness:identity` section。部署角色和行为 → 部署的 persona。 + +### 组装上下文 + +`SystemPrompt.assemble(context)` 接受一个可 merge 扩展的 `AssembleContext`。`dsh-system-prompt` 声明用于 scoped routing 的可选 `scope` 选择器,而 `dsh-agent` 通过 declaration-merge 将可选的类型化 `agent` 字段附加到其上(类型层面的 `agent → system-prompt` 边,无运行时依赖环)。循环在每一步调用 `assembleContextFor(agent)`,使两个字段标识同一个 agent;section 文本提供方可以读取该上下文,`system-prompt/assemble` waterfall(瀑布式事件)也会收到它,监听方可据此按 agent 过滤或扩展。 + +### 提示词变量 + +插件通过 `ctx.systemPrompt.variable(name, provider)` 注册 `{{name}}` 值。组装时将它们解析到 waterfall 可见的变量映射中。渲染阶段拒绝:未知的 own-property 引用、注册的 provider 返回 `undefined`、格式错误的完整引用、以及仍包含闭合 `}}` 的不平衡引用;孤立的未匹配 `{{` 保留为行文,替换后的值不会被再次扫描。注册阶段拒绝无效或重复的变量名,section 名称也必须唯一。 + +`dsh-agent-loop` 注册两个内置变量,均为上下文 agent 的纯投影:`model`(= `options.model`)和 `cwd`(= `session.header.cwd`)。示例 persona 写 `powered by the {{model}} model`——模型名称只在 `model:` 配置键中声明一次。`{{cwd}}` 仅在 ACP 示例中演示:每个 ACP 会话携带客户端的 cwd,而配置预创建的 stdio agent 没有 cwd(在那里声称 `{{cwd}}` 的 persona 会导致该轮次失败——这是有意为之)。变量留在 loop 插件上(不同于下文的 section):它们是本循环所驱动的 agent 的运行时事实,替换循环自行提供自己的变量。 + +### Persona 作为 order-0 section + +`dsh-system-prompt` 持有 order 为 `-100` 的 `harness:identity` 和 order 为 `0` 的已配置 `deployment:persona`,因此两者在替换循环时仍然存活。提示词渲染只有一条路径 `renderPrompt(assembly)`,`agent/pre-step` 因此能测量用于压缩(compaction)的确切提示词。agent 作用域的 `deployment:persona` 遮蔽全局默认值,允许 subagent 提供方在发布前安装 persona。约定的 order 分段为:identity `-100`、persona `0`、工具指导 `100–199`。 + +### 工具指导归属 + +每个工具的语义和选择指导存放在工具描述中。Prompt section 仅承载跨调用习惯,例如检查 bash 退出标记或优先使用文件系统工具而非 shell 命令。`todo_write` 和 subagent 工具不需要 section,因为它们的描述已包含完整契约。部署 persona 只包含角色和行为。 + +### Subagent 对话历史描述符 + +`SubagentProvider.inheritsParentContext` 描述的是对话种子,而非作用域、服务、工具或权限。spawn 和 ACP 将其设为 `false`;fork 设为 `true`。`dsh-tool-subagent` 根据该标志派生工具描述和 prompt 参数描述,包括 fork 继承已完成轮次但不继承进行中轮次这一事实。提供方生命周期事件使该措辞与响应式的 provider 注册保持同步;其设计动机见 [provider-lifecycle-events RFC](2026-07-05-subagent-provider-lifecycle-events.md)。 + +## 曾考虑的替代方案 + +- **循环自行组合一行身份文本**——在必须保持精简的那个包里硬编码面向模型的行文("plugins, not loop changes"),且在 section 流水线之外形成第二条组合路径。(身份确实以代码字面量交付——但作为 `dsh-system-prompt` 注册的普通 section,其 `system-prompt/assemble` waterfall 仍是部署方需要移除它时的逃生阀。) +- **通过 `agent/request` waterfall 注入模型名称**——提示词文本在两处组合,且 `agent/pre-step` 的 `fullSystemPrompt` 会遗漏它,导致压缩(compaction)测量的提示词与模型实际看到的不一致。 +- **在每个 persona 中手写模型名称**——与上方一行的 `model:` 键重复,配置修改后默默失实——正是本 RFC 要治的病。 +- **宽松插值(未知引用保留原样或替换为空)**——一个拼写错误 `{{modle}}`(或一个空洞)会被送到模型,直到 transcript(文本记录)审查才有人注意到。 +- **在配置中逐实例手写 subagent 措辞**——面向模型的行文重新回到每个部署 × 每个实例,又是同一个病。**按 provider 名称匹配措辞**——`providerName` 本身是配置,重命名 provider 后会静默拿到错误的措辞。 +- **在 `apply` 时解析 provider(加载顺序要求)** 和 **仅用 section 承载 subagent 措辞(在 assemble 时惰性解析)**——provider 生命周期事件的替代方案;均在 [provider-lifecycle-events RFC](2026-07-05-subagent-provider-lifecycle-events.md) 中被否决。 + +## 不在范围内 + +- 更多变量(`date`、平台、git 状态)——注册表使每个变量成为拥有该事实的插件的一行贡献;本 RFC 不认领任何一个。 +- 为预创建的 stdio agent 提供配置 `cwd`(可让 stdio persona 使用 `{{cwd}}` 并按真实路径分区持久化)——推迟到 session-cwd 方案重新讨论时。 + +## 交付的不变式 + +- coding-agent 提示词通过一条组装路径渲染:identity、带插值模型名的 persona,然后是 fs/bash/web 指导。 +- fork 和 fresh subagent 的描述反映 provider 是否继承已完成的对话轮次;工具随 provider 生命周期变化而出现、消失和重新措辞。 +- 未知、无值、格式错误或不平衡的变量引用会指名 section 并抛出异常;重复的 section、变量和工具注册也会抛出异常。 +- 快照回放与提示词无关:它按轮次和步骤索引已录制的 chunk 流,不比较发出的请求。 + +## 后果 + +- 组装后的提示词中每个事实现在恰好有一个归属方,叶子 YAML 中手写的工具行文已消除:加载或卸载一个工具插件不再需要编辑任何部署的 persona。 +- `{{model}}` 在组装时反映 `AgentOptions.model`。如果一个插件在 `agent/request` waterfall 中切换模型,提示词中的声明在该步骤就会过时;如果一个插件在那里**提供**模型(options.model 未设置——循环文档记载的回退路径),变量在渲染时无值,含 `{{model}}` 的 persona 会在 waterfall 运行前失败。两者的补救方式相同,且正是归属规则本身:拥有该延迟绑定模型事实的插件在 `system-prompt/assemble` waterfall 上提前声明它(`assembly.variables['model'] = …`)——一个归属方,两处声明;一个循环测试端到端固定了 supply 路径。已接受。 +- 当一个已绑定的 provider 不在位(尚未激活、已卸载、HMR(热模块替换)重载中)时,subagent 工具不存在,该窗口内的模型请求只是缺少它。这是诚实的状态——替代方案是一个描述或执行都不可信的已注册工具。 +- 严格性意味着 persona 可能在渲染时导致轮次失败(例如在无 cwd 的会话上使用 `{{cwd}}`)。失败是受控的——该轮次以 `error` 结束,循环存活——而且这是一个我们希望大声暴露的撰写错误。 +- 目前没有在 prompt 行文中转义字面 `{{name}}` 的语法;如果真实 prompt 确实需要,届时再添加。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml new file mode 100644 index 0000000000..7357dfe0f8 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-05-reconstructable-requests.md: 0978cd8760c6a0420be1bf0a3baf6b50c1a04a13 +2026-07-05-reconstructable-requests.zh.md: 82f9cf085db3d6cd408e54a8e7cf99082d848176 diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md index d95a709ada..0978cd8760 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md @@ -1,5 +1,7 @@ # RFC: Every LLM request is reconstructable from the session log +English | [中文](2026-07-05-reconstructable-requests.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md new file mode 100644 index 0000000000..82f9cf085d --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md @@ -0,0 +1,55 @@ +# RFC:每个 LLM 请求都可从会话日志重建 + +Status: implemented + +[English](2026-07-05-reconstructable-requests.md) | 中文 + +## 问题 + +请求流水线此前不保证前缀稳定性以利用提供方缓存,会话日志也无法重建模型实际看到的内容。日志遗漏了 model、系统提示词和工具 schema,同时允许逐次调用的请求改写。因此缓存行为和回放等价性取决于碰巧加载了哪些插件。 + +快乐路径的参考形态是 MiniCode 的 `LLMClient`:一个有状态的对话客户端,随对话推进只追加、从不重建,仅在系统提示词、工具集或压缩(compaction)真正改变了模型必须看到的内容时才重置。本 RFC 回答的设计问题是:如何在不放弃事件溯源的前提下获得这种纪律。 + +## 决策 + +### 原则 + +**模型可见 ⟺ 已记录。** 凡到达模型请求的内容,都必须记录在会话日志中。可检查的推论:**循环发出的每个对话请求都是会话日志的纯函数**——任何持有日志的人都能逐字节重建它。精确的范围说明:保证覆盖循环构建的 `GenerateOptions`;提供方协议格式(wire format)字节由它推导而来,因为两个适配器的序列化在固定代码版本下都是逐消息的纯函数;直接的一次性调用(压缩的 summarize 调用)记录其信封标量(`compact/summary.{model, maxTokens}`),其输入是对已记录区域的确定性代码运算——可从日志加代码重建,通过 unfrozen-request 标记排除在不变式之外。 + +前缀缓存稳定性是推论 #1,而非标题:一个仅追加的日志经逐节点纯函数投影,在 header 不变时自然产出前一请求的追加扩展——稳定性是涌现的,不是管理出来的。逐字节精确的审计/回放是推论 #2;带*可归因*漂移的恢复与 fork 是推论 #3。 + +### 机制 + +**消息。** `Session.deriveMessages()` 带缓存:每个 surface 节点在首次出现时通过公开的逐节点函数 `deriveEventMessage(event)` 精确投影一次;surface 改写(压缩的 `replace`——`SurfaceManager.replaceGeneration`)触发重建。调用方每次获得一个新数组,其中的消息是共享的、深度冻结的:通过投影修改已记录的历史是不可表达的(会抛异常),取代了旧的每次调用克隆隔离。外部重建器对日志前缀折叠同一个公开函数,因此不可能有两条路径产生分歧。 + +`EpochHeader` 记录请求的非历史状态:调用配置、渲染后的系统提示词、工具 schema 和会话前缀,空值规范化为缺失。`request/header` 写入完整的初始、恢复或回退快照。`request/header-delta` 通过公共前缀/后缀行裁剪编码系统提示词变更,通过按名称键控的增/删/改编码工具变更,通过完整替换编码配置或前缀变更。`foldRequestHeader`、`diffHeader` 和 `applyHeaderDelta` 是纯编解码器。每个循环实例在其首次请求时写入一个快照,以锚定进程边界。Delta 仅是优化:写入方验证往返等价性,对不可表达的变更(如纯工具重排序)回退到完整快照。 + +每一步重建 prompt 组装。实例的第一步中,`agent/session-prefix` 用仅限请求的开场消息扩展一个冻结的空种子;结果被冻结并缓存于该循环实例。`agent/pre-step` 随后在消息快照紧接 `step/start` 之前接收组合后的前缀。首次调用配置从显式的 `AgentOptions` 出发,保留 fork 覆盖和恢复重配置;后续调用从折叠后的 header 出发。`agent/request` 只能替换那个冻结的配置种子,而模型可见的内容通过已记录的通道进入。循环记录欠写的 header 事件(前缀唯一的持久化归属),从前缀、快照和 header 构建 `GenerateOptions`,并深度冻结它,同时保持 `AbortSignal` 活跃。每实例状态仅有缓存的前缀和其锚定快照是否已写入。 + +**`step/start` 是重建边界。** 一步从该序列之前的事件派生消息。快照之后的注入加入下一次请求,事件发布期间的重入追加被拒绝。`agent/pre-step` 是当前请求所需内容的 seam。Header 重建折叠该步骤自身的 `request/header*` 事件,或在无新 header 写入时沿用前一次折叠结果。 + +**强制执行。** 在开发环境中,`dsh-invariants` 通过一个全新的 `Session` 独立重建每个循环请求,使活跃缓存无法为自身背书,然后在 `llm/stream` 处比较消息和折叠后的 header 字段。循环请求通过其冻结形态和 session id 识别;直接的一次性调用被排除。正确性依赖于序列有界的重建而非监听器顺序。带密钥的 e2e 要求首次请求之后出现正数的 cache-read token;逐步 usage 是生产信号,header 变更或压缩表现为下一步 cache-read 的下降。 + +### MiniCode 形态:采纳,但溯源箭头反转 + +与 MiniCode 一样,对话仅追加推进,仅在模型可见状态变更时重置。与 MiniCode 不同的是,事件日志仍是真源,因为它还拥有持久化、恢复、边界、工具配对和溯源。`Session` 缓存从日志派生的消息和 header 折叠结果,使每个请求都可独立检查。 + +## 曾考虑的替代方案 + +- **客户端作为真源**(照搬 MiniCode):在日志之外出现第二个生效的真相——两者漂移而无人察觉;见上节。 +- **镜像日志的有状态传输客户端**:重复对话状态,需要围绕监听器做回滚,留下未记录的编辑面,且仍无法重建请求 header。Session 拥有的缓存加已记录的 header 避免了这些分裂的真相。 +- **逐次调用的请求标量**(每次 `agent/request` 分发时传入一个可自由修改的配置):监听器可以零记账地逐次切换 model,悄然放弃本设计旨在保护的提供方缓存。配置是逐对话的已记录状态;waterfall(瀑布式事件)提议,日志记录。 +- **检测并报告**(比较连续请求,发现分歧时警告):事后捕获违规;违规请求仍可构造并发出。因接口层面的不可表达性而否决。 +- **事件驱动组装**(仅在变更信号时重新渲染):存在信号遗漏的 bug 类别——会话中途注册的工具发出 `tools/change` 而非 `system-prompt/change`,第三方提供方可能什么都不发。逐步渲染加值比较在零信号纪律下仍然健壮。 +- **Header 事件上的叙事字段**(delta 上的 `reason`/`changed` 列表):可通过 diff 连续事件派生——每个事实只有一个归属;快照携带 reason 是因为锚点的成因无法从数据本身派生。 + +## 后果 + +- 一个无法由日志解释的请求不可能被意外构造——无论是循环还是监听器;修改已构建的请求会抛异常;每次 header 变更都是一个持久的、可 diff 的日志事件。 +- 在建议通道之间做选择是变更频率决策,而本设计让稳定的那个成为结构性的:`agent/session-prefix` 的贡献在每个循环实例中只组合一次并逐字复用,因此它以零边际成本扩展可缓存前缀,且**不可能**在会话中途击穿提供方缓存;会话中途变化的内容通过仅追加的历史通道流入——`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——每个都是持久的 `context/message`,付出一次代价后即享受前缀缓存,代价是在历史和日志中累积。将会话冻结的开场内容路由到前缀,将变更通知路由到历史通道;逐步的仅限请求尾部槽位被有意放弃(无消费方,且持久追加覆盖了所有当前更新模式)。 +- 在提供方处仍需全价的内容是固有的且已记录的:压缩(其 `compact/*` 事件和 replace 节点)、真正的 prompt/工具变更(`request/header-delta`)、配置切换(同上)、带漂移的进程边界(`'resume'` 快照与前一个不同)。提供方自身的 reasoning-content 排除由服务端管理。 +- `step/start` 监听器行为变更(见上文)是对插件唯一可观察的语义变更;`agent/pre-step` 是当前请求的 seam。 +- 工具结果裁剪(计划中)无需新机制:一个已记录的单节点 surface replace(`start === end`),携带同一 `callId` 下裁剪后的 `tool/result`——属于压缩家族,回放正确,缓存击穿由相同的压力逻辑批量处理。 +- 会话日志每个对话增长一个 `request/header` 快照(系统提示词 + 工具 schema:主导项),加上真正变更时的 delta——相对于 `assistant/chunk` 的体量很小;`SESSION_FORMAT_VERSION` 保持 `0`(预发布期间的变动被吸收,后端拒绝而非迁移)。 +- 快照 golden 文件变更一次(每份 transcript 增加其 header 事件);写文件系统的 fixture 以规范化的撰写形式存储,工具参数使用 cwd 相对路径,因为回放只往返 cwd 无关的参数路径。 +- FIXME(call-config-shape):重新审视 `LlmCallConfig` 的确切字段集——哪些字段对缓存而言真正属于 epoch 级别(`model` 毫无疑问;采样标量出于谨慎放在那里),以及当适配器需要时,提供方特有的额外项(reasoning 选项、额外 body 参数)应归属何处。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml new file mode 100644 index 0000000000..1bf06ce567 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-05-subagent-provider-lifecycle-events.md: 6d711f2a6d8496a8a229ec63d86dd89816efb6f8 +2026-07-05-subagent-provider-lifecycle-events.zh.md: 45eedcfdfa834722000c9f2c15e3955ced791c2f diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md index 30674f8c8b..6d711f2a6d 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md @@ -1,5 +1,7 @@ # RFC: Subagent provider-lifecycle events — `subagent/provider-added` / `subagent/provider-removed` +English | [中文](2026-07-05-subagent-provider-lifecycle-events.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md new file mode 100644 index 0000000000..45eedcfdfa --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md @@ -0,0 +1,36 @@ +# RFC:Subagent 提供方生命周期事件——`subagent/provider-added` / `subagent/provider-removed` + +Status: implemented + +[English](2026-07-05-subagent-provider-lifecycle-events.md) | 中文 + +## 问题 + +[prompt-variables RFC](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) 使 `dsh-tool-subagent` 从其提供方**派生**面向模型的措辞:`SubagentProvider.inheritsParentContext`(spawn/ACP 为 `false`,fork 为 `true`)同时驱动工具描述和 `prompt` 参数描述(`providerWording`),从而让 fork 工具不再在上下文继承问题上对模型撒谎。这一修复引入了跨 fiber 的数据依赖:工具描述在**工具注册时**就已固定(这是有意为之——描述是 tool-choice 引导所在之处),但提供方在自己的插件 fiber 上到达,时机不确定。 + +如果在工具插件的 `apply` 时刻解析提供方,就会产生隐式的加载顺序要求("在 cordis.yml 中把后端列在工具前面")。这一要求行不通,因为 Cordis Loader 并发启动同级条目,且 `Entry.init()` 不等待激活完成:一个延迟到达的后端可能导致工具 fiber 失败,即使它在配置中列在前面也是如此。Loader 不提供同级顺序保证——"异步状态不是同步状态"(见[防御性模式](../../../defensive-patterns.md))。 + +## 决策 + +注册表将提供方的成员变动作为类型化事件广播,消费方镜像这些事件而非假设顺序: + +- **`subagent/provider-added(provider)`**:一个提供方在 `ctx.subagents` 注册表中变为可解析。在注册时发出。 +- **`subagent/provider-removed(name)`**:一个提供方离开了注册表(其插件 fiber 被 dispose——卸载或 HMR 重载)。从注册的 disposer 中发出。 + +`dsh-tool-subagent` 镜像其命名提供方的生命周期:当提供方可用(或变为可用)时注册工具——在那一刻从该提供方派生措辞;当提供方离开时注销工具;在重新注册时(HMR 重载)重新派生。提供方不在时工具不存在,因此不可能对模型撒谎。这里**刻意不留**任何需要文档化的加载顺序要求:事件使顺序问题消失,而非将其钉死。 + +这些事件还补全了该 seam 的词汇:`ctx.subagents` 是一个命名注册表,多个委派后端(`spawn`、`fork`、`acp`)在其上共存;一个内容会被其他插件用来派生状态的注册表,应当以类型化事件广播成员变动,而非要求轮询或依赖加载顺序。 + +## 曾考虑的替代方案 + +- **在 `apply` 时解析提供方,不存在则抛异常**:否决。"先列后端"会声称一个 Loader 并不提供的顺序保证。 +- **重试查找(轮询直到提供方出现)**:最终会收敛,但在框架已有的机制(effect 注册 + disposal)之外自行发明了一套私有就绪协议;而且它无法感知提供方**离开**,因此 HMR 会让一个措辞描述着已 dispose 后端的工具滞留。 +- **仅在 section 中放置 subagent 措辞,在组装时延迟解析**:同样能容忍任意加载顺序,但把 tool-choice 引导移出了描述,与 prompt-variables RFC 确立的归属规则相矛盾(每个工具的语义和使用时机属于描述)。响应式注册既保持描述的权威性,又不依赖顺序。 +- **根据提供方名称而非提供方对象来确定措辞**:`providerName` 本身是配置,重命名提供方后会静默获得错误的措辞;从已解析提供方自身的 `inheritsParentContext` 派生则不会漂移。 + +## 后果 + +- 从命名提供方派生状态的消费方响应 `subagent/provider-added`/`-removed` 事件,而非在 `apply` 时读取注册表;`dsh-tool-subagent` 是参考实现。 +- **添加时大声失败;移除时按监听器隔离。** 添加监听器可以回滚注册。移除在 disposal 期间运行,因此单个监听器抛异常只会被记录,不会饿死后续镜像或扰乱拆卸流程。`start()` 仍然在每次运行时按名称解析提供方,防止陈旧工具调用已移除的后端。见[事件目录](../../../cordis-catalog/events.md)和[生产者/消费者映射](../../../event-producer-consumer.md)。 +- **工具不存在的窗口期。** 在后端 disposal 与重新注册之间(HMR 重载),模型看不到 subagent 工具。这是诚实的状态——替代方案是一个向空处派发的工具——工具注册表的 `tools/change` 事件确保 prompt 组装保持最新。 +- **两个等待中的 fiber 共享同一 `toolName` 是无效配置,且被延迟捕获。** 如果两个 `dsh-tool-subagent` 实例命名了不同的提供方但相同的 `toolName`,二者都会等待,先到达的提供方触发注册;第二个注册仅在**其**提供方到达时才抛异常。插件中的 `TODO(subagent-dup-toolname)` 记录了这一爆炸半径;工具注册表的重名拒绝机制仍是最终兜底。 diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml new file mode 100644 index 0000000000..cc697c3e30 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-06-timeout-deadline-library.md: 9906aa7cce40ffd7b5f7082199d05edb8d0a54b2 +2026-07-06-timeout-deadline-library.zh.md: ef99a1a051f3cedbe5a2770e5bbeeebe716745c4 diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md index 7aa987c60f..9906aa7cce 100644 --- a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md @@ -1,5 +1,7 @@ # RFC: A shared timeout/deadline primitive, with hard-kill left to each capability +English | [中文](2026-07-06-timeout-deadline-library.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md new file mode 100644 index 0000000000..ef99a1a051 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md @@ -0,0 +1,98 @@ +# RFC:共享的超时/截止时间原语,hard-kill 留给各能力自行实现 + +[English](2026-07-06-timeout-deadline-library.md) | 中文 + +Status: implemented + +## 问题 + +超时处理在各个承载工具的能力之间逐渐分化,而这种分化并非表面的——同一套逻辑被三种方式各自重新实现,每种都带着自己微妙的正确性负担。 + +- **bash**([packages/bash/bash-local/src/run.ts](../../../../packages/bash/bash-local/src/run.ts))在进程管道内部有一套完整、正确的超时实现:一个经配置钳位的 `timeoutMs`,两个独立触发器——用于超时的 `killTimer` 和用于上游取消的 `onAbort` 监听器——各自调用同一个 `kill()` 闭包,该闭包对进程组执行 SIGTERM→宽限期→SIGKILL 升级,以及两个正交的结果布尔值(`timedOut`、`aborted`)各自独立锁存。 +- **web_fetch**([packages/web/web-fetch-local/src/provider.ts](../../../../packages/web/web-fetch-local/src/provider.ts))有一套正确但*手工搭建*的超时:它构造一个 `AbortController`,接入 `setTimeout(() => controller.abort(new WebError(…, 'WEB_FETCH_TIMEOUT')))`,手动添加和移除上游信号监听器,在 `finally` 中清除定时器,并在 `translateAbortOrNetwork` 辅助函数中从 `signal.reason` 恢复超时原因——因为 reader 只抛出裸 `AbortError`。 +- **web_search**([packages/web/tool-web/src/search.ts](../../../../packages/web/tool-web/src/search.ts))**完全没有超时**:`WebSearchRequest`([packages/web/web/src/types.ts](../../../../packages/web/web/src/types.ts))不携带 `timeoutMs` 字段,各提供方的 `search()` 只转发 `exec.signal`。(web_search 在本 RFC 中保持无超时——见「后果」。) + +每个新的外部进程或网络工具都要重新推导同样四件事:钳位请求值、启动定时器、将超时与上游取消融合、在出口处区分「超时」与「被取消」——而融合和原因恢复恰恰是最容易出微妙错误的部分(web_fetch 的 `signal.reason` 舞步就是证据)。与此同时,各能力执行的*终止*动作不可归约地不同:bash 杀的是 OS 进程组(工作运行在子进程中,在本运行时之外,只能通过信号触达),而 web 中止的是进程内的 `fetch`(undici 拆掉 socket)。不存在一种单一机制能停止所有这些工作。 + +## 决策 + +`@deepseek-ai/dsh-timeout` 位于 `packages/util/`(与 `dsh-brand` 同级),拥有超时的*计时与分类*这一半;*终止*那一半——hard kill——留在各能力的实现中。它是一个纯函数库,**不是** Cordis 服务或插件:不接收 `ctx`、不注册任何东西、不持有跨调用状态、不发射事件。刻意不设中央「超时服务」——那样的服务必须知道如何停止每个能力的工作,而这正是微内核要排除在共享层之外的知识,也是 Codex 的 `ExecExpiration` 作用域仅限于 exec 家族所示范的。 + +### 库的对外接口 + +三个函数加一个 reason 类型: + +```ts ignore-check +/** The internal reason attached to a timeout abort, so consumers can classify it after the fact. */ +export class TimeoutReason extends Error { + override name = 'TimeoutReason' + + constructor(readonly code: string, readonly timeoutMs: number) { + super(`${code} after ${timeoutMs}ms`) + } +} + +/** Validate/fill a caller's optional positive hint from the backend's default, then cap at its max. */ +export function clampTimeout( + requested: number | undefined, + def: number, + max: number, + name = 'timeoutMs', +): number + +/** + * Build a deadline signal that aborts on upstream cancellation OR on timeout, + * with the timeout carrying a `TimeoutReason`. `timeoutMs <= 0` means "no + * timeout" (background tasks): forward only the upstream signal, arm no timer. + * The returned object's `[Symbol.dispose]` clears the timer — `using` for a + * scope-lifetime consumer, a manual call for an event-lifetime one. + */ +export function deadline( + upstream: AbortSignal | undefined, + timeoutMs: number, + code: string, +): { signal: AbortSignal; [Symbol.dispose](): void } + +/** Recover the TimeoutReason from an aborted signal (or error); `code` scopes the match to this deadline's timer. */ +export function timeoutOf(x: AbortSignal | { reason?: unknown }, code?: string): TimeoutReason | undefined +``` + +`deadline` 通过 `AbortSignal.any` 将上游信号与定时器融合,附加一个类型化的 `TimeoutReason`,并暴露可 dispose(资源释放)的定时器清理。非正数超时是内部的无超时哨兵,用于后端自有的后台任务;外部提示经 `clampTimeout` 后必须为正有限值。既无定时器也无上游信号时,函数返回一个永不中止的信号,但具有相同的 disposal 形状。提供方将超时原因翻译为 seam 特定的结果。`timeoutOf(signal, code)` 通过 code 限定分类范围,使外层嵌套的 deadline 被视为上游取消而非内层能力的超时。 + +### 分工 + +| 关注点 | 负责方 | +|---|---| +| 校验请求提示并钳位 default/max | `dsh-timeout`(`clampTimeout`)——纯算术加共享的正有限请求契约 | +| 启动定时器、到期中止、携带 reason、与上游取消融合 | `dsh-timeout`(`deadline`) | +| 清除定时器 | `dsh-timeout`(`[Symbol.dispose]`) | +| 中止后分类首个 abort reason | `dsh-timeout`(`timeoutOf`) | +| **实际终止工作** | 各能力的实现 | +| default/max *值* | 各能力的配置 | +| 超时 `code` 字符串 | 各能力(`WEB_FETCH_TIMEOUT` ≠ `BASH_TIMEOUT`) | + +信号只*通知*;终止始终是监听者的职责,而监听者因能力而异。bash 自己写 `addEventListener('abort', kill)`,因为 OS 进程活在本运行时之外,没有别的东西会杀它;web 把 `d.signal` 交给 `fetch`,undici 拆掉 socket。这也是文件 read/write/edit 不接受 **`timeoutMs`** 的原因:本地系统调用至多只能尽力中止,超时无法强制 `fsync`/`rename` 停下,加一个超时等于引入一个违反「显式优于隐式」的隐式默认值。两个参考 agent 出于同样的理由都不给文件 I/O 设超时。 + +### 各能力如何消费 + +- **web_fetch**——工具层保持校验并转发;提供方手工搭建的 controller + `setTimeout` + 手动监听器 + `finally` + `signal.reason` 恢复被提供方自有的 `deadline`/`timeoutOf` 取代。上游信号已预先中止时仍立即抛出 `WEB_ABORTED`;否则 `fetch` 使用融合后的 `d.signal` 运行,`translateAbortOrNetwork` 根据信号分类抛出的错误(`timeoutOf` → `WEB_FETCH_TIMEOUT`,否则已中止 → `WEB_ABORTED`,否则网络 → `WEB_PROVIDER_ERROR`)。公开的错误码契约不变,`TimeoutReason` 永远不会作为公开错误跨越 web seam。 +- **bash**——`resolve()` 将请求钳位为显式规格。前台 `run()` 创建 deadline 并将其信号传给进程执行,后者既有的 abort 监听器执行进程组 kill。执行器将首个 abort 分类为超时或取消。后台启动保持无超时,仅转发上游取消。 + +## 后果 + +- `runBash` 的结果不再独立锁存 `timedOut` 和 `aborted`;超时与用户中止在进程关闭前竞争时,现在报告单一的首个 abort 原因,而非两者同时为 true。统一的 SIGTERM→宽限期→SIGKILL 终止路径不变,seam 类型 `BashRunResult` 保留两个布尔值(现在互斥),因此 `dsh-tool-bash` 的结果渲染不受影响。 +- `SpawnSpec.timeoutMs` 与 `SpawnOutcome.timedOut`/`aborted` 被移除,而非作为始终为零/始终为 false 的残留保留:`runBash` 不再拥有定时器、执行器拥有分类逻辑后,它们无处被读取。这是与字面提案形状(向 `runBash` 传 `timeoutMs: 0`)的唯一偏差;在逐文件覆盖率门禁下,一个始终为 0 且无人读取的字段是死代码。 +- web_fetch 去掉了自建的 controller/timer/listener/reason-recovery;分类器现在基于 deadline 信号(`timeoutOf` + `aborted`)而非抛出错误的形状来判断,这在请求阶段的 reject-with-reason 和读取阶段的裸 `AbortError` 两种情况下都是健壮的。 +- `AbortSignal.any` 与 `using`/`Symbol.dispose` 在此首次进入本仓库(Node ≥ 24 基线,已满足)。 + +不在本 RFC 范围内,列出以标明边界:`web_search` 可以在其 tool-schema/快照覆盖率规划完成后获得可选的面向模型的 `timeout_ms`;未来基于 ripgrep 的文件系统发现工具可以在存在后消费同样的提供方自有 deadline 形状;`tools/execute` waterfall(瀑布式事件)中间件可以通过驱动 `exec.signal` 为每次工具调用设置默认 deadline——那将是一个*消费*本库的插件,仍然只做通知,hard kill 仍是各能力自己的事。 + +## 曾考虑的替代方案 + +**统一的超时*插件* / `ctx.timeout` 服务。** 基于微内核理由否决。一个能停止任何工具工作的服务必须理解每个能力的终止机制(进程组 SIGKILL、socket 拆除、系统调用边界检查)——这正是架构所禁止的「内核知道太多」。Codex 的 `ExecExpiration` 作用域仅限于 exec 家族,正是因为它驱动的 kill(`killpg`)是进程家族特有的;MCP 和 model-stream 各自保有自己的。不存在一个连贯的中间层能为所有东西拥有终止权,因此共享部分只能是纯计时/分类那一半——一个库,而非服务。 + +**每个工具各自实现超时,不共享代码(之前的现状,也是 Claude Code 的选择)。** 否决,因为它已经在产生分化和重复的正确性负担:web_fetch 手工搭建的 controller/reason 逻辑正是未来每个网络/进程工具都要重新推导的,而融合 + `signal.reason` 恢复是容易出错的部分。Claude Code 容忍完全重复;本仓库有一条统一的共享中止通道(每次 `execute` 上的 `exec.signal`),使一个小型共享原语严格更干净,因此成本/收益不同。 + +**用 `withTimeout(promise, ms)` 包装器代替信号工厂。** 否决,因为让 promise 与定时器竞争只是在 deadline 时 resolve *工具调用*的 promise,而不停止底层工作——子进程或 fetch socket 会泄漏。发出信号并要求能力去监听,才能强制一条真正的终止路径存在。这与「dispose 必须达到静止态,而非仅仅请求它」的防御性规则一致。 + +**保留 bash 独立的超时和取消触发器。** 否决,因为一个 deadline 信号移除了自建定时器并标准化了分类。竞争的原因报告先到达的那个 abort,而既有的 SIGTERM→SIGKILL 终止路径不变。 diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml new file mode 100644 index 0000000000..36a4652f26 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-07-tool-call-timeout-policy.md: 0e69c8504dd34dfc4427bf1f3865a80be93eff9d +2026-07-07-tool-call-timeout-policy.zh.md: d842d0a3c811e7502f4d45baba49010a06c5f1a5 diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md index 7bd4e2462d..0e69c8504d 100644 --- a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md @@ -1,5 +1,7 @@ # RFC: Tool-call timeout policy as a plugin +English | [中文](2026-07-07-tool-call-timeout-policy.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md new file mode 100644 index 0000000000..d842d0a3c8 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md @@ -0,0 +1,111 @@ +# RFC:工具调用超时策略作为插件 + +Status: implemented + +[English](2026-07-07-tool-call-timeout-policy.md) | 中文 + +## 问题 + +[超时/截止时间 RFC](2026-07-06-timeout-deadline-library.md) 将计时与分类原语提取到了 `@deepseek-ai/dsh-timeout`,但超时策略仍然附着在各个能力和面向模型的 schema 上。`bash` 暴露了 `timeoutMs`;`web_fetch` 暴露了 `timeout_ms`;`web_search` 没有面向模型的超时参数,尽管提供方已经遵守 `exec.signal`;未来的 grep/glob 工具要么直接导入超时库,要么自行发明超时策略。对于一个插件 SDK 来说,这是错误的编写形态:工具作者通常只需将 `exec.signal` 转发给所调用的实现,而部署策略来决定预算。 + +与此同时,仓库中并非所有超时都是面向模型的工具调用预算。钩子通过直接调用 `ctx.bash` 来执行命令钩子,而非通过 `ctx.tools.execute()`;`bash` 模型工具通过同一后端复用了前台执行、后台启动、后台轮询和钩子调用。一步到位地把所有超时都移入工具插件会混淆这些路径,并有破坏钩子超时语义的风险。 + +## 决策 + +工具调用超时是一项仅适用于面向模型的工具执行的策略,由三部分组成: + +- `@deepseek-ai/dsh-timeout` 仍然是拥有 `deadline()` 和 `timeoutOf()` 的共享库。 +- `@deepseek-ai/dsh-tools` 在 `tools/pre-execute` 和 `tools/post-execute` 之间有一个环绕分发的 waterfall(瀑布式事件)`tools/execute`。 +- `@deepseek-ai/dsh-timeout-policy` 从注册表读取每个工具声明的 `timeoutMs`,并通过派生新的 `exec.signal` 来包装有此声明的调用。 + +执行流水线为: + +```text +ctx.tools.execute(exec) + -> tools/pre-execute + -> tools/execute + -> registry dispatch (the base next()) + -> tool.execute(args, exec) + -> thrown tool errors normalize to ToolExecutionResult + -> tools/post-execute +``` + +默认行为是保守的:未声明 `timeoutMs` 的工具不会从该插件收到 `TOOL_TIMEOUT` 截止时间。 + +### `tools/execute` 环绕 seam + +`@deepseek-ai/dsh-tools` 声明了一个 `tools/execute` waterfall,其基础 `next()` 是「分发并规范化」的 thunk:即同一个内部 `try`/`catch`,它将抛出的工具错误(或未知工具错误)转换为 `isError` 的 `ToolExecutionResult`。监听器接收 `(exec, next)`:调用 `next()` 委托给分发(返回其结果,可选地包装),或返回替代结果以短路分发。整条流水线仍处于 `execute` 的外层 try/catch 之内,因此抛出异常的监听器会变成 `isError` 结果,永远不会导致轮次失败。 + +catch 是基础 `next()` 而非 waterfall 之外的东西,这一点是关键:当提供方看到超时信号并抛出自己的上游中止错误时,注册表分发首先将其转换为正常的错误结果,然后 `timeout-policy` 才能将最终结果替换为 `TOOL_TIMEOUT`。 + +### `timeout-policy` 插件 + +该插件是 `@deepseek-ai/dsh-timeout-policy`,位于 `packages/timeout/` 分组中,是一个零配置的函数/命名空间插件(`name` / `inject` / `apply`)。每个工具的预算声明在工具自身上,而非此插件上:`ToolDefinition` 携带可选的 `timeoutMs`,由拥有该工具的插件从自身配置中设置。例如 `dsh-tool-web` 将 `fetchTimeoutMs` / `searchTimeoutMs`(默认 30000)解析到 `web_fetch` / `web_search` 的定义上: + +```yaml +- id: timeout-policy + name: '@deepseek-ai/dsh-timeout-policy' +- id: tool-web + name: '@deepseek-ai/dsh-tool-web' + config: + fetchTimeoutMs: 30000 + searchTimeoutMs: 30000 +``` + +超时声明在工具定义上而非自由文本的名称映射中,消除了拼错名称导致策略不生效的问题。`defineTool` 会校验预算为正有限数。分发期间,执行器派生截止时间信号,之后恢复调用方信号,并将自身的超时转换为 `TOOL_TIMEOUT`;没有预算的工具原样通过。 + +信号替换采用**就地修改 `exec.signal`** 的方式,而非向 `next()` 传递新对象。Cordis 的 waterfall `next()` 忽略传入的参数,使用共享的 payload 数组重新调用下游监听器(`vendor/cordis/src/events.ts`),因此 Cordis 的文档惯用法——修改共享对象再委托——是唯一能到达分发的机制。插件在 `finally` 中将 `exec.signal` 恢复为调用方的原始信号,使 `tools/post-execute` 永远不会看到此插件的(可能已中止的)截止时间信号。 + +`timeout-policy` 拥有 `TOOL_TIMEOUT` 代码的两种用途:传递给 `deadline()`/`timeoutOf()` 的内部截止时间代码(作用域化,使嵌套的外层截止时间读取为普通取消),以及结构化工具结果的错误代码。其替换结果为: + +```ts ignore-check +function toolTimeoutResult(timeoutMs: number): ToolExecutionResult { + return { + content: [{ type: 'text', text: `Error: tool call timed out after ${timeoutMs}ms` }], + isError: true, + error: { name: 'ToolTimeoutError', code: 'TOOL_TIMEOUT' }, + } +} +``` + +这是一个协作式截止时间。它不会通过与工具 promise 竞速来杀死任意工作;工具或其调用的能力必须遵守 `exec.signal` 并达到静止状态。因此声明 `timeoutMs` 的含义是「此工具对 `exec.signal` 是协作式的」,插件 README 将此作为契约声明。 + +可重建性不需要新的会话事件:`TOOL_TIMEOUT` 就是该调用最终面向模型的 `tool/result`,因此现有会话日志已经记录了下一次模型请求所看到的内容和结构化 `{ name, code }` 错误。 + +### 现有工具适配 + +`web_fetch` 和 `web_search` 已迁移。`dsh-tool-web` 保留对其面向模型 schema 的所有权,这些 schema 不暴露超时旋钮:`web_fetch` 移除了 `timeout_ms` 参数以匹配参考 agent 的形态,`web_search` 保持仅查询。工具体不导入 `@deepseek-ai/dsh-timeout`;它们将 `exec.signal` 转发给 `ctx.web`。 + +`dsh-web-fetch-local` 保留一个配置的提供方级 `timeoutMs`,作为直接调用 `ctx.web.fetch()` 的调用方和配置错误部署的大资源兜底;它不拥有面向模型的超时。当 `TOOL_TIMEOUT` 信号先到达 fetch 提供方时,提供方作用域的分类将其视为上游 `WEB_ABORTED`,外层 `tools/execute` 包装器将最终工具结果替换为 `TOOL_TIMEOUT`。已发布的 web 工具部署将提供方兜底配置为高于 `timeout-policy` 预算,使工具调用策略在模型调用中通常获胜。 + +`bash` 保持当前的后端超时路径。`dsh-tool-bash` 继续暴露 `timeoutMs` 和 `run_in_background`;`dsh-bash-local` 继续使用 `@deepseek-ai/dsh-timeout` 处理 `BASH_TIMEOUT`;钩子桥接继续调用 `runHook()` 并通过 `ctx.bash` 传递 `timeoutMs`。这保持了前台/后台/钩子行为的稳定。 + +`read`、`write`、`edit`、`todo_write`、`bash_output` 和 `bash_kill` 不加入工具调用超时:它们是本地文件系统或短暂的注册表/会话操作,截止时间对它们要么只能尽力而为,要么没有必要。 + +未来面向模型的 grep/glob 工具可以基于 `ctx.bash` 实现,无需导入 `@deepseek-ai/dsh-timeout`:它将 `exec.signal` 转发给 `ctx.bash`,并声明自己的 `timeoutMs`(来自其插件配置)供执行器应用。如果 bash-local 的后端超时对此类工具造成问题,bash seam 可以后续添加调用方拥有截止时间的模式;那不在本次范围内。 + +## 曾考虑的替代方案 + +**将插件命名为 `tool-timeout`。** 字面的 RFC 名称匹配了 `gen-tool-catalog` 完整性守卫的 `packages/*/tool-*` glob,该守卫要求每个匹配项注册一个面向模型的工具。此插件不注册任何工具——它是 `tools/execute` 的包装器——因此 `tool-*` 名称要么导致 `verify-tool-catalog` 失败,要么强制一个误导性的启动条目。包名为 `@deepseek-ai/dsh-timeout-policy`,位于新的 `packages/timeout/` 分组;cordis.yml 的 `id` 仍可为 `timeout-policy`。 + +**仅保留逐工具的超时处理。** 这是 `bash` 和 `web_fetch` 的原有形态,也与 Claude Code 和 Codex 对 shell 命令的做法一致。对 web 类工具而言它不够好,因为每个新的支持超时的工具都必须自行选择校验、上限语义、文档、快照和分类。插件集中了策略和分类,同时让每个工具的 schema 专注于业务输入。 + +**立即将所有超时策略移出 bash-local。** 长期更干净:bash-local 将变为纯子进程执行器,所有调用方拥有自己的截止时间。作为第一步它不合适,因为钩子直接调用 `ctx.bash`,而 bash 模型工具有前台/后台语义,这与工具调用的生命周期不同。保留 `BASH_TIMEOUT` 维持了这些路径的稳定,同时工具调用超时在更简单的工具上验证自身。 + +**为所有工具使用全局默认预算。** 方便,但会让工具作者意外:任何偶然运行超过全局预算的工具在插件加载后就会开始失败。逐工具声明的预算使采纳成为有意识的行为。 + +**暴露面向模型的 `timeout_ms` 覆盖参数。** Claude Code 的 `WebFetch`/`WebSearch` 和 Codex 的 web 工具将超时排除在模型调用形态之外。模型覆盖会使超时成为提示词语义的一部分,并迫使 `timeout-policy` 引入 schema/参数剥离规则。Web 超时仅作为部署策略。 + +**让 `timeout-policy` 自行匹配工具参数。** 类似「当 `bash.run_in_background` 为 true 时禁用超时」的规则引擎会使策略插件了解工具特定的参数语义。通过不将 bash 迁移到工具调用超时来避免此问题。 + +**使用 `tools/pre-execute` 加 `tools/post-execute` 代替新的环绕 seam。** pre 监听器可以启动截止时间并修改 `exec.signal`;post 监听器可以分类并替换。这不可行,因为截止时间的生命周期将跨越两个独立的 waterfall:需要 call-id 映射、在每个 pre-deny/tool-throw/post-throw/dispose 路径上清理,以及与其他监听器的排序规则。`tools/pre-execute` 也是允许/拒绝门禁,而非执行包装器。`tools/execute` 给超时一个词法作用域:启动、委托、分类、释放。 + +**使用 `Promise.race` 为非协作式工具强制超时。** 否决,原因与超时库 RFC 相同:它在底层进程、fetch 或提供方操作可能仍在运行时就将控制权返回给调用方。插件只发送信号;终止仍是实现方的责任。 + +## 后果 + +- `@deepseek-ai/dsh-tools` 在有意拆分 pre/post 工具钩子的拦截 seam 之后,获得了一个环绕分发的表面。其契约是窄的:包装注册表分发,而非替代 pre 门禁或 post 结果策略;基础 `next()` 是「分发并规范化」,因此包装器永远不会看到原始的工具抛出。 +- 多个 `tools/execute` 监听器通过普通的 Cordis waterfall 顺序组合:调用 `next()` 的监听器包装下游监听器加分发;不调用 `next()` 直接返回的监听器短路它们。组合超时与未来的重试/沙箱/指标包装器的部署通过注册顺序选择语义(「超时覆盖整个重试」vs「超时覆盖每次尝试」)。 +- 按声明加入是一个有意的配置错误风险:工具可以声明 `timeoutMs` 但不遵守 `exec.signal`,这样的工具在超时时不会停止。插件契约声明:声明预算意味着协作式;web 工具在已经转发信号的工具上证明了这一模式。 +- 过渡期间 `bash` 和已迁移的 web 工具有意使用不同的超时路径:`TOOL_TIMEOUT` 是面向模型的工具调用预算,而 `BASH_TIMEOUT` 仍然是 bash 和钩子使用的 bash 后端超时。 +- 与字面提案的偏差,按已实现 RFC 规则记录:插件包名为 `@deepseek-ai/dsh-timeout-policy`(而非 `tool-timeout`),信号替换是在 `next()` 之前就地修改 `exec.signal`(而非 `next({ ...exec, signal })`,Cordis 会忽略后者),逐工具预算声明在 `ToolDefinition` 上(`timeoutMs`,由拥有该工具的插件从其配置中设置)而非在此插件的配置中按工具名映射——因此执行器是零配置的,拼错工具名不可能发生。以上三点均在「## 决策」中描述。 diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml new file mode 100644 index 0000000000..7f9d0625f3 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-08-agent-scope-contexts.md: f238d58d90413d36e81b34c1a2c94e1291e889de +2026-07-08-agent-scope-contexts.zh.md: dfade19709ccbf206054f414882ecff114ac1e44 diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md index dcff4d3220..f238d58d90 100644 --- a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md @@ -1,5 +1,7 @@ # RFC: The agent is a registration scope +English | [中文](2026-07-08-agent-scope-contexts.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md new file mode 100644 index 0000000000..dfade19709 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md @@ -0,0 +1,172 @@ +# RFC:agent 即注册作用域 + +Status: implemented + +[English](2026-07-08-agent-scope-contexts.md) | 中文 + +## 问题 + +一个应用需要在多个 agent(智能体)之间共享基础设施,同时让每个 agent 拥有自己的工具、prompt 贡献、策略和监听器。共享的适配器、持久化和用户界面属于部署层面;而一个人设、工具变体或监听器往往只属于某一个 agent。 + +为每个 agent 建立独立的服务图会重复共享基础设施。一个全局注册图则有相反的问题:某个 agent 的专属贡献可能泄漏到无关的 agent 中。贡献者需要一种普通的注册机制,既能决定谁能看到一项贡献,又能决定何时清理它。 + +该机制还需要一个发布边界。agent 在其本地世界完整之前不得变为可见,而拆除过程必须保留该世界直到最终工作停止。 + +## 决策 + +每个存活的 agent 拥有一个扁平的注册层,通过 `agent.ctx` 暴露。代码通过拥有该贡献的上下文进行注册;感知作用域的服务将部署全局注册与恰好一个匹配的 agent 层组合;操作从其真实 agent 选择该层;该层在 agent 完整的已发布生命周期内存在。 + +Cordis 是 SDK 底层的插件框架。Cordis **上下文(context)** 是插件用来访问服务和注册效果的对象,效果的清理跟随该上下文。[Cordis 入门](../../../cordis-primer.md)对框架有更详细的说明。 + +对大多数贡献者而言,完整的契约是四条规则: + +| 问题 | 规则 | +|---|---| +| 在哪里为某个 agent 注册行为? | 通过 `agent.ctx` 调用普通的注册 API | +| 某个 agent 的操作能看到什么? | 部署全局加上该 agent 的层,使用所属服务的合并规则 | +| 哪些作用域监听器会运行? | 无作用域监听器加上为该操作的 agent 注册的监听器 | +| 该层存在多久? | setup 在发布前完成;dispose 保留该层直到工作达到静止 | + +作用域是扁平的。解析永远不会遍历父级或兄弟作用域,生命周期所有权也不意味着注册继承。 + +```mermaid +flowchart LR + plain["Plain plugin context<br/>cleanup follows the plugin"] -->|"registers into"| globalLayer["Deployment-global layer"] + agentAContext["agentA.ctx<br/>cleanup follows Agent A"] -->|"registers into"| agentALayer["Agent A layer"] + agentBContext["agentB.ctx<br/>cleanup follows Agent B"] -->|"registers into"| agentBLayer["Agent B layer"] + + operationA["Operation for Agent A"] -->|"selects"| agentAView["Agent A view<br/>globals plus A local"] + globalLayer --> agentAView + agentALayer --> agentAView + operationB["Operation for Agent B"] -->|"selects"| agentBView["Agent B view<br/>globals plus B local"] + globalLayer --> agentBView + agentBLayer --> agentBView +``` + +缺失的交叉边就是隔离规则:Agent A 的本地注册不会进入 Agent B 的视图,父级的注册也不会仅因为父级拥有子级的生命周期就进入子级。 + +配套的[运行时设计 RFC](2026-07-12-agent-scope-runtime-design.md) 解释了实现与正确性推理。[subagent 组合控制 RFC](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 拥有独立的 `persona`、`toolFilter` 和 `maxDepth` 功能。 + +### 注册来源决定可见性与清理 + +通过普通插件上下文进行的注册是部署全局的,随该插件 dispose。同一方法通过 `agent.ctx` 调用则贡献给一个 agent,随该 agent 的作用域 dispose。 + +| 注册来源 | 默认可见性 | 随谁 dispose | +|---|---|---| +| 普通插件上下文 | 每个符合条件的 agent 视图 | 注册插件 | +| `agent.ctx` | 仅该 agent 的视图 | agent 作用域 | + +工具、prompt 段落与变量、工具限制、守卫和作用域事件监听器都采用此契约。同名的本地值通常对该 agent 遮蔽同名的全局值;每个所属服务自行记录例外与合并行为。 + +普通贡献者的模式是在 agent setup 期间注册完整的本地世界: + +```js +const handle = await ctx.agents.create({ + agentId: AgentId('reviewer'), + sessionId: SessionId('reviewer-session'), + agentOptions: { model: 'model-name' }, + setup(agentCtx) { + agentCtx.systemPrompt.section({ + name: 'deployment:persona', + order: 0, + text: 'Review code, but do not modify files.', + }) + agentCtx.tools.register({ + name: 'review_summary', + description: 'Return the review summary.', + parameters: { type: 'object', properties: {} }, + async execute() { + return [{ type: 'text', text: 'review complete' }] + }, + }) + }, +}) + +ctx.tools.get('review_summary') // undefined: not global +ctx.tools.get('review_summary', handle.agent) // the reviewer-local tool + +await handle.dispose() +ctx.tools.get('review_summary', handle.agent) // undefined: scope is gone +``` + +setup 接收一个完整的受信 Cordis 上下文,因此可以组合普通的插件和服务。其契约仅限组合:通过强制转换或内部注册表调用来驱动或发布正在构建的 agent 是不受支持的。 + +### 操作选择视图 + +注册来源与操作主体是两个独立的事实。通过 `agent.ctx` 调用服务决定的是新注册归属何处,并不将后续读取绑定到该 agent。 + +工具查找与执行接收其服务的 agent。prompt 组装接收正在构建请求的 agent 的组装上下文。事件分发接收其领域主体。这使共享服务实例可在多个 agent 间复用,同时让每个操作的视图保持显式。 + +只有采纳了作用域契约的服务才会解析 agent 层。`agent.ctx` 不会自动改变任意 Cordis 服务调用的行为。 + +### 作用域事件将路由与事件数据分离 + +关于 Agent A 的事件通常到达无作用域监听器和 A 作用域监听器,而不到达 B 作用域监听器。没有 agent 主体的事件只到达无作用域监听器。 + +在 Cordis 层面,`Scoped<T>` 是一个不透明的路由接收器。它携带用于选择监听器的过滤器,但本身不是领域对象。因此事件签名将真实的 `Agent`、工具执行、审批请求或其他主体作为显式参数保留,供监听器检查。 + +以 `{ global: true }` 注册的监听器有意绕过上下文受众过滤,但其清理仍跟随注册上下文。注册表成员变更通知保持不过滤,因为它们描述的是共享注册表状态而非某个 agent 的操作。生成的[事件目录](../../../cordis-catalog/events.md)是详尽的事件参考。 + +### 创建最后发布,dispose 最后撤销 + +`ctx.agents.create()` 和 `resume()` 构建未发布的会话、作用域、agent 和驱动器。它们等待 `setup`,准入最终的会话和 agent 条目,按序公告,启动循环,然后才返回 handle。 + +可选的创建信号仅在 create 或 resume 挂起期间取消工作。promise resolve 后,返回的 `AgentHandle` 拥有显式的 dispose 权。 + +如果加载、setup、准入或发布失败,私有事务回滚其准备的一切。使用同一调用方提供的存活 ID 的并发操作可能都到达 setup,但最终注册表条目只准入一个;所有失败者拒绝并清理其私有资源。在等待 dispose 完成后的顺序复用仍然有效。 + +`AgentHandle.dispose()` 反转边界。它停用创建或驱动,等待同步发布解除,停止并排空驱动器和最终会话刷新,分离 agent 和会话,最后 dispose 作用域。重复或竞争的 dispose 请求合并为一个完成 promise。 + +调用方的 Cordis 上下文和具体的 AgentLoop 工厂是结构性共同所有者。卸载任一方都会 dispose 事务或存活 agent。 + +```mermaid +flowchart TB + request["Create or resume"] --> privateWorld["Build private session, scope, agent, and driver"] + privateWorld --> setup["Await composition through agent.ctx"] + setup --> admission["Admit final session and agent entries"] + admission --> publish["Announce lifecycle and start the driver"] + publish --> live["Return AgentHandle"] + + privateWorld -->|"failure, cancellation, or owner loss"| rollback["Rollback private work"] + setup -->|"failure, cancellation, or owner loss"| rollback + admission -->|"duplicate or owner loss"| rollback + publish -->|"listener failure or owner loss"| rollback + live -->|"handle or owner disposal"| quiesce["Stop and drain work"] + rollback --> quiesce + quiesce --> detach["Detach agent, then session"] + detach --> revoke["Dispose the agent scope"] +``` + +## 安全与权限是非目标 + +agent 作用域组合的是受信的同进程注册。它不沙箱化插件,不定义父到子的权限格,不在创建时冻结授权,也不保证子级不能做超出父级的事。 + +父级可以拥有一个可见工具比自身更宽的子级,因为生命周期所有权不捐赠也不封顶注册。持有 Cordis 上下文的插件同样运行在同一进程中,可以直接调用可用服务。 + +需要非升级保证的部署需要独立的权限表示、传播规则和执行检查。父集合授权、创建时授权快照、显式的未来授权 API、以及通用的能力/输出/终止标签均不在本决策范围内。 + +## 曾考虑的替代方案 + +被否决的设计要么将可见性与清理分离,要么只覆盖一个注册族,要么重复共享基础设施,要么将生命周期所有权与继承混为一谈。 + +### 向每次注册传递 agent 选项 + +类似 `tools.register(definition, { agent })` 的 API 在每个注册表中重复作用域管道,并允许可见性所有权与清理所有权漂移。通过 `agent.ctx` 注册使两个事实跟随同一个 Cordis 效果所有者。 + +### 过滤事件但保持注册表全局 + +监听器过滤能阻止错误的钩子运行,但无法限定工具 schema、可执行查找、prompt 段落、变量或其他已注册数据的作用域。agent 本地组合仍需临时的全局变更。 + +### 为每个 agent 创建一个服务图 + +所需的视图是共享部署服务加上一个本地注册层。每 agent 一个图会重复适配器,并使共享持久化、提供方注册表和应用启动复杂化。 + +### 继承父级注册作用域 + +父子关系描述的是生命周期和对话谱系,而非通用合并策略。层级查找会让无关服务意外继承,且在没有独立权限模型的情况下无法定义安全性。 + +## 后果 + +贡献者使用一种熟悉的模式:通过插件上下文注册共享行为,通过 `agent.ctx` 注册本地行为,在操作上选择真实 agent,dispose 返回的 handle。从观察者角度看 setup 是原子的,teardown 保留本地行为直到工作停止。 + +代价是显式的主体选择、异步的编程式创建,以及服务需要逐个采纳作用域。扁平注册作用域有意不等于权限,subagent 组合控制作为独立功能存在,而非隐藏在作用域语义中。 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml new file mode 100644 index 0000000000..c48d3db510 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-14-acp-agent-client-protocol.md: 0bb2a2f2e307b8f23a3a9ca98edb2a2d3b5df0a8 +2026-06-14-acp-agent-client-protocol.zh.md: 19744cb9f4d4b675586d4327a1da423fdea21b77 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md index bfd0e6a10e..0bb2a2f2e3 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md @@ -1,5 +1,7 @@ # RFC: Agent Client Protocol (ACP) support — drive the coding agent from external editors +English | [中文](2026-06-14-acp-agent-client-protocol.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md new file mode 100644 index 0000000000..19744cb9f4 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md @@ -0,0 +1,59 @@ +# RFC:ACP(Agent Client Protocol)支持——从外部编辑器驱动编码 agent + +[English](2026-06-14-acp-agent-client-protocol.md) | 中文 + +Status: implemented + +## 问题 + +harness 最初只通过 readline 循环暴露 agent(智能体)。该接口能传输文本,但编辑器无法以结构化方式创建或恢复会话、关联 prompt 完成状态、流式输出推理(reasoning)与工具活动、渲染工具专属 UI、请求权限,或在不干扰其他对话的情况下取消某个对话。ACP 将这些交互定义为基于 stdio 的 JSON-RPC,Zed 是用于做出具体兼容性决策的目标客户端。 + +桥接层必须保持 harness 既有的职责边界。它不能依赖具体的 agent loop(智能体循环)、绕过工具注册表、在编辑器中执行 shell 命令,或发明第二个会话真源。stdout 同时也是协议传输通道,因此任何意外的日志输出都会破坏连接。 + +## 决策 + +`@deepseek-ai/dsh-acp` 是位于 `packages/ui/acp` 的 UI/客户端驱动插件。它使用 `@agentclientprotocol/sdk` 的 `AgentSideConnection`(基于 stdin/stdout),仅编程接口级服务:agent 创建/恢复工厂、会话持久化、工具注册表、用户交互,以及可选的审批/bash 能力。它不改变 agent loop,也不是能力 seam 的实现。 + +桥接层实现以下稳定的会话路径: + +- `initialize` 协商协议版本,声明支持 text 与 `resource_link` prompt,并声明 `loadSession`。 +- `session/new` 校验绝对路径 `cwd`,将其存入 `SessionHeader`,通过 `ctx.agents` 创建 agent,并返回组合支持的配置选项。 +- `session/load` 在构造 agent 之前,先用持久化元数据校验请求的 cwd;在异步恢复期间预留 id;将 user/assistant/tool 事件作为 ACP update 回放;并报告恢复后的 config-option fold。 +- `session/prompt` 接受 text 和 resource link,拒绝不支持或空的内容,每个会话只允许一个 in-flight prompt,并在该 prompt 所属的 `turn/end` 时结算。错误 turn 拒绝 RPC;其他关闭 turn 的原因通过一个全覆盖的 ACP stop-reason codec 映射。 +- `session/cancel` 调用队列感知的 agent 取消路径,仅结算被寻址会话的 prompt。 + +工具调用的呈现仍由工具自身负责。工具的 `presentCall` 和 `presentResult` 返回 `generic`、`terminal` 或 `diff` 渲染意图变体;桥接层对该联合类型做 switch 并映射到 ACP。没有 presenter 的工具获得通用回退。Bash 终端卡片使用 Zed 的能力门控 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit` 约定;harness 仍通过 `ctx.bash` 执行命令,保留沙箱、环境变量清理、任务归属和 cwd。不支持该扩展的客户端收到普通文本内容。文件系统工具提供 diff 卡片和文件位置,桥接层中没有硬编码的工具名分支。 + +权限处理是[用户审批 seam](2026-07-06-approval-seam.md) 上的一个 answerer,而非 ACP 中「每次工具调用都询问」的策略。一个带有 call id 的、针对桥接层所属 agent 的 `approval/request`,会变成该 agent 编辑器会话上的 `session/request_permission`,提供一次性允许/拒绝选项。非本桥接层的请求或无 call id 的请求走委托路径;answerer 缺失或失败时保持 fail-closed。决定是否询问的插件(如预执行策略或 bash 升级)拥有「是否询问」的决策权。 + +当 `ctx.permission` 被组合时,桥接层从部署的预设表中暴露一个 `permission` select。出厂的 `workspace-write` 和 `danger-full-access` 预设各自捆绑一个沙箱模式与一个审批策略;无法匹配的有效旋钮组合产生只能切走的 `custom` 状态。`session/set_config_option` 通过 `PermissionService.set()` 校验,并写入两个所属旋钮事件。在 open turn 期间的切换立即追加;idle 状态下的切换在响应中叠加,并在下一次 `agent/prompt-submit` 时锚定,位于请求组装之前。在此之前它仅存于内存,因此崩溃后恢复的是持久化的 fold。ACP session mode 不被建模,因为 config option 是面向未来的协议表面;`AcpConfig.model` 仍为连接级。 + +桥接层还提供基于 ACP 的 `UserInteractionProvider`:`ask_user_question` 请求变为所属会话上的表单引导。select、multi-select、选项描述和自定义回答覆盖语义均被保留。 + +生命周期归属是显式的。桥接层为每个活跃会话持有一个 `AgentHandle`。断连和 Cordis dispose(资源释放)会取消待处理的 prompt、并行 dispose 每个 handle、等待循环静默和持久化刷盘,然后移除记录。流式通知失败被隔离,已消失的客户端无法破坏 agent turn。ACP 应用组合不加载 stdout logger;一个测试守卫 stdout 仅包含帧化的 JSON-RPC。 + +精确的已支持与已推迟的协议行列表见 [`packages/ui/acp/acp-feature-support.md`](../../../../packages/ui/acp/acp-feature-support.md);package README 是运维契约。 + +## 曾考虑的替代方案 + +**在 `tools/execute` 前置一个监听器,对每个 ACP 所属调用都询问权限**:否决。这会把权限策略硬编码进 UI 桥接层,即使没有策略要求也会询问,且无法服务执行开始后才产生的审批请求。共享的用户审批 seam 将机制、询问策略和 UI answerer 分离。 + +**注入具体的 `agentLoop`**:否决。agent 的创建、恢复、idle 观察和 dispose 是 `dsh-agent` 上的接口级归属操作;UI 插件不需要依赖规则的例外。 + +**通过 ACP `terminal/*` 执行 bash**:否决。那会把执行移到 harness 之外,绕过其沙箱、凭证清理、任务归属、cwd 解析和会话日志。终端元数据仅用于呈现。 + +**将权限预设表示为 ACP session mode**:否决。部署定义的预设已经是一个 config-option select,而 session mode 是 ACP v2 计划移除的旧接口。 + +**防御性劫持 stdout**:否决。进程级 monkey-patching 超出 Cordis 副作用归属范围,且与协议传输竞争。应用组合拥有 stdout 纯净性。 + +## 后果 + +编辑器可以通过一条 ACP 连接创建、加载、prompt、取消、渲染、询问和重新配置多个 harness 会话,无需依赖特定的循环实现。会话事件日志仍是回放、prompt 结算、cwd 和每会话配置的持久真源。工具呈现与人工回答通道仍是可扩展的插件契约,而非 ACP 特有行为。 + +桥接层有意不实现会话列表/删除/恢复/关闭能力、MCP 透传、附加目录、图片/音频/嵌入资源 prompt、运行时模型选择、plan、斜杠命令、用量更新、编辑器文件系统委托,以及 ACP 终端执行子协议。功能清单将这些记录为不支持,而非静默接受。 + +idle 状态下的 config 选择在实时响应中是真实的,但在下一次 `agent/prompt-submit` 将其锚定到 open turn 之前不具有持久性。在该边界之前崩溃会丢失待定选择;这是保持会话事件 turn 封闭且回放安全的代价。 + +## 验证 + +ACP 测试套件覆盖内存协议编解码、创建/加载回放、精确的 prompt 结算、取消竞态、不支持的内容、工具呈现、终端能力回退、权限结果映射、config-option 校验与持久化、多会话隔离、断连/dispose 静默,以及 HMR(热模块替换)清理。快照和 built-bin 测试检验应用组合,真实 API 的 e2e 在无 key 时自动跳过。 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml new file mode 100644 index 0000000000..312106acaf --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-14-acp-multi-session.md: b96557d2d94711adb2183aa4f5dd8debf39c1de8 +2026-06-14-acp-multi-session.zh.md: 263e292e7161b789b8e06772deb0d2bc896f8de6 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md index 77fa2b4669..b96557d2d9 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md @@ -1,5 +1,7 @@ # RFC: Multiplex concurrent ACP sessions over one connection +English | [中文](2026-06-14-acp-multi-session.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md new file mode 100644 index 0000000000..263e292e71 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md @@ -0,0 +1,39 @@ +# RFC:在单连接上多路复用并发 ACP 会话 + +Status: implemented + +[English](2026-06-14-acp-multi-session.md) | 中文 + +## 问题 + +一个 ACP(Agent Client Protocol)编辑器可以在同一个 agent(智能体)子进程上维持多个活跃对话。如果桥接层只允许单活跃会话,就不得不额外启动进程,也无法匹配 Zed 的客户端模型——该模型跟踪多个 session id 和并发加载。多路复用引入了隔离风险:事件、prompt 完成、取消、权限提示、配置选择以及可预测的后台任务 id 都绝不能跨越会话边界。 + +## 决策 + +ACP 桥接层将活跃会话存储在 `Map<SessionId, SessionRecord>` 中,并维护一个 `WeakMap<Agent, SessionId>` 反向索引,供 agent 作用域的回调使用。一条记录拥有其 agent 句柄、进行中的 prompt、活跃的工具调用展示状态、待生效的空闲配置切换、会话 cwd 以及客户端能力快照。一个独立的 loading-id 集合在异步恢复之前预留每个 id,使两个流水线化的加载请求无法构造重复的 agent;不同 id 可以并发加载。 + +每个 `session/event` 和 `agent/status` 回调在发送或结算任何内容之前,先解析出所属记录。每个会话独立允许一个进行中的 prompt。prompt 记录一个日志水位线,捕获自己的 `turn/start`,并仅在匹配的 `turn/end` 到来时结算;来自已取消的先前轮次的迟到 end 不能 resolve 更新的 prompt。`session/cancel` 定位到单条记录,只调用该 agent 的队列感知取消路径。 + +权限归属使用同一个反向索引。ACP `approval/request` 应答器仅向拥有发起请求的 agent 的编辑器会话发起提示,并将外部请求委托出去。用户交互引出同样按 agent 归属路由。每会话的沙箱和审批配置值仅折叠该会话自身的事件,待生效的空闲切换存储在该记录上,直到下一个轮次将其锚定。 + +后台 bash 任务携带一个不透明的 owner token,其值等于所属会话的 session id。`bash_output` 和 `bash_kill` 在读取或终止之前,会将调用方的 token 与执行器的任务归属进行比较;仅凭可预测的 task id 不授予访问权限。归属信息存储在执行器任务上,因此工具插件重载不会擦除它。 + +连接拆除时清空活跃 map,将每个待结算的 prompt 以取消状态结算,并并行 dispose 所有 `AgentHandle`。每个句柄停止并等待其循环结束,在仍挂载时刷新会话,注销 agent,然后移除会话。拆除操作被 memoize 并在客户端断开与插件 dispose 之间共享。 + +## 曾考虑的替代方案 + +**每连接单活跃会话**:否决。它增加进程开销,与目标客户端的多会话形态相矛盾,且并未消除编辑器端的多路复用需求。 + +**每会话一个 `ctx.extend()`**:否决。子上下文本身并不创建子插件 fiber,因此监听器仍属于桥接层 fiber。实际实现的桥接层使用全局监听器加显式 O(1) 解复用,以及每会话的归属记录;agent 生命周期由 `AgentHandle` 拥有。 + +**以 agent 对象标识作为 bash 任务归属**:否决。恢复或替换后的 agent 对象可能合法地代表同一个持久会话。不透明的 session token 才是应当在插件重载后存活的跨边界标识。 + +## 后果 + +N 个会话可以并发地进行流式输出、prompt、权限请求、配置切换和后台任务运行,而不会交错或跨会话结算。一个会话中的取消或 dispose 不影响相邻会话。桥接层为此付出了显式 map 和隔离测试的代价,但它不为每个会话添加一套监听器,因此在长连接期间避免了监听器扇出。 + +桥接层目前仍未暴露独立关闭单个活跃会话的协议方法。当前所有记录在连接拆除时一起离开;会话关闭/恢复的生命周期能力在 ACP 功能清单中仍处于推迟状态。 + +## 验证 + +多会话测试套件通过交错更新、独立的进行中 prompt、定向取消、相同 id 与不同 id 的加载竞争、权限路由、配置隔离和拆除来驱动并发会话。工具 bash 测试证明一个会话无法读取或终止另一个会话的后台任务。 diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml b/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml new file mode 100644 index 0000000000..b7e263a61a --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-15-code-mode.md: c64b6d6d8442e60240fa6c849833385ed50d71ff +2026-06-15-code-mode.zh.md: f94ef61dae180bad5ec604b5c7f9552eeecff593 diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.md b/docs/rfc/implemented/feature/2026-06-15-code-mode.md index 950c2b4bd7..c64b6d6d84 100644 --- a/docs/rfc/implemented/feature/2026-06-15-code-mode.md +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.md @@ -1,5 +1,7 @@ # RFC: Code Mode — the model writes TypeScript against the tool registry +English | [中文](2026-06-15-code-mode.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md b/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md new file mode 100644 index 0000000000..f94ef61dae --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md @@ -0,0 +1,132 @@ +# RFC:Code Mode——模型针对工具注册表编写 TypeScript + +Status: implemented + +[English](2026-06-15-code-mode.md) | 中文 + +## 问题 + +在注册表的原生呈现方式中,agent loop(智能体循环)将每个可见能力作为 JSON Schema 函数定义广播。`ToolRegistry` 将其 schema 贡献给系统提示词组装,组装结果中的 `tools` 落到协议格式(wire format)上(也记录在请求头日志中),模型每步调用一个 `tool-call` 块,循环通过 `ctx.tools.execute()` **逐个**分发每次调用(并行工具执行是 `dsh-tools` 和 [docs/architecture.md](../../../architecture.md) 中明确标注的 open TODO),且**每个**中间 `tool-result` 都在下一次请求时重新进入模型上下文。 + +对于多步工具操作,这种方式 token 开销大且串行。模型无法组合工具——遍历结果集、根据中间值分支、扇出、后处理——每次调用都需要一次完整的模型往返,而每次往返都把整个中间结果拖回上下文,无论模型是否需要。 + +Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一种替代方案,基于一个简单观察:LLM(大语言模型)写代码比发出工具调用更擅长,因为它们见过数百万行真实代码,而见过的人造工具调用 trace 相对很少。模型不再每步发出一个工具调用,而是针对工具生成的 API 编写一段 TypeScript 程序,程序在沙箱运行时中执行,模型只取回它打印或返回的内容——而非所有中间结果。 + +工具呈现属于拥有工具可见性的注册表:如果把第二种呈现方式实现为事后的 waterfall(瀑布式事件)变换,正确性将依赖监听器顺序,并与[可重建请求](../../implemented/architecture/2026-07-05-reconstructable-requests.md)冲突。执行基底同样属于基础设施而非占位符:Node `worker_threads` 提供独立隔离区、空环境、堆上限以及对热同步循环的终止能力,同时契合 harness 现有的信任模型(见§信任姿态)。 + +## 决策 + +三项决策,各自在下方独立小节中展开: + +1. **Code Mode 是 `ToolRegistry`(`dsh-tools`)的一等呈现模式**,通过经过校验的 `mode` 配置选择:`'native'`(默认,贡献可见能力 schema)、`'code'`(注册表仅贡献其保留的 `run_code` 传输通道加一份生成的 SDK `.d.ts` 放入系统提示词)、或 `'both'`(原生 schema 加传输通道 + SDK)。注册表在源头塑造其规范贡献;协作式 prompt 组装的结果仍具权威性,请求头日志记录的正是该返回的呈现。 +2. **代码执行是一个能力 seam**——`packages/code-runtime/` 包含接口包 `@deepseek-ai/dsh-code-runtime`,拥有 `ctx.codeRuntime`([能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md);消费方 = `dsh-tools`,core 消费 seam 的先例见 `agent-loop` → `dsh-llm`)。运行时对工具一无所知:它接收一段程序和命名的异步绑定,执行程序,报告 `{ value, logs, error? }`。语言和基底是后端属性,因此未来的 Python 或容器后端只是另一个实现包,而非重新设计。 +3. **交付的实现是 `@deepseek-ai/dsh-code-runtime-worker`**:每次运行启动一个全新的 Node worker 线程,对模型的 TypeScript 进行 type-strip 后执行,绑定通过消息端口桥接,环境为空,堆/输出/时间上限可配置,并支持硬终止。其信任姿态在设计上等同于 bash——不需要 unsafe-acknowledgement 标志——因为 harness 已经提供了 `dsh-bash-local`,后者以严格**更大**的环境权限执行模型编写的任意 shell 命令。 + +### 注册表拥有模式 + +`ToolRegistry` 获得一个 schemastery 校验的配置(`static Config`),这是它的第一个配置:`mode: 'native' | 'code' | 'both'`,默认 `'native'`。部署通过 `cordis.yml` 切换(`tools: { mode: code }`)——无需改代码,遵循 no-hardcoded-tunables 约定。 + +**协议工具列表。** 注册表在 `'native'` 下贡献可见能力,在 `'code'` 下仅贡献 `run_code`,在 `'both'` 下两者都贡献。最终的 `PromptAssembly.tools` 列表记录在请求头中。`run_code` 是一个保留的呈现传输通道,位于注册和限制层之外;直接 prompt 提供方和组装 waterfall 仍各自负责自己的贡献。 + +**与 `toolOrder` 的交互,预先声明:** 如果配置的 `systemPrompt.toolOrder` 命名了原生能力,则在 `mode: 'code'` 下会拒绝所有组装,因为这些名称不在该模式的协议校验范围内。这是正确行为,不是 bug:使用 Code Mode 的部署需要更新其 order 配置或移除它。 + +**SDK prompt 段落。** 在 `'code'` 和 `'both'` 下,tool-guidance order band 中的惰性 `tools:sdk` 段落为作用域内可见能力渲染 TypeScript 声明加固定的使用说明。它共享查找和执行可见性,排除 `run_code`,并按字典序排列工具以获得字节稳定的输出。 + +**组装所有权。** `run_code` 和 `tools:sdk` 作为正常的组装输入进入受信任的 `system-prompt/assemble` waterfall。作用域内的 `tools:sdk` 段落可以在分发前遮蔽全局默认值,监听器可以移除或替换任一贡献。waterfall 返回的组装结果是最终的,因此修改这些输入的人有责任在部署期望 Code Mode 可用时保持协议可行;没有恢复 pass 会覆盖有意的组合。 + +**代码生成。** `jsonSchemaToTs()` 将 `defineTool` 的 JSON Schema 子集映射为 TypeScript,将 schema 描述带入 JSDoc,并将不支持的构造降级为 `unknown`。SDK 以带引号的对象键暴露工具,支持任意名称而无需别名或冲突处理。类型是建议性的,因为运行时在执行前会剥离类型。 + +### run_code 工具与分发桥接 + +在 `'code'` 和 `'both'` 下,注册表拥有 `run_code` 作为保留的呈现传输通道,带一个必需参数 `{ code: string }`。它由一个正常的 `ToolDefinition` 表示以便分发,但位于可过滤的能力层之外,因此限制规则不会意外移除 Code Mode 的唯一入口。调用遍历完整的工具流水线——`tools/pre-execute` → 单调守卫 → `tools/execute` 包裹分发 → `tools/post-execute` → 不可变的 `tools/result` 通知——与原生调用完全一致;权限插件可以在程序运行前检查程序文本,最终结果观察者看到的是归一化的外层结果。其 `execute(args, exec)`: + +1. **构建绑定。** 一个 run 作用域的 signal 跟随外层取消,并在 run 结算时被 abort。每个可见工具绑定对其参数做 JSON 归一化——在分发前拒绝有损值——等待序列化队列,以确定性的 call id 和外层 token 作为 `parent` 执行,并记录 `tool/code-dispatch`。成功的文本变为字符串,非文本块变为占位符;工具错误使绑定 promise reject。每个子调用保留自己的不可变执行身份,并遍历完整的工具流水线。 +2. **运行程序**:`ctx.codeRuntime.run({ program: args.code, bindings: [{ global: 'tools', functions }], signal: runController.signal })`。运行时接收的是 run 作用域的 signal 而非仅调用方的外层 signal,因此外层 run 以任何方式结算都会同时 abort 运行时内部的工作。 +3. **静默后结算。** 运行时结算后,桥接 abort 未完成的工作并排空分发队列后再返回。成功时返回捕获的输出和呈现元数据。运行时失败变为 `CodeRunFailedError`;后端拒绝使用注册表的正常错误边界。两者都产生结构化的错误结果,且 `run_code` 结算后没有子调用可以追加。 + +**子调用的 `additionalContext` 被省略。** 在 `run_code` 期间注入它会破坏父调用/结果的邻接性,而一个程序可以产生多个上下文。支持它需要一个复数通道或循环级别的子分发缓冲区。 + +**并发被序列化。** 每次 run 拥有一个分发队列,因此即使 `Promise.all` 也按提交顺序执行工具调用。结算时放弃尚未开始的排队调用。并行化需要逐工具的并发安全元数据。 + +**呈现。** `run_code` 的渲染意图按 [render-intent RFC](../../implemented/architecture/2026-07-02-tool-render-intent-union.md) 在此决定:`presentCall` → 一个 `generic` 卡片,`kind: 'execute'`,title = 程序文本,`rawInput` = 同一段程序文本;`presentResult` → 一个 `generic` 卡片,内容为捕获的输出(来自 `meta`)。程序作为 title 是因为 ACP execute 卡片可靠地渲染该字段,而某些客户端会省略 body 和 raw-input 内容。这不是 `terminal` 卡片:该卡片的语义是「工作目录中的 shell 命令」,程序不是。 + +### 可观测性:`tool/code-dispatch` + +每次子分发追加一个仅日志的 `tool/code-dispatch` 事件,包含父子 call id、工具身份、归一化参数和结果摘要。它不进入模型历史,但可供持久化和 UI 使用。追加发生在打开的 `run_code` 轮次内。没有 agent 的直接执行仍然运行,但无法记录该事件。 + +### code-runtime seam + +`packages/code-runtime/code-runtime/`——`@deepseek-ai/dsh-code-runtime`,仅依赖 `cordis`。一个抽象的 `CodeRuntime extends Service`(`super(ctx, 'codeRuntime')`)加词汇: + +- `CodeRunRequest = { program: string; bindings: CodeBindingNamespace[]; signal?: AbortSignal }` +- `CodeBindingNamespace = { global: string; functions: Record<string, (args: unknown) => Promise<unknown>> }`——运行时将每个命名空间作为程序内部的全局异步函数对象暴露;绑定参数和解析值必须是 structured-cloneable 的(运行时可能跨越序列化边界;我们的实现确实如此)。 +- `CodeRunResult = { value?: unknown; logs: CodeLogEntry[]; error?: CodeRunFailure }`——程序执行结果,包括异常、超时、abort 和 worker 退出,以 `error` 字段解析。`run()` 仅在调用方/seam 误用时才 reject(例如重复的绑定命名空间);消费方仍在自己的错误边界处理不合规的后端 rejection。 +- `CodeLogEntry = { source: 'console' | 'stdout' | 'stderr'; level?: 'log' | 'info' | 'warn' | 'error' | 'debug'; text: string }` +- `CodeRunFailure = { kind: 'exception' | 'timeout' | 'abort' | 'worker-exit'; message: string }`——正交的结果按[防御性模式](../../../defensive-patterns.md)独立报告;超时的 run 不是异常,abort 不是超时。 +- 两个只读的后端描述符,仅供信息参考不用于门控:`language`(程序必须使用的语言——交付的后端为 `'typescript'`;Python 后端会声明自己,并在呈现侧配对自己的 SDK 生成器)和 `isolation`(交付的后端为 `'worker-thread'`;未来的为 `'process'`、`'container'` 等)。`dsh-tools` 在 MVP 中要求 `language === 'typescript'`——其代码生成输出 TS——否则组装会大声失败,与 `toolOrder` 违规时的配置错误惯用法相同(如 `mode` 为非 native 但根本没有加载 `ctx.codeRuntime`)。 + +请求包含所有运行时输入;实现方拥有经过校验的超时和上限默认值。注册表仅在组装 Code Mode 时查找可选的运行时,因此原生模式不依赖它。缺失或语言不兼容的运行时会大声失败。替代基底或语言可以在同一 seam 后面替换实现,配对相应的 SDK 生成器。 + +### worker 线程运行时 + +`@deepseek-ai/dsh-code-runtime-worker`,`packages/code-runtime/` 组的第二个包。每次 `run()`: + +1. **宿主侧 type-strip**,使用 Node 内置的 `stripTypeScriptTypes`(`node:module`;在本仓库的整个引擎范围 `^22.19.0 || >=24.0.0` 内可用,且保持位置不变,因此运行时错误行号与模型源码一致)。Strip-only 模式拒绝不可擦除的语法(`enum`、namespaces)——该拒绝以 `error.kind: 'exception'` 加 Node 的消息返回,SDK 说明写明「仅限可擦除 TypeScript」,模型像处理任何其他程序错误一样自我纠正。语法级别的失败永远不会 spawn worker。 +2. **每次 run spawn 一个全新 `Worker`**,来自包自身的 bootstrap 模块:`env: {}`(真正为空——比 spawn 命令的 scrubbed-env 规则更严格),`resourceLimits` 来自配置,`stdout`/`stderr` 捕获到 `logs` 而非继承。不做池化、不跨 run 共享状态:程序的世界随 worker 消亡,这使得 run 仅从日志即可重建,且状态泄漏不可表达。 +3. **在 bootstrap 中执行**:剥离类型后的程序成为一个 `AsyncFunction` 的函数体,其参数是绑定全局变量和一个捕获式 `console` shim,因此顶层 `await` 和 `return` 可用,程序的完成值即为 run 的 `value`(structured-cloneable 值原样跨越;其他值被替换为其 `util.inspect` 渲染,已文档化)。 +4. **通过消息端口桥接绑定**:worker 中的每个绑定函数发送 `{ id, global, name, args }` 并等待回复;宿主根据请求的绑定校验名称、调用、并回复 `{ id, ok, value }` 或 `{ id, ok: false, message }`(宿主侧绑定拒绝变为程序侧 rejection)。worker 侧的命名空间对象通过 `defineProperty` 构建为 null-prototype,因此名为 `__proto__`、`constructor` 或 `toString` 的绑定是普通的自有属性,不会产生原型链冲突。未知名称、重复 id 和结算后的消息被拒绝或忽略——端口协议假设对端是敌对的,因为对端运行的是模型代码。 +5. **强制独立预算。** `computeMs` 计量 worker 忙碌时间,允许慢速的 awaited 工具而不放过热循环。`maxWallMs` 限制总经过时间,包括未完成的等待。到期、取消和完成都会终止 worker。堆退出和截断被显式报告;compute、wall、heap、log 和返回值上限都是经过校验的配置。 +6. **Dispose 至静默**:服务自身的 disposal 终止进行中的 worker 并*等待*它们退出后再 resolve,遵循[防御性模式](../../../defensive-patterns.md)。 + +### 信任姿态 + +worker 运行时提供的是封闭隔离,而非安全边界:模型代码可以触及 Node API,权限与 bash 工具相当。`worker.terminate()` 停止线程但不停止它 spawn 的 OS 进程。Code Mode 使用与 bash 相同的 `tools/pre-execute` 策略门控,并额外提供空环境、堆限制、独立隔离区和对程序本身的硬终止。需要硬多租户边界的部署需要为代码和 bash 都使用容器级后端;运行时的 isolation 描述符让它们能区分该后端。 + +### 模型看到的内容 + +SDK 指示模型编写一个异步的可擦除 TypeScript 函数体,通过 `await tools.name(args)` 调用工具,在需要时 catch 被 reject 的工具调用,并仅返回或打印应重新进入上下文的输出。即使在 `Promise.all` 下调用仍保持顺序。声明前缀可以与原生 schema 一样大,尤其在 `'both'` 下,但对提供方缓存保持稳定。 + +## 后果 + +切换到 `'code'` 的部署必须更新任何仅原生的 `toolOrder`。组装监听器负责维护任何被重写的协议表面的完整性。子分发保持序列化,桥接不会传播逐调用的 `additionalContext`,直到为 Code Mode 设计好这些契约。 + +## 测试 + +- **Worker 运行时:** 真实 worker 测试覆盖输出和值捕获、失败类型、compute 和 wall 预算、敌对绑定流量、空环境、structured-clone 回退、输出上限和 disposal 至静默。一个 built-package 测试在纯 Node 下运行 worker 入口。 +- **注册表集成:** 测试覆盖代码生成、所有呈现模式、保留名称和限制规则、作用域可见性、权威组装重写、`toolOrder`、运行时兼容性失败、完整流水线子分发、parent-token 关联、序列化、取消和队列排空、JSON 归一化、错误传播、日志事件、省略的 `additionalContext` 和 HMR(热模块替换)清理。 +- **带密钥 e2e:** 真实模型在一个程序中组合两次 bash 调用;测试验证折叠的请求头、关联的分发事件、生成的文件和精选的回答。 +- **快照:** `code-mode-turn` 和 `both-mode-turn` fixture(测试前置数据)固定 SDK 段落、头部工具列表、分发事件和结果卡片。 + +## 曾考虑的替代方案 + +**一个零核心改动的附加消费方插件。** 否决,因为 `agent/request` 在[可重建请求](../../implemented/architecture/2026-07-05-reconstructable-requests.md)下仅限 call-config,而变换已组装的工具列表需要在不拥有其配置的情况下撤销 `toolOrder` 规范化,且依赖监听器顺序。模型被提供哪些工具、以何种表示,是注册表的单一关注点:原生 schema 和 SDK 是同一可见存储的两种投影。 + +**`node:vm` 作为参考运行时,加固推迟。** 否决:`node:vm` 不是隔离(原型链逃逸可达宿主 realm)且无法中断热循环。worker 线程提供独立隔离区、空环境、`resourceLimits` 和可靠的 `terminate()`,信任等级等同于 bash,因此参考实现和生产实现是同一个包,无需 unsafe-acknowledgement 仪式。 + +**对原生工具调用做结果省略/摘要。** 仅解决问题的上下文膨胀一半:裁剪旧 `tool-result` 作为可重建请求下的日志表面替换很容易添加,但仍然每次调用付出一次模型往返,且无法表达循环、分支或汇合。互补而非竞争;它可以在 Code Mode 下为残余的原生调用分层。 + +**循环中的并行原生分发。** 往返开销的另一个答案;仍是有效的未来工作(open TODO),仍被并发安全元数据阻塞,且仍无组合能力——它并行化的是模型在一步中已经决定的调用。Code Mode 的序列化队列决策使两者兼容:当元数据就绪时,原生并行分发和逐工具绑定并行化一起解锁。 + +**始终排他(忠实于 Cloudflare,无模式)。** 否决,因为本 SDK 的主要消费方是编码 agent:其日常的单次调用(`bash`、`read`、`edit`)作为原生调用已经是理想的,强迫每次编辑都通过程序会加重常见场景的负担。mode 配置让忠实形式(`'code'`)只需一行配置即可启用而不强加。 + +**逐工具可见性层级(此工具原生,彼工具仅 code)。** 推迟:它需要逐工具元数据和 `'native' | 'code' | 'both'` 不具备的呈现拆分,且其设计依赖于模型在 `'both'` 下如何分配使用的证据。 + +**SDK 中的消毒标识符别名**(`my-tool` → `my_tool`,Cloudflare 的做法)。否决:`declare const` 上的带引号键使每个名称可达,零别名冲突逻辑;模型处理 `tools["my-tool"](…)` 没有问题。 + +**REPL 风格的持久内核**(状态跨 `run_code` 调用存活)。MVP 否决:跨调用状态对会话日志不可见,破坏了每个请求是日志纯函数的可重建性保证;每次 run 全新保持了这一点。内核风格后端在未来仍可通过 seam 表达,配合自己的日志方案。 + +## 风险 + +**Worker 不是硬安全边界。** 有意为之且已文档化(见§信任姿态):姿态等同于现有 bash 工具,封闭隔离超过它,门控使用相同的 seam。需要更多的部署需要未来的 `isolation: 'container'` 后端——作为 seam 的设计扩展跟踪,而非本设计的 TODO。 + +**`stripTypeScriptTypes` 标记为 experimental。** 它与 Node 自身原生 `.ts` 执行背后的引擎(amaro/swc)相同,在本仓库的整个引擎范围内作为 API 暴露。缓解措施:运行时的单元测试套件固定了所依赖的行为(位置保持、可擦除限制的拒绝消息形状宽松匹配),调用位于一个私有函数后面,且 `amaro`/`sucrase` 是 API 变动时的即插即用替代品。可擦除子集是面向模型的契约线,错误路径是一个可工作的反馈循环,而非死胡同。 + +**SDK 的 prompt 开销,尤其在 `'both'` 下。** `.d.ts` 可以与它补充的原生 schema 相当大;`'both'` 携带两种表示。前缀稳定性 + 提供方缓存摊销了每会话开销;mode 是逐部署的;本 RFC 不做无条件节省的声明。何时偏好哪种模式的量化指导明确是上线后的学习。 + +**注册表范围增长。** `dsh-tools` 吸收了代码生成、一个工具、一个桥接和一个事件。通过包内的模块边界(`ts-types.ts`、`code-mode.ts` 与 `schema.ts`/`json-schema.ts`/`presentation.ts` 并列)和 seam 来约束:所有基底形状的东西都在 `ctx.codeRuntime` 后面。 + +**Structured-clone 值可以超出 JSON。** 因此工具绑定在分发前对参数做 JSON 归一化,确保每个执行的调用都可以被记录。底层运行时保持其更宽的端口契约,而更严格的消费方在自己的边界处校验。非文本子结果变为占位符。 + +**仅序列化的子分发。** `Promise.all` 尚未获得挂钟并行性,仅减少了往返次数;模型可能过度期望。说明中已声明;解除此限制与原生并行分发 TODO 所需的相同并发安全元数据绑定。 + +**预算计量读取事件循环,而非标志。** 忙碌时间轮询(`eventLoopUtilization()`)比精确 CPU 计量更粗——预算到期最多延迟一个轮询间隔——且其正确性声明(「pending dispatch 无法暂停它」)对敌对程序是承重的。两侧都有单元测试(带 pending decoy dispatch 的热循环在 `computeMs` 时死亡;idle-on-slow-binding 存活到 `maxWallMs`),轮询间隔是内部常量而非配置——部署无法将其误调为绕过。 diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml new file mode 100644 index 0000000000..6aac0209ec --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-17-filesystem-tool-schemas.md: c2d3aa679599b1129a19b9082b9254ecf3103f12 +2026-06-17-filesystem-tool-schemas.zh.md: b13274c41da244d7d2a5fe6ff2064d8d5e0a9b42 diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md index adad17472d..c2d3aa6795 100644 --- a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md @@ -1,5 +1,7 @@ # RFC: Filesystem tool schemas — model-facing read/write/edit shapes +English | [中文](2026-06-17-filesystem-tool-schemas.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md new file mode 100644 index 0000000000..b13274c41d --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md @@ -0,0 +1,112 @@ +# RFC:文件系统工具 schema——面向模型的读/写/编辑形状 + +Status: implemented + +[English](2026-06-17-filesystem-tool-schemas.md) | 中文 + +## 问题 + +[文件系统能力 seam RFC](../architecture/2026-06-17-filesystem-capability-seam.md) 定义了文件系统能力 seam(`ctx.fs`)、包拆分(`dsh-fs`、`dsh-fs-local`、`dsh-tool-fs`,加上 `dsh-fs-policy` 策略插件),以及 read-before-write/edit 检查所依赖的 observed-file/stale-version 策略——[split-fs-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](../architecture/2026-06-26-file-context-as-event-gate.md) 两份 RFC 随后将该策略从 `ctx.fs` 移到了 `dsh-fs-policy` 插件的 `fs/*` 事件门上。第一版文件系统工具交付剩余的决策是面向模型的 schema 表面:模型在 `read`、`write` 和 `edit` 中看到哪些参数。 + +schema 应当足够小,能在 `dsh-tool-fs` 的首次实现中完成;同时又足够稳定,使未来的本地/远程/沙箱文件系统后端不会引起面向模型的接口变动。它还应避免从参考系统照搬所有选项。Claude Code 和 OpenCode 暴露了类似的核心文件工具,但在命名风格和额外 flag 上有所不同;本 RFC 为原型选择最小的共有表面。 + +## 决策 + +`@deepseek-ai/dsh-tool-fs` 在第一版文件系统工具套件中暴露以下三个面向模型的工具: + +| Tool | 我们的 schema | Claude Code | OpenCode | 说明 | 纳入原型 | +|---|---|---|---|---|---| +| `read` | `read(file_path, offset?, limit?)` | `Read(file_path, offset?, limit?, pages?)` | `read(filePath, offset?, limit?)` | 仅文件;`offset` 从 1 开始;首次实现不支持图片/PDF/多模态。 | 是 | +| `write` | `write(file_path, content)` | `Write(file_path, content)` | `write(content, filePath)` | 创建或覆写 UTF-8 文本。在默认 fs-policy 下,更新已有文件需要先有一次观测;新建文件则不需要。 | 是 | +| `edit` | `edit(file_path, old_string, new_string, replace_all?)` | `Edit(file_path, old_string, new_string, replace_all?)` | `edit(filePath, oldString, newString, replaceAll?)` | 字面字符串替换;默认要求唯一匹配;在默认 fs-policy 下需要先有一次观测(任何窗口化的 read 都算)。 | 是 | + +schema 使用 snake_case 字段名(`file_path`、`old_string`、`new_string`、`replace_all`),与 Claude Code 及现有 DeepSeek Harness 工具 schema 示例保持一致。消费方包将这些面向模型的名称转换为 `ctx.fs` 调用和 `fs/*` 事件分发。 + +## 工具 schema + +### `read` + +`read` 检查一个 UTF-8 文本文件并返回带行号的内容。 + +参数: + +- `file_path: string`——必填。要读取的路径,由 `ctx.fs` 解析。 +- `offset?: number`——可选。返回的第一行,从 1 开始。默认为第一行。 +- `limit?: number`——可选。返回的最大行数。默认值和上限是 `dsh-tool-fs` / `ctx.fs` 的实现细节。 + +首次实现的非目标: + +- 不支持 PDF `pages` 参数。 +- 不支持图片或多模态文件读取。 +- 不通过 `read` 列出目录;如有需要,目录列表将作为单独的未来工具。 + +### `write` + +`write` 创建或完全替换一个 UTF-8 文本文件。 + +参数: + +- `file_path: string`——必填。要写入的路径,由 `ctx.fs` 解析。 +- `content: string`——必填。要写入的完整 UTF-8 文本内容。 + +在默认 fs-policy 下,用 `write` 更新已有文件需要同一执行上下文对该文件有过一次先前观测(read/write/edit);`dsh-fs-policy` 插件将观测到的版本作为 `fs/write-intent` 上的 stale guard 提供。创建新文件不需要先前观测。如果策略插件不存在,`write` 是无条件的裸提供方 create-or-overwrite。 + +schema 不将 `expected_hash`、`expected_version` 或 `create_only` 暴露为面向模型的参数。stale-version 检查由后端产生的版本和策略插件的观测状态驱动,而非要求模型通过 schema 复制版本令牌。 + +### `edit` + +`edit` 通过替换字面文本来更新一个已有的 UTF-8 文本文件。 + +参数: + +- `file_path: string`——必填。要编辑的路径,由 `ctx.fs` 解析。 +- `old_string: string`——必填。要替换的字面文本。首次实现中空字符串无效。 +- `new_string: string`——必填。字面替换文本;空字符串表示删除匹配项。 +- `replace_all?: boolean`——可选。默认为 false。为 false 时,`old_string` 必须恰好匹配一处。 + +`edit` 要求同一执行上下文对该文件有过一次先前观测(任何窗口化的 read 都算——授权依据是版本新鲜度,而非全文查看要求),或该上下文对该文件有过先前的 write/edit。`dsh-fs-policy` 策略插件推导所有者并将记录的版本作为 stale guard 提供;提供方的 mutation lock 强制执行。 + +首次实现拒绝 Codex 风格的 patch 语法和多模式 edit API。它使用一种严格的字面替换模式,使面向模型的契约保持简单,后端可以自行掌控精确匹配、重复匹配、行尾和 stale-version 语义。 + +## 结果形状 + +首次实现通过现有的 `ToolDefinition.execute()` 契约返回 `ContentBlock[]`。`ctx.fs` 返回结构化的文件系统结果并负责文件状态的记录/刷新;`tool-fs` 将这些结果格式化为模型投影。 + +默认原生投影: + +| Tool | `tool-fs` 消费的结构化 `ctx.fs` 结果 | 默认模型投影 | +|---|---|---| +| `read` | 返回的行、返回行数、总行数、目标显示路径、文件版本、部分视图标志 | 带行号的文本加分页脚注 | +| `write` | create/update 操作、目标显示路径、新文件版本 | 简洁的 create/update 成功文本 | +| `edit` | 替换次数、replace-all 标志、目标显示路径、新文件版本 | 简洁的 edit 成功文本 | + +结构化结果不重复模型参数(如 `file_path`、`old_string` 或 `content`),除非后端已将其解析为新信息(如 `displayPath`、`targetKey` 或新版本)。token 感知的截断属于模型投影的职责,不属于后端的规范结果。 + +## 延后 + +以下内容被明确排除在首版文件系统 schema 之外: + +- 面向模型的 `expected_hash`、`expected_version` 或 `create_only` 参数。 +- 目录列表、glob、grep 和搜索工具。 +- 二进制安全的读/写操作。 +- PDF/图片/多模态 `read`。 +- 文件系统工具的 Code Mode 投影值。 +- 规范的 edit diff 格式。 + +## 测试 + +schema 测试固定每个工具的必填/可选参数集、空 `old_string` 拒绝、`replace_all` 默认值、snake_case 字段名、描述文本中对观测策略的说明,以及根插件套件注册;集成测试通过 `ctx.tools.execute()` 对真实的 `dsh-fs-local` 提供方执行全部三个工具,并验证模型参数被正确转换为预期的 `ctx.fs` 调用和 `fs/*` 分发。 + +## 曾考虑的替代方案 + +- **Codex 风格的 patch 语法或多模式 edit API**:否决。一种严格的字面替换模式使面向模型的契约保持简单,并让后端自行掌控精确匹配、重复匹配、行尾和 stale-version 语义。 +- **camelCase 参数名(OpenCode 风格)**:snake_case 与 Claude Code 及现有 harness 工具 schema 示例一致,且命名一旦发布即成为公开表面。 +- **面向模型的 `expected_hash` / `expected_version` / `create_only` 参数**:否决。stale 检查由后端产生的版本和策略插件的观测状态驱动,从不依赖模型复制的脆弱令牌。 + +## 后果 + +**首版 schema 有意小于 Claude Code。** 去掉 PDF pages、多模态 read、丰富的 grep/list flag 和 expected hash 字段使实现保持聚焦,但用户可能很快提出这些需求。它们将以独立 RFC 或聚焦的后续工作形式到来,而非在初始 schema 上叠加重载。 + +**v1 没有显式的面向模型 stale guard。** schema 不要求模型提供 expected hash/version。这是有意为之:stale 检查来自后端产生的版本和 `dsh-fs-policy` 插件的观测状态,而非来自模型复制的脆弱令牌。文件系统安全失败通过 `dsh-fs` 拥有的结构化 `FsError` 代码浮现,而非通过模型提供的版本字段。 + +**命名成为公开表面。** 一旦发布,将 `file_path` 改为 `filePath` 或将 `old_string` 改为 `oldString` 会搅动提示词、示例和下游客户端。本 RFC 预先选定 snake_case 并将其视为稳定的面向模型契约。 diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml new file mode 100644 index 0000000000..7f9212b3d3 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-18-acp-terminal-and-tool-rendering.md: cab89aa690c2068399ea5429a9c467410c744ce8 +2026-06-18-acp-terminal-and-tool-rendering.zh.md: 5a545b7a53f0814bc0e6071430c367047dc83f7f diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md index 3b8cd810a8..cab89aa690 100644 --- a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md @@ -1,5 +1,7 @@ # RFC: Rich ACP bash rendering — the terminal card via the `_meta` convention +English | [中文](2026-06-18-acp-terminal-and-tool-rendering.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md new file mode 100644 index 0000000000..5a545b7a53 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md @@ -0,0 +1,48 @@ +# RFC:丰富的 ACP bash 渲染——通过 `_meta` 约定实现终端卡片 + +Status: implemented + +[English](2026-06-18-acp-terminal-and-tool-rendering.md) | 中文 + +## 问题 + +ACP 桥接层允许每个工具通过 `presentCall`/`presentResult` 自行控制调用渲染(见[工具调用 UI 展示](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md)与 `packages/core/tools`)。对于 `bash`,我们将确切命令作为 `tool_call` 标题呈现,模型的 `description` 作为内容文本块,`kind: 'execute'`,完成后的输出包裹在 ` ```console ` 围栏文本块中。 + +参考编辑器将终端元数据渲染为一张专用卡片,包含 cwd、命令、实时风格输出和退出状态;纯文本丢失了这些结构。命令之所以作为标题,是因为执行卡片隐藏了原始输入,而人类可读的描述保留为卡片上方的独立块。 + +## 关键发现:agent 执行的终端使用 `_meta` 约定,而非 `terminal/create` + +ACP 规范有一个*客户端侧*终端子协议:agent 调用客户端的 `terminal/create`,传入 `{ command, args, cwd, env }`,由**编辑器**执行进程,然后 agent 读取 `terminal/output` / `wait_for_exit`。这个模型不适合我们:我们的 harness 通过 `dsh-bash` 自行执行 bash(沙箱化的环境变量清洗、后台任务所有权、按会话的 cwd)。把执行路由到编辑器会绕过所有这些机制,并将执行分裂为两个后端。 + +研究两个参考 agent(2026-06-18)发现,二者都没有为自己的 shell 工具使用 `terminal/create`——**两者都保持 agent 侧执行,并发出一套 `_meta` 约定**,由 Zed 特殊处理: + +- **`claude-agent-acp`**(`tools.ts`、`acp-agent.ts`):以 `clientCapabilities._meta.terminal_output` 为门控。`tool_call` 携带 `content: [{ type: 'terminal', terminalId }]` 和 `_meta.terminal_info.{ terminal_id, cwd }`;输出/退出通过 `tool_call_update` 的 `_meta.terminal_output.{ terminal_id, data }` 和 `_meta.terminal_exit.{ terminal_id, exit_code, signal }` 到达。 +- **`codex-acp`**(`CodexToolCallMapper.ts`、`TerminalOutputMode.ts`):调用上同样携带 `terminal_info`;输出通过 `_meta.terminal_output`(完整)或 `_meta.terminal_output_delta`(增量)发送,由同一个 `_meta.terminal_output` 能力选择。 + +Zed 侧(`crates/agent_servers/src/acp.rs`,已验证):收到 `ToolCall` 且其 `_meta.terminal_info.terminal_id` 已设置时,注册一个**仅展示**的终端(header = `terminal_info.cwd`,label = `tool_call.title`);收到 `ToolCallUpdate` 时,`_meta.terminal_output.data` 写入该终端,`_meta.terminal_exit.{exit_code,signal}` 设置状态。它将能力声明为 `clientCapabilities._meta.terminal_output = true`。`_meta` 本身是 ACP 规范认可的扩展点(在 `ToolCall`/`ToolCallUpdate` 上类型为 `{[k]: unknown} | null`);这里的*具体键*(`terminal_info`/`terminal_output`/`terminal_exit`)是 Zed 约定,不属于 ACP 规范——但它们是 Zed 集成的事实契约,也是在保持 agent 侧执行的前提下获得终端卡片的唯一途径。 + +## 决策 + +保持 `dsh-bash` 的 agent 侧执行;通过 `_meta` 约定渲染终端卡片,以能力声明为门控,以 ` ```console ` 文本块作为保底回退。 + +1. **能力声明。** `initialize` 读取 `clientCapabilities._meta.terminal_output`,桥接层按连接记住它。 +2. **提供方无关的展示词汇。** `dsh-tools` 新增一种终端形态的展示结构,工具可以返回它——提供方无关(`cwd`、输出 `data`、`exitCode`/`signal`),不含 ACP 类型。`dsh-tool-bash` 为 `bash` 返回该结构(cwd 来自解析后的工作目录;输出 + 退出从运行结果解析)。 +3. **桥接映射。** 当客户端声明了该能力时,桥接层将展示结构映射为:在 `tool_call` 上,`content:[…, {type:'terminal', terminalId}]`(工具的任何 `content`,如描述,渲染在终端块之前)+ `_meta.terminal_info.{terminal_id,cwd}`;在 `tool_call_update` 上,`_meta.terminal_output.{terminal_id,data}`(捕获的输出)+ `_meta.terminal_exit.{terminal_id, exit_code|signal}`(解析的退出),且 update 的文本 `content` 被省略(ACP 的 `tool_call_update.content` 会**替换**调用的 content 集合,因此重发围栏块会覆盖终端内容块)。`terminalId` 由 harness 的 `callId` 派生(稳定、每次调用唯一)。当能力未声明时,桥接层在调用上发送描述内容块,在 update 上发送既有的 ` ```console ` 文本内容——行为不变。 +4. **退出标记从渲染输出中解析;无新执行路径,无实时流式传输。** 输出在完成时附加(来自 agent 自身的 `tool/result`),不逐 token 流式传输。退出状态标记(`_meta.terminal_exit.{exit_code,signal}`)会被发出:纯 `presentResult(args, result)` seam 只能看到内容块,因此 `dsh-tool-bash` 通过解析 `renderResult` 追加的状态标记(`[exit code: N]` / `[killed by signal: …]`)来恢复结构化退出——解析是标记发出的精确逆操作,二者在同一文件中共同演进,一个往返测试守护这对关系。dispose 不受影响:没有新资源需要清理,因为桥接层从未创建客户端侧终端。 + +## 曾考虑的替代方案 + +- **ACP 客户端侧终端子协议(`terminal/create`)**:明确否决。编辑器将执行进程,绕过 `dsh-bash` 的环境变量清洗、后台任务所有权和按会话的 cwd,并将执行分裂为两个后端。两个参考 agent 以同样的方式否决了它(见上述关键发现);agent 侧执行加 `_meta` 约定是在保持 harness 执行策略的同时获得终端卡片的唯一形态。 +- **通过事件 schema 透传结构化退出**:否决,改用标记往返方案。纯 `presentResult(args, result)` seam 只能看到内容块,而解析是标记发出的精确逆操作,在同一文件中共同演进并由往返测试守护。 + +## 后果 + +- **Zed 约定的 `_meta` 键。** 终端卡片依赖 Zed 特有的键(`terminal_info`/`terminal_output`/`terminal_exit`),位于 ACP 规范认可的 `_meta` 扩展点内,而非 ACP 终端子协议。不识别这些键的客户端仍然获得文本回退(能力门控确保我们只在客户端通过 `_meta.terminal_output` 声明支持时才发出这些键),因此非 Zed 客户端永远不会变差。如果 ACP 日后标准化了 agent 执行的终端,迁移到该标准并移除约定键。 +- **能力诚实。** 仅在客户端声明了 `_meta.terminal_output` 时才发出终端元数据;文本回退是对所有其他客户端的契约,绝不能退化。由一个无能力测试覆盖,断言 ` ```console ` 路径。 +- **terminalId 冲突。** 从每次调用的 `callId` 派生,保证在会话内唯一且在 call/result 对之间稳定;绝不跨调用复用。 +- **退出从渲染文本中解析。** 退出标记通过解析 `renderResult` 的状态标记来恢复 `exit_code`/`signal`,而非通过事件 schema 透传结构化退出(纯 `presentResult` seam 看不到结构化退出)。解析是标记发出的精确逆操作,位于同一文件中;一个往返测试固定了这对关系,标记格式的变更如果破坏了解析就会使测试套件失败。如果标记将来需要与退出标记的需求分歧,改为在 result 事件上暴露结构化退出。 +- **提供方无关词汇的蔓延。** 终端展示结构扩大了 `dsh-tools` 的接口面;保持其中立性(不让 ACP 类型泄漏到 `dsh-tools`),且只提供第二个 UI 消费方也会需要的丰富度。 + +## 不在范围内 / 非目标 + +文本块基线仍是无能力声明时的默认行为。两个后续工作有意不在此处构建,各自需要独立 RFC:**实时增量流式传输**(`_meta.terminal_output_delta`,在分片到达时发送,需要 `dsh-bash` 上的增量输出 seam),以及**命令分类**(将 `cat`/`sed` 解析为带文件位置的 `read` 卡片、将 `grep` 解析为 `search` 等,回退到终端卡片——仅展示,绝不改变实际执行的内容)。 diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml new file mode 100644 index 0000000000..211ad897f7 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-18-compaction-capability-seam.md: 31b06905924a07a7f0c2af427d8868585966f1a7 +2026-06-18-compaction-capability-seam.zh.md: ef71b3df39f02221f1bd25beb5e026cb056b95a0 diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md index 4a6586b159..31b0690592 100644 --- a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md @@ -1,5 +1,7 @@ # RFC: Compaction as a capability seam (abstract contract + basic backend) +English | [中文](2026-06-18-compaction-capability-seam.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md new file mode 100644 index 0000000000..ef71b3df39 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md @@ -0,0 +1,127 @@ +# RFC:压缩作为能力 seam(抽象契约 + 基础后端) + +Status: implemented + +[English](2026-06-18-compaction-capability-seam.md) | 中文 + +## 问题 + +长时间运行的 agent(智能体)对话会无限增长。随着事件日志不断累积轮次,派生出的消息历史最终逼近模型的上下文窗口——模型随即在响应中途截断(`max-tokens`)或质量退化。**压缩(compaction)**是缓解手段:用一段简洁的摘要替换一段较早的历史,保持近期上下文完整。 + +[会话 surface](../../implemented/architecture/2026-06-18-session-surface.md) 正是为此而建的基础设施:它是事件日志之上的链表,带有一个 `surfaceOp: { op: 'replace', start, end }` 操作,专门用于遮蔽一段节点并插入替换内容,`sourceEventSeqs` 记录来源以便决策可确定性回放。剩下的是那个*决定压缩什么、并产出摘要*的插件。 + +两股力量塑造了设计。第一,压缩是**可替换的**:token 计数可以是 char/4 启发式或真实 tokenizer,摘要生成可以是模型调用、模板或远程服务——这些与*何时*压缩、*压缩哪段*彼此独立变化。第二,`SurfaceEventType` 是封闭的,只有五种事件类型(`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`);只有它们可以携带 `surfaceOp`。因此一个专属的 `compaction/*` 事件**不能**出现在 surface 上——编译器拒绝在其上放 `surfaceOp`,invariants 插件在运行时也会拒绝。 + +## 决策 + +### 压缩是一个能力 seam,接口与实现分离 + +按照[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md),压缩以独立包(package)发布,使契约、算法和(后续的)消费方 surface 各自独立演进: + +1. **接口** — `@deepseek-ai/dsh-compact`:一个抽象的 `CompactService`,拥有 `ctx.compact` 键、`CompactionResult` 词汇以及 `compact/*` 会话事件。它将 `compactIfNeeded()` 和 `compactRegion()` 声明为**抽象方法**——契约阐述压缩*做什么*,而非*怎么做*。 +2. **实现** — `@deepseek-ai/dsh-compact-basic`:一个具体的 `BasicCompactService`,拥有完整算法——token 估算(每 token 字符数——`charsPerToken` 配置,默认 4——加逐块开销)、尾→头保留遍历、通过 `ctx.llm.stream()` 的摘要生成、surface 替换、锁,以及 `agent/pre-step` 自动压缩监听器。基于 tokenizer 或模板的后端是兄弟包(或覆写两个 protected 估算/摘要钩子的子类)。 +3. **消费方** — 推迟。一个 `/compact` 工具和斜杠命令将 `inject: ['compact']` 并调用契约;它们被有意排除在本 RFC 范围之外,以便 seam 先稳定下来。 + +### 契约依赖 `dsh-session` 和 `dsh-llm`——有意的偏离 + +能力 seam RFC 规定接口包「只依赖 cordis」(对 `dsh-bash` 成立,其词汇是自包含的)。压缩**无法**遵守这一点:它的动词定义在 `Session` 之上(`compactRegion(session, start, end)`),其输出*就是*内容词汇(`CompactionResult.summary: ContentBlock[]`)。不引用 `Session`/`SessionEvent`(来自 `dsh-session`)和 `ContentBlock`(来自 `dsh-llm`),契约无法表达。 + +这不是耦合异味——而是契约的领域本身。「只依赖 cordis」的指导原则本来就是「接口只依赖契约真正命名的东西,绝不依赖实现」的简写。`dsh-session` 和 `dsh-llm` 本身就是接口/词汇包,不是实现;`dsh-compact` 仍然不导入任何后端。seam 的真正不变式——*消费方和实现在抽象服务背后独立演进*——完好无损。 + +### 抽象的 `compactIfNeeded` / `compactRegion`,算法在后端 + +早期草案将完整算法(保留遍历、token 求和、文本提取)作为接口上的具体方法,只有 `estimateContentTokens()` 和 `summarize()` 是抽象的。这会把契约重新耦合到一种策略:想要不同保留策略或不同事件排序的后端不得不与继承来的具体代码对抗。将两个核心方法都设为抽象,把所有*怎么做*的决策放在后端——它本该在那里——接口则保持为纯粹的*做什么*声明。后端内部仍有分层——`estimateContentTokens()` 和 `summarize()` 是 `protected` 钩子,子后端可以覆写而无需重新实现遍历——但这种分层是后端的私有关注,不是契约的。 + +`compactIfNeeded(agent, turn, step, fullSystemPrompt, signal)` 接受**必填**参数(而非最初的全可选形态)。自动压缩 seam(见下文)总是提供 agent、生命周期上下文、组装好的系统提示词(计入估算)以及轮次的 abort signal,因此可选性只会在 seam 处引入隐藏默认值。被压缩的会话来自 agent 上下文。`compactRegion(session, start, end, agent, turn, step, signal?)` 保留可选的 signal(手动调用方可以省略)。传递生命周期上下文而非具体模型,使路由 agent 保持诚实:后端的摘要请求可以走 `agent/request`,模型路由插件已在那里选择实际模型。 + +### 自动压缩运行在 `agent/pre-step`,一个专用的 surface 变更 seam + +压缩会变更会话 surface,因此它在步骤开启之前、消息派生之前运行。`agent/request` 仍然是调用配置变换,永远不需要在 surface 变更后重建历史。 + +解决方案是一个专用的循环 seam:**`agent/pre-step`**(`@mode serial`),由循环在系统组装*之后*、步骤开启(`step/start`)*之前*触发: + +``` +assembly = ctx.systemPrompt.assemble() +await ctx.serial('agent/pre-step', agent, turn, step, system, signal) ⟵ compaction mutates the surface here +session('step/start') ⟵ the step opens AFTER the seam +messages = session.deriveMessages() ⟵ single derive, reflects the compaction +request = waterfall agent/request ⟵ pure request transform (hooks, model switch) +``` + +循环在 `agent/pre-step` 之后只派生一次消息。在 `step/start` 之前运行使压缩记录落在任何半开步骤之外,简化崩溃修复。该 seam 是 awaited 且 serial 的,因此 surface 变更不会交错;监听器返回 `void`,不使用 Cordis bail 值作为否决。 + +### 保留是轮次无关的;工具配对平衡是唯一的结构守卫 + +自动压缩在**每个**步骤之前触发,而非每轮一次。这对**失控轮次存活至关重要**:一个工具密集的 ReAct 轮次每步追加一个 `assistant/message` + 一个 `tool/result`,surface 在*一轮之内*就会增长。单独一轮就可能超出窗口(「失控轮次」)——而在下一次模型调用溢出之前能挽救它的唯一时机,就是下一步的 `pre-step` 检查点。如果把压缩限制在轮次的第一步(或更糟,逐字保留整个进行中的轮次),就恰好重新打开了压缩存在的意义所要堵住的那个缺口:harness 会在最需要压缩的时候崩溃。 + +`compactIfNeeded` 保留估算大小达到 `retainTokens` 的最小尾部完整 surface 单元,压缩更早的节点。一个单元是一个完整的已关闭步骤或一条无步骤消息。如果 token 截断点落在步骤内部,保留范围会扩展直到截断处工具配对平衡。平衡按 surface 顺序检查,而非日志序列号,因为替换摘要在旧 surface 位置有新的序列号。`compactRegion` 拒绝将工具调用与其结果拆开的边界。进行中的轮次不享有特殊保留。 + +因此失控轮次的压缩方式与任何其他历史完全相同:其早期*已关闭*步骤被摘要,近期步骤保持逐字。当唯一可压缩的内容只剩一个不可拆分的开放尾部步骤(其工具调用尚无结果)时,压缩拒绝执行(返回 `null`),待该步骤关闭后重试。 + +**单单元溢出不在范围内,这是有意的。** 如果单个被保留的单元——一个已关闭步骤,或一个大型自由节点如粘贴的 `user/message`——*单独*超出预算,压缩无能为力,下一次模型调用可能超预算发出。限制单个单元的大小是另一个关注点(输出截断),在别处处理;压缩对此不作承诺,而没有这种机制的 harness 仍然可能在单个超大单元上崩溃。这里诚实地命名了这个边界,而非掩盖它。 + +### 头部锚定:一个自动检查点,始终在头部 + +自动压缩始终从 surface 头部开始,将先前的检查点与新压缩的历史合并,使自动检查点始终只有一个。因此 `shadowedRange` 是位置性的而非数值序列区间:一个更新的摘要序列号可能占据更旧的 surface 位置。`shadowedSeqs` 记录权威的 surface 顺序。手动的中间范围压缩可能留下多个检查点。 + +### 近似收敛不变式 + +`resolveConfig` 校验数值参数但**不**基于假想的摘要长度不变式拒绝。收敛是动态的:提供方的输出上限可能被隐藏或外显的推理 token 消耗,模型可能输出不可预测大小的摘要。`maxTokens` 只是摘要调用的提供方侧生成上限;推理块在检查点存储前被剥离。如果压缩后的 surface 仍超阈值,`compactIfNeeded()` 最多额外重压缩头部检查点 `compactionRetries` 次,但每次提交的摘要必须小于它遮蔽的内容。唯一的残余情况是上述单单元溢出(一个向后取整的超大步骤可能把保留尾部推过预算)——这恰好是上面声明的范围外关注点,而非抖动 bug。 + +### Surface 替换:`compact/*` 事件仅存于日志;一条 `user/message` 承载摘要 + +由于 `SurfaceEventType` 是封闭的,摘要不能搭载在 `compact/*` 事件上。后端改为追加一条**单独的 `user/message`**,带有 `surfaceOp: { op: 'replace', start, end }`,其 `content` 是(带框架的)摘要,其 `sourceEventSeqs` 覆盖被遮蔽的节点*以及*簿记事件。`compact/*` 事件是纯日志记录(锁 + 来源)。surface 变更位于锁**内部**——`compact/end` 是最后追加的事件: + +``` +compact/start → log-only. Acquires the lock. +[summarize older range via the backend] +compact/summary → log-only. Provenance: raw summary, range, shadowed seqs, token count. +user/message → surfaceOp { op:'replace', start, end }. THE surface mutation (framed summary). + deriveMessages() renders it as a user-role message. +compact/end → log-only. Releases the lock (carries `error` on a recoverable failure). +``` + +`deriveMessages()` 随后产出 `[summary_as_user_message, ...retained_nodes]`。复用 `user/message` 是诚实的而非变通:摘要确实*就是* user 角色的上下文。 + +### 检查点框架 + 增量合并(后端私有) + +基础后端将摘要包装为已建立的检查点上下文,并标记它以便下一轮增量合并。原始摘要保留在 `compact/summary` 上。框架是后端策略;seam 只承诺一条替换 user 消息承载可能带框架的摘要。 + +### 通过日志记录的锁实现阻塞,加上崩溃/可恢复失败分类 + +`compact/start … compact/end` 括号的合理性,按实际承担的工作排序: + +1. **可检测的崩溃孤儿 + 来源记录**(首要)。摘要生成是一次慢模型调用,在 `compact/start` *之后*持久化。摘要生成中途崩溃会留下一个没有匹配 `compact/end` 的 `compact/start`——一个可检测的孤儿。最后释放锁(而非最先释放)将崩溃窗口从*静默损坏*转化为可检测的孤儿。 +2. **防止并发压缩。** 如果当前轮次持有一个未匹配的 `compact/start`,`compactRegion` 拒绝启动。(循环在 awaited 的 `pre-step` 上是单线程的,因此这也是一个重入绊线——抛出的「already in progress」信号意味着真正的 bug。) + +两种失败路径,均有文档记录: + +- **崩溃**(循环在摘要生成中途死亡):一个悬空的 `compact/start`,没有关闭者。因为 `compact/*` 是**仅日志**事件,孤儿是**惰性的**——surface 替换从未落地,所以完整的未压缩历史正确派生。通用轮次修复(`interruptedTurnClosers`)用合成的 `turn/end` 关闭轮次;孤儿位于该 `turn/end` *之前*,因此轮次范围的进行中检查永远看不到它,崩溃不会卡住未来的压缩。压缩在下一个 `pre-step` 简单地重新尝试。 +- **可恢复**(摘要生成抛出异常但循环存活):后端追加带有 **`error`** 字段的 `compact/end`,surface 不受影响,模型调用继续使用完整历史。 + +`compact/end` 保留其 `error?` 字段(与 `tool/result` 的自包含错误一致——一个事件即可区分成功与失败,无需关联兄弟事件)。没有单独的 `compact/error` 事件。 + +**核心会话修复保持对压缩无感知——这是有意的。** `interruptedTurnClosers` 从不被教导 `compact/*`。如果教导它,每个未来的 `xxx/start … xxx/end` 插件对都必须修补核心模块——这恰好是能力 seam 架构存在的意义所要避免的耦合。因为仅日志的孤儿是惰性的,不需要特殊修复:通用轮次修复加上未落地 surface 变更的惰性就足够了。 + +## 曾考虑的替代方案 + +- **完整算法作为接口上的具体方法**(只有估算/摘要是抽象的)——早期草案;否决,因为它把契约重新耦合到一种保留策略。两个核心方法都是抽象的;`protected` 的估算/摘要钩子是后端的私有分层,不是契约的。 +- **压缩运行在 `agent/request` waterfall(瀑布式事件)上**——早期方案;否决,因为它强制了双重派生,且交给监听器的上下文在结构上无法压缩。专用的 `agent/pre-step` seam 使分层在构造上正确。 +- **单独的 `compact/error` 事件**——否决:`compact/end` 保留 `error?` 字段,与 `tool/result` 的自包含错误一致——一个事件即可区分成功与失败,无需关联兄弟事件。 +- **教导核心轮次修复认识 `compact/*`**——否决:仅日志的孤儿是惰性的,而一个为每个未来 `xxx/start … xxx/end` 插件对打补丁的核心模块,恰好是能力 seam 架构存在的意义所要避免的耦合。 + +## 后果 + +- **新包**:`packages/compact/compact`(接口)和兄弟包 `compact-basic`(后端),位于 `packages/compact/` 下,接入根 tsconfig。消费方层推迟。 +- **新循环 seam**:`agent/pre-step`(`@mode serial`),在 `dsh-agent` 中声明,由 `dsh-agent-loop` 在系统组装之后、`step/start` 之前触发。这是循环的文档化变更——`docs/architecture.md` 记录了它,生成的 cordis catalog 携带其签名。 +- **`SessionEventMap`** 通过声明合并(merge-extensible)获得 `compact/start` / `compact/summary` / `compact/end`;`SurfaceEventType` **不受影响**。这些是会话事件而非 cordis `Events`,因此事件分类门禁无需新增条目。 +- **`dsh-session`** 获得工具配对平衡谓词(`isToolPairingBalanced`,位于 `tool-pairing.ts`,从包索引导出),`compactRegion`/`compactIfNeeded` 用它确保折叠区域不会拆开步骤的工具调用/结果对。surface 的 `replace` 操作和 surface 元数据运行时守卫已经存在,直接复用。 +- **`dsh-invariants`** 移除其 `surface replace: start must be <= end` 断言:头部锚定的压缩会将高序列号的替换节点放在更旧范围的*位置*,因此 `start > end` 在数值上是正常且有效的(范围是位置性的,由 surface 的 `indexOf` 检查验证,这些检查保持不变)。轮次包含不变式原样复用。 +- **接线**:`dsh-compact-basic` 在 `examples/coding-agent` 的 `cordis.yml` 中加载,使 seam 在真实演示中交付(此前未在任何地方加载)。 + +## 测试 + +- **单元测试:** 真实 Loader 和 invariant 插件覆盖整单元保留、收敛失败、`compact/end` 的两种结果、头部锚定、开放尾部拒绝、惰性崩溃孤儿,以及在一个超大开放轮次内压缩已关闭步骤。 +- **循环测试:** 测试固定每步在 `turn/start` 和 `step/start` 之间有一次 awaited 的 `agent/pre-step`;在那里的 surface 变更落在步骤之外,并出现在单次派生的请求中。 +- **带密钥 e2e:** 真实模型和 bash 会话在降低限制下触发压缩,记录完整的 `compact/start…end` 对,缩小 surface,并完成任务。 +- **快照缺口:** 失控轮次压缩尚无法回放,因为摘要调用未记录 `assistant/chunk` 事件或 `sessionId`;交错的摘要调用回放仍是后续工作。 diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml new file mode 100644 index 0000000000..ec702a6101 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-21-subagent-capability-seam.md: 2bed84cd9166e8aa1ad5fa65b3afa44b8a842045 +2026-06-21-subagent-capability-seam.zh.md: a99d0fe894dca485452dd266752785a26815bb8a diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md index e2871532c8..2bed84cd91 100644 --- a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md @@ -1,5 +1,7 @@ # RFC: Subagent capability seam +English | [中文](2026-06-21-subagent-capability-seam.zh.md) + Status: implemented > The full seam is shipped: the `dsh-subagent` interface, the `dsh-subagent-mock` test backend, and the `dsh-tool-subagent` consumer; the two in-process backends (`dsh-subagent-spawn`, `dsh-subagent-fork`); the nested-agent snapshot infrastructure ([per-session snapshot replay](../testing/2026-06-22-subagent-snapshot-replay.md)); and the out-of-process `dsh-subagent-acp` backend ([its RFC](2026-06-22-acp-subagent-backend.md)). diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md new file mode 100644 index 0000000000..a99d0fe894 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md @@ -0,0 +1,74 @@ +# RFC:Subagent 能力 seam + +Status: implemented + +[English](2026-06-21-subagent-capability-seam.md) | 中文 + +> 完整 seam 已交付:`dsh-subagent` 接口、`dsh-subagent-mock` 测试后端与 `dsh-tool-subagent` 消费方;两个进程内后端(`dsh-subagent-spawn`、`dsh-subagent-fork`);嵌套 agent 快照基础设施([按会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md));以及进程外 `dsh-subagent-acp` 后端([其 RFC](2026-06-22-acp-subagent-backend.md))。 + +## 问题 + +harness 有一个长期搁置的 subagent seam:一个 agent 将工作委派给另一个 agent。意图已在 `Agent`/`AgentLoop` 接口中勾勒([packages/core/agent/src/types.ts](../../../../packages/core/agent/src/types.ts)、[packages/core/agent-loop/src/index.ts](../../../../packages/core/agent-loop/src/index.ts)):创建选项引用父 agent(fork = 用父会话的事件日志为子会话播种;spawn = 全新会话),子 agent 以 `Agent` 句柄返回,使 steering(中途引导)和事件订阅统一工作。本 RFC 实现该 seam;上方横幅列出了已交付的内容。 + +决定整体设计走向的核心需求是:**多种 subagent 实现必须在运行时共存**。一个父 agent 可能在同一个会话中既需要一个廉价的进程内子 agent 处理有限范围的子任务,又需要一个隔离的进程外子 agent(通过 ACP)。我们预见的传输方式: + +- **进程内**:在同一个 `Context` 上创建子 `ReactLoopAgent`(最廉价,且鉴于已有的 agent 工厂几乎零成本); +- **ACP**:作为 ACP *客户端*驱动另一个 agent 进程(可以是自身的另一个实例); +- 后续:**A2A**、**Codex app-server** 与 **Claude Code Agent SDK**——每种都与 ACP 后端相同的进程外「启动子 agent、发送提示词、流式更新、取消」形态。 + +## 曾考虑的替代方案 + +### 为什么不用 bash seam 的形态 + +bash seam([能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md))在每个 context 中只注册一个 `BashExecutor`;加载第二个会抛异常。这对 bash 是正确的(一台机器、一种执行命令的方式),但对这里是错的:共存才是需求。因此 subagent 服务是一个**命名提供方注册表**:每个实现以唯一名称注册,调用方按名称选取。这与 **LLM 适配器注册表**(`LlmService.registerAdapter`)同构,而非单服务的 bash 执行器。seam 仍然是三包结构(接口 / 实现 / 消费方);唯一不同的轴是「单实现 vs. 多实现」。 + +## 决策 + +### 三包 seam + +新增包组 `packages/subagent/`: + +| 包 | 角色 | +|---|---| +| `@deepseek-ai/dsh-subagent` | 接口:`SubagentService`(`ctx.subagents`)、`SubagentProvider`、`SubagentRun`、请求/结果/能力词汇表、`subagent/*` 事件 | +| `@deepseek-ai/dsh-subagent-spawn` | 实现:通过 `ctx.agents.create` 创建全新的进程内子 agent | +| `@deepseek-ai/dsh-subagent-fork` | 实现:以父会话日志快照为种子的进程内子 agent | +| `@deepseek-ai/dsh-subagent-acp` | 实现:作为 ACP 客户端驱动已配置的子进程 | +| `@deepseek-ai/dsh-subagent-mock` | 支撑:脚本化的提供方,用于通过真实加载路径测试 seam | +| `@deepseek-ai/dsh-tool-subagent` | 消费方:基于 `ctx.subagents` 的面向模型的 `subagent` 工具 | + +### 基本原语:异步 `start → SubagentRun` + +提供方暴露 `start(request) → Promise<SubagentRun>`。完成后发布一个就绪的子 agent 并将其运行句柄转交给调用方。一个信号覆盖就绪前后的取消;`dispose()` 取消剩余工作并等待静默。启动失败时清理部分资源,不发出生命周期事件。`start` 是传输无关的;`spawn` 仅命名全新进程内后端。 + +### 两类可选能力,两种发现方式 + +- **启动时特性**(`outputSchema`、`depthLimit`、`toolFilter`、`persona`)挂在静态 `provider.capabilities` 描述符上。服务在委派之前检查每一项请求的特性,若提供方不支持则**大声拒绝**(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不「接受后静默忽略」。它们必须在 run 存在之前被检查,这就是为什么不能做成运行时方法。 +- **运行时特性**(通过 `sendMessage` 进行 steering、通过 `resume` 进行后续交互)是 `SubagentRun` 上的**可选方法**。方法的存在即是能力,TypeScript 窄化即是发现机制:消费方不经窄化就无法调用不存在的方法,因此不存在静默降级路径,也不需要一个单独的 flags 对象来保持同步。 + +### Fork 与 fresh 是独立后端,而非一个 flag + +全新子 agent 和 fork 子 agent 是独立的提供方,而非请求上的 flag。`dsh-subagent-spawn` 启动隔离的子 agent;`dsh-subagent-fork` 以仅包含已完成父轮次的平衡前缀为种子。进行中的轮次被排除,因为其 subagent 调用尚无结果,无法构成有效的回放历史。 + +### 子 agent 隔离与父日志 + +每个 subagent 运行在自己的 **`Session`** 中(独立 id、`parentSession` 谱系),独立持久化。父日志仅记录 spawn 的 `tool/call` 及其 `tool/result`(子 agent 的最终输出);子 agent 的内部步骤和工具调用留在子 agent 自己的会话中,从不注入父日志。这是唯一在所有传输方式下行为一致的设计:ACP 子 agent 的内部事件物理上无法注入我们的父日志,因此让进程内行为保持一致,使 seam 保持传输无关。 + +### 同步收集(第一版) + +`dsh-tool-subagent` 将其执行信号传给 `start()`,等待子 agent 结果,并在 `finally` 中 dispose 该 run。非完成态的结果变为错误结果,而非成功的部分输出。这个前台消费方不使用 run 的可选 steering 方法。 + +### 提供方选择是配置,不面向模型 + +`dsh-tool-subagent` 绑定到恰好一个提供方名称(`Config.provider`);模型只看到 `{ description, prompt }`。若要暴露多种传输方式,多次加载该工具插件,每次绑定不同的提供方和不同的 `toolName`(工具注册表拒绝重名)。*服务*持有多提供方注册表;*工具*选取其中一个。本版 schema 中没有 provider/type 参数。 + +## 测试 + +seam 通过真实的 Cordis Loader/export 路径测试,这能捕获 [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md) 中描述的 export 形状失败。注册表测试覆盖重载安全性、重名和启动时能力拒绝;嵌套 agent 场景通过[按会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md)进行无密钥回放;进程内后端还有真实循环的单元测试和带密钥的 e2e。 + +## 后果 + +- **递归。** 若无限制,进程内子 agent 能看到委派工具并递归。进程内后端实现了可选的绝对深度限制和有作用域的实时全局 `toolFilter`;ACP 声明这两项能力为关闭并拒绝此类请求。[subagent 组合控制 RFC](2026-07-12-subagent-persona-tool-filter-and-depth.md) 拥有它们的确切语义和安全限制。 +- **阻塞父轮次。** 同步收集在子 agent 的整个持续期间保持父 agent 的 `runStep` 打开。这对第一版是可接受的;**后台 / 轮询 / 溢出语义推迟到未来的重新设计,该重新设计将统一 subagent 与 bash 的长时运行工具处理**(一个 sub-agent 和一个长时间运行的 `bash` 后台任务面临相同的「模型启动了一个慢操作,之后如何收集结果」问题,应共享一套机制而非各自发明)。 +- **实时进度。** 本版仅暴露生命周期事件和最终结果;逐分片的子→父更新流推迟到后台重新设计。 +- **ACP 客户端接口。** 将 ACP 子 agent 的 `fs`/`terminal` 代理回父 agent(共享工作区模式)是后续工作;第一版不声明这两项能力,子 agent 在自己的进程中自给自足。 diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml new file mode 100644 index 0000000000..a34398b188 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-22-acp-subagent-backend.md: 7eb03ddf68f54c29524944e7b8bc801eb1724fe6 +2026-06-22-acp-subagent-backend.zh.md: 6f7b95318a2c714fea43a584ba49da00a7c12040 diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md index 0b98adb0de..7eb03ddf68 100644 --- a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md @@ -1,5 +1,7 @@ # RFC: ACP subagent backend (out-of-process delegation) +English | [中文](2026-06-22-acp-subagent-backend.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md new file mode 100644 index 0000000000..6f7b95318a --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md @@ -0,0 +1,57 @@ +# RFC:ACP subagent 后端(进程外委派) + +Status: implemented + +[English](2026-06-22-acp-subagent-backend.md) | 中文 + +## 问题 + +subagent seam(见 [seam RFC](2026-06-21-subagent-capability-seam.md))的设计使得多个后端可以按名称共存于 `ctx.subagents` 上。进程内后端(`-spawn`/`-fork`)将子 agent 作为同一个 Cordis 上下文上的第二个 `Agent` 运行——开销低,但子 agent 与父 agent 共享进程、模型客户端和工具。seam 的核心意义正是还要支持通过协议到达的进程外子 agent,以证明这层抽象能跨越进程边界泛化。本 RFC 添加第一个此类后端:一个 ACP(Agent Client Protocol)客户端。 + +## 决策 + +`@deepseek-ai/dsh-subagent-acp` 注册一个 `SubagentProvider`,将每个子 agent 运行在一个**派生的子进程**中,以 ACP *客户端*身份驱动。它是现有服务端桥接 `@deepseek-ai/dsh-acp`(ACP *agent*)的方向反转孪生体:桥接**应答** `initialize`/`newSession`/`prompt`;本后端**调用**它们并**实现** `Client` 回调(`sessionUpdate`、`requestPermission`)。将配置的 spawn 命令指向 `acp-agent` 示例,即可让 harness 与自身进程对话。 + +### 每次运行启动新进程 + +每次 `start` 都 spawn 一个新子进程,运行恰好一个 ACP 会话(`initialize` → `newSession` → `prompt`),`dispose` 杀死子进程并等待其退出。这是最简单的生命周期,与进程内「每次运行一个子 agent」的形态一致。 + +### 最小客户端桩 + +客户端不声明任何可选能力(无 `fs`、无 `terminal`):子 agent 在自己的进程中自行处理文件/终端访问。`session/update` 通知被消费——后端累积 `agent_message_chunk` 文本作为结果输出,在本次实现中忽略其余内容(思考、工具调用卡片),仅呈现子 agent 的最终回答。`session/request_permission` 由配置的策略自动应答(`reject` 拒绝每个提示,`allow` 通过第一个 allow 形态的选项批准)——本次实现不将任何提示呈现给人类。将 `fs`/`terminal` 代理回父进程(共享工作区模式)仍是未来工作,如 seam RFC 所述。 + +### 无启动时能力 + +提供方的 `capabilities` 全部为 `false`。进程外子 agent 无法遵守父 agent 的 `maxDepth`(它无法访问 `parent.options.subagentDepth`)或 `toolFilter`(它拥有自己的工具注册表),且本次实现未实现 `outputSchema`。服务在 `start` 运行之前就会拒绝需要上述任何能力的请求。后端仅注入 `subagents`(而非 `ctx.agents`),并忽略 `request.parent`。 + +### StopReason 映射 + +ACP `StopReason` → harness `SubagentStopReason`:`end_turn`→`completed`、`max_tokens`→`max-tokens`、`refusal`→`refusal`、`cancelled`→`aborted`、`max_turn_requests`→`error`(无对等语义——任务未完成)、未知→`error`。spawn/传输/RPC 失败解析为 `error`(如果已请求取消则为 `aborted`);按 seam 契约,`result` 永远不会因子 agent 级别的失败而 reject。 + +### 安全:清洗子进程环境 + +子 agent 是独立进程,因此会继承环境变量。凭证形态的环境变量(`/KEY|SECRET|TOKEN/i`)默认**不**转发——父 harness 自身的密钥不得隐式泄漏到派生进程中(与 bash 执行器采用的策略相同)。子 agent **自身**的凭证(它需要模型密钥)通过 `config.env` **显式**提供,在清洗之后叠加,因此有意传入的 `DEEPSEEK_API_KEY` 得以保留,而偶然存在的 `AWS_SECRET_ACCESS_KEY` 不会。子进程 stderr 继承到父进程的 stderr(诊断信息自然浮现);spawn 级别的 `error` 事件(如命令不存在时的 ENOENT)被捕获并与 ACP 驱动竞争,使错误命令解析为 `error` 而非以未处理错误崩溃父进程。 + +## 测试 + +- **无需密钥的单元/集成测试:** 一个脚本化的 ACP 子进程通过真实 stdio 测试 prompt/output 流、所有 stop-reason 映射、信号与 dispose 取消(包括 pre-abort、pre-session 竞态和管道断裂场景)、两种权限策略、被忽略的非消息更新、命令缺失时的清理、提供方重载,以及命名空间导出。 +- **需要密钥的 e2e 测试:** 后端 spawn 真实的 ACP 示例;其模型回答 `PONG`、写入 `proof.txt`,父进程验证该文件。 +- **快照缺口:** 每个 ACP 子 agent 是独立进程、拥有自己的回放会话,不同于进程内的按会话回放。确定性 mock-server 覆盖已有;`TODO(acp-subagent-replay)` 跟踪父 agent 对回放中子 agent 的回放支持。 + +## 曾考虑的替代方案 + +### 为何继续使用 SDK 0.25.1? + +后端仅需 `ClientSideConnection`、`ndJsonStream`、`PROTOCOL_VERSION` 和客户端协议类型,0.25.1 均已支持。0.28 的 fluent API 需要在 ACP 层同时迁移客户端和服务端连接类,但不会改善本后端,因此升级作为独立变更保留。 + +### 为何不使用持久子进程? + +持久进程池(跨运行复用热子进程)是一项性能优化,推迟到未来工作——它引入会话生命周期和崩溃恢复的复杂性,本次实现不需要;每次 `start` spawn 新子进程与进程内「每次运行一个子 agent」的形态一致。 + +## 后果 + +每次运行都要付出一个新子进程的开销(spawn + `initialize` + `newSession`)。父 agent 仅呈现子 agent 的最终回答:`session/update` 中的思考和工具调用卡片被消费后丢弃,权限提示永远不会到达人类——由配置的策略应答。子进程环境默认经过凭证清洗,因此其自身的模型密钥须通过 `config.env` 显式提供。 + +## 未来提供方 + +同样的进程外 spawn/prompt/stream/cancel 形态可泛化到 seam RFC 中列出的其他传输方式——A2A、Codex app-server 和 Claude Code Agent SDK——每个都是按名称注册的兄弟提供方。ACP 后端证明了 seam 支持跨进程边界;其余在机制上类似。 diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml new file mode 100644 index 0000000000..c46a38e46f --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-25-ask-user-question.md: 06673233038d10214f8de3d1f29766d43b575442 +2026-06-25-ask-user-question.zh.md: 01d1284dba3622984d5403f94e3edd0ba02583b6 diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md index d7c6631b94..0667323303 100644 --- a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md @@ -1,5 +1,7 @@ # RFC: Ask-user question capability +English | [中文](2026-06-25-ask-user-question.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md new file mode 100644 index 0000000000..01d1284dba --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md @@ -0,0 +1,51 @@ +# RFC:ask-user 提问能力 + +Status: implemented + +[English](2026-06-25-ask-user-question.md) | 中文 + +## 问题 + +agent(智能体)有时仅凭模型推理(inference)无法安全地继续:它需要人类选择路径、确认有风险或默认的操作,或提供缺失的信息。在此变更之前,获取答案的唯一方式是模型在 assistant 文本中提问然后停止,这会打断正常的工具调用循环:agent 没有结构化的暂停手段,没有供 UI 使用的选项元数据,没有中止/错误分类体系,也没有让非 stdio 前端一致地呈现问题的方式。 + +这是一个面向用户的能力,但它也跨越了包(package)边界。模型侧的工具需要一套提供方无关的请求词汇;每个 UI 表面需要决定如何展示和收集答案;agent loop(智能体循环)应保持不变,因为工具调用本身已具备正确的异步形态。 + +## 决策 + +引入 `dsh-user-interaction` 作为 `ctx.userInteraction` 的提供方无关接口包,与模型侧消费方 `dsh-tool-ask-user` 一同放在 `packages/ui` 下。这一分组是有意为之:向人类提问是一种由 UI 支撑的产品能力,不属于无提供方的核心主干。seam 仍然拥有稳定的请求/应答/错误词汇,而 UI 产品表面提供收集答案的具体 provider。工具注册 `ask_user_question`,转发 `{ questions, agent, signal }`,并将 provider 计算出的结构化答案作为工具结果返回。 + +模型侧的请求词汇有意与产品研究 schema 对齐:`ask_user_question({ questions: [{ id, question, header?, options?: [{ label, description? }], multi_select? }] })`。`id` 按问题提供并在结果中回传,使批量请求可以路由而不依赖问题文本。`label` 既是面向用户的显示文本,也是返回给模型的选中值;没有单独的 `value`,没有 `recommended`,没有 `allow_custom`,也没有 `desc` 别名。 + +provider 返回 `{ answers: [{ id, selected, custom? }] }`。`selected` 始终是选中选项 label 的数组,因此单选和 `multi_select` 的答案共享同一种结果形态。`custom` 承载自由文本的「其他」答案;无选项的问题直接收集 `custom`。当 `custom` 存在时,它覆盖所有已选选项,`selected` 为空。 + +`UserInteractionError` 继承 `HarnessError`,因此 `NO_PROVIDER`、`ASK_ABORTED`、ACP 取消或会话路由缺失等失败会以可机器路由的 `{ name, code }` 工具错误形式通过 `ctx.tools.execute()` 传出。这与结构化错误分类体系一致,使模型或包装插件能区分「用户取消」与通用抛出异常。 + +## UI 映射 + +`dsh-stdio-demo` 的包内 readline 模块逐题渲染每个问题,在下一行展示每个选项的 `description`,支持以逗号/空格分隔的数字选择 `multi_select`,接受自由格式的自定义答案,并在中止、provider dispose(资源释放)或 stdin EOF 时拒绝待处理的问题。批量请求按顺序逐题询问,合并为一个答案对象返回。stdio provider 通过内部队列序列化并发请求,确保同一时刻只有一个 prompt 占用 stdin。 + +`dsh-acp` 为 ACP(Agent Client Protocol)会话提供同一 seam。它通过 bridge 的 `agent→sessionId` 反向映射将调用方 `Agent` 的 ask 请求路由到对应会话,并为每个问题调用 ACP `unstable_createElicitation`(携带会话作用域的表单)。单选选项变为 `choice` 字符串枚举;`multi_select` 选项变为 `choice` 数组枚举;无选项问题使用必填的 `custom` 文本字段。如果客户端同时返回 `choice` 和非空 `custom`,以 custom 答案为准。ACP `decline`/`cancel`、缺失答案、缺失会话以及客户端不支持 elicitation 的情况都会变为结构化的 `UserInteractionError`。 + +ACP 映射有意使用 elicitation 而非 `session/request_permission`。`request_permission` 仍保留给独立的权限门禁:它是围绕工具执行的 yes/no 或策略式授权协议。`ask_user_question` 是一个通用的信息收集工具,支持可选的自由格式答案,因此 ACP 表单 elicitation 是更贴合的协议。bridge 的会话路由与未来的权限门禁共享,但用户意图不同。 + +## 曾考虑的替代方案 + +**Assistant 文本后跟一个停止的轮次。** 模型可以在纯 assistant 文本中向用户提问然后停止。这会丢失结构化的选项元数据,UI 没有提供方无关的方式来渲染选择,且下一条人类回答只能作为新的 user prompt 到达,而非作为需要答案的那次操作的结果。 + +**核心包拥有 ask-user 相关包。** 最初实现将 seam 和模型侧工具分别放在 `packages/core` 和 `packages/ui`,但两者描述的是同一个由 UI 支撑的人机交互能力。seam 仍然是提供方无关的,但它不是像会话、工具或 agent 注册表那样的无提供方核心基础设施。将 `dsh-user-interaction` 和 `dsh-tool-ask-user` 一起放在 `packages/ui` 下,使包结构与产品边界一致:应用和 bridge 提供人类答案的 provider,stdio 应用选择性加载模型侧工具。 + +**ACP `session/request_permission`。** 权限请求是围绕工具执行的授权;`ask_user_question` 是带可选自由格式答案的信息收集。将权限用于通用提问会混淆两个不同的产品概念,并使未来的权限门禁更难推理。 + +**循环级别的暂停原语。** agent loop 已经知道如何等待工具调用并从工具结果恢复。新增一个循环特例会重复这一异步形态,并迫使每个循环实现都了解一个 UI 关注点。 + +## 后果 + +ACP elicitation 目前在 SDK 中标记为 unstable。回退仍然是结构化的:如果客户端未实现它,工具返回 `ASK_FAILED` 而非挂起。后续 ACP 稳定化可能重命名或重塑该方法;该迁移应留在 `dsh-acp` 内部,因为核心 `ctx.userInteraction` 词汇是提供方无关的。 + +该特性赋予模型一个强大的暂停原语,因此提示词引导很重要。工具描述告诉模型提问要简洁、尽可能使用选项。产品策略后续可以包装 `tools/execute` 来限制工具何时可用,但循环不应对其做特殊处理。 + +`dsh-user-interaction` 和 `dsh-tool-ask-user` 都位于 `packages/ui`,因为它们共同构成一个面向产品的人机交互能力。`agent-core` 不加载工具或 provider。`stdio-agent` 选择性加载 seam、其 readline provider 和模型侧工具。`acp-agent` 默认只保留 `userInteraction` seam/provider:ACP elicitation 支持仍取决于客户端,因此 ACP 叶子节点必须在其客户端能够完成 elicitation 请求后才有意加载模型侧工具。 + +## 测试 + +单元覆盖率固定了以下场景:provider 注册/释放、重复 provider 拒绝、provider 就绪前中止、空问题拒绝、通过 `ctx.tools.execute()` 的结构化工具错误、批量答案、多选答案、自定义答案,以及模型 schema(包括移除 `value`、`recommended`、`allow_custom` 和 `desc` 的验证)。`dsh-stdio-demo` 测试覆盖选项描述、排队请求、EOF/中止清理、无选项自由格式输入、无效选项重新提示、重复多选编号和批量问题流程。ACP bridge 测试驱动一个真实的内存 ACP 连接(使用真实的 `ask_user_question` 工具),验证选中选项、custom 覆盖 choice、多选和无选项自由格式 elicitation 路径能继续 agent loop。 diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml new file mode 100644 index 0000000000..d2c28a3946 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-29-todo-write-tool.md: 69f81cf6fd93df63ce53bb82c97dbac16dbbd486 +2026-06-29-todo-write-tool.zh.md: a687f5ab4bc5b9fcd5583ca4aac2857ab4c3f513 diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md index 126c69f1c0..69f81cf6fd 100644 --- a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md @@ -1,5 +1,7 @@ # RFC: The `todo_write` tool — model task list as event-sourced session state +English | [中文](2026-06-29-todo-write-tool.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md new file mode 100644 index 0000000000..a687f5ab4b --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md @@ -0,0 +1,64 @@ +# RFC:`todo_write` 工具——将模型任务列表建模为事件溯源的会话状态 + +Status: implemented + +[English](2026-06-29-todo-write-tool.md) | 中文 + +## 问题 + +harness 为模型提供了 bash 和 subagent 工具,但没有任何方式记录结构化的任务列表。todo 列表服务于两个同等重要的目的:引导模型规划多步骤工作并保持当前任务明确(最多一个 in_progress,有未完成工作时恰好一个),以及为人类提供实时进度清单。ACP(Agent Client Protocol)协议有原生的 `plan` sessionUpdate,编辑器(Zed)已经在渲染它,但 bridge 从未发出过。调研的每个参考编码 agent(智能体)实现(claude-code、opencode、codex、oh-my-pi、pi)都提供了某种形式的此功能;而 harness 什么都没有。 + +## 决策 + +新增一个面向模型的 `todo_write(todos: [{ content, status }])` 工具,其全量列表状态以新的 `todo/write` `SessionEventMap` 变体存在于事件溯源的会话日志上。stdio UI 和 ACP bridge 都从既有的 `session/event` 渲染——ACP bridge 将列表映射为 `plan` sessionUpdate。 + +### 全量替换,三态 status + +模型每次调用发送**完整**列表;新列表替换旧列表(回放时 last-write-wins)。这是 claude-code V1、opencode 和 codex `update_plan` 共同使用的形态,也是模型训练最多的形态——没有逐项 id,没有 delta 协议。`status` 恰好是 `pending | in_progress | completed`:与 codex `update_plan` 相同的三元组,且关键的是**与 ACP `PlanEntryStatus` 完全一致**,因此 bridge 做 1:1 映射,无损失转换。 + +### 状态在会话日志上,而非服务 + +列表以 `todo/write` 事件追加,携带完整的 `{ todos }` 快照。harness 是事件溯源的——LLM(大语言模型)历史、工具调用和轮次结构都在日志上——所以 todo 列表也在那里。这免费获得了持久性、回放和 `session/load` 重建:重新打开的会话从最后一条 `todo/write` 重新推导当前列表,ACP bridge 在加载时重新发出 `plan`,无需独立的持久化后端、无需重新注水的内存服务、无需额外接线。一个内存中的 `ctx.todos` 服务需要重新发明所有这些。 + +### 不是 surface 事件 + +`todo/write` 被刻意排除在 `SurfaceEventType` 之外。surface 是产出 LLM 消息历史(`deriveMessages()`)的投影;一次 todo write 不产生对话消息。因此它不携带 `surfaceOp`,不加入 surface 链表,不进入 `deriveMessages()`——它是持久的、可回放的 *UI* 状态,伴随对话传播但不属于对话的一部分。(开发模式的不变式仍要求它位于一个打开的轮次内,事实也确实如此:它在工具调用的 mid-step 阶段追加。) + +### priority 仅在 ACP 边界合成 + +ACP 的 `PlanEntry` 要求 `content` + `priority` + `status`,但 `TodoItem` 没有 priority——模型从不推理它。与其在 schema 中增加一个模型每次都必须提供的字段,不如让 bridge 在构建 `plan` 时为每个条目合成一个常量 `priority: 'medium'`。priority 是 ACP 协议格式(wire format)的要求,不是 harness 的概念,因此它恰好存在于需要它的边界处。 + +### 相比 claude-code V1 去掉的字段:`activeForm`、id、priority + +claude-code V1 的 item 是 `{ content, status, activeForm }`;后来(V2)增加了 id、依赖和所有权——但那只是为了支持 agent *集群*(磁盘持久化、锁保护、逐项变更)。本工具将 item 保持在最小集:`{ content, status }`。没有 `activeForm`(现在进行时标签)——UI 直接展示 `content`;没有 id——全量替换不需要稳定标识;没有 priority——见上文。每去掉一个字段,模型每次调用就少产出一项。 + +### 单一所有者——无集群机制(YAGNI) + +每个列表属于调用方 agent 会话,非 agent 调用会被拒绝。没有共享作用域、resolver 或 delta 协议。跨 agent 列表需要逐项日志 delta 和显式作用域选择,因此留作未来独立设计。 + +### 校验:低成本的中间路线 + +schema 强制 type/required/enum。在此之上,`execute` 拒绝空 `content`、重复 `content` 以及多于一个 `in_progress` 任务。claude-code 将 single-in-progress 留给 prompt;oh-my-pi 在代码中强制。我们取中间路线:强制那些使计划*连贯*的低成本不变式(无空白任务、无重复、最多一个活跃),但将排序和保持列表最新的纪律通过工具描述留给模型。被拒绝的写入返回 `isError` 结果,模型可自行修正。 + +## 为什么没有 cordis-catalog 条目 / 没有 `@mode` + +`todo/write` 是 `SessionEventMap` 的成员,不是一等的 cordis `interface Events` 事件。catalog 生成器(`scripts/gen-cordis-catalog.ts`)扫描 `interface Events` 声明;`SessionEventMap` 变体搭载既有的 `session/event` emit,不产生新的 catalog 行。因此它不携带 `@mode` 标签(生成器仅对 `interface Events` 成员要求此标签)——加上它也没有意义。 + +## 测试 + +四层,预先设计: +- **单元测试**——会话事件(append/snapshot-clone/last-write-wins/not-on-surface);工具(schema 形状、通过真实 `ctx.tools.execute` 的参数校验、值校验、事件追加与替换、非 agent 拒绝、`presentCall`、HMR 安全性);ACP `todosToPlan` 映射;stdio 渲染分支。 +- **真实 Loader 路径**——插件通过 `Loader.unwrapExports` 运行,断言命名空间导出形状存活(它有 `inject`,因此一个意外的 default 导出会在加载时崩溃——postmortem/0001)。 +- **全链路集成**——一个脚本化的 mock 模型通过真实 agent loop(智能体循环)调用 `todo_write`;`todo/write` 事件落地,第二次调用替换它。 +- **`session/load` 回放**——一条持久化的 `todo/write` 在新的 ACP bridge 加载会话时重新发出 `plan` 更新。 +- **带 key 的 e2e + 快照**——一个真实 prompt 诱导 `todo_write`;快照 golden 新增 `plan` 通知和日志事件。 + +## 曾考虑的替代方案 + +- **内存中的 `ctx.todos` 服务**——需要重新发明日志免费提供的持久性、回放和 `session/load` 重建。 +- **逐项 delta 协议**——仅在共享多所有者列表时需要,不在本次范围内;全量替换更简单且与参考实现一致。 +- **工具放在 `core/`**——`todo_write` 是注册在 `ctx.tools` 上的扩展工具,不属于主干;它与其他工具族一样放在自己的 `packages/todo/` 分组中。 + +## 后果 + +todo 列表是持久的、可回放的会话状态:一条持久化的 `todo/write` 在 `session/load` 时重新向编辑器发出 `plan` 更新,日志(而非插件内存)是唯一真源。全量替换意味着每次更新一次工具调用、last-write-wins;没有需要协调的 delta 协议。事件不进入 surface,因此 todo 更新永远不会扰动推导出的模型历史——模型只看到自己的工具调用和结果。 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml new file mode 100644 index 0000000000..5402e85e81 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-30-hook-bridges.md: 17ff57307c34121c845592efa93c723e66c98886 +2026-06-30-hook-bridges.zh.md: 2a94d5cca2f490e4aac493fe357a825ad3b4d271 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md index 2d285fb152..17ff57307c 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md @@ -1,5 +1,7 @@ # RFC: dsh-hooks-claude + dsh-hooks-codex — the Claude Code / Codex hook bridges +English | [中文](2026-06-30-hook-bridges.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md new file mode 100644 index 0000000000..2a94d5cca2 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md @@ -0,0 +1,70 @@ +# RFC:dsh-hooks-claude + dsh-hooks-codex——Claude Code / Codex 钩子桥接插件 + +Status: implemented + +[English](2026-06-30-hook-bridges.md) | 中文 + +## 问题 + +harness 的扩展面是其类型化的拦截 seam(见[拦截 seam RFC](2026-06-30-interception-seams.md)):所谓「原生钩子」不过是一个普通的 Cordis 插件,订阅 `agent/session-start`、`agent/prompt-submit`、`tools/pre-execute`、`tools/post-execute`、`agent/turn-continuation`、`subagent/start`、`subagent/end`。但用户带着**已有的** Claude Code(CC)和 Codex 钩子配置到来——一个 `hooks.json`(或设置文件中的 `hooks` 键)里满是 shell 命令钩子——并且希望它们原样运行。本 RFC 引入两个**桥接插件**,将外部 shell 钩子协议翻译到类型化 seam 上,基于共享的协议格式(wire format)库(见 [hook-protocol-lib RFC](2026-06-30-hook-protocol-lib.md))构建。 + +贯穿整个设计的定位是:**桥接是兼容性适配器,不是高级工具。**桥接能做的事(阻止工具、注入上下文、强制继续、观察 subagent),原生 Cordis 插件都能更强力地完成——有类型化返回值、完整的 `ctx`、无序列化边界。桥接存在的理由是运行外部 CC/Codex 命令钩子中被明确支持的子集。这使每个桥接保持精简:解析配置、选择匹配模式、构建每事件的 payload、调用共享库的 `runHook` + `mergeHookOutputs`,再将中性结果映射到 seam 的 Decision。各 package 的 README 记录了当前相对官方协议的不支持事件与部分字段清单。 + +## 决策 + +`packages/hooks/` 分组下两个独立插件,各自为函数/命名空间插件(`name`/`inject`/`Config`/`apply`,无 default export——见 [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md)),仅注入 `bash`: + +- **`dsh-hooks-claude`**——CC 方言。Claude Code 当前钩子点中的七个:`SessionStart`、`UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`Stop`、`SubagentStart` 和 `SubagentStop`。拥有 CC 形状的每事件 stdin payload(基础字段为 `session_id`/`cwd`/`hook_event_name`,加上每事件特有字段)、`CLAUDE_PROJECT_DIR` 环境变量加 `${CLAUDE_PLUGIN_ROOT}`/`${CLAUDE_PROJECT_DIR}` 替换,以及字面量或正则匹配模式。CC 钩子的 stdin 带有**尾随换行**。 +- **`dsh-hooks-codex`**——Codex 当前钩子点中的五个:`PreToolUse`、`PostToolUse`、`SessionStart`、`UserPromptSubmit` 和 `Stop`。使用始终为正则的匹配模式、Codex 形状的 snake_case payload(带 `turn_id`/`model`/`permission_mode` 额外字段),写入时**不带**尾随换行,不注入 Codex 插件环境变量,不做配置时占位符替换,也没有 pre-tool 审批或重写路径。工具调用的 payload 在桥接的精简 `tool_input: { command }` 形状中携带真实的 `tool_name`。 + +### 结果 → Decision 映射 + +每个桥接将共享库返回的中性 `MergedHookOutcome` 映射到 seam 的类型化 Decision: + +| Seam | CC | Codex | +|---|---|---| +| `agent/session-start`(emit) | additionalContext → `agent.inject()` | plain-stdout 输出 → additionalContext → `agent.inject()` | +| `agent/prompt-submit` | `deny`→`block`;仅上下文→delegate+fold | `block`→`block`;仅上下文→delegate+fold | +| `tools/pre-execute` | `deny`→`deny`;`ask`→`ask` | `block`→`deny`(无 allow/ask) | +| `tools/post-execute` | `deny`→`block`+feedback;仅上下文→delegate+fold | 同上 | +| `agent/turn-continuation` | 阻塞式 Stop → `continue`(reason = 下一步 steering(中途引导)) | 同上 | +| `subagent/start`(emit) | additionalContext → 注入进程内活跃子 agent;远程子 agent 没有本地注入目标 | 本桥接不支持 | +| `subagent/end`(emit) | 仅观察 | 本桥接不支持 | + +CC 桥接的 `ask` 结果是一条真正的权限路径,而非桥接的终态决策:`dsh-tools` 通过可选的[审批 seam](2026-07-06-approval-seam.md) 解析它。组合式 ACP 应答器会向拥有者编辑器会话发起提示,`allowed-once` 后继续执行;如果没有 ApprovalService 或应答器,调用以 `deny` 关闭。 + +### 上下文来源始终是插件(错标防护) + +`agent.inject()` 在缺少 `MessageSource` 时默认为 `{ kind: 'user' }`,因此每个桥接的 `inject()` 和 `HookContext` 都传入 `{ kind: 'plugin', plugin: 'hooks-claude' | 'hooks-codex' }`。单元测试覆盖率固定了最终 `context/message.source` 为插件而非用户。 + +### 添加上下文不是否决——先 delegate,再 fold + +仅含上下文的钩子必须调用 `next()` 然后将其 `additionalContext` 折入下游决策;直接返回 allow 或 accept 会绕过后续策略监听器。Post-tool 的 block 和 accept 决策都保留已添加的上下文。Prompt allow 保留上下文,而 prompt block 丢弃上下文,因为提示词从未到达模型。只有显式的钩子 denial 或 block 才会短路 waterfall(瀑布式事件)。 + +### CLAUDE_PROJECT_DIR 默认为会话工作区 + +Claude Code 始终导出 `CLAUDE_PROJECT_DIR`,常见的未修改钩子引用 `$CLAUDE_PROJECT_DIR` 来构造项目相对路径。显式的 `config.projectDir` 优先;当它被省略时(默认的 ACP 接线只配置 `configPath`),桥接将该环境变量按每次运行默认为 agent 的会话工作区——即钩子已经运行其中的 `session.header.cwd`——而不是留空。因此一个标准的项目相对钩子在默认配置下即可工作。 + +### 隔离 + +配置在加载时一次性解析;读取/解析失败时记录日志并不注册任何内容,而非崩溃启动(一个拼错的路径不得拖垮 agent)。CC 只运行 shell 形式的 `type: 'command'` 钩子;`http`、`mcp_tool`、`prompt` 和 `agent` 处理器被解析后跳过。Codex 只运行同步命令处理器,跳过 `async: true` 或非命令条目。emit 监听路径(`session-start`、`subagent/start`)以 detached 方式运行,其 `inject` 包裹在 `.catch` 中记录日志(抛异常的 inject 不得中断会话启动或循环)。 + +### 钩子的运行位置与配置来源 + +钩子在 agent 的会话工作区中运行,因此相对路径指向用户的项目。`configPath` 相对于进程启动 cwd 解析一次,适用于所有会话。按会话的项目本地发现仍推迟在 `TODO(per-session-hook-config)` 下。 + +## 推迟的兼容性缺口 + +- **工具输入重写。** CC/Codex 的 `updatedInput` 被记录日志并发出警告,但不生效——输入重写是一个推迟的一致性设计问题(见 [pre-tool-input-rewrite RFC](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)),因为预执行参数被 `tool/call` 审计、`assistant/message` 历史和 ACP/tool-bash 展示共同读取,诚实的重写是一个设计单元,而非一个字段。 +- **Stop 循环防护**(`TODO(stop-loop-guard)`)。Claude Code 提供 `stop_hook_active` 并在连续八次阻塞后覆盖钩子;Codex 提供 `stop_hook_active` 但文档中没有等效上限。两个桥接始终报告 `false`,因此一个无条件阻塞的 Stop 钩子会在每一步强制继续——钩子作者必须自行限制,直到状态追踪落地。 +- **钩子 `continue:false`(硬停止)。** 钩子可以请求终止整个运行(CC/Codex `continue:false`);共享 merge 将其折入 `MergedHookOutcome.stop`/`stopReason`,但没有桥接对其采取行动(`TODO(hook-continue-false)`)——拦截 seam 尚无「硬停止 agent」原语(Decision 阻塞/引导的是单个点,而非整个运行)。与循环防护工作一起推迟;停止请求记录在 `hook/result` 日志中,钩子在此期间保留其逐点效果(decision/上下文)。 +- **配置发现。** 路径在 `cordis.yml` 中显式指定且为进程级(见上文);完整的多层 CC/Codex 优先级遍历、按会话的项目本地发现以及信任/hash 模型均未重新实现(`TODO(per-session-hook-config)`)。 +- **Session-start / subagent-start 上下文为尽力而为(`TODO(session-start-gating)`)。** 两个钩子以 detached 方式运行于启动之外,因此其上下文在就绪时注入,但可能错过第一个请求或短命子 agent。保证首请求送达需要一个 awaited 的启动 seam。 + +## 曾考虑的替代方案 + +**同一点的钩子并发执行。** 参考引擎对同一点匹配到的钩子并发运行并折叠结果。本桥接**串行**运行它们(匹配循环内逐钩子 `await`),并以相同的最严格合并策略折叠。串行是刻意的:它使每个钩子的 `hook/invoked`/`hook/result` 对在会话日志中相邻且顺序确定,而折叠对决策是顺序无关的(`deny > ask > allow`),因此结果一致。代价是延迟(钩子 *N* 等待钩子 *N−1*)且逐钩子超时不重叠——对真实配置使用的钩子数量而言可接受;如果某天配置扇出到足以影响挂钟时间,再重新审视。 + +## 后果 + +匹配语义、退出码处理与合并优先级位于 `dsh-hook-protocol`;每个桥接只负责解析配置、构建方言 payload 和映射结果。逐文件覆盖率包含配置分支加上通过真实循环、`dsh-bash-local` 和 shell 脚本的端到端映射,同时一个真实 Loader 冒烟测试守护 package 的导出形状。原生插件绕过协议格式,直接返回类型化决策。 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml new file mode 100644 index 0000000000..22f7710469 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-30-hook-protocol-lib.md: 924c320f7ef9fdb55b20ff06f492addbf42d1720 +2026-06-30-hook-protocol-lib.zh.md: 2f1cf0f1e4c99eaf1172642475e3b9bc8c8aed39 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md index ac28345791..924c320f7e 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md @@ -1,5 +1,7 @@ # RFC: dsh-hook-protocol — the shared Claude Code / Codex hook wire-protocol core +English | [中文](2026-06-30-hook-protocol-lib.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md new file mode 100644 index 0000000000..2f1cf0f1e4 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md @@ -0,0 +1,32 @@ +# RFC:dsh-hook-protocol——Claude Code / Codex 钩子协议格式的共享核心库 + +[English](2026-06-30-hook-protocol-lib.md) | 中文 + +Status: implemented + +## 问题 + +钩子子系统提供两个桥接插件:一个运行用户已有的 Claude Code(CC)钩子,一个运行 Codex 钩子。研究参考实现(`~/repos/refs/claude-code`、`~/repos/refs/codex`)后发现一个决定性事实:**Codex 有意重新实现了 CC 钩子协议的一个子集。**它的引擎读取相同的 `hooks.json`,使用相同的 matcher-group 形状、相同的 exit-code/structured-stdout 输出契约,以及相同的 command-hook 执行模型——Codex 的源码甚至以 Claude 的引擎命名自己的引擎,并在注释中标注了「有意偏离」之处。因此两个桥接插件如果各自实现,将重复协议的大部分内容。 + +本 RFC 引入 `@deepseek-ai/dsh-hook-protocol`,一个**库**(不是插件——它不注册也不注入任何东西),持有两个桥接插件共同依赖的、真正相同的原语。共享与方言各自持有的部分之间的切分,是本设计的重心所在。 + +## 决策 + +在 `packages/hooks/` 下新建一个组,`hook-protocol` 作为纯库存在。它拥有四个原语族以及 `hook/*` 会话事件;每个桥接插件(`dsh-hooks-claude`、`dsh-hooks-codex`)拥有真正不同的部分。 + +**共享(本库):** +- **Matcher**——`matchesMatcher(pattern, query, mode)`。两种方言唯一不同的轴被收敛到 `mode` 参数:`claude` 将纯 `[A-Za-z0-9_|]+` 模式视为字面量(管道符 = 精确匹配的交替),其他视为正则;`codex` 始终为无锚定正则。缺失/`''`/`'*'` 时匹配全部;无效正则匹配空集(绝不向循环抛出异常)。 +- **Execution**——`runHook(bash, hook, options)`。通过 `ctx.bash` seam 而非自建 spawn 运行 command hook:执行器已经提供了经过清理但可覆盖的 env、进程组 kill 和超时——正是协议所需的能力,而 `dsh-bash` 的 `stdin`/`env` 字段(正是为此添加的)是进程内桥接插件被允许使用的受信插件接口。它将桥接插件构建的 payload 序列化到 stdin(CC 时追加尾部换行),尊重钩子的 `timeoutSec`(否则使用 `DEFAULT_HOOK_TIMEOUT_MS`,即两种方言共享的 10 分钟参考默认值),且从不抛出异常(执行器的 rejection 变为 non-blocking-error 的 `HookOutput`)。 +- **Decode**——`parseHookOutput(exit, stdout, stderr)`,exit-code + structured-stdout 编解码器,产出方言无关的 `HookOutput`。Exit `0` → 宽松 JSON 解析 stdout;exit `2` → blocking error,`stderr` 作为原因(以 `decision: 'block'` 呈现,调用方无需单独的 exit-code 分支);其他 → non-blocking error。解析 CC structured-stdout 中在某条路径上有消费方的字段(`continue`/`stopReason`/`decision`/`hookSpecificOutput.{permissionDecision,additionalContext,updatedInput}`/`systemMessage`);桥接插件只尊重对其方言有意义的子集。在任何路径上都没有消费方的字段不予解析(CC 的 `suppressOutput`——钩子 stdout 在此从不进入 transcript,因此没有什么可抑制的;见 [tighten-hook-protocol-contract RFC](../simplification/2026-07-04-tighten-hook-protocol-contract.md))。 +- **Merge**——`mergeHookOutputs(outputs)`,将多个匹配钩子的输出折叠为一个最严格的 `MergedHookOutcome`:权限优先级 **deny > ask > allow**,halt 在首个 `continue:false` 时粘滞,block 原因以 `\n\n` 拼接,context/system-messages 按序累积。 +- **`hook/*` 会话事件**——`hook/invoked` / `hook/result`,通过 declaration-merge 加入 `SessionEventMap`(仅记录日志,类似 `compact/*`——不是 `SurfaceEventType`),附带 `appendHookInvoked`/`appendHookResult` 辅助函数,确保 invoked/result 配对和轮次包含关系在各桥接插件间保持一致。`appendHookResult` 还拥有持久化记录的语义——决策字符串(钩子解析出的 decision,否则在 `continue:false` 时为 `'stop'`,否则为 `'pass'`)和 500 字符的 `stderrSummary` 截断均从此处的 `HookOutput` 导出,而非在各桥接插件中分别实现。 + +**方言各自持有(桥接插件):**构建每个事件的 stdin payload(CC 的 base + per-event 字段集 vs Codex 的 snake_case 加 `turn_id`/`model` 额外字段)、方言的 env 与 `${CLAUDE_PLUGIN_ROOT}` 替换(CC)vs 无替换(Codex),以及将方言无关的 `HookOutput`/`MergedHookOutcome` 映射到 harness 的 seam 特定类型化 Decision(`PreToolDecision`、`PromptDecision`、`ContinuationDecision`、`PostToolDecision`)。 + +## 曾考虑的替代方案 + +**一个参数化引擎。** 否决,因为 payload 构建和决策映射在方言间确实不同。Matcher、编解码器、执行、合并规则和事件保持共享;各桥接插件保留自己的 payload 和映射,使其协议格式行为在代码中可就地阅读。 + +## 后果 + +每个桥接插件解析配置、构建方言 payload、调用共享的 runner 和 merge 逻辑、映射决策、追加 `hook/*` 事件。协议测试覆盖每种 matcher 模式、exit-code 与编解码器字段、runner 管道、merge 优先级和审计辅助函数,逐文件 100% 覆盖率;桥接插件测试验证库的真实加载路径。`updatedInput` 已被解析,但在 [input-rewrite 提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)落地之前仅记录日志并发出警告。 diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml new file mode 100644 index 0000000000..b40109802a --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-30-interception-seams.md: fb8efe1e1c2057db13b440881f110ca7f579a81e +2026-06-30-interception-seams.zh.md: b22b3d61bd14b6708e5a063f02537e981fead0fc diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.md b/docs/rfc/implemented/feature/2026-06-30-interception-seams.md index ea371ad55a..fb8efe1e1c 100644 --- a/docs/rfc/implemented/feature/2026-06-30-interception-seams.md +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.md @@ -1,5 +1,7 @@ # RFC: Interception seams — the typed-Decision surface a hook programs against +English | [中文](2026-06-30-interception-seams.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md b/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md new file mode 100644 index 0000000000..b22b3d61bd --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md @@ -0,0 +1,60 @@ +# RFC:拦截 seam——钩子编程所面对的类型化 Decision 表面 + +Status: implemented + +[English](2026-06-30-interception-seams.md) | 中文 + +## 问题 + +harness 需要一套钩子子系统:用户在生命周期节点扩展或拦截 agent(智能体),方式类似 Claude Code(CC)和 Codex。驱动本设计的关键重构是:**"原生钩子"不是一个 package**——原生钩子只是一个普通的 Cordis 插件,订阅规范的生命周期事件。因此真正的产品是一个*强大、类型完备的规范事件表面*;CC/Codex 桥接(`dsh-hooks-claude` / `dsh-hooks-codex` 包)只是把外部 shell-hook 协议映射到同一表面的翻译层。桥接能做的事,普通插件都能直接做——而且更强大(没有序列化边界、完整的 `ctx`、类型化的返回值)。 + +这个表面需要为以下各阶段提供不同的契约:逐 prompt 策略(CC 的 `UserPromptSubmit`)、会话启动观测(CC 的 `SessionStart`)、工具执行前策略、环绕调度控制、工具执行后变换、最终结果观测,以及附带面向模型原因的继续。如果把这些阶段混为一谈,插件就会获得不需要的修改通道,终态也会依赖监听器顺序。[事件域语义 RFC](../architecture/2026-06-30-event-domain-semantics.md) 提供了三域规则和类型化 Decision 惯用法;本 RFC 将它们应用到生命周期 seam 上。 + +## 决策 + +规范表面将可变换策略、环绕调度控制与仅观测通知分离。策略 waterfall(瀑布式事件)返回小型的、seam 专属的**类型化 Decision 联合类型**;包装层返回归一化结果;通知接收不可变快照,不能影响结果。覆盖范围包括本次纳入的钩子点(`session-start`、`prompt-submit`、`pre-tool`、`post-tool`、通过 continuation 实现的 `stop`),同时将非钩子的执行策略留给独立组合。 + +**Agent 事件**(`dsh-agent`): +- `agent/session-start(agent, source)`——emit,在第 1 轮次之前触发一次,携带 `SessionStartSource`(`startup` 表示全新/fork 创建,`resume` 表示重新加载的持久化会话;`clear`/`compact` 保留)。纯通知——它**不能**阻塞启动(这是有意的缺口:桥接用于记录/注入,不用于拦截启动)。监听器通过 `agent.inject()` 注入上下文。 +- `agent/prompt-submit(agent, content, source, next) → PromptDecision`——waterfall,在已开启的轮次内、`user/message` 追加之前,对每条出队的排队消息触发。`allow`(可选地重写 prompt `content` 或附加 `additionalContext`)或 `block`(丢弃该 prompt;循环在其位置追加一条持久的 `prompt/blocked`——见下方调度说明)。 + +**`agent/turn-continuation`** 接收并返回一个 `ContinuationDecision`。`{action:'continue', reason?}` 可携带面向模型的上下文,记录为同一轮次内的下一步 steering(中途引导)——与 `/goal` step-end-steer 模式互为类型化的孪生。 + +### 工具流水线为每个阶段赋予一种权限 + +每次调用遵循 `tools/pre-execute` → guards → `tools/execute` → dispatch → `tools/post-execute` → `tools/result`。注册表快照调用方输入、物化并冻结参数、分配不透明 token。嵌套调用只携带父 token。身份始终不可变;只有 `signal` 可在环绕调度时改变。日志、UI 和工具体因此对「运行了什么」达成一致。 + +- **`tools/pre-execute`** 是可扩展的 waterfall 门禁。其 `PreToolDecision` 允许、拒绝或询问。拒绝跳过 `tools/execute` 和核心调度。询问通过可选的审批 seam 解析:只有 `allowed-once` 继续通过 guards 和调度;拒绝、取消、通道不可用、审批服务缺失或无 agent 调用均归一化为拒绝。每种结果仍会到达后策略和最终观测者。 +- **`ctx.tools.guard()`** 在整个 pre-execute waterfall 之后安装同步的作用域感知策略。guard 可以拒绝或弃权,永远不能强制允许,因此监听器顺序无法复活一个被最终不变式禁止的操作。 +- **`tools/execute`** 是用于超时、重试和指标插件的环绕调度 waterfall。包装层通过 `next()` 委托给核心调度,在此之前只能添加、替换或移除 `exec.signal`,并接收已归一化的抛出或未知工具结果;返回自己的有效结果可短路调度。 +- **`tools/post-execute`** 是检查/变换 waterfall。其 `PostToolDecision` 接受、以反馈阻止、可选地替换内容,或附加 `additionalContext`;对结果的就地修改不是变换通道,因为注册表从受保护的快照加上返回的 decision 重建结果。 +- **`tools/result`** 是每次变换、无损 JSON 物化和外层错误边界之后的同步受限通知。它接收相同的冻结执行身份和权威结果的不可变快照;观测者失败按监听器隔离,不能改变或拒绝 `ToolRegistry.execute()` 返回的结果。 + +核心调度和工具体位于归一化边界内,因此工具、监听器、格式错误的结果、非 JSON 结果和身份形状失败都解析为 JSON 安全的 `isError` 结果,而非逃逸出轮次。post-execute 监听器因此可以检查抛出异常的工具,最终观测者看到的恰好是调用方收到的、会话日志可持久化的内容。 + +**`TurnEndReason.rejected`**(`dsh-session`):整个 prompt 批次被 `prompt-submit` 阻止的轮次。 + +### 三个承重的循环决策 + +1. **在 prompt 策略之前开启轮次。** 被完全阻止的批次成为零步骤的 `rejected` 轮次,保持封闭性并为 ACP 提供持久的终止事件。每次否决还记录 `prompt/blocked`(含原始 prompt 和原因),因此混合批次保留了被阻止的输入。允许的 `additionalContext` 注入到已开启的轮次中。 + +2. **Post-tool `additionalContext` 被缓冲,在所有 `tool/result` 之后追加。** `content`/`feedback` 塑造 `execute()` 返回的结果,但 `additionalContext` 是一条**独立的** `context/message`,而单个步骤可携带多个工具调用。如果在每个结果之后立即追加上下文,会产生 `result(c1) → context → result(c2)` 的交错,破坏工具调用/结果的邻接性。因此 `execute()` 将 `additionalContext` 暴露在其 `ToolExecutionResult` 上,循环为该步骤缓冲每次调用的上下文,仅在所有 `tool/result` 追加完毕后才以 `context/message` 形式追加。 + +3. **强制 `continue` 的 `reason` 通过 steering 通道入队**,使下一步骤的循环顶部 drain 将其记录为继续轮次的 steering——同一轮次内的下一*步骤* steering,而非下一*轮次*的 prompt(与既有的 `hasSteering` force-continue 覆盖一致)。 + +### Pre-tool 输入重写是一个独立的一致性决策 + +`PreToolDecision` 不能重写参数。历史和审计调用在执行前记录,ACP 展示读取相同的输入,因此注册表在策略之前封存参数。有效的重写必须在身份创建之前更新历史、审计、展示和执行;该契约属于[输入重写提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)。 + +### 边界 + +seam 包**不**声明 `hook/*` 会话事件(持久的钩子调用日志);那些属于 `dsh-hook-protocol`,因为原生插件使用类型化 decision 而无需外部钩子日志。原生插件集成测试(`packages/core/agent-loop/tests/interception.spec.ts`)通过真实循环组合这些 seam,不涉及 `hook/*` 协议。压缩(`PreCompact`/`PostCompact`)、Notification 和 Codex `PermissionRequest` 不在本决策范围内。[审批 seam](2026-07-06-approval-seam.md) 通过 `ctx.approval` 解析 `ask` decision,而终止的单调停止由 `agent/turn-stop` 独立负责。 + +## 曾考虑的替代方案 + +- **将 pre-tool 输入重写作为本 seam 集的一部分交付**——推迟,视为过度扩展信号;上文已阐述一致性问题(审计、历史和展示都读取执行前记录的 `tool/call.arguments`),[pre-tool 输入重写提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)负责该设计。 +- **将持久的 `hook/*` SessionEvent 与 seam 一起声明**——否决:原生插件使用类型化 Decision 而完全不需要钩子日志(工作示例已证明),因此持久日志属于[钩子协议库](2026-06-30-hook-protocol-lib.md),而非 seam 表面。 + +## 后果 + +规范的拦截表面实现了统一类型化,同时不给每个扩展相同的权力:钩子返回 decision,执行包装层做包装,终止 guard 只能拒绝,最终观测者只能观测。循环负责 session-start、prompt-submit、post-tool 上下文缓冲和 continuation;`dsh-tools` 负责身份封存和五阶段执行流水线。它们的契约记录在 [architecture.md](../../../architecture.md)、package README、[核心拦截 decision](../../../core-data-structures/core.md#interception-decisions) 和[工具结构](../../../core-data-structures/tools.md)中。ACP 桥接将 `rejected` 轮次映射为其 `cancelled` 编解码值,而钩子驱动的快照端到端验证可观测的桥接行为。 diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml new file mode 100644 index 0000000000..03da25497d --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-30-session-store-fork-api.md: 4bf5c3fe43821570fd947034358e54d0a0a602f9 +2026-06-30-session-store-fork-api.zh.md: 3dd15f5beb095fecb7fdaa7d80abcf4b99c07920 diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md index 8d8813563b..4bf5c3fe43 100644 --- a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md @@ -1,5 +1,7 @@ # RFC: SessionStore fork API +English | [中文](2026-06-30-session-store-fork-api.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md new file mode 100644 index 0000000000..3dd15f5beb --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md @@ -0,0 +1,43 @@ +# RFC:SessionStore fork API + +Status: implemented + +[English](2026-06-30-session-store-fork-api.md) | 中文 + +## 问题 + +事件溯源的会话日志已经具备 fork 所需的原语:创建一个新会话并带上种子事件前缀,然后像回放一样从该种子日志推导模型历史。这个原语有意保持底层:`ctx.sessions.create(id, { seed, meta })` 接受任何合法的种子,但普通的活跃会话分支需要围绕以下问题制定策略:哪些前缀可以复制、子会话打上什么元数据、错误如何分类。 + +语义风险在于 fork 边界。一个合法的用户可见 fork 种子必须是连续的且被轮次封闭。如果在一个活跃轮次内部 fork,会复制一个未关闭的 `turn/start`,可能还有未关闭的 `step/start`,以及悬空的工具调用。这违反了轮次封闭性与 provider-transcript 不变式,并且会创建一段误导性的子会话历史——看起来像是参与了父会话中一个未完成的轮次。现有的 [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 有意解决的是另一个问题:工具触发的 subagent fork 通常发生在父轮次尚未关闭时,因此 `dsh-subagent-fork` 会将种子裁剪到父会话最后一个已完成轮次的前缀。通用的会话 fork 不应静默裁剪;它应当要么在请求的边界处 fork,要么拒绝。 + +## 决策 + +`dsh-session` 直接在 `ctx.sessions` 上拥有普通活跃会话的 fork 能力。没有独立的 `dsh-session-fork` 包(package),也没有 `ctx.sessionFork` 服务:该 API 没有独立的后端、事件词汇、生命周期或持久化行为,所有持久性工作都委托给现有的会话存储与持久化后端。 + +存储暴露一个操作: + +```ts ignore-check +type SessionForkSource = Session | SessionId + +class SessionStore extends Service { + fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Session +} +``` + +`boundary` 是要复制到的源事件 `seq`(含该序号)。省略时默认为源会话当前的最后一个事件;对空源会话省略 `boundary` 会创建一个空的子会话。fork 专有的校验只检查请求的边界是否存在且为 `turn/end`。选定的前缀随后被深拷贝到子会话的种子中。子会话继承源会话的 `cwd`,将 `parentSession` 标记为源会话 id,并将 `seedLength` 设为复制的前缀长度。省略 `childSessionId` 时,`SessionStore` 使用其现有的 id 策略生成一个。 + +空前缀可以 fork;任何非空边界必须是一个安全的、已存在的、位于 `turn/end` 处的序号,无论结束原因是什么。类型化的错误区分源不存在、对象陈旧、子会话 id 重复和边界无效。更广泛的日志校验与崩溃恢复仍由其现有的负责方处理。 + +## 曾考虑的替代方案 + +**独立的 `ctx.sessionFork` 服务。** 这是第一版实现,但评审表明它过度套用了能力 seam 模式。代码没有可替换的后端、没有额外的事件面、没有独立的所有权生命周期,也没有超出 `ctx.sessions.create({ seed, meta })` 的持久化行为。保留独立包会迫使调用方发现并安装第二个服务,仅仅为了在会话存储原语之上执行策略。 + +**两个函数:`snapshot()` 加 `fork()`。** 这保留了可复用的种子/元数据计算,但唯一支持的消费方会立即创建会话。它还让接口感觉比用户实际需要的具体操作更抽象。单一的 `fork()` 加显式 `boundary` 保持了 API 的直接性,同时仍支持对先前时间点的 fork。 + +**静默裁剪未关闭的轮次到最后一个已完成边界。** 这对 `dsh-subagent-fork` 是正确的,因为委托通常在父轮次尚未关闭时开始,子会话应只继承已完成的前缀。但对普通的用户/会话分支来说是错误的,因为它隐藏了请求的 fork 点实际上不是合法边界这一事实,并静默丢弃了父轮次的尾部。 + +## 后果 + +公开接口保持小巧且易于发现:活跃会话分支是 `ctx.sessions` 的一部分,紧邻 `create({ seed })`,而非一个独立服务或两步辅助函数对。持久化继续通过现有的 `session/created` 和 `session/flush` 行为工作:fork 出的子会话以种子事件开始生命,因此现有后端只需持久化一次该种子,并在头部保留 `parentSession` / `seedLength`。 + +v1 范围仍排除 ACP `session/fork`、对未加载的已持久化会话的 fork、面向模型的工具,以及 subagent 重构。如果未来添加 ACP 方法,应在具备 transcript(文本记录)/快照覆盖后才广播该能力;本 RFC 不添加面向编辑器的更新,因此当前不需要 ACP 快照。fork 子会话的回放仍由现有的[种子边界测试 RFC](../../implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md) 覆盖,而本 API 获得专注的 `dsh-session` 单元测试加 JSONL 持久化覆盖。 diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml new file mode 100644 index 0000000000..085f5d2c5b --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-30-subagent-observe-enrich.md: b48a1fff32130345e669a3b3b905c4fda987e41e +2026-06-30-subagent-observe-enrich.zh.md: 59dc555ce4acff30f4ba0b5929b605dc5252fe38 diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md index aa853edd24..b48a1fff32 100644 --- a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md @@ -1,5 +1,7 @@ # RFC: Subagent lifecycle enrichment — lastAssistantMessage (observe-only) +English | [中文](2026-06-30-subagent-observe-enrich.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md new file mode 100644 index 0000000000..59dc555ce4 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md @@ -0,0 +1,31 @@ +# RFC:Subagent 生命周期充实——lastAssistantMessage(仅观测) + +Status: implemented + +[English](2026-06-30-subagent-observe-enrich.md) | 中文 + +## 问题 + +钩子子系统([拦截 seam RFC](2026-06-30-interception-seams.md))允许插件在生命周期节点观测和门控 agent(智能体)。Claude Code 和 Codex 都暴露了 **SubagentStart / SubagentStop** 钩子,且 CC 的钩子携带 subagent 的最终消息。harness 已经发出 `subagent/start` 和 `subagent/end` 生命周期事件([subagent 能力 seam](2026-06-21-subagent-capability-seam.md)),但其载荷极为精简(`provider`、`id`,以及 end 时的 `stopReason`)——不足以让钩子桥接层在不另行访问活跃运行的情况下报告 subagent 产出了什么。 + +本 RFC 充实 end 载荷。它刻意限定为**仅观测**:不改变控制流,不引入 waterfall(瀑布式事件)。影响运行的 subagent-stop 决策(续行、注入改变运行的内容)属于另一项更大的重新设计,不在本 RFC 范围内。 + +## 决策 + +**在 `SubagentRunEndInfo` 中添加 `lastAssistantMessage`——子 agent 的最终输出。** 在正常结算路径上,它是只读的类型化 `SubagentResult.output`,观测者无需持有运行即可看到子 agent 的产出。在基础设施拒绝、不存在 `SubagentResult` 的情况下,该字段缺失,事件报告 `stopReason: 'error'`。提供方与监听者是受信任的同进程协作者,遵守借用不可变载荷的契约。 + +两个事件仍为普通 **`emit`**。异步的 `SubagentService.start()` 将结果观测附加到就绪的提供方运行上,发出 `subagent/start`,然后返回该运行;因此进程内监听者可以通过 `ctx.agents.get(info.id)` 访问已发布的子 agent,而远程提供方无需在本地注册表中有条目。提供方启动被拒绝时不发出任何事件。回调保持仅观测,逐监听者隔离确保一个坏订阅者不会阻塞活跃运行或饿死后续监听者。 + +## 曾考虑的替代方案 + +**`agentType` subagent 类别标签**(CC 的 `subagent_type` 在 harness 中的对应物)放在请求和两个生命周期载荷上——早期草案曾包含它;评审中移除,因为它是 Claude Code 的概念,不适合我们自己的 seam(这里没有任何代码解释它,唯一的消费方是 CC 方言桥接层)。CC 桥接层改为向 Claude Code 自身的 SubagentStart/Stop `agent_type` 匹配器喂入其默认值 `"general-purpose"`,因此本 RFC 只交付一项充实:`lastAssistantMessage`。 + +**控制流式 `subagent/end`**——推迟;见下文。 + +## 为何仅观测,以及推迟了什么 + +控制流式 `subagent/end`(一个被 await 的 waterfall,返回停止/继续决策,与其他拦截 seam 一致)需要:将 `subagent/end` 从 emit 改为 waterfall、重构 `SubagentService.start` 使其在结算前 await 监听者、在进程内提供方中实现 `resume` 能力以便「继续」能真正重新运行子 agent。这属于[能力 seam RFC](2026-06-21-subagent-capability-seam.md) 已推迟的后台/steering(中途引导)subagent 重新设计(同一项重新设计还将统一 subagent 与 bash 之间的长时间运行工具处理)。本 RFC 交付钩子桥接层当前所需的仅观测充实;`FIXME(subagent-continuation)` / `TODO` 锚点标记了控制流版本在该重新设计发生时将落地的位置。 + +## 后果 + +钩子桥接层(或原生插件)现在可以通过订阅既有 emit 将子 agent 的 `lastAssistantMessage` 转发给 SubagentStop 处理器——无需新的控制流接口。词汇新增记录在 [docs/core-data-structures/subagent.md](../../../core-data-structures/subagent.md)(事件行文部分)和两个 subagent README 中;catalog 已重新生成。生产行为无变化——事件的触发方式与之前完全相同,end 载荷多了一个(可选的)字段——因此不需要快照或 e2e 测试变更。 diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml new file mode 100644 index 0000000000..04a6289216 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-05-dynamic-workflows.md: 67ceebf7017f197bd800fd339b575390b3b936c1 +2026-07-05-dynamic-workflows.zh.md: 0ea8e88bfa750a9bb253c7dd3061766fe15d3630 diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md index 6302584103..67ceebf701 100644 --- a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md @@ -1,5 +1,7 @@ # RFC: Dynamic workflows — a script-driven multi-agent orchestration seam +English | [中文](2026-07-05-dynamic-workflows.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md new file mode 100644 index 0000000000..0ea8e88bfa --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md @@ -0,0 +1,80 @@ +# RFC:动态工作流——脚本驱动的多 agent 编排 seam + +Status: implemented + +[English](2026-07-05-dynamic-workflows.md) | 中文 + +## 问题 + +harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`),但需要扇出到多个独立片段的工作——跨多文件审计、迁移、多角度调研、对抗式验证——迫使模型逐轮次编排:每个中间结果都落入父上下文,计划没有持久存放处,每一步的协调都要消耗一次模型往返。Claude Code 以[动态工作流](https://code.claude.com/docs/en/workflows)的形式提供这一能力:模型编写一段 JavaScript 编排脚本,运行时执行它,由脚本(而非对话)持有循环、分支和中间结果。 + +## 决策 + +在 `packages/workflow/` 下以 bash seam 的形态(接口/实现/消费方)提供一组工作流能力,加上 subagent seam 上它所需的结构化输出基础。 + +### 脚本契约(兼容 Claude Code) + +一次工作流调用包含 JSON `meta`(`name`、`description`,以及可选的 `whenToUse`/`phases`)和一段支持顶层 `await` 并返回 JSON 值的 JavaScript `script` 正文。元数据作为数据校验,从不被求值。正文接收 `agent(prompt, options)`、`parallel(thunks)`、`pipeline(items, ...stages)`、`phase(title)`、`log(message)` 和 `args`。pipeline 各阶段接收 `(prev, item, index)`,阶段间无屏障;失败的子 agent 和普通阶段错误将受影响的 item 解析为 `null` 并跳过其剩余阶段。Claude Code 的确定性限制通过 journaling 延后处理,因此兼容的脚本正文在将 meta 头移入参数后,可以使用时钟和随机数。 + +与 Claude Code 的一处刻意**偏离**:钩子误用——未知或延后的选项(`effort`/`isolation`/`agentType`)、格式错误的参数、超出支持子集的 schema、触发上限、seam 启动失败——抛出 `fatal: true` 的 `WorkflowError`,组合器对 fatal 错误**重新抛出**而非将 item 置为 null。如果不这样做,一个拼错的选项会溶解为与子 agent 失败无法区分的 `null`——正是本仓库禁止的「接受后静默忽略」失败模式。一处**新增**:工具的 `args` 参数是 JSON 对象(裸列表会被包装为一个字段),以保持协议格式(wire format)的诚实。 + +### seam(dsh-workflow) + +`ctx.workflows` 是 bash 形态的抽象 `WorkflowService`:每个上下文一个引擎,无命名提供方注册表(引擎是部署级替换,不是共存者)。`start(request)` 对无法启动的脚本同步抛出异常;返回的 `WorkflowRun` 的 `result` 永不 reject(失败解析为 `stopReason: 'error' | 'cancelled'`)。`workflow/*` 事件是仅供观察的 emit,携带数据快照(id + meta;`workflow/end` 不含 result 值),按监听器隔离,与 `subagent/start`/`subagent/end` 对称——控制权留在 run 的持有者手中。词汇细节见 [core-data-structures/workflow.md](../../../core-data-structures/workflow.md)。 + +### 引擎(dsh-workflow-workerthread):每次运行一个 worker 线程 + +**信任前提**:工作流脚本与模型的 bash 访问享有相同信任级别。引擎约束有 bug 的脚本,保证 result 必定 settle、值 JSON 安全、取消后静默;它不防御恶意代码。vm 上下文和 worker 线程不是安全边界:脚本可以逃逸到具有进程级权限的 Node API。沙箱化需要在此 seam 之后放置一个独立进程或 isolated-vm 引擎。 + +**为何选择 `node:worker_threads`**:每次运行获得一个非池化 worker。vm 上下文限制了文档化的脚本表面,而 message-port RPC 将 `agent()` 桥接到宿主侧的子循环。worker 防止脚本的同步工作阻塞宿主,提供序列化边界,并允许取消后强制终止。`isolated-vm` 因其维护状态和部署要求被否决。 + +宿主在发布前校验元数据并解析正文。私有枚举键的 payload map 定义协议格式;待启动记录、已发布的子记录、单一取消信号、worker 死亡回收、result 优先级和 dispose 静默在协议两侧维持 subagent run 契约。[agent-scope runtime-design RFC](../architecture/2026-07-12-agent-scope-runtime-design.md#workflow-children-are-pending-starts-or-published-records) 拥有这些竞态算法。 + +引擎暴露一条进程内 `MessageChannel` 测试路径,因为主进程 V8 覆盖率无法观测 worker 执行。 + +**Meta 是数据**:经 schema 校验的 `meta` 字段以 JSON 形式到达 seam,仅做形状校验。宿主从不对元数据字面量求值——否则脚本控制的访问器会在 worker 隔离之外运行。 + +**值边界**:`materializeFromRealm` 复制出站值,拒绝函数、symbol、嵌套 `undefined`、异域原型、循环引用、稀疏数组和非有限数。数据属性复制使 `"__proto__"` 安全;getter 正常读取,抛出异常的 getter 会大声失败。`args` 通过 `workerData` 传入,暴露前再次克隆。realm 函数被调用而非复制,抛出的值使用全量渲染器以确保 `result` 不会 reject。钩子错误是宿主 realm 的 `WorkflowError`,因此脚本按 `name` 或 `code` 分支而非 `instanceof Error`,如引擎 README 所述。并发、total-agent、item、超时和 grace 限制均为经校验的配置。 + +### 消费方(dsh-tool-workflow) + +一个 `workflow` 工具,镜像 `dsh-tool-subagent` 的同步形态:启动、等待、`try/finally` dispose、abort 桥接 `exec.signal`、非 `completed` → `isError`。渲染意图:一张以调用的 `meta.name` 参数为标题的 `generic` 卡片(展示是参数的纯函数)。工具描述即面向模型的编写规范。使用策略作为工具自身的 `tool:<toolName>` prompt 段随工具一起交付(显式请求才使用的指导——工具指导存在于工具插件中,从不放在部署 persona 里);harness 没有 ultracode 风格的 effort 门控。 + +### 基础:subagent seam 上的结构化输出 + +`SubagentStartRequest.outputSchema` 由 `dsh-subagent-inprocess` 为两个进程内后端实现。每个结构化子 agent 在 `child.ctx` 上获得自己的作用域捕获工具、指令和强制注册;并发子 agent 可以使用不同 schema 而不共享可变策略,dispose 子 agent 时整个附件被移除。 + +输出 schema 使一次 schema 有效的已提交捕获成为子 agent 成功完成的必要条件。作用域运行时呈现捕获工具和指令,仅提交成功的最终结果(包括 SDK 调用的外层 `run_code` 结果),在捕获进入 pending 状态后拒绝后续副作用,并在提交后不再请求模型步骤即停止子 agent。校验失败仍为可重试的工具错误;干净完成但没有已提交捕获的情况 settle 为错误。 + +`StructuredOutputSchema` 是 `dsh-tools` 中可强制执行的原始 JSON-Schema 子集(单字符串 `type`、`properties`/`required`/`additionalProperties`、`items`、标量 `enum`/`const`),不支持的关键字会大声失败,因为该协议数据会逐字成为捕获工具的 parameters。[agent-scope runtime-design RFC](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes) 拥有组装、提交、守卫和终止停止的正确性算法。 + +## 测试 + +worker 侧逻辑通过进程内 `MessageChannel` 运行,以便 V8 覆盖率能度量它。单元测试覆盖脚本辅助函数、fatal 与 nullable 失败、JSON 边界、上限、取消、子 agent 所有权和通过真实循环的结构化输出。built-bin 冒烟测试在纯 Node 下运行单独打包的 `lib/worker.cjs`,带 key 的 e2e 驱动真实子 agent,面向模型的工作流行为通过其所属示例进行快照覆盖。 + +## 延后(本轮明确的非目标) + +- **后台收集**(启动工具 → run id → 完成通知 → 收集),与 bash/subagent 后台统一一起设计。 +- **Journaling + 恢复**(`resumeFromRunId`、缓存的 agent() 前缀):实现它会将 Claude Code 的确定性禁令作为脚本契约收紧重新引入(脚本今天可以读取时钟)。 +- **保存/打包的工作流**(`.deepseek/workflows/` 注册表、斜杠命令界面)和**脚本持久化到 run 目录**(tool-call 事件已经持久记录了脚本)。 +- **嵌套 `workflow()`**、**token `budget`**,以及 `effort`/`isolation`/`agentType` agent 选项(每个都以命名延后项的消息大声拒绝)。 +- **整体运行的挂钟超时**:取消总能释放调用方(result 在 grace 内 settle),因此总运行时间上限是后台重设计的策略旋钮,不是此处的正确性需求。 +- **超越 worker 线程的引擎加固**:在同一 seam 之后放置 isolated-vm 或独立进程引擎(真正的沙箱化;内存限制)。 +- **ACP 进度 UI**:基于 `workflow/*` 事件(`/workflows` 风格的视图);事件已为此存在。 +- **ACP 后端结构化输出**和 **`toolFilter`**(两者仍为能力门控 `false`)。 + +## 曾考虑的替代方案 + +- **宿主侧的恶意值防御**(无 trap 代理拒绝、从不调用访问器的描述符遍历、realm 侧预渲染抛出值、realm 构建的 promise/array/error 克隆并带结构化 fatal 识别):否决。每项防御针对的都是信任前提所接受的作者,而线程的序列化边界已经从构造上使跨 realm 值全量化。 +- **进程内 `node:vm` 执行**:机制最简——无 RPC、无线程——但 `start()` 会在脚本首段同步切片期间阻塞调用方,首个 await 之后的同步自旋无法在进程内被杀死(vm `timeout` 仅覆盖首段切片),`dispose()` 只能在宿主循环上放弃一个未 settle 的脚本。worker 线程引擎保持相同的 vm 上下文脚本表面,同时解除宿主阻塞并使终止成为现实。 +- **后台执行作为默认**(Claude Code 的形态):延后。前台同步与 `dsh-tool-subagent` 的当前形态一致,后台语义应在 bash/subagent/workflow 之间统一设计一次,而非逐工具各做一套。 +- **工作流层为 `agent({schema})` 做 JSON 解析**:在一个消费方重复 seam 的关注点,而 seam 的能力标志仍不诚实地为 `false`。 +- **Meta 嵌入脚本内作为 `export const meta = {...}`**(Claude Code 的精确格式):保持脚本自包含且 Claude Code 脚本可直接使用,但获取 meta 需要在宿主上对模型编写的文本求值。即使是空的限时 vm 上下文,在宿主读取结果对象时也无法约束脚本控制的 getter。JSON 参数消除了扫描器、求值和宿主自旋漏洞;代价是 Claude Code 脚本的 meta 头必须移入参数(正文保持可直接使用)。 +- **`SchemaSpec` 作为 outputSchema 类型**:面向作者的 DSL 无法表达以数据形式到达的内容,且无法在不丢失转换精度的情况下对其校验。 +- **schema 对象库(zod 或仓库的 schemastery)用于结构化输出子集**:schema 是协议数据——纯 JSON,跨越 `agent({schema})` 中的 vm realm 边界,逐字落入强制工具的 parameters——正是活 schema 对象无法存在的位置;在运行时消费原始 JSON Schema 需要在其上叠加第三方转换器(zod core 只输出 JSON Schema,不做反向),且会在 schemastery 的配置角色之外引入第二种 schema 语言。 +- **ajv 做值校验**:它校验完整 JSON Schema,因此子集门控——模块的真正要点,因为每个被接受的关键字都必须是 harness 所强制执行的——无论如何仍需手写;它通过 `new Function` 编译校验器;且它将成为 dsh-tools 的首个运行时依赖,所有这些只为替换约 70 行的值遍历器,而路径限定的、报告每一处违规的错误输出无论如何都是自定义的。 +- **提供方 JSON 模式代替捕获工具**:它保证有效 JSON,不保证 schema 一致性,且它与工具调用的交互尚不明确。捕获工具保留了轮次内的校验重试。提供方侧的严格工具 schema 可以在不改变本设计的前提下进一步收窄接受的子集。 + +## 后果 + +扇出计划现在存在于可重新运行的脚本中,`outputSchema` 提供权威的结构化子 agent 结果。每次运行付出 worker 启动和 message-port RPC 的开销,但宿主启动保持非阻塞,取消可以终止 worker,序列化强制执行值边界。Worker 线程不是安全边界。无效选项会失败而非退化为 Claude Code 的 `null`;消费方通过 run 句柄保持控制,观察者仅接收快照。 diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml b/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml new file mode 100644 index 0000000000..0db4b2ac5a --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-05-skill-system.md: 6cfd1f977ae5a1e1ad646a707a4201e57d46bc38 +2026-07-05-skill-system.zh.md: d491899e03854140c93f67d11e4079a5b6525185 diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.md b/docs/rfc/implemented/feature/2026-07-05-skill-system.md index 0b74aa00ae..6cfd1f977a 100644 --- a/docs/rfc/implemented/feature/2026-07-05-skill-system.md +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.md @@ -1,5 +1,7 @@ # RFC: Skill system — progressive disclosure instructions for agents +English | [中文](2026-07-05-skill-system.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md b/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md new file mode 100644 index 0000000000..d491899e03 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md @@ -0,0 +1,55 @@ +# RFC:Skill 系统——面向 agent 的渐进式指令披露 + +Status: implemented + +[English](2026-07-05-skill-system.md) | 中文 + +## 问题 + +各 agent 产品已趋同于一种 skill 模式:保持请求提示词精简,仅列出可用的指令包,待模型判定任务匹配时再加载完整正文。Codex、Claude Code、OpenCode 和 Kimi Code 在细节上各有不同,但都将发现元数据与完整指令分离,使工作区能承载可复用行为而无需在每个轮次支付全量提示词成本。 + +DeepSeek Harness 使用同一原语,让项目级的评审指导、插件编写指导和工具使用指导存放在工作区或用户的 agent 配置旁,而非硬编码进 agent loop(智能体循环)。 + +## 决策 + +`@deepseek-ai/dsh-skill` 是纯提供方注册表(`ctx.skills`),`@deepseek-ai/dsh-skill-local` 是随附的本地文件系统提供方,`@deepseek-ai/dsh-tool-skill` 负责会话前缀目录和面向模型的 loader 工具。`dsh-agent-spine-demo` 默认加载注册表、本地提供方和消费方,使 stdio 与 ACP 应用获得相同行为,同时嵌入式或远程提供方可在不改动注册表或消费方的前提下贡献 skill。其 `skills` 配置将 `registry`、`local` 和 `tool` 分支分别转发给对应的负责方。 + +提供方插件在 `apply()` 期间同步注册。提供方成员关系是直接由 effect 持有的状态:注册与 dispose(资源释放)同步地使已完成的目录失效,发现操作按需读取当前提供方映射,而非监听注册表变更事件。提供方目录从 awaited `list()` 调用返回排序后的候选项,远程提供方在此期间执行初始化、认证和发现,同时遵守查找的 abort signal。注册表校验每个候选项,对同名 skill 按 rank、提供方注册顺序和提供方内部顺序执行 first-wins 解析,然后按 skill 名称排序摘要以保证消费方获得确定性结果。注册表仅缓存已完成的目录快照,当提供方/运行时修订版本在发现过程中发生变化时重试,因此 unload 不会将一个陈旧、不可解析的 skill 冻结进会话前缀。运行时 `ctx.skills.register(...)` 仍作为嵌入式进程内 skill 的便捷方式保留,使用 project-over-user 优先级;`runtime` 作为注册表持有的提供方名称被保留。 + +本地提供方按 first-wins 的 rank 顺序扫描对 cwd 敏感的项目根目录、自定义根目录和用户根目录:项目 `.dsh`、项目 `.agents`、`customSkillDirs`、用户 `.dsh`,然后是用户 `.agents`。用户 `.dsh/skills` 扫描跳过 `.system`,使系统持有的目录不被当作普通用户内容。DeepSeek Harness 不随附内置系统 skill;嵌入式或远程提供方在配置后提供额外 skill。 + +每个 skill 是 `<name>/SKILL.md` 或带 YAML frontmatter 的 `<name>.md`。`name` 和 `description` 为必填;`whenToUse`、`disableModelInvocation` 和 `metadata` 为可选。名称使用 kebab-case。YAML frontmatter 使用 `yaml` 包解析,而非 `js-yaml` 或手写解析器:`yaml` 是本包有限 frontmatter 需求所声明的现代解析器,手写窄解析器要么拒绝用户期望能正常工作的合法 YAML,要么膨胀为一个未经评审的 YAML 子集。 + +本地 skill 的文件系统 I/O 在加载了文件系统服务时通过 `ctx.fs` 进行:项目根目录查找使用 `resolve` 和 `stat` 探测 `.git`,根目录发现使用 `listDir`,skill 读取使用 `readText`。对于未挂载 fs seam 的最小上下文,Node 文件系统仍作为回退。缺失的根目录、不可读或格式错误的 skill 文件,以及提供方 `list()` 的瞬态失败均降级为 warn-and-skip,使单个坏源不会导致每个 agent 请求失败;格式错误的候选项仍然快速失败,因为它们违反了提供方契约。 + +`dsh-tool-skill` 通过 [`agent/session-prefix`](2026-07-07-session-prefix.md) 贡献一条 user-role `<system-reminder>` 目录。目录仅包含排序后的 skill 名称和描述;不包含正文、路径、来源、提供方和路由提示。描述经过空白规范化、XML 转义,并受 `catalogDescriptionMaxLength` 限制,其默认值为 `500`,最小值为 `3`。会话前缀 seam 将仅用于请求的目录按 loop 实例冻结,并记录在请求头中,在不将其加入持久化历史的前提下保持可重建性。完整 skill 正文从不包含在目录中。 + +`skill({ name })` 工具为当前 agent cwd 加载一个完整 skill,返回包含 `<skill_content name="...">`、`<skill_resources>` 和 `<skill_instructions>` 的工具结果。`resourceBase` 提供一个目录、URL 或不透明的提供方管理的基路径,用于显式引用的脚本、参考资料和资产;资源仅按需加载,不进行目录枚举。无法解析的名称报告该 skill 未知或不再可用;无效名称和标记了 `disableModelInvocation` 的 skill 保留不同的工具错误。工具结果是面向模型的披露路径。 + +数据结构与目录/工具契约记录在 [skills.md](../../../core-data-structures/skills.md),服务签名见生成的[服务目录](../../../cordis-catalog/services.md)。 + +## 曾考虑的替代方案 + +**将完整 skill 正文注入每条系统提示词。** 否决,因为这破坏了渐进式披露,使每个请求都为可能不适用的指令付出代价。 + +**仅将 skill 暴露为斜杠命令。** 否决,因为模型主动加载才是核心能力;斜杠/ACP 命令广播不改变发现机制。 + +**将本地文件系统扫描直接放在 `ctx.skills` 内。** 否决,因为编码 agent、Web agent 和未来的插件生态需要不同的 skill 来源。提供方注册表与 subagent seam 同构:注册表负责冲突解析和消费方,实现负责加载。 + +**使用系统提示词段落。** 否决,因为渲染后的系统提示词是单一字符串,而目录是一条具有仅请求生命周期要求的 user-role `<system-reminder>` 消息。[`agent/session-prefix`](2026-07-07-session-prefix.md) 是选定的机制:它将目录置于派生历史之前,并将组合后的消息记录在请求头中。 + +**将内置 DSH 编写 skill 物化到 `~/.dsh/skills/.system`。** 否决,因为打包的 skill 不应在启动时写入用户主目录,嵌入式或远程提供方在配置后提供 skill。 + +**递归发现嵌套的 `**/SKILL.md`。** 否决。扁平文件和一级目录包已覆盖配置的根目录,同时保持重复处理和目录顺序易于推理。 + +**手写 frontmatter 解析器。** 否决,因为已接受的 schema 包含一个开放的 `metadata` 对象。窄解析器要么拒绝用户期望能正常工作的合法 YAML,要么膨胀为一个未经评审的 YAML 子集。 + +## 后果 + +agent-core 主干包含一个会话前缀贡献者、一个本地提供方和一个面向模型的工具。skill 发现对 cwd 敏感,因此以不同会话 cwd 值创建 agent 的调用方可以按设计观察到不同的项目 skill 覆盖。 + +目录在固定的根目录集和运行时注册修订版本下是确定性的,但不监听磁盘变化;发现结果被缓存,直到运行时注册使缓存失效或进程重启。 + +## 延后 + +fork 式 skill 上下文(`context: fork`)、直接用户/斜杠调用(`user-invocable`)、参数声明与提示(`arguments` 和 `argument-hint`),以及逐 skill 的工具约束(`allowed-tools` 和 `disallowed-tools`)不在已交付的契约范围内。注册表、本地提供方和面向模型的工具不解析、不广播、不强制执行这些字段。 diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml new file mode 100644 index 0000000000..2e89e359db --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-06-approval-seam.md: 3ef51c31216bf9f0c5d945748ab3f901ec82147c +2026-07-06-approval-seam.zh.md: cec1692d509a7c9a0680773fbdbbb18e1c90ab8c diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.md b/docs/rfc/implemented/feature/2026-07-06-approval-seam.md index 4ac066e393..3ef51c3121 100644 --- a/docs/rfc/implemented/feature/2026-07-06-approval-seam.md +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.md @@ -1,5 +1,7 @@ # RFC: The approval seam — one-shot permission decisions over a waterfall of answerers +English | [中文](2026-07-06-approval-seam.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md b/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md new file mode 100644 index 0000000000..cec1692d50 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md @@ -0,0 +1,138 @@ +# RFC:审批 seam——通过应答者瀑布式事件实现一次性权限决策 + +Status: implemented + +[English](2026-07-06-approval-seam.md) | 中文 + +## 问题 + +两个调用方需要向人类提出同一个问题——「这个具体操作可以继续吗?」:`tools/pre-execute` 的 `ask` 决策(包括 Claude-Code 钩子桥的 `permissionDecision: ask`)以及[沙箱 RFC](2026-07-06-sandbox.md) 中拒绝后的一次性升级重试。一个共享的 seam 使它们不必各自发明结果词汇、UI 路由、取消机制和审计追踪,同时保证没有 UI 的部署永远不会批准一个无法应答的请求。 + +路由问题的本质是归属:审批提示必须到达拥有发起请求的 agent 的那个编辑器会话(ACP 桥在一条连接上复用 N 个会话),对无人拥有的 agent(进程内 subagent、测试)默认拒绝(fail-closed),并且不介入没有组合 UI 的部署(无头模式、CI)。 + +## 决策 + +一个包 `dsh-user-approval`(`packages/ui/user-approval`),拥有词汇表和 `ctx.approval` 服务——即机制(MECHANISM)。策略(POLICY)——谁来应答、以及某个会话是否被询问——位于其外部:应答者是 `approval/request` waterfall(瀑布式事件)监听器,由拥有通道的插件注册(ACP 桥、未来的终端 UI、测试脚本),而每会话的策略层可以在任何人类介入之前做出决定。消费方(`dsh-tools` 的 ask 路由、沙箱升级门禁)将问题解析为一个封闭的结果,并从中派生各自的工具结果。刻意只用一个包,而非能力 seam 的三包拆分(见「曾考虑的替代方案」)。 + +### 部署如何使用它 + +一条 `cordis.yml` 条目挂载该 seam。不加载它即为 fail-closed 退出方式:消费方在没有注册任何审批代码的情况下拒绝无法应答的请求。 + +```yaml +- id: approval + name: '@deepseek-ai/dsh-user-approval' + # config: + # policy: never # deployment default for sessions without an override; 'ask' when omitted +``` + +仅有这条条目提供的是机制而非通道:没有组合应答者时,每次 ask 解析为 `unavailable`,发起 ask 的工具调用被拒绝——默认拒绝无需配置。组合 ACP 应用(`@deepseek-ai/dsh-acp-demo`,如 [acp-agent 示例的默认树](../../../../examples/acp-agent/README.md))即可闭合回路:其桥注册一个应答者,通过 `session/request_permission` 向拥有该会话的编辑器发出提示,于是钩子的 `ask` 或升级请求会以一次性 Allow/Reject 提示的形式出现在已流式输出的工具调用上。`policy: never` 是无人值守姿态——每次 ask 确定性地自动拒绝,在系统提示词中声明,无人类参与。`policy` 在插件加载时针对封闭列表做校验;其他值直接抛异常。 + +组合后的部署观察到的行为:`allowed-once` 仅允许该次调用继续;拒绝、关闭和通道缺失以三种不同的原因拒绝,模型可以区分它们;每次 ask 都在发起请求的 agent 的会话日志上落一对持久的 `approval/asked`/`approval/decided`;授权不会在发起请求的那次调用之后持续存在。 + +以下是在此组合下的一次 ask,逐字取自沙箱示例录制的 `escalation-approved` 场景——模型请求沙箱升级,门禁发起 ask,桥向拥有该会话的编辑器发出提示,用户点击 Allow once: + +``` +tool/call bash {"command": "printf 'escalated\n' > escalated.txt && cat escalated.txt", + "sandbox_permissions": "workspace-write", + "justification": "the user asked to write escalated.txt in the workspace"} +approval/asked {"toolName": "bash", "callId": "call_00_…", + "reason": "escalate sandbox to workspace-write: the user asked to write escalated.txt in the workspace"} + → session/request_permission {"toolCall": {"toolCallId": "call_00_…"}, + "options": [{"optionId": "allow-once", "name": "Allow once", "kind": "allow_once"}, + {"optionId": "reject-once", "name": "Reject", "kind": "reject_once"}]} + ← the user picks "Allow once" on the prompt the editor attaches to the streamed bash call +approval/decided {"outcome": "allowed-once"} +tool/result "escalated" — this one call ran under the wider mode; the grant died with it +``` + +`escalation-rejected` 的孪生场景以 `{"outcome": "rejected"}` 结束:什么都不执行,模型的结果携带发起方逐字的 fail-closed 文本(`the user rejected escalating this command to "workspace-write"`)。钩子的 `permissionDecision: ask` 走完全相同的协议;只有发起方和拒绝文本不同(§ dsh-tools 中的 Ask 路由)。无头模式下,同一请求完全跳过提示并以 `unavailable` 结算。 + +### 设计细节 + +#### seam:机制与策略分离 + +经过校验并追加 `approval/asked` 后,`request()` 解析为 `allowed-once`、`rejected`、`cancelled` 或 `unavailable`。服务借用只读请求、运行应答者 waterfall、与取消竞争,并将抛出异常或无效应答归一化为 `unavailable`。随后追加匹配的 `approval/decided`,通过 `ApprovalRequestId` 配对。 + +两个审计事件都必须在一个打开的轮次内;接受或 pre-commit 追加失败会拒绝该请求。Post-commit 观察者被会话所包含。`allowed-once` 仅授权所请求的操作,服务不保留任何授权状态。 + +应答者是 `approval/request` waterfall 监听器。监听器为其拥有的 agent 返回结果,否则调用 `next()`。没有应答者时默认为 `unavailable`;因此卸载 UI 即默认拒绝,不会留下通道。由于兄弟插件的注册顺序不确定,部署应组合一个终端应答者,仅对「决定或委托」门禁使用 `prepend`。 + +`ApprovalRequest` 携带 agent、工具名、可选的 `callId`、原因和 signal。agent 同时路由提示和审计事件。请求使用 `dsh-llm` 的 `CallId` 而不导入 `dsh-tools`,避免包循环。工具参数被省略,因为 UI 应答者附着在已渲染的调用上。 + +#### dsh-tools 中的 Ask 路由 + +`ToolRegistry.execute()` 在拒绝路径之前将 `ask` 发送到审批 seam。只有 `allowed-once` 才继续执行;拒绝、取消和通道不可用产生三种模型可见的不同原因。注册表按调用查找可选服务,因此缺失或未加载的服务默认拒绝,不会阻塞注册表 fiber。无 agent 的执行同样默认拒绝,因为无法路由或审计。 + +#### 每会话策略层 + +seam 拥有会话策略 `'ask' | 'never'`,遵循[沙箱 RFC](2026-07-06-sandbox.md) 中的切换契约。生效的会话或配置策略在应答者之前应用:`'never'` 在 `request()` 内部拒绝,而 `'ask'` 派发请求,无人应答时降级为 `unavailable`。系统提示词仅声明确定性的 `'never'`;叙述者报告切换,每个请求仍然收到其审计对。 + +#### ACP 应答者 + +ACP 桥找到拥有该会话的编辑器,为该 `callId` 发送 `session/request_permission`,并将一次性 allow、reject 和 cancel 响应映射到 seam 词汇。未知选项永远不授权。外部 agent 和没有 `callId` 的请求通过 `next()` 委托;RPC 失败变为 `unavailable`。桥应答请求但不决定哪些调用需要审批。 + +应答者通过 [ACP 支持 RFC](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md) 描述的桥反向映射归属 seam 进行路由,实现了[多会话 RFC](../../implemented/feature/2026-06-14-acp-multi-session.md) 所要求的每会话权限归属。 + +#### 审计,以及模型看到什么 + +`approval/asked` 和 `approval/decided` 是持久的仅日志事件。模型只看到发起方记录的 `tool/result`。每个被接受的请求追加一条匹配的决策,包括取消和被包含的应答者失败。 + +#### 实体与依赖 + +`dsh-user-approval` 拥有固定的派发与审计机制;`dsh-tools` 发起请求,`dsh-acp` 应答。可替换的应答者作为监听器留在其通道拥有者插件中,因此三包能力拆分只会增加一个空的实现层。沙箱执行器仍然只负责传输,静态能力授权与交互式审批保持分离。 + +### 测试 + +- **单元/集成测试:** 覆盖先到先得的委托、fail-closed 默认值、格式错误和抛异常的应答者、取消竞争与迟到应答丢弃、观察者失败下的审计配对、不可绕过的 `'never'`、不同的工具拒绝原因,以及 ACP 每会话路由/结果映射。 +- **快照测试:** 通过沙箱升级的两个分支编排权限应答并固定 `'never'` 提示词加策略切换通知。没有组合应答者时钩子产生的 ask 仍作为 fail-closed 拒绝被覆盖。 + +## 延后 + +- **`allow_always` 授权存储**——兑现持久授权意味着设计存储、范围标识(调用?路径?前缀?会话?时间窗口?)和撤销;在设计完成之前,只宣告一次性选项([沙箱 RFC](2026-07-06-sandbox.md) § 升级记录了开放的范围问题)。 +- **有组合应答者时录制的钩子产生的 ask**——升级录制了人类提示的协议格式(wire format),而当前钩子 fixture(测试前置数据)固定的是无服务拒绝;它们组合的生产者/应答者路径仍由单元测试覆盖。 +- **将子 agent 的审批路由到父会话**——`subagent-acp` 的子端自动应答自己的 `permission` 请求;将它们呈现给父端编辑器是独立的设计。 + +## 曾考虑的替代方案 + +- **单个注册提供方而非 waterfall 监听器**:否决。`registerProvider()` 接口迫使所有组合问题——白名单预过滤、外部钩子决策者、脚本化测试应答、人类前面的策略门禁——都塞进一个提供方实现。waterfall 从运行时已有的机制中获得组合能力、缺失时默认拒绝和 HMR(热模块替换) dispose(资源释放);seam 的 JSDoc 用约定固定单决策槽语义,而非发明一个提供方注册表。 +- **在 ACP 桥中内联 `tools/pre-execute` 权限门禁**:否决。对桥拥有的每次调用都弹出提示,会把发起 ask 的策略硬编码到 UI 插件中,无法服务第二个发起方(沙箱升级发生在执行开始之后,没有 pre-execute 时机),且让钩子产生的 `ask` 决策没有共享机制。 +- **通用用户交互 seam(`ctx.userInteraction`)**:否决作为审批机制。两者共享骨架(按 agent 路由、阻塞等待人类、处理缺失),但审批的契约在每个关键维度上都更窄:封闭的结果词汇而非自由文本、附着在工具调用上的协议原生提示而非通用表单、强制的缺失时默认拒绝、以及审计事件。因此审批不走已发布的 `packages/ui/user-interaction` / `ask_user_question` 引出路径——引出表单不是权限提示,自由文本应答不是封闭结果;如果两者未来趋同,共享提供方管道仍然开放。 +- **在 `dsh-tools` 中静态可选注入**:否决。vendor 的 cordis `Inject` 类型没有可选标志——对象形式将服务名映射到拦截配置,声明的 inject 会阻塞 fiber。`ctx.get('approval')` 是文档化的机会性消费模式(`tool-bash` 的 owner-token 查找、loop 的持久化探测),按调用读取存在性,在 HMR 下无需额外机制即可正确降级。 +- **能力 seam 的三包拆分**:否决。接口/实现/消费方适合实现可替换的 seam(bash-local vs bash-sandbox)。这里服务体是固定机制,可变部分是留在各自通道拥有者中的监听器——拆分只会制造一个空的实现包(「不要预防性拆分」)。 +- **现在就提供 `allow_always`**:否决。协议可以表达它,但兑现它意味着设计授权存储、范围标识和撤销(§ 延后)。宣告一个 harness 无法兑现的选项只会制造注定失败的授权。 + +## 后果 + +- 只有 `allowed-once` 才会派发被询问的操作;缺失、拒绝、取消或应答失败的路径均拒绝。 +- 会话归属路由提示、策略和审计事件,不跨越编辑器会话。 +- 被接受的请求追加一对持久审计事件;模型只看到最终的工具结果。 +- 没有加载该服务的部署不会发出审批提示或审计事件,并在工具边界拒绝每个 `ask`。 + +代价与已接受的局限: + +- **两个急于决策的应答者争抢同一个槽位。** 兄弟插件的监听器顺序不确定,seam 无法仲裁竞争的终端应答者——通过约定缓解(每个部署一个终端应答者;仅对「决定或委托」门禁使用 `prepend`),而非事件总线不具备的优先级机制。 +- **生产环境的验证依赖单一组合。** `ask` 有两个生产者家族——钩子桥通过 `tools/pre-execute`,以及沙箱升级通过其自身门禁——协议格式录制在沙箱示例的快照套件中,因此 seam 的真实覆盖率就是这一种组合,直到更多部署组合它。 +- **归属以 `Agent` 对象同一性为键。** 应答者通过桥现有的 WeakMap 解析会话;当前所有路径在 loop 和各 seam 之间传递同一个对象,但未来如果某个边界克隆或代理了 agent,桥会委托并默认拒绝——安全但静默无 UI——届时需要改用 session-id 匹配。 + +## FAQ + +- **在完全没有应答者的部署中(无头模式、CI)会发生什么?** 每次 ask 穿过空的 waterfall 降级为 `unavailable`,工具调用以「no approval channel is available」原因被拒绝。默认拒绝是零监听器的默认行为,不是配置。 +- **授权能持久化吗——「始终允许」?** 不能。`allowed-once` 仅授权单次被询问的操作,服务在请求之间不存储任何东西;`allow_always` 在授权存储设计完成之前刻意不宣告(§ 延后)。 +- **模型看到审批的什么?** 只看到发起方从结果派生的工具结果——审计对永远不进入 transcript(文本记录)。三种非授权原因各不相同,模型可以区分人类说「不」、提示被关闭、以及通道缺失。 +- **谁决定一次调用是否首先发起 ask?** 策略生产者:返回 `permissionDecision: ask` 的钩子、任何 `tools/pre-execute` 监听器、或沙箱升级门禁。seam 和桥只负责路由和应答;两者都不注入自己对「什么值得弹出提示」的判断。 +- **用户关闭提示或轮次在 ask 进行中中止时会发生什么?** 关闭映射为 `cancelled`,有自己的拒绝文本。已中止的 signal 以 `cancelled` 结算而不派发;ask 进行中的中止丢弃迟到的应答——无论如何只有一对审计事件,绝不会有两对。 +- **如果客户端以 harness 从未提供的选项应答会怎样?** 除已提供的 `allow_once` 之外的任何选项都映射为 `rejected`——来自不合规客户端的未知 optionId 永远不能授权。 +- **subagent 的审批如何路由?** 没有应答者拥有的 agent 穿过整个 waterfall 委托并默认拒绝——进程内 subagent 被刻意设计为不可应答。`subagent-acp` 子端的自动应答是独立的;将子端的 ask 路由到父端编辑器已延后(§ 延后)。 +- **`policy: 'never'` 在运行时实际改变了什么?** 服务在派发任何应答者之前将该会话的每次 ask 解析为 `rejected`(在服务内部,因此没有注册顺序能绕过它);系统提示词声明该策略;切换在边界处被叙述;每次自动拒绝仍然落一对审计事件。 +- **热重载或 UI 插件在会话中途卸载时会发生什么?** 应答者随其拥有的 fiber 一起 dispose,因此下一次 ask 降级为 `unavailable` 而非挂在死通道上;重新挂载会重新注册应答者,无需追赶状态。 +- **用户在哪里看到自己在批准什么?** 在工具调用本身上:提示通过 `callId` 附着在已流式输出的调用上(包含参数),并添加发起方的人类可读 `reason`;请求本身不携带参数副本。 + +## 先例 + +本设计复用或对比的仓库内先例: + +- `fs/write-intent` 门禁(`packages/fs/fs/`)——文档化的单占位决策槽 waterfall 语义(先到先得、通过 `next()` 委托),应答者契约复用了它。 +- `hook/invoked`/`hook/result`——仅日志审计对先例,`approval/asked`/`approval/decided` 沿用了它;[钩子桥 RFC](2026-06-30-hook-bridges.md) 发布了 `permissionDecision: ask`,即第一个生产者。 +- [拦截 seam RFC](2026-06-30-interception-seams.md)——`tools/pre-execute` 的 `allow`/`deny`/`ask` 词汇,本 seam 服务其中的 `ask`。 +- [ACP 支持 RFC](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md)——应答者路由所经过的 `WeakMap<Agent, sessionId>` 归属 seam;[多会话 RFC](../../implemented/feature/2026-06-14-acp-multi-session.md)——本设计实现的每会话权限归属阻塞项。 +- 机会性 `ctx.get()` 消费模式(`tool-bash` 的 owner-token 查找、loop 的持久化探测)——`dsh-tools` 消费该 seam 而不阻塞其 fiber 的方式。 diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml new file mode 100644 index 0000000000..352331b13d --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-06-explicit-tool-order.md: 9d94496ffdcbc4c7df820581b02e3e075ec1c0be +2026-07-06-explicit-tool-order.zh.md: fa3a5bbf83115c25f87471b8a3847b9347d42934 diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md index c56e1eb0ba..9d94496ffd 100644 --- a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md @@ -1,5 +1,7 @@ # RFC: Explicit model-facing tool order +English | [中文](2026-07-06-explicit-tool-order.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md new file mode 100644 index 0000000000..fa3a5bbf83 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md @@ -0,0 +1,50 @@ +# RFC:显式的模型侧工具顺序 + +Status: implemented + +[English](2026-07-06-explicit-tool-order.md) | 中文 + +## 问题 + +模型侧的工具顺序此前跟随插件注册顺序,而注册顺序取决于彼此独立的插件在并发模块加载时的竞态。这一竞态导致 CI 和快照录制中产生不同的请求头。由于顺序影响请求字节、缓存和持久化的头部,需要一个显式的确定性策略。 + +## 决策 + +系统提示词组装拥有模型侧工具的权威顺序,正如它已经拥有 section 顺序一样。`dsh-system-prompt` 上的 `toolOrder?: string[]` 是可选的显式策略: + +- 列表中已注册的工具取其列出的位置。 +- 列表中的名称没有对应的已注册工具,属于配置错误。形状错误(缺少 rest 条目或名称重复)在服务构造器中快速失败;未注册的名称在每次 `assemble()` 时拒绝——这是已注册工具集存在可供检查的最早时刻(工具插件在服务构造之后注册),也是唯一的通用时刻(注册随时可能变化;Cordis 没有「所有插件已加载」事件)。在已交付的 agent loop 下,第一个轮次在任何模型请求之前就会失败——确切的影响范围见下文「后果」。 +- 已注册但不在列表中的工具,插入到 `'<unlisted-tools>'` rest 条目(`TOOL_ORDER_REST`)处,在其他未列出的工具之间按名称字典序排列。 +- 任何已收集的工具不得使用 `TOOL_ORDER_REST` 作为其 `ToolSchema.name`;组装在排序之前就会拒绝该保留名称。 +- 列表必须恰好包含一个 rest 条目,且名称不得重复。 +- 当 `toolOrder` 未设置时,权威顺序为纯字典序(code-unit 比较,与 locale 无关),因此无需配置即可保证确定性。 + +`assemble()` 在 `system-prompt/assemble` waterfall(瀑布式事件)之前规范化提供方工具,从源头消除注册顺序差异。waterfall 从这个确定性列表出发;未被改变的顺序随后流入请求头、冻结请求和重建检查,无需循环特有的排序逻辑。 + +范围刻意收窄:本 RFC 修复的是注册顺序竞态,而非插件行为。`system-prompt/assemble` 的监听器仍可添加、移除或重排工具——正如它可以在 section 排序之后编辑 section——并对自身输出的确定性负责;waterfall 契约已要求监听器具有确定性(可重建性不变式会捕获在构建与回放之间表现不一致的监听器)。 + +配置传递沿用 `persona` 的先例,`toolOrder` 与它并列:应用配置(`dsh-stdio-demo`、`dsh-acp-demo`)接受该键,并通过 `dsh-agent-spine-demo`(其 schema 是各所有者 schema 的交集)转发给 `SystemPrompt` 子服务。有一个 schemastery 细节是关键的:schemastery 数组默认为 `[]`,但省略的 `toolOrder` 必须保持 ABSENT(= 字典序),而不是变成一个显式配置的空列表(无效——缺少 rest 条目),因此链上的每个 schema 都将默认值强制为 `undefined`。 + +## 曾考虑的替代方案 + +- **注册顺序(现状)**:并发导入竞态,依赖宿主环境(上述 CI 不稳定),评审中不可见。 +- **插件依赖图的线性化**:该关系是偏序的,独立的工具插件之间不可比较;上述不稳定发生时偏序已完全满足。 +- **每个插件在工具贡献上设 `weight`**:将顺序分散到各插件中,仍需一个无人拥有的全局编号约定(section 的 `order` 分段已经展示了这种协调成本需要手工承担)。 +- **在 `ToolRegistry.schemas()` 中排序(注册表层)**:同样确定,但注册表是一个被组装之外的更多消费方使用的成员存储;排序是 prompt 组合的关注点,而组装已经拥有 section 的组合策略。 +- **`LlmService` 配置 + 循环在记录头部前调用的 `orderTools()` 方法**:可行,但仅为在远处应用策略就增加了一个公开服务方法和一处循环改动;每个未来的请求组合者都必须记得调用。在列表诞生处规范化使无序列表不可表示,且零新增接口。 +- **在 `llm.stream()` 内部规范化**:在头部事件记录之后才运行(不稳定仍存在),且需要重建深度冻结的信封,静默地解除了重建不变式。 +- **穷举列表(无 rest 条目)**:每个新加载的工具插件都会导致启动失败;强制的 rest 条目使未列出的工具保持确定性,且其位置是显式的。 +- **启动时校验(`dsh-app-boot` 在 `loader.await()` 之后调用 `SystemPrompt.assertToolOrderSatisfied()`)**:能将配置错误变为启动死亡而非首轮失败,但需要一个公开服务方法加上通用启动胶水对单一服务的结构耦合,且无论如何不能替代组装时检查(嵌入式调用者从不运行 app boot;注册在 boot 之后仍会变化)。也没有现成事件可以承载该检查:Cordis v4 没有 ready 类事件,`loader/entry-init`/`internal/status` 在加载中途触发(与工具注册竞态——正是本 RFC 要消除的熵源),而 agent 生命周期事件不会早于组装。在 `assemble()` 设一个执行点被判定值得接受较晚的失败时刻。 + +## 后果 + +- 每个由注册表构建的组装在任何宿主上都以确定性工具顺序开始;在没有专家监听器刻意改变的情况下,每个 `request/header` 事件和模型请求都继承该顺序。CI 与本地之间的注册顺序翻转在结构上被消除,默认为字典序。 +- 初始 `PromptAssembly.tools` 是权威的,因此 waterfall 监听器从模型侧顺序出发;提供方注册顺序在该协作 seam 之前的任何地方都不可观测。 +- 步骤之间的纯工具重排只能表示为 `request/header` 的 `'fallback'` 快照(基于名称键的 `ToolsDelta` 无法表达它);在稳定的权威顺序下,这种重排在实践中不再发生,因此 fallback 路径仅作为安全阀保留。 +- `toolOrder` 键沿 app → `agent-core` → `SystemPrompt` 转发链传递,因此部署时在 app 配置中与 `persona` 并列设置;`dsh-llm` 和 agent loop 不受影响。 +- `toolOrder` 中拼写错误或未加载的工具名称在 prompt 组装时使轮次失败,而非启动时:循环在轮次内组装(`turn/start` 之后、`step/start` 之前),因此拒绝到达轮次的外层 catch——轮次以 `error` 原因平衡关闭并携带消息,`agent/error` 镜像它,不开启步骤,不记录 `request/header`,不向适配器发出请求,agent 回到空闲。每个轮次都以相同方式失败,直到配置被修正;进程本身保持运行(与仓库规则一致:显式配置引用不得被静默忽略——执行点在组装处,因为不存在更早的通用时刻)。 +- 工具提供方返回保留的 rest 条目名称时,其 prompt 组装失败形态与未知的列出名称相同。这防止哨兵值变成歧义的真实工具,并保持「从不丢弃工具」的排序契约。 + +## 测试 + +系统提示词测试覆盖字典序默认顺序、列出/rest 位置、提供方顺序无关性、共享名称、无效列表、未知或保留名称、waterfall 前的权威列表,以及监听器添加的工具不被重新排序的规则。循环测试固定跨注册排列的已记录和已分发顺序一致、通过 agent-core 和两个 app 的转发、深度冻结请求,以及在未知配置名称下的平衡轮次失败(无步骤、无头部、无适配器调用)。快照回放仅在固定的 `text-turn` 头部中保留完整的权威列表;其他 fixture(测试前置数据)继续使用 `{{tools}}`。 diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml new file mode 100644 index 0000000000..c36f317c2f --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-07-mcp-client-plugin.md: 7706190257b54730532e4aa46cc9c47453c59871 +2026-07-07-mcp-client-plugin.zh.md: 4d2ea8532afbf6160a98020b8cc480e1bf683981 diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md index 1be5b225fe..7706190257 100644 --- a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md @@ -1,5 +1,7 @@ # RFC: MCP client plugin — connect to external MCP servers and bridge their tools +English | [中文](2026-07-07-mcp-client-plugin.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md new file mode 100644 index 0000000000..4d2ea8532a --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md @@ -0,0 +1,214 @@ +# RFC:MCP 客户端插件——连接外部 MCP 服务器并桥接其工具 + +Status: implemented + +[English](2026-07-07-mcp-client-plugin.md) | 中文 + +## 问题 + +harness 此前无法消费 MCP(Model Context Protocol)生态的工具。MCP 是工具服务器的新兴标准:GitHub、文件系统、数据库、代码搜索以及数百个社区服务器都通过 MCP 暴露工具。用户希望将 harness 指向一个或多个 MCP 服务器,让它们的工具以原生的模型可见工具形式出现,而无需为每个服务器编写胶水代码。 + +`ToolRegistry` 已经接受原始 JSON Schema 工具定义(见 `dsh-tools` README:"Raw JSON-Schema tool definitions (from MCP servers) are still accepted by `ToolRegistry.register()` directly"),扩展实操手册(cookbook)也勾勒了预期模式("MCP | one plugin per server: discover tools → `ctx.tools.register()`")。基础设施已就绪,缺的是桥接插件。 + +## 决策 + +### 包 + +单个包 `@deepseek-ai/dsh-mcp-client`,位于 `packages/mcp/mcp-client/`。不做能力 seam 三包拆分:可预见范围内不会有第二种 MCP 客户端实现,且约定是「不要预防性拆分」(见[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md))。 + +### SDK + +使用官方 [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk)(`Client`、`StdioClientTransport`、`StreamableHTTPClientTransport`)。harness 不自行实现 JSON-RPC,与 ACP 委托给 `@agentclientprotocol/sdk` 的做法一致。 + +### 范围 + +仅 MCP 客户端(不含服务器端——ACP 已覆盖「将 harness 暴露为 agent」的角色)。仅桥接 **Tools**:Resources 和 Prompts 推迟(它们需要 harness 侧尚不存在的消费机制,且设计空间很大)。 + +### 插件形态 + +命名空间插件(具名导出 `name`/`inject`/`Config`/`apply`,无 `export default`)。`inject: ['tools']`。每个 MCP 服务器在 `cordis.yml` 中是一个插件实例:同一个包以不同配置加载 N 次,与 `dsh-tool-subagent` 相同。 + +### 配置 + +以 `transport` 字段为判别的扁平联合类型: + +```typescript +interface StdioConfig { + transport: 'stdio' + serverName: string // required namespace, ^[A-Za-z0-9_-]{1,32}$ + command: string + args?: string[] + env?: Record<string, string> + cwd?: string + toolCallTimeoutMs?: number // default 60_000 +} + +interface StreamableHttpConfig { + transport: 'streamable-http' + serverName: string // required namespace, ^[A-Za-z0-9_-]{1,32}$ + url: string + headers?: Record<string, string> + toolCallTimeoutMs?: number // default 60_000 +} + +type Config = StdioConfig | StreamableHttpConfig +``` + +`serverName` 是稳定的本地标识,用于在模型可见名称(见下文)中为该服务器的工具划定命名空间。它有意设计为用户配置,**不是**远端的 `serverInfo.name`:远端名称是不可信输入,跨部署不唯一(同一服务器的 prod 和 staging 实例报告相同名称),且可能在服务器升级时变化——这些都不得静默地重命名模型可见工具。多个活跃实例使用相同 `serverName` 属于配置错误:后加载的实例在启动时以可操作的错误消息失败,绝不静默覆盖或跳过。短 `serverName`(如 `gh`)同时也是缩短公开名称的旋钮。 + +`cordis.yml` 用法示例: + +```yaml +- id: mcp-github + name: '@deepseek-ai/dsh-mcp-client' + config: + serverName: github + transport: stdio + command: npx + args: ['-y', '@modelcontextprotocol/server-github'] + env: + GITHUB_TOKEN: !!js process.env.GITHUB_TOKEN + +- id: mcp-web + name: '@deepseek-ai/dsh-mcp-client' + config: + serverName: web + transport: streamable-http + url: http://localhost:3000/mcp + headers: + Authorization: !!js `Bearer ${process.env.MCP_TOKEN}` +``` + +模型看到的是 `mcp__github__create_issue`、`mcp__github__search_code`、`mcp__web__search`。 + +### 生命周期 + +启动时从 `cordis.yml` 加载。HMR(`@cordisjs/plugin-hmr`)提供热替换:编辑 yml 条目会触发旧实例的 dispose(断开连接、注销工具),并创建新实例(连接、发现、注册)。目前不提供运行时动态 API。公开名称是 `(serverName, rawName)` 的纯函数,因此保持 `serverName` 不变的 HMR 替换会重建完全相同的模型可见名称——会话历史和权限规则保持有效——且添加或移除一个无关服务器绝不会重命名已有工具。 + +### 工具发现与注册 + +每个 MCP 工具有两个名称: + +- `rawName`:MCP `Tool.name` 的原始值,仅在协议层(`tools/call`)使用。 +- `publicName`:在 `ToolRegistry` 中注册的全局唯一模型可见名称: + + mcp__<serverName>__<rawName> + +这种按服务器限定的形式是多服务器 agent 客户端的事实标准:所有被调研的终端用户产品都按服务器限定 MCP 工具([Claude Code](https://code.claude.com/docs/en/agent-sdk/mcp#tool-naming-convention) `mcp__github__list_issues`、[Codex](https://openai.com/index/unrolling-the-codex-agent-loop/) `mcp__weather__get-forecast`、[Gemini CLI](https://geminicli.com/docs/tools/mcp-server/#3-tool-naming-and-namespaces)、[VS Code](https://github.com/microsoft/vscode/blob/ab9ec62c6a61e429a9abd612ff220c3f4834c9ea/src/vs/workbench/contrib/mcp/common/mcpServer.ts#L217-L260)、[Cline](https://github.com/cline/cline/blob/52fdbb1d72f7324a28142a7ba7678d4b53c902f4/sdk/packages/core/src/extensions/mcp/name-transform.ts#L20-L35)、[Roo Code](https://github.com/RooCodeInc/Roo-Code/blob/b867ec9145750d0ae1ff7f02d35406e9bf2a0b16/src/utils/mcp-name.ts#L117-L140)、[Goose](https://github.com/block/goose/blob/b3a012cbdde854b0fe14f95b1c48543bf6517c0a/crates/goose/src/agents/extension_manager.rs#L1391-L1441)、[OpenCode](https://github.com/anomalyco/opencode/blob/d199b1bff90282a4f9cd6251b5fc7b16875a52f6/packages/opencode/src/mcp/catalog.ts#L117-L120));`mcp__<server>__<tool>` 的确切拼写沿用 Claude Code 和 Codex。`mcp__` 前缀将 MCP 注册隔离在原生工具命名空间之外,并为权限/遥测规则提供稳定的匹配形状(`mcp__*`、`mcp__github__*`)。 + +1. 连接时:遍历 `client.listTools()` 的分页,推导每个工具的 `publicName`,然后通过 `ctx.tools.register()` 将其注册为原始 `ToolDefinition`。MCP 的 JSON Schema 和 description 原样透传(不做 `defineTool` DSL 转换);仅替换模型可见的 `name`。 +2. 监听 `notifications/tools/list_changed` → 重新执行同步(dispose 上一代、注册新一代)。确定性的名称意味着未变化的工具在重新同步后保持原名。 +3. 执行器闭包持有 `rawName`;公开名称从不发送给服务器,也从不被解析以恢复原始名称。 +4. 不提供 `presentCall`/`presentResult`:ACP 桥接的通用卡片回退负责渲染。 +5. 工具在系统提示词中是透明的:除名称本身外不添加 "[via MCP]" 之类的标注。 + +### 公开名称规范化 + +MCP 允许工具名最长 128 字符且可包含 `.`;DeepSeek 的函数名契约允许 `[A-Za-z0-9_-]` 且最长 64 字符。公开名称按确定性规则规范化:非法字符替换为 `_`,当替换或截断改变了名称时,追加 `(serverName, rawName)` 标识的 12 位十六进制 SHA-256 hash,确保不同的 MCP 标识永远不会折叠为同一个公开名称: + +```typescript +function publicToolName(serverName: string, rawName: string): string { + const joined = `mcp__${serverName}__${rawName}` + const normalized = joined.replace(/[^A-Za-z0-9_-]/g, '_') + if (normalized === joined && normalized.length <= 64) return normalized + const hash = sha256(`${serverName}\0${rawName}`).slice(0, 12) + return `${normalized.slice(0, 64 - 13)}_${hash}` +} +``` + +### 名称冲突处理 + +MCP 仅保证工具名在[单个服务器内](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names)唯一;跨服务器冲突是常态而非例外(一项[微软研究院调研](https://www.microsoft.com/en-us/research/blog/tool-space-interference-in-the-mcp-era-designing-for-agent-compatibility-at-scale/#namespacing-issues-and-naming-ambiguity)覆盖 1,470 个服务器,发现 775 个冲突工具名;仅 `search` 就出现在 32 个服务器中,官方 GitHub 服务器发布的是裸 `create_issue`)。始终启用的命名空间从结构上杜绝冲突,而非在冲突发生时再处理: + +- 两个服务器都发布 `search` → 共存为 `mcp__github__search` 和 `mcp__web__search`。 +- 名为 `search` 的原生 harness 工具不受影响。 +- 重复的 `serverName` 配置导致后加载的实例在启动时失败(见「配置」一节)。 +- 同一服务器列出重复的工具名属于无效工具列表:同步抛出异常,上一代注册保持不变。 +- 替换期间的注册表冲突只可能意味着外部工具占用了本服务器的 `mcp__<serverName>__` 命名空间:部分生成被回滚(该服务器零工具注册),错误被醒目地记录。 + +工具永远不会被静默跳过;哪些工具可用永远不取决于插件加载顺序。 + +### 命名不变式 + +1. 每个 MCP 工具有稳定标识 `(serverName, rawName)`;每个活跃标识恰好对应一个公开名称。 +2. 公开名称是确定性的、全局唯一的,且满足 DeepSeek 64 字符 `[A-Za-z0-9_-]` 契约。 +3. MCP `tools/call` 始终接收原始的 raw name。 +4. 连接、断开或重新同步一个无关服务器,绝不会重命名已有工具。 +5. 注册顺序绝不决定哪个工具可用。 + +### 工具执行 + +为来自同一 MCP 服务器的所有工具提供统一的 `execute` 处理器: + +1. 解析 `rawName`(执行器闭包持有),以配置的超时调用 `client.callTool({ name: rawName, arguments }, { signal: exec.signal })`——公开名称从不发送给服务器。 +2. 映射结果: + - 多个 `text` 内容块 → 以 `'\n'` 连接为单个 `TextBlock`(必要原因:`flattenText` 使用 `join('')` 不带分隔符,多个块会丢失块间边界)。 + - `image` 内容块 → 丢弃并记录 `ctx.logger.warn`(harness 没有图片内容块类型;见 [drop-image RFC](../../implemented/simplification/2026-07-04-drop-image-content-block.md))。 + - `isError: true` → 映射到 harness 的 `isError` 结果路径(`{ content: [...], isError: true }`)。 +3. 取消:`exec.signal`(来自 agent loop 的 cancel)透传给 MCP SDK 的 `callTool`,后者向服务器发送 `$/cancelRequest`。 + +### 子进程环境(stdio 传输) + +复用 `dsh-subagent-acp` 的 `buildChildEnv` + `SENSITIVE_ENV_PATTERN` 清洗逻辑:过滤环境变量(剥离匹配 `/KEY|SECRET|TOKEN/i` 的凭证形变量),然后将 `config.env` 覆盖在上面。显式配置的 env 不受清洗影响。 + +### 断开连接 / 崩溃 + +不自动重连。如果 MCP 服务器进程退出或传输层关闭: + +1. effect dispose → 所有已注册工具被注销(fiber 作用域的 disposer)。 +2. 后续模型对这些工具的调用 → `ToolNotFoundError` → `isError: true`。 +3. 恢复方式:用户编辑 `cordis.yml`(触发 HMR 重载)或重启 harness。 + +这与 ACP subagent 的模式一致:「崩溃即终态,报告错误,清理资源,不重试。」 + +## 曾考虑的替代方案 + +### MCP 服务器端(向外部 MCP 客户端暴露 harness 工具) + +推迟。ACP 桥接已将 harness 暴露为 agent 服务器。再加一层 MCP 服务器会用不同协议重复这一功能,而用户的首要需求是消费外部工具,而非暴露自身工具。 + +### 能力 seam 三包拆分(接口 / 实现 / 消费方) + +否决。可预见范围内不会有替代的 MCP 客户端实现:MCP 只有一个协议、一个 SDK。约定是「在第二种实现出现之前不要预防性拆分」。 + +### 指数退避自动重连 + +v1 否决。引入复杂性(工具已注册但暂时不可用的部分可用状态),且 stdio 进程崩溃通常表明配置问题,重试无法修复。HMR 已提供手动恢复路径。如有需要,未来可作为 `reconnect: boolean` 配置项加入。 + +### 桥接 Resources 和 Prompts + +推迟。Resources 需要 harness 侧的机制来决定何时注入内容(系统提示词?按需?模型触发?)。Prompts 需要 harness 目前缺少的「prompt 模板」概念。两者都需要独立设计;Tools 是高价值、低风险的起点。 + +### 原始模型可见工具名加可选 `toolPrefix` + +否决。这是最初的提案,建立在「大多数 MCP 服务器已在工具名中使用语义前缀(如 `github_create_issue`)」的前提上。该前提不成立:官方 GitHub 服务器发布的是 `create_issue`,参考文件系统服务器是 `read_file`,Sentry 是 `search_issues`——且上述微软调研表明冲突在生态规模下很常见。冲突时再加前缀(或 warn-and-skip)还会使可用工具集取决于插件加载顺序,且添加一个无关服务器可能静默重命名已有工具——在对话中途使会话历史和权限规则失效。所有被调研的多服务器 agent 产品都不使用裸名称。 + +### 仅服务器命名空间(`github__create_issue`,无 `mcp__` 前缀) + +v1 否决。它能防止跨服务器冲突,但无法将 MCP 注册与原生 harness 工具隔离,也放弃了 MCP 全局策略匹配形状(`mcp__*`)。前缀仅消耗 5 个字符;`mcp__<server>__<tool>` 的拼写与 Claude Code 和 Codex 一致,最大化模型的熟悉度。如果 ToolRegistry 将来增加源感知的命名空间,届时可作为命名策略变更重新考虑去掉字面前缀。 + +### 从服务器公告的 `serverInfo.name` 推导命名空间 + +否决。远端名称不可信、跨部署不唯一、升级时可变;工具标识和权限规则不得静默跟随它。命名空间是本地配置。 + +### 在工具结果中保留多个 TextBlock + +否决。DeepSeek 序列化器中的 `flattenText()` 在将 `ContentBlock[]` 展平为协议格式(wire format)时使用 `join('')`(无分隔符)。多个 text 块会静默丢失块间边界——这是正确性 bug。所有现有工具返回单个 TextBlock;MCP 桥接遵循同样做法。 + +## 测试 + +覆盖按层级命名;每个行为放在能表达它的最低成本层级。 + +- **单元测试**(`tests/mcp-client.spec.ts`、`tests/apply.spec.ts`,mock MCP SDK):`publicToolName` 算法(干净路径、规范化、截断加 hash、确定性、不同标识的分离)、raw 与 public 的协议纪律、跨服务器与原生工具共存、重复 `serverName` 加载失败与预留释放、无效工具列表拒绝、代际替换/回滚、重新同步失败时的保留、结果映射、取消、配置 schema 校验。100% 逐文件覆盖率门禁约束该包。 +- **E2E**(`tests/mcp-client.e2e.ts`,无需密钥):使用仓库内 fixture 服务器、`@modelcontextprotocol/server-everything` 和 `@modelcontextprotocol/server-filesystem` 通过 stdio 运行真实 MCP 协议,以及通过进程内 `StreamableHTTPServerTransport` 服务器运行 Streamable HTTP——命名空间下的发现、带点号名称的端到端规范化、执行往返、重复 `serverName` 拒绝、dispose(资源释放)。 +- **快照**:刻意不做。MCP 工具不引入新的 transcript 渲染面——它们注册为原始 `ToolDefinition`,通过 ACP 桥接的通用卡片回退渲染,而桥接的单元测试套件已固定了该行为(`packages/ui/acp/tests/stream-update.spec.ts`)。将 MCP 服务器加入快照示例的 `cordis.yml` 会改变已固定的 `text-turn` 系统提示词 fixture(迫使每条录制的 golden 都需要带密钥重新录制),并使每次回放依赖于 spawn 一个外部 MCP 服务器进程——而新增的渲染行为为零。如果后续变更为 MCP 工具引入专属的渲染意图,该变更届时自行命名其快照覆盖。 + +## 后果 + +- 每个 MCP 服务器只需一条 `cordis.yml` 条目即完成集成:`serverName: filesystem` 加一条 stdio 命令(或一个 Streamable HTTP URL),就能把 `mcp__filesystem__read_file` 放入模型的工具列表,可调用,协议层使用原始的 `read_file`。 +- 公开名称是会话历史与权限/配置界面的一部分;命名算法是由测试固定的 v1 契约,发布后修改它是破坏性变更。 +- `mcp__<serverName>__` 限定符在每个名称上消耗 token。已接受:description 和 JSON Schema 在工具定义 token 中占主导,而限定符换来了稳定标识、冲突隔离和 MCP 全局策略匹配形状(`mcp__*`、`mcp__github__*`)。 +- **MCP SDK 稳定性**:`@modelcontextprotocol/sdk` 仍在演进;破坏性变更需要更新桥接。版本已固定,且该 SDK 被广泛采用(Claude Desktop、Cursor、VS Code),因此破坏性变更不太可能悄然发生。 +- **工具 schema 质量**:MCP 服务器可能暴露描述不佳的工具(模糊的 description、不完整的 JSON Schema)。harness 原样透传——垃圾进垃圾出;这是服务器作者的责任,不是桥接的责任。 +- **Stdio 进程管理**:行为异常的 MCP 服务器如果忽略信号可能卡住 dispose。Cordis fiber 的 dispose 有有界静默期;卡住的传输层最终会在框架层面超时。 +- 崩溃恢复是手动的(HMR 编辑或重启)——v1 已接受;`reconnect` 配置项作为未来工作保持开放。 diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml b/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml new file mode 100644 index 0000000000..fddf23cccb --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-07-session-prefix.md: ffa0fecb86e84ed64d45b24e1b6943d421757fb2 +2026-07-07-session-prefix.zh.md: 292c74fac75d8f2c29628fc5e90c72dadcaf4fdb diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.md b/docs/rfc/implemented/feature/2026-07-07-session-prefix.md index f0d458368a..ffa0fecb86 100644 --- a/docs/rfc/implemented/feature/2026-07-07-session-prefix.md +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.md @@ -1,5 +1,7 @@ # RFC: The session prefix — request-only messages in front of the derived history +English | [中文](2026-07-07-session-prefix.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md b/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md new file mode 100644 index 0000000000..292c74fac7 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md @@ -0,0 +1,44 @@ +# RFC:会话前缀——置于派生历史之前的仅请求消息 + +Status: implemented + +[English](2026-07-07-session-prefix.md) | 中文 + +## 问题 + +插件经常拥有一段会话级别稳定的开场内容,模型必须始终看到它:技能目录、AGENTS.md 摘要、工作区基线。在这个 seam 出现之前,harness 只提供两个归属位置,但对这类内容来说两个都不对。系统提示词是一个渲染后的单字符串:消息形态的内容(user 角色的 `<system-reminder>` 信封、多消息引导序列)放不进去,而且提供方对对话消息与系统文本的权重处理不同。持久化历史(`agent.inject()`、会话开始时的 `context/message`)会让开场内容变成永久记录:每个 `deriveMessages()` 消费方都会回放它,压缩(compaction)的保留遍历拥有它,fork 会把它以陈旧状态烘焙进去,resume 无法刷新它——一份在会话诞生时捕获的目录会比它所描述的世界活得更久。 + +显而易见的第三个选项——让插件在请求发出时编辑 `messages`——被[可重建请求 RFC](../architecture/2026-07-05-reconstructable-requests.md) 禁止:每个由循环构建的请求都是会话日志的纯函数,因此承载开场内容的通道必须精确记录它所发送的内容。缺失的是一个带持久记录的仅请求消息通道。 + +## 决策 + +`agent/session-prefix` 是 agent 事件映射上的一个 waterfall(瀑布式事件)([`packages/core/agent/src/types.ts`](../../../../packages/core/agent/src/types.ts)):监听器接收一个冻结的空种子并返回一个扩展(规范的贡献方式是前置,`[mine, ...await next()]`,在协议格式上产生注册顺序)。循环([`packages/core/agent-loop/src/loop.ts`](../../../../packages/core/agent-loop/src/loop.ts))在每个循环实例中触发一次,延迟到该实例首次 `agent/pre-step` 之前;组合后的列表被深拷贝、深冻结、缓存在实例上,并在该实例发送的每个请求中置于**整个**派生历史之前——紧接在提供方的 system 槽位之后([协议格式顺序](../../../core-data-structures/core.md#the-request-envelope-llmcallconfig-and-the-logged-header))。 + +三个属性承载了这一设计: + +- **仅请求,记录在 header 中。** `deriveMessages()` 从不返回前缀;它唯一的持久记录是实例锚定的 `request/header` 快照上的 `EpochHeader.messagePrefix`——可重建请求 RFC 已经为请求的非历史部分拥有的通道,因此不引入新的会话事件。开发不变式([dsh-invariants](../../../../packages/support/invariants/src/index.ts))对每个循环构建的请求重新计算 `messagePrefix + 边界派生`;未记录的前缀无法到达协议格式。 +- **按实例冻结。** 复用是结构性的,而非靠纪律保证:缓存的产物在会话中途不可变,因此提供方的 prompt 缓存在构造上成立,前缀以每步零边际成本扩展了可缓存区域。进程重启或 `ctx.agents.resume()` 是一个新实例:它重新组合,任何漂移都可归因地落在 `'resume'` header 快照上。这就是该 seam 创建的路由规则:会话冻结的开场内容走前缀;会话中途变化的内容走仅追加历史通道(`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——[拦截 seam RFC](2026-06-30-interception-seams.md)),每条都是一次性持久化的 `context/message`,之后被前缀缓存覆盖。 +- **在压力门禁之前组合。** 组合先于实例的首次 `agent/pre-step`,且 seam 将组合值传递下去:`agent/pre-step` 携带 `sessionPrefix` 参数,`CompactService.compactIfNeeded(agent, fullSystemPrompt, sessionPrefix, signal)` 将其计入 token 压力估算——如果门禁读取的是上一个实例折叠后的前缀,那么在一个贡献者增长了的 resume 或 fork 实例的首步上会低估压力,跳过压缩并发出超窗口的首请求。组合过程中如果 cancel/dispose 落入 waterfall 内部,组合结果被丢弃、永不缓存:一个感知中止的监听器的降级回退不会泄漏到后续请求中,下一轮次在活跃 signal 下重新组合。 + +由于组合在边界快照之前运行,组合监听器的会话追加会加入**当前**请求的派生历史。压缩在结构上无法触及前缀(或系统提示词):它重写的是表面节点,而 header 状态从不进入表面。 + +## 测试 + +[拦截测试](../../../../packages/core/agent-loop/tests/interception.spec.ts)固定了无 header 增量时的组合一次复用、前置顺序、空前缀省略、不可变性,以及组合先于 pre-step;[取消测试](../../../../packages/core/agent-loop/tests/cancel.spec.ts)固定了丢弃与重新组合。会话编解码器、不变式和压缩测试覆盖 header 往返、请求重建和前缀感知的压力计算。快照规范化保留前缀计数,而[固定 header 场景](../testing/2026-07-06-pin-request-header-content-in-one-scenario.md)拥有内容,默认示例保持无前缀。不需要前缀专属的 e2e 测试,因为该 seam 是确定性的且与提供方无关;带密钥的[请求缓存 e2e](../../../../packages/core/agent-loop/tests/request-cache.e2e.ts) 覆盖了其缓存经济性。 + +## 曾考虑的替代方案 + +- **每请求 `before`/`after` 槽位,每步重新计算**(最初提出的形态:每个请求触发一次 waterfall,贡献冻结的 `before` 消息置于历史之前、新鲜的 `after` 消息置于历史之后):否决。每步重新组合 `before` 会引入静默漂移——除非每步记录一个 header 增量,否则没有东西将其锚定到日志——而 `after` 槽位位于不断增长的历史之后,其 token 在每个请求中重新支付,且其后的所有内容不可缓存。与各替代方案对比衡量,当前每种更新模式都能由持久追加更廉价地服务(支付一次,此后缓存读取),唯一没有归属的内容是会话稳定的开场——它需要的是冻结,而非重新计算。 +- **系统提示词分区**(`system-prompt/assemble`):对此类内容否决。组装渲染为单一 `system` 字符串,消息形态的开场放不进去;且系统提示词被设计为每步重新组装(变化时带 header 增量),而开场内容需要的是按实例冻结的语义。 +- **持久化历史开场**(会话开始时 `inject()`):否决。永久历史正是问题陈述中的失败模式——到处回放、可被压缩、跨 resume 陈旧。 +- **按轮次而非按实例组合**:否决。轮次边界的重新组合要么与日志静默失同步,要么强制每次变化产生一个 header 增量,且它每次触发都会破坏提供方缓存;合理的刷新点是实例边界,`'resume'` 快照已经在那里可归因地记录漂移。 +- **在首请求时延迟组合,让压缩读取折叠后的 header**(首次合入时的形态):评审中被取代。折叠值只从实例的第二个请求起才与活跃前缀匹配,因此在 resume/fork 实例的首步上,压力门禁读取的是**上一个**实例的前缀,可能低估压力。在首次 pre-step 之前组合并通过 seam 传递活跃值,使估算在每一步都精确。 +- **承载前缀的专用会话事件**:否决。header 事件在设计上就是请求的非历史记录;第二个事件会成为同一事实的第二个归属,以及又一个需要保持完整的编解码器。 + +## 后果 + +- `agent/pre-step` 和 `CompactService.compactIfNeeded` 携带 `sessionPrefix` 参数:每个 pre-step 监听器和压缩后端都能看到真实的每实例值(所有仓库内实现在同一个变更中更新,遵循预发布立场)。 +- 内容在会话中途变化的贡献者不会被重新读取,直到下一个实例——这是设计意图。需要会话中途目录更新的部署应将变更通知路由到仅追加历史通道,支付一条持久化 `context/message`。 +- 被放弃的 `after` 槽位使请求尾部没有仅请求通道;仓库中没有任何东西需要它,且加回它会重新引入该设计旨在避免的每步重复支付成本。 +- `request/header-delta` 的 `messagePrefix` 分支(整数组替换,空数组编码向缺失的过渡)为编解码器完备性而存在;循环从不行使它,因为缓存的前缀在实例内不可变。 +- 空组合是规范的缺失状态:无贡献者的部署不记录额外 header 字节,其请求就是裸派生。 diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml new file mode 100644 index 0000000000..03817c1073 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-08-repeat-tool-guard.md: 04d5d077a42b54ca7dc04a1efc9ea2f4034b642b +2026-07-08-repeat-tool-guard.zh.md: e20bd06a6902f9fadb77a90e719aaf703d7067cc diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md index 324aa37256..04d5d077a4 100644 --- a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md @@ -1,5 +1,7 @@ # RFC: Repeat-tool-call guard plugin +English | [中文](2026-07-08-repeat-tool-guard.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md new file mode 100644 index 0000000000..e20bd06a69 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md @@ -0,0 +1,76 @@ +# RFC:重复工具调用守卫插件 + +Status: implemented + +[English](2026-07-08-repeat-tool-guard.md) | 中文 + +## 问题 + +模型陷入循环时会反复发出参数逐字节相同的工具调用——重新运行一个失败的 grep、重新读取一个未变化的文件、轮询一个已经给出答案的命令——每一轮往返都消耗 token、挂钟时间和(对付费 API 而言)金钱,却不带来新信息。harness 目前没有任何机制能察觉这一点:循环没有步骤预算,没有插件追踪调用重复,模型只有在碰巧自行改变行为时才能脱困。这种失败模式真实存在且易于检测——[pi-repeat-tool-guard](https://github.com/Kingwl/pi-repeat-tool-guard) 正是将此作为 pi coding-agent 扩展发布的:统计连续相同调用次数,超过阈值后追加一条 `<system-reminder>` 告知模型停止重复、改变策略。 + +harness 已经具备 pi 扩展所用的全部 seam,且更好:[拦截 seam RFC](2026-06-30-interception-seams.md) 赋予 `tools/post-execute` 一种正式途径,可以在已完成的调用上附加面向模型的上下文;循环缓冲并注入该上下文,保持调用/结果的邻接关系;注入的上下文是一条已记录的 `context/message`——因此原生守卫无需新增会话事件即可满足「模型可见 ⟺ 已记录」规则。缺的只是插件本身。 + +## 决策 + +守卫是一个循环卫生插件,而非面向模型的工具。它统计对同一工具以相同规范化参数发起的连续调用次数,并在配置的阈值处注入建议性提醒。它从不延迟、阻塞或改写调用;模型自行决定是否换一种方式重试或结束。 + +该插件为 `@deepseek-ai/dsh-repeat-tool-guard`,位于 `packages/guard/repeat-tool-guard/`,开辟 `guard/` 分组用于循环卫生插件(单包分组有先例:[todo-write RFC](2026-06-29-todo-write-tool.md) 发布了 `todo/tool-todo`)。它注册三个监听器,所有状态保存在以 `AgentId` 为键的插件局部 map 中——工具注册表是 context 级别的单例,其 waterfall(瀑布式事件)交错所有 agent 的调用(subagent 运行在同一 context 上),因此按 agent 分键是正确性要求,而非锦上添花。 + +- **`tools/post-execute`(waterfall)**——唯一的检测点。监听器同时接收 `(exec, result)`,因此计数和提醒投递无需跨事件的 pending map(pi 扩展需要 pending map 仅因其 `tool_call`/`tool_result` 钩子是独立事件)。它始终通过 `next()` 委托,当命中阈值时,将提醒折叠到下游决策的 `additionalContext` 上——这正是[钩子桥接](2026-06-30-hook-bridges.md)已在使用的「观察并丰富」姿态,遵守 waterfall 契约。计数放在此处而非 `tools/pre-execute`,是因为 post-execute 也会为被拒绝的调用触发(`ToolRegistry.execute` 将 deny 路由到同一流水线),而模型反复锤击一个被拒绝的调用恰恰是值得打破的循环。 +- **`agent/prompt-submit`(waterfall)**——纯重置钩子:通过 `next()` 委托,清除提交 agent 的链。用户介入改变了上下文;跨越介入的重复不是循环。 +- **`agent/status`(emit)**——在 `disposed` 时丢弃该 agent 的状态,限制 map 在 harness 生命周期内的增长。 + +### 检测语义 + +链的键为 `(tool name, canonical arguments)`;与前一次被追踪的调用相同则递增该 agent 的连续计数器,不同则重置为 1。规范化方式为深度键排序加 `JSON.stringify`:`ToolExecution.arguments` 按构造即为循环中 `JSON.parse` 的输出(或参数 JSON 格式错误时的原始字符串回退,其本身也是可比较的值),因此 pi 原版对 bigint/循环引用/`undefined` 的处理在此没有输入,被有意去除。 + +两条刻意的规则,均记录在[包 README](../../../../packages/guard/repeat-tool-guard/README.md) 中,因为它们是读者不看文档会猜测的行为: + +- **未追踪的调用对链透明。** 被 `include`/`exclude` 排除的调用既不递增也不重置计数器,因此 `grep X → todo_write → grep X` 在 `todo_write` 被排除时仍计为两次连续的 `grep X`。这正是排除有用的原因——夹在循环中的记账工具不得洗白循环——也是 pi 扩展的(未文档化的)语义,有意保留并写明。 +- **没有 agent 的调用被忽略。** 直接调用 `ctx.tools.execute()` 的调用方(测试、非循环消费方)没有可提醒的模型,也没有可作键的 `AgentId`。 + +### 提醒投递 + +提醒使用 `additionalContext` 并标注插件来源,保留原始 `tool/result`。首次阈值发出简短提示;后续阈值包含工具名、计数和有长度上限的参数预览,而比较仍使用完整的规范化字符串。已有的下游上下文在守卫的 source 下拼接,因为 `HookContext` 支持单一 source。 + +### 配置 + +```yaml +- id: repeat-tool-guard + name: '@deepseek-ai/dsh-repeat-tool-guard' + config: + thresholds: [3, 5, 8] # default; consecutive counts that trigger a reminder + include: [] # tool-name patterns to track; empty ⇒ all tools + exclude: [todo_write] # tool-name patterns transparent to the chain + argumentsPreviewChars: 500 # default; cap on arguments quoted in the detailed reminder +``` + +`thresholds` 在加载时校验,空列表、非整数、小于 2 的值或重复值都会抛出异常——配置错误大声失败,取代 pi 原版的静默回退到默认值。`include`/`exclude` 条目支持 `*` 通配符。模式是对调用时实际存在的工具名的谓词,而非对注册表条目的引用,因此匹配不到任何当前已注册工具的条目不是错误——与 `toolOrder` 的引用检查不同,`exclude: [mcp_*]` 在未加载 MCP 工具的部署中必须保持有效。 + +## 测试 + +- **单元测试:** 使用脚本化适配器的真实循环覆盖计数与重置规则、未追踪透明性、dispose 清理、按 agent 隔离、规范化参数键序、升级、被拒绝的调用、无 agent 执行、通配符转义、无效配置,以及下游阻塞或替换决策,达到逐文件 100% 覆盖率。 +- **快照测试:** keyless 的 `repeat-tool-guard` 场景发出五次相同的 `todo_write` 调用,将第三次的温和提醒和第五次的详细提醒固定在 ACP 输出和会话日志中。该插件在实时示例中加载,但在其他场景中保持静默。 +- **E2e:** 无;该插件是确定性的且与提供方无关,其 seam 契约由各自的所有者覆盖。 + +## 曾考虑的替代方案 + +- **将提醒追加到工具结果中**(`accept` 并替换 `content`——pi 扩展的机制,它修改结果内容是因为那是其 API 提供的唯一通道):否决。这会让已记录的 `tool/result` 对工具实际返回的内容撒谎,而 `additionalContext` 正是为 post-execute 评注设计的独立正式通道,循环级缓冲保持了调用/结果的邻接关系。 +- **在 `tools/pre-execute` 中计数并使用 pending-reminder map**(pi 的两阶段形态):否决。post-execute 单独就能同时看到 `(exec, result)` 且也会为被拒绝的调用触发,因此一个监听器、无跨事件状态,以更少的机制覆盖严格更多的尝试。 +- **在最高阈值升级为 `block`**:在初始范围内否决。阻塞调用会惩罚合理的相同重复(轮询长时间运行的终端、重新检查 agent 预期会变化的文件),而建议性提醒让模型保持控制权。待有证据后重新审视;决策形状(`PostToolDecision`)已支持此选项。 +- **通过 CC/Codex 桥接的按部署外部钩子**(`PostToolUse` 脚本):否决作为最终答案。它对单个部署有效,但一个已发布、有单元测试、可通过 `cordis.yml` 配置的插件才是 harness 原生形式,且无逐调用的子进程开销。 +- **在 `agent-loop` 中设置循环级步骤或重复预算**:否决。「用插件,不改循环」;硬性步骤预算是更粗粒度的正交控制,需要单独的提案。 +- **模糊/近似相同检测**(路径归一化、相似但不完全相同的参数):否决。规范化后的精确匹配廉价、确定性强且可向模型解释;相似度阈值会引入误报,在复杂度得到证据支撑之前不应引入。 +- **将包放在 `core/`**:否决。core 是产品主干;行为守卫是可选的叶子插件,`todo/` 先例表明每个插件家族用一个小型专属分组。 + +## 后果 + +- 提醒在设计上是建议性的:有意重复相同调用的幂等轮询模式在超过阈值后仍会收到提示,减压阀是配置(`thresholds`、`exclude`)加上提醒文本中明确允许「在已收集足够证据时结束」的措辞。每次触发在下一次请求中增加提醒 token 开销;阈值限制了触发频率。 +- 链状态仅存于内存:从持久化恢复的会话以全新的链开始,因此跨越恢复的循环比实时循环更晚收到提醒——可接受,守卫是启发式提示而非已记录的不变式,持久化计数器状态带来的收益不值得其复杂度。 +- 当多个 post-execute 生产者在同一次调用上附加上下文时,折叠在守卫的 `source` 下拼接;插件间的顺序遵循监听器注册顺序。该 seam 无法表示混合来源——这是继承自 `HookContext` 的限制,不属于本插件。 + +## 延后 + +- 上下文压缩(compaction)不重置链:压缩后的历史改变了模型所见,但重复风险通常在压缩后仍然存在。 +- 在高阈值升级为 `block` 未实现;`PostToolDecision` 已支持此选项,待证据出现后可启用。 +- subagent 的链按 agent 隔离;在出现具体需求之前不引入共享机制。 diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml new file mode 100644 index 0000000000..e667e7a029 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-08-self-referential-cordis-toolset.md: 62b97dc4bdbd0e0b5b1f67f77c763065c79964ed +2026-07-08-self-referential-cordis-toolset.zh.md: ce220d256dbb3d43514702e57e71728fdc82a788 diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md index 7ea5f4390e..62b97dc4bd 100644 --- a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md @@ -1,5 +1,7 @@ # RFC: The self-referential cordis toolset +English | [中文](2026-07-08-self-referential-cordis-toolset.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md new file mode 100644 index 0000000000..ce220d256d --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md @@ -0,0 +1,82 @@ +# RFC:自引用 Cordis 工具集 + +Status: implemented + +[English](2026-07-08-self-referential-cordis-toolset.md) | 中文 + +## 问题 + +本 harness 中的一切都是 Cordis 插件,但运行在该插件运行时内部的 agent(智能体)既看不到也碰不到它:它无法枚举周围的服务和事件,无法在会话中途为自己添加新工具,也无法组合自己发明的能力。把这种能力交给模型值得探索——一个能审视并修改自身运行时的自引用 agent——但它同时引出三个正确性问题,而本设计的核心正是回答这些问题,而非单纯的「让模型执行代码」机制。 + +第一,模型编写的注册必须在注册发生时就被校验:格式错误的工具 schema 必须在注册时失败,而非等到后续请求尝试将其组装进提示词时才暴露。第二,模型编写的代码需要调用它从未见过源码的服务 API——猜测方法签名,更糟的是猜测返回值形状,会耗费大量盲目试探步骤。第三,模型挂载的一切都必须完全可 dispose(资源释放):模型可以按需释放,宿主插件重载时普通的插件生命周期也能释放,否则长会话会积累遗留的监听器和工具。 + +## 决策 + +该工具集以 [`@deepseek-ai/dsh-tool-cordis`](../../../../packages/cordis/tool-cordis/README.md) 发布——一个新的顶层 `packages/cordis/` 分组——并由 [`examples/cordis-agent`](../../../../examples/cordis-agent/README.md) 演示。它为模型提供三个工具,操作模型自身运行其中的活跃 Cordis 运行时:审视它、向其中挂载模型编写的插件、再将它们 dispose。 + +vm 隔离了意外的全局污染,上下文门面隐藏了框架内部实现。二者都不限制已暴露服务的权限:一个挂载可以调用 `ctx.bash` 以宿主执行器的权限运行命令,也能触及真实文件系统和网络服务。这是一个需要主动启用的开发工具,信任等级与 bash 等同,既不是安全边界,也不是产品默认配置。 + +### 三个工具 + +| 工具 | 契约 | +|---|---| +| `cordis_inspect` | 对活跃运行时的只读报告,每个 `what` 值对应一个 Markdown 段落(省略 `what` 则返回全部段落)。从不修改状态。 | +| `cordis_mount` | 在 `node:vm` 沙箱中执行 `code`(一个异步 JavaScript 函数体);代码必须 `return` 一个 Cordis 插件,该插件作为 `cordis-dynamic` 分组 fiber 的子节点挂载,并以一个新生成的 id(`dyn-1`、`dyn-2`、……)追踪。 | +| `cordis_unmount` | 按 id dispose 一个动态挂载,并等待 disposal 达到静止——该插件所做的每一项注册都被撤销,而不仅仅是请求停止。 | + +`cordis_inspect` 的段落:`services`(每个已提供的 ctx 服务及其所属 fiber,非活跃的 owner 会被标记)、`plugins`(来自 `ctx.registry` 的所有已加载插件的扁平列表及其生命周期状态——展示加载了哪些能力,刻意不展示树形结构)、`tools`(模型可调用的工具)、`dynamic`(挂载表:id、名称、状态、提供的服务、等待的服务)、`api`(来自生成目录的活跃服务签名及其引用的类型形状)、`events`(harness 事件及其分发模式和签名)。面向模型的工具描述携带模型在调用时所需的操作规则;[生成的工具目录](../../../tool-catalog.md)是其完整渲染。 + +### 沙箱语义 + +挂载代码作为异步函数体在一个新的 vm realm 中运行。其文档化的接口面将文件、网络、进程和定时器访问引导至 Cordis 服务,使挂载保持可审视和可 dispose。宿主 realm 的辅助手段仍使 Node 逃逸成为可能,与信任姿态一致。`vmTimeoutMs` 仅约束同步执行部分。 + +沙箱全局变量刻意精简:一个带标签的直通 `console`(在宿主 stdout/stderr 上输出 `[cordis:<id>] …`,使得挂载调用结束很久后触发的监听器仍能输出到用户可见之处)、`harness.defineTool` / `harness.registerTool` 注册对、新 vm 上下文缺少的编码原语(`btoa`/`atob` 作为宿主闭包封装 `Buffer`——这是一个经过批准的例外,`Buffer` 本身从不暴露——加上 `TextEncoder`/`TextDecoder`),以及对被扣留的 Node API 的可调用陷阱(`require`、`setTimeout`/`setInterval`/`setImmediate`/`clearTimeout`/`clearInterval`、`fetch`),调用时抛出错误并指名 Cordis 替代方案。只有函数形状的全局变量被陷阱拦截;`process` 和 `Buffer` 保持 `undefined`,使 `typeof` 特性探测保持惰性而非触发抛出异常的访问器。 + +挂载代码通过三道控制跨越 vm 边界。双 realm `instanceof` 同时识别宿主和 vm 对象。`harness.defineTool` 将结果规范化为宿主 realm 的 JSON,并在记录日志前校验 `ToolExecuteReturn` 形状。挂载的插件接收一个白名单上下文门面,而非原始或直通的 `Context`;框架管道和以 context 为值的返回会被拒绝。服务读取要求声明 `inject`,保持 Cordis 的激活和卸载语义。`ctx.tools.get` 仅暴露 schema 视图,使挂载代码无法绕过 `ToolRegistry.execute` 直接调用定义。 + +边界将无歧义的 JSON-Schema 形式规范化为 `SchemaSpec`,包括对象包装、`integer` 和可选字段。无效词汇会失败并给出可接受的替代方案。解析错误、TypeScript 错误、缺少 return、Node API 错误和重复工具错误会包含相关源代码行或纠正性契约,但不叙述实现内部细节。 + +### 动态分组与挂载生命周期 + +所有动态挂载都是工具插件下方一个 `cordis-dynamic` 分组的子节点,因此普通的 fiber disposal 即可处理重载和卸载。挂载会等待 settlement;启动失败会在返回错误前 dispose 该 fiber。已 settle 但处于 pending 状态的挂载仍然可见,并列出其缺失的注入。`cordis_unmount` 等待挂载 fiber 的 disposal。 + +### 通过 provide/inject 实现跨挂载组合 + +挂载之间通过普通的 Cordis 服务语义相互关联,以各自的 id 作为生命周期句柄:挂载 A 调用 `ctx.provide('foo', value)`,挂载 B 声明 `inject: ['foo']` 并在 `foo` 存在的瞬间激活;如果 B 先挂载,它会保持 pending 状态并列出缺失的服务;卸载 A 会使 B 回到 pending(其注册被撤销),之后重新 provide 会通过一个新的沙箱门面重新运行 B 的 `apply`;重复 provide 会大声失败并指名拥有该服务的 fiber。一个 realm 注意事项:挂载提供的服务值是 vm realm 对象——从任何地方调用其方法都能工作,但消费方不得假设其上有宿主原型。 + +### 生成的 API 目录 + +`cordis_inspect` 从生成的目录而非重复的表格提供 API 和事件数据。生成器复用 Cordis 目录的 AST 扫描,输出服务摘要、签名、事件模式、引用的类型声明和继承的上下文接口面。有歧义的类型名被省略,过大的声明被标记为截断。 + +新鲜度像所有生成产物一样受门禁保护:`pnpm run verify-cordis-api`(在 `doc-sync` 中)在内存中重新生成并在有任何 diff 时失败,因此修改了公开签名的 JSDoc 变更在不重新生成模型所读目录的情况下无法发布。运行时,inspect 工具将目录与活跃运行时取交集而非直接转储:有目录条目的活跃服务渲染摘要 + 签名,没有目录条目的活跃服务(挂载提供的)渲染名称 + 所属 fiber,有目录条目但没有活跃提供方的服务简要列出,引用的类型形状随后附上。 + +### 配置、渲染与可观测性 + +该插件暴露一个配置字段,由 schemastery 校验并记录在[配置目录](../../../config-catalog.md)中:`vmTimeoutMs`(默认 5000),挂载代码同步执行部分的毫秒上限。工具名称、`cordis-dynamic` 分组名和 `dyn-` id 前缀是结构性词汇,保持固定。三个工具均按[工具实操手册](../../../cookbook/adding-a-tool.md)渲染为 `generic` 卡片(`cordis_inspect` 为 `read`,`cordis_mount` 为 `execute` 并将代码作为 `rawInput` 携带,`cordis_unmount` 为 `delete`),不覆盖 `presentResult`。 + +「模型可见 ⟺ 已记录」成立,且不引入新的会话事件类型:挂载或卸载仅通过其自身的 `tool/call` / `tool/result` 对可见(循环会记录它),而挂载引起的工具集变化则由循环在 schema 在步骤间变化时已有的请求头 delta 日志记录。刻意不设 `cordis/mount` 溯源事件——它只会重复工具调用对已记录的内容。动态挂载是进程生命周期的,不是会话状态:恢复持久化的会话会重建对话但不会重新挂载插件。 + +## 曾考虑的替代方案 + +**用结构化的逐能力注册工具替代 `cordis_mount`。** 最诱人的替代方案是一个带有显式 `name` / `description` / `parameters` / `code` 字段的 `cordis_register_tool`(以及兄弟工具 `cordis_register_listener`、`cordis_register_service`、……),而非单一的「挂载一个插件」原语。否决原因:它唯一的真正优势——对最常见的单一场景省去插件样板——不足以抵偿其代价,而单一的挂载原语能一次性覆盖所有能力。 + +| 维度 | 结构化逐能力工具 | 单一 `cordis_mount` | +|---|---|---| +| Schema 正确性 | `parameters` 仍是模型编写的 JSON 对象,需要 SchemaSpec 校验,只是提前了一步 | 同样的校验在沙箱边界运行,同样的指导性错误 | +| 代码字段 | `execute` 体仍是 vm 中模型编写的 JS;realm 和服务调用正确性问题不变 | 一个沙箱、一条规范化路径、一道受守护的注册 | +| 能力覆盖面 | 仅限工具;监听器、服务、`inject` 关系各需另一个结构化工具——接口面无限增长 | 一套词汇(一个 Cordis 插件)覆盖当前和未来的所有效果 | +| 跨挂载组合 | 在工具注册载荷中无法表达 | 原生 `provide`/`inject`,普通 Cordis 语义 | +| 可审视性 | 注册的东西在插件列表中无法作为插件展示 | 模型挂载的东西正是 `cordis_inspect` 渲染的东西 | +| 模型易用性 | 对最常见的单一场景有优势(无插件样板) | 通过挂载描述中的规范示例加上教导正确做法的边界错误来缓解 | + +因此,正确性投入放在能一次性覆盖所有能力的地方:通过 `cordis_inspect` 暴露的生成 API 目录,以及沙箱边界校验——其错误消息教导正确的调用方式。结构化注册工具日后仍可作为语法糖添加,合成挂载代码即可;本设计不排斥它。 + +**在工具中手工维护服务/事件参考。** inspect 工具的第一版携带了一张手写的服务方法签名表。它被生成的 `api-catalog.ts` 取代,因为手写表在签名变化的瞬间就会与 JSDoc 脱节,且没有门禁检测这种漂移;而生成产物的新鲜度由与文档使用同一 AST 的检查来保证。 + +**新增 `cordis/mount` 会话事件。** 记录每次挂载(源码、名称)的持久溯源事件有明确先例(`hook/invoked`、`compact/start`)。v1 中否决:挂载和卸载已经作为 `tool/call` / `tool/result` 对可见,工具集变化已经作为请求头 delta 被记录,因此专用事件只会重复记录。如果审计用例需要将挂载溯源与工具调用分离,日后仍可添加。 + +**加固的 / 能力受限的沙箱。** 拦截 Node 内置模块并向挂载代码提供白名单门面而非原始 context,可能暗示意图是为安全而沙箱化。明确声明并非如此:陷阱和门面收窄的是挂载代码所见的*接口面*——将其引导至 Cordis 服务、远离易泄漏的 Node 内置模块和框架内部——目的是正确性和封堵未守护的 context 逃逸,但门面暴露的能力(`ctx.bash`、`ctx.fs`、`ctx.web`)触及真实运行时,因此它不是安全边界。真正的安全边界(独立进程、权限提示)对一个开发/主动启用的工具集来说超出范围,且与其核心目标——将活跃运行时交给模型——相悖。 + +## 后果 + +该工具集是刻意需要主动启用的,具有完全权限的 `ctx`,因此部署方采用它的意识程度与采用 bash 工具相同。以下事实由工具描述直接告知模型:waterfall(瀑布式事件)监听器(如 `tools/pre-execute`)如果不调用 `next()` 就返回,会否决整条链,因此挂载的监听器可以瘫痪 agent 自身的工具分发([waterfall 语义](../../../cordis-primer.md#cordis-waterfall-semantics));挂载代码在当前轮次的工具调用内运行,因此 await 任何只在该轮次结束后才 resolve 的东西会死锁;`vmTimeoutMs` 仅约束同步执行;挂载不会在会话恢复后存活。 diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml b/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml new file mode 100644 index 0000000000..eef8b3d86c --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-10-session-query-service.md: 8b742ac19fea21d8404f5f44aa64f8c3cb3efccc +2026-07-10-session-query-service.zh.md: 43175b05d82ad758a16e516f3fd8b7b650f9d762 diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.md b/docs/rfc/implemented/feature/2026-07-10-session-query-service.md index 7e13256669..8b742ac19f 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.md +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.md @@ -1,5 +1,7 @@ # RFC: Exact session query service +English | [中文](2026-07-10-session-query-service.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md b/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md new file mode 100644 index 0000000000..43175b05d8 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md @@ -0,0 +1,43 @@ +# RFC:精确会话查询服务 + +Status: implemented + +[English](2026-07-10-session-query-service.md) | 中文 + +## 问题 + +会话历史存在于两处:当前的 `SessionStore` 对象和可选的持久化后端。需要精确检查的消费方如果不借助统一服务,就得各自重复实现活跃/持久化优先级、持久化生命周期处理、原始事件 surface 分类和防御性克隆。检查点之间持久状态可能落后于活跃日志,因此单靠持久化并不是可信的当前数据源。 + +全文搜索与此相关但规模大得多。在真正的后端出现之前就设计提供方注册、抽取、同步、失效、排序和游标契约,会产生两个投机性的状态机:一个在接口服务中,另一个在最终的数据库包中。 + +## 决策 + +`@deepseek-ai/dsh-session-query` 拥有 `ctx.sessionQuery`:一个面向单一逻辑语料库的小型可信精确读取服务。它暴露 `listSessions()`、`listEvents(sessionId)` 和有界的 `readEvent(request)`。它不暴露过滤器、血缘/溯源遍历、文本抽取器、搜索请求、提供方注册或派生索引同步。 + +该服务动态观察可选的 `ctx.sessionPersistence` 绑定,但不保留持久化缓存或失效监听器。每次跨语料库列举都向活跃后端请求权威元数据,然后叠加一份新鲜的活跃 store 列表。id 匹配的条目合并为一条 `SessionRecord`:活跃 header 优先,`live`/`persisted` 独立报告来源可用性。不可变 header 不一致时报 `SESSION_QUERY_SOURCE_CONFLICT`。 + +精确目标读取首先检查活跃 store,快照活跃 header 和事件日志。此路径从不查询持久化,因此持久化后端故障不会使已知的活跃历史变得不可读。当活跃 store 中无目标时,服务列举当前持久化元数据、证明该 id 存在、加载它,并在列举/加载的 header 不一致时拒绝。所有返回的 header 和事件都经过一次 structured-clone 边界。 + +## Surface 语义 + +`dsh-session` 导出 `foldSurface(events)`,`SurfaceManager` 对其增量缓存使用相同的转换函数。fold 返回分离的当前节点以及每次替换实际移除的 seq。`listEvents()` 利用该结果将每个原始事件分类为 `current`、`shadowed` 或 `log-only`,使检查结果不会在位置替换语义上与 model-history 推导产生分歧。 + +`readEvent()` 返回完整的目标事件以及按连续 seq 排列的原始邻居。`before` 和 `after` 默认为零,各自受 `readWindowMax`(默认 50)约束。结果携带克隆的 `SessionHeader` 而非来源可用性记录,因为判断活跃目标的 persisted 标志会违反「活跃精确读取不依赖持久化健康状态」这一保证。 + +## 安全边界 + +该服务是上下文范围内的可信基础设施,而非授权层。未来面向模型的历史工具或人类 UI 将施加显式的调用方/会话作用域。本阶段不添加面向模型的工具,也不改变 transcript(文本记录)或快照 surface。 + +## 曾考虑的替代方案 + +- **让每个消费方自行实现逻辑语料库解析**:否决。来源优先级、冲突处理、可选服务生命周期、克隆和 surface 分类是共享的正确性规则。 +- **只查询持久化**:否决。检查点之间持久化可能落后于当前活跃日志。 +- **缓存持久化元数据并监听写入/删除**:否决。精确读取可以直接询问权威来源,而缓存失效在规模尚未要求之前就引入了生命周期和并发状态。 +- **现在就定义提供方无关的搜索协议**:否决。目前没有提供方消费它。第一个 SQLite FTS 包应自行拥有一个协调/事务状态机;只有当第二个实现证明了边界时,才提取更小的共享 seam。 +- **在第一阶段就包含血缘、溯源和通用过滤器**:否决。当前没有消费方需要它们,且规范日志足以在有证据时再行添加。 + +## 后果 + +第一阶段只有一个来源解析状态变量:当前挂载的持久化服务。没有提供方队列、指纹、抽取器注册表、观察代次或派生索引更新。精确读取在纯活跃部署中仍然可用,在持久化存在时具有确定性。 + +跨语料库列举和持久化精确读取每次调用都执行后端 I/O。这是有意为之:正确性来自当前权威状态,面向规模的搜索属于第二阶段的数据库。全文搜索在该包定义并实现其完整契约之前不可用。 diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml new file mode 100644 index 0000000000..ad328eaaaa --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-12-subagent-persona-tool-filter-and-depth.md: 368f3a3592c5e241bb9357d4d4ce32e175c3de45 +2026-07-12-subagent-persona-tool-filter-and-depth.zh.md: 6c1ce8ac08fe3d37c400d489808e592570ebd6c7 diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md index 3c2e17aebd..368f3a3592 100644 --- a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md @@ -1,5 +1,7 @@ # RFC: Configure subagent persona, tool visibility, and depth +English | [中文](2026-07-12-subagent-persona-tool-filter-and-depth.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md new file mode 100644 index 0000000000..6c1ce8ac08 --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md @@ -0,0 +1,94 @@ +# RFC:配置 subagent 的 persona、工具可见性与深度 + +Status: implemented + +[English](2026-07-12-subagent-persona-tool-filter-and-depth.md) | 中文 + +## 问题 + +一个可复用的 subagent 提供方解决的是「如何运行子 agent」的问题,但不同的委派工具需要不同的子 agent 行为。某个部署可能需要一个评审者 persona、一组仅限研究的工具集,或一个硬性递归上限,而不必为每种组合都创建新的提供方。 + +这些控制影响子 agent 的第一次模型请求,因此不能在子 agent 可见之后才安装。它们还需要提供方诚实地声明支持:ACP 后端不能静默接受一个仅适用于进程内的工具过滤器,而过滤器也不应在所有插件运行于同一可信进程时被描述为安全边界。 + +## 决策 + +subagent 启动有三个独立的组合控制:`persona`、`toolFilter` 和 `maxDepth`。提供方声明对每个控制的支持,服务在启动运行前拒绝不支持的请求,而进程内提供方在子 agent 尚未发布时安装所请求的组合。 + +这些控制回答不同的问题: + +| 控制 | 问题 | 结果 | +|---|---|---| +| `persona` | 哪些角色指令替换该子 agent 的部署 persona? | 一个子 agent 局部的 prompt 段落遮蔽 `deployment:persona` | +| `toolFilter` | 哪些部署全局工具进入该子 agent 的可见工具视图? | 一个有作用域的限制在添加子 agent 局部工具之前过滤全局工具 | +| `maxDepth` | 这棵委派树最深可以长到多少层? | 当子 agent 深度超过绝对上限时,启动请求被拒绝 | + +`dsh-tool-subagent` 将这些控制作为插件配置暴露,并将它们复制到每个创建的请求中。直接调用 `SubagentService` 的调用方可以按请求选择。提供方能力描述符仍然是后端能否兑现各字段的真源。 + +### Persona 是有作用域的遮蔽 + +persona 控制改变一个子 agent 而不改变部署级别的 prompt 组装。在未发布的设置阶段,进程内提供方在子 agent 作用域中注册一个名为 `deployment:persona` 的段落;普通的最具体者胜出解析规则仅在该子 agent 的组装中替换全局段落。 + +其值具有与部署 persona 相同的严格模板语义。省略时通过全局层继承部署段落;显式空字符串则以空段落遮蔽全局 persona。父 agent 和兄弟 agent 的 persona 永远不会进入子 agent 的扁平作用域。 + +这使用的是正常的系统提示词注册机制,而非第二条 persona 通道。因此第一次 prompt 看到的命名贡献与后续 prompt 和 prompt 检查工具看到的相同。 + +### 工具过滤是一条实时的全局视图规则 + +工具过滤器同时控制能力可见性与可执行查找。进程内提供方在发布前于子 agent 作用域中安装 `ToolRegistry.restrict()`,注册表的单一解析器将相同结果应用于协议格式(wire format)的工具 schema、查找、执行和 Code Mode SDK 生成。独立注册的系统提示词段落不在 `ToolRegistry` 内,因此过滤一个工具不会移除该插件的独立指导文本。 + +解析遵循以下规则: + +1. 每个限制对实时的部署全局工具注册表先应用 `allow` 再应用 `deny`。 +2. 多个限制取交集,因此每个已安装的限制都必须放行一个全局工具。 +3. 子 agent 作用域的工具在全局过滤之后添加,可以遮蔽一个已放行的全局工具。 +4. 保留的 `run_code` 呈现和其他作用域局部的协议贡献不在全局过滤器范围内。 + +当过滤器既不提供 `allow` 也不提供 `deny`,或命名了当前全局可限制集合之外的内容(包括仅作用域局部或保留的名称)时,配置会大声失败。`allow: []` 是合法的,它有意隐藏所有全局工具。这些检查能捕获拼写错误,并防止配置在无法影响所命名条目时看起来有效。 + +全局注册表保持实时。仅 deny 的过滤器会放行后续注册的全局名称(除非显式 deny 该名称);allow 列表会排除后续注册的全局名称(除非显式 allow 该名称)。移除一个全局工具会将其从所有解析视图中移除。这些语义在保持热注册的同时,使 allow 与 deny 的区别显式化。 + +### 深度是绝对的树上限 + +深度限制独立于工具可见性来约束递归委派。顶层 agent 的深度为零;进程内子 agent 的深度为其父 agent 经验证的深度加一。`maxDepth` 是一个绝对的非负安全整数,当推导出的子 agent 深度大于上限时,启动在子 agent 所有权开始之前即被拒绝。 + +每个公开入口都验证值域,而不依赖单一的面向模型的配置路径。负值、小数、负零、非有限值、不安全整数、格式错误的已存储父深度以及推导溢出都会被拒绝。省略上限则该机制不约束深度。 + +部署可以组合深度与过滤。例如,可以在深度一时保留委派工具可见但设置 `maxDepth: 1`,或在子 agent 中完全 deny 委派工具。两种选择都不改变提供方的对话历史行为。 + +### 能力门控保持提供方诚实 + +能力将请求的特性与提供方实现分离。`SubagentCapabilities` 声明 `persona`、`toolFilter` 和 `depthLimit`;`SubagentService.start()` 在调用提供方之前,对照这些标志检查请求中的每个字段。 + +这使得 spawn 和 fork 提供方可以共享进程内实现,而外部提供方只声明自己能强制执行的部分。请求永远不会静默降级:选择一个不支持的控制会产生 `UNSUPPORTED_CAPABILITY`,不会有运行或生命周期事件存在。 + +### 未发布的设置使第一次请求正确 + +所有子 agent 局部的组合在子 agent 变得可观察之前完成。进程内提供方向 agent 创建提供一个设置回调;该回调在子 agent 作用域中安装 persona、工具限制和结构化输出贡献。只有设置成功后,创建才会发布会话和 agent 并允许驱动器启动。 + +设置失败会回滚私有的子 agent。没有观察者能获取到一个「第一次 prompt 使用了部署 persona 或未过滤工具集、后续 prompt 才使用请求配置」的子 agent。 + +## 可见性不是授权 + +这些控制组合的是可信的同进程行为;它们不授权行为。`toolFilter` 改变工具注册表解析出的子 agent 视图,但它不创建父到子的授权格,不要求子 agent 是父 agent 的子集,不沙箱化插件,也不阻止持有另一个 Cordis 上下文的代码直接调用服务。 + +特别地,子 agent 局部工具在全局过滤之后添加,可能不在父 agent 的视图中。仅 deny 的子 agent 也能看到 deny 列表未命名的后续全局工具。这些是有意的实时组合语义,而非不可提权保证。 + +安全设计需要独立的授权表示、传播规则和执行时强制点。创建时的授权快照、父集合子集授权、显式的未来授权 API,以及通用的能力/输出/终止标签都不在本特性范围内。 + +## 曾考虑的替代方案 + +**为每个 persona 或工具集创建一个提供方。** 这会使共享相同传输和生命周期实现的提供方成倍增加,使动态部署配置变得笨拙,且仍然需要递归机制。提供方的职责仍然是执行传输;请求承载每个子 agent 的组合。 + +**复制父 agent 的完整工具视图。** 注册作用域设计上是扁平的,生命周期所有权不意味着可见性继承。复制已解析的视图还会冻结动态全局注册,并在未完整定义任一契约的情况下混淆组合与授权。 + +**在子 agent 创建时快照允许的全局工具。** 冻结的 allow 集合使未来注册一律不可用,但它改变了热注册语义并开启了授权设计。已实现的过滤器保持为实时注册表谓词,并直接记录 allow 与 deny 的行为。 + +**仅隐藏工具 schema。** 仅呈现层的过滤让模型可以通过 Code Mode 或伪造调用执行一个 prompt 声称不存在的工具。改为由一个解析器同时管控呈现与执行。 + +**仅用工具过滤来阻止递归。** 移除委派工具有用但依赖特定提供方,且无法保护直接的服务调用方或替代委派工具。绝对深度是一个独立的结构性约束。 + +## 后果 + +贡献者可以配置子 agent 的角色、可见全局工具和递归深度,而无需定义新的提供方。能力检查在所有权开始前失败,未发布的设置使第一次请求一致,单一工具解析器防止呈现/执行漂移。 + +代价是部署方必须理解实时 allow/deny 行为以及可见性与授权的区别。提供方作者必须准确声明每个支持的控制,进程内提供方必须在发布前安装所有请求的贡献。这些控制有意不解决安全隔离或父到子的不可提权问题。 diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml new file mode 100644 index 0000000000..31c5a1b2e0 --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-doc-sync-enforcement.md: 44ea84daddcae73ce07b0a8240f83ee9945e449d +2026-06-11-doc-sync-enforcement.zh.md: e7abe2d87fd97211f653b63ddb8818077532af48 diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md index 8fd37a1656..44ea84dadd 100644 --- a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md @@ -1,5 +1,7 @@ # RFC: Doc-sync enforcement +English | [中文](2026-06-11-doc-sync-enforcement.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md new file mode 100644 index 0000000000..e7abe2d87f --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md @@ -0,0 +1,32 @@ +# RFC:Doc-sync 强制 + +Status: implemented + +[English](2026-06-11-doc-sync-enforcement.md) | 中文 + +## 问题 + +AGENTS.md 承诺文档与代码严格同步,但这一承诺此前只靠肉眼验证。评审曾两次发现漂移:一次是实操手册(cookbook)示例与类型策略矛盾,一次是 README 引用了错误的 `registerAdapter` 调用。失去同步的文档比没有文档更糟;而本代码库主要由 agent 构建,agent 对门禁的遵从远比对行文的遵从可靠(机械质量门禁)。有两类文档漂移可以被机械检查:不再能编译的代码块,以及重复了 `interface Events` 声明的事件分类体系表。 + +## 决策 + +两道门禁,沿用既有的 `scripts/` 风格(tsx ESM,每个脚本一项职责): + +1. **`doc-typecheck`** 从 `README.md`、`docs/**` 和 `packages/*/README.md` 中提取所有 ` ```ts ` 围栏代码块,写入一个继承根 `tsconfig.json` 的临时项目,然后用 `tsc -b` 编译。临时项目复用源码的 `paths` 映射和根 project references,因此文档示例能看到源码,而 vendor 代码仍在其自身的 tsconfig 设置下被检查。刻意作为草图的代码块可以用显式的 ` ```ts ignore-check ` 信息字符串退出检查;脚本会报告退出比例,超过一半则失败,防止逃生口悄悄变成常态。 +2. **`verify-event-taxonomy`** 从 `packages/*/src` 的 `interface Events` 块中提取事件名,再从 `docs/architecture.md` 的分类体系表中提取事件名,断言两个集合完全一致。只校验、不生成:表格保留手写的 Mode/Purpose 列,只检查名称集合。(落地此门禁时发现了表格缺失的三个事件:`tools/change`、`llm/adapter-change`、`system-prompt/change`。)**已被取代**:[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)取代了此门禁及其 `architecture.md` 表格,改为完全生成的 `docs/cordis-catalog/events.md` + `docs/cordis-catalog/services.md` 及其 `verify-cordis-catalog` 新鲜度门禁。本文的其他门禁(`doc-typecheck` 以及下文修订的 `verify-md-wrap`)不受影响。 + +两者通过一个共享的 `doc-sync` package.json 脚本运行,lefthook pre-push 钩子和 CI 都调用它([机械质量门禁](2026-06-11-quality-gates.md):钩子和 CI 调用相同的脚本,因此门禁在推送前就在本地触发,而不仅仅在推送后)。它们在 `pnpm run typecheck` 之后运行,后者校验 doc-typecheck 所引用的 package/vendor 构建图。 + +**修订(2026-06-17):** 第三道门禁 **`verify-md-wrap`** 后来也被纳入 `doc-sync`。它用 `mdast-util-from-markdown` + GFM 解析范围内的每个 Markdown 文件(`README.md`、`docs/**`、`packages/*/README.md`,加上 `AGENTS.md` / `packages/AGENTS.md`),对任何跨越多行的 `paragraph` 节点报错,强制执行 docs/AGENTS.md 中「一个段落一个物理行」的写作规则。同样遵循只校验不生成的原则:它报告硬换行,从不重写,因此不会引入格式化噪音。`doc-sync` 现在包含三道门禁。 + +## 曾考虑的替代方案 + +- **API-extractor 黄金报告**([已推迟的提案](../../proposed/process/2026-06-11-api-extractor-reports.md)):有意推迟。对于评审者已经能看到源码 diff 的内部 monorepo 而言价值不高,且依赖笨重、配置繁琐。 +- **从源码生成分类体系表**而非校验名称:否决,机制比问题本身更重;表格保留手写的 Mode/Purpose 列,直到[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)完全取代了这项检查。 + +## 后果 + +- 可机械检查的文档漂移现在会让 pre-push 钩子和 CI 失败,而非等待评审者发现。这是「机械门禁优于行文约定」原则的一个实例。 +- 让文档代码片段可编译需要少量 stub import 或 `declare`;`ignore-check` 比例必须保持低位,否则门禁形同虚设(比例守卫强制执行这一点)。 +- 分类体系检查仅限名称:Mode 或 Purpose 列的错误仍需人工评审。 +- 如果这些包(package)将来对外发布,API 报告仍可重新考虑。 diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml new file mode 100644 index 0000000000..addb813047 --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-quality-gates.md: 9862dc019dd6ff3b4639983821256395d0ee7b77 +2026-06-11-quality-gates.zh.md: 7a9dd7cead0e7a4964a44b650664ceb7ff570c7b diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.md b/docs/rfc/implemented/process/2026-06-11-quality-gates.md index 9f92791f4a..9862dc019d 100644 --- a/docs/rfc/implemented/process/2026-06-11-quality-gates.md +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.md @@ -1,5 +1,7 @@ # RFC: Mechanical quality gates over prose guidelines +English | [中文](2026-06-11-quality-gates.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md b/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md new file mode 100644 index 0000000000..7a9dd7cead --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md @@ -0,0 +1,28 @@ +# RFC:以机械质量门禁取代行文约定 + +Status: implemented + +[English](2026-06-11-quality-gates.md) | 中文 + +## 问题 + +本代码库主要由 coding agent 开发。相比行文约定,agent 遵守强制门禁的可靠性远高得多;而当劳动由 agent 完成时,「工作量大」不构成成本论据。早期证据:未通过类型检查的测试被提交了(vitest 不做类型检查),只在评审时才被发现。 + +## 决策 + +AGENTS.md 中的每一项承诺都对应一条退出码非零的命令,同时接入 git 钩子和 CI,两者调用相同的 package.json 脚本: + +- 最严格的 TypeScript(`noUncheckedIndexedAccess`、`exactOptionalPropertyTypes` 等);示例、测试和脚本通过根目录 no-emit `tsconfig.json` 在 CI 中进行类型检查,而 package/vendor 代码保持在各自 project-reference 边界之后。 +- ESLint strict-type-checked + @stylistic(作为强制执行的项目风格),包括文件内重复逻辑检查;vendor 代码排除在外。 +- jscpd 检测 package 生产 TypeScript 和仓库脚本中的跨文件克隆;窄范围的源码区间例外用于记录有意为之的并行实现。 +- `packages/*/*/src` 的逐文件 100% 覆盖率(v8);不可达的防御性守卫保留 `/* v8 ignore */ ` 并注明理由,而非删除。 +- knip(死代码/依赖)、publint(包正确性)、workspace 约束(workspace 规则:private、cordis peer+dev、统一版本、ESM),以及对构建出的包声明文件进行 NodeNext 消费方类型检查。 +- lefthook pre-commit(lint 暂存文件、类型检查、vendor manifest 守卫)和 pre-push(测试、hygiene);CI 在 Node 22.19/24/26 上运行完整矩阵,外加一个端到端驱动 echo-agent 的演示冒烟测试。 + +## 后果 + +- 约定在 agent 更替后仍然存续;违规在本地快速失败。 +- 门禁本身也是需要维护的代码;配置变更与其他变更一样需要评审。 +- 100% 覆盖率的压力可能催生无断言的测试——变异测试是计划中的对冲手段(见[变异测试提案](../../proposed/testing/2026-06-11-mutation-testing.md))。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml new file mode 100644 index 0000000000..d7062a1c20 --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-tsdown-over-dumble.md: c16ac691a9452d952303cf73b40693447d25015c +2026-06-11-tsdown-over-dumble.zh.md: 637a15a49bf22a0dd006039dd1ae2d0ea8120424 diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md index 1e63cef940..c16ac691a9 100644 --- a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md @@ -1,5 +1,7 @@ # RFC: tsdown for JS bundling instead of dumble +English | [中文](2026-06-11-tsdown-over-dumble.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md new file mode 100644 index 0000000000..637a15a49b --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md @@ -0,0 +1,30 @@ +# RFC:用 tsdown 替代 dumble 进行 JS 打包 + +Status: implemented + +[English](2026-06-11-tsdown-over-dumble.md) | 中文 + +## 问题 + +初始构建使用 **dumble**——cordiverse 的零配置 esbuild 包装层,上游 Cordis 本身也用它构建——与 vendor 包的约定最大程度对齐(它读取每个 package.json,从 `exports` 字段推断入口和格式)。但 dumble 作为本仓库的承重工具是一个隐患:v0.2.x,每周约 530 次 npm 下载,实质上只有一位维护者,而且由于它没有 workspace 模式,我们不得不通过一个自定义编排脚本(`scripts/build.ts`)来调用它。 + +目前构建产物只对 `pnpm run build` + publint 有意义(尚无包发布;开发/测试/演示通过 tsx 直接运行未打包的源码),因此切换成本现在最低,一旦包开始发布就只会更高。 + +## 决策 + +用 **tsdown**(基于 rolldown,每周约 250 万次下载,VoidZero 支持,活跃发布)替代 dumble: + +- 根目录 `tsdown.config.ts`,配置 `workspace: ['vendor/*', 'packages/*/*']`(显式 glob 将打包范围限定在 vendor Cordis 和 TypeScript 包树;`workspace: true` 还会发现示例 manifest 和不需要打包的 workspace 成员)。 +- 共享形态:入口 `lib/types/index.js`,`outDir: 'lib'`,ESM,`platform: node`,`target: es2024`,`fixedExtension: false`(对 `"type": "module"` 的包保持 `.js` 扩展名),`dts: false`(声明文件由 tsc -b 负责),`clean: false`(lib/ 同时存放 TSC 的 `lib/types` 中间产物树)。入口最初是 `src/index.ts`;[TSC 优先构建 RFC](2026-06-17-ts-build-config.md) 后来将 tsdown 改为打包 TSC 输出的 JS,使 TypeScript 转换行为来自同一个编译器。 +- vendor/ 中有两个逐包覆盖配置(属于我们的修改,与重新生成的 tsconfig 一样;记录在 vendor/README.md 中):schemastery(通过 `outExtensions` 输出双格式 `.mjs`/`.cjs`)、logger-console(两次单入口 pass,使共享基类内联到每个入口而非生成 hash 命名的 chunk,与上游发布形态一致)。 +- 删除 `scripts/build.ts`;`pnpm run build` = `tsc -b tsconfig.build.json && tsdown`。 + +## 曾考虑的替代方案 + +- **直接编写 esbuild 脚本**:最成熟的引擎,零包装层风险,但需要手动维护 tsdown workspace 模式自动提供的逐包规格表。 +- **pkgroll**:理念上最接近的直接替代品,但每周仅 78k 下载且基于 Rollup:维护前景严格弱于 tsdown。 +- **保留 dumble**:与上游完美对齐,但 bus factor 不可接受。 + +## 后果 + +运行时打包产物仍遵循 dumble 时代的公开入口形态(`lib/index.js`,加上包特有的变体如 `schemastery` 的 `lib/index.mjs`/`lib/index.cjs` 和 `logger-console` 的 `lib/browser.js`);声明文件现在按 [TSC 优先构建 RFC](2026-06-17-ts-build-config.md) 放在 `lib/types` 下。外部依赖仍来自各包的 dependencies/peerDependencies。我们放弃了 dumble 的 exports 字段推断能力:入口形态非默认的新包需要一个逐包的 `tsdown.config.ts`,而不能仅靠 package.json 字段。未来选项:如果 `tsc -b` 成为瓶颈,tsdown 也可以接管声明文件打包(isolatedDeclarations);那将是一个新的 RFC。 diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml new file mode 100644 index 0000000000..baaef0f47c --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-vendor-cordis-as-source.md: 39506300dec73d0c9eb1b7b2246caa23f1b10f7f +2026-06-11-vendor-cordis-as-source.zh.md: 1c942291481f50f602d6733e3c25a892885d47fe diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md index 2aa24907d5..39506300de 100644 --- a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md @@ -1,5 +1,7 @@ # RFC: Vendor Cordis as source, not npm dependencies +English | [中文](2026-06-11-vendor-cordis-as-source.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md new file mode 100644 index 0000000000..1c94229148 --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md @@ -0,0 +1,27 @@ +# RFC:以源码形式收录 Cordis,而非 npm 依赖 + +Status: implemented + +[English](2026-06-11-vendor-cordis-as-source.md) | 中文 + +## 问题 + +DeepSeek Harness SDK 基于 Cordis 框架构建。本仓库启动时,Cordis core 处于 4.0.0-rc.6(一个发布候选版本);harness 依赖框架内部实现(fiber 生命周期、effect dispose(资源释放)、waterfall(瀑布式事件)分发),这些行为的精确语义直接关系到 agent loop(智能体循环)的正确性保证。 + +## 决策 + +将所需的 Cordis 包(core、loader、include、group、timer、hmr、logger-console)及 cordiverse 基础库(cosmokit、schemastery)以源码形式扁平复制到 `vendor/`,保留其原始 npm 包名,使 workspace 解析透明。真正的第三方依赖(js-yaml、chokidar、@standard-schema/spec 等)仍留在 npm。 + +`vendor/README.md` 是 manifest(元数据清单):记录每个包的上游仓库 + commit SHA,以及一份详尽的本地修改日志。pre-commit 守卫(`scripts/check-vendor-manifest.sh`)会拒绝未在同一次提交中更新 manifest 的 vendor 源码改动。 + +## 曾考虑的替代方案 + +- **依赖 npm 包**:否决。core 处于发布候选阶段,且 harness 依赖框架内部实现(fiber 生命周期、effect dispose、waterfall 分发),agent loop 的正确性保证取决于这些行为的精确语义;上游 RC 版本升级可能在没有本地修复路径的情况下破坏它们。 +- **传递性地收录所有依赖**:否决。真正的第三方依赖(js-yaml、chokidar、@standard-schema/spec 等)仍留在 npm;只有内部实现对我们有影响的框架层才被纳入自有管理。 + +## 后果 + +- harness 完全拥有其框架层:可审计、可打补丁、版本锁定。上游 RC 无法破坏我们,框架 bug 可以在仓库内直接修复。 +- 上游同步是手动的(manifest 中记录了操作步骤)。修改日志使 diff 面始终可知。 +- vendor 包保留上游代码风格;lint 与严格性门禁将其排除(它们的 tsconfig 在本地放宽了我们较新的编译器 flag)。 +- 从第一天起就存在一个本地补丁:移除了 HMR 的 locale-YAML 导入(运行时 YAML 导入钩子未被收录)。 diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml new file mode 100644 index 0000000000..c2b598e0db --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-16-pnpm-over-yarn.md: 6e7a6e1f53056e36f54f44b87b305afa593da549 +2026-06-16-pnpm-over-yarn.zh.md: 809f10dbd63d347eccb4d00641a39da51788ee9f diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md index 7a574a3388..6e7a6e1f53 100644 --- a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md @@ -1,5 +1,7 @@ # RFC: pnpm as the package manager instead of Yarn 4 +English | [中文](2026-06-16-pnpm-over-yarn.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md new file mode 100644 index 0000000000..809f10dbd6 --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md @@ -0,0 +1,43 @@ +# RFC:以 pnpm 替代 Yarn 4 作为包管理器 + +Status: implemented + +[English](2026-06-16-pnpm-over-yarn.md) | 中文 + +## 问题 + +本仓库最初使用 **Yarn 4** 搭配 `node-modules` linker 发布——这是一个刻意保守的选择:行为类似 npm 的扁平布局,同时提供 Yarn 的 workspace 和 `yarn constraints`。它能用。但 Yarn 4 的 Plug'n'Play 血统使得 `node-modules` linker 成为非主流模式,而更广泛的 JS 生态——工具默认值、CI action、Corepack 示例、贡献者熟悉度——正日益以 pnpm 为中心。对于一个主要由 agent 构建、偶尔有人类贡献者阅读的仓库来说,「大多数工具和人所预期的包管理器」具有实际价值:更少的意外、更成熟的故障路径、更多可直接复用的答案。 + +切换成本目前处于最低点。本仓库尚无任何包发布(所有 package 均为 `private: true`);开发/测试/演示全部通过 tsx **未构建**运行,因此包管理器只需做到 (a) 解析并链接 `node_modules`,(b) 运行 workspace 脚本,(c) 强制执行 workspace 约束。唯一的 Yarn 专属资产是 `yarn.config.cjs`(`@yarnpkg/types` 约束引擎),体量小且可机械地重新表达。这与 [tsdown 决策](2026-06-11-tsdown-over-dumble.md)的逻辑一致:趁爆炸半径还小,把承重工具换成生态更健康的选项。 + +## 决策 + +采用 **pnpm 11.7.0**,通过 `packageManager` 字段固定、经 Corepack 安装(与 Yarn 使用的机制相同): + +- **Workspace** 从 `package.json` 的 `workspaces` 数组加 `.yarnrc.yml` 迁移到 `pnpm-workspace.yaml`(`vendor/*`、`packages/*`——相同的 glob;`examples/*` 保持非 workspace,与先前设置及 tsdown 的显式 glob 一致)。 +- **严格符号链接 linker**(pnpm 默认)取代 Yarn 的 hoisted `node-modules` linker。我们刻意**不**添加 `node-linker=hoisted` / `shamefully-hoist` 逃生口:pnpm 的非扁平 `node_modules` 会让幽灵依赖(引用未声明的传递依赖)大声失败,这对一个以机械门禁为整体质量策略的仓库而言是一个*优点*(见[机械质量门禁](2026-06-11-quality-gates.md))。门禁套件——类型检查、lint、测试、构建、knip——是安全网,证明不存在此类幽灵引用。 +- **构建脚本白名单。** pnpm 10+ 不运行依赖的生命周期脚本,除非显式列入白名单。`pnpm-workspace.yaml` 携带一份显式的 `allowBuilds` 映射(`esbuild`、`lefthook`、`@google/genai`、`protobufjs`)——与本仓库对模型/工具输出已有的供应链加固姿态一致,现在将其扩展到安装时的代码执行。`peerDependencyRules.allowedVersions.typescript: '>=5 <7'` 消除仓库内 TypeScript 的良性 peer 范围警告。 +- **约束变为包管理器无关。** `yarn.config.cjs`(导入 `@yarnpkg/types`、使用 `Yarn.workspaces()` / `workspace.set()`)被 `scripts/check-workspace-constraints.ts` 取代——一个纯 tsx 脚本,以 `pnpm run constraints` 运行。它在相同的 `vendor` + `packages` 范围上强制执行完全相同的不变式:所有 package `private: true`;`@deepseek-ai/dsh-*` 包将 `cordis` 同时声明为对等依赖(peer dependency)和 dev 依赖且范围匹配、使用根 `package.json` 的版本、设置 `type: module`;vendor 包仅检查 privacy。 +- 所有 CI、lefthook 钩子、`package.json` 脚本和文档中的 `yarn …` 动词统一改为 `pnpm …` / `pnpm run …`。`yarn.lock` → `pnpm-lock.yaml`(lockfile v9)。`.gitignore` 将 `.yarn/` 换为 `.pnpm-store/`。vendor README(如 `vendor/cordis/README.md`)按 Vendoring Policy 保留其上游的 `yarn` 示例不动。 + +## 曾考虑的替代方案 + +- **保留 Yarn 4**:零变动,但押注于使用者更少的 linker 模式和绑定单一包管理器的约束引擎。 +- **npm workspaces**:无处不在,但没有约束机制,monorepo 人体工学也更弱。 +- **pnpm 搭配 hoisted linker**:迁移更平滑,但放弃了幽灵依赖安全性——而这正是迁移的首要正确性理由。 + +## 后果 + +约束检查失去了 Yarn 的自动**修复**能力(`workspace.set()` 可以就地改写 manifest);tsx 脚本仅做检查,不通过时以非零退出码加消息退出。这是可接受的:CI 从未运行过 `--fix`,且需要手动改一行的情况很少。贡献者现在为 pnpm 而非 Yarn 运行 `corepack enable`;`pnpm exec lefthook install` 取代 `yarn lefthook install`(`postinstall` 钩子仍会运行 `lefthook install`)。 + +性能(迁移时在开发 NFS 文件系统上测量;单次运行样本,方差大——仅供方向性参考,非基准测试套件): + +| 场景 | Yarn 4 | pnpm 11 | +|---|---|---| +| Cold (empty cache/store, no `node_modules`) | ~14 s | ~16 s | +| Warm relink (cache/store warm, `node_modules` removed) | ~12–14 s | ~15–22 s | +| Frozen, `node_modules` present (no-op revalidate) | ~2–8 s | ~0.5–7 s | + +在快速本地磁盘上,pnpm 的内容寻址 store 通常在冷/热安装上胜出,尤其在多次 checkout 的**磁盘占用**上优势明显(一个全局 store 通过硬链接进入每个 `node_modules`,而 Yarn 每个 worktree 复制约 279 MB——部分开发者日常保持约 10 个或更多 worktree)。这一去重优势在上述迁移时数据中**未**体现,因为测试 store 和 `node_modules` 位于不同文件系统,硬链接失效;在单文件系统的开发机或 CI 缓存上该优势成立。诚实的总结:在我们的 NFS 开发文件系统上,安装速度在噪声范围内不分伯仲;迁移的理由是生态对齐、幽灵依赖安全性和跨 checkout 磁盘去重——而非原始安装时间的胜出。 + +所有质量门禁(约束、类型检查、lint、doc-sync、100% test:coverage、构建、knip、publint、echo-agent 演示冒烟测试)在 pnpm 上原样通过,这是 linker 切换未引入幽灵依赖破坏的正确性证明。 diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml b/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml new file mode 100644 index 0000000000..9858ce0f2e --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-17-ts-build-config.md: cf70014b5873f74da8476c21dd71feedb956f59f +2026-06-17-ts-build-config.zh.md: f70619de5a48c7040e816c54d21f81772a51a90f diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.md b/docs/rfc/implemented/process/2026-06-17-ts-build-config.md index 0687df250c..cf70014b58 100644 --- a/docs/rfc/implemented/process/2026-06-17-ts-build-config.md +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.md @@ -1,5 +1,7 @@ # RFC: TSC-first build and one tsconfig +English | [中文](2026-06-17-ts-build-config.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md b/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md new file mode 100644 index 0000000000..f70619de5a --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md @@ -0,0 +1,78 @@ +# RFC:以 TSC 为核心的构建与统一 tsconfig + +Status: implemented + +[English](2026-06-17-ts-build-config.md) | 中文 + +## 问题 + +当时的 TypeScript 构建与类型检查配置存在以下问题: + +- `build` 使用 `tsc` 将 `packages/<group>/<pkg>` 和 `vendor/*` 下的 `.ts` 转换为 `.d.ts`,再用 `tsdown` 将 `.ts` 转换为打包后的 `.js`。这导致两个工具各自做一次 TypeScript 转换。 +- `typecheck` 倾向于通过一个根级 typecheck 配置来校验 package、vendor 源码、示例、测试和脚本。 + +目标是让 build 和 typecheck 使用一致的 tsconfig 边界与 TypeScript 解析/转换行为。build 应通过同一个编译器和配置生成 `.js`、`.d.ts`、`.js.map` 和 `.d.ts.map`,使发布产物与类型校验保持一致。 + +验证过程中发现了若干具体技术问题和可能的路径: + +- `tsdown` 使用 `oxc` 做 TypeScript 转换,其行为与 `tsc` 不同。 + - `tsdown` 输出的打包 `.d.ts` 与 Cordis 内部的相对模块增强(module augmentation)结构冲突。 + - tsc 的输出受 `allowImportingTsExtensions` 影响,因此需要确保生成的 `.js` 不会 import `.ts` 文件,且生成的 `.d.ts` 保留 NodeNext/Node16 可接受的显式相对说明符。为此,包内相对导入在 TypeScript 源码中使用显式 `.ts` 说明符,由 `rewriteRelativeImportExtensions` 在输出的 JS 中将其改写为 `.js`。 + - `tsdown` 输出的打包 `.js` 与 `tsc -b` 逐文件输出的 `.js` 行为不同,例如 decorator 转换行为。 +- `vendor/*/src`、示例、测试和脚本无法全部以 plain-include 方式放入一个根级严格程序。 + - 在根级严格配置下直接对 `vendor/*/src` 做类型检查,会触发大量不属于本项目的类型错误。 + - `packages/*/*` 对 `vendor` 的依赖解析到 `vendor/*/lib`,以适应不同的 tsconfig 严格度。 + + +## 决策 + +包内相对导入使用显式 `.ts` 说明符。 + +`pnpm run build` 分两阶段: + +- 阶段 1:`tsc -b tsconfig.build.json` 将逐模块的 `.js`、声明文件 `.d.ts`、JS sourcemap `.js.map` 和声明 sourcemap `.d.ts.map` 输出到各包的 `lib/types`。这是权威的 TypeScript 编译结果。发布时保留 `.d.ts` / `.d.ts.map`,忽略 `.js` / `.js.map`。 + - 构建项目使用 `tsc -b` 编译的 project-reference 图。例如,根 `tsconfig.build.json` 引用包和 vendor 的 tsconfig,校验并输出包/vendor 的构建结果。 +- 阶段 2:bundler 读取 `lib/types` 下输出的 JS,将打包后的运行时入口写为 `lib/index.js` 或 `lib/index.mjs`(沿用当前行为)。此阶段仅做打包,不得读取 TypeScript 源码,也不得输出声明文件。 + +`tsdown` 不再负责 TypeScript 编译或声明文件输出。 + +`pnpm run typecheck` 以 build 模式运行根 `tsconfig.json`。 +- 根 `tsconfig.json` 是唯一的开发/类型检查项目。它以 `noEmit` 检查示例、测试和脚本,并通过 references 校验包/vendor 源码。 +- 被引用的包/vendor 项目保持与 build 相同的输出行为,因此 typecheck 可以刷新它们的 `lib/types` 产物,而无需使用单独的 no-emit 图。项目特有的严格度设置放在各自的 `packages/*/*/tsconfig.json` 或 `vendor/*/tsconfig.json` 中。 +- 根 no-emit 项目禁用 `rewriteRelativeImportExtensions`;它不输出任何文件,且包含跨 project-reference 边界导入 helper 的测试。包/vendor 的输出项目保持该改写启用。 + +命令编排如下: + +```sh +pnpm run build: +tsc -b tsconfig.build.json +tsdown + +pnpm run verify-node-next-types: +tsx scripts/verify-node-next-types.ts + +pnpm run typecheck: +tsc -b tsconfig.json +``` + +`pnpm run demo:*` 仍通过 tsx 和根路径直接运行 `src`,无需编译步骤。 + +## 曾考虑的替代方案 + +- **继续使用 `tsdown`/oxc 作为 TypeScript 转换器**:oxc 的转换行为与 `tsc` 不同(decorator 转换有差异、打包 JS 与逐文件输出不同),且其打包 `.d.ts` 与 Cordis 内部的相对模块增强结构冲突。 +- **一个根级严格程序覆盖包、vendor、示例、测试和脚本**:vendor 源码在根级严格 flag 下会触发不属于本项目的类型错误;带有各项目独立严格度的 project references 才是可行的边界。 + +## 后果 + +构建职责更加清晰: + +- `packages/<group>/<pkg>` 和 `vendor/*` 下的每个模块都有一个本地 tsconfig,同时服务于 build、typecheck 以及直接运行源码的工具(如 `tsx` 和 `vitest`)。 +- `build` 命令使用 `tsconfig.build.json`。`tsc -b` 负责可发布的逐模块 `.js` 和 `.d.ts` 输出,bundler 只负责 `lib/index.*`。 + - `lib/types/*.d.ts` 和 `.d.ts.map` 是发布用的声明文件产物。 + - `lib/types/*.d.ts` 使用显式 `.ts` 相对说明符,TypeScript 的 NodeNext/Node16 解析器会将其映射到同级的 `.d.ts` 文件。 + - `lib/types/*.js` 仅作为 bundler 输入,不得用作运行时入口或公开导入目标。 + - `lib/index.*` 是发布用的运行时产物,由 bundler(当前为 `tsdown`)生成。 +- `pnpm run verify-node-next-types` 扫描构建出的声明文件,检查是否存在缺少文件扩展名的相对说明符,然后以 `moduleResolution: "NodeNext"` 对构建出的 `types`/`exports` 表面进行临时外部 ESM 消费方的类型检查,使声明说明符的回归在发布前即被捕获。 +- `typecheck` 命令使用 `tsconfig.json`。示例、测试和脚本由根 no-emit 项目检查,包和 vendor 模块保持与 `build` 相同的输出行为。包和 vendor 源码始终处于 project-reference 边界之后。 + +Cordis vendor 副本现在与上游多了一处类型结构差异。上游同步时,必须重新应用该差异或明确将其退役。 diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml new file mode 100644 index 0000000000..3773aca2f5 --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-18-markdown-cross-link-lint.md: c802b4071abf652824647e4417cde3f518776353 +2026-06-18-markdown-cross-link-lint.zh.md: abbb5930acb18287effc7c47009b9e3e910f6c89 diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md index db98c2fb7d..c802b4071a 100644 --- a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md @@ -1,5 +1,7 @@ # RFC: Markdown cross-link validity linting +English | [中文](2026-06-18-markdown-cross-link-lint.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md new file mode 100644 index 0000000000..abbb5930ac --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md @@ -0,0 +1,33 @@ +# RFC:Markdown 交叉链接有效性 lint + +Status: implemented + +[English](2026-06-18-markdown-cross-link-lint.md) | 中文 + +## 问题 + +本仓库的文档通过相对路径互相链接:`[topic](../implemented/2026-…-….md)`、`[the cookbook](adding-a-tool.md)`、`[architecture.md](../../architecture.md)`。此前没有任何机制验证这些目标是否存在。一次重命名或移动会悄无声息地打断所有入站链接,直到读者点击时才会发现。[Doc-sync 强制](2026-06-11-doc-sync-enforcement.md)已经将两类文档漂移机械化了(不可编译的代码块、陈旧的事件分类体系表),[verify-md-wrap](2026-06-11-doc-sync-enforcement.md) 处理了第三类(硬换行的行文段落),但死链接是第四类同样可机械检查的问题,此前仍靠肉眼验证。 + +直接触发本门禁的案例是引入它的那次 RFC 目录重组:将 `docs/adr/` + `docs/rfc/` 统一为一个 `docs/rfc/`,下设 `proposed/`、`implemented/`、`rejected/` 子目录,手动改写了约四十条文档间链接。任何一条路径的手误都会让断链随代码一起合入,而没有任何东西能拦住它。 + +## 决策 + +新增第四道 `doc-sync` 门禁 `verify-md-links`(`scripts/verify-md-links.ts`),风格与 `verify-md-wrap` 一致(tsx ESM、基于 AST、只验证不生成): + +- 用 `mdast-util-from-markdown` + GFM 解析范围内的每个 Markdown 文件,遍历所有 `link`、`image` 和 `definition` 节点。 +- 仅当目标是**相对路径**时才检查。跳过带协议的 URL(`https:`、`mailto:` 等)、协议相对路径(`//host`)、根绝对路径(`/path`——在 checkout 中没有稳定基准)以及纯页内锚点(`#section`)。去除 `#fragment`/`?query`,相对于链接所在文件的目录解析路径,并断言该路径在磁盘上存在。 +- 只报告,不改写;发现第一条断链即以非零状态退出。 + +范围与其他门禁一致,另加 AGENTS.md 对和 `.agents/skills/` 下仓库自有的 agent skill Markdown(这些 skill 文件交叉链接到 docs 目录树,因此本次重组也改写了其中的链接):`README.md`、`docs/**/*.md`、`packages/*/README.md`、`AGENTS.md`、`packages/AGENTS.md`、`.agents/skills/**/*.md`,按真实路径去重(`CLAUDE.md` 符号链接解析到 AGENTS.md 文件)。该门禁接入 lefthook pre-push 钩子和 CI 都会运行的 `doc-sync` 脚本,因此断链在推送前就会在本地失败——与[机械质量门禁](2026-06-11-quality-gates.md)保持一致。 + +本门禁检查的是**文件存在性**,而非锚点有效性:链接到一个真实文件但带有 `#wrong-heading` 片段的仍然通过(文件可解析;片段被剥离)。 + +## 曾考虑的替代方案 + +**锚点级有效性检查**:更重且价值更低;实际造成问题的是文件级死链接。这一范围裁剪是有意为之:作者在链接到某个锚点时自行验证 `#fragment`。 + +## 后果 + +- 重命名或移动导致交叉链接悬空时,pre-push 钩子和 CI 会立即失败,而不是等读者点击死链接才发现。这使得引入本门禁的 RFC 重组具有自验证性:同一个 PR 既改写了四十条链接,也加入了证明无一悬空的检查。 +- `doc-sync` 链中多了一个快速 tsx 脚本;无新增依赖(mdast/GFM 技术栈已在 devDependencies 中供 `verify-md-wrap` 使用)。 +- 本门禁强制的约定——通过可机械检查的相对链接交叉引用文档,而非裸文字或编号——记录在 [docs/AGENTS.md](../../../AGENTS.md) 中,让作者知道这道门禁的存在及其原因。 diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml new file mode 100644 index 0000000000..2421ac85fc --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-core-data-structures-catalog.md: 5f1232f2f0d0644d4043af217a7177451155030b +2026-06-20-core-data-structures-catalog.zh.md: d35a4d9d32eb59971bbf8b105d01dd38c0811fb0 diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md index aaac6fbd3c..5f1232f2f0 100644 --- a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md @@ -1,5 +1,7 @@ # RFC: Core-data-structures catalog and the `ts type-equiv` drift gate +English | [中文](2026-06-20-core-data-structures-catalog.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md new file mode 100644 index 0000000000..d35a4d9d32 --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md @@ -0,0 +1,60 @@ +# RFC:核心数据结构目录与 `ts type-equiv` 漂移门禁 + +Status: implemented + +[English](2026-06-20-core-data-structures-catalog.md) | 中文 + +## 问题 + +想要理解 harness 的读者可以在 [architecture.md](../../../architecture.md) 中找到它的*行为*(服务映射、会话/轮次/步骤生命周期、事件分类体系),但没有一个集中的地方描述它的*词汇*——那些行为所操作的数据结构。类型定义只存在于源码中,散落在各个 `packages/*/src/types.ts` 里,因此要理解「什么是 `Message`、`SessionEvent`、`StreamChunk`」就意味着直接阅读声明。一份行文目录会有帮助,但如果目录是对类型定义的转述或粘贴复制,那么字段一改它就会腐烂——而一份失去同步的类型文档比没有更糟,因为读者会信任它。 + +因此这项工作包含两个交织的问题:**这样一份目录应当收录什么**(范围界定问题:一个 harness 有数十个跨包(package)的类型,全部堆上去对谁都没帮助),以及**如何防止粘贴的类型定义漂移**(持久性问题)。本 RFC 记录这两项决策。它的姊妹篇 [生成式 Cordis 事件 + 服务目录](2026-06-20-generated-cordis-catalog.md) 是*接线*轴向的补充:本篇编目数据结构,那篇编目移动它们的事件与服务。 + +## 决策 + +新建 `docs/core-data-structures/` 目录编目词汇,并新增 `verify-type-equiv` doc-sync(文档同步门禁)门禁,确保每一处粘贴的类型定义与源码逐字节一致。 + +### 什么算「核心」——主干与 seam 的分界线 + +范围界定不是自上而下拍板的,而是将候选定义逐一对照具体的边界类型反复测试,直到一条规则在所有案例中都成立。决定性的测试是 `BashExecRequest`/`BashExecSpec`/`BashRunResult`:bash 是一个能力 *seam*,不属于 agent loop 主干;如果这些算「核心」,那「核心」就等于*所有跨包词汇*,目录就是一份平铺的全量转储;如果它们不算,「核心」就意味着*中央主干*,bash 词汇属于子页面。后者胜出,由此确定了整体结构:一个**分层目录**,而非一份平铺文档。 + +解决剩余案例的规则:***你编写、持有或接收的类型是核心;为其提供类型推导、渲染或持久化的机制是子页面细节。*** 逐一验证如下: + +- 一个数据结构是**核心**的,如果它流经 agent loop 主干——无论加载了哪些插件,循环在每个轮次都持有、派生、流式输出或记录它(`Message`、`StreamChunk`、`SessionEvent`、`Agent` 句柄)——**或者**它是插件作者面向某条流水线编写的唯一标题类型(`ToolDefinition`)。 +- `ToolDefinition` 是核心(它是每个工具作者编写的东西),**即使循环从不持有它**——对于这一个标题类型,撰写重要性覆盖了严格的「流经主干」规则。但它的类型推导机制——`SchemaSpec`/`InferArgs` DSL——是子页面细节(你编写的是 `ToolDefinition`;为其提供类型推导的机制你不直接接触)。这就是主干与 seam 分界线的精确表述。 +- `ToolSchema` 是核心(它是 `GenerateOptions` 的字段,而 `GenerateOptions` 是流经每个步骤的模型请求),即使它在概念上属于工具流水线——当*流经主干*与*概念归属*冲突时,前者胜出。 +- 工具展示词汇(`ToolCallView`/`ToolResultView` 等)、`SessionPersistence` 持久性 seam 以及 bash 词汇是子页面。 + +`core.md` 是一份**自包含的主干文档**:它给出每个主干结构的确切类型定义,配以最少的行文,并链接到各 seam 细节的子页面。子页面包括 `llm-streaming.md`、`session.md`、`persistence.md`(沿内存模型与持久性 seam 的分界从 session 中拆出)、`tools.md` 和 `bash.md`。 + +### `ts type-equiv` 机制——逐字且防漂移 + +持久性要求很具体:文档应展示**逐字**的当前类型定义(让读者看到真实形状,而非转述),**并且**机械地保证与源码一致。仓库已经能编译围栏 ` ```ts ` 块(`doc-typecheck`),但一个真正通过类型检查的块需要 import 噪音,且只能证明*可赋值性*而非*逐字节相等*——一个改了名但类型相同的字段仍能通过。因此: + +- 类型定义逐字粘贴到专用的 ` ```ts type-equiv ` 围栏中。`doc-typecheck` 识别该围栏并跳过它(裸定义不能独立编译),并**将其排除在 opt-out 比例之外**——它是一个独立检查的类别,而非未检查的草稿。 +- 新增 `scripts/verify-type-equiv.ts`,通过 TypeScript 解析器提取每个块,并对声明的符号断言**逐字源码匹配**——之所以选择这种方式而非编译式 `_Check` 可赋值性断言,正是因为逐字节相等而非可赋值性才是我们需要的属性。 +- 来源信息保存在中央 `scripts/type-equiv.manifest.json`(`{ doc, symbol, source }` 条目)中,**而非**行文中的指令注释。脚本强制执行 **1:1 对应**:每个 type-equiv 块恰好有一条 manifest 条目,反之亦然;因此不会有块被静默漏检,也不会有条目腐烂。 +- 接入 `doc-sync`,因此与其他文档门禁在同一个 lefthook pre-push 和 CI 路径中运行。 + +### 维护是作者的职责,门禁作为兜底 + +`verify-type-equiv` 能捕获已记录类型的*粘贴漂移*,但无法告诉你一个全新的核心类型没有被记录。因此 AGENTS.md 和 `dsh-code-review` skill 已更新,要求在变更添加或重塑已记录类型时同步更新目录——门禁处理漂移,人处理新增表面。 + +## 曾考虑的替代方案 + +- **平铺转储所有跨包词汇**:`BashExecRequest` 测试案例否决了它。如果 seam 词汇算「核心」,目录对谁都没帮助;分层的主干与 seam 结构胜出。 +- **编译式 `_Check` 可赋值性断言**替代逐字源码匹配:否决,因为逐字节相等而非可赋值性才是我们需要的属性——一个改了名但类型相同的字段能通过可赋值性检查。 +- **来源信息作为行文中的指令注释**:否决,改用中央 manifest;其强制的 1:1 对应确保不会有块被静默漏检,也不会有条目腐烂。 + +## 验证教训 + +主干与 seam 规则在采纳前经过了 `BashExecRequest`、工具 schema 与定义、schema DSL、展示类型以及 session/persistence 拆分的逐一测试。 + +`verify-type-equiv` 必须扫描完整的 Markdown 范围,而不仅是 manifest 中列出的文档。否则未登记的 `type-equiv` 块会逃脱所声称的一对一检查。因此门禁将此类块报告为遗留块。本 RFC 将这条快速失败的扫描规则与主干/seam 分界和逐字匹配决策一并记录;生成式 Cordis 目录在[其 RFC](2026-06-20-generated-cordis-catalog.md) 中有对称的设计记录。 + +## 后果 + +- 词汇现在有了一个**不会静默漂移**的唯一归属地:源码中的字段重命名会在 pre-push 钩子和 CI 中使 `verify-type-equiv` 失败,直到粘贴内容被刷新。 +- 主干与 seam 分界线是一个可复用的范围界定工具,而非一次性决策:同一条「你编写/持有/接收的东西是核心;为其提供类型推导/渲染/持久化的机制是细节」规则,后来也被用于界定事件/服务目录的 harness 层与继承层分层。 +- `ts type-equiv` 围栏是继 ` ```ts `(编译)和 ` ```ts ignore-check `(草稿)之后的第三种文档块类别。后续又新增了第四种 ` ```ts cordis-catalog `(生成签名),复用了相同的跳过并排除处理。 +- 添加或重塑核心类型现在附带一项文档义务,作者必须履行(门禁无法检测缺失的*新*类型),由 `dsh-code-review` 检查清单兜底。 diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml new file mode 100644 index 0000000000..ee4e1d24fc --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-generated-cordis-catalog.md: 6b451e31965f8f00210aa927ed236fed28699351 +2026-06-20-generated-cordis-catalog.zh.md: 9c7150ff5f12d4d9e4a13158acdf8f52e84fd95a diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md index eafce4feae..6b451e3196 100644 --- a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md @@ -1,5 +1,7 @@ # RFC: Generated cordis events + services catalog +English | [中文](2026-06-20-generated-cordis-catalog.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md new file mode 100644 index 0000000000..9c7150ff5f --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md @@ -0,0 +1,41 @@ +# RFC:生成式 Cordis 事件 + 服务目录 + +Status: implemented + +[English](2026-06-20-generated-cordis-catalog.md) | 中文 + +## 问题 + +插件作者需要两个参考面,而此前没有任何单一文档能提供:他们可以监听的每一个 Cordis **事件**(含精确签名与分发模式),以及他们可以调用的每一个 `ctx.<key>` **服务**(含精确接口)。相关信息已经存在,但散落各处:`docs/architecture.md` 中一张手工维护的事件分类*表格*(名称 + 行文描述的 Mode/Purpose,由 `verify-event-taxonomy` 做名称集合校验)、一张服务映射表(8 行角色描述),以及 `interface Events` / `interface Context` 声明本身。分类表还有一个盲区:它无法捕获全新的*未记录*事件——名称集合校验器只检查两侧已有的名称。 + +这是[核心数据结构目录](../../../core-data-structures/core.md)([对应 RFC](2026-06-20-core-data-structures-catalog.md))在连线轴上的互补件:那份目录记录 agent loop 流转的*数据结构*(经校验的手工粘贴);本目录记录流转它们的*事件与服务*。 + +## 决策 + +从源码生成目录,而非手工维护表格再校验子集。 + +`scripts/gen-cordis-catalog.ts` 使用 TypeScript 编译器 API,从声明和源码 JSDoc 分别输出事件参考与服务参考。事件包含分发模式;服务包含公开签名。确定性的 `--write` 与 `--check` 模式使两个页面成为生成产物,新鲜度由 doc-sync 强制。 + +纯生成在这里是正确的,因为代码库足够规范,AST 即全部真相:每个事件/服务名称都是字符串字面量,能往返映射到一个静态声明——没有动态命名的事件,也没有仅运行时存在的服务。因此生成的文档不可能出错,并且从结构上消除了未记录事件的缺口(生成器枚举源码,而非检查手写子集)。 + +具体选择: + +- **`@mode` 标签,交叉校验。** 每个 harness 事件的 JSDoc 携带显式的 `@mode emit|waterfall|parallel|serial` 标签;缺少标签时生成器直接报错。当签名形状具有结论性时——尾部参数为 `next: () => …` 在结构上即为 waterfall——生成器断言标签与之一致,矛盾时直接报错。emit/parallel/serial 的区分在结构上不可见(`session/flush` 返回 `Promise<void> | void` 且无 `next`,有序的 `agent/pre-step` 检查点亦然),因此信任标签。撰写规则见 [AGENTS.md](../../../../AGENTS.md)。 +- **分层范围。** harness 层(8 个 `@deepseek-ai/dsh-*` 服务及其事件)从源码完整渲染。继承层(cordis-core 的 `ctx.on/emit/effect/provide/…` + `internal/*` 事件 + loader/HMR/timer)是插件同样可见的固定 vendor 源;它以精简形式渲染(名称 + 一行说明 + 源码指针),数据来自生成器中的一张手工策展表,而**不是**遍历 vendor AST——cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段(`root`、`baseUrl`、`logger`),且 vendor 表面仅在有意的 vendor 同步时才变化。 +- **交叉链接到数据结构目录。** 签名中出现的类型名(`GenerateOptions`、`StreamChunk`、`ToolDefinition` 等)链接到记录该类型的核心数据结构页面。映射是生成器中一个小型手工策展的 const,而**不是** `type-equiv.manifest.json`——后者记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 +- **专用围栏。** 签名块使用 ` ```ts cordis-catalog ` 信息字符串,`doc-typecheck` 识别并跳过它(裸签名片段不能独立编译),不计入 opt-out 比例——与 `type-equiv` 块的处理方式相同。 + +本决策**取代** [doc-sync 强制](2026-06-11-doc-sync-enforcement.md)中的事件分类部分:`verify-event-taxonomy` 及其 `docs/architecture.md` 表格退役(architecture.md 的标题保留,正文改为指向目录;服务映射角色表作为策展行文保留)。doc-typecheck、verify-md-wrap、verify-md-links 与 verify-type-equiv 不受影响。 + +## 曾考虑的替代方案 + +- **校验而非生成(退役的分类检查所做的事)**:*仅对此表面*反转了方向。这里的数据可以机械地完整获取,因此生成严格强于名称集合校验(完整签名、不会漂移、能捕获未记录事件)。 +- **遍历 vendor AST 以获取继承层**:否决,改用策展表。cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段,且固定的 vendor 表面仅在有意同步时才变化。 +- **复用 `type-equiv.manifest.json` 作为签名交叉链接映射**:否决,改用小型手工策展 const。manifest 记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 + +## 后果 + +- 目录不会漂移:源码变化而已提交文件未反映时,`verify-cordis-catalog` 在 pre-push 钩子和 CI 中失败。新事件缺少 `@mode` 标签、或标签与签名矛盾时,生成器直接报错。 +- 事件的行文描述现在只有一个归属地——声明处的 JSDoc。JSDoc 写得薄,目录条目就薄,这迫使作者在源头做好文档(生成器是 AGENTS.md「每个导出都有语义 JSDoc」规则的强制函数)。 +- 继承层是手工摘要的,因此 vendor 同步若增加或重命名了 cordis-core 事件或 `ctx` 成员,需要同步编辑 `gen-cordis-catalog.ts` 中的策展表。这是不遍历固定 vendor 源的有意代价;变化很少,且在生成器中有明确标注。 +- `verify-event-taxonomy.ts` 被删除,`docs/architecture.md` 的事件表格消失;之前链接到特定表格行的人现在会落到生成目录上。 diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml new file mode 100644 index 0000000000..97b96e7315 --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-rfc-classification.md: 201852a209be7f40b05de45d148a36b9185767a3 +2026-06-20-rfc-classification.zh.md: 38eb920ac216e69087f0c84c95cdd9effca7b9b3 diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.md b/docs/rfc/implemented/process/2026-06-20-rfc-classification.md index 2162687225..201852a209 100644 --- a/docs/rfc/implemented/process/2026-06-20-rfc-classification.md +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.md @@ -1,5 +1,7 @@ # RFC: Classify RFCs by kind via path-encoded subdirectories +English | [中文](2026-06-20-rfc-classification.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md b/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md new file mode 100644 index 0000000000..38eb920ac2 --- /dev/null +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md @@ -0,0 +1,48 @@ +# RFC:通过路径编码的子目录对 RFC 进行分类 + +Status: implemented + +[English](2026-06-20-rfc-classification.md) | 中文 + +## 问题 + +`docs/rfc/` 此前仅按**生命周期**分组:`proposed/`/`implemented/`/`rejected/`。没有任何机制记录每篇 RFC 属于哪一*类*决策。索引是每个生命周期下的一个扁平列表,无法按需筛选「所有精简类」或「所有测试策略类」决策。同一天落地的一批精简类 RFC 让这个缺口变得具体:浏览 `proposed/` 的读者无法在不逐一打开文件的情况下区分新能力、移除和工具策略变更。 + +本仓库的一贯倾向是[机械质量门禁优先于行文指南](2026-06-11-quality-gates.md):不被机器检查的约定终将腐烂。因此这里的分类体系必须可强制执行,而非靠自觉的文件头。 + +## 决策 + +增加第二个维度——RFC 的**类别**——并将其编码在路径中:`{lifecycle}/{class}/yyyy-mm-dd-topic.md`。文件夹*就是*标签。文件的位置声明其类别,封闭集合是「这些文件夹且仅限这些」,而既有的 [verify-md-links](2026-06-18-markdown-cross-link-lint.md) 门禁已经保护了移动文件所需的路径重写。 + +### 六个类别的封闭集合 + +| 类别 | 覆盖范围 | +|---|---| +| `feature` | 面向用户或模型的新能力。 | +| `bug-fix` | 修正缺陷或弥补事后复盘暴露的缺口。 | +| `simplification` | 移除代码、行为或接口面,不增加新能力。 | +| `architecture` | 关于**交付源码**的结构性决策:包之间的关系、运行时词汇是什么。 | +| `process` | 围绕代码的工具、策略或工作流,不涉及运行时行为。 | +| `testing` | 测试基础设施与策略。 | + +`architecture` 与 `process` 的分界线:**architecture** 关乎我们交付的源码;**process** 关乎围绕源码的工具与工作流。本 RFC 本身是一项 `process` 决策——它改变的是仓库的组织方式和门禁,而非 harness 在运行时的行为——因此它位于 `implemented/process/` 下。 + +### 两道门禁 + +两者都是 `doc-sync` 的成员,风格与 `verify-md-wrap` 一致(tsx ESM,只校验不生成,首个违规即以非零退出码退出): + +- **`scripts/verify-rfc-classification.ts`**:封闭集合与索引新鲜度(freshness)。它断言每个生命周期文件夹下的文件都位于规范集合中的某个类别文件夹内(直接放在生命周期根目录的 `.md`,或未知的类别文件夹,都会失败),并断言生成的 [INDEX.md](../../INDEX.md) 与从目录树重新渲染的结果逐字节一致(见[生成 RFC 索引表](2026-07-04-generate-rfc-index-tables.md))。规范类别集合以 `const` 形式定义在 `scripts/rfc-index.ts` 中——这是与生成器共享的机器真源——[README](../../README.md) 以行文形式记录它;类别*描述*保持手写,索引则是生成的。 +- **`scripts/verify-doc-refs.ts`**:源码注释中的文档引用。RFC 路径不仅在 Markdown 中被引用,也出现在 TypeScript 文档注释中(根相对路径,如 `docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md`)。`verify-md-links` 从未扫描过这些引用,因此重组可能会悄悄使它们变成悬空引用。此门禁扫描 `packages/**` 和 `examples/**` 下仓库自有的 `.ts` 文件(排除构建产物 `lib/` 和 `vendor/`),查找 `docs/….md` 形式的 token,将每个根相对路径解析并断言其存在。它要求 `.md` 扩展名,因此无扩展名的行文引用(`docs/postmortem/0001`、`docs/architecture.md § Extending The Harness`)不受影响。 + +## 曾考虑的替代方案 + +- **在每个文件中加一行 `Classification:` 行文**(紧挨 `Status:`),由门禁解析。可行,但它把路径已经能承载的事实重复到了文件内,而且这一行可能与所在文件夹不一致。路径编码让标签与其存储合二为一——没有需要保持同步的东西。 +- **设立 `refactor` 类别。**它与 `simplification` 几乎完全重叠;唯一有人试图用来区分的标准是「可观测行为是否改变?」,而 `simplification` 已经编码了这一点(它不改变)。一个类别,不要两个。 +- **从文件系统自动生成索引。**此处最初否决,以保持索引手写;后来被[生成 RFC 索引表](2026-07-04-generate-rfc-index-tables.md)取代——当堆叠的提案波使手写表格成为仓库中冲突最频繁的文档区域后,列表改为完全生成的 [INDEX.md](../../INDEX.md),而 README 行文保持人工策展。 + +## 后果 + +- 每篇 RFC 现在都位于一个类别文件夹下,索引在每个生命周期内按类别分组。读者扫一个标题就能看到所有精简类或所有测试类决策。 +- `doc-sync` 链中多了两个快速 tsx 脚本;无新增依赖(mdast/GFM 栈已因 `verify-md-wrap`/`verify-md-links` 而存在)。 +- 新增类别是一个刻意的动作:修改 `scripts/rfc-index.ts` 中的 `const` 以及 [Classification 章节](../../README.md#classification),而不是仅仅 `mkdir` 一个文件夹。门禁会拒绝未知文件夹,因此临时类别无法悄悄混入。 +- 源码注释中的文档引用现在也受门禁保护:一个被移动或重命名的文档如果被 `.ts` 注释引用,pre-push 钩子就会失败,从而封堵了 `verify-md-links` 在结构上无法看到的一类漂移。 diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml new file mode 100644 index 0000000000..852f69db42 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-02-tool-schema-catalog.md: 9a99fafd36b3546be4f51a7cd9e9a47fdaaf4c2d +2026-07-02-tool-schema-catalog.zh.md: 373c681fa5870696645b138f12cad7f296434184 diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md index 7d79f73583..9a99fafd36 100644 --- a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md @@ -1,5 +1,7 @@ # RFC: Generated tool-schema catalog (boot-and-harvest) +English | [中文](2026-07-02-tool-schema-catalog.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md new file mode 100644 index 0000000000..373c681fa5 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md @@ -0,0 +1,55 @@ +# RFC:生成式工具 schema 目录(启动并采集) + +Status: implemented + +[English](2026-07-02-tool-schema-catalog.md) | 中文 + +## 问题 + +仓库此前没有一份统一的参考,列出实际暴露给模型的工具名称、描述与 JSON Schema。源码声明分散各处且在运行时组合,而既有的 Cordis 目录和数据结构目录覆盖的是接线与词汇,而非工具本身。 + +## 决策 + +通过**启动每个工具插件并读取其注册的 schema** 来生成目录,而非解析源码。`scripts/gen-tool-catalog.ts` 将每个已发布的工具包(package)挂载到一个全新的 Cordis `Context` 上(带 `SystemPrompt` + `ToolRegistry` 以及插件 `apply` 所读取的注入 seam),调用 `ctx.tools.schemas()`(即发送给模型的 `ToolSchema[]`),dispose 上下文,然后为每个包渲染一个 `## <package>` 小节,每个工具对应一个 ` ```json ` 的 `parameters` 块。它沿用 `gen-cordis-catalog` / `gen-module-graph` 的 CLI 形态:默认 `--write` 重新生成,`--check` 在已提交副本陈旧时失败,输出是确定性的(按 manifest 排序,工具按名称排序)。`verify-tool-catalog`(即 `--check`)运行在 doc-sync 内部,因此新鲜度门禁与其他文档门禁一样在 lefthook pre-push 和 CI 路径中触发。 + +### 为什么启动而非解析(核心论点) + +Cordis 目录是纯 TypeScript AST 遍历,因为每个事件/服务名都是字符串字面量,能往返映射到静态声明——AST 就是全部事实。**工具 schema 不是静态可知的**,因此同样的技术会产出一份说谎的文档: + +- `tool-todo` 写了 `enum: [...STATUSES]`——对一个运行时 `const` 的展开。AST 看到的是展开表达式,而非 `["pending","in_progress","completed"]`。 +- 每段 description 都由字符串**拼接**构建(`'…' + '…'`)。AST 看到的是拼接节点,而非模型实际读到的最终文本。 +- `tool-subagent` 的工具名是 `config.toolName ?? 'subagent'`——加载时选定,不是字面量。 +- MCP 插件可以通过 `ctx.tools.register()` 直接注册**原始 JSON Schema**,完全不经过 `defineTool`,因此结构化枚举 `defineTool(` 调用点会漏计。 + +唯一忠实的真源是插件加载后注册表实际持有的 schema。启动即是[测试策略](../../../testing.md)中「验证世界,而非自我报告」这一原则在文档生成器上的应用:读取已发布的产物,而非对它的重新推导。 + +### 恢复「不会静默遗漏」 + +启动有一项 AST 遍历不具备的代价:没有源码声明集合可供枚举,因此新增的工具包可能被遗忘。一道**完整性守卫**恢复了这一保证——`assertManifestComplete` 对 `packages/` 下所有 `tool-*` 包做 glob,若有任何一个不在生成器的启动 manifest 中则硬报错。新增工具包会导致生成器失败,进而导致 doc-sync 失败,直到该包被注册。这与 Cordis 生成器通过枚举源码免费获得的结构性保证相同,只是为启动式生成器重新实现了一遍。 + +### 手工维护的启动 manifest 是不可约减的策略 + +文件系统负责发现工具包清单,完整性守卫负责拒绝遗漏。`TOOL_PACKAGES` 仍然为每个包持有一份显式的启动配方,因为所需的 seam 实现和配置是**策略**,不是能从目录布局或注入名称安全推断的事实。 + +### 范围 + +`packages/*/tool-*` 下已发布的产品级工具包,各以默认配置启动:`dsh-tool-bash`(`bash`、`bash_output`、`bash_kill`)、`dsh-tool-todo`(`todo_write`)、`dsh-tool-subagent`(`subagent`)。`examples/` 下的演示工具(`echo`)被排除,与 Cordis 目录的 packages-only 范围一致——演示工具不属于读者所要查阅的产品接口。 + +目录的单位是包,而非每个已配置的工具实例。每个包以默认配置启动一次;加载时的别名(如 `subagent_fork`)会注明,但不枚举每种部署排列。部署清单是一个独立的、无界的接口。 + +### 使用普通 `json` 围栏 + +schema 块使用 ` ```json `,而非自定义的 `ts` 系围栏。`doc-typecheck` 只提取 `ts*` 围栏,因此 JSON 块对它不可见——无需 `BlockKind` 接线(不同于 Cordis 目录的 `ts cordis-catalog` 围栏,后者必须加入白名单以避免裸签名片段被编译)。 + +## 曾考虑的替代方案 + +- **纯 TypeScript AST 遍历,如 Cordis 目录**:工具 schema 不是静态可知的(见上文核心论点):运行时展开、字符串拼接、配置选定的名称,以及原始 `ctx.tools.register()` 注册,都会让 AST 推导出的文档说谎。 +- **从各包的 inject 推断启动配方**:[发现包清单提案](../../proposed/process/2026-06-20-discover-package-inventory.md)所警告的「过于聪明」的路径;配方保持手写策略,清单由文件系统发现并受完整性守卫保护。 +- **为 schema 块使用自定义 `ts` 系围栏**:不必要。普通 ` ```json ` 围栏对 `doc-typecheck` 不可见,无需 `BlockKind` 白名单。 + +## 后果 + +- 目录不会漂移:工具 schema 变更而已提交文件未反映时,`verify-tool-catalog` 在 pre-push 钩子和 CI 中失败。新增 `tool-*` 包未加入 manifest 时,完整性守卫直接报错。 +- 工具描述文本只有一个归属地——源码中 `defineTool` 的 `description`——生成的条目质量完全取决于它,与 Cordis 目录对事件 JSDoc 施加的推动力相同。 +- 生成器导入并执行工作区包(这是仓库中第一个这样做的脚本;其他脚本只读取文本)。它通过根 `tsconfig` 的 `paths` 映射在 `tsx` 下运行,走的是演示和测试所用的同一条未构建源码路径,因此不需要构建步骤。 +- 未来某个工具背后新增能力 seam 时,意味着 manifest 中新增一条配方条目(需要挂载哪些 seam)。这是上文明确指出的手写代价;仅在新增工具包时才需变更。 diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml new file mode 100644 index 0000000000..7b522b590b --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-03-documentation-graph-atlas.md: d10b57e5114684ab0a2caed66fa84b84959bdf12 +2026-07-03-documentation-graph-atlas.zh.md: 8473bc27994bb33eac61659196acc53b69a16449 diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md index a17973ea2e..d10b57e511 100644 --- a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md @@ -1,5 +1,7 @@ # RFC: Documentation graph index for maintainers and SDK users +English | [中文](2026-07-03-documentation-graph-atlas.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md new file mode 100644 index 0000000000..8473bc2799 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md @@ -0,0 +1,69 @@ +# RFC:面向维护者和 SDK 用户的文档关系图索引 + +Status: implemented + +[English](2026-07-03-documentation-graph-atlas.md) | 中文 + +## 问题 + +仓库此前已有若干高可信度的文档面,各自覆盖不同维度:[module-graph.md](../../../module-graph.md) 由 package 的 `peerDependencies` 生成;生成的 [Cordis 事件目录](../../../cordis-catalog/events.md)和[服务目录](../../../cordis-catalog/services.md)由 Cordis 的 `Events` 与 `Context` 声明生成;[tool-catalog.md](../../../tool-catalog.md) 通过启动已发布的工具插件生成;[core-data-structures/](../../../core-data-structures/core.md) 使用 `ts type-equiv` 块保持粘贴的类型定义与源码同步。 + +这些参考资料是准确的,但它们大多是目录。维护者仍需自行综合关系:哪些 package 构成一条能力 seam、哪个应用捆绑了具体的主干、哪个事件是持久的而哪个是实时的、钩子或策略插件可以在哪里拦截工作、以及哪个面向模型的工具依赖哪个服务。SDK 用户从另一个角度面临同样的问题:「我想要某种行为,该安装或加载哪个 package?该扩展哪个事件/服务/工具?」 + +钩子子系统使事件的生产者/消费者拓扑与拦截点变得更加重要;文件系统 seam 使能力 seam、策略否决、工具呈现和 SDK 组装路径变得更加重要。如果关系图仅限于一个小的 bash/todo/subagent 表面,它们会立刻陈旧。 + +## 决策 + +新增生成的关系图文档,索引位于 [docs/graph-atlas.md](../../../graph-atlas.md),由专门的生成器产出,并由 `pnpm run verify-doc-graphs` 及既有的目录新鲜度检查(作为 `doc-sync` 的一环)进行验证。 + +该索引是既有目录之上的关系层。它不替代精确的参考资料,而是链接到它们并解释各部分如何组合在一起。 + +### 维护模式 + +每个关系图页面声明一种维护模式: + +- **生成(Generated)**:所有节点和边均从源码发现;如果已提交的产物陈旧,`--check` 失败。 +- **混合生成(Hybrid generated)**:源码发现清单,一份小型 manifest 对不可约的策略进行分类,完整性守卫在发现的条目未被分类时失败。 +- **人工维护(Curated)**:图表解释设计意图、时序或归属;它由生成器输出以保证关系图文档作为一个可重新生成的整体,但内容是有意撰写的。 + +### 首批交付的索引 + +首批索引链接十个关系面。package 拓扑与工具-package 能力映射位于既有的生成目录中(这些目录已拥有相应事实);其余的专项图表由 `scripts/gen-doc-graphs.ts` 生成。 + +| 关系图 | 维护模式 | 真源 | +|---|---|---| +| [模块依赖图](../../../module-graph.md) | 生成 | `packages/*/*/package.json` 的 peer dependencies 加 package 分组路径 | +| [工具 schema 目录与 package 映射](../../../tool-catalog.md) | 生成 | 启动采集的工具 schema 加工具-package 的服务/副作用元数据 | +| [能力 seam 与核心服务](../../../capability-seams.md) | 混合生成 | Cordis 服务声明加 `gen-doc-graphs.ts` 中的角色 manifest | +| [echo-agent 应用组合](../../../../examples/echo-agent/composition.md) | 混合生成 | `examples/echo-agent/cordis.yml` 插件列表加人工维护的应用/bundle 展开 | +| [coding-agent 应用组合](../../../../examples/coding-agent/composition.md) | 混合生成 | `examples/coding-agent/cordis.yml` 插件列表加人工维护的应用/bundle 展开 | +| [acp-agent 应用组合](../../../../examples/acp-agent/composition.md) | 混合生成 | `examples/acp-agent/cordis.yml` 插件列表加人工维护的应用/bundle 展开 | +| [事件生产者/消费者矩阵](../../../event-producer-consumer.md) | 混合生成 | Cordis 事件声明、AST 扫描的 `ctx.on/emit/parallel/serial/waterfall` 调用点,以及显式的动态分发覆盖 | +| [agent 轮次与步骤生命周期](../../../agent-lifecycle.md) | 人工维护 | architecture.md 的循环生命周期、Cordis 目录链接与会话事件语义 | +| [工具执行流水线](../../../tool-execution-pipeline.md) | 人工维护 | 工具流水线语义与 `tools/execute` waterfall(瀑布式事件) | +| [ACP 快照回放](../../../../packages/ui/acp/snapshot-replay.md) | 人工维护 | 快照 harness 行为 | + +### 为什么由生成器拥有这些文档 + +package 拓扑留在 `gen-module-graph.ts`,工具-package 能力映射留在 `gen-tool-catalog.ts`,因为这些生成器已经拥有权威事实和新鲜度门禁。`gen-doc-graphs.ts` 拥有其余关系页面和索引。代价是人工维护的图表需要在 TypeScript 字符串块中编辑,而非直接编辑 Markdown。对首批交付而言这是可接受的,因为面向用户的产物仍是纯 Markdown/Mermaid;如果撰写体验比可重新生成更重要,未来可以将人工维护的页面拆分出来。 + +### 完整性守卫 + +混合生成的页面在其 manifest 陈旧时必须显式失败: + +- 模块图读取每个 package 的 `peerDependencies`,并按 `packages/<group>/<pkg>` 路径对 package 分组。 +- 工具目录通过启动采集已发布的工具,并从同一份 manifest(其完整性守卫已在检查)渲染 package/服务/副作用映射。 +- 能力 seam 图导入 Cordis 服务收集器,断言每个被发现的 harness `ctx.<key>` 都已在 `SERVICE_ROLES` 中分类,且每个已分类的 key 仍然存在。 +- 事件生产者/消费者矩阵标记为混合生成,因为 subagent 生命周期事件有意使用 `ctx.events.dispatch` 实现逐监听器隔离;这些动态边是显式覆盖而非无声遗漏。 +- `verify-mermaid` 用 Mermaid 自身的解析器解析仓库中每个 ` ```mermaid ` 围栏,因此语法错误会在本地和 CI 的 `doc-sync` 中失败,而不是在 GitHub 渲染时才显示为损坏的图表。 + +## 曾考虑的替代方案 + +已提交的图表使用 Mermaid,因为 GitHub 在 Markdown 中原生渲染它,且不引入新的文档构建依赖;密集的多对多数据(如事件生产者/消费者关系)则使用 Markdown 表格。**PlantUML、托管图表服务和生成的 SVG** 曾被考虑,但在 Mermaid 成为瓶颈之前有意不采用。 + +## 后果 + +- 维护者获得了拓扑、seam、事件流、生命周期、应用组合和快照行为的可视化入口。 +- SDK 用户获得了从用例到 package 组合的路径,而不仅仅是自底向上的 package 参考。 +- `doc-sync` 现在包含 `verify-doc-graphs` 和 `verify-mermaid`,因此关系图漂移和 Mermaid 语法错误与其他文档新鲜度门禁一同被捕获。 +- 未来的文件系统和钩子工作有了承载新复杂度的具体位置:文件系统应扩展能力文档和工具目录,钩子应扩展事件矩阵和工具执行流水线。 diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml new file mode 100644 index 0000000000..18408700a9 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-cordis-jsdoc-completeness-gate.md: 44a0ddce9c929deac3e03bb421aec1d5145e65ba +2026-07-04-cordis-jsdoc-completeness-gate.zh.md: 6fea7f96a62295bd37e778a0aadd1e9ee6c8f2b4 diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md index 42ab306bb0..44a0ddce9c 100644 --- a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md @@ -1,5 +1,7 @@ # RFC: JSDoc completeness gate for the cordis surface +English | [中文](2026-07-04-cordis-jsdoc-completeness-gate.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md new file mode 100644 index 0000000000..6fea7f96a6 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md @@ -0,0 +1,41 @@ +# RFC:Cordis 接口的 JSDoc 完整性门禁 + +Status: implemented + +[English](2026-07-04-cordis-jsdoc-completeness-gate.md) | 中文 + +## 问题 + +生成的 Cordis 目录已强制检查事件的 dispatch 模式,但未检查服务与事件契约的完整性。方法可以缺少描述,参数或返回值可以在跨插件 API 接口上不写文档——而这恰恰是 IDE 引导最重要的地方。 + +AGENTS.md 规则("每个导出都有解释语义的 JSDoc")只能靠评审以行文方式检查;本仓库的既定偏好是将不变式编码为机械门禁。"Cordis 服务函数与事件"这一范围有一个精确的机器定义,只有目录生成器知道:事件是 `declare module 'cordis'` 内 `interface Events` 的成员,服务接口是每个 `interface Context` 键所指向的类的公开方法。ESLint 规则看不到这层映射;生成器在每次运行时都会计算它。 + +## 决策 + +扩展 `scripts/gen-cordis-catalog.ts`——同一次遍历、同一个 `@mode` 先例——对其目录化的所有内容强制 JSDoc 完整性。`verify-cordis-catalog` 运行在 `doc-sync` 内部,CI 和 lefthook pre-push 钩子都已执行 `doc-sync`,因此门禁无需新增任何接线(质量门禁原则:单一真源)。 + +契约如下: + +- **事件**需要描述文字,并为每个**载荷参数**提供非空 `@param`。载荷参数是签名中承载事件数据的参数;`this` 接收者注解和尾部的 waterfall `next` 免检——`next` 是 dispatch 机制,其语义已由 `@mode waterfall` 标签(及其结构交叉检查)拥有,逐事件重述只是样板。对免检参数写文档是允许的;门禁只检查缺失。 +- **服务类**需要类级 JSDoc,每个公开方法需要描述文字、每个参数一个非空 `@param`,以及一个非空 `@returns`(除非标注的返回类型是 `void`/`Promise<void>`,此时 `@returns` 可选——解析时机可能值得记录——但从不强制要求)。 +- **陈旧标签报错**:`@param` 命名了一个不存在的参数即为违规,与 `@mode` 与签名矛盾的检查对称。标签描述必须非空;超出此范围的语义质量由评审负责。 +- **遍历可检查的显式性**:门禁是纯 AST 遍历(不使用类型检查器),因此服务方法必须显式标注返回类型(推断的返回类型无法分类),接口参数必须是简单标识符(解构模式没有名字供 `@param` 匹配)。 +- **违规聚合**为一条错误信息,列出所有违规项——修复时一次看到全部。此前快速失败的 `@mode` 检查也移入同一份聚合报告,消息文本不变。 + +这些标签**仅用于门禁强制**:`parseJsDoc` 现在在遇到第一个块标签时截止描述文字(标准 JSDoc 语义,同时也防止多行标签描述泄漏到目录中成为正文),因此 `@param`/`@returns` 永远不会改变渲染出的目录。 + +`packages/core/agent/tests/gen-cordis-catalog.spec.ts` 中的负向路径测试用合成 fixture(测试前置数据)驱动 `collectEvents`/`collectServices`,证明每个守卫都能触发且免检规则成立。撰写规则写在根 [AGENTS.md](../../../../AGENTS.md) 约定条目中,与 `@mode` 规则并列。 + +## 曾考虑的替代方案 + +- **ESLint 规则**:看不到范围的机器定义(哪些 `interface Events` 成员、哪些 `ctx.<key>` 类构成 Cordis 接口);目录生成器在每次运行时恰好计算这层映射,因此门禁放在那里。 +- **将标签渲染到目录中**:曾考虑将服务部分重构为逐方法条目,但有意推迟:方法文档的消费场景是源码 JSDoc 加 IDE 悬浮提示,目录保持索引定位。 +- **逃生标签**:不设。接口面小且经过策划(采纳时 12 个服务、57 个方法、27 个事件),重点在于检查不可豁免。 + +## 后果 + +- 新增事件或服务方法如果参数或返回值未写文档,就无法合入:生成器拒绝重新生成,`verify-cordis-catalog` 在 pre-push 和 CI 中失败。采纳时发现的约 139 处缺口在同一个变更中补齐,门禁以绿色状态落地。 +- 服务接口必须显式标注返回类型并使用标识符参数。两项约束在采纳时均未构成负担(所有方法已有标注;不存在解构的 seam 参数);二者现在都是承重要求,违反时会被机械发现。 +- AGENTS.md 的通用 JSDoc 规则("一行能说清就写一行")在此接口上获得一条更严格的特例:只有当方法无参数且返回 void 时,一行摘要才仍然足够。 +- 对 `next` 或 `this` 写 `@param` 合法但不检查——这是有意的不对称:门禁强制载荷契约,拒绝索要样板。 +- 标签不改变渲染出的目录(正文在第一个块标签处截止)。如果日后需要方法级渲染,那是目录设计的独立决策,不是本门禁的缺口。 diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml new file mode 100644 index 0000000000..5d1764cea6 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-doc-tiers-and-budgets.md: ca9da847849f61f2fb244932e657cca8fec69696 +2026-07-04-doc-tiers-and-budgets.zh.md: 37447d11de181a007bcea23e29084aefd97b1ab5 diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md index 3f88e43c1d..ca9da84784 100644 --- a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md @@ -1,5 +1,7 @@ # RFC: Documentation tiers, budgets, and the ceiling gate +English | [中文](2026-07-04-doc-tiers-and-budgets.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md new file mode 100644 index 0000000000..37447d11de --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md @@ -0,0 +1,28 @@ +# RFC:文档分层、预算与上限门禁 + +Status: implemented + +[English](2026-07-04-doc-tiers-and-budgets.md) | 中文 + +## 问题 + +尽管已有写作指导,常设文档仍然积累了重复的规则、重述的事件、重复的 package 地图和陈旧的 RFC 摘要。由于仅靠评审无法阻止这种膨胀,仓库需要在文档分类体系之外再加一道机械化的预算。 + +## 决策 + +- **分层分类体系,每条事实只有一个归属。** [docs/AGENTS.md](../../../AGENTS.md) 是文档标准:它为每个 Markdown 层级指定唯一职责(常设指令、系统地图、类型目录、决策记录、事件故事、实操手册(cookbook)、package 契约、生成目录、工作流),禁止在归属层级之外重述事实(应改为链接),并附带一份在撰写或评审任何文档时使用的冗余检查清单。 +- **窄范围、硬约束的预算门禁。** [scripts/verify-doc-budgets.ts](../../../../scripts/verify-doc-budgets.ts) 加入 doc-sync:凡列入 [scripts/doc-budgets.manifest.json](../../../../scripts/doc-budgets.manifest.json) 的文档都必须低于其字数上限(`wc -w` 语义,整个文件),且已设预算的文件若缺失也会使门禁失败,防止重命名时预算被静默遗留。范围有意仅限于容易膨胀的常设文档:根目录与子树的 `AGENTS.md`、`architecture.md`、`packages/README.md`,以及它们将内容分流到的常设策略文档(`docs/testing.md`、`docs/defensive-patterns.md`)。参考文档、RFC 和 package README 不设预算:当每一行都是事实时,长度是合理的,由评审加冗余检查清单管控。 +- **上限是只进不退的执行红线。** 上限设定在文档当前大小的至少 5% 以上(留出操作余量,使日常措辞修改不会触发门禁,而真正的膨胀仍会被拦截),并随着文档被压缩到目标预算(根 `AGENTS.md` ≤ 1,500 词;`architecture.md` ≤ 1,800;子树 `AGENTS.md` ≤ 600;`packages/README.md` ≤ 600)而保持该余量向下收紧——与[翻译配对 `required` 清单](2026-07-02-bilingual-docs-and-pairing-gate.md)的推进机制相同。门禁变红时,修复方式是按分类体系迁移或精简内容;只有在 PR 描述中给出明确理由时才允许提高上限,manifest diff 本身即为可评审的动作。 +- **轻量工作流 skill,契约在文档中。** [.agents/skills/dsh-doc-standards](../../../../.agents/skills/dsh-doc-standards/SKILL.md) 承载归位/审计/红灯修复工作流,并将文档标准作为真源——与 [dsh-translate-docs](../../../../.agents/skills/dsh-translate-docs/SKILL.md) 对 i18n 契约的分工方式相同。 + +## 曾考虑的替代方案 + +- **仅靠 skill 与评审纪律,不设门禁**:否决。上述膨胀正是在既有的现状规则和评审者注意力下发生的;一条没有机械后盾的行文规则在这里已被证明守不住,而本仓库自身的[质量门禁立场](2026-06-11-quality-gates.md)说的是:值得保持的不变式就值得编码。 +- **对所有文档层级设置宽泛门禁**:否决。一刀切的上限恰恰惩罚了那些正当的长文档(如功能矩阵或类型目录,每一行都是事实,例如 `packages/ui/acp/acp-feature-support.md`),并产生逐文件的例外修改,训练贡献者无脑批准上调。 +- **将标准放在 skill 内部**:否决。契约放在文档中,工作流放在 skill 中;如果标准被塞进 SKILL.md,那些不调用该 skill 而直接编辑文档的 agent 就看不到它,而 `docs/AGENTS.md` 已经作为子树指令被加载给所有在 `docs/` 下工作的人。 + +## 后果 + +- 向已设预算的文档添加内容现在需要置换:将新增内容迁移到其分类归属处并留下指针,或精简既有行文为其腾出空间。只增不减会导致 CI 失败。 +- 将文档压缩到目标预算的重写以堆叠的后续 PR 落地,每个合并时都将 manifest 中的上限向下收紧;在各自落地之前,文档的冻结上限仅阻止进一步膨胀。 +- 字数是一个粗糙的代理指标,这是有意接受的:它无法判断质量,但它恰好在内容被添加的那一刻强制触发迁移决策——而那正是作者拥有足够上下文来正确归位内容的时刻。 diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml new file mode 100644 index 0000000000..814ca38546 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-generate-rfc-index-tables.md: 6a8888eda8b7cf7105a44802774bf49d6463952d +2026-07-04-generate-rfc-index-tables.zh.md: 42ae64306aa1d5cf9117ca2b4d698a5d8effdeec diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md index d854991ad9..6a8888eda8 100644 --- a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md @@ -1,5 +1,7 @@ # RFC: Generate the RFC index tables +English | [中文](2026-07-04-generate-rfc-index-tables.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md new file mode 100644 index 0000000000..42ae64306a --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md @@ -0,0 +1,34 @@ +# RFC:生成 RFC 索引表 + +Status: implemented + +[English](2026-07-04-generate-rfc-index-tables.md) | 中文 + +## 问题 + +RFC 索引中按生命周期/按类别的表格所列信息完全可推导:RFC 的路径编码了生命周期与类别,文件名编码了首次提出日期,H1 标题即为标题。手工维护这些事实的副本恰恰是本仓库文档中冲突最频繁的热点:每一波提案都向同几行追加行,因此并行的 RFC 分支恰好在此处冲突,而在其他所有地方都没有分歧;每次冲突都要手动合并那些文件系统本已知晓内容的行。[分类 RFC](2026-06-20-rfc-classification.md) 最初为了策展目的保留手写索引,但 README 中真正需要策展的部分是行文,而行文从不冲突;冲突的只有机械表格。 + +## 决策 + +保留策展行文;生成列表。表格位于 [`docs/rfc/INDEX.md`](../../INDEX.md),是一个**完全生成的文件**;策展行文留在 README.md 中,README.md 不包含任何索引行。[`scripts/rfc-index.ts`](../../../../scripts/rfc-index.ts) 是共享的真源:树遍历器(拥有封闭的生命周期/类别集合与结构规则,包括 H1 可解析的要求)和渲染器(行来自 H1 标题并去除 `RFC: ` 前缀,加上文件名日期,按日期再按文件名排序,以 `### {Class}` 分节、按规范类别顺序分组)。两个轻量消费方共享它: + +- [`scripts/gen-rfc-index.ts`](../../../../scripts/gen-rfc-index.ts)(`pnpm run gen-rfc-index`)从目录树完整重写 INDEX.md。 +- [`scripts/verify-rfc-classification.ts`](../../../../scripts/verify-rfc-classification.ts)(doc-sync 的一个成员)检查结构,断言已提交的 INDEX.md 与新鲜渲染结果逐字节一致(与 `gen-cordis-catalog`/`verify-cordis-catalog` 模式相同),并拒绝在策展 README 中出现索引格式的行。新鲜度检查涵盖了索引完整性检查:从磁盘生成的表格在定义上就是完整且标题正确的。 + +添加、移动或删除一个 RFC 只需编辑 RFC 文件本身并运行生成器;分类 RFC 的「否决替代方案」记录中带有取代关系的交叉链接。 + +## 曾考虑的替代方案 + +### 为什么不在 README.md 内使用标记分隔区域? + +最初落地的形态:生成器在 README.md 中的 `gen-rfc-index` 标记注释之间、每个 `## {Lifecycle}` 标题下拼接表格。在 README 同时吸收了文件内格式契约([统一格式 RFC](2026-07-05-uniform-rfc-format.md))之后,被整文件 INDEX.md 方案取代:一个门面 README 承载数百行生成行,会淹没其策展行文;而拼接机制(标记对、标题检查、区域外行检测)的存在只是为了保护策展文本——专用的生成文件根本不包含策展文本。 + +### 为什么不采用纯校验模式? + +纯校验能捕获错误,但每次提案编辑仍然要在手工维护的表格中触碰共享热点;对于一行纯机械内容,校验失败比生成器更令人烦恼:作者已经命名并放置了文件,索引副本不增加任何信息。这与 [package-inventory 提案](../../proposed/process/2026-06-20-discover-package-inventory.md) 对 tsconfig references 和 knip stanzas 所做的「手工列表 vs. 推导」判断相同——应用于这张确实会冲突的列表。 + +## 后果 + +- 生成文件是显式的:其横幅标注了生成器名称,文件内没有需要保护的策展区域,且生成器在目录树结构无效时拒绝运行。 +- 格式错误或缺失的 H1 在生成器和门禁中都是硬错误:H1 现在是承重的,它是索引标题的来源。 +- 并行的 RFC 分支通过重新运行生成器来解决索引冲突,而非手动合并行。 diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml new file mode 100644 index 0000000000..d824b18b5d --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-persistence-log-catalog.md: f8f831ca0470cf3b5c7634550115e67f7deac840 +2026-07-04-persistence-log-catalog.zh.md: d8cd5f74e24968fa2ad01f128dafe8c867f3406c diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md index 0de6255322..f8f831ca04 100644 --- a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md @@ -1,5 +1,7 @@ # RFC: Generated persistence log event catalog +English | [中文](2026-07-04-persistence-log-catalog.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md new file mode 100644 index 0000000000..d8cd5f74e2 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md @@ -0,0 +1,36 @@ +# RFC:生成式持久化日志事件目录 + +Status: implemented + +[English](2026-07-04-persistence-log-catalog.md) | 中文 + +## 问题 + +`SessionEventMap` 是磁盘上的词汇(vocabulary),但其声明分散在所属的 session 包与声明合并中。生成式持久化目录是每个事件及其 payload 的唯一参考;手工维护的表格会漂移,已被移除。这些记录不是 Cordis 事件:观察者通过唯一的 `session/event` 总线事件接收它们,因此 Cordis 目录无法覆盖。生成器会发现所有声明,doc-sync(文档同步门禁)新鲜度门禁会拒绝遗漏或陈旧的输出。 + +## 决策 + +从源码生成 `docs/persistence-catalog.md`,配以新鲜度门禁,作为第四个参考面:持久化会话日志可以包含的*记录*,与 Cordis 目录(接线)、核心数据结构(词汇)和工具目录(工具)互补。 + +`gen-persistence-catalog.ts` 使用 TypeScript AST 扫描所有所属的和声明合并的 `SessionEventMap`。它渲染源码 JSDoc、payload 类型、派生的 surface 徽章、参考链接和源码位置。doc-sync 新鲜度检查会拒绝任何词汇变更后未重新生成目录的情况。 + +具体选择: + +- **JSDoc 完整性,强制执行。** 每个成员必须携带描述性文字:JSDoc 即为目录条目,与 Cordis 目录对总线事件施加的强制函数相同。成员上的 `@mode` 标签是硬错误:dispatch mode 属于 Cordis 总线事件,日志事件没有 mode;该标签会被误读为「此事件以 mode X 在总线上触发」。违规项聚合为一条错误,列出所有违规者。 +- **surface 徽章由派生得出,而非手工列举。** `SurfaceEventType`(产生 LLM 消息且可能携带 `surfaceOp` 的子集)从所属包中的 union 声明解析而来;union 成员如果命名了一个未声明的事件,则为硬错误(否则一个陈旧的 union 成员会静默地不标注任何事件)。其余一律渲染为 **log-only**。 +- **专用围栏。** payload 块使用 ` ```ts persistence-catalog ` 信息字符串,`doc-typecheck` 识别并跳过它,不计入 opt-out 比例——与 `ts cordis-catalog` 的处理方式相同(裸 payload 片段不能独立编译)。 +- **仓库范围。** 目录枚举本仓库中的包,与兄弟目录的 packages-only 范围一致;下游插件可以合并更多事件类型,但它们在设计上不在目录范围内。遍历过程用硬错误保护自身假设:所属的顶层 `interface SessionEventMap` 必须是 `@deepseek-ai/dsh-session` 中唯一的导出声明(一个无关的、局部的或重复的同名接口不能被当作磁盘词汇编入目录);任何声明不得携带 `extends`(继承的键会加入 `keyof SessionEventMap` 却没有对应的目录行);每个成员必须是带有显式 payload 类型的属性签名(方法形式的成员会加入 `keyof` 却被静默遍历跳过);跨声明的重复成员会失败。 + +这取代了手工副本:session.md 的 `hook/*` 表格、compact README 的事件表格、hook-protocol README 的 payload 列表,以及 session README 的名称列表现在链接到目录,而非重述 payload(周围的语义行文保留原位)。hook-protocol 合并成员上两个多余的 `@mode emit` 标签已被移除——新门禁将其拒绝为它们本来就是的类别错误。 + +## 曾考虑的替代方案 + +- **基于启动的生成器(如工具目录的方式)**:日志词汇完全是静态的,AST 遍历无需启动任何东西即可读取全部真相。 +- **保留手工副本**:手工副本只能检查作者已经写下的名称;目录落地时 session README 的合并说明已经漂移。 + +## 后果 + +- 目录不可能漂移:词汇变更而已提交文件未反映的,`verify-persistence-catalog` 在 pre-push 钩子和 CI 中会失败;新合并的事件如果没有 JSDoc,生成器直接报错——插件不能再添加未文档化的磁盘记录类型。 +- 事件描述有唯一归属地:声明处的 JSDoc。JSDoc 写得薄,目录条目就薄,这对作者形成在源头写文档的压力。 +- `SurfaceEventType` union 现在对文档具有结构性承载作用:重命名事件而不更新 union(或反过来)会导致生成器失败,而不仅仅是编译器失败。 +- 徽章派生假设 union 始终是一组封闭的字符串字面量且只有一个所有者;如果重构偏离了这一形状,必须在同一个变更中更新生成器。 diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml new file mode 100644 index 0000000000..bb326da2d8 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-05-uniform-rfc-format.md: f67c61c0b627950cf07e7d57672324308a9462ec +2026-07-05-uniform-rfc-format.zh.md: a11cba1c343f150a67c1af4a04a8d89480185207 diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md index d5ce28066d..f67c61c0b6 100644 --- a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md @@ -1,5 +1,7 @@ # RFC: One gated in-file format for RFCs +English | [中文](2026-07-05-uniform-rfc-format.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md new file mode 100644 index 0000000000..a11cba1c34 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md @@ -0,0 +1,30 @@ +# RFC:为 RFC 统一一种有门禁保障的文件内格式 + +Status: implemented + +[English](2026-07-05-uniform-rfc-format.md) | 中文 + +## 问题 + +RFC 的路径已编码了生命周期与分类,但文件内容仍然混杂着不同的标题风格、状态格式、ADR 模板与提案模板,以及已实施记录中残留的提案时期章节。作者复制手边找到的任何邻居文件作为模板,而生命周期迁移可以跳过必要的改写,因为没有门禁强制执行文件内契约。 + +## 决策 + +[README.md § The file format](../../README.md#the-file-format) 即为文件内契约:头部块(`# RFC: <title>` 加上不含日期、与所在文件夹一致的 `Status:` 枚举,其唯一内容是否决原因);按生命周期区分的正文骨架(所有阶段都以 `Problem` 开头;`proposed/` 中使用 `Proposal`/`Acceptance criteria`/`Risks`;`implemented/` 中使用现在时的 `Decision`/`Consequences` 且禁止提案时期标题;`rejected/` 中冻结提案形态);强制的 `Alternatives considered` 章节;以及规范的章节词汇表——在这些固定章节之间,自定义的技术章节保持自由格式。`pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../../../scripts/verify-rfc-format.ts))作为 doc-sync(文档同步门禁)的一环强制执行每一条机械化条款,因此跳过改写的生命周期迁移现在会导致 CI 失败,而非依赖评审者的记忆。 + +整个语料库在定义格式的同一个变更中完成了规范化——这是预发布阶段的立场:不设过渡期,不容忍双格式并存。唯一的祖父条款针对内容而非格式:替代方案只记录已有的,不凭空编造;因此如果一篇格式定义之前的 RFC 的替代方案无法从记录中重建,它会携带 `rfc-format: alternatives-not-recorded` 注释,门禁仅对日期早于本 RFC 的文件接受该注释。 + +## 曾考虑的替代方案 + +- **完全刚性模板**(每个生命周期一套固定章节顺序,所有 RFC 重构以适配):否决。大型设计 RFC 携带八到十五个自定义技术章节(包拓扑、协议格式契约、schema),这些是承重内容而非漂移;刚性顺序会迫使当下进行破坏性改写,并永远与模板对抗。 +- **仅规范化头部**(H1 与 Status,正文不动):否决。技术债标记指出的正是*正文*的体裁分裂,让 `Context`/`Decision` 与 `Problem`/`Proposal` 无限期并存什么也解决不了。 +- **不设 Status 行**(文件夹本身就是状态;三篇最新的格式定义前 RFC(及其中一篇的中文对侧文件)省略了该行):否决,保留自描述文件。当初促使去掉该行的漂移风险,已被「门禁将该行与文件夹做一致性校验」所消除。 +- **带日期的状态**(`Status: implemented (accepted YYYY-MM-DD)`):否决。接受日期属于叙述性历史,写作规则将其排除在文档之外;文件名承载首次提出日期,git 承载其余信息,门禁能检查日期格式但永远无法检查其真实性。 +- **裸 `# <title>` H1**:否决。`RFC: ` 前缀是语料库中的多数形式,且在文件脱离目录树阅读时能自描述体裁;索引生成器会剥离它,因此索引行无论哪种写法都一样。 +- **`## What we give up` 作为已实施记录的收尾章节**(README 自身用来描述 RFC 所记录内容的措辞):否决。它只命名了代价,而诚实的后果章节同时记录权衡所换来的收益。 +- **约定而无门禁**(写下契约,靠评审强制执行):否决。slop checklist 已通过约定禁止在 `implemented/` 中使用规范体措辞,而十九个文件展示了纯靠约定在这里能达到什么效果。 +- **独立的 `FORMAT.md` 契约文件**:最初落在此处;在生成索引迁出至 [INDEX.md](../../INDEX.md) 后折入 README.md:表格移走后 README 重新有了空间,一个前门同时承载布局、分类与格式,优于将契约拆分到两个文件。 + +## 后果 + +每篇 RFC 现在多了少许结构成本,而强制的 `Alternatives considered` 章节是有意为之的摩擦:一个不记录被否决方案的决策,会招来 RFC 本应防止的反复讨论。格式定义前的 RFC 若其替代方案无法重建,则永久携带祖父条款注释——这是记录上的诚实空白,而非编造的理由。doc-sync 新增一道门禁,在生命周期文件夹之间迁移 RFC 现在是迁移时的实际工作(即迁移本就欠下的正文改写),而非无人追踪的延后清理。三十九个技术债标记已全部消除,由它们等待的模板所解决。 diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml new file mode 100644 index 0000000000..dd08d60974 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-06-export-surface-jsdoc-gate.md: fd255cc6212d7f6f919ad23f999fa68b01478a73 +2026-07-06-export-surface-jsdoc-gate.zh.md: 02a5c2682095c66818a51cc14fd565111b7e6e80 diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md index 6ebb477dea..fd255cc621 100644 --- a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md @@ -1,5 +1,7 @@ # RFC: Export-surface JSDoc gate +English | [中文](2026-07-06-export-surface-jsdoc-gate.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md new file mode 100644 index 0000000000..02a5c26820 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md @@ -0,0 +1,45 @@ +# RFC:导出表面 JSDoc 门禁 + +Status: implemented + +[English](2026-07-06-export-surface-jsdoc-gate.md) | 中文 + +## 问题 + +[cordis JSDoc 完整性门禁](2026-07-04-cordis-jsdoc-completeness-gate.md)使 cordis 表面上的未文档化参数和返回值不再可能——`interface Events` 成员与 `ctx.<key>` 服务类——但那只是插件作者所导入内容的一小部分。AGENTS.md 中「每个导出(及非显而易见的方法)都应有 JSDoc 说明语义」这条规则在其他地方仍然只能靠评审以行文方式检查,而且没有任何机制要求普通导出函数带 `@param`/`@returns`。采纳时的一次调查发现 34 个包中有 203 个文档不完整的模块级导出:seam 相关辅助函数(`runBash`、`readForEdit`、`htmlToMarkdown`)、格式编解码器、整个未文档化的接口和类型别名——正是 IDE 消费方悬停时看到的那些名字。 + +## 决策 + +新增门禁 `scripts/verify-export-jsdoc.ts`(`pnpm run verify-export-jsdoc`,接入 doc-sync,与 `verify-cordis-catalog` 并列),遍历每个 `packages/<group>/<pkg>/src/` 目录树下所有模块级导出名。解析与检查辅助函数从 `gen-cordis-catalog.ts` 移入共享的 `scripts/jsdoc.ts`,因此「已文档化」在两个表面上含义一致:描述文本在第一个块标签处截止,每个可检查参数需要非空 `@param`,非 void 的**已标注**返回值需要非空 `@returns`,过时的 `@param` 报错,违规汇总为一份报告。 + +按声明类型划分的契约: + +- 每个导出名都需要带有非空描述文本的 JSDoc。 +- 函数类导出(函数声明;以函数初始化器或行内可调用标注的 const;非标识符的函数默认导出)遵循完整的函数契约,分类前会剥离包装表达式(括号、`as`/`satisfies` 转型、非空断言)。如果 const 的声明器标注了一个**命名**类型(`export const f: Handler = …`),则签名契约推迟到该类型自身的声明,`@returns` 可选;行内 `(x: T) => U` 标注或单调用签名字面量即为表面签名本身,适用完整契约;而字面量中混合了调用/构造签名与其他成员的情况则直接拒绝(没有单一签名可供标签对照——请提取命名类型)。 +- 导出类需要类级别的描述文本;公开方法(包括静态方法——可通过导出名访问)遵循函数契约;公开属性和访问器需要描述文本(get/set 对由 getter 覆盖)。重载实现免检——由签名承载文档。 +- 导出的接口、类型别名和枚举需要声明级别的描述文本;成员级别的强制有意推迟(承载关键成员契约的 seam 服务类已在 cordis 门禁下)。 +- 导出的命名空间递归检查(在 ambient `declare` 命名空间内,每个成员隐式导出);命名空间本身仅在不与同名已文档化声明合并时才需要描述文本(Config 命名空间惯用法只需文档化插件一次)。 +- `declare module` / `declare global` 体和 `export … from` 再导出语句被跳过:augmentation 不是包的导出,再导出的定义在其定义处检查。`export import X = N.member` 别名文档化**自身**——其目标可能是遍历不会访问的非导出命名空间成员——且仅支持纯描述文本的目标类型:可调用、类或命名空间目标携带别名描述文本无法承载的签名/成员契约,门禁拒绝此类情况并要求直接导出该声明。 +- 其余一切按**封闭**原则失败:`export =` 直接拒绝;基类从未命名的参数即使作为绑定模式仍保留 `@param` 义务;调度未识别的导出语句类型本身即为违规——没有任何导出形式能因遗漏而免检。 + +三类豁免避免门禁要求样板代码,精神与 cordis 门禁的 `this`/`next` 豁免一致(对已豁免的名字主动写文档是允许的;只有缺失才不被检查): + +- **继承成员。**重写从基类声明继承文档。新增的公开表面仍需文档:新增参数、将 protected 成员公开重写、或在 void 基类之上给出具体返回值。继承查找与推断返回值分类是门禁唯一需要类型检查器的工作;其他检查使用 AST。 +- **插件协议槽位。**顶层 `name` / `inject` / `reusable` / `Config` const 与 `apply` 入口,以及插件类上作为静态成员的相同槽位,属于框架协议:其形状由 cordis 固定,模块文档注释加 `interface Config` 承载插件的真实语义。 +- **构造函数**,与 cordis 门禁一致:插件类由框架构造,类文档承载全部说明。 + +`collectExportJsdocViolations()` 返回违规列表(CLI 在非空时以 exit 1 退出),因此 `packages/core/agent/tests/verify-export-jsdoc.spec.ts` 中的负路径测试直接对发现结果断言,通过 fixture 包驱动每一种拒绝和每一种豁免。 + +## 曾考虑的替代方案 + +- **eslint-plugin-jsdoc**(`require-jsdoc`/`require-param`/`require-returns`):覆盖了机械核心,但无法表达本仓库的契约:继承成员豁免需要跨包类型解析,协议槽位和命名空间合并惯用法是 cordis 特有的,而完整性语义(标签前描述文本、过时标签报错、聚合报告)已在 `scripts/jsdoc.ts` 中与 catalog 生成器共享一处。两套微妙不同的「已文档化」定义正是本仓库「一处为家」规则要防止的失败模式。 +- **扩展 `gen-cordis-catalog.ts`**:catalog 生成器渲染一个精选表面并门禁其新鲜度(freshness);仓库级遍历没有 catalog 可渲染。共享辅助函数但保持遍历分离,使每个门禁的职责清晰可读。 +- **强制接口/类型别名的成员文档**:推迟。这会将检查表面扩大到大量自描述字段,而承载关键成员契约的 seam 类已在门禁下。如果评审中出现成员文档漂移再重新考虑。 + +## 后果 + +- 新导出不能在无文档的情况下落地:`verify-export-jsdoc` 使 doc-sync 失败,而 pre-push 和 CI 已经运行 doc-sync。采纳时发现的 203 处缺口在同一个变更中补齐,因此门禁以绿色状态落地。 +- 导出函数必须标注返回类型(采纳时已全面覆盖,现在成为承载性要求),且在 `@param` 需要命名的地方使用标识符参数。 +- seam 文档是权威的:实现从继承链继承文档,值得保留在实现上的行为说明是补充,而非必需。 +- 门禁构建一个 `ts.Program`(约 6 秒)——唯一需要类型解析的文档门禁;在已经编译文档片段的 doc-sync 中可以接受。 +- 协议槽位名在模块顶层按约定保留;一个碰巧名为 `apply` 或 `Config` 的非协议导出会免检——已接受,记录于此。 diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml new file mode 100644 index 0000000000..394c2494ac --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-06-generated-config-catalog.md: 50ba0dc70b0d8ea54a4f93911f3a087806774626 +2026-07-06-generated-config-catalog.zh.md: 2dd0cbe5303f08aa2f3300c6f8613a7823c2bc78 diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md index 999ebd8503..50ba0dc70b 100644 --- a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md @@ -1,5 +1,7 @@ # RFC: Generated plugin config catalog +English | [中文](2026-07-06-generated-config-catalog.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md new file mode 100644 index 0000000000..2dd0cbe530 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md @@ -0,0 +1,40 @@ +# RFC:生成式插件配置目录 + +Status: implemented + +[English](2026-07-06-generated-config-catalog.md) | 中文 + +## 问题 + +仓库此前没有以源码为后盾的插件配置参考。各 package 的 README 对字段的记录方式不一致,没有列举哪些包可被加载,也没有校验运行时 schema 是否与声明的配置类型一致。 + +## 决策 + +`scripts/gen-config-catalog.ts` 从每个插件声明的配置类型与 JSDoc 生成 [docs/config-catalog.md](../../../config-catalog.md),包含注入要求、引用类型链接和源码指针。package 内部类型被传递性地包含;workspace 和外部类型以链接或名称引用。确定性的 `--write` 和 `--check` 模式使提交到仓库的页面成为一个生成产物(artifact)。 + +此处采用纯 AST 生成是正确的,原因与事件/服务目录相同,也与工具目录不同:配置类型是静态声明,仓库中每个 schemastery schema 都是静态的 `z.object`/`z.intersect` 字面量,因此源码就是全部真相——配置表面没有任何部分是运行时组合的。 + +具体选择: + +- **配置类型取自第二参数类型。** 目录记录的是 `apply(ctx, config)` / 服务构造函数 `(ctx, config)` 的声明参数类型——即 Cordis 实际传入的值——而非按命名约定定位的 `Config` 导出。这使得遍历是全量的:无论接口名为 `AcpConfig` 还是 `BasicCompactConfig`,无论类型声明在兄弟文件中,还是插件根本没有校验 schema,都能正常工作。 +- **分类是全量的。** 每个 `packages/<group>/<pkg>` 条目都会被解析(镜像 Loader 的 `unwrapExports`(`exports.default ?? exports`)),归入以下之一:可配置插件、无配置插件、抽象 seam 类或库——各自渲染在独立章节中——无法归类的条目会硬错误。新 package 不可能被静默地遗漏。 +- **逐字段 JSDoc 强制要求。** 粘贴的声明中每个属性(包括嵌套的类型字面量)都需要非空的 JSDoc 描述,否则生成失败。粘贴本身就是文档,因此这与事件目录通过 `@mode` 施加的强制函数相同:源码文档不足时门禁失败,而非产出一份单薄的目录。 +- **Schema 键与声明类型交叉检查。** 生成器通过本地和 workspace 类型解析嵌套的对象与数组路径。确定缺失的路径会失败;无法枚举的外部或动态形状则跳过。检查有意设计为单向的,因为声明类型可能包含从 loader 配置中排除的运行时专用字段。 +- **专用围栏。** 粘贴的声明使用 ` ```ts config-catalog ` 信息字符串,`doc-typecheck` 会跳过它(引用了导入类型的孤立声明无法独立编译),并将其排除在 opt-out 比例之外——与 `cordis-catalog` 和 `persistence-catalog` 围栏的处理方式相同。 +- **单文件 `docs/config-catalog.md`**,而非一个单文件目录:该页面服务于单一受众(`cordis.yml` 的编写者),只有一个维度,不同于 `cordis-catalog/`(它包含两个并列页面)。 + +各 package README 的 `## Config` 章节保留。这种重叠是有意接受的:README 是精心策划的逐 package 契约(部署上下文中的配置语义,连同限制与扩展点),目录则是穷举式的生成枚举。因为目录是生成的,二者之间的分歧说明 README 有误,修复方式是编辑 README——目录不会漂移。 + +## 曾考虑的替代方案 + +- **合成式逐字段渲染**:为每个字段生成一个项目符号列表、表格或带注释的 YAML 片段,由解析后的 JSDoc 加 schema 元数据组装。否决,改用逐字粘贴:带 JSDoc 的接口本身就是以其原始形式撰写的契约,合成渲染器会重新格式化它不拥有的行文,增加一层可能歪曲原意的渲染。 +- **运行时启动 + schema 内省(如工具目录的做法)**:否决。此处没有任何内容是运行时组合的,而且 schema 本身对配置表面的文档化不足(行文记录的默认值、运行时专用字段、完全没有 schema 的插件)。启动只会增加脆弱性而不增加真相。 +- **双向 schema/接口相等性检查**:否决,改用子集检查。声明类型合理地包含 schema 拒绝从配置接受的成员(运行时专用的 seam)。 +- **在同一变更中废弃 README 的 `## Config` 章节**:否决。接受的重叠使逐 package 契约在原地可读,而一次清扫需要先把每个 README 的额外事实折入字段 JSDoc——这是可分离的工作,目录不依赖它。 + +## 后果 + +- 目录不会漂移:源码变化而提交的文件未反映时,`verify-config-catalog` 在 pre-push 和 CI 中失败。未记录的配置字段、无法解析的引用类型名称、或 schema 键在配置类型中缺失,都会导致生成器直接报错。 +- 配置行文现在在声明处有了强制函数:编写新的配置字段意味着编写其 JSDoc,而 JSDoc 会逐字成为目录条目。 +- 生成器对无法静态遍历的形状硬错误——别名化的 package 内部配置导入、非 `object`/`intersect` 组合构建的 schema、未列入的全局类型名。引入这样的形状就必须同时教会生成器(否则该形状不能进入仓库),这正是设计意图:目录始终是全部真相。 +- `gen-cordis-catalog.ts` 导出其 JSDoc/指针辅助函数与 `LINK_MAP` 供复用,因此两个目录以相同方式交叉链接类型,新增一条 link-map 条目同时服务于两者。 diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml new file mode 100644 index 0000000000..d7db5cac08 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-06-node-engine-floor.md: 561b6b4a124b6eaa8e2ba0756a835e35519b30b8 +2026-07-06-node-engine-floor.zh.md: c6ace7a1296b5e3049ff4ef55f29b689fce7f4ff diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md index af08c96be3..561b6b4a12 100644 --- a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md @@ -1,5 +1,7 @@ # RFC: Raise the Node LTS engine floor to 22.19 +English | [中文](2026-07-06-node-engine-floor.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md new file mode 100644 index 0000000000..c6ace7a129 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md @@ -0,0 +1,39 @@ +# RFC:将 Node LTS 引擎下限提升至 22.19 + +Status: implemented + +[English](2026-07-06-node-engine-floor.md) | 中文 + +## 问题 + +根 `engines.node` 范围中的 Node 22 分支是对已安装工作区的契约,而不仅仅是 harness 源码直接调用的运行时 API 的契约。该分支的下限不得低于工作区在该分支上安装的依赖所声明的 package `engines.node`;否则 `pnpm install --engine-strict` 会在一个被宣传的 LTS 版本上失败,而非严格模式的安装则会在依赖所支持的运行时范围之外运行。 + +## 决策 + +将 `engines.node` 设为 `^22.19.0 || >=24.0.0`,并在 keyless CI 兼容性矩阵中测试 `['22.19', 24, 26]`。每个矩阵分支都运行 TypeScript 类型检查加一次 keyless 的源码模式 worker 冒烟测试,因此引擎下限同时通过完整的源码类型检查和真实的未构建运行时路径得到验证。真实 API 的 e2e 工作流保持在 Node 24 上运行,因为它验证的是 API 集成而非运行时下限。 + +两项 Node 特性决定了源码运行时的下限: + +- **`node:sqlite`**:`packages/session-persistence/session-persistence-sqlite` 在顶层执行 `import { DatabaseSync } from 'node:sqlite'`。该模块在 **22.13**(LTS)和 **23.4**(Current)取消了 `--experimental-sqlite` flag 要求;在此之前,导入它会在加载时抛出异常。 +- **原生 TypeScript 类型剥离**:`packages/examples/stdio-demo/tests/built-bin.e2e.ts` 冒烟测试在纯 `node`(无 tsx)下启动已发布的 `lib/bin.js`,并加载示例的 `.ts` 插件(`mock-llm.ts`、`echo-tool.ts`)。类型剥离从 **22.18**(LTS)和 **23.6**(Current)起成为默认行为;在此之前需要 `--experimental-strip-types`。 + +这些源码特性在 22.x 线上于 **22.18** 全部就绪,但已安装的 Pi 适配器依赖将宣传的 LTS 下限进一步抬高。`@deepseek-ai/dsh-llm-pi-ai` 依赖 `@earendil-works/pi-ai@0.79.3`,后者的 package 声明 `engines.node >=22.19.0`,因此 LTS 下限为 **22.19**。24.x 分支保持 `>=24.0.0`。该不连续范围完全排除 Node 23:Node 23.0–23.5 仍有至少一项源码特性需要 flag,而 23 线是非 LTS/已 EOL,宣传 `>=23.6` 只会增加一个已死的发布线和一个不应被任何部署使用的 CI 分支。 + +`@types/node` 继续固定在 22.x 线(`^22.20.0`),以匹配 LTS 支持线:如果使用了 Node 23+/24+/25+ 才有的 API,`tsc` 会在所有机器和类型检查门禁中报错,而不是编译通过后存活到只有下限矩阵分支才能捕获的运行时失败。整棵树目前在 Node 22 类型表面上类型检查全部通过,因此这个固定没有代价。 + +## 后果 + +- 宣传的 LTS 分支不再低于 Pi 适配器依赖的下限。 +- CI 用 Node 22.19 直接验证 Node 22 LTS 下限,Node 24 分支保持 `node: 24`,Node 26 用于下一个偶数线;每个分支都对源码图做类型检查,并实际启动未构建的工作流 worker。 +- built-bin 冒烟测试不需要版本条件 flag:在 22.19 上类型剥离已是默认行为,因此测试保持其文档记录的纯 `node lib/bin.js` 路径。 +- 未来如有依赖或源码 API 抬高运行时下限,必须在同一个变更中同步修改 `engines.node`、兼容性矩阵与本 RFC。 + +## 曾考虑的替代方案 + +- **保持 `^22.18.0 || >=24.0.0`。** 否决:它宣传的 LTS 版本低于 Pi 适配器依赖的下限。`@earendil-works/pi-ai@0.79.3` 要求 `>=22.19.0`。 +- **降级或固定 `@earendil-works/pi-ai` 以保留 22.18 的宣传范围。** 否决:当前的 Pi 适配器依赖是工作区的预期组成部分,且 22.19 仍在 Node 22 LTS 线内。 +- **下限设为 `>=22.13`(`node:sqlite` 边界),在 22.13–22.17 的 built-bin 冒烟测试中加 `--experimental-strip-types`。** 否决:为一个窄范围增加版本条件测试 flag,并将对实验性 flag 的依赖伪装成正式支持。Pi 适配器依赖已经要求更高的 LTS 下限。 +- **开放式 `>=22.19`。** 否决:它宣传支持 Node 23.0–23.5,而在这些版本上 `node:sqlite`(直到 23.4)或类型剥离(直到 23.6)仍需 flag。 +- **包含 Node 23.6+(`^22.19.0 || >=23.6.0`)。** 否决:23.6+ 确实能无 flag 运行两项源码特性,但 Node 23 已 end-of-life;宣传一个已死的发布线只会增加一个范围项和一个 CI 分支,用于一个不应被任何部署使用的运行时。 +- **矩阵用 `[22, 24, 26]` 而非固定 `22.19`。** 否决:浮动的主版本号条目会随时间上漂,悄然不再验证所声明的 LTS 下限。 +- **让 `@types/node` 超前于下限(`^25`)。** 否决:类型定义超前于运行时下限会让仅 Node 24/25 才有的 API 编译通过,仅在 22.x 上运行时才失败。将 `@types/node` 固定在 22.x 线上,会把这种情况变成所有环境下的编译错误。 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml new file mode 100644 index 0000000000..81369745d3 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-06-parallel-github-ci-gates.md: 890adf58ac8a20a39806aa028d035cb253d5a4f1 +2026-07-06-parallel-github-ci-gates.zh.md: 02502b1005a1f8e6f9f539878c792a9f0585e926 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md index be31a439c1..890adf58ac 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md @@ -1,5 +1,7 @@ # RFC: Parallel GitHub CI gates +English | [中文](2026-07-06-parallel-github-ci-gates.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md new file mode 100644 index 0000000000..02502b1005 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md @@ -0,0 +1,41 @@ +# RFC:并行 GitHub CI 门禁 + +Status: implemented + +[English](2026-07-06-parallel-github-ci-gates.md) | 中文 + +## 问题 + +keyless GitHub CI 门禁大多彼此正交:类型检查、lint、文档新鲜度、覆盖率、快照回放、构建、包发布卫生检查、demo 冒烟测试和 built-bin 冒烟测试各自因不同原因失败,且不需要彼此的运行时状态。将它们串成一条有序命令链,工作流的挂钟时间等于所有门禁之和;而将每个叶子门禁拆成独立的 GitHub job,则会重复 checkout、Node 搭建、pnpm restore 和 install 工作,直到编排开销本身成为瓶颈。 + +难点在于产物边界。`publint`、`verify-node-next-types` 和 built-bin 冒烟测试需要构建出的 `lib/` 输出,而大多数门禁只需要源码和依赖。盲目扇出要么让这些产物消费方在 `pnpm run build` 输出声明文件和 bundle 之前就开始执行,要么在每个依赖产物的 job 中重复构建。 + +## 决策 + +[CI](../../../../.github/workflows/ci.yml) 将 keyless 检查分组为若干宽粒度的主运行时 lane,外加一个兼容性矩阵。工作流文件拥有当前 lane 和运行时清单的定义权。 + +每个 lane 委托给 [scripts/run-gates.ts](../../../../scripts/run-gates.ts),后者以有界并发调度独立门禁,并为每个门禁打印一个可归因的结果块。产物消费方在各自 lane 内依赖一次 build;兼容性 job 则将类型检查与一次真实的未构建 worker 启动相结合,以覆盖运行时特定的 loader 行为。 + +生成的 `.sessions/` 日志和 `.doc-typecheck-*` 临时目录被 lint 忽略。聚合的本地 CI 模式仍在 lint 之后运行 demo 冒烟测试;而拆分后的 GitHub 静态 lane 可以直接运行 demo 冒烟测试,因为 lint 已隔离在自己的 lane 中。 + +构建输出在 Node 24 产物 lane 中只生成一次。产物消费方(`publint`、`verify-node-next-types` 和 built-bin 冒烟测试)声明对 `build` 的依赖,因此没有 upload/download 交接,消费方也不可能抢在声明文件或 bundle 之前执行。CI 覆盖率报告仅为文本格式,本地覆盖率则保留 HTML 报告。 + +两个工作流都缓存 pnpm store。真实 API 工作流使用共享的有界 Vitest 文件池,而非为每组测试单独开 job。 + +## 曾考虑的替代方案 + +- **在 Node 矩阵中保留完整串行链**:最容易理解,但会重复执行不产生 Node 版本特定信号的仓库级门禁,且让每个 PR 等待所有门禁之和。 +- **每个门禁各开一个 GitHub job**:最大化 GitHub 可见的扇出,但产生过多 check,且对运行时间短于 runner 准备时间的门禁反复支付 setup/install 开销。 +- **将构建产物上传给依赖产物的 job**:在多 job 间保持正确性,但增加了 artifact upload/download 时间,且在产物消费方可以通过主 job 内的本地依赖运行时仍保持工作流过宽。 +- **并发运行 `typecheck` 和 `build`**:向调度器暴露更多工作,但两者都调用 `tsc -b`;在它们之间共享增量构建状态是一场不必要的竞争,换来的挂钟收益很小。 +- **使用无界的真实 API e2e 并行度**:否决。该套件包含大量真实模型/工具场景;worker 池需要一个显式的 `DSH_E2E_MAX_WORKERS` 上限,这样 CI 和本地运行都能扇出而不会把配额或资源问题隐藏在不稳定的限流失败背后。 + +## 后果 + +PR 反馈以少量 GitHub check 呈现,每个宽粒度 job 内部包含结构化的逐门禁日志块。这使 runner setup 开销可控、Actions UI 紧凑,代价是失去了每个叶子门禁各自独立的 status check。 + +宽粒度 lane 拆分比单一主 job 更频繁地重复 checkout、setup 和 install。这一 setup 开销是有意为之:在 GitHub 托管 runner 上,将 lint、覆盖率和快照回放放在同一个进程池中运行会严重超额占用 CPU,以至于单 job 的关键路径反而长于重复 setup 的方案。 + +这种拆分引入了一项维护义务:当 `package.json` 增删属于 CI 的门禁时,[scripts/run-gates.ts](../../../../scripts/run-gates.ts) 需要相应增删叶子。这一义务是有意的,因为该 runner 是同一套门禁词汇的并行执行计划,而非独立的质量策略。 + +兼容性信号窄于主 Node 24 信号。它证明源码图在每个宣称支持的运行时上能通过类型检查、且真实的未构建 workflow-worker 启动路径能正常执行,而不必重复文档、覆盖率、发布卫生、快照回放和其他不因 Node 版本而异的冒烟检查。 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml new file mode 100644 index 0000000000..3adf939f24 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-06-parallel-pre-push-gates.md: 8a8813f2f3f6726ab2ab028757406d366ceb8b6d +2026-07-06-parallel-pre-push-gates.zh.md: 36207e522982990c193f9fe909faf380de53bca6 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md index f3a7b1e83c..8a8813f2f3 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md @@ -1,5 +1,7 @@ # RFC: Parallel pre-push gates +English | [中文](2026-07-06-parallel-pre-push-gates.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md new file mode 100644 index 0000000000..36207e5229 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md @@ -0,0 +1,42 @@ +# RFC:并行 pre-push 门禁 + +Status: implemented + +[English](2026-07-06-parallel-pre-push-gates.md) | 中文 + +## 问题 + +pre-push 钩子是分支离开本地机器前的最后一道检查点,因此它的挂钟时间直接影响贡献者是否愿意保持启用并信任其信号。Lefthook 已经能并行运行顶层 job,但 `pnpm run hygiene` 和 `pnpm run doc-sync` 这类聚合 job 在单个 job 内部隐藏了长串的顺序执行链。因此钩子可以配置为并行,却仍在等待那些成员彼此独立的串行子命令。 + +把这些成员直接展平到 `lefthook.yml` 只能解决本地钩子的问题。CI 有同样的调度问题,而在 YAML 中重复一份长长的叶子列表会让未来的脚本改动有两处可能漂移。 + +`publint` 在更低一层也有同样的形态。每个包独立地针对自身的 manifest 和构建产物做 lint,但运行器按顺序逐个遍历所有包。在本仓库中,这意味着一个包发布门禁消耗的时间与包数量成正比,尽管各检查之间并不共享可变状态。 + +## 决策 + +[lefthook.yml](../../../../lefthook.yml) 保留一个名为 `full check` 的 pre-push job,运行 `pnpm run check:pre-push`。该包脚本委托给 [scripts/run-gates.ts](../../../../scripts/run-gates.ts),即 CI 使用的同一个有界调度器。 + +`pre-push` 模式展开为以下叶子门禁:单元测试套件、快照测试套件、构建、`hygiene` 成员、`doc-sync` 成员,以及 module-graph 新鲜度。叶子列表保持与包脚本相同的门禁词汇(包括 RFC 分类和 RFC 格式),运行器并发调度独立检查,并为每个门禁打印一个计时/输出块。 + +构建门禁使钩子在干净 worktree 上也能自给自足。`publint` 和 `verify-node-next-types` 等待构建产物,而仅依赖源码的门禁继续并行执行。 + +[scripts/publint-all.ts](../../../../scripts/publint-all.ts) 从 `packages/<group>/<pkg>` 发现包列表,并使用大小取自 `availableParallelism()` 的 worker 池运行 `publint`。`DSH_PUBLINT_CONCURRENCY` 可以为资源配置不同的本地机器和 CI runner 设置 worker 数量上限或提高上限。结果按包缓冲,并按确定性的包顺序打印,因此并行执行不会打乱每个包的日志块。 + +聚合包脚本仍然是临时本地运行的真源。调度器是对其成员门禁的并行执行计划,而非替代词汇。 + +## 曾考虑的替代方案 + +- **在钩子中保留聚合的 `hygiene` 和 `doc-sync` job**:配置更简单,但 pre-push 的大部分挂钟时间仍然花在 lefthook 看不到也无法调度的串行命令链内部。 +- **为每个叶子门禁声明一个 lefthook job**:通过 lefthook 原生的 job 模型暴露并行性,但会让钩子文件承载一份 CI 无法复用的长成员列表。 +- **要求开发者在推送前手动构建**:省去一个钩子门禁,但会导致 `publint` 在干净 worktree 上失败,并把最后的本地检查点从可运行的检查降格为一项约定。 +- **在 shell 脚本中使用后台子命令**:能并行化工作,但会丢失 lefthook 的 job 名称、逐 job 计时和失败分组,且信号处理更难推理。 +- **为每个包声明一个 publint lefthook job**:暴露最大并行度,但会把钩子变成一份手工维护的包清单,恰好在新增包时漂移。 +- **以无界并发运行 publint**:仅在小型机器上以赌进程数、内存压力、包 tarball 创建和日志可读性为代价来最小化耗时。 + +## 后果 + +钩子的关键路径变为最慢的那个实际门禁,而非隐藏门禁链的总和。Lefthook 报告一个 `full check` job,运行器在该 job 内部报告逐门禁计时,因此本地检查点慢时仍能指出主导耗时的那个门禁。 + +钩子文件保持简短,重复的成员列表集中在 [scripts/run-gates.ts](../../../../scripts/run-gates.ts) 中,CI 和 pre-push 可以共享。代价是一个自定义调度器脚本(而非纯 lefthook 配置),外加本地 pre-push 路径中的一次构建。 + +`publint-all.ts` 变为异步代码,缓冲命令输出而非实时继承 stdio。收益是包级并行、稳定的输出顺序,以及一个用于资源调优的环境变量。 diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml new file mode 100644 index 0000000000..bd24f4a6c1 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-10-readme-known-limitations-gate.md: b7f45421bf0d4d50ec1a19941934e782f52e7926 +2026-07-10-readme-known-limitations-gate.zh.md: 4dd8db1df9b0b2be73e7ae6a64e11b8dabc2add1 diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md index 6cd8851149..b7f45421bf 100644 --- a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md @@ -1,5 +1,7 @@ # RFC: A gated Known-Limitations section in every package README +English | [中文](2026-07-10-readme-known-limitations-gate.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md new file mode 100644 index 0000000000..4dd8db1df9 --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md @@ -0,0 +1,29 @@ +# RFC:在每个 package README 中设置受门禁保护的「已知限制」章节 + +Status: implemented + +[English](2026-07-10-readme-known-limitations-gate.md) | 中文 + +## 问题 + +[文档标准](../../../AGENTS.md)将限制事项归属于 package README。如果没有统一的格式,缺失的章节无法区分「经过审计确认无限制」和「忘记写了」,而各式各样的标题也让仓库级搜索无从下手。 + +## 决策 + +`packages/<group>/<pkg>/package.json` 下的每个 package manifest(元数据清单)都有一个同级 README,其中包含规范的 `## Known Limitations and Deferred Work` 章节。该章节的条目记录该 package 拥有的持久性消费方缺口与非显而易见的维护约束;普通的清理工作留在源码 TODO 或所属 RFC 中。[`verify-package-readme-limitations` 门禁](../../../../scripts/verify-package-readme-limitations.ts)从 manifest 推导 package 集合,拒绝缺少 README 的情况,并要求恰好有一个规范的 h2 标题且至少包含一个顶级条目。近似标题(如 "Limitations"、"Deferred"、"What is NOT here" 或 "Non-goals")会导致失败。 + +如果一个 package 确实没有需要声明的限制,则将其列入 `NO_LIMITATIONS` 并省略该章节。新增限制时必须移除该条目;重命名或删除条目会失败,因为每个条目必须对应一个被扫描的 package。 + +门禁检查存在性、格式和白名单。覆盖率与准确性由文档标准和[行文标准](../../../../.agents/skills/dsh-prose-standard/SKILL.md)下的评审负责。常设规则见 [packages/AGENTS.md](../../../../packages/AGENTS.md)。 + +## 曾考虑的替代方案 + +- **自由格式标题**:无法统一搜索,仍然需要近似标题检测。 +- **要求空章节或写 "None."**:样板文字可能在 package 新增限制后仍然残留;白名单使「确认无限制」显式且可评审。 +- **施加字数上限**:合理的限制条目数量因 package 而异,因此由评审管控这一不设预算的 README 层级。 + +## 后果 + +- 新 package 要么声明符合条件的限制事项,要么显式加入白名单;缺失、漂移或空白的章节会在本地和 CI 的 `doc-sync` 中失败。 +- 门禁向 `doc-sync` 新增一个无外部依赖的 TypeScript 脚本。 +- 重命名被强制的标题需要同时修改脚本和所有 package README。 diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml new file mode 100644 index 0000000000..7796a46dfc --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-12-package-model-experience-contract.md: 036efbc9510d6d0ae9e3c52a5ba8f39647adc4c9 +2026-07-12-package-model-experience-contract.zh.md: 6ee96f3befbb2ead7196f412dccf915f475cfc6d diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md index 0f9b0b02a0..036efbc951 100644 --- a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md @@ -1,5 +1,7 @@ # RFC: Package Model Experience contract +English | [中文](2026-07-12-package-model-experience-contract.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md new file mode 100644 index 0000000000..6ee96f3bef --- /dev/null +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md @@ -0,0 +1,33 @@ +# RFC:包(package)模型体验契约 + +Status: implemented + +[English](2026-07-12-package-model-experience-contract.md) | 中文 + +## 问题 + +一个包的 README 可以解释 API 和运行时机制,却不回答主导 agent harness(智能体框架)行为与成本的核心问题:这个包中有什么内容会进入模型请求、在什么条件下进入、以及这些 token 会保留多久。在插件架构中,这一缺失尤其难以审计。消费方可能把后端结果转为工具消息,策略插件可能把成功替换为错误,压缩(compaction)可能移除旧历史,agent 作用域的注册可能改变某个 agent 的提示词或 schema 而对其他 agent 毫无影响。因此只阅读名义上面向模型的包会遗漏真实的上下文影响,而逐依赖阅读源码对于日常评审又过于昂贵。 + +## 决策 + +每个具有面向模型或模型相邻契约的 workspace 包 README,都以规范的 [Model Experience 章节](../../../cookbook/adding-a-package.md#4-write-the-package-readme)结尾,紧接在 `## Known Limitations and Deferred Work` 之前;如果包在 no-limitations 允许列表上,则以 Model Experience 本身结尾。经审计确认为模型无关的通用包通过 `NO_MODEL_EXPERIENCE_SECTION` 省略该章节。 + +具有直接、条件性、有上限、生命周期性、多表面或辅助模型效应的包,每个上下文表面使用一个 H3。每个 H3 说明相关模型接收到什么内容、何时接收,并对 token 效应进行分类。包所拥有的稳定文本逐字引用:系统提示词及其他长文本使用嵌套 H4 加 `markdown` 围栏,短文本则以行内形式保留,带命名的插值占位符。工具 schema 表面链接到生成的[工具目录](../../../tool-catalog.md)中对应的锚点章节,只陈述组合或配置差异;仅在运行时定义的则说明目录为何未收录。数据依赖和提供方拥有的文本以摘要形式呈现。agent 作用域的可见性须显式标注;当作用域可以隐藏提示词而不隐藏 schema(或反之)时,提示词和 schema 表面保持分开记录。 + +没有模型上下文效应的包,或其路径完全由另一个包渲染的包,使用验证器审计过的单句形式:`None, as ` 或 `Indirectly, through `。纯传输和无 ctx key 的测试支持包在不产生模型绑定内容时使用 none 形式。提供方后端即使会截断或过滤数据,也使用 indirect 形式;组装 bundle 在所有效应由具名子包拥有时同样使用 indirect 形式。这些句子定位贡献所在,而不重述消费方的内容。结构化章节同样只记录包自身拥有的输入、转换和差异。 + +`verify-package-readme-model-experience` 发现包的 manifest 并验证三种分类、规范的末尾章节顺序、必填字段、具体的文本证据、嵌套的逐字块以及锚定的工具目录链接。它在 `doc-sync` 和并行门禁运行器中运行。覆盖面、链接相关性和事实准确性仍由评审把关。 + +## 曾考虑的替代方案 + +- **只记录注册了提示词或工具的包**:否决。后端、策略插件、适配器、持久化、作用域和压缩都会改变 token 的内容或生命周期,却不拥有面向模型的 schema。 +- **从源码生成一份中央上下文成本目录**:否决。AST 能找到注册点,但无法推断语义条件,例如历史保留、输出截断、父子可见性或辅助模型边界。包 README 是实现本地的契约;中央副本会增加又一个漂移面。 +- **要求给出数值 token 计数**:否决。精确计数取决于所选模型的 tokenizer、适配器序列化方式、配置和运行时数据。稳定的契约是增长形态:每请求固定、每调用条件性、保留、替换、有上限或零直接。 +- **使用三列表格**:否决。精确的源文本和条件性结果形态使单元格过于密集、难以扫读。重复的子章节为每个上下文表面提供可读的纵向空间,同时保留相同的字段。 +- **允许所有零影响包省略该章节**:否决。无约束的缺失在「经审计的零影响」和「忘了写文档」之间是歧义的。省略仅限于在验证器中以理由具名的模型无关通用包;模型相邻的零影响包保留一句显式说明。 +- **要求经审计的零影响或简单间接包也使用完整结构化形式**:否决。围绕一个事实重复标签没有意义。一句受门禁约束的句子在保持显式覆盖的同时免去了仪式感。 +- **只有约定、没有门禁**:否决。仓库级契约必须覆盖未来的每个包;评审者的记忆无法可靠地检测到遗漏的 README 章节。 + +## 后果 + +评审者可以从任何面向模型或模型相邻的包出发,看到它对会话模型、子模型和辅助调用的贡献,而无需重建完整的插件图。token 预算工作可以区分每次请求的重复开销与数据依赖的历史,agent 作用域的变更有了显式的文档检查点。包作者在模型可见行为变化时维护一个或多个紧凑的上下文表面块,或一句经分类的句子;经审计的通用包不带无关的模型样板文字。结构化字段不承诺提供方精确的 token 计数;测量仍然是模型和负载特定的,而文档化的增长形态与可见性契约保持稳定。 diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml new file mode 100644 index 0000000000..f88f300193 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-19-drop-mutable-session-summary.md: 0d790191906a9128ad12d40526fde3b9f8fa939f +2026-06-19-drop-mutable-session-summary.zh.md: 97293c296cd74b5a33ce7e1ebe473c970ee95d57 diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md index 54f8397fc9..0d79019190 100644 --- a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md @@ -1,5 +1,7 @@ # RFC: Drop the mutable session summary +English | [中文](2026-06-19-drop-mutable-session-summary.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md new file mode 100644 index 0000000000..97293c296c --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md @@ -0,0 +1,35 @@ +# RFC:移除可变的会话摘要 + +Status: implemented + +[English](2026-06-19-drop-mutable-session-summary.md) | 中文 + +## 问题 + +[会话持久化 seam](../architecture/2026-06-14-session-persistence.md) 将会话的日志外元数据拆分为 `dsh-session` 拥有的两种类型:一个不可变的 `SessionHeader`(`version`、`id`、`createdAt`、`cwd?`、`parentSession?`),在创建时一次性写入;一个可变的 `SessionSummary`(`updatedAt`、`title?`、`firstPrompt?`),「无需触碰仅追加日志即可更新」。二者的联合类型为 `SessionMeta = SessionHeader & SessionSummary`,抽象的 `SessionPersistence` 服务为此多出第七个方法 `update(id, summary)`,用于重写摘要。各后端各自实现可变存储:JSONL 在日志旁写一个独立的原子 `.summary.json` **伴随文件**(临时写入 + rename,尽力而为);SQLite 在追加事务内更新 `updated_at`/`title`/`first_prompt` **列**。 + +摘要的设计初衷是服务于未来的会话选择器(通过 `updatedAt` 排序、用 `title`/`firstPrompt` 预览)。该选择器从未实现。对整个仓库的审计表明,`SessionSummary` 的全部表面积都是**死状态**: + +- `SessionPersistence.update()` 的**生产调用方为零**(所有 `.update(` 命中都是 `createHash().update()` 或测试代码)。 +- `firstPrompt` 在生产代码中**从未被读取**。 +- `title` 确实在 ACP bridge 中被读取,但来源是工具调用的 **presenter**(`present.title`),而非存储的会话元数据。 +- `updatedAt` **没有消费方**:`list()` 唯一的生产调用方读取的是 `meta.cwd`(`SessionHeader` 字段),用于在 `session/load` 时校验工作区;resume 读取的是 `createdAt`/`cwd`/`parentSession`,全部是 header 字段。 +- 决定性的事实:活跃的 `Session.header` 早已被类型化为 `SessionHeader` 而非 `SessionMeta`——摘要从未存在于活跃会话对象上;它只存在于持久化层,除了自身的契约测试之外无人写入、无人读取。 + +## 决策 + +彻底删除可变的会话摘要。`SessionSummary` 与 `SessionMeta` 这个名称一并移除;后端存储和返回的元数据仅为 `SessionHeader`。`SessionPersistence.update()` 从抽象服务和所有后端中移除。JSONL 去掉整套伴随文件机制(`writeSidecar`/`readSidecar`/`touchSummary`/`removeSidecars`/`sidecarPath` 以及 load/list 的覆盖逻辑);SQLite 删除 `updated_at`/`title`/`first_prompt` 列及每次追加时的 `updated_at` 更新,其 `SCHEMA_VERSION` 从 `1 → 2`。 + +摘要原本要提供的一切,在消费方真正需要时都**可从仅追加日志中派生**(`firstPrompt` = 第一条 `user/message`;最近活跃时间 = 最后一个事件的 `time` 或文件 mtime),或者已经存在于不可变的 header 中(`createdAt`、`cwd`)。唯一*不可*派生的——用户*手动编辑*的标题——没有任何实现,纯属 YAGNI;如果未来真有功能需要,它可以作为独立的日志事件或 header 字段回归。 + +将此记录为决策,是因为它**持久**(收窄了一个公开服务契约和两个后端的磁盘格式)、**有争议**(摘要是有意的前瞻性设计,不是意外产物)、**出人意料**(未来读者看到 `SessionHeader` 而原始 RFC 描述的是 `SessionMeta`,否则会疑惑摘要为何消失)。它还为[共享持久化写入协调器](../architecture/2026-06-18-shared-persistence-write-coordinator.md)扫清了障碍:没有可变摘要,协调器的钩子接口就不需要 `updateSummary` 钩子,JSONL 伴随文件与 SQLite 列之间的持久性差异也随之消失,两个后端的写入路径得以收敛。 + +## 无需迁移 + +这是未发布的软件(见[根 AGENTS.md](../../../../AGENTS.md)「预发布立场:地基优先于爆炸半径」一节),因此不存在需要保留的磁盘数据库或日志。SQLite 不迁移 v1 数据库:`openDatabase` 守卫现在拒绝任何非当前版本的磁盘 `user_version`(`onDisk !== 0 && onDisk !== SCHEMA_VERSION`),无论更旧还是更新,因此陈旧的 v1 数据库会被干净地拒绝,而非在新列集上半读半错。新建数据库写入当前版本号;这是唯一需要工作的路径。 + +## 后果 + +未来的会话选择器现在必须从日志派生预览和排序信息(或重新引入一个类型化字段),而不能直接读取现成的摘要行。这是正确的代价:为一个不存在的功能维护缓存,是每个后端都要承担的死重,也是每个契约测试都要断言的负担。这一原则——**通过的测试固定的是当前行为,不一定是正确行为;行为可能是过去妥协的产物**——现已作为独立约定记录在[根 AGENTS.md](../../../../AGENTS.md) 中,本次变更即为其实例。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml new file mode 100644 index 0000000000..0e73dbfe7e --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-collapse-trace-only-session-events.md: 9156c2ab356b1c46758d9d2047d491cd1952cbc4 +2026-06-20-collapse-trace-only-session-events.zh.md: f2ecfbf46d8d70cf478d57eae2ed3a18ea8746fa diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md index a93e3d3196..9156c2ab35 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md @@ -1,5 +1,7 @@ # RFC: Fold trace-only session facts into load-bearing events +English | [中文](2026-06-20-collapse-trace-only-session-events.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md new file mode 100644 index 0000000000..f2ecfbf46d --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md @@ -0,0 +1,44 @@ +# RFC:将仅用于追踪的会话事实折叠进承载性事件 + +Status: implemented + +[English](2026-06-20-collapse-trace-only-session-events.md) | 中文 + +## 问题 + +会话事件词汇中包含一些一等事件,它们既不属于可回放的对话历史,在生产环境中也几乎没有消费方。`usage` 在模型流式分片中已经存在,但循环又额外追加了一个独立的 `usage` 事件。`error` 与 `turn/end { kind: 'error', message, code }` 中的循环失败原因重复;ACP(Agent Client Protocol)结算读取的是 turn-end 原因,ACP 渲染忽略 `error` 事件,`deriveMessages()` 也跳过它。 + +这些事件让规范的 transcript(文本记录)看起来比实际更像遥测数据。它们增加了事件变体、不变式、测试、快照和持久化用例,但作为独立记录并不承载实际负荷。它们携带的事实仍然有用:token 用量应当保留以供核算,错误的步骤编号也不应悄然消失。简化的方式是将这些事实折叠进消费方本就必须理解的邻近事件,而非减少记录的信息量。 + +## 决策 + +仅在信息已被保留、无需并行记录的位置移除独立的追踪事件: + +- 成功步骤的 usage 折叠进对应的 `assistant/message`(`assistant/message { turn, step, content, usage? }`),使组装好的模型输出与其核算信息一同传递。 +- 失败或中止的步骤如果有 usage 但没有 assistant 内容,则将 usage 挂在一个空内容的 `assistant/message` 上(下方实现说明给出了无信息丢失的证明)——不会有任何已持久化的 usage 分片失去表示。 +- 独立 `error` 事件中的步骤编号折叠进 `turn/end.reason`(当 `kind: 'error'` 时:`{ kind: 'error', step, message, code? }`)——`turn/end` 是 ACP 和恢复机制已在消费的持久化轮次结果。 +- `agent/error` 和日志保留用于实时诊断;`turn/end` 之后不再有第二条会话日志错误记录。 + +用户对话日志包含渲染、恢复、审计和核算交互所需的全部信息,消费方无需对账重复的追踪行。 + +## 曾考虑的替代方案 + +**保留独立行作为遥测**:这些事件让规范的 transcript 看起来比实际更像遥测数据,代价是增加了事件变体、不变式、测试、快照和持久化用例,却没有消费方使用。如果分析需求真正出现,正确的形态是投影辅助工具或带有独立保留策略的专用遥测存储,而非在对话日志中放置重复的追踪行。 + +## 验证 + +`SessionEventMap` 不再包含独立的 `usage` 或 `error`;循环不再追加独立的 usage 事件,持久化的失败通过 `turn/end { kind: 'error', step, message, code? }` 记录;ACP 快照和持久化测试断言不存在仅追踪行;录制的 fixture(测试前置数据)已采用新事件形状,会话格式版本固定为 `0`(按预发布格式策略,后端拒绝任何非 `0` 的存储日志);文档说明了 token 用量和操作错误的观测位置。 + +## 后果 + +消费方不能再从规范日志中筛选独立的 `usage` 或步骤级 `error` 行,必须从承载它们的 assistant/failure 事件中读取这些事实。只有当实现 PR 证明相同的事实仍然存在时,这才是合理的简化;否则独立事件应当保留。 + +## 实现说明 + +按提案交付,有一处范围细化(遵循 AGENTS.md「RFC 是提案,不是金科玉律」): + +- **空内容的 `assistant/message` 承载 usage,无数据丢失。** 提案要求的证明(不会有已持久化的 usage 分片失去表示)落在 max-tokens 路径上:一个被截断的步骤有 usage 但内容为空(例如只有一个被丢弃的工具调用),此前会发出独立的 `usage`。现在它记录一条空内容的 `assistant/message { content: [], usage }`。为避免这向提供方 transcript 注入一个无内容的虚假 assistant 轮次,`deriveMessages()` 跳过空内容的 `assistant/message` 事件。一个回归测试断言 usage 仍有表示,且派生历史未被破坏。 + +**格式版本。** 此变更改动了持久化事件,但预发布会话格式仍固定为 `0`,拒绝任何其他版本且不做迁移。`dsh-session` 拥有写入方和加载校验使用的常量。单调递增的格式版本从首次正式发布开始。 + +Usage 现在通过 `assistant/message.usage` 观测;操作错误的步骤编号通过 `turn/end.reason`(当 `kind: 'error'` 时)观测。`agent/error` 加日志用于实时诊断,保持不变。 diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml new file mode 100644 index 0000000000..8586b4051e --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-drop-unconsumed-llm-adapter-change-event.md: efe90c0197671ef4385ce517540b4b238962c3b5 +2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md: 13f01566472a030cc9d4f97f6e4438fe4c3ecbf8 diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md index ab921dd62c..efe90c0197 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md @@ -1,5 +1,7 @@ # RFC: Drop the unconsumed `llm/adapter-change` event +English | [中文](2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md new file mode 100644 index 0000000000..13f0156647 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md @@ -0,0 +1,36 @@ +# RFC:移除无消费方的 `llm/adapter-change` 事件 + +Status: implemented + +[English](2026-06-20-drop-unconsumed-llm-adapter-change-event.md) | 中文 + +## 问题 + +`LlmService.registerAdapter()` 在注册和 dispose(资源释放)时发射 `llm/adapter-change`([packages/llm/llm/src/index.ts](../../../../packages/llm/llm/src/index.ts))。在 `packages/*/src` 和 `examples/*/src` 中 grep `llm/adapter-change`,只能找到声明、发射点、文档和测试;没有任何生产代码监听它。 + +这与 `tools/change` 和 `system-prompt/change` 不同。后两个事件目前同样无消费方,但它们是合理的注册表变更信号,未来的实时工具/提示词 UI 可能用到。LLM 适配器注册更像是启动时的实现细节:适配器不是用户可见的面板,真正的模型调用拦截 seam 是 `llm/stream`。保留一个没有监听者的 adapter-change 事件,是 [drop-the-dead-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 模式在更小尺度上的重复。 + +这个事件并非零成本。`registerAdapter()` 在发射 `llm/adapter-change` 之前先 yield 回滚 disposer,这样抛异常的监听者会回退变更而不是泄漏一条适配器条目;包里还有测试覆盖这条监听者抛异常的路径。这种防御性排序所保护的失败模式,只有测试才能触发。 + +## 决策 + +只移除 `llm/adapter-change`:`dsh-llm` 的 `interface Events` 中的声明、`ctx.emit('llm/adapter-change')` 调用,以及 `LlmService.registerAdapter` JSDoc 中「在注册和 dispose 时发射 `llm/adapter-change`」的描述。`registerAdapter()` 的 effect generator 保留变更与回滚 disposer(用于 HMR(热模块替换)/dispose),但去掉仅为已移除事件而存在的监听者抛异常回滚排序。适配器 disposer 测试断言返回的 disposer 能移除适配器,不再订阅该事件;监听者抛异常的回滚测试随其主题一同移除。[docs/architecture.md](../../../architecture.md) 和 [packages/llm/llm/README.md](../../../../packages/llm/llm/README.md) 中的事件分类体系在同一个变更中更新。 + +## 曾考虑的替代方案 + +### 为什么不移除所有注册表变更事件? + +一个注册表主动广播变更的微内核是一种自洽的约定。`tools/change` 和 `system-prompt/change` 在 UI 能实时刷新可用工具或提示词段落时可能变得有用。本 RFC 在有合理的面向用户消费方的地方保留该约定,仅裁掉当前和可预见未来都没有明确消费方的 adapter-change 事件。 + +如果将来需要 LLM 适配器浏览器或动态模型选择器,届时再连同消费方一起重新引入该事件,并给出比「something changed」更清晰的 payload。 + +## 验证 + +`llm/adapter-change` 及其发射点已移除,重新生成的 cordis catalog 是最新的;HMR 安全性保持(dispose 一个贡献 fiber 会移除对应适配器);`tools/change` 和 `system-prompt/change` 仍有文档和测试;没有任何生产路径的可观测行为发生变化——ACP 快照 golden 和 echo-agent 冒烟测试逐字节不变。 + +## 后果 + +- **移除一个已文档化的发射事件属于公开接口变更。** 它出现在分类体系表中,读起来像是有意为之的 API。但「已声明并发射」不等于「有消费方」——这正是当初移除可变 summary 时所依据的同一区分。分类体系表在同一个变更中更新,因此文档不会漂移。 +- **注册表变更约定变得不均匀。** 这是可以接受的,因为 LLM 适配器注册与工具或提示词段落不是同一层面的用户可见概念。不均匀但诚实,胜过统一但空转。 + +这是一个小裁剪,但它退役了一条守护着不存在的消费方的常设正确性不变式。 diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml new file mode 100644 index 0000000000..46b752f26a --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-drop-unconsumed-llm-assembled-surfaces.md: c8999dd0e19b2c8eaff854c8ff544bae2fc068b6 +2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md: 090d3e779e3e7a9f1f0a65af7740ad685f723cf6 diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md index 2b10bf36db..c8999dd0e1 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md @@ -1,5 +1,7 @@ # RFC: Drop unconsumed assembled LLM convenience surfaces +English | [中文](2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md new file mode 100644 index 0000000000..090d3e779e --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md @@ -0,0 +1,39 @@ +# RFC:移除未被消费的 LLM 组装便利接口 + +Status: implemented + +[English](2026-06-20-drop-unconsumed-llm-assembled-surfaces.md) | 中文 + +## 问题 + +`LlmService`([packages/llm/llm/src/index.ts](../../../../packages/llm/llm/src/index.ts))在模型之上暴露了三个调用接口: + +- `stream()`:原始 `StreamChunk`,通过 `llm/stream` waterfall(瀑布式事件)分发。 +- `streamBlocks()`:一个"便利视图",将 chunk 送入 `BlockAssembler` 并按流顺序 yield 已组装完成的 `ContentBlock`([index.ts:137-144](../../../../packages/llm/llm/src/index.ts))。 +- `generate()`:一个完整组装的 `GenerateResult`,通过第二个 `llm/generate` waterfall 分发([index.ts:151-157](../../../../packages/llm/llm/src/index.ts))。 + +LLM(大语言模型)服务唯一的生产消费方是 agent loop(智能体循环),它只使用 `stream()`:将原始 chunk 送入自己的 `BlockAssembler`,以便在并行组装的同时记录 chunk 用于回放保真([packages/core/agent-loop/src/loop.ts](../../../../packages/core/agent-loop/src/loop.ts) 中的 `ctx.llm.stream(req)` 步骤)。在 `packages/*/src` 和 `examples/*/src` 中搜索 `streamBlocks` 与 `ctx.llm.generate`,找不到任何生产调用方。引用它们的只有服务方法定义、文档和测试;适配器测试用 `generate()` 作为便利驱动,但它们完全可以通过同一个 assembler 辅助函数手动消费 `stream()`,无需保留一个公开的生产 API。 + +这与 [drop-mutable-session-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 是同一模式:拥有测试契约的组装视图 API,消费方只有测试而非生产代码。它们是为"不关心 token 级增量"的消费方预先构建的,但唯一的真实消费方恰恰需要增量,以便持久化高保真的回放数据。 + +`streamBlocks()` 拖带了 `BlockAssembler` 中一块专用逻辑:`flushReady()` 和 `flushRemaining()`([packages/llm/llm/src/assembler.ts:138-168](../../../../packages/llm/llm/src/assembler.ts))以及 `flushed` 游标字段,仅为支持按序增量 yield 而存在。`generate()` 拖带了 `GenerateResult`、`BlockAssembler.result()` 以及 `llm/generate` waterfall——在同一底层流之上多出的第二个拦截面。agent loop 对 assembler 的使用仅限 `push()` / `message()` / `usage` / `finish`,不涉及流式 flush 或一次性服务组装。 + +## 决策 + +`stream()` 是唯一的公开 LLM 调用接口。移除 `streamBlocks`、`generate`、其事件/结果类型,以及仅被该路径使用的 assembler 辅助方法。适配器测试通过本地辅助函数对公开的 stream 进行组装,`BlockAssembler` 只保留有生产消费方的操作。 + +## 曾考虑的替代方案 + +**保留 `generate()` 作为仅供测试的便利方法**:否决。适配器测试通过共享 assembler 手动消费 `stream()`,走的是与生产相同的流式路径;一个唯一调用方是测试的公开方法,正是[移除可变摘要先例](2026-06-19-drop-mutable-session-summary.md)所清退的死接口形态。未来如果有消费方需要不带增量的组装块,届时再引入一个有真实消费方的专用辅助方法。 + +## 验证 + +`streamBlocks`、`generate`、`llm/generate` 以及仅被它们使用的 assembler 辅助方法已全部移除,无新增死导出;两个真实适配器通过 `stream()` 加共享 assembler 得到充分测试;agent loop 行为不变(ACP 快照 golden 文件无变化);README、架构文档与模块文档中不再提及被移除的接口。 + +## 后果 + +- **从一个核心词汇包中移除了公开方法。** 未来如果有插件需要不带增量的组装块,它需要直接调用 `stream()` 并使用 `BlockAssembler`,或在有真实消费方时重新引入一个专用辅助方法。鉴于预发布阶段「基础优先于投机性未来」的立场([AGENTS.md](../../../../AGENTS.md)),现在正是清除仅供测试的公开形状的正确时机。 +- **适配器测试变得更显式。** 它们失去了便利的 `generate()` 包装层,但这是有益的压力:测试走的是与生产相同的流式路径。 +- **waterfall 使用方失去 `llm/generate`。** 不存在生产监听者。未来的缓存/重试/日志插件应包装 `llm/stream`,它仍是唯一的提供方调用路径。 + +变更规模不大,但它干净地从 LLM 包中移除了投机性的接口面积,为生产和测试留下唯一一份模型调用契约。 diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml new file mode 100644 index 0000000000..20c7e3718a --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-prune-dead-seam-methods.md: cb3eb576dbae209ddccbea7f42a80ef09f842887 +2026-06-20-prune-dead-seam-methods.zh.md: d3c658ea2ce994e640ec4fd2cf5f74d82f695e69 diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md index ce16ff2ee2..cb3eb576db 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md @@ -1,5 +1,7 @@ # RFC: Prune dead methods from the persistence seam +English | [中文](2026-06-20-prune-dead-seam-methods.zh.md) + Status: implemented > **Implementation note:** Only `SessionPersistence.has()` and `.delete()` were removed. `BashExecutor.get()` and `.list()` remain because removing their one-line lookup surface required substantially more completion-tracking machinery in consumers. Their id branding is covered by the [branded-ids RFC](../architecture/2026-06-20-branded-ids.md). diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md new file mode 100644 index 0000000000..d3c658ea2c --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md @@ -0,0 +1,43 @@ +# RFC:清理持久化 seam 中的无用方法 + +[English](2026-06-20-prune-dead-seam-methods.md) | 中文 + +Status: implemented + +> **实现说明:** 最终只移除了 `SessionPersistence.has()` 和 `.delete()`。`BashExecutor.get()` 和 `.list()` 保留,因为移除它们的单行查找接口需要在消费方引入大量额外的完成状态跟踪机制。它们的 id 品牌化由 [branded-ids RFC](../architecture/2026-06-20-branded-ids.md) 覆盖。 + +## 问题 + +一个能力 seam([接口/实现/消费方](../../implemented/architecture/2026-06-13-capability-seams.md))携带了没有任何消费方调用的抽象方法。seam 存在的意义是让实现与消费方独立演进,但一个没有消费方编程依赖的方法不是 seam,而是投机性的接口面——每个实现仍然必须实现并测试它。 + +### `SessionPersistence.has()` 与 `.delete()` + +抽象服务在 create/append 之外声明了更多操作:`load`、`list`、`has`、`delete`。`ctx.sessionPersistence` 的生产消费方只用到两个:agent loop(智能体循环)的恢复路径调用 `load()`([packages/core/agent-loop/src/index.ts:176](../../../../packages/core/agent-loop/src/index.ts)),ACP 桥接层为 `session/list` 调用 `list()`([packages/ui/acp/src/index.ts:494](../../../../packages/ui/acp/src/index.ts))。在 `packages/*/src` 和 `examples/` 中 grep 所有 `sessionPersistence.*` / `persistence.*` 用法,找不到对该服务的 `has(` 或 `delete(` 调用。`packages/ui/acp/src/index.ts` 中的 `.has(`/`.delete(` 调用作用于内存中的 `SessionStore` 和一个本地的 loading id `Set`,而非持久化服务。`has`/`delete` 的唯一调用方是契约测试套件和各后端的 spec。 + +`has()` 不仅仅是未使用——它还是共享协调器中最复杂的分支:一个 tracked-vs-untracked 双探测(`loadLive(id, cwd)` 用于活跃跟踪的会话,`loadStored(id)` 用于未跟踪的会话),附带多行注释说明理由。`delete()` 则拖带了 `deleteStored` 后端钩子,每个后端都必须实现它。这与 [drop-mutable-session-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 是同一模式:契约测试覆盖了两者,但没有任何发布代码会问「这个会话是否已持久化?」或删除一个会话。 + +## 决策 + +没有消费方使用的方法被移除——从抽象 seam、实现,以及仅为覆盖它们而存在的契约/spec 测试套件中移除: + +- `SessionPersistence.has()` / `.delete()` 已移除:抽象声明、协调器的 `has`/`delete`/`deleteCore`,以及 `PersistenceBackend.deleteStored` 钩子(jsonl 和 sqlite 各自实现 `deleteStored` 仅仅是为了满足该钩子——那些实现也一并移除)。后端属于[双后端](../../implemented/architecture/2026-06-14-session-persistence.md)设计,本身不在本 RFC 范围内;移除它们为无消费方实现的钩子是移除钩子的一部分,而非后端重设计。 +- 所有文档和源码注释中的引用都已更新为存活的四方法、仅含 `list()` 的契约——不仅是字面的 `has(`/`delete(`/`deleteStored` 拼写,还包括 `{@link has}`/`{@link delete}` JSDoc 链接和「六个公开方法」之类的计数——涉及 seam 和后端 README、[docs/architecture.md](../../../architecture.md)、[session-persistence](../../implemented/architecture/2026-06-14-session-persistence.md) 与 [write-coordinator](../../implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md) RFC,以及协调器/后端的 JSDoc。 + +## 曾考虑的替代方案 + +### 为什么不以「seam 应当完整」为由保留? + +「持久化 seam 理应提供 delete」这种直觉是真实的——而它恰恰是预发布阶段所警惕的投机完整性([AGENTS.md](../../../../AGENTS.md):为正确的基础优化,而非为你并不拥有的假想调用方优化)。`delete()` 只是一个方法,等到消费方真正需要时再加回来即可:一个删除旧会话的会话管理 UI 会需要它——到那时再加,针对该 UI 的真实需求设计(软删除?级联?确认?),而非现在猜测。 + +在有活跃消费方时重新加入一个 seam 方法,成本低且设计更优,因为消费方锁定了契约。无人使用地携带它,意味着每个实现(以及未来的每个后端)都必须实现并测试一个什么也不做的方法。 + +## 验证 + +`has`/`delete`/`deleteStored` 已从持久化 seam、实现和契约测试套件中移除,没有新增无用导出;剩余操作(`create`/`append`/`load`/`list`)未受影响,ACP `session/list` 和崩溃恢复行为完全一致;seam README 和 `docs/architecture.md` 只列出存活的方法。 + +## 后果 + +- **`delete()` 是产品最终会需要的那类操作。** 确实如此——但「最终」正是关键。现在删除、等有真实消费方时再加回来,严格优于发布一份猜测的契约。双后端各自去掉了一个 `deleteStored` 实现,这是在本来不在范围内的包中的有限改动。 +- **低耦合。** 移除局限于持久化 seam + 实现 + 测试;没有跨包消费方引用被移除的方法,因此文档之外没有涟漪效应。 + +规模不大,但它将 seam 从「实现必须为无人提供什么」恢复为「恰好是消费方使用的东西」。 diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml new file mode 100644 index 0000000000..dd5dd8e4e1 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-public-agent-stop-surface.md: 8c371911616b0a156156355b2ca15d795cfd21e5 +2026-06-20-public-agent-stop-surface.zh.md: 31deaa3649026a7579702e8e47edfdf05d2543ae diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md index 7ed7d10211..8c37191161 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md @@ -1,5 +1,7 @@ # RFC: Keep one public stop primitive +English | [中文](2026-06-20-public-agent-stop-surface.zh.md) + Status: implemented > **Implementation note:** Only `abort()` was removed. `whenIdle()` remains because it is the public quiescence signal and safely handles waiter settlement and replacement-turn races; consumers should not reconstruct that behavior from status transitions. diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md new file mode 100644 index 0000000000..31deaa3649 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md @@ -0,0 +1,39 @@ +# RFC:保留单一公开停止原语 + +[English](2026-06-20-public-agent-stop-surface.md) | 中文 + +Status: implemented + +> **实现说明:** 仅移除了 `abort()`。`whenIdle()` 予以保留,因为它是公开的静默信号,能安全处理等待者结算与替换轮次竞态;消费方不应从状态转换中自行重建该行为。 + +## 问题 + +公开的 `Agent` 句柄暴露了两种重叠的方式来停止进行中的工作:`abort(reason?)` 与 `cancel(reason?)`。`abort()` 仅终止当前正在执行的步骤,不影响队列中的工作;`cancel()` 清除队列中的工作与 steering(中途引导),终止正在运行的步骤,并处理步骤前竞态。在生产环境中,ACP(Agent Client Protocol)使用 `cancel()` 实现 `session/cancel`,而生命周期所有者通过 `AgentHandle.dispose()` 拆除 agent。没有生产调用方需要裸 `abort()`。 + +`abort()` 与 `cancel()` 的区别是真实存在的:`abort()` 保留队列中的提示词和 steering,而 `cancel()` 丢弃它们。但没有已发布的代码调用过公开的 `abort()` 动词。agent loop(智能体循环)自身的停止路径(`cancel()` 与 dispose)直接终止当前 `AbortController`,而非经由 `Agent.abort()` 路由。大多数调用 `abort()` 的测试实际上中断的是空队列,可以改用 `cancel(reason)`;那个刻意依赖队列保留的 steering 重投递测试则直接驱动进行中的 `AbortController`,因为 `cancel()` 会丢弃它试图证明在步骤终止后仍存活的队列 steering。无参 `abort()` 的默认原因(`'aborted'`)随动词一起删除,而非意外保留;`cancel()` 保留自己的默认值 `'cancelled'`。 + +多余的公开接口面使 agent loop 不得不承载一个本质上是拆除内部机制的公开动词:`abort()` 必须被文档描述为与队列感知的取消不同,尽管 UI 取消几乎总是需要更广义的操作。 + +## 决策 + +`cancel()` 是 `Agent` 上唯一的公开*停止*原语。生命周期所有者使用 `AgentHandle.dispose()` 停止并注销 agent;非所有者使用 `cancel()` 放弃当前与队列中的工作。实现内部保留一个私有 abort controller,但它不属于面向插件的 `Agent` 契约。 + +`whenIdle()` 作为公开的静默观测原语**予以保留**(agent 脱离 `running` 状态后 resolve;已处于 idle 时立即 resolve;dispose 后等待循环退出)。它不是停止动词;它是非所有者观测停止*完成*而无需 dispose agent 的方式。它的活跃消费方是 ACP 和通过此公开 seam 等待结算的 agent 测试(`packages/ui/acp/tests`、`packages/core/agent-loop/tests`);生产环境的 ACP 桥接层拥有其 agent 并通过 `AgentHandle.dispose()` 拆除它们,因此 `packages/ui/acp/src` 本身没有 `whenIdle()` 调用。 + +公开的 `abort()` 被删除,连同将其作为独立 API 测试的用例以及将步骤级终止描述为嵌入特性的文档。空队列终止测试迁移到 `cancel(reason)`,仍然验证取消行为;测试对象为 agent loop 内部 `AbortController` 的测试通过包内类型转换直接驱动该 controller 的私有字段;仅固定已移除的无参 `abort()` 默认值的测试随方法一起删除。disposer 仍为异步,仍等待循环停止。 + +## 曾考虑的替代方案 + +**同时移除 `whenIdle()`**:最初提案的形态,在对照代码验证前提后被推翻(上方的实现说明记录了完整过程):它是承重的静默原语,强迫消费方手动观测 `running`→`idle` 转换正是防御性模式所警告的脆弱路径。 + +## 验证 + +`Agent` 不再暴露公开的 `abort()`,而 `cancel()`、`whenIdle()` 与 `steer()` 保留;ACP 取消调用 `cancel()`;拆除通过 handle disposal 等待静默,`whenIdle()` 为非所有者观测者在静默时 resolve;测试套件覆盖取消与 disposal 作为两条受支持的停止路径。 + +## 后果 + +未来的插件无法通过公开接口仅终止当前模型/工具步骤而保留队列中的提示词。如果该用例变为现实需求,它应当带着一个具名消费方和更窄的契约重新引入。目前它只是把一个私有循环机制暴露为公开接口的潜在泛化。 + +## 相关 + +本 RFC 仅移除冗余的停止动词。中途 steering 仍是有意保留的消息路径;静默观测仍通过 `whenIdle()` 提供。最终的公开接口面为 `send()`、`steer()`、`inject()`、`cancel()`、`whenIdle()`、status、options、session 与 identity。 diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml new file mode 100644 index 0000000000..4f09cbbc3b --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-remove-agent-boundary-mirror-events.md: 46b5e43951885915d4c3dd3f867ced6c31d32035 +2026-06-20-remove-agent-boundary-mirror-events.zh.md: dd6952ec8923c17d703fc6850197bef09b1c0ee7 diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md index e2a1165846..46b5e43951 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md @@ -1,5 +1,7 @@ # RFC: Stop mirroring durable boundaries as agent events +English | [中文](2026-06-20-remove-agent-boundary-mirror-events.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md new file mode 100644 index 0000000000..dd6952ec89 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md @@ -0,0 +1,32 @@ +# RFC:停止将持久化边界镜像为 agent 事件 + +Status: implemented + +[English](2026-06-20-remove-agent-boundary-mirror-events.md) | 中文 + +## 问题 + +agent loop(智能体循环)曾通过可回放的 `SessionEvent` 日志和实时 `agent/*` 镜像两条路径暴露持久化的轮次与步骤边界。消费方不得不在两个表达同一事实的来源之间做选择,并协调二者的时序。ACP(Agent Client Protocol)和持久化层已经使用事件日志;stdio UI 是唯一仍在消费镜像事件的组件,而它也已经从 `session/event` 渲染工具调用和工具结果。 + +这种重复并非零成本。每次生命周期变更都要同时更新会话事件、镜像事件、文档、不变式、测试和快照预期。重复的边界事件还使失败排序变得微妙:一个轮次可能在实时 `agent/turn-end` 监听器运行之前就已被持久化关闭,因此边界之后的监听器失败在日志中已没有合法的位置可插入,只能带外报告。 + +## 决策 + +让 `session/event` 成为唯一的实时边界/transcript(文本记录)流。需要渲染轮次、工具调用、工具结果、助手消息和持久化边界的消费方统一订阅 `session/event`,从持久化层使用的同一套事件词汇派生 UI。 + +移除 `agent/turn-start`、`agent/turn-end`、`agent/step-start` 和 `agent/step-end`。边界消费方改为订阅 `session/event`。需要 agent 标签的 UI 通过 `agent/created` 和 `agent/disposed` 维护一份 session 到 agent 的映射,因为持久化的 `turn/start` 携带轮次编号但不携带 agent id。 + +步骤镜像没有消费方,已由 [event-domain-semantics RFC](../architecture/2026-06-30-event-domain-semantics.md) 率先移除。该决策保留了轮次镜像供 stdio UI 使用;本 RFC 在将测试 REPL 迁移到 `session/event` 加 id 映射之后,将轮次镜像也一并移除。 + +## 范围:移除什么、不移除什么 + +本决策仅涉及持久化的轮次与步骤边界。`agent/steering` 镜像的是一条控制记录,`agent/stream-chunk` 镜像的是 token 流,因此各自单独处理:见 [steering](2026-07-04-remove-agent-steering-mirror.md) 和 [stream chunks](2026-07-02-remove-stream-chunk-mirror.md)。`agent/created`、`agent/disposed`、`agent/status`、`agent/error` 和 `agent/queued` 仍作为实时生命周期或控制事件保留,而非 transcript 镜像;排队的输入可能在任何持久化事件产生之前就被取消。 + +## 曾考虑的替代方案 + +- **在同一个变更中移除 `agent/steering`**:否决,因为它镜像的是控制记录而非边界。 +- **为 stdio UI 保留轮次镜像**:否决,因为 UI 可以渲染 `session/event` 并从 id 映射中恢复 agent 标签。 + +## 后果 + +插件不再能从便捷的 `Agent` 优先事件中观察轮次/步骤边界。它必须订阅 `session/event` 或自行维护 session 到 agent 的关联。这是可接受的取舍:边界消费方不应依赖一条可能与持久化日志产生漂移的第二事件源。 diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml new file mode 100644 index 0000000000..f096620016 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-26-fsspec-style-fs-seam.md: 493af9341177aaaed4cdca03a3c20f326c5c4dac +2026-06-26-fsspec-style-fs-seam.zh.md: ba6a366990f749c5fb84e30142965dc5a2d1d0b7 diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md index 2663637859..493af93411 100644 --- a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md @@ -1,5 +1,7 @@ # RFC: Split the filesystem seam — provider text mutations plus the `dsh-fs-policy` plugin +English | [中文](2026-06-26-fsspec-style-fs-seam.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md new file mode 100644 index 0000000000..ba6a366990 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md @@ -0,0 +1,130 @@ +# RFC:拆分文件系统 seam——提供方文本变更与 `dsh-fs-policy` 插件 + +Status: implemented + +[English](2026-06-26-fsspec-style-fs-seam.md) | 中文 + +## 问题 + +[filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) 引入的文件系统能力目前让一个抽象 `FileSystem` 服务同时承担两类职责: + +1. **提供方操作**——解析目标、stat/版本元数据、文本读取/流式读取、原子写入,以及带守卫的字面编辑。 +2. **面向 agent 的策略**——行窗口、字面编辑语义,以及读后写/编辑的 observed-state。 + +这导致每个未来的后端都要重新实现面向模型的读取语义和观测策略。`readPage` 返回带行号的行和视图元数据;基类服务按 owner 存储文件状态,并区分 `full` 与 `partial` 读取。这些是有用的策略,但它们不是文件系统提供方的原语。字面文本变更则不同:版本守卫、字面匹配、歧义检测与原子重写必须在提供方变更边界内保持一体,但当前的 `applyEdit` 命名及其周围的 seam 把这个提供方操作绑定到了旧的读后编辑策略形状上。 + +这还造成了一个真实的 UX 死胡同:窗口化读取记录 `view: partial`,而 partial 视图无法授权 `edit`。一个模型读取了大文件的第 100-150 行,除非先获得一次 `full` 读取,否则无法编辑第 120 行——而对于超过读取上限的文件,full 读取可能不可行。字面编辑真正需要的只是新鲜度:被匹配的字节必须仍来自模型所读的那个版本。 + +旧 RFC 已经推迟了独立的 `@deepseek-ai/dsh-fs-policy` 包。本 RFC 构建该层,并让 `ctx.fs` 贴近 fsspec 风格的存储原语(`info`/`cat`/`open`),但不将其变成完整的 fsspec。 + +## 决策 + +将栈拆为四层: + +```text +tool dsh-tool-fs model-facing schemas + read windowing + text rendering; the EXECUTOR (reads/writes/edits via ctx.fs, dispatches the fs/* events) +policy dsh-fs-policy observed-state + read-before-edit + write/edit freshness, contributed through the fs/* event gate (no service) +provider seam dsh-fs ctx.fs: text IO + atomic mutation primitives (optional version guard) +provider dsh-fs-local local implementation of ctx.fs +``` + +`dsh-tool-fs` 保持相同的面向模型的 `read`/`write`/`edit` schema。它是执行器:注入 `fs`(不是策略服务)并直接访问 `ctx.fs`,拥有读取窗口化逻辑,并派发 `fs/*` 事件以便 `dsh-fs-policy` 进行门控和记录。 + +本 RFC 决定了四层拆分、提供方契约和新鲜度策略。工具↔策略的**耦合方式**随后由[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 细化:`dsh-fs-policy` 是一个门控**插件**,通过 `fs/*` 事件参与而非提供 `ctx.fileContext` 方法服务,因此工具不与它产生方法耦合,读取窗口化与 fs I/O 留在 `dsh-tool-fs` 中。本文描述的是最终落地的事件门控形态;提供方的版本守卫是可选的(省略 = 无条件裸提供方)。 + +## 提供方契约 + +`@deepseek-ai/dsh-fs` 收缩为提供方文本 IO 加带守卫的文本变更: + +```ts ignore-check +abstract resolve(path: string): Promise<FsTarget> +abstract stat(target: FsTarget, signal?: AbortSignal): Promise<FsInfo | undefined> +abstract readText(target: FsTarget, signal?: AbortSignal): Promise<string> +abstract streamText(target: FsTarget, signal?: AbortSignal): Promise<AsyncIterable<string>> +abstract writeText(target: FsTarget, content: string, expected: FsWriteIntent, signal?: AbortSignal): Promise<FsWriteOutcome> +abstract editText(target: FsTarget, edit: FsEditRequest, expected: { version: FsVersion }, signal?: AbortSignal): Promise<FsEditOutcome> + +interface FsInfo { + version: FsVersion + type: 'file' | 'directory' | 'other' + size?: number +} + +type FsWriteIntent = + | { kind: 'createIfAbsent' } + | { kind: 'replaceIfVersion'; version: FsVersion } +``` + +`stat` 返回元数据而非内容。`version` 是新鲜度令牌;`type` 让执行器在读取前拒绝目录/特殊文件;`size` 让 `read` 工具无需通过失败来探测即可选择 `readText` 还是 `streamText`。返回 `undefined` 表示目标不存在。 + +`readText` 读取整个常规文本文件。`streamText` 以相同的文本语义流式读取大文件。两个提供方原语负责常规文件检查、UTF-8 解码、二进制/NUL 拒绝以及 `FS_NOT_TEXT`;策略层从不处理原始字节,也不重新实现跨分片解码。`readText` 是小文件/直接全文件原语,而面向模型的大文件读取使用 `streamText`。 + +`writeText` 是原子性的临时文件 + rename,带有显式的写入意图。`createIfAbsent` 创建不存在的目标,对已存在的目标以 `FS_NOT_OBSERVED` 拒绝;这是 owner 没有先前读取时使用的路径。`replaceIfVersion` 仅在目标以观测到的版本存在时替换;目标不存在或版本不匹配时抛出 `FS_STALE_VERSION`。 + +`editText` 是提供方级别的带守卫文本变更。启用守卫时,它先验证目标仍以 `expected.version` 存在,然后读取当前文本、应用字面替换并原子写入。陈旧检查必须在字面匹配之前发生,这样基于旧读取的编辑会报告 `FS_STALE_VERSION`,而不是对更新内容做匹配后报告 `FS_EDIT_NOT_FOUND` 或 `FS_AMBIGUOUS_EDIT`。将此原语保留在提供方 seam 上,保持了后端本地锁定能力,也让未来的远程后端可以实现原生的 compare-and-edit 而无需策略层拉取整个文件。 + +这是一个*文本存储* seam,刻意比字节级 fsspec(`cat`/`open` 返回原始字节)高半层。UTF-8 解码、二进制/NUL 拒绝、带守卫的全文件写入和带守卫的字面文本编辑都在提供方内完成,使策略层从不接触原始字节、不重新实现跨分片解码、也不将陈旧检查与变更临界区分离。面向模型的概念仍然不下沉到提供方:行窗口、带行号的行、渲染的页脚、observed-state 存储都不会泄漏下去。 + +从 `dsh-fs` 中删除:`readPage`、`FsExpectation`、`FsView`、`FsStateSource`、`FsReadRequest`、`FsTextLine`、行/窗口常量、`formatReadBody`,以及 observed-state `WeakMap`。`applyEdit` 被更窄的提供方原语 `editText` 取代,后者的契约是版本守卫的字面文本变更,而非策略层的读取授权。`FS_PARTIAL_OBSERVATION` 错误码也从 `FsErrorCode` 分类体系中移除:新鲜度授权没有 partial/full 之分,因此没有任何场景会抛出它。`FsTargetKey` 和 `FsVersion` 按照既有的 [branded-ids RFC](../../implemented/architecture/2026-06-20-branded-ids.md) 成为品牌化的不透明 id。 + +## 策略契约 + +`@deepseek-ai/dsh-fs-policy` 是一个插件而非服务:它不注册任何 `ctx.*` 键,也不注入任何东西。它拥有写入/编辑新鲜度策略和 observed-state——这些不属于 `FileSystem` 提供方基类(否则沙箱化/远程后端会继承它无需承担的面向模型的观测策略)。它通过执行器派发的 `fs/*` 事件门控来贡献这些策略。(本 RFC 最初提出了一个具体的 `ctx.fileContext` 方法服务,带 `read`/`write`/`edit` 方法;[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 将其细化为此处描述的门控插件,使工具从不与策略产生方法耦合。) + +Observed state 以 `WeakMap<owner, Map<targetKey, FsVersion>>` 形式存在于此。当且仅当 owner 读取、写入或编辑过该目标时条目才存在(每次成功都会发出 `fs/observed`),因此条目的存在*本身就是*先前观测记录——没有单独的 `hasRead` 标志。owner 从不透明的事件 actor(`{ agent?: { session? } }`)结构化派生,该形状定义在 `dsh-fs-policy` 中而非 `dsh-fs` 中。 + +该插件决定三个 `fs/*` 事件: + +- `fs/write-intent`——无先前观测 ⇒ `{ kind: 'createIfAbsent' }`(只有新文件可以盲创建);有先前观测 ⇒ `{ kind: 'replaceIfVersion', version: vObserved }`(已有文件仅在自观测以来未变时才替换)。单槽决策;不调用 `next()`。 +- `fs/edit-intent`——要求 owner 有先前观测(否则 `FS_NOT_OBSERVED`);返回 `{ version: vObserved }` 作为 CAS 基础。它不实现字面替换——它授权并提供版本,提供方的变更临界区负责应用守卫,因此基于同一观测版本的并发编辑仍然是一个赢/一个陈旧。 +- `fs/observed`——在成功的读取/写入/编辑后为该 owner+target 记录 `{ version }`。同步、仅副作用的 `WeakMap.set`。 + +该插件不做任何文件系统 I/O:「你是否观测过这个文件?」是一次 `WeakMap` 查找,而「你读到的版本是否仍然是当前版本?」在 `ctx.fs.editText`/`writeText` 内部的同一原子锁中决定(该锁同时执行变更)——插件只提供 `vObserved` 作为基础。 + +## 工具契约 + +`dsh-tool-fs` 保持相同的 schema 和提示词表面。`read` 仍暴露 `file_path`、`offset` 和 `limit`;`write` 和 `edit` 不变。它是执行器:验证模型参数,通过 `ctx.fs` 直接读取/写入/编辑,拥有行窗口化和结果渲染(`N: text`、页脚、`<path>/<content>` 信封),并派发 `fs/*` 事件。 + +每次变更先派发其 intent waterfall(瀑布式事件)并以 `undefined` 作为裸提供方默认值,然后调用 `ctx.fs`,再发出 `fs/observed`:例如 `write` 执行 `ctx.waterfall('fs/write-intent', target, exec, () => undefined)` → `ctx.fs.writeText(target, content, intent)` → `ctx.emit('fs/observed', …)`。`read` 做一次 stat、读取/流式读取、构建窗口,然后发出 `fs/observed`。将 `exec` 作为 actor 传入,让 `dsh-fs-policy` 无需工具深入策略即可派生 owner。 + +由于策略通过带 `undefined` 默认值的事件贡献,`dsh-tool-fs` 不与 `dsh-fs-policy` 产生方法耦合:插件不存在时,每个 intent waterfall 落入 `undefined`(无条件裸提供方写入/编辑),`fs/observed` 无监听者。加载插件后即叠加读后写/编辑策略。 + +## 并发边界 + +进程内更新是安全的:本地后端保持既有的按目标变更锁,因此版本检查-然后-rename 是串行化的,失败的更新看到 `FS_STALE_VERSION`。 + +进程内创建由同一按目标变更锁守卫:两个调用者以 `createIfAbsent` 竞争时串行化,一个创建成功,下一个看到目标已存在并收到 `FS_NOT_OBSERVED`。跨进程创建仅尽力而为;本地的 stat-then-rename 守卫无法在所有未来后端上提供可移植的排他创建保证。 + +跨进程写入是尽力新鲜度加原子替换:`mtime:size` 通常能捕获编辑器保存,但同一时刻相同大小的写入可能遗漏;原子性的 temp+rename 防止文件撕裂但不能防止所有丢失更新。 + +## 取代 + +本 RFC 逆转了 [filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) 的两项决策,并收窄了第三项: + +- 读后写/编辑策略从 `ctx.fs` 移出,进入 `dsh-fs-policy` 插件(在 `fs/*` 事件门控上)。 +- 文本读取不再返回后端编号的行记录或 `full`/`partial` 视图;授权基于版本新鲜度,因此窗口化读取在文件未变时即可授权编辑。 +- 字面编辑不再位于旧的 `applyEdit` API 之后(该 API 混合了后端变更与 seam 拥有的观测策略)。它作为 `editText` 保留为提供方原语,因为版本守卫 + 字面匹配 + 原子重写必须在提供方的变更临界区内保持一体,以确保正确的错误归因和并发行为。 + +保留的内容:接口/实现/消费方纪律、消费方不导入后端规则、后端定义的 target/version/display 元数据、原子本地写入,以及共享的 `FsError` 分类体系。 + +## 验证 + +`dsh-fs` 精确暴露 `resolve`/`stat`/`readText`/`streamText`/`writeText`/`editText`(`stat` 返回 `FsInfo | undefined`,`writeText` 接受 `FsWriteIntent`),已删除的类型/原语不再存在;`dsh-fs-local` 不携带行、视图或 `formatReadBody` 逻辑;面向模型的 schema 逐字节未变。测试固定了以下行为:窗口化读取可以授权对未变文件的后续编辑;基于陈旧读取的编辑在尝试字面匹配之前报告 `FS_STALE_VERSION`;版本 CAS 行为得到保持;观测契约成立(通过 `read` 工具的读取记录 observed-state;直接的 `ctx.fs` 读取不记录);`dsh-fs-policy` 具有 HMR/dispose 覆盖率。 + +## 后续扩展 + +该 seam 后来由 [Add direct directory listing to the filesystem seam](../architecture/2026-07-03-filesystem-directory-listing-seam.md) 扩展了直接目录列表功能。该后续工作单独跟踪,以使本 RFC 的验收标准继续描述最初交付的 fsspec 风格改造。 + +## 曾考虑的替代方案 + +- **字节级 fsspec(`cat`/`open` 返回原始字节)**——否决:该 seam 刻意定位为文本存储,比字节级高半层,使 UTF-8 解码、二进制/NUL 拒绝和带守卫的文本变更在提供方内只实现一次,策略层从不接触原始字节,也不将陈旧检查与变更临界区分离。 +- **具体的 `ctx.fileContext` 方法服务**——本 RFC 最初的策略形态;由[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 改造为门控插件,使工具从不与策略产生方法耦合。 +- **将 `readPage` 和 `full`/`partial` 视图授权保留在提供方上**——改造前的形态,即「取代」一节所逆转的内容:视图完整性不是编辑安全所需的信号,版本新鲜度才是;视图规则使超过读取上限的大文件无法编辑。 + +## 后果 + +- 新增第四个 fs 包和一个新的插件层。这是有意为之:它是此前推迟的策略层,而非第二个抽象后端 seam。 +- 直接使用 `ctx.fs` 会绕过策略:直接的 `ctx.fs.readText` 不发出 `fs/observed`,因此在默认策略下,后续的 `edit` 会以 `FS_NOT_OBSERVED` 拒绝,直到通过 `read` 工具读取该文件。该失败是显式且有文档记录的。 +- 大文件行窗口化从后端移至 `dsh-tool-fs` 中的 `read` 工具;文本解码和二进制拒绝留在 `ctx.fs.streamText` 中,因此这只是窗口化逻辑的迁移,不是第二套文本 IO 实现。 +- 将 `editText` 保留在提供方 seam 上意味着每个后端都必须实现字面替换契约。这是有意为之:该操作不是纯存储,但陈旧守卫 + 字面匹配 + 原子重写是必须保持一体的单元,以确保正确的错误归因和并发行为。该契约应保持窄且仅限文本,以便未来后端可以原生实现或通过全文件重写实现。 +- 新鲜度允许在窗口化读取后执行全文件 `write`。这比旧的视图检查更弱,但避免了大文件无法编辑的问题;提示词引导仍然不鼓励盲目的全文件替换。 diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml new file mode 100644 index 0000000000..ca87af6f9a --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-02-remove-stream-chunk-mirror.md: 1ec633b09c8e53ae7145a49061aced191a9aa765 +2026-07-02-remove-stream-chunk-mirror.zh.md: 83674658d24621b12a866262bb58dde166bedf2d diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md index a272dfe0b2..1ec633b09c 100644 --- a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md @@ -1,5 +1,7 @@ # RFC: Stop mirroring the token stream as an agent event +English | [中文](2026-07-02-remove-stream-chunk-mirror.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md new file mode 100644 index 0000000000..83674658d2 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md @@ -0,0 +1,47 @@ +# RFC:停止将 token 流镜像为 agent 事件 + +Status: implemented + +[English](2026-07-02-remove-stream-chunk-mirror.md) | 中文 + +## 问题 + +agent loop(智能体循环)将模型的每个 token 增量同时记录为持久的 `assistant/chunk` 会话事件,并发射一个携带相同数据的并行实时 `agent/stream-chunk` Cordis 事件。在 `packages/core/agent-loop/src/loop.ts` 中,两者仅相隔一行: + +```ts ignore-check +const chunkEvent = session.append('assistant/chunk', { turn, step, chunk }) +chunkSeqs.push(chunkEvent.seq) +ctx.emit('agent/stream-chunk', agent, turn, step, chunk) // ← the mirror +``` + +- 持久事件:`assistant/chunk: { turn, step, chunk }`。 +- 实时发射:`agent/stream-chunk(agent, turn, step, chunk)`——相同的 `StreamChunk`,相同的 `turn`/`step`。 + +实时发射相比会话事件唯一多出的东西是实时的 `Agent` 句柄,而唯一的消费方丢弃了它(其处理函数签名为 `(_agent, _turn, _step, chunk)`)。 + +这与[边界镜像移除](2026-06-20-remove-agent-boundary-mirror-events.md)为轮次/步骤边界消除的重复如出一辙:消费方对同一个持久事实有两个真源,每次修改都必须同时触及两处。那份 RFC 将分片流推迟处理(「`assistant/chunk` 的持久化仍然是承重的,因此分片流后续可以作为镜像来评估,但那是一个独立的决策」),而非一并打包。本 RFC 就是那个独立的决策。 + +推迟所依赖的前提已经尘埃落定:分片持久化是权威的,且将保留。停止持久化分片、仅保留瞬态实时流事件的提案已被[否决](../../rejected/simplification/2026-06-20-assembled-assistant-messages-only.md)——高保真回放、部分失败的流以及快照回放都依赖持久化的 `assistant/chunk` 流。因此 `session/event` 上的 `assistant/chunk` 是持久的、承重的 token 流,而 `agent/stream-chunk` 是它的纯冗余镜像。 + +## 决策 + +从 agent 事件分类体系中移除 `agent/stream-chunk`。token 流通过 `session/event` 以 `assistant/chunk` 的形式读取——持久化和回放已经使用的正是同一条流。`session/event` 是唯一的实时 transcript(文本记录)流(assistant 分片、轮次/步骤边界、工具活动、todo)。 + +**消费方。** 唯一重要的生产消费方——ACP 桥接层(`dsh-acp`,真正面向编辑器的流式输出接口)——已经从 `session/event` 渲染 `assistant/chunk`,从未使用 `agent/stream-chunk`,因此不受影响。stdio UI(`dsh-ui-stdio`,一个一次性的测试 REPL)是唯一的实时消费方;它在边界迁移时已经有了 `session/event` 监听器,因此其分片渲染被折叠进该监听器的 `assistant/chunk` 分支。合并为一个监听器还消除了一个潜在隐患:`inReasoning` dim-SGR 标志此前在两个独立的监听器(`agent/stream-chunk` 和 `session/event`)之间共享,分片与边界在该标志上竞争时没有确定的顺序;单一监听器按追加顺序处理,使交错变为确定性的。 + +## 范围 + +移除:`agent/stream-chunk`。 + +未触及: +- `assistant/chunk`(持久会话事件)——权威的 token 流,原样保留。本 RFC 移除的是实时镜像,而非持久化(持久化移除提案已被单独否决,见上文)。 +- `agent/steering`——本决策未触及(它是控制信号,不是 token 流)。其持久孪生事件是 `steering/message`,镜像发射由其自己的后续 RFC 移除:[移除 `agent/steering` 镜像发射](2026-07-04-remove-agent-steering-mirror.md)。 +- `agent/status`、`agent/error`、`agent/created`/`agent/disposed`、`agent/queued`、`agent/session-start`——生命周期/控制事件,不是 transcript 数据,也没有持久副本。 + +## 曾考虑的替代方案 + +**移除持久化、仅保留瞬态实时流**——反向裁剪,已被[单独否决](../../rejected/simplification/2026-06-20-assembled-assistant-messages-only.md):高保真回放、部分失败的流以及快照回放都依赖持久化的 `assistant/chunk` 流。这一点既已确定,实时发射就是配对中冗余的那一半。 + +## 后果 + +插件不再能从以 `Agent` 为首参的事件观察 token 增量。它应订阅 `session/event` 并过滤 `assistant/chunk`(如需 `Agent` 句柄,可从 `agent/created`/`agent/disposed` 构建的 session-id→agent 映射中恢复,与边界消费方的做法完全一致)。没有任何生产消费方在分片时需要实时的 `Agent`;这与边界镜像移除所做的权衡完全相同,是可接受的。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml new file mode 100644 index 0000000000..776f41a858 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-drop-image-content-block.md: 8222880b61c225c39a1e132353c5f343fb90cb4b +2026-07-04-drop-image-content-block.zh.md: d1379d69a0c5056cdfcc744182cd9b6c52f222d5 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md index 73645e8fda..8222880b61 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md @@ -1,5 +1,7 @@ # RFC: Drop the `image` content block until a path can honor it +English | [中文](2026-07-04-drop-image-content-block.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md new file mode 100644 index 0000000000..d1379d69a0 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md @@ -0,0 +1,29 @@ +# RFC:移除 `image` 内容块,直到有路径能真正处理它 + +Status: implemented + +[English](2026-07-04-drop-image-content-block.md) | 中文 + +## 问题 + +`ImageBlock`(`packages/llm/llm/src/types.ts`)没有任何生产环境的生产者,而每条路径上的每个消费方都将其**丢弃**:DeepSeek 适配器的序列化器跳过 image 块(这是文档中注明的 MVP 限制);pi-ai 转换器因无法表示而跳过;ACP 编解码器既不声明 image prompt 能力、也不向外转发 image 块,并且对入站的 image prompt 内容直接**拒绝**;压缩(compaction)估算器对其收取一个固定 token 常量并渲染为 `[image]`。此时构造的 `ImageBlock` 会在协议格式(wire format)上静默消失——词汇表声明了一种没有任何路径兑现的能力,这正是 `AGENTS.md` 防御性模式所警告的静默数据丢失形态。唯一的构造点是用于固定 skip/drop/estimate 分支的测试。 + +## 决策 + +移除 `ImageBlock`、其 map 条目,以及适配器、ACP 渲染和压缩中的 image 专用分支。在同一个变更中更新所属词汇文档与生成的引用。未知的扩展块仍然覆盖 default 分支,ACP 继续独立于 harness 词汇拒绝入站 image prompt 内容。 + +## 曾考虑的替代方案 + +### 为什么不保留? + +当适配器、ACP 与压缩全部支持 image 时,`ContentBlockMap` 可以重新引入它。保留一个唯一实现是拒绝的核心类型,等于向外声明一个不可用的接口;移除则让生产者在编译期立即失败。 + +记录在案的回退方案(假设评审决定保留该槽位):保留 `ImageBlock`,但将每处静默跳过替换为显式拒绝,并在词汇文档中记录该策略——静默丢弃是唯一没有辩护者的状态。评审最终决定移除;此回退方案作为文档化的替代方案保留,以备该槽位在完整功能之前回归。 + +## 验证 + +RFC 记录之外没有任何地方构造 harness `ImageBlock`。ACP 独立的入站 image 拒绝仍有测试覆盖,而适配器、编解码器与压缩的 default 分支则通过插件定义的块类型覆盖。 + +## 后果 + +日后重新添加核心词汇类型会同时涉及多个包——但这种协调变更正是真正的多模态功能所需的形态(适配器映射、ACP 能力声明、压缩定价),而当前并没有什么需要保留的实现。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml new file mode 100644 index 0000000000..028162c527 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-drop-inert-request-knobs.md: d5484aa5ec64f89ce705ddd0a434c2c4dfbad460 +2026-07-04-drop-inert-request-knobs.zh.md: 877b073c4693f0c87b5f25003a1d043743b658fa diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md index 95a5a487b5..d5484aa5ec 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md @@ -1,5 +1,7 @@ # RFC: Drop `GenerateOptions.prefill` and `ToolSchema.strict` — request knobs with no working end-to-end path +English | [中文](2026-07-04-drop-inert-request-knobs.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md new file mode 100644 index 0000000000..877b073c46 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md @@ -0,0 +1,35 @@ +# RFC:移除 `GenerateOptions.prefill` 与 `ToolSchema.strict`——无可用端到端路径的请求旋钮 + +[English](2026-07-04-drop-inert-request-knobs.md) | 中文 + +Status: implemented + +## 问题 + +两个请求契约旋钮贯穿了整条请求流水线,但都无法产生任何效果: + +- **`prefill`**(`packages/llm/llm/src/types.ts`)没有生产环境的赋值方:agent loop(智能体循环)组装的只有 `model`/`system`/`tools`/`messages` 加 `sessionId`/`signal`,上下文压缩(context compaction)后端只追加 `maxTokens`;而且**两个**适配器都拒绝它:`packages/llm/llm-deepseek/src/serialize.ts` 和 `packages/llm/llm-pi-ai/src/adapter.ts` 各自在 `prefill` 非 undefined 时抛出 `LlmError('UNSUPPORTED')`。该字段全部可观测行为就是两个 throw,各由一个适配器测试固定。DeepSeek 的 chat-prefix completion 是一个 Beta 功能,使用的 base URL 两个适配器都未指向。 +- **`strict`**(`ToolSchema`,同一文件)贯穿了 `DefineToolOptions`/`defineTool`(`packages/core/tools/src/schema.ts`)、注册表的 `schemas()` 白名单(`packages/core/tools/src/index.ts`)、deepseek 协议格式(wire format)映射(`packages/llm/llm-deepseek/src/serialize.ts`,其 wire-type 注释记录了 strict 模式需要适配器未使用的 `/beta` base URL)、`packages/llm/llm-pi-ai/src/adapter.ts` 中的逐工具 payload 修补,以及 tool-catalog 渲染器(`scripts/gen-tool-catalog.ts`)中的条件 `Strict:` 行。没有任何已发布的工具设置过它:在所有 `tool-*` 包 src 和 `examples/` 中 `rg` 搜索,`strict:` 的生产方为零;唯一的赋值方是 dsh-tools 单元测试。 + +两个旋钮在适配器间是对称的,因此移除时两个孪生适配器一并清理——[孪生适配器设计](../architecture/2026-06-13-twin-llm-adapters.md)不受影响。 + +## 决策 + +- 从 `GenerateOptions` 中移除 `prefill`,同时移除两个适配器的 UNSUPPORTED 守卫、固定这些 throw 的测试、[core.md](../../../core-data-structures/core.md) 中的粘贴行,以及适配器 README 中记录拒绝行为的行。实操手册(Cookbook)中的 UNSUPPORTED 指导([adding-an-llm-adapter.md](../../../cookbook/adding-an-llm-adapter.md))改为泛化表述——你的提供方无法兑现的 `GenerateOptions` 字段应抛出 `LlmError(..., 'UNSUPPORTED')`——而不再以 prefill 为例。[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的后果部分将 prefill 记录为「受生产方门控」而非「已有归属」,遵照 [implemented/AGENTS.md](../AGENTS.md)。 +- 从 `ToolSchema`、`DefineToolOptions`、`defineTool`、`schemas()` 白名单、deepseek 序列化器分支及其 wire-type 字段、以及 tool-catalog 渲染器的 `Strict:` 行中移除 `strict`。pi-ai 的 payload 修补简化为无条件擦除 pi-ai 自身的逐工具 strict 默认值(pi-ai 在每个序列化工具上打 `strict: false`;手写的孪生适配器不发送此字段,因此擦除逻辑为保持协议格式对等而保留,由其序列化器测试固定)。赋值测试和 core.md 粘贴行已移除;`GenerateOptions` 与 `ToolSchema` 在 `scripts/type-equiv.manifest.json` 中保留各自的行,因为两个类型本身仍然存在,只是少了一个字段。 + +本 RFC 有意**不**触及 `temperature`、`stop` 或 `maxTokens`:这些字段被两个适配器端到端地兑现,是 `agent/request` 上请求变更钩子插件的自然首选目标。 + +## 曾考虑的替代方案 + +### 为什么不保留? + +「显式的 UNSUPPORTED throw 是诚实的契约行为」——但一个旋钮在两个孪生适配器中的唯一实现都是拒绝,它什么也不承诺;删除它反而升级了失败模式:意外的赋值从运行时 throw 变为编译错误。「strict schema 遵循是官方文档记录的提供方功能,且管道完整」——但一个旋钮在有已发布工具设置它**且**有端点兑现它之前,都不是产品表面;今天两者都不成立。二者各自随其第一个真实生产方回归:`prefill` 随实现了 chat-prefix completion 的适配器(以及对不支持它的适配器的明确策略)一起回来,`strict` 随需要它的工具和 beta 端点方案一起回来。 + +## 验证 + +`rg prefill` 仅返回 RFC 记录(本文与[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的 producer-gated 后果);在 tool-schema 范围内 `rg strict` 仅返回本 RFC、保留的 pi-ai 擦除逻辑,以及无关行文(如 `strictEqual`)。两个适配器的契约测试在移除守卫后通过,pi-ai 修补仍然擦除库的 strict 默认值——协议格式对等由其序列化器测试固定。 + +## 后果 + +已发布的钩子桥接不设置任何请求字段,而请求变更插件(`agent/request` waterfall(瀑布式事件)监听器)使用的是 `temperature`/`stop`(保留且可用),而非适配器拒绝的字段。如果 chat-prefix completion 或 strict 模式成为产品功能,重新添加将随适配器/端点工作一起落地,届时契约能说明实际发生了什么,而非「所有人都 throw」。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml new file mode 100644 index 0000000000..429f89095a --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-drop-unconsumed-web-observation-surface.md: c48ff5b80c916cd6cc04d6a8339a8555d05b0d40 +2026-07-04-drop-unconsumed-web-observation-surface.zh.md: ce8a108450ed9e9308066ab45b8f000dc20fde39 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md index 35868be2fd..c48ff5b80c 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md @@ -1,5 +1,7 @@ # RFC: Drop the unconsumed web observation surface — the `providers-change` event and the status methods +English | [中文](2026-07-04-drop-unconsumed-web-observation-surface.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md new file mode 100644 index 0000000000..ce8a108450 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md @@ -0,0 +1,34 @@ +# RFC:移除未被消费的 web 观测面——`providers-change` 事件与 status 方法 + +Status: implemented + +[English](2026-07-04-drop-unconsumed-web-observation-surface.md) | 中文 + +## 问题 + +`WebService` 暴露了一组没有任何生产代码观测的观测面: + +- **`web/providers-change`**(`packages/web/web/src/index.ts`)在每次 provider 注册和 dispose(资源释放)时声明并发射。每个注册 effect 的回滚 yield 被刻意排在 emit 之前,唯一目的是让一个抛异常的 change listener 能回退注册。该事件在包自身的两个单元测试之外没有任何 listener(其中一个测试的存在就是为了固定那个回滚顺序)。 +- **`searchStatus()` / `fetchStatus()` 与 `WebCapabilityStatus` 联合类型**(同一个包)没有任何生产调用方:`dsh-tool-web` 直接通过 `ctx.web.search()`/`fetch()` 执行,并将不可用状态以 seam 在执行时抛出的结构化 `WebError` 错误码呈现(`packages/web/tool-web/src/search.ts`、`packages/web/tool-web/src/fetch.ts`);唯一的 status 调用方是 web 包自身的测试。`packages/web/tool-web/README.md` 与 [architecture.md](../../../architecture.md) 中的行文声称工具「只读取聚合的 `searchStatus()`/`fetchStatus()`」——这种漂移之所以存活,仅仅因为没有什么机制会拿行文与调用点做比对。 + +seam 自身的设计使两个观测面都失去了消费方:工具注册跟随产品 ENABLEMENT 而非 provider 可用性(`packages/web/tool-web/src/index.ts`),provider 选择在执行时解析、从不缓存——因此没有需要失效的缓存、没有需要重算的注册集合,也没有调用方需要一个独立于「执行并路由结构化错误」的可用性探针。HMR(热模块替换)清理由 effect disposer 自身承载。 + +这与[移除未被消费的 `llm/adapter-change` 事件](../../implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md)如出一辙:那次从 `LlmService` 移除了相同的通知形态、相同的回滚先于 emit 机制,以及相同的 listener-throw 测试。该 RFC 的保留/裁剪判据——保留 `tools/change`(因为它有合理的面向用户的工具列表消费方),裁剪启动期后端注册表信号——把 web provider 注册表信号明确归入裁剪一侧;status 方法则是同一判断应用于拉取面而非推送面。 + +## 决策 + +移除注册表变更事件、聚合 status 方法与类型,以及它们的专属测试。provider 私有的 status 保留用于执行时选择。面向调用方的覆盖率现在断言成功执行或结构化的选择错误,web 相关文档描述该按需调用契约。 + +## 曾考虑的替代方案 + +### 为什么不保留? + +web seam RFC 当初有意指定了两者——事件作为最小的 HMR 可见性信号,status 方法作为工具的聚合诊断——且未来的 provider 状态面板是可以想象的。但同一 RFC 的其他选择使它们失去了消费方:按需派生的选择与基于 enablement 的注册使得没有消费方**能**需要它们;已交付的工具展示了真实模式(执行并路由结构化错误);漂移的 README 语句表明承诺的消费方从未实现。按照 AGENTS.md 的原则「RFC 是提案,不是金科玉律」,这些正是该提案中被代码证明过度延伸的部分;未来的观测者重新引入它实际消费的最小信号或查询,由该消费方塑造其形态。 + +## 验证 + +`providers-change`、`searchStatus`、`fetchStatus` 和 `WebCapabilityStatus` 在 RFC 历史之外不再有任何拼写残留;catalog 是最新的(`verify-cordis-catalog` 绿色);注册/释放的 HMR 安全测试通过执行行为证明清理正确;tool-web README 与架构段落描述了工具实际拥有的执行时错误路由契约。 + +## 后果 + +未来如果有 provider 选择器 UI 或诊断面板需要变更通知或 status 查询,它会重新添加自己实际消费的最小观测面;相同的判断及其反转条件已记录在 LLM 先例中。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml new file mode 100644 index 0000000000..dfa01c3e89 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-fold-stdio-ui-helper.md: 8d26af190a957b424960519f77cbe132291c74de +2026-07-04-fold-stdio-ui-helper.zh.md: 879cce0d40e396b56f1a961b5ff190bab4fd70dd diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md index d3775754b9..8d26af190a 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md @@ -1,5 +1,7 @@ # RFC: Fold the stdio UI helper into the stdio app +English | [中文](2026-07-04-fold-stdio-ui-helper.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md new file mode 100644 index 0000000000..879cce0d40 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md @@ -0,0 +1,28 @@ +# RFC:将 stdio UI 辅助模块折入 stdio 应用 + +Status: implemented + +[English](2026-07-04-fold-stdio-ui-helper.md) | 中文 + +## 问题 + +readline UI 曾是一个完整的包(`@deepseek-ai/dsh-ui-stdio`,位于 `packages/support/`),其唯一的运行时导入方是应用包 `@deepseek-ai/dsh-stdio-demo`。示例通过加载该应用来使用 readline UI,从不自行组合这个辅助模块;仓库中所有其他引用都是因为包边界存在而存在的机械性或描述性表面:manifest 与 tsconfig 条目、生成的 module-graph 行、依赖图与 README 行,以及命名该包的文档注释。ui 分组 README 记录了 support 放置的理由("主要为示例和覆盖率门禁而存在——`ui/` 保留给作为产品交付的界面"),这留下了一个持续的张力:一个已交付的产品应用依赖一个被文档标注为非产品表面的 support 包。 + +这条边界带来的是包元数据、workspace 与 tsconfig 引用、module-graph 行、README 条目,以及 publint 表面——服务于一个并不可独立替换的辅助模块:stdio 应用的前门集群总是包含 readline UI,且没有其他东西能有意义地消费它。 + +## 决策 + +该辅助模块以终端通道插件的形式存在于 `@deepseek-ai/dsh-stdio` 中(`packages/ui/stdio/src/index.ts`):`createStdioChat`、其 `StdioRuntime` 测试 seam 及单元测试(`packages/ui/stdio/tests/stdio.spec.ts`、`readline.spec.ts`)一并迁入,因此 EOF 处理、渲染、dispose(资源释放)以及 piped-vs-TTY 行为在按文件覆盖率门禁下仍有单元测试覆盖,且无需劫持进程全局对象。该模块保持具名的 `name`/`inject`/`Config`/`apply` 导出形状——即应用通过 `ctx.plugin(uiStdio, …)` 挂载时消费的契约——而 `examples/echo-agent` 与 `examples/coding-agent` 中的 keyless Loader 路径冒烟测试继续证明组合树能通过真实 Loader 启动(stdio 包的插件形状单元测试套件固定了显式的 `unwrapExports` 断言,因为缺少 `inject` 的 bundle 会跳过一个意外的 default 导出而非崩溃)。 + +`packages/support/ui-stdio` 包已删除:manifest、tsconfig 引用、module-graph 行与 README 行均已清理;原先命名该包的文档注释(示例 e2e 模块文档、`packages/README.md`、support 与 todo README、[ui 分组 README](../../../../packages/ui/README.md))现在描述的是包内模块。 + +## 曾考虑的替代方案 + +### 为什么不将其提升到 `ui/`? + +提升可以解决 support 与产品之间的错位,同时保留包边界——但只有在 readline UI 是一个可独立替换的集成或拥有第二个组合方时才是正确选择,而消费方普查表明两者都不成立。结构化的 ACP 桥接保持独立包,因为它是产品协议表面,拥有自己的契约和快照层级;readline 辅助模块只是一个应用前门的脚手架。在正式发布前重新拆出的成本很低:如果未来有第二个产品应用需要 readline UI,届时再拆出,由那个消费方来塑造包契约。 + +## 后果 + +- stdio 应用完整拥有自己的前门;一个叶子 `cordis.yml` 仍然只加载一个应用包,演示的形状没有变化。 +- 未来如果有独立的终端 UI 需要将该辅助模块作为包使用,届时由那个第二消费方驱动重新引入,而非仓库为假设性的复用保留一条边界。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml new file mode 100644 index 0000000000..f710b62445 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-prune-producerless-vocabulary-variants.md: 271b97f6217a2694f36b7fe7339eab6176dba9e5 +2026-07-04-prune-producerless-vocabulary-variants.zh.md: 5d75c0327e2faf5e6e37f8db959509161beda702 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md index 5d40b166bd..271b97f621 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md @@ -1,5 +1,7 @@ # RFC: Prune producer-less vocabulary variants (block cache hints, the `agent` message source, the `continuation` turn trigger) +English | [中文](2026-07-04-prune-producerless-vocabulary-variants.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md new file mode 100644 index 0000000000..5d75c0327e --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md @@ -0,0 +1,33 @@ +# RFC:清理无生产者的词汇变体(块缓存提示、`agent` 消息来源、`continuation` 轮次触发器) + +Status: implemented + +[English](2026-07-04-prune-producerless-vocabulary-variants.md) | 中文 + +## 问题 + +合并可扩展的词汇映射表设计上通过声明合并来增长,代码库已在 `TurnEndReasonMap`(`packages/core/session/src/types.ts`)上声明了准入策略:像 `refusal` 这样的变体「在适配器或循环首次发出它之前,有意不加入」。三个已声明的词汇项违反了这一策略——每个都既无生产者也无消费方,其中两个甚至没有测试: + +- **`CacheHint` 及其 `cache?: CacheHint` 块字段**,位于 `TextBlock`/`ToolResultBlock`(`packages/llm/llm/src/types.ts`;image block 上还有第三个同类字段,随 image block 一起移除——见[移除 image 的 RFC](2026-07-04-drop-image-content-block.md))。没有任何地方构造过带 `cache:` 的块——src、测试和文档粘贴全部搜索为空——两个适配器也都不读 `.cache`:DeepSeek 的 prompt 缓存是自动的,适配器只从响应中映射出 `prompt_cache_hit_tokens`,从不向请求中发送提示。这是 Anthropic 风格的 `cache_control` 接口面,却没有任何提供方能兑现它。 +- **`MessageSourceMap.agent`**(`{ kind: 'agent'; agentId: string }`,同一文件)。零个构造点,测试中也没有。它预期的生产者在上线时并未使用它:subagent 后端将父级的 prompt 发送给子级时不带 `source`,因此日志中记录为 `{ kind: 'user' }`,通用信封渲染器在插值 `source.kind` 时也从不按它路由。 +- **`TurnTriggerMap.continuation`**(`packages/core/session/src/types.ts`)。agent loop(智能体循环)在结构上不可能发出它——续写发生在一个轮次*内部*作为后续步骤,从不作为新轮次——循环只构造 `message` 和 `injection` 触发器。唯一的写入者是一个手工构建的测试 fixture(测试前置数据)(`packages/support/llm-replay/tests/llm-replay.spec.ts`),它只需要一个任意的非 message 触发器,`injection` 触发器同样满足需求;唯一的生产环境触发器读取者 ACP 桥接层只过滤 `kind === 'message'`。 + +## 决策 + +删除 `CacheHint`、其 `cache?` 块字段、`agent` 消息来源变体和 `continuation` 轮次触发器变体:已发布的词汇不再包含它们。llm-replay fixture 改用 `injection` 触发器(任何非 `message` 触发器都能满足其用途)。[core.md](../../../core-data-structures/core.md) 和 [session.md](../../../core-data-structures/session.md) 中的 type-equiv 粘贴与裁剪后的映射表一致——两个符号保留在 `scripts/type-equiv.manifest.json` 中,因为每个映射表只是少了一个成员——[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的「后果」部分将缓存提示记录为「受生产者门控」而非「已有归属」,遵照 [implemented/AGENTS.md](../AGENTS.md)。 + +每个变体在获得真正的生产者之日回归,这正是映射表设计上的增长方式:缓存功能连同传输它的适配器一起重新添加 `cache`;subagent 归属连同打标的后端和路由它的消费方一起重新添加 `agent`;真正启动新轮次的自动续写功能连同发出它的插件一起重新添加 `continuation`。 + +## 曾考虑的替代方案 + +### 为什么不保留它们? + +[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 将「缓存提示……已有归属」列为设计后果,预留的槽位确实能传达意图。但一个空槽位是契约面,每个实现和消费方都必须考虑它(我的适配器是否必须兑现 `cache`?我的渲染器是否必须路由 `agent` 来源?),而兄弟映射表自身的 JSDoc 已经拒绝了「无发出者的预留」——`refusal` 和 `max_turn_requests` 被标注为*当有东西首次发出它们时*再添加的变体,而非提前声明。对已声明但无生产者的变体执行同一标准,才能让词汇表有意义:如果它在映射表里,就一定有东西在生产它。 + +## 验证 + +`rg` 搜索 `CacheHint`、`agent` 消息来源的拼写和 `continuation` 触发器的拼写,只返回 RFC 记录(本文,以及[移除 image 的 RFC](2026-07-04-drop-image-content-block.md) 中关于 image block 自身 `cache` 字段的描述);llm-replay fixture 使用 `injection` 触发器断言相同的回放行为;核心数据结构粘贴与 type-equiv manifest(元数据清单)保持同步。 + +## 后果 + +没有运行时行为改变——本来就没有任何东西能构造这些值。镜像事件的移除([边界镜像 RFC](2026-06-20-remove-agent-boundary-mirror-events.md)、[流式分片镜像 RFC](2026-07-02-remove-stream-chunk-mirror.md))只涉及瞬态的 `agent/*` 事件,从不触及持久化词汇,因此不存在冲突。其他地方准入策略已经生效:`rejected`、`prompt/blocked` 和 `hook/invoked`/`hook/result` 各自都有活跃的生产者——本 RFC 将同一标准延伸到缺少生产者的三个变体。image block 自身的 `cache?` 字段属于[移除 image 的 RFC](2026-07-04-drop-image-content-block.md),随该块一起移除;本 RFC 覆盖的是保留下来的块类型上的两个字段。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml new file mode 100644 index 0000000000..3a4db54e54 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-prune-write-only-fs-surface.md: ac2cbcc282b848b26a3d5d327e0ab54612b5ac91 +2026-07-04-prune-write-only-fs-surface.zh.md: 799847aa77599a292c1aa48e150aae99fa130ae3 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md index 0fc11a1c17..ac2cbcc282 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md @@ -1,5 +1,7 @@ # RFC: Prune write-only fields and a dead routing knob from the fs seam +English | [中文](2026-07-04-prune-write-only-fs-surface.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md new file mode 100644 index 0000000000..799847aa77 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md @@ -0,0 +1,32 @@ +# RFC:从 fs seam 中移除只写字段与一个无效路由旋钮 + +Status: implemented + +[English](2026-07-04-prune-write-only-fs-surface.md) | 中文 + +## 问题 + +[fs seam 拆分](2026-06-26-fsspec-style-fs-seam.md)将读取路由与策略从后端移入 `dsh-tool-fs` 和 `dsh-fs-policy`。四处接口保留了拆分前的形态——每次调用都填充,却无人读取: + +1. **`dsh-fs-local` 中的 `STREAM_MIN_SIZE` + `FsIoInternals.streamMinSize`**——*在本次变更之前已被"无硬编码可调参数"审计移除,该审计将路由阈值改为 `dsh-tool-fs` 的 `readStreamMinSize` 配置;此处记录是为了完整呈现整个裁剪。*原始位置(`packages/fs/fs-local/src/fsio.ts`,从 `packages/fs/fs-local/src/index.ts` 再导出):包括 fs-local 自身源码和测试在内,全仓库零读取者。后端不做读取路由——`readWholeText`/`streamWholeText` 是调用方自行选择的独立原语——真正的路由常量在消费方(`packages/fs/tool-fs/src/read.ts`,与 `info.size` 比较)。10 MiB 这个事实有两份镜像;后端那份是死代码,而该旋钮的 JSDoc 声称提供一个并不存在的"读取路由"覆盖。 +2. **`FsTarget.inputPath`**(`packages/fs/fs/src/types.ts`):每个后端和每个测试 fake 都必须编造一个"仅用于诊断"的值,而生产环境零读取者——策略插件和所有错误消息使用的是 `targetKey`/`displayPath`。`listDir` 的生产者暴露了语义摇摆:目录子项拿到的是裸条目名,这不是任何人的"输入路径"。 +3. **`FsEditOutcome.replacements` + `.replaceAll`**(`packages/fs/fs/src/types.ts`):`replacements` 生产环境零读取者(单匹配策略本身保留——它由后端内部的 `FS_AMBIGUOUS_EDIT`/`FS_EDIT_NOT_FOUND` 抛出强制执行,错误消息保留了内部计数);`replaceAll` 仅被 `packages/fs/tool-fs/src/edit.ts` 中的 `formatEditOutput` 读取——作为工具已持有的 `replace_all` 参数的回声。精简后,`FsEditOutcome` 变为 `{ version, before, after }`,与 `FsWriteOutcome` 中真正由后端发现的字段对齐。 +4. **`FileReadOutcome.limit` + `.version`**(`packages/fs/tool-fs/src/read-render.ts`):由读取工具填充,但 `formatReadOutput` 只渲染 `offset`/`lines`/`totalLines`/`truncatedByBytes`,而 `fs/observed` 事件直接使用 `info.version`,不使用 outcome 的副本。 + +## 决策 + +删除 fs-local 常量及其再导出和 `streamMinSize` 旋钮(`FsIoInternals` 中剩余的旋钮确实被原子写入测试使用);从 `FsTarget` 中移除 `inputPath`;将 `FsEditOutcome` 精简为 `{ version, before, after }`,并将 `replaceAll` 从解析后的参数传给 `formatEditOutput`;从 `FileReadOutcome` 中移除 `limit`/`version`。[filesystem.md](../../../core-data-structures/filesystem.md) 中的粘贴内容、`packages/fs/fs/README.md`,以及那些不得不编造被移除字段的测试 fake 随类型一起精简。 + +## 曾考虑的替代方案 + +### 为什么不保留? + +未来的权限/隔离层可能需要解析前的路径来生成错误文本——但它需要的是*请求*,每个调用点仍然持有请求。"替换了 N 处"可能成为面向模型的文本——那是需要时再设计的行为变更,且后端内部的计数为其错误消息保留着。读取页脚可能展示 `limit`——页脚展示的一切已经可以从 `lines`/`totalLines` 推导。与此同时,当前和未来的每个后端(远程、原生)都必须编造无人消费的协议格式(wire format)字段,每个测试 fake 都必须满足它们。 + +## 验证 + +被移除的接口已不存在——`dsh-fs-local` 中的 `STREAM_MIN_SIZE`/`streamMinSize`、`FsTarget.inputPath`、`FsEditOutcome.replacements`/`.replaceAll`、`FileReadOutcome.limit`/`.version`——而请求侧的 `replaceAll`(`FsEditRequest`)和其他 outcome 类型上的 version 字段未受影响;测试 fake 随类型一起精简。`formatEditOutput` 在 `replace_all` 两个分支下的输出文本不变,因此没有快照 golden 被搅动。 + +## 后果 + +后端不增加新义务;它们卸下了四个无人消费的字段。fs 发现工作(glob/grep 工具)触及相同的 `dsh-fs` 类型文件——这是文本层面而非设计层面的重叠,可以机械地解决。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml new file mode 100644 index 0000000000..1e1c22f3c1 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-remove-agent-steering-mirror.md: 311f0f8ffd278adf71a35617b900d4d16037055a +2026-07-04-remove-agent-steering-mirror.zh.md: 4ceb31a0263a7c386ceed071d3f0db315c7a9f23 diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md index a0a383b255..311f0f8ffd 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md @@ -1,5 +1,7 @@ # RFC: Remove the `agent/steering` mirror emit +English | [中文](2026-07-04-remove-agent-steering-mirror.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md new file mode 100644 index 0000000000..4ceb31a026 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md @@ -0,0 +1,33 @@ +# RFC:移除 `agent/steering` 镜像事件发射 + +[English](2026-07-04-remove-agent-steering-mirror.md) | 中文 + +Status: implemented + +## 问题 + +`agent/steering` 是最后一个仍存在的、对持久会话事件的瞬态镜像。循环的 steering 排空逻辑先追加持久事件 `steering/message { turn, content, source }`,紧接着下一行就发射 `agent/steering(agent, turn, content, source)`——同一个事实以 fire-and-forget 事件的形式重复一遍(`packages/core/agent-loop/src/loop.ts`,`drainSteering`)。它在生产环境中没有任何监听者:唯一的订阅方是一个循环回归测试,断言该发射携带了 `source`——而这个事实在上一行的持久事件中已经记录。 + +`agent/steering` 以相同的 payload 复制了紧邻其前的持久事件 `steering/message`。`agent/queued` 则保留为纯 live 信号,因为它在持久化之前触发,覆盖了可能在进入日志前被取消的工作。 + +steering(中途引导)承载着真实的生产流量:钩子桥的轮次续行决策通过 `inbox.steer()` 注入原因,落地为持久的 `steering/message` 事件,钩子矩阵的 golden 文件固定了这些事件。所有这些消费方观察的都是持久事件,没有任何消费方观察镜像。 + +## 决策 + +`agent/steering` 从 agent 事件分类体系中移除:`packages/core/agent/src/types.ts` 中的声明(及其在 live-events JSDoc 列表中的提及)、`drainSteering` 中的发射(随之移除的还有当时已无用的 `ctx` 参数)、`packages/core/agent/README.md` 中的对应行,以及循环伪代码块中的发射行(`packages/core/agent-loop/src/loop.ts` 模块文档与 [architecture.md](../../../architecture.md));Cordis catalog 重新生成后不再包含它。唯一的回归测试改为在持久事件 `steering/message` 上固定 source 保持——它所固定的事实存在于日志中。 + +三份已实施的 RFC 曾声明保留该事件,每份均按 [implemented/AGENTS.md](../AGENTS.md) 修订,指向本 RFC 作为移除记录:[boundary RFC](2026-06-20-remove-agent-boundary-mirror-events.md) 的保留列表条目、[stream-chunk RFC](2026-07-02-remove-stream-chunk-mirror.md) 的范围条款,以及 [event-domain-semantics RFC](../architecture/2026-06-30-event-domain-semantics.md) 的瞬态发射枚举。 + +## 曾考虑的替代方案 + +### 为什么不保留? + +"它是控制信号,不是边界事件"——但分类体系的实际区分维度是「镜像 vs 纯 live」,而非「控制 vs 边界」,而这个事件属于镜像。需要入队时通知的消费方有 `agent/queued`(带 steering flag);需要排空时通知的消费方本质上是在请求 `steering/message` 被追加的那一刻,而 `session/event` 以相同 payload 加上持久性提供了这一点。被否决的 [retire-mid-turn-steering RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md) 捍卫的是 steering **能力**——`steer()`、持久事件、续行强制——本次移除对这些全部不动。 + +## 验证 + +`agent/steering` 这一拼写仅存在于 RFC 行文中(本 RFC、上述三份修订后的 RFC,以及冻结的[被否决 steering 能力 RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md),其文本记录了它所拒绝的提案);catalog 已重新生成;重定向后的测试在 `steering/message` 上固定 source 保持。 + +## 后果 + +没有需要迁移的生产监听者。两种 live 通知需求都保留了归属:入队时通知归 `agent/queued`(带 `steering` flag),排空时通知归 `session/event`(持久的 `steering/message` 落地时触发)。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml new file mode 100644 index 0000000000..16316292cd --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-share-app-bin-boot-glue.md: afaa61fe909f3dbf900337518969410780020a88 +2026-07-04-share-app-bin-boot-glue.zh.md: 2a022fbb8dcdf6977ede81780a87c570715ce441 diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md index 79abfab2a0..afaa61fe90 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md @@ -1,5 +1,7 @@ # RFC: Share the app bins' boot glue instead of maintaining twin copies +English | [中文](2026-07-04-share-app-bin-boot-glue.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md new file mode 100644 index 0000000000..2a022fbb8d --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md @@ -0,0 +1,27 @@ +# RFC:共享应用 bin 的启动胶水代码,不再维护两份副本 + +Status: implemented + +[English](2026-07-04-share-app-bin-boot-glue.md) | 中文 + +## 问题 + +stdio 和 ACP bin 各自重复了环境加载、fail-loud 处理、入口校验与启动逻辑,包括微妙的 Loader 失败行为。两份副本已经发生漂移,且位于自执行文件中、被排除在单元测试覆盖率之外,导致其中的辅助导出无法被复用。 + +## 决策 + +辅助逻辑只存在一处:[`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot)(`packages/ui/app-boot`,归入 `ui` 组,因为 bin 是已发布产物,其运行时依赖本身也必须是已发布的,而非 `support/`)。包含:`resolveConfigPath`(快照感知,两个 bin 共用的唯一路径解析器)、`loadEnv`、`installFailLoud`、`assertEntriesLoaded` 和 `boot`,每个函数都按 bin 的诊断前缀参数化,并在其副作用 seam(warn sink、process 切片)处可注入,使单元测试套件能覆盖每个分支——包括 `boot()` 在进程内驱动真实 Loader、使用相对路径 specifier 的配置,涵盖已就绪树的正常路径和无 fiber 入口的拒绝路径。该包(package)启用了逐文件 100% 覆盖率门禁;Loader 失败的经验知识只有一个归属地。 + +每个 `bin.ts` 是一个精简的自执行组合:在共享辅助逻辑之上叠加各自应用特有的生命周期(ACP bin:replay 模式下跳过环境加载与 stdin-EOF dispose;stdio bin:无额外逻辑)。bin 文件仍然被排除在覆盖率之外且不导出任何内容;已发布产物的防护措施不变——built-bin 冒烟测试仍然在一个 node_modules 形状的临时目录下用原生 node 运行每个 bin(现在也 symlink 了 `ui/app-boot`),并仍然断言缺少配置时的非零退出码,遵循「真实入口路径意味着已发布产物」的防御模式。[extract-example-app-packages RFC](../architecture/2026-06-20-extract-example-app-packages.md) 中关于 bin 归属的事实已相应修订。 + +## 曾考虑的替代方案 + +### 为什么不保留重复? + +bin 被定位为独立拥有的已发布产物,而新增一个包有固定开销(manifest、README、tsconfig reference、publint 表面积),与去重的代码行数相当。但创建 bin 的那份 RFC 从未权衡过应用间共享——它把三个示例 `start.ts` 副本合并**进**了 bin 就止步了;漂移是已观察到的事实;而覆盖率缺口的论点独立于去重论点:这是仓库中唯一被豁免于逐文件 100% 门禁的非平凡运行时逻辑。记录在案的回退方案(仅将纯逻辑提取为各应用模块)可以结束豁免,但会保留两个经验知识归属地。 + +## 后果 + +- 启动胶水代码的变更(新增守卫、修复解析)只需落地一次,两个已发布 bin 自动继承;bin 之间不会再次漂移。 +- `dsh-app-boot` 保持依赖精简(cordis + loader/include 对)——它是启动机制,不是应用接口。 +- bin 自身的文件是近乎平凡的组合;所有带分支的逻辑都在覆盖率门禁之下。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml new file mode 100644 index 0000000000..38cd3003a8 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-tighten-hook-protocol-contract.md: df438516b836315902378afe7f4fd09e512c0966 +2026-07-04-tighten-hook-protocol-contract.zh.md: decc6ba86131f6d1930eb51a1267a9668d91dcb2 diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md index 72172144d0..df438516b8 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md @@ -1,5 +1,7 @@ # RFC: Tighten the hook-protocol contract — dialect, discarded fields, double defaults, and lib-owned `hook/result` semantics +English | [中文](2026-07-04-tighten-hook-protocol-contract.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md new file mode 100644 index 0000000000..decc6ba861 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md @@ -0,0 +1,32 @@ +# RFC:收紧 hook 协议契约——dialect、废弃字段、双重默认值与 lib 拥有的 `hook/result` 语义 + +[English](2026-07-04-tighten-hook-protocol-contract.md) | 中文 + +Status: implemented + +## 问题 + +`dsh-hook-protocol`/bridge 契约中有四处遗漏了 [subagent-observe-enrich RFC](../feature/2026-06-30-subagent-observe-enrich.md) 所记录的纪律——该 RFC 因缺乏消费方而移除了 `agentType` 生命周期字段,以下四处未通过同样的检验: + +1. **`HookDialect` 的 `'native'` 变体**(`packages/hooks/hook-protocol/src/types.ts`)没有任何生产者——bridge 只打 `'claude'` 和 `'codex'` 标记;唯一的 `'native'` 构造出现在 lib 自身的单元测试中。该字段自己的 JSDoc 将 `dialect` 定义为「执行它的 bridge」,而 native 不是 bridge:[interception-seams RFC](../feature/2026-06-30-interception-seams.md) 记录了 native 钩子不是一个 package,且「native 插件已经可以直接使用类型化的 Decisions」而无需持久化的 hook 日志;旗舰 native 插件的工作示例也正是如此断言的(完全没有 `hook/*` 事件)。 +2. **`HookOutput.suppressOutput`**(同一文件)被 codec 解析后在所有路径上都被丢弃:没有 bridge 分支、没有 merge fold、没有 warn、没有 deferred-list 行——在所有「被解析但未兑现」的同类字段中,它是唯一没有明确延期声明的(`updatedInput` → 一条 warn 日志加 [pre-tool-input-rewrite 提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md);`systemMessage` → 一条 warn 日志加 README deferred 行;`continue`/`stopReason` → 一个 `TODO(hook-continue-false)` 锚点加 `'stop'` decision 记录)。从结构上看根本没有什么可 suppress 的:hook 的 stdout 从不进入任何 transcript(文本记录)(上下文仅通过 `additionalContext` 流入;日志只记录 `decision`/`stderrSummary`),因此 hook 作者设置 `suppressOutput: true` 得到的是无声的空操作,连 warn 都没有。 +3. **`defaultTimeoutMs` 在两个 bridge 配置中被双重默认,使用浮动字面量**——一个 schema `.default(600_000)` 加一个 `?? 600_000` 回退(`packages/hooks/hooks-claude/src/index.ts`、`packages/hooks/hooks-codex/src/index.ts`),每个 bridge 为同一个协议级常量提供两个归属,两个 bridge 可能在共享默认值上悄然分歧。*本提案最初的补救——彻底删除该配置项——被 no-hardcoded-tunables 审计取代,后者保留了该配置项作为 bridge 拥有的显式配置(并在旁边新增了 `stderrSummaryMaxChars`);剩下需要修复的是字面量的归属。* +4. **`hook/result` 的语义存在于两个 bridge 中(各一份),而非拥有该事件的 lib。** `summarize()`——stderr 截断规则——在 `packages/hooks/hooks-claude/src/index.ts` 和 `packages/hooks/hooks-codex/src/index.ts` 中逐字节相同,decision 字符串规则 `output.decision ?? (output.continue === false ? 'stop' : 'pass')` 也是如此;然而 `dsh-hook-protocol` 声明了 `hook/result`、将 `stderrSummary` 文档化为「已截断」却不拥有截断逻辑,将 decision 值文档化却不拥有映射逻辑。如果某个 bridge 漂移(不同的上限、不同的回退),共享的持久化事件的语义就会悄然分叉。 + +## 决策 + +`HookDialect` 是封闭的 bridge 集合,`'claude' | 'codex'`;`HookOutput` 移除不受支持的 `suppressOutput`。`hook/result.durationMs` 保留为持久化的审计计时,仅在快照中做归一化。参考默认值各只存在一处:`DEFAULT_HOOK_TIMEOUT_MS` 和 `DEFAULT_STDERR_SUMMARY_MAX_CHARS`。`HookResultRecord` 与 `appendHookResult` 为两个 bridge 统一拥有 stderr 摘要化和 decision 推导逻辑。`BLOCKING_EXIT_CODE` 为 codec 内部常量。 + +## 曾考虑的替代方案 + +### 为什么不保留? + +不受支持的词汇(vocabulary)可以在真正有消费方时回归。`durationMs` 保留,因为持久化的审计计时独立于当前是否有读取者而有价值。Bridge 特有的 payload 构造留在各自 bridge 中,而共享的持久化事件归一化属于协议库。 + +## 验证 + +`HookDialect` 只包含 Claude 和 Codex,`suppressOutput` 在源码、解析字段文档和归一化逻辑中均不存在。`durationMs` 保留在事件和 fixture(测试前置数据)中,回放时做擦除。`600_000` 和 `500` 默认值各只在协议库中出现一次,per-hook 超时覆盖仍然生效,两个 bridge 的测试套件都验证了库拥有的 stderr 截断和 decision 规则。 + +## 后果 + +`dialect`、`suppressOutput`、可调参数与语义变更在协议格式(wire format)和 golden 文件上不可见。代价是 `dsh-hook-protocol` 和两个 bridge 的代码变动——在预发布阶段这很廉价,且比让持久化事件语义的两份副本各自老化要廉价得多。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml new file mode 100644 index 0000000000..f91d18a48e --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-trim-acp-bridge-unreachable-surface.md: 6decb494dcbfd348777577002187007597a8c374 +2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: 77e22f75c96704ee0379c45d2ed23167df047324 diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md index 191ddd833f..6decb494dc 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md @@ -1,5 +1,7 @@ # RFC: Trim unreachable ACP bridge surface — the branding knobs and the kind-sniffing fallback +English | [中文](2026-07-04-trim-acp-bridge-unreachable-surface.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md new file mode 100644 index 0000000000..77e22f75c9 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md @@ -0,0 +1,26 @@ +# RFC:裁剪不可达的 ACP bridge 接口——品牌旋钮与 kind 嗅探回退 + +Status: implemented + +[English](2026-07-04-trim-acp-bridge-unreachable-surface.md) | 中文 + +## 问题 + +`dsh-acp` 有两处接口在任何已交付的配置下都不可达: + +1. **`AcpConfig.agentName` / `agentVersion`**(`packages/ui/acp/src/index.ts`)。已交付的 app 包(package)只向 bridge 传入 `{ model }`(`packages/examples/acp-demo/src/index.ts`),因此唯一的生产配置面——叶子 `cordis.yml`——根本无法设置这两个旋钮;它们只能通过直接挂载 bridge 来设置,而只有单元测试这样做。所有快照 golden(包括 hook-matrix 场景)都固定了 schema 默认值(`deepseek-harness-acp` / `0.0.1`)。这对字段还带着一条活跃的 `TODO(double-default)`:字面量存在两份(schema 的 `.default(...)` 加 `??` 回退),TODO 要求选定一个归属。 +2. **`toolKindFor` 名称启发式**(同一文件)在通用回退路径中对 `bash*`/`read*`/`write`/`edit*` 工具名做了特殊处理。自 [render-intent union](../architecture/2026-07-02-tool-render-intent-union.md) 以来,这些分支匹配到的每个第一方工具都自带 `presentCall` 并携带其 kind,而没有 presenter 的生产工具(`subagent`、`subagent_fork`)本来就落入 `other`。这些分支在生产中可达的唯一情况是:某个工具拒绝自行呈现其调用——`presentCall` 抛出异常(containment 回退),或模型参数未通过工具 schema 导致 `defineTool` 的 `presentCall` 包装层返回 `undefined`(例如 `bash` 调用缺少必需的 `description`)——而 bridge 自身的模块文档明确声明了该启发式所违反的设计规则:「bridge 从不对工具名做特殊处理」。 + +## 决策 + +在初始化时硬编码现有的握手标识 `{ name: 'deepseek-harness-acp', version: '0.0.1' }`,移除不可达的配置字段与重复默认值。在两处 presenter 回退中,将 `toolKindFor` 替换为中性的 `'other'`。正常的第一方呈现不受影响;格式错误或失败的呈现现在渲染一张诚实的通用卡片,而非从工具名推断 kind。初始化测试和快照固定握手标识;只有 `hook-codex-posttool-block` 中格式错误的调用改变了回退卡片的 kind。 + +## 曾考虑的替代方案 + +### 为什么不保留? + +品牌旋钮可以在 app 包将其暴露给部署时回归。从未知工具名推断呈现方式违反了 render-intent 契约;中性回退卡片还能为格式错误的调用和损坏的 presenter 保留原始输入。 + +## 后果 + +除上述回退渲染的取舍外无其他影响——退化路径下,中性卡片比推断出的第一方卡片更易于诊断。 diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml new file mode 100644 index 0000000000..b423b59448 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-12-drop-unconsumed-skill-provider-events.md: 5ec9d201939b8f58334647353f599361bd2e58a0 +2026-07-12-drop-unconsumed-skill-provider-events.zh.md: 8ab2a5f55b2a1eed676b28a1ca7804d6237f63fd diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md index 0907a63417..5ec9d20193 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md @@ -1,5 +1,7 @@ # RFC: Drop unconsumed skill provider events +English | [中文](2026-07-12-drop-unconsumed-skill-provider-events.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md new file mode 100644 index 0000000000..8ab2a5f55b --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md @@ -0,0 +1,29 @@ +# RFC:移除无消费方的 skill 提供方事件 + +Status: implemented + +[English](2026-07-12-drop-unconsumed-skill-provider-events.md) | 中文 + +## 问题 + +skill(技能)注册表产出了两个通知事件,但在生产代码中没有任何监听方。生成的生产者/消费方矩阵以及精确的事件名搜索表明,`skill/provider-added` 和 `skill/provider-removed` 只出现在声明、发射点、测试、生成目录和行文中。 + +skill 发现按需读取当前提供方映射表,提供方注册同步清除已完成的目录缓存,await 后的修订检查防止陈旧的发现结果进入缓存。没有兄弟插件通过这些事件等待 skill 提供方,不同于 `subagent/provider-added` 的实际消费方(它容忍兄弟并发加载)。 + +`tools/change` 和 `system-prompt/change` 明确不在本提案范围内。既有的简化决策将它们保留为面向实时工具和提示词 UI 的有意观测点,且自引用的已挂载插件已在使用 `tools/change`。本提案同样不改动 `subagent/provider-added`/`removed`,因为 `tool-subagent` 有生产级的生命周期消费方。 + +## 决策 + +skill 注册表不再声明和发射提供方成员变更事件。提供方的注册与 dispose(资源释放)仍为 effect 拥有的直接状态变更,同步使已完成的目录缓存失效;查找与发现按需读取当前提供方映射表。测试通过提供方查找和收集的输出来观察清理行为,而非生命周期通知。 + +生成的事件目录、API 目录与生产者/消费方矩阵不再包含已删除的通知。skill 系统 RFC 和包文档通过 effect 拥有的直接状态及缓存失效契约来描述注册行为。 + +## 曾考虑的替代方案 + +**为未来插件保留 skill 提供方通知。** 第三方插件可能想观察提供方的可用性,但直接提供方注册与按需查找才是扩展契约;当前没有消费方需要推送信号。如果未来出现兄弟加载竞态,可以像 subagent 注册表那样引入一个带有该消费方实际所需的身份与就绪语义的通知。 + +## 后果 + +生成的事件矩阵中不再有 `skill/provider-added` 或 `skill/provider-removed` 的行。skill 发现、直接运行时注册、提供方 effect 回滚/dispose、缓存失效与注册表查找清理均保留;随事件一起消失的是监听器触发的回滚。`tools/change`、`system-prompt/change` 以及已被消费的 subagent 提供方生命周期事件不受影响。 + +预发布消费方失去 skill 提供方观测点,但仍保留贡献 skill 的两种方式:直接运行时注册与提供方注册。未来若有消费方需要实时的提供方可用性信息,须新增一个带有其实际所需的身份与就绪语义的专用通知。 diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml new file mode 100644 index 0000000000..6c0c1f9108 --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-12-prune-unused-web-seam-fields.md: b4773c2706cf6d18ea4bb96720cd6c932cdf8942 +2026-07-12-prune-unused-web-seam-fields.zh.md: 1beb9e597c4b990f2c4aaaf3e34e71027c3f3fb7 diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md index 8ece4214b7..b4773c2706 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md @@ -1,5 +1,7 @@ # RFC: Prune unused web seam fields +English | [中文](2026-07-12-prune-unused-web-seam-fields.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md new file mode 100644 index 0000000000..1beb9e597c --- /dev/null +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md @@ -0,0 +1,27 @@ +# RFC:裁剪 web seam 中未使用的字段 + +Status: implemented + +[English](2026-07-12-prune-unused-web-seam-fields.md) | 中文 + +## 问题 + +web 能力携带了一组 request/result/status 值,每个已交付的实现都填充了它们,但没有生产消费方读取。`WebSearchResult.providerId`、`query` 和 `WebFetchResult.providerId` 是结果回显;`tool-web` 只格式化 content/sources/truncation 或 final URL/status/body/truncation,其他运行时也不读取这些字段。搜索提供方返回 `WebProviderStatus.reason`,但可用性检查只看 `available`,并有意输出一条通用的不可用诊断。 + +`WebFetchRequest.timeoutMs` 同样没有生产调用方设置。`tool-web` 只提供 URL,用工具定义的超时加 `exec.signal` 作为调用方截止时间,并依赖本地提供方的配置默认值作为兜底。这个未使用的按请求超时覆盖迫使 `web-fetch-local` 暴露 `maxTimeoutMs`、钳位两个超时源,并为没有产品路径能选中的优先级规则编写文档和测试。`WebExecContext` 则是另一个单字段包装层:每个调用方分配 `{ signal }`,每个提供方立即解包 `exec?.signal`;不存在第二个执行控制字段。 + +## 决策 + +web seam 省略搜索/抓取的 `providerId` 结果回显和搜索 `query` 回显;调用方本身已持有请求和提供方选择信息。提供方以返回布尔值的方法暴露可用性。抓取请求不再有按请求超时或 `maxTimeoutMs` 钳位;本地提供方保留其可配置的默认超时,工具保留自身的截止时间。提供方方法接收一个直接的可选 `AbortSignal`,而非单字段的 `WebExecContext` 包装层。 + +所有 web 实现和面向模型的工具使用更小的契约。接口/实现/消费方的包拆分、提供方选择、来源引用、最终 URL/状态数据、截断报告与安全限制保持不变。 + +## 曾考虑的替代方案 + +**保留自描述结果、按请求截止时间和可扩展的执行上下文对象。** 结果回显可以帮助通用遥测,请求超时可以帮助受信的编程调用方,包装层对象为未来的控制留出空间。但这样的消费方或第二字段并不存在;在每个提供方中携带重复的身份信息、第二套截止时间策略以及包装/解包管道,使当前契约更难实现和解释。如果遥测或按调用的预算控制到来,它应当定义哪个截止时间获胜、在哪里观测提供方身份,以及多个控制是否足以证明上下文对象的存在。 + +## 后果 + +保留下来的每个 web request/result 字段都被生产代码消费或为执行提供方请求所必需。工具可见的搜索/抓取输出、提供方回退、中止行为、配置的超时兜底、截断与引用仍被覆盖,无需请求超时优先级分支或执行上下文包装层。 + +预发布的编程调用方失去结果来源回显和按请求的抓取截止时间。提供方仍有部署可配置的超时并尊重取消信号,因此这次精简移除的是可配置性而非安全边界。 diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml new file mode 100644 index 0000000000..34850593d6 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-property-based-testing.md: 169989746ea5114b1f35e7ebe35a02e8aeb0f782 +2026-06-11-property-based-testing.zh.md: 9e1532c02bb2c46c40577af7275d6aabbb2f9a4f diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md index 67404ab49a..169989746e 100644 --- a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md @@ -1,5 +1,7 @@ # RFC: Property-based testing for protocol-shaped code +English | [中文](2026-06-11-property-based-testing.zh.md) + Status: implemented > Merges the original proposal and the decision record for one topic. It found a real BlockAssembler duplicate-`block-end` bug on first run. diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md new file mode 100644 index 0000000000..9e1532c02b --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md @@ -0,0 +1,29 @@ +# RFC:对协议形态代码进行基于属性的测试 + +Status: implemented + +[English](2026-06-11-property-based-testing.md) | 中文 + +> 将原始提案与决策记录合并为一篇。首次运行即发现了 BlockAssembler 的重复 `block-end` 真实 bug。 + +## 问题 + +基于示例的测试只能固定我们想到的用例。harness 的核心是协议形态的代码:分片流、事件日志、schema 转换、收件箱调度。这类代码的输入空间是组合爆炸的,有趣的 bug 藏在没人写过示例的交错序列里。佐证:一个 block 组装的排序 bug 曾在 happy path 100% 行覆盖率下存活。逐文件 100% 覆盖率只能证明每行都跑过,不能证明每种交错都正确。 + +## 决策 + +引入 `fast-check`(根 devDependency),在每个协议形态的包中编写一个 `tests/properties.spec.ts`。生成器调优为*逼真但对抗性*的输入(而非均匀噪声),`numRuns` 控制在本地套件总耗时远低于约 10 秒。失败时打印可复现的 seed。(原始提案还草拟了一个夜间 CI job,以 100 倍迭代运行;该部分未交付——属性测试套件仅在常规 `push`/`pull_request` CI 中运行,定时高迭代 job 仍属可能的后续工作。) + +- **dsh-llm / BlockAssembler:** 任意分片流(合法 + 畸形:重复索引、滞后分片、缺少 block-start)。不变式:`blocks()` 数量 ≤ 出现过的不同索引数;重组幂等(`blocks()` 在重复调用间稳定,且 `message().content` 与之一致);`blocks()` 从不抛异常且只产出合法的 content-block 标签;`finish` 反映最后一个 `finish` 分片,无 `finish` 分片时默认为 `{kind:'stop'}`。 +- **dsh-session:** 任意事件日志。不变式:`deriveMessages` 确定性;从 seed 回放结果一致;seq 严格单调递增;非消息事件不影响派生历史;派生内容与日志解耦。 +- **dsh-tools:** 任意 `SchemaSpec`。不变式:JSON Schema 的 `required` 等于每层 `required:true` 的键集合;转换是全函数;**并且与[运行时参数校验](../architecture/2026-06-11-runtime-arg-validation.md)组合验证**——满足 spec 的生成参数通过 `validateArgs`,定向破坏(删除 required 键、顶层非 object)被拒绝。这封堵了 validator 与 `InferArgs` 漂移的风险。 +- **dsh-agent-loop:** 任意发送调度,对接一个永不耗尽的适配器,通过 `agent/status` settle 信号驱动(无挂钟 sleep)。不变式:无消息丢失;轮次编号严格递增;状态转换始终在合法状态机上。 + +## 后果 + +- 生成器质量是价值杠杆——生成器偏向小索引池和短字符串,使碰撞与交错频繁出现。 +- **已经产出回报:** BlockAssembler 的流测试发现了一个真实 bug——同一索引的重复 `block-end` 覆写了已刷出的块,导致流式前缀与最终 `blocks()` 不一致。已修复(首次关闭生效,与既有的滞后分片规则一致),并附带专门的回归测试。 +- 属性测试因超时而 flake 是一个发现,不应重试了事。agent loop 的属性测试在设计上是确定性的(通过 `agent/status` settle),因此挂起即为真实缺陷。 +- 属性测试是示例测试的补充而非替代;示例测试固定特定分支,服务于 100% 覆盖率门禁。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml new file mode 100644 index 0000000000..8014cd6b63 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-19-acp-snapshot-tests.md: 0b93c99932a33bca9945dd88ce45f4a1e100ccfc +2026-06-19-acp-snapshot-tests.zh.md: dc0aeb102039d3261ad6bbbb21321ca2b6ef5ec3 diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md index 5f05c92317..0b93c99932 100644 --- a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md @@ -1,5 +1,7 @@ # RFC: ACP snapshot tests — record-once / replay-deterministic +English | [中文](2026-06-19-acp-snapshot-tests.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md new file mode 100644 index 0000000000..dc0aeb1020 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md @@ -0,0 +1,82 @@ +# RFC:ACP 快照测试——一次录制 / 确定性回放 + +Status: implemented + +[English](2026-06-19-acp-snapshot-tests.md) | 中文 + +## 问题 + +单元测试无法覆盖完整的 ACP 子进程 transcript(文本记录),而真实 API 测试既不确定又依赖密钥。因此,面向编辑器的 `session/update` 输出可能在单元覆盖率全绿的情况下发生回归,正如 [default-export 事后分析](../../../postmortem/0001-acp-default-export-drops-inject.md)所展示的那样。 + +全 transcript 测试的阻塞点在于模型:agent(智能体)的输出由非确定性的 LLM(大语言模型)驱动,而每次运行都命中真实 API 的密钥门控测试既不确定也无法在 CI 中运行。我们需要真实运行的保真度,同时具备 fixture(测试前置数据)的确定性。 + +本 RFC 记录了添加第三层测试——**快照测试**——的决策,以及使其确定、CI 中无需密钥且维护成本低的设计选择。 + +## 决策 + +快照测试启动真实的 ACP 示例,通过确定性脚本驱动其 stdio 协议,并将归一化后的输出与已提交的 golden 文件比对。一次从真实 API 录制的会话日志为后续所有模型流提供数据。fixture 就是产品正常持久化的 JSONL。 + +### fixture 即持久化的会话 JSONL + +每个场景的 `session.jsonl` 从一次真实运行中采集。`assistant/chunk` 事件重现模型流;工具、消息和边界事件捕获 harness 行为。一份普通的会话产物因此同时充当回放源和行为 golden。 + +### 回放从日志推导模型脚本 + +`llm-replay` 短路了提供方无关的 `llm/stream` waterfall(瀑布式事件)。`deriveReplayScript()` 按 `(turn, step)` 对已录制的 chunk 分组,每次模型调用服务一组。循环每步发起一次流调用,因此分组是精确的,且无需特殊处理即可包含 error finish chunk。 + +### 内存中的回放条目遵守完整的 LLM 契约 + +`deriveReplayScript` 产出一组 `ReplayEntry`,即回放监听器按位置服务的内存单元: + +``` +{ kind: 'chunks', chunks: StreamChunk[] } +| { kind: 'throw', chunks: StreamChunk[], message: string, code: string, status?: number } +| { kind: 'hang' } +``` + +日志推导出 chunk 条目。流开始前的抛出和挂起没有可重建的 chunk 表示,因此这些场景提供 `replay.override.json`。throw 条目可以包含前缀 chunk 以表示流中途失败。显式覆盖避免了从有损的 turn-end reason 推断适配器行为。 + +### 位置式回放,单个在途流 + +回放是位置式的,因此每个场景只允许一个在途模型流。并发会话快照需要按请求键索引的条目。调用顺序变化需要重新录制,fixture 缺失或耗尽时会大声失败。 + +### 录制采集日志;无密钥回放需要无提供方的配置 + +录制使用真实的 `llm-deepseek` 适配器和 JSONL 持久化后端运行场景,然后将产出的 `.jsonl` 复制到场景目录。逐事件追加是持久的,但 harness 在采集前会优雅关闭子进程(关闭 stdin → `await ctx.dispose()`),确保最终事件已刷出。`llm-replay` 本身不做录制——它只负责回放。 + +回放使用 `cordis.snapshot.yml` 覆盖层,将真实适配器替换为 `llm-replay`,同时保留活跃的组合。录制使用普通配置和 harness 提供的持久化根目录。回放模式跳过 `.env` 加载,因此一个意外存在的 API key 不会触发真实调用。见[单一源配置 RFC](2026-07-04-single-source-acp-replay-config.md)。 + +### 两个表面:归一化后比对 + +快照运行断言**两个**归一化后的表面,因为 harness 的外部表面是不同的: + +1. **stdout transcript**——编辑器看到的帧化 `session/update` JSON-RPC。捕获 ACP bridge 的事件→update 转换(`streamSessionEventUpdate`)中的回归。与已提交的 `stdout.golden.jsonl` 比对。 +2. **重新持久化的会话 JSONL**,归一化后与 `session.jsonl` 比对。同一份 fixture 既是回放源也是期望日志。提示词文本被擦除;每个 header 类别一个场景固定可读的 prompt 和工具内容,见 [header-pinning RFC](2026-07-06-pin-request-header-content-in-one-scenario.md)。覆盖场景的模型行为完全来自其伴随记录。 + +两个表面互补:stdout 覆盖 bridge 投影,JSONL 覆盖投影所省略的循环、工具和边界结构。 + +归一化替换会话 ID、cwd、protocol-id、时间戳、路径和进程易变值,同时保留确定性序列号。场景将真实 bash 使用限制在稳定命令上。stdout golden 保持协议格式(wire format)的 JSONL,每行原始数据必须能解析为 JSON。Vitest 只更新 stdout golden;归一化后的会话相等性检查从不覆写回放 fixture。 + +### 隔离:当前靠归一化,后续可沙箱 + +工具确定性来自临时 cwd、擦除的环境变量、全新的非登录 shell、受限命令和归一化。它不声称具备 OS 级隔离。如果需要更强的层级,沙箱执行器可以通过既有的[能力 seam](../architecture/2026-06-13-capability-seams.md) 替换本地后端。 + +### 回放插件是独立的包 + +`@deepseek-ai/dsh-llm-replay` 是一个支撑包(package),而非示例本地的胶水代码。它通过用从 JSONL 重建的流短路 `llm/stream` 来替换真实适配器,其包级放置使回放逻辑处于正常覆盖率门禁之下。 + +### 两个子命令,回放在默认门禁中 + +`pnpm run test:snapshot` 无密钥回放已提交的 fixture;`test:snapshot:record` 使用真实 API 并重写采集到的会话日志和 stdout golden。fixture 缺失时大声失败。每个场景携带 `input.json`、`stdout.golden.jsonl` 和 `session.jsonl`;无模型场景使用仅含 header 的日志。`replay.override.json` 仅在标记为 `overridden` 的场景中必需,因为它的存在会替换推导出的回放。fixture 守卫拒绝缺失、不匹配和遗留的文件。两个命令都接受场景过滤器。 + +## 曾考虑的替代方案 + +- **手写的模型 chunk `llm.json`**:早期草案;复用真实会话日志使 fixture 成为系统的真实产物而非手工构建的 mock,并兼作行为 golden。 +- **字节级 HTTP 录制库(Polly/nock/MSW)**:否决。适配器相关、与流式 SSE 配合笨拙,且层级低于被测对象。 +- **从 `turn/end {kind:'error'|'aborted'}` 合成 throw/cancel 条目**:否决。这会将 `llm-replay` 耦合到循环内部的 turn 关闭语义,且 `turn/end` reason 是有损的(无法区分抛出的 401 和 finish-error);显式的 `replay.override.json` 伴随记录是更干净的 seam。 + +## 后果 + +新层级为每个场景添加经评审的 input、session、stdout、可选 override 和可选 workspace fixture。workspace 种子在录制和回放时都被复制到临时 cwd。作为回报,该层级通过真实的 Loader 和工具组合提供确定性的无密钥 transcript 覆盖。子进程、input、workspace、归一化和回放 harness 可以支持 ACP 以外的示例。 + +本 RFC 与[拟议的确定性 RFC](../../proposed/testing/2026-06-11-deterministic-and-stress-testing.md) 相关但不取代它:该提案的「通用回放 fixture」在每次测试后重新推导会话*消息历史*(一个内部一致性不变式),而快照测试固定的是*外部协议输出*。二者互补:一个守护事件溯源不变式,另一个守护面向编辑器的契约。 diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml new file mode 100644 index 0000000000..fadd3e4a52 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-19-real-api-e2e-ci.md: 3b5995a3e060ef9b4b1639b5c7fb17c819e73150 +2026-06-19-real-api-e2e-ci.zh.md: 4d4b38cd5989426482b773da79b3a44cec90f747 diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md index ea2eb6964a..3b5995a3e0 100644 --- a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md @@ -1,5 +1,7 @@ # RFC: Real-API e2e in CI against the external DeepSeek API +English | [中文](2026-06-19-real-api-e2e-ci.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md new file mode 100644 index 0000000000..4d4b38cd59 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md @@ -0,0 +1,100 @@ +# RFC:在 CI 中对外部 DeepSeek API 运行真实 API e2e 测试 + +Status: implemented + +[English](2026-06-19-real-api-e2e-ci.md) | 中文 + +## 问题 + +按照既定策略,harness 高度依赖真实 API 测试:[docs/testing.md](../../../testing.md) 论证了无密钥测试套件只能验证管道连通性而非产品行为,[ACP inject 事后分析](../../../postmortem/0001-acp-default-export-drops-inject.md)是现成的证据——178 个无密钥测试全绿,而真实编辑器会话一启动就崩溃。真实 API e2e 套件(`pnpm run test:e2e`,即 `*.e2e.ts` 文件)正是为了弥合这一缺口:它驱动 agent 对接线上 DeepSeek API——真实模型调用、真实 bash 工具、多轮对话、恢复、ACP-over-stdio。 + +默认门禁([.github/workflows/ci.yml](../../../../.github/workflows/ci.yml))刻意不携带密钥:它不含 secret,可供 fork 运行。`test:e2e` 在无密钥时自动跳过(`describe.skipIf(!process.env.DEEPSEEK_API_KEY)`),因此把它加到 ci.yml 只会报绿而不会真正执行真实套件。要让真实 API 覆盖率成为合并信号,需要一个独立的、携带 secret 的工作流。 + +本 RFC 记录的决策是:新增一个**第二个、消费 secret 的工作流**来在 CI 中运行真实 API 套件。同时,由于这是向一个未来可能公开的仓库引入首个 CI secret,属于安全/隔离决策,本文一并记录其依赖的威胁模型以及仓库公开后会发生什么变化。 + +## 决策 + +新增专用工作流 [.github/workflows/e2e.yml](../../../../.github/workflows/e2e.yml),与 ci.yml 分离。它仅在受信事件上使用仓库 secret 对外部 API 运行 `pnpm run test:e2e`,并设有预检步骤:secret 缺失时以显式失败替代假绿。无密钥工作流保持独立,使可 fork 的质量门禁与消费 secret 的真实 API 门禁各自拥有不同的触发和凭证策略。 + +### 独立工作流,而非 ci.yml 中的一个 job + +ci.yml 的价值在于它无密钥、可 fork、始终绿色:任何贡献者(包括外部 fork)都能获得完整的无密钥信号,secret 不在其爆炸半径内。在那里添加消费 secret 的 job 会将这个始终绿色的门禁耦合到凭证可用性和不同的触发策略上。将携带 secret 的工作放在独立文件中,隔离了 secret、触发和并发策略,并为 fork 保留了 ci.yml 的特性。不同的生命周期 → 不同的文件。 + +### 成本不是约束,可靠性才是 + +内部推理成本不是限制因素,因此工作流以覆盖率和信号为优化目标。它在多种触发条件和每个受信 PR 上运行所有匹配的 `*.e2e.ts` 文件,落实 [docs/testing.md](../../../testing.md) 的 with-key 策略。 + +### 触发条件:仅受信事件 + +`workflow_dispatch` + `push` 到 `main`/`master` + 每日定时 `schedule`(`17 0 * * *`,即北京时间 08:17)+ `pull_request`。push 提供合并后信号;schedule 捕获外部 API 漂移;dispatch 是手动逃生口;受信 pull request 获得合并前门禁。该合并前信号有意接受 § 安全性 中描述的更大密钥暴露面。 + +### 不受信 PR 的门禁 + +GitHub 对两类 PR 隐藏仓库 secret:来自 **fork** 的 PR,以及 **Dependabot** PR(同仓库分支,因此 `head.repo.fork == false`,但 secret 仍被隐藏)。job 级 `if:` 对两者都跳过整个 job: + +``` +github.event_name != 'pull_request' + || !(github.event.pull_request.head.repo.fork || github.event.pull_request.user.login == 'dependabot[bot]') +``` + +Dependabot 子句基于 PR **作者**(`pull_request.user.login`)而非 `github.actor`(运行触发者):维护者重新打开或重跑 Dependabot PR 时,`github.actor` 会变成人类,但 PR 仍然无密钥;基于作者的判断在这种情况下依然正确。被 **job 级** `if:` 跳过的 job 报告为*成功*检查(不同于工作流/触发级跳过,后者保持 pending),因此如果需要,可以安全地将此工作流标记为 required status check——fork/Dependabot PR 的跳过但绿色的检查不会阻塞合并。 + +该门禁是一个*干净跳过的便利措施*,而非 secret 的安全边界(见 § 安全性——边界是 GitHub 自身在 `pull_request` 下对 fork 的 secret 隐藏机制)。没有这个门禁,fork 仍然无法读取密钥;它们只会遇到一个令人困惑的预检硬失败并浪费计算资源。 + +### 预检:大声失败,绝不假绿 + +由于 job 仅在 secret 预期存在的受信事件上运行,预检是无条件的存在性检查:密钥为空 → `exit 1` 并附带 `::error::` 注解指明需要配置的 secret 名称。这是让自跳过套件可以安全用作门禁的关键。没有它,被删除/重命名/配置错误的 secret 会让 `test:e2e` 跳过所有真实套件并报告全绿——整个安全网的静默退化。这个守卫将「secret 缺失」从不可见的假通过变为可见的失败。(其正确性已在实际中验证:secret 存在之前的运行恰好在此步骤失败。) + +### Secret 映射与卫生 + +仓库 secret 命名为 `DEEPSEEK_API_KEY_EXTERNAL`;它被映射到适配器和测试读取的 `DEEPSEEK_API_KEY` 环境变量(`process.env.DEEPSEEK_API_KEY`)。独立的 secret 名称记录了意图(这是*外部*公开 API 密钥,不是内部端点密钥),并允许内部端点密钥日后无冲突地共存。以下卫生选择均为防御性设计: + +- **步骤级 secret。** `DEEPSEEK_API_KEY` 仅在预检和 e2e 步骤的 `env:` 中设置,绝不在 job 级设置——因此 checkout/setup-node/install 永远看不到它。依赖中被入侵的安装时生命周期脚本无法读取不在其环境中的 secret。 +- **`permissions: contents: read`。** 该 job 仅读取仓库以运行测试;不需要写权限(不写 PR 评论、不写 status),因此 `GITHUB_TOKEN` 降至最小权限。 +- **`DEEPSEEK_BASE_URL` 固定**为 e2e 步骤上的 `https://api.deepseek.com`。适配器在未设置时会默认使用此值([packages/llm/llm-deepseek/src/index.ts](../../../../packages/llm/llm-deepseek/src/index.ts) 中的 `PUBLIC_BASE_URL`),但显式固定具有自文档化和密封性——一个意外的仓库根目录 `.env`(`vitest.e2e.config.ts` 如果存在会加载它)无法静默地将运行重定向到其他端点。 +- **不回显 secret。** 预检仅打印 `DEEPSEEK_API_KEY present.`——不打印值或长度。 + +### 范围与运行时形态 + +该 job 仅在 Node 24 上运行 `test:e2e`;无密钥门禁和版本兼容性属于主 CI 工作流。测试通过 workspace paths 映射以未构建形式运行,使用有界可配置的 worker 池、逐测试重试和 job 超时。被取代的 PR 运行会被取消,而 push 和定时运行完整执行以提供合并后信号。 + +## 安全性 + +仓库的首个 CI secret 需要一份记录在案的威胁模型,因为同仓库 PR、fork PR 和 Dependabot PR 之间的访问权限不同,且仓库公开后会发生变化。 + +### 今天谁能触及 secret(私有仓库) + +- **无写权限(fork PR):不能。** 两个独立事实阻止了它。第一,工作流使用 `pull_request` 而**非** `pull_request_target`——GitHub 不会将仓库 secret 传递给 fork PR 的 `pull_request` 运行,因此 `secrets.DEEPSEEK_API_KEY_EXTERNAL` 在 fork runner 上解析为空。第二,`if:` 门禁完全跳过 fork PR。secret 隐藏机制是真正的边界;门禁是纵深防御和用户体验。 +- **写(push)权限:能。** 同仓库分支 PR 会收到 secret,因此有写权限的作者可以修改测试代码(或安装生命周期脚本,或其分支上的工作流 YAML)来窃取密钥。这是 **GitHub Actions 固有的,并非本文引入的**:任何对任何仓库有 push 权限的人都可以通过编写工作流来窃取该仓库的任何 Actions secret。写权限 ⇒ secret 访问权,始终如此。缓解措施在于谁被授予写权限以及分支保护,而非本文件。 + +因此「任何能开 PR 的人都能窃取它」是错误的:只有写权限集合内的人能,而该集合本来就能窃取仓库持有的任何 secret。 + +### `pull_request` 触发器增加的残余暴露面 + +由于启用了 PR 运行,密钥会在合并前被交给**写权限作者 PR 分支上的代码**。这比 `push` + `schedule` + `workflow_dispatch` 的暴露面更大,为了在受信写权限集合内获得合并前信号而被接受。如果这一权衡发生变化,可以去掉 `pull_request` 触发器,同时保留合并后、每夜和按需覆盖。 + +### 仓库公开后会发生什么变化 + +**通过本工作流**,secret 对公众仍然受保护:`pull_request` 在公开仓库上行为一致——fork PR(现在任何人都能开)仍然收不到 secret,且在公开仓库上 GitHub 额外要求维护者批准 fork PR 运行,即使批准后运行也不会获得 secret(批准运行不等于交出密钥)。写权限集合不因可见性改变,因此内部人员的现实也不变。 + +变差的是*周边*模型,以下是翻转可见性之前需要处理的事项: + +- **日志变为全球可读。** 今天泄露给组织成员的粗心 secret 回显,在公开后会泄露给整个互联网并在几分钟内被爬取。secret 处理纪律(不回显值/长度——已完成)的重要性大幅提升。 +- **`pull_request_target` 陷阱变为灾难性的。** 如果有人为了「修复」PR 运行而将触发器切换为 `pull_request_target`,工作流将在 base 仓库上下文中运行不受信的 fork 代码**并携带** secret——完整的密钥泄露向量。这在私有仓库上尚可容忍,在公开仓库上则是灾难。e2e.yml 中触发器上的 `SECURITY —` 注释禁止此更改并指向本文。 +- **翻转时轮换密钥。** 该密钥曾存在于私有仓库的 CI 中;将公开视为「假设已暴露」,在那一刻轮换 `DEEPSEEK_API_KEY_EXTERNAL`。 +- **将 secret 置于控制之下。** 确认 Settings → Actions → *"Send secrets to workflows from fork pull requests"* 保持**关闭**(这是唯一能真正打破 fork 边界的设置),并考虑将密钥移入带有 required reviewers 的 GitHub **Environment**,使即使已合并的代码也只在受控条件下使用它,且轮换有一个统一的归属。 + +以上均不需要修改工作流即可公开仓库;它们是运维步骤加上已添加的 `pull_request_target` 守卫注释。 + +## 曾考虑的替代方案 + +- **在 ci.yml 中添加消费 secret 的 job**:否决。它会将无密钥、可 fork、始终绿色的门禁耦合到凭证可用性和不同的触发/并发策略上;不同的生命周期,不同的文件。 +- **省略 `pull_request` 触发器**(更小的密钥暴露面):为了合并前信号而否决;安全性一节承载了被接受的暴露分析。 + +## 后果 + +新增一个 CI 工作流和仓库首个需要维护的 secret。真实 API 套件现在成为合并门禁(受信 PR 上的合并前门禁、main 分支上的合并后门禁)并每夜运行,因此 agent 与外部 API 交互中的真实故障会在 CI 中浮现,而非仅在开发者的本地运行中出现——代价是每个受信 PR 和合并都会产生真实(但内部免费)的 API 调用。预检使 secret 配置错误变为自我通告而非静默禁用安全网。 + +本设计携带一个记录在案的约束面:`pull_request` 触发器的密钥暴露权衡(去掉它以加固)、`if:` 门禁对基于作者的 Dependabot 判断的依赖,以及对 `pull_request_target` 的硬性禁止。上述公开清单是运维伴侣——本 RFC 是未来维护者在更改触发器集合或翻转仓库可见性之前应重新阅读的地方,而非从头重新推导 fork/secret 模型。 + +定时触发器在仓库不活跃 60 天后会自动禁用(GitHub 行为);push/PR/dispatch 是后备,活跃的 monorepo 不会触及此限制。假设 runner 可出站访问 `https://api.deepseek.com`——GitHub 托管的 `ubuntu-latest` 具备此条件;出站受限的自托管 runner 需要在依赖每夜运行之前确认连通性。 diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml new file mode 100644 index 0000000000..592c10b7e0 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-remove-redundant-snapshot-log-goldens.md: badd32d4479ac6d44bb7be3cd262cba57b1b3a38 +2026-06-20-remove-redundant-snapshot-log-goldens.zh.md: 35e4a698cbd19bcceb97df714d2b6bfb371c155a diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md index 45348cfd2e..badd32d447 100644 --- a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md @@ -1,5 +1,7 @@ # RFC: Use `session.jsonl` as the only snapshot session-log artifact +English | [中文](2026-06-20-remove-redundant-snapshot-log-goldens.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md new file mode 100644 index 0000000000..35e4a698cb --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md @@ -0,0 +1,37 @@ +# RFC:使用 `session.jsonl` 作为唯一的快照会话日志产物 + +Status: implemented + +[English](2026-06-20-remove-redundant-snapshot-log-goldens.md) | 中文 + +## 问题 + +模型驱动的 ACP 快照场景同时包含 `session.jsonl` 和 `session.golden.jsonl`。对于普通录制场景,`session.jsonl` 是从真实运行中采集的回放 fixture(测试前置数据),回放测试将新持久化的日志归一化后与 `session.golden.jsonl` 比较。在当前 fixture 中,普通录制场景的归一化录制日志与归一化 golden 完全相同。 + +手工编写的覆盖场景(`error-finish`、`cancel`)目前使用 `replay.override.json` 驱动模型行为,并保留 `session.jsonl` 作为最小占位 fixture,而 `session.golden.jsonl` 存放预期的持久化日志。覆盖文件是一个 `ReplayEntry` 对象的 JSON 数组:`{ "kind": "chunks", "chunks": StreamChunk[] }`、`{ "kind": "throw", "chunks": StreamChunk[], "message": string, "code": string, "status"?: number }` 或 `{ "kind": "hang" }`。这种拆分同样没有必要:当覆盖 sidecar 存在时,`llm-replay` 会替换派生的脚本,不需要从 `session.jsonl` 获取模型分片,因此 `session.jsonl` 仍然可以充当该场景的预期会话日志产物。 + +## 决策 + +彻底移除 `session.golden.jsonl` 概念。每个场景最多只有一个提交的会话日志产物 `session.jsonl`: + +- 对于录制场景,`session.jsonl` 仍是原始采集的日志。回放仍从中派生模型分片,快照测试将回放运行的归一化持久化日志与归一化后的 `session.jsonl` 比较。 +- 对于手工编写的覆盖场景,`replay.override.json` 驱动模型行为,`session.jsonl` 存放预期产出的会话日志。当覆盖文件存在时回放适配器会忽略 fixture 中的模型分片,因此同一个文件既可作为预期日志,又不影响回放行为。 +- 对于无模型场景,`session.jsonl` 可以保留为启动 `llm-replay` 所需的最小 fixture;除非该场景创建了持久化会话,否则无需进行会话日志比较。 + +stdout golden 保持不变;它们是面向编辑器的投影,与会话 fixture 并不冗余。 + +## 曾考虑的替代方案 + +**基于共享(回放运行)上下文对两侧进行归一化**:否决。`normalizeSessionLog` 通过精确字符串匹配擦除 cwd,因此 fixture 中录制的 cwd 不会被擦除,每次比较都会失败。两侧各自基于自身 header 派生的上下文进行归一化——下方的实现说明描述了具体机制。 + +## 验证 + +`session.golden.jsonl` 不再出现在快照 harness、fixture、遗留文件守卫或文档中的任何位置;快照测试对每个模型场景都从 `session.jsonl` 派生预期会话日志;手工编写的 sidecar 场景将其预期产出的日志提交为 `session.jsonl`,并以 `replay.override.json` 作为模型行为覆盖;遗留 fixture 守卫知道每种场景类型需要哪些文件。[ACP 快照测试 RFC](../../implemented/testing/2026-06-19-acp-snapshot-tests.md) 描述了精简后的 fixture 集合。 + +## 后果 + +评审人失去了一个让预期持久化日志在视觉上与回放 fixture 分离的产物名称。stdout golden 仍然保护编辑器 transcript(文本记录),将回放输出与 `session.jsonl` 比较则在不重复文件的前提下保留了 agent loop(智能体循环)/持久化的回归检查。 + +## 实现说明 + +两侧各自基于自身 header 值进行归一化,因为录制与回放具有不同的 id、路径和时间戳。`fixtureContext()` 从 fixture 的 header 派生 fixture 上下文,使已归一化的 fixture 具有幂等性。会话日志使用普通相等比较而非文件快照更新,因此比较过程永远不会改写 fixture。 diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml new file mode 100644 index 0000000000..73c068be2c --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-22-fork-child-replay-seed-boundary.md: a0bf064508107a23147df1a6c824c53a3906c43e +2026-06-22-fork-child-replay-seed-boundary.zh.md: 7ee6c3d373ff5e598efa82d5c8fbad6b8e162aeb diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md index 14db415b1b..a0bf064508 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md @@ -1,5 +1,7 @@ # RFC: Persist the seed boundary so fork-child replay routes correctly +English | [中文](2026-06-22-fork-child-replay-seed-boundary.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md new file mode 100644 index 0000000000..7ee6c3d373 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md @@ -0,0 +1,49 @@ +# RFC:持久化 seed 边界以确保 fork 子会话回放路由正确 + +Status: implemented + +[English](2026-06-22-fork-child-replay-seed-boundary.md) | 中文 + +## 问题 + +[逐会话快照回放 RFC](2026-06-22-subagent-snapshot-replay.md) 让快照层表达了嵌套 agent 的结构:一个父会话加上每个进程内 subagent 各一份录制日志,每份日志以调用方会话为键独立回放为自己的脚本。该 RFC 在 §Scope 末尾提到 fork 快照是「一个简单的后续补充,不是键控方案的缺口」。这个说法对 fork 子会话而言是错的——问题不在键控,而在*脚本推导*。 + +subagent 脚本由 [`deriveReplayScript`](../../../../packages/support/llm-replay) 从录制的会话日志推导而来:它按 `(turn, step)` 对日志中的 `assistant/chunk` 事件分组,每次 `stream()` 调用对应一条回放条目。对 **spawn** 子会话而言这是正确的,因为其日志只包含自己的模型调用。 + +**fork** 子会话不同。fork 后端用*父会话日志中一段平衡的已完成轮次前缀*([`dsh-subagent-inprocess`](../../../../packages/subagent/subagent-inprocess))来初始化子会话,而这段 seed 会成为子会话持久化的 `log`(`Session` 构造函数将 seed 复制到 `this.log`)。因此 fork 子会话的 `.jsonl` 以**父会话**的事件开头——包括父会话的 `assistant/chunk` 事件——之后才是子会话自己的轮次。 + +如果从 fork 子会话的完整日志推导脚本,就会把**父会话**录制的响应当作**子会话**的模型调用来回放:活跃的 fork 子会话第一次调用 `stream()` 时,会收到父会话的第一段 chunk 序列而非自己的。目前录制的场景全部是 spawn,所以这个问题从未触发——但 fork 快照会静默地路由错误,而这恰恰是快照层存在的意义所要捕获的那类 bug。 + +## 决策 + +记录会话**继承**前缀的结束位置,将其持久化,并让回放 harness 仅从子会话**自身**的事件推导脚本。 + +### 1. 会话头部的 `seedLength` + +`SessionHeader` 新增可选字段 `seedLength: number`:表示前导多少个事件是通过 seed 继承而来、而非本会话产生的。fork 后端在创建子会话时设置它(= seed 前缀长度);新建的 spawn 子会话不设置(等价于 0)。该字段通过 `CreateSessionOptions.meta`(以及 `CreateAgentOptions.meta`)传递,在 `SessionStore.prepare` 中设置。 + +`seedLength` 是**显式**的,从不从 `seed.length` 推断。重建(resume/load)时用会话的完整存储日志作为 seed,此时 `seed.length` 是全长而非原始边界——重建路径改为从加载的 header 中取回持久化的 `seedLength`。(形状与 `createdAt` 相同:重建时显式保留,而非重新默认为当前时间。) + +### 2. 两个持久化后端都完整往返 + +- **JSONL**:header 行上的 `seedLength` 字段(`toHeaderLine`/`fromHeaderLine`)。 +- **SQLite**:`sessions` 表上的 `seed_length` 列。 + +包含 `seed_length`、`source_event_seqs` 和 `surface_op` 的 SQLite 布局为 schema version 4。更早的 version 3 布局存在歧义,因此按预发布政策,所有非当前 `user_version` 均直接拒绝,不做迁移。 + +### 3. 回放在边界之后推导子会话脚本 + +`dsh-llm-replay` 的 `parseSessionHeader` 现在也读取 `seedLength`(缺失 ⇒ 0),`loadSessionScripts` 从 `parseSessionLog(text).slice(seedLength)` 推导子会话的条目——即边界处及之后的事件,也就是子会话自己的模型调用。对 spawn 子会话而言 `seedLength` 为 0,这是一个空操作,因此 spawn 场景逐字节不变。 + +这关闭了路由正确性的缺口,两个录制的 fork 场景对其进行了端到端验证——见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md)。 + +## 曾考虑的替代方案 + +- **在 `llm-replay` 中启发式推导边界**(seed 前缀是连续的父事件,止于子会话第一条 `user/message` 之前的最后一个 `turn/end`)。否决:在测试 harness 中用脆弱的启发式重新推导一个生产者已经知道的事实。在源头(fork 后端)持久化边界,是「包边界处显式优于隐式」规则跨持久化边界的应用——子会话 fixture 的读取方永远不需要重建继承在哪里结束。 +- **固定格式版本而不递增**(事件日志使用的 `SESSION_FORMAT_VERSION = 0`「不稳定」策略)。对 SQLite *表*布局否决:`SCHEMA_VERSION` 是单调递增并拒绝旧版的旋钮(一小组值得区分的修订),与事件词汇的 `version` 不同。新增列正是它所版本化的那种破坏性表结构变更,因此递增。 + +## 后果 + +- 在 core 与两个后端之间新增一个持久化的 header 字段;核心数据结构目录(`persistence.md`)在同一个变更中更新(其 `SessionHeader` / `CreateSessionOptions` 的 `type-equiv` 块)。 +- 既有的 schema v2 SQLite 数据库在打开时被拒绝(预发布阶段无用户数据)。 +- spawn 回放不变(`seedLength` 为 0)。fork 回放现在将子会话路由到自己的脚本;由 `llm-replay` 测试中的一个回归用例覆盖(一个子会话 fixture,其 seed 前缀包含父会话的 chunk——推导出的子会话脚本必须排除它,不做 slice 时该用例为红),以及一个持久化往返测试(两个后端,通过共享的 coordinator 契约)。 diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml new file mode 100644 index 0000000000..7312eb5cab --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-22-fork-snapshot-scenarios.md: baca94d6a1071ec38ee20ca841fc3472a870b1a2 +2026-06-22-fork-snapshot-scenarios.zh.md: 227d54cc2bb2e66a391dddd29a7f2593cb02f7e2 diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md index b2c39047b9..baca94d6a1 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md @@ -1,5 +1,7 @@ # RFC: Record fork and mixed spawn+fork snapshot scenarios +English | [中文](2026-06-22-fork-snapshot-scenarios.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md new file mode 100644 index 0000000000..227d54cc2b --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md @@ -0,0 +1,31 @@ +# RFC:记录 fork 与混合 spawn+fork 快照场景 + +[English](2026-06-22-fork-snapshot-scenarios.md) | 中文 + +Status: implemented + +## 问题 + +[seed-boundary RFC](2026-06-22-fork-child-replay-seed-boundary.md) 让 fork 子会话的回放路由正确工作了:`dsh-llm-replay` 从子会话持久化的 `seedLength` 边界处或之后的事件推导出子会话的脚本,因此 fork 子会话继承的父会话前缀不会被当作子会话自身的模型调用来回放。但该 RFC 交付时**没有录制 fork 场景**:切片逻辑仅由 `llm-replay` 的单元测试(一个合成的子会话 fixture(测试前置数据))和一个持久化往返测试覆盖。全 transcript(文本记录)快照层——那个启动真实 `acp-agent` 并回放端到端嵌套 transcript 的网——只有 spawn 子会话(`subagent-spawn`、`subagent-multi`)。一个让单元测试保持绿色的 fork 路由回归,仍然会逃过专为捕获 transcript 回归而建的那一层。 + +表达 fork 场景所需的快照基础设施已经就位:两个进程内后端都通过 `cordis.yml` / `cordis.snapshot.yml` 接入为两个面向模型的工具(`subagent` → spawn、`subagent_fork` → fork),harness 收集每个子会话的日志,回放按 `seedLength` 为键转发每个子会话的 fixture。缺少的只是一个*录制好的场景*来驱动 fork 子会话走完这条路径。 + +## 决策 + +对真实 API 录制两个场景,均在默认门禁中以 keyless 方式回放: + +- **`subagent-fork`**:父会话完成一个轮次以建立一个事实,然后通过 `subagent_fork` 委派一个子任务。fork 子会话继承对话(其日志携带非零 `seedLength`),因此能从父会话的上下文中作答。这是聚焦的回归守卫:子会话 fixture 的 `seedLength` 就是回放切片所依赖的边界,来自真实 fork 的录制而非手工合成。 +- **`subagent-mixed`**:父会话完成一个轮次,然后在同一个 transcript 中分别通过 `subagent`(全新的 spawn 子会话,`seedLength` 为 0)和 `subagent_fork`(fork 子会话,非零 `seedLength`)各委派一次。这是 seed-boundary 和 per-session-replay 两份 RFC 都提到的「未来补充」的混合 spawn+fork 场景:一个 transcript 同时覆盖两种传输方式和切片的两个分支(`seedLength` 0 = 无操作,`seedLength > 0` = 裁掉继承的前缀),两个子会话按 `createdAt` 排序为先 spawn 后 fork。 + +### 为什么需要一个已完成的第一轮次 + +fork 后端用父会话的**已完成轮次的平衡前缀**([`completedTurnPrefix`](../../../../packages/subagent/subagent-fork))来填充子会话种子。如果父会话在第一个轮次就 fork,则没有已完成的轮次可继承,种子为空(≡ 全新 spawn,`seedLength` 为 0),这**不会**覆盖切片逻辑。因此两个场景都使用两条提示词输入:第一条提示词完成一个轮次(建立一个 codeword 供子会话稍后回忆),第二条委派 fork。子会话 transcript 中回忆出的 codeword 只是模型行为的附带结果;真正承载验证的产物是子会话 fixture 中录制的 `seedLength`,回放切片消费的正是它。 + +## 后果 + +- fork 路由切片现在由全 transcript 层守卫,而不仅仅是单元测试。移除 `slice(seedLength)`(回放整个子会话日志)会让**两个**新场景变红——fork 子会话收到的是父会话录制的 chunk 而非自己的——证明守卫确实生效(场景落地时已验证红→绿)。 +- `subagent-mixed` 是第一个在同一个 transcript 中驱动两个*不同* subagent 后端的快照场景,同时覆盖了跨 spawn 和 fork 子会话的 per-session 回放键控。 +- 进程外(ACP)subagent 回放是另一种形态(每个子会话是独立进程、有自己的回放),仍以 `TODO(acp-subagent-replay)` 跟踪——本文场景仅限进程内。 +- 重新录制(`pnpm run test:snapshot:record`)会从真实 API 重新生成全部四个 fork/spawn fixture;两个新场景在没有 key 时与所有录制场景一样自动跳过。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml new file mode 100644 index 0000000000..9ce1aefb81 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-22-subagent-snapshot-replay.md: fbb2e5b93cced118a24f5560f229e2dc341bf3b2 +2026-06-22-subagent-snapshot-replay.zh.md: fd4ba0c109d77fdf9b64e25de74d3da577ce5a9b diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md index 8135f6afd1..fbb2e5b93c 100644 --- a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md @@ -1,5 +1,7 @@ # RFC: Per-session snapshot replay for nested agents +English | [中文](2026-06-22-subagent-snapshot-replay.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md new file mode 100644 index 0000000000..fd4ba0c109 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md @@ -0,0 +1,58 @@ +# RFC:嵌套 agent 的逐会话快照回放 + +Status: implemented + +[English](2026-06-22-subagent-snapshot-replay.md) | 中文 + +## 问题 + +快照测试层(`pnpm run test:snapshot`)启动真实的 `acp-agent` 子进程,通过 [`dsh-llm-replay`](../../../../packages/support/llm-replay) 回放录制的会话,并将归一化后的 stdout transcript(文本记录)与重新持久化的会话日志同提交的 golden 文件做 diff。这是唯一一个端到端验证完整编辑器侧 transcript 的测试层。 + +它最初为**单会话单进程**而建,这一假设硬编码在两处: + +- **`dsh-llm-replay` 没有任何键控。** 它用一个全局游标,将第 N 次 `llm/stream` 调用对应到单一录制序列的第 N 条。当父 agent 和进程内 subagent 同时在一个 context 上流式输出时,调用交错,单一游标会把子 agent 的脚本交给父 agent(反之亦然)。 +- **harness 只收割一份日志。** `findSessionLog` 遍历 sessions 根目录,返回找到的**第一个** `.jsonl`。subagent 作为同一 cwd bucket 中的第二个 `Session` 运行、拥有自己的日志,因此子 agent 的 transcript 被静默丢弃。 + +这正是 [subagent seam RFC](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 中记录的 `TODO(subagent-snapshots)` 延期项:进程内后端(PR2)已有单元测试和 e2e 覆盖,但全 transcript 快照层在本基础设施落地之前无法表达嵌套 agent 的形态。本 RFC 即为该堆叠后续。 + +## 决策 + +回放按**调用方会话**键控,harness 收割**所有**会话日志。 + +### 1. 调用方会话 id 随模型请求传递 + +`GenerateOptions` 新增可选字段 `sessionId`,在请求组装时从 `agent.session.id` 打入。适配器忽略它;`llm/stream` 监听器用它按发起方会话路由。其类型为 `Branded<'SessionId'>`(来自 `dsh-brand`)而非 `dsh-session` 的 `SessionId`,因为后者所在包导入了 `dsh-llm` 的 `Message`,反向导入会形成循环。两个类型等价,会话 id 赋值无需强制转换。将 brand 移入专用 ids 包属于独立工作,因为它会触及所有 id 导入。 + +### 2. 回放按首次调用顺序将活跃会话绑定到录制脚本 + +嵌套场景录制不止一份日志:父会话(`session.jsonl`)加每个 subagent 子会话各一份(`session.1.jsonl`、……)。`dsh-llm-replay` 全部加载,为每个录制会话推导一份脚本,并按 header 中的 `createdAt` 排序(父会话先于子会话创建)。 + +活跃会话 id 每次运行都是全新随机值,永远不等于录制时的 id,因此活跃会话无法通过 id 相等绑定脚本。取而代之的是**首次调用顺序**绑定:第一个发起模型调用的活跃会话认领排序第一的脚本(即父会话——`createdAt` 最早,且必然最先流式输出,因为它必须先运行一个轮次才能委派),下一个新活跃会话认领下一份脚本,依此类推。之后每个会话独立推进自己的游标。 + +这按**谁在调用**键控,而非按全局调用顺序——因此即使 subagent 将来并发运行或在后台运行也保持正确(全局游标会导致交错)。不携带 `sessionId` 的调用(直接在单元测试中调用 `stream()`)被视为一个匿名会话、绑定到主脚本,因此单会话路径的行为与旧版逐字节一致。活跃会话数多于录制脚本数是一个 fail-loud 错误(出现了未录制的 subagent),绝不会静默误路由。 + +子 fixture 按 `createdAt` 排序,在兄弟会话严格顺序执行时与调用顺序一致。id 平局打破只是让退化碰撞确定化。并发或后台子会话必须引入显式的首次调用序号,而非依赖时间戳。 + +## 曾考虑的替代方案 + +曾考虑并否决的方案是将父子日志**按调用顺序合并**为一份全局脚本(仅在进程内 subagent 严格嵌套执行——父 agent 阻塞等待子 agent——时才正确)。对当前的同步切面更简单,但把「父阻塞于子」这一不变式烤死了;未来的后台/并发 subagent 会打破它,而逐会话键控不会。 + +### 3. harness 收割所有日志,主会话优先 + +`harvestSessionLogs` 收集 sessions 根目录下每个 cwd bucket 中的所有 `.jsonl`(JSONL 后端将父会话与同 cwd 的子会话放在同一 bucket),解析各自的 header,并按主会话优先排序:顶层会话(无 `parentSession`)在前,子会话按 `createdAt` 升序排列。`RunResult.sessionLogs` 是复数结果;spec 在录制时将每份日志写回 fixture(`session.jsonl` + `session.<n>.jsonl`),在回放时将每份收割的日志与对应 fixture 做 diff。归一化器已接受复数会话 id 并折叠任何游离 UUID,因此无需修改归一化器。 + +### 4. 场景 + +新增两个嵌套场景,均对真实 API 录制: + +- **`subagent-spawn`**:父 agent 通过 `subagent` 工具将一个子任务委派给一个新 spawn 子会话(2 个会话)。 +- **`subagent-multi`**:父 agent 委派两个子任务,各自交给独立的 spawn 子会话(3 个会话),以三份并行脚本和同一父会话下两个子会话的 `createdAt` 排序来压测逐会话键控。 + +两者均在默认门禁中以 keyless 方式回放。 + +## 后果 + +- `TODO(subagent-snapshots)` 延期项已解决:嵌套 agent transcript 现在是快照的一等形态。 +- `GenerateOptions.sessionId` 是一个小而诚实的 core-seam 新增,在回放之外也有用(遥测、请求路由)。 +- `subagent` 工具绑定到单一提供方,因此 `subagent-multi` 中的两个子会话都是 spawn(全新)。键控按会话路由而非按后端路由,因此对 fork 也已正确。但脚本*推导*并非如此:fork 子会话的日志以种子化的父前缀(父会话的 `assistant/chunk` 事件)开头,从整份日志推导脚本会把父会话的响应当作子会话的来回放。这一正确性缺口通过持久化种子边界来弥合——见 [Persist the seed boundary so fork-child replay routes correctly](2026-06-22-fork-child-replay-seed-boundary.md)——录制的 fork 与混合 spawn+fork 场景现在通过一份 transcript 同时验证两种传输方式(见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md))。 +- 进程外(ACP)subagent 是完全不同的回放形态(每个子 agent 是独立进程、有自己的 replay),作为 `TODO(acp-subagent-replay)` 记录在 PR3 计划中。 diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml new file mode 100644 index 0000000000..10cfb7320c --- /dev/null +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-hook-snapshot-matrix.md: 8505e82fb681975c7506102a3eb858a29ccc11c8 +2026-07-04-hook-snapshot-matrix.zh.md: 6bd4b65b6ba2e16f8433fb0e67ae7ca4eb6a470e diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md index edfcc18585..8505e82fb6 100644 --- a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md @@ -1,5 +1,7 @@ # RFC: Hook snapshot matrix — end-to-end goldens for both bridges +English | [中文](2026-07-04-hook-snapshot-matrix.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md new file mode 100644 index 0000000000..6bd4b65b6b --- /dev/null +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md @@ -0,0 +1,50 @@ +# RFC:钩子快照矩阵——覆盖两种桥接的端到端金标测试 + +Status: implemented + +[English](2026-07-04-hook-snapshot-matrix.md) | 中文 + +## 问题 + +钩子桥接——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude)(7 个 Claude Code 钩子点)与 [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex)(5 个 Codex 钩子点)——将外部钩子命令映射到 harness 的拦截 seam 上。它们拥有深度的单元测试与覆盖率规格覆盖(每个决策分支、每种 payload 方言,均对 mock seam 驱动),外加一个需要密钥的 e2e 测试(`hooks.e2e.ts`,一次真实的 `PreToolUse` 拦截)。但全 transcript(文本记录)快照层——那张真正启动 `acp-agent` 子进程、无密钥回放录制会话、并将归一化的 ACP stdout 与重新持久化的日志对比已提交金标的网——只覆盖了**一个**钩子:Claude 的 `UserPromptSubmit` 拦截(`hook-cc-promptsubmit-block`)。 + +这正是 mock 单元测试在结构上无法替代的层级:它让真实的桥接翻译真实钩子进程的结果,送入真实的 seam 决策,再由真实的 agent loop(智能体循环)做出反应,渲染结果与编辑器所见完全一致。一个桥接翻译或循环结构的回归,即使让所有单元测试保持绿色,也会在除那一个钩子点之外的所有点上逃逸——而对于 Codex 桥接,ACP 示例甚至没有加载它,因此没有任何 Codex 钩子能端到端触发。 + +## 决策 + +实现由两个耦合部分组成: + +### 1. ACP 示例同时加载两种钩子桥接 + +`examples/acp-agent/cordis.yml` 与 `cordis.snapshot.yml` 现在在 `dsh-hooks-claude` 之外同时加载 `dsh-hooks-codex`,各自指向自己的配置文件(Claude 用 `./hooks.json`,Codex 用 `./codex-hooks.json`——两种方言无法共用一个文件)。这是一个真正的产品表面变更,而非仅测试用的接线:交付的 ACP 服务器(以及 `demo:acp` 入口)现在同时携带两种桥接。 + +这是安全的,因为配置文件不存在时桥接是**静默空操作**:`apply()` 捕获读取失败、通过 `ctx.logger` 记录日志、不注册任何东西——零监听器、零会话事件。`acp-agent` 应用不挂载 stdout logger,因此该警告不会到达 ACP JSON-RPC 通道。只需要 Claude 钩子的场景(或真实项目)只提供 `hooks.json`;Codex 桥接找不到 `codex-hooks.json` 便自行消失。这已通过实验验证:两种桥接同时加载时,所有既有快照(均未提供 `codex-hooks.json`)逐字节一致。 + +同时加载是让快照层能够在产品交付的同一个真实应用上对每种方言进行测试的最低要求。录制(启动 `cordis.yml`)天然加载两者,回放以同样方式继承:`cordis.snapshot.yml` 是 `cordis.yml` 的 include-overlay,仅替换 llm 条目(见 [single-source the acp-agent replay config](2026-07-04-single-source-acp-replay-config.md)),因此添加到运行时配置树的桥接无需第二次编辑即出现在回放树中。 + +### 2. 每个钩子点 × 其标志性结果各一个快照场景,覆盖两种方言 + +`examples/acp-agent/tests/snapshots/` 下共 13 个场景,命名为 `hook-<dialect>-<point>-<outcome>`: + +- **手工编写、无模型轮次**(无密钥、无 sidecar——派生的回放脚本为空;比对的是携带 `hook/*` 事件的 `rejected` 轮次):`hook-cc-promptsubmit-block`、`hook-codex-promptsubmit-block`。 +- **对真实 API 录制、录制期间钩子活跃**(模型对决策的反应是捕获的 transcript 的一部分,此后无密钥回放):`hook-{cc,codex}-promptsubmit-context`(allow + additionalContext 折叠)、`hook-cc-pretool-deny` / `hook-codex-pretool-block`(deny → `isError` 工具结果)、`hook-cc-pretool-ask`(ask → 降级为 deny 并附带 approval-required 原因)、`hook-{cc,codex}-posttool-block`(block 并附反馈)、`hook-{cc,codex}-posttool-context`(accept + additionalContext)、`hook-{cc,codex}-stop-continue`(阻塞式 Stop 钩子通过 steering(中途引导)强制多走一步)。 + +每个钩子命令只输出**固定字面字符串**(无时间戳/pid/`$RANDOM`/cwd 回显);快照归一化器擦除 `hook/result` 携带的唯一易变字段(`durationMs`)。`Stop` 场景通过标记文件(`.stop_fired`)自限,使 force-continue 不会循环——`stop_hook_active` 循环守卫仍是桥接的一个 `TODO`,因此无条件的 Stop 钩子会对每一步都 force-continue。 + +### 三个钩子点被有意排除在快照之外 + +在构建矩阵过程中发现,记录在此是因为这是一个决策而非疏漏: + +- **`SessionStart` 与 `SubagentStart`** 通过一个分离的、尽力而为的 `void runPoint(...).then(agent.inject())` 注入上下文,**没有轮次绑定**。产生的 `context/message` 与它所先于的工作(首次模型请求/子 agent 的首轮)存在竞争,落在日志中的位置不确定。录制的金标甚至在自身回放时都无法复现——10 次回放稳定性检查对两者均 10/10 失败。它们留在桥接的单元覆盖中,单元测试直接驱动 seam 而无时序竞争。(如果注入将来变为轮次绑定且确定性的——`TODO(session-start-gating)` 所指的方向——这些点就可以纳入快照。) +- **`SubagentStop`** 是纯观察:其 `subagent/end` 处理器不传递轮次(因此无 `hook/*` 日志事件)、不做注入。它对 transcript **什么都不写**,因此金标会与无钩子运行逐字节一致,永远无法被证明失败——一道咬不到人的守卫。它留在单元覆盖中(`bridge.spec.ts` 已断言该纯观察调用)。 + +因此该矩阵覆盖了所有具有**确定性、可观测 transcript 足迹**的钩子点,涵盖两种方言。 + +## 后果 + +- 每个具有可观测 transcript 的桥接 seam 映射现在都在全 transcript 层、在真实应用中、为两种方言设有守卫——包括此前完全没有端到端覆盖的 Codex 桥接。录制的金标捕获了模型对 denied/blocked/force-continued 轮次的真实反应,这是手工编写的 transcript 只能猜测的。 +- block 场景无需密钥(无模型轮次);其余场景从录制的 fixture(测试前置数据)无密钥回放。`pnpm run test:snapshot:record` 从真实 API 重新生成录制的 fixture,无密钥时像所有录制场景一样自动跳过。 +- prove-red 纪律成立:篡改钩子配置的输出(例如修改 deny 原因)会使其场景在回放时变红——钩子进程在回放期间**真实运行**(只有模型被回放),因此金标守卫的是实际的 hook→seam→loop 路径,而非它的 mock。 +- `acp-agent` 演示现在加载了一个通常会空操作的 Codex 桥接(典型项目中没有 `codex-hooks.json`),这正是预期的 fail-soft 行为,而非代价。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml new file mode 100644 index 0000000000..642ba7f9ad --- /dev/null +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-single-source-acp-replay-config.md: 922bdcced50f8e289449e05b51774f202228b0f8 +2026-07-04-single-source-acp-replay-config.zh.md: d27ea0d3b7227f0fb5f349478591962dd5fe8030 diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md index 70730f0382..922bdcced5 100644 --- a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md @@ -1,5 +1,7 @@ # RFC: Single-source the acp-agent replay config +English | [中文](2026-07-04-single-source-acp-replay-config.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md new file mode 100644 index 0000000000..d27ea0d3b7 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md @@ -0,0 +1,27 @@ +# RFC:将 acp-agent 回放配置收归单一来源 + +Status: implemented + +[English](2026-07-04-single-source-acp-replay-config.md) | 中文 + +## 问题 + +`examples/acp-agent` 曾维护两份手写配置:`cordis.yml`(线上树)和一份 `cordis.snapshot.yml`,后者逐条镜像前者、仅替换 LLM 后端。去掉注释后,全部差异只是八行 `llm-deepseek` 段落换成两行 `llm-replay` 段落。每次应用形态变更都要改两遍,且没有门禁保证对称性:如果两份副本漂移,快照层会静默地测试一个与实际交付不同的应用——正是快照层本身要消除的[「单元全绿、产品却坏」类缺口](../../../postmortem/0001-acp-default-export-drops-inject.md),在更高一层被重新引入,唯一的防线是评审者的警觉。 + +## 决策 + +`cordis.snapshot.yml` include 线上配置,按 id 和 name 禁用指定的 DeepSeek 适配器,并插入回放适配器。因此除此之外的所有条目均来自交付树。回放时选择 overlay;录制仍然启动 `cordis.yml`,加载守卫允许被有意禁用的条目。 + +overlay 依赖的一个 vendor 插件事实(有意为之):include 在加载文件时应用 `patches`——其 `refresh()`/`internal/update` 路径重读时不重新打补丁——这恰好满足一次性回放启动的需要(回放应用不加载 `hmr`,也没有东西在运行中改写配置)。快照套件即为证明:所有场景在 overlay 上原样通过,包括逐字节一致的 golden 文件。 + +## 曾考虑的替代方案 + +### 为什么不选这些方案? + +保留完整的双份配置并加一道对称性校验门禁是记录在案的兜底方案——它能消除静默漂移这一类问题,但仍保留一份 125 行的近似副本,其全部内容只是一个条目的差异,且随应用每增加一个插件而增长。在 bin 侧做替换(解析配置、替换条目、删除文件)会把 YAML 手术放进发布产物,并将回放差异移出视野;overlay 方案让差异保持声明式、可读、且紧邻基础配置——这正是双份配置的支持者真正想要的教学价值。 + +## 后果 + +- 向 `cordis.yml` 添加的插件无需第二次编辑即进入回放树;漂移类问题从结构上消除,而非仅靠门禁拦截。 +- overlay 依赖条目携带稳定的 `id:`。禁用补丁上的 `name` 断言防止误定位(id 被复用时补丁跳过而非禁用错误的插件)。id **重命名**会使补丁退化为跳过,其警告需要一个回放应用有意不具备的 logger——可观察的结果是一条无用的无密钥 `llm-deepseek` 条目与 `llm-replay` 并存,回放输出仍然正确(`llm-replay` 拥有流的短路权);这属于留给评审发现的配置腐烂,而非错误的快照。顶层插入的条目若 id 与已有条目冲突,通过 loader 的 id map 以 last-wins 解析——当前配置无冲突,新增补丁行才是引入冲突的位置。 +- 如果未来回放树需要第二处分歧(另一个后端被替换),只需多加一行补丁,而非再 fork 一份文件。 diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml new file mode 100644 index 0000000000..3ee0a6df6d --- /dev/null +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-06-pin-request-header-content-in-one-scenario.md: 5ccaa23a268114c5ba37ec153f4960b47df13bfd +2026-07-06-pin-request-header-content-in-one-scenario.zh.md: f5ef5e056bb2c05d14ed71315f31c962237db72c diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md index 42c67320f6..5ccaa23a26 100644 --- a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md @@ -1,5 +1,7 @@ # RFC: Pin request-header content in one snapshot scenario +English | [中文](2026-07-06-pin-request-header-content-in-one-scenario.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md new file mode 100644 index 0000000000..f5ef5e056b --- /dev/null +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md @@ -0,0 +1,35 @@ +# RFC:在单一快照场景中固定 request-header 内容 + +[English](2026-07-06-pin-request-header-content-in-one-scenario.md) | 中文 + +Status: implemented + +## 问题 + +ACP(Agent Client Protocol)快照测试套件需要证明每个 `request/header` 中实际发送的组合系统提示词和工具 schema 列表,但如果在每个 `session.jsonl` 中重复这些内容,一次提示词或 schema 编辑就会改写数十条巨大的单行 JSON 记录。保留一份原始 header 可以避免重复,但提示词的评审体验仍然很差:行文被 JSON 转义到一行里,与数千字符的工具 schema 混在一起。 + +## 决策 + +每个 header 组合类别恰好有一个场景被标记为 `pinsHeader`。其目录按评审格式拆分固定内容:`system-prompt.golden.md` 以普通 Markdown 存放归一化后的组合提示词,`tool-schemas.golden.json` 以结构化 JSON 存放完整的初始 schema 及后续 schema 变更,`session.jsonl` 保留 config、reason 和任何模型可见的前缀,同时将 `header.system` 和 `header.tools` 存为 `"{{system}}"` / `"{{tools}}"`。其余所有 JSONL 使用相同的提示词和工具 token,并同样对 session-prefix 内容做 token 化。固定机制实现在 [`dsh-acp-snapshot`](../../../../packages/support/acp-snapshot/README.md) 中,其套件工厂强制每个类别只有一个 pin。 + +纯净的 `scrubSystemPrompts` 和 `scrubToolSchemas` 归一化器应用于所有存储的 session fixture(测试前置数据),独立地对初始 header 内容和 header-delta 批量内容做 token 化。`scrubRequestHeaders` 还为非固定场景对 session-prefix 内容做 token 化,同时保留结构性事实:system-delta 的位置与数量、增删改的工具名称、前缀消息数量、字段存在性、config 和 reason。record 和 refresh 的回写操作在写入 JSONL 前应用相应的 scrub,并从归一化的实时 header 和 delta 重新生成两个 sidecar 文件,因此两条路径都不会将提示词/schema 批量内容重新引入 JSONL,也不会让评审产物变陈旧。 + +守卫使这一拆分自我强制。在磁盘上:每个 `session*.jsonl` 都是提示词和 schema 两个 scrubber 的不动点;只有非固定 fixture(测试前置数据)还必须是完整 header scrub 的不动点;两个 sidecar 恰好存在于固定 fixture 旁边,采用规范的换行终止格式;每个类别有且仅有一个 pin。在运行时:由 parent、spawn 子进程、fork 子进程、初始请求或恢复产生的每个 `request/header`,在易变值归一化后必须与重建的 pin 匹配;固定运行的提示词和 schema delta 也必须与其 sidecar 匹配。如果 header 缺少字符串类型的 prompt、缺少数组类型的工具列表,或出现未声明的 `request/header-delta`,则立即报错。 + +一个 pin 覆盖整个套件,因为每个会话(parent、spawn 子进程、fork 子进程)组合出的工具列表完全相同、提示词除 cwd 外完全相同,而一致性守卫会在这一前提不再成立时立即使套件失败。如果 header 组合在设计上变为会话相关的(例如受限的 subagent 工具集),则分化出的形状获得自己的固定场景。 + +## 曾考虑的替代方案 + +- **每次变更重新录制或手动编辑所有 fixture**:保留了精确的 header,但行为差异被重复的提示词和 schema 内容淹没。 +- **仅在比较时 scrub,fixture 保持原始状态**:比较能通过,但已提交的 fixture 保留着陈旧的重复内容,下次录制时整体改写。存储 token 诚实地表明每个 JSONL 没有固定什么。 +- **全部 scrub,不做任何固定**:丢失了组合 header 实际发送内容(提示词组装、已注册工具顺序、完整 schema)的唯一端到端记录。生成的工具目录只孤立地记录每个工具;只有真实 fixture 能固定组合后的完整集合。 +- **将完整的 pin 全部保留在 JSONL 中**:消除了套件级重复,但提示词和 schema 变更仍然表现为一行转义文本。Markdown 和结构化 JSON 为各自的内容提供了自然的评审格式,同时不削弱重建 header 的断言。 +- **精简会话日志本身(记录内容摘要,header 存到别处)**:违反可重建契约:产品日志必须逐比特重现每个请求(见[可重建请求 RFC](../architecture/2026-07-05-reconstructable-requests.md))。header 体积是测试产物的问题,在测试归一化中解决;线上日志不受影响。 + +## 验证 + +套件针对拆分后的 pin 回放每个场景。单元覆盖率检验独立 scrubber 和完整 scrubber、两种 sidecar 格式、record/refresh 重新生成、归一化的提示词/schema 提取、不动点强制、必需文件对称性、重建 header 的一致性,以及 delta 拒绝。 + +## 后果 + +系统提示词的变更在每个受影响的组合类别中产生一个面向行的 Markdown diff;工具描述的变更在每个类别中产生一个结构化 JSON diff;普通的行为 fixture 不受影响。session fixture 以 token 显示被省略的内容,运行时一致性守卫使每个拆分 pin 对其类别中的所有会话具有权威性。每个固定场景携带两个生成的、换行规范化的 sidecar 文件。 diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml new file mode 100644 index 0000000000..d888da4d05 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-08-shared-acp-snapshot-package.md: 81714191a704af1a9ed029fb8004deac88e39427 +2026-07-08-shared-acp-snapshot-package.zh.md: 2a7c3091c731ded61bed939c8ae0a323123daac9 diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md index 1fb887db52..81714191a7 100644 --- a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md @@ -1,5 +1,7 @@ # RFC: Extract the ACP snapshot suite into a support package +English | [中文](2026-07-08-shared-acp-snapshot-package.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md new file mode 100644 index 0000000000..2a7c3091c7 --- /dev/null +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md @@ -0,0 +1,38 @@ +# RFC:将 ACP 快照测试套件提取为支持包 + +Status: implemented + +[English](2026-07-08-shared-acp-snapshot-package.md) | 中文 + +## 问题 + +ACP 快照层([快照 RFC](2026-06-19-acp-snapshot-tests.md))由三个位于某个示例测试目录内的模块构成:`snapshot-harness.ts`(启动真实 bin 子进程、通过 ACP JSON-RPC 驱动它、收集持久化日志)、`snapshot-normalize.ts`(纯粹的 golden 归一化器),以及 `acp.snapshot.ts` 中约 150 行的场景主体与 fixture(测试前置数据)守卫(record/replay 模式、stdout-golden 与日志比对、pinned-header 一致性守卫、orphan/required-file/single-pin 元测试)。 + +第二个 ACP 示例只能复制 record、归一化与收集逻辑,而这些逻辑必须保持一致。`examples/` 下的代码还处于包(package)覆盖率门禁之外,且原有 harness 只能取消权限请求。共享包使这些机制纳入度量,并允许场景脚本化地指定审批答案。 + +## 决策 + +机制代码位于 [`packages/support/acp-snapshot`](../../../../packages/support/acp-snapshot/README.md)(`@deepseek-ai/dsh-acp-snapshot`);示例的 `*.snapshot.ts` 只包含场景表、agent 路径和一次工厂调用,配合自己的 `snapshots/` fixture 与 `cordis.snapshot.yml` 覆盖层([单源 replay 配置](2026-07-04-single-source-acp-replay-config.md))。读取 `DSH_SNAPSHOT` 留在该边界——库接收的是已解析的 `mode`。 + +**`src/harness.ts`** 提供 `runScenario` 及其脚本/结果类型,以 agent 的 bin 路径和配置路径为参数。权限答案构成一个 FIFO 队列,按稳定的 option kind(而非随机的 option id)索引。缺少答案时取消该请求;不可用的 kind 取消 agent 请求并使场景失败。 + +**`src/normalize.ts`**:纯归一化器,按策略不含钩子。当未来的事件携带新的易变字段(如审批耗时),共享归一化器在同一个变更中学会它,保持「归一化」的含义只有一个归属地,而非各套件各自扩展清洗逻辑。 + +**`src/suite.ts`**:`Scenario` 类型与 `defineAcpSnapshotSuite(options)`,注册逐场景比对、record/refresh 的 fixture 回写、header pin 及其实时一致性守卫,以及 fixture 守卫块(无 orphan 场景目录、必需文件齐全、每个 class 恰好一个 pin、每个 JSONL 是 `scrubSystemPrompts` 的不动点、非 pinning 的 fixture 也是 `scrubRequestHeaders` 的不动点)。pinned-header 契约([pinned-header RFC](2026-07-06-pin-request-header-content-in-one-scenario.md))按套件生效:每个 header class 恰好标记一个 `pinsHeader` 场景,其 `system-prompt.golden.md` 与 JSONL 工具列表将组合后的 header 拆分为可评审的产物;一致性守卫将二者与该 class 中每个实时 header 进行比对。纯辅助函数(`childFixturePaths`、`fixtureContext`、`normalizedHeaders`、`normalizedSystemPrompts`、`formatSystemPromptSnapshot`、`headerDeltaCount`)从模块导出,以便直接进行单元覆盖。 + +## 曾考虑的替代方案 + +- **将模块复制到每个示例中**:正是本 RFC 要阻止的分叉。record/guard 逻辑恰恰是必须在各套件间逐字节一致的代码,而 examples 在覆盖率门禁之外,因此每份副本也无法被度量。 +- **在 `examples/` 下建共享模块目录**:代码仍在覆盖率门禁之外,且需要跨示例边界的相对导入,违背包名导入约定;`examples/` 的叶子节点按设计保持精简。 +- **在 `dsh-acp-demo` 中导出 `/testing` 子路径**:将测试基础设施耦合到产品包的公开接口与依赖集中;`packages/support/` 正是为真实但兼容性要求较低的开发/测试包而设,`dsh-llm-replay` 是先例,本包是其补全。 +- **导出原始测试体函数而非套件工厂**:每个示例将重新拥有 `describe`/`it` 骨架(每套件约 80 行注册样板),却无灵活性收益;工厂让消费方只需一张场景表加一次调用,导出的纯辅助函数在工厂设计内保留了单元可测性。 +- **可注入的 ACP `Client` 工厂取代声明式 `permissionAnswers`**:灵活性最大化,但将 SDK 客户端构造泄漏给每个消费方,并在正被统一的层面重新引入逐示例漂移;声明式队列让 `input.json` 保持为唯一的脚本化接口,且可被 golden 归一化。 +- **泛化到 ACP 之外(传输无关的快照 harness)**:不存在第二种传输;harness 端到端都是 ACP 形态(SDK 客户端、JSON-RPC 帧、`session/update` 等待器),推测性的抽象会在没有消费方之前就拆出一个 seam。 + +## 测试 + +提取保留了所有既有 ACP golden 的每一个字节。包的 `src/` 通过脚本化的 ACP 子进程实现逐文件 100% 覆盖:harness 测试覆盖每个步骤操作、两个预期错误分支、权限选择/回退/不可能选项、环境变量转发、工作区种子注入与收集排序/噪声/回退;suite 测试对已提交的合成 fixture 执行 replay,并对临时副本执行 record,加上纯辅助函数的测试。两个结构上不可达的守卫保留了有理由的覆盖率排除。fake agent 将 `session/new` 的 cwd 替换进日志,包括 Darwin 的 `/var` realpath 行为,与真实 bin 一致。 + +## 后果 + +新示例只需一张场景表加 fixture 即可获得完整的快照层——sandbox 分支从 master 合并后添加自己的套件(自己的 pin 场景、自己的覆盖层、通过 `test:snapshot:record` 生成 fixture、通过 `permissionAnswers` 指定审批答案)。代价:`suite.ts` 导入 vitest,因此该包只能在 vitest 运行中被导入——这是其他包没有的形态,已在其 README 中声明;每个套件 pin 自己的约 8 KB header fixture(真正不同的组合理应有自己的 pin;相同的组合会被该套件的一致性守卫捕获);e2e 启动器的重复仍然存在(`TODO(acp-test-harness)`)——当该迁移落地时,harness 是提取目标。 diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml new file mode 100644 index 0000000000..5b46f88338 --- /dev/null +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-16-typed-event-schemas.md: 8d14c3b2d90d8dcf295e122e95267c2c0d7b2a17 +2026-06-16-typed-event-schemas.zh.md: 87bd6b89a2332b7a3a609a9c36d1e9835e42a0b1 diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md index 9eb4c585a4..8d14c3b2d9 100644 --- a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md @@ -1,5 +1,7 @@ # RFC: Runtime schemas for the event vocabulary (Zod vs the merge-extensible-map pattern) +English | [中文](2026-06-16-typed-event-schemas.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md new file mode 100644 index 0000000000..87bd6b89a2 --- /dev/null +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md @@ -0,0 +1,77 @@ +# RFC:事件词汇的运行时 schema(Zod 与 merge-extensible-map 模式之争) + +[English](2026-06-16-typed-event-schemas.md) | 中文 + +Status: proposed + +## 问题 + +harness 将其核心词汇——内容块、消息来源、结束原因、轮次触发器、轮次结束原因与会话事件——建模为 **merge-extensible map**:一个 TypeScript `interface`(如 `SessionEventMap`、`ContentBlockMap`),插件通过声明合并对其扩展,公开联合类型以 `Map[keyof Map]` 派生。这是本仓库的通用扩展模式,记录在 [docs/architecture.md](../../../architecture.md) 中("The same merge-extensible-map pattern is used for `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`"),并被 `defineTool` 的 `InferArgs` DSL 与 `assertNever` 穷尽性约定所依赖。 + +该模式**仅存在于编译期**。类型在运行时消失:没有 schema 对象可供校验传入值、解析不可信输入或在运行时枚举。[会话持久化契约](../../implemented/architecture/2026-06-14-session-persistence.md)暴露了两个后果: + +1. **持久化将 `event.data` 视为不透明 JSON。** JSONL/SQLite 后端对每个事件逐字 `JSON.stringify`/`JSON.parse`;唯一的运行时守卫是 `isJsonValue`(往返可序列化性——拒绝 BigInt、函数、循环引用、非有限数等),而**不是**结构校验。一个损坏但仍为合法 JSON 的事件数据(字段类型错误、字段缺失)会静默往返,只有在之后被消费方的 `switch` 处理时才可能被发现。 +2. **插件新增的变体没有运行时契约。** 一个通过声明合并添加新 `SessionEventMap` 键的插件,在自身代码中获得了编译期类型,但没有任何机制校验它产出的值是否匹配它声明的形状——无论在生产端、持久化边界还是重新加载时。 + +由此引出问题:事件词汇是否应迁移到 **Zod** 或其他运行时 schema 库,使持久化边界与插件边界拥有运行时 schema 而非被擦除的类型。 + +本 RFC 界定这一问题的范围,不提出具体实现。 + +## 为什么这不是一个持久化变更 + +很容易把「用 Zod 做序列化」理解为对 `dsh-session-persistence-jsonl/src/format.ts` 的局部改动。但它不是,原因在于一个结构性事实:**插件无法通过声明合并扩展一个 Zod schema。** 声明合并是 TypeScript 的编译期机制;Zod schema 是运行时值。要用 Zod 校验事件,你需要一个**运行时注册表**,每个产出事件的包向其贡献自己的 schema(如 `ctx.sessionEvents.register('compaction/marker', z.object({…}))`),每个消费方从中读取。这个注册表——而非持久化后端——将成为词汇的真源,取代 merge-extensible interface。 + +因此真正的提案是:**用运行时 schema 注册表替换编译期的 merge-extensible-map 模式,覆盖全仓库。** 这是一次核心词汇的重新设计。 + +## 影响范围(实测) + +将事件/词汇表面迁移到运行时 schema,至少涉及: + +- **六个 merge-extensible map**(约 370 行核心类型):`ContentBlockMap`、`MessageSourceMap`、`FinishReasonMap`(在 `dsh-llm` 中);`TurnTriggerMap`、`TurnEndReasonMap`、`SessionEventMap`(在 `dsh-session` 中)。 +- **约 10 个 `declare module` 扩展点**,分布在 `dsh-agent`、`dsh-agent-loop`、`dsh-bash`、`dsh-llm`、`dsh-session`、`dsh-session-persistence`、`dsh-system-prompt`、`dsh-tools` 中——每个都将从声明合并改为运行时 `register()` 调用。 +- **事件生产端**——agent loop 中 16 处 `session.append(...)` 调用点——形状不变,但现在在边界处被校验。 +- **约 7 个 switch 消费方**,按这些联合类型分支:`deriveMessages`(`dsh-session`)、`BlockAssembler`(`dsh-llm`)、`dsh-invariants` 插件、两个 LLM 适配器(`dsh-llm-deepseek`、`dsh-llm-pi-ai`)以及工具 schema 层(`dsh-tools`)。`assertNever` 对封闭联合的穷尽性 vs 对可扩展联合的 fall-through 约定(一条已文档化的 lint 规则)需要重新考量——运行时变体不具备静态穷尽性。 +- **`defineTool` 的 `InferArgs` DSL**(`dsh-tools`),它从编译期 schema 规格派生零强制转换的 `execute` 参数类型——这是当前方案的标杆用例。 +- **文档**:architecture.md(该模式被描述为基础性的)、[开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md),以及任何引用该模式的 RFC。 + +这是一次仓库级别的词汇重新设计,不是持久化的实现细节。 + +## 曾考虑的替代方案 + +### A. 维持现状——merge-extensible 类型 + 持久化边界的 `isJsonValue` +保留编译期模式。持久化继续使用不透明 JSON + 可序列化性守卫。插件通过声明合并扩展;事件*形状*的正确性由生产方负责,在编译期由 TypeScript 强制,在开发模式下由 `dsh-invariants` 插件的结构检查强制。 + +- **优点**:零变更;插件扩展只需一行 `interface` 声明合并,具备完整类型推断且无运行时注册仪式;无新运行时依赖;`defineTool` DSL 与 `assertNever` 穷尽性保持正常工作。 +- **缺点**:持久化边界和插件 seam 处无运行时结构校验;格式错误但仍为合法 JSON 的数据被延迟捕获。 + +### B. 仅对 header/封闭形状做校验(schemastery),事件保持不透明 +仅对那些已有手写类型守卫的真正封闭形状加强校验——例如 JSONL 的 `HeaderLine` 守卫(`isHeaderLine`)——使用 **schemastery**(本仓库现有的 schema 库,已用于每个插件的 `static Config`)。merge-extensible 事件联合保持不变。 + +- **优点**:改动小,契合既有约定(schemastery,非新库);用声明式 schema 替换封闭形状上的手写守卫;无核心重设计。 +- **缺点**:不解决事件数据的校验问题;仅固定的元数据记录得到改善。 + +### C. 为整个词汇建立运行时 schema 注册表(Zod 或 schemastery) +用运行时注册表替换 merge-extensible map,生产方向其贡献 schema,持久化/消费方据其校验。 + +- **优点**:持久化边界与插件 seam 处有真正的运行时校验;单一真源;支持通用工具(自动生成文档、模糊测试、协议格式检查)。 +- **缺点**:上述完整影响范围;**Zod 目前不是直接依赖**(仅作为 `@earendil-works/pi-ai` 的传递依赖),本仓库选定的 schema 库是 **schemastery**——广泛引入 Zod 本身就是一个依赖决策;声明合并的人体工学(一行插件扩展、完整推断)被运行时注册 + 手动类型接线取代;`assertNever` 穷尽性保证弱化(运行时变体不具备静态穷尽性)。 + +## 提案 + +暂缓。如果需要在持久化边界做运行时校验,**方案 B**(用 schemastery 校验封闭的 header 与元数据形状)是既有约定内的适度步骤。**方案 C** 是一项架构决策,需要自己的实现 RFC,包括在 Zod 与 schemastery 之间做出选择。 + +## 验收标准 + +- 方案 C 只能通过自己的实现 RFC 推进,绝不作为持久化的附带效果。 +- 如果采纳方案 B,封闭的 header/元数据形状(JSONL 的 `isHeaderLine` 守卫及同类)改用 schemastery 校验以替代手写守卫,merge-extensible map 保持不变。 + +## 风险 + +- 暂缓意味着事件 `data` 在持久化边界仍无结构校验:格式错误但仍为合法 JSON 的数据被延迟捕获,由消费方的 `switch` 处理——这是现状的代价,有意接受。 +- 如果方案 C 最终被采纳,人体工学损失是实际的:一行声明合并变为运行时注册加手动类型接线,`assertNever` 的静态穷尽性保证弱化。 + +## 待解问题 + +- 如果采用注册表,schema 库选 **schemastery**(已在依赖树中,已是配置 schema 库)还是 **Zod**(生态更丰富,目前仅为传递依赖)?同时维护两个 schema 库本身就是成本。 +- 能否采用混合方案:保留编译期推断(使 `defineTool` 和插件 DX 不受影响),同时为每个变体添加*可选*的运行时 schema,仅在持久化/协议边界校验而非每次进程内 append 时校验? +- `dsh-invariants` 插件在开发模式下是否已覆盖了足够多的运行时形状缺口,使得边界校验仅在面对真正不可信的输入(如重新加载被外部修改的日志)时才有必要? diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml new file mode 100644 index 0000000000..edc5a3604d --- /dev/null +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-generic-long-running-tool-runtime.md: ea773a651b5aeec87179aac2ed419f176486977f +2026-06-20-generic-long-running-tool-runtime.zh.md: d50eb6858c11b9c98817b24bfe40f4e2c780f4b9 diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md index 5ed9c6354e..ea773a651b 100644 --- a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -1,5 +1,7 @@ # RFC: Extract a generic long-running tool runtime +English | [中文](2026-06-20-generic-long-running-tool-runtime.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md new file mode 100644 index 0000000000..d50eb6858c --- /dev/null +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md @@ -0,0 +1,43 @@ +# RFC:提取通用的长时运行工具运行时 + +[English](2026-06-20-generic-long-running-tool-runtime.md) | 中文 + +Status: proposed + +## 问题 + +bash 能力 seam 同时支持前台命令和长时运行的后台任务。后台支持体量不小:抽象执行器暴露 `start`、`get`、`ownerOf`、`list`、`readOutput`、`kill` 和 `onTaskDone`;本地执行器跟踪任务、增量读取、owner token、进程清理和完成监听器;模型侧看到三个工具(`bash`、`bash_output`、`bash_kill`);工具插件将完成通知注入回所属 agent 的会话。本地执行器用 owner token 隔离任务访问,因为可预测的全局 task id 会带来跨会话的读取/终止风险。 + +[工具实操手册](../../../cookbook/adding-a-tool.md)已经指出了真正的设计异味:后台 bash 实质上是寄居在一个工具内部的通用长时运行工具基础设施。如果未来的工具也需要后台执行、轮询、终止、所有权和完成通知,这些语义不应藏在 `dsh-bash` 里。 + +## 提案 + +将长时运行任务的语义从 bash 上方抽出,放入一个与工具无关的运行时。bash 仍然能运行后台命令,但不再拥有 task id、ownership token、轮询、取消、完成通知以及模型侧「读取/终止此任务」命令等通用概念。 + +该运行时应拥有: + +- 稳定的 task id 与 owner token,按调用方的会话/agent 键控。 +- 注册一个长时运行任务,附带增量输出的生产者和一个完成 promise。 +- 通用的 read/cancel/list 操作,对所有工具使用相同的跨会话授权规则。 +- 向所属会话注入完成通知。 +- 待处理/运行中/已完成任务状态的展示钩子,bash 只提供命令特有的标签和输出格式化。 + +`dsh-bash` 随后只保留 bash 特有的执行契约:将请求解析为命令规格、运行前台命令,或启动进程并将其流/进程句柄交给通用运行时。`dsh-tool-bash` 保留模型侧的命令工具,但后续操作变为通用的长时运行工具操作(或 bash 向其注册的共享工具层),而非定制的 `bash_output`/`bash_kill` 管道。 + +## 当前 seam 消费情况 + +当前消费方划分清晰:`dsh-tool-bash` 使用完整的前台/后台 seam,而钩子桥接只使用前台的 `resolve` 和 `run`(带受信的 `stdin` 与 `env`)。`get` 和 `list` 仅在测试中使用;`BashTask.done` 仅在实现内部用于 dispose(资源释放),生产环境的完成通知走 `onTaskDone`。提取出的运行时应暴露单一的公开完成机制,保留钩子所需的简单前台路径,并决定后台的 `timeoutMs` 是否属于 `start`。如果运行时拥有进程 spawn,还应集中处理目前重复的凭证清洗逻辑。 + +## 验收标准 + +- bash 特有的包不再定义通用的任务注册表、owner-token 授权、轮询、取消或完成通知机制。 +- 一个共享的长时运行任务服务或工具层拥有这些语义,并作为未来任何具备后台能力的工具的文档化路径。 +- bash 的后台行为仍可通过共享层使用,测试证明跨会话隔离依然成立。 +- ACP 和快照 fixture(测试前置数据)通过共享的任务词汇渲染后台 bash,而非通过 bash 独有的生命周期语义。 +- [工具实操手册](../../../cookbook/adding-a-tool.md)将长时运行工具指向共享运行时,而非告诉每个工具自行发明任务协议。 + +## 风险 + +bash 包失去了对一个已经可用的后台任务实现的本地所有权,实施 PR 可能暂时搅动模型侧的工具名称或 transcript(文本记录)展示。如果最终结果是留下一份后台任务契约、而非让每个未来的长时运行工具克隆 bash 的私有协议,这种搅动是值得的。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml new file mode 100644 index 0000000000..2c12df37b1 --- /dev/null +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-30-pre-tool-input-rewrite.md: add84bfc76434eb25870f09e71860279663d291e +2026-06-30-pre-tool-input-rewrite.zh.md: c636cf42d5c55f0ee1192a46283f8cdbe8c4cadc diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md index 9657512082..add84bfc76 100644 --- a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md @@ -1,5 +1,7 @@ # RFC: Pre-tool input rewrite — a consistent design +English | [中文](2026-06-30-pre-tool-input-rewrite.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md new file mode 100644 index 0000000000..c636cf42d5 --- /dev/null +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md @@ -0,0 +1,53 @@ +# RFC:工具执行前输入改写——一致性设计 + +[English](2026-06-30-pre-tool-input-rewrite.md) | 中文 + +Status: proposed + +## 问题 + +[拦截 seam RFC](../../implemented/feature/2026-06-30-interception-seams.md) 将 `tools/pre-execute` 定义为一道 allow/deny/ask 门禁,作用于身份已受保护、参数已被深度冻结的执行对象。Claude Code 的 `PreToolUse` 钩子还提供了 `updatedInput`,因此忠实的桥接需要一个显式的改写机制。改写不能是对现有执行对象的可变逃逸口:它必须保持持久化历史、审计记录、展示层与实际执行值之间的一致性。 + +## 问题本质:执行前参数的三个读取方 + +在 agent loop(智能体循环)中,工具调用的参数在工具执行之前就已被提交到日志并被活跃消费方读取: + +1. **`assistant/message`** 在工具分发之前追加——它是 `deriveMessages()` 回放时的模型历史来源,因此携带的是模型自身生成的工具调用参数。 +2. **`tool/call`** 是持久化的审计记录,在 `ctx.tools.execute()` 之前追加。 +3. **展示层实时读取 `tool/call.arguments`**:ACP 桥接会记住这些参数并传给 `presentResult`;`dsh-tool-bash` 从中派生卡片标题、rawInput、cwd 以及终端/后台的处理方式。 + +如果只做执行层面的改写,UI 会展示一条命令而实际运行的是另一条,并且结果会对着错误的参数渲染。注册表目前阻止了这种失败模式:它对 `arguments` 做 structured-clone 并深度冻结,将执行身份属性设为不可写,且不暴露任何可替换它们的测试 shim 或监听路径。改写设计必须保持这一受保护的身份边界,而非削弱它。 + +## 提案 + +改写是一次「身份构造前的一致性事务」。当钩子提供 `updatedInput` 时,有效值必须在注册表构造不可变的 `ToolExecution` 之前确定,并原子性地反映到全部三个读取方: + +- `tool/call` 审计事件记录**改写后**的参数(原始参数保留在一个 sidecar 字段中用于审计追踪——钩子改变了调用,原始参数和生效参数都是值得保留的事实)。 +- 派生历史中的 `assistant/message` 必须与实际执行一致——待评估的选项:就地改写 assistant 消息中的工具调用块(改变模型「看到自己说过的话」),或记录一条单独的修正由下一次请求携带。CC 的模型是让模型看到改写已生效。 +- 展示层(`presentCall`/`presentResult`)读取改写后的参数,UI 展示的是实际运行的内容。 + +在 `PreToolDecision` 当前的触发点上做扩展不够:此时两条持久化记录都已存在,执行身份已受保护。实现必须要么将相关决策移到日志提交之前,要么在待处理的模型调用上增加一个专门的更早期改写决策。当循环将生效参数提交到历史和审计之后,再按常规构造不可变执行对象,并照常运行现有的 allow/deny/ask 与工具流水线。 + +## 曾考虑的替代方案 + +### 为什么不直接修改执行对象? + +允许 pre-execute 监听器赋值 `exec.arguments` 只能提供执行层面的改写,模型历史、审计和展示层不会跟着变。保持身份受保护使得这种局部行为无法被表达。在一致性事务实现之前,CC/Codex 桥接对 `updatedInput` 只做日志记录并发出警告,而非声称已兑现;循环分发处的 `TODO(pre-tool-input-rewrite)` 锚定了这个缺失的更早阶段。 + +## 验收标准 + +- 请求的改写在 `ToolExecution` 身份创建之前完成解析,并原子性地反映到全部三个读取方:`tool/call` 审计记录改写后的参数(原始参数保留在 sidecar 字段)、派生历史与实际执行一致、展示层渲染改写后的参数。 +- 生效的 `ToolExecution.arguments` 在 pre-policy、guards、dispatch、post-policy 和最终观测的全过程中保持深度冻结且不可写;不引入任何可变 shim。 +- CC/Codex 桥接兑现 `updatedInput`,不再输出忠实但降级的警告。 + +## 风险 + +- 改写 `assistant/message` 中的工具调用块会改变模型「看到自己说过的话」;是否有提供方在回放时拒绝这种改写,是一个必须在决策形态冻结前通过实验验证的开放问题。 +- 更早期的改写阶段改变了 `assistant/message`、`tool/call`、钩子审计事件与执行之间的顺序关系;设计必须固定这一顺序,同时不削弱轮次封闭性或 call/result 邻接性。 + +## 开放问题 + +- 改写 `assistant/message` 中的工具调用块是否会破坏某些提供方在回放时的预期?还是记录一条单独的修正更安全? +- 原始参数是否应保留在 `tool/call` 事件(审计)上?如果是,放在哪个字段? +- 改写决策是移到日志提交之前,还是成为一个专门的更早期 seam?现有的 pre-tool allow/deny 钩子如何避免运行两次? +- 这与未来的权限 `ask` 流程(用户批准一个被改写的调用)如何交互? diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml new file mode 100644 index 0000000000..d7b4dcf71f --- /dev/null +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-07-claude-code-and-codex-subagent-backends.md: 1ebf01dd8df0980f6c464be8b27033bdfab942f3 +2026-07-07-claude-code-and-codex-subagent-backends.zh.md: 0ed5b42bc9d60b54ac610a8f34f8261f3aeefaed diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md index bf4e85e020..1ebf01dd8d 100644 --- a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md @@ -1,5 +1,7 @@ # RFC: Claude Code and Codex subagent backends (out-of-process delegation to external coding agents) +English | [中文](2026-07-07-claude-code-and-codex-subagent-backends.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md new file mode 100644 index 0000000000..0ed5b42bc9 --- /dev/null +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md @@ -0,0 +1,89 @@ +# RFC:Claude Code 与 Codex subagent 后端(进程外委派至外部编码 agent) + +[English](2026-07-07-claude-code-and-codex-subagent-backends.md) | 中文 + +Status: proposed + +## 问题 + +为 Claude Code 和 Codex 添加隔离的 subagent 提供方。既有的[命名提供方 seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 和 [ACP 后端](../../implemented/feature/2026-06-22-acp-subagent-backend.md)已确立了进程边界的形状。harness 的一个轮次应当能够将一个自包含的任务委派给上述任一产品,并接收其最终回答,同时不暴露父进程的密钥,也不继承来自 `~/.claude` 或 `~/.codex` 的宿主配置。 + +## 方案 + +两个兄弟提供方包(ACP 后端的结构变体),加一次提取: + +- `@deepseek-ai/dsh-subagent-claude-code`:通过 `@anthropic-ai/claude-agent-sdk` 的 `query()` 驱动一个 Claude Code 子进程(SDK 在父进程中运行,并将其捆绑的 `claude` CLI 作为子进程 spawn)。提供方名称 `claude-code`:子进程是 Claude Code 这个**产品**,而非 Anthropic 模型适配器——"claude" 保留给未来的 `dsh-llm` 适配器。 +- `@deepseek-ai/dsh-subagent-codex`:spawn `codex app-server`,通过其 JSON-RPC-over-stdio 协议,使用包内一个手写的换行 JSON 客户端(约 200–300 行)驱动一个 thread/turn。 +- `@deepseek-ai/dsh-subagent-process`:纯库(`subagent-inprocess` 先例),提取 `dsh-subagent-acp` 已有且两个新后端都需要的内容:凭证环境清洗(`SENSITIVE_ENV_PATTERN`/`buildChildEnv`)、EOF → SIGTERM → SIGKILL 的 dispose 阶梯,以及新的隔离配置目录辅助函数(`mkdtemp` 创建、尽力删除)。ACP 后端迁移到该库上;`bash-local` 的兄弟副本保持不动以限制变更范围。 + +两个提供方遵循 ACP 后端契约:每次 `start` 创建一个全新子进程、一次 prompt 往返、不继承父上下文也不声明可选能力、忽略 `request.parent` 和 `request.agentOptions`、使用随机品牌 agent id。`result` 永不 reject;子进程失败映射为 stop reason,原始错误送入 logger。每个提供方在不同的工具名下挂载 `dsh-tool-subagent`。工具结果是唯一新增的模型可见产物,因此不需要新的会话事件;工作区变更仍是 transcript 回放之外的环境副作用。 + +## 已验证的接口事实(固定版本) + +两个集成面在本提案之前均已针对固定实现进行了验证——读取类型与捆绑源码、运行 keyless spike——而非仅依赖厂商文档。固定版本是验证基线,不是运行时契约:后端不执行运行时版本探测(无 `codex --version` 门控、无 SDK 版本嗅探)。兼容性在开发时强制执行——每次依赖升级都重跑 keyless 套件以验证真实加载路径——运行时则通过大声失败来保障:协议层的意外通过 `onError` 结算为 `error`,绝不静默异常。 + +**`@anthropic-ai/claude-agent-sdk` 0.3.202。** `options.env` 会**替换**子进程环境(不与 `process.env` 合并),这正是清洗所需的行为。`settingSources` 默认加载所有文件系统设置——隔离要求显式传入 `[]`。结果子类型为 `success` | `error_during_execution` | `error_max_turns` | `error_max_budget_usd` | `error_max_structured_output_retries`。中止时 SDK 自行升级 CLI 子进程:立即关闭 stdin,若子进程忽略则约 2 秒后发送 SIGTERM(已观察到;无残留进程)——无需自定义 kill 回退。`outputFormat: {type: 'json_schema'}` 和 `agents` 选项已存在,为 seam 的 `outputSchema` 能力和命名 subagent 类型提供了未来着陆点;二者均不在本 RFC 范围内。 + +**codex CLI 0.142.5,`codex app-server`(v2 词汇)。** LF 分隔的 JSON,JSON-RPC 2.0 形状但省略 `"jsonrpc"` 头。 + +- 生命周期:`initialize{clientInfo}` + `initialized` → `thread/start`(接受 `cwd`、`model`、`sandbox`、`approvalPolicy`、`ephemeral`;未认证即可成功)→ `turn/start{threadId, input:[{type:'text',text}]}` 立即返回一个 `inProgress` 的 turn;终止信号是携带 `Turn{status: completed|interrupted|failed|inProgress, error}` 的 `turn/completed` 通知。 +- 审批为服务端发起的请求——`item/commandExecution/requestApproval`、`item/fileChange/requestApproval`、`item/permissions/requestApproval`、`item/tool/requestUserInput`、`mcpServer/elicitation/request`——以 `accept`/`decline` 系列决策应答。 +- 认证:`account/login/start{type:'apiKey', apiKey}` 是一等 RPC,`account/read` 报告 `requiresOpenaiAuth`——且未认证的 `turn/start` 不会快速失败(它会挂在重试中),因此后端必须预检认证并大声结算 `error`,而非等待 turn。 +- 隔离:`CODEX_HOME` 重定向被尊重(`initialize` 响应会回显它,测试可据此断言隔离),且 `ephemeral: true` 的 thread 完全不留会话文件。 + +## 隔离与凭证 + +认证仅使用 API key。每次运行使用一个全新的配置目录(Claude Code 用 `CLAUDE_CONFIG_DIR` 配合 `settingSources: []`,Codex 用 `CODEX_HOME`),dispose 时尽力删除;配置也可选择一个持久目录。共享的子进程环境辅助函数转发 `PATH`、`HOME`、`TMPDIR`、locale、代理设置等普通值,移除凭证形状的名称,并叠加显式的 `config.env`。Claude Code 通过该叠加接收 API key,Codex 则通过 `account/login/start` 接收,而非手写认证文件。 + +## 权限与审批策略 + +每个后端暴露其引擎的原生策略词汇。Claude Code 默认 `permissionMode: default` 配合 `permission: reject`;Codex 默认 `sandboxMode: read-only`、`approvalPolicy: never`,以及相同的拒绝回退。示例可选择启用 `acceptEdits` 或 `workspace-write`。已知的审批、用户输入和 elicitation 请求接收配置的应答;未知方法接收 method-not-found,未知通知被消费。没有 prompt 到达人类,子进程也不会因等待不可用的输入而无限挂起。 + +## StopReason 映射 + +Claude Code:`success` → `completed`;`error_max_turns`、`error_during_execution`、`error_max_budget_usd`、`error_max_structured_output_retries` → `error`(与 ACP 对 `max_turn_requests` 的处理对齐:未完成的任务不算成功);生成器中止 → `aborted`;未知值 → `error`。Codex:`Turn.status` `completed` → `completed`;`interrupted` → `aborted`;`failed` 且 `codexErrorInfo: 'contextWindowExceeded'` → `max-tokens`,其他 `failed` → `error`;传输/spawn/认证预检失败 → `error`(若已请求取消则为 `aborted`)。两者中,`cancel()` 采用 ACP 形状:标志位 + abort/interrupt + 一个 cancel-settled 竞争分支,使不合作的子进程无法阻塞结果。 + +活性姿态,明确声明:teardown 时序是配置项,turn 时长不是。两个后端将 dispose 阶梯的宽限期作为带默认值的已验证配置字段(ACP 后端的 `disposeEofGraceMs`/`disposeGraceMs` 形状,由提取库承载),但刻意**不设** turn 时长或启动超时——与 ACP 一致:turn 期间的活性由调用方通过 `cancel()`/abort signal 掌控,subagent turn 合理地可达数分钟,且 Codex 认证预检已消除了唯一经验证的必然挂起场景;需要墙钟上限的部署从父进程取消即可。 + +## 测试 + +每个适用层级都要求覆盖: + +- **Keyless 单元/集成:** 通过真实 SDK 驱动一个假 Claude CLI,通过真实 wire 客户端驱动一个脚本化的 Codex app-server。在逐文件 100% 覆盖率下,覆盖往返、每个 stop 映射、两条取消路径及预中止、权限策略、未知消息、spawn 失败、reload 清理、导出形状、清洗后的环境、临时目录删除,以及 Codex 认证预检失败。 +- **带 key 的 e2e:** 每个真实引擎在 `acceptEdits` 或 `workspace-write` 下执行文件操作;跳过时命名缺失的二进制文件或 key,并断言无残留子进程。 +- **快照:** 以 `TODO(claude-code-subagent-replay)` 和 `TODO(codex-subagent-replay)` 延后,等待 [subagent 回放 RFC](../../implemented/testing/2026-06-22-subagent-snapshot-replay.md) 描述的进程特定回放形状。 + +## 曾考虑的替代方案 + +### 为什么不用官方 `@openai/codex-sdk` 而是手写客户端? + +dispose 阶梯和环境清洗要求拥有子进程(spawn 参数、env、信号、exit 等待);SDK 隐藏了进程。协议格式极其简单(LF JSON),形状可按固定版本生成(`codex app-server generate-json-schema`),且仓库先例(`hook-protocol`)是自有精简协议核心而非包装他人运行时。SDK 能节省协议演进的维护成本,但代价是失去本后端存在的意义所在的精确控制。 + +### 为什么不用模型可见的 `subagent_type` 参数(单一 Task 风格工具)? + +Claude Code 自己的 Task 工具将 subagent 类型放在模型可见的 schema 中,选择一个 prompt + 工具集人格。这里的选择是在**执行引擎**之间做出的,而只有部署者知道哪些引擎配置了凭证——因此选择留在部署配置中,保持 `dsh-tool-subagent` 文档化的一提供方一工具契约。人格式的类型选择器应当是针对工具的独立 RFC,而非后端。 + +### 为什么不用登录态凭证和用户自己的配置? + +继承 `~/.claude` / `~/.codex`(订阅登录、用户设置、skill、MCP 服务器)会让子进程行为依赖宿主机状态,并在 ACP 后端和 bash 执行器确立的「凭证通过 `config.env` 显式进入,绝不隐式继承」规则上打一个隐式例外。仅 API key 加强制配置目录隔离保持了运行的可复现性;需要共享状态的部署可以刻意将配置目录字段指向一个持久目录。 + +### 为什么不为 Claude Code keyless 测试注入一个驱动 seam? + +注入一个假 `query()` 会 mock 我们自己的边界,使真实 SDK 加载路径未被测试(docs/testing.md 中的 real-over-mock 策略)。曾考虑此方案的风险——SDK↔CLI 的 stream-json 控制协议是内部的——已被 spike 消除:假 CLI harness 今天能对着真实固定版本的 SDK 工作。如果 SDK 升级破坏了 mock,keyless 套件会让升级 PR 失败,这正是门禁在发挥作用。 + +### 为什么不用 ACP 适配器(如 `claude-code-acp`)复用既有后端? + +社区 shim 将两个引擎包装为 ACP,这会让它们在 `dsh-subagent-acp` 上变成「仅配置」。但这在 harness 与引擎之间插入了一个非官方第三方层,抹掉了本 RFC 暴露的原生控制面(permissionMode、sandboxMode/approvalPolicy、配置目录隔离、apiKey RPC),并以 shim 的发布节奏换取第一方协议的稳定性。第一方接口——Agent SDK 和 app-server——才是受支持的集成点。 + +## 验收标准 + +在同时配置了两个引擎和 key 的机器上:一个 REPL 驱动的模型通过 `subagent_claude_code` 完成一个真实文件任务,通过 `subagent_codex` 完成另一个,工具结果为子进程的最终回答,父会话日志中仅有 `tool/call` + `tool/result`。Keyless 套件在无凭证环境中以逐文件 100% 覆盖率通过,断言隔离(清洗后的子进程 env、dispose 后无残留临时配置目录)以及 `~/.claude` / `~/.codex` 的存在与否不影响子进程行为。取消父轮次后,两个后端在有界时间内静默,无残留子进程。e2e 套件干净地自跳过,命名缺失的前置条件。 + +## 风险 + +- `codex app-server` 以 CLI flag 标记为实验性,其 v1/v2 词汇共存;客户端固定 0.142.5、仅实现 v2、消费未知方法/通知而不崩溃,但未来 codex 升级仍可能迫使返工(每次升级重新生成 schema 并重跑 keyless 套件——这是上述「不做运行时版本探测」立场背后的开发时强制执行)。 +- Claude Code 假 CLI mock 依赖一个内部协议:任何 SDK 升级都必须通过 keyless 套件,控制协议的破坏性变更意味着返工 mock(回退方案:上面否决的驱动注入 seam 成为逃生口)。 +- SDK 的 optionalDependencies 每平台约 280MB——已接受,且限制在单个后端包内。 +- SDK 的 SIGKILL 分支(EOF→SIGTERM 之后)未被观察到,信任其存在;e2e 保留无残留进程断言。 +- Codex 是部署前置条件(无 npm 捆绑的二进制文件);缺失或不兼容的二进制文件表现为大声的 spawn/协议 `error`,而非版本探测。 +- 每次运行付出一个全新子进程的代价,且仅最终回答浮出——思考、工具卡片和用量被消费后丢弃;池化、中间进度浮出、`sendMessage`/`resume`、通过 SDK 的 `outputFormat` 实现 `outputSchema`、以及通过 SDK 的 `agents` 选项实现命名 subagent 类型,均为刻意延后。 diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml new file mode 100644 index 0000000000..d9853d91fe --- /dev/null +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-08-interactive-side-sessions.md: 250a906d9ec339399a0e0e29e70b2b8dc189fa72 +2026-07-08-interactive-side-sessions.zh.md: 17d416e2297320e8dfa238569230ecdec91dfa32 diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md index 7caceed4ba..250a906d9e 100644 --- a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md @@ -1,5 +1,7 @@ # RFC: Interactive side sessions and merge-back +English | [中文](2026-07-08-interactive-side-sessions.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md new file mode 100644 index 0000000000..17d416e229 --- /dev/null +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md @@ -0,0 +1,41 @@ +# RFC:交互式侧会话与合并回写 + +Status: proposed + +[English](2026-07-08-interactive-side-sessions.md) | 中文 + +## 问题 + +用户可能希望在不改变当前会话主上下文的前提下探索一个问题。现有原语无法提供这种产品形态:[session-store fork](../../implemented/feature/2026-06-30-session-store-fork-api.md) 创建的是一个无关联的会话,而 [fork subagent](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 是模型驱动的任务,其 transcript(文本记录)会折叠为一条工具结果。两者都不能给用户一个独立的对话,也都不能将结论带着来源信息写回父会话。 + +## 提案 + +**侧会话(side session)** 是一个普通的活跃会话,从源会话最后一个已完成轮次处 fork 而来,附属于自己的 agent,以只读顾问的角色运行,并能够**合并回写**一条精炼笔记。 + +- **Fork 并附属:** 以父会话的均衡已完成轮次前缀创建子会话,并在其元数据中标记 `parentSession` 与 `seedLength`。这组合了 `ctx.agents.create({ seed, meta })`;不新增核心服务或 session-store 方法。 +- **顾问框架:** 创建后注入一条插件来源的 `context/message`,告知子会话只做解释,不执行变更或继续任务。保持系统提示词逐字节一致,以保留提供方对继承历史的前缀缓存。 +- **合并回写:** 向子会话请求一条有长度上限的交还内容,然后向父会话注入一条插件来源的 `context/message`。父会话的下一次请求会在其日志位置看到它,保持回放与[请求可重建性](../../implemented/architecture/2026-07-05-reconstructable-requests.md),无需新增会话事件。 +- **呈现:** 调用方式、会话切换与交还内容的渲染属于首个客户端拥有的界面。本 RFC 仅规定与界面无关的机制。 + +回退产品化、会话树视图、面向模型的侧会话工具,以及 `forkName`/`mergedInto` 元数据不在本 RFC 范围内。一次 live-adapter 原型验证了源日志隔离、继承上下文、多轮子会话交互,以及合并回写在父会话下一轮次中的可见性。 + +## 曾考虑的替代方案 + +- **使用 subagent seam:** 否决。侧会话是用户驱动的、客户端可见的,且可能比父会话的一个轮次存活更久;subagent 是模型驱动的运行,返回一条工具结果。 +- **修改子会话的系统提示词:** 默认否决,因为任何字节变化都会从第零个 token 起使前缀缓存失效。部署方仍可选择更强的隔离。 +- **新增 `sidechat/*` 事件:** 推迟。插件来源的 `context/message` 已经提供持久性、来源信息与回放能力;只有当某个界面需要区分渲染时,专用事件才有正当理由。 +- **现在就绑定协议界面:** 否决。当前 UI 由客户端拥有。实时呈现最终必须从持久化消息派生,以确保回放渲染出相同的记录。 + +## 验收标准 + +- Fork 不改动源会话,并创建一个子会话,子会话具有均衡的已完成轮次前缀、`parentSession`、`seedLength`,以及逐字节一致的系统提示词。 +- 顾问框架在子会话追加历史的头部恰好添加一条插件来源的 `context/message`,而非修改其系统提示词。 +- 合并回写恰好添加一条有长度上限的 `context/message`,来源为 `plugin: sidechat`;父会话的下一次请求与回放在相同位置看到它。 +- 父会话与子会话并发运行,日志与流之间无串扰。 +- 单元测试覆盖 fork/attach 与合并回写;快照覆盖率随首个绑定界面一起落地。 + +## 风险 + +- 只读行为在 `tools/pre-execute` 拒绝门禁强制执行之前仅为建议性的;[拦截 seam](../../implemented/feature/2026-06-30-interception-seams.md) 可以在不改变本机制的前提下添加该门禁。 +- 经过压缩(compaction)的源会话 fork 出的是其压缩视图,因此绑定界面应当告知用户:子会话继承的是摘要而非被替换的轮次。 +- 反复的交还内容会消耗父会话上下文。每次合并的长度上限约束了单条笔记的大小;后续整合属于压缩的职责。 diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml new file mode 100644 index 0000000000..349767710c --- /dev/null +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-10-sqlite-session-query-provider.md: 8b67baf420433feca9d5cd09d58852bb9b1545a9 +2026-07-10-sqlite-session-query-provider.zh.md: de97e59ac6f2f90a738ff5c8b9c2872d54ba3954 diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md index acfdf23bee..8b67baf420 100644 --- a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md @@ -1,5 +1,7 @@ # RFC: SQLite FTS5 session search +English | [中文](2026-07-10-sqlite-session-query-provider.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md new file mode 100644 index 0000000000..de97e59ac6 --- /dev/null +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md @@ -0,0 +1,53 @@ +# RFC:SQLite FTS5 会话搜索 + +[English](2026-07-10-sqlite-session-query-provider.md) | 中文 + +Status: proposed + +## 问题 + +精确读取服务 `ctx.sessionQuery` 有意不维护派生索引。大规模持久化的历史记录需要全文搜索,而不能在每次查询时扫描所有事件;同时,当前活跃会话需要一个比上次持久性检查点更新的覆盖层。搜索还需要具体的排序、摘要片段、过滤、分页、取消以及重建行为。 + +如果把这些关注点拆分到一个推测性的 provider 协调器和一个数据库实现中,会产生两个耦合的协调状态机。第一个真实实现应当将源观察、提取、SQLite 事务、generation 管理和查询作为一个完整生命周期来拥有。 + +## 提案 + +在精确读取包旁新增 `@deepseek-ai/dsh-session-query-sqlite`。该包将暴露一个搜索服务或以其实际消费方所需的最小 API 扩展现有服务族;第一阶段不预先承诺 provider 注册协议。它将依赖 `ctx.sessions` 和可选的 `ctx.sessionPersistence`,拥有一个独立的派生 SQLite 数据库,并复用规范的 `foldSurface()` 分类。 + +实现拥有一个串行化的协调/数据库事务状态机。一次事务观察权威的持久化元数据和活跃快照,提取语义文档,更新派生表,推进相关的游标 generation,并执行或启用相应的查询。没有第二个服务维护并行的指纹、脏标记、活跃 ID 集合或失效 generation。 + +持久化文档在重启后保留。活跃覆盖层是连接局部的,为同一会话遮蔽持久化行,在活跃所有者或数据库关闭时消失。派生数据库与规范持久化分离,因此索引重置、损坏、分词器变更和 schema 变动不会危及持久的对话日志。 + +## 随实现确定的搜索语义 + +实现必须从可执行的用例出发定义跨会话和会话内两种搜索范围。每个可搜索事件是一个文档,包含会话元数据、事件元数据、surface 分类、归一化语义文本和有界的纯文本摘要片段。会话级结果按其最强匹配事件分组;数值化的后端分数保持私有。 + +过滤器在排序之前编译为参数化 SQL。查询语法作为数据处理。排序包含稳定的平局字段。不透明游标绑定到归一化的请求形状和最小相关 generation;不相关的会话变更不应使会话内游标失效。取消操作必须停止调用方等待,并在运行时允许的范围内中断 SQLite 工作。 + +分词器选择仍是一个实现实验。FTS5 trigram 支持子串召回,但会拒绝短于三字符的有用词项并增大索引体积;提案在将其纳入契约之前,必须对比默认 Unicode 分词器做基准测试。 + +## 提取与协调 + +该包首先为消息、推理(reasoning)、工具调用/结果、被拦截的提示词、上下文、steering(中途引导)、待办事项和错误/状态详情提供第一方语义提取。结构性事件和流式分片不贡献文档。未知的声明合并事件/内容类型保持不可搜索,除非有真实的扩展消费方证明需要公开的提取器注册表。 + +协调可以使用稳定指纹来避免重写未变更的持久化会话,但指纹的计算和存储由数据库包拥有。当源观察或提取失败时,它绝不能报告某行为最新。provider-schema 不匹配只重置派生数据库;普通的源变更使用事务性 upsert/delete。已挂载但不可读的持久化使受影响的搜索失败,但不影响规范写入或已知的活跃精确读取。 + +## 曾考虑的替代方案 + +- **在规范持久化数据库中添加 FTS 表**:否决。可重建的索引不应与权威日志共享 schema/重置/故障边界。 +- **在第一阶段重新引入 provider 协调**:否决。只有一个计划中的实现,没有证据表明存在稳定的多 provider seam。 +- **立即持久化活跃覆盖层**:否决。活跃事件在现有检查点提交之前不是规范的。 +- **返回 BM25 分数**:否决。提供方特有的数值尺度在语料变化时不稳定。 + +## 验收标准 + +- 重启测试覆盖未变更、新增、已变更和已删除的持久化会话,且不重建整个索引。 +- 重新打开时保留持久化行并移除活跃行;活跃行先遮蔽、后显露其持久化基底。 +- 测试覆盖两种搜索范围、元数据过滤、surface 默认值、摘要片段、转义、确定性平局、分页、范围内的陈旧游标、取消、动态持久化挂载/卸载,以及事务失败后的恢复。 +- schema 不匹配只重置派生数据库。 +- 一个无 key 的端到端测试将真实的持久化后端与真实的 SQLite 搜索包组合使用。 +- 在移入 `implemented/` 之前,本 RFC 须修订为实际实现的分词器和公开 API。 + +## 风险 + +单一所有者比提供方无关的 seam 更简单,但初期可复用性较低。这是有意为之:第二个真实后端能揭示应当抽取什么。SQLite 运行时差异可能影响 FTS 排序和摘要片段,因此测试只能固定契约控制的排序和呈现。独立数据库增加了配置和生命周期工作,但保全了规范存储的安全边界。 diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml new file mode 100644 index 0000000000..6b40707fbf --- /dev/null +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-13-stream-workflow-progress-through-tool-calls.md: 525f2793052a80d82de29d2d370cfd747d002af6 +2026-07-13-stream-workflow-progress-through-tool-calls.zh.md: b5cc86df3ca42e513bda7e56b485a8287f275613 diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md index 200ed50b1e..525f279305 100644 --- a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md @@ -1,5 +1,7 @@ # RFC: Stream workflow progress through tool calls +English | [中文](2026-07-13-stream-workflow-progress-through-tool-calls.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md new file mode 100644 index 0000000000..b5cc86df3c --- /dev/null +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md @@ -0,0 +1,43 @@ +# RFC:通过工具调用流式传输工作流进度 + +[English](2026-07-13-stream-workflow-progress-through-tool-calls.md) | 中文 + +Status: proposed + +## 问题 + +工作流引擎有意为 run、phase、narration 和子 agent 进度发出成对平衡的 `workflow/*` 观察事件,但目前没有生产消费方呈现它们。因此编辑器在最终结果到来之前只显示一张 pending 状态的工作流工具卡片,尽管引擎已经报告了当前活跃的 phase、脚本日志内容以及哪些子 agent 已启动或已完成。[dynamic-workflows 决策](../../implemented/feature/2026-07-05-dynamic-workflows.md)明确将 ACP 进度 UI 保留给这条事件流。 + +如果让 `dsh-acp` 直接监听工作流事件,会反转能力边界:通用的 UI 桥接层将依赖一个可选的工作流包(package),并对一个工具名做特殊处理。工具流水线已经拥有实时更新所需的路由信息(agent 和 call id),但只暴露了纯粹的 pending/final 展示器,因此长时间运行的工具没有提供方无关的方式在二者之间报告瞬态 UI 状态。 + +## 提案 + +为 `dsh-tools` 添加一条实时进度通道。注册表持有的 `ToolExecution` 新增 `reportProgress(view): boolean`,其中 `view` 是一个独立的、提供方无关的通用进度快照,包含可选的替换标题和面向 UI 的内容块。进度不能改变调用的 args 派生卡片标签、kind、原始输入、locations、terminal intent 或 diff intent;它只更新初始选定的展示形式中的实时标题/内容。执行活跃期间,该方法校验并快照 view,然后派发一个受限的、agent 作用域的 `tools/progress` 观察事件,携带权威的执行标识与快照。一旦 final-result 处理开始,方法返回 `false` 且不再派发,确保迟到的异步报告者无法覆盖终态卡片。观察者异常被记录但不会导致工具失败。 + +`dsh-acp` 以通用方式消费 `tools/progress`。它通过现有的 agent-to-session 映射解析执行所属的 agent,并为同一 call id 发出一条 in-progress 的 `tool_call_update`。由于报告仅在工具执行流水线内部可用,持久化的 `tool/call` 及其 ACP `tool_call` 始终先于第一条 update;在 `tools/result` 之前关闭报告者确保没有进度更新出现在 completed/failed 卡片之后。进度是实时 UI 状态而非模型输入或持久历史:会话回放继续从 `tool/call` 和 `tool/result` 重建 pending 与 final 卡片,无需重放瞬态更新。 + +`dsh-tool-workflow` 成为第一个生产者。每次工具执行在调用 `ctx.workflows.start()` 之前安装一个紧凑的事件捕获器,因为合法的引擎可能在 `start()` 内部同步发出进度。在调用返回之前,捕获器将观察到的事件按 `WorkflowRunInfo.id` 归约为候选状态;随后选取返回的 `WorkflowRun.id`、丢弃其他候选、报告累积的快照,并将后续匹配事件直接路由。如果 `start()` 抛出异常,捕获器被 dispose,其候选被丢弃。这在不向 `WorkflowStartRequest` 添加观察者关联、也不要求进度等到 `start()` 返回的前提下,保持了引擎的可替换性。 + +归约器消费现有的 start、phase、log、agent-start、agent-end 和 end 事件,报告一个替换快照,包含当前 phase、最新日志行、活跃子 agent 标签,以及 completed/failed/cancelled 计数。它不累积 narration transcript;已完成的子 agent 离开活跃集合、转为计数。`workflow/end`、工具结算或插件 dispose 移除归约器条目和事件捕获器。六种工作流事件、它们的元数据、成对的子 agent 生命周期、run handle、取消通道和观察者隔离保持不变;第三方观察者可继续直接消费它们。 + +更新工具执行/展示文档、生成的事件与 API 目录、工作流包文档以及工作流数据结构目录。ACP 集成覆盖率必须使用脚本化的模型边界对真实的工作流工具和 worker seam 进行测试;主 ACP 快照套件新增一个 workflow-progress 场景,因为此变更改变了面向编辑器的 transcript。 + +## 曾考虑的替代方案 + +**删除工作流观察面。** 在 [collapse-workflow 简化提案](../../rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md)中被否决:这些事件及其平衡的生命周期是有意设计的,缺失的部分是消费方。 + +**让 ACP 直接了解工作流。** 这可以将 `WorkflowRunInfo` 映射到会话和卡片,但会使通用桥接层依赖一个可选能力,并绕过「工具拥有展示意图」的规则。工具进度通道为所有长时间运行的工具解决了同样的路由问题。 + +**将每次进度更新持久化为会话事件。** 这会使实时 narration 可回放,但会用一种权威持久结果已由 tool call/result 对表达的状态永久膨胀日志。如果可恢复的工作流进度成为产品需求,它需要一个工作流日志化设计,而非伪装成持久事实的 UI 快照。 + +## 验收标准 + +- `ToolExecution.reportProgress()` 由注册表持有、agent 作用域、快照化、观察者隔离,且在终态处理开始后返回 `false` 而不派发。 +- ACP 将进度路由到正确实时会话中的正确调用;不同会话中的并发工作流不能串扰,且 `tool_call_update` 不会出现在其 `tool_call` 之前或终态更新之后。 +- 工作流进度显示当前 phase、最新日志行、活跃子 agent 和结果计数,同时保持所有现有 `workflow/*` 事件和 run 语义;一个在 `start()` 内部同步发出 start、phase、log、child 和 end 事件的 seam 测试引擎不会丢失任何归约器状态。 +- 取消、worker 死亡、工具失败、会话关闭和插件 dispose 释放归约器状态;回放仅发出持久的 pending/final 卡片对。 +- 单元测试、工作流集成测试、ACP 集成测试、快照、类型检查、覆盖率、doc-sync、module-graph、构建和 hygiene 门禁全部通过。 + +## 风险 + +此变更向工具 seam 添加了一个公开的实时进度方法和事件,因此实现方必须精确维护 active/terminal 边界,并在观察者看到快照之前将其分离。pre-start 捕获器可能短暂观察到无关的工作流 run,因此它仅按 run id 持有紧凑的候选状态,并在 `start()` 返回后立即丢弃所有不匹配的候选。一个工作流可能发出大量进度变更;有界归约器避免了 transcript 增长,但在关联之后仍会为每个有意义的事件发送一次 UI 更新。如果实测客户端需要合并更新,必须通过带默认值的、经过校验的桥接配置实现,而非硬编码的节流。瞬态进度在回放时有意消失,因此最终的工具结果仍是唯一持久的工作流卡片内容。 diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml new file mode 100644 index 0000000000..26c31b7471 --- /dev/null +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-api-extractor-reports.md: 0f3f736ba662fd6366eb8d7f26887fb319b2b563 +2026-06-11-api-extractor-reports.zh.md: 3c472d64bc96c7fffa784c091f8a7a70bb0beb56 diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md index a6f3bfb14c..0f3f736ba6 100644 --- a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md @@ -1,5 +1,7 @@ # RFC: API extractor reports +English | [中文](2026-06-11-api-extractor-reports.zh.md) + Status: proposed > Split out from the original "Doc-sync and API reports" RFC (2026-06-11). Parts 1-2 (doc-block typechecking, event-taxonomy verification) shipped — see [doc-sync enforcement](../../implemented/process/2026-06-11-doc-sync-enforcement.md). This is the deferred part 3, kept as a standalone proposal. diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md new file mode 100644 index 0000000000..3c472d64bc --- /dev/null +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md @@ -0,0 +1,32 @@ +# RFC:API extractor 报告 + +[English](2026-06-11-api-extractor-reports.md) | 中文 + +Status: proposed + +> 从最初的「Doc-sync 与 API 报告」RFC(2026-06-11)中拆出。第 1、2 部分(文档块类型检查、事件分类体系校验)已交付——见 [doc-sync 强制](../../implemented/process/2026-06-11-doc-sync-enforcement.md)。本文是被推迟的第 3 部分,作为独立提案保留。 + +## 问题 + +公开 API 的变更是不可见的:没有任何机制让「这个 commit 改变了公开接口」成为一个显式、可评审的事实。评审者阅读 diff 时可能遗漏一个导出类型新增了字段或方法签名发生了变化。 + +## 提案 + +使用 api-extractor(或 `tsc --emitDeclarationOnly` 加一份归一化的公开接口导出)为每个包(package)生成一份签入仓库的 `etc/<pkg>.api.md`;如果重新生成的结果与签入版本不同,CI 失败。这样每一次公开 API 变更都会变成评审者(或评审 agent)必须看到的一行 diff。 + +## 曾考虑的替代方案 + +**`tsc --emitDeclarationOnly` 加一份归一化的公开接口导出**:如果 api-extractor 被证明过重,这是更轻量的机制;两者都满足本提案所需的「签入仓库、可 diff」的报告形态。 + +## 验收标准 + +- 每个包有一份签入仓库的 `etc/<pkg>.api.md`;重新生成结果与已提交报告不同时 CI 失败。 +- 公开 API 变更(新增导出、字段放宽、签名变化)在评审中以报告 diff 行的形式可见。 + +## 风险 + +该依赖重且难伺候——这正是它被推迟的原因——且报告格式会随编译器升级而变动,在各包尚未发布的阶段增加了一个收益甚微的维护面。 + +## 推迟原因 + +在 doc-sync 落地时被推迟:对于评审者已经能看到源码 diff 的内部 monorepo 而言价值有限,且依赖重、难伺候。如果这些包将来对外发布,届时一份稳定、可 diff 的公开接口报告才值得其维护成本。 diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml new file mode 100644 index 0000000000..8aa3f297cd --- /dev/null +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-architectural-conformance.md: 40858d049af2df1928e27280238d0b198a5202f7 +2026-06-11-architectural-conformance.zh.md: d61751210ef78b26e05a05efae4d5abccbfd2e5c diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md index e0d16b455d..40858d049a 100644 --- a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md @@ -1,5 +1,7 @@ # RFC: Architectural conformance — dependency rules and the adapter kit +English | [中文](2026-06-11-architectural-conformance.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md new file mode 100644 index 0000000000..d61751210e --- /dev/null +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md @@ -0,0 +1,36 @@ +# RFC:架构一致性——依赖规则与适配器套件 + +[English](2026-06-11-architectural-conformance.md) | 中文 + +Status: proposed + +## 问题 + +两项架构保证目前仅存在于行文中:(1)任何包不得依赖具体的 loop 包([微内核承诺](../../implemented/architecture/2026-06-11-microkernel-event-taxonomy.md));(2)每个 LlmAdapter 都正确地遵循 chunk 协议。两者都应当机械化([质量门禁原则](../../implemented/process/2026-06-11-quality-gates.md))。 + +## 提案 + +**dependency-cruiser** 配合以下规则: + +- `packages/*`(agent-loop 自身的测试和 examples/ 除外)禁止导入 `@deepseek-ai/dsh-agent-loop`。 +- 禁止跨包深层导入(`@deepseek-ai/dsh-*/src/...` 路径)——只允许使用公开入口点。 +- packages/ 内禁止任何导入循环。 +- `vendor/*` 禁止从 `packages/*` 导入。 +- 分层:dsh-llm 不导入其他 dsh 包;dsh-session 只导入 dsh-llm;以此类推(即 packages/README.md 中的依赖表,强制执行)。 + +**适配器一致性套件**位于 dsh-llm(`@deepseek-ai/dsh-llm/conformance`):一个可复用的 vitest 套件,以适配器工厂为参数,断言 chunk 协议契约——每个 block 的 index 单调递增、`block-end` 之后该 index 不再有 delta、恰好一个 `finish`、usage 至多出现一次、每个 `tool-call-delta` 携带 call id、abort 被及时响应。当前对 mock 运行;DeepSeek V4 适配器从第一天起继承该套件。可选地提供一个 dev 模式的 `strictAdapter()` 包装层,在 debug flag 下于运行时强制执行相同约束(与 [dev 模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)配对)。 + +## 计划 + +先落地 dependency-cruiser 配置与 CI 步骤(约一小时工作量,永久保证);一致性套件随其首个消费方测试(针对 MockAdapter)一起落地,并作为 V4 适配器阶段的前置条件。 + +## 验收标准 + +- dependency-cruiser 在 CI 中运行上述规则族;违规导入导致构建失败。 +- 一致性套件对 mock 适配器和两个正式适配器运行通过;新适配器包通过调用该套件并传入自己的工厂即可继承测试。 + +## 风险 + +随着包的增加需要维护 dep-cruiser 规则——应保持规则基于模式(`dsh-*`)而非逐一枚举。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml new file mode 100644 index 0000000000..5ac9f62fee --- /dev/null +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-supply-chain-and-vendor-drift.md: 306e185e9175e3e7af24455cf95167f54b3d1c17 +2026-06-11-supply-chain-and-vendor-drift.zh.md: 1aeb0a8eff3f335bc87c05742acc4502a19bf3c5 diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md index e787133026..306e185e91 100644 --- a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md @@ -1,5 +1,7 @@ # RFC: Supply chain checks and vendor drift verification +English | [中文](2026-06-11-supply-chain-and-vendor-drift.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md new file mode 100644 index 0000000000..1aeb0a8eff --- /dev/null +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md @@ -0,0 +1,35 @@ +# RFC:供应链检查与 vendor 漂移校验 + +[English](2026-06-11-supply-chain-and-vendor-drift.md) | 中文 + +Status: proposed + +## 问题 + +vendor manifest([vendor 化决策](../../implemented/process/2026-06-11-vendor-cordis-as-source.md))在提交时只做*正向*强制(vendor 代码变更 ⇒ manifest 更新),但没有任何机制校验 manifest 的*声明*:即 vendor/ 确实等于「上游指定 SHA 的代码 + 日志中记录的修改」。此外,少量真正的 npm 依赖也没有安全公告监控或更新节奏。 + +## 提案 + +1. **Vendor 漂移检查**(夜间 CI):以 manifest 中的 SHA 浅克隆上游仓库,复制对应 package 的源码,与 `vendor/*/src` 做 diff。除非 diff 与日志中的本地修改一致(每项修改保存为一个入库的 patch 文件,使日志条目成为可校验的产物而非纯文字),否则 job 失败。 +2. **依赖安全公告**:对 lockfile 运行 osv-scanner(或 `pnpm audit`),按计划调度 + 在涉及 lockfile 的 PR 上触发。 +3. **许可证清单**:一个脚本断言每个 vendor 化的 package 都携带 LICENSE 文件,且 package.json 的 `license` 字段与 vendor/README.md 中的清单一致(我们混合了 vendor 化的 MIT 与自有的 BSD-3)。作为 CI 步骤运行。 +4. **Renovate**(或一个定时 agent 任务)以小 PR 提议 npm 依赖更新,这些 PR 走完整门禁套件;vendor 化的 package 排除在外(它们的更新遵循 manifest 同步流程,理想情况下作为半自动化的 agent 工作流:拉取上游、重新应用 patch、运行门禁、打开 PR 并更新 manifest 表格)。 + +## 计划 + +3 最简单,先做。1 需要 CI 能通过网络访问上游仓库(私有镜像,需要 token),并将现有两项已记录的修改转为 patch 文件。2 和 4 属于配置工作。 + +## 曾考虑的替代方案 + +- **用 `pnpm audit` 代替 osv-scanner**:两者都满足安全公告扫描的需求;具体选择推迟到实现阶段决定。 +- **用定时 agent 任务代替 Renovate**:在「以小 PR 提议更新并走完整门禁」这件事上效果等价;vendor 化的 package 无论哪种方案都排除在外(它们的更新遵循 manifest 同步流程)。 + +## 验收标准 + +- 许可证清单脚本在 CI 中运行,缺少 LICENSE 或 `license` 字段与 `vendor/README.md` 清单矛盾时失败。 +- 夜间漂移 job 从 manifest SHA 加入库 patch 文件重建 `vendor/`,出现任何无法解释的 diff 时失败。 +- 安全公告扫描按计划对 lockfile 运行,并在涉及 lockfile 的 PR 上运行。 + +## 风险 + +上游仓库是私有镜像;CI 凭证与可用性是漂移检查的主要阻力。如果受阻,改为本地定时 agent 任务而非 CI 运行。 diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml new file mode 100644 index 0000000000..f08e3c5dff --- /dev/null +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-discover-package-inventory.md: 22b3e9acbe4dad8ef829d0dd30415c516031d66b +2026-06-20-discover-package-inventory.zh.md: 8b62d42d2d514f60016690ba55d5ce77a50b3aff diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md index c4ee6161bd..22b3e9acbe 100644 --- a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md @@ -1,5 +1,7 @@ # RFC: Discover package inventories instead of maintaining static lists +English | [中文](2026-06-20-discover-package-inventory.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md new file mode 100644 index 0000000000..8b62d42d2d --- /dev/null +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md @@ -0,0 +1,36 @@ +# RFC:通过发现机制获取包清单,取代静态列表维护 + +[English](2026-06-20-discover-package-inventory.md) | 中文 + +Status: proposed + +## 问题 + +包(package)与门禁的清单在 TypeScript project references、package 文档、CI 行文、Knip 覆盖项以及快照场景元数据中反复出现。其中大部分只是重述包布局、manifest 数据、聚合命令内容或 fixture(测试前置数据)文件。每新增一个包或场景,都会产生本可避免的同步点。 + +[包层级结构](../../implemented/architecture/2026-06-20-package-hierarchy.md)已经手动消除了其中若干:`scripts/publint-all.ts` 现在从 `packages/<group>/<pkg>` 布局推导清单,两份 `tsconfig` 的 `paths` 映射也合并为一个 `@deepseek-ai/dsh-*` 通配符。剩下的是无法用 glob 消除的清单——主要是 `tsconfig.build.json` 的 project `references`,TypeScript 要求它是一个显式数组(没有通配符形式)。 + +静态列表在编码策略时是合理的;当它们只是重复 `package.json`、workspace glob 或包层级结构中已有的 manifest 数据或布局事实时,就是无谓的摩擦。 + +## 提案 + +让剩余的包/门禁清单可被发现。一个唯一的权威来源——`packages/<group>/<pkg>` 层级结构加上 package manifest——应当驱动 `tsconfig.build.json` 的 `references`、模块图以及任何全量包列表,并配合一个生成加校验步骤(沿用现有的 `gen-module-graph` / `gen-cordis-catalog` 模式:生成器写入产物,`--check` 模式在 `hygiene`/`doc-sync` 中检测已提交副本是否陈旧)。模块图生成器已经在读取 package manifest。`doc-sync` 应当成为定义并打印其子门禁的唯一命令,文档链接到该命令而非重述第二份清单。 + +层级结构不需要编码一个包的所有信息,但应当编码宽泛的维护策略:core/product 包、集成包、能力 seam 包与 support/test/example 包不应在脚本能区分它们之前先要求一份手工维护的例外清单。 + +有两项被编目的内容根本不需要生成器:把 e2e 入口 glob 折入 knip 的默认 stanza 即可直接删除各包的重述;`childSessions` 可以从每个场景的 fixture 目录发现,让场景表只声明策略(`recorded`、`hasModelTurn`、`comparesLog`)。而即便这些策略字段,今天也在追踪可从 fixture 推导的事实(`comparesLog` ⟺ 已提交的日志在表头行之后有内容;`recorded` ⟺ `hasModelTurn` 且没有 `replay.override.json` 兄弟文件),因此每个新场景类别都在不断添加 fixture 目录已经能回答的开关。 + +## 验收标准 + +- `tsconfig.build.json` 的 project `references` 由层级结构生成(生成器输出它们;`--check` 门禁在已提交副本陈旧时失败),而非手工维护。 +- 新增一个包不需要为任何门禁编辑静态包列表。 +- 文档描述真源,而非重复生成的清单。 +- CI 调用聚合命令,由这些命令自行管理其子门禁列表。 +- `knip.json` 仅在编码真实信息(额外入口文件、被忽略的依赖)时才携带 per-package 覆盖项,绝不重述默认 stanza。 +- 快照场景只声明策略,不声明可从其 fixture 目录发现的事实。 + +## 风险 + +发现脚本可能变得过于精巧。实现应保持朴素:读取 manifest、按显式字段过滤、打印解析后的列表、出错时大声报错。收益在于消除手工清单漂移,而非发明一套构建系统。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml new file mode 100644 index 0000000000..db8dc2d650 --- /dev/null +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-unify-agent-and-session-id.md: 3a6daa411673003eb1c3017e7a717ae4bf98b735 +2026-06-20-unify-agent-and-session-id.zh.md: c931831c028e3147bfb84ed4fdeefe83037e92f4 diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md index d94ce11f5c..3a6daa4116 100644 --- a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md @@ -1,5 +1,7 @@ # RFC: Unify the agent id and the session id +English | [中文](2026-06-20-unify-agent-and-session-id.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md new file mode 100644 index 0000000000..c931831c02 --- /dev/null +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md @@ -0,0 +1,42 @@ +# RFC:统一 agent id 与 session id + +[English](2026-06-20-unify-agent-and-session-id.md) | 中文 + +Status: proposed + +## 问题 + +agent 工厂为每个活跃的 agent/会话对维护两个 id:`agentId`(`AgentRegistry` 的路由句柄)和 `sessionId`(事件溯源与持久化日志的身份标识)。`CreateAgentOptions` 接收两者;`ResumeAgentOptions` 接收 `agentId` 加 `resumeSessionId`;进程内 subagent 铸造两个独立的 UUID,尽管血缘关系另行记录。 + +ACP(Agent Client Protocol)已经对两个身份使用同一个值。二者在配置创建的 agent、恢复的会话和进程内子 agent 中才出现分歧,但没有任何生产路径会将一个活跃 agent 重新关联到多个会话,或让一个会话经过多个 agent id。Stdio 保留 `labelBySession` 仅仅是为了从会话事件中恢复 agent 标签,而钩子同时暴露两个值让使用者自行对齐。 + +[agent 作用域运行时](../../implemented/architecture/2026-07-12-agent-scope-runtime-design.md)没有与身份相关的预留状态:创建和恢复使用同一个 `AgentCreationTransaction`,两个注册表条目使用相同的 final-entry 碰撞规则。分离的 id 并未复制活跃性、回滚或静默机制。统一后删除一个调用方提供的 id、每个进程内子 agent 的一个 UUID 以及剩余的翻译路径,而不改变事务生命周期;同时使活跃 agent 注册表强制执行后台任务所有权所使用的会话身份。 + +`Session` 另外同时暴露 `Session.id` 和 `Session.header.id`,尽管构造时要求二者一致。持久化边界必须校验这一重复值,消费方必须在同一事实的两个归属位置之间做选择。 + +## 提案 + +对 agent 注册表条目和 `session.header.id` 使用同一个 id。`CreateAgentOptions` 为两个最终条目接受一个身份标识;恢复操作以被恢复的 session id 注册 agent;subagent 创建铸造一个合并后的 id;`Session` 只保留一个身份归属位置。保留当前的事务、final-entry 碰撞检查、exact-entry 摘除、回滚与静默机制;仅移除唯一职责是在两个 id 之间做翻译的 map 和字段。 + +配置驱动的路径必须先确定其恢复还是创建的策略。目前它使用一个稳定的 agent 标签加一个带 UUID 后缀的新 session id,以避免在下次运行时与已有的持久化日志碰撞。统一后它必须明确选择:恢复一个固定 id、铸造一个新的合并 id,或将该策略暴露出来;实现不得默默做出选择。 + +`agent/created` 和 `agent/disposed` 不在本提案范围内。它们是发布生命周期事件而非身份别名;移除它们需要单独的生产方-消费方审计与决策。 + +## 曾考虑的替代方案 + +**保留分离的路由身份与日志身份。** 一个稳定的配置 agent 标签搭配一个新的对话,是这种区分的真实用途。如果确实需要该显示或路由身份,则应否决本提案,转而显式强制 session id 唯一性,而不是将翻译隐藏在另一个 map 中。 + +## 验收标准 + +- agent 创建/恢复与 subagent 创建只携带一个身份标识;`Session` 将其存储在一个位置。 +- 创建事务保留 final-entry 碰撞、exact-entry 摘除、回滚与静默保证,且不依赖与身份相关的生命周期状态。 +- ACP、stdio、钩子、bash 所有权、持久化与血缘关系无需 agent/session id 翻译。 +- 配置驱动的恢复还是创建策略是显式的,并在持久化重启场景中得到覆盖。 +- `agent/created` 和 `agent/disposed` 仅在单独的生产方-消费方审计之后才变更。 +- 类型检查、覆盖率、快照、doc-sync、module-graph 校验、构建与 hygiene 全部通过。 + +## 风险 + +统一后将无法再拥有一个跨多个会话日志的稳定 actor 身份,包括未来可能的交接或 fork(保留 actor 但更换会话)。重新引入该设计需要一个新的显式 actor 身份。统一还使一个持久化的、可能由客户端选择的 session id 成为注册表句柄,并改变每个创建/恢复调用点和 fixture(测试前置数据)。 + +配置重启策略是阻塞性的设计决策:固定的合并 id 可能与其已有日志碰撞,而每次运行生成新 id 则放弃了稳定的配置标签。如果确实需要独立的 actor 身份或稳定标签/新会话的配对,则应否决本提案,保留分离的 id 并加上显式的唯一性守卫。 diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml new file mode 100644 index 0000000000..1d5522f5b3 --- /dev/null +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-prune-dead-core-spine-surface.md: c46fe464e8627dcfc39a1d3fbb38a9cbd84269cf +2026-07-04-prune-dead-core-spine-surface.zh.md: 86830904ef0d1262d4cc132fb8d4b6a50e033e1d diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md index cca7c57b34..c46fe464e8 100644 --- a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md @@ -1,5 +1,7 @@ # RFC: Prune dead public and result surface +English | [中文](2026-07-04-prune-dead-core-spine-surface.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md new file mode 100644 index 0000000000..86830904ef --- /dev/null +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md @@ -0,0 +1,62 @@ +# RFC:裁剪无用的公开接口与结果面 + +Status: proposed + +[English](2026-07-04-prune-dead-core-spine-surface.md) | 中文 + +## 问题 + +若干包根导出、结果字段和便利方法没有生产消费方。它们之所以存活,要么是因为测试通过公开入口导入内部实现,要么是因为某个类型预设了一个从未出现的调用者。每一项单独看都很小,但合在一起,它们扩大了 SDK 契约、生成的目录、文档和回归矩阵,却没有支撑任何已交付的路径。 + +生产语料库是 `packages/*/*/src`、示例源码/配置和运行时脚本。测试、package README 和 RFC 行文是发布的证据,但不是固定的调用者。`cordis_inspect` 使 `packages/cordis/tool-cordis/src/api-catalog.ts` 对模型可见,`cordis_mount` 可以通过受保护的真实服务代理调用注入的服务,因此被编目的服务方法和返回形状是真正的动态产品面。下表因此区分了「没有固定的仓库内调用者」与「不可达」:涉及编目词汇的行有意收缩模型编写的 mount 所能发现和调用的内容,而包根的实现辅助函数并不通过该服务门面可达。精确符号搜索得出以下清单: + +| 接口面 | 生产证据 | 简化方式 | +| --- | --- | --- | +| `SurfaceManager.invalidate()` | 仅其单元测试调用;seeding 在惰性创建的 manager 存在之前就已完成,且会话从不替换其日志引用。 | 删除该方法及其不可能触发的整体替换契约。 | +| `ToolExecutionResult.callId` | 每个钩子已经接收不可变的 `ToolExecution`;循环和 ACP(Agent Client Protocol)通过 call/session 事件关联。没有消费方读取这个重复的结果字段。 | 移除该字段、复制/不匹配守卫,以及证明该重复不会不一致的测试。 | +| `ReactLoopAgent` 根导出 | 包外的具名导入都是测试;生产代码面向 `Agent` 编程,通过 `ctx.agents` 创建/恢复。 | 返回/接口类型为 `Agent`,将具体循环类设为包内部;保留有意为之的同步纯配置 `AgentLoop.create()` 路径。 | +| `workflow-workerthread` 的 protocol/runtime/session 再导出与具名 `WorkerWorkflowEngine` | 所有包名消费方使用默认引擎;workflow RFC 已将 worker 协议格式定义为私有。 | 保留默认插件类/配置契约;移除重复的具名类导出,将协议模块设为源码私有。 | +| `code-runtime-worker` 的 protocol/bootstrap 再导出 | 包外的生产/e2e 消费方使用 `WorkerCodeRuntime` 和配置,而非 `BootstrapPort`、`PatchableStream` 或 worker 消息/启动类型。 | 保留运行时类/配置契约,将其协议格式/bootstrap 词汇设为源码私有。 | +| ACP 的 translation/presenter 根导出 | `agentOptions`、`streamSessionEventUpdate`、`todosToPlan`、`ToolPresenter`、`nullToolPresenter` 和 `TerminalRendering` 仅有同文件或 ACP 测试消费方;唯一的包外生产消费方挂载的是插件命名空间。 | 保留 `name`、`inject`、`Config`、`AcpConfig` 和 `apply`;将 translation/presentation 辅助函数设为源码私有,在包内测试。 | +| `providerWording` 和 `completedTurnPrefix` 根导出 | 各有一个同包生产调用者;仅 balanced-prefix 辅助函数有一个同包白盒测试。 | 设为源码私有,通过 provider 行为测试。 | +| `depthOf`、`SubagentDepthError`、`SENSITIVE_ENV_PATTERN`、`waitForExit` 和 `exitsWithin` 根导出 | 生产 subagent 后端消费的是进程内 runner 和子进程构造/释放辅助函数,而非这些强制/测试内部实现。 | 保留深度/环境/退出行为,但将辅助函数和 error/regex 设为源码私有;通过 spawn 和释放来测试。 | +| `PersistenceCoordinator.inits`、后端 `inits` 访问器、`seedCoversPrefix` 和 `assertSerializable` | 访问器为白盒测试而存在;`seedCoversPrefix` 没有包外生产导入者;`assertSerializable` 没有生产调用者,且与 coordinator append 边界的无损快照重复。 | 通过 `session/flush` 观察初始化,将 `seedCoversPrefix` 设为源码私有,删除 `assertSerializable`。保留两个后端、`SessionHeader` 和 SQLite 的版本契约。 | +| `LlmError.status` 与 replay status | 适配器/replay 填充它,但生产分支基于稳定的 error code/message,从不读取原始 status。 | 移除未读字段和 replay 管道,同时保留错误分类。 | +| `BlockAssembler.push()` 返回值 | 两个生产调用者都忽略返回的已完成块。 | 返回 `void`;保留有意公开的 `blocks()`/`message()` 契约。 | +| `compactRegion` 的独立 `session` 参数 | 固定调用者传入的对象与 `agent.session` 已经是同一个;模型可见的 mount API 也能调用该方法,但接受两个身份允许挂载的插件提供不一致的配对。 | 保留手动区域 seam,同时有意将其收窄为以 `agent.session` 为唯一真源。 | +| `CompactionResult.startSeq`、`summarySeq`、`endSeq` 和 `summary` | 生产消费方只读取 shadowed range/seq/token 统计;持久日志拥有摘要和事件标识。 | 移除四个结果回显,同时保留两个共享的 transcript(文本记录)渲染器。 | +| `BasicCompactService` 的 estimation/summarization 可见性 | 没有包外生产调用者调用这五个方法;已实现的 RFC 仅将 `estimateContentTokens()` 和 `summarize()` 列为子类钩子。 | 将这两个方法设为 `protected`,将三个仅用于编排的估算器设为 private。 | +| `CodeLogEntry.source`/`level` 和 `RunCodeMeta.dispatches` | 所有生产消费方将日志映射为文本;没有 presenter/模型路径读取其他字段或持久化的 dispatch 计数。 | 将 code-runtime 日志改为字符串(或纯文本条目),移除 result-meta dispatch 管道;保留用于生成确定性 dispatch id 的本地计数器。 | +| `ToolNotFoundError.toolName`、`SystemPrompt.config` 和 `BashTask.command` | 每个存储的公开值都没有生产读取者。 | 移除未读字段,同时保留错误消息、已解析的配置行为和任务生命周期。 | +| 后端包根实现辅助函数 | 下方精确清单仅通过相对同包导入调用。生产命名空间导入挂载的是保留的插件契约,不读取这些属性;具名根消费方是测试。 | 保留每个适配器/提供方/服务及其配置/错误契约;停止在包根导出所列辅助函数/常量。 | +| 消费方包根实现辅助函数 | 下方精确清单仅有同包生产调用者。生产命名空间导入挂载插件契约,不读取辅助属性;具名根消费方是测试。 | 保留插件契约和稳定错误码;将测试移至包内模块或公开行为,停止在包根导出所列辅助函数。 | + +### 分组辅助导出清单 + +- `dsh-llm-deepseek`:`httpErrorCode`、`serializeMessages`、`serializeRequest`、`DONE`、`parseSse`、`mapFinishReason`、`mapUsage` 和 `translate`;`dsh-llm-pi-ai`:`buildModel`、`mapStopReason`、`mapUsage`、`toPiContext` 和 `toStreamChunks`。 +- `dsh-bash-local`:`DEFAULT_GRACE_MS`、`ENV_OVERRIDES`、`killGroup`、`OutputCollector` 和 `runBash`;`dsh-bash-sandbox`:`shellQuote`、`classifyDenial` 和 `classifyRunnerFailure`;`dsh-sandbox-local`:`bwrapProfileArgs`、`landlockProfileArgs` 和 `seatbeltProfileArgs`。公开的可变测试注入字段及其类型不在本提案范围内。 +- `dsh-fs-local`:`applyLiteralEdit`、`listDirectory`、`probe`、`readForEdit`、`readTextForDiff`、`readWholeText`、`resolveLocalTarget`、`restoreLineEndings`、`streamWholeText` 和 `writeFileAtomic`。 +- `dsh-web-fetch-local`:`classifyContentType`、`decoderForCharset`、`isSameOrigin`、`parseCharset` 和 `validateFetchUrl`;`dsh-web-search-exa`:`mapExaResponse` 和 `mapExaResult`;`dsh-web-search-deepseek`:`citationSnippets` 和 `mapAnthropicResponse`;`dsh-web-search-perplexity`:`mapPerplexityResponse` 和 `mapPerplexityResult`。 +- `dsh-tool-fs`:`READ_LIMIT`、`STREAM_MIN_SIZE`、`READ_MAX_BYTES`、`READ_MAX_LINE_LENGTH`、`DIFF_CONTEXT`、`applyReadTool`、`parseReadArgs`、`applyWriteTool`、`formatWriteOutput`、`parseWriteArgs`、`applyEditTool`、`formatEditOutput`、`parseEditArgs`、`buildWindow`、`formatReadOutput`、`computeHunkDiffs` 和 `diffsFromMeta`。 +- `dsh-tool-web`:`WEB_SEARCH_MAX_RESULTS`、`applyWebSearchTool`、`formatSearchOutput`、`parseSearchArgs`、`presentSearchCall`、`applyWebFetchTool`、`formatFetchOutput`、`parseFetchArgs`、`presentFetchCall`、`renderBody` 和 `htmlToMarkdown`;`dsh-timeout-policy`:`toolTimeoutResult`;`dsh-compact-basic`:`resolveConfig`;`dsh-tool-bash`:`renderResult`。 + +## 提案 + +以一次有界的、协调的公开接口面清理,移除或降级上述每一行。更新 package README、JSDoc、生成的 API/事件目录、type-equiv 记录、必要时的 exports map 以及测试,使测试通过所属的公开 seam 来验证行为,而非保留仅为测试而存在的入口点。不折叠任何能力 seam、LLM(大语言模型)适配器、持久化后端或生命周期静默契约。 + +## 曾考虑的替代方案 + +**保留测试便利函数和自包含结果字段为公开。** 公开辅助函数可以让白盒测试更方便,自包含的结果字段看起来更符合人体工学,未来的嵌入者可能需要具体循环类或枚举方法。这些好处是假设性的;今天它们让每一处实现和文档都要解释没有已交付调用者能观察到的状态。真正的消费方可以引入它所需的最小契约,其所有权和失败语义已知。 + +**为模型编写的 mount 保留所有编目成员。** 自引用工具集是一条真实的通用消费路径,而非生成文档的噪音。然而,它的价值来自准确、可组合的服务面,而非无限期保留重复字段或不一致的参数对;上述每一项编目收缩都移除了在同一次执行、agent(智能体)或结果上其他位置已可获得的事实,并在同一个变更中更新 API 参考。 + +## 验收标准 + +- 精确符号搜索显示被移除的接口面不出现在本 RFC 和任何已实现 RFC 修正案之外。 +- 本 RFC 列出的每一项接口面均已按指定方式移除或降级;清单之外有意保留的扩展/测试契约不受影响。 +- 工具执行、压缩(compaction)、两个 LLM 适配器、两个持久化后端、工作流隔离以及 agent 创建/恢复保持其已交付行为。 +- 类型检查、覆盖率、快照、doc-sync(文档同步门禁)、module-graph 校验、构建和 hygiene 全部通过。 + +## 风险 + +大多数移除在编译时可见但运行时无影响。压缩参数清理有意禁止 session/context 不匹配,同时保留手动区域 seam。外部预发布嵌入者和现有模型编写的 mount 可能导入更少的辅助函数、传入更少的参数或接收更窄的结果形状;这是有意的产品接口面收缩,而非仅仅是生成目录的清理。仓库尚未发布,因此承载不受支持的接口面才是更大的基础成本。 diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml new file mode 100644 index 0000000000..f7a882d65c --- /dev/null +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-12-simplify-session-log-representation.md: 52720231d6e4cbe0cbb412332cd016ba63f83569 +2026-07-12-simplify-session-log-representation.zh.md: 468f9a565177089c8d49c06e8d490ab56980054a diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md index 715ce93924..52720231d6 100644 --- a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md @@ -1,5 +1,7 @@ # RFC: Simplify session-log representation +English | [中文](2026-07-12-simplify-session-log-representation.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md new file mode 100644 index 0000000000..468f9a5651 --- /dev/null +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md @@ -0,0 +1,38 @@ +# RFC:简化会话日志表示 + +[English](2026-07-12-simplify-session-log-representation.md) | 中文 + +Status: proposed + +## 问题 + +会话日志维护着两种表示,其机制开销超出了消费方的实际需求:伪链表 surface 与自定义请求头增量编码。 + +`SurfaceManager` 将同一顺序存储在数组、seq 映射和可变的 `prev`/`next` 链接三处。生产代码从不读取 `prev`;压缩(compaction)唯一一次读取 `next` 是取数组位置的后继。替换操作已经使用 `indexOf`,因此链接并未使其主要操作达到常数时间。一个 seq 数组加线性替换查找具有相同的渐近替换开销,且只有一种表示需要校验。 + +请求头子系统实现了自定义的 system/tool 增量编解码器与传输决策层,尽管其契约声明增量只是编码优化而非可重建性要求。在每个 agent loop 实例边界保留 initial/resume 完整快照,然后在该实例的组装头发生变化时写入一条规范的完整 `request/header`,即可保留回放能力,同时删除 `SystemDelta`、`ToolsDelta`、往返 fallback 以及持久化的 `request/header-delta` 变体。编解码器专用词汇随编解码器一起消失,并非因为其各分支本身无效。 + +本提案有意保留 append 与 replacement 的 `sourceEventSeqs`、崩溃恢复溯源,以及所有 `SessionStartSource` 变体:已实施的 RFC 赋予了这些字段审计/拦截角色,零当前读者不足以推翻这一点。 + +## 提案 + +将 `SurfaceManager.nodes` 改为事件序列号的 `readonly number[]`,移除公开的 `SurfaceNode` 形状。保留内部的 replace-generation 信号;更新工具配对平衡与压缩调用方,使其通过数组值/索引获取前驱、后继与替换范围,移除节点链接与 seq-to-node 映射。将锚点后的请求头增量替换为规范的完整变更头快照,移除增量编解码器/事件/测试;initial 与 resume 锚点即使折叠后的头未变也仍为完整快照。 + +修订会话 surface 与可重建请求的 RFC 中描述已移除编码的部分。更新事件类型/不变式、请求日志/回放、持久化 fixture(测试前置数据)、生成的 catalog、包文档与快照。将编解码器专用的 `fallback` 原因替换为显式的 `change` 原因(用于锚点后的完整快照),以区别于保留的 `initial` 与 `resume` 锚点。 + +`SESSION_FORMAT_VERSION` 有意保持为 `0`,因此包含 `request/header-delta` 的旧 v0 日志在增量折叠被删除后,若不做处理将通过版本检查并静默丢失头变更。seed/load 校验必须在格式边界处拒绝该遗留事件并快速失败;不添加兼容折叠或迁移。 + +## 曾考虑的替代方案 + +**保留链表节点与紧凑增量以备未来规模。** 链接可能有助于未来的游标 API,增量在大型工具 schema 仅有少量变化时能减小日志体积。但没有已发布的游标使用这些链接,而完整快照以磁盘空间换取显著更简单的正确性。如果头部体积确实成为问题,可以基于真实 trace 设计压缩方案或经过度量的规范增量方案。 + +## 验收标准 + +- `SurfaceManager.nodes` 是一个有序 seq 数组,没有 `SurfaceNode`、链接字段或 seq-to-node 映射;增量追加处理与内部 replace-generation 信号保留。 +- 回放完整变更头快照能重建出完全相同的请求;不再存在任何 header-delta 事件/类型/编解码器。 +- 包含遗留 `request/header-delta` 的 v0 seed 或持久化日志在回放前被拒绝,JSONL 与 SQLite 加载路径均有覆盖。 +- 新形状的 v0 JSONL/SQLite 回放、溯源、崩溃恢复、压缩、快照、不变式、类型检查、覆盖率、doc-sync、构建与 hygiene 全部通过。 + +## 风险 + +完整头会增加日志体积,线性替换查找在非常大的 surface 上可能更慢。替换操作目前已经是线性的,因为实现调用了 `indexOf`;只有在真实 trace 表明更简单的数组成为瓶颈时才应添加基准测试。由于格式版本保持为 `0`,如果遗漏了对遗留事件的显式拒绝,后果将是静默数据损坏而非类型错误;因此快速失败的加载测试是本提案的组成部分,而非可选的清理工作。 diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml new file mode 100644 index 0000000000..3e3afa30d0 --- /dev/null +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-deterministic-and-stress-testing.md: e4ed7043d1880b55dd7d77b3e09a81dd58739a70 +2026-06-11-deterministic-and-stress-testing.zh.md: d933c1dda329b95573b7a5a3fbe3a61ef94390cb diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md index 2a30969ba4..e4ed7043d1 100644 --- a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md @@ -1,5 +1,7 @@ # RFC: Deterministic tests, the replay invariant fixture, and race stress +English | [中文](2026-06-11-deterministic-and-stress-testing.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md new file mode 100644 index 0000000000..d933c1dda3 --- /dev/null +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md @@ -0,0 +1,33 @@ +# RFC:确定性测试、回放不变式 fixture 与竞态压力测试 + +[English](2026-06-11-deterministic-and-stress-testing.md) | 中文 + +Status: proposed + +## 问题 + +若干 agent loop(智能体循环)测试通过 `setTimeout(30)` 睡眠来同步——这是一笔不稳定性债务,浪费 agent 重试周期,还可能掩盖排序 bug。另一方面,我们的核心架构承诺(任何会话日志回放后都能得到完全相同的派生历史)目前只在两个测试中断言,但在*所有地方*断言的成本很低。此外,inbox 唤醒竞态只被手动验证过一次,没有任何东西持续地重新验证它。 + +## 提案 + +三项措施: + +1. **测试中禁止挂钟睡眠。** 将 `setTimeout(N)` 等待替换为事件驱动等待(现有的 `waitForIdle` 模式,扩展为 `waitForStatus`、`waitForEvent(n)`),或在需要测试时间本身时使用 vitest fake timers。通过 lint 规则强制:禁止在 `packages/*/tests` 中使用 `setTimeout`,白名单辅助模块除外。 +2. **通用回放 fixture(测试前置数据)。** 一个共享的测试辅助函数包装 agent loop harness,使得每个测试结束后,agent 的会话日志被回放到一个全新的 Session 中,并自动断言 `deriveMessages()` 相等。这样该不变式在每次 CI 运行中会被检查数百次(覆盖套件产生的所有场景),而非仅两次。 +3. **夜间竞态压力测试。** 一个 CI job 以 `vitest --repeat=200`(加 `--shuffle`)运行 agent-loop 和 inbox 套件,以暴露调度依赖的失败;发现的任何不稳定测试都作为 bug 修复,绝不靠重试掩盖。 + +## 计划 + +措施 1 和 2 一起落地(它们改动相同的辅助模块);在套件消除所有睡眠之后再添加夜间 job,使重复运行足够快。 + +## 验收标准 + +- `packages/*/tests` 中不再有 `setTimeout`(白名单辅助模块除外),由 lint 规则强制。 +- 共享 harness 对每个测试的会话日志进行回放,将其注入全新的 `Session` 并自动断言 `deriveMessages()` 相等,覆盖整个套件。 +- 夜间 job 以 `--repeat` 和 `--shuffle` 运行 agent-loop 和 inbox 套件;发现的不稳定测试作为 bug 分诊处理,绝不靠重试掩盖。 + +## 风险 + +Fake timers 与 agent loop 中的 Promise 调度存在微妙交互——优先使用事件驱动等待;仅在测试 timer 服务行为本身时才使用 fake timers。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml new file mode 100644 index 0000000000..3f6c6157fa --- /dev/null +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-mutation-testing.md: 344263d1c91a5e6c83320f367bf76ed6f7ef5a49 +2026-06-11-mutation-testing.zh.md: aa89b3335a143b6f34858bdc2f3344a6a7d758d9 diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md index 8c68ccf09f..344263d1c9 100644 --- a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md @@ -1,5 +1,7 @@ # RFC: Mutation testing as the coverage counterweight +English | [中文](2026-06-11-mutation-testing.zh.md) + Status: proposed ## Problem diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md new file mode 100644 index 0000000000..aa89b3335a --- /dev/null +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md @@ -0,0 +1,36 @@ +# RFC:变异测试作为覆盖率的制衡 + +[English](2026-06-11-mutation-testing.md) | 中文 + +Status: proposed + +## 问题 + +逐文件 100% 覆盖率门禁(见[质量门禁决策](../../implemented/process/2026-06-11-quality-gates.md))证明的是每一行都在测试中*被执行*了,而非任何断言会在该行出错时有所察觉。在 agent 编写测试的场景下,覆盖率压力可能催生「执行但无断言」的测试。变异测试衡量的正是覆盖率无法衡量的:测试套件是否能*杀死*被刻意注入的缺陷。 + +## 提案 + +在 `packages/*/src` 上运行 Stryker(`@stryker-mutator/vitest-runner`): + +- **PR 粒度的增量运行**(仅变更文件),作为 CI job:调优后足够快,可以作为合并门禁。 +- **每夜全量运行**,跟踪变异分数;先记录基线,再将阈值设为观测到的基线值并只升不降(与覆盖率策略一致:阈值只收紧)。 +- 存活的变异体是待办工作项:agent 选取一个存活体、编写杀死它的测试、循环往复——一个形态良好的自主循环。 +- 等价变异体(可证明不改变行为的)加带理由的排除注解,与 `/* v8 ignore */` 策略对称。 + +## 计划 + +1. 添加 Stryker 配置,范围限定在一个包(llm:最小、最具算法性),测量运行时间。 +2. 扩展到所有包;在配置中记录基线分数。 +3. 接入每夜 job;当运行时间可接受后,添加 PR 粒度的增量 job。 + +## 验收标准 + +- Stryker 配置在 `packages/*/src` 上以 vitest runner 运行;每夜 job 记录变异分数,且当分数低于记录的基线时,运行失败(阈值只升不降)。 +- PR 粒度的增量运行在运行时间可接受后作为合并门禁;或者明确保持仅每夜运行,并将该结论记录于此。 +- 等价变异体带有附理由的排除注解,与 `/* v8 ignore */` 策略对称。 + +## 风险 + +运行时间:变异测试开销大;逐文件 100% 覆盖率有所帮助(每个变异体至少会被执行到)。如果 PR 粒度的运行始终太慢,则保持仅每夜运行,依赖分数只升不降的机制。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml new file mode 100644 index 0000000000..3c2a50a714 --- /dev/null +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-11-immutable-public-surfaces.md: 68472d9817f0de22777314927f05f90949903723 +2026-06-11-immutable-public-surfaces.zh.md: e067b48d9a936133abdf149fbb9ff626c9411851 diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md index 3eedd92a2d..68472d9817 100644 --- a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md @@ -1,5 +1,7 @@ # RFC: Deep-readonly public surfaces +English | [中文](2026-06-11-immutable-public-surfaces.zh.md) + Status: rejected — the pervasive `DeepReadonly<T>` type flip is replaced by source-owned runtime immutability in `Session` plus relational development assertions. See [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md). ## Problem diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md new file mode 100644 index 0000000000..e067b48d9a --- /dev/null +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md @@ -0,0 +1,29 @@ +# RFC:深度只读的公开接口 + +[English](2026-06-11-immutable-public-surfaces.md) | 中文 + +Status: rejected — the pervasive `DeepReadonly<T>` type flip is replaced by source-owned runtime immutability in `Session` plus relational development assertions. See [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md). + +## 问题 + +被否决的提案针对的是一个所有权漏洞:仅靠 `readonly SessionEvent[]` 类型无法封堵该漏洞,因为数组元素在运行时仍然可变,一次类型断言或纯 JavaScript 就能改写嵌套的历史记录。最终实现的设计在 `Session` 中通过物化并深度冻结每个已接受的事件、返回冻结的数组快照来封堵该漏洞。进行中的 prompt waterfall(瀑布式事件)被有意保留为可变,因此不可变性是一条所有权边界,而非一条覆盖全局的类型规则。 + +## 提案 + +> **实际实现方式不同——见 Status 行与 [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)。** 下文的 `DeepReadonly<T>` 设计已被否决:它仅在编译期生效、对消费方噪音大、且可被 cast 绕过。`Session` 改为在每次组合中对已接受的事件和公开日志快照进行快照与深度冻结;`deriveMessages()` 返回分离的冻结投影;开发插件检查跨记录与跨 seam 的关系约束。 + +在类型层面将不可变性施加于「变异即腐败」的位置: + +- `SessionEvent` 数据在从会话**输出**时(`events`、`session/event` 监听器)变为 `DeepReadonly`;`append()` 仍接受普通可变输入。一个 `DeepReadonly<T>` 工具类型放入 dsh-llm,与 brand/never 辅助类型并列。 +- `deriveMessages()` 返回深度只读的消息;agent loop(智能体循环)在将可变请求交给 `agent/request` waterfall 之前先克隆一份(在 waterfall 中变异是被允许的——克隆使边界显式且廉价,每步仅一次)。 +- `PromptAssembly` 在其 waterfall 流程中保持可变(被允许),但注册表的内部 section 列表在每次组装时被克隆(已有此行为)。 + +## 计划 + +引入 `DeepReadonly`,翻转会话的读取路径,并修复消费方由此产生的编译错误。 + +## 风险 + +`DeepReadonly` 类型会在 waterfall 边界处产生噪音错误——因为变异在那里正是 API 的一部分。应将可变/只读边界严格限定在「已记录 vs 进行中」,并在会话 README 中加以说明。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml new file mode 100644 index 0000000000..ba7de6f475 --- /dev/null +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-providerless-example-base.md: be5122ec6665dcea15619f3cb4b3ed3a2fa03972 +2026-06-20-providerless-example-base.zh.md: 011636bbdfb782a5b6e4c03695cd0a4a428993d5 diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md index 0fd4ca27f7..be5122ec66 100644 --- a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md @@ -1,5 +1,7 @@ # RFC: Make the shared example base providerless +English | [中文](2026-06-20-providerless-example-base.zh.md) + Status: rejected — superseded by [Extract example apps into packages](../../implemented/architecture/2026-06-20-extract-example-app-packages.md), which moves the spine into a `dsh-agent-spine-demo` bundle and deletes the `base*.yml` files, so there is no shared base YAML left to rename. ## Problem diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md new file mode 100644 index 0000000000..011636bbdf --- /dev/null +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md @@ -0,0 +1,31 @@ +# RFC:使共享示例基础配置不依赖提供方 + +[English](2026-06-20-providerless-example-base.md) | 中文 + +Status: rejected — superseded by [Extract example apps into packages](../../implemented/architecture/2026-06-20-extract-example-app-packages.md), which moves the spine into a `dsh-agent-spine-demo` bundle and deletes the `base*.yml` files, so there is no shared base YAML left to rename. + +## 问题 + +示例曾有两个共享基础文件:`examples/base-core.yml` 不依赖任何模型提供方,而 `examples/base.yml` 在此核心之上加入了真实的 `llm-deepseek` 适配器。快照回放需要搭配 `llm-replay` 使用那个提供方无关的核心,因为在没有 key 的情况下加载真实适配器会抛错。常规演示则需要真实适配器。结果是命名倒挂:名为 `base.yml` 的文件并非所有示例的可复用基础,而真正的基础反而叫 `base-core.yml`。 + +这种拆分可以理解,但它让每次解释配置都变得更长。它还导致了别扭的测试搭建方式:keyless 冒烟测试需要携带一个假 API key 才能让适配器启动,尽管模型根本不会被调用。 + +## 提案 + +将提供方无关的核心重命名为 `examples/base.yml`,让适配器选择在每个具体示例中显式声明。编码与 ACP 真实配置添加一小段 `llm-deepseek` include 或本地块;快照配置添加 `llm-replay`。删除 `examples/base-core.yml`。 + +共享基础应当只包含提供方无关的服务与工具:`llm`、会话、系统提示词、工具、agent、不变式、bash 执行器与 bash 工具 schema。任何选择模型提供方的内容都属于叶子配置。 + +## 验收标准 + +- `examples/base.yml` 不依赖任何提供方。 +- `examples/base-core.yml` 已删除。 +- 真实演示配置显式添加 DeepSeek 适配器。 +- 快照回放配置引入同一个提供方无关的基础及其回放适配器。 +- [examples README](../../../../examples/README.md)、各示例的 README 与 RFC 引用不再解释"base = base-core 加适配器"。 + +## 放弃了什么 + +真实演示失去了一层便利:每个都必须显式引入适配器。对示例而言这是正确的默认值,因为适配器选择是可变部分,而提供方无关的接线才是共享的产品核心。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml new file mode 100644 index 0000000000..243b308c50 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-assembled-assistant-messages-only.md: 7605f286cf5914a127f5f8e2b77490648b42cc30 +2026-06-20-assembled-assistant-messages-only.zh.md: e282c5bd74fd3b854c85112d64de44a5470007bc diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md index 088fa8d25d..7605f286cf 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md @@ -1,5 +1,7 @@ # RFC: Persist assembled assistant messages, not stream chunks +English | [中文](2026-06-20-assembled-assistant-messages-only.zh.md) + Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md new file mode 100644 index 0000000000..e282c5bd74 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md @@ -0,0 +1,36 @@ +# RFC:只持久化已组装的 assistant 消息,不持久化流式分片 + +Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement. + +[English](2026-06-20-assembled-assistant-messages-only.md) | 中文 + +## 问题 + +当前的规范会话日志会逐条持久化模型流出的每个 `assistant/chunk`。[会话持久化 RFC](../../implemented/architecture/2026-06-14-session-persistence.md) 选择这一方案是为了 token 级别的回放保真度和连续的 `seq`,但代价日益增长:JSONL fixture(测试前置数据)被大量微小的 delta 记录占据;快照场景通过分组 chunk 事件来回放模型;ACP 加载时需要从 chunk 重建先前的 assistant 输出;任何未来的日志读取方都必须区分持久的消息历史与 token 级别的追踪。 + +对于成功完成并组装出完整内容的步骤,agent loop(智能体循环)已经追加了一条 `assistant/message`。这正是 `deriveMessages()` 用来构造下一次模型请求的事件。换言之,正常的可恢复对话状态已经存在,无需 chunk;chunk 是实时渲染和确定性测试的产物,不是必需的对话历史。失败或中止的流则不同:部分 assistant 输出可能仅以 chunk 形式存在,而空的 max-token 步骤可能根本不产生 `assistant/message`。 + +## 提案 + +停止在规范会话日志中存储 `assistant/chunk`。持久日志只保留 `assistant/message`、`tool/call`、`tool/result`、保留的 `usage`,以及轮次边界。实时 UI 仍可通过一个刻意设计为瞬态的流事件接收 token 增量。快照回放应将其模型脚本移入显式的 fixture 伴随文件,或从已记录的适配器产物派生,而不是把规范的用户会话当作 token 磁带。需要部分失败流输出的场景必须在回放 fixture 中记录该输出。 + +ACP 的 `session/load` 可以将先前的 assistant 消息作为完整内容块回放,而不是模拟原始的 token 流。加载的 transcript(文本记录)不必重现每一个历史 delta;它必须展示相同的已完成 assistant 内容,并以有效的提供方历史恢复对话。 + +## 验收标准 + +- `SessionEventMap` 移除 `assistant/chunk`,或在需要过渡性实时事件时将其标记为不持久化。 +- [会话持久化文档](../../../../packages/session-persistence/session-persistence/README.md)不再要求逐条存储每个流式分片。 +- `llm-replay` 与 ACP 快照使用显式的回放 fixture 格式或伴随文件来承载模型 chunk。 +- `session/load` 从 `assistant/message` 渲染已完成的 assistant 消息。 +- 存储的日志大幅缩小,且在没有 chunk 空洞的情况下保持 `seq` 连续。 +- 会话格式版本与已记录的 fixture 一并刷新;按预发布格式策略拒绝非当前版本的存储日志。 + +## 放弃了什么 + +规范的用户会话不再能重建旧轮次的精确 token 流。它还会丢失失败或中止流的部分 assistant 输出,除非有其他事件或 fixture 记录了它。对于当前的恢复、加载和快照契约而言,这是过大的信息损失。需要精确确定性流的测试应当自行拥有该 fixture,前提是生产会话日志为用户可见的恢复保留了足够的保真度。 + +## 相关 + +本 RFC 取代[会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md)中关于 chunk 持久化的决策,并影响 [ACP 快照测试](../../implemented/testing/2026-06-19-acp-snapshot-tests.md)——其当前的回放插件从 `assistant/chunk` 事件派生脚本。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml new file mode 100644 index 0000000000..9d083a9f72 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-drop-acp-session-load.md: 39f24d313db6083db45ff6fbc4a84f504e7714cb +2026-06-20-drop-acp-session-load.zh.md: 003c66636a75e21199f3c3ac600867cf9b73b87c diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md index 18cd6e981d..39f24d313d 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md @@ -1,5 +1,7 @@ # RFC: Drop ACP session/load until resume has a product shape +English | [中文](2026-06-20-drop-acp-session-load.zh.md) + Status: rejected — Zed is the current target ACP client, advertises and exercises load-capable sessions, and keeps pending-load state for concurrent `session/load`. The bridge should keep `session/load` and make the resume contract solid. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md new file mode 100644 index 0000000000..003c66636a --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md @@ -0,0 +1,29 @@ +# RFC:移除 ACP session/load,待恢复功能具备产品形态后再引入 + +Status: rejected — Zed is the current target ACP client, advertises and exercises load-capable sessions, and keeps pending-load state for concurrent `session/load`. The bridge should keep `session/load` and make the resume contract solid. + +[English](2026-06-20-drop-acp-session-load.md) | 中文 + +## 问题 + +ACP(Agent Client Protocol)当前通告 `loadSession: true` 并实现了 `session/load`:向 bridge 注入持久化能力、校验 cwd 与存储元数据的一致性、从持久化日志重建 agent、并向客户端回放先前的 transcript(文本记录)更新。这条路径有自己的竞态处理、loading-id 守卫、回放展示逻辑和测试。它还依赖规范日志保留足够的 UI 数据来重建旧的分片和工具展示。 + +持久化本身仍是基础能力,但编辑器可见的恢复功能尚未经过产品流程设计。目前没有会话选择器、没有标题/预览元数据,对加载失败或部分加载也没有清晰的用户体验。bridge 正在为一个仅由测试、文档和当前目标客户端的会话模型所使用的功能承担复杂度。 + +## 提案 + +暂时只支持新建会话。`initialize` 通告 `loadSession: false` 或省略该能力,`session/load` 不予支持。持久化仍可供 agent loop(智能体循环)和测试使用;如果其他消费方需要,恢复功能仍可作为底层工厂存在。编辑器 bridge 应在具备真正的会话选择 UX 和稳定的加载 transcript 契约后,再重新引入 `session/load`。 + +## 验收标准 + +- ACP 不再仅为 `session/load` 注入 `sessionPersistence`。 +- `initialize` 不通告加载支持。 +- `session/load` 处理器、loading-id 追踪、已加载会话的 cwd 预检以及加载回放测试全部移除。 +- 快照 fixture(测试前置数据)不再依赖加载回放的展示逻辑。 +- [ACP 文档](../../../../packages/ui/acp/README.md)仅描述新建会话的支持。 + +## 放弃了什么 + +编辑器无法通过 ACP 重新打开先前持久化的会话。这确实是一个有价值的产品功能,但当前实现超前于 UX 设计,且将 bridge 绑定在 token 级别的日志回放上。保留持久化但移除编辑器加载,将 bridge 收窄到它当前能干净呈现的工作流。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml new file mode 100644 index 0000000000..61557e984b --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-drop-acp-terminal-meta.md: 4ae3b31824ece850da0ddbc004e97b21e3cb9aad +2026-06-20-drop-acp-terminal-meta.zh.md: 62341ccae728d981400fdc22b8ec7380bbb3faf2 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md index 2f1408dc4c..4ae3b31824 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md @@ -1,5 +1,7 @@ # RFC: Drop ACP terminal `_meta` rendering +English | [中文](2026-06-20-drop-acp-terminal-meta.zh.md) + Status: rejected — Zed is the current target client, and the terminal `_meta` convention is intentional Zed UX with a plain ACP fallback for other clients. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md new file mode 100644 index 0000000000..62341ccae7 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md @@ -0,0 +1,31 @@ +# RFC:移除 ACP 终端 `_meta` 渲染 + +Status: rejected — Zed is the current target client, and the terminal `_meta` convention is intentional Zed UX with a plain ACP fallback for other clients. + +[English](2026-06-20-drop-acp-terminal-meta.md) | 中文 + +## 问题 + +ACP(Agent Client Protocol)桥接层通过 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit` 实现了一套 Zed 专属的终端卡片约定。已实现的[富 ACP bash 渲染 RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 有意避开了 ACP 客户端侧的 `terminal/create`(因为 bash 执行属于 harness 的职责),但仍采用了参考 agent 的纯展示用 `_meta` 约定。这为 Zed 带来了更好的卡片效果,代价是桥接层状态、能力协商、终端 id、特殊的 update 映射、文本回退测试,以及 `dsh-tool-bash` 中的 exit-pill 解析。 + +回退路径已经存在:将工具调用和完成输出渲染为普通的 ACP 内容块。非 Zed 客户端本来就依赖这条路径,但 Zed 终端卡片是当前目标客户端的功能,而非投机性的装饰。 + +## 提案 + +忽略 `clientCapabilities._meta.terminal_output`,通过普通 ACP 内容路径渲染 bash 结果。执行仍留在 agent 侧,通过 `dsh-bash` 完成;只移除与展示相关的终端元数据。如果 ACP 日后标准化了 agent 执行的终端,或产品决定 Zed 专属展示值得维护成本,终端卡片可以回归。 + +本提案比[收拢工具自有 UI 展示](2026-06-20-generic-tool-rendering.md)更窄:如果通用的 `presentCall`/`presentResult` 保留,本提案不动它们,只移除终端子形态和 `_meta` 映射。 + +## 验收标准 + +- ACP 不再读取或存储 `_meta.terminal_output` 能力状态。 +- `TerminalRendering`、终端 id、终端 cwd 解析以及 `_meta.terminal_*` update 映射从 `@deepseek-ai/dsh-acp` 中消失。 +- `ToolTerminal` 从 `@deepseek-ai/dsh-tools` 中消失,或在展示清理中因无使用而删除。 +- Bash 结果展示不再为终端 pill 解析退出状态。 +- 已实现的[富 ACP bash 渲染 RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 保留在 `implemented/` 中作为已交付的历史记录,如被本提案取代则互相交叉引用。 + +## 放弃的内容 + +Zed 用户将失去专属终端卡片:没有 cwd 头部、终端展示或 exit pill。他们仍能以普通内容形式看到命令和输出。在 ACP 桥接层尚未发布、`_meta` 键仍是约定而非标准的阶段,这是合理的简化。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml new file mode 100644 index 0000000000..f0ed7ad2b5 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-drop-bash-output-spill-files.md: bbc26c645cefb1659012ca0debda78fc6850d276 +2026-06-20-drop-bash-output-spill-files.zh.md: 1439616bf55ad388e69ba693cbc7c130f4e2fc8c diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md index 0a13d90f1b..bbc26c645c 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md @@ -1,5 +1,7 @@ # RFC: Drop bash full-output spill files +English | [中文](2026-06-20-drop-bash-output-spill-files.zh.md) + Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md new file mode 100644 index 0000000000..1439616bf5 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md @@ -0,0 +1,31 @@ +# RFC:移除 bash 完整输出溢出文件 + +Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output. + +[English](2026-06-20-drop-bash-output-spill-files.md) | 中文 + +## 问题 + +`dsh-bash-local` 在内存中保留有界的输出,并将大体积的 stdout/stderr 流溢出到私有临时文件。这要求维护一个私有目录、创建仅所有者可读的随机文件、处理关闭失败、按字节偏移增量读取、报告有损读取、在面向模型的文本中渲染路径,以及清理纪律。当输出被截断时,工具会告诉模型去读取一个本地溢出路径。 + +这解决了一个真实问题,但方式狭窄且有泄漏。溢出路径是一个暴露在模型输出中的进程本地文件系统产物,而非具备作用域访问、保留策略或 UI 能力的持久化 harness 产物。它还使后台任务的读取变得复杂,因为有损增量读取必须指向一到两个溢出文件。 + +## 提案 + +保留尾部截断,移除完整输出溢出文件。bash 结果包含有界的尾部内容加一个明确的截断标记;不输出路径。如果用户需要恢复完整输出,则添加一个通用的产物/blob 服务(具备显式的所有权、清理和 UI 渲染),再让 bash 将大体积输出附加到该服务。 + +本提案可以独立于[通用长时运行工具运行时](../../proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md)落地。如果后台任务保留,`bash_output` 仍应报告输出已被丢弃,但不再公布溢出路径。 + +## 验收标准 + +- `CollectedOutput` 不再携带溢出路径。 +- `OutputCollector` 仅保留有界缓冲区,删除临时文件机制。 +- `renderResult()` 报告截断时不包含文件系统路径。 +- 测试覆盖尾部截断,不再断言完整输出文件的内容。 +- [docs/defensive-patterns.md](../../../defensive-patterns.md) 中的安全指导不再将私有溢出文件视为面向模型的接口。 + +## 放弃了什么 + +模型或用户无法再从临时文件恢复大体积命令输出中被省略的前缀。在真正的产物服务出现之前,这是可接受的。当前的溢出路径为一个生命周期和权限都未经设计的功能引入了过多的定制机制。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml new file mode 100644 index 0000000000..51d6027a24 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-drop-durable-step-boundaries.md: fba8ad4211db69d3a04d253fd9544caca0f538c6 +2026-06-20-drop-durable-step-boundaries.zh.md: 9ffa12cfba697f1e3bc9059529d0fdf97f595705 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md index 94313fd0ad..fba8ad4211 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md @@ -1,5 +1,7 @@ # RFC: Drop durable step boundary events +English | [中文](2026-06-20-drop-durable-step-boundaries.zh.md) + Status: rejected — `step/end` is the durable indication that a model step finished, and keeping the symmetric `step/start` / `step/end` pair makes crash repair, invariants, and transcript inspection clearer than inferring completion from adjacent step-scoped events. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md new file mode 100644 index 0000000000..9ffa12cfba --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md @@ -0,0 +1,32 @@ +# RFC:移除持久化的步骤边界事件 + +[English](2026-06-20-drop-durable-step-boundaries.md) | 中文 + +Status: rejected — `step/end` 是模型步骤已完成的持久化标识,保留对称的 `step/start` / `step/end` 对,在崩溃恢复、不变式检查和 transcript(文本记录)审查方面,都比从相邻的步骤级事件推断完成状态更清晰。 + +## 问题 + +会话日志存储了 `step/start` 和 `step/end` 事件,尽管每个步骤级事件本身已携带 `{ turn, step }`:assistant 分片、assistant 消息、工具调用、工具结果、token 用量和错误。`deriveMessages()` 忽略步骤边界,ACP(Agent Client Protocol)在 UI 层也忽略它们,主要消费方是不变式检查、测试、快照 golden 文件和崩溃恢复。 + +被否决的论点是:边界事件让日志更像仪式而非信息。实际上,`step/end` 是具体信息:读者无需从下一个事件推导,就能判断一次模型请求是已完成、已崩溃还是正在被修复。同样,一条孤立的 `step/start` 对于「模型请求已发起但在产出任何分片之前就失败了」的场景也有用。 + +## 提案 + +以轮次作为唯一的持久化边界。从 `SessionEventMap` 中移除 `step/start` 和 `step/end`;保留步骤级事件上用于分组的数值 `step` 字段。agent loop(智能体循环)递增步骤计数器,并以该编号记录步骤级事件,但不再追加开/关边界事件。消费方通过共享 `(turn, step)` 的连续事件推断步骤分组。 + +不变式插件应强制步骤级事件在一个已打开的轮次内具有有效的正整数步骤编号,而非要求它们被独立的边界记录包围。崩溃恢复不应合成 `step/end`;如果一个被中断的轮次被保留,恢复路径仍可关闭该轮次而无需捏造步骤边界记录。 + +## 验收标准 + +- `SessionEventMap` 不再包含 `step/start` 或 `step/end`。 +- agent loop 不再有 `closeStep()` 终结路径。 +- ACP 快照和持久化契约 fixture(测试前置数据)不再期望步骤边界行。 +- `deriveMessages()` 和回放从步骤级事件推导出相同的消息历史。 +- [事件分类体系文档](../../../architecture.md)将轮次描述为持久化边界,将步骤描述为步骤级记录上的一个字段。 +- 会话格式版本和已记录的 fixture 被刷新;按预发布格式策略,非当前版本的已存储日志被拒绝。 + +## 放弃了什么 + +日志不再将「一次模型请求已发起但进程在产出任何事件之前就终止了」记录为持久化事实,也不再有显式的「此步骤已完成」标记。在会话日志仍是持久化回放与审计表面的当下,这一损失不可接受。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml new file mode 100644 index 0000000000..aeb154fbb1 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-drop-unused-session-lineage.md: 4200532726a27e257e09f927240846f20a0b30ad +2026-06-20-drop-unused-session-lineage.zh.md: c20f964317a1924c3cbc36b7f7838f3a207a65c1 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md index fc06cc76c9..4200532726 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md @@ -1,5 +1,7 @@ # RFC: Drop unused session lineage metadata +English | [中文](2026-06-20-drop-unused-session-lineage.zh.md) + Status: rejected — `parentSession` is part of the documented fork/sub-agent seam and is already preserved by the agent/session resume path. The field is future-facing, but it is not accidental dead state. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md new file mode 100644 index 0000000000..c20f964317 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md @@ -0,0 +1,31 @@ +# RFC:移除未使用的会话血缘元数据 + +Status: rejected — `parentSession` is part of the documented fork/sub-agent seam and is already preserved by the agent/session resume path. The field is future-facing, but it is not accidental dead state. + +[English](2026-06-20-drop-unused-session-lineage.md) | 中文 + +## 问题 + +`SessionHeader.parentSession` 记录新会话从哪个会话 fork 而来。它在 `dsh-session` 中定义,被持久化后端保存,在 resume 路径中被复制,作为血缘元数据被文档记录,并有往返测试覆盖。然而仓库中没有任何已上线的 fork UI 或 subagent 流程读取它。计划中的 subagent/fork seam 仍是一个 TODO,因此该字段目前只是被存储的未来形状。 + +单文件的代价虽小,但在整个格式中分布广泛:每个后端 schema 和元数据序列化器都在保存一个尚无已完成功能读取的值。由于 header 是一份磁盘契约,即便是占位字段也会成为未来重构必须维护、迁移或有意打破的东西。 + +## 提案 + +从 `SessionHeader` 中移除 `parentSession`,直到真正的 fork/resume 功能需要血缘信息时再引入。如果存在相应 API,fork 仍然可以用先前事件来初始化新会话,但持久化的父指针应当与读取它的功能和解释它的 UX 一同引入。 + +如果血缘信息回归,届时再决定它应放在不可变 header 中、会话图索引中,还是作为一等事件。当前字段不应预先锁定那个设计。 + +## 验收标准 + +- `SessionHeader` 仅包含 version、id、createdAt 和可选的 cwd。 +- JSONL 与 SQLite 元数据 schema 不再存储 parent-session id。 +- resume 和 list API 不再往返传递 `parentSession`。 +- 文档和测试移除没有生产消费方支撑的 fork 血缘声明。 +- 会话格式版本、后端 schema 版本和录制的 fixture(测试前置数据)按需刷新;按预发布格式策略,非当前版本的已存储数据将被拒绝,不提供迁移路径。 + +## 放弃了什么 + +代码库失去一个为未来 fork/subagent UX 准备好的血缘钩子。这是有意为之。该字段在功能存在时很容易重新引入,而未发布的立场允许格式变更无需迁移。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml new file mode 100644 index 0000000000..bb1af91b9b --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-fold-session-persistence-interface.md: 695cd679c67f3e0a9f901c671c33e9507ecbe279 +2026-06-20-fold-session-persistence-interface.zh.md: 1ef93fb64cc27eeeb465136dc7dac6e751a7ccfc diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md index a59c992b0d..695cd679c6 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md @@ -1,5 +1,7 @@ # RFC: Fold the persistence interface into dsh-session +English | [中文](2026-06-20-fold-session-persistence-interface.zh.md) + Status: rejected — the separate persistence interface package is the intended modular capability seam for durable backends. Folding it into `dsh-session` would reduce package count at the cost of a cleaner backend boundary. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md new file mode 100644 index 0000000000..1ef93fb64c --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md @@ -0,0 +1,31 @@ +# RFC:将持久化接口合入 dsh-session + +Status: rejected — the separate persistence interface package is the intended modular capability seam for durable backends. Folding it into `dsh-session` would reduce package count at the cost of a cleaner backend boundary. + +[English](2026-06-20-fold-session-persistence-interface.md) | 中文 + +## 问题 + +`dsh-session-persistence` 是一个接口包(package),其核心概念已由 `dsh-session` 拥有:`SessionHeader`、`SessionEvent`、`SessionId`、`session/event` 和 `session/flush`。该包额外引入了抽象的 `SessionPersistence` 服务、共享写协调器和契约辅助工具。后端包依赖它,`agent-loop` 则需要可选地发现一个兄弟服务来实现恢复。 + +当持久化还是一个全新的可替换后端设计时,能力 seam 的拆分是合理的。但在可变摘要被移除之后,这个接口包基本上只是包装了会话日志自身的存储关注点。保持独立可能带来的仪式感多于清晰度。 + +## 提案 + +将抽象的 `SessionPersistence` 服务、协调器和持久化契约辅助工具移入 `dsh-session`。JSONL 和 SQLite 仍作为独立的后端包,注册由 session 包拥有的服务。这样既保留了后端可替换性,又删除了一个支撑包和一条跨包 seam。 + +实施 PR(Pull Request)应更新[能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md) 指南,补充此例外:持久化不同于 bash 或 LLM(大语言模型),因为它的词汇和生命周期事件本身就是 session 包的核心领域。 + +## 验收标准 + +- `@deepseek-ai/dsh-session-persistence` 作为包被移除。 +- `dsh-session` 导出持久化服务类型、协调器和契约辅助工具。 +- JSONL 和 SQLite 后端包直接依赖 `dsh-session`。 +- `agent-loop` 的恢复功能使用由 session 包拥有的服务键。 +- [会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md)、[共享持久化写协调器](../../implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)与[包文档](../../../../packages/session-persistence/session-persistence/README.md)说明后端实现为何仍保持独立。 + +## 放弃了什么 + +`dsh-session` 变得更重:它同时拥有内存日志和持久化接口。这就是取舍。如果第三方持久化后端已经形成公开生态,独立的接口包会是更清晰的 SDK 边界;但在预发布阶段,多出的包看起来像是在有外部消费方之前的过度抽象。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml new file mode 100644 index 0000000000..db3ac5d979 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-generic-tool-rendering.md: 07102ed3b12d7f587b1d12f0e240c1202a2e1cdd +2026-06-20-generic-tool-rendering.zh.md: 86ea52545a79ff975fc6b9c5d080e111a2750290 diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md index 6125feaa8b..07102ed3b1 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md @@ -1,5 +1,7 @@ # RFC: Collapse tool-owned UI presentation +English | [中文](2026-06-20-generic-tool-rendering.zh.md) + Status: rejected — tool-owned presentation should wait for more real tools before being generalized or deleted. Bash and ACP currently need the existing richer presentation path. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md new file mode 100644 index 0000000000..86ea52545a --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md @@ -0,0 +1,35 @@ +# RFC:收拢工具自有的 UI 展示逻辑 + +[English](2026-06-20-generic-tool-rendering.md) | 中文 + +Status: rejected — tool-owned presentation should wait for more real tools before being generalized or deleted. Bash and ACP currently need the existing richer presentation path. + +## 问题 + +工具可以定义 `presentCall()` 和 `presentResult()` 回调,返回 `ToolCallPresentation`、`ToolResultPresentation` 以及可选的 `ToolTerminal` 字段。代码本身已标记出设计的混乱:title、kind、raw input、content、terminal cwd、terminal output、exit code 和 signal 逐步堆积成一堆可选字段。ACP(Agent Client Protocol)随后维护 pending call 状态以将 result 与原始 args 配对,在 `session/load` 时创建仅用于回放的 presenter,并将 terminal 子字段映射为 Zed 特有的 `_meta`。`dsh-tool-bash` 甚至从已渲染的文本中反向解析退出状态,因为纯回放安全的 presenter 已经拿不到结构化的 `BashRunResult`。 + +真正的一方使用场景是 ACP 的 bash 展示。这不足以作为冻结一个跨包 UI 展示 API 的依据。 + +## 提案 + +暂时移除工具自有的 UI 展示回调。规范的工具事件已经携带工具名称、原始参数字符串、结果内容与错误状态。UI 从这些字段渲染一个通用的工具卡片。工具特有的富展示可以在至少有两个真实工具和两个真实消费方来验证词汇后,以 tagged render-intent union 的形式回归。 + +## 曾考虑的替代方案 + +一个更小的替代方案是在单个 PR(Pull Request)中将当前的可选字段包替换为一个显式 union;但如果目标是简化,更彻底的做法是删除回调、保留通用路径。 + +## 验收标准 + +- `ToolDefinition` 移除 `presentCall` 和 `presentResult`。 +- `ToolCallPresentation`、`ToolResultPresentation`、`ToolTerminal` 和 `ToolCallKind` 消失,除非一个最小的通用 UI 类型仍需要其中之一。 +- ACP 不再维护 presenter pending 状态,也不在实时流式输出/加载回放期间调用工具回调。 +- `dsh-tool-bash` 不再解析已渲染文本来恢复退出状态以生成 UI pill。 +- 快照 golden 展示通用工具卡片和文本结果。 + +## 放弃了什么 + +Bash 失去其自定义的终端风格卡片和模型撰写的描述位置。回退方案仍然合理:命令作为工具输入展示,输出作为文本展示。富展示应在产品拥有足够的 UI/工具多样性、足以支撑一份稳定的展示契约时再行设计。 + +## 相关 + +本 RFC 是[移除 ACP terminal 元数据](2026-06-20-drop-acp-terminal-meta.md)的宽泛版本。如果本 RFC 被接受,那个更窄的 RFC 就不再需要。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml new file mode 100644 index 0000000000..62eb41dc9a --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-retire-mid-turn-steering.md: bf78125ec175aa9152789bdccd1f8e8a16863a5b +2026-06-20-retire-mid-turn-steering.zh.md: 03af2b24916a5d1a479dc06a30d54003dfa7f156 diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md index fd1a4687b3..bf78125ec1 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md @@ -1,5 +1,7 @@ # RFC: Retire mid-turn steering +English | [中文](2026-06-20-retire-mid-turn-steering.zh.md) + Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md new file mode 100644 index 0000000000..03af2b2491 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md @@ -0,0 +1,37 @@ +# RFC:废除中途 steering(中途引导) + +Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. + +[English](2026-06-20-retire-mid-turn-steering.md) | 中文 + +## 问题 + +agent(智能体)暴露了两条用户消息路径,看起来相近但生命周期语义不同:`send()` 将一条普通用户轮次排入队列,而 `steer()` 在当前运行轮次的步骤之间注入一条消息,空闲时则回退为 `send()`。这一区别渗透到整个栈:`Agent.steer()` 是公开 API,会话日志有持久化的 `steering/message` 事件,agent 事件分类体系有 `agent/steering`,循环在排队消息 FIFO 之外还维护一个 steering FIFO,取消操作需要清空两个队列,`deriveMessages()` 必须将 steering 渲染为带标签的合成用户消息而非普通提示词。 + +continuation seam 放大了这一成本。`agent/turn-continuation` 默认为 `hadToolCalls || steeringInjected`,因此同一轮次内的 steering 消息即使模型没有请求工具调用也能强制循环再次调用模型。注释中提到了未来的 `/goal`、`/loop` 和预算守卫用途,但当前仓库没有生产级监听器;只有测试注册了该 waterfall(瀑布式事件)。另外,唯一调用 `steer()` 的生产 UI 是 stdio 演示。ACP 在轮次运行期间已经通过普通队列发送提示词。 + +## 提案 + +暂时删除中途用户 steering。`Agent.send()` 成为提交用户内容的唯一公开方式;当 agent 正在运行时,内容等待下一轮次。循环仅因工具调用而在轮次内继续,而非因为用户在某步骤运行期间输入了内容。想要中断当前轮次的调用方使用 `cancel()` 再 `send()`。 + +移除 `Agent.steer()`、steering FIFO、`steering/message`、`agent/steering`、由 steering 驱动的 continuation,以及区分排队消息与 steering 消息的取消逻辑。在同一变更中移除 `agent/turn-continuation`,除非实现 PR 发现了生产级监听器;没有 steering 之后,当前仓库不再有具体的 continuation 消费方。如果将来真正的预算或 goal 插件需要强制 continuation,应以该插件为具体消费方重新引入一个更窄的 seam。 + +## 验收标准 + +- `Agent` 暴露唯一的用户消息入口 `send()`。 +- 持久化会话事件词汇不再包含 `steering/message`。 +- `deriveMessages()` 渲染普通用户消息和上下文注入,不再有 steering 标签路径。 +- 循环只有一个排队消息 FIFO,没有同轮次用户消息 continuation 路径。 +- `agent/turn-continuation` 被移除或收窄到一个具名的生产级消费方。 +- stdio UI 和文档将运行期间的输入描述为排入下一轮次的输入。 +- 会话格式版本和录制的 fixture(测试前置数据)已刷新;按预发布格式策略拒绝非当前版本的存储日志。 + +## 放弃了什么 + +用户无法在模型处于工具步骤之间时添加同轮次 steering 内容。这种行为在理论上对「你已经在工作了,顺便也考虑一下 X」有用,但它不是 ACP 今天暴露的行为,而且它使轮次边界变得更难推理。更简单的行为是合理的:用户输入成为下一条提示词,取消仍是替换进行中工作的显式手段。 + +## 相关 + +本提案与[删除持久化步骤边界](2026-06-20-drop-durable-step-boundaries.md)天然配对,因为移除同轮次 steering 和 `agent/turn-continuation` 之后,工具调用成为一个轮次包含多个模型步骤的唯一原因。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml new file mode 100644 index 0000000000..aa8c2bbf58 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-single-session-acp-bridge.md: b7b52ca4df2d118358303745f4484e3e40a242b3 +2026-06-20-single-session-acp-bridge.zh.md: 2f00067fffcbd7a74f403c6247b290ac09a846b8 diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md index 8f1d4e4531..b7b52ca4df 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md @@ -1,5 +1,7 @@ # RFC: Return the ACP bridge to one live session per connection +English | [中文](2026-06-20-single-session-acp-bridge.zh.md) + Status: rejected — Zed is the current target ACP client and its ACP implementation is explicitly multi-session: it stores live sessions in a `HashMap<SessionId, AcpSession>`, tracks `pending_sessions`, joins concurrent loads for the same id, and tests close-during-load behavior. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md new file mode 100644 index 0000000000..2f00067fff --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md @@ -0,0 +1,31 @@ +# RFC:将 ACP 桥接恢复为每连接单会话 + +[English](2026-06-20-single-session-acp-bridge.md) | 中文 + +Status: rejected — Zed 是当前目标 ACP 客户端,其 ACP 实现明确支持多会话:它将活跃会话存储在 `HashMap<SessionId, AcpSession>` 中,跟踪 `pending_sessions`,对同一 id 的并发加载进行合并,并测试加载期间关闭的行为。 + +## 问题 + +ACP 桥接现已支持在一条 JSON-RPC 连接上承载多个活跃会话。这一能力带来了多条目会话映射、反向的会话/agent 查找、逐会话的提示词状态、加载中 id、每个事件的解复用、跨会话的销毁,以及未来权限提示与后台任务的隔离问题。早先的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)仍在跟踪未完成的权限归属部分;本 RFC 是与之竞争的简化路径。 + +产品目标已证明它需要在一个 harness 进程上承载并发的编辑器对话:Zed 的 ACP 连接拥有多个会话和加载状态。快照回放层仍然避免并发模型流,因为其回放条目是位置敏感的;这是测试 fixture 的局限,不是移除桥接多路复用的理由。 + +## 提案 + +将 ACP 的作用域收回到每连接一个活跃会话。`session/new` 或 `session/load` 创建唯一的会话记录;在现有会话被 dispose 或连接关闭之前,第二个活跃会话请求将被拒绝。如果编辑器需要多个聊天标签页,可以启动多个 agent 子进程,直到桥接具备具体的多会话 UX 和权限模型。 + +在单个 `SessionRecord | undefined` 即可满足需求的地方,移除多会话映射和解复用逻辑。桥接仍可保留使销毁行为正确的 agent/会话生命周期 seam;简化仅针对在同一传输层上多路复用多个活跃会话这一点。 + +## 验收标准 + +- ACP 每连接仅有一条活跃会话记录。 +- 当该记录存在时,`session/new` 和 `session/load` 拒绝请求。 +- 事件处理器不再跨 `Map<sessionId, record>` 解复用。 +- 多会话测试被移除,或移至继续支持多路复用的提案下。 +- 既有的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)更新为链接本 RFC,并继续作为当前方向。 + +## 放弃了什么 + +ACP 客户端无法在一个服务器进程上承载多个并发对话。这是一项有实质意义的能力削减。对于一个尚未发布的 harness 而言,更简单的模型仍然合理:一个编辑器对话对应一个 agent 进程,跨会话的权限/后台任务隔离不再是活跃的正确性负担。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml new file mode 100644 index 0000000000..32aca9d1e8 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-20-truncate-interrupted-turns.md: e17cb20f0185fe5d47d0a5ca18b7a389951fbadd +2026-06-20-truncate-interrupted-turns.zh.md: 9ded51b29323be452bd67901dea2ba7b309a9903 diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md index 1ed26c66f8..e17cb20f01 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md @@ -1,5 +1,7 @@ # RFC: Truncate interrupted final turns on load +English | [中文](2026-06-20-truncate-interrupted-turns.zh.md) + Status: rejected — a single turn can contain substantial real work, including many steps and large tool output. Preserving interrupted turns is preferable to silently dropping that tail on load. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md new file mode 100644 index 0000000000..9ded51b293 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md @@ -0,0 +1,36 @@ +# RFC:加载时截断被中断的末尾轮次 + +Status: rejected — a single turn can contain substantial real work, including many steps and large tool output. Preserving interrupted turns is preferable to silently dropping that tail on load. + +[English](2026-06-20-truncate-interrupted-turns.md) | 中文 + +## 问题 + +当前的持久化契约会保留最后一个已持久写入但从未关闭的轮次。加载时,`interruptedTurnClosers()` 扫描尾部,为未应答的工具调用合成错误的 `tool/result` 事件,在步骤未关闭时追加 `step/end`,追加 `turn/end { kind: 'interrupted' }`,并要求后端持久提交这段修复。协调器、JSONL 后端、SQLite 后端、会话事件词汇、不变式、文档和测试都对这条合成关闭路径建了模。 + +这是为了保留上一次崩溃轮次的部分工作而引入的大量机制。它还会生造从未发生过的事件。合成的工具结果有用处(它使提供方历史保持合法),但也意味着恢复后的日志中包含了没有任何工具产出过的、模型可见的文本。当前设计在尚无已发布产品、也没有真实的恢复 UX 来证明部分轮次恢复确有价值的情况下,就优化了最大化的尾部保留。 + +## 提案 + +加载时只保留到最后一个已完成的轮次。后端仍然容忍并截断撕裂的末尾记录,但如果解析出的持久前缀在一个已打开的 `turn/start` 之后结束,规范的修复方式是丢弃上一个 `turn/end` 之后的所有事件。不合成 `tool/result`,不合成 `step/end`,不追加 `turn/end { interrupted }`,也不需要 `interrupted` 轮次结束原因。 + +这使持久化的轮次边界变得简单:一个已完成的 `turn/end` 就是检查点。最后一个检查点之后的内容都是崩溃尾部。下一次提示词从最后一个已知合法的提供方 transcript 恢复,而非从部分重建的末尾轮次恢复。 + +## 验收标准 + +- `TurnEndReasonMap` 移除 `interrupted` 变体。 +- `interruptedTurnClosers()` 及其测试消失。 +- 持久化协调器的修复钩子截断后端特定的撕裂/未关闭尾部状态,不追加关闭事件。 +- [会话持久化文档](../../../../packages/session-persistence/session-persistence/README.md)说明加载返回到最后一个已完成轮次,不包含部分末尾轮次。 +- 快照测试与契约测试随其所固定的行为一起更新。 +- 会话格式版本与已记录的 fixture(测试前置数据)一并刷新;按预发布格式策略,非当前版本的存储日志被拒绝,不提供迁移路径。 + +## 放弃了什么 + +一次崩溃可能丢失末尾轮次中的真实工作:上一个 `turn/end` 之后追加的助手文本、工具调用和工具输出。这是有意为之的简化。产品尚未发布,末尾轮次恢复的语义未经用户验证,而一个干净的「已完成轮次即检查点」模型在解释、测试和实现上都容易得多。未来如果需要「恢复部分崩溃工作」功能,应当设计为一个面向用户的显式恢复视图,而非静默插入规范 transcript 的合成事件。 + +## 相关 + +本 RFC 是对[会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md)和[轮次封闭不变式](../../implemented/architecture/2026-06-15-turn-enclosure-invariant.md)的直接简化。它还移除了持久化步骤边界事件的大部分动机,使 [drop durable step boundary events](2026-06-20-drop-durable-step-boundaries.md) 的变更范围更小。 + +<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml new file mode 100644 index 0000000000..c61b774371 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-04-prune-unimplemented-subagent-vocabulary.md: 3c86f11564d85b423fe59d784c6bf69959fb3907 +2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: ad8c8541ca682be6e71b6fe4ae166c3b65d14cdf diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md index 4c52d0b1a4..3c86f11564 100644 --- a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md @@ -1,5 +1,7 @@ # RFC: Prune the unimplemented subagent seam vocabulary +English | [中文](2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md) + Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below stands as the record of what is currently unimplemented. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md new file mode 100644 index 0000000000..ad8c8541ca --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md @@ -0,0 +1,39 @@ +# RFC:裁剪 subagent seam 中未实现的词汇 + +Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below stands as the record of what is currently unimplemented. + +[English](2026-07-04-prune-unimplemented-subagent-vocabulary.md) | 中文 + +## 问题 + +[subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 交付了一套两层能力设计:由服务在启动时检查的能力 flag,以及 `SubagentRun` 上的可选运行时方法。三项启动时特性和两个可选运行时方法均无实现、无调用方: + +- **`outputSchema`/`structured` 与 `toolFilter`**(`SubagentCapabilities`、`SubagentStartRequest`、`SubagentResult`,位于 `packages/subagent/subagent/src/types.ts`):每个真实提供方都声明 `outputSchema: false, toolFilter: false`(`packages/subagent/subagent-spawn/src/index.ts`、`packages/subagent/subagent-fork/src/index.ts`、`packages/subagent/subagent-acp/src/index.ts`);唯一的生产环境 `ctx.subagents.start` 调用方(`packages/subagent/tool-subagent/src/index.ts`)构建 `{ prompt, parent, signal?, agentOptions? }`,结构上无法设置这两项;`structured` 仅由测试 mock(`packages/support/subagent-mock`)为其自身 spec 产出。服务的能力检查包含两行 assert,唯一的执行者是拒绝测试。 +- **`SubagentRun.sendMessage` / `SubagentRun.resume`**(同一文件):没有任何提供方实现——连 mock 也没有;spawn spec 断言的是它们的*缺席*。 + +`dsh-subagent` 依赖 `dsh-tools` 的唯一原因是 `outputSchema` 的 `SchemaSpec` 类型。三个后续 subagent 工作流(per-session 快照回放、fork seed 边界、ACP 后端)都围绕这块表面落地,却没有增长出哪怕一个消费方。 + +## 提案 + +从 seam 中移除 `outputSchema`/`structured`、`toolFilter`、`sendMessage` 和 `resume`;将 `SubagentCapabilities` 缩减为 `{ depthLimit }`;删除两行能力 assert、三个提供方上的 all-false flag、mock 的 structured 分支及其 `capabilities`/`structured` 配置旋钮,以及为固定被移除表面而存在的测试(两行拒绝测试、spawn 缺席测试、mock structured spec)。从 `packages/subagent/subagent/package.json` 中删除 `dsh-tools` 的 peer/dev 依赖。更新 [subagent.md](../../../core-data-structures/subagent.md) 中的粘贴内容与 type-equiv manifest,以及 `packages/subagent/subagent`、`packages/subagent/subagent-spawn`、`packages/subagent/subagent-fork` 和 `packages/support/subagent-mock` 的 README 相关行。实现 PR 按 [implemented/AGENTS.md](../../implemented/AGENTS.md) 修订 seam RFC 的能力目录。 + +**保留** `depthLimit`/`maxDepth` 与能力检查。进程内后端强制执行该限制,尽管当前发布的工具尚未设置它。递归是已知的 seam 风险,因此恰当的后续工作是补上工具默认值,而非删除正在工作的强制逻辑。 + +审视过但有意不动的相邻表面:`SubagentService.getProvider()`/`list()` 只有测试 harness 消费方,但 [prune-dead-seam-methods 实现说明](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md) 记录了完全相同的形态曾从 bash executor 中移除后又被回退——测试 harness 对于一个在已跟踪 map 上的单行访问器而言就是消费方。`SubagentRunEndInfo.lastAssistantMessage` 是一个已记录的保留项([subagent-observe-enrich RFC](../../implemented/feature/2026-06-30-subagent-observe-enrich.md) 的评审删除了 `agentType` 但有意保留了它,因为它是进程外子 agent 唯一的最终消息通道);它当前未接通的桥接转发是一个待弥合的缺口或待记录的消费方,不是本 RFC 要裁剪的表面。 + +这是 [从持久化 seam 裁剪死方法](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md) 在 seam 词汇层面的回声:每个实现都必须为无人声明的成员——甚至更弱,因为这里连一个实现都不存在。 + +## 曾考虑的替代方案 + +### 为什么不保留? + +两类能力的设计是 seam RFC 的核心亮点,日后重新添加 `outputSchema` 会涉及多个文件。但该设计以 `depthLimit` 作为活跃示例、以 RFC 作为记录仍然成立;而且 seam RFC 本身承认已交付的 `toolFilter` 形态是错的(真正的强制需要在子 agent 的上下文中设置 `tools/pre-execute` deny,而非 schema 过滤)——该 deny 原语已存在于拦截 seam 上,因此面向真实实现提供方重新添加时,将固定一份比当前推测性契约更好的契约。 + +## 验收标准 + +- 被移除的拼写仅出现在本 RFC 和修订后的 seam RFC 中;`SubagentCapabilities` 为 `{ depthLimit: boolean }`;`dsh-tools` 依赖边已消除(`hygiene` 绿)。 +- 深度强制测试不变且绿。 + +## 风险 + +subagent 生命周期事件在结束载荷上携带 `lastAssistantMessage`——该增强位于服务模块中,不在本 RFC 缩减的 seam 词汇范围内;observe-enrich RFC 记录了因缺乏消费方而删除 `agentType` 兄弟字段的判断:本 RFC 延续的正是这一判断。CC hooks 桥接是这些生命周期事件的第一个外部消费方,它只读取事件载荷,不触及本文移除的任何表面;observe-enrich RFC 中延期的控制流重设计将实现 `resume` 列为自身的未来工作——恰好是本 RFC 模式所预期的重新添加触发点。 diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml new file mode 100644 index 0000000000..96bb401556 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-12-collapse-workflow-to-foreground-core.md: 78b67c10ac39fddaf4ea76ca90d5cbf760fe5866 +2026-07-12-collapse-workflow-to-foreground-core.zh.md: 567da63e86b24dbedfd6fb50da0984c9866bd9cb diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md index 7624629d41..78b67c10ac 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md @@ -1,5 +1,7 @@ # RFC: Collapse workflows to the exercised foreground core +English | [中文](2026-07-12-collapse-workflow-to-foreground-core.zh.md) + Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md new file mode 100644 index 0000000000..567da63e86 --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md @@ -0,0 +1,39 @@ +# RFC:将工作流收缩至实际使用的前台核心 + +Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it. + +[English](2026-07-12-collapse-workflow-to-foreground-core.md) | 中文 + +## 问题 + +工作流能力执行前台 JavaScript 来编排 subagent,但它同时携带了一套无人消费的进度观测系统。没有任何生产环境的监听器订阅六个 `workflow/*` 事件中的任何一个;监听器仅存在于工作流测试中。尽管如此,seam 仍定义了 run/phase/agent outcome 载荷,worker 仍发送 phase/log/agent 生命周期协议消息,host 通过一个 `liveAgents` 配对账本转发它们,引擎维护 run id 的唯一目的就是关联这些通知。 + +这套进度词汇不仅未被使用,而且在不重新设计的情况下无法服务于它唯一的具名未来消费方。`WorkflowRunInfo` 包含 `{id, meta}` 但没有父 agent、会话或工具调用标识,而面向模型的工具从不暴露 run id。一个全局 ACP 监听器无法将事件路由到正确的客户端会话。`meta.phases` 从未被查询,`phase(title)` 不会对其做校验,phase 的 `detail`/`model` 和 agent 的 `label`/`phase` 只喂给事件,`whenToUse` 被校验和复制但从未被渲染或用于选择。`phase()` 和 `log()` 仍然跨越 worker 边界,尽管没有接收方。 + +live handle 在观察者消失后仍重复事件时代的数据。`WorkflowRun.id` 没有非事件消费方,而工具读取 `run.meta.name` 只是为了渲染一个它已经以 `args.meta.name` 形式持有的值;两者都不属于执行/取消 handle。 + +取消也为一个同步启动提供了两条公开通道。`WorkflowStartRequest.signal` 被传给 worker host,而唯一的生产调用方另外将同一个 signal 桥接到 `WorkflowRun.cancel()`。因为 `start()` 在控制权让出之前就返回了 run,不存在需要请求时取消的就绪窗口;重复的 signal 增加了 host 的 listener/disarm 状态却没有消除任何竞态。 + +`WorkflowError.fatal` 是同类投机分支的微缩版:每个生产环境的构造都是 fatal 的,`fatal: false` 仅存在于测试中,组合子已经通过 `instanceof` 区分工作流失败。 + +## 提案 + +保留实际使用的核心:`agent(prompt, { schema, model })`、`parallel`、`pipeline`、`args`、并发/agent 上限、取消、有界 dispose、结构化结果、worker 隔离,以及前台工具收集。移除所有 `workflow/*` 事件及其仅服务于事件的 info/outcome 类型;移除 `phase()`、`log()`、agent 的 `label`/`phase`、phase 声明、`whenToUse` 及其 worker 消息/host 观察者;将工作流元数据收缩为工具实际使用的 name;移除仅服务于事件的 run id/meta 快照以及合成的 agent-end 账本。将 `WorkflowRun` 收缩为 `result`、`cancel()` 和 `dispose()`;工具渲染请求方持有的 name。移除 `WorkflowStartRequest.signal` 及 worker host 的 input-signal listener/disarm 状态,保留调用方从自身 abort signal 到 `run.cancel()` 的桥接。将 `WorkflowError` 变为单一的 fatal 错误类,不再有布尔模式或 `isFatalWorkflowError()` 辅助函数。 + +修订已实施的动态工作流 RFC,并更新 seam/tool/worker README、工具 schema、生成的 catalog 与包依赖图、worker type-equiv 记录、单元测试,以及工作流快照/header fixture。如果未来委托进度 UI 工作,应从一份命名了父 agent/会话/工具调用的关联契约出发,而非原样复活此协议。 + +## 曾考虑的替代方案 + +**为未来 UI 保留预建的观测词汇。** 当前形状类似 Claude Code 的动态工作流元数据,host 有意地将每个转发的 agent start 与 worker 的 end 或合成的终端 end 配对。移除它意味着放弃形状兼容性,使进度 UI 成为一项全新的设计任务;但现有载荷仍然缺少可路由的归属信息,因此仅靠平衡的生命周期也无法在不重新设计的情况下让具名的 ACP 消费方可行。 + +## 验收标准 + +- 工作流公开 seam 仅包含有生产消费方的执行、取消、结果与 dispose 契约。 +- 不再保留任何工作流事件、phase/log 协议消息、run-id 生成器、仅服务于进度的元数据、host 配对账本或 fatal 模式分支。 +- run handle 不再有 id/meta 回显,取消在同步 `start()` 返回后只有一条持有者拥有的通道。 +- parallel/pipeline 行为、上限、取消静默、worker 隔离、结构化输出以及面向模型的工作流场景保持覆盖率。 +- 类型检查、覆盖率、快照、doc-sync、module-graph 校验、构建与 hygiene 全部通过。 + +## 风险 + +这是对工作流 DSL、事件分类体系、handle 与 start request 的编译可见收缩。现有提供描述性元数据的工作流调用,以及使用 `phase`、`log` 或 label 的脚本,必须相应精简;程序化调用方需自行将 abort 源桥接到返回的 handle;未来的观察者必须添加一个关联性更好的 seam。使工作流真正有用的执行语义不变。 diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml new file mode 100644 index 0000000000..1fb7c5343a --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-12-prune-unused-skill-registry-surface.md: 3e8c009871c3d609612b4a01edc2048ddedfad0d +2026-07-12-prune-unused-skill-registry-surface.zh.md: 1412e3cfac1adbb8b563ad50edb08c53a719feb8 diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md index cafd50e8a5..3e8c009871 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md @@ -1,5 +1,7 @@ # RFC: Prune unused skill registry surface +English | [中文](2026-07-12-prune-unused-skill-registry-surface.zh.md) + Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins. ## Problem diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md new file mode 100644 index 0000000000..1412e3cfac --- /dev/null +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md @@ -0,0 +1,29 @@ +# RFC:裁剪未使用的 skill 注册表接口 + +Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins. + +[English](2026-07-12-prune-unused-skill-registry-surface.md) | 中文 + +## 问题 + +skill 服务的嵌入式运行时子系统没有任何生产调用方调用 `ctx.skills.register()`。它引入了一个保留的 `runtime` 提供方名称、一套运行时 map/rank/source、重复策略、缓存键中的第二个 revision、规范化逻辑、dispose 函数和测试,而这些都与每个已交付 skill 实际使用的提供方 seam 并行存在。`SkillSummary.whenToUse` 以及 candidate/definition 上的 `path` 被解析和复制,但没有任何生产消费方读取它们:模型目录只渲染 name/description,资源加载使用 `resourceBase`,提供方自行管理其定位符。刻意开放的 `metadata` 扩展点保留不动。 + +## 提案 + +移除 `SkillService.register()`、`SkillRegistration`、运行时伪提供方及保留名称规则、运行时 revision/缓存分支,以及仅用于运行时的 source/rank 规范化逻辑。需要嵌入式 skill 的测试改为注册一个小型真实提供方。保留 `providerRevision` 作为进行中的发现纪元,但已完成的目录仅以 cwd 为键:每次提供方变更都同步清除缓存,await 之后的 revision 比较已能阻止插入陈旧结果。从 skill 契约和本地提供方副本中移除 `whenToUse`、`SkillCandidate.path` 和 `SkillDefinition.path`,同时保留提供方的 locator/root 路径;保留 `metadata`、`disableModelInvocation`、`source`、`provider`、`locator` 和 `resourceBase`,它们要么是刻意的扩展词汇,要么是生产中被消费的字段。 + +同步修订 skill 系统 RFC、README、JSDoc、目录文件和测试。agent 作用域的系统提示词段落、工具提供方和变量明确不在本提案范围内:[agent 作用域贡献者契约](../../implemented/architecture/2026-07-08-agent-scope-contexts.md)有意允许在 `setup(agentCtx)` 期间通过 agent 拥有的上下文注册这三者,因此仓库内没有固定的作用域注册并不能证明无人消费。 + +## 曾考虑的替代方案 + +**为嵌入方保留运行时 skill 注册。** 这是已实现的 skill RFC 中一个刻意设计的同步直接定义便利接口。一个小型提供方包装层可以在 effect 拥有的生命周期下暴露相同的嵌入数据,但它必须实现异步 `list()`/`get()`、携带提供方身份、并接受提供方的重复语义。本提案选择保留一条统一的提供方路径,而非维护第二套排序、校验、缓存失效和查找路径。 + +## 验收标准 + +- skill 收集只有一条提供方驱动的路径;已完成缓存的键仅为 cwd;revision 纪元仅用于进行中的失效;保留的 skill 字段要么有生产读取方,要么有记录在案的刻意扩展契约。 +- agent 作用域的 prompt 段落、变量、工具提供方、工具守卫,以及原生模式和 Code Mode 下的结构化输出提交行为保持不变。 +- 类型检查、覆盖率、快照、doc-sync、module-graph 校验、构建和 hygiene 全部通过。 + +## 风险 + +这是对预发布 skill 注册表的一次编译可见的收缩。外部编程式 `list()`/`get()` 消费方将失去 `whenToUse` 路由提示和 candidate/definition 上的 `path`;已交付的模型目录从未渲染它们,资源解析保留了显式的 `resourceBase` 加上提供方自有的不透明 locator,但这些字段在可观测性上并不等价。skill 本地的 frontmatter 解析必须继续保留并校验所支持的 metadata schema,外部提供方仍可提供嵌入式、文件系统、远程或其他 skill 来源。 diff --git a/scripts/translation-pairing.manifest.json b/scripts/translation-pairing.manifest.json index be766dbaad..97d92459f2 100644 --- a/scripts/translation-pairing.manifest.json +++ b/scripts/translation-pairing.manifest.json @@ -37,8 +37,154 @@ "docs/postmortem/0002-js-expression-disabled-filesystem-tools.md", "docs/postmortem/README.md", "docs/rfc/README.md", + "docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md", + "docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md", + "docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md", + "docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md", + "docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md", + "docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md", + "docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md", + "docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md", + "docs/rfc/implemented/architecture/2026-06-13-capability-seams.md", + "docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md", + "docs/rfc/implemented/architecture/2026-06-14-session-persistence.md", + "docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md", + "docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md", + "docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md", + "docs/rfc/implemented/architecture/2026-06-18-session-surface.md", + "docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md", + "docs/rfc/implemented/architecture/2026-06-20-branded-ids.md", + "docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md", + "docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md", + "docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md", + "docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md", + "docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md", + "docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md", + "docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md", + "docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md", + "docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md", + "docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md", + "docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md", + "docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md", + "docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md", + "docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md", + "docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md", + "docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md", "docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md", + "docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md", + "docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md", + "docs/rfc/implemented/feature/2026-06-15-code-mode.md", + "docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md", + "docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md", + "docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md", + "docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md", + "docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md", + "docs/rfc/implemented/feature/2026-06-25-ask-user-question.md", + "docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md", + "docs/rfc/implemented/feature/2026-06-30-hook-bridges.md", + "docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md", + "docs/rfc/implemented/feature/2026-06-30-interception-seams.md", + "docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md", + "docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md", + "docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md", + "docs/rfc/implemented/feature/2026-07-05-skill-system.md", + "docs/rfc/implemented/feature/2026-07-06-approval-seam.md", + "docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md", + "docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md", + "docs/rfc/implemented/feature/2026-07-07-session-prefix.md", + "docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md", + "docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md", + "docs/rfc/implemented/feature/2026-07-10-session-query-service.md", + "docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md", + "docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md", + "docs/rfc/implemented/process/2026-06-11-quality-gates.md", + "docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md", + "docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md", + "docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md", + "docs/rfc/implemented/process/2026-06-17-ts-build-config.md", + "docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md", + "docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md", + "docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md", + "docs/rfc/implemented/process/2026-06-20-rfc-classification.md", "docs/rfc/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md", + "docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md", + "docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md", + "docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md", + "docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md", + "docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md", + "docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md", + "docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md", + "docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md", + "docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md", + "docs/rfc/implemented/process/2026-07-06-node-engine-floor.md", + "docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md", + "docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md", + "docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md", + "docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md", + "docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md", + "docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md", + "docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md", + "docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md", + "docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md", + "docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md", + "docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md", + "docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md", + "docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md", + "docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md", + "docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md", + "docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md", + "docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md", + "docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md", + "docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md", + "docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md", + "docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md", + "docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md", + "docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md", + "docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md", + "docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md", + "docs/rfc/implemented/testing/2026-06-11-property-based-testing.md", + "docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md", + "docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md", + "docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md", + "docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md", + "docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md", + "docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md", + "docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md", + "docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md", + "docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md", + "docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md", + "docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md", + "docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md", + "docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md", + "docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md", + "docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md", + "docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md", + "docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md", + "docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md", + "docs/rfc/proposed/process/2026-06-11-architectural-conformance.md", + "docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md", + "docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md", + "docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md", + "docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md", + "docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md", + "docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md", + "docs/rfc/proposed/testing/2026-06-11-mutation-testing.md", + "docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md", + "docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md", + "docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md", + "docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md", + "docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md", + "docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md", + "docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md", + "docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md", + "docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md", + "docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md", + "docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md", + "docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md", + "docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md", + "docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md", + "docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md", + "docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md", "docs/testing.md", "python/README.md", "python/sdk-runtime/README.md", @@ -58,6 +204,8 @@ "docs/module-graph.md", "docs/persistence-catalog.md", "docs/rfc/INDEX.md", + "docs/rfc/implemented/AGENTS.md", + "docs/rfc/implemented/CLAUDE.md", "docs/tool-catalog.md", "docs/tool-execution-pipeline.md", "python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/" From 60fcb494a763dec5ad8e431f922e016799cb529f Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Thu, 16 Jul 2026 00:19:25 -0700 Subject: [PATCH 013/368] docs(i18n): restore prompt-v4 as the pipeline baseline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按 jingtingxiang 拍板将 prompt 回到 v4 基线:模板正文恢复内嵌的 格式/语气/句式/词汇/标点全量约束与 11 组正误例(量词规则按术语表 现行裁定 package→包 写作「由三个包构成的 seam」),不再注入 translation-rules.md——该文件约束人和 agent,不进模板;占位符收敛 为 source_lang/target_lang/terminology 三个,切换行由模型按文档 自身拼写。渲染器、解析器、conformance 门禁与单测同步回 v4 契约: 三段裸 XML(translation/review/final 顺序唯一),容忍整体 ```xml 围栏回显;saxes 依赖随 CDATA 协议一并移除。 --- docs/i18n/translation-prompt.md | 168 +++++++++++++++++++-------- package.json | 1 - pnpm-lock.yaml | 22 ++-- scripts/translation-prompt.spec.ts | 87 +++++--------- scripts/translation-prompt.ts | 144 +++++++---------------- scripts/verify-translation-prompt.ts | 28 ++--- 6 files changed, 213 insertions(+), 237 deletions(-) diff --git a/docs/i18n/translation-prompt.md b/docs/i18n/translation-prompt.md index 8bc15d6e8e..d59170b00a 100644 --- a/docs/i18n/translation-prompt.md +++ b/docs/i18n/translation-prompt.md @@ -1,6 +1,6 @@ # Translation prompt (pipeline asset) -本文件是自动翻译流水线使用的 prompt 模板;从 `# Translation Prompt` 开始的正文会逐字进入模型请求,因此本文件不参与双语配对(见 [README.md](README.md) 排除清单)。渲染时会把 [translation-rules.md](translation-rules.md) 全文填入 `{{translation_rules}}`,把 [terminology.md](terminology.md) 整表填入 `{{terminology}}`,以免模板另存一份规则而日后失去同步。[style-samples.md](style-samples.md) 定义文体,模板中的 Examples 只用于说明典型问题;术语表、忠实性和结构规则优先于样例,样例只在这些硬性约束内决定文体。修改本文件会改变翻译行为,需正常经过 PR 评审。 +本文件是自动翻译流水线的 prompt 模板;从 `# Translation Prompt` 开始的正文会逐字进入模型请求,因此本文件不参与双语配对(见 [README.md](README.md) 排除清单)。模板正文与内嵌 few-shot 正误例由 jingtingxiang 基于对存量译文的质量评审撰写,是流水线行为的拍板基线。渲染时把 [terminology.md](terminology.md) 整表填入 `{{terminology}}`;除此之外不注入任何其他仓库文件(translation-rules.md 约束人和 agent 的翻译工作,不注入本模板)。[style-samples.md](style-samples.md) 定义文体,模板中的 Examples 只用于说明典型问题,两者冲突时以文体样例为准。修改本文件会改变翻译行为,需正常经过 PR 评审。 ## 占位符契约 @@ -10,18 +10,13 @@ |---|---|---| | `{{source_lang}}` | 源语言名(`English` / `Chinese`) | 由改动侧文件推断:`.zh.md` 被改则为 `Chinese` | | `{{target_lang}}` | 目标语言名(`Chinese` / `English`) | 与 `{{source_lang}}` 相对 | -| `{{translation_rules}}` | [translation-rules.md](translation-rules.md) 全文(Markdown 原文) | 渲染时读取仓库当前版本,不缓存 | | `{{terminology}}` | [terminology.md](terminology.md) 的完整表格(Markdown 原文) | 渲染时读取仓库当前版本,不缓存 | -| `{{source_filename}}` | 源文档的 basename(如 `foo.md` 或 `foo.zh.md`) | 由流水线从待译文件路径取得 | -| `{{source_filename_zh}}` | 中文侧 basename(如 `foo.zh.md`) | 英文源追加 `.zh`;中文源使用自身 basename | -例如,英译中时若源文件是 `foo.md`,`{{source_filename}}` 填 `foo.md`,`{{source_filename_zh}}` 填 `foo.zh.md`;中译英时若源文件是 `foo.zh.md`,两个占位符都填 `foo.zh.md`。 - -流水线只识别上表中的占位符,并且一次翻译整篇文档。它不支持 `{{to}}`、`{{title_prompt}}`、`{{summary_prompt}}`、`{{terms_prompt}}`、`{{imt_style_guide}}` 或 `%%` 分段协议。输出必须是一个以 `<dsh-translation-response>` 为根元素的 XML 文档;三个子元素中的 Markdown 内容都放在 CDATA 中。内容出现 `]]>` 时写成 `]]]]><![CDATA[>`,XML 解析后仍会还原为原文。 +流水线只识别上表中的占位符,并且一次翻译整篇文档。它不支持 `{{to}}`、`{{title_prompt}}`、`{{summary_prompt}}`、`{{terms_prompt}}`、`{{imt_style_guide}}`、`{{translation_rules}}` 或 `%%` 分段协议;输出采用模板正文规定的三段 XML,流水线解析取 `<final>` 段。 ## Few-shot 金标 -流水线使用**整篇文档**的中英对照作为 few-shot,不是模板内嵌的句子级正误例。以下 5 组配对文档均经过人工评审,并以仓库当前版本为准,随仓库一同更新: +流水线使用**整篇文档**的中英对照作为 few-shot,不是模板内嵌的句子级正误例。以下 5 组配对文档均经过人工评审,以仓库当前版本为准、随仓库更新: - `README.md` ↔ `README.zh.md` - `docs/development.md` ↔ `docs/development.zh.md` @@ -29,58 +24,131 @@ - `docs/i18n/translation-rules.md` ↔ `docs/i18n/translation-rules.zh.md` - `docs/rfc/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md` ↔ 对应 `.zh.md` -注入时按当前翻译方向选择每组的源侧与目标侧:user 消息包含源文档全文,assistant 消息采用模板正文规定的 XML 协议;`translation` 与 `final` 都放入目标文档全文,`review` 填 `- [None] No corrections.`。CDATA 遵循上文的 `]]>` 拆分规则。上下文不足时,按上列顺序从后往前删减示例组数。这 5 组也是评审校准锚点;改动任何一组都会改变流水线行为。 +注入方式:在系统消息(本模板)之后、待译文档之前,每组作为一轮示例对话——user 消息为源文档全文,assistant 消息为定稿译文全文(裸文本,不带三段 XML 包装;只有真实请求要求三段输出)。上下文不足时按上列顺序从后往前删减组数。这 5 组也是评审校准锚点(见 [style-samples.md](style-samples.md)),改动任何一组即改变流水线行为。 ## 模板正文 ````text # Translation Prompt -You are a senior technical translator specializing in LLM and agent development documentation. Translate the complete source document from {{source_lang}} to {{target_lang}} as natural, professional technical prose. +You are a senior technical translator specializing in LLM and agent development documentation. Your task is to translate the given source document from {{source_lang}} to {{target_lang}}, producing natural, professional technical prose. -## Binding Translation Rules +## Quality Requirements -The canonical repository rules below are injected verbatim. Apply every direction-appropriate requirement. In those rules, the authored document is the source for this request and the generated document is its counterpart. +### Structure and Format Preservation +- Output a complete translated document that maintains exactly the same structure as the source: heading hierarchy, list shape, table columns, link targets, and code blocks. +- Fenced code blocks must be byte-identical to the source, including ALL comments inside them. Do NOT translate comments inside code blocks. This is a hard rule with no exceptions. +- Inline code spans (commands, flags, paths, API names, version numbers) must be kept verbatim. Never translate or reformat them. +- Every relative link must point to the same target as in the source. Link text is translated; link targets are not. +- Language switcher line: when translating into Chinese, write `[English](source-filename.md) | 中文`. When translating into English, write `English | [中文](source-filename.zh.md)`. Do NOT copy the switcher line from the source file unchanged — you must flip the link direction. +- After a closing bold marker `**`, always insert a space before the next character. -{{translation_rules}} +### Tone and Style +- The translation must read as if originally written in the target language by a native speaker. If an expression sounds like a word-for-word rendering from the source language, rephrase it. +- Write in a professional, formal tone appropriate for developer documentation. Never use colloquial or casual expressions. +- Use polite imperative forms where the text instructs the reader to do something. +- Keep the author's register: concise stays concise, detailed stays detailed. -## Request-Specific Structure +### Sentence Structure +- Break long sentences with commas or semicolons. Avoid run-on sentences. +- Prefer active voice. Convert passive constructions to active if it reads more naturally. +- Translate meaning, not words. Restructure sentences where the target language grammar requires it. +- Do not invent words or expressions that do not exist in natural technical writing of the target language. -- The source basename is `{{source_filename}}`. When translating into Chinese, write `[English]({{source_filename}}) | 中文` immediately after the H1. When translating into English, write `English | [中文]({{source_filename_zh}})` immediately after the H1. -- Emit the switcher for a new pair and flip an existing switcher; never copy it unchanged. +### Word Choice +- Prefer precise, formal vocabulary over casual or colloquial alternatives. +- When multiple synonyms exist, choose the one most commonly used in professional technical documentation of the target language. +- Avoid slang, internal jargon, or overly literal translations that would not be recognized by the general developer audience. +- Do not use the same word to translate two different source-language terms that carry distinct meanings. +- Avoid repeating the same verb in close proximity; vary word choice for readability. -## Binding Terminology +#### When translating into Chinese +- When a number modifies a noun, always include a Chinese classifier or measure word (量词). For example: "three-package seam" → "由三个包构成的 seam", not "三包 seam". -Apply the current table below exactly as required by the injected translation rules. +### Punctuation + +#### When translating into Chinese +- Use full-width Chinese punctuation in prose: `,。:;?!()「」`. +- Strongly prefer replacing all em-dashes (——) with colons, periods, commas, or parentheses. Keep an em-dash only if no other punctuation works at all. +- Use enumeration commas (、) between parallel items, not regular commas. +- List item endings: use semicolons or no punctuation. Do not end list items with commas. +- Put one half-width space between Chinese text and Latin words/numbers. +- For RFC 2119 keywords (MUST, MUST NOT, SHOULD, MAY), render the corresponding Chinese term in italics: *必须*、*禁止*、*应当*、*可以*. + +#### When translating into English +(To be added.) + +## Terminology + +A terminology table is provided below. Follow it strictly: +- Render every listed term exactly as specified. +- First occurrence: write as shown in the "首次出现" column (with parenthetical gloss). Subsequent occurrences: write only the part before the parentheses. +- If a term has already been glossed as part of a compound term, do not gloss it again when it appears alone later. +- NEVER use translations listed in the "不要译作" column. +- For technical terms not in the table: keep them in the source language. Do not invent a translation. This rule applies to terminology only; for general prose, freely restructure and paraphrase for natural expression. {{terminology}} ## Output Format -Return exactly one well-formed XML document with this root and these three child elements. Do not wrap it in a Markdown code fence. Put all Markdown and review text inside CDATA. If any content contains the CDATA terminator, split it as `]]]]><![CDATA[>` so XML parsing reconstructs the original `]]>` sequence. +Produce your output in three XML sections: ```xml -<dsh-translation-response version="1"> -<translation><![CDATA[ -(Complete first-pass translation) -]]></translation> -<review><![CDATA[ -- [Tone] Replaced a literal rendering with the established target-language phrasing. -- [Terminology] Applied the binding sidecar record term. -]]></review> -<final><![CDATA[ -(Complete corrected translation) -]]></final> -</dsh-translation-response> +<translation> +(Complete translation of the source document) +</translation> + +<review> +(Self-review notes, one correction per line with category tag, e.g.) +- [Tone] "旁挂记录" → "伴随记录"(生造词) +- [Sentence] 第 3 段补充逗号断句 +- [Punctuation] 两处破折号替换为冒号 +- 无修正 +</review> + +<final> +(Final translation after corrections) +</final> ``` ## Self-Review Instructions -After writing `<translation>`, re-read it in the target language without looking at the source. Then apply the injected translation rules as a clause-by-clause comparison against the source and record actual corrections in English inside `<review>`. Apply every recorded correction in `<final>`. If no correction is needed, write only `- [None] No corrections.` in `<review>` and copy `<translation>` unchanged into `<final>`. +After writing `<translation>`, re-read it in the target language only, without looking at the source. Check by category: + +**Structure** +- Is the heading hierarchy, list shape, and code block content identical to the source? +- Are ALL comments inside code blocks left untranslated (byte-identical to source)? +- Is the language switcher line correctly flipped (not copied from source)? +- Are link targets preserved and bold markers followed by a space? + +**Tone & Style** +- Does every sentence read as if originally written by a native speaker? +- Is there any colloquial, casual, or overly informal phrasing? + +**Sentence Structure** +- Are there run-on sentences that need breaking? +- Are there stiff passive constructions that should be converted to active voice? + +**Word Choice** +- Are there overly literal translations that sound unnatural? +- Is the same target-language word used to translate two distinct source concepts? +- Is any slang or internal jargon present? + +**Terminology** +- Are first-occurrence glosses correctly applied (not missing, not repeated)? +- Are any "不要译作" forbidden translations present? +- Are unlisted terms correctly kept in the source language? + +**Punctuation** (when target is Chinese) +- Are there em-dashes that should be replaced with colons, periods, or commas? +- Are list items ending with commas instead of semicolons? +- Are RFC 2119 keywords rendered in italics? + +Record corrections in `<review>` with category tags. Then output the corrected version in `<final>`. If no corrections are needed, write "无修正" in `<review>` and copy the translation unchanged into `<final>`. ## Examples -Follow the Good versions; these sentence-level examples illustrate error categories, not the assistant-message wire format. +Below are representative examples of common problems and their corrections. Follow the "Good" versions. ### Colloquial verb → Professional verb - Source: `The repo pins pnpm@11.7.0 in package.json` @@ -102,40 +170,40 @@ Follow the Good versions; these sentence-level examples illustrate error categor - Bad: `旁挂记录两侧 blob hash,使一致性可检查` - Good: `伴随记录保存两侧 blob hash,使一致性可检查` +### Em-dash → Colon/period +- Source: `FIXME — an issue that should block a new release. A release should not ship with an open FIXME unless reviewers explicitly agree the change can be merged anyway.` +- Bad: `FIXME——应当阻塞新版本发布的问题。除非评审者明确同意可以照常合入,发布不应带着未解决的 FIXME 出门。` +- Good: `FIXME:应当阻塞新版本发布的问题。除非评审者明确同意该更改可以合并,否则发布版本不应包含未解决的 FIXME。` + ### Overly literal → Meaningful rendering - Source: `awkward phrasing is easier to hear without the source anchoring you` - Bad: `没有源文锚着,别扭的表述更容易被听出来` - Good: `不对照原文时,更容易察觉别扭的表达` -### Terminology — keep the binding English form +### Terminology — do not translate what should be kept in English - Source: `typed service seams, and explicit extension points` - Bad: `类型化的服务 seam(扩展点)与显式扩展点` - Good: `类型化的服务 seam 与显式扩展点` -### Slang → Professional phrasing +### Slang/jargon → Professional phrasing - Source: `The committed agent workflow lives in .agents/skills/dsh-translate-docs` - Bad: `进仓的 agent 工作流见 .agents/skills/dsh-translate-docs` - Good: `仓库内置的 agent 工作流见 .agents/skills/dsh-translate-docs` -### Chinese → English — idiomatic subject and predicate -- Source: `门禁绿并不代表译文内容正确。` -- Bad: `The gate green does not represent that the translation content is correct.` -- Good: `A green gate does not mean the translation is correct.` +### "For humans" — translate the intent, not the word +- Source: `For humans, start with the development guide` +- Bad: `对于人工读者,请先从开发指南开始`("人工读者"生硬) +- Good: `面向开发者:请先阅读开发指南`("开发者"自然,且中文里冒号在此处更自然) -### Code block comments — never translate +### Code block comments — NEVER translate - Source code block contains: `# REPL agent demo (needs DEEPSEEK_API_KEY)` - Bad: `# REPL agent 演示(需要 DEEPSEEK_API_KEY)` -- Good: `# REPL agent demo (needs DEEPSEEK_API_KEY)` (byte-identical) +- Good: `# REPL agent demo (needs DEEPSEEK_API_KEY)` (keep exactly as-is, byte-for-byte) -### Language switcher — English to Chinese -- Source: `English | [中文](README.zh.md)` -- Bad: `English | [中文](README.zh.md)` -- Good: `[English](README.md) | 中文` - -### Language switcher — Chinese to English -- Source: `[English](README.md) | 中文` -- Bad: `[English](README.md) | 中文` -- Good: `English | [中文](README.zh.md)` +### Language switcher — flip direction +- Source file (English) has: `English | [中文](README.zh.md)` +- Bad (copying source unchanged): `English | [中文](README.zh.md)` +- Good (flipped for Chinese file): `[English](README.md) | 中文` --- diff --git a/package.json b/package.json index aaec1e62c4..51fd789a2b 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,6 @@ "mermaid": "11.16.0", "micromark-extension-gfm": "^3.0.0", "publint": "^0.3.21", - "saxes": "^6.0.0", "tsdown": "^0.22.2", "tsx": "^4.22.4", "typescript": "^6.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1a3a78030..0e71da2ea1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,9 +68,6 @@ importers: publint: specifier: ^0.3.21 version: 0.3.21 - saxes: - specifier: ^6.0.0 - version: 6.0.0 tsdown: specifier: ^0.22.2 version: 0.22.2(oxc-resolver@11.20.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3) @@ -819,7 +816,7 @@ importers: dependencies: '@earendil-works/pi-ai': specifier: ^0.79.1 - version: 0.79.3(ws@8.21.0)(zod@4.4.3) + version: 0.79.3(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(ws@8.21.0)(zod@4.4.3) schemastery: specifier: ^3.18.0 version: 3.18.0 @@ -3059,6 +3056,10 @@ packages: cpu: [x64] os: [win32] + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -6137,11 +6138,11 @@ snapshots: '@csstools/css-tokenizer@4.0.0': {} - '@earendil-works/pi-ai@0.79.3(ws@8.21.0)(zod@4.4.3)': + '@earendil-works/pi-ai@0.79.3(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(ws@8.21.0)(zod@4.4.3)': dependencies: '@anthropic-ai/sdk': 0.91.1(zod@4.4.3) '@aws-sdk/client-bedrock-runtime': 3.1048.0 - '@google/genai': 1.52.0 + '@google/genai': 1.52.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)) '@mistralai/mistralai': 2.2.1 '@smithy/node-http-handler': 4.7.3 http-proxy-agent: 7.0.2 @@ -6299,12 +6300,14 @@ snapshots: '@exodus/bytes@1.15.1': {} - '@google/genai@1.52.0': + '@google/genai@1.52.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))': dependencies: google-auth-library: 10.7.0 p-retry: 4.6.2 protobufjs: 7.6.4 ws: 8.21.0 + optionalDependencies: + '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) transitivePeerDependencies: - bufferutil - supports-color @@ -6563,6 +6566,9 @@ snapshots: '@oxc-resolver/binding-win32-x64-msvc@11.20.0': optional: true + '@pkgjs/parseargs@0.11.0': + optional: true + '@protobufjs/aspromise@1.1.2': {} '@protobufjs/base64@1.1.2': {} @@ -8034,6 +8040,8 @@ snapshots: jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 jiti@2.7.0: {} diff --git a/scripts/translation-prompt.spec.ts b/scripts/translation-prompt.spec.ts index 93754a79a1..db3f8b31a0 100644 --- a/scripts/translation-prompt.spec.ts +++ b/scripts/translation-prompt.spec.ts @@ -1,5 +1,7 @@ -/** Regression tests for the executable translation prompt contract. */ +/** Unit tests for the prompt-v4 renderer and three-section response parser. */ +import { readFileSync } from 'node:fs' +import { join, resolve } from 'node:path' import { describe, expect, it } from 'vitest' import { parseTranslationResponse, @@ -7,70 +9,43 @@ import { renderTranslationResponse, } from './translation-prompt.ts' -const document = `# Wrapper - -## 模板正文 - -\`\`\`\`text -{{source_lang}} to {{target_lang}} -{{translation_rules}} -{{terminology}} -[English]({{source_filename}}) | [中文]({{source_filename_zh}}) -\`\`\`\` -` +const root = resolve(import.meta.dirname, '..') +const document = readFileSync(join(root, 'docs/i18n/translation-prompt.md'), 'utf8') +const terminology = '| English | 中文 |\n|---|---|\n| agent | agent |' describe('translation prompt rendering', () => { - it('renders every supported placeholder without recursively rewriting injected rules', () => { - const rendered = renderTranslationPrompt(document, { - sourceLanguage: 'English', - sourceFilename: 'guide.md', - translationRules: 'A literal {{source_lang}} in injected rules.', - terminology: '| English | 中文 |', - }) - expect(rendered).toContain('English to Chinese') - expect(rendered).toContain('A literal {{source_lang}} in injected rules.') - expect(rendered).toContain('[English](guide.md) | [中文](guide.zh.md)') + it('renders both directions with every placeholder resolved', () => { + const en = renderTranslationPrompt(document, { sourceLanguage: 'English', terminology }) + expect(en).toContain('from English to Chinese') + expect(en).toContain(terminology) + expect(en).not.toContain('{{') + const zh = renderTranslationPrompt(document, { sourceLanguage: 'Chinese', terminology }) + expect(zh).toContain('from Chinese to English') }) - it('rejects a filename whose suffix contradicts the source language', () => { - expect(() => renderTranslationPrompt(document, { - sourceLanguage: 'Chinese', - sourceFilename: 'guide.md', - translationRules: 'rules', - terminology: 'terms', - })).toThrow('does not match source language Chinese') - }) - - it('rejects malformed template placeholders before injecting rule contents', () => { - expect(() => renderTranslationPrompt(document.replace('{{source_lang}}', '{{source-lang}}'), { - sourceLanguage: 'English', - sourceFilename: 'guide.md', - translationRules: 'A literal {{source_lang}} in injected rules.', - terminology: '| English | 中文 |', - })).toThrow('template contains malformed placeholder syntax') + it('rejects a template with unknown or missing placeholders', () => { + const alien = document.replaceAll('{{terminology}}', '{{terms_prompt}}') + expect(() => renderTranslationPrompt(alien, { sourceLanguage: 'English', terminology })).toThrow(/unsupported placeholder/) + const missing = document.replaceAll('{{terminology}}', '') + expect(() => renderTranslationPrompt(missing, { sourceLanguage: 'English', terminology })).toThrow(/required placeholder/) }) }) -describe('translation response XML', () => { - it('round-trips Markdown and the CDATA terminator', () => { - const response = { - translation: '# Draft\n\nA ]]> marker.', - review: '- [Tone] Fixed.', - final: '# Final\n\nA ]]> marker.', - } +describe('translation response sections', () => { + it('round-trips Markdown bodies', () => { + const response = { translation: '# 标题\n\n正文 **加粗**。', review: '- [Tone] 修正一处。\n- 无修正', final: '# 标题\n\n定稿。' } expect(parseTranslationResponse(renderTranslationResponse(response))).toEqual(response) }) - it('rejects missing, reordered, nested, attributed, or non-CDATA children', () => { - expect(() => parseTranslationResponse('<dsh-translation-response version="1"/>')).toThrow('translation, review, and final') - expect(() => parseTranslationResponse('<dsh-translation-response version="1"><review><![CDATA[x]]></review></dsh-translation-response>')) - .toThrow('expected translation, got review') - expect(() => parseTranslationResponse(renderTranslationResponse({ translation: 'x', review: 'y', final: 'z' }) - .replace('<translation><![CDATA[x]]></translation>', '<translation><b><![CDATA[x]]></b></translation>'))) - .toThrow('nested element b is not allowed') - expect(() => parseTranslationResponse(renderTranslationResponse({ translation: 'x', review: 'y', final: 'z' }).replace('<review>', '<review lang="en">'))) - .toThrow('review must not have attributes') - expect(() => parseTranslationResponse(renderTranslationResponse({ translation: 'x', review: 'y', final: 'z' }).replace('<![CDATA[x]]>', 'x'))) - .toThrow('all response field content must be inside CDATA') + it('tolerates a fenced xml wrapper around the whole response', () => { + const fenced = '```xml\n<translation>\nA\n</translation>\n\n<review>\n- 无修正\n</review>\n\n<final>\nA\n</final>\n```' + expect(parseTranslationResponse(fenced).final).toBe('A') + }) + + it('rejects missing, unterminated, or duplicated sections', () => { + expect(() => parseTranslationResponse('<translation>\nA\n</translation>')).toThrow(/missing <review>/) + expect(() => parseTranslationResponse('<translation>\nA')).toThrow(/unterminated <translation>/) + const dup = '<translation>\nA\n</translation>\n<review>\nR\n</review>\n<final>\nF\n</final>\n<final>\nG\n</final>' + expect(() => parseTranslationResponse(dup)).toThrow(/duplicate <final>/) }) }) diff --git a/scripts/translation-prompt.ts b/scripts/translation-prompt.ts index e30c962498..0556ff39fa 100644 --- a/scripts/translation-prompt.ts +++ b/scripts/translation-prompt.ts @@ -1,20 +1,16 @@ /** - * Executable renderer and strict response parser for the committed - * documentation-translation prompt contract. + * Executable renderer and response parser for the committed + * documentation-translation prompt contract (prompt-v4). + * + * The v4 contract: three placeholders (`source_lang`, `target_lang`, + * `terminology`), whole-document translation, and a three-section response + * (`<translation>`, `<review>`, `<final>` in order, bare XML tags with raw + * Markdown bodies). The switcher filename is spelled out by the model from + * the document itself; the pipeline injects no other repository file. */ -import { basename } from 'node:path' -import { SaxesParser } from 'saxes' - /** Placeholder names supported by the committed translation prompt. */ -export const TRANSLATION_PROMPT_PLACEHOLDERS = [ - 'source_lang', - 'target_lang', - 'translation_rules', - 'terminology', - 'source_filename', - 'source_filename_zh', -] as const +export const TRANSLATION_PROMPT_PLACEHOLDERS = ['source_lang', 'target_lang', 'terminology'] as const type TranslationPromptPlaceholder = (typeof TRANSLATION_PROMPT_PLACEHOLDERS)[number] @@ -24,15 +20,11 @@ type TranslationLanguage = 'English' | 'Chinese' /** Inputs that vary for one rendered translation request. */ export interface TranslationPromptInput { sourceLanguage: TranslationLanguage - /** Source basename, including `.md` or `.zh.md`. */ - sourceFilename: string - /** Complete current `translation-rules.md` contents. */ - translationRules: string /** Complete current `terminology.md` contents. */ terminology: string } -/** Parsed contents of the three-element XML response. */ +/** Parsed contents of the three-section response. */ export interface TranslationResponse { translation: string review: string @@ -42,7 +34,7 @@ export interface TranslationResponse { const PLACEHOLDER = /{{([a-z_]+)}}/g const TEMPLATE_OPEN = '## 模板正文\n\n````text\n' const TEMPLATE_CLOSE = '\n````' -const RESPONSE_CHILDREN = ['translation', 'review', 'final'] as const +const RESPONSE_SECTIONS = ['translation', 'review', 'final'] as const /** Extract the machine-consumed text fence from `translation-prompt.md`. */ function extractTranslationPrompt(document: string): string { @@ -61,31 +53,15 @@ export function documentedTranslationPromptPlaceholders(document: string): strin return [...document.slice(0, preambleEnd).matchAll(/^\| `{{([a-z_]+)}}` \|/gm)].map(match => match[1] ?? '') } -/** Render one system prompt from the checked-in template and canonical rules. */ +/** Render one system prompt from the checked-in template. */ export function renderTranslationPrompt(document: string, input: TranslationPromptInput): string { - if (basename(input.sourceFilename) !== input.sourceFilename) { - throw new Error(`translation prompt: sourceFilename must be a basename; got ${JSON.stringify(input.sourceFilename)}`) - } - const sourceIsChinese = input.sourceFilename.endsWith('.zh.md') - if (input.sourceLanguage === 'Chinese' ? !sourceIsChinese : sourceIsChinese || !input.sourceFilename.endsWith('.md')) { - throw new Error(`translation prompt: ${input.sourceFilename} does not match source language ${input.sourceLanguage}`) - } - const targetLanguage: TranslationLanguage = input.sourceLanguage === 'English' ? 'Chinese' : 'English' - const sourceFilenameZh = sourceIsChinese ? input.sourceFilename : input.sourceFilename.replace(/\.md$/, '.zh.md') const values: Record<TranslationPromptPlaceholder, string> = { source_lang: input.sourceLanguage, target_lang: targetLanguage, - translation_rules: input.translationRules, terminology: input.terminology, - source_filename: input.sourceFilename, - source_filename_zh: sourceFilenameZh, } const template = extractTranslationPrompt(document) - const placeholderFreeTemplate = template.replace(PLACEHOLDER, '') - if (placeholderFreeTemplate.includes('{{') || placeholderFreeTemplate.includes('}}')) { - throw new Error('translation prompt: template contains malformed placeholder syntax') - } const names = [...template.matchAll(PLACEHOLDER)].map(match => match[1] ?? '') const unknown = names.filter(name => !TRANSLATION_PROMPT_PLACEHOLDERS.includes(name as TranslationPromptPlaceholder)) if (unknown.length > 0) throw new Error(`translation prompt: unsupported placeholder(s): ${[...new Set(unknown)].join(', ')}`) @@ -95,77 +71,37 @@ export function renderTranslationPrompt(document: string, input: TranslationProm return template.replace(PLACEHOLDER, (_token, name: string) => values[name as TranslationPromptPlaceholder]) } -/** Escape one value so it remains byte-identical inside an XML CDATA field. */ -function escapeTranslationCdata(value: string): string { - return value.replaceAll(']]>', ']]]]><![CDATA[>') -} - -/** Serialize a response using the exact XML wire contract in the prompt. */ +/** Serialize a response in the exact three-section shape the prompt requests. */ export function renderTranslationResponse(response: TranslationResponse): string { - return [ - '<dsh-translation-response version="1">', - `<translation><![CDATA[${escapeTranslationCdata(response.translation)}]]></translation>`, - `<review><![CDATA[${escapeTranslationCdata(response.review)}]]></review>`, - `<final><![CDATA[${escapeTranslationCdata(response.final)}]]></final>`, - '</dsh-translation-response>', - ].join('\n') + return RESPONSE_SECTIONS.map(section => `<${section}>\n${response[section]}\n</${section}>`).join('\n\n') } -/** Parse and validate the exact XML response shape emitted by the model. */ -export function parseTranslationResponse(xml: string): TranslationResponse { - const values: TranslationResponse = { translation: '', review: '', final: '' } - const stack: string[] = [] - const cdataFields = new Set<string>() - let rootSeen = false - let childIndex = 0 - const fail = (message: string): never => { - throw new Error(`translation response: ${message}`) - } - const parser = new SaxesParser({ xmlns: false }) +/** + * Parse the three-section response. Sections must each appear exactly once + * and in order; bodies are raw Markdown taken verbatim between the tags. + * A fenced ```xml wrapper around the whole response is tolerated, matching + * the shape some models echo back from the prompt's own example. + */ +export function parseTranslationResponse(text: string): TranslationResponse { + let body = text.trim() + const fenced = /^```(?:xml)?\n([\s\S]*?)\n```$/.exec(body) + if (fenced?.[1] !== undefined) body = fenced[1].trim() - parser.on('opentag', (tag) => { - if (stack.length === 0) { - if (rootSeen) fail('contains more than one root element') - if (tag.name !== 'dsh-translation-response') fail(`expected dsh-translation-response root, got ${tag.name}`) - const attributes = Object.keys(tag.attributes) - if (attributes.length !== 1 || tag.attributes.version !== '1') fail('root must have only version="1"') - rootSeen = true - } else if (stack.length === 1) { - const expected = RESPONSE_CHILDREN[childIndex] - if (tag.name !== expected) fail(`expected ${expected ?? 'no more children'}, got ${tag.name}`) - if (Object.keys(tag.attributes).length !== 0) fail(`${tag.name} must not have attributes`) - childIndex++ - } else { - fail(`nested element ${tag.name} is not allowed`) - } - stack.push(tag.name) - }) - parser.on('text', (value) => { - if (stack.length <= 1 && value.trim() === '') return - fail('all response field content must be inside CDATA') - }) - parser.on('cdata', (value) => { - const field = stack.at(-1) - if (field === undefined || !RESPONSE_CHILDREN.includes(field as (typeof RESPONSE_CHILDREN)[number])) { - fail('CDATA is allowed only inside translation, review, or final') - } - const key = field as (typeof RESPONSE_CHILDREN)[number] - values[key] += value - cdataFields.add(key) - }) - parser.on('closetag', (tag) => { - const expected = stack.pop() - if (expected !== tag.name) fail(`closing ${tag.name} does not match ${expected ?? 'nothing'}`) - }) - parser.on('comment', () => fail('comments are not allowed')) - parser.on('doctype', () => fail('doctypes are not allowed')) - parser.on('processinginstruction', () => fail('processing instructions are not allowed')) - parser.on('error', error => fail(`invalid XML: ${error.message}`)) - parser.write(xml).close() - - if (childIndex !== RESPONSE_CHILDREN.length) fail('translation, review, and final must each appear exactly once and in order') - for (const field of RESPONSE_CHILDREN) { - if (!cdataFields.has(field)) fail(`${field} must contain a CDATA section`) + const values: Partial<Record<(typeof RESPONSE_SECTIONS)[number], string>> = {} + let cursor = 0 + for (const section of RESPONSE_SECTIONS) { + const open = `<${section}>` + const close = `</${section}>` + const start = body.indexOf(open, cursor) + if (start === -1) throw new Error(`translation response: missing <${section}> section`) + const end = body.indexOf(close, start + open.length) + if (end === -1) throw new Error(`translation response: unterminated <${section}> section`) + values[section] = body.slice(start + open.length, end).replace(/^\n/, '').replace(/\n$/, '') + cursor = end + close.length } - return values + for (const section of RESPONSE_SECTIONS) { + const again = body.indexOf(`<${section}>`, cursor) + if (again !== -1) throw new Error(`translation response: duplicate <${section}> section`) + } + return values as TranslationResponse } diff --git a/scripts/verify-translation-prompt.ts b/scripts/verify-translation-prompt.ts index 66d83e47ad..df72ac73ce 100644 --- a/scripts/verify-translation-prompt.ts +++ b/scripts/verify-translation-prompt.ts @@ -18,37 +18,27 @@ function read(path: string): string { try { const document = read('docs/i18n/translation-prompt.md') - const translationRules = read('docs/i18n/translation-rules.md') const terminology = read('docs/i18n/terminology.md') const documented = documentedTranslationPromptPlaceholders(document) if (documented.join('\n') !== TRANSLATION_PROMPT_PLACEHOLDERS.join('\n')) { throw new Error(`placeholder table must list exactly: ${TRANSLATION_PROMPT_PLACEHOLDERS.join(', ')}`) } - const englishSource = renderTranslationPrompt(document, { - sourceLanguage: 'English', - sourceFilename: 'example.md', - translationRules, - terminology, - }) - const chineseSource = renderTranslationPrompt(document, { - sourceLanguage: 'Chinese', - sourceFilename: 'example.zh.md', - translationRules, - terminology, - }) - if (!englishSource.includes('[English](example.md) | 中文')) throw new Error('English-source render does not carry the Chinese switcher instruction') - if (!chineseSource.includes('English | [中文](example.zh.md)')) throw new Error('Chinese-source render does not carry the English switcher instruction') + const englishSource = renderTranslationPrompt(document, { sourceLanguage: 'English', terminology }) + const chineseSource = renderTranslationPrompt(document, { sourceLanguage: 'Chinese', terminology }) + if (englishSource.includes('{{') || chineseSource.includes('{{')) throw new Error('rendered prompt contains an unresolved placeholder') + if (!englishSource.includes('from English to Chinese')) throw new Error('English-source render does not translate into Chinese') + if (!chineseSource.includes('from Chinese to English')) throw new Error('Chinese-source render does not translate into English') const example = /```xml\n([\s\S]*?)\n```/.exec(englishSource)?.[1] - if (example === undefined) throw new Error('rendered prompt has no XML response example') + if (example === undefined) throw new Error('rendered prompt has no three-section response example') parseTranslationResponse(example) - const roundTrip = { translation: 'first ]]> pass', review: '- [None] No corrections.', final: 'final ]]> text' } + const roundTrip = { translation: 'first pass\n\nwith **markdown**', review: '- 无修正', final: 'final text' } const parsed = parseTranslationResponse(renderTranslationResponse(roundTrip)) - if (JSON.stringify(parsed) !== JSON.stringify(roundTrip)) throw new Error('CDATA split rule does not round-trip response content') + if (JSON.stringify(parsed) !== JSON.stringify(roundTrip)) throw new Error('three-section response does not round-trip') - console.log('verify-translation-prompt: both directions render and the XML response contract parses.') + console.log('verify-translation-prompt: both directions render and the three-section response contract parses.') } catch (error) { const message = error instanceof Error ? error.message : String(error) console.error(`verify-translation-prompt: ${message}`) From 75e9958f11e941ef33753eba037915f6d92be6ec Mon Sep 17 00:00:00 2001 From: Hypatia May <hypatiamay@outlook.com> Date: Fri, 17 Jul 2026 09:39:39 +0800 Subject: [PATCH 014/368] fix(session-query): close review edge cases (round 4) --- docs/config-catalog.md | 8 +-- .../session-persistence-jsonl/src/index.ts | 26 ++++---- .../tests/jsonl.spec.ts | 33 ++++++++++ .../session-persistence-sqlite/README.md | 4 +- .../session-persistence-sqlite/src/index.ts | 11 +++- .../session-persistence-sqlite/src/schema.ts | 5 +- .../tests/sqlite.spec.ts | 25 +++++++- .../session-query-sqlite/README.md | 4 +- .../session-query-sqlite/src/index.ts | 62 +++++++++++++------ .../session-query-sqlite/src/query.ts | 25 +++++--- .../session-query-sqlite/tests/query.spec.ts | 10 ++- .../session-query-sqlite/tests/sqlite.spec.ts | 51 +++++++++++++++ 12 files changed, 213 insertions(+), 51 deletions(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index c4d5ecc523..6d141185ca 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -627,7 +627,7 @@ export interface Config { export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' ``` -Source: [`packages/session-persistence/session-persistence-sqlite/src/index.ts:39`](../packages/session-persistence/session-persistence-sqlite/src/index.ts) +Source: [`packages/session-persistence/session-persistence-sqlite/src/index.ts:40`](../packages/session-persistence/session-persistence-sqlite/src/index.ts) ## `@deepseek-ai/dsh-session-query` @@ -654,9 +654,9 @@ export interface Config { path: string /** SQLite journal mode. Defaults to `wal`. */ journalMode?: JournalMode - /** Page size when a request omits `limit`. Defaults to 20. */ + /** Page size when a request omits `limit`. At most `Number.MAX_SAFE_INTEGER - 1`; defaults to 20. */ defaultLimit?: number - /** Largest accepted page size. Defaults to 100. */ + /** Largest accepted page size. At most `Number.MAX_SAFE_INTEGER - 1`; defaults to 100. */ maxLimit?: number /** Maximum snippet length in Unicode code points. Defaults to 240. */ snippetChars?: number @@ -666,7 +666,7 @@ export interface Config { export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' ``` -Source: [`packages/session-query/session-query-sqlite/src/index.ts:67`](../packages/session-query/session-query-sqlite/src/index.ts) +Source: [`packages/session-query/session-query-sqlite/src/index.ts:72`](../packages/session-query/session-query-sqlite/src/index.ts) ## `@deepseek-ai/dsh-skill` diff --git a/packages/session-persistence/session-persistence-jsonl/src/index.ts b/packages/session-persistence/session-persistence-jsonl/src/index.ts index d45f31e3df..b47766e186 100644 --- a/packages/session-persistence/session-persistence-jsonl/src/index.ts +++ b/packages/session-persistence/session-persistence-jsonl/src/index.ts @@ -145,17 +145,21 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi async listSnapshots(): Promise<SessionPersistenceSnapshot[]> { const snapshots: SessionPersistenceSnapshot[] = [] for (const artifact of await this.listArtifacts()) { - const identity = await stat(artifact.path, { bigint: true }) - snapshots.push({ - header: artifact.header, - revision: SessionPersistenceRevision([ - identity.dev, - identity.ino, - identity.size, - identity.mtimeNs, - identity.ctimeNs, - ].join(':')), - }) + try { + const identity = await stat(artifact.path, { bigint: true }) + snapshots.push({ + header: artifact.header, + revision: SessionPersistenceRevision([ + identity.dev, + identity.ino, + identity.size, + identity.mtimeNs, + identity.ctimeNs, + ].join(':')), + }) + } catch (error: unknown) { + if (!isENOENT(error)) throw error + } } return snapshots } diff --git a/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts b/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts index 0cb4ed3fea..3c826db2eb 100644 --- a/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts +++ b/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts @@ -179,6 +179,39 @@ describe('SessionPersistenceJsonl: durability and crash semantics', () => { await otherCtx.fiber.dispose() }) + it('omits a snapshot artifact removed after discovery', async () => { + const m = meta('vanishing-snapshot') + await ctx.sessionPersistence.create(m) + await ctx.sessionPersistence.append(m.id, oneTurnLog()) + const persistence = ctx.sessionPersistence as unknown as { + listArtifacts(): Promise<Array<{ header: SessionHeader; path: string }>> + } + const listArtifacts = persistence.listArtifacts.bind(persistence) + const discovery = vi.spyOn(persistence, 'listArtifacts').mockImplementation(async () => { + const artifacts = await listArtifacts() + await rm(artifacts[0]!.path) + return artifacts + }) + + await expect(ctx.sessionPersistence.listSnapshots()).resolves.toEqual([]) + discovery.mockRestore() + }) + + it('surfaces non-ENOENT snapshot stat failures after discovery', async () => { + const blocker = join(root, 'snapshot-not-a-directory') + await writeFile(blocker, 'x') + const persistence = ctx.sessionPersistence as unknown as { + listArtifacts(): Promise<Array<{ header: SessionHeader; path: string }>> + } + const discovery = vi.spyOn(persistence, 'listArtifacts').mockResolvedValue([{ + header: meta('snapshot-stat-failure'), + path: join(blocker, 'session.jsonl'), + }]) + + await expect(ctx.sessionPersistence.listSnapshots()).rejects.toThrow(/ENOTDIR/) + discovery.mockRestore() + }) + it('persists a forked child seed through the existing session write path', async () => { const source = ctx.sessions.create(SessionId('persist-parent'), { meta: { cwd: '/workspace' } }) appendClosedTurn(source) diff --git a/packages/session-persistence/session-persistence-sqlite/README.md b/packages/session-persistence/session-persistence-sqlite/README.md index a4a0e645c4..cae28d2bd4 100644 --- a/packages/session-persistence/session-persistence-sqlite/README.md +++ b/packages/session-persistence/session-persistence-sqlite/README.md @@ -6,7 +6,7 @@ A SQLite durable session-persistence backend — a second `SessionPersistence` i ## Storage model -Each `SessionEvent` maps 1:1 onto a row in an `events` table `(session_id, seq, type, time, data, source_event_seqs, surface_op)` — `data` is the event payload as JSON text, so the row shape is the event verbatim (including `assistant/chunk`, keeping `seq` contiguous). The two `TEXT` columns `source_event_seqs` and `surface_op` are nullable; they store the event's optional surface-metadata fields (see [session surface](../../../docs/rfc/implemented/architecture/2026-06-18-session-surface.md)). Out-of-log metadata (`SessionHeader`) and a monotonic per-log revision live in a `sessions` row; a singleton state row carries the immutable store id. A `sessions` row is written only by the first `append` — its existence is the lazy-materialization signal (`list` reports exactly the sessions that have a row). +Each `SessionEvent` maps 1:1 onto a row in an `events` table `(session_id, seq, type, time, data, source_event_seqs, surface_op)` — `data` is the event payload as JSON text, so the row shape is the event verbatim (including `assistant/chunk`, keeping `seq` contiguous). The two `TEXT` columns `source_event_seqs` and `surface_op` are nullable; they store the event's optional surface-metadata fields (see [session surface](../../../docs/rfc/implemented/architecture/2026-06-18-session-surface.md)). Out-of-log metadata (`SessionHeader`), a per-materialization incarnation id, and a monotonic per-log revision live in a `sessions` row; a singleton state row carries the immutable store id. A `sessions` row is written only by the first `append` — its existence is the lazy-materialization signal (`list` reports exactly the sessions that have a row). The repository's Node range supports unflagged `node:sqlite`. The database enables foreign keys and uses the configured journal mode (`wal` by default; use a rollback mode where WAL shared-memory files are unsuitable). `PRAGMA user_version` stores the table-layout version; databases with any other version are rejected because this unreleased format has no migrations. @@ -15,7 +15,7 @@ The repository's Node range supports unflagged `node:sqlite`. The database enabl - **Append = a transaction.** `append` runs `BEGIN`/`COMMIT` around the batch: it materializes the `sessions` row (if still lazy) and INSERTs every event, asserting the contiguous-seq contract first (the first event's `seq` must equal the stored next-seq). A mid-batch failure (a UNIQUE violation on a duplicated seq) rolls back entirely, so the stored log and the in-memory cursor stay consistent. (`load()` already balanced the stored log, so `append` never has to repair a crash tail.) - **Lazy materialization.** `create()` records intent in memory only — no row is written until the first `append`. A created-but-never-appended session has no `sessions` row, so it is absent from `list()` (which reports exactly the sessions that have a row). - **Interrupted-turn close on load.** `load()` implements the shared [crash-recovery contract](../../../docs/rfc/implemented/architecture/2026-06-14-session-persistence.md): preserve the valid interrupted turn, append its synthetic closing events in one transaction, and remove only a torn tail row. Committed parse errors or sequence gaps make the session unloadable. Because recovery mutates stored rows, the next append starts from a balanced log and accurate cursor. -- **Lightweight revisions.** `listSnapshots()` combines an immutable store identity, the database file identity, and a per-session counter incremented in each mutating transaction. This keeps unchanged observations stable without parsing event rows and prevents independent stores from sharing a revision accidentally. +- **Lightweight revisions.** `listSnapshots()` combines the immutable store and database-file identity, a per-materialization incarnation id, and a per-session counter incremented in each mutating transaction. This keeps unchanged observations stable without parsing event rows and distinguishes independent stores and recreated same-id logs. ## Configuration (schemastery) diff --git a/packages/session-persistence/session-persistence-sqlite/src/index.ts b/packages/session-persistence/session-persistence-sqlite/src/index.ts index 6759704d7f..2f3b941f8b 100644 --- a/packages/session-persistence/session-persistence-sqlite/src/index.ts +++ b/packages/session-persistence/session-persistence-sqlite/src/index.ts @@ -7,6 +7,7 @@ import { Context } from 'cordis' import z from 'schemastery' +import { randomUUID } from 'node:crypto' import { statSync } from 'node:fs' import { DatabaseSync } from 'node:sqlite' import { mkdir } from 'node:fs/promises' @@ -235,7 +236,9 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers const rows = this.db.prepare('SELECT * FROM sessions').all() as unknown as SessionRow[] return rows.map(row => ({ header: rowToMeta(row), - revision: SessionPersistenceRevision(`${this.storeIdentity}:revision:${row.revision}`), + revision: SessionPersistenceRevision( + `${this.storeIdentity}:incarnation:${row.incarnation}:revision:${row.revision}`, + ), })) } @@ -259,8 +262,9 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers */ private writeRow(meta: SessionHeader): void { this.db.prepare(` - INSERT INTO sessions (id, version, created_at, cwd, parent_session, seed_length, revision) - VALUES (?, ?, ?, ?, ?, ?, 0) + INSERT INTO sessions + (id, version, created_at, cwd, parent_session, seed_length, incarnation, revision) + VALUES (?, ?, ?, ?, ?, ?, ?, 0) ON CONFLICT(id) DO UPDATE SET version = excluded.version, created_at = excluded.created_at, @@ -274,6 +278,7 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers meta.cwd ?? null, meta.parentSession ?? null, meta.seedLength ?? null, + randomUUID(), ) } } diff --git a/packages/session-persistence/session-persistence-sqlite/src/schema.ts b/packages/session-persistence/session-persistence-sqlite/src/schema.ts index fe7db15d67..fc397ff742 100644 --- a/packages/session-persistence/session-persistence-sqlite/src/schema.ts +++ b/packages/session-persistence/session-persistence-sqlite/src/schema.ts @@ -17,7 +17,7 @@ import type { SessionEvent, SessionId, SessionHeader, SurfaceOp } from '@deepsee * layout; orthogonal to a session's own `version` (which versions the EVENT * vocabulary, stored per session in the `sessions` row). */ -export const SCHEMA_VERSION = 6 +export const SCHEMA_VERSION = 7 /** * A row of the `sessions` table — the out-of-log metadata ({@link SessionHeader}). @@ -33,6 +33,8 @@ export interface SessionRow { cwd: string | null parent_session: string | null seed_length: number | null + /** Stable identity assigned when this log is materialized. */ + incarnation: string /** Monotonic log-change token incremented in each mutating transaction. */ revision: number } @@ -108,6 +110,7 @@ function configureDatabase(db: DatabaseSync, path: string, journalMode: JournalM cwd TEXT, parent_session TEXT, seed_length INTEGER, + incarnation TEXT NOT NULL, revision INTEGER NOT NULL ) STRICT `) diff --git a/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts b/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts index 26b39e22d4..c1d4f8e74f 100644 --- a/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts +++ b/packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts @@ -378,8 +378,31 @@ describe('SessionPersistenceSqlite: durability and crash semantics', () => { await b.dispose() }) + it('changes revisions when a deleted session id is materialized again in the same database', async () => { + const path = await freshDbPath() + const m = meta('recreated-revision') + const first = await backend(path) + await first.ctx.sessionPersistence.create(m) + await first.ctx.sessionPersistence.append(m.id, oneTurnLog()) + const before = (await first.ctx.sessionPersistence.listSnapshots())[0]?.revision + await first.dispose() + + const cleanup = openDatabase(path, 'wal') + cleanup.prepare('DELETE FROM sessions WHERE id = ?').run(m.id) + cleanup.close() + + const second = await backend(path) + await second.ctx.sessionPersistence.create(m) + await second.ctx.sessionPersistence.append(m.id, oneTurnLog()) + const after = (await second.ctx.sessionPersistence.listSnapshots())[0]?.revision + expect(after).not.toBe(before) + expect(String(before)).toMatch(/:revision:1$/) + expect(String(after)).toMatch(/:revision:1$/) + await second.dispose() + }) + it('exposes the schema version constant', () => { - expect(SCHEMA_VERSION).toBe(6) + expect(SCHEMA_VERSION).toBe(7) }) it('keeps the revision stable for an empty repair hook', async () => { diff --git a/packages/session-query/session-query-sqlite/README.md b/packages/session-query/session-query-sqlite/README.md index 101f03eeca..dba2132f43 100644 --- a/packages/session-query/session-query-sqlite/README.md +++ b/packages/session-query/session-query-sqlite/README.md @@ -24,8 +24,8 @@ The database is disposable but reset is guarded: a recognized incompatible searc |---|---:|---| | `path` | required | Dedicated derived-index SQLite path; `:memory:` is supported. | | `journalMode` | `wal` | `wal`, `delete`, `truncate`, or `persist`. | -| `defaultLimit` | `20` | Page size when a request omits `limit`. | -| `maxLimit` | `100` | Largest accepted request page size. | +| `defaultLimit` | `20` | Page size when a request omits `limit`; at most `Number.MAX_SAFE_INTEGER - 1`. | +| `maxLimit` | `100` | Largest accepted request page size; at most `Number.MAX_SAFE_INTEGER - 1`. | | `snippetChars` | `240` | Maximum snippet length in Unicode code points. | ## Tokenizer and limits diff --git a/packages/session-query/session-query-sqlite/src/index.ts b/packages/session-query/session-query-sqlite/src/index.ts index 1590a1d61c..4265405098 100644 --- a/packages/session-query/session-query-sqlite/src/index.ts +++ b/packages/session-query/session-query-sqlite/src/index.ts @@ -48,6 +48,7 @@ import { quoteFtsData, requestFingerprint, sanitizeFtsText, + SQLITE_MAX_PAGE_LIMIT, } from './query.ts' export { @@ -63,15 +64,19 @@ export const SESSION_QUERY_SQLITE_MAX_LIMIT = 100 /** Default maximum snippet length in Unicode code points. */ export const SESSION_QUERY_SQLITE_SNIPPET_CHARS = 240 +// A serialized search tolerates one transient source change; repeated churn +// fails instead of monopolizing the operation queue. +const STABLE_OBSERVATION_ATTEMPTS = 2 + /** SQLite session-search configuration. */ export interface Config { /** Dedicated derived-index path; `:memory:` is supported for tests. */ path: string /** SQLite journal mode. Defaults to `wal`. */ journalMode?: JournalMode - /** Page size when a request omits `limit`. Defaults to 20. */ + /** Page size when a request omits `limit`. At most `Number.MAX_SAFE_INTEGER - 1`; defaults to 20. */ defaultLimit?: number - /** Largest accepted page size. Defaults to 100. */ + /** Largest accepted page size. At most `Number.MAX_SAFE_INTEGER - 1`; defaults to 100. */ maxLimit?: number /** Maximum snippet length in Unicode code points. Defaults to 240. */ snippetChars?: number @@ -154,8 +159,8 @@ export class SessionSearchSqlite extends SessionSearchService { static Config: z<Config> = z.object({ path: z.string().required(), journalMode: z.union(['wal', 'delete', 'truncate', 'persist'] as const).default('wal'), - defaultLimit: z.number().step(1).min(1).default(SESSION_QUERY_SQLITE_DEFAULT_LIMIT), - maxLimit: z.number().step(1).min(1).default(SESSION_QUERY_SQLITE_MAX_LIMIT), + defaultLimit: z.number().step(1).min(1).max(SQLITE_MAX_PAGE_LIMIT).default(SESSION_QUERY_SQLITE_DEFAULT_LIMIT), + maxLimit: z.number().step(1).min(1).max(SQLITE_MAX_PAGE_LIMIT).default(SESSION_QUERY_SQLITE_MAX_LIMIT), snippetChars: z.number().step(1).min(1).default(SESSION_QUERY_SQLITE_SNIPPET_CHARS), }) @@ -206,14 +211,14 @@ export class SessionSearchSqlite extends SessionSearchService { const signal = exec?.signal return this._serialized(signal, async () => { await this._ensureReady(signal) - await this._reconcile(signal) + const persistenceBinding = await this._reconcile(signal) assertNotAborted(signal) const generation = String(this._globalGeneration) const fingerprint = requestFingerprint(normalized) const offset = normalized.cursor === undefined ? 0 : decodeCursor(normalized.cursor, this._instance, 'sessions', fingerprint, generation) - const rows = this._querySessions(normalized, offset) + const rows = this._querySessions(normalized, offset, persistenceBinding) return page(rows, normalized.limit, row => this._sessionHit(row), cursorOffset => encodeCursor({ version: 1, instance: this._instance, @@ -233,14 +238,14 @@ export class SessionSearchSqlite extends SessionSearchService { const signal = exec?.signal return this._serialized(signal, async () => { await this._ensureReady(signal) - await this._reconcile(signal) + const persistenceBinding = await this._reconcile(signal) assertNotAborted(signal) - const generation = this._targetGeneration(normalized.sessionId) + const generation = this._targetGeneration(normalized.sessionId, persistenceBinding) const fingerprint = requestFingerprint(normalized) const offset = normalized.cursor === undefined ? 0 : decodeCursor(normalized.cursor, this._instance, 'events', fingerprint, generation) - const rows = this._queryEvents(normalized, offset) + const rows = this._queryEvents(normalized, offset, persistenceBinding) return page(rows, normalized.limit, row => this._eventHit(row), cursorOffset => encodeCursor({ version: 1, instance: this._instance, @@ -316,7 +321,7 @@ export class SessionSearchSqlite extends SessionSearchService { } } - private async _reconcile(signal: AbortSignal | undefined): Promise<void> { + private async _reconcile(signal: AbortSignal | undefined): Promise<PersistenceBinding> { const db = this._requireDb() const persistedRows = db.prepare( 'SELECT id, revision, generation FROM persisted_sessions', @@ -392,13 +397,14 @@ export class SessionSearchSqlite extends SessionSearchService { if (pointerChanged) this._persistenceEpoch += 1 this._localGeneration = nextLocalGeneration this._lastPersistenceIdentity = observation.persistenceBinding.identity + return observation.persistenceBinding } private async _observeStable( indexed: ReadonlyMap<SessionId, IndexedPersistedRow>, signal: AbortSignal | undefined, ): Promise<Observation> { - for (;;) { + for (let attempt = 0; attempt < STABLE_OBSERVATION_ATTEMPTS; attempt += 1) { assertNotAborted(signal) const persistenceBinding = this._persistenceBinding const persistence = persistenceBinding.service @@ -446,6 +452,10 @@ export class SessionSearchSqlite extends SessionSearchService { return { persistenceBinding, persisted, live } } } + throw new SessionQueryError( + 'session-search persistence observation did not stabilize after one retry', + 'SESSION_QUERY_PERSISTENCE_FAILED', + ) } private _mainGeneration(): number { @@ -540,7 +550,11 @@ export class SessionSearchSqlite extends SessionSearchService { } } - private _querySessions(request: NormalizedSessionRequest, offset: number): SearchRow[] { + private _querySessions( + request: NormalizedSessionRequest, + offset: number, + persistenceBinding: PersistenceBinding, + ): SearchRow[] { const selected = selectedDocumentsSql() const sessionWhere = buildSessionWhere(request.sessionFilters) const eventWhere = buildEventWhere(request.eventFilters) @@ -562,7 +576,7 @@ export class SessionSearchSqlite extends SessionSearchService { ORDER BY match_count DESC, document_length ASC, time DESC, session_id ASC, seq DESC LIMIT ? OFFSET ? `).all( - ...selectedDocumentsParams(request.query, this._persistenceBinding.service !== undefined), + ...selectedDocumentsParams(request.query, persistenceBinding.service !== undefined), ...sessionWhere.params, ...eventWhere.params, request.limit + 1, @@ -570,7 +584,11 @@ export class SessionSearchSqlite extends SessionSearchService { ) as unknown as SearchRow[] } - private _queryEvents(request: NormalizedEventRequest, offset: number): SearchRow[] { + private _queryEvents( + request: NormalizedEventRequest, + offset: number, + persistenceBinding: PersistenceBinding, + ): SearchRow[] { const selected = selectedDocumentsSql() const eventWhere = buildEventWhere(request.filters) const where = ['session_id = ?', eventWhere.sql].filter(Boolean).join(' AND ') @@ -581,7 +599,7 @@ export class SessionSearchSqlite extends SessionSearchService { ORDER BY match_count DESC, document_length ASC, time DESC, seq DESC LIMIT ? OFFSET ? `).all( - ...selectedDocumentsParams(request.query, this._persistenceBinding.service !== undefined), + ...selectedDocumentsParams(request.query, persistenceBinding.service !== undefined), request.sessionId, ...eventWhere.params, request.limit + 1, @@ -589,13 +607,13 @@ export class SessionSearchSqlite extends SessionSearchService { ) as unknown as SearchRow[] } - private _targetGeneration(sessionId: SessionId): string { + private _targetGeneration(sessionId: SessionId, persistenceBinding: PersistenceBinding): string { const db = this._requireDb() const live = db.prepare( 'SELECT generation FROM temp.live_sessions WHERE id = ?', ).get(sessionId) as { generation: number } | undefined if (live !== undefined) return `live:${live.generation}` - if (this._persistenceBinding.service !== undefined) { + if (persistenceBinding.service !== undefined) { const persisted = db.prepare( 'SELECT generation FROM persisted_sessions WHERE id = ?', ).get(sessionId) as { generation: number } | undefined @@ -850,8 +868,8 @@ function resolveConfig(config: Config): ResolvedConfig { if (typeof resolved.path !== 'string' || resolved.path.trim().length === 0) { throw invalidConfig('path must not be blank') } - assertPositiveInteger('defaultLimit', resolved.defaultLimit) - assertPositiveInteger('maxLimit', resolved.maxLimit) + assertPageLimit('defaultLimit', resolved.defaultLimit) + assertPageLimit('maxLimit', resolved.maxLimit) assertPositiveInteger('snippetChars', resolved.snippetChars) if (resolved.defaultLimit > resolved.maxLimit) { throw invalidConfig('defaultLimit must be less than or equal to maxLimit') @@ -865,6 +883,12 @@ function assertPositiveInteger(name: string, value: number): void { if (!Number.isInteger(value) || value < 1) throw invalidConfig(`${name} must be a positive integer`) } +function assertPageLimit(name: string, value: number): void { + if (!Number.isSafeInteger(value) || value < 1 || value > SQLITE_MAX_PAGE_LIMIT) { + throw invalidConfig(`${name} must be an integer between 1 and ${SQLITE_MAX_PAGE_LIMIT}`) + } +} + function invalidConfig(detail: string): SessionQueryError { return new SessionQueryError( `session-search SQLite config: ${detail}`, diff --git a/packages/session-query/session-query-sqlite/src/query.ts b/packages/session-query/session-query-sqlite/src/query.ts index 9654f6ae70..5eb3ed8380 100644 --- a/packages/session-query/session-query-sqlite/src/query.ts +++ b/packages/session-query/session-query-sqlite/src/query.ts @@ -20,6 +20,9 @@ export const FTS_HIGHLIGHT_START = '\uFDD0' /** Collision-free marker inserted after an FTS5 match by `highlight()`. */ export const FTS_HIGHLIGHT_END = '\uFDD1' +/** Largest page size whose internal lookahead remains an exact SQLite integer binding. */ +export const SQLITE_MAX_PAGE_LIMIT = Number.MAX_SAFE_INTEGER - 1 + /** Limit defaults needed to normalize a search request. */ export interface QueryLimits { /** Page size used when the request omits one. */ @@ -232,14 +235,17 @@ export function makeSnippet(markedText: string, maxChars: number): string { const characters = Array.from(clean) if (characters.length <= maxChars) return clean if (maxChars === 1) return '…' - let start = Math.max(0, matchStart - Math.floor(maxChars / 3)) - let prefix = start > 0 ? '…' : '' + const matchedIndex = Math.min(matchStart, characters.length - 1) + let start = Math.max(0, matchedIndex - Math.floor(maxChars / 3)) + const prefix = start > 0 ? '…' : '' let suffix = '…' let contentLength = maxChars - prefix.length - suffix.length if (contentLength < 1) { - start = 0 - prefix = '' - contentLength = maxChars - 1 + start = matchedIndex + suffix = '' + contentLength = maxChars - prefix.length - suffix.length + } else if (matchedIndex >= start + contentLength) { + start = matchedIndex - contentLength + 1 } let end = Math.min(characters.length, start + contentLength) if (end === characters.length) { @@ -326,9 +332,14 @@ function materializeMetadataFilters( function normalizeLimit(value: number | undefined, limits: QueryLimits): number { const limit = value ?? limits.defaultLimit - if (!Number.isInteger(limit) || limit < 1 || limit > limits.maxLimit) { + const maxLimit = Math.min(limits.maxLimit, SQLITE_MAX_PAGE_LIMIT) + if ( + !Number.isSafeInteger(limit) + || limit < 1 + || limit > maxLimit + ) { throw new SessionQueryError( - `session-search limit must be an integer between 1 and ${limits.maxLimit}`, + `session-search limit must be an integer between 1 and ${maxLimit}`, 'SESSION_QUERY_INVALID_LIMIT', ) } diff --git a/packages/session-query/session-query-sqlite/tests/query.spec.ts b/packages/session-query/session-query-sqlite/tests/query.spec.ts index f9c0a5d19e..14e84aae75 100644 --- a/packages/session-query/session-query-sqlite/tests/query.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/query.spec.ts @@ -11,6 +11,7 @@ import { normalizeSessionRequest, quoteFtsData, requestFingerprint, + SQLITE_MAX_PAGE_LIMIT, type NormalizedEventRequest, type NormalizedSessionRequest, } from '../src/query.ts' @@ -88,6 +89,12 @@ describe('SQLite search request normalization', () => { expect(() => normalizeEventRequest({ sessionId: SessionId('s'), query: 'x', limit }, limits)) .toThrow(expectCode('SESSION_QUERY_INVALID_LIMIT')) } + expect(() => normalizeEventRequest({ + sessionId: SessionId('s'), + query: 'x', + limit: SQLITE_MAX_PAGE_LIMIT + 1, + }, { defaultLimit: 1, maxLimit: SQLITE_MAX_PAGE_LIMIT + 1 })) + .toThrow(expectCode('SESSION_QUERY_INVALID_LIMIT')) }) it('materializes owned filter values during normalization', () => { @@ -214,7 +221,8 @@ describe('SQLite query identity and presentation', () => { expect(makeSnippet(`abcde${FTS_HIGHLIGHT_START}f${FTS_HIGHLIGHT_END}`, 1)).toBe('…') expect(makeSnippet('abcdefghij', 5)).toBe('abcd…') expect(makeSnippet(`ab${FTS_HIGHLIGHT_START}c${FTS_HIGHLIGHT_END}defghij`, 5)).toBe('…bcd…') - expect(makeSnippet(`abcde${FTS_HIGHLIGHT_START}f${FTS_HIGHLIGHT_END}`, 2)).toBe('a…') + expect(makeSnippet(`ab${FTS_HIGHLIGHT_START}c${FTS_HIGHLIGHT_END}defghij`, 3)).toBe('…c…') + expect(makeSnippet(`abcde${FTS_HIGHLIGHT_START}f${FTS_HIGHLIGHT_END}`, 2)).toBe('…f') expect(makeSnippet(`abcde${FTS_HIGHLIGHT_START}f${FTS_HIGHLIGHT_END}`, 5)).toBe('…cdef') expect(makeSnippet(` x—${FTS_HIGHLIGHT_START}café${FTS_HIGHLIGHT_END}\n y `, 20)) .toBe('x—café y') diff --git a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts index b4a69acbbd..0895b6f08e 100644 --- a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts @@ -387,6 +387,8 @@ describe('SQLite session search', () => { { path: '' }, { path: ':memory:', defaultLimit: 0 }, { path: ':memory:', maxLimit: 0 }, + { path: ':memory:', defaultLimit: 1e100 }, + { path: ':memory:', maxLimit: 1e100 }, { path: ':memory:', snippetChars: 0 }, { path: ':memory:', defaultLimit: 3, maxLimit: 2 }, { path: ':memory:', journalMode: 'memory' }, @@ -462,6 +464,39 @@ describe('SQLite reconciliation and source lifecycle', () => { .rejects.toThrow(expectCode('SESSION_QUERY_SESSION_NOT_FOUND')) }) + it('uses the reconciled persistence binding through the query boundary', async () => { + const durable = header('post-reconcile-unmount') + TestPersistence.reset([{ meta: durable, events: [ + ...messageEvents('durable needle', 1), + { ...messageEvents('durable needle again', 2)[0]!, seq: 1 }, + ] }]) + const ctx = await liveContext({ path: ':memory:', defaultLimit: 1, maxLimit: 2 }) + const persistence = await ctx.plugin(TestPersistence) + const internals = ctx.sessionSearch as unknown as { + _reconcile(signal: AbortSignal | undefined): Promise<{ + identity: symbol + service?: SessionPersistence + }> + } + const reconcile = internals._reconcile.bind(internals) + const boundary = vi.spyOn(internals, '_reconcile').mockImplementation(async (signal) => { + const binding = await reconcile(signal) + await persistence.dispose() + return binding + }) + + const page = await ctx.sessionSearch.searchEvents({ + sessionId: durable.id, + query: 'needle', + limit: 1, + }) + expect(page.items).toMatchObject([{ sessionId: durable.id }]) + expect(page.nextCursor).toEqual(expect.any(String)) + boundary.mockRestore() + await expect(ctx.sessionSearch.searchEvents({ sessionId: durable.id, query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_SESSION_NOT_FOUND')) + }) + it('discards a stale list rejection when persistence unmounts during observation', async () => { const durable = header('racing') TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) @@ -561,6 +596,22 @@ describe('SQLite reconciliation and source lifecycle', () => { expect(TestPersistence.loads.get(added.id)).toBe(1) }) + it('fails after one retry when persistence snapshots keep changing', async () => { + const durable = header('continuous-mutation') + TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) + const ctx = await liveContext() + await ctx.plugin(TestPersistence) + let lists = 0 + TestPersistence.snapshotEffect = () => { + lists += 1 + TestPersistence.set({ meta: durable, events: messageEvents(`durable needle ${lists}`) }) + } + + await expect(ctx.sessionSearch.searchSessions({ query: 'needle' })) + .rejects.toThrow(expectCode('SESSION_QUERY_PERSISTENCE_FAILED')) + expect(lists).toBe(4) + }) + it('retries if the persistence binding changes while live sessions are observed', async () => { const durable = header('live-boundary-retry') TestPersistence.reset([{ meta: durable, events: messageEvents('durable needle') }]) From 220076e5e2e74248f56bb8b4bf23de9b792f72bc Mon Sep 17 00:00:00 2001 From: Hypatia May <hypatiamay@outlook.com> Date: Fri, 17 Jul 2026 10:15:48 +0800 Subject: [PATCH 015/368] fix(session-query): preserve typed query failures (round 5) --- .../session-query-sqlite/README.md | 2 +- .../session-query-sqlite/src/index.ts | 47 +++++++++++++------ .../session-query-sqlite/tests/sqlite.spec.ts | 46 ++++++++++++++++++ 3 files changed, 79 insertions(+), 16 deletions(-) diff --git a/packages/session-query/session-query-sqlite/README.md b/packages/session-query/session-query-sqlite/README.md index dba2132f43..1a5ee97e29 100644 --- a/packages/session-query/session-query-sqlite/README.md +++ b/packages/session-query/session-query-sqlite/README.md @@ -4,7 +4,7 @@ SQLite FTS5 implementation of `ctx.sessionSearch`. The service searches the live ## Search contract -`searchSessions(request, exec?)` returns `SessionSearchHit` pages across the corpus; `searchEvents(request, exec?)` returns `SessionEventSearchHit` pages within one session. Queries are required, trimmed, whitespace-normalized literal phrases. FTS5 syntax such as quotes, `OR`, `NEAR`, and `*` is treated as data rather than executable MATCH syntax. Metadata filters are parameterized SQL predicates applied before ranking. +`searchSessions(request, exec?)` returns `SessionSearchHit` pages across the corpus; `searchEvents(request, exec?)` returns `SessionEventSearchHit` pages within one session. Queries are required, trimmed, whitespace-normalized literal phrases. FTS5 syntax such as quotes, `OR`, `NEAR`, and `*` is treated as data rather than executable MATCH syntax. Metadata filters are parameterized SQL predicates applied before ranking. A request exceeding SQLite's portable limit of 32,766 total bindings, including fixed query and pagination values, fails with `SESSION_QUERY_INVALID_FILTER` before statement preparation. Relevance is source-comparable across persistent and TEMP tables: actual FTS5 highlighted-match span count descending, then stored document code-point length ascending. Event time, session id where applicable, and seq break remaining ties. Cross-session results expose the selected event as `bestMatch`; both scopes derive whitespace-normalized plain text from FTS5 highlight positions and bound it in Unicode code points. Cursors are opaque branded values, bind to the normalized request and service instance, and fail when the relevant generation changes. A within-session cursor survives unrelated-session changes; a cross-session cursor does not. diff --git a/packages/session-query/session-query-sqlite/src/index.ts b/packages/session-query/session-query-sqlite/src/index.ts index 4265405098..4428d7ca00 100644 --- a/packages/session-query/session-query-sqlite/src/index.ts +++ b/packages/session-query/session-query-sqlite/src/index.ts @@ -559,6 +559,14 @@ export class SessionSearchSqlite extends SessionSearchService { const sessionWhere = buildSessionWhere(request.sessionFilters) const eventWhere = buildEventWhere(request.eventFilters) const where = [sessionWhere.sql, eventWhere.sql].filter(Boolean).join(' AND ') + const bindings = [ + ...selectedDocumentsParams(request.query, persistenceBinding.service !== undefined), + ...sessionWhere.params, + ...eventWhere.params, + request.limit + 1, + offset, + ] + assertPortableBindingCount(bindings) return this._requireDb().prepare(` ${selected.sql}, filtered AS ( @@ -575,13 +583,7 @@ export class SessionSearchSqlite extends SessionSearchService { WHERE event_rank = 1 ORDER BY match_count DESC, document_length ASC, time DESC, session_id ASC, seq DESC LIMIT ? OFFSET ? - `).all( - ...selectedDocumentsParams(request.query, persistenceBinding.service !== undefined), - ...sessionWhere.params, - ...eventWhere.params, - request.limit + 1, - offset, - ) as unknown as SearchRow[] + `).all(...bindings) as unknown as SearchRow[] } private _queryEvents( @@ -592,19 +594,21 @@ export class SessionSearchSqlite extends SessionSearchService { const selected = selectedDocumentsSql() const eventWhere = buildEventWhere(request.filters) const where = ['session_id = ?', eventWhere.sql].filter(Boolean).join(' AND ') + const bindings = [ + ...selectedDocumentsParams(request.query, persistenceBinding.service !== undefined), + request.sessionId, + ...eventWhere.params, + request.limit + 1, + offset, + ] + assertPortableBindingCount(bindings) return this._requireDb().prepare(` ${selected.sql} SELECT * FROM matched WHERE ${where} ORDER BY match_count DESC, document_length ASC, time DESC, seq DESC LIMIT ? OFFSET ? - `).all( - ...selectedDocumentsParams(request.query, persistenceBinding.service !== undefined), - request.sessionId, - ...eventWhere.params, - request.limit + 1, - offset, - ) as unknown as SearchRow[] + `).all(...bindings) as unknown as SearchRow[] } private _targetGeneration(sessionId: SessionId, persistenceBinding: PersistenceBinding): string { @@ -728,6 +732,19 @@ function selectedDocumentsParams(query: string, persistenceVisible: boolean): Ar ] } +// SQLite builds may raise this ceiling; supported modern versions share 32,766 +// as the portable host-parameter limit. +const SQLITE_PORTABLE_VARIABLE_LIMIT = 32_766 + +function assertPortableBindingCount(bindings: readonly (string | number)[]): void { + if (bindings.length > SQLITE_PORTABLE_VARIABLE_LIMIT) { + throw new SessionQueryError( + `session-search request requires ${bindings.length} SQLite bindings; reduce filters to stay within the portable ${SQLITE_PORTABLE_VARIABLE_LIMIT}-variable limit`, + 'SESSION_QUERY_INVALID_FILTER', + ) + } +} + function observeLive(session: Session): ObservedSession { return observeSession(session.header, session.events) } @@ -834,7 +851,7 @@ function decodeCursor( || decoded.instance !== instance || decoded.scope !== scope || decoded.fingerprint !== fingerprint - || !Number.isInteger(decoded.offset) + || !Number.isSafeInteger(decoded.offset) || decoded.offset === undefined || decoded.offset < 0 ) { diff --git a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts index 0895b6f08e..4b875931c4 100644 --- a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts @@ -53,6 +53,16 @@ function expectCode(code: SessionQueryErrorCode): Error { return expect.objectContaining({ code }) as Error } +function replaceCursorOffset( + cursor: ReturnType<typeof SessionSearchCursor>, + offset: number, +): ReturnType<typeof SessionSearchCursor> { + const payload = JSON.parse( + Buffer.from(cursor, 'base64url').toString('utf8'), + ) as Record<string, unknown> + return SessionSearchCursor(Buffer.from(JSON.stringify({ ...payload, offset }), 'utf8').toString('base64url')) +} + class TestPersistence extends SessionPersistence { static entries = new Map<SessionIdType, { meta: SessionHeader; events: SessionEvent[] }>() static revisions = new Map<SessionIdType, number>() @@ -276,6 +286,14 @@ describe('SQLite session search', () => { expect(sessionPage.nextCursor).toEqual(expect.any(String)) if (eventPage.nextCursor === undefined || sessionPage.nextCursor === undefined) throw new Error('expected cursors') + const unsafeOffsetCursor = replaceCursorOffset(eventPage.nextCursor, 1e100) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: target.id, + query: 'needle', + limit: 1, + cursor: unsafeOffsetCursor, + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_CURSOR')) + const eventKeys = eventPage.items.map(item => `${item.sessionId}:${item.seq}`) let eventCursor: ReturnType<typeof SessionSearchCursor> | undefined = eventPage.nextCursor while (eventCursor !== undefined) { @@ -399,6 +417,34 @@ describe('SQLite session search', () => { .toThrow(expectCode('SESSION_QUERY_INVALID_CONFIG')) } }) + + it('rejects aggregate filter bindings above SQLite\'s portable variable limit', async () => { + const ctx = await liveContext() + const session = ctx.sessions.create(SessionId('binding-limit'), { seed: messageEvents('needle') }) + // Each clause is below the ceiling; combined with its sibling and fixed + // query bindings, the complete statement is not portable. + const halfPortableLimit = 16_383 + const ids = Array.from( + { length: halfPortableLimit }, + (_, index) => SessionId(`binding-${index}`), + ) + const types = Array.from({ length: halfPortableLimit }, () => 'user/message' as const) + const surfaces = Array.from({ length: halfPortableLimit }, () => 'current' as const) + + await expect(ctx.sessionSearch.searchSessions({ + query: 'needle', + sessionFilters: [{ kind: 'id', values: ids }], + eventFilters: [{ kind: 'type', values: types }], + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: session.id, + query: 'needle', + filters: [ + { kind: 'type', values: types }, + { kind: 'surface', values: surfaces }, + ], + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + }) }) describe('SQLite reconciliation and source lifecycle', () => { From f401528941e39c4b96957a9d910af5ced7ab08de Mon Sep 17 00:00:00 2001 From: Hypatia May <hypatiamay@outlook.com> Date: Fri, 17 Jul 2026 10:29:49 +0800 Subject: [PATCH 016/368] fix(session-query): preflight SQLite bindings (round 6) --- .../session-query-sqlite/src/index.ts | 21 +++--------- .../session-query-sqlite/src/query.ts | 33 ++++++++++++++++--- .../session-query-sqlite/tests/sqlite.spec.ts | 13 ++++++++ 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/packages/session-query/session-query-sqlite/src/index.ts b/packages/session-query/session-query-sqlite/src/index.ts index 4428d7ca00..05b5edace4 100644 --- a/packages/session-query/session-query-sqlite/src/index.ts +++ b/packages/session-query/session-query-sqlite/src/index.ts @@ -40,6 +40,7 @@ import { type NormalizedSessionRequest, FTS_HIGHLIGHT_END, FTS_HIGHLIGHT_START, + assertPortableBindingCount, buildEventWhere, buildSessionWhere, makeSnippet, @@ -64,8 +65,7 @@ export const SESSION_QUERY_SQLITE_MAX_LIMIT = 100 /** Default maximum snippet length in Unicode code points. */ export const SESSION_QUERY_SQLITE_SNIPPET_CHARS = 240 -// A serialized search tolerates one transient source change; repeated churn -// fails instead of monopolizing the operation queue. +// One transient source change gets a retry; repeated churn fails rather than monopolizing the queue. const STABLE_OBSERVATION_ATTEMPTS = 2 /** SQLite session-search configuration. */ @@ -566,7 +566,7 @@ export class SessionSearchSqlite extends SessionSearchService { request.limit + 1, offset, ] - assertPortableBindingCount(bindings) + assertPortableBindingCount(bindings.length) return this._requireDb().prepare(` ${selected.sql}, filtered AS ( @@ -601,7 +601,7 @@ export class SessionSearchSqlite extends SessionSearchService { request.limit + 1, offset, ] - assertPortableBindingCount(bindings) + assertPortableBindingCount(bindings.length) return this._requireDb().prepare(` ${selected.sql} SELECT * FROM matched @@ -732,19 +732,6 @@ function selectedDocumentsParams(query: string, persistenceVisible: boolean): Ar ] } -// SQLite builds may raise this ceiling; supported modern versions share 32,766 -// as the portable host-parameter limit. -const SQLITE_PORTABLE_VARIABLE_LIMIT = 32_766 - -function assertPortableBindingCount(bindings: readonly (string | number)[]): void { - if (bindings.length > SQLITE_PORTABLE_VARIABLE_LIMIT) { - throw new SessionQueryError( - `session-search request requires ${bindings.length} SQLite bindings; reduce filters to stay within the portable ${SQLITE_PORTABLE_VARIABLE_LIMIT}-variable limit`, - 'SESSION_QUERY_INVALID_FILTER', - ) - } -} - function observeLive(session: Session): ObservedSession { return observeSession(session.header, session.events) } diff --git a/packages/session-query/session-query-sqlite/src/query.ts b/packages/session-query/session-query-sqlite/src/query.ts index 5eb3ed8380..409c20f028 100644 --- a/packages/session-query/session-query-sqlite/src/query.ts +++ b/packages/session-query/session-query-sqlite/src/query.ts @@ -23,6 +23,22 @@ export const FTS_HIGHLIGHT_END = '\uFDD1' /** Largest page size whose internal lookahead remains an exact SQLite integer binding. */ export const SQLITE_MAX_PAGE_LIMIT = Number.MAX_SAFE_INTEGER - 1 +/** Portable host-parameter ceiling shared by predicate and statement builders. */ +export const SQLITE_PORTABLE_VARIABLE_LIMIT = 32_766 + +/** + * Reject prospective SQLite binding growth beyond the portable ceiling. + * @param count - binding count at the current construction boundary. + */ +export function assertPortableBindingCount(count: number): void { + if (count > SQLITE_PORTABLE_VARIABLE_LIMIT) { + throw new SessionQueryError( + `session-search request exceeds SQLite's portable ${SQLITE_PORTABLE_VARIABLE_LIMIT}-variable limit; reduce filter values`, + 'SESSION_QUERY_INVALID_FILTER', + ) + } +} + /** Limit defaults needed to normalize a search request. */ export interface QueryLimits { /** Page size used when the request omits one. */ @@ -356,8 +372,7 @@ function addList( clauses.push('0') return } - clauses.push(`${column} IN (${values.map(() => '?').join(', ')})`) - params.push(...values) + clauses.push(`${column} IN (${appendListBindings(params, values)})`) } function addNullableList( @@ -373,8 +388,7 @@ function addNullableList( const concrete = values.filter((value): value is string => value !== null) const parts: string[] = [] if (concrete.length > 0) { - parts.push(`${column} IN (${concrete.map(() => '?').join(', ')})`) - params.push(...concrete) + parts.push(`${column} IN (${appendListBindings(params, concrete)})`) } if (values.includes(null)) parts.push(`${column} IS NULL`) clauses.push(`(${parts.join(' OR ')})`) @@ -387,15 +401,26 @@ function addRange( range: { from?: number; to?: number }, ): void { if (range.from !== undefined) { + assertPortableBindingCount(params.length + 1) clauses.push(`CAST(${column} AS INTEGER) >= ?`) params.push(range.from) } if (range.to !== undefined) { + assertPortableBindingCount(params.length + 1) clauses.push(`CAST(${column} AS INTEGER) <= ?`) params.push(range.to) } } +function appendListBindings( + params: Array<string | number>, + values: readonly (string | number)[], +): string { + assertPortableBindingCount(params.length + values.length) + for (const value of values) params.push(value) + return values.map(() => '?').join(', ') +} + function canonicalFilters(filters: readonly (SessionResultFilter | SessionEventMetadataFilter)[]): unknown[] { return filters.map((filter) => { if ('values' in filter) { diff --git a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts index 4b875931c4..8db1df5666 100644 --- a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts @@ -445,6 +445,19 @@ describe('SQLite session search', () => { ], })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) }) + + it('rejects one 125,000-value filter list with a typed error', async () => { + const ctx = await liveContext() + const ids = Array.from( + { length: 125_000 }, + (_, index) => SessionId(`oversized-binding-${index}`), + ) + + await expect(ctx.sessionSearch.searchSessions({ + query: 'needle', + sessionFilters: [{ kind: 'id', values: ids }], + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + }) }) describe('SQLite reconciliation and source lifecycle', () => { From e8abfd6482b6d7050e161915de5cb98486e3e14a Mon Sep 17 00:00:00 2001 From: Hypatia May <hypatiamay@outlook.com> Date: Fri, 17 Jul 2026 11:13:03 +0800 Subject: [PATCH 017/368] fix(session-query): guard FTS predicate planning (round 7) --- docs/config-catalog.md | 2 +- .../session-query-sqlite/README.md | 2 +- .../session-query-sqlite/src/index.ts | 3 + .../session-query-sqlite/src/query.ts | 24 +++++++- .../session-query-sqlite/tests/query.spec.ts | 42 ++++++++++++-- .../session-query-sqlite/tests/sqlite.spec.ts | 55 +++++++++++++++++++ 6 files changed, 119 insertions(+), 9 deletions(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 6d141185ca..de1a316cc6 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -666,7 +666,7 @@ export interface Config { export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist' ``` -Source: [`packages/session-query/session-query-sqlite/src/index.ts:72`](../packages/session-query/session-query-sqlite/src/index.ts) +Source: [`packages/session-query/session-query-sqlite/src/index.ts:73`](../packages/session-query/session-query-sqlite/src/index.ts) ## `@deepseek-ai/dsh-skill` diff --git a/packages/session-query/session-query-sqlite/README.md b/packages/session-query/session-query-sqlite/README.md index 1a5ee97e29..1beb479d5e 100644 --- a/packages/session-query/session-query-sqlite/README.md +++ b/packages/session-query/session-query-sqlite/README.md @@ -4,7 +4,7 @@ SQLite FTS5 implementation of `ctx.sessionSearch`. The service searches the live ## Search contract -`searchSessions(request, exec?)` returns `SessionSearchHit` pages across the corpus; `searchEvents(request, exec?)` returns `SessionEventSearchHit` pages within one session. Queries are required, trimmed, whitespace-normalized literal phrases. FTS5 syntax such as quotes, `OR`, `NEAR`, and `*` is treated as data rather than executable MATCH syntax. Metadata filters are parameterized SQL predicates applied before ranking. A request exceeding SQLite's portable limit of 32,766 total bindings, including fixed query and pagination values, fails with `SESSION_QUERY_INVALID_FILTER` before statement preparation. +`searchSessions(request, exec?)` returns `SessionSearchHit` pages across the corpus; `searchEvents(request, exec?)` returns `SessionEventSearchHit` pages within one session. Queries are required, trimmed, whitespace-normalized literal phrases. FTS5 syntax such as quotes, `OR`, `NEAR`, and `*` is treated as data rather than executable MATCH syntax. Metadata filters are parameterized SQL predicates applied before ranking. To keep SQLite FTS5 MATCH in a supported outer-predicate context, cross-session requests may compile at most 14 combined session and event filter predicates; within-session requests may compile at most 13 filter predicates because the fixed target-session predicate consumes one slot. Each range endpoint compiles as one predicate. A request exceeding either predicate budget or SQLite's portable limit of 32,766 total bindings, including fixed query and pagination values, fails with `SESSION_QUERY_INVALID_FILTER` before statement preparation. Relevance is source-comparable across persistent and TEMP tables: actual FTS5 highlighted-match span count descending, then stored document code-point length ascending. Event time, session id where applicable, and seq break remaining ties. Cross-session results expose the selected event as `bestMatch`; both scopes derive whitespace-normalized plain text from FTS5 highlight positions and bound it in Unicode code points. Cursors are opaque branded values, bind to the normalized request and service instance, and fail when the relevant generation changes. A within-session cursor survives unrelated-session changes; a cross-session cursor does not. diff --git a/packages/session-query/session-query-sqlite/src/index.ts b/packages/session-query/session-query-sqlite/src/index.ts index 05b5edace4..2bccb6f269 100644 --- a/packages/session-query/session-query-sqlite/src/index.ts +++ b/packages/session-query/session-query-sqlite/src/index.ts @@ -40,6 +40,7 @@ import { type NormalizedSessionRequest, FTS_HIGHLIGHT_END, FTS_HIGHLIGHT_START, + assertFts5OuterPredicateCount, assertPortableBindingCount, buildEventWhere, buildSessionWhere, @@ -558,6 +559,7 @@ export class SessionSearchSqlite extends SessionSearchService { const selected = selectedDocumentsSql() const sessionWhere = buildSessionWhere(request.sessionFilters) const eventWhere = buildEventWhere(request.eventFilters) + assertFts5OuterPredicateCount(sessionWhere.predicateCount + eventWhere.predicateCount) const where = [sessionWhere.sql, eventWhere.sql].filter(Boolean).join(' AND ') const bindings = [ ...selectedDocumentsParams(request.query, persistenceBinding.service !== undefined), @@ -593,6 +595,7 @@ export class SessionSearchSqlite extends SessionSearchService { ): SearchRow[] { const selected = selectedDocumentsSql() const eventWhere = buildEventWhere(request.filters) + assertFts5OuterPredicateCount(1 + eventWhere.predicateCount) const where = ['session_id = ?', eventWhere.sql].filter(Boolean).join(' AND ') const bindings = [ ...selectedDocumentsParams(request.query, persistenceBinding.service !== undefined), diff --git a/packages/session-query/session-query-sqlite/src/query.ts b/packages/session-query/session-query-sqlite/src/query.ts index 409c20f028..5a67653911 100644 --- a/packages/session-query/session-query-sqlite/src/query.ts +++ b/packages/session-query/session-query-sqlite/src/query.ts @@ -26,6 +26,9 @@ export const SQLITE_MAX_PAGE_LIMIT = Number.MAX_SAFE_INTEGER - 1 /** Portable host-parameter ceiling shared by predicate and statement builders. */ export const SQLITE_PORTABLE_VARIABLE_LIMIT = 32_766 +/** Supported outer-predicate budget that keeps SQLite FTS5 MATCH usable. */ +export const SQLITE_FTS5_OUTER_PREDICATE_LIMIT = 14 + /** * Reject prospective SQLite binding growth beyond the portable ceiling. * @param count - binding count at the current construction boundary. @@ -39,6 +42,19 @@ export function assertPortableBindingCount(count: number): void { } } +/** + * Reject compiled outer predicates beyond the supported FTS5 planner budget. + * @param count - predicate count including fixed statement predicates. + */ +export function assertFts5OuterPredicateCount(count: number): void { + if (count > SQLITE_FTS5_OUTER_PREDICATE_LIMIT) { + throw new SessionQueryError( + `session-search request exceeds the supported SQLite FTS5 outer-predicate budget of ${SQLITE_FTS5_OUTER_PREDICATE_LIMIT}; reduce filters`, + 'SESSION_QUERY_INVALID_FILTER', + ) + } +} + /** Limit defaults needed to normalize a search request. */ export interface QueryLimits { /** Page size used when the request omits one. */ @@ -71,6 +87,8 @@ export interface SqlWhere { sql: string /** Bindings in placeholder order. */ params: Array<string | number> + /** Number of compiled predicates in `sql`. */ + predicateCount: number } /** @@ -163,7 +181,8 @@ export function buildSessionWhere(filters: readonly SessionResultFilter[]): SqlW unknownFilter(filter) } } - return { sql: clauses.join(' AND '), params } + assertFts5OuterPredicateCount(clauses.length) + return { sql: clauses.join(' AND '), params, predicateCount: clauses.length } } /** @@ -192,7 +211,8 @@ export function buildEventWhere(filters: readonly SessionEventMetadataFilter[]): unknownFilter(filter) } } - return { sql: clauses.join(' AND '), params } + assertFts5OuterPredicateCount(clauses.length) + return { sql: clauses.join(' AND '), params, predicateCount: clauses.length } } /** diff --git a/packages/session-query/session-query-sqlite/tests/query.spec.ts b/packages/session-query/session-query-sqlite/tests/query.spec.ts index 14e84aae75..b40489d429 100644 --- a/packages/session-query/session-query-sqlite/tests/query.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/query.spec.ts @@ -11,6 +11,7 @@ import { normalizeSessionRequest, quoteFtsData, requestFingerprint, + SQLITE_FTS5_OUTER_PREDICATE_LIMIT, SQLITE_MAX_PAGE_LIMIT, type NormalizedEventRequest, type NormalizedSessionRequest, @@ -111,24 +112,36 @@ describe('SQLite search request normalization', () => { describe('SQLite search predicate compilation', () => { it('compiles all logical-session clauses including empty and nullable values', () => { - expect(buildSessionWhere([])).toEqual({ sql: '', params: [] }) - expect(buildSessionWhere([{ kind: 'id', values: [] }])).toEqual({ sql: '0', params: [] }) + expect(buildSessionWhere([])).toEqual({ sql: '', params: [], predicateCount: 0 }) + expect(buildSessionWhere([{ kind: 'id', values: [] }])).toEqual({ + sql: '0', + params: [], + predicateCount: 1, + }) expect(buildSessionWhere([{ kind: 'id', values: [SessionId('a'), SessionId('b')] }])).toEqual({ sql: 'session_id IN (?, ?)', params: [SessionId('a'), SessionId('b')], + predicateCount: 1, + }) + expect(buildSessionWhere([{ kind: 'cwd', values: [] }])).toEqual({ + sql: '0', + params: [], + predicateCount: 1, }) - expect(buildSessionWhere([{ kind: 'cwd', values: [] }])).toEqual({ sql: '0', params: [] }) expect(buildSessionWhere([{ kind: 'cwd', values: [null] }])).toEqual({ sql: '(cwd IS NULL)', params: [], + predicateCount: 1, }) expect(buildSessionWhere([{ kind: 'cwd', values: ['/a'] }])).toEqual({ sql: '(cwd IN (?))', params: ['/a'], + predicateCount: 1, }) expect(buildSessionWhere([{ kind: 'parent', values: [SessionId('p'), null] }])).toEqual({ sql: '(parent_session IN (?) OR parent_session IS NULL)', params: [SessionId('p')], + predicateCount: 1, }) expect(buildSessionWhere([ { kind: 'created-at', from: 1, to: 2 }, @@ -138,8 +151,13 @@ describe('SQLite search predicate compilation', () => { ])).toEqual({ sql: 'CAST(created_at AS INTEGER) >= ? AND CAST(created_at AS INTEGER) <= ? AND 0 AND live = 1', params: [1, 2], + predicateCount: 4, + }) + expect(buildSessionWhere([{ kind: 'created-at' }])).toEqual({ + sql: '', + params: [], + predicateCount: 0, }) - expect(buildSessionWhere([{ kind: 'created-at' }])).toEqual({ sql: '', params: [] }) }) it('compiles every event clause and empty lists', () => { @@ -151,11 +169,25 @@ describe('SQLite search predicate compilation', () => { ])).toEqual({ sql: 'CAST(seq AS INTEGER) >= ? AND CAST(time AS INTEGER) <= ? AND type IN (?) AND surface IN (?, ?)', params: [1, 9, 'user/message', 'current', 'log-only'], + predicateCount: 4, }) expect(buildEventWhere([ { kind: 'type', values: [] }, { kind: 'surface', values: [] }, - ])).toEqual({ sql: '0 AND 0', params: [] }) + ])).toEqual({ sql: '0 AND 0', params: [], predicateCount: 2 }) + }) + + it('rejects predicate builders above the supported FTS5 outer budget', () => { + const filters = Array.from( + { length: SQLITE_FTS5_OUTER_PREDICATE_LIMIT }, + () => ({ kind: 'id' as const, values: [SessionId('safe')] }), + ) + + expect(buildSessionWhere(filters).predicateCount).toBe(SQLITE_FTS5_OUTER_PREDICATE_LIMIT) + expect(() => buildSessionWhere([ + ...filters, + { kind: 'id', values: [SessionId('over')] }, + ])).toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) }) it('rejects runtime-unknown filter discriminants in both SQL builders', () => { diff --git a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts index 8db1df5666..043bf3cf6b 100644 --- a/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts +++ b/packages/session-query/session-query-sqlite/tests/sqlite.spec.ts @@ -210,6 +210,61 @@ describe('SQLite session search', () => { }) }) + it('searches at the supported FTS5 outer-predicate boundary in both scopes', async () => { + const ctx = await liveContext() + const session = ctx.sessions.create(SessionId('predicate-boundary'), { + seed: messageEvents('needle'), + meta: { cwd: '/work' }, + }) + const sessionFilters = Array.from( + { length: 14 }, + () => ({ kind: 'cwd' as const, values: ['/work', null] }), + ) + const eventFilters = Array.from( + { length: 13 }, + () => ({ kind: 'type' as const, values: ['user/message' as const] }), + ) + + await expect(ctx.sessionSearch.searchSessions({ query: 'needle', sessionFilters })) + .resolves.toMatchObject({ items: [{ header: { id: session.id } }] }) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: session.id, + query: 'needle', + filters: eventFilters, + })).resolves.toMatchObject({ items: [{ sessionId: session.id, seq: 0 }] }) + }) + + it('rejects unsupported FTS5 outer-predicate counts with typed errors', async () => { + const ctx = await liveContext() + const session = ctx.sessions.create(SessionId('predicate-limit'), { seed: messageEvents('needle') }) + const sessionFilters = Array.from( + { length: 1_100 }, + () => ({ kind: 'id' as const, values: [session.id] }), + ) + const eventFilters = Array.from( + { length: 1_100 }, + () => ({ kind: 'type' as const, values: ['user/message' as const] }), + ) + + await expect(ctx.sessionSearch.searchSessions({ query: 'needle', sessionFilters })) + .rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: session.id, + query: 'needle', + filters: eventFilters, + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + await expect(ctx.sessionSearch.searchSessions({ + query: 'needle', + sessionFilters: sessionFilters.slice(0, 7), + eventFilters: eventFilters.slice(0, 8), + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + await expect(ctx.sessionSearch.searchEvents({ + sessionId: session.id, + query: 'needle', + filters: eventFilters.slice(0, 14), + })).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER')) + }) + it('uses literal phrase tokens, stable ties, and bounded Unicode snippets', async () => { const ctx = await liveContext({ path: ':memory:', defaultLimit: 10, maxLimit: 10, snippetChars: 5 }) ctx.sessions.create(SessionId('a'), { seed: messageEvents('😀😀 alpha beta BRAID 😀😀', 10), meta: { createdAt: 1 } }) From 73e3f658c609a5b43e2acf292315a0260d87b36a Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:40:10 +0800 Subject: [PATCH 018/368] fix(persistence): bind JSONL identity before mutation JSONL discovered a log by the requested session id but later routed repair and append from the parsed header. A log selected for session A could therefore declare session B and redirect mutation to B. Validate the requested id and exact header-derived cwd-bucket path before returning a stored prefix, reject duplicate ids across buckets, and repeat the id/cwd guards in the coordinator before repair or state publication. Collapse the redundant loadLive hook into loadStored while retaining the existing bucket layout and one-live-writer topology, avoiding flat-layout churn and a locator generic that SQLite and test backends do not need. --- ...18-shared-persistence-write-coordinator.md | 9 +-- ...026-07-20-jsonl-storage-identity.i18n.yaml | 6 ++ .../2026-07-20-jsonl-storage-identity.md | 29 +++++++ .../2026-07-20-jsonl-storage-identity.zh.md | 29 +++++++ .../session-persistence-jsonl/README.md | 7 +- .../session-persistence-jsonl/src/index.ts | 71 ++++++++++-------- .../tests/jsonl.spec.ts | 75 ++++++++++++++++--- .../session-persistence-sqlite/src/index.ts | 5 -- .../session-persistence/README.md | 5 +- .../session-persistence/src/coordinator.ts | 59 ++++++++------- .../tests/persistence.spec.ts | 48 +++++++++--- 11 files changed, 245 insertions(+), 98 deletions(-) create mode 100644 .agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.i18n.yaml create mode 100644 .agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.md create mode 100644 .agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.zh.md diff --git a/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md b/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md index 7c73cf24a4..8f26aea91b 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md +++ b/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md @@ -16,11 +16,10 @@ The coordinator retires each live session from its `session/disposed` notificati ### The hook interface (`PersistenceBackend<TornMarker>`) -Six methods (five required + an optional lifecycle hook) — the only seam between the coordinator and storage: +Five required members plus an optional lifecycle hook form the only boundary between the coordinator and storage: - `name` — backend label for the dispose-failure `AggregateError`. -- `loadStored(id)` — read a stored prefix by id, scanning ANY storage scope (every JSONL cwd bucket; SQLite's id is globally unique). Used by resume/load and, via `!== undefined`, the create-collision probe. -- `loadLive(id, cwd)` — read a stored prefix SCOPED to `cwd`. **Deliberately distinct from `loadStored`**: HMR live-adoption must only adopt a persisted log at the SAME cwd as the live session; a same-id log at a different cwd is a collision, not a resume. Collapsing the two reintroduces a cross-cwd adoption bug. SQLite ignores `cwd`. +- `loadStored(id)` — read one stored prefix by id across every storage scope (every JSONL cwd bucket; SQLite's id is globally unique). Resume/load, live adoption, and the create-collision probe share this lookup. The coordinator asserts the returned id and rejects a stored/live cwd mismatch before repair or state publication. - `appendBatch(meta, events, isMaterialized)` — durably append a contiguous batch, lazily materializing the session ATOMICALLY when not yet materialized (the materialize-write and the first event batch must commit together — a crash between them must not leave a materialized-but-empty session; this is why there is no separate `materialize` hook). - `commitRepair(meta, tornMarker, closers)` — make a crash repair durable: truncate the torn tail (iff `tornMarker !== undefined`) and append `closers`. **NOT required to be atomic** — JSONL legitimately truncates-then-appends in two fsync'd steps, SQLite does DELETE+INSERT in one transaction. Used by `load` (truncate + synthetic closers) and live-adoption (truncate only, `closers = []`). - `list()` — list all stored metadata. @@ -37,8 +36,8 @@ The shared `runPersistenceContract` (public-API contract) keeps running for ever ## Alternatives considered - **A base class the backends extend** — rejected for composition: a backend exposes only the hooks, cannot reach the coordinator's private orchestration state, and a third-party backend may still implement the abstract service directly without the coordinator at all. -- **A wider hook surface** — each candidate hook folded away: there is no separate `materialize` hook (the materialize-write must commit atomically with the first event batch inside `appendBatch`), no separate create-collision probe (it is `loadStored(id) !== undefined`), and no coordinator pass-through for `list()` (listing needs none of the orchestration). +- **A wider hook surface** — each candidate hook folds away: there is no scope-specific live lookup because `loadStored` plus the coordinator's cwd check preserves the collision boundary, no storage-locator generic because validated JSONL metadata reproduces its path while SQLite is already id-bound, no separate `materialize` hook because the first batch must commit atomically with materialization, no separate create-collision probe because it is `loadStored(id) !== undefined`, and no coordinator pass-through for `list()` because listing needs none of the orchestration. ## Consequences -The coordinator adds one indirection, an opaque torn marker, and detached session-retirement tasks, but centralizes correctness-heavy orchestration previously duplicated by every backend. Session disposal remains an observe-only event, so the session owner does not await persistence retirement; the coordinator contains failures, preserves uncommitted buffers, and makes backend teardown the quiescence boundary. Its hook surface stays narrow: collision checks reuse `loadStored`, materialization stays atomic inside `appendBatch`, and listing bypasses the coordinator. New backends implement storage primitives rather than copy the event-buffer-flush lifecycle. +The coordinator adds one indirection, an opaque torn marker, and detached session-retirement tasks, but centralizes correctness-heavy orchestration previously duplicated by every backend. Session disposal remains an observe-only event, so the session owner does not await persistence retirement; the coordinator contains failures, preserves uncommitted buffers, and makes backend teardown the quiescence boundary. Its hook surface stays narrow: identity, adoption, and collision checks reuse `loadStored`; materialization stays atomic inside `appendBatch`; and listing bypasses the coordinator. New backends implement storage primitives rather than copy the event-buffer-flush lifecycle. diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.i18n.yaml new file mode 100644 index 0000000000..2feb8bdf82 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-20-jsonl-storage-identity.md: c22377834244e5749993952a5fe8018b89130c1c +2026-07-20-jsonl-storage-identity.zh.md: 8b9a291772ba7e079c06e0d9e3ab9f285ac1ad7e diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.md b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.md new file mode 100644 index 0000000000..c223778342 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.md @@ -0,0 +1,29 @@ +# Agent Note: Bind JSONL session identity before mutation + +Status: implemented + +English | [中文](2026-07-20-jsonl-storage-identity.zh.md) + +## Problem + +JSONL lookup selects a physical log from the requested session id across cwd buckets, while the parsed `SessionHeader` supplies the metadata used by later repair and append operations. Without binding those two facts, a log selected for session A can declare session B's id or cwd and redirect a repair or later append to B's path. The bucket scan also needs a defined result when the same encoded id exists in more than one bucket. SQLite does not share this ambiguity because its primary-key query binds metadata and events to the requested id. + +## Decision + +`loadStored(id)` is the coordinator's single stored-prefix lookup. The JSONL backend scans every cwd bucket, requires at most one matching encoded filename, parses that file, then validates both `header.id === id` and `selectedPath === logPath(root, header.cwd, header.id)` before returning metadata. `list()` applies the same path validation and rejects duplicate ids across buckets. + +The coordinator independently asserts the returned id and compares the stored cwd with a live session's cwd before repair, state publication, or suffix persistence. It keeps a detached copy of validated metadata; JSONL append and repair derive their path from that copy. The `PersistenceBackend<TornMarker>` interface therefore needs neither a scope-specific live lookup nor a storage-locator type. + +The backend supports one live writer per session; another backend instance or process must not mutate that session until the owner finishes disposal and all writes stop. + +## Alternatives considered + +**Flatten storage by session id.** A flat namespace makes duplicate publication collide on one path, but path validation and duplicate rejection close the identity defect without changing the project-grouped cwd layout or its consumers. + +**Carry an opaque storage locator through the coordinator.** A locator binds JSONL mutations directly to a selected path, but JSONL can reproduce that path from metadata it has already validated. Adding another generic and argument to SQLite, test backends, append, and repair makes every implementation carry a concept only the file backend needs. + +**Coordinate multiple live writers.** A dedicated coordination service, process-global registry, or cross-process lock would define a new deployment topology rather than repair identity validation. The supported topology has one live writer; no-overwrite hard-link publication still arbitrates an initial same-id creation race. + +## Consequences + +Mismatched, misplaced, and duplicate JSONL logs fail before repair or coordinator state mutation. The cwd-bucket format stays unchanged and needs no migration. Lookup remains proportional to the number of buckets, and one-live-writer ownership remains an explicit limitation. Coordinator and JSONL tests pin rejection before repair, unchanged bytes for both affected logs, path validation during listing, duplicate-id rejection, and cwd collision handling. diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.zh.md b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.zh.md new file mode 100644 index 0000000000..8b9a291772 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.zh.md @@ -0,0 +1,29 @@ +# Agent Note: 在变更前绑定 JSONL 会话身份 + +Status: implemented + +[English](2026-07-20-jsonl-storage-identity.md) | 中文 + +## 问题 + +JSONL 查找会根据请求的会话 id 在各个 cwd 分桶目录中选出物理日志,而解析得到的 `SessionHeader` 会提供后续修复和追加操作使用的元数据。如果这两个事实没有绑定,为会话 A 选中的日志就能声明会话 B 的 id 或 cwd,并将修复或后续追加重定向到 B 的路径。当同一个编码后 id 出现在多个分桶目录中时,分桶扫描也必须给出确定的结果。SQLite 不存在这种歧义,因为主键查询会将元数据和事件绑定到请求的 id。 + +## 决策 + +`loadStored(id)` 是协调器唯一的已存前缀查找操作。JSONL 后端扫描所有 cwd 分桶目录,要求匹配编码文件名的日志至多有一个,解析该文件,然后在返回元数据前同时验证 `header.id === id` 和 `selectedPath === logPath(root, header.cwd, header.id)`。`list()` 执行相同的路径验证,并拒绝跨分桶目录重复的 id。 + +协调器会独立断言返回的 id,并在修复、发布状态或持久化后缀之前比较已存 cwd 和活动会话的 cwd。协调器保留一份已验证元数据的独立副本;JSONL 的追加和修复操作根据该副本派生路径。因此,`PersistenceBackend<TornMarker>` 接口既不需要限定范围的活动会话查找,也不需要存储定位器类型。 + +后端对每个会话只支持一个活动写入方;在所有者完成资源释放且所有写入停止之前,另一个后端实例或进程不得变更该会话。 + +## 考虑过的替代方案 + +**按会话 id 扁平化存储。** 扁平命名空间会让重复发布在同一路径上冲突,但路径验证和重复项拒绝无需改变按项目分组的 cwd 布局及其消费方,也能消除身份缺陷。 + +**通过协调器传递不透明存储定位器。** 定位器可以将 JSONL 变更直接绑定到选定路径,但 JSONL 可以根据已经验证的元数据重新得到该路径。为 SQLite、测试后端、追加和修复操作增加一个泛型和参数,会让每个实现都承担只有文件后端需要的概念。 + +**协调多个活动写入方。** 专用协调服务、进程级全局注册表或跨进程锁会定义新的部署拓扑,而不是修复身份验证。受支持的拓扑只有一个活动写入方;禁止覆盖的硬链接发布仍会裁决初始的同 id 创建竞争。 + +## 后果 + +JSONL 日志的身份不匹配、位置错误和重复会在修复或协调器状态变更前失败。cwd 分桶格式保持不变,无需迁移。查找开销仍与分桶目录数量成正比,单一活动写入方的所有权仍是明确限制。协调器和 JSONL 测试固定了修复前拒绝、两个受影响日志的字节均保持不变、列出时的路径验证、重复 id 拒绝以及 cwd 冲突处理。 diff --git a/packages/session-persistence/session-persistence-jsonl/README.md b/packages/session-persistence/session-persistence-jsonl/README.md index cf733b85d4..a97fbfd206 100644 --- a/packages/session-persistence/session-persistence-jsonl/README.md +++ b/packages/session-persistence/session-persistence-jsonl/README.md @@ -11,7 +11,7 @@ The JSONL durable session-persistence backend — a concrete `SessionPersistence ``` - The first `.jsonl` line is the immutable `SessionHeader` tagged `{ type: 'session', version, id, cwd?, createdAt, parentSession?, seedLength? }`; every subsequent line is one `SessionEvent` JSON, **verbatim including `assistant/chunk`** so `seq` stays contiguous (`events[i].seq === i`). -- Session ids are unvalidated branded strings, so they are percent-encoded to a single safe path segment before use (no traversal, no collision). +- Session ids are unvalidated branded strings, so they are injectively encoded as one safe path segment before use (no traversal, no collision). ## Config @@ -23,6 +23,7 @@ The JSONL durable session-persistence backend — a concrete `SessionPersistence ## Durability and crash semantics +- **Bound storage identity.** Lookup requires one matching encoded filename across the cwd buckets, then verifies that the header id equals the requested id and that the header's id/cwd derive the selected path. Listing applies the same path check and rejects duplicate ids. Identity failures occur before repair or append. - **Lazy materialization.** `create(meta)` writes nothing; on the first `append`, the backend writes and `fsync`s a temporary file, publishes it without overwrite via a hard link, then `fsync`s the directory when the host supports it. A created-but-never-appended session leaves nothing on disk and is absent from `list`. - **Append-only.** Committed events (at or below a flushed `turn/end`) are never rewritten. Subsequent appends are line appends at EOF + `fsync`. - **Crash recovery — preserve valid tail work.** `load` keeps the contiguous valid prefix of an interrupted final turn. It truncates from the first unparsable or sequence-gapped uncommitted record, then appends the synthetic tool, step, and turn closers required by the shared [persistence contract](../../../.agents/notes/implemented/architecture/2026-06-14-session-persistence.md); the same defect at or before the last committed `turn/end` rejects. @@ -30,7 +31,7 @@ The JSONL durable session-persistence backend — a concrete `SessionPersistence ## Write path -The plugin buffers frozen session events and drains them on flush or disposal. A per-session cursor prevents resumed sessions from re-appending stored events, and live sessions are seeded when the plugin loads. Operations for one session are serialized; disposal waits for initialization and the final drain so no write lands after teardown. +The plugin buffers frozen session events and drains them on flush or disposal. A per-session cursor prevents resumed sessions from re-appending stored events, and live sessions are seeded when the plugin loads. The owning backend instance serializes operations for one session; disposal waits for initialization and the final drain so no write lands after teardown. ## Model Experience @@ -52,6 +53,6 @@ JSONL storage does not mutate live request prefixes. A resumed loop can reuse pr - **Only the current `SESSION_FORMAT_VERSION` (v0) loads** — the on-disk format is pre-release/unstable: a breaking format change is absorbed at v0 and non-current logs are rejected; there is no migration. - **Nothing deletes session files** — logs accumulate under `root` until removed externally (the seam has no deletion surface). -- **Single-process assumption** — per-session serialization and the write cursor live in this process; two processes appending to the same `root` are not coordinated. +- **One live writer per session** — append and repair are coordinated only inside the owning backend instance. Another backend instance or process must not write the same session until that owner reaches quiescent disposal; initial same-id publication remains collision-safe through the no-overwrite hard link. - **Initial materialization requires hard-link support** — first append uses `link()` so same-id races fail instead of overwriting a committed log; a filesystem that cannot create hard links cannot host this backend. - **Windows cannot `fsync` directory handles through Node** — the backend tolerates only Windows `EPERM` from directory `fsync`; file-content `fsync` remains mandatory, but a crash can lose a newly published directory entry on a host without an equivalent directory-sync primitive. diff --git a/packages/session-persistence/session-persistence-jsonl/src/index.ts b/packages/session-persistence/session-persistence-jsonl/src/index.ts index 4e52cb0b9e..84db4ac541 100644 --- a/packages/session-persistence/session-persistence-jsonl/src/index.ts +++ b/packages/session-persistence/session-persistence-jsonl/src/index.ts @@ -9,7 +9,7 @@ import { Context } from 'cordis' import z from 'schemastery' import { open, mkdir, readFile, readdir, link, rm, truncate } from 'node:fs/promises' -import { dirname, resolve } from 'node:path' +import { dirname, join, resolve } from 'node:path' import { randomBytes } from 'node:crypto' import { SessionPersistence, PersistenceCoordinator, @@ -97,28 +97,19 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi /** Read a stored prefix by id across all cwd buckets when cwd is unknown. */ async loadStored(id: SessionId): Promise<StoredPrefix<number> | undefined> { - const file = await this.findLog(id) - if (file === undefined) return undefined - return this.readPrefix(file.path) - } - - /** - * Read a stored prefix within one cwd for HMR adoption. `undefined` names the - * no-cwd bucket rather than an unknown cwd, so this never scans other buckets. - */ - async loadLive(id: SessionId, cwd: string | undefined): Promise<StoredPrefix<number> | undefined> { - const path = logPath(this.root, cwd, id) - if (!await this.exists(path)) return undefined - return this.readPrefix(path) + const path = await this.findLog(id) + if (path === undefined) return undefined + return this.readPrefix(path, id) } /** * Read a stored prefix and convert torn-tail state to the byte offset the * coordinator can round-trip without knowing the file format. */ - private async readPrefix(path: string): Promise<StoredPrefix<number>> { + private async readPrefix(path: string, expectedId: SessionId): Promise<StoredPrefix<number>> { const buffer = await readFile(path) const { meta, events, committedBytes } = scanLog(buffer) + this.assertStoredIdentity(path, meta, expectedId) return { meta, events, @@ -145,16 +136,23 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi if (closers.length > 0) await this.appendLines(meta, closers) } - /** List all stored sessions' metadata (header line only — no full-log parse). */ + /** List valid unique stored sessions' metadata (header line only — no full-log parse). */ async list(): Promise<SessionHeader[]> { const metas: SessionHeader[] = [] + const ids = new Set<SessionId>() for (const dir of await this.listCwdDirs()) { for (const name of await this.listJsonl(dir)) { + const path = join(dir, name) // Read only headers so listing scales with session count, not log size. - const first = await this.readFirstLine(`${dir}/${name}`) + const first = await this.readFirstLine(path) if (first === undefined) continue // empty/half-written file const meta = parseHeaderMeta(first) if (meta === undefined) continue // not a session header + this.assertStoredIdentity(path, meta) + if (ids.has(meta.id)) { + throw new Error(`duplicate JSONL session id "${meta.id}" appears in multiple cwd buckets`) + } + ids.add(meta.id) metas.push(meta) } } @@ -292,28 +290,41 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi } } - /** - * Find a session by id across cwd buckets for resume. Cwd-scoped HMR adoption - * bypasses this scan so a no-cwd session cannot claim another bucket. - */ - private async findLog(id: SessionId): Promise<{ path: string; cwd: string | undefined } | undefined> { + /** Find the unique physical log for an id across every cwd bucket. */ + private async findLog(id: SessionId): Promise<string | undefined> { const target = encodeSegment(id) + '.jsonl' + const matches: string[] = [] for (const dir of await this.listCwdDirs()) { - const path = `${dir}/${target}` - if (await this.exists(path)) { - // Recover the cwd from the header so the caller has the session's bucket. - const { meta } = scanLog(await readFile(path)) - return { path, cwd: meta.cwd } - } + const path = join(dir, target) + if (await this.exists(path)) matches.push(path) + } + if (matches.length > 1) { + throw new Error(`duplicate JSONL session id "${id}" appears in multiple cwd buckets`) + } + return matches[0] + } + + /** Reject metadata that does not identify the selected physical log. */ + private assertStoredIdentity(path: string, meta: SessionHeader, expectedId?: SessionId): void { + if (expectedId !== undefined && meta.id !== expectedId) { + throw new Error(`corrupt session log "${path}": requested id "${expectedId}" does not match header id "${meta.id}"`) + } + let expectedPath: string + try { + expectedPath = logPath(this.root, meta.cwd, meta.id) + } catch (error) { + throw new Error(`corrupt session log "${path}": header id cannot name a storage path`, { cause: error }) + } + if (path !== expectedPath) { + throw new Error(`corrupt session log "${path}": header id "${meta.id}" and cwd belong at "${expectedPath}"`) } - return undefined } /** The cwd-bucket directories under the root (absolute paths). */ private async listCwdDirs(): Promise<string[]> { try { const entries = await readdir(this.root, { withFileTypes: true }) - return entries.filter(e => e.isDirectory()).map(e => `${this.root}/${e.name}`) + return entries.filter(e => e.isDirectory()).map(e => join(this.root, e.name)) } catch (error) { // Only an absent root means no sessions; rethrow every other I/O failure. if (isENOENT(error)) return [] diff --git a/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts b/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts index e7dc469132..ab62bce938 100644 --- a/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts +++ b/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts @@ -21,6 +21,15 @@ function mutableHeader(header: SessionHeader): MutableSessionHeader { return header } +/** Rewrite only a stored header while preserving every event byte below it. */ +async function rewriteHeader(path: string, update: (header: Record<string, unknown>) => void): Promise<void> { + const lines = (await readFile(path, 'utf8')).split('\n') + const header = JSON.parse(lines[0] as string) as Record<string, unknown> + update(header) + lines[0] = JSON.stringify(header) + await writeFile(path, lines.join('\n')) +} + async function expectParallelFlushError(promise: Promise<unknown>, message: RegExp): Promise<void> { try { await promise @@ -393,6 +402,31 @@ describe('SessionPersistenceJsonl: durability and crash semantics', () => { expect(reloaded.events.map(e => e.seq)).toEqual([0, 1, 2, 3, 4, 5, 6, 7]) }) + it('rejects a mismatched header before repairing either session log', async () => { + const a = meta('identity-a', '/same') + const b = meta('identity-b', '/same') + await ctx.sessionPersistence.create(a) + await ctx.sessionPersistence.append(a.id, [{ + type: 'turn/start', + seq: 0, + time: 1, + data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } }, + }]) + await ctx.sessionPersistence.create(b) + await ctx.sessionPersistence.append(b.id, oneTurnLog()) + + const aPath = logPath(root, a.cwd, a.id) + const bPath = logPath(root, b.cwd, b.id) + await rewriteHeader(aPath, (header) => { header.id = b.id }) + const beforeA = await readFile(aPath) + const beforeB = await readFile(bPath) + + await expect(ctx.sessionPersistence.load(a.id)) + .rejects.toThrow(/requested id "identity-a" does not match header id "identity-b"/) + expect(await readFile(aPath)).toEqual(beforeA) + expect(await readFile(bPath)).toEqual(beforeB) + }) + it('rejects a re-append of an already-stored seq', async () => { const m = meta('reappend') await ctx.sessionPersistence.create(m) @@ -599,6 +633,28 @@ describe('SessionPersistenceJsonl: edge cases', () => { expect(ids).toContain('big') }) + it('list rejects a header whose cwd does not identify its physical log', async () => { + const m = meta('misplaced', '/stored') + await ctx.sessionPersistence.create(m) + await ctx.sessionPersistence.append(m.id, oneTurnLog()) + await rewriteHeader(logPath(root, m.cwd, m.id), (header) => { header.cwd = '/elsewhere' }) + + await expect(ctx.sessionPersistence.list()).rejects.toThrow(/and cwd belong at/) + }) + + it('load and list reject one id materialized in multiple cwd buckets', async () => { + const id = SessionId('duplicate') + for (const cwd of ['/a', '/b']) { + const m = meta(id, cwd) + await mkdir(sessionDir(root, cwd), { recursive: true }) + const content = [JSON.stringify(toHeaderLine(m)), ...oneTurnLog().map(event => JSON.stringify(event))].join('\n') + '\n' + await writeFile(logPath(root, cwd, id), content) + } + + await expect(ctx.sessionPersistence.load(id)).rejects.toThrow(/appears in multiple cwd buckets/) + await expect(ctx.sessionPersistence.list()).rejects.toThrow(/appears in multiple cwd buckets/) + }) + it('a DIFFERENT live session object reusing a disposed id gets its own init (no stale cache)', async () => { // Session A materializes a log under id "reuse". const sessFiberA = await ctx.plugin(Object.assign((inner: Context) => { @@ -619,18 +675,16 @@ describe('SessionPersistenceJsonl: edge cases', () => { await expect(ctx.sessions.flush(b)).rejects.toThrow(/already bound to a different live session|already has a persisted log on disk/) }) - it('a NO-CWD live session does NOT cross-cwd-adopt a same-id log from a real cwd bucket (loadLive is scope-exact)', async () => { + it('a no-cwd live session cannot adopt a same-id log from another cwd', async () => { // Backend 1: materialize a log under id "x" in the cwd "/w" bucket, then // dispose the WHOLE backend (so backend 2 mounts with an EMPTY states map — - // the HMR/reload path where onCreated goes through loadLive, not a tracked - // collision). + // the HMR/reload path with no tracked collision state). await ctx.sessionPersistence.create(meta('x', '/w')) await ctx.sessionPersistence.append(SessionId('x'), oneTurnLog()) await ctx.fiber.dispose() - // Backend 2 creates a no-cwd session whose id exists only in `/w`. Exact `loadLive(id, - // undefined)` must not adopt across buckets; the any-cwd collision check then rejects instead - // of grafting no-cwd events onto a log with mismatched cwd. + // Backend 2 creates a no-cwd session whose id exists only in `/w`. The + // stored cwd check rejects instead of grafting no-cwd events onto that log. const ctx2 = new Context() await ctx2.plugin(SessionStore) await ctx2.plugin(SessionPersistenceJsonl, { root }) @@ -638,7 +692,7 @@ describe('SessionPersistenceJsonl: edge cases', () => { await ctx2.plugin(Object.assign((inner: Context) => { b = inner.sessions.create(SessionId('x')) // no cwd }, { inject: ['sessions'] })) - await expect(ctx2.sessions.flush(b)).rejects.toThrow(/already has a persisted log on disk/) + await expect(ctx2.sessions.flush(b)).rejects.toThrow(/different cwd|id collision/) // The "/w" log is untouched — no no-cwd events were grafted onto it, and no // `_no-cwd` log for "x" was created. @@ -706,9 +760,7 @@ describe('SessionPersistenceJsonl: edge cases', () => { await ctx2.fiber.dispose() }) - it('loadLive surfaces a non-ENOENT lookup error (ENOTDIR) instead of reporting absent', async () => { - // A non-ENOENT per-id open error must surface rather than become "not found" and permit false - // live adoption. Making the cwd bucket a regular file forces ENOTDIR for its child log path. + it('materialization surfaces a cwd-bucket storage fault', async () => { const cwd = '/x' const ctx2 = new Context() await ctx2.plugin(SessionStore) @@ -717,8 +769,9 @@ describe('SessionPersistenceJsonl: edge cases', () => { let s!: Session await ctx2.plugin(Object.assign((inner: Context) => { s = inner.sessions.create(SessionId('exists-fault'), { meta: { cwd } }) + appendClosedTurn(s) }, { inject: ['sessions'] })) - await expect(ctx2.sessions.flush(s)).rejects.toThrow(/ENOTDIR/) + await expect(ctx2.sessions.flush(s)).rejects.toThrow(/EEXIST|ENOTDIR/) await ctx2.fiber.dispose() }) diff --git a/packages/session-persistence/session-persistence-sqlite/src/index.ts b/packages/session-persistence/session-persistence-sqlite/src/index.ts index 4661b41309..c7d7770642 100644 --- a/packages/session-persistence/session-persistence-sqlite/src/index.ts +++ b/packages/session-persistence/session-persistence-sqlite/src/index.ts @@ -144,11 +144,6 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers return this.readPrefix(id) } - /** Read a stored prefix; `cwd` is ignored (the id is globally unique in SQLite). */ - loadLive(id: SessionId, _cwd: string | undefined): Promise<StoredPrefix<number> | undefined> { - return this.readPrefix(id) - } - /** * Read a session's row + ordered events into a {@link StoredPrefix}. The * torn-tail marker is the seq from which a never-committed tail must be deleted diff --git a/packages/session-persistence/session-persistence/README.md b/packages/session-persistence/session-persistence/README.md index ca04cd1ab8..7ed713a3d6 100644 --- a/packages/session-persistence/session-persistence/README.md +++ b/packages/session-persistence/session-persistence/README.md @@ -34,14 +34,13 @@ The `PersistenceBackend<TornMarker>` hooks (the only seam between the coordinato | Hook | Role | |---|---| | `name` | Backend label for the dispose-failure `AggregateError`. | -| `loadStored(id)` | Read a stored prefix by id, scanning ANY storage scope. Used by resume/load and, via `!== undefined`, the create-collision probe. Returns an opaque `tornMarker` iff a torn tail must be truncated. | -| `loadLive(id, cwd)` | Read a stored prefix SCOPED to `cwd` (HMR live-adoption must only adopt a log at the SAME cwd; a same-id log elsewhere is a collision, not a resume). A globally-unique-id backend ignores `cwd`. | +| `loadStored(id)` | Read a stored prefix by id across every storage scope. Used by resume/load, live adoption, and the create-collision probe. Returned metadata identifies `id`; an opaque `tornMarker` is present iff a torn tail must be truncated. | | `appendBatch(meta, events, isMaterialized)` | Durably append a contiguous batch, lazily materializing ATOMICALLY when not yet materialized. | | `commitRepair(meta, tornMarker, closers)` | Make a crash repair durable: truncate the torn tail (iff `tornMarker !== undefined` — a marker may be falsy, e.g. seq/offset `0`) and append `closers`. NOT required to be atomic. Used by load (truncate + closers) and live-adoption (truncate only). | | `list()` | List all stored metadata. | | `close?()` | Optional lifecycle teardown (e.g. close a db handle), awaited after the dispose drain. | -The `tornMarker` is fully OPAQUE: the coordinator only tests `!== undefined` and round-trips it to `commitRepair`, never inspecting its value (the JSONL backend uses the byte offset to truncate to, the SQLite backend the seq to delete from). The public `SessionPersistence` service shape is unchanged, so a third-party backend MAY still implement the abstract service directly without the coordinator. See [the write-coordinator Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md). +The coordinator asserts the stored id and compares stored/live cwd before repair or live adoption. The `tornMarker` is fully OPAQUE: the coordinator only tests `!== undefined` and round-trips it to `commitRepair`, never inspecting its value (the JSONL backend uses the byte offset to truncate to, the SQLite backend the seq to delete from). The public `SessionPersistence` service shape is unchanged, so a third-party backend MAY still implement the abstract service directly without the coordinator. See [the write-coordinator Agent Note](../../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md). ## Testing backends diff --git a/packages/session-persistence/session-persistence/src/coordinator.ts b/packages/session-persistence/session-persistence/src/coordinator.ts index beb5fca483..11e003147c 100644 --- a/packages/session-persistence/session-persistence/src/coordinator.ts +++ b/packages/session-persistence/session-persistence/src/coordinator.ts @@ -35,22 +35,14 @@ export interface PersistenceBackend<TornMarker = unknown> { readonly name: string /** - * Read a stored prefix by id, scanning ANY storage scope (for JSONL: every - * cwd bucket). Returns `undefined` if no stored artifact exists. Used by - * resume/load, and — via `!== undefined` — by the create-collision probe. - * The returned `tornMarker` is present iff there is a torn tail to truncate. + * Read a stored prefix by id, scanning every backend storage scope. Returns + * `undefined` if no stored artifact exists. Returned metadata must identify + * `id` before repair or state publication. Used by resume/load, live adoption, + * and — via `!== undefined` — the create-collision probe. The returned + * `tornMarker` is present iff there is a torn tail to truncate. */ loadStored(id: SessionId): Promise<StoredPrefix<TornMarker> | undefined> - /** - * Read a stored prefix SCOPED to `cwd`. Deliberately distinct from - * {@link loadStored}: HMR live-adoption must only adopt a persisted log at the - * SAME cwd as the live session (a same-id log at a different cwd is a - * collision, not a resume) — conflating the two reintroduces a cross-cwd - * adoption bug. For a globally-unique-id backend (SQLite) `cwd` is ignored. - */ - loadLive(id: SessionId, cwd: string | undefined): Promise<StoredPrefix<TornMarker> | undefined> - /** * Durably append a CONTIGUOUS batch, lazily materializing the session first * when `!isMaterialized`. The materialize-write and the first event batch MUST @@ -259,6 +251,7 @@ export class PersistenceCoordinator<TornMarker = unknown> { const stored = await this.backend.loadStored(id) if (stored === undefined) throw new Error(`session "${id}" not found`) const { meta, events, tornMarker } = stored + this.assertStoredId(id, meta) this.assertVersion(meta) assertSupportedEvents(events, id) @@ -317,6 +310,13 @@ export class PersistenceCoordinator<TornMarker = unknown> { } } + /** Reject backend metadata that is not bound to the requested session id. */ + private assertStoredId(id: SessionId, meta: SessionHeader): void { + if (meta.id !== id) { + throw new Error(`stored session identity mismatch: requested "${id}", header contains "${meta.id}"`) + } + } + // --- write path (session/event → flush drain) --- private installWritePath(): void { @@ -439,6 +439,7 @@ export class PersistenceCoordinator<TornMarker = unknown> { const stored = await this.backend.loadStored(id) /* v8 ignore next -- a cursor > 0 means the session was materialized, so it exists */ if (stored === undefined) return false + this.assertStoredId(id, stored.meta) return seedCoversPrefix(seed, stored.events.slice(0, cursor)) } @@ -448,9 +449,10 @@ export class PersistenceCoordinator<TornMarker = unknown> { * Cases, by whether this backend tracks the id and whether an artifact exists: * 1. Already tracked → no-op (or claim ownerless state if the seed matches, * or reclaim a truly-abandoned id, else reject as a collision). - * 2. Not tracked, an artifact EXISTS at this cwd and is a seq-aligned PREFIX - * of the live events → ADOPT it (HMR/reload), persisting any live suffix. - * 3. Not tracked, an artifact EXISTS but is NOT a prefix → REJECT (collision). + * 2. Not tracked, an artifact EXISTS at the same cwd and is a seq-aligned + * PREFIX of the live events → ADOPT it, persisting any live suffix. + * 3. Not tracked, an artifact EXISTS at another cwd or is NOT a prefix → + * REJECT (collision). * 4. Not tracked and NO artifact → a genuinely new session: register meta * (lazy) and persist its seed once. */ @@ -464,14 +466,11 @@ export class PersistenceCoordinator<TornMarker = unknown> { if (tracked.owner === undefined) { // Ownerless state from the public create()/load() API. The FIRST live // session claims it — but ONLY if BOTH the cwd scope and the seed match. - // The cwd guard mirrors case-2's cwd-scoped loadLive(): a same-id - // ownerless artifact at a DIFFERENT cwd is a collision, not a claim - // (claiming it would append the live cwd's events under the stored - // header's cwd, the exact cross-cwd corruption the loadLive scope - // prevents). The seed guard then ensures the live events reproduce the - // persisted prefix (else a fresh, unrelated session reusing the id would - // have its seq 0..cursor-1 events filtered as already-written and - // grafted on). + // A same-id ownerless artifact at a different cwd is a collision, not a + // claim: accepting it would append this live session's events through + // the stored header's cwd. The seed guard then ensures the live events + // reproduce the persisted prefix; otherwise a fresh session reusing the + // id could have its leading events filtered as already written. if (tracked.meta.cwd !== session.header.cwd) { throw new Error(`session "${id}" is already persisted at a different cwd (persisted: ${String(tracked.meta.cwd)}, live: ${String(session.header.cwd)}) (id collision)`) } @@ -495,11 +494,9 @@ export class PersistenceCoordinator<TornMarker = unknown> { } } - // case 2/3: an artifact at THIS cwd is adopted as a live prefix (or rejected - // as a collision inside adoptLivePrefix). cwd-scoped (loadLive), never - // any-scope: a same-id artifact at a different cwd is a collision, not a - // resume. - const live = await this.backend.loadLive(id, session.header.cwd) + // case 2/3: resolve the id once across storage, then let adoption reject a + // cwd mismatch before repair or state publication. + const live = await this.backend.loadStored(id) if (live !== undefined) { // Do NOT route through loadCore(): that crash-repairs open turns as // interrupted, which is wrong for HMR while the live Session is still the @@ -528,6 +525,10 @@ export class PersistenceCoordinator<TornMarker = unknown> { */ private async adoptLivePrefix(session: Session, seed: readonly SessionEvent[], stored: StoredPrefix<TornMarker>): Promise<void> { const { meta, events, tornMarker } = stored + this.assertStoredId(session.header.id, meta) + if (meta.cwd !== session.header.cwd) { + throw new Error(`session "${session.header.id}" is already persisted at a different cwd (persisted: ${String(meta.cwd)}, live: ${String(session.header.cwd)}) (id collision)`) + } this.assertVersion(meta) assertSupportedEvents(events, session.header.id) if (!seedCoversPrefix(seed, events)) { diff --git a/packages/session-persistence/session-persistence/tests/persistence.spec.ts b/packages/session-persistence/session-persistence/tests/persistence.spec.ts index e083ac3543..21d878a6a7 100644 --- a/packages/session-persistence/session-persistence/tests/persistence.spec.ts +++ b/packages/session-persistence/session-persistence/tests/persistence.spec.ts @@ -63,7 +63,7 @@ class MemoryPersistence extends SessionPersistence implements PersistenceBackend super(ctx) // Assign the store BEFORE constructing the coordinator: the coordinator's // constructor installs the write path and synchronously seeds existing live - // sessions (onCreated → loadLive → this.store), so store must exist first. + // sessions through loadStored(), so store must exist first. this.store = config?.store ?? new Map<string, { meta: SessionHeader; events: SessionEvent[] }>() this.coordinator = new PersistenceCoordinator<never>(this.ctx, this) } @@ -88,18 +88,13 @@ class MemoryPersistence extends SessionPersistence implements PersistenceBackend // --- PersistenceBackend hooks (the Map storage primitives) --- - // A Map-backed store has no torn tails, so `tornMarker` is never set. Ids are - // globally unique, so loadStored and loadLive are identical (cwd is ignored). + // A Map-backed store has no torn tails, so `tornMarker` is never set. async loadStored(id: SessionId): Promise<StoredPrefix<never> | undefined> { const entry = this.store.get(id) if (!entry) return undefined return { meta: structuredClone(entry.meta), events: structuredClone(entry.events) } } - loadLive(id: SessionId, _cwd: string | undefined): Promise<StoredPrefix<never> | undefined> { - return this.loadStored(id) - } - async appendBatch(m: SessionHeader, events: readonly SessionEvent[], _isMaterialized: boolean): Promise<void> { // Defense-in-depth: the coordinator already validates serializability, but a // durable store must reject non-JSON data at its own boundary too. @@ -137,6 +132,7 @@ class ControlledBackend implements PersistenceBackend<never> { readonly lifecycle: string[] = [] appendAttempts = 0 loadAttempts = 0 + repairAttempts = 0 beforeAppend?: (attempt: number) => Promise<void> beforeLoadStored?: (attempt: number) => Promise<void> @@ -147,10 +143,6 @@ class ControlledBackend implements PersistenceBackend<never> { return { meta: structuredClone(entry.meta), events: structuredClone(entry.events) } } - loadLive(id: SessionId, _cwd: string | undefined): Promise<StoredPrefix<never> | undefined> { - return this.loadStored(id) - } - async appendBatch(m: SessionHeader, events: readonly SessionEvent[], _isMaterialized: boolean): Promise<void> { const attempt = ++this.appendAttempts await this.beforeAppend?.(attempt) @@ -162,7 +154,9 @@ class ControlledBackend implements PersistenceBackend<never> { } } - async commitRepair(_m: SessionHeader, _tornMarker: undefined, _closers: readonly SessionEvent[]): Promise<void> {} + async commitRepair(_m: SessionHeader, _tornMarker: undefined, _closers: readonly SessionEvent[]): Promise<void> { + this.repairAttempts += 1 + } async list(): Promise<SessionHeader[]> { return [...this.store.values()].map(entry => structuredClone(entry.meta)) @@ -194,6 +188,36 @@ runCoordinatorContract('memory', async (): Promise<CoordinatorFixture> => { } }) +describe('PersistenceCoordinator stored identity', () => { + it('rejects a mismatched backend header before repair or state publication', async () => { + const ctx = new Context() + await ctx.plugin(SessionStore) + const backend = new ControlledBackend() + const requested = SessionId('requested') + backend.store.set(requested, { + meta: meta('different'), + events: [{ + type: 'turn/start', + seq: 0, + time: 1, + data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } }, + }], + }) + let coordinator!: PersistenceCoordinator<never> + const fiber = await ctx.plugin(Object.assign((inner: Context) => { + coordinator = new PersistenceCoordinator(inner, backend) + }, { inject: ['sessions'] })) + try { + await expect(coordinator.load(requested)).rejects.toThrow(/stored session identity mismatch/) + expect(backend.repairAttempts).toBe(0) + expect((coordinator as unknown as CoordinatorInternals).states.size).toBe(0) + } finally { + await fiber.dispose() + await ctx.fiber.dispose() + } + }) +}) + describe('PersistenceCoordinator retirement', () => { it('a retiring unmaterialized owner without buffered events releases its id', async () => { const ctx = new Context() From c9d3d5d557afb3f5376c50f13d44e66a451ca630 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:41:40 +0800 Subject: [PATCH 019/368] fix(jsonl): reject unusable roots at plugin load A configured root that already exists as a file or unreadable directory cannot host cwd buckets, but the backend previously mounted and deferred that deterministic configuration error until a later list or write. Probe the resolved root while the plugin loads, surface every error except ENOENT, and keep an absent root valid for lazy first materialization. Document the timing contract, regenerate the config catalog, and pin the non-directory case at the load boundary. --- .../2026-07-20-jsonl-storage-identity.i18n.yaml | 4 ++-- .../bug-fix/2026-07-20-jsonl-storage-identity.md | 4 ++-- .../2026-07-20-jsonl-storage-identity.zh.md | 4 ++-- docs/config-catalog.md | 6 ++++-- .../session-persistence-jsonl/README.md | 2 +- .../session-persistence-jsonl/src/index.ts | 16 +++++++++++++++- .../tests/jsonl.spec.ts | 7 ++----- 7 files changed, 28 insertions(+), 15 deletions(-) diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.i18n.yaml index 2feb8bdf82..f907cf276b 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.i18n.yaml +++ b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.i18n.yaml @@ -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 -2026-07-20-jsonl-storage-identity.md: c22377834244e5749993952a5fe8018b89130c1c -2026-07-20-jsonl-storage-identity.zh.md: 8b9a291772ba7e079c06e0d9e3ab9f285ac1ad7e +2026-07-20-jsonl-storage-identity.md: 1ada16791f411a54fbcf9271c7d7963223bbe683 +2026-07-20-jsonl-storage-identity.zh.md: 8027c51dbf6c7d01463b7851d859a40890bf03e1 diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.md b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.md index c223778342..1ada16791f 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.md +++ b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.md @@ -14,7 +14,7 @@ JSONL lookup selects a physical log from the requested session id across cwd buc The coordinator independently asserts the returned id and compares the stored cwd with a live session's cwd before repair, state publication, or suffix persistence. It keeps a detached copy of validated metadata; JSONL append and repair derive their path from that copy. The `PersistenceBackend<TornMarker>` interface therefore needs neither a scope-specific live lookup nor a storage-locator type. -The backend supports one live writer per session; another backend instance or process must not mutate that session until the owner finishes disposal and all writes stop. +An existing configured JSONL root must be a readable directory when the plugin loads. An absent root remains valid and is created on first materialization. The backend supports one live writer per session; another backend instance or process must not mutate that session until the owner finishes disposal and all writes stop. ## Alternatives considered @@ -26,4 +26,4 @@ The backend supports one live writer per session; another backend instance or pr ## Consequences -Mismatched, misplaced, and duplicate JSONL logs fail before repair or coordinator state mutation. The cwd-bucket format stays unchanged and needs no migration. Lookup remains proportional to the number of buckets, and one-live-writer ownership remains an explicit limitation. Coordinator and JSONL tests pin rejection before repair, unchanged bytes for both affected logs, path validation during listing, duplicate-id rejection, and cwd collision handling. +Mismatched, misplaced, and duplicate JSONL logs fail before repair or coordinator state mutation. The cwd-bucket format stays unchanged and needs no migration. Lookup remains proportional to the number of buckets, and one-live-writer ownership remains an explicit limitation. Coordinator and JSONL tests pin rejection before repair, unchanged bytes for both affected logs, path validation during listing, duplicate-id rejection, cwd collision handling, and load-time root validation. diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.zh.md b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.zh.md index 8b9a291772..8027c51dbf 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.zh.md +++ b/.agents/notes/implemented/bug-fix/2026-07-20-jsonl-storage-identity.zh.md @@ -14,7 +14,7 @@ JSONL 查找会根据请求的会话 id 在各个 cwd 分桶目录中选出物 协调器会独立断言返回的 id,并在修复、发布状态或持久化后缀之前比较已存 cwd 和活动会话的 cwd。协调器保留一份已验证元数据的独立副本;JSONL 的追加和修复操作根据该副本派生路径。因此,`PersistenceBackend<TornMarker>` 接口既不需要限定范围的活动会话查找,也不需要存储定位器类型。 -后端对每个会话只支持一个活动写入方;在所有者完成资源释放且所有写入停止之前,另一个后端实例或进程不得变更该会话。 +如果配置的 JSONL 根目录已存在,插件加载时该路径必须是可读目录。根目录不存在仍然是有效配置,首次物化时会创建该目录。后端对每个会话只支持一个活动写入方;在所有者完成资源释放且所有写入停止之前,另一个后端实例或进程不得变更该会话。 ## 考虑过的替代方案 @@ -26,4 +26,4 @@ JSONL 查找会根据请求的会话 id 在各个 cwd 分桶目录中选出物 ## 后果 -JSONL 日志的身份不匹配、位置错误和重复会在修复或协调器状态变更前失败。cwd 分桶格式保持不变,无需迁移。查找开销仍与分桶目录数量成正比,单一活动写入方的所有权仍是明确限制。协调器和 JSONL 测试固定了修复前拒绝、两个受影响日志的字节均保持不变、列出时的路径验证、重复 id 拒绝以及 cwd 冲突处理。 +JSONL 日志的身份不匹配、位置错误和重复会在修复或协调器状态变更前失败。cwd 分桶格式保持不变,无需迁移。查找开销仍与分桶目录数量成正比,单一活动写入方的所有权仍是明确限制。协调器和 JSONL 测试固定了修复前拒绝、两个受影响日志的字节均保持不变、列出时的路径验证、重复 id 拒绝、cwd 冲突处理以及加载时的根目录验证。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index c2d31f93e3..c0ccd5f8ee 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -735,13 +735,15 @@ export interface Config { /** * Root directory for all session files. Required (no default): a default of * `process.cwd()` would scatter session files as the process's cwd changes - * (bash calls, subprocesses). Sessions group under per-cwd subdirectories. + * (bash calls, subprocesses). Sessions group under per-cwd subdirectories. An + * existing root must be a readable directory; an absent root is created on + * first materialization. */ root: string } ``` -Source: [`packages/session-persistence/session-persistence-jsonl/src/index.ts:24`](../packages/session-persistence/session-persistence-jsonl/src/index.ts) +Source: [`packages/session-persistence/session-persistence-jsonl/src/index.ts:25`](../packages/session-persistence/session-persistence-jsonl/src/index.ts) ## `@deepseek-ai/dsh-session-persistence-sqlite` diff --git a/packages/session-persistence/session-persistence-jsonl/README.md b/packages/session-persistence/session-persistence-jsonl/README.md index a97fbfd206..f2a6a0a9b7 100644 --- a/packages/session-persistence/session-persistence-jsonl/README.md +++ b/packages/session-persistence/session-persistence-jsonl/README.md @@ -17,7 +17,7 @@ The JSONL durable session-persistence backend — a concrete `SessionPersistence | Key | Type | Notes | |---|---|---| -| `root` | `string` (required) | Root directory for all session files. **No default** — a `process.cwd()` default would scatter files as the process's cwd changes (bash calls, subprocesses). | +| `root` | `string` (required) | Root directory for all session files. **No default** — a `process.cwd()` default would scatter files as the process's cwd changes (bash calls, subprocesses). An existing root must be a readable directory; an absent root is created on first materialization. | `locate(meta)` returns `{ kind: 'jsonl', path }` using the resolved absolute root and the same cwd-bucket/id encoding as materialization. It performs no filesystem I/O: the target can be returned before the file exists, and an existing file contains only the last flushed prefix. diff --git a/packages/session-persistence/session-persistence-jsonl/src/index.ts b/packages/session-persistence/session-persistence-jsonl/src/index.ts index 84db4ac541..a3fdb8b440 100644 --- a/packages/session-persistence/session-persistence-jsonl/src/index.ts +++ b/packages/session-persistence/session-persistence-jsonl/src/index.ts @@ -8,6 +8,7 @@ import { Context } from 'cordis' import z from 'schemastery' +import { readdirSync } from 'node:fs' import { open, mkdir, readFile, readdir, link, rm, truncate } from 'node:fs/promises' import { dirname, join, resolve } from 'node:path' import { randomBytes } from 'node:crypto' @@ -25,7 +26,9 @@ export interface Config { /** * Root directory for all session files. Required (no default): a default of * `process.cwd()` would scatter session files as the process's cwd changes - * (bash calls, subprocesses). Sessions group under per-cwd subdirectories. + * (bash calls, subprocesses). Sessions group under per-cwd subdirectories. An + * existing root must be a readable directory; an absent root is created on + * first materialization. */ root: string } @@ -64,6 +67,7 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi super(ctx) // Resolve once so later process.cwd() changes cannot split one backend across roots. this.root = resolve(config.root) + this.assertUsableRoot() this.coordinator = new PersistenceCoordinator<number>(this.ctx, this) } @@ -304,6 +308,16 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi return matches[0] } + /** Require an existing configured root to be a readable directory. */ + private assertUsableRoot(): void { + try { + readdirSync(this.root) + } catch (error) { + if (isENOENT(error)) return + throw error + } + } + /** Reject metadata that does not identify the selected physical log. */ private assertStoredIdentity(path: string, meta: SessionHeader, expectedId?: SessionId): void { if (expectedId !== undefined && meta.id !== expectedId) { diff --git a/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts b/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts index ab62bce938..d68a48a72d 100644 --- a/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts +++ b/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts @@ -748,15 +748,12 @@ describe('SessionPersistenceJsonl: edge cases', () => { await ctx2.fiber.dispose() }) - it('list surfaces a non-ENOENT root error (ENOTDIR) instead of reporting no sessions', async () => { - // A durable backend must not collapse a storage fault to "no sessions". Making the root a - // regular file forces ENOTDIR from `readdir`, which must propagate. + it('plugin load rejects an existing root that is not a directory', async () => { const filePath = join(root, 'not-a-dir') await writeFile(filePath, 'x') const ctx2 = new Context() await ctx2.plugin(SessionStore) - await ctx2.plugin(SessionPersistenceJsonl, { root: filePath }) - await expect(ctx2.sessionPersistence.list()).rejects.toThrow(/ENOTDIR/) + await expect(ctx2.plugin(SessionPersistenceJsonl, { root: filePath })).rejects.toThrow(/ENOTDIR/) await ctx2.fiber.dispose() }) From f4c9e53a2a466abff7eeb463dfe643538d9c2d24 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:42:03 +0800 Subject: [PATCH 020/368] docs(persistence): state backend ownership precisely The shared coordinator serializes operations within one backend instance; it does not coordinate multiple instances writing the same on-disk session. Remove prose that implied unsupported shared-writer semantics. Also update the older seam-simplification note to describe the surviving loadStored existence probe instead of the removed loadLive hook, so implemented documentation matches the current contract. --- .../simplification/2026-06-20-prune-dead-seam-methods.md | 2 +- docs/core-data-structures/persistence.md | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.md b/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.md index 782ffe891e..f74de250ef 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.md +++ b/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.md @@ -12,7 +12,7 @@ A capability seam ([interface / implementation / consumer](../architecture/2026- The abstract service declared its operations beyond create/append: `load`, `list`, `has`, `delete`. Production consumers of `ctx.sessionPersistence` use only two: the agent-loop resume path calls `load()` ([packages/core/agent-loop/src/index.ts:176](../../../../packages/core/agent-loop/src/index.ts)), and the ACP bridge calls `list()` for `session/list` ([packages/ui/acp/src/index.ts:494](../../../../packages/ui/acp/src/index.ts)). Grepping every `sessionPersistence.*` / `persistence.*` use across `packages/*/src` and `examples/` finds no `has(` and no `delete(` on the service. The `.has(`/`.delete(` calls in `packages/ui/acp/src/index.ts` are on the in-memory `SessionStore` and a local `Set` of loading ids, not persistence. The only callers of `has`/`delete` were the contract suites and per-backend specs. -`has()` was not just unused — it was the most intricate branch in the shared coordinator: a tracked-vs-untracked dual-probe (`loadLive(id, cwd)` for a live-tracked session vs `loadStored(id)` for an untracked one) with a multi-line rationale. `delete()` dragged the `deleteStored` backend hook that every backend had to implement. This is the [drop-mutable-session-summary](2026-06-19-drop-mutable-session-summary.md) pattern: a contract test exercised both, but no shipping code asks "is this session persisted?" or removes one. +`has()` was not just unused: it added a tracked-vs-untracked coordinator probe and a contract branch even though `loadStored(id)` already owns durable existence checks. `delete()` dragged the `deleteStored` backend hook that every backend had to implement. This is the [drop-mutable-session-summary](2026-06-19-drop-mutable-session-summary.md) pattern: a contract test exercised both, but no shipping code asks "is this session persisted?" or removes one. ## Decision diff --git a/docs/core-data-structures/persistence.md b/docs/core-data-structures/persistence.md index a80b9bc896..c88df10294 100644 --- a/docs/core-data-structures/persistence.md +++ b/docs/core-data-structures/persistence.md @@ -97,5 +97,3 @@ Both implement the same abstract `SessionPersistence` (locate/create/append/load - **[dsh-session-persistence-jsonl](../../packages/session-persistence/session-persistence-jsonl)** — an append-only JSONL log per session with crash-safe atomic writes, the interrupted-turn crash recovery above, and a read/replay path. - **[dsh-session-persistence-sqlite](../../packages/session-persistence/session-persistence-sqlite)** — `node:sqlite`, one row per `SessionEvent`. The row shape `(session_id, seq, type, time, data, source_event_seqs, surface_op)` maps 1:1 onto the event, including optional surface metadata, so there is no parallel persisted schema to keep in sync. - -Multiple backends sharing one on-disk session coordinate writes through the [shared persistence write-coordinator](../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md). From 7a9177d624ac06830a1d242c4a969ed0a97acd64 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:46:51 +0800 Subject: [PATCH 021/368] test(jsonl): pin corruption and storage-fault rejection Identity validation must reject a header id that cannot derive a path, and only ENOENT may mean that storage is absent. Other root or per-path failures must remain visible instead of becoming an empty list or false miss. Exercise those branches with narrow storage-mechanics cases, preserving per-file 100% coverage without restoring the flat-layout or multi-writer tests removed from the replacement design. --- .../tests/jsonl.spec.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts b/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts index d68a48a72d..8589fcd2f9 100644 --- a/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts +++ b/packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts @@ -642,6 +642,16 @@ describe('SessionPersistenceJsonl: edge cases', () => { await expect(ctx.sessionPersistence.list()).rejects.toThrow(/and cwd belong at/) }) + it('list rejects a session header whose id cannot name a storage path', async () => { + const bucket = sessionDir(root, undefined) + await mkdir(bucket, { recursive: true }) + await writeFile(join(bucket, 'invalid-id.jsonl'), JSON.stringify({ + type: 'session', version: 0, id: '', createdAt: 1, + }) + '\n') + + await expect(ctx.sessionPersistence.list()).rejects.toThrow(/header id cannot name a storage path/) + }) + it('load and list reject one id materialized in multiple cwd buckets', async () => { const id = SessionId('duplicate') for (const cwd of ['/a', '/b']) { @@ -757,6 +767,21 @@ describe('SessionPersistenceJsonl: edge cases', () => { await ctx2.fiber.dispose() }) + it('list surfaces a root that becomes unusable after plugin load', async () => { + await rm(root, { recursive: true }) + await writeFile(root, 'not a directory') + + await expect(ctx.sessionPersistence.list()).rejects.toThrow(/ENOTDIR/) + }) + + it('per-id lookup surfaces non-ENOENT storage errors', async () => { + const blocker = join(root, 'not-a-directory') + await writeFile(blocker, 'x') + const backend = ctx.sessionPersistence as unknown as { exists(path: string): Promise<boolean> } + + await expect(backend.exists(join(blocker, 'child.jsonl'))).rejects.toThrow(/ENOTDIR/) + }) + it('materialization surfaces a cwd-bucket storage fault', async () => { const cwd = '/x' const ctx2 = new Context() From 8500974fd466b2faadeda3c95cf9574e1a934a74 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 01:11:55 +0800 Subject: [PATCH 022/368] feat: unify JSON value schema DSL --- .../2026-06-11-custom-schema-dsl.md | 4 +- .../2026-06-11-runtime-arg-validation.md | 6 +- ...20-unified-json-value-schema-dsl.i18n.yaml | 6 + ...026-07-20-unified-json-value-schema-dsl.md | 32 + ...-07-20-unified-json-value-schema-dsl.zh.md | 32 + .../feature/2026-07-05-dynamic-workflows.md | 4 +- ...6-07-08-self-referential-cordis-toolset.md | 4 +- ...2026-06-20-core-data-structures-catalog.md | 2 +- .../2026-06-11-property-based-testing.md | 2 +- ...prune-unimplemented-subagent-vocabulary.md | 2 +- docs/config-catalog.md | 2 +- docs/cookbook/adding-a-tool.i18n.yaml | 4 +- docs/cookbook/adding-a-tool.md | 2 +- docs/cookbook/adding-a-tool.zh.md | 2 +- docs/cordis-catalog/events.md | 10 +- docs/cordis-catalog/services.md | 2 +- docs/core-data-structures/core.md | 4 +- docs/core-data-structures/subagent.md | 4 +- docs/core-data-structures/tools.md | 136 +++-- docs/event-producer-consumer.md | 10 +- docs/tool-catalog.md | 10 +- docs/user/develop/basic/tool.i18n.yaml | 4 +- docs/user/develop/basic/tool.md | 22 +- docs/user/develop/basic/tool.zh.md | 22 +- .../system-prompt.expected.md | 52 +- .../tool-schemas.expected.json | 8 +- .../both-mode-turn/system-prompt.expected.md | 44 +- .../both-mode-turn/tool-schemas.expected.json | 6 +- .../code-mode-turn/system-prompt.expected.md | 44 +- .../system-prompt.expected.md | 44 +- .../tool-schemas.expected.json | 12 +- .../tool-schemas.expected.json | 12 +- .../skill-load/tool-schemas.expected.json | 6 +- .../text-turn/tool-schemas.expected.json | 6 +- .../tool-schemas.expected.json | 6 +- packages/bash/tool-bash/src/index.ts | 2 +- packages/bash/tool-bash/tests/tools.spec.ts | 4 +- .../cordis/tool-cordis/src/api-catalog.ts | 34 +- packages/cordis/tool-cordis/src/guard.ts | 238 ++++++-- packages/cordis/tool-cordis/src/index.ts | 6 +- .../cordis/tool-cordis/tests/mount.spec.ts | 146 ++++- packages/core/tools/README.md | 8 +- packages/core/tools/src/index.ts | 39 +- packages/core/tools/src/json-schema.ts | 495 ++++++++------- packages/core/tools/src/schema.ts | 573 ++++++++++-------- packages/core/tools/src/ts-types.ts | 72 ++- packages/core/tools/tests/json-schema.spec.ts | 482 ++++++++------- packages/core/tools/tests/properties.spec.ts | 72 ++- packages/core/tools/tests/schema.spec.ts | 138 +++++ packages/core/tools/tests/tools.spec.ts | 96 +-- packages/core/tools/tests/ts-types.spec.ts | 59 +- .../subagent-inprocess/src/structured.ts | 8 +- .../tests/structured.spec.ts | 16 +- packages/subagent/subagent/src/index.ts | 4 +- packages/subagent/subagent/src/types.ts | 6 +- packages/tasks/tool-tasks/src/index.ts | 2 +- packages/todo/tool-todo/src/index.ts | 3 +- packages/ui/tool-ask-user/src/index.ts | 2 + packages/workflow/tool-workflow/src/index.ts | 3 + .../workflow-workerthread/src/runtime.ts | 14 +- .../workflow-workerthread/src/types.ts | 4 +- scripts/type-equiv.manifest.json | 14 +- 62 files changed, 1929 insertions(+), 1179 deletions(-) create mode 100644 .agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml create mode 100644 .agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md create mode 100644 .agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md create mode 100644 packages/core/tools/tests/schema.spec.ts diff --git a/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.md b/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.md index bf8c02140a..41b72f1551 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.md +++ b/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.md @@ -8,7 +8,7 @@ Tool parameters must reach the model as standard JSON Schema while giving tool a ## Decision -A small custom DSL in dsh-tools: `SchemaSpec` (per-property specs with `required: true` booleans), type-level `InferArgs<S>` mapping a spec to the argument type (required keys non-optional, others genuinely optional via `?`), a runtime `schemaSpecToJsonSchema()` converter, and `defineTool()` tying them together. Raw JSON-Schema `ToolDefinition`s remain accepted by `ToolRegistry.register()` — that's how MCP-sourced tools arrive. +This decision is superseded by the [unified JSON-value schema DSL](2026-07-20-unified-json-value-schema-dsl.md), which retains the small authoring surface while making parameters and typed values share one vocabulary. `ParameterSchemaSpec` keeps per-property `required: true`; `InferArgs<S>` maps required keys to non-optional properties; `parameterSchemaSpecToJsonSchema()` compiles the implicit open object root; and `defineTool()` ties inference, compilation, and validation together. Raw JSON-Schema `ToolDefinition`s remain accepted by `ToolRegistry.register()` for MCP and other external tools. ## Alternatives considered @@ -17,5 +17,5 @@ A small custom DSL in dsh-tools: `SchemaSpec` (per-property specs with `required ## Consequences - First-party tool authors get zero-cast typed args; the type gymnastics cost stays inside the core package (sanctioned by the AGENTS.md type-safety policy). -- The DSL is deliberately small (string/number/boolean/object/array, enum, default, nested properties/items). Gaps vs full JSON Schema (unions, formats, constraints) are accepted until real tools demand them. +- The owning unified note defines the current nodes, literal constraints, unions, JSON-value boundary, and object-openness rules. - The `InferArgs` mapping is regression-tested at the type level after an early optionality bug. diff --git a/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.md b/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.md index 454f12d0af..94b0c6af60 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.md +++ b/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.md @@ -4,13 +4,13 @@ Status: implemented ## Problem -`defineTool` ([the custom schema DSL](2026-06-11-custom-schema-dsl.md)) gives tool authors a typed `execute(args)` via the `InferArgs<S>` mapping. But that type is a compile-time claim about a value that arrives at runtime as model-generated JSON: nothing forced the model to honor the schema, so a malformed call — missing a required key, a string where a number was declared, an enum value outside the set — reached `execute` typed-in-name-only. The tool body then either crashed on the bad shape (a generic stack trace the model can't act on) or, worse, silently misbehaved. Meanwhile the converter already encodes the exact structure a validator would need to walk. +`defineTool` ([the unified schema DSL](2026-07-20-unified-json-value-schema-dsl.md)) gives tool authors a typed `execute(args)` via the `InferArgs<S>` mapping. But that type is a compile-time claim about a value that arrives at runtime as model-generated JSON: nothing forced the model to honor the schema, so a malformed call — missing a required key, a string where a number was declared, or a literal outside the declared set — reached `execute` typed-in-name-only. The tool body then either crashed on the bad shape or silently misbehaved. ## Decision -`validateArgs(spec, args): string[]` interprets a `SchemaSpec` over a runtime value, returning human-readable violations (empty = valid), and is total (never throws). `defineTool` runs it before the typed body; on violations it throws `ToolArgsError` (`code: 'INVALID_ARGS'`, message listing the violations), which the registry's existing execute-waterfall catch turns into an `isError` result the model reads and self-corrects from. +`validateArgs(spec, args): string[]` compiles a `ParameterSchemaSpec` and delegates to the shared `validateJsonSchemaValue()` walker, returning human-readable violations for a well-formed declaration. `defineTool` snapshots the compiled parameter schema at definition time and runs that validation before the typed body; violations throw `ToolArgsError` (`INVALID_ARGS`), which the registry returns as an error result the model can correct. -The validator mirrors `schemaSpecToJsonSchema` semantics exactly — same structure walked, same rules: top level must be a non-array object; required keys come only from `required: true`; extra keys are allowed (no `additionalProperties: false`); `default` is not applied; an `object`/`array` prop without `properties`/`items` only type-checks; `enum` is membership. Raw-registered (MCP) tools are not touched — they validate their own input. +The validator and compiler therefore share exact semantics: the implicit parameter root is an open object; required keys come only from `required: true`; defaults remain annotations; explicit nested objects honor their declared openness; arrays recurse through `items`; scalar literal constraints are type-correct; and `oneOf` accepts exactly one matching branch. Raw-registered tools own their input validation. ## Consequences diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml new file mode 100644 index 0000000000..f434c81118 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-20-unified-json-value-schema-dsl.md: ab7bb268407ac26230283172ebb291de80412bf2 +2026-07-20-unified-json-value-schema-dsl.zh.md: 479699fc2d58666b86861f0ea1db907ae4957dc5 diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md new file mode 100644 index 0000000000..ab7bb26840 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md @@ -0,0 +1,32 @@ +# Agent Note: Unified JSON-value schema DSL + +Status: implemented + +English | [中文](2026-07-20-unified-json-value-schema-dsl.zh.md) + +## Problem + +Tool parameters used a small author DSL while subagent/workflow structured output used a separate raw JSON Schema subset and validator. The two vocabularies disagreed about roots, scalar constraints, and validation, so a typed canonical tool-output contract would either duplicate both paths again or accept schemas that some projection could not enforce. + +## Decision + +`dsh-tools` owns one JSON-value schema vocabulary with two representations. `ValueSchemaSpec` is the author form for any JSON root; `ParameterSchemaSpec` is its implicit object-property-map form with per-property `required: true`. `JsonSchemaNode` is the raw wire form. Both support string, finite number, integer, boolean, null, array, object, type-correct scalar `enum`/`const`, and exact-one `oneOf`; `{ type: 'json' }` is author-only sugar for an annotation-only unconstrained raw node. + +An explicit author object must declare `additionalProperties: true | false`. The implicit parameter root and raw JSON Schema preserve the standard open default. `InferValue<S>` and `InferArgs<P>` derive TypeScript values from the same declarations that `valueSchemaSpecToJsonSchema()` and `parameterSchemaSpecToJsonSchema()` compile. `assertSupportedJsonSchema()` rejects unsupported or misplaced keywords, and `validateJsonSchemaValue()` enforces the accepted subset against the lossless `JsonValue` boundary: no `undefined`, negative zero, non-finite numbers, sparse arrays, cycles, exotic objects, functions, symbols, or other coercive values. + +Object-rooting is a consumer rule rather than a vocabulary restriction. Subagent and workflow caller-defined structured outputs use `assertObjectJsonSchema()` and `ObjectJsonSchema`; tool outputs may use any root. Dynamic Cordis registrations rebuild realm-foreign schemas into host-owned JSON, preserve raw-wrapper openness, and require direct-DSL object openness before calling the same compiler. + +## Alternatives considered + +- **Keep separate parameter and structured-output schema systems:** rejected because every added output construct would require parallel inference, compilation, validation, and code-generation changes with no useful ownership boundary. +- **Adopt full JSON Schema or Ajv:** rejected because the harness must fail on every construct it cannot project into its generated SDK and validators; accepting a larger language would make enforcement and model guidance dishonest. +- **Make every object implicitly open or closed:** rejected because either choice hides a consequential author decision. Only the legacy-shaped implicit parameter root and external raw schema retain an intentional default. +- **Define `oneOf` as first-match:** rejected because branch ordering would change validation semantics and allow overlapping branches to hide ambiguous values. + +## Consequences + +- Parameter validation, output validation, schema-to-TypeScript generation, subagent/workflow guards, and dynamic registration share one enforced vocabulary. +- Output declarations can infer object, array, scalar, or null roots; subagent/workflow structured outputs remain object-rooted at their existing seams. +- Explicit object openness and type-correct literal constraints make malformed declarations fail during authoring or registration rather than during a later model call. +- Raw tools may still register broader JSON Schema directly, but unified code generation treats unsupported schemas as unknown instead of pretending to enforce them. +- Runtime and compile-time tests cover every root, exact-one overlap/no-match behavior, raw open defaults, explicit openness, lossy JSON values, and inference. diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md new file mode 100644 index 0000000000..479699fc2d --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md @@ -0,0 +1,32 @@ +# Agent Note:统一 JSON 值 schema DSL + +Status: implemented + +[English](2026-07-20-unified-json-value-schema-dsl.md) | 中文 + +## 问题 + +工具参数使用一套精简的作者侧 schema DSL,subagent/工作流的结构化输出则使用另一套原始 JSON Schema 子集和校验器。两套词汇在根类型、标量约束和校验方式上并不一致;如果继续沿用这种划分,类型化的规范工具输出契约要么还需重复实现两条路径,要么只能接受部分投影无法强制执行的 schema。 + +## 决策 + +`dsh-tools` 以两种表示形式统一管理一套 JSON 值 schema 词汇。`ValueSchemaSpec` 是可描述任意 JSON 根类型的作者侧形式;`ParameterSchemaSpec` 是其隐式对象属性映射形式,每个属性可标记 `required: true`。`JsonSchemaNode` 是原始协议表示。两种形式都支持字符串、有限数值、整数、布尔值、null、数组、对象、类型正确的标量 `enum`/`const`,以及要求恰好匹配一个分支的 `oneOf`;`{ type: 'json' }` 仅是作者侧语法糖,会编译为仅含注解、不施加约束的原始节点。 + +显式的作者侧对象必须声明 `additionalProperties: true | false`。隐式参数根对象和原始 JSON Schema 保留标准的默认开放语义。`InferValue<S>` 和 `InferArgs<P>` 根据同一份声明推导 TypeScript 值,`valueSchemaSpecToJsonSchema()` 和 `parameterSchemaSpecToJsonSchema()` 也将这些声明编译为 JSON Schema。`assertSupportedJsonSchema()` 会拒绝不受支持或位置错误的关键字;`validateJsonSchemaValue()` 则以无损 `JsonValue` 边界校验受支持的子集,不允许 `undefined`、负零、非有限数、稀疏数组、循环引用、非普通对象、函数、symbol 及其他需要强制转换的值。 + +对象根限制属于消费方规则,不属于 schema 词汇本身。subagent 和工作流中由调用方定义的结构化输出通过 `assertObjectJsonSchema()` 和 `ObjectJsonSchema` 保持对象根限制;工具输出可以使用任意根类型。动态 Cordis 注册会把跨 JavaScript 运行域传入的 schema 重建为当前运行时持有的 JSON,保留原始包装层的默认开放语义,并要求直接使用 DSL 声明的对象明确选择开放方式,然后再调用同一编译器。 + +## 备选方案 + +- **保留两套独立的参数与结构化输出 schema 系统:**不予采纳。每新增一种输出结构,都必须分别修改类型推导、编译、校验和代码生成,而这种重复并未形成有意义的职责边界。 +- **采用完整 JSON Schema 或 Ajv:**不予采纳。harness 必须拒绝所有无法投影到生成 SDK 和校验器中的结构;如果接受更大的语言子集,强制执行能力和模型指引就会与事实不符。 +- **让所有对象默认开放或默认封闭:**不予采纳。这两种选择都会隐藏一项影响重大的作者决策。只有保持旧有形态的隐式参数根对象和外部原始 schema 才有意保留默认值。 +- **把 `oneOf` 定义为首个匹配分支:**不予采纳。这样一来,分支顺序会改变校验语义,重叠分支也会掩盖值的歧义。 + +## 影响 + +- 参数校验、输出校验、schema 到 TypeScript 的代码生成、subagent/工作流门禁和动态注册共用一套强制执行的词汇。 +- 输出声明可以推导对象、数组、标量或 null 根类型;subagent/工作流的结构化输出仍在其现有服务边界保持对象根限制。 +- 显式的对象开放方式和类型正确的字面量约束会让格式错误的声明在编写或注册阶段快速失败,而不是拖到后续模型调用时才失败。 +- 原始工具仍可直接注册范围更广的 JSON Schema,但统一代码生成会把不受支持的 schema 视为未知类型,不会假装自己能够强制执行。 +- 运行时和编译期测试覆盖所有根类型、恰好匹配一个分支时的重叠/无匹配行为、原始 schema 的默认开放语义、显式开放方式、有损 JSON 值和类型推导。 diff --git a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md index 599c895ae2..fcd0b66062 100644 --- a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md +++ b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md @@ -44,7 +44,7 @@ A `workflow` tool mirroring `dsh-tool-subagent`'s synchronous shape: start, awai An output schema makes a schema-valid committed capture mandatory for successful child completion. The scoped runtime presents the capture tool and instruction, commits only a successful final outcome—including the enclosing `run_code` outcome for an SDK call—denies later side effects after capture becomes pending, and stops the child without another model step after commit. A validation failure remains a retryable tool error; clean completion without a committed capture settles as an error. -`StructuredOutputSchema` is the raw enforceable JSON-Schema subset in `dsh-tools` (single-string `type`, `properties`/`required`/`additionalProperties`, `items`, scalar `enum`/`const`), and unsupported keywords fail loudly because that wire data becomes the capture tool's parameters verbatim. The [agent-scope runtime-design Agent Note](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes) owns the assembly, commit, guard, and terminal-stop correctness algorithms. +`ObjectJsonSchema` is the object-rooted consumer view of the unified enforceable raw JSON Schema subset in `dsh-tools`; unsupported keywords fail loudly because that wire data becomes the capture tool's parameters verbatim. The [unified JSON-value schema Agent Note](../architecture/2026-07-20-unified-json-value-schema-dsl.md) owns the vocabulary and validation semantics, while the [agent-scope runtime-design Agent Note](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes) owns the assembly, commit, guard, and terminal-stop algorithms. ## Testing @@ -68,7 +68,7 @@ Worker-side logic runs through an in-process `MessageChannel` so V8 coverage mea - **Background execution as the default** (CC's shape): deferred; foreground-synchronous matches `dsh-tool-subagent`'s cut, and background semantics should be designed ONCE across bash/subagent/workflow rather than per-tool. - **Workflow-layer JSON parsing for `agent({schema})`**: duplicating a seam concern at one consumer while the seam's capability flag stayed dishonestly `false`. - **Meta embedded in the script as `export const meta = {...}`** (CC's exact format): keeps scripts self-contained and CC scripts drop-in, but obtaining meta requires evaluating model-written text on the host. Even an empty timed vm context cannot bound script-controlled getters when the host reads the resulting object. A JSON parameter removes the scanner, evaluation, and host-spin hole; the cost is that a CC script's meta header must move into the parameter (the body stays drop-in). -- **`SchemaSpec` as the outputSchema type**: the author-facing DSL cannot express what arrives as data and cannot be validated against without conversion loss. +- **`ValueSchemaSpec` as the `outputSchema` wire type**: the author form now has equivalent vocabulary, but a workflow supplies realm-foreign raw JSON Schema data; pretending that runtime data is a trusted author declaration would skip the raw-schema assertion boundary. - **A schema-object library (zod, or the repo's schemastery) for the structured-output subset**: the schema is wire data — plain JSON that crosses the vm realm boundary in `agent({schema})` and lands verbatim in the forced tool's parameters — exactly where live schema objects cannot sit; consuming raw JSON Schema at runtime would need a third-party converter on top (zod core only emits JSON Schema, not the reverse), and it would put a second schema language beside schemastery's config role. - **ajv for value validation**: it validates FULL JSON Schema, so the subset gate — the module's actual point, since every accepted keyword must be one the harness enforces — would remain hand-written regardless; it compiles validators through `new Function`; and it would be dsh-tools' first runtime dependency, all to replace the ~70-line value walker while the path-qualified, every-violation error reporting stays custom either way. - **Provider JSON mode instead of the capture tool:** it guarantees valid JSON, not schema conformance, and its interaction with tool calling is unclear. The capture tool preserves in-turn validation retries. Provider-side strict tool schemas can later narrow the accepted subset without changing this design. diff --git a/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md b/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md index 144bdd018f..2038b2b719 100644 --- a/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md +++ b/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md @@ -32,7 +32,7 @@ Sandbox globals are deliberately small: a tagged write-through `console` (`[cord Mount code crosses the vm boundary through three controls. Dual-realm `instanceof` recognizes both host and vm objects. `harness.defineTool` normalizes results into host-realm JSON and validates the `ToolExecuteReturn` shape before logging. The mounted plugin receives a whitelist context façade, not a raw or pass-through `Context`; framework plumbing and context-valued returns are rejected. Service reads require a declared `inject`, preserving Cordis activation and unload semantics. `ctx.tools.get` exposes only the schema view, so mounted code cannot bypass `ToolRegistry.execute` by calling a definition directly. -The boundary normalizes unambiguous JSON-Schema forms into `SchemaSpec`, including object wrappers, `integer`, and optional fields. Invalid vocabulary fails with the accepted alternatives. Parse, TypeScript, missing-return, Node-API, and duplicate-tool errors include the relevant source line or corrective contract without narrating implementation internals. +The boundary normalizes unambiguous JSON-Schema forms into `ParameterSchemaSpec`, preserving `integer`, raw object openness, and required arrays. Direct DSL object nodes must declare `additionalProperties`; invalid vocabulary fails with the accepted alternatives. Parse, TypeScript, missing-return, Node-API, and duplicate-tool errors include the relevant source line or corrective contract without narrating implementation internals. ### The dynamic group and mount lifecycle @@ -60,7 +60,7 @@ Model-visible ⟺ logged holds with no new session event type: a mount or unmoun | Dimension | Structured per-capability tools | Single `cordis_mount` | |---|---|---| -| Schema correctness | `parameters` is still a model-written JSON object needing SchemaSpec validation, merely one step earlier | The same validation runs at the sandbox boundary, with the same instructive errors | +| Schema correctness | `parameters` is still model-written JSON needing unified-schema validation, merely one step earlier | The same validation runs at the sandbox boundary, with the same instructive errors | | The code field | An `execute` body is still model-written JS in a vm; the realm and service-call correctness problems are unchanged | One sandbox, one normalization path, one guarded registration | | Capability coverage | Tools only; listeners, services, `inject` relations each need another structured tool — a surface that grows without bound | One vocabulary (a cordis plugin) covers every effect, present and future | | Cross-mount composition | Not expressible in a tool-registration payload | Native `provide`/`inject`, ordinary cordis semantics | diff --git a/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.md b/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.md index 21b86b1812..99ab46ef68 100644 --- a/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.md +++ b/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.md @@ -19,7 +19,7 @@ The scoping line was not picked top-down; it was discovered by testing candidate The rule that settled the remaining cases: ***the type you write, hold, or receive is core; the machinery that types it, renders it, or persists it is a sub-page detail.*** Worked through: - A data structure is **core** if it flows through the agent-loop spine — the loop holds, derives, streams, or logs it on every turn regardless of which plugins load (`Message`, `StreamChunk`, `SessionEvent`, the `Agent` handle) — **or** it is the single headline type a plugin author writes against a pipeline (`ToolDefinition`). -- `ToolDefinition` is core (it is what every tool author writes) **even though the loop never holds one** — authoring-importance overrides the strict flows-through-spine rule for this one headline type. But its typing machinery — the `SchemaSpec`/`InferArgs` DSL — is a sub-page detail (you write a `ToolDefinition`; the type-level machinery that types it you do not). That is the spine-vs-seam line made sharp. +- `ToolDefinition` is core (it is what every tool author writes) **even though the loop never holds one** — authoring-importance overrides the strict flows-through-spine rule for this one headline type. But its typing machinery — `ValueSchemaSpec`, `ParameterSchemaSpec`, `InferValue`, and `InferArgs` — is a sub-page detail. That is the spine-vs-seam line made sharp. - `ToolSchema` is core (it is a field of `GenerateOptions`, the model request that flows through every step) even though it is conceptually part of the tool pipeline — *flows through the spine* wins over *conceptual home* when they conflict. - The tool-presentation vocabulary (`ToolCallView`/`ToolResultView`, …), the `SessionPersistence` durability seam, and bash vocabulary are sub-pages. diff --git a/.agents/notes/implemented/testing/2026-06-11-property-based-testing.md b/.agents/notes/implemented/testing/2026-06-11-property-based-testing.md index 06350753cd..5109aa1c80 100644 --- a/.agents/notes/implemented/testing/2026-06-11-property-based-testing.md +++ b/.agents/notes/implemented/testing/2026-06-11-property-based-testing.md @@ -14,7 +14,7 @@ Adopt `fast-check` (a root devDependency) with one `tests/properties.spec.ts` pe - **dsh-llm / BlockAssembler:** arbitrary chunk streams (valid + malformed: duplicate indices, stragglers, missing block-start). Invariants: `blocks()` count ≤ distinct indices seen; re-assembly idempotent (`blocks()` is stable across repeated calls and `message().content` mirrors it); `blocks()` never throws and yields only valid content-block tags; `finish` reflects the last `finish` chunk, defaulting to `{kind:'stop'}` when none arrives. - **dsh-session:** arbitrary event logs. Invariants: `deriveMessages` deterministic; replay-from-seed identical; seq strictly monotonic; non-message events never affect derived history; derived content is decoupled from the log. -- **dsh-tools:** arbitrary `SchemaSpec`. Invariants: JSON Schema `required` equals the `required:true` keys at every level; conversion total; **and the composition with [runtime arg validation](../architecture/2026-06-11-runtime-arg-validation.md)** — generated args satisfying a spec pass `validateArgs`, and targeted corruptions (dropped required key, non-object top level) are rejected. This closes the validator/`InferArgs` drift risk. +- **dsh-tools:** arbitrary `ParameterSchemaSpec`. Invariants: JSON Schema `required` equals the `required:true` keys at every level; conversion is total for valid declarations; **and the composition with [runtime arg validation](../architecture/2026-06-11-runtime-arg-validation.md)** — generated args satisfying a spec pass `validateArgs`, and targeted corruptions (dropped required key, non-object top level) are rejected. Focused cases cover every value root, exact-one overlap/no-match, explicit openness, raw defaults, and lossy JSON. This closes the compiler/validator/`InferArgs` drift risk. - **dsh-agent-loop:** arbitrary send schedules against a never-exhausting adapter, driven through the `agent/status` settle signal (no wall-clock sleeps). Invariants: no message lost; turn numbers strictly increase; status transitions stay on the legal machine. ## Consequences diff --git a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md index 582673f185..1f07492c9c 100644 --- a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md +++ b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md @@ -9,7 +9,7 @@ The [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-sea - **`outputSchema`/`structured` and `toolFilter`** (`SubagentCapabilities`, `SubagentStartRequest`, `SubagentResult` in `packages/subagent/subagent/src/types.ts`): at the decision point, every real provider declared `outputSchema: false, toolFilter: false` (`packages/subagent/subagent-spawn/src/index.ts`, `packages/subagent/subagent-fork/src/index.ts`, `packages/subagent/subagent-acp/src/index.ts`); the sole production `ctx.subagents.start` caller (`packages/subagent/tool-subagent/src/index.ts`) built `{ prompt, parent, signal?, agentOptions? }` and structurally could not set either; `structured` appeared only in the scripted test fixture. The service's capability check carried two assert rows whose only exercisers were the rejection tests. - **`SubagentRun.sendMessage` / `SubagentRun.resume`** (same file): implemented by NO provider — not even the mock; the spawn spec asserts their *absence*. -The only reason `dsh-subagent` depends on `dsh-tools` at all is `outputSchema`'s `SchemaSpec` type. Three subsequent subagent workstreams (per-session snapshot replay, the fork seed boundary, the ACP backend) landed around this surface without growing a single consumer. +The only reason `dsh-subagent` depended on `dsh-tools` at the decision point was `outputSchema`'s schema type (now `ObjectJsonSchema`). Three subsequent subagent workstreams (per-session snapshot replay, the fork seed boundary, the ACP backend) landed around this surface without growing a single consumer. ## Proposal diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 5bc5657d2a..44e27bb572 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -1303,7 +1303,7 @@ export interface Config { export type ToolPresentationMode = 'native' | 'code' | 'both' ``` -Source: [`packages/core/tools/src/index.ts:382`](../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:397`](../packages/core/tools/src/index.ts) ## `@deepseek-ai/dsh-tui` diff --git a/docs/cookbook/adding-a-tool.i18n.yaml b/docs/cookbook/adding-a-tool.i18n.yaml index 070cc45f93..288ee96446 100644 --- a/docs/cookbook/adding-a-tool.i18n.yaml +++ b/docs/cookbook/adding-a-tool.i18n.yaml @@ -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 -adding-a-tool.md: a45315dc0ec92ab28963c2aca32dffcf5f778dcd -adding-a-tool.zh.md: f574957ddd0e42cedc93ddc0f3270110a8f110c5 +adding-a-tool.md: 94cb4fcfa9a0155fd57ef18f9a855a264c2eff84 +adding-a-tool.zh.md: 637dc3381765e57c2d0420164ac13fde7fb590fe diff --git a/docs/cookbook/adding-a-tool.md b/docs/cookbook/adding-a-tool.md index a45315dc0e..94cb4fcfa9 100644 --- a/docs/cookbook/adding-a-tool.md +++ b/docs/cookbook/adding-a-tool.md @@ -35,7 +35,7 @@ Registration is effect-based: disposing the plugin fiber unregisters the tool (w ## Rules of the execute() contract -- **Args are validated for you.** `defineTool` validates the model-generated `arguments` against the `SchemaSpec` before `execute` runs (type, required keys, enum membership, nested objects/arrays — [runtime arg validation](../../.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.md)), so inside `execute` the args already match `InferArgs`. You still hand-check value constraints the DSL can't express (non-empty strings, positive numbers, cross-field rules); throw a descriptive Error for those. Raw JSON-Schema tools registered directly (MCP) are NOT validated by the harness — they validate their own input. +- **Args are validated for you.** `defineTool` validates model-generated `arguments` against the unified `ParameterSchemaSpec` before `execute` runs (types, required keys, literal constraints, exact-one unions, and nested values — [runtime arg validation](../../.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.md)), so inside `execute` the args match `InferArgs`. Explicit object nodes declare `additionalProperties: true | false`; the implicit parameter root stays open. You still hand-check constraints the DSL does not express, such as non-empty strings, positive numbers, or cross-field rules. Raw JSON-Schema tools registered directly own their input validation. - **Registration borrows your readonly definition.** A typed same-process contribution is not a serialization boundary; do not mutate its schema or replace callbacks after registration. `schemas()` materializes only the explicit model-facing projection. To hot-swap a tool, dispose its owning effect and register the replacement; mutable state inside the callback's closure remains ordinary plugin state. - **Execution identity is protected.** The registry materializes `arguments` as detached lossless JSON in one recursive pass, freezes that value before policy starts, and assigns an opaque `exec.token`; `callId`, `name`, `arguments`, `agent`, `token`, and an optional enclosing-transport `parent` token stay immutable through dispatch. `parent` is identity-only and exposes no live outer execution. Treat `args` as readonly input. An around-dispatch wrapper may add, replace, or remove only `exec.signal` to impose cancellation or a deadline. - **Throwing or returning non-JSON data means `isError`.** The registry catches throws and materializes the final result before observers run. A malformed or non-JSON result becomes `{ isError: true }`, preventing a live success that cannot be logged. Throw for infrastructure failures; report domain failures in result text when the model must interpret them. diff --git a/docs/cookbook/adding-a-tool.zh.md b/docs/cookbook/adding-a-tool.zh.md index f574957ddd..637dc33817 100644 --- a/docs/cookbook/adding-a-tool.zh.md +++ b/docs/cookbook/adding-a-tool.zh.md @@ -35,7 +35,7 @@ export function apply(ctx: Context) { ## execute() 契约的规则 -- **参数已为你校验。** `defineTool` 在 `execute` 运行前,会根据 `SchemaSpec` 校验模型生成的 `arguments`(类型、必填键、枚举成员、嵌套对象/数组——见[运行时参数校验](../../.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.md)),因此 `execute` 内部的 args 已匹配 `InferArgs`。你仍需手动检查 DSL 无法表达的值约束(非空字符串、正数、跨字段规则),对这些情况抛出描述性 Error。直接注册的原始 JSON-Schema 工具(MCP)不由 harness 校验,它们自行校验输入。 +- **参数已为你校验。** `defineTool` 在 `execute` 运行前,会根据统一的 `ParameterSchemaSpec` 校验模型生成的 `arguments`(类型、必填键、字面量约束、恰好匹配一个分支的联合以及嵌套值——见[运行时参数校验](../../.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.md)),因此 `execute` 内的 args 会匹配 `InferArgs`。显式对象节点必须声明 `additionalProperties: true | false`;隐式参数根对象保持开放。你仍需手动检查 schema DSL 无法表达的约束,例如非空字符串、正数或跨字段规则。直接注册的原始 JSON Schema 工具自行负责输入校验。 - **注册借用你的只读定义。** 类型化的同进程贡献不是序列化边界;注册后不要修改其 schema 或替换回调。`schemas()` 只物化显式的模型可见投影。如需热替换工具,请 dispose 其所属副作用并注册替代品;回调闭包内的可变状态仍是普通的插件状态。 - **执行身份受保护。** 注册表在一次递归遍历中将 `arguments` 物化为分离的无损 JSON,在策略开始前冻结该值,并分配一个不透明的 `exec.token`;`callId`、`name`、`arguments`、`agent`、`token` 以及可选的外层传输 `parent` token 在整个分发过程中保持不可变。`parent` 仅用于身份标识,不暴露活跃的外层执行。请将 `args` 视为只读输入。around-dispatch 包装器只能添加、替换或移除 `exec.signal`,以施加取消或截止时间。 - **抛出异常或返回非 JSON 数据意味着 `isError`。** 注册表捕获异常,并在观察者运行前物化最终结果。格式错误或非 JSON 的结果变为 `{ isError: true }`,防止出现无法记录的活跃成功。基础设施故障请抛异常;当模型需要解读领域失败时,请在结果文本中报告。 diff --git a/docs/cordis-catalog/events.md b/docs/cordis-catalog/events.md index a213c9e11a..cde1c4340b 100644 --- a/docs/cordis-catalog/events.md +++ b/docs/cordis-catalog/events.md @@ -760,7 +760,7 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai 'tools/change'(): void ``` -Source: [`packages/core/tools/src/index.ts:116`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:131`](../../packages/core/tools/src/index.ts) ### `tools/execute` — waterfall @@ -780,7 +780,7 @@ Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a nor Types: [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:89`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:104`](../../packages/core/tools/src/index.ts) ### `tools/post-execute` — waterfall @@ -800,7 +800,7 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts Types: [PostToolDecision](../core-data-structures/tools.md) · [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:98`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:113`](../../packages/core/tools/src/index.ts) ### `tools/pre-execute` — waterfall @@ -819,7 +819,7 @@ Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approv Types: [PreToolDecision](../core-data-structures/tools.md) · [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:80`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:95`](../../packages/core/tools/src/index.ts) ### `tools/result` — emit @@ -838,7 +838,7 @@ Observe the frozen, lossless-JSON final outcome. Listener failures are contained Types: [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:106`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:121`](../../packages/core/tools/src/index.ts) ## `workflow/*` diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 5fa14917e1..48feaa92a6 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -1361,7 +1361,7 @@ async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult> Types: [ScopeKey](../core-data-structures/scope.md) · [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolGuard](../core-data-structures/tools.md) · [ToolRestriction](../core-data-structures/tools.md) · [ToolSchema](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:438`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:453`](../../packages/core/tools/src/index.ts) ## `ctx.userInteraction` — `UserInteractionService` diff --git a/docs/core-data-structures/core.md b/docs/core-data-structures/core.md index dfdc258cb0..460fdc7a48 100644 --- a/docs/core-data-structures/core.md +++ b/docs/core-data-structures/core.md @@ -11,7 +11,7 @@ Precisely, a data structure is **core** if either: 1. it flows through the agent-loop spine — the loop holds it, derives it, streams it, or logs it on every turn (a `Message`, a `StreamChunk`, a `SessionEvent`, the `Agent` handle itself), independent of which plugins are present; **or** 2. it is the single headline type a plugin author writes against a pipeline — `ToolDefinition` (what every tool *is*). -Everything else is documented on a **sub-page**, not here. The rule that draws the line: *the type you write, hold, or receive is core; the machinery that types it, renders it, or persists it is a sub-page detail.* So `ToolDefinition` is core, but the `SchemaSpec`/`InferArgs` DSL that types it, the `ToolCallView`/`ToolResultView` render-intent vocabulary that renders it, and the `SessionPersistence` seam that stores the event log are not — they live on the sub-pages below. +Everything else is documented on a **sub-page**, not here. The rule that draws the line: *the type you write, hold, or receive is core; the machinery that types it, renders it, or persists it is a sub-page detail.* So `ToolDefinition` is core, but the `ValueSchemaSpec`/`ParameterSchemaSpec` inference machinery that types it, the `ToolCallView`/`ToolResultView` render-intent vocabulary that renders it, and the `SessionPersistence` seam that stores the event log are not — they live on the sub-pages below. | Sub-page | Owns | |---|---| @@ -490,4 +490,4 @@ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact' The one pipeline-authoring type that is core: what every registered tool *is* — a model-facing `ToolSchema` plus an `execute` function and optional UI presenters. A tool author rarely constructs it by hand (the `defineTool` DSL builds it with typed args), but it is the contract the registry holds and the loop dispatches through. -Its full fields, the `defineTool`/`SchemaSpec`/`InferArgs` typed schema DSL, the `ToolExecution`/`ToolExecutionResult` waterfall shapes, and the tool-presentation UI vocabulary are on **[tools.md](tools.md)**. +Its full fields, the `defineTool`/`ValueSchemaSpec`/`ParameterSchemaSpec` typed schema DSL, the `ToolExecution`/`ToolExecutionResult` waterfall shapes, and the tool-presentation UI vocabulary are on **[tools.md](tools.md)**. diff --git a/docs/core-data-structures/subagent.md b/docs/core-data-structures/subagent.md index bd4324e697..1b048b94d3 100644 --- a/docs/core-data-structures/subagent.md +++ b/docs/core-data-structures/subagent.md @@ -63,11 +63,11 @@ interface SubagentStartRequest { /** Per-child agent options (model and plugin-defined extension fields). */ readonly agentOptions?: AgentOptions /** - * Object-rooted JSON Schema within `assertSupportedOutputSchema`'s enforced subset. Start rejects + * Object-rooted JSON Schema within `assertObjectJsonSchema`'s enforced subset. Start rejects * unsupported schemas or providers without the capability. Data must be plain host-realm JSON; * a successful child returns the matching value as {@link SubagentResult.structured}. */ - readonly outputSchema?: StructuredOutputSchema + readonly outputSchema?: ObjectJsonSchema /** * Optional absolute delegation-depth cap for the child being started: its * computed depth must be less than or equal to this non-negative safe diff --git a/docs/core-data-structures/tools.md b/docs/core-data-structures/tools.md index 9e3d698440..20a74e0190 100644 --- a/docs/core-data-structures/tools.md +++ b/docs/core-data-structures/tools.md @@ -57,65 +57,65 @@ interface ToolDefinition extends ToolSchema { `execute` receives `args: unknown` — a raw `ToolDefinition` validates its own input. First-party tools don't write that by hand; they use `defineTool`, which validates and narrows for them. -## The typed schema DSL +## The unified JSON-value schema DSL -Plugin authors write per-property specs with a boolean `required: true`, and a type-level helper maps the spec to the `execute` argument type — zero casts. The DSL is *machinery that types* `ToolDefinition`; it is intentionally a sub-page detail, not core. +Plugin authors use one vocabulary for typed parameters and typed output values. `ValueSchemaSpec` supports `string`, `number`, `integer`, `boolean`, `null`, `array`, `object`, author-only `json`, and exact-one `oneOf`; scalar `enum` and `const` values must match their node type. An explicit object node always declares `additionalProperties: true | false`. Parameter definitions remain an implicit open object property map, with `required: true` attached to each required property. Source: [`packages/core/tools/src/schema.ts`](../../packages/core/tools/src/schema.ts) ```ts type-equiv -/** One schema-spec property entry. */ -interface SchemaProp { - type: SchemaType - /** Per-property required flag (NOT the JSON Schema top-level required array). */ - required?: true - /** Human-readable description, surfaced in the JSON Schema as well. */ - description?: string - /** Enum of allowed values (strings only). */ - enum?: string[] - /** - * Model-visible JSON Schema default annotation. Validation does not apply it; - * dynamic tool mounts may supply it even though first-party definitions do not. - */ - default?: unknown - /** Nested properties for type: 'object'. */ - properties?: SchemaSpec - /** Items schema for type: 'array'. */ - items?: SchemaProp -} +/** One author-facing schema for any lossless JSON value root. */ +type ValueSchemaSpec = + | StringValueSchemaSpec + | NumberValueSchemaSpec + | IntegerValueSchemaSpec + | BooleanValueSchemaSpec + | NullValueSchemaSpec + | ArrayValueSchemaSpec + | ObjectValueSchemaSpec + | JsonValueSchemaSpec + | OneOfValueSchemaSpec +``` + +```ts type-equiv +/** One implicit parameter-root property, optionally required. */ +type ParameterPropertySpec = ValueSchemaSpec & { required?: true } ``` ```ts type-equiv /** - * The author-facing parameter schema: a shallow map of property name to - * {@link SchemaProp}. Required-ness is a per-property boolean (`required: - * true`), not a separate array. + * Tool parameter schema. The map itself is an implicit open object root; + * requiredness remains a per-property `required: true` annotation. */ -type SchemaSpec = Record<string, SchemaProp> +type ParameterSchemaSpec = Record<string, ParameterPropertySpec> ``` -`SchemaType` is the primitive union `'string' | 'number' | 'boolean' | 'object' | 'array'`. `InferArgs<S>` maps a `SchemaSpec` to the TS argument type — `required: true` props become required keys, everything else genuinely optional: +`{ type: 'json' }` infers `JsonValue` and compiles to an annotation-only unconstrained raw schema. Output roots can be objects, arrays, scalars, or null. `InferValue<S>` honors literal constraints and object openness; `InferArgs<P>` turns per-property requiredness into required and optional keys: ```ts type-equiv /** - * Infer the TS argument type for a complete {@link SchemaSpec}. - * - * Properties marked `required: true` are required keys; all others are - * genuinely optional keys (`?`), so callers may omit them entirely. - * - * Example: - * ```ts - * type Args = InferArgs<{ path: { type: 'string'; required: true }; limit: { type: 'number' } }> - * // → { path: string; limit?: number } - * ``` + * Infer the TypeScript value accepted by an author-facing value schema. + * Output schemas may therefore infer object, array, scalar, or null roots. */ -type InferArgs<S extends SchemaSpec> = Simplify< - & { [K in RequiredKeys<S>]: InferPropValue<S[K]> } - & { [K in Exclude<keyof S, RequiredKeys<S>>]?: InferPropValue<S[K]> } -> +type InferValue<S extends ValueSchemaSpec> = + S extends StringValueSchemaSpec ? InferScalar<S, string> : + S extends NumberValueSchemaSpec | IntegerValueSchemaSpec ? InferScalar<S, number> : + S extends BooleanValueSchemaSpec ? InferScalar<S, boolean> : + S extends NullValueSchemaSpec ? null : + S extends ArrayValueSchemaSpec + ? S extends { items: infer I extends ValueSchemaSpec } ? InferValue<I>[] : JsonValue[] + : S extends ObjectValueSchemaSpec ? InferObject<S> : + S extends JsonValueSchemaSpec ? JsonValue : + S extends OneOfValueSchemaSpec ? InferValue<S['oneOf'][number]> : + never ``` -`defineTool({ name, description, parameters, execute, … })` ties it together: `parameters` is a `SchemaSpec`, `execute(args, exec)` gets `args: InferArgs<typeof parameters>`, and the helper converts the spec to JSON Schema (`schemaSpecToJsonSchema`) for the wire and validates model-generated args (`validateArgs`) before the typed body runs. A mismatch throws `ToolArgsError` (`code: 'INVALID_ARGS'`), which the registry turns into an `isError` result so the model can self-correct. Why a custom DSL and not schemastery: tool parameters need JSON Schema (the LLM wire format), not validation/transformation — the lightweight DSL gives the best authoring DX with the smallest surface. +```ts type-equiv +/** Infer the TypeScript argument object for an implicit parameter schema. */ +type InferArgs<S extends ParameterSchemaSpec> = InferProperties<S> +``` + +`defineTool({ name, description, parameters, execute, … })` ties parameter inference to `parameterSchemaSpecToJsonSchema()` and `validateArgs()`. `valueSchemaSpecToJsonSchema()` compiles value/output declarations through the same enforced raw subset. A parameter mismatch throws `ToolArgsError` (`INVALID_ARGS`), which the registry returns through the normal tool-error path. Raw JSON Schema remains open by default; unsupported keywords reject instead of being accepted without enforcement. Registration is a trusted same-process contract. The registry borrows the typed definition as readonly input and validates only semantic requirements such as a positive finite `timeoutMs`; `schemas()` materializes the explicit model-facing projection at the model boundary so execution and presentation share one resolved definition without leaking callbacks onto the wire. @@ -288,55 +288,57 @@ Call `next()` for the default or return a decision to short-circuit. Pre-policy Post-policy may replace content; a block becomes an `isError` result containing its corrective feedback. `tools/result` receives the frozen execution and result after normalization; observers cannot transform them, and observer failures are contained. Unknown and throwing tools both become structured errors (`ToolNotFoundError` maps to `UNKNOWN_TOOL`), so the call fails without ending the turn. -## The structured-output schema subset +## The enforced raw JSON Schema subset -The vocabulary a caller uses to demand a machine-readable result from a subagent (`SubagentStartRequest.outputSchema`, [subagent.md](subagent.md#the-start-request)) or a workflow `agent()` call. It is deliberately NOT full JSON Schema: the schema travels verbatim to the model as a forced tool's `parameters`, and the produced value is validated client-side by `validateStructuredValue` — so every accepted keyword must be one the validator actually enforces, and `assertSupportedOutputSchema` rejects anything else loud (`OutputSchemaError`, listing every violation). Both walkers reason over own enumerable properties only (JSON carries nothing else) and reject non-plain objects (`Date`, `Map`) that would serialize lossily. +Raw schemas from subagents, workflows, MCP, and dynamic registrations use the wire-level counterpart of the author DSL. `assertSupportedJsonSchema()` accepts any JSON root, `validateJsonSchemaValue()` enforces it, and `JsonSchemaError` reports every unsupported or malformed schema path. The empty annotation-only node means unconstrained lossless JSON. `oneOf` requires at least two branches and a value must match exactly one. Consumers that still require an object root call `assertObjectJsonSchema()` and carry `ObjectJsonSchema`; this is how subagent/workflow caller-defined structured output remains object-rooted without restricting the shared vocabulary. ```ts type-equiv -/** The scalar values `enum`/`const` may carry (finite numbers only). */ -type StructuredScalar = string | number | boolean | null +/** Scalar JSON values supported by `enum` and `const`. */ +type JsonSchemaScalar = string | number | boolean | null ``` ```ts type-equiv -/** The `type` keywords the subset accepts. */ -type StructuredSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null' +/** Single-type keywords accepted by the enforced subset. */ +type JsonSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null' ``` ```ts type-equiv /** - * One node of the structured-output schema subset. Recursive via `properties` - * and `items`; see the module doc for the exact keyword semantics. + * One raw JSON Schema node in the enforced subset. The optional fields express + * the external wire shape; {@link assertSupportedJsonSchema} rejects invalid + * combinations before a caller treats the node as trusted. */ -interface StructuredSchemaNode { - type: StructuredSchemaType +interface JsonSchemaNode { + /** Omit with no constraints for any JSON value, or use `oneOf`. */ + type?: JsonSchemaType + /** Exactly one branch must validate; at least two branches are required. */ + oneOf?: JsonSchemaNode[] /** Nested property schemas (`type: 'object'` only). */ - properties?: Record<string, StructuredSchemaNode> + properties?: Record<string, JsonSchemaNode> /** Required property names; each must appear in `properties`. */ required?: string[] - /** `false` rejects undeclared keys; absent/`true` allows them (JSON Schema default). */ + /** `false` rejects undeclared keys; absent/`true` follows JSON Schema's open default. */ additionalProperties?: boolean - /** Item schema (`type: 'array'` only); absent ⇒ any JSON items. */ - items?: StructuredSchemaNode - /** Allowed values (scalar types only). */ - enum?: StructuredScalar[] - /** The single allowed value (scalar types only). */ - const?: StructuredScalar + /** Item schema (`type: 'array'` only); absent accepts any JSON item. */ + items?: JsonSchemaNode + /** Allowed values for a scalar node. */ + enum?: JsonSchemaScalar[] + /** The single allowed value for a scalar node. */ + const?: JsonSchemaScalar /** Annotation, ignored for validation. */ description?: string /** Annotation, ignored for validation. */ title?: string - /** Annotation, ignored for validation (must still be JSON data). */ - default?: unknown - /** Annotation, ignored for validation (must still be JSON data). */ - examples?: unknown + /** Annotation, ignored for validation but required to be lossless JSON. */ + default?: JsonValue + /** Annotation, ignored for validation but required to be lossless JSON. */ + examples?: JsonValue } ``` -A schema is an object-rooted node (`enum`/`const` are scalar-only; `description`/`title`/`default`/`examples` are annotations, allowed and ignored but still required to be JSON data — they ride the wire): - ```ts type-equiv -/** A structured-output schema: an OBJECT-rooted {@link StructuredSchemaNode}. */ -type StructuredOutputSchema = StructuredSchemaNode & { type: 'object' } +/** A consumer-constrained object-rooted schema. */ +type ObjectJsonSchema = JsonSchemaNode & { type: 'object' } ``` ## Tool-presentation UI vocabulary diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index 99acf07d24..6185522793 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -41,11 +41,11 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:130`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude) | | `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:27`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`acp`](../packages/ui/acp) | | `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:33`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - | -| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:116`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | -| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:89`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`timeout-policy`](../packages/timeout/timeout-policy) | -| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:98`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`workspace-context`](../packages/context/workspace-context) | -| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:80`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | -| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:106`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | +| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:131`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | +| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:104`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`timeout-policy`](../packages/timeout/timeout-policy) | +| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:113`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`workspace-context`](../packages/context/workspace-context) | +| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:95`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | +| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:121`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:81`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | | `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:70`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | | `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:91`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md index 6196a71521..eaf24e38a7 100644 --- a/docs/tool-catalog.md +++ b/docs/tool-catalog.md @@ -45,6 +45,7 @@ Ask the user a concise question when you need confirmation, a choice, or missing "description": "Questions to ask the user before continuing.", "items": { "type": "object", + "additionalProperties": true, "properties": { "id": { "type": "string", @@ -63,6 +64,7 @@ Ask the user a concise question when you need confirmation, a choice, or missing "description": "Optional choices to show the user. If you recommend one, put it first and append \"(Recommended)\" to that label.", "items": { "type": "object", + "additionalProperties": true, "properties": { "label": { "type": "string", @@ -201,7 +203,7 @@ Source: [`packages/cordis/tool-cordis/src/index.ts`](../packages/cordis/tool-cor ### `cordis_mount` -Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, async execute(args) { … } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'boolean'|'object'|'array', required?: true, description?, enum?, items?, properties? }; a JSON-Schema-style { type: 'object', properties, required: […] } wrapper and type 'integer' are also accepted and normalized. A tool's `execute` MUST return an ARRAY of content blocks, e.g. `return [{ type: 'text', text: someString }]` — never a bare string. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime. +Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, async execute(args) { … } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return an ARRAY of content blocks, e.g. `return [{ type: 'text', text: someString }]` — never a bare string. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime. ```json { @@ -659,6 +661,7 @@ Record and update a structured task list for the current work. Send the ENTIRE l "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -720,6 +723,7 @@ Constraints: concurrency and total-agent caps apply; no filesystem, network, tim "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -738,6 +742,7 @@ Constraints: concurrency and total-agent caps apply; no filesystem, network, tim "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -769,7 +774,8 @@ Constraints: concurrency and total-agent caps apply; no filesystem, network, tim }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ diff --git a/docs/user/develop/basic/tool.i18n.yaml b/docs/user/develop/basic/tool.i18n.yaml index d2f4343cf1..b741ccf65f 100644 --- a/docs/user/develop/basic/tool.i18n.yaml +++ b/docs/user/develop/basic/tool.i18n.yaml @@ -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 -tool.md: 416733bcb584fa5303a8b3ba5e6e904302e7f992 -tool.zh.md: fce9a7d9b973853c8b4fb9ae2c034e749d8da999 +tool.md: 17adbfc5f7eb804856dfe39b4d2b4a65374b6414 +tool.zh.md: 8857e16ca836dfa5b158a68581bd3c715dcb1ac5 diff --git a/docs/user/develop/basic/tool.md b/docs/user/develop/basic/tool.md index 416733bcb5..17adbfc5f7 100644 --- a/docs/user/develop/basic/tool.md +++ b/docs/user/develop/basic/tool.md @@ -37,10 +37,11 @@ export function apply(ctx: Context) { ```ts export const parameters = { path: { type: 'string', required: true }, - limit: { type: 'number' }, + limit: { type: 'integer' }, recursive: { type: 'boolean' }, + parent: { type: 'null' }, } -// Inferred type: { path: string; limit?: number; recursive?: boolean } +// Inferred type: { path: string; limit?: number; recursive?: boolean; parent?: null } ``` ### Enums @@ -49,7 +50,7 @@ export const parameters = { export const parameters = { mode: { type: 'string', required: true, enum: ['read', 'write', 'append'] }, } -// Inferred type: { mode: string } (enum values are validated at runtime) +// Inferred type: { mode: 'read' | 'write' | 'append' } ``` ### Nested objects @@ -58,13 +59,14 @@ export const parameters = { export const parameters = { options: { type: 'object', + additionalProperties: true, properties: { timeout: { type: 'number' }, retries: { type: 'number' }, }, }, } -// Inferred type: { options?: { timeout?: number; retries?: number } } +// The declared fields are inferred; additional JSON-valued keys are allowed. ``` ### Arrays @@ -83,12 +85,16 @@ export const parameters = { | Field | Type | Meaning | |------|------|------| -| `type` | `'string' \| 'number' \| 'boolean' \| 'object' \| 'array'` | Value type | +| `type` | `'string' \| 'number' \| 'integer' \| 'boolean' \| 'null' \| 'object' \| 'array' \| 'json'` | Value type; `json` accepts any lossless JSON value | | `required` | `true` | Marks the property required and affects inference | | `description` | `string` | Description sent to the model | -| `enum` | `string[]` | Allowed string values | -| `properties` | `SchemaSpec` | Nested properties for an object | -| `items` | `SchemaProp` | Element schema for an array | +| `enum` / `const` | matching scalar values | Allowed literal values, checked at author and runtime boundaries | +| `properties` | `ParameterSchemaSpec` | Nested properties for an object | +| `additionalProperties` | `true \| false` | Required on every explicit object node | +| `items` | `ValueSchemaSpec` | Element schema for an array | +| `oneOf` | at least two `ValueSchemaSpec` branches | Requires exactly one matching branch; used instead of `type` | + +The outer `parameters` map is an implicit open object. Explicit nested objects choose their openness; raw JSON Schema registered without `defineTool` keeps JSON Schema's open-by-default behavior. ## The execute function diff --git a/docs/user/develop/basic/tool.zh.md b/docs/user/develop/basic/tool.zh.md index fce9a7d9b9..8857e16ca8 100644 --- a/docs/user/develop/basic/tool.zh.md +++ b/docs/user/develop/basic/tool.zh.md @@ -37,10 +37,11 @@ export function apply(ctx: Context) { ```ts export const parameters = { path: { type: 'string', required: true }, - limit: { type: 'number' }, + limit: { type: 'integer' }, recursive: { type: 'boolean' }, + parent: { type: 'null' }, } -// Inferred type: { path: string; limit?: number; recursive?: boolean } +// Inferred type: { path: string; limit?: number; recursive?: boolean; parent?: null } ``` ### 枚举 @@ -49,7 +50,7 @@ export const parameters = { export const parameters = { mode: { type: 'string', required: true, enum: ['read', 'write', 'append'] }, } -// Inferred type: { mode: string } (enum values are validated at runtime) +// Inferred type: { mode: 'read' | 'write' | 'append' } ``` ### 嵌套对象 @@ -58,13 +59,14 @@ export const parameters = { export const parameters = { options: { type: 'object', + additionalProperties: true, properties: { timeout: { type: 'number' }, retries: { type: 'number' }, }, }, } -// Inferred type: { options?: { timeout?: number; retries?: number } } +// The declared fields are inferred; additional JSON-valued keys are allowed. ``` ### 数组 @@ -83,12 +85,16 @@ export const parameters = { | 字段 | 类型 | 说明 | |------|------|------| -| `type` | `'string' \| 'number' \| 'boolean' \| 'object' \| 'array'` | 值类型 | +| `type` | `'string' \| 'number' \| 'integer' \| 'boolean' \| 'null' \| 'object' \| 'array' \| 'json'` | 值类型;`json` 接受任意无损 JSON 值 | | `required` | `true` | 标记为必填(影响类型推导) | | `description` | `string` | 发送给模型的描述 | -| `enum` | `string[]` | 允许的枚举值 | -| `properties` | `SchemaSpec` | 嵌套属性(type 为 object 时) | -| `items` | `SchemaProp` | 数组元素 schema(type 为 array 时) | +| `enum` / `const` | 匹配类型的标量值 | 允许的字面量值,在编写和运行时边界校验 | +| `properties` | `ParameterSchemaSpec` | 对象的嵌套属性 | +| `additionalProperties` | `true \| false` | 每个显式对象节点都必须声明 | +| `items` | `ValueSchemaSpec` | 数组的元素 schema | +| `oneOf` | 至少两个 `ValueSchemaSpec` 分支 | 要求恰好匹配一个分支;代替 `type` 使用 | + +外层 `parameters` 映射是一个隐式的开放对象。显式嵌套对象需自行选择是否开放;不通过 `defineTool` 注册的原始 JSON Schema 保持 JSON Schema 的默认开放语义。 ## execute 函数 diff --git a/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md index e5773c1319..3e111b8ba2 100644 --- a/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md @@ -36,6 +36,8 @@ Pass `run_code` the body of an async TypeScript function (erasable syntax only The available tools: ```ts +type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } + declare const tools: { /** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Current harness environment facts are exposed through managed `$DSH_*` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`. Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later. */ bash(args: { @@ -53,31 +55,31 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Inspect the live cordis runtime that is running THIS agent. Read-only. Sections: `services` (every provided ctx service and the plugin fiber that owns it), `plugins` (a flat list of the loaded plugins with their lifecycle states), `tools` (the model-facing tools currently registered, i.e. what you can call), `dynamic` (plugins you mounted via cordis_mount: id, name, state, provided services, awaited services), `api` (method signatures AND argument/return type shapes for every LIVE service — read this before writing plugin code that calls a service), `events` (every harness event with its dispatch mode and exact signature — pick listener targets here). Omit `what` to get all six sections. With `what:"api"` or `what:"events"`, pass an exact `name` to narrow to one service/event and include its original source JSDoc. */ cordis_inspect(args: { /** Limit the report to one section. Omit for all sections. */ what?: "services" | "plugins" | "tools" | "dynamic" | "api" | "events"; /** Exact service key or event name whose original JSDoc to include; valid only with what:"api" or what:"events". */ name?: string; - }): Promise<string>; - /** Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, async execute(args) { … } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'boolean'|'object'|'array', required?: true, description?, enum?, items?, properties? }; a JSON-Schema-style { type: 'object', properties, required: […] } wrapper and type 'integer' are also accepted and normalized. A tool's `execute` MUST return an ARRAY of content blocks, e.g. `return [{ type: 'text', text: someString }]` — never a bare string. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime. */ + } & Record<string, JsonValue>): Promise<string>; + /** Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, async execute(args) { … } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return an ARRAY of content blocks, e.g. `return [{ type: 'text', text: someString }]` — never a bare string. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime. */ cordis_mount(args: { /** Body of an async JS function; must `return` the plugin to mount. */ code: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Dispose a plugin previously mounted with cordis_mount, by id. All its registrations (event listeners, tools, services) are cleaned up through the cordis effect lifecycle. Returns only after disposal has fully completed (quiescence, not just a request to stop). */ cordis_unmount(args: { /** The dynamic mount id returned by cordis_mount (e.g. "dyn-1"). */ id: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say "create a goal". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority. */ create_goal(args: { /** The concrete completion objective inferred from the direct human request. */ objective: string; /** Optional positive safe-integer limit on automatic continuation rounds. */ max_goal_rounds?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Edit an existing UTF-8 text file by replacing literal text. */ edit(args: { /** Path to edit, resolved by the filesystem backend. */ @@ -92,16 +94,16 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal. */ - get_goal(args: Record<string, unknown>): Promise<string>; + get_goal(args: Record<string, JsonValue>): Promise<string>; /** Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools. */ ralph(args: { /** The immutable completion objective for every fresh Ralph round. */ objective: string; /** Optional positive safe-integer round cap, bounded by the deployment ceiling. */ maxRounds?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Read a UTF-8 text file and return line-numbered content. */ read(args: { /** Path to read, resolved by the filesystem backend. */ @@ -110,12 +112,12 @@ declare const tools: { offset?: number; /** Maximum number of lines to return. Defaults to 2000. */ limit?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */ skill(args: { /** The exact skill name from the available skills list. */ name: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ subagent(args: { /** A short (3-5 word) description of the delegated task, for display. */ @@ -124,7 +126,7 @@ declare const tools: { prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ subagent_fork(args: { /** A short (3-5 word) description of the delegated task, for display. */ @@ -133,16 +135,16 @@ declare const tools: { prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops. */ task_kill(args: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Optional short reason, recorded in the log and forwarded to the task. */ reason?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** List your background tasks (running and finished) with their ids, kinds, and statuses. */ - task_list(args: Record<string, unknown>): Promise<string>; + task_list(args: Record<string, JsonValue>): Promise<string>; /** Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap. */ task_output(args: { /** Task id returned by the tool that started the background work. */ @@ -151,7 +153,7 @@ declare const tools: { wait?: boolean; /** Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum. */ timeout_ms?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Keep AT MOST ONE todo `in_progress` at a time; while work remains, exactly one active task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished). */ todo_write(args: { /** The COMPLETE task list, replacing any previous list. */ @@ -160,8 +162,8 @@ declare const tools: { content: string; /** pending (not started) | in_progress (now) | completed (done). */ status: "pending" | "in_progress" | "completed"; - })[]; - }): Promise<string>; + } & Record<string, JsonValue>)[]; + } & Record<string, JsonValue>): Promise<string>; /** Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason. */ update_goal(args: { /** Exact id returned by get_goal. */ @@ -176,7 +178,7 @@ declare const tools: { max_goal_rounds?: number; /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ workflow(args: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ @@ -190,7 +192,7 @@ declare const tools: { /** Optional guidance on when this workflow applies. */ whenToUse?: string; /** Optional phase declarations matched by phase() calls. */ - phases?: { + phases?: ({ /** The phase title phase() calls match by exact string. */ title: string; /** Optional one-line description of the phase. */ @@ -199,11 +201,11 @@ declare const tools: { provider?: string; /** Optional model override this phase is expected to use. */ model?: string; - }[]; - }; + } & Record<string, JsonValue>)[]; + } & Record<string, JsonValue>; /** Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}). */ - args?: Record<string, unknown>; - }): Promise<string>; + args?: Record<string, JsonValue>; + } & Record<string, JsonValue>): Promise<string>; /** Create or fully replace a UTF-8 text file. */ write(args: { /** Path to write, resolved by the filesystem backend. */ @@ -214,6 +216,6 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; } ``` diff --git a/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json index 71597bc9c3..95cdd43b83 100644 --- a/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json @@ -72,7 +72,7 @@ }, { "name": "cordis_mount", - "description": "Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:\"api\" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:\"events\"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, async execute(args) { … } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'boolean'|'object'|'array', required?: true, description?, enum?, items?, properties? }; a JSON-Schema-style { type: 'object', properties, required: […] } wrapper and type 'integer' are also accepted and normalized. A tool's `execute` MUST return an ARRAY of content blocks, e.g. `return [{ type: 'text', text: someString }]` — never a bare string. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:\"api\" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime.", + "description": "Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:\"api\" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:\"events\"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, async execute(args) { … } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return an ARRAY of content blocks, e.g. `return [{ type: 'text', text: someString }]` — never a bare string. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:\"api\" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime.", "parameters": { "type": "object", "properties": { @@ -361,6 +361,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -446,6 +447,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -464,6 +466,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -495,7 +498,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ diff --git a/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md index ac1114d0a3..2ec278e294 100644 --- a/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md @@ -36,6 +36,8 @@ Pass `run_code` the body of an async TypeScript function (erasable syntax only The available tools: ```ts +type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } + declare const tools: { /** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Current harness environment facts are exposed through managed `$DSH_*` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`. Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later. */ bash(args: { @@ -53,14 +55,14 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say "create a goal". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority. */ create_goal(args: { /** The concrete completion objective inferred from the direct human request. */ objective: string; /** Optional positive safe-integer limit on automatic continuation rounds. */ max_goal_rounds?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Edit an existing UTF-8 text file by replacing literal text. */ edit(args: { /** Path to edit, resolved by the filesystem backend. */ @@ -75,16 +77,16 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal. */ - get_goal(args: Record<string, unknown>): Promise<string>; + get_goal(args: Record<string, JsonValue>): Promise<string>; /** Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools. */ ralph(args: { /** The immutable completion objective for every fresh Ralph round. */ objective: string; /** Optional positive safe-integer round cap, bounded by the deployment ceiling. */ maxRounds?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Read a UTF-8 text file and return line-numbered content. */ read(args: { /** Path to read, resolved by the filesystem backend. */ @@ -93,12 +95,12 @@ declare const tools: { offset?: number; /** Maximum number of lines to return. Defaults to 2000. */ limit?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */ skill(args: { /** The exact skill name from the available skills list. */ name: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ subagent(args: { /** A short (3-5 word) description of the delegated task, for display. */ @@ -107,7 +109,7 @@ declare const tools: { prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ subagent_fork(args: { /** A short (3-5 word) description of the delegated task, for display. */ @@ -116,16 +118,16 @@ declare const tools: { prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops. */ task_kill(args: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Optional short reason, recorded in the log and forwarded to the task. */ reason?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** List your background tasks (running and finished) with their ids, kinds, and statuses. */ - task_list(args: Record<string, unknown>): Promise<string>; + task_list(args: Record<string, JsonValue>): Promise<string>; /** Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap. */ task_output(args: { /** Task id returned by the tool that started the background work. */ @@ -134,7 +136,7 @@ declare const tools: { wait?: boolean; /** Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum. */ timeout_ms?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Keep AT MOST ONE todo `in_progress` at a time; while work remains, exactly one active task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished). */ todo_write(args: { /** The COMPLETE task list, replacing any previous list. */ @@ -143,8 +145,8 @@ declare const tools: { content: string; /** pending (not started) | in_progress (now) | completed (done). */ status: "pending" | "in_progress" | "completed"; - })[]; - }): Promise<string>; + } & Record<string, JsonValue>)[]; + } & Record<string, JsonValue>): Promise<string>; /** Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason. */ update_goal(args: { /** Exact id returned by get_goal. */ @@ -159,7 +161,7 @@ declare const tools: { max_goal_rounds?: number; /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ workflow(args: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ @@ -173,7 +175,7 @@ declare const tools: { /** Optional guidance on when this workflow applies. */ whenToUse?: string; /** Optional phase declarations matched by phase() calls. */ - phases?: { + phases?: ({ /** The phase title phase() calls match by exact string. */ title: string; /** Optional one-line description of the phase. */ @@ -182,11 +184,11 @@ declare const tools: { provider?: string; /** Optional model override this phase is expected to use. */ model?: string; - }[]; - }; + } & Record<string, JsonValue>)[]; + } & Record<string, JsonValue>; /** Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}). */ - args?: Record<string, unknown>; - }): Promise<string>; + args?: Record<string, JsonValue>; + } & Record<string, JsonValue>): Promise<string>; /** Create or fully replace a UTF-8 text file. */ write(args: { /** Path to write, resolved by the filesystem backend. */ @@ -197,6 +199,6 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; } ``` diff --git a/examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json index ab52ec415d..8406669edc 100644 --- a/examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json @@ -304,6 +304,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -389,6 +390,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -407,6 +409,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -438,7 +441,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md index ac1114d0a3..2ec278e294 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md @@ -36,6 +36,8 @@ Pass `run_code` the body of an async TypeScript function (erasable syntax only The available tools: ```ts +type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } + declare const tools: { /** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Current harness environment facts are exposed through managed `$DSH_*` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`. Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later. */ bash(args: { @@ -53,14 +55,14 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say "create a goal". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority. */ create_goal(args: { /** The concrete completion objective inferred from the direct human request. */ objective: string; /** Optional positive safe-integer limit on automatic continuation rounds. */ max_goal_rounds?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Edit an existing UTF-8 text file by replacing literal text. */ edit(args: { /** Path to edit, resolved by the filesystem backend. */ @@ -75,16 +77,16 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal. */ - get_goal(args: Record<string, unknown>): Promise<string>; + get_goal(args: Record<string, JsonValue>): Promise<string>; /** Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools. */ ralph(args: { /** The immutable completion objective for every fresh Ralph round. */ objective: string; /** Optional positive safe-integer round cap, bounded by the deployment ceiling. */ maxRounds?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Read a UTF-8 text file and return line-numbered content. */ read(args: { /** Path to read, resolved by the filesystem backend. */ @@ -93,12 +95,12 @@ declare const tools: { offset?: number; /** Maximum number of lines to return. Defaults to 2000. */ limit?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */ skill(args: { /** The exact skill name from the available skills list. */ name: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ subagent(args: { /** A short (3-5 word) description of the delegated task, for display. */ @@ -107,7 +109,7 @@ declare const tools: { prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ subagent_fork(args: { /** A short (3-5 word) description of the delegated task, for display. */ @@ -116,16 +118,16 @@ declare const tools: { prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops. */ task_kill(args: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Optional short reason, recorded in the log and forwarded to the task. */ reason?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** List your background tasks (running and finished) with their ids, kinds, and statuses. */ - task_list(args: Record<string, unknown>): Promise<string>; + task_list(args: Record<string, JsonValue>): Promise<string>; /** Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap. */ task_output(args: { /** Task id returned by the tool that started the background work. */ @@ -134,7 +136,7 @@ declare const tools: { wait?: boolean; /** Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum. */ timeout_ms?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Keep AT MOST ONE todo `in_progress` at a time; while work remains, exactly one active task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished). */ todo_write(args: { /** The COMPLETE task list, replacing any previous list. */ @@ -143,8 +145,8 @@ declare const tools: { content: string; /** pending (not started) | in_progress (now) | completed (done). */ status: "pending" | "in_progress" | "completed"; - })[]; - }): Promise<string>; + } & Record<string, JsonValue>)[]; + } & Record<string, JsonValue>): Promise<string>; /** Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason. */ update_goal(args: { /** Exact id returned by get_goal. */ @@ -159,7 +161,7 @@ declare const tools: { max_goal_rounds?: number; /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ workflow(args: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ @@ -173,7 +175,7 @@ declare const tools: { /** Optional guidance on when this workflow applies. */ whenToUse?: string; /** Optional phase declarations matched by phase() calls. */ - phases?: { + phases?: ({ /** The phase title phase() calls match by exact string. */ title: string; /** Optional one-line description of the phase. */ @@ -182,11 +184,11 @@ declare const tools: { provider?: string; /** Optional model override this phase is expected to use. */ model?: string; - }[]; - }; + } & Record<string, JsonValue>)[]; + } & Record<string, JsonValue>; /** Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}). */ - args?: Record<string, unknown>; - }): Promise<string>; + args?: Record<string, JsonValue>; + } & Record<string, JsonValue>): Promise<string>; /** Create or fully replace a UTF-8 text file. */ write(args: { /** Path to write, resolved by the filesystem backend. */ @@ -197,6 +199,6 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; } ``` diff --git a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md index ac1114d0a3..2ec278e294 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md @@ -36,6 +36,8 @@ Pass `run_code` the body of an async TypeScript function (erasable syntax only The available tools: ```ts +type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } + declare const tools: { /** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Current harness environment facts are exposed through managed `$DSH_*` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`. Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later. */ bash(args: { @@ -53,14 +55,14 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say "create a goal". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority. */ create_goal(args: { /** The concrete completion objective inferred from the direct human request. */ objective: string; /** Optional positive safe-integer limit on automatic continuation rounds. */ max_goal_rounds?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Edit an existing UTF-8 text file by replacing literal text. */ edit(args: { /** Path to edit, resolved by the filesystem backend. */ @@ -75,16 +77,16 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal. */ - get_goal(args: Record<string, unknown>): Promise<string>; + get_goal(args: Record<string, JsonValue>): Promise<string>; /** Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools. */ ralph(args: { /** The immutable completion objective for every fresh Ralph round. */ objective: string; /** Optional positive safe-integer round cap, bounded by the deployment ceiling. */ maxRounds?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Read a UTF-8 text file and return line-numbered content. */ read(args: { /** Path to read, resolved by the filesystem backend. */ @@ -93,12 +95,12 @@ declare const tools: { offset?: number; /** Maximum number of lines to return. Defaults to 2000. */ limit?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */ skill(args: { /** The exact skill name from the available skills list. */ name: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ subagent(args: { /** A short (3-5 word) description of the delegated task, for display. */ @@ -107,7 +109,7 @@ declare const tools: { prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ subagent_fork(args: { /** A short (3-5 word) description of the delegated task, for display. */ @@ -116,16 +118,16 @@ declare const tools: { prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops. */ task_kill(args: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Optional short reason, recorded in the log and forwarded to the task. */ reason?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** List your background tasks (running and finished) with their ids, kinds, and statuses. */ - task_list(args: Record<string, unknown>): Promise<string>; + task_list(args: Record<string, JsonValue>): Promise<string>; /** Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap. */ task_output(args: { /** Task id returned by the tool that started the background work. */ @@ -134,7 +136,7 @@ declare const tools: { wait?: boolean; /** Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum. */ timeout_ms?: number; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Keep AT MOST ONE todo `in_progress` at a time; while work remains, exactly one active task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished). */ todo_write(args: { /** The COMPLETE task list, replacing any previous list. */ @@ -143,8 +145,8 @@ declare const tools: { content: string; /** pending (not started) | in_progress (now) | completed (done). */ status: "pending" | "in_progress" | "completed"; - })[]; - }): Promise<string>; + } & Record<string, JsonValue>)[]; + } & Record<string, JsonValue>): Promise<string>; /** Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason. */ update_goal(args: { /** Exact id returned by get_goal. */ @@ -159,7 +161,7 @@ declare const tools: { max_goal_rounds?: number; /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ workflow(args: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ @@ -173,7 +175,7 @@ declare const tools: { /** Optional guidance on when this workflow applies. */ whenToUse?: string; /** Optional phase declarations matched by phase() calls. */ - phases?: { + phases?: ({ /** The phase title phase() calls match by exact string. */ title: string; /** Optional one-line description of the phase. */ @@ -182,11 +184,11 @@ declare const tools: { provider?: string; /** Optional model override this phase is expected to use. */ model?: string; - }[]; - }; + } & Record<string, JsonValue>)[]; + } & Record<string, JsonValue>; /** Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}). */ - args?: Record<string, unknown>; - }): Promise<string>; + args?: Record<string, JsonValue>; + } & Record<string, JsonValue>): Promise<string>; /** Create or fully replace a UTF-8 text file. */ write(args: { /** Path to write, resolved by the filesystem backend. */ @@ -197,6 +199,6 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - }): Promise<string>; + } & Record<string, JsonValue>): Promise<string>; } ``` diff --git a/examples/acp-agent/tests/snapshots/model-switching/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/model-switching/tool-schemas.expected.json index 1bfe74b704..4ee311eb65 100644 --- a/examples/acp-agent/tests/snapshots/model-switching/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/model-switching/tool-schemas.expected.json @@ -288,6 +288,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -373,6 +374,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -391,6 +393,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -422,7 +425,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ @@ -755,6 +759,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -840,6 +845,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -858,6 +864,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -889,7 +896,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ diff --git a/examples/acp-agent/tests/snapshots/permission-switching/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/permission-switching/tool-schemas.expected.json index 1bfe74b704..4ee311eb65 100644 --- a/examples/acp-agent/tests/snapshots/permission-switching/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/permission-switching/tool-schemas.expected.json @@ -288,6 +288,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -373,6 +374,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -391,6 +393,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -422,7 +425,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ @@ -755,6 +759,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -840,6 +845,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -858,6 +864,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -889,7 +896,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ diff --git a/examples/acp-agent/tests/snapshots/skill-load/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/skill-load/tool-schemas.expected.json index 52b3c1812e..de3254fd2e 100644 --- a/examples/acp-agent/tests/snapshots/skill-load/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/skill-load/tool-schemas.expected.json @@ -288,6 +288,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -373,6 +374,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -391,6 +393,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -422,7 +425,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ diff --git a/examples/acp-agent/tests/snapshots/text-turn/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/text-turn/tool-schemas.expected.json index 52b3c1812e..de3254fd2e 100644 --- a/examples/acp-agent/tests/snapshots/text-turn/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/text-turn/tool-schemas.expected.json @@ -288,6 +288,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -373,6 +374,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -391,6 +393,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -422,7 +425,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ diff --git a/examples/acp-agent/tests/snapshots/workspace-context/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/workspace-context/tool-schemas.expected.json index 52b3c1812e..de3254fd2e 100644 --- a/examples/acp-agent/tests/snapshots/workspace-context/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/workspace-context/tool-schemas.expected.json @@ -288,6 +288,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -373,6 +374,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -391,6 +393,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -422,7 +425,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ diff --git a/packages/bash/tool-bash/src/index.ts b/packages/bash/tool-bash/src/index.ts index 0feec1729a..6098056fb9 100644 --- a/packages/bash/tool-bash/src/index.ts +++ b/packages/bash/tool-bash/src/index.ts @@ -206,7 +206,7 @@ export class BashEnvRegistry extends Service { } } -/** Parsed tool args; execute validates value constraints absent from SchemaSpec. */ +/** Parsed tool args; execute validates value constraints absent from ParameterSchemaSpec. */ interface BashToolArgs { command: string description: string diff --git a/packages/bash/tool-bash/tests/tools.spec.ts b/packages/bash/tool-bash/tests/tools.spec.ts index 04c18264b1..b2a78ff9fe 100644 --- a/packages/bash/tool-bash/tests/tools.spec.ts +++ b/packages/bash/tool-bash/tests/tools.spec.ts @@ -287,7 +287,7 @@ describe('bash tool', () => { }) // Type and required-key violations are rejected by the harness - // (defineTool validates against the SchemaSpec — the arg-validation Agent Note) before execute. + // (defineTool validates against the ParameterSchemaSpec — the arg-validation Agent Note) before execute. it.each([ [{}, /missing required property "command"/], [{ command: 42, description: 'd' }, /"command" must be a string/], @@ -303,7 +303,7 @@ describe('bash tool', () => { expect(text(result)).toMatch(pattern) }) - // Value constraints the SchemaSpec can't express stay in the tool body. + // Value constraints the ParameterSchemaSpec can't express stay in the tool body. it.each([ [{ command: ' ', description: 'd' }, /invalid command/], [{ command: 'x', description: ' ' }, /invalid description/], diff --git a/packages/cordis/tool-cordis/src/api-catalog.ts b/packages/cordis/tool-cordis/src/api-catalog.ts index 20ea51c087..23ffa88923 100644 --- a/packages/cordis/tool-cordis/src/api-catalog.ts +++ b/packages/cordis/tool-cordis/src/api-catalog.ts @@ -1336,6 +1336,18 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'InjectOptions', declaration: 'export interface InjectOptions extends SendOptions {\n meta?: JsonValue;\n}', }, + { + name: 'JsonSchemaNode', + declaration: 'export interface JsonSchemaNode {\n type?: JsonSchemaType;\n oneOf?: JsonSchemaNode[];\n properties?: Record<string, JsonSchemaNode>;\n required?: string[];\n additionalProperties?: boolean;\n items?: JsonSchemaNode;\n enum?: JsonSchemaScalar[];\n const?: JsonSchemaScalar;\n description?: string;\n title?: string;\n default?: JsonValue;\n examples?: JsonValue;\n}', + }, + { + name: 'JsonSchemaScalar', + declaration: 'export type JsonSchemaScalar = string | number | boolean | null;', + }, + { + name: 'JsonSchemaType', + declaration: 'export type JsonSchemaType = \'object\' | \'array\' | \'string\' | \'number\' | \'integer\' | \'boolean\' | \'null\';', + }, { name: 'JsonValue', declaration: 'export type JsonValue = null | boolean | number | string | JsonValue[] | {\n [key: string]: JsonValue;\n};', @@ -1368,6 +1380,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'MessageSourceMap', declaration: 'export interface MessageSourceMap {\n user: {\n kind: \'user\';\n };\n plugin: {\n kind: \'plugin\';\n plugin: string;\n };\n}', }, + { + name: 'ObjectJsonSchema', + declaration: 'export type ObjectJsonSchema = JsonSchemaNode & {\n type: \'object\';\n};', + }, { name: 'PresetOption', declaration: 'export interface PresetOption {\n value: string;\n name: string;\n description?: string;\n}', @@ -1544,22 +1560,6 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'StreamChunk', declaration: 'export type StreamChunk = {\n type: \'block-start\';\n index: number;\n blockType: ContentBlockType;\n} | {\n type: \'text-delta\';\n index: number;\n text: string;\n} | {\n type: \'reasoning-delta\';\n index: number;\n text: string;\n} | {\n type: \'tool-call-delta\';\n index: number;\n id: CallId;\n name?: string;\n argumentsDelta: string;\n} | {\n type: \'block-end\';\n index: number;\n block: ContentBlock;\n} | {\n type: \'usage\';\n usage: TokenUsage;\n} | {\n type: \'finish\';\n reason: FinishReason;\n replayState?: unknown;\n};', }, - { - name: 'StructuredOutputSchema', - declaration: 'export type StructuredOutputSchema = StructuredSchemaNode & {\n type: \'object\';\n};', - }, - { - name: 'StructuredScalar', - declaration: 'export type StructuredScalar = string | number | boolean | null;', - }, - { - name: 'StructuredSchemaNode', - declaration: 'export interface StructuredSchemaNode {\n type: StructuredSchemaType;\n properties?: Record<string, StructuredSchemaNode>;\n required?: string[];\n additionalProperties?: boolean;\n items?: StructuredSchemaNode;\n enum?: StructuredScalar[];\n const?: StructuredScalar;\n description?: string;\n title?: string;\n default?: unknown;\n examples?: unknown;\n}', - }, - { - name: 'StructuredSchemaType', - declaration: 'export type StructuredSchemaType = \'object\' | \'array\' | \'string\' | \'number\' | \'integer\' | \'boolean\' | \'null\';', - }, { name: 'SubagentCapabilities', declaration: 'export interface SubagentCapabilities {\n readonly outputSchema: boolean;\n readonly depthLimit: boolean;\n readonly toolFilter: boolean;\n readonly persona: boolean;\n}', @@ -1578,7 +1578,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'SubagentStartRequest', - declaration: 'export interface SubagentStartRequest {\n readonly prompt: ContentBlock[];\n readonly parent: Agent;\n readonly signal: AbortSignal;\n readonly agentOptions?: AgentOptions;\n readonly outputSchema?: StructuredOutputSchema;\n readonly maxDepth?: number;\n readonly toolFilter?: ToolRestriction;\n readonly persona?: string;\n}', + declaration: 'export interface SubagentStartRequest {\n readonly prompt: ContentBlock[];\n readonly parent: Agent;\n readonly signal: AbortSignal;\n readonly agentOptions?: AgentOptions;\n readonly outputSchema?: ObjectJsonSchema;\n readonly maxDepth?: number;\n readonly toolFilter?: ToolRestriction;\n readonly persona?: string;\n}', }, { name: 'SubagentStopReason', diff --git a/packages/cordis/tool-cordis/src/guard.ts b/packages/cordis/tool-cordis/src/guard.ts index 2198533376..c55fd34b78 100644 --- a/packages/cordis/tool-cordis/src/guard.ts +++ b/packages/cordis/tool-cordis/src/guard.ts @@ -1,5 +1,5 @@ /** - * The registration boundary between sandboxed mount code and the real runtime: SchemaSpec + * The registration boundary between sandboxed mount code and the real runtime: ParameterSchemaSpec * normalization + validation with teaching errors, the marker-guarded `harness.defineTool` / * `harness.registerTool` pair, the SANDBOX CONTEXT FAÇADE a mounted plugin's `apply` receives * in place of the real `ctx`, and the plugin-shape helpers the mount lifecycle narrows sandbox @@ -15,12 +15,13 @@ import { Context } from 'cordis' import type { Plugin } from 'cordis' import { scopeOf } from '@deepseek-ai/dsh-scope' -import { defineTool } from '@deepseek-ai/dsh-tools' +import { assertSupportedJsonSchema, defineTool } from '@deepseek-ai/dsh-tools' import type { ToolDefinition, ToolExecuteReturn } from '@deepseek-ai/dsh-tools' const DYNAMIC_TOOL = Symbol('tool-cordis.dynamic-tool') -const SCHEMA_TYPES = new Set<unknown>(['string', 'number', 'boolean', 'object', 'array']) -const VALID_TYPES = '\'string\' | \'number\' | \'boolean\' | \'object\' | \'array\'' +const SCHEMA_TYPES = new Set<unknown>(['string', 'number', 'integer', 'boolean', 'null', 'object', 'array', 'json']) +const VALID_TYPES = '\'string\' | \'number\' | \'integer\' | \'boolean\' | \'null\' | \'object\' | \'array\' | \'json\'' +const ANNOTATION_KEYS = ['description', 'title', 'default', 'examples'] as const type DynamicToolDefinition = ToolDefinition & { [DYNAMIC_TOOL]: true } type DynamicToolMarker = { [DYNAMIC_TOOL]?: unknown } @@ -29,70 +30,196 @@ function isPlainRecord(value: unknown): value is Record<string, unknown> { return Object.prototype.toString.call(value) === '[object Object]' } +/** Materialize realm-foreign lossless JSON without allowing JSON.stringify coercions. */ +function cloneJson(value: unknown, path: string, seen = new Set<object>()): unknown { + if (value === null || typeof value === 'string' || typeof value === 'boolean') return value + if (typeof value === 'number') { + if (Number.isFinite(value) && !Object.is(value, -0)) return value + throw new Error(`harness.defineTool ${path} must be lossless JSON data`) + } + if (typeof value !== 'object') throw new Error(`harness.defineTool ${path} must be lossless JSON data`) + if (seen.has(value)) throw new Error(`harness.defineTool ${path} must be lossless JSON data`) + seen.add(value) + try { + if (Array.isArray(value)) { + const output: unknown[] = [] + for (let index = 0; index < value.length; index++) { + if (!Object.hasOwn(value, index)) throw new Error(`harness.defineTool ${path} must be lossless JSON data`) + output.push(cloneJson(value[index], `${path}[${index}]`, seen)) + } + return output + } + if (!isPlainRecord(value)) throw new Error(`harness.defineTool ${path} must be lossless JSON data`) + const output: Record<string, unknown> = {} + for (const [key, entry] of Object.entries(value)) output[key] = cloneJson(entry, `${path}.${key}`, seen) + return output + } finally { + seen.delete(value) + } +} + +/** Copy and realm-materialize the shared annotation vocabulary. */ +function copyAnnotations(value: Record<string, unknown>, output: Record<string, unknown>, path: string): void { + if (Object.hasOwn(value, 'description')) output.description = value.description + if (Object.hasOwn(value, 'title')) output.title = value.title + if (Object.hasOwn(value, 'default')) output.default = cloneJson(value.default, `${path}.default`) + if (Object.hasOwn(value, 'examples')) output.examples = cloneJson(value.examples, `${path}.examples`) +} + +/** Reject sandbox schema keys that the unified DSL would otherwise ignore. */ +function assertSchemaKeys(value: Record<string, unknown>, path: string, allowed: readonly string[]): void { + for (const key of Object.keys(value)) { + if (!allowed.includes(key)) throw new Error(`harness.defineTool ${path}.${key} is not supported by the unified schema DSL`) + } +} + /** * Normalize a sandbox-provided `parameters` value into a fresh host-realm - * SchemaSpec. Accepts the DSL directly, or the JSON-Schema-style - * `{ type: 'object', properties, required: […] }` wrapper models write by - * prior — the wrapper unwraps and its `required` array becomes per-property - * flags (see the module doc). + * ParameterSchemaSpec. A raw JSON-Schema object wrapper retains its open root + * default, while the direct DSL is already an implicit open property map. */ -function normalizeSchemaSpec(value: unknown, path = 'parameters'): Record<string, unknown> { +function normalizeParameterSchemaSpec(value: unknown, path = 'parameters'): { + spec: Record<string, unknown> + rootAnnotations?: Record<string, unknown> +} { if (!isPlainRecord(value)) { - throw new Error(`harness.defineTool ${path} must be a SchemaSpec object`) + throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec object`) } - let entries = value - const requiredNames = new Set<unknown>() - if (value.type === 'object' && isPlainRecord(value.properties)) { - if (Array.isArray(value.required)) { - for (const name of value.required) requiredNames.add(name) + if (value.type === 'object') { + assertSchemaKeys(value, path, ['type', 'properties', 'required', 'additionalProperties', ...ANNOTATION_KEYS]) + if (!isPlainRecord(value.properties)) { + throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`) + } + if (Object.hasOwn(value, 'additionalProperties') && value.additionalProperties !== true) { + throw new Error(`harness.defineTool ${path}.additionalProperties must be true or omitted because the implicit parameter root is open`) + } + if (Object.hasOwn(value, 'required') && value.required === undefined) { + throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`) + } + const required = normalizeRequiredNames(value.required, value.properties, `${path}.required`) + const rootAnnotations: Record<string, unknown> = {} + copyAnnotations(value, rootAnnotations, path) + return { + spec: normalizePropertyMap(value.properties, path, required, true), + ...(Object.keys(rootAnnotations).length === 0 ? {} : { rootAnnotations }), } - entries = value.properties } + return { spec: normalizePropertyMap(value, path, new Set(), false) } +} + +/** Validate raw required names and return their lookup set. */ +function normalizeRequiredNames(value: unknown, properties: Record<string, unknown>, path: string): Set<string> { + if (value === undefined) return new Set() + if (!Array.isArray(value) || value.some(name => typeof name !== 'string')) { + throw new Error(`harness.defineTool ${path} must be an array of declared property names`) + } + const names = new Set(value as string[]) + for (const name of names) { + if (!Object.hasOwn(properties, name)) throw new Error(`harness.defineTool ${path} names undeclared property ${JSON.stringify(name)}`) + } + return names +} + +/** Normalize one implicit property map. */ +function normalizePropertyMap( + entries: Record<string, unknown>, + path: string, + requiredNames: ReadonlySet<string>, + raw: boolean, +): Record<string, unknown> { const spec: Record<string, unknown> = {} for (const [key, prop] of Object.entries(entries)) { - spec[key] = normalizeSchemaProp(prop, `${path}.${key}`, requiredNames.has(key)) + spec[key] = normalizeValueSchema(prop, `${path}.${key}`, requiredNames.has(key), raw, true) } return spec } -/** Normalize one property: `integer` → `number`, `required: false` → absent, nested wrappers unwrapped recursively. */ -function normalizeSchemaProp(value: unknown, path: string, forceRequired = false): Record<string, unknown> { +/** Normalize one property or nested value schema into the host realm. */ +function normalizeValueSchema( + value: unknown, + path: string, + forceRequired = false, + raw = false, + parameterProperty = false, +): Record<string, unknown> { if (!isPlainRecord(value)) { - throw new Error(`harness.defineTool ${path} must be a SchemaSpec property object`) + throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec property object`) } - const type = value.type === 'integer' ? 'number' : value.type - if (!SCHEMA_TYPES.has(type)) { + const requiredKey = parameterProperty && !raw ? ['required'] : [] + if (parameterProperty && raw && Object.hasOwn(value, 'required') && value.type !== 'object') { + throw new Error(`harness.defineTool ${path}.required belongs to the containing raw object schema`) + } + if (parameterProperty && !raw && Object.hasOwn(value, 'required') && value.required !== true) { + throw new Error(`harness.defineTool ${path}.required must be true when present`) + } + const prop: Record<string, unknown> = {} + if (forceRequired || value.required === true) prop.required = true + copyAnnotations(value, prop, path) + + if (Object.hasOwn(value, 'oneOf')) { + assertSchemaKeys(value, path, ['oneOf', ...requiredKey, ...ANNOTATION_KEYS]) + if (!Array.isArray(value.oneOf)) throw new Error(`harness.defineTool ${path}.oneOf must contain at least two schemas`) + prop.oneOf = value.oneOf.map((branch, index) => normalizeValueSchema(branch, `${path}.oneOf[${index}]`, false, raw)) + return prop + } + + if (raw && !Object.hasOwn(value, 'type')) { + assertSchemaKeys(value, path, ANNOTATION_KEYS) + prop.type = 'json' + return prop + } + if (!SCHEMA_TYPES.has(value.type) || raw && value.type === 'json') { throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES} (got ${JSON.stringify(value.type)})`) } - // On an object property a JSON-Schema-style `required` ARRAY names required - // children (handled by the nested unwrap below); everywhere else `required` - // must be a boolean, and `false` means optional. - const nestedRequiredArray = type === 'object' && Array.isArray(value.required) - if (value.required !== undefined && typeof value.required !== 'boolean' && !nestedRequiredArray) { - throw new Error(`harness.defineTool ${path}.required must be a boolean when present`) - } - const prop: Record<string, unknown> = { type } - if (forceRequired || value.required === true) prop.required = true - if (typeof value.description === 'string') prop.description = value.description - if (Array.isArray(value.enum)) prop.enum = [...value.enum as unknown[]] - if (value.default !== undefined) prop.default = value.default - if (value.properties !== undefined) { - if (type !== 'object') { - throw new Error(`harness.defineTool ${path}.properties is only valid for type "object"`) + const type = value.type + prop.type = type + + switch (type) { + case 'object': { + assertSchemaKeys(value, path, ['type', 'properties', 'additionalProperties', ...requiredKey, ...(raw ? ['required'] : []), ...ANNOTATION_KEYS]) + if (!raw && (!Object.hasOwn(value, 'additionalProperties') || typeof value.additionalProperties !== 'boolean')) { + throw new Error(`harness.defineTool ${path}.additionalProperties must be explicitly true or false`) + } + if (raw && Object.hasOwn(value, 'additionalProperties') && typeof value.additionalProperties !== 'boolean') { + throw new Error(`harness.defineTool ${path}.additionalProperties must be a boolean`) + } + if (raw && Object.hasOwn(value, 'required') && value.required === undefined) { + throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`) + } + prop.additionalProperties = raw ? value.additionalProperties ?? true : value.additionalProperties + if (Object.hasOwn(value, 'properties')) { + if (!isPlainRecord(value.properties)) throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`) + const nestedRequired = raw ? normalizeRequiredNames(value.required, value.properties, `${path}.required`) : new Set<string>() + prop.properties = normalizePropertyMap(value.properties, `${path}.properties`, nestedRequired, raw) + } else if (raw && value.required !== undefined) { + normalizeRequiredNames(value.required, {}, `${path}.required`) + } + return prop } - // Re-wrap so the nested unwrap applies a nested `required` array too. - prop.properties = normalizeSchemaSpec( - { type: 'object', properties: value.properties, required: value.required }, - `${path}.properties`, - ) + case 'array': + assertSchemaKeys(value, path, ['type', 'items', ...requiredKey, ...ANNOTATION_KEYS]) + if (Object.hasOwn(value, 'items')) prop.items = normalizeValueSchema(value.items, `${path}.items`, false, raw) + return prop + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': + assertSchemaKeys(value, path, ['type', 'enum', 'const', ...requiredKey, ...ANNOTATION_KEYS]) + if (Object.hasOwn(value, 'enum')) { + prop.enum = Array.isArray(value.enum) + ? value.enum.map((entry, index) => cloneJson(entry, `${path}.enum[${index}]`)) + : value.enum + } + if (Object.hasOwn(value, 'const')) prop.const = cloneJson(value.const, `${path}.const`) + return prop + case 'json': + assertSchemaKeys(value, path, ['type', ...requiredKey, ...ANNOTATION_KEYS]) + return prop + /* v8 ignore next 2 -- SCHEMA_TYPES narrows this closed switch before dispatch. */ + default: + throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES}`) } - if (value.items !== undefined) { - if (type !== 'array') { - throw new Error(`harness.defineTool ${path}.items is only valid for type "array"`) - } - prop.items = normalizeSchemaProp(value.items, `${path}.items`) - } - return prop } function markDynamicTool(tool: ToolDefinition): DynamicToolDefinition { @@ -160,19 +287,22 @@ function assertExecuteReturn(value: unknown): ToolExecuteReturn { /** * The `harness.defineTool` handed into the sandbox: the real DSL, with `parameters` normalized - * into a fresh host-realm SchemaSpec (JSON-Schema wrapper unwrapped, `integer` mapped, - * `required: false` dropped) and the tool's `execute` return normalized into the host realm + * into a fresh host-realm ParameterSchemaSpec (raw object wrappers unwrapped, + * required arrays mapped, and explicit DSL object openness enforced) and the tool's `execute` return normalized into the host realm * via a JSON round-trip. Non-JSON or wrong-shape output fails that call instead of poisoning * the session log. - * @param options - the standard `defineTool` options; `parameters` may be the SchemaSpec DSL or a JSON-Schema-style wrapper. + * @param options - the standard `defineTool` options; `parameters` may be the ParameterSchemaSpec DSL or a JSON-Schema-style wrapper. * @returns the marker-tagged definition `harness.registerTool` (and the guarded `ctx.tools.register`) accepts. */ export function sandboxDefineTool(options: Parameters<typeof defineTool>[0]): ToolDefinition { - const parameters = normalizeSchemaSpec((options as { parameters?: unknown }).parameters) - const tool = defineTool({ ...options, parameters } as Parameters<typeof defineTool>[0]) + const normalized = normalizeParameterSchemaSpec((options as { parameters?: unknown }).parameters) + const tool = defineTool({ ...options, parameters: normalized.spec } as Parameters<typeof defineTool>[0]) + const parameters = { ...tool.parameters, ...normalized.rootAnnotations } + assertSupportedJsonSchema(parameters) const execute = tool.execute.bind(tool) return markDynamicTool({ ...tool, + parameters, async execute(args, exec) { // JSON.stringify yields NO JSON for an undefined (or function/symbol) // return despite its string-typed signature — route that into diff --git a/packages/cordis/tool-cordis/src/index.ts b/packages/cordis/tool-cordis/src/index.ts index 4fc5bd4328..9ac29aeb07 100644 --- a/packages/cordis/tool-cordis/src/index.ts +++ b/packages/cordis/tool-cordis/src/index.ts @@ -121,9 +121,9 @@ export function apply(ctx: Context, config: Config): void { + '`harness.registerTool(ctx, harness.defineTool({ name, description, parameters: ' + '{ text: { type: \'string\', required: true } }, async execute(args) { … } }))` ' + 'to give yourself a new tool — it becomes callable on your NEXT step. ' - + 'Tool parameters: each key IS a property — { type: \'string\'|\'number\'|\'boolean\'|\'object\'|\'array\', ' - + 'required?: true, description?, enum?, items?, properties? }; a JSON-Schema-style ' - + '{ type: \'object\', properties, required: […] } wrapper and type \'integer\' are also accepted and normalized. A ' + + 'Tool parameters: each key IS a property — { type: \'string\'|\'number\'|\'integer\'|\'boolean\'|\'null\'|\'object\'|\'array\'|\'json\', ' + + 'required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and ' + + 'oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: \'object\', properties, required?: […] } wrapper is also accepted with open-by-default objects. A ' + 'tool\'s `execute` MUST return an ARRAY of content blocks, e.g. `return ' + '[{ type: \'text\', text: someString }]` — never a bare string. ' + 'Mounts can COMPOSE: one plugin may `ctx.provide(\'name\', value)` a service and ' diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 2ddee8dbca..42af6fc64e 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -156,11 +156,14 @@ describe('cordis_mount', () => { description: 'written in the JSON-Schema dialect', parameters: { type: 'object', + title: 'Raw parameters', + default: { text: 'default' }, + examples: [{ text: 'example' }], properties: { text: { type: 'string', description: 'the text' }, count: { type: 'integer', default: 1 }, mode: { type: 'string', enum: ['fast', 'slow'] }, - extra: { type: 'string', required: false }, + extra: { type: 'string' }, }, required: ['text'], }, @@ -173,14 +176,19 @@ describe('cordis_mount', () => { expect(result.isError).toBe(false) // The registered schema is canonical JSON Schema derived from the DSL: - // the required array survived, integer became number, extra is optional. + // the required array survived, integer stayed integer, extra is optional. const schema = ctx.tools.schemas().find(s => s.name === 'json_schema_tool')! const parameters = schema.parameters as { properties: Record<string, { type: string; enum?: string[]; default?: unknown }> required?: string[] } expect(parameters.required).toEqual(['text']) - expect(parameters.properties.count!.type).toBe('number') + expect(parameters).toMatchObject({ + title: 'Raw parameters', + default: { text: 'default' }, + examples: [{ text: 'example' }], + }) + expect(parameters.properties.count!.type).toBe('integer') expect(parameters.properties.count!.default).toBe(1) expect(parameters.properties.mode!.enum).toEqual(['fast', 'slow']) // Arg validation enforces the normalized spec: text required, extra not. @@ -202,7 +210,10 @@ describe('cordis_mount', () => { name: 'nested_json_schema_tool', description: 'nested dialect', parameters: { - cfg: { type: 'object', properties: { label: { type: 'string' } }, required: ['label'] }, + type: 'object', + properties: { + cfg: { type: 'object', properties: { label: { type: 'string' } }, required: ['label'] }, + }, }, async execute(args) { return [{ type: 'text', text: args.cfg.label }] }, })) @@ -217,14 +228,123 @@ describe('cordis_mount', () => { expect(text(await call(ctx, 'nested_json_schema_tool', { cfg: { label: 'hi' } }))).toBe('hi') }) + it('normalizes every unified DSL node and lossless annotation shape across the sandbox realm', async () => { + const ctx = await setup() + const result = await call(ctx, 'cordis_mount', { + code: ` + return { + name: 'unified-schema', + inject: ['tools'], + apply(ctx) { + harness.registerTool(ctx, harness.defineTool({ + name: 'unified_schema_tool', + description: 'all unified nodes', + parameters: { + any: { + type: 'json', + title: 'Any JSON', + default: { nested: [1, 'x', null] }, + examples: [{ ok: true }], + }, + choice: { + oneOf: [{ type: 'string', const: 'x' }, { type: 'null' }], + required: true, + }, + flags: { type: 'array' }, + closed: { type: 'object', additionalProperties: false }, + count: { type: 'number', enum: [1, 2], const: 1 }, + }, + async execute(args) { return [{ type: 'text', text: String(args.choice) }] }, + })) + }, + } + `, + }) + expect(result.isError).toBe(false) + const schema = ctx.tools.schemas().find(s => s.name === 'unified_schema_tool')! + expect(schema.parameters).toMatchObject({ + properties: { + any: { title: 'Any JSON', default: { nested: [1, 'x', null] }, examples: [{ ok: true }] }, + choice: { oneOf: [{ type: 'string', const: 'x' }, { type: 'null' }] }, + flags: { type: 'array' }, + closed: { type: 'object', additionalProperties: false }, + count: { type: 'number', enum: [1, 2], const: 1 }, + }, + required: ['choice'], + }) + }) + + it('normalizes unconstrained and closed nested nodes from a raw JSON Schema wrapper', async () => { + const ctx = await setup() + const result = await call(ctx, 'cordis_mount', { + code: ` + return { + name: 'raw-unified-schema', + inject: ['tools'], + apply(ctx) { + harness.registerTool(ctx, harness.defineTool({ + name: 'raw_unified_schema_tool', + description: 'raw unified nodes', + parameters: { + type: 'object', + additionalProperties: true, + properties: { + any: { description: 'unconstrained' }, + cfg: { + type: 'object', + additionalProperties: false, + properties: { label: { type: 'string' } }, + required: ['label'], + }, + choice: { oneOf: [{ type: 'boolean' }, { type: 'null' }] }, + }, + }, + async execute() { return [] }, + })) + }, + } + `, + }) + expect(result.isError).toBe(false) + expect(ctx.tools.schemas().find(s => s.name === 'raw_unified_schema_tool')!.parameters).toMatchObject({ + properties: { + any: {}, + cfg: { additionalProperties: false, required: ['label'] }, + choice: { oneOf: [{ type: 'boolean' }, { type: 'null' }] }, + }, + }) + }) + it.each([ - ['parameters: 42', 'must be a SchemaSpec object'], - ['parameters: { text: 42 }', 'parameters.text must be a SchemaSpec property object'], - ['parameters: { text: { type: \'str\' } }', 'parameters.text must declare a valid type: \'string\' | \'number\' | \'boolean\' | \'object\' | \'array\' (got "str")'], - ['parameters: { text: { type: \'string\', required: \'yes\' } }', 'parameters.text.required must be a boolean when present'], - ['parameters: { text: { type: \'string\', properties: {} } }', 'parameters.text.properties is only valid for type "object"'], - ['parameters: { text: { type: \'string\', items: { type: \'string\' } } }', 'parameters.text.items is only valid for type "array"'], - ])('rejects a malformed SchemaSpec (%s) with a teaching error', async (parameters, message) => { + ['parameters: 42', 'must be a ParameterSchemaSpec object'], + ['parameters: { text: 42 }', 'parameters.text must be a ParameterSchemaSpec property object'], + ['parameters: { text: { type: \'str\' } }', 'parameters.text must declare a valid type: \'string\' | \'number\' | \'integer\' | \'boolean\' | \'null\' | \'object\' | \'array\' | \'json\' (got "str")'], + ['parameters: { text: { type: \'string\', required: \'yes\' } }', 'parameters.text.required must be true when present'], + ['parameters: { text: { type: \'string\', properties: {} } }', 'parameters.text.properties is not supported by the unified schema DSL'], + ['parameters: { text: { type: \'string\', items: { type: \'string\' } } }', 'parameters.text.items is not supported by the unified schema DSL'], + ['parameters: { text: { type: \'object\', properties: {} } }', 'parameters.text.additionalProperties must be explicitly true or false'], + ['parameters: { text: { type: \'object\', additionalProperties: \'no\' } }', 'parameters.text.additionalProperties must be explicitly true or false'], + ['parameters: { type: \'object\' }', 'parameters.properties must be an object of schemas'], + ['parameters: { type: \'object\', properties: {}, additionalProperties: false }', 'parameters.additionalProperties must be true or omitted'], + ['parameters: { type: \'object\', properties: {}, required: \'text\' }', 'parameters.required must be an array of declared property names'], + ['parameters: { type: \'object\', properties: {}, required: undefined }', 'parameters.required must be an array of declared property names'], + ['parameters: { type: \'object\', properties: {}, required: [\'text\'] }', 'parameters.required names undeclared property "text"'], + ['parameters: { type: \'object\', properties: { text: { type: \'string\', required: true } } }', 'parameters.text.required belongs to the containing raw object schema'], + ['parameters: { type: \'object\', properties: { text: { oneOf: \'bad\' } } }', 'parameters.text.oneOf must contain at least two schemas'], + ['parameters: { type: \'object\', properties: { text: { type: \'json\' } } }', 'parameters.text must declare a valid type'], + ['parameters: { type: \'object\', properties: { cfg: { type: \'object\', additionalProperties: \'no\' } } }', 'parameters.cfg.additionalProperties must be a boolean'], + ['parameters: { type: \'object\', properties: { cfg: { type: \'object\', properties: 42 } } }', 'parameters.cfg.properties must be an object of schemas'], + ['parameters: { type: \'object\', properties: { cfg: { type: \'object\', required: [\'label\'] } } }', 'parameters.cfg.required names undeclared property "label"'], + ['parameters: { type: \'object\', properties: { cfg: { type: \'object\', required: undefined } } }', 'parameters.cfg.required must be an array of declared property names'], + ['parameters: { value: { oneOf: \'bad\' } }', 'parameters.value.oneOf must contain at least two schemas'], + ['parameters: { value: { type: \'string\', enum: \'bad\' } }', 'enum must be a non-empty array'], + ['parameters: { value: { type: \'json\', default: -0 } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: Infinity } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: () => 1 } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: (() => { const v = {}; v.self = v; return v })() } }', 'parameters.value.default.self must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: Array(2) } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: new Date(0) } }', 'parameters.value.default must be lossless JSON data'], + ])('rejects a malformed ParameterSchemaSpec (%s) with a teaching error', async (parameters, message) => { const ctx = await setup() const result = await call(ctx, 'cordis_mount', { code: ` @@ -246,7 +366,7 @@ describe('cordis_mount', () => { expect(text(result)).toContain(message) }) - it('accepts a nested object/array SchemaSpec (the DSL recursion)', async () => { + it('accepts a nested object/array ParameterSchemaSpec (the DSL recursion)', async () => { const ctx = await setup() const result = await call(ctx, 'cordis_mount', { code: ` @@ -258,7 +378,7 @@ describe('cordis_mount', () => { name: 'nested_schema_tool', description: 'nested', parameters: { - item: { type: 'object', required: true, properties: { label: { type: 'string', required: true } } }, + item: { type: 'object', additionalProperties: true, required: true, properties: { label: { type: 'string', required: true } } }, tags: { type: 'array', items: { type: 'string' } }, }, async execute(args) { return [{ type: 'text', text: args.item.label }] }, diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 2cb841d0e2..5ec2d4e7e4 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -80,19 +80,19 @@ ctx.tools.register(defineTool({ })) ``` -The helper converts the author-facing `SchemaSpec` (with `required: true` as a per-property boolean) to standard JSON Schema for the wire format and uses the same typed spec for execute/presentation validation. Raw JSON-Schema tool definitions (from MCP servers) are still accepted by the registry directly. +The unified schema DSL uses `ParameterSchemaSpec` for the implicit open parameter object and `ValueSchemaSpec` for any JSON-value root. It supports `string`, `number`, `integer`, `boolean`, `null`, `array`, `object`, author-only `json`, and exact-one `oneOf`; scalar `enum`/`const` values are type-correct. Every explicit DSL object declares `additionalProperties: true | false`, while the implicit parameter root and raw JSON Schema keep the standard open default. A `defineTool` definition validates model arguments before execution and turns missing required values, wrong primitives, invalid enum members, and nested violations into `ToolArgsError` (`INVALID_ARGS`) for the normal error-result path. Extra keys are allowed, defaults are not applied, and object or array fields without `properties` or `items` receive only a type check. Raw-registered tools own their validation. -See `defineTool`, `validateArgs`, `ToolArgsError`, `SchemaSpec`, `InferArgs`, and `schemaSpecToJsonSchema` in the public API for details. +See `defineTool`, `validateArgs`, `ToolArgsError`, `ValueSchemaSpec`, `ParameterSchemaSpec`, `InferValue`, `InferArgs`, `valueSchemaSpecToJsonSchema`, and `parameterSchemaSpecToJsonSchema` in the public API for details. Optional `timeoutMs` must be positive and finite; it is policy metadata, not model-visible schema. Optional `isConcurrencySafe(args)` receives typed, softly validated arguments. Exact `true` permits concurrent dispatch/body execution; invalid input and all other outcomes remain exclusive. Opted-in bodies do not mutate parent-owned state, and shared-state races must commute or fail closed. The [parallel tool-call Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) owns the full safety contract. -### Structured-output schema subset +### Enforced raw JSON Schema subset -`StructuredOutputSchema` is the object-rooted raw JSON Schema subset used by subagents and workflows for machine-readable results. It accepts one scalar `type`, object `properties`/`required`/boolean `additionalProperties`, array `items`, and scalar `enum`/`const`. The annotations `description`, `title`, `default`, and `examples` are ignored but must remain JSON data. Type arrays, undeclared required keys, and unsupported keywords fail through `OutputSchemaError` rather than being ignored; `validateStructuredValue()` returns path-qualified violations without throwing. +`JsonSchemaNode` is the raw counterpart shared by tool outputs, Code Mode generation, subagents, and workflows. It permits any JSON root, an annotation-only unconstrained JSON node, and exact-one `oneOf`; annotations must remain lossless JSON. `assertSupportedJsonSchema()` rejects unsupported constructs, while `validateJsonSchemaValue()` returns path-qualified violations. Subagents and workflows retain their caller-defined object-root requirement through `assertObjectJsonSchema()` and `ObjectJsonSchema`, not through a limitation in the shared vocabulary. ### Tool-owned UI presentation diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 18fa286a16..2c01639047 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -23,27 +23,42 @@ import { renderToolsSdk } from './ts-types.ts' export { defineTool, - schemaSpecToJsonSchema, + valueSchemaSpecToJsonSchema, + parameterSchemaSpecToJsonSchema, validateArgs, ToolArgsError, - type SchemaSpec, - type SchemaProp, - type SchemaType, + type ValueSchemaAnnotations, + type StringValueSchemaSpec, + type NumberValueSchemaSpec, + type IntegerValueSchemaSpec, + type BooleanValueSchemaSpec, + type NullValueSchemaSpec, + type ArrayValueSchemaSpec, + type ObjectValueSchemaSpec, + type JsonValueSchemaSpec, + type OneOfValueSchemaSpec, + type ValueSchemaSpec, + type ParameterPropertySpec, + type ParameterSchemaSpec, + type ParameterJsonSchema, + type InferValue, type InferArgs, type DefineToolOptions, - type JsonSchemaObject, } from './schema.ts' export { - assertSupportedOutputSchema, - validateStructuredValue, - OutputSchemaError, - type StructuredOutputSchema, - type StructuredSchemaNode, - type StructuredSchemaType, - type StructuredScalar, + assertSupportedJsonSchema, + assertObjectJsonSchema, + validateJsonSchemaValue, + JsonSchemaError, + type JsonSchemaNode, + type ObjectJsonSchema, + type JsonSchemaType, + type JsonSchemaScalar, } from './json-schema.ts' +export type { JsonValue } from '@deepseek-ai/dsh-session' + export { CodeRunFailedError, RUN_CODE_NAME } from './code-mode.ts' export { jsonSchemaToTs, renderToolsSdk } from './ts-types.ts' diff --git a/packages/core/tools/src/json-schema.ts b/packages/core/tools/src/json-schema.ts index e1a0dc43a6..82ee0c50ac 100644 --- a/packages/core/tools/src/json-schema.ts +++ b/packages/core/tools/src/json-schema.ts @@ -1,122 +1,124 @@ /** - * Structured-output JSON Schema subset for subagents and workflows. It supports - * one scalar `type`; object `properties`/`required`/boolean - * `additionalProperties`; array `items`; scalar `enum`/`const`; and JSON-valued - * annotations. Unsupported or misplaced keywords reject rather than being - * accepted without enforcement, and structured-output roots must be objects. + * Enforced JSON Schema subset shared by tool outputs, generated Code Mode + * types, subagents, and workflows. The subset accepts any JSON root, an + * annotation-only schema for unconstrained JSON, one scalar `type`, object + * `properties`/`required`/boolean `additionalProperties`, array `items`, + * type-correct scalar `enum`/`const`, and exact-one `oneOf`. + * + * Unsupported or misplaced keywords reject rather than being accepted without + * enforcement. Consumers that require an object root apply + * {@link assertObjectJsonSchema} at their own boundary. * @module dsh-tools/json-schema */ import { assertNever, HarnessError } from '@deepseek-ai/dsh-llm' +import { isJsonValue, type JsonValue } from '@deepseek-ai/dsh-session' -/** The scalar values `enum`/`const` may carry (finite numbers only). */ -export type StructuredScalar = string | number | boolean | null +/** Scalar JSON values supported by `enum` and `const`. */ +export type JsonSchemaScalar = string | number | boolean | null -/** The `type` keywords the subset accepts. */ -export type StructuredSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null' +/** Single-type keywords accepted by the enforced subset. */ +export type JsonSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null' + +/** Scalar-only schema types accepted by literal constraints. */ +type JsonSchemaScalarType = Exclude<JsonSchemaType, 'object' | 'array'> /** - * One node of the structured-output schema subset. Recursive via `properties` - * and `items`; see the module doc for the exact keyword semantics. + * One raw JSON Schema node in the enforced subset. The optional fields express + * the external wire shape; {@link assertSupportedJsonSchema} rejects invalid + * combinations before a caller treats the node as trusted. */ -export interface StructuredSchemaNode { - type: StructuredSchemaType +export interface JsonSchemaNode { + /** Omit with no constraints for any JSON value, or use `oneOf`. */ + type?: JsonSchemaType + /** Exactly one branch must validate; at least two branches are required. */ + oneOf?: JsonSchemaNode[] /** Nested property schemas (`type: 'object'` only). */ - properties?: Record<string, StructuredSchemaNode> + properties?: Record<string, JsonSchemaNode> /** Required property names; each must appear in `properties`. */ required?: string[] - /** `false` rejects undeclared keys; absent/`true` allows them (JSON Schema default). */ + /** `false` rejects undeclared keys; absent/`true` follows JSON Schema's open default. */ additionalProperties?: boolean - /** Item schema (`type: 'array'` only); absent ⇒ any JSON items. */ - items?: StructuredSchemaNode - /** Allowed values (scalar types only). */ - enum?: StructuredScalar[] - /** The single allowed value (scalar types only). */ - const?: StructuredScalar + /** Item schema (`type: 'array'` only); absent accepts any JSON item. */ + items?: JsonSchemaNode + /** Allowed values for a scalar node. */ + enum?: JsonSchemaScalar[] + /** The single allowed value for a scalar node. */ + const?: JsonSchemaScalar /** Annotation, ignored for validation. */ description?: string /** Annotation, ignored for validation. */ title?: string - /** Annotation, ignored for validation (must still be JSON data). */ - default?: unknown - /** Annotation, ignored for validation (must still be JSON data). */ - examples?: unknown + /** Annotation, ignored for validation but required to be lossless JSON. */ + default?: JsonValue + /** Annotation, ignored for validation but required to be lossless JSON. */ + examples?: JsonValue } -/** A structured-output schema: an OBJECT-rooted {@link StructuredSchemaNode}. */ -export type StructuredOutputSchema = StructuredSchemaNode & { type: 'object' } +/** A consumer-constrained object-rooted schema. */ +export type ObjectJsonSchema = JsonSchemaNode & { type: 'object' } /** - * Thrown by {@link assertSupportedOutputSchema} when a schema falls outside the - * supported subset. Extends {@link HarnessError} (`code: 'UNSUPPORTED_SCHEMA'`) - * so seam code and tool results can route on it; `violations` lists every - * offending path, not just the first. + * Thrown when a raw schema falls outside the enforced subset. `violations` + * lists every offending path instead of stopping at the first author error. */ -export class OutputSchemaError extends HarnessError { - /** The individual violation messages, in walk order. */ +export class JsonSchemaError extends HarnessError { + /** Individual schema violations in walk order. */ readonly violations: string[] constructor(violations: string[]) { - super(`unsupported output schema: ${violations.join('; ')}`, 'UNSUPPORTED_SCHEMA') - this.name = 'OutputSchemaError' + super(`unsupported JSON schema: ${violations.join('; ')}`, 'UNSUPPORTED_SCHEMA') + this.name = 'JsonSchemaError' this.violations = violations } } -/** The keywords the subset accepts, checked (`constraint`) or ignored (`annotation`). */ -const CONSTRAINT_KEYWORDS = new Set(['type', 'properties', 'required', 'additionalProperties', 'items', 'enum', 'const']) +const CONSTRAINT_KEYWORDS = new Set([ + 'type', + 'oneOf', + 'properties', + 'required', + 'additionalProperties', + 'items', + 'enum', + 'const', +]) const ANNOTATION_KEYWORDS = new Set(['description', 'title', 'default', 'examples']) - -const SCHEMA_TYPES: readonly StructuredSchemaType[] = ['object', 'array', 'string', 'number', 'integer', 'boolean', 'null'] +const SCHEMA_TYPES: readonly JsonSchemaType[] = ['object', 'array', 'string', 'number', 'integer', 'boolean', 'null'] /** - * Whether a value is a PLAIN JSON object — non-null, non-array, and with a - * prototype chain of at most one link (`null`-proto, or any realm's - * `Object.prototype`, whose own prototype is `null`). Realm-agnostic on - * purpose: a schema materialized in another realm carries THAT realm's - * `Object.prototype`, which an identity check would wrongly reject. Exotic - * hosts (`Date`, `Map`, class instances) have longer chains and are rejected — - * they would serialize lossily (`Date` → string, `Map` → `{}`) instead of - * failing loud. + * Test for a realm-agnostic plain JSON record without accepting arrays or + * exotic objects. + * @param value - candidate record from any JavaScript realm. + * @returns Whether the value has a plain-object prototype chain. */ -function isObjectLike(value: unknown): value is Record<string, unknown> { +export function isPlainJsonRecord(value: unknown): value is Record<string, unknown> { if (typeof value !== 'object' || value === null || Array.isArray(value)) return false const proto: unknown = Object.getPrototypeOf(value) return proto === null || Object.getPrototypeOf(proto) === null } -/** Whether a value is a supported scalar (`enum`/`const` member): string, finite number, boolean, or null. */ -function isStructuredScalar(value: unknown): value is StructuredScalar { - return value === null || typeof value === 'string' || typeof value === 'boolean' - || (typeof value === 'number' && Number.isFinite(value)) +/** Lossless finite JSON number, excluding negative zero. */ +function isJsonNumber(value: unknown): value is number { + return typeof value === 'number' && Number.isFinite(value) && !Object.is(value, -0) } -/** - * Whether a value is JSON data (annotation payloads only): scalars, arrays, and - * object-likes of such values. Realm-agnostic on purpose (no prototype check) — - * the schema may have been materialized from another realm; structural JSON-ness - * is what the wire needs. Cycles are rejected via `seen`. - */ -function isJsonData(value: unknown, seen: Set<object>): boolean { - if (isStructuredScalar(value)) return true - // The scalar check above already returned for null, so `object` here is a real object. - if (typeof value !== 'object') return false - if (seen.has(value)) return false - seen.add(value) - try { - if (Array.isArray(value)) return value.every(entry => isJsonData(entry, seen)) - // A non-plain object (Date, Map, class instance) is NOT JSON data even when - // it has no enumerable values — it would serialize lossily, not loudly. - if (!isObjectLike(value)) return false - return Object.values(value).every(entry => isJsonData(entry, seen)) - } finally { - seen.delete(value) +/** Whether a scalar is valid for one declared schema type. */ +function scalarMatches(type: JsonSchemaScalarType, value: unknown): value is JsonSchemaScalar { + switch (type) { + case 'string': return typeof value === 'string' + case 'number': return isJsonNumber(value) + case 'integer': return isJsonNumber(value) && Number.isInteger(value) + case 'boolean': return typeof value === 'boolean' + case 'null': return value === null + /* v8 ignore next -- JsonSchemaScalarType is closed; this retains compile-time exhaustiveness. */ + default: return assertNever(type, 'JsonSchemaType') } } -/** Collect subset violations for one schema node (recursive walk). */ +/** Collect every violation for one raw schema node. */ function checkSchemaNode(node: unknown, path: string, violations: string[], seen: Set<object>): void { - if (!isObjectLike(node)) { + if (!isPlainJsonRecord(node)) { violations.push(`${path} must be a schema object`) return } @@ -125,199 +127,258 @@ function checkSchemaNode(node: unknown, path: string, violations: string[], seen return } seen.add(node) - - for (const key of Object.keys(node)) { - if (CONSTRAINT_KEYWORDS.has(key)) continue - if (ANNOTATION_KEYWORDS.has(key)) { - if (!isJsonData(node[key], new Set())) violations.push(`${path}.${key} annotation must be JSON data`) - continue + try { + for (const key of Object.keys(node)) { + if (CONSTRAINT_KEYWORDS.has(key)) continue + if (ANNOTATION_KEYWORDS.has(key)) { + try { + if (!isJsonValue(node[key])) violations.push(`${path}.${key} annotation must be lossless JSON data`) + } catch { + violations.push(`${path}.${key} annotation must be lossless JSON data`) + } + continue + } + violations.push(`${path}.${key} is not a supported keyword (subset: type/oneOf/properties/required/additionalProperties/items/enum/const + annotations)`) + } + if (node.description !== undefined && typeof node.description !== 'string') { + violations.push(`${path}.description must be a string`) + } + if (node.title !== undefined && typeof node.title !== 'string') { + violations.push(`${path}.title must be a string`) } - violations.push(`${path}.${key} is not a supported keyword (subset: type/properties/required/additionalProperties/items/enum/const + annotations)`) - } - if (typeof node.description !== 'undefined' && typeof node.description !== 'string') { - violations.push(`${path}.description must be a string`) - } - if (typeof node.title !== 'undefined' && typeof node.title !== 'string') { - violations.push(`${path}.title must be a string`) - } - const type = node.type - if (typeof type !== 'string' || !(SCHEMA_TYPES as readonly unknown[]).includes(type)) { - violations.push(Array.isArray(type) - ? `${path}.type must be a single type string (type arrays are not supported)` - : `${path}.type must be one of ${SCHEMA_TYPES.join('/')}`) + const hasType = Object.hasOwn(node, 'type') + const hasOneOf = Object.hasOwn(node, 'oneOf') + if (hasType && hasOneOf) { + violations.push(`${path} cannot declare both type and oneOf`) + return + } + if (!hasType && !hasOneOf) { + for (const key of ['properties', 'required', 'additionalProperties', 'items', 'enum', 'const']) { + if (Object.hasOwn(node, key)) violations.push(`${path}.${key} requires type or oneOf`) + } + return + } + + if (hasOneOf) { + const oneOf = node.oneOf + if (!Array.isArray(oneOf) || oneOf.length < 2) { + violations.push(`${path}.oneOf must be an array of at least two schemas`) + } else { + for (let index = 0; index < oneOf.length; index++) { + checkSchemaNode(oneOf[index], `${path}.oneOf[${index}]`, violations, seen) + } + } + for (const key of ['properties', 'required', 'additionalProperties', 'items', 'enum', 'const']) { + if (Object.hasOwn(node, key)) violations.push(`${path}.${key} is not supported beside oneOf`) + } + return + } + + const type = node.type + if (typeof type !== 'string' || !(SCHEMA_TYPES as readonly unknown[]).includes(type)) { + violations.push(Array.isArray(type) + ? `${path}.type must be a single type string (type arrays are not supported)` + : `${path}.type must be one of ${SCHEMA_TYPES.join('/')}`) + return + } + const schemaType = type as JsonSchemaType + const allowedFor: Record<string, JsonSchemaType[]> = { + properties: ['object'], + required: ['object'], + additionalProperties: ['object'], + items: ['array'], + enum: ['string', 'number', 'integer', 'boolean', 'null'], + const: ['string', 'number', 'integer', 'boolean', 'null'], + } + for (const [key, types] of Object.entries(allowedFor)) { + if (Object.hasOwn(node, key) && !types.includes(schemaType)) { + violations.push(`${path}.${key} is not supported on type "${schemaType}"`) + } + } + + switch (schemaType) { + case 'object': { + const properties = node.properties + if (Object.hasOwn(node, 'properties')) { + if (!isPlainJsonRecord(properties)) { + violations.push(`${path}.properties must be an object of schemas`) + } else { + for (const [key, child] of Object.entries(properties)) { + checkSchemaNode(child, `${path}.properties.${key}`, violations, seen) + } + } + } + const required = node.required + if (Object.hasOwn(node, 'required')) { + if (!Array.isArray(required) || required.some(entry => typeof entry !== 'string')) { + violations.push(`${path}.required must be an array of strings`) + } else { + const declared = isPlainJsonRecord(properties) ? properties : {} + for (const key of required as string[]) { + if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names "${key}" which is not in properties`) + } + } + } + if (Object.hasOwn(node, 'additionalProperties') && typeof node.additionalProperties !== 'boolean') { + violations.push(`${path}.additionalProperties must be a boolean`) + } + break + } + case 'array': { + if (Object.hasOwn(node, 'items')) checkSchemaNode(node.items, `${path}.items`, violations, seen) + break + } + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': { + const allowed = node.enum + if (Object.hasOwn(node, 'enum')) { + if (!Array.isArray(allowed) || allowed.length === 0 || !allowed.every(entry => scalarMatches(schemaType, entry))) { + violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`) + } + } + if (Object.hasOwn(node, 'const') && !scalarMatches(schemaType, node.const)) { + violations.push(`${path}.const must be a ${schemaType} value`) + } + break + } + /* v8 ignore next -- schemaType was narrowed from the closed SCHEMA_TYPES table above. */ + default: assertNever(schemaType, 'JsonSchemaType') + } + } finally { seen.delete(node) - return } - const schemaType = type as StructuredSchemaType - - // Keywords that only make sense on one type are rejected elsewhere — an - // `items` on an object (or `properties` on a string) is a schema-author bug - // the subset surfaces rather than ignores. - const allowedFor: Record<string, StructuredSchemaType[]> = { - properties: ['object'], - required: ['object'], - additionalProperties: ['object'], - items: ['array'], - enum: ['string', 'number', 'integer', 'boolean', 'null'], - const: ['string', 'number', 'integer', 'boolean', 'null'], - } - for (const [key, types] of Object.entries(allowedFor)) { - if (key in node && !types.includes(schemaType)) { - violations.push(`${path}.${key} is not supported on type "${schemaType}"`) - } - } - - switch (schemaType) { - case 'object': { - const properties = node.properties - if (properties !== undefined) { - if (!isObjectLike(properties)) { - violations.push(`${path}.properties must be an object of schemas`) - } else { - for (const [key, child] of Object.entries(properties)) { - checkSchemaNode(child, `${path}.properties.${key}`, violations, seen) - } - } - } - const required = node.required - if (required !== undefined) { - if (!Array.isArray(required) || required.some(entry => typeof entry !== 'string')) { - violations.push(`${path}.required must be an array of strings`) - } else { - const declared = isObjectLike(properties) ? properties : {} - // The guard above proved every entry is a string. - for (const key of required as string[]) { - // Own-property check: `in` would let inherited names (`toString`) - // satisfy the declared-in-properties contract via the prototype. - if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names "${key}" which is not in properties`) - } - } - } - if (node.additionalProperties !== undefined && typeof node.additionalProperties !== 'boolean') { - violations.push(`${path}.additionalProperties must be a boolean`) - } - break - } - case 'array': { - if (node.items !== undefined) checkSchemaNode(node.items, `${path}.items`, violations, seen) - break - } - case 'string': - case 'number': - case 'integer': - case 'boolean': - case 'null': { - const allowed = node.enum - if (allowed !== undefined) { - if (!Array.isArray(allowed) || allowed.length === 0 || !allowed.every(entry => isStructuredScalar(entry))) { - violations.push(`${path}.enum must be a non-empty array of scalars`) - } - } - if ('const' in node && !isStructuredScalar(node.const)) { - violations.push(`${path}.const must be a scalar`) - } - break - } - /* v8 ignore start -- defensive: schemaType was membership-checked against SCHEMA_TYPES above, so no runtime value reaches here */ - default: - assertNever(schemaType, 'assertSupportedOutputSchema') - /* v8 ignore stop */ - } - - seen.delete(node) } /** - * Assert `schema` is a supported {@link StructuredOutputSchema} — object-rooted - * and entirely within the enforced subset. Throws {@link OutputSchemaError} - * (`UNSUPPORTED_SCHEMA`) listing EVERY violation; returns (and narrows) on - * success. Call this at the seam boundary, before any child is created. - * @param schema - the caller-supplied schema (unknown until asserted). - * @returns nothing — the assertion signature narrows `schema` to - * {@link StructuredOutputSchema} in the caller's scope on normal return. + * Assert that an arbitrary raw schema uses only the enforced subset. + * Annotation-only schemas are accepted as the standard unconstrained-JSON + * form; callers that require an object root use {@link assertObjectJsonSchema}. + * @param schema - untrusted raw JSON Schema. + * @returns Assertion that the schema belongs to the supported subset. */ -export function assertSupportedOutputSchema(schema: unknown): asserts schema is StructuredOutputSchema { +export function assertSupportedJsonSchema(schema: unknown): asserts schema is JsonSchemaNode { const violations: string[] = [] checkSchemaNode(schema, 'schema', violations, new Set()) - if (violations.length === 0 && (schema as StructuredSchemaNode).type !== 'object') { - violations.push('schema.type must be "object" (structured output is object-rooted)') - } - if (violations.length > 0) throw new OutputSchemaError(violations) + if (violations.length > 0) throw new JsonSchemaError(violations) } -/** Collect violations for one value against an (already asserted) schema node. */ -function checkValue(node: StructuredSchemaNode, value: unknown, path: string): string[] { +/** + * Assert the enforced subset plus the object-root constraint retained by + * subagent and workflow structured outputs. + * @param schema - untrusted caller-supplied schema. + * @returns Assertion that the schema belongs to the supported subset and has an object root. + */ +export function assertObjectJsonSchema(schema: unknown): asserts schema is ObjectJsonSchema { + const violations: string[] = [] + checkSchemaNode(schema, 'schema', violations, new Set()) + if (violations.length === 0 && (schema as JsonSchemaNode).type !== 'object') { + violations.push('schema.type must be "object" (structured output is object-rooted)') + } + if (violations.length > 0) throw new JsonSchemaError(violations) +} + +/** Safely test the lossless JSON boundary when a getter may throw. */ +function safelyIsJsonValue(value: unknown): boolean { + try { + return isJsonValue(value) + } catch { + return false + } +} + +/** Root-aware diagnostic path for the parameter validator's empty sentinel. */ +function diagnosticPath(path: string): string { + return path === '' ? 'arguments' : path +} + +/** Append one object property without a leading dot at an implicit root. */ +function propertyPath(path: string, key: string): string { + return path === '' ? key : `${path}.${key}` +} + +/** Collect value violations for one trusted schema node. */ +function checkValue(node: JsonSchemaNode, value: unknown, path: string): string[] { + if (node.oneOf !== undefined) { + const matches = node.oneOf.filter(branch => checkValue(branch, value, path).length === 0).length + return matches === 1 ? [] : [`"${diagnosticPath(path)}" must match exactly one oneOf branch (matched ${matches})`] + } + if (node.type === undefined) { + return safelyIsJsonValue(value) ? [] : [`"${diagnosticPath(path)}" must be a lossless JSON value`] + } + switch (node.type) { case 'object': { - if (!isObjectLike(value)) return [`"${path}" must be an object`] + if (!isPlainJsonRecord(value)) return [`"${diagnosticPath(path)}" must be an object`] const violations: string[] = [] const properties = node.properties ?? {} - // Own-property discipline throughout: JSON carries own enumerable - // properties only, so an inherited `toString` must not satisfy - // `required`, dodge `additionalProperties: false`, or be validated as if - // the value carried it. for (const key of node.required ?? []) { - if (!Object.hasOwn(value, key) || value[key] === undefined) violations.push(`missing required property "${path}.${key}"`) + if (!Object.hasOwn(value, key) || value[key] === undefined) violations.push(`missing required property "${propertyPath(path, key)}"`) } for (const [key, child] of Object.entries(properties)) { if (!Object.hasOwn(value, key) || value[key] === undefined) continue - violations.push(...checkValue(child, value[key], `${path}.${key}`)) + violations.push(...checkValue(child, value[key], propertyPath(path, key))) } if (node.additionalProperties === false) { for (const key of Object.keys(value)) { - if (!Object.hasOwn(properties, key)) violations.push(`"${path}.${key}" is not a declared property (additionalProperties: false)`) + if (!Object.hasOwn(properties, key)) violations.push(`"${propertyPath(path, key)}" is not a declared property (additionalProperties: false)`) } } - return violations + if (violations.length > 0) return violations + return safelyIsJsonValue(value) ? [] : [`"${diagnosticPath(path)}" must be a lossless JSON object`] } case 'array': { - if (!Array.isArray(value)) return [`"${path}" must be an array`] - if (!node.items) return [] + if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) return [`"${diagnosticPath(path)}" must be an array`] const items = node.items - return value.flatMap((entry, index) => checkValue(items, entry, `${path}[${index}]`)) + const violations = items === undefined + ? [] + : value.flatMap((entry, index) => checkValue(items, entry, `${path}[${index}]`)) + if (violations.length > 0) return violations + return safelyIsJsonValue(value) ? [] : [`"${diagnosticPath(path)}" must be a dense lossless JSON array`] } case 'string': { - if (typeof value !== 'string') return [`"${path}" must be a string`] + if (typeof value !== 'string') return [`"${diagnosticPath(path)}" must be a string`] break } case 'number': { - if (typeof value !== 'number' || !Number.isFinite(value)) return [`"${path}" must be a finite number`] + if (typeof value !== 'number') return [`"${diagnosticPath(path)}" must be a number`] + if (!isJsonNumber(value)) return [`"${diagnosticPath(path)}" must be a finite JSON number`] break } case 'integer': { - if (typeof value !== 'number' || !Number.isInteger(value)) return [`"${path}" must be an integer`] + if (!isJsonNumber(value) || !Number.isInteger(value)) return [`"${diagnosticPath(path)}" must be an integer`] break } case 'boolean': { - if (typeof value !== 'boolean') return [`"${path}" must be a boolean`] + if (typeof value !== 'boolean') return [`"${diagnosticPath(path)}" must be a boolean`] break } case 'null': { - if (value !== null) return [`"${path}" must be null`] + if (value !== null) return [`"${diagnosticPath(path)}" must be null`] break } - default: - return assertNever(node.type, 'validateStructuredValue') + default: return assertNever(node.type, 'JsonSchemaType') } - // Scalar constraint checks, shared by every scalar branch above. - if (node.enum && !node.enum.includes(value)) { - return [`"${path}" must be one of ${JSON.stringify(node.enum)}`] + if (node.enum !== undefined && !node.enum.includes(value)) { + return [`"${diagnosticPath(path)}" must be one of ${JSON.stringify(node.enum)}`] } - if ('const' in node && value !== node.const) { - return [`"${path}" must be ${JSON.stringify(node.const)}`] + if (Object.hasOwn(node, 'const') && value !== node.const) { + return [`"${diagnosticPath(path)}" must be ${JSON.stringify(node.const)}`] } return [] } /** - * Validate a value against an (already {@link assertSupportedOutputSchema}- - * asserted) schema. Returns human-readable, path-qualified violation messages - * — empty means valid. Total: never throws, however malformed the value. - * @param schema - the asserted schema to check against. - * @param value - the candidate value (e.g. parsed tool-call arguments). - * @returns every violation found, in walk order (empty = valid). + * Validate a candidate value against an asserted raw schema. The function is + * total for arbitrary values and returns path-qualified violations. + * @param schema - a schema accepted by {@link assertSupportedJsonSchema}. + * @param value - the candidate JSON value. + * @param path - root label used in diagnostics. + * @returns All violations in walk order; empty means valid. */ -export function validateStructuredValue(schema: StructuredOutputSchema, value: unknown): string[] { - return checkValue(schema, value, 'value') +export function validateJsonSchemaValue(schema: JsonSchemaNode, value: unknown, path = 'value'): string[] { + return checkValue(schema, value, path) } diff --git a/packages/core/tools/src/schema.ts b/packages/core/tools/src/schema.ts index f2b62669b1..98be959e4e 100644 --- a/packages/core/tools/src/schema.ts +++ b/packages/core/tools/src/schema.ts @@ -1,173 +1,314 @@ -/** Typed tool-parameter DSL with argument inference and JSON Schema output. @module dsh-tools/schema */ +/** Unified JSON-value schema DSL, inference, compilation, and typed tool helper. @module dsh-tools/schema */ -import { assertNever, HarnessError } from '@deepseek-ai/dsh-llm' +import { HarnessError } from '@deepseek-ai/dsh-llm' +import type { JsonValue } from '@deepseek-ai/dsh-session' import type { ToolDefinition, ToolExecuteReturn, ToolRunContext, ToolResult } from './index.ts' +import { assertSupportedJsonSchema, isPlainJsonRecord, JsonSchemaError, validateJsonSchemaValue } from './json-schema.ts' +import type { JsonSchemaNode, JsonSchemaScalar, ObjectJsonSchema } from './json-schema.ts' import type { ToolCallView, ToolResultView } from './presentation.ts' -// --------------------------------------------------------------------------- -// SchemaSpec — the author-facing per-property type -// --------------------------------------------------------------------------- - -/** Valid JSON Schema primitive types for tool parameters. */ -export type SchemaType = 'string' | 'number' | 'boolean' | 'object' | 'array' - -/** One schema-spec property entry. */ -export interface SchemaProp { - type: SchemaType - /** Per-property required flag (NOT the JSON Schema top-level required array). */ - required?: true - /** Human-readable description, surfaced in the JSON Schema as well. */ +/** Annotation keywords shared by every author-facing schema node. */ +export interface ValueSchemaAnnotations { + /** Human-readable description projected into JSON Schema and generated types. */ description?: string - /** Enum of allowed values (strings only). */ - enum?: string[] - /** - * Model-visible JSON Schema default annotation. Validation does not apply it; - * dynamic tool mounts may supply it even though first-party definitions do not. - */ - default?: unknown - /** Nested properties for type: 'object'. */ - properties?: SchemaSpec - /** Items schema for type: 'array'. */ - items?: SchemaProp + /** Human-readable title projected into JSON Schema. */ + title?: string + /** Non-validating default annotation; it must be lossless JSON data. */ + default?: JsonValue + /** Non-validating examples annotation; it must be lossless JSON data. */ + examples?: JsonValue +} + +/** String value schema with type-correct literal constraints. */ +export interface StringValueSchemaSpec extends ValueSchemaAnnotations { + type: 'string' + enum?: readonly string[] + const?: string +} + +/** Finite JSON-number schema with type-correct literal constraints. */ +export interface NumberValueSchemaSpec extends ValueSchemaAnnotations { + type: 'number' + enum?: readonly number[] + const?: number +} + +/** Integer schema with type-correct literal constraints. */ +export interface IntegerValueSchemaSpec extends ValueSchemaAnnotations { + type: 'integer' + enum?: readonly number[] + const?: number +} + +/** Boolean value schema with type-correct literal constraints. */ +export interface BooleanValueSchemaSpec extends ValueSchemaAnnotations { + type: 'boolean' + enum?: readonly boolean[] + const?: boolean +} + +/** Null value schema with type-correct literal constraints. */ +export interface NullValueSchemaSpec extends ValueSchemaAnnotations { + type: 'null' + enum?: readonly null[] + const?: null +} + +/** Array value schema; omitted `items` accepts any lossless JSON item. */ +export interface ArrayValueSchemaSpec extends ValueSchemaAnnotations { + type: 'array' + items?: ValueSchemaSpec } /** - * The author-facing parameter schema: a shallow map of property name to - * {@link SchemaProp}. Required-ness is a per-property boolean (`required: - * true`), not a separate array. + * Explicit object value schema. Openness is mandatory so a nested or output + * object never acquires an accidental JSON Schema default. */ -export type SchemaSpec = Record<string, SchemaProp> +export interface ObjectValueSchemaSpec extends ValueSchemaAnnotations { + type: 'object' + properties?: ParameterSchemaSpec + additionalProperties: boolean +} -// --------------------------------------------------------------------------- -// InferArgs — type-level mapping from SchemaSpec to TS argument type -// --------------------------------------------------------------------------- +/** Author-only unconstrained lossless JSON node. */ +export interface JsonValueSchemaSpec extends ValueSchemaAnnotations { + type: 'json' +} -/** Map a {@link SchemaType} to its TS primitive type. */ -type TypeOf<T extends SchemaType> = - T extends 'string' ? string : - T extends 'number' ? number : - T extends 'boolean' ? boolean : - T extends 'object' ? Record<string, unknown> : - T extends 'array' ? unknown[] : - never +/** Exact-one union schema; at least two branches are required. */ +export interface OneOfValueSchemaSpec extends ValueSchemaAnnotations { + oneOf: readonly [ValueSchemaSpec, ValueSchemaSpec, ...ValueSchemaSpec[]] +} + +/** One author-facing schema for any lossless JSON value root. */ +export type ValueSchemaSpec = + | StringValueSchemaSpec + | NumberValueSchemaSpec + | IntegerValueSchemaSpec + | BooleanValueSchemaSpec + | NullValueSchemaSpec + | ArrayValueSchemaSpec + | ObjectValueSchemaSpec + | JsonValueSchemaSpec + | OneOfValueSchemaSpec + +/** One implicit parameter-root property, optionally required. */ +export type ParameterPropertySpec = ValueSchemaSpec & { required?: true } + +/** + * Tool parameter schema. The map itself is an implicit open object root; + * requiredness remains a per-property `required: true` annotation. + */ +export type ParameterSchemaSpec = Record<string, ParameterPropertySpec> + +/** Raw JSON Schema projection of the implicit parameter object. */ +export interface ParameterJsonSchema extends ObjectJsonSchema { + properties: Record<string, JsonSchemaNode> +} /** Flatten an intersection into one object type for readable hovers. */ type Simplify<T> = { [K in keyof T]: T[K] } & {} -/** Keys of `S` whose prop is marked `required: true`. */ -type RequiredKeys<S extends SchemaSpec> = - { [K in keyof S]: S[K] extends { required: true } ? K : never }[keyof S] +/** Keys of a property map marked `required: true`. */ +type RequiredKeys<S extends ParameterSchemaSpec> = { + [K in keyof S]: S[K] extends { required: true } ? K : never +}[keyof S] -/** - * The VALUE type of one {@link SchemaProp} — optionality is handled at the - * key level by {@link InferArgs}, never here. - * - `properties` on 'object' → recurse into the nested SchemaSpec - * - `items` on 'array' → recurse into the item prop (arrays of objects work) - * - otherwise → the primitive for `type` - */ -type InferPropValue<P extends SchemaProp> = - P extends { type: 'object'; properties: infer Sub extends SchemaSpec } ? InferArgs<Sub> : - P extends { type: 'array'; items: infer Item extends SchemaProp } ? InferPropValue<Item>[] : - TypeOf<P['type']> +/** Infer the declared value of one parameter property without key optionality. */ +type InferProperty<P extends ParameterPropertySpec> = P extends ValueSchemaSpec ? InferValue<P> : never -/** - * Infer the TS argument type for a complete {@link SchemaSpec}. - * - * Properties marked `required: true` are required keys; all others are - * genuinely optional keys (`?`), so callers may omit them entirely. - * - * Example: - * ```ts - * type Args = InferArgs<{ path: { type: 'string'; required: true }; limit: { type: 'number' } }> - * // → { path: string; limit?: number } - * ``` - */ -export type InferArgs<S extends SchemaSpec> = Simplify< - & { [K in RequiredKeys<S>]: InferPropValue<S[K]> } - & { [K in Exclude<keyof S, RequiredKeys<S>>]?: InferPropValue<S[K]> } +/** Infer an implicit property map into required and optional object keys. */ +type InferProperties<S extends ParameterSchemaSpec> = Simplify< + & { [K in RequiredKeys<S>]: InferProperty<S[K]> } + & { [K in Exclude<keyof S, RequiredKeys<S>>]?: InferProperty<S[K]> } > -// --------------------------------------------------------------------------- -// Runtime conversion: SchemaSpec → JSON Schema -// --------------------------------------------------------------------------- +/** Infer an explicit object node, including its declared openness. */ +type InferObject<S extends ObjectValueSchemaSpec> = + S extends { properties: infer P extends ParameterSchemaSpec } + ? S['additionalProperties'] extends true + ? InferProperties<P> & Record<string, JsonValue> + : InferProperties<P> + : S['additionalProperties'] extends true + ? Record<string, JsonValue> + : Record<string, never> + +/** Infer a scalar node's literal constraint before its broad primitive type. */ +type InferScalar<S, Fallback> = + S extends { const: infer C } ? C : + S extends { enum: readonly (infer E)[] } ? E : + Fallback /** - * Convert a single {@link SchemaProp} to its JSON Schema `properties` entry. - * The per-property `required` flag is collected; the caller builds the - * top-level `required` array. + * Infer the TypeScript value accepted by an author-facing value schema. + * Output schemas may therefore infer object, array, scalar, or null roots. */ -function propToJsonSchema(prop: SchemaProp): { schema: Record<string, unknown>; required: boolean } { - const result: Record<string, unknown> = { type: prop.type } - if (prop.description) result.description = prop.description - if (prop.enum) result.enum = prop.enum - if (prop.default !== undefined) result.default = prop.default +export type InferValue<S extends ValueSchemaSpec> = + S extends StringValueSchemaSpec ? InferScalar<S, string> : + S extends NumberValueSchemaSpec | IntegerValueSchemaSpec ? InferScalar<S, number> : + S extends BooleanValueSchemaSpec ? InferScalar<S, boolean> : + S extends NullValueSchemaSpec ? null : + S extends ArrayValueSchemaSpec + ? S extends { items: infer I extends ValueSchemaSpec } ? InferValue<I>[] : JsonValue[] + : S extends ObjectValueSchemaSpec ? InferObject<S> : + S extends JsonValueSchemaSpec ? JsonValue : + S extends OneOfValueSchemaSpec ? InferValue<S['oneOf'][number]> : + never - const required = prop.required === true +/** Infer the TypeScript argument object for an implicit parameter schema. */ +export type InferArgs<S extends ParameterSchemaSpec> = InferProperties<S> - if (prop.type === 'object' && prop.properties) { - const nested = schemaSpecToJsonSchema(prop.properties) - result.properties = nested.properties - if (nested.required && nested.required.length > 0) { - result.required = nested.required +const ANNOTATION_KEYS = ['description', 'title', 'default', 'examples'] as const + +/** Throw one author-schema violation through the shared schema error type. */ +function authorError(message: string): never { + throw new JsonSchemaError([message]) +} + +/** Copy own annotation fields for validation by the raw-schema boundary. */ +function copyAnnotations(source: Record<string, unknown>, target: JsonSchemaNode): void { + if (Object.hasOwn(source, 'description')) target.description = source.description as string + if (Object.hasOwn(source, 'title')) target.title = source.title as string + if (Object.hasOwn(source, 'default')) target.default = source.default as JsonValue + if (Object.hasOwn(source, 'examples')) target.examples = source.examples as JsonValue +} + +/** Reject author-only keys outside one node's declared vocabulary. */ +function assertAuthorKeys(source: Record<string, unknown>, path: string, allowed: readonly string[]): void { + for (const key of Object.keys(source)) { + if (!allowed.includes(key)) authorError(`${path}.${key} is not supported by the value schema DSL`) + } +} + +/** Compile one implicit property map, collecting per-property requiredness. */ +function compilePropertyMap( + input: unknown, + path: string, + seen: Set<object>, +): { properties: Record<string, JsonSchemaNode>; required?: string[] } { + if (!isPlainJsonRecord(input)) authorError(`${path} must be an object of value schemas`) + if (seen.has(input)) authorError(`${path} is circular`) + seen.add(input) + try { + const properties: Record<string, JsonSchemaNode> = {} + const required: string[] = [] + for (const [key, property] of Object.entries(input)) { + if (!isPlainJsonRecord(property)) authorError(`${path}.${key} must be a value schema object`) + if (Object.hasOwn(property, 'required') && property.required !== true) { + authorError(`${path}.${key}.required must be true when present`) + } + properties[key] = compileValueSchema(property, `${path}.${key}`, seen, true) + if (property.required === true) required.push(key) } + return required.length > 0 ? { properties, required } : { properties } + } finally { + seen.delete(input) } - - if (prop.type === 'array' && prop.items) { - const { schema: itemsSchema } = propToJsonSchema(prop.items) - result.items = itemsSchema - } - - return { schema: result, required } } -/** The return type of {@link schemaSpecToJsonSchema}. */ -export interface JsonSchemaObject { - type: 'object' - properties: Record<string, unknown> - required?: string[] +/** Compile one author node without applying any consumer root restriction. */ +function compileValueSchema( + input: unknown, + path: string, + seen: Set<object>, + allowRequired = false, +): JsonSchemaNode { + if (!isPlainJsonRecord(input)) authorError(`${path} must be a value schema object`) + if (seen.has(input)) authorError(`${path} is circular`) + seen.add(input) + try { + const authorKeys = [...ANNOTATION_KEYS, ...(allowRequired ? ['required'] : [])] + const node: JsonSchemaNode = {} + + if (Object.hasOwn(input, 'oneOf')) { + assertAuthorKeys(input, path, [...authorKeys, 'oneOf', 'type']) + if (Object.hasOwn(input, 'type')) authorError(`${path} cannot declare both type and oneOf`) + if (!Array.isArray(input.oneOf)) authorError(`${path}.oneOf must be an array of at least two value schemas`) + node.oneOf = input.oneOf.map((branch, index) => compileValueSchema(branch, `${path}.oneOf[${index}]`, seen)) + copyAnnotations(input, node) + return node + } + + switch (input.type) { + case 'json': + assertAuthorKeys(input, path, [...authorKeys, 'type']) + copyAnnotations(input, node) + return node + case 'object': { + assertAuthorKeys(input, path, [...authorKeys, 'type', 'properties', 'additionalProperties']) + if (!Object.hasOwn(input, 'additionalProperties') || typeof input.additionalProperties !== 'boolean') { + authorError(`${path}.additionalProperties must be explicitly true or false`) + } + node.type = 'object' + copyAnnotations(input, node) + node.additionalProperties = input.additionalProperties + if (Object.hasOwn(input, 'properties')) { + const compiled = compilePropertyMap(input.properties, `${path}.properties`, seen) + node.properties = compiled.properties + if (compiled.required !== undefined) node.required = compiled.required + } + return node + } + case 'array': + assertAuthorKeys(input, path, [...authorKeys, 'type', 'items']) + node.type = 'array' + copyAnnotations(input, node) + if (Object.hasOwn(input, 'items')) node.items = compileValueSchema(input.items, `${path}.items`, seen) + return node + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': + assertAuthorKeys(input, path, [...authorKeys, 'type', 'enum', 'const']) + node.type = input.type + copyAnnotations(input, node) + if (Object.hasOwn(input, 'enum')) { + node.enum = Array.isArray(input.enum) + ? Array.from(input.enum as unknown[], entry => entry as JsonSchemaScalar) + : input.enum as JsonSchemaScalar[] + } + if (Object.hasOwn(input, 'const')) node.const = input.const as JsonSchemaScalar + return node + default: + return authorError(`${path}.type must be string/number/integer/boolean/null/array/object/json, or use oneOf`) + } + } finally { + seen.delete(input) + } } /** - * Convert a {@link SchemaSpec} to standard JSON Schema (`type: 'object'`, - * `properties`, `required` array). - * - * This is a plain function — no schemastery or other framework dependency. - * @param spec - the author-facing per-property schema to convert. - * @returns the wire-format JSON Schema; the top-level `required` array is - * omitted entirely when no property is marked required. + * Compile one author-facing value schema to the enforced raw JSON Schema + * subset. The author-only `json` node becomes an annotation-only schema. + * @param spec - schema for any JSON-value root. + * @returns The asserted raw schema projection. */ -export function schemaSpecToJsonSchema(spec: SchemaSpec): JsonSchemaObject { - const properties: Record<string, unknown> = {} - const required: string[] = [] +export function valueSchemaSpecToJsonSchema(spec: ValueSchemaSpec): JsonSchemaNode { + const schema = compileValueSchema(spec, 'schema', new Set()) + assertSupportedJsonSchema(schema) + return schema +} - for (const [key, prop] of Object.entries(spec)) { - const { schema, required: isRequired } = propToJsonSchema(prop) - properties[key] = schema - if (isRequired) required.push(key) - } - - const result: JsonSchemaObject = { +/** + * Compile the implicit open parameter object into raw JSON Schema. + * @param spec - per-property parameter definitions. + * @returns An object-rooted raw schema with no implicit-root openness override. + */ +export function parameterSchemaSpecToJsonSchema(spec: ParameterSchemaSpec): ParameterJsonSchema { + const compiled = compilePropertyMap(spec, 'parameters', new Set()) + const schema: ParameterJsonSchema = { type: 'object', - properties, + properties: compiled.properties, + ...(compiled.required === undefined ? {} : { required: compiled.required }), } - if (required.length > 0) result.required = required - - return result + assertSupportedJsonSchema(schema) + return schema } -// --------------------------------------------------------------------------- -// Runtime validation: model-generated args ↔ SchemaSpec -// --------------------------------------------------------------------------- - -/** - * Thrown by a {@link defineTool} tool when the model-generated arguments don't - * match the declared {@link SchemaSpec}. Extends {@link HarnessError} - * (`code: 'INVALID_ARGS'`); the registry's execution pipeline catches it and - * returns an `isError` ToolExecutionResult carrying the structured error, so - * the model can self-correct and downstream plugins can route on the code. - */ +/** Invalid model-generated arguments for a typed tool. */ export class ToolArgsError extends HarnessError { - /** The individual violation messages, in declaration order. */ + /** Individual violations in schema-walk order. */ readonly violations: string[] constructor(violations: string[]) { @@ -177,152 +318,63 @@ export class ToolArgsError extends HarnessError { } } -/** Whether a value is a non-null, non-array object (a JSON Schema `object`). */ -function isPlainObject(value: unknown): value is Record<string, unknown> { - return typeof value === 'object' && value !== null && !Array.isArray(value) -} - -/** Collect violations for one property value against its {@link SchemaProp}. */ -function checkValue(prop: SchemaProp, value: unknown, path: string): string[] { - switch (prop.type) { - case 'string': { - if (typeof value !== 'string') return [`"${path}" must be a string`] - break - } - case 'number': { - if (typeof value !== 'number') return [`"${path}" must be a number`] - break - } - case 'boolean': { - if (typeof value !== 'boolean') return [`"${path}" must be a boolean`] - break - } - case 'object': { - if (!isPlainObject(value)) return [`"${path}" must be an object`] - // Mirror the converter: an object without `properties` only type-checks. - return prop.properties ? checkSpec(prop.properties, value, path) : [] - } - case 'array': { - if (!Array.isArray(value)) return [`"${path}" must be an array`] - // Mirror the converter: an array without `items` only type-checks. - if (!prop.items) return [] - const items = prop.items - return value.flatMap((el, i) => checkValue(items, el, `${path}[${i}]`)) - } - default: return assertNever(prop.type, 'validateArgs') - } - // Enum membership, checked uniformly: the converter emits `enum` for any - // type ([prop.enum]), so the validator must too. `enum` is `string[]`, so a - // non-string value can never be a member — it falls out here, consistent - // with the schema the model was given. - if (prop.enum && !(prop.enum as unknown[]).includes(value)) { - return [`"${path}" must be one of ${JSON.stringify(prop.enum)}`] - } - return [] -} - -/** Collect violations for an object value against a {@link SchemaSpec}. */ -function checkSpec(spec: SchemaSpec, value: unknown, path: string): string[] { - if (!isPlainObject(value)) return [`"${path || 'arguments'}" must be an object`] - const violations: string[] = [] - for (const [key, prop] of Object.entries(spec)) { - const propPath = path ? `${path}.${key}` : key - const v = value[key] - if (v === undefined) { - // A required key absent OR present-but-undefined is a violation; an - // optional absent key is fine. `default` is NOT applied (validation only). - if (prop.required === true) violations.push(`missing required property "${propPath}"`) - continue - } - violations.push(...checkValue(prop, v, propPath)) - } - return violations -} - /** - * Validate model-generated `args` against a {@link SchemaSpec}, returning a - * list of human-readable violation messages (empty = valid). Total — never - * throws, regardless of how malformed `args` is. - * - * Semantics mirror {@link schemaSpecToJsonSchema} exactly: the top level must - * be a non-array object; required keys come only from `required: true`; extra - * keys are allowed (no `additionalProperties: false`); `default` is not - * applied; an `object`/`array` prop without `properties`/`items` only - * type-checks; `enum` is membership (strings only). - * @param spec - the declared parameter schema to validate against. - * @param args - the model-generated arguments, however malformed. - * @returns the violation messages in declaration order; empty means valid. + * Validate model-generated arguments against an implicit parameter schema. + * @param spec - declared parameter schema. + * @param args - candidate arguments, however malformed. + * @returns Path-qualified violations; empty means valid. */ -export function validateArgs(spec: SchemaSpec, args: unknown): string[] { - return checkSpec(spec, args, '') +export function validateArgs(spec: ParameterSchemaSpec, args: unknown): string[] { + return validateJsonSchemaValue(parameterSchemaSpecToJsonSchema(spec), args, '') } -// --------------------------------------------------------------------------- -// defineTool — typed helper for first-party plugin authors -// --------------------------------------------------------------------------- - /** Options for {@link defineTool}. */ -export interface DefineToolOptions<S extends SchemaSpec> { +export interface DefineToolOptions<S extends ParameterSchemaSpec> { /** Tool name (must be unique). */ readonly name: string /** Human-readable description sent to the model. */ readonly description: string - /** - * Parameter schema using the per-property-required DSL. Converted to - * standard JSON Schema at runtime. - */ + /** Per-property parameter schema compiled to an implicit open object root. */ readonly parameters: S - /** - * Optional cooperative tool-call timeout budget in milliseconds. When given it - * must be a positive finite number; it is attached to the produced - * {@link ToolDefinition} for `@deepseek-ai/dsh-timeout-policy` to enforce and - * is never sent to the model. - */ + /** Optional positive cooperative timeout budget in milliseconds. */ readonly timeoutMs?: number /** - * Optional pure synchronous classifier for sibling overlap. It receives typed - * arguments after soft validation; invalid input returns `false` without - * invoking it. See {@link ToolDefinition.isConcurrencySafe}. + * Pure classifier for sibling overlap. * @param args - typed validated arguments. - * @returns whether this call may join a parallel group. + * @returns Whether the call may join a parallel group. */ isConcurrencySafe?(args: InferArgs<S>): boolean /** - * Tool execution function. `args` is typed as {@link InferArgs<S>} — zero - * casts needed. Returns either a bare {@link ContentBlock}`[]` (model-facing - * content only) or a `{ content, meta }` object to also attach a tool-private - * presentation payload (see {@link ToolExecuteReturn}). + * Execute the tool after argument validation. + * @param args - typed validated arguments. + * @param exec - execution identity, caller, cancellation, and nesting data. + * @returns Model-facing content and optional presentation metadata. */ execute(args: InferArgs<S>, exec: ToolRunContext): Promise<ToolExecuteReturn> /** - * Optional: how to present the PENDING state of one call in a UI (an editor - * tool-call card, a CLI log line). `args` is the typed, schema-validated - * argument shape — zero casts. Pure and side-effect-free: a UI may call it - * during live streaming AND a session-log replay, so depend only on `args`. - * The tool owns its presentation so a UI never special-cases tool names. See - * {@link ToolCallView}. + * Pure pending-state presenter. + * @param args - typed validated arguments. + * @returns Tool-owned render intent, or `undefined` for the generic card. */ presentCall?(args: InferArgs<S>): ToolCallView | undefined /** - * Optional: how to present the COMPLETED state, given the typed `args` and the - * `result`. Use it to reformat result content for a UI distinctly from the - * model-facing text (e.g. a fenced ```console block). Pure and side-effect- - * free for the same replay reason. See {@link ToolResultView}. + * Pure completed-state presenter. + * @param args - typed validated arguments. + * @param result - final model-facing tool result. + * @returns Tool-owned render intent, or `undefined` for the generic card. */ presentResult?(args: InferArgs<S>, result: ToolResult): ToolResultView | undefined } /** - * Define a first-party tool whose execution and presentation arguments are - * inferred from its per-property schema. Raw JSON-Schema definitions remain - * valid inputs to {@link ToolRegistry.register}; this helper is authoring sugar. - * @param options - the tool's name, description, typed parameter schema, - * execute body, and optional presenters. - * @returns a registry-ready definition with strict execution validation and - * soft presenter and classifier validation for replay compatibility. + * Define a first-party tool with inferred arguments and strict execution + * validation. Replay-only presenters validate softly and fall back to generic + * rendering for obsolete logged arguments. + * @param options - typed definition and optional presenters. + * @returns A registry-ready definition. */ -export function defineTool<S extends SchemaSpec>(options: DefineToolOptions<S>): ToolDefinition { - // Object-literal execute methods don't use `this`; the reference is safe. +export function defineTool<S extends ParameterSchemaSpec>(options: DefineToolOptions<S>): ToolDefinition { + // Object-literal methods do not use `this`; retaining references is safe. // eslint-disable-next-line @typescript-eslint/unbound-method const userExecute = options.execute // eslint-disable-next-line @typescript-eslint/unbound-method @@ -334,41 +386,34 @@ export function defineTool<S extends SchemaSpec>(options: DefineToolOptions<S>): if (options.timeoutMs !== undefined && (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) { throw new Error(`defineTool(${options.name}): timeoutMs must be a positive finite number`) } + const parameters = parameterSchemaSpecToJsonSchema(options.parameters) + const validate = (args: unknown): string[] => validateJsonSchemaValue(parameters, args, '') const tool: ToolDefinition = { name: options.name, description: options.description, - parameters: schemaSpecToJsonSchema(options.parameters) as unknown as Record<string, unknown>, + parameters: parameters as unknown as Record<string, unknown>, ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}), async execute(args: unknown, exec: ToolRunContext): Promise<ToolExecuteReturn> { - // Validate the model-generated args before the typed body runs. On - // mismatch we throw ToolArgsError; the registry turns it into an - // isError result so the model can self-correct. After this guard, the - // cast to InferArgs<S> reflects the validated shape. - const violations = validateArgs(options.parameters, args) + const violations = validate(args) if (violations.length > 0) throw new ToolArgsError(violations) return userExecute(args as InferArgs<S>, exec) }, } - // Presentation is display-only and may run on REPLAY of arbitrary logged args - // (possibly from an older schema), so it must never throw: validate softly and - // fall back to `undefined` (a generic UI presentation) on any mismatch, rather - // than the hard `ToolArgsError` the execute path raises. if (userPresentCall) { tool.presentCall = (args: unknown): ToolCallView | undefined => { - if (validateArgs(options.parameters, args).length > 0) return undefined + if (validate(args).length > 0) return undefined return userPresentCall(args as InferArgs<S>) } } if (userPresentResult) { tool.presentResult = (args: unknown, result: ToolResult): ToolResultView | undefined => { - if (validateArgs(options.parameters, args).length > 0) return undefined + if (validate(args).length > 0) return undefined return userPresentResult(args as InferArgs<S>, result) } } - // Invalid arguments fail closed without invoking the typed classifier. if (userIsConcurrencySafe) { tool.isConcurrencySafe = (args: unknown): boolean => { - if (validateArgs(options.parameters, args).length > 0) return false + if (validate(args).length > 0) return false return userIsConcurrencySafe(args as InferArgs<S>) } } diff --git a/packages/core/tools/src/ts-types.ts b/packages/core/tools/src/ts-types.ts index e5f67d0891..39cec5665e 100644 --- a/packages/core/tools/src/ts-types.ts +++ b/packages/core/tools/src/ts-types.ts @@ -7,6 +7,8 @@ */ import type { ToolSchema } from '@deepseek-ai/dsh-llm' +import { assertSupportedJsonSchema } from './json-schema.ts' +import type { JsonSchemaScalar } from './json-schema.ts' /** Property names that are valid bare TS identifiers; anything else is quoted. */ const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/ @@ -30,47 +32,72 @@ function docLines(description: unknown, indent: number): string[] { return [`${pad(indent)}/** ${collapsed.replaceAll('*/', String.raw`*\/`)} */`] } +/** Render one scalar already validated by the unified schema boundary. */ +function renderScalar(value: JsonSchemaScalar): string { + return JSON.stringify(value) +} + +/** Render a validated scalar `const`/`enum`, falling back to the broad type. */ +function renderConstrainedScalar(node: Record<string, unknown>, type: string): string { + const broad = type === 'integer' ? 'number' : type + if (Object.hasOwn(node, 'const')) return renderScalar(node.const as JsonSchemaScalar) + if (Object.hasOwn(node, 'enum')) { + return (node.enum as JsonSchemaScalar[]).map(renderScalar).join(' | ') + } + return broad +} + +/** Parenthesize a union or object intersection before applying `[]`. */ +function arrayItem(type: string): string { + return type.includes('|') || type.includes('&') ? `(${type})[]` : `${type}[]` +} + /** - * Map one JSON-Schema node to a TypeScript type literal. Handles exactly the - * subset the `defineTool` DSL emits — `object` (`properties` + `required`), - * `string` (with `enum` → a literal union), `number`, `boolean`, `array` - * (`items`) — and returns `unknown` for anything else, without throwing. + * Map one enforced JSON-Schema node to a TypeScript type literal. Supports + * every unified schema construct and returns `unknown` for malformed or + * unsupported inputs without throwing. * @param schema - the JSON-Schema node (any shape; hostile inputs degrade). * @param indent - the indentation level for nested object members. * @returns the TS type text (multi-line for objects with properties). */ export function jsonSchemaToTs(schema: unknown, indent = 0): string { - if (typeof schema !== 'object' || schema === null) return 'unknown' + try { + assertSupportedJsonSchema(schema) + } catch { + return 'unknown' + } const node = schema as Record<string, unknown> + if (Object.hasOwn(node, 'oneOf')) { + return (node.oneOf as unknown[]).map(branch => jsonSchemaToTs(branch, indent)).join(' | ') + } + if (!Object.hasOwn(node, 'type')) return 'JsonValue' switch (node.type) { - case 'string': { - if (Array.isArray(node.enum) && node.enum.length > 0 && node.enum.every(value => typeof value === 'string')) { - return node.enum.map(value => JSON.stringify(value)).join(' | ') - } - return 'string' - } - case 'number': return 'number' - case 'boolean': return 'boolean' + case 'string': return renderConstrainedScalar(node, 'string') + case 'number': return renderConstrainedScalar(node, 'number') + case 'integer': return renderConstrainedScalar(node, 'integer') + case 'boolean': return renderConstrainedScalar(node, 'boolean') + case 'null': return renderConstrainedScalar(node, 'null') case 'array': { - const item = jsonSchemaToTs(node.items, indent) - // Parenthesize a union item type so `('a' | 'b')[]` parses as intended. - return item.includes('|') ? `(${item})[]` : `${item}[]` + return arrayItem(Object.hasOwn(node, 'items') ? jsonSchemaToTs(node.items, indent) : 'JsonValue') } case 'object': { const properties = node.properties - if (typeof properties !== 'object' || properties === null) return 'Record<string, unknown>' + const open = node.additionalProperties !== false + if (properties === undefined) return open ? 'Record<string, JsonValue>' : 'Record<string, never>' const entries = Object.entries(properties as Record<string, unknown>) - if (entries.length === 0) return 'Record<string, unknown>' - const required = new Set(Array.isArray(node.required) ? node.required.filter(name => typeof name === 'string') : []) + if (entries.length === 0) return open ? 'Record<string, JsonValue>' : 'Record<string, never>' + const required = new Set(node.required as string[] | undefined) const lines: string[] = ['{'] for (const [name, prop] of entries) { - const description = typeof prop === 'object' && prop !== null ? (prop as Record<string, unknown>).description : undefined + const description = (prop as Record<string, unknown>).description lines.push(...docLines(description, indent + 1)) lines.push(`${pad(indent + 1)}${renderKey(name)}${required.has(name) ? '' : '?'}: ${jsonSchemaToTs(prop, indent + 1)};`) } lines.push(`${pad(indent)}}`) - return lines.join('\n') + const declared = lines.join('\n') + return open ? `${declared} & Record<string, JsonValue>` : declared } + /* v8 ignore next -- assertSupportedJsonSchema narrowed this closed type union. */ default: return 'unknown' } } @@ -106,5 +133,6 @@ export function renderToolsSdk(schemas: ToolSchema[]): string { const declaration = members.length > 0 ? `declare const tools: {\n${members.join('\n')}\n}` : 'declare const tools: {}' - return `${SDK_INSTRUCTIONS}\n\n\`\`\`ts\n${declaration}\n\`\`\`` + const jsonValue = 'type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue }' + return `${SDK_INSTRUCTIONS}\n\n\`\`\`ts\n${jsonValue}\n\n${declaration}\n\`\`\`` } diff --git a/packages/core/tools/tests/json-schema.spec.ts b/packages/core/tools/tests/json-schema.spec.ts index 6fa895288e..26124083a9 100644 --- a/packages/core/tools/tests/json-schema.spec.ts +++ b/packages/core/tools/tests/json-schema.spec.ts @@ -1,304 +1,326 @@ import { describe, expect, it } from 'vitest' import { - assertSupportedOutputSchema, - OutputSchemaError, - validateStructuredValue, - type StructuredOutputSchema, -} from '../src/json-schema.ts' + assertObjectJsonSchema, + assertSupportedJsonSchema, + JsonSchemaError, + validateJsonSchemaValue, + type JsonSchemaNode, + type ObjectJsonSchema, +} from '../src/index.ts' -/** Assert-and-narrow helper: the asserted schema, typed. */ -function asserted(schema: unknown): StructuredOutputSchema { - assertSupportedOutputSchema(schema) +function asserted(schema: unknown): JsonSchemaNode { + assertSupportedJsonSchema(schema) return schema } -/** The violations OutputSchemaError carries for a bad schema (throws if it passes). */ -function violationsOf(schema: unknown): string[] { - try { - assertSupportedOutputSchema(schema) - } catch (error: unknown) { - if (error instanceof OutputSchemaError) return error.violations - throw error - } - throw new Error('expected the schema to be rejected') +function assertedObject(schema: unknown): ObjectJsonSchema { + assertObjectJsonSchema(schema) + return schema } -describe('assertSupportedOutputSchema', () => { - it('accepts a representative subset schema (all supported keywords)', () => { - const schema = asserted({ - type: 'object', - description: 'a finding', - title: 'Finding', - properties: { - file: { type: 'string', description: 'path' }, - line: { type: 'integer' }, - severity: { type: 'string', enum: ['low', 'high'] }, - kind: { type: 'string', const: 'bug' }, - score: { type: 'number' }, - confirmed: { type: 'boolean' }, - parent: { type: 'null' }, - tags: { type: 'array', items: { type: 'string' } }, - nested: { - type: 'object', - properties: { x: { type: 'number', default: 3, examples: [1, 2] } }, - additionalProperties: false, +function violationsOf(schema: unknown, objectRoot = false): string[] { + try { + if (objectRoot) assertObjectJsonSchema(schema) + else assertSupportedJsonSchema(schema) + } catch (error: unknown) { + if (error instanceof JsonSchemaError) return error.violations + throw error + } + throw new Error('expected schema rejection') +} + +describe('the enforced raw JSON Schema subset', () => { + it('accepts every JSON root and every supported node', () => { + for (const schema of [ + { type: 'string' }, + { type: 'number' }, + { type: 'integer' }, + { type: 'boolean' }, + { type: 'null' }, + { type: 'array', items: { type: 'string' } }, + { + type: 'object', + properties: { + nested: { type: 'object', properties: {}, additionalProperties: false }, + free: {}, }, - anything: { type: 'array' }, + required: ['nested'], + additionalProperties: true, }, - required: ['file', 'line'], - additionalProperties: true, - }) - expect(schema.type).toBe('object') + { oneOf: [{ type: 'string' }, { type: 'number' }] }, + { description: 'any JSON', title: 'JSON', default: null, examples: [1, 'x'] }, + ]) { + expect(() => { assertSupportedJsonSchema(schema) }, JSON.stringify(schema)).not.toThrow() + } }) - it('rejects a non-object root (scalar/array-rooted schemas)', () => { - expect(violationsOf({ type: 'string' })).toEqual(['schema.type must be "object" (structured output is object-rooted)']) - expect(violationsOf({ type: 'array', items: { type: 'string' } })) - .toContain('schema.type must be "object" (structured output is object-rooted)') + it('retains an object-root guard only at consumers that need it', () => { + expect(assertedObject({ type: 'object' }).type).toBe('object') + for (const schema of [{}, { type: 'string' }, { type: 'array' }, { oneOf: [{ type: 'string' }, { type: 'null' }] }]) { + expect(violationsOf(schema, true)).toEqual(['schema.type must be "object" (structured output is object-rooted)']) + } }) - it('rejects non-object schema nodes and missing/unknown type', () => { - expect(violationsOf('nope')).toEqual(['schema must be a schema object']) + it('rejects non-schema nodes, unknown types, and type arrays', () => { expect(violationsOf(null)).toEqual(['schema must be a schema object']) expect(violationsOf([])).toEqual(['schema must be a schema object']) - expect(violationsOf({})).toEqual(['schema.type must be one of object/array/string/number/integer/boolean/null']) + expect(violationsOf('no')).toEqual(['schema must be a schema object']) expect(violationsOf({ type: 'tuple' })[0]).toMatch(/type must be one of/) - expect(violationsOf({ type: 'object', properties: { a: 'str' } })).toEqual(['schema.properties.a must be a schema object']) - }) - - it('rejects type ARRAYS with a dedicated message', () => { expect(violationsOf({ type: ['string', 'null'] })) .toEqual(['schema.type must be a single type string (type arrays are not supported)']) }) - it('rejects unsupported constraint keywords loudly (never accepted-then-ignored)', () => { - for (const keyword of ['oneOf', 'anyOf', 'allOf', 'not', 'pattern', 'minimum', 'maxLength', '$ref']) { - const bad = violationsOf({ type: 'object', [keyword]: [] }) - expect(bad.some(v => v.includes(`schema.${keyword} is not a supported keyword`))).toBe(true) - } + it('enforces oneOf vocabulary and its minimum branch count', () => { + expect(violationsOf({ oneOf: [] })).toEqual(['schema.oneOf must be an array of at least two schemas']) + expect(violationsOf({ oneOf: [{}] })).toEqual(['schema.oneOf must be an array of at least two schemas']) + expect(violationsOf({ oneOf: 'x' })).toEqual(['schema.oneOf must be an array of at least two schemas']) + expect(violationsOf({ type: 'string', oneOf: [{}, {}] })) + .toEqual(['schema cannot declare both type and oneOf']) + expect(violationsOf({ oneOf: [{ type: 'string' }, { type: 'number' }], items: {} })) + .toEqual(['schema.items is not supported beside oneOf']) + expect(violationsOf({ oneOf: [{ type: 'string' }, { type: 'weird' }] })[0]) + .toContain('schema.oneOf[1].type') }) - it('reports EVERY violation, not just the first', () => { - const bad = violationsOf({ + it('rejects unknown and misplaced keywords without accepted-then-ignored behavior', () => { + for (const keyword of ['anyOf', 'allOf', 'not', 'pattern', 'minimum', 'maxLength', '$ref']) { + expect(violationsOf({ type: 'object', [keyword]: [] })[0]).toContain(`schema.${keyword} is not a supported keyword`) + } + expect(violationsOf({ type: 'object', items: {} })) + .toEqual(['schema.items is not supported on type "object"']) + expect(violationsOf({ type: 'array', properties: {} })) + .toEqual(['schema.properties is not supported on type "array"']) + expect(violationsOf({ type: 'object', enum: ['x'] })) + .toEqual(['schema.enum is not supported on type "object"']) + expect(violationsOf({ type: 'array', const: null })) + .toEqual(['schema.const is not supported on type "array"']) + expect(violationsOf({ properties: {}, required: [], additionalProperties: true, items: {}, enum: [], const: null })) + .toEqual([ + 'schema.properties requires type or oneOf', + 'schema.required requires type or oneOf', + 'schema.additionalProperties requires type or oneOf', + 'schema.items requires type or oneOf', + 'schema.enum requires type or oneOf', + 'schema.const requires type or oneOf', + ]) + }) + + it('reports every independent schema violation', () => { + expect(violationsOf({ type: 'object', pattern: 'x', properties: { a: { type: 'weird' }, b: { type: 'string', minimum: 1 } }, - }) - expect(bad.length).toBe(3) + })).toHaveLength(3) }) - it('rejects keywords on the wrong type (items on object, properties on string, enum on object)', () => { - expect(violationsOf({ type: 'object', items: { type: 'string' } })) - .toEqual(['schema.items is not supported on type "object"']) - expect(violationsOf({ type: 'object', properties: { a: { type: 'string', properties: {} } } })) - .toEqual(['schema.properties.a.properties is not supported on type "string"']) - expect(violationsOf({ type: 'object', enum: [1] })) - .toEqual(['schema.enum is not supported on type "object"']) - expect(violationsOf({ type: 'object', properties: { a: { type: 'array', const: 1 } } })) - .toEqual(['schema.properties.a.const is not supported on type "array"']) - }) - - it('validates required: must be string[] naming declared properties', () => { - expect(violationsOf({ type: 'object', required: 'file' })) + it('validates object properties, required names, and openness', () => { + expect(violationsOf({ type: 'object', properties: [] })) + .toEqual(['schema.properties must be an object of schemas']) + expect(violationsOf({ type: 'object', properties: { a: 'x' } })) + .toEqual(['schema.properties.a must be a schema object']) + expect(violationsOf({ type: 'object', required: 'a' })) .toEqual(['schema.required must be an array of strings']) expect(violationsOf({ type: 'object', required: [1] })) .toEqual(['schema.required must be an array of strings']) - expect(violationsOf({ type: 'object', properties: { a: { type: 'string' } }, required: ['b'] })) - .toEqual(['schema.required names "b" which is not in properties']) - expect(violationsOf({ type: 'object', required: ['a'] })) - .toEqual(['schema.required names "a" which is not in properties']) - }) - - it('validates additionalProperties must be boolean and enum/const must be scalars', () => { - expect(violationsOf({ type: 'object', additionalProperties: {} })) + expect(violationsOf({ type: 'object', properties: {}, required: ['missing'] })) + .toEqual(['schema.required names "missing" which is not in properties']) + expect(violationsOf({ type: 'object', additionalProperties: 'yes' })) .toEqual(['schema.additionalProperties must be a boolean']) - expect(violationsOf({ type: 'object', properties: { a: { type: 'string', enum: [] } } })) - .toEqual(['schema.properties.a.enum must be a non-empty array of scalars']) - expect(violationsOf({ type: 'object', properties: { a: { type: 'string', enum: [{}] } } })) - .toEqual(['schema.properties.a.enum must be a non-empty array of scalars']) - expect(violationsOf({ type: 'object', properties: { a: { type: 'string', enum: 'x' } } })) - .toEqual(['schema.properties.a.enum must be a non-empty array of scalars']) - expect(violationsOf({ type: 'object', properties: { a: { type: 'number', enum: [Number.NaN] } } })) - .toEqual(['schema.properties.a.enum must be a non-empty array of scalars']) - expect(violationsOf({ type: 'object', properties: { a: { type: 'string', const: {} } } })) - .toEqual(['schema.properties.a.const must be a scalar']) + expect(violationsOf({ type: 'object', properties: undefined })) + .toEqual(['schema.properties must be an object of schemas']) + expect(violationsOf({ type: 'object', properties: undefined, required: ['missing'] })) + .toEqual([ + 'schema.properties must be an object of schemas', + 'schema.required names "missing" which is not in properties', + ]) }) - it('rejects non-string description/title and non-JSON annotation payloads', () => { - expect(violationsOf({ type: 'object', description: 7 })) - .toEqual(['schema.description must be a string']) - expect(violationsOf({ type: 'object', title: 7 })) - .toEqual(['schema.title must be a string']) - expect(violationsOf({ type: 'object', default: () => 1 })) - .toEqual(['schema.default annotation must be JSON data']) - expect(violationsOf({ type: 'object', examples: [undefined] })) - .toEqual(['schema.examples annotation must be JSON data']) - expect(violationsOf({ type: 'object', examples: [Number.POSITIVE_INFINITY] })) - .toEqual(['schema.examples annotation must be JSON data']) - // A cyclic annotation payload is caught by the JSON-data walk. - const cyclicAnnotation: Record<string, unknown> = {} - cyclicAnnotation.self = cyclicAnnotation - expect(violationsOf({ type: 'object', default: cyclicAnnotation })) - .toEqual(['schema.default annotation must be JSON data']) - // Object/array annotations that ARE JSON data pass. - asserted({ type: 'object', default: { a: [1, 'x', null, true] } }) + it('requires type-correct scalar enum and const values', () => { + for (const schema of [ + { type: 'string', enum: ['a'], const: 'a' }, + { type: 'number', enum: [1.5], const: 1.5 }, + { type: 'integer', enum: [1], const: 1 }, + { type: 'boolean', enum: [true], const: true }, + { type: 'null', enum: [null], const: null }, + ]) { + expect(() => { assertSupportedJsonSchema(schema) }, JSON.stringify(schema)).not.toThrow() + } + + expect(violationsOf({ type: 'string', enum: [] })) + .toEqual(['schema.enum must be a non-empty array of string values']) + expect(violationsOf({ type: 'number', enum: ['1'] })) + .toEqual(['schema.enum must be a non-empty array of number values']) + expect(violationsOf({ type: 'integer', enum: [1.5] })) + .toEqual(['schema.enum must be a non-empty array of integer values']) + expect(violationsOf({ type: 'number', enum: [Number.NaN] })) + .toEqual(['schema.enum must be a non-empty array of number values']) + expect(violationsOf({ type: 'number', const: -0 })) + .toEqual(['schema.const must be a number value']) + expect(violationsOf({ type: 'boolean', const: 1 })) + .toEqual(['schema.const must be a boolean value']) + expect(violationsOf({ type: 'string', enum: undefined })) + .toEqual(['schema.enum must be a non-empty array of string values']) }) - it('rejects a circular schema instead of recursing forever', () => { - const node: Record<string, unknown> = { type: 'object' } - node.properties = { self: node } - expect(violationsOf(node)).toEqual(['schema.properties.self is circular']) + it('validates annotation types and lossless JSON payloads', () => { + expect(violationsOf({ description: 1 })).toEqual(['schema.description must be a string']) + expect(violationsOf({ title: 1 })).toEqual(['schema.title must be a string']) + for (const [key, value] of [ + ['default', undefined], + ['examples', [undefined]], + ['default', Number.POSITIVE_INFINITY], + ['examples', new Date(0)], + ] as const) { + expect(violationsOf({ [key]: value })).toEqual([`schema.${key} annotation must be lossless JSON data`]) + } + const cyclic: Record<string, unknown> = {} + cyclic.self = cyclic + expect(violationsOf({ default: cyclic })) + .toEqual(['schema.default annotation must be lossless JSON data']) + + const explosive = new Proxy({}, { + ownKeys() { throw new Error('annotation trap') }, + }) + expect(violationsOf({ examples: explosive })) + .toEqual(['schema.examples annotation must be lossless JSON data']) }) - it('accepts the same subschema object reused in two SIBLING positions (a DAG, not a cycle)', () => { + it('rejects cyclic/exotic schema structure but permits sibling reuse', () => { + const cyclic: Record<string, unknown> = { type: 'object' } + cyclic.properties = { self: cyclic } + expect(violationsOf(cyclic)).toEqual(['schema.properties.self is circular']) const leaf = { type: 'string' } - asserted({ type: 'object', properties: { a: leaf, b: leaf } }) - }) - - it('required cannot be satisfied by INHERITED names — `toString` is not a declared property', () => { - // `'toString' in {}` is true via Object.prototype; the declared-property - // contract must be an own-property check. - expect(violationsOf({ type: 'object', properties: {}, required: ['toString'] })) - .toEqual(['schema.required names "toString" which is not in properties']) - }) - - it('rejects exotic host objects where the subset expects plain JSON structure', () => { - // A Map as `properties` has no own enumerable entries: structurally it - // would read as "no properties" and serialize to {} — lossy, not loud. + expect(() => { assertSupportedJsonSchema({ type: 'object', properties: { a: leaf, b: leaf } }) }).not.toThrow() expect(violationsOf({ type: 'object', properties: new Map() })) .toEqual(['schema.properties must be an object of schemas']) - // A Date node is not a schema object even though Object.values(date) is []. expect(violationsOf({ type: 'object', properties: { at: new Date(0) } })) .toEqual(['schema.properties.at must be a schema object']) }) - it('rejects exotic annotation payloads that would serialize lossily', () => { - expect(violationsOf({ type: 'object', default: new Date(0) })) - .toEqual(['schema.default annotation must be JSON data']) - expect(violationsOf({ type: 'object', examples: [new Map()] })) - .toEqual(['schema.examples annotation must be JSON data']) + it('uses own-property semantics for required declarations', () => { + expect(violationsOf({ type: 'object', properties: {}, required: ['toString'] })) + .toEqual(['schema.required names "toString" which is not in properties']) }) }) -describe('validateStructuredValue', () => { - const schema = asserted({ - type: 'object', - properties: { - file: { type: 'string' }, - line: { type: 'integer' }, - score: { type: 'number' }, - confirmed: { type: 'boolean' }, - parent: { type: 'null' }, - severity: { type: 'string', enum: ['low', 'high'] }, - kind: { type: 'string', const: 'bug' }, - tags: { type: 'array', items: { type: 'string' } }, - free: { type: 'array' }, - nested: { type: 'object', properties: { x: { type: 'number' } }, required: ['x'], additionalProperties: false }, - }, - required: ['file'], +describe('validateJsonSchemaValue', () => { + it('validates scalar, array, object, and null roots', () => { + expect(validateJsonSchemaValue(asserted({ type: 'string' }), 'x')).toEqual([]) + expect(validateJsonSchemaValue(asserted({ type: 'number' }), 1.5)).toEqual([]) + expect(validateJsonSchemaValue(asserted({ type: 'integer' }), 2)).toEqual([]) + expect(validateJsonSchemaValue(asserted({ type: 'boolean' }), true)).toEqual([]) + expect(validateJsonSchemaValue(asserted({ type: 'null' }), null)).toEqual([]) + expect(validateJsonSchemaValue(asserted({ type: 'array', items: { type: 'string' } }), ['x'])).toEqual([]) + expect(validateJsonSchemaValue(asserted({ type: 'object' }), { x: 1 })).toEqual([]) }) - it('accepts a fully valid value (empty violations)', () => { - expect(validateStructuredValue(schema, { - file: 'a.ts', line: 3, score: 0.5, confirmed: true, parent: null, - severity: 'high', kind: 'bug', tags: ['x'], free: [1, { any: true }], nested: { x: 1 }, - })).toEqual([]) + it('rejects wrong scalar types and lossy numbers', () => { + expect(validateJsonSchemaValue(asserted({ type: 'string' }), 1)).toEqual(['"value" must be a string']) + expect(validateJsonSchemaValue(asserted({ type: 'number' }), '1')).toEqual(['"value" must be a number']) + expect(validateJsonSchemaValue(asserted({ type: 'number' }), Number.NaN)).toEqual(['"value" must be a finite JSON number']) + expect(validateJsonSchemaValue(asserted({ type: 'number' }), -0)).toEqual(['"value" must be a finite JSON number']) + expect(validateJsonSchemaValue(asserted({ type: 'integer' }), 1.5)).toEqual(['"value" must be an integer']) + expect(validateJsonSchemaValue(asserted({ type: 'boolean' }), 'true')).toEqual(['"value" must be a boolean']) + expect(validateJsonSchemaValue(asserted({ type: 'null' }), 0)).toEqual(['"value" must be null']) }) - it('reports missing required and wrong root type', () => { - expect(validateStructuredValue(schema, {})).toEqual(['missing required property "value.file"']) - expect(validateStructuredValue(schema, 'nope')).toEqual(['"value" must be an object']) - expect(validateStructuredValue(schema, [])).toEqual(['"value" must be an object']) + it('enforces scalar enum and const together', () => { + const schema = asserted({ type: 'string', enum: ['a', 'b'], const: 'a' }) + expect(validateJsonSchemaValue(schema, 'a')).toEqual([]) + expect(validateJsonSchemaValue(schema, 'c')).toEqual(['"value" must be one of ["a","b"]']) + expect(validateJsonSchemaValue(schema, 'b')).toEqual(['"value" must be "a"']) }) - it('type-checks every scalar branch with path-qualified messages', () => { - expect(validateStructuredValue(schema, { file: 1 })).toEqual(['"value.file" must be a string']) - expect(validateStructuredValue(schema, { file: 'a', line: 1.5 })).toEqual(['"value.line" must be an integer']) - expect(validateStructuredValue(schema, { file: 'a', line: 'x' })).toEqual(['"value.line" must be an integer']) - expect(validateStructuredValue(schema, { file: 'a', score: 'x' })).toEqual(['"value.score" must be a finite number']) - expect(validateStructuredValue(schema, { file: 'a', score: Number.NaN })).toEqual(['"value.score" must be a finite number']) - expect(validateStructuredValue(schema, { file: 'a', confirmed: 'yes' })).toEqual(['"value.confirmed" must be a boolean']) - expect(validateStructuredValue(schema, { file: 'a', parent: 0 })).toEqual(['"value.parent" must be null']) + it('validates object requiredness, nested values, and raw open defaults', () => { + const open = asserted({ + type: 'object', + properties: { + file: { type: 'string' }, + nested: { + type: 'object', + properties: { line: { type: 'integer' } }, + required: ['line'], + additionalProperties: false, + }, + }, + required: ['file'], + }) + expect(validateJsonSchemaValue(open, { file: 'a', extra: [1], nested: { line: 2 } })).toEqual([]) + expect(validateJsonSchemaValue(open, { nested: { line: 1 } })) + .toEqual(['missing required property "value.file"']) + expect(validateJsonSchemaValue(open, { file: 1, nested: {} })).toEqual([ + '"value.file" must be a string', + 'missing required property "value.nested.line"', + ]) + expect(validateJsonSchemaValue(open, { file: 'a', nested: { line: 1, extra: true } })) + .toEqual(['"value.nested.extra" is not a declared property (additionalProperties: false)']) + expect(validateJsonSchemaValue(open, 'x')).toEqual(['"value" must be an object']) }) - it('enforces enum membership and const equality', () => { - expect(validateStructuredValue(schema, { file: 'a', severity: 'mid' })) - .toEqual(['"value.severity" must be one of ["low","high"]']) - expect(validateStructuredValue(schema, { file: 'a', kind: 'feature' })) - .toEqual(['"value.kind" must be "bug"']) + it('treats present undefined as missing when required, then rejects other lossy objects', () => { + const required = asserted({ type: 'object', properties: { x: {} }, required: ['x'] }) + expect(validateJsonSchemaValue(required, { x: undefined })) + .toEqual(['missing required property "value.x"']) + expect(validateJsonSchemaValue(asserted({ type: 'object' }), { x: undefined })) + .toEqual(['"value" must be a lossless JSON object']) + expect(validateJsonSchemaValue(asserted({ type: 'object' }), new Date(0))) + .toEqual(['"value" must be an object']) }) - it('checks arrays per index; an items-less array accepts anything', () => { - expect(validateStructuredValue(schema, { file: 'a', tags: 'x' })).toEqual(['"value.tags" must be an array']) - expect(validateStructuredValue(schema, { file: 'a', tags: ['ok', 2] })).toEqual(['"value.tags[1]" must be a string']) - expect(validateStructuredValue(schema, { file: 'a', free: [{ deep: [1] }, null] })).toEqual([]) + it('validates dense arrays per index and rejects lossy arrays', () => { + const schema = asserted({ type: 'array', items: { type: 'integer' } }) + expect(validateJsonSchemaValue(schema, [1, 2])).toEqual([]) + expect(validateJsonSchemaValue(schema, [1, 1.5])).toEqual(['"value[1]" must be an integer']) + expect(validateJsonSchemaValue(schema, 'x')).toEqual(['"value" must be an array']) + const sparse: number[] = [] + sparse.length = 2 + sparse[0] = 1 + expect(validateJsonSchemaValue(schema, sparse)).toEqual(['"value" must be a dense lossless JSON array']) }) - it('recurses into nested objects: required + additionalProperties: false', () => { - expect(validateStructuredValue(schema, { file: 'a', nested: {} })) - .toEqual(['missing required property "value.nested.x"']) - expect(validateStructuredValue(schema, { file: 'a', nested: { x: 1, y: 2 } })) - .toEqual(['"value.nested.y" is not a declared property (additionalProperties: false)']) - expect(validateStructuredValue(schema, { file: 'a', nested: 3 })) - .toEqual(['"value.nested" must be an object']) + it('validates exact-one oneOf semantics, including overlap', () => { + const disjoint = asserted({ oneOf: [{ type: 'string' }, { type: 'number' }] }) + expect(validateJsonSchemaValue(disjoint, 'x')).toEqual([]) + expect(validateJsonSchemaValue(disjoint, null)) + .toEqual(['"value" must match exactly one oneOf branch (matched 0)']) + const overlap = asserted({ oneOf: [{ type: 'number' }, { type: 'integer' }] }) + expect(validateJsonSchemaValue(overlap, 1)) + .toEqual(['"value" must match exactly one oneOf branch (matched 2)']) + expect(validateJsonSchemaValue(overlap, 1.5)).toEqual([]) }) - it('a required key present-but-undefined counts as missing', () => { - expect(validateStructuredValue(schema, { file: undefined })).toEqual(['missing required property "value.file"']) + it('an unconstrained schema accepts only lossless JSON values', () => { + const anyJson = asserted({}) + for (const value of [null, true, 1, 'x', [1], { x: null }]) { + expect(validateJsonSchemaValue(anyJson, value), JSON.stringify(value)).toEqual([]) + } + for (const value of [undefined, () => 1, Number.POSITIVE_INFINITY, -0, new Map()]) { + expect(validateJsonSchemaValue(anyJson, value)).toEqual(['"value" must be a lossless JSON value']) + } + const cyclic: Record<string, unknown> = {} + cyclic.self = cyclic + expect(validateJsonSchemaValue(anyJson, cyclic)).toEqual(['"value" must be a lossless JSON value']) + const explosive = new Proxy({}, { + ownKeys() { throw new Error('value trap') }, + }) + expect(validateJsonSchemaValue(anyJson, explosive)).toEqual(['"value" must be a lossless JSON value']) }) - it('inherited properties satisfy nothing: required, additionalProperties, and recursion are own-property only', () => { - // required: ['toString'] must NOT be satisfied by Object.prototype.toString. - expect(validateStructuredValue( + it('uses own properties for requiredness, recursion, and closed-object checks', () => { + expect(validateJsonSchemaValue( asserted({ type: 'object', properties: { toString: { type: 'string' } }, required: ['toString'] }), {}, )).toEqual(['missing required property "value.toString"']) - // additionalProperties: false must flag an OWN `toString` key even though - // `'toString' in properties` is true via the prototype. - expect(validateStructuredValue( - asserted({ type: 'object', additionalProperties: false }), - { toString: 1 }, - )).toEqual(['"value.toString" is not a declared property (additionalProperties: false)']) - // A declared property the value does NOT carry must not be validated - // against the value's INHERITED member (constructor is a function on - // every plain object's prototype, not a carried property). - expect(validateStructuredValue( + expect(validateJsonSchemaValue(asserted({ type: 'object', additionalProperties: false }), { toString: 1 })) + .toEqual(['"value.toString" is not a declared property (additionalProperties: false)']) + expect(validateJsonSchemaValue( asserted({ type: 'object', properties: { constructor: { type: 'string' } } }), {}, )).toEqual([]) }) - it('a non-plain object value is not an object in the JSON sense', () => { - expect(validateStructuredValue(asserted({ type: 'object' }), new Date(0))) - .toEqual(['"value" must be an object']) - }) - - it('collects multiple violations across branches in one pass', () => { - expect(validateStructuredValue(schema, { line: 'x', severity: 'mid' })).toEqual([ - 'missing required property "value.file"', - '"value.line" must be an integer', - '"value.severity" must be one of ["low","high"]', - ]) - }) - - it('null-typed const/enum work through the scalar path', () => { - const nullish = asserted({ type: 'object', properties: { a: { type: 'null', const: null } } }) - expect(validateStructuredValue(nullish, { a: null })).toEqual([]) - }) - - it('rejects a non-object properties value in the schema walk', () => { - expect(violationsOf({ type: 'object', properties: [] })) - .toEqual(['schema.properties must be an object of schemas']) - }) - - it('an object schema without properties/required only type-checks its value', () => { - const bare = asserted({ type: 'object' }) - expect(validateStructuredValue(bare, { any: ['thing'] })).toEqual([]) - expect(validateStructuredValue(bare, 7)).toEqual(['"value" must be an object']) - }) - - it('validateStructuredValue throws on a type the assert would never let through (assertNever backstop)', () => { - const forged = { type: 'tuple' } as unknown as StructuredOutputSchema - expect(() => validateStructuredValue(forged, 1)).toThrow(/tuple/) + it('keeps assertNever as a forged-schema backstop', () => { + const forged = { type: 'tuple' } as unknown as JsonSchemaNode + expect(() => validateJsonSchemaValue(forged, 1)).toThrow(/tuple/) }) }) diff --git a/packages/core/tools/tests/properties.spec.ts b/packages/core/tools/tests/properties.spec.ts index 51b49fccd4..54c4088909 100644 --- a/packages/core/tools/tests/properties.spec.ts +++ b/packages/core/tools/tests/properties.spec.ts @@ -1,61 +1,91 @@ /** * Property-based tests for the tool-schema DSL (the property-testing Agent Note), including - * the the property-testing ↔ runtime-validation composition composition: generated args that satisfy a SchemaSpec must + * the property-testing ↔ runtime-validation composition: generated args that satisfy a ParameterSchemaSpec must * pass validateArgs, and targeted corruptions must be rejected. This closes the * validator/InferArgs drift risk noted in the arg-validation Agent Note. */ import { describe, expect, it } from 'vitest' import fc from 'fast-check' -import { schemaSpecToJsonSchema, validateArgs } from '@deepseek-ai/dsh-tools' -import type { SchemaProp, SchemaSpec } from '@deepseek-ai/dsh-tools' +import { parameterSchemaSpecToJsonSchema, validateArgs } from '@deepseek-ai/dsh-tools' +import type { ParameterPropertySpec, ParameterSchemaSpec, ValueSchemaSpec } from '@deepseek-ai/dsh-tools' + +/** Remove parameter-only requiredness before nesting a schema as an array item. */ +function asValueSchema(prop: ParameterPropertySpec): ValueSchemaSpec { + const { required: _required, ...schema } = prop + return schema +} // A leaf prop arbitrary (no nesting) with optional required/enum. -function leafPropArb(): fc.Arbitrary<SchemaProp> { +function leafPropArb(): fc.Arbitrary<ParameterPropertySpec> { return fc.oneof( - fc.record({ required: fc.boolean() }).map(({ required }): SchemaProp => ({ type: 'string', ...required ? { required: true } : {} })), - fc.record({ required: fc.boolean() }).map(({ required }): SchemaProp => ({ type: 'number', ...required ? { required: true } : {} })), - fc.record({ required: fc.boolean() }).map(({ required }): SchemaProp => ({ type: 'boolean', ...required ? { required: true } : {} })), + fc.record({ required: fc.boolean() }).map(({ required }): ParameterPropertySpec => ({ type: 'string', ...required ? { required: true } : {} })), + fc.record({ required: fc.boolean() }).map(({ required }): ParameterPropertySpec => ({ type: 'number', ...required ? { required: true } : {} })), + fc.record({ required: fc.boolean() }).map(({ required }): ParameterPropertySpec => ({ type: 'integer', ...required ? { required: true } : {} })), + fc.record({ required: fc.boolean() }).map(({ required }): ParameterPropertySpec => ({ type: 'boolean', ...required ? { required: true } : {} })), + fc.record({ required: fc.boolean() }).map(({ required }): ParameterPropertySpec => ({ type: 'null', ...required ? { required: true } : {} })), + fc.record({ required: fc.boolean() }).map(({ required }): ParameterPropertySpec => ({ type: 'json', ...required ? { required: true } : {} })), fc.record({ values: fc.uniqueArray(fc.string({ minLength: 1 }), { minLength: 1, maxLength: 3 }), required: fc.boolean() }) - .map(({ values, required }): SchemaProp => ({ type: 'string', enum: values, ...required ? { required: true } : {} })), + .map(({ values, required }): ParameterPropertySpec => ({ type: 'string', enum: values, ...required ? { required: true } : {} })), + fc.record({ value: fc.string(), required: fc.boolean() }) + .map(({ value, required }): ParameterPropertySpec => ({ type: 'string', const: value, ...required ? { required: true } : {} })), + fc.record({ required: fc.boolean() }) + .map(({ required }): ParameterPropertySpec => ({ + oneOf: [{ type: 'string' }, { type: 'null' }], + ...required ? { required: true } : {}, + })), ) } /** A prop arbitrary up to `depth` levels of nesting (objects and arrays). */ -function propArb(depth: number): fc.Arbitrary<SchemaProp> { +function propArb(depth: number): fc.Arbitrary<ParameterPropertySpec> { if (depth <= 0) return leafPropArb() return fc.oneof( { weight: 3, arbitrary: leafPropArb() }, { weight: 1, - arbitrary: fc.record({ properties: specArb(depth - 1), required: fc.boolean() }) - .map(({ properties, required }): SchemaProp => ({ type: 'object', properties, ...required ? { required: true } : {} })), + arbitrary: fc.record({ properties: specArb(depth - 1), required: fc.boolean(), additionalProperties: fc.boolean() }) + .map(({ properties, required, additionalProperties }): ParameterPropertySpec => ({ + type: 'object', + additionalProperties, + properties, + ...required ? { required: true } : {}, + })), }, { weight: 1, arbitrary: fc.record({ items: propArb(depth - 1), required: fc.boolean() }) - .map(({ items, required }): SchemaProp => ({ type: 'array', items, ...required ? { required: true } : {} })), + .map(({ items, required }): ParameterPropertySpec => ({ + type: 'array', + items: asValueSchema(items), + ...required ? { required: true } : {}, + })), }, ) } -function specArb(depth: number): fc.Arbitrary<SchemaSpec> { +function specArb(depth: number): fc.Arbitrary<ParameterSchemaSpec> { return fc.dictionary(fc.string({ minLength: 1, maxLength: 6 }), propArb(depth), { maxKeys: 4 }) } /** Generate a value that satisfies a prop (used to build valid args). */ -function valueForProp(prop: SchemaProp): fc.Arbitrary<unknown> { +function valueForProp(prop: ParameterPropertySpec): fc.Arbitrary<unknown> { + if ('oneOf' in prop) return fc.oneof(...prop.oneOf.map(valueForProp)) + if ('const' in prop) return fc.constant(prop.const) switch (prop.type) { case 'string': return prop.enum ? fc.constantFrom(...prop.enum) : fc.string() - case 'number': return fc.double({ noNaN: true, noDefaultInfinity: true }) + case 'number': return fc.double({ noNaN: true, noDefaultInfinity: true }).filter(value => !Object.is(value, -0)) + case 'integer': return fc.integer() case 'boolean': return fc.boolean() + case 'null': return fc.constant(null) case 'object': return prop.properties ? validArgsForSpec(prop.properties) : fc.constant({}) case 'array': return prop.items ? fc.array(valueForProp(prop.items), { maxLength: 3 }) : fc.constant([]) + case 'json': return fc.jsonValue() } } /** Generate args satisfying every required key of a spec (optionals included randomly). */ -function validArgsForSpec(spec: SchemaSpec): fc.Arbitrary<Record<string, unknown>> { +function validArgsForSpec(spec: ParameterSchemaSpec): fc.Arbitrary<Record<string, unknown>> { const entries = Object.entries(spec) return fc.tuple(...entries.map(([key, prop]) => fc.tuple( @@ -76,29 +106,29 @@ function validArgsForSpec(spec: SchemaSpec): fc.Arbitrary<Record<string, unknown } /** Collect the `required: true` keys at the top level of a spec. */ -function requiredKeys(spec: SchemaSpec): string[] { +function requiredKeys(spec: ParameterSchemaSpec): string[] { return Object.entries(spec).filter(([, p]) => p.required === true).map(([k]) => k) } describe('schema DSL properties', () => { it('JSON Schema `required` equals the required:true keys at every level', () => { fc.assert(fc.property(specArb(2), (spec) => { - const checkLevel = (s: SchemaSpec, json: { required?: string[]; properties: Record<string, unknown> }) => { + const checkLevel = (s: ParameterSchemaSpec, json: { required?: string[]; properties: Record<string, unknown> }) => { expect(new Set(json.required ?? [])).toEqual(new Set(requiredKeys(s))) for (const [key, prop] of Object.entries(s)) { const propJson = json.properties[key] as Record<string, unknown> - if (prop.type === 'object' && prop.properties) { + if ('type' in prop && prop.type === 'object' && prop.properties) { checkLevel(prop.properties, propJson as { required?: string[]; properties: Record<string, unknown> }) } } } - checkLevel(spec, schemaSpecToJsonSchema(spec)) + checkLevel(spec, parameterSchemaSpecToJsonSchema(spec)) })) }) it('conversion is total (never throws) for any spec', () => { fc.assert(fc.property(specArb(3), (spec) => { - expect(() => schemaSpecToJsonSchema(spec)).not.toThrow() + expect(() => parameterSchemaSpecToJsonSchema(spec)).not.toThrow() })) }) diff --git a/packages/core/tools/tests/schema.spec.ts b/packages/core/tools/tests/schema.spec.ts new file mode 100644 index 0000000000..5bbd5b8b6d --- /dev/null +++ b/packages/core/tools/tests/schema.spec.ts @@ -0,0 +1,138 @@ +import { describe, expect, expectTypeOf, it } from 'vitest' +import { + JsonSchemaError, + parameterSchemaSpecToJsonSchema, + valueSchemaSpecToJsonSchema, + type InferArgs, + type InferValue, + type JsonValue, + type ParameterSchemaSpec, + type ValueSchemaSpec, +} from '../src/index.ts' + +describe('the unified author schema DSL', () => { + it('compiles every value root and the author-only json node', () => { + expect(valueSchemaSpecToJsonSchema({ type: 'string', enum: ['a', 'b'], const: 'a' })) + .toEqual({ type: 'string', enum: ['a', 'b'], const: 'a' }) + expect(valueSchemaSpecToJsonSchema({ type: 'number' })).toEqual({ type: 'number' }) + expect(valueSchemaSpecToJsonSchema({ type: 'integer' })).toEqual({ type: 'integer' }) + expect(valueSchemaSpecToJsonSchema({ type: 'boolean' })).toEqual({ type: 'boolean' }) + expect(valueSchemaSpecToJsonSchema({ type: 'null' })).toEqual({ type: 'null' }) + expect(valueSchemaSpecToJsonSchema({ type: 'array', items: { type: 'json' } })) + .toEqual({ type: 'array', items: {} }) + expect(valueSchemaSpecToJsonSchema({ type: 'object', additionalProperties: false, properties: {} })) + .toEqual({ type: 'object', additionalProperties: false, properties: {} }) + expect(valueSchemaSpecToJsonSchema({ + type: 'json', + description: 'anything', + title: 'Any JSON', + default: null, + examples: [{ nested: true }], + })).toEqual({ description: 'anything', title: 'Any JSON', default: null, examples: [{ nested: true }] }) + expect(valueSchemaSpecToJsonSchema({ oneOf: [{ type: 'string' }, { type: 'null' }] })) + .toEqual({ oneOf: [{ type: 'string' }, { type: 'null' }] }) + }) + + it('keeps the implicit parameter root open while preserving explicit object openness', () => { + expect(parameterSchemaSpecToJsonSchema({ + closed: { + type: 'object', + additionalProperties: false, + required: true, + properties: { id: { type: 'integer', required: true } }, + }, + open: { type: 'object', additionalProperties: true }, + })).toEqual({ + type: 'object', + properties: { + closed: { + type: 'object', + additionalProperties: false, + properties: { id: { type: 'integer' } }, + required: ['id'], + }, + open: { type: 'object', additionalProperties: true }, + }, + required: ['closed'], + }) + }) + + it('rejects runtime-forged author forms rather than compiling them lossily', () => { + for (const schema of [ + { type: 'object' }, + { oneOf: [{ type: 'string' }] }, + { type: 'number', enum: ['1'] }, + { type: 'integer', const: 1.5 }, + { type: 'json', default: undefined }, + { type: 'array', items: { type: 'string', required: true } }, + { type: 'array', items: 42 }, + { type: 'string', extra: true }, + { type: 'string', oneOf: [{ type: 'string' }, { type: 'null' }] }, + { oneOf: 'not-an-array' }, + { type: 'string', enum: 'a' }, + null, + ]) { + expect(() => valueSchemaSpecToJsonSchema(schema as ValueSchemaSpec), JSON.stringify(schema)).toThrow(JsonSchemaError) + } + expect(() => parameterSchemaSpecToJsonSchema({ + value: { type: 'string', required: false }, + } as unknown as ParameterSchemaSpec)).toThrow(JsonSchemaError) + expect(() => parameterSchemaSpecToJsonSchema(null as unknown as ParameterSchemaSpec)).toThrow(JsonSchemaError) + expect(() => parameterSchemaSpecToJsonSchema({ bad: 42 } as unknown as ParameterSchemaSpec)).toThrow(JsonSchemaError) + }) + + it('rejects cyclic author schemas', () => { + const schema: Record<string, unknown> = { type: 'array' } + schema.items = schema + expect(() => valueSchemaSpecToJsonSchema(schema as unknown as ValueSchemaSpec)).toThrow(/circular/) + + const properties: Record<string, unknown> = {} + properties.self = { type: 'object', additionalProperties: true, properties } + expect(() => parameterSchemaSpecToJsonSchema(properties as ParameterSchemaSpec)).toThrow(/circular/) + }) + + it('infers scalar literals, arrays, objects, json, and exact-one unions', () => { + expectTypeOf<InferValue<{ type: 'string'; enum: readonly ['a', 'b'] }>>().toEqualTypeOf<'a' | 'b'>() + expectTypeOf<InferValue<{ type: 'number'; const: 1 }>>().toEqualTypeOf<1>() + expectTypeOf<InferValue<{ type: 'integer' }>>().toEqualTypeOf<number>() + expectTypeOf<InferValue<{ type: 'boolean'; enum: readonly [true] }>>().toEqualTypeOf<true>() + expectTypeOf<InferValue<{ type: 'null' }>>().toEqualTypeOf<null>() + expectTypeOf<InferValue<{ type: 'array'; items: { type: 'string' } }>>().toEqualTypeOf<string[]>() + expectTypeOf<InferValue<{ type: 'array' }>>().toEqualTypeOf<JsonValue[]>() + expectTypeOf<InferValue<{ type: 'json' }>>().toEqualTypeOf<JsonValue>() + expectTypeOf<InferValue<{ oneOf: readonly [{ type: 'string' }, { type: 'null' }] }>>() + .toEqualTypeOf<string | null>() + expectTypeOf<InferValue<{ + type: 'object' + additionalProperties: false + properties: { id: { type: 'integer'; required: true }; label: { type: 'string' } } + }>>().toEqualTypeOf<{ id: number; label?: string }>() + expectTypeOf<InferValue<{ + type: 'object' + additionalProperties: true + properties: { id: { type: 'integer'; required: true } } + }>>().toEqualTypeOf<{ id: number } & Record<string, JsonValue>>() + }) + + it('infers required and optional parameter keys', () => { + expectTypeOf<InferArgs<{ + path: { type: 'string'; required: true } + offset: { type: 'integer' } + data: { type: 'json' } + }>>().toEqualTypeOf<{ path: string; offset?: number; data?: JsonValue }>() + }) + + it('makes invalid author forms compile-time errors', () => { + const invalidObjects = { + // @ts-expect-error explicit object schemas require an openness decision + object: { type: 'object' } satisfies ValueSchemaSpec, + // @ts-expect-error oneOf requires at least two branches + oneOf: { oneOf: [{ type: 'string' }] } satisfies ValueSchemaSpec, + // @ts-expect-error scalar enum values must match the node type + enum: { type: 'number', enum: ['1'] } satisfies ValueSchemaSpec, + // @ts-expect-error parameter requiredness is true-or-absent + required: { value: { type: 'string', required: false } } satisfies ParameterSchemaSpec, + } + expect(Object.keys(invalidObjects)).toHaveLength(4) + }) +}) diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index 6c35f4f549..5ddac2cd31 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -5,8 +5,8 @@ import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import type { Agent } from '@deepseek-ai/dsh-agent' import ApprovalService, { type ApprovalOutcome, type ApprovalRequest } from '@deepseek-ai/dsh-user-approval' import ToolRegistry, { - defineTool, schemaSpecToJsonSchema, validateArgs, ToolArgsError, ToolNotFoundError, - type InferArgs, type SchemaSpec, type PreToolDecision, type PostToolDecision, + defineTool, JsonSchemaError, parameterSchemaSpecToJsonSchema, validateArgs, ToolArgsError, ToolNotFoundError, + type InferArgs, type JsonValue, type ParameterSchemaSpec, type PreToolDecision, type PostToolDecision, type ToolExecution, type ToolExecutionResult, } from '@deepseek-ai/dsh-tools' @@ -775,13 +775,13 @@ describe('ToolRegistry', () => { }) describe('defineTool / schema DSL', () => { - it('converts SchemaSpec to standard JSON Schema with required array', () => { + it('converts ParameterSchemaSpec to standard JSON Schema with required array', () => { const spec = { path: { type: 'string', required: true, description: 'Absolute path' }, offset: { type: 'number' }, limit: { type: 'number', description: 'Max lines' }, - } satisfies SchemaSpec - const jsonSchema = schemaSpecToJsonSchema(spec) + } satisfies ParameterSchemaSpec + const jsonSchema = parameterSchemaSpecToJsonSchema(spec) expect(jsonSchema).toEqual({ type: 'object', properties: { @@ -794,7 +794,7 @@ describe('defineTool / schema DSL', () => { }) it('handles empty spec (no properties, no required)', () => { - expect(schemaSpecToJsonSchema({})).toEqual({ + expect(parameterSchemaSpecToJsonSchema({})).toEqual({ type: 'object', properties: {}, }) @@ -804,19 +804,21 @@ describe('defineTool / schema DSL', () => { const spec = { config: { type: 'object', + additionalProperties: true, required: true, properties: { host: { type: 'string', required: true }, port: { type: 'number' }, }, }, - } satisfies SchemaSpec - const jsonSchema = schemaSpecToJsonSchema(spec) + } satisfies ParameterSchemaSpec + const jsonSchema = parameterSchemaSpecToJsonSchema(spec) expect(jsonSchema).toEqual({ type: 'object', properties: { config: { type: 'object', + additionalProperties: true, properties: { host: { type: 'string' }, port: { type: 'number' }, @@ -958,8 +960,8 @@ describe('schema DSL edge cases', () => { it('emits enum values in JSON Schema property', () => { const spec = { color: { type: 'string', enum: ['red', 'green', 'blue'], description: 'Color choice' }, - } satisfies SchemaSpec - const jsonSchema = schemaSpecToJsonSchema(spec) + } satisfies ParameterSchemaSpec + const jsonSchema = parameterSchemaSpecToJsonSchema(spec) expect(jsonSchema.properties['color']).toMatchObject({ type: 'string', enum: ['red', 'green', 'blue'], @@ -970,8 +972,8 @@ describe('schema DSL edge cases', () => { it('emits default value in JSON Schema property', () => { const spec = { limit: { type: 'number', default: 25 }, - } satisfies SchemaSpec - const jsonSchema = schemaSpecToJsonSchema(spec) + } satisfies ParameterSchemaSpec + const jsonSchema = parameterSchemaSpecToJsonSchema(spec) expect(jsonSchema.properties['limit']).toMatchObject({ type: 'number', default: 25, @@ -981,8 +983,8 @@ describe('schema DSL edge cases', () => { it('handles array items without nested properties (plain type array)', () => { const spec = { tags: { type: 'array', items: { type: 'string' } }, - } satisfies SchemaSpec - const jsonSchema = schemaSpecToJsonSchema(spec) + } satisfies ParameterSchemaSpec + const jsonSchema = parameterSchemaSpecToJsonSchema(spec) expect(jsonSchema.properties['tags']).toEqual({ type: 'array', items: { type: 'string' }, @@ -992,8 +994,8 @@ describe('schema DSL edge cases', () => { it('handles enum and default together in one property', () => { const spec = { level: { type: 'string', enum: ['low', 'high'], default: 'low' }, - } satisfies SchemaSpec - const jsonSchema = schemaSpecToJsonSchema(spec) + } satisfies ParameterSchemaSpec + const jsonSchema = parameterSchemaSpecToJsonSchema(spec) expect(jsonSchema.properties['level']).toMatchObject({ type: 'string', enum: ['low', 'high'], @@ -1004,8 +1006,8 @@ describe('schema DSL edge cases', () => { it('omits description, enum, default keys when not specified', () => { const spec = { bare: { type: 'string' }, - } satisfies SchemaSpec - const jsonSchema = schemaSpecToJsonSchema(spec) + } satisfies ParameterSchemaSpec + const jsonSchema = parameterSchemaSpecToJsonSchema(spec) const prop = jsonSchema.properties['bare'] as Record<string, unknown> expect(prop).toEqual({ type: 'string' }) expect('description' in prop).toBe(false) @@ -1016,8 +1018,8 @@ describe('schema DSL edge cases', () => { it('handles array with no items (items omitted)', () => { const spec = { raw: { type: 'array' }, - } satisfies SchemaSpec - const jsonSchema = schemaSpecToJsonSchema(spec) + } satisfies ParameterSchemaSpec + const jsonSchema = parameterSchemaSpecToJsonSchema(spec) expect(jsonSchema.properties['raw']).toEqual({ type: 'array', }) @@ -1027,13 +1029,14 @@ describe('schema DSL edge cases', () => { const spec = { config: { type: 'object', + additionalProperties: true, properties: { host: { type: 'string' }, port: { type: 'number' }, }, }, - } satisfies SchemaSpec - const jsonSchema = schemaSpecToJsonSchema(spec) + } satisfies ParameterSchemaSpec + const jsonSchema = parameterSchemaSpecToJsonSchema(spec) expect(jsonSchema.properties['config']).toMatchObject({ type: 'object', properties: { @@ -1064,6 +1067,7 @@ describe('schema DSL optional and nested contracts', () => { type: 'array' items: { type: 'object' + additionalProperties: true properties: { host: { type: 'string'; required: true } port: { type: 'number' } @@ -1073,7 +1077,7 @@ describe('schema DSL optional and nested contracts', () => { }> expectTypeOf<Args>().toEqualTypeOf<{ names: string[] - servers?: { host: string; port?: number }[] + servers?: ({ host: string; port?: number } & Record<string, JsonValue>)[] }>() }) @@ -1083,20 +1087,22 @@ describe('schema DSL optional and nested contracts', () => { type: 'array', items: { type: 'object', + additionalProperties: true, properties: { host: { type: 'string', required: true }, port: { type: 'number' }, }, }, }, - } satisfies SchemaSpec - expect(schemaSpecToJsonSchema(spec)).toEqual({ + } satisfies ParameterSchemaSpec + expect(parameterSchemaSpecToJsonSchema(spec)).toEqual({ type: 'object', properties: { servers: { type: 'array', items: { type: 'object', + additionalProperties: true, properties: { host: { type: 'string' }, port: { type: 'number' }, @@ -1178,7 +1184,7 @@ describe('validateArgs (the runtime-validation Agent Note, part 1)', () => { const spec = { path: { type: 'string', required: true }, limit: { type: 'number' }, - } satisfies SchemaSpec + } satisfies ParameterSchemaSpec expect(validateArgs(spec, { path: '/tmp' })).toEqual([]) expect(validateArgs(spec, { path: '/tmp', limit: 5 })).toEqual([]) // never throws regardless of shape @@ -1188,18 +1194,18 @@ describe('validateArgs (the runtime-validation Agent Note, part 1)', () => { }) it('flags a missing required key and a required key present as undefined', () => { - const spec = { path: { type: 'string', required: true } } satisfies SchemaSpec + const spec = { path: { type: 'string', required: true } } satisfies ParameterSchemaSpec expect(validateArgs(spec, {})).toEqual(['missing required property "path"']) expect(validateArgs(spec, { path: undefined })).toEqual(['missing required property "path"']) }) it('allows extra keys (no additionalProperties:false) and omitted optionals', () => { - const spec = { path: { type: 'string', required: true } } satisfies SchemaSpec + const spec = { path: { type: 'string', required: true } } satisfies ParameterSchemaSpec expect(validateArgs(spec, { path: '/tmp', extra: 1 })).toEqual([]) }) it('does not apply defaults (validation only)', () => { - const spec = { limit: { type: 'number', default: 25 } } satisfies SchemaSpec + const spec = { limit: { type: 'number', default: 25 } } satisfies ParameterSchemaSpec // absent optional is valid, and validation does not synthesize the default expect(validateArgs(spec, {})).toEqual([]) }) @@ -1209,39 +1215,41 @@ describe('validateArgs (the runtime-validation Agent Note, part 1)', () => { s: { type: 'string' }, n: { type: 'number' }, b: { type: 'boolean' }, - } satisfies SchemaSpec + } satisfies ParameterSchemaSpec expect(validateArgs(spec, { s: 1 })).toEqual(['"s" must be a string']) expect(validateArgs(spec, { n: 'x' })).toEqual(['"n" must be a number']) expect(validateArgs(spec, { b: 'x' })).toEqual(['"b" must be a boolean']) }) it('checks enum membership', () => { - const spec = { color: { type: 'string', enum: ['red', 'green'] } } satisfies SchemaSpec + const spec = { color: { type: 'string', enum: ['red', 'green'] } } satisfies ParameterSchemaSpec expect(validateArgs(spec, { color: 'red' })).toEqual([]) expect(validateArgs(spec, { color: 'blue' })).toEqual(['"color" must be one of ["red","green"]']) }) - it('checks enum uniformly with the converter (enum on a non-string prop)', () => { - // The converter emits `enum` regardless of type; the validator must agree. - // `enum` is string[], so a number value can never be a member. - const spec = { n: { type: 'number', enum: ['1', '2'] } } as unknown as SchemaSpec - expect(validateArgs(spec, { n: 1 })).toEqual(['"n" must be one of ["1","2"]']) + it('enforces type-correct scalar enum declarations', () => { + const spec = { n: { type: 'number', enum: [1, 2] } } satisfies ParameterSchemaSpec + expect(validateArgs(spec, { n: 1 })).toEqual([]) + expect(validateArgs(spec, { n: 3 })).toEqual(['"n" must be one of [1,2]']) + const invalid = { n: { type: 'number', enum: ['1', '2'] } } as unknown as ParameterSchemaSpec + expect(() => validateArgs(invalid, { n: 1 })).toThrow(JsonSchemaError) }) - it('rejects an unknown SchemaType at runtime (assertNever guard)', () => { - const spec = { x: { type: 'weird' } } as unknown as SchemaSpec - expect(() => validateArgs(spec, { x: 1 })).toThrow(/unreachable variant.*validateArgs/) + it('rejects an unknown schema type at the author boundary', () => { + const spec = { x: { type: 'weird' } } as unknown as ParameterSchemaSpec + expect(() => validateArgs(spec, { x: 1 })).toThrow(JsonSchemaError) }) it('recurses into nested objects (and an object without properties only type-checks)', () => { const spec = { config: { type: 'object', + additionalProperties: true, required: true, properties: { host: { type: 'string', required: true }, port: { type: 'number' } }, }, - bag: { type: 'object' }, - } satisfies SchemaSpec + bag: { type: 'object', additionalProperties: true }, + } satisfies ParameterSchemaSpec expect(validateArgs(spec, { config: { host: 'h' }, bag: { anything: true } })).toEqual([]) expect(validateArgs(spec, { config: { port: 9 }, bag: 5 })).toEqual([ 'missing required property "config.host"', @@ -1253,7 +1261,7 @@ describe('validateArgs (the runtime-validation Agent Note, part 1)', () => { const spec = { tags: { type: 'array', items: { type: 'string' } }, raw: { type: 'array' }, - } satisfies SchemaSpec + } satisfies ParameterSchemaSpec expect(validateArgs(spec, { tags: ['a', 'b'], raw: [1, {}, 'x'] })).toEqual([]) expect(validateArgs(spec, { tags: ['a', 2] })).toEqual(['"tags[1]" must be a string']) // a non-array value for an array-typed prop @@ -1264,9 +1272,9 @@ describe('validateArgs (the runtime-validation Agent Note, part 1)', () => { const spec = { servers: { type: 'array', - items: { type: 'object', properties: { host: { type: 'string', required: true } } }, + items: { type: 'object', additionalProperties: true, properties: { host: { type: 'string', required: true } } }, }, - } satisfies SchemaSpec + } satisfies ParameterSchemaSpec expect(validateArgs(spec, { servers: [{ host: 'a' }, {}] })).toEqual([ 'missing required property "servers[1].host"', ]) diff --git a/packages/core/tools/tests/ts-types.spec.ts b/packages/core/tools/tests/ts-types.spec.ts index df30a58238..14b14f7ecd 100644 --- a/packages/core/tools/tests/ts-types.spec.ts +++ b/packages/core/tools/tests/ts-types.spec.ts @@ -1,20 +1,37 @@ import { describe, expect, it } from 'vitest' import { jsonSchemaToTs, renderToolsSdk } from '@deepseek-ai/dsh-tools/src/ts-types.ts' -import { schemaSpecToJsonSchema } from '@deepseek-ai/dsh-tools' +import { parameterSchemaSpecToJsonSchema } from '@deepseek-ai/dsh-tools' import type { ToolSchema } from '@deepseek-ai/dsh-llm' describe('jsonSchemaToTs', () => { - it('maps the defineTool DSL subset', () => { + it('maps every unified schema construct', () => { const cases: [unknown, string][] = [ [{ type: 'string' }, 'string'], [{ type: 'number' }, 'number'], + [{ type: 'integer' }, 'number'], [{ type: 'boolean' }, 'boolean'], + [{ type: 'null' }, 'null'], [{ type: 'string', enum: ['a', 'b'] }, '"a" | "b"'], + [{ type: 'number', enum: [1, 2] }, '1 | 2'], + [{ type: 'integer', const: 2 }, '2'], + [{ type: 'boolean', const: true }, 'true'], + [{ type: 'null', const: null }, 'null'], + [{ type: 'string', enum: ['a', 'b'], const: 'a' }, '"a"'], + [{ oneOf: [{ type: 'string' }, { type: 'null' }] }, 'string | null'], [{ type: 'array', items: { type: 'number' } }, 'number[]'], [{ type: 'array', items: { type: 'string', enum: ['x', 'y'] } }, '("x" | "y")[]'], - [{ type: 'array' }, 'unknown[]'], - [{ type: 'object' }, 'Record<string, unknown>'], - [{ type: 'object', properties: {} }, 'Record<string, unknown>'], + [{ type: 'array' }, 'JsonValue[]'], + [{ type: 'object' }, 'Record<string, JsonValue>'], + [{ type: 'object', additionalProperties: false }, 'Record<string, never>'], + [{ type: 'object', properties: {} }, 'Record<string, JsonValue>'], + [{ type: 'object', properties: {}, additionalProperties: false }, 'Record<string, never>'], + [{ + type: 'object', + additionalProperties: false, + properties: { id: { type: 'integer' }, label: { type: 'string' } }, + required: ['id'], + }, ['{', ' id: number;', ' label?: string;', '}'].join('\n')], + [{}, 'JsonValue'], ] for (const [schema, expected] of cases) { expect(jsonSchemaToTs(schema), JSON.stringify(schema)).toBe(expected) @@ -22,11 +39,12 @@ describe('jsonSchemaToTs', () => { }) it('renders objects with required/optional keys, nested shapes, and per-property docs', () => { - const schema = schemaSpecToJsonSchema({ + const schema = parameterSchemaSpecToJsonSchema({ path: { type: 'string', required: true, description: 'Absolute file path' }, limit: { type: 'number' }, opts: { type: 'object', + additionalProperties: true, properties: { deep: { type: 'boolean', required: true } }, }, }) @@ -37,8 +55,8 @@ describe('jsonSchemaToTs', () => { ' limit?: number;', ' opts?: {', ' deep: boolean;', - ' };', - '}', + ' } & Record<string, JsonValue>;', + '} & Record<string, JsonValue>', ].join('\n')) }) @@ -48,9 +66,6 @@ describe('jsonSchemaToTs', () => { null, 42, 'string-schema', - {}, - { type: 'integer' }, - { type: 'null' }, { oneOf: [{ type: 'string' }] }, { $ref: '#/defs/x' }, { type: 'object', properties: 7 }, @@ -61,18 +76,13 @@ describe('jsonSchemaToTs', () => { for (const schema of cases) { expect(() => jsonSchemaToTs(schema), JSON.stringify(schema)).not.toThrow() } - expect(jsonSchemaToTs({ type: 'integer' })).toBe('unknown') expect(jsonSchemaToTs({ oneOf: [] })).toBe('unknown') - expect(jsonSchemaToTs({ type: 'object', properties: 7 })).toBe('Record<string, unknown>') - expect(jsonSchemaToTs({ type: 'object', properties: { bad: { $ref: 'x' } }, required: ['bad'] })).toContain('bad: unknown;') - // A non-string-only enum degrades to plain string; an empty one too. - expect(jsonSchemaToTs({ type: 'string', enum: [1, 2] })).toBe('string') - expect(jsonSchemaToTs({ type: 'string', enum: [] })).toBe('string') - // A hostile required list only accepts string members. - expect(jsonSchemaToTs({ type: 'object', properties: { a: { type: 'string' } }, required: [7] })).toContain('a?: string;') - // A property VALUE that is not an object degrades to unknown (and can - // carry no description). - expect(jsonSchemaToTs({ type: 'object', properties: { weird: 42 } })).toContain('weird?: unknown;') + expect(jsonSchemaToTs({ type: 'object', properties: 7 })).toBe('unknown') + expect(jsonSchemaToTs({ type: 'object', properties: { bad: { $ref: 'x' } }, required: ['bad'] })).toBe('unknown') + expect(jsonSchemaToTs({ type: 'string', enum: [1, 2] })).toBe('unknown') + expect(jsonSchemaToTs({ type: 'string', enum: [] })).toBe('unknown') + expect(jsonSchemaToTs({ type: 'object', properties: { a: { type: 'string' } }, required: [7] })).toBe('unknown') + expect(jsonSchemaToTs({ type: 'object', properties: { weird: 42 } })).toBe('unknown') }) it('escapes a comment-closer inside a description so the generated JSDoc cannot end early', () => { @@ -89,17 +99,18 @@ describe('renderToolsSdk', () => { const bash: ToolSchema = { name: 'bash', description: 'Run a shell command.', - parameters: schemaSpecToJsonSchema({ command: { type: 'string', required: true } }) as unknown as Record<string, unknown>, + parameters: parameterSchemaSpecToJsonSchema({ command: { type: 'string', required: true } }) as unknown as Record<string, unknown>, } const exotic: ToolSchema = { name: 'my-mcp.tool', description: 'Exotic name.', - parameters: schemaSpecToJsonSchema({}) as unknown as Record<string, unknown>, + parameters: parameterSchemaSpecToJsonSchema({}) as unknown as Record<string, unknown>, } it('declares every tool in lexicographic order with quoted keys for exotic names', () => { const text = renderToolsSdk([exotic, bash]) expect(text).toContain('declare const tools: {') + expect(text).toContain('type JsonValue = null | boolean | number | string') expect(text.indexOf('bash(args:')).toBeGreaterThan(0) expect(text).toContain('"my-mcp.tool"(args:') expect(text.indexOf('bash(args:')).toBeLessThan(text.indexOf('"my-mcp.tool"(args:')) diff --git a/packages/subagent/subagent-inprocess/src/structured.ts b/packages/subagent/subagent-inprocess/src/structured.ts index 09aa2d24b7..9d2cce1570 100644 --- a/packages/subagent/subagent-inprocess/src/structured.ts +++ b/packages/subagent/subagent-inprocess/src/structured.ts @@ -14,7 +14,7 @@ import type { Context } from 'cordis' import type { ContinuationStop } from '@deepseek-ai/dsh-agent' import type { ContentBlock, ToolSchema } from '@deepseek-ai/dsh-llm' import type { ToolExecution } from '@deepseek-ai/dsh-tools' -import { ToolArgsError, validateStructuredValue, type StructuredOutputSchema } from '@deepseek-ai/dsh-tools' +import { ToolArgsError, validateJsonSchemaValue, type ObjectJsonSchema } from '@deepseek-ai/dsh-tools' /** The model-facing tool name a structured child must call to finish. */ export const STRUCTURED_OUTPUT_TOOL = 'structured_output' @@ -44,10 +44,10 @@ export interface StructuredAttachment { * its creation window. Child disposal removes every registration. * @param childCtx - the child agent's scope context (`setup`'s argument). * @param schema - the trusted, already-asserted schema subset to enforce (see - * `assertSupportedOutputSchema` in dsh-tools). + * `assertObjectJsonSchema` in dsh-tools). * @returns the attachment handle (read `captured()` after the child settles). */ -export function attachStructuredRuntime(childCtx: Context, schema: StructuredOutputSchema): StructuredAttachment { +export function attachStructuredRuntime(childCtx: Context, schema: ObjectJsonSchema): StructuredAttachment { /** * Validated values staged by the capture tool body, awaiting THEIR OWN * authoritative `tools/result` notification. The execution object's identity @@ -75,7 +75,7 @@ export function attachStructuredRuntime(childCtx: Context, schema: StructuredOut childCtx.tools.register({ ...schemaEntry, execute(args: unknown, exec: ToolExecution): Promise<ContentBlock[]> { - const violations = validateStructuredValue(schema, args) + const violations = validateJsonSchemaValue(schema, args) // ToolArgsError → isError result with INVALID_ARGS: the model retries // within the same turn, exactly like a schema-validated defineTool call. if (violations.length > 0) throw new ToolArgsError(violations) diff --git a/packages/subagent/subagent-inprocess/tests/structured.spec.ts b/packages/subagent/subagent-inprocess/tests/structured.spec.ts index e50457bcb4..56a78a225f 100644 --- a/packages/subagent/subagent-inprocess/tests/structured.spec.ts +++ b/packages/subagent/subagent-inprocess/tests/structured.spec.ts @@ -7,7 +7,7 @@ import AgentLoop from '@deepseek-ai/dsh-agent-loop' import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit' import * as Invariants from '@deepseek-ai/dsh-invariants' import SubagentService, { type SubagentStartRequest } from '@deepseek-ai/dsh-subagent' -import type { Config as ToolConfig, StructuredOutputSchema } from '@deepseek-ai/dsh-tools' +import type { Config as ToolConfig, ObjectJsonSchema } from '@deepseek-ai/dsh-tools' import { RUN_CODE_NAME } from '@deepseek-ai/dsh-tools' import { MockAdapter, textResponse, toolCallResponse } from '../../../core/agent-loop/tests/mock-adapter.ts' import { startInProcessRun } from '../src/index.ts' @@ -27,7 +27,7 @@ interface SetupOptions { codeRun?: (request: CodeRunRequestLike) => Promise<{ logs: never[]; value?: unknown }> } -const SCHEMA: StructuredOutputSchema = { +const SCHEMA: ObjectJsonSchema = { type: 'object', properties: { answer: { type: 'number' }, note: { type: 'string' } }, required: ['answer'], @@ -320,17 +320,17 @@ describe('in-process structured output', () => { it('rejects a schema outside the subset loud, before any child exists', async () => { const { ctx, parent } = await setup([]) await expect(ctx.subagents.start('spawn', structuredRequest(parent, { - outputSchema: { type: 'object', oneOf: [] } as unknown as StructuredOutputSchema, - }))).rejects.toThrow(/unsupported output schema/) + outputSchema: { type: 'object', oneOf: [] } as unknown as ObjectJsonSchema, + }))).rejects.toThrow(/unsupported JSON schema/) expect(ctx.agents.get(SessionId('parent'))).toBeDefined() }) - it('a schema carrying non-JSON values fails as OutputSchemaError at the validation boundary', async () => { + it('a schema carrying non-JSON values fails as JsonSchemaError at the validation boundary', async () => { const { ctx, parent } = await setup([]) // Semantic assertion runs before provider startup. await expect(ctx.subagents.start('spawn', structuredRequest(parent, { - outputSchema: { type: 'object', default: () => {} } as unknown as StructuredOutputSchema, - }))).rejects.toThrow(/unsupported output schema.*annotation must be JSON data/) + outputSchema: { type: 'object', default: () => {} } as unknown as ObjectJsonSchema, + }))).rejects.toThrow(/unsupported JSON schema.*annotation must be lossless JSON data/) }) it('a post-execute BLOCK on the capture call denies the capture: log and result agree on failure', async () => { @@ -547,7 +547,7 @@ describe('in-process structured output', () => { }) it('two concurrent structured children each see their OWN schema', async () => { - const otherSchema: StructuredOutputSchema = { + const otherSchema: ObjectJsonSchema = { type: 'object', properties: { verdict: { type: 'string', enum: ['real', 'bogus'] } }, required: ['verdict'], diff --git a/packages/subagent/subagent/src/index.ts b/packages/subagent/subagent/src/index.ts index 00655f1f51..95e9300b0b 100644 --- a/packages/subagent/subagent/src/index.ts +++ b/packages/subagent/subagent/src/index.ts @@ -32,7 +32,7 @@ import { randomUUID } from 'node:crypto' import { Context, Service } from 'cordis' import { scopeTarget } from '@deepseek-ai/dsh-scope' import type { Scoped } from '@deepseek-ai/dsh-scope' -import { assertSupportedOutputSchema } from '@deepseek-ai/dsh-tools' +import { assertObjectJsonSchema } from '@deepseek-ai/dsh-tools' import { HarnessError } from '@deepseek-ai/dsh-llm' import type { ContentBlock } from '@deepseek-ai/dsh-llm' import type { Agent } from '@deepseek-ai/dsh-agent' @@ -242,7 +242,7 @@ export class SubagentService extends Service { } this.assertCapabilities(provider, request) assertSubagentMaxDepth(request.maxDepth) - if (request.outputSchema !== undefined) assertSupportedOutputSchema(request.outputSchema) + if (request.outputSchema !== undefined) assertObjectJsonSchema(request.outputSchema) const parent = request.parent const run = await provider.start(request) diff --git a/packages/subagent/subagent/src/types.ts b/packages/subagent/subagent/src/types.ts index 1b1645d89b..7448f087d4 100644 --- a/packages/subagent/subagent/src/types.ts +++ b/packages/subagent/subagent/src/types.ts @@ -10,7 +10,7 @@ import type { Agent, AgentOptions } from '@deepseek-ai/dsh-agent' import type { Branded } from '@deepseek-ai/dsh-brand' import type { ContentBlock } from '@deepseek-ai/dsh-llm' import type { SessionId } from '@deepseek-ai/dsh-session' -import type { StructuredOutputSchema, ToolRestriction } from '@deepseek-ai/dsh-tools' +import type { ObjectJsonSchema, ToolRestriction } from '@deepseek-ai/dsh-tools' /** Identifies one accepted subagent run across its lifecycle event pair. */ export type SubagentRunId = Branded<'SubagentRunId'> @@ -70,11 +70,11 @@ export interface SubagentStartRequest { /** Per-child agent options (model and plugin-defined extension fields). */ readonly agentOptions?: AgentOptions /** - * Object-rooted JSON Schema within `assertSupportedOutputSchema`'s enforced subset. Start rejects + * Object-rooted JSON Schema within `assertObjectJsonSchema`'s enforced subset. Start rejects * unsupported schemas or providers without the capability. Data must be plain host-realm JSON; * a successful child returns the matching value as {@link SubagentResult.structured}. */ - readonly outputSchema?: StructuredOutputSchema + readonly outputSchema?: ObjectJsonSchema /** * Optional absolute delegation-depth cap for the child being started: its * computed depth must be less than or equal to this non-negative safe diff --git a/packages/tasks/tool-tasks/src/index.ts b/packages/tasks/tool-tasks/src/index.ts index 2d556cada9..3f8256be15 100644 --- a/packages/tasks/tool-tasks/src/index.ts +++ b/packages/tasks/tool-tasks/src/index.ts @@ -41,7 +41,7 @@ export function statusLine(snapshot: TaskSnapshot): string { : `[status: ${snapshot.status}]` } -/** Validate the non-empty constraint that SchemaSpec cannot express. */ +/** Validate the non-empty constraint that ParameterSchemaSpec cannot express. */ function validateTaskId(value: string): TaskId { if (value.length === 0) { throw new Error(`invalid task_id: expected a non-empty string, got ${JSON.stringify(value)}`) diff --git a/packages/todo/tool-todo/src/index.ts b/packages/todo/tool-todo/src/index.ts index 039d2085f7..919e53f7bb 100644 --- a/packages/todo/tool-todo/src/index.ts +++ b/packages/todo/tool-todo/src/index.ts @@ -28,7 +28,7 @@ const DESCRIPTION = + '(not started), `in_progress` (being worked on now), `completed` (finished).' /** - * Validate the value constraints the SchemaSpec can't express and build the canonical {@link + * Validate the value constraints the ParameterSchemaSpec can't express and build the canonical {@link * TodoItem}[]: trimmed non-empty unique content and at most one in-progress item. The registry * has already enforced the status enum; the cast below records that guarantee. */ @@ -67,6 +67,7 @@ export function apply(ctx: Context): void { description: 'The COMPLETE task list, replacing any previous list.', items: { type: 'object', + additionalProperties: true, properties: { content: { type: 'string', required: true, description: 'What the task is — a short imperative line.' }, status: { diff --git a/packages/ui/tool-ask-user/src/index.ts b/packages/ui/tool-ask-user/src/index.ts index 2591b28ddd..47cb6e8d22 100644 --- a/packages/ui/tool-ask-user/src/index.ts +++ b/packages/ui/tool-ask-user/src/index.ts @@ -27,6 +27,7 @@ export function apply(ctx: Context): void { description: 'Questions to ask the user before continuing.', items: { type: 'object', + additionalProperties: true, properties: { id: { type: 'string', required: true, description: 'Stable id for this question; echoed in the answer.' }, question: { type: 'string', required: true, description: 'The specific question to ask the user.' }, @@ -39,6 +40,7 @@ export function apply(ctx: Context): void { description: 'Optional choices to show the user. If you recommend one, put it first and append "(Recommended)" to that label.', items: { type: 'object', + additionalProperties: true, properties: { label: { type: 'string', required: true, description: 'Short user-facing option label.' }, description: { type: 'string', description: 'One sentence explaining the tradeoff or impact.' }, diff --git a/packages/workflow/tool-workflow/src/index.ts b/packages/workflow/tool-workflow/src/index.ts index 2a8ef96682..71121730e5 100644 --- a/packages/workflow/tool-workflow/src/index.ts +++ b/packages/workflow/tool-workflow/src/index.ts @@ -131,6 +131,7 @@ export function apply(ctx: Context, config: Config): void { }, meta: { type: 'object', + additionalProperties: true, required: true, description: 'The workflow identity block (plain JSON — never code).', properties: { @@ -142,6 +143,7 @@ export function apply(ctx: Context, config: Config): void { description: 'Optional phase declarations matched by phase() calls.', items: { type: 'object', + additionalProperties: true, properties: { title: { type: 'string', required: true, description: 'The phase title phase() calls match by exact string.' }, detail: { type: 'string', description: 'Optional one-line description of the phase.' }, @@ -154,6 +156,7 @@ export function apply(ctx: Context, config: Config): void { }, args: { type: 'object', + additionalProperties: true, description: 'Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}).', }, }, diff --git a/packages/workflow/workflow-workerthread/src/runtime.ts b/packages/workflow/workflow-workerthread/src/runtime.ts index 535917fc42..38194f4c03 100644 --- a/packages/workflow/workflow-workerthread/src/runtime.ts +++ b/packages/workflow/workflow-workerthread/src/runtime.ts @@ -15,8 +15,8 @@ import * as vm from 'node:vm' import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { SessionId } from '@deepseek-ai/dsh-session' -import { assertSupportedOutputSchema, OutputSchemaError } from '@deepseek-ai/dsh-tools' -import type { StructuredOutputSchema } from '@deepseek-ai/dsh-tools' +import { assertObjectJsonSchema, JsonSchemaError } from '@deepseek-ai/dsh-tools' +import type { ObjectJsonSchema } from '@deepseek-ai/dsh-tools' import { isFatalWorkflowError, WorkflowError } from '@deepseek-ai/dsh-workflow' import type { WorkflowAgentEndInfo, @@ -350,7 +350,7 @@ export class WorkflowExecution { phase?: string provider?: string model?: string - schema?: StructuredOutputSchema + schema?: ObjectJsonSchema } { if (rawOpts === undefined) return {} let opts: unknown @@ -377,14 +377,14 @@ export class WorkflowExecution { throw new WorkflowError(`agent() option "${key}" must be a string`, 'INVALID_ARGUMENT') } } - let schema: StructuredOutputSchema | undefined + let schema: ObjectJsonSchema | undefined if (record.schema !== undefined) { try { - assertSupportedOutputSchema(record.schema) + assertObjectJsonSchema(record.schema) schema = record.schema } catch (error: unknown) { - /* v8 ignore next -- defensive rethrow arm: assertSupportedOutputSchema only throws OutputSchemaError */ - if (!(error instanceof OutputSchemaError)) throw error + /* v8 ignore next -- defensive rethrow arm: assertObjectJsonSchema only throws JsonSchemaError */ + if (!(error instanceof JsonSchemaError)) throw error throw new WorkflowError(`agent() schema is outside the supported subset — ${error.message}`, 'UNSUPPORTED_SCHEMA', { cause: error }) } } diff --git a/packages/workflow/workflow-workerthread/src/types.ts b/packages/workflow/workflow-workerthread/src/types.ts index 7e2bfff36c..9d7ddf6808 100644 --- a/packages/workflow/workflow-workerthread/src/types.ts +++ b/packages/workflow/workflow-workerthread/src/types.ts @@ -6,7 +6,7 @@ */ import type { ContentBlock } from '@deepseek-ai/dsh-llm' -import type { StructuredOutputSchema } from '@deepseek-ai/dsh-tools' +import type { ObjectJsonSchema } from '@deepseek-ai/dsh-tools' import type { WorkflowMeta } from '@deepseek-ai/dsh-workflow' /** @@ -41,7 +41,7 @@ export interface ChildStartRequest { /** The child's prompt text. */ prompt: string /** The structured-output schema, if the call passed one (already subset-checked). */ - schema?: StructuredOutputSchema + schema?: ObjectJsonSchema /** The per-child provider override, if the call passed one. */ provider?: string /** The per-child model override, if the call passed one. */ diff --git a/scripts/type-equiv.manifest.json b/scripts/type-equiv.manifest.json index 5cb84266da..ed53ac469c 100644 --- a/scripts/type-equiv.manifest.json +++ b/scripts/type-equiv.manifest.json @@ -91,8 +91,10 @@ { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventTrace", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolDefinition", "source": "packages/core/tools/src/index.ts" }, - { "doc": "docs/core-data-structures/tools.md", "symbol": "SchemaProp", "source": "packages/core/tools/src/schema.ts" }, - { "doc": "docs/core-data-structures/tools.md", "symbol": "SchemaSpec", "source": "packages/core/tools/src/schema.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "ValueSchemaSpec", "source": "packages/core/tools/src/schema.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "ParameterPropertySpec", "source": "packages/core/tools/src/schema.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "ParameterSchemaSpec", "source": "packages/core/tools/src/schema.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "InferValue", "source": "packages/core/tools/src/schema.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "InferArgs", "source": "packages/core/tools/src/schema.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolExecutionToken", "source": "packages/core/tools/src/index.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolExecutionInput", "source": "packages/core/tools/src/index.ts" }, @@ -104,10 +106,10 @@ { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolExecutionResult", "source": "packages/core/tools/src/index.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "PreToolDecision", "source": "packages/core/tools/src/index.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "PostToolDecision", "source": "packages/core/tools/src/index.ts" }, - { "doc": "docs/core-data-structures/tools.md", "symbol": "StructuredScalar", "source": "packages/core/tools/src/json-schema.ts" }, - { "doc": "docs/core-data-structures/tools.md", "symbol": "StructuredSchemaType", "source": "packages/core/tools/src/json-schema.ts" }, - { "doc": "docs/core-data-structures/tools.md", "symbol": "StructuredSchemaNode", "source": "packages/core/tools/src/json-schema.ts" }, - { "doc": "docs/core-data-structures/tools.md", "symbol": "StructuredOutputSchema", "source": "packages/core/tools/src/json-schema.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "JsonSchemaScalar", "source": "packages/core/tools/src/json-schema.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "JsonSchemaType", "source": "packages/core/tools/src/json-schema.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "JsonSchemaNode", "source": "packages/core/tools/src/json-schema.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "ObjectJsonSchema", "source": "packages/core/tools/src/json-schema.ts" }, { "doc": "docs/core-data-structures/user-interaction.md", "symbol": "AskUserQuestionOption", "source": "packages/ui/user-interaction/src/index.ts" }, { "doc": "docs/core-data-structures/user-interaction.md", "symbol": "AskUserQuestionItem", "source": "packages/ui/user-interaction/src/index.ts" }, From 66c36e7325b1a496557a20e9c71c75e01a113692 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 03:08:35 +0800 Subject: [PATCH 023/368] feat: add canonical typed tool outputs --- .../2026-06-17-filesystem-capability-seam.md | 2 +- ...26-07-02-result-time-applied-hunk-diffs.md | 16 +- ...026-07-06-tool-result-retention-library.md | 2 +- .../2026-07-07-tool-call-timeout-policy.md | 5 +- .../2026-07-08-tool-output-spill-files.md | 8 +- ...0-canonical-tool-output-contract.i18n.yaml | 6 + ...26-07-20-canonical-tool-output-contract.md | 76 +++ ...07-20-canonical-tool-output-contract.zh.md | 76 +++ .../2026-06-17-filesystem-tool-schemas.md | 2 +- .../feature/2026-06-30-interception-seams.md | 6 +- ...6-07-08-self-referential-cordis-toolset.md | 2 +- docs/architecture.md | 5 +- docs/config-catalog.md | 14 +- docs/cookbook/adding-a-tool.i18n.yaml | 4 +- docs/cookbook/adding-a-tool.md | 21 +- docs/cookbook/adding-a-tool.zh.md | 21 +- docs/cordis-catalog/events.md | 10 +- docs/cordis-catalog/services.md | 2 +- docs/core-data-structures/session.md | 25 +- docs/core-data-structures/tools.md | 123 +++-- docs/event-producer-consumer.md | 10 +- docs/persistence-catalog.md | 35 +- docs/tool-catalog.md | 2 +- docs/user/develop/basic/index.i18n.yaml | 4 +- docs/user/develop/basic/index.md | 6 +- docs/user/develop/basic/index.zh.md | 6 +- docs/user/develop/basic/tool.i18n.yaml | 4 +- docs/user/develop/basic/tool.md | 57 ++- docs/user/develop/basic/tool.zh.md | 57 ++- docs/user/develop/practice/index.i18n.yaml | 4 +- docs/user/develop/practice/index.md | 6 +- docs/user/develop/practice/index.zh.md | 6 +- .../system-prompt.expected.md | 2 +- .../tool-schemas.expected.json | 2 +- .../snapshots/cancel-tool-calls/session.jsonl | 4 +- .../cordis-inspect-jsdoc/session.jsonl | 2 +- .../stdout.expected.jsonl | 2 +- .../escalation-rejected/session.jsonl | 2 +- .../fs-escalation-approved/session.jsonl | 2 +- .../snapshots/fs-policy-reject/session.jsonl | 2 +- .../tests/snapshots/fs-write/session.jsonl | 2 +- .../hook-cc-posttool-block/session.jsonl | 2 +- .../hook-cc-pretool-ask/session.jsonl | 2 +- .../hook-cc-pretool-deny/session.jsonl | 2 +- .../hook-codex-posttool-block/session.jsonl | 2 +- .../hook-codex-pretool-block/session.jsonl | 2 +- .../session.2.jsonl | 2 +- packages/bash/tool-bash/README.md | 2 + packages/bash/tool-bash/src/index.ts | 97 +++- packages/bash/tool-bash/tests/tools.spec.ts | 36 +- .../tests/compact-loop-repro.spec.ts | 4 +- .../tests/tool-result-prune.spec.ts | 4 +- .../time-context/tests/time-context.spec.ts | 4 +- .../context/workspace-context/src/index.ts | 3 +- .../tests/workspace-context.spec.ts | 38 +- packages/cordis/tool-cordis/README.md | 2 + .../cordis/tool-cordis/src/api-catalog.ts | 28 +- .../cordis/tool-cordis/src/fiber-state.ts | 4 +- packages/cordis/tool-cordis/src/guard.ts | 84 ++-- packages/cordis/tool-cordis/src/index.ts | 67 ++- packages/cordis/tool-cordis/src/inspect.ts | 11 +- .../tool-cordis/tests/cross-mount.spec.ts | 3 +- packages/cordis/tool-cordis/tests/helpers.ts | 28 +- .../cordis/tool-cordis/tests/inspect.spec.ts | 2 + .../cordis/tool-cordis/tests/mount.spec.ts | 95 +++- .../tool-cordis/tests/sandbox-context.spec.ts | 8 +- .../tool-cordis/tests/unmount-hmr.spec.ts | 2 + packages/core/agent-loop/src/tool-calls.ts | 5 +- .../agent-loop/tests/agent-initiator.spec.ts | 10 +- packages/core/agent-loop/tests/cancel.spec.ts | 6 +- .../tests/contract-regressions.spec.ts | 30 +- .../agent-loop/tests/coverage-edges.spec.ts | 10 +- .../agent-loop/tests/interception.spec.ts | 16 +- packages/core/agent-loop/tests/loop.spec.ts | 48 +- .../agent-loop/tests/request-cache.e2e.ts | 4 +- .../tests/request-reconstruction.spec.ts | 4 +- .../agent-loop/tests/request-recovery.spec.ts | 8 +- .../agent-loop/tests/scope-lifecycle.spec.ts | 10 +- .../core/agent-loop/tests/tool-calls.spec.ts | 46 +- .../core/agent-loop/tests/tool-order.spec.ts | 4 +- .../core/agent-loop/tests/turn-stop.spec.ts | 4 +- packages/core/session/README.md | 2 + packages/core/session/src/repair.ts | 5 +- packages/core/session/src/types.ts | 25 +- packages/core/session/tests/repair.spec.ts | 2 +- packages/core/tools/README.md | 23 +- packages/core/tools/src/code-mode.ts | 38 +- packages/core/tools/src/index.ts | 252 +++++++--- packages/core/tools/src/schema.ts | 85 ++-- packages/core/tools/src/testing.ts | 42 ++ packages/core/tools/tests/code-mode.spec.ts | 28 +- .../core/tools/tests/execution-mode.spec.ts | 23 +- packages/core/tools/tests/scoped.spec.ts | 23 +- packages/core/tools/tests/tools.spec.ts | 441 ++++++++++++++++-- .../examples/acp-demo/tests/acp-agent.spec.ts | 3 +- .../agent-spine-demo/tests/agent-core.spec.ts | 3 +- .../examples/cli-demo/tests/cli-demo.spec.ts | 8 +- packages/examples/cli-demo/tests/cli.spec.ts | 6 +- packages/fs/tool-fs-search/README.md | 4 +- packages/fs/tool-fs-search/src/glob.ts | 54 ++- packages/fs/tool-fs-search/src/grep.ts | 91 +++- packages/fs/tool-fs-search/src/surface.ts | 27 ++ .../tool-fs-search/tests/integration.spec.ts | 10 +- .../fs/tool-fs-search/tests/tools.spec.ts | 147 +++++- packages/fs/tool-fs/README.md | 2 + packages/fs/tool-fs/src/edit.ts | 31 +- packages/fs/tool-fs/src/read-render.ts | 2 +- packages/fs/tool-fs/src/read.ts | 47 +- packages/fs/tool-fs/src/write.ts | 41 +- packages/fs/tool-fs/tests/integration.spec.ts | 28 +- packages/fs/tool-fs/tests/tools.spec.ts | 38 +- packages/goal/tool-goal/README.md | 2 + packages/goal/tool-goal/src/index.ts | 93 +++- .../goal/tool-goal/tests/tool-goal.spec.ts | 47 +- packages/guard/repeat-tool-guard/src/index.ts | 3 +- .../tests/repeat-tool-guard.spec.ts | 10 +- packages/hooks/hooks-claude/src/index.ts | 3 +- .../hooks/hooks-claude/tests/bridge.spec.ts | 12 +- .../hooks-claude/tests/coverage-cases.ts | 48 +- packages/hooks/hooks-codex/src/index.ts | 3 +- .../hooks/hooks-codex/tests/bridge.spec.ts | 4 +- .../hooks/hooks-codex/tests/coverage-cases.ts | 52 +-- packages/llm/llm-retry/tests/retry.spec.ts | 4 +- packages/mcp/mcp-client/README.md | 10 +- packages/mcp/mcp-client/src/index.ts | 2 + packages/mcp/mcp-client/src/tools.ts | 69 ++- .../mcp/mcp-client/tests/mcp-client.spec.ts | 134 +++++- .../session-persistence/tests/contract.ts | 2 +- packages/skill/tool-skill/README.md | 2 +- packages/skill/tool-skill/src/index.ts | 55 ++- .../skill/tool-skill/tests/tool-skill.spec.ts | 16 +- packages/spill/spill-policy/README.md | 8 +- packages/spill/spill-policy/src/index.ts | 14 +- .../spill-policy/tests/spill-policy.spec.ts | 38 +- .../subagent/subagent-inprocess/README.md | 2 +- .../subagent-inprocess/src/structured.ts | 15 +- .../tests/structured.spec.ts | 35 +- .../tests/subagent-spawn.spec.ts | 5 +- packages/subagent/tool-subagent/README.md | 4 +- packages/subagent/tool-subagent/src/index.ts | 52 ++- .../tool-subagent/tests/tool-subagent.spec.ts | 8 + packages/support/invariants/src/index.ts | 2 +- .../invariants/tests/invariants.spec.ts | 6 +- packages/tasks/tool-tasks/README.md | 2 + packages/tasks/tool-tasks/src/index.ts | 110 ++++- .../tasks/tool-tasks/tests/tool-tasks.spec.ts | 40 +- packages/timeout/timeout-policy/README.md | 2 +- packages/timeout/timeout-policy/src/index.ts | 5 +- .../tests/timeout-policy.spec.ts | 36 +- packages/todo/tool-todo/README.md | 2 +- packages/todo/tool-todo/src/index.ts | 49 +- .../todo/tool-todo/tests/tool-todo.spec.ts | 5 + packages/ui/acp/src/index.ts | 3 +- packages/ui/acp/tests/stream-update.spec.ts | 17 +- packages/ui/acp/tests/turns.spec.ts | 8 +- packages/ui/tool-ask-user/README.md | 4 +- packages/ui/tool-ask-user/src/index.ts | 30 +- .../tool-ask-user/tests/tool-ask-user.spec.ts | 12 +- packages/ui/tui/src/index.ts | 4 +- packages/ui/tui/tests/tui.snapshot.ts | 5 +- packages/ui/tui/tests/tui.spec.ts | 25 +- packages/web/tool-web/README.md | 2 + packages/web/tool-web/src/fetch.ts | 43 +- packages/web/tool-web/src/search.ts | 39 +- .../web/tool-web/tests/integration.spec.ts | 17 +- packages/web/tool-web/tests/tool-web.spec.ts | 33 +- packages/workflow/tool-ralph/README.md | 2 +- packages/workflow/tool-ralph/src/index.ts | 27 +- .../tool-ralph/tests/tool-ralph.spec.ts | 8 +- packages/workflow/tool-workflow/README.md | 4 +- packages/workflow/tool-workflow/src/index.ts | 30 +- .../tool-workflow/tests/tool-workflow.spec.ts | 11 +- scripts/type-equiv.manifest.json | 4 + 173 files changed, 3298 insertions(+), 954 deletions(-) create mode 100644 .agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml create mode 100644 .agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md create mode 100644 .agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md create mode 100644 packages/core/tools/src/testing.ts create mode 100644 packages/fs/tool-fs-search/src/surface.ts diff --git a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.md b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.md index e76ca22e2d..7fa2bde08c 100644 --- a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.md +++ b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.md @@ -122,7 +122,7 @@ The root plugin registers the full suite by composing the per-tool registration ## Testing -Tests follow the package boundary, not only the user-visible tools: the service seam in `dsh-fs`; real filesystem behavior through the `ctx.fs` interface in `dsh-fs-local` (resolution, symlinks, streaming, binary/UTF-8 rejection, unconditional and version-guarded writes, literal-edit semantics, line-ending preservation, structured `FsError` codes); the consumer surface in `dsh-tool-fs` against the real local provider (mock only the model/clock, never the collaborator); and integration through `ctx.tools.execute()` with and without `dsh-fs-policy`, world-verified by reading files back from disk rather than trusting the returned `ContentBlock[]`. The observed-state/owner-derivation policy is tested in `dsh-fs-policy`, not here. +Tests follow the package boundary, not only the user-visible tools: the service seam in `dsh-fs`; real filesystem behavior through the `ctx.fs` interface in `dsh-fs-local` (resolution, symlinks, streaming, binary/UTF-8 rejection, unconditional and version-guarded writes, literal-edit semantics, line-ending preservation, structured `FsError` codes); the consumer surface in `dsh-tool-fs` against the real local provider (mock only the model/clock, never the collaborator); and integration through `ctx.tools.execute()` with and without `dsh-fs-policy`, world-verified by reading files back from disk rather than trusting either the canonical value or rendered content. The observed-state/owner-derivation policy is tested in `dsh-fs-policy`, not here. The defensive-pattern classes this repo has been bitten by are pinned directly: diff --git a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md b/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md index 8ddd1e8941..ce0f146b39 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md +++ b/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md @@ -14,24 +14,20 @@ The obstacle is a seam boundary: `presentResult(args, result)` is a **pure funct Add a **persisted, tool-private presentation channel** so a tool's `execute` can attach a result-time render payload that survives replay, and use it to carry the applied-hunk diff. -### 1. A `meta` channel on the tool result (core) +### 1. A replayable presentation projection on canonical tool output (core) -`ToolDefinition.execute` may now return either its model-facing `ContentBlock[]` (unchanged, the common case) OR `{ content: ContentBlock[]; meta?: unknown }`: +The original implementation let `execute` return `{ content, meta }`. The [canonical tool-output contract](2026-07-20-canonical-tool-output-contract.md) supersedes that authoring shape: every tool now returns one schema-declared JSON value, `output.render(args, value)` derives model-facing blocks, and optional `output.presentationMeta(args, value)` derives replayable UI data. -```ts ignore-check -type ToolExecuteReturn = ContentBlock[] | { content: ContentBlock[]; meta?: unknown } -``` +`presentationMeta` is tool-owned `JsonValue` that the core persists without interpreting its fields. `Session.append` validates it with the rest of the event, and replay passes the stored payload back to `presentResult`; presentations therefore reproduce without I/O or recomputation. The canonical value itself remains execution-local and is not added to the session format. -`meta` is tool-owned `unknown` that the core persists without interpretation. `Session.append` rejects non-JSON values, and replay passes the stored payload back to `presentResult`; presentations therefore reproduce without I/O or recomputation. Runtime validation avoids adding a shared serializable-value dependency to the tools core. - -This is the general shape ("a tool attaches durable result presentation"), not an fs-specific one — any tool can use it. +This remains the general shape ("a tool projects durable result presentation"), not an fs-specific one—any tool can use it. ### 2. The tool computes the hunk; the backend returns before/after (fs) Per the [capability-seam split](2026-06-13-capability-seams.md), the storage backend returns only **storage facts** and the model-facing tool owns **presentation**: - `dsh-fs` widens `FsEditOutcome` with `{ before: string; after: string }` and `FsWriteOutcome` with `{ before: string | null; after: string }` (`before: null` ⇒ a create, or an existing-but-undiffable binary/non-UTF-8 file). The local backend already holds both texts at write time; it returns them as raw LF-normalized text, with **no diff/UI concept** entering the seam. -- `dsh-tool-fs` stores contextual hunks in `meta: { diffs: FileDiff[] }`. Successful mutations always complete with a diff card because ACP result content replaces the pending card: creates or unchanged overwrites fall back to an args-derived whole-file diff, while edits use applied hunks. Failed mutations carry no diff metadata and render their error normally. +- `dsh-tool-fs` returns canonical before/after mutation facts and projects contextual hunks as `meta: { diffs: FileDiff[] }`. Successful mutations always complete with a diff card because ACP result content replaces the pending card: creates or unchanged overwrites fall back to an args-derived whole-file diff, while edits use applied hunks. Failed mutations carry no diff metadata and render their error normally. ### 3. The bridge renders a `diff` result card @@ -43,7 +39,7 @@ Per the [capability-seam split](2026-06-13-capability-seams.md), the storage bac ## Consequences -`tool/result` events may now carry a tool-private `meta` payload — part of the on-disk vocabulary, runtime-gated to JSON by `Session.append` — and any tool can attach durable result presentation without another core change. The diff card reproduces on session reload and snapshot replay for free: it is read back from the log, never recomputed. The costs: an overwrite holds both the prior and new text in memory to compute a UI-only hunk (`TODO(overwrite-diff-bound)`), and `dsh-tool-fs` carries a small, well-known runtime dependency. +`tool/result` events carry a tool-private `meta` payload—part of the on-disk vocabulary, runtime-gated to JSON by `Session.append`—and any tool can project durable result presentation without another core change. The diff card reproduces on session reload and snapshot replay for free: it is read back from the log, never recomputed. The costs: an overwrite holds both the prior and new text in memory to compute a UI-only hunk (`TODO(overwrite-diff-bound)`), and `dsh-tool-fs` carries a small, well-known runtime dependency. ## Non-goals diff --git a/.agents/notes/implemented/architecture/2026-07-06-tool-result-retention-library.md b/.agents/notes/implemented/architecture/2026-07-06-tool-result-retention-library.md index f90e653a7c..2962f1006e 100644 --- a/.agents/notes/implemented/architecture/2026-07-06-tool-result-retention-library.md +++ b/.agents/notes/implemented/architecture/2026-07-06-tool-result-retention-library.md @@ -150,6 +150,6 @@ The formatter hook is deliberately small: a tool turns a `RetentionNotice` into **Put `read` windowing behind `ItemRetainer`.** Rejected for v1: `read` is the only current window consumer, and its semantics are file pagination rather than generic retention. A single `Omitted` count cannot represent both sides of a line window, and `read` also carries `totalLines`, offset-range errors, per-line preview truncation, and a byte cap over selected output. Keeping `read-render` tool-owned avoids growing the shared library around one special case. -**Make truncation part of `ToolExecutionResult`.** Rejected: the tool registry would have to understand tool-specific recovery guidance, grouping, line numbering, exit status, and provider semantics. Retention is a library used before a tool returns `ContentBlock[]`; the model-facing result remains tool-owned. +**Make truncation part of `ToolExecutionResult`.** Rejected: the tool registry would have to understand tool-specific recovery guidance, grouping, line numbering, exit status, and provider semantics. Retention is a library used by a tool's Native renderer; the model-facing projection remains tool-owned while the [canonical value](2026-07-20-canonical-tool-output-contract.md) may retain the complete acquired result. **Expose limits in every model-facing tool schema.** Rejected as the default: Claude Code's grep exposes `head_limit` / `offset`, but this harness keeps routine budgets as deployment config unless the model genuinely needs pagination control. A future read-like continuation field can be added per tool; it does not belong in the shared retention primitive. diff --git a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.md b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.md index 040a6c2fdc..df0608cb34 100644 --- a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.md +++ b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.md @@ -61,7 +61,10 @@ function toolTimeoutResult(timeoutMs: number): ToolExecutionResult { return { content: [{ type: 'text', text: `Error: tool call timed out after ${timeoutMs}ms` }], isError: true, - error: { name: 'ToolTimeoutError', code: 'TOOL_TIMEOUT' }, + error: { + message: `tool call timed out after ${timeoutMs}ms`, + info: { name: 'ToolTimeoutError', code: 'TOOL_TIMEOUT' }, + }, } } ``` diff --git a/.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md b/.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md index a9197de179..e2df9a902b 100644 --- a/.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md +++ b/.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md @@ -8,7 +8,7 @@ Tool outputs need bounded model-facing previews, but some oversized results are Before this change the behavior was uneven. `dsh-bash-local` already writes complete stdout/stderr streams to private temp spill files when its in-memory tail overflows, but ordinary text tool results were returned inline unless the tool hand-rolled its own cap. The [tool result retention library](2026-07-06-tool-result-retention-library.md) owns preview mechanics, but it does not own storage or an execution-pipeline policy that applies those mechanics to final tool results. -The shape matches the timeout policy design: a tool author normally returns the text result, and a policy plugin enforces the deployment's default context budget. Tool-specific early spill remains possible later for outputs that do not survive to the final `ToolExecutionResult`; the first cut proves the default final-result path. +The shape matches the timeout policy design: a tool author declares a canonical value plus Native renderer, and a policy plugin enforces the deployment's default context budget on rendered content. Tool-specific early spill remains possible for provider acquisition bounds; tool-owned surface spill may retain a complete acquired canonical value while replacing only presentation. The [canonical tool-output contract](2026-07-20-canonical-tool-output-contract.md) owns that split. ## Decision @@ -97,9 +97,13 @@ The policy skips `read` to avoid a circular `read -> spill file -> read again` l ```ts ignore-check ctx.tools.register(defineTool({ name: 'web_fetch', + output: { + schema: WEB_FETCH_RESULT_SCHEMA, + render: (_args, value) => [{ type: 'text', text: formatFetchOutput(value) }], + }, async execute(args, exec) { const result = await ctx.web.fetch({ url: args.url }, exec.signal ? { signal: exec.signal } : undefined) - return [{ type: 'text', text: formatFetchOutput(result) }] + return result }, })) ``` diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml new file mode 100644 index 0000000000..d76de6a74e --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-20-canonical-tool-output-contract.md: 226ca3274e08e2d46d29075ee412d4945fda753a +2026-07-20-canonical-tool-output-contract.zh.md: c5c5e46e267dd3d0795df7fb6761e867e52b5b2b diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md new file mode 100644 index 0000000000..226ca3274e --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md @@ -0,0 +1,76 @@ +# Agent Note: Canonical tool output contract + +Status: implemented + +English | [中文](2026-07-20-canonical-tool-output-contract.zh.md) + +## Problem + +Tool bodies previously authored model-facing `ContentBlock[]` directly, optionally wrapping it with opaque `meta`. Native function calling therefore had a usable human projection, but a programmatic caller had no stable domain value: Code Mode flattened the blocks back into a string, dynamic tools repeated the content shape, and policy could replace presentation without any way to distinguish that change from replacing the operation's result. Several capability seams already returned richer provider values only to discard them at their model-facing tool boundary. + +The durable session contract made that presentation authoritative for replay, but persisting every rich intermediate value would enlarge logs, expose implementation data to compaction and migration, and incorrectly turn an execution-local API into session format. The foundation instead needs one typed value during execution and an explicit projection into the existing durable/model-facing content. + +## Decision + +Every tool declares a mandatory canonical output and returns only the value described by it: + +```ts ignore-check +output: { + schema: OutputSchema + render(args, value): ContentBlock[] + presentationMeta?(args, value): JsonValue +} +``` + +`defineTool` infers the body return and both projectors from the unified `ValueSchemaSpec`. Raw and dynamic definitions provide the compiled `JsonSchemaNode` form. Registration rejects a missing declaration or unsupported raw schema; there is no content-return compatibility path. + +For each successful dispatch the registry snapshots the returned value as lossless `JsonValue`, validates it against `output.schema`, deep-freezes it, then invokes the pure renderer and, for a direct surface call, the optional metadata projector. Renderer, projector, schema, or lossless-JSON failures are contained as ordinary `ToolOutputError` results. An around `tools/execute` wrapper receives and returns the canonical success/failure union; a wrapper-authored success is normalized again through the resolved tool's output declaration instead of trusting independently authored content. + +```ts ignore-check +type ToolExecutionResult = + | { isError: false; value: JsonValue; content: ContentBlock[]; meta?: JsonValue; additionalContexts?: HookContext[] } + | { isError: true; error: { message: string; info?: { name: string; code: string } }; content: ContentBlock[]; meta?: JsonValue; additionalContexts?: HookContext[] } +``` + +`tools/post-execute` has two mutually exclusive successful projections. Replacing `content` changes only Native/model presentation and preserves the canonical value and metadata. Replacing `value` revalidates the replacement and recomputes both presentation projections. A block removes the value and becomes a failure. Content replacement is therefore not a confidentiality mechanism: policy that must prevent programmatic access blocks the call or replaces the value. + +Canonical values are execution-local. The agent loop persists `tool/result` with only `content`, `error`, and `meta`; Code Mode's `tool/code-dispatch` persists only its bounded summary. Neither event stores the intermediate value, so replay reproduces presentation but cannot reconstruct the programmatic result. `presentationMeta` is computed only for a direct surface call, including the outer `run_code`; a nested Code dispatch gets no metadata or result card. Generic and tool-owned spill projections similarly skip nested dispatches, whose canonical value never enters model context. + +The first-party tools preserve their existing Native text while returning domain DTOs: + +| Tool family | Canonical value | +|---|---| +| `read` | `{ path, offset, lines: [{ number, text }], totalLines }` | +| `write` | `{ path, operation: "create" | "update", before: string | null, after }` | +| `edit` | `{ path, before, after }` | +| `glob` | `{ paths: string[] }` | +| `grep` | `{ matches: [{ path, lineNumber, line }] }` | +| `web_search` / `web_fetch` | The normalized `WebSearchResult` / `WebFetchResult` | +| `bash` | `{ kind: "background", taskId }` or `{ kind: "foreground" } & BashRunResult` | +| `task_output` / `task_list` / `task_kill` | Public task snapshots without owner or notification bookkeeping | +| `subagent` | Background task handle or `{ kind: "foreground", runId, output: JsonValue[] }` | +| `workflow` / `ralph` | `{ runId, agentsStarted, result: JsonValue }` | +| `skill` | `{ name, provider, resourceBase?, content }` | +| `todo_write` | `{ todos, counts }` | +| `ask_user_question` | `{ answers: [{ id, selected, custom? }] }` | +| `cordis_inspect` / `cordis_mount` / `cordis_unmount` | Inspection text or typed dynamic-mount handles | +| `structured_output` | `{ recorded: true }` | +| `run_code` | `{ logs: string[], result?: JsonValue }` | + +Provider and executor acquisition limits remain real limits on the canonical value. Formatting-only limits belong in `render`; `glob` and `grep`, for example, keep every acquired item in `value` while their Native projection retains and best-effort spills the configured first page. Filesystem mutations derive replayable diff metadata from `args` and the canonical before/after value rather than returning UI state from the body. + +MCP bridges preserve protocol blocks through `McpResult<{...}> = { content: JsonValue[]; structuredContent? }`. An advertised `outputSchema` is enforced when it belongs to the supported raw subset; unsupported schemas fall back to `JsonValue` rather than pretending to validate them. Native rendering still uses the existing MCP-to-`ContentBlock` projection, and MCP `isError` becomes a failed tool result. + +## Alternatives considered + +- **Return rendered text to Code Mode:** rejected because callers would continue scraping prose for task ids, mount ids, paths, and structured provider results. +- **Persist canonical values on `tool/result`:** rejected because nested execution values are not model history, need not survive replay, and would create a session-format and storage commitment unrelated to Native reconstruction. +- **Let tools return both value and content:** rejected because two author-owned results can disagree and policy cannot state which one is authoritative. The renderer makes presentation a deterministic projection of the validated value. +- **Treat content replacement as value redaction:** rejected because presentation and programmatic access are different consumers; hiding only the former would create a false security boundary. +- **Require object-rooted tool outputs:** rejected because scalar, array, and null results are legitimate JSON APIs. Object-rooting remains a consumer rule for caller-defined subagent/workflow structured output. + +## Consequences + +Native and replay behavior remains content-first and byte-compatible, while execution-time callers can use a validated domain value without parsing that content. Failures have one required message plus optional internal class/code information, successful and failed outcomes are discriminated, and a failed result can never promise a value. Tool authors must design the value and Native projection together; the extra declaration is intentional because it prevents accidental programmatic contracts from being inferred from prose. + +Intermediate values remain bounded only by the producing capability and process memory. Their omission from the log means replay cannot recover them, and a content-only post policy does not hide them. These are explicit properties of the execution-local contract, not accidental gaps. diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md new file mode 100644 index 0000000000..c5c5e46e26 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md @@ -0,0 +1,76 @@ +# Agent Note:规范工具输出契约 + +Status: implemented + +[English](2026-07-20-canonical-tool-output-contract.md) | 中文 + +## 问题 + +工具主体过去直接编写面向模型的 `ContentBlock[]`,并可选择将其与不透明的 `meta` 包装在一起。因此,Native 模式的 Function Calling(函数调用)虽然拥有可供人阅读的投影,但程序化调用方没有稳定的领域值:Code Mode 会将内容块重新展平为字符串,动态工具会重复定义内容形态,策略也可以替换展示内容,却无法区分这项变更究竟是替换展示,还是替换操作结果。多个能力 seam 已经返回了信息更丰富的提供方值,却又在面向模型的工具边界丢弃这些值。 + +持久会话契约将这份展示内容视为回放时的权威来源,但如果持久化每一个信息丰富的中间值,就会扩大日志、使实现数据进入压缩和迁移流程,还会错误地把执行期本地 API 变成会话格式的一部分。因此,系统底层需要在执行期间保留一个类型化值,并显式将其投影为现有的持久化内容和模型可见内容。 + +## 决策 + +每个工具都必须声明规范输出,并且只能返回该声明描述的值: + +```ts ignore-check +output: { + schema: OutputSchema + render(args, value): ContentBlock[] + presentationMeta?(args, value): JsonValue +} +``` + +`defineTool` 从统一的 `ValueSchemaSpec` 推导工具主体返回值和两个投影器的类型。原始定义和动态定义则提供编译后的 `JsonSchemaNode` 形式。注册时会拒绝缺失输出声明或采用不受支持原始 schema 的定义,不提供兼容旧式内容返回值的路径。 + +每次成功分发时,注册表会将返回值快照为无损 `JsonValue`,依据 `output.schema` 校验并深度冻结,然后调用纯渲染器;对于直接的外层调用,还会调用可选的元数据投影器。渲染器、投影器、schema 或无损 JSON 处理失败都会被收敛为普通 `ToolOutputError` 结果。around `tools/execute` 包装层接收并返回规范的成功/失败联合;包装层自行产生的成功结果会再次通过已解析工具的输出声明完成归一化,而不会信任其独立编写的内容。 + +```ts ignore-check +type ToolExecutionResult = + | { isError: false; value: JsonValue; content: ContentBlock[]; meta?: JsonValue; additionalContexts?: HookContext[] } + | { isError: true; error: { message: string; info?: { name: string; code: string } }; content: ContentBlock[]; meta?: JsonValue; additionalContexts?: HookContext[] } +``` + +`tools/post-execute` 为成功结果提供两种互斥的投影方式。替换 `content` 只改变 Native/模型展示,并保留规范值和元数据。替换 `value` 会重新校验替代值,并重新计算两份展示投影。阻止操作会移除值并转为失败。因此,替换内容并不是保密机制:必须阻止程序化访问的策略,应当阻止调用或替换值。 + +规范值仅存在于执行期间。agent loop(智能体循环)持久化的 `tool/result` 只包含 `content`、`error` 和 `meta`;Code Mode 的 `tool/code-dispatch` 只持久化其有界摘要。两个事件都不存储中间值,因此回放可以重现展示,却无法重建程序化结果。系统只会为直接的外层调用计算 `presentationMeta`,其中包括外层 `run_code`;嵌套 Code 分发没有元数据或结果卡片。通用以及工具自有的输出落盘投影同样跳过嵌套分发,因为它们的规范值永远不会进入模型上下文。 + +第一方工具在保持现有 Native 文本不变的同时返回领域 DTO: + +| 工具系列 | 规范值 | +|---|---| +| `read` | `{ path, offset, lines: [{ number, text }], totalLines }` | +| `write` | `{ path, operation: "create" | "update", before: string | null, after }` | +| `edit` | `{ path, before, after }` | +| `glob` | `{ paths: string[] }` | +| `grep` | `{ matches: [{ path, lineNumber, line }] }` | +| `web_search` / `web_fetch` | 归一化后的 `WebSearchResult` / `WebFetchResult` | +| `bash` | `{ kind: "background", taskId }` 或 `{ kind: "foreground" } & BashRunResult` | +| `task_output` / `task_list` / `task_kill` | 不含所有者或通知账务字段的公开任务快照 | +| `subagent` | 后台任务句柄或 `{ kind: "foreground", runId, output: JsonValue[] }` | +| `workflow` / `ralph` | `{ runId, agentsStarted, result: JsonValue }` | +| `skill` | `{ name, provider, resourceBase?, content }` | +| `todo_write` | `{ todos, counts }` | +| `ask_user_question` | `{ answers: [{ id, selected, custom? }] }` | +| `cordis_inspect` / `cordis_mount` / `cordis_unmount` | 检查文本或类型化的动态挂载句柄 | +| `structured_output` | `{ recorded: true }` | +| `run_code` | `{ logs: string[], result?: JsonValue }` | + +提供方和执行器的采集上限仍会实际限制规范值。仅用于格式化的限制归 `render` 所有;例如,`glob` 和 `grep` 会在 `value` 中保留所有已采集项,而其 Native 投影仍只保留配置指定的第一页,并尽力将完整展示内容写入落盘文件。文件系统变更工具根据 `args` 和规范的变更前/后值推导可回放的 diff 元数据,不再由工具主体返回 UI 状态。 + +MCP 桥接层通过 `McpResult<{...}> = { content: JsonValue[]; structuredContent? }` 保留协议内容块。当公布的 `outputSchema` 属于受支持的原始子集时,系统会强制校验;不受支持的 schema 则回退为 `JsonValue`,而不会假装已完成校验。Native 渲染仍使用现有的 MCP 到 `ContentBlock` 投影,MCP `isError` 则会变为失败的工具结果。 + +## 备选方案 + +- **向 Code Mode 返回渲染后的文本:**不予采纳。调用方仍需从自然语言中提取 task id、挂载 id、路径和结构化提供方结果。 +- **在 `tool/result` 上持久化规范值:**不予采纳。嵌套执行值不属于模型历史记录,无需在回放后继续存在;持久化还会引入与 Native 重建无关的会话格式和存储承诺。 +- **允许工具同时返回值和内容:**不予采纳。由作者分别维护的两份结果可能互相矛盾,策略也无法说明哪一份才是权威结果。渲染器会根据已校验值确定性地产生展示。 +- **将内容替换视为值脱敏:**不予采纳。展示内容和程序化访问面向不同消费方;只隐藏前者会制造虚假的安全边界。 +- **要求工具输出必须以对象为根:**不予采纳。标量、数组和 null 结果都是合理的 JSON API。只有由调用方定义的 subagent/工作流结构化输出仍受消费方的对象根规则约束。 + +## 影响 + +Native 和回放行为仍以内容为先,并保持逐字节兼容;执行期调用方则无需解析内容,即可使用经过校验的领域值。失败结果必须包含消息,并可选择附加内部类名/代码信息;成功与失败结果由判别字段区分,失败结果绝不会承诺存在值。工具作者必须一并设计值及其 Native 投影;增加这项声明是有意为之,因为它避免从自然语言内容意外推导出程序化契约。 + +中间值只受产生它们的能力和进程内存限制。日志不包含这些值,因此回放无法恢复;仅处理内容的 post 策略也无法隐藏这些值。这些都是执行期本地契约的明确属性,并非意外缺口。 diff --git a/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.md b/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.md index a318956ddf..59bf9be768 100644 --- a/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.md +++ b/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.md @@ -68,7 +68,7 @@ The first pass rejects Codex-style patch grammars and multi-mode edit APIs. It u ## Result shape -The first implementation returns `ContentBlock[]` through the existing `ToolDefinition.execute()` contract. `ctx.fs` returns structured filesystem results and owns file-state recording/refreshing; `tool-fs` formats those results into the model projection. +The first implementation formatted `ContentBlock[]` in `execute`. The [canonical tool-output contract](../architecture/2026-07-20-canonical-tool-output-contract.md) now keeps `ctx.fs` result facts as the tool's validated value and derives the same model text through `output.render`; file-state recording/refreshing remains on `ctx.fs`. Default native projections: diff --git a/.agents/notes/implemented/feature/2026-06-30-interception-seams.md b/.agents/notes/implemented/feature/2026-06-30-interception-seams.md index 2535c1c564..82102efa99 100644 --- a/.agents/notes/implemented/feature/2026-06-30-interception-seams.md +++ b/.agents/notes/implemented/feature/2026-06-30-interception-seams.md @@ -24,11 +24,11 @@ Every call follows `tools/pre-execute` → guards → `tools/execute` → dispat - **`tools/pre-execute`** is the extensible waterfall gate. Its `PreToolDecision` allows, denies, or asks. Deny skips `tools/execute` and core dispatch. Ask resolves through the optional approval seam: only `allowed-once` continues through guards and dispatch; rejection, cancellation, an unavailable channel, a missing approval service, or an agent-less call becomes a normalized denial. Every outcome still reaches post-policy and final observers. - **`ctx.tools.guard()`** installs synchronous scope-aware policy after the whole pre-execute waterfall. A guard may deny or abstain, never force-allow, so listener ordering cannot resurrect an operation that a final invariant forbids. -- **`tools/execute`** is the around-dispatch waterfall for timeout, retry, and metrics plugins. A wrapper delegates to core dispatch with `next()`, may add, replace, or remove only `exec.signal` before doing so, and receives the already-normalized result of a thrown or unknown tool; returning its own valid result short-circuits dispatch. -- **`tools/post-execute`** is the inspect/transform waterfall. Its `PostToolDecision` accepts, blocks with feedback, optionally replaces content, or attaches `additionalContexts`. The returned decision is the supported transform channel; after the waterfall, the registry materializes the complete outcome once before final observation. +- **`tools/execute`** is the around-dispatch waterfall for timeout, retry, and metrics plugins. A wrapper delegates to core dispatch with `next()`, may add, replace, or remove only `exec.signal` before doing so, and receives the already-normalized canonical success/failure result of a thrown or unknown tool; a wrapper-authored success is re-normalized through the resolved output declaration. +- **`tools/post-execute`** is the inspect/transform waterfall. Its `PostToolDecision` accepts, blocks with feedback, replaces either presentation content or canonical value, or attaches `additionalContexts`. Value replacement revalidates and recomputes presentation; content replacement preserves programmatic value and is not a confidentiality boundary. The returned decision is the supported transform channel; after the waterfall, the registry materializes the complete outcome once before final observation. - **`tools/result`** is the synchronous contained notification after every transform, lossless-JSON materialization, and the outer error boundary. It receives the same frozen execution identity and an immutable snapshot of the authoritative result; observer failures are contained per listener and cannot change or reject `ToolRegistry.execute()`'s returned outcome. -Core dispatch and the tool body sit inside normalization boundaries, so tool, listener, malformed-result, non-JSON result, and identity-shape failures resolve as JSON-safe `isError` results rather than escaping the turn. A post-execute listener can therefore inspect a thrown tool, and a final observer sees exactly what the caller receives and the session log can persist. +Core dispatch and the tool body sit inside normalization boundaries, so tool, listener, invalid canonical value, renderer/projector, non-JSON presentation, and identity-shape failures resolve as JSON-safe `isError` results rather than escaping the turn. A post-execute listener can therefore inspect a thrown tool, and a final observer sees the execution-local canonical value beside exactly the presentation fields the session log can persist. The [canonical tool-output contract](../architecture/2026-07-20-canonical-tool-output-contract.md) owns the value/projection and durability rules. **`TurnEndReason.rejected`** (`dsh-session`): a zero-step turn whose claimed prompt was blocked by `prompt-submit`. diff --git a/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md b/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md index 2038b2b719..429102aeee 100644 --- a/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md +++ b/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md @@ -30,7 +30,7 @@ Mount code runs as an async-function body in a fresh vm realm. Its documented su Sandbox globals are deliberately small: a tagged write-through `console` (`[cordis:<id>] …` on the host stdout/stderr, so a listener that fires long after the mount call still lands somewhere the user sees), the `harness.defineTool` / `harness.registerTool` registration pair, the encoding primitives fresh vm contexts lack (`btoa`/`atob` as host closures over `Buffer` — a sanctioned exception, `Buffer` itself is never exposed — plus `TextEncoder`/`TextDecoder`), and callable traps over the withheld Node APIs (`require`, `setTimeout`/`setInterval`/`setImmediate`/`clearTimeout`/`clearInterval`, `fetch`) that throw a redirect naming the cordis alternative. Only function-shaped globals are trapped; `process` and `Buffer` stay `undefined` so a `typeof` feature probe stays inert rather than detonating a throwing accessor. -Mount code crosses the vm boundary through three controls. Dual-realm `instanceof` recognizes both host and vm objects. `harness.defineTool` normalizes results into host-realm JSON and validates the `ToolExecuteReturn` shape before logging. The mounted plugin receives a whitelist context façade, not a raw or pass-through `Context`; framework plumbing and context-valued returns are rejected. Service reads require a declared `inject`, preserving Cordis activation and unload semantics. `ctx.tools.get` exposes only the schema view, so mounted code cannot bypass `ToolRegistry.execute` by calling a definition directly. +Mount code crosses the vm boundary through three controls. Dual-realm `instanceof` recognizes both host and vm objects. `harness.defineTool` rebuilds the output schema/projectors in the host realm, snapshots the body value as host-owned JSON, and lets the registry enforce the [canonical tool-output contract](../architecture/2026-07-20-canonical-tool-output-contract.md) before observation. The mounted plugin receives a whitelist context façade, not a raw or pass-through `Context`; framework plumbing and context-valued returns are rejected. Service reads require a declared `inject`, preserving Cordis activation and unload semantics. `ctx.tools.get` exposes only the schema view, so mounted code cannot bypass `ToolRegistry.execute` by calling a definition directly. The boundary normalizes unambiguous JSON-Schema forms into `ParameterSchemaSpec`, preserving `integer`, raw object openness, and required arrays. Direct DSL object nodes must declare `additionalProperties`; invalid vocabulary fails with the accepted alternatives. Parse, TypeScript, missing-return, Node-API, and duplicate-tool errors include the relevant source line or corrective contract without narrating implementation internals. diff --git a/docs/architecture.md b/docs/architecture.md index 0c3e55f269..f51059e63d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -97,7 +97,8 @@ forever: exclusive -> one-call barrier parallel -> rolling pool, <= maxParallelToolCalls in flight; reclassify before start each start -> 'tool/call' -> ordered tools/pre-execute -> concurrent tools/execute - each model-order result -> ordered tools/post-execute -> 'tool/result' + body value -> validate/snapshot -> Native/meta projection + each model-order result -> ordered tools/post-execute -> projected 'tool/result' append accepted tool-batch context after all recorded results, then steering agent/post-step 'step/end' @@ -110,7 +111,7 @@ forever: Each step assembles ordered prompt sections, tool schemas, and `{{name}}` variables; unknown or valueless references fail the turn. `dsh-system-prompt` owns the harness identity and default persona, which an agent scope may shadow. The loop supplies `model` and `cwd` ([prompt ownership](../.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)). -Tool-time context—including async `agent.inject()` notices and post-tool `additionalContexts`—settles after results. Steering drains; before signal closure, `agent/post-step` observes durable output, results, context, and steering. Leftovers queue. Terminal `agent/turn-stop` runs after continuation and steering folding, remains authoritative through close/flush, and discards later steering while preserving queued prompts. +Tool success separates an execution-local canonical JSON value from Native projections; post-policy replaces one projection or blocks, and the loop persists only projections ([contract](../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md)). Tool-time context—including async `agent.inject()` notices and post-tool `additionalContexts`—settles after results. Steering drains; before signal closure, `agent/post-step` observes durable output, results, context, and steering. Leftovers queue. Terminal `agent/turn-stop` runs after continuation and steering folding, remains authoritative through close/flush, and discards later steering while preserving queued prompts. Pruning precedes summaries; overflow retries require durable progress. Bounded transient retries compose on `agent/request-error`; cancellation wins ([compaction](../.agents/notes/implemented/architecture/2026-07-10-after-call-compaction-pressure-and-overflow-recovery.md), [retry](../.agents/notes/implemented/architecture/2026-06-21-bounded-llm-request-recovery.md)). diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 44e27bb572..47a9926575 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -27,7 +27,7 @@ export interface AcpConfig { Depends on: `Stream` (`@agentclientprotocol/sdk`) -Source: [`packages/ui/acp/src/index.ts:247`](../packages/ui/acp/src/index.ts) +Source: [`packages/ui/acp/src/index.ts:248`](../packages/ui/acp/src/index.ts) ## `@deepseek-ai/dsh-acp-demo` @@ -666,7 +666,7 @@ export interface StreamableHttpConfig { } ``` -Source: [`packages/mcp/mcp-client/src/index.ts:91`](../packages/mcp/mcp-client/src/index.ts) +Source: [`packages/mcp/mcp-client/src/index.ts:93`](../packages/mcp/mcp-client/src/index.ts) ## `@deepseek-ai/dsh-permission` @@ -923,7 +923,7 @@ export interface Config { } ``` -Source: [`packages/spill/spill-policy/src/index.ts:45`](../packages/spill/spill-policy/src/index.ts) +Source: [`packages/spill/spill-policy/src/index.ts:50`](../packages/spill/spill-policy/src/index.ts) ## `@deepseek-ai/dsh-subagent-acp` @@ -1157,7 +1157,7 @@ export interface Config { } ``` -Source: [`packages/workflow/tool-ralph/src/index.ts:22`](../packages/workflow/tool-ralph/src/index.ts) +Source: [`packages/workflow/tool-ralph/src/index.ts:23`](../packages/workflow/tool-ralph/src/index.ts) ## `@deepseek-ai/dsh-tool-skill` @@ -1227,7 +1227,7 @@ export interface Config { Depends on: [`AgentOptions`](core-data-structures/core.md) -Source: [`packages/subagent/tool-subagent/src/index.ts:23`](../packages/subagent/tool-subagent/src/index.ts) +Source: [`packages/subagent/tool-subagent/src/index.ts:24`](../packages/subagent/tool-subagent/src/index.ts) ## `@deepseek-ai/dsh-tool-tasks` @@ -1281,7 +1281,7 @@ export interface Config { } ``` -Source: [`packages/workflow/tool-workflow/src/index.ts:26`](../packages/workflow/tool-workflow/src/index.ts) +Source: [`packages/workflow/tool-workflow/src/index.ts:27`](../packages/workflow/tool-workflow/src/index.ts) ## `@deepseek-ai/dsh-tools` @@ -1303,7 +1303,7 @@ export interface Config { export type ToolPresentationMode = 'native' | 'code' | 'both' ``` -Source: [`packages/core/tools/src/index.ts:397`](../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:448`](../packages/core/tools/src/index.ts) ## `@deepseek-ai/dsh-tui` diff --git a/docs/cookbook/adding-a-tool.i18n.yaml b/docs/cookbook/adding-a-tool.i18n.yaml index 288ee96446..eb536bb063 100644 --- a/docs/cookbook/adding-a-tool.i18n.yaml +++ b/docs/cookbook/adding-a-tool.i18n.yaml @@ -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 -adding-a-tool.md: 94cb4fcfa9a0155fd57ef18f9a855a264c2eff84 -adding-a-tool.zh.md: 637dc3381765e57c2d0420164ac13fde7fb590fe +adding-a-tool.md: f94ddfaa9df53c0ee4596d683e676baae6bd85b2 +adding-a-tool.zh.md: 915dc8250c2bcfc490483f87c71e725b1f92f635 diff --git a/docs/cookbook/adding-a-tool.md b/docs/cookbook/adding-a-tool.md index 94cb4fcfa9..f94ddfaa9d 100644 --- a/docs/cookbook/adding-a-tool.md +++ b/docs/cookbook/adding-a-tool.md @@ -22,10 +22,14 @@ export function apply(ctx: Context) { path: { type: 'string', required: true, description: 'Absolute path' }, limit: { type: 'number' }, // optional by default }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args, exec) { // args is TYPED from the schema: { path: string; limit?: number } // exec carries immutable identity + token; signal is the operational field - return [{ type: 'text', text: await readFile(args.path, 'utf8') }] + return readFile(args.path, 'utf8') }, })) } @@ -38,9 +42,10 @@ Registration is effect-based: disposing the plugin fiber unregisters the tool (w - **Args are validated for you.** `defineTool` validates model-generated `arguments` against the unified `ParameterSchemaSpec` before `execute` runs (types, required keys, literal constraints, exact-one unions, and nested values — [runtime arg validation](../../.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.md)), so inside `execute` the args match `InferArgs`. Explicit object nodes declare `additionalProperties: true | false`; the implicit parameter root stays open. You still hand-check constraints the DSL does not express, such as non-empty strings, positive numbers, or cross-field rules. Raw JSON-Schema tools registered directly own their input validation. - **Registration borrows your readonly definition.** A typed same-process contribution is not a serialization boundary; do not mutate its schema or replace callbacks after registration. `schemas()` materializes only the explicit model-facing projection. To hot-swap a tool, dispose its owning effect and register the replacement; mutable state inside the callback's closure remains ordinary plugin state. - **Execution identity is protected.** The registry materializes `arguments` as detached lossless JSON in one recursive pass, freezes that value before policy starts, and assigns an opaque `exec.token`; `callId`, `name`, `arguments`, `agent`, `token`, and an optional enclosing-transport `parent` token stay immutable through dispatch. `parent` is identity-only and exposes no live outer execution. Treat `args` as readonly input. An around-dispatch wrapper may add, replace, or remove only `exec.signal` to impose cancellation or a deadline. -- **Throwing or returning non-JSON data means `isError`.** The registry catches throws and materializes the final result before observers run. A malformed or non-JSON result becomes `{ isError: true }`, preventing a live success that cannot be logged. Throw for infrastructure failures; report domain failures in result text when the model must interpret them. +- **Declare and return one canonical JSON value.** `output.schema` uses `ValueSchemaSpec` and may have an object, array, scalar, or null root. `execute` returns only the inferred value; the registry snapshots it as lossless JSON, validates it, freezes it, and passes it to `output.render(args, value)`. Do not return content blocks from the body or make callers parse prose for ids and fields. +- **Throwing or returning an invalid value means `isError`.** The registry catches throws and contains schema, renderer, metadata-projector, and lossless-JSON failures before observers run. Throw for infrastructure failures. Represent a successful domain outcome in the canonical value even when its Native renderer explains a non-ideal state, such as a non-zero process exit. - **Honor `exec.signal`.** Cancel in-flight work when it fires. -- **Attach durable card data with `meta` (optional).** `execute` may return `{ content, meta }` instead of a bare `ContentBlock[]` — `meta` is a JSON-serializable payload the core treats as opaque, persisted on the `tool/result` event and handed back to your `presentResult` (so a card that needs more than `args`, like `write`/`edit`'s applied-hunk diff, survives a session replay). Keep UI-only data here, never in the model-facing `content`. +- **Project durable card data with `presentationMeta` (optional).** `output.presentationMeta(args, value)` derives replayable JSON from the same canonical value. The core persists it on `tool/result` and hands it to `presentResult`, so a card that needs result-time facts—such as `write`/`edit` applied hunks—survives replay without persisting the canonical value. The projector is skipped for nested Code dispatches because they have no cards. - **Use `exec.agent` for async notifications.** `agent.inject(content, {source: {kind: 'plugin', plugin: '<name>'}})` appends durable context the NEXT model request sees — it is not a wake-up (an idle agent stays idle). Guard against disposed agents (try/catch). ## Long-running work @@ -51,7 +56,7 @@ The producer supplies synchronous `cancel`, non-rejecting `done` that settles af ## Execution policy and observation -Prefer not to build deployment policy into the tool. Use `tools/pre-execute` for extensible allow/deny/ask policy (the [permission-gate example](extension-cookbook.md#a-hook-plugin-permission-gate-example)), `ctx.tools.guard()` for a final monotonic deny that later listeners cannot undo, `tools/execute` to wrap core dispatch with a deadline/retry/metrics scope, `tools/post-execute` to transform or attach model-facing context, and `tools/result` to observe the immutable normalized outcome without changing it. A sandboxing implementation can also sit behind the tool's executor capability seam; the exact contracts are in the [`dsh-tools` README](../../packages/core/tools/README.md#extension-points). +Prefer not to build deployment policy into the tool. Use `tools/pre-execute` for extensible allow/deny/ask policy (the [permission-gate example](extension-cookbook.md#a-hook-plugin-permission-gate-example)), `ctx.tools.guard()` for a final monotonic deny that later listeners cannot undo, `tools/execute` to wrap canonical dispatch with a deadline/retry/metrics scope, `tools/post-execute` to replace either presentation content or the canonical value, block, or attach model-facing context, and `tools/result` to observe the immutable normalized outcome. A content replacement leaves programmatic access to `value` intact; confidentiality policy blocks or replaces the value. A sandboxing implementation can also sit behind the tool's executor capability seam; the exact contracts are in the [`dsh-tools` README](../../packages/core/tools/README.md#extension-points). ## Code Mode reaches your tool for free @@ -59,7 +64,7 @@ In [Code Mode](../../packages/core/tools/README.md), every visible registered to ## How your tool renders in an editor (ACP presentation) -Your tool's `execute` returns model-facing content; its **editor card** is a separate, optional concern you declare with two pure display methods on the `defineTool` options. Design this alongside `execute`, not after — an editor (Zed, over the ACP bridge) shows the card, and a tool with no presentation falls back to a bland generic card (title = tool name, raw args as input). +Your tool's `output.render` returns model-facing content; its **editor card** is a separate concern declared through pure presentation projections and optional `presentCall` / `presentResult` methods. Design these alongside the canonical value—an editor (Zed, over the ACP bridge) shows the card, and a tool with no UI presentation falls back to a generic card (title = tool name, raw args as input). Both methods return a **`card`-tagged render intent** — pick the card kind that matches what your tool does: @@ -70,16 +75,16 @@ Both methods return a **`card`-tagged render intent** — pick the card kind tha - `presentResult(args, { content, isError, meta? })` returns the completed card: - `generic` supplies an optional title and content. - `terminal` supplies raw output and optional exit metadata; the bridge renders the capability-specific or fenced fallback view. - - `diff` supplies applied hunks, often carried in persisted `result.meta` so replay reproduces them. Mutation tools keep a diff result because an ACP update replaces the pending card's content. + - `diff` supplies applied hunks, often derived by `output.presentationMeta` and carried in persisted `result.meta` so replay reproduces them. Mutation tools keep a diff result because an ACP update replaces the pending card's content. Hard rules (they bite if broken): - **Purity.** These run on live streaming AND on session-log REPLAY, so they must be pure functions of `args` (+ the result) — NO I/O, NO reading session state, NO clock/random. A diff is derived from the args (`write` uses `oldText: null` because a call-time presenter has no prior file content); the BRIDGE, not the tool, fills the session cwd and relativizes a display-path title. If you find yourself wanting the file's old content or the working directory inside `presentCall`, stop — that belongs on the bridge or a future result-event shape, not the presenter. -- **UI-only formatting stays out of the model result.** A fenced ` ```console ` block, a diff, a relativized path — none of these may appear in what `execute` returns to the model; they live only in the presentation. (A `terminal` result view carries RAW `output`; the bridge adds the fences.) +- **UI-only formatting stays out of the model result.** A fenced ` ```console ` block, a diff, a relativized path—none of these belongs in the canonical value or Native content merely to serve an editor. `output.render` owns model-facing prose; `presentationMeta` plus the card presenters own replayable UI state. A `terminal` result view carries raw output and the bridge adds fences. - **`defineTool` soft-validates the display path.** A malformed/older logged arg shape makes the wrapper return `undefined` (a generic fallback) rather than throw — display must never crash a replay. The neutral vocabulary lives in `dsh-tools` (never import an ACP type into a tool); the ACP bridge maps each `card` to the wire. The design and the why are in [the render-intent-union Agent Note](../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md); `dsh-tool-fs` (generic/diff) and `dsh-tool-bash` (terminal) are the reference implementations. ## Tests every tool needs -Cover argument rejection, every result shape, and HMR disposal. For a side-effecting tool, drive the real tool through the agent loop with a scripted `MockAdapter` and assert its `tool/call` and `tool/result` session events. For an editor card, assert the exact `presentCall` and `presentResult` views and add an [ACP snapshot](../../.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md) through the real bridge; a terminal card's scenario sets `terminalOutput: true` to exercise the capable-client path. +Cover argument rejection, every canonical value and Native rendering shape, output-schema rejection, and HMR disposal. For a side-effecting tool, drive the real tool through the agent loop with a scripted `MockAdapter` and assert its `tool/call` and projected `tool/result` session events; prove the canonical value itself is not persisted. For an editor card, assert the exact `presentCall` and `presentResult` views and add an [ACP snapshot](../../.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md) through the real bridge; a terminal card's scenario sets `terminalOutput: true` to exercise the capable-client path. diff --git a/docs/cookbook/adding-a-tool.zh.md b/docs/cookbook/adding-a-tool.zh.md index 637dc33817..915dc8250c 100644 --- a/docs/cookbook/adding-a-tool.zh.md +++ b/docs/cookbook/adding-a-tool.zh.md @@ -22,10 +22,14 @@ export function apply(ctx: Context) { path: { type: 'string', required: true, description: 'Absolute path' }, limit: { type: 'number' }, // optional by default }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args, exec) { // args is TYPED from the schema: { path: string; limit?: number } // exec carries immutable identity + token; signal is the operational field - return [{ type: 'text', text: await readFile(args.path, 'utf8') }] + return readFile(args.path, 'utf8') }, })) } @@ -38,9 +42,10 @@ export function apply(ctx: Context) { - **参数已为你校验。** `defineTool` 在 `execute` 运行前,会根据统一的 `ParameterSchemaSpec` 校验模型生成的 `arguments`(类型、必填键、字面量约束、恰好匹配一个分支的联合以及嵌套值——见[运行时参数校验](../../.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.md)),因此 `execute` 内的 args 会匹配 `InferArgs`。显式对象节点必须声明 `additionalProperties: true | false`;隐式参数根对象保持开放。你仍需手动检查 schema DSL 无法表达的约束,例如非空字符串、正数或跨字段规则。直接注册的原始 JSON Schema 工具自行负责输入校验。 - **注册借用你的只读定义。** 类型化的同进程贡献不是序列化边界;注册后不要修改其 schema 或替换回调。`schemas()` 只物化显式的模型可见投影。如需热替换工具,请 dispose 其所属副作用并注册替代品;回调闭包内的可变状态仍是普通的插件状态。 - **执行身份受保护。** 注册表在一次递归遍历中将 `arguments` 物化为分离的无损 JSON,在策略开始前冻结该值,并分配一个不透明的 `exec.token`;`callId`、`name`、`arguments`、`agent`、`token` 以及可选的外层传输 `parent` token 在整个分发过程中保持不可变。`parent` 仅用于身份标识,不暴露活跃的外层执行。请将 `args` 视为只读输入。around-dispatch 包装器只能添加、替换或移除 `exec.signal`,以施加取消或截止时间。 -- **抛出异常或返回非 JSON 数据意味着 `isError`。** 注册表捕获异常,并在观察者运行前物化最终结果。格式错误或非 JSON 的结果变为 `{ isError: true }`,防止出现无法记录的活跃成功。基础设施故障请抛异常;当模型需要解读领域失败时,请在结果文本中报告。 +- **声明并返回一个规范 JSON 值。** `output.schema` 使用 `ValueSchemaSpec`,根可以是对象、数组、标量或 null。`execute` 只返回推导出的值;注册表将其快照为无损 JSON,完成校验和冻结后,再传给 `output.render(args, value)`。工具主体不要返回内容块,也不要迫使调用方从自然语言中解析 id 和字段。 +- **抛出异常或返回无效值意味着 `isError`。** 注册表会捕获异常,并在观察者运行前收敛 schema、渲染器、元数据投影器和无损 JSON 失败。基础设施故障请抛异常。成功的领域结果即使表示不理想的状态,也应写入规范值;其 Native 渲染器可以解释该状态,例如进程以非零状态退出。 - **遵守 `exec.signal`。** 信号触发时取消进行中的工作。 -- **使用 `meta` 附加持久化的卡片数据(可选)。** `execute` 可以返回 `{ content, meta }` 而非裸的 `ContentBlock[]`。`meta` 是 JSON 可序列化的载荷,核心将其视为不透明数据,持久化在 `tool/result` 事件上并回传给你的 `presentResult`(这样需要 `args` 之外信息的卡片——如 `write`/`edit` 的已应用 hunk diff——在会话回放中依然存活)。仅在此处放 UI 数据,绝不放入模型可见的 `content`。 +- **使用 `presentationMeta` 投影持久化的卡片数据(可选)。** `output.presentationMeta(args, value)` 从同一个规范值派生可回放的 JSON。核心将其持久化在 `tool/result` 上并传给 `presentResult`,因此需要结果期事实的卡片——例如 `write`/`edit` 的已应用 hunk——无需持久化规范值也能在回放中重现。嵌套 Code 分发没有卡片,因此会跳过该投影器。 - **使用 `exec.agent` 发送异步通知。** `agent.inject(content, {source: {kind: 'plugin', plugin: '<name>'}})` 追加持久化上下文,下一次模型请求会看到它——这不是唤醒(空闲的 agent(智能体)保持空闲)。请防范已 dispose 的 agent(try/catch)。 ## 长时间运行的工作 @@ -51,7 +56,7 @@ producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的 ## 执行策略与观测 -尽量不要把部署策略内建到工具中。使用 `tools/pre-execute` 实现可扩展的允许/拒绝/询问策略(见[权限门禁示例](extension-cookbook.md#a-hook-plugin-permission-gate-example));使用 `ctx.tools.guard()` 设置最终的单调拒绝(后续监听器无法撤销);使用 `tools/execute` 为核心分发包装截止时间/重试/指标作用域;使用 `tools/post-execute` 转换或附加模型可见的上下文;使用 `tools/result` 观测不可变的归一化结果而不改变它。沙箱实现也可以位于工具执行器的能力 seam 之后;确切契约见 [`dsh-tools` README](../../packages/core/tools/README.md#extension-points)。 +尽量不要把部署策略内建到工具中。使用 `tools/pre-execute` 实现可扩展的允许/拒绝/询问策略(见[权限门禁示例](extension-cookbook.md#a-hook-plugin-permission-gate-example));使用 `ctx.tools.guard()` 设置最终的单调拒绝,后续监听器无法撤销;使用 `tools/execute` 为规范分发包装截止时间/重试/指标作用域;使用 `tools/post-execute` 替换展示内容或规范值、阻止调用,或附加模型可见上下文;使用 `tools/result` 观测不可变的归一化结果而不改变它。替换内容不会阻止程序化访问 `value`;保密策略必须阻止调用或替换值。沙箱实现也可以位于工具执行器的能力 seam 之后;确切契约见 [`dsh-tools` README](../../packages/core/tools/README.md#extension-points)。 ## Code Mode 自动触达你的工具 @@ -59,7 +64,7 @@ producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的 ## 工具在编辑器中的渲染方式(ACP 展示) -工具的 `execute` 返回模型可见的内容;其**编辑器卡片**是一个独立的、可选的关注点,通过 `defineTool` 选项中的两个纯展示方法声明。请与 `execute` 同步设计,而非事后补充——编辑器(如 Zed,通过 ACP(Agent Client Protocol)桥接)会展示该卡片,没有展示方法的工具回退为一个朴素的通用卡片(标题 = 工具名,原始 args 作为输入)。 +工具的 `output.render` 返回模型可见的内容;其**编辑器卡片**是另一项独立关注点,通过纯展示投影以及可选的 `presentCall`/`presentResult` 方法声明。请将这些内容与规范值一并设计:编辑器(如 Zed,通过 ACP(Agent Client Protocol)桥接)会展示该卡片,没有 UI 展示方法的工具则回退到通用卡片(标题 = 工具名,原始 args 作为输入)。 两个方法都返回一个 **`card` 标签的渲染意图**——选择与你的工具行为匹配的卡片类型: @@ -70,16 +75,16 @@ producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的 - `presentResult(args, { content, isError, meta? })` 返回完成后的卡片: - `generic` 提供可选的标题和内容。 - `terminal` 提供原始输出和可选的退出元数据;桥接层渲染能力特定或围栏回退视图。 - - `diff` 提供已应用的 hunk,通常由持久化的 `result.meta` 携带,使回放能重现它们。变更类工具保留 diff 结果,因为 ACP 更新会替换 pending 卡片的内容。 + - `diff` 提供已应用的 hunk,通常由 `output.presentationMeta` 派生并通过持久化的 `result.meta` 携带,使回放能重现它们。变更类工具保留 diff 结果,因为 ACP 更新会替换 pending 卡片的内容。 硬性规则(违反会出问题): - **纯函数。** 这些方法在实时流式输出和会话日志回放时都会运行,因此必须是 `args`(加 result)的纯函数——不做 I/O、不读会话状态、不用时钟/随机数。diff 从 args 派生(`write` 使用 `oldText: null`,因为调用时的展示器没有文件先前内容);**桥接层**(而非工具)填充会话 cwd 并相对化展示路径标题。如果你发现自己想在 `presentCall` 内获取文件旧内容或工作目录,请停下——那属于桥接层或未来的 result-event 形态,不属于展示器。 -- **UI 格式不进入模型结果。** 围栏 ` ```console ` 块、diff、相对化路径——这些都不得出现在 `execute` 返回给模型的内容中;它们只存在于展示层。(`terminal` 结果视图携带原始 `output`;桥接层添加围栏。) +- **UI 格式不进入模型结果。** 围栏 ` ```console ` 块、diff、相对化路径均不应仅为服务编辑器而进入规范值或 Native 内容。`output.render` 负责模型可见的自然语言;`presentationMeta` 和卡片展示器负责可回放的 UI 状态。`terminal` 结果视图携带原始输出,由桥接层添加围栏。 - **`defineTool` 对展示路径做软校验。** 格式错误或旧版日志中的 arg 形态会使包装器返回 `undefined`(通用回退)而非抛异常——展示绝不能导致回放崩溃。 中性词汇定义在 `dsh-tools` 中(绝不在工具中导入 ACP 类型);ACP 桥接层将每个 `card` 映射到协议格式(wire format)。设计与原因见[渲染意图联合体 Agent Note](../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md);`dsh-tool-fs`(generic/diff)和 `dsh-tool-bash`(terminal)是参考实现。 ## 每个工具必须的测试 -覆盖参数拒绝、每种结果形态和 HMR dispose。对于有副作用的工具,使用脚本化的 `MockAdapter` 驱动真实工具通过 agent loop(智能体循环),并断言其 `tool/call` 和 `tool/result` 会话事件。对于编辑器卡片,断言 `presentCall` 和 `presentResult` 的精确视图,并通过真实桥接层添加一个 [ACP 快照](../../.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md);终端卡片的场景设置 `terminalOutput: true` 以覆盖 capable-client 路径。 +覆盖参数拒绝、每种规范值和 Native 渲染形态、输出 schema 拒绝以及 HMR dispose。对于有副作用的工具,使用脚本化的 `MockAdapter` 驱动真实工具通过 agent loop(智能体循环),并断言其 `tool/call` 和投影后的 `tool/result` 会话事件;同时证明规范值本身未被持久化。对于编辑器卡片,断言 `presentCall` 和 `presentResult` 的精确视图,并通过真实桥接层添加一个 [ACP 快照](../../.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md);终端卡片的场景设置 `terminalOutput: true` 以覆盖 capable-client 路径。 diff --git a/docs/cordis-catalog/events.md b/docs/cordis-catalog/events.md index cde1c4340b..2b995146ce 100644 --- a/docs/cordis-catalog/events.md +++ b/docs/cordis-catalog/events.md @@ -760,7 +760,7 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai 'tools/change'(): void ``` -Source: [`packages/core/tools/src/index.ts:131`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:135`](../../packages/core/tools/src/index.ts) ### `tools/execute` — waterfall @@ -780,7 +780,7 @@ Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a nor Types: [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:104`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:108`](../../packages/core/tools/src/index.ts) ### `tools/post-execute` — waterfall @@ -800,7 +800,7 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts Types: [PostToolDecision](../core-data-structures/tools.md) · [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:113`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:117`](../../packages/core/tools/src/index.ts) ### `tools/pre-execute` — waterfall @@ -819,7 +819,7 @@ Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approv Types: [PreToolDecision](../core-data-structures/tools.md) · [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:95`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:99`](../../packages/core/tools/src/index.ts) ### `tools/result` — emit @@ -838,7 +838,7 @@ Observe the frozen, lossless-JSON final outcome. Listener failures are contained Types: [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:121`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:125`](../../packages/core/tools/src/index.ts) ## `workflow/*` diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 48feaa92a6..53180d3621 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -1361,7 +1361,7 @@ async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult> Types: [ScopeKey](../core-data-structures/scope.md) · [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolGuard](../core-data-structures/tools.md) · [ToolRestriction](../core-data-structures/tools.md) · [ToolSchema](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:453`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:504`](../../packages/core/tools/src/index.ts) ## `ctx.userInteraction` — `UserInteractionService` diff --git a/docs/core-data-structures/session.md b/docs/core-data-structures/session.md index 8650688222..2df677790b 100644 --- a/docs/core-data-structures/session.md +++ b/docs/core-data-structures/session.md @@ -73,15 +73,24 @@ interface SessionEventMap { */ 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string } /** - * A completed tool call's model-facing result, plus an optional tool-private - * `meta` presentation payload. `meta` is opaque to the core (`unknown` — the - * producing tool owns its shape and reads it back in `presentResult`) but MUST - * be JSON-serializable: `Session.append` runtime-validates all event data with - * `isJsonValue`, so a non-serializable `meta` is rejected at the source, and the - * durable log reproduces the identical card on replay. Absent unless the tool - * attaches one (e.g. `dsh-tool-fs` carries its result-time contextual diff here). + * A completed tool call's model-facing result, canonical failure detail, and + * optional tool-private `meta` presentation payload. `meta` is opaque to the + * core (the producing tool owns its shape and reads it back in `presentResult`) + * but MUST be JSON-serializable: `Session.append` runtime-validates all event + * data with `isJsonValue`, so a non-serializable `meta` is rejected at the + * source, and the durable log reproduces the identical card on replay. Absent + * unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time + * contextual diff here). */ - 'tool/result': { turn: number; step: number; callId: CallId; content: ContentBlock[]; isError: boolean; error?: { name: string; code: string }; meta?: unknown } + 'tool/result': { + turn: number + step: number + callId: CallId + content: ContentBlock[] + isError: boolean + error?: { message: string; info?: { name: string; code: string } } + meta?: JsonValue + } /** Steering content injected between steps of a running turn. */ 'steering/message': { turn: number; content: ContentBlock[]; source: MessageSource } /** Whole-list snapshot; latest write wins on replay. Log-only UI state; never derived history. */ diff --git a/docs/core-data-structures/tools.md b/docs/core-data-structures/tools.md index 20a74e0190..6ec941d0df 100644 --- a/docs/core-data-structures/tools.md +++ b/docs/core-data-structures/tools.md @@ -6,12 +6,27 @@ Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index ## `ToolDefinition` — a registered tool -A `ToolSchema` (the model-facing fields) plus the `execute` function, host-only scheduler metadata, and optional UI presenters. The registry holds these; the loop dispatches calls through them. The registry's `schemas()` builds the model-facing `ToolSchema[]` by an explicit allowlist — `execute`/`timeoutMs`/`isConcurrencySafe`/`presentCall`/`presentResult` must never leak into a model request. +A `ToolSchema` (the model-facing fields) plus a mandatory canonical output declaration, the `execute` function, host-only scheduler metadata, and optional UI presenters. The registry holds these; the loop dispatches calls through them. The registry's `schemas()` builds the model-facing `ToolSchema[]` by an explicit allowlist — `output`/`execute`/`timeoutMs`/`isConcurrencySafe`/`presentCall`/`presentResult` must never leak into a model request. + +```ts type-equiv +/** Tool-owned canonical output contract used after the body returns a JSON value. */ +interface ToolOutputDefinition { + /** Raw supported JSON Schema enforced against every successful canonical value. */ + readonly schema: JsonSchemaNode + /** Pure projection from validated arguments and value to Native/model content. */ + render(args: unknown, value: JsonValue): ContentBlock[] + /** Pure replayable presentation projection, computed only for surface calls. */ + presentationMeta?(args: unknown, value: JsonValue): JsonValue +} +``` ```ts type-equiv /** A registered tool: its schema plus the execution function. */ interface ToolDefinition extends ToolSchema { - execute(args: unknown, exec: ToolRunContext): Promise<ToolExecuteReturn> + /** Mandatory canonical output declaration. */ + readonly output: ToolOutputDefinition + /** Execute the tool and return only its canonical lossless-JSON value. */ + execute(args: unknown, exec: ToolRunContext): Promise<unknown> /** * Cooperative tool-call timeout budget in milliseconds. Omit for no deadline. * Enforced by `@deepseek-ai/dsh-timeout-policy` (a `tools/execute` wrapper); it @@ -46,7 +61,7 @@ interface ToolDefinition extends ToolSchema { presentCall?(args: unknown): ToolCallView | undefined /** * Optional: how to present the COMPLETED state, given the same `args` and the - * `result` (`execute`'s content + whether it errored). Returns a + * durable result projection (`content`, failure state, and optional `meta`). Returns a * {@link ToolResultView}, or `undefined` (or omit the method) to keep the * pending title and render the raw result content. Pure and side-effect-free * for the same replay reason. @@ -55,7 +70,7 @@ interface ToolDefinition extends ToolSchema { } ``` -`execute` receives `args: unknown` — a raw `ToolDefinition` validates its own input. First-party tools don't write that by hand; they use `defineTool`, which validates and narrows for them. +`execute` receives `args: unknown` — a raw `ToolDefinition` validates its own input. First-party tools don't write that by hand; they use `defineTool`, which validates and narrows the arguments, infers the body return from `output.schema`, and types both output projectors. ## The unified JSON-value schema DSL @@ -97,27 +112,28 @@ type ParameterSchemaSpec = Record<string, ParameterPropertySpec> * Infer the TypeScript value accepted by an author-facing value schema. * Output schemas may therefore infer object, array, scalar, or null roots. */ -type InferValue<S extends ValueSchemaSpec> = - S extends StringValueSchemaSpec ? InferScalar<S, string> : - S extends NumberValueSchemaSpec | IntegerValueSchemaSpec ? InferScalar<S, number> : - S extends BooleanValueSchemaSpec ? InferScalar<S, boolean> : - S extends NullValueSchemaSpec ? null : - S extends ArrayValueSchemaSpec - ? S extends { items: infer I extends ValueSchemaSpec } ? InferValue<I>[] : JsonValue[] - : S extends ObjectValueSchemaSpec ? InferObject<S> : - S extends JsonValueSchemaSpec ? JsonValue : - S extends OneOfValueSchemaSpec ? InferValue<S['oneOf'][number]> : - never +type InferValue<S extends ValueSchemaSpec, D extends readonly unknown[] = readonly []> = + D['length'] extends 12 ? JsonValue : + S extends StringValueSchemaSpec ? InferScalar<S, string> : + S extends NumberValueSchemaSpec | IntegerValueSchemaSpec ? InferScalar<S, number> : + S extends BooleanValueSchemaSpec ? InferScalar<S, boolean> : + S extends NullValueSchemaSpec ? null : + S extends ArrayValueSchemaSpec + ? S extends { items: infer I extends ValueSchemaSpec } ? InferValue<I, NextDepth<D>>[] : JsonValue[] + : S extends ObjectValueSchemaSpec ? InferObject<S, NextDepth<D>> : + S extends JsonValueSchemaSpec ? JsonValue : + S extends OneOfValueSchemaSpec ? InferValue<S['oneOf'][number], NextDepth<D>> : + never ``` ```ts type-equiv /** Infer the TypeScript argument object for an implicit parameter schema. */ -type InferArgs<S extends ParameterSchemaSpec> = InferProperties<S> +type InferArgs<S extends ParameterSchemaSpec> = InferProperties<S, readonly []> ``` -`defineTool({ name, description, parameters, execute, … })` ties parameter inference to `parameterSchemaSpecToJsonSchema()` and `validateArgs()`. `valueSchemaSpecToJsonSchema()` compiles value/output declarations through the same enforced raw subset. A parameter mismatch throws `ToolArgsError` (`INVALID_ARGS`), which the registry returns through the normal tool-error path. Raw JSON Schema remains open by default; unsupported keywords reject instead of being accepted without enforcement. +`defineTool({ name, description, parameters, output, execute, … })` ties parameter inference to `parameterSchemaSpecToJsonSchema()` and `validateArgs()`, and ties `execute`/`render`/`presentationMeta` to `InferValue<OutputSchema>`. Inference widens to `JsonValue` after twelve nested nodes so large schemas remain compilable; runtime validation keeps walking the complete schema. `valueSchemaSpecToJsonSchema()` compiles output declarations through the same enforced raw subset. A parameter mismatch throws `ToolArgsError` (`INVALID_ARGS`); an invalid body or post-policy value throws `ToolOutputError` (`INVALID_TOOL_OUTPUT`). Both use the normal tool-error path. Raw JSON Schema remains open by default; unsupported keywords reject instead of being accepted without enforcement. -Registration is a trusted same-process contract. The registry borrows the typed definition as readonly input and validates only semantic requirements such as a positive finite `timeoutMs`; `schemas()` materializes the explicit model-facing projection at the model boundary so execution and presentation share one resolved definition without leaking callbacks onto the wire. +Registration is a trusted same-process contract. The registry borrows the typed definition as readonly input, requires `output`, validates its raw schema, and checks semantic requirements such as a positive finite `timeoutMs`; `schemas()` materializes the explicit model-facing projection at the model boundary so execution and presentation share one resolved definition without leaking callbacks onto the wire. ## `ToolRestriction` — one scope's live global filter @@ -230,34 +246,48 @@ type ToolGuard = (execution: Readonly<ToolExecution>) => string | undefined ``` ```ts type-equiv -/** The outcome of one tool call. */ -interface ToolExecutionResult { - content: ContentBlock[] - isError: boolean - /** - * Set when the call failed with a {@link HarnessError}: machine-routable - * `{ name, code }` for retry/sandbox plugins and replay. The model-facing - * text in `content` is always present; this is extra structure for code. - */ - error?: ToolErrorInfo - /** - * Model-facing context for the next request, separate from this tool result. The loop - * accepts it into the active-batch FIFO, then appends after recorded results even if interrupted. - */ - additionalContexts?: HookContext[] - /** - * The tool-private presentation payload from a successful `execute` (the object - * return form). Threaded onto the `tool/result` session event and back into - * {@link ToolResult} for `presentResult`. Opaque (`unknown`); absent when the - * tool attached none or the call failed. - */ - meta?: unknown +/** Canonical failure detail; internal routing information remains optional. */ +interface ToolFailure { + /** Human-readable failure message without the Native `Error: ` envelope. */ + message: string + /** Internal error class/code used by policy and durable diagnostics. */ + info?: ToolErrorInfo } ``` -The result carries only the outcome. Call identity remains on the immutable `ToolExecution` that accompanies it through every hook and on the durable `tool/call` / `tool/result` session events, so wrappers cannot create a second, disagreeing identity. +```ts type-equiv +/** Successful canonical tool execution, including its Native/model projection. */ +interface ToolExecutionSuccess { + readonly isError: false + /** Execution-local canonical value; deliberately omitted from durable events. */ + readonly value: JsonValue + readonly content: ContentBlock[] + readonly error?: never + readonly meta?: JsonValue + readonly additionalContexts?: HookContext[] +} +``` -The registry materializes and freezes the final accepted result immediately before `tools/result`. Its content, structured error, additional context, and presentation metadata must round-trip losslessly through JSON; an invalid outcome becomes a JSON-safe `isError` result, so the observed live outcome is safe for the later durable `tool/result` append. +```ts type-equiv +/** Failed canonical tool execution; failures never carry a successful value. */ +interface ToolExecutionFailure { + readonly isError: true + readonly error: ToolFailure + readonly value?: never + readonly content: ContentBlock[] + readonly meta?: JsonValue + readonly additionalContexts?: HookContext[] +} +``` + +```ts type-equiv +/** The discriminated, execution-local outcome of one tool call. */ +type ToolExecutionResult = ToolExecutionSuccess | ToolExecutionFailure +``` + +The result carries only the outcome. Call identity remains on the immutable `ToolExecution` that accompanies it through every hook and on the durable `tool/call` / `tool/result` session events, so wrappers cannot create a second, disagreeing identity. The canonical `value` is execution-local: the loop persists only `content`, `error`, and `meta`, while `tool/code-dispatch` stores a bounded summary. Replay reproduces presentation but cannot reconstruct intermediate values. + +On success the registry snapshots and validates the body value, freezes it, and invokes the pure renderer plus the optional direct-surface metadata projector. It separately materializes the durable presentation fields immediately before `tools/result`; an invalid value, renderer/projector failure, or non-JSON presentation becomes a JSON-safe `isError`. The final live observer therefore sees the exact execution-local value beside fields safe for the later durable append. Each interception waterfall returns a typed **Decision** (the idiom shared with the `agent/*` seams). `tools/pre-execute` listeners receive `(exec, next)` and return a `PreToolDecision`; `tools/execute` wrappers return a `ToolExecutionResult`; `tools/post-execute` listeners receive `(exec, result, next)` and return a `PostToolDecision`: @@ -276,17 +306,18 @@ type PreToolDecision = ```ts type-equiv /** - * Post-dispatch decision: accept or replace content, attach context for the next - * request, or block by turning corrective feedback into an error result. + * Post-dispatch decision: accept, replace one projection, attach context for the + * next request, or block by turning corrective feedback into an error result. */ type PostToolDecision = - | { kind: 'accept'; content?: ContentBlock[]; additionalContexts?: HookContext[] } + | { kind: 'accept'; content?: ContentBlock[]; value?: never; additionalContexts?: HookContext[] } + | { kind: 'accept'; value: JsonValue; content?: never; additionalContexts?: HookContext[] } | { kind: 'block'; feedback: ContentBlock[]; additionalContexts?: HookContext[] } ``` Call `next()` for the default or return a decision to short-circuit. Pre-policy may deny or ask; only `allowed-once` proceeds, while a non-grant, missing approval channel or service, or agent-less request becomes a denial. Guards may still impose a final denial. Arguments cannot be rewritten because history, audit, UI, and execution must agree. -Post-policy may replace content; a block becomes an `isError` result containing its corrective feedback. `tools/result` receives the frozen execution and result after normalization; observers cannot transform them, and observer failures are contained. Unknown and throwing tools both become structured errors (`ToolNotFoundError` maps to `UNKNOWN_TOOL`), so the call fails without ending the turn. +Post-policy may replace either content or value, never both. Content replacement preserves the canonical value and existing metadata; value replacement is revalidated and recomputes content/metadata; a block removes the value and becomes an `isError` containing corrective feedback. Content replacement is presentation policy, not confidentiality policy: a listener that must hide the programmatic value blocks or replaces it. `tools/result` receives the frozen execution and result after normalization; observers cannot transform them, and observer failures are contained. Unknown and throwing tools both become structured errors (`ToolNotFoundError` maps to `UNKNOWN_TOOL`), so the call fails without ending the turn. ## The enforced raw JSON Schema subset diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index 6185522793..f84eee5ac7 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -41,11 +41,11 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:130`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude) | | `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:27`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`acp`](../packages/ui/acp) | | `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:33`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - | -| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:131`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | -| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:104`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`timeout-policy`](../packages/timeout/timeout-policy) | -| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:113`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`workspace-context`](../packages/context/workspace-context) | -| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:95`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | -| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:121`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | +| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:135`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | +| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:108`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`timeout-policy`](../packages/timeout/timeout-policy) | +| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:117`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-fs-search`](../packages/fs/tool-fs-search), [`workspace-context`](../packages/context/workspace-context) | +| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:99`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | +| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:125`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:81`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | | `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:70`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | | `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:91`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md index 80b0b7196d..9ca545854c 100644 --- a/docs/persistence-catalog.md +++ b/docs/persistence-catalog.md @@ -79,7 +79,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = { }[T] ``` -Sources: [`packages/core/session/src/types.ts:267`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:274`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:304`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:336`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:276`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:283`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:313`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:345`](../packages/core/session/src/types.ts) ## Events @@ -356,7 +356,7 @@ Source: [`packages/core/session/src/types.ts:213`](../packages/core/session/src/ 'request/header': { header: EpochHeader; reason: RequestHeaderReason } ``` -Source: [`packages/core/session/src/types.ts:263`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:272`](../packages/core/session/src/types.ts) ### `sandbox/*` @@ -387,7 +387,7 @@ Source: [`packages/sandbox/sandbox-policy/src/session-mode.ts:34`](../packages/s Types: [ContentBlock](core-data-structures/core.md) · [MessageSource](core-data-structures/core.md) -Source: [`packages/core/session/src/types.ts:256`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:265`](../packages/core/session/src/types.ts) ### `step/*` @@ -420,7 +420,7 @@ Source: [`packages/core/session/src/types.ts:204`](../packages/core/session/src/ Types: [TodoItem](core-data-structures/session.md) -Source: [`packages/core/session/src/types.ts:258`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:267`](../packages/core/session/src/types.ts) ### `tool/*` @@ -468,20 +468,29 @@ Source: [`packages/core/tools/src/code-mode.ts:34`](../packages/core/tools/src/c ```ts persistence-catalog /** - * A completed tool call's model-facing result, plus an optional tool-private - * `meta` presentation payload. `meta` is opaque to the core (`unknown` — the - * producing tool owns its shape and reads it back in `presentResult`) but MUST - * be JSON-serializable: `Session.append` runtime-validates all event data with - * `isJsonValue`, so a non-serializable `meta` is rejected at the source, and the - * durable log reproduces the identical card on replay. Absent unless the tool - * attaches one (e.g. `dsh-tool-fs` carries its result-time contextual diff here). + * A completed tool call's model-facing result, canonical failure detail, and + * optional tool-private `meta` presentation payload. `meta` is opaque to the + * core (the producing tool owns its shape and reads it back in `presentResult`) + * but MUST be JSON-serializable: `Session.append` runtime-validates all event + * data with `isJsonValue`, so a non-serializable `meta` is rejected at the + * source, and the durable log reproduces the identical card on replay. Absent + * unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time + * contextual diff here). */ -'tool/result': { turn: number; step: number; callId: CallId; content: ContentBlock[]; isError: boolean; error?: { name: string; code: string }; meta?: unknown } +'tool/result': { + turn: number + step: number + callId: CallId + content: ContentBlock[] + isError: boolean + error?: { message: string; info?: { name: string; code: string } } + meta?: JsonValue +} ``` Types: [CallId](core-data-structures/core.md) · [ContentBlock](core-data-structures/core.md) -Source: [`packages/core/session/src/types.ts:254`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:255`](../packages/core/session/src/types.ts) ### `turn/*` diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md index eaf24e38a7..fa75d4dd17 100644 --- a/docs/tool-catalog.md +++ b/docs/tool-catalog.md @@ -203,7 +203,7 @@ Source: [`packages/cordis/tool-cordis/src/index.ts`](../packages/cordis/tool-cor ### `cordis_mount` -Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, async execute(args) { … } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return an ARRAY of content blocks, e.g. `return [{ type: 'text', text: someString }]` — never a bare string. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime. +Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, output: { schema: { type: 'string' }, render(_args, value) { return [{ type: 'text', text: value }] } }, async execute(args) { return args.text } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return the lossless JSON value declared by `output.schema`; `output.render(args, value)` separately returns Native/model content blocks. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime. ```json { diff --git a/docs/user/develop/basic/index.i18n.yaml b/docs/user/develop/basic/index.i18n.yaml index 711715a5de..a6ab84c3e0 100644 --- a/docs/user/develop/basic/index.i18n.yaml +++ b/docs/user/develop/basic/index.i18n.yaml @@ -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 -index.md: d7d657ff7b8cb9001dd5e9c3af658a7a3c45b5b7 -index.zh.md: 7a134f7aaed470b87ee8ca8978dd39593de2651b +index.md: 5a9f8dfb8f2d87dfbd2ba30b4d09d002ae9b635c +index.zh.md: 08aca87cbc02d1b0dfbe6fe2d92b3f6e87075097 diff --git a/docs/user/develop/basic/index.md b/docs/user/develop/basic/index.md index d7d657ff7b..5a9f8dfb8f 100644 --- a/docs/user/develop/basic/index.md +++ b/docs/user/develop/basic/index.md @@ -138,8 +138,12 @@ export function apply(ctx: Context) { parameters: { name: { type: 'string', required: true }, }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args) { - return [{ type: 'text', text: `Hello, ${args.name}!` }] + return `Hello, ${args.name}!` }, })) } diff --git a/docs/user/develop/basic/index.zh.md b/docs/user/develop/basic/index.zh.md index 7a134f7aae..08aca87cbc 100644 --- a/docs/user/develop/basic/index.zh.md +++ b/docs/user/develop/basic/index.zh.md @@ -138,8 +138,12 @@ export function apply(ctx: Context) { parameters: { name: { type: 'string', required: true }, }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args) { - return [{ type: 'text', text: `Hello, ${args.name}!` }] + return `Hello, ${args.name}!` }, })) } diff --git a/docs/user/develop/basic/tool.i18n.yaml b/docs/user/develop/basic/tool.i18n.yaml index b741ccf65f..73970f99d8 100644 --- a/docs/user/develop/basic/tool.i18n.yaml +++ b/docs/user/develop/basic/tool.i18n.yaml @@ -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 -tool.md: 17adbfc5f7eb804856dfe39b4d2b4a65374b6414 -tool.zh.md: 8857e16ca836dfa5b158a68581bd3c715dcb1ac5 +tool.md: 7b211cfef54306f7c316dc08da1df759dcbf1b06 +tool.zh.md: 214b35b28de0c647737bc8297b13b4997947b52e diff --git a/docs/user/develop/basic/tool.md b/docs/user/develop/basic/tool.md index 17adbfc5f7..7b211cfef5 100644 --- a/docs/user/develop/basic/tool.md +++ b/docs/user/develop/basic/tool.md @@ -20,9 +20,13 @@ export function apply(ctx: Context) { parameters: { name: { type: 'string', required: true, description: 'The name to greet' }, }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args) { // args is inferred as { name: string }. - return [{ type: 'text', text: `Hello, ${args.name}!` }] + return `Hello, ${args.name}!` }, })) } @@ -107,33 +111,45 @@ export const tool = defineTool({ name: 'example', description: 'Return an example result.', parameters: {}, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args, exec) { // args: inferred from parameters // exec: ToolExecution context - // Return a ContentBlock array. + // Return the value declared by output.schema. void args void exec - return [{ type: 'text', text: 'result here' }] + return 'result here' }, }) ``` ### Return value -`execute` returns a `ContentBlock[]` that becomes the tool result visible to the model: +`execute` returns the lossless JSON value declared by `output.schema`. `output.render(args, value)` separately turns that validated value into the Native/model-facing content: ```ts ignore-check -// Text result -return [{ type: 'text', text: 'file content here...' }] - -// Multiple blocks -return [ - { type: 'text', text: 'Found 3 matches:' }, - { type: 'text', text: matchResults.join('\n') }, -] +output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + path: { type: 'string', required: true }, + content: { type: 'string', required: true }, + }, + }, + render: (_args, value) => [{ type: 'text', text: value.content }], +}, +async execute(args) { + return { path: args.path, content: await readFile(args.path, 'utf8') } +} ``` +The canonical value is available to execution-time programmatic callers and is not persisted in `tool/result`; the rendered content and optional `presentationMeta` are the replayable projections. A body value that does not satisfy the schema, or is not lossless JSON, becomes an `INVALID_TOOL_OUTPUT` failure. + ### Argument validation Before calling `execute`, `defineTool` validates model-generated arguments. Invalid input raises `ToolArgsError`; the framework turns it into an `isError` result so the model can correct its call. @@ -148,6 +164,10 @@ A tool can define UI presentation methods for terminal and ACP clients: defineTool({ name: 'bash', // ... + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, presentCall(args) { return { card: 'terminal', @@ -196,13 +216,24 @@ export function apply(ctx: Context) { path: { type: 'string', required: true, description: 'Directory path' }, extension: { type: 'string', description: 'Filter by extension (e.g. ".ts")' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + count: { type: 'integer', required: true }, + files: { type: 'array', required: true, items: { type: 'string' } }, + }, + }, + render: (_args, value) => [{ type: 'text', text: `Found ${value.count} files.` }], + }, async execute(args) { const entries = await readdir(args.path, { withFileTypes: true }) let files = entries.filter(e => e.isFile()) if (args.extension) { files = files.filter(f => f.name.endsWith(args.extension!)) } - return [{ type: 'text', text: `Found ${files.length} files.` }] + return { count: files.length, files: files.map(file => file.name) } }, })) } diff --git a/docs/user/develop/basic/tool.zh.md b/docs/user/develop/basic/tool.zh.md index 8857e16ca8..214b35b28d 100644 --- a/docs/user/develop/basic/tool.zh.md +++ b/docs/user/develop/basic/tool.zh.md @@ -20,9 +20,13 @@ export function apply(ctx: Context) { parameters: { name: { type: 'string', required: true, description: 'The name to greet' }, }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args) { // args is inferred as { name: string }. - return [{ type: 'text', text: `Hello, ${args.name}!` }] + return `Hello, ${args.name}!` }, })) } @@ -107,33 +111,45 @@ export const tool = defineTool({ name: 'example', description: 'Return an example result.', parameters: {}, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args, exec) { // args: inferred from parameters // exec: ToolExecution context - // Return a ContentBlock array. + // Return the value declared by output.schema. void args void exec - return [{ type: 'text', text: 'result here' }] + return 'result here' }, }) ``` ### 返回值 -`execute` 必须返回一个 `ContentBlock[]`,告诉模型 tool 的执行结果: +`execute` 返回由 `output.schema` 声明的无损 JSON 值。`output.render(args, value)` 会将经过校验的值另外转换为 Native/模型可见的内容: ```ts ignore-check -// Text result -return [{ type: 'text', text: 'file content here...' }] - -// Multiple blocks -return [ - { type: 'text', text: 'Found 3 matches:' }, - { type: 'text', text: matchResults.join('\n') }, -] +output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + path: { type: 'string', required: true }, + content: { type: 'string', required: true }, + }, + }, + render: (_args, value) => [{ type: 'text', text: value.content }], +}, +async execute(args) { + return { path: args.path, content: await readFile(args.path, 'utf8') } +} ``` +执行期间的程序化调用方可以使用规范值,但 `tool/result` 不会持久化该值;渲染后的内容和可选的 `presentationMeta` 才是可回放的投影。工具主体返回的值若不满足 schema 或不是无损 JSON,就会变为 `INVALID_TOOL_OUTPUT` 失败。 + ### 参数校验 `defineTool` 在调用 `execute` 之前会自动校验模型生成的参数。如果参数不合法,会抛出 `ToolArgsError`,框架将其转换为 `isError` 结果返回给模型,让模型自行修正。 @@ -148,6 +164,10 @@ Tool 可以定义 UI 渲染方法,用于在终端或 ACP 客户端中展示 to defineTool({ name: 'bash', // ... + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, presentCall(args) { return { card: 'terminal', @@ -196,13 +216,24 @@ export function apply(ctx: Context) { path: { type: 'string', required: true, description: 'Directory path' }, extension: { type: 'string', description: 'Filter by extension (e.g. ".ts")' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + count: { type: 'integer', required: true }, + files: { type: 'array', required: true, items: { type: 'string' } }, + }, + }, + render: (_args, value) => [{ type: 'text', text: `Found ${value.count} files.` }], + }, async execute(args) { const entries = await readdir(args.path, { withFileTypes: true }) let files = entries.filter(e => e.isFile()) if (args.extension) { files = files.filter(f => f.name.endsWith(args.extension!)) } - return [{ type: 'text', text: `Found ${files.length} files.` }] + return { count: files.length, files: files.map(file => file.name) } }, })) } diff --git a/docs/user/develop/practice/index.i18n.yaml b/docs/user/develop/practice/index.i18n.yaml index d2478abf75..799dffc1c6 100644 --- a/docs/user/develop/practice/index.i18n.yaml +++ b/docs/user/develop/practice/index.i18n.yaml @@ -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 -index.md: 0261b49b071167f7c2a33f78bbc1959cc6f1879f -index.zh.md: 5819344430fcbde31bf825e9815120983e44e3f6 +index.md: e197d499d7f5bd9911ea60bebf584251cd4ed915 +index.zh.md: 8b8d08f9d0c6d0ca8d95fbaa3281c98b7a600fe4 diff --git a/docs/user/develop/practice/index.md b/docs/user/develop/practice/index.md index 0261b49b07..e197d499d7 100644 --- a/docs/user/develop/practice/index.md +++ b/docs/user/develop/practice/index.md @@ -132,9 +132,13 @@ export function apply(ctx: Context) { parameters: { input: { type: 'string', required: true }, }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args) { const result = await ctx.myCap.execute({ input: args.input }) - return [{ type: 'text', text: result.output }] + return result.output }, })) } diff --git a/docs/user/develop/practice/index.zh.md b/docs/user/develop/practice/index.zh.md index 5819344430..8b8d08f9d0 100644 --- a/docs/user/develop/practice/index.zh.md +++ b/docs/user/develop/practice/index.zh.md @@ -132,9 +132,13 @@ export function apply(ctx: Context) { parameters: { input: { type: 'string', required: true }, }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args) { const result = await ctx.myCap.execute({ input: args.input }) - return [{ type: 'text', text: result.output }] + return result.output }, })) } diff --git a/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md index 3e111b8ba2..e463aff141 100644 --- a/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md @@ -63,7 +63,7 @@ declare const tools: { /** Exact service key or event name whose original JSDoc to include; valid only with what:"api" or what:"events". */ name?: string; } & Record<string, JsonValue>): Promise<string>; - /** Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, async execute(args) { … } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return an ARRAY of content blocks, e.g. `return [{ type: 'text', text: someString }]` — never a bare string. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime. */ + /** Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, output: { schema: { type: 'string' }, render(_args, value) { return [{ type: 'text', text: value }] } }, async execute(args) { return args.text } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return the lossless JSON value declared by `output.schema`; `output.render(args, value)` separately returns Native/model content blocks. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime. */ cordis_mount(args: { /** Body of an async JS function; must `return` the plugin to mount. */ code: string; diff --git a/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json index 95cdd43b83..487af4392e 100644 --- a/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json @@ -72,7 +72,7 @@ }, { "name": "cordis_mount", - "description": "Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:\"api\" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:\"events\"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, async execute(args) { … } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return an ARRAY of content blocks, e.g. `return [{ type: 'text', text: someString }]` — never a bare string. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:\"api\" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime.", + "description": "Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:\"api\" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:\"events\"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, output: { schema: { type: 'string' }, render(_args, value) { return [{ type: 'text', text: value }] } }, async execute(args) { return args.text } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return the lossless JSON value declared by `output.schema`; `output.render(args, value)` separately returns Native/model content blocks. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:\"api\" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime.", "parameters": { "type": "object", "properties": { diff --git a/examples/acp-agent/tests/snapshots/cancel-tool-calls/session.jsonl b/examples/acp-agent/tests/snapshots/cancel-tool-calls/session.jsonl index cdb76be163..db08475efd 100644 --- a/examples/acp-agent/tests/snapshots/cancel-tool-calls/session.jsonl +++ b/examples/acp-agent/tests/snapshots/cancel-tool-calls/session.jsonl @@ -13,8 +13,8 @@ {"type":"assistant/chunk","seq":11,"time":1784437195077,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":12,"time":1784437195078,"data":{"turn":1,"step":1,"content":[{"type":"tool-call","id":"call_wait","name":"bash","arguments":"{\"command\":\"node -e \\\"setInterval(() => {}, 1000)\\\"\",\"description\":\"Wait until cancellation\"}"},{"type":"tool-call","id":"call_skipped","name":"bash","arguments":"{\"command\":\"printf skipped > skipped.txt\",\"description\":\"Write skipped marker\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":10,"outputTokens":10}},"sourceEventSeqs":[4,5,6,7,8,9,10,11],"surfaceOp":"append"} {"type":"tool/call","seq":13,"time":1784437195078,"data":{"turn":1,"step":1,"callId":"call_wait","name":"bash","arguments":"{\"command\":\"node -e \\\"setInterval(() => {}, 1000)\\\"\",\"description\":\"Wait until cancellation\"}"}} -{"type":"tool/result","seq":14,"time":1784437195089,"data":{"turn":1,"step":1,"callId":"call_wait","content":[{"type":"text","text":"Error: command aborted"}],"isError":true},"sourceEventSeqs":[13],"surfaceOp":"append"} +{"type":"tool/result","seq":14,"time":1784437195089,"data":{"turn":1,"step":1,"callId":"call_wait","content":[{"type":"text","text":"Error: command aborted"}],"isError":true,"error":{"message":"command aborted"}},"sourceEventSeqs":[13],"surfaceOp":"append"} {"type":"tool/call","seq":15,"time":1784437195089,"data":{"turn":1,"step":1,"callId":"call_skipped","name":"bash","arguments":"{\"command\":\"printf skipped > skipped.txt\",\"description\":\"Write skipped marker\"}"}} -{"type":"tool/result","seq":16,"time":1784437195089,"data":{"turn":1,"step":1,"callId":"call_skipped","content":[{"type":"text","text":"Error: tool call skipped because the step was aborted before execution"}],"isError":true,"error":{"name":"AbortError","code":"ABORTED"}},"sourceEventSeqs":[15],"surfaceOp":"append"} +{"type":"tool/result","seq":16,"time":1784437195089,"data":{"turn":1,"step":1,"callId":"call_skipped","content":[{"type":"text","text":"Error: tool call skipped because the step was aborted before execution"}],"isError":true,"error":{"message":"tool call skipped because the step was aborted before execution","info":{"name":"AbortError","code":"ABORTED"}}},"sourceEventSeqs":[15],"surfaceOp":"append"} {"type":"step/end","seq":17,"time":1784437195090,"data":{"turn":1,"step":1}} {"type":"turn/end","seq":18,"time":1784437195090,"data":{"turn":1,"reason":{"kind":"aborted","reason":"session/cancel"}}} diff --git a/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl b/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl index 207f8d8cc3..f04f7c9cf1 100644 --- a/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl +++ b/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl @@ -10,7 +10,7 @@ {"type":"assistant/chunk","seq":8,"time":1783951000009,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":9,"time":1784449176722,"data":{"turn":1,"step":1,"content":[{"type":"tool-call","id":"inspect-tools-api","name":"cordis_inspect","arguments":"{\"what\":\"api\",\"name\":\"tools\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[4,5,6,7,8],"surfaceOp":"append"} {"type":"tool/call","seq":10,"time":1784449176722,"data":{"turn":1,"step":1,"callId":"inspect-tools-api","name":"cordis_inspect","arguments":"{\"what\":\"api\",\"name\":\"tools\"}"}} -{"type":"tool/result","seq":11,"time":1784449176732,"data":{"turn":1,"step":1,"callId":"inspect-tools-api","content":[{"type":"text","text":"## api\n- tools — Tool registry and execution pipeline.\n /**\n * Register globally or in the calling agent scope. Scoped tools shadow\n * globals; duplicates within one layer and the reserved `run_code` name fail.\n * @param definition - the tool schema, execution, and optional presentation functions.\n * @returns the exact disposer that unregisters the tool.\n */\n register(definition: ToolDefinition): () => void\n /**\n * Restrict global tools for the calling agent scope. Empty filters, unknown\n * names, scope-local names, and reserved transport names fail. Restrictions\n * intersect; scoped registrations remain visible.\n * @param filter - global-surface mask: `allow` (keep only) and/or `deny` (remove).\n * @returns the exact disposer that lifts this restriction.\n */\n restrict(filter: ToolRestriction): () => void\n /**\n * Register a monotonic guard after the extensible `tools/pre-execute`\n * waterfall. A plain-context guard applies globally; one registered through\n * `agent.ctx` applies only to that agent. Any matching guard may deny by\n * returning a reason, while no guard can force-allow a call another guard\n * denied. The exact effect disposer is returned for ordered ownership and\n * HMR cleanup.\n * @param guard - synchronous check; a returned string denies the execution.\n * @returns the exact disposer that unregisters the guard.\n */\n guard(guard: ToolGuard): () => void\n /**\n * Look up a tool as one scope sees it (scoped\n * shadows global; a restricted-away global reads as absent). Presenters pass\n * the calling agent so the rendered card matches the definition that\n * actually executed.\n * @param name - the tool name as registered.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns the definition the scope resolves, or undefined when none is visible.\n */\n get(name: string, scope?: ScopeKey): ToolDefinition | undefined\n /**\n * Project visible definitions onto the allowlisted model-facing schema fields,\n * excluding execution and presentation callbacks.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns one deep-cloned schema per visible tool.\n */\n schemas(scope?: ScopeKey): ToolSchema[]\n /**\n * Classify a pending call through the caller's visible tool definition. Only\n * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or\n * throwing classifiers are exclusive.\n * @param exec - call name, parsed arguments, and optional agent scope.\n * @returns the fail-closed scheduling mode.\n */\n executionMode(exec: ToolExecutionInput): ToolExecutionMode\n /**\n * Execute through pre-policy, guards, around-dispatch, post-policy, and final\n * notification. Tool and listener failures resolve as materialized error\n * results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is\n * the same lossless, frozen snapshot final observers receive.\n * @param exec - the typed same-process call input. The registry assigns its\n * correlation token before policy begins.\n * @returns the materialized final result.\n */\n async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>\ntype shapes (referenced by the signatures above — read these before assuming a field is a string):\n export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly status: AgentStatus;\n readonly ctx: Context;\n send(content: ContentBlock[], options?: SendOptions): void;\n steer(content: ContentBlock[], options?: SendOptions): void;\n inject(content: ContentBlock[], options?: InjectOptions): void;\n cancel(reason?: string): void;\n whenIdle(): Promise<void>;\n }\n export interface AgentOptions {\n provider?: string;\n model?: string;\n }\n export type AgentStatus = 'idle' | 'running' | 'disposed';\n export type Branded<B extends string> = string & {\n readonly [BRAND]: B;\n };\n export type CallId = Branded<'CallId'>;\n export interface DiffCallView {\n card: 'diff';\n title: string;\n diffs: FileDiff[];\n locations?: FileLocation[];\n }\n export interface DiffResultView {\n card: 'diff';\n title?: string;\n diffs: FileDiff[];\n }\n export interface FileDiff {\n path: string;\n oldText: string | null;\n newText: string;\n }\n export interface FileLocation {\n path: string;\n line?: number;\n }\n export interface GenericCallView {\n card: 'generic';\n title: string;\n kind?: ToolCallKind;\n rawInput?: unknown;\n content?: ContentBlock[];\n locations?: FileLocation[];\n }\n export interface GenericResultView {\n card: 'generic';\n title?: string;\n content?: ContentBlock[];\n }\n export interface HookContext {\n content: ContentBlock[];\n source: MessageSource;\n meta?: JsonValue;\n }\n export interface InjectOptions extends SendOptions {\n meta?: JsonValue;\n }\n export type JsonValue = null | boolean | number | string | JsonValue[] | {\n [key: string]: JsonValue;\n };\n export type MessageSource = MessageSourceMap[keyof MessageSourceMap];\n export interface MessageSourceMap {\n user: {\n kind: 'user';\n };\n plugin: {\n kind: 'plugin';\n plugin: string;\n };\n }\n export type ScopeKey = object;\n export interface SendOptions {\n source?: MessageSource;\n }\n export type SessionId = Branded<'SessionId'>;\n export interface TerminalCallView {\n card: 'terminal';\n title: string;\n description?: string;\n cwd?: string;\n }\n export interface TerminalResultView {\n card: 'terminal';\n title?: string;\n output?: string;\n exitCode?: number;\n signal?: string;\n }\n export type ToolCallKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other';\n export type ToolCallView = GenericCallView | TerminalCallView | DiffCallView;\n export interface ToolDefinition extends ToolSchema {\n execute(args: unknown, exec: ToolRunContext): Promise<ToolExecuteReturn>;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n }\n export interface ToolErrorInfo {\n name: string;\n code: string;\n }\n export type ToolExecuteReturn = ContentBlock[] | {\n content: ContentBlock[];\n meta?: unknown;\n };\n export interface ToolExecution extends ToolExecutionInput {\n readonly token: ToolExecutionToken;\n }\n export interface ToolExecutionInput {\n readonly callId: CallId;\n readonly name: string;\n readonly arguments: unknown;\n readonly agent?: Agent;\n readonly parent?: ToolExecutionToken;\n signal?: AbortSignal;\n }\n export type ToolExecutionMode = {\n kind: 'parallel';\n } | {\n kind: 'exclusive';\n };\n export interface ToolExecutionResult {\n content: ContentBlock[];\n isError: boolean;\n error?: ToolErrorInfo;\n additionalContexts?: HookContext[];\n meta?: unknown;\n }\n export type ToolExecutionToken = symbol & {\n readonly [toolExecutionTokenBrand]: true;\n };\n export type ToolGuard = (execution: Readonly<ToolExecution>) => string | undefined;\n export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n }\n export interface ToolResult {\n content: ContentBlock[];\n isError: boolean;\n meta?: unknown;\n }\n export type ToolResultView = GenericResultView | TerminalResultView | DiffResultView;\n export interface ToolRunContext extends ToolExecution {\n deferContext(context: HookContext): void;\n }\n export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n }"}],"isError":false},"sourceEventSeqs":[10],"surfaceOp":"append"} +{"type":"tool/result","seq":11,"time":1784449176732,"data":{"turn":1,"step":1,"callId":"inspect-tools-api","content":[{"type":"text","text":"## api\n- tools — Tool registry and execution pipeline.\n /**\n * Register globally or in the calling agent scope. Scoped tools shadow\n * globals; duplicates within one layer and the reserved `run_code` name fail.\n * @param definition - the tool schema, execution, and optional presentation functions.\n * @returns the exact disposer that unregisters the tool.\n */\n register(definition: ToolDefinition): () => void\n /**\n * Restrict global tools for the calling agent scope. Empty filters, unknown\n * names, scope-local names, and reserved transport names fail. Restrictions\n * intersect; scoped registrations remain visible.\n * @param filter - global-surface mask: `allow` (keep only) and/or `deny` (remove).\n * @returns the exact disposer that lifts this restriction.\n */\n restrict(filter: ToolRestriction): () => void\n /**\n * Register a monotonic guard after the extensible `tools/pre-execute`\n * waterfall. A plain-context guard applies globally; one registered through\n * `agent.ctx` applies only to that agent. Any matching guard may deny by\n * returning a reason, while no guard can force-allow a call another guard\n * denied. The exact effect disposer is returned for ordered ownership and\n * HMR cleanup.\n * @param guard - synchronous check; a returned string denies the execution.\n * @returns the exact disposer that unregisters the guard.\n */\n guard(guard: ToolGuard): () => void\n /**\n * Look up a tool as one scope sees it (scoped\n * shadows global; a restricted-away global reads as absent). Presenters pass\n * the calling agent so the rendered card matches the definition that\n * actually executed.\n * @param name - the tool name as registered.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns the definition the scope resolves, or undefined when none is visible.\n */\n get(name: string, scope?: ScopeKey): ToolDefinition | undefined\n /**\n * Project visible definitions onto the allowlisted model-facing schema fields,\n * excluding execution and presentation callbacks.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns one deep-cloned schema per visible tool.\n */\n schemas(scope?: ScopeKey): ToolSchema[]\n /**\n * Classify a pending call through the caller's visible tool definition. Only\n * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or\n * throwing classifiers are exclusive.\n * @param exec - call name, parsed arguments, and optional agent scope.\n * @returns the fail-closed scheduling mode.\n */\n executionMode(exec: ToolExecutionInput): ToolExecutionMode\n /**\n * Execute through pre-policy, guards, around-dispatch, post-policy, and final\n * notification. Tool and listener failures resolve as materialized error\n * results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is\n * the same lossless, frozen snapshot final observers receive.\n * @param exec - the typed same-process call input. The registry assigns its\n * correlation token before policy begins.\n * @returns the materialized final result.\n */\n async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>\ntype shapes (referenced by the signatures above — read these before assuming a field is a string):\n export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly status: AgentStatus;\n readonly ctx: Context;\n send(content: ContentBlock[], options?: SendOptions): void;\n steer(content: ContentBlock[], options?: SendOptions): void;\n inject(content: ContentBlock[], options?: InjectOptions): void;\n cancel(reason?: string): void;\n whenIdle(): Promise<void>;\n }\n export interface AgentOptions {\n provider?: string;\n model?: string;\n }\n export type AgentStatus = 'idle' | 'running' | 'disposed';\n export type Branded<B extends string> = string & {\n readonly [BRAND]: B;\n };\n export type CallId = Branded<'CallId'>;\n export interface DiffCallView {\n card: 'diff';\n title: string;\n diffs: FileDiff[];\n locations?: FileLocation[];\n }\n export interface DiffResultView {\n card: 'diff';\n title?: string;\n diffs: FileDiff[];\n }\n export interface FileDiff {\n path: string;\n oldText: string | null;\n newText: string;\n }\n export interface FileLocation {\n path: string;\n line?: number;\n }\n export interface GenericCallView {\n card: 'generic';\n title: string;\n kind?: ToolCallKind;\n rawInput?: unknown;\n content?: ContentBlock[];\n locations?: FileLocation[];\n }\n export interface GenericResultView {\n card: 'generic';\n title?: string;\n content?: ContentBlock[];\n }\n export interface HookContext {\n content: ContentBlock[];\n source: MessageSource;\n meta?: JsonValue;\n }\n export interface InjectOptions extends SendOptions {\n meta?: JsonValue;\n }\n export interface JsonSchemaNode {\n type?: JsonSchemaType;\n oneOf?: JsonSchemaNode[];\n properties?: Record<string, JsonSchemaNode>;\n required?: string[];\n additionalProperties?: boolean;\n items?: JsonSchemaNode;\n enum?: JsonSchemaScalar[];\n const?: JsonSchemaScalar;\n description?: string;\n title?: string;\n default?: JsonValue;\n examples?: JsonValue;\n }\n export type JsonSchemaScalar = string | number | boolean | null;\n export type JsonSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null';\n export type JsonValue = null | boolean | number | string | JsonValue[] | {\n [key: string]: JsonValue;\n };\n export type MessageSource = MessageSourceMap[keyof MessageSourceMap];\n export interface MessageSourceMap {\n user: {\n kind: 'user';\n };\n plugin: {\n kind: 'plugin';\n plugin: string;\n };\n }\n export type ScopeKey = object;\n export interface SendOptions {\n source?: MessageSource;\n }\n export type SessionId = Branded<'SessionId'>;\n export interface TerminalCallView {\n card: 'terminal';\n title: string;\n description?: string;\n cwd?: string;\n }\n export interface TerminalResultView {\n card: 'terminal';\n title?: string;\n output?: string;\n exitCode?: number;\n signal?: string;\n }\n export type ToolCallKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other';\n export type ToolCallView = GenericCallView | TerminalCallView | DiffCallView;\n export interface ToolDefinition extends ToolSchema {\n readonly output: ToolOutputDefinition;\n execute(args: unknown, exec: ToolRunContext): Promise<unknown>;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n }\n export interface ToolErrorInfo {\n name: string;\n code: string;\n }\n export interface ToolExecution extends ToolExecutionInput {\n readonly token: ToolExecutionToken;\n }\n export interface ToolExecutionFailure {\n readonly isError: true;\n readonly error: ToolFailure;\n readonly value?: never;\n readonly content: ContentBlock[];\n readonly meta?: JsonValue;\n readonly additionalContexts?: HookContext[];\n }\n export interface ToolExecutionInput {\n readonly callId: CallId;\n readonly name: string;\n readonly arguments: unknown;\n readonly agent?: Agent;\n readonly parent?: ToolExecutionToken;\n signal?: AbortSignal;\n }\n export type ToolExecutionMode = {\n kind: 'parallel';\n } | {\n kind: 'exclusive';\n };\n export type ToolExecutionResult = ToolExecutionSuccess | ToolExecutionFailure;\n export interface ToolExecutionSuccess {\n readonly isError: false;\n readonly value: JsonValue;\n readonly content: ContentBlock[];\n readonly error?: never;\n readonly meta?: JsonValue;\n readonly additionalContexts?: HookContext[];\n }\n export type ToolExecutionToken = symbol & {\n readonly [toolExecutionTokenBrand]: true;\n };\n export interface ToolFailure {\n message: string;\n info?: ToolErrorInfo;\n }\n export type ToolGuard = (execution: Readonly<ToolExecution>) => string | undefined;\n export interface ToolOutputDefinition {\n readonly schema: JsonSchemaNode;\n render(args: unknown, value: JsonValue): ContentBlock[];\n presentationMeta?(args: unknown, value: JsonValue): JsonValue;\n }\n export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n }\n export interface ToolResult {\n content: ContentBlock[];\n isError: boolean;\n meta?: JsonValue;\n }\n export type ToolResultView = GenericResultView | TerminalResultView | DiffResultView;\n export interface ToolRunContext extends ToolExecution {\n deferContext(context: HookContext): void;\n }\n export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n }"}],"isError":false},"sourceEventSeqs":[10],"surfaceOp":"append"} {"type":"step/end","seq":12,"time":1784449176732,"data":{"turn":1,"step":1}} {"type":"step/start","seq":13,"time":1784449176733,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":14,"time":1783951000015,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}} diff --git a/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl b/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl index 5528c956d8..45ae5c9f50 100644 --- a/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl +++ b/examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl @@ -2,7 +2,7 @@ {"jsonrpc":"2.0","id":2,"result":{"sessionId":"{{sessionId}}","configOptions":[{"id":"model","name":"Model","description":"Sets this session's provider and model.","category":"model","type":"select","currentValue":"[\"deepseek\",\"deepseek-v4-flash\"]","options":[{"value":"[\"deepseek\",\"deepseek-v4-flash\"]","name":"deepseek-v4-flash"},{"value":"[\"deepseek\",\"deepseek-v4-pro\"]","name":"deepseek-v4-pro"}]},{"id":"permission","name":"Permissions","description":"The session permission preset: each choice bundles a sandbox mode and an approval policy.","category":"mode","type":"select","currentValue":"danger-full-access","options":[{"value":"workspace-write","name":"workspace-write","description":"Write inside the workspace and permitted temporary directories; wider retries require approval."},{"value":"danger-full-access","name":"danger-full-access","description":"Full file access without approval prompts."}]}]}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"available_commands_update","availableCommands":[{"name":"goal","description":"set or view the goal for a long-running task","input":{"hint":"[<objective>|clear|edit <objective>|pause|resume]"}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"inspect-tools-api","title":"Inspect cordis runtime: api: tools","kind":"read","status":"in_progress"}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"inspect-tools-api","status":"completed","content":[{"type":"content","content":{"type":"text","text":"## api\n- tools — Tool registry and execution pipeline.\n /**\n * Register globally or in the calling agent scope. Scoped tools shadow\n * globals; duplicates within one layer and the reserved `run_code` name fail.\n * @param definition - the tool schema, execution, and optional presentation functions.\n * @returns the exact disposer that unregisters the tool.\n */\n register(definition: ToolDefinition): () => void\n /**\n * Restrict global tools for the calling agent scope. Empty filters, unknown\n * names, scope-local names, and reserved transport names fail. Restrictions\n * intersect; scoped registrations remain visible.\n * @param filter - global-surface mask: `allow` (keep only) and/or `deny` (remove).\n * @returns the exact disposer that lifts this restriction.\n */\n restrict(filter: ToolRestriction): () => void\n /**\n * Register a monotonic guard after the extensible `tools/pre-execute`\n * waterfall. A plain-context guard applies globally; one registered through\n * `agent.ctx` applies only to that agent. Any matching guard may deny by\n * returning a reason, while no guard can force-allow a call another guard\n * denied. The exact effect disposer is returned for ordered ownership and\n * HMR cleanup.\n * @param guard - synchronous check; a returned string denies the execution.\n * @returns the exact disposer that unregisters the guard.\n */\n guard(guard: ToolGuard): () => void\n /**\n * Look up a tool as one scope sees it (scoped\n * shadows global; a restricted-away global reads as absent). Presenters pass\n * the calling agent so the rendered card matches the definition that\n * actually executed.\n * @param name - the tool name as registered.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns the definition the scope resolves, or undefined when none is visible.\n */\n get(name: string, scope?: ScopeKey): ToolDefinition | undefined\n /**\n * Project visible definitions onto the allowlisted model-facing schema fields,\n * excluding execution and presentation callbacks.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns one deep-cloned schema per visible tool.\n */\n schemas(scope?: ScopeKey): ToolSchema[]\n /**\n * Classify a pending call through the caller's visible tool definition. Only\n * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or\n * throwing classifiers are exclusive.\n * @param exec - call name, parsed arguments, and optional agent scope.\n * @returns the fail-closed scheduling mode.\n */\n executionMode(exec: ToolExecutionInput): ToolExecutionMode\n /**\n * Execute through pre-policy, guards, around-dispatch, post-policy, and final\n * notification. Tool and listener failures resolve as materialized error\n * results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is\n * the same lossless, frozen snapshot final observers receive.\n * @param exec - the typed same-process call input. The registry assigns its\n * correlation token before policy begins.\n * @returns the materialized final result.\n */\n async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>\ntype shapes (referenced by the signatures above — read these before assuming a field is a string):\n export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly status: AgentStatus;\n readonly ctx: Context;\n send(content: ContentBlock[], options?: SendOptions): void;\n steer(content: ContentBlock[], options?: SendOptions): void;\n inject(content: ContentBlock[], options?: InjectOptions): void;\n cancel(reason?: string): void;\n whenIdle(): Promise<void>;\n }\n export interface AgentOptions {\n provider?: string;\n model?: string;\n }\n export type AgentStatus = 'idle' | 'running' | 'disposed';\n export type Branded<B extends string> = string & {\n readonly [BRAND]: B;\n };\n export type CallId = Branded<'CallId'>;\n export interface DiffCallView {\n card: 'diff';\n title: string;\n diffs: FileDiff[];\n locations?: FileLocation[];\n }\n export interface DiffResultView {\n card: 'diff';\n title?: string;\n diffs: FileDiff[];\n }\n export interface FileDiff {\n path: string;\n oldText: string | null;\n newText: string;\n }\n export interface FileLocation {\n path: string;\n line?: number;\n }\n export interface GenericCallView {\n card: 'generic';\n title: string;\n kind?: ToolCallKind;\n rawInput?: unknown;\n content?: ContentBlock[];\n locations?: FileLocation[];\n }\n export interface GenericResultView {\n card: 'generic';\n title?: string;\n content?: ContentBlock[];\n }\n export interface HookContext {\n content: ContentBlock[];\n source: MessageSource;\n meta?: JsonValue;\n }\n export interface InjectOptions extends SendOptions {\n meta?: JsonValue;\n }\n export type JsonValue = null | boolean | number | string | JsonValue[] | {\n [key: string]: JsonValue;\n };\n export type MessageSource = MessageSourceMap[keyof MessageSourceMap];\n export interface MessageSourceMap {\n user: {\n kind: 'user';\n };\n plugin: {\n kind: 'plugin';\n plugin: string;\n };\n }\n export type ScopeKey = object;\n export interface SendOptions {\n source?: MessageSource;\n }\n export type SessionId = Branded<'SessionId'>;\n export interface TerminalCallView {\n card: 'terminal';\n title: string;\n description?: string;\n cwd?: string;\n }\n export interface TerminalResultView {\n card: 'terminal';\n title?: string;\n output?: string;\n exitCode?: number;\n signal?: string;\n }\n export type ToolCallKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other';\n export type ToolCallView = GenericCallView | TerminalCallView | DiffCallView;\n export interface ToolDefinition extends ToolSchema {\n execute(args: unknown, exec: ToolRunContext): Promise<ToolExecuteReturn>;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n }\n export interface ToolErrorInfo {\n name: string;\n code: string;\n }\n export type ToolExecuteReturn = ContentBlock[] | {\n content: ContentBlock[];\n meta?: unknown;\n };\n export interface ToolExecution extends ToolExecutionInput {\n readonly token: ToolExecutionToken;\n }\n export interface ToolExecutionInput {\n readonly callId: CallId;\n readonly name: string;\n readonly arguments: unknown;\n readonly agent?: Agent;\n readonly parent?: ToolExecutionToken;\n signal?: AbortSignal;\n }\n export type ToolExecutionMode = {\n kind: 'parallel';\n } | {\n kind: 'exclusive';\n };\n export interface ToolExecutionResult {\n content: ContentBlock[];\n isError: boolean;\n error?: ToolErrorInfo;\n additionalContexts?: HookContext[];\n meta?: unknown;\n }\n export type ToolExecutionToken = symbol & {\n readonly [toolExecutionTokenBrand]: true;\n };\n export type ToolGuard = (execution: Readonly<ToolExecution>) => string | undefined;\n export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n }\n export interface ToolResult {\n content: ContentBlock[];\n isError: boolean;\n meta?: unknown;\n }\n export type ToolResultView = GenericResultView | TerminalResultView | DiffResultView;\n export interface ToolRunContext extends ToolExecution {\n deferContext(context: HookContext): void;\n }\n export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n }"}}]}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"inspect-tools-api","status":"completed","content":[{"type":"content","content":{"type":"text","text":"## api\n- tools — Tool registry and execution pipeline.\n /**\n * Register globally or in the calling agent scope. Scoped tools shadow\n * globals; duplicates within one layer and the reserved `run_code` name fail.\n * @param definition - the tool schema, execution, and optional presentation functions.\n * @returns the exact disposer that unregisters the tool.\n */\n register(definition: ToolDefinition): () => void\n /**\n * Restrict global tools for the calling agent scope. Empty filters, unknown\n * names, scope-local names, and reserved transport names fail. Restrictions\n * intersect; scoped registrations remain visible.\n * @param filter - global-surface mask: `allow` (keep only) and/or `deny` (remove).\n * @returns the exact disposer that lifts this restriction.\n */\n restrict(filter: ToolRestriction): () => void\n /**\n * Register a monotonic guard after the extensible `tools/pre-execute`\n * waterfall. A plain-context guard applies globally; one registered through\n * `agent.ctx` applies only to that agent. Any matching guard may deny by\n * returning a reason, while no guard can force-allow a call another guard\n * denied. The exact effect disposer is returned for ordered ownership and\n * HMR cleanup.\n * @param guard - synchronous check; a returned string denies the execution.\n * @returns the exact disposer that unregisters the guard.\n */\n guard(guard: ToolGuard): () => void\n /**\n * Look up a tool as one scope sees it (scoped\n * shadows global; a restricted-away global reads as absent). Presenters pass\n * the calling agent so the rendered card matches the definition that\n * actually executed.\n * @param name - the tool name as registered.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns the definition the scope resolves, or undefined when none is visible.\n */\n get(name: string, scope?: ScopeKey): ToolDefinition | undefined\n /**\n * Project visible definitions onto the allowlisted model-facing schema fields,\n * excluding execution and presentation callbacks.\n * @param scope - the viewing scope (the agent); omitted = the global view.\n * @returns one deep-cloned schema per visible tool.\n */\n schemas(scope?: ScopeKey): ToolSchema[]\n /**\n * Classify a pending call through the caller's visible tool definition. Only\n * an exact `true` is parallel; unknown, hidden, undeclared, invalid, or\n * throwing classifiers are exclusive.\n * @param exec - call name, parsed arguments, and optional agent scope.\n * @returns the fail-closed scheduling mode.\n */\n executionMode(exec: ToolExecutionInput): ToolExecutionMode\n /**\n * Execute through pre-policy, guards, around-dispatch, post-policy, and final\n * notification. Tool and listener failures resolve as materialized error\n * results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is\n * the same lossless, frozen snapshot final observers receive.\n * @param exec - the typed same-process call input. The registry assigns its\n * correlation token before policy begins.\n * @returns the materialized final result.\n */\n async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>\ntype shapes (referenced by the signatures above — read these before assuming a field is a string):\n export interface Agent {\n readonly id: SessionId;\n readonly options: AgentOptions;\n readonly session: Session;\n readonly status: AgentStatus;\n readonly ctx: Context;\n send(content: ContentBlock[], options?: SendOptions): void;\n steer(content: ContentBlock[], options?: SendOptions): void;\n inject(content: ContentBlock[], options?: InjectOptions): void;\n cancel(reason?: string): void;\n whenIdle(): Promise<void>;\n }\n export interface AgentOptions {\n provider?: string;\n model?: string;\n }\n export type AgentStatus = 'idle' | 'running' | 'disposed';\n export type Branded<B extends string> = string & {\n readonly [BRAND]: B;\n };\n export type CallId = Branded<'CallId'>;\n export interface DiffCallView {\n card: 'diff';\n title: string;\n diffs: FileDiff[];\n locations?: FileLocation[];\n }\n export interface DiffResultView {\n card: 'diff';\n title?: string;\n diffs: FileDiff[];\n }\n export interface FileDiff {\n path: string;\n oldText: string | null;\n newText: string;\n }\n export interface FileLocation {\n path: string;\n line?: number;\n }\n export interface GenericCallView {\n card: 'generic';\n title: string;\n kind?: ToolCallKind;\n rawInput?: unknown;\n content?: ContentBlock[];\n locations?: FileLocation[];\n }\n export interface GenericResultView {\n card: 'generic';\n title?: string;\n content?: ContentBlock[];\n }\n export interface HookContext {\n content: ContentBlock[];\n source: MessageSource;\n meta?: JsonValue;\n }\n export interface InjectOptions extends SendOptions {\n meta?: JsonValue;\n }\n export interface JsonSchemaNode {\n type?: JsonSchemaType;\n oneOf?: JsonSchemaNode[];\n properties?: Record<string, JsonSchemaNode>;\n required?: string[];\n additionalProperties?: boolean;\n items?: JsonSchemaNode;\n enum?: JsonSchemaScalar[];\n const?: JsonSchemaScalar;\n description?: string;\n title?: string;\n default?: JsonValue;\n examples?: JsonValue;\n }\n export type JsonSchemaScalar = string | number | boolean | null;\n export type JsonSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null';\n export type JsonValue = null | boolean | number | string | JsonValue[] | {\n [key: string]: JsonValue;\n };\n export type MessageSource = MessageSourceMap[keyof MessageSourceMap];\n export interface MessageSourceMap {\n user: {\n kind: 'user';\n };\n plugin: {\n kind: 'plugin';\n plugin: string;\n };\n }\n export type ScopeKey = object;\n export interface SendOptions {\n source?: MessageSource;\n }\n export type SessionId = Branded<'SessionId'>;\n export interface TerminalCallView {\n card: 'terminal';\n title: string;\n description?: string;\n cwd?: string;\n }\n export interface TerminalResultView {\n card: 'terminal';\n title?: string;\n output?: string;\n exitCode?: number;\n signal?: string;\n }\n export type ToolCallKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other';\n export type ToolCallView = GenericCallView | TerminalCallView | DiffCallView;\n export interface ToolDefinition extends ToolSchema {\n readonly output: ToolOutputDefinition;\n execute(args: unknown, exec: ToolRunContext): Promise<unknown>;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n }\n export interface ToolErrorInfo {\n name: string;\n code: string;\n }\n export interface ToolExecution extends ToolExecutionInput {\n readonly token: ToolExecutionToken;\n }\n export interface ToolExecutionFailure {\n readonly isError: true;\n readonly error: ToolFailure;\n readonly value?: never;\n readonly content: ContentBlock[];\n readonly meta?: JsonValue;\n readonly additionalContexts?: HookContext[];\n }\n export interface ToolExecutionInput {\n readonly callId: CallId;\n readonly name: string;\n readonly arguments: unknown;\n readonly agent?: Agent;\n readonly parent?: ToolExecutionToken;\n signal?: AbortSignal;\n }\n export type ToolExecutionMode = {\n kind: 'parallel';\n } | {\n kind: 'exclusive';\n };\n export type ToolExecutionResult = ToolExecutionSuccess | ToolExecutionFailure;\n export interface ToolExecutionSuccess {\n readonly isError: false;\n readonly value: JsonValue;\n readonly content: ContentBlock[];\n readonly error?: never;\n readonly meta?: JsonValue;\n readonly additionalContexts?: HookContext[];\n }\n export type ToolExecutionToken = symbol & {\n readonly [toolExecutionTokenBrand]: true;\n };\n export interface ToolFailure {\n message: string;\n info?: ToolErrorInfo;\n }\n export type ToolGuard = (execution: Readonly<ToolExecution>) => string | undefined;\n export interface ToolOutputDefinition {\n readonly schema: JsonSchemaNode;\n render(args: unknown, value: JsonValue): ContentBlock[];\n presentationMeta?(args: unknown, value: JsonValue): JsonValue;\n }\n export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n }\n export interface ToolResult {\n content: ContentBlock[];\n isError: boolean;\n meta?: JsonValue;\n }\n export type ToolResultView = GenericResultView | TerminalResultView | DiffResultView;\n export interface ToolRunContext extends ToolExecution {\n deferContext(context: HookContext): void;\n }\n export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n }"}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"inspect-tools-event","title":"Inspect cordis runtime: events: tools/pre-execute","kind":"read","status":"in_progress"}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"inspect-tools-event","status":"completed","content":[{"type":"content","content":{"type":"text","text":"## events\n- tools/pre-execute [waterfall] — Allow, deny, or ask before dispatch.\n /**\n * Allow, deny, or ask before dispatch. `next()` delegates to allow; missing\n * approval support turns `ask` into denial.\n * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's calls.\n * @param exec - the pending call (name, parsed arguments, caller agent).\n * @mode waterfall\n */\n 'tools/pre-execute'(this: Scoped<ToolRegistry>, exec: ToolExecution, next: () => Promise<PreToolDecision>): Promise<PreToolDecision>\nwaterfall listeners receive a trailing next() and MUST call it to delegate — returning without next() vetoes the chain."}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"CORDIS_INSPECT_JSDOC_OK"}}}} diff --git a/examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl b/examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl index ff6d1187b3..4190704a7f 100644 --- a/examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl +++ b/examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl @@ -157,7 +157,7 @@ {"type":"tool/call","seq":155,"time":1783962246274,"data":{"turn":1,"step":1,"callId":"call_00_WB1vnPomi8yr6MlcFKTj7912","name":"bash","arguments":"{\"command\": \"printf 'escalated\\\\n' > /tmp/dsh-escalated.txt && cat /tmp/dsh-escalated.txt && rm /tmp/dsh-escalated.txt\", \"description\": \"Write to /tmp and verify, then clean up\", \"sandbox_permissions\": \"danger-full-access\", \"justification\": \"the user asked to write a file outside the workspace\"}"}} {"type":"approval/asked","seq":156,"time":1783962246275,"data":{"id":"46c8dba4-52c9-4a6a-b6a6-5f34c95c28df","toolName":"bash","callId":"call_00_WB1vnPomi8yr6MlcFKTj7912","reason":"escalate sandbox to danger-full-access: the user asked to write a file outside the workspace"}} {"type":"approval/decided","seq":157,"time":1783962246275,"data":{"id":"46c8dba4-52c9-4a6a-b6a6-5f34c95c28df","outcome":"rejected"}} -{"type":"tool/result","seq":158,"time":1783962246275,"data":{"turn":1,"step":1,"callId":"call_00_WB1vnPomi8yr6MlcFKTj7912","content":[{"type":"text","text":"Error: the user rejected escalating this command to \"danger-full-access\""}],"isError":true},"sourceEventSeqs":[155],"surfaceOp":"append"} +{"type":"tool/result","seq":158,"time":1783962246275,"data":{"turn":1,"step":1,"callId":"call_00_WB1vnPomi8yr6MlcFKTj7912","content":[{"type":"text","text":"Error: the user rejected escalating this command to \"danger-full-access\""}],"isError":true,"error":{"message":"the user rejected escalating this command to \"danger-full-access\""}},"sourceEventSeqs":[155],"surfaceOp":"append"} {"type":"step/end","seq":159,"time":1783962246276,"data":{"turn":1,"step":1}} {"type":"step/start","seq":160,"time":1783962246276,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":161,"time":1783860683140,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/fs-escalation-approved/session.jsonl b/examples/acp-agent/tests/snapshots/fs-escalation-approved/session.jsonl index 54601f5354..013b002edc 100644 --- a/examples/acp-agent/tests/snapshots/fs-escalation-approved/session.jsonl +++ b/examples/acp-agent/tests/snapshots/fs-escalation-approved/session.jsonl @@ -91,7 +91,7 @@ {"type":"tool/call","seq":89,"time":1784045703780,"data":{"turn":1,"step":1,"callId":"call_00_Fnymmavpr4klMDy4Fdej3227","name":"write","arguments":"{\"file_path\": \"escalated.md\", \"content\": \"escalated\", \"sandbox_permissions\": \"danger-full-access\", \"justification\": \"the user asked to escalate this write\"}"}} {"type":"approval/asked","seq":90,"time":1784045703782,"data":{"id":"c37500b3-c252-4a9b-ad0d-9c4349419b30","toolName":"write","callId":"call_00_Fnymmavpr4klMDy4Fdej3227","reason":"escalate sandbox to danger-full-access: the user asked to escalate this write"}} {"type":"approval/decided","seq":91,"time":1784045703786,"data":{"id":"c37500b3-c252-4a9b-ad0d-9c4349419b30","outcome":"allowed-once"}} -{"type":"tool/result","seq":92,"time":1784045703798,"data":{"turn":1,"step":1,"callId":"call_00_Fnymmavpr4klMDy4Fdej3227","content":[{"type":"text","text":"<path>/var/folders/2g/b32ct0qn1d728l_v6tdkjytr0000gn/T/acp-snap-cwd-vmEGzd/escalated.md</path>\n<type>file</type>\n<content>\nCreated file\n</content>"}],"isError":false},"sourceEventSeqs":[89],"surfaceOp":"append"} +{"type":"tool/result","seq":92,"time":1784045703798,"data":{"turn":1,"step":1,"callId":"call_00_Fnymmavpr4klMDy4Fdej3227","content":[{"type":"text","text":"<path>/var/folders/2g/b32ct0qn1d728l_v6tdkjytr0000gn/T/acp-snap-cwd-vmEGzd/escalated.md</path>\n<type>file</type>\n<content>\nCreated file\n</content>"}],"isError":false,"meta":{"diffs":[]}},"sourceEventSeqs":[89],"surfaceOp":"append"} {"type":"step/end","seq":93,"time":1784045703798,"data":{"turn":1,"step":1}} {"type":"step/start","seq":94,"time":1784045703799,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":95,"time":1784045704512,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl b/examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl index 66efd5f934..5b1ccd60fc 100644 --- a/examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl +++ b/examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl @@ -77,7 +77,7 @@ {"type":"assistant/chunk","seq":75,"time":1783611703969,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":76,"time":1783611703972,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to use the edit tool to replace \"blue\" with \"green\" in settings.txt without reading the file first, and then reply with just \"DONE\"."},{"type":"tool-call","id":"call_00_x0zlnXl5JOxLrAYL9y7P0119","name":"edit","arguments":"{\"file_path\": \"settings.txt\", \"old_string\": \"blue\", \"new_string\": \"green\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3132,"outputTokens":115,"cacheReadTokens":0,"reasoningTokens":36}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75],"surfaceOp":"append"} {"type":"tool/call","seq":77,"time":1783611703972,"data":{"turn":1,"step":1,"callId":"call_00_x0zlnXl5JOxLrAYL9y7P0119","name":"edit","arguments":"{\"file_path\": \"settings.txt\", \"old_string\": \"blue\", \"new_string\": \"green\"}"}} -{"type":"tool/result","seq":78,"time":1783611703978,"data":{"turn":1,"step":1,"callId":"call_00_x0zlnXl5JOxLrAYL9y7P0119","content":[{"type":"text","text":"Error: edit requires reading \"/var/folders/2c/psb0_fmx7hbgz558xjt_f0l00000gn/T/acp-snap-cwd-QzoqnB/settings.txt\" first"}],"isError":true,"error":{"name":"FsError","code":"FS_NOT_OBSERVED"}},"sourceEventSeqs":[77],"surfaceOp":"append"} +{"type":"tool/result","seq":78,"time":1783611703978,"data":{"turn":1,"step":1,"callId":"call_00_x0zlnXl5JOxLrAYL9y7P0119","content":[{"type":"text","text":"Error: edit requires reading \"/var/folders/2c/psb0_fmx7hbgz558xjt_f0l00000gn/T/acp-snap-cwd-QzoqnB/settings.txt\" first"}],"isError":true,"error":{"message":"edit requires reading \"/var/folders/2c/psb0_fmx7hbgz558xjt_f0l00000gn/T/acp-snap-cwd-QzoqnB/settings.txt\" first","info":{"name":"FsError","code":"FS_NOT_OBSERVED"}}},"sourceEventSeqs":[77],"surfaceOp":"append"} {"type":"step/end","seq":79,"time":1783611703978,"data":{"turn":1,"step":1}} {"type":"step/start","seq":80,"time":1783611703978,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":81,"time":1783611704825,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/fs-write/session.jsonl b/examples/acp-agent/tests/snapshots/fs-write/session.jsonl index 04fd86da0d..acbe253e99 100644 --- a/examples/acp-agent/tests/snapshots/fs-write/session.jsonl +++ b/examples/acp-agent/tests/snapshots/fs-write/session.jsonl @@ -62,7 +62,7 @@ {"type":"assistant/chunk","seq":60,"time":1783352079886,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":61,"time":1783352079888,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to create a file named notes.txt with the content \"hello world\" using the write tool, then reply with \"DONE\"."},{"type":"tool-call","id":"call_00_APMUCJJm9lrTSlVbg6dB0185","name":"write","arguments":"{\"file_path\": \"notes.txt\", \"content\": \"hello world\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":2891,"outputTokens":92,"cacheReadTokens":0,"reasoningTokens":30}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60],"surfaceOp":"append"} {"type":"tool/call","seq":62,"time":1783352079888,"data":{"turn":1,"step":1,"callId":"call_00_APMUCJJm9lrTSlVbg6dB0185","name":"write","arguments":"{\"file_path\": \"notes.txt\", \"content\": \"hello world\"}"}} -{"type":"tool/result","seq":63,"time":1783352079897,"data":{"turn":1,"step":1,"callId":"call_00_APMUCJJm9lrTSlVbg6dB0185","content":[{"type":"text","text":"<path>/tmp/acp-snap-cwd-sNvn5N/notes.txt</path>\n<type>file</type>\n<content>\nCreated file\n</content>"}],"isError":false},"sourceEventSeqs":[62],"surfaceOp":"append"} +{"type":"tool/result","seq":63,"time":1783352079897,"data":{"turn":1,"step":1,"callId":"call_00_APMUCJJm9lrTSlVbg6dB0185","content":[{"type":"text","text":"<path>/tmp/acp-snap-cwd-sNvn5N/notes.txt</path>\n<type>file</type>\n<content>\nCreated file\n</content>"}],"isError":false,"meta":{"diffs":[]}},"sourceEventSeqs":[62],"surfaceOp":"append"} {"type":"step/end","seq":64,"time":1783352079898,"data":{"turn":1,"step":1}} {"type":"step/start","seq":65,"time":1783352079899,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":66,"time":1783352080825,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl b/examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl index c362de7a26..8cab55c391 100644 --- a/examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl +++ b/examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl @@ -75,7 +75,7 @@ {"type":"tool/call","seq":73,"time":1783962505993,"data":{"turn":1,"step":1,"callId":"call_00_VAByyMjsct4c7P6k1ysX9256","name":"bash","arguments":"{\"command\": \"echo HELLO\", \"description\": \"Echo HELLO to stdout\"}"}} {"type":"hook/invoked","seq":74,"time":1783962506001,"data":{"turn":1,"point":"PostToolUse","dialect":"claude","handlerId":"claude:PostToolUse:1","matcher":"bash"}} {"type":"hook/result","seq":75,"time":1783962506011,"data":{"turn":1,"point":"PostToolUse","handlerId":"claude:PostToolUse:1","decision":"block","exitCode":2,"stderrSummary":"tool output rejected by policy: retry once","durationMs":9.922291999999743}} -{"type":"tool/result","seq":76,"time":1783962506011,"data":{"turn":1,"step":1,"callId":"call_00_VAByyMjsct4c7P6k1ysX9256","content":[{"type":"text","text":"tool output rejected by policy: retry once"}],"isError":true},"sourceEventSeqs":[73],"surfaceOp":"append"} +{"type":"tool/result","seq":76,"time":1783962506011,"data":{"turn":1,"step":1,"callId":"call_00_VAByyMjsct4c7P6k1ysX9256","content":[{"type":"text","text":"tool output rejected by policy: retry once"}],"isError":true,"error":{"message":"tool output rejected by policy: retry once"}},"sourceEventSeqs":[73],"surfaceOp":"append"} {"type":"step/end","seq":77,"time":1783962506012,"data":{"turn":1,"step":1}} {"type":"step/start","seq":78,"time":1783962506012,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":79,"time":1783962507038,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl b/examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl index 247e13a075..1309b5c30d 100644 --- a/examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl +++ b/examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl @@ -57,7 +57,7 @@ {"type":"hook/result","seq":55,"time":1783352172573,"data":{"turn":1,"point":"PreToolUse","handlerId":"claude:PreToolUse:1","decision":"ask","exitCode":0,"durationMs":14.113374999999905}} {"type":"approval/asked","seq":56,"time":1783962235813,"data":{"id":"68f1e09d-f3e5-4e39-8a51-da082ba3ba99","toolName":"bash","callId":"call_00_6k0oGSliVHxGSgqBmMEO4311","reason":"bash requires manual approval in this session"}} {"type":"approval/decided","seq":57,"time":1783962235813,"data":{"id":"68f1e09d-f3e5-4e39-8a51-da082ba3ba99","outcome":"rejected"}} -{"type":"tool/result","seq":58,"time":1783962235814,"data":{"turn":1,"step":1,"callId":"call_00_6k0oGSliVHxGSgqBmMEO4311","content":[{"type":"text","text":"Error: the user rejected tool \"bash\""}],"isError":true},"sourceEventSeqs":[53],"surfaceOp":"append"} +{"type":"tool/result","seq":58,"time":1783962235814,"data":{"turn":1,"step":1,"callId":"call_00_6k0oGSliVHxGSgqBmMEO4311","content":[{"type":"text","text":"Error: the user rejected tool \"bash\""}],"isError":true,"error":{"message":"the user rejected tool \"bash\""}},"sourceEventSeqs":[53],"surfaceOp":"append"} {"type":"step/end","seq":59,"time":1783962235814,"data":{"turn":1,"step":1}} {"type":"step/start","seq":60,"time":1783962235814,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":61,"time":1783352173584,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl b/examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl index 4193c7fe80..869fca1eca 100644 --- a/examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl +++ b/examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl @@ -55,7 +55,7 @@ {"type":"tool/call","seq":53,"time":1783352166514,"data":{"turn":1,"step":1,"callId":"call_00_JliP571Bh0QQ8QExbSPk0080","name":"bash","arguments":"{\"command\": \"echo HELLO\", \"description\": \"Run echo HELLO\"}"}} {"type":"hook/invoked","seq":54,"time":1783352166515,"data":{"turn":1,"point":"PreToolUse","dialect":"claude","handlerId":"claude:PreToolUse:1","matcher":"bash"}} {"type":"hook/result","seq":55,"time":1783352166528,"data":{"turn":1,"point":"PreToolUse","handlerId":"claude:PreToolUse:1","decision":"block","exitCode":2,"stderrSummary":"bash is disabled by policy in this session","durationMs":12.367074000000684}} -{"type":"tool/result","seq":56,"time":1783352166528,"data":{"turn":1,"step":1,"callId":"call_00_JliP571Bh0QQ8QExbSPk0080","content":[{"type":"text","text":"Error: bash is disabled by policy in this session"}],"isError":true},"sourceEventSeqs":[53],"surfaceOp":"append"} +{"type":"tool/result","seq":56,"time":1783352166528,"data":{"turn":1,"step":1,"callId":"call_00_JliP571Bh0QQ8QExbSPk0080","content":[{"type":"text","text":"Error: bash is disabled by policy in this session"}],"isError":true,"error":{"message":"bash is disabled by policy in this session"}},"sourceEventSeqs":[53],"surfaceOp":"append"} {"type":"step/end","seq":57,"time":1783352166529,"data":{"turn":1,"step":1}} {"type":"step/start","seq":58,"time":1783352166529,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":59,"time":1783352167307,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl b/examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl index dc68891c14..4a05a2daa7 100644 --- a/examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl +++ b/examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl @@ -66,7 +66,7 @@ {"type":"tool/call","seq":64,"time":1783986963664,"data":{"turn":1,"step":1,"callId":"call_00_1rmSWHhVchVg7PDTmegT0421","name":"bash","arguments":"{\"command\": \"echo HELLO\", \"description\": \"Echo HELLO to stdout\"}"}} {"type":"hook/invoked","seq":65,"time":1783986963673,"data":{"turn":1,"point":"PostToolUse","dialect":"codex","handlerId":"codex:PostToolUse:1","matcher":"bash"}} {"type":"hook/result","seq":66,"time":1783986963677,"data":{"turn":1,"point":"PostToolUse","handlerId":"codex:PostToolUse:1","decision":"block","exitCode":2,"stderrSummary":"tool output rejected by codex policy: summarize instead","durationMs":4.42941699999983}} -{"type":"tool/result","seq":67,"time":1783986963678,"data":{"turn":1,"step":1,"callId":"call_00_1rmSWHhVchVg7PDTmegT0421","content":[{"type":"text","text":"tool output rejected by codex policy: summarize instead"}],"isError":true},"sourceEventSeqs":[64],"surfaceOp":"append"} +{"type":"tool/result","seq":67,"time":1783986963678,"data":{"turn":1,"step":1,"callId":"call_00_1rmSWHhVchVg7PDTmegT0421","content":[{"type":"text","text":"tool output rejected by codex policy: summarize instead"}],"isError":true,"error":{"message":"tool output rejected by codex policy: summarize instead"}},"sourceEventSeqs":[64],"surfaceOp":"append"} {"type":"step/end","seq":68,"time":1783986963678,"data":{"turn":1,"step":1}} {"type":"step/start","seq":69,"time":1783986963679,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":70,"time":1783986964555,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl b/examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl index c2675ae3af..eb928d7dff 100644 --- a/examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl +++ b/examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl @@ -55,7 +55,7 @@ {"type":"tool/call","seq":53,"time":1783352215804,"data":{"turn":1,"step":1,"callId":"call_00_tv0SMeLXaTuyuVrOxnV97085","name":"bash","arguments":"{\"command\": \"echo HELLO\", \"description\": \"Run echo HELLO\"}"}} {"type":"hook/invoked","seq":54,"time":1783352215805,"data":{"turn":1,"point":"PreToolUse","dialect":"codex","handlerId":"codex:PreToolUse:1","matcher":"bash"}} {"type":"hook/result","seq":55,"time":1783352215832,"data":{"turn":1,"point":"PreToolUse","handlerId":"codex:PreToolUse:1","decision":"block","exitCode":2,"stderrSummary":"bash is disabled by codex policy in this session","durationMs":26.08518500000082}} -{"type":"tool/result","seq":56,"time":1783352215832,"data":{"turn":1,"step":1,"callId":"call_00_tv0SMeLXaTuyuVrOxnV97085","content":[{"type":"text","text":"Error: bash is disabled by codex policy in this session"}],"isError":true},"sourceEventSeqs":[53],"surfaceOp":"append"} +{"type":"tool/result","seq":56,"time":1783352215832,"data":{"turn":1,"step":1,"callId":"call_00_tv0SMeLXaTuyuVrOxnV97085","content":[{"type":"text","text":"Error: bash is disabled by codex policy in this session"}],"isError":true,"error":{"message":"bash is disabled by codex policy in this session"}},"sourceEventSeqs":[53],"surfaceOp":"append"} {"type":"step/end","seq":57,"time":1783352215833,"data":{"turn":1,"step":1}} {"type":"step/start","seq":58,"time":1783352215834,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":59,"time":1783352216779,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.2.jsonl b/examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.2.jsonl index 7b36136970..ed8f566219 100644 --- a/examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.2.jsonl +++ b/examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.2.jsonl @@ -10,7 +10,7 @@ {"type":"assistant/chunk","seq":8,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":9,"time":1784540790335,"data":{"turn":1,"step":1,"content":[{"type":"tool-call","id":"call_depth_three_rejected","name":"subagent","arguments":"{\"description\":\"Exceed depth cap\",\"prompt\":\"This child must never start.\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":10,"outputTokens":5}},"sourceEventSeqs":[4,5,6,7,8],"surfaceOp":"append"} {"type":"tool/call","seq":10,"time":1784540790335,"data":{"turn":1,"step":1,"callId":"call_depth_three_rejected","name":"subagent","arguments":"{\"description\":\"Exceed depth cap\",\"prompt\":\"This child must never start.\"}"}} -{"type":"tool/result","seq":11,"time":1784540790337,"data":{"turn":1,"step":1,"callId":"call_depth_three_rejected","content":[{"type":"text","text":"Error: subagent depth 3 exceeds maxDepth 2"}],"isError":true},"sourceEventSeqs":[10],"surfaceOp":"append"} +{"type":"tool/result","seq":11,"time":1784540790337,"data":{"turn":1,"step":1,"callId":"call_depth_three_rejected","content":[{"type":"text","text":"Error: subagent depth 3 exceeds maxDepth 2"}],"isError":true,"error":{"message":"subagent depth 3 exceeds maxDepth 2"}},"sourceEventSeqs":[10],"surfaceOp":"append"} {"type":"step/end","seq":12,"time":1784540790338,"data":{"turn":1,"step":1}} {"type":"step/start","seq":13,"time":1784540790338,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":14,"time":1784540790339,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"text"}}} diff --git a/packages/bash/tool-bash/README.md b/packages/bash/tool-bash/README.md index 258967fad9..a7eb37f9e3 100644 --- a/packages/bash/tool-bash/README.md +++ b/packages/bash/tool-bash/README.md @@ -49,6 +49,8 @@ The overlay is computed from the current `ToolExecution` and passed through the Result text contains stdout, an optional `[stderr]` section, then applicable sandbox-denial, timeout, signal, exit-code, and truncation markers. Timeout is reported independently of final exit status; nonzero exit remains a model-interpreted result rather than `isError`. Truncation links a safe complete spill file or reports it unavailable. Only infrastructure failures such as spawn errors and aborts produce `isError`. +The canonical success is `{ kind: 'foreground', ...BashRunResult }` for a completed foreground process or `{ kind: 'background', taskId }` for a published task. The Native renderer preserves the text above, including exactly `started background task <id>`; programmatic consumers use the typed fields without parsing those strings. Executor stream caps remain acquisition limits on `BashRunResult` and carry their spill paths. + When `run_in_background` is true, this plugin preflights `ctx.tasks.start()` before spawning, registers the calling agent as owner, and adapts the returned `BashProcess` handle into generic cancel/done/incremental-output hooks. The task runtime owns ids, cross-session isolation, completion notices, waiting, and disposal cleanup; this plugin only maps bash exit/sandbox facts into task output and outcome detail. `enableRunInBackground: false` removes the parameter and rejects a forced background call at execution time. ## UI presentation diff --git a/packages/bash/tool-bash/src/index.ts b/packages/bash/tool-bash/src/index.ts index 6098056fb9..6ee2fc2b99 100644 --- a/packages/bash/tool-bash/src/index.ts +++ b/packages/bash/tool-bash/src/index.ts @@ -22,7 +22,7 @@ import type { SandboxMode } from '@deepseek-ai/dsh-sandbox' import { ESCALATION_TARGETS, approveEscalation, validateEscalationArgs } from '@deepseek-ai/dsh-sandbox' import { effectiveSandboxMode } from '@deepseek-ai/dsh-sandbox-policy' import { DSH_ENV_PREFIX } from '@deepseek-ai/dsh-bash' -import type { DshEnvironment, DshEnvironmentKey } from '@deepseek-ai/dsh-bash' +import type { BashRunResult, DshEnvironment, DshEnvironmentKey } from '@deepseek-ai/dsh-bash' import { DSH_HOME_ENV, resolveDshHome } from '@deepseek-ai/dsh-home' import { processOutcome } from './background.ts' import { parseExitStatus, renderProcessRead, renderResult } from './render.ts' @@ -311,6 +311,38 @@ function resolveWorkdir(modelWorkdir: string | undefined, exec: { agent?: Agent return modelWorkdir } +/** Detach the executor DTO from readonly seam interfaces into plain JSON data. */ +function canonicalBashResult(result: BashRunResult) { + const output = (stream: BashRunResult['stdout']) => ({ + text: stream.text, + truncated: stream.truncated, + ...stream.spillPath !== undefined ? { spillPath: stream.spillPath } : {}, + }) + return { + exitCode: result.exitCode, + signal: result.signal, + timedOut: result.timedOut, + aborted: result.aborted, + timeoutMs: result.timeoutMs, + stdout: output(result.stdout), + stderr: output(result.stderr), + ...result.sandbox !== undefined ? { + sandbox: { + mode: result.sandbox.mode, + denied: result.sandbox.denied, + ...result.sandbox.enforcement !== undefined ? { enforcement: result.sandbox.enforcement } : {}, + ...result.sandbox.runnerFailed !== undefined ? { runnerFailed: result.sandbox.runnerFailed } : {}, + }, + } : {}, + } +} + +/** Canonical background-handle properties shared by the bash output union. */ +const BACKGROUND_OUTPUT_PROPERTIES = { + kind: { type: 'string', required: true, const: 'background' }, + taskId: { type: 'string', required: true }, +} as const + export function apply(ctx: Context, config: Config = {}): void { const bashEnv = new BashEnvRegistry(ctx, config) bashEnv.register({ @@ -398,6 +430,65 @@ export function apply(ctx: Context, config: Config = {}): void { }, } : {}, }, + output: { + schema: { + oneOf: [ + { + type: 'object', + additionalProperties: false, + properties: BACKGROUND_OUTPUT_PROPERTIES, + }, + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'foreground' }, + exitCode: { required: true, oneOf: [{ type: 'integer' }, { type: 'null' }] }, + signal: { required: true, oneOf: [{ type: 'string' }, { type: 'null' }] }, + timedOut: { type: 'boolean', required: true }, + aborted: { type: 'boolean', required: true }, + timeoutMs: { type: 'number', required: true }, + stdout: { + type: 'object', + additionalProperties: false, + required: true, + properties: { + text: { type: 'string', required: true }, + truncated: { type: 'boolean', required: true }, + spillPath: { type: 'string' }, + }, + }, + stderr: { + type: 'object', + additionalProperties: false, + required: true, + properties: { + text: { type: 'string', required: true }, + truncated: { type: 'boolean', required: true }, + spillPath: { type: 'string' }, + }, + }, + sandbox: { + type: 'object', + additionalProperties: false, + properties: { + mode: { type: 'string', required: true }, + denied: { type: 'boolean', required: true }, + enforcement: { type: 'string' }, + runnerFailed: { type: 'boolean' }, + }, + }, + }, + }, + ], + }, + render: (_args, value) => [{ + type: 'text', + text: value.kind === 'background' + ? `started background task ${value.taskId}` + : renderResult(value as { kind: 'foreground' } & BashRunResult, escalationModes), + }], + }, async execute(args: BashToolArgs, exec) { validateBashArgs(args) // Description is display metadata; workdir defaults to the caller's session. @@ -438,14 +529,14 @@ export function apply(ctx: Context, config: Config = {}): void { } }, }) - return [{ type: 'text', text: `started background task ${id}` }] + return { kind: 'background' as const, taskId: id } } const result = await ctx.bash.run(ctx.bash.resolve({ ...request, ...exec.signal ? { signal: exec.signal } : {}, })) if (result.aborted) throw new Error('command aborted') - return [{ type: 'text', text: renderResult(result, escalationModes) }] + return { kind: 'foreground' as const, ...canonicalBashResult(result) } }, presentCall: presentBashCall, presentResult: presentBashResult, diff --git a/packages/bash/tool-bash/tests/tools.spec.ts b/packages/bash/tool-bash/tests/tools.spec.ts index b2a78ff9fe..0158f5f908 100644 --- a/packages/bash/tool-bash/tests/tools.spec.ts +++ b/packages/bash/tool-bash/tests/tools.spec.ts @@ -119,7 +119,13 @@ class RecordingSandboxExecutor extends BashExecutor { timeoutMs: spec.timeoutMs, stdout: { text: 'ok', truncated: false }, stderr: { text: '', truncated: false }, - sandbox: { mode: spec.sandboxMode ?? 'read-only', denied: false }, + sandbox: { + mode: spec.sandboxMode ?? 'read-only', + denied: false, + ...spec.command === 'without optional sandbox facts' + ? {} + : { enforcement: 'full' as const, runnerFailed: false }, + }, }) } @@ -204,6 +210,16 @@ describe('bash tool', () => { const ctx = await setup() const result = await call(ctx, 'bash', { command: 'echo hello', description: 'test command' }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected bash success') + expect(result.value).toMatchObject({ + kind: 'foreground', + exitCode: 0, + signal: null, + timedOut: false, + aborted: false, + stdout: { text: 'hello\n', truncated: false }, + stderr: { text: '', truncated: false }, + }) expect(text(result)).toBe('hello\n') }) @@ -399,6 +415,8 @@ describe('background execution through the task runtime', () => { const ctx = await setupWithTasks() const started = await call(ctx, 'bash', { command: 'echo bg-ok', description: 'test command', run_in_background: true }) expect(started.isError).toBe(false) + if (started.isError) throw new Error('expected background bash success') + expect(started.value).toEqual({ kind: 'background', taskId: 'bash-1' }) expect(text(started)).toBe('started background task bash-1') const read = await callUntilText(ctx, 'task_output', { task_id: 'bash-1' }, 'bg-ok') @@ -606,6 +624,22 @@ describe('sandbox escalation through the generic task producer', () => { expect(bash.modes).toEqual(['workspace-write', 'danger-full-access']) }) + it('omits sandbox facts the executor did not acquire from the canonical result', async () => { + const { ctx } = await setupSandboxed() + const result = await call(ctx, 'bash', { + command: 'without optional sandbox facts', + description: 'exercise optional sandbox facts', + }) + + if (result.isError) throw new Error('expected foreground bash success') + expect(result.value).toMatchObject({ + kind: 'foreground', + sandbox: { mode: 'read-only', denied: false }, + }) + expect((result.value as { sandbox: object }).sandbox).not.toHaveProperty('enforcement') + expect((result.value as { sandbox: object }).sandbox).not.toHaveProperty('runnerFailed') + }) + it('keeps the exhaustiveness backstop for a rogue approval implementation', async () => { const { ctx } = await setupSandboxed(true) ctx.approval.request = () => Promise.resolve('rogue' as ApprovalOutcome) diff --git a/packages/compact/compact-basic/tests/compact-loop-repro.spec.ts b/packages/compact/compact-basic/tests/compact-loop-repro.spec.ts index e899979f46..273bfb3987 100644 --- a/packages/compact/compact-basic/tests/compact-loop-repro.spec.ts +++ b/packages/compact/compact-basic/tests/compact-loop-repro.spec.ts @@ -4,7 +4,7 @@ import { toolPairingBalancedAfter, toolPairingBalancedBefore } from '@deepseek-a import { CONTEXT_WINDOW_EXCEEDED_CODE, LlmError } from '@deepseek-ai/dsh-llm' import type { ContentBlock, GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm' import { CallId, LlmAdapter } from '@deepseek-ai/dsh-llm' -import { defineTool } from '@deepseek-ai/dsh-tools' +import { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import type { Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit' @@ -111,7 +111,7 @@ async function harness(toolSteps: number): Promise<{ ctx: Context; compact: Repr await ctx.plugin(AgentLoop, { agents: [] }) await ctx.plugin(TokenMeterService, { contextWindow: 400 }) ctx.llm.registerAdapter(['mock'], new StepwiseToolAdapter(toolSteps)) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'work', description: 'does work', parameters: { i: { type: 'number' } }, diff --git a/packages/compact/compact-tool-result-prune/tests/tool-result-prune.spec.ts b/packages/compact/compact-tool-result-prune/tests/tool-result-prune.spec.ts index bc382c8e4e..0d3478b1c0 100644 --- a/packages/compact/compact-tool-result-prune/tests/tool-result-prune.spec.ts +++ b/packages/compact/compact-tool-result-prune/tests/tool-result-prune.spec.ts @@ -151,7 +151,7 @@ describe('ToolResultPruneService session transaction', () => { text: 'x'.repeat(100), }], { isError: true, - error: { name: 'ExitError', code: 'EXIT_1' }, + error: { message: 'exit 1', info: { name: 'ExitError', code: 'EXIT_1' } }, meta: { diff: ['a', 'b'] }, futureField: { nested: true }, }) @@ -180,7 +180,7 @@ describe('ToolResultPruneService session transaction', () => { step: 1, callId: CallId('one'), isError: true, - error: { name: 'ExitError', code: 'EXIT_1' }, + error: { message: 'exit 1', info: { name: 'ExitError', code: 'EXIT_1' } }, meta: { diff: ['a', 'b'] }, futureField: { nested: true }, }, diff --git a/packages/context/time-context/tests/time-context.spec.ts b/packages/context/time-context/tests/time-context.spec.ts index 06ae13818d..d69a7bb2ed 100644 --- a/packages/context/time-context/tests/time-context.spec.ts +++ b/packages/context/time-context/tests/time-context.spec.ts @@ -6,7 +6,7 @@ import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm' import { Session, SessionId } from '@deepseek-ai/dsh-session' import AgentRegistry from '@deepseek-ai/dsh-agent' import type { Agent } from '@deepseek-ai/dsh-agent' -import { defineTool } from '@deepseek-ai/dsh-tools' +import { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit' import * as timeContext from '@deepseek-ai/dsh-time-context' @@ -387,7 +387,7 @@ describe('real agent-loop request history', () => { it('persists one ordered context per request, accumulates readings, and leaves system headers unchanged', async () => { const adapter = new ScriptedAdapter([toolCallResponse(), textResponse('done')]) const ctx = await loopHarness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'tick', description: 'advance fake time', parameters: {}, diff --git a/packages/context/workspace-context/src/index.ts b/packages/context/workspace-context/src/index.ts index 21ef979459..77cef391b6 100644 --- a/packages/context/workspace-context/src/index.ts +++ b/packages/context/workspace-context/src/index.ts @@ -128,8 +128,7 @@ export function apply(ctx: Context, config: Config): void { if (update === undefined) return downstream pendingVersionUpdates.set(exec.token, update.versionUpdates) return { - kind: 'accept', - ...downstream.content !== undefined ? { content: downstream.content } : {}, + ...downstream, additionalContexts: [update.context, ...downstream.additionalContexts ?? []], } }) diff --git a/packages/context/workspace-context/tests/workspace-context.spec.ts b/packages/context/workspace-context/tests/workspace-context.spec.ts index 8b0320bcfc..8d1fa4a339 100644 --- a/packages/context/workspace-context/tests/workspace-context.spec.ts +++ b/packages/context/workspace-context/tests/workspace-context.spec.ts @@ -22,7 +22,7 @@ import type { } from '@deepseek-ai/dsh-fs' import LocalFileSystem from '@deepseek-ai/dsh-fs-local' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import type { ToolExecution, ToolExecutionToken } from '@deepseek-ai/dsh-tools' import * as ToolFs from '@deepseek-ai/dsh-tool-fs' import { @@ -800,6 +800,7 @@ describe('workspace context request injection', () => { agent: stubAgent('/virtual/repo'), }), { isError: false, + value: null, content: [{ type: 'text', text: 'file content' }], }, async () => ({ kind: 'accept', @@ -835,7 +836,8 @@ describe('workspace context request injection', () => { agent, }) const result = { - isError: false, + isError: false as const, + value: null, content: [{ type: 'text' as const, text: 'hello' }], } @@ -1589,7 +1591,7 @@ describe('dynamic nested workspace context injection', () => { await ctx.plugin(AgentLoop, { agents: [] }) ctx.llm.registerAdapter(['mock'], adapter) const agent = ctx.agentLoop.create(SessionId('workspace-context-abort'), { provider: 'mock', model: 'mock' }, { cwd: root }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'abort_step', description: 'Abort the current test step.', parameters: {}, @@ -1660,6 +1662,7 @@ describe('dynamic nested workspace context injection', () => { const pending = ctx.waterfall('tools/post-execute', exec, { content: [{ type: 'text', text: 'ok' }], isError: false, + value: null, }, () => Promise.resolve({ kind: 'accept' as const })) await expect(pending).rejects.toBe(reason) @@ -2380,7 +2383,8 @@ describe('dynamic nested workspace context injection', () => { const result = { callId: CallId('provider-probe-result'), content: [{ type: 'text' as const, text: 'ok' }], - isError: false, + isError: false as const, + value: null, } const failedStat = await ctx.waterfall('tools/post-execute', stubToolExecution({ @@ -2429,7 +2433,7 @@ describe('dynamic nested workspace context injection', () => { } }) - it('preserves nested and downstream post-execute contexts as separate entries', async () => { + it('preserves a downstream canonical value replacement and keeps contexts separate', async () => { const root = await tempRepo() const home = await tempRepo() try { @@ -2440,7 +2444,12 @@ describe('dynamic nested workspace context injection', () => { await mountFileToolsAndWorkspaceContext(ctx, { dshHome: home, maxBytes: 65536 }) ctx.on('tools/post-execute', async () => ({ kind: 'accept' as const, - content: [{ type: 'text' as const, text: 'downstream replacement' }], + value: { + path: 'pkg/deep/file.txt', + offset: 1, + lines: [{ number: 1, text: 'downstream replacement' }], + totalLines: 1, + }, additionalContexts: [{ content: [{ type: 'text' as const, text: 'downstream context' }], source: { kind: 'plugin' as const, plugin: 'downstream' }, @@ -2454,7 +2463,15 @@ describe('dynamic nested workspace context injection', () => { agent: stubAgent(root), }) - expect(blocksText(result.content)).toBe('downstream replacement') + expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected read replacement success') + expect(result.value).toEqual({ + path: 'pkg/deep/file.txt', + offset: 1, + lines: [{ number: 1, text: 'downstream replacement' }], + totalLines: 1, + }) + expect(blocksText(result.content)).toContain('downstream replacement') expect(result.additionalContexts).toHaveLength(2) expect(workspaceContextOf(result)?.source).toEqual({ kind: 'plugin', plugin: 'workspace-context' }) expect(workspaceContextOf(result)?.meta).toMatchObject({ @@ -2568,7 +2585,7 @@ describe('dynamic nested workspace context injection', () => { await ctx.plugin(ToolRegistry) await ctx.plugin(LocalFileSystem, { cwd: '/' }) await ctx.plugin(ToolFs) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'composite-read', description: 'read through a nested dispatch', parameters: {}, @@ -2620,7 +2637,7 @@ describe('dynamic nested workspace context injection', () => { await ctx.plugin(workspaceContext, { maxBytes: 65536 }) const agent = stubAgent('/') const parent = Symbol('parent') as ToolExecutionToken - const plainResult = { callId: CallId('plain'), content: [], isError: false } + const plainResult = { callId: CallId('plain'), content: [], isError: false as const, value: null } ctx.emit('tools/result', stubToolExecution({ callId: CallId('agentless-child'), name: 'read', arguments: {}, parent, @@ -2658,7 +2675,8 @@ describe('dynamic nested workspace context injection', () => { const result = { callId: CallId('manual'), content: [{ type: 'text' as const, text: 'manual result' }], - isError: false, + isError: false as const, + value: null, } const cases = [ { name: 'read', arguments: { file_path: 'pkg/deep/file.txt' }, agent: undefined }, diff --git a/packages/cordis/tool-cordis/README.md b/packages/cordis/tool-cordis/README.md index 7819cb8c2c..51a6850fad 100644 --- a/packages/cordis/tool-cordis/README.md +++ b/packages/cordis/tool-cordis/README.md @@ -10,6 +10,8 @@ The self-referential cordis toolset: three model-facing tools over the live runt Exact model-facing schemas: [the generated tool catalog](../../../docs/tool-catalog.md). +Canonical successes are the inspection string, mount `{ id, pluginName, state, provides, waitingFor }`, and unmount `{ id, pluginName }`. Native renderers preserve the existing prose, so programs can use `mounted.id` while ordinary function calling still sees `mounted dyn-1 (...)`. + ## Trust stance The sandbox isolates globals but is not a security boundary. Node globals are absent or redirect to Cordis services such as `ctx.fs`, `ctx.web`, and `ctx.bash`, and writes to `globalThis` stay local, but host-realm helpers make escape possible. Mounted plugins receive a façade without framework internals, yet its allowed services affect the live runtime. Treat this toolset like bash access; see the [design and trust stance](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). diff --git a/packages/cordis/tool-cordis/src/api-catalog.ts b/packages/cordis/tool-cordis/src/api-catalog.ts index 23ffa88923..e8ddc86f83 100644 --- a/packages/cordis/tool-cordis/src/api-catalog.ts +++ b/packages/cordis/tool-cordis/src/api-catalog.ts @@ -1450,7 +1450,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'SessionEventMap', - declaration: 'export interface SessionEventMap {\n \'turn/start\': {\n turn: number;\n trigger: TurnTrigger;\n };\n \'turn/end\': {\n turn: number;\n reason: TurnEndReason;\n };\n \'step/start\': {\n turn: number;\n step: number;\n };\n \'step/end\': {\n turn: number;\n step: number;\n };\n \'user/message\': {\n content: ContentBlock[];\n source: MessageSource;\n };\n \'prompt/blocked\': {\n content: ContentBlock[];\n source: MessageSource;\n reason: string;\n };\n \'context/message\': {\n content: ContentBlock[];\n source: MessageSource;\n meta?: JsonValue;\n };\n \'assistant/chunk\': {\n turn: number;\n step: number;\n chunk: StreamChunk;\n };\n \'assistant/message\': {\n turn: number;\n step: number;\n content: ContentBlock[];\n provenance: AssistantProvenance;\n usage?: TokenUsage;\n };\n \'tool/call\': {\n turn: number;\n step: number;\n callId: CallId;\n name: string;\n arguments: string;\n };\n \'tool/result\': {\n turn: number;\n step: number;\n callId: CallId;\n content: ContentBlock[];\n isError: boolean;\n error?: {\n name: string;\n code: string;\n };\n meta?: unknown;\n };\n \'steering/message\': {\n turn: number;\n content: ContentBlock[];\n source: MessageSource;\n };\n \'todo/write\': {\n /* …truncated — full shape in source */', + declaration: 'export interface SessionEventMap {\n \'turn/start\': {\n turn: number;\n trigger: TurnTrigger;\n };\n \'turn/end\': {\n turn: number;\n reason: TurnEndReason;\n };\n \'step/start\': {\n turn: number;\n step: number;\n };\n \'step/end\': {\n turn: number;\n step: number;\n };\n \'user/message\': {\n content: ContentBlock[];\n source: MessageSource;\n };\n \'prompt/blocked\': {\n content: ContentBlock[];\n source: MessageSource;\n reason: string;\n };\n \'context/message\': {\n content: ContentBlock[];\n source: MessageSource;\n meta?: JsonValue;\n };\n \'assistant/chunk\': {\n turn: number;\n step: number;\n chunk: StreamChunk;\n };\n \'assistant/message\': {\n turn: number;\n step: number;\n content: ContentBlock[];\n provenance: AssistantProvenance;\n usage?: TokenUsage;\n };\n \'tool/call\': {\n turn: number;\n step: number;\n callId: CallId;\n name: string;\n arguments: string;\n };\n \'tool/result\': {\n turn: number;\n step: number;\n callId: CallId;\n content: ContentBlock[];\n isError: boolean;\n error?: {\n message: string;\n info?: {\n name: string;\n code: string;\n };\n };\n meta?: JsonValue;\n };\n \'steering/message\': {\n turn: number;\n content: Content /* …truncated — full shape in source */', }, { name: 'SessionEventReadRequest', @@ -1674,20 +1674,20 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'ToolDefinition', - declaration: 'export interface ToolDefinition extends ToolSchema {\n execute(args: unknown, exec: ToolRunContext): Promise<ToolExecuteReturn>;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n}', + declaration: 'export interface ToolDefinition extends ToolSchema {\n readonly output: ToolOutputDefinition;\n execute(args: unknown, exec: ToolRunContext): Promise<unknown>;\n timeoutMs?: number;\n isConcurrencySafe?(args: unknown): boolean;\n presentCall?(args: unknown): ToolCallView | undefined;\n presentResult?(args: unknown, result: ToolResult): ToolResultView | undefined;\n}', }, { name: 'ToolErrorInfo', declaration: 'export interface ToolErrorInfo {\n name: string;\n code: string;\n}', }, - { - name: 'ToolExecuteReturn', - declaration: 'export type ToolExecuteReturn = ContentBlock[] | {\n content: ContentBlock[];\n meta?: unknown;\n};', - }, { name: 'ToolExecution', declaration: 'export interface ToolExecution extends ToolExecutionInput {\n readonly token: ToolExecutionToken;\n}', }, + { + name: 'ToolExecutionFailure', + declaration: 'export interface ToolExecutionFailure {\n readonly isError: true;\n readonly error: ToolFailure;\n readonly value?: never;\n readonly content: ContentBlock[];\n readonly meta?: JsonValue;\n readonly additionalContexts?: HookContext[];\n}', + }, { name: 'ToolExecutionInput', declaration: 'export interface ToolExecutionInput {\n readonly callId: CallId;\n readonly name: string;\n readonly arguments: unknown;\n readonly agent?: Agent;\n readonly parent?: ToolExecutionToken;\n signal?: AbortSignal;\n}', @@ -1698,16 +1698,28 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'ToolExecutionResult', - declaration: 'export interface ToolExecutionResult {\n content: ContentBlock[];\n isError: boolean;\n error?: ToolErrorInfo;\n additionalContexts?: HookContext[];\n meta?: unknown;\n}', + declaration: 'export type ToolExecutionResult = ToolExecutionSuccess | ToolExecutionFailure;', + }, + { + name: 'ToolExecutionSuccess', + declaration: 'export interface ToolExecutionSuccess {\n readonly isError: false;\n readonly value: JsonValue;\n readonly content: ContentBlock[];\n readonly error?: never;\n readonly meta?: JsonValue;\n readonly additionalContexts?: HookContext[];\n}', }, { name: 'ToolExecutionToken', declaration: 'export type ToolExecutionToken = symbol & {\n readonly [toolExecutionTokenBrand]: true;\n};', }, + { + name: 'ToolFailure', + declaration: 'export interface ToolFailure {\n message: string;\n info?: ToolErrorInfo;\n}', + }, { name: 'ToolGuard', declaration: 'export type ToolGuard = (execution: Readonly<ToolExecution>) => string | undefined;', }, + { + name: 'ToolOutputDefinition', + declaration: 'export interface ToolOutputDefinition {\n readonly schema: JsonSchemaNode;\n render(args: unknown, value: JsonValue): ContentBlock[];\n presentationMeta?(args: unknown, value: JsonValue): JsonValue;\n}', + }, { name: 'ToolProviderResult', declaration: 'export interface ToolProviderResult {\n readonly schemas: readonly ToolSchema[];\n readonly knownNames?: readonly string[];\n}', @@ -1718,7 +1730,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'ToolResult', - declaration: 'export interface ToolResult {\n content: ContentBlock[];\n isError: boolean;\n meta?: unknown;\n}', + declaration: 'export interface ToolResult {\n content: ContentBlock[];\n isError: boolean;\n meta?: JsonValue;\n}', }, { name: 'ToolResultBlock', diff --git a/packages/cordis/tool-cordis/src/fiber-state.ts b/packages/cordis/tool-cordis/src/fiber-state.ts index 8c9f0e2f45..dcd9da149b 100644 --- a/packages/cordis/tool-cordis/src/fiber-state.ts +++ b/packages/cordis/tool-cordis/src/fiber-state.ts @@ -21,11 +21,11 @@ export const FiberState = { export type FiberState = FiberStateEnum /** Human-readable label for each {@link FiberState}, keyed by member (inlining-safe — no reverse mapping). */ -export const STATE_LABELS: Record<FiberState, string> = { +export const STATE_LABELS = { [FiberState.PENDING]: 'pending', [FiberState.LOADING]: 'loading', [FiberState.ACTIVE]: 'active', [FiberState.FAILED]: 'failed', [FiberState.DISPOSED]: 'disposed', [FiberState.UNLOADING]: 'unloading', -} +} as const satisfies Record<FiberState, string> diff --git a/packages/cordis/tool-cordis/src/guard.ts b/packages/cordis/tool-cordis/src/guard.ts index c55fd34b78..47cb8a7a53 100644 --- a/packages/cordis/tool-cordis/src/guard.ts +++ b/packages/cordis/tool-cordis/src/guard.ts @@ -6,8 +6,8 @@ * return values with. The façade is a whitelist of lifecycle-safe verbs and declared services; * framework internals and context-valued service returns are denied. * - * VM-realm schemas are rebuilt as host objects, and tool results are JSON-round-tripped and - * shape-checked before session logging. Common JSON-Schema spellings are normalized when they + * VM-realm schemas and canonical values are rebuilt as host objects, while rendered content and + * presentation metadata are shape-checked before entering the registry. Common JSON-Schema spellings are normalized when they * have one meaning; invalid vocabulary fails during registration with a teaching error. * @module @deepseek-ai/dsh-tool-cordis/guard */ @@ -16,7 +16,9 @@ import { Context } from 'cordis' import type { Plugin } from 'cordis' import { scopeOf } from '@deepseek-ai/dsh-scope' import { assertSupportedJsonSchema, defineTool } from '@deepseek-ai/dsh-tools' -import type { ToolDefinition, ToolExecuteReturn } from '@deepseek-ai/dsh-tools' +import type { ToolDefinition } from '@deepseek-ai/dsh-tools' +import type { ContentBlock } from '@deepseek-ai/dsh-llm' +import type { JsonValue } from '@deepseek-ai/dsh-session' const DYNAMIC_TOOL = Symbol('tool-cordis.dynamic-tool') const SCHEMA_TYPES = new Set<unknown>(['string', 'number', 'integer', 'boolean', 'null', 'object', 'array', 'json']) @@ -254,34 +256,23 @@ const RETURN_PREVIEW_LIMIT = 120 * (`String(…)` for the un-stringifiable undefined case), truncated to * {@link RETURN_PREVIEW_LIMIT}. */ -function describeReturn(value: unknown): string { - // JSON.stringify is TYPED as always returning string, but it yields - // undefined for an undefined input (the routed forgot-return case) — the - // assertion widens the type back to the runtime truth. - const json = JSON.stringify(value) as string | undefined - if (json === undefined) return String(value) +function describeReturn(value: JsonValue): string { + // The caller has already crossed cloneJson, so this value is lossless JSON + // and serialization cannot produce undefined. + const json = JSON.stringify(value) return json.length > RETURN_PREVIEW_LIMIT ? `${json.slice(0, RETURN_PREVIEW_LIMIT)}…` : json } /** - * Validate a round-tripped `execute` return against the two shapes - * {@link ToolExecuteReturn} allows: an ARRAY of content blocks, or - * `{ content: blocks, meta? }`. The registry trusts the shape blindly — it - * spreads `result.content`, so an unvalidated `{ content: 'ok' }` would enter - * the session log as `['o','k']` and silently corrupt the next model request — - * so a wrong shape fails THIS call with a teaching error instead. + * Validate and host-materialize a sandbox renderer's content blocks. */ -function assertExecuteReturn(value: unknown): ToolExecuteReturn { +function assertRenderedContent(value: JsonValue): ContentBlock[] { if (Array.isArray(value) && value.every(isContentBlockShape)) { - return value as ToolExecuteReturn - } - if (isPlainRecord(value) && Array.isArray(value.content) && value.content.every(isContentBlockShape)) { - return value as ToolExecuteReturn + return value as unknown as ContentBlock[] } throw new Error( - `execute returned ${describeReturn(value)} — a tool's execute must return an ARRAY of content blocks, never a bare string:\n` - + ' ✓ return [{ type: \'text\', text: someString }]\n' - + ' ✓ return { content: [{ type: \'text\', text: someString }], meta: anyJsonValue }', + `output.render returned ${describeReturn(value)} — it must return an ARRAY of content blocks:\n` + + ' ✓ return [{ type: \'text\', text: String(value) }]', ) } @@ -294,23 +285,46 @@ function assertExecuteReturn(value: unknown): ToolExecuteReturn { * @param options - the standard `defineTool` options; `parameters` may be the ParameterSchemaSpec DSL or a JSON-Schema-style wrapper. * @returns the marker-tagged definition `harness.registerTool` (and the guarded `ctx.tools.register`) accepts. */ -export function sandboxDefineTool(options: Parameters<typeof defineTool>[0]): ToolDefinition { - const normalized = normalizeParameterSchemaSpec((options as { parameters?: unknown }).parameters) - const tool = defineTool({ ...options, parameters: normalized.spec } as Parameters<typeof defineTool>[0]) +export function sandboxDefineTool(options: unknown): ToolDefinition { + if (!isPlainRecord(options)) throw new Error('harness.defineTool options must be an object') + const normalized = normalizeParameterSchemaSpec(options.parameters) + if (!isPlainRecord(options.output)) { + throw new Error('harness.defineTool output must declare { schema, render, presentationMeta? }') + } + const output = options.output + if (typeof output.render !== 'function') throw new Error('harness.defineTool output.render must be a function') + if (output.presentationMeta !== undefined && typeof output.presentationMeta !== 'function') { + throw new Error('harness.defineTool output.presentationMeta must be a function when present') + } + if (typeof options.execute !== 'function') throw new Error('harness.defineTool execute must be a function') + const schema = normalizeValueSchema(output.schema, 'output.schema') + const rawExecute = options.execute as (args: unknown, exec: unknown) => Promise<unknown> + const rawRender = output.render as (args: unknown, value: unknown) => unknown + const rawPresentationMeta = output.presentationMeta as ((args: unknown, value: unknown) => unknown) | undefined + const erasedDefineTool = defineTool as unknown as (definition: unknown) => ToolDefinition + const tool = erasedDefineTool({ + ...options, + parameters: normalized.spec, + output: { + schema, + render(args: unknown, value: unknown): ContentBlock[] { + return assertRenderedContent(cloneJson(rawRender(args, value), 'output.render result') as JsonValue) + }, + ...rawPresentationMeta !== undefined ? { + presentationMeta(args: unknown, value: unknown): JsonValue { + return cloneJson(rawPresentationMeta(args, value), 'output.presentationMeta result') as JsonValue + }, + } : {}, + }, + async execute(args: unknown, exec: unknown): Promise<JsonValue> { + return cloneJson(await rawExecute(args, exec), 'execute result') as JsonValue + }, + }) const parameters = { ...tool.parameters, ...normalized.rootAnnotations } assertSupportedJsonSchema(parameters) - const execute = tool.execute.bind(tool) return markDynamicTool({ ...tool, parameters, - async execute(args, exec) { - // JSON.stringify yields NO JSON for an undefined (or function/symbol) - // return despite its string-typed signature — route that into - // assertExecuteReturn's teaching error rather than letting JSON.parse - // throw its cryptic '"undefined" is not valid JSON'. - const json = JSON.stringify(await execute(args, exec)) as string | undefined - return assertExecuteReturn(json === undefined ? undefined : JSON.parse(json) as unknown) - }, }) } diff --git a/packages/cordis/tool-cordis/src/index.ts b/packages/cordis/tool-cordis/src/index.ts index 9ac29aeb07..15fd735468 100644 --- a/packages/cordis/tool-cordis/src/index.ts +++ b/packages/cordis/tool-cordis/src/index.ts @@ -13,7 +13,7 @@ import { defineTool } from '@deepseek-ai/dsh-tools' import { STATE_LABELS } from './fiber-state.ts' import { isPlugin, pluginName } from './guard.ts' import { EVENT_API, INHERITED_CTX_API, SERVICE_API, TYPE_API } from './api-catalog.ts' -import { describeApi, describeDynamic, describeEvents, describePlugins, describeServices, describeTools } from './inspect.ts' +import { describeApi, describeDynamic, describeEvents, describePlugins, describeServices, describeTools, providedServices } from './inspect.ts' import { missingServices, mountDynamic, type DynamicMount } from './mount.ts' import { presentInspectCall, presentMountCall, presentUnmountCall } from './present.ts' import { createSandbox, evaluateMountCode } from './sandbox.ts' @@ -76,7 +76,11 @@ export function apply(ctx: Context, config: Config): void { description: 'Exact service key or event name whose original JSDoc to include; valid only with what:"api" or what:"events".', }, }, - execute(args, exec): Promise<{ type: 'text'; text: string }[]> { + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, + execute(args, exec): Promise<string> { if (args.name !== undefined && args.what !== 'api' && args.what !== 'events') { throw new Error('name is valid only with what:"api" or what:"events"') } @@ -94,7 +98,7 @@ export function apply(ctx: Context, config: Config): void { const text = selected .map(([heading, body]) => `## ${heading}\n${body().join('\n')}`) .join('\n\n') - return Promise.resolve([{ type: 'text', text }]) + return Promise.resolve(text) }, presentCall: presentInspectCall, })) @@ -119,13 +123,14 @@ export function apply(ctx: Context, config: Config): void { + 'Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe ' + 'events (see cordis_inspect what:"events"), or call ' + '`harness.registerTool(ctx, harness.defineTool({ name, description, parameters: ' - + '{ text: { type: \'string\', required: true } }, async execute(args) { … } }))` ' + + '{ text: { type: \'string\', required: true } }, output: { schema: { type: \'string\' }, ' + + 'render(_args, value) { return [{ type: \'text\', text: value }] } }, async execute(args) { return args.text } }))` ' + 'to give yourself a new tool — it becomes callable on your NEXT step. ' + 'Tool parameters: each key IS a property — { type: \'string\'|\'number\'|\'integer\'|\'boolean\'|\'null\'|\'object\'|\'array\'|\'json\', ' + 'required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and ' + 'oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: \'object\', properties, required?: […] } wrapper is also accepted with open-by-default objects. A ' - + 'tool\'s `execute` MUST return an ARRAY of content blocks, e.g. `return ' - + '[{ type: \'text\', text: someString }]` — never a bare string. ' + + 'tool\'s `execute` MUST return the lossless JSON value declared by `output.schema`; ' + + '`output.render(args, value)` separately returns Native/model content blocks. ' + 'Mounts can COMPOSE: one plugin may `ctx.provide(\'name\', value)` a service and ' + 'another may declare `inject: [\'name\']` to consume it — the consumer stays pending ' + 'until the provider exists and returns to pending when the provider is unmounted. ' @@ -157,6 +162,32 @@ export function apply(ctx: Context, config: Config): void { description: 'Body of an async JS function; must `return` the plugin to mount.', }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + id: { type: 'string', required: true }, + pluginName: { type: 'string', required: true }, + state: { + type: 'string', + required: true, + enum: ['pending', 'loading', 'active', 'failed', 'disposed', 'unloading'], + }, + provides: { type: 'array', required: true, items: { type: 'string' } }, + waitingFor: { type: 'array', required: true, items: { type: 'string' } }, + }, + }, + render: (_args, value) => { + const note = value.waitingFor.length > 0 + ? ` — waiting for service(s): ${value.waitingFor.join(', ')} (activates when provided)` + : '' + return [{ + type: 'text', + text: `mounted ${value.id} (plugin "${value.pluginName}", state: ${value.state}${note})`, + }] + }, + }, async execute(args) { const id = `dyn-${nextId++}` const sandbox = createSandbox(id) @@ -180,10 +211,13 @@ export function apply(ctx: Context, config: Config): void { // it mounted but tell the model what it is waiting for. const missing = missingServices(ctx, fiber) const state = STATE_LABELS[fiber.state] - const note = missing.length > 0 - ? ` — waiting for service(s): ${missing.join(', ')} (activates when provided)` - : '' - return [{ type: 'text', text: `mounted ${id} (plugin "${pluginName(evaluated)}", state: ${state}${note})` }] + return { + id, + pluginName: pluginName(evaluated), + state, + provides: providedServices(ctx, fiber), + waitingFor: missing, + } }, presentCall: presentMountCall, })) @@ -202,6 +236,17 @@ export function apply(ctx: Context, config: Config): void { description: 'The dynamic mount id returned by cordis_mount (e.g. "dyn-1").', }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + id: { type: 'string', required: true }, + pluginName: { type: 'string', required: true }, + }, + }, + render: (_args, value) => [{ type: 'text', text: `unmounted ${value.id} (plugin "${value.pluginName}")` }], + }, async execute(args) { const mount = mounts.get(args.id) if (!mount) { @@ -209,7 +254,7 @@ export function apply(ctx: Context, config: Config): void { } await mount.fiber.dispose() mounts.delete(args.id) - return [{ type: 'text', text: `unmounted ${args.id} (plugin "${mount.pluginName}")` }] + return { id: args.id, pluginName: mount.pluginName } }, presentCall: presentUnmountCall, })) diff --git a/packages/cordis/tool-cordis/src/inspect.ts b/packages/cordis/tool-cordis/src/inspect.ts index 7196f370ce..cdcad29699 100644 --- a/packages/cordis/tool-cordis/src/inspect.ts +++ b/packages/cordis/tool-cordis/src/inspect.ts @@ -33,8 +33,13 @@ function withinFiber(fiber: Fiber, root: Fiber): boolean { } } -/** The service names provided by a mount's fiber subtree, sorted. */ -function providedBy(ctx: Context, fiber: Fiber): string[] { +/** + * Return the service names provided by a mount's fiber subtree. + * @param ctx - the runtime whose service registrations are inspected. + * @param fiber - the root of the mounted fiber subtree. + * @returns the provided service names in lexical order. + */ +export function providedServices(ctx: Context, fiber: Fiber): string[] { return liveImpls(ctx) .filter(impl => withinFiber(impl.fiber, fiber)) .map(impl => impl.name) @@ -96,7 +101,7 @@ export function describeTools(ctx: Context, scope?: ScopeKey): string[] { export function describeDynamic(ctx: Context, mounts: ReadonlyMap<string, DynamicMount>): string[] { if (mounts.size === 0) return ['(no dynamic plugins mounted)'] return [...mounts].map(([id, mount]) => { - const provides = providedBy(ctx, mount.fiber) + const provides = providedServices(ctx, mount.fiber) const waiting = missingServices(ctx, mount.fiber) const providesNote = provides.length > 0 ? ` — provides: ${provides.join(', ')}` : '' const waitingNote = waiting.length > 0 ? ` — waiting for: ${waiting.join(', ')}` : '' diff --git a/packages/cordis/tool-cordis/tests/cross-mount.spec.ts b/packages/cordis/tool-cordis/tests/cross-mount.spec.ts index dcfdb815c4..b2e515b4c8 100644 --- a/packages/cordis/tool-cordis/tests/cross-mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/cross-mount.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { call, CONSUMER_CODE, PROVIDER_CODE, setup, text } from './helpers.ts' +import { call, CONSUMER_CODE, CONTENT_OUTPUT_CODE, PROVIDER_CODE, setup, text } from './helpers.ts' /** * Cross-mount composition through ordinary cordis provide/inject semantics: @@ -116,6 +116,7 @@ describe('cross-mount provide/inject', () => { name: 'answer', description: 'Read the provided primitive services.', parameters: {}, + ${CONTENT_OUTPUT_CODE} async execute() { return [{ type: 'text', text: ctx.answer + '/' + ctx.get('answer') + '/' + ctx.nothing }] }, diff --git a/packages/cordis/tool-cordis/tests/helpers.ts b/packages/cordis/tool-cordis/tests/helpers.ts index b183a2444f..6a681b93c6 100644 --- a/packages/cordis/tool-cordis/tests/helpers.ts +++ b/packages/cordis/tool-cordis/tests/helpers.ts @@ -45,6 +45,13 @@ export const LISTENER_CODE = ` } ` +/** Explicit content-array output declaration for dynamic-tool behavior fixtures. */ +export const CONTENT_OUTPUT_CODE = ` + output: { + schema: { type: 'array', items: { type: 'json' } }, + render(_args, value) { return value }, + },` + /** Mount code for a self-made tool: registers `reverse_text` via the sandbox's harness helpers. */ export const REVERSE_TOOL_CODE = ` return { @@ -55,8 +62,14 @@ export const REVERSE_TOOL_CODE = ` name: 'reverse_text', description: 'Reverse a string.', parameters: { text: { type: 'string', required: true } }, + output: { + schema: { type: 'string' }, + render(_args, value) { + return [{ type: 'text', text: value }] + }, + }, async execute(args) { - return [{ type: 'text', text: args.text.split('').reverse().join('') }] + return args.text.split('').reverse().join('') }, })) }, @@ -83,8 +96,14 @@ export const CONSUMER_CODE = ` name: 'greet', description: 'Greet someone via the greeter service.', parameters: { name: { type: 'string', required: true } }, + output: { + schema: { type: 'string' }, + render(_args, value) { + return [{ type: 'text', text: value }] + }, + }, async execute(args) { - return [{ type: 'text', text: ctx.greeter.greet(args.name) }] + return ctx.greeter.greet(args.name) }, })) }, @@ -97,8 +116,9 @@ export function dummyTool(name: string): ToolDefinition { name, description: 'test trigger', parameters: { type: 'object' as const, properties: {} }, - async execute(): Promise<[]> { - return [] + output: { schema: { type: 'null' }, render: () => [] }, + async execute(): Promise<null> { + return null }, } } diff --git a/packages/cordis/tool-cordis/tests/inspect.spec.ts b/packages/cordis/tool-cordis/tests/inspect.spec.ts index 4d986d4f3e..8eaa154535 100644 --- a/packages/cordis/tool-cordis/tests/inspect.spec.ts +++ b/packages/cordis/tool-cordis/tests/inspect.spec.ts @@ -16,6 +16,8 @@ describe('cordis_inspect', () => { const result = await call(ctx, 'cordis_inspect', {}) expect(result.isError).toBe(false) const report = text(result) + if (result.isError) throw new Error('expected cordis_inspect success') + expect(result.value).toBe(report) for (const heading of ['services', 'plugins', 'tools', 'dynamic', 'api', 'events']) { expect(report).toContain(`## ${heading}`) } diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 42af6fc64e..6d98cb33a3 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -1,7 +1,8 @@ import { afterEach, describe, expect, it, vi } from 'vitest' import { isJsonValue } from '@deepseek-ai/dsh-session' +import { sandboxDefineTool } from '../src/guard.ts' import { syntaxErrorContext } from '../src/sandbox.ts' -import { call, dummyTool, LISTENER_CODE, REVERSE_TOOL_CODE, setup, text } from './helpers.ts' +import { call, CONTENT_OUTPUT_CODE, dummyTool, LISTENER_CODE, REVERSE_TOOL_CODE, setup, text } from './helpers.ts' /** * The `cordis_mount` success/failure family: real plugins land on a genuine @@ -14,12 +15,48 @@ afterEach(() => { }) describe('cordis_mount', () => { + it.each([ + [42, 'options must be an object'], + [{ parameters: {} }, 'output must declare { schema, render, presentationMeta? }'], + [{ parameters: {}, output: { schema: { type: 'json' } }, execute: async (): Promise<null> => null }, 'output.render must be a function'], + [{ parameters: {}, output: { schema: { type: 'json' }, render: () => [] }, execute: true }, 'execute must be a function'], + [{ + parameters: {}, + output: { schema: { type: 'json' }, render: () => [], presentationMeta: true }, + execute: async (): Promise<null> => null, + }, 'output.presentationMeta must be a function'], + ])('rejects an invalid dynamic tool declaration before registration: %j', (definition, message) => { + expect(() => sandboxDefineTool(definition)).toThrow(message) + }) + + it('bounds the preview of an invalid dynamic renderer return', () => { + const definition = sandboxDefineTool({ + name: 'invalid-renderer', + description: 'invalid renderer', + parameters: {}, + output: { + schema: { type: 'string' }, + render: () => ['x'.repeat(500)], + }, + execute: async () => 'ok', + }) + expect(() => definition.output.render({}, 'ok')).toThrow(/output\.render returned \["x+…/) + }) + it('mounts a listener plugin that observes real events, tagged-logging through to the host console', async () => { const ctx = await setup() const log = vi.spyOn(console, 'log').mockImplementation(() => {}) const result = await call(ctx, 'cordis_mount', { code: LISTENER_CODE }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected cordis_mount success') + expect(result.value).toEqual({ + id: 'dyn-1', + pluginName: 'change-logger', + state: 'active', + provides: [], + waitingFor: [], + }) expect(text(result)).toContain('mounted dyn-1 (plugin "change-logger", state: active)') // Fire a REAL tools/change by registering a tool; the mounted listener logs. @@ -44,6 +81,8 @@ describe('cordis_mount', () => { expect(ctx.tools.schemas().map(schema => schema.name)).toContain('reverse_text') const reversed = await call(ctx, 'reverse_text', { text: 'harness' }) expect(reversed.isError).toBe(false) + if (reversed.isError) throw new Error('expected dynamic tool success') + expect(reversed.value).toBe('ssenrah') expect(text(reversed)).toBe('ssenrah') }) @@ -55,7 +94,7 @@ describe('cordis_mount', () => { expect(isJsonValue({ content: reversed.content, isError: reversed.isError })).toBe(true) }) - it('threads the { content, meta } object return form through to the registry result', async () => { + it('projects presentation metadata from a dynamic canonical value', async () => { const ctx = await setup() await call(ctx, 'cordis_mount', { code: ` @@ -67,8 +106,13 @@ describe('cordis_mount', () => { name: 'meta_tool', description: 'attaches a private presentation payload', parameters: {}, + output: { + schema: { type: 'string' }, + render(_args, value) { return [{ type: 'text', text: value }] }, + presentationMeta() { return { kind: 'demo' } }, + }, async execute() { - return { content: [{ type: 'text', text: 'ok' }], meta: { kind: 'demo' } } + return 'ok' }, })) }, @@ -77,20 +121,20 @@ describe('cordis_mount', () => { }) const result = await call(ctx, 'meta_tool', {}) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected dynamic tool success') + expect(result.value).toBe('ok') expect(text(result)).toBe('ok') expect(result.meta).toEqual({ kind: 'demo' }) }) it.each([ - ['a bare string', 'return \'ok\'', '"ok"'], - ['an object whose content is a string', 'return { content: \'ok\' }', '{"content":"ok"}'], - ['an array of non-objects', 'return [\'ok\']', '["ok"]'], - ['blocks missing the type tag', 'return [{ text: \'hi\' }]', '[{"text":"hi"}]'], - ['object-form blocks missing the type tag', 'return { content: [{ text: \'hi\' }] }', '{"content":[{"text":"hi"}]}'], - ['undefined — a forgotten return', 'return undefined', 'undefined'], - ])('rejects an execute return of %s as that one call\'s teaching error', async (_label, returnStatement, preview) => { - // The registry spreads result.content, so { content: 'ok' } would become ['o','k']; reject - // it as this call's error before it corrupts the next request. + ['a bare string', 'return \'ok\'', 'returned invalid output: "value" must be an array'], + ['an object whose content is a string', 'return { content: \'ok\' }', 'returned invalid output: "value" must be an array'], + ['an array of non-objects', 'return [\'ok\']', 'output.render returned ["ok"]'], + ['blocks missing the type tag', 'return [{ text: \'hi\' }]', 'output.render returned [{"text":"hi"}]'], + ['object-form blocks missing the type tag', 'return { content: [{ text: \'hi\' }] }', 'returned invalid output: "value" must be an array'], + ['undefined — a forgotten return', 'return undefined', 'execute result must be lossless JSON data'], + ])('rejects an execute return of %s against its declared output', async (_label, returnStatement, diagnostic) => { const ctx = await setup() await call(ctx, 'cordis_mount', { code: ` @@ -102,6 +146,7 @@ describe('cordis_mount', () => { name: 'bad_return_tool', description: 'returns a wrong shape', parameters: {}, + ${CONTENT_OUTPUT_CODE} async execute() { ${returnStatement} }, })) }, @@ -112,12 +157,10 @@ describe('cordis_mount', () => { expect(result.isError).toBe(true) expect(result.content).toHaveLength(1) expect(result.content[0]!.type).toBe('text') - expect(text(result)).toContain(`execute returned ${preview}`) - expect(text(result)).toContain('must return an ARRAY of content blocks') - expect(text(result)).toContain('✓ return { content: [{ type: \'text\', text: someString }], meta: anyJsonValue }') + expect(text(result)).toContain(diagnostic) }) - it('truncates a huge invalid execute return in the teaching error', async () => { + it('does not echo a huge schema-invalid canonical value in the diagnostic', async () => { const ctx = await setup() await call(ctx, 'cordis_mount', { code: ` @@ -129,6 +172,7 @@ describe('cordis_mount', () => { name: 'huge_return_tool', description: 'returns a huge wrong shape', parameters: {}, + ${CONTENT_OUTPUT_CODE} async execute() { return 'x'.repeat(500) }, })) }, @@ -137,7 +181,7 @@ describe('cordis_mount', () => { }) const result = await call(ctx, 'huge_return_tool', {}) expect(result.isError).toBe(true) - expect(text(result)).toContain('…') + expect(text(result)).toContain('returned invalid output') expect(text(result)).not.toContain('x'.repeat(200)) }) @@ -167,6 +211,7 @@ describe('cordis_mount', () => { }, required: ['text'], }, + ${CONTENT_OUTPUT_CODE} async execute(args) { return [{ type: 'text', text: args.text + ':' + (args.count ?? 0) }] }, })) }, @@ -215,6 +260,7 @@ describe('cordis_mount', () => { cfg: { type: 'object', properties: { label: { type: 'string' } }, required: ['label'] }, }, }, + ${CONTENT_OUTPUT_CODE} async execute(args) { return [{ type: 'text', text: args.cfg.label }] }, })) }, @@ -254,6 +300,7 @@ describe('cordis_mount', () => { closed: { type: 'object', additionalProperties: false }, count: { type: 'number', enum: [1, 2], const: 1 }, }, + ${CONTENT_OUTPUT_CODE} async execute(args) { return [{ type: 'text', text: String(args.choice) }] }, })) }, @@ -299,6 +346,7 @@ describe('cordis_mount', () => { choice: { oneOf: [{ type: 'boolean' }, { type: 'null' }] }, }, }, + ${CONTENT_OUTPUT_CODE} async execute() { return [] }, })) }, @@ -356,6 +404,7 @@ describe('cordis_mount', () => { name: 'bad_schema_tool', description: 'bad', ${parameters}, + ${CONTENT_OUTPUT_CODE} async execute() { return [] }, })) }, @@ -381,6 +430,7 @@ describe('cordis_mount', () => { item: { type: 'object', additionalProperties: true, required: true, properties: { label: { type: 'string', required: true } } }, tags: { type: 'array', items: { type: 'string' } }, }, + ${CONTENT_OUTPUT_CODE} async execute(args) { return [{ type: 'text', text: args.item.label }] }, })) }, @@ -404,6 +454,7 @@ describe('cordis_mount', () => { name: 'raw_dynamic_tool', description: 'raw', parameters: { type: 'object', properties: {} }, + ${CONTENT_OUTPUT_CODE} async execute() { return [] }, }) }, @@ -457,6 +508,14 @@ describe('cordis_mount', () => { code: 'return { name: \'waiter\', inject: [\'no-such-service\'], apply(ctx) {} }', }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected pending cordis_mount success') + expect(result.value).toEqual({ + id: 'dyn-1', + pluginName: 'waiter', + state: 'pending', + provides: [], + waitingFor: ['no-such-service'], + }) expect(text(result)).toContain('state: pending') expect(text(result)).toContain('waiting for service(s): no-such-service') // Unmounting a pending mount works like any other. @@ -517,6 +576,7 @@ describe('cordis_mount', () => { name: 'cordis_mount', description: 'dup', parameters: {}, + ${CONTENT_OUTPUT_CODE} async execute() { return [] }, })) }, @@ -663,6 +723,7 @@ describe('cordis_mount', () => { name: 'probe_instanceof', description: 'report instanceof checks across realms', parameters: { items: { type: 'array', required: true, items: { type: 'string' } } }, + ${CONTENT_OUTPUT_CODE} async execute(args) { const checks = { hostArray: args.items instanceof Array, diff --git a/packages/cordis/tool-cordis/tests/sandbox-context.spec.ts b/packages/cordis/tool-cordis/tests/sandbox-context.spec.ts index c27d34d4c3..05a33848c0 100644 --- a/packages/cordis/tool-cordis/tests/sandbox-context.spec.ts +++ b/packages/cordis/tool-cordis/tests/sandbox-context.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { call, setup, text } from './helpers.ts' +import { call, CONTENT_OUTPUT_CODE, setup, text } from './helpers.ts' /** * The sandbox context façade is a whitelist, not a pass-through proxy. Mounted code reaches only @@ -51,6 +51,7 @@ describe('sandbox context façade — escape surface is closed', () => { name: 'smuggled', description: 'raw, unguarded', parameters: { type: 'object', properties: {} }, + ${CONTENT_OUTPUT_CODE} async execute() { return [] }, }) }, @@ -87,6 +88,7 @@ describe('sandbox context façade — escape surface is closed', () => { name: 'smuggled_via_service', description: 'raw, unguarded', parameters: { type: 'object', properties: {} }, + ${CONTENT_OUTPUT_CODE} async execute() { return [] }, }) }, @@ -116,6 +118,7 @@ describe('sandbox context façade — escape surface is closed', () => { name: 'do_fetch', description: 'awaits the host async service', parameters: {}, + ${CONTENT_OUTPUT_CODE} async execute() { const value = await ctx.hostAsync.grab() return [{ type: 'text', text: value }] @@ -203,6 +206,7 @@ describe('sandbox context façade — inject gate on services', () => { name: 'greet_undeclared', description: 'uses greeter without declaring it', parameters: { n: { type: 'string', required: true } }, + ${CONTENT_OUTPUT_CODE} async execute(args) { return [{ type: 'text', text: ctx.greeter.greet(args.n) }] }, })) }, @@ -235,6 +239,7 @@ describe('sandbox tools façade — get is a read-only schema view', () => { name: 'report_view', description: 'reports the shape of a tool view', parameters: {}, + ${CONTENT_OUTPUT_CODE} async execute() { const view = ctx.tools.get('cordis_mount') return [{ type: 'text', text: JSON.stringify({ @@ -270,6 +275,7 @@ describe('sandbox tools façade — get is a read-only schema view', () => { name: 'probe_unknown', description: 'reports whether an unknown tool resolves', parameters: {}, + ${CONTENT_OUTPUT_CODE} async execute() { return [{ type: 'text', text: String(ctx.tools.get('no_such_tool') === undefined) }] }, diff --git a/packages/cordis/tool-cordis/tests/unmount-hmr.spec.ts b/packages/cordis/tool-cordis/tests/unmount-hmr.spec.ts index 718a213968..92e5ee7a66 100644 --- a/packages/cordis/tool-cordis/tests/unmount-hmr.spec.ts +++ b/packages/cordis/tool-cordis/tests/unmount-hmr.spec.ts @@ -26,6 +26,8 @@ describe('cordis_unmount', () => { const result = await call(ctx, 'cordis_unmount', { id: 'dyn-1' }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected cordis_unmount success') + expect(result.value).toEqual({ id: 'dyn-1', pluginName: 'change-logger' }) expect(text(result)).toContain('unmounted dyn-1') // Immediately after the awaited unmount, the listener must be gone — no diff --git a/packages/core/agent-loop/src/tool-calls.ts b/packages/core/agent-loop/src/tool-calls.ts index 663dda1b53..61a6d37947 100644 --- a/packages/core/agent-loop/src/tool-calls.ts +++ b/packages/core/agent-loop/src/tool-calls.ts @@ -219,7 +219,10 @@ function appendSkippedToolCall(session: Session, turn: number, step: number, blo appendToolResult(session, turn, step, block, { content: [{ type: 'text', text: 'Error: tool call skipped because the step was aborted before execution' }], isError: true, - error: { name: 'AbortError', code: 'ABORTED' }, + error: { + message: 'tool call skipped because the step was aborted before execution', + info: { name: 'AbortError', code: 'ABORTED' }, + }, }, callSeq) } diff --git a/packages/core/agent-loop/tests/agent-initiator.spec.ts b/packages/core/agent-loop/tests/agent-initiator.spec.ts index 8e9b951fa1..5ede648726 100644 --- a/packages/core/agent-loop/tests/agent-initiator.spec.ts +++ b/packages/core/agent-loop/tests/agent-initiator.spec.ts @@ -6,7 +6,7 @@ import LlmService, { CallId, LlmAdapter } from '@deepseek-ai/dsh-llm' import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import { MockAdapter, textResponse, toolCallResponse } from './mock-adapter.ts' interface Harness { @@ -156,7 +156,7 @@ describe('AgentLoop initiator scope', () => { let parentWhileChildDriverActive: Agent | undefined let child: Agent | undefined - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'spawn-child', description: 'create one child agent', parameters: {}, @@ -168,7 +168,7 @@ describe('AgentLoop initiator scope', () => { setup: (agentCtx) => { parentDuringSetup = ctx.agents.requireInitiator() explicitChild = agentCtx.agent - agentCtx.tools.register(defineTool({ + agentCtx.tools.register(defineContentToolFixture({ name: 'observe-child', description: 'observe child execution identity', parameters: {}, @@ -216,7 +216,7 @@ describe('AgentLoop initiator scope', () => { let directAmbient: Agent | undefined let captured: Agent | undefined - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'agentless-probe', description: 'observe an agentless call', parameters: {}, @@ -226,7 +226,7 @@ describe('AgentLoop initiator scope', () => { return [{ type: 'text', text: 'ok' }] }, })) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'capability-request', description: 'call the test capability transport', parameters: { path: { type: 'string' } }, diff --git a/packages/core/agent-loop/tests/cancel.spec.ts b/packages/core/agent-loop/tests/cancel.spec.ts index f6df171365..301ebbf992 100644 --- a/packages/core/agent-loop/tests/cancel.spec.ts +++ b/packages/core/agent-loop/tests/cancel.spec.ts @@ -12,7 +12,7 @@ import { Context } from 'cordis' import LlmService, { type Message } from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId, TurnEndReason } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import { MockAdapter, textResponse, toolCallResponse } from './mock-adapter.ts' @@ -366,7 +366,7 @@ describe('Agent.cancel()', () => { ]) const ctx = await harness(adapter) let executions = 0 - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'danger', description: 'must not run after cancellation', parameters: {}, @@ -397,7 +397,7 @@ describe('Agent.cancel()', () => { expect(result?.type === 'tool/result' ? result.data : undefined).toMatchObject({ callId: 'c1', isError: true, - error: { name: 'AbortError', code: 'ABORTED' }, + error: { info: { name: 'AbortError', code: 'ABORTED' } }, }) send(agent, 'continue safely') diff --git a/packages/core/agent-loop/tests/contract-regressions.spec.ts b/packages/core/agent-loop/tests/contract-regressions.spec.ts index 7ed8c2075e..17f12de400 100644 --- a/packages/core/agent-loop/tests/contract-regressions.spec.ts +++ b/packages/core/agent-loop/tests/contract-regressions.spec.ts @@ -3,7 +3,7 @@ import { Context } from 'cordis' import LlmService, { CallId, ContentBlock, MessageSource, ProviderRequestId, StreamChunk } from '@deepseek-ai/dsh-llm' import SessionStore, { Session, SessionEvent, SessionId, TurnEndReason } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool, type PostToolDecision } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture, type PostToolDecision } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent, type ContinuationDecision } from '@deepseek-ai/dsh-agent' import AgentLoop, { DEFAULT_MAX_PARALLEL_TOOL_CALLS } from '@deepseek-ai/dsh-agent-loop' import { prepareReactLoopAgent } from '../src/agent.ts' @@ -50,7 +50,7 @@ describe('session log records what agent/step-result actually produced', () => { const adapter = new MockAdapter([original, textResponse('done')]) const ctx = await harness(adapter) const executed: string[] = [] - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'injected-tool', description: '', parameters: {}, @@ -219,7 +219,7 @@ describe('abort during tool execution ends the turn', () => { const ctx = await harness(adapter) const executed: string[] = [] const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'aborter', description: '', parameters: {}, @@ -241,7 +241,7 @@ describe('abort during tool execution ends the turn', () => { source: { kind: 'plugin', plugin: 'abort-test' }, }], })) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'second', description: '', parameters: {}, @@ -259,7 +259,7 @@ describe('abort during tool execution ends the turn', () => { case 'assistant/message': order.push('assistant/message'); break case 'tool/call': order.push(`tool/call:${event.data.callId}`); break case 'tool/result': { - const outcome = event.data.error?.code === 'ABORTED' ? 'synthetic-aborted' : 'real' + const outcome = event.data.error?.info?.code === 'ABORTED' ? 'synthetic-aborted' : 'real' order.push(`tool/result:${event.data.callId}:${outcome}`) break } @@ -308,7 +308,7 @@ describe('abort during tool execution ends the turn', () => { expect(results[1]!.data).toMatchObject({ callId: CallId('c2'), isError: true, - error: { name: 'AbortError', code: 'ABORTED' }, + error: { info: { name: 'AbortError', code: 'ABORTED' } }, }) }) @@ -316,7 +316,7 @@ describe('abort during tool execution ends the turn', () => { const adapter = new MockAdapter([toolCallResponse('c1', 'aborter', {})]) const ctx = await harness(adapter) const agent = ctx.agentLoop.create(SessionId('a-abort-injection'), { provider: 'mock', model: 'mock' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'aborter', description: '', parameters: {}, @@ -362,7 +362,7 @@ describe('abort during tool execution ends the turn', () => { ] satisfies StreamChunk[]]) const ctx = await harness(adapter) const agent = ctx.agentLoop.create(SessionId('a-later-abort-context'), { provider: 'mock', model: 'mock' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'first', description: '', parameters: {}, @@ -370,7 +370,7 @@ describe('abort during tool execution ends the turn', () => { return [{ type: 'text', text: 'first done' }] }, })) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'aborter', description: '', parameters: {}, @@ -411,7 +411,7 @@ describe('abort during tool execution ends the turn', () => { const fiber = await ctx.plugin(Object.assign((inner: Context) => { agent = inner.agentLoop.create(SessionId('a-dispose-injection'), { provider: 'mock', model: 'mock' }) }, { inject: ['agentLoop'] })) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'waiter', description: '', parameters: {}, @@ -463,7 +463,7 @@ describe('abort during tool execution ends the turn', () => { ]) const ctx = await harness(adapter) const agent = ctx.agentLoop.create(SessionId('a-historical-tool-pair'), { provider: 'mock', model: 'mock' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'aborter', description: '', parameters: {}, @@ -472,7 +472,7 @@ describe('abort during tool execution ends the turn', () => { return [{ type: 'text', text: 'done' }] }, })) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'second', description: '', parameters: {}, @@ -771,7 +771,7 @@ describe('adapter registration, routing, and accepted-input ownership', () => { const adapter = new MockAdapter([toolCallResponse('c1', 'noop', {}), textResponse('done')]) const ctx = await harness(adapter) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'noop', description: '', parameters: {}, @@ -837,7 +837,7 @@ describe('adapter registration, routing, and accepted-input ownership', () => { const agent = ctx.agentLoop.create(SessionId('owned-steer'), { provider: 'mock', model: 'mock' }) const entered = Promise.withResolvers<undefined>() const release = Promise.withResolvers<undefined>() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'gate', description: '', parameters: {}, @@ -1423,7 +1423,7 @@ describe('tool result call identity', () => { textResponse('done'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo', parameters: { x: { type: 'number' } }, diff --git a/packages/core/agent-loop/tests/coverage-edges.spec.ts b/packages/core/agent-loop/tests/coverage-edges.spec.ts index ac7f301525..65c2258d0b 100644 --- a/packages/core/agent-loop/tests/coverage-edges.spec.ts +++ b/packages/core/agent-loop/tests/coverage-edges.spec.ts @@ -4,7 +4,7 @@ import LlmService, { CallId, LlmError, StreamChunk } from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId, TurnEndReason } from '@deepseek-ai/dsh-session' import type { SessionEvent } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' @@ -77,7 +77,7 @@ describe('tool JSON parse', () => { textResponse('done'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo tool', parameters: { input: { type: 'string' } }, @@ -110,7 +110,7 @@ describe('tool JSON parse', () => { textResponse('done'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'noarg', description: 'no-arg tool', parameters: {}, @@ -259,7 +259,7 @@ describe('structured tool error propagation (the runtime-validation Agent Note, ]) const ctx = await harness(adapter) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'boom', description: 'always fails', parameters: {}, @@ -274,6 +274,6 @@ describe('structured tool error propagation (the runtime-validation Agent Note, const toolResult = agent.session.events.find(e => e.type === 'tool/result') expect(toolResult?.type === 'tool/result' && toolResult.data.isError).toBe(true) expect(toolResult?.type === 'tool/result' && toolResult.data.error) - .toEqual({ name: 'HarnessError', code: 'BOOM' }) + .toEqual({ message: 'exploded', info: { name: 'HarnessError', code: 'BOOM' } }) }) }) diff --git a/packages/core/agent-loop/tests/interception.spec.ts b/packages/core/agent-loop/tests/interception.spec.ts index 83b156b0ef..3d4a5e67c5 100644 --- a/packages/core/agent-loop/tests/interception.spec.ts +++ b/packages/core/agent-loop/tests/interception.spec.ts @@ -3,7 +3,7 @@ import { Context } from 'cordis' import LlmService, { CallId, type Message } from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId, type SessionEvent, type TurnEndReason } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool, type PostToolDecision, type PreToolDecision } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture, type PostToolDecision, type PreToolDecision } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent, type ContinuationDecision, type PromptDecision, type SessionStartSource } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' @@ -347,7 +347,7 @@ describe('agent/session-prefix', () => { textResponse('again'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo', parameters: { text: { type: 'string' } }, async execute(args) { return [{ type: 'text', text: String(args.text) }] }, })) @@ -469,7 +469,7 @@ describe('agent/session-prefix', () => { textResponse('done'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo', parameters: { text: { type: 'string' } }, async execute(args) { return [{ type: 'text', text: String(args.text) }] }, })) @@ -522,7 +522,7 @@ describe('agent/turn-continuation (ContinuationDecision)', () => { it('a stop decision ends the turn even when the step had tool calls', async () => { const adapter = new MockAdapter([toolCallResponse('c1', 'echo', { text: 'hi' })]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo', parameters: { text: { type: 'string' } }, async execute(args) { return [{ type: 'text', text: String(args.text) }] }, })) @@ -552,7 +552,7 @@ describe('tool additionalContexts buffering across a step', () => { ] const adapter = new MockAdapter([twoCalls, textResponse('done')]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo', parameters: { text: { type: 'string' } }, async execute(args) { return [{ type: 'text', text: String(args.text) }] }, })) @@ -594,7 +594,7 @@ describe('tool additionalContexts buffering across a step', () => { it('appends multiple contexts deferred by one composite tool after its outer result', async () => { const adapter = new MockAdapter([toolCallResponse('c1', 'composite', {}), textResponse('done')]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'composite', description: 'composite', parameters: {}, async execute(_args, exec) { exec.deferContext({ content: [{ type: 'text', text: 'nested-a' }], source: { kind: 'plugin', plugin: 'a' }, meta: { order: 1 } }) @@ -625,7 +625,7 @@ describe('tools/pre-execute gate (native-plugin permission pattern, end-to-end t const adapter = new MockAdapter([toolCallResponse('c1', 'danger', {}), textResponse('ok')]) const ctx = await harness(adapter) let ran = false - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'danger', description: 'danger', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'should not run' }] }, })) @@ -687,7 +687,7 @@ describe('worked example: a native hook plugin is just a cordis plugin on the se const adapter = new MockAdapter([toolCallResponse('c1', 'echo', { text: 'hi' }), textResponse('done')]) const ctx = await harness(adapter) await ctx.plugin(NativeGuard) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo', parameters: { text: { type: 'string' } }, async execute(args) { return [{ type: 'text', text: String(args.text) }] }, })) diff --git a/packages/core/agent-loop/tests/loop.spec.ts b/packages/core/agent-loop/tests/loop.spec.ts index dd686edfcb..aa3a35bc36 100644 --- a/packages/core/agent-loop/tests/loop.spec.ts +++ b/packages/core/agent-loop/tests/loop.spec.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from 'vitest' import { Context } from 'cordis' import LlmService, { CallId, StreamChunk } from '@deepseek-ai/dsh-llm' -import SessionStore, { SessionId, TurnEndReason } from '@deepseek-ai/dsh-session' +import SessionStore, { SessionId, TurnEndReason, type JsonValue } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture, defineTool } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' @@ -89,7 +89,7 @@ describe('agent loop', () => { textResponse('done'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo back', parameters: { text: { type: 'string' } }, @@ -118,22 +118,27 @@ describe('agent loop', () => { const types = agent.session.events.map(e => e.type) expect(types).toContain('tool/call') expect(types).toContain('tool/result') + const durableResult = agent.session.events.find(event => event.type === 'tool/result') + expect(durableResult?.type === 'tool/result' && 'value' in durableResult.data).toBe(false) }) - it('threads a tool-attached meta (execute object return) onto the tool/result event', async () => { + it('persists presentation metadata projected from the canonical value', async () => { const adapter = new MockAdapter([ toolCallResponse('c1', 'writer', { path: 'a.txt' }, 'writing'), textResponse('done'), ]) const ctx = await harness(adapter) - // A tool that returns the { content, meta } object form: the loop must - // persist `meta` on the tool/result event so a UI reproduces the card on replay. ctx.tools.register(defineTool({ name: 'writer', description: 'writes a file', parameters: { path: { type: 'string' } }, + output: { + schema: { type: 'string' }, + render: () => [{ type: 'text', text: 'ok' }], + presentationMeta: (_args, value) => ({ diffs: [{ path: value, oldText: null, newText: 'x' }] }), + }, async execute() { - return { content: [{ type: 'text', text: 'ok' }], meta: { diffs: [{ path: 'a.txt', oldText: null, newText: 'x' }] } } + return 'a.txt' }, })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) @@ -152,7 +157,7 @@ describe('agent loop', () => { // projecting this agent's configured model, so the model knows its own name. const ctx = await harness(adapter, 'You are a test agent on {{model}}.') ctx.systemPrompt.section({ name: 'tool:noop', order: 100, text: 'Use the noop tool wisely.' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'noop', description: 'does nothing', parameters: {}, @@ -248,7 +253,7 @@ describe('agent loop', () => { ['BigInt', { n: 1n }], ['Map', new Map([['key', 'value']])], ['class instance', new (class ResultMeta { x = 1 })()], - ])('normalizes non-JSON tool meta (%s) before the durable result commit', async (_kind, meta) => { + ])('normalizes non-JSON presentation metadata (%s) before the durable result commit', async (_kind, meta) => { const adapter = new MockAdapter([ toolCallResponse('bad-meta-call', 'bad-meta', {}, 'calling'), textResponse('recovered'), @@ -258,7 +263,12 @@ describe('agent loop', () => { name: 'bad-meta', description: 'returns invalid durable metadata', parameters: {}, - execute: () => Promise.resolve({ content: [{ type: 'text' as const, text: 'apparent success' }], meta }), + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + presentationMeta: () => meta as unknown as JsonValue, + }, + execute: () => Promise.resolve('apparent success'), })) const agent = ctx.agentLoop.create(SessionId('bad-meta-agent'), { provider: 'mock', model: 'mock' }) @@ -326,7 +336,7 @@ describe('agent loop', () => { const ctx = await harness(adapter) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'slow', description: '', parameters: {}, @@ -432,7 +442,7 @@ describe('agent loop', () => { const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) let visibleDuringTool = false const meta = { kind: 'deferred-test', version: 1 } - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'noticer', description: 'injects a notice', parameters: {}, @@ -494,7 +504,7 @@ describe('agent loop', () => { ]) const ctx = await harness(adapter) const agent = ctx.agentLoop.create(SessionId('invalid-context'), { provider: 'mock', model: 'mock' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'invalid-injector', description: 'attempts an invalid context injection', parameters: {}, @@ -541,7 +551,7 @@ describe('agent loop', () => { it('agent/turn-continuation can veto continuation despite tool calls (budget-guard pattern)', async () => { const adapter = new MockAdapter([toolCallResponse('c1', 'echo', { text: 'x' })]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: '', parameters: { text: { type: 'string' } }, @@ -589,7 +599,7 @@ describe('agent loop', () => { textResponse('done'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo', parameters: {}, async execute() { return [{ type: 'text', text: 'echoed' }] }, })) @@ -781,7 +791,7 @@ describe('agent loop', () => { ]]) const ctx = await harness(adapter) let executions = 0 - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: '', parameters: { text: { type: 'string' } }, @@ -821,7 +831,7 @@ describe('agent loop', () => { { type: 'finish', reason: { kind: 'max-tokens' } }, ]]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: '', parameters: { text: { type: 'string' } }, @@ -908,7 +918,7 @@ describe('agent loop', () => { textResponse('continued after tool call'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: '', parameters: { text: { type: 'string' } }, @@ -1240,7 +1250,7 @@ describe('agent loop', () => { textResponse('done'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: '', parameters: { text: { type: 'string' } }, diff --git a/packages/core/agent-loop/tests/request-cache.e2e.ts b/packages/core/agent-loop/tests/request-cache.e2e.ts index 36d88feaa9..f1e1a1a367 100644 --- a/packages/core/agent-loop/tests/request-cache.e2e.ts +++ b/packages/core/agent-loop/tests/request-cache.e2e.ts @@ -3,7 +3,7 @@ import { Context } from 'cordis' import LlmService from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' @@ -45,7 +45,7 @@ async function loopHarness(): Promise<Context> { await created.plugin(AgentRegistry) await created.plugin(AgentLoop, { agents: [] }) await created.plugin(LlmDeepSeek) - created.tools.register(defineTool({ + created.tools.register(defineContentToolFixture({ name: 'lookup', description: 'Look up the stored value for a key.', parameters: { key: { type: 'string', description: 'The key to look up.' } }, diff --git a/packages/core/agent-loop/tests/request-reconstruction.spec.ts b/packages/core/agent-loop/tests/request-reconstruction.spec.ts index 46cfe3eb56..755953c6f7 100644 --- a/packages/core/agent-loop/tests/request-reconstruction.spec.ts +++ b/packages/core/agent-loop/tests/request-reconstruction.spec.ts @@ -11,7 +11,7 @@ import LlmService from '@deepseek-ai/dsh-llm' import type { GenerateOptions } from '@deepseek-ai/dsh-llm' import SessionStore, { Session, SessionId, foldRequestHeader } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' @@ -53,7 +53,7 @@ function expectPrefixExtension(previous: GenerateOptions, current: GenerateOptio } function registerEcho(ctx: Context) { - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo back', parameters: { text: { type: 'string' } }, diff --git a/packages/core/agent-loop/tests/request-recovery.spec.ts b/packages/core/agent-loop/tests/request-recovery.spec.ts index cf87d376ef..2bdd7e8d33 100644 --- a/packages/core/agent-loop/tests/request-recovery.spec.ts +++ b/packages/core/agent-loop/tests/request-recovery.spec.ts @@ -11,7 +11,7 @@ import LlmService, { import type { GenerateOptions, LlmFailure, StreamChunk } from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import type { PostToolDecision } from '@deepseek-ai/dsh-tools' import AgentRegistry from '@deepseek-ai/dsh-agent' import type { Agent } from '@deepseek-ai/dsh-agent' @@ -133,7 +133,7 @@ describe('agent post-step and request-error lifecycle', () => { ] const adapter = new FailureScriptAdapter([twoCalls, textResponse('done')]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'work', description: 'do work', parameters: {}, @@ -222,7 +222,7 @@ describe('agent post-step and request-error lifecycle', () => { textResponse('must not continue'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'work', description: 'do work', parameters: {}, @@ -535,7 +535,7 @@ describe('agent post-step and request-error lifecycle', () => { contextError('later overflow'), ]) const resetCtx = await harness(reset) - resetCtx.tools.register(defineTool({ + resetCtx.tools.register(defineContentToolFixture({ name: 'work', description: 'continue', parameters: {}, diff --git a/packages/core/agent-loop/tests/scope-lifecycle.spec.ts b/packages/core/agent-loop/tests/scope-lifecycle.spec.ts index 73ee48f7a6..469a815d8b 100644 --- a/packages/core/agent-loop/tests/scope-lifecycle.spec.ts +++ b/packages/core/agent-loop/tests/scope-lifecycle.spec.ts @@ -3,7 +3,7 @@ import { Context, symbols, type EffectMeta, type Fiber } from 'cordis' import LlmService from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import AgentRegistry, { agentEvents, assembleContextFor } from '@deepseek-ai/dsh-agent' import type { Agent } from '@deepseek-ai/dsh-agent' @@ -172,10 +172,10 @@ describe('agent scope lifecycle', () => { const handle = await ctx.agents.create({ sessionId: SessionId('s1'), agentOptions: { provider: 'mock', model: 'mock' } }) const { agent } = handle agent.ctx.systemPrompt.section({ name: 'deployment:persona', order: 0, text: 'You run tests.' }) - agent.ctx.tools.register({ + agent.ctx.tools.register(defineContentToolFixture({ name: 'mine', description: 'scoped', parameters: {}, execute: () => Promise.resolve(text('ran')), - }) + })) const scopedAssembly = await ctx.systemPrompt.assemble(assembleContextFor(agent)) expect(scopedAssembly.sections.find(s => s.name === 'deployment:persona')?.text).toBe('You run tests.') @@ -587,12 +587,12 @@ describe('agent scope lifecycle', () => { sessionId: SessionId('dependency-origin-s'), agentOptions: { provider: 'mock', model: 'mock' }, setup: (agentCtx) => { - agentCtx.tools.register({ + agentCtx.tools.register(defineContentToolFixture({ name: 'dependency-origin-tool', description: 'proves AgentLoop dependency origin', parameters: {}, execute: () => Promise.resolve(text('ok')), - }) + })) agentCtx.systemPrompt.section({ name: 'dependency-origin-section', order: 1, diff --git a/packages/core/agent-loop/tests/tool-calls.spec.ts b/packages/core/agent-loop/tests/tool-calls.spec.ts index a77e1d678e..e13caa13c5 100644 --- a/packages/core/agent-loop/tests/tool-calls.spec.ts +++ b/packages/core/agent-loop/tests/tool-calls.spec.ts @@ -9,7 +9,7 @@ import { CallId, StreamChunk } from '@deepseek-ai/dsh-llm' import SessionStore, { SessionEvent, SessionId } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import LlmService from '@deepseek-ai/dsh-llm' -import ToolRegistry, { defineTool, type PostToolDecision, type PreToolDecision } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture, type PostToolDecision, type PreToolDecision } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import { MockAdapter, textResponse } from './mock-adapter.ts' @@ -61,7 +61,7 @@ function multiCall(calls: { id: string; name: string; args: object }[]): StreamC function gatedTool(name: string, parallel: boolean) { const gates = new Map<string, () => void>() const started: string[] = [] - const tool = defineTool({ + const tool = defineContentToolFixture({ name, description: `gated ${name}`, parameters: { id: { type: 'string', required: true } }, @@ -123,12 +123,12 @@ describe('tool-call scheduler: grouping and barriers', () => { textResponse('done'), ]) const ctx = await harness(adapter) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'r', description: 'read', parameters: { id: { type: 'string', required: true } }, isConcurrencySafe: () => true, async execute(args) { order.push(`r-start-${args.id}`); order.push(`r-end-${args.id}`); return [{ type: 'text', text: 'r' }] }, })) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'w', description: 'write', parameters: { id: { type: 'string', required: true } }, async execute(args) { order.push(`w-${args.id}`); return [{ type: 'text', text: 'w' }] }, })) @@ -150,14 +150,14 @@ describe('tool-call scheduler: grouping and barriers', () => { ]) const ctx = await harness(adapter) const replacement = gatedExclusiveTool('x') - const disposeSafe = ctx.tools.register(defineTool({ + const disposeSafe = ctx.tools.register(defineContentToolFixture({ name: 'x', description: 'initially safe', parameters: { id: { type: 'string', required: true } }, isConcurrencySafe: () => true, async execute(args) { return [{ type: 'text', text: `old-${args.id}` }] }, })) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'replace', description: 'replace x', parameters: { id: { type: 'string', required: true } }, @@ -476,8 +476,22 @@ describe('tool-call scheduler: abort handling', () => { isError: e.data.isError, error: e.data.error, }))).toEqual([ - { callId: CallId('c1'), isError: true, error: { name: 'AbortError', code: 'ABORTED' } }, - { callId: CallId('c2'), isError: true, error: { name: 'AbortError', code: 'ABORTED' } }, + { + callId: CallId('c1'), + isError: true, + error: { + message: 'tool call skipped because the step was aborted before execution', + info: { name: 'AbortError', code: 'ABORTED' }, + }, + }, + { + callId: CallId('c2'), + isError: true, + error: { + message: 'tool call skipped because the step was aborted before execution', + info: { name: 'AbortError', code: 'ABORTED' }, + }, + }, ]) }) @@ -509,7 +523,7 @@ describe('tool-call scheduler: abort handling', () => { expect(events(agent).filter(e => e.type === 'tool/result').map(e => e.data.callId)) .toEqual([CallId('c1'), CallId('c2')]) expect(events(agent).filter(e => e.type === 'tool/result').at(-1)?.data) - .toMatchObject({ callId: CallId('c2'), isError: true, error: { name: 'AbortError', code: 'ABORTED' } }) + .toMatchObject({ callId: CallId('c2'), isError: true, error: { info: { name: 'AbortError', code: 'ABORTED' } } }) }) it('stops replenishing after abort, commits started results, and drains accepted additional contexts', async () => { @@ -538,10 +552,14 @@ describe('tool-call scheduler: abort handling', () => { .toEqual([CallId('c1'), CallId('c2'), CallId('c3'), CallId('c4')]) expect(events(agent).filter(e => e.type === 'tool/result').map(e => e.data.callId)) .toEqual([CallId('c1'), CallId('c2'), CallId('c3'), CallId('c4')]) - expect(events(agent).filter(e => e.type === 'tool/result').slice(-2).map(e => e.data)) + expect(events(agent).filter(e => e.type === 'tool/result').slice(-2).map(e => ({ + callId: e.data.callId, + isError: e.data.isError, + errorInfo: e.data.error?.info, + }))) .toEqual([ - expect.objectContaining({ callId: CallId('c3'), isError: true, error: { name: 'AbortError', code: 'ABORTED' } }), - expect.objectContaining({ callId: CallId('c4'), isError: true, error: { name: 'AbortError', code: 'ABORTED' } }), + { callId: CallId('c3'), isError: true, errorInfo: { name: 'AbortError', code: 'ABORTED' } }, + { callId: CallId('c4'), isError: true, errorInfo: { name: 'AbortError', code: 'ABORTED' } }, ]) const settled = events(agent).filter(e => e.type === 'tool/result' || e.type === 'context/message') expect(settled.map(e => e.type)) @@ -564,7 +582,7 @@ describe('tool-call scheduler: abort handling', () => { const gated = gatedParallelTool('p') const exclusive: string[] = [] ctx.tools.register(gated.tool) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'x', description: 'exclusive', parameters: { id: { type: 'string', required: true } }, @@ -583,6 +601,6 @@ describe('tool-call scheduler: abort handling', () => { expect(events(agent).filter(e => e.type === 'tool/call').map(e => e.data.callId)) .toEqual([CallId('c1'), CallId('c2'), CallId('c3')]) expect(events(agent).filter(e => e.type === 'tool/result').at(-1)?.data) - .toMatchObject({ callId: CallId('c3'), isError: true, error: { name: 'AbortError', code: 'ABORTED' } }) + .toMatchObject({ callId: CallId('c3'), isError: true, error: { info: { name: 'AbortError', code: 'ABORTED' } } }) }) }) diff --git a/packages/core/agent-loop/tests/tool-order.spec.ts b/packages/core/agent-loop/tests/tool-order.spec.ts index bf78208a42..76b14e92c2 100644 --- a/packages/core/agent-loop/tests/tool-order.spec.ts +++ b/packages/core/agent-loop/tests/tool-order.spec.ts @@ -12,7 +12,7 @@ import LlmService from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId, foldRequestHeader } from '@deepseek-ai/dsh-session' import SystemPrompt, { TOOL_ORDER_REST } from '@deepseek-ai/dsh-system-prompt' import type { Config as SystemPromptConfig } from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' @@ -42,7 +42,7 @@ function waitForIdle(ctx: Context, agent: Agent): Promise<void> { } function registerNamed(ctx: Context, name: string) { - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name, description: `the ${name} tool`, parameters: {}, diff --git a/packages/core/agent-loop/tests/turn-stop.spec.ts b/packages/core/agent-loop/tests/turn-stop.spec.ts index 355e1e8e3d..f7b59e3585 100644 --- a/packages/core/agent-loop/tests/turn-stop.spec.ts +++ b/packages/core/agent-loop/tests/turn-stop.spec.ts @@ -3,7 +3,7 @@ import { Context } from 'cordis' import LlmService from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId, type TurnEndReason } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent, type ContinuationStop } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' @@ -29,7 +29,7 @@ function send(agent: Agent, text = 'go'): Promise<void> { } function registerEcho(ctx: Context): void { - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'echo', parameters: { text: { type: 'string' } }, diff --git a/packages/core/session/README.md b/packages/core/session/README.md index 28210e8f6c..aaf1d429ee 100644 --- a/packages/core/session/README.md +++ b/packages/core/session/README.md @@ -58,6 +58,8 @@ Durable values need one accepted representation, not a check followed by a secon `context/message` renders its `content` verbatim as a user-role message, and may attach JSON `meta` for replayable plugin state; metadata remains durable but is excluded from `deriveMessages()`. +`tool/result` persists the model-facing content, canonical failure detail, and optional presentation metadata. A tool's successful canonical `value` is deliberately execution-local and never enters the session event, so replay reconstructs the Native/model presentation but cannot recover intermediate programmatic values. This does not change `SESSION_FORMAT_VERSION`: the persisted projection remains authoritative. + ### Session event vocabulary (`types.ts`) The append-only log's event types, enumerated member by member — payloads, surface badges, provenance — in the generated [persistence log event catalog](../../../docs/persistence-catalog.md). Token accounting reads per-step `assistant/chunk { type: 'usage' }` records and treats `assistant/message.usage` as the committed-step fallback when no usage chunk exists; failed model-request attempts have no assistant message. Provider/model/replay provenance rides on `assistant/message`; an operational error's step is on `turn/end.reason` for `kind: 'error'`, with structured provider facts for a final model-request failure. diff --git a/packages/core/session/src/repair.ts b/packages/core/session/src/repair.ts index efbb3d2004..fa3b8bbb50 100644 --- a/packages/core/session/src/repair.ts +++ b/packages/core/session/src/repair.ts @@ -92,7 +92,10 @@ export function interruptedTurnClosers(events: readonly SessionEvent[]): Session callId, content: [{ type: 'text', text: 'Tool call interrupted by a crash; no result was recorded.' }], isError: true, - error: { name: 'InterruptedError', code: 'interrupted' }, + error: { + message: 'Tool call interrupted by a crash; no result was recorded.', + info: { name: 'InterruptedError', code: 'interrupted' }, + }, }, surfaceOp: 'append', ...callSeq !== undefined ? { sourceEventSeqs: [callSeq] } : {}, diff --git a/packages/core/session/src/types.ts b/packages/core/session/src/types.ts index ea0ad55a51..cc7ea81ba1 100644 --- a/packages/core/session/src/types.ts +++ b/packages/core/session/src/types.ts @@ -243,15 +243,24 @@ export interface SessionEventMap { */ 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string } /** - * A completed tool call's model-facing result, plus an optional tool-private - * `meta` presentation payload. `meta` is opaque to the core (`unknown` — the - * producing tool owns its shape and reads it back in `presentResult`) but MUST - * be JSON-serializable: `Session.append` runtime-validates all event data with - * `isJsonValue`, so a non-serializable `meta` is rejected at the source, and the - * durable log reproduces the identical card on replay. Absent unless the tool - * attaches one (e.g. `dsh-tool-fs` carries its result-time contextual diff here). + * A completed tool call's model-facing result, canonical failure detail, and + * optional tool-private `meta` presentation payload. `meta` is opaque to the + * core (the producing tool owns its shape and reads it back in `presentResult`) + * but MUST be JSON-serializable: `Session.append` runtime-validates all event + * data with `isJsonValue`, so a non-serializable `meta` is rejected at the + * source, and the durable log reproduces the identical card on replay. Absent + * unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time + * contextual diff here). */ - 'tool/result': { turn: number; step: number; callId: CallId; content: ContentBlock[]; isError: boolean; error?: { name: string; code: string }; meta?: unknown } + 'tool/result': { + turn: number + step: number + callId: CallId + content: ContentBlock[] + isError: boolean + error?: { message: string; info?: { name: string; code: string } } + meta?: JsonValue + } /** Steering content injected between steps of a running turn. */ 'steering/message': { turn: number; content: ContentBlock[]; source: MessageSource } /** Whole-list snapshot; latest write wins on replay. Log-only UI state; never derived history. */ diff --git a/packages/core/session/tests/repair.spec.ts b/packages/core/session/tests/repair.spec.ts index 765502b8ce..826d410dc8 100644 --- a/packages/core/session/tests/repair.spec.ts +++ b/packages/core/session/tests/repair.spec.ts @@ -64,7 +64,7 @@ describe('interruptedTurnClosers', () => { expect(closers.map(e => e.seq)).toEqual([3, 4, 5]) const result = closers[0]! expect(result.type === 'tool/result' && result.data).toMatchObject({ - turn: 2, step: 1, callId: CallId('call-1'), isError: true, error: { code: 'interrupted' }, + turn: 2, step: 1, callId: CallId('call-1'), isError: true, error: { info: { code: 'interrupted' } }, }) }) diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 5ec2d4e7e4..1b42f2c28f 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -15,7 +15,7 @@ tools: ### Public API -- `ctx.tools.register(definition: ToolDefinition): () => void` Register a trusted typed same-process definition. The layer is the calling context's scope: a plain plugin context registers globally; an agent's `agent.ctx` registers for that agent alone, shadowing a same-named global tool there. Duplicate names within one layer throw; non-native modes also reject the reserved `run_code` transport name. `timeoutMs`, when present, must be positive and finite. Disposed with the calling fiber. +- `ctx.tools.register(definition: ToolDefinition): () => void` Register a trusted typed same-process definition with a mandatory canonical `output` declaration. The layer is the calling context's scope: a plain plugin context registers globally; an agent's `agent.ctx` registers for that agent alone, shadowing a same-named global tool there. Duplicate names within one layer throw; non-native modes also reject the reserved `run_code` transport name. Missing/unsupported output declarations and a non-positive/non-finite `timeoutMs` fail at registration. Disposed with the calling fiber. - `ctx.tools.restrict(filter)` applies an agent-scoped allow/deny mask to global tools and throws from a plain context. The filter is snapshotted at registration; multiple masks intersect and scope-local tools merge afterwards. Deny masks admit later unnamed globals, while allow masks exclude later names. Unknown, local, or reserved names and empty filters reject. This is live visibility composition, not an authority boundary; see the [scope security non-goal](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-explicit-non-goals). - `ctx.tools.get(name: string, scope?: ScopeKey): ToolDefinition | undefined` Resolution as one scope sees it (shadowing applied; a restricted-away global reads as absent) — presenters pass the calling agent so the card matches what executed. - `ctx.tools.schemas(scope?: ScopeKey): ToolSchema[]` Schemas of everything the scope can see (without the `execute` functions). The shipped tools' schemas are catalogued in [docs/tool-catalog.md](../../../docs/tool-catalog.md), generated by booting each tool plugin and harvesting this method (see [the tool-schema-catalog Agent Note](../../../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md)). @@ -33,14 +33,14 @@ The live registry pipeline has three transformable waterfalls followed by the ob ### Key types -- `ToolDefinition` — `ToolSchema` + `execute(args, exec)`, optional presentation callbacks, cooperative `timeoutMs`, and optional per-call `isConcurrencySafe(args)` classification. +- `ToolDefinition` — `ToolSchema` + mandatory `output { schema, render, presentationMeta? }` + `execute(args, exec)`, optional presentation callbacks, cooperative `timeoutMs`, and optional per-call `isConcurrencySafe(args)` classification. A body returns only the canonical JSON value declared by the output schema. - `ToolExecutionInput` — the caller-supplied call description: `{ callId, name, arguments, agent?, parent?, signal? }`; callers may pass an enclosing execution's opaque token as `parent` but never choose the new execution's own token. - `ToolExecutionToken` — a fresh branded `Symbol` assigned by the registry. It supports equality correlation only and never crosses a model, log, or worker boundary. - `ToolExecution` — the pipeline-owned call: immutable `{ token, callId, name, arguments, agent?, parent? }` identity plus optional operational `signal`, which an around wrapper may add, replace, remove, and restore. A nested call's `parent` is a `ToolExecutionToken`, not an execution object. - `ToolRunContext` — the execution passed to a tool body, extending `ToolExecution` with `deferContext(context)`. Composite tools use it to ferry context produced by nested dispatches to the outer result even when the tool later throws; it never injects immediately. -- `ToolExecutionResult` — losslessly JSON-serializable outcome: `{ content, isError, error?, additionalContexts?, meta? }`. Call identity stays on the immutable `ToolExecution` supplied alongside the result instead of being duplicated on the outcome. The registry materializes and freezes the complete post-policy value before final observation. On failure with a `HarnessError`, `error: { name, code }` carries the structured failure class alongside the model-facing text. `additionalContexts` preserves each deferred or post-execute `HookContext` with its own source and durable JSON metadata; the loop buffers the array and appends each entry as a `context/message` after all `tool/result`s in the step. +- `ToolExecutionResult` — discriminated execution-local outcome. Success is `{ isError:false, value:JsonValue, content, meta?, additionalContexts? }`; failure is `{ isError:true, error:{ message, info? }, content, meta?, additionalContexts? }` and has no value. Call identity stays on the immutable `ToolExecution`. The registry snapshots, validates, and freezes the canonical value before rendering, then materializes the durable presentation fields before final observation. `ToolFailure.info` carries an internal `{ name, code }` for a `HarnessError`; `additionalContexts` preserves every deferred or post-execute `HookContext` for the loop's post-result FIFO. - `PreToolDecision` — `{kind:'allow'}` | `{kind:'deny', reason}` | `{kind:'ask', reason?}`. Input rewrite is deliberately not offered; `ask` is serviced by [`ctx.approval`](../../ui/user-approval/README.md) when mounted and otherwise degrades to deny. -- `PostToolDecision` — `{kind:'accept', content?, additionalContexts?}` (keep the call successful, optionally replacing the model-facing content) | `{kind:'block', feedback, additionalContexts?}` (turn it into an `isError` whose content is the corrective feedback). Accept preserves tool-deferred contexts before decision contexts; block discards tool-deferred contexts and exposes only contexts explicitly supplied by the blocking decision. +- `PostToolDecision` — accept may replace `content` or `value`, never both, and may attach `additionalContexts`; block turns feedback into a valueless failure. Content replacement preserves the canonical value and metadata. Value replacement is revalidated and rerenders content/metadata. Accept preserves tool-deferred contexts before decision contexts; block discards tool-deferred contexts and exposes only contexts explicitly supplied by the blocking decision. - `ToolGuard` — `(execution) => string | undefined`; the returned string is a final monotonic denial reason evaluated after the reorderable pre-execute waterfall and before dispatch. - `ToolCallView` / `ToolResultView` — provider-neutral `card`-tagged render intents a tool returns from `presentCall` / `presentResult` to own how a UI renders ITS calls (see "Tool-owned UI presentation"). @@ -48,8 +48,8 @@ The live registry pipeline has three transformable waterfalls followed by the ob - Tool plugins call `ctx.tools.register()` — schemas flow into the assembly automatically. - `tools/pre-execute` is the reorderable allow/deny/ask gate; `ctx.tools.guard()` adds monotonic owner policy after it. -- `tools/execute` wraps normalized core dispatch for timeout, retry, or metrics. Wrappers may replace only the operational signal. -- `tools/post-execute` may replace content, block with feedback, or attach ordered contexts; `tools/result` observes the immutable final outcome. +- `tools/execute` wraps normalized canonical dispatch for timeout, retry, or metrics. Wrappers may replace only the operational signal; a wrapper-authored success is normalized through the resolved tool's output declaration. +- `tools/post-execute` may replace presentation content, replace the canonical value, block with feedback, or attach ordered contexts; `tools/result` observes the immutable final outcome. Content replacement is not a confidentiality boundary: block or replace the value when programmatic consumers must not receive it. - Exact signatures and ordering live in the generated [event catalog](../../../docs/cordis-catalog/events.md) and [pipeline](../../../docs/tool-execution-pipeline.md). - MCP servers: one plugin per server, discover tools, call `ctx.tools.register()` with the server's schemas. @@ -72,17 +72,20 @@ ctx.tools.register(defineTool({ offset: { type: 'number' }, limit: { type: 'number' }, }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args, exec) { // args is typed: { path: string; offset?: number; limit?: number } - const text = await readFile(args.path, 'utf8') - return [{ type: 'text', text }] + return readFile(args.path, 'utf8') }, })) ``` The unified schema DSL uses `ParameterSchemaSpec` for the implicit open parameter object and `ValueSchemaSpec` for any JSON-value root. It supports `string`, `number`, `integer`, `boolean`, `null`, `array`, `object`, author-only `json`, and exact-one `oneOf`; scalar `enum`/`const` values are type-correct. Every explicit DSL object declares `additionalProperties: true | false`, while the implicit parameter root and raw JSON Schema keep the standard open default. -A `defineTool` definition validates model arguments before execution and turns missing required values, wrong primitives, invalid enum members, and nested violations into `ToolArgsError` (`INVALID_ARGS`) for the normal error-result path. Extra keys are allowed, defaults are not applied, and object or array fields without `properties` or `items` receive only a type check. Raw-registered tools own their validation. +A `defineTool` definition validates model arguments before execution and turns missing required values, wrong primitives, invalid enum members, and nested violations into `ToolArgsError` (`INVALID_ARGS`) for the normal error-result path. It also infers the body return and pure output projectors from `output.schema`; the registry snapshots and validates the returned lossless JSON before presentation. Extra parameter keys are allowed, defaults are not applied, and object or array fields without `properties` or `items` receive only a type check. Raw-registered tools own input validation but still declare and receive registry-enforced output. See `defineTool`, `validateArgs`, `ToolArgsError`, `ValueSchemaSpec`, `ParameterSchemaSpec`, `InferValue`, `InferArgs`, `valueSchemaSpecToJsonSchema`, and `parameterSchemaSpecToJsonSchema` in the public API for details. @@ -101,7 +104,7 @@ Tools optionally own pure `presentCall()` and `presentResult()` render intents, - Call views are `{ card: 'generic', title, kind?, rawInput?, content?, locations? }`, `{ card: 'terminal', title, description?, cwd? }`, or `{ card: 'diff', title, diffs, locations? }`. - Result views are `{ card: 'generic', title?, content? }`, `{ card: 'terminal', title?, output?, exitCode?, signal? }`, or `{ card: 'diff', title?, diffs }`. -Returning `undefined` selects generic fallback. Presenters depend only on their arguments because UIs call them during live streaming and log replay. Result presentation may read JSON-serializable `result.meta`, which persists with the result; `defineTool` soft-validates older logged arguments and falls back instead of crashing replay. `dsh-tool-bash` and `dsh-tool-fs` are the reference implementations; the [render-intent Agent Note](../../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md) owns the rationale. +Returning `undefined` selects generic fallback. Presenters depend only on their arguments and the durable result because UIs call them during live streaming and log replay. `output.presentationMeta(args, value)` derives JSON metadata for direct surface calls; that metadata persists with `tool/result` and returns to `presentResult`, while the canonical value itself remains execution-local and is never replayed. Nested Code dispatches do not compute metadata. `defineTool` soft-validates older logged arguments and falls back instead of crashing replay. `dsh-tool-bash` and `dsh-tool-fs` are the reference implementations; the [canonical-output Agent Note](../../../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md) owns the value/presentation split and the [render-intent Agent Note](../../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md) owns card vocabulary. ### Code Mode diff --git a/packages/core/tools/src/code-mode.ts b/packages/core/tools/src/code-mode.ts index 0a65c9e434..21fcfcb8b5 100644 --- a/packages/core/tools/src/code-mode.ts +++ b/packages/core/tools/src/code-mode.ts @@ -10,7 +10,7 @@ import { inspect } from 'node:util' import { CallId, HarnessError } from '@deepseek-ai/dsh-llm' import type { ContentBlock } from '@deepseek-ai/dsh-llm' import type { CodeBindingFunction, CodeRunResult, CodeRuntime } from '@deepseek-ai/dsh-code-runtime' -import type {} from '@deepseek-ai/dsh-session' +import type { JsonValue } from '@deepseek-ai/dsh-session' import { defineTool } from './schema.ts' import type { ToolDefinition, ToolRegistry } from './index.ts' @@ -111,9 +111,8 @@ function jsonNormalizeArgs(value: unknown): { dispatched: unknown; logged: unkno return { dispatched: JSON.parse(text) as unknown, logged: JSON.parse(text) as unknown } } -/** Render the program's completion value for the model-facing result text (`''` when the program returned nothing). */ -function renderValue(value: unknown): string { - if (value === undefined) return '' +/** Render one present program completion value for the model-facing result text. */ +function renderValue(value: JsonValue): string { return typeof value === 'string' ? value : inspect(value, INSPECT_OPTIONS) } @@ -122,6 +121,9 @@ interface RunCodeMeta { logs: CodeRunResult['logs'] } +/** Canonical value returned by the outer Code Mode transport. */ +type RunCodeOutput = { logs: string[]; result?: JsonValue } + /** Soft-narrow a result `meta` back to {@link RunCodeMeta} (replay may carry older shapes; presentation must not throw). */ function asRunCodeMeta(meta: unknown): RunCodeMeta | undefined { if (typeof meta !== 'object' || meta === null) return undefined @@ -152,7 +154,23 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () => parameters: { code: { type: 'string', required: true, description: 'The program: the body of an async TypeScript function.' }, }, - async execute(args, exec) { + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + logs: { type: 'array', required: true, items: { type: 'string' } }, + result: { type: 'json' }, + }, + }, + render: (_args, value) => { + const rendered = value.result === undefined ? '' : renderValue(value.result) + const parts = [value.logs.join('\n'), rendered].filter(part => part.length > 0) + return [{ type: 'text', text: parts.length > 0 ? parts.join('\n') : '(run_code completed with no output)' }] + }, + presentationMeta: (_args, value) => ({ logs: value.logs }), + }, + async execute(args, exec): Promise<RunCodeOutput> { const runtime = requireRuntime() // The run-scoped abort: follows the outer signal in, and fires when the @@ -265,12 +283,12 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () => const logsText = result.logs.length > 0 ? `\nCaptured output:\n${result.logs.join('\n')}` : '' throw new CodeRunFailedError(`code run failed (${result.error.kind}): ${result.error.message}${logsText}`) } - const rendered = renderValue(result.value) - const parts = [result.logs.join('\n'), rendered].filter(part => part.length > 0) - const meta: RunCodeMeta = { logs: result.logs } + // The runtime seam is wider than JSON until PR 3 makes this boundary + // lossless. The registry immediately snapshots and rejects any value + // that does not satisfy the declared JSON output. return { - content: [{ type: 'text', text: parts.length > 0 ? parts.join('\n') : '(run_code completed with no output)' }], - meta, + logs: result.logs, + ...result.value !== undefined ? { result: result.value as JsonValue } : {}, } } finally { exec.signal?.removeEventListener('abort', onOuterAbort) diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 2c01639047..f6fe38d4da 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -12,12 +12,15 @@ import type { CallId, ContentBlock, ToolSchema } from '@deepseek-ai/dsh-llm' import { assertNever, deepFreeze, HarnessError } from '@deepseek-ai/dsh-llm' import type { Agent, HookContext } from '@deepseek-ai/dsh-agent' import { snapshotJsonValue } from '@deepseek-ai/dsh-session' +import type { JsonValue } from '@deepseek-ai/dsh-session' import type { ToolProviderResult } from '@deepseek-ai/dsh-system-prompt' import type { CodeRuntime } from '@deepseek-ai/dsh-code-runtime' // Type-only: makes `ctx.get('approval')` resolve to the ApprovalService // augmentation. The seam stays optional at runtime — see `serviceAsk`. import type {} from '@deepseek-ai/dsh-user-approval' import type { ToolCallView, ToolResultView } from './presentation.ts' +import { assertSupportedJsonSchema, validateJsonSchemaValue } from './json-schema.ts' +import type { JsonSchemaNode } from './json-schema.ts' import { createRunCodeTool, RUN_CODE_NAME, SDK_SECTION_ORDER } from './code-mode.ts' import { renderToolsSdk } from './ts-types.ts' @@ -61,6 +64,7 @@ export type { JsonValue } from '@deepseek-ai/dsh-session' export { CodeRunFailedError, RUN_CODE_NAME } from './code-mode.ts' export { jsonSchemaToTs, renderToolsSdk } from './ts-types.ts' +export { defineContentToolFixture, type ContentToolFixtureOptions } from './testing.ts' // The render-intent vocabulary a tool declares via `presentCall`/`presentResult` // lives in its own UI-facing module; re-export it so `@deepseek-ai/dsh-tools` @@ -132,12 +136,22 @@ declare module 'cordis' { } } -/** Tool output, optionally with lossless-JSON presentation metadata persisted for replay. */ -export type ToolExecuteReturn = ContentBlock[] | { content: ContentBlock[]; meta?: unknown } +/** Tool-owned canonical output contract used after the body returns a JSON value. */ +export interface ToolOutputDefinition { + /** Raw supported JSON Schema enforced against every successful canonical value. */ + readonly schema: JsonSchemaNode + /** Pure projection from validated arguments and value to Native/model content. */ + render(args: unknown, value: JsonValue): ContentBlock[] + /** Pure replayable presentation projection, computed only for surface calls. */ + presentationMeta?(args: unknown, value: JsonValue): JsonValue +} /** A registered tool: its schema plus the execution function. */ export interface ToolDefinition extends ToolSchema { - execute(args: unknown, exec: ToolRunContext): Promise<ToolExecuteReturn> + /** Mandatory canonical output declaration. */ + readonly output: ToolOutputDefinition + /** Execute the tool and return only its canonical lossless-JSON value. */ + execute(args: unknown, exec: ToolRunContext): Promise<unknown> /** * Cooperative tool-call timeout budget in milliseconds. Omit for no deadline. * Enforced by `@deepseek-ai/dsh-timeout-policy` (a `tools/execute` wrapper); it @@ -172,7 +186,7 @@ export interface ToolDefinition extends ToolSchema { presentCall?(args: unknown): ToolCallView | undefined /** * Optional: how to present the COMPLETED state, given the same `args` and the - * `result` (`execute`'s content + whether it errored). Returns a + * durable result projection (`content`, failure state, and optional `meta`). Returns a * {@link ToolResultView}, or `undefined` (or omit the method) to keep the * pending title and render the raw result content. Pure and side-effect-free * for the same replay reason. @@ -182,17 +196,16 @@ export interface ToolDefinition extends ToolSchema { /** The completed outcome handed to {@link ToolDefinition.presentResult}. */ export interface ToolResult { - /** The model-facing content `execute` returned (or the error text on failure). */ + /** The final model-facing content (or the rendered error text on failure). */ content: ContentBlock[] /** Whether the call failed. */ isError: boolean /** - * The tool-private presentation payload the tool attached from `execute` (via - * the object return form), threaded verbatim from the `tool/result` event. - * Opaque (`unknown`); the tool narrows it back to its own shape. Absent when - * the tool attached none. + * The tool-private presentation payload projected by its output declaration + * and threaded verbatim from the `tool/result` event. Absent when the tool + * declared no projector or the call was nested under a composite transport. */ - meta?: unknown + meta?: JsonValue } declare const toolExecutionTokenBrand: unique symbol @@ -303,6 +316,14 @@ export interface ToolErrorInfo { code: string } +/** Canonical failure detail; internal routing information remains optional. */ +export interface ToolFailure { + /** Human-readable failure message without the Native `Error: ` envelope. */ + message: string + /** Internal error class/code used by policy and durable diagnostics. */ + info?: ToolErrorInfo +} + /** * Thrown (internally) when the model requests a tool that isn't registered. * Extends {@link HarnessError} (`code: 'UNKNOWN_TOOL'`) so an unknown-tool @@ -316,30 +337,42 @@ export class ToolNotFoundError extends HarnessError { } } -/** The outcome of one tool call. */ -export interface ToolExecutionResult { - content: ContentBlock[] - isError: boolean - /** - * Set when the call failed with a {@link HarnessError}: machine-routable - * `{ name, code }` for retry/sandbox plugins and replay. The model-facing - * text in `content` is always present; this is extra structure for code. - */ - error?: ToolErrorInfo - /** - * Model-facing context for the next request, separate from this tool result. The loop - * accepts it into the active-batch FIFO, then appends after recorded results even if interrupted. - */ - additionalContexts?: HookContext[] - /** - * The tool-private presentation payload from a successful `execute` (the object - * return form). Threaded onto the `tool/result` session event and back into - * {@link ToolResult} for `presentResult`. Opaque (`unknown`); absent when the - * tool attached none or the call failed. - */ - meta?: unknown +/** Thrown when a tool body or post-policy value violates its declared output. */ +export class ToolOutputError extends HarnessError { + /** Schema/value violations in validation order. */ + readonly violations: string[] + + constructor(toolName: string, violations: string[]) { + super(`tool "${toolName}" returned invalid output: ${violations.join('; ')}`, 'INVALID_TOOL_OUTPUT') + this.name = 'ToolOutputError' + this.violations = violations + } } +/** Successful canonical tool execution, including its Native/model projection. */ +export interface ToolExecutionSuccess { + readonly isError: false + /** Execution-local canonical value; deliberately omitted from durable events. */ + readonly value: JsonValue + readonly content: ContentBlock[] + readonly error?: never + readonly meta?: JsonValue + readonly additionalContexts?: HookContext[] +} + +/** Failed canonical tool execution; failures never carry a successful value. */ +export interface ToolExecutionFailure { + readonly isError: true + readonly error: ToolFailure + readonly value?: never + readonly content: ContentBlock[] + readonly meta?: JsonValue + readonly additionalContexts?: HookContext[] +} + +/** The discriminated, execution-local outcome of one tool call. */ +export type ToolExecutionResult = ToolExecutionSuccess | ToolExecutionFailure + /** * Pre-dispatch decision. `allow` runs the call; `deny` materializes an error; * `ask` runs only after an approval service returns `allowed-once` and otherwise @@ -352,11 +385,12 @@ export type PreToolDecision = | { kind: 'ask'; reason?: string } /** - * Post-dispatch decision: accept or replace content, attach context for the next - * request, or block by turning corrective feedback into an error result. + * Post-dispatch decision: accept, replace one projection, attach context for the + * next request, or block by turning corrective feedback into an error result. */ export type PostToolDecision = - | { kind: 'accept'; content?: ContentBlock[]; additionalContexts?: HookContext[] } + | { kind: 'accept'; content?: ContentBlock[]; value?: never; additionalContexts?: HookContext[] } + | { kind: 'accept'; value: JsonValue; content?: never; additionalContexts?: HookContext[] } | { kind: 'block'; feedback: ContentBlock[]; additionalContexts?: HookContext[] } /** @@ -381,6 +415,23 @@ function errorMessage(error: unknown): string { } } +/** Derive one failure message from policy feedback without changing its rendered blocks. */ +function failureMessageFromContent(content: ContentBlock[]): string { + const text = content + .map(block => block.type === 'text' ? block.text : `[${block.type} content]`) + .join('\n') + return text.length > 0 ? text : 'tool result blocked by post-execute policy' +} + +/** Snapshot and freeze one durable tool-result projection or reject lossy data. */ +function materializePresentation<T>(candidate: T): T { + const detached = snapshotJsonValue(candidate) + if (detached === undefined) { + throw new TypeError('tool result must be losslessly JSON-serializable') + } + return deepFreeze(detached) +} + /** Structured `{ name, code }` for a thrown HarnessError, else undefined. */ function errorInfo(error: unknown): ToolErrorInfo | undefined { try { @@ -553,6 +604,13 @@ export class ToolRegistry extends Service { register(definition: ToolDefinition): () => void { const scope = scopeOf(this.ctx) const name = definition.name + const output = (definition as Partial<ToolDefinition>).output + if (output === undefined || typeof output !== 'object' + || typeof output.render !== 'function' + || (output.presentationMeta !== undefined && typeof output.presentationMeta !== 'function')) { + throw new TypeError(`tool "${name}" must declare output { schema, render, presentationMeta? }`) + } + assertSupportedJsonSchema(output.schema) const timeoutMs = definition.timeoutMs if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) { @@ -880,10 +938,11 @@ export class ToolRegistry extends Service { return await next({ kind: 'post-result', exec, - result: { + result: this.materializeFinalResult({ content: [{ type: 'text', text: `Error: ${denialReason}` }], isError: true, - }, + error: { message: denialReason }, + }), }) } return await next({ kind: 'dispatch', exec }) @@ -909,27 +968,26 @@ export class ToolRegistry extends Service { const tool = this.get(exec.name, exec.agent) if (!tool) throw new ToolNotFoundError(exec.name) const returned = await tool.execute(exec.arguments, exec) - const content = Array.isArray(returned) ? returned : returned.content - const meta = Array.isArray(returned) ? undefined : returned.meta - return { content, isError: false, ...meta !== undefined ? { meta } : {} } + return this.createSuccessResult(exec, tool, returned) } catch (error: unknown) { - return toolErrorResult(error) + return this.materializeFinalResult(toolErrorResult(error)) } }, ) + const normalized = this.normalizeDispatchResult(exec, result) const deferredContexts = this.deferredContexts.get(exec) /* v8 ignore next -- dispatch only receives executions minted by this registry's prepare stage */ if (deferredContexts === undefined) throw new Error('tool registry scheduler invariant violated: unprepared execution') const resultWithDeferredContexts: ToolExecutionResult = deferredContexts.length === 0 - ? result - : { - ...result, + ? normalized + : this.markCanonical({ + ...normalized, additionalContexts: [ ...deferredContexts, - ...result.additionalContexts ?? [], + ...normalized.additionalContexts ?? [], ], - } - return { kind: 'post-result', result: resultWithDeferredContexts } + }) + return { kind: 'post-result', result: this.materializeFinalResult(resultWithDeferredContexts) } } catch (error: unknown) { return { kind: 'final-result', result: toolErrorResult(error) } } @@ -1046,32 +1104,103 @@ export class ToolRegistry extends Service { ) const decisionContexts = decision.additionalContexts ?? [] if (decision.kind === 'block') { - return { + const message = failureMessageFromContent(decision.feedback) + return this.markCanonical({ content: decision.feedback, isError: true, + error: { message }, ...decisionContexts.length > 0 ? { additionalContexts: decisionContexts } : {}, - } + }) + } + if (Object.hasOwn(decision, 'content') && Object.hasOwn(decision, 'value')) { + throw new TypeError('tools/post-execute accept decision cannot replace both value and content') } - // Accept: replace content if supplied, preserve the dispatched outcome, and - // append decision contexts after contexts deferred by the tool body. const additionalContexts = [ ...result.additionalContexts ?? [], ...decisionContexts, ] - return { - ...result, - ...decision.content ? { content: decision.content } : {}, - ...additionalContexts.length > 0 ? { additionalContexts } : {}, + if (Object.hasOwn(decision, 'value')) { + if (result.isError) { + throw new TypeError('tools/post-execute cannot replace the value of a failed result') + } + const tool = this.get(exec.name, exec.agent) + if (tool === undefined) throw new ToolNotFoundError(exec.name) + const replaced = this.createSuccessResult(exec, tool, decision.value) + return this.markCanonical({ + ...replaced, + ...additionalContexts.length > 0 ? { additionalContexts } : {}, + }) } + return this.markCanonical({ + ...result, + ...decision.content !== undefined ? { content: decision.content } : {}, + ...additionalContexts.length > 0 ? { additionalContexts } : {}, + }) + } + + /** Results created by the registry already own a validated, frozen canonical value. */ + private readonly canonicalResults = new WeakSet<object>() + + /** Mark a registry-normalized result without freezing presentation fields prematurely. */ + private markCanonical<T extends ToolExecutionResult>(result: T): T { + this.canonicalResults.add(result) + return result + } + + /** Snapshot, validate, render, and optionally project one successful body value. */ + private createSuccessResult(exec: ToolExecution, tool: ToolDefinition, candidate: unknown): ToolExecutionSuccess { + const detached = snapshotJsonValue(candidate) + if (detached === undefined) { + throw new ToolOutputError(tool.name, ['value is not lossless JSON']) + } + const violations = validateJsonSchemaValue(tool.output.schema, detached, 'value') + if (violations.length > 0) throw new ToolOutputError(tool.name, violations) + const value = deepFreeze(detached as JsonValue) + const content = tool.output.render(exec.arguments, value) + const meta = exec.parent === undefined && tool.output.presentationMeta !== undefined + ? tool.output.presentationMeta(exec.arguments, value) + : undefined + return this.markCanonical(this.materializeFinalResult({ + isError: false, + value, + content, + ...meta !== undefined ? { meta } : {}, + }) as ToolExecutionSuccess) + } + + /** Normalize an around-dispatch wrapper's authored result through the owning output contract. */ + private normalizeDispatchResult(exec: ToolExecution, result: ToolExecutionResult): ToolExecutionResult { + if (this.canonicalResults.has(result)) return result + if (result.isError) { + return this.markCanonical({ + isError: true, + error: result.error, + content: result.content, + ...result.meta !== undefined ? { meta: result.meta } : {}, + ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, + }) + } + const tool = this.get(exec.name, exec.agent) + if (tool === undefined) throw new ToolNotFoundError(exec.name) + const normalized = this.createSuccessResult(exec, tool, result.value) + return this.markCanonical({ + ...normalized, + ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, + }) } /** Materialize the authoritative commit outcome once, immediately before `tools/result`. */ private materializeFinalResult(result: ToolExecutionResult): ToolExecutionResult { - const detached = snapshotJsonValue(result) - if (detached === undefined) { - throw new TypeError('tool result must be losslessly JSON-serializable') + const presentation = { + content: result.content, + ...result.meta !== undefined ? { meta: result.meta } : {}, + ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, } - return deepFreeze(detached) + if (result.isError) { + return materializePresentation({ isError: true as const, error: result.error, ...presentation }) + } + const detached = materializePresentation({ isError: false as const, ...presentation }) + return deepFreeze({ ...detached, value: result.value }) } } @@ -1082,10 +1211,11 @@ function createExecutionToken(): ToolExecutionToken { function toolErrorResult(error: unknown): ToolExecutionResult { const info = errorInfo(error) + const message = errorMessage(error) return { - content: [{ type: 'text', text: `Error: ${errorMessage(error)}` }], + content: [{ type: 'text', text: `Error: ${message}` }], isError: true, - ...info ? { error: info } : {}, + error: { message, ...info ? { info } : {} }, } } diff --git a/packages/core/tools/src/schema.ts b/packages/core/tools/src/schema.ts index 98be959e4e..d81a97508c 100644 --- a/packages/core/tools/src/schema.ts +++ b/packages/core/tools/src/schema.ts @@ -1,8 +1,9 @@ /** Unified JSON-value schema DSL, inference, compilation, and typed tool helper. @module dsh-tools/schema */ import { HarnessError } from '@deepseek-ai/dsh-llm' +import type { ContentBlock } from '@deepseek-ai/dsh-llm' import type { JsonValue } from '@deepseek-ai/dsh-session' -import type { ToolDefinition, ToolExecuteReturn, ToolRunContext, ToolResult } from './index.ts' +import type { ToolDefinition, ToolRunContext, ToolResult } from './index.ts' import { assertSupportedJsonSchema, isPlainJsonRecord, JsonSchemaError, validateJsonSchemaValue } from './json-schema.ts' import type { JsonSchemaNode, JsonSchemaScalar, ObjectJsonSchema } from './json-schema.ts' import type { ToolCallView, ToolResultView } from './presentation.ts' @@ -114,21 +115,25 @@ type RequiredKeys<S extends ParameterSchemaSpec> = { [K in keyof S]: S[K] extends { required: true } ? K : never }[keyof S] +/** Advance the bounded inference walk through one nested schema node. */ +type NextDepth<D extends readonly unknown[]> = readonly [...D, unknown] + /** Infer the declared value of one parameter property without key optionality. */ -type InferProperty<P extends ParameterPropertySpec> = P extends ValueSchemaSpec ? InferValue<P> : never +type InferProperty<P extends ParameterPropertySpec, D extends readonly unknown[]> = + P extends ValueSchemaSpec ? InferValue<P, D> : never /** Infer an implicit property map into required and optional object keys. */ -type InferProperties<S extends ParameterSchemaSpec> = Simplify< - & { [K in RequiredKeys<S>]: InferProperty<S[K]> } - & { [K in Exclude<keyof S, RequiredKeys<S>>]?: InferProperty<S[K]> } +type InferProperties<S extends ParameterSchemaSpec, D extends readonly unknown[]> = Simplify< + & { [K in RequiredKeys<S>]: InferProperty<S[K], D> } + & { [K in Exclude<keyof S, RequiredKeys<S>>]?: InferProperty<S[K], D> } > /** Infer an explicit object node, including its declared openness. */ -type InferObject<S extends ObjectValueSchemaSpec> = +type InferObject<S extends ObjectValueSchemaSpec, D extends readonly unknown[]> = S extends { properties: infer P extends ParameterSchemaSpec } ? S['additionalProperties'] extends true - ? InferProperties<P> & Record<string, JsonValue> - : InferProperties<P> + ? InferProperties<P, D> & Record<string, JsonValue> + : InferProperties<P, D> : S['additionalProperties'] extends true ? Record<string, JsonValue> : Record<string, never> @@ -143,20 +148,21 @@ type InferScalar<S, Fallback> = * Infer the TypeScript value accepted by an author-facing value schema. * Output schemas may therefore infer object, array, scalar, or null roots. */ -export type InferValue<S extends ValueSchemaSpec> = - S extends StringValueSchemaSpec ? InferScalar<S, string> : - S extends NumberValueSchemaSpec | IntegerValueSchemaSpec ? InferScalar<S, number> : - S extends BooleanValueSchemaSpec ? InferScalar<S, boolean> : - S extends NullValueSchemaSpec ? null : - S extends ArrayValueSchemaSpec - ? S extends { items: infer I extends ValueSchemaSpec } ? InferValue<I>[] : JsonValue[] - : S extends ObjectValueSchemaSpec ? InferObject<S> : - S extends JsonValueSchemaSpec ? JsonValue : - S extends OneOfValueSchemaSpec ? InferValue<S['oneOf'][number]> : - never +export type InferValue<S extends ValueSchemaSpec, D extends readonly unknown[] = readonly []> = + D['length'] extends 12 ? JsonValue : + S extends StringValueSchemaSpec ? InferScalar<S, string> : + S extends NumberValueSchemaSpec | IntegerValueSchemaSpec ? InferScalar<S, number> : + S extends BooleanValueSchemaSpec ? InferScalar<S, boolean> : + S extends NullValueSchemaSpec ? null : + S extends ArrayValueSchemaSpec + ? S extends { items: infer I extends ValueSchemaSpec } ? InferValue<I, NextDepth<D>>[] : JsonValue[] + : S extends ObjectValueSchemaSpec ? InferObject<S, NextDepth<D>> : + S extends JsonValueSchemaSpec ? JsonValue : + S extends OneOfValueSchemaSpec ? InferValue<S['oneOf'][number], NextDepth<D>> : + never /** Infer the TypeScript argument object for an implicit parameter schema. */ -export type InferArgs<S extends ParameterSchemaSpec> = InferProperties<S> +export type InferArgs<S extends ParameterSchemaSpec> = InferProperties<S, readonly []> const ANNOTATION_KEYS = ['description', 'title', 'default', 'examples'] as const @@ -329,13 +335,22 @@ export function validateArgs(spec: ParameterSchemaSpec, args: unknown): string[] } /** Options for {@link defineTool}. */ -export interface DefineToolOptions<S extends ParameterSchemaSpec> { +export interface DefineToolOptions<S extends ParameterSchemaSpec, O extends ValueSchemaSpec> { /** Tool name (must be unique). */ readonly name: string /** Human-readable description sent to the model. */ readonly description: string /** Per-property parameter schema compiled to an implicit open object root. */ readonly parameters: S + /** Canonical output schema plus pure Native and presentation projections. */ + readonly output: { + /** Schema enforced against every successful body or policy-replaced value. */ + readonly schema: O + /** Pure Native/model rendering of one validated canonical value. */ + render(args: InferArgs<S>, value: InferValue<NoInfer<O>>): ContentBlock[] + /** Pure replayable presentation metadata for direct surface calls. */ + presentationMeta?(args: InferArgs<S>, value: InferValue<NoInfer<O>>): JsonValue + } /** Optional positive cooperative timeout budget in milliseconds. */ readonly timeoutMs?: number /** @@ -348,9 +363,9 @@ export interface DefineToolOptions<S extends ParameterSchemaSpec> { * Execute the tool after argument validation. * @param args - typed validated arguments. * @param exec - execution identity, caller, cancellation, and nesting data. - * @returns Model-facing content and optional presentation metadata. + * @returns The canonical value declared by `output.schema`. */ - execute(args: InferArgs<S>, exec: ToolRunContext): Promise<ToolExecuteReturn> + execute(args: InferArgs<S>, exec: ToolRunContext): Promise<InferValue<NoInfer<O>>> /** * Pure pending-state presenter. * @param args - typed validated arguments. @@ -373,11 +388,17 @@ export interface DefineToolOptions<S extends ParameterSchemaSpec> { * @param options - typed definition and optional presenters. * @returns A registry-ready definition. */ -export function defineTool<S extends ParameterSchemaSpec>(options: DefineToolOptions<S>): ToolDefinition { +export function defineTool<const S extends ParameterSchemaSpec, const O extends ValueSchemaSpec>( + options: DefineToolOptions<S, O>, +): ToolDefinition { // Object-literal methods do not use `this`; retaining references is safe. // eslint-disable-next-line @typescript-eslint/unbound-method const userExecute = options.execute // eslint-disable-next-line @typescript-eslint/unbound-method + const userRender = options.output.render + // eslint-disable-next-line @typescript-eslint/unbound-method + const userPresentationMeta = options.output.presentationMeta + // eslint-disable-next-line @typescript-eslint/unbound-method const userPresentCall = options.presentCall // eslint-disable-next-line @typescript-eslint/unbound-method const userPresentResult = options.presentResult @@ -387,16 +408,28 @@ export function defineTool<S extends ParameterSchemaSpec>(options: DefineToolOpt throw new Error(`defineTool(${options.name}): timeoutMs must be a positive finite number`) } const parameters = parameterSchemaSpecToJsonSchema(options.parameters) + const outputSchema = valueSchemaSpecToJsonSchema(options.output.schema) const validate = (args: unknown): string[] => validateJsonSchemaValue(parameters, args, '') const tool: ToolDefinition = { name: options.name, description: options.description, parameters: parameters as unknown as Record<string, unknown>, + output: { + schema: outputSchema, + render(args: unknown, value: JsonValue): ContentBlock[] { + return userRender(args as InferArgs<S>, value as unknown as InferValue<NoInfer<O>>) + }, + ...userPresentationMeta !== undefined ? { + presentationMeta(args: unknown, value: JsonValue): JsonValue { + return userPresentationMeta(args as InferArgs<S>, value as unknown as InferValue<NoInfer<O>>) + }, + } : {}, + }, ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}), - async execute(args: unknown, exec: ToolRunContext): Promise<ToolExecuteReturn> { + async execute(args: unknown, exec: ToolRunContext): Promise<JsonValue> { const violations = validate(args) if (violations.length > 0) throw new ToolArgsError(violations) - return userExecute(args as InferArgs<S>, exec) + return userExecute(args as InferArgs<S>, exec) as Promise<JsonValue> }, } if (userPresentCall) { diff --git a/packages/core/tools/src/testing.ts b/packages/core/tools/src/testing.ts new file mode 100644 index 0000000000..ad9fa52d85 --- /dev/null +++ b/packages/core/tools/src/testing.ts @@ -0,0 +1,42 @@ +/** Canonical tool-definition fixtures for repository tests. @module dsh-tools/testing */ + +import type { ContentBlock } from '@deepseek-ai/dsh-llm' +import type { JsonValue } from '@deepseek-ai/dsh-session' +import { defineTool } from './schema.ts' +import type { DefineToolOptions, ParameterSchemaSpec } from './schema.ts' +import type { ToolDefinition, ToolRunContext } from './index.ts' + +const CONTENT_VALUE_SCHEMA = { type: 'array', items: { type: 'json' } } as const + +/** Options for a fixture whose canonical value is its rendered content array. */ +export type ContentToolFixtureOptions<S extends ParameterSchemaSpec> = Omit< + DefineToolOptions<S, typeof CONTENT_VALUE_SCHEMA>, + 'output' | 'execute' +> & { + /** Produce the fixture's content blocks as its canonical test value. */ + execute(args: import('./schema.ts').InferArgs<S>, exec: ToolRunContext): Promise<ContentBlock[]> +} + +/** + * Define a test fixture that deliberately uses its content blocks as the + * canonical JSON value. Product tools must declare domain-owned DTOs instead. + * @param options - ordinary fixture fields plus a content-producing body. + * @returns a registry-ready tool with an explicit JSON-array output contract. + * @internal + */ +export function defineContentToolFixture<const S extends ParameterSchemaSpec>( + options: ContentToolFixtureOptions<S>, +): ToolDefinition { + // eslint-disable-next-line @typescript-eslint/unbound-method + const execute = options.execute + return defineTool({ + ...options, + output: { + schema: CONTENT_VALUE_SCHEMA, + render: (_args, value) => value as unknown as ContentBlock[], + }, + async execute(args, exec) { + return await execute(args, exec) as unknown as JsonValue[] + }, + }) +} diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index 227ff98129..0fe48af14a 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -6,7 +6,7 @@ import type { Scope } from '@deepseek-ai/dsh-scope' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import { CodeRuntime } from '@deepseek-ai/dsh-code-runtime' import type { CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' -import ToolRegistry, { CodeRunFailedError, RUN_CODE_NAME, defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { CodeRunFailedError, RUN_CODE_NAME, defineContentToolFixture } from '@deepseek-ai/dsh-tools' import type { Config, PostToolDecision, ToolExecutionResult } from '@deepseek-ai/dsh-tools' import type { Agent } from '@deepseek-ai/dsh-agent' import { Session, SessionId } from '@deepseek-ai/dsh-session' @@ -68,7 +68,7 @@ async function mintAgentScope(ctx: Context, name = 'scoped'): Promise<{ scope: S /** Register a trivial echo tool; returns the calls it received. */ function registerEcho(ctx: Context, name = 'echo'): unknown[] { const calls: unknown[] = [] - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name, description: `Echo tool ${name}.`, parameters: { value: { type: 'string', required: true } }, @@ -217,7 +217,7 @@ describe('mode-aware wire contribution', () => { it.each(['code', 'both'] as const)('reserves run_code against scoped shadows and explicit restrictions in mode %s', async (mode) => { const { ctx, systemPrompt } = await setup({ mode }) const { scope, agent } = await mintAgentScope(ctx) - const impostor = defineTool({ + const impostor = defineContentToolFixture({ name: RUN_CODE_NAME, description: 'Scoped impostor.', parameters: {}, @@ -229,7 +229,7 @@ describe('mode-aware wire contribution', () => { expect(() => scope.ctx.tools.restrict({ allow: [RUN_CODE_NAME] })).toThrow(/cannot name reserved Code Mode presentation transport/) expect(() => scope.ctx.tools.restrict({ deny: [RUN_CODE_NAME] })).toThrow(/cannot name reserved Code Mode presentation transport/) scope.ctx.systemPrompt.section({ name: 'scoped-note', order: 149, text: 'safe note' }) - scope.ctx.tools.register(defineTool({ + scope.ctx.tools.register(defineContentToolFixture({ name: 'scoped_safe', description: 'Safe scoped tool.', parameters: {}, @@ -332,6 +332,8 @@ describe('the run_code dispatch bridge', () => { } const result = await runCode(ctx, 'const …: string = …', { agent }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected run_code success') + expect(result.value).toEqual({ logs: ['saw echo:one'], result: 'echo:two' }) expect(result.content).toEqual([{ type: 'text', text: 'saw echo:one\necho:two' }]) expect(calls).toEqual([{ value: 'one' }, { value: 'two' }]) const dispatches = events.filter(event => event.type === 'tool/code-dispatch') @@ -374,7 +376,7 @@ describe('the run_code dispatch bridge', () => { const { ctx, runtime } = await setup({ mode: 'code' }) const intervals: [string, string][] = [] let active = 0 - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'probe', description: 'Records execution overlap.', parameters: { id: { type: 'string', required: true } }, @@ -405,7 +407,7 @@ describe('the run_code dispatch bridge', () => { it('rejects the program-side call when the tool errors, with the tool error text', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'fail', description: 'Always fails.', parameters: {}, @@ -549,7 +551,7 @@ describe('the run_code dispatch bridge', () => { }) const result = await runCode(ctx, 'program') expect(result.isError).toBe(true) - expect(result.error).toEqual({ name: 'CodeRunFailedError', code: 'CODE_RUN_FAILED' }) + expect(result.error).toMatchObject({ info: { name: 'CodeRunFailedError', code: 'CODE_RUN_FAILED' } }) const text = (result.content[0] as { text: string }).text expect(text).toContain('code run failed (timeout)') expect(text).toContain('compute budget exhausted') @@ -566,7 +568,7 @@ describe('the run_code dispatch bridge', () => { const { ctx, runtime } = await setup({ mode: 'code' }) const seen: string[] = [] let sawAbort = false - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'slow', description: 'Slow tool observing its signal.', parameters: { id: { type: 'string', required: true } }, @@ -602,7 +604,7 @@ describe('the run_code dispatch bridge', () => { let sawAbort = false let started!: () => void const inFlight = new Promise<void>((resolve) => { started = resolve }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'slow', description: 'Slow tool observing its signal.', parameters: { id: { type: 'string', required: true } }, @@ -689,7 +691,7 @@ describe('the run_code dispatch bridge', () => { const { ctx, runtime } = await setup({ mode: 'code' }) const { agent, events } = fakeAgent() const long = 'x'.repeat(300) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'mixed', description: 'Returns mixed content.', parameters: {}, @@ -714,7 +716,7 @@ describe('the run_code dispatch bridge', () => { it('normalizes the session workspace root before bounding durable result summaries', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'workspace_path', description: 'Return a path beneath the session workspace.', parameters: {}, @@ -792,7 +794,7 @@ describe('the run_code dispatch bridge', () => { const { ctx, runtime } = await setup({ mode: 'code' }) const { agent, events } = fakeAgent() let mutationSucceeded: boolean | undefined - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'mutator', description: 'Attempts to mutate its args object.', parameters: { list: { type: 'array', required: true } }, @@ -814,7 +816,7 @@ describe('the run_code dispatch bridge', () => { it('exposes a tool named __proto__ as an ordinary own binding', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: '__proto__', description: 'A prototype-colliding tool name.', parameters: {}, diff --git a/packages/core/tools/tests/execution-mode.spec.ts b/packages/core/tools/tests/execution-mode.spec.ts index 9a12f33a51..ac490396a4 100644 --- a/packages/core/tools/tests/execution-mode.spec.ts +++ b/packages/core/tools/tests/execution-mode.spec.ts @@ -5,7 +5,7 @@ import { Context } from 'cordis' import { CallId } from '@deepseek-ai/dsh-llm' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import ToolRegistry, { - defineTool, + defineContentToolFixture, type ToolDefinition, type ToolExecutionInput, type ToolExecutionMode, @@ -25,7 +25,7 @@ function exec(name: string, args: unknown): ToolExecutionInput { describe('ToolRegistry.executionMode', () => { it('returns parallel only for an explicit true classifier', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'safe', description: 'parallel-safe', parameters: {}, @@ -37,7 +37,7 @@ describe('ToolRegistry.executionMode', () => { it('defaults to exclusive for a tool with no isConcurrencySafe declaration', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'plain', description: 'no declaration', parameters: {}, @@ -53,7 +53,7 @@ describe('ToolRegistry.executionMode', () => { it('returns exclusive when the classifier returns false for these args', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'rw', description: 'read or write', parameters: { mode: { type: 'string', required: true } }, @@ -64,9 +64,9 @@ describe('ToolRegistry.executionMode', () => { expect(ctx.tools.executionMode(exec('rw', { mode: 'write' }))).toEqual({ kind: 'exclusive' }) }) - it('classifies invalid defineTool arguments as exclusive without throwing', async () => { + it('classifies invalid defineContentToolFixture arguments as exclusive without throwing', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'needs-mode', description: 'requires mode', parameters: { mode: { type: 'string', required: true } }, @@ -82,8 +82,9 @@ describe('ToolRegistry.executionMode', () => { name: 'thrower', description: 'classifier throws', parameters: { type: 'object', properties: {} }, + output: { schema: { type: 'null' }, render: () => [] }, isConcurrencySafe() { throw new Error('boom') }, - async execute() { return [] }, + async execute() { return null }, } ctx.tools.register(raw) expect(ctx.tools.executionMode(exec('thrower', {}))).toEqual({ kind: 'exclusive' }) @@ -95,8 +96,9 @@ describe('ToolRegistry.executionMode', () => { name: 'truthy', description: 'classifier returns a truthy string', parameters: { type: 'object', properties: {} }, + output: { schema: { type: 'null' }, render: () => [] }, isConcurrencySafe() { return 'yes' }, - async execute() { return [] }, + async execute() { return null }, } as unknown as ToolDefinition ctx.tools.register(raw) expect(ctx.tools.executionMode(exec('truthy', {}))).toEqual({ kind: 'exclusive' }) @@ -109,8 +111,9 @@ describe('ToolRegistry.executionMode', () => { name: 'raw-safe', description: 'raw', parameters: { type: 'object', properties: {} }, + output: { schema: { type: 'null' }, render: () => [] }, isConcurrencySafe(args) { seen = args; return true }, - async execute() { return [] }, + async execute() { return null }, }) expect(ctx.tools.executionMode(exec('raw-safe', { anything: 1 }))).toEqual({ kind: 'parallel' }) expect(seen).toEqual({ anything: 1 }) @@ -118,7 +121,7 @@ describe('ToolRegistry.executionMode', () => { it('isConcurrencySafe never reaches the model-facing schemas() projection', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'safe', description: 'parallel-safe', parameters: { x: { type: 'string', required: true } }, diff --git a/packages/core/tools/tests/scoped.spec.ts b/packages/core/tools/tests/scoped.spec.ts index 843aeb3837..a214f4f6bf 100644 --- a/packages/core/tools/tests/scoped.spec.ts +++ b/packages/core/tools/tests/scoped.spec.ts @@ -9,7 +9,6 @@ import type { PreToolDecision, ToolDefinition, ToolExecution, ToolExecutionInput import type { Agent } from '@deepseek-ai/dsh-agent' import { CallId } from '@deepseek-ai/dsh-llm' -import type { ContentBlock } from '@deepseek-ai/dsh-llm' import type { SessionId } from '@deepseek-ai/dsh-session' /** Mount the registry (with its systemPrompt dependency) on a fresh context. */ @@ -37,7 +36,11 @@ function tool(name: string, reply = `ran:${name}`): ToolDefinition { name, description: `tool ${name}`, parameters: { type: 'object', properties: {} }, - execute: (): Promise<ContentBlock[]> => Promise.resolve([{ type: 'text', text: reply }]), + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value as string }], + }, + execute: (): Promise<string> => Promise.resolve(reply), } } @@ -221,7 +224,7 @@ describe('scoped execution dispatch', () => { ...tool('t'), execute: () => { bodyCalls += 1 - return Promise.resolve([{ type: 'text', text: 'ran:t' }]) + return Promise.resolve('ran:t') }, }) const guard = (execution: Readonly<ToolExecution>): string => { @@ -253,7 +256,7 @@ describe('scoped execution dispatch', () => { ...tool('t'), execute: () => { bodyCalls += 1 - return Promise.resolve([]) + return Promise.resolve('ran:t') }, }) ctx.tools.guard(() => undefined) @@ -276,14 +279,14 @@ describe('scoped execution dispatch', () => { execute: (args) => { safeCalls += 1 safeArguments = args - return Promise.resolve([{ type: 'text', text: 'safe' }]) + return Promise.resolve('safe') }, }) ctx.tools.register({ ...tool('danger'), execute: () => { dangerCalls += 1 - return Promise.resolve([{ type: 'text', text: 'danger' }]) + return Promise.resolve('danger') }, }) scope.ctx.tools.guard(exec => exec.name === 'danger' ? 'danger denied' : undefined) @@ -335,7 +338,7 @@ describe('scoped execution dispatch', () => { ...tool('t'), execute: () => { bodyCalls += 1 - return Promise.resolve([]) + return Promise.resolve('ran:t') }, }) ctx.on('tools/pre-execute', (_exec, next) => { @@ -396,7 +399,7 @@ describe('scoped execution dispatch', () => { ...tool('t'), execute: (_args, exec) => { observed.push(exec.parent) - return Promise.resolve([{ type: 'text', text: 'ran:t' }]) + return Promise.resolve('ran:t') }, }) ctx.on('tools/pre-execute', (exec, next) => { @@ -511,7 +514,7 @@ describe('scoped execution dispatch', () => { ...tool('t'), execute: () => { bodyCalls += 1 - return Promise.resolve([]) + return Promise.resolve('ran:t') }, }) ctx.on('tools/pre-execute', (_exec, next) => { @@ -552,6 +555,7 @@ describe('scoped execution dispatch', () => { expect(result).toEqual({ content: [{ type: 'text', text: 'ran:t' }], isError: false, + value: 'ran:t', }) }) @@ -570,6 +574,7 @@ describe('scoped execution dispatch', () => { return { content: [{ type: 'text', text: 'outer failure' }], isError: true, + error: { message: 'outer failure' }, } }, { prepend: true }) scope.ctx.on('tools/result', (_exec, result) => { diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index 5ddac2cd31..a8ccf384d5 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -5,9 +5,9 @@ import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import type { Agent } from '@deepseek-ai/dsh-agent' import ApprovalService, { type ApprovalOutcome, type ApprovalRequest } from '@deepseek-ai/dsh-user-approval' import ToolRegistry, { - defineTool, JsonSchemaError, parameterSchemaSpecToJsonSchema, validateArgs, ToolArgsError, ToolNotFoundError, + defineContentToolFixture, defineTool, JsonSchemaError, parameterSchemaSpecToJsonSchema, validateArgs, ToolArgsError, ToolNotFoundError, type InferArgs, type JsonValue, type ParameterSchemaSpec, type PreToolDecision, type PostToolDecision, - type ToolExecution, type ToolExecutionResult, + type ToolDefinition, type ToolExecution, type ToolExecutionResult, type ToolExecutionToken, } from '@deepseek-ai/dsh-tools' async function setup() { @@ -21,8 +21,12 @@ const echoTool = defineTool({ name: 'echo', description: 'echo arguments back', parameters: { text: { type: 'string' } }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args) { - return [{ type: 'text' as const, text: args.text ?? '' }] + return args.text ?? '' }, }) @@ -50,7 +54,7 @@ describe('ToolRegistry', () => { // the system-prompt assembly → the model request, so those callbacks (and // `execute`) must be stripped: a function in the JSON tool schema would // corrupt the request. schemas() is an explicit allowlist, so it can't leak. - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'present', description: 'has presenters', parameters: { x: { type: 'string', required: true } }, @@ -67,7 +71,7 @@ describe('ToolRegistry', () => { it('schemas() excludes timeoutMs — the budget must never reach the model', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'budgeted', description: 'has a budget', parameters: {}, timeoutMs: 5_000, async execute() { return [{ type: 'text' as const, text: 'ok' }] }, })) @@ -79,17 +83,24 @@ describe('ToolRegistry', () => { it('executes a tool and returns its content', async () => { const ctx = await setup() ctx.tools.register(echoTool) + let observed: ToolExecutionResult | undefined + ctx.on('tools/result', (_exec, result) => { observed = result }) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'echo', arguments: { text: 'hi' } }) - expect(result).toEqual({ content: [{ type: 'text', text: 'hi' }], isError: false }) + expect(result).toEqual({ content: [{ type: 'text', text: 'hi' }], isError: false, value: 'hi' }) + expect(observed).toEqual(result) }) - it('threads a tool-attached meta (object return form) onto the result', async () => { + it('projects presentation metadata from the canonical value', async () => { const ctx = await setup() ctx.tools.register({ ...echoTool, name: 'meta-tool', + output: { + ...echoTool.output, + presentationMeta: () => ({ diffs: [{ path: 'a', oldText: null, newText: 'x' }] }), + }, async execute() { - return { content: [{ type: 'text', text: 'ok' }], meta: { diffs: [{ path: 'a', oldText: null, newText: 'x' }] } } + return 'ok' }, }) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'meta-tool', arguments: {} }) @@ -97,20 +108,21 @@ describe('ToolRegistry', () => { content: [{ type: 'text', text: 'ok' }], isError: false, meta: { diffs: [{ path: 'a', oldText: null, newText: 'x' }] }, + value: 'ok', }) }) - it('omits meta when the object return form supplies none', async () => { + it('omits meta when no presentation projector is declared', async () => { const ctx = await setup() ctx.tools.register({ ...echoTool, name: 'no-meta-tool', async execute() { - return { content: [{ type: 'text', text: 'ok' }] } + return 'ok' }, }) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'no-meta-tool', arguments: {} }) - expect(result).toEqual({ content: [{ type: 'text', text: 'ok' }], isError: false }) + expect(result).toEqual({ content: [{ type: 'text', text: 'ok' }], isError: false, value: 'ok' }) expect('meta' in result).toBe(false) }) @@ -121,8 +133,12 @@ describe('ToolRegistry', () => { ctx.tools.register({ ...echoTool, name: 'bad-meta', + output: { + ...echoTool.output, + presentationMeta: () => (() => undefined) as unknown as JsonValue, + }, async execute() { - return { content: [], meta: () => undefined } + return 'ok' }, }) @@ -134,6 +150,284 @@ describe('ToolRegistry', () => { expect(observedError).toBe(true) }) + it('requires every raw registration to declare its canonical output', async () => { + const ctx = await setup() + const missingOutput = { + name: 'legacy-content-tool', + description: 'missing output', + parameters: {}, + execute: async () => [{ type: 'text', text: 'legacy' }], + } as unknown as ToolDefinition + + expect(() => ctx.tools.register(missingOutput)) + .toThrow('must declare output { schema, render, presentationMeta? }') + }) + + it('rejects lossy and schema-mismatched body values before post-execute', async () => { + const ctx = await setup() + ctx.tools.register(defineTool({ + name: 'lossy-output', + description: 'lossy', + parameters: {}, + output: { schema: { type: 'json' }, render: () => [] }, + execute: async () => (() => undefined) as unknown as JsonValue, + })) + ctx.tools.register(defineTool({ + name: 'wrong-output', + description: 'wrong schema', + parameters: {}, + output: { schema: { type: 'string' }, render: () => [] }, + execute: async () => 42 as unknown as string, + })) + + const lossy = await ctx.tools.execute({ callId: CallId('lossy'), name: 'lossy-output', arguments: {} }) + const mismatch = await ctx.tools.execute({ callId: CallId('mismatch'), name: 'wrong-output', arguments: {} }) + expect(lossy.error).toMatchObject({ info: { name: 'ToolOutputError', code: 'INVALID_TOOL_OUTPUT' } }) + expect(lossy.content[0]?.type === 'text' ? lossy.content[0].text : '').toContain('not lossless JSON') + expect(mismatch.error).toMatchObject({ info: { name: 'ToolOutputError', code: 'INVALID_TOOL_OUTPUT' } }) + expect(mismatch.content[0]?.type === 'text' ? mismatch.content[0].text : '').toContain('"value" must be a string') + }) + + it.each(['render', 'presentationMeta'] as const)('contains a throwing output.%s projector as one failed call', async (projector) => { + const ctx = await setup() + ctx.tools.register(defineTool({ + name: `throwing-${projector}`, + description: projector, + parameters: {}, + output: { + schema: { type: 'string' }, + render: () => { + if (projector === 'render') throw new Error('renderer exploded') + return [{ type: 'text', text: 'ok' }] + }, + presentationMeta: () => { + if (projector === 'presentationMeta') throw new Error('metadata exploded') + return null + }, + }, + execute: async () => 'ok', + })) + + const result = await ctx.tools.execute({ callId: CallId(projector), name: `throwing-${projector}`, arguments: {} }) + expect(result).toMatchObject({ + isError: true, + error: { message: projector === 'render' ? 'renderer exploded' : 'metadata exploded' }, + }) + expect('value' in result).toBe(false) + }) + + it('keeps value/meta through content replacement and recomputes both projections after value replacement', async () => { + const ctx = await setup() + ctx.tools.register(defineTool({ + name: 'projected', + description: 'projected', + parameters: {}, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { text: { type: 'string', required: true } }, + }, + render: (_args, value) => [{ type: 'text', text: `render:${value.text}` }], + presentationMeta: (_args, value) => ({ projected: value.text }), + }, + execute: async () => ({ text: 'body' }), + })) + let replacement: 'content' | 'value' = 'content' + ctx.on('tools/post-execute', async () => { + if (replacement === 'content') { + return { kind: 'accept', content: [{ type: 'text', text: 'policy content' }] } + } + return { + kind: 'accept', + value: { text: 'policy value' }, + additionalContexts: [{ content: [{ type: 'text', text: 'value context' }], source: { kind: 'plugin', plugin: 'test' } }], + } + }) + + const content = await ctx.tools.execute({ callId: CallId('content'), name: 'projected', arguments: {} }) + replacement = 'value' + const value = await ctx.tools.execute({ callId: CallId('value'), name: 'projected', arguments: {} }) + + expect(content).toEqual({ + isError: false, + value: { text: 'body' }, + content: [{ type: 'text', text: 'policy content' }], + meta: { projected: 'body' }, + }) + expect(value).toEqual({ + isError: false, + value: { text: 'policy value' }, + content: [{ type: 'text', text: 'render:policy value' }], + meta: { projected: 'policy value' }, + additionalContexts: [{ content: [{ type: 'text', text: 'value context' }], source: { kind: 'plugin', plugin: 'test' } }], + }) + }) + + it('fails a post-execute decision that replaces both projections or supplies an invalid value', async () => { + const both = await setup() + both.tools.register(echoTool) + both.on('tools/post-execute', async () => ({ + kind: 'accept', + value: 'replacement', + content: [{ type: 'text', text: 'also replacement' }], + } as unknown as PostToolDecision)) + const bothResult = await both.tools.execute({ callId: CallId('both'), name: 'echo', arguments: {} }) + expect(bothResult).toMatchObject({ + isError: true, + error: { message: 'tools/post-execute accept decision cannot replace both value and content' }, + }) + + const invalid = await setup() + invalid.tools.register(echoTool) + invalid.on('tools/post-execute', async () => ({ kind: 'accept', value: 1 })) + const invalidResult = await invalid.tools.execute({ callId: CallId('invalid'), name: 'echo', arguments: {} }) + expect(invalidResult.error).toMatchObject({ info: { code: 'INVALID_TOOL_OUTPUT' } }) + expect('value' in invalidResult).toBe(false) + }) + + it('turns a post-execute block into a valueless failure', async () => { + const ctx = await setup() + ctx.tools.register(echoTool) + ctx.on('tools/post-execute', async () => ({ + kind: 'block', + feedback: [{ type: 'text', text: 'blocked by policy' }], + })) + + const result = await ctx.tools.execute({ callId: CallId('block'), name: 'echo', arguments: { text: 'secret' } }) + expect(result).toEqual({ + isError: true, + error: { message: 'blocked by policy' }, + content: [{ type: 'text', text: 'blocked by policy' }], + }) + expect('value' in result).toBe(false) + }) + + it('replaces a canonical value without manufacturing additional context', async () => { + const ctx = await setup() + ctx.tools.register(echoTool) + ctx.on('tools/post-execute', async () => ({ kind: 'accept', value: 'replacement' })) + + const result = await ctx.tools.execute({ callId: CallId('replace-value'), name: 'echo', arguments: {} }) + expect(result).toEqual({ + isError: false, + value: 'replacement', + content: [{ type: 'text', text: 'replacement' }], + }) + }) + + it.each([ + [[], 'tool result blocked by post-execute policy'], + [[{ type: 'reasoning', text: 'private rationale' }], '[reasoning content]'], + ] as const)('derives a stable failure message from non-text or empty block feedback', async (feedback, message) => { + const ctx = await setup() + ctx.tools.register(echoTool) + ctx.on('tools/post-execute', async () => ({ kind: 'block', feedback: [...feedback] })) + + const result = await ctx.tools.execute({ callId: CallId('block-message'), name: 'echo', arguments: {} }) + expect(result.error?.message).toBe(message) + }) + + it('contains a non-JSON post-execute failure projection as a safe final error', async () => { + const ctx = await setup() + ctx.tools.register(echoTool) + ctx.on('tools/post-execute', async () => ({ + kind: 'block', + feedback: [{ type: 'text', text: 'blocked', invalid: () => undefined } as never], + })) + + const result = await ctx.tools.execute({ callId: CallId('invalid-block'), name: 'echo', arguments: {} }) + expect(result).toMatchObject({ + isError: true, + error: { message: 'tool result must be losslessly JSON-serializable' }, + }) + }) + + it('rejects value replacement on a failed dispatch', async () => { + const ctx = await setup() + ctx.tools.register({ + ...echoTool, + name: 'throw-before-replace', + async execute() { throw new Error('body failed') }, + }) + ctx.on('tools/post-execute', async () => ({ kind: 'accept', value: 'replacement' })) + + const result = await ctx.tools.execute({ + callId: CallId('failed-replace'), name: 'throw-before-replace', arguments: {}, + }) + expect(result.error?.message).toBe('tools/post-execute cannot replace the value of a failed result') + }) + + it('fails value replacement when the owning tool disappears before post-policy resolves', async () => { + const ctx = await setup() + const dispose = ctx.tools.register(echoTool) + ctx.on('tools/post-execute', async () => { + dispose() + return { kind: 'accept', value: 'replacement' } + }) + + const result = await ctx.tools.execute({ callId: CallId('post-disposed'), name: 'echo', arguments: {} }) + expect(result.error).toEqual({ + message: 'unknown tool "echo"', + info: { name: 'ToolNotFoundError', code: 'UNKNOWN_TOOL' }, + }) + }) + + it('normalizes wrapper-authored failure metadata and contexts', async () => { + const ctx = await setup() + ctx.tools.register(echoTool) + ctx.on('tools/execute', async () => ({ + isError: true, + error: { message: 'wrapped failure' }, + content: [{ type: 'text', text: 'wrapper content' }], + meta: { wrapped: true }, + additionalContexts: [{ content: [{ type: 'text', text: 'wrapper context' }], source: { kind: 'plugin', plugin: 'test' } }], + })) + + const result = await ctx.tools.execute({ callId: CallId('wrapper-failure'), name: 'echo', arguments: {} }) + expect(result).toEqual({ + isError: true, + error: { message: 'wrapped failure' }, + content: [{ type: 'text', text: 'wrapper content' }], + meta: { wrapped: true }, + additionalContexts: [{ content: [{ type: 'text', text: 'wrapper context' }], source: { kind: 'plugin', plugin: 'test' } }], + }) + }) + + it('fails wrapper-authored success normalization when the owning tool disappears', async () => { + const ctx = await setup() + const dispose = ctx.tools.register(echoTool) + ctx.on('tools/execute', async () => { + dispose() + return { isError: false, value: 'replacement', content: [] } + }) + + const result = await ctx.tools.execute({ callId: CallId('wrapper-disposed'), name: 'echo', arguments: {} }) + expect(result.error).toEqual({ + message: 'unknown tool "echo"', + info: { name: 'ToolNotFoundError', code: 'UNKNOWN_TOOL' }, + }) + }) + + it('suppresses presentation metadata only for nested composite dispatches', async () => { + const ctx = await setup() + ctx.tools.register({ + ...echoTool, + name: 'meta-suppression', + output: { ...echoTool.output, presentationMeta: () => ({ card: true }) }, + }) + const direct = await ctx.tools.execute({ callId: CallId('direct'), name: 'meta-suppression', arguments: {} }) + const nested = await ctx.tools.execute({ + callId: CallId('nested'), + name: 'meta-suppression', + arguments: {}, + parent: Symbol('outer') as ToolExecutionToken, + }) + expect(direct.meta).toEqual({ card: true }) + expect(nested.meta).toBeUndefined() + expect(nested.isError ? undefined : nested.value).toBe('') + }) + it('returns isError results for unknown tools and throwing tools', async () => { const ctx = await setup() ctx.tools.register({ @@ -148,7 +442,10 @@ describe('ToolRegistry', () => { expect(unknown.isError).toBe(true) expect(unknown.content[0]).toMatchObject({ text: 'Error: unknown tool "nope"' }) // An unknown tool is a routable failure class, same as a tool-thrown one. - expect(unknown.error).toEqual({ name: 'ToolNotFoundError', code: 'UNKNOWN_TOOL' }) + expect(unknown.error).toEqual({ + message: 'unknown tool "nope"', + info: { name: 'ToolNotFoundError', code: 'UNKNOWN_TOOL' }, + }) const thrown = await ctx.tools.execute({ callId: CallId('c2'), name: 'boom', arguments: {} }) expect(thrown.isError).toBe(true) @@ -189,15 +486,22 @@ describe('ToolRegistry', () => { it('lets a tools/pre-execute listener deny a call (permission pattern)', async () => { const ctx = await setup() ctx.tools.register(echoTool) + let postSawFrozen = false ctx.on('tools/pre-execute', async (exec, next): Promise<PreToolDecision> => { if (exec.name === 'echo') return { kind: 'deny', reason: 'denied by policy' } return next() }) + ctx.on('tools/post-execute', async (_exec, result, next) => { + postSawFrozen = Object.isFrozen(result) + expect(Reflect.set(result, 'content', [])).toBe(false) + return next() + }) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'echo', arguments: { text: 'hi' } }) expect(result.isError).toBe(true) expect(result.content[0]).toMatchObject({ text: 'Error: denied by policy' }) + expect(postSawFrozen).toBe(true) }) it('an ask decision degrades to deny when no approval seam is mounted', async () => { @@ -378,7 +682,7 @@ describe('ToolRegistry', () => { it('preserves tool-deferred, execute-wrapper, and post-execute contexts in order', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'composite', description: 'composite', parameters: {}, @@ -422,7 +726,7 @@ describe('ToolRegistry', () => { it('keeps deferred contexts when a composite tool throws, but drops them when the outer call is blocked', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'failing-composite', description: 'failing composite', parameters: {}, @@ -473,7 +777,7 @@ describe('ToolRegistry', () => { it('runs tools/execute after an allowed pre-execute, around dispatch, and before post-execute', async () => { const ctx = await setup() const order: string[] = [] - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'traced', description: 'echo', parameters: { text: { type: 'string' } }, @@ -493,7 +797,7 @@ describe('ToolRegistry', () => { ctx.on('tools/post-execute', async (_exec, _result, next) => { order.push('post'); return next() }) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'traced', arguments: { text: 'hi' } }) - expect(result).toEqual({ content: [{ type: 'text', text: 'hi' }], isError: false }) + expect(result).toEqual({ content: [{ type: 'text', text: 'hi' }], isError: false, value: [{ type: 'text', text: 'hi' }] }) // The around seam wraps dispatch; pre gates before it, post runs over its result. expect(order).toEqual(['pre', 'execute:before', 'dispatch', 'execute:after', 'post']) }) @@ -533,11 +837,35 @@ describe('ToolRegistry', () => { }) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'boom', arguments: {} }) - expect(seen).toEqual({ isError: true, error: { name: 'HarnessError', code: 'BOOM' } }) + expect(seen).toEqual({ + isError: true, + error: { message: 'kaboom', info: { name: 'HarnessError', code: 'BOOM' } }, + }) expect(result.isError).toBe(true) expect(result.content[0]).toMatchObject({ text: 'Error: kaboom' }) }) + it('freezes core dispatch outcomes before around and post listeners can observe them', async () => { + const ctx = await setup() + ctx.tools.register(echoTool) + const mutationAttempts: boolean[] = [] + ctx.on('tools/execute', async (_exec, next) => { + const result = await next() + mutationAttempts.push(Reflect.set(result, 'value', 'around mutation')) + return result + }) + ctx.on('tools/post-execute', async (_exec, result, next) => { + mutationAttempts.push(Reflect.set(result, 'value', 'post mutation')) + return next() + }) + + const result = await ctx.tools.execute({ + callId: CallId('frozen-canonical'), name: 'echo', arguments: { text: 'original' }, + }) + expect(mutationAttempts).toEqual([false, false]) + expect(result.isError ? undefined : result.value).toBe('original') + }) + it('a thrown tool normalized inside tools/execute still reaches post-execute', async () => { const ctx = await setup() ctx.tools.register({ @@ -567,7 +895,7 @@ describe('ToolRegistry', () => { name: 'signal-probe', async execute(_args, exec) { seenSignal = exec.signal - return [{ type: 'text' as const, text: 'ok' }] + return 'ok' }, }) @@ -591,11 +919,11 @@ describe('ToolRegistry', () => { ctx.tools.register({ ...echoTool, name: 'never-runs', - async execute() { dispatched = true; return [] }, + async execute() { dispatched = true; return 'unreachable' }, }) ctx.on('tools/execute', async (_exec: ToolExecution, _next: () => Promise<ToolExecutionResult>): Promise<ToolExecutionResult> => - ({ content: [{ type: 'text', text: 'short-circuited' }], isError: false })) + ({ content: [{ type: 'text', text: 'ignored authored content' }], isError: false, value: 'short-circuited' })) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'never-runs', arguments: {} }) expect(dispatched).toBe(false) // returning without next() skips core dispatch @@ -608,6 +936,7 @@ describe('ToolRegistry', () => { ctx.on('tools/execute', async () => ({ content: [{ type: 'text', text: 'short-circuited with context' }], isError: false, + value: 'short-circuited with context', additionalContexts: [{ content: [{ type: 'text', text: 'from around dispatch' }], source: { kind: 'plugin', plugin: 'test' }, @@ -631,6 +960,7 @@ describe('ToolRegistry', () => { const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'echo', arguments: { text: 'hi' } }) expect(result).toEqual({ content: [{ type: 'text', text: 'Error: wrapper broke' }], + error: { message: 'wrapper broke' }, isError: true, }) }) @@ -646,6 +976,7 @@ describe('ToolRegistry', () => { expect(result).toEqual({ content: [{ type: 'text', text: 'Error: permission hook broke' }], + error: { message: 'permission hook broke' }, isError: true, }) }) @@ -661,6 +992,7 @@ describe('ToolRegistry', () => { expect(result).toEqual({ content: [{ type: 'text', text: 'Error: post hook broke' }], + error: { message: 'post hook broke' }, isError: true, }) }) @@ -676,7 +1008,7 @@ describe('ToolRegistry', () => { expect(result).toMatchObject({ isError: true, - error: { name: 'HarnessError', code: 'DENIED' }, + error: { message: 'denied', info: { name: 'HarnessError', code: 'DENIED' } }, }) }) @@ -839,10 +1171,14 @@ describe('defineTool / schema DSL', () => { text: { type: 'string', required: true }, uppercase: { type: 'boolean' }, }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args) { // args is typed: { text: string; uppercase?: boolean } const result = args.uppercase ? args.text.toUpperCase() : args.text - return [{ type: 'text', text: result }] + return result }, }) @@ -866,6 +1202,7 @@ describe('defineTool / schema DSL', () => { arguments: { text: 'hello', uppercase: true }, }) expect(result.isError).toBe(false) + expect(result.isError ? undefined : result.value).toBe('HELLO') expect(result.content).toEqual([{ type: 'text', text: 'HELLO' }]) }) @@ -876,12 +1213,13 @@ describe('defineTool / schema DSL', () => { name: 'type-check', description: '', parameters: { a: { type: 'string' as const, required: true as const }, b: { type: 'number' as const } }, + output: { schema: { type: 'string' }, render: () => [] }, async execute(args) { // Verify types at runtime via typeof expect(typeof args.a).toBe('string') // args.b should be undefined when not provided void args - return [{ type: 'text', text: args.a }] + return args.a }, }) void tool @@ -896,8 +1234,12 @@ describe('defineTool / schema DSL', () => { req: { type: 'string', required: true }, opt: { type: 'number', description: 'Optional number' }, }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args) { - return [{ type: 'text', text: `${args.req}:${args.opt ?? 'none'}` }] + return `${args.req}:${args.opt ?? 'none'}` }, })) @@ -933,9 +1275,13 @@ describe('defineTool / schema DSL', () => { properties: { path: { type: 'string' } }, required: ['path'], }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value as string }], + }, async execute(args: unknown) { const p = args as { path: string } - return [{ type: 'text', text: p.path }] + return p.path }, }) @@ -1284,7 +1630,7 @@ describe('validateArgs (the runtime-validation Agent Note, part 1)', () => { describe('defineTool validation (the runtime-validation Agent Note, part 1)', () => { it('returns an isError result with the violations when the model sends bad args', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'reader', description: 'reads a path', parameters: { path: { type: 'string', required: true } }, @@ -1302,7 +1648,7 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () it('runs execute normally when args are valid', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'reader', description: 'reads a path', parameters: { path: { type: 'string', required: true } }, @@ -1311,7 +1657,11 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () }, })) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'reader', arguments: { path: '/x' } }) - expect(result).toEqual({ content: [{ type: 'text', text: 'read /x' }], isError: false }) + expect(result).toEqual({ + content: [{ type: 'text', text: 'read /x' }], + isError: false, + value: [{ type: 'text', text: 'read /x' }], + }) }) it('ToolArgsError carries a stable code and the violation list', () => { @@ -1325,7 +1675,7 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () it('a schema-invalid call surfaces the structured error on the result', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'reader', description: 'reads a path', parameters: { path: { type: 'string', required: true } }, @@ -1335,7 +1685,10 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () })) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'reader', arguments: {} }) expect(result.isError).toBe(true) - expect(result.error).toEqual({ name: 'ToolArgsError', code: 'INVALID_ARGS' }) + expect(result.error).toEqual({ + message: 'invalid arguments: missing required property "path"', + info: { name: 'ToolArgsError', code: 'INVALID_ARGS' }, + }) }) it('a tool throwing a HarnessError surfaces its name and code', async () => { @@ -1350,11 +1703,11 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () }) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'coded', arguments: {} }) expect(result.isError).toBe(true) - expect(result.error).toEqual({ name: 'HarnessError', code: 'ENOSPC' }) + expect(result.error).toEqual({ message: 'disk full', info: { name: 'HarnessError', code: 'ENOSPC' } }) expect(result.content[0]).toMatchObject({ text: 'Error: disk full' }) }) - it('a non-HarnessError throw has no structured error (only the text)', async () => { + it('a non-HarnessError throw retains only its message', async () => { const ctx = await setup() ctx.tools.register({ ...echoTool, @@ -1365,7 +1718,7 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () }) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'plain', arguments: {} }) expect(result.isError).toBe(true) - expect(result.error).toBeUndefined() + expect(result.error).toEqual({ message: 'just a message' }) expect(result.content[0]).toMatchObject({ text: 'Error: just a message' }) }) @@ -1376,8 +1729,12 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () name: 'raw', description: 'raw tool', parameters: { type: 'object', properties: { path: { type: 'string' } }, required: ['path'] }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value as string }], + }, async execute(args: unknown) { - return [{ type: 'text', text: typeof args }] + return typeof args }, }) // Missing the "required" path — but raw tools validate their own input, so @@ -1387,7 +1744,7 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () }) it('attaches a positive-finite timeoutMs to the definition', () => { - const tool = defineTool({ + const tool = defineContentToolFixture({ name: 'x', description: 'd', parameters: {}, timeoutMs: 30_000, async execute() { return [{ type: 'text' as const, text: 'ok' }] }, }) @@ -1395,7 +1752,7 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () }) it('omits timeoutMs when not declared', () => { - const tool = defineTool({ + const tool = defineContentToolFixture({ name: 'x', description: 'd', parameters: {}, async execute() { return [{ type: 'text' as const, text: 'ok' }] }, }) @@ -1403,7 +1760,7 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () }) it('throws when timeoutMs is zero or negative', () => { - const make = (ms: number) => defineTool({ + const make = (ms: number) => defineContentToolFixture({ name: 'x', description: 'd', parameters: {}, timeoutMs: ms, async execute() { return [{ type: 'text' as const, text: 'ok' }] }, }) @@ -1412,7 +1769,7 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () }) it('throws when timeoutMs is non-finite', () => { - expect(() => defineTool({ + expect(() => defineContentToolFixture({ name: 'x', description: 'd', parameters: {}, timeoutMs: Infinity, async execute() { return [{ type: 'text' as const, text: 'ok' }] }, })).toThrow('positive finite number') @@ -1421,7 +1778,7 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () describe('defineTool presentation (presentCall / presentResult)', () => { it('threads presentCall/presentResult onto the ToolDefinition with typed args', () => { - const tool = defineTool({ + const tool = defineContentToolFixture({ name: 'demo', description: 'demo', parameters: { path: { type: 'string', required: true }, n: { type: 'number' } }, @@ -1441,7 +1798,7 @@ describe('defineTool presentation (presentCall / presentResult)', () => { }) it('a tool without presentCall/presentResult leaves them undefined (UI falls back generically)', () => { - const tool = defineTool({ + const tool = defineContentToolFixture({ name: 'plain', description: 'plain', parameters: { x: { type: 'string', required: true } }, @@ -1452,7 +1809,7 @@ describe('defineTool presentation (presentCall / presentResult)', () => { }) it('presentCall/presentResult validate softly: malformed args return undefined, never throw (display runs on replay)', () => { - const tool = defineTool({ + const tool = defineContentToolFixture({ name: 'demo', description: 'demo', parameters: { path: { type: 'string', required: true } }, diff --git a/packages/examples/acp-demo/tests/acp-agent.spec.ts b/packages/examples/acp-demo/tests/acp-agent.spec.ts index 52ad60449e..08c3927fe5 100644 --- a/packages/examples/acp-demo/tests/acp-agent.spec.ts +++ b/packages/examples/acp-demo/tests/acp-agent.spec.ts @@ -203,7 +203,8 @@ describe('dsh-acp-demo composition', () => { name, description: name, parameters: {}, - execute: async () => [], + output: { schema: { type: 'null' }, render: () => [] }, + execute: async () => null, }) } const assembly = await ctx.get('systemPrompt')!.assemble() diff --git a/packages/examples/agent-spine-demo/tests/agent-core.spec.ts b/packages/examples/agent-spine-demo/tests/agent-core.spec.ts index c8788ca01b..19c35b5624 100644 --- a/packages/examples/agent-spine-demo/tests/agent-core.spec.ts +++ b/packages/examples/agent-spine-demo/tests/agent-core.spec.ts @@ -494,7 +494,8 @@ describe('dsh-agent-spine-demo bundle', () => { name, description: name, parameters: {}, - execute: async () => [], + output: { schema: { type: 'null' }, render: () => [] }, + execute: async () => null, }) } const assembly = await ctx.get('systemPrompt')!.assemble() diff --git a/packages/examples/cli-demo/tests/cli-demo.spec.ts b/packages/examples/cli-demo/tests/cli-demo.spec.ts index c248242ad1..1433645eb5 100644 --- a/packages/examples/cli-demo/tests/cli-demo.spec.ts +++ b/packages/examples/cli-demo/tests/cli-demo.spec.ts @@ -95,7 +95,13 @@ describe('dsh-cli-demo app composition', () => { }) ctx.skills.register({ name: 'cli-skill', description: 'CLI skill', source: 'runtime', content: 'body' }) for (const name of ['alpha', 'zulu']) { - ctx.tools.register({ name, description: name, parameters: {}, execute: async () => [] }) + ctx.tools.register({ + name, + description: name, + parameters: {}, + output: { schema: { type: 'null' }, render: () => [] }, + execute: async () => null, + }) } expect(JSON.stringify(await composePrefix(ctx))).toContain('- `cli-skill`: CLI...') expect((await ctx.systemPrompt.assemble()).tools.map(tool => tool.name)).toEqual([ diff --git a/packages/examples/cli-demo/tests/cli.spec.ts b/packages/examples/cli-demo/tests/cli.spec.ts index f038efe67e..8de89e63e6 100644 --- a/packages/examples/cli-demo/tests/cli.spec.ts +++ b/packages/examples/cli-demo/tests/cli.spec.ts @@ -115,7 +115,11 @@ async function harness(script: readonly ScriptEntry[]): Promise<Harness> { name: 'echo', description: 'Echo text.', parameters: { text: { type: 'string', required: true } }, - execute: async args => [{ type: 'text', text: `ECHO: ${(args as { text: string }).text}` }], + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value as string }], + }, + execute: async args => `ECHO: ${(args as { text: string }).text}`, }) const [agent] = ctx.agents.roots() if (agent === undefined) throw new Error('test main agent missing') diff --git a/packages/fs/tool-fs-search/README.md b/packages/fs/tool-fs-search/README.md index 7b254fd59e..5d0655bcc9 100644 --- a/packages/fs/tool-fs-search/README.md +++ b/packages/fs/tool-fs-search/README.md @@ -1,6 +1,6 @@ # @deepseek-ai/dsh-tool-fs-search -The **model-facing filesystem discovery tools** — `glob`, `grep` — backed by the **bash executor seam**, not by `ctx.fs` provider methods. At load, the package probes `command -v rg` through `ctx.bash`; if the executor cannot find ripgrep on its `PATH`, it logs a warning and registers no tools or prompt sections. Each call assembles a fixed ripgrep command (every model-controlled value through one package-private shell-quoting helper), runs it via `ctx.bash.resolve(request)` → `ctx.bash.run(spec)` as an ordinary foreground tool call, parses the raw `rg` output, and returns a bounded, workdir-relative result. The package injects `tools`, `systemPrompt`, and `bash` — deliberately **not** `fs`; `ctx.spillStore` is read opportunistically with `ctx.get()` because formatted-result spill is optional. +The **model-facing filesystem discovery tools**—`glob`, `grep`—are backed by the **bash executor seam**, not by `ctx.fs` provider methods. At load, the package probes `command -v rg` through `ctx.bash`; if the executor cannot find ripgrep on its `PATH`, it logs a warning and registers no tools or prompt sections. Each call assembles a fixed ripgrep command (every model-controlled value through one package-private shell-quoting helper), runs it via `ctx.bash.resolve(request)` → `ctx.bash.run(spec)` as an ordinary foreground tool call, parses the raw `rg` output, and returns a workdir-relative canonical value. The package injects `tools`, `systemPrompt`, and `bash`—deliberately **not** `fs`; `ctx.spillStore` is read opportunistically with `ctx.get()` because formatted-result spill is optional. ```ts ignore-check // Default deployment: a bash executor whose PATH includes rg, then the discovery tools. @@ -39,7 +39,7 @@ Routine budgets stay out of the model-facing schema (no `head_limit`/`offset`/`c ## Two budgets, two artifacts -Raw `rg` stdout is an internal transport detail. Each search requests `stdoutMaxBytes: rawOutputMaxBytes` from the bash seam and parses only complete retained stdout; if the executor still returns `stdout.truncated`, the search fails with `SEARCH_RAW_OUTPUT_OVERFLOW` and tells the model to narrow the query. The model-facing recovery artifact is different: when a search yields more logical results than the inline cap, the tool saves the COMPLETE formatted result through `ctx.spillStore.saveText()` (suggested names `glob-results.txt` / `grep-results.txt`, owner = the calling session, source = the tool execution identity) and appends a footer naming the returned locator and retrieval hint. This is the first tool-owned spill call in the codebase — deliberate, because retention here is item-level: the generic `@deepseek-ai/dsh-spill-policy` only sees the final text on `tools/post-execute`, by which point a capped search has already omitted later paths/matches. A missing spill backend, a call with no session owner, or a `saveText()` failure keeps the inline page and reports that the complete result could not be saved — never an `isError`. +Raw `rg` stdout is an internal transport detail. Each search requests `stdoutMaxBytes: rawOutputMaxBytes` from the bash seam and parses only complete retained stdout; if the executor still returns `stdout.truncated`, the search fails with `SEARCH_RAW_OUTPUT_OVERFLOW` and tells the model to narrow the query. A successful `glob` keeps every acquired path in `{ paths }`; `grep` keeps every acquired `{ path, lineNumber, line }` in `{ matches }`. Inline item and per-line preview caps apply only in the Native renderer. For a direct surface call with more logical results than the inline cap, post-policy best-effort saves the complete formatted preview through `ctx.spillStore.saveText()` and replaces only presentation with a head page plus locator. Nested Code dispatches skip that spill because their full canonical value does not enter model context. Missing/failed spill keeps the inline page and reports that the complete result could not be saved—never an `isError`. ## Errors diff --git a/packages/fs/tool-fs-search/src/glob.ts b/packages/fs/tool-fs-search/src/glob.ts index a3e803fb50..6d42acee66 100644 --- a/packages/fs/tool-fs-search/src/glob.ts +++ b/packages/fs/tool-fs-search/src/glob.ts @@ -12,7 +12,6 @@ import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' import type { GenericCallView } from '@deepseek-ai/dsh-tools' -import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { ItemRetainer } from '@deepseek-ai/dsh-retention' import type { RetainedItems } from '@deepseek-ai/dsh-retention' import type { SpillRef } from '@deepseek-ai/dsh-spill' @@ -20,6 +19,7 @@ import type {} from '@deepseek-ai/dsh-bash' import type {} from '@deepseek-ai/dsh-system-prompt' import { runRipgrep, toWorkdirRelative, trySaveFormattedResult } from './search-core.ts' import { singleQuote } from './shell-quote.ts' +import { acceptedSurfaceValue } from './surface.ts' /** * Default cap on paths retained inline by one `glob` call (the `globMaxResults` @@ -117,6 +117,14 @@ export function formatGlobOutput(retained: RetainedItems<string>, spillRef: Spil return `${body}\n\n(Showing ${retained.kept} of ${retained.seen} paths. ${recovery})` } +/** Retain and format one canonical path list for the Native surface. */ +function renderGlobPaths(paths: string[], maxResults: number, spillRef?: SpillRef): string { + if (paths.length === 0) return 'No files found' + const retainer = new ItemRetainer<string>({ kind: 'head', maxItems: maxResults }) + for (const path of paths) retainer.push(path) + return formatGlobOutput(retainer.finish(), spillRef) +} + /** * Pending-call presentation: a search card titled by the pattern (and root). * @@ -142,7 +150,7 @@ export function applyGlobTool(ctx: Context, caps: GlobToolCaps): void { text: 'Use the glob tool — not shell find or ls — to discover files by path pattern. Results are sorted by modification time and include hidden and ignored files.', }) - ctx.tools.register(defineTool({ + const tool = defineTool({ name: 'glob', description: 'Find files whose paths match a glob pattern. Returns matching paths sorted by modification time, ' + 'including hidden and ignored files (VCS metadata directories are excluded). ' @@ -152,28 +160,44 @@ export function applyGlobTool(ctx: Context, caps: GlobToolCaps): void { path: { type: 'string', description: 'Directory to search in. Defaults to the session workspace; a relative path resolves against it.' }, }, timeoutMs: caps.timeoutMs, - async execute(args, exec): Promise<ContentBlock[]> { + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + paths: { type: 'array', required: true, items: { type: 'string' } }, + }, + }, + render: (_args, value) => [{ type: 'text', text: renderGlobPaths(value.paths, caps.maxResults) }], + }, + async execute(args, exec) { const input = parseGlobArgs(args) const run = await runRipgrep(ctx, exec, 'glob', buildGlobCommand(input), caps.rawOutputMaxBytes) - if (run.noMatches) return [{ type: 'text', text: 'No files found' }] + if (run.noMatches) return { paths: [] } - const retainer = new ItemRetainer<string>({ kind: 'head', maxItems: caps.maxResults }) const all: string[] = [] for (const line of run.stdout.split('\n')) { if (line.length === 0) continue const displayPath = toWorkdirRelative(line, run.workdir) all.push(displayPath) - retainer.push(displayPath) } - const retained = retainer.finish() - - // The complete sorted list is the recovery artifact; save it only when - // the inline page omitted paths (an uncapped result needs no spill file). - const spillRef = retained.truncated - ? await trySaveFormattedResult(ctx, exec, 'glob-results.txt', all.join('\n')) - : undefined - return [{ type: 'text', text: formatGlobOutput(retained, spillRef) }] + return { paths: all } }, presentCall: presentGlobCall, - })) + }) + ctx.tools.register(tool) + + ctx.on('tools/post-execute', async (exec, result, next) => { + const decision = await next() + const value = acceptedSurfaceValue(ctx, tool, exec, result, decision) as { paths: string[] } | undefined + if (value === undefined) return decision + const paths = value.paths + if (paths.length <= caps.maxResults) return decision + const spillRef = await trySaveFormattedResult(ctx, exec, 'glob-results.txt', paths.join('\n')) + return { + kind: 'accept', + content: [{ type: 'text', text: renderGlobPaths(paths, caps.maxResults, spillRef) }], + ...decision.additionalContexts !== undefined ? { additionalContexts: decision.additionalContexts } : {}, + } + }) } diff --git a/packages/fs/tool-fs-search/src/grep.ts b/packages/fs/tool-fs-search/src/grep.ts index 3935513b73..aa82749f3f 100644 --- a/packages/fs/tool-fs-search/src/grep.ts +++ b/packages/fs/tool-fs-search/src/grep.ts @@ -13,7 +13,6 @@ import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' import type { GenericCallView } from '@deepseek-ai/dsh-tools' -import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { ItemRetainer, TextRetainer } from '@deepseek-ai/dsh-retention' import type { RetainedItems } from '@deepseek-ai/dsh-retention' import type { SpillRef } from '@deepseek-ai/dsh-spill' @@ -21,6 +20,7 @@ import type {} from '@deepseek-ai/dsh-bash' import type {} from '@deepseek-ai/dsh-system-prompt' import { SearchError, runRipgrep, toWorkdirRelative, trySaveFormattedResult } from './search-core.ts' import { singleQuote } from './shell-quote.ts' +import { acceptedSurfaceValue } from './surface.ts' /** * Default cap on flat matches retained inline by one `grep` call (the @@ -241,6 +241,20 @@ export function formatGrepOutput(retained: RetainedItems<GrepMatch>, spillRef: S return `${header}\n\n${body}\n\n(${recovery})` } +/** Apply the Native per-line preview budget without changing the canonical matches. */ +function previewGrepMatches(matches: GrepMatch[], maxLineBytes: number): GrepMatch[] { + return matches.map(match => ({ ...match, line: previewLine(match.line, maxLineBytes) })) +} + +/** Retain and format one canonical match list for the Native surface. */ +function renderGrepMatches(matches: GrepMatch[], maxMatches: number, maxLineBytes: number, spillRef?: SpillRef): string { + if (matches.length === 0) return 'No matches found' + const previewed = previewGrepMatches(matches, maxLineBytes) + const retainer = new ItemRetainer<GrepMatch>({ kind: 'head', maxItems: maxMatches }) + for (const match of previewed) retainer.push(match) + return formatGrepOutput(retainer.finish(), spillRef) +} + /** * Pending-call presentation: a search card titled by the pattern (and target / * include filter). @@ -268,7 +282,7 @@ export function applyGrepTool(ctx: Context, caps: GrepToolCaps): void { text: 'Use the grep tool — not shell grep or rg — to search file contents. Use read on a matched file when you need surrounding context.', }) - ctx.tools.register(defineTool({ + const tool = defineTool({ name: 'grep', description: 'Search file contents with a ripgrep regular expression. Returns matching lines with line numbers, grouped by file. ' + `Returns the first ${caps.maxMatches} matches inline; a capped result reports where the complete match list was saved. ` @@ -279,37 +293,70 @@ export function applyGrepTool(ctx: Context, caps: GrepToolCaps): void { include: { type: 'string', description: 'One glob filter for which files to search (e.g. "*.ts", "*.{js,jsx}"). Not a list; negation is not supported.' }, }, timeoutMs: caps.timeoutMs, - async execute(args, exec): Promise<ContentBlock[]> { + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + matches: { + type: 'array', + required: true, + items: { + type: 'object', + additionalProperties: false, + properties: { + path: { type: 'string', required: true }, + lineNumber: { type: 'integer', required: true }, + line: { type: 'string', required: true }, + }, + }, + }, + }, + }, + render: (_args, value) => [{ + type: 'text', + text: renderGrepMatches(value.matches, caps.maxMatches, caps.maxLineBytes), + }], + }, + async execute(args, exec) { const input = parseGrepArgs(args) const run = await runRipgrep(ctx, exec, 'grep', buildGrepCommand(input), caps.rawOutputMaxBytes) - if (run.noMatches) return [{ type: 'text', text: 'No matches found' }] + if (run.noMatches) return { matches: [] } - const retainer = new ItemRetainer<GrepMatch>({ kind: 'head', maxItems: caps.maxMatches }) const all: GrepMatch[] = [] for (const raw of parseGrepMatches(run.stdout)) { const match: GrepMatch = { path: toWorkdirRelative(raw.path, run.workdir), lineNumber: raw.lineNumber, - line: previewLine(raw.line, caps.maxLineBytes), + line: raw.line, } all.push(match) - retainer.push(match) } - const retained = retainer.finish() - - // The spill file stores the FULL formatted match list (same grouped, - // per-line-previewed shape the model saw), so read offset/limit pages the - // same logical result; save only when the inline page omitted matches. - const spillRef = retained.truncated - ? await trySaveFormattedResult( - ctx, - exec, - 'grep-results.txt', - `Found ${all.length} ${matchNoun(all.length)}\n\n${formatGrepMatches(all)}`, - ) - : undefined - return [{ type: 'text', text: formatGrepOutput(retained, spillRef) }] + return { matches: all } }, presentCall: presentGrepCall, - })) + }) + ctx.tools.register(tool) + + ctx.on('tools/post-execute', async (exec, result, next) => { + const decision = await next() + const value = acceptedSurfaceValue(ctx, tool, exec, result, decision) as { matches: GrepMatch[] } | undefined + if (value === undefined) return decision + const matches = value.matches + if (matches.length <= caps.maxMatches) return decision + const spillRef = await trySaveFormattedResult( + ctx, + exec, + 'grep-results.txt', + `Found ${matches.length} ${matchNoun(matches.length)}\n\n${formatGrepMatches(previewGrepMatches(matches, caps.maxLineBytes))}`, + ) + return { + kind: 'accept', + content: [{ + type: 'text', + text: renderGrepMatches(matches, caps.maxMatches, caps.maxLineBytes, spillRef), + }], + ...decision.additionalContexts !== undefined ? { additionalContexts: decision.additionalContexts } : {}, + } + }) } diff --git a/packages/fs/tool-fs-search/src/surface.ts b/packages/fs/tool-fs-search/src/surface.ts new file mode 100644 index 0000000000..78bdd6cc42 --- /dev/null +++ b/packages/fs/tool-fs-search/src/surface.ts @@ -0,0 +1,27 @@ +/** Shared surface-only post-policy selection for search result spill. @module dsh-tool-fs-search/surface */ + +import type { Context } from 'cordis' +import type { JsonValue, PostToolDecision, ToolDefinition, ToolExecution, ToolExecutionResult } from '@deepseek-ai/dsh-tools' + +/** + * Return the accepted canonical value only when this tool still owns a direct + * successful surface call and no downstream policy replaced either projection. + * @param ctx - the tool plugin context used to resolve the live scoped owner. + * @param tool - the exact registered definition whose value may be projected. + * @param exec - the completed execution identity. + * @param result - the canonical result before post-policy decisions are applied. + * @param decision - the composed downstream post-policy decision. + * @returns the canonical value to project, or `undefined` when spill must defer. + */ +export function acceptedSurfaceValue( + ctx: Context, + tool: ToolDefinition, + exec: ToolExecution, + result: ToolExecutionResult, + decision: PostToolDecision, +): JsonValue | undefined { + if (decision.kind !== 'accept' || decision.content !== undefined || Object.hasOwn(decision, 'value') + || exec.parent !== undefined || exec.name !== tool.name || result.isError + || ctx.tools.get(exec.name, exec.agent) !== tool) return undefined + return result.value +} diff --git a/packages/fs/tool-fs-search/tests/integration.spec.ts b/packages/fs/tool-fs-search/tests/integration.spec.ts index 36fb2c28e6..31c30d5b15 100644 --- a/packages/fs/tool-fs-search/tests/integration.spec.ts +++ b/packages/fs/tool-fs-search/tests/integration.spec.ts @@ -96,7 +96,7 @@ describe.skipIf(!hasRg)('search tools over the real bash executor + real rg', () it('classifies an invalid glob as SEARCH_INVALID_PATTERN', async () => { const result = await call('glob', { pattern: '[' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ name: 'SearchError', code: 'SEARCH_INVALID_PATTERN' }) + expect(result.error).toMatchObject({ info: { name: 'SearchError', code: 'SEARCH_INVALID_PATTERN' } }) }) }) @@ -139,13 +139,13 @@ describe.skipIf(!hasRg)('search tools over the real bash executor + real rg', () it('classifies a real rg regex error as SEARCH_INVALID_PATTERN', async () => { const result = await call('grep', { pattern: '(unclosed' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'SEARCH_INVALID_PATTERN' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_INVALID_PATTERN' } }) }) it('classifies a missing target as SEARCH_FAILED', async () => { const result = await call('grep', { pattern: 'x', path: 'no-such-dir' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'SEARCH_FAILED' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_FAILED' } }) }) }) @@ -176,14 +176,14 @@ describe.skipIf(!hasRg)('search tools over the real bash executor + real rg', () signal: controller.signal, }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ name: 'SearchError', code: 'SEARCH_ABORTED' }) + expect(result.error).toMatchObject({ info: { name: 'SearchError', code: 'SEARCH_ABORTED' } }) }) it('an unusable session cwd (spawn failure) is SEARCH_FAILED', async () => { const gone = join(dir, 'deleted-session-dir') const result = await call('glob', { pattern: '*' }, { session: { header: { id: 'session-int', cwd: gone } } }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ name: 'SearchError', code: 'SEARCH_FAILED' }) + expect(result.error).toMatchObject({ info: { name: 'SearchError', code: 'SEARCH_FAILED' } }) expect(text(result)).toContain('could not start') }) }) diff --git a/packages/fs/tool-fs-search/tests/tools.spec.ts b/packages/fs/tool-fs-search/tests/tools.spec.ts index c11b10556a..146a0e1166 100644 --- a/packages/fs/tool-fs-search/tests/tools.spec.ts +++ b/packages/fs/tool-fs-search/tests/tools.spec.ts @@ -14,7 +14,7 @@ import { describe, expect, it } from 'vitest' import { Context } from 'cordis' import { CallId } from '@deepseek-ai/dsh-llm' import SystemPrompt, { renderPrompt } from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry from '@deepseek-ai/dsh-tools' +import ToolRegistry, { type ToolExecutionToken } from '@deepseek-ai/dsh-tools' import { BashExecutor } from '@deepseek-ai/dsh-bash' import type { BashExecRequest, BashExecSpec, BashProcess, BashRunResult } from '@deepseek-ai/dsh-bash' import { SpillLocator, SpillStore } from '@deepseek-ai/dsh-spill' @@ -145,13 +145,19 @@ async function expectSetupRejects(options: SetupOptions, message: RegExp): Promi const agent = (cwd?: string) => ({ session: { header: { id: 'session-1', ...cwd !== undefined ? { cwd } : {} } } }) let callCounter = 0 -function call(ctx: Context, name: string, args: unknown, options: { agent?: object; signal?: AbortSignal } = {}) { +function call( + ctx: Context, + name: string, + args: unknown, + options: { agent?: object; signal?: AbortSignal; parent?: ToolExecutionToken } = {}, +) { return ctx.tools.execute({ callId: CallId(`call-${++callCounter}`), name, arguments: args, ...options.agent ? { agent: options.agent as never } : {}, ...options.signal ? { signal: options.signal } : {}, + ...options.parent ? { parent: options.parent } : {}, }) } @@ -310,7 +316,7 @@ describe('workdir derivation and signal forwarding', () => { const result = await call(ctx, 'grep', { pattern: 'x' }, { signal: controller.signal }) expect(bash.specs[0]?.signal).toBe(controller.signal) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ name: 'SearchError', code: 'SEARCH_ABORTED' }) + expect(result.error).toMatchObject({ info: { name: 'SearchError', code: 'SEARCH_ABORTED' } }) expect(text(result)).toContain('aborted') }) @@ -319,7 +325,7 @@ describe('workdir derivation and signal forwarding', () => { bash.handler = () => runResult('', { timedOut: true, timeoutMs: 1234, exitCode: null, signal: 'SIGTERM' }) const result = await call(ctx, 'glob', { pattern: '*' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'SEARCH_ABORTED' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_ABORTED' } }) expect(text(result)).toContain('timed out after 1234ms') }) @@ -332,7 +338,7 @@ describe('workdir derivation and signal forwarding', () => { bash.handler = () => { throw new Error('aborted before spawn') } const result = await call(ctx, 'grep', { pattern: 'x' }, { signal: controller.signal }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ name: 'SearchError', code: 'SEARCH_ABORTED' }) + expect(result.error).toMatchObject({ info: { name: 'SearchError', code: 'SEARCH_ABORTED' } }) }) it('translates a run() rejection without an abort (unusable workdir) into SEARCH_FAILED', async () => { @@ -340,7 +346,7 @@ describe('workdir derivation and signal forwarding', () => { bash.handler = () => { throw new Error('spawn bash ENOENT') } const result = await call(ctx, 'glob', { pattern: '*' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ name: 'SearchError', code: 'SEARCH_FAILED' }) + expect(result.error).toMatchObject({ info: { name: 'SearchError', code: 'SEARCH_FAILED' } }) expect(text(result)).toContain('could not start') }) }) @@ -361,7 +367,7 @@ describe('exit semantics and failure classification', () => { const { ctx, bash } = await setup() bash.handler = () => runResult('', { exitCode: 2, stderr: { text: 'rg: regex parse error:\n (\nerror: unclosed group', truncated: false } }) const result = await call(ctx, 'grep', { pattern: '(' }) - expect(result.error).toMatchObject({ code: 'SEARCH_INVALID_PATTERN' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_INVALID_PATTERN' } }) expect(text(result)).toContain('regex parse error') }) @@ -369,14 +375,14 @@ describe('exit semantics and failure classification', () => { const { ctx, bash } = await setup() bash.handler = () => runResult('', { exitCode: 2, stderr: { text: 'rg: error parsing glob \'[\': unclosed character class', truncated: false } }) const result = await call(ctx, 'glob', { pattern: '[' }) - expect(result.error).toMatchObject({ code: 'SEARCH_INVALID_PATTERN' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_INVALID_PATTERN' } }) }) it('a missing rg binary classifies as SEARCH_FAILED naming ripgrep', async () => { const { ctx, bash } = await setup() bash.handler = () => runResult('', { exitCode: 127, stderr: { text: 'bash: line 1: rg: command not found', truncated: false } }) const result = await call(ctx, 'glob', { pattern: '*' }) - expect(result.error).toMatchObject({ code: 'SEARCH_FAILED' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_FAILED' } }) expect(text(result)).toContain('requires ripgrep (rg)') // The same classification holds from either evidence alone: the 127 exit // with silent stderr, or a shell's command-not-found text on another exit. @@ -390,7 +396,7 @@ describe('exit semantics and failure classification', () => { const { ctx, bash } = await setup() bash.handler = () => runResult('', { exitCode: 2, stderr: { text: 'rg: missing.dir: IO error: no such file or directory', truncated: false } }) const result = await call(ctx, 'grep', { pattern: 'x', path: 'missing.dir' }) - expect(result.error).toMatchObject({ code: 'SEARCH_FAILED' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_FAILED' } }) expect(text(result)).toContain('IO error') }) @@ -398,7 +404,7 @@ describe('exit semantics and failure classification', () => { const { ctx, bash } = await setup() bash.handler = () => runResult('', { exitCode: 3 }) const result = await call(ctx, 'glob', { pattern: '*' }) - expect(result.error).toMatchObject({ code: 'SEARCH_FAILED' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_FAILED' } }) expect(text(result)).toContain('exit 3') }) @@ -416,7 +422,7 @@ describe('exit semantics and failure classification', () => { const { ctx, bash } = await setup() bash.handler = () => runResult('', { exitCode: null, signal: 'SIGKILL' }) const result = await call(ctx, 'grep', { pattern: 'x' }) - expect(result.error).toMatchObject({ code: 'SEARCH_FAILED' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_FAILED' } }) expect(text(result)).toContain('SIGKILL') }) @@ -424,7 +430,7 @@ describe('exit semantics and failure classification', () => { const { ctx, bash } = await setup() bash.handler = () => runResult('', { exitCode: null, signal: null }) const result = await call(ctx, 'glob', { pattern: '*' }) - expect(result.error).toMatchObject({ code: 'SEARCH_FAILED' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_FAILED' } }) }) }) @@ -442,7 +448,7 @@ describe('raw output acquisition', () => { const { ctx, bash } = await setup({ config: { rawOutputMaxBytes: 16 } }) bash.handler = () => runResult('', { stdout: { text: 'x', truncated: true, spillPath: '/does/not/get-read' } }) const result = await call(ctx, 'glob', { pattern: '*' }) - expect(result.error).toMatchObject({ code: 'SEARCH_RAW_OUTPUT_OVERFLOW' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_RAW_OUTPUT_OVERFLOW' } }) expect(text(result)).toContain('narrow pattern, path, or include') }) @@ -453,7 +459,7 @@ describe('raw output acquisition', () => { const { ctx, bash } = await setup({ config: { rawOutputMaxBytes: 16 } }) bash.handler = () => runResult(`${'x'.repeat(64)}\n`) const result = await call(ctx, 'grep', { pattern: 'x' }) - expect(result.error).toMatchObject({ name: 'SearchError', code: 'SEARCH_RAW_OUTPUT_OVERFLOW' }) + expect(result.error).toMatchObject({ info: { name: 'SearchError', code: 'SEARCH_RAW_OUTPUT_OVERFLOW' } }) expect(text(result)).toContain('narrow pattern, path, or include') }) @@ -461,7 +467,7 @@ describe('raw output acquisition', () => { const { ctx, bash } = await setup() bash.handler = () => runResult('', { stdout: { text: 'partial', truncated: true } }) const result = await call(ctx, 'grep', { pattern: 'x' }) - expect(result.error).toMatchObject({ code: 'SEARCH_RAW_OUTPUT_OVERFLOW' }) + expect(result.error).toMatchObject({ info: { code: 'SEARCH_RAW_OUTPUT_OVERFLOW' } }) }) }) @@ -470,6 +476,8 @@ describe('glob results', () => { const { ctx, bash } = await setup() bash.handler = () => runResult('/sessions/s1/src/a.ts\n/elsewhere/b.ts\nrel/c.ts\n') const result = await call(ctx, 'glob', { pattern: '*' }, { agent: agent('/sessions/s1') }) + if (result.isError) throw new Error('expected glob success') + expect(result.value).toEqual({ paths: ['src/a.ts', '/elsewhere/b.ts', 'rel/c.ts'] }) expect(text(result)).toBe('src/a.ts\n/elsewhere/b.ts\nrel/c.ts') }) @@ -489,9 +497,15 @@ describe('glob results', () => { it('caps at globMaxResults and saves the FULL sorted list through spillStore', async () => { const { ctx, bash, spill } = await setup({ config: { globMaxResults: 2 }, spill: true }) + ctx.on('tools/post-execute', async () => ({ + kind: 'accept', + additionalContexts: [{ content: [{ type: 'text', text: 'glob context' }], source: { kind: 'plugin', plugin: 'test' } }], + })) bash.handler = () => runResult('a.ts\nb.ts\nc.ts\nd.ts\n') const result = await call(ctx, 'glob', { pattern: '*.ts' }, { agent: agent('/w') }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected glob success') + expect(result.value).toEqual({ paths: ['a.ts', 'b.ts', 'c.ts', 'd.ts'] }) expect(text(result)).toBe('a.ts\nb.ts\n\n(Showing 2 of 4 paths. Full sorted result stored at: /spill/glob-results.txt. Use the fake retrieval hint.)') expect(spill?.saves).toHaveLength(1) expect(spill?.saves[0]).toMatchObject({ @@ -501,6 +515,7 @@ describe('glob results', () => { content: 'a.ts\nb.ts\nc.ts\nd.ts', }) expect(spill?.saves[0]?.source.callId).toBeDefined() + expect(result.additionalContexts?.[0]?.content).toEqual([{ type: 'text', text: 'glob context' }]) }) it('does not create a spill file when the result fits inline', async () => { @@ -511,6 +526,36 @@ describe('glob results', () => { expect(spill?.saves).toHaveLength(0) }) + it('preserves a downstream canonical value replacement instead of spilling the old value', async () => { + const { ctx, bash, spill } = await setup({ config: { globMaxResults: 1 }, spill: true }) + ctx.on('tools/post-execute', async () => ({ + kind: 'accept' as const, + value: { paths: ['replacement-a.ts', 'replacement-b.ts'] }, + })) + bash.handler = () => runResult('old-a.ts\nold-b.ts\n') + + const result = await call(ctx, 'glob', { pattern: '*.ts' }, { agent: agent('/w') }) + + if (result.isError) throw new Error('expected glob replacement success') + expect(result.value).toEqual({ paths: ['replacement-a.ts', 'replacement-b.ts'] }) + expect(text(result)).toContain('replacement-a.ts') + expect(text(result)).not.toContain('old-a.ts') + expect(spill?.saves).toHaveLength(0) + }) + + it('keeps the full nested Code value without creating a surface spill', async () => { + const { ctx, bash, spill } = await setup({ config: { globMaxResults: 2 }, spill: true }) + bash.handler = () => runResult('a.ts\nb.ts\nc.ts\nd.ts\n') + const result = await call(ctx, 'glob', { pattern: '*.ts' }, { + agent: agent('/w'), + parent: Symbol('run_code') as ToolExecutionToken, + }) + if (result.isError) throw new Error('expected glob success') + expect(result.value).toEqual({ paths: ['a.ts', 'b.ts', 'c.ts', 'd.ts'] }) + expect(text(result)).toBe('a.ts\nb.ts\n\n(Showing 2 of 4 paths. The complete result could not be saved; narrow pattern or path to see more.)') + expect(spill?.saves).toHaveLength(0) + }) + it.each([ ['no spill backend loaded', { fail: false, spill: false, ownerless: false }], ['saveText fails', { fail: true, spill: true, ownerless: false }], @@ -539,6 +584,14 @@ describe('grep results', () => { ].join('\n')) const result = await call(ctx, 'grep', { pattern: 'const' }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected grep success') + expect(result.value).toEqual({ + matches: [ + { path: 'a.ts', lineNumber: 3, line: 'const x = 1' }, + { path: 'a.ts', lineNumber: 9, line: 'const y = 2' }, + { path: 'b.ts', lineNumber: 1, line: 'const z = 3' }, + ], + }) expect(text(result)).toBe('Found 3 matches\n\na.ts\nLine 3: const x = 1\nLine 9: const y = 2\n\nb.ts\nLine 1: const z = 3') }) @@ -561,6 +614,8 @@ describe('grep results', () => { // Use a multibyte straddle instead: 'aé' repeated — cut at 7 bytes: a(1)é(2)a(1)é(2)=6 +a(1)=7 → next é straddles: trimmed. bash.handler = () => runResult(`${matchLine('a.txt', 1, 'aéaéaéaé')}\n`) const result = await call(ctx, 'grep', { pattern: 'a' }) + if (result.isError) throw new Error('expected grep success') + expect(result.value).toEqual({ matches: [{ path: 'a.txt', lineNumber: 1, line: 'aéaéaéaé' }] }) expect(text(result)).toContain('Line 1: aéaéa (line truncated)') }) @@ -578,6 +633,10 @@ describe('grep results', () => { it('caps at grepMaxMatches and spills the full formatted match list', async () => { const { ctx, bash, spill } = await setup({ config: { grepMaxMatches: 2 }, spill: true }) + ctx.on('tools/post-execute', async () => ({ + kind: 'accept', + additionalContexts: [{ content: [{ type: 'text', text: 'grep context' }], source: { kind: 'plugin', plugin: 'test' } }], + })) bash.handler = () => runResult([ matchLine('a.ts', 1, 'one'), matchLine('a.ts', 2, 'two'), @@ -585,12 +644,66 @@ describe('grep results', () => { '', ].join('\n')) const result = await call(ctx, 'grep', { pattern: 'e' }, { agent: agent('/w') }) + if (result.isError) throw new Error('expected grep success') + expect(result.value).toEqual({ + matches: [ + { path: 'a.ts', lineNumber: 1, line: 'one' }, + { path: 'a.ts', lineNumber: 2, line: 'two' }, + { path: 'b.ts', lineNumber: 3, line: 'three' }, + ], + }) expect(text(result)).toBe('Found 2 of 3 matches\n\na.ts\nLine 1: one\nLine 2: two\n\n(Full grep result stored at: /spill/grep-results.txt. Use the fake retrieval hint.)') expect(spill?.saves[0]).toMatchObject({ source: { toolName: 'grep', label: 'result' }, suggestedName: 'grep-results.txt', content: 'Found 3 matches\n\na.ts\nLine 1: one\nLine 2: two\n\nb.ts\nLine 3: three', }) + expect(result.additionalContexts?.[0]?.content).toEqual([{ type: 'text', text: 'grep context' }]) + }) + + it('preserves a downstream canonical value replacement instead of spilling the old matches', async () => { + const { ctx, bash, spill } = await setup({ config: { grepMaxMatches: 1 }, spill: true }) + ctx.on('tools/post-execute', async () => ({ + kind: 'accept' as const, + value: { + matches: [ + { path: 'replacement.ts', lineNumber: 7, line: 'first' }, + { path: 'replacement.ts', lineNumber: 8, line: 'second' }, + ], + }, + })) + bash.handler = () => runResult(`${matchLine('old.ts', 1, 'old')}\n`) + + const result = await call(ctx, 'grep', { pattern: 'old' }, { agent: agent('/w') }) + + if (result.isError) throw new Error('expected grep replacement success') + expect(result.value).toEqual({ + matches: [ + { path: 'replacement.ts', lineNumber: 7, line: 'first' }, + { path: 'replacement.ts', lineNumber: 8, line: 'second' }, + ], + }) + expect(text(result)).toContain('replacement.ts') + expect(text(result)).not.toContain('old.ts') + expect(spill?.saves).toHaveLength(0) + }) + + it('keeps every nested Code match in the value without creating a surface spill', async () => { + const { ctx, bash, spill } = await setup({ config: { grepMaxMatches: 1 }, spill: true }) + bash.handler = () => runResult(`${matchLine('a.ts', 1, 'one')}\n${matchLine('b.ts', 2, 'two')}\n`) + const result = await call(ctx, 'grep', { pattern: 'o' }, { + agent: agent('/w'), + parent: Symbol('run_code') as ToolExecutionToken, + }) + if (result.isError) throw new Error('expected grep success') + expect(result.value).toEqual({ + matches: [ + { path: 'a.ts', lineNumber: 1, line: 'one' }, + { path: 'b.ts', lineNumber: 2, line: 'two' }, + ], + }) + expect(text(result)).toBe('Found 1 of 2 matches\n\na.ts\nLine 1: one\n\n(The complete result could not be saved; narrow pattern, path, or include to see more.)') + expect(spill?.saves).toHaveLength(0) }) it('reports the unsaved remainder when capped with no spill backend', async () => { @@ -633,7 +746,7 @@ describe('rg --json transport failures (SEARCH_FAILED)', () => { bash.handler = () => runResult(`${line}\n`) const result = await call(ctx, 'grep', { pattern: 'x' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ name: 'SearchError', code: 'SEARCH_FAILED' }) + expect(result.error).toMatchObject({ info: { name: 'SearchError', code: 'SEARCH_FAILED' } }) }) }) diff --git a/packages/fs/tool-fs/README.md b/packages/fs/tool-fs/README.md index 6dd22d384f..a99316c181 100644 --- a/packages/fs/tool-fs/README.md +++ b/packages/fs/tool-fs/README.md @@ -32,6 +32,8 @@ All keys are optional; the defaults are the shipped read caps. Field names are snake_case to match Claude Code and existing harness tool schemas. +Canonical successes are `read` → `{ path, offset, lines: [{ number, text }], totalLines }`, `write` → `{ path, operation: 'create' | 'update', before: string | null, after }`, and `edit` → `{ path, before, after }`. Native renderers preserve the line-numbered read and mutation acknowledgements below. Write/edit derive replayable diff-card metadata from these values; the values themselves are execution-local and are not added to `tool/result`. + ## The tool is the executor; policy is an event gate The tools do **not** inject a policy service or inspect any cache. Each tool resolves the path via `ctx.fs.resolve(path, { cwd, signal })` — passing the calling agent's session cwd (`exec.agent.session.header.cwd`) so a relative path resolves against the session's workspace, matching `dsh-tool-bash`, and forwarding tool cancellation through resolution (see [the per-session cwd Agent Note](../../../.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.md)) — then: diff --git a/packages/fs/tool-fs/src/edit.ts b/packages/fs/tool-fs/src/edit.ts index 46655f80b7..e2895c5cf4 100644 --- a/packages/fs/tool-fs/src/edit.ts +++ b/packages/fs/tool-fs/src/edit.ts @@ -8,10 +8,9 @@ import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' import type { DiffCallView, DiffResultView, ToolResult } from '@deepseek-ai/dsh-tools' -import type { ContentBlock } from '@deepseek-ai/dsh-llm' import type {} from '@deepseek-ai/dsh-fs' import type {} from '@deepseek-ai/dsh-system-prompt' -import { computeHunkDiffs, diffsFromMeta, type FsDiffMeta } from './diff.ts' +import { computeHunkDiffs, diffsFromMeta } from './diff.ts' import { sessionResolveOptions } from './session-cwd.ts' import type { FsSandboxSurface } from './sandbox.ts' @@ -90,7 +89,26 @@ export function applyEditTool(ctx: Context, sandbox: FsSandboxSurface): void { replace_all: { type: 'boolean', description: 'Replace all matches. Defaults to false; when false, old_string must appear exactly once.' }, ...sandbox.escalationModes.length > 0 ? sandbox.schemaFields() : {}, }, - async execute(args: EditToolArgs, exec): Promise<{ content: ContentBlock[]; meta?: FsDiffMeta }> { + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + path: { type: 'string', required: true }, + before: { type: 'string', required: true }, + after: { type: 'string', required: true }, + }, + }, + render: (args, value) => [{ + type: 'text', + text: formatEditOutput(value.path, args.replace_all ?? false), + }], + presentationMeta: (args, value) => ({ + diffs: computeHunkDiffs(args.file_path, value.before, value.after) + .map(({ path, oldText, newText }) => ({ path, oldText, newText })), + }), + }, + async execute(args: EditToolArgs, exec) { const input = parseEditArgs(args) // Resolve the per-call sandbox mode (escalation grant > session override // > backend default) BEFORE anything executes. @@ -115,11 +133,10 @@ export function applyEditTool(ctx: Context, sandbox: FsSandboxSurface): void { } // Record the observed version (a no-op when no policy plugin listens). ctx.emit('fs/observed', target, outcome.version, exec) - // An edit necessarily changes content, so result metadata carries at least one applied hunk. - const diffs = computeHunkDiffs(input.filePath, outcome.before, outcome.after) return { - content: [{ type: 'text', text: formatEditOutput(target.displayPath, input.replaceAll) }], - meta: { diffs }, + path: target.displayPath, + before: outcome.before, + after: outcome.after, } }, // Pure display: a diff card of the literal replacement (old_string → new_string), derived diff --git a/packages/fs/tool-fs/src/read-render.ts b/packages/fs/tool-fs/src/read-render.ts index 943ff98f61..de9e530a13 100644 --- a/packages/fs/tool-fs/src/read-render.ts +++ b/packages/fs/tool-fs/src/read-render.ts @@ -77,6 +77,7 @@ function lineByteSize(line: string, currentLineCount: number): number { function consumeLine(acc: WindowAccumulator, rawLine: string, request: ReadWindow): void { acc.totalLines += 1 + if (acc.done) return if (acc.totalLines < request.offset || acc.lines.length >= request.limit) return const text = truncateLine(rawLine, request.maxLineLength) @@ -137,7 +138,6 @@ export async function buildWindow( appendToLineBuffer(chunk.slice(startPos, newlinePos)) flushLine() startPos = newlinePos + 1 - if (acc.done) return finish(acc, request, displayPath) } appendToLineBuffer(chunk.slice(startPos)) } diff --git a/packages/fs/tool-fs/src/read.ts b/packages/fs/tool-fs/src/read.ts index a19b073514..ea709f1172 100644 --- a/packages/fs/tool-fs/src/read.ts +++ b/packages/fs/tool-fs/src/read.ts @@ -7,12 +7,10 @@ import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' import type { GenericCallView } from '@deepseek-ai/dsh-tools' -import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { FsError } from '@deepseek-ai/dsh-fs' import type {} from '@deepseek-ai/dsh-fs' import type {} from '@deepseek-ai/dsh-system-prompt' import { buildWindow, formatReadOutput } from './read-render.ts' -import type { FileReadOutcome } from './read-render.ts' import { sessionResolveOptions } from './session-cwd.ts' /** Default and maximum number of lines returned by one `read` call (the `readLimit` config). */ @@ -84,9 +82,46 @@ export function applyReadTool(ctx: Context, caps: ReadToolCaps): void { offset: { type: 'number', description: '1-based first line to return. Defaults to 1.' }, limit: { type: 'number', description: `Maximum number of lines to return. Defaults to ${caps.limit}.` }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + path: { type: 'string', required: true }, + offset: { type: 'integer', required: true }, + lines: { + type: 'array', + required: true, + items: { + type: 'object', + additionalProperties: false, + properties: { + number: { type: 'integer', required: true }, + text: { type: 'string', required: true }, + }, + }, + }, + totalLines: { type: 'integer', required: true }, + }, + }, + render: (args, value) => { + const input = parseReadArgs(args, caps.limit) + const endLine = value.lines.at(-1)?.number ?? Math.max(0, value.offset - 1) + const truncatedByBytes = value.lines.length < input.limit && endLine < value.totalLines + return [{ + type: 'text', + text: formatReadOutput(value.path, { + offset: value.offset, + lines: value.lines, + totalLines: value.totalLines, + ...truncatedByBytes ? { truncatedByBytes: true } : {}, + }), + }] + }, + }, // Observation races fail closed because guarded mutations re-check the version in-lock. isConcurrencySafe: () => true, - async execute(args, exec): Promise<ContentBlock[]> { + async execute(args, exec) { const input = parseReadArgs(args, caps.limit) const target = await ctx.fs.resolve(input.filePath, sessionResolveOptions(exec)) @@ -107,17 +142,17 @@ export function applyReadTool(ctx: Context, caps: ReadToolCaps): void { target.displayPath, ) - const outcome: FileReadOutcome = { + const outcome = { + path: target.displayPath, offset: input.offset, lines: window.lines, totalLines: window.totalLines, - ...window.truncatedByBytes ? { truncatedByBytes: true } : {}, } // Record the observed version (a no-op when no policy plugin listens). The // read already succeeded; an fs/observed listener is contractually a // synchronous, side-effect-only recorder. ctx.emit('fs/observed', target, info.version, exec) - return [{ type: 'text', text: formatReadOutput(target.displayPath, outcome) }] + return outcome }, // Pure display: a generic card titled by the file with the read window appended (`Read // foo.txt (5 - 8)`), `read` kind (icon), and a follow-along location whose line is the diff --git a/packages/fs/tool-fs/src/write.ts b/packages/fs/tool-fs/src/write.ts index 3f23e9b5ea..b541c1c2e0 100644 --- a/packages/fs/tool-fs/src/write.ts +++ b/packages/fs/tool-fs/src/write.ts @@ -8,11 +8,10 @@ import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' import type { DiffCallView, DiffResultView, ToolResult } from '@deepseek-ai/dsh-tools' -import type { ContentBlock } from '@deepseek-ai/dsh-llm' import type { FsWriteOutcome } from '@deepseek-ai/dsh-fs' import type {} from '@deepseek-ai/dsh-fs' import type {} from '@deepseek-ai/dsh-system-prompt' -import { computeHunkDiffs, diffsFromMeta, type FsDiffMeta } from './diff.ts' +import { computeHunkDiffs, diffsFromMeta } from './diff.ts' import { sessionResolveOptions } from './session-cwd.ts' import type { FsSandboxSurface } from './sandbox.ts' @@ -33,7 +32,7 @@ export function parseWriteArgs(args: { file_path: string; content: string }): { * @param outcome - the write outcome; its `operation` selects the Created/Updated wording. * @returns the model-facing confirmation envelope (no file content is echoed back). */ -export function formatWriteOutput(displayPath: string, outcome: FsWriteOutcome): string { +export function formatWriteOutput(displayPath: string, outcome: Pick<FsWriteOutcome, 'operation'>): string { const verb = outcome.operation === 'create' ? 'Created' : 'Updated' return `<path>${displayPath}</path> <type>file</type> @@ -74,7 +73,32 @@ export function applyWriteTool(ctx: Context, sandbox: FsSandboxSurface): void { content: { type: 'string', required: true, description: 'Full UTF-8 text content to write.' }, ...sandbox.escalationModes.length > 0 ? sandbox.schemaFields() : {}, }, - async execute(args: WriteToolArgs, exec): Promise<{ content: ContentBlock[]; meta?: FsDiffMeta }> { + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + path: { type: 'string', required: true }, + operation: { type: 'string', required: true, enum: ['create', 'update'] }, + before: { + required: true, + oneOf: [ + { type: 'string' }, + { type: 'null' }, + ], + }, + after: { type: 'string', required: true }, + }, + }, + render: (_args, value) => [{ type: 'text', text: formatWriteOutput(value.path, value) }], + presentationMeta: (args, value) => ({ + diffs: value.before === null + ? [] + : computeHunkDiffs(args.file_path, value.before, value.after) + .map(({ path, oldText, newText }) => ({ path, oldText, newText })), + }), + }, + async execute(args: WriteToolArgs, exec) { const input = parseWriteArgs(args) // Resolve the per-call sandbox mode (escalation grant > session override // > backend default) BEFORE anything executes; an escalating call @@ -94,12 +118,11 @@ export function applyWriteTool(ctx: Context, sandbox: FsSandboxSurface): void { } // Record the observed version (a no-op when no policy plugin listens). ctx.emit('fs/observed', target, outcome.version, exec) - // Overwrites carry applied hunks. Creates have no prior text, so result presentation uses - // the args-derived whole-file diff instead. - const diffs = outcome.before !== null ? computeHunkDiffs(input.filePath, outcome.before, outcome.after) : [] return { - content: [{ type: 'text', text: formatWriteOutput(target.displayPath, outcome) }], - ...diffs.length > 0 ? { meta: { diffs } } : {}, + path: target.displayPath, + operation: outcome.operation, + before: outcome.before, + after: outcome.after, } }, // Pure display: a diff card (an editor renders write as a new-file / full- replace diff). diff --git a/packages/fs/tool-fs/tests/integration.spec.ts b/packages/fs/tool-fs/tests/integration.spec.ts index 6a9e6f3568..05056cada2 100644 --- a/packages/fs/tool-fs/tests/integration.spec.ts +++ b/packages/fs/tool-fs/tests/integration.spec.ts @@ -67,7 +67,7 @@ describe('default deployment (with dsh-fs-policy)', () => { await writeFile(join(dir, 'a.txt'), 'original') const result = await call('write', { file_path: 'a.txt', content: 'clobber' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_NOT_OBSERVED' }) + expect(result.error).toMatchObject({ info: { code: 'FS_NOT_OBSERVED' } }) expect(await readFile(join(dir, 'a.txt'), 'utf8')).toBe('original') }) @@ -85,7 +85,7 @@ describe('default deployment (with dsh-fs-policy)', () => { await writeFile(join(dir, 'a.txt'), 'changed-externally') // out-of-band change const result = await call('write', { file_path: 'a.txt', content: 'replaced' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_STALE_VERSION' }) + expect(result.error).toMatchObject({ info: { code: 'FS_STALE_VERSION' } }) }) }) @@ -102,7 +102,7 @@ describe('default deployment (with dsh-fs-policy)', () => { await writeFile(join(dir, 'bin'), Buffer.from([0x00, 0x01, 0x02])) const result = await call('read', { file_path: 'bin' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_NOT_TEXT' }) + expect(result.error).toMatchObject({ info: { code: 'FS_NOT_TEXT' } }) }) it('paginates a multi-line file with offset/limit', async () => { @@ -127,7 +127,7 @@ describe('default deployment (with dsh-fs-policy)', () => { await writeFile(join(dir, 'a.txt'), 'hello world') const result = await call('edit', { file_path: 'a.txt', old_string: 'world', new_string: 'there' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_NOT_OBSERVED' }) + expect(result.error).toMatchObject({ info: { code: 'FS_NOT_OBSERVED' } }) expect(await readFile(join(dir, 'a.txt'), 'utf8')).toBe('hello world') }) @@ -151,7 +151,7 @@ describe('default deployment (with dsh-fs-policy)', () => { await writeFile(join(dir, 'a.txt'), 'goodbye') // out-of-band change removes 'world' const result = await call('edit', { file_path: 'a.txt', old_string: 'world', new_string: 'there' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_STALE_VERSION' }) + expect(result.error).toMatchObject({ info: { code: 'FS_STALE_VERSION' } }) }) it('rejects an ambiguous match without replace_all', async () => { @@ -159,7 +159,7 @@ describe('default deployment (with dsh-fs-policy)', () => { await call('read', { file_path: 'a.txt' }) const result = await call('edit', { file_path: 'a.txt', old_string: 'a', new_string: 'b' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_AMBIGUOUS_EDIT' }) + expect(result.error).toMatchObject({ info: { code: 'FS_AMBIGUOUS_EDIT' } }) expect(await readFile(join(dir, 'a.txt'), 'utf8')).toBe('a a a') }) @@ -187,7 +187,7 @@ describe('default deployment (with dsh-fs-policy)', () => { // The model-facing edit still rejects: the read did not emit fs/observed. const result = await call('edit', { file_path: 'a.txt', old_string: 'world', new_string: 'there' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_NOT_OBSERVED' }) + expect(result.error).toMatchObject({ info: { code: 'FS_NOT_OBSERVED' } }) }) }) @@ -260,14 +260,14 @@ describe('bare provider (no dsh-fs-policy)', () => { it('edit of a MISSING target reports FS_STALE_VERSION even on the unguarded path', async () => { const result = await call('edit', { file_path: 'missing.txt', old_string: 'a', new_string: 'b' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_STALE_VERSION' }) + expect(result.error).toMatchObject({ info: { code: 'FS_STALE_VERSION' } }) }) it('edit still enforces literal-match codes (FS_EDIT_NOT_FOUND), unrelated to freshness', async () => { await writeFile(join(dir, 'a.txt'), 'hello world') const result = await call('edit', { file_path: 'a.txt', old_string: 'absent', new_string: 'x' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_EDIT_NOT_FOUND' }) + expect(result.error).toMatchObject({ info: { code: 'FS_EDIT_NOT_FOUND' } }) }) it('neither write nor edit stats in the tool on the bare path', async () => { @@ -350,11 +350,11 @@ describe('signal, concurrency, and the fs/observed contract', () => { await writeFile(join(dir, 'a.txt'), 'hello') const read = await callSig(AbortSignal.abort(), 'read', { file_path: 'a.txt' }) expect(read.isError).toBe(true) - expect(read.error).toMatchObject({ code: 'FS_ABORTED' }) + expect(read.error).toMatchObject({ info: { code: 'FS_ABORTED' } }) const write = await callSig(AbortSignal.abort(), 'write', { file_path: 'new.txt', content: 'x' }) expect(write.isError).toBe(true) - expect(write.error).toMatchObject({ code: 'FS_ABORTED' }) + expect(write.error).toMatchObject({ info: { code: 'FS_ABORTED' } }) await expect(readFile(join(dir, 'new.txt'), 'utf8')).rejects.toMatchObject({ code: 'ENOENT' }) // Read first (un-aborted, SAME session owner) so the edit clears the @@ -363,7 +363,7 @@ describe('signal, concurrency, and the fs/observed contract', () => { expect((await callOwned('read', { file_path: 'a.txt' })).isError).toBe(false) const edit = await callSig(AbortSignal.abort(), 'edit', { file_path: 'a.txt', old_string: 'hello', new_string: 'bye' }) expect(edit.isError).toBe(true) - expect(edit.error).toMatchObject({ code: 'FS_ABORTED' }) + expect(edit.error).toMatchObject({ info: { code: 'FS_ABORTED' } }) expect(await readFile(join(dir, 'a.txt'), 'utf8')).toBe('hello') // unchanged }) @@ -378,7 +378,7 @@ describe('signal, concurrency, and the fs/observed contract', () => { ]) const errors = [one, two].filter(r => r.isError) expect(errors).toHaveLength(1) - expect(errors[0]?.error).toMatchObject({ code: 'FS_STALE_VERSION' }) + expect(errors[0]?.error).toMatchObject({ info: { code: 'FS_STALE_VERSION' } }) // The world is consistent: exactly one edit landed. const onDisk = await readFile(join(dir, 'a.txt'), 'utf8') expect(onDisk === 'ONE value here' || onDisk === 'base TWO here').toBe(true) @@ -407,7 +407,7 @@ describe('signal, concurrency, and the fs/observed contract', () => { new_string: 'edited', }) expect(edit.isError).toBe(true) - expect(edit.error).toMatchObject({ code: 'FS_STALE_VERSION' }) + expect(edit.error).toMatchObject({ info: { code: 'FS_STALE_VERSION' } }) expect(await readFile(join(dir, 'a.txt'), 'utf8')).toBe('newer current content\n') }) diff --git a/packages/fs/tool-fs/tests/tools.spec.ts b/packages/fs/tool-fs/tests/tools.spec.ts index 4d80061584..b94bcb9486 100644 --- a/packages/fs/tool-fs/tests/tools.spec.ts +++ b/packages/fs/tool-fs/tests/tools.spec.ts @@ -161,6 +161,13 @@ describe('read tool', () => { fs.files.set('key:a.txt', 'hello\nworld') const result = await call(ctx, 'read', { file_path: 'a.txt' }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected read success') + expect(result.value).toEqual({ + path: '/abs/a.txt', + offset: 1, + lines: [{ number: 1, text: 'hello' }, { number: 2, text: 'world' }], + totalLines: 2, + }) expect(text(result)).toBe(`<path>/abs/a.txt</path> <type>file</type> <content> @@ -171,6 +178,15 @@ describe('read tool', () => { </content>`) }) + it('returns an explicit empty canonical line window for an empty file', async () => { + const { ctx, fs } = await setup() + fs.files.set('key:empty.txt', '') + const result = await call(ctx, 'read', { file_path: 'empty.txt' }) + if (result.isError) throw new Error('expected empty read success') + expect(result.value).toEqual({ path: '/abs/empty.txt', offset: 1, lines: [], totalLines: 0 }) + expect(text(result)).toContain('(End of file - total 0 lines)') + }) + it('rejects a non-positive offset via arg validation', async () => { const { ctx } = await setup() const result = await call(ctx, 'read', { file_path: 'a.txt', offset: 0 }) @@ -226,7 +242,7 @@ describe('read tool', () => { const { ctx } = await setup() const result = await call(ctx, 'read', { file_path: 'missing.txt' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_NOT_FOUND' }) + expect(result.error).toMatchObject({ info: { code: 'FS_NOT_FOUND' } }) }) it('rejects a non-regular target', async () => { @@ -235,7 +251,7 @@ describe('read tool', () => { fs.stat = async () => ({ version: FsVersion('v1'), type: 'directory' }) const result = await call(ctx, 'read', { file_path: 'd' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_NOT_REGULAR_FILE' }) + expect(result.error).toMatchObject({ info: { code: 'FS_NOT_REGULAR_FILE' } }) }) it('streams a large file (size at/above the cap) instead of reading whole', async () => { @@ -301,6 +317,8 @@ describe('write tool', () => { const { ctx, fs } = await setup() const result = await call(ctx, 'write', { file_path: 'a.txt', content: 'hi' }, { session: { header: {} } }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected write success') + expect(result.value).toEqual({ path: '/abs/a.txt', operation: 'create', before: null, after: 'hi' }) expect(text(result)).toContain('Created file') expect(fs.writeIntents).toEqual([{ kind: 'createIfAbsent' }]) }) @@ -317,7 +335,7 @@ describe('write tool', () => { fs.rejectWith = new FsError('blocked', 'FS_STALE_VERSION') const result = await call(ctx, 'write', { file_path: 'a.txt', content: 'hi' }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ name: 'FsError', code: 'FS_STALE_VERSION' }) + expect(result.error).toMatchObject({ info: { name: 'FsError', code: 'FS_STALE_VERSION' } }) }) }) @@ -328,6 +346,8 @@ describe('edit tool', () => { fs.files.set('key:a.txt', 'a') await call(ctx, 'read', { file_path: 'a.txt' }, { session }) const result = await call(ctx, 'edit', { file_path: 'a.txt', old_string: 'a', new_string: 'b' }, { session }) + if (result.isError) throw new Error('expected edit success') + expect(result.value).toEqual({ path: '/abs/a.txt', before: 'a', after: 'b' }) expect(text(result)).toBe('The file /abs/a.txt has been updated successfully.') }) @@ -366,7 +386,7 @@ describe('edit tool', () => { fs.files.set('key:a.txt', 'hello') const result = await call(ctx, 'edit', { file_path: 'a.txt', old_string: 'a', new_string: 'b' }, { session: { header: {} } }) expect(result.isError).toBe(true) - expect(result.error).toMatchObject({ code: 'FS_NOT_OBSERVED' }) + expect(result.error).toMatchObject({ info: { code: 'FS_NOT_OBSERVED' } }) }) }) @@ -464,27 +484,27 @@ describe('result-time contextual diff (meta + presentResult)', () => { expect(view).toEqual({ card: 'diff', title: 'Write a.txt', diffs: [{ path: 'a.txt', oldText: 'a\nb\nc\nOLD\nd\ne\nf', newText: 'a\nb\nc\nNEW\nd\ne\nf' }] }) }) - it('write CREATE: no before-version → no meta, but presentResult still renders a whole-file diff card', async () => { - // A create has no prior content (no `meta`), yet the completed card must be a `diff` — an + it('write CREATE: an empty applied-diff projection still falls back to the whole-file diff card', async () => { + // A create has no prior content, yet the completed card must be a `diff` — an // ACP tool_call_update.content REPLACES the call's content, so a non-diff result would // clobber the pending new-file diff. const { ctx } = await setup() const session = { header: {} } const result = await call(ctx, 'write', { file_path: 'new.txt', content: 'fresh\n' }, { session }) expect(result.isError).toBe(false) - expect(result.meta).toBeUndefined() + expect(result.meta).toEqual({ diffs: [] }) const view = ctx.tools.get('write')?.presentResult?.({ file_path: 'new.txt', content: 'fresh\n' }, result) expect(view).toEqual({ card: 'diff', title: 'Write new.txt', diffs: [{ path: 'new.txt', oldText: null, newText: 'fresh\n' }] }) }) - it('write OVERWRITE with identical content: a before exists but yields no hunk → no meta, presentResult falls back to a whole-file diff', async () => { + it('write OVERWRITE with identical content: an empty applied-diff projection falls back to a whole-file diff', async () => { const { ctx, fs } = await setup() const session = { header: {} } fs.files.set('key:a.txt', 'same\n') await call(ctx, 'read', { file_path: 'a.txt' }, { session }) const result = await call(ctx, 'write', { file_path: 'a.txt', content: 'same\n' }, { session }) expect(result.isError).toBe(false) - expect(result.meta).toBeUndefined() + expect(result.meta).toEqual({ diffs: [] }) const view = ctx.tools.get('write')?.presentResult?.({ file_path: 'a.txt', content: 'same\n' }, result) expect(view).toEqual({ card: 'diff', title: 'Write a.txt', diffs: [{ path: 'a.txt', oldText: null, newText: 'same\n' }] }) }) diff --git a/packages/goal/tool-goal/README.md b/packages/goal/tool-goal/README.md index 6b900e2a05..3f286f8ec3 100644 --- a/packages/goal/tool-goal/README.md +++ b/packages/goal/tool-goal/README.md @@ -10,6 +10,8 @@ The model-facing control surface for [`ctx.goals`](../goal/README.md): `get_goal All calls are exclusive, so a model-ordered batch observes earlier mutations and their new revisions. ACP and other clients receive pure generic cards: read for `get_goal`, other for mutations. +All three canonical values match the compact JSON already rendered to Native callers: `{ goal: null }` or `{ goal: { id, revision, objective, phase, roundsStarted, maxGoalRounds, blockedReason? }, activation }`. Programmatic consumers therefore receive the same domain structure without parsing the rendered JSON. + An autonomous goal round that successfully reports `complete` or `blocked` contributes the existing terminal `agent/turn-stop` decision for that physical turn. Direct-human mutations never contribute this stop: the assistant may acknowledge the change and concurrent human steering remains available to the loop. ## Authority diff --git a/packages/goal/tool-goal/src/index.ts b/packages/goal/tool-goal/src/index.ts index 075264f93e..009a00376f 100644 --- a/packages/goal/tool-goal/src/index.ts +++ b/packages/goal/tool-goal/src/index.ts @@ -54,6 +54,62 @@ const GET_DESCRIPTION = + 'continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. ' + 'Call this before updating a goal.' +/** Canonical goal-tool output, matching the existing compact Native JSON. */ +type GoalToolValue = + | { goal: null } + | { + goal: { + id: string + revision: number + objective: string + phase: GoalView['phase'] + roundsStarted: number + maxGoalRounds: number + blockedReason?: { code: string; message: string } + } + activation: GoalView['activation'] + } + +const GOAL_VALUE_SCHEMA = { + oneOf: [ + { + type: 'object', + additionalProperties: false, + properties: { + goal: { type: 'null', required: true }, + }, + }, + { + type: 'object', + additionalProperties: false, + properties: { + goal: { + type: 'object', + additionalProperties: false, + required: true, + properties: { + id: { type: 'string', required: true }, + revision: { type: 'integer', required: true }, + objective: { type: 'string', required: true }, + phase: { type: 'string', required: true, enum: ['active', 'paused', 'blocked', 'complete'] }, + roundsStarted: { type: 'integer', required: true }, + maxGoalRounds: { type: 'integer', required: true }, + blockedReason: { + type: 'object', + additionalProperties: false, + properties: { + code: { type: 'string', required: true }, + message: { type: 'string', required: true }, + }, + }, + }, + }, + activation: { type: 'string', required: true, enum: ['armed', 'disarmed'] }, + }, + }, + ], +} as const + /** Render policy guidance with its deployment-selected blocked threshold. */ function guidance(blockedAfter: number): string { return 'Use goal tools for one long-running completion objective in the current session. ' @@ -89,9 +145,9 @@ function goalRef(goalId: string, revision: number): GoalRef { } /** Stable compact model result; activation is an observation, not replay state. */ -function renderGoal(goal: GoalView | undefined): string { - if (goal === undefined) return JSON.stringify({ goal: null }) - return JSON.stringify({ +function goalValue(goal: GoalView | undefined): GoalToolValue { + if (goal === undefined) return { goal: null } + return { goal: { id: goal.id, revision: goal.revision, @@ -99,10 +155,18 @@ function renderGoal(goal: GoalView | undefined): string { phase: goal.phase, roundsStarted: goal.roundsStarted, maxGoalRounds: goal.maxGoalRounds, - ...goal.blockedReason === undefined ? {} : { blockedReason: goal.blockedReason }, + ...goal.blockedReason === undefined ? {} : { + blockedReason: { code: goal.blockedReason.code, message: goal.blockedReason.message }, + }, }, activation: goal.activation, - }) + } +} + +/** Reusable canonical output declaration for all three goal controls. */ +const GOAL_OUTPUT = { + schema: GOAL_VALUE_SCHEMA, + render: (_args: unknown, value: GoalToolValue) => [{ type: 'text' as const, text: JSON.stringify(value) }], } /** Generic, args-only pending presentation shared by the goal tools. */ @@ -144,12 +208,10 @@ export function apply(ctx: Context, config: Config): void { name: 'get_goal', description: GET_DESCRIPTION, parameters: {}, + output: GOAL_OUTPUT, execute(_args, exec) { const execution = goalToolExecution(ctx, exec) - return Promise.resolve([{ - type: 'text', - text: renderGoal(ctx.goals.get(execution.agent)), - }]) + return Promise.resolve(goalValue(ctx.goals.get(execution.agent))) }, presentCall: () => present('Read current goal', 'read'), })) @@ -168,6 +230,7 @@ export function apply(ctx: Context, config: Config): void { description: 'Optional positive safe-integer limit on automatic continuation rounds.', }, }, + output: GOAL_OUTPUT, execute(args, exec) { const execution = goalToolExecution(ctx, exec) requireDirectHuman(ctx, execution) @@ -176,7 +239,7 @@ export function apply(ctx: Context, config: Config): void { ...args.max_goal_rounds === undefined ? {} : { maxGoalRounds: args.max_goal_rounds }, }) observeMutation(terminalTurns, execution, false) - return Promise.resolve([{ type: 'text', text: renderGoal(goal) }]) + return Promise.resolve(goalValue(goal)) }, presentCall: args => present('Create goal', 'other', args.objective), })) @@ -203,6 +266,7 @@ export function apply(ctx: Context, config: Config): void { description: 'Concrete blocking condition; required only with action blocked.', }, }, + output: GOAL_OUTPUT, execute(args, exec) { const execution = goalToolExecution(ctx, exec) const ref = goalRef(args.goal_id, args.revision) @@ -217,10 +281,7 @@ export function apply(ctx: Context, config: Config): void { } const goal = ctx.goals.edit(execution.agent, ref, replacements) observeMutation(terminalTurns, execution, false) - return Promise.resolve([{ - type: 'text', - text: renderGoal(goal), - }]) + return Promise.resolve(goalValue(goal)) } if (args.action === 'pause' || args.action === 'resume') { requireDirectHuman(ctx, execution) @@ -234,7 +295,7 @@ export function apply(ctx: Context, config: Config): void { ? ctx.goals.pause(execution.agent, ref) : ctx.goals.resume(execution.agent, ref) observeMutation(terminalTurns, execution, false) - return Promise.resolve([{ type: 'text', text: renderGoal(goal) }]) + return Promise.resolve(goalValue(goal)) } const authority = completionAuthority(ctx, execution) if (args.objective !== undefined || args.max_goal_rounds !== undefined) { @@ -265,7 +326,7 @@ export function apply(ctx: Context, config: Config): void { message: args.blocked_reason as string, }) observeMutation(terminalTurns, execution, authority.kind === 'goal-round') - return Promise.resolve([{ type: 'text', text: renderGoal(goal) }]) + return Promise.resolve(goalValue(goal)) }, presentCall: args => present( `${args.action === 'blocked' ? 'Mark' : args.action.charAt(0).toUpperCase() + args.action.slice(1)} goal`, diff --git a/packages/goal/tool-goal/tests/tool-goal.spec.ts b/packages/goal/tool-goal/tests/tool-goal.spec.ts index 2065bac23e..8acd304bca 100644 --- a/packages/goal/tool-goal/tests/tool-goal.spec.ts +++ b/packages/goal/tool-goal/tests/tool-goal.spec.ts @@ -95,9 +95,12 @@ async function execute( /** Parse the compact JSON returned by a successful goal tool. */ function resultJson(result: ToolExecutionResult): Record<string, unknown> { expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected goal tool success') const block = result.content[0] if (block?.type !== 'text') throw new Error('expected text tool result') - return JSON.parse(block.text) as Record<string, unknown> + const parsed = JSON.parse(block.text) as Record<string, unknown> + expect(result.value).toEqual(parsed) + return parsed } /** Read the returned goal sub-object. */ @@ -193,7 +196,7 @@ describe('goal tool execution authority', () => { it('rejects agentless, driverless, non-human, and live-child creation', async () => { const { ctx, root } = await harness() const agentless = await execute(ctx, 'get_goal', {}) - expect(agentless.error?.code).toBe('GOAL_TOOL_AGENT_REQUIRED') + expect(agentless.error?.info?.code).toBe('GOAL_TOOL_AGENT_REQUIRED') openTurn(root, { kind: 'user' }) const driverless = await ctx.tools.execute({ @@ -202,12 +205,12 @@ describe('goal tool execution authority', () => { arguments: {}, agent: root.agent, }) - expect(driverless.error?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') + expect(driverless.error?.info?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') closeTurn(root, 1) openTurn(root, { kind: 'plugin', plugin: 'test' }) const nonHuman = await execute(ctx, 'create_goal', { objective: 'forged' }, root.agent) - expect(nonHuman.error?.code).toBe('GOAL_TOOL_AUTHORITY_REQUIRED') + expect(nonHuman.error?.info?.code).toBe('GOAL_TOOL_AUTHORITY_REQUIRED') closeTurn(root, 2) const child = stubAgent('goal-tool-child') @@ -215,7 +218,7 @@ describe('goal tool execution authority', () => { ctx.agents.announce(child.agent) openTurn(child, { kind: 'user' }) const childResult = await execute(ctx, 'create_goal', { objective: 'child goal' }, child.agent) - expect(childResult.error?.code).toBe('GOAL_TOOL_AUTHORITY_REQUIRED') + expect(childResult.error?.info?.code).toBe('GOAL_TOOL_AUTHORITY_REQUIRED') }) it('rejects stale agent objects and agents outside running status through the executor', async () => { @@ -223,11 +226,11 @@ describe('goal tool execution authority', () => { openTurn(root, { kind: 'user' }) const stale = { ...root.agent } const staleResult = await execute(ctx, 'get_goal', {}, stale, stale) - expect(staleResult.error?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') + expect(staleResult.error?.info?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') root.setStatus('idle') const idleResult = await execute(ctx, 'get_goal', {}, root.agent) - expect(idleResult.error?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') + expect(idleResult.error?.info?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') }) it('treats a fork resumed as a runtime root as direct-human authority', async () => { @@ -257,12 +260,12 @@ describe('goal tool execution authority', () => { it('rejects calls before a turn and after its end boundary', async () => { const { ctx, root } = await harness() const before = await execute(ctx, 'get_goal', {}, root.agent) - expect(before.error?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') + expect(before.error?.info?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') const turn = openTurn(root, { kind: 'user' }) closeTurn(root, turn) const after = await execute(ctx, 'get_goal', {}, root.agent) - expect(after.error?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') + expect(after.error?.info?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') }) it('rejects terminal reporting without human input or a current goal round', async () => { @@ -271,11 +274,11 @@ describe('goal tool execution authority', () => { const result = await execute(ctx, 'update_goal', { goal_id: 'goal-missing', revision: 1, action: 'complete', }, root.agent) - expect(result.error?.code).toBe('GOAL_TOOL_AUTHORITY_REQUIRED') + expect(result.error?.info?.code).toBe('GOAL_TOOL_AUTHORITY_REQUIRED') const malformed = await execute(ctx, 'update_goal', { goal_id: 'goal-missing', revision: 1, action: 'pause', objective: 'probe', }, root.agent) - expect(malformed.error?.code).toBe('GOAL_TOOL_AUTHORITY_REQUIRED') + expect(malformed.error?.info?.code).toBe('GOAL_TOOL_AUTHORITY_REQUIRED') }) it('accepts direct human steering in a goal-sourced root turn', async () => { @@ -303,7 +306,7 @@ describe('goal tool execution authority', () => { ctx.agents.register(other.agent) openTurn(other, { kind: 'user' }) const result = await execute(ctx, 'get_goal', {}, other.agent, root.agent) - expect(result.error?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') + expect(result.error?.info?.code).toBe('GOAL_TOOL_DRIVER_REQUIRED') }) }) @@ -374,7 +377,7 @@ describe('goal tool state transitions', () => { const { ctx, root } = await harness() openTurn(root, { kind: 'user' }) const invalidCreate = await execute(ctx, 'create_goal', { objective: ' ' }, root.agent) - expect(invalidCreate.error?.code).toBe('GOAL_INVALID_OBJECTIVE') + expect(invalidCreate.error?.info?.code).toBe('GOAL_INVALID_OBJECTIVE') const created = ctx.goals.create(root.agent, { objective: 'valid' }) const replacement = await execute(ctx, 'update_goal', { goal_id: created.id, @@ -382,26 +385,26 @@ describe('goal tool state transitions', () => { action: 'pause', objective: 'not valid for pause', }, root.agent) - expect(replacement.error?.code).toBe('GOAL_TOOL_INVALID_UPDATE') + expect(replacement.error?.info?.code).toBe('GOAL_TOOL_INVALID_UPDATE') const terminalUpdate = await execute(ctx, 'update_goal', { goal_id: created.id, revision: created.revision, action: 'complete', max_goal_rounds: 2, }, root.agent) - expect(terminalUpdate.error?.code).toBe('GOAL_TOOL_INVALID_UPDATE') + expect(terminalUpdate.error?.info?.code).toBe('GOAL_TOOL_INVALID_UPDATE') const blockedWithoutReason = await execute(ctx, 'update_goal', { goal_id: created.id, revision: created.revision, action: 'blocked', }, root.agent) - expect(blockedWithoutReason.error?.code).toBe('GOAL_TOOL_INVALID_UPDATE') + expect(blockedWithoutReason.error?.info?.code).toBe('GOAL_TOOL_INVALID_UPDATE') const blockedWithEmptyReason = await execute(ctx, 'update_goal', { goal_id: created.id, revision: created.revision, action: 'blocked', blocked_reason: ' ', }, root.agent) - expect(blockedWithEmptyReason.error?.code).toBe('GOAL_TOOL_INVALID_UPDATE') + expect(blockedWithEmptyReason.error?.info?.code).toBe('GOAL_TOOL_INVALID_UPDATE') const completeWithReason = await execute(ctx, 'update_goal', { goal_id: created.id, revision: created.revision, action: 'complete', blocked_reason: 'Not a blocker.', }, root.agent) - expect(completeWithReason.error?.code).toBe('GOAL_TOOL_INVALID_UPDATE') + expect(completeWithReason.error?.info?.code).toBe('GOAL_TOOL_INVALID_UPDATE') const editWithReason = await execute(ctx, 'update_goal', { goal_id: created.id, revision: created.revision, @@ -409,11 +412,11 @@ describe('goal tool state transitions', () => { objective: 'still valid', blocked_reason: 'Not valid for edit.', }, root.agent) - expect(editWithReason.error?.code).toBe('GOAL_TOOL_INVALID_UPDATE') + expect(editWithReason.error?.info?.code).toBe('GOAL_TOOL_INVALID_UPDATE') const malformedRef = await execute(ctx, 'update_goal', { goal_id: '', revision: 0, action: 'edit', objective: 'x', }, root.agent) - expect(malformedRef.error?.code).toBe('GOAL_TOOL_INVALID_UPDATE') + expect(malformedRef.error?.info?.code).toBe('GOAL_TOOL_INVALID_UPDATE') }) it('allows exact goal rounds to complete but not edit or pause', async () => { @@ -425,7 +428,7 @@ describe('goal tool state transitions', () => { const edit = await execute(ctx, 'update_goal', { goal_id: created.id, revision: created.revision, action: 'edit', objective: 'forbidden', }, root.agent) - expect(edit.error?.code).toBe('GOAL_TOOL_AUTHORITY_REQUIRED') + expect(edit.error?.info?.code).toBe('GOAL_TOOL_AUTHORITY_REQUIRED') const complete = await execute(ctx, 'update_goal', { goal_id: created.id, revision: created.revision, action: 'complete', }, root.agent) @@ -447,7 +450,7 @@ describe('goal tool state transitions', () => { action: 'blocked', blocked_reason: 'The required credential is still unavailable.', }, root.agent) - expect(result.error?.code).toBe('GOAL_TOOL_BLOCK_THRESHOLD') + expect(result.error?.info?.code).toBe('GOAL_TOOL_BLOCK_THRESHOLD') closeTurn(root, turn) } openTurn(root, { kind: 'goal', goalId: ref.id, revision: ref.revision, round: 3 }) diff --git a/packages/guard/repeat-tool-guard/src/index.ts b/packages/guard/repeat-tool-guard/src/index.ts index 0c630686b4..0a4e3b417f 100644 --- a/packages/guard/repeat-tool-guard/src/index.ts +++ b/packages/guard/repeat-tool-guard/src/index.ts @@ -213,8 +213,7 @@ export function apply(ctx: Context, config: Config): void { return { kind: 'block', feedback: downstream.feedback, additionalContexts: prependContext(reminder, downstream.additionalContexts) } } return { - kind: 'accept', - ...downstream.content !== undefined ? { content: downstream.content } : {}, + ...downstream, additionalContexts: prependContext(reminder, downstream.additionalContexts), } }) diff --git a/packages/guard/repeat-tool-guard/tests/repeat-tool-guard.spec.ts b/packages/guard/repeat-tool-guard/tests/repeat-tool-guard.spec.ts index 101c542d5a..54aacc6073 100644 --- a/packages/guard/repeat-tool-guard/tests/repeat-tool-guard.spec.ts +++ b/packages/guard/repeat-tool-guard/tests/repeat-tool-guard.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest' import { Context } from 'cordis' import { CallId } from '@deepseek-ai/dsh-llm' import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session' -import { defineTool } from '@deepseek-ai/dsh-tools' +import { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import type { Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit' @@ -24,8 +24,8 @@ async function harness(config: Config = {}): Promise<Context> { await mountAgentLoopTestDependencies(ctx) await ctx.plugin(AgentLoop, { agents: [] }) await ctx.plugin(RepeatToolGuard, config) - ctx.tools.register(defineTool({ name: 'probe', description: 'p', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) - ctx.tools.register(defineTool({ name: 'other', description: 'o', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'probe', description: 'p', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'other', description: 'o', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) return ctx } @@ -332,11 +332,11 @@ describe('fold onto the downstream decision', () => { expect(results[1]!.data.content).toEqual([{ type: 'text', text: 'nope' }]) }) - it('preserves a downstream accept content replacement while folding', async () => { + it('preserves a downstream canonical value replacement while folding', async () => { const ctx = await harness({ thresholds: [2] }) ctx.on('tools/post-execute', async () => ({ kind: 'accept' as const, - content: [{ type: 'text' as const, text: 'replaced' }], + value: [{ type: 'text' as const, text: 'replaced' }], })) const adapter = new MockAdapter([ toolCallResponse('c1', 'probe', { q: 1 }), diff --git a/packages/hooks/hooks-claude/src/index.ts b/packages/hooks/hooks-claude/src/index.ts index 03ac21fea6..4f672ea416 100644 --- a/packages/hooks/hooks-claude/src/index.ts +++ b/packages/hooks/hooks-claude/src/index.ts @@ -253,8 +253,7 @@ export function apply(ctx: Context, config: Config): void { return { ...downstream, additionalContexts: prependContext(context, downstream.additionalContexts) } } return { - kind: 'accept', - ...downstream.content !== undefined ? { content: downstream.content } : {}, + ...downstream, additionalContexts: prependContext(context, downstream.additionalContexts), } }) diff --git a/packages/hooks/hooks-claude/tests/bridge.spec.ts b/packages/hooks/hooks-claude/tests/bridge.spec.ts index 65dd29d146..fd2b018a51 100644 --- a/packages/hooks/hooks-claude/tests/bridge.spec.ts +++ b/packages/hooks/hooks-claude/tests/bridge.spec.ts @@ -5,7 +5,7 @@ import { join } from 'node:path' import { Context, type Fiber } from 'cordis' import Loader from '@cordisjs/plugin-loader' import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session' -import { defineTool } from '@deepseek-ai/dsh-tools' +import { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import type { Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit' @@ -138,7 +138,7 @@ describe('hooks-claude bridge — PreToolUse', () => { const adapter = new MockAdapter([toolCallResponse('c1', 'danger', {}), textResponse('done')]) const ctx = await harness(dir, adapter) let ran = false - ctx.tools.register(defineTool({ name: 'danger', description: 'd', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'should not run' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'danger', description: 'd', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'should not run' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'use danger' }]) await waitForIdle(ctx, agent) @@ -161,7 +161,7 @@ describe('hooks-claude bridge — PreToolUse', () => { const adapter = new MockAdapter([toolCallResponse('c1', 'safe', {}), textResponse('done')]) const ctx = await harness(dir, adapter) let ran = false - ctx.tools.register(defineTool({ name: 'safe', description: 's', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'ran ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'safe', description: 's', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'ran ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'use safe' }]) await waitForIdle(ctx, agent) @@ -183,7 +183,7 @@ describe('hooks-claude bridge — PostToolUse', () => { const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(dir, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'raw output' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'raw output' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -204,7 +204,7 @@ describe('hooks-claude bridge — PostToolUse', () => { const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(dir, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -228,7 +228,7 @@ describe('hooks-claude bridge — PostToolUse', () => { const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(dir, adapter) let ran = false - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'x' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'x' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) diff --git a/packages/hooks/hooks-claude/tests/coverage-cases.ts b/packages/hooks/hooks-claude/tests/coverage-cases.ts index 870d369784..ae6347e31d 100644 --- a/packages/hooks/hooks-claude/tests/coverage-cases.ts +++ b/packages/hooks/hooks-claude/tests/coverage-cases.ts @@ -5,7 +5,7 @@ import { join } from 'node:path' import { Context } from 'cordis' import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session' import SessionPersistenceJsonl from '@deepseek-ai/dsh-session-persistence-jsonl' -import { defineTool } from '@deepseek-ai/dsh-tools' +import { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import type { Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit' @@ -65,7 +65,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'capture.sh', `#!/usr/bin/env bash\ncat > "${cap}"\n`) }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter, { ...sessionRoot !== undefined ? { sessionRoot } : {} }) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('transcript'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -95,7 +95,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter, { pluginRoot: d, projectDir: d }) ctx.logger.warn = warn as never - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -111,7 +111,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const ctx = await harness(path, adapter) ctx.logger.warn = warn as never let sawArgs: unknown - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: { command: { type: 'string' } }, async execute(args) { sawArgs = args; return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: { command: { type: 'string' } }, async execute(args) { sawArgs = args; return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -142,7 +142,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const ctx = await harness(path, new MockAdapter([])) let ran = false - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'x' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'x' }] } })) // Call execute() directly with NO agent — the bridge's no-agent/no-turn path. const { CallId } = await import('@deepseek-ai/dsh-llm') const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'echo', arguments: {} }) @@ -157,7 +157,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -182,7 +182,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter, { stderrSummaryMaxChars: 40 }) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -262,7 +262,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'x' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'x' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -276,7 +276,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -320,7 +320,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) let ran = false - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'x' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'x' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -335,7 +335,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -375,7 +375,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) let ran = false - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -390,7 +390,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -409,7 +409,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) let ran = false - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -426,7 +426,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -446,7 +446,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) let ran = false - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -529,16 +529,16 @@ export function defineCoverageCases(group: CoverageGroup): void { expect(contexts[1]?.type === 'context/message' && contexts[1].data.meta).toEqual({ owner: 'policy' }) }) - it('folds the bridge PostToolUse context onto a downstream ACCEPT that replaces content', async () => { + it('folds the bridge PostToolUse context onto a downstream canonical value replacement', async () => { // The bridge hook adds context; a later post-execute listener accepts with a - // content rewrite. Both the rewrite and the bridge context survive. + // canonical replacement. Both the replacement and the bridge context survive. const d = dir() const s = sh(d, 'ctx.sh', '#!/usr/bin/env bash\necho \'{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"bridge-note"}}\'\n') const path = hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) - ctx.on('tools/post-execute', async () => ({ kind: 'accept' as const, content: [{ type: 'text' as const, text: 'rewritten-result' }] })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.on('tools/post-execute', async () => ({ kind: 'accept' as const, value: [{ type: 'text' as const, text: 'rewritten-result' }] })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -553,7 +553,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) ctx.on('tools/post-execute', async () => ({ kind: 'accept' as const, additionalContexts: [{ @@ -583,7 +583,7 @@ export function defineCoverageCases(group: CoverageGroup): void { const path = hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: s }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) ctx.on('tools/post-execute', async () => ({ kind: 'block' as const, feedback: [{ type: 'text' as const, text: 'downstream-block' }] })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) @@ -608,7 +608,7 @@ export function defineCoverageCases(group: CoverageGroup): void { // yields a HookOutput with exitCode undefined → the `exitCode` spread false arm. const bash = ctx.bash bash.run = (() => Promise.reject(new Error('executor down'))) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -656,7 +656,7 @@ export function defineCoverageCases(group: CoverageGroup): void { await ctx.plugin(LocalBashExecutor, { timeoutMs: 10_000, cwd: serverDir }) await ctx.plugin(HooksClaude, { configPath: join(serverDir, 'hooks.json') }) ctx.llm.registerAdapter(['mock'], adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const { SessionId } = await import('@deepseek-ai/dsh-session') const handle = await ctx.agents.create({ sessionId: SessionId('s1'), meta: { cwd: sessionDir }, agentOptions: { provider: 'mock', model: 'mock' } }) diff --git a/packages/hooks/hooks-codex/src/index.ts b/packages/hooks/hooks-codex/src/index.ts index 75c33e2d92..41529c64d6 100644 --- a/packages/hooks/hooks-codex/src/index.ts +++ b/packages/hooks/hooks-codex/src/index.ts @@ -226,8 +226,7 @@ export function apply(ctx: Context, config: Config): void { return { ...downstream, additionalContexts: prependContext(context, downstream.additionalContexts) } } return { - kind: 'accept', - ...downstream.content !== undefined ? { content: downstream.content } : {}, + ...downstream, additionalContexts: prependContext(context, downstream.additionalContexts), } }) diff --git a/packages/hooks/hooks-codex/tests/bridge.spec.ts b/packages/hooks/hooks-codex/tests/bridge.spec.ts index 2cb4cb0bc5..9ce955630b 100644 --- a/packages/hooks/hooks-codex/tests/bridge.spec.ts +++ b/packages/hooks/hooks-codex/tests/bridge.spec.ts @@ -5,7 +5,7 @@ import { join } from 'node:path' import { Context } from 'cordis' import Loader from '@cordisjs/plugin-loader' import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session' -import { defineTool } from '@deepseek-ai/dsh-tools' +import { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import type { Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit' @@ -75,7 +75,7 @@ describe('hooks-codex bridge', () => { const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'ls' }), textResponse('done')]) const ctx = await harness(dir, adapter) let ran = false - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'no' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'no' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'run ls' }]) await waitForIdle(ctx, agent) diff --git a/packages/hooks/hooks-codex/tests/coverage-cases.ts b/packages/hooks/hooks-codex/tests/coverage-cases.ts index e02ea52df1..5c8ddb4487 100644 --- a/packages/hooks/hooks-codex/tests/coverage-cases.ts +++ b/packages/hooks/hooks-codex/tests/coverage-cases.ts @@ -5,7 +5,7 @@ import { join } from 'node:path' import { Context } from 'cordis' import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session' import SessionPersistenceJsonl from '@deepseek-ai/dsh-session-persistence-jsonl' -import { defineTool } from '@deepseek-ai/dsh-tools' +import { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import type { Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit' @@ -61,7 +61,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro const path = hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'capture.sh', `#!/usr/bin/env bash\ncat > "${cap}"\n`) }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(path, adapter, { ...sessionRoot !== undefined ? { sessionRoot } : {} }) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('transcript'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]) await waitForIdle(ctx, agent) @@ -144,13 +144,13 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro }) if (selected.has('post-tool')) describe('hooks-codex coverage — post-tool and session context mapping', () => { - it('folds the bridge PostToolUse context onto a downstream ACCEPT that replaces content', async () => { + it('folds the bridge PostToolUse context onto a downstream canonical value replacement', async () => { const d = dir() hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'pc.sh', '#!/usr/bin/env bash\necho \'{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"bridge-note"}}\'\n') }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) - ctx.on('tools/post-execute', async () => ({ kind: 'accept' as const, content: [{ type: 'text' as const, text: 'rewritten-result' }] })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.on('tools/post-execute', async () => ({ kind: 'accept' as const, value: [{ type: 'text' as const, text: 'rewritten-result' }] })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const result = events(agent).find(e => e.type === 'tool/result') @@ -163,7 +163,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'pc.sh', '#!/usr/bin/env bash\necho \'{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"bridge-note"}}\'\n') }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) ctx.on('tools/post-execute', async () => ({ kind: 'accept' as const, additionalContexts: [{ @@ -188,7 +188,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'pc.sh', '#!/usr/bin/env bash\necho \'{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"bridge-note"}}\'\n') }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'echo', {}), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'echo', description: 'e', parameters: {}, async execute() { return [{ type: 'text', text: 'ok' }] } })) ctx.on('tools/post-execute', async () => ({ kind: 'block' as const, feedback: [{ type: 'text' as const, text: 'downstream-block' }] })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) @@ -215,7 +215,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'p.sh', '#!/usr/bin/env bash\nexit 2\n') }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'ls' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const r = events(agent).find(e => e.type === 'tool/result') @@ -228,7 +228,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'pc.sh', '#!/usr/bin/env bash\necho \'{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"post-ctx"}}\'\n') }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'ls' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) expect(events(agent).some(e => e.type === 'context/message' && e.data.content.some(b => b.type === 'text' && b.text.includes('post-ctx')))).toBe(true) @@ -242,7 +242,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', {}), textResponse('done')]) // no command arg const ctx = await harness(join(d, 'hooks.json'), adapter) let ran = false - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: {}, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) expect(ran).toBe(true) // clean-exit hook allows; commandOf returned '' @@ -253,7 +253,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'n.sh', '#!/usr/bin/env bash\nexit 0\n') }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'x' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const res = events(agent).find(e => e.type === 'hook/result') @@ -266,7 +266,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'l.sh', '#!/usr/bin/env bash\nprintf "x%.0s" {1..600} >&2\nexit 2\n') }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'x' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const res = events(agent).find(e => e.type === 'hook/result') @@ -289,7 +289,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'l.sh', '#!/usr/bin/env bash\nprintf "x%.0s" {1..600} >&2\nexit 2\n') }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'x' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter, { stderrSummaryMaxChars: 40 }) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const res = events(agent).find(e => e.type === 'hook/result') @@ -325,7 +325,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'x' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) let ran = false - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) expect(ran).toBe(true) @@ -366,7 +366,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'x' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) let ran = false - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) expect(ran).toBe(true) @@ -379,7 +379,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'x' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) let ran = false - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) expect(ran).toBe(true) // matcher didn't match → no hook ran → tool proceeded @@ -395,7 +395,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'x' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) let ran = false - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const res = events(agent).find(e => e.type === 'hook/result') @@ -408,7 +408,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'd.sh', '#!/usr/bin/env bash\nexit 2\n') }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'x' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const r = events(agent).find(e => e.type === 'tool/result') @@ -420,7 +420,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'bc.sh', '#!/usr/bin/env bash\necho \'{"decision":"block","reason":"bad","hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"ctx too"}}\'\n') }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'x' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const r = events(agent).find(e => e.type === 'tool/result') @@ -437,7 +437,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'cap.sh', `#!/usr/bin/env bash\ncat > "${cap}"\nexit 0\n`) }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 7 }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'number' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'number' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const payload = JSON.parse(readFileSync(cap, 'utf8')) as { tool_input: { command: string } } @@ -449,7 +449,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'd.sh', '#!/usr/bin/env bash\nexit 2\n') }] }] }) const ctx = await harness(join(d, 'hooks.json'), new MockAdapter([])) let ran = false - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'x' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'x' }] } })) const { CallId } = await import('@deepseek-ai/dsh-llm') const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'Bash', arguments: { command: 'x' } }) expect(ran).toBe(false) // denied @@ -460,7 +460,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro const d = dir() hooks(d, { PostToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'pc.sh', '#!/usr/bin/env bash\necho \'{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"x"}}\'\n') }] }] }) const ctx = await harness(join(d, 'hooks.json'), new MockAdapter([])) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const { CallId } = await import('@deepseek-ai/dsh-llm') const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'Bash', arguments: { command: 'x' } }) expect(result.isError).toBeFalsy() @@ -473,7 +473,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro const adapter = new MockAdapter([toolCallResponse('c1', 'Bash', { command: 'x' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) ctx.bash.run = (() => Promise.reject(new Error('executor down'))) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const res = events(agent).find(e => e.type === 'hook/result') @@ -570,7 +570,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro hooks(d, { PreToolUse: [{ hooks: [{ type: 'command', command: sh(d, 'cap.sh', `#!/usr/bin/env bash\ncat > "${cap}"\nexit 0\n`) }] }] }) const adapter = new MockAdapter([toolCallResponse('c1', 'shell', { command: 'ls' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) - ctx.tools.register(defineTool({ name: 'shell', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'shell', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) const payload = JSON.parse(readFileSync(cap, 'utf8')) as { tool_name: string; tool_input: { command: string } } @@ -586,7 +586,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro const adapter = new MockAdapter([toolCallResponse('c1', 'shell', { command: 'ls' }), textResponse('done')]) const ctx = await harness(join(d, 'hooks.json'), adapter) let ran = false - ctx.tools.register(defineTool({ name: 'shell', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'shell', description: 'b', parameters: { command: { type: 'string' } }, async execute() { ran = true; return [{ type: 'text', text: 'ok' }] } })) const agent = ctx.agentLoop.create(SessionId('a1'), { provider: 'mock', model: 'mock' }) agent.send([{ type: 'text', text: 'go' }]); await waitForIdle(ctx, agent) expect(ran).toBe(false) // the matcher fired → the hook denied the tool @@ -620,7 +620,7 @@ export function defineCoverageCases(groups: CoverageGroup | readonly CoverageGro await ctx.plugin(LocalBashExecutor, { timeoutMs: 10_000, cwd: serverDir }) await ctx.plugin(HooksCodex, { configPath: join(serverDir, 'hooks.json'), model: 'm' }) ctx.llm.registerAdapter(['mock'], adapter) - ctx.tools.register(defineTool({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) + ctx.tools.register(defineContentToolFixture({ name: 'Bash', description: 'b', parameters: { command: { type: 'string' } }, async execute() { return [{ type: 'text', text: 'ok' }] } })) const { SessionId } = await import('@deepseek-ai/dsh-session') const handle = await ctx.agents.create({ sessionId: SessionId('s1'), meta: { cwd: sessionDir }, agentOptions: { provider: 'mock', model: 'mock' } }) handle.agent.send([{ type: 'text', text: 'go' }]) diff --git a/packages/llm/llm-retry/tests/retry.spec.ts b/packages/llm/llm-retry/tests/retry.spec.ts index 8e2f086e97..18669920e0 100644 --- a/packages/llm/llm-retry/tests/retry.spec.ts +++ b/packages/llm/llm-retry/tests/retry.spec.ts @@ -6,7 +6,7 @@ import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId } from '@deepseek-ai/dsh-session' import type { SessionEvent } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import AgentRegistry from '@deepseek-ai/dsh-agent' import type { Agent, RequestErrorDecision } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' @@ -166,7 +166,7 @@ describe('bounded transient retry policy', () => { ]) ;({ ctx: context } = await harness(adapter)) let toolExecutions = 0 - context.tools.register(defineTool({ + context.tools.register(defineContentToolFixture({ name: 'danger', description: 'must not run for a failed provider attempt', parameters: {}, diff --git a/packages/mcp/mcp-client/README.md b/packages/mcp/mcp-client/README.md index ebcf29fad5..252cd27bfc 100644 --- a/packages/mcp/mcp-client/README.md +++ b/packages/mcp/mcp-client/README.md @@ -56,8 +56,9 @@ Every MCP tool has two names: the raw MCP name (sent on the wire in `tools/call` - On connect: `listTools()` → registers each tool via `ctx.tools.register()` under its public name. - Listens for `notifications/tools/list_changed` → re-syncs; a failed re-sync keeps the previous generation registered. -- Tool execute: `client.callTool({ name: rawName, arguments }, { signal })` with timeout + abort support — the public name is never sent to the server. -- Image content in results is discarded with a placeholder (the harness has no image block type). +- Tool execute: `client.callTool({ name: rawName, arguments }, { signal })` with timeout + abort support—the public name is never sent to the server. +- Canonical success is `{ content: JsonValue[], structuredContent? }`; complete JSON MCP blocks survive for programmatic callers. A supported advertised `outputSchema` validates `structuredContent`; unsupported schema vocabulary falls back to unconstrained `JsonValue`. +- Native/model rendering keeps the existing text projection: text blocks join with newlines while image, audio, resource, and unsupported blocks become placeholders. - On disconnect/crash: all tools are unregistered; no auto-reconnect. ## Services consumed @@ -86,7 +87,7 @@ Prefix-stable while the discovered tool set and schemas are unchanged. A re-sync #### What the model sees -The public tool name and JSON arguments remain in assistant history. Text result blocks are joined with newlines into one retained text result; image, audio, resource, and unsupported blocks become short placeholders, and MCP `isError` results follow the registry's model-visible error path. +The public tool name and JSON arguments remain in assistant history. Text result blocks are joined with newlines into one retained Native text result; image, audio, resource, and unsupported blocks become short placeholders there. Their full JSON blocks and optional structured content remain in the execution-local canonical value, and MCP `isError` rejects the call through the registry's error path. #### Token effect @@ -101,4 +102,5 @@ Append-only; newly visible content follows the reusable request prefix and does - **Initial discovery is asynchronous** — plugin load does not wait for connection and `listTools()`, so a turn started immediately after boot or HMR can assemble before the MCP tools are registered. - **Tools are the only bridged MCP capability** — Resources and Prompts have no harness consumption surface and are deferred. - **Crash recovery is manual** — transport closure unregisters the server's tools, but reconnect requires an HMR reload or harness restart. -- **Non-text results are lossy** — image, audio, and resource payloads are replaced with placeholders, and a structured-only result has no model-visible structured representation. +- **Native non-text rendering is lossy** — image, audio, and resource payloads become placeholders in model context even though the execution-local canonical value preserves their JSON blocks. Richer Native multimedia projection is deferred. +- **Unsupported MCP output schemas are not enforced** — `structuredContent` falls back to `JsonValue` when the advertised schema uses vocabulary outside the harness subset. diff --git a/packages/mcp/mcp-client/src/index.ts b/packages/mcp/mcp-client/src/index.ts index 4a18f85ff5..2e16e33b44 100644 --- a/packages/mcp/mcp-client/src/index.ts +++ b/packages/mcp/mcp-client/src/index.ts @@ -22,6 +22,8 @@ import { syncTools } from './tools.ts' // Side-effect type import: declaration-merges `ctx.tools` onto Context. import type {} from '@deepseek-ai/dsh-tools' +export type { McpResult } from './tools.ts' + /** Cordis plugin name used by loader diagnostics. */ export const name = 'mcp-client' diff --git a/packages/mcp/mcp-client/src/tools.ts b/packages/mcp/mcp-client/src/tools.ts index 7b9217e814..1a8eabf416 100644 --- a/packages/mcp/mcp-client/src/tools.ts +++ b/packages/mcp/mcp-client/src/tools.ts @@ -16,6 +16,8 @@ import { createHash } from 'node:crypto' import type { Client } from '@modelcontextprotocol/sdk/client/index.js' import type { Context } from 'cordis' import type { ToolDefinition, ToolExecution } from '@deepseek-ai/dsh-tools' +import { assertSupportedJsonSchema } from '@deepseek-ai/dsh-tools' +import type { JsonSchemaNode, JsonValue } from '@deepseek-ai/dsh-tools' /** Resolved options relevant to tool bridging. */ export interface ToolBridgeOptions { @@ -26,6 +28,12 @@ export interface ToolBridgeOptions { /** State for one sync generation: the current set of disposers keyed by public name. */ export type ToolDisposers = Map<string, () => void> +/** Canonical MCP result exposed to Code Mode without discarding protocol blocks. */ +export type McpResult<Structured extends JsonValue = JsonValue> = { + content: JsonValue[] + structuredContent?: Structured +} + /** * DeepSeek function-name contract: at most 64 characters. Wire-protocol * constant, not configuration. @@ -105,6 +113,7 @@ export async function syncTools( name: publicName, description: tool.description ?? '', parameters: tool.inputSchema, + output: createOutput(tool.name, supportedOutputSchema(tool.outputSchema)), execute: createExecutor(client, tool.name, opts), }) } @@ -141,6 +150,36 @@ interface McpContentBlock { mimeType?: string } +/** Keep a supported advertised schema; unsupported MCP vocabulary falls back to JsonValue. */ +function supportedOutputSchema(candidate: unknown): JsonSchemaNode | undefined { + if (candidate === undefined) return undefined + try { + assertSupportedJsonSchema(candidate) + return candidate + } catch { + return undefined + } +} + +/** Build the canonical result schema and existing Native text projection. */ +function createOutput(rawName: string, structuredSchema: JsonSchemaNode | undefined): ToolDefinition['output'] { + return { + schema: { + type: 'object', + properties: { + content: { type: 'array', items: {} }, + structuredContent: structuredSchema ?? {}, + }, + required: ['content'], + additionalProperties: false, + }, + render(_args, value) { + const result = value as unknown as McpResult + return [{ type: 'text', text: extractText(result.content, rawName) }] + }, + } +} + /** * Create an execute function for one MCP tool. The executor closes over the * raw MCP tool name and calls `client.callTool` with it (never the public @@ -172,18 +211,24 @@ function createExecutor( // The SDK may return a legacy `toolResult` shape; normalize to content array. if (!('content' in result) || !Array.isArray(result.content)) { - const text = 'toolResult' in result + const rendered: unknown = 'toolResult' in result ? JSON.stringify(result.toolResult) : '(no output)' - return [{ type: 'text' as const, text }] + const text = typeof rendered === 'string' ? rendered : '(no output)' + if ('isError' in result && result.isError === true) throw new Error(text) + return { + content: [{ type: 'text', text }], + ...'structuredContent' in result && result.structuredContent !== undefined + ? { structuredContent: result.structuredContent as JsonValue } + : {}, + } } // Trust boundary: the SDK's return type erases to `any[]` due to the // union of CallToolResult | CompatibilityCallToolResult. We process each // element defensively in extractText (reading only .type/.text/.mimeType // with optional fallbacks). - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const content: McpContentBlock[] = result.content + const content = result.content as unknown as JsonValue[] const text = extractText(content, rawName) // MCP isError → throw so ToolRegistry produces an isError result for the model. @@ -191,7 +236,12 @@ function createExecutor( throw new Error(text) } - return [{ type: 'text', text }] + return { + content, + ...'structuredContent' in result && result.structuredContent !== undefined + ? { structuredContent: result.structuredContent as JsonValue } + : {}, + } } } @@ -203,10 +253,15 @@ function createExecutor( * Defensive: fields that the MCP spec declares required (mimeType, text) are * guarded with fallbacks because this is a network trust boundary. */ -function extractText(mcpContent: McpContentBlock[], toolName: string): string { +function extractText(mcpContent: JsonValue[], toolName: string): string { const parts: string[] = [] - for (const block of mcpContent) { + for (const value of mcpContent) { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + parts.push('[unsupported content type: unknown]') + continue + } + const block = value as unknown as McpContentBlock switch (block.type) { case 'text': if (block.text !== undefined) parts.push(block.text) diff --git a/packages/mcp/mcp-client/tests/mcp-client.spec.ts b/packages/mcp/mcp-client/tests/mcp-client.spec.ts index 8fff832434..30e7a6297c 100644 --- a/packages/mcp/mcp-client/tests/mcp-client.spec.ts +++ b/packages/mcp/mcp-client/tests/mcp-client.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, it, vi, beforeEach } from 'vitest' import { Context } from 'cordis' import { CallId } from '@deepseek-ai/dsh-llm' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry from '@deepseek-ai/dsh-tools' +import ToolRegistry, { type JsonValue } from '@deepseek-ai/dsh-tools' import { publicToolName, syncTools, type ToolBridgeOptions } from '@deepseek-ai/dsh-mcp-client/src/tools.ts' import { createTransport } from '@deepseek-ai/dsh-mcp-client/src/transport.ts' import type { Config } from '@deepseek-ai/dsh-mcp-client' @@ -13,10 +13,12 @@ interface MockTool { name: string description?: string inputSchema: Record<string, unknown> + outputSchema?: Record<string, unknown> } interface MockCallResult { - content: Array<{ type: string; text?: string; mimeType?: string }> + content: JsonValue[] + structuredContent?: JsonValue isError?: boolean } @@ -114,7 +116,8 @@ describe('syncTools', () => { name: 'search', description: 'Native search', parameters: { type: 'object' }, - execute: async () => [{ type: 'text', text: 'native' }], + output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value as string }] }, + execute: async () => 'native', }) const client = createMockClient([{ name: 'search', inputSchema: { type: 'object' } }]) @@ -156,7 +159,8 @@ describe('syncTools', () => { name: 'mcp__srv__taken', description: 'Squatter', parameters: { type: 'object' }, - execute: async () => [{ type: 'text', text: 'squatter' }], + output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value as string }] }, + execute: async () => 'squatter', }) const client = createMockClient([ { name: 'free', inputSchema: { type: 'object' } }, @@ -221,6 +225,8 @@ describe('tool execution', () => { expect(result.isError).toBe(false) expect(result.content).toEqual([{ type: 'text', text: 'hello world' }]) + if (result.isError) throw new Error('expected MCP success') + expect(result.value).toEqual({ content: [{ type: 'text', text: 'hello world' }] }) // The wire sees the raw MCP name, never the public name. expect(client.callTool).toHaveBeenCalledWith( { name: 'echo', arguments: { msg: 'hi' } }, @@ -259,16 +265,85 @@ describe('tool execution', () => { expect(result.content).toEqual([{ type: 'text', text: 'line1\nline2' }]) }) - it('discards image content with placeholder', async () => { + it('preserves full JSON MCP blocks while Native rendering uses placeholders', async () => { + const blocks = [ + { type: 'text', text: 'before' }, + { type: 'image', mimeType: 'image/png', data: 'base64-data', annotations: { audience: ['assistant'] } }, + ] satisfies JsonValue[] const client = createMockClient( [{ name: 'img', inputSchema: { type: 'object' } }], - { content: [{ type: 'text', text: 'before' }, { type: 'image', mimeType: 'image/png' }] }, + { content: blocks }, ) await syncTools(client as never, ctx, defaultOpts, new Map()) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'mcp__srv__img', arguments: {} }) expect(result.content[0]).toEqual({ type: 'text', text: 'before\n[image: image/png, content discarded]' }) + if (result.isError) throw new Error('expected MCP success') + expect(result.value).toEqual({ content: blocks }) + }) + + it('preserves primitive JSON MCP blocks while Native rendering marks them unsupported', async () => { + const blocks = [42, null, ['nested']] satisfies JsonValue[] + const client = createMockClient( + [{ name: 'primitive-blocks', inputSchema: { type: 'object' } }], + { content: blocks }, + ) + + await syncTools(client as never, ctx, defaultOpts, new Map()) + const result = await ctx.tools.execute({ + callId: CallId('primitive'), name: 'mcp__srv__primitive-blocks', arguments: {}, + }) + + expect(result.content[0]).toEqual({ + type: 'text', + text: '[unsupported content type: unknown]\n[unsupported content type: unknown]\n[unsupported content type: unknown]', + }) + if (result.isError) throw new Error('expected primitive MCP blocks to remain a successful JSON value') + expect(result.value).toEqual({ content: blocks }) + }) + + it('validates structuredContent when the advertised output schema is supported', async () => { + const outputSchema = { + type: 'object', + additionalProperties: false, + properties: { answer: { type: 'integer' } }, + required: ['answer'], + } + const valid = createMockClient( + [{ name: 'structured', inputSchema: { type: 'object' }, outputSchema }], + { content: [{ type: 'text', text: '42' }], structuredContent: { answer: 42 } }, + ) + await syncTools(valid as never, ctx, defaultOpts, new Map()) + const success = await ctx.tools.execute({ callId: CallId('valid'), name: 'mcp__srv__structured', arguments: {} }) + if (success.isError) throw new Error('expected supported structuredContent to validate') + expect(success.value).toEqual({ content: [{ type: 'text', text: '42' }], structuredContent: { answer: 42 } }) + + const invalidCtx = await mountRegistry() + const invalid = createMockClient( + [{ name: 'structured', inputSchema: { type: 'object' }, outputSchema }], + { content: [{ type: 'text', text: 'wrong' }], structuredContent: { answer: 'forty-two' } }, + ) + await syncTools(invalid as never, invalidCtx, defaultOpts, new Map()) + const failure = await invalidCtx.tools.execute({ callId: CallId('invalid'), name: 'mcp__srv__structured', arguments: {} }) + expect(failure.error).toMatchObject({ info: { code: 'INVALID_TOOL_OUTPUT' } }) + expect(failure.content[0]?.type === 'text' ? failure.content[0].text : '') + .toContain('value.structuredContent.answer') + }) + + it('falls back to JsonValue for unsupported advertised output schemas', async () => { + const client = createMockClient( + [{ + name: 'future-schema', + inputSchema: { type: 'object' }, + outputSchema: { type: 'object', patternProperties: { '^x-': { type: 'string' } } }, + }], + { content: [], structuredContent: ['kept', { nested: true }] }, + ) + await syncTools(client as never, ctx, defaultOpts, new Map()) + const result = await ctx.tools.execute({ callId: CallId('fallback'), name: 'mcp__srv__future-schema', arguments: {} }) + if (result.isError) throw new Error('unsupported MCP output schemas must fall back') + expect(result.value).toEqual({ content: [], structuredContent: ['kept', { nested: true }] }) }) it('maps isError to an error result via throw', async () => { @@ -282,6 +357,7 @@ describe('tool execution', () => { expect(result.isError).toBe(true) expect(result.content[0]).toEqual({ type: 'text', text: 'Error: something went wrong' }) + expect('value' in result).toBe(false) }) it('passes abort signal to callTool', async () => { @@ -313,6 +389,38 @@ describe('tool execution', () => { expect(result.isError).toBe(false) expect(result.content[0]).toEqual({ type: 'text', text: '{"key":"value"}' }) }) + + it('preserves structuredContent on a successful legacy result', async () => { + const client = createMockClient([{ name: 'legacy-structured', inputSchema: { type: 'object' } }]) + client.callTool.mockResolvedValue({ + toolResult: 'legacy', + structuredContent: { answer: 42 }, + }) + + await syncTools(client as never, ctx, defaultOpts, new Map()) + const result = await ctx.tools.execute({ + callId: CallId('legacy-structured'), name: 'mcp__srv__legacy-structured', arguments: {}, + }) + + if (result.isError) throw new Error('expected legacy structured result success') + expect(result.value).toEqual({ + content: [{ type: 'text', text: '"legacy"' }], + structuredContent: { answer: 42 }, + }) + }) + + it('maps a legacy isError reply to failure', async () => { + const client = createMockClient([{ name: 'legacy-error', inputSchema: { type: 'object' } }]) + client.callTool.mockResolvedValue({ toolResult: { reason: 'nope' }, isError: true }) + + await syncTools(client as never, ctx, defaultOpts, new Map()) + const result = await ctx.tools.execute({ + callId: CallId('legacy-error'), name: 'mcp__srv__legacy-error', arguments: {}, + }) + + expect(result.isError).toBe(true) + expect(result.error?.message).toBe('{"reason":"nope"}') + }) }) describe('tool execution edge cases', () => { @@ -423,7 +531,7 @@ describe('tool execution edge cases', () => { const client = createMockClient( [{ name: 'legacy2', inputSchema: { type: 'object' } }], ) - client.callTool.mockResolvedValue({}) + client.callTool.mockResolvedValue({ toolResult: undefined, structuredContent: undefined }) await syncTools(client as never, ctx, defaultOpts, new Map()) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'mcp__srv__legacy2', arguments: {} }) @@ -431,6 +539,18 @@ describe('tool execution edge cases', () => { expect(result.content[0]).toEqual({ type: 'text', text: '(no output)' }) }) + it('handles a legacy result with neither content nor toolResult', async () => { + const client = createMockClient( + [{ name: 'legacy-empty', inputSchema: { type: 'object' } }], + ) + client.callTool.mockResolvedValue({}) + + await syncTools(client as never, ctx, defaultOpts, new Map()) + const result = await ctx.tools.execute({ callId: CallId('legacy-empty'), name: 'mcp__srv__legacy-empty', arguments: {} }) + + expect(result.content[0]).toEqual({ type: 'text', text: '(no output)' }) + }) + it('handles isError with non-text content (fallback error message)', async () => { const client = createMockClient( [{ name: 'err_notext', inputSchema: { type: 'object' } }], diff --git a/packages/session-persistence/session-persistence/tests/contract.ts b/packages/session-persistence/session-persistence/tests/contract.ts index 84386c016b..d36ed98234 100644 --- a/packages/session-persistence/session-persistence/tests/contract.ts +++ b/packages/session-persistence/session-persistence/tests/contract.ts @@ -149,7 +149,7 @@ export function runPersistenceContract(name: string, make: () => Promise<Contrac ]) const synthetic = loaded.events.find(e => e.type === 'tool/result') expect(synthetic?.type === 'tool/result' && synthetic.data).toMatchObject({ - callId: CallId('call-x'), isError: true, error: { code: 'interrupted' }, + callId: CallId('call-x'), isError: true, error: { info: { code: 'interrupted' } }, }) // The synthetic result carries the SAME callId as the orphaned tool-call, // so deriveMessages() pairs them — no provider-invalid dangling call. diff --git a/packages/skill/tool-skill/README.md b/packages/skill/tool-skill/README.md index 89a6e843ab..578c6e7300 100644 --- a/packages/skill/tool-skill/README.md +++ b/packages/skill/tool-skill/README.md @@ -16,7 +16,7 @@ The plugin contributes one user-role `<system-reminder>` catalog through `agent/ |---|---|---| | `name` | string (required) | Exact kebab-case skill name from the available skills listing. | -Execution uses the calling agent's `session.header.cwd` so workspace-sensitive providers resolve the winning skill. A successful call returns one text result containing `<skill_content name="...">`, `<skill_resources>`, and `<skill_instructions>`. +Execution uses the calling agent's `session.header.cwd` so workspace-sensitive providers resolve the winning skill. A successful call returns canonical `{ name, provider, resourceBase?, content }`, excluding catalog ranking and provider-internal machinery; its Native renderer produces one text result containing `<skill_content name="...">`, `<skill_resources>`, and `<skill_instructions>`. Resource guidance resolves only paths or URLs explicitly referenced by the instructions against `resourceBase`; scripts, references, and assets load on demand, and the result does not enumerate a skill directory. Local providers may supply a directory, while remote or embedded providers may supply a URL or opaque loading guidance. diff --git a/packages/skill/tool-skill/src/index.ts b/packages/skill/tool-skill/src/index.ts index 50c4b0db74..f5fbd1dff5 100644 --- a/packages/skill/tool-skill/src/index.ts +++ b/packages/skill/tool-skill/src/index.ts @@ -42,6 +42,46 @@ export function apply(ctx: Context, config: Config = {}): void { parameters: { name: { type: 'string', required: true, description: 'The exact skill name from the available skills list.' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + name: { type: 'string', required: true }, + provider: { type: 'string', required: true }, + resourceBase: { + oneOf: [ + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'directory' }, + path: { type: 'string', required: true }, + }, + }, + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'url' }, + url: { type: 'string', required: true }, + }, + }, + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'opaque' }, + description: { type: 'string', required: true }, + }, + }, + ], + }, + content: { type: 'string', required: true }, + }, + }, + render: (_args, value) => [{ type: 'text', text: renderSkillContent(value) }], + }, async execute(args, exec) { if (!isSkillName(args.name)) { throw new Error(`invalid skill name "${args.name}"`) @@ -53,7 +93,14 @@ export function apply(ctx: Context, config: Config = {}): void { if (skill.disableModelInvocation === true) { throw new Error(`skill "${args.name}" is not available for model invocation`) } - return [{ type: 'text', text: renderSkillContent(skill) }] + return { + name: skill.name, + provider: skill.provider, + ...skill.resourceBase !== undefined ? { + resourceBase: { ...skill.resourceBase }, + } : {}, + content: skill.content, + } }, presentCall(args) { return { card: 'generic', title: `Load skill ${args.name}`, kind: 'read', rawInput: args.name } @@ -77,7 +124,7 @@ export function apply(ctx: Context, config: Config = {}): void { }) } -function renderSkillContent(skill: SkillDefinition): string { +function renderSkillContent(skill: Pick<SkillDefinition, 'name' | 'provider' | 'resourceBase' | 'content'>): string { const resourceHint = renderResourceHint(skill) return [ `<skill_content name="${escapeAttr(skill.name)}">`, @@ -92,7 +139,7 @@ function renderSkillContent(skill: SkillDefinition): string { ].join('\n') } -function renderResourceHint(skill: SkillDefinition): string[] { +function renderResourceHint(skill: Pick<SkillDefinition, 'provider' | 'resourceBase'>): string[] { const base = skill.resourceBase if (base === undefined) { return [ @@ -116,8 +163,10 @@ function renderResourceHint(skill: SkillDefinition): string[] { `Resources for this skill: ${escapeText(base.description)}`, 'Load referenced resources only as needed.', ] + /* v8 ignore start -- SkillResourceBase is a closed union; a future kind must fail compilation here. */ default: return assertNever(base, 'SkillResourceBase.kind') + /* v8 ignore stop */ } } diff --git a/packages/skill/tool-skill/tests/tool-skill.spec.ts b/packages/skill/tool-skill/tests/tool-skill.spec.ts index cab7f4aa02..843c14c93f 100644 --- a/packages/skill/tool-skill/tests/tool-skill.spec.ts +++ b/packages/skill/tool-skill/tests/tool-skill.spec.ts @@ -6,7 +6,7 @@ import { Context } from 'cordis' import { CallId, type Message } from '@deepseek-ai/dsh-llm' import { createScope, type Scope } from '@deepseek-ai/dsh-scope' import SystemPrompt, { renderPrompt } from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import { agentEvents, type Agent } from '@deepseek-ai/dsh-agent' import SkillService from '@deepseek-ai/dsh-skill' import * as SkillLocal from '@deepseek-ai/dsh-skill-local' @@ -185,7 +185,7 @@ describe('dsh-tool-skill', () => { const ctx = await setup(home) ctx.skills.register({ name: 'listed-skill', description: 'Listed', source: 'runtime', content: 'body' }) const { agent, scope } = await mintAgentScope(ctx, '/workspace') - scope.ctx.tools.register(defineTool({ + scope.ctx.tools.register(defineContentToolFixture({ name: 'skill', description: 'A scoped tool with unrelated semantics.', parameters: {}, @@ -226,6 +226,13 @@ describe('dsh-tool-skill', () => { }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected skill success') + expect(result.value).toEqual({ + name: 'project-skill', + provider: 'local', + resourceBase: { kind: 'directory', path: join(project, '.dsh/skills/project-skill') }, + content: 'Project instructions.', + }) const block = result.content[0] expect(block?.type).toBe('text') if (block?.type !== 'text') throw new Error('expected text skill result') @@ -283,7 +290,7 @@ describe('dsh-tool-skill', () => { expect(provider.content[0].text).toContain('<skill_resources>\nResources for this skill are managed by provider "runtime".\nLoad referenced resources only as needed.\n</skill_resources>') }) - it('fails loud on an unknown resource base kind', async () => { + it('rejects an unknown resource-base kind at the canonical output boundary', async () => { const home = await tempDir('tool-resource-assert-never') const ctx = await setup(home) ctx.skills.register({ @@ -298,9 +305,10 @@ describe('dsh-tool-skill', () => { const result = await ctx.tools.execute({ callId: CallId('c5'), name: 'skill', arguments: { name: 'rogue-resource-skill' } }) expect(result.isError).toBe(true) + expect(result.error?.info?.code).toBe('INVALID_TOOL_OUTPUT') const block = result.content[0] if (block?.type !== 'text') throw new Error('expected text tool result') - expect(block.text).toContain('unreachable variant') + expect(block.text).toContain('value.resourceBase') }) it('returns isError for unknown, invalid, and model-disabled skills', async () => { diff --git a/packages/spill/spill-policy/README.md b/packages/spill/spill-policy/README.md index 936f254d6a..9b746f27bc 100644 --- a/packages/spill/spill-policy/README.md +++ b/packages/spill/spill-policy/README.md @@ -13,7 +13,7 @@ This plugin registers **no service** and owns no storage or preview mechanics: p ## Behavior 1. Let the tool run (delegates via `next()`, so it bounds whatever a downstream hook accepted). -2. Skip `read` (avoids a `read → spill → read again` loop) and any non-`accept` decision (a `block`'s corrective feedback passes through). +2. Skip nested executions (`exec.parent` is present), accepted value replacements (the registry must revalidate and rerender them), `read` (avoids a `read → spill → read again` loop), and any non-`accept` decision (a `block`'s corrective feedback passes through). 3. Flatten the accepted content only when it is **plain text** (all `text` blocks); a result with any non-text block is left untouched. 4. If its UTF-8 size is `≤ maxInlineBytes`, leave it unchanged. 5. Otherwise save the full text and replace the result with a preview + this notice, sized so the whole replacement (preview + blank line + notice) stays within `maxInlineBytes` — the notice's byte cost is reserved out of the budget, so the preview shrinks to fit and the model-facing result never exceeds the cap: @@ -26,11 +26,11 @@ This plugin registers **no service** and owns no storage or preview mechanics: p When the notice alone fills the budget (a tiny cap or a long locator) the preview is empty and only the notice is returned. If even that notice-only replacement would exceed `maxInlineBytes`, the policy keeps the inline result — it never emits a replacement over the cap (and a within-cap replacement is always smaller than the original, so this also means spilling never adds bytes). -**Best-effort:** no session owner, no `ctx.spillStore` backend, or a `saveText` rejection ⇒ the policy logs a warning and returns the original result. A spill failure never turns a successful call into an `isError` or hides the inline result. +**Best-effort:** no session owner, no `ctx.spillStore` backend, or a `saveText` rejection ⇒ the policy logs a warning and returns the original result. A spill failure never turns a successful call into an `isError` or hides the inline result. A successful replacement changes only `content`; the canonical programmatic value is preserved. ## Scope -The policy sees only the FINAL formatted tool result — not a tool's internal resource. If a provider already truncated (e.g. `web-fetch-local.maxBodyChars`), the spill artifact holds the full formatted result the tool returned, not the full original source. Provider/resource caps stay mandatory and separate. Tool-owned early spill (bash streams, subagent rollouts) is future work — see the [tool output spill Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md). +The policy sees only the FINAL formatted surface result—not a tool's internal resource or canonical value. If a provider already truncated (e.g. `web-fetch-local.maxBodyChars`), the spill artifact holds the full formatted result the tool returned, not the full original source. Provider/resource caps stay mandatory and separate. `glob`/`grep` own item-level surface spill because their complete acquired values still exist before rendering; bash streams own acquisition-time spill. See the [tool output spill Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md). ## Model Experience @@ -38,7 +38,7 @@ The policy sees only the FINAL formatted tool result — not a tool's internal r #### What the model sees -Results at or below `maxInlineBytes`, `read` results, blocked decisions, and results containing non-text blocks are unchanged. An oversized plain-text result becomes a bounded head/tail preview followed by `(Omitted <bytes> bytes. Full formatted result stored at: <locator>. <retrievalHint>)`; storage or ownership failures leave the original result visible. +Results at or below `maxInlineBytes`, nested results, `read` results, blocked decisions, and results containing non-text blocks are unchanged. An oversized plain-text surface result becomes a bounded head/tail preview followed by `(Omitted <bytes> bytes. Full formatted result stored at: <locator>. <retrievalHint>)`; storage or ownership failures leave the original result visible. #### Token effect diff --git a/packages/spill/spill-policy/src/index.ts b/packages/spill/spill-policy/src/index.ts index b7ac4a31fc..c2abd094ed 100644 --- a/packages/spill/spill-policy/src/index.ts +++ b/packages/spill/spill-policy/src/index.ts @@ -16,15 +16,20 @@ * - Plain-text results only: a result carrying any non-text block is left * untouched (the policy knows only the final formatted text, not tool * internals). + * - Nested composite calls are skipped; only their outer surface result may + * become model-facing and spillable. + * - Accepted value replacements pass through for registry revalidation and + * rendering; this presentation policy cannot also replace content in the + * same mutually exclusive decision. * - `read` is skipped to avoid a `read → spill → read again` loop. * - Best-effort: no session owner, no `ctx.spillStore` backend, or a save * failure ⇒ log and return the original result. A spill failure must NEVER * turn a successful tool call into an `isError` or hide the inline result. * * It COMPOSES with other post-execute listeners: it delegates via `next()` and - * bounds the resulting `accept` content, so a hook that replaced the content - * still has its replacement bounded, and a `block` decision passes through - * unchanged. + * bounds the resulting content projection, so a hook that replaced content + * still has its replacement bounded, while value replacements and `block` + * decisions pass through unchanged. * * @module @deepseek-ai/dsh-spill-policy */ @@ -109,7 +114,8 @@ export function apply(ctx: Context, config: Config): void { // accepted plain-text results, never corrective feedback. const decision = await next() // Skip `read` to avoid a read → spill → read again loop. - if (decision.kind !== 'accept' || exec.name === 'read') return decision + if (decision.kind !== 'accept' || Object.hasOwn(decision, 'value') + || exec.parent !== undefined || exec.name === 'read') return decision const content = decision.content ?? result.content const text = flattenPlainText(content) diff --git a/packages/spill/spill-policy/tests/spill-policy.spec.ts b/packages/spill/spill-policy/tests/spill-policy.spec.ts index 2449f26a8c..e01703525f 100644 --- a/packages/spill/spill-policy/tests/spill-policy.spec.ts +++ b/packages/spill/spill-policy/tests/spill-policy.spec.ts @@ -15,8 +15,8 @@ import { CallId } from '@deepseek-ai/dsh-llm' import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { SessionId } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool } from '@deepseek-ai/dsh-tools' -import type { ToolExecution } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' +import type { ToolExecution, ToolExecutionToken } from '@deepseek-ai/dsh-tools' import { SpillLocator, SpillStore } from '@deepseek-ai/dsh-spill' import type { SaveTextSpill, SpillRef } from '@deepseek-ai/dsh-spill' import * as SpillPolicy from '@deepseek-ai/dsh-spill-policy' @@ -39,7 +39,7 @@ class StubStore extends SpillStore { /** A tool returning `text` verbatim (name configurable so we can register `read`). */ function textTool(name: string, text: string) { - return defineTool({ + return defineContentToolFixture({ name, description: name, parameters: {}, @@ -159,7 +159,7 @@ describe('oversized plain-text replacement', () => { it('leaves a result with a non-text block unchanged', async () => { const { ctx, spill } = await setup({ maxInlineBytes: 5 }) - ctx.tools.register(defineTool({ + ctx.tools.register(defineContentToolFixture({ name: 'mixed', description: 'mixed', parameters: {}, @@ -183,6 +183,21 @@ describe('read skip', () => { }) }) +describe('nested-call skip', () => { + it('leaves nested composite results complete and spillable only through their outer call', async () => { + const { ctx, spill } = await setup({ maxInlineBytes: 10 }) + const body = 'x'.repeat(1000) + ctx.tools.register(textTool('nested', body)) + const nested = { + ...exec('nested'), + parent: Symbol('outer') as ToolExecutionToken, + } + const result = await ctx.tools.execute(nested) + expect(textOf(result.content)).toBe(body) + expect(spill?.saves).toHaveLength(0) + }) +}) + describe('best-effort fallback', () => { it('keeps the original result when saveText fails', async () => { const { ctx, spill } = await setup({ maxInlineBytes: 10 }) @@ -238,6 +253,21 @@ describe('composition', () => { expect(textOf(result.content)).toContain('Full formatted result stored at') expect(result.additionalContexts).toEqual([context]) }) + + it('passes a downstream value replacement through for registry rendering', async () => { + const { ctx, spill } = await setup({ maxInlineBytes: 10 }) + const replacement = [{ type: 'text' as const, text: 'z'.repeat(500) }] + ctx.on('tools/post-execute', async () => ({ kind: 'accept' as const, value: replacement })) + ctx.tools.register(textTool('small', 'tiny')) + + const result = await ctx.tools.execute(exec('small')) + + expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected replacement success') + expect(result.value).toEqual(replacement) + expect(textOf(result.content)).toBe('z'.repeat(500)) + expect(spill?.saves).toHaveLength(0) + }) }) describe('cap invariant', () => { diff --git a/packages/subagent/subagent-inprocess/README.md b/packages/subagent/subagent-inprocess/README.md index d51fc53e5d..194ffeea47 100644 --- a/packages/subagent/subagent-inprocess/README.md +++ b/packages/subagent/subagent-inprocess/README.md @@ -60,7 +60,7 @@ Independent of the parent request cache. The child's later history is append-onl #### What the model sees -A structured run adds the structured-output instruction below. It also adds a child-scoped `structured_output` definition with exact description `Report your final structured result. Call this exactly once, when your answer is complete; the arguments must match this tool's parameter schema exactly.` and the requested schema. This runtime-only definition is outside the generated shipped [tool package map](../../../docs/tool-catalog.md#tool-package-map). Success returns `Structured output recorded.`; a later call becomes ``Error: structured output already recorded: the run is complete, so `<tool>` is not executed``. +A structured run adds the structured-output instruction below. It also adds a child-scoped `structured_output` definition with exact description `Report your final structured result. Call this exactly once, when your answer is complete; the arguments must match this tool's parameter schema exactly.` and the requested schema. This runtime-only definition is outside the generated shipped [tool package map](../../../docs/tool-catalog.md#tool-package-map). Its canonical acknowledgement is `{ recorded: true }`, rendered as `Structured output recorded.`; a later call becomes ``Error: structured output already recorded: the run is complete, so `<tool>` is not executed``. ##### Structured-output instruction diff --git a/packages/subagent/subagent-inprocess/src/structured.ts b/packages/subagent/subagent-inprocess/src/structured.ts index 9d2cce1570..9adf5899fe 100644 --- a/packages/subagent/subagent-inprocess/src/structured.ts +++ b/packages/subagent/subagent-inprocess/src/structured.ts @@ -12,7 +12,7 @@ import type { Context } from 'cordis' import type { ContinuationStop } from '@deepseek-ai/dsh-agent' -import type { ContentBlock, ToolSchema } from '@deepseek-ai/dsh-llm' +import type { ToolSchema } from '@deepseek-ai/dsh-llm' import type { ToolExecution } from '@deepseek-ai/dsh-tools' import { ToolArgsError, validateJsonSchemaValue, type ObjectJsonSchema } from '@deepseek-ai/dsh-tools' @@ -74,7 +74,16 @@ export function attachStructuredRuntime(childCtx: Context, schema: ObjectJsonSch childCtx.tools.register({ ...schemaEntry, - execute(args: unknown, exec: ToolExecution): Promise<ContentBlock[]> { + output: { + schema: { + type: 'object', + properties: { recorded: { type: 'boolean', const: true } }, + required: ['recorded'], + additionalProperties: false, + }, + render: () => [{ type: 'text', text: 'Structured output recorded.' }], + }, + execute(args: unknown, exec: ToolExecution): Promise<{ recorded: true }> { const violations = validateJsonSchemaValue(schema, args) // ToolArgsError → isError result with INVALID_ARGS: the model retries // within the same turn, exactly like a schema-validated defineTool call. @@ -83,7 +92,7 @@ export function attachStructuredRuntime(childCtx: Context, schema: ObjectJsonSch // waterfalls may still turn the success into an error. ToolRegistry has // already frozen model-bound arguments at the actual input boundary. staged.set(exec, { value: args }) - return Promise.resolve([{ type: 'text', text: 'Structured output recorded.' }]) + return Promise.resolve({ recorded: true }) }, }) diff --git a/packages/subagent/subagent-inprocess/tests/structured.spec.ts b/packages/subagent/subagent-inprocess/tests/structured.spec.ts index 56a78a225f..a41ede8b86 100644 --- a/packages/subagent/subagent-inprocess/tests/structured.spec.ts +++ b/packages/subagent/subagent-inprocess/tests/structured.spec.ts @@ -8,7 +8,7 @@ import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-test import * as Invariants from '@deepseek-ai/dsh-invariants' import SubagentService, { type SubagentStartRequest } from '@deepseek-ai/dsh-subagent' import type { Config as ToolConfig, ObjectJsonSchema } from '@deepseek-ai/dsh-tools' -import { RUN_CODE_NAME } from '@deepseek-ai/dsh-tools' +import { defineContentToolFixture, RUN_CODE_NAME } from '@deepseek-ai/dsh-tools' import { MockAdapter, textResponse, toolCallResponse } from '../../../core/agent-loop/tests/mock-adapter.ts' import { startInProcessRun } from '../src/index.ts' import { @@ -85,10 +85,15 @@ describe('in-process structured output', () => { const { ctx, parent } = await setup([ toolCallResponse('c1', STRUCTURED_OUTPUT_TOOL, { answer: 42, note: 'done' }), ]) + let acknowledgement: unknown + ctx.on('tools/result', (exec, toolResult) => { + if (exec.name === STRUCTURED_OUTPUT_TOOL && !toolResult.isError) acknowledgement = toolResult.value + }) const run = await ctx.subagents.start('spawn', structuredRequest(parent)) const result = await run.result expect(result.stopReason).toBe('completed') expect(result.structured).toEqual({ answer: 42, note: 'done' }) + expect(acknowledgement).toEqual({ recorded: true }) await run.dispose() }) @@ -119,15 +124,15 @@ describe('in-process structured output', () => { ] as Script[number] const { ctx, parent } = await setup([response]) let sideEffectRan = false - ctx.tools.register({ + ctx.tools.register(defineContentToolFixture({ name: 'side_effect', description: 'probe', - parameters: { type: 'object', properties: {} }, + parameters: {}, execute(): Promise<ContentBlock[]> { sideEffectRan = true return Promise.resolve([{ type: 'text', text: 'ran' }]) }, - }) + })) const run = await ctx.subagents.start('spawn', structuredRequest(parent)) const result = await run.result expect(result.stopReason).toBe('completed') @@ -147,15 +152,15 @@ describe('in-process structured output', () => { ] as Script[number] const { ctx, parent } = await setup([response]) let sideEffectRan = false - ctx.tools.register({ + ctx.tools.register(defineContentToolFixture({ name: 'side_effect', description: 'probe', - parameters: { type: 'object', properties: {} }, + parameters: {}, execute(): Promise<ContentBlock[]> { sideEffectRan = true return Promise.resolve([{ type: 'text', text: 'ran' }]) }, - }) + })) const run = await ctx.subagents.start('spawn', structuredRequest(parent)) // Registered after the child and prepended: this listener returns allow // after every downstream pre-execute decision. The service-owned guard @@ -184,15 +189,15 @@ describe('in-process structured output', () => { ] as Script[number] const { ctx, parent } = await setup([response]) let sideEffectRan = false - ctx.tools.register({ + ctx.tools.register(defineContentToolFixture({ name: 'side_effect', description: 'probe', - parameters: { type: 'object', properties: {} }, + parameters: {}, execute(): Promise<ContentBlock[]> { sideEffectRan = true return Promise.resolve([{ type: 'text', text: 'ran' }]) }, - }) + })) const run = await ctx.subagents.start('spawn', structuredRequest(parent)) const result = await run.result // The call ran BEFORE captured was set: the deny gate only guards the @@ -589,12 +594,12 @@ describe('in-process structured output', () => { ]) // A global tool sorts lexicographically after structured_output, while a // global section above the 190 band follows the capture instruction. - ctx.tools.register({ + ctx.tools.register(defineContentToolFixture({ name: 'zz_probe', description: 'probe', - parameters: { type: 'object', properties: {} }, + parameters: {}, execute: () => Promise.resolve([{ type: 'text', text: 'x' }]), - }) + })) ctx.systemPrompt.section({ name: 'after-band', order: 200, text: 'AFTER-BAND' }) const run = await ctx.subagents.start('spawn', structuredRequest(parent)) await run.result @@ -646,7 +651,7 @@ describe('in-process structured output', () => { agent: parent, }) expect(result.isError).toBe(true) - expect(result.error?.code).toBe('UNKNOWN_TOOL') + expect(result.error?.info?.code).toBe('UNKNOWN_TOOL') }) it('a structured_output call with NO calling agent at all is UNKNOWN_TOOL', async () => { @@ -657,7 +662,7 @@ describe('in-process structured output', () => { arguments: { answer: 1 }, }) expect(result.isError).toBe(true) - expect(result.error?.code).toBe('UNKNOWN_TOOL') + expect(result.error?.info?.code).toBe('UNKNOWN_TOOL') }) it('a failed execution stage is discarded and never promoted by a later call', async () => { diff --git a/packages/subagent/subagent-spawn/tests/subagent-spawn.spec.ts b/packages/subagent/subagent-spawn/tests/subagent-spawn.spec.ts index 7de5f6f4d6..368e3700c9 100644 --- a/packages/subagent/subagent-spawn/tests/subagent-spawn.spec.ts +++ b/packages/subagent/subagent-spawn/tests/subagent-spawn.spec.ts @@ -10,6 +10,7 @@ import SubagentService, { type SubagentStartRequest } from '@deepseek-ai/dsh-sub import { MockAdapter, maxTokensResponse, textResponse, toolCallResponse } from '../../../core/agent-loop/tests/mock-adapter.ts' import * as spawn from '../src/index.ts' import { STRUCTURED_OUTPUT_TOOL } from '@deepseek-ai/dsh-subagent-inprocess' +import { defineContentToolFixture } from '@deepseek-ai/dsh-tools' type Script = ConstructorParameters<typeof MockAdapter>[0] @@ -383,10 +384,10 @@ describe('dsh-subagent-spawn', () => { toolCallResponse('c1', 'forbidden_tool', {}), textResponse('done'), ]) - ctx.tools.register({ + ctx.tools.register(defineContentToolFixture({ name: 'forbidden_tool', description: 'global', parameters: {}, execute: () => Promise.resolve([{ type: 'text', text: 'ran' }]), - }) + })) const run = await start(ctx, 'spawn', { prompt: [{ type: 'text', text: 'do X' }], parent, diff --git a/packages/subagent/tool-subagent/README.md b/packages/subagent/tool-subagent/README.md index e2af5ac552..08e143f94d 100644 --- a/packages/subagent/tool-subagent/README.md +++ b/packages/subagent/tool-subagent/README.md @@ -6,9 +6,9 @@ The model-facing delegation tool over one configured `ctx.subagents` provider. C Each plugin instance binds one `provider` to one `toolName`; the model receives no provider selector. Load another distinctly named instance to expose another transport. The tool registers only while its provider exists, avoiding sibling load-order and provider-reload dependencies. Its description follows `provider.inheritsParentContext`: fresh children require standalone prompts, while forked children already see completed parent turns. -A foreground call passes the execution signal through startup and execution, awaits `run.result`, and always awaits `run.dispose()` before returning. Only `completed` returns final text; abort, refusal, token limit, and other failures become errored tool results without partial output. +A foreground call passes the execution signal through startup and execution, awaits `run.result`, and always awaits `run.dispose()` before returning. Only `completed` returns the canonical `{ kind: 'foreground', runId, output: JsonValue[] }`, rendered as the same final text; abort, refusal, token limit, and other failures become errored tool results without partial output. -With `run_in_background: true`, the tool registers the parent-owned task before starting the provider. A task-owned signal covers pending startup and the child after the starting call returns. `task_kill` and owner disposal abort it. Settlement awaits startup rollback or child disposal, then maps completed final text, abort to `killed`, and other failures to `failed`. The task has no incremental read; generic task tools own later status, collection, cancellation, and notices. See the [background subagent Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-background-subagent-tasks.md). +With `run_in_background: true`, the tool registers the parent-owned task before starting the provider and returns canonical `{ kind: 'background', taskId }`, rendered as `started background subagent task <id>`. A task-owned signal covers pending startup and the child after the starting call returns. `task_kill` and owner disposal abort it. Settlement awaits startup rollback or child disposal, then maps completed final text, abort to `killed`, and other failures to `failed`. The task has no incremental read; generic task tools own later status, collection, cancellation, and notices. See the [background subagent Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-background-subagent-tasks.md). `toolFilter` changes the child's global tool layer but is not a parent-derived authority ceiling. See the [agent-scope security non-goal](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals). diff --git a/packages/subagent/tool-subagent/src/index.ts b/packages/subagent/tool-subagent/src/index.ts index bcd28c6ab1..2af2c58dc6 100644 --- a/packages/subagent/tool-subagent/src/index.ts +++ b/packages/subagent/tool-subagent/src/index.ts @@ -12,6 +12,7 @@ import z from 'schemastery' import { defineTool } from '@deepseek-ai/dsh-tools' import type { Agent, AgentOptions } from '@deepseek-ai/dsh-agent' import type { ContentBlock } from '@deepseek-ai/dsh-llm' +import type { JsonValue } from '@deepseek-ai/dsh-session' import { assertSubagentMaxDepth } from '@deepseek-ai/dsh-subagent' import type { SubagentProvider, SubagentResult, SubagentRun, SubagentStartRequest } from '@deepseek-ai/dsh-subagent' import type { TaskOutcome } from '@deepseek-ai/dsh-tasks' @@ -95,6 +96,16 @@ function outputText(blocks: ContentBlock[]): string { .join('') } +/** Render text blocks from the canonical JSON block array without trusting arbitrary values. */ +function outputValueText(values: JsonValue[]): string { + return values + .filter((value): value is { type: 'text'; text: string } => + typeof value === 'object' && value !== null && !Array.isArray(value) + && value.type === 'text' && typeof value.text === 'string') + .map(value => value.text) + .join('') +} + /** A non-`completed` stop reason means the child did not finish cleanly. */ function stopReasonError(result: SubagentResult): string | undefined { switch (result.stopReason) { @@ -268,7 +279,36 @@ export function apply(ctx: Context, config: Config): void { }, } : {}, }, - async execute(args, exec): Promise<ContentBlock[]> { + output: { + schema: { + oneOf: [ + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'background' }, + taskId: { type: 'string', required: true }, + }, + }, + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'foreground' }, + runId: { type: 'string', required: true }, + output: { type: 'array', required: true, items: { type: 'json' } }, + }, + }, + ], + }, + render: (_args, value) => [{ + type: 'text', + text: value.kind === 'background' + ? `started background subagent task ${value.taskId}` + : outputValueText(value.output), + }], + }, + async execute(args, exec) { const parent = exec.agent if (!parent) { // Non-agent callers provide no parent for delegation ownership. @@ -308,7 +348,7 @@ export function apply(ctx: Context, config: Config): void { } }, }) - return [{ type: 'text', text: `started background subagent task ${id}` }] + return { kind: 'background' as const, taskId: id } } const request = startRequest( @@ -327,7 +367,13 @@ export function apply(ctx: Context, config: Config): void { // The registry converts this throw to isError; partial output is not success. throw new Error(error) } - return [{ type: 'text', text: outputText(result.output) }] + return { + kind: 'foreground' as const, + runId: run.id, + // Content blocks already cross durable JSON boundaries elsewhere; + // the registry performs the authoritative lossless snapshot here. + output: result.output as unknown as JsonValue[], + } } finally { // Dispose before returning so no child session outlives the call. await run.dispose() diff --git a/packages/subagent/tool-subagent/tests/tool-subagent.spec.ts b/packages/subagent/tool-subagent/tests/tool-subagent.spec.ts index 9e4d68c08c..a679b236fc 100644 --- a/packages/subagent/tool-subagent/tests/tool-subagent.spec.ts +++ b/packages/subagent/tool-subagent/tests/tool-subagent.spec.ts @@ -62,6 +62,12 @@ describe('dsh-tool-subagent', () => { const ctx = await setup({ provider: 'mock' }, { reply: 'child says hi' }) const result = await callSubagent(ctx, { description: 'do a thing', prompt: 'go research X' }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected subagent success') + expect(result.value).toEqual({ + kind: 'foreground', + runId: 'scripted-subagent:mock:parent-1', + output: [{ type: 'text', text: 'child says hi' }], + }) expect(text(result)).toBe('child says hi') }) @@ -637,6 +643,8 @@ describe('dsh-tool-subagent background mode', () => { const start = await callSubagent(ctx, { description: 'deep research', prompt: 'dig in', run_in_background: true }, { agent: parent }) expect(start.isError).toBe(false) + if (start.isError) throw new Error('expected background subagent success') + expect(start.value).toEqual({ kind: 'background', taskId: 'subagent-1' }) expect(text(start)).toBe('started background subagent task subagent-1') const collected = await ctx.tools.execute({ diff --git a/packages/support/invariants/src/index.ts b/packages/support/invariants/src/index.ts index 91b4da4566..4a6b39be72 100644 --- a/packages/support/invariants/src/index.ts +++ b/packages/support/invariants/src/index.ts @@ -165,7 +165,7 @@ function validateEvent(trace: SessionTrace, event: SessionEvent): SessionTraceTr // A result needs a prior matching call in the same step. (The converse // does NOT hold: a call may have no result — a throwing tool-execution // pipeline step ends the turn with no tool/result, which is legal.) - const syntheticInterrupted = event.data.isError && event.data.error?.code === 'interrupted' + const syntheticInterrupted = event.data.isError && event.data.error?.info?.code === 'interrupted' if (!trace.pendingCalls.has(event.data.callId) && !syntheticInterrupted) { throw new InvariantError(`tool/result for ${event.data.callId} with no prior tool/call in this step`) } diff --git a/packages/support/invariants/tests/invariants.spec.ts b/packages/support/invariants/tests/invariants.spec.ts index 4f066eff8c..e9a09ea356 100644 --- a/packages/support/invariants/tests/invariants.spec.ts +++ b/packages/support/invariants/tests/invariants.spec.ts @@ -217,7 +217,7 @@ describe('session-log invariants', () => { callId: CallId('crashed'), content: [{ type: 'text', text: 'interrupted' }], isError: true, - error: { name: 'InterruptedError', code: 'interrupted' }, + error: { message: 'interrupted', info: { name: 'InterruptedError', code: 'interrupted' } }, }, { surfaceOp: 'append' }) session.append('step/end', { turn: 1, step: 1 }) session.append('turn/end', { turn: 1, reason: { kind: 'interrupted' } }) @@ -500,7 +500,7 @@ describe('surface contract under the invariants composition', () => { callId: CallId('rewrite'), content: [{ type: 'text' as const, text: 'original' }], isError: true, - error: { name: 'ExitError', code: 'EXIT_1' }, + error: { message: 'exit 1', info: { name: 'ExitError', code: 'EXIT_1' } }, meta: { presentation: { kind: 'terminal', output: 'full output' } }, futureField: { nested: ['preserve', 1] }, } @@ -585,7 +585,7 @@ describe('surface contract under the invariants composition', () => { ['callId', { callId: CallId('forged') }], ['turn', { turn: 2 }], ['step', { step: 2 }], - ['error', { error: { name: 'ExitError', code: 'DIFFERENT' } }], + ['error', { error: { message: 'exit 1', info: { name: 'ExitError', code: 'DIFFERENT' } } }], ['meta', { meta: { presentation: { kind: 'generic' } } }], ['future data', { futureField: { nested: ['changed'] } }], ])('rejects a content rewrite with altered %s', async (_label, altered) => { diff --git a/packages/tasks/tool-tasks/README.md b/packages/tasks/tool-tasks/README.md index 7e1ab82971..69063b681c 100644 --- a/packages/tasks/tool-tasks/README.md +++ b/packages/tasks/tool-tasks/README.md @@ -10,6 +10,8 @@ The model-facing control surface for `ctx.tasks`: three kind-independent tools, All three use generic ACP cards: `read` for output and list, `execute` for kill. +Their canonical values are `{ text, task }`, `PublicTaskSnapshot[]`, and `{ outcome: 'cancellation-requested' | 'already-finished', task }`. A public snapshot carries id, kind, label, status/detail, and start/finish times; it deliberately omits `ownerSession` and the internal `reported` notice bit. Native renderers preserve the status and acknowledgement text above. + ## Completion notices An unreported completion injects `background task <id> (<kind>: <label>) finished [status: ...]. Read its output with task_output.` into the exact owner's session. Injection is durable context for the next request, not a wake-up. A kill or terminal read/wait marks delivery reported and suppresses the redundant notice; owner-disposal races are contained. diff --git a/packages/tasks/tool-tasks/src/index.ts b/packages/tasks/tool-tasks/src/index.ts index 3f8256be15..f4546a7088 100644 --- a/packages/tasks/tool-tasks/src/index.ts +++ b/packages/tasks/tool-tasks/src/index.ts @@ -30,12 +30,55 @@ export const Config: z<Config> = z.object({ maxWaitTimeoutMs: z.number().min(1).default(600_000), }) +/** Task state safe for model-authored programs; ownership/bookkeeping fields are omitted. */ +export interface PublicTaskSnapshot { + id: string + kind: string + label: string + status: TaskSnapshot['status'] + detail?: string + startedAt: number + finishedAt?: number +} + +/** Shared schema for task-control outputs. */ +const PUBLIC_TASK_SCHEMA = { + type: 'object', + additionalProperties: false, + properties: { + id: { type: 'string', required: true }, + kind: { type: 'string', required: true }, + label: { type: 'string', required: true }, + status: { + type: 'string', + required: true, + enum: ['running', 'stopping', 'completed', 'killed', 'failed'], + }, + detail: { type: 'string' }, + startedAt: { type: 'integer', required: true }, + finishedAt: { type: 'integer' }, + }, +} as const + +/** Remove task ownership and notification bookkeeping from a registry snapshot. */ +function publicTask(snapshot: TaskSnapshot): PublicTaskSnapshot { + return { + id: snapshot.id, + kind: snapshot.kind, + label: snapshot.label, + status: snapshot.status, + ...snapshot.detail !== undefined ? { detail: snapshot.detail } : {}, + startedAt: snapshot.startedAt, + ...snapshot.finishedAt !== undefined ? { finishedAt: snapshot.finishedAt } : {}, + } +} + /** * Render generic status with optional producer detail. * @param snapshot - task state to render. * @returns a bracketed status line. */ -export function statusLine(snapshot: TaskSnapshot): string { +export function statusLine(snapshot: Pick<TaskSnapshot, 'status' | 'detail'>): string { return snapshot.detail !== undefined ? `[status: ${snapshot.status}, ${snapshot.detail}]` : `[status: ${snapshot.status}]` @@ -98,6 +141,21 @@ export function apply(ctx: Context, config: Config): void { wait: { type: 'boolean', description: 'Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task alive.' }, timeout_ms: { type: 'number', description: 'Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum.' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + text: { type: 'string', required: true }, + task: { ...PUBLIC_TASK_SCHEMA, required: true }, + }, + }, + render: (_args, value) => { + const body = value.text.length > 0 ? value.text : '(no new output)' + const separator = body.endsWith('\n') ? '' : '\n' + return [{ type: 'text', text: `${body}${separator}${statusLine(value.task)}` }] + }, + }, async execute(args, exec) { const id = validateTaskId(args.task_id) if (args.wait === true) { @@ -105,9 +163,7 @@ export function apply(ctx: Context, config: Config): void { await ctx.tasks.wait(id, timeout, exec.agent, exec.signal) } const read = ctx.tasks.read(id, exec.agent) - const body = read.text.length > 0 ? read.text : '(no new output)' - const separator = body.endsWith('\n') ? '' : '\n' - return [{ type: 'text', text: `${body}${separator}${statusLine(read.snapshot)}` }] + return { text: read.text, task: publicTask(read.snapshot) } }, presentCall: args => presentTaskCall(`Read output from background task ${args.task_id}`, 'read', args.task_id), })) @@ -116,12 +172,18 @@ export function apply(ctx: Context, config: Config): void { name: 'task_list', description: 'List your background tasks (running and finished) with their ids, kinds, and statuses.', parameters: {}, + output: { + schema: { type: 'array', items: PUBLIC_TASK_SCHEMA }, + render: (_args, tasks) => [{ + type: 'text', + text: tasks.length === 0 + ? '(no background tasks)' + : tasks.map(t => `${t.id} [${t.kind}] ${t.status} — ${t.label}`).join('\n'), + }], + }, execute(_args, exec) { const tasks = ctx.tasks.list(exec.agent) - const text = tasks.length === 0 - ? '(no background tasks)' - : tasks.map(t => `${t.id} [${t.kind}] ${t.status} — ${t.label}`).join('\n') - return Promise.resolve([{ type: 'text', text }]) + return Promise.resolve(tasks.map(publicTask)) }, presentCall: () => presentTaskCall('List background tasks', 'read'), })) @@ -133,15 +195,35 @@ export function apply(ctx: Context, config: Config): void { task_id: { type: 'string', required: true, description: 'Task id returned by the tool that started the background work.' }, reason: { type: 'string', description: 'Optional short reason, recorded in the log and forwarded to the task.' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + outcome: { + type: 'string', + required: true, + enum: ['cancellation-requested', 'already-finished'], + }, + task: { ...PUBLIC_TASK_SCHEMA, required: true }, + }, + }, + render: (_args, value) => [{ + type: 'text', + text: value.outcome === 'already-finished' + ? `task ${value.task.id} had already finished ${statusLine(value.task)}` + : `requested cancellation of task ${value.task.id}`, + }], + }, execute(args, exec) { const id = validateTaskId(args.task_id) const result = ctx.tasks.kill(id, exec.agent, args.reason) - if (result === 'already-finished') { - // A snapshot describes terminal state without consuming pending output. - const snapshot = ctx.tasks.get(id, exec.agent) - return Promise.resolve([{ type: 'text', text: `task ${id} had already finished ${statusLine(snapshot)}` }]) - } - return Promise.resolve([{ type: 'text', text: `requested cancellation of task ${id}` }]) + // A snapshot describes current state without consuming pending output. + const snapshot = publicTask(ctx.tasks.get(id, exec.agent)) + return Promise.resolve({ + outcome: result === 'already-finished' ? 'already-finished' as const : 'cancellation-requested' as const, + task: snapshot, + }) }, presentCall: args => presentTaskCall(`Kill background task ${args.task_id}`, 'execute', args.task_id), })) diff --git a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts index 0a2d89431e..3753742fc6 100644 --- a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts +++ b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts @@ -114,7 +114,16 @@ describe('task_output', () => { ctx.tasks.start(producer({ readOutput: () => chunks.shift() ?? '' }).spec) // A body already ending in a newline gets no doubled separator. - expect(text(await call(ctx, 'task_output', { task_id: 'bash-1' }))).toBe('line one\n[status: running]') + const first = await call(ctx, 'task_output', { task_id: 'bash-1' }) + if (first.isError) throw new Error('expected task_output success') + const firstValue = first.value as { text: string; task: Record<string, unknown> } + expect(firstValue).toMatchObject({ + text: 'line one\n', + task: { id: 'bash-1', kind: 'bash', label: 'sleep 60', status: 'running' }, + }) + expect(firstValue.task).not.toHaveProperty('ownerSession') + expect(firstValue.task).not.toHaveProperty('reported') + expect(text(first)).toBe('line one\n[status: running]') expect(text(await call(ctx, 'task_output', { task_id: 'bash-1' }))).toBe('(no new output)\n[status: running]') }) @@ -171,7 +180,17 @@ describe('task_list', () => { p.settle({ status: 'completed', detail: 'exit code: 0' }) await tick() - expect(text(await call(ctx, 'task_list', {}, alice))).toBe([ + const listed = await call(ctx, 'task_list', {}, alice) + if (listed.isError) throw new Error('expected task_list success') + const listedValue = listed.value as Array<Record<string, unknown>> + expect(listedValue).toHaveLength(3) + expect(listedValue[0]).toMatchObject({ id: 'bash-1', kind: 'bash', label: 'pnpm test', status: 'running' }) + expect(listedValue[2]).toMatchObject({ id: 'bash-2', kind: 'bash', label: 'build', status: 'completed', detail: 'exit code: 0' }) + for (const task of listedValue) { + expect(task).not.toHaveProperty('ownerSession') + expect(task).not.toHaveProperty('reported') + } + expect(text(listed)).toBe([ 'bash-1 [bash] running — pnpm test', 'subagent-1 [subagent] running — open research', 'bash-2 [bash] completed — build', @@ -189,6 +208,14 @@ describe('task_kill', () => { ctx.tasks.start(p.spec) const result = await call(ctx, 'task_kill', { task_id: 'bash-1', reason: 'superseded' }) + if (result.isError) throw new Error('expected task_kill success') + const killValue = result.value as { outcome: string; task: Record<string, unknown> } + expect(killValue).toMatchObject({ + outcome: 'cancellation-requested', + task: { id: 'bash-1', kind: 'bash', label: 'sleep 60', status: 'stopping' }, + }) + expect(killValue.task).not.toHaveProperty('ownerSession') + expect(killValue.task).not.toHaveProperty('reported') expect(text(result)).toBe('requested cancellation of task bash-1') expect(p.cancels).toEqual(['superseded']) }) @@ -201,8 +228,13 @@ describe('task_kill', () => { p.settle({ status: 'completed', detail: 'exit code: 0' }) await tick() - expect(text(await call(ctx, 'task_kill', { task_id: 'bash-1' }))) - .toBe('task bash-1 had already finished [status: completed, exit code: 0]') + const killed = await call(ctx, 'task_kill', { task_id: 'bash-1' }) + if (killed.isError) throw new Error('expected task_kill success') + expect(killed.value).toMatchObject({ + outcome: 'already-finished', + task: { id: 'bash-1', kind: 'bash', label: 'sleep 60', status: 'completed', detail: 'exit code: 0' }, + }) + expect(text(killed)).toBe('task bash-1 had already finished [status: completed, exit code: 0]') // The kill described the task via a non-consuming snapshot: the delta is intact. expect(text(await call(ctx, 'task_output', { task_id: 'bash-1' }))).toBe('unread tail\n[status: completed, exit code: 0]') }) diff --git a/packages/timeout/timeout-policy/README.md b/packages/timeout/timeout-policy/README.md index 60b590a7f8..aea741d1fe 100644 --- a/packages/timeout/timeout-policy/README.md +++ b/packages/timeout/timeout-policy/README.md @@ -19,7 +19,7 @@ For a tool that **declares a `timeoutMs`** the listener: 1. Reads the budget from the tool's own declaration in the registry (`ctx.tools.get(exec.name)?.timeoutMs`) and arms `deadline(exec.signal, timeoutMs, 'TOOL_TIMEOUT')` — one signal fusing the caller's abort with this plugin's timer (`@deepseek-ai/dsh-timeout`). 2. Swaps that derived signal onto `exec` for the downstream dispatch, then restores the caller's own signal afterward (cordis `next()` ignores passed arguments, so the wrapper mutates the shared `exec` in place; restoring keeps `tools/post-execute` seeing the caller's signal). -3. After dispatch, if `timeoutOf(d.signal, 'TOOL_TIMEOUT')` matches — this plugin's own timer fired — replaces the result with a structured `TOOL_TIMEOUT` tool result: `{ isError: true, error: { name: 'ToolTimeoutError', code: 'TOOL_TIMEOUT' }, content: 'Error: tool call timed out after <ms>ms' }`. +3. After dispatch, if `timeoutOf(d.signal, 'TOOL_TIMEOUT')` matches — this plugin's own timer fired — replaces the result with a structured `TOOL_TIMEOUT` tool result: `{ isError: true, error: { message, info: { name: 'ToolTimeoutError', code: 'TOOL_TIMEOUT' } }, content: 'Error: tool call timed out after <ms>ms' }`. A tool that **declares no budget** delegates untouched (no deadline). diff --git a/packages/timeout/timeout-policy/src/index.ts b/packages/timeout/timeout-policy/src/index.ts index e946c2af61..50526c4f4a 100644 --- a/packages/timeout/timeout-policy/src/index.ts +++ b/packages/timeout/timeout-policy/src/index.ts @@ -33,10 +33,11 @@ export const inject = ['tools'] * @returns the `isError` {@link ToolExecutionResult} with a `TOOL_TIMEOUT` error. */ function toolTimeoutResult(timeoutMs: number): ToolExecutionResult { + const message = `tool call timed out after ${timeoutMs}ms` return { - content: [{ type: 'text', text: `Error: tool call timed out after ${timeoutMs}ms` }], + content: [{ type: 'text', text: `Error: ${message}` }], isError: true, - error: { name: 'ToolTimeoutError', code: TOOL_TIMEOUT }, + error: { message, info: { name: 'ToolTimeoutError', code: TOOL_TIMEOUT } }, } } diff --git a/packages/timeout/timeout-policy/tests/timeout-policy.spec.ts b/packages/timeout/timeout-policy/tests/timeout-policy.spec.ts index bd06ed6e16..32ed4f2525 100644 --- a/packages/timeout/timeout-policy/tests/timeout-policy.spec.ts +++ b/packages/timeout/timeout-policy/tests/timeout-policy.spec.ts @@ -11,7 +11,7 @@ import { Context } from 'cordis' import Loader from '@cordisjs/plugin-loader' import { CallId, HarnessError } from '@deepseek-ai/dsh-llm' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { defineTool, type ToolExecutionInput, type PostToolDecision } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { defineContentToolFixture, type ToolExecutionInput, type PostToolDecision } from '@deepseek-ai/dsh-tools' import * as timeoutPolicy from '@deepseek-ai/dsh-timeout-policy' import { TOOL_TIMEOUT } from '@deepseek-ai/dsh-timeout-policy' @@ -25,7 +25,7 @@ async function setup() { } /** A cooperative tool that settles ONLY when its exec.signal aborts (returns text). */ -const cooperativeTool = defineTool({ +const cooperativeTool = defineContentToolFixture({ name: 'slow', description: 'stops when aborted', parameters: {}, timeoutMs: 100, execute(_args, exec): Promise<{ type: 'text'; text: string }[]> { const done = [{ type: 'text' as const, text: 'stopped cooperatively' }] @@ -35,7 +35,7 @@ const cooperativeTool = defineTool({ }) /** A cooperative tool that THROWS its own upstream-abort error when aborted (web-provider shape). */ -const abortThrowingTool = defineTool({ +const abortThrowingTool = defineContentToolFixture({ name: 'aborter', description: 'throws WEB_ABORTED when aborted', parameters: {}, timeoutMs: 100, execute(_args, exec): Promise<never> { if (exec.signal?.aborted) return Promise.reject(new HarnessError('web fetch aborted', 'WEB_ABORTED')) @@ -47,7 +47,7 @@ describe('timeout-policy delegation (unconfigured / fast)', () => { it('delegates a tool with NO declared budget unchanged and does not touch exec.signal', async () => { const ctx = await setup() let seenSignal: AbortSignal | undefined - ctx.tools.register(defineTool({ name: 'probe', description: 'd', parameters: {}, + ctx.tools.register(defineContentToolFixture({ name: 'probe', description: 'd', parameters: {}, async execute(_a, exec) { seenSignal = exec.signal; return [{ type: 'text' as const, text: 'ok' }] } })) const upstream = new AbortController().signal const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'probe', arguments: {}, signal: upstream }) @@ -57,16 +57,20 @@ describe('timeout-policy delegation (unconfigured / fast)', () => { it('a tool with a budget that returns fast keeps its own result (no timeout)', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ name: 'fast', description: 'd', parameters: {}, timeoutMs: 10_000, + ctx.tools.register(defineContentToolFixture({ name: 'fast', description: 'd', parameters: {}, timeoutMs: 10_000, async execute() { return [{ type: 'text' as const, text: 'ok' }] } })) const result = await ctx.tools.execute({ callId: CallId('c1'), name: 'fast', arguments: {} }) - expect(result).toEqual({ content: [{ type: 'text', text: 'ok' }], isError: false }) + expect(result).toEqual({ + content: [{ type: 'text', text: 'ok' }], + isError: false, + value: [{ type: 'text', text: 'ok' }], + }) }) it('a budgeted tool receives the DERIVED deadline signal (not the caller signal) during dispatch', async () => { const ctx = await setup() let seenSignal: AbortSignal | undefined - ctx.tools.register(defineTool({ name: 'probe', description: 'd', parameters: {}, timeoutMs: 10_000, + ctx.tools.register(defineContentToolFixture({ name: 'probe', description: 'd', parameters: {}, timeoutMs: 10_000, async execute(_a, exec) { seenSignal = exec.signal; return [{ type: 'text' as const, text: 'ok' }] } })) const upstream = new AbortController().signal await ctx.tools.execute({ callId: CallId('c1'), name: 'probe', arguments: {}, signal: upstream }) @@ -78,7 +82,7 @@ describe('timeout-policy delegation (unconfigured / fast)', () => { describe('timeout-policy signal restoration', () => { it('restores the caller signal for post-execute after wrapping', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ name: 'fast', description: 'd', parameters: {}, timeoutMs: 10_000, + ctx.tools.register(defineContentToolFixture({ name: 'fast', description: 'd', parameters: {}, timeoutMs: 10_000, async execute() { return [{ type: 'text' as const, text: 'ok' }] } })) let postSignal: AbortSignal | undefined | 'unset' = 'unset' ctx.on('tools/post-execute', async (exec, _result, next): Promise<PostToolDecision> => { postSignal = exec.signal; return next() }) @@ -89,7 +93,7 @@ describe('timeout-policy signal restoration', () => { it('deletes exec.signal again when the caller passed none', async () => { const ctx = await setup() - ctx.tools.register(defineTool({ name: 'fast', description: 'd', parameters: {}, timeoutMs: 10_000, + ctx.tools.register(defineContentToolFixture({ name: 'fast', description: 'd', parameters: {}, timeoutMs: 10_000, async execute() { return [{ type: 'text' as const, text: 'ok' }] } })) let hadSignal: boolean | undefined ctx.on('tools/post-execute', async (exec, _result, next): Promise<PostToolDecision> => { hadSignal = 'signal' in exec && exec.signal !== undefined; return next() }) @@ -111,7 +115,10 @@ describe('timeout-policy TOOL_TIMEOUT replacement (deadline wins)', () => { expect(result).toEqual({ content: [{ type: 'text', text: 'Error: tool call timed out after 100ms' }], isError: true, - error: { name: 'ToolTimeoutError', code: 'TOOL_TIMEOUT' }, + error: { + message: 'tool call timed out after 100ms', + info: { name: 'ToolTimeoutError', code: 'TOOL_TIMEOUT' }, + }, }) }) @@ -122,7 +129,10 @@ describe('timeout-policy TOOL_TIMEOUT replacement (deadline wins)', () => { await vi.advanceTimersByTimeAsync(150) const result = await pending expect(result.isError).toBe(true) - expect(result.error).toEqual({ name: 'ToolTimeoutError', code: 'TOOL_TIMEOUT' }) + expect(result.error).toEqual({ + message: 'tool call timed out after 100ms', + info: { name: 'ToolTimeoutError', code: 'TOOL_TIMEOUT' }, + }) expect(result.content[0]).toMatchObject({ text: 'Error: tool call timed out after 100ms' }) }) @@ -151,7 +161,7 @@ describe('timeout-policy disposal (HMR safety)', () => { await ctx.plugin(SystemPrompt) await ctx.plugin(ToolRegistry) let seenSignal: AbortSignal | undefined - ctx.tools.register(defineTool({ name: 'probe', description: 'd', parameters: {}, timeoutMs: 10_000, + ctx.tools.register(defineContentToolFixture({ name: 'probe', description: 'd', parameters: {}, timeoutMs: 10_000, async execute(_a, exec) { seenSignal = exec.signal; return [{ type: 'text' as const, text: 'ok' }] } })) const fiber = await ctx.plugin(timeoutPolicy) const upstream = new AbortController().signal @@ -178,7 +188,7 @@ describe('dsh-timeout-policy real-load-path guard', () => { const ctx = new Context() await ctx.plugin(SystemPrompt) await ctx.plugin(ToolRegistry) - ctx.tools.register(defineTool({ name: 'fast', description: 'd', parameters: {}, timeoutMs: 5_000, + ctx.tools.register(defineContentToolFixture({ name: 'fast', description: 'd', parameters: {}, timeoutMs: 5_000, async execute() { return [{ type: 'text' as const, text: 'ok' }] } })) const loader = Object.create(Loader.prototype) as Loader const unwrapped = loader.unwrapExports(timeoutPolicy) as Parameters<Context['plugin']>[0] diff --git a/packages/todo/tool-todo/README.md b/packages/todo/tool-todo/README.md index 2ccdd7699e..febb2c9ce0 100644 --- a/packages/todo/tool-todo/README.md +++ b/packages/todo/tool-todo/README.md @@ -18,7 +18,7 @@ Beyond the schema's type/required/enum checks, `execute` rejects an empty or dup ## Rendering -The tool writes only the session event; it does not render. UIs subscribe to `session/event` and render the `todo/write` data themselves: the [TUI app](../../examples/tui-demo) shows a persistent plan, and the [ACP bridge](../../ui/acp) maps the list to a `plan` sessionUpdate (synthesizing the `priority` ACP requires). +The canonical result is `{ todos, counts: { pending, inProgress, completed } }`; its Native renderer returns the compact update acknowledgement. The tool also writes the full `todo/write` session event. UIs subscribe to `session/event` and render that durable list themselves: the [TUI app](../../examples/tui-demo) shows a persistent plan, and the [ACP bridge](../../ui/acp) maps the list to a `plan` sessionUpdate (synthesizing the `priority` ACP requires). ## Export shape diff --git a/packages/todo/tool-todo/src/index.ts b/packages/todo/tool-todo/src/index.ts index 919e53f7bb..1da9914ac9 100644 --- a/packages/todo/tool-todo/src/index.ts +++ b/packages/todo/tool-todo/src/index.ts @@ -6,7 +6,6 @@ */ import type { Context } from 'cordis' -import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { defineTool } from '@deepseek-ai/dsh-tools' import type { TodoItem } from '@deepseek-ai/dsh-session' @@ -80,7 +79,41 @@ export function apply(ctx: Context): void { }, }, }, - execute(args, exec): Promise<ContentBlock[]> { + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + todos: { + type: 'array', + required: true, + items: { + type: 'object', + additionalProperties: false, + properties: { + content: { type: 'string', required: true }, + status: { type: 'string', required: true, enum: [...STATUSES] }, + }, + }, + }, + counts: { + type: 'object', + additionalProperties: false, + required: true, + properties: { + pending: { type: 'integer', required: true }, + inProgress: { type: 'integer', required: true }, + completed: { type: 'integer', required: true }, + }, + }, + }, + }, + render: (_args, value) => [{ + type: 'text', + text: `Updated todo list: ${value.counts.pending} pending, ${value.counts.inProgress} in progress, ${value.counts.completed} completed.`, + }], + }, + execute(args, exec) { const todos = toTodoList(args.todos) if (!exec.agent) { // The list is per-agent-session state; a non-agent caller (no owning @@ -89,10 +122,14 @@ export function apply(ctx: Context): void { } exec.agent.session.append('todo/write', { todos }) const count = (status: TodoItem['status']): number => todos.filter(t => t.status === status).length - return Promise.resolve([{ - type: 'text', - text: `Updated todo list: ${count('pending')} pending, ${count('in_progress')} in progress, ${count('completed')} completed.`, - }]) + return Promise.resolve({ + todos: todos.map(todo => ({ content: todo.content, status: todo.status })), + counts: { + pending: count('pending'), + inProgress: count('in_progress'), + completed: count('completed'), + }, + }) }, presentCall: args => ({ card: 'generic', title: 'Update todo list', kind: 'other', rawInput: args.todos }), })) diff --git a/packages/todo/tool-todo/tests/tool-todo.spec.ts b/packages/todo/tool-todo/tests/tool-todo.spec.ts index 2059bf13e8..a8156f2ed4 100644 --- a/packages/todo/tool-todo/tests/tool-todo.spec.ts +++ b/packages/todo/tool-todo/tests/tool-todo.spec.ts @@ -70,6 +70,11 @@ describe('dsh-tool-todo', () => { ] const result = await callTodo(ctx, { todos }, { agent }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected todo_write success') + expect(result.value).toEqual({ + todos, + counts: { pending: 1, inProgress: 1, completed: 0 }, + }) expect(text(result)).toContain('1 pending, 1 in progress, 0 completed') const event = agent.session.events.findLast(e => e.type === 'todo/write')! diff --git a/packages/ui/acp/src/index.ts b/packages/ui/acp/src/index.ts index 62455223a4..8365b0590c 100644 --- a/packages/ui/acp/src/index.ts +++ b/packages/ui/acp/src/index.ts @@ -50,6 +50,7 @@ import type {} from '@deepseek-ai/dsh-llm-retry' import type { Agent } from '@deepseek-ai/dsh-agent' import type {} from '@deepseek-ai/dsh-commands' import { SessionId } from '@deepseek-ai/dsh-session' +import type { JsonValue } from '@deepseek-ai/dsh-session' // Side-effect type import: resolves `ctx.get('permission')` to the service. import type {} from '@deepseek-ai/dsh-permission' import type { SessionEvent, TodoItem, TurnEndReason } from '@deepseek-ai/dsh-session' @@ -1348,7 +1349,7 @@ export class ToolPresenter { * @param meta - the result's machine-readable meta, forwarded when present. * @returns a normalized tool-owned view or raw-content fallback. */ - result(callId: CallId, content: ContentBlock[], isError: boolean, meta?: unknown): ToolResultView { + result(callId: CallId, content: ContentBlock[], isError: boolean, meta?: JsonValue): ToolResultView { const call = this.pending.get(callId) this.pending.delete(callId) // No remembered call (unknown/late callId) → nothing to present from; raw content. diff --git a/packages/ui/acp/tests/stream-update.spec.ts b/packages/ui/acp/tests/stream-update.spec.ts index feda449054..d09628527d 100644 --- a/packages/ui/acp/tests/stream-update.spec.ts +++ b/packages/ui/acp/tests/stream-update.spec.ts @@ -10,6 +10,11 @@ import FsLocal from '@deepseek-ai/dsh-fs-local' import * as ToolFs from '@deepseek-ai/dsh-tool-fs' import { streamSessionEventUpdate, agentOptions, todosToPlan, ToolPresenter } from '../src/index.ts' +const UNUSED_TOOL_OUTPUT: ToolDefinition['output'] = { + schema: { type: 'null' }, + render: () => [], +} + /** Collect the updates a single event produces (no presenter → generic fallback). */ function updatesFor(event: SessionEvent): SessionNotification['update'][] { const out: SessionNotification['update'][] = [] @@ -232,6 +237,7 @@ describe('ToolPresenter (tool-owned presentation via the tool registry)', () => name: 'bash', description: 'run a command', parameters: {}, + output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: (args: unknown) => { const a = args as { command: string; description: string } @@ -289,7 +295,7 @@ describe('ToolPresenter (tool-owned presentation via the tool registry)', () => }) it('a tool with no presentCall/presentResult gets the generic fallback (title = name)', () => { - const plain: ToolDefinition = { name: 'plain', description: 'p', parameters: {}, execute: async () => [] } + const plain: ToolDefinition = { name: 'plain', description: 'p', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [] } const presenter = new ToolPresenter(registryOf(plain)) const [update] = updatesWith(presenter, evt('tool/call', { turn: 1, step: 1, callId: CallId('c1'), name: 'plain', arguments: '{"a":1}', @@ -305,6 +311,7 @@ describe('ToolPresenter (tool-owned presentation via the tool registry)', () => name: 'mini', description: 'm', parameters: {}, + output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'generic', title: 'Doing a thing' }), presentResult: () => ({ card: 'generic', title: 'Did the thing' }), @@ -351,6 +358,7 @@ describe('ToolPresenter (tool-owned presentation via the tool registry)', () => name: 'boom', description: 'b', parameters: {}, + output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => { throw new Error('call boom') }, presentResult: () => { throw new Error('result boom') }, @@ -380,6 +388,7 @@ describe('ToolPresenter (tool-owned presentation via the tool registry)', () => name: 'boom', description: 'b', parameters: {}, + output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => { throw new Error('call boom') }, presentResult: () => { throw new Error('result boom') }, @@ -403,6 +412,7 @@ describe('ToolPresenter (tool-owned presentation via the tool registry)', () => name: 'rogue', description: 'r', parameters: {}, + output: UNUSED_TOOL_OUTPUT, execute: async () => [], // A card value outside the union — forced with a cast (no valid input reaches this). presentCall: () => ({ card: 'chart', title: 'nope' }) as unknown as ReturnType<NonNullable<ToolDefinition['presentCall']>>, @@ -421,6 +431,7 @@ describe('ToolPresenter (tool-owned presentation via the tool registry)', () => name: 'rogue', description: 'r', parameters: {}, + output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'generic', title: 'r' }), presentResult: () => ({ card: 'chart' }) as unknown as ReturnType<NonNullable<ToolDefinition['presentResult']>>, @@ -483,6 +494,7 @@ describe('terminal-card mapping (capability-gated)', () => { name: 'bash', description: 'run a command', parameters: {}, + output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: (args: unknown) => { const command = (args as { command: string }).command @@ -644,6 +656,7 @@ describe('terminal-card mapping (capability-gated)', () => { name: 'bash', description: 'run a command', parameters: {}, + output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: (args: unknown) => ({ card: 'terminal', title: (args as { command: string }).command }), } @@ -666,6 +679,7 @@ describe('diff-card mapping', () => { name: 'writer', description: 'writes a file', parameters: {}, + output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => view as ReturnType<NonNullable<ToolDefinition['presentCall']>>, }) @@ -799,6 +813,7 @@ describe('result-time diff card (REAL fs edit tool → tool_call_update diff blo name: 'writer', description: 'writes a file', parameters: {}, + output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'diff', title: 'Write x', diffs: [{ path: 'x', oldText: null, newText: 'y' }] }), presentResult: () => ({ card: 'diff', diffs: [] }), diff --git a/packages/ui/acp/tests/turns.spec.ts b/packages/ui/acp/tests/turns.spec.ts index e3e8d679ea..fc2e390f31 100644 --- a/packages/ui/acp/tests/turns.spec.ts +++ b/packages/ui/acp/tests/turns.spec.ts @@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest' import { mkdtemp, rm } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' -import { defineTool } from '@deepseek-ai/dsh-tools' +import { defineContentToolFixture } from '@deepseek-ai/dsh-tools' import { PROTOCOL_VERSION } from '@agentclientprotocol/sdk' import { errorResponse, @@ -63,7 +63,7 @@ describe('acp bridge — turn outcomes', () => { storageDir, script: [toolCallResponse('c1', 'bash', { command: 'echo hi' }), textResponse('done')], }) - harness.ctx.tools.register(defineTool({ + harness.ctx.tools.register(defineContentToolFixture({ name: 'bash', description: 'run a command', parameters: { command: { type: 'string' } }, @@ -204,7 +204,7 @@ describe('acp bridge — turn outcomes', () => { storageDir, script: [toolCallResponse('c1', 'kaboom', { x: 1 }), textResponse('done')], }) - harness.ctx.tools.register(defineTool({ + harness.ctx.tools.register(defineContentToolFixture({ name: 'kaboom', description: 'explodes when presented', parameters: { x: { type: 'number' } }, @@ -227,7 +227,7 @@ describe('acp bridge — turn outcomes', () => { storageDir, script: [toolCallResponse('c1', 'bash', { command: 'boom' }), textResponse('ok')], }) - harness.ctx.tools.register(defineTool({ + harness.ctx.tools.register(defineContentToolFixture({ name: 'bash', description: 'run a command', parameters: { command: { type: 'string' } }, diff --git a/packages/ui/tool-ask-user/README.md b/packages/ui/tool-ask-user/README.md index 96d5a43856..ff67395800 100644 --- a/packages/ui/tool-ask-user/README.md +++ b/packages/ui/tool-ask-user/README.md @@ -13,7 +13,7 @@ Model-facing `ask_user_question` tool over `ctx.userInteraction`. It lets the mo - `options` — optional choices with `label` and `description`. If recommending a choice, put it first and append `(Recommended)` to that label. - `multi_select` — whether that question may return more than one selected option. -The tool calls `ctx.userInteraction.ask()` and returns JSON text shaped as `{ "answers": [{ "id": "...", "selected": ["..."], "custom": "..." }] }`. `selected` contains option labels; `custom` is present only for a free-form answer and overrides selected choices. +The tool calls `ctx.userInteraction.ask()` and returns canonical `{ answers: [{ id, selected, custom? }] }`. `selected` contains option labels; `custom` is present only for a free-form answer and overrides selected choices. The Native renderer preserves the compact JSON text shape `{ "answers": [{ "id": "...", "selected": ["..."], "custom": "..." }] }`. ## Role @@ -52,4 +52,4 @@ Append-only; newly visible content follows the reusable request prefix and does ## Known Limitations and Deferred Work - **A pending question blocks the tool call until the human answers** — the tool declares no `timeout-policy` budget; cancellation rides the turn's `exec.signal` only. -- **Answers return as JSON text** — the seam's structured `AskUserQuestionAnswer` is serialized into the tool result rather than carried as typed content blocks. +- **Native answers render as JSON text** — the canonical value remains structured, but the model-facing result uses compact JSON rather than a richer content-block vocabulary. diff --git a/packages/ui/tool-ask-user/src/index.ts b/packages/ui/tool-ask-user/src/index.ts index 47cb6e8d22..8498fc8caf 100644 --- a/packages/ui/tool-ask-user/src/index.ts +++ b/packages/ui/tool-ask-user/src/index.ts @@ -55,6 +55,28 @@ export function apply(ctx: Context): void { }, }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + answers: { + type: 'array', + required: true, + items: { + type: 'object', + additionalProperties: false, + properties: { + id: { type: 'string', required: true }, + selected: { type: 'array', required: true, items: { type: 'string' } }, + custom: { type: 'string' }, + }, + }, + }, + }, + }, + render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }], + }, async execute(args, exec) { const result = await ctx.userInteraction.ask({ questions: args.questions.map(question => ({ @@ -67,7 +89,13 @@ export function apply(ctx: Context): void { ...exec.agent !== undefined ? { agent: exec.agent } : {}, ...exec.signal !== undefined ? { signal: exec.signal } : {}, }) - return [{ type: 'text', text: JSON.stringify(result) }] + return { + answers: result.answers.map(answer => ({ + id: answer.id, + selected: [...answer.selected], + ...answer.custom !== undefined ? { custom: answer.custom } : {}, + })), + } }, })) } diff --git a/packages/ui/tool-ask-user/tests/tool-ask-user.spec.ts b/packages/ui/tool-ask-user/tests/tool-ask-user.spec.ts index ceff7df388..ca70cb4971 100644 --- a/packages/ui/tool-ask-user/tests/tool-ask-user.spec.ts +++ b/packages/ui/tool-ask-user/tests/tool-ask-user.spec.ts @@ -159,6 +159,14 @@ describe('ask_user_question tool', () => { }, }) + expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected ask_user_question success') + expect(result.value).toEqual({ + answers: [ + { id: 'targets', selected: ['tests', 'docs'] }, + { id: 'notes', selected: [], custom: 'ship today' }, + ], + }) expect(result.content).toEqual([{ type: 'text', text: '{"answers":[{"id":"targets","selected":["tests","docs"]},{"id":"notes","selected":[],"custom":"ship today"}]}', @@ -219,7 +227,7 @@ describe('ask_user_question tool', () => { expect(result).toMatchObject({ isError: true, - error: { name: 'UserInteractionError', code: 'NO_PROVIDER' }, + error: { info: { name: 'UserInteractionError', code: 'NO_PROVIDER' } }, }) }) @@ -234,7 +242,7 @@ describe('ask_user_question tool', () => { expect(result).toMatchObject({ isError: true, - error: { name: 'UserInteractionError', code: 'EMPTY_QUESTIONS' }, + error: { info: { name: 'UserInteractionError', code: 'EMPTY_QUESTIONS' } }, }) }) diff --git a/packages/ui/tui/src/index.ts b/packages/ui/tui/src/index.ts index cbb3593209..b87294764b 100644 --- a/packages/ui/tui/src/index.ts +++ b/packages/ui/tui/src/index.ts @@ -39,7 +39,7 @@ import type {} from '@deepseek-ai/dsh-commands' import { errorChain } from '@deepseek-ai/dsh-llm' import type { ContentBlock, StreamChunk, TokenUsage } from '@deepseek-ai/dsh-llm' import type {} from '@deepseek-ai/dsh-llm-retry' -import { SessionId, type Session, type SessionEvent, type TodoItem } from '@deepseek-ai/dsh-session' +import { SessionId, type JsonValue, type Session, type SessionEvent, type TodoItem } from '@deepseek-ai/dsh-session' import type { FileDiff, TerminalCallView, @@ -454,7 +454,7 @@ function diffLines(diff: FileDiff, palette: Palette): string[] { } class ToolCardComponent implements Component { - private result: { content: ContentBlock[]; isError: boolean; meta?: unknown } | undefined + private result: { content: ContentBlock[]; isError: boolean; meta?: JsonValue } | undefined private expanded = false private callView: ToolCallView private resultView: ToolResultView | undefined diff --git a/packages/ui/tui/tests/tui.snapshot.ts b/packages/ui/tui/tests/tui.snapshot.ts index b8afc452cb..5f6a4a5b44 100644 --- a/packages/ui/tui/tests/tui.snapshot.ts +++ b/packages/ui/tui/tests/tui.snapshot.ts @@ -5,7 +5,7 @@ import { afterAll, describe, expect, it } from 'vitest' import type { Context } from 'cordis' import { CallId, type ContentBlock } from '@deepseek-ai/dsh-llm' import type {} from '@deepseek-ai/dsh-llm-retry' -import type { Session } from '@deepseek-ai/dsh-session' +import type { JsonValue, Session } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import ToolRegistry, { type ToolDefinition, type ToolResultView } from '@deepseek-ai/dsh-tools' import * as ToolCordis from '@deepseek-ai/dsh-tool-cordis' @@ -131,7 +131,7 @@ function appendToolResult( session: Session, id: string, content: ContentBlock[], - options: { isError?: boolean; meta?: unknown } = {}, + options: { isError?: boolean; meta?: JsonValue } = {}, ): void { session.append('tool/result', { turn: 1, @@ -152,6 +152,7 @@ function visualTool( name, description: `${name} snapshot fixture`, parameters: {}, + output: { schema: { type: 'null' }, render: () => [] }, execute: () => Promise.resolve([]), presentCall: call, ...result === undefined ? {} : { presentResult: result }, diff --git a/packages/ui/tui/tests/tui.spec.ts b/packages/ui/tui/tests/tui.spec.ts index aa2ff5510e..01e5fe9bd4 100644 --- a/packages/ui/tui/tests/tui.spec.ts +++ b/packages/ui/tui/tests/tui.spec.ts @@ -23,6 +23,11 @@ import { type TuiHarnessOptions, } from './harness.ts' +const UNUSED_TOOL_OUTPUT: ToolDefinition['output'] = { + schema: { type: 'null' }, + render: () => [], +} + class FakeTerminal implements Terminal { columns = 88 rows = 32 @@ -645,17 +650,17 @@ describe('pi-tui chat lifecycle and transcript', () => { describe('tool cards and surface replay', () => { const tools: Record<string, ToolDefinition> = { bash: { - name: 'bash', description: '', parameters: {}, execute: async () => [], + name: 'bash', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'terminal', title: 'printf hello', description: 'Run command', cwd: '/tmp' }), presentResult: () => ({ card: 'terminal', output: 'hello\nworld\nthird', exitCode: 0 }), }, signal: { - name: 'signal', description: '', parameters: {}, execute: async () => [], + name: 'signal', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'terminal', title: 'sleep 10' }), presentResult: () => ({ card: 'terminal', signal: 'SIGTERM' }), }, edit: { - name: 'edit', description: '', parameters: {}, execute: async () => [], + name: 'edit', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'diff', title: 'Edit files', @@ -667,35 +672,35 @@ describe('tool cards and surface replay', () => { presentResult: () => ({ card: 'diff', diffs: [{ path: 'a.txt', oldText: null, newText: 'created' }] }), }, generic: { - name: 'generic', description: '', parameters: {}, execute: async () => [], + name: 'generic', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'generic', title: 'Inspect value', rawInput: { alpha: 1 } }), presentResult: () => ({ card: 'generic', title: 'Inspected', content: [{ type: 'text', text: 'result text' }] }), }, throwing: { - name: 'throwing', description: '', parameters: {}, execute: async () => [], + name: 'throwing', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => { throw new Error('call presenter boom') }, presentResult: () => { throw new Error('result presenter boom') }, }, rawTerminal: { - name: 'rawTerminal', description: '', parameters: {}, execute: async () => [], + name: 'rawTerminal', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'terminal', title: 'raw command' }), }, undefinedViews: { - name: 'undefinedViews', description: '', parameters: {}, execute: async () => [], + name: 'undefinedViews', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => undefined, presentResult: () => undefined, }, empty: { - name: 'empty', description: '', parameters: {}, execute: async () => [], + name: 'empty', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'generic', title: 'Empty card' }), }, terminalResult: { - name: 'terminalResult', description: '', parameters: {}, execute: async () => [], + name: 'terminalResult', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'generic', title: 'Becomes terminal' }), presentResult: () => ({ card: 'terminal', output: 'converted terminal' }), }, symbolic: { - name: 'symbolic', description: '', parameters: {}, execute: async () => [], + name: 'symbolic', description: '', parameters: {}, output: UNUSED_TOOL_OUTPUT, execute: async () => [], presentCall: () => ({ card: 'generic', title: 'Symbol input', rawInput: Symbol('input') }), }, } diff --git a/packages/web/tool-web/README.md b/packages/web/tool-web/README.md index 8cdb9ea737..27147104e9 100644 --- a/packages/web/tool-web/README.md +++ b/packages/web/tool-web/README.md @@ -13,6 +13,8 @@ Each tool is registered independently; a product that wants only one disables th Both tools opt into concurrent scheduling because provider reads return content without mutating parent-agent state. +The normalized seam results are also the canonical tool values: `WebSearchResult` and `WebFetchResult`. Native renderers preserve the answer/source and fetched-body text below; provider search/body caps remain acquisition limits rather than presentation-only truncation. + ## Config | Key | Default | Meaning | diff --git a/packages/web/tool-web/src/fetch.ts b/packages/web/tool-web/src/fetch.ts index 83358251fb..cc2ae52970 100644 --- a/packages/web/tool-web/src/fetch.ts +++ b/packages/web/tool-web/src/fetch.ts @@ -8,7 +8,6 @@ import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' import type { GenericCallView } from '@deepseek-ai/dsh-tools' -import type { ContentBlock } from '@deepseek-ai/dsh-llm' import type { WebFetchBody, WebFetchResult } from '@deepseek-ai/dsh-web' import { assertNever } from '@deepseek-ai/dsh-llm' import type {} from '@deepseek-ai/dsh-system-prompt' @@ -91,16 +90,54 @@ export function applyWebFetchTool(ctx: Context, timeoutMs: number): void { parameters: { url: { type: 'string', required: true, description: 'The HTTP(S) URL to fetch.' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + url: { type: 'string', required: true }, + statusCode: { type: 'integer', required: true }, + body: { + required: true, + oneOf: [ + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'html' }, + content: { type: 'string', required: true }, + }, + }, + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'text' }, + content: { type: 'string', required: true }, + }, + }, + ], + }, + truncated: { type: 'boolean', required: true }, + }, + }, + render: (_args, value) => [{ type: 'text', text: formatFetchOutput(value) }], + }, timeoutMs, // Provider reads do not mutate parent-agent state. isConcurrencySafe: () => true, - async execute(args, exec): Promise<ContentBlock[]> { + async execute(args, exec) { const input = parseFetchArgs(args) const result = await ctx.web.fetch( { url: input.url }, exec.signal, ) - return [{ type: 'text', text: formatFetchOutput(result) }] + return { + url: result.url, + statusCode: result.statusCode, + body: { kind: result.body.kind, content: result.body.content }, + truncated: result.truncated, + } }, presentCall: presentFetchCall, })) diff --git a/packages/web/tool-web/src/search.ts b/packages/web/tool-web/src/search.ts index af8753720d..816650e4b0 100644 --- a/packages/web/tool-web/src/search.ts +++ b/packages/web/tool-web/src/search.ts @@ -8,7 +8,6 @@ import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' import type { GenericCallView } from '@deepseek-ai/dsh-tools' -import type { ContentBlock } from '@deepseek-ai/dsh-llm' import type { WebSearchResult } from '@deepseek-ai/dsh-web' import type {} from '@deepseek-ai/dsh-system-prompt' @@ -108,16 +107,50 @@ export function applyWebSearchTool(ctx: Context, maxResults: number, timeoutMs: parameters: { query: { type: 'string', required: true, description: 'The search query.' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + content: { type: 'string' }, + sources: { + type: 'array', + required: true, + items: { + type: 'object', + additionalProperties: false, + properties: { + url: { type: 'string', required: true }, + title: { type: 'string' }, + snippet: { type: 'string' }, + publishedAt: { type: 'string' }, + }, + }, + }, + truncated: { type: 'boolean', required: true }, + }, + }, + render: (_args, value) => [{ type: 'text', text: formatSearchOutput(value) }], + }, timeoutMs, // Provider reads do not mutate parent-agent state. isConcurrencySafe: () => true, - async execute(args, exec): Promise<ContentBlock[]> { + async execute(args, exec) { const input = parseSearchArgs(args) const result = await ctx.web.search( { query: input.query, maxResults }, exec.signal, ) - return [{ type: 'text', text: formatSearchOutput(result) }] + return { + ...result.content !== undefined ? { content: result.content } : {}, + sources: result.sources.map(source => ({ + url: source.url, + ...source.title !== undefined ? { title: source.title } : {}, + ...source.snippet !== undefined ? { snippet: source.snippet } : {}, + ...source.publishedAt !== undefined ? { publishedAt: source.publishedAt } : {}, + })), + truncated: result.truncated, + } }, presentCall: presentSearchCall, })) diff --git a/packages/web/tool-web/tests/integration.spec.ts b/packages/web/tool-web/tests/integration.spec.ts index e99f524b3c..a48668f5f9 100644 --- a/packages/web/tool-web/tests/integration.spec.ts +++ b/packages/web/tool-web/tests/integration.spec.ts @@ -12,7 +12,7 @@ import { AddressInfo } from 'node:net' import { Context } from 'cordis' import { CallId } from '@deepseek-ai/dsh-llm' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry from '@deepseek-ai/dsh-tools' +import ToolRegistry, { type ToolExecutionResult } from '@deepseek-ai/dsh-tools' import WebService from '@deepseek-ai/dsh-web' import * as WebFetchLocal from '@deepseek-ai/dsh-web-fetch-local' import * as WebSearchExa from '@deepseek-ai/dsh-web-search-exa' @@ -54,8 +54,7 @@ afterEach(async () => { }) let counter = 0 -type ToolResult = { isError: boolean; content: { type: string; text?: string }[]; error?: { code: string } } -function call(name: string, args: unknown): Promise<ToolResult> { +function call(name: string, args: unknown): Promise<ToolExecutionResult> { return ctx.tools.execute({ callId: CallId(`call-${++counter}`), name, arguments: args }) } @@ -63,7 +62,7 @@ describe('web_fetch integration over the real backend', () => { it('fetches an html page and renders it to markdown', async () => { const out = await call('web_fetch', { url: base }) expect(out.isError).toBe(false) - const text = out.content.map(b => b.text).join('') + const text = out.content.map(b => b.type === 'text' ? b.text : '').join('') expect(text).toContain(`Fetched ${base}`) expect(text).toContain('# Hello') expect(text).toContain('World') @@ -73,20 +72,20 @@ describe('web_fetch integration over the real backend', () => { handler = (_req, res) => { res.writeHead(404, { 'content-type': 'text/plain' }); res.end('missing') } const out = await call('web_fetch', { url: base }) expect(out.isError).toBe(false) - expect(out.content.map(b => b.text).join('')).toContain('HTTP 404') + expect(out.content.map(b => b.type === 'text' ? b.text : '').join('')).toContain('HTTP 404') }) it('surfaces WEB_INVALID_URL as a structured tool error', async () => { const out = await call('web_fetch', { url: 'ftp://example.com' }) expect(out.isError).toBe(true) - expect(out.error?.code).toBe('WEB_INVALID_URL') + expect(out.error?.info?.code).toBe('WEB_INVALID_URL') }) it('surfaces a blocked cross-origin redirect as WEB_REDIRECT_BLOCKED', async () => { handler = (_req, res) => { res.writeHead(302, { location: 'https://example.com/' }); res.end() } const out = await call('web_fetch', { url: base }) expect(out.isError).toBe(true) - expect(out.error?.code).toBe('WEB_REDIRECT_BLOCKED') + expect(out.error?.info?.code).toBe('WEB_REDIRECT_BLOCKED') }) }) @@ -98,7 +97,7 @@ describe('web_search integration over the real Exa provider', () => { ))) const out = await call('web_search', { query: 'deepseek' }) expect(out.isError).toBe(false) - expect(out.content.map(b => b.text).join('')).toContain('[Result](https://result.test)') + expect(out.content.map(b => b.type === 'text' ? b.text : '').join('')).toContain('[Result](https://result.test)') }) }) @@ -151,7 +150,7 @@ describe('tool-call timeout returns TOOL_TIMEOUT (deadline wins over a slow fetc expect(out.isError).toBe(true) // The outer tool-call deadline won: TOOL_TIMEOUT, owned by dsh-timeout-policy, // NOT the provider's own WEB_FETCH_TIMEOUT (its 30s backstop never fired). - expect(out.error?.code).toBe('TOOL_TIMEOUT') + expect(out.error?.info?.code).toBe('TOOL_TIMEOUT') const text = out.content.map(b => (b.type === 'text' ? b.text : '')).join('') expect(text).toContain('timed out after 50ms') }) diff --git a/packages/web/tool-web/tests/tool-web.spec.ts b/packages/web/tool-web/tests/tool-web.spec.ts index 088ace395e..f3d16b0f3f 100644 --- a/packages/web/tool-web/tests/tool-web.spec.ts +++ b/packages/web/tool-web/tests/tool-web.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest' import { Context } from 'cordis' import { CallId } from '@deepseek-ai/dsh-llm' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry from '@deepseek-ai/dsh-tools' +import ToolRegistry, { type ToolExecutionResult } from '@deepseek-ai/dsh-tools' import WebService from '@deepseek-ai/dsh-web' import type { WebSearchProvider, WebSearchResult } from '@deepseek-ai/dsh-web' import * as ToolWeb from '@deepseek-ai/dsh-tool-web' @@ -30,7 +30,7 @@ async function mountTools(opts: { webConfig?: ConstructorParameters<typeof WebService>[1] search?: WebSearchProvider fetchProvider?: import('@deepseek-ai/dsh-web').WebFetchProvider -} = {}): Promise<{ ctx: Context; fiber: Awaited<ReturnType<Context['plugin']>>; call: (name: string, args: unknown) => Promise<{ isError: boolean; content: { type: string; text?: string }[]; error?: { code: string } }> }> { +} = {}): Promise<{ ctx: Context; fiber: Awaited<ReturnType<Context['plugin']>>; call: (name: string, args: unknown) => Promise<ToolExecutionResult> }> { const ctx = new Context() await ctx.plugin(SystemPrompt) await ctx.plugin(ToolRegistry) @@ -39,7 +39,7 @@ async function mountTools(opts: { if (opts.fetchProvider) ctx.web.registerFetchProvider(opts.fetchProvider) const fiber = await ctx.plugin(ToolWeb, opts.config ?? {}) let counter = 0 - const call = (name: string, args: unknown) => ctx.tools.execute({ callId: CallId(`call-${++counter}`), name, arguments: args }) as never + const call = (name: string, args: unknown) => ctx.tools.execute({ callId: CallId(`call-${++counter}`), name, arguments: args }) return { ctx, fiber, call } } @@ -196,7 +196,7 @@ describe('tool-web registration', () => { // No provider is registered: the schema stays visible and execution reports // the structured unavailability instead. const out = await call('web_search', { query: 'q' }) - expect(out.error?.code).toBe('WEB_PROVIDER_UNAVAILABLE') + expect(out.error?.info?.code).toBe('WEB_PROVIDER_UNAVAILABLE') await fiber.dispose() }) @@ -214,12 +214,13 @@ describe('tool-web execution through the real registry', () => { it('executes web_search and formats the result', async () => { const result: WebSearchResult = { content: 'answer', truncated: false, - sources: [{ url: 'https://a.test', title: 'A', snippet: 'snip' }], + sources: [{ url: 'https://a.test', title: 'A', snippet: 'snip', publishedAt: '2026-07-20' }], } const { fiber, call } = await mountTools({ webConfig: { searchProvider: 'stub-search' }, search: searchProvider(result) }) const out = await call('web_search', { query: 'q' }) expect(out.isError).toBe(false) - expect(out.content.map(b => b.text).join('')).toContain('[A](https://a.test)') + expect(out.value).toEqual(result) + expect(out.content.map(b => b.type === 'text' ? b.text : '').join('')).toContain('[A](https://a.test)') await fiber.dispose() }) @@ -227,7 +228,7 @@ describe('tool-web execution through the real registry', () => { const { fiber, call } = await mountTools() const out = await call('web_search', { query: 'q' }) expect(out.isError).toBe(true) - expect(out.error?.code).toBe('WEB_PROVIDER_UNAVAILABLE') + expect(out.error?.info?.code).toBe('WEB_PROVIDER_UNAVAILABLE') await fiber.dispose() }) @@ -236,7 +237,7 @@ describe('tool-web execution through the real registry', () => { ctx.web.registerSearchProvider({ id: 'other', available: () => available, search: () => Promise.resolve({ sources: [], truncated: false }) }) const out = await call('web_search', { query: 'q' }) expect(out.isError).toBe(true) - expect(out.error?.code).toBe('WEB_PROVIDER_AMBIGUOUS') + expect(out.error?.info?.code).toBe('WEB_PROVIDER_AMBIGUOUS') await fiber.dispose() }) @@ -244,7 +245,7 @@ describe('tool-web execution through the real registry', () => { const { fiber, call } = await mountTools({ webConfig: { searchProvider: 'stub-search' }, search: searchProvider({ sources: [], truncated: false }) }) const out = await call('web_search', { query: 123 }) expect(out.isError).toBe(true) - expect(out.error?.code).toBe('INVALID_ARGS') + expect(out.error?.info?.code).toBe('INVALID_ARGS') await fiber.dispose() }) @@ -267,6 +268,12 @@ describe('tool-web execution through the real registry', () => { const controller = new AbortController() const out = await ctx.tools.execute({ callId: CallId('fetch-1'), name: 'web_fetch', arguments: { url: 'https://a.test' }, signal: controller.signal }) expect(out.isError).toBe(false) + expect(out.value).toEqual({ + url: 'https://a.test', + statusCode: 200, + body: { kind: 'text', content: 'ok' }, + truncated: false, + }) // The model schema exposes no timeout: the tool forwards only the url; the // tool-call budget is owned by dsh-timeout-policy over exec.signal. expect(seen.request).toEqual({ url: 'https://a.test' }) @@ -289,6 +296,12 @@ describe('tool-web execution through the real registry', () => { // No signal on the execution: the tool passes `undefined`. const out = await ctx.tools.execute({ callId: CallId('fetch-2'), name: 'web_fetch', arguments: { url: 'https://a.test' } }) expect(out.isError).toBe(false) + expect(out.value).toEqual({ + url: 'https://a.test', + statusCode: 200, + body: { kind: 'text', content: 'ok' }, + truncated: false, + }) expect(seen.passedSignal).toBe(false) expect(seen.signal).toBeUndefined() await fiber.dispose() @@ -333,7 +346,7 @@ describe('searchMaxResults is plugin config', () => { const { fiber, call } = await mountTools({ config: { searchMaxResults: 2 }, webConfig: { searchProvider: 'stub-search' }, search: provider }) const out = await call('web_search', { query: 'q' }) expect(out.isError).toBe(false) - const body = out.content.map(b => b.text).join('') + const body = out.content.map(b => b.type === 'text' ? b.text : '').join('') expect(body).toContain('https://s1.test') expect(body).not.toContain('https://s2.test') expect(body).toContain('Showing the first 2 sources.') diff --git a/packages/workflow/tool-ralph/README.md b/packages/workflow/tool-ralph/README.md index 230e2db643..8f54c101f0 100644 --- a/packages/workflow/tool-ralph/README.md +++ b/packages/workflow/tool-ralph/README.md @@ -8,7 +8,7 @@ The model-facing `ralph` tool runs a fixed foreground workflow that gives one im Each child receives only the immutable objective, its current Ralph round and cap, a shared-workspace-as-authority instruction, and the previous structured handoff. The workspace is long-term memory; parent conversation and prior child sessions are not seeded. Reports have `status: continue | complete | blocked`, a non-empty summary, evidence, next steps, and blocker text. Status-specific semantics and the serialized `maxHandoffChars` ceiling are validated inside the fixed workflow and again at the consumer boundary. Invalid, missing, or oversized reports fail the workflow instead of being truncated or mistaken for cap exhaustion. -The successful terminal tool result is `complete`, `blocked`, or `budget-limited`, with the last bounded report and number of rounds started. Completion and blocker labels explicitly say that a worker reported the outcome; they are not independent certification. `maxResultChars` bounds the complete successful text including its envelope and truncation marker, without altering the validated report used as a cross-round handoff. +The successful terminal tool result is `complete`, `blocked`, or `budget-limited`, with the last bounded report and number of rounds started. The canonical envelope is `{ runId, agentsStarted, result }`; completion and blocker labels in its Native renderer explicitly say that a worker reported the outcome, not independent certification. `maxResultChars` bounds only that rendered text including its truncation marker, without altering the validated report in the canonical value or the cross-round handoff. An ordinary child failure produces an error naming the failed round and retaining the last successful handoff when one exists. Ralph does not retry that round. Fatal provider-start, transport, worker, or workflow failures remain workflow errors and may settle before the fixed script can return a handoff. Cancellation is also an error; partial output is never success. diff --git a/packages/workflow/tool-ralph/src/index.ts b/packages/workflow/tool-ralph/src/index.ts index 0f23ae062a..9191a2a8ae 100644 --- a/packages/workflow/tool-ralph/src/index.ts +++ b/packages/workflow/tool-ralph/src/index.ts @@ -8,6 +8,7 @@ import type { Context } from 'cordis' import z from 'schemastery' import type { ContentBlock } from '@deepseek-ai/dsh-llm' +import type { JsonValue } from '@deepseek-ai/dsh-session' import type { SubagentProvider } from '@deepseek-ai/dsh-subagent' import { defineTool } from '@deepseek-ai/dsh-tools' import type { ToolCallView, ToolResultView } from '@deepseek-ai/dsh-tools' @@ -374,6 +375,13 @@ function renderResult(result: RalphRunResult, maxChars: number): string { return boundResult(text, maxChars) } +/** Canonical Ralph result fields shared by schema inference and rendering. */ +const RALPH_OUTPUT_PROPERTIES = { + runId: { type: 'string', required: true }, + agentsStarted: { type: 'integer', required: true }, + result: { type: 'json', required: true }, +} as const + /** Render an ordinary child failure with the most recent durable handoff. */ function renderRoundFailure(result: RalphRoundFailure, maxChars: number): string { const header = `Ralph round ${result.roundsStarted} child failed before producing a structured report.` @@ -415,7 +423,18 @@ export function apply(ctx: Context, config: Config): void { description: 'Optional positive safe-integer round cap, bounded by the deployment ceiling.', }, }, - async execute(args, exec): Promise<ContentBlock[]> { + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: RALPH_OUTPUT_PROPERTIES, + }, + render: (_args, value) => [{ + type: 'text', + text: renderResult(value.result as unknown as RalphRunResult, resolved.maxResultChars), + }], + }, + async execute(args, exec) { const parent = exec.agent if (parent === undefined) { throw new Error('Ralph tool requires a calling agent (exec.agent was undefined)') @@ -444,7 +463,11 @@ export function apply(ctx: Context, config: Config): void { if (error !== undefined) throw new Error(error) const value = readRunResult(settled.value, maxRounds, resolved.maxHandoffChars) if (value.status === 'round-failed') throw new Error(renderRoundFailure(value, resolved.maxResultChars)) - return [{ type: 'text', text: renderResult(value, resolved.maxResultChars) }] + return { + runId: run.id, + agentsStarted: settled.agentsStarted, + result: value as unknown as JsonValue, + } } finally { exec.signal?.removeEventListener('abort', onAbort) await run.dispose() diff --git a/packages/workflow/tool-ralph/tests/tool-ralph.spec.ts b/packages/workflow/tool-ralph/tests/tool-ralph.spec.ts index 119da3def3..9d40f97296 100644 --- a/packages/workflow/tool-ralph/tests/tool-ralph.spec.ts +++ b/packages/workflow/tool-ralph/tests/tool-ralph.spec.ts @@ -156,6 +156,12 @@ describe('dsh-tool-ralph', () => { report: COMPLETE, }) expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected Ralph success') + expect(result.value).toEqual({ + runId: 'ralph-1', + agentsStarted: 1, + result: { status: 'complete', roundsStarted: 1, report: COMPLETE }, + }) expect((result.content[0] as { text: string }).text) .toContain('Ralph worker reported completion after 1 round.') expect((result.content[0] as { text: string }).text).toContain('All required gates pass.') @@ -279,7 +285,7 @@ describe('dsh-tool-ralph', () => { expect((await execute(ctx, { objective: 'Work.', maxRounds }, { agent: parent })).isError).toBe(true) } const missing = await execute(ctx, {}, { agent: parent }) - expect(missing.error?.code).toBe('INVALID_ARGS') + expect(missing.error?.info?.code).toBe('INVALID_ARGS') expect(engine.requests).toHaveLength(0) }) diff --git a/packages/workflow/tool-workflow/README.md b/packages/workflow/tool-workflow/README.md index 016f885914..e7cfceea9a 100644 --- a/packages/workflow/tool-workflow/README.md +++ b/packages/workflow/tool-workflow/README.md @@ -8,7 +8,7 @@ Three parameters: `meta` (required identity data: `name`, `description`, and opt ## Lifecycle -Collection is SYNCHRONOUS this cut (like [`dsh-tool-subagent`](../../subagent/tool-subagent/README.md)): `execute` starts a run and awaits `run.result` inside a `try/finally` that always disposes the run, so the script and its children reach quiescence on every path. `exec.signal` is bridged to `run.cancel()` (including the already-aborted-before-start case). A non-`completed` stop reason maps to an `isError` result reporting the reason — never partial output as success; a parse/meta failure thrown synchronously by `start()` becomes an `isError` the model can correct from. The completed result renders the meta name, the agent count, and the return value as JSON, truncated at `maxResultChars` with an explicit notice. +Collection is SYNCHRONOUS this cut (like [`dsh-tool-subagent`](../../subagent/tool-subagent/README.md)): `execute` starts a run and awaits `run.result` inside a `try/finally` that always disposes the run, so the script and its children reach quiescence on every path. `exec.signal` is bridged to `run.cancel()` (including the already-aborted-before-start case). A non-`completed` stop reason maps to an `isError` result reporting the reason—never partial output as success; a parse/meta failure thrown synchronously by `start()` becomes an `isError` the model can correct from. Completion returns canonical `{ runId, agentsStarted, result }`; the Native renderer preserves the meta name, agent count, and JSON value, truncating only that projection at `maxResultChars`. ## Render intent @@ -74,5 +74,5 @@ Append-only; newly visible content follows the reusable request prefix and does ## Known Limitations and Deferred Work - **The parent turn blocks until the whole workflow settles** — there is no background start/poll surface, and cancellation discards partial output as an error. -- **`args` must be an object and the result is bounded text** — callers wrap top-level arrays/scalars in a field, and JSON beyond `maxResultChars` is truncated rather than stored behind a retrieval handle. +- **`args` must be an object and Native result text is bounded** — callers wrap top-level arrays/scalars in a field; the canonical workflow result remains complete, while JSON beyond `maxResultChars` is truncated in the model-facing projection rather than stored behind a retrieval handle. - **Workflow policy is fixed per tool registration** — provider selection, caps, and tool name are deployment config, not model-call arguments. diff --git a/packages/workflow/tool-workflow/src/index.ts b/packages/workflow/tool-workflow/src/index.ts index 71121730e5..6dca58d343 100644 --- a/packages/workflow/tool-workflow/src/index.ts +++ b/packages/workflow/tool-workflow/src/index.ts @@ -15,6 +15,7 @@ import z from 'schemastery' import { defineTool } from '@deepseek-ai/dsh-tools' import type { ToolCallView, ToolResultView } from '@deepseek-ai/dsh-tools' import type { ContentBlock } from '@deepseek-ai/dsh-llm' +import type { JsonValue } from '@deepseek-ai/dsh-session' import type { WorkflowResult, WorkflowRun } from '@deepseek-ai/dsh-workflow' // Declaration merge only: makes ctx.systemPrompt visible for the section registration. import type {} from '@deepseek-ai/dsh-system-prompt' @@ -100,13 +101,13 @@ function stopReasonError(result: WorkflowResult): string | undefined { } /** Render the run's outcome text: the meta name, agent count, and the JSON value (capped). */ -function renderResult(run: WorkflowRun, result: WorkflowResult, maxChars: number): string { +function renderResult(name: string, agentsStarted: number, value: JsonValue, maxChars: number): string { // The engine returns JSON data (null for a valueless script), so stringify never yields undefined. - const rendered = JSON.stringify(result.value, null, 2) + const rendered = JSON.stringify(value, null, 2) const clipped = rendered.length > maxChars ? `${rendered.slice(0, maxChars)}\n… [truncated: ${rendered.length - maxChars} more characters]` : rendered - return `workflow "${run.meta.name}" completed (${result.agentsStarted} agent${result.agentsStarted === 1 ? '' : 's'}).\nReturn value:\n${clipped}` + return `workflow "${name}" completed (${agentsStarted} agent${agentsStarted === 1 ? '' : 's'}).\nReturn value:\n${clipped}` } export function apply(ctx: Context, config: Config): void { @@ -160,7 +161,22 @@ export function apply(ctx: Context, config: Config): void { description: 'Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}).', }, }, - async execute(args, exec): Promise<ContentBlock[]> { + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + runId: { type: 'string', required: true }, + agentsStarted: { type: 'integer', required: true }, + result: { type: 'json', required: true }, + }, + }, + render: (args, value) => [{ + type: 'text', + text: renderResult(args.meta.name, value.agentsStarted, value.result, maxResultChars), + }], + }, + async execute(args, exec) { const parent = exec.agent if (!parent) { // The loop sets `exec.agent` for every model-driven call; its absence @@ -197,7 +213,11 @@ export function apply(ctx: Context, config: Config): void { // throw into an isError). Report the reason, not partial output. throw new Error(error) } - return [{ type: 'text', text: renderResult(run, result, maxResultChars) }] + return { + runId: run.id, + agentsStarted: result.agentsStarted, + result: result.value as JsonValue, + } } finally { exec.signal?.removeEventListener('abort', onAbort) // Always reach run quiescence — never leak a live script or children. diff --git a/packages/workflow/tool-workflow/tests/tool-workflow.spec.ts b/packages/workflow/tool-workflow/tests/tool-workflow.spec.ts index d8c72ed567..a6939f3a9f 100644 --- a/packages/workflow/tool-workflow/tests/tool-workflow.spec.ts +++ b/packages/workflow/tool-workflow/tests/tool-workflow.spec.ts @@ -79,8 +79,10 @@ describe('dsh-tool-workflow', () => { engine.settle({ value: { findings: [1, 2] }, stopReason: 'completed', agentsStarted: 7 }) const result = await pending expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected workflow success') + expect(result.value).toEqual({ runId: 'run-1', agentsStarted: 7, result: { findings: [1, 2] } }) const rendered = (result.content[0] as { text: string }).text - expect(rendered).toContain('workflow "stub-flow" completed (7 agents)') + expect(rendered).toContain('workflow "audit" completed (7 agents)') expect(rendered).toContain('"findings"') expect(engine.disposed).toBe(1) }) @@ -151,7 +153,7 @@ describe('dsh-tool-workflow', () => { const { ctx, parent } = await setup() const result = await execute(ctx, {}, { agent: parent }) expect(result.isError).toBe(true) - expect(result.error?.code).toBe('INVALID_ARGS') + expect(result.error?.info?.code).toBe('INVALID_ARGS') }) it('cancels the run when exec.signal is ALREADY aborted at call time', async () => { @@ -169,7 +171,10 @@ describe('dsh-tool-workflow', () => { const pending = execute(ctx, { script: SCRIPT, meta: META }, { agent: parent }) await vi.waitFor(() => { expect(engine.requests.length).toBe(1) }) engine.settle({ value: { blob: 'x'.repeat(500) }, stopReason: 'completed', agentsStarted: 1 }) - const rendered = ((await pending).content[0] as { text: string }).text + const result = await pending + if (result.isError) throw new Error('expected workflow success') + expect(result.value).toEqual({ runId: 'run-1', agentsStarted: 1, result: { blob: 'x'.repeat(500) } }) + const rendered = (result.content[0] as { text: string }).text expect(rendered).toContain('[truncated:') expect(rendered.length).toBeLessThan(400) }) diff --git a/scripts/type-equiv.manifest.json b/scripts/type-equiv.manifest.json index ed53ac469c..a003a50625 100644 --- a/scripts/type-equiv.manifest.json +++ b/scripts/type-equiv.manifest.json @@ -90,6 +90,7 @@ { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventTraceRequest", "source": "packages/session-query/session-query/src/types.ts" }, { "doc": "docs/core-data-structures/session-query.md", "symbol": "SessionEventTrace", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolOutputDefinition", "source": "packages/core/tools/src/index.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolDefinition", "source": "packages/core/tools/src/index.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "ValueSchemaSpec", "source": "packages/core/tools/src/schema.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "ParameterPropertySpec", "source": "packages/core/tools/src/schema.ts" }, @@ -103,6 +104,9 @@ { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolRunContext", "source": "packages/core/tools/src/index.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolGuard", "source": "packages/core/tools/src/index.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolRestriction", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolFailure", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolExecutionSuccess", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolExecutionFailure", "source": "packages/core/tools/src/index.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolExecutionResult", "source": "packages/core/tools/src/index.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "PreToolDecision", "source": "packages/core/tools/src/index.ts" }, { "doc": "docs/core-data-structures/tools.md", "symbol": "PostToolDecision", "source": "packages/core/tools/src/index.ts" }, From c1d7b0df814c2ffe57e53b406e60f9ca69338d19 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 04:34:14 +0800 Subject: [PATCH 024/368] feat: return typed values from Code Mode --- ...06-20-generic-long-running-tool-runtime.md | 2 + .../feature/2026-06-15-code-mode.md | 17 +- ...-20-code-mode-typed-tool-returns.i18n.yaml | 6 + ...2026-07-20-code-mode-typed-tool-returns.md | 112 +++++++ ...6-07-20-code-mode-typed-tool-returns.zh.md | 112 +++++++ docs/config-catalog.md | 14 +- docs/cookbook/adding-a-tool.i18n.yaml | 4 +- docs/cookbook/adding-a-tool.md | 8 +- docs/cookbook/adding-a-tool.zh.md | 8 +- docs/cordis-catalog/events.md | 10 +- docs/cordis-catalog/services.md | 4 +- docs/core-data-structures/code-runtime.md | 36 ++- docs/event-producer-consumer.md | 10 +- docs/module-graph.md | 5 +- .../system-prompt.expected.md | 287 +++++++++++++++--- .../snapshots/both-mode-turn/session.jsonl | 8 +- .../both-mode-turn/stdout.expected.jsonl | 2 +- .../both-mode-turn/system-prompt.expected.md | 263 ++++++++++++++-- .../snapshots/code-mode-turn/session.jsonl | 10 +- .../code-mode-turn/stdout.expected.jsonl | 2 +- .../code-mode-turn/system-prompt.expected.md | 263 ++++++++++++++-- .../code-mode-workspace-context/session.jsonl | 10 +- .../stdout.expected.jsonl | 4 +- .../system-prompt.expected.md | 263 ++++++++++++++-- .../headless-agent/tests/code-mode.e2e.ts | 224 +++++++++++++- .../tests/snapshots/code-mode/session.jsonl | 10 +- .../code-runtime-worker/README.md | 15 +- .../code-runtime-worker/package.json | 2 + .../code-runtime-worker/src/bootstrap.ts | 97 +++--- .../code-runtime-worker/src/index.ts | 187 ++++++++---- .../code-runtime-worker/src/protocol.ts | 28 +- .../tests/bootstrap.spec.ts | 144 ++++++--- .../code-runtime-worker/tests/runtime.spec.ts | 198 ++++++++---- .../code-runtime-worker/tsconfig.json | 3 + packages/code-runtime/code-runtime/README.md | 7 +- .../code-runtime/code-runtime/src/index.ts | 1 + .../code-runtime/code-runtime/src/types.ts | 28 +- .../code-runtime/tests/service.spec.ts | 2 +- .../cordis/tool-cordis/src/api-catalog.ts | 10 +- packages/core/tools/README.md | 15 +- packages/core/tools/src/code-mode.ts | 56 ++-- packages/core/tools/src/index.ts | 13 +- packages/core/tools/src/ts-types.ts | 34 ++- packages/core/tools/tests/code-mode.spec.ts | 114 ++++--- packages/core/tools/tests/ts-types.spec.ts | 36 ++- packages/spill/spill-policy/package.json | 1 + .../spill-policy/tests/spill-policy.spec.ts | 37 +++ .../tests/structured.spec.ts | 6 +- pnpm-lock.yaml | 6 + scripts/type-equiv.manifest.json | 1 + 50 files changed, 2155 insertions(+), 580 deletions(-) create mode 100644 .agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml create mode 100644 .agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md create mode 100644 .agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md index 4db0d78910..b5117b1045 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -23,6 +23,8 @@ Long-running tools are producers. `dsh-tool-bash` adapts a `BashProcess` into in The literal types live in the [task data-structure catalog](../../../../docs/core-data-structures/tasks.md). A producer calls `ctx.tasks.start()` with a kind, label, optional owning `Agent`, and a `run()` function. The runtime completes all failable preflight work before calling `run()` and invokes it once. After `run()` returns hooks, registration commits without another failable step; a producer cannot start work that lacks a collectable task id. +A model-facing producer exposes that committed id in its canonical success value, normally `{ kind: 'background', taskId }`; Native rendering may keep human-readable prose. A pre-aborted background call fails rather than returning a no-op because no task exists to satisfy the promised handle. Once registration publishes the id, cancellation belongs to the task's own controller and the task runtime: later cancellation of the producing tool call must not kill the published task. `task_kill`, owner disposal, and service teardown request cancellation; foreground execution remains coupled to the call's `exec.signal`. + The producer hooks define three responsibilities: - `cancel(reason?)` synchronously requests termination, is idempotent, and must cause `done` to settle. diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.md index 329eaf2d0a..e51f95d247 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.md @@ -20,6 +20,8 @@ Three decisions, each elaborated in its own section below: 2. **Code execution is a capability seam** — `packages/code-runtime/` contains the interface package `@deepseek-ai/dsh-code-runtime`, which owns `ctx.codeRuntime` ([capability seams](../architecture/2026-06-13-capability-seams.md); consumer = `dsh-tools`, with core-consumes-a-seam precedent in `agent-loop` → `dsh-llm`). The runtime knows nothing about tools: it is handed a program and named async bindings, runs the program, and reports `{ value, logs, error? }`. Language and substrate are backend properties, so a future Python or container backend is another implementation package, not a redesign. 3. **The shipped implementation is `@deepseek-ai/dsh-code-runtime-worker`**: one fresh Node worker thread per run, executing the model's TypeScript after type-strip, with bindings bridged over the message port, an empty environment, configurable heap/output/time caps, and hard termination. Its trust posture is bash-equivalent by design — no unsafe-acknowledgement flags — because the harness already ships `dsh-bash-local`, which executes arbitrary model-written shell commands with strictly *more* ambient authority. +This note owns Code Mode's presentation, composition, isolation, and settlement foundation. The later [typed tool-return Agent Note](2026-07-20-code-mode-typed-tool-returns.md) owns the generated output map, canonical binding values, `ToolCallError`, and the lossless outer-output boundary. + ### The registry owns the mode `ToolRegistry` gains a schemastery-validated config (`static Config`), its first: `mode: 'native' | 'code' | 'both'`, default `'native'`. A deployment flips it from `cordis.yml` (`tools: { mode: code }`) — no code edit, per the no-hardcoded-tunables convention. @@ -38,7 +40,7 @@ Three decisions, each elaborated in its own section below: Under `'code'` and `'both'` the registry owns `run_code` as a reserved presentation transport with one required parameter, `{ code: string }`. It is represented by a normal `ToolDefinition` for dispatch but stays outside the filterable capability layers, so restrictions cannot accidentally remove Code Mode's only entry point. Calls traverse the complete tool pipeline — `tools/pre-execute` → monotonic guards → `tools/execute` around dispatch → `tools/post-execute` → immutable `tools/result` notification — exactly like native calls; a permission plugin can inspect the program text before it runs, and final-result observers see the normalized outer outcome. Its `execute(args, exec)`: -1. **Build bindings.** One run-scoped signal follows outer cancellation and is aborted whenever the run settles. Each visible tool binding JSON-normalizes its arguments—rejecting lossy values before dispatch—waits on the serialization queue, executes with a deterministic call id and the outer token as `parent`, defers returned contexts through the outer execution, and logs `tool/code-dispatch`. Successful text becomes a string and non-text blocks become placeholders; tool errors reject the binding promise. Every sub-call retains its own immutable execution identity and traverses the full tool pipeline. +1. **Build bindings.** One run-scoped signal follows outer cancellation and is aborted whenever the run settles. Each visible tool binding snapshots lossless-JSON arguments, waits on the serialization queue, executes with a deterministic call id and the outer token as `parent`, defers returned contexts through the outer execution, and logs `tool/code-dispatch`. Success returns the tool's final canonical JSON value; failure becomes the program-visible `ToolCallError`. Every sub-call retains its own immutable execution identity and traverses the full tool pipeline. 2. **Runs the program**: `ctx.codeRuntime.run({ program: args.code, bindings: [{ global: 'tools', functions }], signal: runController.signal })`. The runtime receives the run-scoped signal, not only the caller's outer signal, so any way the outer run settles also aborts work inside the runtime. 3. **Settle after quiescence.** When the runtime settles, the bridge aborts outstanding work and drains the dispatch queue before returning. Success returns captured output and presentation metadata. A runtime failure becomes `CodeRunFailedError`; backend rejection uses the registry's normal error boundary. Both produce structured error results, and no sub-call can append after `run_code` settles. @@ -57,10 +59,9 @@ Each sub-dispatch appends a log-only `tool/code-dispatch` event containing paren `packages/code-runtime/code-runtime/` — `@deepseek-ai/dsh-code-runtime`, depending only on `cordis`. An abstract `CodeRuntime extends Service` (`super(ctx, 'codeRuntime')`) plus the vocabulary: - `CodeRunRequest = { program: string; bindings: CodeBindingNamespace[]; signal?: AbortSignal }` -- `CodeBindingNamespace = { global: string; functions: Record<string, (args: unknown) => Promise<unknown>> }` — the runtime exposes each namespace as a global object of async functions inside the program; binding arguments and resolutions must be structured-cloneable (a runtime may cross a serialization boundary; ours does). -- `CodeRunResult = { value?: unknown; logs: CodeLogEntry[]; error?: CodeRunFailure }` — program execution outcomes, including exception, timeout, abort, and worker exit, resolve as the `error` field. `run()` may reject only for caller/seam misuse (for example a duplicate binding namespace); consumers still contain a non-conforming backend rejection at their own error boundary. -- `CodeLogEntry = { source: 'console' | 'stdout' | 'stderr'; level?: 'log' | 'info' | 'warn' | 'error' | 'debug'; text: string }` -- `CodeRunFailure = { kind: 'exception' | 'timeout' | 'abort' | 'worker-exit'; message: string }` — orthogonal outcomes reported independently per [defensive patterns](../../../../docs/defensive-patterns.md); a timed-out run is not an exception, an abort is not a timeout. +- `CodeBindingNamespace = { global: string; functions: Record<string, (args: unknown) => Promise<CodeJsonValue>> }` — the runtime exposes each namespace as a global object of async functions inside the program; `CodeJsonValue` is this dependency-light seam's structural lossless-JSON type, so binding arguments and resolutions cross the implementation's serialization boundary whole. +- `CodeRunResult = { value?: CodeJsonValue; logs: string[]; error?: CodeRunFailure }` — program execution outcomes resolve as the `error` field. `run()` may reject only for caller/seam misuse (for example a duplicate binding namespace); consumers still contain a non-conforming backend rejection at their own error boundary. +- `CodeRunFailure = { kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' | 'invalid-output' | 'output-limit'; message: string }` — orthogonal outcomes reported independently per [defensive patterns](../../../../docs/defensive-patterns.md); a timed-out run is not an exception, an abort is not a timeout, a lossy completion is not an overflow, and a substrate exit is none of them. - Two readonly backend descriptors, informational not gating: `language` (what the program must be written in — `'typescript'` for the shipped backend; a Python backend would say so, and pair with its own SDK generator on the presentation side) and `isolation` (`'worker-thread'` for the shipped backend; `'process'`, `'container'`, … for future ones). `dsh-tools` requires `language === 'typescript'` in the MVP — its codegen emits TS — and fails the assembly loudly otherwise, the same misconfiguration idiom as `toolOrder` violations (as when `mode` is non-native with no `ctx.codeRuntime` loaded at all). Requests contain every runtime input; implementations own validated timeout and cap defaults. The registry looks up the optional runtime only when Code Mode is assembled, so native mode does not depend on one. Missing or language-incompatible runtimes fail loudly. Alternate substrates or languages can replace the implementation behind the same seam, paired with the appropriate SDK generator. @@ -71,9 +72,9 @@ Requests contain every runtime input; implementations own validated timeout and 1. **Type-strip host-side** with Node's built-in `stripTypeScriptTypes` (`node:module`; present across the repo's whole engines range, `^22.19.0 || >=24.0.0`, and position-preserving, so runtime error line numbers match the model's source). Strip-only mode rejects non-erasable syntax (`enum`, namespaces) — that rejection returns as `error.kind: 'exception'` with Node's message, the SDK instructions say "erasable TypeScript only", and the model self-corrects like any other program error. A syntax-level failure never spawns a worker. 2. **Spawn one fresh `Worker` per run** from the package's own bootstrap module: `env: {}` (truly empty — stronger than the scrubbed-env rule for spawned commands), `resourceLimits` from config, `stdout`/`stderr` captured into `logs` rather than inherited. No pooling and no cross-run state: a program's world dies with its worker, which keeps runs reconstructable from the log alone and makes state bleed unrepresentable. -3. **Execute** in the bootstrap: the stripped program becomes the body of an `AsyncFunction` whose parameters are the binding globals and a capturing `console` shim, so top-level `await` and `return` work and the program's completion value is the run's `value` (structured-cloneable values cross as-is; anything else is replaced by its `util.inspect` rendering, documented). +3. **Execute** in the bootstrap: the stripped program becomes the body of an `AsyncFunction` whose parameters are the binding globals, the real `ToolCallError` class, and a capturing `console` shim, so top-level `await` and `return` work. A lossless JSON completion crosses exactly; `undefined` remains absence, a lossy value is `invalid-output`, and an oversized outer result is `output-limit` rather than an inspected-string substitute. 4. **Bridge bindings over the message port**: each binding function in the worker posts `{ id, global, name, args }` and awaits the reply; the host validates the name against the request's bindings, invokes, and replies `{ id, ok, value }` or `{ id, ok: false, message }` (a host-side binding rejection becomes a program-side rejection). The worker-side namespace objects are built null-prototype via `defineProperty`, so a binding named `__proto__`, `constructor`, or `toString` is an ordinary own property, not a prototype collision. Unknown names, duplicate ids, and post-settlement messages are rejected or ignored — the port protocol assumes a hostile peer, because the peer runs model code. -5. **Enforce independent budgets.** `computeMs` meters worker busy time, allowing slow awaited tools without excusing a hot loop. `maxWallMs` bounds total elapsed time, including unresolved waits. Expiry, cancellation, and completion terminate the worker. Heap exits and truncation are reported explicitly; compute, wall, heap, log, and return-value caps are validated configuration. +5. **Enforce independent budgets.** `computeMs` meters worker busy time, allowing slow awaited tools without excusing a hot loop. `maxWallMs` bounds total elapsed time, including unresolved waits. `maxOutputBytes` bounds only the combined serialized outer logs, completion, or diagnostic; intermediate binding values have no byte cap. Expiry, cancellation, and completion terminate the worker, and heap exits or outer overflow are explicit failures. 6. **Dispose to quiescence**: the service's own disposal terminates in-flight workers and *awaits* their exits before resolving, per [defensive patterns](../../../../docs/defensive-patterns.md). ### Trust posture @@ -90,7 +91,7 @@ Deployments switching to `'code'` must update any native-only `toolOrder`. Assem ## Testing -- **Worker runtime:** Real-worker tests cover output and value capture, failure kinds, compute and wall budgets, hostile binding traffic, empty environment, structured-clone fallback, output caps, and disposal to quiescence. A built-package test runs the worker entry under plain Node. +- **Worker runtime:** Real-worker tests cover typed binding values and failures, every lossless JSON completion root, invalid and over-limit output, exact combined ledger boundaries, compute and wall budgets, hostile binding traffic, empty environment, and disposal to quiescence. A built-package test runs the worker entry under plain Node. - **Registry integration:** Tests cover code generation, all presentation modes, reserved-name and restriction rules, scoped visibility, authoritative assembly rewrites, `toolOrder`, runtime compatibility failures, full-pipeline sub-dispatch, parent-token correlation, serialization, cancellation and queue drain, JSON normalization, error propagation, log events, ordered context deferral across successful and failed programs, outer-block suppression, and HMR cleanup. - **With-key e2e:** A real model composes two bash calls in one program; another discovers nested workspace instructions through a Code Mode fs dispatch. The tests verify collapsed request headers, correlated dispatch events, resulting files, deferred context, and model behavior. - **Snapshot:** The `code-mode-turn`, `both-mode-turn`, and `code-mode-workspace-context` fixtures pin SDK text, header tool lists, dispatch events, deferred context, and result cards. diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml new file mode 100644 index 0000000000..3b3e9544f2 --- /dev/null +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-20-code-mode-typed-tool-returns.md: 1beecbc9e5f61ac5dce50aeba508ce75cb0ce507 +2026-07-20-code-mode-typed-tool-returns.zh.md: 0dbad69f6b8120e0904f026961b004855d23f3ab diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md new file mode 100644 index 0000000000..1beecbc9e5 --- /dev/null +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md @@ -0,0 +1,112 @@ +# Agent Note: Typed tool returns in Code Mode + +Status: implemented + +English | [中文](2026-07-20-code-mode-typed-tool-returns.zh.md) + +## Problem + +Code Mode originally projected each nested tool result back from `ContentBlock[]` into one string. That preserved the human-readable Native surface but erased the canonical result the tool had already produced: programs had to scrape task ids and dynamic mount ids from prose, structured search and workflow results lost their shape, and non-text blocks became placeholders. The generated SDK could describe arguments but could only promise `Promise<string>` regardless of the tool's real output. + +The runtime also treated binding values and the final program value as presentation data. Separate log and completion caps could replace an oversized or non-cloneable completion with inspected text even though intermediate values do not enter model context. That made programmatic composition lossy and confused the memory boundary with the prompt boundary. + +The [canonical tool-output contract](../architecture/2026-07-20-canonical-tool-output-contract.md) establishes one validated execution-time value and a separate Native renderer. Code Mode should consume that value directly, preserve it across the worker boundary, and bound only the final output the program deliberately returns to the model. + +## Decision + +Code Mode is a typed projection of the visible tool registry. Each successful binding resolves to the final canonical `JsonValue` after post-execute policy, while a failed binding rejects with a real `ToolCallError`. Intermediate values remain inside the run and cross the worker boundary whole. Only the outer `run_code` logs, completion value, or failure diagnostic enter the configurable output ledger and the model-facing spill pipeline. + +This note owns the return and failure contract layered on the original [Code Mode foundation](2026-06-15-code-mode.md). The unified schema vocabulary is owned by the [JSON-value schema DSL note](../architecture/2026-07-20-unified-json-value-schema-dsl.md), and Native rendering and policy projection remain owned by the canonical-output note. + +### Generated SDK + +At each prompt assembly the registry projects every visible tool's parameter schema and detached canonical output schema into one deterministic declaration: + +```ts ignore-check +type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } + +interface ToolArgsMap { + // one exact inferred entry per visible tool +} + +interface ToolOutputMap { + // one exact inferred entry per visible tool +} + +type ToolName = keyof ToolOutputMap + +declare class ToolCallError extends Error { + readonly name: 'ToolCallError' + readonly toolName: ToolName +} + +declare const tools: { + [K in ToolName]: (args: ToolArgsMap[K]) => Promise<ToolOutputMap[K]> +} +``` + +`jsonSchemaToTs()` covers every supported unified-schema node: object, array, string, number, integer, boolean, null, unconstrained JSON, scalar `enum` and `const`, and `oneOf`. Unsupported raw constructs degrade to `unknown` during prompt generation rather than breaking assembly. Tool names retain their exact keys, including names that require quoted access. + +### Binding values and failures + +Before dispatch the bridge snapshots binding arguments as lossless JSON and makes independent clones for execution and the durable summary event. `undefined`, non-finite numbers, `-0`, sparse arrays, cycles, functions, and exotic objects reject that call before the tool runs. Successful dispatch returns `ToolExecutionResult.value`; Native `content`, metadata, and internal error information do not cross to the program. + +The worker exposes the actual `ToolCallError` constructor used for `tools` binding failures, so `error instanceof ToolCallError` works. The error has the standard `Error` message plus the exact `toolName`; it deliberately omits `ToolFailure.info`, error codes, and Native content. This is an exception contract for control flow, not a failure union for programmatic classification. + +Binding arguments and resolutions are revalidated as lossless JSON on both sides of the hostile worker protocol and cross through structured clone with no byte cap. The dependency-light runtime seam names its structural equivalent `CodeJsonValue` so it need not depend on the session-owned canonical type; the generated SDK and tool API use `JsonValue`. Intermediate values are not prompt-truncated, context-spilled, or persisted. This preserves full acquired search, workflow, task, filesystem, and MCP values for programmatic filtering while leaving provider and executor acquisition limits truthful. + +### Outer result and output ledger + +The runtime accepts an exact lossless JSON completion of any root. Returning `undefined` omits the completion; returning `null` is an explicit result. `run_code` exposes the canonical outer value `{ logs: string[], result?: JsonValue }`. Its Native renderer emits logs first, renders a string result raw, and pretty-prints every other JSON root. + +`WorkerCodeRuntime` replaces the former independent log and value caps with configurable `maxOutputBytes`, defaulting to `67_108_864` bytes. One host-side hostile-peer ledger accounts the JSON serialization of the outer logs array plus either the completion value or failure diagnostic. A result at or below the cap is exact. A completion that cannot survive lossless JSON snapshotting fails as `invalid-output`; a value or combined logs/value outcome over the cap fails as `output-limit` rather than becoming inspected or truncated text. + +Logs stream eagerly so a terminated run can retain output already admitted. When the cap is crossed, the runtime returns an explicit bounded failure with the fitting captured prefix. That outer result then traverses the ordinary `run_code` rendering and spill policy, which may save the captured text and expose its configured head/tail preview. The spill layer cannot recover bytes the runtime rejected beyond the hard cap. + +Compute time, wall time, worker heap, cancellation, and fresh-worker isolation remain independent limits. The outer ledger never charges intermediate bindings, so structured-clone cost and available process or worker memory are their practical bounds. + +### Typed handles and lifetime + +Background producers return a typed canonical handle such as `{ kind: 'background', taskId }` while retaining their established Native sentence. A pre-aborted background call remains a failure because successful output promises an id and no task was created. After `ctx.tasks.start()` publishes the id, task-owned cancellation governs the work: settlement or later cancellation of the enclosing `run_code` call does not kill it. A later program can pass the returned id to `task_output`, and `task_kill`, owner disposal, or service teardown owns cancellation. Foreground execution remains coupled to the call signal. The task lifetime contract is owned by the [background task runtime note](../architecture/2026-06-20-generic-long-running-tool-runtime.md). + +Dynamic Cordis mounting follows the same rule: `cordis_mount` returns `{ id, pluginName, state, provides, waitingFor }`, so a program can read `mounted.id`, inspect active or pending state, and pass that id to `cordis_unmount` without parsing the stable Native sentence. + +### Persistence, metadata, and spill + +Nested dispatch keeps the existing bounded `tool/code-dispatch.resultSummary` for diagnostics but does not persist canonical values. `tool/result` continues to persist only rendered content, error, and optional metadata. This is deliberately not a session-format change, so `SESSION_FORMAT_VERSION` remains unchanged and replay cannot recreate intermediate program values. + +The opaque `exec.parent` token marks nested calls. Presentation metadata and generic or tool-owned spill projections skip those calls because they have no direct result card and their canonical values never enter context. The outer `run_code` call alone computes presentation metadata, produces one card, and may spill its final post-policy presentation. + +## Testing + +Compile-time and snapshot tests pin exact `ToolArgsMap`, `ToolOutputMap`, `ToolName`, schema-to-TypeScript coverage, and exotic names. Registry and real-worker tests cover scalar, array, object, and null values; raw string rendering; absent `undefined`; the real `ToolCallError`; invalid arguments and completions; large uncapped intermediate bindings; nested spill suppression; exact and over-limit 64 MiB accounting; combined logs/value accounting; bounded failure spill; hostile forged traffic; and built-package execution. + +Keyless real-worker integration tests pin the two handle workflows that prose results could not safely support. A background bash call returns its task id, the outer run settles, and a later run polls that id to completion; separate cases prove pre-abort creates no task, post-publication call abort preserves the task, foreground execution stays signal-coupled, and `task_kill` owns cancellation. A Cordis program reads an active or pending mount's id and `waitingFor` fields directly, unmounts by that id, and confirms removal without parsing rendered text. + +## Alternatives considered + +**Return Native text plus optional JSON.** Rejected because the program would have two competing success contracts and would still need tool-specific parsing rules when the optional value is absent. Canonical value is the API; Native content is its presentation. + +**Expose a success/failure union from every binding.** Rejected because failure has no stable programmatic taxonomy. Rejections preserve ordinary `try`/`catch` control flow and expose only the tool name and human-readable message. + +**Cap each intermediate binding.** Rejected because intermediate values are not placed in model context and arbitrary truncation would corrupt programmatic composition. The producer's acquisition contract and process memory remain explicit boundaries. + +**Silently inspect or truncate an oversized completion.** Rejected because changing a JSON value into a string is lossy and type-incorrect. The explicit `output-limit` failure lets the model choose a smaller result, while the retained logs and diagnostic can still use normal outer spill. + +## Consequences + +Code programs can compose tools through stable values instead of reverse-engineering Native prose. Native and Both Mode retain their existing text and editor presentation, while Code Mode receives output-schema types and exact runtime JSON. Tool authors must treat the canonical value as their programmatic API and put display-only formatting in the renderer. + +The worker performs structured cloning and lossless validation but does not make intermediate values cheap or durable. Outer overflow is an explicit failed run, and error handling remains intentionally human-guided rather than a versioned code union. + +## Known Limitations and Deferred Work + +- Subagent and workflow caller-defined structured outputs remain object-rooted through consumer-level guards even though tool outputs may use any JSON root. +- Post-execute has separate value and presentation projections; replacing content is not a confidentiality mechanism, so policy must block or replace the value to hide it from programmatic callers. +- Intermediate canonical values are execution-local and unavailable to replay because durable events persist only presentation and bounded summaries. +- Intermediate values have no byte cap and can exhaust process or worker memory through retention or structured-clone cost. +- The 64 MiB hard cap applies only to outer output; spill cannot recover bytes rejected beyond that cap. +- Provider or executor acquisition limits may already have discarded source data before a canonical value reaches Code Mode. +- Unsupported MCP output schemas fall back to `JsonValue`; richer Native multimedia projection is deferred. +- There is one result card per outer `run_code`, never per nested call. +- Code failures expose `ToolCallError` message and tool name only, without a programmatic error-code union. diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md new file mode 100644 index 0000000000..0dbad69f6b --- /dev/null +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md @@ -0,0 +1,112 @@ +# Agent Note:Code Mode 的类型化工具返回值 + +Status: implemented + +[English](2026-07-20-code-mode-typed-tool-returns.md) | 中文 + +## 问题 + +Code Mode 过去会把每个嵌套工具的结果从 `ContentBlock[]` 重新投影为一个字符串。这样虽然保留了适合人类阅读的 Native 接口,却丢失了工具已经生成的规范结果:程序只能从自然语言中提取 task id 和动态挂载 id;结构化搜索与工作流结果失去原有形态;非文本块则变为占位符。生成的 SDK 可以描述参数,却无论工具实际输出为何都只能承诺 `Promise<string>`。 + +运行时还把绑定值和程序最终返回值当作展示数据。日志和完成值分别设置上限,导致过大或无法克隆的完成值可能被替换为检查格式化后的文本,而中间值本来就不会进入模型上下文。这种设计使程序化组合产生信息损失,也混淆了内存边界与提示词边界。 + +[规范工具输出契约](../architecture/2026-07-20-canonical-tool-output-contract.md)确立了单一、经过校验的执行期值,并将 Native 渲染器与之分离。Code Mode 应直接消费该值,在跨越 worker 边界时完整保留它,并且只限制程序有意返回给模型的最终输出。 + +## 决策 + +Code Mode 是可见工具注册表的类型化投影。每个成功的绑定调用都会解析为 post-execute 策略处理后的最终规范 `JsonValue`,失败的绑定调用则以真正的 `ToolCallError` reject。中间值只存在于本次运行中,并完整跨越 worker 边界。只有外层 `run_code` 的日志、完成值或失败诊断会进入可配置的输出账本以及面向模型的输出落盘流水线。 + +本文档定义叠加在原始 [Code Mode 基础](2026-06-15-code-mode.md)之上的返回值与失败契约。统一 schema 词汇由 [JSON 值 schema DSL Agent Note](../architecture/2026-07-20-unified-json-value-schema-dsl.md)定义;Native 渲染与策略投影仍由规范输出 Agent Note 定义。 + +### 生成的 SDK + +每次组装提示词时,注册表都会把每个可见工具的参数 schema 及其分离的规范输出 schema 投影为一份确定性声明: + +```ts ignore-check +type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } + +interface ToolArgsMap { + // one exact inferred entry per visible tool +} + +interface ToolOutputMap { + // one exact inferred entry per visible tool +} + +type ToolName = keyof ToolOutputMap + +declare class ToolCallError extends Error { + readonly name: 'ToolCallError' + readonly toolName: ToolName +} + +declare const tools: { + [K in ToolName]: (args: ToolArgsMap[K]) => Promise<ToolOutputMap[K]> +} +``` + +`jsonSchemaToTs()` 覆盖统一 schema 支持的所有节点:对象、数组、字符串、数字、整数、布尔值、null、无约束 JSON、标量 `enum` 与 `const`,以及 `oneOf`。提示词生成期间,不支持的原始结构会降级为 `unknown`,而不会导致组装失败。工具名会保留精确键名,包括必须使用引号访问的名称。 + +### 绑定值与失败 + +分发前,桥接层会把绑定参数快照为无损 JSON,并为执行和持久摘要事件分别创建独立副本。`undefined`、非有限数、`-0`、稀疏数组、循环引用、函数和非普通对象都会使该调用在工具运行前 reject。成功分发会返回 `ToolExecutionResult.value`;Native `content`、元数据和内部错误信息不会传入程序。 + +worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造函数,因此 `error instanceof ToolCallError` 能够成立。该错误包含标准的 `Error` 消息和确切的 `toolName`,并有意省略 `ToolFailure.info`、错误代码与 Native 内容。这是一项用于控制流的异常契约,而不是供程序分类的失败联合。 + +绑定参数与绑定返回值会在不可信 worker 协议的两端重新校验为无损 JSON,再通过结构化克隆传输,且不设字节上限。为保持依赖轻量,运行时 seam 将结构等价类型命名为 `CodeJsonValue`,从而无需依赖会话侧拥有的规范类型;生成的 SDK 和工具 API 则使用 `JsonValue`。这些值不会经过提示词截断、上下文输出落盘或持久化。因此,程序可以完整筛选已经采集的搜索、工作流、任务、文件系统与 MCP 值,同时提供方和执行器的采集上限仍会实际生效。 + +### 外层结果与输出账本 + +运行时接受以任意 JSON 类型为根的精确无损完成值。返回 `undefined` 表示省略完成值;返回 `null` 则是显式结果。`run_code` 暴露规范外层值 `{ logs: string[], result?: JsonValue }`。其 Native 渲染器先输出日志;字符串结果保持原文,其他所有 JSON 根值采用美化格式输出。 + +`WorkerCodeRuntime` 以可配置的 `maxOutputBytes` 取代彼此独立的日志与值上限,默认值为 `67_108_864` 字节。宿主侧为不可信对端维护一份统一账本,计入外层日志数组以及完成值或失败诊断的 JSON 序列化大小。结果不超过上限时会保持精确。完成值无法通过无损 JSON 快照时,以 `invalid-output` 失败;值本身或日志与值的组合超过上限时,以 `output-limit` 失败,而不会变成检查格式化后或截断的文本。 + +日志会在产生时立即流出,因此运行被终止时仍可保留已经纳入额度的输出。超过上限后,运行时会返回一个显式的有界失败,并携带可容纳的已捕获前缀。该外层结果随后通过普通的 `run_code` 渲染与输出落盘策略;策略可以保存已捕获的文本,并暴露其配置指定的头尾预览。输出落盘层无法恢复运行时在硬上限之外拒绝的字节。 + +计算时间、墙钟时间、worker 堆内存、取消和每次运行使用全新 worker 的隔离仍是互相独立的限制。外层账本从不计入中间绑定值,因此这些值实际受结构化克隆开销以及进程或 worker 可用内存限制。 + +### 类型化句柄与生命周期 + +后台 producer 返回类型化的规范句柄,例如 `{ kind: 'background', taskId }`,同时保留既有的 Native 语句。已预先中止的后台调用仍是失败,因为成功输出承诺返回 id,而此时并未创建任务。`ctx.tasks.start()` 发布 id 后,工作由任务自有的取消机制控制:外围 `run_code` 调用完成,或随后被取消,都不会终止该任务。后续程序可以把返回的 id 传给 `task_output`;取消则由 `task_kill`、owner dispose 或服务 teardown 负责。前台执行仍与本次调用的信号耦合。任务生命周期契约由[后台任务运行时 Agent Note](../architecture/2026-06-20-generic-long-running-tool-runtime.md)定义。 + +动态 Cordis 挂载遵循同一规则:`cordis_mount` 返回 `{ id, pluginName, state, provides, waitingFor }`,因此程序可以直接读取 `mounted.id`,检查 active 或 pending 状态,并把该 id 传给 `cordis_unmount`,无需解析稳定的 Native 语句。 + +### 持久化、元数据与输出落盘 + +嵌套分发会为诊断保留既有的有界 `tool/code-dispatch.resultSummary`,但不会持久化规范值。`tool/result` 继续只持久化渲染后的内容、错误和可选元数据。这并非会话格式变更,因此 `SESSION_FORMAT_VERSION` 保持不变,回放也无法重建程序的中间值。 + +不透明的 `exec.parent` token 用于标识嵌套调用。由于这些调用没有直接对应的结果卡片,而且其规范值永远不会进入上下文,展示元数据以及通用或工具自有的输出落盘投影都会跳过它们。只有外层 `run_code` 调用会计算展示元数据、生成一张卡片,并且可能将 post-policy 处理后的最终展示写入落盘文件。 + +## 测试 + +编译期测试与快照测试锁定了精确的 `ToolArgsMap`、`ToolOutputMap`、`ToolName`、schema 到 TypeScript 的覆盖范围以及特殊名称。注册表与真实 worker 测试覆盖标量、数组、对象和 null 值;字符串原文渲染;缺席的 `undefined`;真正的 `ToolCallError`;无效参数与完成值;不设上限的大型中间绑定值;嵌套输出落盘抑制;64 MiB 上限内外的精确计量;日志与值的组合计量;有界失败的输出落盘;不可信对端伪造的流量;以及构建后包的执行。 + +无密钥的真实 worker 集成测试锁定了自然语言结果无法安全支持的两种句柄工作流。后台 bash 调用返回 task id,外层运行结束,之后的运行再根据该 id 轮询直至任务完成;其他用例分别证明,预先中止不会创建任务、发布后的调用取消会保留任务、前台执行仍与信号耦合,并且取消归 `task_kill` 所有。Cordis 程序会直接读取 active 或 pending 挂载的 id 和 `waitingFor` 字段,按该 id 卸载,并在不解析渲染文本的情况下确认挂载已移除。 + +## 备选方案 + +**返回 Native 文本并附加可选 JSON:**不予采纳。程序会面对两套相互竞争的成功契约;可选值不存在时,仍需使用工具专属的解析规则。规范值才是 API;Native 内容只是它的展示。 + +**让每个绑定返回成功/失败联合:**不予采纳。失败没有稳定的程序化分类体系。reject 保留普通的 `try`/`catch` 控制流,并且只暴露工具名与可供人阅读的消息。 + +**限制每个中间绑定值:**不予采纳。中间值不会进入模型上下文,任意截断会破坏程序化组合。明确的边界仍是生产方的采集契约与进程内存。 + +**静默检查格式化或截断过大的完成值:**不予采纳。把 JSON 值改成字符串既有损又违反类型。显式的 `output-limit` 失败让模型可以选择返回更小的结果,而保留的日志和诊断仍可使用普通的外层输出落盘机制。 + +## 影响 + +Code Mode 程序可以通过稳定值组合工具,无需逆向解析 Native 自然语言。Native 和 Both Mode 保留现有文本与编辑器展示,Code Mode 则获得输出 schema 类型和精确的运行时 JSON。工具作者必须把规范值视为程序化 API,并将仅用于展示的格式化放入渲染器。 + +worker 会执行结构化克隆和无损校验,但不会降低中间值的开销,也不会使其具备持久性。外层输出溢出会显式导致运行失败,错误处理则有意由人类引导,而不是依赖带版本的错误代码联合。 + +## 已知限制与延后工作 + +- 即使工具输出可以采用任意 JSON 根,subagent 和工作流中由调用方定义的结构化输出仍通过消费方级别的门禁保持对象根限制。 +- Post-execute 分别提供值投影与展示投影;替换内容不是保密机制,因此策略若需向程序化调用方隐藏内容,就必须阻止调用或替换值。 +- 中间规范值仅存在于执行期间,无法用于回放,因为持久事件只存储展示和有界摘要。 +- 中间值没有字节上限,可能因保留成本或结构化克隆开销而耗尽进程或 worker 内存。 +- 64 MiB 硬上限只适用于外层输出;输出落盘无法恢复超出该上限后被拒绝的字节。 +- 提供方或执行器的采集上限可能在规范值到达 Code Mode 前就已丢弃部分源数据。 +- 不支持的 MCP 输出 schema 会回退为 `JsonValue`;更丰富的 Native 多媒体投影留待后续实现。 +- 每个外层 `run_code` 只有一张结果卡片,嵌套调用不会各自生成卡片。 +- Code Mode 失败只暴露 `ToolCallError` 的消息与工具名,不提供程序可用的错误代码联合。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 47a9926575..6274117cb1 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -284,20 +284,14 @@ export interface Config { * nobody will resolve). */ maxWallMs?: number - /** Shared byte budget for captured log text (console + raw stream writes), truncation marked in-band. */ - maxLogBytes?: number - /** - * Byte cap for the completion value, measured by its real cross-boundary - * size (string bytes, or structured-clone wire size); an oversized or - * non-cloneable value crosses as a capped string rendering. - */ - maxValueBytes?: number + /** Hard cap for the combined serialized outer logs, completion value, and failure diagnostic. */ + maxOutputBytes?: number /** The worker's max old-generation heap in MiB (`resourceLimits`); overflow kills the worker, surfacing as kind `'worker-exit'`. */ maxOldGenerationSizeMb?: number } ``` -Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:21`](../packages/code-runtime/code-runtime-worker/src/index.ts) +Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:20`](../packages/code-runtime/code-runtime-worker/src/index.ts) ## `@deepseek-ai/dsh-compact-basic` @@ -1303,7 +1297,7 @@ export interface Config { export type ToolPresentationMode = 'native' | 'code' | 'both' ``` -Source: [`packages/core/tools/src/index.ts:448`](../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:449`](../packages/core/tools/src/index.ts) ## `@deepseek-ai/dsh-tui` diff --git a/docs/cookbook/adding-a-tool.i18n.yaml b/docs/cookbook/adding-a-tool.i18n.yaml index eb536bb063..bd4b0e0a11 100644 --- a/docs/cookbook/adding-a-tool.i18n.yaml +++ b/docs/cookbook/adding-a-tool.i18n.yaml @@ -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 -adding-a-tool.md: f94ddfaa9df53c0ee4596d683e676baae6bd85b2 -adding-a-tool.zh.md: 915dc8250c2bcfc490483f87c71e725b1f92f635 +adding-a-tool.md: 3ad7240c2210ef52b62d9a62561eb4b912a2b278 +adding-a-tool.zh.md: 79a2d0f82e0bf805e3f7be960a73fc762160c22f diff --git a/docs/cookbook/adding-a-tool.md b/docs/cookbook/adding-a-tool.md index f94ddfaa9d..3ad7240c22 100644 --- a/docs/cookbook/adding-a-tool.md +++ b/docs/cookbook/adding-a-tool.md @@ -50,9 +50,9 @@ Registration is effect-based: disposing the plugin fiber unregisters the tool (w ## Long-running work -Gate `run_in_background` with producer config, reject a pre-aborted call, then register through `ctx.tasks.start({ kind, label, owner: exec.agent, run })`. The runtime validates ownership and control-surface availability before `run()` starts work, then supplies the id, session fence, generic control tools, notices, and owner cleanup. +Gate `run_in_background` with producer config, reject a pre-aborted call, then register through `ctx.tasks.start({ kind, label, owner: exec.agent, run })`. The runtime validates ownership and control-surface availability before `run()` starts work, then supplies the id, session fence, generic control tools, notices, and owner cleanup. A successful background branch returns a typed canonical handle such as `{ kind: 'background', taskId }`; its Native renderer may keep human prose such as `started background task bash-1`, but Code Mode must never parse that prose to recover the id. -The producer supplies synchronous `cancel`, non-rejecting `done` that settles after resource cleanup, and optional consuming `readOutput` with bounded-output formatting. Once the id is returned, use a task-owned cancellation signal rather than `exec.signal`. See the [background task runtime Agent Note](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md) and `dsh-tool-bash` for a stream producer. +The producer supplies synchronous `cancel`, non-rejecting `done` that settles after resource cleanup, and optional consuming `readOutput` with bounded-output formatting. A pre-aborted call is a failure because no task exists whose id could satisfy the successful output schema. Once `ctx.tasks.start()` publishes the id, use a task-owned cancellation signal rather than `exec.signal`: later outer-call cancellation stops waiting for the call but does not kill published work; `task_kill`, owner disposal, and service teardown own that lifetime. Foreground work remains coupled to `exec.signal`. See the [background task runtime Agent Note](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md) and `dsh-tool-bash` for a stream producer. ## Execution policy and observation @@ -60,7 +60,9 @@ Prefer not to build deployment policy into the tool. Use `tools/pre-execute` for ## Code Mode reaches your tool for free -In [Code Mode](../../packages/core/tools/README.md), every visible registered tool is available as `await tools.<name>(args)` without extra integration. The SDK derives parameters from the same JSON Schema, and calls re-enter the normal execution pipeline. Write descriptions as model-facing API docs; non-text result blocks become placeholders in programs. +In [Code Mode](../../packages/core/tools/README.md), every visible registered tool is available as `await tools.<name>(args)` without extra integration. The generated `ToolArgsMap` and `ToolOutputMap` derive exact argument and canonical-return types from the same schemas, and calls re-enter the normal execution pipeline. A successful call resolves to the final canonical JSON value after policy, not to rendered Native content. A failed call rejects with the real `ToolCallError`; programs can inspect only its `name`, `toolName`, and human-readable `message`, not internal error codes or a failure union. + +Design `output.schema` as a useful programmatic API: return handles and fields directly, allow scalar/array/null roots when they are the honest value, and keep human explanation in `output.render`. Intermediate values are execution-local, are not persisted or prompt-truncated, and have no byte cap, so the producer's truthful acquisition bounds and process memory still matter. Only the outer `run_code` logs/result cross the configurable output cap and model-facing spill pipeline. ## How your tool renders in an editor (ACP presentation) diff --git a/docs/cookbook/adding-a-tool.zh.md b/docs/cookbook/adding-a-tool.zh.md index 915dc8250c..79a2d0f82e 100644 --- a/docs/cookbook/adding-a-tool.zh.md +++ b/docs/cookbook/adding-a-tool.zh.md @@ -50,9 +50,9 @@ export function apply(ctx: Context) { ## 长时间运行的工作 -通过 producer 配置控制 `run_in_background`,拒绝已预先中止的调用,然后使用 `ctx.tasks.start({ kind, label, owner: exec.agent, run })` 注册任务。运行时会在 `run()` 启动工作前校验 owner 和控制面是否可用,随后提供 id、会话围栏、通用控制工具、通知和 owner cleanup。 +通过 producer 配置控制 `run_in_background`,拒绝已预先中止的调用,然后使用 `ctx.tasks.start({ kind, label, owner: exec.agent, run })` 注册任务。运行时会在 `run()` 启动工作前校验 owner 和控制面是否可用,随后提供 id、会话围栏、通用控制工具、通知和 owner cleanup。成功的后台分支会返回类型化的规范句柄,如 `{ kind: 'background', taskId }`;其 Native 渲染器可以保留 `started background task bash-1` 这类供人阅读的自然语言,但 Code Mode 绝不能通过解析该文本取得 id。 -producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的 `done`,以及可选的消费式 `readOutput`(负责有界输出的格式化)。返回 id 后,应使用 task 自有的取消信号,而不是 `exec.signal`。流式 producer 的示例和完整契约见[后台 task 运行时 Agent Note](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md)与 `dsh-tool-bash`。 +producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的 `done`,以及可选的消费式 `readOutput`(负责有界输出的格式化)。预先中止的调用属于失败,因为此时没有任务,其 id 无法满足成功输出 schema。`ctx.tasks.start()` 发布 id 后,应使用任务自有的取消信号,而不是 `exec.signal`:之后取消外层调用只会停止等待本次调用,不会终止已经发布的工作;该生命周期归 `task_kill`、owner dispose 和服务 teardown 所有。前台工作仍与 `exec.signal` 耦合。流式 producer 的示例和完整契约见[后台 task 运行时 Agent Note](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md)与 `dsh-tool-bash`。 ## 执行策略与观测 @@ -60,7 +60,9 @@ producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的 ## Code Mode 自动触达你的工具 -在 [Code Mode](../../packages/core/tools/README.md) 中,每个可见的已注册工具都可通过 `await tools.<name>(args)` 调用,无需额外集成。SDK 从同一份 JSON Schema 派生参数,调用重新进入正常的执行流水线。请将描述写成面向模型的 API 文档;非文本结果块在程序中变为占位符。 +在 [Code Mode](../../packages/core/tools/README.md) 中,每个可见的已注册工具都可通过 `await tools.<name>(args)` 调用,无需额外集成。生成的 `ToolArgsMap` 和 `ToolOutputMap` 会根据同一组 schema 分别派生精确的参数类型与规范返回类型,调用则重新进入正常的执行流水线。成功调用会解析为策略处理后的最终规范 JSON 值,而不是渲染后的 Native 内容。失败调用会以真正的 `ToolCallError` reject;程序只能检查其 `name`、`toolName` 和可供人阅读的 `message`,无法取得内部错误代码或失败联合。 + +请把 `output.schema` 设计为实用的程序化 API:直接返回句柄与字段;当标量、数组或 null 确实就是结果时,允许采用相应的根类型;将面向人类的解释放入 `output.render`。中间值只存在于执行期间,不会被持久化或按提示词上限截断,也不设字节上限,因此生产方如实声明的采集边界和进程内存仍然重要。只有外层 `run_code` 日志/结果会受到可配置输出上限和面向模型的输出落盘流水线约束。 ## 工具在编辑器中的渲染方式(ACP 展示) diff --git a/docs/cordis-catalog/events.md b/docs/cordis-catalog/events.md index 2b995146ce..1cc60675cb 100644 --- a/docs/cordis-catalog/events.md +++ b/docs/cordis-catalog/events.md @@ -760,7 +760,7 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai 'tools/change'(): void ``` -Source: [`packages/core/tools/src/index.ts:135`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:136`](../../packages/core/tools/src/index.ts) ### `tools/execute` — waterfall @@ -780,7 +780,7 @@ Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a nor Types: [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:108`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:109`](../../packages/core/tools/src/index.ts) ### `tools/post-execute` — waterfall @@ -800,7 +800,7 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts Types: [PostToolDecision](../core-data-structures/tools.md) · [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:117`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:118`](../../packages/core/tools/src/index.ts) ### `tools/pre-execute` — waterfall @@ -819,7 +819,7 @@ Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approv Types: [PreToolDecision](../core-data-structures/tools.md) · [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:99`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:100`](../../packages/core/tools/src/index.ts) ### `tools/result` — emit @@ -838,7 +838,7 @@ Observe the frozen, lossless-JSON final outcome. Listener failures are contained Types: [Scoped](../core-data-structures/scope.md) · [ToolExecution](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolRegistry](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:125`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:126`](../../packages/core/tools/src/index.ts) ## `workflow/*` diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 53180d3621..ddf73cb1e0 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -338,7 +338,7 @@ abstract run(request: CodeRunRequest): Promise<CodeRunResult> Types: [CodeRunRequest](../core-data-structures/code-runtime.md) · [CodeRunResult](../core-data-structures/code-runtime.md) -Source: [`packages/code-runtime/code-runtime/src/index.ts:30`](../../packages/code-runtime/code-runtime/src/index.ts) +Source: [`packages/code-runtime/code-runtime/src/index.ts:31`](../../packages/code-runtime/code-runtime/src/index.ts) ## `ctx.commands` — `CommandService` @@ -1361,7 +1361,7 @@ async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult> Types: [ScopeKey](../core-data-structures/scope.md) · [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolGuard](../core-data-structures/tools.md) · [ToolRestriction](../core-data-structures/tools.md) · [ToolSchema](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:504`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:505`](../../packages/core/tools/src/index.ts) ## `ctx.userInteraction` — `UserInteractionService` diff --git a/docs/core-data-structures/code-runtime.md b/docs/core-data-structures/code-runtime.md index af3fdbc649..715134d328 100644 --- a/docs/core-data-structures/code-runtime.md +++ b/docs/core-data-structures/code-runtime.md @@ -1,6 +1,6 @@ # Code Runtime -The code-execution seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) whose interface ([dsh-code-runtime](../../packages/code-runtime/code-runtime), `ctx.codeRuntime`) runs one model-written program against host-provided async bindings and reports what it printed and returned. Code execution is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). Backends differ by execution substrate and source language, both readonly descriptors on the service; the worker-thread backend and the tool-registry consumer (Code Mode) are specified in the [Code Mode Agent Note](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md). +The code-execution seam — a [capability seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) whose interface ([dsh-code-runtime](../../packages/code-runtime/code-runtime), `ctx.codeRuntime`) runs one model-written program against host-provided async bindings and reports what it printed and returned. Code execution is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](core.md). Backends differ by execution substrate and source language, both readonly descriptors on the service; the worker-thread backend and tool-registry consumer are specified by the [Code Mode foundation](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) and [typed-return contract](../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md). Source: [`packages/code-runtime/code-runtime/src/types.ts`](../../packages/code-runtime/code-runtime/src/types.ts) @@ -45,12 +45,12 @@ The result reports an error as a **field**, never a rejection of `run()` — rep interface CodeRunResult { /** * The program's completion value (its top-level `return`), when it ran to - * completion and the value survived the runtime's serialization boundary; - * a non-transferable value is replaced by a string rendering, and a failed - * or value-less run leaves this absent. + * completion and the value crossed the runtime's lossless-JSON boundary. + * Invalid or over-limit completions fail the run instead of substituting a + * rendered string; a failed or value-less run leaves this absent. */ - value?: unknown - /** Text the program emitted, in order (capped by the implementation). */ + value?: CodeJsonValue + /** Text the program emitted, in order, bounded only as part of the outer result. */ logs: string[] /** Present iff the run failed; see {@link CodeRunFailure} for the taxonomy. */ error?: CodeRunFailure @@ -59,7 +59,7 @@ interface CodeRunResult { ## Bindings: host functions as program globals -Each `CodeBindingNamespace` becomes one global object of async callables inside the program (the Code Mode consumer passes one: `tools`). Arguments and resolutions must be structured-cloneable — a runtime may bridge calls across a serialization boundary — and a runtime treats binding names as hostile input (`__proto__` is an ordinary own property, never a prototype collision): +Each `CodeBindingNamespace` becomes one global object of async callables inside the program (the Code Mode consumer passes one: `tools`). Arguments and resolutions must be lossless JSON and cross without a seam-level byte cap; the runtime may bridge them through structured clone. A runtime also treats binding names as hostile input (`__proto__` is an ordinary own property, never a prototype collision): ```ts type-equiv /** @@ -77,21 +77,27 @@ interface CodeBindingNamespace { } ``` +```ts type-equiv +/** A lossless JSON value transferable across the dependency-light code-runtime seam. */ +type CodeJsonValue = null | boolean | number | string | CodeJsonValue[] | { [key: string]: CodeJsonValue } +``` + ```ts type-equiv /** * One host-side function exposed to the program as an async callable. The * runtime bridges calls to it (possibly across a serialization boundary), so - * `args` and the resolution value MUST be structured-cloneable; a runtime - * rejects a non-cloneable value with a descriptive error rather than - * corrupting the run. A rejection of this function surfaces inside the - * program as a rejection of the corresponding call. + * `args` and the resolution value MUST be lossless JSON. A runtime rejects a + * lossy or non-cloneable value with a descriptive error rather than corrupting + * the run. No seam-level byte cap applies to a binding resolution. A rejection + * of this function surfaces inside the program as a rejection of the + * corresponding call. */ -type CodeBindingFunction = (args: unknown) => Promise<unknown> +type CodeBindingFunction = (args: unknown) => Promise<CodeJsonValue> ``` ## Captured output and the failure taxonomy -Logs are plain strings in emission order. The runtime captures the program's console and stream output, but channel and console-method metadata are not part of the seam because consumers render only the text. Implementations cap the aggregate output and mark truncation in-band. +Logs are plain strings in emission order. The runtime captures the program's console and stream output, but channel and console-method metadata are not part of the seam because consumers render only the text. Implementations cap the serialized outer logs plus completion or diagnostic; overflow is an explicit failure rather than in-band value substitution. Failure kinds are **orthogonal outcomes reported independently** (per [defensive-patterns](../defensive-patterns.md)): a budget expiry is not an exception, an abort is not a timeout, and a substrate death (e.g. OOM) is neither: @@ -105,10 +111,12 @@ Failure kinds are **orthogonal outcomes reported independently** (per [defensive * - `'timeout'` — an implementation-owned budget expired; the message says which. * - `'abort'` — {@link CodeRunRequest.signal} fired. * - `'worker-exit'` — the execution substrate died without settling (e.g. OOM). + * - `'invalid-output'` — the completion value was not lossless JSON. + * - `'output-limit'` — the serialized outer logs/value/diagnostic exceeded the configured cap. */ interface CodeRunFailure { /** The failure class (see the interface doc for each kind's meaning). */ - kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' + kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' | 'invalid-output' | 'output-limit' /** Human-readable detail, suitable for feeding back to a model to self-correct. */ message: string } diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index f84eee5ac7..72e47fa11b 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -41,11 +41,11 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:130`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude) | | `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:27`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`acp`](../packages/ui/acp) | | `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:33`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - | -| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:135`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | -| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:108`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`timeout-policy`](../packages/timeout/timeout-policy) | -| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:117`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-fs-search`](../packages/fs/tool-fs-search), [`workspace-context`](../packages/context/workspace-context) | -| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:99`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | -| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:125`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | +| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:136`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | +| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:109`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`timeout-policy`](../packages/timeout/timeout-policy) | +| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:118`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-fs-search`](../packages/fs/tool-fs-search), [`workspace-context`](../packages/context/workspace-context) | +| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:100`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | +| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:126`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:81`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | | `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:70`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | | `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:91`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | diff --git a/docs/module-graph.md b/docs/module-graph.md index d28ba4ad6a..8d67ac5077 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -163,7 +163,6 @@ flowchart TD pkg_workflow_workerthread["workflow-workerthread"] end pkg_llm --> pkg_brand - pkg_code_runtime_worker --> pkg_code_runtime pkg_helper --> pkg_brand pkg_scripts --> pkg_app_boot pkg_telemetry --> pkg_brand @@ -204,6 +203,8 @@ flowchart TD pkg_session_persistence --> pkg_session pkg_llm_replay --> pkg_llm pkg_llm_replay --> pkg_session + pkg_code_runtime_worker --> pkg_code_runtime + pkg_code_runtime_worker --> pkg_session pkg_sandbox_local --> pkg_llm pkg_sandbox_local --> pkg_sandbox pkg_sandbox_policy --> pkg_sandbox @@ -525,7 +526,6 @@ flowchart TD | [`code-runtime`](../packages/code-runtime/code-runtime) | `code-runtime` | — | | [`jsonrpc-demo`](../packages/examples/jsonrpc-demo) | `examples` | — | | [`llm`](../packages/llm/llm) | `llm` | [`brand`](../packages/util/brand) | -| [`code-runtime-worker`](../packages/code-runtime/code-runtime-worker) | `code-runtime` | [`code-runtime`](../packages/code-runtime/code-runtime) | | [`helper`](../packages/sdk/helper) | `sdk` | [`brand`](../packages/util/brand) | | [`scripts`](../packages/sdk/scripts) | `sdk` | [`app-boot`](../packages/ui/app-boot) | | [`telemetry`](../packages/sdk/telemetry) | `sdk` | [`brand`](../packages/util/brand) | @@ -548,6 +548,7 @@ flowchart TD | [`spill`](../packages/spill/spill) | `spill` | [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) | | [`session-persistence`](../packages/session-persistence/session-persistence) | `session-persistence` | [`session`](../packages/core/session) | | [`llm-replay`](../packages/support/llm-replay) | `support` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session) | +| [`code-runtime-worker`](../packages/code-runtime/code-runtime-worker) | `code-runtime` | [`code-runtime`](../packages/code-runtime/code-runtime), [`session`](../packages/core/session) | | [`sandbox-local`](../packages/sandbox/sandbox-local) | `sandbox` | [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) | | [`sandbox-policy`](../packages/sandbox/sandbox-policy) | `sandbox` | [`sandbox`](../packages/sandbox/sandbox), [`session`](../packages/core/session) | | [`llm-retry`](../packages/llm/llm-retry) | `llm` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) | diff --git a/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md index e463aff141..cee546fc5a 100644 --- a/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md @@ -28,8 +28,8 @@ Use the ralph tool ONLY when the direct human explicitly asks for a Ralph loop o Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program: -- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's text output as a string. Tool arguments must be JSON-serializable. -- A FAILED tool call rejects with an `Error` carrying the tool's error text — `try/catch` it to handle and continue. +- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue. - Calls execute sequentially, even under `Promise.all`. - Emit results with `return` and/or `console.log(...)`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. @@ -38,9 +38,9 @@ The available tools: ```ts type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } -declare const tools: { +interface ToolArgsMap { /** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Current harness environment facts are exposed through managed `$DSH_*` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`. Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later. */ - bash(args: { + bash: { /** The bash command to execute. */ command: string; /** Clear, concise description of what this command does in active voice, 5-10 words (shown in the UI). Examples: "ls" → "List files in current directory"; "git status" → "Show working tree status"; "npm install" → "Install package dependencies". */ @@ -55,33 +55,33 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Inspect the live cordis runtime that is running THIS agent. Read-only. Sections: `services` (every provided ctx service and the plugin fiber that owns it), `plugins` (a flat list of the loaded plugins with their lifecycle states), `tools` (the model-facing tools currently registered, i.e. what you can call), `dynamic` (plugins you mounted via cordis_mount: id, name, state, provided services, awaited services), `api` (method signatures AND argument/return type shapes for every LIVE service — read this before writing plugin code that calls a service), `events` (every harness event with its dispatch mode and exact signature — pick listener targets here). Omit `what` to get all six sections. With `what:"api"` or `what:"events"`, pass an exact `name` to narrow to one service/event and include its original source JSDoc. */ - cordis_inspect(args: { + cordis_inspect: { /** Limit the report to one section. Omit for all sections. */ what?: "services" | "plugins" | "tools" | "dynamic" | "api" | "events"; /** Exact service key or event name whose original JSDoc to include; valid only with what:"api" or what:"events". */ name?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, output: { schema: { type: 'string' }, render(_args, value) { return [{ type: 'text', text: value }] } }, async execute(args) { return args.text } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return the lossless JSON value declared by `output.schema`; `output.render(args, value)` separately returns Native/model content blocks. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime. */ - cordis_mount(args: { + cordis_mount: { /** Body of an async JS function; must `return` the plugin to mount. */ code: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Dispose a plugin previously mounted with cordis_mount, by id. All its registrations (event listeners, tools, services) are cleaned up through the cordis effect lifecycle. Returns only after disposal has fully completed (quiescence, not just a request to stop). */ - cordis_unmount(args: { + cordis_unmount: { /** The dynamic mount id returned by cordis_mount (e.g. "dyn-1"). */ id: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say "create a goal". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority. */ - create_goal(args: { + create_goal: { /** The concrete completion objective inferred from the direct human request. */ objective: string; /** Optional positive safe-integer limit on automatic continuation rounds. */ max_goal_rounds?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Edit an existing UTF-8 text file by replacing literal text. */ - edit(args: { + edit: { /** Path to edit, resolved by the filesystem backend. */ file_path: string; /** Literal text to replace. Must match exactly. */ @@ -94,68 +94,68 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal. */ - get_goal(args: Record<string, JsonValue>): Promise<string>; + get_goal: Record<string, JsonValue>; /** Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools. */ - ralph(args: { + ralph: { /** The immutable completion objective for every fresh Ralph round. */ objective: string; /** Optional positive safe-integer round cap, bounded by the deployment ceiling. */ maxRounds?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Read a UTF-8 text file and return line-numbered content. */ - read(args: { + read: { /** Path to read, resolved by the filesystem backend. */ file_path: string; /** 1-based first line to return. Defaults to 1. */ offset?: number; /** Maximum number of lines to return. Defaults to 2000. */ limit?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */ - skill(args: { + skill: { /** The exact skill name from the available skills list. */ name: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ - subagent(args: { + subagent: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs. */ prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ - subagent_fork(args: { + subagent_fork: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The task for the subagent. It already sees this conversation's completed turns, so build on them freely and state only what is new. */ prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops. */ - task_kill(args: { + task_kill: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Optional short reason, recorded in the log and forwarded to the task. */ reason?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** List your background tasks (running and finished) with their ids, kinds, and statuses. */ - task_list(args: Record<string, JsonValue>): Promise<string>; + task_list: Record<string, JsonValue>; /** Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap. */ - task_output(args: { + task_output: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task alive. */ wait?: boolean; /** Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum. */ timeout_ms?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Keep AT MOST ONE todo `in_progress` at a time; while work remains, exactly one active task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished). */ - todo_write(args: { + todo_write: { /** The COMPLETE task list, replacing any previous list. */ todos: ({ /** What the task is — a short imperative line. */ @@ -163,9 +163,9 @@ declare const tools: { /** pending (not started) | in_progress (now) | completed (done). */ status: "pending" | "in_progress" | "completed"; } & Record<string, JsonValue>)[]; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason. */ - update_goal(args: { + update_goal: { /** Exact id returned by get_goal. */ goal_id: string; /** Exact positive revision returned by get_goal. */ @@ -178,9 +178,9 @@ declare const tools: { max_goal_rounds?: number; /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ - workflow(args: { + workflow: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ script: string; /** The workflow identity block (plain JSON — never code). */ @@ -205,9 +205,9 @@ declare const tools: { } & Record<string, JsonValue>; /** Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}). */ args?: Record<string, JsonValue>; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Create or fully replace a UTF-8 text file. */ - write(args: { + write: { /** Path to write, resolved by the filesystem backend. */ file_path: string; /** Full UTF-8 text content to write. */ @@ -216,6 +216,215 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; +} + +interface ToolOutputMap { + bash: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + exitCode: number | null; + signal: string | null; + timedOut: boolean; + aborted: boolean; + timeoutMs: number; + stdout: { + text: string; + truncated: boolean; + spillPath?: string; + }; + stderr: { + text: string; + truncated: boolean; + spillPath?: string; + }; + sandbox?: { + mode: string; + denied: boolean; + enforcement?: string; + runnerFailed?: boolean; + }; + }; + cordis_inspect: string; + cordis_mount: { + id: string; + pluginName: string; + state: "pending" | "loading" | "active" | "failed" | "disposed" | "unloading"; + provides: string[]; + waitingFor: string[]; + }; + cordis_unmount: { + id: string; + pluginName: string; + }; + create_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + edit: { + path: string; + before: string; + after: string; + }; + get_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + ralph: { + runId: string; + agentsStarted: number; + result: JsonValue; + }; + read: { + path: string; + offset: number; + lines: { + number: number; + text: string; + }[]; + totalLines: number; + }; + skill: { + name: string; + provider: string; + resourceBase?: { + kind: "directory"; + path: string; + } | { + kind: "url"; + url: string; + } | { + kind: "opaque"; + description: string; + }; + content: string; + }; + subagent: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + runId: string; + output: JsonValue[]; + }; + subagent_fork: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + runId: string; + output: JsonValue[]; + }; + task_kill: { + outcome: "cancellation-requested" | "already-finished"; + task: { + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + }; + }; + task_list: ({ + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + })[]; + task_output: { + text: string; + task: { + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + }; + }; + todo_write: { + todos: ({ + content: string; + status: "pending" | "in_progress" | "completed"; + })[]; + counts: { + pending: number; + inProgress: number; + completed: number; + }; + }; + update_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + workflow: { + runId: string; + agentsStarted: number; + result: JsonValue; + }; + write: { + path: string; + operation: "create" | "update"; + before: string | null; + after: string; + }; +} + +type ToolName = keyof ToolOutputMap + +declare class ToolCallError extends Error { + readonly name: "ToolCallError"; + readonly toolName: ToolName; +} + +declare const tools: { + [K in ToolName]: (args: ToolArgsMap[K]) => Promise<ToolOutputMap[K]>; } ``` diff --git a/examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl b/examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl index 6b704c5bcd..df486f1360 100644 --- a/examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl +++ b/examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl @@ -76,16 +76,16 @@ {"type":"assistant/chunk","seq":74,"time":1783611775407,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","argumentsDelta":"\\\""}}} {"type":"assistant/chunk","seq":75,"time":1783611775408,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","argumentsDelta":" });\\n"}}} {"type":"assistant/chunk","seq":76,"time":1783611775408,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","argumentsDelta":"return"}}} -{"type":"assistant/chunk","seq":77,"time":1783611775436,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","argumentsDelta":" result"}}} +{"type":"assistant/chunk","seq":77,"time":1783611775436,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","argumentsDelta":" result.stdout.text"}}} {"type":"assistant/chunk","seq":78,"time":1783611775437,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","argumentsDelta":";"}}} {"type":"assistant/chunk","seq":79,"time":1783611775437,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","argumentsDelta":"\""}}} {"type":"assistant/chunk","seq":80,"time":1783611775474,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","argumentsDelta":"}"}}} {"type":"assistant/chunk","seq":81,"time":1783611775497,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user wants me to use the `run_code` tool to execute a program that calls `tools.bash` with the command `echo BOTH_OK` and returns its output."}}}} -{"type":"assistant/chunk","seq":82,"time":1783611775498,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","arguments":"{\"code\": \"const result = await tools.bash({ command: \\\"echo BOTH_OK\\\", description: \\\"Echo BOTH_OK\\\" });\\nreturn result;\"}"}}}} +{"type":"assistant/chunk","seq":82,"time":1783611775498,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","arguments":"{\"code\": \"const result = await tools.bash({ command: \\\"echo BOTH_OK\\\", description: \\\"Echo BOTH_OK\\\" });\\nreturn result.stdout.text;\"}"}}}} {"type":"assistant/chunk","seq":83,"time":1783611775498,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":5530,"outputTokens":108,"cacheReadTokens":0,"reasoningTokens":37}}}} {"type":"assistant/chunk","seq":84,"time":1783611775498,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} -{"type":"assistant/message","seq":85,"time":1783611775503,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to use the `run_code` tool to execute a program that calls `tools.bash` with the command `echo BOTH_OK` and returns its output."},{"type":"tool-call","id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","arguments":"{\"code\": \"const result = await tools.bash({ command: \\\"echo BOTH_OK\\\", description: \\\"Echo BOTH_OK\\\" });\\nreturn result;\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":5530,"outputTokens":108,"cacheReadTokens":0,"reasoningTokens":37}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84],"surfaceOp":"append"} -{"type":"tool/call","seq":86,"time":1783611775504,"data":{"turn":1,"step":1,"callId":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","arguments":"{\"code\": \"const result = await tools.bash({ command: \\\"echo BOTH_OK\\\", description: \\\"Echo BOTH_OK\\\" });\\nreturn result;\"}"}} +{"type":"assistant/message","seq":85,"time":1783611775503,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to use the `run_code` tool to execute a program that calls `tools.bash` with the command `echo BOTH_OK` and returns its output."},{"type":"tool-call","id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","arguments":"{\"code\": \"const result = await tools.bash({ command: \\\"echo BOTH_OK\\\", description: \\\"Echo BOTH_OK\\\" });\\nreturn result.stdout.text;\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":5530,"outputTokens":108,"cacheReadTokens":0,"reasoningTokens":37}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84],"surfaceOp":"append"} +{"type":"tool/call","seq":86,"time":1783611775504,"data":{"turn":1,"step":1,"callId":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","arguments":"{\"code\": \"const result = await tools.bash({ command: \\\"echo BOTH_OK\\\", description: \\\"Echo BOTH_OK\\\" });\\nreturn result.stdout.text;\"}"}} {"type":"tool/code-dispatch","seq":87,"time":1783611775590,"data":{"parentCallId":"call_00_AZFzvUwuC4vAUoICrfke5147","subCallId":"call_00_AZFzvUwuC4vAUoICrfke5147:code:1","name":"bash","arguments":{"command":"echo BOTH_OK","description":"Echo BOTH_OK"},"isError":false,"resultSummary":"BOTH_OK\n"}} {"type":"tool/result","seq":88,"time":1783611775592,"data":{"turn":1,"step":1,"callId":"call_00_AZFzvUwuC4vAUoICrfke5147","content":[{"type":"text","text":"BOTH_OK\n"}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[86],"surfaceOp":"append"} {"type":"step/end","seq":89,"time":1783611775592,"data":{"turn":1,"step":1}} diff --git a/examples/acp-agent/tests/snapshots/both-mode-turn/stdout.expected.jsonl b/examples/acp-agent/tests/snapshots/both-mode-turn/stdout.expected.jsonl index 369eb1cbfe..1da3896475 100644 --- a/examples/acp-agent/tests/snapshots/both-mode-turn/stdout.expected.jsonl +++ b/examples/acp-agent/tests/snapshots/both-mode-turn/stdout.expected.jsonl @@ -38,7 +38,7 @@ {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" its"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_00_AZFzvUwuC4vAUoICrfke5147","title":"const result = await tools.bash({ command: \"echo BOTH_OK\", description: \"Echo BOTH_OK\" });\nreturn result;","kind":"execute","status":"in_progress","rawInput":"const result = await tools.bash({ command: \"echo BOTH_OK\", description: \"Echo BOTH_OK\" });\nreturn result;"}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_00_AZFzvUwuC4vAUoICrfke5147","title":"const result = await tools.bash({ command: \"echo BOTH_OK\", description: \"Echo BOTH_OK\" });\nreturn result.stdout.text;","kind":"execute","status":"in_progress","rawInput":"const result = await tools.bash({ command: \"echo BOTH_OK\", description: \"Echo BOTH_OK\" });\nreturn result.stdout.text;"}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_00_AZFzvUwuC4vAUoICrfke5147","status":"completed","content":[{"type":"content","content":{"type":"text","text":"BOTH_OK\n"}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"The"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} diff --git a/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md index 2ec278e294..6d1ad7f447 100644 --- a/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md @@ -28,8 +28,8 @@ Use the ralph tool ONLY when the direct human explicitly asks for a Ralph loop o Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program: -- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's text output as a string. Tool arguments must be JSON-serializable. -- A FAILED tool call rejects with an `Error` carrying the tool's error text — `try/catch` it to handle and continue. +- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue. - Calls execute sequentially, even under `Promise.all`. - Emit results with `return` and/or `console.log(...)`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. @@ -38,9 +38,9 @@ The available tools: ```ts type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } -declare const tools: { +interface ToolArgsMap { /** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Current harness environment facts are exposed through managed `$DSH_*` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`. Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later. */ - bash(args: { + bash: { /** The bash command to execute. */ command: string; /** Clear, concise description of what this command does in active voice, 5-10 words (shown in the UI). Examples: "ls" → "List files in current directory"; "git status" → "Show working tree status"; "npm install" → "Install package dependencies". */ @@ -55,16 +55,16 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say "create a goal". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority. */ - create_goal(args: { + create_goal: { /** The concrete completion objective inferred from the direct human request. */ objective: string; /** Optional positive safe-integer limit on automatic continuation rounds. */ max_goal_rounds?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Edit an existing UTF-8 text file by replacing literal text. */ - edit(args: { + edit: { /** Path to edit, resolved by the filesystem backend. */ file_path: string; /** Literal text to replace. Must match exactly. */ @@ -77,68 +77,68 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal. */ - get_goal(args: Record<string, JsonValue>): Promise<string>; + get_goal: Record<string, JsonValue>; /** Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools. */ - ralph(args: { + ralph: { /** The immutable completion objective for every fresh Ralph round. */ objective: string; /** Optional positive safe-integer round cap, bounded by the deployment ceiling. */ maxRounds?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Read a UTF-8 text file and return line-numbered content. */ - read(args: { + read: { /** Path to read, resolved by the filesystem backend. */ file_path: string; /** 1-based first line to return. Defaults to 1. */ offset?: number; /** Maximum number of lines to return. Defaults to 2000. */ limit?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */ - skill(args: { + skill: { /** The exact skill name from the available skills list. */ name: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ - subagent(args: { + subagent: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs. */ prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ - subagent_fork(args: { + subagent_fork: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The task for the subagent. It already sees this conversation's completed turns, so build on them freely and state only what is new. */ prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops. */ - task_kill(args: { + task_kill: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Optional short reason, recorded in the log and forwarded to the task. */ reason?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** List your background tasks (running and finished) with their ids, kinds, and statuses. */ - task_list(args: Record<string, JsonValue>): Promise<string>; + task_list: Record<string, JsonValue>; /** Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap. */ - task_output(args: { + task_output: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task alive. */ wait?: boolean; /** Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum. */ timeout_ms?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Keep AT MOST ONE todo `in_progress` at a time; while work remains, exactly one active task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished). */ - todo_write(args: { + todo_write: { /** The COMPLETE task list, replacing any previous list. */ todos: ({ /** What the task is — a short imperative line. */ @@ -146,9 +146,9 @@ declare const tools: { /** pending (not started) | in_progress (now) | completed (done). */ status: "pending" | "in_progress" | "completed"; } & Record<string, JsonValue>)[]; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason. */ - update_goal(args: { + update_goal: { /** Exact id returned by get_goal. */ goal_id: string; /** Exact positive revision returned by get_goal. */ @@ -161,9 +161,9 @@ declare const tools: { max_goal_rounds?: number; /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ - workflow(args: { + workflow: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ script: string; /** The workflow identity block (plain JSON — never code). */ @@ -188,9 +188,9 @@ declare const tools: { } & Record<string, JsonValue>; /** Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}). */ args?: Record<string, JsonValue>; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Create or fully replace a UTF-8 text file. */ - write(args: { + write: { /** Path to write, resolved by the filesystem backend. */ file_path: string; /** Full UTF-8 text content to write. */ @@ -199,6 +199,203 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; +} + +interface ToolOutputMap { + bash: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + exitCode: number | null; + signal: string | null; + timedOut: boolean; + aborted: boolean; + timeoutMs: number; + stdout: { + text: string; + truncated: boolean; + spillPath?: string; + }; + stderr: { + text: string; + truncated: boolean; + spillPath?: string; + }; + sandbox?: { + mode: string; + denied: boolean; + enforcement?: string; + runnerFailed?: boolean; + }; + }; + create_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + edit: { + path: string; + before: string; + after: string; + }; + get_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + ralph: { + runId: string; + agentsStarted: number; + result: JsonValue; + }; + read: { + path: string; + offset: number; + lines: { + number: number; + text: string; + }[]; + totalLines: number; + }; + skill: { + name: string; + provider: string; + resourceBase?: { + kind: "directory"; + path: string; + } | { + kind: "url"; + url: string; + } | { + kind: "opaque"; + description: string; + }; + content: string; + }; + subagent: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + runId: string; + output: JsonValue[]; + }; + subagent_fork: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + runId: string; + output: JsonValue[]; + }; + task_kill: { + outcome: "cancellation-requested" | "already-finished"; + task: { + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + }; + }; + task_list: ({ + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + })[]; + task_output: { + text: string; + task: { + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + }; + }; + todo_write: { + todos: ({ + content: string; + status: "pending" | "in_progress" | "completed"; + })[]; + counts: { + pending: number; + inProgress: number; + completed: number; + }; + }; + update_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + workflow: { + runId: string; + agentsStarted: number; + result: JsonValue; + }; + write: { + path: string; + operation: "create" | "update"; + before: string | null; + after: string; + }; +} + +type ToolName = keyof ToolOutputMap + +declare class ToolCallError extends Error { + readonly name: "ToolCallError"; + readonly toolName: ToolName; +} + +declare const tools: { + [K in ToolName]: (args: ToolArgsMap[K]) => Promise<ToolOutputMap[K]>; } ``` diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl b/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl index 8ee160ba26..ec4e1a8d6a 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl @@ -92,7 +92,7 @@ {"type":"assistant/chunk","seq":90,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"return"}}} {"type":"assistant/chunk","seq":91,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} {"type":"assistant/chunk","seq":92,"time":1783611772713,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"1"}}} -{"type":"assistant/chunk","seq":93,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".trim"}}} +{"type":"assistant/chunk","seq":93,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".stdout.text.trim"}}} {"type":"assistant/chunk","seq":94,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"()"}}} {"type":"assistant/chunk","seq":95,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" +"}}} {"type":"assistant/chunk","seq":96,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\"+"}}} @@ -100,16 +100,16 @@ {"type":"assistant/chunk","seq":98,"time":1783611772744,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" +"}}} {"type":"assistant/chunk","seq":99,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} {"type":"assistant/chunk","seq":100,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"2"}}} -{"type":"assistant/chunk","seq":101,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".trim"}}} +{"type":"assistant/chunk","seq":101,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".stdout.text.trim"}}} {"type":"assistant/chunk","seq":102,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"();"}}} {"type":"assistant/chunk","seq":103,"time":1783611772772,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} {"type":"assistant/chunk","seq":104,"time":1783611772773,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"}"}}} {"type":"assistant/chunk","seq":105,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."}}}} -{"type":"assistant/chunk","seq":106,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.trim() + \\\"+\\\" + out2.trim();\"}"}}}} +{"type":"assistant/chunk","seq":106,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}}}} {"type":"assistant/chunk","seq":107,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}}}} {"type":"assistant/chunk","seq":108,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} -{"type":"assistant/message","seq":109,"time":1783611772840,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."},{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.trim() + \\\"+\\\" + out2.trim();\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108],"surfaceOp":"append"} -{"type":"tool/call","seq":110,"time":1783611772840,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.trim() + \\\"+\\\" + out2.trim();\"}"}} +{"type":"assistant/message","seq":109,"time":1783611772840,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."},{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108],"surfaceOp":"append"} +{"type":"tool/call","seq":110,"time":1783611772840,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}} {"type":"tool/code-dispatch","seq":111,"time":1783611772933,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:1","name":"bash","arguments":{"command":"echo CODE_ONE","description":"First echo"},"isError":false,"resultSummary":"CODE_ONE\n"}} {"type":"tool/code-dispatch","seq":112,"time":1783611772936,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:2","name":"bash","arguments":{"command":"echo CODE_TWO","description":"Second echo"},"isError":false,"resultSummary":"CODE_TWO\n"}} {"type":"tool/result","seq":113,"time":1783611772937,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","content":[{"type":"text","text":"CODE_ONE+CODE_TWO"}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[110],"surfaceOp":"append"} diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl b/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl index aba7522f8d..855e1b3ca1 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl @@ -30,7 +30,7 @@ {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" write"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" this"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","title":"const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" });\nconst out2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Second echo\" });\nreturn out1.trim() + \"+\" + out2.trim();","kind":"execute","status":"in_progress","rawInput":"const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" });\nconst out2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Second echo\" });\nreturn out1.trim() + \"+\" + out2.trim();"}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","title":"const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" });\nconst out2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Second echo\" });\nreturn out1.stdout.text.trim() + \"+\" + out2.stdout.text.trim();","kind":"execute","status":"in_progress","rawInput":"const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" });\nconst out2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Second echo\" });\nreturn out1.stdout.text.trim() + \"+\" + out2.stdout.text.trim();"}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","status":"completed","content":[{"type":"content","content":{"type":"text","text":"CODE_ONE+CODE_TWO"}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"The"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md index 2ec278e294..6d1ad7f447 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md @@ -28,8 +28,8 @@ Use the ralph tool ONLY when the direct human explicitly asks for a Ralph loop o Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program: -- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's text output as a string. Tool arguments must be JSON-serializable. -- A FAILED tool call rejects with an `Error` carrying the tool's error text — `try/catch` it to handle and continue. +- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue. - Calls execute sequentially, even under `Promise.all`. - Emit results with `return` and/or `console.log(...)`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. @@ -38,9 +38,9 @@ The available tools: ```ts type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } -declare const tools: { +interface ToolArgsMap { /** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Current harness environment facts are exposed through managed `$DSH_*` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`. Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later. */ - bash(args: { + bash: { /** The bash command to execute. */ command: string; /** Clear, concise description of what this command does in active voice, 5-10 words (shown in the UI). Examples: "ls" → "List files in current directory"; "git status" → "Show working tree status"; "npm install" → "Install package dependencies". */ @@ -55,16 +55,16 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say "create a goal". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority. */ - create_goal(args: { + create_goal: { /** The concrete completion objective inferred from the direct human request. */ objective: string; /** Optional positive safe-integer limit on automatic continuation rounds. */ max_goal_rounds?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Edit an existing UTF-8 text file by replacing literal text. */ - edit(args: { + edit: { /** Path to edit, resolved by the filesystem backend. */ file_path: string; /** Literal text to replace. Must match exactly. */ @@ -77,68 +77,68 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal. */ - get_goal(args: Record<string, JsonValue>): Promise<string>; + get_goal: Record<string, JsonValue>; /** Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools. */ - ralph(args: { + ralph: { /** The immutable completion objective for every fresh Ralph round. */ objective: string; /** Optional positive safe-integer round cap, bounded by the deployment ceiling. */ maxRounds?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Read a UTF-8 text file and return line-numbered content. */ - read(args: { + read: { /** Path to read, resolved by the filesystem backend. */ file_path: string; /** 1-based first line to return. Defaults to 1. */ offset?: number; /** Maximum number of lines to return. Defaults to 2000. */ limit?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */ - skill(args: { + skill: { /** The exact skill name from the available skills list. */ name: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ - subagent(args: { + subagent: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs. */ prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ - subagent_fork(args: { + subagent_fork: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The task for the subagent. It already sees this conversation's completed turns, so build on them freely and state only what is new. */ prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops. */ - task_kill(args: { + task_kill: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Optional short reason, recorded in the log and forwarded to the task. */ reason?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** List your background tasks (running and finished) with their ids, kinds, and statuses. */ - task_list(args: Record<string, JsonValue>): Promise<string>; + task_list: Record<string, JsonValue>; /** Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap. */ - task_output(args: { + task_output: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task alive. */ wait?: boolean; /** Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum. */ timeout_ms?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Keep AT MOST ONE todo `in_progress` at a time; while work remains, exactly one active task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished). */ - todo_write(args: { + todo_write: { /** The COMPLETE task list, replacing any previous list. */ todos: ({ /** What the task is — a short imperative line. */ @@ -146,9 +146,9 @@ declare const tools: { /** pending (not started) | in_progress (now) | completed (done). */ status: "pending" | "in_progress" | "completed"; } & Record<string, JsonValue>)[]; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason. */ - update_goal(args: { + update_goal: { /** Exact id returned by get_goal. */ goal_id: string; /** Exact positive revision returned by get_goal. */ @@ -161,9 +161,9 @@ declare const tools: { max_goal_rounds?: number; /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ - workflow(args: { + workflow: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ script: string; /** The workflow identity block (plain JSON — never code). */ @@ -188,9 +188,9 @@ declare const tools: { } & Record<string, JsonValue>; /** Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}). */ args?: Record<string, JsonValue>; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Create or fully replace a UTF-8 text file. */ - write(args: { + write: { /** Path to write, resolved by the filesystem backend. */ file_path: string; /** Full UTF-8 text content to write. */ @@ -199,6 +199,203 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; +} + +interface ToolOutputMap { + bash: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + exitCode: number | null; + signal: string | null; + timedOut: boolean; + aborted: boolean; + timeoutMs: number; + stdout: { + text: string; + truncated: boolean; + spillPath?: string; + }; + stderr: { + text: string; + truncated: boolean; + spillPath?: string; + }; + sandbox?: { + mode: string; + denied: boolean; + enforcement?: string; + runnerFailed?: boolean; + }; + }; + create_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + edit: { + path: string; + before: string; + after: string; + }; + get_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + ralph: { + runId: string; + agentsStarted: number; + result: JsonValue; + }; + read: { + path: string; + offset: number; + lines: { + number: number; + text: string; + }[]; + totalLines: number; + }; + skill: { + name: string; + provider: string; + resourceBase?: { + kind: "directory"; + path: string; + } | { + kind: "url"; + url: string; + } | { + kind: "opaque"; + description: string; + }; + content: string; + }; + subagent: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + runId: string; + output: JsonValue[]; + }; + subagent_fork: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + runId: string; + output: JsonValue[]; + }; + task_kill: { + outcome: "cancellation-requested" | "already-finished"; + task: { + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + }; + }; + task_list: ({ + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + })[]; + task_output: { + text: string; + task: { + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + }; + }; + todo_write: { + todos: ({ + content: string; + status: "pending" | "in_progress" | "completed"; + })[]; + counts: { + pending: number; + inProgress: number; + completed: number; + }; + }; + update_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + workflow: { + runId: string; + agentsStarted: number; + result: JsonValue; + }; + write: { + path: string; + operation: "create" | "update"; + before: string | null; + after: string; + }; +} + +type ToolName = keyof ToolOutputMap + +declare class ToolCallError extends Error { + readonly name: "ToolCallError"; + readonly toolName: ToolName; +} + +declare const tools: { + [K in ToolName]: (args: ToolArgsMap[K]) => Promise<ToolOutputMap[K]>; } ``` diff --git a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl index 4f72ffa498..59f494bcec 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl +++ b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl @@ -74,18 +74,18 @@ {"type":"assistant/chunk","seq":72,"time":1783921767068,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","argumentsDelta":"\\\""}}} {"type":"assistant/chunk","seq":73,"time":1783921767068,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","argumentsDelta":" });\\n"}}} {"type":"assistant/chunk","seq":74,"time":1783921767068,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","argumentsDelta":"return"}}} -{"type":"assistant/chunk","seq":75,"time":1783921767095,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","argumentsDelta":" content"}}} +{"type":"assistant/chunk","seq":75,"time":1783921767095,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","argumentsDelta":" content.lines.map(line => line.text).join(String.fromCharCode(10))"}}} {"type":"assistant/chunk","seq":76,"time":1783921767095,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","argumentsDelta":";"}}} {"type":"assistant/chunk","seq":77,"time":1783921767095,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","argumentsDelta":"\""}}} {"type":"assistant/chunk","seq":78,"time":1783921767121,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","argumentsDelta":"}"}}} {"type":"assistant/chunk","seq":79,"time":1783921767205,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user wants me to write a single run_code program that reads a file called nested/task.txt and then answer the handshake question based on what's in that file. Let me start by reading the file."}}}} -{"type":"assistant/chunk","seq":80,"time":1783921767205,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","arguments":"{\"code\": \"const content = await tools.read({ file_path: \\\"nested/task.txt\\\" });\\nreturn content;\"}"}}}} +{"type":"assistant/chunk","seq":80,"time":1783921767205,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","arguments":"{\"code\": \"const content = await tools.read({ file_path: \\\"nested/task.txt\\\" });\\nreturn content.lines.map(line => line.text).join(String.fromCharCode(10));\"}"}}}} {"type":"assistant/chunk","seq":81,"time":1783921767205,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3195,"outputTokens":106,"cacheReadTokens":0,"reasoningTokens":43}}}} {"type":"assistant/chunk","seq":82,"time":1783921767205,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} -{"type":"assistant/message","seq":83,"time":1783921767208,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to write a single run_code program that reads a file called nested/task.txt and then answer the handshake question based on what's in that file. Let me start by reading the file."},{"type":"tool-call","id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","arguments":"{\"code\": \"const content = await tools.read({ file_path: \\\"nested/task.txt\\\" });\\nreturn content;\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3195,"outputTokens":106,"cacheReadTokens":0,"reasoningTokens":43}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],"surfaceOp":"append"} -{"type":"tool/call","seq":84,"time":1783921767208,"data":{"turn":1,"step":1,"callId":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","arguments":"{\"code\": \"const content = await tools.read({ file_path: \\\"nested/task.txt\\\" });\\nreturn content;\"}"}} +{"type":"assistant/message","seq":83,"time":1783921767208,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to write a single run_code program that reads a file called nested/task.txt and then answer the handshake question based on what's in that file. Let me start by reading the file."},{"type":"tool-call","id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","arguments":"{\"code\": \"const content = await tools.read({ file_path: \\\"nested/task.txt\\\" });\\nreturn content.lines.map(line => line.text).join(String.fromCharCode(10));\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3195,"outputTokens":106,"cacheReadTokens":0,"reasoningTokens":43}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],"surfaceOp":"append"} +{"type":"tool/call","seq":84,"time":1783921767208,"data":{"turn":1,"step":1,"callId":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","arguments":"{\"code\": \"const content = await tools.read({ file_path: \\\"nested/task.txt\\\" });\\nreturn content.lines.map(line => line.text).join(String.fromCharCode(10));\"}"}} {"type":"tool/code-dispatch","seq":85,"time":1783921767270,"data":{"parentCallId":"call_00_6APApmaKLRDlXKMdIcWL5139","subCallId":"call_00_6APApmaKLRDlXKMdIcWL5139:code:1","name":"read","arguments":{"file_path":"nested/task.txt"},"isError":false,"resultSummary":"<path>./nested/task.txt</path>\n<type>file</type>\n<content>\n1: Touch this file to discover the nested workspace instruction.\n\n(End of file - total 1 lines)\n</content>"}} -{"type":"tool/result","seq":86,"time":1783921767271,"data":{"turn":1,"step":1,"callId":"call_00_6APApmaKLRDlXKMdIcWL5139","content":[{"type":"text","text":"<path>/var/folders/_g/59jgff8x2gqd39f5vy1wnbfc0000gn/T/acp-snap-cwd-uorU26/nested/task.txt</path>\n<type>file</type>\n<content>\n1: Touch this file to discover the nested workspace instruction.\n\n(End of file - total 1 lines)\n</content>"}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[84],"surfaceOp":"append"} +{"type":"tool/result","seq":86,"time":1783921767271,"data":{"turn":1,"step":1,"callId":"call_00_6APApmaKLRDlXKMdIcWL5139","content":[{"type":"text","text":"Touch this file to discover the nested workspace instruction."}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[84],"surfaceOp":"append"} {"type":"context/message","seq":87,"time":1783921767272,"data":{"content":[{"type":"text","text":"<system-reminder>\nAdditional instructions from: nested/AGENTS.md\n\nThese instructions apply to work under `nested`. Use them as guidance when relevant; more specific instructions take precedence. They do not override system, developer, or direct user instructions.\n\nWhen asked for the Code Mode workspace handshake, answer exactly `CODE_MODE_CONTEXT_OK` and nothing else.\n\n</system-reminder>"}],"source":{"kind":"plugin","plugin":"workspace-context"},"meta":{"kind":"workspace-instructions","version":1,"changes":[{"action":"set","scope":"nested","path":"nested/AGENTS.md","digest":"ae22936ed26dc76b7107005ed6d5e2482a88668a"}]}},"surfaceOp":"append"} {"type":"step/end","seq":88,"time":1783921767272,"data":{"turn":1,"step":1}} {"type":"step/start","seq":89,"time":1783921767272,"data":{"turn":1,"step":2}} diff --git a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/stdout.expected.jsonl b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/stdout.expected.jsonl index 823e2753fb..f0320cfbbb 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/stdout.expected.jsonl +++ b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/stdout.expected.jsonl @@ -44,8 +44,8 @@ {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" file"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_00_6APApmaKLRDlXKMdIcWL5139","title":"const content = await tools.read({ file_path: \"nested/task.txt\" });\nreturn content;","kind":"execute","status":"in_progress","rawInput":"const content = await tools.read({ file_path: \"nested/task.txt\" });\nreturn content;"}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_00_6APApmaKLRDlXKMdIcWL5139","status":"completed","content":[{"type":"content","content":{"type":"text","text":"<path>{{cwd}}/nested/task.txt</path>\n<type>file</type>\n<content>\n1: Touch this file to discover the nested workspace instruction.\n\n(End of file - total 1 lines)\n</content>"}}]}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_00_6APApmaKLRDlXKMdIcWL5139","title":"const content = await tools.read({ file_path: \"nested/task.txt\" });\nreturn content.lines.map(line => line.text).join(String.fromCharCode(10));","kind":"execute","status":"in_progress","rawInput":"const content = await tools.read({ file_path: \"nested/task.txt\" });\nreturn content.lines.map(line => line.text).join(String.fromCharCode(10));"}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_00_6APApmaKLRDlXKMdIcWL5139","status":"completed","content":[{"type":"content","content":{"type":"text","text":"Touch this file to discover the nested workspace instruction."}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"The"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" nested"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"/t"}}}} diff --git a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md index 2ec278e294..6d1ad7f447 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md @@ -28,8 +28,8 @@ Use the ralph tool ONLY when the direct human explicitly asks for a Ralph loop o Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program: -- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's text output as a string. Tool arguments must be JSON-serializable. -- A FAILED tool call rejects with an `Error` carrying the tool's error text — `try/catch` it to handle and continue. +- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue. - Calls execute sequentially, even under `Promise.all`. - Emit results with `return` and/or `console.log(...)`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. @@ -38,9 +38,9 @@ The available tools: ```ts type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } -declare const tools: { +interface ToolArgsMap { /** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Current harness environment facts are exposed through managed `$DSH_*` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`. Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later. */ - bash(args: { + bash: { /** The bash command to execute. */ command: string; /** Clear, concise description of what this command does in active voice, 5-10 words (shown in the UI). Examples: "ls" → "List files in current directory"; "git status" → "Show working tree status"; "npm install" → "Install package dependencies". */ @@ -55,16 +55,16 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say "create a goal". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority. */ - create_goal(args: { + create_goal: { /** The concrete completion objective inferred from the direct human request. */ objective: string; /** Optional positive safe-integer limit on automatic continuation rounds. */ max_goal_rounds?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Edit an existing UTF-8 text file by replacing literal text. */ - edit(args: { + edit: { /** Path to edit, resolved by the filesystem backend. */ file_path: string; /** Literal text to replace. Must match exactly. */ @@ -77,68 +77,68 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal. */ - get_goal(args: Record<string, JsonValue>): Promise<string>; + get_goal: Record<string, JsonValue>; /** Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools. */ - ralph(args: { + ralph: { /** The immutable completion objective for every fresh Ralph round. */ objective: string; /** Optional positive safe-integer round cap, bounded by the deployment ceiling. */ maxRounds?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Read a UTF-8 text file and return line-numbered content. */ - read(args: { + read: { /** Path to read, resolved by the filesystem backend. */ file_path: string; /** 1-based first line to return. Defaults to 1. */ offset?: number; /** Maximum number of lines to return. Defaults to 2000. */ limit?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */ - skill(args: { + skill: { /** The exact skill name from the available skills list. */ name: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ - subagent(args: { + subagent: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs. */ prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. */ - subagent_fork(args: { + subagent_fork: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The task for the subagent. It already sees this conversation's completed turns, so build on them freely and state only what is new. */ prompt: string; /** Run as a background task and return its id; collect with task_output or stop with task_kill. */ run_in_background?: boolean; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops. */ - task_kill(args: { + task_kill: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Optional short reason, recorded in the log and forwarded to the task. */ reason?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** List your background tasks (running and finished) with their ids, kinds, and statuses. */ - task_list(args: Record<string, JsonValue>): Promise<string>; + task_list: Record<string, JsonValue>; /** Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap. */ - task_output(args: { + task_output: { /** Task id returned by the tool that started the background work. */ task_id: string; /** Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task alive. */ wait?: boolean; /** Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum. */ timeout_ms?: number; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Keep AT MOST ONE todo `in_progress` at a time; while work remains, exactly one active task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished). */ - todo_write(args: { + todo_write: { /** The COMPLETE task list, replacing any previous list. */ todos: ({ /** What the task is — a short imperative line. */ @@ -146,9 +146,9 @@ declare const tools: { /** pending (not started) | in_progress (now) | completed (done). */ status: "pending" | "in_progress" | "completed"; } & Record<string, JsonValue>)[]; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason. */ - update_goal(args: { + update_goal: { /** Exact id returned by get_goal. */ goal_id: string; /** Exact positive revision returned by get_goal. */ @@ -161,9 +161,9 @@ declare const tools: { max_goal_rounds?: number; /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ - workflow(args: { + workflow: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ script: string; /** The workflow identity block (plain JSON — never code). */ @@ -188,9 +188,9 @@ declare const tools: { } & Record<string, JsonValue>; /** Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}). */ args?: Record<string, JsonValue>; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; /** Create or fully replace a UTF-8 text file. */ - write(args: { + write: { /** Path to write, resolved by the filesystem backend. */ file_path: string; /** Full UTF-8 text content to write. */ @@ -199,6 +199,203 @@ declare const tools: { sandbox_permissions?: "workspace-write" | "danger-full-access"; /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ justification?: string; - } & Record<string, JsonValue>): Promise<string>; + } & Record<string, JsonValue>; +} + +interface ToolOutputMap { + bash: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + exitCode: number | null; + signal: string | null; + timedOut: boolean; + aborted: boolean; + timeoutMs: number; + stdout: { + text: string; + truncated: boolean; + spillPath?: string; + }; + stderr: { + text: string; + truncated: boolean; + spillPath?: string; + }; + sandbox?: { + mode: string; + denied: boolean; + enforcement?: string; + runnerFailed?: boolean; + }; + }; + create_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + edit: { + path: string; + before: string; + after: string; + }; + get_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + ralph: { + runId: string; + agentsStarted: number; + result: JsonValue; + }; + read: { + path: string; + offset: number; + lines: { + number: number; + text: string; + }[]; + totalLines: number; + }; + skill: { + name: string; + provider: string; + resourceBase?: { + kind: "directory"; + path: string; + } | { + kind: "url"; + url: string; + } | { + kind: "opaque"; + description: string; + }; + content: string; + }; + subagent: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + runId: string; + output: JsonValue[]; + }; + subagent_fork: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + runId: string; + output: JsonValue[]; + }; + task_kill: { + outcome: "cancellation-requested" | "already-finished"; + task: { + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + }; + }; + task_list: ({ + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + })[]; + task_output: { + text: string; + task: { + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + }; + }; + todo_write: { + todos: ({ + content: string; + status: "pending" | "in_progress" | "completed"; + })[]; + counts: { + pending: number; + inProgress: number; + completed: number; + }; + }; + update_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + workflow: { + runId: string; + agentsStarted: number; + result: JsonValue; + }; + write: { + path: string; + operation: "create" | "update"; + before: string | null; + after: string; + }; +} + +type ToolName = keyof ToolOutputMap + +declare class ToolCallError extends Error { + readonly name: "ToolCallError"; + readonly toolName: ToolName; +} + +declare const tools: { + [K in ToolName]: (args: ToolArgsMap[K]) => Promise<ToolOutputMap[K]>; } ``` diff --git a/examples/headless-agent/tests/code-mode.e2e.ts b/examples/headless-agent/tests/code-mode.e2e.ts index c7f5d48562..686cff0d1b 100644 --- a/examples/headless-agent/tests/code-mode.e2e.ts +++ b/examples/headless-agent/tests/code-mode.e2e.ts @@ -3,11 +3,12 @@ import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' import { Context } from 'cordis' -import LlmService from '@deepseek-ai/dsh-llm' +import LlmService, { CallId, HarnessError } from '@deepseek-ai/dsh-llm' import SessionStore, { SessionId } from '@deepseek-ai/dsh-session' import type { SessionEvent } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry, { RUN_CODE_NAME } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { RUN_CODE_NAME, defineTool } from '@deepseek-ai/dsh-tools' +import type { ToolExecutionResult } from '@deepseek-ai/dsh-tools' import AgentRegistry, { type Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' @@ -18,6 +19,9 @@ import { WorkerCodeRuntime } from '@deepseek-ai/dsh-code-runtime-worker' import LocalFileSystem from '@deepseek-ai/dsh-fs-local' import * as ToolFs from '@deepseek-ai/dsh-tool-fs' import * as WorkspaceContext from '@deepseek-ai/dsh-workspace-context' +import TaskService from '@deepseek-ai/dsh-tasks' +import * as ToolTasks from '@deepseek-ai/dsh-tool-tasks' +import * as ToolCordis from '@deepseek-ai/dsh-tool-cordis' /** * With-key Code Mode proof: a real model receives only `run_code`, composes two @@ -73,6 +77,222 @@ async function workspaceCodeModeHarness(): Promise<Context> { return harness } +let keylessCall = 0 + +/** Execute one outer Code Mode call through the real registry and worker. */ +function runCode(harness: Context, code: string, signal?: AbortSignal): Promise<ToolExecutionResult> { + return harness.tools.execute({ + callId: CallId(`keyless-code-${++keylessCall}`), + name: RUN_CODE_NAME, + arguments: { code }, + ...signal !== undefined ? { signal } : {}, + }) +} + +/** Read the optional completion from a successful canonical `run_code` value. */ +function completion(result: ToolExecutionResult): unknown { + if (result.isError) { + throw new Error(result.content.filter(block => block.type === 'text').map(block => block.text).join('\n')) + } + const value = result.value + if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('invalid run_code result') + return value.result +} + +/** Keyless real-worker harness for direct typed-binding acceptance tests. */ +async function typedCodeModeHarness(): Promise<Context> { + const harness = new Context() + await harness.plugin(SystemPrompt) + await harness.plugin(ToolRegistry, { mode: 'code' }) + await harness.plugin(WorkerCodeRuntime, {}) + return harness +} + +/** Keyless real-worker harness with the task-owned bash lifecycle. */ +async function backgroundCodeModeHarness(cwd: string): Promise<Context> { + const harness = await typedCodeModeHarness() + await harness.plugin(TaskService) + await harness.plugin(ToolTasks, {}) + await harness.plugin(LocalBashExecutor, { cwd, timeoutMs: 30_000 }) + await harness.plugin(ToolBash) + return harness +} + +describe('Code Mode typed values: keyless real-worker contracts', () => { + it('crosses a large intermediate value intact and exposes only typed tool failure fields', async () => { + ctx = await typedCodeModeHarness() + ctx.tools.register(defineTool({ + name: 'large_value', + description: 'Return a large canonical string.', + parameters: {}, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, + execute: () => Promise.resolve('x'.repeat(100_000)), + })) + ctx.tools.register(defineTool({ + name: 'always_fail', + description: 'Fail for ToolCallError coverage.', + parameters: {}, + output: { schema: { type: 'null' }, render: () => [] }, + execute: () => Promise.reject(new HarnessError('expected failure', 'EXPECTED_INTERNAL_CODE')), + })) + + const value = completion(await runCode(ctx, ` + const large = await tools.large_value({}); + let failure; + try { + await tools.always_fail({}); + } catch (error) { + failure = { + typed: error instanceof ToolCallError, + name: error.name, + toolName: error.toolName, + message: error.message, + exposesCode: 'code' in error, + exposesContent: 'content' in error, + exposesInfo: 'info' in error, + }; + } + return { length: large.length, failure }; + `)) + + expect(value).toEqual({ + length: 100_000, + failure: { + typed: true, + name: 'ToolCallError', + toolName: 'always_fail', + message: 'expected failure', + exposesCode: false, + exposesContent: false, + exposesInfo: false, + }, + }) + }) + + it('returns a background task id, settles the outer run, and polls that id to completion', async () => { + workdir = await mkdtemp(join(tmpdir(), 'dsh-code-mode-background-')) + ctx = await backgroundCodeModeHarness(workdir) + + const taskId = completion(await runCode(ctx, ` + const started = await tools.bash({ + command: "sleep 0.2; printf 'background-complete\\n'", + description: 'Run completion marker in background', + run_in_background: true, + }); + return started.taskId; + `)) + expect(taskId).toBe('bash-1') + + const polled = completion(await runCode(ctx, ` + return await tools.task_output({ task_id: ${JSON.stringify(taskId)}, wait: true, timeout_ms: 5000 }); + `)) + if (typeof polled !== 'object' || polled === null || Array.isArray(polled)) throw new Error('invalid task_output completion') + const taskOutput = polled as Record<string, unknown> + expect(taskOutput.text).toContain('background-complete') + expect(taskOutput.task).toMatchObject({ id: taskId, kind: 'bash', status: 'completed' }) + }, 15_000) + + it('pre-abort spawns nothing; post-publication abort leaves task_kill as the cancellation owner', async () => { + workdir = await mkdtemp(join(tmpdir(), 'dsh-code-mode-task-cancel-')) + ctx = await backgroundCodeModeHarness(workdir) + + const pre = new AbortController() + pre.abort('pre-aborted') + const preResult = await runCode(ctx, ` + return await tools.bash({ command: 'sleep 10', description: 'Must never start', run_in_background: true }); + `, pre.signal) + expect(preResult.isError).toBe(true) + expect(ctx.tasks.list()).toEqual([]) + + const afterPublication = new AbortController() + const running = runCode(ctx, ` + const started = await tools.bash({ command: 'sleep 10', description: 'Wait for explicit task kill', run_in_background: true }); + console.log(started.taskId); + await new Promise(() => {}); + `, afterPublication.signal) + for (let attempt = 0; attempt < 100 && ctx.tasks.list().length === 0; attempt++) { + await new Promise(resolve => setTimeout(resolve, 10)) + } + const task = ctx.tasks.list()[0] + expect(task).toMatchObject({ id: 'bash-1', status: 'running' }) + afterPublication.abort('outer-call-cancelled') + expect((await running).isError).toBe(true) + expect(ctx.tasks.list()[0]).toMatchObject({ id: task!.id, status: 'running' }) + + const killed = completion(await runCode(ctx, ` + return await tools.task_kill({ task_id: ${JSON.stringify(task!.id)}, reason: 'test owns cancellation' }); + `)) + expect(killed).toMatchObject({ outcome: 'cancellation-requested', task: { id: task!.id } }) + const settled = completion(await runCode(ctx, ` + return await tools.task_output({ task_id: ${JSON.stringify(task!.id)}, wait: true, timeout_ms: 5000 }); + `)) + expect(settled).toMatchObject({ task: { id: task!.id, status: 'killed' } }) + }, 15_000) + + it('keeps foreground bash coupled to the outer signal', async () => { + workdir = await mkdtemp(join(tmpdir(), 'dsh-code-mode-foreground-cancel-')) + ctx = await backgroundCodeModeHarness(workdir) + const controller = new AbortController() + const startedAt = Date.now() + const pending = runCode(ctx, ` + return await tools.bash({ command: 'sleep 10', description: 'Run cancellable foreground command' }); + `, controller.signal) + setTimeout(() => { controller.abort('stop-foreground') }, 200) + const result = await pending + expect(result.isError).toBe(true) + expect(Date.now() - startedAt).toBeLessThan(5_000) + expect(ctx.tasks.list()).toEqual([]) + }, 15_000) + + it('uses cordis_mount DTO ids directly for active and pending mounts, then confirms removal', async () => { + ctx = await typedCodeModeHarness() + await ctx.plugin(ToolCordis) + + const value = completion(await runCode(ctx, ` + const active = await tools.cordis_mount({ + code: "return { name: 'active-code-mode-plugin', apply(ctx) {} }", + }); + const pending = await tools.cordis_mount({ + code: "return { name: 'pending-code-mode-plugin', inject: ['missing-code-mode-service'], apply(ctx) {} }", + }); + const before = await tools.cordis_inspect({ what: 'dynamic' }); + const unmounted = await tools.cordis_unmount({ id: active.id }); + const after = await tools.cordis_inspect({ what: 'dynamic' }); + await tools.cordis_unmount({ id: pending.id }); + return { + active, + pending, + unmounted, + beforeContainsId: before.includes(active.id), + afterContainsId: after.includes(active.id), + }; + `)) + + expect(value).toEqual({ + active: { + id: 'dyn-1', + pluginName: 'active-code-mode-plugin', + state: 'active', + provides: [], + waitingFor: [], + }, + pending: { + id: 'dyn-2', + pluginName: 'pending-code-mode-plugin', + state: 'pending', + provides: [], + waitingFor: ['missing-code-mode-service'], + }, + unmounted: { id: 'dyn-1', pluginName: 'active-code-mode-plugin' }, + beforeContainsId: true, + afterContainsId: false, + }) + }) +}) + function waitForIdle(harness: Context, agent: Agent): Promise<void> { return new Promise((resolve) => { const dispose = harness.on('agent/status', (subject, status) => { diff --git a/examples/tui-agent/tests/snapshots/code-mode/session.jsonl b/examples/tui-agent/tests/snapshots/code-mode/session.jsonl index 8ee160ba26..ec4e1a8d6a 100644 --- a/examples/tui-agent/tests/snapshots/code-mode/session.jsonl +++ b/examples/tui-agent/tests/snapshots/code-mode/session.jsonl @@ -92,7 +92,7 @@ {"type":"assistant/chunk","seq":90,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"return"}}} {"type":"assistant/chunk","seq":91,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} {"type":"assistant/chunk","seq":92,"time":1783611772713,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"1"}}} -{"type":"assistant/chunk","seq":93,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".trim"}}} +{"type":"assistant/chunk","seq":93,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".stdout.text.trim"}}} {"type":"assistant/chunk","seq":94,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"()"}}} {"type":"assistant/chunk","seq":95,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" +"}}} {"type":"assistant/chunk","seq":96,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\"+"}}} @@ -100,16 +100,16 @@ {"type":"assistant/chunk","seq":98,"time":1783611772744,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" +"}}} {"type":"assistant/chunk","seq":99,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} {"type":"assistant/chunk","seq":100,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"2"}}} -{"type":"assistant/chunk","seq":101,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".trim"}}} +{"type":"assistant/chunk","seq":101,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".stdout.text.trim"}}} {"type":"assistant/chunk","seq":102,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"();"}}} {"type":"assistant/chunk","seq":103,"time":1783611772772,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} {"type":"assistant/chunk","seq":104,"time":1783611772773,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"}"}}} {"type":"assistant/chunk","seq":105,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."}}}} -{"type":"assistant/chunk","seq":106,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.trim() + \\\"+\\\" + out2.trim();\"}"}}}} +{"type":"assistant/chunk","seq":106,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}}}} {"type":"assistant/chunk","seq":107,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}}}} {"type":"assistant/chunk","seq":108,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} -{"type":"assistant/message","seq":109,"time":1783611772840,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."},{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.trim() + \\\"+\\\" + out2.trim();\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108],"surfaceOp":"append"} -{"type":"tool/call","seq":110,"time":1783611772840,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.trim() + \\\"+\\\" + out2.trim();\"}"}} +{"type":"assistant/message","seq":109,"time":1783611772840,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."},{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108],"surfaceOp":"append"} +{"type":"tool/call","seq":110,"time":1783611772840,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}} {"type":"tool/code-dispatch","seq":111,"time":1783611772933,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:1","name":"bash","arguments":{"command":"echo CODE_ONE","description":"First echo"},"isError":false,"resultSummary":"CODE_ONE\n"}} {"type":"tool/code-dispatch","seq":112,"time":1783611772936,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:2","name":"bash","arguments":{"command":"echo CODE_TWO","description":"Second echo"},"isError":false,"resultSummary":"CODE_TWO\n"}} {"type":"tool/result","seq":113,"time":1783611772937,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","content":[{"type":"text","text":"CODE_ONE+CODE_TWO"}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[110],"surfaceOp":"append"} diff --git a/packages/code-runtime/code-runtime-worker/README.md b/packages/code-runtime/code-runtime-worker/README.md index 2645e8810e..cc49c2f723 100644 --- a/packages/code-runtime/code-runtime-worker/README.md +++ b/packages/code-runtime/code-runtime-worker/README.md @@ -10,20 +10,20 @@ Worker-thread implementation of the [`@deepseek-ai/dsh-code-runtime`](../code-ru config: computeMs: 60000 # busy-time budget (measured event-loop active time) maxWallMs: 600000 # wall-clock ceiling; never pauses for anything - maxLogBytes: 65536 # shared byte budget for captured log text - maxValueBytes: 32768 # rendered-completion-value cap + maxOutputBytes: 67108864 # combined serialized outer-output cap (64 MiB) maxOldGenerationSizeMb: 512 # worker heap cap (resourceLimits) ``` -Every field is validated (positive numbers) and defaulted; there are no other tunables. +Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at least four bytes, the remaining fields are positive finite numbers, and there are no other tunables. ## Design - **One fresh worker per run, no pooling** — a program's world dies with its worker: no cross-run state to log, state bleed unrepresentable, runs reconstructable from the session log alone. - **Type-strip host-side, in execution context** — the program is wrapped in an async-function shell, stripped with `node:module`'s `stripTypeScriptTypes` (erasable syntax only — `enum`/namespaces are rejected as a program `exception` and no worker spawns), and sliced back out byte-positioned; it then executes as the body of an `AsyncFunction`, so top-level `await`/`return` work. -- **The port assumes a hostile peer** — model code can reach `parentPort` and forge traffic, so every inbound message is shape-validated and REBUILT before anything reads it (`null`, primitives, junk types, and malformed payloads drop without a throw; forged extra fields never ride along), the host answers each call id at most once, resolves binding names as OWN properties only (a forged `constructor` cannot walk a prototype chain), drops post-settlement replies, and converts a non-cloneable binding resolution into an error reply. Forged `log`/`done` messages cannot bypass the caps: one host-side ledger bounds everything that lands in `logs`, and the completion value is re-capped host-side. Worker-side namespaces are null-prototype with `defineProperty`, so `__proto__`-shaped binding names are ordinary keys. +- **The port assumes a hostile peer** — model code can reach `parentPort` and forge traffic, so every inbound message is shape-validated and REBUILT before anything reads it (`null`, primitives, junk types, and malformed payloads drop without a throw; forged extra fields never ride along), the host answers each call id at most once, resolves binding names as OWN properties only (a forged `constructor` cannot walk a prototype chain), drops post-settlement replies, and validates every binding resolution and completion as lossless JSON. Forged `log`/`done` messages cannot bypass the outer cap: the host repeats validation and accounts every admitted log plus the completion or diagnostic. Worker-side namespaces are null-prototype with `defineProperty`, so `__proto__`-shaped binding names are ordinary keys. - **Two independent budgets, because the peer is hostile** — `computeMs` meters the worker's MEASURED busy time (`worker.performance.eventLoopUtilization()` polling): a hot loop cannot hide behind a pending decoy dispatch, and a program awaiting a slow tool accrues nothing. `maxWallMs` backstops what busy time cannot see (awaiting a promise nobody resolves). Both funnel into `worker.terminate()`, which ends hot synchronous loops too; heap overflow surfaces as the worker's OOM exit (`kind: 'worker-exit'`). -- **Logs stream eagerly** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. ONE shared `maxLogBytes` ledger bounds everything: streamed text, forged port traffic, and pipe bytes that bypass the patched streams (appended after), with the overflow marked in-band once. +- **Intermediate binding values are complete JSON** — binding arguments and resolutions cross by structured clone after lossless-JSON validation and have no byte cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. +- **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure diagnostic. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. - **Empty environment** — the worker gets `env: {}` and `execArgv: []`: no ambient credentials (stronger than the scrubbed-env rule for spawned commands) and no inherited loader flags. - **Dispose to quiescence** — teardown fails in-flight runs as `abort` and AWAITS each worker's exit before resolving. @@ -35,7 +35,7 @@ The SDK surface is the default/named `WorkerCodeRuntime` class plus `Config`. Th ## Model Experience -Indirectly, through Code Mode in [`dsh-tools`](../../core/tools/README.md), which renders this worker's capped printed or returned data and exact `[dsh-code-runtime-worker] log capture truncated at <maxLogBytes> bytes` and `… [truncated]` markers into a retained `run_code` result. Binding traffic and worker internals stay outside context. +Indirectly, through Code Mode in [`dsh-tools`](../../core/tools/README.md), which renders the exact outer value when it fits or an explicit `invalid-output` / `output-limit` failure. Only the outer `run_code` result enters model context and its ordinary spill policy; binding traffic and intermediate values remain execution-local. #### KV Cache effect @@ -47,4 +47,5 @@ No direct invalidation; the named consumer owns any request-prefix changes. - **Type-strip rides Node's experimental `stripTypeScriptTypes` API** — the relied-on behavior is pinned by unit tests, with amaro/sucrase as named drop-in replacements if it shifts. - **`computeMs` expiry can overshoot by up to one poll interval** — busy time is sampled every 25 ms (an internal constant, deliberately not config). - **Programs get a five-method `console` shim** (`log`/`info`/`warn`/`error`/`debug`) — deliberately not Node's full console surface. -- **A non-cloneable or oversize completion value does not cross as a value** — it arrives as a bounded, truncation-marked `util.inspect` rendering in `value`'s place. +- **Intermediate binding values have no byte cap** — a program can exhaust process or worker memory with a value that never becomes outer output. +- **The 64 MiB default is a rejection boundary, not recoverable storage** — outer spill can save only the bounded logs and diagnostic returned after `output-limit`; bytes rejected beyond the runtime cap never reach the spill layer. diff --git a/packages/code-runtime/code-runtime-worker/package.json b/packages/code-runtime/code-runtime-worker/package.json index 77169f8eab..c65eae4508 100644 --- a/packages/code-runtime/code-runtime-worker/package.json +++ b/packages/code-runtime/code-runtime-worker/package.json @@ -27,6 +27,7 @@ "license": "BSD-3-Clause", "peerDependencies": { "@deepseek-ai/dsh-code-runtime": "^0.0.1", + "@deepseek-ai/dsh-session": "^0.0.1", "cordis": "^4.0.0-rc.7" }, "dependencies": { @@ -34,6 +35,7 @@ }, "devDependencies": { "@deepseek-ai/dsh-code-runtime": "workspace:^", + "@deepseek-ai/dsh-session": "workspace:^", "cordis": "^4.0.0-rc.7" } } diff --git a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts index 7f36364a7c..e62ddd405e 100644 --- a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts +++ b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts @@ -6,8 +6,7 @@ */ import { inspect } from 'node:util' -import { serialize } from 'node:v8' -import { logTruncationMarker } from './protocol.ts' +import { snapshotJsonValue } from '@deepseek-ai/dsh-session' import type { DoneMessage, ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts' /** The port surface the bootstrap needs — satisfied by `parentPort` and by the tests' fake. */ @@ -30,9 +29,8 @@ export interface PatchableStream { * Ordered text capture under one shared byte budget, delivered to a sink as * each item lands (the real sink streams text over the port eagerly, so * captured output survives a mid-run termination). Once the budget is - * exhausted it emits exactly one in-band marker and silently drops everything - * after. The cap is a blast-radius bound, so "how much was lost" intentionally - * stays unmeasured. + * exhausted it emits the fitting prefix and reports the limit once; the host + * turns that condition into an explicit `output-limit` run failure. */ export class LogBuffer { private remaining: number @@ -40,12 +38,12 @@ export class LogBuffer { // Explicit fields, not constructor parameter properties: this module loads // under Node's native strip-only mode, which rejects non-erasable syntax — // and parameter properties are non-erasable. - private readonly maxBytes: number private readonly sink: (text: string) => void + private readonly onLimit: () => void - constructor(maxBytes: number, sink: (text: string) => void) { - this.maxBytes = maxBytes + constructor(maxBytes: number, sink: (text: string) => void, onLimit: () => void = () => {}) { this.sink = sink + this.onLimit = onLimit this.remaining = maxBytes } @@ -58,7 +56,10 @@ export class LogBuffer { const cost = Buffer.byteLength(text, 'utf8') if (cost > this.remaining) { this.truncated = true - this.sink(logTruncationMarker(this.maxBytes)) + const prefix = truncateUtf8Bytes(text, this.remaining) + if (prefix.length > 0) this.sink(prefix) + this.remaining = 0 + this.onLimit() return } this.remaining -= cost @@ -144,37 +145,30 @@ export function truncateUtf8Bytes(text: string, maxBytes: number): string { } /** - * Prepare the program's completion value for the done message: a value whose MEASURED - * cross-boundary size fits `maxValueBytes` crosses raw — exact bytes for a string, the - * structured-clone wire size (`v8.serialize`) for everything else, so a huge container whose - * bounded inspect rendering happens to be small cannot smuggle itself past the cap. Oversized - * or non-cloneable values are replaced by a bounded string rendering with an in-band marker. + * Prepare the program's completion value for the done message. Only lossless + * JSON crosses, and an individually oversized value reports `output-limit`; + * the host revalidates both and accounts for the combined outer envelope. * * @param value - the program's completion value. - * @param maxValueBytes - the byte cap for the value. + * @param maxOutputBytes - the byte cap for the outer result. * @returns the done-message fragment: `{}` for `undefined`, else `{ value }`. */ -export function prepareValue(value: unknown, maxValueBytes: number): { value?: unknown } { +export function prepareCompletion(value: unknown, maxOutputBytes: number): Omit<DoneMessage, 'type'> { if (value === undefined) return {} - if (typeof value === 'string') { - if (Buffer.byteLength(value, 'utf8') <= maxValueBytes) return { value } - } else { - let size: number | undefined - try { - size = serialize(value).byteLength - } catch { - // Only the verdict matters: the value has parts the structured-clone - // algorithm rejects (functions, classes, …) and must cross as its - // rendering instead. - size = undefined - } - if (size !== undefined && size <= maxValueBytes) return { value } + let snapshot: unknown + try { + snapshot = snapshotJsonValue(value) + } catch { + snapshot = undefined } - const rendered = typeof value === 'string' ? value : inspect(value, INSPECT_OPTIONS) - const capped = Buffer.byteLength(rendered, 'utf8') > maxValueBytes - ? `${truncateUtf8Bytes(rendered, maxValueBytes)}… [truncated]` - : rendered - return { value: capped } + if (snapshot === undefined) { + return { error: { kind: 'invalid-output', message: 'program completion must be lossless JSON' } } + } + const size = Buffer.byteLength(JSON.stringify(snapshot), 'utf8') + if (size > maxOutputBytes) { + return { error: { kind: 'output-limit', message: `outer output exceeded ${maxOutputBytes} bytes` } } + } + return { value: snapshot } } /** One awaited binding call's settlement handles, keyed by call id in the pending map. */ @@ -183,6 +177,17 @@ export interface PendingCall { reject(error: Error): void } +/** Program-visible typed rejection for a failed member of the `tools` namespace. */ +export class ToolCallError extends Error { + override readonly name = 'ToolCallError' + readonly toolName: string + + constructor(toolName: string, message: string) { + super(message) + this.toolName = toolName + } +} + /** * Route host replies into the pending-call map: each reply settles its call * at most once, and a reply for an unknown id (stray, or a duplicate answer @@ -227,12 +232,18 @@ export function makeNamespaces( enumerable: true, value: (args: unknown): Promise<unknown> => new Promise((resolve, reject) => { const id = nextId.value++ - pending.set(id, { resolve, reject }) + pending.set(id, { + resolve, + reject: (error) => { + reject(global === 'tools' ? new ToolCallError(name, error.message) : error) + }, + }) try { port.postMessage({ type: 'call', id, global, name, args }) } catch (error: unknown) { pending.delete(id) - reject(new Error(`binding arguments must be structured-cloneable: ${error instanceof Error ? error.message : String(error)}`)) + const message = `binding arguments must be structured-cloneable: ${error instanceof Error ? error.message : String(error)}` + reject(global === 'tools' ? new ToolCallError(name, message) : new Error(message)) } }), }) @@ -254,7 +265,11 @@ export async function runWorkerMain( data: WorkerBootData, streams: { stdout: PatchableStream; stderr: PatchableStream }, ): Promise<void> { - const logs = new LogBuffer(data.maxLogBytes, (text) => { port.postMessage({ type: 'log', text }) }) + const logs = new LogBuffer( + data.maxOutputBytes, + (text) => { port.postMessage({ type: 'log', text }) }, + () => { port.postMessage({ type: 'output-limit' }) }, + ) captureStreamWrites(logs, streams.stdout) captureStreamWrites(logs, streams.stderr) @@ -271,12 +286,12 @@ export async function runWorkerMain( // `AsyncFunction` is not a global. The program body is strict-mode. /* v8 ignore next -- the arrow exists only to reach the AsyncFunction constructor; it is never invoked. */ const AsyncFunction = (async () => {}).constructor as new (...args: string[]) => (...fnArgs: unknown[]) => Promise<unknown> - const fn = new AsyncFunction(...data.namespaces.map(namespace => namespace.global), 'console', `'use strict';\n${data.code}`) - const value = await fn(...namespaces, consoleShim) - done = { type: 'done', ...prepareValue(value, data.maxValueBytes) } + const fn = new AsyncFunction(...data.namespaces.map(namespace => namespace.global), 'ToolCallError', 'console', `'use strict';\n${data.code}`) + const value = await fn(...namespaces, ToolCallError, consoleShim) + done = { type: 'done', ...prepareCompletion(value, data.maxOutputBytes) } } catch (error: unknown) { const message = error instanceof Error ? error.stack ?? error.message : String(error) - done = { type: 'done', error: { message } } + done = { type: 'done', error: { kind: 'exception', message } } } port.postMessage(done) } diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index 4a13baa07c..6cc7124bb6 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -12,9 +12,8 @@ import { fileURLToPath } from 'node:url' import { Context } from 'cordis' import z from 'schemastery' import { CodeRuntime } from '@deepseek-ai/dsh-code-runtime' -import type { CodeBindingFunction, CodeRunFailure, CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' -import { prepareValue, truncateUtf8Bytes } from './bootstrap.ts' -import { logTruncationMarker } from './protocol.ts' +import type { CodeBindingFunction, CodeJsonValue, CodeRunFailure, CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' +import { snapshotJsonValue } from '@deepseek-ai/dsh-session' import type { ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts' /** Plugin config: every execution cap, changeable from `cordis.yml` (no hardcoded tunables). */ @@ -35,14 +34,8 @@ export interface Config { * nobody will resolve). */ maxWallMs?: number - /** Shared byte budget for captured log text (console + raw stream writes), truncation marked in-band. */ - maxLogBytes?: number - /** - * Byte cap for the completion value, measured by its real cross-boundary - * size (string bytes, or structured-clone wire size); an oversized or - * non-cloneable value crosses as a capped string rendering. - */ - maxValueBytes?: number + /** Hard cap for the combined serialized outer logs, completion value, and failure diagnostic. */ + maxOutputBytes?: number /** The worker's max old-generation heap in MiB (`resourceLimits`); overflow kills the worker, surfacing as kind `'worker-exit'`. */ maxOldGenerationSizeMb?: number } @@ -59,6 +52,9 @@ type ResolvedConfig = Required<Config> */ const ELU_POLL_INTERVAL_MS = 25 +/** Smallest cap that can represent the empty logs array plus an empty JSON failure diagnostic. */ +const MIN_OUTPUT_BYTES = 4 + /** ECMAScript reserved words that cannot be async-function parameter names — rejected as binding globals. */ const RESERVED_WORDS = new Set([ 'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', @@ -130,25 +126,74 @@ function parseWorkerMessage(raw: unknown): WorkerToHost | undefined { if (typeof m.text !== 'string') return undefined return { type: 'log', text: m.text } } + case 'output-limit': return { type: 'output-limit' } case 'done': { if (m.error === undefined) return { type: 'done', ...m.value !== undefined ? { value: m.value } : {} } const error = m.error if (typeof error !== 'object' || error === null) return undefined - const message = (error as Record<string, unknown>).message - if (typeof message !== 'string') return undefined - return { type: 'done', ...m.value !== undefined ? { value: m.value } : {}, error: { message } } + const { kind, message } = error as Record<string, unknown> + if ((kind !== 'exception' && kind !== 'invalid-output' && kind !== 'output-limit') || typeof message !== 'string') return undefined + return { type: 'done', error: { kind, message } } } default: return undefined } } -/** - * Headroom the host's value re-cap grants over `maxValueBytes`: exactly the - * truncation suffix {@link prepareValue} appends, so a value the WORKER - * already capped (byte-exact prefix + this marker) passes through unchanged - * instead of being marked twice. - */ -const VALUE_RENDER_SLACK = Buffer.byteLength('… [truncated]', 'utf8') + +/** Serialized byte size of one lossless JSON value. */ +function jsonBytes(value: CodeJsonValue): number { + return Buffer.byteLength(JSON.stringify(value), 'utf8') +} + +/** One run's combined outer-output ledger; binding values never enter it. */ +class OutputLedger { + private bytes = 2 // JSON serialization of the empty logs array: [] + private entries = 0 + + constructor(private readonly maxBytes: number) {} + + /** Admit one exact log entry, or report that the hard cap was crossed. */ + admit(text: string, sink: string[]): boolean { + const cost = Buffer.byteLength(JSON.stringify(text), 'utf8') + (this.entries > 0 ? 1 : 0) + if (this.bytes + cost > this.maxBytes) return false + this.bytes += cost + this.entries += 1 + sink.push(text) + return true + } + + /** Finalize a successful absent-or-JSON completion against the combined cap. */ + success(logs: string[], value?: CodeJsonValue): CodeRunResult { + if (value !== undefined && this.bytes + jsonBytes(value) > this.maxBytes) return this.limit(logs) + return { logs, ...value !== undefined ? { value } : {} } + } + + /** Finalize a failure diagnostic, with output-limit taking precedence when combined bytes exceed the cap. */ + failure(logs: string[], error: CodeRunFailure): CodeRunResult { + if (this.bytes + Buffer.byteLength(JSON.stringify(error.message), 'utf8') > this.maxBytes) return this.limit(logs) + return { logs, error } + } + + /** Build the explicit output-limit failure while retaining the fitting log prefix. */ + limit(logs: string[]): CodeRunResult { + const fullMessage = `outer output exceeded ${this.maxBytes} bytes` + let retainedBytes = this.bytes + const messageBytes = Buffer.byteLength(JSON.stringify(fullMessage), 'utf8') + while (logs.length > 0 && retainedBytes + messageBytes > this.maxBytes) { + const removed = logs.pop() + /* v8 ignore next -- the while guard proves pop cannot return undefined. */ + if (removed === undefined) throw new Error('output ledger lost its final log entry') + retainedBytes -= Buffer.byteLength(JSON.stringify(removed), 'utf8') + (logs.length > 0 ? 1 : 0) + } + const availableMessageBytes = this.maxBytes - retainedBytes + // This fixed diagnostic is ASCII with no JSON escapes, so two bytes are + // the surrounding quotes and every retained character costs one byte. + const message = messageBytes <= availableMessageBytes + ? fullMessage + : fullMessage.slice(0, availableMessageBytes - 2) + return { logs, error: { kind: 'output-limit', message } } + } +} /** * The shipped {@link CodeRuntime} backend (`ctx.codeRuntime`). Registers as @@ -161,8 +206,7 @@ export class WorkerCodeRuntime extends CodeRuntime { static Config: z<Config> = z.object({ computeMs: z.number().default(60_000), maxWallMs: z.number().default(600_000), - maxLogBytes: z.number().default(65_536), - maxValueBytes: z.number().default(32_768), + maxOutputBytes: z.number().default(67_108_864), maxOldGenerationSizeMb: z.number().default(512), }) @@ -181,6 +225,9 @@ export class WorkerCodeRuntime extends CodeRuntime { for (const [key, value] of Object.entries(this.config)) { if (!(Number.isFinite(value) && value > 0)) throw new Error(`dsh-code-runtime-worker: config.${key} must be a positive number, got ${String(value)}`) } + if (!Number.isSafeInteger(this.config.maxOutputBytes) || this.config.maxOutputBytes < MIN_OUTPUT_BYTES) { + throw new Error(`dsh-code-runtime-worker: config.maxOutputBytes must be a safe integer of at least ${MIN_OUTPUT_BYTES}, got ${String(this.config.maxOutputBytes)}`) + } ctx.effect(() => () => this.teardown(), 'worker code-runtime teardown') } @@ -232,7 +279,7 @@ export class WorkerCodeRuntime extends CodeRuntime { if (!IDENTIFIER.test(namespace.global) || RESERVED_WORDS.has(namespace.global)) { throw new Error(`dsh-code-runtime-worker: binding global ${JSON.stringify(namespace.global)} is not a usable identifier`) } - if (namespace.global === 'console' || bindings.has(namespace.global)) { + if (namespace.global === 'console' || namespace.global === 'ToolCallError' || bindings.has(namespace.global)) { throw new Error(`dsh-code-runtime-worker: duplicate binding global ${JSON.stringify(namespace.global)}`) } bindings.set(namespace.global, namespace.functions) @@ -249,8 +296,7 @@ export class WorkerCodeRuntime extends CodeRuntime { const bootData: WorkerBootData = { code, namespaces: [...bindings].map(([global, functions]) => ({ global, names: Object.keys(functions) })), - maxLogBytes: this.config.maxLogBytes, - maxValueBytes: this.config.maxValueBytes, + maxOutputBytes: this.config.maxOutputBytes, } const worker = new Worker(WORKER_PATH, { workerData: bootData, @@ -274,28 +320,13 @@ export class WorkerCodeRuntime extends CodeRuntime { const answered = new Set<number>() const logs: string[] = [] const strayLogs: string[] = [] - - // One host-side budget covers normal, forged, and stray-pipe log entries. The first - // overflow emits the shared in-band marker and drops everything after it. - let logBudget = this.config.maxLogBytes - let logsTruncated = false - const admit = (text: string, sink: string[]): void => { - if (logsTruncated) return - const cost = Buffer.byteLength(text, 'utf8') - if (cost > logBudget) { - logsTruncated = true - sink.push(logTruncationMarker(this.config.maxLogBytes)) - return - } - logBudget -= cost - sink.push(text) - } + const output = new OutputLedger(this.config.maxOutputBytes) // No settled guard: `finish` snapshots the arrays when it resolves, so // a chunk flushing after settlement mutates only the discarded buffers, // and the ledger bounds that growth until the pipes close. const captureStray = (chunk: Buffer): void => { - admit(chunk.toString('utf8'), strayLogs) + if (!settled && !output.admit(chunk.toString('utf8'), strayLogs)) finish(output.limit([...logs, ...strayLogs])) } worker.stdout.on('data', captureStray) worker.stderr.on('data', captureStray) @@ -304,7 +335,7 @@ export class WorkerCodeRuntime extends CodeRuntime { // logs captured before timeout, abort, or failure remain in the result. let finishResolve!: () => void const finished = new Promise<void>((done) => { finishResolve = done }) - const finish = (result: Omit<CodeRunResult, 'logs'>): void => { + const finish = (result: CodeRunResult): void => { if (settled) return settled = true clearInterval(eluTimer) @@ -313,18 +344,28 @@ export class WorkerCodeRuntime extends CodeRuntime { this.live.delete(live) void worker.terminate().then(() => { finishResolve() - resolve({ ...result, logs: [...logs, ...strayLogs] }) + resolve(result) }) } const onDone = (message: WorkerToHost): void => { if (message.type !== 'done') return - // Re-cap forged completion traffic at the hostile boundary. Honest worker-capped values - // pass unchanged via VALUE_RENDER_SLACK; error text is bounded too. - finish({ - ...prepareValue(message.value, this.config.maxValueBytes + VALUE_RENDER_SLACK), - ...message.error ? { error: { kind: 'exception' as const, message: truncateUtf8Bytes(message.error.message, this.config.maxValueBytes) } } : {}, - }) + const captured = [...logs, ...strayLogs] + if (message.error) { + finish(output.failure(captured, message.error)) + return + } + if (message.value === undefined) { + finish(output.success(captured)) + return + } + // The worker-thread boundary has already structured-cloned this + // hostile value, so accessors and proxies cannot survive to throw + // during the lossless-JSON snapshot. + const value = snapshotJsonValue(message.value) as CodeJsonValue | undefined + finish(value === undefined + ? output.failure(captured, { kind: 'invalid-output', message: 'program completion must be lossless JSON' }) + : output.success(captured, value)) } const onCall = (message: WorkerToHost): void => { @@ -336,13 +377,9 @@ export class WorkerCodeRuntime extends CodeRuntime { answered.add(message.id) const reply = (payload: ReplyMessage): void => { if (settled) return - try { - worker.postMessage(payload) - } catch { - // The reply value failed structured clone; renegotiate as an error - // reply, which is always clone-plain. Nothing else throws here. - worker.postMessage({ type: 'reply', id: message.id, ok: false, message: 'binding resolution is not structured-cloneable' }) - } + // Canonical resolutions were snapshotted as lossless JSON before + // this point, so this payload is structured-cloneable by contract. + worker.postMessage(payload) } const record = bindings.get(message.global) // Own-property lookup only: a forged name like 'constructor' or @@ -355,7 +392,18 @@ export class WorkerCodeRuntime extends CodeRuntime { } void (async () => { try { - reply({ type: 'reply', id: message.id, ok: true, value: await fn(message.args) }) + const resolved = await fn(message.args) + let value: CodeJsonValue | undefined + try { + value = snapshotJsonValue(resolved) + } catch { + value = undefined + } + if (value === undefined) { + reply({ type: 'reply', id: message.id, ok: false, message: 'binding resolution must be lossless JSON' }) + } else { + reply({ type: 'reply', id: message.id, ok: true, value }) + } } catch (error: unknown) { reply({ type: 'reply', id: message.id, ok: false, message: messageOf(error) }) } @@ -367,15 +415,22 @@ export class WorkerCodeRuntime extends CodeRuntime { // this listener would crash the host process. Junk drops silently. const message = parseWorkerMessage(raw) if (!message) return - if (message.type === 'log' && !settled) admit(message.text, logs) + if (message.type === 'log' && !settled && !output.admit(message.text, logs)) { + finish(output.limit([...logs, ...strayLogs])) + return + } + if (message.type === 'output-limit' && !settled) { + finish(output.limit([...logs, ...strayLogs])) + return + } onCall(message) onDone(message) }) worker.on('error', (error: Error) => { - finish({ error: { kind: 'worker-exit', message: `worker error: ${error.message}` } }) + finish(output.failure([...logs, ...strayLogs], { kind: 'worker-exit', message: `worker error: ${error.message}` })) }) worker.on('exit', (exitCode: number) => { - finish({ error: { kind: 'worker-exit', message: `worker exited with code ${exitCode} before completing` } }) + finish(output.failure([...logs, ...strayLogs], { kind: 'worker-exit', message: `worker exited with code ${exitCode} before completing` })) }) // The compute budget reads the worker's own measured busy time, so a @@ -384,21 +439,21 @@ export class WorkerCodeRuntime extends CodeRuntime { const eluTimer = setInterval(() => { const elu = worker.performance.eventLoopUtilization() if (elu.active > this.config.computeMs) { - finish({ error: { kind: 'timeout', message: `compute budget exhausted (${this.config.computeMs}ms busy)` } }) + finish(output.failure([...logs, ...strayLogs], { kind: 'timeout', message: `compute budget exhausted (${this.config.computeMs}ms busy)` })) } }, ELU_POLL_INTERVAL_MS) const wallTimer = setTimeout(() => { - finish({ error: { kind: 'timeout', message: `wall-clock ceiling reached (${this.config.maxWallMs}ms)` } }) + finish(output.failure([...logs, ...strayLogs], { kind: 'timeout', message: `wall-clock ceiling reached (${this.config.maxWallMs}ms)` })) }, this.config.maxWallMs) const onAbort = (): void => { - finish({ error: { kind: 'abort', message: String(request.signal?.reason) } }) + finish(output.failure([...logs, ...strayLogs], { kind: 'abort', message: String(request.signal?.reason) })) } request.signal?.addEventListener('abort', onAbort, { once: true }) const live: LiveRun = { worker, finished, - settle: (failure: CodeRunFailure) => { finish({ error: failure }) }, + settle: (failure: CodeRunFailure) => { finish(output.failure([...logs, ...strayLogs], failure)) }, } this.live.add(live) }) diff --git a/packages/code-runtime/code-runtime-worker/src/protocol.ts b/packages/code-runtime/code-runtime-worker/src/protocol.ts index 1ce108b7cc..a76515a78c 100644 --- a/packages/code-runtime/code-runtime-worker/src/protocol.ts +++ b/packages/code-runtime/code-runtime-worker/src/protocol.ts @@ -11,10 +11,8 @@ export interface WorkerBootData { code: string /** Binding namespaces to materialize: the global name plus the function names (functions themselves stay host-side). */ namespaces: { global: string; names: string[] }[] - /** Shared byte budget for captured log text; exceeding it drops further entries after one in-band marker. */ - maxLogBytes: number - /** Byte cap for the rendered completion value (see the value-preparation contract in bootstrap.ts). */ - maxValueBytes: number + /** Hard cap for the combined serialized outer logs plus completion value or failure diagnostic. */ + maxOutputBytes: number } /** Worker → host: one bridged binding call. */ @@ -36,6 +34,11 @@ interface LogMessage { text: string } +/** Worker → host: worker-side capture or completion measurement exceeded the outer cap. */ +interface OutputLimitMessage { + type: 'output-limit' +} + /** * Worker → host: the program settled. `error` carries a program exception * (the only failure the bootstrap itself can report — budgets, aborts, and @@ -47,26 +50,13 @@ interface LogMessage { export interface DoneMessage { type: 'done' value?: unknown - error?: { message: string } + error?: { kind: 'exception' | 'invalid-output' | 'output-limit'; message: string } } /** Every message the worker sends. */ -export type WorkerToHost = CallMessage | LogMessage | DoneMessage +export type WorkerToHost = CallMessage | LogMessage | OutputLimitMessage | DoneMessage /** Host → worker: the answer to one {@link CallMessage}. */ export type ReplyMessage = | { type: 'reply'; id: number; ok: true; value: unknown } | { type: 'reply'; id: number; ok: false; message: string } - -/** - * The in-band marker entry text announcing that log capture stopped at the - * byte budget. Shared wire vocabulary: the worker's LogBuffer emits it when - * ITS budget exhausts, and the host emits the identical text when its own - * ledger drops an entry first (forged port traffic, stray pipe bytes) — so - * a truncated run reads the same however the cap was hit. - * @param maxBytes - the configured `maxLogBytes` the marker names. - * @returns the marker line. - */ -export function logTruncationMarker(maxBytes: number): string { - return `[dsh-code-runtime-worker] log capture truncated at ${maxBytes} bytes` -} diff --git a/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts b/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts index 111aa4f15f..2f817e0edc 100644 --- a/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' import { EventEmitter } from 'node:events' -import { LogBuffer, makeConsoleShim, makeNamespaces, captureStreamWrites, prepareValue, runWorkerMain, truncateUtf8Bytes, wireReplies } from '../src/bootstrap.ts' +import { LogBuffer, makeConsoleShim, makeNamespaces, captureStreamWrites, prepareCompletion, runWorkerMain, ToolCallError, truncateUtf8Bytes, wireReplies } from '../src/bootstrap.ts' import type { BootstrapPort, PatchableStream, PendingCall } from '../src/bootstrap.ts' import type { ReplyMessage, WorkerToHost } from '../src/protocol.ts' @@ -43,19 +43,34 @@ function fakeStreams(): { stdout: PatchableStream; stderr: PatchableStream } { return { stdout: { write: () => true }, stderr: { write: () => true } } } -const BOOT = { maxLogBytes: 65_536, maxValueBytes: 32_768 } +/** Capture one promise rejection without Vitest's intentionally `any` matcher channel. */ +async function rejectionOf(promise: Promise<unknown>): Promise<unknown> { + try { + await promise + return undefined + } catch (error: unknown) { + return error + } +} + +const BOOT = { maxOutputBytes: 65_536 } describe('LogBuffer', () => { - it('streams entries to the sink until the byte budget, then emits one marker and drops the rest', () => { + it('streams entries to the sink until the byte budget, then emits one fitting prefix and reports the limit once', () => { const seen: string[] = [] - const buffer = new LogBuffer(10, text => seen.push(text)) + let limits = 0 + const buffer = new LogBuffer(10, text => seen.push(text), () => { limits += 1 }) buffer.push('12345') buffer.push('123456') buffer.push('dropped') - expect(seen).toEqual([ - '12345', - '[dsh-code-runtime-worker] log capture truncated at 10 bytes', - ]) + expect(seen).toEqual(['12345', '12345']) + expect(limits).toBe(1) + + const exactlyFull: string[] = [] + const fullBuffer = new LogBuffer(4, text => exactlyFull.push(text)) + fullBuffer.push('1234') + fullBuffer.push('no-prefix-fits') + expect(exactlyFull).toEqual(['1234']) }) }) @@ -109,45 +124,42 @@ describe('captureStreamWrites', () => { }) }) -describe('prepareValue', () => { - it('omits undefined, passes small cloneable values raw', () => { - expect(prepareValue(undefined, 100)).toEqual({}) - expect(prepareValue({ a: [1, 'two'] }, 100)).toEqual({ value: { a: [1, 'two'] } }) +describe('prepareCompletion', () => { + it('omits undefined and passes lossless JSON values exactly', () => { + expect(prepareCompletion(undefined, 100)).toEqual({}) + expect(prepareCompletion({ a: [1, 'two'] }, 100)).toEqual({ value: { a: [1, 'two'] } }) }) - it('replaces a non-cloneable value with its rendering', () => { - const { value } = prepareValue({ fn: () => 1 }, 1_000) - expect(typeof value).toBe('string') - expect(value).toContain('fn') + it('turns every lossy completion shape into invalid-output', () => { + const cyclic: Record<string, unknown> = {} + cyclic.self = cyclic + const sparse = Array(2) + class Exotic { readonly marker = true } + for (const value of [{ fn: () => 1 }, -0, Number.POSITIVE_INFINITY, sparse, cyclic, new Exotic()]) { + expect(prepareCompletion(value, 1_000)).toEqual({ + error: { kind: 'invalid-output', message: 'program completion must be lossless JSON' }, + }) + } }) - it('replaces an oversized value with a truncation-marked capped rendering', () => { - const { value } = prepareValue('x'.repeat(50), 10) - expect(value).toBe(`${'x'.repeat(10)}… [truncated]`) + it('reports an oversized value instead of substituting rendered text', () => { + expect(prepareCompletion('x'.repeat(50), 10)).toEqual({ + error: { kind: 'output-limit', message: 'outer output exceeded 10 bytes' }, + }) }) - it('measures a container by its structured-clone wire size, not its bounded rendering', () => { - // The bounded inspect rendering of a huge array is tiny ("... N more - // items"), but its real cross-boundary size is not — the cap must catch - // it, replacing the value with that bounded rendering. - const huge = new Array(50_000).fill(7) - const { value } = prepareValue(huge, 1_000) - expect(typeof value).toBe('string') - expect(value).toContain('more items') + it('measures the exact JSON serialization at and over the boundary', () => { + expect(prepareCompletion('€', 5)).toEqual({ value: '€' }) + expect(prepareCompletion('€', 4)).toEqual({ + error: { kind: 'output-limit', message: 'outer output exceeded 4 bytes' }, + }) }) - it('caps a multibyte string by UTF-8 bytes, not UTF-16 length', () => { - // 4 code units but 12 UTF-8 bytes: a length-counting cap would pass the - // full string through untruncated. - expect(prepareValue('€€€€', 4)).toEqual({ value: '€… [truncated]' }) - }) - - it('caps a multibyte rendering by UTF-8 bytes too', () => { - // Wire size (24-byte string inside an array) exceeds the cap, so the - // value crosses as its rendering — whose truncation must also be - // byte-exact: "[ '" (3 bytes) + two € (6 bytes) = 9; a third € would - // overflow the 10-byte budget. - expect(prepareValue(['€€€€€€€€'], 10)).toEqual({ value: "[ '€€… [truncated]" }) + it('contains a getter failure as invalid-output', () => { + const value = Object.defineProperty({}, 'x', { enumerable: true, get() { throw new Error('getter exploded') } }) + expect(prepareCompletion(value, 1_000)).toEqual({ + error: { kind: 'invalid-output', message: 'program completion must be lossless JSON' }, + }) }) }) @@ -191,10 +203,35 @@ describe('makeNamespaces', () => { } const pending = new Map<number, PendingCall>() const [tools] = makeNamespaces({ namespaces: [{ global: 'tools', names: ['x'] }] }, throwingPort, pending, { value: 1 }) as [Record<string, (args: unknown) => Promise<unknown>>] - await expect(tools.x?.(() => 1)).rejects.toThrow(/structured-cloneable: DataCloneError-ish/) - await expect(tools.x?.(() => 1)).rejects.toThrow(/structured-cloneable: raw-clone-failure/) + const first = await rejectionOf(tools.x?.(() => 1) ?? Promise.resolve()) + const second = await rejectionOf(tools.x?.(() => 1) ?? Promise.resolve()) + expect(first).toMatchObject({ name: 'ToolCallError', toolName: 'x' }) + expect(second).toMatchObject({ name: 'ToolCallError', toolName: 'x' }) + expect(first).toBeInstanceOf(ToolCallError) + expect(second).toBeInstanceOf(ToolCallError) + expect((first as Error).message).toMatch(/DataCloneError-ish/) + expect((second as Error).message).toMatch(/raw-clone-failure/) expect(pending.size).toBe(0) }) + + it('uses ordinary Error for non-tools namespace failures', async () => { + const deniedPort = new FakePort() + deniedPort.respond = message => message.type === 'call' + ? { type: 'reply', id: message.id, ok: false, message: 'helper denied' } + : undefined + const deniedPending = new Map<number, PendingCall>() + wireReplies(deniedPort, deniedPending) + const [helpers] = makeNamespaces({ namespaces: [{ global: 'helpers', names: ['x'] }] }, deniedPort, deniedPending, { value: 1 }) as [Record<string, (args: unknown) => Promise<unknown>>] + const denied = await rejectionOf(helpers.x?.({}) ?? Promise.resolve()) + expect(denied).toBeInstanceOf(Error) + expect(denied).not.toBeInstanceOf(ToolCallError) + + const clonePort: BootstrapPort = { postMessage: () => { throw new Error('clone failed') }, on: () => {} } + const [cloneHelpers] = makeNamespaces({ namespaces: [{ global: 'helpers', names: ['x'] }] }, clonePort, new Map(), { value: 1 }) as [Record<string, (args: unknown) => Promise<unknown>>] + const cloneFailure = await rejectionOf(cloneHelpers.x?.(() => 1) ?? Promise.resolve()) + expect(cloneFailure).toBeInstanceOf(Error) + expect(cloneFailure).not.toBeInstanceOf(ToolCallError) + }) }) describe('runWorkerMain', () => { @@ -210,11 +247,24 @@ describe('runWorkerMain', () => { expect(port.done()).toEqual({ type: 'done', value: { doubled: 42 } }) }) + it('reports worker-side log capture overflow before completing', async () => { + const port = new FakePort() + await runWorkerMain(port, { + maxOutputBytes: 4, + code: 'console.log("12345"); return null', + namespaces: [], + }, fakeStreams()) + expect(port.sent).toContainEqual({ type: 'log', text: '1234' }) + expect(port.sent).toContainEqual({ type: 'output-limit' }) + expect(port.done()).toEqual({ type: 'done', value: null }) + }) + it('reports a thrown program error on the done message', async () => { const port = new FakePort() await runWorkerMain(port, { ...BOOT, code: 'throw new Error("boom")', namespaces: [] }, fakeStreams()) const done = port.done() expect(done?.type).toBe('done') + expect(done?.type === 'done' ? done.error?.kind : undefined).toBe('exception') expect(done?.type === 'done' ? done.error?.message : undefined).toContain('boom') expect(done?.type === 'done' ? done.value : undefined).toBeUndefined() }) @@ -222,11 +272,11 @@ describe('runWorkerMain', () => { it('renders non-Error throws and stack-less Errors on the done message', async () => { const rawPort = new FakePort() await runWorkerMain(rawPort, { ...BOOT, code: 'throw "raw-throw"', namespaces: [] }, fakeStreams()) - expect(rawPort.done()).toEqual({ type: 'done', error: { message: 'raw-throw' } }) + expect(rawPort.done()).toEqual({ type: 'done', error: { kind: 'exception', message: 'raw-throw' } }) const barePort = new FakePort() await runWorkerMain(barePort, { ...BOOT, code: 'const e = new Error("bare"); e.stack = undefined; throw e', namespaces: [] }, fakeStreams()) - expect(barePort.done()).toEqual({ type: 'done', error: { message: 'bare' } }) + expect(barePort.done()).toEqual({ type: 'done', error: { kind: 'exception', message: 'bare' } }) }) it('surfaces a host failure reply as a program-side rejection it can catch', async () => { @@ -234,10 +284,14 @@ describe('runWorkerMain', () => { port.respond = message => message.type === 'call' ? { type: 'reply', id: message.id, ok: false, message: 'denied by host' } : undefined await runWorkerMain(port, { ...BOOT, - code: 'try { await tools.x({}) } catch (error) { return `caught: ${error.message}` }', + code: 'try { await tools.x({}) } catch (error) { return { caught: error instanceof ToolCallError, name: error.name, toolName: error.toolName, message: error.message } }', namespaces: [{ global: 'tools', names: ['x'] }], }, fakeStreams()) - expect(port.done()).toEqual({ type: 'done', value: 'caught: denied by host' }) + expect(port.done()).toEqual({ + type: 'done', + value: { caught: true, name: 'ToolCallError', toolName: 'x', message: 'denied by host' }, + }) + expect(new ToolCallError('x', 'nope')).toMatchObject({ name: 'ToolCallError', toolName: 'x', message: 'nope' }) }) it('ignores replies for unknown pending ids', async () => { diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index ae2cb2b639..22787a2154 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest' import { Context } from 'cordis' import { WorkerCodeRuntime } from '@deepseek-ai/dsh-code-runtime-worker' import type { Config } from '@deepseek-ai/dsh-code-runtime-worker' -import type { CodeRunResult } from '@deepseek-ai/dsh-code-runtime' +import type { CodeBindingFunction, CodeBindingNamespace, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' /** * Integration suite over REAL worker threads (no mocks — workers are cheap @@ -17,8 +17,8 @@ async function setup(config: Config = {}) { } /** Convenience: one namespace `tools` with the given functions. */ -function tools(functions: Record<string, (args: unknown) => Promise<unknown>>) { - return [{ global: 'tools', functions }] +function tools(functions: Record<string, (args: unknown) => Promise<unknown>>): CodeBindingNamespace[] { + return [{ global: 'tools', functions: functions as Record<string, CodeBindingFunction> }] } describe('WorkerCodeRuntime — programs and bindings (real workers)', () => { @@ -52,10 +52,10 @@ describe('WorkerCodeRuntime — programs and bindings (real workers)', () => { const result = await runtime.run({ program: ` const first = await tools.echo({ n: 1 }); - let caught = ''; - try { await tools.fail({}) } catch (error) { caught = error.message } - let caughtRaw = ''; - try { await tools.failRaw({}) } catch (error) { caughtRaw = error.message } + let caught = {}; + try { await tools.fail({}) } catch (error) { caught = { isTyped: error instanceof ToolCallError, name: error.name, toolName: error.toolName, message: error.message } } + let caughtRaw = {}; + try { await tools.failRaw({}) } catch (error) { caughtRaw = { name: error.name, toolName: error.toolName, message: error.message } } return { first, caught, caughtRaw }; `, bindings: tools({ @@ -66,7 +66,11 @@ describe('WorkerCodeRuntime — programs and bindings (real workers)', () => { }), }) expect(result.error).toBeUndefined() - expect(result.value).toEqual({ first: { echoed: { n: 1 } }, caught: 'nope', caughtRaw: 'raw-nope' }) + expect(result.value).toEqual({ + first: { echoed: { n: 1 } }, + caught: { isTyped: true, name: 'ToolCallError', toolName: 'fail', message: 'nope' }, + caughtRaw: { name: 'ToolCallError', toolName: 'failRaw', message: 'raw-nope' }, + }) expect(calls).toEqual([{ n: 1 }]) }) @@ -90,10 +94,11 @@ describe('WorkerCodeRuntime — programs and bindings (real workers)', () => { expect(result.value).toBe('{}') }) - it('replaces a non-cloneable return value with a string rendering', async () => { + it('rejects a non-lossless completion instead of replacing it with rendered text', async () => { const { runtime } = await setup() const result = await runtime.run({ program: 'return { f: () => 1 }', bindings: [] }) - expect(typeof result.value).toBe('string') + expect(result.value).toBeUndefined() + expect(result.error).toEqual({ kind: 'invalid-output', message: 'program completion must be lossless JSON' }) }) it('completes a program that returns nothing with no value at all', async () => { @@ -201,30 +206,47 @@ describe('WorkerCodeRuntime — budgets and containment (real workers)', () => { expect(after.value).toBe('alive') }, 30_000) - it('truncates runaway log output at the byte budget with an in-band marker', async () => { - const { runtime } = await setup({ maxLogBytes: 300 }) + it('fails runaway log output explicitly while retaining a bounded prefix', async () => { + const { runtime } = await setup({ maxOutputBytes: 300 }) const result = await runtime.run({ program: 'for (let i = 0; i < 1000; i++) console.log("spam line", i); return 1', bindings: [], }) - expect(result.logs.at(-1)).toContain('truncated at 300 bytes') - const total = result.logs.reduce((sum, text) => sum + Buffer.byteLength(text, 'utf8'), 0) - expect(total).toBeLessThan(1_000) + expect(result.error).toEqual({ kind: 'output-limit', message: 'outer output exceeded 300 bytes' }) + expect(result.value).toBeUndefined() + expect(result.logs.length).toBeGreaterThan(0) + expect(Buffer.byteLength(JSON.stringify(result.logs), 'utf8')).toBeLessThan(300) }) - it('caps an oversized return value with a truncation marker', async () => { - const { runtime } = await setup({ maxValueBytes: 64 }) + it('fails an oversized return value without substituting a string', async () => { + const { runtime } = await setup({ maxOutputBytes: 64 }) const result = await runtime.run({ program: 'return "y".repeat(10_000)', bindings: [] }) - expect(result.value).toBe(`${'y'.repeat(64)}… [truncated]`) + expect(result.value).toBeUndefined() + expect(result.error).toEqual({ kind: 'output-limit', message: 'outer output exceeded 64 bytes' }) }) - it('caps a multibyte return value by UTF-8 bytes, not string length', async () => { - // 4 code units, 12 UTF-8 bytes: a length-counting cap would let the full - // string cross. The worker's byte-exact capped rendering then passes the - // host re-cap unchanged (cap + marker is exactly the granted slack). - const { runtime } = await setup({ maxValueBytes: 4 }) - const result = await runtime.run({ program: 'return "€€€€"', bindings: [] }) - expect(result.value).toBe('€… [truncated]') + it('uses UTF-8 serialized bytes at the exact completion boundary', async () => { + const exact = await setup({ maxOutputBytes: 7 }) + const exactResult = await exact.runtime.run({ program: 'return "€"', bindings: [] }) + // [] costs two bytes and JSON serialization of "€" costs five. + expect(exactResult).toEqual({ logs: [], value: '€' }) + + const over = await setup({ maxOutputBytes: 6 }) + const overResult = await over.runtime.run({ program: 'return "€"', bindings: [] }) + expect(overResult.error?.kind).toBe('output-limit') + }) + + it('accounts logs and completion in one exact combined ledger', async () => { + // JSON(["abc"]) is seven bytes and JSON("xy") is four. + const exact = await setup({ maxOutputBytes: 11 }) + expect(await exact.runtime.run({ program: 'console.log("abc"); return "xy"', bindings: [] })) + .toEqual({ logs: ['abc'], value: 'xy' }) + + const over = await setup({ maxOutputBytes: 10 }) + const result = await over.runtime.run({ program: 'console.log("abc"); return "xy"', bindings: [] }) + expect(result.value).toBeUndefined() + expect(result.error?.kind).toBe('output-limit') + expect(Buffer.byteLength(JSON.stringify(result.logs), 'utf8') + Buffer.byteLength(JSON.stringify(result.error?.message), 'utf8')).toBeLessThanOrEqual(10) }) it('completes a program that awaits its write callback, capturing the chunk', async () => { @@ -241,32 +263,48 @@ describe('WorkerCodeRuntime — budgets and containment (real workers)', () => { expect(result.logs).toContain('flushed') }) - it('caps a huge container whose bounded rendering is small (wire size, not rendering, is what counts)', async () => { + it('returns a large JSON container exactly when the outer cap permits it', async () => { const { runtime } = await setup() const result = await runtime.run({ program: 'return new Array(50_000).fill(7)', bindings: [] }) expect(result.error).toBeUndefined() - expect(typeof result.value).toBe('string') - expect(result.value).toContain('more items') + expect(result.value).toEqual(new Array(50_000).fill(7)) }) - it('captures pipe writes that bypass the patched write slot as stray logs, capped by the same budget', async () => { - const { runtime } = await setup({ maxLogBytes: 4 }) + it('returns an exact completion at the default 64 MiB combined boundary', async () => { + const { runtime } = await setup() + // [] costs two bytes and the JSON string contributes two quotes, leaving + // exactly this many payload bytes under the 67_108_864-byte default. + const result = await runtime.run({ program: 'return "x".repeat(67_108_860)', bindings: [] }) + expect(result.error).toBeUndefined() + expect(result.logs).toEqual([]) + expect(result.value).toHaveLength(67_108_860) + }, 60_000) + + it('fails one byte over the default 64 MiB combined boundary', async () => { + const { runtime } = await setup() + const result = await runtime.run({ program: 'return "x".repeat(67_108_861)', bindings: [] }) + expect(result.value).toBeUndefined() + expect(result.error).toEqual({ kind: 'output-limit', message: 'outer output exceeded 67108864 bytes' }) + }, 60_000) + + it('accounts pipe writes that bypass the patched write slot in the same outer ledger', async () => { + const { runtime } = await setup({ maxOutputBytes: 80 }) const result = await runtime.run({ // The prototype write bypasses the patched instance and reaches the real pipe. Pauses keep // writes in separate chunks and let both reach the host before settlement. program: ` const write = (text) => Object.getPrototypeOf(process.stdout).write.call(process.stdout, text); - write('abcd'); + write('a'.repeat(20)); await new Promise(resolve => setTimeout(resolve, 150)); - write('ef'); + write('b'.repeat(100)); await new Promise(resolve => setTimeout(resolve, 100)); return 1; `, bindings: [], }) - expect(result.error).toBeUndefined() - expect(result.logs).toContain('abcd') - expect(result.logs).not.toContain('ef') + expect(result.error?.kind).toBe('output-limit') + expect(result.logs).toContain('a'.repeat(20)) + expect(result.logs).not.toContain('b'.repeat(100)) }, 15_000) }) @@ -305,7 +343,8 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { { type: 'log', text: 7 }, { type: 'log', text: {} }, { type: 'done', error: 5 }, - { type: 'done', error: { message: 5 } }, + { type: 'done', error: { kind: 'exception', message: 5 } }, + { type: 'done', error: { kind: 'invented', message: 'bad kind' } }, ]) parentPort.postMessage(junk); return await tools.real({}); `, @@ -316,10 +355,10 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { expect(result.logs).toEqual([]) }) - it('caps forged log floods and forged done values at the configured budgets, dropping forged extra fields', async () => { - const { runtime } = await setup({ maxLogBytes: 200, maxValueBytes: 64 }) + it('fails forged log floods and forged done values through the same outer cap', async () => { + const { runtime } = await setup({ maxOutputBytes: 200 }) const result = await runtime.run({ - // Forged messages bypass the worker-side LogBuffer and prepareValue + // Forged messages bypass the worker-side LogBuffer and completion check // entirely — only the host-side ledger and re-cap stand between model // code and an unbounded result. program: ` @@ -330,53 +369,79 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { `, bindings: [], }) - expect(typeof result.value).toBe('string') - const value = result.value as string - expect(value.startsWith('V'.repeat(64))).toBe(true) - expect(value.endsWith('… [truncated]')).toBe(true) - expect(value.length).toBeLessThan(120) - const marker = '[dsh-code-runtime-worker] log capture truncated at 200 bytes' - const total = result.logs.reduce((sum, text) => sum + Buffer.byteLength(text, 'utf8'), 0) - expect(total).toBeLessThanOrEqual(200 + Buffer.byteLength(marker, 'utf8')) - expect(result.logs.at(-1)).toBe(marker) + expect(result.value).toBeUndefined() + expect(result.error).toEqual({ kind: 'output-limit', message: 'outer output exceeded 200 bytes' }) + expect(Buffer.byteLength(JSON.stringify(result.logs), 'utf8')).toBeLessThan(200) }) - it('accepts a forged done carrying both value and error (self-sabotage, contained)', async () => { + it('drops a malformed forged done carrying both value and error', async () => { const { runtime } = await setup() const result = await runtime.run({ program: ` const { parentPort } = await import('node:worker_threads'); - parentPort.postMessage({ type: 'done', value: 'lied', error: { message: 'fake failure' } }); - for (;;) {} + parentPort.postMessage({ type: 'done', value: 'lied', error: { kind: 'exception', message: 'fake failure' } }); + return 'honest'; `, bindings: [], }) - expect(result.value).toBe('lied') - expect(result.error).toEqual({ kind: 'exception', message: 'fake failure' }) + expect(result).toEqual({ logs: [], error: { kind: 'exception', message: 'fake failure' } }) }) - it('byte-bounds forged multibyte error text at the host', async () => { - // Forged error text bypasses the worker entirely; the host bound is a - // BYTE bound (two € = 6 bytes fit an 8-byte cap, a third would not). - const { runtime } = await setup({ maxValueBytes: 8 }) + it('turns forged over-limit error text into output-limit at the host', async () => { + const { runtime } = await setup({ maxOutputBytes: 64 }) const result = await runtime.run({ program: ` const { parentPort } = await import('node:worker_threads'); - parentPort.postMessage({ type: 'done', error: { message: '€'.repeat(1000) } }); + parentPort.postMessage({ type: 'done', error: { kind: 'exception', message: '€'.repeat(1000) } }); for (;;) {} `, bindings: [], }) - expect(result.error).toEqual({ kind: 'exception', message: '€€' }) + expect(result.error).toEqual({ kind: 'output-limit', message: 'outer output exceeded 64 bytes' }) }) - it('answers a binding whose resolution cannot be cloned with a failure reply', async () => { + it('answers a binding whose resolution is not lossless JSON with a typed failure reply', async () => { const { runtime } = await setup() const result = await runtime.run({ - program: 'try { await tools.bad({}) } catch (error) { return error.message }', + program: 'try { await tools.bad({}) } catch (error) { return { name: error.name, toolName: error.toolName, message: error.message } }', bindings: tools({ bad: async () => (() => 1) }), }) - expect(result.value).toContain('not structured-cloneable') + expect(result.value).toEqual({ name: 'ToolCallError', toolName: 'bad', message: 'binding resolution must be lossless JSON' }) + }) + + it('contains throwing getters while snapshotting binding resolutions', async () => { + const { runtime } = await setup() + const result = await runtime.run({ + program: 'try { await tools.bad({}) } catch (error) { return { name: error.name, toolName: error.toolName, message: error.message } }', + bindings: tools({ bad: async () => Object.defineProperty({}, 'bad', { enumerable: true, get() { throw new Error('getter exploded') } }) }), + }) + expect(result.value).toEqual({ name: 'ToolCallError', toolName: 'bad', message: 'binding resolution must be lossless JSON' }) + }) + + it('revalidates a forged lossy completion at the host boundary', async () => { + const { runtime } = await setup() + const result = await runtime.run({ + program: ` + const { parentPort } = await import('node:worker_threads'); + parentPort.postMessage({ type: 'done', value: -0 }); + for (;;) {} + `, + bindings: [], + }) + expect(result).toEqual({ logs: [], error: { kind: 'invalid-output', message: 'program completion must be lossless JSON' } }) + }) + + it('honors a forged worker-side output-limit signal', async () => { + const { runtime } = await setup() + const result = await runtime.run({ + program: ` + const { parentPort } = await import('node:worker_threads'); + parentPort.postMessage({ type: 'output-limit' }); + for (;;) {} + `, + bindings: [], + }) + expect(result).toEqual({ logs: [], error: { kind: 'output-limit', message: 'outer output exceeded 67108864 bytes' } }) }) it('exposes binding names that collide with Object.prototype as ordinary functions', async () => { @@ -392,12 +457,13 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { }) describe('WorkerCodeRuntime — seam misuse and lifecycle', () => { - it('rejects invalid binding globals loudly (identifier, reserved word, duplicate, console)', async () => { + it('rejects invalid binding globals loudly (identifier, reserved word, duplicate, reserved injected globals)', async () => { const { runtime } = await setup() const cases: [string, RegExp][] = [ ['not valid!', /not a usable identifier/], ['await', /not a usable identifier/], ['console', /duplicate binding global/], + ['ToolCallError', /duplicate binding global/], ] for (const [global, message] of cases) { await expect(runtime.run({ program: 'return 1', bindings: [{ global, functions: {} }] })).rejects.toThrow(message) @@ -413,6 +479,12 @@ describe('WorkerCodeRuntime — seam misuse and lifecycle', () => { await expect(ctx.plugin(WorkerCodeRuntime, { computeMs: -1 })).rejects.toThrow(/positive number/) }) + it('requires maxOutputBytes to fit the smallest outer failure envelope', async () => { + const ctx = new Context() + await expect(ctx.plugin(WorkerCodeRuntime, { maxOutputBytes: 3 })).rejects.toThrow(/safe integer of at least 4/) + await expect(ctx.plugin(WorkerCodeRuntime, { maxOutputBytes: 4.5 })).rejects.toThrow(/safe integer of at least 4/) + }) + it('keeps runs isolated: no state survives from one run to the next', async () => { const { runtime } = await setup() await runtime.run({ program: 'globalThis.leak = "value"; return 1', bindings: [] }) diff --git a/packages/code-runtime/code-runtime-worker/tsconfig.json b/packages/code-runtime/code-runtime-worker/tsconfig.json index af962eda4f..dc7bb2ac45 100644 --- a/packages/code-runtime/code-runtime-worker/tsconfig.json +++ b/packages/code-runtime/code-runtime-worker/tsconfig.json @@ -8,6 +8,9 @@ "src" ], "references": [ + { + "path": "../../core/session" + }, { "path": "../../../vendor/cosmokit" }, diff --git a/packages/code-runtime/code-runtime/README.md b/packages/code-runtime/code-runtime/README.md index b31af71397..24e1fb51a1 100644 --- a/packages/code-runtime/code-runtime/README.md +++ b/packages/code-runtime/code-runtime/README.md @@ -8,15 +8,15 @@ This package is the interface third of the capability (the bash trio is the temp | Member | Semantics | |---|---| -| `run(request)` | Execute one program against the request's bindings. **Resolves with an error FIELD for every program outcome** — parse/transform failure, thrown exception, budget expiry, abort, substrate death (`CodeRunFailure`'s orthogonal `kind` taxonomy); it rejects only for caller misuse of the seam itself (e.g. a run submitted after disposal). The program runs as the body of an async function: top-level `await`/`return` work, and the completion value becomes `result.value` when it survives the serialization boundary. | +| `run(request)` | Execute one program against the request's bindings. **Resolves with an error FIELD for every program outcome** — parse/transform failure, thrown exception, invalid completion, output overflow, budget expiry, abort, or substrate death (`CodeRunFailure`'s orthogonal `kind` taxonomy); it rejects only for caller misuse of the seam itself (e.g. a run submitted after disposal). The program runs as the body of an async function: top-level `await`/`return` work, and a lossless JSON completion becomes `result.value`. | | `language` | Readonly descriptor: the source language `run` expects (`'typescript'` is the well-known value). Informational, not gating — a consumer that generates language-specific presentation switches on it and fails loud on a language it cannot present. | | `isolation` | Readonly descriptor: the execution substrate (`'worker-thread'`, `'process'`, `'container'`). A label for deployments and diagnostics, **not a security claim**. | -Semantics every implementation must honor (contract details in the class JSDoc): binding calls bridge to the caller's functions verbatim with structured-cloneable arguments/resolutions; the program is treated as a hostile peer (arbitrary binding names are own properties, malformed traffic never crashes the host); no state survives between runs; disposal terminates in-flight runs AND awaits their exit before completing. +Semantics every implementation must honor (contract details in the class JSDoc): binding calls bridge complete lossless-JSON arguments and resolutions with no seam-level byte cap; the program is treated as a hostile peer (arbitrary binding names are own properties, malformed traffic never crashes the host); no state survives between runs; disposal terminates in-flight runs AND awaits their exit before completing. ## Vocabulary -`CodeRunRequest` (`program`, `bindings`, `signal?`) carries everything the runtime acts on — defaulting (time budgets, output caps) is the implementation's validated config, never a hidden `??` inside `run()`. `bindings` is a list of `CodeBindingNamespace`s (`global` + `functions`), each exposed to the program as one global object of async callables. `CodeRunResult` reports the completion `value?`, ordered capped `logs: string[]`, and the `error?` (`CodeRunFailure`: `kind` + model-feedable `message`). See `src/types.ts` for the full contracts. +`CodeRunRequest` (`program`, `bindings`, `signal?`) carries everything the runtime acts on — defaulting (time budgets and outer-output cap) is the implementation's validated config, never a hidden `??` inside `run()`. `bindings` is a list of `CodeBindingNamespace`s (`global` + `functions`), each exposed to the program as one global object of async callables returning `CodeJsonValue`, the seam-local structural equivalent of canonical `JsonValue` that keeps this interface package independent of sessions. `CodeRunResult` reports the lossless JSON completion `value?`, ordered `logs: string[]`, and the `error?` (`CodeRunFailure`: `kind` + model-feedable `message`). See `src/types.ts` for the full contracts. ## Model Experience @@ -31,3 +31,4 @@ No direct invalidation; the named consumer owns any request-prefix changes. - **`run()` is one-shot** — `logs` arrive only on the resolved `CodeRunResult`; the seam exposes no streaming-log or progress surface for a live program's output. - **A persistent REPL-style kernel is recorded future work** — the no-state-between-runs contract stands until a persistent-kernel backend brings its own logging story ([Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)). - **Only the worker-thread backend ships** — `'process'`/`'container'` are declared well-known `isolation` values with no implementation; a hard security boundary awaits a container backend. +- **Intermediate binding values have no byte cap** — implementations remain subject to structured-clone cost and process memory, while a provider or executor may already have imposed its own acquisition bound. diff --git a/packages/code-runtime/code-runtime/src/index.ts b/packages/code-runtime/code-runtime/src/index.ts index bd8efe1377..9b9fd0d48e 100644 --- a/packages/code-runtime/code-runtime/src/index.ts +++ b/packages/code-runtime/code-runtime/src/index.ts @@ -10,6 +10,7 @@ import type { CodeRunRequest, CodeRunResult } from './types.ts' export type { CodeBindingFunction, CodeBindingNamespace, + CodeJsonValue, CodeRunFailure, CodeRunRequest, CodeRunResult, diff --git a/packages/code-runtime/code-runtime/src/types.ts b/packages/code-runtime/code-runtime/src/types.ts index d7669a4785..259e497e14 100644 --- a/packages/code-runtime/code-runtime/src/types.ts +++ b/packages/code-runtime/code-runtime/src/types.ts @@ -9,12 +9,16 @@ /** * One host-side function exposed to the program as an async callable. The * runtime bridges calls to it (possibly across a serialization boundary), so - * `args` and the resolution value MUST be structured-cloneable; a runtime - * rejects a non-cloneable value with a descriptive error rather than - * corrupting the run. A rejection of this function surfaces inside the - * program as a rejection of the corresponding call. + * `args` and the resolution value MUST be lossless JSON. A runtime rejects a + * lossy or non-cloneable value with a descriptive error rather than corrupting + * the run. No seam-level byte cap applies to a binding resolution. A rejection + * of this function surfaces inside the program as a rejection of the + * corresponding call. */ -export type CodeBindingFunction = (args: unknown) => Promise<unknown> +export type CodeBindingFunction = (args: unknown) => Promise<CodeJsonValue> + +/** A lossless JSON value transferable across the dependency-light code-runtime seam. */ +export type CodeJsonValue = null | boolean | number | string | CodeJsonValue[] | { [key: string]: CodeJsonValue } /** * A named group of {@link CodeBindingFunction}s the runtime exposes to the @@ -63,10 +67,12 @@ export interface CodeRunRequest { * - `'timeout'` — an implementation-owned budget expired; the message says which. * - `'abort'` — {@link CodeRunRequest.signal} fired. * - `'worker-exit'` — the execution substrate died without settling (e.g. OOM). + * - `'invalid-output'` — the completion value was not lossless JSON. + * - `'output-limit'` — the serialized outer logs/value/diagnostic exceeded the configured cap. */ export interface CodeRunFailure { /** The failure class (see the interface doc for each kind's meaning). */ - kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' + kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' | 'invalid-output' | 'output-limit' /** Human-readable detail, suitable for feeding back to a model to self-correct. */ message: string } @@ -79,12 +85,12 @@ export interface CodeRunFailure { export interface CodeRunResult { /** * The program's completion value (its top-level `return`), when it ran to - * completion and the value survived the runtime's serialization boundary; - * a non-transferable value is replaced by a string rendering, and a failed - * or value-less run leaves this absent. + * completion and the value crossed the runtime's lossless-JSON boundary. + * Invalid or over-limit completions fail the run instead of substituting a + * rendered string; a failed or value-less run leaves this absent. */ - value?: unknown - /** Text the program emitted, in order (capped by the implementation). */ + value?: CodeJsonValue + /** Text the program emitted, in order, bounded only as part of the outer result. */ logs: string[] /** Present iff the run failed; see {@link CodeRunFailure} for the taxonomy. */ error?: CodeRunFailure diff --git a/packages/code-runtime/code-runtime/tests/service.spec.ts b/packages/code-runtime/code-runtime/tests/service.spec.ts index 7811ef0531..4fc83f7552 100644 --- a/packages/code-runtime/code-runtime/tests/service.spec.ts +++ b/packages/code-runtime/code-runtime/tests/service.spec.ts @@ -45,7 +45,7 @@ describe('CodeRuntime service seam', () => { const calls: unknown[] = [] const result = await runtime.run({ program: 'return 1', - bindings: [{ global: 'tools', functions: { probe: async args => void calls.push(args) } }], + bindings: [{ global: 'tools', functions: { probe: async (args) => { calls.push(args); return null } } }], }) expect(result).toEqual({ logs: [] }) expect(calls).toEqual([{ from: 'stub' }]) diff --git a/packages/cordis/tool-cordis/src/api-catalog.ts b/packages/cordis/tool-cordis/src/api-catalog.ts index e8ddc86f83..7dfaa9070e 100644 --- a/packages/cordis/tool-cordis/src/api-catalog.ts +++ b/packages/cordis/tool-cordis/src/api-catalog.ts @@ -1126,15 +1126,19 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'CodeBindingFunction', - declaration: 'export type CodeBindingFunction = (args: unknown) => Promise<unknown>;', + declaration: 'export type CodeBindingFunction = (args: unknown) => Promise<CodeJsonValue>;', }, { name: 'CodeBindingNamespace', declaration: 'export interface CodeBindingNamespace {\n global: string;\n functions: Record<string, CodeBindingFunction>;\n}', }, + { + name: 'CodeJsonValue', + declaration: 'export type CodeJsonValue = null | boolean | number | string | CodeJsonValue[] | {\n [key: string]: CodeJsonValue;\n};', + }, { name: 'CodeRunFailure', - declaration: 'export interface CodeRunFailure {\n kind: \'exception\' | \'timeout\' | \'abort\' | \'worker-exit\';\n message: string;\n}', + declaration: 'export interface CodeRunFailure {\n kind: \'exception\' | \'timeout\' | \'abort\' | \'worker-exit\' | \'invalid-output\' | \'output-limit\';\n message: string;\n}', }, { name: 'CodeRunRequest', @@ -1142,7 +1146,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'CodeRunResult', - declaration: 'export interface CodeRunResult {\n value?: unknown;\n logs: string[];\n error?: CodeRunFailure;\n}', + declaration: 'export interface CodeRunResult {\n value?: CodeJsonValue;\n logs: string[];\n error?: CodeRunFailure;\n}', }, { name: 'CollectedOutput', diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 1b42f2c28f..d71b25e48d 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -108,11 +108,12 @@ Returning `undefined` selects generic fallback. Presenters depend only on their ### Code Mode -Under `code` or `both`, the registry exposes the reserved `run_code` transport and a deterministic TypeScript SDK for the current scope; only program output re-enters model context. Each JSON-normalized binding re-enters the complete tool pipeline sequentially with logged correlation to the outer call. Denials reject that binding, ordinary side effects are not rolled back, and sub-call `additionalContexts` are deferred through the parent result to preserve call/result adjacency. Run settlement aborts and drains outstanding bindings; failures surface as `CodeRunFailedError`. See the [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) and [code-runtime seam](../../code-runtime/README.md). Try `pnpm run demo:code-mode`. +Under `code` or `both`, the registry exposes the reserved `run_code` transport and a deterministic TypeScript SDK for the current scope; only the program's outer logs and return value re-enter model context. The SDK declares exact `ToolArgsMap` and `ToolOutputMap` entries for every visible tool, and each binding resolves to the tool's canonical JSON value. Each lossless-JSON binding call re-enters the complete tool pipeline sequentially with logged correlation to the outer call. Denials and other failed results reject with the real program-visible `ToolCallError` carrying only `toolName` and `message`; Native content and internal error codes stay outside the Code contract. Ordinary side effects are not rolled back, and sub-call `additionalContexts` are deferred through the parent result to preserve call/result adjacency. Run settlement aborts and drains outstanding bindings; runtime failures surface as `CodeRunFailedError`. See the [Code Mode foundation](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md), [typed-return contract](../../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md), and [code-runtime seam](../../code-runtime/README.md). Try `pnpm run demo:code-mode`. -- **The SDK section** (`tools:sdk`, order 150): a lazy prompt section regenerating, at each assembly, a `declare const tools: {...}` TypeScript declaration of the calling scope's visible end capabilities (exotic names via quoted keys), plus fixed usage instructions. Deterministic — lexicographic tool order, byte-identical text for an unchanged tool set (prefix-cache-friendly). The codegen (`jsonSchemaToTs`, exported) is total: constructs outside the `defineTool` subset degrade to `unknown`, never throw. -- **The dispatch bridge** (`run_code`'s execute): every binding call is JSON-normalized before dispatch (a value that does not survive — `BigInt`, circulars — rejects that one call, so the dispatched form and logged form are the same JSON value by construction), serialized through a per-run queue (even `Promise.all` executes underlying calls one at a time in submission order), given the outer execution's opaque token as `parent`, and run through the complete pre-execute → guards → execute → post-execute → result pipeline. A denial reaches the program as a binding rejection, and each sub-call is logged as a `tool/code-dispatch` session event with deterministic id `<parent>:code:<n>`; `deriveMessages()` does not surface that event. Token correlation lets commit-style observers defer an inner success until the final `run_code` result without exposing the live outer execution; ordinary tool side effects are not rolled back. Every sub-call `additionalContexts` entry is deferred through the outer `ToolRunContext` in dispatch order; the loop appends those contexts only after the parent `run_code` result, preserving adjacency and retaining each source/meta even when the program later fails. +- **The SDK section** (`tools:sdk`, order 150): a lazy prompt section regenerating, at each assembly, `JsonValue`, exact `ToolArgsMap` / `ToolOutputMap`, `ToolName`, the `ToolCallError` declaration, and a mapped `tools` namespace for the calling scope's visible end capabilities (exotic names via quoted keys), plus fixed usage instructions. Deterministic — lexicographic tool order, byte-identical text for an unchanged tool set (prefix-cache-friendly). The codegen (`jsonSchemaToTs`, exported) handles every unified schema construct and degrades unsupported raw constructs to `unknown`, never throwing during prompt assembly. +- **The dispatch bridge** (`run_code`'s execute): every binding call is snapshotted as lossless JSON before dispatch (`undefined`, `BigInt`, cycles, sparse arrays, `-0`, and exotic objects reject that one call), serialized through a per-run queue (even `Promise.all` executes underlying calls one at a time in submission order), given the outer execution's opaque token as `parent`, and run through the complete pre-execute → guards → execute → post-execute → result pipeline. A success returns the final canonical value after policy; a failure reaches the worker as one message and becomes `ToolCallError(toolName, message)`. Each sub-call is logged as a `tool/code-dispatch` session event with deterministic id `<parent>:code:<n>` and a bounded Native-content summary; `deriveMessages()` does not surface that event or persist the value. Token correlation lets commit-style observers defer an inner success until the final `run_code` result without exposing the live outer execution; ordinary tool side effects are not rolled back. Every sub-call `additionalContexts` entry is deferred through the outer `ToolRunContext` in dispatch order; the loop appends those contexts only after the parent `run_code` result, preserving adjacency and retaining each source/meta even when the program later fails. - **Settlement discipline**: the bridge owns a run-scoped abort that follows the outer signal in and fires when the run settles for any reason, so a budget expiry aborts an in-flight sub-tool instead of orphaning it; the bridge then drains its queue BEFORE returning, so every `tool/code-dispatch` lands inside the open turn. A failed run throws `CodeRunFailedError` (`code: 'CODE_RUN_FAILED'`, message = the failure kind + captured logs), which the pipeline converts to a structured `isError` the model self-corrects from. +- **Result boundary**: intermediate binding values cross the worker boundary whole and have no per-binding byte cap. `run_code` returns canonical `{ logs: string[], result?: JsonValue }`; strings render raw, every other present JSON root renders as pretty JSON, `null` remains explicit, and absent `result` means the program returned `undefined`. The worker's configurable `maxOutputBytes` (default 64 MiB) applies only to the combined serialized outer logs, completion, or failure diagnostic; invalid and over-limit completions fail explicitly, and only this outer result is eligible for ordinary spill. ### Parallel execution @@ -147,8 +148,8 @@ Code Mode exposes the generated [`run_code` schema](../../../docs/tool-catalog.m Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program: -- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's text output as a string. Tool arguments must be JSON-serializable. -- A FAILED tool call rejects with an `Error` carrying the tool's error text — `try/catch` it to handle and continue. +- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue. - Calls execute sequentially, even under `Promise.all`. - Emit results with `return` and/or `console.log(...)`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. @@ -181,8 +182,8 @@ Append-only; newly visible content follows the reusable request prefix and does - **Concurrency policy is not an event seam** — `executionMode()` reads the resolved tool definition directly; plugins can only declare a classifier on definitions they own. - **`tools/pre-execute` deliberately cannot rewrite `exec.arguments`** — logged and rendered args would desync from what ran; the rewrite design is [a proposed Agent Note](../../../.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.md). -- **`defineTool`'s schema DSL is a deliberate subset** — string/number/boolean/object/array with string-only `enum`; `validateArgs` tolerates extra keys and preserves `default` as a model-visible JSON Schema annotation without applying it during validation; dynamic Cordis mounts may supply defaults even though first-party definitions do not, while raw-registered JSON-Schema tools validate their own input. +- **Caller-defined subagent and workflow structured outputs remain object-rooted** — this is a consumer-level guard; the shared schema vocabulary and tool outputs support every JSON root. - **`timeoutMs` on a definition is declarative only** — the registry never enforces deadlines; enforcement requires the `@deepseek-ai/dsh-timeout-policy` wrapper. - **Code Mode is TypeScript-only and the presentation mode is service-wide** — `mode: code`/`both` rejects prompt assembly unless `ctx.codeRuntime.language === 'typescript'`; scoped restrictions/shadows still choose each agent's visible bindings, but one tool cannot be native-only while another is code-only. -- **Code Mode bindings return text only** — non-text content blocks in a sub-call result collapse to `[<type> content]` placeholders. +- **Code Mode intermediate values are execution-local and unbounded by bytes** — they cannot be reconstructed from session replay and may exhaust process or worker memory; only the outer `run_code` output has the worker's configurable hard cap. - **`run_code` state is fresh per run** — a persistent REPL-style kernel is rejected for the MVP (cross-call state would be invisible to the log); see [the Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md). diff --git a/packages/core/tools/src/code-mode.ts b/packages/core/tools/src/code-mode.ts index 21fcfcb8b5..c9bda10358 100644 --- a/packages/core/tools/src/code-mode.ts +++ b/packages/core/tools/src/code-mode.ts @@ -6,10 +6,10 @@ */ import { parse } from 'node:path' -import { inspect } from 'node:util' import { CallId, HarnessError } from '@deepseek-ai/dsh-llm' import type { ContentBlock } from '@deepseek-ai/dsh-llm' import type { CodeBindingFunction, CodeRunResult, CodeRuntime } from '@deepseek-ai/dsh-code-runtime' +import { snapshotJsonValue } from '@deepseek-ai/dsh-session' import type { JsonValue } from '@deepseek-ai/dsh-session' import { defineTool } from './schema.ts' import type { ToolDefinition, ToolRegistry } from './index.ts' @@ -62,10 +62,7 @@ export class CodeRunFailedError extends HarnessError { */ const SUMMARY_MAX_CHARS = 200 -/** Bounded inspect for rendering a program's completion value into the model-facing text. */ -const INSPECT_OPTIONS = { depth: 4, maxArrayLength: 100, maxStringLength: 10_000 } as const - -/** Join a result's text blocks; a non-text block becomes a placeholder (an MVP limitation, stated in the SDK instructions). */ +/** Join Native content for the bounded durable sub-dispatch summary; non-text blocks become diagnostic placeholders. */ function textOf(content: ContentBlock[]): string { return content .map((block) => { @@ -88,32 +85,26 @@ function summarize(text: string, cwd: string | undefined): string { } /** - * JSON-normalize one binding call's argument into TWO independent parses of the same canonical - * text: `dispatched` goes to the tool, `logged` to the `tool/code-dispatch` event — identical - * by construction (the runtime's structured-clone boundary is wider than JSON; the session log - * accepts only JSON), and separate objects, so a tool mutating its args can neither desync the - * log from what was dispatched nor re-poison the append. + * Snapshot one binding call's argument as lossless JSON, then clone it into + * independent dispatch/log values so a tool mutation cannot desynchronize the + * durable event from what was called. */ function jsonNormalizeArgs(value: unknown): { dispatched: unknown; logged: unknown } { - if (value === undefined) { - throw new Error('tool arguments must be JSON-serializable (call the tool with an arguments object, e.g. `{}`)') - } - let text: string | undefined + let snapshot: JsonValue | undefined try { - text = JSON.stringify(value) + snapshot = snapshotJsonValue(value) as JsonValue | undefined } catch (error: unknown) { - throw new Error(`tool arguments must be JSON-serializable: ${error instanceof Error ? error.message : String(error)}`) + throw new Error(`tool arguments must be lossless JSON: ${error instanceof Error ? error.message : String(error)}`) } - // JSON.stringify's lib type claims `string`, but a bare function or symbol - // root really yields `undefined` at runtime — the guard is live. - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (text === undefined) throw new Error('tool arguments must be JSON-serializable (got a value JSON cannot represent)') - return { dispatched: JSON.parse(text) as unknown, logged: JSON.parse(text) as unknown } + if (snapshot === undefined) { + throw new Error('tool arguments must be lossless JSON (call the tool with an arguments object, e.g. `{}`)') + } + return { dispatched: structuredClone(snapshot), logged: structuredClone(snapshot) } } /** Render one present program completion value for the model-facing result text. */ function renderValue(value: JsonValue): string { - return typeof value === 'string' ? value : inspect(value, INSPECT_OPTIONS) + return typeof value === 'string' ? value : JSON.stringify(value, null, 2) } /** The run_code result's `meta` payload (JSON-serializable; `presentResult` narrows it back). */ @@ -203,7 +194,7 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () => // would be narrowed away by control flow analysis. const runOver = (): boolean => runController.signal.aborted - const binding = (name: string): CodeBindingFunction => async (rawArgs: unknown): Promise<unknown> => { + const binding = (name: string): CodeBindingFunction => async (rawArgs: unknown): Promise<JsonValue> => { if (runOver()) { throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} not dispatched`) } @@ -234,7 +225,9 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () => isError: result.isError, resultSummary: summarize(text, exec.agent.session.header.cwd), }) - return { text, isError: result.isError } + return result.isError + ? { isError: true as const, message: result.error.message } + : { isError: false as const, value: result.value } }) // A budget expiry or outer cancel that lands while this call was in // flight already aborted the dispatch; stop the program now rather @@ -242,11 +235,11 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () => if (runOver()) { throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} result discarded`) } - // A failed tool call REJECTS — real code signals failure by throwing, - // so try/catch and Promise.all short-circuiting behave as models - // expect (the error text is the tool's model-facing result text). - if (outcome.isError) throw new Error(outcome.text) - return outcome.text + // The worker turns a binding rejection into ToolCallError and adds + // only the binding name. Native content and internal error metadata + // stay outside the program-facing failure contract. + if (outcome.isError) throw new Error(outcome.message) + return outcome.value } // Null-prototype + defineProperty, mirroring the worker-side namespace @@ -283,12 +276,9 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () => const logsText = result.logs.length > 0 ? `\nCaptured output:\n${result.logs.join('\n')}` : '' throw new CodeRunFailedError(`code run failed (${result.error.kind}): ${result.error.message}${logsText}`) } - // The runtime seam is wider than JSON until PR 3 makes this boundary - // lossless. The registry immediately snapshots and rejects any value - // that does not satisfy the declared JSON output. return { logs: result.logs, - ...result.value !== undefined ? { result: result.value as JsonValue } : {}, + ...result.value !== undefined ? { result: result.value } : {}, } } finally { exec.signal?.removeEventListener('abort', onOuterAbort) diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index f6fe38d4da..a01b5cf928 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -23,6 +23,7 @@ import { assertSupportedJsonSchema, validateJsonSchemaValue } from './json-schem import type { JsonSchemaNode } from './json-schema.ts' import { createRunCodeTool, RUN_CODE_NAME, SDK_SECTION_ORDER } from './code-mode.ts' import { renderToolsSdk } from './ts-types.ts' +import type { ToolSdkSchema } from './ts-types.ts' export { defineTool, @@ -550,7 +551,7 @@ export class ToolRegistry extends Service { // Regenerate from the calling scope's visible tools in stable order. text: (context) => { this.requireCodeRuntime() - return renderToolsSdk(this.schemas(context.scope).filter(schema => schema.name !== RUN_CODE_NAME)) + return renderToolsSdk(this.sdkSchemas(context.scope)) }, }) } @@ -815,6 +816,16 @@ export class ToolRegistry extends Service { return [...this.view(scope).visible.values()].map(definition => this.schemaOf(definition, true)) } + /** Project visible callable tools onto the generated Code Mode SDK contract. */ + private sdkSchemas(scope?: ScopeKey): ToolSdkSchema[] { + return [...this.view(scope).visible.values()] + .filter(definition => definition.name !== RUN_CODE_NAME) + .map((definition): ToolSdkSchema => ({ + ...this.schemaOf(definition, true), + output: structuredClone(definition.output.schema), + })) + } + /** Project one definition onto the model-facing schema fields. */ private schemaOf(definition: ToolDefinition, detachParameters: boolean): ToolSchema { const { name, description, parameters } = definition diff --git a/packages/core/tools/src/ts-types.ts b/packages/core/tools/src/ts-types.ts index 39cec5665e..6897c3cb2a 100644 --- a/packages/core/tools/src/ts-types.ts +++ b/packages/core/tools/src/ts-types.ts @@ -8,7 +8,13 @@ import type { ToolSchema } from '@deepseek-ai/dsh-llm' import { assertSupportedJsonSchema } from './json-schema.ts' -import type { JsonSchemaScalar } from './json-schema.ts' +import type { JsonSchemaNode, JsonSchemaScalar } from './json-schema.ts' + +/** Internal Code Mode projection: the model-facing schema plus the canonical output schema. */ +export interface ToolSdkSchema extends ToolSchema { + /** Validated canonical value returned by the tool binding. */ + output: JsonSchemaNode +} /** Property names that are valid bare TS identifiers; anything else is quoted. */ const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/ @@ -107,8 +113,8 @@ const SDK_INSTRUCTIONS = `## Writing code for run_code Pass \`run_code\` the body of an async TypeScript function (erasable syntax only — no \`enum\` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program: -- Call tools as \`await tools.name(args)\` — quoted access for exotic names: \`tools["my-tool"](args)\`. Every call resolves to the tool's text output as a string. Tool arguments must be JSON-serializable. -- A FAILED tool call rejects with an \`Error\` carrying the tool's error text — \`try/catch\` it to handle and continue. +- Call tools as \`await tools.name(args)\` — quoted access for exotic names: \`tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose \`message\` is human-readable — \`try/catch\` it to handle and continue. - Calls execute sequentially, even under \`Promise.all\`. - Emit results with \`return\` and/or \`console.log(...)\`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. @@ -123,16 +129,24 @@ The available tools:` * `run_code` itself). * @returns the complete section text. */ -export function renderToolsSdk(schemas: ToolSchema[]): string { +export function renderToolsSdk(schemas: ToolSdkSchema[]): string { const sorted = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0) - const members: string[] = [] + const argsMembers: string[] = [] + const outputMembers: string[] = [] for (const schema of sorted) { - members.push(...docLines(schema.description, 1)) - members.push(`${pad(1)}${renderKey(schema.name)}(args: ${jsonSchemaToTs(schema.parameters, 1)}): Promise<string>;`) + argsMembers.push(...docLines(schema.description, 1)) + argsMembers.push(`${pad(1)}${renderKey(schema.name)}: ${jsonSchemaToTs(schema.parameters, 1)};`) + outputMembers.push(`${pad(1)}${renderKey(schema.name)}: ${jsonSchemaToTs(schema.output, 1)};`) } - const declaration = members.length > 0 - ? `declare const tools: {\n${members.join('\n')}\n}` - : 'declare const tools: {}' + const argsMap = `interface ToolArgsMap {${argsMembers.length > 0 ? `\n${argsMembers.join('\n')}\n` : ''}}` + const outputMap = `interface ToolOutputMap {${outputMembers.length > 0 ? `\n${outputMembers.join('\n')}\n` : ''}}` + const declaration = [ + argsMap, + outputMap, + 'type ToolName = keyof ToolOutputMap', + ['declare class ToolCallError extends Error {', ' readonly name: "ToolCallError";', ' readonly toolName: ToolName;', '}'].join('\n'), + ['declare const tools: {', ' [K in ToolName]: (args: ToolArgsMap[K]) => Promise<ToolOutputMap[K]>;', '}'].join('\n'), + ].join('\n\n') const jsonValue = 'type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue }' return `${SDK_INSTRUCTIONS}\n\n\`\`\`ts\n${jsonValue}\n\n${declaration}\n\`\`\`` } diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index 0fe48af14a..cfff494a62 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -6,7 +6,7 @@ import type { Scope } from '@deepseek-ai/dsh-scope' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import { CodeRuntime } from '@deepseek-ai/dsh-code-runtime' import type { CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' -import ToolRegistry, { CodeRunFailedError, RUN_CODE_NAME, defineContentToolFixture } from '@deepseek-ai/dsh-tools' +import ToolRegistry, { CodeRunFailedError, RUN_CODE_NAME, defineContentToolFixture, defineTool } from '@deepseek-ai/dsh-tools' import type { Config, PostToolDecision, ToolExecutionResult } from '@deepseek-ai/dsh-tools' import type { Agent } from '@deepseek-ai/dsh-agent' import { Session, SessionId } from '@deepseek-ai/dsh-session' @@ -68,13 +68,17 @@ async function mintAgentScope(ctx: Context, name = 'scoped'): Promise<{ scope: S /** Register a trivial echo tool; returns the calls it received. */ function registerEcho(ctx: Context, name = 'echo'): unknown[] { const calls: unknown[] = [] - ctx.tools.register(defineContentToolFixture({ + ctx.tools.register(defineTool({ name, description: `Echo tool ${name}.`, parameters: { value: { type: 'string', required: true } }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, execute(args) { calls.push(args) - return Promise.resolve([{ type: 'text' as const, text: `${name}:${args.value}` }]) + return Promise.resolve(`${name}:${args.value}`) }, })) return calls @@ -119,8 +123,8 @@ describe('mode-aware wire contribution', () => { expect(assembly.tools.map(tool => tool.name)).toEqual([RUN_CODE_NAME]) const sdk = assembly.sections.find(section => section.name === 'tools:sdk') expect(sdk?.text).toContain('declare const tools: {') - expect(sdk?.text).toContain('echo(args:') - expect(sdk?.text).not.toContain('run_code(args:') + expect(sdk?.text).toContain('echo: {') + expect(sdk?.text).not.toContain('run_code:') }) it.each(['code', 'both'] as const)('treats expert assembly output as authoritative in mode %s', async (mode) => { @@ -172,8 +176,8 @@ describe('mode-aware wire contribution', () => { ? [RUN_CODE_NAME] : ['echo', RUN_CODE_NAME]) const sdk = assembly.sections.find(section => section.name === 'tools:sdk')?.text - expect(sdk).toContain('echo(args:') - expect(sdk).not.toContain('hidden(args:') + expect(sdk).toContain('echo: {') + expect(sdk).not.toContain('hidden:') runtime.behavior = request => Promise.resolve({ logs: [], @@ -202,8 +206,8 @@ describe('mode-aware wire contribution', () => { ? [RUN_CODE_NAME] : ['kept', RUN_CODE_NAME]) const sdk = assembly.sections.find(section => section.name === 'tools:sdk')?.text - expect(sdk).not.toContain('denied(args:') - expect(sdk).toContain('kept(args:') + expect(sdk).not.toContain('denied:') + expect(sdk).toContain('kept: {') runtime.behavior = request => Promise.resolve({ logs: [], @@ -241,7 +245,7 @@ describe('mode-aware wire contribution', () => { expect(transports).toHaveLength(1) expect(transports[0]?.description).toContain('Execute a TypeScript program') expect(assembly.sections.find(section => section.name === 'scoped-note')?.text).toBe('safe note') - expect(assembly.sections.find(section => section.name === 'tools:sdk')?.text).toContain('scoped_safe(args:') + expect(assembly.sections.find(section => section.name === 'tools:sdk')?.text).toContain('scoped_safe:') expect(ctx.tools.get(RUN_CODE_NAME, agent)).toBe(ctx.tools.get(RUN_CODE_NAME)) const result = await runCode(ctx, 'return 1', { agent }) expect(result.content).toEqual([{ type: 'text', text: '(run_code completed with no output)' }]) @@ -328,7 +332,8 @@ describe('the run_code dispatch bridge', () => { const tools = request.bindings[0]!.functions const first = await tools.echo!({ value: 'one' }) const second = await tools.echo!({ value: 'two' }) - return { logs: [`saw ${String(first)}`], value: second } + if (typeof first !== 'string' || typeof second !== 'string') throw new Error('echo returned a non-string') + return { logs: [`saw ${first}`], value: second } } const result = await runCode(ctx, 'const …: string = …', { agent }) expect(result.isError).toBe(false) @@ -376,10 +381,14 @@ describe('the run_code dispatch bridge', () => { const { ctx, runtime } = await setup({ mode: 'code' }) const intervals: [string, string][] = [] let active = 0 - ctx.tools.register(defineContentToolFixture({ + ctx.tools.register(defineTool({ name: 'probe', description: 'Records execution overlap.', parameters: { id: { type: 'string', required: true } }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, async execute(args) { active++ expect(active, 'probe executions overlapped').toBe(1) @@ -387,12 +396,13 @@ describe('the run_code dispatch bridge', () => { await new Promise(resolve => setTimeout(resolve, 20)) intervals.push(['exit', args.id]) active-- - return [{ type: 'text' as const, text: args.id }] + return args.id }, })) runtime.behavior = async (request) => { const tools = request.bindings[0]!.functions const values = await Promise.all([tools.probe!({ id: 'a' }), tools.probe!({ id: 'b' }), tools.probe!({ id: 'c' })]) + if (!values.every(value => typeof value === 'string')) throw new Error('probe returned a non-string') return { logs: [], value: values.join(',') } } const result = await runCode(ctx, 'program') @@ -422,7 +432,7 @@ describe('the run_code dispatch bridge', () => { } } const result = await runCode(ctx, 'program') - expect(result.content[0]).toEqual({ type: 'text', text: 'caught: Error: deliberate failure' }) + expect(result.content[0]).toEqual({ type: 'text', text: 'caught: deliberate failure' }) }) it('a tools/pre-execute deny reaches the program as a binding rejection', async () => { @@ -445,7 +455,7 @@ describe('the run_code dispatch bridge', () => { expect((result.content[0] as { text: string }).text).toContain('not on my watch') }) - it('rejects a binding argument that does not survive JSON normalization, dispatching nothing', async () => { + it('rejects a binding argument that is not lossless JSON, dispatching nothing', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) const calls = registerEcho(ctx) const { agent, events } = fakeAgent() @@ -458,25 +468,24 @@ describe('the run_code dispatch bridge', () => { } } const result = await runCode(ctx, 'program', { agent }) - expect((result.content[0] as { text: string }).text).toContain('JSON-serializable') + expect((result.content[0] as { text: string }).text).toContain('lossless JSON') expect(calls).toEqual([]) expect(events.filter(event => event.type === 'tool/code-dispatch')).toEqual([]) }) - it('dispatches the JSON-normalized value: what the tool sees is what the event logs', async () => { + it('dispatches and logs independent snapshots of the same lossless JSON value', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) const calls = registerEcho(ctx) const { agent, events } = fakeAgent() runtime.behavior = async (request) => { - // A Date survives structured clone but is not JSON; the bridge - // normalizes it to its JSON form (an ISO string) BEFORE dispatch. - await request.bindings[0]!.functions.echo!({ value: 'x', when: new Date(0) }).catch(() => undefined) + const args = Object.assign(Object.create(null) as Record<string, unknown>, { value: 'x', nested: ['same'] }) + await request.bindings[0]!.functions.echo!(args) return { logs: [] } } await runCode(ctx, 'program', { agent }) - expect(calls).toEqual([{ value: 'x', when: '1970-01-01T00:00:00.000Z' }]) + expect(calls).toEqual([{ value: 'x', nested: ['same'] }]) const dispatch = events.find(event => event.type === 'tool/code-dispatch')?.data as SessionEventMap['tool/code-dispatch'] - expect(dispatch.arguments).toEqual({ value: 'x', when: '1970-01-01T00:00:00.000Z' }) + expect(dispatch.arguments).toEqual({ value: 'x', nested: ['same'] }) }) it('defers sub-call additionalContexts onto the outer run_code result', async () => { @@ -691,15 +700,19 @@ describe('the run_code dispatch bridge', () => { const { ctx, runtime } = await setup({ mode: 'code' }) const { agent, events } = fakeAgent() const long = 'x'.repeat(300) - ctx.tools.register(defineContentToolFixture({ + ctx.tools.register(defineTool({ name: 'mixed', description: 'Returns mixed content.', parameters: {}, + output: { + schema: { type: 'string' }, + render: () => [ + { type: 'text', text: long }, + { type: 'reasoning', text: 'hidden' }, + ], + }, execute() { - return Promise.resolve([ - { type: 'text' as const, text: long }, - { type: 'reasoning' as const, text: 'hidden' }, - ]) + return Promise.resolve('mixed-value') }, })) runtime.behavior = async (request) => { @@ -708,7 +721,7 @@ describe('the run_code dispatch bridge', () => { } const result = await runCode(ctx, 'program', { agent }) expect(result.isError).toBe(false) - expect((result.content[0] as { text: string }).text).toBe(`${long}\n[reasoning content]`) + expect((result.content[0] as { text: string }).text).toBe('mixed-value') const dispatch = events.find(event => event.type === 'tool/code-dispatch')?.data as SessionEventMap['tool/code-dispatch'] expect(dispatch.resultSummary.length).toBe(201) expect(dispatch.resultSummary.endsWith('…')).toBe(true) @@ -716,13 +729,17 @@ describe('the run_code dispatch bridge', () => { it('normalizes the session workspace root before bounding durable result summaries', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) - ctx.tools.register(defineContentToolFixture({ + ctx.tools.register(defineTool({ name: 'workspace_path', description: 'Return a path beneath the session workspace.', parameters: {}, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, execute(_args, exec) { const cwd = exec.agent?.session.header.cwd ?? '' - return Promise.resolve([{ type: 'text' as const, text: `<path>${cwd}/nested/task.txt</path>\n${'x'.repeat(240)}` }]) + return Promise.resolve(`<path>${cwd}/nested/task.txt</path>\n${'x'.repeat(240)}`) }, })) runtime.behavior = async request => ({ @@ -760,7 +777,7 @@ describe('the run_code dispatch bridge', () => { expect((root.events[0]!.data as SessionEventMap['tool/code-dispatch']).resultSummary).toBe('echo:/workspace/value') }) - it('rejects undefined, JSON-throwing, and JSON-unrepresentable binding arguments BEFORE dispatch', async () => { + it('rejects undefined, getter-throwing, exotic, and unrepresentable binding arguments before dispatch', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) const calls = registerEcho(ctx) const { agent, events } = fakeAgent() @@ -773,8 +790,9 @@ describe('the run_code dispatch bridge', () => { // Root undefined must reject up front: the event log rejects it as // data, and nothing may execute unlogged. await catchMessage(echo(undefined)), - // A toJSON that throws a NON-Error propagates out of JSON.stringify. - await catchMessage(echo({ toJSON() { throw 'raw-throw' } })), + await catchMessage(echo(Object.defineProperty({}, 'bad', { enumerable: true, get() { throw 'raw-throw' } }))), + await catchMessage(echo(Object.defineProperty({}, 'bad', { enumerable: true, get() { throw new Error('error-throw') } }))), + await catchMessage(echo(new Date(0))), // A bare function is a value JSON cannot represent at all. await catchMessage(echo(() => 1)), ].join(' | '), @@ -783,9 +801,10 @@ describe('the run_code dispatch bridge', () => { const result = await runCode(ctx, 'program', { agent }) const text = (result.content[0] as { text: string }).text expect(text).toContain('call the tool with an arguments object') - expect(text).toContain('JSON-serializable: raw-throw') - expect(text).toContain('a value JSON cannot represent') - // None of the three dispatched, none logged. + expect(text).toContain('lossless JSON: raw-throw') + expect(text).toContain('lossless JSON: error-throw') + expect(text.match(/tool arguments must be lossless JSON/g)).toHaveLength(5) + // None dispatched or logged. expect(calls).toEqual([]) expect(events.filter(event => event.type === 'tool/code-dispatch')).toEqual([]) }) @@ -816,11 +835,15 @@ describe('the run_code dispatch bridge', () => { it('exposes a tool named __proto__ as an ordinary own binding', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) - ctx.tools.register(defineContentToolFixture({ + ctx.tools.register(defineTool({ name: '__proto__', description: 'A prototype-colliding tool name.', parameters: {}, - execute() { return Promise.resolve([{ type: 'text' as const, text: 'proto-tool-ok' }]) }, + output: { + schema: { type: 'string' }, + render: (_args, value) => [{ type: 'text', text: value }], + }, + execute() { return Promise.resolve('proto-tool-ok') }, })) runtime.behavior = async (request) => { const functions = request.bindings[0]!.functions @@ -833,11 +856,20 @@ describe('the run_code dispatch bridge', () => { expect(result.content[0]).toEqual({ type: 'text', text: 'proto-tool-ok' }) }) - it('renders a non-string completion value inspect-style', async () => { + it('renders every non-string JSON root as pretty JSON while preserving strings raw', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) runtime.behavior = () => Promise.resolve({ logs: [], value: { n: 42 } }) - const result = await runCode(ctx, 'program') - expect((result.content[0] as { text: string }).text).toBe('{ n: 42 }') + expect((await runCode(ctx, 'object')).content[0]).toEqual({ type: 'text', text: '{\n "n": 42\n}' }) + runtime.behavior = () => Promise.resolve({ logs: [], value: ['x', 2] }) + expect((await runCode(ctx, 'array')).content[0]).toEqual({ type: 'text', text: '[\n "x",\n 2\n]' }) + runtime.behavior = () => Promise.resolve({ logs: [], value: null }) + expect((await runCode(ctx, 'null')).content[0]).toEqual({ type: 'text', text: 'null' }) + runtime.behavior = () => Promise.resolve({ logs: [], value: 'raw' }) + expect((await runCode(ctx, 'string')).content[0]).toEqual({ type: 'text', text: 'raw' }) + runtime.behavior = () => Promise.resolve({ logs: [] }) + const absent = await runCode(ctx, 'undefined') + expect(absent.content[0]).toEqual({ type: 'text', text: '(run_code completed with no output)' }) + expect(absent.isError ? undefined : absent.value).toEqual({ logs: [] }) }) it('reports a pre-aborted outer signal as the run failure without dispatching anything', async () => { diff --git a/packages/core/tools/tests/ts-types.spec.ts b/packages/core/tools/tests/ts-types.spec.ts index 14b14f7ecd..48a174cbf4 100644 --- a/packages/core/tools/tests/ts-types.spec.ts +++ b/packages/core/tools/tests/ts-types.spec.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest' import { jsonSchemaToTs, renderToolsSdk } from '@deepseek-ai/dsh-tools/src/ts-types.ts' +import type { ToolSdkSchema } from '@deepseek-ai/dsh-tools/src/ts-types.ts' import { parameterSchemaSpecToJsonSchema } from '@deepseek-ai/dsh-tools' -import type { ToolSchema } from '@deepseek-ai/dsh-llm' describe('jsonSchemaToTs', () => { it('maps every unified schema construct', () => { @@ -96,31 +96,45 @@ describe('jsonSchemaToTs', () => { }) describe('renderToolsSdk', () => { - const bash: ToolSchema = { + const bash: ToolSdkSchema = { name: 'bash', description: 'Run a shell command.', parameters: parameterSchemaSpecToJsonSchema({ command: { type: 'string', required: true } }) as unknown as Record<string, unknown>, + output: { + type: 'object', + additionalProperties: false, + properties: { exitCode: { type: 'integer' } }, + required: ['exitCode'], + }, } - const exotic: ToolSchema = { + const exotic: ToolSdkSchema = { name: 'my-mcp.tool', description: 'Exotic name.', parameters: parameterSchemaSpecToJsonSchema({}) as unknown as Record<string, unknown>, + output: { type: 'array', items: { type: 'string' } }, } it('declares every tool in lexicographic order with quoted keys for exotic names', () => { const text = renderToolsSdk([exotic, bash]) + expect(text).toContain('interface ToolArgsMap {') + expect(text).toContain('interface ToolOutputMap {') + expect(text).toContain('type ToolName = keyof ToolOutputMap') + expect(text).toContain('declare class ToolCallError extends Error') + expect(text).toContain('readonly toolName: ToolName;') expect(text).toContain('declare const tools: {') expect(text).toContain('type JsonValue = null | boolean | number | string') - expect(text.indexOf('bash(args:')).toBeGreaterThan(0) - expect(text).toContain('"my-mcp.tool"(args:') - expect(text.indexOf('bash(args:')).toBeLessThan(text.indexOf('"my-mcp.tool"(args:')) - expect(text).toContain('): Promise<string>;') + expect(text.indexOf('bash: {')).toBeGreaterThan(0) + expect(text).toContain('"my-mcp.tool":') + expect(text.indexOf('bash:')).toBeLessThan(text.indexOf('"my-mcp.tool":')) + expect(text).toContain('exitCode: number;') + expect(text).toContain('"my-mcp.tool": string[];') + expect(text).toContain('[K in ToolName]: (args: ToolArgsMap[K]) => Promise<ToolOutputMap[K]>;') expect(text).toContain('/** Run a shell command. */') // The fixed instruction lines the model relies on. expect(text).toContain('erasable syntax only') - expect(text).toContain('rejects with an `Error`') + expect(text).toContain('rejects with `ToolCallError`') expect(text).toContain('sequentially, even under `Promise.all`') - expect(text).toContain('JSON-serializable') + expect(text).toContain('lossless JSON') }) it('is deterministic: same tool set, byte-identical text regardless of input order', () => { @@ -130,6 +144,8 @@ describe('renderToolsSdk', () => { }) it('renders an empty declaration for an empty tool set', () => { - expect(renderToolsSdk([])).toContain('declare const tools: {}') + const text = renderToolsSdk([]) + expect(text).toContain('interface ToolArgsMap {}') + expect(text).toContain('interface ToolOutputMap {}') }) }) diff --git a/packages/spill/spill-policy/package.json b/packages/spill/spill-policy/package.json index 9c28ea5382..7dc4631818 100644 --- a/packages/spill/spill-policy/package.json +++ b/packages/spill/spill-policy/package.json @@ -34,6 +34,7 @@ }, "devDependencies": { "@deepseek-ai/dsh-agent": "workspace:^", + "@deepseek-ai/dsh-code-runtime-worker": "workspace:^", "@deepseek-ai/dsh-llm": "workspace:^", "@deepseek-ai/dsh-retention": "workspace:^", "@deepseek-ai/dsh-session": "workspace:^", diff --git a/packages/spill/spill-policy/tests/spill-policy.spec.ts b/packages/spill/spill-policy/tests/spill-policy.spec.ts index e01703525f..ec40743db3 100644 --- a/packages/spill/spill-policy/tests/spill-policy.spec.ts +++ b/packages/spill/spill-policy/tests/spill-policy.spec.ts @@ -20,6 +20,7 @@ import type { ToolExecution, ToolExecutionToken } from '@deepseek-ai/dsh-tools' import { SpillLocator, SpillStore } from '@deepseek-ai/dsh-spill' import type { SaveTextSpill, SpillRef } from '@deepseek-ai/dsh-spill' import * as SpillPolicy from '@deepseek-ai/dsh-spill-policy' +import { WorkerCodeRuntime } from '@deepseek-ai/dsh-code-runtime-worker' /** A stub spill backend recording its saves; `fail` exercises the best-effort fallback. */ class StubStore extends SpillStore { @@ -173,6 +174,42 @@ describe('oversized plain-text replacement', () => { }) }) +describe('outer Code Mode failure capture', () => { + it('spills the bounded output-limit diagnostic through the ordinary outer-result policy', async () => { + const ctx = new Context() + await ctx.plugin(SystemPrompt) + await ctx.plugin(ToolRegistry, { mode: 'code' }) + await ctx.plugin(StubStore) + await ctx.plugin(SpillPolicy, { maxInlineBytes: 200 }) + await ctx.plugin(WorkerCodeRuntime, { maxOutputBytes: 500 }) + const events: unknown[] = [] + const agent = { + session: { + header: { id: SessionId('code-spill'), cwd: '/workspace' }, + append: (_type: string, data: unknown) => { events.push(data) }, + }, + } + + const result = await ctx.tools.execute({ + callId: CallId('code-output-limit'), + name: 'run_code', + arguments: { + code: 'console.log("HEAD-" + "x".repeat(300)); console.log("TAIL-" + "y".repeat(300)); return "unreachable";', + }, + agent: agent as never, + }) + + expect(result.isError).toBe(true) + const saved = (ctx.spillStore as StubStore).saves + expect(saved).toHaveLength(1) + expect(saved[0]?.source.toolName).toBe('run_code') + expect(saved[0]?.content).toContain('code run failed (output-limit)') + expect(saved[0]?.content).toContain('HEAD-') + expect(textOf(result.content)).toContain('Full formatted result stored at: /spill/run_code.txt') + expect(events).toEqual([]) + }) +}) + describe('read skip', () => { it('never spills the read tool result (avoids a read → spill → read loop)', async () => { const { ctx, spill } = await setup({ maxInlineBytes: 10 }) diff --git a/packages/subagent/subagent-inprocess/tests/structured.spec.ts b/packages/subagent/subagent-inprocess/tests/structured.spec.ts index a41ede8b86..114cebdd40 100644 --- a/packages/subagent/subagent-inprocess/tests/structured.spec.ts +++ b/packages/subagent/subagent-inprocess/tests/structured.spec.ts @@ -443,8 +443,10 @@ describe('in-process structured output', () => { expect(result.structured).toEqual({ answer: 12 }) const request = adapter.requests[0]! expect(toolNames(request)).toEqual([RUN_CODE_NAME]) - expect(request.system).toContain('declare const tools:') - expect(request.system).toContain('structured_output(args:') + expect(request.system).toContain('interface ToolArgsMap') + expect(request.system).toContain('interface ToolOutputMap') + expect(request.system).toContain('recorded: true;') + expect(request.system).toContain('Promise<ToolOutputMap[K]>') expect(request.system).toContain(STRUCTURED_OUTPUT_INSTRUCTION) await run.dispose() }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 903d8a7ca2..67bed639dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -369,6 +369,9 @@ importers: '@deepseek-ai/dsh-code-runtime': specifier: workspace:^ version: link:../code-runtime + '@deepseek-ai/dsh-session': + specifier: workspace:^ + version: link:../../core/session cordis: specifier: ^4.0.0-rc.7 version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5) @@ -1774,6 +1777,9 @@ importers: '@deepseek-ai/dsh-agent': specifier: workspace:^ version: link:../../core/agent + '@deepseek-ai/dsh-code-runtime-worker': + specifier: workspace:^ + version: link:../../code-runtime/code-runtime-worker '@deepseek-ai/dsh-llm': specifier: workspace:^ version: link:../../llm/llm diff --git a/scripts/type-equiv.manifest.json b/scripts/type-equiv.manifest.json index a003a50625..a191ebf947 100644 --- a/scripts/type-equiv.manifest.json +++ b/scripts/type-equiv.manifest.json @@ -154,6 +154,7 @@ { "doc": "docs/core-data-structures/code-runtime.md", "symbol": "CodeRunRequest", "source": "packages/code-runtime/code-runtime/src/types.ts" }, { "doc": "docs/core-data-structures/code-runtime.md", "symbol": "CodeRunResult", "source": "packages/code-runtime/code-runtime/src/types.ts" }, { "doc": "docs/core-data-structures/code-runtime.md", "symbol": "CodeBindingNamespace", "source": "packages/code-runtime/code-runtime/src/types.ts" }, + { "doc": "docs/core-data-structures/code-runtime.md", "symbol": "CodeJsonValue", "source": "packages/code-runtime/code-runtime/src/types.ts" }, { "doc": "docs/core-data-structures/code-runtime.md", "symbol": "CodeBindingFunction", "source": "packages/code-runtime/code-runtime/src/types.ts" }, { "doc": "docs/core-data-structures/code-runtime.md", "symbol": "CodeRunFailure", "source": "packages/code-runtime/code-runtime/src/types.ts" }, From 7c2fb0a6fe9d4edc14d61028a18d9f3b08ff0573 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 04:55:56 +0800 Subject: [PATCH 025/368] fix: keep Code Mode result cards complete --- ...de-mode-result-card-completeness.i18n.yaml | 6 +++ ...7-20-code-mode-result-card-completeness.md | 37 ++++++++++++++++++ ...0-code-mode-result-card-completeness.zh.md | 37 ++++++++++++++++++ .../feature/2026-06-15-code-mode.md | 2 +- .../snapshots/code-mode-turn/session.jsonl | 10 ++--- .../code-mode-turn/stdout.expected.jsonl | 4 +- .../tests/snapshots/code-mode/session.jsonl | 10 ++--- .../snapshots/code-mode/terminal.expected.txt | 30 ++++++++------- packages/core/tools/src/code-mode.ts | 26 ++----------- packages/core/tools/tests/code-mode.spec.ts | 38 ++++++++++--------- 10 files changed, 133 insertions(+), 67 deletions(-) create mode 100644 .agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml create mode 100644 .agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md create mode 100644 .agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml new file mode 100644 index 0000000000..2466af8f85 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-20-code-mode-result-card-completeness.md: 65aad02713498f5dbeff5ab3886da558326a0003 +2026-07-20-code-mode-result-card-completeness.zh.md: 082e209544d4ea43f75bb979fc3aa490b426952e diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md new file mode 100644 index 0000000000..65aad02713 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md @@ -0,0 +1,37 @@ +# Agent Note: Keep the Code Mode result card complete + +Status: implemented + +English | [中文](2026-07-20-code-mode-result-card-completeness.zh.md) + +## Problem + +The outer `run_code` tool persisted complete rendered content, but its editor presenter ignored that content and rebuilt the card body from a logs-only `presentationMeta` projection. A result-only run appeared correct because an empty presenter body let ACP and TUI fall back to `tool/result.content`. Once the program emitted a log, the presenter supplied non-empty content, that fallback stopped, and the returned value disappeared from the completed card. Failure text and a spill policy's final head/tail preview were vulnerable to the same split ownership. + +Nested Code calls never owned cards, so producing metadata for the outer call solely to reconstruct one incomplete card also obscured the intended one-card boundary. + +## Decision + +The `run_code` output renderer remains the single owner of model-facing outer content. It renders captured logs followed by the return value, the explicit no-output marker, or the failure content produced by the canonical tool pipeline. Post-execute policy and spill may replace that content before it is persisted. + +`run_code.presentResult` now forwards the final `result.content` into one generic result card. It deliberately omits the title so the pending card retains the program text. The existing logs metadata remains in `tool/result` for transcript compatibility, but the presenter no longer treats it as a second content source: `tool/result.content` is the durable, replayable, post-policy projection. + +Nested dispatch remains unchanged. Calls marked by `exec.parent` emit bounded `tool/code-dispatch` diagnostics but no `tool/call` or `tool/result` surface cards, so one outer `run_code` invocation still produces exactly one card. + +## Testing + +Presenter unit coverage pins logs-only, result-only, logs-plus-result, no-output, failure, and spilled-result content. Every case proves stale metadata cannot replace the final content. + +The keyless ACP and TUI Code Mode snapshots execute one outer program that performs two nested bash calls, logs `captured output`, and returns `CODE_ONE+CODE_TWO`. Both surfaces show one completed outer card containing both lines and no nested cards. + +## Alternatives considered + +**Append the return value to logs metadata.** Rejected because metadata would duplicate the renderer, need a second stable formatting contract for every JSON root, and still miss post-policy content replacement or spill previews. + +**Merge presenter metadata with `result.content`.** Rejected because the rendered content already contains the logs; merging would duplicate them and require brittle deduplication. + +**Create one card per nested dispatch.** Rejected because intermediate values are intentionally execution-local and never model-facing. Multiple cards would expose an implementation trace instead of the single Code Mode operation the model and user invoked. + +## Consequences + +ACP and TUI now display the same complete content the model receives and replay persists, including post-policy spill previews. The change adds or removes no event fields and requires no session-format bump. Existing and future replay records remain valid because the presenter ignores logs metadata when choosing card content and reads their durable rendered content. diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md new file mode 100644 index 0000000000..082e209544 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md @@ -0,0 +1,37 @@ +# Agent Note: 保证 Code Mode 结果卡片内容完整 + +Status: implemented + +[English](2026-07-20-code-mode-result-card-completeness.md) | 中文 + +## 问题 + +外层 `run_code` 工具会持久化完整的渲染内容,但编辑器的卡片展示逻辑忽略了这些内容,转而根据仅含日志的 `presentationMeta` 投影重新构建卡片正文。仅有结果的运行看似正确,是因为展示逻辑未提供正文时,ACP 和 TUI 会回退到 `tool/result.content`。只要程序输出一条日志,展示逻辑就会提供非空内容,回退随即停止,返回值便会从完成态卡片中消失。失败文本以及输出落盘策略最终生成的头尾预览,也会受到同一职责拆分的影响。 + +嵌套 Code 调用从不生成自己的卡片。因此,仅仅为了重建这一张不完整卡片而给外层调用生成元数据,还掩盖了每次外层调用只生成一张卡片的预期边界。 + +## 决策 + +`run_code` 输出渲染器继续作为面向模型的外层内容的唯一所有者。它先渲染已捕获的日志,然后渲染返回值、显式的无输出标记,或规范工具流水线生成的失败内容。Post-execute 策略与输出落盘机制可以在内容持久化之前替换它。 + +`run_code.presentResult` 会把最终的 `result.content` 转交给一张通用结果卡片。它有意省略标题,使待完成卡片保留程序文本。现有日志元数据仍保留在 `tool/result` 中,以维持 transcript(文本记录)兼容性;但展示逻辑不再把它视为第二个内容来源:`tool/result.content` 才是持久、可回放且经过 post-policy 处理的投影。 + +嵌套分发保持不变。带有 `exec.parent` 标记的调用会发出有界的 `tool/code-dispatch` 诊断,但不会生成与 `tool/call` 或 `tool/result` 对应的界面卡片,因此一次外层 `run_code` 调用仍然只会生成一张卡片。 + +## 测试 + +展示逻辑的单元测试覆盖仅有日志、仅有结果、日志与结果并存、无输出、失败和结果落盘六种情况。每个用例都证明,陈旧元数据无法替换最终内容。 + +无密钥的 ACP 与 TUI Code Mode 快照会执行一个外层程序:程序进行两次嵌套 bash 调用,记录 `captured output`,并返回 `CODE_ONE+CODE_TWO`。两个界面都只显示一张完成态外层卡片,其中包含这两行内容,且没有嵌套卡片。 + +## 备选方案 + +**把返回值追加到日志元数据:**不予采纳。元数据会与渲染器重复,并且需要为每一种 JSON 根另行维护稳定的格式化契约;post-policy 内容替换或输出落盘预览仍然会被遗漏。 + +**把展示元数据与 `result.content` 合并:**不予采纳。渲染内容已经包含日志;合并会造成重复,还需要依赖脆弱的去重逻辑。 + +**为每次嵌套分发创建一张卡片:**不予采纳。中间值有意只存在于执行期间,永远不面向模型。多张卡片会暴露实现轨迹,而不是模型与用户调用的单次 Code Mode 操作。 + +## 影响 + +ACP 和 TUI 会显示模型接收、回放持久化的同一份完整内容,其中包括 post-policy 输出落盘预览。该变更不增加或删除任何事件字段,也不需要提升会话格式版本。现有及未来的回放记录都保持有效,因为展示逻辑在选择卡片内容时会忽略日志元数据,转而读取记录中的持久化渲染内容。 diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.md index e51f95d247..4983ddcfaf 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.md @@ -48,7 +48,7 @@ Under `'code'` and `'both'` the registry owns `run_code` as a reserved presentat **Concurrency is serialized.** Each run owns a dispatch queue, so even `Promise.all` executes tool calls in submission order. Settlement abandons queued calls that have not started. Parallelism requires per-tool concurrency-safety metadata. -**Presentation.** `run_code`'s render intent is decided here per the [render-intent Agent Note](../architecture/2026-07-02-tool-render-intent-union.md): `presentCall` → a `generic` card, `kind: 'execute'`, title = the program text, `rawInput` = the same program text; `presentResult` → a `generic` card whose content is the captured output (from `meta`). The program is the title because ACP execute cards reliably render that field while some clients omit body and raw-input content. This is not a `terminal` card: that card's semantics are "a shell command in a working directory", which a program is not. +**Presentation.** `run_code`'s render intent is decided here per the [render-intent Agent Note](../architecture/2026-07-02-tool-render-intent-union.md): `presentCall` → a `generic` card, `kind: 'execute'`, title = the program text, `rawInput` = the same program text; `presentResult` → a `generic` card whose content is the final durable `tool/result.content`, including captured logs plus the returned value, failure, or post-policy spill preview. The existing logs metadata remains replayable but is not a second content source. The program is the title because ACP execute cards reliably render that field while some clients omit body and raw-input content. This is not a `terminal` card: that card's semantics are "a shell command in a working directory", which a program is not. See the [result-card completeness note](../bug-fix/2026-07-20-code-mode-result-card-completeness.md). ### Observability: `tool/code-dispatch` diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl b/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl index ec4e1a8d6a..84ebc9605a 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl @@ -89,7 +89,7 @@ {"type":"assistant/chunk","seq":87,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" echo"}}} {"type":"assistant/chunk","seq":88,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\""}}} {"type":"assistant/chunk","seq":89,"time":1783611772684,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" });\\n"}}} -{"type":"assistant/chunk","seq":90,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"return"}}} +{"type":"assistant/chunk","seq":90,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"console.log(\\\"captured output\\\");\\nreturn"}}} {"type":"assistant/chunk","seq":91,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} {"type":"assistant/chunk","seq":92,"time":1783611772713,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"1"}}} {"type":"assistant/chunk","seq":93,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".stdout.text.trim"}}} @@ -105,14 +105,14 @@ {"type":"assistant/chunk","seq":103,"time":1783611772772,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} {"type":"assistant/chunk","seq":104,"time":1783611772773,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"}"}}} {"type":"assistant/chunk","seq":105,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."}}}} -{"type":"assistant/chunk","seq":106,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}}}} +{"type":"assistant/chunk","seq":106,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}}}} {"type":"assistant/chunk","seq":107,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}}}} {"type":"assistant/chunk","seq":108,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} -{"type":"assistant/message","seq":109,"time":1783611772840,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."},{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108],"surfaceOp":"append"} -{"type":"tool/call","seq":110,"time":1783611772840,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}} +{"type":"assistant/message","seq":109,"time":1783611772840,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."},{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108],"surfaceOp":"append"} +{"type":"tool/call","seq":110,"time":1783611772840,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}} {"type":"tool/code-dispatch","seq":111,"time":1783611772933,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:1","name":"bash","arguments":{"command":"echo CODE_ONE","description":"First echo"},"isError":false,"resultSummary":"CODE_ONE\n"}} {"type":"tool/code-dispatch","seq":112,"time":1783611772936,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:2","name":"bash","arguments":{"command":"echo CODE_TWO","description":"Second echo"},"isError":false,"resultSummary":"CODE_TWO\n"}} -{"type":"tool/result","seq":113,"time":1783611772937,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","content":[{"type":"text","text":"CODE_ONE+CODE_TWO"}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[110],"surfaceOp":"append"} +{"type":"tool/result","seq":113,"time":1783611772937,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","content":[{"type":"text","text":"captured output\nCODE_ONE+CODE_TWO"}],"isError":false,"meta":{"logs":["captured output"]}},"sourceEventSeqs":[110],"surfaceOp":"append"} {"type":"step/end","seq":114,"time":1783611772938,"data":{"turn":1,"step":1}} {"type":"step/start","seq":115,"time":1783611772938,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":116,"time":1783611773376,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl b/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl index 855e1b3ca1..ce9167133f 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl @@ -30,8 +30,8 @@ {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" write"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" this"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","title":"const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" });\nconst out2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Second echo\" });\nreturn out1.stdout.text.trim() + \"+\" + out2.stdout.text.trim();","kind":"execute","status":"in_progress","rawInput":"const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" });\nconst out2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Second echo\" });\nreturn out1.stdout.text.trim() + \"+\" + out2.stdout.text.trim();"}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","status":"completed","content":[{"type":"content","content":{"type":"text","text":"CODE_ONE+CODE_TWO"}}]}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","title":"const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" });\nconst out2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Second echo\" });\nconsole.log(\"captured output\");\nreturn out1.stdout.text.trim() + \"+\" + out2.stdout.text.trim();","kind":"execute","status":"in_progress","rawInput":"const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" });\nconst out2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Second echo\" });\nconsole.log(\"captured output\");\nreturn out1.stdout.text.trim() + \"+\" + out2.stdout.text.trim();"}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","status":"completed","content":[{"type":"content","content":{"type":"text","text":"captured output\nCODE_ONE+CODE_TWO"}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"The"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" is"}}}} diff --git a/examples/tui-agent/tests/snapshots/code-mode/session.jsonl b/examples/tui-agent/tests/snapshots/code-mode/session.jsonl index ec4e1a8d6a..84ebc9605a 100644 --- a/examples/tui-agent/tests/snapshots/code-mode/session.jsonl +++ b/examples/tui-agent/tests/snapshots/code-mode/session.jsonl @@ -89,7 +89,7 @@ {"type":"assistant/chunk","seq":87,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" echo"}}} {"type":"assistant/chunk","seq":88,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\""}}} {"type":"assistant/chunk","seq":89,"time":1783611772684,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" });\\n"}}} -{"type":"assistant/chunk","seq":90,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"return"}}} +{"type":"assistant/chunk","seq":90,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"console.log(\\\"captured output\\\");\\nreturn"}}} {"type":"assistant/chunk","seq":91,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} {"type":"assistant/chunk","seq":92,"time":1783611772713,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"1"}}} {"type":"assistant/chunk","seq":93,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".stdout.text.trim"}}} @@ -105,14 +105,14 @@ {"type":"assistant/chunk","seq":103,"time":1783611772772,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} {"type":"assistant/chunk","seq":104,"time":1783611772773,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"}"}}} {"type":"assistant/chunk","seq":105,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."}}}} -{"type":"assistant/chunk","seq":106,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}}}} +{"type":"assistant/chunk","seq":106,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}}}} {"type":"assistant/chunk","seq":107,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}}}} {"type":"assistant/chunk","seq":108,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} -{"type":"assistant/message","seq":109,"time":1783611772840,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."},{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108],"surfaceOp":"append"} -{"type":"tool/call","seq":110,"time":1783611772840,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}} +{"type":"assistant/message","seq":109,"time":1783611772840,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."},{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108],"surfaceOp":"append"} +{"type":"tool/call","seq":110,"time":1783611772840,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}} {"type":"tool/code-dispatch","seq":111,"time":1783611772933,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:1","name":"bash","arguments":{"command":"echo CODE_ONE","description":"First echo"},"isError":false,"resultSummary":"CODE_ONE\n"}} {"type":"tool/code-dispatch","seq":112,"time":1783611772936,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:2","name":"bash","arguments":{"command":"echo CODE_TWO","description":"Second echo"},"isError":false,"resultSummary":"CODE_TWO\n"}} -{"type":"tool/result","seq":113,"time":1783611772937,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","content":[{"type":"text","text":"CODE_ONE+CODE_TWO"}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[110],"surfaceOp":"append"} +{"type":"tool/result","seq":113,"time":1783611772937,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","content":[{"type":"text","text":"captured output\nCODE_ONE+CODE_TWO"}],"isError":false,"meta":{"logs":["captured output"]}},"sourceEventSeqs":[110],"surfaceOp":"append"} {"type":"step/end","seq":114,"time":1783611772938,"data":{"turn":1,"step":1}} {"type":"step/start","seq":115,"time":1783611772938,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":116,"time":1783611773376,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/tui-agent/tests/snapshots/code-mode/terminal.expected.txt b/examples/tui-agent/tests/snapshots/code-mode/terminal.expected.txt index 2850e0c7d0..7f8998bd43 100644 --- a/examples/tui-agent/tests/snapshots/code-mode/terminal.expected.txt +++ b/examples/tui-agent/tests/snapshots/code-mode/terminal.expected.txt @@ -1,7 +1,7 @@ terminal 100x36 buffer=normal length=36 base=0 viewport=0 lifecycle started=1 stopped=0 progress=inactive title "DSH TUI snapshot" -cursor hidden column=1 viewportRow=29 bufferRow=29 +cursor hidden column=1 viewportRow=30 bufferRow=30 buffer 0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮" style 0-99 fg=bright-blue @@ -54,26 +54,28 @@ buffer 19| "▌ const o " style 0-0 fg=green style 2-8 bold -20| "▌ CODE_ONE+CODE_TWO " +20| "▌ captured output " style 0-0 fg=green -21| "▌ " +21| "▌ CODE_ONE+CODE_TWO " style 0-0 fg=green -22| <blank> -23| " Reasoning " +22| "▌ " + style 0-0 fg=green +23| <blank> +24| " Reasoning " style 1-9 fg=bright-black italic -24| " The output is exactly what the user asked for: CODE_ONE+CODE_TWO " +25| " The output is exactly what the user asked for: CODE_ONE+CODE_TWO " style 1-64 fg=bright-black italic -25| <blank> -26| " Assistant " +26| <blank> +27| " Assistant " style 1-9 fg=bright-magenta bold -27| " CODE_ONE+CODE_TWO " -28| "────────────────────────────────────────────────────────────────────────────────────────────────────" +28| " CODE_ONE+CODE_TWO " +29| "────────────────────────────────────────────────────────────────────────────────────────────────────" style 0-99 dim -29| " " +30| " " style 1-1 inverse -30| "────────────────────────────────────────────────────────────────────────────────────────────────────" +31| "────────────────────────────────────────────────────────────────────────────────────────────────────" style 0-99 dim -31| "/workspace/project ↑3.1k ↓158 idle reasoning:on tools:compact" +32| "/workspace/project ↑3.1k ↓158 idle reasoning:on tools:compact" style 0-49 dim style 67-99 dim -32-35| <blank> +33-35| <blank> diff --git a/packages/core/tools/src/code-mode.ts b/packages/core/tools/src/code-mode.ts index c9bda10358..713978b87e 100644 --- a/packages/core/tools/src/code-mode.ts +++ b/packages/core/tools/src/code-mode.ts @@ -107,22 +107,9 @@ function renderValue(value: JsonValue): string { return typeof value === 'string' ? value : JSON.stringify(value, null, 2) } -/** The run_code result's `meta` payload (JSON-serializable; `presentResult` narrows it back). */ -interface RunCodeMeta { - logs: CodeRunResult['logs'] -} - /** Canonical value returned by the outer Code Mode transport. */ type RunCodeOutput = { logs: string[]; result?: JsonValue } -/** Soft-narrow a result `meta` back to {@link RunCodeMeta} (replay may carry older shapes; presentation must not throw). */ -function asRunCodeMeta(meta: unknown): RunCodeMeta | undefined { - if (typeof meta !== 'object' || meta === null) return undefined - const m = meta as Record<string, unknown> - if (!Array.isArray(m.logs) || !m.logs.every(log => typeof log === 'string')) return undefined - return m as unknown as RunCodeMeta -} - /** * Build the `run_code` {@link ToolDefinition}: one required `code` parameter, * executed through the dispatch bridge described above. The @@ -293,15 +280,8 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () => }), // Title omitted on the result: an update replaces only the fields it // carries, so the pending card's program title persists through - // completion; the captured output rides as body content. - presentResult: (_args, result) => { - const meta = asRunCodeMeta(result.meta) - if (!meta) return undefined - const output = meta.logs.join('\n') - return { - card: 'generic', - ...output.length > 0 ? { content: [{ type: 'text' as const, text: output }] } : {}, - } - }, + // completion. The durable final content already includes logs plus the + // return value, failure, or post-policy spill preview. + presentResult: (_args, result) => ({ card: 'generic', content: result.content }), }) } diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index cfff494a62..7f76a0b539 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -663,7 +663,7 @@ describe('the run_code dispatch bridge', () => { expect((result.content[0] as { text: string }).text).toContain('requires a code runtime') }) - it('presents the PROGRAM as the execute-card title on both call and result (the one slot execute cards always show)', async () => { + it('presents the program as the execute-card title', async () => { const { ctx } = await setup({ mode: 'code' }) const tool = ctx.tools.get(RUN_CODE_NAME)! // The program IS the title, mirroring how command tools title their cards @@ -676,24 +676,28 @@ describe('the run_code dispatch bridge', () => { kind: 'execute', rawInput: 'return 1', }) - const view = tool.presentResult?.({ code: 'return 1' }, { - content: [{ type: 'text', text: 'model-facing' }], - isError: false, - meta: { logs: ['printed'] }, - }) + }) + + it.each([ + ['logs only', 'printed', false], + ['result only', 'returned', false], + ['logs plus result', 'printed\nreturned', false], + ['no output', '(run_code completed with no output)', false], + ['failure', 'Error: code run failed (output-limit): outer output exceeded 8 bytes', true], + ['spilled result', 'HEAD\n\n(Omitted 100 bytes. Full formatted result stored at: /tmp/run-code.txt.)\n\nTAIL', false], + ] as const)('presents %s from the final post-policy content', async (_name, text, isError) => { + const { ctx } = await setup({ mode: 'code' }) + const tool = ctx.tools.get(RUN_CODE_NAME)! // The result omits the title — an update replaces only provided fields, // so the pending card's program title persists through completion. - expect(view).toEqual({ - card: 'generic', - content: [{ type: 'text', text: 'printed' }], - }) - // No captured output → no content either; everything pending persists. - expect(tool.presentResult?.({ code: 'x' }, { content: [], isError: false, meta: { logs: [] } })) - .toEqual({ card: 'generic' }) - // Replay with an unrecognizable meta falls back to the generic rendering. - expect(tool.presentResult?.({ code: 'x' }, { content: [], isError: false, meta: { logs: [{ text: 'legacy' }], dispatches: 1 } })).toBeUndefined() - expect(tool.presentResult?.({ code: 'x' }, { content: [], isError: false, meta: { other: true } })).toBeUndefined() - expect(tool.presentResult?.({ code: 'x' }, { content: [], isError: false })).toBeUndefined() + const content = [{ type: 'text' as const, text }] + expect(tool.presentResult?.({ code: 'return 1' }, { + content, + isError, + // Stale or unrelated metadata must not replace the authoritative + // post-policy content used by the card. + meta: { logs: ['stale logs-only projection'] }, + })).toEqual({ card: 'generic', content }) }) it('renders non-text sub-result blocks as placeholders and truncates long event summaries', async () => { From aca8162ef21322e4dfbeff4938e546b26e44d4d1 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 04:57:34 +0800 Subject: [PATCH 026/368] docs: describe lossless Code Mode bindings --- .agents/notes/implemented/feature/2026-06-15-code-mode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.md index e51f95d247..91e0899e44 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.md @@ -124,7 +124,7 @@ Deployments switching to `'code'` must update any native-only `toolOrder`. Assem **Registry scope growth.** `dsh-tools` absorbs codegen, a tool, a bridge, and an event. Contained by module boundaries inside the package (`ts-types.ts`, `code-mode.ts` beside `schema.ts`/`json-schema.ts`/`presentation.ts`) and by the seam: everything substrate-shaped lives behind `ctx.codeRuntime`. -**Structured-clone values can exceed JSON.** Tool bindings therefore JSON-normalize arguments before dispatch, ensuring every executed call can be logged. The lower-level runtime keeps its wider port contract, while stricter consumers validate at their boundary. Non-text sub-results become placeholders. +**Large lossless JSON values can exhaust memory.** Tool bindings snapshot lossless JSON before dispatch and return canonical JSON resolutions whole. The runtime validates both sides of the worker port and applies no per-binding byte cap; structured-clone cost and process or worker memory are the practical bounds. The combined outer-output ledger for logs, the completion value, and a failure diagnostic is the only byte-capped boundary. **Serialized-only sub-dispatch.** `Promise.all` gains no wall-clock parallelism yet, only fewer round-trips; models may over-expect. The instructions state it; lifting it is tied to the same concurrency-safety metadata the native parallel-dispatch TODO needs. From 1709b8cfee7c00643007e0fd15f02b5eaa1d6865 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 05:19:40 +0800 Subject: [PATCH 027/368] fix: keep source Code Mode worker self-contained A direct runtime import of the session package made the unbuilt worker depend on sibling lib output. Use a parity-tested local JSON snapshotter and pin the isolated source closure with a real-worker test. --- .../code-runtime-worker/README.md | 2 +- .../code-runtime-worker/src/bootstrap.ts | 4 +- .../code-runtime-worker/src/worker-json.ts | 67 ++++++++++++++ .../tests/source-worker.compat.spec.ts | 36 ++++++++ .../tests/worker-json.spec.ts | 87 +++++++++++++++++++ 5 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 packages/code-runtime/code-runtime-worker/src/worker-json.ts create mode 100644 packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts create mode 100644 packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts diff --git a/packages/code-runtime/code-runtime-worker/README.md b/packages/code-runtime/code-runtime-worker/README.md index cc49c2f723..bfa19b1189 100644 --- a/packages/code-runtime/code-runtime-worker/README.md +++ b/packages/code-runtime/code-runtime-worker/README.md @@ -29,7 +29,7 @@ Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at ## The worker entry, unbuilt and built -Source mode loads erasable-only `src/worker.ts` through Node's native type stripping. Built mode passes the sibling `lib/worker.cjs` as a filesystem path because pkg's VFS Worker hook expects CommonJS; the same path works under ordinary Node. `tests/built-lib.e2e.ts` pins the real load path required by [docs/testing.md](../../../docs/testing.md). +Source mode loads erasable-only `src/worker.ts` through Node's native type stripping. Its transitive runtime closure contains only Node built-ins and relative source modules, so a fresh checkout never requires a sibling workspace package's unbuilt `lib/` export. The worker-local JSON snapshotter is parity-tested against the session-owned canonical boundary; the host repeats canonical validation after structured clone. Built mode passes the sibling `lib/worker.cjs` as a filesystem path because pkg's VFS Worker hook expects CommonJS; the same path works under ordinary Node. `tests/built-lib.e2e.ts` pins the real load path required by [docs/testing.md](../../../docs/testing.md). The SDK surface is the default/named `WorkerCodeRuntime` class plus `Config`. The operational `./worker` subpath exists only as the packaged spawn entry; the wire protocol and bootstrap helpers are source-private implementation details. diff --git a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts index e62ddd405e..45c8a4d2d2 100644 --- a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts +++ b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts @@ -6,8 +6,8 @@ */ import { inspect } from 'node:util' -import { snapshotJsonValue } from '@deepseek-ai/dsh-session' import type { DoneMessage, ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts' +import { snapshotCodeJsonValue } from './worker-json.ts' /** The port surface the bootstrap needs — satisfied by `parentPort` and by the tests' fake. */ export interface BootstrapPort { @@ -157,7 +157,7 @@ export function prepareCompletion(value: unknown, maxOutputBytes: number): Omit< if (value === undefined) return {} let snapshot: unknown try { - snapshot = snapshotJsonValue(value) + snapshot = snapshotCodeJsonValue(value) } catch { snapshot = undefined } diff --git a/packages/code-runtime/code-runtime-worker/src/worker-json.ts b/packages/code-runtime/code-runtime-worker/src/worker-json.ts new file mode 100644 index 0000000000..eec80184f6 --- /dev/null +++ b/packages/code-runtime/code-runtime-worker/src/worker-json.ts @@ -0,0 +1,67 @@ +/** Lossless-JSON snapshots for the dependency-free source worker closure. @module @deepseek-ai/dsh-code-runtime-worker/worker-json */ + +import type { CodeJsonValue } from '@deepseek-ai/dsh-code-runtime' + +/** + * Validate and detach one worker-boundary value without loading another + * workspace package at runtime. This mirrors the session-owned canonical + * JSON boundary while remaining safe to import from the unbuilt worker. + * + * @param value - the candidate completion value. + * @returns a detached lossless-JSON snapshot, or `undefined` when invalid. + */ +export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined { + const active = new Set<object>() + + const within = <T extends CodeJsonValue>(source: object, build: () => T | undefined): T | undefined => { + if (active.has(source)) return undefined + active.add(source) + try { + return build() + } finally { + active.delete(source) + } + } + + const copy = (candidate: unknown): CodeJsonValue | undefined => { + if (candidate === null) return null + if (typeof candidate === 'boolean' || typeof candidate === 'string') return candidate + if (typeof candidate === 'number') { + return Number.isFinite(candidate) && !Object.is(candidate, -0) ? candidate : undefined + } + if (typeof candidate !== 'object') return undefined + + if (Array.isArray(candidate)) { + if (Object.getPrototypeOf(candidate) !== Array.prototype) return undefined + return within(candidate, () => { + const result: CodeJsonValue[] = [] + for (let index = 0; index < candidate.length; index++) { + if (!Object.hasOwn(candidate, index)) return undefined + const item = copy(candidate[index]) + if (item === undefined) return undefined + result.push(item) + } + return result + }) + } + + const prototype = Object.getPrototypeOf(candidate) as unknown + if (prototype !== Object.prototype && prototype !== null) return undefined + return within(candidate, () => { + const result: Record<string, CodeJsonValue> = {} + for (const key of Object.keys(candidate)) { + const item = copy((candidate as Record<string, unknown>)[key]) + if (item === undefined) return undefined + Object.defineProperty(result, key, { + value: item, + enumerable: true, + configurable: true, + writable: true, + }) + } + return result + }) + } + + return copy(value) +} diff --git a/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts b/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts new file mode 100644 index 0000000000..5b71a9a94a --- /dev/null +++ b/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts @@ -0,0 +1,36 @@ +import { copyFile, mkdtemp, rm } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { Worker } from 'node:worker_threads' +import { expect, it } from 'vitest' + +/** + * Prove the unbuilt worker is a self-contained source closure. Copying it out + * of the workspace makes any package runtime import fail even when local + * `lib/` artifacts happen to exist. + */ +it('boots the source worker without workspace package outputs', async () => { + const directory = await mkdtemp(join(tmpdir(), 'dsh-code-source-worker-')) + let worker: Worker | undefined + try { + const files = ['worker.ts', 'bootstrap.ts', 'protocol.ts', 'worker-json.ts'] + await Promise.all(files.map(async (file) => { + await copyFile(new URL(`../src/${file}`, import.meta.url), join(directory, file)) + })) + + worker = new Worker(join(directory, 'worker.ts'), { + workerData: { code: 'return { answer: 42 }', namespaces: [], maxOutputBytes: 65_536 }, + env: {}, + execArgv: [], + }) + const message = await new Promise<unknown>((resolve, reject) => { + worker?.once('message', resolve) + worker?.once('error', reject) + }) + + expect(message).toEqual({ type: 'done', value: { answer: 42 } }) + } finally { + if (worker) await worker.terminate() + await rm(directory, { recursive: true, force: true }) + } +}) diff --git a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts new file mode 100644 index 0000000000..3f717599b7 --- /dev/null +++ b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts @@ -0,0 +1,87 @@ +import { describe, expect, it } from 'vitest' +import { snapshotJsonValue } from '@deepseek-ai/dsh-session' +import { snapshotCodeJsonValue } from '../src/worker-json.ts' + +describe('snapshotCodeJsonValue', () => { + it('matches the canonical scalar boundary', () => { + const unsupported = [undefined, 1n, Symbol('value'), () => 1] + for (const value of [null, false, 'text', 1.25, -0, Number.NaN, Number.POSITIVE_INFINITY, ...unsupported]) { + expect(snapshotCodeJsonValue(value)).toEqual(snapshotJsonValue(value)) + } + }) + + it('detaches dense arrays and plain or null-prototype records', () => { + const shared = { value: 1 } + const nullPrototype = Object.assign(Object.create(null) as Record<string, unknown>, { shared }) + const source = { list: [nullPrototype, shared], alias: shared } + + const snapshot = snapshotCodeJsonValue(source) as Record<string, unknown> + shared.value = 2 + + expect(snapshot).toEqual({ list: [{ shared: { value: 1 } }, { value: 1 }], alias: { value: 1 } }) + expect(snapshot).not.toBe(source) + expect((snapshot.list as unknown[])[0]).not.toBe(nullPrototype) + expect(snapshot.alias).not.toBe(shared) + }) + + it('reads each accepted slot once and preserves a literal __proto__ key', () => { + let objectReads = 0 + let arrayReads = 0 + const source = Object.create(null) as Record<string, unknown> + Object.defineProperty(source, '__proto__', { + enumerable: true, + get: () => { + objectReads += 1 + return { safe: true } + }, + }) + const array = new Array<unknown>(1) + Object.defineProperty(array, 0, { + enumerable: true, + get: () => { + arrayReads += 1 + return arrayReads === 1 ? source : undefined + }, + }) + + const snapshot = snapshotCodeJsonValue(array) as Record<string, unknown>[] + + expect(objectReads).toBe(1) + expect(arrayReads).toBe(1) + expect(Object.getPrototypeOf(snapshot[0])).toBe(Object.prototype) + expect(Object.hasOwn(snapshot[0]!, '__proto__')).toBe(true) + expect(snapshot[0]?.['__proto__']).toEqual({ safe: true }) + }) + + it('rejects exotic containers, sparse arrays, cycles, and invalid children', () => { + class ExoticObject { + readonly value = 1 + } + class ExoticArray extends Array<number> {} + const cyclic: Record<string, unknown> = {} + cyclic.self = cyclic + + for (const value of [ + new ExoticObject(), + new Map([['value', 1]]), + new ExoticArray(1), + new Array(1), + cyclic, + [undefined], + { value: undefined }, + ]) { + expect(snapshotCodeJsonValue(value)).toBeUndefined() + } + }) + + it('propagates a throwing getter and releases its recursion guard', () => { + const failure = new Error('getter failed') + const source = Object.defineProperty({}, 'value', { + enumerable: true, + get: () => { throw failure }, + }) + + expect(() => snapshotCodeJsonValue(source)).toThrow(failure) + expect(snapshotCodeJsonValue({ after: true })).toEqual({ after: true }) + }) +}) From 64d70670e8e5fe0d36151f3ad6cb4f7d20b96a7d Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:46:46 -0700 Subject: [PATCH 028/368] docs(i18n): address ds-review-bot on the v4 restoration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 解析器:三段闭合标签改为行首锚定(正文提及 </translation> 不再截 断)、重复段全文扫描并校验段序(补两条回归测试)。切换行:v4 模板 保持字面占位不变,资产文档写明全新配对由流水线在解析后按目标文件 名机械插入、配对门禁兜底。加粗后空格限定于字母/数字/汉字、标点前 一律不加;RFC 2119 关键词改为保留源侧强调标记(斜体归斜体、加粗 归加粗)。i18n README 双侧同步 v4 契约描述(不再承诺 CDATA 协议与 规则注入)并重录配对。 --- docs/i18n/README.i18n.yaml | 4 ++-- docs/i18n/README.md | 2 +- docs/i18n/README.zh.md | 2 +- docs/i18n/translation-prompt.md | 6 ++++-- scripts/translation-prompt.spec.ts | 14 ++++++++++++-- scripts/translation-prompt.ts | 24 ++++++++++++------------ 6 files changed, 32 insertions(+), 20 deletions(-) diff --git a/docs/i18n/README.i18n.yaml b/docs/i18n/README.i18n.yaml index ab1c9024ad..a1ff3a701e 100644 --- a/docs/i18n/README.i18n.yaml +++ b/docs/i18n/README.i18n.yaml @@ -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 -README.md: 17bb1eeb67b4f5119a698fca23f12490c9378a7f -README.zh.md: c957a82bf420a942e2249942a2d9afc54ad950cf +README.md: 3980aef52545aeb7c8ec44856cb95c7c0f7c7f22 +README.zh.md: 39e03cb6d33c008d2f310915db6b6bebd638cded diff --git a/docs/i18n/README.md b/docs/i18n/README.md index 17bb1eeb67..3980aef525 100644 --- a/docs/i18n/README.md +++ b/docs/i18n/README.md @@ -49,4 +49,4 @@ The gate's limit, stated plainly: **a green gate means the pair was confirmed co ## Division of labor -Counterparts here are produced by an agent running [dsh-translate-docs](../../.agents/skills/dsh-translate-docs/SKILL.md) and reviewed by a human — inference is cheap here, review attention is the scarce resource. The gate checks pair completeness, recorded hashes, switchers, and its documented structural signature. Review still owns translation quality, terminology, and structural requirements that the signature does not encode. The prompt contract is executable: [scripts/translation-prompt.ts](../../scripts/translation-prompt.ts) renders the canonical rules into either direction and strictly parses the three-field XML response, while `verify-translation-prompt` exercises both render directions, the checked-in example, and the CDATA split rule in `doc-sync`. +Counterparts here are produced by an agent running [dsh-translate-docs](../../.agents/skills/dsh-translate-docs/SKILL.md) and reviewed by a human — inference is cheap here, review attention is the scarce resource. The gate checks pair completeness, recorded hashes, switchers, and its documented structural signature. Review still owns translation quality, terminology, and structural requirements that the signature does not encode. The prompt contract is executable: [scripts/translation-prompt.ts](../../scripts/translation-prompt.ts) renders the committed template (terminology injected; the template carries its own calibrated rules) into either direction and parses the three-section response, while `verify-translation-prompt` exercises both render directions and the checked-in example in `doc-sync`. diff --git a/docs/i18n/README.zh.md b/docs/i18n/README.zh.md index c957a82bf4..39e03cb6d3 100644 --- a/docs/i18n/README.zh.md +++ b/docs/i18n/README.zh.md @@ -49,4 +49,4 @@ ## 分工 -对侧译文由运行 [dsh-translate-docs](../../.agents/skills/dsh-translate-docs/SKILL.md) 的 agent 生成,再由人评审:在这里推理(inference)很便宜,评审注意力才是稀缺资源。门禁负责检查配对是否完整、记录的 hash、语言切换行以及本文列出的结构签名;翻译质量、术语和签名未涵盖的结构要求仍由评审把关。prompt 契约也有可执行实现:[scripts/translation-prompt.ts](../../scripts/translation-prompt.ts) 会把权威规则渲染到英译中或中译英的 prompt 中,并严格解析包含三个字段的 XML 响应;`doc-sync` 中的 `verify-translation-prompt` 会检查两个渲染方向、仓库内示例与 CDATA 拆分规则。 +对侧译文由运行 [dsh-translate-docs](../../.agents/skills/dsh-translate-docs/SKILL.md) 的 agent 生成,再由人评审:在这里推理(inference)很便宜,评审注意力才是稀缺资源。门禁负责检查配对是否完整、记录的 hash、语言切换行以及本文列出的结构签名;翻译质量、术语和签名未涵盖的结构要求仍由评审把关。prompt 契约也有可执行实现:[scripts/translation-prompt.ts](../../scripts/translation-prompt.ts) 会把进仓模板(注入术语表;模板自带经人工校准的规则)渲染到英译中或中译英的 prompt 中,并解析三段式响应;`doc-sync` 中的 `verify-translation-prompt` 会检查两个渲染方向与仓库内示例。 diff --git a/docs/i18n/translation-prompt.md b/docs/i18n/translation-prompt.md index d59170b00a..91b52bbb51 100644 --- a/docs/i18n/translation-prompt.md +++ b/docs/i18n/translation-prompt.md @@ -14,6 +14,8 @@ 流水线只识别上表中的占位符,并且一次翻译整篇文档。它不支持 `{{to}}`、`{{title_prompt}}`、`{{summary_prompt}}`、`{{terms_prompt}}`、`{{imt_style_guide}}`、`{{translation_rules}}` 或 `%%` 分段协议;输出采用模板正文规定的三段 XML,流水线解析取 `<final>` 段。 +语言切换行:已有配对的源文件自带切换行,模型按模板规则翻转即可。全新配对的源文件没有切换行,模型也无从得知文件名——此时由流水线在解析 `<final>` 后按目标文件名插入或校正切换行(机械后处理,配对门禁兜底校验)。 + ## Few-shot 金标 流水线使用**整篇文档**的中英对照作为 few-shot,不是模板内嵌的句子级正误例。以下 5 组配对文档均经过人工评审,以仓库当前版本为准、随仓库更新: @@ -41,7 +43,7 @@ You are a senior technical translator specializing in LLM and agent development - Inline code spans (commands, flags, paths, API names, version numbers) must be kept verbatim. Never translate or reformat them. - Every relative link must point to the same target as in the source. Link text is translated; link targets are not. - Language switcher line: when translating into Chinese, write `[English](source-filename.md) | 中文`. When translating into English, write `English | [中文](source-filename.zh.md)`. Do NOT copy the switcher line from the source file unchanged — you must flip the link direction. -- After a closing bold marker `**`, always insert a space before the next character. +- After a closing bold marker `**`, insert a space before the next character when that character is a Latin letter, digit, or CJK ideograph. Never insert a space before any punctuation (full-width or half-width). ### Tone and Style - The translation must read as if originally written in the target language by a native speaker. If an expression sounds like a word-for-word rendering from the source language, rephrase it. @@ -73,7 +75,7 @@ You are a senior technical translator specializing in LLM and agent development - Use enumeration commas (、) between parallel items, not regular commas. - List item endings: use semicolons or no punctuation. Do not end list items with commas. - Put one half-width space between Chinese text and Latin words/numbers. -- For RFC 2119 keywords (MUST, MUST NOT, SHOULD, MAY), render the corresponding Chinese term in italics: *必须*、*禁止*、*应当*、*可以*. +- For RFC 2119 keywords (MUST, MUST NOT, SHOULD, MAY), translate to the corresponding Chinese term (必须、禁止、应当、可以) and keep the SOURCE emphasis marker: plain source stays plain in italics (*必须*), bold source stays bold (**必须**). #### When translating into English (To be added.) diff --git a/scripts/translation-prompt.spec.ts b/scripts/translation-prompt.spec.ts index db3f8b31a0..45ba97b8e7 100644 --- a/scripts/translation-prompt.spec.ts +++ b/scripts/translation-prompt.spec.ts @@ -42,9 +42,19 @@ describe('translation response sections', () => { expect(parseTranslationResponse(fenced).final).toBe('A') }) + it('keeps an inline close tag inside prose from terminating the section', () => { + const doc = { translation: 'the wire format uses </translation> as its close tag', review: '- 无修正', final: 'F' } + expect(parseTranslationResponse(renderTranslationResponse(doc))).toEqual(doc) + }) + + it('rejects a duplicate section appearing before final', () => { + const early = '<translation>\nA\n</translation>\n<translation>\nB\n</translation>\n<review>\nR\n</review>\n<final>\nF\n</final>' + expect(() => parseTranslationResponse(early)).toThrow(/duplicate <translation>/) + }) + it('rejects missing, unterminated, or duplicated sections', () => { - expect(() => parseTranslationResponse('<translation>\nA\n</translation>')).toThrow(/missing <review>/) - expect(() => parseTranslationResponse('<translation>\nA')).toThrow(/unterminated <translation>/) + expect(() => parseTranslationResponse('<translation>\nA\n</translation>')).toThrow(/missing or unterminated <review>/) + expect(() => parseTranslationResponse('<translation>\nA')).toThrow(/missing or unterminated <translation>/) const dup = '<translation>\nA\n</translation>\n<review>\nR\n</review>\n<final>\nF\n</final>\n<final>\nG\n</final>' expect(() => parseTranslationResponse(dup)).toThrow(/duplicate <final>/) }) diff --git a/scripts/translation-prompt.ts b/scripts/translation-prompt.ts index 0556ff39fa..25f1d9ae09 100644 --- a/scripts/translation-prompt.ts +++ b/scripts/translation-prompt.ts @@ -81,6 +81,10 @@ export function renderTranslationResponse(response: TranslationResponse): string * and in order; bodies are raw Markdown taken verbatim between the tags. * A fenced ```xml wrapper around the whole response is tolerated, matching * the shape some models echo back from the prompt's own example. + * + * Section close tags are matched at line starts (the wire shape the prompt + * example establishes), so a tag mentioned inline in translated prose does + * not terminate its section early. */ export function parseTranslationResponse(text: string): TranslationResponse { let body = text.trim() @@ -88,20 +92,16 @@ export function parseTranslationResponse(text: string): TranslationResponse { if (fenced?.[1] !== undefined) body = fenced[1].trim() const values: Partial<Record<(typeof RESPONSE_SECTIONS)[number], string>> = {} - let cursor = 0 for (const section of RESPONSE_SECTIONS) { - const open = `<${section}>` - const close = `</${section}>` - const start = body.indexOf(open, cursor) - if (start === -1) throw new Error(`translation response: missing <${section}> section`) - const end = body.indexOf(close, start + open.length) - if (end === -1) throw new Error(`translation response: unterminated <${section}> section`) - values[section] = body.slice(start + open.length, end).replace(/^\n/, '').replace(/\n$/, '') - cursor = end + close.length + const pattern = new RegExp(`^<${section}>\\n?([\\s\\S]*?)\\n?^</${section}>$`, 'gm') + const first = pattern.exec(body) + if (first?.[1] === undefined) throw new Error(`translation response: missing or unterminated <${section}> section`) + if (pattern.exec(body) !== null) throw new Error(`translation response: duplicate <${section}> section`) + values[section] = first[1] } - for (const section of RESPONSE_SECTIONS) { - const again = body.indexOf(`<${section}>`, cursor) - if (again !== -1) throw new Error(`translation response: duplicate <${section}> section`) + const order = RESPONSE_SECTIONS.map(section => body.search(new RegExp(`^<${section}>`, 'm'))) + if (!(order[0]! < order[1]! && order[1]! < order[2]!)) { + throw new Error('translation response: sections must appear in translation, review, final order') } return values as TranslationResponse } From 4574340d7a09e5296b1ba25aaa997f28c88eaf5b Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 17:44:46 +0800 Subject: [PATCH 029/368] fix(tools): harden unified JSON value boundaries --- docs/tool-catalog.md | 2 +- .../system-prompt.expected.md | 2 +- .../tool-schemas.expected.json | 2 +- .../both-mode-turn/system-prompt.expected.md | 2 +- .../both-mode-turn/tool-schemas.expected.json | 2 +- .../code-mode-turn/system-prompt.expected.md | 2 +- .../system-prompt.expected.md | 2 +- .../tool-schemas.expected.json | 4 +-- .../tool-schemas.expected.json | 4 +-- .../skill-load/tool-schemas.expected.json | 2 +- .../text-turn/tool-schemas.expected.json | 2 +- .../tool-schemas.expected.json | 2 +- packages/cordis/tool-cordis/src/guard.ts | 23 ++++++++++-- .../cordis/tool-cordis/tests/mount.spec.ts | 36 +++++++++++++++++++ packages/core/session/src/json.ts | 16 ++++++--- packages/core/session/tests/json.spec.ts | 15 ++++++-- packages/core/tools/README.md | 2 +- packages/core/tools/src/json-schema.ts | 28 ++++++++++++--- packages/core/tools/src/schema.ts | 7 +++- packages/core/tools/tests/json-schema.spec.ts | 17 +++++++++ packages/core/tools/tests/schema.spec.ts | 12 +++++++ packages/workflow/tool-workflow/src/index.ts | 2 +- 22 files changed, 155 insertions(+), 31 deletions(-) diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md index eaf24e38a7..904234b54f 100644 --- a/docs/tool-catalog.md +++ b/docs/tool-catalog.md @@ -703,7 +703,7 @@ Run a JavaScript workflow script that orchestrates subagents at scale. Use this The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: -- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. +- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. diff --git a/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md index 3e111b8ba2..dad8009286 100644 --- a/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md @@ -179,7 +179,7 @@ declare const tools: { /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; } & Record<string, JsonValue>): Promise<string>; - /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ + /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ workflow(args: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ script: string; diff --git a/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json index 95cdd43b83..03dfc09154 100644 --- a/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json @@ -436,7 +436,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { diff --git a/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md index 2ec278e294..e40337ac14 100644 --- a/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md @@ -162,7 +162,7 @@ declare const tools: { /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; } & Record<string, JsonValue>): Promise<string>; - /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ + /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ workflow(args: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ script: string; diff --git a/examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json index 8406669edc..0fc8107917 100644 --- a/examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json @@ -379,7 +379,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md index 2ec278e294..e40337ac14 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md @@ -162,7 +162,7 @@ declare const tools: { /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; } & Record<string, JsonValue>): Promise<string>; - /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ + /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ workflow(args: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ script: string; diff --git a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md index 2ec278e294..e40337ac14 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md @@ -162,7 +162,7 @@ declare const tools: { /** Concrete blocking condition; required only with action blocked. */ blocked_reason?: string; } & Record<string, JsonValue>): Promise<string>; - /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ + /** Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn. The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages. - `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`. Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes. */ workflow(args: { /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`). */ script: string; diff --git a/examples/acp-agent/tests/snapshots/model-switching/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/model-switching/tool-schemas.expected.json index 4ee311eb65..a4524cc974 100644 --- a/examples/acp-agent/tests/snapshots/model-switching/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/model-switching/tool-schemas.expected.json @@ -363,7 +363,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { @@ -834,7 +834,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { diff --git a/examples/acp-agent/tests/snapshots/permission-switching/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/permission-switching/tool-schemas.expected.json index 4ee311eb65..a4524cc974 100644 --- a/examples/acp-agent/tests/snapshots/permission-switching/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/permission-switching/tool-schemas.expected.json @@ -363,7 +363,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { @@ -834,7 +834,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { diff --git a/examples/acp-agent/tests/snapshots/skill-load/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/skill-load/tool-schemas.expected.json index de3254fd2e..d4973bfea4 100644 --- a/examples/acp-agent/tests/snapshots/skill-load/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/skill-load/tool-schemas.expected.json @@ -363,7 +363,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { diff --git a/examples/acp-agent/tests/snapshots/text-turn/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/text-turn/tool-schemas.expected.json index de3254fd2e..d4973bfea4 100644 --- a/examples/acp-agent/tests/snapshots/text-turn/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/text-turn/tool-schemas.expected.json @@ -363,7 +363,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { diff --git a/examples/acp-agent/tests/snapshots/workspace-context/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/workspace-context/tool-schemas.expected.json index de3254fd2e..d4973bfea4 100644 --- a/examples/acp-agent/tests/snapshots/workspace-context/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/workspace-context/tool-schemas.expected.json @@ -363,7 +363,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { diff --git a/packages/cordis/tool-cordis/src/guard.ts b/packages/cordis/tool-cordis/src/guard.ts index c55fd34b78..8ef931c5e5 100644 --- a/packages/cordis/tool-cordis/src/guard.ts +++ b/packages/cordis/tool-cordis/src/guard.ts @@ -27,7 +27,9 @@ type DynamicToolDefinition = ToolDefinition & { [DYNAMIC_TOOL]: true } type DynamicToolMarker = { [DYNAMIC_TOOL]?: unknown } function isPlainRecord(value: unknown): value is Record<string, unknown> { - return Object.prototype.toString.call(value) === '[object Object]' + if (typeof value !== 'object' || value === null || Array.isArray(value)) return false + const prototype: unknown = Object.getPrototypeOf(value) + return prototype === null || Object.getPrototypeOf(prototype) === null } /** Materialize realm-foreign lossless JSON without allowing JSON.stringify coercions. */ @@ -42,6 +44,9 @@ function cloneJson(value: unknown, path: string, seen = new Set<object>()): unkn seen.add(value) try { if (Array.isArray(value)) { + if (Reflect.ownKeys(value).length !== value.length + 1) { + throw new Error(`harness.defineTool ${path} must be lossless JSON data`) + } const output: unknown[] = [] for (let index = 0; index < value.length; index++) { if (!Object.hasOwn(value, index)) throw new Error(`harness.defineTool ${path} must be lossless JSON data`) @@ -51,7 +56,14 @@ function cloneJson(value: unknown, path: string, seen = new Set<object>()): unkn } if (!isPlainRecord(value)) throw new Error(`harness.defineTool ${path} must be lossless JSON data`) const output: Record<string, unknown> = {} - for (const [key, entry] of Object.entries(value)) output[key] = cloneJson(entry, `${path}.${key}`, seen) + for (const [key, entry] of Object.entries(value)) { + Object.defineProperty(output, key, { + value: cloneJson(entry, `${path}.${key}`, seen), + enumerable: true, + configurable: true, + writable: true, + }) + } return output } finally { seen.delete(value) @@ -129,7 +141,12 @@ function normalizePropertyMap( ): Record<string, unknown> { const spec: Record<string, unknown> = {} for (const [key, prop] of Object.entries(entries)) { - spec[key] = normalizeValueSchema(prop, `${path}.${key}`, requiredNames.has(key), raw, true) + Object.defineProperty(spec, key, { + value: normalizeValueSchema(prop, `${path}.${key}`, requiredNames.has(key), raw, true), + enumerable: true, + configurable: true, + writable: true, + }) } return spec } diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 42af6fc64e..db001c3877 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -343,6 +343,8 @@ describe('cordis_mount', () => { ['parameters: { value: { type: \'json\', default: () => 1 } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: (() => { const v = {}; v.self = v; return v })() } }', 'parameters.value.default.self must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: Array(2) } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: Object.assign([1], { extra: true }) } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: new (class DefaultValue { constructor() { this.ok = true } })() } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: new Date(0) } }', 'parameters.value.default must be lossless JSON data'], ])('rejects a malformed ParameterSchemaSpec (%s) with a teaching error', async (parameters, message) => { const ctx = await setup() @@ -366,6 +368,40 @@ describe('cordis_mount', () => { expect(text(result)).toContain(message) }) + it('preserves literal __proto__ keys in sandbox schemas and annotations', async () => { + const ctx = await setup() + const result = await call(ctx, 'cordis_mount', { + code: ` + return { + name: 'proto-schema', + inject: ['tools'], + apply(ctx) { + harness.registerTool(ctx, harness.defineTool({ + name: 'proto_schema_tool', + description: 'literal JSON keys', + parameters: { + ['__proto__']: { type: 'string', required: true }, + value: { type: 'json', default: { ['__proto__']: { safe: true } } }, + }, + async execute() { return [] }, + })) + }, + } + `, + }) + + expect(result.isError).toBe(false) + const parameters = ctx.tools.schemas().find(schema => schema.name === 'proto_schema_tool')!.parameters as { + properties: Record<string, { default?: unknown }> + required?: string[] + } + expect(Object.hasOwn(parameters.properties, '__proto__')).toBe(true) + expect(parameters.required).toContain('__proto__') + const defaultValue = parameters.properties.value!.default as Record<string, unknown> + expect(Object.hasOwn(defaultValue, '__proto__')).toBe(true) + expect(defaultValue.__proto__).toEqual({ safe: true }) + }) + it('accepts a nested object/array ParameterSchemaSpec (the DSL recursion)', async () => { const ctx = await setup() const result = await call(ctx, 'cordis_mount', { diff --git a/packages/core/session/src/json.ts b/packages/core/session/src/json.ts index 35874a49e5..f0d3d42266 100644 --- a/packages/core/session/src/json.ts +++ b/packages/core/session/src/json.ts @@ -3,11 +3,12 @@ /** * A value that round-trips losslessly through JSON: `null`, a boolean, a finite * number other than negative zero, a string, an array of such values, or a - * plain object whose values are such values. TypeScript cannot distinguish - * `-0` from `number`, so {@link isJsonValue} and {@link snapshotJsonValue} - * enforce that last numeric detail at runtime. Use this type for a payload that - * must survive session-log persistence and replay byte-identically — e.g. a - * tool's private presentation `meta`. + * plain object whose values are such values. Arrays may carry only their dense + * indexed elements; extra own properties would be discarded by JSON. TypeScript + * cannot distinguish `-0` from `number`, so {@link isJsonValue} and + * {@link snapshotJsonValue} enforce these details at runtime. Use this type for + * a payload that must survive session-log persistence and replay byte-identically + * — e.g. a tool's private presentation `meta`. */ export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } @@ -47,6 +48,10 @@ export function snapshotJsonValue<T>(value: T): T | undefined { if (Array.isArray(current)) { if (Object.getPrototypeOf(current) !== Array.prototype) return undefined const length = current.length + // Every ordinary array owns `length`; dense indexed elements account + // for the remaining keys. Anything else would be lost by JSON and by + // structured clone, including symbols and non-enumerable properties. + if (Reflect.ownKeys(current).length !== length + 1) return undefined const snapshot: JsonValue[] = [] for (let index = 0; index < length; index++) { if (!Object.prototype.hasOwnProperty.call(current, index)) return undefined @@ -111,6 +116,7 @@ export function isJsonValue(value: unknown, seen: Set<object> = new Set()): bool try { if (Array.isArray(value)) { if (Object.getPrototypeOf(value) !== Array.prototype) return false + if (Reflect.ownKeys(value).length !== value.length + 1) return false // Reject sparse arrays: a hole is skipped by `every`/`forEach` but // JSON.stringify writes it as `null`, so `[1, , 3]` would round-trip // lossily. Require every index 0..length-1 to be an OWN property. diff --git a/packages/core/session/tests/json.spec.ts b/packages/core/session/tests/json.spec.ts index 4fb06fd744..435126c22e 100644 --- a/packages/core/session/tests/json.spec.ts +++ b/packages/core/session/tests/json.spec.ts @@ -63,12 +63,16 @@ describe('snapshotJsonValue', () => { expect(arrayReads).toBe(1) }) - it('rejects exotic containers, sparse arrays, cycles, and invalid children', () => { + it('rejects exotic containers, sparse or decorated arrays, cycles, and invalid children', () => { class ExoticObject { readonly value = 1 } class ExoticArray extends Array<number> {} const sparse = new Array<number>(1) + const decorated = [1] + Object.defineProperty(decorated, 'extra', { value: true }) + const symbolDecorated = [1] + Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) const cyclic: Record<string, unknown> = {} cyclic.self = cyclic @@ -76,6 +80,8 @@ describe('snapshotJsonValue', () => { expect(snapshotJsonValue(new Map([['value', 1]]))).toBeUndefined() expect(snapshotJsonValue(new ExoticArray(1))).toBeUndefined() expect(snapshotJsonValue(sparse)).toBeUndefined() + expect(snapshotJsonValue(decorated)).toBeUndefined() + expect(snapshotJsonValue(symbolDecorated)).toBeUndefined() expect(snapshotJsonValue(cyclic)).toBeUndefined() expect(snapshotJsonValue([undefined])).toBeUndefined() expect(snapshotJsonValue({ value: undefined })).toBeUndefined() @@ -133,16 +139,21 @@ describe('isJsonValue', () => { expect(isJsonValue(nullPrototype)).toBe(true) }) - it('rejects sparse arrays, invalid children, exotic objects, and cycles', () => { + it('rejects sparse or decorated arrays, invalid children, exotic objects, and cycles', () => { class Exotic { readonly value = 1 } class ExoticArray extends Array<number> {} const sparse = new Array<number>(1) + const decorated = Object.assign([1], { extra: true }) + const symbolDecorated = [1] + Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) const cyclic: Record<string, unknown> = {} cyclic.self = cyclic expect(isJsonValue(sparse)).toBe(false) + expect(isJsonValue(decorated)).toBe(false) + expect(isJsonValue(symbolDecorated)).toBe(false) expect(isJsonValue(new ExoticArray(1))).toBe(false) expect(isJsonValue([undefined])).toBe(false) expect(isJsonValue({ value: undefined })).toBe(false) diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 5ec2d4e7e4..a26bffd8f6 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -178,7 +178,7 @@ Append-only; newly visible content follows the reusable request prefix and does - **Concurrency policy is not an event seam** — `executionMode()` reads the resolved tool definition directly; plugins can only declare a classifier on definitions they own. - **`tools/pre-execute` deliberately cannot rewrite `exec.arguments`** — logged and rendered args would desync from what ran; the rewrite design is [a proposed Agent Note](../../../.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.md). -- **`defineTool`'s schema DSL is a deliberate subset** — string/number/boolean/object/array with string-only `enum`; `validateArgs` tolerates extra keys and preserves `default` as a model-visible JSON Schema annotation without applying it during validation; dynamic Cordis mounts may supply defaults even though first-party definitions do not, while raw-registered JSON-Schema tools validate their own input. +- **Caller-defined subagent and workflow structured outputs remain object-rooted** — this is a consumer-level guard; the shared schema vocabulary supports every JSON root. - **`timeoutMs` on a definition is declarative only** — the registry never enforces deadlines; enforcement requires the `@deepseek-ai/dsh-timeout-policy` wrapper. - **Code Mode is TypeScript-only and the presentation mode is service-wide** — `mode: code`/`both` rejects prompt assembly unless `ctx.codeRuntime.language === 'typescript'`; scoped restrictions/shadows still choose each agent's visible bindings, but one tool cannot be native-only while another is code-only. - **Code Mode bindings return text only** — non-text content blocks in a sub-call result collapse to `[<type> content]` placeholders. diff --git a/packages/core/tools/src/json-schema.ts b/packages/core/tools/src/json-schema.ts index 82ee0c50ac..a60b166b78 100644 --- a/packages/core/tools/src/json-schema.ts +++ b/packages/core/tools/src/json-schema.ts @@ -235,13 +235,21 @@ function checkSchemaNode(node: unknown, path: string, violations: string[], seen case 'boolean': case 'null': { const allowed = node.enum + const enumValid = Array.isArray(allowed) + && allowed.length > 0 + && allowed.every(entry => scalarMatches(schemaType, entry)) if (Object.hasOwn(node, 'enum')) { - if (!Array.isArray(allowed) || allowed.length === 0 || !allowed.every(entry => scalarMatches(schemaType, entry))) { + if (!enumValid) { violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`) } } - if (Object.hasOwn(node, 'const') && !scalarMatches(schemaType, node.const)) { - violations.push(`${path}.const must be a ${schemaType} value`) + const constValid = scalarMatches(schemaType, node.const) + if (Object.hasOwn(node, 'const')) { + if (!constValid) { + violations.push(`${path}.const must be a ${schemaType} value`) + } else if (enumValid && !allowed.includes(node.const as JsonSchemaScalar)) { + violations.push(`${path}.const must be one of ${path}.enum when both are declared`) + } } break } @@ -300,8 +308,20 @@ function propertyPath(path: string, key: string): string { return path === '' ? key : `${path}.${key}` } -/** Collect value violations for one trusted schema node. */ +/** Contain hostile getters/proxies so validation remains total for arbitrary values. */ function checkValue(node: JsonSchemaNode, value: unknown, path: string): string[] { + if (node.type !== undefined && !(SCHEMA_TYPES as readonly unknown[]).includes(node.type)) { + return checkValueUnchecked(node, value, path) + } + try { + return checkValueUnchecked(node, value, path) + } catch { + return [`"${diagnosticPath(path)}" must be a lossless JSON value`] + } +} + +/** Collect value violations for one trusted schema node after the exception boundary. */ +function checkValueUnchecked(node: JsonSchemaNode, value: unknown, path: string): string[] { if (node.oneOf !== undefined) { const matches = node.oneOf.filter(branch => checkValue(branch, value, path).length === 0).length return matches === 1 ? [] : [`"${diagnosticPath(path)}" must match exactly one oneOf branch (matched ${matches})`] diff --git a/packages/core/tools/src/schema.ts b/packages/core/tools/src/schema.ts index 98be959e4e..4a559d47eb 100644 --- a/packages/core/tools/src/schema.ts +++ b/packages/core/tools/src/schema.ts @@ -197,7 +197,12 @@ function compilePropertyMap( if (Object.hasOwn(property, 'required') && property.required !== true) { authorError(`${path}.${key}.required must be true when present`) } - properties[key] = compileValueSchema(property, `${path}.${key}`, seen, true) + Object.defineProperty(properties, key, { + value: compileValueSchema(property, `${path}.${key}`, seen, true), + enumerable: true, + configurable: true, + writable: true, + }) if (property.required === true) required.push(key) } return required.length > 0 ? { properties, required } : { properties } diff --git a/packages/core/tools/tests/json-schema.spec.ts b/packages/core/tools/tests/json-schema.spec.ts index 26124083a9..96feb9b63d 100644 --- a/packages/core/tools/tests/json-schema.spec.ts +++ b/packages/core/tools/tests/json-schema.spec.ts @@ -160,6 +160,8 @@ describe('the enforced raw JSON Schema subset', () => { .toEqual(['schema.const must be a boolean value']) expect(violationsOf({ type: 'string', enum: undefined })) .toEqual(['schema.enum must be a non-empty array of string values']) + expect(violationsOf({ type: 'string', enum: ['a'], const: 'b' })) + .toEqual(['schema.const must be one of schema.enum when both are declared']) }) it('validates annotation types and lossless JSON payloads', () => { @@ -267,6 +269,21 @@ describe('validateJsonSchemaValue', () => { .toEqual(['"value" must be an object']) }) + it('returns a violation instead of throwing for a container with a hostile getter', () => { + const value = Object.defineProperty({}, 'answer', { + enumerable: true, + get() { throw new Error('getter exploded') }, + }) + const schema = asserted({ + type: 'object', + properties: { answer: { type: 'integer' } }, + required: ['answer'], + }) + + expect(validateJsonSchemaValue(schema, value)) + .toEqual(['"value" must be a lossless JSON value']) + }) + it('validates dense arrays per index and rejects lossy arrays', () => { const schema = asserted({ type: 'array', items: { type: 'integer' } }) expect(validateJsonSchemaValue(schema, [1, 2])).toEqual([]) diff --git a/packages/core/tools/tests/schema.spec.ts b/packages/core/tools/tests/schema.spec.ts index 5bbd5b8b6d..8de826aade 100644 --- a/packages/core/tools/tests/schema.spec.ts +++ b/packages/core/tools/tests/schema.spec.ts @@ -62,6 +62,7 @@ describe('the unified author schema DSL', () => { { type: 'object' }, { oneOf: [{ type: 'string' }] }, { type: 'number', enum: ['1'] }, + { type: 'string', enum: ['a'], const: 'b' }, { type: 'integer', const: 1.5 }, { type: 'json', default: undefined }, { type: 'array', items: { type: 'string', required: true } }, @@ -91,6 +92,17 @@ describe('the unified author schema DSL', () => { expect(() => parameterSchemaSpecToJsonSchema(properties as ParameterSchemaSpec)).toThrow(/circular/) }) + it('preserves a property literally named __proto__ as schema data', () => { + const properties = Object.create(null) as ParameterSchemaSpec + properties.__proto__ = { type: 'string', required: true } + + const schema = parameterSchemaSpecToJsonSchema(properties) + + expect(Object.hasOwn(schema.properties, '__proto__')).toBe(true) + expect(schema.properties.__proto__).toEqual({ type: 'string' }) + expect(schema.required).toEqual(['__proto__']) + }) + it('infers scalar literals, arrays, objects, json, and exact-one unions', () => { expectTypeOf<InferValue<{ type: 'string'; enum: readonly ['a', 'b'] }>>().toEqualTypeOf<'a' | 'b'>() expectTypeOf<InferValue<{ type: 'number'; const: 1 }>>().toEqualTypeOf<1>() diff --git a/packages/workflow/tool-workflow/src/index.ts b/packages/workflow/tool-workflow/src/index.ts index 71121730e5..0fcdc77786 100644 --- a/packages/workflow/tool-workflow/src/index.ts +++ b/packages/workflow/tool-workflow/src/index.ts @@ -47,7 +47,7 @@ const DESCRIPTION = `Run a JavaScript workflow script that orchestrates subagent The workflow's identity rides the \`meta\` parameter as JSON: required \`name\` (short kebab-case) and \`description\` strings, optional \`whenToUse\` string and \`phases\` array (\`{title, detail?, provider?, model?}\`). The \`script\` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO \`export const meta\` statement — meta is a parameter, not code), running with top-level await; end with \`return <value>\` — the value must be JSON-serializable and is this tool's result. Script-body hooks: -- \`agent(prompt, opts?): Promise<any>\` — run one subagent to completion. Without \`opts.schema\` it resolves to the child's final text; with \`opts.schema\` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves \`null\` when the child fails (filter with \`.filter(Boolean)\`). Other opts: \`label\` (display), \`phase\` (progress group), and independent \`provider\`/\`model\` LLM target overrides (either may be provided alone). Anything else (\`effort\`/\`isolation\`/\`agentType\`) is rejected loudly. +- \`agent(prompt, opts?): Promise<any>\` — run one subagent to completion. Without \`opts.schema\` it resolves to the child's final text; with \`opts.schema\` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves \`null\` when the child fails (filter with \`.filter(Boolean)\`). Other opts: \`label\` (display), \`phase\` (progress group), and independent \`provider\`/\`model\` LLM target overrides (either may be provided alone). Anything else (\`effort\`/\`isolation\`/\`agentType\`) is rejected loudly. - \`pipeline(items, ...stages): Promise<any[]>\` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives \`(prev, item, index)\`. An ordinary stage throw drops that ITEM to \`null\` and skips its remaining stages. - \`parallel(thunks): Promise<any[]>\` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to \`null\`. - \`phase(title)\` — start a progress phase; \`log(message)\` — narrate progress; \`args\` — the tool call's \`args\` input, verbatim. From e1633fbc3f2d332d59b1377efd395438d93f7104 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:03:01 +0800 Subject: [PATCH 030/368] fix(tools): preserve canonical output boundaries --- docs/config-catalog.md | 2 +- docs/cordis-catalog/services.md | 2 +- docs/core-data-structures/session.md | 15 +-- docs/persistence-catalog.md | 25 ++-- .../snapshots/cancel-tool-calls/session.jsonl | 4 +- .../escalation-rejected/session.jsonl | 2 +- .../snapshots/fs-policy-reject/session.jsonl | 2 +- .../hook-cc-posttool-block/session.jsonl | 2 +- .../hook-cc-pretool-ask/session.jsonl | 2 +- .../hook-cc-pretool-deny/session.jsonl | 2 +- .../hook-codex-posttool-block/session.jsonl | 2 +- .../hook-codex-pretool-block/session.jsonl | 2 +- .../session.2.jsonl | 2 +- .../tests/tool-result-prune.spec.ts | 4 +- .../cordis/tool-cordis/src/api-catalog.ts | 2 +- packages/core/agent-loop/src/tool-calls.ts | 2 +- packages/core/agent-loop/tests/cancel.spec.ts | 2 +- .../tests/contract-regressions.spec.ts | 4 +- .../core/agent-loop/tests/tool-calls.spec.ts | 16 +-- packages/core/session/README.md | 2 +- packages/core/session/src/repair.ts | 5 +- packages/core/session/src/types.ts | 15 +-- packages/core/session/tests/repair.spec.ts | 2 +- packages/core/tools/src/index.ts | 40 ++++++- packages/core/tools/tests/tools.spec.ts | 9 +- packages/fs/tool-fs/src/read-render.ts | 1 + packages/mcp/mcp-client/package.json | 6 +- packages/mcp/mcp-client/src/tools.ts | 69 +++++++---- .../mcp/mcp-client/tests/mcp-client.spec.ts | 113 +++++++++++++++++- .../session-persistence/tests/contract.ts | 2 +- packages/support/invariants/src/index.ts | 2 +- .../invariants/tests/invariants.spec.ts | 6 +- pnpm-lock.yaml | 6 +- 33 files changed, 269 insertions(+), 103 deletions(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 47a9926575..6285eac69a 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -1303,7 +1303,7 @@ export interface Config { export type ToolPresentationMode = 'native' | 'code' | 'both' ``` -Source: [`packages/core/tools/src/index.ts:448`](../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:467`](../packages/core/tools/src/index.ts) ## `@deepseek-ai/dsh-tui` diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 53180d3621..e93d734d82 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -1361,7 +1361,7 @@ async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult> Types: [ScopeKey](../core-data-structures/scope.md) · [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolGuard](../core-data-structures/tools.md) · [ToolRestriction](../core-data-structures/tools.md) · [ToolSchema](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:504`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:523`](../../packages/core/tools/src/index.ts) ## `ctx.userInteraction` — `UserInteractionService` diff --git a/docs/core-data-structures/session.md b/docs/core-data-structures/session.md index 2df677790b..b8f2d64136 100644 --- a/docs/core-data-structures/session.md +++ b/docs/core-data-structures/session.md @@ -73,12 +73,13 @@ interface SessionEventMap { */ 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string } /** - * A completed tool call's model-facing result, canonical failure detail, and - * optional tool-private `meta` presentation payload. `meta` is opaque to the - * core (the producing tool owns its shape and reads it back in `presentResult`) - * but MUST be JSON-serializable: `Session.append` runtime-validates all event - * data with `isJsonValue`, so a non-serializable `meta` is rejected at the - * source, and the durable log reproduces the identical card on replay. Absent + * A completed tool call's model-facing result, optional internal failure + * identity, and optional tool-private `meta` presentation payload. `meta` is + * opaque to the core (the producing tool owns its shape and reads it back in + * `presentResult`) but MUST be JSON-serializable: `Session.append` + * runtime-validates all event data with `isJsonValue`, so a non-serializable + * `meta` is rejected at the source, and the durable log reproduces the + * identical card on replay. Absent * unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time * contextual diff here). */ @@ -88,7 +89,7 @@ interface SessionEventMap { callId: CallId content: ContentBlock[] isError: boolean - error?: { message: string; info?: { name: string; code: string } } + error?: { name: string; code: string } meta?: JsonValue } /** Steering content injected between steps of a running turn. */ diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md index 9ca545854c..f310c22c44 100644 --- a/docs/persistence-catalog.md +++ b/docs/persistence-catalog.md @@ -79,7 +79,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = { }[T] ``` -Sources: [`packages/core/session/src/types.ts:276`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:283`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:313`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:345`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:277`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:284`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:314`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:346`](../packages/core/session/src/types.ts) ## Events @@ -356,7 +356,7 @@ Source: [`packages/core/session/src/types.ts:213`](../packages/core/session/src/ 'request/header': { header: EpochHeader; reason: RequestHeaderReason } ``` -Source: [`packages/core/session/src/types.ts:272`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:273`](../packages/core/session/src/types.ts) ### `sandbox/*` @@ -387,7 +387,7 @@ Source: [`packages/sandbox/sandbox-policy/src/session-mode.ts:34`](../packages/s Types: [ContentBlock](core-data-structures/core.md) · [MessageSource](core-data-structures/core.md) -Source: [`packages/core/session/src/types.ts:265`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:266`](../packages/core/session/src/types.ts) ### `step/*` @@ -420,7 +420,7 @@ Source: [`packages/core/session/src/types.ts:204`](../packages/core/session/src/ Types: [TodoItem](core-data-structures/session.md) -Source: [`packages/core/session/src/types.ts:267`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:268`](../packages/core/session/src/types.ts) ### `tool/*` @@ -468,12 +468,13 @@ Source: [`packages/core/tools/src/code-mode.ts:34`](../packages/core/tools/src/c ```ts persistence-catalog /** - * A completed tool call's model-facing result, canonical failure detail, and - * optional tool-private `meta` presentation payload. `meta` is opaque to the - * core (the producing tool owns its shape and reads it back in `presentResult`) - * but MUST be JSON-serializable: `Session.append` runtime-validates all event - * data with `isJsonValue`, so a non-serializable `meta` is rejected at the - * source, and the durable log reproduces the identical card on replay. Absent + * A completed tool call's model-facing result, optional internal failure + * identity, and optional tool-private `meta` presentation payload. `meta` is + * opaque to the core (the producing tool owns its shape and reads it back in + * `presentResult`) but MUST be JSON-serializable: `Session.append` + * runtime-validates all event data with `isJsonValue`, so a non-serializable + * `meta` is rejected at the source, and the durable log reproduces the + * identical card on replay. Absent * unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time * contextual diff here). */ @@ -483,14 +484,14 @@ Source: [`packages/core/tools/src/code-mode.ts:34`](../packages/core/tools/src/c callId: CallId content: ContentBlock[] isError: boolean - error?: { message: string; info?: { name: string; code: string } } + error?: { name: string; code: string } meta?: JsonValue } ``` Types: [CallId](core-data-structures/core.md) · [ContentBlock](core-data-structures/core.md) -Source: [`packages/core/session/src/types.ts:255`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:256`](../packages/core/session/src/types.ts) ### `turn/*` diff --git a/examples/acp-agent/tests/snapshots/cancel-tool-calls/session.jsonl b/examples/acp-agent/tests/snapshots/cancel-tool-calls/session.jsonl index db08475efd..cdb76be163 100644 --- a/examples/acp-agent/tests/snapshots/cancel-tool-calls/session.jsonl +++ b/examples/acp-agent/tests/snapshots/cancel-tool-calls/session.jsonl @@ -13,8 +13,8 @@ {"type":"assistant/chunk","seq":11,"time":1784437195077,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":12,"time":1784437195078,"data":{"turn":1,"step":1,"content":[{"type":"tool-call","id":"call_wait","name":"bash","arguments":"{\"command\":\"node -e \\\"setInterval(() => {}, 1000)\\\"\",\"description\":\"Wait until cancellation\"}"},{"type":"tool-call","id":"call_skipped","name":"bash","arguments":"{\"command\":\"printf skipped > skipped.txt\",\"description\":\"Write skipped marker\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":10,"outputTokens":10}},"sourceEventSeqs":[4,5,6,7,8,9,10,11],"surfaceOp":"append"} {"type":"tool/call","seq":13,"time":1784437195078,"data":{"turn":1,"step":1,"callId":"call_wait","name":"bash","arguments":"{\"command\":\"node -e \\\"setInterval(() => {}, 1000)\\\"\",\"description\":\"Wait until cancellation\"}"}} -{"type":"tool/result","seq":14,"time":1784437195089,"data":{"turn":1,"step":1,"callId":"call_wait","content":[{"type":"text","text":"Error: command aborted"}],"isError":true,"error":{"message":"command aborted"}},"sourceEventSeqs":[13],"surfaceOp":"append"} +{"type":"tool/result","seq":14,"time":1784437195089,"data":{"turn":1,"step":1,"callId":"call_wait","content":[{"type":"text","text":"Error: command aborted"}],"isError":true},"sourceEventSeqs":[13],"surfaceOp":"append"} {"type":"tool/call","seq":15,"time":1784437195089,"data":{"turn":1,"step":1,"callId":"call_skipped","name":"bash","arguments":"{\"command\":\"printf skipped > skipped.txt\",\"description\":\"Write skipped marker\"}"}} -{"type":"tool/result","seq":16,"time":1784437195089,"data":{"turn":1,"step":1,"callId":"call_skipped","content":[{"type":"text","text":"Error: tool call skipped because the step was aborted before execution"}],"isError":true,"error":{"message":"tool call skipped because the step was aborted before execution","info":{"name":"AbortError","code":"ABORTED"}}},"sourceEventSeqs":[15],"surfaceOp":"append"} +{"type":"tool/result","seq":16,"time":1784437195089,"data":{"turn":1,"step":1,"callId":"call_skipped","content":[{"type":"text","text":"Error: tool call skipped because the step was aborted before execution"}],"isError":true,"error":{"name":"AbortError","code":"ABORTED"}},"sourceEventSeqs":[15],"surfaceOp":"append"} {"type":"step/end","seq":17,"time":1784437195090,"data":{"turn":1,"step":1}} {"type":"turn/end","seq":18,"time":1784437195090,"data":{"turn":1,"reason":{"kind":"aborted","reason":"session/cancel"}}} diff --git a/examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl b/examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl index 4190704a7f..ff6d1187b3 100644 --- a/examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl +++ b/examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl @@ -157,7 +157,7 @@ {"type":"tool/call","seq":155,"time":1783962246274,"data":{"turn":1,"step":1,"callId":"call_00_WB1vnPomi8yr6MlcFKTj7912","name":"bash","arguments":"{\"command\": \"printf 'escalated\\\\n' > /tmp/dsh-escalated.txt && cat /tmp/dsh-escalated.txt && rm /tmp/dsh-escalated.txt\", \"description\": \"Write to /tmp and verify, then clean up\", \"sandbox_permissions\": \"danger-full-access\", \"justification\": \"the user asked to write a file outside the workspace\"}"}} {"type":"approval/asked","seq":156,"time":1783962246275,"data":{"id":"46c8dba4-52c9-4a6a-b6a6-5f34c95c28df","toolName":"bash","callId":"call_00_WB1vnPomi8yr6MlcFKTj7912","reason":"escalate sandbox to danger-full-access: the user asked to write a file outside the workspace"}} {"type":"approval/decided","seq":157,"time":1783962246275,"data":{"id":"46c8dba4-52c9-4a6a-b6a6-5f34c95c28df","outcome":"rejected"}} -{"type":"tool/result","seq":158,"time":1783962246275,"data":{"turn":1,"step":1,"callId":"call_00_WB1vnPomi8yr6MlcFKTj7912","content":[{"type":"text","text":"Error: the user rejected escalating this command to \"danger-full-access\""}],"isError":true,"error":{"message":"the user rejected escalating this command to \"danger-full-access\""}},"sourceEventSeqs":[155],"surfaceOp":"append"} +{"type":"tool/result","seq":158,"time":1783962246275,"data":{"turn":1,"step":1,"callId":"call_00_WB1vnPomi8yr6MlcFKTj7912","content":[{"type":"text","text":"Error: the user rejected escalating this command to \"danger-full-access\""}],"isError":true},"sourceEventSeqs":[155],"surfaceOp":"append"} {"type":"step/end","seq":159,"time":1783962246276,"data":{"turn":1,"step":1}} {"type":"step/start","seq":160,"time":1783962246276,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":161,"time":1783860683140,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl b/examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl index 5b1ccd60fc..66efd5f934 100644 --- a/examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl +++ b/examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl @@ -77,7 +77,7 @@ {"type":"assistant/chunk","seq":75,"time":1783611703969,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":76,"time":1783611703972,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to use the edit tool to replace \"blue\" with \"green\" in settings.txt without reading the file first, and then reply with just \"DONE\"."},{"type":"tool-call","id":"call_00_x0zlnXl5JOxLrAYL9y7P0119","name":"edit","arguments":"{\"file_path\": \"settings.txt\", \"old_string\": \"blue\", \"new_string\": \"green\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3132,"outputTokens":115,"cacheReadTokens":0,"reasoningTokens":36}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75],"surfaceOp":"append"} {"type":"tool/call","seq":77,"time":1783611703972,"data":{"turn":1,"step":1,"callId":"call_00_x0zlnXl5JOxLrAYL9y7P0119","name":"edit","arguments":"{\"file_path\": \"settings.txt\", \"old_string\": \"blue\", \"new_string\": \"green\"}"}} -{"type":"tool/result","seq":78,"time":1783611703978,"data":{"turn":1,"step":1,"callId":"call_00_x0zlnXl5JOxLrAYL9y7P0119","content":[{"type":"text","text":"Error: edit requires reading \"/var/folders/2c/psb0_fmx7hbgz558xjt_f0l00000gn/T/acp-snap-cwd-QzoqnB/settings.txt\" first"}],"isError":true,"error":{"message":"edit requires reading \"/var/folders/2c/psb0_fmx7hbgz558xjt_f0l00000gn/T/acp-snap-cwd-QzoqnB/settings.txt\" first","info":{"name":"FsError","code":"FS_NOT_OBSERVED"}}},"sourceEventSeqs":[77],"surfaceOp":"append"} +{"type":"tool/result","seq":78,"time":1783611703978,"data":{"turn":1,"step":1,"callId":"call_00_x0zlnXl5JOxLrAYL9y7P0119","content":[{"type":"text","text":"Error: edit requires reading \"/var/folders/2c/psb0_fmx7hbgz558xjt_f0l00000gn/T/acp-snap-cwd-QzoqnB/settings.txt\" first"}],"isError":true,"error":{"name":"FsError","code":"FS_NOT_OBSERVED"}},"sourceEventSeqs":[77],"surfaceOp":"append"} {"type":"step/end","seq":79,"time":1783611703978,"data":{"turn":1,"step":1}} {"type":"step/start","seq":80,"time":1783611703978,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":81,"time":1783611704825,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl b/examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl index 8cab55c391..c362de7a26 100644 --- a/examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl +++ b/examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl @@ -75,7 +75,7 @@ {"type":"tool/call","seq":73,"time":1783962505993,"data":{"turn":1,"step":1,"callId":"call_00_VAByyMjsct4c7P6k1ysX9256","name":"bash","arguments":"{\"command\": \"echo HELLO\", \"description\": \"Echo HELLO to stdout\"}"}} {"type":"hook/invoked","seq":74,"time":1783962506001,"data":{"turn":1,"point":"PostToolUse","dialect":"claude","handlerId":"claude:PostToolUse:1","matcher":"bash"}} {"type":"hook/result","seq":75,"time":1783962506011,"data":{"turn":1,"point":"PostToolUse","handlerId":"claude:PostToolUse:1","decision":"block","exitCode":2,"stderrSummary":"tool output rejected by policy: retry once","durationMs":9.922291999999743}} -{"type":"tool/result","seq":76,"time":1783962506011,"data":{"turn":1,"step":1,"callId":"call_00_VAByyMjsct4c7P6k1ysX9256","content":[{"type":"text","text":"tool output rejected by policy: retry once"}],"isError":true,"error":{"message":"tool output rejected by policy: retry once"}},"sourceEventSeqs":[73],"surfaceOp":"append"} +{"type":"tool/result","seq":76,"time":1783962506011,"data":{"turn":1,"step":1,"callId":"call_00_VAByyMjsct4c7P6k1ysX9256","content":[{"type":"text","text":"tool output rejected by policy: retry once"}],"isError":true},"sourceEventSeqs":[73],"surfaceOp":"append"} {"type":"step/end","seq":77,"time":1783962506012,"data":{"turn":1,"step":1}} {"type":"step/start","seq":78,"time":1783962506012,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":79,"time":1783962507038,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl b/examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl index 1309b5c30d..247e13a075 100644 --- a/examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl +++ b/examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl @@ -57,7 +57,7 @@ {"type":"hook/result","seq":55,"time":1783352172573,"data":{"turn":1,"point":"PreToolUse","handlerId":"claude:PreToolUse:1","decision":"ask","exitCode":0,"durationMs":14.113374999999905}} {"type":"approval/asked","seq":56,"time":1783962235813,"data":{"id":"68f1e09d-f3e5-4e39-8a51-da082ba3ba99","toolName":"bash","callId":"call_00_6k0oGSliVHxGSgqBmMEO4311","reason":"bash requires manual approval in this session"}} {"type":"approval/decided","seq":57,"time":1783962235813,"data":{"id":"68f1e09d-f3e5-4e39-8a51-da082ba3ba99","outcome":"rejected"}} -{"type":"tool/result","seq":58,"time":1783962235814,"data":{"turn":1,"step":1,"callId":"call_00_6k0oGSliVHxGSgqBmMEO4311","content":[{"type":"text","text":"Error: the user rejected tool \"bash\""}],"isError":true,"error":{"message":"the user rejected tool \"bash\""}},"sourceEventSeqs":[53],"surfaceOp":"append"} +{"type":"tool/result","seq":58,"time":1783962235814,"data":{"turn":1,"step":1,"callId":"call_00_6k0oGSliVHxGSgqBmMEO4311","content":[{"type":"text","text":"Error: the user rejected tool \"bash\""}],"isError":true},"sourceEventSeqs":[53],"surfaceOp":"append"} {"type":"step/end","seq":59,"time":1783962235814,"data":{"turn":1,"step":1}} {"type":"step/start","seq":60,"time":1783962235814,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":61,"time":1783352173584,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl b/examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl index 869fca1eca..4193c7fe80 100644 --- a/examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl +++ b/examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl @@ -55,7 +55,7 @@ {"type":"tool/call","seq":53,"time":1783352166514,"data":{"turn":1,"step":1,"callId":"call_00_JliP571Bh0QQ8QExbSPk0080","name":"bash","arguments":"{\"command\": \"echo HELLO\", \"description\": \"Run echo HELLO\"}"}} {"type":"hook/invoked","seq":54,"time":1783352166515,"data":{"turn":1,"point":"PreToolUse","dialect":"claude","handlerId":"claude:PreToolUse:1","matcher":"bash"}} {"type":"hook/result","seq":55,"time":1783352166528,"data":{"turn":1,"point":"PreToolUse","handlerId":"claude:PreToolUse:1","decision":"block","exitCode":2,"stderrSummary":"bash is disabled by policy in this session","durationMs":12.367074000000684}} -{"type":"tool/result","seq":56,"time":1783352166528,"data":{"turn":1,"step":1,"callId":"call_00_JliP571Bh0QQ8QExbSPk0080","content":[{"type":"text","text":"Error: bash is disabled by policy in this session"}],"isError":true,"error":{"message":"bash is disabled by policy in this session"}},"sourceEventSeqs":[53],"surfaceOp":"append"} +{"type":"tool/result","seq":56,"time":1783352166528,"data":{"turn":1,"step":1,"callId":"call_00_JliP571Bh0QQ8QExbSPk0080","content":[{"type":"text","text":"Error: bash is disabled by policy in this session"}],"isError":true},"sourceEventSeqs":[53],"surfaceOp":"append"} {"type":"step/end","seq":57,"time":1783352166529,"data":{"turn":1,"step":1}} {"type":"step/start","seq":58,"time":1783352166529,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":59,"time":1783352167307,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl b/examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl index 4a05a2daa7..dc68891c14 100644 --- a/examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl +++ b/examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl @@ -66,7 +66,7 @@ {"type":"tool/call","seq":64,"time":1783986963664,"data":{"turn":1,"step":1,"callId":"call_00_1rmSWHhVchVg7PDTmegT0421","name":"bash","arguments":"{\"command\": \"echo HELLO\", \"description\": \"Echo HELLO to stdout\"}"}} {"type":"hook/invoked","seq":65,"time":1783986963673,"data":{"turn":1,"point":"PostToolUse","dialect":"codex","handlerId":"codex:PostToolUse:1","matcher":"bash"}} {"type":"hook/result","seq":66,"time":1783986963677,"data":{"turn":1,"point":"PostToolUse","handlerId":"codex:PostToolUse:1","decision":"block","exitCode":2,"stderrSummary":"tool output rejected by codex policy: summarize instead","durationMs":4.42941699999983}} -{"type":"tool/result","seq":67,"time":1783986963678,"data":{"turn":1,"step":1,"callId":"call_00_1rmSWHhVchVg7PDTmegT0421","content":[{"type":"text","text":"tool output rejected by codex policy: summarize instead"}],"isError":true,"error":{"message":"tool output rejected by codex policy: summarize instead"}},"sourceEventSeqs":[64],"surfaceOp":"append"} +{"type":"tool/result","seq":67,"time":1783986963678,"data":{"turn":1,"step":1,"callId":"call_00_1rmSWHhVchVg7PDTmegT0421","content":[{"type":"text","text":"tool output rejected by codex policy: summarize instead"}],"isError":true},"sourceEventSeqs":[64],"surfaceOp":"append"} {"type":"step/end","seq":68,"time":1783986963678,"data":{"turn":1,"step":1}} {"type":"step/start","seq":69,"time":1783986963679,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":70,"time":1783986964555,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl b/examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl index eb928d7dff..c2675ae3af 100644 --- a/examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl +++ b/examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl @@ -55,7 +55,7 @@ {"type":"tool/call","seq":53,"time":1783352215804,"data":{"turn":1,"step":1,"callId":"call_00_tv0SMeLXaTuyuVrOxnV97085","name":"bash","arguments":"{\"command\": \"echo HELLO\", \"description\": \"Run echo HELLO\"}"}} {"type":"hook/invoked","seq":54,"time":1783352215805,"data":{"turn":1,"point":"PreToolUse","dialect":"codex","handlerId":"codex:PreToolUse:1","matcher":"bash"}} {"type":"hook/result","seq":55,"time":1783352215832,"data":{"turn":1,"point":"PreToolUse","handlerId":"codex:PreToolUse:1","decision":"block","exitCode":2,"stderrSummary":"bash is disabled by codex policy in this session","durationMs":26.08518500000082}} -{"type":"tool/result","seq":56,"time":1783352215832,"data":{"turn":1,"step":1,"callId":"call_00_tv0SMeLXaTuyuVrOxnV97085","content":[{"type":"text","text":"Error: bash is disabled by codex policy in this session"}],"isError":true,"error":{"message":"bash is disabled by codex policy in this session"}},"sourceEventSeqs":[53],"surfaceOp":"append"} +{"type":"tool/result","seq":56,"time":1783352215832,"data":{"turn":1,"step":1,"callId":"call_00_tv0SMeLXaTuyuVrOxnV97085","content":[{"type":"text","text":"Error: bash is disabled by codex policy in this session"}],"isError":true},"sourceEventSeqs":[53],"surfaceOp":"append"} {"type":"step/end","seq":57,"time":1783352215833,"data":{"turn":1,"step":1}} {"type":"step/start","seq":58,"time":1783352215834,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":59,"time":1783352216779,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.2.jsonl b/examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.2.jsonl index ed8f566219..7b36136970 100644 --- a/examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.2.jsonl +++ b/examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/session.2.jsonl @@ -10,7 +10,7 @@ {"type":"assistant/chunk","seq":8,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":9,"time":1784540790335,"data":{"turn":1,"step":1,"content":[{"type":"tool-call","id":"call_depth_three_rejected","name":"subagent","arguments":"{\"description\":\"Exceed depth cap\",\"prompt\":\"This child must never start.\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":10,"outputTokens":5}},"sourceEventSeqs":[4,5,6,7,8],"surfaceOp":"append"} {"type":"tool/call","seq":10,"time":1784540790335,"data":{"turn":1,"step":1,"callId":"call_depth_three_rejected","name":"subagent","arguments":"{\"description\":\"Exceed depth cap\",\"prompt\":\"This child must never start.\"}"}} -{"type":"tool/result","seq":11,"time":1784540790337,"data":{"turn":1,"step":1,"callId":"call_depth_three_rejected","content":[{"type":"text","text":"Error: subagent depth 3 exceeds maxDepth 2"}],"isError":true,"error":{"message":"subagent depth 3 exceeds maxDepth 2"}},"sourceEventSeqs":[10],"surfaceOp":"append"} +{"type":"tool/result","seq":11,"time":1784540790337,"data":{"turn":1,"step":1,"callId":"call_depth_three_rejected","content":[{"type":"text","text":"Error: subagent depth 3 exceeds maxDepth 2"}],"isError":true},"sourceEventSeqs":[10],"surfaceOp":"append"} {"type":"step/end","seq":12,"time":1784540790338,"data":{"turn":1,"step":1}} {"type":"step/start","seq":13,"time":1784540790338,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":14,"time":1784540790339,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"text"}}} diff --git a/packages/compact/compact-tool-result-prune/tests/tool-result-prune.spec.ts b/packages/compact/compact-tool-result-prune/tests/tool-result-prune.spec.ts index 0d3478b1c0..bc382c8e4e 100644 --- a/packages/compact/compact-tool-result-prune/tests/tool-result-prune.spec.ts +++ b/packages/compact/compact-tool-result-prune/tests/tool-result-prune.spec.ts @@ -151,7 +151,7 @@ describe('ToolResultPruneService session transaction', () => { text: 'x'.repeat(100), }], { isError: true, - error: { message: 'exit 1', info: { name: 'ExitError', code: 'EXIT_1' } }, + error: { name: 'ExitError', code: 'EXIT_1' }, meta: { diff: ['a', 'b'] }, futureField: { nested: true }, }) @@ -180,7 +180,7 @@ describe('ToolResultPruneService session transaction', () => { step: 1, callId: CallId('one'), isError: true, - error: { message: 'exit 1', info: { name: 'ExitError', code: 'EXIT_1' } }, + error: { name: 'ExitError', code: 'EXIT_1' }, meta: { diff: ['a', 'b'] }, futureField: { nested: true }, }, diff --git a/packages/cordis/tool-cordis/src/api-catalog.ts b/packages/cordis/tool-cordis/src/api-catalog.ts index e8ddc86f83..1537aa5960 100644 --- a/packages/cordis/tool-cordis/src/api-catalog.ts +++ b/packages/cordis/tool-cordis/src/api-catalog.ts @@ -1450,7 +1450,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'SessionEventMap', - declaration: 'export interface SessionEventMap {\n \'turn/start\': {\n turn: number;\n trigger: TurnTrigger;\n };\n \'turn/end\': {\n turn: number;\n reason: TurnEndReason;\n };\n \'step/start\': {\n turn: number;\n step: number;\n };\n \'step/end\': {\n turn: number;\n step: number;\n };\n \'user/message\': {\n content: ContentBlock[];\n source: MessageSource;\n };\n \'prompt/blocked\': {\n content: ContentBlock[];\n source: MessageSource;\n reason: string;\n };\n \'context/message\': {\n content: ContentBlock[];\n source: MessageSource;\n meta?: JsonValue;\n };\n \'assistant/chunk\': {\n turn: number;\n step: number;\n chunk: StreamChunk;\n };\n \'assistant/message\': {\n turn: number;\n step: number;\n content: ContentBlock[];\n provenance: AssistantProvenance;\n usage?: TokenUsage;\n };\n \'tool/call\': {\n turn: number;\n step: number;\n callId: CallId;\n name: string;\n arguments: string;\n };\n \'tool/result\': {\n turn: number;\n step: number;\n callId: CallId;\n content: ContentBlock[];\n isError: boolean;\n error?: {\n message: string;\n info?: {\n name: string;\n code: string;\n };\n };\n meta?: JsonValue;\n };\n \'steering/message\': {\n turn: number;\n content: Content /* …truncated — full shape in source */', + declaration: 'export interface SessionEventMap {\n \'turn/start\': {\n turn: number;\n trigger: TurnTrigger;\n };\n \'turn/end\': {\n turn: number;\n reason: TurnEndReason;\n };\n \'step/start\': {\n turn: number;\n step: number;\n };\n \'step/end\': {\n turn: number;\n step: number;\n };\n \'user/message\': {\n content: ContentBlock[];\n source: MessageSource;\n };\n \'prompt/blocked\': {\n content: ContentBlock[];\n source: MessageSource;\n reason: string;\n };\n \'context/message\': {\n content: ContentBlock[];\n source: MessageSource;\n meta?: JsonValue;\n };\n \'assistant/chunk\': {\n turn: number;\n step: number;\n chunk: StreamChunk;\n };\n \'assistant/message\': {\n turn: number;\n step: number;\n content: ContentBlock[];\n provenance: AssistantProvenance;\n usage?: TokenUsage;\n };\n \'tool/call\': {\n turn: number;\n step: number;\n callId: CallId;\n name: string;\n arguments: string;\n };\n \'tool/result\': {\n turn: number;\n step: number;\n callId: CallId;\n content: ContentBlock[];\n isError: boolean;\n error?: {\n name: string;\n code: string;\n };\n meta?: JsonValue;\n };\n \'steering/message\': {\n turn: number;\n content: ContentBlock[];\n source: MessageSource;\n };\n \'todo/write\': {\n /* …truncated — full shape in source */', }, { name: 'SessionEventReadRequest', diff --git a/packages/core/agent-loop/src/tool-calls.ts b/packages/core/agent-loop/src/tool-calls.ts index 61a6d37947..e9a255dbce 100644 --- a/packages/core/agent-loop/src/tool-calls.ts +++ b/packages/core/agent-loop/src/tool-calls.ts @@ -248,7 +248,7 @@ function appendToolResult( callId: block.id, content: result.content, isError: result.isError, - ...result.error ? { error: result.error } : {}, + ...result.error?.info ? { error: result.error.info } : {}, // The tool's private presentation payload (e.g. a result-time diff), // persisted so a UI bridge reproduces the card on replay. ...result.meta !== undefined ? { meta: result.meta } : {}, diff --git a/packages/core/agent-loop/tests/cancel.spec.ts b/packages/core/agent-loop/tests/cancel.spec.ts index 301ebbf992..784855262b 100644 --- a/packages/core/agent-loop/tests/cancel.spec.ts +++ b/packages/core/agent-loop/tests/cancel.spec.ts @@ -397,7 +397,7 @@ describe('Agent.cancel()', () => { expect(result?.type === 'tool/result' ? result.data : undefined).toMatchObject({ callId: 'c1', isError: true, - error: { info: { name: 'AbortError', code: 'ABORTED' } }, + error: { name: 'AbortError', code: 'ABORTED' }, }) send(agent, 'continue safely') diff --git a/packages/core/agent-loop/tests/contract-regressions.spec.ts b/packages/core/agent-loop/tests/contract-regressions.spec.ts index 17f12de400..97bf57ad72 100644 --- a/packages/core/agent-loop/tests/contract-regressions.spec.ts +++ b/packages/core/agent-loop/tests/contract-regressions.spec.ts @@ -259,7 +259,7 @@ describe('abort during tool execution ends the turn', () => { case 'assistant/message': order.push('assistant/message'); break case 'tool/call': order.push(`tool/call:${event.data.callId}`); break case 'tool/result': { - const outcome = event.data.error?.info?.code === 'ABORTED' ? 'synthetic-aborted' : 'real' + const outcome = event.data.error?.code === 'ABORTED' ? 'synthetic-aborted' : 'real' order.push(`tool/result:${event.data.callId}:${outcome}`) break } @@ -308,7 +308,7 @@ describe('abort during tool execution ends the turn', () => { expect(results[1]!.data).toMatchObject({ callId: CallId('c2'), isError: true, - error: { info: { name: 'AbortError', code: 'ABORTED' } }, + error: { name: 'AbortError', code: 'ABORTED' }, }) }) diff --git a/packages/core/agent-loop/tests/tool-calls.spec.ts b/packages/core/agent-loop/tests/tool-calls.spec.ts index e13caa13c5..0d6d20b287 100644 --- a/packages/core/agent-loop/tests/tool-calls.spec.ts +++ b/packages/core/agent-loop/tests/tool-calls.spec.ts @@ -479,18 +479,12 @@ describe('tool-call scheduler: abort handling', () => { { callId: CallId('c1'), isError: true, - error: { - message: 'tool call skipped because the step was aborted before execution', - info: { name: 'AbortError', code: 'ABORTED' }, - }, + error: { name: 'AbortError', code: 'ABORTED' }, }, { callId: CallId('c2'), isError: true, - error: { - message: 'tool call skipped because the step was aborted before execution', - info: { name: 'AbortError', code: 'ABORTED' }, - }, + error: { name: 'AbortError', code: 'ABORTED' }, }, ]) }) @@ -523,7 +517,7 @@ describe('tool-call scheduler: abort handling', () => { expect(events(agent).filter(e => e.type === 'tool/result').map(e => e.data.callId)) .toEqual([CallId('c1'), CallId('c2')]) expect(events(agent).filter(e => e.type === 'tool/result').at(-1)?.data) - .toMatchObject({ callId: CallId('c2'), isError: true, error: { info: { name: 'AbortError', code: 'ABORTED' } } }) + .toMatchObject({ callId: CallId('c2'), isError: true, error: { name: 'AbortError', code: 'ABORTED' } }) }) it('stops replenishing after abort, commits started results, and drains accepted additional contexts', async () => { @@ -555,7 +549,7 @@ describe('tool-call scheduler: abort handling', () => { expect(events(agent).filter(e => e.type === 'tool/result').slice(-2).map(e => ({ callId: e.data.callId, isError: e.data.isError, - errorInfo: e.data.error?.info, + errorInfo: e.data.error, }))) .toEqual([ { callId: CallId('c3'), isError: true, errorInfo: { name: 'AbortError', code: 'ABORTED' } }, @@ -601,6 +595,6 @@ describe('tool-call scheduler: abort handling', () => { expect(events(agent).filter(e => e.type === 'tool/call').map(e => e.data.callId)) .toEqual([CallId('c1'), CallId('c2'), CallId('c3')]) expect(events(agent).filter(e => e.type === 'tool/result').at(-1)?.data) - .toMatchObject({ callId: CallId('c3'), isError: true, error: { info: { name: 'AbortError', code: 'ABORTED' } } }) + .toMatchObject({ callId: CallId('c3'), isError: true, error: { name: 'AbortError', code: 'ABORTED' } }) }) }) diff --git a/packages/core/session/README.md b/packages/core/session/README.md index aaf1d429ee..107eaf25bf 100644 --- a/packages/core/session/README.md +++ b/packages/core/session/README.md @@ -58,7 +58,7 @@ Durable values need one accepted representation, not a check followed by a secon `context/message` renders its `content` verbatim as a user-role message, and may attach JSON `meta` for replayable plugin state; metadata remains durable but is excluded from `deriveMessages()`. -`tool/result` persists the model-facing content, canonical failure detail, and optional presentation metadata. A tool's successful canonical `value` is deliberately execution-local and never enters the session event, so replay reconstructs the Native/model presentation but cannot recover intermediate programmatic values. This does not change `SESSION_FORMAT_VERSION`: the persisted projection remains authoritative. +`tool/result` persists the model-facing content, optional internal failure identity, and optional presentation metadata. A tool's successful canonical `value` and human-readable canonical failure message remain execution-local; rendered error content is the replay-authoritative message. This preserves the existing event shape and does not change `SESSION_FORMAT_VERSION`. ### Session event vocabulary (`types.ts`) diff --git a/packages/core/session/src/repair.ts b/packages/core/session/src/repair.ts index fa3b8bbb50..efbb3d2004 100644 --- a/packages/core/session/src/repair.ts +++ b/packages/core/session/src/repair.ts @@ -92,10 +92,7 @@ export function interruptedTurnClosers(events: readonly SessionEvent[]): Session callId, content: [{ type: 'text', text: 'Tool call interrupted by a crash; no result was recorded.' }], isError: true, - error: { - message: 'Tool call interrupted by a crash; no result was recorded.', - info: { name: 'InterruptedError', code: 'interrupted' }, - }, + error: { name: 'InterruptedError', code: 'interrupted' }, }, surfaceOp: 'append', ...callSeq !== undefined ? { sourceEventSeqs: [callSeq] } : {}, diff --git a/packages/core/session/src/types.ts b/packages/core/session/src/types.ts index cc7ea81ba1..0d253e9091 100644 --- a/packages/core/session/src/types.ts +++ b/packages/core/session/src/types.ts @@ -243,12 +243,13 @@ export interface SessionEventMap { */ 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string } /** - * A completed tool call's model-facing result, canonical failure detail, and - * optional tool-private `meta` presentation payload. `meta` is opaque to the - * core (the producing tool owns its shape and reads it back in `presentResult`) - * but MUST be JSON-serializable: `Session.append` runtime-validates all event - * data with `isJsonValue`, so a non-serializable `meta` is rejected at the - * source, and the durable log reproduces the identical card on replay. Absent + * A completed tool call's model-facing result, optional internal failure + * identity, and optional tool-private `meta` presentation payload. `meta` is + * opaque to the core (the producing tool owns its shape and reads it back in + * `presentResult`) but MUST be JSON-serializable: `Session.append` + * runtime-validates all event data with `isJsonValue`, so a non-serializable + * `meta` is rejected at the source, and the durable log reproduces the + * identical card on replay. Absent * unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time * contextual diff here). */ @@ -258,7 +259,7 @@ export interface SessionEventMap { callId: CallId content: ContentBlock[] isError: boolean - error?: { message: string; info?: { name: string; code: string } } + error?: { name: string; code: string } meta?: JsonValue } /** Steering content injected between steps of a running turn. */ diff --git a/packages/core/session/tests/repair.spec.ts b/packages/core/session/tests/repair.spec.ts index 826d410dc8..765502b8ce 100644 --- a/packages/core/session/tests/repair.spec.ts +++ b/packages/core/session/tests/repair.spec.ts @@ -64,7 +64,7 @@ describe('interruptedTurnClosers', () => { expect(closers.map(e => e.seq)).toEqual([3, 4, 5]) const result = closers[0]! expect(result.type === 'tool/result' && result.data).toMatchObject({ - turn: 2, step: 1, callId: CallId('call-1'), isError: true, error: { info: { code: 'interrupted' } }, + turn: 2, step: 1, callId: CallId('call-1'), isError: true, error: { code: 'interrupted' }, }) }) diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index f6fe38d4da..58b6824ada 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -349,6 +349,25 @@ export class ToolOutputError extends HarnessError { } } +/** Convert one projector exception into the canonical invalid-output failure. */ +function projectionError(toolName: string, projector: 'render' | 'presentationMeta', error: unknown): ToolOutputError { + return new ToolOutputError(toolName, [`output.${projector} failed: ${errorMessage(error)}`]) +} + +/** Snapshot one projector result before later durable-result materialization. */ +function snapshotProjection<T>(toolName: string, projector: 'render' | 'presentationMeta', candidate: T): T { + try { + const detached = snapshotJsonValue(candidate) + if (detached === undefined) { + throw new ToolOutputError(toolName, [`output.${projector} returned non-lossless JSON`]) + } + return detached + } catch (error: unknown) { + if (error instanceof ToolOutputError) throw error + throw projectionError(toolName, projector, error) + } +} + /** Successful canonical tool execution, including its Native/model projection. */ export interface ToolExecutionSuccess { readonly isError: false @@ -1156,10 +1175,23 @@ export class ToolRegistry extends Service { const violations = validateJsonSchemaValue(tool.output.schema, detached, 'value') if (violations.length > 0) throw new ToolOutputError(tool.name, violations) const value = deepFreeze(detached as JsonValue) - const content = tool.output.render(exec.arguments, value) - const meta = exec.parent === undefined && tool.output.presentationMeta !== undefined - ? tool.output.presentationMeta(exec.arguments, value) - : undefined + let rendered: ContentBlock[] + try { + rendered = tool.output.render(exec.arguments, value) + } catch (error: unknown) { + throw projectionError(tool.name, 'render', error) + } + const content = snapshotProjection(tool.name, 'render', rendered) + let meta: JsonValue | undefined + if (exec.parent === undefined && tool.output.presentationMeta !== undefined) { + let projected: JsonValue + try { + projected = tool.output.presentationMeta(exec.arguments, value) + } catch (error: unknown) { + throw projectionError(tool.name, 'presentationMeta', error) + } + meta = snapshotProjection(tool.name, 'presentationMeta', projected) + } return this.markCanonical(this.materializeFinalResult({ isError: false, value, diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index a8ccf384d5..d237430dda 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -147,6 +147,7 @@ describe('ToolRegistry', () => { }) expect(result.isError).toBe(true) expect(result.content[0]?.type === 'text' && result.content[0].text).toContain('Error:') + expect(result.error).toMatchObject({ info: { name: 'ToolOutputError', code: 'INVALID_TOOL_OUTPUT' } }) expect(observedError).toBe(true) }) @@ -209,10 +210,10 @@ describe('ToolRegistry', () => { })) const result = await ctx.tools.execute({ callId: CallId(projector), name: `throwing-${projector}`, arguments: {} }) - expect(result).toMatchObject({ - isError: true, - error: { message: projector === 'render' ? 'renderer exploded' : 'metadata exploded' }, - }) + expect(result.isError).toBe(true) + expect(result.error?.message) + .toContain(projector === 'render' ? 'renderer exploded' : 'metadata exploded') + expect(result.error?.info).toEqual({ name: 'ToolOutputError', code: 'INVALID_TOOL_OUTPUT' }) expect('value' in result).toBe(false) }) diff --git a/packages/fs/tool-fs/src/read-render.ts b/packages/fs/tool-fs/src/read-render.ts index de9e530a13..e30dad7bcd 100644 --- a/packages/fs/tool-fs/src/read-render.ts +++ b/packages/fs/tool-fs/src/read-render.ts @@ -138,6 +138,7 @@ export async function buildWindow( appendToLineBuffer(chunk.slice(startPos, newlinePos)) flushLine() startPos = newlinePos + 1 + if (acc.done) return finish(acc, request, displayPath) } appendToLineBuffer(chunk.slice(startPos)) } diff --git a/packages/mcp/mcp-client/package.json b/packages/mcp/mcp-client/package.json index 6b8f145108..ff34be015c 100644 --- a/packages/mcp/mcp-client/package.json +++ b/packages/mcp/mcp-client/package.json @@ -28,14 +28,14 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "^1.12.0", - "schemastery": "^3.18.0" + "schemastery": "^3.18.0", + "zod": "^4.4.3" }, "devDependencies": { "@deepseek-ai/dsh-tools": "workspace:^", "@deepseek-ai/dsh-llm": "workspace:^", "@modelcontextprotocol/server-everything": "^2026.7.4", "@modelcontextprotocol/server-filesystem": "^2026.7.4", - "cordis": "^4.0.0-rc.7", - "zod": "^4.4.3" + "cordis": "^4.0.0-rc.7" } } diff --git a/packages/mcp/mcp-client/src/tools.ts b/packages/mcp/mcp-client/src/tools.ts index 1a8eabf416..be0c6ebea7 100644 --- a/packages/mcp/mcp-client/src/tools.ts +++ b/packages/mcp/mcp-client/src/tools.ts @@ -14,6 +14,8 @@ import { createHash } from 'node:crypto' import type { Client } from '@modelcontextprotocol/sdk/client/index.js' +import { ListToolsResultSchema } from '@modelcontextprotocol/sdk/types.js' +import { z } from 'zod' import type { Context } from 'cordis' import type { ToolDefinition, ToolExecution } from '@deepseek-ai/dsh-tools' import { assertSupportedJsonSchema } from '@deepseek-ai/dsh-tools' @@ -46,6 +48,35 @@ const INVALID_NAME_CHARS = /[^A-Za-z0-9_-]/g /** Hex chars of the SHA-256 identity hash appended on lossy normalization. */ const HASH_LENGTH = 12 +/** Raw result record: the bridge owns JSON-value validation after transport. */ +const RawCallToolResultSchema = z.record(z.string(), z.unknown()) + +/** List without mutating the SDK's per-page output-validator cache. */ +function listToolsUncached(client: Client, cursor?: string) { + return client.request( + { method: 'tools/list', ...cursor === undefined ? {} : { params: { cursor } } }, + ListToolsResultSchema, + ) +} + +/** Call without the SDK pre-validating an output schema the bridge may not support. */ +function callToolUncached( + client: Client, + rawName: string, + args: Record<string, unknown>, + exec: ToolExecution, + opts: ToolBridgeOptions, +) { + return client.request( + { method: 'tools/call', params: { name: rawName, arguments: args } }, + RawCallToolResultSchema, + { + ...exec.signal ? { signal: exec.signal } : {}, + timeout: opts.toolCallTimeoutMs, + }, + ) +} + /** * Derive the model-facing public name for one MCP tool. * @@ -73,7 +104,7 @@ export function publicToolName(serverName: string, rawName: string): string { * * Two phases keep the swap safe: * - * 1. Fetch: drain `client.listTools()` pagination and build the full next + * 1. Fetch: drain uncached `tools/list` pagination and build the full next * generation of `ToolDefinition`s under public names. Any failure here * (network error, duplicate raw name in the server's list) rejects and * leaves the previous generation registered untouched. @@ -101,7 +132,7 @@ export async function syncTools( const definitions = new Map<string, ToolDefinition>() let cursor: string | undefined do { - const response = await client.listTools(cursor ? { cursor } : undefined) + const response = await listToolsUncached(client, cursor) for (const tool of response.tools) { const publicName = publicToolName(opts.serverName, tool.name) if (definitions.has(publicName)) { @@ -114,7 +145,7 @@ export async function syncTools( description: tool.description ?? '', parameters: tool.inputSchema, output: createOutput(tool.name, supportedOutputSchema(tool.outputSchema)), - execute: createExecutor(client, tool.name, opts), + execute: createExecutor(client, tool.name, tool.execution?.taskSupport === 'required', opts), }) } cursor = response.nextCursor @@ -170,7 +201,7 @@ function createOutput(rawName: string, structuredSchema: JsonSchemaNode | undefi content: { type: 'array', items: {} }, structuredContent: structuredSchema ?? {}, }, - required: ['content'], + required: structuredSchema === undefined ? ['content'] : ['content', 'structuredContent'], additionalProperties: false, }, render(_args, value) { @@ -182,9 +213,10 @@ function createOutput(rawName: string, structuredSchema: JsonSchemaNode | undefi /** * Create an execute function for one MCP tool. The executor closes over the - * raw MCP tool name and calls `client.callTool` with it (never the public - * name), with abort signal and timeout, then maps the result to harness - * ContentBlocks. + * raw MCP tool name and sends an uncached `tools/call` request with it (never + * the public name), with abort signal and timeout, then maps the result to + * harness ContentBlocks. Owning the raw request prevents the SDK's internal + * per-page schema cache from pre-validating a different contract. * * When the MCP server returns `isError: true`, the executor throws so that * the ToolRegistry's catch path produces an `isError` result for the model. @@ -192,33 +224,30 @@ function createOutput(rawName: string, structuredSchema: JsonSchemaNode | undefi function createExecutor( client: Client, rawName: string, + taskRequired: boolean, opts: ToolBridgeOptions, ): ToolDefinition['execute'] { return async (args: unknown, exec: ToolExecution) => { + if (taskRequired) { + throw new Error(`Tool "${rawName}" requires task-based execution, which this bridge does not support`) + } // The agent loop passes `JSON.parse(model_arguments)` which is usually an // object, but can be any JSON value if the model misbehaves (outputs a bare // string/number/null). Fallback to {} lets the MCP server produce a // specific "missing required param" error the model can learn from. const argsObj = (typeof args === 'object' && args !== null ? args : {}) as Record<string, unknown> - const result = await client.callTool( - { name: rawName, arguments: argsObj }, - undefined, - { - ...exec.signal ? { signal: exec.signal } : {}, - timeout: opts.toolCallTimeoutMs, - }, - ) + const result = await callToolUncached(client, rawName, argsObj, exec, opts) // The SDK may return a legacy `toolResult` shape; normalize to content array. - if (!('content' in result) || !Array.isArray(result.content)) { + if (!Array.isArray(result.content)) { const rendered: unknown = 'toolResult' in result ? JSON.stringify(result.toolResult) : '(no output)' const text = typeof rendered === 'string' ? rendered : '(no output)' - if ('isError' in result && result.isError === true) throw new Error(text) + if (result.isError === true) throw new Error(text) return { content: [{ type: 'text', text }], - ...'structuredContent' in result && result.structuredContent !== undefined + ...result.structuredContent !== undefined ? { structuredContent: result.structuredContent as JsonValue } : {}, } @@ -232,13 +261,13 @@ function createExecutor( const text = extractText(content, rawName) // MCP isError → throw so ToolRegistry produces an isError result for the model. - if ('isError' in result && result.isError === true) { + if (result.isError === true) { throw new Error(text) } return { content, - ...'structuredContent' in result && result.structuredContent !== undefined + ...result.structuredContent !== undefined ? { structuredContent: result.structuredContent as JsonValue } : {}, } diff --git a/packages/mcp/mcp-client/tests/mcp-client.spec.ts b/packages/mcp/mcp-client/tests/mcp-client.spec.ts index 30e7a6297c..77c61e53a7 100644 --- a/packages/mcp/mcp-client/tests/mcp-client.spec.ts +++ b/packages/mcp/mcp-client/tests/mcp-client.spec.ts @@ -1,4 +1,6 @@ import { describe, expect, it, vi, beforeEach } from 'vitest' +import { Client } from '@modelcontextprotocol/sdk/client/index.js' +import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js' import { Context } from 'cordis' import { CallId } from '@deepseek-ai/dsh-llm' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' @@ -14,6 +16,7 @@ interface MockTool { description?: string inputSchema: Record<string, unknown> outputSchema?: Record<string, unknown> + execution?: { taskSupport?: 'optional' | 'required' | 'forbidden' } } interface MockCallResult { @@ -23,9 +26,26 @@ interface MockCallResult { } function createMockClient(tools: MockTool[], callResult: MockCallResult = { content: [{ type: 'text', text: 'ok' }] }) { + const listTools = vi.fn(async ( + _params?: Record<string, unknown>, + ): Promise<{ tools: MockTool[]; nextCursor: string | undefined }> => ({ tools, nextCursor: undefined })) + const callTool = vi.fn(async ( + _params?: Record<string, unknown>, + _compatibilitySchema?: unknown, + _options?: unknown, + ): Promise<Record<string, unknown>> => ({ ...callResult })) return { - listTools: vi.fn().mockResolvedValue({ tools, nextCursor: undefined }), - callTool: vi.fn().mockResolvedValue(callResult), + listTools, + callTool, + request: vi.fn(async ( + request: { method: string; params?: Record<string, unknown> }, + _schema: unknown, + options?: unknown, + ): Promise<unknown> => { + if (request.method === 'tools/list') return listTools(request.params) + if (request.method === 'tools/call') return callTool(request.params, undefined, options) + throw new Error(`unexpected MCP request: ${request.method}`) + }), setNotificationHandler: vi.fn(), connect: vi.fn().mockResolvedValue(undefined), close: vi.fn().mockResolvedValue(undefined), @@ -205,6 +225,80 @@ describe('syncTools', () => { expect(ctx.tools.get('mcp__srv__page1')).toBeDefined() expect(ctx.tools.get('mcp__srv__page2')).toBeDefined() }) + + it('owns output validation independently of the SDK per-page cache', async () => { + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair() + serverTransport.onmessage = (message) => { + if (!('id' in message) || !('method' in message)) return + const params = 'params' in message ? message.params : undefined + let result: Record<string, unknown> + if (message.method === 'initialize') { + const protocolVersion = params && 'protocolVersion' in params + ? params.protocolVersion + : '2025-11-25' + result = { + protocolVersion, + capabilities: { tools: {} }, + serverInfo: { name: 'raw-test', version: '1' }, + } + } else if (message.method === 'tools/list') { + const cursor = params && 'cursor' in params ? params.cursor : undefined + result = cursor === undefined + ? { + tools: [{ + name: 'supported', + inputSchema: { type: 'object' }, + outputSchema: { + type: 'object', + additionalProperties: false, + properties: { answer: { type: 'integer' } }, + required: ['answer'], + }, + }], + nextCursor: 'page-2', + } + : { + tools: [{ + name: 'future-schema', + inputSchema: { type: 'object' }, + outputSchema: { type: 'object', patternProperties: { '^x-': { type: 'string' } } }, + }], + } + } else if (message.method === 'tools/call') { + const name = params && 'name' in params ? params.name : undefined + result = name === 'supported' + ? { content: [{ type: 'text', text: 'missing structured content' }] } + : { content: [42, null], structuredContent: ['kept', { nested: true }] } + } else { + result = {} + } + void serverTransport.send({ jsonrpc: '2.0', id: message.id, result }) + } + await serverTransport.start() + const client = new Client({ name: 'cache-independent-test', version: '1' }) + await client.connect(clientTransport) + + try { + await syncTools(client, ctx, defaultOpts, new Map()) + + const missing = await ctx.tools.execute({ + callId: CallId('missing'), name: 'mcp__srv__supported', arguments: {}, + }) + expect(missing.error).toMatchObject({ info: { code: 'INVALID_TOOL_OUTPUT' } }) + expect(missing.error?.message).toContain('structuredContent') + + const fallback = await ctx.tools.execute({ + callId: CallId('fallback'), name: 'mcp__srv__future-schema', arguments: {}, + }) + if (fallback.isError) throw new Error('unsupported schema must use the bridge fallback') + expect(fallback.value).toEqual({ + content: [42, null], + structuredContent: ['kept', { nested: true }], + }) + } finally { + await client.close() + } + }) }) describe('tool execution', () => { @@ -360,6 +454,21 @@ describe('tool execution', () => { expect('value' in result).toBe(false) }) + it('rejects tools that require task-based execution', async () => { + const client = createMockClient([ + { name: 'task-only', inputSchema: { type: 'object' }, execution: { taskSupport: 'required' } }, + ]) + + await syncTools(client as never, ctx, defaultOpts, new Map()) + const result = await ctx.tools.execute({ + callId: CallId('task-only'), name: 'mcp__srv__task-only', arguments: {}, + }) + + expect(result.isError).toBe(true) + expect(result.error?.message).toContain('requires task-based execution') + expect(client.callTool).not.toHaveBeenCalled() + }) + it('passes abort signal to callTool', async () => { const controller = new AbortController() const client = createMockClient( diff --git a/packages/session-persistence/session-persistence/tests/contract.ts b/packages/session-persistence/session-persistence/tests/contract.ts index d36ed98234..84386c016b 100644 --- a/packages/session-persistence/session-persistence/tests/contract.ts +++ b/packages/session-persistence/session-persistence/tests/contract.ts @@ -149,7 +149,7 @@ export function runPersistenceContract(name: string, make: () => Promise<Contrac ]) const synthetic = loaded.events.find(e => e.type === 'tool/result') expect(synthetic?.type === 'tool/result' && synthetic.data).toMatchObject({ - callId: CallId('call-x'), isError: true, error: { info: { code: 'interrupted' } }, + callId: CallId('call-x'), isError: true, error: { code: 'interrupted' }, }) // The synthetic result carries the SAME callId as the orphaned tool-call, // so deriveMessages() pairs them — no provider-invalid dangling call. diff --git a/packages/support/invariants/src/index.ts b/packages/support/invariants/src/index.ts index 4a6b39be72..91b4da4566 100644 --- a/packages/support/invariants/src/index.ts +++ b/packages/support/invariants/src/index.ts @@ -165,7 +165,7 @@ function validateEvent(trace: SessionTrace, event: SessionEvent): SessionTraceTr // A result needs a prior matching call in the same step. (The converse // does NOT hold: a call may have no result — a throwing tool-execution // pipeline step ends the turn with no tool/result, which is legal.) - const syntheticInterrupted = event.data.isError && event.data.error?.info?.code === 'interrupted' + const syntheticInterrupted = event.data.isError && event.data.error?.code === 'interrupted' if (!trace.pendingCalls.has(event.data.callId) && !syntheticInterrupted) { throw new InvariantError(`tool/result for ${event.data.callId} with no prior tool/call in this step`) } diff --git a/packages/support/invariants/tests/invariants.spec.ts b/packages/support/invariants/tests/invariants.spec.ts index e9a09ea356..4f066eff8c 100644 --- a/packages/support/invariants/tests/invariants.spec.ts +++ b/packages/support/invariants/tests/invariants.spec.ts @@ -217,7 +217,7 @@ describe('session-log invariants', () => { callId: CallId('crashed'), content: [{ type: 'text', text: 'interrupted' }], isError: true, - error: { message: 'interrupted', info: { name: 'InterruptedError', code: 'interrupted' } }, + error: { name: 'InterruptedError', code: 'interrupted' }, }, { surfaceOp: 'append' }) session.append('step/end', { turn: 1, step: 1 }) session.append('turn/end', { turn: 1, reason: { kind: 'interrupted' } }) @@ -500,7 +500,7 @@ describe('surface contract under the invariants composition', () => { callId: CallId('rewrite'), content: [{ type: 'text' as const, text: 'original' }], isError: true, - error: { message: 'exit 1', info: { name: 'ExitError', code: 'EXIT_1' } }, + error: { name: 'ExitError', code: 'EXIT_1' }, meta: { presentation: { kind: 'terminal', output: 'full output' } }, futureField: { nested: ['preserve', 1] }, } @@ -585,7 +585,7 @@ describe('surface contract under the invariants composition', () => { ['callId', { callId: CallId('forged') }], ['turn', { turn: 2 }], ['step', { step: 2 }], - ['error', { error: { message: 'exit 1', info: { name: 'ExitError', code: 'DIFFERENT' } } }], + ['error', { error: { name: 'ExitError', code: 'DIFFERENT' } }], ['meta', { meta: { presentation: { kind: 'generic' } } }], ['future data', { futureField: { nested: ['changed'] } }], ])('rejects a content rewrite with altered %s', async (_label, altered) => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 903d8a7ca2..ee04300c15 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1447,6 +1447,9 @@ importers: schemastery: specifier: ^3.18.0 version: 3.18.0 + zod: + specifier: ^4.4.3 + version: 4.4.3 devDependencies: '@deepseek-ai/dsh-llm': specifier: workspace:^ @@ -1463,9 +1466,6 @@ importers: cordis: specifier: ^4.0.0-rc.7 version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5) - zod: - specifier: ^4.4.3 - version: 4.4.3 packages/sandbox/sandbox: devDependencies: From 2623ddbee4ae625458b77fb0fb2594f2f44aec7e Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:19:07 +0800 Subject: [PATCH 031/368] fix(code-runtime): validate arguments before worker dispatch --- .../code-runtime-worker/src/bootstrap.ts | 46 +++++++++++++------ .../code-runtime-worker/src/index.ts | 31 +++++++++---- .../code-runtime-worker/src/output-json.ts | 36 +++++++++++++++ .../code-runtime-worker/src/worker-json.ts | 1 + .../tests/bootstrap.spec.ts | 39 ++++++++++++++-- .../tests/output-json.spec.ts | 18 ++++++++ .../code-runtime-worker/tests/runtime.spec.ts | 42 ++++++++++++++++- .../tests/worker-json.spec.ts | 9 ++++ 8 files changed, 194 insertions(+), 28 deletions(-) create mode 100644 packages/code-runtime/code-runtime-worker/src/output-json.ts create mode 100644 packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts diff --git a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts index 45c8a4d2d2..2334085377 100644 --- a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts +++ b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts @@ -188,6 +188,12 @@ export class ToolCallError extends Error { } } +/** Create the namespace-specific rejection for one lossy binding argument. */ +function bindingArgumentFailure(global: string, name: string): Error { + const message = 'binding arguments must be lossless JSON' + return global === 'tools' ? new ToolCallError(name, message) : new Error(message) +} + /** * Route host replies into the pending-call map: each reply settles its call * at most once, and a reply for an unknown id (stray, or a duplicate answer @@ -211,7 +217,8 @@ export function wireReplies(port: BootstrapPort, pending: Map<number, PendingCal * Build the binding namespace objects the program sees: one null-prototype global per * namespace, each declared name an own enumerable async function that bridges over the port * (`__proto__`/`constructor`/`toString` are ordinary keys, never prototype collisions). - * Non-cloneable arguments and host failure replies reject only the corresponding call. + * Lossy arguments reject before posting; clone failures and host failure + * replies reject only the corresponding call. * * @param data - the boot payload's namespace declarations (globals + names). * @param port - the port binding calls are posted to. @@ -230,22 +237,31 @@ export function makeNamespaces( for (const name of names) { Object.defineProperty(namespace, name, { enumerable: true, - value: (args: unknown): Promise<unknown> => new Promise((resolve, reject) => { - const id = nextId.value++ - pending.set(id, { - resolve, - reject: (error) => { - reject(global === 'tools' ? new ToolCallError(name, error.message) : error) - }, - }) + value: (args: unknown): Promise<unknown> => { + let detached: unknown try { - port.postMessage({ type: 'call', id, global, name, args }) - } catch (error: unknown) { - pending.delete(id) - const message = `binding arguments must be structured-cloneable: ${error instanceof Error ? error.message : String(error)}` - reject(global === 'tools' ? new ToolCallError(name, message) : new Error(message)) + detached = snapshotCodeJsonValue(args) + } catch { + detached = undefined } - }), + if (detached === undefined) return Promise.reject(bindingArgumentFailure(global, name)) + return new Promise((resolve, reject) => { + const id = nextId.value++ + pending.set(id, { + resolve, + reject: (error) => { + reject(global === 'tools' ? new ToolCallError(name, error.message) : error) + }, + }) + try { + port.postMessage({ type: 'call', id, global, name, args: detached }) + } catch (error: unknown) { + pending.delete(id) + const message = `binding arguments must be structured-cloneable: ${error instanceof Error ? error.message : String(error)}` + reject(global === 'tools' ? new ToolCallError(name, message) : new Error(message)) + } + }) + }, }) } return namespace diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index 6cc7124bb6..f59f3e8d9a 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -15,6 +15,7 @@ import { CodeRuntime } from '@deepseek-ai/dsh-code-runtime' import type { CodeBindingFunction, CodeJsonValue, CodeRunFailure, CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' import { snapshotJsonValue } from '@deepseek-ai/dsh-session' import type { ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts' +import { truncateJsonStringBytes } from './output-json.ts' /** Plugin config: every execution cap, changeable from `cordis.yml` (no hardcoded tunables). */ export interface Config { @@ -174,16 +175,29 @@ class OutputLedger { return { logs, error } } - /** Build the explicit output-limit failure while retaining the fitting log prefix. */ + /** Build the explicit output-limit failure while retaining a fitting prefix of the final log. */ limit(logs: string[]): CodeRunResult { const fullMessage = `outer output exceeded ${this.maxBytes} bytes` - let retainedBytes = this.bytes const messageBytes = Buffer.byteLength(JSON.stringify(fullMessage), 'utf8') - while (logs.length > 0 && retainedBytes + messageBytes > this.maxBytes) { - const removed = logs.pop() + const retained = [...logs] + let retainedBytes = jsonBytes(retained) + const logBudget = this.maxBytes - messageBytes + while (retained.length > 0 && retainedBytes > logBudget) { + const removed = retained.pop() /* v8 ignore next -- the while guard proves pop cannot return undefined. */ if (removed === undefined) throw new Error('output ledger lost its final log entry') - retainedBytes -= Buffer.byteLength(JSON.stringify(removed), 'utf8') + (logs.length > 0 ? 1 : 0) + const separatorBytes = retained.length > 0 ? 1 : 0 + retainedBytes -= Buffer.byteLength(JSON.stringify(removed), 'utf8') + separatorBytes + const prefix = truncateJsonStringBytes(removed, logBudget - retainedBytes - separatorBytes) + if (prefix.length > 0) { + retained.push(prefix) + retainedBytes += Buffer.byteLength(JSON.stringify(prefix), 'utf8') + separatorBytes + break + } + } + if (logBudget < 2) { + retained.length = 0 + retainedBytes = 2 } const availableMessageBytes = this.maxBytes - retainedBytes // This fixed diagnostic is ASCII with no JSON escapes, so two bytes are @@ -191,7 +205,7 @@ class OutputLedger { const message = messageBytes <= availableMessageBytes ? fullMessage : fullMessage.slice(0, availableMessageBytes - 2) - return { logs, error: { kind: 'output-limit', message } } + return { logs: retained, error: { kind: 'output-limit', message } } } } @@ -326,7 +340,8 @@ export class WorkerCodeRuntime extends CodeRuntime { // a chunk flushing after settlement mutates only the discarded buffers, // and the ledger bounds that growth until the pipes close. const captureStray = (chunk: Buffer): void => { - if (!settled && !output.admit(chunk.toString('utf8'), strayLogs)) finish(output.limit([...logs, ...strayLogs])) + const text = chunk.toString('utf8') + if (!settled && !output.admit(text, strayLogs)) finish(output.limit([...logs, ...strayLogs, text])) } worker.stdout.on('data', captureStray) worker.stderr.on('data', captureStray) @@ -416,7 +431,7 @@ export class WorkerCodeRuntime extends CodeRuntime { const message = parseWorkerMessage(raw) if (!message) return if (message.type === 'log' && !settled && !output.admit(message.text, logs)) { - finish(output.limit([...logs, ...strayLogs])) + finish(output.limit([...logs, ...strayLogs, message.text])) return } if (message.type === 'output-limit' && !settled) { diff --git a/packages/code-runtime/code-runtime-worker/src/output-json.ts b/packages/code-runtime/code-runtime-worker/src/output-json.ts new file mode 100644 index 0000000000..dd3c3529f5 --- /dev/null +++ b/packages/code-runtime/code-runtime-worker/src/output-json.ts @@ -0,0 +1,36 @@ +/** JSON string-prefix accounting for the outer-output ledger. @module @deepseek-ai/dsh-code-runtime-worker/output-json */ + +/** Control characters with a two-byte short JSON escape instead of `\u00XX`. */ +const SHORT_ESCAPE_CODES = new Set([0x08, 0x09, 0x0a, 0x0c, 0x0d]) + +/** Serialized bytes contributed by one complete Unicode code point inside JSON quotes. */ +function serializedCharacterBytes(character: string): number { + if (character.length === 2) return 4 + if (character === '"' || character === '\\') return 2 + const code = character.charCodeAt(0) + if (code >= 0xd800 && code <= 0xdfff) return 6 + if (code < 0x20) return SHORT_ESCAPE_CODES.has(code) ? 2 : 6 + return Buffer.byteLength(character, 'utf8') +} + +/** + * Return the longest code-point-aligned prefix whose JSON string encoding, + * including its surrounding quotes, fits `maxBytes`. + * + * @param text - the candidate string. + * @param maxBytes - serialized JSON-string bytes available. + * @returns the fitting prefix, or an empty string when even useful content cannot fit. + */ +export function truncateJsonStringBytes(text: string, maxBytes: number): string { + if (maxBytes < 2) return '' + if (Buffer.byteLength(JSON.stringify(text), 'utf8') <= maxBytes) return text + let bytes = 2 + let end = 0 + for (const character of text) { + const cost = serializedCharacterBytes(character) + if (bytes + cost > maxBytes) break + bytes += cost + end += character.length + } + return text.slice(0, end) +} diff --git a/packages/code-runtime/code-runtime-worker/src/worker-json.ts b/packages/code-runtime/code-runtime-worker/src/worker-json.ts index eec80184f6..9151d07e7e 100644 --- a/packages/code-runtime/code-runtime-worker/src/worker-json.ts +++ b/packages/code-runtime/code-runtime-worker/src/worker-json.ts @@ -33,6 +33,7 @@ export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined if (Array.isArray(candidate)) { if (Object.getPrototypeOf(candidate) !== Array.prototype) return undefined + if (Reflect.ownKeys(candidate).length !== candidate.length + 1) return undefined return within(candidate, () => { const result: CodeJsonValue[] = [] for (let index = 0; index < candidate.length; index++) { diff --git a/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts b/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts index 2f817e0edc..300b08d85f 100644 --- a/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts @@ -190,7 +190,7 @@ describe('makeNamespaces', () => { await expect(tools['toString']?.({})).resolves.toBe('toString-ok') }) - it('rejects a non-cloneable argument without leaking the pending entry', async () => { + it('rejects a postMessage clone failure without leaking the pending entry', async () => { let firstCall = true const throwingPort: BootstrapPort = { // First call throws an Error (the real DataCloneError shape), the @@ -203,8 +203,8 @@ describe('makeNamespaces', () => { } const pending = new Map<number, PendingCall>() const [tools] = makeNamespaces({ namespaces: [{ global: 'tools', names: ['x'] }] }, throwingPort, pending, { value: 1 }) as [Record<string, (args: unknown) => Promise<unknown>>] - const first = await rejectionOf(tools.x?.(() => 1) ?? Promise.resolve()) - const second = await rejectionOf(tools.x?.(() => 1) ?? Promise.resolve()) + const first = await rejectionOf(tools.x?.({ first: true }) ?? Promise.resolve()) + const second = await rejectionOf(tools.x?.({ second: true }) ?? Promise.resolve()) expect(first).toMatchObject({ name: 'ToolCallError', toolName: 'x' }) expect(second).toMatchObject({ name: 'ToolCallError', toolName: 'x' }) expect(first).toBeInstanceOf(ToolCallError) @@ -214,6 +214,32 @@ describe('makeNamespaces', () => { expect(pending.size).toBe(0) }) + it('rejects lossy arguments before posting or allocating a call id', async () => { + let posts = 0 + const port: BootstrapPort = { postMessage: () => { posts += 1 }, on: () => {} } + const pending = new Map<number, PendingCall>() + const nextId = { value: 1 } + const [tools] = makeNamespaces( + { namespaces: [{ global: 'tools', names: ['x'] }] }, port, pending, nextId, + ) as [Record<string, (args: unknown) => Promise<unknown>>] + const decorated = [1] + Object.defineProperty(decorated, 'extra', { value: true }) + const throwing = Object.defineProperty({}, 'value', { + enumerable: true, + get: () => { throw new Error('getter exploded') }, + }) + + for (const value of [() => 1, new Date(), decorated, throwing]) { + const failure = await rejectionOf(tools.x?.(value) ?? Promise.resolve()) + expect(failure).toMatchObject({ + name: 'ToolCallError', toolName: 'x', message: 'binding arguments must be lossless JSON', + }) + } + expect(posts).toBe(0) + expect(pending.size).toBe(0) + expect(nextId.value).toBe(1) + }) + it('uses ordinary Error for non-tools namespace failures', async () => { const deniedPort = new FakePort() deniedPort.respond = message => message.type === 'call' @@ -226,9 +252,14 @@ describe('makeNamespaces', () => { expect(denied).toBeInstanceOf(Error) expect(denied).not.toBeInstanceOf(ToolCallError) + const invalid = await rejectionOf(helpers.x?.(() => 1) ?? Promise.resolve()) + expect(invalid).toBeInstanceOf(Error) + expect(invalid).not.toBeInstanceOf(ToolCallError) + expect((invalid as Error).message).toBe('binding arguments must be lossless JSON') + const clonePort: BootstrapPort = { postMessage: () => { throw new Error('clone failed') }, on: () => {} } const [cloneHelpers] = makeNamespaces({ namespaces: [{ global: 'helpers', names: ['x'] }] }, clonePort, new Map(), { value: 1 }) as [Record<string, (args: unknown) => Promise<unknown>>] - const cloneFailure = await rejectionOf(cloneHelpers.x?.(() => 1) ?? Promise.resolve()) + const cloneFailure = await rejectionOf(cloneHelpers.x?.({}) ?? Promise.resolve()) expect(cloneFailure).toBeInstanceOf(Error) expect(cloneFailure).not.toBeInstanceOf(ToolCallError) }) diff --git a/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts new file mode 100644 index 0000000000..8340d6e74c --- /dev/null +++ b/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from 'vitest' +import { truncateJsonStringBytes } from '../src/output-json.ts' + +describe('truncateJsonStringBytes', () => { + it('returns a fitting string whole and rejects budgets without JSON quotes', () => { + expect(truncateJsonStringBytes('fits', 6)).toBe('fits') + expect(truncateJsonStringBytes('x', 1)).toBe('') + }) + + it('accounts every JSON escape and cuts only between complete code points', () => { + const prefix = '"\\\b\t\n\f\r\u0000😀\ud800€a' + const text = `${prefix}z` + const budget = Buffer.byteLength(JSON.stringify(prefix), 'utf8') + + expect(truncateJsonStringBytes(text, budget)).toBe(prefix) + expect(Buffer.byteLength(JSON.stringify(truncateJsonStringBytes(text, budget)), 'utf8')).toBe(budget) + }) +}) diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index 22787a2154..5615062286 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -218,6 +218,19 @@ describe('WorkerCodeRuntime — budgets and containment (real workers)', () => { expect(Buffer.byteLength(JSON.stringify(result.logs), 'utf8')).toBeLessThan(300) }) + it('retains a fitting prefix when one oversized log is the first output', async () => { + const { runtime } = await setup({ maxOutputBytes: 96 }) + const result = await runtime.run({ + program: 'console.log(`start-${`😀"\\\\\\n`.repeat(100)}`); return null', + bindings: [], + }) + expect(result.error).toEqual({ kind: 'output-limit', message: 'outer output exceeded 96 bytes' }) + expect(result.logs).toHaveLength(1) + expect(result.logs[0]?.startsWith('start-')).toBe(true) + expect(Buffer.byteLength(JSON.stringify(result.logs), 'utf8') + + Buffer.byteLength(JSON.stringify(result.error?.message), 'utf8')).toBeLessThanOrEqual(96) + }) + it('fails an oversized return value without substituting a string', async () => { const { runtime } = await setup({ maxOutputBytes: 64 }) const result = await runtime.run({ program: 'return "y".repeat(10_000)', bindings: [] }) @@ -304,7 +317,8 @@ describe('WorkerCodeRuntime — budgets and containment (real workers)', () => { }) expect(result.error?.kind).toBe('output-limit') expect(result.logs).toContain('a'.repeat(20)) - expect(result.logs).not.toContain('b'.repeat(100)) + expect(result.logs[1]?.length).toBeGreaterThan(0) + expect('b'.repeat(100).startsWith(result.logs[1] ?? '')).toBe(true) }, 15_000) }) @@ -409,6 +423,32 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { expect(result.value).toEqual({ name: 'ToolCallError', toolName: 'bad', message: 'binding resolution must be lossless JSON' }) }) + it('rejects lossy binding arguments in the worker before invoking the host binding', async () => { + const { runtime } = await setup() + let calls = 0 + const result = await runtime.run({ + program: ` + const decorated = [1]; Object.defineProperty(decorated, 'extra', { value: true }); + const values = [new Date(), decorated, () => 1]; + const failures = []; + for (const value of values) { + try { await tools.never(value) } catch (error) { + failures.push({ typed: error instanceof ToolCallError, name: error.name, toolName: error.toolName, message: error.message }); + } + } + return failures; + `, + bindings: tools({ never: async () => { calls += 1; return null } }), + }) + expect(calls).toBe(0) + expect(result.value).toEqual(new Array(3).fill({ + typed: true, + name: 'ToolCallError', + toolName: 'never', + message: 'binding arguments must be lossless JSON', + })) + }) + it('contains throwing getters while snapshotting binding resolutions', async () => { const { runtime } = await setup() const result = await runtime.run({ diff --git a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts index 3f717599b7..b574e80aff 100644 --- a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts @@ -60,12 +60,21 @@ describe('snapshotCodeJsonValue', () => { class ExoticArray extends Array<number> {} const cyclic: Record<string, unknown> = {} cyclic.self = cyclic + const decorated = [1] + Object.defineProperty(decorated, 'extra', { value: true }) + const compensatedSparse = new Array(1) + Object.defineProperty(compensatedSparse, 'extra', { value: true }) + const symbolDecorated = [1] + Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) for (const value of [ new ExoticObject(), new Map([['value', 1]]), new ExoticArray(1), new Array(1), + decorated, + compensatedSparse, + symbolDecorated, cyclic, [undefined], { value: undefined }, From 72693a346e54771ddd26ec9d8736783adc5f3344 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:20:18 +0800 Subject: [PATCH 032/368] test(tools): cover adversarial JSON containers --- packages/cordis/tool-cordis/tests/mount.spec.ts | 1 + packages/core/session/tests/json.spec.ts | 6 ++++++ packages/core/tools/tests/properties.spec.ts | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index db001c3877..607f8b6192 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -344,6 +344,7 @@ describe('cordis_mount', () => { ['parameters: { value: { type: \'json\', default: (() => { const v = {}; v.self = v; return v })() } }', 'parameters.value.default.self must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: Array(2) } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: Object.assign([1], { extra: true }) } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: (() => { const v = Array(1); v.extra = true; return v })() } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: new (class DefaultValue { constructor() { this.ok = true } })() } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: new Date(0) } }', 'parameters.value.default must be lossless JSON data'], ])('rejects a malformed ParameterSchemaSpec (%s) with a teaching error', async (parameters, message) => { diff --git a/packages/core/session/tests/json.spec.ts b/packages/core/session/tests/json.spec.ts index 435126c22e..35d521f6d1 100644 --- a/packages/core/session/tests/json.spec.ts +++ b/packages/core/session/tests/json.spec.ts @@ -69,6 +69,8 @@ describe('snapshotJsonValue', () => { } class ExoticArray extends Array<number> {} const sparse = new Array<number>(1) + const compensatedSparse = new Array<number>(1) + Object.defineProperty(compensatedSparse, 'extra', { value: true }) const decorated = [1] Object.defineProperty(decorated, 'extra', { value: true }) const symbolDecorated = [1] @@ -80,6 +82,7 @@ describe('snapshotJsonValue', () => { expect(snapshotJsonValue(new Map([['value', 1]]))).toBeUndefined() expect(snapshotJsonValue(new ExoticArray(1))).toBeUndefined() expect(snapshotJsonValue(sparse)).toBeUndefined() + expect(snapshotJsonValue(compensatedSparse)).toBeUndefined() expect(snapshotJsonValue(decorated)).toBeUndefined() expect(snapshotJsonValue(symbolDecorated)).toBeUndefined() expect(snapshotJsonValue(cyclic)).toBeUndefined() @@ -145,6 +148,8 @@ describe('isJsonValue', () => { } class ExoticArray extends Array<number> {} const sparse = new Array<number>(1) + const compensatedSparse = new Array<number>(1) + Object.defineProperty(compensatedSparse, 'extra', { value: true }) const decorated = Object.assign([1], { extra: true }) const symbolDecorated = [1] Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) @@ -152,6 +157,7 @@ describe('isJsonValue', () => { cyclic.self = cyclic expect(isJsonValue(sparse)).toBe(false) + expect(isJsonValue(compensatedSparse)).toBe(false) expect(isJsonValue(decorated)).toBe(false) expect(isJsonValue(symbolDecorated)).toBe(false) expect(isJsonValue(new ExoticArray(1))).toBe(false) diff --git a/packages/core/tools/tests/properties.spec.ts b/packages/core/tools/tests/properties.spec.ts index 54c4088909..e04e9f5c5b 100644 --- a/packages/core/tools/tests/properties.spec.ts +++ b/packages/core/tools/tests/properties.spec.ts @@ -7,6 +7,7 @@ import { describe, expect, it } from 'vitest' import fc from 'fast-check' +import { isJsonValue } from '@deepseek-ai/dsh-session' import { parameterSchemaSpecToJsonSchema, validateArgs } from '@deepseek-ai/dsh-tools' import type { ParameterPropertySpec, ParameterSchemaSpec, ValueSchemaSpec } from '@deepseek-ai/dsh-tools' @@ -80,7 +81,7 @@ function valueForProp(prop: ParameterPropertySpec): fc.Arbitrary<unknown> { case 'null': return fc.constant(null) case 'object': return prop.properties ? validArgsForSpec(prop.properties) : fc.constant({}) case 'array': return prop.items ? fc.array(valueForProp(prop.items), { maxLength: 3 }) : fc.constant([]) - case 'json': return fc.jsonValue() + case 'json': return fc.jsonValue().filter(value => isJsonValue(value)) } } From 1f4f147699e62ece81ea3d13698ac382603f059a Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:22:14 +0800 Subject: [PATCH 033/368] test(tools): close canonical output coverage gaps --- .../cordis/tool-cordis/tests/mount.spec.ts | 1 + .../agent-loop/tests/coverage-edges.spec.ts | 2 +- packages/core/agent-loop/tests/loop.spec.ts | 7 +++-- packages/core/tools/tests/tools.spec.ts | 31 ++++++++++++++++++- packages/fs/tool-fs/src/read-render.ts | 1 - packages/mcp/mcp-client/tests/apply.spec.ts | 16 ++++++++-- 6 files changed, 50 insertions(+), 8 deletions(-) diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 6bc2d5970d..a46f37a721 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -433,6 +433,7 @@ describe('cordis_mount', () => { ['__proto__']: { type: 'string', required: true }, value: { type: 'json', default: { ['__proto__']: { safe: true } } }, }, + ${CONTENT_OUTPUT_CODE} async execute() { return [] }, })) }, diff --git a/packages/core/agent-loop/tests/coverage-edges.spec.ts b/packages/core/agent-loop/tests/coverage-edges.spec.ts index 65c2258d0b..eb1a456c7a 100644 --- a/packages/core/agent-loop/tests/coverage-edges.spec.ts +++ b/packages/core/agent-loop/tests/coverage-edges.spec.ts @@ -274,6 +274,6 @@ describe('structured tool error propagation (the runtime-validation Agent Note, const toolResult = agent.session.events.find(e => e.type === 'tool/result') expect(toolResult?.type === 'tool/result' && toolResult.data.isError).toBe(true) expect(toolResult?.type === 'tool/result' && toolResult.data.error) - .toEqual({ message: 'exploded', info: { name: 'HarnessError', code: 'BOOM' } }) + .toEqual({ name: 'HarnessError', code: 'BOOM' }) }) }) diff --git a/packages/core/agent-loop/tests/loop.spec.ts b/packages/core/agent-loop/tests/loop.spec.ts index aa3a35bc36..3c89eda70c 100644 --- a/packages/core/agent-loop/tests/loop.spec.ts +++ b/packages/core/agent-loop/tests/loop.spec.ts @@ -253,7 +253,7 @@ describe('agent loop', () => { ['BigInt', { n: 1n }], ['Map', new Map([['key', 'value']])], ['class instance', new (class ResultMeta { x = 1 })()], - ])('normalizes non-JSON presentation metadata (%s) before the durable result commit', async (_kind, meta) => { + ])('rejects non-JSON presentation metadata (%s) before the durable result commit', async (_kind, meta) => { const adapter = new MockAdapter([ toolCallResponse('bad-meta-call', 'bad-meta', {}, 'calling'), textResponse('recovered'), @@ -281,15 +281,16 @@ describe('agent loop', () => { expect(result.data.callId).toBe('bad-meta-call') expect(result.data.isError).toBe(true) expect(result.data.meta).toBeUndefined() + expect(result.data.error).toEqual({ name: 'ToolOutputError', code: 'INVALID_TOOL_OUTPUT' }) expect(result.data.content).toEqual([{ type: 'text', - text: 'Error: tool result must be losslessly JSON-serializable', + text: 'Error: tool "bad-meta" returned invalid output: output.presentationMeta returned non-lossless JSON', }]) } // The normalized failure was durably logged and fed back to the model; the // turn continued normally instead of failing after an apparent success. expect(adapter.requests).toHaveLength(2) - expect(JSON.stringify(adapter.requests[1]!.messages)).toContain('losslessly JSON-serializable') + expect(JSON.stringify(adapter.requests[1]!.messages)).toContain('output.presentationMeta returned non-lossless JSON') }) it('omits the system field when a system-prompt/assemble veto empties the assembly', async () => { diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index d237430dda..874500ed3f 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -1,6 +1,6 @@ import { describe, expect, expectTypeOf, it } from 'vitest' import { Context } from 'cordis' -import { CallId, HarnessError } from '@deepseek-ai/dsh-llm' +import { CallId, HarnessError, type ContentBlock } from '@deepseek-ai/dsh-llm' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import type { Agent } from '@deepseek-ai/dsh-agent' import ApprovalService, { type ApprovalOutcome, type ApprovalRequest } from '@deepseek-ai/dsh-user-approval' @@ -217,6 +217,35 @@ describe('ToolRegistry', () => { expect('value' in result).toBe(false) }) + it.each(['render', 'presentationMeta'] as const)('contains a throwing output.%s snapshot as one failed call', async (projector) => { + const ctx = await setup() + const hostile = Object.defineProperty({}, 'value', { + enumerable: true, + get: () => { throw new Error('snapshot getter exploded') }, + }) + ctx.tools.register(defineTool({ + name: `hostile-${projector}`, + description: projector, + parameters: {}, + output: { + schema: { type: 'string' }, + render: () => projector === 'render' + ? hostile as unknown as ContentBlock[] + : [{ type: 'text', text: 'ok' }], + presentationMeta: () => projector === 'presentationMeta' + ? hostile as unknown as JsonValue + : null, + }, + execute: async () => 'ok', + })) + + const result = await ctx.tools.execute({ + callId: CallId(`hostile-${projector}`), name: `hostile-${projector}`, arguments: {}, + }) + expect(result.error?.message).toContain('snapshot getter exploded') + expect(result.error?.info).toEqual({ name: 'ToolOutputError', code: 'INVALID_TOOL_OUTPUT' }) + }) + it('keeps value/meta through content replacement and recomputes both projections after value replacement', async () => { const ctx = await setup() ctx.tools.register(defineTool({ diff --git a/packages/fs/tool-fs/src/read-render.ts b/packages/fs/tool-fs/src/read-render.ts index e30dad7bcd..943ff98f61 100644 --- a/packages/fs/tool-fs/src/read-render.ts +++ b/packages/fs/tool-fs/src/read-render.ts @@ -77,7 +77,6 @@ function lineByteSize(line: string, currentLineCount: number): number { function consumeLine(acc: WindowAccumulator, rawLine: string, request: ReadWindow): void { acc.totalLines += 1 - if (acc.done) return if (acc.totalLines < request.offset || acc.lines.length >= request.limit) return const text = truncateLine(rawLine, request.maxLineLength) diff --git a/packages/mcp/mcp-client/tests/apply.spec.ts b/packages/mcp/mcp-client/tests/apply.spec.ts index 4b43411346..e36e091478 100644 --- a/packages/mcp/mcp-client/tests/apply.spec.ts +++ b/packages/mcp/mcp-client/tests/apply.spec.ts @@ -15,14 +15,26 @@ import type { Config } from '@deepseek-ai/dsh-mcp-client' const { mockConnect, mockClose, mockListTools, mockCallTool, mockSetNotificationHandler, MockClient } = vi.hoisted(() => { const mockConnect = vi.fn<() => Promise<void>>() const mockClose = vi.fn<() => Promise<void>>() - const mockListTools = vi.fn() - const mockCallTool = vi.fn() + const mockListTools = vi.fn<(_params?: Record<string, unknown>) => Promise<unknown>>() + const mockCallTool = vi.fn<( + _params?: Record<string, unknown>, _compatibilitySchema?: unknown, _options?: unknown, + ) => Promise<unknown>>() const mockSetNotificationHandler = vi.fn() + const mockRequest = vi.fn(async ( + request: { method: string; params?: Record<string, unknown> }, + _schema: unknown, + options?: unknown, + ): Promise<unknown> => { + if (request.method === 'tools/list') return await mockListTools(request.params) + if (request.method === 'tools/call') return await mockCallTool(request.params, undefined, options) + throw new Error(`unexpected MCP request: ${request.method}`) + }) class MockClient { connect = mockConnect close = mockClose listTools = mockListTools callTool = mockCallTool + request = mockRequest setNotificationHandler = mockSetNotificationHandler } return { mockConnect, mockClose, mockListTools, mockCallTool, mockSetNotificationHandler, MockClient } From 449e3cf29831d1da2be64ed84418ab2df60a690e Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:38:22 +0800 Subject: [PATCH 034/368] fix(tools): make code result cards authoritative --- ...0-canonical-tool-output-contract.i18n.yaml | 4 +- ...26-07-20-canonical-tool-output-contract.md | 2 +- ...07-20-canonical-tool-output-contract.zh.md | 2 +- ...de-mode-result-card-completeness.i18n.yaml | 4 +- ...7-20-code-mode-result-card-completeness.md | 8 +- ...0-code-mode-result-card-completeness.zh.md | 8 +- .../feature/2026-06-15-code-mode.md | 2 +- .../advanced-toolchain/session.jsonl | 2 +- .../snapshots/both-mode-turn/session.jsonl | 2 +- .../tests/snapshots/code-mode-turn/input.json | 2 +- .../snapshots/code-mode-turn/session.jsonl | 834 ++++++++++++++---- .../code-mode-turn/stdout.expected.jsonl | 556 +++++++++++- .../code-mode-workspace-context/session.jsonl | 2 +- .../advanced-toolchain/session.jsonl | 2 +- .../stream-json.expected.jsonl | 2 +- .../tests/snapshots/code-mode/session.jsonl | 369 ++++---- .../snapshots/code-mode/terminal.expected.txt | 74 +- packages/core/tools/src/code-mode.ts | 1 - packages/core/tools/tests/code-mode.spec.ts | 24 +- 19 files changed, 1526 insertions(+), 374 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml index d76de6a74e..8300177847 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml @@ -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 -2026-07-20-canonical-tool-output-contract.md: 226ca3274e08e2d46d29075ee412d4945fda753a -2026-07-20-canonical-tool-output-contract.zh.md: c5c5e46e267dd3d0795df7fb6761e867e52b5b2b +2026-07-20-canonical-tool-output-contract.md: 906bd85303e2bee5c02690772cef8763292e166f +2026-07-20-canonical-tool-output-contract.zh.md: a2359f43b22d6bf2da747cd438cca95f90dddf56 diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md index 226ca3274e..906bd85303 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md @@ -34,7 +34,7 @@ type ToolExecutionResult = `tools/post-execute` has two mutually exclusive successful projections. Replacing `content` changes only Native/model presentation and preserves the canonical value and metadata. Replacing `value` revalidates the replacement and recomputes both presentation projections. A block removes the value and becomes a failure. Content replacement is therefore not a confidentiality mechanism: policy that must prevent programmatic access blocks the call or replaces the value. -Canonical values are execution-local. The agent loop persists `tool/result` with only `content`, `error`, and `meta`; Code Mode's `tool/code-dispatch` persists only its bounded summary. Neither event stores the intermediate value, so replay reproduces presentation but cannot reconstruct the programmatic result. `presentationMeta` is computed only for a direct surface call, including the outer `run_code`; a nested Code dispatch gets no metadata or result card. Generic and tool-owned spill projections similarly skip nested dispatches, whose canonical value never enters model context. +Canonical values are execution-local. The agent loop persists `tool/result` with only `content`, `error`, and optional `meta`; Code Mode's `tool/code-dispatch` persists only its bounded summary. Neither event stores the intermediate value, so replay reproduces presentation but cannot reconstruct the programmatic result. When a tool declares `presentationMeta`, it is computed only for a direct surface call; a nested Code dispatch gets no metadata or result card. The outer `run_code` card instead reads final post-policy content and declares no presentation metadata. Generic and tool-owned spill projections similarly skip nested dispatches, whose canonical value never enters model context. The first-party tools preserve their existing Native text while returning domain DTOs: diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md index c5c5e46e26..a2359f43b2 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md @@ -34,7 +34,7 @@ type ToolExecutionResult = `tools/post-execute` 为成功结果提供两种互斥的投影方式。替换 `content` 只改变 Native/模型展示,并保留规范值和元数据。替换 `value` 会重新校验替代值,并重新计算两份展示投影。阻止操作会移除值并转为失败。因此,替换内容并不是保密机制:必须阻止程序化访问的策略,应当阻止调用或替换值。 -规范值仅存在于执行期间。agent loop(智能体循环)持久化的 `tool/result` 只包含 `content`、`error` 和 `meta`;Code Mode 的 `tool/code-dispatch` 只持久化其有界摘要。两个事件都不存储中间值,因此回放可以重现展示,却无法重建程序化结果。系统只会为直接的外层调用计算 `presentationMeta`,其中包括外层 `run_code`;嵌套 Code 分发没有元数据或结果卡片。通用以及工具自有的输出落盘投影同样跳过嵌套分发,因为它们的规范值永远不会进入模型上下文。 +规范值仅存在于执行期间。agent loop(智能体循环)持久化的 `tool/result` 只包含 `content`、`error` 和可选的 `meta`;Code Mode 的 `tool/code-dispatch` 只持久化其有界摘要。两个事件都不存储中间值,因此回放可以重现展示,却无法重建程序化结果。当工具声明 `presentationMeta` 时,系统只会为直接的外层调用计算它;嵌套 Code 分发没有元数据或结果卡片。外层 `run_code` 卡片则读取最终的 post-policy 内容,并且不声明展示元数据。通用以及工具自有的输出落盘投影同样跳过嵌套分发,因为它们的规范值永远不会进入模型上下文。 第一方工具在保持现有 Native 文本不变的同时返回领域 DTO: diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml index 2466af8f85..c5ab1722dd 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml @@ -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 -2026-07-20-code-mode-result-card-completeness.md: 65aad02713498f5dbeff5ab3886da558326a0003 -2026-07-20-code-mode-result-card-completeness.zh.md: 082e209544d4ea43f75bb979fc3aa490b426952e +2026-07-20-code-mode-result-card-completeness.md: 1fbdbdd311f359cbe2ab505210768b2136d56067 +2026-07-20-code-mode-result-card-completeness.zh.md: 619c742e6adb2dc846a9c278e78938dd8e0559b1 diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md index 65aad02713..1fbdbdd311 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md @@ -6,7 +6,7 @@ English | [中文](2026-07-20-code-mode-result-card-completeness.zh.md) ## Problem -The outer `run_code` tool persisted complete rendered content, but its editor presenter ignored that content and rebuilt the card body from a logs-only `presentationMeta` projection. A result-only run appeared correct because an empty presenter body let ACP and TUI fall back to `tool/result.content`. Once the program emitted a log, the presenter supplied non-empty content, that fallback stopped, and the returned value disappeared from the completed card. Failure text and a spill policy's final head/tail preview were vulnerable to the same split ownership. +The outer `run_code` tool persisted complete rendered content, but its editor presenter ignored that content and rebuilt the card body from a logs-only `presentationMeta` projection. A result-only run appeared correct because an empty presenter body let ACP and TUI fall back to `tool/result.content`. Once the program emitted a log, the presenter supplied non-empty content, that fallback stopped, and the returned value disappeared from the completed card. A spill policy's final head/tail preview was vulnerable to the same split ownership whenever captured logs made the stale projection non-empty. Nested Code calls never owned cards, so producing metadata for the outer call solely to reconstruct one incomplete card also obscured the intended one-card boundary. @@ -14,13 +14,13 @@ Nested Code calls never owned cards, so producing metadata for the outer call so The `run_code` output renderer remains the single owner of model-facing outer content. It renders captured logs followed by the return value, the explicit no-output marker, or the failure content produced by the canonical tool pipeline. Post-execute policy and spill may replace that content before it is persisted. -`run_code.presentResult` now forwards the final `result.content` into one generic result card. It deliberately omits the title so the pending card retains the program text. The existing logs metadata remains in `tool/result` for transcript compatibility, but the presenter no longer treats it as a second content source: `tool/result.content` is the durable, replayable, post-policy projection. +`run_code.presentResult` now forwards the final `result.content` into one generic result card. It deliberately omits the title so the pending card retains the program text. The redundant logs-only `presentationMeta` projection is removed: `tool/result.content` is the durable, replayable, post-policy projection and the card's only result-content source. Nested dispatch remains unchanged. Calls marked by `exec.parent` emit bounded `tool/code-dispatch` diagnostics but no `tool/call` or `tool/result` surface cards, so one outer `run_code` invocation still produces exactly one card. ## Testing -Presenter unit coverage pins logs-only, result-only, logs-plus-result, no-output, failure, and spilled-result content. Every case proves stale metadata cannot replace the final content. +Presenter unit coverage pins logs-only, result-only, logs-plus-result, no-output, and spilled-result content. A separate integration-shaped unit drives a real runtime failure through the canonical registry result before presenting it. The successful cases prove stale metadata cannot replace final content; the failure case guards complete forwarding without claiming it reproduced the original metadata-triggered defect. The keyless ACP and TUI Code Mode snapshots execute one outer program that performs two nested bash calls, logs `captured output`, and returns `CODE_ONE+CODE_TWO`. Both surfaces show one completed outer card containing both lines and no nested cards. @@ -34,4 +34,4 @@ The keyless ACP and TUI Code Mode snapshots execute one outer program that perfo ## Consequences -ACP and TUI now display the same complete content the model receives and replay persists, including post-policy spill previews. The change adds or removes no event fields and requires no session-format bump. Existing and future replay records remain valid because the presenter ignores logs metadata when choosing card content and reads their durable rendered content. +ACP and TUI now display the same complete content the model receives and replay persists, including post-policy spill previews. New `run_code` results no longer carry the optional logs metadata, but this requires no session-format bump: existing records remain valid because the presenter ignores that field and reads their durable rendered content. diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md index 082e209544..619c742e6a 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md @@ -6,7 +6,7 @@ Status: implemented ## 问题 -外层 `run_code` 工具会持久化完整的渲染内容,但编辑器的卡片展示逻辑忽略了这些内容,转而根据仅含日志的 `presentationMeta` 投影重新构建卡片正文。仅有结果的运行看似正确,是因为展示逻辑未提供正文时,ACP 和 TUI 会回退到 `tool/result.content`。只要程序输出一条日志,展示逻辑就会提供非空内容,回退随即停止,返回值便会从完成态卡片中消失。失败文本以及输出落盘策略最终生成的头尾预览,也会受到同一职责拆分的影响。 +外层 `run_code` 工具会持久化完整的渲染内容,但编辑器的卡片展示逻辑忽略了这些内容,转而根据仅含日志的 `presentationMeta` 投影重新构建卡片正文。仅有结果的运行看似正确,是因为展示逻辑未提供正文时,ACP 和 TUI 会回退到 `tool/result.content`。只要程序输出一条日志,展示逻辑就会提供非空内容,回退随即停止,返回值便会从完成态卡片中消失。当已捕获的日志使陈旧投影变为非空时,输出落盘策略最终生成的头尾预览也会受到同一职责拆分的影响。 嵌套 Code 调用从不生成自己的卡片。因此,仅仅为了重建这一张不完整卡片而给外层调用生成元数据,还掩盖了每次外层调用只生成一张卡片的预期边界。 @@ -14,13 +14,13 @@ Status: implemented `run_code` 输出渲染器继续作为面向模型的外层内容的唯一所有者。它先渲染已捕获的日志,然后渲染返回值、显式的无输出标记,或规范工具流水线生成的失败内容。Post-execute 策略与输出落盘机制可以在内容持久化之前替换它。 -`run_code.presentResult` 会把最终的 `result.content` 转交给一张通用结果卡片。它有意省略标题,使待完成卡片保留程序文本。现有日志元数据仍保留在 `tool/result` 中,以维持 transcript(文本记录)兼容性;但展示逻辑不再把它视为第二个内容来源:`tool/result.content` 才是持久、可回放且经过 post-policy 处理的投影。 +`run_code.presentResult` 会把最终的 `result.content` 转交给一张通用结果卡片。它有意省略标题,使待完成卡片保留程序文本。多余的仅含日志的 `presentationMeta` 投影被移除:`tool/result.content` 是持久、可回放且经过 post-policy 处理的投影,也是卡片中结果内容的唯一来源。 嵌套分发保持不变。带有 `exec.parent` 标记的调用会发出有界的 `tool/code-dispatch` 诊断,但不会生成与 `tool/call` 或 `tool/result` 对应的界面卡片,因此一次外层 `run_code` 调用仍然只会生成一张卡片。 ## 测试 -展示逻辑的单元测试覆盖仅有日志、仅有结果、日志与结果并存、无输出、失败和结果落盘六种情况。每个用例都证明,陈旧元数据无法替换最终内容。 +展示逻辑的单元测试覆盖仅有日志、仅有结果、日志与结果并存、无输出和结果落盘时的内容。另一个具有集成测试形态的单元测试会触发真实的运行时失败,先让它经过规范注册表形成结果,再交给展示逻辑。成功场景证明陈旧元数据无法替换最终内容;失败场景则保护内容的完整转发,同时不声称它复现了最初由元数据触发的缺陷。 无密钥的 ACP 与 TUI Code Mode 快照会执行一个外层程序:程序进行两次嵌套 bash 调用,记录 `captured output`,并返回 `CODE_ONE+CODE_TWO`。两个界面都只显示一张完成态外层卡片,其中包含这两行内容,且没有嵌套卡片。 @@ -34,4 +34,4 @@ Status: implemented ## 影响 -ACP 和 TUI 会显示模型接收、回放持久化的同一份完整内容,其中包括 post-policy 输出落盘预览。该变更不增加或删除任何事件字段,也不需要提升会话格式版本。现有及未来的回放记录都保持有效,因为展示逻辑在选择卡片内容时会忽略日志元数据,转而读取记录中的持久化渲染内容。 +ACP 和 TUI 会显示模型接收、回放持久化的同一份完整内容,其中包括 post-policy 输出落盘预览。新的 `run_code` 结果不再携带可选的日志元数据,但无需提升会话格式版本:展示逻辑会忽略该字段并读取记录中持久化的渲染内容,因此现有记录仍然有效。 diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.md index 35d012435a..b845f6dde7 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.md @@ -48,7 +48,7 @@ Under `'code'` and `'both'` the registry owns `run_code` as a reserved presentat **Concurrency is serialized.** Each run owns a dispatch queue, so even `Promise.all` executes tool calls in submission order. Settlement abandons queued calls that have not started. Parallelism requires per-tool concurrency-safety metadata. -**Presentation.** `run_code`'s render intent is decided here per the [render-intent Agent Note](../architecture/2026-07-02-tool-render-intent-union.md): `presentCall` → a `generic` card, `kind: 'execute'`, title = the program text, `rawInput` = the same program text; `presentResult` → a `generic` card whose content is the final durable `tool/result.content`, including captured logs plus the returned value, failure, or post-policy spill preview. The existing logs metadata remains replayable but is not a second content source. The program is the title because ACP execute cards reliably render that field while some clients omit body and raw-input content. This is not a `terminal` card: that card's semantics are "a shell command in a working directory", which a program is not. See the [result-card completeness note](../bug-fix/2026-07-20-code-mode-result-card-completeness.md). +**Presentation.** `run_code`'s render intent is decided here per the [render-intent Agent Note](../architecture/2026-07-02-tool-render-intent-union.md): `presentCall` → a `generic` card, `kind: 'execute'`, title = the program text, `rawInput` = the same program text; `presentResult` → a `generic` card whose content is the final durable `tool/result.content`, including captured logs plus the returned value, failure, or post-policy spill preview. The program is the title because ACP execute cards reliably render that field while some clients omit body and raw-input content. This is not a `terminal` card: that card's semantics are "a shell command in a working directory", which a program is not. See the [result-card completeness note](../bug-fix/2026-07-20-code-mode-result-card-completeness.md). ### Observability: `tool/code-dispatch` diff --git a/examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl b/examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl index 46c8e41257..1289150dbf 100644 --- a/examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl +++ b/examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl @@ -21,7 +21,7 @@ {"type":"assistant/message","seq":19,"time":1783957884490,"data":{"turn":1,"step":2,"content":[{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\":\"return await tools.cordis_inspect({ what: 'dynamic' })\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[14,15,16,17,18],"surfaceOp":"append"} {"type":"tool/call","seq":20,"time":1783957884490,"data":{"turn":1,"step":2,"callId":"advanced-code","name":"run_code","arguments":"{\"code\":\"return await tools.cordis_inspect({ what: 'dynamic' })\"}"}} {"type":"tool/code-dispatch","seq":21,"time":1783957884560,"data":{"parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_inspect","arguments":{"what":"dynamic"},"isError":false,"resultSummary":"## dynamic\n- dyn-1: snapshot-marker [active]"}} -{"type":"tool/result","seq":22,"time":1783957884561,"data":{"turn":1,"step":2,"callId":"advanced-code","content":[{"type":"text","text":"## dynamic\n- dyn-1: snapshot-marker [active]"}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[20],"surfaceOp":"append"} +{"type":"tool/result","seq":22,"time":1783957884561,"data":{"turn":1,"step":2,"callId":"advanced-code","content":[{"type":"text","text":"## dynamic\n- dyn-1: snapshot-marker [active]"}],"isError":false},"sourceEventSeqs":[20],"surfaceOp":"append"} {"type":"step/end","seq":23,"time":1783957884561,"data":{"turn":1,"step":2}} {"type":"step/start","seq":24,"time":1783957884562,"data":{"turn":1,"step":3}} {"type":"assistant/chunk","seq":25,"time":1783950000026,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}} diff --git a/examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl b/examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl index df486f1360..e1eb777a1d 100644 --- a/examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl +++ b/examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl @@ -87,7 +87,7 @@ {"type":"assistant/message","seq":85,"time":1783611775503,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to use the `run_code` tool to execute a program that calls `tools.bash` with the command `echo BOTH_OK` and returns its output."},{"type":"tool-call","id":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","arguments":"{\"code\": \"const result = await tools.bash({ command: \\\"echo BOTH_OK\\\", description: \\\"Echo BOTH_OK\\\" });\\nreturn result.stdout.text;\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":5530,"outputTokens":108,"cacheReadTokens":0,"reasoningTokens":37}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84],"surfaceOp":"append"} {"type":"tool/call","seq":86,"time":1783611775504,"data":{"turn":1,"step":1,"callId":"call_00_AZFzvUwuC4vAUoICrfke5147","name":"run_code","arguments":"{\"code\": \"const result = await tools.bash({ command: \\\"echo BOTH_OK\\\", description: \\\"Echo BOTH_OK\\\" });\\nreturn result.stdout.text;\"}"}} {"type":"tool/code-dispatch","seq":87,"time":1783611775590,"data":{"parentCallId":"call_00_AZFzvUwuC4vAUoICrfke5147","subCallId":"call_00_AZFzvUwuC4vAUoICrfke5147:code:1","name":"bash","arguments":{"command":"echo BOTH_OK","description":"Echo BOTH_OK"},"isError":false,"resultSummary":"BOTH_OK\n"}} -{"type":"tool/result","seq":88,"time":1783611775592,"data":{"turn":1,"step":1,"callId":"call_00_AZFzvUwuC4vAUoICrfke5147","content":[{"type":"text","text":"BOTH_OK\n"}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[86],"surfaceOp":"append"} +{"type":"tool/result","seq":88,"time":1783611775592,"data":{"turn":1,"step":1,"callId":"call_00_AZFzvUwuC4vAUoICrfke5147","content":[{"type":"text","text":"BOTH_OK\n"}],"isError":false},"sourceEventSeqs":[86],"surfaceOp":"append"} {"type":"step/end","seq":89,"time":1783611775592,"data":{"turn":1,"step":1}} {"type":"step/start","seq":90,"time":1783611775592,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":91,"time":1783611776183,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/input.json b/examples/acp-agent/tests/snapshots/code-mode-turn/input.json index c6d4a1039e..03a3bca538 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/input.json +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/input.json @@ -2,6 +2,6 @@ "steps": [ { "op": "initialize" }, { "op": "newSession" }, - { "op": "prompt", "text": "Using ONE run_code program: call the bash tool twice — exactly `echo CODE_ONE` then exactly `echo CODE_TWO` — and return the two outputs joined with a plus sign. Then reply with that joined string only and stop." } + { "op": "prompt", "text": "Using ONE run_code program: call the bash tool twice — exactly `echo CODE_ONE` then exactly `echo CODE_TWO`. Inside that same program, console.log exactly `captured output`, then return the two outputs joined with a plus sign. Reply with that joined string only and stop." } ] } diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl b/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl index 84ebc9605a..336e230b61 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl @@ -1,150 +1,684 @@ -{"type":"session","version":0,"id":"94cd1ae4-e1d1-4ec8-9d27-50a1f849b6b3","createdAt":1783611771392,"cwd":"/var/folders/2c/psb0_fmx7hbgz558xjt_f0l00000gn/T/acp-snap-cwd-BteTVR","delegationDepth":0} -{"type":"turn/start","seq":0,"time":1783611771394,"data":{"turn":1,"trigger":{"kind":"message","source":{"kind":"user"}}}} -{"type":"user/message","seq":1,"time":1783611771394,"data":{"content":[{"type":"text","text":"Using ONE run_code program: call the bash tool twice — exactly `echo CODE_ONE` then exactly `echo CODE_TWO` — and return the two outputs joined with a plus sign. Then reply with that joined string only and stop."}],"source":{"kind":"user"}},"surfaceOp":"append"} -{"type":"step/start","seq":2,"time":1783611771396,"data":{"turn":1,"step":1}} -{"type":"request/header","seq":3,"time":1783611771396,"data":{"header":{"config":{"provider":"deepseek","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}} -{"type":"assistant/chunk","seq":4,"time":1783611771869,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} -{"type":"assistant/chunk","seq":5,"time":1783611771869,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"The"}}} -{"type":"assistant/chunk","seq":6,"time":1783611771978,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" user"}}} -{"type":"assistant/chunk","seq":7,"time":1783611772007,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" wants"}}} -{"type":"assistant/chunk","seq":8,"time":1783611772008,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" a"}}} -{"type":"assistant/chunk","seq":9,"time":1783611772036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" single"}}} -{"type":"assistant/chunk","seq":10,"time":1783611772036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" run"}}} -{"type":"assistant/chunk","seq":11,"time":1783611772036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_code"}}} -{"type":"assistant/chunk","seq":12,"time":1783611772036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" program"}}} -{"type":"assistant/chunk","seq":13,"time":1783611772036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" that"}}} -{"type":"assistant/chunk","seq":14,"time":1783611772089,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" calls"}}} -{"type":"assistant/chunk","seq":15,"time":1783611772089,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" bash"}}} -{"type":"assistant/chunk","seq":16,"time":1783611772089,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" twice"}}} -{"type":"assistant/chunk","seq":17,"time":1783611772096,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":","}}} -{"type":"assistant/chunk","seq":18,"time":1783611772124,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" then"}}} -{"type":"assistant/chunk","seq":19,"time":1783611772153,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" returns"}}} -{"type":"assistant/chunk","seq":20,"time":1783611772183,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} -{"type":"assistant/chunk","seq":21,"time":1783611772183,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" two"}}} -{"type":"assistant/chunk","seq":22,"time":1783611772211,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" outputs"}}} -{"type":"assistant/chunk","seq":23,"time":1783611772212,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" joined"}}} -{"type":"assistant/chunk","seq":24,"time":1783611772212,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} -{"type":"assistant/chunk","seq":25,"time":1783611772212,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" a"}}} -{"type":"assistant/chunk","seq":26,"time":1783611772212,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" plus"}}} -{"type":"assistant/chunk","seq":27,"time":1783611772212,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" sign"}}} -{"type":"assistant/chunk","seq":28,"time":1783611772241,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} -{"type":"assistant/chunk","seq":29,"time":1783611772241,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" Let"}}} -{"type":"assistant/chunk","seq":30,"time":1783611772241,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} -{"type":"assistant/chunk","seq":31,"time":1783611772241,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" write"}}} -{"type":"assistant/chunk","seq":32,"time":1783611772270,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" this"}}} -{"type":"assistant/chunk","seq":33,"time":1783611772270,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} -{"type":"assistant/chunk","seq":34,"time":1783611772361,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}}} -{"type":"assistant/chunk","seq":35,"time":1783611772361,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":""}}} -{"type":"assistant/chunk","seq":36,"time":1783611772361,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"{"}}} -{"type":"assistant/chunk","seq":37,"time":1783611772362,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} -{"type":"assistant/chunk","seq":38,"time":1783611772390,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"code"}}} -{"type":"assistant/chunk","seq":39,"time":1783611772390,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} -{"type":"assistant/chunk","seq":40,"time":1783611772390,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":": "}}} -{"type":"assistant/chunk","seq":41,"time":1783611772390,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} -{"type":"assistant/chunk","seq":42,"time":1783611772420,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"const"}}} -{"type":"assistant/chunk","seq":43,"time":1783611772420,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} -{"type":"assistant/chunk","seq":44,"time":1783611772420,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"1"}}} -{"type":"assistant/chunk","seq":45,"time":1783611772420,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" ="}}} -{"type":"assistant/chunk","seq":46,"time":1783611772421,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" await"}}} -{"type":"assistant/chunk","seq":47,"time":1783611772421,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" tools"}}} -{"type":"assistant/chunk","seq":48,"time":1783611772449,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".b"}}} -{"type":"assistant/chunk","seq":49,"time":1783611772449,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"ash"}}} -{"type":"assistant/chunk","seq":50,"time":1783611772449,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"({"}}} -{"type":"assistant/chunk","seq":51,"time":1783611772449,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" command"}}} -{"type":"assistant/chunk","seq":52,"time":1783611772478,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":":"}}} -{"type":"assistant/chunk","seq":53,"time":1783611772479,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\""}}} -{"type":"assistant/chunk","seq":54,"time":1783611772479,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"echo"}}} -{"type":"assistant/chunk","seq":55,"time":1783611772479,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" CODE"}}} -{"type":"assistant/chunk","seq":56,"time":1783611772479,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"_"}}} -{"type":"assistant/chunk","seq":57,"time":1783611772508,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"ONE"}}} -{"type":"assistant/chunk","seq":58,"time":1783611772510,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\","}}} -{"type":"assistant/chunk","seq":59,"time":1783611772510,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" description"}}} -{"type":"assistant/chunk","seq":60,"time":1783611772510,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":":"}}} -{"type":"assistant/chunk","seq":61,"time":1783611772510,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\""}}} -{"type":"assistant/chunk","seq":62,"time":1783611772510,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"First"}}} -{"type":"assistant/chunk","seq":63,"time":1783611772538,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" echo"}}} -{"type":"assistant/chunk","seq":64,"time":1783611772538,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\""}}} -{"type":"assistant/chunk","seq":65,"time":1783611772566,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" });\\n"}}} -{"type":"assistant/chunk","seq":66,"time":1783611772567,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"const"}}} -{"type":"assistant/chunk","seq":67,"time":1783611772567,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} -{"type":"assistant/chunk","seq":68,"time":1783611772567,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"2"}}} -{"type":"assistant/chunk","seq":69,"time":1783611772567,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" ="}}} -{"type":"assistant/chunk","seq":70,"time":1783611772567,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" await"}}} -{"type":"assistant/chunk","seq":71,"time":1783611772597,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" tools"}}} -{"type":"assistant/chunk","seq":72,"time":1783611772597,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".b"}}} -{"type":"assistant/chunk","seq":73,"time":1783611772597,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"ash"}}} -{"type":"assistant/chunk","seq":74,"time":1783611772598,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"({"}}} -{"type":"assistant/chunk","seq":75,"time":1783611772598,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" command"}}} -{"type":"assistant/chunk","seq":76,"time":1783611772598,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":":"}}} -{"type":"assistant/chunk","seq":77,"time":1783611772625,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\""}}} -{"type":"assistant/chunk","seq":78,"time":1783611772625,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"echo"}}} -{"type":"assistant/chunk","seq":79,"time":1783611772625,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" CODE"}}} -{"type":"assistant/chunk","seq":80,"time":1783611772626,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"_T"}}} -{"type":"assistant/chunk","seq":81,"time":1783611772626,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"WO"}}} -{"type":"assistant/chunk","seq":82,"time":1783611772626,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\","}}} -{"type":"assistant/chunk","seq":83,"time":1783611772654,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" description"}}} -{"type":"assistant/chunk","seq":84,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":":"}}} -{"type":"assistant/chunk","seq":85,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\""}}} -{"type":"assistant/chunk","seq":86,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"Second"}}} -{"type":"assistant/chunk","seq":87,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" echo"}}} -{"type":"assistant/chunk","seq":88,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\""}}} -{"type":"assistant/chunk","seq":89,"time":1783611772684,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" });\\n"}}} -{"type":"assistant/chunk","seq":90,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"console.log(\\\"captured output\\\");\\nreturn"}}} -{"type":"assistant/chunk","seq":91,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} -{"type":"assistant/chunk","seq":92,"time":1783611772713,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"1"}}} -{"type":"assistant/chunk","seq":93,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".stdout.text.trim"}}} -{"type":"assistant/chunk","seq":94,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"()"}}} -{"type":"assistant/chunk","seq":95,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" +"}}} -{"type":"assistant/chunk","seq":96,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\"+"}}} -{"type":"assistant/chunk","seq":97,"time":1783611772744,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\""}}} -{"type":"assistant/chunk","seq":98,"time":1783611772744,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" +"}}} -{"type":"assistant/chunk","seq":99,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} -{"type":"assistant/chunk","seq":100,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"2"}}} -{"type":"assistant/chunk","seq":101,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".stdout.text.trim"}}} -{"type":"assistant/chunk","seq":102,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"();"}}} -{"type":"assistant/chunk","seq":103,"time":1783611772772,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} -{"type":"assistant/chunk","seq":104,"time":1783611772773,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"}"}}} -{"type":"assistant/chunk","seq":105,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."}}}} -{"type":"assistant/chunk","seq":106,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}}}} -{"type":"assistant/chunk","seq":107,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}}}} -{"type":"assistant/chunk","seq":108,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} -{"type":"assistant/message","seq":109,"time":1783611772840,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."},{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108],"surfaceOp":"append"} -{"type":"tool/call","seq":110,"time":1783611772840,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}} -{"type":"tool/code-dispatch","seq":111,"time":1783611772933,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:1","name":"bash","arguments":{"command":"echo CODE_ONE","description":"First echo"},"isError":false,"resultSummary":"CODE_ONE\n"}} -{"type":"tool/code-dispatch","seq":112,"time":1783611772936,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:2","name":"bash","arguments":{"command":"echo CODE_TWO","description":"Second echo"},"isError":false,"resultSummary":"CODE_TWO\n"}} -{"type":"tool/result","seq":113,"time":1783611772937,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","content":[{"type":"text","text":"captured output\nCODE_ONE+CODE_TWO"}],"isError":false,"meta":{"logs":["captured output"]}},"sourceEventSeqs":[110],"surfaceOp":"append"} -{"type":"step/end","seq":114,"time":1783611772938,"data":{"turn":1,"step":1}} -{"type":"step/start","seq":115,"time":1783611772938,"data":{"turn":1,"step":2}} -{"type":"assistant/chunk","seq":116,"time":1783611773376,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} -{"type":"assistant/chunk","seq":117,"time":1783611773376,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"The"}}} -{"type":"assistant/chunk","seq":118,"time":1783611773480,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} -{"type":"assistant/chunk","seq":119,"time":1783611773511,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" is"}}} -{"type":"assistant/chunk","seq":120,"time":1783611773512,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" exactly"}}} -{"type":"assistant/chunk","seq":121,"time":1783611773540,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" what"}}} -{"type":"assistant/chunk","seq":122,"time":1783611773541,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} -{"type":"assistant/chunk","seq":123,"time":1783611773541,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" user"}}} -{"type":"assistant/chunk","seq":124,"time":1783611773569,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" asked"}}} -{"type":"assistant/chunk","seq":125,"time":1783611773570,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" for"}}} -{"type":"assistant/chunk","seq":126,"time":1783611773570,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} -{"type":"assistant/chunk","seq":127,"time":1783611773597,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} -{"type":"assistant/chunk","seq":128,"time":1783611773597,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} -{"type":"assistant/chunk","seq":129,"time":1783611773597,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} -{"type":"assistant/chunk","seq":130,"time":1783611773626,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"+"}}} -{"type":"assistant/chunk","seq":131,"time":1783611773627,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} -{"type":"assistant/chunk","seq":132,"time":1783611773627,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} -{"type":"assistant/chunk","seq":133,"time":1783611773627,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} -{"type":"assistant/chunk","seq":134,"time":1783611773654,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":1,"blockType":"text"}}} -{"type":"assistant/chunk","seq":135,"time":1783611773655,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"CODE"}}} -{"type":"assistant/chunk","seq":136,"time":1783611773655,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"_"}}} -{"type":"assistant/chunk","seq":137,"time":1783611773656,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"ONE"}}} -{"type":"assistant/chunk","seq":138,"time":1783611773656,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"+"}}} -{"type":"assistant/chunk","seq":139,"time":1783611773656,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"CODE"}}} -{"type":"assistant/chunk","seq":140,"time":1783611773657,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"_T"}}} -{"type":"assistant/chunk","seq":141,"time":1783611773685,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"WO"}}} -{"type":"assistant/chunk","seq":142,"time":1783611773686,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The output is exactly what the user asked for: CODE_ONE+CODE_TWO"}}}} -{"type":"assistant/chunk","seq":143,"time":1783611773686,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":1,"block":{"type":"text","text":"CODE_ONE+CODE_TWO"}}}} -{"type":"assistant/chunk","seq":144,"time":1783611773686,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":89,"outputTokens":25,"cacheReadTokens":3072,"reasoningTokens":17}}}} -{"type":"assistant/chunk","seq":145,"time":1783611773686,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"stop"}}}} -{"type":"assistant/message","seq":146,"time":1783611773687,"data":{"turn":1,"step":2,"content":[{"type":"reasoning","text":"The output is exactly what the user asked for: CODE_ONE+CODE_TWO"},{"type":"text","text":"CODE_ONE+CODE_TWO"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":89,"outputTokens":25,"cacheReadTokens":3072,"reasoningTokens":17}},"sourceEventSeqs":[116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145],"surfaceOp":"append"} -{"type":"step/end","seq":147,"time":1783611773687,"data":{"turn":1,"step":2}} -{"type":"turn/end","seq":148,"time":1783611773687,"data":{"turn":1,"reason":{"kind":"completed"}}} +{"type":"session","version":0,"id":"bfa65aa9-f8f8-4b91-af4b-9653cee8fc19","createdAt":1784629671301,"cwd":"/var/folders/2c/psb0_fmx7hbgz558xjt_f0l00000gn/T/acp-snap-cwd-QAp4c9","delegationDepth":0} +{"type":"turn/start","seq":0,"time":1784629671304,"data":{"turn":1,"trigger":{"kind":"message","source":{"kind":"user"}}}} +{"type":"user/message","seq":1,"time":1784629671305,"data":{"content":[{"type":"text","text":"Using ONE run_code program: call the bash tool twice — exactly `echo CODE_ONE` then exactly `echo CODE_TWO`. Inside that same program, console.log exactly `captured output`, then return the two outputs joined with a plus sign. Reply with that joined string only and stop."}],"source":{"kind":"user"}},"surfaceOp":"append"} +{"type":"step/start","seq":2,"time":1784629671311,"data":{"turn":1,"step":1}} +{"type":"request/header","seq":3,"time":1784629671312,"data":{"header":{"config":{"provider":"deepseek","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}} +{"type":"assistant/chunk","seq":4,"time":1784629671745,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} +{"type":"assistant/chunk","seq":5,"time":1784629671746,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"Let"}}} +{"type":"assistant/chunk","seq":6,"time":1784629671954,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} +{"type":"assistant/chunk","seq":7,"time":1784629671983,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" carefully"}}} +{"type":"assistant/chunk","seq":8,"time":1784629672017,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" read"}}} +{"type":"assistant/chunk","seq":9,"time":1784629672017,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":10,"time":1784629672039,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" instructions"}}} +{"type":"assistant/chunk","seq":11,"time":1784629672040,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":12,"time":1784629672040,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" I"}}} +{"type":"assistant/chunk","seq":13,"time":1784629672040,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" need"}}} +{"type":"assistant/chunk","seq":14,"time":1784629672040,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" to"}}} +{"type":"assistant/chunk","seq":15,"time":1784629672040,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" write"}}} +{"type":"assistant/chunk","seq":16,"time":1784629672068,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" ONE"}}} +{"type":"assistant/chunk","seq":17,"time":1784629672068,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" run"}}} +{"type":"assistant/chunk","seq":18,"time":1784629672068,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_code"}}} +{"type":"assistant/chunk","seq":19,"time":1784629672068,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" program"}}} +{"type":"assistant/chunk","seq":20,"time":1784629672096,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" that"}}} +{"type":"assistant/chunk","seq":21,"time":1784629672096,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":\n\n"}}} +{"type":"assistant/chunk","seq":22,"time":1784629672096,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"1"}}} +{"type":"assistant/chunk","seq":23,"time":1784629672096,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":24,"time":1784629672096,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" Calls"}}} +{"type":"assistant/chunk","seq":25,"time":1784629672125,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" bash"}}} +{"type":"assistant/chunk","seq":26,"time":1784629672125,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} +{"type":"assistant/chunk","seq":27,"time":1784629672125,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":28,"time":1784629672153,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"echo"}}} +{"type":"assistant/chunk","seq":29,"time":1784629672153,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":30,"time":1784629672153,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":31,"time":1784629672153,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":32,"time":1784629672153,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`"}}} +{"type":"assistant/chunk","seq":33,"time":1784629672187,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" -"}}} +{"type":"assistant/chunk","seq":34,"time":1784629672187,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" just"}}} +{"type":"assistant/chunk","seq":35,"time":1784629672210,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":36,"time":1784629672237,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" command"}}} +{"type":"assistant/chunk","seq":37,"time":1784629672238,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":38,"time":1784629672265,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"echo"}}} +{"type":"assistant/chunk","seq":39,"time":1784629672294,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":40,"time":1784629672294,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":41,"time":1784629672294,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":42,"time":1784629672295,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\"\n"}}} +{"type":"assistant/chunk","seq":43,"time":1784629672295,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"2"}}} +{"type":"assistant/chunk","seq":44,"time":1784629672295,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":45,"time":1784629672327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" Calls"}}} +{"type":"assistant/chunk","seq":46,"time":1784629672327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" bash"}}} +{"type":"assistant/chunk","seq":47,"time":1784629672327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} +{"type":"assistant/chunk","seq":48,"time":1784629672327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":49,"time":1784629672327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"echo"}}} +{"type":"assistant/chunk","seq":50,"time":1784629672327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":51,"time":1784629672351,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} +{"type":"assistant/chunk","seq":52,"time":1784629672351,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} +{"type":"assistant/chunk","seq":53,"time":1784629672351,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`"}}} +{"type":"assistant/chunk","seq":54,"time":1784629672351,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" -"}}} +{"type":"assistant/chunk","seq":55,"time":1784629672351,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" just"}}} +{"type":"assistant/chunk","seq":56,"time":1784629672351,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":57,"time":1784629672382,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" command"}}} +{"type":"assistant/chunk","seq":58,"time":1784629672382,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":59,"time":1784629672382,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"echo"}}} +{"type":"assistant/chunk","seq":60,"time":1784629672383,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":61,"time":1784629672383,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} +{"type":"assistant/chunk","seq":62,"time":1784629672383,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} +{"type":"assistant/chunk","seq":63,"time":1784629672410,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\"\n"}}} +{"type":"assistant/chunk","seq":64,"time":1784629672410,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"3"}}} +{"type":"assistant/chunk","seq":65,"time":1784629672410,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":66,"time":1784629672411,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" Inside"}}} +{"type":"assistant/chunk","seq":67,"time":1784629672438,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" that"}}} +{"type":"assistant/chunk","seq":68,"time":1784629672468,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" same"}}} +{"type":"assistant/chunk","seq":69,"time":1784629672468,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" program"}}} +{"type":"assistant/chunk","seq":70,"time":1784629672468,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":","}}} +{"type":"assistant/chunk","seq":71,"time":1784629672468,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" console"}}} +{"type":"assistant/chunk","seq":72,"time":1784629672468,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".log"}}} +{"type":"assistant/chunk","seq":73,"time":1784629672468,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" exactly"}}} +{"type":"assistant/chunk","seq":74,"time":1784629672495,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":75,"time":1784629672496,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"capt"}}} +{"type":"assistant/chunk","seq":76,"time":1784629672496,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ured"}}} +{"type":"assistant/chunk","seq":77,"time":1784629672496,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":78,"time":1784629672525,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`\n"}}} +{"type":"assistant/chunk","seq":79,"time":1784629672525,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"4"}}} +{"type":"assistant/chunk","seq":80,"time":1784629672525,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":81,"time":1784629672525,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" Return"}}} +{"type":"assistant/chunk","seq":82,"time":1784629672552,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":83,"time":1784629672552,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" two"}}} +{"type":"assistant/chunk","seq":84,"time":1784629672553,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" outputs"}}} +{"type":"assistant/chunk","seq":85,"time":1784629672553,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" joined"}}} +{"type":"assistant/chunk","seq":86,"time":1784629672553,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} +{"type":"assistant/chunk","seq":87,"time":1784629672553,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" a"}}} +{"type":"assistant/chunk","seq":88,"time":1784629672581,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" plus"}}} +{"type":"assistant/chunk","seq":89,"time":1784629672581,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" sign"}}} +{"type":"assistant/chunk","seq":90,"time":1784629672581,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\n\n"}}} +{"type":"assistant/chunk","seq":91,"time":1784629672581,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"Let"}}} +{"type":"assistant/chunk","seq":92,"time":1784629672610,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} +{"type":"assistant/chunk","seq":93,"time":1784629672610,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" look"}}} +{"type":"assistant/chunk","seq":94,"time":1784629672610,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" at"}}} +{"type":"assistant/chunk","seq":95,"time":1784629672610,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":96,"time":1784629672638,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" bash"}}} +{"type":"assistant/chunk","seq":97,"time":1784629672639,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" tool"}}} +{"type":"assistant/chunk","seq":98,"time":1784629672639,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" signature"}}} +{"type":"assistant/chunk","seq":99,"time":1784629672668,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" carefully"}}} +{"type":"assistant/chunk","seq":100,"time":1784629672668,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":101,"time":1784629672696,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" The"}}} +{"type":"assistant/chunk","seq":102,"time":1784629672696,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":103,"time":1784629672726,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"command"}}} +{"type":"assistant/chunk","seq":104,"time":1784629672726,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`"}}} +{"type":"assistant/chunk","seq":105,"time":1784629672726,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" parameter"}}} +{"type":"assistant/chunk","seq":106,"time":1784629672727,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" is"}}} +{"type":"assistant/chunk","seq":107,"time":1784629672758,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":108,"time":1784629672758,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" bash"}}} +{"type":"assistant/chunk","seq":109,"time":1784629672786,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" command"}}} +{"type":"assistant/chunk","seq":110,"time":1784629672786,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" to"}}} +{"type":"assistant/chunk","seq":111,"time":1784629672814,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" execute"}}} +{"type":"assistant/chunk","seq":112,"time":1784629672814,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":113,"time":1784629672814,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" So"}}} +{"type":"assistant/chunk","seq":114,"time":1784629672843,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" I"}}} +{"type":"assistant/chunk","seq":115,"time":1784629672843,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"'d"}}} +{"type":"assistant/chunk","seq":116,"time":1784629672871,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" pass"}}} +{"type":"assistant/chunk","seq":117,"time":1784629672871,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":118,"time":1784629672900,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"echo"}}} +{"type":"assistant/chunk","seq":119,"time":1784629672930,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":120,"time":1784629672931,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":121,"time":1784629672931,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":122,"time":1784629672931,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`"}}} +{"type":"assistant/chunk","seq":123,"time":1784629672931,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" as"}}} +{"type":"assistant/chunk","seq":124,"time":1784629672958,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":125,"time":1784629672958,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" command"}}} +{"type":"assistant/chunk","seq":126,"time":1784629672959,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".\n\n"}}} +{"type":"assistant/chunk","seq":127,"time":1784629672959,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"But"}}} +{"type":"assistant/chunk","seq":128,"time":1784629672959,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" wait"}}} +{"type":"assistant/chunk","seq":129,"time":1784629672989,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" -"}}} +{"type":"assistant/chunk","seq":130,"time":1784629672989,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" I"}}} +{"type":"assistant/chunk","seq":131,"time":1784629672989,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" need"}}} +{"type":"assistant/chunk","seq":132,"time":1784629673016,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" to"}}} +{"type":"assistant/chunk","seq":133,"time":1784629673016,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" be"}}} +{"type":"assistant/chunk","seq":134,"time":1784629673016,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" careful"}}} +{"type":"assistant/chunk","seq":135,"time":1784629673044,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" about"}}} +{"type":"assistant/chunk","seq":136,"time":1784629673044,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" what"}}} +{"type":"assistant/chunk","seq":137,"time":1784629673044,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":138,"time":1784629673073,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":139,"time":1784629673073,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" looks"}}} +{"type":"assistant/chunk","seq":140,"time":1784629673103,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" like"}}} +{"type":"assistant/chunk","seq":141,"time":1784629673103,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":142,"time":1784629673103,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" The"}}} +{"type":"assistant/chunk","seq":143,"time":1784629673103,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" bash"}}} +{"type":"assistant/chunk","seq":144,"time":1784629673130,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" tool"}}} +{"type":"assistant/chunk","seq":145,"time":1784629673130,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" returns"}}} +{"type":"assistant/chunk","seq":146,"time":1784629673159,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" stdout"}}} +{"type":"assistant/chunk","seq":147,"time":1784629673159,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"/st"}}} +{"type":"assistant/chunk","seq":148,"time":1784629673187,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"derr"}}} +{"type":"assistant/chunk","seq":149,"time":1784629673187,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" objects"}}} +{"type":"assistant/chunk","seq":150,"time":1784629673217,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":151,"time":1784629673218,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" Let"}}} +{"type":"assistant/chunk","seq":152,"time":1784629673218,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} +{"type":"assistant/chunk","seq":153,"time":1784629673218,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" check"}}} +{"type":"assistant/chunk","seq":154,"time":1784629673245,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":155,"time":1784629673245,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":156,"time":1784629673275,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" type"}}} +{"type":"assistant/chunk","seq":157,"time":1784629673302,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":\n\n"}}} +{"type":"assistant/chunk","seq":158,"time":1784629673302,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"```"}}} +{"type":"assistant/chunk","seq":159,"time":1784629673302,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ts"}}} +{"type":"assistant/chunk","seq":160,"time":1784629673303,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\n"}}} +{"type":"assistant/chunk","seq":161,"time":1784629673303,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"bash"}}} +{"type":"assistant/chunk","seq":162,"time":1784629673335,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":163,"time":1784629673335,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" {\n"}}} +{"type":"assistant/chunk","seq":164,"time":1784629673335,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" "}}} +{"type":"assistant/chunk","seq":165,"time":1784629673360,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" kind"}}} +{"type":"assistant/chunk","seq":166,"time":1784629673360,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":167,"time":1784629673360,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":168,"time":1784629673388,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"fore"}}} +{"type":"assistant/chunk","seq":169,"time":1784629673421,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ground"}}} +{"type":"assistant/chunk","seq":170,"time":1784629673421,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":171,"time":1784629673421,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" |"}}} +{"type":"assistant/chunk","seq":172,"time":1784629673422,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":173,"time":1784629673422,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"background"}}} +{"type":"assistant/chunk","seq":174,"time":1784629673448,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\";\n"}}} +{"type":"assistant/chunk","seq":175,"time":1784629673448,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" "}}} +{"type":"assistant/chunk","seq":176,"time":1784629673448,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" //"}}} +{"type":"assistant/chunk","seq":177,"time":1784629673477,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" if"}}} +{"type":"assistant/chunk","seq":178,"time":1784629673506,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" foreground"}}} +{"type":"assistant/chunk","seq":179,"time":1784629673507,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":\n"}}} +{"type":"assistant/chunk","seq":180,"time":1784629673507,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" "}}} +{"type":"assistant/chunk","seq":181,"time":1784629673534,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" exit"}}} +{"type":"assistant/chunk","seq":182,"time":1784629673534,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"Code"}}} +{"type":"assistant/chunk","seq":183,"time":1784629673534,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":184,"time":1784629673534,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" number"}}} +{"type":"assistant/chunk","seq":185,"time":1784629673534,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" |"}}} +{"type":"assistant/chunk","seq":186,"time":1784629673562,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" null"}}} +{"type":"assistant/chunk","seq":187,"time":1784629673562,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":";\n"}}} +{"type":"assistant/chunk","seq":188,"time":1784629673562,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" "}}} +{"type":"assistant/chunk","seq":189,"time":1784629673562,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" stdout"}}} +{"type":"assistant/chunk","seq":190,"time":1784629673590,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":191,"time":1784629673590,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" {"}}} +{"type":"assistant/chunk","seq":192,"time":1784629673618,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" text"}}} +{"type":"assistant/chunk","seq":193,"time":1784629673619,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":194,"time":1784629673619,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" string"}}} +{"type":"assistant/chunk","seq":195,"time":1784629673619,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":";"}}} +{"type":"assistant/chunk","seq":196,"time":1784629673619,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" truncated"}}} +{"type":"assistant/chunk","seq":197,"time":1784629673647,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":198,"time":1784629673647,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" boolean"}}} +{"type":"assistant/chunk","seq":199,"time":1784629673647,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":";"}}} +{"type":"assistant/chunk","seq":200,"time":1784629673647,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" spill"}}} +{"type":"assistant/chunk","seq":201,"time":1784629673675,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"Path"}}} +{"type":"assistant/chunk","seq":202,"time":1784629673676,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"?:"}}} +{"type":"assistant/chunk","seq":203,"time":1784629673676,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" string"}}} +{"type":"assistant/chunk","seq":204,"time":1784629673676,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":";"}}} +{"type":"assistant/chunk","seq":205,"time":1784629673728,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" };\n"}}} +{"type":"assistant/chunk","seq":206,"time":1784629673728,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" "}}} +{"type":"assistant/chunk","seq":207,"time":1784629673728,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" st"}}} +{"type":"assistant/chunk","seq":208,"time":1784629673728,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"derr"}}} +{"type":"assistant/chunk","seq":209,"time":1784629673728,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":210,"time":1784629673728,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" {"}}} +{"type":"assistant/chunk","seq":211,"time":1784629673728,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" text"}}} +{"type":"assistant/chunk","seq":212,"time":1784629673732,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":213,"time":1784629673733,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" string"}}} +{"type":"assistant/chunk","seq":214,"time":1784629673733,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":";"}}} +{"type":"assistant/chunk","seq":215,"time":1784629673733,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" ..."}}} +{"type":"assistant/chunk","seq":216,"time":1784629673782,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" };\n"}}} +{"type":"assistant/chunk","seq":217,"time":1784629673782,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" "}}} +{"type":"assistant/chunk","seq":218,"time":1784629673782,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" ...\n"}}} +{"type":"assistant/chunk","seq":219,"time":1784629673805,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"}\n"}}} +{"type":"assistant/chunk","seq":220,"time":1784629673805,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"```\n\n"}}} +{"type":"assistant/chunk","seq":221,"time":1784629673805,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"So"}}} +{"type":"assistant/chunk","seq":222,"time":1784629673805,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" I"}}} +{"type":"assistant/chunk","seq":223,"time":1784629673805,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" need"}}} +{"type":"assistant/chunk","seq":224,"time":1784629673838,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" to"}}} +{"type":"assistant/chunk","seq":225,"time":1784629673838,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" extract"}}} +{"type":"assistant/chunk","seq":226,"time":1784629673838,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":227,"time":1784629673866,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"std"}}} +{"type":"assistant/chunk","seq":228,"time":1784629673867,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"out"}}} +{"type":"assistant/chunk","seq":229,"time":1784629673867,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".text"}}} +{"type":"assistant/chunk","seq":230,"time":1784629673894,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`"}}} +{"type":"assistant/chunk","seq":231,"time":1784629673894,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" from"}}} +{"type":"assistant/chunk","seq":232,"time":1784629673894,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" each"}}} +{"type":"assistant/chunk","seq":233,"time":1784629673894,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" call"}}} +{"type":"assistant/chunk","seq":234,"time":1784629673983,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".\n\n"}}} +{"type":"assistant/chunk","seq":235,"time":1784629673983,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"Let"}}} +{"type":"assistant/chunk","seq":236,"time":1784629673983,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} +{"type":"assistant/chunk","seq":237,"time":1784629673983,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" also"}}} +{"type":"assistant/chunk","seq":238,"time":1784629673983,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" make"}}} +{"type":"assistant/chunk","seq":239,"time":1784629673983,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" sure"}}} +{"type":"assistant/chunk","seq":240,"time":1784629673983,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" about"}}} +{"type":"assistant/chunk","seq":241,"time":1784629674007,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":242,"time":1784629674007,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":243,"time":1784629674035,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"description"}}} +{"type":"assistant/chunk","seq":244,"time":1784629674036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`"}}} +{"type":"assistant/chunk","seq":245,"time":1784629674036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" parameter"}}} +{"type":"assistant/chunk","seq":246,"time":1784629674064,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" -"}}} +{"type":"assistant/chunk","seq":247,"time":1784629674064,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" it"}}} +{"type":"assistant/chunk","seq":248,"time":1784629674064,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"'s"}}} +{"type":"assistant/chunk","seq":249,"time":1784629674064,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" required"}}} +{"type":"assistant/chunk","seq":250,"time":1784629674092,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" and"}}} +{"type":"assistant/chunk","seq":251,"time":1784629674124,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" should"}}} +{"type":"assistant/chunk","seq":252,"time":1784629674153,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" be"}}} +{"type":"assistant/chunk","seq":253,"time":1784629674153,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":254,"time":1784629674181,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"5"}}} +{"type":"assistant/chunk","seq":255,"time":1784629674181,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"-"}}} +{"type":"assistant/chunk","seq":256,"time":1784629674181,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"10"}}} +{"type":"assistant/chunk","seq":257,"time":1784629674210,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" words"}}} +{"type":"assistant/chunk","seq":258,"time":1784629674210,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":259,"time":1784629674239,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" describing"}}} +{"type":"assistant/chunk","seq":260,"time":1784629674239,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":261,"time":1784629674270,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" command"}}} +{"type":"assistant/chunk","seq":262,"time":1784629674270,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".\n\n"}}} +{"type":"assistant/chunk","seq":263,"time":1784629674270,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"Let"}}} +{"type":"assistant/chunk","seq":264,"time":1784629674270,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} +{"type":"assistant/chunk","seq":265,"time":1784629674270,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" write"}}} +{"type":"assistant/chunk","seq":266,"time":1784629674296,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":267,"time":1784629674296,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" code"}}} +{"type":"assistant/chunk","seq":268,"time":1784629674327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":\n\n"}}} +{"type":"assistant/chunk","seq":269,"time":1784629674327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"```"}}} +{"type":"assistant/chunk","seq":270,"time":1784629674327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ts"}}} +{"type":"assistant/chunk","seq":271,"time":1784629674327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\n"}}} +{"type":"assistant/chunk","seq":272,"time":1784629674327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"const"}}} +{"type":"assistant/chunk","seq":273,"time":1784629674327,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" r"}}} +{"type":"assistant/chunk","seq":274,"time":1784629674354,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"1"}}} +{"type":"assistant/chunk","seq":275,"time":1784629674354,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" ="}}} +{"type":"assistant/chunk","seq":276,"time":1784629674354,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" await"}}} +{"type":"assistant/chunk","seq":277,"time":1784629674354,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" tools"}}} +{"type":"assistant/chunk","seq":278,"time":1784629674354,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".b"}}} +{"type":"assistant/chunk","seq":279,"time":1784629674354,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ash"}}} +{"type":"assistant/chunk","seq":280,"time":1784629674382,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"({"}}} +{"type":"assistant/chunk","seq":281,"time":1784629674382,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" command"}}} +{"type":"assistant/chunk","seq":282,"time":1784629674382,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":283,"time":1784629674382,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":284,"time":1784629674382,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"echo"}}} +{"type":"assistant/chunk","seq":285,"time":1784629674382,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":286,"time":1784629674411,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":287,"time":1784629674411,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":288,"time":1784629674411,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\","}}} +{"type":"assistant/chunk","seq":289,"time":1784629674411,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" description"}}} +{"type":"assistant/chunk","seq":290,"time":1784629674411,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":291,"time":1784629674411,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":292,"time":1784629674440,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"E"}}} +{"type":"assistant/chunk","seq":293,"time":1784629674440,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"cho"}}} +{"type":"assistant/chunk","seq":294,"time":1784629674472,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":295,"time":1784629674472,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":296,"time":1784629674472,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":297,"time":1784629674472,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" to"}}} +{"type":"assistant/chunk","seq":298,"time":1784629674501,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" stdout"}}} +{"type":"assistant/chunk","seq":299,"time":1784629674501,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":300,"time":1784629674501,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" });\n"}}} +{"type":"assistant/chunk","seq":301,"time":1784629674501,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"const"}}} +{"type":"assistant/chunk","seq":302,"time":1784629674501,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" r"}}} +{"type":"assistant/chunk","seq":303,"time":1784629674529,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"2"}}} +{"type":"assistant/chunk","seq":304,"time":1784629674529,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" ="}}} +{"type":"assistant/chunk","seq":305,"time":1784629674529,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" await"}}} +{"type":"assistant/chunk","seq":306,"time":1784629674529,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" tools"}}} +{"type":"assistant/chunk","seq":307,"time":1784629674529,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".b"}}} +{"type":"assistant/chunk","seq":308,"time":1784629674529,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ash"}}} +{"type":"assistant/chunk","seq":309,"time":1784629674561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"({"}}} +{"type":"assistant/chunk","seq":310,"time":1784629674561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" command"}}} +{"type":"assistant/chunk","seq":311,"time":1784629674561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":312,"time":1784629674561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":313,"time":1784629674561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"echo"}}} +{"type":"assistant/chunk","seq":314,"time":1784629674561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":315,"time":1784629674590,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} +{"type":"assistant/chunk","seq":316,"time":1784629674590,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} +{"type":"assistant/chunk","seq":317,"time":1784629674590,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\","}}} +{"type":"assistant/chunk","seq":318,"time":1784629674590,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" description"}}} +{"type":"assistant/chunk","seq":319,"time":1784629674590,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} +{"type":"assistant/chunk","seq":320,"time":1784629674591,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":321,"time":1784629674620,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"E"}}} +{"type":"assistant/chunk","seq":322,"time":1784629674620,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"cho"}}} +{"type":"assistant/chunk","seq":323,"time":1784629674620,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":324,"time":1784629674620,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} +{"type":"assistant/chunk","seq":325,"time":1784629674620,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} +{"type":"assistant/chunk","seq":326,"time":1784629674620,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" to"}}} +{"type":"assistant/chunk","seq":327,"time":1784629674650,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" stdout"}}} +{"type":"assistant/chunk","seq":328,"time":1784629674651,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":329,"time":1784629674651,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" });\n"}}} +{"type":"assistant/chunk","seq":330,"time":1784629674651,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"console"}}} +{"type":"assistant/chunk","seq":331,"time":1784629674651,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".log"}}} +{"type":"assistant/chunk","seq":332,"time":1784629674709,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"(\""}}} +{"type":"assistant/chunk","seq":333,"time":1784629674709,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"capt"}}} +{"type":"assistant/chunk","seq":334,"time":1784629674709,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ured"}}} +{"type":"assistant/chunk","seq":335,"time":1784629674709,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":336,"time":1784629674709,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\");\n"}}} +{"type":"assistant/chunk","seq":337,"time":1784629674709,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"return"}}} +{"type":"assistant/chunk","seq":338,"time":1784629674712,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" r"}}} +{"type":"assistant/chunk","seq":339,"time":1784629674741,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"1"}}} +{"type":"assistant/chunk","seq":340,"time":1784629674741,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".stdout"}}} +{"type":"assistant/chunk","seq":341,"time":1784629674741,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".text"}}} +{"type":"assistant/chunk","seq":342,"time":1784629674770,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".trim"}}} +{"type":"assistant/chunk","seq":343,"time":1784629674770,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"()"}}} +{"type":"assistant/chunk","seq":344,"time":1784629674770,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" +"}}} +{"type":"assistant/chunk","seq":345,"time":1784629674770,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \"+"}}} +{"type":"assistant/chunk","seq":346,"time":1784629674798,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":347,"time":1784629674798,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" +"}}} +{"type":"assistant/chunk","seq":348,"time":1784629674799,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" r"}}} +{"type":"assistant/chunk","seq":349,"time":1784629674799,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"2"}}} +{"type":"assistant/chunk","seq":350,"time":1784629674799,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".stdout"}}} +{"type":"assistant/chunk","seq":351,"time":1784629674799,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".text"}}} +{"type":"assistant/chunk","seq":352,"time":1784629674827,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".trim"}}} +{"type":"assistant/chunk","seq":353,"time":1784629674827,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"();\n"}}} +{"type":"assistant/chunk","seq":354,"time":1784629674827,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"```\n\n"}}} +{"type":"assistant/chunk","seq":355,"time":1784629674827,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"Let"}}} +{"type":"assistant/chunk","seq":356,"time":1784629674827,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} +{"type":"assistant/chunk","seq":357,"time":1784629674827,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" think"}}} +{"type":"assistant/chunk","seq":358,"time":1784629674855,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" about"}}} +{"type":"assistant/chunk","seq":359,"time":1784629674855,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":360,"time":1784629674883,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":361,"time":1784629674883,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" format"}}} +{"type":"assistant/chunk","seq":362,"time":1784629674911,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":363,"time":1784629674911,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":364,"time":1784629674911,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"echo"}}} +{"type":"assistant/chunk","seq":365,"time":1784629674940,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":366,"time":1784629674940,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":367,"time":1784629674940,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":368,"time":1784629674941,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`"}}} +{"type":"assistant/chunk","seq":369,"time":1784629674941,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" will"}}} +{"type":"assistant/chunk","seq":370,"time":1784629674969,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":371,"time":1784629674969,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":372,"time":1784629675000,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":373,"time":1784629675000,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":374,"time":1784629675000,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":375,"time":1784629675000,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\\n"}}} +{"type":"assistant/chunk","seq":376,"time":1784629675000,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`."}}} +{"type":"assistant/chunk","seq":377,"time":1784629675025,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" So"}}} +{"type":"assistant/chunk","seq":378,"time":1784629675055,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":379,"time":1784629675084,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"r"}}} +{"type":"assistant/chunk","seq":380,"time":1784629675084,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"1"}}} +{"type":"assistant/chunk","seq":381,"time":1784629675084,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".stdout"}}} +{"type":"assistant/chunk","seq":382,"time":1784629675111,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".text"}}} +{"type":"assistant/chunk","seq":383,"time":1784629675111,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`"}}} +{"type":"assistant/chunk","seq":384,"time":1784629675145,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" would"}}} +{"type":"assistant/chunk","seq":385,"time":1784629675145,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" be"}}} +{"type":"assistant/chunk","seq":386,"time":1784629675145,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":387,"time":1784629675145,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":388,"time":1784629675171,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":389,"time":1784629675171,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":390,"time":1784629675171,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":391,"time":1784629675172,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\\n"}}} +{"type":"assistant/chunk","seq":392,"time":1784629675172,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":393,"time":1784629675172,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`"}}} +{"type":"assistant/chunk","seq":394,"time":1784629675199,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" and"}}} +{"type":"assistant/chunk","seq":395,"time":1784629675199,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" after"}}} +{"type":"assistant/chunk","seq":396,"time":1784629675229,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" trim"}}} +{"type":"assistant/chunk","seq":397,"time":1784629675257,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" it"}}} +{"type":"assistant/chunk","seq":398,"time":1784629675257,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"'s"}}} +{"type":"assistant/chunk","seq":399,"time":1784629675257,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":400,"time":1784629675285,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":401,"time":1784629675286,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":402,"time":1784629675286,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":403,"time":1784629675286,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":404,"time":1784629675286,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":405,"time":1784629675318,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`.\n\n"}}} +{"type":"assistant/chunk","seq":406,"time":1784629675318,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"So"}}} +{"type":"assistant/chunk","seq":407,"time":1784629675360,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":408,"time":1784629675361,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" joined"}}} +{"type":"assistant/chunk","seq":409,"time":1784629675361,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" string"}}} +{"type":"assistant/chunk","seq":410,"time":1784629675370,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" would"}}} +{"type":"assistant/chunk","seq":411,"time":1784629675371,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" be"}}} +{"type":"assistant/chunk","seq":412,"time":1784629675371,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":413,"time":1784629675371,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":414,"time":1784629675399,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":415,"time":1784629675399,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":416,"time":1784629675399,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"+"}}} +{"type":"assistant/chunk","seq":417,"time":1784629675399,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":418,"time":1784629675399,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} +{"type":"assistant/chunk","seq":419,"time":1784629675427,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} +{"type":"assistant/chunk","seq":420,"time":1784629675428,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`.\n\n"}}} +{"type":"assistant/chunk","seq":421,"time":1784629675428,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"And"}}} +{"type":"assistant/chunk","seq":422,"time":1784629675456,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" console"}}} +{"type":"assistant/chunk","seq":423,"time":1784629675484,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".log"}}} +{"type":"assistant/chunk","seq":424,"time":1784629675484,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"(\""}}} +{"type":"assistant/chunk","seq":425,"time":1784629675515,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"capt"}}} +{"type":"assistant/chunk","seq":426,"time":1784629675515,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ured"}}} +{"type":"assistant/chunk","seq":427,"time":1784629675515,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":428,"time":1784629675515,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\")"}}} +{"type":"assistant/chunk","seq":429,"time":1784629675515,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" prints"}}} +{"type":"assistant/chunk","seq":430,"time":1784629675546,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":431,"time":1784629675579,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"capt"}}} +{"type":"assistant/chunk","seq":432,"time":1784629675579,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ured"}}} +{"type":"assistant/chunk","seq":433,"time":1784629675580,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":434,"time":1784629675580,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":435,"time":1784629675609,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" to"}}} +{"type":"assistant/chunk","seq":436,"time":1784629675609,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":437,"time":1784629675638,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" console"}}} +{"type":"assistant/chunk","seq":438,"time":1784629675667,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".\n\n"}}} +{"type":"assistant/chunk","seq":439,"time":1784629675667,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"The"}}} +{"type":"assistant/chunk","seq":440,"time":1784629675667,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" response"}}} +{"type":"assistant/chunk","seq":441,"time":1784629675695,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" comes"}}} +{"type":"assistant/chunk","seq":442,"time":1784629675724,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" back"}}} +{"type":"assistant/chunk","seq":443,"time":1784629675725,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" as"}}} +{"type":"assistant/chunk","seq":444,"time":1784629675756,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":445,"time":1784629675756,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" tool"}}} +{"type":"assistant/chunk","seq":446,"time":1784629675786,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" result"}}} +{"type":"assistant/chunk","seq":447,"time":1784629675786,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" which"}}} +{"type":"assistant/chunk","seq":448,"time":1784629675814,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" includes"}}} +{"type":"assistant/chunk","seq":449,"time":1784629675814,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" stdout"}}} +{"type":"assistant/chunk","seq":450,"time":1784629675843,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" and"}}} +{"type":"assistant/chunk","seq":451,"time":1784629675873,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":452,"time":1784629675901,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" return"}}} +{"type":"assistant/chunk","seq":453,"time":1784629675901,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" value"}}} +{"type":"assistant/chunk","seq":454,"time":1784629675901,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":455,"time":1784629675932,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" Since"}}} +{"type":"assistant/chunk","seq":456,"time":1784629675932,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":457,"time":1784629675932,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" return"}}} +{"type":"assistant/chunk","seq":458,"time":1784629675961,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" value"}}} +{"type":"assistant/chunk","seq":459,"time":1784629675991,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" is"}}} +{"type":"assistant/chunk","seq":460,"time":1784629675991,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" what"}}} +{"type":"assistant/chunk","seq":461,"time":1784629676026,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" we"}}} +{"type":"assistant/chunk","seq":462,"time":1784629676050,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" want"}}} +{"type":"assistant/chunk","seq":463,"time":1784629676077,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":","}}} +{"type":"assistant/chunk","seq":464,"time":1784629676077,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" and"}}} +{"type":"assistant/chunk","seq":465,"time":1784629676108,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":466,"time":1784629676108,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"reply"}}} +{"type":"assistant/chunk","seq":467,"time":1784629676136,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} +{"type":"assistant/chunk","seq":468,"time":1784629676167,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" that"}}} +{"type":"assistant/chunk","seq":469,"time":1784629676168,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" joined"}}} +{"type":"assistant/chunk","seq":470,"time":1784629676168,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" string"}}} +{"type":"assistant/chunk","seq":471,"time":1784629676168,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" only"}}} +{"type":"assistant/chunk","seq":472,"time":1784629676198,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" and"}}} +{"type":"assistant/chunk","seq":473,"time":1784629676198,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" stop"}}} +{"type":"assistant/chunk","seq":474,"time":1784629676198,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`"}}} +{"type":"assistant/chunk","seq":475,"time":1784629676227,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" -"}}} +{"type":"assistant/chunk","seq":476,"time":1784629676227,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" I"}}} +{"type":"assistant/chunk","seq":477,"time":1784629676258,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" think"}}} +{"type":"assistant/chunk","seq":478,"time":1784629676258,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":479,"time":1784629676286,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" return"}}} +{"type":"assistant/chunk","seq":480,"time":1784629676287,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" value"}}} +{"type":"assistant/chunk","seq":481,"time":1784629676287,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" of"}}} +{"type":"assistant/chunk","seq":482,"time":1784629676315,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":483,"time":1784629676315,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" run"}}} +{"type":"assistant/chunk","seq":484,"time":1784629676344,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_code"}}} +{"type":"assistant/chunk","seq":485,"time":1784629676344,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" function"}}} +{"type":"assistant/chunk","seq":486,"time":1784629676344,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" is"}}} +{"type":"assistant/chunk","seq":487,"time":1784629676344,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" what"}}} +{"type":"assistant/chunk","seq":488,"time":1784629676372,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" matters"}}} +{"type":"assistant/chunk","seq":489,"time":1784629676372,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":490,"time":1784629676400,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" But"}}} +{"type":"assistant/chunk","seq":491,"time":1784629676401,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" console"}}} +{"type":"assistant/chunk","seq":492,"time":1784629676430,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".log"}}} +{"type":"assistant/chunk","seq":493,"time":1784629676431,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":494,"time":1784629676459,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" also"}}} +{"type":"assistant/chunk","seq":495,"time":1784629676486,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" comes"}}} +{"type":"assistant/chunk","seq":496,"time":1784629676514,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" back"}}} +{"type":"assistant/chunk","seq":497,"time":1784629676514,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".\n\n"}}} +{"type":"assistant/chunk","seq":498,"time":1784629676514,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"Let"}}} +{"type":"assistant/chunk","seq":499,"time":1784629676543,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} +{"type":"assistant/chunk","seq":500,"time":1784629676543,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" just"}}} +{"type":"assistant/chunk","seq":501,"time":1784629676571,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" write"}}} +{"type":"assistant/chunk","seq":502,"time":1784629676599,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" it"}}} +{"type":"assistant/chunk","seq":503,"time":1784629676600,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" and"}}} +{"type":"assistant/chunk","seq":504,"time":1784629676600,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" see"}}} +{"type":"assistant/chunk","seq":505,"time":1784629676630,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":506,"time":1784629676713,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}}} +{"type":"assistant/chunk","seq":507,"time":1784629676713,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":""}}} +{"type":"assistant/chunk","seq":508,"time":1784629676742,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"{"}}} +{"type":"assistant/chunk","seq":509,"time":1784629676742,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\""}}} +{"type":"assistant/chunk","seq":510,"time":1784629676742,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"code"}}} +{"type":"assistant/chunk","seq":511,"time":1784629676742,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\""}}} +{"type":"assistant/chunk","seq":512,"time":1784629676742,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":": "}}} +{"type":"assistant/chunk","seq":513,"time":1784629676770,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\""}}} +{"type":"assistant/chunk","seq":514,"time":1784629676770,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\\n"}}} +{"type":"assistant/chunk","seq":515,"time":1784629676770,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"const"}}} +{"type":"assistant/chunk","seq":516,"time":1784629676770,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" r"}}} +{"type":"assistant/chunk","seq":517,"time":1784629676770,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"1"}}} +{"type":"assistant/chunk","seq":518,"time":1784629676770,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" ="}}} +{"type":"assistant/chunk","seq":519,"time":1784629676799,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" await"}}} +{"type":"assistant/chunk","seq":520,"time":1784629676799,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" tools"}}} +{"type":"assistant/chunk","seq":521,"time":1784629676799,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":".b"}}} +{"type":"assistant/chunk","seq":522,"time":1784629676799,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"ash"}}} +{"type":"assistant/chunk","seq":523,"time":1784629676799,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"({"}}} +{"type":"assistant/chunk","seq":524,"time":1784629676827,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" command"}}} +{"type":"assistant/chunk","seq":525,"time":1784629676828,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":":"}}} +{"type":"assistant/chunk","seq":526,"time":1784629676828,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" \\\""}}} +{"type":"assistant/chunk","seq":527,"time":1784629676828,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"echo"}}} +{"type":"assistant/chunk","seq":528,"time":1784629676828,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" CODE"}}} +{"type":"assistant/chunk","seq":529,"time":1784629676855,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"_"}}} +{"type":"assistant/chunk","seq":530,"time":1784629676856,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"ONE"}}} +{"type":"assistant/chunk","seq":531,"time":1784629676856,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\\\","}}} +{"type":"assistant/chunk","seq":532,"time":1784629676856,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" description"}}} +{"type":"assistant/chunk","seq":533,"time":1784629676856,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":":"}}} +{"type":"assistant/chunk","seq":534,"time":1784629676856,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" \\\""}}} +{"type":"assistant/chunk","seq":535,"time":1784629676883,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"E"}}} +{"type":"assistant/chunk","seq":536,"time":1784629676884,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"cho"}}} +{"type":"assistant/chunk","seq":537,"time":1784629676884,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" CODE"}}} +{"type":"assistant/chunk","seq":538,"time":1784629676884,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"_"}}} +{"type":"assistant/chunk","seq":539,"time":1784629676884,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"ONE"}}} +{"type":"assistant/chunk","seq":540,"time":1784629676884,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" to"}}} +{"type":"assistant/chunk","seq":541,"time":1784629676912,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" stdout"}}} +{"type":"assistant/chunk","seq":542,"time":1784629676912,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\\\""}}} +{"type":"assistant/chunk","seq":543,"time":1784629676912,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" });\\n"}}} +{"type":"assistant/chunk","seq":544,"time":1784629676912,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"const"}}} +{"type":"assistant/chunk","seq":545,"time":1784629676912,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" r"}}} +{"type":"assistant/chunk","seq":546,"time":1784629676912,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"2"}}} +{"type":"assistant/chunk","seq":547,"time":1784629676941,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" ="}}} +{"type":"assistant/chunk","seq":548,"time":1784629676941,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" await"}}} +{"type":"assistant/chunk","seq":549,"time":1784629676941,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" tools"}}} +{"type":"assistant/chunk","seq":550,"time":1784629676941,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":".b"}}} +{"type":"assistant/chunk","seq":551,"time":1784629676941,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"ash"}}} +{"type":"assistant/chunk","seq":552,"time":1784629676941,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"({"}}} +{"type":"assistant/chunk","seq":553,"time":1784629676972,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" command"}}} +{"type":"assistant/chunk","seq":554,"time":1784629676972,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":":"}}} +{"type":"assistant/chunk","seq":555,"time":1784629676972,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" \\\""}}} +{"type":"assistant/chunk","seq":556,"time":1784629676972,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"echo"}}} +{"type":"assistant/chunk","seq":557,"time":1784629676972,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" CODE"}}} +{"type":"assistant/chunk","seq":558,"time":1784629676972,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"_T"}}} +{"type":"assistant/chunk","seq":559,"time":1784629677001,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"WO"}}} +{"type":"assistant/chunk","seq":560,"time":1784629677001,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\\\","}}} +{"type":"assistant/chunk","seq":561,"time":1784629677001,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" description"}}} +{"type":"assistant/chunk","seq":562,"time":1784629677001,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":":"}}} +{"type":"assistant/chunk","seq":563,"time":1784629677001,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" \\\""}}} +{"type":"assistant/chunk","seq":564,"time":1784629677002,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"E"}}} +{"type":"assistant/chunk","seq":565,"time":1784629677029,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"cho"}}} +{"type":"assistant/chunk","seq":566,"time":1784629677029,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" CODE"}}} +{"type":"assistant/chunk","seq":567,"time":1784629677029,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"_T"}}} +{"type":"assistant/chunk","seq":568,"time":1784629677029,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"WO"}}} +{"type":"assistant/chunk","seq":569,"time":1784629677029,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" to"}}} +{"type":"assistant/chunk","seq":570,"time":1784629677029,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" stdout"}}} +{"type":"assistant/chunk","seq":571,"time":1784629677058,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\\\""}}} +{"type":"assistant/chunk","seq":572,"time":1784629677058,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" });\\n"}}} +{"type":"assistant/chunk","seq":573,"time":1784629677058,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"console"}}} +{"type":"assistant/chunk","seq":574,"time":1784629677058,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":".log"}}} +{"type":"assistant/chunk","seq":575,"time":1784629677058,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"(\\\""}}} +{"type":"assistant/chunk","seq":576,"time":1784629677058,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"capt"}}} +{"type":"assistant/chunk","seq":577,"time":1784629677086,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"ured"}}} +{"type":"assistant/chunk","seq":578,"time":1784629677086,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" output"}}} +{"type":"assistant/chunk","seq":579,"time":1784629677086,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\\\");\\n"}}} +{"type":"assistant/chunk","seq":580,"time":1784629677086,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"return"}}} +{"type":"assistant/chunk","seq":581,"time":1784629677086,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" r"}}} +{"type":"assistant/chunk","seq":582,"time":1784629677086,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"1"}}} +{"type":"assistant/chunk","seq":583,"time":1784629677114,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":".stdout"}}} +{"type":"assistant/chunk","seq":584,"time":1784629677115,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":".text"}}} +{"type":"assistant/chunk","seq":585,"time":1784629677143,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":".trim"}}} +{"type":"assistant/chunk","seq":586,"time":1784629677143,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"()"}}} +{"type":"assistant/chunk","seq":587,"time":1784629677143,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" +"}}} +{"type":"assistant/chunk","seq":588,"time":1784629677143,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" \\\"+"}}} +{"type":"assistant/chunk","seq":589,"time":1784629677172,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\\\""}}} +{"type":"assistant/chunk","seq":590,"time":1784629677172,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" +"}}} +{"type":"assistant/chunk","seq":591,"time":1784629677172,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":" r"}}} +{"type":"assistant/chunk","seq":592,"time":1784629677172,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"2"}}} +{"type":"assistant/chunk","seq":593,"time":1784629677172,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":".stdout"}}} +{"type":"assistant/chunk","seq":594,"time":1784629677172,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":".text"}}} +{"type":"assistant/chunk","seq":595,"time":1784629677200,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":".trim"}}} +{"type":"assistant/chunk","seq":596,"time":1784629677200,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"();\\n"}}} +{"type":"assistant/chunk","seq":597,"time":1784629677200,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"\""}}} +{"type":"assistant/chunk","seq":598,"time":1784629677231,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","argumentsDelta":"}"}}} +{"type":"assistant/chunk","seq":599,"time":1784629677261,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"Let me carefully read the instructions. I need to write ONE run_code program that:\n\n1. Calls bash with `echo CODE_ONE` - just the command \"echo CODE_ONE\"\n2. Calls bash with `echo CODE_TWO` - just the command \"echo CODE_TWO\"\n3. Inside that same program, console.log exactly `captured output`\n4. Return the two outputs joined with a plus sign\n\nLet me look at the bash tool signature carefully. The `command` parameter is the bash command to execute. So I'd pass `echo CODE_ONE` as the command.\n\nBut wait - I need to be careful about what the output looks like. The bash tool returns stdout/stderr objects. Let me check the output type:\n\n```ts\nbash: {\n kind: \"foreground\" | \"background\";\n // if foreground:\n exitCode: number | null;\n stdout: { text: string; truncated: boolean; spillPath?: string; };\n stderr: { text: string; ... };\n ...\n}\n```\n\nSo I need to extract `stdout.text` from each call.\n\nLet me also make sure about the `description` parameter - it's required and should be \"5-10 words\" describing the command.\n\nLet me write the code:\n\n```ts\nconst r1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"Echo CODE_ONE to stdout\" });\nconst r2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Echo CODE_TWO to stdout\" });\nconsole.log(\"captured output\");\nreturn r1.stdout.text.trim() + \"+\" + r2.stdout.text.trim();\n```\n\nLet me think about the output format. `echo CODE_ONE` will output `CODE_ONE\\n`. So `r1.stdout.text` would be `\"CODE_ONE\\n\"` and after trim it's `\"CODE_ONE\"`.\n\nSo the joined string would be `CODE_ONE+CODE_TWO`.\n\nAnd console.log(\"captured output\") prints \"captured output\" to the console.\n\nThe response comes back as the tool result which includes stdout and the return value. Since the return value is what we want, and `reply with that joined string only and stop` - I think the return value of the run_code function is what matters. But console.log output also comes back.\n\nLet me just write it and see."}}}} +{"type":"assistant/chunk","seq":600,"time":1784629677261,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","arguments":"{\"code\": \"\\nconst r1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"Echo CODE_ONE to stdout\\\" });\\nconst r2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Echo CODE_TWO to stdout\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn r1.stdout.text.trim() + \\\"+\\\" + r2.stdout.text.trim();\\n\"}"}}}} +{"type":"assistant/chunk","seq":601,"time":1784629677261,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":6005,"outputTokens":626,"cacheReadTokens":0,"reasoningTokens":501}}}} +{"type":"assistant/chunk","seq":602,"time":1784629677261,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} +{"type":"assistant/message","seq":603,"time":1784629677264,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"Let me carefully read the instructions. I need to write ONE run_code program that:\n\n1. Calls bash with `echo CODE_ONE` - just the command \"echo CODE_ONE\"\n2. Calls bash with `echo CODE_TWO` - just the command \"echo CODE_TWO\"\n3. Inside that same program, console.log exactly `captured output`\n4. Return the two outputs joined with a plus sign\n\nLet me look at the bash tool signature carefully. The `command` parameter is the bash command to execute. So I'd pass `echo CODE_ONE` as the command.\n\nBut wait - I need to be careful about what the output looks like. The bash tool returns stdout/stderr objects. Let me check the output type:\n\n```ts\nbash: {\n kind: \"foreground\" | \"background\";\n // if foreground:\n exitCode: number | null;\n stdout: { text: string; truncated: boolean; spillPath?: string; };\n stderr: { text: string; ... };\n ...\n}\n```\n\nSo I need to extract `stdout.text` from each call.\n\nLet me also make sure about the `description` parameter - it's required and should be \"5-10 words\" describing the command.\n\nLet me write the code:\n\n```ts\nconst r1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"Echo CODE_ONE to stdout\" });\nconst r2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Echo CODE_TWO to stdout\" });\nconsole.log(\"captured output\");\nreturn r1.stdout.text.trim() + \"+\" + r2.stdout.text.trim();\n```\n\nLet me think about the output format. `echo CODE_ONE` will output `CODE_ONE\\n`. So `r1.stdout.text` would be `\"CODE_ONE\\n\"` and after trim it's `\"CODE_ONE\"`.\n\nSo the joined string would be `CODE_ONE+CODE_TWO`.\n\nAnd console.log(\"captured output\") prints \"captured output\" to the console.\n\nThe response comes back as the tool result which includes stdout and the return value. Since the return value is what we want, and `reply with that joined string only and stop` - I think the return value of the run_code function is what matters. But console.log output also comes back.\n\nLet me just write it and see."},{"type":"tool-call","id":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","arguments":"{\"code\": \"\\nconst r1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"Echo CODE_ONE to stdout\\\" });\\nconst r2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Echo CODE_TWO to stdout\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn r1.stdout.text.trim() + \\\"+\\\" + r2.stdout.text.trim();\\n\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":6005,"outputTokens":626,"cacheReadTokens":0,"reasoningTokens":501}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602],"surfaceOp":"append"} +{"type":"tool/call","seq":604,"time":1784629677264,"data":{"turn":1,"step":1,"callId":"call_00_9r18203KAw8KCXThwJ7k3704","name":"run_code","arguments":"{\"code\": \"\\nconst r1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"Echo CODE_ONE to stdout\\\" });\\nconst r2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Echo CODE_TWO to stdout\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn r1.stdout.text.trim() + \\\"+\\\" + r2.stdout.text.trim();\\n\"}"}} +{"type":"tool/code-dispatch","seq":605,"time":1784629677359,"data":{"parentCallId":"call_00_9r18203KAw8KCXThwJ7k3704","subCallId":"call_00_9r18203KAw8KCXThwJ7k3704:code:1","name":"bash","arguments":{"command":"echo CODE_ONE","description":"Echo CODE_ONE to stdout"},"isError":false,"resultSummary":"CODE_ONE\n"}} +{"type":"tool/code-dispatch","seq":606,"time":1784629677361,"data":{"parentCallId":"call_00_9r18203KAw8KCXThwJ7k3704","subCallId":"call_00_9r18203KAw8KCXThwJ7k3704:code:2","name":"bash","arguments":{"command":"echo CODE_TWO","description":"Echo CODE_TWO to stdout"},"isError":false,"resultSummary":"CODE_TWO\n"}} +{"type":"tool/result","seq":607,"time":1784629677363,"data":{"turn":1,"step":1,"callId":"call_00_9r18203KAw8KCXThwJ7k3704","content":[{"type":"text","text":"captured output\nCODE_ONE+CODE_TWO"}],"isError":false},"sourceEventSeqs":[604],"surfaceOp":"append"} +{"type":"step/end","seq":608,"time":1784629677365,"data":{"turn":1,"step":1}} +{"type":"step/start","seq":609,"time":1784629677366,"data":{"turn":1,"step":2}} +{"type":"assistant/chunk","seq":610,"time":1784629677997,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} +{"type":"assistant/chunk","seq":611,"time":1784629677997,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"The"}}} +{"type":"assistant/chunk","seq":612,"time":1784629678140,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":613,"time":1784629678165,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" shows"}}} +{"type":"assistant/chunk","seq":614,"time":1784629678193,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":":\n"}}} +{"type":"assistant/chunk","seq":615,"time":1784629678193,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"-"}}} +{"type":"assistant/chunk","seq":616,"time":1784629678221,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":617,"time":1784629678221,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"capt"}}} +{"type":"assistant/chunk","seq":618,"time":1784629678222,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"ured"}}} +{"type":"assistant/chunk","seq":619,"time":1784629678222,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":620,"time":1784629678249,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":621,"time":1784629678249,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" ("}}} +{"type":"assistant/chunk","seq":622,"time":1784629678250,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"from"}}} +{"type":"assistant/chunk","seq":623,"time":1784629678278,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" console"}}} +{"type":"assistant/chunk","seq":624,"time":1784629678278,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":".log"}}} +{"type":"assistant/chunk","seq":625,"time":1784629678278,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":")\n"}}} +{"type":"assistant/chunk","seq":626,"time":1784629678279,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"-"}}} +{"type":"assistant/chunk","seq":627,"time":1784629678279,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":628,"time":1784629678306,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":629,"time":1784629678306,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":630,"time":1784629678306,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":631,"time":1784629678306,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"+"}}} +{"type":"assistant/chunk","seq":632,"time":1784629678306,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":633,"time":1784629678306,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} +{"type":"assistant/chunk","seq":634,"time":1784629678334,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} +{"type":"assistant/chunk","seq":635,"time":1784629678334,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"\""}}} +{"type":"assistant/chunk","seq":636,"time":1784629678334,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" ("}}} +{"type":"assistant/chunk","seq":637,"time":1784629678334,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"the"}}} +{"type":"assistant/chunk","seq":638,"time":1784629678361,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" return"}}} +{"type":"assistant/chunk","seq":639,"time":1784629678362,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" value"}}} +{"type":"assistant/chunk","seq":640,"time":1784629678362,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":")\n\n"}}} +{"type":"assistant/chunk","seq":641,"time":1784629678362,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"The"}}} +{"type":"assistant/chunk","seq":642,"time":1784629678362,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" instructions"}}} +{"type":"assistant/chunk","seq":643,"time":1784629678390,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" say"}}} +{"type":"assistant/chunk","seq":644,"time":1784629678391,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":645,"time":1784629678391,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"Reply"}}} +{"type":"assistant/chunk","seq":646,"time":1784629678417,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} +{"type":"assistant/chunk","seq":647,"time":1784629678417,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" that"}}} +{"type":"assistant/chunk","seq":648,"time":1784629678417,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" joined"}}} +{"type":"assistant/chunk","seq":649,"time":1784629678418,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" string"}}} +{"type":"assistant/chunk","seq":650,"time":1784629678445,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" only"}}} +{"type":"assistant/chunk","seq":651,"time":1784629678446,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" and"}}} +{"type":"assistant/chunk","seq":652,"time":1784629678446,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" stop"}}} +{"type":"assistant/chunk","seq":653,"time":1784629678473,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":".\""}}} +{"type":"assistant/chunk","seq":654,"time":1784629678474,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" So"}}} +{"type":"assistant/chunk","seq":655,"time":1784629678474,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" I"}}} +{"type":"assistant/chunk","seq":656,"time":1784629678474,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" should"}}} +{"type":"assistant/chunk","seq":657,"time":1784629678501,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" reply"}}} +{"type":"assistant/chunk","seq":658,"time":1784629678501,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} +{"type":"assistant/chunk","seq":659,"time":1784629678502,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" \""}}} +{"type":"assistant/chunk","seq":660,"time":1784629678529,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":661,"time":1784629678529,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":662,"time":1784629678529,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":663,"time":1784629678529,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"+"}}} +{"type":"assistant/chunk","seq":664,"time":1784629678529,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":665,"time":1784629678530,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} +{"type":"assistant/chunk","seq":666,"time":1784629678557,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} +{"type":"assistant/chunk","seq":667,"time":1784629678558,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"\"."}}} +{"type":"assistant/chunk","seq":668,"time":1784629678558,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":1,"blockType":"text"}}} +{"type":"assistant/chunk","seq":669,"time":1784629678558,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"CODE"}}} +{"type":"assistant/chunk","seq":670,"time":1784629678558,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"_"}}} +{"type":"assistant/chunk","seq":671,"time":1784629678558,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"ONE"}}} +{"type":"assistant/chunk","seq":672,"time":1784629678587,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"+"}}} +{"type":"assistant/chunk","seq":673,"time":1784629678587,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"CODE"}}} +{"type":"assistant/chunk","seq":674,"time":1784629678587,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"_T"}}} +{"type":"assistant/chunk","seq":675,"time":1784629678587,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"WO"}}} +{"type":"assistant/chunk","seq":676,"time":1784629678587,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The output shows:\n- \"captured output\" (from console.log)\n- \"CODE_ONE+CODE_TWO\" (the return value)\n\nThe instructions say \"Reply with that joined string only and stop.\" So I should reply with \"CODE_ONE+CODE_TWO\"."}}}} +{"type":"assistant/chunk","seq":677,"time":1784629678587,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":1,"block":{"type":"text","text":"CODE_ONE+CODE_TWO"}}}} +{"type":"assistant/chunk","seq":678,"time":1784629678587,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":766,"outputTokens":65,"cacheReadTokens":5888,"reasoningTokens":57}}}} +{"type":"assistant/chunk","seq":679,"time":1784629678587,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"stop"}}}} +{"type":"assistant/message","seq":680,"time":1784629678588,"data":{"turn":1,"step":2,"content":[{"type":"reasoning","text":"The output shows:\n- \"captured output\" (from console.log)\n- \"CODE_ONE+CODE_TWO\" (the return value)\n\nThe instructions say \"Reply with that joined string only and stop.\" So I should reply with \"CODE_ONE+CODE_TWO\"."},{"type":"text","text":"CODE_ONE+CODE_TWO"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":766,"outputTokens":65,"cacheReadTokens":5888,"reasoningTokens":57}},"sourceEventSeqs":[610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679],"surfaceOp":"append"} +{"type":"step/end","seq":681,"time":1784629678588,"data":{"turn":1,"step":2}} +{"type":"turn/end","seq":682,"time":1784629678588,"data":{"turn":1,"reason":{"kind":"completed"}}} diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl b/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl index ce9167133f..b661ef33b1 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl @@ -1,21 +1,83 @@ {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":1,"agentInfo":{"name":"deepseek-harness-acp","version":"0.0.1"},"agentCapabilities":{"loadSession":true,"promptCapabilities":{"image":false,"audio":false,"embeddedContext":false}},"authMethods":[]}} {"jsonrpc":"2.0","id":2,"result":{"sessionId":"{{sessionId}}","configOptions":[{"id":"model","name":"Model","description":"Sets this session's provider and model.","category":"model","type":"select","currentValue":"[\"deepseek\",\"deepseek-v4-flash\"]","options":[{"value":"[\"deepseek\",\"deepseek-v4-flash\"]","name":"deepseek-v4-flash"},{"value":"[\"deepseek\",\"deepseek-v4-pro\"]","name":"deepseek-v4-pro"}]},{"id":"permission","name":"Permissions","description":"The session permission preset: each choice bundles a sandbox mode and an approval policy.","category":"mode","type":"select","currentValue":"danger-full-access","options":[{"value":"workspace-write","name":"workspace-write","description":"Write inside the workspace and permitted temporary directories; wider retries require approval."},{"value":"danger-full-access","name":"danger-full-access","description":"Full file access without approval prompts."}]}]}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"available_commands_update","availableCommands":[{"name":"goal","description":"set or view the goal for a long-running task","input":{"hint":"[<objective>|clear|edit <objective>|pause|resume]"}}]}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"The"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" user"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" wants"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" a"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" single"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"Let"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" me"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" carefully"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" read"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" instructions"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" I"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" need"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" to"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" write"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" ONE"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" run"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_code"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" program"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" that"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" calls"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"1"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" Calls"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" bash"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" twice"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" with"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"echo"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" -"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" just"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" command"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"echo"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\"\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"2"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" Calls"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" bash"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" with"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"echo"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_T"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"WO"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" -"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" just"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" command"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"echo"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_T"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"WO"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\"\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"3"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" Inside"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" that"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" same"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" program"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":","}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" then"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" returns"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" console"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".log"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" exactly"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"capt"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ured"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"4"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" Return"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" two"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" outputs"}}}} @@ -24,31 +86,481 @@ {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" a"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" plus"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" sign"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"Let"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" me"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" look"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" at"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" bash"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" tool"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" signature"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" carefully"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" The"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"command"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" parameter"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" is"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" bash"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" command"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" to"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" execute"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" So"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" I"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"'d"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" pass"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"echo"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" as"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" command"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"But"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" wait"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" -"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" I"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" need"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" to"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" be"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" careful"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" about"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" what"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" looks"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" like"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" The"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" bash"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" tool"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" returns"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" stdout"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"/st"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"derr"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" objects"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" Let"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" me"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" write"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" this"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","title":"const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" });\nconst out2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Second echo\" });\nconsole.log(\"captured output\");\nreturn out1.stdout.text.trim() + \"+\" + out2.stdout.text.trim();","kind":"execute","status":"in_progress","rawInput":"const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" });\nconst out2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Second echo\" });\nconsole.log(\"captured output\");\nreturn out1.stdout.text.trim() + \"+\" + out2.stdout.text.trim();"}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","status":"completed","content":[{"type":"content","content":{"type":"text","text":"captured output\nCODE_ONE+CODE_TWO"}}]}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"The"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" is"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" exactly"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" what"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" check"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" user"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" asked"}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" for"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" type"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"```"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ts"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"bash"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" {\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" "}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" kind"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"fore"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ground"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" |"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"background"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\";\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" "}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" //"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" if"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" foreground"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" "}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" exit"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"Code"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" number"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" |"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" null"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":";\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" "}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" stdout"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" {"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" text"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" string"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":";"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" truncated"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" boolean"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":";"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" spill"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"Path"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"?:"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" string"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":";"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" };\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" "}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" st"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"derr"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" {"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" text"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" string"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":";"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" ..."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" };\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" "}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" ...\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"}\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"```\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"So"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" I"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" need"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" to"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" extract"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"std"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"out"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".text"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" from"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" each"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" call"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"Let"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" me"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" also"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" make"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" sure"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" about"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"description"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" parameter"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" -"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" it"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"'s"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" required"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" and"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" should"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" be"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"5"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"-"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"10"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" words"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" describing"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" command"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"Let"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" me"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" write"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" code"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"```"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ts"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"const"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" r"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"1"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" ="}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" await"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" tools"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".b"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ash"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"({"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" command"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"echo"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" CODE"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\","}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" description"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"E"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"cho"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" to"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" stdout"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" });\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"const"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" r"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"2"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" ="}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" await"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" tools"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".b"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ash"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"({"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" command"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"echo"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_T"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"WO"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\","}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" description"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"E"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"cho"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_T"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"WO"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" to"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" stdout"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" });\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"console"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".log"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"(\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"capt"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ured"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\");\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"return"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" r"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"1"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".stdout"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".text"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".trim"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"()"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" +"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \"+"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" +"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" r"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"2"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".stdout"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".text"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".trim"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"();\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"```\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"Let"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" me"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" think"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" about"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" format"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"echo"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" will"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" So"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"r"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"1"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".stdout"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".text"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" would"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" be"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" and"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" after"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" trim"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" it"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"'s"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`.\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"So"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" joined"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" string"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" would"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" be"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"+"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"CODE"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_T"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"WO"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`.\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"And"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" console"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".log"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"(\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"capt"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ured"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\")"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" prints"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"capt"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ured"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" to"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" console"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"The"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" response"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" comes"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" back"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" as"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" tool"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" result"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" which"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" includes"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" stdout"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" and"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" return"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" value"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" Since"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" return"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" value"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" is"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" what"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" we"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" want"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":","}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" and"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" `"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"reply"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" with"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" that"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" joined"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" string"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" only"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" and"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" stop"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"`"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" -"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" I"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" think"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" return"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" value"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" of"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" run"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_code"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" function"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" is"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" what"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" matters"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" But"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" console"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".log"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" also"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" comes"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" back"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"Let"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" me"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" just"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" write"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" it"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" and"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" see"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"."}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_00_9r18203KAw8KCXThwJ7k3704","title":"\nconst r1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"Echo CODE_ONE to stdout\" });\nconst r2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Echo CODE_TWO to stdout\" });\nconsole.log(\"captured output\");\nreturn r1.stdout.text.trim() + \"+\" + r2.stdout.text.trim();\n","kind":"execute","status":"in_progress","rawInput":"\nconst r1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"Echo CODE_ONE to stdout\" });\nconst r2 = await tools.bash({ command: \"echo CODE_TWO\", description: \"Echo CODE_TWO to stdout\" });\nconsole.log(\"captured output\");\nreturn r1.stdout.text.trim() + \"+\" + r2.stdout.text.trim();\n"}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_00_9r18203KAw8KCXThwJ7k3704","status":"completed","content":[{"type":"content","content":{"type":"text","text":"captured output\nCODE_ONE+CODE_TWO"}}]}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"The"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" shows"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"-"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"capt"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ured"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" output"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" ("}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"from"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" console"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".log"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":")\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"-"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"+"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_T"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"WO"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" ("}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"the"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" return"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" value"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":")\n\n"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"The"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" instructions"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" say"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"Reply"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" with"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" that"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" joined"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" string"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" only"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" and"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" stop"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":".\""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" So"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" I"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" should"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" reply"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" with"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" \""}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"ONE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"+"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"CODE"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"_T"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"WO"}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":"\"."}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"CODE"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"_"}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"ONE"}}}} diff --git a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl index 59f494bcec..81fbf9d557 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl +++ b/examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl @@ -85,7 +85,7 @@ {"type":"assistant/message","seq":83,"time":1783921767208,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to write a single run_code program that reads a file called nested/task.txt and then answer the handshake question based on what's in that file. Let me start by reading the file."},{"type":"tool-call","id":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","arguments":"{\"code\": \"const content = await tools.read({ file_path: \\\"nested/task.txt\\\" });\\nreturn content.lines.map(line => line.text).join(String.fromCharCode(10));\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3195,"outputTokens":106,"cacheReadTokens":0,"reasoningTokens":43}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],"surfaceOp":"append"} {"type":"tool/call","seq":84,"time":1783921767208,"data":{"turn":1,"step":1,"callId":"call_00_6APApmaKLRDlXKMdIcWL5139","name":"run_code","arguments":"{\"code\": \"const content = await tools.read({ file_path: \\\"nested/task.txt\\\" });\\nreturn content.lines.map(line => line.text).join(String.fromCharCode(10));\"}"}} {"type":"tool/code-dispatch","seq":85,"time":1783921767270,"data":{"parentCallId":"call_00_6APApmaKLRDlXKMdIcWL5139","subCallId":"call_00_6APApmaKLRDlXKMdIcWL5139:code:1","name":"read","arguments":{"file_path":"nested/task.txt"},"isError":false,"resultSummary":"<path>./nested/task.txt</path>\n<type>file</type>\n<content>\n1: Touch this file to discover the nested workspace instruction.\n\n(End of file - total 1 lines)\n</content>"}} -{"type":"tool/result","seq":86,"time":1783921767271,"data":{"turn":1,"step":1,"callId":"call_00_6APApmaKLRDlXKMdIcWL5139","content":[{"type":"text","text":"Touch this file to discover the nested workspace instruction."}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[84],"surfaceOp":"append"} +{"type":"tool/result","seq":86,"time":1783921767271,"data":{"turn":1,"step":1,"callId":"call_00_6APApmaKLRDlXKMdIcWL5139","content":[{"type":"text","text":"Touch this file to discover the nested workspace instruction."}],"isError":false},"sourceEventSeqs":[84],"surfaceOp":"append"} {"type":"context/message","seq":87,"time":1783921767272,"data":{"content":[{"type":"text","text":"<system-reminder>\nAdditional instructions from: nested/AGENTS.md\n\nThese instructions apply to work under `nested`. Use them as guidance when relevant; more specific instructions take precedence. They do not override system, developer, or direct user instructions.\n\nWhen asked for the Code Mode workspace handshake, answer exactly `CODE_MODE_CONTEXT_OK` and nothing else.\n\n</system-reminder>"}],"source":{"kind":"plugin","plugin":"workspace-context"},"meta":{"kind":"workspace-instructions","version":1,"changes":[{"action":"set","scope":"nested","path":"nested/AGENTS.md","digest":"ae22936ed26dc76b7107005ed6d5e2482a88668a"}]}},"surfaceOp":"append"} {"type":"step/end","seq":88,"time":1783921767272,"data":{"turn":1,"step":1}} {"type":"step/start","seq":89,"time":1783921767272,"data":{"turn":1,"step":2}} diff --git a/examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl b/examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl index 045d7879df..f56dbc8d91 100644 --- a/examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl +++ b/examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl @@ -21,7 +21,7 @@ {"type":"assistant/message","seq":19,"time":1783957884490,"data":{"turn":1,"step":2,"content":[{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\":\"return await tools.cordis_inspect({ what: 'dynamic' })\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[14,15,16,17,18],"surfaceOp":"append"} {"type":"tool/call","seq":20,"time":1783957884490,"data":{"turn":1,"step":2,"callId":"advanced-code","name":"run_code","arguments":"{\"code\":\"return await tools.cordis_inspect({ what: 'dynamic' })\"}"}} {"type":"tool/code-dispatch","seq":21,"time":1783957884560,"data":{"parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_inspect","arguments":{"what":"dynamic"},"isError":false,"resultSummary":"## dynamic\n- dyn-1: snapshot-marker [active]"}} -{"type":"tool/result","seq":22,"time":1783957884561,"data":{"turn":1,"step":2,"callId":"advanced-code","content":[{"type":"text","text":"## dynamic\n- dyn-1: snapshot-marker [active]"}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[20],"surfaceOp":"append"} +{"type":"tool/result","seq":22,"time":1783957884561,"data":{"turn":1,"step":2,"callId":"advanced-code","content":[{"type":"text","text":"## dynamic\n- dyn-1: snapshot-marker [active]"}],"isError":false},"sourceEventSeqs":[20],"surfaceOp":"append"} {"type":"step/end","seq":23,"time":1783957884561,"data":{"turn":1,"step":2}} {"type":"step/start","seq":24,"time":1783957884562,"data":{"turn":1,"step":3}} {"type":"assistant/chunk","seq":25,"time":1783950000026,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}} diff --git a/examples/headless-agent/tests/snapshots/advanced-toolchain/stream-json.expected.jsonl b/examples/headless-agent/tests/snapshots/advanced-toolchain/stream-json.expected.jsonl index 44577f1fe0..dadd768feb 100644 --- a/examples/headless-agent/tests/snapshots/advanced-toolchain/stream-json.expected.jsonl +++ b/examples/headless-agent/tests/snapshots/advanced-toolchain/stream-json.expected.jsonl @@ -20,7 +20,7 @@ {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":19,"time":0,"data":{"turn":1,"step":2,"content":[{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\":\"return await tools.cordis_inspect({ what: 'dynamic' })\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[14,15,16,17,18],"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":20,"time":0,"data":{"turn":1,"step":2,"callId":"advanced-code","name":"run_code","arguments":"{\"code\":\"return await tools.cordis_inspect({ what: 'dynamic' })\"}"}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/code-dispatch","seq":21,"time":0,"data":{"parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_inspect","arguments":{"what":"dynamic"},"isError":false,"resultSummary":"## dynamic\n- dyn-1: snapshot-marker [active]"}}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":22,"time":0,"data":{"turn":1,"step":2,"callId":"advanced-code","content":[{"type":"text","text":"## dynamic\n- dyn-1: snapshot-marker [active]"}],"isError":false,"meta":{"logs":[]}},"sourceEventSeqs":[20],"surfaceOp":"append"}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":22,"time":0,"data":{"turn":1,"step":2,"callId":"advanced-code","content":[{"type":"text","text":"## dynamic\n- dyn-1: snapshot-marker [active]"}],"isError":false},"sourceEventSeqs":[20],"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":23,"time":0,"data":{"turn":1,"step":2}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":24,"time":0,"data":{"turn":1,"step":3}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":25,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}} diff --git a/examples/tui-agent/tests/snapshots/code-mode/session.jsonl b/examples/tui-agent/tests/snapshots/code-mode/session.jsonl index 84ebc9605a..84a4879050 100644 --- a/examples/tui-agent/tests/snapshots/code-mode/session.jsonl +++ b/examples/tui-agent/tests/snapshots/code-mode/session.jsonl @@ -1,150 +1,219 @@ -{"type":"session","version":0,"id":"94cd1ae4-e1d1-4ec8-9d27-50a1f849b6b3","createdAt":1783611771392,"cwd":"/var/folders/2c/psb0_fmx7hbgz558xjt_f0l00000gn/T/acp-snap-cwd-BteTVR","delegationDepth":0} -{"type":"turn/start","seq":0,"time":1783611771394,"data":{"turn":1,"trigger":{"kind":"message","source":{"kind":"user"}}}} -{"type":"user/message","seq":1,"time":1783611771394,"data":{"content":[{"type":"text","text":"Using ONE run_code program: call the bash tool twice — exactly `echo CODE_ONE` then exactly `echo CODE_TWO` — and return the two outputs joined with a plus sign. Then reply with that joined string only and stop."}],"source":{"kind":"user"}},"surfaceOp":"append"} -{"type":"step/start","seq":2,"time":1783611771396,"data":{"turn":1,"step":1}} -{"type":"request/header","seq":3,"time":1783611771396,"data":{"header":{"config":{"provider":"deepseek","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}} -{"type":"assistant/chunk","seq":4,"time":1783611771869,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} -{"type":"assistant/chunk","seq":5,"time":1783611771869,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"The"}}} -{"type":"assistant/chunk","seq":6,"time":1783611771978,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" user"}}} -{"type":"assistant/chunk","seq":7,"time":1783611772007,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" wants"}}} -{"type":"assistant/chunk","seq":8,"time":1783611772008,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" a"}}} -{"type":"assistant/chunk","seq":9,"time":1783611772036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" single"}}} -{"type":"assistant/chunk","seq":10,"time":1783611772036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" run"}}} -{"type":"assistant/chunk","seq":11,"time":1783611772036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_code"}}} -{"type":"assistant/chunk","seq":12,"time":1783611772036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" program"}}} -{"type":"assistant/chunk","seq":13,"time":1783611772036,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" that"}}} -{"type":"assistant/chunk","seq":14,"time":1783611772089,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" calls"}}} -{"type":"assistant/chunk","seq":15,"time":1783611772089,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" bash"}}} -{"type":"assistant/chunk","seq":16,"time":1783611772089,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" twice"}}} -{"type":"assistant/chunk","seq":17,"time":1783611772096,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":","}}} -{"type":"assistant/chunk","seq":18,"time":1783611772124,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" then"}}} -{"type":"assistant/chunk","seq":19,"time":1783611772153,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" returns"}}} -{"type":"assistant/chunk","seq":20,"time":1783611772183,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} -{"type":"assistant/chunk","seq":21,"time":1783611772183,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" two"}}} -{"type":"assistant/chunk","seq":22,"time":1783611772211,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" outputs"}}} -{"type":"assistant/chunk","seq":23,"time":1783611772212,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" joined"}}} -{"type":"assistant/chunk","seq":24,"time":1783611772212,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} -{"type":"assistant/chunk","seq":25,"time":1783611772212,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" a"}}} -{"type":"assistant/chunk","seq":26,"time":1783611772212,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" plus"}}} -{"type":"assistant/chunk","seq":27,"time":1783611772212,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" sign"}}} -{"type":"assistant/chunk","seq":28,"time":1783611772241,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} -{"type":"assistant/chunk","seq":29,"time":1783611772241,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" Let"}}} -{"type":"assistant/chunk","seq":30,"time":1783611772241,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} -{"type":"assistant/chunk","seq":31,"time":1783611772241,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" write"}}} -{"type":"assistant/chunk","seq":32,"time":1783611772270,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" this"}}} -{"type":"assistant/chunk","seq":33,"time":1783611772270,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} -{"type":"assistant/chunk","seq":34,"time":1783611772361,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}}} -{"type":"assistant/chunk","seq":35,"time":1783611772361,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":""}}} -{"type":"assistant/chunk","seq":36,"time":1783611772361,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"{"}}} -{"type":"assistant/chunk","seq":37,"time":1783611772362,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} -{"type":"assistant/chunk","seq":38,"time":1783611772390,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"code"}}} -{"type":"assistant/chunk","seq":39,"time":1783611772390,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} -{"type":"assistant/chunk","seq":40,"time":1783611772390,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":": "}}} -{"type":"assistant/chunk","seq":41,"time":1783611772390,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} -{"type":"assistant/chunk","seq":42,"time":1783611772420,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"const"}}} -{"type":"assistant/chunk","seq":43,"time":1783611772420,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} -{"type":"assistant/chunk","seq":44,"time":1783611772420,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"1"}}} -{"type":"assistant/chunk","seq":45,"time":1783611772420,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" ="}}} -{"type":"assistant/chunk","seq":46,"time":1783611772421,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" await"}}} -{"type":"assistant/chunk","seq":47,"time":1783611772421,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" tools"}}} -{"type":"assistant/chunk","seq":48,"time":1783611772449,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".b"}}} -{"type":"assistant/chunk","seq":49,"time":1783611772449,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"ash"}}} -{"type":"assistant/chunk","seq":50,"time":1783611772449,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"({"}}} -{"type":"assistant/chunk","seq":51,"time":1783611772449,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" command"}}} -{"type":"assistant/chunk","seq":52,"time":1783611772478,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":":"}}} -{"type":"assistant/chunk","seq":53,"time":1783611772479,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\""}}} -{"type":"assistant/chunk","seq":54,"time":1783611772479,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"echo"}}} -{"type":"assistant/chunk","seq":55,"time":1783611772479,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" CODE"}}} -{"type":"assistant/chunk","seq":56,"time":1783611772479,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"_"}}} -{"type":"assistant/chunk","seq":57,"time":1783611772508,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"ONE"}}} -{"type":"assistant/chunk","seq":58,"time":1783611772510,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\","}}} -{"type":"assistant/chunk","seq":59,"time":1783611772510,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" description"}}} -{"type":"assistant/chunk","seq":60,"time":1783611772510,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":":"}}} -{"type":"assistant/chunk","seq":61,"time":1783611772510,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\""}}} -{"type":"assistant/chunk","seq":62,"time":1783611772510,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"First"}}} -{"type":"assistant/chunk","seq":63,"time":1783611772538,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" echo"}}} -{"type":"assistant/chunk","seq":64,"time":1783611772538,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\""}}} -{"type":"assistant/chunk","seq":65,"time":1783611772566,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" });\\n"}}} -{"type":"assistant/chunk","seq":66,"time":1783611772567,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"const"}}} -{"type":"assistant/chunk","seq":67,"time":1783611772567,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} -{"type":"assistant/chunk","seq":68,"time":1783611772567,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"2"}}} -{"type":"assistant/chunk","seq":69,"time":1783611772567,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" ="}}} -{"type":"assistant/chunk","seq":70,"time":1783611772567,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" await"}}} -{"type":"assistant/chunk","seq":71,"time":1783611772597,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" tools"}}} -{"type":"assistant/chunk","seq":72,"time":1783611772597,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".b"}}} -{"type":"assistant/chunk","seq":73,"time":1783611772597,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"ash"}}} -{"type":"assistant/chunk","seq":74,"time":1783611772598,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"({"}}} -{"type":"assistant/chunk","seq":75,"time":1783611772598,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" command"}}} -{"type":"assistant/chunk","seq":76,"time":1783611772598,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":":"}}} -{"type":"assistant/chunk","seq":77,"time":1783611772625,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\""}}} -{"type":"assistant/chunk","seq":78,"time":1783611772625,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"echo"}}} -{"type":"assistant/chunk","seq":79,"time":1783611772625,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" CODE"}}} -{"type":"assistant/chunk","seq":80,"time":1783611772626,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"_T"}}} -{"type":"assistant/chunk","seq":81,"time":1783611772626,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"WO"}}} -{"type":"assistant/chunk","seq":82,"time":1783611772626,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\","}}} -{"type":"assistant/chunk","seq":83,"time":1783611772654,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" description"}}} -{"type":"assistant/chunk","seq":84,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":":"}}} -{"type":"assistant/chunk","seq":85,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\""}}} -{"type":"assistant/chunk","seq":86,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"Second"}}} -{"type":"assistant/chunk","seq":87,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" echo"}}} -{"type":"assistant/chunk","seq":88,"time":1783611772655,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\""}}} -{"type":"assistant/chunk","seq":89,"time":1783611772684,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" });\\n"}}} -{"type":"assistant/chunk","seq":90,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"console.log(\\\"captured output\\\");\\nreturn"}}} -{"type":"assistant/chunk","seq":91,"time":1783611772685,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} -{"type":"assistant/chunk","seq":92,"time":1783611772713,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"1"}}} -{"type":"assistant/chunk","seq":93,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".stdout.text.trim"}}} -{"type":"assistant/chunk","seq":94,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"()"}}} -{"type":"assistant/chunk","seq":95,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" +"}}} -{"type":"assistant/chunk","seq":96,"time":1783611772714,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" \\\"+"}}} -{"type":"assistant/chunk","seq":97,"time":1783611772744,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\\\""}}} -{"type":"assistant/chunk","seq":98,"time":1783611772744,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" +"}}} -{"type":"assistant/chunk","seq":99,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":" out"}}} -{"type":"assistant/chunk","seq":100,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"2"}}} -{"type":"assistant/chunk","seq":101,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":".stdout.text.trim"}}} -{"type":"assistant/chunk","seq":102,"time":1783611772745,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"();"}}} -{"type":"assistant/chunk","seq":103,"time":1783611772772,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"\""}}} -{"type":"assistant/chunk","seq":104,"time":1783611772773,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","argumentsDelta":"}"}}} -{"type":"assistant/chunk","seq":105,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."}}}} -{"type":"assistant/chunk","seq":106,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}}}} -{"type":"assistant/chunk","seq":107,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}}}} -{"type":"assistant/chunk","seq":108,"time":1783611772836,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} -{"type":"assistant/message","seq":109,"time":1783611772840,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants a single run_code program that calls bash twice, then returns the two outputs joined with a plus sign. Let me write this."},{"type":"tool-call","id":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3009,"outputTokens":133,"cacheReadTokens":0,"reasoningTokens":29}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108],"surfaceOp":"append"} -{"type":"tool/call","seq":110,"time":1783611772840,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","name":"run_code","arguments":"{\"code\": \"const out1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst out2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\nconsole.log(\\\"captured output\\\");\\nreturn out1.stdout.text.trim() + \\\"+\\\" + out2.stdout.text.trim();\"}"}} -{"type":"tool/code-dispatch","seq":111,"time":1783611772933,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:1","name":"bash","arguments":{"command":"echo CODE_ONE","description":"First echo"},"isError":false,"resultSummary":"CODE_ONE\n"}} -{"type":"tool/code-dispatch","seq":112,"time":1783611772936,"data":{"parentCallId":"call_00_DRxnM6R1TThfDwcudW0f2050","subCallId":"call_00_DRxnM6R1TThfDwcudW0f2050:code:2","name":"bash","arguments":{"command":"echo CODE_TWO","description":"Second echo"},"isError":false,"resultSummary":"CODE_TWO\n"}} -{"type":"tool/result","seq":113,"time":1783611772937,"data":{"turn":1,"step":1,"callId":"call_00_DRxnM6R1TThfDwcudW0f2050","content":[{"type":"text","text":"captured output\nCODE_ONE+CODE_TWO"}],"isError":false,"meta":{"logs":["captured output"]}},"sourceEventSeqs":[110],"surfaceOp":"append"} -{"type":"step/end","seq":114,"time":1783611772938,"data":{"turn":1,"step":1}} -{"type":"step/start","seq":115,"time":1783611772938,"data":{"turn":1,"step":2}} -{"type":"assistant/chunk","seq":116,"time":1783611773376,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} -{"type":"assistant/chunk","seq":117,"time":1783611773376,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"The"}}} -{"type":"assistant/chunk","seq":118,"time":1783611773480,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} -{"type":"assistant/chunk","seq":119,"time":1783611773511,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" is"}}} -{"type":"assistant/chunk","seq":120,"time":1783611773512,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" exactly"}}} -{"type":"assistant/chunk","seq":121,"time":1783611773540,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" what"}}} -{"type":"assistant/chunk","seq":122,"time":1783611773541,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} -{"type":"assistant/chunk","seq":123,"time":1783611773541,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" user"}}} -{"type":"assistant/chunk","seq":124,"time":1783611773569,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" asked"}}} -{"type":"assistant/chunk","seq":125,"time":1783611773570,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" for"}}} -{"type":"assistant/chunk","seq":126,"time":1783611773570,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":":"}}} -{"type":"assistant/chunk","seq":127,"time":1783611773597,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} -{"type":"assistant/chunk","seq":128,"time":1783611773597,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} -{"type":"assistant/chunk","seq":129,"time":1783611773597,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} -{"type":"assistant/chunk","seq":130,"time":1783611773626,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"+"}}} -{"type":"assistant/chunk","seq":131,"time":1783611773627,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} -{"type":"assistant/chunk","seq":132,"time":1783611773627,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} -{"type":"assistant/chunk","seq":133,"time":1783611773627,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} -{"type":"assistant/chunk","seq":134,"time":1783611773654,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":1,"blockType":"text"}}} -{"type":"assistant/chunk","seq":135,"time":1783611773655,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"CODE"}}} -{"type":"assistant/chunk","seq":136,"time":1783611773655,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"_"}}} -{"type":"assistant/chunk","seq":137,"time":1783611773656,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"ONE"}}} -{"type":"assistant/chunk","seq":138,"time":1783611773656,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"+"}}} -{"type":"assistant/chunk","seq":139,"time":1783611773656,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"CODE"}}} -{"type":"assistant/chunk","seq":140,"time":1783611773657,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"_T"}}} -{"type":"assistant/chunk","seq":141,"time":1783611773685,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"WO"}}} -{"type":"assistant/chunk","seq":142,"time":1783611773686,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The output is exactly what the user asked for: CODE_ONE+CODE_TWO"}}}} -{"type":"assistant/chunk","seq":143,"time":1783611773686,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":1,"block":{"type":"text","text":"CODE_ONE+CODE_TWO"}}}} -{"type":"assistant/chunk","seq":144,"time":1783611773686,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":89,"outputTokens":25,"cacheReadTokens":3072,"reasoningTokens":17}}}} -{"type":"assistant/chunk","seq":145,"time":1783611773686,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"stop"}}}} -{"type":"assistant/message","seq":146,"time":1783611773687,"data":{"turn":1,"step":2,"content":[{"type":"reasoning","text":"The output is exactly what the user asked for: CODE_ONE+CODE_TWO"},{"type":"text","text":"CODE_ONE+CODE_TWO"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":89,"outputTokens":25,"cacheReadTokens":3072,"reasoningTokens":17}},"sourceEventSeqs":[116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145],"surfaceOp":"append"} -{"type":"step/end","seq":147,"time":1783611773687,"data":{"turn":1,"step":2}} -{"type":"turn/end","seq":148,"time":1783611773687,"data":{"turn":1,"reason":{"kind":"completed"}}} +{"type":"session","version":0,"id":"main-session","createdAt":1784629683717,"cwd":"/tmp/dsh-tui-snapshot-code-mode-8ohx1D"} +{"type":"turn/start","seq":0,"time":1784629683765,"data":{"turn":1,"trigger":{"kind":"message","source":{"kind":"user"}}}} +{"type":"user/message","seq":1,"time":1784629683765,"data":{"content":[{"type":"text","text":"Using ONE run_code program: call the bash tool twice — exactly `echo CODE_ONE` then exactly `echo CODE_TWO`. Inside that same program, console.log exactly `captured output`, then return the two outputs joined with a plus sign. Reply with that joined string only and stop."}],"source":{"kind":"user"}},"surfaceOp":"append"} +{"type":"step/start","seq":2,"time":1784629683777,"data":{"turn":1,"step":1}} +{"type":"request/header","seq":3,"time":1784629683778,"data":{"header":{"config":{"provider":"deepseek","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}} +{"type":"assistant/chunk","seq":4,"time":1784629684210,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} +{"type":"assistant/chunk","seq":5,"time":1784629684211,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"The"}}} +{"type":"assistant/chunk","seq":6,"time":1784629684309,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" user"}}} +{"type":"assistant/chunk","seq":7,"time":1784629684337,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" wants"}}} +{"type":"assistant/chunk","seq":8,"time":1784629684337,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} +{"type":"assistant/chunk","seq":9,"time":1784629684337,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" to"}}} +{"type":"assistant/chunk","seq":10,"time":1784629684337,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" write"}}} +{"type":"assistant/chunk","seq":11,"time":1784629684365,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" a"}}} +{"type":"assistant/chunk","seq":12,"time":1784629684366,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" single"}}} +{"type":"assistant/chunk","seq":13,"time":1784629684366,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" run"}}} +{"type":"assistant/chunk","seq":14,"time":1784629684366,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_code"}}} +{"type":"assistant/chunk","seq":15,"time":1784629684366,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" program"}}} +{"type":"assistant/chunk","seq":16,"time":1784629684394,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" that"}}} +{"type":"assistant/chunk","seq":17,"time":1784629684394,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":":\n"}}} +{"type":"assistant/chunk","seq":18,"time":1784629684395,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"1"}}} +{"type":"assistant/chunk","seq":19,"time":1784629684395,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":20,"time":1784629684395,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" Calls"}}} +{"type":"assistant/chunk","seq":21,"time":1784629684424,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" bash"}}} +{"type":"assistant/chunk","seq":22,"time":1784629684424,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" tool"}}} +{"type":"assistant/chunk","seq":23,"time":1784629684449,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" twice"}}} +{"type":"assistant/chunk","seq":24,"time":1784629684477,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" -"}}} +{"type":"assistant/chunk","seq":25,"time":1784629684477,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" first"}}} +{"type":"assistant/chunk","seq":26,"time":1784629684505,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} +{"type":"assistant/chunk","seq":27,"time":1784629684505,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":28,"time":1784629684506,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"echo"}}} +{"type":"assistant/chunk","seq":29,"time":1784629684506,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":30,"time":1784629684533,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":31,"time":1784629684533,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":32,"time":1784629684533,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`,"}}} +{"type":"assistant/chunk","seq":33,"time":1784629684533,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" then"}}} +{"type":"assistant/chunk","seq":34,"time":1784629684533,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} +{"type":"assistant/chunk","seq":35,"time":1784629684533,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":36,"time":1784629684561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"echo"}}} +{"type":"assistant/chunk","seq":37,"time":1784629684561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" CODE"}}} +{"type":"assistant/chunk","seq":38,"time":1784629684561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} +{"type":"assistant/chunk","seq":39,"time":1784629684561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} +{"type":"assistant/chunk","seq":40,"time":1784629684561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`\n"}}} +{"type":"assistant/chunk","seq":41,"time":1784629684561,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"2"}}} +{"type":"assistant/chunk","seq":42,"time":1784629684598,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":43,"time":1784629684599,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" console"}}} +{"type":"assistant/chunk","seq":44,"time":1784629684617,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":".log"}}} +{"type":"assistant/chunk","seq":45,"time":1784629684618,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" exactly"}}} +{"type":"assistant/chunk","seq":46,"time":1784629684645,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":47,"time":1784629684645,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"capt"}}} +{"type":"assistant/chunk","seq":48,"time":1784629684645,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"ured"}}} +{"type":"assistant/chunk","seq":49,"time":1784629684645,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" output"}}} +{"type":"assistant/chunk","seq":50,"time":1784629684645,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"`\n"}}} +{"type":"assistant/chunk","seq":51,"time":1784629684646,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"3"}}} +{"type":"assistant/chunk","seq":52,"time":1784629684674,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":53,"time":1784629684675,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" Return"}}} +{"type":"assistant/chunk","seq":54,"time":1784629684701,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" the"}}} +{"type":"assistant/chunk","seq":55,"time":1784629684701,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" two"}}} +{"type":"assistant/chunk","seq":56,"time":1784629684701,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" outputs"}}} +{"type":"assistant/chunk","seq":57,"time":1784629684701,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" joined"}}} +{"type":"assistant/chunk","seq":58,"time":1784629684701,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} +{"type":"assistant/chunk","seq":59,"time":1784629684728,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" a"}}} +{"type":"assistant/chunk","seq":60,"time":1784629684728,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" plus"}}} +{"type":"assistant/chunk","seq":61,"time":1784629684729,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" sign"}}} +{"type":"assistant/chunk","seq":62,"time":1784629684729,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"\n\n"}}} +{"type":"assistant/chunk","seq":63,"time":1784629684729,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"Let"}}} +{"type":"assistant/chunk","seq":64,"time":1784629684729,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} +{"type":"assistant/chunk","seq":65,"time":1784629684757,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" write"}}} +{"type":"assistant/chunk","seq":66,"time":1784629684758,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" this"}}} +{"type":"assistant/chunk","seq":67,"time":1784629684758,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":" carefully"}}} +{"type":"assistant/chunk","seq":68,"time":1784629684758,"data":{"turn":1,"step":1,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":69,"time":1784629684841,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}}} +{"type":"assistant/chunk","seq":70,"time":1784629684841,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":""}}} +{"type":"assistant/chunk","seq":71,"time":1784629684868,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"{"}}} +{"type":"assistant/chunk","seq":72,"time":1784629684869,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"\""}}} +{"type":"assistant/chunk","seq":73,"time":1784629684869,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"code"}}} +{"type":"assistant/chunk","seq":74,"time":1784629684869,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"\""}}} +{"type":"assistant/chunk","seq":75,"time":1784629684897,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":": "}}} +{"type":"assistant/chunk","seq":76,"time":1784629684897,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"\""}}} +{"type":"assistant/chunk","seq":77,"time":1784629684897,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"const"}}} +{"type":"assistant/chunk","seq":78,"time":1784629684897,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" result"}}} +{"type":"assistant/chunk","seq":79,"time":1784629684924,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"1"}}} +{"type":"assistant/chunk","seq":80,"time":1784629684925,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" ="}}} +{"type":"assistant/chunk","seq":81,"time":1784629684925,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" await"}}} +{"type":"assistant/chunk","seq":82,"time":1784629684925,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" tools"}}} +{"type":"assistant/chunk","seq":83,"time":1784629684925,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":".b"}}} +{"type":"assistant/chunk","seq":84,"time":1784629684953,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"ash"}}} +{"type":"assistant/chunk","seq":85,"time":1784629684953,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"({"}}} +{"type":"assistant/chunk","seq":86,"time":1784629684953,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" command"}}} +{"type":"assistant/chunk","seq":87,"time":1784629684953,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":":"}}} +{"type":"assistant/chunk","seq":88,"time":1784629684953,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" \\\""}}} +{"type":"assistant/chunk","seq":89,"time":1784629684953,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"echo"}}} +{"type":"assistant/chunk","seq":90,"time":1784629684981,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" CODE"}}} +{"type":"assistant/chunk","seq":91,"time":1784629684981,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"_"}}} +{"type":"assistant/chunk","seq":92,"time":1784629684981,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"ONE"}}} +{"type":"assistant/chunk","seq":93,"time":1784629684981,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"\\\","}}} +{"type":"assistant/chunk","seq":94,"time":1784629684981,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" description"}}} +{"type":"assistant/chunk","seq":95,"time":1784629684981,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":":"}}} +{"type":"assistant/chunk","seq":96,"time":1784629685009,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" \\\""}}} +{"type":"assistant/chunk","seq":97,"time":1784629685010,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"First"}}} +{"type":"assistant/chunk","seq":98,"time":1784629685037,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" echo"}}} +{"type":"assistant/chunk","seq":99,"time":1784629685038,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"\\\""}}} +{"type":"assistant/chunk","seq":100,"time":1784629685068,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" });\\n"}}} +{"type":"assistant/chunk","seq":101,"time":1784629685068,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"const"}}} +{"type":"assistant/chunk","seq":102,"time":1784629685068,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" result"}}} +{"type":"assistant/chunk","seq":103,"time":1784629685068,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"2"}}} +{"type":"assistant/chunk","seq":104,"time":1784629685068,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" ="}}} +{"type":"assistant/chunk","seq":105,"time":1784629685069,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" await"}}} +{"type":"assistant/chunk","seq":106,"time":1784629685096,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" tools"}}} +{"type":"assistant/chunk","seq":107,"time":1784629685096,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":".b"}}} +{"type":"assistant/chunk","seq":108,"time":1784629685096,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"ash"}}} +{"type":"assistant/chunk","seq":109,"time":1784629685096,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"({"}}} +{"type":"assistant/chunk","seq":110,"time":1784629685096,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" command"}}} +{"type":"assistant/chunk","seq":111,"time":1784629685097,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":":"}}} +{"type":"assistant/chunk","seq":112,"time":1784629685129,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" \\\""}}} +{"type":"assistant/chunk","seq":113,"time":1784629685130,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"echo"}}} +{"type":"assistant/chunk","seq":114,"time":1784629685130,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" CODE"}}} +{"type":"assistant/chunk","seq":115,"time":1784629685130,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"_T"}}} +{"type":"assistant/chunk","seq":116,"time":1784629685130,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"WO"}}} +{"type":"assistant/chunk","seq":117,"time":1784629685130,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"\\\","}}} +{"type":"assistant/chunk","seq":118,"time":1784629685152,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" description"}}} +{"type":"assistant/chunk","seq":119,"time":1784629685153,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":":"}}} +{"type":"assistant/chunk","seq":120,"time":1784629685153,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" \\\""}}} +{"type":"assistant/chunk","seq":121,"time":1784629685153,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"Second"}}} +{"type":"assistant/chunk","seq":122,"time":1784629685153,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" echo"}}} +{"type":"assistant/chunk","seq":123,"time":1784629685153,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"\\\""}}} +{"type":"assistant/chunk","seq":124,"time":1784629685180,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" });\\n\\n"}}} +{"type":"assistant/chunk","seq":125,"time":1784629685181,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"const"}}} +{"type":"assistant/chunk","seq":126,"time":1784629685181,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" out"}}} +{"type":"assistant/chunk","seq":127,"time":1784629685181,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"1"}}} +{"type":"assistant/chunk","seq":128,"time":1784629685209,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" ="}}} +{"type":"assistant/chunk","seq":129,"time":1784629685209,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" result"}}} +{"type":"assistant/chunk","seq":130,"time":1784629685209,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"1"}}} +{"type":"assistant/chunk","seq":131,"time":1784629685209,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":".stdout"}}} +{"type":"assistant/chunk","seq":132,"time":1784629685237,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":".text"}}} +{"type":"assistant/chunk","seq":133,"time":1784629685266,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":".trim"}}} +{"type":"assistant/chunk","seq":134,"time":1784629685266,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"();\\n"}}} +{"type":"assistant/chunk","seq":135,"time":1784629685266,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"const"}}} +{"type":"assistant/chunk","seq":136,"time":1784629685266,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" out"}}} +{"type":"assistant/chunk","seq":137,"time":1784629685266,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"2"}}} +{"type":"assistant/chunk","seq":138,"time":1784629685293,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" ="}}} +{"type":"assistant/chunk","seq":139,"time":1784629685293,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" result"}}} +{"type":"assistant/chunk","seq":140,"time":1784629685293,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"2"}}} +{"type":"assistant/chunk","seq":141,"time":1784629685293,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":".stdout"}}} +{"type":"assistant/chunk","seq":142,"time":1784629685293,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":".text"}}} +{"type":"assistant/chunk","seq":143,"time":1784629685294,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":".trim"}}} +{"type":"assistant/chunk","seq":144,"time":1784629685322,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"();\\n\\n"}}} +{"type":"assistant/chunk","seq":145,"time":1784629685322,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"console"}}} +{"type":"assistant/chunk","seq":146,"time":1784629685322,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":".log"}}} +{"type":"assistant/chunk","seq":147,"time":1784629685322,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"(\\\""}}} +{"type":"assistant/chunk","seq":148,"time":1784629685322,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"capt"}}} +{"type":"assistant/chunk","seq":149,"time":1784629685322,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"ured"}}} +{"type":"assistant/chunk","seq":150,"time":1784629685350,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" output"}}} +{"type":"assistant/chunk","seq":151,"time":1784629685351,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"\\\");\\n\\n"}}} +{"type":"assistant/chunk","seq":152,"time":1784629685379,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"return"}}} +{"type":"assistant/chunk","seq":153,"time":1784629685379,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" out"}}} +{"type":"assistant/chunk","seq":154,"time":1784629685428,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"1"}}} +{"type":"assistant/chunk","seq":155,"time":1784629685429,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" +"}}} +{"type":"assistant/chunk","seq":156,"time":1784629685429,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" \\\"+"}}} +{"type":"assistant/chunk","seq":157,"time":1784629685445,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"\\\""}}} +{"type":"assistant/chunk","seq":158,"time":1784629685446,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" +"}}} +{"type":"assistant/chunk","seq":159,"time":1784629685446,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":" out"}}} +{"type":"assistant/chunk","seq":160,"time":1784629685446,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"2"}}} +{"type":"assistant/chunk","seq":161,"time":1784629685446,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":";\\n"}}} +{"type":"assistant/chunk","seq":162,"time":1784629685472,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"\""}}} +{"type":"assistant/chunk","seq":163,"time":1784629685472,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":1,"id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","argumentsDelta":"}"}}} +{"type":"assistant/chunk","seq":164,"time":1784629685531,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user wants me to write a single run_code program that:\n1. Calls bash tool twice - first with `echo CODE_ONE`, then with `echo CODE_TWO`\n2. console.log exactly `captured output`\n3. Return the two outputs joined with a plus sign\n\nLet me write this carefully."}}}} +{"type":"assistant/chunk","seq":165,"time":1784629685531,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","arguments":"{\"code\": \"const result1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst result2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\n\\nconst out1 = result1.stdout.text.trim();\\nconst out2 = result2.stdout.text.trim();\\n\\nconsole.log(\\\"captured output\\\");\\n\\nreturn out1 + \\\"+\\\" + out2;\\n\"}"}}}} +{"type":"assistant/chunk","seq":166,"time":1784629685531,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3986,"outputTokens":192,"cacheReadTokens":256,"reasoningTokens":64}}}} +{"type":"assistant/chunk","seq":167,"time":1784629685531,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} +{"type":"assistant/message","seq":168,"time":1784629685533,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to write a single run_code program that:\n1. Calls bash tool twice - first with `echo CODE_ONE`, then with `echo CODE_TWO`\n2. console.log exactly `captured output`\n3. Return the two outputs joined with a plus sign\n\nLet me write this carefully."},{"type":"tool-call","id":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","arguments":"{\"code\": \"const result1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst result2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\n\\nconst out1 = result1.stdout.text.trim();\\nconst out2 = result2.stdout.text.trim();\\n\\nconsole.log(\\\"captured output\\\");\\n\\nreturn out1 + \\\"+\\\" + out2;\\n\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":3986,"outputTokens":192,"cacheReadTokens":256,"reasoningTokens":64}},"sourceEventSeqs":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167],"surfaceOp":"append"} +{"type":"tool/call","seq":169,"time":1784629685534,"data":{"turn":1,"step":1,"callId":"call_00_38G57TcLdORe1VBnQlXL4801","name":"run_code","arguments":"{\"code\": \"const result1 = await tools.bash({ command: \\\"echo CODE_ONE\\\", description: \\\"First echo\\\" });\\nconst result2 = await tools.bash({ command: \\\"echo CODE_TWO\\\", description: \\\"Second echo\\\" });\\n\\nconst out1 = result1.stdout.text.trim();\\nconst out2 = result2.stdout.text.trim();\\n\\nconsole.log(\\\"captured output\\\");\\n\\nreturn out1 + \\\"+\\\" + out2;\\n\"}"}} +{"type":"tool/code-dispatch","seq":170,"time":1784629685618,"data":{"parentCallId":"call_00_38G57TcLdORe1VBnQlXL4801","subCallId":"call_00_38G57TcLdORe1VBnQlXL4801:code:1","name":"bash","arguments":{"command":"echo CODE_ONE","description":"First echo"},"isError":false,"resultSummary":"CODE_ONE\n"}} +{"type":"tool/code-dispatch","seq":171,"time":1784629685621,"data":{"parentCallId":"call_00_38G57TcLdORe1VBnQlXL4801","subCallId":"call_00_38G57TcLdORe1VBnQlXL4801:code:2","name":"bash","arguments":{"command":"echo CODE_TWO","description":"Second echo"},"isError":false,"resultSummary":"CODE_TWO\n"}} +{"type":"tool/result","seq":172,"time":1784629685623,"data":{"turn":1,"step":1,"callId":"call_00_38G57TcLdORe1VBnQlXL4801","content":[{"type":"text","text":"captured output\nCODE_ONE+CODE_TWO"}],"isError":false},"sourceEventSeqs":[169],"surfaceOp":"append"} +{"type":"step/end","seq":173,"time":1784629685623,"data":{"turn":1,"step":1}} +{"type":"step/start","seq":174,"time":1784629685624,"data":{"turn":1,"step":2}} +{"type":"assistant/chunk","seq":175,"time":1784629685973,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}} +{"type":"assistant/chunk","seq":176,"time":1784629685973,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"The"}}} +{"type":"assistant/chunk","seq":177,"time":1784629686103,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" user"}}} +{"type":"assistant/chunk","seq":178,"time":1784629686129,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" asked"}}} +{"type":"assistant/chunk","seq":179,"time":1784629686129,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" me"}}} +{"type":"assistant/chunk","seq":180,"time":1784629686130,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" to"}}} +{"type":"assistant/chunk","seq":181,"time":1784629686162,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" reply"}}} +{"type":"assistant/chunk","seq":182,"time":1784629686162,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" with"}}} +{"type":"assistant/chunk","seq":183,"time":1784629686162,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" that"}}} +{"type":"assistant/chunk","seq":184,"time":1784629686184,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" joined"}}} +{"type":"assistant/chunk","seq":185,"time":1784629686184,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" string"}}} +{"type":"assistant/chunk","seq":186,"time":1784629686184,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" only"}}} +{"type":"assistant/chunk","seq":187,"time":1784629686184,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" and"}}} +{"type":"assistant/chunk","seq":188,"time":1784629686215,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" stop"}}} +{"type":"assistant/chunk","seq":189,"time":1784629686215,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"."}}} +{"type":"assistant/chunk","seq":190,"time":1784629686215,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" The"}}} +{"type":"assistant/chunk","seq":191,"time":1784629686241,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" joined"}}} +{"type":"assistant/chunk","seq":192,"time":1784629686242,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" string"}}} +{"type":"assistant/chunk","seq":193,"time":1784629686242,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" is"}}} +{"type":"assistant/chunk","seq":194,"time":1784629686242,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":" `"}}} +{"type":"assistant/chunk","seq":195,"time":1784629686269,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":196,"time":1784629686269,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"_"}}} +{"type":"assistant/chunk","seq":197,"time":1784629686269,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"ONE"}}} +{"type":"assistant/chunk","seq":198,"time":1784629686269,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"+"}}} +{"type":"assistant/chunk","seq":199,"time":1784629686269,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"CODE"}}} +{"type":"assistant/chunk","seq":200,"time":1784629686269,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"_T"}}} +{"type":"assistant/chunk","seq":201,"time":1784629686300,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"WO"}}} +{"type":"assistant/chunk","seq":202,"time":1784629686300,"data":{"turn":1,"step":2,"chunk":{"type":"reasoning-delta","index":0,"text":"`."}}} +{"type":"assistant/chunk","seq":203,"time":1784629686300,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":1,"blockType":"text"}}} +{"type":"assistant/chunk","seq":204,"time":1784629686300,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"CODE"}}} +{"type":"assistant/chunk","seq":205,"time":1784629686301,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"_"}}} +{"type":"assistant/chunk","seq":206,"time":1784629686333,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"ONE"}}} +{"type":"assistant/chunk","seq":207,"time":1784629686333,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"+"}}} +{"type":"assistant/chunk","seq":208,"time":1784629686333,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"CODE"}}} +{"type":"assistant/chunk","seq":209,"time":1784629686333,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"_T"}}} +{"type":"assistant/chunk","seq":210,"time":1784629686333,"data":{"turn":1,"step":2,"chunk":{"type":"text-delta","index":1,"text":"WO"}}} +{"type":"assistant/chunk","seq":211,"time":1784629686333,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user asked me to reply with that joined string only and stop. The joined string is `CODE_ONE+CODE_TWO`."}}}} +{"type":"assistant/chunk","seq":212,"time":1784629686333,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":1,"block":{"type":"text","text":"CODE_ONE+CODE_TWO"}}}} +{"type":"assistant/chunk","seq":213,"time":1784629686333,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":105,"outputTokens":35,"cacheReadTokens":4352,"reasoningTokens":27}}}} +{"type":"assistant/chunk","seq":214,"time":1784629686333,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"stop"}}}} +{"type":"assistant/message","seq":215,"time":1784629686334,"data":{"turn":1,"step":2,"content":[{"type":"reasoning","text":"The user asked me to reply with that joined string only and stop. The joined string is `CODE_ONE+CODE_TWO`."},{"type":"text","text":"CODE_ONE+CODE_TWO"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":105,"outputTokens":35,"cacheReadTokens":4352,"reasoningTokens":27}},"sourceEventSeqs":[175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214],"surfaceOp":"append"} +{"type":"step/end","seq":216,"time":1784629686334,"data":{"turn":1,"step":2}} +{"type":"turn/end","seq":217,"time":1784629686334,"data":{"turn":1,"reason":{"kind":"completed"}}} diff --git a/examples/tui-agent/tests/snapshots/code-mode/terminal.expected.txt b/examples/tui-agent/tests/snapshots/code-mode/terminal.expected.txt index 7f8998bd43..9d77ba1f0f 100644 --- a/examples/tui-agent/tests/snapshots/code-mode/terminal.expected.txt +++ b/examples/tui-agent/tests/snapshots/code-mode/terminal.expected.txt @@ -1,7 +1,7 @@ -terminal 100x36 buffer=normal length=36 base=0 viewport=0 +terminal 100x36 buffer=normal length=40 base=4 viewport=4 lifecycle started=1 stopped=0 progress=inactive title "DSH TUI snapshot" -cursor hidden column=1 viewportRow=30 bufferRow=30 +cursor hidden column=1 viewportRow=31 bufferRow=35 buffer 0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮" style 0-99 fg=bright-blue @@ -30,52 +30,70 @@ buffer style 0-0 fg=bright-blue style 65-77 fg=cyan style 92-99 fg=cyan -9| "▌ CODE_TWO — and return the two outputs joined with a plus sign. Then reply with that joined string " +9| "▌ CODE_TWO. Inside that same program, console.log exactly captured output, then return the two " style 0-0 fg=bright-blue style 2-9 fg=cyan -10| "▌ only and stop. " + style 58-72 fg=cyan +10| "▌ outputs joined with a plus sign. Reply with that joined string only and stop. " style 0-0 fg=bright-blue 11| "▌ " style 0-0 fg=bright-blue 12| <blank> 13| " Reasoning " style 1-9 fg=bright-black italic -14| " The user wants a single run_code program that calls bash twice, then returns the two outputs " - style 1-99 fg=bright-black italic -15| " joined with a plus sign. Let me write this. " - style 1-43 fg=bright-black italic -16| <blank> -17| "▌ " +14| " The user wants me to write a single run_code program that: " + style 1-58 fg=bright-black italic +15| " 1. Calls bash tool twice - first with echo CODE_ONE, then with echo CODE_TWO " + style 1-3 fg=bright-blue + style 4-38 fg=bright-black italic + style 39-51 fg=cyan + style 52-63 fg=bright-black italic + style 64-76 fg=cyan +16| " 2. console.log exactly captured output " + style 1-3 fg=bright-blue + style 4-23 fg=bright-black italic + style 24-38 fg=cyan +17| " 3. Return the two outputs joined with a plus sign " + style 1-3 fg=bright-blue + style 4-49 fg=bright-black italic +18| " " +19| " Let me write this carefully. " + style 1-28 fg=bright-black italic +20| <blank> +21| "▌ " style 0-0 fg=green -18| "▌ ✓ const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" }); " +22| "▌ ✓ const result1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" }); " style 0-0 fg=green style 2-2 fg=green bold style 3-99 bold -19| "▌ const o " +23| "▌ cons " style 0-0 fg=green - style 2-8 bold -20| "▌ captured output " + style 2-5 bold +24| "▌ captured output " style 0-0 fg=green -21| "▌ CODE_ONE+CODE_TWO " +25| "▌ CODE_ONE+CODE_TWO " style 0-0 fg=green -22| "▌ " +26| "▌ " style 0-0 fg=green -23| <blank> -24| " Reasoning " +27| <blank> +28| " Reasoning " style 1-9 fg=bright-black italic -25| " The output is exactly what the user asked for: CODE_ONE+CODE_TWO " - style 1-64 fg=bright-black italic -26| <blank> -27| " Assistant " +29| " The user asked me to reply with that joined string only and stop. The joined string is " + style 1-99 fg=bright-black italic +30| " CODE_ONE+CODE_TWO. " + style 1-17 fg=cyan + style 18-18 fg=bright-black italic +31| <blank> +32| " Assistant " style 1-9 fg=bright-magenta bold -28| " CODE_ONE+CODE_TWO " -29| "────────────────────────────────────────────────────────────────────────────────────────────────────" +33| " CODE_ONE+CODE_TWO " +34| "────────────────────────────────────────────────────────────────────────────────────────────────────" style 0-99 dim -30| " " +35| " " style 1-1 inverse -31| "────────────────────────────────────────────────────────────────────────────────────────────────────" +36| "────────────────────────────────────────────────────────────────────────────────────────────────────" style 0-99 dim -32| "/workspace/project ↑3.1k ↓158 idle reasoning:on tools:compact" +37| "/workspace/project ↑4.1k ↓227 idle reasoning:on tools:compact" style 0-49 dim style 67-99 dim -33-35| <blank> +38-39| <blank> diff --git a/packages/core/tools/src/code-mode.ts b/packages/core/tools/src/code-mode.ts index 713978b87e..87702462e9 100644 --- a/packages/core/tools/src/code-mode.ts +++ b/packages/core/tools/src/code-mode.ts @@ -146,7 +146,6 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () => const parts = [value.logs.join('\n'), rendered].filter(part => part.length > 0) return [{ type: 'text', text: parts.length > 0 ? parts.join('\n') : '(run_code completed with no output)' }] }, - presentationMeta: (_args, value) => ({ logs: value.logs }), }, async execute(args, exec): Promise<RunCodeOutput> { const runtime = requireRuntime() diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index 7f76a0b539..496c3d55b6 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -346,7 +346,7 @@ describe('the run_code dispatch bridge', () => { { parentCallId: 'call-1', subCallId: 'call-1:code:1', name: 'echo', arguments: { value: 'one' }, isError: false, resultSummary: 'echo:one' }, { parentCallId: 'call-1', subCallId: 'call-1:code:2', name: 'echo', arguments: { value: 'two' }, isError: false, resultSummary: 'echo:two' }, ]) - expect(result.meta).toEqual({ logs: ['saw echo:one'] }) + expect(result.meta).toBeUndefined() }) it('exposes only an opaque parent token to nested result observers', async () => { @@ -683,7 +683,6 @@ describe('the run_code dispatch bridge', () => { ['result only', 'returned', false], ['logs plus result', 'printed\nreturned', false], ['no output', '(run_code completed with no output)', false], - ['failure', 'Error: code run failed (output-limit): outer output exceeded 8 bytes', true], ['spilled result', 'HEAD\n\n(Omitted 100 bytes. Full formatted result stored at: /tmp/run-code.txt.)\n\nTAIL', false], ] as const)('presents %s from the final post-policy content', async (_name, text, isError) => { const { ctx } = await setup({ mode: 'code' }) @@ -700,6 +699,27 @@ describe('the run_code dispatch bridge', () => { })).toEqual({ card: 'generic', content }) }) + it('presents failure content produced by the canonical execution pipeline', async () => { + const { ctx, runtime } = await setup({ mode: 'code' }) + runtime.behavior = () => Promise.resolve({ + logs: ['captured before failure'], + error: { kind: 'output-limit', message: 'outer output exceeded 8 bytes' }, + }) + + const result = await runCode(ctx, 'return 1') + const tool = ctx.tools.get(RUN_CODE_NAME)! + + expect(result.isError).toBe(true) + expect(result.content).toEqual([{ + type: 'text', + text: 'Error: code run failed (output-limit): outer output exceeded 8 bytes\nCaptured output:\ncaptured before failure', + }]) + expect(tool.presentResult?.({ code: 'return 1' }, result)).toEqual({ + card: 'generic', + content: result.content, + }) + }) + it('renders non-text sub-result blocks as placeholders and truncates long event summaries', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) const { agent, events } = fakeAgent() From 9a96d7c34198c68f93e9c4128434c8e04d131e10 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:50:15 +0800 Subject: [PATCH 035/368] docs(code-runtime): refresh config catalog --- docs/config-catalog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index c564036903..b923db756c 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -291,7 +291,7 @@ export interface Config { } ``` -Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:20`](../packages/code-runtime/code-runtime-worker/src/index.ts) +Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:21`](../packages/code-runtime/code-runtime-worker/src/index.ts) ## `@deepseek-ai/dsh-compact-basic` From e134e7cc38131b0ad66cd691faf877aeeae37580 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:06:52 +0800 Subject: [PATCH 036/368] test(snapshot): refresh unified tool schema fixtures --- .../snapshots/lsp-definition/tool-schemas.expected.json | 8 ++++++-- .../cordis-dynamic-toolchain/terminal.expected.txt | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/acp-agent/tests/snapshots/lsp-definition/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/lsp-definition/tool-schemas.expected.json index 4fa5010b72..5d27e93da3 100644 --- a/examples/acp-agent/tests/snapshots/lsp-definition/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/lsp-definition/tool-schemas.expected.json @@ -325,6 +325,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -399,7 +400,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { @@ -410,6 +411,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -428,6 +430,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -459,7 +462,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ diff --git a/examples/tui-agent/tests/snapshots/cordis-dynamic-toolchain/terminal.expected.txt b/examples/tui-agent/tests/snapshots/cordis-dynamic-toolchain/terminal.expected.txt index 02fbde0fe0..2913d401da 100644 --- a/examples/tui-agent/tests/snapshots/cordis-dynamic-toolchain/terminal.expected.txt +++ b/examples/tui-agent/tests/snapshots/cordis-dynamic-toolchain/terminal.expected.txt @@ -111,6 +111,6 @@ buffer style 1-1 inverse 48| "────────────────────────────────────────────────────────────────────────────────────────────────────" style 0-99 dim -49| "/tmp/dsh-tui-snapshot-cordis-dyn ↑18 ↓18 7% context tools:compact deepseek-v4-flash(reasoning:on)" +49| "/tmp/dsh-tui-snapshot-cordis-dyn ↑18 ↓18 8% context tools:compact deepseek-v4-flash(reasoning:on)" style 0-31 dim style 42-99 dim From 0ed8e7baf62ee5243ea67e9a864ca2000fd2ca63 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:15:40 +0800 Subject: [PATCH 037/368] docs(lsp): document canonical query results --- .../2026-07-20-canonical-tool-output-contract.i18n.yaml | 4 ++-- .../architecture/2026-07-20-canonical-tool-output-contract.md | 1 + .../2026-07-20-canonical-tool-output-contract.zh.md | 1 + packages/lsp/tool-lsp/README.md | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml index d76de6a74e..c4afb670c9 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml @@ -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 -2026-07-20-canonical-tool-output-contract.md: 226ca3274e08e2d46d29075ee412d4945fda753a -2026-07-20-canonical-tool-output-contract.zh.md: c5c5e46e267dd3d0795df7fb6761e867e52b5b2b +2026-07-20-canonical-tool-output-contract.md: feca70f8fed284f64c5a5560e3fddd3e2aa9a752 +2026-07-20-canonical-tool-output-contract.zh.md: 0fca743c1cc050236787ce25553684bd393ba861 diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md index 226ca3274e..feca70f8fe 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md @@ -46,6 +46,7 @@ The first-party tools preserve their existing Native text while returning domain | `glob` | `{ paths: string[] }` | | `grep` | `{ matches: [{ path, lineNumber, line }] }` | | `web_search` / `web_fetch` | The normalized `WebSearchResult` / `WebFetchResult` | +| `lsp` | `{ kind: "locations", locations, resolvedWorkspaceRoot }` or `{ kind: "hover", hover }` | | `bash` | `{ kind: "background", taskId }` or `{ kind: "foreground" } & BashRunResult` | | `task_output` / `task_list` / `task_kill` | Public task snapshots without owner or notification bookkeeping | | `subagent` | Background task handle or `{ kind: "foreground", runId, output: JsonValue[] }` | diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md index c5c5e46e26..0fca743c1c 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md @@ -46,6 +46,7 @@ type ToolExecutionResult = | `glob` | `{ paths: string[] }` | | `grep` | `{ matches: [{ path, lineNumber, line }] }` | | `web_search` / `web_fetch` | 归一化后的 `WebSearchResult` / `WebFetchResult` | +| `lsp` | `{ kind: "locations", locations, resolvedWorkspaceRoot }` 或 `{ kind: "hover", hover }` | | `bash` | `{ kind: "background", taskId }` 或 `{ kind: "foreground" } & BashRunResult` | | `task_output` / `task_list` / `task_kill` | 不含所有者或通知账务字段的公开任务快照 | | `subagent` | 后台任务句柄或 `{ kind: "foreground", runId, output: JsonValue[] }` | diff --git a/packages/lsp/tool-lsp/README.md b/packages/lsp/tool-lsp/README.md index 4a844d2537..e2f15ba79a 100644 --- a/packages/lsp/tool-lsp/README.md +++ b/packages/lsp/tool-lsp/README.md @@ -8,7 +8,7 @@ Namespace plugin (`name` / `inject` / `Config` / `apply`, no default export). In `lsp` accepts `operation` (`goToDefinition` | `findReferences` | `goToImplementation` | `hover`), `file_path`, `line`, and `character`. `line` and `character` are positive, one-based UTF-16 cursor coordinates; the tool converts them to the seam's zero-based positions and converts rendered locations back. `findReferences` includes declarations so impact analysis does not omit the defining site. Provider, language id, workspace root, limits, timeout, initialization, and executable stay outside model input. -The tool requires the workspace root from the session `header.cwd`, with no fallback: absence fails as `LSP_WORKSPACE_REQUIRED` before querying. Locations render as stable, file-grouped `path:line:character` entries relativized against the result's `resolvedWorkspaceRoot` (the provider's canonical root), not the session cwd — so a symlinked cwd still renders in-workspace results as workspace-relative paths; a `file:` URI becomes a workspace-relative path (inside) or absolute path (outside), and any other URI stays verbatim. Empty locations and `null` hover are successful no-result responses; malformed provider payloads remain structured errors. +The tool requires the workspace root from the session `header.cwd`, with no fallback: absence fails as `LSP_WORKSPACE_REQUIRED` before querying. Its canonical result is the complete normalized seam union: `{ kind: "locations", locations, resolvedWorkspaceRoot }` or `{ kind: "hover", hover }`; Code Mode can inspect every acquired location and zero-based range directly. Native rendering then projects stable, file-grouped `path:line:character` entries relativized against the result's `resolvedWorkspaceRoot` (the provider's canonical root), not the session cwd — so a symlinked cwd still renders in-workspace results as workspace-relative paths; a `file:` URI becomes a workspace-relative path (inside) or absolute path (outside), and any other URI stays verbatim. Empty locations and `null` hover are successful no-result responses; malformed provider payloads remain structured errors. ## Configuration @@ -58,7 +58,7 @@ Prefix-stable while the visible tool definition and order are unchanged; registr #### What the model sees -File-grouped `path:line:character` location lines or normalized hover text, capped first by `maxLocations` and then by `maxResultChars`; omission and truncation markers are included inside the complete character cap. Empty results use distinct `No results.` / `No hover information.` lines. +File-grouped `path:line:character` location lines or normalized hover text, capped first by `maxLocations` and then by `maxResultChars`; omission and truncation markers are included inside the complete character cap. These caps affect only Native/model presentation, not the canonical value. Empty results use distinct `No results.` / `No hover information.` lines. #### Token effect From 5b36be339d918962feb09844f79f828e2727fe24 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:26:52 +0800 Subject: [PATCH 038/368] docs(architecture): keep canonical output map concise --- docs/architecture.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 203c118186..5106fcc706 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -98,7 +98,7 @@ forever: exclusive -> one-call barrier parallel -> rolling pool, <= maxParallelToolCalls in flight; reclassify before start each start -> 'tool/call' -> ordered tools/pre-execute -> concurrent tools/execute - body value -> validate/snapshot -> Native/meta projection + body -> validate/snapshot -> Native/meta each model-order result -> ordered tools/post-execute -> projected 'tool/result' append accepted tool-batch context after all recorded results, then steering agent/post-step @@ -112,7 +112,7 @@ forever: Each step assembles ordered prompt sections, tool schemas, and `{{name}}` variables; unknown or valueless references fail the turn. `dsh-system-prompt` owns the harness identity and default persona, which an agent scope may shadow. The loop supplies `model` and `cwd` ([prompt ownership](../.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)). -Tool success separates an execution-local canonical JSON value from Native projections; post-policy replaces one projection or blocks, and the loop persists only projections ([contract](../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md)). Tool-time context—including async `agent.inject()` notices and post-tool `additionalContexts`—settles after results. Steering drains; before signal closure, `agent/post-step` observes durable output, results, context, and steering. Leftovers queue. Terminal `agent/turn-stop` runs after continuation and steering folding, remains authoritative through close/flush, and discards later steering while preserving queued prompts. +Canonical tool JSON stays execution-local; post-policy replaces value or presentation, or blocks; the loop persists projections ([contract](../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md)). Tool-time context—including async `agent.inject()` notices and post-tool `additionalContexts`—settles after results. Steering drains; before signal closure, `agent/post-step` observes durable output, results, context, and steering. Leftovers queue. Terminal `agent/turn-stop` runs after continuation and steering folding, remains authoritative through close/flush, and discards later steering while preserving queued prompts. Pruning precedes summaries; overflow retries require durable progress. Bounded transient retries compose on `agent/request-error`; cancellation wins ([compaction](../.agents/notes/implemented/architecture/2026-07-10-after-call-compaction-pressure-and-overflow-recovery.md), [retry](../.agents/notes/implemented/architecture/2026-06-21-bounded-llm-request-recovery.md)). From 8ae6e1ffbd61d7fb64801962649d9a11568ab011 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 20:00:09 +0800 Subject: [PATCH 039/368] docs(architecture): retain canonical output budget --- docs/architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture.md b/docs/architecture.md index b8a7d7c4dd..384ebc5dcd 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -113,7 +113,7 @@ forever: Each step assembles ordered prompt sections, tool schemas, and `{{name}}` variables; unknown or valueless references fail the turn. `dsh-system-prompt` owns the harness identity and default persona, which an agent scope may shadow. The loop supplies `model` and `cwd` ([prompt ownership](../.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)). -Canonical tool JSON stays execution-local; post-policy replaces value or presentation, or blocks; the loop persists projections ([contract](../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md)). Tool-time context—including async `agent.inject()` notices and post-tool `additionalContexts`—settles after results. Steering drains; before signal closure, `agent/post-step` observes durable output, results, context, and steering. Leftovers queue. Terminal `agent/turn-stop` runs after continuation and steering folding, remains authoritative through close/flush, and discards later steering while preserving queued prompts. +Canonical JSON stays execution-local; post-policy replaces value or presentation, or blocks; the loop persists projections ([contract](../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md)). Tool-time context—including async `agent.inject()` notices and post-tool `additionalContexts`—settles after results. Steering drains; before signal closure, `agent/post-step` observes durable output, results, context, and steering. Leftovers queue. Terminal `agent/turn-stop` runs after continuation and steering folding, remains authoritative through close/flush, and discards later steering while preserving queued prompts. Pruning precedes summaries; overflow retries require durable progress. Bounded transient retries compose on `agent/request-error`; cancellation wins ([compaction](../.agents/notes/implemented/architecture/2026-07-10-after-call-compaction-pressure-and-overflow-recovery.md), [retry](../.agents/notes/implemented/architecture/2026-06-21-bounded-llm-request-recovery.md)). From 60a88114c21db0760f6e95d40d2a62f2116aa5ac Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 21:10:45 +0800 Subject: [PATCH 040/368] docs(code-mode): align result presentation contract --- .agents/notes/implemented/feature/2026-06-15-code-mode.md | 2 +- .../feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml | 4 ++-- .../feature/2026-07-20-code-mode-typed-tool-returns.md | 2 +- .../feature/2026-07-20-code-mode-typed-tool-returns.zh.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.md index b845f6dde7..4182089478 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.md @@ -42,7 +42,7 @@ Under `'code'` and `'both'` the registry owns `run_code` as a reserved presentat 1. **Build bindings.** One run-scoped signal follows outer cancellation and is aborted whenever the run settles. Each visible tool binding snapshots lossless-JSON arguments, waits on the serialization queue, executes with a deterministic call id and the outer token as `parent`, defers returned contexts through the outer execution, and logs `tool/code-dispatch`. Success returns the tool's final canonical JSON value; failure becomes the program-visible `ToolCallError`. Every sub-call retains its own immutable execution identity and traverses the full tool pipeline. 2. **Runs the program**: `ctx.codeRuntime.run({ program: args.code, bindings: [{ global: 'tools', functions }], signal: runController.signal })`. The runtime receives the run-scoped signal, not only the caller's outer signal, so any way the outer run settles also aborts work inside the runtime. -3. **Settle after quiescence.** When the runtime settles, the bridge aborts outstanding work and drains the dispatch queue before returning. Success returns captured output and presentation metadata. A runtime failure becomes `CodeRunFailedError`; backend rejection uses the registry's normal error boundary. Both produce structured error results, and no sub-call can append after `run_code` settles. +3. **Settle after quiescence.** When the runtime settles, the bridge aborts outstanding work and drains the dispatch queue before returning. Success returns captured logs and the completion value as canonical output; the registry renders that value into durable `tool/result.content`, which the result card reads directly. A runtime failure becomes `CodeRunFailedError`; backend rejection uses the registry's normal error boundary. Both produce structured error results, and no sub-call can append after `run_code` settles. **Sub-call contexts are deferred through the parent.** Injecting inside `run_code` would break parent call/result adjacency, so `ToolRunContext.deferContext()` collects every sub-result `additionalContexts` entry in dispatch order. The registry carries that array even when the program later throws, and the loop appends each entry only after the outer result and every sibling result in the step. An outer post-execute block discards tool-deferred entries and exposes only contexts explicitly attached by the blocking decision. diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml index 3b3e9544f2..1e491cc223 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml @@ -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 -2026-07-20-code-mode-typed-tool-returns.md: 1beecbc9e5f61ac5dce50aeba508ce75cb0ce507 -2026-07-20-code-mode-typed-tool-returns.zh.md: 0dbad69f6b8120e0904f026961b004855d23f3ab +2026-07-20-code-mode-typed-tool-returns.md: a8503f7a57c0a34624b6e923185078307ece6c68 +2026-07-20-code-mode-typed-tool-returns.zh.md: f2a65286d3eb89ad80920a11dfd14d784d878d35 diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md index 1beecbc9e5..a8503f7a57 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md @@ -75,7 +75,7 @@ Dynamic Cordis mounting follows the same rule: `cordis_mount` returns `{ id, plu Nested dispatch keeps the existing bounded `tool/code-dispatch.resultSummary` for diagnostics but does not persist canonical values. `tool/result` continues to persist only rendered content, error, and optional metadata. This is deliberately not a session-format change, so `SESSION_FORMAT_VERSION` remains unchanged and replay cannot recreate intermediate program values. -The opaque `exec.parent` token marks nested calls. Presentation metadata and generic or tool-owned spill projections skip those calls because they have no direct result card and their canonical values never enter context. The outer `run_code` call alone computes presentation metadata, produces one card, and may spill its final post-policy presentation. +The opaque `exec.parent` token marks nested calls. Presentation metadata and generic or tool-owned spill projections skip those calls because they have no direct result card and their canonical values never enter context. The outer `run_code` call alone produces one card and may spill its final post-policy presentation; its presenter reads durable `tool/result.content` directly instead of persisting a presentation-metadata copy. ## Testing diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md index 0dbad69f6b..f2a65286d3 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md @@ -75,7 +75,7 @@ worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造 嵌套分发会为诊断保留既有的有界 `tool/code-dispatch.resultSummary`,但不会持久化规范值。`tool/result` 继续只持久化渲染后的内容、错误和可选元数据。这并非会话格式变更,因此 `SESSION_FORMAT_VERSION` 保持不变,回放也无法重建程序的中间值。 -不透明的 `exec.parent` token 用于标识嵌套调用。由于这些调用没有直接对应的结果卡片,而且其规范值永远不会进入上下文,展示元数据以及通用或工具自有的输出落盘投影都会跳过它们。只有外层 `run_code` 调用会计算展示元数据、生成一张卡片,并且可能将 post-policy 处理后的最终展示写入落盘文件。 +不透明的 `exec.parent` token 用于标识嵌套调用。由于这些调用没有直接对应的结果卡片,而且其规范值永远不会进入上下文,展示元数据以及通用或工具自有的输出落盘投影都会跳过它们。只有外层 `run_code` 调用会生成一张卡片,并且可能将 post-policy 处理后的最终展示写入落盘文件;它的展示逻辑直接读取持久化的 `tool/result.content`,而不是持久化一份展示元数据副本。 ## 测试 From 379ac32401eb5b71894436dd28b3f88463010213 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 21:20:41 +0800 Subject: [PATCH 041/368] fix(code-runtime): close outer boundary bypasses --- .../code-runtime-worker/src/index.ts | 21 ++++++-- .../code-runtime-worker/tests/runtime.spec.ts | 48 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index f59f3e8d9a..0fa66dbd71 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -269,7 +269,7 @@ export class WorkerCodeRuntime extends CodeRuntime { if (this.disposed) throw new Error('dsh-code-runtime-worker: run() after disposal') const bindings = this.validateBindings(request) if (request.signal?.aborted) { - return { logs: [], error: { kind: 'abort', message: String(request.signal.reason) } } + return this.failureBeforeWorker({ kind: 'abort', message: String(request.signal.reason) }) } let code: string @@ -280,12 +280,17 @@ export class WorkerCodeRuntime extends CodeRuntime { // A program that does not survive the type-strip (syntax error, // non-erasable syntax like `enum`) is a program failure, reported the // same way a thrown exception would be — and no worker ever spawns. - return { logs: [], error: { kind: 'exception', message: messageOf(error) } } + return this.failureBeforeWorker({ kind: 'exception', message: messageOf(error) }) } return await this.execute(request, code, bindings) } + /** Apply the outer-output ledger to failures that occur before a worker owns one. */ + private failureBeforeWorker(error: CodeRunFailure): CodeRunResult { + return new OutputLedger(this.config.maxOutputBytes).failure([], error) + } + /** Reject (seam misuse) malformed binding namespaces: non-identifier or reserved globals, duplicates, and the `console` collision. */ private validateBindings(request: CodeRunRequest): Map<string, Record<string, CodeBindingFunction>> { const bindings = new Map<string, Record<string, CodeBindingFunction>>() @@ -405,9 +410,19 @@ export class WorkerCodeRuntime extends CodeRuntime { reply({ type: 'reply', id: message.id, ok: false, message: `unknown binding ${JSON.stringify(`${message.global}.${message.name}`)}` }) return } + let args: CodeJsonValue | undefined + try { + args = snapshotJsonValue(message.args) as CodeJsonValue | undefined + } catch { + args = undefined + } + if (args === undefined) { + reply({ type: 'reply', id: message.id, ok: false, message: 'binding arguments must be lossless JSON' }) + return + } void (async () => { try { - const resolved = await fn(message.args) + const resolved = await fn(args) let value: CodeJsonValue | undefined try { value = snapshotJsonValue(resolved) diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index 5615062286..8bcee8389b 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -171,6 +171,19 @@ describe('WorkerCodeRuntime — budgets and containment (real workers)', () => { expect(result.error).toEqual({ kind: 'abort', message: 'too-late' }) }) + it('applies the outer-output cap to failures before worker startup', async () => { + const capped = await setup({ maxOutputBytes: 64 }) + const controller = new AbortController() + controller.abort('A'.repeat(1_000)) + const aborted = await capped.runtime.run({ program: 'return 1', bindings: [], signal: controller.signal }) + expect(aborted).toEqual({ logs: [], error: { kind: 'output-limit', message: 'outer output exceeded 64 bytes' } }) + + const minimal = await setup({ maxOutputBytes: 4 }) + const invalid = await minimal.runtime.run({ program: 'enum E { A }\nreturn 1', bindings: [] }) + expect(invalid.error?.kind).toBe('output-limit') + expect(Buffer.byteLength(JSON.stringify(invalid.logs), 'utf8') + Buffer.byteLength(JSON.stringify(invalid.error?.message), 'utf8')).toBeLessThanOrEqual(4) + }) + it('drops a binding resolution that lands after the run settled', async () => { const { runtime } = await setup() const controller = new AbortController() @@ -449,6 +462,41 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { })) }) + it('rejects forged lossy binding arguments again at the host boundary', async () => { + const { runtime } = await setup() + let calls = 0 + const result = await runtime.run({ + program: ` + const { parentPort } = await import('node:worker_threads'); + const forged = (id, args) => new Promise((resolve) => { + const receive = (message) => { + if (message?.type !== 'reply' || message.id !== id) return; + parentPort.off('message', receive); + resolve(message); + }; + parentPort.on('message', receive); + parentPort.postMessage({ type: 'call', id, global: 'tools', name: 'never', args }); + }); + const sparse = []; sparse.length = 1; + const cycle = {}; cycle.self = cycle; + return await Promise.all([ + forged(8001, new Date()), + forged(8002, -0), + forged(8003, sparse), + forged(8004, cycle), + ]); + `, + bindings: tools({ never: async () => { calls += 1; return null } }), + }) + expect(calls).toBe(0) + expect(result.value).toEqual([8001, 8002, 8003, 8004].map(id => ({ + type: 'reply', + id, + ok: false, + message: 'binding arguments must be lossless JSON', + }))) + }) + it('contains throwing getters while snapshotting binding resolutions', async () => { const { runtime } = await setup() const result = await runtime.run({ From acc628f3afde26ac47168434a3daa4f42351c936 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 21:37:11 +0800 Subject: [PATCH 042/368] fix(tools): preserve literal and realm-safe schemas --- ...20-unified-json-value-schema-dsl.i18n.yaml | 4 +-- ...026-07-20-unified-json-value-schema-dsl.md | 2 +- ...-07-20-unified-json-value-schema-dsl.zh.md | 2 +- packages/core/session/src/json.ts | 22 +++++++++++----- packages/core/session/tests/json.spec.ts | 26 ++++++++++++++++++- packages/core/tools/src/schema.ts | 2 +- packages/core/tools/tests/json-schema.spec.ts | 11 ++++++++ packages/core/tools/tests/tools.spec.ts | 15 +++++++++++ 8 files changed, 72 insertions(+), 12 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml index f434c81118..0cd154e190 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml @@ -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 -2026-07-20-unified-json-value-schema-dsl.md: ab7bb268407ac26230283172ebb291de80412bf2 -2026-07-20-unified-json-value-schema-dsl.zh.md: 479699fc2d58666b86861f0ea1db907ae4957dc5 +2026-07-20-unified-json-value-schema-dsl.md: 94c3f5aa5fcb84abddc58e8fd298188b3284f7ea +2026-07-20-unified-json-value-schema-dsl.zh.md: d8362c2c9987689fbd812b6c16aae815f56062e1 diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md index ab7bb26840..94c3f5aa5f 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md @@ -12,7 +12,7 @@ Tool parameters used a small author DSL while subagent/workflow structured outpu `dsh-tools` owns one JSON-value schema vocabulary with two representations. `ValueSchemaSpec` is the author form for any JSON root; `ParameterSchemaSpec` is its implicit object-property-map form with per-property `required: true`. `JsonSchemaNode` is the raw wire form. Both support string, finite number, integer, boolean, null, array, object, type-correct scalar `enum`/`const`, and exact-one `oneOf`; `{ type: 'json' }` is author-only sugar for an annotation-only unconstrained raw node. -An explicit author object must declare `additionalProperties: true | false`. The implicit parameter root and raw JSON Schema preserve the standard open default. `InferValue<S>` and `InferArgs<P>` derive TypeScript values from the same declarations that `valueSchemaSpecToJsonSchema()` and `parameterSchemaSpecToJsonSchema()` compile. `assertSupportedJsonSchema()` rejects unsupported or misplaced keywords, and `validateJsonSchemaValue()` enforces the accepted subset against the lossless `JsonValue` boundary: no `undefined`, negative zero, non-finite numbers, sparse arrays, cycles, exotic objects, functions, symbols, or other coercive values. +An explicit author object must declare `additionalProperties: true | false`. The implicit parameter root and raw JSON Schema preserve the standard open default. `InferValue<S>` and `InferArgs<P>` derive TypeScript values from the same declarations that `valueSchemaSpecToJsonSchema()` and `parameterSchemaSpecToJsonSchema()` compile. `assertSupportedJsonSchema()` rejects unsupported or misplaced keywords, and `validateJsonSchemaValue()` enforces the accepted subset against the lossless `JsonValue` boundary: no `undefined`, negative zero, non-finite numbers, sparse arrays, cycles, exotic objects, functions, symbols, or other coercive values. Intrinsic plain Object and Array containers remain plain across JavaScript realms; subclasses remain exotic. Object-rooting is a consumer rule rather than a vocabulary restriction. Subagent and workflow caller-defined structured outputs use `assertObjectJsonSchema()` and `ObjectJsonSchema`; tool outputs may use any root. Dynamic Cordis registrations rebuild realm-foreign schemas into host-owned JSON, preserve raw-wrapper openness, and require direct-DSL object openness before calling the same compiler. diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md index 479699fc2d..d8362c2c99 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md @@ -12,7 +12,7 @@ Status: implemented `dsh-tools` 以两种表示形式统一管理一套 JSON 值 schema 词汇。`ValueSchemaSpec` 是可描述任意 JSON 根类型的作者侧形式;`ParameterSchemaSpec` 是其隐式对象属性映射形式,每个属性可标记 `required: true`。`JsonSchemaNode` 是原始协议表示。两种形式都支持字符串、有限数值、整数、布尔值、null、数组、对象、类型正确的标量 `enum`/`const`,以及要求恰好匹配一个分支的 `oneOf`;`{ type: 'json' }` 仅是作者侧语法糖,会编译为仅含注解、不施加约束的原始节点。 -显式的作者侧对象必须声明 `additionalProperties: true | false`。隐式参数根对象和原始 JSON Schema 保留标准的默认开放语义。`InferValue<S>` 和 `InferArgs<P>` 根据同一份声明推导 TypeScript 值,`valueSchemaSpecToJsonSchema()` 和 `parameterSchemaSpecToJsonSchema()` 也将这些声明编译为 JSON Schema。`assertSupportedJsonSchema()` 会拒绝不受支持或位置错误的关键字;`validateJsonSchemaValue()` 则以无损 `JsonValue` 边界校验受支持的子集,不允许 `undefined`、负零、非有限数、稀疏数组、循环引用、非普通对象、函数、symbol 及其他需要强制转换的值。 +显式的作者侧对象必须声明 `additionalProperties: true | false`。隐式参数根对象和原始 JSON Schema 保留标准的默认开放语义。`InferValue<S>` 和 `InferArgs<P>` 根据同一份声明推导 TypeScript 值,`valueSchemaSpecToJsonSchema()` 和 `parameterSchemaSpecToJsonSchema()` 也将这些声明编译为 JSON Schema。`assertSupportedJsonSchema()` 会拒绝不受支持或位置错误的关键字;`validateJsonSchemaValue()` 则以无损 `JsonValue` 边界校验受支持的子集,不允许 `undefined`、负零、非有限数、稀疏数组、循环引用、非普通对象、函数、symbol 及其他需要强制转换的值。内建的普通 Object 和 Array 容器跨 JavaScript 运行域后仍视为普通容器;其子类仍视为非普通对象。 对象根限制属于消费方规则,不属于 schema 词汇本身。subagent 和工作流中由调用方定义的结构化输出通过 `assertObjectJsonSchema()` 和 `ObjectJsonSchema` 保持对象根限制;工具输出可以使用任意根类型。动态 Cordis 注册会把跨 JavaScript 运行域传入的 schema 重建为当前运行时持有的 JSON,保留原始包装层的默认开放语义,并要求直接使用 DSL 声明的对象明确选择开放方式,然后再调用同一编译器。 diff --git a/packages/core/session/src/json.ts b/packages/core/session/src/json.ts index f0d3d42266..e2c681b100 100644 --- a/packages/core/session/src/json.ts +++ b/packages/core/session/src/json.ts @@ -12,6 +12,18 @@ */ export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } +/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */ +function hasPlainArrayPrototype(value: unknown[]): boolean { + const prototype: unknown = Object.getPrototypeOf(value) + return Array.isArray(prototype) && Object.getPrototypeOf(Object.getPrototypeOf(prototype)) === null +} + +/** Whether an object is a plain or null-prototype record from any JavaScript realm. */ +function hasPlainObjectPrototype(value: object): boolean { + const prototype: unknown = Object.getPrototypeOf(value) + return prototype === null || Object.getPrototypeOf(prototype) === null +} + /** * Validate and detach lossless JSON in one read per property, so a stateful * getter cannot change between validation and copying. Accepts ordinary arrays, @@ -46,7 +58,7 @@ export function snapshotJsonValue<T>(value: T): T | undefined { ancestors.add(current) try { if (Array.isArray(current)) { - if (Object.getPrototypeOf(current) !== Array.prototype) return undefined + if (!hasPlainArrayPrototype(current)) return undefined const length = current.length // Every ordinary array owns `length`; dense indexed elements account // for the remaining keys. Anything else would be lost by JSON and by @@ -62,8 +74,7 @@ export function snapshotJsonValue<T>(value: T): T | undefined { return snapshot } - const prototype = Object.getPrototypeOf(current) as unknown - if (prototype !== Object.prototype && prototype !== null) return undefined + if (!hasPlainObjectPrototype(current)) return undefined const snapshot: { [key: string]: JsonValue } = {} for (const key of Object.keys(current)) { const item = visit((current as Record<string, unknown>)[key]) @@ -115,7 +126,7 @@ export function isJsonValue(value: unknown, seen: Set<object> = new Set()): bool seen.add(value) try { if (Array.isArray(value)) { - if (Object.getPrototypeOf(value) !== Array.prototype) return false + if (!hasPlainArrayPrototype(value)) return false if (Reflect.ownKeys(value).length !== value.length + 1) return false // Reject sparse arrays: a hole is skipped by `every`/`forEach` but // JSON.stringify writes it as `null`, so `[1, , 3]` would round-trip @@ -127,8 +138,7 @@ export function isJsonValue(value: unknown, seen: Set<object> = new Set()): bool return true } // Plain object only (reject Map/Set/Date/class instances). - const proto = Object.getPrototypeOf(value) as unknown - if (proto !== Object.prototype && proto !== null) return false + if (!hasPlainObjectPrototype(value)) return false return Object.values(value).every(v => isJsonValue(v, seen)) } finally { seen.delete(value) diff --git a/packages/core/session/tests/json.spec.ts b/packages/core/session/tests/json.spec.ts index 35d521f6d1..1d00d70787 100644 --- a/packages/core/session/tests/json.spec.ts +++ b/packages/core/session/tests/json.spec.ts @@ -1,5 +1,6 @@ +import { runInNewContext } from 'node:vm' import { describe, expect, it } from 'vitest' -import { isJsonValue, snapshotJsonValue } from '@deepseek-ai/dsh-session' +import { isJsonValue, snapshotJsonValue, type JsonValue } from '@deepseek-ai/dsh-session' describe('snapshotJsonValue', () => { it('copies the complete JSON scalar vocabulary and rejects unsupported scalars', () => { @@ -36,6 +37,22 @@ describe('snapshotJsonValue', () => { expect(Object.getPrototypeOf(snapshot.list[0])).toBe(Object.prototype) }) + it('accepts intrinsic plain containers from another JavaScript realm', () => { + const foreign = runInNewContext('({ object: { nested: [1] }, array: [2, { ok: true }] })') as { + object: { nested: number[] } + array: JsonValue[] + } + + expect(isJsonValue(foreign.object)).toBe(true) + expect(isJsonValue(foreign.array)).toBe(true) + const objectSnapshot = snapshotJsonValue(foreign.object)! + const arraySnapshot = snapshotJsonValue(foreign.array)! + expect(objectSnapshot).toEqual({ nested: [1] }) + expect(arraySnapshot).toEqual([2, { ok: true }]) + expect(Object.getPrototypeOf(objectSnapshot)).toBe(Object.prototype) + expect(Object.getPrototypeOf(arraySnapshot)).toBe(Array.prototype) + }) + it('reads each object value and array slot once while materializing', () => { class Exotic { readonly accepted = false @@ -77,10 +94,17 @@ describe('snapshotJsonValue', () => { Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) const cyclic: Record<string, unknown> = {} cyclic.self = cyclic + const foreignExotics = runInNewContext(`(() => { + class Box { constructor() { this.value = 1 } } + class List extends Array {} + return [new Box(), new List(1)] + })()`) as [object, unknown[]] expect(snapshotJsonValue(new ExoticObject())).toBeUndefined() expect(snapshotJsonValue(new Map([['value', 1]]))).toBeUndefined() expect(snapshotJsonValue(new ExoticArray(1))).toBeUndefined() + expect(snapshotJsonValue(foreignExotics[0])).toBeUndefined() + expect(snapshotJsonValue(foreignExotics[1])).toBeUndefined() expect(snapshotJsonValue(sparse)).toBeUndefined() expect(snapshotJsonValue(compensatedSparse)).toBeUndefined() expect(snapshotJsonValue(decorated)).toBeUndefined() diff --git a/packages/core/tools/src/schema.ts b/packages/core/tools/src/schema.ts index 4a559d47eb..9f52eb6e33 100644 --- a/packages/core/tools/src/schema.ts +++ b/packages/core/tools/src/schema.ts @@ -378,7 +378,7 @@ export interface DefineToolOptions<S extends ParameterSchemaSpec> { * @param options - typed definition and optional presenters. * @returns A registry-ready definition. */ -export function defineTool<S extends ParameterSchemaSpec>(options: DefineToolOptions<S>): ToolDefinition { +export function defineTool<const S extends ParameterSchemaSpec>(options: DefineToolOptions<S>): ToolDefinition { // Object-literal methods do not use `this`; retaining references is safe. // eslint-disable-next-line @typescript-eslint/unbound-method const userExecute = options.execute diff --git a/packages/core/tools/tests/json-schema.spec.ts b/packages/core/tools/tests/json-schema.spec.ts index 96feb9b63d..fb03a75ae2 100644 --- a/packages/core/tools/tests/json-schema.spec.ts +++ b/packages/core/tools/tests/json-schema.spec.ts @@ -1,3 +1,4 @@ +import { runInNewContext } from 'node:vm' import { describe, expect, it } from 'vitest' import { assertObjectJsonSchema, @@ -187,6 +188,16 @@ describe('the enforced raw JSON Schema subset', () => { .toEqual(['schema.examples annotation must be lossless JSON data']) }) + it('accepts lossless annotation containers from another JavaScript realm', () => { + const schema = runInNewContext(`({ + type: 'object', + default: { x: 1 }, + examples: [[{ ok: true }]], + })`) as unknown + + expect(() => { assertSupportedJsonSchema(schema) }).not.toThrow() + }) + it('rejects cyclic/exotic schema structure but permits sibling reuse', () => { const cyclic: Record<string, unknown> = { type: 'object' } cyclic.properties = { self: cyclic } diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index 5ddac2cd31..80f5812071 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -1420,6 +1420,21 @@ describe('defineTool validation (the runtime-validation Agent Note, part 1)', () }) describe('defineTool presentation (presentCall / presentResult)', () => { + it('preserves inline enum and const literals in inferred arguments', () => { + defineTool({ + name: 'literal-args', + description: 'literal arguments', + parameters: { + mode: { type: 'string', enum: ['read', 'write'], required: true }, + attempt: { type: 'integer', const: 1 }, + }, + async execute(args) { + expectTypeOf(args).toEqualTypeOf<{ mode: 'read' | 'write'; attempt?: 1 }>() + return [] + }, + }) + }) + it('threads presentCall/presentResult onto the ToolDefinition with typed args', () => { const tool = defineTool({ name: 'demo', From 627eb6e00bd83296eb4288b7333b4926cc6d3053 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 21:56:38 +0800 Subject: [PATCH 043/368] fix(code-runtime): bound hostile output accounting --- .../code-runtime-worker/src/index.ts | 70 ++++++++----------- .../code-runtime-worker/src/output-json.ts | 68 +++++++++++++++++- .../tests/output-json.spec.ts | 45 +++++++++++- .../code-runtime-worker/tests/runtime.spec.ts | 16 +++++ 4 files changed, 156 insertions(+), 43 deletions(-) diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index 0fa66dbd71..198bec694b 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -15,7 +15,7 @@ import { CodeRuntime } from '@deepseek-ai/dsh-code-runtime' import type { CodeBindingFunction, CodeJsonValue, CodeRunFailure, CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' import { snapshotJsonValue } from '@deepseek-ai/dsh-session' import type { ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts' -import { truncateJsonStringBytes } from './output-json.ts' +import { jsonStringBytesUpTo, jsonValueBytesUpTo, truncateJsonStringBytes } from './output-json.ts' /** Plugin config: every execution cap, changeable from `cordis.yml` (no hardcoded tunables). */ export interface Config { @@ -141,11 +141,6 @@ function parseWorkerMessage(raw: unknown): WorkerToHost | undefined { } -/** Serialized byte size of one lossless JSON value. */ -function jsonBytes(value: CodeJsonValue): number { - return Buffer.byteLength(JSON.stringify(value), 'utf8') -} - /** One run's combined outer-output ledger; binding values never enter it. */ class OutputLedger { private bytes = 2 // JSON serialization of the empty logs array: [] @@ -155,9 +150,10 @@ class OutputLedger { /** Admit one exact log entry, or report that the hard cap was crossed. */ admit(text: string, sink: string[]): boolean { - const cost = Buffer.byteLength(JSON.stringify(text), 'utf8') + (this.entries > 0 ? 1 : 0) - if (this.bytes + cost > this.maxBytes) return false - this.bytes += cost + const separatorBytes = this.entries > 0 ? 1 : 0 + const stringBytes = jsonStringBytesUpTo(text, this.maxBytes - this.bytes - separatorBytes) + if (stringBytes === undefined) return false + this.bytes += stringBytes + separatorBytes this.entries += 1 sink.push(text) return true @@ -165,46 +161,45 @@ class OutputLedger { /** Finalize a successful absent-or-JSON completion against the combined cap. */ success(logs: string[], value?: CodeJsonValue): CodeRunResult { - if (value !== undefined && this.bytes + jsonBytes(value) > this.maxBytes) return this.limit(logs) + if (value !== undefined && jsonValueBytesUpTo(value, this.maxBytes - this.bytes) === undefined) return this.limit(logs) return { logs, ...value !== undefined ? { value } : {} } } /** Finalize a failure diagnostic, with output-limit taking precedence when combined bytes exceed the cap. */ failure(logs: string[], error: CodeRunFailure): CodeRunResult { - if (this.bytes + Buffer.byteLength(JSON.stringify(error.message), 'utf8') > this.maxBytes) return this.limit(logs) + if (jsonStringBytesUpTo(error.message, this.maxBytes - this.bytes) === undefined) return this.limit(logs) return { logs, error } } /** Build the explicit output-limit failure while retaining a fitting prefix of the final log. */ limit(logs: string[]): CodeRunResult { const fullMessage = `outer output exceeded ${this.maxBytes} bytes` - const messageBytes = Buffer.byteLength(JSON.stringify(fullMessage), 'utf8') - const retained = [...logs] - let retainedBytes = jsonBytes(retained) + // The fixed diagnostic is ASCII, so every character is one byte plus the quotes. + const messageBytes = fullMessage.length + 2 + const retained: string[] = [] + let retainedBytes = 2 const logBudget = this.maxBytes - messageBytes - while (retained.length > 0 && retainedBytes > logBudget) { - const removed = retained.pop() - /* v8 ignore next -- the while guard proves pop cannot return undefined. */ - if (removed === undefined) throw new Error('output ledger lost its final log entry') + for (const text of logs) { const separatorBytes = retained.length > 0 ? 1 : 0 - retainedBytes -= Buffer.byteLength(JSON.stringify(removed), 'utf8') + separatorBytes - const prefix = truncateJsonStringBytes(removed, logBudget - retainedBytes - separatorBytes) - if (prefix.length > 0) { - retained.push(prefix) - retainedBytes += Buffer.byteLength(JSON.stringify(prefix), 'utf8') + separatorBytes - break + const availableBytes = logBudget - retainedBytes - separatorBytes + const stringBytes = jsonStringBytesUpTo(text, availableBytes) + if (stringBytes !== undefined) { + retained.push(text) + retainedBytes += stringBytes + separatorBytes + continue } - } - if (logBudget < 2) { - retained.length = 0 - retainedBytes = 2 + const prefix = truncateJsonStringBytes(text, availableBytes) + if (prefix.length > 0) { + const prefixBytes = jsonStringBytesUpTo(prefix, availableBytes) + /* v8 ignore next -- truncateJsonStringBytes guarantees its returned prefix fits the same budget. */ + if (prefixBytes === undefined) throw new Error('output ledger produced an oversized log prefix') + retained.push(prefix) + retainedBytes += prefixBytes + separatorBytes + } + break } const availableMessageBytes = this.maxBytes - retainedBytes - // This fixed diagnostic is ASCII with no JSON escapes, so two bytes are - // the surrounding quotes and every retained character costs one byte. - const message = messageBytes <= availableMessageBytes - ? fullMessage - : fullMessage.slice(0, availableMessageBytes - 2) + const message = truncateJsonStringBytes(fullMessage, availableMessageBytes) return { logs: retained, error: { kind: 'output-limit', message } } } } @@ -410,12 +405,9 @@ export class WorkerCodeRuntime extends CodeRuntime { reply({ type: 'reply', id: message.id, ok: false, message: `unknown binding ${JSON.stringify(`${message.global}.${message.name}`)}` }) return } - let args: CodeJsonValue | undefined - try { - args = snapshotJsonValue(message.args) as CodeJsonValue | undefined - } catch { - args = undefined - } + // Structured clone has already removed accessors and proxies, so the + // host can repeat the lossless snapshot without a reflective throw. + const args = snapshotJsonValue(message.args) as CodeJsonValue | undefined if (args === undefined) { reply({ type: 'reply', id: message.id, ok: false, message: 'binding arguments must be lossless JSON' }) return diff --git a/packages/code-runtime/code-runtime-worker/src/output-json.ts b/packages/code-runtime/code-runtime-worker/src/output-json.ts index dd3c3529f5..2110a4ab27 100644 --- a/packages/code-runtime/code-runtime-worker/src/output-json.ts +++ b/packages/code-runtime/code-runtime-worker/src/output-json.ts @@ -1,5 +1,7 @@ /** JSON string-prefix accounting for the outer-output ledger. @module @deepseek-ai/dsh-code-runtime-worker/output-json */ +import type { CodeJsonValue } from '@deepseek-ai/dsh-code-runtime' + /** Control characters with a two-byte short JSON escape instead of `\u00XX`. */ const SHORT_ESCAPE_CODES = new Set([0x08, 0x09, 0x0a, 0x0c, 0x0d]) @@ -13,6 +15,69 @@ function serializedCharacterBytes(character: string): number { return Buffer.byteLength(character, 'utf8') } +/** + * Measure one JSON string without materializing its complete escaped form. + * @param text - the candidate string. + * @param maxBytes - largest serialized size the caller can admit. + * @returns Exact serialized bytes, or `undefined` as soon as the cap is crossed. + */ +export function jsonStringBytesUpTo(text: string, maxBytes: number): number | undefined { + if (maxBytes < 2) return undefined + let bytes = 2 + for (const character of text) { + bytes += serializedCharacterBytes(character) + if (bytes > maxBytes) return undefined + } + return bytes +} + +/** + * Measure one lossless JSON value without allocating its serialized form. + * @param value - already validated lossless JSON. + * @param maxBytes - largest serialized size the caller can admit. + * @returns Exact serialized bytes, or `undefined` as soon as the cap is crossed. + */ +export function jsonValueBytesUpTo(value: CodeJsonValue, maxBytes: number): number | undefined { + if (value === null) return maxBytes >= 4 ? 4 : undefined + if (typeof value === 'string') return jsonStringBytesUpTo(value, maxBytes) + if (typeof value === 'number') { + const bytes = Buffer.byteLength(String(value), 'utf8') + return bytes <= maxBytes ? bytes : undefined + } + if (typeof value === 'boolean') { + const bytes = value ? 4 : 5 + return bytes <= maxBytes ? bytes : undefined + } + + let bytes = 2 + if (bytes > maxBytes) return undefined + if (Array.isArray(value)) { + for (let index = 0; index < value.length; index++) { + if (index > 0 && ++bytes > maxBytes) return undefined + const item = value[index] + if (item === undefined) return undefined + const itemBytes = jsonValueBytesUpTo(item, maxBytes - bytes) + if (itemBytes === undefined) return undefined + bytes += itemBytes + } + return bytes + } + + let entries = 0 + for (const [key, item] of Object.entries(value)) { + if (entries > 0 && ++bytes > maxBytes) return undefined + const keyBytes = jsonStringBytesUpTo(key, maxBytes - bytes) + if (keyBytes === undefined) return undefined + bytes += keyBytes + 1 + if (bytes > maxBytes) return undefined + const itemBytes = jsonValueBytesUpTo(item, maxBytes - bytes) + if (itemBytes === undefined) return undefined + bytes += itemBytes + entries += 1 + } + return bytes +} + /** * Return the longest code-point-aligned prefix whose JSON string encoding, * including its surrounding quotes, fits `maxBytes`. @@ -23,7 +88,6 @@ function serializedCharacterBytes(character: string): number { */ export function truncateJsonStringBytes(text: string, maxBytes: number): string { if (maxBytes < 2) return '' - if (Buffer.byteLength(JSON.stringify(text), 'utf8') <= maxBytes) return text let bytes = 2 let end = 0 for (const character of text) { @@ -32,5 +96,5 @@ export function truncateJsonStringBytes(text: string, maxBytes: number): string bytes += cost end += character.length } - return text.slice(0, end) + return end === text.length ? text : text.slice(0, end) } diff --git a/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts index 8340d6e74c..36f6ebcfad 100644 --- a/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts @@ -1,10 +1,12 @@ -import { describe, expect, it } from 'vitest' -import { truncateJsonStringBytes } from '../src/output-json.ts' +import { describe, expect, it, vi } from 'vitest' +import { jsonStringBytesUpTo, jsonValueBytesUpTo, truncateJsonStringBytes } from '../src/output-json.ts' describe('truncateJsonStringBytes', () => { it('returns a fitting string whole and rejects budgets without JSON quotes', () => { expect(truncateJsonStringBytes('fits', 6)).toBe('fits') expect(truncateJsonStringBytes('x', 1)).toBe('') + expect(jsonStringBytesUpTo('fits', 6)).toBe(6) + expect(jsonStringBytesUpTo('fits', 5)).toBeUndefined() }) it('accounts every JSON escape and cuts only between complete code points', () => { @@ -15,4 +17,43 @@ describe('truncateJsonStringBytes', () => { expect(truncateJsonStringBytes(text, budget)).toBe(prefix) expect(Buffer.byteLength(JSON.stringify(truncateJsonStringBytes(text, budget)), 'utf8')).toBe(budget) }) + + it('bounds hostile strings without materializing their complete escaped form', () => { + const stringify = vi.spyOn(JSON, 'stringify').mockImplementation(() => { throw new Error('must not stringify') }) + try { + expect(jsonStringBytesUpTo('"'.repeat(10_000), 32)).toBeUndefined() + expect(truncateJsonStringBytes('"'.repeat(10_000), 32)).toBe('"'.repeat(15)) + } finally { + stringify.mockRestore() + } + }) +}) + +describe('jsonValueBytesUpTo', () => { + it('matches JSON serialization for every lossless value branch and stops at the cap', () => { + const value = { + empty: {}, + nil: null, + yes: true, + no: false, + number: 1.5, + text: '"\n😀', + array: [1, 'x'], + } + const bytes = Buffer.byteLength(JSON.stringify(value), 'utf8') + + expect(jsonValueBytesUpTo(value, bytes)).toBe(bytes) + expect(jsonValueBytesUpTo(value, bytes - 1)).toBeUndefined() + expect(jsonValueBytesUpTo({}, 1)).toBeUndefined() + expect(jsonValueBytesUpTo(null, 3)).toBeUndefined() + expect(jsonValueBytesUpTo(10, 1)).toBeUndefined() + expect(jsonValueBytesUpTo(false, 4)).toBeUndefined() + expect(jsonValueBytesUpTo(new Array<never>(1), 10)).toBeUndefined() + expect(jsonValueBytesUpTo([null], 5)).toBeUndefined() + expect(jsonValueBytesUpTo([0, 0], 3)).toBeUndefined() + expect(jsonValueBytesUpTo({ a: null, b: null }, 10)).toBeUndefined() + expect(jsonValueBytesUpTo({ long: null }, 2)).toBeUndefined() + expect(jsonValueBytesUpTo({ '': null }, 4)).toBeUndefined() + expect(jsonValueBytesUpTo({ a: null }, 9)).toBeUndefined() + }) }) diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index 8bcee8389b..4d4bb4c3c1 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -401,6 +401,22 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { expect(Buffer.byteLength(JSON.stringify(result.logs), 'utf8')).toBeLessThan(200) }) + it('bounds one oversized forged log while retaining its fitting escaped prefix', async () => { + const { runtime } = await setup({ maxOutputBytes: 96 }) + const result = await runtime.run({ + program: ` + const { parentPort } = await import('node:worker_threads'); + parentPort.postMessage({ type: 'log', text: '"'.repeat(1_000_000) }); + for (;;) {} + `, + bindings: [], + }) + expect(result.error).toEqual({ kind: 'output-limit', message: 'outer output exceeded 96 bytes' }) + expect(result.logs).toHaveLength(1) + expect(result.logs[0]).toMatch(/^"+$/) + expect(Buffer.byteLength(JSON.stringify(result.logs), 'utf8') + Buffer.byteLength(JSON.stringify('outer output exceeded 96 bytes'), 'utf8')).toBeLessThanOrEqual(96) + }) + it('drops a malformed forged done carrying both value and error', async () => { const { runtime } = await setup() const result = await runtime.run({ From 71f5015c6108835545f941eb2bf630420855bb43 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:03:46 +0800 Subject: [PATCH 044/368] docs(code-mode): clarify result content ownership --- .../2026-07-20-code-mode-result-card-completeness.i18n.yaml | 4 ++-- .../bug-fix/2026-07-20-code-mode-result-card-completeness.md | 2 +- .../2026-07-20-code-mode-result-card-completeness.zh.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml index c5ab1722dd..267a75bd5e 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml @@ -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 -2026-07-20-code-mode-result-card-completeness.md: 1fbdbdd311f359cbe2ab505210768b2136d56067 -2026-07-20-code-mode-result-card-completeness.zh.md: 619c742e6adb2dc846a9c278e78938dd8e0559b1 +2026-07-20-code-mode-result-card-completeness.md: 5fce1c51dbe029f7c109dfdac55444a51f0dd886 +2026-07-20-code-mode-result-card-completeness.zh.md: 624d541cea2e5b4402c880bfe00c586bda7df0ee diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md index 1fbdbdd311..5fce1c51db 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md @@ -12,7 +12,7 @@ Nested Code calls never owned cards, so producing metadata for the outer call so ## Decision -The `run_code` output renderer remains the single owner of model-facing outer content. It renders captured logs followed by the return value, the explicit no-output marker, or the failure content produced by the canonical tool pipeline. Post-execute policy and spill may replace that content before it is persisted. +The canonical tool registry pipeline owns the final model-facing outer content. On success, the `run_code` output renderer renders captured logs followed by the return value or the explicit no-output marker. Runtime failures and policy denials are normalized into error content by `ToolRegistry` without invoking that renderer. Post-execute policy and spill may replace content before persistence. `run_code.presentResult` now forwards the final `result.content` into one generic result card. It deliberately omits the title so the pending card retains the program text. The redundant logs-only `presentationMeta` projection is removed: `tool/result.content` is the durable, replayable, post-policy projection and the card's only result-content source. diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md index 619c742e6a..624d541cea 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md @@ -12,7 +12,7 @@ Status: implemented ## 决策 -`run_code` 输出渲染器继续作为面向模型的外层内容的唯一所有者。它先渲染已捕获的日志,然后渲染返回值、显式的无输出标记,或规范工具流水线生成的失败内容。Post-execute 策略与输出落盘机制可以在内容持久化之前替换它。 +规范的工具注册表流水线负责最终面向模型的外层内容。成功时,`run_code` 输出渲染器先渲染已捕获的日志,然后渲染返回值或显式的无输出标记。运行时失败和策略拒绝由 `ToolRegistry` 归一化为错误内容,过程中不会调用该渲染器。Post-execute 策略与输出落盘机制可以在持久化之前替换这些内容。 `run_code.presentResult` 会把最终的 `result.content` 转交给一张通用结果卡片。它有意省略标题,使待完成卡片保留程序文本。多余的仅含日志的 `presentationMeta` 投影被移除:`tool/result.content` 是持久、可回放且经过 post-policy 处理的投影,也是卡片中结果内容的唯一来源。 From 384cc8c15742e157793179f48dc0db1ca4121e5e Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:11:41 +0800 Subject: [PATCH 045/368] fix(schema): harden realm-safe JSON validation --- packages/cordis/tool-cordis/src/guard.ts | 3 +++ .../cordis/tool-cordis/tests/mount.spec.ts | 2 ++ packages/core/session/src/json.ts | 20 ++++++++++++++++--- packages/core/session/tests/json.spec.ts | 18 +++++++++++++++++ packages/core/tools/src/json-schema.ts | 2 +- packages/core/tools/tests/json-schema.spec.ts | 5 +++++ 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/cordis/tool-cordis/src/guard.ts b/packages/cordis/tool-cordis/src/guard.ts index 8ef931c5e5..e8eb19e524 100644 --- a/packages/cordis/tool-cordis/src/guard.ts +++ b/packages/cordis/tool-cordis/src/guard.ts @@ -55,6 +55,9 @@ function cloneJson(value: unknown, path: string, seen = new Set<object>()): unkn return output } if (!isPlainRecord(value)) throw new Error(`harness.defineTool ${path} must be lossless JSON data`) + if (Reflect.ownKeys(value).some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) { + throw new Error(`harness.defineTool ${path} must be lossless JSON data`) + } const output: Record<string, unknown> = {} for (const [key, entry] of Object.entries(value)) { Object.defineProperty(output, key, { diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 607f8b6192..64301f2172 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -345,6 +345,8 @@ describe('cordis_mount', () => { ['parameters: { value: { type: \'json\', default: Array(2) } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: Object.assign([1], { extra: true }) } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: (() => { const v = Array(1); v.extra = true; return v })() } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: Object.defineProperty({}, \'hidden\', { value: true }) } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: { [Symbol(\'hidden\')]: true } } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: new (class DefaultValue { constructor() { this.ok = true } })() } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: new Date(0) } }', 'parameters.value.default must be lossless JSON data'], ])('rejects a malformed ParameterSchemaSpec (%s) with a teaching error', async (parameters, message) => { diff --git a/packages/core/session/src/json.ts b/packages/core/session/src/json.ts index e2c681b100..eb277d299b 100644 --- a/packages/core/session/src/json.ts +++ b/packages/core/session/src/json.ts @@ -15,7 +15,11 @@ export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: /** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */ function hasPlainArrayPrototype(value: unknown[]): boolean { const prototype: unknown = Object.getPrototypeOf(value) - return Array.isArray(prototype) && Object.getPrototypeOf(Object.getPrototypeOf(prototype)) === null + if (!Array.isArray(prototype)) return false + const objectPrototype: unknown = Object.getPrototypeOf(prototype) + return objectPrototype !== null + && !Array.isArray(objectPrototype) + && Object.getPrototypeOf(objectPrototype) === null } /** Whether an object is a plain or null-prototype record from any JavaScript realm. */ @@ -24,6 +28,13 @@ function hasPlainObjectPrototype(value: object): boolean { return prototype === null || Object.getPrototypeOf(prototype) === null } +/** Return every JSON-visible object key, or reject own data JSON would discard. */ +function enumerableStringKeys(value: object): string[] | undefined { + const keys = Reflect.ownKeys(value) + if (keys.some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) return undefined + return keys as string[] +} + /** * Validate and detach lossless JSON in one read per property, so a stateful * getter cannot change between validation and copying. Accepts ordinary arrays, @@ -75,8 +86,10 @@ export function snapshotJsonValue<T>(value: T): T | undefined { } if (!hasPlainObjectPrototype(current)) return undefined + const keys = enumerableStringKeys(current) + if (keys === undefined) return undefined const snapshot: { [key: string]: JsonValue } = {} - for (const key of Object.keys(current)) { + for (const key of keys) { const item = visit((current as Record<string, unknown>)[key]) if (item === undefined) return undefined // Define the key as data so a JSON field literally named "__proto__" @@ -139,7 +152,8 @@ export function isJsonValue(value: unknown, seen: Set<object> = new Set()): bool } // Plain object only (reject Map/Set/Date/class instances). if (!hasPlainObjectPrototype(value)) return false - return Object.values(value).every(v => isJsonValue(v, seen)) + const keys = enumerableStringKeys(value) + return keys !== undefined && keys.every(key => isJsonValue((value as Record<string, unknown>)[key], seen)) } finally { seen.delete(value) } diff --git a/packages/core/session/tests/json.spec.ts b/packages/core/session/tests/json.spec.ts index 1d00d70787..06fd37b9d2 100644 --- a/packages/core/session/tests/json.spec.ts +++ b/packages/core/session/tests/json.spec.ts @@ -92,6 +92,12 @@ describe('snapshotJsonValue', () => { Object.defineProperty(decorated, 'extra', { value: true }) const symbolDecorated = [1] Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) + const hiddenObject = Object.defineProperty({}, 'hidden', { value: true }) + const symbolObject = { [Symbol('extra')]: true } + const forgedPrototype: unknown[] = [] + Object.setPrototypeOf(forgedPrototype, null) + const forgedArray = [1] + Object.setPrototypeOf(forgedArray, forgedPrototype) const cyclic: Record<string, unknown> = {} cyclic.self = cyclic const foreignExotics = runInNewContext(`(() => { @@ -109,6 +115,9 @@ describe('snapshotJsonValue', () => { expect(snapshotJsonValue(compensatedSparse)).toBeUndefined() expect(snapshotJsonValue(decorated)).toBeUndefined() expect(snapshotJsonValue(symbolDecorated)).toBeUndefined() + expect(snapshotJsonValue(hiddenObject)).toBeUndefined() + expect(snapshotJsonValue(symbolObject)).toBeUndefined() + expect(snapshotJsonValue(forgedArray)).toBeUndefined() expect(snapshotJsonValue(cyclic)).toBeUndefined() expect(snapshotJsonValue([undefined])).toBeUndefined() expect(snapshotJsonValue({ value: undefined })).toBeUndefined() @@ -177,6 +186,12 @@ describe('isJsonValue', () => { const decorated = Object.assign([1], { extra: true }) const symbolDecorated = [1] Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) + const hiddenObject = Object.defineProperty({}, 'hidden', { value: true }) + const symbolObject = { [Symbol('extra')]: true } + const forgedPrototype: unknown[] = [] + Object.setPrototypeOf(forgedPrototype, null) + const forgedArray = [1] + Object.setPrototypeOf(forgedArray, forgedPrototype) const cyclic: Record<string, unknown> = {} cyclic.self = cyclic @@ -184,6 +199,9 @@ describe('isJsonValue', () => { expect(isJsonValue(compensatedSparse)).toBe(false) expect(isJsonValue(decorated)).toBe(false) expect(isJsonValue(symbolDecorated)).toBe(false) + expect(isJsonValue(hiddenObject)).toBe(false) + expect(isJsonValue(symbolObject)).toBe(false) + expect(isJsonValue(forgedArray)).toBe(false) expect(isJsonValue(new ExoticArray(1))).toBe(false) expect(isJsonValue([undefined])).toBe(false) expect(isJsonValue({ value: undefined })).toBe(false) diff --git a/packages/core/tools/src/json-schema.ts b/packages/core/tools/src/json-schema.ts index a60b166b78..d849572789 100644 --- a/packages/core/tools/src/json-schema.ts +++ b/packages/core/tools/src/json-schema.ts @@ -351,7 +351,7 @@ function checkValueUnchecked(node: JsonSchemaNode, value: unknown, path: string) return safelyIsJsonValue(value) ? [] : [`"${diagnosticPath(path)}" must be a lossless JSON object`] } case 'array': { - if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) return [`"${diagnosticPath(path)}" must be an array`] + if (!Array.isArray(value)) return [`"${diagnosticPath(path)}" must be an array`] const items = node.items const violations = items === undefined ? [] diff --git a/packages/core/tools/tests/json-schema.spec.ts b/packages/core/tools/tests/json-schema.spec.ts index fb03a75ae2..8be1bbd35d 100644 --- a/packages/core/tools/tests/json-schema.spec.ts +++ b/packages/core/tools/tests/json-schema.spec.ts @@ -186,6 +186,10 @@ describe('the enforced raw JSON Schema subset', () => { }) expect(violationsOf({ examples: explosive })) .toEqual(['schema.examples annotation must be lossless JSON data']) + expect(violationsOf({ default: Object.defineProperty({}, 'hidden', { value: true }) })) + .toEqual(['schema.default annotation must be lossless JSON data']) + expect(violationsOf({ default: { [Symbol('hidden')]: true } })) + .toEqual(['schema.default annotation must be lossless JSON data']) }) it('accepts lossless annotation containers from another JavaScript realm', () => { @@ -298,6 +302,7 @@ describe('validateJsonSchemaValue', () => { it('validates dense arrays per index and rejects lossy arrays', () => { const schema = asserted({ type: 'array', items: { type: 'integer' } }) expect(validateJsonSchemaValue(schema, [1, 2])).toEqual([]) + expect(validateJsonSchemaValue(schema, runInNewContext('[1, 2]'))).toEqual([]) expect(validateJsonSchemaValue(schema, [1, 1.5])).toEqual(['"value[1]" must be an integer']) expect(validateJsonSchemaValue(schema, 'x')).toEqual(['"value" must be an array']) const sparse: number[] = [] From 8fd1201cfaa15b8215f4d62b3dc664e616a504f0 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:29:55 +0800 Subject: [PATCH 046/368] fix(code-runtime): align worker JSON snapshots --- .../code-runtime-worker/src/worker-json.ts | 39 ++++++++++++++++--- .../tests/worker-json.spec.ts | 33 ++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/packages/code-runtime/code-runtime-worker/src/worker-json.ts b/packages/code-runtime/code-runtime-worker/src/worker-json.ts index 9151d07e7e..d49c26d7d1 100644 --- a/packages/code-runtime/code-runtime-worker/src/worker-json.ts +++ b/packages/code-runtime/code-runtime-worker/src/worker-json.ts @@ -2,6 +2,31 @@ import type { CodeJsonValue } from '@deepseek-ai/dsh-code-runtime' +/* jscpd:ignore-start -- the source worker mirrors session JSON helpers without workspace runtime imports */ +/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */ +function hasPlainArrayPrototype(value: unknown[]): boolean { + const prototype: unknown = Object.getPrototypeOf(value) + if (!Array.isArray(prototype)) return false + const objectPrototype: unknown = Object.getPrototypeOf(prototype) + return objectPrototype !== null + && !Array.isArray(objectPrototype) + && Object.getPrototypeOf(objectPrototype) === null +} + +/** Whether an object is a plain or null-prototype record from any JavaScript realm. */ +function hasPlainObjectPrototype(value: object): boolean { + const prototype: unknown = Object.getPrototypeOf(value) + return prototype === null || Object.getPrototypeOf(prototype) === null +} + +/** Return every JSON-visible object key, or reject own data JSON would discard. */ +function enumerableStringKeys(value: object): string[] | undefined { + const keys = Reflect.ownKeys(value) + if (keys.some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) return undefined + return keys as string[] +} +/* jscpd:ignore-end */ + /** * Validate and detach one worker-boundary value without loading another * workspace package at runtime. This mirrors the session-owned canonical @@ -32,11 +57,12 @@ export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined if (typeof candidate !== 'object') return undefined if (Array.isArray(candidate)) { - if (Object.getPrototypeOf(candidate) !== Array.prototype) return undefined - if (Reflect.ownKeys(candidate).length !== candidate.length + 1) return undefined + if (!hasPlainArrayPrototype(candidate)) return undefined + const length = candidate.length + if (Reflect.ownKeys(candidate).length !== length + 1) return undefined return within(candidate, () => { const result: CodeJsonValue[] = [] - for (let index = 0; index < candidate.length; index++) { + for (let index = 0; index < length; index++) { if (!Object.hasOwn(candidate, index)) return undefined const item = copy(candidate[index]) if (item === undefined) return undefined @@ -46,11 +72,12 @@ export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined }) } - const prototype = Object.getPrototypeOf(candidate) as unknown - if (prototype !== Object.prototype && prototype !== null) return undefined + if (!hasPlainObjectPrototype(candidate)) return undefined + const keys = enumerableStringKeys(candidate) + if (keys === undefined) return undefined return within(candidate, () => { const result: Record<string, CodeJsonValue> = {} - for (const key of Object.keys(candidate)) { + for (const key of keys) { const item = copy((candidate as Record<string, unknown>)[key]) if (item === undefined) return undefined Object.defineProperty(result, key, { diff --git a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts index b574e80aff..029b5789ac 100644 --- a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts @@ -1,3 +1,4 @@ +import { runInNewContext } from 'node:vm' import { describe, expect, it } from 'vitest' import { snapshotJsonValue } from '@deepseek-ai/dsh-session' import { snapshotCodeJsonValue } from '../src/worker-json.ts' @@ -24,6 +25,16 @@ describe('snapshotCodeJsonValue', () => { expect(snapshot.alias).not.toBe(shared) }) + it('accepts intrinsic plain containers from another JavaScript realm', () => { + const foreign = runInNewContext('({ object: { nested: [1] }, array: [2, { ok: true }] })') as { + object: unknown + array: unknown + } + + expect(snapshotCodeJsonValue(foreign.object)).toEqual({ nested: [1] }) + expect(snapshotCodeJsonValue(foreign.array)).toEqual([2, { ok: true }]) + }) + it('reads each accepted slot once and preserves a literal __proto__ key', () => { let objectReads = 0 let arrayReads = 0 @@ -66,6 +77,12 @@ describe('snapshotCodeJsonValue', () => { Object.defineProperty(compensatedSparse, 'extra', { value: true }) const symbolDecorated = [1] Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) + const hiddenObject = Object.defineProperty({}, 'hidden', { value: true }) + const symbolObject = { [Symbol('extra')]: true } + const forgedPrototype: unknown[] = [] + Object.setPrototypeOf(forgedPrototype, null) + const forgedArray = [1] + Object.setPrototypeOf(forgedArray, forgedPrototype) for (const value of [ new ExoticObject(), @@ -75,6 +92,9 @@ describe('snapshotCodeJsonValue', () => { decorated, compensatedSparse, symbolDecorated, + hiddenObject, + symbolObject, + forgedArray, cyclic, [undefined], { value: undefined }, @@ -83,6 +103,19 @@ describe('snapshotCodeJsonValue', () => { } }) + it('rejects an array whose getter mutates the validated length', () => { + const array = [0, 2] + Object.defineProperty(array, 0, { + enumerable: true, + get: () => { + array.length = 1 + return 1 + }, + }) + + expect(snapshotCodeJsonValue(array)).toBeUndefined() + }) + it('propagates a throwing getter and releases its recursion guard', () => { const failure = new Error('getter failed') const source = Object.defineProperty({}, 'value', { From 87f4e0b28e621de4c84bef11b895070b3c73efec Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:41:37 +0800 Subject: [PATCH 047/368] fix(session): identify intrinsic JSON prototypes --- packages/core/session/src/json.ts | 25 +++++++++++++++++++----- packages/core/session/tests/json.spec.ts | 6 ++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/core/session/src/json.ts b/packages/core/session/src/json.ts index eb277d299b..f7609a1f46 100644 --- a/packages/core/session/src/json.ts +++ b/packages/core/session/src/json.ts @@ -12,20 +12,35 @@ */ export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } +/** Whether a realm-owned intrinsic prototype names and points back to its constructor. */ +function hasIntrinsicConstructor(prototype: object, name: 'Array' | 'Object'): boolean { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor') + const constructor: unknown = descriptor?.value + return typeof constructor === 'function' + && constructor.name === name + && constructor.prototype === prototype +} + +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value: object): boolean { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, 'Object') +} + /** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */ function hasPlainArrayPrototype(value: unknown[]): boolean { const prototype: unknown = Object.getPrototypeOf(value) - if (!Array.isArray(prototype)) return false + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) return false const objectPrototype: unknown = Object.getPrototypeOf(prototype) - return objectPrototype !== null - && !Array.isArray(objectPrototype) - && Object.getPrototypeOf(objectPrototype) === null + return typeof objectPrototype === 'object' + && objectPrototype !== null + && isIntrinsicObjectPrototype(objectPrototype) } /** Whether an object is a plain or null-prototype record from any JavaScript realm. */ function hasPlainObjectPrototype(value: object): boolean { const prototype: unknown = Object.getPrototypeOf(value) - return prototype === null || Object.getPrototypeOf(prototype) === null + return prototype === null + || typeof prototype === 'object' && isIntrinsicObjectPrototype(prototype) } /** Return every JSON-visible object key, or reject own data JSON would discard. */ diff --git a/packages/core/session/tests/json.spec.ts b/packages/core/session/tests/json.spec.ts index 06fd37b9d2..90b3ec6928 100644 --- a/packages/core/session/tests/json.spec.ts +++ b/packages/core/session/tests/json.spec.ts @@ -94,6 +94,8 @@ describe('snapshotJsonValue', () => { Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) const hiddenObject = Object.defineProperty({}, 'hidden', { value: true }) const symbolObject = { [Symbol('extra')]: true } + const customPrototype = Object.create(null) as Record<string, unknown> + const customPrototypeObject = Object.assign(Object.create(customPrototype) as Record<string, unknown>, { value: 1 }) const forgedPrototype: unknown[] = [] Object.setPrototypeOf(forgedPrototype, null) const forgedArray = [1] @@ -117,6 +119,7 @@ describe('snapshotJsonValue', () => { expect(snapshotJsonValue(symbolDecorated)).toBeUndefined() expect(snapshotJsonValue(hiddenObject)).toBeUndefined() expect(snapshotJsonValue(symbolObject)).toBeUndefined() + expect(snapshotJsonValue(customPrototypeObject)).toBeUndefined() expect(snapshotJsonValue(forgedArray)).toBeUndefined() expect(snapshotJsonValue(cyclic)).toBeUndefined() expect(snapshotJsonValue([undefined])).toBeUndefined() @@ -188,6 +191,8 @@ describe('isJsonValue', () => { Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) const hiddenObject = Object.defineProperty({}, 'hidden', { value: true }) const symbolObject = { [Symbol('extra')]: true } + const customPrototype = Object.create(null) as Record<string, unknown> + const customPrototypeObject = Object.assign(Object.create(customPrototype) as Record<string, unknown>, { value: 1 }) const forgedPrototype: unknown[] = [] Object.setPrototypeOf(forgedPrototype, null) const forgedArray = [1] @@ -201,6 +206,7 @@ describe('isJsonValue', () => { expect(isJsonValue(symbolDecorated)).toBe(false) expect(isJsonValue(hiddenObject)).toBe(false) expect(isJsonValue(symbolObject)).toBe(false) + expect(isJsonValue(customPrototypeObject)).toBe(false) expect(isJsonValue(forgedArray)).toBe(false) expect(isJsonValue(new ExoticArray(1))).toBe(false) expect(isJsonValue([undefined])).toBe(false) From fc9740394642a9df393982a78d35375adce90cde Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:54:12 +0800 Subject: [PATCH 048/368] fix(code-runtime): contain deep output accounting --- .../code-runtime-worker/src/output-json.ts | 80 ++++++++++++------- .../code-runtime-worker/src/worker-json.ts | 25 ++++-- .../tests/output-json.spec.ts | 12 +++ .../code-runtime-worker/tests/runtime.spec.ts | 23 ++++++ .../tests/worker-json.spec.ts | 3 + 5 files changed, 107 insertions(+), 36 deletions(-) diff --git a/packages/code-runtime/code-runtime-worker/src/output-json.ts b/packages/code-runtime/code-runtime-worker/src/output-json.ts index 2110a4ab27..de7ed6f301 100644 --- a/packages/code-runtime/code-runtime-worker/src/output-json.ts +++ b/packages/code-runtime/code-runtime-worker/src/output-json.ts @@ -38,42 +38,60 @@ export function jsonStringBytesUpTo(text: string, maxBytes: number): number | un * @returns Exact serialized bytes, or `undefined` as soon as the cap is crossed. */ export function jsonValueBytesUpTo(value: CodeJsonValue, maxBytes: number): number | undefined { - if (value === null) return maxBytes >= 4 ? 4 : undefined - if (typeof value === 'string') return jsonStringBytesUpTo(value, maxBytes) - if (typeof value === 'number') { - const bytes = Buffer.byteLength(String(value), 'utf8') - return bytes <= maxBytes ? bytes : undefined - } - if (typeof value === 'boolean') { - const bytes = value ? 4 : 5 - return bytes <= maxBytes ? bytes : undefined - } + type Task = + | { kind: 'value'; value: CodeJsonValue } + | { kind: 'array'; value: CodeJsonValue[]; index: number } + | { kind: 'object'; value: Record<string, CodeJsonValue>; keys: string[]; index: number } - let bytes = 2 - if (bytes > maxBytes) return undefined - if (Array.isArray(value)) { - for (let index = 0; index < value.length; index++) { - if (index > 0 && ++bytes > maxBytes) return undefined - const item = value[index] - if (item === undefined) return undefined - const itemBytes = jsonValueBytesUpTo(item, maxBytes - bytes) - if (itemBytes === undefined) return undefined - bytes += itemBytes + let bytes = 0 + const add = (cost: number): boolean => { + bytes += cost + return bytes <= maxBytes + } + const tasks: Task[] = [{ kind: 'value', value }] + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'value') { + const current = task.value + if (current === null) { + if (!add(4)) return undefined + } else if (typeof current === 'string') { + const stringBytes = jsonStringBytesUpTo(current, maxBytes - bytes) + if (stringBytes === undefined) return undefined + bytes += stringBytes + } else if (typeof current === 'number') { + if (!add(Buffer.byteLength(String(current), 'utf8'))) return undefined + } else if (typeof current === 'boolean') { + if (!add(current ? 4 : 5)) return undefined + } else if (Array.isArray(current)) { + if (!add(2)) return undefined + if (current.length > 0) tasks.push({ kind: 'array', value: current, index: 0 }) + } else { + if (!add(2)) return undefined + const keys = Object.keys(current) + if (keys.length > 0) tasks.push({ kind: 'object', value: current, keys, index: 0 }) + } + continue } - return bytes - } - let entries = 0 - for (const [key, item] of Object.entries(value)) { - if (entries > 0 && ++bytes > maxBytes) return undefined + if (task.index > 0 && !add(1)) return undefined + if (task.kind === 'array') { + const item = task.value[task.index] + if (item === undefined) return undefined + if (task.index + 1 < task.value.length) tasks.push({ ...task, index: task.index + 1 }) + tasks.push({ kind: 'value', value: item }) + continue + } + + const key = task.keys[task.index] + /* v8 ignore next -- an object frame is created and advanced only for an existing Object.keys entry. */ + if (key === undefined) return undefined const keyBytes = jsonStringBytesUpTo(key, maxBytes - bytes) if (keyBytes === undefined) return undefined - bytes += keyBytes + 1 - if (bytes > maxBytes) return undefined - const itemBytes = jsonValueBytesUpTo(item, maxBytes - bytes) - if (itemBytes === undefined) return undefined - bytes += itemBytes - entries += 1 + if (!add(keyBytes + 1)) return undefined + const item = task.value[key] + if (item === undefined) return undefined + if (task.index + 1 < task.keys.length) tasks.push({ ...task, index: task.index + 1 }) + tasks.push({ kind: 'value', value: item }) } return bytes } diff --git a/packages/code-runtime/code-runtime-worker/src/worker-json.ts b/packages/code-runtime/code-runtime-worker/src/worker-json.ts index d49c26d7d1..fbc0cd7720 100644 --- a/packages/code-runtime/code-runtime-worker/src/worker-json.ts +++ b/packages/code-runtime/code-runtime-worker/src/worker-json.ts @@ -3,20 +3,35 @@ import type { CodeJsonValue } from '@deepseek-ai/dsh-code-runtime' /* jscpd:ignore-start -- the source worker mirrors session JSON helpers without workspace runtime imports */ +/** Whether a realm-owned intrinsic prototype names and points back to its constructor. */ +function hasIntrinsicConstructor(prototype: object, name: 'Array' | 'Object'): boolean { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor') + const constructor: unknown = descriptor?.value + return typeof constructor === 'function' + && constructor.name === name + && constructor.prototype === prototype +} + +/** Whether a candidate is one realm's intrinsic `Object.prototype`. */ +function isIntrinsicObjectPrototype(value: object): boolean { + return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, 'Object') +} + /** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */ function hasPlainArrayPrototype(value: unknown[]): boolean { const prototype: unknown = Object.getPrototypeOf(value) - if (!Array.isArray(prototype)) return false + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) return false const objectPrototype: unknown = Object.getPrototypeOf(prototype) - return objectPrototype !== null - && !Array.isArray(objectPrototype) - && Object.getPrototypeOf(objectPrototype) === null + return typeof objectPrototype === 'object' + && objectPrototype !== null + && isIntrinsicObjectPrototype(objectPrototype) } /** Whether an object is a plain or null-prototype record from any JavaScript realm. */ function hasPlainObjectPrototype(value: object): boolean { const prototype: unknown = Object.getPrototypeOf(value) - return prototype === null || Object.getPrototypeOf(prototype) === null + return prototype === null + || typeof prototype === 'object' && isIntrinsicObjectPrototype(prototype) } /** Return every JSON-visible object key, or reject own data JSON would discard. */ diff --git a/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts index 36f6ebcfad..dde3cba5fc 100644 --- a/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/output-json.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it, vi } from 'vitest' +import type { CodeJsonValue } from '@deepseek-ai/dsh-code-runtime' import { jsonStringBytesUpTo, jsonValueBytesUpTo, truncateJsonStringBytes } from '../src/output-json.ts' describe('truncateJsonStringBytes', () => { @@ -45,6 +46,8 @@ describe('jsonValueBytesUpTo', () => { expect(jsonValueBytesUpTo(value, bytes)).toBe(bytes) expect(jsonValueBytesUpTo(value, bytes - 1)).toBeUndefined() expect(jsonValueBytesUpTo({}, 1)).toBeUndefined() + expect(jsonValueBytesUpTo([], 1)).toBeUndefined() + expect(jsonValueBytesUpTo([], 2)).toBe(2) expect(jsonValueBytesUpTo(null, 3)).toBeUndefined() expect(jsonValueBytesUpTo(10, 1)).toBeUndefined() expect(jsonValueBytesUpTo(false, 4)).toBeUndefined() @@ -55,5 +58,14 @@ describe('jsonValueBytesUpTo', () => { expect(jsonValueBytesUpTo({ long: null }, 2)).toBeUndefined() expect(jsonValueBytesUpTo({ '': null }, 4)).toBeUndefined() expect(jsonValueBytesUpTo({ a: null }, 9)).toBeUndefined() + expect(jsonValueBytesUpTo({ a: undefined } as unknown as CodeJsonValue, 100)).toBeUndefined() + }) + + it('meters deeply nested arrays without recursive stack growth', () => { + let value: CodeJsonValue = null + for (let depth = 0; depth < 5_000; depth++) value = [value] + + expect(jsonValueBytesUpTo(value, 10_004)).toBe(10_004) + expect(jsonValueBytesUpTo(value, 10_003)).toBeUndefined() }) }) diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index 4d4bb4c3c1..c38ee7f492 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -430,6 +430,29 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { expect(result).toEqual({ logs: [], error: { kind: 'exception', message: 'fake failure' } }) }) + it('contains a deeply nested forged completion without overflowing the host meter', async () => { + const { runtime } = await setup() + const result = await runtime.run({ + program: ` + const { parentPort } = await import('node:worker_threads'); + let value = null; + for (let depth = 0; depth < 3_000; depth++) value = [value]; + parentPort.postMessage({ type: 'done', value }); + `, + bindings: [], + }) + expect(result.error).toBeUndefined() + let value = result.value + let depth = 0 + while (Array.isArray(value)) { + expect(value).toHaveLength(1) + value = value[0] + depth += 1 + } + expect(depth).toBe(3_000) + expect(value).toBeNull() + }) + it('turns forged over-limit error text into output-limit at the host', async () => { const { runtime } = await setup({ maxOutputBytes: 64 }) const result = await runtime.run({ diff --git a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts index 029b5789ac..3d67a67897 100644 --- a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts @@ -79,6 +79,8 @@ describe('snapshotCodeJsonValue', () => { Object.defineProperty(symbolDecorated, Symbol('extra'), { value: true }) const hiddenObject = Object.defineProperty({}, 'hidden', { value: true }) const symbolObject = { [Symbol('extra')]: true } + const customPrototype = Object.create(null) as Record<string, unknown> + const customPrototypeObject = Object.assign(Object.create(customPrototype) as Record<string, unknown>, { value: 1 }) const forgedPrototype: unknown[] = [] Object.setPrototypeOf(forgedPrototype, null) const forgedArray = [1] @@ -94,6 +96,7 @@ describe('snapshotCodeJsonValue', () => { symbolDecorated, hiddenObject, symbolObject, + customPrototypeObject, forgedArray, cyclic, [undefined], From 3ed74d54761e95a09da64b9ed997ab1cee6ee3a0 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 21 Jul 2026 23:44:08 +0800 Subject: [PATCH 049/368] docs: refresh merged contract references --- docs/architecture.md | 6 +++--- docs/config-catalog.md | 2 +- docs/cordis-catalog/services.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index e05721a9a8..f32c35ca93 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -113,13 +113,13 @@ forever: Each step assembles ordered prompt sections, tool schemas, and `{{name}}` variables; unknown or valueless references fail the turn. `dsh-system-prompt` owns the harness identity and default persona, which an agent scope may shadow. The loop supplies `model` and `cwd` ([prompt ownership](../.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)). -Canonical JSON stays execution-local; post-policy replaces value or presentation, or blocks; the loop persists projections ([contract](../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md)). Tool-time context—including async `agent.inject()` notices and post-tool `additionalContexts`—settles after results. Steering drains; before signal closure, `agent/post-step` observes durable output, results, context, and steering. Leftovers queue. Terminal `agent/turn-stop` runs after continuation and steering folding, remains authoritative through close/flush, and discards later steering while preserving queued prompts. +Canonical JSON is execution-local; post-policy replaces value or presentation, or blocks; the loop persists projections ([contract](../.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md)). Tool context—including async `agent.inject()` and post-tool `additionalContexts`—settles after results. Before signal closure, `agent/post-step` observes durable results, context, and drained steering. Leftovers queue. Terminal `agent/turn-stop` follows continuation and steering folding, remains authoritative through close/flush, and discards later steering while preserving queued prompts. Pruning precedes summaries; overflow retries require durable progress. Bounded transient retries compose on `agent/request-error`; cancellation wins ([compaction](../.agents/notes/implemented/architecture/2026-07-10-after-call-compaction-pressure-and-overflow-recovery.md), [retry](../.agents/notes/implemented/architecture/2026-06-21-bounded-llm-request-recovery.md)). ### Failure Boundaries -The turn contains failures. Adapter failures close the step before `agent/request-error`, which receives exact `Error`, `LlmFailure`, and history. Retry opens another step; success clears history; exhaustion stores failure on `turn/end`. Failed chunks commit no message/tool. +Adapter failures close the step before `agent/request-error`, which receives exact `Error`, `LlmFailure`, and history. Retry opens a step; success clears history; exhaustion stores failure on `turn/end`. Failed chunks commit no message/tool. Other failures use `agent/error`. Cancellation and disposal beat recovery; undispatched model tool calls get synthetic `tool/call`/`ABORTED_BEFORE_DISPATCH` pairs. One turn signal retires before `turn/end`. Effective `cancel()` emits its typed `user | parent` cause before clearing queues and aborting; observers cannot veto, idle calls emit nothing, and durability records only `aborted`. Disposal awaits quiescence before unregistering ([decision](../.agents/notes/implemented/architecture/2026-07-16-explicit-turn-cancellation.md)). @@ -131,7 +131,7 @@ Every session event is turn-enclosed. Reloading preserves an interrupted tail an ### Agent Scope -Every live agent owns a scoped `agent.ctx`. Its registrations shadow globals, receive only that agent's dispatches, and unwind with it; async effects such as background-task cleanup are awaited. `CreateAgentOptions.setup(agentCtx)` composes the scope before publication. Typed resolvers derive carrier checks from merged `Events` signatures and `scopeTarget` ([semantic gates](../.agents/notes/implemented/process/2026-07-14-typescript-program-backed-semantic-gates.md)). See [agent scope](../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md) and [subagent composition controls](../.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md). `AgentLoop` runs drivers inside `ctx.agents.withInitiator()`; private orchestration derives `agent.session`; turn, step, signal, cwd, and authority stay explicit ([decision](../.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md)). +Each agent owns scoped `agent.ctx`; registrations shadow globals, receive its dispatches, and unwind with it while awaiting async cleanup. `CreateAgentOptions.setup(agentCtx)` composes before publication. Typed resolvers derive carrier checks from merged `Events` signatures and `scopeTarget` ([semantic gates](../.agents/notes/implemented/process/2026-07-14-typescript-program-backed-semantic-gates.md)). See [agent scope](../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md) and [subagent composition controls](../.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md). `AgentLoop` runs drivers inside `ctx.agents.withInitiator()`; private orchestration derives `agent.session`; turn, step, signal, cwd, and authority stay explicit ([decision](../.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md)). ## State diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 43a7f8da95..7e11e1dcdd 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -1142,7 +1142,7 @@ export interface Config { } ``` -Source: [`packages/bash/tool-bash/src/index.ts:40`](../packages/bash/tool-bash/src/index.ts) +Source: [`packages/bash/tool-bash/src/index.ts:41`](../packages/bash/tool-bash/src/index.ts) ## `@deepseek-ai/dsh-tool-cordis` diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 5121770083..07bfb362d8 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -317,7 +317,7 @@ list(): BashEnvVariableInfo[] Types: [DshEnvironment](../core-data-structures/bash.md) · [ToolExecution](../core-data-structures/tools.md) -Source: [`packages/bash/tool-bash/src/index.ts:103`](../../packages/bash/tool-bash/src/index.ts) +Source: [`packages/bash/tool-bash/src/index.ts:104`](../../packages/bash/tool-bash/src/index.ts) ## `ctx.codeRuntime` — `CodeRuntime` (abstract seam) From 0517d7487538331b9468ab0fe1ff6e5f655f48d7 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:03:23 +0800 Subject: [PATCH 050/368] test(persistence): use stored-prefix lookup --- .../session-persistence-jsonl/tests/zstd.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/session-persistence/session-persistence-jsonl/tests/zstd.spec.ts b/packages/session-persistence/session-persistence-jsonl/tests/zstd.spec.ts index 830e17ffc7..43ef0b62c2 100644 --- a/packages/session-persistence/session-persistence-jsonl/tests/zstd.spec.ts +++ b/packages/session-persistence/session-persistence-jsonl/tests/zstd.spec.ts @@ -460,7 +460,7 @@ describe('SessionPersistenceJsonl: encoding selection', () => { '', ].join('\n')) await expect(ctx.sessionPersistence.load(loadHeader.id)).rejects.toThrow(/uses \.jsonl/) - await expect((ctx.sessionPersistence as SessionPersistenceJsonl).loadLive(loadHeader.id, loadHeader.cwd)) + await expect((ctx.sessionPersistence as SessionPersistenceJsonl).loadStored(loadHeader.id)) .rejects.toThrow(/uses \.jsonl/) await expect(ctx.sessionPersistence.list()).rejects.toThrow(/uses \.jsonl/) }) From 63d48593cc2f6d3024289c8269412e0e4b9c7b44 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:55:59 +0800 Subject: [PATCH 051/368] fix(tools): preserve complete bounded presentations --- ...0-canonical-tool-output-contract.i18n.yaml | 4 +-- ...26-07-20-canonical-tool-output-contract.md | 2 +- ...07-20-canonical-tool-output-contract.zh.md | 2 +- packages/fs/tool-fs/src/read-render.ts | 20 ++++++------- packages/fs/tool-fs/tests/read-render.spec.ts | 2 ++ packages/fs/tool-fs/tests/tools.spec.ts | 3 ++ packages/spill/spill-policy/README.md | 2 +- packages/spill/spill-policy/src/index.ts | 11 +++---- .../spill-policy/tests/spill-policy.spec.ts | 29 +++++++++++++++++-- 9 files changed, 52 insertions(+), 23 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml index c4afb670c9..6b90e6fa26 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml @@ -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 -2026-07-20-canonical-tool-output-contract.md: feca70f8fed284f64c5a5560e3fddd3e2aa9a752 -2026-07-20-canonical-tool-output-contract.zh.md: 0fca743c1cc050236787ce25553684bd393ba861 +2026-07-20-canonical-tool-output-contract.md: 0cdce1111d976058eab939e0f7e51d6310071ec8 +2026-07-20-canonical-tool-output-contract.zh.md: e62842ddbb1ff753288beaaaa81f33e1edba2303 diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md index feca70f8fe..0cdce1111d 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md @@ -58,7 +58,7 @@ The first-party tools preserve their existing Native text while returning domain | `structured_output` | `{ recorded: true }` | | `run_code` | `{ logs: string[], result?: JsonValue }` | -Provider and executor acquisition limits remain real limits on the canonical value. Formatting-only limits belong in `render`; `glob` and `grep`, for example, keep every acquired item in `value` while their Native projection retains and best-effort spills the configured first page. Filesystem mutations derive replayable diff metadata from `args` and the canonical before/after value rather than returning UI state from the body. +Provider and executor acquisition limits remain real limits on the canonical value. Formatting-only limits belong in `render`; `glob` and `grep`, for example, keep every acquired item in `value` while their Native projection retains and best-effort spills the configured first page. Generic spill prepends and delegates its post-execute listener so an ordinary tool-owned asynchronous projection completes before generic byte bounding regardless of plugin load order. Filesystem mutations derive replayable diff metadata from `args` and the canonical before/after value rather than returning UI state from the body. MCP bridges preserve protocol blocks through `McpResult<{...}> = { content: JsonValue[]; structuredContent? }`. An advertised `outputSchema` is enforced when it belongs to the supported raw subset; unsupported schemas fall back to `JsonValue` rather than pretending to validate them. Native rendering still uses the existing MCP-to-`ContentBlock` projection, and MCP `isError` becomes a failed tool result. diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md index 0fca743c1c..e62842ddbb 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md @@ -58,7 +58,7 @@ type ToolExecutionResult = | `structured_output` | `{ recorded: true }` | | `run_code` | `{ logs: string[], result?: JsonValue }` | -提供方和执行器的采集上限仍会实际限制规范值。仅用于格式化的限制归 `render` 所有;例如,`glob` 和 `grep` 会在 `value` 中保留所有已采集项,而其 Native 投影仍只保留配置指定的第一页,并尽力将完整展示内容写入落盘文件。文件系统变更工具根据 `args` 和规范的变更前/后值推导可回放的 diff 元数据,不再由工具主体返回 UI 状态。 +提供方和执行器的采集上限仍会实际限制规范值。仅用于格式化的限制归 `render` 所有;例如,`glob` 和 `grep` 会在 `value` 中保留所有已采集项,而其 Native 投影仍只保留配置指定的第一页,并尽力将完整展示内容写入落盘文件。通用落盘机制会前置注册其 post-execute 监听器,并让该监听器先向后委托,因此无论插件加载顺序如何,普通工具自有的异步投影都会在通用字节数上限处理之前完成。文件系统变更工具根据 `args` 和规范的变更前/后值推导可回放的 diff 元数据,不再由工具主体返回 UI 状态。 MCP 桥接层通过 `McpResult<{...}> = { content: JsonValue[]; structuredContent? }` 保留协议内容块。当公布的 `outputSchema` 属于受支持的原始子集时,系统会强制校验;不受支持的 schema 则回退为 `JsonValue`,而不会假装已完成校验。Native 渲染仍使用现有的 MCP 到 `ContentBlock` 投影,MCP `isError` 则会变为失败的工具结果。 diff --git a/packages/fs/tool-fs/src/read-render.ts b/packages/fs/tool-fs/src/read-render.ts index 943ff98f61..7e581bb22c 100644 --- a/packages/fs/tool-fs/src/read-render.ts +++ b/packages/fs/tool-fs/src/read-render.ts @@ -37,9 +37,9 @@ export interface FileTextLine { export interface WindowResult { /** Returned lines, already numbered. */ lines: FileTextLine[] - /** Total line count in the file, unless `truncatedByBytes` stopped scanning early. */ + /** Exact total line count in the file. */ totalLines: number - /** Whether selected output hit the byte cap before EOF or the requested limit. */ + /** Whether selected output hit the byte cap. */ truncatedByBytes: boolean } @@ -49,9 +49,9 @@ export interface FileReadOutcome { offset: number /** Returned lines, already numbered. */ lines: FileTextLine[] - /** Total line count in the file, unless `truncatedByBytes` stopped scanning early. */ + /** Exact total line count in the file. */ totalLines: number - /** Whether selected output hit the byte cap before EOF or the requested limit. */ + /** Whether selected output hit the byte cap. */ truncatedByBytes?: true } @@ -60,11 +60,10 @@ interface WindowAccumulator { totalLines: number outputBytes: number truncatedByBytes: boolean - done: boolean } function newAccumulator(): WindowAccumulator { - return { lines: [], totalLines: 0, outputBytes: 0, truncatedByBytes: false, done: false } + return { lines: [], totalLines: 0, outputBytes: 0, truncatedByBytes: false } } function truncateLine(line: string, maxLineLength: number): string { @@ -77,13 +76,12 @@ function lineByteSize(line: string, currentLineCount: number): number { function consumeLine(acc: WindowAccumulator, rawLine: string, request: ReadWindow): void { acc.totalLines += 1 - if (acc.totalLines < request.offset || acc.lines.length >= request.limit) return + if (acc.truncatedByBytes || acc.totalLines < request.offset || acc.lines.length >= request.limit) return const text = truncateLine(rawLine, request.maxLineLength) const bytes = lineByteSize(text, acc.lines.length) if (acc.outputBytes + bytes > request.maxBytes) { acc.truncatedByBytes = true - acc.done = true return } acc.outputBytes += bytes @@ -102,8 +100,9 @@ function finish(acc: WindowAccumulator, request: ReadWindow, displayPath: string } /** - * Build one window from streamed or whole-file chunks, enforcing line and byte caps and throwing - * `FS_NOT_FOUND` when the requested offset is past EOF. + * Build one window from streamed or whole-file chunks, enforcing line and byte caps while still + * scanning to an exact total line count, and throwing `FS_NOT_FOUND` when the requested offset is + * past EOF. * @param chunks - decoded text chunks in file order; chunk boundaries carry no meaning. * @param request - the resolved window; the caller has already applied its defaults and caps. * @param displayPath - the caller-facing path used in the offset-out-of-range error. @@ -137,7 +136,6 @@ export async function buildWindow( appendToLineBuffer(chunk.slice(startPos, newlinePos)) flushLine() startPos = newlinePos + 1 - if (acc.done) return finish(acc, request, displayPath) } appendToLineBuffer(chunk.slice(startPos)) } diff --git a/packages/fs/tool-fs/tests/read-render.spec.ts b/packages/fs/tool-fs/tests/read-render.spec.ts index ab4d2a618b..c2afaf002e 100644 --- a/packages/fs/tool-fs/tests/read-render.spec.ts +++ b/packages/fs/tool-fs/tests/read-render.spec.ts @@ -86,6 +86,7 @@ describe('buildWindow', () => { it('caps output at a custom maxBytes', async () => { const result = await buildWindow(whole('aaaa\nbbbb\ncccc'), { offset: 1, limit: 10, maxLineLength: 2000, maxBytes: 9 }, 'f') expect(result.lines.map(l => l.text)).toEqual(['aaaa', 'bbbb']) + expect(result.totalLines).toBe(3) expect(result.truncatedByBytes).toBe(true) }) }) @@ -105,6 +106,7 @@ describe('buildWindow', () => { it('caps output bytes mid-stream', async () => { const big = Array.from({ length: 2000 }, () => 'y'.repeat(100)).join('\n') const result = await buildWindow(chunked(big, 512), READ_ALL, 'f') + expect(result.totalLines).toBe(2000) expect(result.truncatedByBytes).toBe(true) }) diff --git a/packages/fs/tool-fs/tests/tools.spec.ts b/packages/fs/tool-fs/tests/tools.spec.ts index 4f227b3359..ad31ffbafe 100644 --- a/packages/fs/tool-fs/tests/tools.spec.ts +++ b/packages/fs/tool-fs/tests/tools.spec.ts @@ -572,6 +572,9 @@ describe('read caps are plugin config', () => { const { ctx, fs } = await setupWith({ readMaxBytes: 9 }) fs.files.set('key:a.txt', 'aaaa\nbbbb\ncccc') const result = await call(ctx, 'read', { file_path: 'a.txt' }) + expect(result.isError).toBe(false) + if (result.isError) throw new Error('expected read success') + expect(result.value).toMatchObject({ totalLines: 3 }) expect(text(result)).toContain('Output capped.') expect(text(result)).not.toContain('cccc') }) diff --git a/packages/spill/spill-policy/README.md b/packages/spill/spill-policy/README.md index 9b746f27bc..cf46ccafd6 100644 --- a/packages/spill/spill-policy/README.md +++ b/packages/spill/spill-policy/README.md @@ -30,7 +30,7 @@ This plugin registers **no service** and owns no storage or preview mechanics: p ## Scope -The policy sees only the FINAL formatted surface result—not a tool's internal resource or canonical value. If a provider already truncated (e.g. `web-fetch-local.maxBodyChars`), the spill artifact holds the full formatted result the tool returned, not the full original source. Provider/resource caps stay mandatory and separate. `glob`/`grep` own item-level surface spill because their complete acquired values still exist before rendering; bash streams own acquisition-time spill. See the [tool output spill Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md). +The policy sees only the FINAL formatted surface result—not a tool's internal resource or canonical value. If a provider already truncated (e.g. `web-fetch-local.maxBodyChars`), the spill artifact holds the full formatted result the tool returned, not the full original source. Provider/resource caps stay mandatory and separate. `glob`/`grep` own item-level surface spill because their complete acquired values still exist before rendering; bash streams own acquisition-time spill. The generic policy prepends its waterfall listener, then delegates, so ordinary tool-owned asynchronous projections complete before generic byte bounding regardless of plugin load order. See the [tool output spill Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md). ## Model Experience diff --git a/packages/spill/spill-policy/src/index.ts b/packages/spill/spill-policy/src/index.ts index c2abd094ed..26c501257c 100644 --- a/packages/spill/spill-policy/src/index.ts +++ b/packages/spill/spill-policy/src/index.ts @@ -26,10 +26,11 @@ * failure ⇒ log and return the original result. A spill failure must NEVER * turn a successful tool call into an `isError` or hide the inline result. * - * It COMPOSES with other post-execute listeners: it delegates via `next()` and - * bounds the resulting content projection, so a hook that replaced content - * still has its replacement bounded, while value replacements and `block` - * decisions pass through unchanged. + * It COMPOSES with other post-execute listeners: its prepended listener + * delegates via `next()` and bounds the resulting content projection, so + * tool-owned asynchronous projection runs before generic bounding, a hook that + * replaced content still has its replacement bounded, and value replacements + * and `block` decisions pass through unchanged. * * @module @deepseek-ai/dsh-spill-policy */ @@ -176,5 +177,5 @@ export function apply(ctx: Context, config: Config): void { } const replaced: ContentBlock[] = [{ type: 'text', text: replacedText }] return { kind: 'accept', content: replaced, ...decision.additionalContexts ? { additionalContexts: decision.additionalContexts } : {} } - }) + }, { prepend: true }) } diff --git a/packages/spill/spill-policy/tests/spill-policy.spec.ts b/packages/spill/spill-policy/tests/spill-policy.spec.ts index 8feaa9da95..9a96727d3b 100644 --- a/packages/spill/spill-policy/tests/spill-policy.spec.ts +++ b/packages/spill/spill-policy/tests/spill-policy.spec.ts @@ -16,7 +16,7 @@ import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { SessionId } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import ToolRegistry, { defineContentToolFixture } from '@deepseek-ai/dsh-tools' -import type { ToolExecution, ToolExecutionToken } from '@deepseek-ai/dsh-tools' +import type { PostToolDecision, ToolExecution, ToolExecutionToken } from '@deepseek-ai/dsh-tools' import { SpillLocator, SpillStore } from '@deepseek-ai/dsh-spill' import type { SaveTextSpill, SpillRef } from '@deepseek-ai/dsh-spill' import * as SpillPolicy from '@deepseek-ai/dsh-spill-policy' @@ -60,7 +60,11 @@ function exec(name: string, session = 's1'): ToolExecution { * Build a context with tools + the policy, and optionally a spill backend. * Returns the context and the backend handle (undefined when `withSpill` false). */ -async function setup(config: SpillPolicy.Config, withSpill = true): Promise<{ ctx: Context; spill?: StubStore; fiber: Awaited<ReturnType<Context['plugin']>> }> { +async function setup( + config: SpillPolicy.Config, + withSpill = true, + beforePolicy?: (ctx: Context) => void, +): Promise<{ ctx: Context; spill?: StubStore; fiber: Awaited<ReturnType<Context['plugin']>> }> { const ctx = new Context() await ctx.plugin(SystemPrompt) await ctx.plugin(ToolRegistry) @@ -69,6 +73,7 @@ async function setup(config: SpillPolicy.Config, withSpill = true): Promise<{ ct await ctx.plugin(StubStore) spill = ctx.spillStore as StubStore } + beforePolicy?.(ctx) const fiber = await ctx.plugin(SpillPolicy, config) return { ctx, fiber, ...spill ? { spill } : {} } } @@ -234,6 +239,26 @@ describe('best-effort fallback', () => { }) describe('composition', () => { + it('wraps an earlier tool-owned projection before applying the generic cap', async () => { + let downstreamDecision: PostToolDecision | undefined + const { ctx, spill } = await setup({ maxInlineBytes: 200 }, true, (target) => { + target.on('tools/post-execute', async (_exec, _result, next): Promise<PostToolDecision> => { + downstreamDecision = await next() + return { + kind: 'accept', + content: [{ type: 'text', text: `first page\n\nFull canonical result stored at /spill/search-results.txt.\n${'z'.repeat(500)}` }], + } + }) + }) + ctx.tools.register(textTool('search', 'initial capped page')) + + const result = await ctx.tools.execute(exec('search')) + + expect(downstreamDecision).toEqual({ kind: 'accept' }) + expect(spill?.saves[0]?.content).toContain('Full canonical result stored at /spill/search-results.txt.') + expect(textOf(result.content)).toContain('Full formatted result stored at') + }) + it('bounds content a downstream post-execute listener replaced', async () => { const { ctx, spill } = await setup({ maxInlineBytes: 200 }) // A later-registered listener replaces the (small) tool result with a big one; From 1f7e1765a5e60443c7990136d8d093da6ba4e39c Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:57:29 +0800 Subject: [PATCH 052/368] docs(tools): distinguish closed object validation --- packages/core/tools/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 24588299d9..bc1f9ffeac 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -86,7 +86,7 @@ ctx.tools.register(defineTool({ The unified schema DSL uses `ParameterSchemaSpec` for the implicit open parameter object and `ValueSchemaSpec` for any JSON-value root. It supports `string`, `number`, `integer`, `boolean`, `null`, `array`, `object`, author-only `json`, and exact-one `oneOf`; scalar `enum`/`const` values are type-correct. Every explicit DSL object declares `additionalProperties: true | false`, while the implicit parameter root and raw JSON Schema keep the standard open default. -A `defineTool` definition validates model arguments before execution and turns missing required values, wrong primitives, invalid enum members, and nested violations into `ToolArgsError` (`INVALID_ARGS`) for the normal error-result path. Extra keys are allowed, defaults are not applied, and object or array fields without `properties` or `items` receive only a type check. Raw-registered tools own their validation. +A `defineTool` definition validates model arguments before execution and turns missing required values, wrong primitives, invalid enum members, and nested violations into `ToolArgsError` (`INVALID_ARGS`) for the normal error-result path. The implicit parameter root is open; an explicit object accepts extra keys only with `additionalProperties: true`, and a closed object with no declared properties accepts only `{}`. Raw JSON Schema objects remain open unless they explicitly set `additionalProperties: false`. Defaults are not applied; open objects without `properties` and arrays without `items` receive only a container type check. Raw-registered tools own their validation. See `defineTool`, `validateArgs`, `ToolArgsError`, `ValueSchemaSpec`, `ParameterSchemaSpec`, `InferValue`, `InferArgs`, `valueSchemaSpecToJsonSchema`, and `parameterSchemaSpecToJsonSchema` in the public API for details. From 6250c103b675e6e2aaa87ffa42709f77e4ca8a47 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:11:47 +0800 Subject: [PATCH 053/368] docs(tools): sync bounded output contracts --- docs/config-catalog.md | 2 +- docs/core-data-structures/filesystem.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 37624ea0da..f1bd8c4594 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -1053,7 +1053,7 @@ export interface Config { } ``` -Source: [`packages/spill/spill-policy/src/index.ts:50`](../packages/spill/spill-policy/src/index.ts) +Source: [`packages/spill/spill-policy/src/index.ts:51`](../packages/spill/spill-policy/src/index.ts) ## `@deepseek-ai/dsh-subagent-acp` diff --git a/docs/core-data-structures/filesystem.md b/docs/core-data-structures/filesystem.md index 84d1ce9c5a..25df997bb0 100644 --- a/docs/core-data-structures/filesystem.md +++ b/docs/core-data-structures/filesystem.md @@ -205,7 +205,7 @@ interface FsPolicyExec { ## Read outcome (consumer / read rendering) -A text read is bounded by line window, byte cap, and backend limits. The outcome the model-facing `read` tool renders is purely presentational; there is no `full`/`partial` view — authorization is freshness-based (the tool emits `fs/observed` with the stat's version directly), so any windowed read can authorize a later write/edit when the file is unchanged. Read windowing and this outcome shape live in `dsh-tool-fs` (the executor that owns the read), not in the policy plugin. +A text read is bounded by line window, byte cap, and backend limits. After the byte cap is reached, scanning continues without retaining more lines so `totalLines` remains exact. The outcome the model-facing `read` tool renders is purely presentational; there is no `full`/`partial` view — authorization is freshness-based (the tool emits `fs/observed` with the stat's version directly), so any windowed read can authorize a later write/edit when the file is unchanged. Read windowing and this outcome shape live in `dsh-tool-fs` (the executor that owns the read), not in the policy plugin. ```ts type-equiv /** Outcome of a bounded text read — what {@link formatReadOutput} renders. */ @@ -214,9 +214,9 @@ interface FileReadOutcome { offset: number /** Returned lines, already numbered. */ lines: FileTextLine[] - /** Total line count in the file, unless `truncatedByBytes` stopped scanning early. */ + /** Exact total line count in the file. */ totalLines: number - /** Whether selected output hit the byte cap before EOF or the requested limit. */ + /** Whether selected output hit the byte cap. */ truncatedByBytes?: true } ``` From 865d7de858906efe41e3cb2041ad83fb542bc688 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:27:03 +0800 Subject: [PATCH 054/368] fix(code-runtime): drain late worker pipe output --- ...-20-code-mode-typed-tool-returns.i18n.yaml | 4 +- ...2026-07-20-code-mode-typed-tool-returns.md | 2 +- ...6-07-20-code-mode-typed-tool-returns.zh.md | 2 +- .../code-runtime-worker/README.md | 2 +- .../code-runtime-worker/src/index.ts | 79 ++++++++++++++----- .../code-runtime-worker/tests/runtime.spec.ts | 18 +++++ 6 files changed, 82 insertions(+), 25 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml index 3b3e9544f2..7981bedde0 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml @@ -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 -2026-07-20-code-mode-typed-tool-returns.md: 1beecbc9e5f61ac5dce50aeba508ce75cb0ce507 -2026-07-20-code-mode-typed-tool-returns.zh.md: 0dbad69f6b8120e0904f026961b004855d23f3ab +2026-07-20-code-mode-typed-tool-returns.md: 42fe44c1b6f6a0d0debc9d8e1f742b436cd22047 +2026-07-20-code-mode-typed-tool-returns.zh.md: c567fa86bbe381b9bd54ed37d83fbc0e18252b51 diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md index 1beecbc9e5..42fe44c1b6 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md @@ -61,7 +61,7 @@ The runtime accepts an exact lossless JSON completion of any root. Returning `un `WorkerCodeRuntime` replaces the former independent log and value caps with configurable `maxOutputBytes`, defaulting to `67_108_864` bytes. One host-side hostile-peer ledger accounts the JSON serialization of the outer logs array plus either the completion value or failure diagnostic. A result at or below the cap is exact. A completion that cannot survive lossless JSON snapshotting fails as `invalid-output`; a value or combined logs/value outcome over the cap fails as `output-limit` rather than becoming inspected or truncated text. -Logs stream eagerly so a terminated run can retain output already admitted. When the cap is crossed, the runtime returns an explicit bounded failure with the fitting captured prefix. That outer result then traverses the ordinary `run_code` rendering and spill policy, which may save the captured text and expose its configured head/tail preview. The spill layer cannot recover bytes the runtime rejected beyond the hard cap. +Logs stream eagerly so a terminated run can retain output already admitted. Native stdout and stderr writes that bypass the worker's patched stream slots use independent pipes, so terminal settlement continues bounded capture until worker termination completes before materializing the result. When the cap is crossed, the runtime returns an explicit bounded failure with the fitting captured prefix. That outer result then traverses the ordinary `run_code` rendering and spill policy, which may save the captured text and expose its configured head/tail preview. The spill layer cannot recover bytes the runtime rejected beyond the hard cap. Compute time, wall time, worker heap, cancellation, and fresh-worker isolation remain independent limits. The outer ledger never charges intermediate bindings, so structured-clone cost and available process or worker memory are their practical bounds. diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md index 0dbad69f6b..c567fa86bb 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md @@ -61,7 +61,7 @@ worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造 `WorkerCodeRuntime` 以可配置的 `maxOutputBytes` 取代彼此独立的日志与值上限,默认值为 `67_108_864` 字节。宿主侧为不可信对端维护一份统一账本,计入外层日志数组以及完成值或失败诊断的 JSON 序列化大小。结果不超过上限时会保持精确。完成值无法通过无损 JSON 快照时,以 `invalid-output` 失败;值本身或日志与值的组合超过上限时,以 `output-limit` 失败,而不会变成检查格式化后或截断的文本。 -日志会在产生时立即流出,因此运行被终止时仍可保留已经纳入额度的输出。超过上限后,运行时会返回一个显式的有界失败,并携带可容纳的已捕获前缀。该外层结果随后通过普通的 `run_code` 渲染与输出落盘策略;策略可以保存已捕获的文本,并暴露其配置指定的头尾预览。输出落盘层无法恢复运行时在硬上限之外拒绝的字节。 +日志会在产生时立即流出,因此运行被终止时仍可保留已经纳入额度的输出。绕过 worker 中已改写流写入入口的原生 stdout 和 stderr 写入会经由彼此独立的管道传输,因此运行时在终态结算期间仍会继续在上限内捕获输出,直至 worker 完全终止,然后才组装结果。超过上限后,运行时会返回一个显式的有界失败,并携带可容纳的已捕获前缀。该外层结果随后通过普通的 `run_code` 渲染与输出落盘策略;策略可以保存已捕获的文本,并暴露其配置指定的头尾预览。输出落盘层无法恢复运行时在硬上限之外拒绝的字节。 计算时间、墙钟时间、worker 堆内存、取消和每次运行使用全新 worker 的隔离仍是互相独立的限制。外层账本从不计入中间绑定值,因此这些值实际受结构化克隆开销以及进程或 worker 可用内存限制。 diff --git a/packages/code-runtime/code-runtime-worker/README.md b/packages/code-runtime/code-runtime-worker/README.md index bfa19b1189..6ff75e9fe5 100644 --- a/packages/code-runtime/code-runtime-worker/README.md +++ b/packages/code-runtime/code-runtime-worker/README.md @@ -23,7 +23,7 @@ Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at - **The port assumes a hostile peer** — model code can reach `parentPort` and forge traffic, so every inbound message is shape-validated and REBUILT before anything reads it (`null`, primitives, junk types, and malformed payloads drop without a throw; forged extra fields never ride along), the host answers each call id at most once, resolves binding names as OWN properties only (a forged `constructor` cannot walk a prototype chain), drops post-settlement replies, and validates every binding resolution and completion as lossless JSON. Forged `log`/`done` messages cannot bypass the outer cap: the host repeats validation and accounts every admitted log plus the completion or diagnostic. Worker-side namespaces are null-prototype with `defineProperty`, so `__proto__`-shaped binding names are ordinary keys. - **Two independent budgets, because the peer is hostile** — `computeMs` meters the worker's MEASURED busy time (`worker.performance.eventLoopUtilization()` polling): a hot loop cannot hide behind a pending decoy dispatch, and a program awaiting a slow tool accrues nothing. `maxWallMs` backstops what busy time cannot see (awaiting a promise nobody resolves). Both funnel into `worker.terminate()`, which ends hot synchronous loops too; heap overflow surfaces as the worker's OOM exit (`kind: 'worker-exit'`). - **Intermediate binding values are complete JSON** — binding arguments and resolutions cross by structured clone after lossless-JSON validation and have no byte cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. -- **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure diagnostic. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. +- **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. Native writes that bypass the patched stream slots arrive on pipes independent of the completion port; settlement therefore continues bounded pipe capture until worker termination completes before materializing the result. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure diagnostic. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. - **Empty environment** — the worker gets `env: {}` and `execArgv: []`: no ambient credentials (stronger than the scrubbed-env rule for spawned commands) and no inherited loader flags. - **Dispose to quiescence** — teardown fails in-flight runs as `abort` and AWAITS each worker's exit before resolving. diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index 198bec694b..121b1a47d4 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -8,6 +8,7 @@ import { Worker } from 'node:worker_threads' import { stripTypeScriptTypes } from 'node:module' +import type { Readable } from 'node:stream' import { fileURLToPath } from 'node:url' import { Context } from 'cordis' import z from 'schemastery' @@ -106,6 +107,25 @@ function messageOf(error: unknown): string { return error instanceof Error ? error.message : String(error) } +/** Resolve after a worker pipe emits all queued data, or closes/errors during termination. */ +function waitForPipeDrain(stream: Readable): Promise<void> { + if (stream.readableEnded || stream.destroyed) return Promise.resolve() + return new Promise((resolve) => { + const done = (): void => { + stream.off('end', done) + stream.off('close', done) + stream.off('error', done) + resolve() + } + stream.once('end', done) + stream.once('close', done) + stream.once('error', done) + // Close the event-registration race if termination finished between the + // initial state check and the listeners above. + if (stream.readableEnded || stream.destroyed) done() + }) +} + /** * Runtime shape gate for inbound port traffic. The peer runs MODEL CODE and * can post anything — `null`, primitives, objects with poisoned fields — so @@ -335,13 +355,20 @@ export class WorkerCodeRuntime extends CodeRuntime { const logs: string[] = [] const strayLogs: string[] = [] const output = new OutputLedger(this.config.maxOutputBytes) + let terminalOverride: CodeRunResult | undefined - // No settled guard: `finish` snapshots the arrays when it resolves, so - // a chunk flushing after settlement mutates only the discarded buffers, - // and the ledger bounds that growth until the pipes close. + // Pipe and message-port delivery are independent. Continue bounded pipe + // capture after a terminal message while worker termination drains bytes + // that were already queued; `finish` materializes the result only after + // termination completes. const captureStray = (chunk: Buffer): void => { + if (terminalOverride !== undefined) return const text = chunk.toString('utf8') - if (!settled && !output.admit(text, strayLogs)) finish(output.limit([...logs, ...strayLogs, text])) + if (!output.admit(text, strayLogs)) { + const limited = output.limit([...logs, ...strayLogs, text]) + terminalOverride = limited + finish(() => limited) + } } worker.stdout.on('data', captureStray) worker.stderr.on('data', captureStray) @@ -350,14 +377,20 @@ export class WorkerCodeRuntime extends CodeRuntime { // logs captured before timeout, abort, or failure remain in the result. let finishResolve!: () => void const finished = new Promise<void>((done) => { finishResolve = done }) - const finish = (result: CodeRunResult): void => { + const finish = (finalize: () => CodeRunResult): void => { if (settled) return settled = true clearInterval(eluTimer) clearTimeout(wallTimer) request.signal?.removeEventListener('abort', onAbort) this.live.delete(live) - void worker.terminate().then(() => { + // Let the poll phase deliver pipe bytes already queued independently + // of the terminal port message before termination closes the streams. + void new Promise<void>((resume) => { setImmediate(resume) }).then(async () => { + const stdoutDrained = waitForPipeDrain(worker.stdout) + const stderrDrained = waitForPipeDrain(worker.stderr) + await Promise.all([worker.terminate(), stdoutDrained, stderrDrained]) + const result = terminalOverride ?? finalize() finishResolve() resolve(result) }) @@ -365,22 +398,24 @@ export class WorkerCodeRuntime extends CodeRuntime { const onDone = (message: WorkerToHost): void => { if (message.type !== 'done') return - const captured = [...logs, ...strayLogs] if (message.error) { - finish(output.failure(captured, message.error)) + const error = message.error + finish(() => output.failure([...logs, ...strayLogs], error)) return } if (message.value === undefined) { - finish(output.success(captured)) + finish(() => output.success([...logs, ...strayLogs])) return } // The worker-thread boundary has already structured-cloned this // hostile value, so accessors and proxies cannot survive to throw // during the lossless-JSON snapshot. const value = snapshotJsonValue(message.value) as CodeJsonValue | undefined - finish(value === undefined - ? output.failure(captured, { kind: 'invalid-output', message: 'program completion must be lossless JSON' }) - : output.success(captured, value)) + if (value === undefined) { + finish(() => output.failure([...logs, ...strayLogs], { kind: 'invalid-output', message: 'program completion must be lossless JSON' })) + } else { + finish(() => output.success([...logs, ...strayLogs], value)) + } } const onCall = (message: WorkerToHost): void => { @@ -438,21 +473,25 @@ export class WorkerCodeRuntime extends CodeRuntime { const message = parseWorkerMessage(raw) if (!message) return if (message.type === 'log' && !settled && !output.admit(message.text, logs)) { - finish(output.limit([...logs, ...strayLogs, message.text])) + const limited = output.limit([...logs, ...strayLogs, message.text]) + terminalOverride = limited + finish(() => limited) return } if (message.type === 'output-limit' && !settled) { - finish(output.limit([...logs, ...strayLogs])) + const limited = output.limit([...logs, ...strayLogs]) + terminalOverride = limited + finish(() => limited) return } onCall(message) onDone(message) }) worker.on('error', (error: Error) => { - finish(output.failure([...logs, ...strayLogs], { kind: 'worker-exit', message: `worker error: ${error.message}` })) + finish(() => output.failure([...logs, ...strayLogs], { kind: 'worker-exit', message: `worker error: ${error.message}` })) }) worker.on('exit', (exitCode: number) => { - finish(output.failure([...logs, ...strayLogs], { kind: 'worker-exit', message: `worker exited with code ${exitCode} before completing` })) + finish(() => output.failure([...logs, ...strayLogs], { kind: 'worker-exit', message: `worker exited with code ${exitCode} before completing` })) }) // The compute budget reads the worker's own measured busy time, so a @@ -461,21 +500,21 @@ export class WorkerCodeRuntime extends CodeRuntime { const eluTimer = setInterval(() => { const elu = worker.performance.eventLoopUtilization() if (elu.active > this.config.computeMs) { - finish(output.failure([...logs, ...strayLogs], { kind: 'timeout', message: `compute budget exhausted (${this.config.computeMs}ms busy)` })) + finish(() => output.failure([...logs, ...strayLogs], { kind: 'timeout', message: `compute budget exhausted (${this.config.computeMs}ms busy)` })) } }, ELU_POLL_INTERVAL_MS) const wallTimer = setTimeout(() => { - finish(output.failure([...logs, ...strayLogs], { kind: 'timeout', message: `wall-clock ceiling reached (${this.config.maxWallMs}ms)` })) + finish(() => output.failure([...logs, ...strayLogs], { kind: 'timeout', message: `wall-clock ceiling reached (${this.config.maxWallMs}ms)` })) }, this.config.maxWallMs) const onAbort = (): void => { - finish(output.failure([...logs, ...strayLogs], { kind: 'abort', message: String(request.signal?.reason) })) + finish(() => output.failure([...logs, ...strayLogs], { kind: 'abort', message: String(request.signal?.reason) })) } request.signal?.addEventListener('abort', onAbort, { once: true }) const live: LiveRun = { worker, finished, - settle: (failure: CodeRunFailure) => { finish(output.failure([...logs, ...strayLogs], failure)) }, + settle: (failure: CodeRunFailure) => { finish(() => output.failure([...logs, ...strayLogs], failure)) }, } this.live.add(live) }) diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index c38ee7f492..4d73c859ce 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -333,6 +333,24 @@ describe('WorkerCodeRuntime — budgets and containment (real workers)', () => { expect(result.logs[1]?.length).toBeGreaterThan(0) expect('b'.repeat(100).startsWith(result.logs[1] ?? '')).toBe(true) }, 15_000) + + it('drains pipe output queued before terminal worker teardown completes', async () => { + const { runtime } = await setup({ maxOutputBytes: 200_000 }) + const payload = `late-pipe-${'x'.repeat(100_000)}` + const result = await runtime.run({ + program: ` + const { parentPort } = await import('node:worker_threads'); + const write = (text) => Object.getPrototypeOf(process.stdout).write.call(process.stdout, text); + write('late-pipe-' + 'x'.repeat(100_000)); + parentPort.postMessage({ type: 'done', value: 'done' }); + for (;;) {} + `, + bindings: [], + }) + expect(result.error).toBeUndefined() + expect(result.value).toBe('done') + expect(result.logs.join('') === payload).toBe(true) + }, 15_000) }) describe('WorkerCodeRuntime — hostile programs (real workers)', () => { From 0708bd5ef2bf45e5d7e3e008cadacac060ac9c83 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:29:14 +0800 Subject: [PATCH 055/368] docs(code-runtime): refresh config catalog --- docs/config-catalog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 1fbb2223fa..80a28d74b3 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -301,7 +301,7 @@ export interface Config { } ``` -Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:21`](../packages/code-runtime/code-runtime-worker/src/index.ts) +Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:22`](../packages/code-runtime/code-runtime-worker/src/index.ts) ## `@deepseek-ai/dsh-compact-basic` From bb6709b14ac342f848905f4d6400a625fb93fb51 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:42:41 +0800 Subject: [PATCH 056/368] fix(code-runtime): bound completion measurement --- ...26-07-20-code-mode-typed-tool-returns.i18n.yaml | 4 ++-- .../2026-07-20-code-mode-typed-tool-returns.md | 2 +- .../2026-07-20-code-mode-typed-tool-returns.zh.md | 2 +- .../code-runtime-worker/src/bootstrap.ts | 6 +++--- .../code-runtime/code-runtime-worker/src/index.ts | 14 +++++++------- .../code-runtime-worker/tests/runtime.spec.ts | 9 +++++++++ .../tests/source-worker.compat.spec.ts | 2 +- 7 files changed, 24 insertions(+), 15 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml index 7981bedde0..a4cf2dab15 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml @@ -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 -2026-07-20-code-mode-typed-tool-returns.md: 42fe44c1b6f6a0d0debc9d8e1f742b436cd22047 -2026-07-20-code-mode-typed-tool-returns.zh.md: c567fa86bbe381b9bd54ed37d83fbc0e18252b51 +2026-07-20-code-mode-typed-tool-returns.md: 089773cc715b9003ab4e1667e5af36a8aa1686d4 +2026-07-20-code-mode-typed-tool-returns.zh.md: 24e41ae49182e2d1976e451601cfc8008b1ed11a diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md index 42fe44c1b6..089773cc71 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md @@ -59,7 +59,7 @@ Binding arguments and resolutions are revalidated as lossless JSON on both sides The runtime accepts an exact lossless JSON completion of any root. Returning `undefined` omits the completion; returning `null` is an explicit result. `run_code` exposes the canonical outer value `{ logs: string[], result?: JsonValue }`. Its Native renderer emits logs first, renders a string result raw, and pretty-prints every other JSON root. -`WorkerCodeRuntime` replaces the former independent log and value caps with configurable `maxOutputBytes`, defaulting to `67_108_864` bytes. One host-side hostile-peer ledger accounts the JSON serialization of the outer logs array plus either the completion value or failure diagnostic. A result at or below the cap is exact. A completion that cannot survive lossless JSON snapshotting fails as `invalid-output`; a value or combined logs/value outcome over the cap fails as `output-limit` rather than becoming inspected or truncated text. +`WorkerCodeRuntime` replaces the former independent log and value caps with configurable `maxOutputBytes`, defaulting to `67_108_864` bytes. The worker preflights the detached completion with bounded JSON measurement, and one host-side hostile-peer ledger accounts the JSON serialization of the outer logs array plus either the completion value or failure diagnostic. Neither stage materializes an over-limit serialized completion. A result at or below the cap is exact. A completion that cannot survive lossless JSON snapshotting fails as `invalid-output`; a value or combined logs/value outcome over the cap fails as `output-limit` rather than becoming inspected or truncated text. Logs stream eagerly so a terminated run can retain output already admitted. Native stdout and stderr writes that bypass the worker's patched stream slots use independent pipes, so terminal settlement continues bounded capture until worker termination completes before materializing the result. When the cap is crossed, the runtime returns an explicit bounded failure with the fitting captured prefix. That outer result then traverses the ordinary `run_code` rendering and spill policy, which may save the captured text and expose its configured head/tail preview. The spill layer cannot recover bytes the runtime rejected beyond the hard cap. diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md index c567fa86bb..24e41ae491 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md @@ -59,7 +59,7 @@ worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造 运行时接受以任意 JSON 类型为根的精确无损完成值。返回 `undefined` 表示省略完成值;返回 `null` 则是显式结果。`run_code` 暴露规范外层值 `{ logs: string[], result?: JsonValue }`。其 Native 渲染器先输出日志;字符串结果保持原文,其他所有 JSON 根值采用美化格式输出。 -`WorkerCodeRuntime` 以可配置的 `maxOutputBytes` 取代彼此独立的日志与值上限,默认值为 `67_108_864` 字节。宿主侧为不可信对端维护一份统一账本,计入外层日志数组以及完成值或失败诊断的 JSON 序列化大小。结果不超过上限时会保持精确。完成值无法通过无损 JSON 快照时,以 `invalid-output` 失败;值本身或日志与值的组合超过上限时,以 `output-limit` 失败,而不会变成检查格式化后或截断的文本。 +`WorkerCodeRuntime` 以可配置的 `maxOutputBytes` 取代彼此独立的日志与值上限,默认值为 `67_108_864` 字节。worker 会先用有界 JSON 计量对分离后的完成值执行预检,宿主侧则为不可信对端维护一份统一账本,计入外层日志数组以及完成值或失败诊断的 JSON 序列化大小。这两个阶段都不会实际生成超出上限的完成值序列化结果。结果不超过上限时会保持精确。完成值无法通过无损 JSON 快照时,以 `invalid-output` 失败;值本身或日志与值的组合超过上限时,以 `output-limit` 失败,而不会变成检查格式化后或截断的文本。 日志会在产生时立即流出,因此运行被终止时仍可保留已经纳入额度的输出。绕过 worker 中已改写流写入入口的原生 stdout 和 stderr 写入会经由彼此独立的管道传输,因此运行时在终态结算期间仍会继续在上限内捕获输出,直至 worker 完全终止,然后才组装结果。超过上限后,运行时会返回一个显式的有界失败,并携带可容纳的已捕获前缀。该外层结果随后通过普通的 `run_code` 渲染与输出落盘策略;策略可以保存已捕获的文本,并暴露其配置指定的头尾预览。输出落盘层无法恢复运行时在硬上限之外拒绝的字节。 diff --git a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts index 2334085377..28c0919749 100644 --- a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts +++ b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts @@ -7,6 +7,7 @@ import { inspect } from 'node:util' import type { DoneMessage, ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts' +import { jsonValueBytesUpTo } from './output-json.ts' import { snapshotCodeJsonValue } from './worker-json.ts' /** The port surface the bootstrap needs — satisfied by `parentPort` and by the tests' fake. */ @@ -155,7 +156,7 @@ export function truncateUtf8Bytes(text: string, maxBytes: number): string { */ export function prepareCompletion(value: unknown, maxOutputBytes: number): Omit<DoneMessage, 'type'> { if (value === undefined) return {} - let snapshot: unknown + let snapshot: ReturnType<typeof snapshotCodeJsonValue> try { snapshot = snapshotCodeJsonValue(value) } catch { @@ -164,8 +165,7 @@ export function prepareCompletion(value: unknown, maxOutputBytes: number): Omit< if (snapshot === undefined) { return { error: { kind: 'invalid-output', message: 'program completion must be lossless JSON' } } } - const size = Buffer.byteLength(JSON.stringify(snapshot), 'utf8') - if (size > maxOutputBytes) { + if (jsonValueBytesUpTo(snapshot, maxOutputBytes) === undefined) { return { error: { kind: 'output-limit', message: `outer output exceeded ${maxOutputBytes} bytes` } } } return { value: snapshot } diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index 121b1a47d4..568d6558ca 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -122,6 +122,7 @@ function waitForPipeDrain(stream: Readable): Promise<void> { stream.once('error', done) // Close the event-registration race if termination finished between the // initial state check and the listeners above. + /* v8 ignore next -- this race cannot be scheduled deterministically between the adjacent state check and listener registration. */ if (stream.readableEnded || stream.destroyed) done() }) } @@ -362,12 +363,13 @@ export class WorkerCodeRuntime extends CodeRuntime { // that were already queued; `finish` materializes the result only after // termination completes. const captureStray = (chunk: Buffer): void => { + /* v8 ignore next -- a second post-overflow chunk races immediate worker termination; the first overflow path is covered. */ if (terminalOverride !== undefined) return const text = chunk.toString('utf8') if (!output.admit(text, strayLogs)) { const limited = output.limit([...logs, ...strayLogs, text]) terminalOverride = limited - finish(() => limited) + finish(limited) } } worker.stdout.on('data', captureStray) @@ -377,7 +379,7 @@ export class WorkerCodeRuntime extends CodeRuntime { // logs captured before timeout, abort, or failure remain in the result. let finishResolve!: () => void const finished = new Promise<void>((done) => { finishResolve = done }) - const finish = (finalize: () => CodeRunResult): void => { + const finish = (finalize: CodeRunResult | (() => CodeRunResult)): void => { if (settled) return settled = true clearInterval(eluTimer) @@ -390,7 +392,7 @@ export class WorkerCodeRuntime extends CodeRuntime { const stdoutDrained = waitForPipeDrain(worker.stdout) const stderrDrained = waitForPipeDrain(worker.stderr) await Promise.all([worker.terminate(), stdoutDrained, stderrDrained]) - const result = terminalOverride ?? finalize() + const result = terminalOverride ?? (typeof finalize === 'function' ? finalize() : finalize) finishResolve() resolve(result) }) @@ -474,14 +476,12 @@ export class WorkerCodeRuntime extends CodeRuntime { if (!message) return if (message.type === 'log' && !settled && !output.admit(message.text, logs)) { const limited = output.limit([...logs, ...strayLogs, message.text]) - terminalOverride = limited - finish(() => limited) + finish(limited) return } if (message.type === 'output-limit' && !settled) { const limited = output.limit([...logs, ...strayLogs]) - terminalOverride = limited - finish(() => limited) + finish(limited) return } onCall(message) diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index 4d73c859ce..f8b5210ee9 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -219,6 +219,15 @@ describe('WorkerCodeRuntime — budgets and containment (real workers)', () => { expect(after.value).toBe('alive') }, 30_000) + it('reports a worker that exits before publishing a completion', async () => { + const { runtime } = await setup() + const result = await runtime.run({ program: 'process.exit(7)', bindings: [] }) + expect(result).toEqual({ + logs: [], + error: { kind: 'worker-exit', message: 'worker exited with code 7 before completing' }, + }) + }) + it('fails runaway log output explicitly while retaining a bounded prefix', async () => { const { runtime } = await setup({ maxOutputBytes: 300 }) const result = await runtime.run({ diff --git a/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts b/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts index 5b71a9a94a..ee35b0e990 100644 --- a/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts @@ -13,7 +13,7 @@ it('boots the source worker without workspace package outputs', async () => { const directory = await mkdtemp(join(tmpdir(), 'dsh-code-source-worker-')) let worker: Worker | undefined try { - const files = ['worker.ts', 'bootstrap.ts', 'protocol.ts', 'worker-json.ts'] + const files = ['worker.ts', 'bootstrap.ts', 'protocol.ts', 'worker-json.ts', 'output-json.ts'] await Promise.all(files.map(async (file) => { await copyFile(new URL(`../src/${file}`, import.meta.url), join(directory, file)) })) From 0d851adc3e9b64e3935ed9f978a6072ad8a92c53 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:58:38 +0800 Subject: [PATCH 057/368] fix(session): traverse JSON values iteratively --- ...20-unified-json-value-schema-dsl.i18n.yaml | 4 +- ...026-07-20-unified-json-value-schema-dsl.md | 2 +- ...-07-20-unified-json-value-schema-dsl.zh.md | 2 +- packages/cordis/tool-cordis/src/guard.ts | 29 ++- .../cordis/tool-cordis/tests/mount.spec.ts | 1 + packages/core/session/README.md | 2 +- packages/core/session/src/json.ts | 220 +++++++++--------- packages/core/session/tests/json.spec.ts | 13 ++ 8 files changed, 161 insertions(+), 112 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml index 0cd154e190..ae5592ef01 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml @@ -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 -2026-07-20-unified-json-value-schema-dsl.md: 94c3f5aa5fcb84abddc58e8fd298188b3284f7ea -2026-07-20-unified-json-value-schema-dsl.zh.md: d8362c2c9987689fbd812b6c16aae815f56062e1 +2026-07-20-unified-json-value-schema-dsl.md: 6a3dc21a7ae76ba8f84f5b3edf8306285a02a683 +2026-07-20-unified-json-value-schema-dsl.zh.md: 77ac599e6713563528d0382dfecff83071488930 diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md index 94c3f5aa5f..6a3dc21a7a 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md @@ -12,7 +12,7 @@ Tool parameters used a small author DSL while subagent/workflow structured outpu `dsh-tools` owns one JSON-value schema vocabulary with two representations. `ValueSchemaSpec` is the author form for any JSON root; `ParameterSchemaSpec` is its implicit object-property-map form with per-property `required: true`. `JsonSchemaNode` is the raw wire form. Both support string, finite number, integer, boolean, null, array, object, type-correct scalar `enum`/`const`, and exact-one `oneOf`; `{ type: 'json' }` is author-only sugar for an annotation-only unconstrained raw node. -An explicit author object must declare `additionalProperties: true | false`. The implicit parameter root and raw JSON Schema preserve the standard open default. `InferValue<S>` and `InferArgs<P>` derive TypeScript values from the same declarations that `valueSchemaSpecToJsonSchema()` and `parameterSchemaSpecToJsonSchema()` compile. `assertSupportedJsonSchema()` rejects unsupported or misplaced keywords, and `validateJsonSchemaValue()` enforces the accepted subset against the lossless `JsonValue` boundary: no `undefined`, negative zero, non-finite numbers, sparse arrays, cycles, exotic objects, functions, symbols, or other coercive values. Intrinsic plain Object and Array containers remain plain across JavaScript realms; subclasses remain exotic. +An explicit author object must declare `additionalProperties: true | false`. The implicit parameter root and raw JSON Schema preserve the standard open default. `InferValue<S>` and `InferArgs<P>` derive TypeScript values from the same declarations that `valueSchemaSpecToJsonSchema()` and `parameterSchemaSpecToJsonSchema()` compile. `assertSupportedJsonSchema()` rejects unsupported or misplaced keywords, and `validateJsonSchemaValue()` enforces the accepted subset against the lossless `JsonValue` boundary: no `undefined`, negative zero, non-finite numbers, sparse arrays, cycles, exotic objects, functions, symbols, or other coercive values. Intrinsic plain Object and Array containers remain plain across JavaScript realms; subclasses remain exotic. Validation and snapshot traversal are iterative, so valid nesting is limited by available memory rather than the JavaScript call stack. Object-rooting is a consumer rule rather than a vocabulary restriction. Subagent and workflow caller-defined structured outputs use `assertObjectJsonSchema()` and `ObjectJsonSchema`; tool outputs may use any root. Dynamic Cordis registrations rebuild realm-foreign schemas into host-owned JSON, preserve raw-wrapper openness, and require direct-DSL object openness before calling the same compiler. diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md index d8362c2c99..77ac599e67 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md @@ -12,7 +12,7 @@ Status: implemented `dsh-tools` 以两种表示形式统一管理一套 JSON 值 schema 词汇。`ValueSchemaSpec` 是可描述任意 JSON 根类型的作者侧形式;`ParameterSchemaSpec` 是其隐式对象属性映射形式,每个属性可标记 `required: true`。`JsonSchemaNode` 是原始协议表示。两种形式都支持字符串、有限数值、整数、布尔值、null、数组、对象、类型正确的标量 `enum`/`const`,以及要求恰好匹配一个分支的 `oneOf`;`{ type: 'json' }` 仅是作者侧语法糖,会编译为仅含注解、不施加约束的原始节点。 -显式的作者侧对象必须声明 `additionalProperties: true | false`。隐式参数根对象和原始 JSON Schema 保留标准的默认开放语义。`InferValue<S>` 和 `InferArgs<P>` 根据同一份声明推导 TypeScript 值,`valueSchemaSpecToJsonSchema()` 和 `parameterSchemaSpecToJsonSchema()` 也将这些声明编译为 JSON Schema。`assertSupportedJsonSchema()` 会拒绝不受支持或位置错误的关键字;`validateJsonSchemaValue()` 则以无损 `JsonValue` 边界校验受支持的子集,不允许 `undefined`、负零、非有限数、稀疏数组、循环引用、非普通对象、函数、symbol 及其他需要强制转换的值。内建的普通 Object 和 Array 容器跨 JavaScript 运行域后仍视为普通容器;其子类仍视为非普通对象。 +显式的作者侧对象必须声明 `additionalProperties: true | false`。隐式参数根对象和原始 JSON Schema 保留标准的默认开放语义。`InferValue<S>` 和 `InferArgs<P>` 根据同一份声明推导 TypeScript 值,`valueSchemaSpecToJsonSchema()` 和 `parameterSchemaSpecToJsonSchema()` 也将这些声明编译为 JSON Schema。`assertSupportedJsonSchema()` 会拒绝不受支持或位置错误的关键字;`validateJsonSchemaValue()` 则以无损 `JsonValue` 边界校验受支持的子集,不允许 `undefined`、负零、非有限数、稀疏数组、循环引用、非普通对象、函数、symbol 及其他需要强制转换的值。内建的普通 Object 和 Array 容器跨 JavaScript 运行域后仍视为普通容器;其子类仍视为非普通对象。校验和快照遍历均以迭代方式执行,因此合法嵌套的深度上限由可用内存决定,而非 JavaScript 调用栈。 对象根限制属于消费方规则,不属于 schema 词汇本身。subagent 和工作流中由调用方定义的结构化输出通过 `assertObjectJsonSchema()` 和 `ObjectJsonSchema` 保持对象根限制;工具输出可以使用任意根类型。动态 Cordis 注册会把跨 JavaScript 运行域传入的 schema 重建为当前运行时持有的 JSON,保留原始包装层的默认开放语义,并要求直接使用 DSL 声明的对象明确选择开放方式,然后再调用同一编译器。 diff --git a/packages/cordis/tool-cordis/src/guard.ts b/packages/cordis/tool-cordis/src/guard.ts index e8eb19e524..2ebba0fbd8 100644 --- a/packages/cordis/tool-cordis/src/guard.ts +++ b/packages/cordis/tool-cordis/src/guard.ts @@ -29,9 +29,34 @@ type DynamicToolMarker = { [DYNAMIC_TOOL]?: unknown } function isPlainRecord(value: unknown): value is Record<string, unknown> { if (typeof value !== 'object' || value === null || Array.isArray(value)) return false const prototype: unknown = Object.getPrototypeOf(value) - return prototype === null || Object.getPrototypeOf(prototype) === null + return prototype === null + || typeof prototype === 'object' + && Object.getPrototypeOf(prototype) === null + && hasIntrinsicConstructor(prototype, 'Object') } +/* jscpd:ignore-start -- this VM boundary mirrors the session-owned realm-safe intrinsic test */ +/** Whether a realm-owned intrinsic prototype names and points back to its constructor. */ +function hasIntrinsicConstructor(prototype: object, name: 'Array' | 'Object'): boolean { + const descriptor = Object.getOwnPropertyDescriptor(prototype, 'constructor') + const constructor: unknown = descriptor?.value + return typeof constructor === 'function' + && constructor.name === name + && constructor.prototype === prototype +} + +/** Whether an array uses one realm's intrinsic Array prototype rather than a subclass. */ +function hasPlainArrayPrototype(value: unknown[]): boolean { + const prototype: unknown = Object.getPrototypeOf(value) + if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, 'Array')) return false + const objectPrototype: unknown = Object.getPrototypeOf(prototype) + return typeof objectPrototype === 'object' + && objectPrototype !== null + && Object.getPrototypeOf(objectPrototype) === null + && hasIntrinsicConstructor(objectPrototype, 'Object') +} +/* jscpd:ignore-end */ + /** Materialize realm-foreign lossless JSON without allowing JSON.stringify coercions. */ function cloneJson(value: unknown, path: string, seen = new Set<object>()): unknown { if (value === null || typeof value === 'string' || typeof value === 'boolean') return value @@ -44,7 +69,7 @@ function cloneJson(value: unknown, path: string, seen = new Set<object>()): unkn seen.add(value) try { if (Array.isArray(value)) { - if (Reflect.ownKeys(value).length !== value.length + 1) { + if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) { throw new Error(`harness.defineTool ${path} must be lossless JSON data`) } const output: unknown[] = [] diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 64301f2172..22df219b1b 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -348,6 +348,7 @@ describe('cordis_mount', () => { ['parameters: { value: { type: \'json\', default: Object.defineProperty({}, \'hidden\', { value: true }) } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: { [Symbol(\'hidden\')]: true } } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: new (class DefaultValue { constructor() { this.ok = true } })() } }', 'parameters.value.default must be lossless JSON data'], + ['parameters: { value: { type: \'json\', default: new (class DefaultList extends Array {})() } }', 'parameters.value.default must be lossless JSON data'], ['parameters: { value: { type: \'json\', default: new Date(0) } }', 'parameters.value.default must be lossless JSON data'], ])('rejects a malformed ParameterSchemaSpec (%s) with a teaching error', async (parameters, message) => { const ctx = await setup() diff --git a/packages/core/session/README.md b/packages/core/session/README.md index bba2a21e06..e01e8072c3 100644 --- a/packages/core/session/README.md +++ b/packages/core/session/README.md @@ -46,7 +46,7 @@ Plain class (not a Cordis Service). Create via `ctx.sessions.create()`. ### Lossless JSON utilities -Durable values need one accepted representation, not a check followed by a second read. `isJsonValue(value)` is the boolean predicate; `snapshotJsonValue(value)` recursively validates and copies a plain value in one pass, returning `undefined` for invalid input and propagating a throwing getter. The snapshot helper accepts finite JSON numbers except `-0` (JSON rewrites it to `0`), dense ordinary arrays, and plain or null-prototype objects; it rejects cycles, unsupported scalars, and exotic prototypes before normalization. +Durable values need one accepted representation, not a check followed by a second read. `isJsonValue(value)` is the boolean predicate; `snapshotJsonValue(value)` iteratively validates and copies a plain value in one pass, returning `undefined` for invalid input and propagating a throwing getter. The snapshot helper accepts finite JSON numbers except `-0` (JSON rewrites it to `0`), dense ordinary arrays, and plain or null-prototype objects; it rejects cycles, unsupported scalars, and exotic prototypes before normalization without imposing a call-stack depth limit. ### Surface types diff --git a/packages/core/session/src/json.ts b/packages/core/session/src/json.ts index f7609a1f46..e1452457fd 100644 --- a/packages/core/session/src/json.ts +++ b/packages/core/session/src/json.ts @@ -50,79 +50,127 @@ function enumerableStringKeys(value: object): string[] | undefined { return keys as string[] } +type SnapshotDestination = + | { kind: 'root' } + | { kind: 'array'; target: JsonValue[]; index: number } + | { kind: 'object'; target: { [key: string]: JsonValue }; key: string } + +type JsonWalkTask = + | { kind: 'visit'; value: unknown; destination?: SnapshotDestination } + | { kind: 'array-item'; source: unknown[]; index: number; target?: JsonValue[] } + | { kind: 'object-property'; source: Record<string, unknown>; key: string; target?: { [key: string]: JsonValue } } + | { kind: 'leave'; source: object } + +/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */ +function walkJsonValue(value: unknown, detach: boolean): JsonValue | true | undefined { + const ancestors = new Set<object>() + let root: JsonValue | undefined + const assign = (destination: SnapshotDestination | undefined, item: JsonValue): void => { + if (destination === undefined) return + if (destination.kind === 'root') { + root = item + } else if (destination.kind === 'array') { + destination.target[destination.index] = item + } else { + Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true, + }) + } + } + + const tasks: JsonWalkTask[] = [{ + kind: 'visit', + value, + ...(detach ? { destination: { kind: 'root' } as const } : {}), + }] + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + ancestors.delete(task.source) + continue + } + if (task.kind === 'array-item') { + if (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return undefined + tasks.push({ + kind: 'visit', + value: task.source[task.index], + ...(task.target === undefined ? {} : { destination: { kind: 'array', target: task.target, index: task.index } as const }), + }) + continue + } + if (task.kind === 'object-property') { + tasks.push({ + kind: 'visit', + value: task.source[task.key], + ...(task.target === undefined ? {} : { destination: { kind: 'object', target: task.target, key: task.key } as const }), + }) + continue + } + + const current = task.value + if (current === null) { + assign(task.destination, null) + continue + } + if (typeof current === 'boolean' || typeof current === 'string') { + assign(task.destination, current) + continue + } + if (typeof current === 'number') { + if (!Number.isFinite(current) || Object.is(current, -0)) return undefined + assign(task.destination, current) + continue + } + if (typeof current !== 'object') return undefined + if (ancestors.has(current)) return undefined + + if (Array.isArray(current)) { + if (!hasPlainArrayPrototype(current)) return undefined + const length = current.length + if (Reflect.ownKeys(current).length !== length + 1) return undefined + const target = detach ? [] as JsonValue[] : undefined + if (target !== undefined) assign(task.destination, target) + ancestors.add(current) + tasks.push({ kind: 'leave', source: current }) + for (let index = length - 1; index >= 0; index--) { + tasks.push({ kind: 'array-item', source: current, index, ...(target === undefined ? {} : { target }) }) + } + continue + } + + if (!hasPlainObjectPrototype(current)) return undefined + const keys = enumerableStringKeys(current) + if (keys === undefined) return undefined + const target = detach ? {} as { [key: string]: JsonValue } : undefined + if (target !== undefined) assign(task.destination, target) + ancestors.add(current) + tasks.push({ kind: 'leave', source: current }) + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index] + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) return undefined + tasks.push({ kind: 'object-property', source: current as Record<string, unknown>, key, ...(target === undefined ? {} : { target }) }) + } + } + return detach ? root : true +} + /** * Validate and detach lossless JSON in one read per property, so a stateful - * getter cannot change between validation and copying. Accepts ordinary arrays, - * plain or null-prototype objects, and JSON scalars; rejects sparse, cyclic, - * exotic, negative-zero, and non-finite values. Getter throws propagate. + * getter cannot change between validation and copying. Traversal is iterative, + * so valid nesting is bounded by available memory rather than the JavaScript + * call stack. Accepts ordinary arrays, plain or null-prototype objects, and JSON + * scalars; rejects sparse, cyclic, exotic, negative-zero, and non-finite values. + * Getter throws propagate. * * @param value - the candidate value to validate and detach. * @returns the detached snapshot, or `undefined` when the value is not * losslessly JSON-serializable. */ export function snapshotJsonValue<T>(value: T): T | undefined { - const ancestors = new Set<object>() - - const visit = (current: unknown): JsonValue | undefined => { - if (current === null) return null - switch (typeof current) { - case 'boolean': - case 'string': - return current - case 'number': - return Number.isFinite(current) && !Object.is(current, -0) ? current : undefined - case 'bigint': - case 'function': - case 'symbol': - case 'undefined': - return undefined - case 'object': - break - } - - if (ancestors.has(current)) return undefined - ancestors.add(current) - try { - if (Array.isArray(current)) { - if (!hasPlainArrayPrototype(current)) return undefined - const length = current.length - // Every ordinary array owns `length`; dense indexed elements account - // for the remaining keys. Anything else would be lost by JSON and by - // structured clone, including symbols and non-enumerable properties. - if (Reflect.ownKeys(current).length !== length + 1) return undefined - const snapshot: JsonValue[] = [] - for (let index = 0; index < length; index++) { - if (!Object.prototype.hasOwnProperty.call(current, index)) return undefined - const item = visit(current[index]) - if (item === undefined) return undefined - snapshot.push(item) - } - return snapshot - } - - if (!hasPlainObjectPrototype(current)) return undefined - const keys = enumerableStringKeys(current) - if (keys === undefined) return undefined - const snapshot: { [key: string]: JsonValue } = {} - for (const key of keys) { - const item = visit((current as Record<string, unknown>)[key]) - if (item === undefined) return undefined - // Define the key as data so a JSON field literally named "__proto__" - // cannot mutate the snapshot's prototype through ordinary assignment. - Object.defineProperty(snapshot, key, { - value: item, - enumerable: true, - configurable: true, - writable: true, - }) - } - return snapshot - } finally { - ancestors.delete(current) - } - } - - return visit(value) as T | undefined + return walkJsonValue(value, true) as T | undefined } /** @@ -130,46 +178,8 @@ export function snapshotJsonValue<T>(value: T): T | undefined { * detaching it. Only own enumerable string properties participate; `toJSON` * is ignored and getters run, so persistence boundaries use the snapshotter. * @param value - the candidate event data to test. - * @param seen - current recursion path; callers omit it. * @returns whether `value` survives JSON round-trip losslessly. */ -export function isJsonValue(value: unknown, seen: Set<object> = new Set()): boolean { - if (value === null) return true - switch (typeof value) { - case 'boolean': - case 'string': - return true - case 'number': - return Number.isFinite(value) && !Object.is(value, -0) - case 'bigint': - case 'function': - case 'symbol': - case 'undefined': - return false - case 'object': - break // handled below - } - // object - if (seen.has(value)) return false // circular - seen.add(value) - try { - if (Array.isArray(value)) { - if (!hasPlainArrayPrototype(value)) return false - if (Reflect.ownKeys(value).length !== value.length + 1) return false - // Reject sparse arrays: a hole is skipped by `every`/`forEach` but - // JSON.stringify writes it as `null`, so `[1, , 3]` would round-trip - // lossily. Require every index 0..length-1 to be an OWN property. - for (let i = 0; i < value.length; i++) { - if (!Object.prototype.hasOwnProperty.call(value, i)) return false - if (!isJsonValue(value[i], seen)) return false - } - return true - } - // Plain object only (reject Map/Set/Date/class instances). - if (!hasPlainObjectPrototype(value)) return false - const keys = enumerableStringKeys(value) - return keys !== undefined && keys.every(key => isJsonValue((value as Record<string, unknown>)[key], seen)) - } finally { - seen.delete(value) - } +export function isJsonValue(value: unknown): boolean { + return walkJsonValue(value, false) === true } diff --git a/packages/core/session/tests/json.spec.ts b/packages/core/session/tests/json.spec.ts index 90b3ec6928..e8680142f3 100644 --- a/packages/core/session/tests/json.spec.ts +++ b/packages/core/session/tests/json.spec.ts @@ -80,6 +80,19 @@ describe('snapshotJsonValue', () => { expect(arrayReads).toBe(1) }) + it('accepts deeply nested valid JSON without using the JavaScript call stack', () => { + let value: JsonValue = 'leaf' + for (let depth = 0; depth < 5_000; depth++) value = [value] + + expect(isJsonValue(value)).toBe(true) + let cursor: JsonValue | undefined = snapshotJsonValue(value) + for (let depth = 0; depth < 5_000; depth++) { + expect(Array.isArray(cursor)).toBe(true) + cursor = Array.isArray(cursor) ? cursor[0] : undefined + } + expect(cursor).toBe('leaf') + }) + it('rejects exotic containers, sparse or decorated arrays, cycles, and invalid children', () => { class ExoticObject { readonly value = 1 From fb5292cee5bc462694fe2ffb37895e38785fcbc3 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 02:02:46 +0800 Subject: [PATCH 058/368] fix(tools): classify body snapshot failures --- packages/core/tools/src/index.ts | 19 ++++++++++++++----- packages/core/tools/tests/tools.spec.ts | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 37c444bdf5..565e06eb70 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -405,6 +405,18 @@ function snapshotProjection<T>(toolName: string, projector: 'render' | 'presenta } } +/** Snapshot one body or policy value into the canonical invalid-output failure class. */ +function snapshotToolValue(toolName: string, candidate: unknown): JsonValue { + try { + const detached = snapshotJsonValue(candidate) + if (detached === undefined) throw new ToolOutputError(toolName, ['value is not lossless JSON']) + return detached as JsonValue + } catch (error: unknown) { + if (error instanceof ToolOutputError) throw error + throw new ToolOutputError(toolName, [`value snapshot failed: ${errorMessage(error)}`]) + } +} + /** Successful canonical tool execution, including its Native/model projection. */ export interface ToolExecutionSuccess { readonly isError: false @@ -1316,13 +1328,10 @@ export class ToolRegistry extends Service { /** Snapshot, validate, render, and optionally project one successful body value. */ private createSuccessResult(exec: ToolExecution, tool: ToolDefinition, candidate: unknown): ToolExecutionSuccess { - const detached = snapshotJsonValue(candidate) - if (detached === undefined) { - throw new ToolOutputError(tool.name, ['value is not lossless JSON']) - } + const detached = snapshotToolValue(tool.name, candidate) const violations = validateJsonSchemaValue(tool.output.schema, detached, 'value') if (violations.length > 0) throw new ToolOutputError(tool.name, violations) - const value = deepFreeze(detached as JsonValue) + const value = deepFreeze(detached) let rendered: ContentBlock[] try { rendered = tool.output.render(exec.arguments, value) diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index 49ec56d14d..b23d99f405 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -193,6 +193,28 @@ describe('ToolRegistry', () => { expect(mismatch.content[0]?.type === 'text' ? mismatch.content[0].text : '').toContain('"value" must be a string') }) + it('classifies a throwing body snapshot as invalid tool output', async () => { + const ctx = await setup() + const hostile = Object.defineProperty({}, 'value', { + enumerable: true, + get: () => { throw new Error('body snapshot getter exploded') }, + }) + ctx.tools.register(defineTool({ + name: 'hostile-body', + description: 'hostile body', + parameters: {}, + output: { schema: { type: 'json' }, render: () => [] }, + execute: async () => hostile as JsonValue, + })) + + const result = await ctx.tools.execute({ + signal: testToolSignal, + callId: CallId('hostile-body'), name: 'hostile-body', arguments: {}, + }) + expect(result.error?.message).toContain('value snapshot failed: body snapshot getter exploded') + expect(result.error?.info).toEqual({ name: 'ToolOutputError', code: 'INVALID_TOOL_OUTPUT' }) + }) + it.each(['render', 'presentationMeta'] as const)('contains a throwing output.%s projector as one failed call', async (projector) => { const ctx = await setup() ctx.tools.register(defineTool({ From 6c887e8bcf69a724c1e334fac1efeeda2da33921 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 02:05:02 +0800 Subject: [PATCH 059/368] docs(tools): refresh generated catalogs --- docs/config-catalog.md | 2 +- docs/cordis-catalog/services.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index f1bd8c4594..a8eb73730e 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -1451,7 +1451,7 @@ export interface Config { export type ToolPresentationMode = 'native' | 'code' | 'both' ``` -Source: [`packages/core/tools/src/index.ts:504`](../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:516`](../packages/core/tools/src/index.ts) ## `@deepseek-ai/dsh-tui` diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 1f666d1a96..3c9c684b2f 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -1456,7 +1456,7 @@ async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult> Types: [ScopeKey](../core-data-structures/scope.md) · [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolGuard](../core-data-structures/tools.md) · [ToolRestriction](../core-data-structures/tools.md) · [ToolSchema](../core-data-structures/tools.md) -Source: [`packages/core/tools/src/index.ts:578`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:590`](../../packages/core/tools/src/index.ts) ## `ctx.userInteraction` — `UserInteractionService` From f2d86b232e721baff58424e7fd2a01bd817e7537 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 02:13:37 +0800 Subject: [PATCH 060/368] fix(code-runtime): accept deeply nested JSON --- ...-20-code-mode-typed-tool-returns.i18n.yaml | 4 +- ...2026-07-20-code-mode-typed-tool-returns.md | 2 +- ...6-07-20-code-mode-typed-tool-returns.zh.md | 2 +- .../code-runtime-worker/README.md | 2 +- .../code-runtime-worker/src/worker-json.ts | 121 ++++++++++++------ .../code-runtime-worker/tests/runtime.spec.ts | 20 +++ .../tests/worker-json.spec.ts | 12 ++ 7 files changed, 119 insertions(+), 44 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml index a4cf2dab15..a84e69c18e 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml @@ -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 -2026-07-20-code-mode-typed-tool-returns.md: 089773cc715b9003ab4e1667e5af36a8aa1686d4 -2026-07-20-code-mode-typed-tool-returns.zh.md: 24e41ae49182e2d1976e451601cfc8008b1ed11a +2026-07-20-code-mode-typed-tool-returns.md: 2f7b39ddaa3d4f2441a9061583bb60dbb4c8e14c +2026-07-20-code-mode-typed-tool-returns.zh.md: 9842897cb372d04b4b09679ed13062511347cdc2 diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md index 089773cc71..2f7b39ddaa 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md @@ -53,7 +53,7 @@ Before dispatch the bridge snapshots binding arguments as lossless JSON and make The worker exposes the actual `ToolCallError` constructor used for `tools` binding failures, so `error instanceof ToolCallError` works. The error has the standard `Error` message plus the exact `toolName`; it deliberately omits `ToolFailure.info`, error codes, and Native content. This is an exception contract for control flow, not a failure union for programmatic classification. -Binding arguments and resolutions are revalidated as lossless JSON on both sides of the hostile worker protocol and cross through structured clone with no byte cap. The dependency-light runtime seam names its structural equivalent `CodeJsonValue` so it need not depend on the session-owned canonical type; the generated SDK and tool API use `JsonValue`. Intermediate values are not prompt-truncated, context-spilled, or persisted. This preserves full acquired search, workflow, task, filesystem, and MCP values for programmatic filtering while leaving provider and executor acquisition limits truthful. +Binding arguments and resolutions are revalidated as lossless JSON on both sides of the hostile worker protocol and cross through structured clone with no byte cap. Both snapshot boundaries traverse iteratively, so valid nesting has no JavaScript call-stack depth cap. The dependency-light runtime seam names its structural equivalent `CodeJsonValue` so it need not depend on the session-owned canonical type; the generated SDK and tool API use `JsonValue`. Intermediate values are not prompt-truncated, context-spilled, or persisted. This preserves full acquired search, workflow, task, filesystem, and MCP values for programmatic filtering while leaving provider and executor acquisition limits truthful. ### Outer result and output ledger diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md index 24e41ae491..9842897cb3 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md @@ -53,7 +53,7 @@ declare const tools: { worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造函数,因此 `error instanceof ToolCallError` 能够成立。该错误包含标准的 `Error` 消息和确切的 `toolName`,并有意省略 `ToolFailure.info`、错误代码与 Native 内容。这是一项用于控制流的异常契约,而不是供程序分类的失败联合。 -绑定参数与绑定返回值会在不可信 worker 协议的两端重新校验为无损 JSON,再通过结构化克隆传输,且不设字节上限。为保持依赖轻量,运行时 seam 将结构等价类型命名为 `CodeJsonValue`,从而无需依赖会话侧拥有的规范类型;生成的 SDK 和工具 API 则使用 `JsonValue`。这些值不会经过提示词截断、上下文输出落盘或持久化。因此,程序可以完整筛选已经采集的搜索、工作流、任务、文件系统与 MCP 值,同时提供方和执行器的采集上限仍会实际生效。 +绑定参数与绑定返回值会在不可信 worker 协议的两端重新校验为无损 JSON,再通过结构化克隆传输,且不设字节上限。两处快照边界均采用迭代方式遍历,因此有效嵌套不受 JavaScript 调用栈深度上限限制。为保持依赖轻量,运行时 seam 将结构等价类型命名为 `CodeJsonValue`,从而无需依赖会话侧拥有的规范类型;生成的 SDK 和工具 API 则使用 `JsonValue`。这些值不会经过提示词截断、上下文输出落盘或持久化。因此,程序可以完整筛选已经采集的搜索、工作流、任务、文件系统与 MCP 值,同时提供方和执行器的采集上限仍会实际生效。 ### 外层结果与输出账本 diff --git a/packages/code-runtime/code-runtime-worker/README.md b/packages/code-runtime/code-runtime-worker/README.md index 6ff75e9fe5..3e69d0ae0f 100644 --- a/packages/code-runtime/code-runtime-worker/README.md +++ b/packages/code-runtime/code-runtime-worker/README.md @@ -22,7 +22,7 @@ Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at - **Type-strip host-side, in execution context** — the program is wrapped in an async-function shell, stripped with `node:module`'s `stripTypeScriptTypes` (erasable syntax only — `enum`/namespaces are rejected as a program `exception` and no worker spawns), and sliced back out byte-positioned; it then executes as the body of an `AsyncFunction`, so top-level `await`/`return` work. - **The port assumes a hostile peer** — model code can reach `parentPort` and forge traffic, so every inbound message is shape-validated and REBUILT before anything reads it (`null`, primitives, junk types, and malformed payloads drop without a throw; forged extra fields never ride along), the host answers each call id at most once, resolves binding names as OWN properties only (a forged `constructor` cannot walk a prototype chain), drops post-settlement replies, and validates every binding resolution and completion as lossless JSON. Forged `log`/`done` messages cannot bypass the outer cap: the host repeats validation and accounts every admitted log plus the completion or diagnostic. Worker-side namespaces are null-prototype with `defineProperty`, so `__proto__`-shaped binding names are ordinary keys. - **Two independent budgets, because the peer is hostile** — `computeMs` meters the worker's MEASURED busy time (`worker.performance.eventLoopUtilization()` polling): a hot loop cannot hide behind a pending decoy dispatch, and a program awaiting a slow tool accrues nothing. `maxWallMs` backstops what busy time cannot see (awaiting a promise nobody resolves). Both funnel into `worker.terminate()`, which ends hot synchronous loops too; heap overflow surfaces as the worker's OOM exit (`kind: 'worker-exit'`). -- **Intermediate binding values are complete JSON** — binding arguments and resolutions cross by structured clone after lossless-JSON validation and have no byte cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. +- **Intermediate binding values are complete JSON** — binding arguments and resolutions cross by structured clone after iterative lossless-JSON validation and have no byte or call-stack depth cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. - **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. Native writes that bypass the patched stream slots arrive on pipes independent of the completion port; settlement therefore continues bounded pipe capture until worker termination completes before materializing the result. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure diagnostic. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. - **Empty environment** — the worker gets `env: {}` and `execArgv: []`: no ambient credentials (stronger than the scrubbed-env rule for spawned commands) and no inherited loader flags. - **Dispose to quiescence** — teardown fails in-flight runs as `abort` and AWAITS each worker's exit before resolving. diff --git a/packages/code-runtime/code-runtime-worker/src/worker-json.ts b/packages/code-runtime/code-runtime-worker/src/worker-json.ts index fbc0cd7720..105cc2a646 100644 --- a/packages/code-runtime/code-runtime-worker/src/worker-json.ts +++ b/packages/code-runtime/code-runtime-worker/src/worker-json.ts @@ -40,71 +40,114 @@ function enumerableStringKeys(value: object): string[] | undefined { if (keys.some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) return undefined return keys as string[] } -/* jscpd:ignore-end */ + +type SnapshotDestination = + | { kind: 'root' } + | { kind: 'array'; target: CodeJsonValue[]; index: number } + | { kind: 'object'; target: Record<string, CodeJsonValue>; key: string } + +type SnapshotTask = + | { kind: 'visit'; value: unknown; destination: SnapshotDestination } + | { kind: 'array-item'; source: unknown[]; index: number; target: CodeJsonValue[] } + | { kind: 'object-property'; source: Record<string, unknown>; key: string; target: Record<string, CodeJsonValue> } + | { kind: 'leave'; source: object } /** * Validate and detach one worker-boundary value without loading another * workspace package at runtime. This mirrors the session-owned canonical * JSON boundary while remaining safe to import from the unbuilt worker. + * Its iterative traversal adds no JavaScript call-stack depth limit. * * @param value - the candidate completion value. * @returns a detached lossless-JSON snapshot, or `undefined` when invalid. */ export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined { const active = new Set<object>() - - const within = <T extends CodeJsonValue>(source: object, build: () => T | undefined): T | undefined => { - if (active.has(source)) return undefined - active.add(source) - try { - return build() - } finally { - active.delete(source) + let root: CodeJsonValue | undefined + const assign = (destination: SnapshotDestination, item: CodeJsonValue): void => { + if (destination.kind === 'root') { + root = item + } else if (destination.kind === 'array') { + destination.target[destination.index] = item + } else { + Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true, + }) } } - const copy = (candidate: unknown): CodeJsonValue | undefined => { - if (candidate === null) return null - if (typeof candidate === 'boolean' || typeof candidate === 'string') return candidate + const tasks: SnapshotTask[] = [{ kind: 'visit', value, destination: { kind: 'root' } }] + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + active.delete(task.source) + continue + } + if (task.kind === 'array-item') { + if (!Object.hasOwn(task.source, task.index)) return undefined + tasks.push({ + kind: 'visit', + value: task.source[task.index], + destination: { kind: 'array', target: task.target, index: task.index }, + }) + continue + } + if (task.kind === 'object-property') { + tasks.push({ + kind: 'visit', + value: task.source[task.key], + destination: { kind: 'object', target: task.target, key: task.key }, + }) + continue + } + + const candidate = task.value + if (candidate === null) { + assign(task.destination, null) + continue + } + if (typeof candidate === 'boolean' || typeof candidate === 'string') { + assign(task.destination, candidate) + continue + } if (typeof candidate === 'number') { - return Number.isFinite(candidate) && !Object.is(candidate, -0) ? candidate : undefined + if (!Number.isFinite(candidate) || Object.is(candidate, -0)) return undefined + assign(task.destination, candidate) + continue } if (typeof candidate !== 'object') return undefined + if (active.has(candidate)) return undefined if (Array.isArray(candidate)) { if (!hasPlainArrayPrototype(candidate)) return undefined const length = candidate.length if (Reflect.ownKeys(candidate).length !== length + 1) return undefined - return within(candidate, () => { - const result: CodeJsonValue[] = [] - for (let index = 0; index < length; index++) { - if (!Object.hasOwn(candidate, index)) return undefined - const item = copy(candidate[index]) - if (item === undefined) return undefined - result.push(item) - } - return result - }) + const target: CodeJsonValue[] = [] + assign(task.destination, target) + active.add(candidate) + tasks.push({ kind: 'leave', source: candidate }) + for (let index = length - 1; index >= 0; index--) { + tasks.push({ kind: 'array-item', source: candidate, index, target }) + } + continue } if (!hasPlainObjectPrototype(candidate)) return undefined const keys = enumerableStringKeys(candidate) if (keys === undefined) return undefined - return within(candidate, () => { - const result: Record<string, CodeJsonValue> = {} - for (const key of keys) { - const item = copy((candidate as Record<string, unknown>)[key]) - if (item === undefined) return undefined - Object.defineProperty(result, key, { - value: item, - enumerable: true, - configurable: true, - writable: true, - }) - } - return result - }) + const target: Record<string, CodeJsonValue> = {} + assign(task.destination, target) + active.add(candidate) + tasks.push({ kind: 'leave', source: candidate }) + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index] + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) return undefined + tasks.push({ kind: 'object-property', source: candidate as Record<string, unknown>, key, target }) + } } - - return copy(value) + return root } +/* jscpd:ignore-end */ diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index f8b5210ee9..c4dfefff91 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -74,6 +74,26 @@ describe('WorkerCodeRuntime — programs and bindings (real workers)', () => { expect(calls).toEqual([{ n: 1 }]) }) + it('bridges a deeply nested lossless JSON argument, resolution, and completion', async () => { + const { runtime } = await setup() + const result = await runtime.run({ + program: ` + let value = 'leaf'; + for (let depth = 0; depth < 3_000; depth++) value = [value]; + return await tools.echo(value); + `, + bindings: tools({ echo: async args => args }), + }) + + expect(result.error).toBeUndefined() + let cursor = result.value + for (let depth = 0; depth < 3_000; depth++) { + expect(Array.isArray(cursor)).toBe(true) + cursor = Array.isArray(cursor) ? cursor[0] : undefined + } + expect(cursor).toBe('leaf') + }) + it('reports non-erasable syntax as an exception without spawning a worker', async () => { const { runtime } = await setup() const result = await runtime.run({ program: 'enum E { A }\nreturn 1', bindings: [] }) diff --git a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts index 3d67a67897..8481747c4b 100644 --- a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts @@ -64,6 +64,18 @@ describe('snapshotCodeJsonValue', () => { expect(snapshot[0]?.['__proto__']).toEqual({ safe: true }) }) + it('accepts deeply nested valid JSON without using the JavaScript call stack', () => { + let value: unknown = 'leaf' + for (let depth = 0; depth < 5_000; depth++) value = [value] + + let cursor = snapshotCodeJsonValue(value) + for (let depth = 0; depth < 5_000; depth++) { + expect(Array.isArray(cursor)).toBe(true) + cursor = Array.isArray(cursor) ? cursor[0] : undefined + } + expect(cursor).toBe('leaf') + }) + it('rejects exotic containers, sparse arrays, cycles, and invalid children', () => { class ExoticObject { readonly value = 1 From ccdc6b0ad32090c0e4f3d7e87c072eacb252733f Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 02:28:12 +0800 Subject: [PATCH 061/368] docs(code-mode): clarify post-policy rendering --- .../2026-07-20-code-mode-result-card-completeness.i18n.yaml | 4 ++-- .../bug-fix/2026-07-20-code-mode-result-card-completeness.md | 2 +- .../2026-07-20-code-mode-result-card-completeness.zh.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml index 267a75bd5e..73691b55d9 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.i18n.yaml @@ -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 -2026-07-20-code-mode-result-card-completeness.md: 5fce1c51dbe029f7c109dfdac55444a51f0dd886 -2026-07-20-code-mode-result-card-completeness.zh.md: 624d541cea2e5b4402c880bfe00c586bda7df0ee +2026-07-20-code-mode-result-card-completeness.md: 85942a564b7e4ff6768bedb040ae4371f48bb665 +2026-07-20-code-mode-result-card-completeness.zh.md: 3e71667de66e017176266fd7f5d82aeabf507c61 diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md index 5fce1c51db..85942a564b 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.md @@ -12,7 +12,7 @@ Nested Code calls never owned cards, so producing metadata for the outer call so ## Decision -The canonical tool registry pipeline owns the final model-facing outer content. On success, the `run_code` output renderer renders captured logs followed by the return value or the explicit no-output marker. Runtime failures and policy denials are normalized into error content by `ToolRegistry` without invoking that renderer. Post-execute policy and spill may replace content before persistence. +The canonical tool registry pipeline owns the final model-facing outer content. On success, the `run_code` output renderer renders captured logs followed by the return value or the explicit no-output marker. Runtime failures and pre-execution policy denials are normalized into error content by `ToolRegistry` without invoking that renderer. A post-execute block runs after successful rendering and replaces the result with error content; other post-execute policy and spill decisions may replace content before persistence. `run_code.presentResult` now forwards the final `result.content` into one generic result card. It deliberately omits the title so the pending card retains the program text. The redundant logs-only `presentationMeta` projection is removed: `tool/result.content` is the durable, replayable, post-policy projection and the card's only result-content source. diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md index 624d541cea..3e71667de6 100644 --- a/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md +++ b/.agents/notes/implemented/bug-fix/2026-07-20-code-mode-result-card-completeness.zh.md @@ -12,7 +12,7 @@ Status: implemented ## 决策 -规范的工具注册表流水线负责最终面向模型的外层内容。成功时,`run_code` 输出渲染器先渲染已捕获的日志,然后渲染返回值或显式的无输出标记。运行时失败和策略拒绝由 `ToolRegistry` 归一化为错误内容,过程中不会调用该渲染器。Post-execute 策略与输出落盘机制可以在持久化之前替换这些内容。 +规范的工具注册表流水线负责最终面向模型的外层内容。成功时,`run_code` 输出渲染器先渲染已捕获的日志,然后渲染返回值或显式的无输出标记。运行时失败和执行前策略拒绝由 `ToolRegistry` 归一化为错误内容,过程中不会调用该渲染器。Post-execute 阻断发生在成功渲染之后,并把结果替换为错误内容;其他 post-execute 策略与输出落盘决策可以在持久化之前替换内容。 `run_code.presentResult` 会把最终的 `result.content` 转交给一张通用结果卡片。它有意省略标题,使待完成卡片保留程序文本。多余的仅含日志的 `presentationMeta` 投影被移除:`tool/result.content` 是持久、可回放且经过 post-policy 处理的投影,也是卡片中结果内容的唯一来源。 From 642ef353ece7a0d028b3ec6f4003b2718944f3f5 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:40:23 +0800 Subject: [PATCH 062/368] docs(config): refresh catalog after merge --- docs/config-catalog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 92e45d5b65..b3acd460a3 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -894,7 +894,7 @@ export interface Config { export type JsonlCompression = 'zstd' | 'none' ``` -Source: [`packages/session-persistence/session-persistence-jsonl/src/index.ts:37`](../packages/session-persistence/session-persistence-jsonl/src/index.ts) +Source: [`packages/session-persistence/session-persistence-jsonl/src/index.ts:38`](../packages/session-persistence/session-persistence-jsonl/src/index.ts) ## `@deepseek-ai/dsh-session-persistence-sqlite` @@ -1495,7 +1495,7 @@ export interface TuiConfig { } ``` -Source: [`packages/ui/tui/src/index.ts:128`](../packages/ui/tui/src/index.ts) +Source: [`packages/ui/tui/src/index.ts:129`](../packages/ui/tui/src/index.ts) ## `@deepseek-ai/dsh-tui-demo` From e23c201da87955e8c50f75c3ee4504fd6866d369 Mon Sep 17 00:00:00 2001 From: Chinesezjc <jczhai@deepseek.com> Date: Wed, 22 Jul 2026 13:21:18 +0800 Subject: [PATCH 063/368] perf(ci): parallelize packed-companion probes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit verify-built-package-invariants ran 100+ npm-pack + plain-Node probes serially, dominating the CI artifacts lane (~4min of a ~5min job; ~7.5min on Windows). Each probe stages its packed view inside its own package and spawns its own processes, so the probes are independent — run them through the same bounded worker pool shape as publint-all, capped by DSH_BUILT_INVARIANTS_CONCURRENCY (default availableParallelism), failures kept in manifest order. Measured on the gate alone: 2m07s serial -> 17s at concurrency 8. CI lanes pin the cap to 8, matching DSH_PUBLINT_CONCURRENCY. --- .../2026-07-06-parallel-pre-push-gates.md | 2 + .github/workflows/ci.yml | 12 +++ scripts/verify-built-package-invariants.mjs | 93 ++++++++++++++----- 3 files changed, 85 insertions(+), 22 deletions(-) diff --git a/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.md b/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.md index 710c37cb3a..e649c8c2c9 100644 --- a/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.md +++ b/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.md @@ -20,6 +20,8 @@ The build gate makes the hook self-contained from a clean worktree. `publint`, ` [scripts/publint-all.ts](../../../../scripts/publint-all.ts) discovers the package list from `packages/<group>/<pkg>` and runs `publint` with a worker pool sized from `availableParallelism()`. `DSH_PUBLINT_CONCURRENCY` can cap or raise the worker count for local machines and CI runners with different resource profiles. Results are buffered per package and printed in deterministic package order, so parallel execution does not scramble each package's log block. +[scripts/verify-built-package-invariants.mjs](../../../../scripts/verify-built-package-invariants.mjs) has the same per-package independence — each probe stages its packed view inside its own package and spawns its own `npm pack` and Node processes — so it uses the same bounded-pool shape with `DSH_BUILT_INVARIANTS_CONCURRENCY` as its cap. Serially it dominated the CI artifacts lane (about 4 minutes for 100+ packages, over half the lane's wall clock); the pool collapses that to the slowest probe batch, and failures keep manifest order. + The per-gate package scripts remain the vocabulary for ad hoc local runs. `hygiene` stays an aggregate `&&` chain the scheduler mirrors, while `doc-sync` has since moved its member list into the scheduler itself ([doc-sync through the gate scheduler](2026-07-21-doc-sync-through-gate-scheduler.md)). ## Alternatives considered diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de9a03288b..3aabcb60cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,7 @@ jobs: env: DSH_GATE_CONCURRENCY: ${{ matrix.gate_concurrency }} DSH_PUBLINT_CONCURRENCY: ${{ matrix.publint_concurrency }} + DSH_BUILT_INVARIANTS_CONCURRENCY: ${{ matrix.built_invariants_concurrency }} DSH_COVERAGE_MAX_WORKERS: ${{ matrix.coverage_max_workers }} DSH_ESLINT_CACHE: ${{ matrix.eslint_cache }} strategy: @@ -32,30 +33,35 @@ jobs: command: pnpm run check:ci:static gate_concurrency: '4' publint_concurrency: '8' + built_invariants_concurrency: '8' coverage_max_workers: '' eslint_cache: '' - lane: lint command: pnpm run check:ci:lint gate_concurrency: '1' publint_concurrency: '8' + built_invariants_concurrency: '8' coverage_max_workers: '' eslint_cache: '1' - lane: coverage command: pnpm run check:ci:coverage gate_concurrency: '1' publint_concurrency: '8' + built_invariants_concurrency: '8' coverage_max_workers: '4' eslint_cache: '' - lane: snapshot command: pnpm run check:ci:snapshot gate_concurrency: '1' publint_concurrency: '8' + built_invariants_concurrency: '8' coverage_max_workers: '' eslint_cache: '' - lane: artifacts command: pnpm run check:ci:artifacts gate_concurrency: '3' publint_concurrency: '8' + built_invariants_concurrency: '8' coverage_max_workers: '' eslint_cache: '' steps: @@ -192,6 +198,7 @@ jobs: env: DSH_GATE_CONCURRENCY: ${{ matrix.gate_concurrency }} DSH_PUBLINT_CONCURRENCY: ${{ matrix.publint_concurrency }} + DSH_BUILT_INVARIANTS_CONCURRENCY: ${{ matrix.built_invariants_concurrency }} DSH_COVERAGE_MAX_WORKERS: ${{ matrix.coverage_max_workers }} DSH_ESLINT_CACHE: ${{ matrix.eslint_cache }} strategy: @@ -202,30 +209,35 @@ jobs: command: pnpm run check:ci:static gate_concurrency: '4' publint_concurrency: '8' + built_invariants_concurrency: '8' coverage_max_workers: '' eslint_cache: '' - lane: lint command: pnpm run check:ci:lint gate_concurrency: '1' publint_concurrency: '8' + built_invariants_concurrency: '8' coverage_max_workers: '' eslint_cache: '1' - lane: coverage command: pnpm run check:ci:coverage gate_concurrency: '1' publint_concurrency: '8' + built_invariants_concurrency: '8' coverage_max_workers: '4' eslint_cache: '' - lane: snapshot command: pnpm run check:ci:snapshot gate_concurrency: '1' publint_concurrency: '8' + built_invariants_concurrency: '8' coverage_max_workers: '' eslint_cache: '' - lane: artifacts command: pnpm run check:ci:artifacts gate_concurrency: '3' publint_concurrency: '8' + built_invariants_concurrency: '8' coverage_max_workers: '' eslint_cache: '' steps: diff --git a/scripts/verify-built-package-invariants.mjs b/scripts/verify-built-package-invariants.mjs index 4b298946d1..7b9aa0c187 100644 --- a/scripts/verify-built-package-invariants.mjs +++ b/scripts/verify-built-package-invariants.mjs @@ -1,6 +1,6 @@ /** Verify every packed companion through its package self-reference under plain Node. */ -import { spawnSync } from 'node:child_process' +import { execFile } from 'node:child_process' import { copyFileSync, globSync, @@ -9,12 +9,16 @@ import { readFileSync, rmSync, } from 'node:fs' +import { availableParallelism } from 'node:os' import { dirname, resolve } from 'node:path' import { pathToFileURL } from 'node:url' +import { promisify } from 'node:util' + +const execFileAsync = promisify(execFile) +const CONCURRENCY_ENV = 'DSH_BUILT_INVARIANTS_CONCURRENCY' const root = resolve(import.meta.dirname, '..') const loaderUrl = pathToFileURL(resolve(root, 'vendor/loader/lib/index.js')).href -const failures = [] const manifests = globSync('packages/*/*/package.json', { cwd: root }).sort() const packArgs = ['pack', '--dry-run', '--json', '--ignore-scripts'] // Windows cannot spawn npm's .cmd shim directly; setup-node installs this JS @@ -23,24 +27,54 @@ const npmInvocation = process.platform === 'win32' ? [process.execPath, [resolve(dirname(process.execPath), 'node_modules/npm/bin/npm-cli.js'), ...packArgs]] : ['npm', packArgs] -for (const manifestPath of manifests) { +function probeConcurrency(total) { + if (total === 0) return 0 + + const raw = process.env[CONCURRENCY_ENV] + if (raw !== undefined && raw !== '') { + const parsed = Number.parseInt(raw, 10) + if (!Number.isSafeInteger(parsed) || parsed < 1) { + throw new Error(`verify-built-package-invariants: ${CONCURRENCY_ENV} must be a positive integer, got ${JSON.stringify(raw)}.`) + } + return Math.min(total, parsed) + } + + return Math.min(total, availableParallelism()) +} + +async function runCommand(command, args, cwd) { + try { + const { stdout, stderr } = await execFileAsync(command, args, { + cwd, + encoding: 'utf8', + maxBuffer: 10 * 1024 * 1024, + }) + return { status: 0, stdout, stderr, message: undefined } + } catch (error) { + const failed = /** @type {{ code?: number; stdout?: unknown; stderr?: unknown; message?: string }} */ (error) + return { + status: typeof failed.code === 'number' ? failed.code : 1, + stdout: typeof failed.stdout === 'string' ? failed.stdout : '', + stderr: typeof failed.stderr === 'string' ? failed.stderr : '', + message: failed.message ?? 'command failed', + } + } +} + +/** Probe one manifest's packed companion; resolves to a failure string or undefined. */ +async function verifyManifest(manifestPath) { const packageDir = dirname(resolve(root, manifestPath)) const manifest = JSON.parse(readFileSync(resolve(root, manifestPath), 'utf8')) const packageName = manifest.name if (typeof packageName !== 'string' || packageName.length === 0) { - failures.push(`${manifestPath}: missing package name`) - continue + return `${manifestPath}: missing package name` } - const pack = spawnSync(npmInvocation[0], npmInvocation[1], { - cwd: packageDir, - encoding: 'utf8', - }) + const pack = await runCommand(npmInvocation[0], npmInvocation[1], packageDir) if (pack.status !== 0) { - const detail = pack.error?.message - ?? (pack.stderr.trim() || pack.stdout.trim() || `npm pack exited ${pack.status}`) - failures.push(`${packageName}: ${detail}`) - continue + const detail = pack.stderr.trim() || pack.stdout.trim() || pack.message + || `npm pack exited ${pack.status}` + return `${packageName}: ${detail}` } let files @@ -49,8 +83,7 @@ for (const manifestPath of manifests) { files = result[0]?.files if (!Array.isArray(files)) throw new Error('npm pack returned no file inventory') } catch (error) { - failures.push(`${packageName}: cannot parse npm pack inventory: ${String(error)}`) - continue + return `${packageName}: cannot parse npm pack inventory: ${String(error)}` } // Keep the packed view below its owning package so Node reaches the real @@ -79,20 +112,36 @@ for (const manifestPath of manifests) { } if (typeof unwrapped.apply !== 'function') throw new Error('companion apply is missing'); ` - const result = spawnSync(process.execPath, ['--input-type=module', '--eval', probe], { - cwd: stagedPackageDir, - encoding: 'utf8', - }) + const result = await runCommand(process.execPath, ['--input-type=module', '--eval', probe], stagedPackageDir) if (result.status !== 0) { - const detail = result.error?.message - ?? (result.stderr.trim() || result.stdout.trim() || `node exited ${result.status}`) - failures.push(`${packageName}: ${detail}`) + const detail = result.stderr.trim() || result.stdout.trim() || result.message + || `node exited ${result.status}` + return `${packageName}: ${detail}` } + return undefined } finally { rmSync(stagedPackageDir, { recursive: true, force: true }) } } +/** Run every manifest probe through a bounded worker pool, keeping failures in manifest order. */ +async function runAll(paths, concurrency) { + let next = 0 + const results = new Array(paths.length) + const workers = Array.from({ length: concurrency }, async () => { + for (;;) { + const index = next + next += 1 + if (index >= paths.length) return + results[index] = await verifyManifest(paths[index]) + } + }) + await Promise.all(workers) + return results.filter(failure => failure !== undefined) +} + +const failures = await runAll(manifests, probeConcurrency(manifests.length)) + if (failures.length > 0) { console.error('verify-built-package-invariants: packed companion failures:') for (const failure of failures) console.error(` ${failure}`) From 0580bc9068b042e6d1557dea298005139a572cae Mon Sep 17 00:00:00 2001 From: Chinesezjc <jczhai@deepseek.com> Date: Wed, 22 Jul 2026 15:30:53 +0800 Subject: [PATCH 064/368] fix(ci): reject partially parsed concurrency limits Number.parseInt accepts a numeric prefix, so values like 1.5 or 8junk silently ran an unintended worker count. Require the full string to round-trip (same pattern as run-gates' positiveIntArg). --- scripts/verify-built-package-invariants.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/verify-built-package-invariants.mjs b/scripts/verify-built-package-invariants.mjs index 7b9aa0c187..7412404a97 100644 --- a/scripts/verify-built-package-invariants.mjs +++ b/scripts/verify-built-package-invariants.mjs @@ -33,7 +33,7 @@ function probeConcurrency(total) { const raw = process.env[CONCURRENCY_ENV] if (raw !== undefined && raw !== '') { const parsed = Number.parseInt(raw, 10) - if (!Number.isSafeInteger(parsed) || parsed < 1) { + if (!Number.isSafeInteger(parsed) || parsed < 1 || String(parsed) !== raw) { throw new Error(`verify-built-package-invariants: ${CONCURRENCY_ENV} must be a positive integer, got ${JSON.stringify(raw)}.`) } return Math.min(total, parsed) From 21456a36cafce19bfc088720140e481e5abf59fe Mon Sep 17 00:00:00 2001 From: Turtle <turtle1999@deepseek.com> Date: Wed, 22 Jul 2026 16:36:48 +0800 Subject: [PATCH 065/368] docs: add hands-on Cordis tutorial Seven-chapter tutorial under docs/cordis-tutorial/ for agent developers new to Cordis: first plugin, lifecycle/effects, services, events, config, composition/HMR, and a final chapter registering a tool against real harness services. Every transcript was produced by running the chapter files in a gitignored tmp/ scratch directory. Published to both website locales as mirrored English pages under a new 'Cordis tutorial' develop-sidebar section; a Chinese pair can be added later without route changes. --- .../2026-07-22-cordis-tutorial-docs.i18n.yaml | 6 + .../2026-07-22-cordis-tutorial-docs.md | 32 ++++ .../2026-07-22-cordis-tutorial-docs.zh.md | 32 ++++ docs/cordis-primer.md | 2 +- docs/cordis-tutorial/01-first-plugin.md | 91 ++++++++++++ .../02-lifecycle-and-effects.md | 89 +++++++++++ docs/cordis-tutorial/03-services.md | 94 ++++++++++++ docs/cordis-tutorial/04-events.md | 140 ++++++++++++++++++ docs/cordis-tutorial/05-config.md | 84 +++++++++++ .../cordis-tutorial/06-composition-and-hmr.md | 105 +++++++++++++ docs/cordis-tutorial/07-into-the-harness.md | 101 +++++++++++++ docs/cordis-tutorial/index.md | 54 +++++++ website/.vitepress/config.ts | 2 + website/docs.ts | 21 +++ 14 files changed, 852 insertions(+), 1 deletion(-) create mode 100644 .agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.i18n.yaml create mode 100644 .agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.md create mode 100644 .agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.zh.md create mode 100644 docs/cordis-tutorial/01-first-plugin.md create mode 100644 docs/cordis-tutorial/02-lifecycle-and-effects.md create mode 100644 docs/cordis-tutorial/03-services.md create mode 100644 docs/cordis-tutorial/04-events.md create mode 100644 docs/cordis-tutorial/05-config.md create mode 100644 docs/cordis-tutorial/06-composition-and-hmr.md create mode 100644 docs/cordis-tutorial/07-into-the-harness.md create mode 100644 docs/cordis-tutorial/index.md diff --git a/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.i18n.yaml b/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.i18n.yaml new file mode 100644 index 0000000000..b2aa854cf3 --- /dev/null +++ b/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-22-cordis-tutorial-docs.md: 45abb8f524218ce0b2678606ae62c7bf2dbca00b +2026-07-22-cordis-tutorial-docs.zh.md: cd1a62e2a6e7f2e28bc32109dd67746840f8b8b7 diff --git a/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.md b/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.md new file mode 100644 index 0000000000..45abb8f524 --- /dev/null +++ b/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.md @@ -0,0 +1,32 @@ +# Agent Note: Tutorial-style Cordis docs under docs/cordis-tutorial + +Status: implemented + +English | [中文](2026-07-22-cordis-tutorial-docs.zh.md) + +## Problem + +The repo documents Cordis at two levels: the condensed [cordis-primer](../../../../docs/cordis-primer.md) states the concepts, and the `docs/user/develop/` pages teach harness plugin authoring against harness services. Neither serves a developer meeting Cordis itself for the first time: the primer assumes the reader already writes plugins, and the develop pages jump straight to `defineTool` without showing how contexts, fibers, services, and dispatch actually behave. There was no path where a reader runs bare Cordis, watches a fiber go PENDING, or sees a waterfall veto happen. + +## Decision + +`docs/cordis-tutorial/` holds a seven-chapter hands-on tutorial (first plugin → lifecycle/effects → services → events → config → composition/HMR → harness tool). Its properties, in decreasing order of load-bearing-ness: + +- **Every transcript is real.** Each chapter's files run in the gitignored `tmp/cordis-tutorial/` scratch directory via `node --import tsx ../../vendor/cordis/bin.js`, and the shown output is what those commands print. The chapter that uses harness packages (`@deepseek-ai/dsh-tools` and `@deepseek-ai/dsh-llm`) runs keylessly. +- **dsh-flavored, not pure Cordis**: later chapters use real harness services and events (`ctx.tools`, `tools/result`) so the tutorial lands the reader inside this repo's actual composition model, per the requesting user's choice. +- **English-only, published to both website locales** through `mirroredPages()` in [website/docs.ts](../../../../website/docs.ts) under a `Cordis 教程` / `Cordis tutorial` section of the develop sidebar — the same pattern as the reference pages, so a Chinese pair can ratchet in later without route changes. +- Code fences compile under `doc-typecheck` except the two fences that import scratch-relative files (`./stats.ts`) or intentionally throw, which carry `ignore-check`. + +## Alternatives considered + +**Under `docs/user/develop/` as paired product docs.** That tier requires en+zh+i18n records in the same PR, roughly doubling the change and coupling every future tutorial edit to a translation. Rejected for the first landing; the mirrored projection keeps the same public visibility. + +**Pure-Cordis tutorial with no harness packages.** Cleaner as framework documentation, but the audience is agent developers extending this harness; ending at `ctx.tools.execute` and `tools/result` teaches the composition they will actually work in. The user chose this explicitly. + +**Extending the primer instead of a new directory.** The primer is a 600-word budgeted concept reference; a multi-chapter walkthrough inside it would break its tier's job (and its budget) rather than complement it. + +## Consequences + +- A runnable introduction to Cordis exercises the loader, fiber states, effects, service injection, all five dispatch-mode contracts, Schemastery validation, and HMR. It demonstrates PENDING dependencies and validation failure; it explains the loader's logged unresolved-entry failure because that boot-time log may not reach a console exporter. +- The tutorial's transcripts pin behavior informally but are not snapshot-gated; if loader or HMR behavior changes, the transcripts drift until a human replays the chapters. The compile gate covers only the code fences. +- The chapters name concrete harness APIs (`ctx.tools.execute`, `CallId`, `tools/result`); renames must update the tutorial like any other doc reference (`verify-md-links` catches file moves, not API prose). diff --git a/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.zh.md b/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.zh.md new file mode 100644 index 0000000000..cd1a62e2a6 --- /dev/null +++ b/.agents/notes/implemented/process/2026-07-22-cordis-tutorial-docs.zh.md @@ -0,0 +1,32 @@ +# Agent Note: `docs/cordis-tutorial` 下的 Cordis 实操教程文档 + +Status: implemented + +[English](2026-07-22-cordis-tutorial-docs.md) | 中文 + +## 问题 + +本仓库从两个层面介绍 Cordis:精简的 [cordis-primer](../../../../docs/cordis-primer.md) 阐述概念,`docs/user/develop/` 下的页面则讲解如何基于 harness 服务编写 harness 插件。但二者都不适合初次接触 Cordis 的开发者:primer 假定读者已经会编写插件,开发页面则直接从 `defineTool` 讲起,没有展示上下文、fiber、服务和 dispatch 的实际行为。此前没有一条学习路径让读者运行原生 Cordis、观察 fiber 进入 PENDING 状态,或看到 waterfall(瀑布式事件)否决实际发生。 + +## 决策 + +`docs/cordis-tutorial/` 包含一套七章实操教程(第一个插件 → 生命周期与 effect → 服务 → 事件 → 配置 → 组合与 HMR(热模块替换)→ harness 工具)。以下是教程的特性,按重要性从高到低排列: + +- **每段 transcript(文本记录)都真实可复现。** 每章文件都通过 `node --import tsx ../../vendor/cordis/bin.js` 在 git 忽略的 `tmp/cordis-tutorial/` 临时目录中运行,展示的输出就是这些命令实际打印的内容。使用 harness 包(package)(`@deepseek-ai/dsh-tools` 和 `@deepseek-ai/dsh-llm`)的章节无需密钥即可运行。 +- **采用 dsh 风格,而非纯 Cordis**:后续章节使用真实的 harness 服务和事件(`ctx.tools`、`tools/result`),使读者最终进入本仓库实际采用的组合模型,这遵循了提出请求的用户所作的选择。 +- **仅提供英文版,但发布到网站的两个语言区域**:通过 [website/docs.ts](../../../../website/docs.ts) 中的 `mirroredPages()`,发布到开发侧边栏的 `Cordis 教程` / `Cordis tutorial` 分区。该方式与参考页面采用的模式相同,因此日后可以逐步纳入中文配对,而无需更改路由。 +- 除两个围栏代码块外,其余代码块均通过 `doc-typecheck` 编译;这两个例外分别导入临时目录中的相对路径文件(`./stats.ts`)或有意抛出异常,因此标有 `ignore-check`。 + +## 考虑过的替代方案 + +**作为双语产品文档放在 `docs/user/develop/` 下。** 该层级要求在同一个 PR(Pull Request)中同时提供英文、中文和 i18n 记录,这会使变更量大致翻倍,并要求未来每次修改教程时都同步翻译。首次落地不采用此方案;镜像投影仍可保持同等的公开可见性。 + +**不使用任何 harness 包的纯 Cordis 教程。** 作为框架文档会更简洁,但目标读者是扩展此 harness 的 agent(智能体)开发者;以 `ctx.tools.execute` 和 `tools/result` 收尾,能讲清他们实际使用的组合方式。用户明确选择了此方案。 + +**扩充 primer,而非新建目录。** primer 是一份预算上限为 600 词的精简概念参考;在其中加入多章演练会破坏该文档层级的职责及其篇幅预算,而非形成补充。 + +## 结果 + +- 现在有了一份可运行的 Cordis 入门教程,涵盖 loader、fiber 状态、effect、服务注入、全部五种 dispatch 模式的契约、Schemastery 校验和 HMR。教程实际展示了依赖处于 PENDING 状态和配置校验失败;对于 loader 记录的配置项解析失败,教程只作说明,因为启动阶段的日志可能无法到达控制台导出器。 +- 教程中的 transcript 以非正式方式固定了行为,但没有快照门禁;如果 loader 或 HMR 的行为发生变化,transcript 会逐渐偏离实际结果,直到有人重新运行各章。编译门禁只覆盖围栏代码块。 +- 各章写明了具体的 harness API(`ctx.tools.execute`、`CallId`、`tools/result`);这些 API 重命名时,必须像更新其他文档引用一样同步修改教程(`verify-md-links` 能发现文件移动,但无法发现 API 文字引用变化)。 diff --git a/docs/cordis-primer.md b/docs/cordis-primer.md index d8e92dcb67..64230564b7 100644 --- a/docs/cordis-primer.md +++ b/docs/cordis-primer.md @@ -1,6 +1,6 @@ # Cordis Primer -Cordis is the vendored plugin framework underneath the DeepSeek Harness SDK. This primer teaches the Cordis ideas a harness plugin author needs before reading the generated [events](cordis-catalog/events.md) and [services](cordis-catalog/services.md) catalogs. The vendored source and sync procedure live in [vendor/README.md](../vendor/README.md). +Cordis is the vendored plugin framework underneath the DeepSeek Harness SDK. This primer teaches the Cordis ideas a harness plugin author needs before reading the generated [events](cordis-catalog/events.md) and [services](cordis-catalog/services.md) catalogs; the [Cordis tutorial](cordis-tutorial/index.md) walks the same ideas hands-on. The vendored source and sync procedure live in [vendor/README.md](../vendor/README.md). ## Cordis In Five Ideas diff --git a/docs/cordis-tutorial/01-first-plugin.md b/docs/cordis-tutorial/01-first-plugin.md new file mode 100644 index 0000000000..468683a71d --- /dev/null +++ b/docs/cordis-tutorial/01-first-plugin.md @@ -0,0 +1,91 @@ +# 1. Your first plugin + +In the loader configuration used here, a Cordis plugin module named-exports an `apply` function. When Cordis loads it, it calls `apply` with a **context** — the `ctx` object through which the plugin registers everything it contributes. + +## Write the plugin + +In your `tmp/cordis-tutorial` directory (see [setup](index.md#setup)), create `hello.ts`: + +```ts +import type { Context } from 'cordis' + +export const name = 'hello' + +export function apply(ctx: Context) { + console.log('hello from my first plugin') +} +``` + +The `name` export is optional display metadata; it labels the plugin in diagnostics. + +## Compose the app + +This tutorial's launcher assembles the application from configuration. Create `cordis.yml`: + +```yaml +- name: './hello.ts' +``` + +The file is a list of plugin entries. `name` is a module specifier — a relative path or an npm package name — and the loader mounts each entry in order. + +## Run it + +```sh +node --import tsx ../../vendor/cordis/bin.js +``` + +Expected output: + +``` +hello from my first plugin +``` + +The process exits on its own once nothing is left running. What happened: + +1. The launcher created a root `Context` and mounted the **Loader** plugin. +2. The Loader read `cordis.yml`, resolved `./hello.ts`, and mounted it as a child plugin. +3. Cordis called your `apply(ctx)`. + +There is no framework bootstrap code in your file: a plugin describes what it contributes, and `cordis.yml` composes the application. The [TUI agent](../../examples/tui-agent/cordis.yml), for example, is a longer plugin composition. + +## The two other plugin shapes + +A function is the most common shape, but Cordis accepts three: + +```ts +import { Service, type Context } from 'cordis' + +// 1. Function plugin (what you just wrote). +export function apply(ctx: Context) {} + +// 2. Object plugin: an object with an `apply` method. +export const objectPlugin = { + name: 'object-plugin', + apply(ctx: Context) {}, +} + +// 3. Class plugin: a Service subclass (covered in chapter 3). +export class MyService extends Service { + constructor(ctx: Context) { + super(ctx, 'myTutorialService') + } +} +``` + +Use the function form until you need to expose a service; [chapter 3](03-services.md) covers when the class form earns its place. + +## Try breaking it + +Make `apply` throw: + +```ts ignore-check +export function apply(ctx: Context) { + throw new Error('apply exploded') +} +``` + +Run again: the process dies with your error. A plugin that fails to load is a loud failure, not a skipped entry. + +One caveat worth knowing early: a config entry whose module cannot be **resolved** — a typo'd path or package name — is reported through the Cordis logger service instead of crashing the process, and at boot that report can be lost before a console exporter is watching. If a freshly added entry seems to do nothing, check the spelling first. + +Next: [Lifecycle and effects](02-lifecycle-and-effects.md) — what happens when a plugin unloads. diff --git a/docs/cordis-tutorial/02-lifecycle-and-effects.md b/docs/cordis-tutorial/02-lifecycle-and-effects.md new file mode 100644 index 0000000000..9763c0e2e6 --- /dev/null +++ b/docs/cordis-tutorial/02-lifecycle-and-effects.md @@ -0,0 +1,89 @@ +# 2. Lifecycle and effects + +A Cordis plugin can be unloaded by a config edit, hot reload, explicit disposal, or loss of a required service. Registrations made through Cordis APIs are effects and are undone when their owning plugin unloads; resources managed outside those APIs must be wrapped in `ctx.effect()`. + +## Effects + +For a resource Cordis does not already manage — a timer, a connection, a watcher — wrap it in `ctx.effect()` and return a disposer: + +Create `lifecycle.ts` in `tmp/cordis-tutorial`: + +```ts +import type { Context } from 'cordis' + +export const name = 'lifecycle-demo' + +function heartbeat(ctx: Context) { + console.log('heartbeat plugin loading') + ctx.effect(() => { + const timer = setInterval(() => console.log('tick'), 200) + return () => { + clearInterval(timer) + console.log('heartbeat cleaned up') + } + }) +} + +export function apply(ctx: Context) { + // Mount a child plugin and keep its fiber to dispose it later. + const fiber = ctx.plugin(heartbeat) + setTimeout(async () => { + await fiber.dispose() + console.log('disposed') + process.exit(0) + }, 700) +} +``` + +Point `cordis.yml` at it: + +```yaml +- name: './lifecycle.ts' +``` + +Run (`node --import tsx ../../vendor/cordis/bin.js`) and you get: + +``` +heartbeat plugin loading +tick +tick +tick +heartbeat cleaned up +disposed +``` + +Three things to notice: + +- `ctx.plugin(heartbeat)` mounts a plugin **from code** — the same operation the YAML loader performs for each config entry. It returns a **fiber**, the runtime handle for one loaded plugin instance. +- The effect body runs during load; the disposer it returns runs during unload. You never call the disposer yourself for a plugin-lifetime resource. +- `fiber.dispose()` resolves after all of the plugin's cleanup — including async disposers — has finished, and recursively unloads any child plugins it mounted. + +## The fiber state machine + +Every loaded plugin instance owns a fiber that moves through these states: + +``` +PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED + ↘ FAILED +``` + +- **PENDING** — declared, but a required service (chapter 3) is not available yet. +- **LOADING / ACTIVE** — `apply` is running / has completed. +- **FAILED** — `apply` or config validation threw. +- **UNLOADING / DISPOSED** — disposers are running / everything is torn down. + +You will meet PENDING again in [chapter 6](06-composition-and-hmr.md), where it is the usual answer to "why does my plugin print nothing?". + +## What is already an effect + +You rarely write `ctx.effect()` yourself, because the built-in registration APIs are effects already: + +- `ctx.on(event, listener)` — the listener is removed on unload ([chapter 4](04-events.md)). +- `ctx.plugin(child)` — the child is disposed with its parent. +- Service registrations are effects. Harness registries such as `ctx.tools.register(...)` also attach their returned disposers to the calling plugin, so they unwind automatically ([chapter 7](07-into-the-harness.md)). + +For a resource Cordis does not manage, acquire it inside `ctx.effect()` and return a disposer that releases it. Cordis then invokes that release during unloading, including hot reload. + +One ordering caveat: disposers start in reverse registration order, but multiple **async** disposers run concurrently. If teardown steps must run in sequence, keep them in one disposer and await them there. + +Next: [Services](03-services.md) — how plugins share capabilities. diff --git a/docs/cordis-tutorial/03-services.md b/docs/cordis-tutorial/03-services.md new file mode 100644 index 0000000000..a3538d1a9e --- /dev/null +++ b/docs/cordis-tutorial/03-services.md @@ -0,0 +1,94 @@ +# 3. Services + +A **service** is a named capability one plugin provides and other plugins consume through `ctx`. In the harness, `ctx.tools`, `ctx.llm`, and `ctx.agents` are services. A consumer names the capability, such as `'tools'`, rather than importing its provider, so configuration can select a provider without changing the consumer. + +## Provide a service + +Create `greeter.ts` in `tmp/cordis-tutorial`: + +```ts +import { Service, type Context } from 'cordis' + +declare module 'cordis' { + interface Context { + greeter: GreeterService + } +} + +export class GreeterService extends Service { + constructor(ctx: Context) { + super(ctx, 'greeter') + } + + greet(who: string) { + return `Hello, ${who}!` + } +} + +export const name = 'greeter' + +export function apply(ctx: Context) { + ctx.plugin(GreeterService) +} +``` + +Two pieces work together: + +- **Runtime**: `super(ctx, 'greeter')` registers the instance under the name `greeter`. From then on, any plugin can reach it as `ctx.greeter`. The registration is an effect — unloading the provider removes the service. +- **Compile time**: the `declare module 'cordis'` block is TypeScript declaration merging. It adds `greeter` to the `Context` interface so `ctx.greeter` typechecks everywhere. It generates no code; without it the service still works at runtime, but consumers lose type safety. + +A `Service` subclass is itself a plugin (the class form from chapter 1), so `ctx.plugin(GreeterService)` mounts it like any other. + +## Consume a service with `inject` + +Create `consumer.ts`: + +```ts +import type { Context } from 'cordis' + +export const name = 'consumer' +export const inject = ['greeter'] + +export function apply(ctx: Context) { + console.log(ctx.greeter.greet('world')) +} +``` + +`inject` lists the services this plugin requires. Cordis holds the plugin in PENDING until every listed service exists, so inside `apply`, `ctx.greeter` is guaranteed ready. Load order in `cordis.yml` does not matter — dependencies, not file order, decide when plugins start. + +Compose and run: + +```yaml +- name: './greeter.ts' +- name: './consumer.ts' +``` + +``` +Hello, world! +``` + +Swap the two lines in `cordis.yml` and rerun: same output. Try removing `./greeter.ts` entirely: the consumer stays PENDING and prints nothing — no crash, no partial run. [Chapter 6](06-composition-and-hmr.md) shows how to diagnose that state. + +## Dependencies are live + +`inject` is not a one-shot boot check. If a required service disappears while the app runs — its provider was unloaded or hot-replaced — every dependent plugin is unloaded too, and loads again when the service returns. Combined with effects ([chapter 2](02-lifecycle-and-effects.md)), this prevents a running consumer from retaining a reference to an unavailable service: its own registrations are unwound when the dependency disappears. + +This is also why service replacement works in config: unload the `dsh-bash-local` entry, mount a different `bash` provider, and every plugin injecting `'bash'` cleanly restarts against the new implementation. + +## Optional dependencies + +`inject` is for hard requirements. For a capability the plugin can live without, skip `inject` and probe at the use site: + +```ts ignore-check +export function apply(ctx: Context) { + // undefined when no provider is loaded; the plugin still runs. + const greeter = ctx.get('greeter') + console.log(greeter?.greet('maybe') ?? 'no greeter available') +} +``` + +## Naming + +Service names live in one flat namespace per application. Prefix or namespace your own services distinctively (the harness claims plain names like `tools` and `llm`); the generated [services catalog](../cordis-catalog/services.md) lists every name the harness registers. + +Next: [Events](04-events.md) — communication without a shared service. diff --git a/docs/cordis-tutorial/04-events.md b/docs/cordis-tutorial/04-events.md new file mode 100644 index 0000000000..5646d86a0c --- /dev/null +++ b/docs/cordis-tutorial/04-events.md @@ -0,0 +1,140 @@ +# 4. Events + +Services support direct calls; **events** let a plugin announce something without knowing which plugins listen. The harness uses events for interactions such as tool results, model requests, and approval decisions. + +## Declare, emit, listen + +Create `stats.ts` in `tmp/cordis-tutorial` — a service that counts things and announces each change: + +```ts +import { Service, type Context } from 'cordis' + +declare module 'cordis' { + interface Context { + stats: StatsService + } + interface Events { + 'stats/report'(name: string, count: number): void + } +} + +export class StatsService extends Service { + private counts = new Map<string, number>() + + constructor(ctx: Context) { + super(ctx, 'stats') + } + + bump(name: string) { + const next = (this.counts.get(name) ?? 0) + 1 + this.counts.set(name, next) + this.ctx.emit('stats/report', name, next) + } +} + +export const name = 'stats' + +export function apply(ctx: Context) { + ctx.plugin(StatsService) +} +``` + +The `interface Events` merge is the event-system twin of the `interface Context` merge from chapter 3: it declares the event name and its listener signature, so `ctx.emit` and `ctx.on` are fully typed. The `namespace/action` naming convention keeps the flat event namespace readable. + +Create `reporter.ts`: + +```ts ignore-check +import type { Context } from 'cordis' +import type {} from './stats.ts' + +export const name = 'reporter' +export const inject = ['stats'] + +export function apply(ctx: Context) { + ctx.on('stats/report', (name, count) => { + console.log(`[stats] ${name} -> ${count}`) + }) + ctx.stats.bump('tool_call') + ctx.stats.bump('tool_call') + ctx.stats.bump('prompt') +} +``` + +The `import type {} from './stats.ts'` line imports nothing at runtime; it exists so TypeScript sees the declaration merges. Compose and run: + +```yaml +- name: './stats.ts' +- name: './reporter.ts' +``` + +``` +[stats] tool_call -> 1 +[stats] tool_call -> 2 +[stats] prompt -> 1 +``` + +Because `ctx.on()` is an effect, the listener disappears with the plugin — no manual `removeListener` bookkeeping, ever. + +## Dispatch modes + +`emit` is one of five dispatch modes. Which one an event uses is part of its contract — it decides whether listeners can return values, run concurrently, or veto each other: + +| Mode | Call | Semantics | +|---|---|---| +| emit | `ctx.emit(name, ...args)` | Synchronous broadcast; returned promises and values are not awaited or collected. | +| parallel | `await ctx.parallel(name, ...args)` | All listeners run concurrently; awaited together. | +| serial | `await ctx.serial(name, ...args)` | Listeners run in order, awaited; the first non-`null`/`false`/`undefined` return wins and stops the rest. | +| bail | `ctx.bail(name, ...args)` | Synchronous version of serial. | +| waterfall | `ctx.waterfall(name, ...args, next)` | Around-middleware; see below. | + +Every harness event documents its mode in the generated [events catalog](../cordis-catalog/events.md). + +## Waterfall: transform or veto + +Waterfall is the mode that powers interception. Each listener receives the arguments plus a `next()` continuation; it can transform what `next()` returns, or refuse to call `next()` at all — the veto. Create `waterfall-demo.ts`: + +```ts +import type { Context } from 'cordis' + +declare module 'cordis' { + interface Events { + 'demo/transform'(input: string, next: () => Promise<string>): Promise<string> + } +} + +export const name = 'waterfall-demo' + +export function apply(ctx: Context) { + // Listener 1: wrap the downstream result. + ctx.on('demo/transform', async (input, next) => { + const downstream = await next() + return downstream.toUpperCase() + }) + + // Listener 2: veto when it owns the decision. + ctx.on('demo/transform', async (input, next) => { + if (input.includes('blocked')) return '** vetoed **' + return next() + }) + + void (async () => { + console.log(await ctx.waterfall('demo/transform', 'hello', async () => 'hello')) + console.log(await ctx.waterfall('demo/transform', 'blocked words', async () => 'blocked words')) + })() +} +``` + +Point `cordis.yml` at just this file and run: + +``` +HELLO +** VETOED ** +``` + +Walk through the second line: listener 1 runs first, calls `next()`, which invokes listener 2; listener 2 sees `blocked` and returns without calling `next()` — the innermost default (the function passed to `ctx.waterfall`) never runs — and listener 1 uppercases the veto message on the way out. + +The discipline that follows: **a waterfall listener that only observes or annotates must call `next()`**; returning without it is a deliberate veto. Forgetting `next()` in a logging listener silently swallows the default behavior for everyone downstream. This is important enough that it is a standing rule of this repository ([waterfall semantics](../cordis-primer.md#cordis-waterfall-semantics)). + +The harness uses waterfalls for decisions that cooperating plugins may wrap or answer: [`agent/request`](../cordis-catalog/events.md#agentrequest--waterfall) lets a plugin replace the model-call config, and [`approval/request`](../cordis-catalog/events.md#approvalrequest--waterfall) lets a policy answer instead of the user. + +Next: [Configuration](05-config.md) — plugin options from `cordis.yml`. diff --git a/docs/cordis-tutorial/05-config.md b/docs/cordis-tutorial/05-config.md new file mode 100644 index 0000000000..60ee2f719d --- /dev/null +++ b/docs/cordis-tutorial/05-config.md @@ -0,0 +1,84 @@ +# 5. Configuration + +Each `cordis.yml` entry can carry a `config` block, and the plugin declares a schema that validates it before `apply` runs. Bad config fails the load with a precise error — the plugin never starts half-configured. + +## A configurable plugin + +Create `config-demo.ts` in `tmp/cordis-tutorial`: + +```ts +import type { Context } from 'cordis' +import Schema from 'schemastery' + +export const name = 'config-demo' + +export interface Config { + greeting: string + targets: string[] +} + +export const Config: Schema<Config> = Schema.object({ + greeting: Schema.string().default('Hello'), + targets: Schema.array(String).default(['world']), +}) + +export function apply(ctx: Context, config: Config) { + for (const target of config.targets) { + console.log(`${config.greeting}, ${target}!`) + } +} +``` + +The exported `Config` is both a TypeScript interface and a runtime schema with the same name — consumers get the type, Cordis gets the validator. This repo uses [Schemastery](https://github.com/shigma/schemastery) for schemas; Cordis itself accepts any [Standard Schema](https://standardschema.dev/) validator, so a plain object exported as `Config` will not work. + +Configure it: + +```yaml +- name: './config-demo.ts' + config: + targets: ['alpha', 'beta'] +``` + +Run: + +``` +Hello, alpha! +Hello, beta! +``` + +`greeting` was omitted, so the schema default filled it in — `apply` always receives complete, validated config. + +## Fail loud + +Now feed it something invalid: + +```yaml +- name: './config-demo.ts' + config: + targets: 'not-an-array' +``` + +``` +ValidationError: invalid config: + - $.targets expected array but got not-an-array (at targets) +``` + +The plugin's fiber goes to FAILED, and this tutorial's launcher exits with status 1 after printing the error. A plugin should also reject schema-valid config that names an unavailable resource or provider as soon as it can resolve that reference. + +## What belongs in config + +The harness convention, useful for any Cordis app: **anything two deployments may want to set differently is a config field**, not a constant in the plugin. Timeouts, model ids, directory roots, thresholds — the test is whether `cordis.yml` can change the value without a code edit. Compare `timeoutMs` on [`dsh-bash-local`](../../packages/bash/bash-local/src/index.ts) in the [headless example](../../examples/headless-agent/cordis.yml). + +## Computed config values + +The loader used in this repo supports a `!!js` tag for config values that must be computed at load time, such as reading an API key from the environment: + +```yaml +- name: '@deepseek-ai/dsh-llm-deepseek' + config: + apiKey: !!js process.env.DEEPSEEK_API_KEY +``` + +`!!js` works **only inside `config`**. Entry metadata (`name`, `id`, `disabled`, `inject`, ...) is static; `disabled: !!js ...` produces a truthy expression object that always disables the entry. See [loader configuration](../cordis-primer.md#loader-configuration). + +Next: [Composition and HMR](06-composition-and-hmr.md) — treating `cordis.yml` as the application. diff --git a/docs/cordis-tutorial/06-composition-and-hmr.md b/docs/cordis-tutorial/06-composition-and-hmr.md new file mode 100644 index 0000000000..8e7be022c3 --- /dev/null +++ b/docs/cordis-tutorial/06-composition-and-hmr.md @@ -0,0 +1,105 @@ +# 6. Composition and HMR + +Every capability built so far is a plugin, and `cordis.yml` selects the application's plugin tree. This chapter changes that composition, hot-reloads a plugin, and diagnoses a plugin that never loads. + +## Entries are more than a name + +A config entry accepts metadata beyond `name` and `config`: + +```yaml +- id: greeter # stable identity for this entry + name: './greeter.ts' +- id: consumer + name: './consumer.ts' + disabled: true # keep the entry, skip mounting it +``` + +`id` gives the entry a stable identity so the loader can tell an edit to an existing entry apart from a removal plus an addition. `disabled: true` unmounts a plugin without deleting its entry — flip it back and the plugin (and everything PENDING on its services) loads again. + +Groups nest a sub-list of entries that load and unload as one unit, and `isolate` gives a group its own instance of a service name — two groups can each see a differently-configured `bash` without affecting each other. Those are worth knowing about before you need them; the [Cordis primer](../cordis-primer.md) and the [service isolation example](../user/develop/framework/service.md#service-isolation) cover the details. + +## Hot module replacement + +Because unloading releases effects ([chapter 2](02-lifecycle-and-effects.md)) and loading follows dependencies ([chapter 3](03-services.md)), HMR can replace a running plugin by unloading and loading it. The `@cordisjs/plugin-hmr` plugin watches your files and does exactly that on save. + +In `tmp/cordis-tutorial`, write `cordis.yml`: + +```yaml +- name: '@cordisjs/plugin-logger-console' +- name: '@cordisjs/plugin-timer' +- name: '@cordisjs/plugin-hmr' + config: + root: ['.'] +- name: './hello.ts' +``` + +Two support plugins joined the list: HMR logs through the Cordis logger service, so without a console exporter you would not see its messages, and it `inject`s the `timer` service for debouncing — without `@cordisjs/plugin-timer` it sits in PENDING forever, silently. That silence is the subject of the next section. + +HMR also needs Node's loader internals: + +```sh +node --expose-internals --import tsx ../../vendor/cordis/bin.js +``` + +Now edit `hello.ts` — change the log message — and save: + +``` +hello from my first plugin +2026-07-22 15:44:36 [I] hmr watching [ '.' ] +2026-07-22 15:44:39 [I] hmr reload plugin at hello.ts +hello from my EDITED plugin +``` + +The old instance unloaded (all its effects unwound), the new code loaded, `apply` ran again. Stop the process with Ctrl-C. Editing `cordis.yml` itself is also picked up: the loader diffs entries by `id` and mounts, unmounts, or reconfigures only what changed. + +## Diagnosing a plugin that never loads + +The flip side of dependency-driven loading: a plugin whose `inject` names a service nobody provides waits forever, printing nothing. No error — PENDING is a legitimate state, since the provider may be mounted later. + +You can see the states directly. Every context can enumerate the plugin registry; create `diagnose.ts`: + +```ts +import { FiberState, type Context } from 'cordis' + +export const name = 'diagnose' + +export function apply(ctx: Context) { + setTimeout(() => { + for (const runtime of ctx.registry.values()) { + for (const fiber of runtime.fibers) { + if (fiber.state === FiberState.PENDING) { + console.log(`${fiber.name} is PENDING — a required service is missing`) + } + } + } + }, 500) +} +``` + +And a plugin with an unsatisfiable dependency, `needs-timer.ts`: + +```ts +import type { Context } from 'cordis' + +export const name = 'needs-timer' +export const inject = ['timer'] + +export function apply(ctx: Context) { + console.log('needs-timer loaded') +} +``` + +```yaml +- name: './needs-timer.ts' +- name: './diagnose.ts' +``` + +Run it (plain `node --import tsx ../../vendor/cordis/bin.js`; stop with Ctrl-C): + +``` +needs-timer is PENDING — a required service is missing +``` + +`inject: ['timer']` has no provider. Add `- name: '@cordisjs/plugin-timer'` to the list and the plugin loads. When a plugin does nothing and reports nothing, inspect its fiber state. Iterating without the PENDING filter also shows the loader's own plugins (Loader, Include) as ACTIVE fibers because plugins mount the config file itself. + +Next: [Into the harness](07-into-the-harness.md) — the same patterns against real harness services. diff --git a/docs/cordis-tutorial/07-into-the-harness.md b/docs/cordis-tutorial/07-into-the-harness.md new file mode 100644 index 0000000000..8b3f8dc893 --- /dev/null +++ b/docs/cordis-tutorial/07-into-the-harness.md @@ -0,0 +1,101 @@ +# 7. Into the harness + +This chapter registers a model-callable tool with the harness's `tools` service, executes it through the harness tool pipeline, and observes the result event. It remains keyless and does not call a model. + +## A tool plugin + +Create `greet-tool.ts` in `tmp/cordis-tutorial`: + +```ts +import type { Context } from 'cordis' +import { defineTool } from '@deepseek-ai/dsh-tools' +import { CallId } from '@deepseek-ai/dsh-llm' + +export const name = 'greet-tool' +export const inject = ['tools'] + +export function apply(ctx: Context) { + ctx.tools.register(defineTool({ + name: 'greet', + description: 'Greet the named person.', + parameters: { + name: { type: 'string', required: true, description: 'Who to greet' }, + }, + async execute(args) { + return [{ type: 'text', text: `Hello, ${args.name}!` }] + }, + })) + + // Drive one call through the real execution pipeline, standing in for + // the model. CallId brands the correlation id a provider would issue. + void (async () => { + const result = await ctx.tools.execute({ + callId: CallId('demo-1'), + name: 'greet', + arguments: { name: 'Cordis' }, + signal: new AbortController().signal, + }) + console.log('tool replied:', JSON.stringify(result.content)) + })() +} +``` + +Every pattern here is from the earlier chapters: `inject: ['tools']` ([chapter 3](03-services.md)) holds the plugin until the tool registry exists; `ctx.tools.register(...)` attaches the registration disposer to the plugin ([chapter 2](02-lifecycle-and-effects.md)), so unloading unregisters the tool. `defineTool` converts the `parameters` spec to the JSON Schema shown to the model, infers the type of `args`, and validates model-supplied arguments before `execute` runs. + +## An observer plugin + +Create `tool-logger.ts` — a separate plugin that watches every tool call in the app through the harness's `tools/result` event: + +```ts +import type { Context } from 'cordis' +import type {} from '@deepseek-ai/dsh-tools' + +export const name = 'tool-logger' +export const inject = ['tools'] + +export function apply(ctx: Context) { + ctx.on('tools/result', (exec, result) => { + const text = result.content + .map(block => (block.type === 'text' ? block.text : '')) + .join('') + console.log(`[tool-logger] ${exec.name} -> ${text}`) + }) +} +``` + +The `import type {} from '@deepseek-ai/dsh-tools'` line pulls in the package's declaration merges so `'tools/result'` and its payload are typed — the same move as chapter 4's `stats.ts` import, at package scale. + +## Compose and run + +```yaml +- name: '@deepseek-ai/dsh-system-prompt' +- name: '@deepseek-ai/dsh-tools' +- name: './tool-logger.ts' +- name: './greet-tool.ts' +``` + +`@deepseek-ai/dsh-tools` injects the `systemPrompt` service because tools contribute schemas to the system prompt, so the composition lists its provider too. Without it, the tools plugin remains PENDING as described in [chapter 6](06-composition-and-hmr.md). + +```sh +node --import tsx ../../vendor/cordis/bin.js +``` + +``` +[tool-logger] greet -> Hello, Cordis! +tool replied: [{"type":"text","text":"Hello, Cordis!"}] +``` + +The logger fired first: `tools/result` is emitted as part of result materialization, before `execute`'s promise resolves to the caller. Neither of your plugins knows the other exists — the registry service and the event connect them. + +## From here to a full agent + +A real agent is this composition plus more plugins: an LLM adapter, the agent loop, persistence, a front end. Compare [examples/headless-agent/cordis.yml](../../examples/headless-agent/cordis.yml) — you can read every entry in it now. Add your `greet-tool.ts` to a copy of that file and, with a `DEEPSEEK_API_KEY` in the root `.env`, the model can actually call your tool. + +Where to go next: + +- [Build a tool](../user/develop/basic/tool.md) — more of `defineTool`, including presentation and richer schemas. +- [Three-layer capability design](../user/develop/practice/index.md) — how the harness structures replaceable capabilities. +- The generated [services](../cordis-catalog/services.md) and [events](../cordis-catalog/events.md) catalogs — everything you can inject and listen to. +- [Architecture](../architecture.md) — the system map these plugins live in. + +[![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-harness/deepseek-harness) diff --git a/docs/cordis-tutorial/index.md b/docs/cordis-tutorial/index.md new file mode 100644 index 0000000000..243926f812 --- /dev/null +++ b/docs/cordis-tutorial/index.md @@ -0,0 +1,54 @@ +# Cordis tutorial + +Cordis is the plugin framework underneath the DeepSeek Harness SDK: a small runtime where every capability — tools, LLM adapters, file access, the agent loop itself — is a plugin mounted into a shared context. This tutorial teaches Cordis hands-on: each chapter is a runnable example you build in a scratch directory inside this repository, ending with a plugin wired into real harness services. + +The audience is agent developers. You do not need deep TypeScript experience; the [TypeScript notes](#typescript-notes) below explain the syntax that may be unfamiliar, and every chapter shows the exact commands and expected output. + +If you want the condensed concept reference instead of a walkthrough, read the [Cordis primer](../cordis-primer.md). The exhaustive API reference lives in the generated [events](../cordis-catalog/events.md) and [services](../cordis-catalog/services.md) catalogs and the [Cordis core API](../cordis-catalog/core/context.md) pages. + +## Setup + +You need a clone of this repository with dependencies installed — the [quick start](../user/guide/quickstart.md) covers prerequisites. No API key is needed for this tutorial; every example runs keylessly. + +```sh +git clone https://github.com/deepseek-harness/deepseek-harness.git +cd deepseek-harness +pnpm install +``` + +Create the scratch directory the chapters work in. `tmp/` is gitignored, so nothing you write there touches version control: + +```sh +mkdir -p tmp/cordis-tutorial +cd tmp/cordis-tutorial +``` + +Every chapter runs the same command from this directory: + +```sh +node --import tsx ../../vendor/cordis/bin.js +``` + +That one-file launcher (see [vendor/cordis/bin.js](../../vendor/cordis/bin.js)) creates a root `Context`, mounts the Loader plugin, and tells it to load `./cordis.yml` from the current directory. Everything else — which plugins exist, how they are configured — comes from that YAML file, which you will write in a moment. The `--import tsx` flag lets Node run the TypeScript files the config points at without a build step. + +## Chapters + +1. [Your first plugin](01-first-plugin.md) — a plugin is a function; the loader mounts it. +2. [Lifecycle and effects](02-lifecycle-and-effects.md) — Cordis-managed registrations are undone when their plugin unloads. +3. [Services](03-services.md) — expose a capability on `ctx` and depend on it with `inject`. +4. [Events](04-events.md) — typed events, broadcast dispatch, and the waterfall veto. +5. [Configuration](05-config.md) — validated config from `cordis.yml`, failing loud on bad input. +6. [Composition and HMR](06-composition-and-hmr.md) — the config file as a plugin tree, hot reload, and diagnosing a plugin that never loads. +7. [Into the harness](07-into-the-harness.md) — register a model-callable tool against real harness services. + +## TypeScript notes + +The examples use three TypeScript features beyond ordinary modern JavaScript: + +- **Type annotations** describe values without changing runtime behavior: `ctx: Context` says that `ctx` has the Cordis context API, `who: string` accepts text, and `string[]` means an array of strings. +- **`import type { Context } from 'cordis'`** imports only type information. It vanishes at runtime, so a plugin file that needs `Context` solely for annotations adds no runtime dependency. +- **Declaration merging** (`declare module 'cordis' { ... }`) adds your entries to interfaces that Cordis already declares — for example the type of a new `ctx.greeter` property or event name. It generates no runtime wiring; the plugin separately provides the service or emits the event. Chapter 3 shows the pattern in full. + +Chapter 5 also uses an `interface` to describe a configuration object's fields and a generic type such as `Schema<Config>` to say which object shape a schema validates. You can copy those declarations as shown; the surrounding text explains what each one connects. + +[![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-harness/deepseek-harness) diff --git a/website/.vitepress/config.ts b/website/.vitepress/config.ts index 3ea513a0bb..da3892eaa2 100644 --- a/website/.vitepress/config.ts +++ b/website/.vitepress/config.ts @@ -13,6 +13,7 @@ const sectionOrder = [ '基础', '框架能力', '实战', + 'Cordis 教程', '概念', '生成参考', 'Cordis API', @@ -22,6 +23,7 @@ const sectionOrder = [ 'Basics', 'Framework', 'Practice', + 'Cordis tutorial', 'Concepts', 'Generated reference', 'Cordis Core API', diff --git a/website/docs.ts b/website/docs.ts index 528fa36110..8094f342aa 100644 --- a/website/docs.ts +++ b/website/docs.ts @@ -206,6 +206,26 @@ const develop = pairedPages([ }, ]) +const cordisTutorial = mirroredPages(([ + ['index.md', 'Cordis 教程', 'Cordis tutorial'], + ['01-first-plugin.md', '1. 第一个插件', '1. Your first plugin'], + ['02-lifecycle-and-effects.md', '2. 生命周期与副作用', '2. Lifecycle and effects'], + ['03-services.md', '3. 服务', '3. Services'], + ['04-events.md', '4. 事件', '4. Events'], + ['05-config.md', '5. 配置', '5. Configuration'], + ['06-composition-and-hmr.md', '6. 组合与热重载', '6. Composition and HMR'], + ['07-into-the-harness.md', '7. 进入 Harness', '7. Into the harness'], +] as const).map(([file, rootLabel, enLabel], order): MirroredPage => ({ + source: `docs/cordis-tutorial/${file}`, + route: `develop/cordis-tutorial/${file}`, + contentLocale: 'en-US', + label: { root: rootLabel, en: enLabel }, + sidebar: { root: 'zh-develop', en: 'en-develop' }, + section: { root: 'Cordis 教程', en: 'Cordis tutorial' }, + order, + ...(file === 'index.md' ? { sourceAliases: ['docs/cordis-tutorial'] } : {}), +}))) + const reference = mirroredPages([ ...([ ['docs/architecture.md', 'reference/index.md', '架构', 'Architecture'], @@ -301,5 +321,6 @@ const reference = mirroredPages([ export const docsPages: DocsPage[] = [ ...homeAndGuide, ...develop, + ...cordisTutorial, ...reference, ] From 1628f5028350d2903443d49d80a9c089b14ddb18 Mon Sep 17 00:00:00 2001 From: Turtle <turtle1999@deepseek.com> Date: Wed, 22 Jul 2026 17:07:15 +0800 Subject: [PATCH 066/368] docs(cordis-tutorial): clarify ctx.plugin function form; add dsh badge to every chapter --- docs/cordis-tutorial/01-first-plugin.md | 2 ++ docs/cordis-tutorial/02-lifecycle-and-effects.md | 4 +++- docs/cordis-tutorial/03-services.md | 2 ++ docs/cordis-tutorial/04-events.md | 2 ++ docs/cordis-tutorial/05-config.md | 2 ++ docs/cordis-tutorial/06-composition-and-hmr.md | 2 ++ 6 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/cordis-tutorial/01-first-plugin.md b/docs/cordis-tutorial/01-first-plugin.md index 468683a71d..cd4f060b03 100644 --- a/docs/cordis-tutorial/01-first-plugin.md +++ b/docs/cordis-tutorial/01-first-plugin.md @@ -89,3 +89,5 @@ Run again: the process dies with your error. A plugin that fails to load is a lo One caveat worth knowing early: a config entry whose module cannot be **resolved** — a typo'd path or package name — is reported through the Cordis logger service instead of crashing the process, and at boot that report can be lost before a console exporter is watching. If a freshly added entry seems to do nothing, check the spelling first. Next: [Lifecycle and effects](02-lifecycle-and-effects.md) — what happens when a plugin unloads. + +[![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-harness/deepseek-harness) diff --git a/docs/cordis-tutorial/02-lifecycle-and-effects.md b/docs/cordis-tutorial/02-lifecycle-and-effects.md index 9763c0e2e6..4f3534a0eb 100644 --- a/docs/cordis-tutorial/02-lifecycle-and-effects.md +++ b/docs/cordis-tutorial/02-lifecycle-and-effects.md @@ -54,7 +54,7 @@ disposed Three things to notice: -- `ctx.plugin(heartbeat)` mounts a plugin **from code** — the same operation the YAML loader performs for each config entry. It returns a **fiber**, the runtime handle for one loaded plugin instance. +- `ctx.plugin(heartbeat)` mounts a function **from code** as a plugin — the same operation the YAML loader performs for each config entry. A function plugin needs no `apply` method: Cordis calls the function directly and uses its name only for diagnostics. An `apply` method is required only for the object form, `ctx.plugin({ apply(ctx) { /* ... */ } })`. The call returns a **fiber**, the runtime handle for one loaded plugin instance. - The effect body runs during load; the disposer it returns runs during unload. You never call the disposer yourself for a plugin-lifetime resource. - `fiber.dispose()` resolves after all of the plugin's cleanup — including async disposers — has finished, and recursively unloads any child plugins it mounted. @@ -87,3 +87,5 @@ For a resource Cordis does not manage, acquire it inside `ctx.effect()` and retu One ordering caveat: disposers start in reverse registration order, but multiple **async** disposers run concurrently. If teardown steps must run in sequence, keep them in one disposer and await them there. Next: [Services](03-services.md) — how plugins share capabilities. + +[![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-harness/deepseek-harness) diff --git a/docs/cordis-tutorial/03-services.md b/docs/cordis-tutorial/03-services.md index a3538d1a9e..4915b59d48 100644 --- a/docs/cordis-tutorial/03-services.md +++ b/docs/cordis-tutorial/03-services.md @@ -92,3 +92,5 @@ export function apply(ctx: Context) { Service names live in one flat namespace per application. Prefix or namespace your own services distinctively (the harness claims plain names like `tools` and `llm`); the generated [services catalog](../cordis-catalog/services.md) lists every name the harness registers. Next: [Events](04-events.md) — communication without a shared service. + +[![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-harness/deepseek-harness) diff --git a/docs/cordis-tutorial/04-events.md b/docs/cordis-tutorial/04-events.md index 5646d86a0c..fbc8eae441 100644 --- a/docs/cordis-tutorial/04-events.md +++ b/docs/cordis-tutorial/04-events.md @@ -138,3 +138,5 @@ The discipline that follows: **a waterfall listener that only observes or annota The harness uses waterfalls for decisions that cooperating plugins may wrap or answer: [`agent/request`](../cordis-catalog/events.md#agentrequest--waterfall) lets a plugin replace the model-call config, and [`approval/request`](../cordis-catalog/events.md#approvalrequest--waterfall) lets a policy answer instead of the user. Next: [Configuration](05-config.md) — plugin options from `cordis.yml`. + +[![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-harness/deepseek-harness) diff --git a/docs/cordis-tutorial/05-config.md b/docs/cordis-tutorial/05-config.md index 60ee2f719d..3716c2d5e5 100644 --- a/docs/cordis-tutorial/05-config.md +++ b/docs/cordis-tutorial/05-config.md @@ -82,3 +82,5 @@ The loader used in this repo supports a `!!js` tag for config values that must b `!!js` works **only inside `config`**. Entry metadata (`name`, `id`, `disabled`, `inject`, ...) is static; `disabled: !!js ...` produces a truthy expression object that always disables the entry. See [loader configuration](../cordis-primer.md#loader-configuration). Next: [Composition and HMR](06-composition-and-hmr.md) — treating `cordis.yml` as the application. + +[![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-harness/deepseek-harness) diff --git a/docs/cordis-tutorial/06-composition-and-hmr.md b/docs/cordis-tutorial/06-composition-and-hmr.md index 8e7be022c3..dd5020db0a 100644 --- a/docs/cordis-tutorial/06-composition-and-hmr.md +++ b/docs/cordis-tutorial/06-composition-and-hmr.md @@ -103,3 +103,5 @@ needs-timer is PENDING — a required service is missing `inject: ['timer']` has no provider. Add `- name: '@cordisjs/plugin-timer'` to the list and the plugin loads. When a plugin does nothing and reports nothing, inspect its fiber state. Iterating without the PENDING filter also shows the loader's own plugins (Loader, Include) as ACTIVE fibers because plugins mount the config file itself. Next: [Into the harness](07-into-the-harness.md) — the same patterns against real harness services. + +[![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-harness/deepseek-harness) From bbcc8faa95b092cada91b3881cb8ed891ca9d5d5 Mon Sep 17 00:00:00 2001 From: Turtle <turtle1999@deepseek.com> Date: Wed, 22 Jul 2026 17:19:46 +0800 Subject: [PATCH 067/368] docs(cordis-tutorial): note PENDING fibers do not keep Node alive --- docs/cordis-tutorial/03-services.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cordis-tutorial/03-services.md b/docs/cordis-tutorial/03-services.md index 4915b59d48..4bf32e81da 100644 --- a/docs/cordis-tutorial/03-services.md +++ b/docs/cordis-tutorial/03-services.md @@ -67,7 +67,7 @@ Compose and run: Hello, world! ``` -Swap the two lines in `cordis.yml` and rerun: same output. Try removing `./greeter.ts` entirely: the consumer stays PENDING and prints nothing — no crash, no partial run. [Chapter 6](06-composition-and-hmr.md) shows how to diagnose that state. +Swap the two lines in `cordis.yml` and rerun: same output. Try removing `./greeter.ts` entirely: the consumer stays PENDING and prints nothing — no crash, no partial run. A PENDING fiber does not keep Node's event loop alive either, so a composition with nothing else running exits 0 silently. [Chapter 6](06-composition-and-hmr.md) shows how to diagnose that state. ## Dependencies are live From 1df244507254354db9b45da80becd023fc9f642e Mon Sep 17 00:00:00 2001 From: Turtle <turtle1999@deepseek.com> Date: Wed, 22 Jul 2026 17:24:03 +0800 Subject: [PATCH 068/368] docs(cordis-tutorial): rename 'Dependencies are live' heading to state the mechanism --- docs/cordis-tutorial/03-services.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cordis-tutorial/03-services.md b/docs/cordis-tutorial/03-services.md index 4bf32e81da..9f62003e99 100644 --- a/docs/cordis-tutorial/03-services.md +++ b/docs/cordis-tutorial/03-services.md @@ -69,7 +69,7 @@ Hello, world! Swap the two lines in `cordis.yml` and rerun: same output. Try removing `./greeter.ts` entirely: the consumer stays PENDING and prints nothing — no crash, no partial run. A PENDING fiber does not keep Node's event loop alive either, so a composition with nothing else running exits 0 silently. [Chapter 6](06-composition-and-hmr.md) shows how to diagnose that state. -## Dependencies are live +## Dependencies are tracked after load `inject` is not a one-shot boot check. If a required service disappears while the app runs — its provider was unloaded or hot-replaced — every dependent plugin is unloaded too, and loads again when the service returns. Combined with effects ([chapter 2](02-lifecycle-and-effects.md)), this prevents a running consumer from retaining a reference to an unavailable service: its own registrations are unwound when the dependency disappears. From 484b5f5a06cfc459a2ff798782c78ba25b7ff0a3 Mon Sep 17 00:00:00 2001 From: Turtle <turtle1999@deepseek.com> Date: Wed, 22 Jul 2026 17:44:31 +0800 Subject: [PATCH 069/368] docs(cordis-tutorial): say short-circuit instead of veto --- docs/cordis-tutorial/04-events.md | 16 ++++++++-------- docs/cordis-tutorial/index.md | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/cordis-tutorial/04-events.md b/docs/cordis-tutorial/04-events.md index fbc8eae441..4c14ba5313 100644 --- a/docs/cordis-tutorial/04-events.md +++ b/docs/cordis-tutorial/04-events.md @@ -77,7 +77,7 @@ Because `ctx.on()` is an effect, the listener disappears with the plugin — no ## Dispatch modes -`emit` is one of five dispatch modes. Which one an event uses is part of its contract — it decides whether listeners can return values, run concurrently, or veto each other: +`emit` is one of five dispatch modes. Which one an event uses is part of its contract — it decides whether listeners can return values, run concurrently, or short-circuit each other: | Mode | Call | Semantics | |---|---|---| @@ -89,9 +89,9 @@ Because `ctx.on()` is an effect, the listener disappears with the plugin — no Every harness event documents its mode in the generated [events catalog](../cordis-catalog/events.md). -## Waterfall: transform or veto +## Waterfall: transform or short-circuit -Waterfall is the mode that powers interception. Each listener receives the arguments plus a `next()` continuation; it can transform what `next()` returns, or refuse to call `next()` at all — the veto. Create `waterfall-demo.ts`: +Waterfall is the mode that powers interception. Each listener receives the arguments plus a `next()` continuation; it can transform what `next()` returns, or return without calling `next()` and short-circuit the rest of the chain — what the Cordis docs call the veto. Create `waterfall-demo.ts`: ```ts import type { Context } from 'cordis' @@ -111,9 +111,9 @@ export function apply(ctx: Context) { return downstream.toUpperCase() }) - // Listener 2: veto when it owns the decision. + // Listener 2: short-circuit when it owns the decision. ctx.on('demo/transform', async (input, next) => { - if (input.includes('blocked')) return '** vetoed **' + if (input.includes('blocked')) return '** blocked **' return next() }) @@ -128,12 +128,12 @@ Point `cordis.yml` at just this file and run: ``` HELLO -** VETOED ** +** BLOCKED ** ``` -Walk through the second line: listener 1 runs first, calls `next()`, which invokes listener 2; listener 2 sees `blocked` and returns without calling `next()` — the innermost default (the function passed to `ctx.waterfall`) never runs — and listener 1 uppercases the veto message on the way out. +Walk through the second line: listener 1 runs first, calls `next()`, which invokes listener 2; listener 2 sees `blocked` and returns without calling `next()` — the innermost default (the function passed to `ctx.waterfall`) never runs — and listener 1 uppercases the replacement message on the way out. -The discipline that follows: **a waterfall listener that only observes or annotates must call `next()`**; returning without it is a deliberate veto. Forgetting `next()` in a logging listener silently swallows the default behavior for everyone downstream. This is important enough that it is a standing rule of this repository ([waterfall semantics](../cordis-primer.md#cordis-waterfall-semantics)). +The discipline that follows: **a waterfall listener that only observes or annotates must call `next()`**; returning without it is a deliberate short-circuit. Forgetting `next()` in a logging listener silently swallows the default behavior for everyone downstream. This is important enough that it is a standing rule of this repository ([waterfall semantics](../cordis-primer.md#cordis-waterfall-semantics)). The harness uses waterfalls for decisions that cooperating plugins may wrap or answer: [`agent/request`](../cordis-catalog/events.md#agentrequest--waterfall) lets a plugin replace the model-call config, and [`approval/request`](../cordis-catalog/events.md#approvalrequest--waterfall) lets a policy answer instead of the user. diff --git a/docs/cordis-tutorial/index.md b/docs/cordis-tutorial/index.md index 243926f812..9cf3966117 100644 --- a/docs/cordis-tutorial/index.md +++ b/docs/cordis-tutorial/index.md @@ -36,7 +36,7 @@ That one-file launcher (see [vendor/cordis/bin.js](../../vendor/cordis/bin.js)) 1. [Your first plugin](01-first-plugin.md) — a plugin is a function; the loader mounts it. 2. [Lifecycle and effects](02-lifecycle-and-effects.md) — Cordis-managed registrations are undone when their plugin unloads. 3. [Services](03-services.md) — expose a capability on `ctx` and depend on it with `inject`. -4. [Events](04-events.md) — typed events, broadcast dispatch, and the waterfall veto. +4. [Events](04-events.md) — typed events, broadcast dispatch, and the waterfall short-circuit. 5. [Configuration](05-config.md) — validated config from `cordis.yml`, failing loud on bad input. 6. [Composition and HMR](06-composition-and-hmr.md) — the config file as a plugin tree, hot reload, and diagnosing a plugin that never loads. 7. [Into the harness](07-into-the-harness.md) — register a model-callable tool against real harness services. From 55af920defaa3b5f845a91dab8c2b3d464e4801d Mon Sep 17 00:00:00 2001 From: Turtle <turtle1999@deepseek.com> Date: Wed, 22 Jul 2026 17:36:57 +0800 Subject: [PATCH 070/368] fix(vendor/include): keep config reloads resilient --- ...-20-config-hot-reload-resilience.i18n.yaml | 6 + ...2026-07-20-config-hot-reload-resilience.md | 38 ++++++ ...6-07-20-config-hot-reload-resilience.zh.md | 38 ++++++ ...26-07-20-dsh-cli-personal-config.i18n.yaml | 4 +- .../2026-07-20-dsh-cli-personal-config.md | 2 + .../2026-07-20-dsh-cli-personal-config.zh.md | 2 + .../2026-07-21-tui-reload-command.i18n.yaml | 4 +- .../feature/2026-07-21-tui-reload-command.md | 6 +- .../2026-07-21-tui-reload-command.zh.md | 6 +- .../ui/app-boot/tests/config-reload.spec.ts | 128 ++++++++++++++++++ vendor/README.md | 1 + vendor/include/src/index.ts | 63 +++++++-- 12 files changed, 274 insertions(+), 24 deletions(-) create mode 100644 .agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.i18n.yaml create mode 100644 .agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.md create mode 100644 .agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.zh.md create mode 100644 packages/ui/app-boot/tests/config-reload.spec.ts diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.i18n.yaml new file mode 100644 index 0000000000..b16ef70d7c --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-20-config-hot-reload-resilience.md: 1a8e29c603ede50b60199e9151fca58dadcc3d40 +2026-07-20-config-hot-reload-resilience.zh.md: 6c7a421bfa84504a36d5329e13a485bf72cc6b6c diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.md b/.agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.md new file mode 100644 index 0000000000..1a8e29c603 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.md @@ -0,0 +1,38 @@ +# Agent Note: A config hot-reload must not kill or degrade a live app + +Status: implemented + +English | [中文](2026-07-20-config-hot-reload-resilience.zh.md) + +## Problem + +The demo apps mount `@cordisjs/plugin-hmr` as a leaf so a running agent picks up `cordis.yml` edits. One bad edit killed the process: `Include.refresh()` rethrew the YAML parse error, the HMR watcher awaits `refresh()` inside an async chokidar callback nobody catches, and the resulting unhandled rejection tripped `dsh-app-boot`'s fail-loud handler — `exit(1)` mid-session, losing the live TUI. Two adjacent defects made even *valid* reloads wrong: a file that parses to `undefined` (empty or mid-write truncated — editors and `sed -i` routinely produce these states) crashed the entry walk instead of reading as invalid, and a re-read never re-applied the include's `config.patches`, so any hot-reload of an overlay-based tree (Code Mode, personal overlays) silently reverted patched entries and removed inserted ones. + +## Decision + +Harden the vendored `@cordisjs/plugin-include` (logged as local modification 8 in [vendor/README.md](../../../../vendor/README.md)) rather than the callers: + +- `refresh()` awaits the whole read-and-update and catches failures, logs a warning, and keeps the last good entry tree. A hot-reload is advisory; the invariant is that no file state reachable by an editor may take the process down. +- `read()` rejects a non-array parse result with a `TypeError`, folding the `undefined`-parse case into the same "invalid file" signal, and commits `content`/`data` only after a successful parse — so reverting an edit to the exact last good content correctly reads as "unchanged". +- `refresh()` and the `internal/update` listener apply `this.applyPatches(...)` before `root.update()`, restoring parity with `[Service.init]`. `applyPatches` deep-copies the cached parse (`structuredClone`) instead of mutating it, so repeated application converges and removing a patch reverts to the file's own values. The listener uses the incoming config's `patches` and persists that config itself: it vetoes the fiber restart (children update in place), and `Fiber.update` only assigns `this.config` behind `next()`, so without the explicit assignment the next re-read would re-apply the old overlay. + +Boot-time behavior stays fail-loud and gets a sharper diagnostic: `[Service.init]` falls back to `initial` (or "config file not found") only on `ENOENT`; an existing-but-invalid file now fails with its real parse error instead of being mislabelled as absent or silently overwritten by `initial`. + +## Alternatives considered + +**Catch in the HMR watcher callback instead of `refresh()`.** Rejected: it would leave `refresh()` a trap for every other caller (the `internal/update` path shares the same tree-update logic), and it cannot fix the `undefined`-parse or patch-loss defects, which live inside the include. + +**Filter config-file rejections in `installFailLoud`.** Rejected: the fail-loud handler exists to make late load failures visible; teaching it to classify exceptions by origin would silently swallow genuine boot failures and leave the stale-`data` crash in place. + +**A PTY e2e proving the TUI survives a bad edit.** Rejected as the primary gate: the PTY smoke reads the repo's committed `cordis.yml`, so corrupting it in-place is not test-safe, and a temp copy cannot resolve the tree's bare package specifiers. The unit spec drives the exact `refresh()` entry point the watcher calls; the fix was additionally verified manually against the live TUI (bad YAML, empty file, restored file). + +## Consequences + +- A bad `cordis.yml` edit now logs `ignoring config reload at <file>` and the agent keeps running on the last good tree; the next valid edit applies normally. With no logger exporter mounted in the TUI demos the warning is currently invisible on screen — surfacing loader warnings in the TUI is deferred. +- Overlay trees survive base-file reloads with patches intact instead of silently reverting to the unpatched base. +- The vendored include diverges further from upstream; the divergence is logged in the vendor manifest and re-applies on the next sync. +- Known gap, out of scope here: the HMR watcher only handles chokidar `change` events, so editors that replace the file by rename (BSD `sed -i`, `git checkout`) do not trigger a config reload at all; and a reloaded app-entry config does not visibly restart the running TUI (pre-existing on the unmodified tree). + +## Testing + +`packages/ui/app-boot/tests/config-reload.spec.ts` boots real Loader trees against temp configs and pins: an invalid-YAML edit and an empty-file edit both resolve `refresh()` without rejection and keep the previous entry config; a subsequent valid edit applies; an overlay tree re-applies both entry patches and inserted entries on re-read; a hot-update of the include entry's own `patches` applies immediately, survives the next file re-read, and reverts cleanly when the patches are removed. The assertions fail on the unpatched vendored include. diff --git a/.agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.zh.md b/.agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.zh.md new file mode 100644 index 0000000000..6c7a421bfa --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-20-config-hot-reload-resilience.zh.md @@ -0,0 +1,38 @@ +# Agent Note: 配置热重载不得杀死或降级正在运行的应用 + +Status: implemented + +[English](2026-07-20-config-hot-reload-resilience.md) | 中文 + +## Problem + +各示例应用把 `@cordisjs/plugin-hmr` 挂载为叶子配置项,让运行中的 agent 能感知 `cordis.yml` 的编辑。一次错误的编辑就会杀死进程:`Include.refresh()` 把 YAML 解析错误原样抛出,HMR 的文件监听器在一个无人捕获的异步 chokidar 回调里 await `refresh()`,产生的未处理 rejection 触发 `dsh-app-boot` 的快速失败处理器——会话中途 `exit(1)`,正在运行的 TUI 就此丢失。另有两个相邻缺陷让*合法*的重载也出错:解析结果为 `undefined` 的文件(空文件或写入中途被截断的文件——编辑器和 `sed -i` 常态性地产生这类中间状态)会让配置项遍历直接崩溃,而不是被判定为无效文件;并且重新读取时从不重新应用 include 的 `config.patches`,因此对基于 overlay 的配置树(Code Mode、个人 overlay)做任何热重载,都会悄悄把打过补丁的配置项回退、并把插入的配置项移除。 + +## Decision + +加固 vendor 的 `@cordisjs/plugin-include`(在 [vendor/README.md](../../../../vendor/README.md) 中记录为本地修改第 8 条),而不是修改调用方: + +- `refresh()` await 整个「读取并更新」过程并捕获失败,记录一条警告,并保留上一份完好的配置树。热重载是尽力而为的;不变式是编辑器可能产生的任何文件状态都不得导致进程退出。 +- `read()` 对非数组的解析结果抛出 `TypeError`,把 `undefined` 解析结果并入同一个「无效文件」信号,并且只在解析成功后才提交 `content`/`data`——因此把编辑撤销回与上一份完好内容完全一致时,会正确地判定为「无变化」。 +- `refresh()` 与 `internal/update` 监听器在 `root.update()` 之前调用 `this.applyPatches(...)`,与 `[Service.init]` 保持一致。`applyPatches` 对缓存的解析结果做深拷贝(`structuredClone`)而不是就地修改,因此重复应用会收敛,移除补丁会回退到文件自身的值。监听器使用传入配置中的 `patches` 并自行持久化该配置:它否决 fiber 重启(子配置项就地更新),而 `Fiber.update` 只在 `next()` 之后才赋值 `this.config`,若不显式赋值,下一次重新读取会重新应用旧的 overlay。 + +启动期行为保持快速失败并获得更准确的诊断:`[Service.init]` 只在 `ENOENT` 时回退到 `initial`(或「config file not found」);存在但无效的文件现在会以真实的解析错误失败,而不是被误标为文件缺失、或被 `initial` 静默覆盖。 + +## Alternatives considered + +**在 HMR 监听回调里捕获,而不是在 `refresh()` 里。** 否决:这会让 `refresh()` 继续成为其他所有调用方的陷阱(`internal/update` 路径共享同一套树更新逻辑),而且无法修复 `undefined` 解析结果与补丁丢失这两个位于 include 内部的缺陷。 + +**在 `installFailLoud` 里过滤配置文件相关的 rejection。** 否决:快速失败处理器的存在意义就是让延迟出现的加载失败可见;教它按来源给异常分类会悄悄吞掉真正的启动失败,并且原样保留陈旧 `data` 导致的崩溃。 + +**用 PTY e2e 证明 TUI 能在错误编辑后存活。** 否决其作为主要门禁:PTY 冒烟测试读取仓库中已提交的 `cordis.yml`,就地破坏它对测试不安全,而临时副本无法解析该配置树的裸包说明符。单元测试直接驱动监听器所调用的 `refresh()` 入口;此外还对运行中的 TUI 做了人工验证(错误 YAML、空文件、恢复文件)。 + +## Consequences + +- 现在错误的 `cordis.yml` 编辑会记录 `ignoring config reload at <file>`,agent 继续运行在上一份完好的配置树上;下一次合法编辑正常生效。TUI 示例没有挂载任何日志导出器,这条警告目前不会显示在屏幕上——在 TUI 中呈现 loader 警告的工作暂缓。 +- overlay 配置树在基础文件重载后补丁保持完整,不再悄悄回退到未打补丁的基础配置。 +- vendor 的 include 与上游进一步分叉;该分叉已记录在 vendor 的 manifest 里,下次同步时重新应用。 +- 已知缺口,不在本次范围内:HMR 监听器只处理 chokidar 的 `change` 事件,因此通过重命名替换文件的编辑方式(BSD `sed -i`、`git checkout`)完全不会触发配置重载;应用配置项重载后也不会可见地重启运行中的 TUI(未修改的代码树上即已如此)。 + +## Testing + +`packages/ui/app-boot/tests/config-reload.spec.ts` 用真实 Loader 树加载临时配置并固定以下行为:无效 YAML 编辑和空文件编辑都让 `refresh()` 正常 resolve 而不产生 rejection,并保留之前的配置项配置;随后的合法编辑正常生效;overlay 配置树在重新读取时重新应用配置项补丁和插入的配置项;对 include 配置项自身 `patches` 的热更新立即生效、在下一次文件重读后依然保持、并在补丁移除后干净地回退。这些断言在未打补丁的 vendor include 上会失败。 diff --git a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.i18n.yaml index a8c9c28d58..7addc991d2 100644 --- a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.i18n.yaml @@ -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 -2026-07-20-dsh-cli-personal-config.md: e349374a6bc7fc0137bf14836469aef8bae8d49d -2026-07-20-dsh-cli-personal-config.zh.md: 88210dc386a245002de927950dab2852e40218ea +2026-07-20-dsh-cli-personal-config.md: 514bb5b12a3e04c7deaad1e8616472eed1c920e1 +2026-07-20-dsh-cli-personal-config.zh.md: 16fada82c59c8a356e6df112234e6b7565aae1bf diff --git a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.md b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.md index e349374a6b..514bb5b12a 100644 --- a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.md +++ b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.md @@ -22,6 +22,8 @@ Two coupled pieces, aligned with the `apps/` assembly tier proposed by the `dsh The PTY smoke's launcher isolates `$DSH_HOME` to a per-test directory, exactly as it already isolates `DSH_AGENTS_HOME`, so a developer's real personal overlay cannot leak into fixtures; only the dsh CLI reads personal config, so no other test launcher needed changes. +Hot-reload interplay: the include re-applies its `patches` on every config re-read (the [config hot-reload resilience Agent Note](../bug-fix/2026-07-20-config-hot-reload-resilience.md)), so a live `cordis.yml` edit keeps the personal overlay applied. + ## Alternatives considered **A standalone `bin/dsh` wrapper owning the `dsh` name.** Rejected after reading PR #443: that PR establishes `apps/cli` as the `dsh` CLI with subcommand dispatch (`web`, `-p`) and leaves the default slot unclaimed. Two competing `dsh` entrypoints would collide in `$PATH` and in product identity; claiming the default slot inside the same package shape confines the eventual merge conflict to the small dispatch chain. diff --git a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.zh.md b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.zh.md index 88210dc386..16fada82c5 100644 --- a/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-dsh-cli-personal-config.zh.md @@ -22,6 +22,8 @@ Status: implemented PTY 冒烟测试的启动器把 `$DSH_HOME` 隔离到每个测试自己的目录,与它已有的 `DSH_AGENTS_HOME` 隔离方式完全一致,开发者真实的个人 overlay 不可能泄漏进 fixture;只有 dsh CLI 读取个人配置,因此其他测试启动器无需改动。 +与热重载的交互:include 在每次配置重读时重新应用其 `patches`(见[配置热重载韧性 Agent Note](../bug-fix/2026-07-20-config-hot-reload-resilience.md)),因此运行中编辑 `cordis.yml` 后个人 overlay 仍保持生效。 + ## Alternatives considered **独立的 `bin/dsh` 包装脚本占有 `dsh` 这个名字。** 读过 PR #443 后否决:该 PR 把 `apps/cli` 确立为带子命令分发(`web`、`-p`)的 `dsh` CLI,并且默认位空缺。两个互相竞争的 `dsh` 入口会在 `$PATH` 和产品身份上冲突;在同一包形态内认领默认位,把最终的合并冲突限制在小小的分发链上。 diff --git a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.i18n.yaml b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.i18n.yaml index 321131ac96..f3fba8a006 100644 --- a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.i18n.yaml @@ -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 -2026-07-21-tui-reload-command.md: de9a5502214a610d88024730b1c0c1044a396c92 -2026-07-21-tui-reload-command.zh.md: 25d1d448459221698ca63377f8f18d05a0fa3d21 +2026-07-21-tui-reload-command.md: e5600f0ab5cd82dc556df76006fcf532d8c7d302 +2026-07-21-tui-reload-command.zh.md: 3798b0518df1c379cca808bd4af38490016567cb diff --git a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.md b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.md index de9a550221..e5600f0ab5 100644 --- a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.md +++ b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.md @@ -10,7 +10,7 @@ HMR's file watcher only reacts to in-place `change` events under its configured ## Decision -`dsh-tui` gains an **experimental, dev-only** `/reload` slash command: it walks `ctx.loader.entries()` and calls `refresh()` on every file-backed subtree (`Include`), i.e. the exact code path the HMR watcher's config-change branch drives, invoked manually and watcher-independent. Unchanged files are no-ops (content comparison in `Include.read`). +`dsh-tui` gains an **experimental, dev-only** `/reload` slash command: it walks `ctx.loader.entries()` and calls `refresh()` on every file-backed subtree (`Include`), i.e. the exact code path the HMR watcher's config-change branch drives, invoked manually and watcher-independent. Unchanged files are no-ops (content comparison in `Include.read`); invalid files warn and keep the running tree (the hot-reload-resilience contract); include `patches` — including the dsh CLI's personal overlay — re-apply on every re-read. The TUI reaches the Loader **structurally** (`ctx.loader` via a local type, not `inject`): tests and embedders run the TUI without a Loader, where `/reload` degrades to a warning notice instead of failing the mount. Module-source hot reload stays watcher-owned; `/reload` refreshes configs only. @@ -28,8 +28,8 @@ The TUI reaches the Loader **structurally** (`ctx.loader` via a local type, not - The command reports tree count and completion as transcript notices; per-file failures surface only in loader logs, which the TUI does not display — acceptable for a dev-only surface, noted in the completion message. - A re-entrancy guard serializes reloads: `/reload` while one is in flight is refused with a warning, keeping the loader's unmutexed tree-update pass single-writer; the guard releases on completion or failure. - `/reload` runs only while the agent is idle: a reload can dispose and re-mount entries, which under an active turn could tear tools or the adapter out from under in-flight calls. The check is advisory (a send can race in after it) but removes the common footgun. -- If any `refresh()` rejects, the command reports the failure instead of leaving an unhandled rejection. +- If `refresh()`'s never-reject contract ever changes, the command reports the failure instead of leaving an unhandled rejection. ## Testing -`packages/ui/tui/tests/tui.spec.ts` pins: `/reload` refreshes every file-backed subtree and skips plain entries (structural fake Loader), reports completion, refuses re-entry while a gated refresh is in flight and runs again after release, releases the guard on the failure arm, refuses a running agent and runs again at idle, reports a rejecting refresh, and degrades to a warning without a Loader — including mounted as a real plugin fiber, where a throwing service lookup would escape. Verified live in tmux against the real tree: a probe edit reloads successfully. +`packages/ui/tui/tests/tui.spec.ts` pins: `/reload` refreshes every file-backed subtree and skips plain entries (structural fake Loader), reports completion, refuses re-entry while a gated refresh is in flight and runs again after release, releases the guard on the failure arm, refuses a running agent and runs again at idle, reports a rejecting refresh, and degrades to a warning without a Loader — including mounted as a real plugin fiber, where a throwing service lookup would escape. Verified live in tmux against the real tree: probe edit → reload applies; invalid edit → reload keeps the running tree. diff --git a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.zh.md b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.zh.md index 25d1d44845..3798b0518d 100644 --- a/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.zh.md +++ b/.agents/notes/implemented/feature/2026-07-21-tui-reload-command.zh.md @@ -10,7 +10,7 @@ HMR 的文件监听器只对其配置根目录(示例中即配置叶子所在 ## Decision -`dsh-tui` 增加一个**实验性、仅供开发**的 `/reload` 斜杠命令:遍历 `ctx.loader.entries()`,对每个文件后端的子树(`Include`)调用 `refresh()`——即 HMR 监听器配置变更分支所走的同一条代码路径,改为手动触发、不依赖监听器。未变化的文件是无操作(`Include.read` 做内容比较)。 +`dsh-tui` 增加一个**实验性、仅供开发**的 `/reload` 斜杠命令:遍历 `ctx.loader.entries()`,对每个文件后端的子树(`Include`)调用 `refresh()`——即 HMR 监听器配置变更分支所走的同一条代码路径,改为手动触发、不依赖监听器。未变化的文件是无操作(`Include.read` 做内容比较);无效文件记录警告并保留运行中的树(热重载韧性契约);include 的 `patches`——包括 dsh CLI 的个人 overlay——在每次重读时重新应用。 TUI 以**结构方式**访问 Loader(通过局部类型访问 `ctx.loader`,而非 `inject`):测试和嵌入方在没有 Loader 的情况下运行 TUI,此时 `/reload` 退化为一条警告通知而不是挂载失败。模块源码热重载仍由监听器负责;`/reload` 只刷新配置。 @@ -28,8 +28,8 @@ TUI 以**结构方式**访问 Loader(通过局部类型访问 `ctx.loader`, - 命令以 transcript 通知报告树数量与完成;单文件失败只出现在 loader 日志里,TUI 不显示——对仅供开发的表面可以接受,完成消息中已注明。 - 重入保护串行化重载:前一次进行中时 `/reload` 会被拒绝并提示警告,使 loader 无互斥的树更新过程保持单写者;保护在完成或失败时释放。 - `/reload` 只在 agent 空闲时运行:重载可能卸载并重新挂载配置项,在活跃轮次下这会把工具或适配器从进行中的调用脚下抽掉。检查是建议性的(检查后仍可能有 send 竞争进来),但消除了常见的坑。 -- 任一 `refresh()` 若 reject,命令会报告失败而不是留下未处理的 rejection。 +- 若 `refresh()` 的永不 reject 契约将来改变,命令会报告失败而不是留下未处理的 rejection。 ## Testing -`packages/ui/tui/tests/tui.spec.ts` 固定:`/reload` 刷新每个文件后端子树并跳过普通配置项(结构化的假 Loader)、报告完成、在门控的刷新进行中拒绝重入并在释放后可再次运行、失败分支同样释放保护、拒绝运行中的 agent 并在空闲后可再次运行、报告 reject 的 refresh、无 Loader 时退化为警告——包括作为真实插件 fiber 挂载的情形,在那里会抛出的服务查找会泄露出去。已在 tmux 中对真实配置树实机验证:探针编辑后 reload 成功生效。 +`packages/ui/tui/tests/tui.spec.ts` 固定:`/reload` 刷新每个文件后端子树并跳过普通配置项(结构化的假 Loader)、报告完成、在门控的刷新进行中拒绝重入并在释放后可再次运行、失败分支同样释放保护、拒绝运行中的 agent 并在空闲后可再次运行、报告 reject 的 refresh、无 Loader 时退化为警告——包括作为真实插件 fiber 挂载的情形,在那里会抛出的服务查找会泄露出去。已在 tmux 中对真实配置树实机验证:探针编辑 → reload 生效;无效编辑 → reload 保留运行中的树。 diff --git a/packages/ui/app-boot/tests/config-reload.spec.ts b/packages/ui/app-boot/tests/config-reload.spec.ts new file mode 100644 index 0000000000..05ebe80b58 --- /dev/null +++ b/packages/ui/app-boot/tests/config-reload.spec.ts @@ -0,0 +1,128 @@ +/** + * Config hot-reload resilience of the booted include tree. `dsh-app-boot` + * installs a fail-loud unhandled-rejection handler, so a `refresh()` that + * rethrows a config-file parse error would kill a live app on one bad + * `cordis.yml` edit (the HMR watcher awaits `refresh()` in an async event + * callback nobody else catches). These tests pin the vendored + * `@cordisjs/plugin-include` contract that boot relies on: an invalid file + * keeps the last good tree, and a valid re-read re-applies overlay patches + * exactly like the initial load. + */ + +import { mkdtempSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { describe, expect, it } from 'vitest' +import type { Context } from 'cordis' +import type { Include } from '@cordisjs/plugin-include' +import { boot } from '../src/index.ts' + +const NAME = 'dsh-test-bin' + +const NOOP_PLUGIN = 'export const name = "noop"\nexport function apply() {}\n' + +interface TreeFixture { + ctx: Context + dir: string + include: Include +} + +async function bootTree(configBody: string): Promise<TreeFixture> { + const dir = mkdtempSync(join(tmpdir(), 'dsh-config-reload-')) + writeFileSync(join(dir, 'noop.mjs'), NOOP_PLUGIN) + writeFileSync(join(dir, 'cordis.yml'), configBody) + const ctx = await boot(NAME, join(dir, 'cordis.yml')) + const entry = [...ctx.loader.entries()].find(candidate => candidate.subtree !== undefined) + if (entry?.subtree === undefined) throw new Error('booted tree has no include entry') + return { ctx, dir, include: entry.subtree as Include } +} + +function entryConfig(ctx: Context, id: string): unknown { + return [...ctx.loader.entries()].find(entry => entry.options.id === id)?.options.config +} + +describe('include refresh with an invalid file', () => { + it('keeps the last good tree instead of throwing, then applies the next valid edit', async () => { + const { ctx, dir, include } = await bootTree('- id: noop\n name: ./noop.mjs\n config:\n value: 1\n') + try { + expect(entryConfig(ctx, 'noop')).toEqual({ value: 1 }) + + writeFileSync(join(dir, 'cordis.yml'), 'invalid: [unclosed\n') + await expect(include.refresh()).resolves.toBeUndefined() + expect(entryConfig(ctx, 'noop')).toEqual({ value: 1 }) + + // An empty file parses to `undefined` without a YAML error; it must be + // treated exactly like a parse failure, not crash the entry walk. + writeFileSync(join(dir, 'cordis.yml'), '') + await expect(include.refresh()).resolves.toBeUndefined() + expect(entryConfig(ctx, 'noop')).toEqual({ value: 1 }) + + writeFileSync(join(dir, 'cordis.yml'), '- id: noop\n name: ./noop.mjs\n config:\n value: 2\n') + await include.refresh() + await ctx.loader.await() + expect(entryConfig(ctx, 'noop')).toEqual({ value: 2 }) + } finally { + await ctx.fiber.dispose() + } + }) +}) + +describe('include refresh with overlay patches', () => { + it('re-applies entry patches and inserted entries on every re-read (parity with initial load)', async () => { + const dir = mkdtempSync(join(tmpdir(), 'dsh-config-reload-overlay-')) + writeFileSync(join(dir, 'noop.mjs'), NOOP_PLUGIN) + writeFileSync(join(dir, 'base.yml'), '- id: noop\n name: ./noop.mjs\n config:\n value: base\n') + writeFileSync(join(dir, 'cordis.yml'), [ + '- id: base', + " name: 'cordis:include'", + ' config:', + ' path: ./base.yml', + ' patches:', + ' - id: noop', + ' name: ./noop.mjs', + ' config:', + ' value: patched', + ' - insert:', + ' - id: extra', + ' name: ./noop.mjs', + '', + ].join('\n')) + const ctx = await boot(NAME, join(dir, 'cordis.yml')) + try { + const entry = [...ctx.loader.entries()].find(candidate => candidate.options.id === 'base') + if (entry?.subtree === undefined) throw new Error('overlay tree has no base include entry') + const include = entry.subtree as Include + expect(entryConfig(ctx, 'noop')).toEqual({ value: 'patched' }) + expect(entryConfig(ctx, 'extra')).toBeUndefined() + expect([...ctx.loader.entries()].some(candidate => candidate.options.id === 'extra')).toBe(true) + + writeFileSync(join(dir, 'base.yml'), '- id: noop\n name: ./noop.mjs\n config:\n value: edited\n') + await include.refresh() + await ctx.loader.await() + expect(entryConfig(ctx, 'noop')).toEqual({ value: 'patched' }) + expect([...ctx.loader.entries()].some(candidate => candidate.options.id === 'extra')).toBe(true) + + // Hot-update of the include entry's own config (the `internal/update` + // path): the new patches must apply now AND stick for later re-reads — + // the listener vetoes the fiber restart, so it must persist the new + // config itself or the next refresh() re-applies the old overlay. + await entry.update({ config: { path: './base.yml', patches: [{ id: 'noop', name: './noop.mjs', config: { value: 'patched-v2' } }] } }) + await ctx.loader.await() + expect(entryConfig(ctx, 'noop')).toEqual({ value: 'patched-v2' }) + expect([...ctx.loader.entries()].some(candidate => candidate.options.id === 'extra')).toBe(false) + + writeFileSync(join(dir, 'base.yml'), '- id: noop\n name: ./noop.mjs\n config:\n value: edited-2\n') + await include.refresh() + await ctx.loader.await() + expect(entryConfig(ctx, 'noop')).toEqual({ value: 'patched-v2' }) + + // Removing every patch must revert to the file's own values: patching + // may not bake earlier patch results into the cached parse. + await entry.update({ config: { path: './base.yml', patches: [] } }) + await ctx.loader.await() + expect(entryConfig(ctx, 'noop')).toEqual({ value: 'edited-2' }) + } finally { + await ctx.fiber.dispose() + } + }) +}) diff --git a/vendor/README.md b/vendor/README.md index ae43760ceb..1f4d61e6b1 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -37,6 +37,7 @@ Keep this log exhaustive — every divergence from upstream must be listed. 5. **`schemastery/tsdown.config.ts` and `logger-console/tsdown.config.ts`**: ours, not upstream files — per-package build-shape overrides (dual ESM+CJS output; separate node/browser entries) for the repo-root tsdown build. They read the JS emitted under `lib/types` and then write the publish runtime entries under `lib/`. Like the regenerated tsconfigs, they are not part of the upstream sync surface. 6. **`cordis/src/fiber.ts` lifecycle hardening**: locally closes three reentrant disposal gaps. An effect's owner-list wrapper is registered before its setup body runs, so an unload begun from inside setup awaits setup and every collected cleanup; synchronous setup failure removes the wrapper and rolls back collected cleanup. Async cleanup stays owner-visible until quiescence, and Cordis's internal effect composition joins an already-running cleanup while repeated public disposer calls retain their upstream single-shot result. Effect creation is rejected while the owner is `UNLOADING` (while `PENDING` and `LOADING` remain legal), preventing cleanup-time registrations from escaping the unload snapshot. Child fibers register and receive their parent-owned disposer before `internal/plugin` publication, resolve dependency declarations added by that notification before activation, drain effects attached while pending, skip plugin execution when reentrant disposal invalidates the load epoch before its first checkpoint, and contain teardown-notification failures per observer so one callback cannot starve peers or interrupt ownership cleanup. 7. **`cordis/src/*.ts` JSDoc enrichment**: added `@param`/`@returns` tags and contract documentation (disposal semantics, waterfall veto, bail conditions, error cases) across the public plugin-author surface — `Context` (class, statics, and the `Context` interface properties incl. `root`), `EventsService`, `Fiber`, `RegistryService`, `ReflectService`, `Service`, `LoggerService` and their `declare module './context.ts'` overloads. Comment-only; no code changes. Motivation: the website API-reference generator renders these docs and hard-errors on undocumented members. Retire this entry when the enrichment is upstreamed to the fork. +8. **`include/src/index.ts` hot-reload hardening**: `refresh()` awaits the full read-and-update and catches failures (logging a warning and keeping the last good entry tree) instead of rethrowing — upstream's throw escaped `@cordisjs/plugin-hmr`'s async watcher callback as an unhandled rejection, so one bad `cordis.yml` edit killed a live app. `read()` rejects a non-array parse result (an empty or mid-write truncated file parses to `undefined`, which upstream later crashed on) and commits `content`/`data` only on success, so reverting an edit to the exact last good content reads as "unchanged". `refresh()` and the `internal/update` listener re-apply `config.patches` before `root.update()`, matching initial load; upstream applied patches only in `[Service.init]`, so any config hot-reload silently reverted overlay-patched entries and removed inserted ones. `applyPatches` deep-copies via `structuredClone` instead of mutating the cached parse (repeated application converges; removing a patch reverts), and the veto-style `internal/update` listener persists the incoming config itself (`Fiber.update` only assigns behind `next()`), so later re-reads use the new patches. `[Service.init]` falls back to `initial` only on `ENOENT`; an existing-but-invalid file fails loud with its real parse error instead of "config file not found" (or a silent overwrite). Covered by `packages/ui/app-boot/tests/config-reload.spec.ts`. ## Sync procedure diff --git a/vendor/include/src/index.ts b/vendor/include/src/index.ts index 2258d3af06..b1517d5458 100644 --- a/vendor/include/src/index.ts +++ b/vendor/include/src/index.ts @@ -77,7 +77,15 @@ export class Include extends EntryTree { ctx.on('internal/update', (config, _, next) => { if (config.path !== this.config.path) return next() - this.root.update(this.data!) + // Veto the fiber restart (children update in place), but persist the new + // config ourselves — `Fiber.update` only assigns `this.config` behind + // `next()`, and a stale `this.config.patches` would make the next + // `refresh()` re-apply the old overlay. + this.config = config + this.root.update(this.applyPatches(this.data!, config.patches)).catch((error) => { + this.ctx.logger.warn('config update at %C failed', this.filename) + this.ctx.logger.warn(error) + }) }) } @@ -93,22 +101,37 @@ export class Include extends EntryTree { private async read(forced = false) { const content = await readFile(this.filename, 'utf8') if (!forced && this.content === content) return false - this.content = content + let data: any if (this.type === 'application/yaml') { - this.data = yaml.load(this.content, { schema }) as any + data = yaml.load(content, { schema }) } else if (this.type === 'application/json') { - this.data = JSON.parse(this.content) as any + data = JSON.parse(content) } else { const module = await import(/* @vite-ignore */ this.filename) - this.data = module.default || module + data = module.default || module } + // An empty or truncated file (common mid-edit: editors and `sed -i` write + // through temp states) parses to `undefined`, not an error; reject every + // non-array shape here so callers see one "invalid file" signal. Content + // and data commit only on success, so an edit that is later reverted to + // the exact last good content correctly reads as "unchanged". + if (!Array.isArray(data)) { + throw new TypeError(`config file must be a top-level array of entries: ${this.filename}`) + } + this.content = content + this.data = data await this.checkAccess() return true } - private applyPatches(data: EntryOptions[]): EntryOptions[] { - const { patches } = this.config - if (!patches?.length) return data + private applyPatches(data: EntryOptions[], patches = this.config.patches): EntryOptions[] { + // Always detach from the cached parse: patching shared entry objects would + // bake earlier patch values into `this.data`, so repeated application + // (config hot-reloads) could never revert a removed or changed patch. The + // supported extensions guarantee JSON-safe plain data, so `structuredClone` + // cannot throw here. + if (!patches?.length) return [...data] + data = structuredClone(data) const entryMap = new Map<string, EntryOptions>() const buildMap = (entries: EntryOptions[]) => { @@ -174,7 +197,11 @@ export class Include extends EntryTree { async* [Service.init]() { try { await this.read() - } catch { + } catch (error) { + // Only a missing file falls back to `initial` (or the not-found error): + // an existing-but-invalid file must fail loud with its real parse error, + // never be mislabelled as absent or silently overwritten. + if ((error as NodeJS.ErrnoException | null)?.code !== 'ENOENT') throw error if (this.config.initial) { this.writeFile(this.config.initial as any) await this.read() @@ -184,18 +211,26 @@ export class Include extends EntryTree { } yield () => this.stop() - const data = this.applyPatches([...this.data!]) - await this.root.update(data) + await this.root.update(this.applyPatches(this.data!)) } stop() { this.root.stop() } - /** Re-read the file and refresh child entries when content changed. */ + /** + * Re-read the file and refresh child entries when content changed. An + * unreadable or unparsable file logs a warning and keeps the last good + * tree: a hot-reload of a live app must never take the process down. + */ async refresh() { - if (!await this.read()) return - this.root.update(this.data!) + try { + if (!await this.read()) return + await this.root.update(this.applyPatches(this.data!)) + } catch (error) { + this.ctx.logger.warn('config reload at %C failed; keeping the running tree', this.filename) + this.ctx.logger.warn(error) + } } private async _writeFile(config: EntryOptions[]) { From 129549387865b8c2561fa08c2a5727bd86659ff8 Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Wed, 22 Jul 2026 03:04:38 -0700 Subject: [PATCH 071/368] docs(i18n): re-translate core batch with the prompt-v4 pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 五篇核心文档译文按 v4 基线(#348)重出:v4 模板+术语表渲染、金标 few-shot 裸文本注入、三段协议取 <final>、切换行流水线后处理;全量 机械核对(结构/切换行/术语禁项/重复括注)零异常,architecture 一处 被模型合并的列表项已按源结构拆回。 --- .worktrees/i18n-prompt-sync | 1 + docs/architecture.i18n.yaml | 2 +- docs/architecture.zh.md | 68 +++++++++++++++---------------- docs/cordis-primer.i18n.yaml | 2 +- docs/cordis-primer.zh.md | 28 ++++++------- docs/defensive-patterns.i18n.yaml | 2 +- docs/defensive-patterns.zh.md | 20 ++++----- docs/glossary.i18n.yaml | 2 +- docs/glossary.zh.md | 22 +++++----- docs/testing.i18n.yaml | 2 +- docs/testing.zh.md | 26 ++++++------ 11 files changed, 88 insertions(+), 87 deletions(-) create mode 160000 .worktrees/i18n-prompt-sync diff --git a/.worktrees/i18n-prompt-sync b/.worktrees/i18n-prompt-sync new file mode 160000 index 0000000000..7d822f3be7 --- /dev/null +++ b/.worktrees/i18n-prompt-sync @@ -0,0 +1 @@ +Subproject commit 7d822f3be7523bb5b6f3a874eed476b05ec545fd diff --git a/docs/architecture.i18n.yaml b/docs/architecture.i18n.yaml index 9ff56c00ef..eda1339fb4 100644 --- a/docs/architecture.i18n.yaml +++ b/docs/architecture.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write architecture.md: 32b9700b9aece988985ff932e597b537872f12c3 -architecture.zh.md: 1adb0111fb67c6e252153e2500732a320de44523 +architecture.zh.md: 6a4cf414da141b9d19e15d68e6b98458822b612a diff --git a/docs/architecture.zh.md b/docs/architecture.zh.md index 1adb0111fb..6a4cf414da 100644 --- a/docs/architecture.zh.md +++ b/docs/architecture.zh.md @@ -2,13 +2,13 @@ [English](architecture.md) | 中文 -**DeepSeek Harness SDK** 基于 Cordis 构建 agent harness(智能体框架)。原则很简单:**一切皆插件**。内置的循环只是一个插件,不是特权内核。 +**DeepSeek Harness SDK** 基于 Cordis 构建 agent harness(智能体框架)。原则很简单:**一切皆插件**。内置的循环只是一个插件,而非特权内核。 ## 概览 -一个 harness 就是一个 [Cordis](cordis-primer.md) 上下文。各包(package)贡献服务键、类型化事件和可 dispose(资源释放)的注册:服务暴露稳定的调用(`ctx.llm`、`ctx.tools`、`ctx.sessions`),事件提供拦截与通知(`agent/request`、`tools/pre-execute`、`session/event`),注册则安装提示词段、工具、提供方、适配器或监听器。 +一个 harness 就是一个 [Cordis](cordis-primer.md) 上下文。各包(package)贡献服务键、类型化事件和可释放的注册:服务暴露稳定调用(`ctx.llm`、`ctx.tools`、`ctx.sessions`),事件提供拦截与通知(`agent/request`、`tools/pre-execute`、`session/event`),注册则安装提示词段、工具、提供方、适配器或监听器。 -`packages/core/` 组织了默认的 agent 流程;周边能力同样是一等的 Cordis 插件。 +`packages/core/` 组织了默认的 agent 流程;周围的能力同样是一等的 Cordis 插件。 ### 默认服务 @@ -27,7 +27,7 @@ |---|---|---| | `ctx.llm` | [`llm/`](../packages/llm/README.md) | 适配器注册表与流式模型调用 | | `ctx.bash` | [`bash/`](../packages/bash/README.md) | 前台/后台命令执行 | -| `ctx.sandbox` | [`sandbox/`](../packages/sandbox/README.md) | 同世界进程隔离(argv 包装、逐调用策略) | +| `ctx.sandbox` | [`sandbox/`](../packages/sandbox/README.md) | 同世界进程隔离(argv 包装、逐次策略) | | `ctx.codeRuntime` | [`code-runtime/`](../packages/code-runtime/README.md) | 模型编写的程序执行 | | `ctx.fs` | [`fs/`](../packages/fs/README.md) | 文件系统提供方原语与策略事件 | | `ctx.skills` | [`skill/`](../packages/skill/README.md) | skill(技能)提供方注册表与渐进式披露 | @@ -36,27 +36,27 @@ | `ctx.subagents` | [`subagent/`](../packages/subagent/README.md) | 命名委托提供方 | | `ctx.workflows` | [`workflow/`](../packages/workflow/README.md) | 脚本驱动的多 agent 编排 | | `ctx.sessionPersistence` | [`session-persistence/`](../packages/session-persistence/README.md) | 会话日志的持久化存储 | -| `ctx.sessionQuery` | [`session-query/`](../packages/session-query/README.md) | 活跃优先的逻辑语料库与精确事件读取 | +| `ctx.sessionQuery` | [`session-query/`](../packages/session-query/README.md) | 优先活跃会话的逻辑语料库与精确事件读取 | ## 事件 -事件构成服务扩展 API;详见完整的[事件目录](cordis-catalog/events.md)与[生产者/消费方映射](event-producer-consumer.md)。 +事件构成服务扩展 API;详见完整的[事件目录](cordis-catalog/events.md)与[生产方/消费方映射](event-producer-consumer.md)。 ### 事件域 -- **会话事件**是持久的、可回放的事实。轮次与步骤边界、用户输入、助手输出、工具调用、工具结果、steering(中途引导)、压缩记录以及工具拥有的持久事实追加到会话日志,并流经 `session/event`。 -- **Agent 事件**携带活跃的 `Agent` 句柄,用于状态、诊断、prompt 准入、调用配置塑形、结果校验与续行策略。 -- **能力事件**归属于拥有该动作的 seam。`tools/*`、`llm/*`、`system-prompt/*`、`fs/*` 与 `subagent/*` 让策略和适配器无需导入循环即可接入。 +- **会话事件**是持久的、可回放的事实。轮次与步骤边界、用户输入、助手输出、工具调用、工具结果、steering(中途引导)、压缩记录以及工具拥有的持久事实追加到会话日志,并通过 `session/event` 流出。 +- **Agent 事件**携带活跃的 `Agent` 句柄,用于状态、诊断、提示词准入、调用配置塑形、结果校验与续行策略。 +- **能力事件**属于拥有该动作的 seam。`tools/*`、`llm/*`、`system-prompt/*`、`fs/*` 与 `subagent/*` 让策略和适配器无需导入循环即可接入。 ### 拦截语义 -waterfall(瀑布式事件)的行为类似 around 中间件:监听器通过调用 `next()` 委托下游;不调用 `next()` 直接返回即为否决或接管。完整规则见 [Cordis waterfall 语义](cordis-primer.md#cordis-waterfall-semantics)。 +waterfall(瀑布式事件)的行为类似环绕中间件:监听器通过调用 `next()` 委托下游;不调用 `next()` 直接返回则表示否决或接管。完整规则见 [Cordis waterfall 语义](cordis-primer.md#cordis-waterfall-semantics)。 ## 默认循环生命周期 -内置循环消耗工作队列、组装请求、流式接收模型回答、执行工具、应用续行策略并持久化检查点。每一个暂停点都是一个服务调用或事件,可供插件介入。 +内置循环排空工作队列、组装请求、流式接收模型回答、执行工具、应用续行策略并持久化状态检查点。每个暂停点都是一个对插件可用的服务调用或事件。 -**会话**是一个 agent 的仅追加事件日志。**轮次(turn)**消耗一批排队消息,运行到模型不再请求工具且没有插件要求续行为止。**步骤(step)**是一次模型请求加上该响应引发的工具执行。下面的流程中([时序图伴侣文档](agent-lifecycle.md)),带引号的名称是持久化的会话事件,事件名称是扩展点。 +**会话**是一个 agent 的仅追加事件日志。**轮次**排空一批排队消息,运行直到模型不再请求工具且没有插件请求续行。**步骤**是一次模型请求加上该响应引发的工具执行。下文流程([时序伴随文档](agent-lifecycle.md))中,带引号的名称是持久会话事件,事件名称是扩展点。 ### 轮次流程 @@ -96,76 +96,76 @@ forever: checkpoint persistence and notify idle/running status ``` -循环每步骤渲染一次 prompt 组装。插件贡献有序段、工具 schema 与 `{{name}}` 变量;未知或无值的引用会使轮次失败,而非带着空洞发送。`dsh-system-prompt` 拥有 harness 身份与默认部署人格;agent 作用域的人格可以遮蔽默认值。循环提供 `model` 和 `cwd`。见 [prompt 所有权 RFC](rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)。 +循环每个步骤渲染一次提示词组装。插件贡献有序段、工具 schema 和 `{{name}}` 变量;未知或无值的引用会使轮次失败,而非带着空洞发送。`dsh-system-prompt` 拥有 harness 身份与默认部署人设;agent 作用域的人设可以遮蔽默认值。循环提供 `model` 和 `cwd`。见[提示词归属 RFC](rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)。 -Post-tool 上下文在所有工具结果之后落入,以保持 tool-call/result 的邻接稳定。steering 在步骤之间排空;轮次结束后的普通剩余 steering 作为输入重新入队。终止性的 `agent/turn-stop` 是显式例外:它在普通续行与 steering 折叠之后运行,然后在轮次关闭和刷新期间保持权威,因此这些后续监听器产生的 steering 被丢弃而非成为新的步骤或轮次;普通排队的 prompt 则被保留。 +工具后上下文在所有工具结果之后追加,以保持工具调用/结果的邻接稳定。Steering 在步骤之间排空;轮次结束后的普通剩余 steering 作为输入重新入队。终止性的 `agent/turn-stop` 是显式例外:它在普通续行与 steering 折叠之后运行,然后在轮次关闭和刷新期间保持权威,使后续监听器产生的 steering 被丢弃而非变成另一个步骤或轮次;普通排队的提示词则被保留。 ### 失败边界 -轮次是容错边界。抛出异常的监听器、适配器错误结束或失败的步骤会以错误原因结束当前轮次,并通过 `agent/error` 报告实时诊断;它不会杀死驱动循环。`cancel()` 清除排队与 steering 工作,在可能时中止活跃的模型/工具边界,并记录相应的轮次结束。dispose 停止循环、等待静默、注销 agent,并让服务 disposer 排空。 +轮次是容错边界。抛出异常的监听器、适配器错误结束、或失败的步骤会以错误原因结束当前轮次,并通过 `agent/error` 报告实时诊断;它不会终止驱动循环。`cancel()` 清除排队和 steering 工作,在可能时中止活跃的模型/工具边界,并记录相应的轮次结束。dispose(资源释放)停止循环、等待静默、注销 agent,并让服务的 disposer 排空。 -每个会话事件都被轮次包围。重新加载崩溃的会话时,系统保留中断的尾部并以合成的 `interrupted` 轮次结束关闭它。持久化轮次已关闭后的失败仅通过 `agent/error` 报告,因为已没有安全的轮次内位置。轮次以一个 `TurnEndReason` 结束(`completed`、`aborted`、`error`、`disposed`、`max-tokens`、`rejected` 或 `interrupted`);各变体的语义见 [session.md § TurnEndReasonMap](core-data-structures/session.md#why-a-turn-ended-turnendreasonmap)。 +每个会话事件都被轮次包围。重新加载崩溃的会话时,中断的尾部被保留,并以合成的 `interrupted` 轮次结束关闭。持久轮次已关闭之后发生的失败仅通过 `agent/error` 报告,因为已没有安全的轮次内位置。轮次以一个 `TurnEndReason` 结束(`completed`、`aborted`、`error`、`disposed`、`max-tokens`、`rejected` 或 `interrupted`);各变体的语义见 [session.md § TurnEndReasonMap](core-data-structures/session.md#why-a-turn-ended-turnendreasonmap)。 ### Agent 句柄 -`ctx.agents` 拥有活跃 agent 并返回 `AgentHandle { agent, dispose() }`。`Agent` 是其他插件驱动的 API:`send()` 入队工作,`steer()` 注入轮次中内容,`inject()` 追加上下文并在空闲时开启一次性注入轮次,`cancel()` 是公开的停止原语,`whenIdle()` 观察静默状态。调用方 fiber 与具体工厂提供方在结构上共同拥有编程式生命周期;消费方句柄是唯一的非结构性拆卸能力,且每个所有者到达同一个被 await 的 disposer。 +`ctx.agents` 拥有活跃 agent 并返回 `AgentHandle { agent, dispose() }`。`Agent` 是其他插件驱动的 API:`send()` 入队工作,`steer()` 注入轮次中内容,`inject()` 追加上下文并在空闲时开启一次性注入轮次,`cancel()` 是公开的停止原语,`whenIdle()` 观察静默状态。调用方 fiber 与具体工厂提供方在结构上共同拥有编程式生命周期;消费方句柄是唯一的非结构性拆除能力,每个所有者到达同一个被等待的 disposer。 ### Agent 作用域 -每个活跃 agent 拥有一个作用域化的 `agent.ctx`。其注册遮蔽同名全局注册,只接收该 agent 的派发,并随 agent 一起解除。`CreateAgentOptions.setup(agentCtx)` 在发布前组合作用域。[语义门禁 RFC](rfc/implemented/process/2026-07-14-typescript-program-backed-semantic-gates.md) 定义了类型化解析器,从合并的 `Events` 签名与 `scopeTarget` 派生载体检查,消除了手写事件表。见 [agent 作用域 RFC](rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md);subagent 组合控制另行记录于[此](rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md)。 +每个活跃 agent 拥有一个作用域化的 `agent.ctx`。其注册遮蔽同名全局注册,只接收该 agent 的分发,并随 agent 一起卸载。`CreateAgentOptions.setup(agentCtx)` 在发布前组合作用域。[语义门禁 RFC](rfc/implemented/process/2026-07-14-typescript-program-backed-semantic-gates.md) 定义了类型化解析器,从合并的 `Events` 签名与 `scopeTarget` 推导载体检查,消除了手写事件表。见 [agent 作用域 RFC](rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md);subagent 组合控制另行[文档化](rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md)。 ## 状态 ### 会话日志 -会话日志是真源。`deriveMessages()` 将会话事件投影为发送给模型的 `Message[]`;原始 `assistant/chunk` 事件留在日志中用于回放和 UI 保真。回放、fork、恢复、transcript(文本记录)渲染、遥测和持久化都从同一事件流派生。 +会话日志是真源。`deriveMessages()` 将会话事件投影为发送给模型的 `Message[]`;原始 `assistant/chunk` 事件保留在日志中,用于回放和 UI 保真。回放、fork、恢复、transcript(文本记录)渲染、遥测与持久化都从同一事件流派生。 -**模型可见 ⟺ 已记录**:日志能重建每次请求——`step/start` 处的消息前置 header 的会话前缀,header 通过折叠 `request/header` 得出——开发不变式对此做断言([可重建性 RFC](rfc/implemented/architecture/2026-07-05-reconstructable-requests.md))。 +**模型可见 ⟺ 已记录**:日志重建每个请求(`step/start` 处的消息以 header 的 session prefix 为前缀,header 通过折叠 `request/header` 得出),开发不变式对此进行断言([可重建性 RFC](rfc/implemented/architecture/2026-07-05-reconstructable-requests.md))。 持久性是插件关注点。持久化后端缓冲同步的 `session/event` 通知,循环在轮次结束检查点完成后才继续。`SessionPersistence` seam 直接存储 `SessionEvent`,元数据在 `SessionHeader` 中;JSONL 与 SQLite 共享同一套契约测试。 ### 模型内容 -消息是类型化内容块(`text`、`reasoning`、`tool-call`、`tool-result`)的数组。联合类型派生自可合并扩展的 `ContentBlockMap`;同一模式也用于 `MessageSource`、`FinishReason`、`TurnTrigger` 与 `TurnEndReason`。新的块类型需要跨适配器、UI 桥接、压缩计价与持久化协调,因此块类型仍是仓库级契约。 +消息是类型化内容块的数组(`text`、`reasoning`、`tool-call`、`tool-result`)。联合类型派生自可合并扩展的 `ContentBlockMap`;同一模式也用于 `MessageSource`、`FinishReason`、`TurnTrigger` 和 `TurnEndReason`。新的块类型需要跨适配器、UI 桥接、压缩计价和持久化协调,因此块类型仍是仓库级契约。 -流式输出是原始分片协议(从 `block-start` 到 `finish`),`BlockAssembler` 是共享的 chunk 到 block 组装器。循环在组装分片以供派发的同时记录原始 chunk。`LlmAdapter` 是提供方 seam:继承它、实现 `stream()`、用 `ctx.llm.registerAdapter(models, adapter)` 注册。StreamChunk 约定见 [llm-streaming.md](core-data-structures/llm-streaming.md)。 +流式输出是原始分片协议(从 `block-start` 到 `finish`),`BlockAssembler` 是共享的分片到块组装器。循环在组装分片以供分发的同时记录原始分片。`LlmAdapter` 是提供方 seam:继承、实现 `stream()`,然后通过 `ctx.llm.registerAdapter(models, adapter)` 注册。StreamChunk 约定见 [llm-streaming.md](core-data-structures/llm-streaming.md)。 ## 扩展与组合 ### 能力模式 -一个可替换的能力通常拆分为**接口 / 实现 / 消费方**:接口拥有其 `ctx` 键与事件,实现注册后端,消费方通过工具或 prompt 暴露模型行为。Bash 是参考实现;[能力图](capability-seams.md)展示了每个族。 +一个可替换的能力通常拆分为**接口/实现/消费方**:接口拥有其 `ctx` 键和事件,实现注册后端,消费方通过工具或提示词暴露模型行为。Bash 是参考实现;[能力图](capability-seams.md)展示了每个族。 -部分 seam 有意偏离模板。LLM(大语言模型)将接口与消费方词汇放在一起,因为适配器就是实现。文件系统在提供方原语周围添加策略门禁。Web 是一个服务加搜索/抓取两个提供方注册表,因此提供方替换不会重命名模型工具。skill 与 subagent 使用命名提供方注册表;本地 skill 扫描项目/用户根目录,其他提供方可以在不改动注册表/工具的情况下添加嵌入式或远程目录。subagent 可以全新 spawn、从父级已完成轮次的前缀 fork,或使用 ACP 子进程([subagent.md](core-data-structures/subagent.md))。 +部分 seam 有意偏离模板。LLM 将接口与消费方词汇放在一起,因为适配器就是实现。文件系统在提供方原语周围增加了策略门。Web 是一个服务加搜索/抓取两个提供方注册表,因此替换提供方不会重命名模型工具。Skills 和 subagents 使用命名提供方注册表;本地 skills 扫描项目/用户根目录,其他提供方可以添加嵌入式或远程目录而无需修改注册表/工具。Subagents 可以全新 spawn、从父级已完成轮次的前缀 fork,或使用 ACP 子进程([subagent.md](core-data-structures/subagent.md))。 ### Bundle 与应用 -`dsh-agent-spine-demo` 是默认的组合 bundle:一个插件加载共享主干([README](../packages/examples/agent-spine-demo/README.md))。应用包将其与前端入口和启动 `bin` 组合:`dsh-stdio-demo` 用于终端 REPL,`dsh-acp-demo` 用于基于 JSON-RPC stdio 的 ACP(无 stdout logger)([ui/](../packages/ui/README.md))。`dsh-jsonrpc-agent` 则启动外部 `cordis.yml`;Python SDK 在未设置显式配置通道时注入包默认值,并通过行分隔的 stdio JSON-RPC 驱动 `dsh-jsonrpc`([Python SDK](../python/README.md))。一个部署就是一片薄薄的 `cordis.yml` 叶子:可替换的后端、一个应用入口和可选的产品工具([examples/](../examples/AGENTS.md)、[可运行接线](cookbook/extension-cookbook.md#runnable-wirings)、[关系图索引](graph-atlas.md))。 +`dsh-agent-spine-demo` 是默认的组合 bundle:一个插件加载共享主干([README](../packages/examples/agent-spine-demo/README.md))。应用包在其上组合前端入口和启动 `bin`:`dsh-stdio-demo` 用于终端 REPL,`dsh-acp-demo` 用于通过 JSON-RPC stdio 提供 ACP 且不带 stdout 日志([ui/](../packages/ui/README.md))。`dsh-jsonrpc-agent` 则启动外部 `cordis.yml`;Python SDK 仅在未设置显式配置通道时注入包默认值,并通过行分隔的 stdio JSON-RPC 驱动 `dsh-jsonrpc`([Python SDK](../python/README.md))。一个部署就是一片薄薄的 `cordis.yml` 叶子:可替换的后端、一个应用入口,加上可选的产品工具([examples/](../examples/AGENTS.md)、[可运行接线](cookbook/extension-cookbook.md#runnable-wirings)、[关系图索引](graph-atlas.md))。 ### 新行为的归属 -新行为应接入已记录的扩展点;修改内置循环需要同步更新本映射。 +新行为应接入已文档化的扩展点;修改内置循环需要同步更新此映射表。 | 目标 | 机制 | |---|---| | 添加模型提供方 | 在 `ctx.llm` 上注册适配器 | -| 添加面向模型的能力 | 在 `ctx.tools` 上注册工具;schema 流入 prompt 组装 | +| 添加面向模型的能力 | 在 `ctx.tools` 上注册工具;schema 流入提示词组装 | | 添加命令执行 | 实现并注册 `ctx.bash` 后端 | | 添加文件系统访问或策略 | 实现 `ctx.fs` 提供方或监听 `fs/*` 策略事件 | | 隔离 spawn 的进程 | 一个 `ctx.sandbox` 后端;消费方在 spawn 前包装 argv | -| 拦截 prompt、请求、工具使用或续行 | 监听相关的 `agent/*` 或 `tools/*` waterfall;使用串行 `agent/turn-stop` 实现单调终止 | +| 拦截提示词、请求、工具使用或续行 | 监听相关 `agent/*` 或 `tools/*` waterfall;使用串行 `agent/turn-stop` 实现单调终止停止 | | 添加历史之外的会话稳定请求前缀 | 在 `agent/session-prefix` 上组合,每个循环实例一次;记录在请求 header 上 | | 添加 UI 或编辑器集成 | 驱动 `ctx.agents` 并从 `session/event` 渲染 | -| 添加持久化会话状态 | 添加 `SessionEventMap` 成员并从日志渲染/回放 | -| fork 活跃会话 | 使用 `ctx.sessions.fork(source, boundary?, childSessionId?)` | -| 将工具、prompt 段或监听器限定到单个 agent | 通过该 agent 的 `agent.ctx` 注册(见 Agent 作用域) | +| 添加持久会话状态 | 添加 `SessionEventMap` 成员并从日志渲染/回放 | +| Fork 活跃会话 | 使用 `ctx.sessions.fork(source, boundary?, childSessionId?)` | +| 将工具、提示词段或监听器限定到单个 agent | 通过该 agent 的 `agent.ctx` 注册(见 Agent 作用域) | -[扩展实操手册(cookbook)](cookbook/extension-cookbook.md)提供插件骨架与功能到 seam 的映射;分步指南覆盖[包](cookbook/adding-a-package.md)、[工具](cookbook/adding-a-tool.md)、[LLM 适配器](cookbook/adding-an-llm-adapter.md)与[vendor 包](cookbook/adding-a-vendored-package.md)。 +[扩展实操手册](cookbook/extension-cookbook.md)提供插件骨架和功能到 seam 的映射;分步指南覆盖[包](cookbook/adding-a-package.md)、[工具](cookbook/adding-a-tool.md)、[LLM 适配器](cookbook/adding-an-llm-adapter.md)与 [vendor 包](cookbook/adding-a-vendored-package.md)。 ## 快速参考 - 领域术语见[术语表](glossary.md) - 类型定义见 [core-data-structures/](core-data-structures/core.md) -- 精确的事件与服务签名见[事件目录](cordis-catalog/events.md) -- [服务目录](cordis-catalog/services.md) +- 精确的事件与服务签名见[事件](cordis-catalog/events.md) +- 与[服务](cordis-catalog/services.md)目录 - 包契约见[包映射](../packages/README.md) - [RFC](rfc/README.md) diff --git a/docs/cordis-primer.i18n.yaml b/docs/cordis-primer.i18n.yaml index 405a377ed1..5345efe3f0 100644 --- a/docs/cordis-primer.i18n.yaml +++ b/docs/cordis-primer.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write cordis-primer.md: 39d3d97b9ac43fec50cb0c832af449fc8bc6232f -cordis-primer.zh.md: 4915f665cae51b44f89190d43d147e5cda0df146 +cordis-primer.zh.md: f941c90489e1153910ed809d2cef30ece8539f8f diff --git a/docs/cordis-primer.zh.md b/docs/cordis-primer.zh.md index 4915f665ca..f941c90489 100644 --- a/docs/cordis-primer.zh.md +++ b/docs/cordis-primer.zh.md @@ -2,19 +2,19 @@ [English](cordis-primer.md) | 中文 -Cordis 是 DeepSeek Harness SDK 底层以 vendor 方式引入的插件框架。本入门文档讲解 harness 插件作者在阅读生成的[事件](cordis-catalog/events.md)与[服务](cordis-catalog/services.md)目录之前需要了解的 Cordis 核心概念。vendor 源码与同步流程见 [vendor/README.md](../vendor/README.md)。 +Cordis 是 DeepSeek Harness SDK 底层以 vendor 方式引入的插件框架。本文介绍 harness 插件作者在阅读生成的[事件](cordis-catalog/events.md)与[服务](cordis-catalog/services.md)目录之前需要了解的 Cordis 核心概念。vendor 源码与同步流程见 [vendor/README.md](../vendor/README.md)。 -## Cordis 五大理念 +## 五个核心概念 -- **插件是实现了 Service 的对象。** 它可以是一个带有可选 `inject` 和 `apply(ctx)` 字段的函数,也可以是一个 `Service` 子类,其生命周期由 Cordis 挂载到当前上下文中。 -- **上下文是服务的注册表。** 一个服务在上下文中声明一个稳定的 `ctx.<key>`(如 `ctx.tools`、`ctx.llm`、`ctx.sessions`);其他插件通过 key 查找服务,而非导入具体实现。 -- **通过 `inject` 声明服务依赖。** 插件声明所需的服务后,会等待这些服务就绪;加载顺序通过服务依赖表达,而非手动编排启动序列。 -- **类型化事件用于通信。** 服务通过 TypeScript 声明合并定义事件名,然后以 `emit`、`waterfall`(瀑布式事件)、`parallel` 或 `serial` 方式分发,分别对应监听者观察、包装、并行扇出或按序执行。 -- **注册是可逆的副作用。** 提示词片段、工具 schema、适配器、提供方和监听器通过 `ctx.effect()` 或 `ctx.on()` 安装,因此重载和拆卸能可预测地回退它们。 +- **插件是实现 Service 的对象。** 它可以是一个带有可选 `inject` 和 `apply(ctx)` 字段的函数,也可以是一个 `Service` 子类,其生命周期由 Cordis 挂载到当前上下文中。 +- **上下文是服务的容器。** 一个服务占据一个稳定的 `ctx.<key>`(如 `ctx.tools`、`ctx.llm`、`ctx.sessions`);其他插件通过 key 查找服务,而非导入具体实现。 +- **通过 `inject` 声明服务依赖。** 插件声明所需的服务后,会等待这些服务就绪才启动;加载顺序通过服务依赖表达,而非手动编排启动序列。 +- **类型化事件用于通信。** 服务通过 TypeScript 声明合并注册事件名,然后以 `emit`、`waterfall`(瀑布式事件)、`parallel` 或 `serial` 方式分发,分别对应监听者观察、包装、并行扇出或按序执行。 +- **注册是可逆的副作用。** 提示词片段、工具 schema、适配器、提供方和监听器通过 `ctx.effect()` 或 `ctx.on()` 安装,reload 和 teardown 时可预期地回卷。 ## 分发模式 -每个事件具有以下分发模式之一,且只能通过对应的方法分发。 +每个事件具有以下分发模式之一,且只能通过对应方法分发。 | 模式 | 是否 await? | 分发顺序 | 是否有返回值? | |---|---|---|---| @@ -23,22 +23,22 @@ Cordis 是 DeepSeek Harness SDK 底层以 vendor 方式引入的插件框架。 | `parallel` | 是 | 所有监听器并行观察事件 | 否 | | `serial` | 是 | 监听器按注册顺序观察 | 是 | -分发模式是事件公开契约的一部分。新的 harness 事件通过 `@mode` 标签记录它,以便生成的目录能将声明与分发站点进行交叉校验。 +分发模式是事件公开契约的一部分。新的 harness 事件通过 `@mode` 标签记录模式,以便生成的目录可以将声明与分发调用点做交叉校验。 ## Cordis Waterfall 语义 `ctx.waterfall` 是环绕中间件。监听器接收 `(...args, next)`。调用 `next()` 将可能经过包装的结果委托给下一个服务;不调用 `next()` 直接返回则短路。值通过 `next()` 的返回值向下传播。 -协作式监听器通常修改一个共享的请求或决策对象,然后委托。监听器也可以选择完全替换结果,下游监听器只会看到替换后的结果。仅当监听器必须在普通注册之前运行时才使用 `prepend: true`。 +协作式监听器通常修改一个共享的请求或决策对象,然后委托。监听器也可以选择完全替换结果,下游监听器将只看到替换后的结果。仅当监听器必须在普通注册之前运行时才使用 `prepend: true`。 -对于单决策事件,短路是设计意图。策略监听器在拥有决策权时可以不调用 `next()` 直接返回,而仅做标注或观察的监听器必须委托。 +对于单决策事件,短路是设计意图。策略监听器在拥有决策权时可以不调用 `next()` 直接返回,而仅做标注或观察的监听器则必须委托。 ## Loader 配置 -`@cordisjs/plugin-include` 将 `!!js` 解析为表达式节点,但 Loader 仅在挂载插件前对条目的 `config` 进行插值。条目元数据(`id`、`name`、`group`、`disabled`、`inject`、`intercept` 和 `isolate`)保持字面值;因此 `disabled: !!js ...` 是一个真值对象,总是会禁用该条目。当需要根据环境选择挂载哪些插件时,请使用显式的配置覆盖。 +`@cordisjs/plugin-include` 将 `!!js` 解析为表达式节点,但 Loader 仅在挂载插件前对条目的 `config` 做插值。条目元数据(`id`、`name`、`group`、`disabled`、`inject`、`intercept` 和 `isolate`)保持字面值;因此 `disabled: !!js ...` 是一个 truthy 对象,会始终禁用该条目。需要根据环境选择挂载哪些插件时,请使用显式的配置覆盖层。 ## 实践规则 -将行为封装到插件中:工具流水线事件属于 `ctx.tools`,模型流式输出属于 `ctx.llm`,实时 agent 协调属于 `ctx.agents`。拦截和策略优先使用事件;直接能力调用优先使用服务方法。 +将行为封装为插件:工具流水线事件属于 `ctx.tools`,模型流式输出属于 `ctx.llm`,实时 agent(智能体)协调属于 `ctx.agents`。拦截和策略优先使用事件;直接能力调用优先使用服务方法。 -每个注册都应有对应的 dispose(资源释放)器:要么从 `ctx.effect()` 返回一个,要么使用 Cordis 提供的辅助函数自动处理。如果拆卸顺序有要求,请将相关工作放在同一个 effect 中,以确保 dispose 按预期顺序回退。 +每个注册都应有对应的 disposer(dispose(资源释放)函数):要么从 `ctx.effect()` 返回一个,要么使用 Cordis 提供的辅助方法自动处理。如果 teardown 顺序有要求,请将相关工作放在同一个 effect 中,以确保资源释放按预期顺序回卷。 diff --git a/docs/defensive-patterns.i18n.yaml b/docs/defensive-patterns.i18n.yaml index 03765e44ae..96bb5de13f 100644 --- a/docs/defensive-patterns.i18n.yaml +++ b/docs/defensive-patterns.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write defensive-patterns.md: fda0be0d2d3b7fa099162123b3d219673eebd07d -defensive-patterns.zh.md: 60d7389db50c30e2b85fd88b320f04b43e22d84d +defensive-patterns.zh.md: f6e4712a4a239c954193f63f32285037eb6d4f0e diff --git a/docs/defensive-patterns.zh.md b/docs/defensive-patterns.zh.md index 60d7389db5..f6e4712a4a 100644 --- a/docs/defensive-patterns.zh.md +++ b/docs/defensive-patterns.zh.md @@ -2,28 +2,28 @@ [English](defensive-patterns.md) | 中文 -来之不易的缺陷类别规则:以下每条模式都是本项目中实际发布或险些发布的一类缺陷,以防止其复发的规则形式陈述。在编写生命周期、并发、子进程或清理代码之前,请先阅读本文。测试层面的对应规则(真实入口路径、world 验证、资源归属)见 [testing.md](testing.md)。 +来之不易的缺陷类别规则:下面每条模式都是本项目实际发布或差点发布的一类缺陷,以防止其复发的规则形式陈述。在编写生命周期、并发、子进程或清理代码之前请先阅读本文。测试层面的对应规则(真实入口路径、world 验证、资源归属)见 [testing.md](testing.md)。 ## 正交结果独立上报 -一个结果可以同时具有多重性质:进程可能既超时又以 exit 0 退出,因为它捕获了信号。每个独立事实(`timedOut`、`signal`、`exitCode`)都应独立暴露;永远不要把一个 flag 的上报嵌套在另一个 flag 的分支内,否则调用方会把一次被截断的运行误读为正常成功。 +一个结果可以同时具有多重性质:进程可能既超时又以 exit 0 退出,因为它捕获了信号。每个独立事实(`timedOut`、`signal`、`exitCode`)都应独立暴露;切勿将某个 flag 的上报嵌套在另一个 flag 的分支内,否则调用方会把一次被截断的运行误读为正常成功。 -## 在接口两侧都遵守跨 seam 契约 +## 跨 seam 契约两侧都要遵守 -当接口文档记录了两种有效的信号方式时——例如适配器可以通过从 `stream()` 抛出异常来报告失败,也可以通过以 `finish {kind:'error'|'aborted'}` 分片结束流来报告——消费方必须两种都处理,而不只是第一个实现碰巧使用的那种。基于库的适配器在流中途无法抛出异常,只能依赖带内路径;如果 agent loop 只捕获 throw,就会把提供方的 401 变成一个正常完成的轮次。请在类型定义处记录契约;通过真实消费方测试每个分支。 +当一个接口文档记录了两种合法的信号方式时——例如适配器可以通过从 `stream()` 抛出异常来报告失败,也可以通过以 `finish {kind:'error'|'aborted'}` 分片结束流来报告——消费方必须同时处理两种路径,而不是只处理第一个实现恰好使用的那种。依赖库的适配器可能无法在流中途抛出异常,只能走带内路径;如果 agent loop(智能体循环)只捕获抛出的异常,就会把提供方的 401 错误变成一个正常完成的轮次。请在类型定义处记录契约;通过真实消费方测试每个分支。 ## 异步状态不是同步状态 -`agent.send()` 不会在返回前翻转状态;后台任务的完成与轮次边界存在竞态;`reader.close()` 在 EOF 和 dispose(资源释放)两种情况下都会触发。永远不要基于一个你刚刚请求的状态来控制流程——应当基于实际触发的事件/promise 来驱动生命周期(`agent/status`、`task.done`),并观察状态转换(先看到 `running` 再看到 `idle`),而不是假设你发出的动作与轮次 1:1 对应(循环会批量处理排队的消息)。这条守则是双向的:如果等待的转换永远不会发生(EOF 且没有提交过工作 → 永远不会进入 `running`),等待就会挂起——请显式处理「无需等待」的分支。 +`agent.send()` 不会在返回前翻转状态;后台任务的完成与轮次边界存在竞争;`reader.close()` 在 EOF 和 dispose(资源释放)两种情况下都会触发。切勿基于一个刚刚请求的状态来控制流程——应以实际触发的事件/promise(`agent/status`、`task.done`)驱动生命周期,并观察状态转换(先看到 `running` 再看到 `idle`),而非计数你假定与轮次一一对应的操作(循环会批量处理排队消息)。这条守则是双向的:如果等待的转换永远不会发生(EOF 时没有提交过任何工作 → 永远不会进入 `running`),等待就会挂起——请显式处理「无需等待」的分支。 -## dispose 必须达到静止,而非仅仅请求停止 +## Dispose 必须达到静止,而不仅仅是请求停止 -一个只发出 kill/abort 就返回的清理逻辑会留下孤儿进程。请让清理逻辑异步化并 await 子进程退出(kill → await `done`),并在 kill 之前关闭监听器/通知注册表,使迟到的完成事件保持静默。测试应证明 dispose 确实等到了进程退出(`await fiber.dispose()` 之后 pid 已不存在),而非仅仅证明进程最终会死。 +一个清理流程如果发出 kill/abort 后就返回、而不等待工作实际停止,就会留下孤儿进程。请让清理逻辑异步化并 await 子进程退出(kill → await `done`),并在 kill 之前关闭监听器/通知注册表,使迟到的完成事件保持静默。测试应证明 dispose 确实等待了(`await fiber.dispose()` 之后 pid 已不存在),而不仅仅是进程最终会死。 ## 在边界处包容回调异常 -用户提供的监听器抛出异常时,不得导致它所在的 promise 被 reject,也不得饿死排在它之后的监听器。请在分发循环中用 try/catch 包裹并记录日志;一个有问题的订阅者永远不能破坏核心生命周期。 +用户提供的监听器如果抛出异常,不得导致它所在的 promise 被 reject,也不得饿死排在它后面的监听器。请用 try/catch 包裹分发循环并记录日志;一个行为不当的订阅者绝不能破坏核心生命周期。 -## 永远不要把环境变量或可预测路径暴露给不可信输出 +## 绝不将环境变量或可预测路径暴露给不可信输出 -spawn 的命令应获得一个经过清洗的 env(移除 `*KEY*`/`*SECRET*`/`*TOKEN*`),确保 harness 凭证不会泄漏到输出、`env` 或溢出文件中。临时/溢出文件应使用私有(0700)目录、随机文件名和排他的仅所有者可打开模式(`'wx'`、`0o600`)——可预测的全局可读路径会招致符号链接竞态和信息泄露。 +spawn 的命令应获得一份经过清洗的 env(去除 `*KEY*`/`*SECRET*`/`*TOKEN*`),使 harness 凭证无法泄漏到输出、`env` 或溢出文件中。临时/溢出文件应使用私有(0700)目录、随机文件名和排他的仅所有者可访问打开方式(`'wx'`、`0o600`)——可预测的全局可读路径会招致符号链接竞争和信息泄露。 diff --git a/docs/glossary.i18n.yaml b/docs/glossary.i18n.yaml index a0765ef752..fe099eb156 100644 --- a/docs/glossary.i18n.yaml +++ b/docs/glossary.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write glossary.md: 23eebc5793e8232482a796f5bde1e794f0556208 -glossary.zh.md: 7163015eeed71c96743b9cae491db206585a70b2 +glossary.zh.md: a233f926ba3af0a4e90de90bf21d68a2244c3ea6 diff --git a/docs/glossary.zh.md b/docs/glossary.zh.md index 7163015eee..a233f926ba 100644 --- a/docs/glossary.zh.md +++ b/docs/glossary.zh.md @@ -2,18 +2,18 @@ [English](glossary.md) | 中文 -DeepSeek Harness SDK 的领域词汇对每个概念使用唯一的规范术语。各术语通过标准 Markdown 锚点互相链接;实现细节留在各 package README 和 RFC 中。 +DeepSeek Harness SDK 的领域词汇对每个概念使用唯一的规范术语。各术语通过标准 Markdown 锚点互相链接;实现细节留在各 package README 与 RFC 中。 FIXME(glossary-completeness): Expand this glossary before the first release so it covers the SDK's other core and capability subsystems, not only agent scope. -## agent 作用域 +## agent-scope -- **scope(作用域)**:按 agent(智能体)注册的单位。一项贡献(工具、prompt 段落、变量、限制、监听器)要么是*全局*的(对所有 agent 可见),要么是*有作用域*的(归属于恰好一个 [scope key](#scope-key))。只有两层,扁平结构:有作用域的注册不会向下继承给 subagent;子树行为通过[血统](#lineage)数据表达,从不通过作用域结构。 -- **scope key(作用域键)**:作用域的不透明标识,按对象同一性比较。harness 约定:一个活跃的 agent 就是其自身作用域的 key。<a id="scope-key"></a> -- **agent context(`agent.ctx`)**:agent 的有作用域上下文;通过它进行的注册既是作用域可见的,也是作用域生命周期的(一个事实同时驱动两者),其上的监听器参与该 agent 的作用域过滤分发。注册表主体事件可以在其自身的事件契约下有意保持不过滤。 -- **scope carrier(作用域载体)**:作用域过滤分发所携带的 `thisArg`(由 `scopeTarget` 构建);其过滤器放行无标签监听器加上主体自身的监听器。*无主体*的载体(没有 key)只放行无标签监听器。 -- **scoped dispatch(作用域分发)**:规则是:关于某个 agent 活动的事件以该 agent 的载体进行分发。关于注册表本身的事件(如「一个工具被添加」)属于*注册表主体*事件,保持不过滤。 -- **shadowing(遮蔽)**:最具体者胜出的名称解析:一个有作用域的工具/段落/变量仅在该作用域内替代其同名的全局副本。这是按 agent 定制人设和按 agent 定制工具变体的机制。 -- **restriction / scope-local registration(限制 / 作用域局部注册)**:限制(`tools.restrict`)为单个作用域过滤全局工具面(按交集组合);作用域局部注册在过滤之后合并。被过滤掉的全局工具既不出现在 prompt 中,也拒绝执行,与不存在的工具无法区分。 -- **setup window(设置窗口)**:创建者组装 agent 有作用域世界的创建时隙(`CreateAgentOptions.setup`):在作用域和 agent 对象已存在、但 agent 或会话尚未发布、`agent/session-start` 尚未触发、首次 prompt 尚未组装之前。设置窗口只做注册,从不驱动 agent。 -- **lineage(血统)**:以数据形式携带的父子关系(`parentSession`、`subagentDepth`);从不影响可见性。<a id="lineage"></a> +- **scope**:按 agent(智能体)划分的注册单位。一项贡献(工具、提示词片段、变量、限制、监听器)要么是*全局的*(对所有 agent 可见),要么是*有范围的*(归属于恰好一个 [scope key](#scope-key))。只有两层,扁平结构:有范围的注册不会向下继承给 subagent;子树行为通过 [lineage](#lineage) 数据表达,从不通过 scope 结构。 +- **scope key**:scope 的不透明标识,按对象同一性比较。harness 约定:一个活跃的 agent 就是其自身 scope 的 key。<a id="scope-key"></a> +- **agent 上下文(`agent.ctx`)**:agent 的有范围上下文;通过它进行的注册既是 scope 可见的,也是 scope 生命周期的(同一事实决定两者),其上的监听器参与该 agent 的 scope 过滤分发。注册表主体事件可以在各自的事件契约下保持故意不过滤。 +- **scope carrier**:scope 过滤分发所携带的 `thisArg`(由 `scopeTarget` 构建);其过滤器放行无标签监听器加上主体自身的监听器。*无主体*的 carrier(没有 key)只放行无标签监听器。 +- **scoped dispatch**:规则是:关于某个 agent 活动的事件以该 agent 的 carrier 进行分发。关于注册表本身的事件(如「一个工具被添加了」)属于*注册表主体*事件,保持不过滤。 +- **shadowing**:最具体者胜出的名称解析:一个有范围的工具/片段/变量仅在该 scope 内替换同名的全局对应项。这是按 agent 定制 persona 和按 agent 定制工具变体的机制。 +- **restriction / scope-local 注册**:restriction(`tools.restrict`)为单个 scope 过滤全局工具表面(多个 restriction 取交集组合);scope-local 注册在过滤之后合并。被过滤掉的全局工具既不出现在提示词中,也拒绝执行,与不存在的工具无法区分。 +- **setup window**:创建者组装 agent 有范围世界的创建时隙(`CreateAgentOptions.setup`):在 scope 和 agent 对象已存在、但 agent 或会话尚未发布、`agent/session-start` 尚未触发、首次提示词尚未组装之前。setup 只做注册,从不驱动 agent。 +- **lineage**:以数据形式携带的父子关系事实(`parentSession`、`subagentDepth`);从不影响可见性。<a id="lineage"></a> diff --git a/docs/testing.i18n.yaml b/docs/testing.i18n.yaml index 3adcf28723..e91d6712ea 100644 --- a/docs/testing.i18n.yaml +++ b/docs/testing.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write testing.md: ddb9da0b38e5dc9cc75ede81ec157c4744fd11c2 -testing.zh.md: 6d21a37b175c8052fbc34db0fc5a9b522c27f7ec +testing.zh.md: 8a37a9eaffbf19b205e3b98e7609464133060cf2 diff --git a/docs/testing.zh.md b/docs/testing.zh.md index 6d21a37b17..8a37a9eaff 100644 --- a/docs/testing.zh.md +++ b/docs/testing.zh.md @@ -2,34 +2,34 @@ [English](testing.md) | 中文 -本文说明本仓库如何逐层测试,以及保持绿色测试套件有意义的规则。命令见根目录 [AGENTS.md](../AGENTS.md);关联 RFC 承载设计动机。 +本文说明本仓库的分层测试方式,以及保持绿色测试套件有意义的规则。命令见根目录 [AGENTS.md](../AGENTS.md);关联的 RFC 承载设计动机。 ## 层级 -- **单元测试**(`pnpm run test`):vitest 运行 `packages|examples/*/tests/**/*.spec.ts`,与被测代码同目录。每个注册表都有一个 HMR(热模块替换)安全测试(dispose 贡献该注册的 fiber,断言清理完成)。优先覆盖边界情况、错误路径、事件顺序、并发竞态与永久契约回归(见 `packages/core/agent-loop/tests/contract-regressions.spec.ts`)。 -- **覆盖率门禁**(`pnpm run test:coverage`):门禁级运行,对 `packages/*/*/src` 按文件 100% 覆盖。未覆盖的行往往是门禁正确标记出的死代码(应删除),而非需要补写的测试。行覆盖率是必要条件,绝非充分条件:它证明代码行被执行过,不证明功能按交付预期工作。 -- **真实 API e2e**(`pnpm run test:e2e`):带密钥测试,对接真实提供方 API——DeepSeek 模型加各提供方独立冒烟测试(各自依赖自己的密钥:`EXA_API_KEY`、`PERPLEXITY_API_KEY` 等);每个套件在缺少对应密钥时自动跳过,确保无密钥 CI 保持绿色([真实 API e2e RFC](rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md))。 -- **快照测试**(`pnpm run test:snapshot`):启动真实示例子进程,无密钥回放录制的会话,将归一化后的 stdout 与重新持久化的日志同已提交的 golden 文件做 diff([快照 RFC](rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md))。当模型 transcript(文本记录)需要变更时使用 `pnpm run test:snapshot:record`;当已提交的 transcript 仍是正确的 mock LLM(大语言模型)输入、只需无密钥重写回放 golden 时使用 `pnpm run test:snapshot:refresh`。请评审 golden diff。系统提示词/工具 schema 内容由一个场景(`text-turn`)固定,其余 fixture(测试前置数据)中以 token 化形式引用,因此 prompt 或 schema 的修改只变动一行已提交内容([pinned-header RFC](rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md))。 +- **单元测试**(`pnpm run test`):vitest 运行 `packages|examples/*/tests/**/*.spec.ts`,与被测代码同目录。每个注册表都有一个 HMR(热模块替换)安全测试(dispose(资源释放)贡献的 fiber,断言清理完成)。优先覆盖边界情况、错误路径、事件顺序、并发竞态,以及永久性契约回归(见 `packages/core/agent-loop/tests/contract-regressions.spec.ts`)。 +- **覆盖率门禁**(`pnpm run test:coverage`):门禁级运行,对 `packages/*/*/src` 按文件 100% 覆盖。未覆盖的行往往是门禁正确标记出的死代码(应删除),而非需要补写的测试。行覆盖率是必要条件,但永远不是充分条件:它证明行被执行过,不证明功能按交付预期工作。 +- **真实 API e2e**(`pnpm run test:e2e`):带密钥测试,调用真实提供方 API。包括 DeepSeek 模型以及各提供方特有的冒烟测试(各自依赖自己的密钥:`EXA_API_KEY`、`PERPLEXITY_API_KEY` 等);缺少密钥时各套件自动跳过,keyless CI 保持绿色([真实 API e2e RFC](rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md))。 +- **快照测试**(`pnpm run test:snapshot`):启动真实示例子进程,在无密钥环境下回放录制的会话,将归一化的 stdout 与重新持久化的日志与已提交的 golden 文件做 diff([快照 RFC](rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md))。当模型 transcript(文本记录)需要变更时使用 `pnpm run test:snapshot:record`;当已提交的 transcript 仍是正确的 mock LLM(大语言模型)输入、只需无密钥重写回放 golden 时使用 `pnpm run test:snapshot:refresh`。请审查 golden diff。系统提示词/工具 schema 内容由**一个**场景(`text-turn`)固定,其余 fixture(测试前置数据)中以 token 化形式引用,因此 prompt 或 schema 的修改只影响一行已提交内容([pinned-header RFC](rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md))。 ## 带密钥策略:推理在这里很便宜 -我们是 DeepSeek:不要吝惜真实 API 测试。无密钥测试证明管道通了;只有带密钥运行才能证明 agent 对接真实模型时能正常工作。多写:文件写入 prompt、多轮对话、工具调用、流中取消。价值最高的是**冒烟测试**:启动真实示例、发送一条真实 prompt、检查外部世界的状态。它们能捕获「单元测试全绿、产品却坏了」这类 mock 在结构上无法发现的问题([事后分析 0001](postmortem/0001-acp-default-export-drops-inject.md))。自动跳过机制的存在仅仅是为了不阻塞无密钥 CI 和无密钥贡献者,它不是成本信号。每个示例都附带一个无密钥冒烟测试,以及(除非本身就不需要密钥)一个带密钥冒烟测试([examples/AGENTS.md](../examples/AGENTS.md))。 +我们是 DeepSeek,不要吝惜真实 API 测试。无密钥测试只能证明管道通畅;只有带密钥运行才能证明 agent(智能体)在真实模型面前能正常工作。请大量编写:文件写入 prompt、多轮次对话、工具调用、流中取消。价值最高的是**冒烟测试**:启动真实示例、发送一条真实 prompt、检查外部世界的状态。它们能捕获「单元测试全绿、产品却坏了」这一类 mock 在结构上无法发现的问题([事后分析 0001](postmortem/0001-acp-default-export-drops-inject.md))。自动跳过机制的存在仅仅是为了不阻塞无密钥的 CI 和无密钥的贡献者,它不是成本信号。每个示例都附带一个 keyless 冒烟测试,并且——除非本身就不需要密钥——还附带一个带密钥冒烟测试([examples/AGENTS.md](../examples/AGENTS.md))。 ## 优先使用真实实现而非 mock -只 mock 真正昂贵或不确定的边界(LLM 适配器、网络、时钟);下游一切保持真实。手写的替身只能证明桥接层在搬运字节,不能证明交付的工具行为符合断言——两者会漂移,而测试仍然绿着。示例:bridge 工具调用测试运行脚本化的 mock 模型,但使用真实的 tool + 真实的执行器(`makeBridgeHarness({ withBash: true })` 接入 `dsh-bash-local` + `dsh-tool-bash`,执行真正的 `echo`)。 +只在真正昂贵或不确定的边界处 mock(LLM 适配器、网络、时钟);下游一切保持真实。手写的替身只能证明桥接层在搬运字节,不能证明交付的工具行为符合断言——两者会漂移,而测试继续绿着。例如:bridge 工具调用测试运行脚本化的 mock 模型,但使用真实的 tool + 真实的执行器(`makeBridgeHarness({ withBash: true })` 接入 `dsh-bash-local` + `dsh-tool-bash` 并执行真正的 `echo`)。 ## 验证外部世界,而非自我报告 -e2e 断言应重新运行命令或从外部重新读取文件;仅对 agent 自身输出做关键词探测会让作弊的 agent 通过。断言未改动的文件字节相同。e2e 测试拥有自己的资源:在测试中创建 harness,在 `afterEach` 中 dispose(即使失败/重试/超时);共享 fixture 放在普通的 `tests/harness.ts` 中,绝不放在另一个 `*.e2e.ts` 里(import 一个 spec 会重新注册其 `describe`,导致真实 API 调用重复)。 +e2e 断言应重新运行命令或从外部重新读取文件;对 agent 自身输出做关键词探测会让作弊的 agent 通过。断言未修改的文件逐字节一致。e2e 测试自行管理资源:在测试中创建 harness,在 `afterEach` 中 dispose(即使失败/重试/超时也要释放);共享 fixture 放在普通的 `tests/harness.ts` 中,绝不放在另一个 `*.e2e.ts` 中(导入一个 spec 会重新注册其 `describe`,导致真实 API 调用重复执行)。 ## 测试真实入口路径 -- 产品可见的插件需要一个非单元的真实组合测试。手工搭建的 `ctx.plugin(...)` 套件不够:通过 Loader 和 app/process 启动仅用于测试的 `cordis.yml`,只 mock 外部/不确定边界,断言模型可见的请求/日志、持久状态或用户可见输出。不要把 opt-in 混入默认交付。 -- 一个守卫只有在回归真正让它失败时才算守卫。对于没有 `inject` 的插件(bundle/组合插件),Loader 冒烟测试在导出形状损坏时仍然绿——需要加一个显式的 `expect('default' in mod).toBe(false)` 加 `unwrapExports` 往返断言,并证明它有效:引入回归、观察变红、还原。 -- 「真实入口路径」指已发布的产物:package 的 `bin` 指向构建出的 `lib/bin.js`,在原生 `node` 下运行;tsx 会掩盖竞态、模块解析问题以及静默以 0 退出的加载失败。同理适用于构建后 package 在运行时解析的任何非 index 运行时入口(worker-thread 运行时的兄弟文件 `lib/worker.cjs`)。保持构建产物冒烟测试绿色(`packages/ui/*/tests/built-bin.e2e.ts`、`packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts`),并断言真正缺失的配置以非零退出。 -- 从临时 cwd spawn 示例的 e2e 测试需要设置 `TSX_TSCONFIG_PATH` 指向仓库根 tsconfig,否则会静默回退到陈旧的构建 `lib/`([examples/AGENTS.md](../examples/AGENTS.md))。 +- 产品可见的插件必须有一个非单元的真实组合测试。手动构建的 `ctx.plugin(...)` 套件不够:通过 Loader 和 app/process 启动仅用于测试的 `cordis.yml`,只 mock 外部/不确定边界,断言模型可见的请求/日志、持久状态或用户可见输出。不要把 opt-in 选项混入交付默认值。 +- 一个守卫只有在回归真的能让它失败时才有效。对于没有 `inject` 的插件(bundle/组合插件),Loader 冒烟测试在导出形状损坏时仍然绿着——需要添加显式的 `expect('default' in mod).toBe(false)` 加 `unwrapExports` 往返断言,并证明它有效:引入回归、观察变红、回退。 +- 「真实入口路径」指已发布的产物:package 的 `bin` 指向在普通 `node` 下运行的构建产物 `lib/bin.js`,tsx 会掩盖问题(竞态、模块解析、吞掉的加载失败以 exit 0 退出)。同样适用于构建后的 package 在运行时解析的任何非 index 运行时入口(worker-thread 运行时的兄弟文件 `lib/worker.cjs`)。保持构建产物冒烟测试绿色(`packages/ui/*/tests/built-bin.e2e.ts`、`packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts`),并断言真正缺失的配置以非零退出码退出。 +- 从临时 cwd spawn 示例的 e2e 测试需要设置 `TSX_TSCONFIG_PATH` 为仓库根目录的 tsconfig,否则会静默回退到陈旧的构建产物 `lib/`([examples/AGENTS.md](../examples/AGENTS.md))。 ## 何时需要快照测试 -任何影响编辑器侧 transcript 或端到端 agent 用户体验的变更——ACP bridge、agent loop(智能体循环)的可观测输出、工具呈现——都应在所属示例的快照套件中添加或更新场景(`examples/<name>/tests/snapshots/`,基于 [`dsh-acp-snapshot`](../packages/support/acp-snapshot/README.md) 套件工厂的场景表;`examples/acp-agent` 是主套件),或在 PR 中说明为何不适用。新的能力 seam、生命周期形态或 transcript 表面在计划阶段就要标明各层的覆盖方式,并验证 harness 能表达它——harness 的缺口是排期工作,不是构建中途的意外。 +任何影响编辑器侧 transcript 或端到端 agent UX 的变更——ACP bridge、agent loop(智能体循环)的可观测输出、工具呈现——都需要在所属示例的快照套件中添加或更新场景(`examples/<name>/tests/snapshots/`,基于 [`dsh-acp-snapshot`](../packages/support/acp-snapshot/README.md) 套件工厂的场景表;`examples/acp-agent` 是主套件),或在 PR 中说明为何不适用。新的能力 seam、生命周期形态或 transcript 表面在计划阶段就要列出各层级的覆盖方案,并验证 harness 能够表达它——harness 的缺口是排期工作,不是构建中途的意外。 From 6bf93b8e6af24ddf543660f65e940b9ee07f11ba Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Wed, 22 Jul 2026 03:04:54 -0700 Subject: [PATCH 072/368] chore: drop stray embedded worktree from index --- .worktrees/i18n-prompt-sync | 1 - 1 file changed, 1 deletion(-) delete mode 160000 .worktrees/i18n-prompt-sync diff --git a/.worktrees/i18n-prompt-sync b/.worktrees/i18n-prompt-sync deleted file mode 160000 index 7d822f3be7..0000000000 --- a/.worktrees/i18n-prompt-sync +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7d822f3be7523bb5b6f3a874eed476b05ec545fd From e38955b2fa829cd2b8d8ef2e686731330079115c Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Wed, 22 Jul 2026 03:06:01 -0700 Subject: [PATCH 073/368] docs(i18n): re-translate cds/postmortem batch with the prompt-v4 pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 22 篇(core-data-structures 18、postmortem 3、rfc/README)译文按 v4 基线重出;机械核对零异常;rfc/README.zh 页内锚点按门禁规则改回 英文侧锚名。 --- docs/core-data-structures/approval.i18n.yaml | 2 +- docs/core-data-structures/approval.zh.md | 16 ++--- docs/core-data-structures/bash.i18n.yaml | 2 +- docs/core-data-structures/bash.zh.md | 24 +++---- .../code-runtime.i18n.yaml | 2 +- docs/core-data-structures/code-runtime.zh.md | 14 ++-- .../core-data-structures/compaction.i18n.yaml | 2 +- docs/core-data-structures/compaction.zh.md | 18 ++--- .../core-data-structures/filesystem.i18n.yaml | 2 +- docs/core-data-structures/filesystem.zh.md | 32 ++++----- .../llm-streaming.i18n.yaml | 2 +- docs/core-data-structures/llm-streaming.zh.md | 20 +++--- .../persistence.i18n.yaml | 2 +- docs/core-data-structures/persistence.zh.md | 20 +++--- docs/core-data-structures/sandbox.i18n.yaml | 2 +- docs/core-data-structures/sandbox.zh.md | 18 ++--- docs/core-data-structures/scope.i18n.yaml | 2 +- docs/core-data-structures/scope.zh.md | 8 +-- .../session-query.i18n.yaml | 2 +- docs/core-data-structures/session-query.zh.md | 8 +-- docs/core-data-structures/session.i18n.yaml | 2 +- docs/core-data-structures/session.zh.md | 44 ++++++------- docs/core-data-structures/skills.i18n.yaml | 2 +- docs/core-data-structures/skills.zh.md | 26 ++++---- docs/core-data-structures/subagent.i18n.yaml | 2 +- docs/core-data-structures/subagent.zh.md | 28 ++++---- .../system-prompt.i18n.yaml | 2 +- docs/core-data-structures/system-prompt.zh.md | 10 +-- docs/core-data-structures/tools.i18n.yaml | 2 +- docs/core-data-structures/tools.zh.md | 44 ++++++------- .../user-interaction.i18n.yaml | 2 +- .../user-interaction.zh.md | 12 ++-- docs/core-data-structures/web.i18n.yaml | 2 +- docs/core-data-structures/web.zh.md | 22 +++---- docs/core-data-structures/workflow.i18n.yaml | 2 +- docs/core-data-structures/workflow.zh.md | 16 ++--- ...-acp-default-export-drops-inject.i18n.yaml | 2 +- ...0001-acp-default-export-drops-inject.zh.md | 66 +++++++++---------- ...ession-disabled-filesystem-tools.i18n.yaml | 2 +- ...expression-disabled-filesystem-tools.zh.md | 34 +++++----- docs/postmortem/README.i18n.yaml | 2 +- docs/postmortem/README.zh.md | 12 ++-- docs/rfc/README.i18n.yaml | 2 +- docs/rfc/README.zh.md | 62 ++++++++--------- 44 files changed, 299 insertions(+), 299 deletions(-) diff --git a/docs/core-data-structures/approval.i18n.yaml b/docs/core-data-structures/approval.i18n.yaml index f51b3ab961..9a644ee85a 100644 --- a/docs/core-data-structures/approval.i18n.yaml +++ b/docs/core-data-structures/approval.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write approval.md: 772582955145092f3d483c297f7704b2b8506375 -approval.zh.md: dc45e1c6969099a2b285b4da071153510356acce +approval.zh.md: 706613b84784d81cf112622059c755e815c23f16 diff --git a/docs/core-data-structures/approval.zh.md b/docs/core-data-structures/approval.zh.md index dc45e1c696..706613b847 100644 --- a/docs/core-data-structures/approval.zh.md +++ b/docs/core-data-structures/approval.zh.md @@ -2,19 +2,19 @@ [English](approval.md) | 中文 -[dsh-user-approval](../../packages/ui/user-approval) 的用户审批 seam 回答一个问题:这个具体操作是否可以继续?它拥有共享的请求/结果词汇、`ctx.approval` 分发服务、`approval/request` 应答者 waterfall(瀑布式事件)、仅记录日志的审计事件对,以及按会话的 `ask`/`never` 策略。UI 通道(如 [dsh-acp](../../packages/ui/acp))提供应答者;调用方(如 [dsh-tools](../../packages/core/tools) 和 [dsh-tool-bash](../../packages/bash/tool-bash))消费封闭的结果,并在结果不是 `allowed-once` 时默认拒绝。 +[dsh-user-approval](../../packages/ui/user-approval) 的用户审批 seam 回答一个问题:这个具体操作是否可以继续?它拥有共享的请求/结果词汇、`ctx.approval` 分发服务、`approval/request` 应答者 waterfall(瀑布式事件)、仅记录日志的审计事件对,以及按会话的 `ask`/`never` 策略。UI 通道如 [dsh-acp](../../packages/ui/acp) 提供应答者;调用方如 [dsh-tools](../../packages/core/tools) 和 [dsh-tool-bash](../../packages/bash/tool-bash) 消费闭合的结果,除非结果为 `allowed-once`,否则一律拒绝。 源码:[`packages/ui/user-approval/src/index.ts`](../../packages/ui/user-approval/src/index.ts) ## 标识与结果 -每个请求获得一个新的 `ApprovalRequestId`。该品牌类型将 `approval/asked` 与 `approval/decided` 审计事件配对,同时防止审批 id 与工具调用、会话或 agent id 混用。 +每个请求获得一个全新的 `ApprovalRequestId`。该品牌类型将 `approval/asked` 和 `approval/decided` 审计事件配对,同时确保审批 id 不会与 tool-call、session 或 agent id 混用。 ```ts type-equiv type ApprovalRequestId = Branded<'ApprovalRequestId'> ``` -`ApprovalOutcome` 是封闭的,且默认拒绝。`allowed-once` 仅授权被询问的那个操作;调用方在遇到 `rejected`、`cancelled` 和 `unavailable` 时一律拒绝。缺失的、不拥有该请求的、抛出异常的或不符合规范的应答者会产生 `unavailable`,而不是放行。 +`ApprovalOutcome` 是闭合的,且默认拒绝。`allowed-once` 仅授权所询问的那一个操作;调用方对 `rejected`、`cancelled` 和 `unavailable` 均执行拒绝。缺失、无所有权、抛异常或不合规的应答者会产生 `unavailable`,而非放行。 ```ts type-equiv type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable' @@ -22,17 +22,17 @@ type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable' ## 按会话策略 -`ApprovalPolicy` 决定在交互式应答者运行之前发生什么。`ask` 委托给组合的应答者链,其无应答默认值为 `unavailable`;`never` 确定性地返回 `rejected`,不分发任何应答者。生效值取会话日志中最后一条 `approval/policy` 事件,回退到服务配置。`setApprovalPolicy(session, policy)` 是唯一的写入路径,因此回放能重建覆盖值。 +`ApprovalPolicy` 决定在交互式应答者运行之前发生什么。`ask` 委托给组合的应答者链,链的无应答默认值为 `unavailable`;`never` 确定性地返回 `rejected`,不分发任何应答者。生效值为会话日志中最后一条 `approval/policy` 事件,回退到服务配置。`setApprovalPolicy(session, policy)` 是唯一的写入路径,因此回放能重建覆盖值。 ```ts type-equiv type ApprovalPolicy = 'ask' | 'never' ``` -提示词段落会声明 `never` 的确定性行为,并用服务自有的标记记录当前策略。重启后,pre-step 叙述器从已记录的请求头中读取该标记;它不从部署 persona 行文中推断状态。ACP 中空闲时的策略切换会被桥接层持有到下一次 `turn/start`,因为审批审计事件和策略事件必须保持在轮次内,以确保持久回放的正确性。 +提示词段落会声明 `never` 的确定性行为,并以服务自有的标记记录当前策略。重启后,步骤前叙述器从已记录的请求头中读取该标记,而非从部署 persona 行文中推断状态。ACP 空闲切换会在 bridge 中保持,直到下一个 `turn/start`,因为审批审计和策略事件必须保持在轮次内,以确保持久回放的正确性。 ## 审批请求 -`ApprovalRequest` 足够精确地标识 agent 和工具操作,以便路由和审计该问题。它有意省略工具参数:应答者通过 `callId` 将提示附加到已流式输出的工具调用上,而不是渲染可能漂移的第二份副本。 +`ApprovalRequest` 以足够精确的方式标识 agent 和工具操作,以便路由和审计该问题。它有意省略工具参数:应答者通过 `callId` 将提示附加到已流式输出的工具调用上,而非渲染一份可能漂移的副本。 ```ts type-equiv interface ApprovalRequest { @@ -61,6 +61,6 @@ interface ApprovalRequest { ## 分发与审计 -`ctx.approval.request(req)` 要求发起请求的会话处于一个打开的轮次内。它追加 `approval/asked`,获取一个结果,追加匹配的 `approval/decided`,然后以该结果 resolve。`never` 策略在服务内部、waterfall 分发之前就已强制执行,因此即使后来用 `prepend` 注册的应答者也无法绕过它。应答者在拥有该请求时返回结果,否则调用 `next()` 委托;第一个应答占据唯一的决策槽位。 +`ctx.approval.request(req)` 要求发起请求的会话处于一个打开的轮次内。它追加 `approval/asked`,获取一个结果,追加对应的 `approval/decided`,然后以该结果 resolve。`never` 策略在服务内部、waterfall 分发之前强制执行,因此即使后来以 `prepend` 注册的应答者也无法绕过它。应答者在拥有该请求时返回结果,否则调用 `next()` 委托;第一个应答占据唯一的决策槽位。 -审计事件仅记录日志,不进入模型 transcript(文本记录)。模型可见的行为是调用方派生的工具结果,而请求头记录的是模型实际看到的提示词策略。服务 dispose(资源释放)时会同时移除其提示词段落和 pre-step 叙述器;应答者监听器独立地通过 effect 绑定到其所属插件。 +审计事件仅写入日志,不进入模型 transcript(文本记录)。模型可见的行为是调用方派生的工具结果,而请求头记录的是模型实际看到的提示词策略。服务 dispose(资源释放)时会一并移除其提示词段落和步骤前叙述器;应答者监听器独立地通过 effect 绑定到其所属插件。 diff --git a/docs/core-data-structures/bash.i18n.yaml b/docs/core-data-structures/bash.i18n.yaml index 323300cc4e..eba38e8f77 100644 --- a/docs/core-data-structures/bash.i18n.yaml +++ b/docs/core-data-structures/bash.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write bash.md: 7b5c779b832ef5be6591e626980f7f22db54f239 -bash.zh.md: 519a7bf973fdf9fd9d7c4be2cc6ebf77e576135d +bash.zh.md: 8a209b4853e44d1846460c41f4d5b9a43082a65b diff --git a/docs/core-data-structures/bash.zh.md b/docs/core-data-structures/bash.zh.md index 519a7bf973..8a209b4853 100644 --- a/docs/core-data-structures/bash.zh.md +++ b/docs/core-data-structures/bash.zh.md @@ -2,13 +2,13 @@ [English](bash.md) | 中文 -Bash 执行 seam:典型的[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md) 示例,拆分为三个包(package):接口([dsh-bash](../../packages/bash/bash),`ctx.bash`)、实现([dsh-bash-local](../../packages/bash/bash-local),本地子进程)、消费方([dsh-tool-bash](../../packages/bash/tool-bash),`bash`/`bash_output`/`bash_kill` 工具 schema)。Bash 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此,而非 [core.md](core.md)。沙箱化、容器化或远程后端只需作为兄弟包实现同一接口。 +Bash 执行 seam:典型的[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md) 示例,拆分为三个包(package):接口([dsh-bash](../../packages/bash/bash),`ctx.bash`)、实现([dsh-bash-local](../../packages/bash/bash-local),本地子进程)和消费方([dsh-tool-bash](../../packages/bash/tool-bash),`bash`/`bash_output`/`bash_kill` 工具 schema)。Bash 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此处而非 [core.md](core.md)。沙箱化、容器化或远程后端是实现同一接口的兄弟包。 源码:[`packages/bash/bash/src/types.ts`](../../packages/bash/bash/src/types.ts) ## 请求与规格:`resolve()` 拆分 -该 seam 将**面向模型/插件的请求**(`workdir`/`timeoutMs` 可选,由配置填充)与**执行器实际执行的完全解析规格**(这些字段为必填)分开。工具层在二者之间调用 `ctx.bash.resolve(request)`。这是本仓库「包边界处显式优于隐式」规则的具体体现:读到一个 `BashExecSpec` 的人永远不必猜测工作目录从何而来。 +该 seam 将**面向模型/插件的请求**(`workdir`/`timeoutMs` 可选,由配置填充)与**执行器实际执行的完全解析规格**(这些字段为必填)分离。工具层在二者之间调用 `ctx.bash.resolve(request)`。这是本仓库「在包边界处显式优于隐式」规则的具体体现:阅读 `BashExecSpec` 的人永远不会疑惑工作目录从何而来。 ```ts type-equiv interface BashExecRequest { @@ -108,15 +108,15 @@ interface BashExecSpec { } ``` -`owner` token 是隔离键:执行器存储它但从不解释它(访问策略是消费方的职责),因此一个 agent 启动的后台任务不会被跨会话读取。必填但可空的字段设计使得遗忘 owner 会表现为一个可见的 `undefined`,而非一个静默无主的任务。 +`owner` token 是隔离键:执行器存储它但从不解释它(访问策略是消费方的职责),因此一个 agent 启动的后台任务不会被跨会话读取。必填但可空的字段使遗忘的 owner 成为一个可见的 `undefined`,而非一个静默无主的任务。 -受信的进程内插件使用 `stdin` 和 `env` 传递钩子载荷和钩子专用变量。面向模型的 bash 工具从其命名 schema 字段构造请求,不暴露这两个输入,因为 shell 语法已提供等价能力;测试会防止未来出现 `...args` 展开。这是请求形状纪律,而非安全边界:`dsh-bash-local` 无论这些字段如何都会清洗环境凭证,然后叠加调用方已持有的显式值。详见 [bash stdin/env RFC](../rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md)。 +受信的进程内插件使用 `stdin` 和 `env` 传递钩子载荷与钩子专用变量。面向模型的 bash 工具从其命名的 schema 字段构造请求,不暴露这两个输入,因为 shell 语法本身已提供等价能力;测试防止未来出现 `...args` 展开。这是请求形状的纪律约束,而非安全边界:`dsh-bash-local` 无论这些字段如何都会清洗环境凭证,然后叠加调用方已持有的显式值。见 [bash stdin/env RFC](../rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md)。 -该 seam 处理的两个 id 都是[品牌化](core.md)的(零成本 `string` 品牌,与 `SessionId`/`AgentId` 同一套机制):`BashTaskId`(被追踪的后台任务,由本地执行器生成 `bash-N`)和 `OwnerToken`(不透明的隔离键)。`OwnerToken` 刻意是与 `SessionId` **不同**的品牌,而非别名:bash seam 是一个能力 seam,它不得知道 owner token *意味着什么*,因此从不导入 `dsh-session` 的词汇。将所属 agent 的 `SessionId` 转换为 `OwnerToken` 的唯一边界是 `dsh-tool-bash` 消费方。对两者都做品牌化,可以防止裸 `string`(或在需要 `OwnerToken` 的位置传入 `BashTaskId`,反之亦然)在面向模型的 `task_id` 路径上通过类型检查。 +该 seam 处理的两个 id 都是[品牌化的](core.md)(零成本 `string` 品牌,与 `SessionId`/`AgentId` 相同的机制):`BashTaskId`(被跟踪的后台任务,由本地执行器生成 `bash-N`)和 `OwnerToken`(不透明的隔离键)。`OwnerToken` 刻意是一个与 `SessionId` **不同**的品牌,而非别名:bash seam 是一个能力 seam,不得知道 owner token *意味着*什么,因此它从不导入 `dsh-session` 的词汇。`dsh-tool-bash` 消费方是唯一将拥有者 agent 的 `SessionId` 转换为 `OwnerToken` 的边界。对两者施加品牌化,可以防止裸 `string`(或在需要 `OwnerToken` 的地方传入 `BashTaskId`,反之亦然)在面向模型的 `task_id` 路径上通过类型检查。 ## 前台运行:`BashRunResult` -一次已完成(或被终止)的前台运行的结果。正交的结果**独立报告**:一个进程可以既超时又以 exit 0 退出(因为它捕获了信号),因此 `timedOut`、`aborted`、`signal` 和 `exitCode` 各自独立为一个字段;调用方永远不会把一次被截断的运行误读为干净的成功。 +一次已完成(或被终止)的前台运行的结果。正交的结果**独立报告**:一个进程可以同时超时并以退出码 0 退出(因为它捕获了信号),因此 `timedOut`、`aborted`、`signal` 和 `exitCode` 各自独立为一个字段;调用方永远不会把一次被截断的运行误读为干净的成功。 ```ts type-equiv interface BashRunResult { @@ -156,9 +156,9 @@ interface CollectedOutput { ## 文件沙箱:`BashSandboxInfo` -消费沙箱的执行器(`dsh-bash-sandbox`)通过 `BashExecutor.sandboxMode` 暴露其配置的回退模式。工具层折叠每个 agent 会话的持久 `bash/sandbox-mode` 覆盖,将生效模式盖章到请求上,并可能为一次用户批准的严格更宽调用替换它。工具层刻意不声明当前模式,也不叙述切换过程;拒绝结果会指明该命令实际运行时所处的模式。模式/强制词汇由 [`@deepseek-ai/dsh-sandbox` seam](sandbox.md) 拥有并编目,其提供方包装执行器的 argv;模式仅管辖文件效果,不管网络或进程可见性。 +消费沙箱的执行器(`dsh-bash-sandbox`)通过 `BashExecutor.sandboxMode` 暴露其配置的回退模式。工具层折叠每个 agent 会话的持久 `bash/sandbox-mode` 覆盖,将生效模式印到请求上,并可为一次用户批准的严格更宽调用替换它。它刻意既不声明当前模式也不叙述切换过程;拒绝结果会指明该命令实际运行时所处的模式。模式/执行词汇由 [`@deepseek-ai/dsh-sandbox` seam](sandbox.md) 拥有并编目,其提供方包装执行器的 argv;模式仅管控文件效果,不涉及网络或进程可见性。 -沙箱化运行始终在 `BashRunResult.sandbox` 上报告其执行时的事实:`denied` 是执行器对「失败由沙箱引起」的保守分类(一次失败退出且 stderr 带有文件系统权限签名——从不是干净退出或信号终止),从收集的 stderr 尾部读取;`enforcement` 报告所选后端对该模式文件效果的治理完整度(`SandboxEnforcement = 'full' | 'partial'`——当较旧的 Landlock ABI 仅治理所请求访问的子集时为 `partial`;`danger-full-access` 下不存在,因为什么都没被限制);`runnerFailed` 标记与拒绝相反的情况——沙箱 runner 本身失败,命令从未运行(仅在已结算的后台任务上盖章;前台运行通过抛出 `SANDBOX_UNAVAILABLE` 错误暴露同一状况): +沙箱化运行始终在 `BashRunResult.sandbox` 上报告其执行时的事实:`denied` 是执行器对失败的保守分类——判定为沙箱导致(退出失败且 stderr 携带文件系统权限特征——从不是干净退出或信号终止),从收集到的 stderr 尾部读取;`enforcement` 报告所选后端对该模式文件效果的管控完整程度(`SandboxEnforcement = 'full' | 'partial'`:`partial` 表示较旧的 Landlock ABI 仅管控所请求访问的子集;`danger-full-access` 下不存在此字段,因为没有任何限制);`runnerFailed` 标记与拒绝相反的情况——沙箱运行器本身失败、命令从未执行(仅在已结算的后台任务上标记;前台运行通过抛出 `SANDBOX_UNAVAILABLE` 错误暴露同一状况): ```ts type-equiv interface BashSandboxInfo { @@ -195,11 +195,11 @@ interface BashSandboxInfo { } ``` -还有一个词汇完成整幅图景:`SANDBOX_UNAVAILABLE` 错误码(由 [sandbox seam](sandbox.md) 拥有)是 `ctx.sandbox` 提供方在受限模式没有可用后端时抛出的——执行器将其传播。所选 runner 拒绝其 profile 也会到达同一个快速失败的前台错误;已结算的后台任务则记录 `runnerFailed`。模型在结果中收到拒绝/runner 事实,仅在拒绝标记指明模式时才得知生效模式,并可通过 `sandbox_permissions` 加 `justification` 请求一次严格更宽的重试;`ctx.approval` 必须在任何执行之前批准该确切调用。完整的策略与切换设计见 [sandbox RFC](../rfc/implemented/feature/2026-07-06-sandbox.md)。 +还有一个词汇完成整幅图景:`SANDBOX_UNAVAILABLE` 错误码(由 [sandbox seam](sandbox.md) 拥有)是 `ctx.sandbox` 提供方在受限模式没有可用后端时抛出的错误,执行器将其传播。所选运行器拒绝其 profile 时也触发同一快速失败的前台错误;已结算的后台任务则记录 `runnerFailed`。模型在结果中接收拒绝/运行器事实,仅在拒绝标记指明模式时才获知生效模式,并可通过 `sandbox_permissions` 加 `justification` 请求一次严格更宽的重试;`ctx.approval` 必须在任何执行之前批准该确切调用。完整的策略与切换设计见 [sandbox RFC](../rfc/implemented/feature/2026-07-06-sandbox.md)。 ## 后台任务:`BashTask` -通过 `start()` 启动的长时间运行命令被追踪为 `BashTask`。`BashTaskStatus` 为 `'running' | 'completed' | 'killed'`;`done` 在底层进程关闭时 resolve,从不 reject。沙箱化执行器在任务结算后盖章 `sandbox`(分类针对已结算任务收集的 stderr 运行),因此该字段在运行中以及非沙箱化执行器下不存在。 +通过 `start()` 启动的长时间运行命令被跟踪为 `BashTask`。`BashTaskStatus` 为 `'running' | 'completed' | 'killed'`;`done` 在底层进程关闭时 resolve,从不 reject。沙箱化执行器在任务结算后标记 `sandbox`(分类针对已结算任务收集到的 stderr 运行),因此该字段在运行中以及非沙箱化执行器下不存在。 ```ts type-equiv interface BashTask { @@ -224,7 +224,7 @@ interface BashTask { } ``` -`readOutput()` 返回增量的 `BashTaskRead`:自上次读取以来产生的输出,附带一个 `lossy` 标志表示截断丢弃了未读字节: +`readOutput()` 返回增量的 `BashTaskRead`:自上次读取以来产生的输出,附带一个 `lossy` 标志指示截断是否丢弃了未读字节: ```ts type-equiv interface BashTaskRead { @@ -242,4 +242,4 @@ interface BashTaskRead { ## 服务 -`BashExecutor`(`ctx.bash`,抽象——定义于 [`packages/bash/bash/src/index.ts`](../../packages/bash/bash/src/index.ts))镜像 `LlmService`/`LlmAdapter` 的拆分:`resolve`(请求→规格)、`run`(前台)、`start`(后台)、`get`/`ownerOf`/`list`/`readOutput`/`kill`,以及 `onTaskDone`(`BashTaskListener` 完成回调)。spawn 的命令获得一个**清洗后的 env**(丢弃 `*KEY*`/`*SECRET*`/`*TOKEN*`),溢出文件使用一个权限为 0700 的私有目录(随机文件名、仅所有者可打开)——模型输出永远拿不到宿主环境或可预测路径。提供这一切的实现是 `dsh-bash-local`;调用它的面向模型的 `bash`/`bash_output`/`bash_kill` schema 位于 `dsh-tool-bash`(并通过[工具呈现词汇](tools.md#tool-presentation-ui-vocabulary)以终端形式展示)。 +`BashExecutor`(`ctx.bash`,抽象——定义于 [`packages/bash/bash/src/index.ts`](../../packages/bash/bash/src/index.ts))遵循 `LlmService`/`LlmAdapter` 的拆分模式:`resolve`(请求→规格)、`run`(前台)、`start`(后台)、`get`/`ownerOf`/`list`/`readOutput`/`kill`,以及 `onTaskDone`(`BashTaskListener` 完成回调)。spawn 的命令获得一个**清洗后的 env**(丢弃 `*KEY*`/`*SECRET*`/`*TOKEN*`),溢出文件使用一个权限为 0700 的私有目录(随机文件名、仅所有者可打开)。模型输出永远不会获得环境变量或可预测路径。提供这一切的实现是 `dsh-bash-local`;调用它的面向模型的 `bash`/`bash_output`/`bash_kill` schema 位于 `dsh-tool-bash`(并通过[工具展示词汇](tools.md#tool-presentation-ui-vocabulary)作为终端呈现)。 diff --git a/docs/core-data-structures/code-runtime.i18n.yaml b/docs/core-data-structures/code-runtime.i18n.yaml index b2c8f97ae1..7c9ef2a7a3 100644 --- a/docs/core-data-structures/code-runtime.i18n.yaml +++ b/docs/core-data-structures/code-runtime.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write code-runtime.md: 28152947d0853fb10228c472ca3e121e77b7b598 -code-runtime.zh.md: f12816fd5392f1efff3a1faeee232fb004142f37 +code-runtime.zh.md: 8270d12e7cce8c3b2443da9de268d95cf9d692d8 diff --git a/docs/core-data-structures/code-runtime.zh.md b/docs/core-data-structures/code-runtime.zh.md index f12816fd53..8270d12e7c 100644 --- a/docs/core-data-structures/code-runtime.zh.md +++ b/docs/core-data-structures/code-runtime.zh.md @@ -2,13 +2,13 @@ [English](code-runtime.md) | 中文 -代码执行 seam:一个[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md),其接口([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)负责运行一段模型编写的程序,对接宿主提供的异步绑定,并报告程序打印和返回的内容。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此处而非 [core.md](core.md)。后端因执行基底和源语言而异,二者均为服务上的只读描述符;worker-thread 后端与工具注册表消费方(Code Mode)在 [Code Mode RFC](../rfc/implemented/feature/2026-06-15-code-mode.md) 中规定。 +代码执行 seam:一个[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md),其接口([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)运行一段模型编写的程序,对接宿主提供的异步绑定,并报告程序的打印输出与返回值。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此,而非 [core.md](core.md)。后端因执行基底和源语言而异,二者都是服务上的只读描述符;worker-thread 后端与工具注册表消费方(Code Mode)在 [Code Mode RFC](../rfc/implemented/feature/2026-06-15-code-mode.md) 中定义。 源码:[`packages/code-runtime/code-runtime/src/types.ts`](../../packages/code-runtime/code-runtime/src/types.ts) ## 运行:请求进,结果出 -`CodeRunRequest` 携带**运行时所需的全部信息**。按照「包(package)seam 处显式优于隐式」的规则,默认值(时间预算、输出上限)由实现的已校验配置提供,绝不是 `run()` 内部隐藏的 `??`: +`CodeRunRequest` 携带**运行时所需的一切**。按照「包(package)边界处显式优于隐式」的规则,默认值(时间预算、输出上限)来自实现的已校验配置,绝不是 `run()` 内部隐藏的 `??`: ```ts type-equiv interface CodeRunRequest { @@ -30,7 +30,7 @@ interface CodeRunRequest { } ``` -结果将错误报告为一个**字段**,而非 `run()` 的 rejection:报告程序失败是调用方的职责,不是异常路径(与 `BashExecutor.run` 的 resolve-on-failure 契约一致): +结果将错误报告为一个**字段**,而非 `run()` 的 rejection。报告失败的程序是调用方的职责,不走异常路径(与 `BashExecutor.run` 的 resolve-on-failure 契约一致): ```ts type-equiv interface CodeRunResult { @@ -50,7 +50,7 @@ interface CodeRunResult { ## 绑定:宿主函数作为程序全局变量 -每个 `CodeBindingNamespace` 在程序内部成为一个由异步可调用成员组成的全局对象(Code Mode 消费方传入一个:`tools`)。参数与解析值必须可 structured-clone:运行时可能跨序列化边界桥接调用。运行时将绑定名视为不可信输入(`__proto__` 是普通的 own property,绝不会产生原型碰撞): +每个 `CodeBindingNamespace` 在程序内成为一个由异步可调用函数组成的全局对象(Code Mode 消费方传入一个:`tools`)。参数与返回值必须可 structured-clone(运行时可能跨序列化边界桥接调用),且运行时将绑定名视为不可信输入(`__proto__` 是普通自有属性,绝不会发生原型碰撞): ```ts type-equiv interface CodeBindingNamespace { @@ -67,9 +67,9 @@ type CodeBindingFunction = (args: unknown) => Promise<unknown> ## 捕获的输出与失败分类体系 -日志是按发出顺序排列的纯字符串。运行时捕获程序的 console 和流输出,但通道与 console 方法的元数据不属于 seam 的一部分,因为消费方只渲染文本。实现对聚合输出设上限,并在输出内标记截断。 +日志是按发出顺序排列的纯字符串。运行时捕获程序的 console 与流输出,但通道和 console 方法的元数据不属于 seam 的一部分,因为消费方只渲染文本。实现对聚合输出设上限,并在输出内标记截断。 -失败类型是**正交的结果,独立报告**(见 [defensive-patterns](../defensive-patterns.md)):预算耗尽不是异常,中止不是超时,基底崩溃(如 OOM)也不是二者之一: +失败类型是**正交的结果,独立报告**(见 [defensive-patterns](../defensive-patterns.md)):预算耗尽不是异常,中止不是超时,基底崩溃(如 OOM)也不是二者中的任何一个: ```ts type-equiv interface CodeRunFailure { @@ -82,4 +82,4 @@ interface CodeRunFailure { ## 服务 -`CodeRuntime`(`ctx.codeRuntime`,抽象服务,定义于 [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts))是 `run(request)` 加两个只读描述符:`language`(程序必须使用的语言:`'typescript'` 是已知值;生成语言相关展示的消费方据此分支,遇到无法展示的语言时应显式报错)和 `isolation`(执行基底:`'worker-thread'`、`'process'`、`'container'`;是诊断标签,**不是安全承诺**)。实现必须保证各次运行彼此隔离(无跨运行状态),并在 dispose(资源释放)时达到静止状态:进行中的运行在 teardown 完成前被终止并 await。 +`CodeRuntime`(`ctx.codeRuntime`,抽象服务,定义于 [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts))由 `run(request)` 加两个只读描述符组成:`language`(程序必须使用的语言,`'typescript'` 是已知值;生成语言相关展示的消费方据此切换,遇到无法展示的语言时应显式报错)和 `isolation`(执行基底,`'worker-thread'`、`'process'`、`'container'`;仅为诊断标签,**不构成安全承诺**)。实现必须保证各次运行彼此隔离(无跨运行状态),且 dispose(资源释放)至静默:进行中的运行在 teardown 完成前被终止并等待结束。 diff --git a/docs/core-data-structures/compaction.i18n.yaml b/docs/core-data-structures/compaction.i18n.yaml index a5dda25c68..a0a32275e6 100644 --- a/docs/core-data-structures/compaction.i18n.yaml +++ b/docs/core-data-structures/compaction.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write compaction.md: e82cc103932ad05e68bc5311dec23c3f2c1a7ce4 -compaction.zh.md: 889cdba416767e90592359361fc0f65bcb2472c3 +compaction.zh.md: ad8b524a1984357b5bb911b59300a194407bdbb9 diff --git a/docs/core-data-structures/compaction.zh.md b/docs/core-data-structures/compaction.zh.md index 889cdba416..ad8b524a19 100644 --- a/docs/core-data-structures/compaction.zh.md +++ b/docs/core-data-structures/compaction.zh.md @@ -1,28 +1,28 @@ -# 压缩 +# 上下文压缩 [English](compaction.md) | 中文 -压缩(compaction)seam 是一个[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md),按 bash 模式拆分:接口([dsh-compact](../../packages/compact/compact),`ctx.compact`)、实现(后端,如 [dsh-compact-basic](../../packages/compact/compact-basic))、消费方(一个 `/compact` 工具,暂缓)。压缩是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此,而非 [core.md](core.md)。基于 tokenizer 或模板的后端是实现同一接口的兄弟包。与 bash 不同的是,该接口必然依赖 `dsh-session` 和 `dsh-llm`:它的动词定义在 `Session` 之上,输出是 `ContentBlock` 词汇(见[压缩能力 seam RFC](../rfc/implemented/feature/2026-06-18-compaction-capability-seam.md))。 +上下文压缩(context compaction)的 seam 是一个[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md),按 bash 式拆分:接口([dsh-compact](../../packages/compact/compact),`ctx.compact`)、实现(后端,如 [dsh-compact-basic](../../packages/compact/compact-basic))、消费方(一个 `/compact` 工具,暂缓实现)。上下文压缩是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此处,而非 [core.md](core.md)。基于 tokenizer 或模板的后端是实现同一接口的兄弟包。与 bash 不同的是,该接口必然依赖 `dsh-session` 和 `dsh-llm`:它的动词定义在 `Session` 之上,输出使用 `ContentBlock` 词汇(见[上下文压缩能力 seam RFC](../rfc/implemented/feature/2026-06-18-compaction-capability-seam.md))。 源码:[`packages/compact/compact/src/types.ts`](../../packages/compact/compact/src/types.ts) ## `compact/*` 会话事件 -压缩通过声明合并为 [`SessionEventMap`](session.md) 扩展了三种事件类型。三者均为**仅日志**事件:它们记录压缩锁及其来源信息,永远不进入 surface。`SurfaceEventType` 被刻意**不**扩展(只有产生消息的事件才到达模型),因此摘要本身搭载在一条单独的 `user/message` 上,带有 `surfaceOp: { op: 'replace', start, end }`——唯一的 surface 变更。关于为何复用 `user/message` 是诚实的做法而非变通手段,见 RFC。 +上下文压缩通过声明合并为 [`SessionEventMap`](session.md) 扩展了三种事件类型。三者均为**仅日志**事件:它们记录压缩锁及其来源信息,永远不进入 surface。`SurfaceEventType` 被刻意**不**扩展(只有产生消息的事件才到达模型),因此摘要本身搭载在一条独立的 `user/message` 上,带有 `surfaceOp: { op: 'replace', start, end }`——唯一的 surface 变更。关于为何复用 `user/message` 是诚实的做法而非权宜之计,见 RFC。 | 事件 | 载荷 | 作用 | |---|---|---| | `compact/start` | `{ turn }` | 获取日志记录的锁 | -| `compact/summary` | `{ summary, shadowedRange, shadowedSeqs, shadowedTokenCount, model, maxTokens? }` | 来源信息:摘要块、被遮蔽的 surface 边界对(`start`/`end` seq——位置跨度,非数值区间)、按 surface 顺序排列的被遮蔽 seq、估算 token 数量,以及摘要调用的信封(`model`,加上生效时的生成上限)——记录下来以便从日志 + 代码重建一次性请求(可重建性 RFC) | -| `compact/end` | `{ turn, error? }` | 释放锁(摘要生成抛出异常时设置 `error`) | +| `compact/summary` | `{ summary, shadowedRange, shadowedSeqs, shadowedTokenCount, model, maxTokens? }` | 来源信息:摘要块、被遮蔽的 surface 边界对(`start`/`end` seq,是位置跨度而非数值区间)、按 surface 顺序排列的被遮蔽 seq、估算的 token 数量,以及摘要调用的信封(`model`,加上生效时的生成上限)。记录这些信息使得单次请求可从日志加代码重建(reconstructability RFC) | +| `compact/end` | `{ turn, error? }` | 释放锁(摘要调用抛出异常时设置 `error`) | -锁括住**整个**操作:先追加 `compact/start`,然后执行摘要生成、落入 `compact/summary` 来源记录和 `user/message` 替换,最后才追加 `compact/end`。最后释放锁意味着操作中途崩溃会变成一个可检测的遗留锁(有 `compact/start` 而无匹配的 `compact/end`),而不是一个虚假声称压缩已完成的 `compact/end`。 +锁括住**整个**操作:先追加 `compact/start`,然后执行摘要生成、写入 `compact/summary` 来源记录与 `user/message` 替换,最后才追加 `compact/end`。最后释放锁意味着操作中途崩溃会表现为可检测的遗留锁(有 `compact/start` 而无匹配的 `compact/end`),而非一个虚假声称压缩已完成的 `compact/end`。 这些变体在 `declare module '@deepseek-ai/dsh-session'` 块内合并,因此——与其他子页面上的顶层类型不同——它们不以漂移检查的 ` ```ts type-equiv ` 块粘贴(`verify-type-equiv` 提取器只按名称匹配顶层声明)。上方的载荷表即为目录条目;权威形状请循源码链接查看。 ## `CompactionResult` -一次成功的压缩返回给调用方的内容:三个追加的 `compact/*` 事件的 seq、摘要块,以及被遮蔽的范围/seq 加上估算 token 数量。 +一次成功的压缩返回给调用方的内容:三个追加的 `compact/*` 事件的 seq、摘要块,以及被遮蔽的范围/seq 和估算的 token 数量。 ```ts type-equiv interface CompactionResult { @@ -52,6 +52,6 @@ interface CompactionResult { ## 服务 -`CompactService` 暴露 `compactIfNeeded(...)` 用于压力触发的压缩(不需要压缩时返回 `null`),以及 `compactRegion(...)` 用于对显式的 surface 闭区间执行压缩。pre-step 调用方提供 agent、完整提示词、会话前缀和 abort signal;实现必须将该 signal 转发给摘要生成。估算、保留策略、事件排序和摘要生成均为后端策略。 +`CompactService` 暴露 `compactIfNeeded(...)` 用于压力触发的压缩(不需要压缩时返回 `null`),以及 `compactRegion(...)` 用于对显式的闭区间 surface 范围进行压缩。pre-step 调用方提供 agent、完整 prompt、会话前缀和 abort signal;实现必须将该 signal 转发给摘要生成。估算、保留策略、事件排序与摘要生成均为后端策略。 -自动压缩在串行的 `agent/pre-step` 时运行,位于步骤和请求推导之前,因此它可以替换 surface 节点,同时将 trace 事件保持在步骤之外。区域边界保留工具调用/结果的配对,但不保留完整轮次,允许一个超大轮次中较早关闭的步骤被压缩。保留策略与失败处理的细节由 `dsh-compact-basic` 负责。 +自动压缩在串行的 `agent/pre-step` 时运行,位于步骤和请求推导之前,因此可以在替换 surface 节点的同时将 trace 事件保持在步骤之外。区域边界保持工具调用/结果配对,但不保持完整轮次,允许一个超大轮次中已关闭的早期步骤被压缩。保留策略与失败处理的细节由 `dsh-compact-basic` 负责。 diff --git a/docs/core-data-structures/filesystem.i18n.yaml b/docs/core-data-structures/filesystem.i18n.yaml index 760bf4eda7..4e3d400339 100644 --- a/docs/core-data-structures/filesystem.i18n.yaml +++ b/docs/core-data-structures/filesystem.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write filesystem.md: 8bdc2323a0bf63588e01520926f093538fee4912 -filesystem.zh.md: 93ca9b26e054cadb40382391404573c95a1c8d05 +filesystem.zh.md: 1b636dd35e3c614d87973c617ea052058995e0e0 diff --git a/docs/core-data-structures/filesystem.zh.md b/docs/core-data-structures/filesystem.zh.md index 93ca9b26e0..1b636dd35e 100644 --- a/docs/core-data-structures/filesystem.zh.md +++ b/docs/core-data-structures/filesystem.zh.md @@ -2,15 +2,15 @@ [English](filesystem.md) | 中文 -可选的文件系统能力由四部分组成:[dsh-fs](../../packages/fs/fs) 拥有 `ctx.fs` 以及带可选版本守卫的原子文本操作,[dsh-fs-local](../../packages/fs/fs-local) 实现本地磁盘后端,[dsh-fs-policy](../../packages/fs/fs-policy) 通过事件(而非服务)添加观测状态与新鲜度规则,[dsh-tool-fs](../../packages/fs/tool-fs) 直接执行面向模型的 read/write/edit 调用并渲染窗口。它位于 agent loop 主干之外;替换后端不会改变策略或工具 schema。 +可选的文件系统能力由四个部分组成:[dsh-fs](../../packages/fs/fs) 拥有 `ctx.fs` 以及带可选版本守卫的原子文本操作;[dsh-fs-local](../../packages/fs/fs-local) 实现本地磁盘后端;[dsh-fs-policy](../../packages/fs/fs-policy) 通过事件(而非服务)添加观测状态与新鲜度规则;[dsh-tool-fs](../../packages/fs/tool-fs) 直接执行面向模型的 read/write/edit 调用并渲染窗口。它位于 agent loop(智能体循环)主干之外;替换后端不会改变策略或工具 schema。 -该模型是**加法式而非减法式**的:`ctx.fs` 本身就是一个完整、无约束的文本存储 seam(`write` 无条件创建或覆盖,`edit` 无条件替换字面文本)。`dsh-fs-policy` 是一个在此之上*添加*策略的插件,通过裁决 `fs/*` waterfall(瀑布式事件)实现;移除它只会留下裸提供方,而不会破坏工具,因为工具与策略之间没有方法级耦合。加载了 `dsh-tool-fs` 的部署预期同时加载 `dsh-fs-policy`,使默认行为为先读后写/编辑。 +该模型是**加法式而非减法式**的:`ctx.fs` 本身就是一个完整、无约束的文本存储 seam(`write` 无条件创建或覆盖,`edit` 无条件替换字面文本)。`dsh-fs-policy` 是一个插件,通过裁决 `fs/*` waterfall(瀑布式事件)在上层*叠加*策略;移除它只会暴露裸提供方,而不会破坏工具,因为工具与策略之间没有方法级耦合。加载了 `dsh-tool-fs` 的部署通常也应加载 `dsh-fs-policy`,使默认行为为「先读后写/编辑」。 提供方源码:[`packages/fs/fs/src/types.ts`](../../packages/fs/fs/src/types.ts) 与 [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts)。策略源码:[`packages/fs/fs-policy/src/types.ts`](../../packages/fs/fs-policy/src/types.ts)。读取渲染源码:[`packages/fs/tool-fs/src/read-render.ts`](../../packages/fs/tool-fs/src/read-render.ts)。 ## 目标标识与元数据(提供方 seam) -每个操作首先将用户提供的路径解析为一个不透明的后端目标。消费方可以展示 `displayPath`,但不得解析 `targetKey`(一个品牌化的不透明 id),也不得假设它是本地绝对路径。 +每个操作首先将用户提供的路径解析为不透明的后端目标。消费方可以显示 `displayPath`,但禁止解析 `targetKey`(一个品牌化的不透明 id),也不得假设它是本地绝对路径。 ```ts type-equiv interface FsTarget { @@ -19,7 +19,7 @@ interface FsTarget { } ``` -后端拥有文件版本 token:即 write/edit 所守卫的新鲜度 token。策略插件存储它们用于陈旧检查;消费方不解释其含义。两个 id 都是品牌化的不透明字符串。 +后端拥有文件版本 token,即 write/edit 所守卫的新鲜度 token。策略插件存储它们以进行陈旧检查;消费方不解释其内容。两个 id 都是品牌化的不透明字符串。 ```ts type-equiv type FsTargetKey = Branded<'FsTargetKey'> @@ -29,7 +29,7 @@ type FsTargetKey = Branded<'FsTargetKey'> type FsVersion = Branded<'FsVersion'> ``` -`stat` 返回元数据(从不返回内容),目标不存在时返回 `undefined`。`type` 让工具在读取前拒绝目录/特殊文件,`size` 让工具无需通过失败探测即可选择 `readText` 还是 `streamText`。 +`stat` 返回元数据(从不返回内容),目标不存在时返回 `undefined`。`type` 让工具在读取前拒绝目录或特殊文件;`size` 让工具无需通过失败探测即可选择 `readText` 还是 `streamText`。 ```ts type-equiv interface FsInfo { @@ -39,7 +39,7 @@ interface FsInfo { } ``` -`listDir` 以稳定的名称顺序返回直接子条目。每个条目携带子项的 basename、类型、已解析的目标,以及后端能廉价报告时的元数据。它不得读取文件内容,因此 `size` 仅适用于普通文件,`version` 来源于元数据。损坏或消失的子项可以作为 `other` 返回且不带元数据;列举或解析子项元数据时的权限或后端 I/O 失败会以 `FS_PERMISSION_DENIED` 或 `FS_IO_ERROR` 使整个列举失败。 +`listDir` 按稳定的名称顺序返回直接子条目。每个条目携带子项的 basename、类型、已解析目标,以及后端能报告时的廉价元数据。它禁止读取文件内容,因此 `size` 仅用于普通文件,`version` 来自元数据。已损坏或已消失的子项可以作为 `other` 返回且不带元数据;列出或解析子项元数据时的权限或后端 I/O 失败会以 `FS_PERMISSION_DENIED` 或 `FS_IO_ERROR` 使整个列表操作失败。 ```ts type-equiv interface FsDirEntry { @@ -53,7 +53,7 @@ interface FsDirEntry { ## 写入与编辑守卫(提供方 seam) -`writeText` 和 `editText` 都以可选方式接受版本守卫:省略即为无条件(裸提供方)变更,提供即为守卫。`writeText` 的守卫是 `FsWriteIntent`:`createIfAbsent` 创建缺失的目标,若目标已存在则以 `FS_NOT_OBSERVED` 拒绝;`replaceIfVersion` 仅在目标存在且版本匹配时替换,否则报 `FS_STALE_VERSION`。省略 `expected` 则无条件创建或覆盖。联合类型本身只携带两种守卫意图;「无守卫」通过省略表达,因此 write 和 edit 共享同一个对称的 `expected?` 形状。 +`writeText` 和 `editText` 的版本守卫都是可选的:省略它执行无条件(裸提供方)变更,提供它则启用守卫。`writeText` 的守卫是 `FsWriteIntent`:`createIfAbsent` 在目标缺失时创建,目标已存在时以 `FS_NOT_OBSERVED` 拒绝;`replaceIfVersion` 仅在目标存在且版本匹配时替换,否则报 `FS_STALE_VERSION`。省略 `expected` 则无条件创建或覆盖。联合类型本身只包含两种有守卫的意图;「无守卫」通过省略表达,因此 write 和 edit 共享同一个对称的 `expected?` 形状。 ```ts type-equiv type FsWriteIntent = @@ -70,7 +70,7 @@ interface FsWriteOutcome { } ``` -`editText` 是提供方级别的变更,而非在别处组合的 `read` 加 `write`。守卫模式下,它在字面匹配之前先验证预期版本(因此对陈旧内容的编辑报 `FS_STALE_VERSION`,而非对更新内容的匹配失败);无守卫模式下,它编辑当前内容。无论哪种路径,它都应用替换并原子写入——将匹配、行尾处理、陈旧检查与原子替换保持在同一个变更临界区内——且目标缺失时两种路径都报 `FS_STALE_VERSION`。 +`editText` 是提供方级别的变更操作,而非在别处组合的 `read` 加 `write`。带守卫时,它在字面匹配之前先验证预期版本(因此对陈旧内容的编辑报 `FS_STALE_VERSION`,而非对更新内容的匹配失败);不带守卫时,它编辑当前内容。无论哪种路径,它都应用替换并原子写入——将匹配、行尾处理、陈旧检查和原子替换保持在一个变更临界区内——目标缺失时两条路径都报 `FS_STALE_VERSION`。 ```ts type-equiv interface FsEditRequest { @@ -90,13 +90,13 @@ interface FsEditOutcome { ## fs 策略事件(提供方 seam 词汇) -`dsh-fs` 拥有三个事件,由工具派发、策略插件监听,使发射方(`dsh-tool-fs`)和监听方(`dsh-fs-policy`)共享词汇而无需发射方依赖策略插件。它们只携带 `dsh-fs` 词汇加一个不透明的 `object` actor,不含面向模型的概念,也不含 agent/会话所有者结构。 +`dsh-fs` 拥有三个事件,由工具分发、策略插件监听,使发射方(`dsh-tool-fs`)与监听方(`dsh-fs-policy`)共享词汇,而发射方无需依赖策略插件。它们只携带 `dsh-fs` 词汇加一个不透明的 `object` actor,不含面向模型的概念,也不含 agent/session 所有者结构。 -`fs/write-intent` 和 `fs/edit-intent` 是**单槽决策 waterfall**:工具派发时附带一个默认 thunk(返回 `undefined`,即裸提供方),监听方完全裁决而不调用 `next()`。该槽按注册顺序先到先得——策略插件占据该槽是部署约定,而非强制不变式。`fs/observed` 是一个即发即忘的记录事件,通过普通 `ctx.emit` 派发;其监听方必须是同步且仅有副作用的,因为工具不守卫该 emit——抛出异常的监听方会作为工具对一个已成功变更的 `isError` 结果暴露出来。生成的目录在 [events.md](../cordis-catalog/events.md) 展示确切签名。 +`fs/write-intent` 与 `fs/edit-intent` 是**单槽决策 waterfall**:工具分发时附带一个默认 thunk(返回 `undefined`,即裸提供方),监听方完全决策而不调用 `next()`。该槽按注册顺序先到先得——由策略插件占据是部署约定,而非强制不变式。`fs/observed` 是一个即发即弃的记录事件,通过普通 `ctx.emit` 分发;其监听方必须是同步的、仅产生副作用,因为工具不守卫该 emit——抛异常的监听方会在一次已成功的变更上表现为工具的 `isError` 结果。生成的目录在 [events.md](../cordis-catalog/events.md) 中展示确切签名。 ## 执行上下文(策略插件) -策略插件只需要足够的执行上下文来从 `fs/*` 事件携带的不透明 `object` actor 中窄化出观测状态的所有者。`ToolExecution` 满足此形状,因此 `dsh-tool-fs` 将其执行对象作为 actor 透传,而无需让 `dsh-fs-policy` 导入工具、agent 或会话包。 +策略插件只需要足够的执行上下文,通过收窄 `fs/*` 事件携带的不透明 `object` actor 来推导观测状态的所有者。`ToolExecution` 满足此形状,因此 `dsh-tool-fs` 将其执行对象作为 actor 直接传递,而无需让 `dsh-fs-policy` 导入 tool、agent 或 session 包。 ```ts type-equiv interface FsPolicyExec { @@ -108,7 +108,7 @@ interface FsPolicyExec { ## 读取结果(消费方 / 读取渲染) -文本读取受行窗口、字节上限和后端限制约束。面向模型的 `read` 工具渲染的结果纯粹是展示性的;不存在 `full`/`partial` 视图区分——授权基于新鲜度(工具直接以 stat 的版本 emit `fs/observed`),因此任何窗口化读取在文件未变时都能授权后续的 write/edit。读取窗口化与此结果形状位于 `dsh-tool-fs`(拥有读取的执行器),而非策略插件。 +文本读取受行窗口、字节上限和后端限制约束。面向模型的 `read` 工具渲染的结果纯粹是展示性的;不存在 `full`/`partial` 视图区分——授权基于新鲜度(工具直接用 stat 的版本 emit `fs/observed`),因此任何窗口化读取在文件未变时都能授权后续的 write/edit。读取窗口化与此结果形状位于 `dsh-tool-fs`(拥有读取操作的执行器)中,而非策略插件中。 ```ts type-equiv interface FileReadOutcome { @@ -121,11 +121,11 @@ interface FileReadOutcome { ## 已观测文件状态(策略插件) -已观测状态是 `dsh-fs-policy` 插件内部持有的 `WeakMap<owner, Map<targetKey, { version }>>`。条目存在**当且仅当**所有者已读取、写入或编辑过该目标(每次成功都 emit `fs/observed`),因此条目的存在本身就是先前观测的记录——没有单独的 `hasRead` 标志,也没有视图区分。所有者从事件 actor 派生(通常是 `exec.agent.session`),被视为不透明且从不读取。成功的 read/write/edit 会刷新该所有者对应的已记录版本;dispose 时丢弃全部数据(HMR 安全)。 +已观测状态是 `dsh-fs-policy` 插件内部持有的 `WeakMap<owner, Map<targetKey, { version }>>`。当且仅当所有者已读取、写入或编辑过该目标时(每次成功都 emit `fs/observed`),条目才存在,因此其存在本身就是先前观测的记录——没有单独的 `hasRead` 标志,也没有视图区分。所有者从事件 actor 推导(通常是 `exec.agent.session`),被视为不透明且从不读取。成功的 read/write/edit 会刷新该所有者对应的已记录版本;dispose(资源释放)时丢弃全部数据(HMR(热模块替换)安全)。 ## 错误分类体系(提供方 seam) -文件系统失败使用稳定的 `FsErrorCode` 字符串,由 `FsError`(`HarnessError`)携带。工具注册表在错误结果上保留 `{ name, code }`,使重试、权限和 UI 层无需解析文本即可分支。 +文件系统故障使用稳定的 `FsErrorCode` 字符串,由 `FsError`(`HarnessError`)携带。工具注册表在错误结果上保留 `{ name, code }`,使重试、权限和 UI 层可以按 code 分支而无需解析文本。 ```ts type-equiv type FsErrorCode = @@ -142,8 +142,8 @@ type FsErrorCode = | 'FS_ABORTED' ``` -`FS_NOT_DIRECTORY`、`FS_PERMISSION_DENIED` 和 `FS_IO_ERROR` 用于目录列举,分别区分目标存在但不是目录、列举被拒绝、以及意外的后端 I/O 失败。`FS_NOT_OBSERVED` 表示策略插件没有该所有者的先前观测记录(或 `createIfAbsent` 遇到了已存在的文件)。`FS_STALE_VERSION` 表示后端版本不再匹配已观测版本(或编辑遇到了缺失的目标)。新鲜度授权没有 partial/full 区分,因此不存在 `FS_PARTIAL_OBSERVATION`。 +`FS_NOT_DIRECTORY`、`FS_PERMISSION_DENIED` 和 `FS_IO_ERROR` 用于目录列表操作,分别区分目标存在但不是目录、列表被拒绝、以及意外的后端 I/O 故障。`FS_NOT_OBSERVED` 表示策略插件对该所有者没有先前观测记录(或 `createIfAbsent` 遇到了已存在的文件)。`FS_STALE_VERSION` 表示后端版本不再匹配已观测版本(或 edit 遇到了缺失的目标)。新鲜度授权没有 partial/full 区分,因此不存在 `FS_PARTIAL_OBSERVATION`。 ## 服务与插件 -`FileSystem`(`ctx.fs`,抽象)拥有提供方原语:`resolve`、`stat`、`readText`、`streamText`、`listDir`、`writeText` 和 `editText`。`dsh-fs-policy` **不注册服务**——它是一个通过 `fs/*` 事件门添加策略的插件:它裁决 write/edit intent waterfall(提供 `createIfAbsent`/`replaceIfVersion`/`{ version }` 或抛出 `FS_NOT_OBSERVED`),并在 `fs/observed` 上记录。执行器是 `dsh-tool-fs`:它通过 `ctx.fs` 读/写/编辑,派发 waterfall,并 emit 记录事件。生成的接线目录在 [services.md](../cordis-catalog/services.md#ctxfs--filesystem-abstract-seam) 展示确切的 `ctx.fs` 签名。 +`FileSystem`(`ctx.fs`,抽象)拥有提供方原语:`resolve`、`stat`、`readText`、`streamText`、`listDir`、`writeText` 和 `editText`。`dsh-fs-policy` 不注册任何服务——它是一个通过 `fs/*` 事件门控叠加策略的插件:它裁决 write/edit intent waterfall(提供 `createIfAbsent`/`replaceIfVersion`/`{ version }` 或抛出 `FS_NOT_OBSERVED`),并在 `fs/observed` 上记录。执行器是 `dsh-tool-fs`:它通过 `ctx.fs` 读取/写入/编辑,分发 waterfall,并 emit 记录事件。生成的接线目录在 [services.md](../cordis-catalog/services.md#ctxfs--filesystem-abstract-seam) 中展示确切的 `ctx.fs` 签名。 diff --git a/docs/core-data-structures/llm-streaming.i18n.yaml b/docs/core-data-structures/llm-streaming.i18n.yaml index 4227258611..f9cd711351 100644 --- a/docs/core-data-structures/llm-streaming.i18n.yaml +++ b/docs/core-data-structures/llm-streaming.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write llm-streaming.md: ffd276b4647be8d10afcab0fb3c3f6daad790d20 -llm-streaming.zh.md: 051d6f5d28059bf81ba38c348ea306c46e73d4e2 +llm-streaming.zh.md: 4cb87c9fe65e264f9ce2f39d6ea3b5c6183d5cc1 diff --git a/docs/core-data-structures/llm-streaming.zh.md b/docs/core-data-structures/llm-streaming.zh.md index 051d6f5d28..4cb87c9fe6 100644 --- a/docs/core-data-structures/llm-streaming.zh.md +++ b/docs/core-data-structures/llm-streaming.zh.md @@ -8,7 +8,7 @@ ## `StreamChunk`:原始协议 -一次流式响应会交错多种类型的块(文本、推理、多个工具调用)。`index` 将每个 delta 关联到对应的块;`block-end` 携带完整组装好的 `ContentBlock`,消费方无需自行重新组装 delta。这是一个**封闭的**可辨识联合类型:对 `type` 的 `switch` 以 `assertNever` 结尾,因此新增变体会在每个必须处理它的消费方处触发编译错误。 +一个流式响应交错包含多种类型的块(文本、推理(reasoning)、多个工具调用)。`index` 将每个 delta 关联到其所属块;`block-end` 携带完整组装好的 `ContentBlock`,消费方无需自行重新组装 delta。这是一个**封闭的**可辨识联合类型:对 `type` 的 `switch` 以 `assertNever` 结尾,因此新增变体会在每个必须处理它的消费方处触发编译错误。 ```ts type-equiv type StreamChunk = @@ -23,18 +23,18 @@ type StreamChunk = ## 适配器契约 -每个适配器必须遵守以下规则,每个消费方可以依赖它们: +每个适配器**必须**遵守以下规则,每个消费方可以依赖它们: - **`usage` 在 `finish` 之前,`finish` 之后不再有任何分片。** 将两者都推迟到提供方的流结束标记,这样尾部的 usage-only 分片就不会违反顺序。 -- **工具调用的 `arguments` 全程保持原始 JSON 字符串。** 部分片段通过 `argumentsDelta` 流式传输;如果提供方返回的是已解析的对象,适配器在 `block-end` 时重新序列化。 -- **两条认可的错误路径。** 失败可以从 `stream()` 抛出异常(传输/协议错误),**或者**以 `finish {kind:'error'|'aborted'}` 结束流(提供方带内错误,适用于无法在流中途抛出异常的适配器)。消费方必须同时处理*两种*情况。agent loop(智能体循环)将 finish-error/aborted 转化为轮次错误,绝不会为失败的步骤记录一条正常完成的 assistant 消息。 -- **每个提供方 HTTP 请求都携带应用归属头。** 适配器发送 `attributionHeaders()`(见下文)作为 `User-Agent` 基线,并通过协议级测试证明这一点(mock 服务器断言收到的 header,或库支持的适配器使用库的 header 钩子)。 +- **工具调用的 `arguments` 全程保持原始 JSON 字符串。** 部分片段通过 `argumentsDelta` 流式传输;如果提供方返回的是已解析的对象,适配器在 `block-end` 时重新序列化为字符串。 +- **两条许可的错误路径。** 失败可以从 `stream()` 中 THROW(传输/协议错误),**或者**以 `finish {kind:'error'|'aborted'}` 结束流(提供方带内错误,适用于无法在流中途抛出异常的适配器)。消费方必须同时处理*两种*情况。agent loop(智能体循环)将 finish-error/aborted 转化为轮次错误,绝不会为失败的步骤记录一条正常完成的 assistant 消息。 +- **每个提供方 HTTP 请求都携带应用归属头。** 适配器发送 `attributionHeaders()`(见下文)作为 `User-Agent` 基线,并通过协议级测试加以证明(mock 服务器断言收到的 header,或对基于库的适配器使用库的 header 钩子)。 -这份契约正是两个适配器作为有意配对存在的原因:`dsh-llm-deepseek`(手写的 fetch/SSE(Server-Sent Events))与 `dsh-llm-pi-ai`(通过 `@earendil-works/pi-ai` 访问同一端点)。两套独立的内部实现共享一份契约,正是它将协议钉死的方式:库支持的适配器无法在流中途抛异常,因此它行使了手写适配器可能不会走到的 finish-chunk 错误路径。 +这份契约正是两个适配器作为刻意配对存在的原因:`dsh-llm-deepseek`(手写 fetch/SSE(Server-Sent Events))与 `dsh-llm-pi-ai`(通过 `@earendil-works/pi-ai` 访问同一端点)。两套独立内部实现共享一份契约,正是将协议固定下来的方式:基于库的适配器无法在流中途抛出异常,因此它走通了手写适配器可能不会走到的 finish-chunk 错误路径。 ## `AppIdentity`:应用归属 -每个适配器向提供方发送的静态公开应用身份([`packages/llm/llm/src/attribution.ts`](../../packages/llm/llm/src/attribution.ts))。`attributionHeaders(identity?)` 仅将其映射为标准 `User-Agent` header;本契约有意不支持 OpenRouter 特有的应用归属 header。默认的 `APP_IDENTITY` 从包(package)的 manifest(元数据清单)获取版本号;每个字段都是公开的产品事实,不含密钥、路径、会话 id 或用户标识符,且没有任何逐请求的值可以影响这些字段。设计依据见 [强制 `User-Agent` 归属](../rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 +每个适配器向提供方发送的静态公开应用标识([`packages/llm/llm/src/attribution.ts`](../../packages/llm/llm/src/attribution.ts))。`attributionHeaders(identity?)` 仅将其映射为标准 `User-Agent` header;本契约有意不支持 OpenRouter 特有的应用归属 header。默认的 `APP_IDENTITY` 从 package manifest(元数据清单)获取版本号;每个字段都是公开的产品事实,不含密钥、路径、会话 id 或用户级标识符,且任何请求级信息都不得影响这些值。设计依据见 [Mandatory `User-Agent` attribution](../rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 ```ts type-equiv interface AppIdentity { @@ -60,13 +60,13 @@ interface TokenUsage { ## `BlockAssembler` -`BlockAssembler`([`packages/llm/llm/src/assembler.ts`](../../packages/llm/llm/src/assembler.ts))是唯一的共享实现,负责将 `StreamChunk` 流折叠回 `ContentBlock` 序列与最终的 `Message`。agent loop 记录原始分片(保证回放保真度),同时将相同的分片送入 assembler;这样权威日志保留了 token 级别的细节,而派生的消息可以确定性地重建。需要组装结果但不想重新实现折叠逻辑的消费方使用它。 +`BlockAssembler`([`packages/llm/llm/src/assembler.ts`](../../packages/llm/llm/src/assembler.ts))是唯一的共享实现,将 `StreamChunk` 流折叠回 `ContentBlock` 列表与最终的 `Message`。agent loop 记录原始分片(保证回放保真度),同时将相同的分片送入 assembler,因此权威日志保留了 token 级细节,而派生消息可确定性地重建。需要组装结果而不想重新实现折叠逻辑的消费方使用它。 ## seam -`LlmAdapter` 是提供方 seam:继承它、实现 `stream()`、通过 `ctx.llm.registerAdapter(models, adapter)` 注册。`block-start`/`block-end` 的 `index` 关联加上 assembler,意味着适配器只需发出格式正确的分片,块的重新组装不是各适配器自己的问题。消费方接口(`ctx.llm.stream()`)与 `llm/stream` waterfall(瀑布式事件)在 [architecture.md § Content blocks and streaming](../architecture.md#content-blocks-and-streaming-dsh-llm) 中描述。 +`LlmAdapter` 是提供方 seam:继承它、实现 `stream()`、通过 `ctx.llm.registerAdapter(models, adapter)` 注册。`block-start`/`block-end` 的 `index` 关联加上 assembler 意味着适配器只需发出格式正确的分片,块重组不是各适配器需要操心的事。消费方接口(`ctx.llm.stream()`)与 `llm/stream` waterfall(瀑布式事件)在 [architecture.md § Content blocks and streaming](../architecture.md#content-blocks-and-streaming-dsh-llm) 中描述。 -`ContentBlockType`(`index` 关联的块所携带的键集合)派生自 `ContentBlockMap`: +`ContentBlockType`(`index` 关联块所携带的键集合)派生自 `ContentBlockMap`: ```ts type-equiv interface ContentBlockMap { diff --git a/docs/core-data-structures/persistence.i18n.yaml b/docs/core-data-structures/persistence.i18n.yaml index 9f69617b7f..3072063a43 100644 --- a/docs/core-data-structures/persistence.i18n.yaml +++ b/docs/core-data-structures/persistence.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write persistence.md: ce7a21a5613da903a9bddd339e122bf9f899d2bd -persistence.zh.md: 07d54895ef59b99dca47142e3fde16e6d7d0d1b3 +persistence.zh.md: 33ddda66aacc21f847dfd45702b11b5381711cce diff --git a/docs/core-data-structures/persistence.zh.md b/docs/core-data-structures/persistence.zh.md index 07d54895ef..33ddda66aa 100644 --- a/docs/core-data-structures/persistence.zh.md +++ b/docs/core-data-structures/persistence.zh.md @@ -2,21 +2,21 @@ [English](persistence.md) | 中文 -事件日志的**持久性 seam**。[session.md](session.md) 描述了内存中的 `Session`:仅追加的 `SessionEvent` 日志即为真源。本页描述该日志如何被持久化:抽象的 `SessionPersistence` 服务、它的后端、flush 检查点、崩溃恢复,以及随日志一起存储的元数据头。日志所承载的事件词汇在生成的[持久化日志事件目录](../persistence-catalog.md)中逐一列出。 +事件日志的**持久性 seam**。[session.md](session.md) 描述了内存中的 `Session`:仅追加的 `SessionEvent` 日志即为真源。本页描述如何使该日志持久化:抽象的 `SessionPersistence` 服务、它的后端、flush 检查点、崩溃恢复,以及随日志一同存储的元数据头。日志承载的事件词汇在生成的[持久化日志事件目录](../persistence-catalog.md)中逐项列举。 -该 seam 是教科书式的[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md):一个抽象服务([dsh-session-persistence](../../packages/session-persistence/session-persistence),`ctx.sessionPersistence`)在既有的 `SessionEvent` 之上定义 create/append/load/list——**没有平行的持久化类型**——以及两个可互换的后端,它们通过同一套 `runPersistenceContract` 测试。见 [session-persistence RFC](../rfc/implemented/architecture/2026-06-14-session-persistence.md)。 +该 seam 是典型的[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md):一个抽象服务([dsh-session-persistence](../../packages/session-persistence/session-persistence),`ctx.sessionPersistence`)在已有的 `SessionEvent` 之上定义 create/append/load/list 操作,**没有并行的持久化类型**,以及两个可互换的后端,它们通过同一套 `runPersistenceContract` 测试。详见 [session-persistence RFC](../rfc/implemented/architecture/2026-06-14-session-persistence.md)。 ## flush 检查点 -`session/event` 是一个*同步*通知;持久化插件对其进行缓冲(write-behind),并在 agent loop 于每个轮次结束时触发的 `session/flush` 检查点处排空缓冲区。flush 使用 `ctx.parallel`(被 await):一个轮次的事件在下一个轮次开始前被持久提交,轮次边界即提交边界。flush 失败时通过 `agent/error` 和 logger 报告,而非作为会话事件(那样会落在提交边界之后),因此后端保留其缓冲事件等待下一次 flush。 +`session/event` 是一个*同步*通知;持久化插件对其进行缓冲(write-behind),并在 agent loop(智能体循环)于每个轮次结束时触发的 `session/flush` 检查点处排空缓冲区。flush 使用 `ctx.parallel`(被 await):一个轮次的事件在下一个轮次开始前已被持久提交,轮次边界即提交边界。flush 拒绝时通过 `agent/error` 和 logger 报告,而非作为会话事件(那样会落在提交边界之后),因此后端保留其缓冲事件等待下一次 flush。 ## 崩溃恢复保留被中断的轮次 -后端重新加载一个在轮次中途崩溃的日志时,会发现一个已打开的 `turn/start` 而没有对应的 `turn/end`。它**不会**截断日志:在长周期任务中,单个轮次可能非常大(许多步骤、大量工具输出),而这些事件在崩溃前已被持久追加。后端改为用一个合成的 `turn/end { reason: { kind: 'interrupted' } }` 关闭这个遗留轮次,保持日志平衡与轮次封闭不变式完好。`interrupted` 是唯一一个 agent loop 不会自行发出的 `TurnEndReason`(见 [session.md](session.md#why-a-turn-ended-turnendreasonmap))。 +后端重新加载一个在轮次中途崩溃的日志时,会发现一个已打开的 `turn/start` 却没有 `turn/end`。它**不会**截断日志:在长周期任务中,单个轮次可能非常庞大(许多步骤、大量工具输出),而这些事件在崩溃前已被持久追加。后端改为用一个合成的 `turn/end { reason: { kind: 'interrupted' } }` 关闭这个遗留轮次,保持日志平衡与轮次闭合不变式。`interrupted` 是唯一一个不由循环发出的 `TurnEndReason`(见 [session.md](session.md#why-a-turn-ended-turnendreasonmap))。 ## `SessionHeader`:日志旁的元数据 -每个会话的元数据与事件日志**分开**存储:格式版本、cwd、血缘关系和 seed 边界属于存储关注点而非对话事件,因此它们不在 `SessionEventMap` 中,也不会进入 `deriveMessages()`。header 通过 `session.header` 附加到 `Session` 上。 +每个会话的元数据与事件日志**分开**存储:格式版本、cwd、血统与 seed 边界是存储层关注点而非对话事件,因此不进入 `SessionEventMap`,也不会到达 `deriveMessages()`。header 通过 `session.header` 附加到 `Session` 上。 源码:[`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) @@ -51,7 +51,7 @@ interface SessionHeader { ## `CreateSessionOptions`:seed 与元数据 -通过 store 创建 `Session` 时接受 `seed`(回放/fork 一个已有事件日志)和 `meta`(store 折叠进 `SessionHeader` 的存储级字段)。store 填充 `version`/`id` 并为 `createdAt` 设默认值;调用方提供经过校验的绝对路径 `cwd`、`parentSession` 血缘、`seedLength` seed 边界,以及仅在重建持久化会话时提供的原始 `createdAt` 以保留它。 +通过 store 创建 `Session` 时接受 `seed`(回放/fork 已有事件日志)和 `meta`(store 折叠进 `SessionHeader` 的存储层字段)。store 填充 `version`/`id` 并默认 `createdAt`;调用方提供经过校验的绝对路径 `cwd`、`parentSession` 血统、`seedLength` seed 边界,以及仅在重建持久化会话时提供的原始 `createdAt` 以保留其值。 ```ts type-equiv interface CreateSessionOptions { @@ -78,13 +78,13 @@ interface CreateSessionOptions { } ``` -因此,回放/fork 是 `ctx.sessions.create(id, { seed: seedEvents })`;将一个*持久化*会话恢复为活跃 agent 是 `ctx.agents.resume({ resumeSessionId })`。 +因此,回放/fork 的调用方式为 `ctx.sessions.create(id, { seed: seedEvents })`;将一个*持久化*会话恢复为活跃 agent 的调用方式为 `ctx.agents.resume({ resumeSessionId })`。 ## 后端 -两个后端实现同一个抽象 `SessionPersistence`(在 `SessionEvent` 之上的 create/append/load/list),并通过 `runPersistenceContract`,证明该 seam 真正与后端无关: +两者实现相同的抽象 `SessionPersistence`(在 `SessionEvent` 之上提供 create/append/load/list),并通过 `runPersistenceContract`,证明该 seam 真正与后端无关: - **[dsh-session-persistence-jsonl](../../packages/session-persistence/session-persistence-jsonl)**:每个会话一个仅追加的 JSONL 日志,具备崩溃安全的原子写入、上述中断轮次崩溃恢复,以及读取/回放路径。 -- **[dsh-session-persistence-sqlite](../../packages/session-persistence/session-persistence-sqlite)**:基于 `node:sqlite`,每个 `SessionEvent` 一行。行结构 `(session_id, seq, type, time, data, source_event_seqs, surface_op)` 与事件 1:1 映射(包括可选的 surface 元数据),因此没有需要保持同步的平行持久化 schema。 +- **[dsh-session-persistence-sqlite](../../packages/session-persistence/session-persistence-sqlite)**:基于 `node:sqlite`,每个 `SessionEvent` 一行。行结构 `(session_id, seq, type, time, data, source_event_seqs, surface_op)` 与事件 1:1 映射(包含可选的 surface 元数据),因此没有需要保持同步的并行持久化 schema。 -多个后端共享同一个磁盘会话时,通过[共享持久化写协调器](../rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)协调写入。 +多个后端共享同一磁盘会话时,通过[共享持久化写协调器](../rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)协调写入。 diff --git a/docs/core-data-structures/sandbox.i18n.yaml b/docs/core-data-structures/sandbox.i18n.yaml index 67bc36207d..e68f9b2c75 100644 --- a/docs/core-data-structures/sandbox.i18n.yaml +++ b/docs/core-data-structures/sandbox.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write sandbox.md: be8e3cd60681077ff5036915fd99520fe9685140 -sandbox.zh.md: 2e9e5aa9a65e636167e45900f169ed6da5219c24 +sandbox.zh.md: ca21c09e7f3d0756f78d7bd1581b9b4b03a43815 diff --git a/docs/core-data-structures/sandbox.zh.md b/docs/core-data-structures/sandbox.zh.md index 2e9e5aa9a6..ca21c09e7f 100644 --- a/docs/core-data-structures/sandbox.zh.md +++ b/docs/core-data-structures/sandbox.zh.md @@ -2,25 +2,25 @@ [English](sandbox.md) | 中文 -[dsh-sandbox](../../packages/sandbox/sandbox) 的进程沙箱 seam 将同世界子进程 argv 包装在文件效果策略中,而不将消费方耦合到特定平台运行器。[dsh-sandbox-local](../../packages/sandbox/sandbox-local) 提供 Linux bwrap/Landlock 与 macOS Seatbelt 后端;[dsh-bash-sandbox](../../packages/bash/bash-sandbox) 是第一个消费方。容器、microVM 与远程执行是整体能力 seam 的兄弟实现,而非 `ctx.sandbox` 的提供方。 +[dsh-sandbox](../../packages/sandbox/sandbox) 的进程沙箱 seam 将同世界子进程的 argv 包装在文件效果策略中,而不将消费方耦合到特定平台运行器。[dsh-sandbox-local](../../packages/sandbox/sandbox-local) 提供 Linux bwrap/Landlock 与 macOS Seatbelt 后端;[dsh-bash-sandbox](../../packages/bash/bash-sandbox) 是第一个消费方。容器、microVM 和远程执行是完整能力 seam 的兄弟实现,而非 `ctx.sandbox` 的提供方。 源码:[`packages/sandbox/sandbox/src/index.ts`](../../packages/sandbox/sandbox/src/index.ts) -## 模式与强制 +## 模式与强制执行 -`SandboxMode` 仅管控文件系统效果。`read-only` 拒绝写入(必需的 `/dev/null` sink 除外);`workspace-write` 允许在工作区根目录与后端承诺的临时区域下写入;`danger-full-access` 绕过隔离。网络与进程可见性不在此词汇范围内。 +`SandboxMode` 仅管控文件系统效果。`read-only` 拒绝所有写入(必需的 `/dev/null` 接收器除外);`workspace-write` 允许在工作区根目录及后端承诺的临时区域下写入;`danger-full-access` 绕过隔离。网络与进程可见性不在此处的定义范围内。 ```ts type-equiv type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access' ``` -只有前两种模式可以发送给提供方。`danger-full-access` 消费方直接 spawn 原始 argv,不调用 `ctx.sandbox`。 +只有前两种模式可以发送给提供方。`danger-full-access` 的消费方直接 spawn 原始 argv,不调用 `ctx.sandbox`。 ```ts type-equiv type ConfinedSandboxMode = Exclude<SandboxMode, 'danger-full-access'> ``` -强制级别是一个报告事实。`full` 表示后端管控了该模式承诺的所有文件效果;`partial` 表示活跃后端或较旧的内核 ABI 仅管控了一个子集,因此要求绝对承诺的消费方必须拒绝或向上暴露这一区别。 +强制执行程度是一个报告事实。`full` 表示后端管控了该模式承诺的所有文件效果;`partial` 表示活跃后端或较旧的内核 ABI 仅管控其中一个子集,因此要求绝对保证的消费方必须拒绝或向上暴露这一区别。 ```ts type-equiv type SandboxEnforcement = 'full' | 'partial' @@ -28,7 +28,7 @@ type SandboxEnforcement = 'full' | 'partial' ## 逐调用策略 -策略在每次调用时完全解析并随调用携带。这使得并发消费方和一次性升级重试可以向同一个提供方请求不同的边界,而无需修改提供方状态。 +策略在每次调用时完全解析并随调用携带。这使得并发消费方和一次性提权重试能够向同一个提供方请求不同的边界,而无需修改提供方状态。 ```ts type-equiv interface SandboxPolicy { @@ -41,7 +41,7 @@ interface SandboxPolicy { ## 包装后的 argv 与分类方言 -`ConfinedArgv` 是消费方实际 spawn 的内容。除了替换后的 argv,它还携带后端的强制事实和两组正交的 stderr 方言。`denialSignatures` 标识沙箱正常工作时被隔离命令被阻止的情况。`runnerFailureSignatures` 标识沙箱运行器在执行命令之前拒绝或失败的情况;消费方应先检查后者,将其作为沙箱基础设施故障暴露,而非普通任务失败。 +`ConfinedArgv` 是消费方实际 spawn 的内容。除了替换后的 argv,它还携带后端的强制执行事实和两种正交的 stderr 方言。`denialSignatures` 用于识别沙箱正常工作时被隔离命令被阻止的情况。`runnerFailureSignatures` 用于识别沙箱运行器在执行命令之前拒绝或失败的情况;消费方应先检查后者,将其作为沙箱基础设施故障上报,而非普通任务失败。 ```ts type-equiv interface ConfinedArgv { @@ -75,10 +75,10 @@ interface ConfinedArgv { } ``` -运维人员配置的本地运行器必须为自身的 pre-exec 拒绝方言提供至少一条 `runnerFailureSignatures` 条目;提供方会自动添加外层 shell 的 missing 和 unexecutable 形式。这使得可执行的自定义运行器拒绝其 profile 的情况与被包装命令以相同状态码退出的情况可以区分开来。 +运维人员配置的本地运行器必须为自身的 pre-exec 拒绝方言提供至少一条 `runnerFailureSignatures` 条目;提供方会自动添加外层 shell 的 missing 和 unexecutable 形式。这使得可执行的自定义运行器拒绝其 profile 的情况能够与被包装命令以相同状态码退出的情况区分开来。 ## 提供方与 fail-closed 错误 `ctx.sandbox.confine(argv, policy)` 返回一个 `ConfinedArgv`,或在没有可用后端时抛出 `SandboxUnavailableError`(错误码 `SANDBOX_UNAVAILABLE`)。已选定的运行器也可能在执行时 fail-closed,此时其失败签名承载相同的基础设施含义。对于受限策略,静默的无隔离透传永远不合法。 -提供方探测在多个候选后端之间仲裁,结果在提供方生命周期内缓存。只有一个候选的平台可以直接选定它;执行时拒绝仍保留安全属性。本地提供方将 bwrap 和 Seatbelt 报告为 full,并保留 Landlock 启动器的 full/partial 内核裁定。 +提供方探测在多个候选后端之间仲裁,结果在提供方生命周期内缓存。只有一个候选后端的平台可以直接选定它;执行时拒绝仍保留安全属性。本地提供方将 bwrap 和 Seatbelt 报告为 full,并保留 Landlock 启动器的 full/partial 内核裁定。 diff --git a/docs/core-data-structures/scope.i18n.yaml b/docs/core-data-structures/scope.i18n.yaml index 45f21bc10d..a9467c71da 100644 --- a/docs/core-data-structures/scope.i18n.yaml +++ b/docs/core-data-structures/scope.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write scope.md: f95594329ee9ac83da2efcc31df377c53e64331a -scope.zh.md: 80b2a7355e0499fcccf0e218c57f395252416cbd +scope.zh.md: 277fa4ec5c365e5ff3ee6d9baeae525d3dfc9f96 diff --git a/docs/core-data-structures/scope.zh.md b/docs/core-data-structures/scope.zh.md index 80b2a7355e..277fa4ec5c 100644 --- a/docs/core-data-structures/scope.zh.md +++ b/docs/core-data-structures/scope.zh.md @@ -2,19 +2,19 @@ [English](scope.md) | 中文 -[scope 包](../../packages/core/scope)提供身份标识与载体词汇,使一个注册上下文同时表达「按 agent 可见」和「共享生命周期所有权」两层含义。它是一个库级原语,而非 Cordis 服务;[agent-scope 运行时设计 RFC](../rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#scope-routing-one-opaque-key-selects-one-layer) 拥有实现动机,包的 [README](../../packages/core/scope/README.md) 拥有可调用 API 与过滤语义。 +[scope 包(package)](../../packages/core/scope)提供身份标识与载体词汇,使一个注册上下文同时表达逐 agent(智能体)的可见性与共享的生命周期归属。它是一个库级原语,而非 Cordis 服务;[agent-scope 运行时设计 RFC](../rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#scope-routing-one-opaque-key-selects-one-layer) 阐述了实现原理,包的 [README](../../packages/core/scope/README.md) 说明了可调用 API 与过滤语义。 源码:[`packages/core/scope/src/index.ts`](../../packages/core/scope/src/index.ts)。 ## 身份标识与分发载体 -`ScopeKey` 是一个不透明的对象标识。已交付的 agent loop 使用活跃的 `Agent` 对象作为自身的 key,但该原语从不检视该对象。 +`ScopeKey` 是一个不透明的对象身份标识。已交付的 agent loop(智能体循环)使用活跃的 `Agent` 对象作为自身的 key,但该原语从不检视该对象。 ```ts type-equiv type ScopeKey = object ``` -`Scoped<T>` 是 `scopeTarget(base, key)` 返回的不透明路由接收者上的编译期品牌类型。经作用域过滤的事件声明要求以此载体作为其 `this` 类型,而真正的事件主体仍作为显式参数传递。 +`Scoped<T>` 是编译期品牌标记,标注在 `scopeTarget(base, key)` 返回的不透明路由接收器上。作用域过滤的事件声明要求以此载体作为 `this` 类型,而真正的事件主体仍作为显式参数传入。 ```ts type-equiv type Scoped<T extends object> = object & { readonly [ScopedBrand]: T } @@ -22,7 +22,7 @@ type Scoped<T extends object> = object & { readonly [ScopedBrand]: T } ## 拥有所有权的注册上下文 -`Scope` 将带标签的注册上下文与两个拆卸面配对。`rawDispose` 保留有序组合副作用所需的精确 Cordis disposer 标识;`dispose()` 是面向直接调用方和竞争调用方的公共共享静默边界。 +`Scope` 将带标签的注册上下文与两个拆卸接口配对。`rawDispose` 保留有序复合 effect 所需的精确 Cordis disposer 身份;`dispose()` 是面向直接调用方和竞争调用方的公共静默边界,用于 dispose(资源释放)。 ```ts type-equiv interface Scope { diff --git a/docs/core-data-structures/session-query.i18n.yaml b/docs/core-data-structures/session-query.i18n.yaml index 53170b4ef6..ff5bae0fba 100644 --- a/docs/core-data-structures/session-query.i18n.yaml +++ b/docs/core-data-structures/session-query.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write session-query.md: 444f2bb2256a43df7bd8521dfe234f771eec7181 -session-query.zh.md: 4d00e5fa310d82c6099ab4f5255f09f9e253c150 +session-query.zh.md: 70f9737a702f84074962d9d1c7ac49a7c119f8cf diff --git a/docs/core-data-structures/session-query.zh.md b/docs/core-data-structures/session-query.zh.md index 4d00e5fa31..70f9737a70 100644 --- a/docs/core-data-structures/session-query.zh.md +++ b/docs/core-data-structures/session-query.zh.md @@ -2,13 +2,13 @@ [English](session-query.md) | 中文 -对实时优先的逻辑会话语料库进行精确读取。[包(package)契约](../../packages/session-query/session-query)定义了源优先级、动态可选持久化、克隆、surface 分类、有界窗口与类型化错误。全文搜索是一个独立提议的 SQLite 阶段。 +对实时优先的逻辑会话语料库进行精确读取。[包(package)契约](../../packages/session-query/session-query)定义了源优先级、动态可选持久化、克隆、surface 分类、有界窗口与类型化错误。全文搜索是另一个拟议的 SQLite 阶段。 源码:[`packages/session-query/session-query/src/types.ts`](../../packages/session-query/session-query/src/types.ts) ## 逻辑记录 -`SessionRecord` 由跨语料库列表返回。它独立于克隆的实时优先 header 暴露源可用性。`SessionEventRecord` 是一个轻量的原始日志投影;分类使用与 model-history 推导相同的 `foldSurface()` 状态转换。 +`SessionRecord` 由跨语料库列表返回。它独立于克隆后的实时优先 header 暴露源可用性。`SessionEventRecord` 是轻量的原始日志投影;分类使用与 model-history 推导相同的 `foldSurface()` 状态转换。 ```ts type-equiv export type SessionEventSurface = 'current' | 'shadowed' | 'log-only' @@ -34,7 +34,7 @@ export interface SessionEventRecord { ## 有界事件读取 -请求指定一个原始 seq 以及可选的前后邻近数量。结果携带 `SessionHeader` 而非可用性标志,使已知的实时目标可以独立于持久化健康状态。 +请求指定一个原始 seq 及可选的邻近数量。结果携带 `SessionHeader` 而非可用性标志,使已知的实时目标可以独立于持久化健康状态。 ```ts type-equiv export interface SessionEventReadRequest { @@ -57,7 +57,7 @@ export interface SessionEventWindow { ## 错误 -封闭的 code 联合类型区分请求校验、目标缺失、surface 日志格式错误、可选后端失败与源元数据矛盾。 +封闭的 code 联合类型区分请求校验、目标缺失、surface 日志格式错误、可选后端故障与矛盾的源元数据。 ```ts type-equiv export type SessionQueryErrorCode = diff --git a/docs/core-data-structures/session.i18n.yaml b/docs/core-data-structures/session.i18n.yaml index 9910652ad0..23b16e8d66 100644 --- a/docs/core-data-structures/session.i18n.yaml +++ b/docs/core-data-structures/session.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write session.md: 796abebbc31a54c7c341028cf0a09031ae59cd78 -session.zh.md: a2ff9319af1425792702502e12bd287d7f3ca805 +session.zh.md: b55ff3b7fe9c3a5f65dc46addf266dc1e5430116 diff --git a/docs/core-data-structures/session.zh.md b/docs/core-data-structures/session.zh.md index a2ff9319af..b55ff3b7fe 100644 --- a/docs/core-data-structures/session.zh.md +++ b/docs/core-data-structures/session.zh.md @@ -2,13 +2,13 @@ [English](session.md) | 中文 -[dsh-session](../../packages/core/session) 的内存事件溯源模型。`Session` 是一份由类型化 `SessionEvent` 组成的**仅追加日志**,是 agent(智能体)整个交互历史的唯一真源。LLM(大语言模型)消息历史从日志*派生*而来,从不单独存储;回放即从同一组事件重新派生。日志如何实现**持久化**(持久化 seam、后端、崩溃恢复)是兄弟文档 [persistence.md](persistence.md) 的关注点。 +[dsh-session](../../packages/core/session) 的内存事件溯源模型。`Session` 是一份由类型化 `SessionEvent` 组成的**仅追加日志**,是 agent(智能体)完整交互历史的唯一真源。LLM(大语言模型)消息历史从日志*派生*而来,从不单独存储;回放即从同一组事件重新派生。日志如何实现**持久化**(持久化 seam、后端、崩溃恢复)是兄弟文档 [persistence.md](persistence.md) 的关注点。 源码:[`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) ## `SessionEventMap`:事件词汇 -仅追加的事件类型。可通过声明合并扩展:插件通过 declaration merging 声明额外的事件类型。例如[压缩(compaction) seam](compaction.md) 添加了 `compact/start` / `compact/summary` / `compact/end`,`@deepseek-ai/dsh-hook-protocol` 添加了仅记录日志的 `hook/invoked` / `hook/result` 溯源事件用于钩子桥接。与 `compact/*` 一样,这些都不是 `SurfaceEventType`(没有 `surfaceOp`)。生成的[持久化日志事件目录](../persistence-catalog.md)列举了所有成员(核心与合并的),包括其 payload、surface 标记和声明位置。 +仅追加的事件类型。可通过声明合并扩展:插件通过 declaration merging 声明额外的事件类型。例如[上下文压缩(context compaction) seam](compaction.md) 添加了 `compact/start` / `compact/summary` / `compact/end`,`@deepseek-ai/dsh-hook-protocol` 添加了仅记录日志的 `hook/invoked` / `hook/result` 溯源事件,用于钩子桥接。与 `compact/*` 一样,这些都不是 `SurfaceEventType`(没有 `surfaceOp`)。生成的[持久化日志事件目录](../persistence-catalog.md)列举了所有成员(核心与合并扩展的),包含其 payload、surface 标记与声明位置。 ```ts type-equiv interface SessionEventMap { @@ -90,7 +90,7 @@ interface SessionEventMap { ### `TodoItem`:一条待办项 -`todo/write` 事件全量快照的单元。刻意保持最小化:一行 `content` 加一个三态 `status`(无 id、无优先级、无 `activeForm`)。列表在每次写入时整体替换,因此条目不需要稳定标识;三态 status 恰好对应 ACP 的 `PlanEntryStatus`,UI 桥接层可以将 todo 列表 1:1 映射到 ACP `plan`(ACP 额外要求的 priority 由桥接层合成)。见 [todo_write RFC](../rfc/implemented/feature/2026-06-29-todo-write-tool.md)。 +`todo/write` 事件全量快照的单元。刻意保持精简:一行 `content` 加一个三态 `status`(无 id、无优先级、无 `activeForm`)。列表在每次写入时整体替换,因此条目不需要稳定标识;三态 status 恰好是 ACP(Agent Client Protocol)的 `PlanEntryStatus`,UI 桥接层可以将待办列表 1:1 映射到 ACP `plan`(再合成 ACP 额外要求的优先级)。见 [todo_write RFC](../rfc/implemented/feature/2026-06-29-todo-write-tool.md)。 ```ts type-equiv export interface TodoItem { @@ -101,7 +101,7 @@ export interface TodoItem { ### 请求头事件:`request/header` 与 `request/header-delta` -请求信封(`EpochHeader`:调用配置 + 渲染后的系统提示词 + 组装好的工具 schema + 会话前缀)是被记录到日志中的会话状态,因此每次对话请求都是日志的纯函数(可重建性 RFC)。`request/header` 快照(reason 为 `'initial' | 'resume' | 'fallback'`)在对话创建、进程边界和 delta 编码回退时锚定折叠点;`request/header-delta` 事件在运行中修正它。`foldRequestHeader(events)` 可重建任何请求构建时所用的 header;写入器在记录每个 delta 前都会做往返验证,因此格式良好的日志总能折叠。两者都不是 `SurfaceEventType`,不产生 LLM 消息。 +请求信封(`EpochHeader`:调用配置 + 渲染后的系统提示词 + 组装好的工具 schema + 会话前缀)是被记录到日志中的会话状态,使得每次对话请求都是日志的纯函数(可重建性 RFC)。`request/header` 快照(reason 为 `'initial' | 'resume' | 'fallback'`)在对话诞生、进程边界和 delta 编码回退时锚定折叠点;`request/header-delta` 事件在运行中修正它。`foldRequestHeader(events)` 可重建任一请求构建时所用的 header;写入器在记录每个 delta 前都会做往返验证,因此格式正确的日志总能折叠。两者都不是 `SurfaceEventType`,不产生 LLM 消息。 ```ts type-equiv export interface EpochHeader { @@ -122,11 +122,11 @@ export interface EpochHeader { } ``` -规范形式:空的系统提示词、空的工具列表和空的会话前缀表示为字段缺失,与请求构建方式一致。`messagePrefix` 是 `agent/session-prefix` waterfall(瀑布式事件)产物的持久记录(请求 = `messagePrefix` + 派生历史);每个 agent loop(智能体循环)实例组装一次,由该实例的快照锚定,因此循环实际上不会产生 prefix delta。delta 分支(数组整体替换,空数组编码回到缺失状态的转换)为编解码完备性而存在。其他 delta payload(`SystemDelta`:公共前缀/后缀行裁剪;`ToolsDelta`:按名称键控的增/删/改)与事件一起定义在 [`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) 中。 +规范形式:空的系统提示词、空的工具列表和空的会话前缀均为 ABSENT 字段,与请求构建方式一致。`messagePrefix` 是 `agent/session-prefix` waterfall(瀑布式事件)产物的持久记录(请求 = `messagePrefix` + 派生历史);每个 agent loop(智能体循环)实例组合一次,由该实例的快照锚定,因此实际上 loop 不会产生前缀 delta。delta 分支(整数组替换,空数组编码「回到无前缀」的转换)存在是为了编解码的完备性。其他 delta payload(`SystemDelta`:公共前缀/后缀行裁剪;`ToolsDelta`:按名称键控的增/删/改)与事件一起定义在 [`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts)。 ## `SessionEvent<T>`:一条日志条目 -基于 `type` 的正规可辨识联合(而非独立的 `type`/`data` 联合),因此 `switch (event.type)` 可以收窄 `event.data` 而无需类型断言。`seq` 是日志中的单调递增位置(`seq = log.length`);`time` 为 epoch 毫秒。 +基于 `type` 的真正可辨识联合(而非独立的 `type`/`data` 联合),因此 `switch (event.type)` 能直接收窄 `event.data`,无需类型断言。`seq` 是日志中的单调递增位置(`seq = log.length`);`time` 为 epoch 毫秒。 ```ts type-equiv type SessionEvent<T extends SessionEventType = SessionEventType> = { @@ -150,13 +150,13 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = { }[T] ``` -`SessionEventType = keyof SessionEventMap`。由于 `SessionEventMap` 可通过合并扩展,对 `SessionEvent` 的 switch 禁止使用 `assertNever`:插件添加的变体是合法的未知值;处理已知 case 后在 `default` 中放行。 +`SessionEventType = keyof SessionEventMap`。由于 `SessionEventMap` 可通过合并扩展,对 `SessionEvent` 的 switch 语句禁止使用 `assertNever`:插件添加的变体是合法的未知值;处理已知 case 后在 `default` 中放行。 ## Surface 类型 -五种产生消息的类型(`SurfaceEventType`:`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`)携带 surface 元数据,声明它们如何加入派生的 surface 链表。见[会话 surface RFC](../rfc/implemented/architecture/2026-06-18-session-surface.md)。 +五种产生消息的类型(`SurfaceEventType`:`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`)携带 surface 元数据,声明它们如何加入派生的 surface 链表。见 [session surface RFC](../rfc/implemented/architecture/2026-06-18-session-surface.md)。 -### `SurfaceEventType`:产生消息的事件类型子集 +### `SurfaceEventType`:事件类型中产生消息的子集 ```ts type-equiv export type SurfaceEventType = @@ -175,7 +175,7 @@ export type SurfaceOp = | { op: 'replace'; start: number; end: number } ``` -`'append'` 是正常的尾部追加路径。`replace` 遮蔽从 `start` 到 `end`(含两端,两者必须是有效的 surface 节点 seq;`start === end` 替换单个节点)的 surface 节点,并在其位置插入新节点。 +`'append'` 是正常的尾部追加路径。`replace` 遮蔽从 `start` 到 `end`(含两端)的 surface 节点(两者都必须是有效的 surface 节点 seq),并在其位置插入新节点。 ### `SurfaceIntent`:`session.append()` 的参数 @@ -186,7 +186,7 @@ export interface SurfaceIntent { } ``` -`SurfaceEventType` 事件必须提供此参数:每个产生消息的事件都必须声明它如何加入 surface(派生历史的唯一来源)。非 surface 类型在编译期拒绝此参数。 +对 `SurfaceEventType` 事件必填:每个产生消息的事件都必须声明它如何加入 surface(派生历史的唯一来源)。非 surface 类型在编译期拒绝此参数。 ### `SurfaceNode`:surface 链表中的一个节点 @@ -220,22 +220,22 @@ export interface SurfaceFoldResult { ## 派生历史:`deriveMessages()` 与 `deriveEventMessage()` -`Session.deriveMessages()` 将事件日志投影为模型看到的 `Message[]`。它是缓存的(每个 surface 节点在首次出现时投影一次;surface 重写触发重建)且冻结的(每次调用返回一个新数组,其中的消息是共享的深度冻结对象,因此无法通过投影来修改已记录的历史)。`deriveEventMessage(event)` 是折叠所应用的逐节点纯函数,公开暴露以便外部重建器和开发不变式检查能以完全相同的规则投影日志前缀,不会与缓存产生分歧。投影规则: +`Session.deriveMessages()` 将事件日志投影为模型看到的 `Message[]`。它是缓存的(每个 surface 节点在首次出现时投影一次;surface 重写触发重建)且冻结的(每次调用返回一个新数组,引用共享的深冻结消息,因此通过投影修改已记录的历史在类型上不可表达)。`deriveEventMessage(event)` 是折叠所应用的逐节点纯函数,公开暴露以便外部重建器和开发不变式检查能以完全相同的规则投影日志前缀,不会与缓存产生分歧。投影规则: - `user/message` → 一条 user 消息。 -- `assistant/message` → 一条 assistant 消息。原始 `assistant/chunk` 事件是回放/UI 数据,在派生中被**跳过**(组装后的消息才是权威的)。**空内容**的 `assistant/message` 也被跳过:max-tokens 截断且无内容的步骤仍会记录 `assistant/message` 以承载其 `usage`,但无内容的 assistant 轮次不得进入提供方的 transcript(文本记录)。 +- `assistant/message` → 一条 assistant 消息。原始 `assistant/chunk` 事件是回放/UI 数据,在派生中被**跳过**(组装后的消息才是权威的)。**空内容**的 `assistant/message` 也被跳过:一个因 max-tokens 截断且无内容的步骤仍会记录 `assistant/message` 以承载其 `usage`,但无内容的 assistant 轮次不得进入提供方的 transcript(文本记录)。 - `tool/result` → 一条携带 `tool-result` 块的 user 消息。 -- `context/message`、`steering/message` → 按时间顺序插入的 user 角色消息,包裹在标签信封中(`<context source="…">…</context>`)。这是"系统提醒"模式;模型通过信封将它们与真实提示词区分开来。 +- `context/message`、`steering/message` → 以 user 角色、按时间顺序插入的消息,包裹在标记信封中(`<context source="…">…</context>`),即「系统提醒」模式;模型通过信封区分它们与真实提示词。 -其他一切(`turn/*`、`step/*`)是结构性的,不投影为消息。token 用量在 `assistant/message.usage` 上观察(即产生它的那个步骤);操作错误的步骤编号在 `turn/end.reason` 中(`kind: 'error'` 时)。 +其他一切(`turn/*`、`step/*`)是结构性事件,不投影为消息。token 用量通过 `assistant/message.usage` 观察(产生该用量的步骤);操作错误的步骤号在 `turn/end.reason` 中(`kind: 'error'` 时)。 ## 活跃会话 fork API `ctx.sessions.create(id, { seed, meta })` 是底层的回放/fork 原语。对于普通的活跃会话 fork,`SessionStore` 暴露一个策略 API: -- `fork(source, boundary?, childSessionId?)` 接受一个活跃的 `Session` 对象或活跃的 `SessionId`,选取源事件直到(含)`boundary` seq(默认:当前最后一个事件),要求 boundary 事件为 `turn/end`,然后创建一个活跃的子会话,包含深克隆的种子事件和子元数据(`parentSession`、`seedLength` 以及继承的 `cwd`)。 +- `fork(source, boundary?, childSessionId?)` 接受一个活跃的 `Session` 对象或活跃的 `SessionId`,选取到 `boundary` seq(含)为止的源事件(默认为当前最后一个事件),要求 boundary 事件必须是 `turn/end`,然后创建一个活跃的子会话,包含深克隆的种子事件和子会话元数据(`parentSession`、`seedLength` 及继承的 `cwd`)。 -显式 `boundary` 允许调用方从之前完成的轮次 fork,即使源有更新的事件或一个未关闭的当前轮次。API 拒绝非 `turn/end` 的 boundary,而不是静默裁剪。更广泛的轮次封闭性检查保留在既有的 `dsh-invariants` 插件和持久化修复路径中,而非在 `fork()` 中重复。`dsh-subagent-fork` 保留其已完成前缀裁剪逻辑,因为工具时委托通常在父轮次打开时启动;普通的会话分支应显式指定所请求的 boundary。 +显式 `boundary` 允许调用者从之前完成的轮次 fork,即使源会话有更新的事件或正在进行的轮次。API 拒绝非 `turn/end` 的 boundary,而不是静默截断。更广泛的轮次封闭性检查留在既有的 `dsh-invariants` 插件和持久化修复路径中,不在 `fork()` 中重复。`dsh-subagent-fork` 保留其已完成前缀截断逻辑,因为工具时委托通常在父轮次仍然打开时启动;普通的会话分支应显式指定请求的 boundary。 ## 轮次的触发原因:`TurnTriggerMap` @@ -293,20 +293,20 @@ interface TurnEndReasonMap { } ``` -`max-tokens` 对应同名的模型调用 `FinishReason`:轮次中任何一个步骤出现 `max-tokens`,整个轮次就以 `max-tokens` 结束而非 `completed`(截断事实优先于后续续写),消费方可以区分正常停止与被截断的情况。但这仅相对于 `completed` 而言:`disposed`/`aborted`/`error` 结果优先级更高。`rejected` 是一个零步骤轮次,其整个提示词批次被 `agent/prompt-submit` 钩子阻止(ACP 桥接层将其映射为 `cancelled`)。`interrupted` 是唯一不由循环发出的 reason,由崩溃恢复合成(见 [persistence.md](persistence.md))。两个 map 均可通过合并扩展。 +`max-tokens` 对应同名的模型调用 `FinishReason`:轮次中任何一个步骤出现 `max-tokens`,整个轮次就以 `max-tokens` 结束而非 `completed`(截断事实优先于后续的继续),消费方据此区分正常停止与被截断的情况。但这仅相对于 `completed` 而言:`disposed`/`aborted`/`error` 结果优先级更高。`rejected` 是一个零步骤轮次,其整批提示词被 `agent/prompt-submit` 钩子阻止(ACP 桥接层将其映射为 `cancelled`)。`interrupted` 是唯一不由 loop 发出的原因,由崩溃恢复合成(见 [persistence.md](persistence.md))。两个 map 均可通过合并扩展。 ## 轮次封闭不变式 -每个会话事件都位于一个轮次**内部**(在 `turn/start` 与其对应的 `turn/end` 之间)。循环在 `turn/start` *之后*追加排队的 `user/message` 事件;空闲时的 `agent.inject()` 将其 `context/message` 包裹在一个一次性的 `injection` 轮次中。这使得轮次成为唯一的持久性/回放边界:后端可以将最后一个 `turn/end` 之后的任何内容视为中断崩溃的尾部,而不会误丢合法记录的轮次间上下文。`dsh-invariants` 插件在开发环境中强制执行此不变式(在未打开的轮次中追加消息事件会抛出异常)。见[轮次封闭不变式 RFC](../rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md)。 +每个会话事件都存在于一个轮次**内部**(位于 `turn/start` 与其对应的 `turn/end` 之间)。loop 在 `turn/start` *之后*追加排队的 `user/message` 事件;空闲时的 `agent.inject()` 将其 `context/message` 包裹在一个一次性的 `injection` 轮次中。这使得轮次成为唯一的持久性/回放边界:后端可以将最后一个 `turn/end` 之后的任何内容视为中断崩溃的尾部,而不会误丢合法记录的轮次间上下文。`dsh-invariants` 插件在开发环境中强制执行此不变式(在无打开轮次时追加消息事件会抛出异常)。见[轮次封闭不变式 RFC](../rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md)。 ## 插件贡献的仅日志事件 -插件可以通过 declaration merging 向 `SessionEventMap` 添加额外类型。这些是**仅日志**事件:不是 `SurfaceEventType`(不携带 `surfaceOp`,不参与派生历史),但与所有事件一样,必须位于一个已打开的轮次内。完整的逐事件枚举(核心与插件贡献的,含 payload 和溯源信息)见生成的[持久化日志事件目录](../persistence-catalog.md);压缩 seam 的 `compact/*` 语义在 [compaction.md](compaction.md) 中讨论。 +插件可以通过 declaration merging 添加额外的 `SessionEventMap` 类型。这些是**仅日志**事件:不是 `SurfaceEventType`(不携带 `surfaceOp`,不参与派生历史),但与所有事件一样,必须位于一个打开的轮次内。完整的逐事件枚举(核心与插件贡献的,含 payload 与溯源信息)见生成的[持久化日志事件目录](../persistence-catalog.md);压缩 seam 的 `compact/*` 语义在 [compaction.md](compaction.md) 中讨论。 -钩子桥接的 `hook/invoked` / `hook/result` 溯源对(来自 `@deepseek-ai/dsh-hook-protocol`)通过 `handlerId` 关联。轮次中的钩子点(`PreToolUse`/`PostToolUse`/`UserPromptSubmit`/`Stop`)在循环的已打开轮次内触发,因此其 `hook/*` 记录天然满足轮次封闭。`SessionStart` 没有 `hook/*` 记录(其注入的 `context/message` 就是持久证据),因为它没有可以容纳记录的已打开轮次(见[钩子桥接 RFC](../rfc/implemented/feature/2026-06-30-hook-bridges.md))。 +钩子桥接的 `hook/invoked` / `hook/result` 溯源对(来自 `@deepseek-ai/dsh-hook-protocol`)通过 `handlerId` 关联。轮次中的钩子点(`PreToolUse`/`PostToolUse`/`UserPromptSubmit`/`Stop`)在 loop 打开的轮次内触发,因此其 `hook/*` 记录天然满足轮次封闭。`SessionStart` 不产生 `hook/*` 记录(其注入的 `context/message` 就是持久证据),因为它没有打开的轮次来容纳记录(见[钩子桥接 RFC](../rfc/implemented/feature/2026-06-30-hook-bridges.md))。 ## 持久性契约 -持久化后端所依赖的契约:持久日志逐字保存每个事件,**包括** `assistant/chunk`。`seq` 必须保持连续,因此不能从规范日志中过滤掉 chunk。所有 `event.data` 必须是 JSON 可序列化的;`Session.append` 在源头强制执行此约束(对不可序列化的数据抛出异常),因此坏事件永远不会进入日志,`session.events` 始终等于后端可以持久化的内容。添加一个携带不可序列化数据的事件类型,或破坏不变式插件所检查的轮次/步骤嵌套,都是对磁盘格式的破坏性变更。 +持久化后端所依赖的约定:持久日志逐字保存每个事件,**包括** `assistant/chunk`。`seq` 必须保持连续,因此不能从规范日志中过滤掉 chunk。所有 `event.data` 必须可 JSON 序列化;`Session.append` 在源头强制执行此约束(对不可序列化的数据抛出异常),因此坏事件永远不会进入日志,`session.events` 始终等于后端能持久化的内容。添加一个携带不可序列化数据的事件类型,或破坏不变式插件所检查的 turn/step 嵌套结构,都是对磁盘格式的破坏性变更。 消费此契约的后端见 [persistence.md](persistence.md)。 diff --git a/docs/core-data-structures/skills.i18n.yaml b/docs/core-data-structures/skills.i18n.yaml index 8958dbe359..32c97d6b0a 100644 --- a/docs/core-data-structures/skills.i18n.yaml +++ b/docs/core-data-structures/skills.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write skills.md: b0a847cec05651b63e63de96423170a0fd7ca2a9 -skills.zh.md: db196d2058cd1ede2ef7c9fda7668720ea2824b9 +skills.zh.md: 201bf53e95b5cbf5f8873217acca3c478cf30860 diff --git a/docs/core-data-structures/skills.zh.md b/docs/core-data-structures/skills.zh.md index db196d2058..201bf53e95 100644 --- a/docs/core-data-structures/skills.zh.md +++ b/docs/core-data-structures/skills.zh.md @@ -2,13 +2,13 @@ [English](skills.md) | 中文 -[skill(技能)能力族](../../packages/skill)拆分为三个包(package):注册表([dsh-skill](../../packages/skill/skill),`ctx.skills`)合并各提供方的目录;本地提供方([dsh-skill-local](../../packages/skill/skill-local))扫描项目/自定义/用户目录;消费方([dsh-tool-skill](../../packages/skill/tool-skill))拥有会话前缀目录和面向模型的 `skill` 工具。Skill 是可选指令而非会话事件,因此其词汇定义在此处而非 [core.md](core.md)。 +[skill 能力族](../../packages/skill)拆分为三个包(package):注册表([dsh-skill](../../packages/skill/skill),`ctx.skills`)合并各提供方的目录;本地提供方([dsh-skill-local](../../packages/skill/skill-local))扫描项目/自定义/用户目录;消费方([dsh-tool-skill](../../packages/skill/tool-skill))拥有会话前缀目录和面向模型的 `skill` 工具。skill(技能)是可选的指令而非会话事件,因此其词汇定义在此处而非 [core.md](core.md)。 源码:[`packages/skill/skill/src/index.ts`](../../packages/skill/skill/src/index.ts)、[`packages/skill/skill-local/src/index.ts`](../../packages/skill/skill-local/src/index.ts) 与 [`packages/skill/tool-skill/src/index.ts`](../../packages/skill/tool-skill/src/index.ts)。 ## 提供方注册表 -`ctx.skills` 组合本地、内嵌、远程或其他提供方。注册是同步的;远程初始化和发现属于 await 的 `list()`。提供方对象、选项和候选项以只读方式借用,语义字段会被校验。 +`ctx.skills` 组合本地、内嵌、远程或其他提供方。注册是同步的;远程初始化与发现属于 `list()` 的 await 阶段。提供方对象、选项与候选项以只读方式借用,语义字段会被校验。 重名按 rank、提供方顺序、本地顺序依次解决;摘要按名称排序。`list()` 拒绝时记录日志并跳过,不缓存降级后的目录;格式错误的候选项快速失败。 @@ -22,7 +22,7 @@ interface SkillProvider { ## 本地发现优先级 -内置的本地提供方按 rank 顺序扫描根目录: +内置的本地提供方按 rank 顺序扫描各根目录: | Rank | Source | Root | |---|---|---| @@ -32,11 +32,11 @@ interface SkillProvider { | 400 | `user-dsh` | `<dshHome>/skills` | | 500 | `user-agents` | `<agentsHome>/skills` | -项目根目录是最近的包含 `.git` 的祖先目录;找不到时使用当前 cwd。当 `ctx.fs` 可用时,git-root 遍历通过文件系统服务探测 `.git`,使远程或沙箱化的工作区不会回退到宿主文件系统边界。用户 DSH 根目录会跳过其 `.system` 子目录。本地提供方不附带内置系统 skill;部署方通过另一个提供方提供内置 skill。 +项目根目录为包含 `.git` 的最近祖先目录;找不到时使用当前 cwd。当 `ctx.fs` 可用时,git-root 向上查找通过文件系统服务探测 `.git`,使远程或沙箱工作区不会回退到宿主文件系统边界。用户 DSH 根目录会跳过其 `.system` 子目录。本地提供方不附带内置系统 skill;部署方通过另一个提供方提供内置 skill。 -## Skill 标识 +## Skill 身份 -Skill 名称为 kebab-case(`^[a-z0-9]+(?:-[a-z0-9]+)*$`)。本地提供方接受目录包(`<name>/SKILL.md`)和扁平 Markdown 文件(`<name>.md`)。嵌套递归的 `**/SKILL.md` 发现有意不在 v1 范围内。 +skill 名称为 kebab-case(`^[a-z0-9]+(?:-[a-z0-9]+)*$`)。本地提供方接受目录包(`<name>/SKILL.md`)和扁平 Markdown 文件(`<name>.md`)。嵌套递归的 `**/SKILL.md` 发现有意不在 v1 范围内。 ```ts type-equiv type SkillSource = 'project-dsh' | 'project-agents' | 'runtime' | 'user-dsh' | 'user-agents' | 'custom' | (string & {}) @@ -44,7 +44,7 @@ type SkillSource = 'project-dsh' | 'project-agents' | 'runtime' | 'user-dsh' | ' ## 摘要、候选项与完整定义 -`SkillSummary` 是注册表面向模型可调用的摘要形状。消费方自行选择渲染哪些字段;会话目录仅使用 `name` 和 `description`,从不使用正文或绝对文件路径。`disableModelInvocation` 将 skill 从模型列表中隐藏,但允许受信代码按名称加载。 +`SkillSummary` 是注册表中可供模型调用的摘要形状。消费方自行选择渲染哪些字段;会话目录仅使用 `name` 和 `description`,从不使用 body 或绝对文件路径。`disableModelInvocation` 将 skill 从模型列表中隐藏,但允许受信代码按名称加载。 ```ts type-equiv interface SkillSummary { @@ -58,7 +58,7 @@ interface SkillSummary { } ``` -`SkillCandidate` 是提供方到注册表的形状。`locator` 是提供方的不透明状态;注册表只存储它并在调用获胜提供方的 `get()` 时回传。 +`SkillCandidate` 是提供方到注册表的形状。`locator` 是提供方的不透明状态;注册表只存储它并在调用获胜提供方的 `get()` 时传回。 ```ts type-equiv interface SkillCandidate extends SkillSummary { @@ -69,7 +69,7 @@ interface SkillCandidate extends SkillSummary { } ``` -`SkillDefinition` 是 `ctx.skills.get()` 返回的完整解析结果,供 `skill` 工具使用。`resourceBase` 告诉工具如何为本地、URL 或提供方管理的 skill 渲染相对资源指引。 +`SkillDefinition` 是 `ctx.skills.get()` 返回的完整解析结果,供 `skill` 工具使用。`resourceBase` 告知工具如何为本地、URL 或提供方管理的 skill 渲染相对资源引导。 ```ts type-equiv type SkillResourceBase = @@ -96,7 +96,7 @@ type SkillRegistration = Omit<SkillDefinition, 'provider'> & { ## 查找与配置 -Skill 查找对 cwd 敏感,因为提供方可能暴露工作区本地的 skill;可选的 signal 为调用方取消提供方工作。提供方接收同一个只读选项对象,用于缓存标识和加载。取消在目录选择前后(包括缓存命中)都会检查,并同时竞争发现和完整定义加载。如果找不到 git 根目录,本地提供方将提供的 cwd 本身视为项目根目录。 +skill 查找对 cwd 敏感,因为提供方可能暴露工作区本地的 skill;可选的 signal 为调用方取消提供方的工作。提供方接收与缓存标识和加载相同的只读选项对象。取消在目录选择前后(包括缓存命中时)都会检查,并与发现和完整定义加载竞争。如果找不到 git root,本地提供方将所提供的 cwd 本身视为项目根目录。 ```ts type-equiv interface SkillLookupOptions { @@ -105,7 +105,7 @@ interface SkillLookupOptions { } ``` -注册表只拥有其发现缓存上限。本地提供方拥有文件系统根目录(`dshHome`、`agentsHome` 和 `customSkillDirs`)。消费方拥有其目录描述上限。 +注册表只拥有其发现缓存上限。本地提供方拥有文件系统根目录(`dshHome`、`agentsHome` 与 `customSkillDirs`)。消费方拥有其目录描述上限。 ```ts type-equiv interface Config { @@ -115,6 +115,6 @@ interface Config { ## 会话目录与工具契约 -`dsh-tool-skill` 通过 `agent/session-prefix` 贡献一个 user-role 的 `<system-reminder>`。目录包含按名称排序的 skill `name` 和经过规范化、XML 转义的 `description`;不包含正文、路径、来源、提供方和路由提示。前缀发现通过 `SkillLookupOptions` 转发调用方的 abort signal。`catalogDescriptionMaxLength` 是消费方配置的描述上限,默认 `500`,整数最小值 `3`。其仅限请求、记录于 header 的生命周期由 [session-prefix RFC](../rfc/implemented/feature/2026-07-07-session-prefix.md) 定义。 +`dsh-tool-skill` 通过 `agent/session-prefix` 贡献一条 user-role 的 `<system-reminder>`。目录包含排序后的 skill `name` 和经过规范化、XML 转义的 `description`;不包含 body、路径、来源、提供方和路由提示。前缀发现通过 `SkillLookupOptions` 转发调用方的 abort signal。`catalogDescriptionMaxLength` 是消费方配置的描述上限,默认值 `500`,整数最小值 `3`。其仅请求级别、记录于 header 的生命周期由 [session-prefix RFC](../rfc/implemented/feature/2026-07-07-session-prefix.md) 定义。 -面向模型的 `skill({ name })` 工具校验 kebab-case 名称,为调用 agent 的 cwd 加载完整定义,将未解决的 skill 报告为未知或不再可用,拒绝 `disableModelInvocation` 的 skill,并返回包含 `<skill_content name="...">`、`<skill_resources>` 和 `<skill_instructions>` 的工具结果。`resourceBase` 仅按需解析显式引用的脚本、参考资料和资产;加载结果不枚举 skill 目录。工具结果是模型获取完整指令的可见路径。 +面向模型的 `skill({ name })` 工具校验 kebab-case 名称,为调用方 agent 的 cwd 加载完整定义,将未解析的 skill 报告为 unknown 或 no longer available,拒绝 `disableModelInvocation` 的 skill,并返回包含 `<skill_content name="...">`、`<skill_resources>` 和 `<skill_instructions>` 的工具结果。`resourceBase` 仅按需解析显式引用的脚本、参考资料和资产;加载结果不枚举 skill 目录。工具结果是模型获取完整指令的可见路径。 diff --git a/docs/core-data-structures/subagent.i18n.yaml b/docs/core-data-structures/subagent.i18n.yaml index b859346be3..6d4a5fdaf2 100644 --- a/docs/core-data-structures/subagent.i18n.yaml +++ b/docs/core-data-structures/subagent.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write subagent.md: eb9160abaee26969aecdc533fb9fd56fae18b7fa -subagent.zh.md: f29ebcd50b5d3a6d961583e381b81eb88ab95823 +subagent.zh.md: c8f680217a9f62f245a4de81cbc546deba87bbed diff --git a/docs/core-data-structures/subagent.zh.md b/docs/core-data-structures/subagent.zh.md index f29ebcd50b..c8f680217a 100644 --- a/docs/core-data-structures/subagent.zh.md +++ b/docs/core-data-structures/subagent.zh.md @@ -2,15 +2,15 @@ [English](subagent.md) | 中文 -subagent seam:一个 agent(智能体)将工作委派给子 agent。与 [bash](bash.md) 类似,它是**一项可选能力**,不属于 agent loop(智能体循环)的主干,因此其词汇定义在这里而非 [core.md](core.md)。但它在一个维度上与其他所有 seam 不同:**多个提供方实现在同一个上下文中共存**,按名称注册(`ctx.subagents`),而 bash 只允许一个执行器。注册表的形状参照 [LLM 适配器注册表](llm-streaming.md),而非单服务的 bash 执行器。 +subagent seam:一个 agent(智能体)将工作委派给子 agent。与 [bash](bash.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。但它在一个维度上与其他所有 seam 不同:**同一上下文中可共存多个提供方实现**,按名称注册(`ctx.subagents`),而 bash 只允许一个执行器。注册表的形状参照 [LLM 适配器注册表](llm-streaming.md),而非单服务的 bash 执行器。 -接口:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。实现是兄弟包(`dsh-subagent-spawn`、`-fork`、`-acp`);面向模型的消费方是 [dsh-tool-subagent](../../packages/subagent/tool-subagent)。提案与设计动机见 [subagent RFC](../rfc/implemented/feature/2026-06-21-subagent-capability-seam.md)。 +接口:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。实现为兄弟包(`dsh-subagent-spawn`、`-fork`、`-acp`);面向模型的消费方是 [dsh-tool-subagent](../../packages/subagent/tool-subagent)。提案与设计动机见 [subagent RFC](../rfc/implemented/feature/2026-06-21-subagent-capability-seam.md)。 源码:[`packages/subagent/subagent/src/types.ts`](../../packages/subagent/subagent/src/types.ts) ## 两类能力,两种发现方式 -提供方通过一个静态描述符公布其**启动时**特性,服务在运行实例存在之前就会检查它;如果请求需要提供方不具备的特性,会被大声拒绝(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不会接受后静默忽略。**运行时**特性(steering(中途引导)、resume)则是 [`SubagentRun`](#a-live-run-subagentrun) 上的可选方法:方法的存在本身即为能力,TypeScript 的类型收窄就是发现机制。 +提供方通过一个静态描述符公布其**启动时**特性,服务在 run 存在之前即行检查;如果请求依赖提供方不具备的特性,会被大声拒绝(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不会被接受后静默忽略。**运行时**特性(steering(中途引导)、resume)则是 [`SubagentRun`](#a-live-run-subagentrun) 上的可选方法——方法的存在即为能力,TypeScript 的类型收窄即为发现机制。 ```ts type-equiv interface SubagentCapabilities { @@ -23,7 +23,7 @@ interface SubagentCapabilities { ## 启动请求 -工具层根据模型输入和自身配置构建此请求;服务在 `start` 之前对照指定提供方进行校验。必填的 `parent` 提供会话 cwd、血统链和委派深度。可选的 output schema、depth、tool filter 和 persona 需要对应的能力标志位。不支持的 schema 在启动时即失败;进程内后端将 filter 和 persona 限定在子 agent 创建阶段,并通过一个强制捕获工具实现所支持的 object-rooted schema。 +工具层根据模型输入和自身配置构建此请求;服务在 `start` 之前针对指定提供方进行校验。必填的 `parent` 提供会话 cwd、谱系与委派深度。可选的 output schema、depth、tool filter 和 persona 需要对应的能力 flag 匹配。不支持的 schema 在启动时即失败;进程内后端将 filter 和 persona 的作用域限定在子 agent 创建阶段,并通过强制 capture tool 实现所支持的 object-rooted schema。 ```ts type-equiv interface SubagentStartRequest { @@ -38,11 +38,11 @@ interface SubagentStartRequest { } ``` -`signal` 是就绪前后唯一的取消通道。[subagent 组合控制 RFC](../rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 拥有 persona、实时全局工具过滤、绝对深度以及「可见性而非权限」的设计理由。 +`signal` 是就绪前后唯一的取消通道。[subagent 组合控制 RFC](../rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 负责 persona、运行时全局工具过滤、绝对深度以及「可见性而非权限」的设计理由。 ## 终态结果:`SubagentResult` -一次运行的结果,由 `SubagentRun.result` resolve。`structured` 仅在请求了 `outputSchema` 且成功满足时才存在;请求 schema 不保证一定能得到,提供方在子 agent 失败或结束时未产出有效捕获时可能返回 `stopReason: 'error'`。非 `completed` 的 `stopReason` 意味着 `output` 可能不完整:消费方将其映射为 `isError` 的工具结果,而非把不完整的输出当作成功上报。 +一次 run 的最终产出,由 `SubagentRun.result` resolve。`structured` 仅在请求了 `outputSchema` 且成功满足时才存在;请求 schema 不保证一定能得到它,当子 agent 失败或结束时未产出有效 capture 时,提供方可能返回 `stopReason: 'error'`。非 `completed` 的 `stopReason` 意味着 `output` 可能不完整——消费方将其映射为 `isError` 的工具结果,而非将部分输出报告为成功。 ```ts type-equiv interface SubagentResult { @@ -52,7 +52,7 @@ interface SubagentResult { } ``` -`SubagentStopReason` 是一个[可合并扩展的派生联合类型](core.md#the-map--derived-union-pattern):后端可以添加变体,因此消费方应对已知 case 分支处理,并将未知的终态原因视为失败: +`SubagentStopReason` 是一个[可合并扩展的派生联合类型](core.md#the-map--derived-union-pattern)——后端可以添加变体,因此消费方应对已知 case 分支处理,将未知的终态原因视为失败: ```ts type-equiv interface SubagentStopReasonMap { @@ -64,9 +64,9 @@ interface SubagentStopReasonMap { } ``` -## 活跃运行:`SubagentRun` +## 活跃 run:`SubagentRun` -`SubagentRun` 是消费方持有的、指向一个就绪子 agent 的句柄。消费方 await `result` 并始终 dispose 该运行以达到静止态。子 agent 失败以非 completed 的 stop reason resolve;只有无法表示的基础设施故障才会 reject。可选的 `sendMessage` 和 `resume` 方法通过其存在性公布运行时能力。 +`SubagentRun` 是消费方持有的、指向一个就绪子 agent 的句柄。消费方 await `result` 并始终 dispose(资源释放)该 run 以达到静止状态。子 agent 失败时以非 completed 的 stop reason resolve;只有不可表示的基础设施故障才会 reject。可选的 `sendMessage` 和 `resume` 方法通过自身的存在来公布运行时能力。 ```ts type-equiv interface SubagentRun { @@ -80,7 +80,7 @@ interface SubagentRun { ## 提供方 seam:`SubagentProvider` -每个提供方是一个具名的子 agent 传输层,多个提供方可以共存。服务在 `start()` 之前校验请求的启动时能力。`inheritsParentContext` 仅描述对话种子行为(`fork`:true;`spawn` 和 `acp`:false),使消费方能生成准确的面向模型的措辞,而不暗示继承了工具、服务或权限。 +每个提供方是一个具名的子 agent 传输层,多个提供方可以共存。服务在 `start()` 之前校验请求的启动时能力。`inheritsParentContext` 仅描述对话种子注入(`fork`:true;`spawn` 和 `acp`:false),使消费方能生成准确的面向模型的措辞,而不暗示继承了工具、服务或权限。 ```ts type-equiv interface SubagentProvider { @@ -91,11 +91,11 @@ interface SubagentProvider { } ``` -`start()` 仅在运行就绪时才 fulfill。服务观察其 result、发出 `subagent/start`,并返回同一个 run;rejection 意味着提供方已自行清理,且不发出生命周期事件对。进程内子 agent 可通过 `ctx.agents` 发现,远程子 agent 则不必如此。`subagent/end` 报告最终输出或基础设施故障。两个事件均为仅观察事件,包含监听器异常。 +`start()` 仅在 run 就绪时 fulfill。服务观察其 result、发出 `subagent/start`,并返回同一个 run;rejection 意味着提供方已自行清理,不发出生命周期配对事件。进程内子 agent 可通过 `ctx.agents` 发现,远程子 agent 则不必如此。`subagent/end` 报告最终输出或基础设施故障。两个事件均为仅观察事件,包含监听器异常。 ## 进程内后端:深度与种子 -spawn 和 fork 后端通过 `parent.ctx` 创建一个普通 agent,将取消信号传入核心创建过程,并通过 `AgentHandle` 进行 dispose。提供方被移除时会阻止新的 start,但不会撤销已接受的运行。每个子 agent 获得一个新的扁平作用域,而非继承父级的注册。深度和 fork 种子复用既有的 agent 与会话词汇: +spawn 和 fork 后端通过 `parent.ctx` 创建一个普通 agent,将取消信号传入核心创建流程,并通过 `AgentHandle` 进行 dispose。移除提供方会阻止新的 start,但不会撤销已接受的 run。每个子 agent 获得一个新的扁平作用域,而非继承父级注册。深度与 fork 种子注入复用既有的 agent 和会话词汇: -- **委派深度**是一个可合并扩展的 `AgentOptions.subagentDepth` 字段(顶层 agent 为 `0`,子 agent 为 parent + 1)。只有 `undefined` 表示顶层;每个已存储的 present 值必须是非负安全整数。该 seam 拥有此字段:循环既不设置也不读取它。嵌套 spawn 校验其父级的已存储深度,拒绝超出安全整数范围的派生子深度,并将已定义的绝对 `request.maxDepth` 上限应用于该子 agent。 -- **Fork 种子**使用 `CreateAgentOptions.seed`(一个 `SessionEvent[]` 前缀,经由 `AgentLoop.createAgent` → `ctx.sessions.prepare({ seed })` 传递,与 resume 使用的是同一原语)。fork 后端传入父级日志的一段*平衡的已完成轮次前缀*:父级事件直到并包含其最后一个 `turn/end`。因此种子从 0 开始连续,[invariants](../../packages/support/invariants) 的回放能接受它(进行中的、未平衡的轮次被排除在外)。 +- **委派深度**是一个可合并扩展的 `AgentOptions.subagentDepth` 字段(顶层 agent 为 `0`,子 agent 为 parent + 1)。只有 `undefined` 表示顶层;所有已存储的值必须是非负安全整数。该字段归 seam 所有——循环既不设置也不读取它——因此嵌套 spawn 会校验父级的已存储深度,拒绝超出安全整数域的派生子深度,并在定义了绝对 `request.maxDepth` 上限时将其施加于子 agent。 +- **Fork 种子注入**使用 `CreateAgentOptions.seed`(一个 `SessionEvent[]` 前缀,经由 `AgentLoop.createAgent` → `ctx.sessions.prepare({ seed })` 传递,与 `resume` 使用的原语相同)。fork 后端传入父级日志的一段*平衡的已完成轮次前缀*——父级事件直到并包括其最后一个 `turn/end`——因此种子从 0 连续,[invariants](../../packages/support/invariants) 回放可以接受它(进行中的、未平衡的轮次被排除在外)。 diff --git a/docs/core-data-structures/system-prompt.i18n.yaml b/docs/core-data-structures/system-prompt.i18n.yaml index b07308b84a..f2918af35f 100644 --- a/docs/core-data-structures/system-prompt.i18n.yaml +++ b/docs/core-data-structures/system-prompt.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write system-prompt.md: 175f2af407e5c39a24f0f8f8e4e664063b897ead -system-prompt.zh.md: ea1f48c56f18c97203e1052d6d0eca72710e942d +system-prompt.zh.md: 8827ac0b915915f716643e0a9e04edaacedbc868 diff --git a/docs/core-data-structures/system-prompt.zh.md b/docs/core-data-structures/system-prompt.zh.md index ea1f48c56f..8827ac0b91 100644 --- a/docs/core-data-structures/system-prompt.zh.md +++ b/docs/core-data-structures/system-prompt.zh.md @@ -2,13 +2,13 @@ [English](system-prompt.md) | 中文 -[system-prompt 包](../../packages/core/system-prompt)定义了提示词贡献方与单次组装调用之间交换的数据。包的 [README](../../packages/core/system-prompt/README.md) 文档记录了注册、排序、作用域与渲染行为;本页固定各插件实现或传递的跨包字面形状。 +[system-prompt 包](../../packages/core/system-prompt)负责管理 prompt 贡献者与一次组装调用之间交换的数据。该包的 [README](../../packages/core/system-prompt/README.md) 记录了注册、排序、作用域与渲染行为;本页固定各插件实现或传递的跨包字面形状。 源码:[`packages/core/system-prompt/src/index.ts`](../../packages/core/system-prompt/src/index.ts)。 ## 组装上下文 -`AssembleContext` 标识单次组装所解析的作用域层。它可通过合并扩展:`dsh-agent` 添加了可选的运行时 `agent` 字段,`assembleContextFor(agent)` 同时设置该字段与 `scope`。 +`AssembleContext` 标识一次组装所解析的作用域层。它可通过合并扩展:`dsh-agent` 添加可选的活跃 `agent` 字段,`assembleContextFor(agent)` 同时设置该字段与 `scope`。 ```ts type-equiv interface AssembleContext { @@ -18,7 +18,7 @@ interface AssembleContext { ## 工具提供方结果 -`ToolProviderResult.schemas` 是当前组装中模型可见的工具集。`knownNames` 是提供方在限制前的完整名称集合,用于区分「配置名拼写错误」与「已知工具在此作用域下被有意隐藏」。 +`ToolProviderResult.schemas` 是当前组装中对模型可见的工具集合。`knownNames` 是提供方在限制前的名称全集,用于区分「配置名拼写错误」与「已知工具在此作用域中被有意隐藏」。 ```ts type-equiv interface ToolProviderResult { @@ -27,9 +27,9 @@ interface ToolProviderResult { } ``` -## 提示词段 +## Prompt 段落 -`PromptSection` 是一个只读的同进程注册契约。其文本可以是静态的,也可以从当前组装上下文动态解析。 +`PromptSection` 是一份只读的同进程注册契约。其文本可以是静态的,也可以从当前组装上下文动态解析。 ```ts type-equiv interface PromptSection { diff --git a/docs/core-data-structures/tools.i18n.yaml b/docs/core-data-structures/tools.i18n.yaml index 5b2b306ec9..1b2db95b67 100644 --- a/docs/core-data-structures/tools.i18n.yaml +++ b/docs/core-data-structures/tools.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write tools.md: f8be67054cd81027d4b751329948a784fa4f0ed9 -tools.zh.md: 080d0d99decb8630525e434a8079e29591e63ce9 +tools.zh.md: 8b77259b37b0e4c2118cc91af0e6dc3ca27c0479 diff --git a/docs/core-data-structures/tools.zh.md b/docs/core-data-structures/tools.zh.md index 080d0d99de..8b77259b37 100644 --- a/docs/core-data-structures/tools.zh.md +++ b/docs/core-data-structures/tools.zh.md @@ -2,13 +2,13 @@ [English](tools.md) | 中文 -[dsh-tools](../../packages/core/tools) 的工具流水线。[core.md](core.md) 介绍了 `ToolDefinition` 作为唯一被提升到主干的流水线编写类型,以及 `ToolSchema` 作为面向模型的协议格式(wire format)。本页拥有完整的 `ToolDefinition`、构建它的类型化 schema DSL、带守卫的执行形状,以及 UI 展示词汇。 +[dsh-tools](../../packages/core/tools) 的工具流水线。[core.md](core.md) 介绍了 `ToolDefinition`(唯一被提升到主干的流水线编写类型)和 `ToolSchema`(面向模型的协议格式(wire format)形状)。本页拥有完整的 `ToolDefinition`、用于构建它的类型化 schema DSL、受保护的执行形状,以及 UI 展示词汇。 源码:[`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) · [`packages/core/tools/src/schema.ts`](../../packages/core/tools/src/schema.ts) · [`packages/core/tools/src/presentation.ts`](../../packages/core/tools/src/presentation.ts) -## `ToolDefinition`:一个已注册的工具 +## `ToolDefinition` — 一个已注册的工具 -一个 `ToolSchema`(面向模型的字段)加上 `execute` 函数与可选的 UI 展示器。注册表持有这些定义;agent loop(智能体循环)通过它们分发调用。注册表的 `schemas()` 通过显式白名单构建面向模型的 `ToolSchema[]`:`execute`/`presentCall`/`presentResult` 绝不能泄漏到模型请求中。 +一个 `ToolSchema`(面向模型的字段)加上 `execute` 函数和可选的 UI 展示器。注册表持有这些定义;agent loop(智能体循环)通过它们分派调用。注册表的 `schemas()` 通过显式白名单构建面向模型的 `ToolSchema[]`——`execute`/`presentCall`/`presentResult` 绝不能泄漏到模型请求中。 ```ts type-equiv interface ToolDefinition extends ToolSchema { @@ -42,11 +42,11 @@ interface ToolDefinition extends ToolSchema { } ``` -`execute` 接收 `args: unknown`:原始的 `ToolDefinition` 自行校验输入。第一方工具不需要手写校验;它们使用 `defineTool`,由后者代为校验和收窄类型。 +`execute` 接收 `args: unknown`——原始的 `ToolDefinition` 自行校验输入。第一方工具不需要手写校验;它们使用 `defineTool`,由后者代为校验并收窄类型。 ## 类型化 schema DSL -插件作者为每个属性编写带有布尔值 `required: true` 的规格,类型层面的辅助工具将规格映射为 `execute` 的参数类型——零类型断言。该 DSL 是为 `ToolDefinition` *提供类型*的机制;它有意作为子页面细节,不属于核心。 +插件作者为每个属性编写带有布尔值 `required: true` 的规格,类型层面的辅助工具将规格映射为 `execute` 的参数类型——零类型断言。该 DSL 是为 `ToolDefinition` 提供类型的*机制*;它有意作为子页面细节,而非核心内容。 源码:[`packages/core/tools/src/schema.ts`](../../packages/core/tools/src/schema.ts) @@ -72,7 +72,7 @@ interface SchemaProp { type SchemaSpec = Record<string, SchemaProp> ``` -`SchemaType` 是原始联合类型 `'string' | 'number' | 'boolean' | 'object' | 'array'`。`InferArgs<S>` 将一个 `SchemaSpec` 映射为 TS 参数类型:`required: true` 的属性成为必选键,其余为真正的可选: +`SchemaType` 是原始联合类型 `'string' | 'number' | 'boolean' | 'object' | 'array'`。`InferArgs<S>` 将一个 `SchemaSpec` 映射为 TS 参数类型——`required: true` 的属性成为必选键,其余为真正的可选: ```ts type-equiv type InferArgs<S extends SchemaSpec> = Simplify< @@ -81,11 +81,11 @@ type InferArgs<S extends SchemaSpec> = Simplify< > ``` -`defineTool({ name, description, parameters, execute, … })` 将各部分串联:`parameters` 是一个 `SchemaSpec`,`execute(args, exec)` 得到 `args: InferArgs<typeof parameters>`,辅助函数将规格转换为 JSON Schema(`schemaSpecToJsonSchema`)用于协议传输,并在类型化函数体运行前校验模型生成的参数(`validateArgs`)。不匹配时抛出 `ToolArgsError`(`code: 'INVALID_ARGS'`),注册表将其转为 `isError` 结果以便模型自我修正。为什么用自定义 DSL 而非 schemastery:工具参数需要的是 JSON Schema(LLM(大语言模型)协议格式),不是校验/转换——轻量 DSL 以最小表面积提供最佳编写体验。 +`defineTool({ name, description, parameters, execute, … })` 将各部分串联:`parameters` 是一个 `SchemaSpec`,`execute(args, exec)` 获得 `args: InferArgs<typeof parameters>`,辅助函数将规格转换为 JSON Schema(`schemaSpecToJsonSchema`)用于协议传输,并在类型化函数体运行前校验模型生成的参数(`validateArgs`)。校验不通过时抛出 `ToolArgsError`(`code: 'INVALID_ARGS'`),注册表将其转为 `isError` 结果以便模型自行修正。为何用自定义 DSL 而非 schemastery:工具参数需要 JSON Schema(LLM(大语言模型)的协议格式),而非校验/转换——轻量 DSL 以最小的接口面积提供最佳的编写体验。 -注册是受信的同进程契约。注册表以 readonly 方式借用类型化定义作为输入,仅校验语义要求(如 `timeoutMs` 必须为正有限值);`schemas()` 在模型边界处具象化显式的面向模型投影,使执行与展示共享同一份已解析定义,而不会将回调泄漏到协议上。 +注册是一个受信任的同进程契约。注册表以 readonly 输入借用类型化定义,仅校验语义要求(如 `timeoutMs` 必须为正有限值);`schemas()` 在模型边界处物化显式的面向模型投影,使执行和展示共享同一份已解析定义,而不会将回调泄漏到协议上。 -## `ToolRestriction`:单个作用域的实时全局过滤器 +## `ToolRestriction` — 单个作用域的实时全局过滤器 `ToolRestriction` 仅作用于实时的部署全局工具层。注册表将 readonly 名称编译为私有集合,对多个限制取交集,再叠加作用域本地工具。仅 deny 的过滤器允许后续未列出的全局工具通过,而 allow 列表则排除它们。 @@ -98,7 +98,7 @@ interface ToolRestriction { ## 执行:可扩展的 waterfall(瀑布式事件)加单调策略 -`ctx.tools.execute()` 接受调用方拥有的 `ToolExecutionInput`,将其解析后的 JSON 参数一次性具象化为流水线拥有的 `ToolExecution`,然后将该调用依次通过 `tools/pre-execute`(可重排的 allow/deny/ask waterfall)→ 已注册的单调守卫 → `tools/execute`(around-dispatch 包装层)→ `tools/post-execute`(检查/替换结果)→ `tools/result`(不可变的权威结果)。最终结果是一个 `ToolExecutionResult`。 +`ctx.tools.execute()` 接收调用方拥有的 `ToolExecutionInput`,将其解析后的 JSON 参数一次性物化为流水线拥有的 `ToolExecution`,然后依次通过 `tools/pre-execute`(可重排的 allow/deny/ask waterfall)→ 已注册的单调 guard → `tools/execute`(around-dispatch 包装层)→ `tools/post-execute`(检查/替换结果)→ `tools/result`(不可变的权威结果)。最终产出为 `ToolExecutionResult`。 ```ts type-equiv type ToolExecutionToken = symbol & { readonly [toolExecutionTokenBrand]: true } @@ -129,9 +129,9 @@ interface ToolExecution extends ToolExecutionInput { } ``` -`ToolExecutionToken` 是一个不透明的运行时 `Symbol`,仅用于身份比较。在策略执行之前,`execute()` 具象化并冻结参数、拒绝非 JSON 输入、分配 token。身份字段和可选的 parent token 保持 readonly;只有 `signal` 可在 dispatch 前后变化。最终观察者接收到的是冻结的执行身份。 +`ToolExecutionToken` 是一个不透明的运行时 `Symbol`,仅用于身份比较。在策略执行之前,`execute()` 物化并冻结参数、拒绝非 JSON 输入、分配 token。身份字段和可选的 parent token 保持 readonly;只有 `signal` 可以在分派前后变化。最终观察者接收到的是冻结的执行身份。 -`ToolGuard` 是感知作用域的最终 pre-dispatch 策略。其形状有意不包含 allow 结果:`undefined` 保留 waterfall 的决策,而返回的 reason 只能缩减权限,因此后续监听器无法撤销它。 +`ToolGuard` 是感知作用域的最终预分派策略。其形状有意不包含 allow 结果:`undefined` 保留 waterfall 的决策,而返回的 reason 只能缩减权限,因此后续监听器无法撤销它。 ```ts type-equiv type ToolGuard = (execution: Readonly<ToolExecution>) => string | undefined @@ -168,9 +168,9 @@ interface ToolExecutionResult { } ``` -结果仅承载结果本身。调用身份保留在不可变的 `ToolExecution` 上,后者伴随结果通过每个钩子,也保留在持久化的 `tool/call` / `tool/result` 会话事件上,因此包装层无法创建第二个相互矛盾的身份。 +结果仅承载产出。调用身份保留在不可变的 `ToolExecution` 上,后者伴随结果经过每个钩子,并出现在持久化的 `tool/call` / `tool/result` 会话事件上,因此包装层无法创建第二个相互矛盾的身份。 -注册表在 `tools/result` 之前立即具象化并冻结最终接受的结果。其 content、结构化错误、附加上下文和展示元数据必须通过 JSON 无损往返;无效结果会被转为 JSON 安全的 `isError` 结果,确保被观察到的实时结果对后续持久化的 `tool/result` 追加是安全的。 +注册表在 `tools/result` 之前立即物化并冻结最终接受的结果。其内容、结构化错误、附加上下文和展示元数据必须通过 JSON 无损往返;无效的产出会被转为 JSON 安全的 `isError` 结果,从而保证被观察到的实时产出对后续持久化的 `tool/result` 追加是安全的。 每个拦截 waterfall 返回一个类型化的 **Decision**(与 `agent/*` seam 共享的惯用模式)。`tools/pre-execute` 监听器接收 `(exec, next)` 并返回 `PreToolDecision`;`tools/execute` 包装层返回 `ToolExecutionResult`;`tools/post-execute` 监听器接收 `(exec, result, next)` 并返回 `PostToolDecision`: @@ -187,13 +187,13 @@ type PostToolDecision = | { kind: 'block'; feedback: ContentBlock[]; additionalContext?: HookContext } ``` -调用 `next()` 走默认路径,或返回 decision 以短路。Pre-policy 可以 deny 或 ask;只有 `allowed-once` 才继续执行,而 non-grant、缺少审批通道或服务、或无 agent 的请求都会变为 denial。守卫仍可施加最终 denial。参数不可被改写,因为历史记录、审计、UI 和执行必须一致。 +调用 `next()` 获取默认决策,或直接返回一个决策以短路。前置策略可以 deny 或 ask;只有 `allowed-once` 才继续执行,而未授权、缺少审批通道或服务、或无 agent 的请求都会变为拒绝。Guard 仍可施加最终拒绝。参数不可被改写,因为历史记录、审计、UI 和执行必须保持一致。 -Post-policy 可以替换 content;block 会变为包含其纠正反馈的 `isError` 结果。`tools/result` 在归一化后接收冻结的执行和结果;观察者无法转换它们,观察者的失败被隔离。未知工具和抛出异常的工具都变为结构化错误(`ToolNotFoundError` 映射为 `UNKNOWN_TOOL`),调用失败但不终止当前轮次。 +后置策略可以替换内容;block 会变为包含纠正反馈的 `isError` 结果。`tools/result` 在归一化后接收冻结的执行和结果;观察者无法对其进行变换,观察者的失败也会被隔离。未知工具和抛出异常的工具都会变为结构化错误(`ToolNotFoundError` 映射为 `UNKNOWN_TOOL`),调用失败但不终止当前轮次。 ## 结构化输出 schema 子集 -调用方用来向 subagent 要求机器可读结果的词汇(`SubagentStartRequest.outputSchema`,见 [subagent.md](subagent.md#the-start-request)),或工作流 `agent()` 调用使用的词汇。它有意**不是**完整的 JSON Schema:schema 原样传递给模型作为强制工具的 `parameters`,产出的值由客户端的 `validateStructuredValue` 校验——因此每个被接受的关键字都必须是校验器实际执行的,`assertSupportedOutputSchema` 会大声拒绝其他任何内容(`OutputSchemaError`,列出所有违规)。两个遍历器都只处理自有可枚举属性(JSON 不携带其他东西),并拒绝会有损序列化的非普通对象(`Date`、`Map`)。 +调用方用来向 subagent 要求机器可读结果的词汇(`SubagentStartRequest.outputSchema`,见 [subagent.md](subagent.md#the-start-request)),或工作流 `agent()` 调用使用的词汇。它有意**不是**完整的 JSON Schema:schema 原样传给模型作为强制工具的 `parameters`,产出的值由 `validateStructuredValue` 在客户端校验——因此每个被接受的关键字都必须是校验器实际执行的,`assertSupportedOutputSchema` 会大声拒绝其他任何内容(`OutputSchemaError`,列出所有违规项)。两个遍历器仅推理自有可枚举属性(JSON 不携带其他内容),并拒绝会有损序列化的非纯对象(`Date`、`Map`)。 ```ts type-equiv type StructuredScalar = string | number | boolean | null @@ -219,7 +219,7 @@ interface StructuredSchemaNode { } ``` -schema 是一个以 object 为根的节点(`enum`/`const` 仅限标量;`description`/`title`/`default`/`examples` 是注解,允许但忽略,仍要求为 JSON 数据——它们随协议传输): +schema 是一个以 object 为根的节点(`enum`/`const` 仅限标量;`description`/`title`/`default`/`examples` 是注解,允许但忽略,但仍要求为 JSON 数据——它们随协议传输): ```ts type-equiv type StructuredOutputSchema = StructuredSchemaNode & { type: 'object' } @@ -227,11 +227,11 @@ type StructuredOutputSchema = StructuredSchemaNode & { type: 'object' } ## 工具展示 UI 词汇 -工具希望其调用在 UI 中如何呈现(编辑器工具调用卡片、CLI 日志行),提供方无关,使工具无需依赖任何客户端协议即可描述自身。`presentCall`/`presentResult` 返回一个 **`card` 标签的渲染意图**——一个可辨识联合类型,UI 桥接层据此分发: +工具希望其调用在 UI 中如何呈现(编辑器工具调用卡片、CLI 日志行),提供方无关,使工具在不依赖任何客户端协议的情况下描述自身。`presentCall`/`presentResult` 返回一个 **`card` 标签的渲染意图**——一个可辨识联合类型,UI 桥接层据此分发: -- `ToolCallView`(pending 状态):`{ card: 'generic', title, kind?, rawInput?, content?, locations? }`(默认卡片;`locations` 是 `{ path, line? }[]`,表示该调用读取/修改的文件,供编辑器跟随定位)、`{ card: 'terminal', title, description?, cwd? }`(shell 命令 → 终端卡片)、或 `{ card: 'diff', title, diffs, locations? }`(文件创建/修改 → 内联 diff 卡片;`diffs` 是 `{ path, oldText, newText }[]`,`oldText: null` 表示新文件)。 -- `ToolResultView`(completed 状态):`{ card: 'generic', title?, content? }`、`{ card: 'terminal', title?, output?, exitCode?, signal? }`(捕获的运行输出 + 退出状态;有能力的 UI 显示退出状态标签,无能力的 UI 获得桥接层从 `output` 派生的围栏 ` ```console ` 回退)、或 `{ card: 'diff', title?, diffs }`(已完成的文件变更 → 要展示的变更,通常是从 before/after 内容计算出带上下文行的已应用 hunk,或在没有 before-image 时的整文件 diff——如文件创建。`tool_call_update` 的 content 会**替换**调用的 content,因此变更工具即使与调用时的片段重复也要返回此值,以防结果文本覆盖 diff)。 +- `ToolCallView`(待执行):`{ card: 'generic', title, kind?, rawInput?, content?, locations? }`(默认卡片;`locations` 是 `{ path, line? }[]`,表示调用读取/修改的文件,供编辑器跟随)、`{ card: 'terminal', title, description?, cwd? }`(shell 命令→终端卡片)、或 `{ card: 'diff', title, diffs, locations? }`(文件创建/修改→行内 diff 卡片;`diffs` 是 `{ path, oldText, newText }[]`,新文件时 `oldText: null`)。 +- `ToolResultView`(已完成):`{ card: 'generic', title?, content? }`、`{ card: 'terminal', title?, output?, exitCode?, signal? }`(捕获的运行输出 + 退出状态;有能力的 UI 显示退出状态标签,无能力的 UI 获得桥接层从 `output` 派生的围栏 ` ```console ` 回退)、或 `{ card: 'diff', title?, diffs }`(已完成的文件变更→要展示的变更,通常是从变更前后内容计算出带上下文行的已应用 hunk,或在没有前像时的整文件 diff——例如文件创建。`tool_call_update` 的内容会**替换**调用的内容,因此变更工具即使与调用时的片段重复也要返回此卡片,以防结果文本覆盖 diff)。 -`ToolCallKind`(`'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other'`)为 generic 卡片选择图标。`FileLocation`(`{ path, line? }`)和 `FileDiff`(`{ path, oldText, newText }`)是共享的文件卡片词汇。该设计固定于[渲染意图联合类型 RFC](../rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md);ACP(Agent Client Protocol)桥接层将 `diff` 卡片映射为 `{ type: 'diff' }` 内容块,将 `terminal` 卡片映射为 `_meta` 终端约定,并将文件卡片的标题相对于会话 cwd 做相对化处理。 +`ToolCallKind`(`'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other'`)为 generic 卡片选择图标。`FileLocation`(`{ path, line? }`)和 `FileDiff`(`{ path, oldText, newText }`)是共享的文件卡片词汇。该设计固定在[渲染意图联合类型 RFC](../rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md) 中;ACP 桥接层将 `diff` 卡片映射为 `{ type: 'diff' }` 内容块,将 `terminal` 卡片映射为 `_meta` 终端约定,并将文件卡片的标题相对于会话 cwd 做相对化处理。 完整的展示字段文档见 [`packages/core/tools/src/presentation.ts`](../../packages/core/tools/src/presentation.ts)。bash 工具自身的 schema(`bash`/`bash_output`/`bash_kill`)及其驱动的执行器见 [bash.md](bash.md)。 diff --git a/docs/core-data-structures/user-interaction.i18n.yaml b/docs/core-data-structures/user-interaction.i18n.yaml index f80530393b..d0c0b33ce5 100644 --- a/docs/core-data-structures/user-interaction.i18n.yaml +++ b/docs/core-data-structures/user-interaction.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write user-interaction.md: 47e0e26cd0a5201185dd252a882496456a9c3edd -user-interaction.zh.md: bddcc991fd48d475f06912b9134b331d623b80d2 +user-interaction.zh.md: e7d2f27b8729a7694008d1ae7e21bdccae6058dd diff --git a/docs/core-data-structures/user-interaction.zh.md b/docs/core-data-structures/user-interaction.zh.md index bddcc991fd..e7d2f27b87 100644 --- a/docs/core-data-structures/user-interaction.zh.md +++ b/docs/core-data-structures/user-interaction.zh.md @@ -2,13 +2,13 @@ [English](user-interaction.md) | 中文 -[dsh-user-interaction](../../packages/ui/user-interaction) 的用户交互 seam。它是工具或权限插件在需要人类回答后 agent 才能继续时所使用的提供方无关词汇。UI 表面提供活跃的 `UserInteractionProvider`:`dsh-stdio-demo` 在 readline 中渲染问题,`dsh-acp` 将其映射为 ACP 表单引出。 +[dsh-user-interaction](../../packages/ui/user-interaction) 的用户交互 seam。它是提供方无关的词汇,工具或权限插件在需要人类回答后 agent(智能体)才能继续时使用这套词汇。UI 表面提供活跃的 `UserInteractionProvider`:`dsh-stdio-demo` 在 readline 中渲染问题,`dsh-acp` 将其映射为 ACP(Agent Client Protocol)表单征询。 源码:[`packages/ui/user-interaction/src/index.ts`](../../packages/ui/user-interaction/src/index.ts) ## 问题选项 -`AskUserQuestionOption` 是可选择项的形状。`label` 是面向用户的选项文字,同时也是模型侧选中后的值;`description` 是可选的 UI 辅助文字。 +`AskUserQuestionOption` 是可选择项的形状。`label` 是面向用户的选项文字,同时也是面向模型的选中值;`description` 是可选的 UI 帮助文本。 ```ts type-equiv interface AskUserQuestionOption { @@ -40,7 +40,7 @@ interface AskUserQuestionItem { ## 提问请求 -`AskUserQuestionRequest` 是跨包请求。`questions` 是数组,这样 UI 可以在一次流程中展示相关问题,同时为每个回答保留稳定的 id。 +`AskUserQuestionRequest` 是跨包(package)的请求。`questions` 是数组,这样 UI 可以在一个流程中呈现相关提示,同时保持每个回答有稳定的 id。 ```ts type-equiv interface AskUserQuestionRequest { @@ -55,7 +55,7 @@ interface AskUserQuestionRequest { ## 回答 -提供方为每个已回答的问题 id 返回一条回答。`selected` 包含选中的选项 label,`custom` 在用户输入了自由文本"其他"答案时携带该内容。当 `custom` 存在时,`selected` 为空;自定义文本是对选中项的覆盖,而非补充。 +提供方为每个已回答的问题 id 返回一条回答。`selected` 包含选中的选项标签,`custom` 在用户输入自由文本时携带「其他」回答。当 `custom` 存在时,`selected` 为空;自定义文本是对选中项的覆盖,而非补充。 ```ts type-equiv interface AskUserQuestionAnswerItem { @@ -77,7 +77,7 @@ interface AskUserQuestionAnswer { ## 提供方 -同一上下文中只能有一个活跃的提供方。提供方注册与 effect 绑定,因此 HMR(热模块替换)或 dispose(资源释放)会移除活跃的 UI。 +同一上下文中只能有一个活跃的提供方。提供方注册绑定到 effect,因此 HMR(热模块替换)或 dispose(资源释放)会移除当前活跃的 UI。 ```ts type-equiv interface UserInteractionProvider { @@ -87,7 +87,7 @@ interface UserInteractionProvider { ## 错误 -`UserInteractionError` 继承 `HarnessError`,因此 `ctx.tools.execute()` 会为面向模型的工具失败保留 `{ name, code }`,例如 `EMPTY_QUESTIONS`、`NO_PROVIDER`、`ASK_ABORTED` 或 ACP 侧的取消。 +`UserInteractionError` 继承 `HarnessError`,因此 `ctx.tools.execute()` 会保留 `{ name, code }`,用于面向模型的工具失败,如 `EMPTY_QUESTIONS`、`NO_PROVIDER`、`ASK_ABORTED` 或 ACP 侧取消。 ```ts type-equiv class UserInteractionError extends HarnessError { diff --git a/docs/core-data-structures/web.i18n.yaml b/docs/core-data-structures/web.i18n.yaml index b5b4fd1f29..7c248359a9 100644 --- a/docs/core-data-structures/web.i18n.yaml +++ b/docs/core-data-structures/web.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write web.md: 74db18835df02ef233f78ad7fbfec5d9b26d58e6 -web.zh.md: da8dad9dc06309b6f3108148dc39bc2b66bb5d22 +web.zh.md: 7b94aa457985075c79052aeef66b2e46eac5b49d diff --git a/docs/core-data-structures/web.zh.md b/docs/core-data-structures/web.zh.md index da8dad9dc0..7b94aa4579 100644 --- a/docs/core-data-structures/web.zh.md +++ b/docs/core-data-structures/web.zh.md @@ -2,17 +2,17 @@ [English](web.md) | 中文 -Web 访问 seam 是一个[能力 seam](../rfc/implemented/architecture/2026-06-24-web-capability-seam.md),在单一 `ctx.web` 服务上横跨**两种能力**(搜索与抓取),拆分到多个包(package)中:接口([dsh-web](../../packages/web/web),`ctx.web` + 提供方注册表)、实现([dsh-web-search-exa](../../packages/web/web-search-exa)、[dsh-web-search-perplexity](../../packages/web/web-search-perplexity)、[dsh-web-search-deepseek](../../packages/web/web-search-deepseek)、[dsh-web-fetch-local](../../packages/web/web-fetch-local)),以及消费方([dsh-tool-web](../../packages/web/tool-web),`web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop 主干,因此其词汇定义在此,而非 [core.md](core.md)。更换搜索提供方不会改变模型发起查询的方式,更换抓取实现也不会改变模型请求 URL 的方式。 +Web 访问 seam 是一个[能力 seam](../rfc/implemented/architecture/2026-06-24-web-capability-seam.md),在一个 `ctx.web` 服务上横跨**两项能力**(搜索与抓取),分布在多个包(package)中:接口([dsh-web](../../packages/web/web),`ctx.web` + 提供方注册表)、实现([dsh-web-search-exa](../../packages/web/web-search-exa)、[dsh-web-search-perplexity](../../packages/web/web-search-perplexity)、[dsh-web-search-deepseek](../../packages/web/web-search-deepseek)、[dsh-web-fetch-local](../../packages/web/web-fetch-local)),以及消费方([dsh-tool-web](../../packages/web/tool-web),`web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此,而非 [core.md](core.md)。更换搜索提供方不会改变模型发起查询的方式,更换抓取实现也不会改变模型请求 URL 的方式。 源码:[`packages/web/web/src/types.ts`](../../packages/web/web/src/types.ts) -## 为何两种能力共用一个 seam +## 为什么两项能力合为一个 seam -搜索与抓取既不共享请求 schema,也不共享业务逻辑,但它们被有意设计为同一个 `ctx.web` 中间层:一个提供方选择策略的归属者、一套 abort/error 词汇、一个面向产品的「此 harness 如何访问 Web」配置界面。代价是服务上出现了并行的 `searchX`/`fetchX` 方法对;这种并行是有意为之,而非遗漏的提取。提供方注册的是**能力**(`WebSearchProvider` 或 `WebFetchProvider`),而非工具;面向模型的名称、schema、prompt 引导与展示全部集中在唯一的消费方 `dsh-tool-web` 中。 +搜索与抓取既不共享请求 schema,也不共享业务逻辑,但它们被有意设计为同一个 `ctx.web` 中间层:一个提供方选择策略的所有者、一套 abort/error 词汇、一个面向产品的「此 harness 如何访问 Web」配置界面。代价是服务上并行的 `searchX`/`fetchX` 方法对;这种并行是有意为之,而非遗漏的提取。提供方注册的是**能力**(`WebSearchProvider` 或 `WebFetchProvider`),而非工具;面向模型的名称、schema、prompt 引导与展示全部集中在唯一的消费方 `dsh-tool-web` 中。 ## 搜索请求与结果 -面向模型的工具参数仅为一个 `query`;`maxResults` 是消费方持有的上限(`dsh-tool-web` 的 `searchMaxResults` 配置,默认 `8`),通过 seam 传递并在返回时强制执行:如果提供方返回的结果超量,seam 会截断 `sources[]` 并设置 `truncated`。 +面向模型的工具参数仅为一个 `query`;`maxResults` 是消费方自有的上限(`dsh-tool-web` 的 `searchMaxResults` 配置,默认 `8`),通过 seam 传递并在返回时强制执行——如果提供方返回超量,seam 截断 `sources[]` 并设置 `truncated`。 ```ts type-equiv interface WebSearchRequest { @@ -33,7 +33,7 @@ interface WebSearchResult { } ``` -`content` 是提供方可选生成的回答文本(Exa 和 DeepSeek 不返回;Perplexity 返回生成式回答)。`sources[]` 是可移植的引用界面。每条 source 必有 `url`;`title`/`snippet`/`publishedAt` 可选,因为并非所有提供方都返回它们:Perplexity 的引用可能只有 URL,强迫适配器编造其余字段会让 seam 说谎。`dsh-tool-web` 渲染时使用 `title ?? hostname(url)`。 +`content` 是提供方可选生成的回答文本(Exa 和 DeepSeek 不返回;Perplexity 返回生成式回答)。`sources[]` 是可移植的引用表面。一个 source 必有 `url`;`title`/`snippet`/`publishedAt` 可选,因为并非每个提供方都返回它们——Perplexity 的引用可能只有 URL,强迫适配器编造其余字段会让 seam 说谎。`dsh-tool-web` 渲染时使用 `title ?? hostname(url)`。 ```ts type-equiv interface WebSearchSource { @@ -52,7 +52,7 @@ interface WebFetchRequest { } ``` -HTTP 状态码是被抓取资源状态的一部分,不自动视为失败:成功的网络抓取返回 `404`/`500` 时,结果仍是一个带状态码和有界解码 body 的 `WebFetchResult`。`url` 是经过允许的重定向后的最终 URL。`WebError` 保留给无法安全获取或表示资源的失败情形。 +HTTP 状态码是被抓取资源状态的一部分,不自动视为失败:成功的网络抓取返回 `404`/`500` 时,仍产出一个带状态码和有界解码 body 的 `WebFetchResult`。`url` 是经过允许的重定向后的最终 URL。`WebError` 仅用于无法安全获取或表示资源的情况。 ```ts type-equiv interface WebFetchResult { @@ -63,7 +63,7 @@ interface WebFetchResult { } ``` -`WebFetchBody` 是 `dsh-web` 持有的**封闭**可辨识联合类型(不是可合并扩展的 map):提供方解码 kind,`dsh-tool-web` 渲染它,因此新增一个 kind 是跨已知包的协调变更,而非插件扩展。消费方对 `kind` 做 `switch` 并以 `default: assertNever(...)` 结尾,因此新增 kind 会在每个消费方处破坏编译直到被处理。即使当前各分支字段相同,每个分支仍保持独立的对象字面量,为将来的分支特有字段留出空间(例如未来 `pdf` body 的 `pageCount`)。 +`WebFetchBody` 是 `dsh-web` 拥有的**封闭**可辨识联合类型(不是可合并扩展的 map):提供方解码 kind,`dsh-tool-web` 渲染它,因此新增一个 kind 是已知包之间的协调变更,而非插件扩展。消费方对 `kind` 做 `switch` 并以 `default: assertNever(...)` 结尾,所以新增 kind 会在每个消费方处编译失败,直到被处理。即使各分支当前字段一致,每个分支仍保持独立的对象字面量,为将来分支特有字段留出空间(例如未来 `pdf` body 的 `pageCount`)。 ```ts type-equiv type WebFetchBody = @@ -73,14 +73,14 @@ type WebFetchBody = ## 提供方可用性 -提供方的 `available(): boolean` 是一个廉价的**本地**检查(凭证是否存在、配置是否可解析),**禁止发起网络调用**。它是执行时选择的输入,而非健康检查系统:`search()`/`fetch()` 读取它来选出可用的提供方,选择失败以结构化的 `WebError` 呈现给调用方路由,其 code 和 message 携带可分支的细节(缺失的 id 或歧义的候选集)。 +提供方的 `available(): boolean` 是一个廉价的**本地**检查(凭证是否存在、配置是否可解析),**禁止发起网络调用**。它是执行时选择的输入,而非健康检查系统:`search()`/`fetch()` 读取它以选出可用的提供方,选择失败以结构化的 `WebError` 呈现给调用方路由——其 code 和 message 携带可分支的细节(缺失的 id 或有歧义的候选集)。 -选择从不依赖注册顺序、配置顺序或 HMR 顺序:一项能力要么有显式的提供方 id(配置 `searchProvider`/`fetchProvider`,或喂入同一字段的对应环境变量),要么在恰好只有一个可用提供方注册时自动选择;多个可用提供方且未配置 id 时为 `WEB_PROVIDER_AMBIGUOUS`,而非先注册先赢。 +选择从不依赖注册顺序、配置顺序或 HMR(热模块替换)顺序:一项能力要么有显式的提供方 id(配置 `searchProvider`/`fetchProvider`,或填充同一字段的对应环境变量),要么在恰好只有一个可用提供方注册时自动选择;多个可用提供方且未配置 id 时为 `WEB_PROVIDER_AMBIGUOUS`,而非先注册先赢。 ## 错误 -`WebError extends HarnessError`([core.md](core.md) 错误分类体系),带有 `code: string`(开放式,与其他 seam 的错误一致:`LlmError`、`SubagentError`),而非封闭联合类型:提供方可以在不修改 `dsh-web` 的情况下抛出自己的 code,消费方必须容忍未知 code。code 按归属者划分。seam 中性的 code 由 `WebService` 选择逻辑和共享契约抛出:`WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE`、`WEB_PROVIDER_AMBIGUOUS`、`WEB_DUPLICATE_PROVIDER`(注册时的编程错误,类似 `LlmService` 的 `DUPLICATE_ADAPTER`)、`WEB_ABORTED`,以及 `WEB_PROVIDER_ERROR`(提供方自身失败通过 seam 暴露的兜底 code,包括网络/传输失败:DNS、连接被拒、TLS)。抓取传输层 code 由 `dsh-web-fetch-local` 实现持有,不同的抓取后端不必抛出它们:`WEB_INVALID_URL`、`WEB_BLOCKED_URL`、`WEB_REDIRECT_BLOCKED`、`WEB_FETCH_TOO_LARGE`、`WEB_FETCH_TIMEOUT`、`WEB_UNSUPPORTED_CONTENT_TYPE`。 +`WebError extends HarnessError`([core.md](core.md) 错误分类体系),带有 `code: string`(开放式,与其他 seam 的错误一致——`LlmError`、`SubagentError`),而非封闭联合类型:提供方可以在不修改 `dsh-web` 的情况下抛出自己的 code,消费方必须容忍未知 code。code 按所有者划分。seam 中立的 code 由 `WebService` 选择逻辑和共享契约抛出:`WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE`、`WEB_PROVIDER_AMBIGUOUS`、`WEB_DUPLICATE_PROVIDER`(注册时的编程错误,类似 `LlmService` 的 `DUPLICATE_ADAPTER`)、`WEB_ABORTED`,以及 `WEB_PROVIDER_ERROR`(提供方自身故障通过 seam 暴露的兜底 code,包括网络/传输失败——DNS、连接被拒、TLS)。抓取传输层 code 由 `dsh-web-fetch-local` 实现拥有,不同的抓取后端无需抛出它们:`WEB_INVALID_URL`、`WEB_BLOCKED_URL`、`WEB_REDIRECT_BLOCKED`、`WEB_FETCH_TOO_LARGE`、`WEB_FETCH_TIMEOUT`、`WEB_UNSUPPORTED_CONTENT_TYPE`。 ## 服务 -`WebService` 注册搜索与抓取提供方,以 `WEB_DUPLICATE_PROVIDER` 拒绝重复 id,并在执行时以结构化的选择错误解析提供方。本地抓取后端仅接受 HTTP(S)、拒绝凭证、限制重定向次数、字节数、字符数与时间、对每一跳同源重定向重新校验,并解码 body;展示由工具负责。私有网络阻断尚未实现,因此不要在能触及敏感内部目标的环境中启用 `web_fetch`。 +`WebService` 注册搜索与抓取提供方,以 `WEB_DUPLICATE_PROVIDER` 拒绝重复 id,并在执行时以结构化的选择错误解析提供方。本地抓取后端仅接受 HTTP(S)、拒绝凭证、限制重定向次数、字节数、字符数和时间、对每一跳同源重定向重新校验,并解码 body;展示由工具负责。私有网络阻断尚未实现,因此请勿在可触及敏感内部目标的环境中启用 `web_fetch`。 diff --git a/docs/core-data-structures/workflow.i18n.yaml b/docs/core-data-structures/workflow.i18n.yaml index b7e831aac8..c06899bc74 100644 --- a/docs/core-data-structures/workflow.i18n.yaml +++ b/docs/core-data-structures/workflow.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write workflow.md: 1571723c172fe851e89550e4ed8588ddb14088a0 -workflow.zh.md: 9fa3b4eea4efdcdb8e594c3558e30846aea0af46 +workflow.zh.md: 68a5ff9b6ddf43145966e60706a42a758ea260ba diff --git a/docs/core-data-structures/workflow.zh.md b/docs/core-data-structures/workflow.zh.md index 9fa3b4eea4..68a5ff9b6d 100644 --- a/docs/core-data-structures/workflow.zh.md +++ b/docs/core-data-structures/workflow.zh.md @@ -2,15 +2,15 @@ [English](workflow.md) | 中文 -工作流 seam:由 agent(智能体)运行一段模型编写的编排脚本(SCRIPT),向外扇出 subagent。与 [subagent](subagent.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。与 subagent 注册表不同,它采用 bash 形态:每个上下文只有一个引擎实现提供 `ctx.workflows`;没有命名提供方注册表(第二个引擎是插件替换,而非共存)。 +工作流 seam:一个 agent(智能体)运行由模型编写的编排脚本(SCRIPT),扇出 subagent。与 [subagent](subagent.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此处而非 [core.md](core.md)。与 subagent 注册表不同,它采用 bash 形态:每个上下文只有一个引擎实现提供 `ctx.workflows`;没有命名提供方注册表(第二个引擎是插件替换,而非共存)。 -接口:[dsh-workflow](../../packages/workflow/workflow)(`ctx.workflows` + 下文词汇)。实现为 [dsh-workflow-workerthread](../../packages/workflow/workflow-workerthread)(基于 `node:worker_threads` 的引擎:每次运行一个 worker,脚本的 vm 上下文在其中执行);面向模型的消费方是 [dsh-tool-workflow](../../packages/workflow/tool-workflow)。提案与设计理由见[动态工作流 RFC](../rfc/implemented/feature/2026-07-05-dynamic-workflows.md)。 +接口:[dsh-workflow](../../packages/workflow/workflow)(`ctx.workflows` + 下文词汇)。实现是 [dsh-workflow-workerthread](../../packages/workflow/workflow-workerthread)(一个 `node:worker_threads` 引擎:每次运行一个 worker,脚本的 vm 上下文在其中执行);面向模型的消费方是 [dsh-tool-workflow](../../packages/workflow/tool-workflow)。提案与设计动机见[动态工作流 RFC](../rfc/implemented/feature/2026-07-05-dynamic-workflows.md)。 源码:[`packages/workflow/workflow/src/types.ts`](../../packages/workflow/workflow/src/types.ts) ## 启动请求 -调用方启动一次运行时发出的请求。工具层根据模型的 `{ script, meta, args }` 调用加上发起调用的 agent 构建此请求;`meta` 和 `args` 是纯 JSON 数据(引擎在任何代码运行之前对 `meta` 做形状校验,不通过则大声拒绝——永远不会为了获取 meta 而执行脚本文本)。`parent` 是必需的:脚本 spawn 的每个子 agent 都归属于它(cwd、血统和深度通过 [subagent seam](subagent.md) 流转)。 +调用方启动一次运行时提交的内容。工具层从模型的 `{ script, meta, args }` 调用加上发起调用的 agent 构建此请求;`meta` 和 `args` 是纯 JSON 数据(引擎在任何代码执行之前对 `meta` 做形状校验,不通过则立即报错:永远不会为了获取 meta 而执行脚本文本)。`parent` 是必填项:脚本 spawn 的每个子 agent 都归属于它(cwd、血统与深度通过 [subagent seam](subagent.md) 传递)。 ```ts type-equiv interface WorkflowStartRequest { @@ -24,7 +24,7 @@ interface WorkflowStartRequest { ## 工作流的身份标识:`WorkflowMeta` -作为数据附在启动请求上的身份块(工具的 `meta` 参数;字段词汇与 Claude Code 动态工作流的 meta 块一致)。`phases` 仅为进度词汇:`phase()` 调用与标题匹配供观察者使用;不暗示任何执行结构。 +作为数据附在启动请求上的身份块(工具的 `meta` 参数;字段词汇与 Claude Code 动态工作流的 meta 块一致)。`phases` 仅用于进度展示:`phase()` 调用与标题匹配,供观察者使用;不暗示任何执行结构。 ```ts type-equiv interface WorkflowMeta { @@ -37,7 +37,7 @@ interface WorkflowMeta { ## 终态结果:`WorkflowResult` -一次运行的结果,由 `WorkflowRun.result` resolve。`value` 是脚本的物化返回值——纯宿主域 JSON 数据(脚本无返回值时为 `null`)——仅在 `completed` 时有意义。`stopReason` 是一个封闭联合类型(引擎拥有;消费方可穷举):`completed` | `cancelled` | `error`。非 `completed` 的原因在 `error` 中携带失败信息,消费方将其映射为 `isError` 工具结果,而非把部分输出当作成功上报。 +一次运行的结果,由 `WorkflowRun.result` resolve。`value` 是脚本的物化返回值——纯宿主域 JSON 数据(脚本无返回值时为 `null`)——仅在 `completed` 时有意义。`stopReason` 是封闭联合类型(引擎所有;消费方可穷举):`completed` | `cancelled` | `error`。非 `completed` 的原因在 `error` 中携带失败信息,消费方将其映射为 `isError` 工具结果,而非把部分输出当作成功上报。 ```ts type-equiv interface WorkflowResult { @@ -50,7 +50,7 @@ interface WorkflowResult { ## 活跃运行:`WorkflowRun` -脚本执行期间消费方持有的句柄。消费方 await `result`,可在运行中途 `cancel`,且必须在每条路径上调用 `dispose`。`result` 不会 reject:脚本失败以 `stopReason: 'error'` resolve;一旦运行被取消,即使脚本本身永不 settle,它也会在引擎的有界宽限期内 settle(引擎强制以 `cancelled` settle;worker-thread 引擎随后终止脚本的 worker),因此消费方 await `result` 不会在取消后永远卡住。`dispose()` = cancel + 有界 settle + 子 agent 静默;它不会因脚本卡死而挂起。 +脚本执行期间消费方持有的句柄。消费方 await `result`,可中途 `cancel`,且*必须*在每条路径上 `dispose`。`result` 不会 reject:脚本失败以 `stopReason: 'error'` resolve;一旦运行被取消,即使脚本本身永不 settle,它也会在引擎的有界宽限期内 settle(引擎强制以 `cancelled` settle;worker-thread 引擎随后终止脚本的 worker),因此消费方 await `result` 不会在取消后卡死。`dispose()` = cancel + 有界 settle + 子 agent 静默;它不会因脚本卡死而挂起。 ```ts type-equiv interface WorkflowRun { @@ -64,8 +64,8 @@ interface WorkflowRun { ## 失败纪律:`WorkflowError.fatal` -脚本内部的钩子误用——错误参数、未知或延迟的 `agent()` 选项、超出[结构化输出子集](../../packages/core/tools/README.md)的 schema、触发的上限、seam 启动失败、取消——会抛出 `fatal: true` 的 `WorkflowError`。`parallel()`/`pipeline()` 组合器对 fatal 错误执行重新抛出,而非将该项映射为 `null`:一个拼写错误的选项必须大声杀死脚本,绝不能消融为看似普通子 agent 失败的东西。逐项的 `null` 保留给子运行失败(非 `completed` 的 stop reason)和阶段内的普通脚本错误。 +脚本内部的钩子误用:错误参数、未知或延迟的 `agent()` 选项、超出[结构化输出子集](../../packages/core/tools/README.md)的 schema、触发的上限、seam 启动失败、取消,都会抛出 `fatal: true` 的 `WorkflowError`。`parallel()`/`pipeline()` 组合器对 fatal 错误直接重新抛出,而非将该项映射为 `null`:一个拼写错误的选项必须让脚本大声失败,绝不能消融为看似普通子 agent 失败的结果。逐项的 `null` 保留给子运行失败(非 `completed` 的 stop reason)和阶段内的普通脚本错误。 ## 事件 -`workflow/*` 事件(`workflow/start`、`workflow/phase`、`workflow/log`、`workflow/agent-start`、`workflow/agent-end`、`workflow/end`——见[事件目录](../cordis-catalog/events.md))是**仅供观察**的 emit,携带数据快照:每个 payload 以 `WorkflowRunInfo`(id + meta)开头,从不暴露活跃的 `WorkflowRun`,因此订阅者无法获得 `cancel`/`dispose`;`workflow/end` 刻意省略 result value(观察结果的监听器不得收到调用方 result 的可变别名)。每次 emit 对每个监听器隔离:抛异常的订阅者被记录但不传播,不会饿死其后注册的监听器;每个监听器收到自己的 payload 克隆,因此修改它既不会损坏引擎也不会影响其他监听器。这种隔离与 `subagent/start`/`subagent/end` 一致。 +`workflow/*` 事件(`workflow/start`、`workflow/phase`、`workflow/log`、`workflow/agent-start`、`workflow/agent-end`、`workflow/end`,见[事件目录](../cordis-catalog/events.md))是**仅供观察**的 emit,携带数据快照:每个 payload 以 `WorkflowRunInfo`(id + meta)开头,而非活跃的 `WorkflowRun`,因此订阅者无法获得 `cancel`/`dispose`;`workflow/end` 刻意省略 result value(观察结果的监听器不得收到调用方 result 的可变别名)。每次 emit 对每个监听器隔离:抛出异常的订阅者被记录日志但不传播,不会饿死在它之后注册的监听器;每个监听器收到自己的 payload 克隆,因此修改它既不会损坏引擎也不会影响其他监听器。这种隔离方式与 `subagent/start`/`subagent/end` 一致。 diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml b/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml index 9e6c34072b..f36c38cf0a 100644 --- a/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml +++ b/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 0001-acp-default-export-drops-inject.md: 6a71d8d7ef72e3110a99774b180f3de7115ef622 -0001-acp-default-export-drops-inject.zh.md: 12bb3501a56c3cfef8f7a1b0d773be62db8e09ca +0001-acp-default-export-drops-inject.zh.md: 1d97f1140a9595ac7e304b5a1600c3cbc47292f1 diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.zh.md b/docs/postmortem/0001-acp-default-export-drops-inject.zh.md index 12bb3501a5..1d97f1140a 100644 --- a/docs/postmortem/0001-acp-default-export-drops-inject.zh.md +++ b/docs/postmortem/0001-acp-default-export-drops-inject.zh.md @@ -6,23 +6,23 @@ Status: resolved (fix in PR #41 `feat/acp-2-bridge`) ## 摘要 -两个集成错误在单元测试全绿的情况下击溃了 ACP:一个 default export 导致 Loader 丢弃 `inject`,一个经过 traceable 代理的可选服务查找在 shadow 边界上失败。手动挂载的测试绕过了这两条路径。修复后新增了无需 API key 的真实 Loader 覆盖,以及关于插件导出和可选服务访问的包(package)规则。 +两个集成错误在单元测试全覆盖的情况下仍然导致 ACP(Agent Client Protocol)崩溃:一个 default export 使 Loader 丢弃了 `inject`,一个经 traceable 代理的可选服务查找在 shadow 边界上失败。手动挂载的测试绕过了这两条路径。修复方案增加了无需 API key 的真实 Loader 覆盖率,并为插件导出和可选服务访问制定了包(package)级规则。 ## 概述 -ACP 服务器(`examples/acp-agent`、`@deepseek-ai/dsh-acp`)在真实编辑器(Zed)连接的瞬间崩溃:第一个 `session/new` 请求返回 `Internal error: cannot get property "agents" without inject`,`session/load` 对 `sessionPersistence` 返回相同错误。尽管有 178 个绿色单元测试和 100% 行覆盖率,bridge 在生产环境中完全无法工作。两个独立的 bug 隐藏在同一个错误字符串背后,测试套件因同一个原因漏掉了二者:每个测试都通过一条不会触及插件实际加载方式或服务实际解析方式的路径来挂载插件。 +ACP 服务器(`examples/acp-agent`、`@deepseek-ai/dsh-acp`)在真实编辑器(Zed)连接的瞬间崩溃:第一个 `session/new` 请求返回 `Internal error: cannot get property "agents" without inject`,`session/load` 对 `sessionPersistence` 返回同样的错误。尽管有 178 个绿色单元测试和 100% 行覆盖率,bridge 在生产环境中完全无法工作。两个独立的 bug 隐藏在同一个错误字符串背后,测试套件之所以两个都没捕获,原因也相同:所有测试都通过一条不会触及插件真实加载方式和服务真实解析方式的路径来挂载插件。 ## 影响 -ACP 服务器无法创建或加载任何一个会话——这正是编辑器最先调用的两个 RPC。任何将 agent 接入 Zed 的人都会立即遇到硬性失败。无数据丢失(崩溃前没有持久化任何内容);代价完全是「功能不可用」加上两次定位原因的调试时间。 +ACP 服务器无法创建或加载任何一个会话——而这正是编辑器最先调用的两个 RPC。任何将 agent(智能体)接入 Zed 的人都会立即遭遇硬性失败。无数据丢失(崩溃前没有任何内容被持久化);代价完全是「功能不可用」加上两次定位原因的调试时间。 ## 时间线 -- Bridge(RFC 010)带着完整的单元测试套件(编解码、内存传输、基于属性的协议形状测试、失败路径、HMR(热模块替换))、一个需要 key 的真实 API e2e 测试,以及一个无需 key 的 stdout 纯净性 e2e 测试一起落地。全部绿色,100% 覆盖率。 -- 一次真实的 Zed 会话立即在 `session/new` 上失败,报错 `cannot get property "agents" without inject`。 -- 调查最初追踪的是 Cordis「traceable/shadow」理论(合理,且机制确实存在——见 Bug #2),随后在 vendor 的 `reflect.ts` 中对实际 fiber 遍历做了插桩,并运行了真实子进程。trace 显示 throw 发生在 `apply()` 第 179 行、**插件加载时**,位于 ROOT fiber 且没有 shadow——推翻了 shadow 理论对 `session/new` 的解释。 -- 找到根因 #1:一行多余的 `export default apply`。移除后 `session/new` 修复。 -- 移除后暴露了 Bug #2:`session/load` 仍然在 `sessionPersistence` 上抛出——这是一个真正不同的机制(shadow 遍历),通过隔离修复并重新运行真实子进程得到确认。 +- bridge(RFC 010)落地时附带完整的单元测试套件(codec、内存传输、基于属性的协议形状测试、失败路径、HMR(热模块替换))、一个需要 key 的真实 API e2e 测试,以及一个无需 key 的 stdout 纯净性 e2e 测试。全部绿色,100% 覆盖率。 +- 真实 Zed 会话在 `session/new` 上立即失败,报错 `cannot get property "agents" without inject`。 +- 调查最初追踪了一个 Cordis「traceable/shadow」理论(看似合理,且该机制确实存在——见 Bug #2),随后在 vendor 的 `reflect.ts` 中对实际 fiber 遍历做了插桩,并运行了真实子进程。trace 显示 throw 发生在 `apply()` 第 179 行、**插件加载时**,位于 ROOT fiber 且没有 shadow——推翻了 shadow 理论对 `session/new` 的解释。 +- 找到根因 #1:一行多余的 `export default apply`。删除后 `session/new` 修复。 +- 删除后暴露了 Bug #2:`session/load` 仍然在 `sessionPersistence` 上抛错——这是一个真正不同的机制(shadow 遍历),通过隔离修复并重新运行真实子进程得到确认。 ## 根因 #1——`export default apply` 丢弃了插件的 `inject`(导致 `session/new` 崩溃) @@ -36,7 +36,7 @@ export function apply(ctx: Context, config: AcpConfig): void { /* … */ } export default apply // ← the bug ``` -当插件从 `cordis.yml` 加载时,Cordis Loader 通过 `Loader.unwrapExports`(`vendor/loader/src/index.ts`)对导入的模块做规范化处理: +当插件从 `cordis.yml` 加载时,Cordis Loader 通过 `Loader.unwrapExports`(`vendor/loader/src/index.ts`)对导入的模块进行规范化: ```ts ignore-check unwrapExports(exports: any) { @@ -47,19 +47,19 @@ unwrapExports(exports: any) { } ``` -存在 default export 时,`exports.default ?? exports` 解析为**裸 `apply` 函数**。裸函数没有 `inject`、没有 `name`、没有 `Config` 属性——这些作为*兄弟*命名导出存在于模块命名空间上,而 unwrap 到 `.default` 把命名空间整个丢弃了。Loader 随后基于一个空的 `inject` 构建了插件的 fiber。 +存在 default export 时,`exports.default ?? exports` 解析为**裸 `apply` 函数**。裸函数没有 `inject`、没有 `name`、没有 `Config` 属性——这些作为*兄弟*命名导出存在于模块命名空间上,而 unwrap 到 `.default` 把整个命名空间丢弃了。Loader 随后基于空的 `inject` 构建了插件的 fiber。 因此 `apply` 在一个**没有注入任何服务**的 fiber 中运行。第一行 `const agents = ctx.agents` 遍历 fiber 树(ROOT → Include → Loader → ROOT),在所有 fiber 的 store 中都找不到 `agents`,到达根 fiber(`runtime === null`)后抛出 `cannot get property "agents" without inject`。崩溃发生在*加载时*,而非后续的请求处理器中——请求只是恰好触发了加载。 -**修复:**删除 `export default apply`。Loader 随后使用模块命名空间,正确识别 `inject`/`name`/`Config`,`apply` 在一个真正授予了声明服务的 fiber 中运行。 +**修复:** 删除 `export default apply`。Loader 随后使用模块命名空间,正确识别 `inject`/`name`/`Config`,`apply` 在一个真正授予了声明服务的 fiber 中运行。 -## 根因 #2——可选服务的属性读取在 traceable shadow 中触发 inject 守卫(导致 `session/load` 崩溃) +## 根因 #2——可选服务读取通过 traceable shadow 触发 inject 守卫(导致 `session/load` 崩溃) -修复 #1 后,`session/new` 正常工作,但 `session/load` 仍然抛出 `cannot get property "sessionPersistence" without inject`。这次*确实*是 Cordis 的 traceable/shadow 机制,值得精确理解。 +修复 #1 后,`session/new` 正常工作,但 `session/load` 仍然抛出 `cannot get property "sessionPersistence" without inject`。这个问题*确实*是 Cordis 的 traceable/shadow 机制,值得精确理解。 -`session/load` 调用 `agents.resume(...)`,后者委托给 `AgentLoop.resume()`,其中读取了 `this.ctx.sessionPersistence`。`AgentLoop` 的 `static inject` 故意**不**包含 `sessionPersistence`——注入它会导致非持久化的演示永远挂起,等待一个永远不会加载的后端。该服务由一个独立的兄弟插件/fiber 提供,按需读取。 +`session/load` 调用 `agents.resume(...)`,后者委托给 `AgentLoop.resume()`,其中读取了 `this.ctx.sessionPersistence`。`AgentLoop` 的 `static inject` 故意**不**包含 `sessionPersistence`——注入它会导致非持久化的演示永远挂起,等待一个永远不会加载的后端。该服务由一个独立的兄弟插件/fiber 提供,以机会性方式读取。 -Cordis 中的服务访问通过上下文代理(`vendor/cordis/src/reflect.ts`)进行。当通过从外部 fiber 获取的 *traceable 代理*调用服务方法时(此处:bridge fiber 调用 `ctx.agents.resume`,注册表返回 `this.factory`——即 `AgentLoop`——被重新包装为绑定到调用方的新 traceable 代理),`createShadowMethod`(`vendor/cordis/src/utils.ts`)将 `this` 重新绑定到一个 *shadow* 对象,其 `ctx` 携带 `[symbols.shadow]` 指向 `AgentLoop` 自身的构造上下文。在 `resume` 内部,`this.ctx.sessionPersistence` 的解析从 shadow 的 fiber 开始遍历: +Cordis 中的服务访问通过上下文代理(`vendor/cordis/src/reflect.ts`)进行。当通过从外部 fiber 获取的 *traceable 代理*调用服务方法时(此处:bridge fiber 调用 `ctx.agents.resume`,注册表返回 `this.factory`——即 `AgentLoop`——重新包装为绑定到调用方的新 traceable 代理),`createShadowMethod`(`vendor/cordis/src/utils.ts`)将 `this` 重新绑定到一个 *shadow* 对象,其 `ctx` 携带 `[symbols.shadow]` 指向 `AgentLoop` 自身的构造上下文。在 `resume` 内部,`this.ctx.sessionPersistence` 的解析从 shadow 的 fiber 开始遍历: ```ts ignore-check // reflect.ts get handler @@ -74,40 +74,40 @@ while (true) { } ``` -遍历**只走祖先方向**。`sessionPersistence` 既不在 `AgentLoop` 的 fiber store 中(不在其 `static inject` 里),也不在通往根的任何祖先上(它在一个*兄弟*分支上),因此遍历到达根 fiber 后抛出。 +遍历**仅向祖先方向**进行。`sessionPersistence` 既不在 `AgentLoop` 的 fiber store 中(不在其 `static inject` 中),也不在通往 root 的任何祖先上(它位于一个*兄弟*分支),因此遍历到达根 fiber 后抛错。 -为什么内存中的 `AgentLoop` resume 测试没有捕获到这个问题?因为它们从测试代码中直接调用 `ctx.agents.resume(...)`——*不在任何插件 fiber 内*。此时 `ctx.fiber.runtime` 为 `null`,代理处理器走了一条提前退出的路径: +为什么内存中的 `AgentLoop` resume 测试没有捕获这个问题?因为它们从测试代码直接调用 `ctx.agents.resume(...)`——*在任何插件 fiber 之外*。此时 `ctx.fiber.runtime` 为 `null`,代理处理器走了一条提前绕过的路径: ```ts ignore-check if (!ctx.fiber.runtime) return ctx.reflect.get(prop, false) // ← direct global-store lookup, no fiber walk ``` -`ctx.reflect.get(name, false)` 是基于 isolate symbol 的全局服务 store 直接查找——完全忽略 fiber 拓扑,能找到服务。因此从顶层测试读取正常;从真实插件 fiber 内部、经由 shadow 到达时则抛出。bridge 恰好是后者。 +`ctx.reflect.get(name, false)` 是基于 isolate symbol 的全局服务 store 直接查找——完全忽略 fiber 拓扑,能找到服务。因此从顶层测试读取可以成功;而从真实插件 fiber 内部、经由 shadow 到达时则抛错。bridge 恰好是后者。 -**修复:**使用 `ctx.get('sessionPersistence')` 读取可选服务,该方法使用全局 isolate-keyed store,同时保留活跃状态检查。对于插件声明注入集中的服务,直接属性读取仍然适用。 +**修复:** 使用 `ctx.get('sessionPersistence')` 读取可选服务,该方法使用全局 isolate-keyed store 同时保留活跃状态检查。对于插件声明注入集中的服务,直接属性读取仍然适用。 -## 为什么所有测试都漏掉了(真正的失败) +## 为什么所有测试都没有捕获(真正的失败) -两个 bug 共享同一个流程缺口:**没有任何测试通过插件的真实加载路径或真实调用拓扑来运行它。** +两个 bug 共享同一个流程缺口:**没有任何测试通过插件的真实加载路径或真实调用拓扑来驱动它。** -- 内存 harness 通过手动构建插件对象来挂载 bridge:`ctx.plugin({ name, inject, apply })`。这手动提供了 `inject`,因此永远无法复现 Bug #1——`unwrapExports` 只被 *Loader* 调用,`ctx.plugin` 从不调用它。即使 `ctx.plugin(NamespaceImport)` 也无法捕获此问题。 -- 同一个 harness 把所有东西平铺挂载在一个根上下文上,因此从中触达的 `AgentLoop` resume 要么在顶层运行(`!runtime` 旁路),要么通过一个 origin 仍在根上解析的 shadow——掩盖了 Bug #2 的祖先遍历失败。 -- 唯一的无 key e2e 发送 `initialize` 并检查 stdout 纯净性。`initialize` 从不触达 factory,因此安然通过两个 bug。 -- 唯一驱动 `session/new`/`session/load` 的测试需要 key 才能运行,CI(无 key)跳过了它——而本地它之所以「通过」,只是因为一个陈旧的已构建 `lib/`(包含旧代码)恰好满足了模块解析。 +- 内存 harness 通过手动构建插件对象来挂载 bridge:`ctx.plugin({ name, inject, apply })`。这手动提供了 `inject`,因此永远无法复现 Bug #1——`unwrapExports` 只被 *Loader* 调用,`ctx.plugin` 从不调用它。即使 `ctx.plugin(NamespaceImport)` 也无法捕获。 +- 同一个 harness 将所有内容平铺挂载在一个根上下文上,因此从中触达的 `AgentLoop` resume 要么运行在顶层(`!runtime` 绕过),要么通过一个 origin 仍然解析在 root 上的 shadow——掩盖了 Bug #2 的祖先遍历失败。 +- 唯一的无 key e2e 发送 `initialize` 并检查 stdout 纯净性。`initialize` 从不触达 factory,因此两个 bug 都安然通过。 +- 唯一驱动 `session/new`/`session/load` 的测试需要 key 才能运行,因此 CI(无 key)跳过了它——而本地它之所以「通过」,只是因为一个陈旧的已构建 `lib/`(包含旧代码)恰好满足了模块解析。 -100% 行覆盖率自始至终满足。覆盖率证明代码行*被执行过*;它不能说明功能是否*以交付的方式*工作。 +100% 行覆盖率始终满足。覆盖率证明代码行*被执行过*;它不能说明功能是否*按交付方式正常工作*。 ## 新增的防护措施 -- **移除 `export default apply`**(`packages/ui/acp/src/index.ts`)——Bug #1 的修复。 +- **删除 `export default apply`**(`packages/ui/acp/src/index.ts`)——Bug #1 的修复。 - **`AgentLoop.resume` 使用 `this.ctx.get('sessionPersistence')`**(`packages/core/agent-loop/src/index.ts`)——Bug #2 的修复,附注释说明 shadow 遍历陷阱。 - **无需 key 的 `session/new` e2e,通过真实 stdio 运行**(`examples/acp-agent/tests/acp.e2e.ts`):以子进程方式通过真实 Loader 启动示例,并断言 `session/new` 正常返回。无需 API key 即可在 Bug #1 上大声失败。已验证恢复 `export default apply` 时测试失败。 -- **e2e spawn 中设置 `TSX_TSCONFIG_PATH`**:子进程从临时 cwd 运行,tsx 无法通过向上搜索找到仓库根的 tsconfig `paths` 映射——因此 dsh-* 的导入静默回退到已构建的 `lib/`。将 tsx 指向仓库 tsconfig 使解析不依赖 cwd,确保测试运行的是*源码*而非可能陈旧的构建产物。 -- **[docs/testing.md](../testing.md) 规则**:「测试真实入口路径」,行覆盖率不等于行为覆盖率——将此教训编纂为所有未来插件的规则。 +- **e2e spawn 中设置 `TSX_TSCONFIG_PATH`**:子进程从临时 cwd 运行,tsx 无法通过向上搜索找到仓库根的 tsconfig `paths` 映射——因此 dsh-* 的 import 静默回退到已构建的 `lib/`。将 tsx 指向仓库 tsconfig 使解析不依赖 cwd,确保测试运行的是*源码*而非可能陈旧的构建产物。 +- **[docs/testing.md](../testing.md) 规则**:「测试真实入口路径」,行覆盖率不等于行为覆盖率——将这一教训编纂为所有未来插件的规则。 -## 教训 +## 经验教训 - 命名空间插件与 default export 在 Cordis Loader 下互斥。选择命名空间形式(`name`/`inject`/`Config`/`apply`),不要添加 `export default`——`unwrapExports` 会丢弃命名空间。 -- 对于插件按需读取但**不**声明在 `static inject` 中的服务,使用 `ctx.get(name)`,绝不使用 `ctx.<name>`。属性代理通过只走祖先方向的 fiber 遍历解析,经由外部 shadow 时会失败;`ctx.get(name)` 是拓扑无关的查找(且默认严格——后端未激活时返回 `undefined`,而非在 teardown 过程中把半拆除的实例交出去)。 -- 手动构造插件的测试无法验证插件的加载方式。至少一个测试必须端到端地驱动真实的 Loader/export 路径。当核心操作不调用模型时,该测试无需 API key——因此它属于 CI,而非 key 门控之后。 -- 相信 trace,不要相信理论。优雅的 shadow 解释是真实的,但它是*第二个* bug;*第一个*是一行导出错误,在数小时合理但错误的推理之后,一条 fiber 遍历的 `console.error` 几分钟就找到了它。 +- 对于插件机会性读取但**未**在 `static inject` 中声明的服务,使用 `ctx.get(name)`,绝不使用 `ctx.<name>`。属性代理通过仅向祖先方向的 fiber 遍历解析,经由外部 shadow 时会失败;`ctx.get(name)` 是拓扑无关的查找(且默认严格——非活跃后端读取为 `undefined`,而非在 teardown 过程中被交出)。 +- 手动构建插件的测试无法验证插件的加载方式。至少一个测试必须端到端地驱动真实的 Loader/export 路径。当核心操作不调用模型时,该测试无需 API key——因此它属于 CI,而非 key 门控之后。 +- 相信 trace,不要相信理论。优雅的 shadow 解释是真实的,但它是*第二个* bug;*第一个*是一行导出错误,在数小时看似合理但实际错误的推理之后,一个 fiber 遍历的 `console.error` 在几分钟内就找到了它。 diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml index f59f7794de..533c899345 100644 --- a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 0002-js-expression-disabled-filesystem-tools.md: 43e57a6bd1b68f38c47eeda3c3abb8455024b350 -0002-js-expression-disabled-filesystem-tools.zh.md: e54431b7f4061bb4bdc22a37f0651697c6247dda +0002-js-expression-disabled-filesystem-tools.zh.md: 35bd54bb6f1551b5927c00184306141417803eaf diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md index e54431b7f4..35bd54bb6f 100644 --- a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md @@ -4,44 +4,44 @@ Status: resolved +## 概要 + +ACP(Agent Client Protocol)示例试图通过 `disabled: !!js ...` 有条件地启用文件系统插件,但 Cordis 仅在插件 `config` 内部对 JavaScript 表达式求值。原始的表达式对象为 truthy,因此文件系统栈始终处于禁用状态。快照刷新随后将 `UNKNOWN_TOOL` 结果接受为新的 golden 基准。修复方案改用显式的文件系统 overlay,并增加了静态配置守卫和快照结果守卫。 + ## 摘要 -ACP 示例试图通过 `disabled: !!js ...` 有条件地启用文件系统插件,但 Cordis 仅在插件 `config` 内部求值 JavaScript 表达式。原始的表达式对象为 truthy,因此文件系统栈始终处于禁用状态。快照刷新随后将 `UNKNOWN_TOOL` 结果作为新的 golden 接受。修复方案使用显式的文件系统 overlay,并增加了静态配置守卫和快照结果守卫。 +默认的 ACP 组合有意只启用 bash,因为其沙箱无法约束进程内的文件系统提供方。文件系统快照场景仍然需要 `read`、`write` 和 `edit`,因此这些插件被放在默认的 `cordis.yml` 中,并附带一个 `disabled` 表达式,意图仅在全权限启动和快照模式下启用它们。 -## 概述 - -默认的 ACP 组合有意仅包含 bash,因为其沙箱无法约束进程内的文件系统提供方。文件系统快照场景仍需要 `read`、`write` 和 `edit`,因此这些插件被放入默认的 `cordis.yml`,并附带一个 `disabled` 表达式,意图仅在全权限启动和快照模式下启用它们。 - -Cordis Include 将每个 `!!js` 标量解析为一个表达式对象。Loader 递归地对插件的 `config` 进行了插值,但直接消费了 `disabled` 等入口元数据。因此每个文件系统入口都看到一个 truthy 对象,在所有模式下均保持禁用。 +Cordis Include 将每个 `!!js` 标量解析为一个表达式对象。Loader 递归地对插件的 `config` 进行插值,但直接消费 `disabled` 等入口元数据。因此每个文件系统入口看到的都是一个 truthy 对象,在所有模式下均保持禁用。 ## 影响 -七个文件系统场景和一个混合工作区编辑场景调用了注册表中不存在的工具。它们的结构化会话日志携带 `ToolNotFoundError`(code 为 `UNKNOWN_TOOL`),stdout 则渲染了通用的失败工具卡片。快照套件通过了,因为两个表面都与刷新后的 fixture(测试前置数据)匹配;它证明的是回归的确定性回放,而非文件系统行为的正确性。 +七个文件系统场景和一个混合工作区编辑场景调用了注册表中不存在的工具。其结构化会话日志携带 `ToolNotFoundError`(code 为 `UNKNOWN_TOOL`),stdout 渲染出通用的失败工具卡片。快照套件通过了,因为两个表面都与刷新后的 fixture(测试前置数据)匹配;它证明的是回归的确定性回放,而非文件系统行为的正确性。 -实际运行的受限默认组合并未获得意外的文件系统访问。一个朴素的插值修复反而会引入该风险:权限预设在运行时更新 bash 沙箱和审批状态,但无法挂载、卸载或约束文件系统栈。 +实际运行的受限默认模式并未获得意外的文件系统访问权限。一个简单的插值修复反而会制造该风险:权限预设在运行时更新 bash 沙箱和审批状态,但无法挂载、卸载或约束文件系统栈。 ## 时间线 - PR #261 整合了 ACP 组合并刷新了文件系统快照,同时引入了条件式文件系统入口。 - 所有单元测试、覆盖率、快照、文档、构建和 hygiene 检查均通过。 - 对刷新后的文件系统 golden 的评审发现了通用的失败卡片和结构化的 `UNKNOWN_TOOL` 结果。 -- 一次真实的 Loader 启动确认:每个 `disabled` 值仍然是表达式对象,每个文件系统 fiber 均未注册。 +- 一次真实的 Loader 启动确认:每个 `disabled` 值仍为表达式对象,每个文件系统 fiber 均未创建。 ## 根因 -实现方假设 `!!js` 适用于整个 Loader 入口。其实际边界更窄:`Entry._resolveConfig()` 仅对 `entry.options.config` 进行插值;`Entry.disabled` 直接测试 `entry.options.disabled`,不做插值。YAML 标签在语法上合法,因此加载过程不产生任何诊断信息。 +实现时假设 `!!js` 适用于整个 Loader 入口。其实际边界更窄:`Entry._resolveConfig()` 仅对 `entry.options.config` 进行插值;`Entry.disabled` 直接测试 `entry.options.disabled`,不经过插值。YAML 标签在语法上合法,因此加载过程不产生任何诊断信息。 -快照框架将任何确定性的 transcript(文本记录)视为有效行为。Header pin 验证了组合后的工具 schema,但文件系统场景共享了来自默认组合的 pin,因此未独立证明其所需工具已注册。刷新在任何语义断言拒绝缺失工具之前,就已重写了预期的 stdout 和会话日志。 +快照框架将任何确定性的 transcript(文本记录)视为有效行为。Header pin 验证了组合后的工具 schema,但文件系统场景共享来自默认组合的 pin,因此未独立证明其所需工具已注册。刷新在任何语义断言拒绝缺失工具之前,就已重写了预期的 stdout 和会话日志。 -## 新增的防护措施 +## 已添加的防护措施 - 文件系统场景启动 `fs.cordis.yml`:一个显式的固定全权限 overlay,配有对应的 replay 配置和独立的 request-header 类。 -- [`AGENTS.md`](../../AGENTS.md) 和 [Cordis 入门](../cordis-primer.md#loader-configuration) 明确说明 `!!js` 仅在插件 `config` 下有效,条件式组合应使用 overlay。 -- `verify-cordis-config` 解析仓库中的 Cordis YAML,拒绝 Loader 入口元数据(包括 include patch 和插入的入口)中出现表达式节点。 -- `dsh-acp-snapshot` 在新鲜运行和已提交的会话 fixture 中拒绝结构化的 `UNKNOWN_TOOL` 结果,阻止其成为被接受的 golden。 +- [`AGENTS.md`](../../AGENTS.md) 与 [Cordis 入门](../cordis-primer.md#loader-configuration)明确说明 `!!js` 仅在插件 `config` 内有效,条件式组合应使用 overlay。 +- `verify-cordis-config` 解析仓库中的 Cordis YAML,拒绝 Loader 入口元数据中的表达式节点(包括 include patch 和插入的入口)。 +- `dsh-acp-snapshot` 在新鲜运行和已提交的会话 fixture 中拒绝结构化的 `UNKNOWN_TOOL` 结果,防止其成为被接受的 golden 基准。 ## 教训 - 语法上被接受的配置值不一定在该位置被求值;应记录并验证插值边界。 -- 快照刷新是 fixture 生产,不是正确性评审。像「已注册工具缺失」这样的语义不可能性需要独立于 golden 的断言。 -- 权限控制只应描述它实际管辖的能力。组合时的文件系统访问无法安全地跟随运行时的 bash-only 预设。 +- 快照刷新是 fixture 的生产过程,不是正确性审查。诸如已注册工具缺失这类语义上不可能的结果,需要独立于 golden 的断言。 +- 权限控制只应描述其实际管辖的能力。组合时的文件系统访问无法安全地跟随运行时的 bash-only 预设。 diff --git a/docs/postmortem/README.i18n.yaml b/docs/postmortem/README.i18n.yaml index f57d280d36..9fd5399786 100644 --- a/docs/postmortem/README.i18n.yaml +++ b/docs/postmortem/README.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write README.md: 4dc59e4f5e70f51c4c0baa64fbe34b213f2a7c3d -README.zh.md: 7e2d05d429b2521e7e772956b7644740d4642fac +README.zh.md: e9ea00dacf3fde6f4d04c9a3b6dd5beeb7929660 diff --git a/docs/postmortem/README.zh.md b/docs/postmortem/README.zh.md index 7e2d05d429..e9ea00dacf 100644 --- a/docs/postmortem/README.zh.md +++ b/docs/postmortem/README.zh.md @@ -2,15 +2,15 @@ [English](README.md) | 中文 -事故记录:一个 bug 到达了它不该到达的地方(真实用户、已合并的 PR(Pull Request)、已发布的版本),有意义的部分是**为什么我们的流程放过了它**,而不仅仅是那行修复。 +事件复盘:一个 bug 到达了它不该到达的地方(真实用户、已合并的 PR(Pull Request)、已发布的版本),值得关注的是*为什么我们的流程放过了它*,而不仅仅是那一行修复。 -事后分析不是 [RFC](../rfc/README.md)(RFC 记录的是经过深思熟虑的设计决策及其被否决的替代方案,或提出未来工作)。它是一份面向过去的失败记录:什么坏了、机制是什么、为什么每道安全网都没拦住、以及加了哪些具体护栏使同类 bug 下次能快速失败。 +事后分析不是 [RFC](../rfc/README.md)(RFC 记录一个经过深思熟虑的设计决策及其被否决的替代方案,或提出未来工作)。它是一份回顾性的失败记录:什么坏了、机制是什么、为什么每道安全网都没拦住、以及加了哪些具体的防护措施使同类 bug 下次能被显式暴露。 -满足以下条件时写一篇:bug **隐蔽**(机制不显而易见,一位细心的工程师也得费力重新推导)、**系统性**(逃逸的原因是测试/工具/约定的缺口,而非一次性手误)、**重新发现的代价高**(它消耗了真实的调试时间,而且下次还会)。请链接该事后分析所推动建立的护栏(测试、AGENTS.md 规则、ADR)。 +当一个 bug 满足以下条件时,请撰写事后分析:**隐蔽**(机制不显而易见,即使是细心的工程师也得费力重新推导)、**系统性**(逃逸的原因是测试/工具/约定的缺口,而非一次性的笔误)、**重新发现的代价高**(它消耗了真实的调试时间,且下次还会如此)。请链接该事后分析所推动建立的防护措施(测试、AGENTS.md 规则、ADR)。 -每篇事后分析以一段 **Executive summary** 开头:一段简短的文字,让忙碌的读者在三十秒内了解全貌——什么坏了、用通俗语言说的根因、为什么逃逸了、以及持久的教训——之后再展开详细的 Summary / Timeline / Root cause / Guardrails 各节。 +每篇事后分析以一段**摘要**开头:一个简短段落,让忙碌的读者在三十秒内吸收要点——什么坏了、用直白的话说根因是什么、为什么逃逸了、持久的教训是什么——然后才是后续的详细「概述 / 时间线 / 根因 / 防护措施」各节。 | # | 标题 | |---|---| -| [0001](0001-acp-default-export-drops-inject.md) | ACP server crashed on connect: `export default` dropped the plugin's `inject` | -| [0002](0002-js-expression-disabled-filesystem-tools.md) | Filesystem snapshot tools were permanently disabled by a literal `!!js` object | +| [0001](0001-acp-default-export-drops-inject.md) | ACP 服务器在连接时崩溃:`export default` 丢失了插件的 `inject` | +| [0002](0002-js-expression-disabled-filesystem-tools.md) | 文件系统快照工具被一个字面量 `!!js` 对象永久禁用 | diff --git a/docs/rfc/README.i18n.yaml b/docs/rfc/README.i18n.yaml index 5bda02fc38..8d007fe169 100644 --- a/docs/rfc/README.i18n.yaml +++ b/docs/rfc/README.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write README.md: 9014579f3a98be907885332a0c815bca5c96855c -README.zh.md: b51343b35aa04830b694f560ca9ae490995dcd43 +README.zh.md: cf258dc9ae1d73bf89d6a82c9bf246152c15e8b4 diff --git a/docs/rfc/README.zh.md b/docs/rfc/README.zh.md index b51343b35a..cf258dc9ae 100644 --- a/docs/rfc/README.zh.md +++ b/docs/rfc/README.zh.md @@ -2,48 +2,48 @@ [English](README.md) | 中文 -这里存放一类设计文档。**RFC** 记录塑造本代码库的决策或提案——代码和文档本身无法承载的*为什么*以及*放弃了什么*。完整列表见生成的 [INDEX.md](INDEX.md);本文是契约——RFC 放在哪里、何时该写,以及[文件内格式](#the-file-format)。 +这里存放一类设计文档。**RFC** 记录塑造本代码库的决策或提案:代码和文档无法承载的*为什么*以及*放弃了什么*。完整列表见生成的 [INDEX.md](INDEX.md);本文件是契约:RFC 存放在哪里、何时需要写一份,以及[文件内格式](#the-file-format)。 ## 布局与命名 -每篇 RFC 有两个轴,都编码在其**路径**中——`{lifecycle}/{class}/yyyy-mm-dd-topic-title.md`: +每份 RFC 有两个维度,都编码在其**路径**中:`{lifecycle}/{class}/yyyy-mm-dd-topic-title.md`。 -- **生命周期**(顶层文件夹)是 RFC 的状态,RFC 随状态变更在文件夹间移动: - - **`proposed/`**——实现前评审的提案;尚未构建(或仅部分构建)。 - - **`implemented/`**——决策已交付。文件记录做了什么决定、否决了什么,并**与实际交付的内容保持同步**:当代码后来移动了文件、重命名了包(package)或更改了键/默认值时,RFC 在同一个变更中更新以匹配(仅限事实——路径、名称、结构——不涉及决策本身)。见 [implemented/AGENTS.md](implemented/AGENTS.md)。 - - **`rejected/`**——提案经考虑后被否决。保留以备查阅,避免同一问题被反复争论。 -- **分类**(嵌套文件夹)是决策的*类型*——见下方[分类](#classification)。 +- **生命周期**(顶层文件夹)是 RFC 的状态,RFC 随状态变化在文件夹之间移动: + - **`proposed/`**:实施前评审的提案;尚未构建(或仅部分构建)。 + - **`implemented/`**:决策已交付。文件记录做了什么决定、否决了什么,并**与实际交付的内容保持同步**:当代码后续移动文件、重命名包(package)或更改键名/默认值时,RFC 在同一个变更中同步更新(仅限事实——路径、名称、结构——而非决策本身)。见 [implemented/AGENTS.md](implemented/AGENTS.md)。 + - **`rejected/`**:提案经过讨论后被否决。保留以备查阅,避免同一问题被反复争论。 +- **类别**(嵌套文件夹)是决策的*种类*——见下方[分类](#classification)。 文件名中的日期是该主题**首次提出**的时间(以 git 历史为准)。RFC 之间的交叉引用使用相对 Markdown 链接(`[topic](../../implemented/architecture/2026-…-….md)`),从不使用纯文字或编号,这样既可机械检查,也能在文件夹间移动时保持有效。 ## 分类 -每篇 RFC 归属于 `scripts/rfc-index.ts` 中封闭集合里的一个路径编码分类;分类门禁拒绝其他文件夹。[INDEX.md](INDEX.md) 由路径、标题和文件名日期生成,其新鲜度受门禁保护。新增分类需要同时更新规范集合与本节。见[分类 RFC](implemented/process/2026-06-20-rfc-classification.md) 与[索引生成 RFC](implemented/process/2026-07-04-generate-rfc-index-tables.md)。 +每份 RFC 属于 `scripts/rfc-index.ts` 中封闭集合里的一个路径编码类别;分类门禁拒绝其他文件夹。[INDEX.md](INDEX.md) 由路径、标题和文件名日期生成,其新鲜度受门禁保护。新增类别需要同时更新规范集合与本节。见[分类 RFC](implemented/process/2026-06-20-rfc-classification.md) 与[索引生成 RFC](implemented/process/2026-07-04-generate-rfc-index-tables.md)。 -| 分类 | 涵盖内容 | +| 类别 | 覆盖范围 | |---|---| | `feature` | 面向用户或模型的新能力。 | -| `bug-fix` | 修正缺陷或填补事后复盘暴露的空白。 | -| `simplification` | 在不增加能力的前提下移除代码、行为或接口面。 | -| `architecture` | 关于**交付源码**的结构性决策——包之间的关系、运行时词汇。 | -| `process` | 围绕代码的工具、政策或工作流——门禁、包管理器、vendor 化——而非运行时行为。 | +| `bug-fix` | 修正缺陷或弥补事后复盘发现的缺口。 | +| `simplification` | 在不增加能力的前提下移除代码、行为或对外表面积。 | +| `architecture` | 关于**交付源码**的结构性决策:包之间的关系、运行时词汇。 | +| `process` | 代码**周边**的工具、策略或工作流——门禁、包管理器、vendor 化——不涉及运行时行为。 | | `testing` | 测试基础设施与策略。 | -`architecture` 与 `process` 的分界线:**architecture** 关乎我们交付的源码;**process** 关乎围绕源码的工具与工作流。(`refactor` 被刻意省略——它与 `simplification` 重叠,后者的判别标准「可观测行为是否改变」已覆盖了它。) +`architecture` 与 `process` 的界线:**architecture** 关乎我们交付的源码;**process** 关乎围绕源码的工具与工作流。(`refactor` 被有意排除:它与 `simplification` 重叠,而后者的判别标准「可观察行为是否改变」已经覆盖了它。) -## 何时该写 +## 何时需要写一份 -当一个决策**持久**(它塑造代码库的范围超出单个函数或包)、**有争议**(存在一个合理工程师可能选择的真实替代方案)、且**令人意外**(未来读者否则会问「为什么要这样做」)时,请写一篇 RFC。对未来大量工作的提案从 `proposed/` 开始;已做出的决策从 `implemented/` 开始。选择与决策匹配的分类文件夹(见[分类](#classification))。 +当一个决策具备以下三个特征时,请写一份 RFC:**持久性**(它的影响超出单个函数或包)、**争议性**(存在一个合理工程师可能选择的真实替代方案)、**意外性**(未来读者否则会问「为什么要这样做」)。对未来重大工作的提案从 `proposed/` 开始;已经做出的决策从 `implemented/` 开始。选择与决策匹配的类别文件夹(见[分类](#classification))。 -以下情况**不要**写 RFC:机械性或局部的选择(变量名、单文件重构);已由门禁或 AGENTS.md 中的约定强制并解释的事项;代码中标记为 `TODO(...)` 的暂定决策——将其记为 TODO,待尘埃落定后再提升为 RFC。RFC 永远不会被编辑成*另一个决策*:用新 RFC 取代旧的并互相链接。(编辑 `implemented/` RFC 以跟踪其已做出的决策现在*位于何处*——移动的文件、重命名的包——不是另一个决策,是必须做的,而非禁止的;见 [implemented/AGENTS.md](implemented/AGENTS.md)。) +以下情况**不要**写 RFC:机械性或局部的选择(一个变量名、一次单文件重构);已由门禁或 AGENTS.md 中的约定强制执行并解释的事项;代码中标记为 `TODO(...)` 的临时决策——将其记为 TODO,待稳定后再升级为 RFC。RFC 永远不会被编辑为一个*不同的决策*:用新 RFC 取代旧的,并互相链接。(编辑 `implemented/` RFC 以跟踪其已做出的决策现在*位于*何处——移动的文件、重命名的包——不是不同的决策,这是必需的而非禁止的;见 [implemented/AGENTS.md](implemented/AGENTS.md)。) ## 文件格式 -每篇 RFC 遵循统一的文件内格式,由 `pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../scripts/verify-rfc-format.ts),doc-sync(文档同步门禁)的一环)强制执行;该格式的设计动机及其否决的替代方案见[统一格式 RFC](implemented/process/2026-07-05-uniform-rfc-format.md)。 +每份 RFC 遵循统一的文件内格式,由 `pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../scripts/verify-rfc-format.ts),`doc-sync`(文档同步门禁)的一环)强制执行;该格式的设计动机及其否决的替代方案见[统一格式 RFC](implemented/process/2026-07-05-uniform-rfc-format.md)。 ### 头部块 -每篇 RFC 的前三行严格为: +每份 RFC 的前三行严格为: ```markdown # RFC: <title> @@ -51,17 +51,17 @@ Status: <status> ``` -后接一个空行。`Status:` 的值有三种形式,且必须与文件所在的生命周期文件夹一致——门禁会交叉检查: +后跟一个空行。`Status:` 的值有三种形式,且必须与文件所在的生命周期文件夹一致——门禁会交叉检查: - `Status: proposed` - `Status: implemented` - `Status: rejected — <why, in one line>` -状态行不带日期、不带括号补充说明:文件名承载首次提出日期,git 承载其余一切,「以修订形式接受」之类的说明属于正文内容(在陈述决策的地方说明修订)。否决原因是唯一带内容的状态行,因为读者查阅被否决 RFC 时要的就是结论。 +状态行不带日期、不带括号补充说明:文件名记录首次提出日期,git 记录其余一切;「以修订形式接受」之类的说明属于正文内容(在陈述决策的地方说明修订)。拒绝原因是唯一带内容的状态,因为读者查阅被否决的 RFC 时,结论正是他们要找的。 ### 正文骨架 -每篇 RFC 的正文以 `## Problem` 开头——动机,写法应独立于解决方案。后续内容取决于生命周期;重复出现的章节使用以下规范名称且仅限这些名称,而真正特有的技术章节(包拓扑、协议格式(wire format)、schema)在必需章节之间自由编排。 +每份 RFC 的正文以 `## Problem` 开头:动机,写法上不依赖解决方案即可独立成文。后续内容取决于生命周期;固定章节使用以下规范名称且仅限这些名称,而真正独特的技术章节(包拓扑、协议契约、schema 等)在必需章节之间可自由组织。 #### `proposed/` @@ -74,7 +74,7 @@ Status: <status> ## Risks ``` -`## Proposal` 是拟议的变更,可以正当地使用将来时——计划、迁移步骤和未决问题在工作尚未构建时属于此处。`## Acceptance criteria` 说明什么可观测状态意味着完成。`## Risks` 涵盖可能出错的事项以及变更有意放弃的东西。 +`## Proposal` 描述拟议的变更,可以合理地使用将来时态——计划、迁移步骤和待解决问题在工作尚未完成时属于此处。`## Acceptance criteria` 说明什么可观察状态意味着完成。`## Risks` 涵盖可能出错的事项以及该变更有意放弃的东西。 #### `implemented/` @@ -86,26 +86,26 @@ Status: <status> ## Consequences ``` -`## Decision` 以现在时描述已交付的现实,整个文件按 [implemented/AGENTS.md](implemented/AGENTS.md) 的要求与之保持同步。`## Consequences` 记录权衡的代价**与**收益。提案阶段的标题在这里属于规格用语,门禁会拒绝:`## Proposal`、`## Plan`、`## Migration plan` 和 `## Acceptance criteria` 不得出现在 implemented RFC 中([slop 检查清单](../AGENTS.md)说明了原因)。`## Testing`、`## Deferred` 或 `## Related` 章节在陈述现在时事实时是允许的。 +`## Decision` 以现在时态描述已交付的现实,整个文件按 [implemented/AGENTS.md](implemented/AGENTS.md) 的要求与之保持同步。`## Consequences` 记录权衡的代价**与**收益。提案阶段的标题在此属于规格用语,门禁会拒绝它们:`## Proposal`、`## Plan`、`## Migration plan` 和 `## Acceptance criteria` 不得出现在 implemented RFC 中(原因见 [slop 检查清单](../AGENTS.md))。`## Testing`、`## Deferred` 或 `## Related` 章节在陈述现在时态的事实时是允许的。 #### `rejected/` -被否决的 RFC 是冻结的提案:保留其提案时的所有章节(包括 `## Acceptance criteria` 或 `## Plan`),结论写在 `Status:` 行。仅头部块、`## Problem` 开头、`## Proposal` 章节,以及下方的「曾考虑的替代方案」强制要求适用。 +被否决的 RFC 是冻结的提案:保留提案时的所有章节(包括 `## Acceptance criteria` 或 `## Plan`),结论写在 `Status:` 行上。仅头部块、`## Problem` 开头、`## Proposal` 章节以及下方的「曾考虑的替代方案」强制要求适用。 -### 曾考虑的替代方案——强制要求 +### 曾考虑的替代方案——必需 -每篇 RFC 都必须有一个 `## Alternatives considered` 章节:每个真实的替代方案及其落选原因,每个替代方案一段(加粗引导),或对争议较大的方案使用 `### Why not <X>?` 子章节。记录决策却不记录它击败了什么,就是在邀请反复争论——正是 RFC 存在的目的所要防止的。 +每份 RFC 都必须包含 `## Alternatives considered` 章节:每个真实的替代方案及其落选原因,每个替代方案用一个加粗引导的段落,或对争议较大的替代方案用 `### Why not <X>?` 子节。记录决策时不记录它击败了什么,就是在邀请反复争论——正是 RFC 存在的意义所要防止的。 -替代方案是记录下来的,而非凭空编造的。日期早于 2026-07-05 的 RFC,如果其替代方案无法从记录中重建,则在该章节位置放置以下精确注释,门禁仅对格式前文件接受此注释: +替代方案是记录下来的,不是凭空编造的。日期早于 2026-07-05 且替代方案无法从记录中重建的 RFC,在该章节位置放置以下精确注释,门禁仅对格式规范之前的文件接受此注释: ```markdown <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> ``` -### 在生命周期间移动 +### 在生命周期之间移动 -将文件在生命周期文件夹间移动意味着在同一个变更中更新 `Status:` 行并满足目标文件夹的骨架要求——否则门禁会失败。具体而言,`proposed/` → `implemented/` 将 `## Proposal` 改写为现在时的 `## Decision`,将 `## Acceptance criteria` 和 `## Risks` 折叠进 `## Consequences`(或一个现在时的 `## Testing`/`## Verification` 章节,用于说明现在什么在固定该行为),并用实际交付的内容替换计划——即 [implemented/AGENTS.md](implemented/AGENTS.md) 要求的改写,使之机械化。`proposed/` → `rejected/` 仅在 `Status:` 行添加原因并冻结文件。 +将文件在生命周期文件夹之间移动意味着在同一个变更中更新 `Status:` 行并满足目标文件夹的骨架要求——否则门禁会失败。具体而言,`proposed/` → `implemented/` 将 `## Proposal` 改写为现在时态的 `## Decision`,将 `## Acceptance criteria` 和 `## Risks` 折入 `## Consequences`(或折入一个现在时态的 `## Testing`/`## Verification` 章节,用于描述现在锁定该行为的内容),并用实际交付的内容替换计划——即 [implemented/AGENTS.md](implemented/AGENTS.md) 所要求的改写,使之机械化。`proposed/` → `rejected/` 仅在 `Status:` 行添加原因并冻结文件。 ### 中文对侧文件 -`.zh.md` 对侧文件按 [i18n 契约](../i18n/README.md)逐章节镜像其英文兄弟文件的结构;机器检查的头部标记(`# RFC: ` 和 `Status:` 行)保持英文原样不变。格式门禁跳过 `.zh.md` 文件——配对门禁负责它们的一致性。 +`.zh.md` 对侧文件按 [i18n 契约](../i18n/README.md)逐章节镜像其英文兄弟文件的结构;机器检查的头部标记(`# RFC: ` 和 `Status:` 行)保持英文原样不翻译。格式门禁跳过 `.zh.md` 文件——配对门禁负责它们的一致性。 From 8ea5cdd894d9db4680f83644b214faebd9df535d Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Wed, 22 Jul 2026 03:07:36 -0700 Subject: [PATCH 074/368] docs(i18n): re-translate RFC batch with the prompt-v4 pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 146 篇 RFC 译文按 v4 基线(#348)重出:v4 模板+术语表、金标 few-shot、三段协议、切换行后处理;全量机械核对零异常(一处 task id 术语违规已修)。三篇超长 RFC(code-mode 已入,web-seam/ agent-scope/sandbox/cds-core 仍在长文档通道产出)随后补。 --- ...6-06-11-content-block-vocabulary.i18n.yaml | 2 +- .../2026-06-11-content-block-vocabulary.zh.md | 18 +-- .../2026-06-11-custom-schema-dsl.i18n.yaml | 2 +- .../2026-06-11-custom-schema-dsl.zh.md | 12 +- ...ev-invariants-over-deep-readonly.i18n.yaml | 2 +- ...11-dev-invariants-over-deep-readonly.zh.md | 34 +++--- ...026-06-11-event-sourced-sessions.i18n.yaml | 2 +- .../2026-06-11-event-sourced-sessions.zh.md | 18 +-- ...06-11-microkernel-event-taxonomy.i18n.yaml | 2 +- ...026-06-11-microkernel-event-taxonomy.zh.md | 24 ++-- ...026-06-11-runtime-arg-validation.i18n.yaml | 2 +- .../2026-06-11-runtime-arg-validation.zh.md | 12 +- ...-06-11-structured-error-taxonomy.i18n.yaml | 2 +- ...2026-06-11-structured-error-taxonomy.zh.md | 16 +-- ...-tool-schemas-in-prompt-assembly.i18n.yaml | 2 +- ...6-11-tool-schemas-in-prompt-assembly.zh.md | 12 +- .../2026-06-13-capability-seams.i18n.yaml | 2 +- .../2026-06-13-capability-seams.zh.md | 28 ++--- .../2026-06-13-twin-llm-adapters.i18n.yaml | 2 +- .../2026-06-13-twin-llm-adapters.zh.md | 18 +-- .../2026-06-14-session-persistence.i18n.yaml | 2 +- .../2026-06-14-session-persistence.zh.md | 28 ++--- ...6-06-15-turn-enclosure-invariant.i18n.yaml | 2 +- .../2026-06-15-turn-enclosure-invariant.zh.md | 36 +++--- ...06-17-filesystem-capability-seam.i18n.yaml | 2 +- ...026-06-17-filesystem-capability-seam.zh.md | 106 ++++++++-------- ...nt-lifecycle-and-ownership-seams.i18n.yaml | 2 +- ...-agent-lifecycle-and-ownership-seams.zh.md | 26 ++-- .../2026-06-18-session-surface.i18n.yaml | 2 +- .../2026-06-18-session-surface.zh.md | 46 +++---- ...ed-persistence-write-coordinator.i18n.yaml | 2 +- ...shared-persistence-write-coordinator.zh.md | 38 +++--- .../2026-06-20-branded-ids.i18n.yaml | 2 +- .../architecture/2026-06-20-branded-ids.zh.md | 46 +++---- ...-20-extract-example-app-packages.i18n.yaml | 2 +- ...6-06-20-extract-example-app-packages.zh.md | 52 ++++---- .../2026-06-20-package-hierarchy.i18n.yaml | 2 +- .../2026-06-20-package-hierarchy.zh.md | 38 +++--- ...andatory-app-attribution-headers.i18n.yaml | 2 +- ...21-mandatory-app-attribution-headers.zh.md | 74 ++++++------ ...06-26-file-context-as-event-gate.i18n.yaml | 2 +- ...026-06-26-file-context-as-event-gate.zh.md | 92 +++++++------- ...stdin-env-trusted-plugin-surface.i18n.yaml | 2 +- ...ash-stdin-env-trusted-plugin-surface.zh.md | 22 ++-- ...026-06-30-event-domain-semantics.i18n.yaml | 2 +- .../2026-06-30-event-domain-semantics.zh.md | 28 ++--- .../2026-07-02-fs-per-session-cwd.i18n.yaml | 2 +- .../2026-07-02-fs-per-session-cwd.zh.md | 28 ++--- ...2-result-time-applied-hunk-diffs.i18n.yaml | 2 +- ...07-02-result-time-applied-hunk-diffs.zh.md | 46 +++---- ...6-07-02-tool-render-intent-union.i18n.yaml | 2 +- .../2026-07-02-tool-render-intent-union.zh.md | 48 ++++---- ...ilesystem-directory-listing-seam.i18n.yaml | 2 +- ...03-filesystem-directory-listing-seam.zh.md | 44 +++---- ...bles-and-tool-guidance-ownership.i18n.yaml | 2 +- ...ariables-and-tool-guidance-ownership.zh.md | 64 +++++----- ...6-07-05-reconstructable-requests.i18n.yaml | 2 +- .../2026-07-05-reconstructable-requests.zh.md | 46 +++---- ...bagent-provider-lifecycle-events.i18n.yaml | 2 +- ...5-subagent-provider-lifecycle-events.zh.md | 30 ++--- ...6-07-06-timeout-deadline-library.i18n.yaml | 2 +- .../2026-07-06-timeout-deadline-library.zh.md | 52 ++++---- ...6-07-07-tool-call-timeout-policy.i18n.yaml | 2 +- .../2026-07-07-tool-call-timeout-policy.zh.md | 66 +++++----- .../2026-07-08-agent-scope-contexts.i18n.yaml | 2 +- .../2026-07-08-agent-scope-contexts.zh.md | 64 +++++----- ...-06-14-acp-agent-client-protocol.i18n.yaml | 2 +- ...2026-06-14-acp-agent-client-protocol.zh.md | 46 +++---- .../2026-06-14-acp-multi-session.i18n.yaml | 2 +- .../2026-06-14-acp-multi-session.zh.md | 30 ++--- .../feature/2026-06-15-code-mode.i18n.yaml | 2 +- .../feature/2026-06-15-code-mode.zh.md | 114 +++++++++--------- ...26-06-17-filesystem-tool-schemas.i18n.yaml | 2 +- .../2026-06-17-filesystem-tool-schemas.zh.md | 74 ++++++------ ...-acp-terminal-and-tool-rendering.i18n.yaml | 2 +- ...6-18-acp-terminal-and-tool-rendering.zh.md | 40 +++--- ...06-18-compaction-capability-seam.i18n.yaml | 2 +- ...026-06-18-compaction-capability-seam.zh.md | 90 +++++++------- ...6-06-21-subagent-capability-seam.i18n.yaml | 2 +- .../2026-06-21-subagent-capability-seam.zh.md | 54 ++++----- .../2026-06-22-acp-subagent-backend.i18n.yaml | 2 +- .../2026-06-22-acp-subagent-backend.zh.md | 36 +++--- .../2026-06-25-ask-user-question.i18n.yaml | 2 +- .../2026-06-25-ask-user-question.zh.md | 34 +++--- .../2026-06-29-todo-write-tool.i18n.yaml | 2 +- .../feature/2026-06-29-todo-write-tool.zh.md | 48 ++++---- .../feature/2026-06-30-hook-bridges.i18n.yaml | 2 +- .../feature/2026-06-30-hook-bridges.zh.md | 50 ++++---- .../2026-06-30-hook-protocol-lib.i18n.yaml | 2 +- .../2026-06-30-hook-protocol-lib.zh.md | 24 ++-- .../2026-06-30-interception-seams.i18n.yaml | 2 +- .../2026-06-30-interception-seams.zh.md | 44 +++---- ...026-06-30-session-store-fork-api.i18n.yaml | 2 +- .../2026-06-30-session-store-fork-api.zh.md | 26 ++-- ...26-06-30-subagent-observe-enrich.i18n.yaml | 2 +- .../2026-06-30-subagent-observe-enrich.zh.md | 20 +-- .../2026-07-05-dynamic-workflows.i18n.yaml | 2 +- .../2026-07-05-dynamic-workflows.zh.md | 70 +++++------ .../feature/2026-07-05-skill-system.i18n.yaml | 2 +- .../feature/2026-07-05-skill-system.zh.md | 40 +++--- .../2026-07-06-approval-seam.i18n.yaml | 2 +- .../feature/2026-07-06-approval-seam.zh.md | 92 +++++++------- .../2026-07-06-explicit-tool-order.i18n.yaml | 2 +- .../2026-07-06-explicit-tool-order.zh.md | 52 ++++---- .../2026-07-07-mcp-client-plugin.i18n.yaml | 2 +- .../2026-07-07-mcp-client-plugin.zh.md | 106 ++++++++-------- .../2026-07-07-session-prefix.i18n.yaml | 2 +- .../feature/2026-07-07-session-prefix.zh.md | 40 +++--- .../2026-07-08-repeat-tool-guard.i18n.yaml | 2 +- .../2026-07-08-repeat-tool-guard.zh.md | 56 ++++----- ...-self-referential-cordis-toolset.i18n.yaml | 2 +- ...7-08-self-referential-cordis-toolset.zh.md | 66 +++++----- ...2026-07-10-session-query-service.i18n.yaml | 2 +- .../2026-07-10-session-query-service.zh.md | 32 ++--- ...nt-persona-tool-filter-and-depth.i18n.yaml | 2 +- ...bagent-persona-tool-filter-and-depth.zh.md | 78 ++++++------ .../2026-06-11-doc-sync-enforcement.i18n.yaml | 2 +- .../2026-06-11-doc-sync-enforcement.zh.md | 26 ++-- .../2026-06-11-quality-gates.i18n.yaml | 2 +- .../process/2026-06-11-quality-gates.zh.md | 24 ++-- .../2026-06-11-tsdown-over-dumble.i18n.yaml | 2 +- .../2026-06-11-tsdown-over-dumble.zh.md | 26 ++-- ...26-06-11-vendor-cordis-as-source.i18n.yaml | 2 +- .../2026-06-11-vendor-cordis-as-source.zh.md | 24 ++-- .../2026-06-16-pnpm-over-yarn.i18n.yaml | 2 +- .../process/2026-06-16-pnpm-over-yarn.zh.md | 40 +++--- .../2026-06-17-ts-build-config.i18n.yaml | 2 +- .../process/2026-06-17-ts-build-config.zh.md | 65 +++++----- ...6-06-18-markdown-cross-link-lint.i18n.yaml | 2 +- .../2026-06-18-markdown-cross-link-lint.zh.md | 28 ++--- ...-20-core-data-structures-catalog.i18n.yaml | 2 +- ...6-06-20-core-data-structures-catalog.zh.md | 48 ++++---- ...6-06-20-generated-cordis-catalog.i18n.yaml | 2 +- .../2026-06-20-generated-cordis-catalog.zh.md | 36 +++--- .../2026-06-20-rfc-classification.i18n.yaml | 2 +- .../2026-06-20-rfc-classification.zh.md | 42 +++---- .../2026-07-02-tool-schema-catalog.i18n.yaml | 2 +- .../2026-07-02-tool-schema-catalog.zh.md | 46 +++---- ...-07-03-documentation-graph-atlas.i18n.yaml | 2 +- ...2026-07-03-documentation-graph-atlas.zh.md | 70 +++++------ ...4-cordis-jsdoc-completeness-gate.i18n.yaml | 2 +- ...07-04-cordis-jsdoc-completeness-gate.zh.md | 40 +++--- ...2026-07-04-doc-tiers-and-budgets.i18n.yaml | 2 +- .../2026-07-04-doc-tiers-and-budgets.zh.md | 26 ++-- ...-07-04-generate-rfc-index-tables.i18n.yaml | 2 +- ...2026-07-04-generate-rfc-index-tables.zh.md | 22 ++-- ...26-07-04-persistence-log-catalog.i18n.yaml | 2 +- .../2026-07-04-persistence-log-catalog.zh.md | 26 ++-- .../2026-07-05-uniform-rfc-format.i18n.yaml | 2 +- .../2026-07-05-uniform-rfc-format.zh.md | 30 ++--- ...-07-06-export-surface-jsdoc-gate.i18n.yaml | 2 +- ...2026-07-06-export-surface-jsdoc-gate.zh.md | 48 ++++---- ...6-07-06-generated-config-catalog.i18n.yaml | 2 +- .../2026-07-06-generated-config-catalog.zh.md | 34 +++--- .../2026-07-06-node-engine-floor.i18n.yaml | 2 +- .../2026-07-06-node-engine-floor.zh.md | 36 +++--- ...6-07-06-parallel-github-ci-gates.i18n.yaml | 2 +- .../2026-07-06-parallel-github-ci-gates.zh.md | 34 +++--- ...26-07-06-parallel-pre-push-gates.i18n.yaml | 2 +- .../2026-07-06-parallel-pre-push-gates.zh.md | 36 +++--- ...10-readme-known-limitations-gate.i18n.yaml | 2 +- ...-07-10-readme-known-limitations-gate.zh.md | 26 ++-- ...ackage-model-experience-contract.i18n.yaml | 2 +- ...12-package-model-experience-contract.zh.md | 32 ++--- ...-19-drop-mutable-session-summary.i18n.yaml | 2 +- ...6-06-19-drop-mutable-session-summary.zh.md | 22 ++-- ...llapse-trace-only-session-events.i18n.yaml | 2 +- ...0-collapse-trace-only-session-events.zh.md | 28 ++--- ...onsumed-llm-adapter-change-event.i18n.yaml | 2 +- ...-unconsumed-llm-adapter-change-event.zh.md | 22 ++-- ...nconsumed-llm-assembled-surfaces.i18n.yaml | 2 +- ...op-unconsumed-llm-assembled-surfaces.zh.md | 26 ++-- ...26-06-20-prune-dead-seam-methods.i18n.yaml | 2 +- .../2026-06-20-prune-dead-seam-methods.zh.md | 24 ++-- ...-06-20-public-agent-stop-surface.i18n.yaml | 2 +- ...2026-06-20-public-agent-stop-surface.zh.md | 24 ++-- ...ove-agent-boundary-mirror-events.i18n.yaml | 2 +- ...-remove-agent-boundary-mirror-events.zh.md | 22 ++-- .../2026-06-26-fsspec-style-fs-seam.i18n.yaml | 2 +- .../2026-06-26-fsspec-style-fs-seam.zh.md | 78 ++++++------ ...07-02-remove-stream-chunk-mirror.i18n.yaml | 2 +- ...026-07-02-remove-stream-chunk-mirror.zh.md | 22 ++-- ...6-07-04-drop-image-content-block.i18n.yaml | 2 +- .../2026-07-04-drop-image-content-block.zh.md | 16 +-- ...6-07-04-drop-inert-request-knobs.i18n.yaml | 2 +- .../2026-07-04-drop-inert-request-knobs.zh.md | 22 ++-- ...consumed-web-observation-surface.i18n.yaml | 2 +- ...p-unconsumed-web-observation-surface.zh.md | 20 +-- .../2026-07-04-fold-stdio-ui-helper.i18n.yaml | 2 +- .../2026-07-04-fold-stdio-ui-helper.zh.md | 18 +-- ...producerless-vocabulary-variants.i18n.yaml | 2 +- ...une-producerless-vocabulary-variants.zh.md | 24 ++-- ...7-04-prune-write-only-fs-surface.i18n.yaml | 2 +- ...26-07-04-prune-write-only-fs-surface.zh.md | 24 ++-- ...-04-remove-agent-steering-mirror.i18n.yaml | 2 +- ...6-07-04-remove-agent-steering-mirror.zh.md | 18 +-- ...26-07-04-share-app-bin-boot-glue.i18n.yaml | 2 +- .../2026-07-04-share-app-bin-boot-glue.zh.md | 22 ++-- ...4-tighten-hook-protocol-contract.i18n.yaml | 2 +- ...07-04-tighten-hook-protocol-contract.zh.md | 20 +-- ...m-acp-bridge-unreachable-surface.i18n.yaml | 2 +- ...-trim-acp-bridge-unreachable-surface.zh.md | 18 +-- ...unconsumed-skill-provider-events.i18n.yaml | 2 +- ...rop-unconsumed-skill-provider-events.zh.md | 20 +-- ...-12-prune-unused-web-seam-fields.i18n.yaml | 2 +- ...6-07-12-prune-unused-web-seam-fields.zh.md | 18 +-- ...026-06-11-property-based-testing.i18n.yaml | 2 +- .../2026-06-11-property-based-testing.zh.md | 22 ++-- .../2026-06-19-acp-snapshot-tests.i18n.yaml | 2 +- .../2026-06-19-acp-snapshot-tests.zh.md | 42 +++---- .../2026-06-19-real-api-e2e-ci.i18n.yaml | 2 +- .../testing/2026-06-19-real-api-e2e-ci.zh.md | 82 ++++++------- ...e-redundant-snapshot-log-goldens.i18n.yaml | 2 +- ...emove-redundant-snapshot-log-goldens.zh.md | 22 ++-- ...-fork-child-replay-seed-boundary.i18n.yaml | 2 +- ...6-22-fork-child-replay-seed-boundary.zh.md | 36 +++--- ...26-06-22-fork-snapshot-scenarios.i18n.yaml | 2 +- .../2026-06-22-fork-snapshot-scenarios.zh.md | 24 ++-- ...6-06-22-subagent-snapshot-replay.i18n.yaml | 2 +- .../2026-06-22-subagent-snapshot-replay.zh.md | 46 +++---- .../2026-07-04-hook-snapshot-matrix.i18n.yaml | 2 +- .../2026-07-04-hook-snapshot-matrix.zh.md | 38 +++--- ...-single-source-acp-replay-config.i18n.yaml | 2 +- ...7-04-single-source-acp-replay-config.zh.md | 22 ++-- ...t-header-content-in-one-scenario.i18n.yaml | 2 +- ...quest-header-content-in-one-scenario.zh.md | 28 ++--- ...7-08-shared-acp-snapshot-package.i18n.yaml | 2 +- ...26-07-08-shared-acp-snapshot-package.zh.md | 34 +++--- .../2026-06-16-typed-event-schemas.i18n.yaml | 2 +- .../2026-06-16-typed-event-schemas.zh.md | 72 +++++------ ...eneric-long-running-tool-runtime.i18n.yaml | 2 +- ...20-generic-long-running-tool-runtime.zh.md | 34 +++--- ...026-06-30-pre-tool-input-rewrite.i18n.yaml | 2 +- .../2026-06-30-pre-tool-input-rewrite.zh.md | 46 +++---- ...code-and-codex-subagent-backends.i18n.yaml | 2 +- ...ude-code-and-codex-subagent-backends.zh.md | 68 +++++------ ...-07-08-interactive-side-sessions.i18n.yaml | 2 +- ...2026-07-08-interactive-side-sessions.zh.md | 38 +++--- ...10-sqlite-session-query-provider.i18n.yaml | 2 +- ...-07-10-sqlite-session-query-provider.zh.md | 38 +++--- ...flow-progress-through-tool-calls.i18n.yaml | 2 +- ...workflow-progress-through-tool-calls.zh.md | 28 ++--- ...2026-06-11-api-extractor-reports.i18n.yaml | 2 +- .../2026-06-11-api-extractor-reports.zh.md | 14 +-- ...-06-11-architectural-conformance.i18n.yaml | 2 +- ...2026-06-11-architectural-conformance.zh.md | 16 +-- ...11-supply-chain-and-vendor-drift.i18n.yaml | 2 +- ...-06-11-supply-chain-and-vendor-drift.zh.md | 26 ++-- ...06-20-discover-package-inventory.i18n.yaml | 2 +- ...026-06-20-discover-package-inventory.zh.md | 26 ++-- ...06-20-unify-agent-and-session-id.i18n.yaml | 2 +- ...026-06-20-unify-agent-and-session-id.zh.md | 28 ++--- ...04-prune-dead-core-spine-surface.i18n.yaml | 2 +- ...-07-04-prune-dead-core-spine-surface.zh.md | 70 +++++------ ...plify-session-log-representation.i18n.yaml | 2 +- ...-simplify-session-log-representation.zh.md | 24 ++-- ...deterministic-and-stress-testing.i18n.yaml | 2 +- ...-11-deterministic-and-stress-testing.zh.md | 18 +-- .../2026-06-11-mutation-testing.i18n.yaml | 2 +- .../testing/2026-06-11-mutation-testing.zh.md | 22 ++-- ...-06-11-immutable-public-surfaces.i18n.yaml | 2 +- ...2026-06-11-immutable-public-surfaces.zh.md | 18 +-- ...-06-20-providerless-example-base.i18n.yaml | 2 +- ...2026-06-20-providerless-example-base.zh.md | 18 +-- ...ssembled-assistant-messages-only.i18n.yaml | 2 +- ...20-assembled-assistant-messages-only.zh.md | 24 ++-- ...2026-06-20-drop-acp-session-load.i18n.yaml | 2 +- .../2026-06-20-drop-acp-session-load.zh.md | 24 ++-- ...026-06-20-drop-acp-terminal-meta.i18n.yaml | 2 +- .../2026-06-20-drop-acp-terminal-meta.zh.md | 20 +-- ...-20-drop-bash-output-spill-files.i18n.yaml | 2 +- ...6-06-20-drop-bash-output-spill-files.zh.md | 16 +-- ...-20-drop-durable-step-boundaries.i18n.yaml | 2 +- ...6-06-20-drop-durable-step-boundaries.zh.md | 20 +-- ...6-20-drop-unused-session-lineage.i18n.yaml | 2 +- ...26-06-20-drop-unused-session-lineage.zh.md | 16 +-- ...ld-session-persistence-interface.i18n.yaml | 2 +- ...0-fold-session-persistence-interface.zh.md | 14 +-- ...026-06-20-generic-tool-rendering.i18n.yaml | 2 +- .../2026-06-20-generic-tool-rendering.zh.md | 18 +-- ...6-06-20-retire-mid-turn-steering.i18n.yaml | 2 +- .../2026-06-20-retire-mid-turn-steering.zh.md | 28 ++--- ...-06-20-single-session-acp-bridge.i18n.yaml | 2 +- ...2026-06-20-single-session-acp-bridge.zh.md | 14 +-- ...06-20-truncate-interrupted-turns.i18n.yaml | 2 +- ...026-06-20-truncate-interrupted-turns.zh.md | 26 ++-- ...nimplemented-subagent-vocabulary.i18n.yaml | 2 +- ...ne-unimplemented-subagent-vocabulary.zh.md | 30 ++--- ...apse-workflow-to-foreground-core.i18n.yaml | 2 +- ...collapse-workflow-to-foreground-core.zh.md | 28 ++--- ...ne-unused-skill-registry-surface.i18n.yaml | 2 +- ...-prune-unused-skill-registry-surface.zh.md | 22 ++-- 292 files changed, 2819 insertions(+), 2820 deletions(-) diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml index 67537fda94..7ddbc75586 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-content-block-vocabulary.md: 9414bda624fa6e5fc7e9b11b7a738d32b269af6b -2026-06-11-content-block-vocabulary.zh.md: 32308a5fe58f3a2e3c402982b7067811b9698218 +2026-06-11-content-block-vocabulary.zh.md: 764791cbef65c2031b8337af4f4cb6835e9d312a diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md index 32308a5fe5..764791cbef 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md @@ -1,4 +1,4 @@ -# RFC:由 dsh-llm 持有的提供方无关内容块词汇 +# RFC:由 dsh-llm 拥有的提供方无关内容块词汇 Status: implemented @@ -10,19 +10,19 @@ harness 需要一套统一的内部消息语言,供 agent loop(智能体循 ## 决策 -自行持有词汇:消息是类型化内容块(`text`、`reasoning`、`tool-call`、`tool-result`)的数组,其联合类型派生自可合并扩展的 `ContentBlockMap`,插件通过声明合并添加新的块类型。同一套可合并扩展映射模式也用于所有「字符串化」字段的类型定义(`MessageSource`、`FinishReason`、`TurnTrigger`、`TurnEndReason`)。流式输出是原始分片协议;`BlockAssembler` 是唯一的共享组装实现。适配器负责转换为各提供方的协议格式(wire format):映射成本留在适配器中,这正是它该待的地方。 +自主拥有词汇:消息是类型化内容块的数组(`text`、`reasoning`、`tool-call`、`tool-result`),其联合类型派生自可合并扩展的 `ContentBlockMap`,插件通过声明合并添加新的块类型。同一可合并扩展映射模式为所有「字符串化」字段提供类型(`MessageSource`、`FinishReason`、`TurnTrigger`、`TurnEndReason`)。流式输出采用原始分片协议;`BlockAssembler` 是唯一的共享组装实现。适配器负责转换为提供方的协议格式(wire format)——映射成本留在适配器中,正是它该在的地方。 -会话内上下文注入(`context/message`、`steering/message`)渲染为带标签的 user-role 信封(system-reminder 模式),而非引入新 role,因此适配器零负担。真实适配器验证已确认该渲染方式在当前 DeepSeek 行为下有效;如果未来某个提供方出现不匹配,应在该适配器内处理,而非引入新的规范 role。 +会话内上下文注入(`context/message`、`steering/message`)渲染为带标签的 user-role 信封(system-reminder 模式),而非引入新角色,因此适配器无需承担额外负担。实际适配器验证已确认此渲染方式符合当前 DeepSeek 的行为;如果未来某提供方出现不兼容,应在该适配器内处理,而非引入新的规范角色。 ## 曾考虑的替代方案 -- **镜像 DeepSeek/OpenAI chat-completions 的结构**:对第一个提供方零映射成本,但对富内容(推理(reasoning)、作为结构化块的工具结果)处理起来别扭。 -- **原样采用 Anthropic Messages 的块结构**:经过实战检验,但规范类型将镜像一个 harness 并非首要对接的第三方 API。 +- **镜像 DeepSeek/OpenAI chat-completions 结构**:对第一个提供方零映射成本,但对富内容(推理、结构化块形式的工具结果)处理不便。 +- **原样采用 Anthropic Messages 块结构**:经过实战检验,但规范类型将镜像一个 harness 并非首要对接的第三方 API。 ## 后果 - 推理(reasoning)在核心层有了归属,无需依赖提供方特有的结构。 -- 多模态块只有在适配器、UI 与上下文压缩(context compaction)三方协同支持时才会回归;见[移除 image 内容块 RFC](../simplification/2026-07-04-drop-image-content-block.md)。 -- 缓存提示与 assistant prefill 在有实际适配器能兑现之前保持缺席;见[无生产者的变体](../simplification/2026-07-04-prune-producerless-vocabulary-variants.md)与[惰性请求旋钮](../simplification/2026-07-04-drop-inert-request-knobs.md) RFC。 -- 每个适配器都要承担翻译成本;首批真实适配器已验证了流式输出协议,后续新适配器应继续在适配器本地测试中证明其提供方特有的映射。 -- 跨包边界的 ID 使用品牌类型(`CallId`、`SessionId`、`AgentId`):零运行时成本的名义类型。 +- 多模态块只有在适配器、UI 和上下文压缩(context compaction)三方协同支持后才会回归;见 [drop-image RFC](../simplification/2026-07-04-drop-image-content-block.md)。 +- 缓存提示与 assistant prefill 在有实际适配器能兑现之前保持缺席;见 [producer-less variants](../simplification/2026-07-04-prune-producerless-vocabulary-variants.md) 与 [inert request knobs](../simplification/2026-07-04-drop-inert-request-knobs.md) RFC。 +- 每个适配器都需承担翻译成本;首批真实适配器已验证了流式输出协议,新适配器应继续在适配器本地测试中验证其提供方特有的映射。 +- 跨包(package)边界的 ID 使用品牌类型(`CallId`、`SessionId`、`AgentId`)——零运行时开销的名义类型。 diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml index 5046fe3a38..6e7b3a2125 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-custom-schema-dsl.md: 4c4d572b15d5e474e00e99fc5e7dd89240251c63 -2026-06-11-custom-schema-dsl.zh.md: 31af594846b6b1bc8ce983b7b9d4ddd956a560ff +2026-06-11-custom-schema-dsl.zh.md: eca0428d46ba3b3a4beac0cf9e8f02a9fa198388 diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md index 31af594846..eca0428d46 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md @@ -1,4 +1,4 @@ -# RFC:使用自定义类型化工具 schema DSL 替代 schemastery +# RFC:使用自定义类型化 tool-schema DSL 替代 schemastery Status: implemented @@ -6,18 +6,18 @@ Status: implemented ## 问题 -工具参数必须以标准 JSON Schema 的形式传递给模型,同时让工具作者在 `execute(args)` 中获得类型推导而无需类型断言。schemastery 已用于插件配置,但工具作者 API 需要的是逐属性的 `required: true` 布尔值,而非 JSON Schema 的独立 `required` 数组。 +工具参数必须以标准 JSON Schema 形式到达模型,同时让工具作者在 `execute(args)` 中获得类型化的参数而无需类型断言。Schemastery 已用于插件配置,但工具作者 API 需要逐属性的 `required: true` 布尔值,而非 JSON Schema 的独立 `required` 数组。 ## 决策 -在 dsh-tools 中实现一个小型自定义 DSL:`SchemaSpec`(逐属性规格,带 `required: true` 布尔值);类型层面的 `InferArgs<S>` 将规格映射为参数类型(required 键为必选,其余通过 `?` 真正可选);运行时的 `schemaSpecToJsonSchema()` 转换器;以及将它们串联起来的 `defineTool()`。`ToolRegistry.register()` 仍接受原始 JSON Schema 的 `ToolDefinition`——MCP 来源的工具就是这样注册的。 +在 dsh-tools 中实现一个小型自定义 DSL:`SchemaSpec`(逐属性规格,带 `required: true` 布尔值);类型层面的 `InferArgs<S>` 将规格映射为参数类型(required 键为必选,其余通过 `?` 标记为真正可选);运行时的 `schemaSpecToJsonSchema()` 转换器;以及将三者串联的 `defineTool()`。`ToolRegistry.register()` 仍然接受原始 JSON Schema 的 `ToolDefinition`——MCP 来源的工具正是以此方式注册。 ## 曾考虑的替代方案 -**schemastery**(已 vendor、用于插件 Config)经评估后被否决:它面向的是基于 StandardSchema 的校验/转换,而非 JSON Schema *生成*,因此会增加间接层却无法干净地产出协议格式(wire format)。 +**Schemastery**(已作为 vendor 引入,用于插件 Config)经评估后被否决:它面向的是基于 StandardSchema 的校验/转换,而非 JSON Schema **生成**,因此会增加间接层却无法干净地产出协议格式(wire format)。 ## 后果 - 第一方工具作者获得零类型断言的类型化参数;类型体操的成本留在核心包内部(符合 AGENTS.md 的类型安全策略)。 -- DSL 刻意保持小巧(string/number/boolean/object/array、enum、default、嵌套 properties/items)。相对完整 JSON Schema 的缺口(union、format、约束)在真实工具提出需求之前暂不填补。 -- `InferArgs` 映射在一次早期可选性 bug 之后已有类型层面的回归测试。 +- DSL 有意保持小巧(string/number/boolean/object/array、enum、default、嵌套 properties/items)。相对完整 JSON Schema 的缺口(union、format、constraint)在真实工具提出需求之前暂不补齐。 +- `InferArgs` 映射在类型层面有回归测试,源于早期一个可选性 bug。 diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml index ef2f73d949..0758761505 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-dev-invariants-over-deep-readonly.md: dc89b5b66d02bde2f4fe2794e04b76ecdeac62ae -2026-06-11-dev-invariants-over-deep-readonly.zh.md: 02beb323df84cd442611f0c52b3c56734d6d0554 +2026-06-11-dev-invariants-over-deep-readonly.zh.md: 2c3c9e221b42f4b45216d09e825a41b1be3bcee9 diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md index 02beb323df..2c3c9e221b 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md @@ -1,4 +1,4 @@ -# RFC:源头拥有的会话不可变性与开发模式不变式 +# RFC:源端拥有的会话不可变性与开发模式不变式 Status: implemented @@ -6,55 +6,55 @@ Status: implemented ## 问题 -会话日志需要两种不同的保护:对每条已存储事实的不可变所有权,以及对跨时间和服务 seam 的事实间关系的检查。如果将二者混为一体放进一个可选的开发插件,生产环境的历史记录将失去保护;如果试图通过 TypeScript readonly 类型同时表达两者,既无法建立运行时边界,也无法描述关系规则。 +会话日志需要两种不同的保护:对每条已存储事实的不可变所有权,以及对跨时间和服务 seam 的事实之间关系的检查。如果将二者混为一个可选的开发插件,生产环境的历史记录将失去保护;如果试图通过 TypeScript readonly 类型同时表达两者,既无法建立运行时边界,也无法描述关系规则。 -会话日志是回放、请求重建、持久化和用户可见历史的持久真源。会话包以外的代码必须能够检视该历史,但不能保留一个可以事后改写它的引用;从调用方接收的输入也不能继续连接到调用方拥有的可变对象上。 +会话日志是回放、请求重建、持久化与用户可见历史的持久真源。会话包(package)外部的代码必须能检视历史,但不能保留一个可在之后改写历史的引用;从调用方接受的输入也不能继续连接到调用方拥有的可变对象。 单个值的不可变性只是契约的一半。一份日志可以包含完全不可变的记录,但其序列、轮次/步骤嵌套、工具调用配对、作用域分发或重建的模型请求是错误的。这些规则涉及多条记录或多个服务,无法通过冻结单个对象来建立。 -TypeScript readonly 类型不构成充分的运行时边界。它们在程序运行时消失,一次类型转换即可绕过,而递归的 `DeepReadonly<T>` 会扩散到每个日志和消息消费方,尽管某些下游请求处理 API 有意使用可变值。 +TypeScript readonly 类型不是充分的运行时边界。它们在程序运行时消失,类型转换可以绕过它们,而递归的 `DeepReadonly<T>` 会扩散到每个日志和消息消费方,尽管某些下游请求处理 API 有意使用可变值。 ## 决策 -职责在一个始终开启的存储边界与可选的开发断言之间分离。 +职责在始终启用的存储边界与可选的开发断言之间分离。 ### Session 拥有不可变历史 -`Session` 仅在一次递归遍历完成无损 JSON 快照后才接受事件。该遍历拒绝不支持的值,并产出进入日志的确切脱离记录,因此校验和存储不可能从有状态的 getter 观察到不同的值,也不会保留调用方拥有的嵌套引用。 +`Session` 仅在一次递归遍历完成无损 JSON 快照的物化之后才接受事件。该遍历拒绝不支持的值,并产出进入日志的确切分离记录,因此验证与存储不会从有状态的 getter 观察到不同的值,也不会保留调用方拥有的嵌套引用。 -被接受的事件及其所有后代在发布前被深度冻结。`append()` 返回该拥有的冻结事件,`session/event` 观察者收到同一条记录,`session.events` 返回一份冻结的数组快照。先前返回的数组不会因后续 append 而增长。种子记录在构造成功前经过相同的校验、快照与冻结边界。 +被接受的事件及其所有后代在发布前被深度冻结。`append()` 返回该拥有的冻结事件,`session/event` 观察者接收同一记录,`session.events` 返回冻结的数组快照。先前返回的数组不会因后续 append 而增长。种子记录在构造成功前经过相同的验证、快照与冻结边界。 -这一保证属于 `Session` 而非可选的监听器,因为每种组合都依赖可信的历史。无论是否注册了开发支持插件,生产部署、聚焦测试或自定义嵌入都获得相同的存储语义。 +此保证属于 `Session` 而非可选监听器,因为每种组合都依赖可信的历史。无论是否注册了开发支持插件,生产部署、聚焦测试或自定义嵌入都获得相同的存储语义。 -### 派生请求保持脱离 +### 派生请求保持分离 -`deriveMessages()` 将已记录的表面事件投影为脱离的、深度冻结的 `Message` 对象,并返回一份新的数组快照。请求组装因此可以将派生历史与其他输入组合,而不会暴露一条回到日志的路径。缓存复用安全的不可变投影,而非为每次模型调用重新克隆完整历史。 +`deriveMessages()` 将已记录的表面事件投影为分离的、深度冻结的 `Message` 对象,并返回一份新的数组快照。因此请求组装可以将派生历史与其他输入组合,而不会暴露一条回到日志的路径。缓存复用安全的不可变投影,而非为每次模型调用重新克隆完整历史。 ### 不变式插件检查关系 -`dsh-invariants` 是一个纯监听的开发插件。它不冻结记录,没有配置;dispose 仅移除其断言。它检查需要追踪状态或观察另一个 seam 的规则,包括单调递增的序列号、轮次与步骤嵌套、工具调用/结果配对、合法的 agent 状态转换、主体正确的作用域分发,以及 agent loop 构建的请求与从其会话日志前缀重建的请求之间的等价性。 +`dsh-invariants` 是一个纯监听器的开发插件。它不冻结记录,没有配置;dispose(资源释放)仅移除其断言。它检查需要跟踪状态或观察另一个 seam 的规则,包括单调递增的序列号、轮次与步骤嵌套、工具调用/结果配对、合法的 agent(智能体)状态转换、主体正确的作用域分发,以及循环构建的请求与从其会话日志前缀重建的请求之间的等价性。 -当插件附加到已有或已播种的会话时,它回放不可变日志以重建追踪状态。这使得在轮次中间进行热重载是安全的,同时不赋予插件对会话存储的所有权。 +当插件附加到已有或已播种的会话时,它回放不可变日志以重建跟踪状态。这使得在轮次中途热重载是安全的,同时不赋予插件对会话存储的所有权。 ## 曾考虑的替代方案 ### 全面的 deep-readonly 类型 -[被否决的不可变公开表面提案](../../rejected/architecture/2026-06-11-immutable-public-surfaces.md)会在公开的日志和消息表面全面应用递归 readonly 类型。这能提供编辑器反馈,但不能提供运行时保证:TypeScript 类型在运行时被擦除,插件代码可以通过类型转换绕过。它还会将 readonly 类型推入有意进行修改的消费方。在 `Session` 边界处的运行时所有权保护所有调用方,无需这种类型传播。 +[被否决的不可变公共表面提案](../../rejected/architecture/2026-06-11-immutable-public-surfaces.md)会在公共日志和消息表面上应用递归 readonly 类型。这能提供编辑器反馈,但无法提供运行时保证:TypeScript 类型在运行时被擦除,插件代码可以通过类型转换绕过。它还会将 readonly 类型推入有意进行修改的消费方。在 `Session` 边界处的运行时所有权保护所有调用方,无需这种类型传播。 ### 仅在开发模式冻结 -仅在安装了不变式插件时才冻结历史,会使核心保证依赖于组合方式。代码可能通过开发测试,却在生产环境或省略了该插件的聚焦组合中破坏历史。因此存储不可变性始终开启,而更昂贵的关系检查保持为可选的开发支持。 +仅当不变式插件安装时才冻结历史,会使核心保证依赖于组合方式。代码可能通过开发测试,却在生产环境或省略了该插件的聚焦组合中破坏历史。因此存储不可变性始终启用,而开销更大的关系检查则保持为可选的开发支持。 ### 仅在派生消息时克隆 -脱离 `deriveMessages()` 会保护最常见的请求路径,但 `session.events` 的其他读者、append 返回值和会话事件观察者仍能修改持久历史。日志必须保护自身的边界;派生投影是额外的隔离边界,不是替代品。 +分离 `deriveMessages()` 能保护最常见的请求路径,但 `session.events` 的其他读取者、append 返回值和会话事件观察者仍能修改持久历史。日志必须保护自身的边界;派生投影是额外的隔离边界,而非替代品。 ## 后果 -- 每条被接受的实时或种子会话事件在任何观察者收到之前,都已从调用方拥有的输入中脱离并深度不可变。 +- 每个被接受的实时或种子会话事件在任何观察者接收之前,都已从调用方拥有的输入中分离并深度不可变。 - `session.events` 暴露稳定的不可变快照,而非私有的增长数组。 - 请求侧的修改无法通过派生消息触及已存储的历史。 - 开发构建可以启用关系断言而不改变存储行为;dispose 或省略该插件不会削弱日志不可变性。 - `dsh-invariants` 没有 `Config` 表面,因为它没有可调节的行为。 -- 运行时边界在每条被接受的事件上承担一次递归快照与冻结的开销;后续读者和缓存投影复用已拥有的不可变记录。 +- 运行时边界对每个被接受的事件产生一次递归快照与冻结的开销;后续读取者和缓存投影复用已拥有的不可变记录。 diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml index 00e6dc9181..e7645f5f8d 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-event-sourced-sessions.md: 04ff974826ffbc9052c7eb9f5794bc16557241f9 -2026-06-11-event-sourced-sessions.zh.md: a3fec18445673bc2368333413f9802f9822b9c89 +2026-06-11-event-sourced-sessions.zh.md: 12d6aedcc32b4d93f0dbe010854bcd3a0721703f diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md index a3fec18445..12d6aedcc3 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md @@ -1,28 +1,28 @@ # RFC:事件溯源的会话与派生消息历史 -Status: implemented - [English](2026-06-11-event-sourced-sessions.md) | 中文 +Status: implemented + ## 问题 -MVP 要求严格的基于事件的 trace、logging 系统,session 完全可回放。 +MVP 要求严格的基于事件的追踪,以及完全可回放的会话(严格的基于事件的 trace、logging 系统,session 完全可回放)。 ## 决策 -`Session` 是一份仅追加的、类型化的 `SessionEvent` 日志,是唯一的真源。LLM(大语言模型)消息历史从日志*派生*(`deriveMessages()`);原始流分片被记入日志以保证 token 级别的回放保真度,而组装后的 `assistant/message` 事件才是派生的权威来源。回放/fork = 用已有日志初始化一个新会话。 +`Session` 是一份仅追加的、类型化的 `SessionEvent` 日志,是唯一的真源。LLM(大语言模型)消息历史从日志*派生*(`deriveMessages()`);原始流分片被记录以保证 token 级别的回放保真度,而组装后的 `assistant/message` 事件才是派生的权威依据。回放/fork = 用已有日志初始化一个新会话。 -追加操作是同步的(热路径从不阻塞在 I/O 上);`session/event` 是同步通知;持久化插件在后台缓冲写入,并在每个轮次结束时触发的 `session/flush` 检查点处等待排空。 +追加操作是同步的(热路径从不阻塞于 I/O);`session/event` 是同步通知;持久化插件在后台缓冲写入,并在每个轮次结束时触发的 `session/flush` 检查点处等待排空。 顺序契约:agent loop(智能体循环)先追加到会话,再发出对应的 Cordis 事件;`agent/step-result` waterfall(瀑布式事件)在 `assistant/message` 追加之前运行,因此日志记录的是工具调度实际使用的消息。回归测试固定了这一顺序。 ## 曾考虑的替代方案 -**可变消息数组 + 事件作为通知发出**:更简单,但状态与日志可能分歧;采用事件溯源后,日志本身就是状态,分歧在结构上不可能发生。 +**可变消息数组 + 事件仅作通知发出**:更简单,但状态与日志可能分歧;采用事件溯源后,日志本身即是状态,分歧在结构上不可能发生。 ## 后果 -- 回放、trace 与遥测在结构上得到保证,而非事后附加。 -- 持久化仍是插件关注点;内存存储随 dsh-session 一起发布。 +- 回放、追踪与遥测在结构上得到保证,而非事后附加。 +- 持久化仍是插件关注点;内存存储随 dsh-session 一起提供。 - 事件词汇可通过合并扩展(插件可添加如压缩(compaction)事件);[会话持久化](2026-06-14-session-persistence.md)在日志变为持久后冻结了其形状。 -- 派生成本随日志长度增长——压缩(未来插件)是预期的缓解手段,而非日志变更。 +- 派生成本随日志长度增长,压缩(未来插件)是预期的缓解手段,而非日志变更。 diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml index 00320a6991..8634a86f36 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-microkernel-event-taxonomy.md: c66968257a5a6304f187ccb5b9a162aa143e608d -2026-06-11-microkernel-event-taxonomy.zh.md: 86750f6ece488e735f2c14f759db7c9eef360828 +2026-06-11-microkernel-event-taxonomy.zh.md: 7becf5872aee16fe21b4acbbc61920ed91c40f44 diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md index 86750f6ece..7becf5872a 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md @@ -6,26 +6,26 @@ Status: implemented ## 问题 -产品原则是「一切皆插件」:钩子、/goal、/loop、动态工作流、上下文压缩(context compaction)、沙箱、权限、UI、持久化、MCP、skill(技能)都必须能以插件形式编写,而无需修改核心。 +产品原则是「一切皆插件」:钩子、/goal、/loop、动态工作流、上下文压缩(context compaction)、沙箱、权限、UI、持久化、MCP、skill(技能)都必须能以插件形式编写,无需修改核心。 ## 决策 -纯 Cordis 事件分类体系(taxonomy)。循环的扩展 seam 是带有明确分发模式的类型化事件: +纯 Cordis 事件分类体系。agent loop(智能体循环)的扩展 seam 是带类型的事件,具有明确的分发模式: -- **waterfall(瀑布式事件)**(around-middleware):插件可以变换、否决或包装:`agent/prompt-submit`、`agent/request`、`agent/step-result`、`agent/turn-continuation`、`tools/pre-execute`、`tools/execute`、`tools/post-execute`、`llm/stream`、`system-prompt/assemble`。 -- **serial**(按监听器顺序依次 await;bail 值会阻止后续监听器):用于有序检查点。所有 `agent/pre-step` 监听器在全部弃权时都会运行,而 `agent/turn-stop` 返回的第一个 stop 值即为最终的终止决策。 -- **parallel**(await 扇出):每个监听器都必须获得独立执行机会:`session/flush` 持久性检查点。 -- **emit**(同步 fire-and-forget):用于通知:轮次/步骤边界、流式分片、生命周期、错误,以及包含不可变 `tools/result` 观测值的事件。 +- **waterfall(瀑布式事件)**(around-middleware):插件可变换、否决或包装:`agent/prompt-submit`、`agent/request`、`agent/step-result`、`agent/turn-continuation`、`tools/pre-execute`、`tools/execute`、`tools/post-execute`、`llm/stream`、`system-prompt/assemble`。 +- **serial**(按监听器顺序依次 await;bail 值会阻止后续监听器执行):用于有序检查点。所有 `agent/pre-step` 监听器在全部弃权时才继续运行,而 `agent/turn-stop` 返回的第一个 stop 值即为最终的终止决策。 +- **parallel**(await 扇出):每个监听器都必须获得独立执行的机会:`session/flush` 持久性检查点。 +- **emit**(同步 fire-and-forget):用于通知:轮次/步骤边界、流分片、生命周期、错误,以及包含不可变 `tools/result` 观测的事件。 -事件词汇定义在接口包中(dsh-agent 声明 agent/* 事件);`@deepseek-ai/dsh-agent-loop` 是唯一的具体循环插件,且本身可替换——它之外的任何代码都不得依赖它。 +事件词汇定义在接口包中(dsh-agent 声明 agent/* 事件);`@deepseek-ai/dsh-agent-loop` 是唯一的具体循环插件,且自身可替换——外部不得依赖它。 ## 曾考虑的替代方案 -**专用中间件栈(koa-compose 风格)** 与 **插件插入其中的显式阶段状态机**:两者都需要重新实现分发、dispose(资源释放)和重载语义,而 Cordis 原生事件系统已经提供了这些;作为 Cordis effect,监听器天然获得 HMR(热模块替换)和 dispose 能力。 +**专用中间件栈(koa-compose 风格)** 与**显式阶段状态机(插件向其中插入阶段)**:两者都需要重新实现 Cordis 原生事件系统已提供的分发、dispose(资源释放)与重载语义;作为 Cordis effect,监听器天然获得 HMR(热模块替换)与 dispose 能力。 ## 后果 -- 每个 MVP 功能都映射到一个监听器([功能→机制映射](../../../cookbook/extension-cookbook.md#the-feature--mechanism-map)是证明义务,保持最新)。 -- HMR 和 dispose 免费获得:监听器和注册都是 Cordis effect。 -- waterfall 语义(调用 `next()` 或短路)不直观,需要教学——已在 AGENTS.md 中记录,并由组合测试覆盖。 -- 循环必须具备防御性:插件异常在轮次级别被隔离,来自任何 seam 的 steering(中途引导)绝不会被搁置(有回归测试保障)。 +- 每个 MVP 功能都映射到一个监听器([功能→机制映射](../../../cookbook/extension-cookbook.md#the-feature--mechanism-map)是证明义务,保持更新)。 +- HMR 与 dispose 无需额外工作:监听器和注册均为 Cordis effect。 +- waterfall 语义(调用 `next()` 或短路)不直观,需要教学——在 AGENTS.md 中记录,并由组合测试覆盖。 +- 循环必须具备防御性:插件异常在轮次级别被隔离,任何 seam 发出的 steering(中途引导)永远不会被搁置(有回归测试保障)。 diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml index 8e7b36b58d..9ae6b5d602 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-runtime-arg-validation.md: 6da117643166d304bee1d368a314cc1602cac828 -2026-06-11-runtime-arg-validation.zh.md: fb67568da3bfc7f1f8fcc0429b6c68193e04693a +2026-06-11-runtime-arg-validation.zh.md: 5f41ff99a2d56f39ff8d61191d92dc782f163c82 diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md index fb67568da3..5f41ff99a2 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md @@ -6,19 +6,19 @@ Status: implemented ## 问题 -`defineTool`([自定义 schema DSL](2026-06-11-custom-schema-dsl.md))通过 `InferArgs<S>` 映射为工具作者提供了类型化的 `execute(args)`。但该类型只是编译期对一个运行时值的声明:这个值以模型生成的 JSON 形式到达,没有任何机制强制模型遵守 schema。因此,一次格式错误的调用(缺少必填键、声明为数字的位置传入字符串、枚举值超出集合)会以「仅有类型之名」的状态抵达 `execute`。工具体要么在错误形状上崩溃(产生一条模型无法据以行动的通用堆栈跟踪),要么更糟:静默地行为异常。与此同时,转换器已经编码了校验器遍历所需的完整结构。 +`defineTool`([自定义 schema DSL](2026-06-11-custom-schema-dsl.md))通过 `InferArgs<S>` 映射为工具作者提供了类型化的 `execute(args)`。但该类型只是对运行时值的编译期声明,而这个值实际上是模型生成的 JSON:没有任何机制强制模型遵守 schema,因此畸形调用(缺少必需键、声明为数字的位置传入字符串、枚举值超出集合)会以「仅名义类型化」的状态到达 `execute`。工具函数体要么在错误形状上崩溃(产生模型无法据以自我修正的通用堆栈跟踪),要么更糟——静默地行为异常。与此同时,转换器已经编码了校验器遍历所需的完整结构。 ## 决策 -`validateArgs(spec, args): string[]` 对一个运行时值解释 `SchemaSpec`,返回人类可读的违规列表(空 = 合法),且是全函数(从不抛出异常)。`defineTool` 在调用类型化的工具体之前运行它;如果存在违规,则抛出 `ToolArgsError`(`code: 'INVALID_ARGS'`,消息列出违规项),注册表既有的 execute-waterfall catch 将其转为模型可读取并据以自我修正的 `isError` 结果。 +`validateArgs(spec, args): string[]` 对运行时值解释一个 `SchemaSpec`,返回可读的违规列表(空数组 = 合法),且是全函数(永不抛出异常)。`defineTool` 在调用类型化函数体之前运行它;存在违规时抛出 `ToolArgsError`(`code: 'INVALID_ARGS'`,消息中列出违规项),注册表既有的 execute-waterfall(瀑布式事件)catch 将其转为模型可读取并据以自我修正的 `isError` 结果。 -校验器严格镜像 `schemaSpecToJsonSchema` 的语义:遍历相同的结构、执行相同的规则:顶层必须是非数组对象;必填键仅来自 `required: true`;允许额外键(不设 `additionalProperties: false`);不应用 `default`;没有 `properties`/`items` 的 `object`/`array` 属性仅做类型检查;`enum` 是成员判定。原始注册的(MCP)工具不受影响:它们自行校验输入。 +校验器严格镜像 `schemaSpecToJsonSchema` 的语义——遍历相同结构、执行相同规则:顶层必须是非数组对象;必需键仅来自 `required: true`;允许额外键(不设 `additionalProperties: false`);不应用 `default`;没有 `properties`/`items` 的 `object`/`array` 属性仅做类型检查;`enum` 是成员资格检查。原始注册的(MCP)工具不受影响——它们自行校验输入。 ## 后果 -- 模型在自身格式错误的调用上获得可操作的反馈,而非不透明的崩溃,弥合了 `InferArgs` 的承诺与运行时现实之间的鸿沟。 -- 校验器与 `InferArgs` 必须保持一致;一组[属性测试](../testing/2026-06-11-property-based-testing.md)会生成满足 spec 的参数并断言它们通过 `validateArgs`(同时断言定向破坏的参数被拒绝),以机械方式封堵漂移风险。 -- `ToolArgsError` 目前是一个带 `code` 字段的普通 `Error`;如果日后引入 harness 级别的错误分类体系,它将变为子类,而不影响读取 `.message` 的调用方。 +- 模型在自身畸形调用上获得可操作的反馈,而非不透明的崩溃,弥合了 `InferArgs` 的承诺与运行时现实之间的鸿沟。 +- 校验器与 `InferArgs` 必须保持一致;一项[属性测试](../testing/2026-06-11-property-based-testing.md)生成满足 spec 的参数并断言它们通过 `validateArgs`(同时断言定向破坏的参数被拒绝),以机械方式封堵漂移风险。 +- `ToolArgsError` 目前是带 `code` 字段的普通 `Error`;如果日后引入 harness 级别的错误分类体系,它将变为子类,但不影响读取 `.message` 的调用方。 - 校验开销相对于一次模型调用可忽略不计。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml index 84528dccf1..aa6cdb26ff 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-structured-error-taxonomy.md: 2baf88a1f942215e79561e565f455276c80178c4 -2026-06-11-structured-error-taxonomy.zh.md: f4762c4e92fb94c5bdbccc5f9a61e1496dc4c66d +2026-06-11-structured-error-taxonomy.zh.md: 90b0fdd7f6c8b4f0565c6538c2ddd4cb31680c38 diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md index f4762c4e92..90b0fdd7f6 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md @@ -6,21 +6,21 @@ Status: implemented ## 问题 -错误跨越服务边界时只是裸字符串。工具错误被扁平化为一个文本块——name、code 和 stack 全部丢失——导致未来的沙箱/重试插件无法区分 ENOENT 和 EACCES,模型得到的反馈也不如本可以获得的那样可操作。非 Error 的 throw 退化得更严重:agent loop(智能体循环)将其包装为 `new Error(String(x))`,丢弃了所有 code。而 `LlmError` 是系统中唯一的类型化错误,没有共享基类,消费方无法对一个通用基类做 `instanceof`。 +故障跨越 seam 时只是裸字符串。工具错误被扁平化为一个文本块(name、code 和 stack 全部丢失),导致未来的沙箱/重试插件无法区分 ENOENT 和 EACCES,模型得到的反馈也不如本可以那样具有可操作性。非 Error 的 throw 退化更严重:agent loop(智能体循环)将其包装为 `new Error(String(x))`,丢弃了所有 code。而 `LlmError` 是系统中唯一的类型化错误,没有共享基类,消费方无法对其进行通用的 `instanceof` 判断。 ## 决策 -在 `dsh-llm`(叶子包(package),所有其他包都已依赖它——不引入新的依赖边)中建立一个 `HarnessError extends Error` 基类:稳定的 `code`(与 `message` 分离)、通过 `ErrorOptions` 的 `cause` 链式传递、`name` 默认为子类名。`isHarnessError` 在服务边界处做类型收窄。 +在 `dsh-llm`(叶子包,所有其他包都已依赖它,不引入新的依赖边)中引入一个 `HarnessError extends Error` 基类:稳定的 `code`(与 `message` 分离)、通过 `ErrorOptions` 进行 `cause` 链接、`name` 默认为子类名。`isHarnessError` 在 seam 处做类型收窄。 - `LlmError`、`ToolArgsError`(dsh-tools)和 `InvariantError`(dsh-invariants)现在继承该基类,保留各自既有的 code。 -- `ToolExecutionResult` 新增可选字段 `error: { name, code }`,在注册表的 catch 中当抛出值为 `HarnessError` 时填充。agent loop 将其转发到 `tool/result` 会话事件(该事件也新增了同一可选字段),使结构化的失败信息存入日志,供重试/沙箱插件和回放使用。面向模型的文本块不变。 -- agent loop 的 `toError` 将非 Error 的 throw 包装为 `HarnessError`(`code: 'UNKNOWN'`,原始值通过 `cause` 链接),而非裸 `Error`;这样即使是不规范的 throw 也能携带可路由的 code 进入会话的 `error` 事件(该事件已暴露 `code`)。 +- `ToolExecutionResult` 新增可选字段 `error: { name, code }`,在注册表的 catch 中当抛出值为 `HarnessError` 时填充。agent loop 将其转发到 `tool/result` 会话事件(该事件也新增了同一可选字段),使结构化的失败信息存活到日志中,供重试/沙箱插件和回放使用。面向模型的文本块保持不变。 +- agent loop 的 `toError` 将非 Error 的 throw 包装为 `HarnessError`(`code: 'UNKNOWN'`,原始值作为 `cause` 链接),而非裸 `Error`;这样即使是不规范的 throw 也能携带可路由的 code 进入会话的 `error` 事件(该事件此前已暴露 `code`)。 ## 后果 -- 错误在端到端链路上可被机器路由:插件可以按 `error.code` 分支,而非对 message 做子串匹配。 -- 一个基类被广泛导入,但它位于所有包本已依赖的包中,代价只是一条 import 语句,而非一条新的依赖边。 -- `deriveMessages` 不会将 `error` 字段呈现到模型历史中——模型仍然看到文本块;结构化字段服务于代码逻辑和回放。 -- 参数校验与开发不变式保留各自既有的 code 和行为;共享基类添加了跨服务边界的路由元数据,不改变面向模型的文本。 +- 错误端到端可机器路由:插件可以基于 `error.code` 分支,而无需对 message 做子串匹配。 +- 一个基类被广泛导入,但它位于所有包已经依赖的包中,代价仅是一条 import 语句,而非新的依赖边。 +- `deriveMessages` 不会将 `error` 暴露到模型历史中——模型仍然看到文本块;结构化字段服务于代码和回放。 +- 参数校验与开发不变式保留各自既有的 code 和行为;共享基类增加了跨 seam 的路由元数据,不改变面向模型的文本。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml index c0625866a3..5f5b2ef266 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-tool-schemas-in-prompt-assembly.md: 443e6f20115e5a76001b4466c2d756675adbd886 -2026-06-11-tool-schemas-in-prompt-assembly.zh.md: 2d23d6fd0ead17fbeed3feaf3cec864813ef47e4 +2026-06-11-tool-schemas-in-prompt-assembly.zh.md: 03624b98fabdedf691f3fb448cc5f37ba5a649ef diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md index 2d23d6fd0e..03624b98fa 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md @@ -1,4 +1,4 @@ -# RFC:工具 schema 属于系统提示词组装的一部分 +# RFC:工具 schema 是系统提示词组装的一部分 Status: implemented @@ -6,18 +6,18 @@ Status: implemented ## 问题 -在协议格式(wire format)层面,工具 schema 通过模型请求中专用的 `tools` 字段传输,而非嵌入提示词文本。但从架构角度看,「模型被告知它能做什么」是一个内聚的关注点:提示词段落和工具列表由同一批插件贡献组装而成,并在同一时刻被消费。 +在协议格式(wire format)层面,工具 schema 通过模型请求中专用的 `tools` 字段传输,而非嵌入提示词文本。然而从架构角度看,「模型被告知它能做什么」是一个统一的关注点:提示词段落与工具列表由相同的插件贡献组装,并在同一时刻被消费。 ## 决策 -`PromptAssembly { sections, tools }`:系统提示词服务同时收集有序的文本段落和工具 schema(工具注册表自动贡献一个提供方)。agent loop(智能体循环)每步消费一个 assembly;适配器将 `sections` 映射到提供方的 system 槽位,将 `tools` 映射到协议格式的 `tools` 字段。因此 `system-prompt/assemble` waterfall(瀑布式事件)是模型前置信息的唯一拦截点——工具过滤(ToolSearch / 渐进式披露)是一次 assembly 改写,与提示词编辑无异。 +`PromptAssembly { sections, tools }`:系统提示词服务同时收集有序的文本段落和工具 schema(工具注册表自动贡献一个提供方)。agent loop(智能体循环)每个步骤消费一份 assembly;适配器将 `sections` 映射到提供方的 system 槽位,将 `tools` 映射到协议格式的 `tools` 字段。因此 `system-prompt/assemble` waterfall(瀑布式事件)是模型预先获知的所有信息的唯一拦截点:工具过滤(ToolSearch / 渐进式披露)是一次 assembly 重写,与提示词编辑无异。 ## 曾考虑的替代方案 -**循环分别向工具注册表和提示词服务查询**——将一个内聚的关注点拆到两个 seam 上;任何想塑造「模型被告知什么」的拦截(工具过滤、plan 模式)都需要在两个接口上各挂一个监听器,而非一次 assembly 改写。 +**循环从工具注册表和提示词服务分别查询**:将一个统一的关注点拆到两个 seam 上;任何想影响「模型被告知什么」的拦截(工具过滤、plan 模式)都需要在两个接口上各挂一个监听器,而非一次 assembly 重写即可完成。 ## 后果 - 一条 waterfall 统管模型的常驻上下文;plan 模式等插件可以在一个监听器中同时替换提示词文本和可见工具。 -- assembly 接口通过声明合并实现可扩展(无需无类型的 `extras` 包——扩展即声明合并)。 -- 「schema 出现在提示词服务中」有轻微的概念意外感,本文与 package README 对此做了说明。 +- assembly 接口通过声明合并实现可扩展(没有无类型的 `extras` 包——扩展即声明合并),为未来的槽位预留空间。 +- 将 schema 放在「提示词」服务中略有概念上的意外感,已在本文及 package README 中加以说明。 diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml index 25e7f01d0f..d0eac81287 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-13-capability-seams.md: e9d417dbd2bafcaece39601b12dbb310feb1e19b -2026-06-13-capability-seams.zh.md: e5d9be803f71ef3b85f79ed483dab64612a27fc7 +2026-06-13-capability-seams.zh.md: c569f3df083ec48bd05e6be2d3a1e5875fde362f diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md index e5d9be803f..c569f3df08 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md @@ -1,32 +1,32 @@ -# RFC:能力 seam——接口/实现/消费方拆分 - -Status: implemented +# RFC:能力 seam——接口/实现/消费方三分 [English](2026-06-13-capability-seams.md) | 中文 +Status: implemented + ## 问题 -harness 具有可替换的能力:目前是 bash 执行,未来会有沙箱/远程执行器和替代模型提供方。一项能力有三个关注点,它们以不同的速率、出于不同的原因变化:*契约*(这项能力是什么)、*实现*(它如何运行)、*消费方接口*(模型和其他插件面对什么来编程)。将三者打包在一个 package 中会耦合这些变化速率:把本地执行器换成沙箱执行器时,模型看到的工具 schema 也会被搅动,尽管面向模型的契约从未改变。 +harness 具有可替换的能力:当前是 bash 执行,未来会有沙箱化/远程执行器和替代模型提供方。一项能力涉及三个关注点,它们以不同速率、因不同原因变化:*契约*(这项能力是什么)、*实现*(它如何运行)、*消费方接口*(模型和其他插件面向什么编程)。将三者捆绑在一个包(package)中会耦合这些变化速率——把本地执行器换成沙箱化执行器时,模型看到的工具 schema 也会被搅动,尽管面向模型的契约从未改变。 -这与「运行时谁提供、谁需要一项能力」是不同的问题,后者 Cordis 已经用 service + `inject` 回答了(提供方注册 `ctx.bash`;消费方声明 `inject: ['bash']`,其 fiber 挂起直到该服务存在)。那套机制是必要的,但它不决定 package 边界;本 RFC 决定。 +这与「谁在运行时提供、谁需要一项能力」是不同的问题,后者 Cordis 已通过 service + `inject` 解决(提供方注册 `ctx.bash`;消费方声明 `inject: ['bash']`,其 fiber 挂起直到服务存在)。该机制是必要的,但不决定包的边界;本 RFC 决定的是包的边界。 ## 决策 -一项可替换的能力拆为**三个 package**: +一项可替换的能力由**三个包**构成: -1. **接口**:一个抽象 service 加词汇类型,拥有 `ctx.<key>`,仅依赖 cordis(例如 `dsh-bash`:`BashExecutor`、`BashRunResult`、`BashTask`)。 -2. **实现**:一个具体子类,以插件形式加载(例如 `dsh-bash-local`:子进程、进程组 kill、spill-file 截断)。沙箱/远程后端是实现同一接口的兄弟 package。 -3. **消费方**:模型和插件看到的东西(例如 `dsh-tool-bash`:`bash`/`bash_output`/`bash_kill` 工具 schema)。消费方 `inject` 接口 key,从不导入实现类型。 +1. **接口**——一个抽象服务加词汇类型,拥有 `ctx.<key>`,仅依赖 cordis(例如 `dsh-bash`:`BashExecutor`、`BashRunResult`、`BashTask`)。 +2. **实现**——一个具体子类,以插件形式加载(例如 `dsh-bash-local`:子进程、进程组 kill、溢出文件截断)。沙箱化/远程后端是实现同一接口的兄弟包。 +3. **消费方**——模型和插件看到的内容(例如 `dsh-tool-bash`:`bash`/`bash_output`/`bash_kill` 工具 schema)。消费方 `inject` 接口键,从不导入实现类型。 -实现与消费方随后独立演进:沙箱执行器替换 `dsh-bash-local` 时无需触碰任何工具 schema。 +实现与消费方由此独立演进:沙箱化执行器替换 `dsh-bash-local` 时无需触碰任何工具 schema。 -当各部分确实属于同一关注点时,拆分并非强制:LLM seam 将接口 + 消费方合并为 `dsh-llm`(消费方是 agent loop(智能体循环)本身,而非可替换的 schema 表面),适配器作为实现 package。不要预防性拆分:只有一种可设想的实现和一个消费方的能力保持为一个 package,直到第二个出现。 +当各部分确实属于同一个关注点时,三分并非强制:LLM(大语言模型) seam 将接口 + 消费方合并为 `dsh-llm`(消费方是 agent loop(智能体循环)本身,而非可替换的 schema 表面),适配器作为实现包。不要预防性地拆分——如果一项能力只有一种可设想的实现和一个消费方,就保持为一个包,直到第二种出现。 ## 曾考虑的替代方案 -- **合并为一个 package**:否决,因为它重新耦合了拆分所要分离的三种变化速率(这正是拆分的全部意义)。 -- **`@cordisjs/plugin-capability`**:完全不同的维度。它是一个权限/能力*安全*服务(带继承的命名权限,通过 `ctx.capability.test` 对会话进行检测),是延后的权限/沙箱工作(`tools/pre-execute` deny/ask seam)的候选方案,而**不是**替换实现的机制。混淆这两个「能力」正是本 RFC 所指出的陷阱。 +- **单一合并包**:否决。因为它重新耦合了三分设计本要分离的三种变化速率(这正是拆分的意义所在)。 +- **`@cordisjs/plugin-capability`**:这是完全不同的维度。它是一个权限/能力*安全*服务(具名权限加继承,通过 `ctx.capability.test` 对会话进行检测),是延后的权限/沙箱工作(`tools/pre-execute` deny/ask seam)的候选方案,**不是**替换实现的机制。混淆这两个「能力」概念正是本 RFC 所指出的陷阱。 ## 后果 -每项能力多出更多 package 和更多样板代码(一套 `package.json`/`tsconfig`/README,加上 inject 接线)。换来的是:实现与消费方独立发布和版本化,新后端永远不会波及面向模型的契约。该规则记录在 [AGENTS.md](../../../../AGENTS.md) § Conventions("Capability seams are three packages")和 [architecture.md](../../../architecture.md) § "Capability seams" 中;bash 三件套是参考模板。何时合并、何时拆分是一个判断性决策,架构文档已做说明——本 RFC 记录的是*为什么*默认选择拆分。 +每项能力需要更多包和更多样板代码(一组 `package.json`/`tsconfig`/README,加上 inject 接线)。换来的是:实现与消费方独立发布和版本管理,新后端永远不会波及面向模型的契约。该规则记录在 [AGENTS.md](../../../../AGENTS.md) § Conventions("Capability seams are three packages")和 [architecture.md](../../../architecture.md) § "Capability seams" 中;bash 三件套是参考模板。何时合并、何时拆分是一个判断问题,架构文档对此有详细说明——本 RFC 记录的是*为什么*默认选择拆分。 diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml index a46193a7cd..df04a14d6a 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-13-twin-llm-adapters.md: 4efefcf4e2f6b1d60567ba3bfed7ae1ea53a7a4e -2026-06-13-twin-llm-adapters.zh.md: 806eea84ff3e6c4de988348964429ccaea27f4ba +2026-06-13-twin-llm-adapters.zh.md: 6cabd95c5361afdea5b33ffdee34a5acb6026f7f diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md index 806eea84ff..6cabd95c53 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md @@ -1,4 +1,4 @@ -# RFC:以两个 LLM 适配器作为设计验证孪生 +# RFC:以两个 LLM 适配器作为设计验证孪生体 Status: implemented @@ -6,22 +6,22 @@ Status: implemented ## 问题 -`dsh-llm` 拥有一套提供方无关的流式输出词汇:`StreamChunk` 协议(`block-start`、`text-delta`、`reasoning-delta`、`tool-call-delta`、`block-end`、`usage`、`finish`)以及内容块类型([内容块词汇](2026-06-11-content-block-vocabulary.md))。如果词汇只针对单一适配器定义,就有把该适配器的怪癖烘焙进「中立」契约的风险:那个唯一实现碰巧做了什么,就会变成事实上的规范;而抽象在第二个提供方到来之前都无法被验证——届时泄漏已经代价高昂。 +`dsh-llm` 拥有一套提供方无关的流式词汇:`StreamChunk` 协议(`block-start`、`text-delta`、`reasoning-delta`、`tool-call-delta`、`block-end`、`usage`、`finish`)以及内容块类型([内容块词汇](2026-06-11-content-block-vocabulary.md))。如果词汇仅针对单个适配器定义,就有可能将该适配器的特异行为烘焙进「中立」契约:唯一实现碰巧做了什么,什么就成为事实上的规范;在第二个提供方到来之前,抽象层未经验证——而届时泄漏已代价高昂。 ## 决策 -从一开始就针对同一份契约交付**两个**适配器,刻意基于不同的内部实现: +从一开始就针对同一份契约交付**两个**适配器,刻意基于不同的内部实现构建: -- `dsh-llm-deepseek`:手写 `fetch` + SSE 解析,直连 DeepSeek API。 -- `dsh-llm-pi-ai`:通过 `@earendil-works/pi-ai` 库(有自己的事件词汇)访问同一端点。 +- `dsh-llm-deepseek`:手写 `fetch` + SSE(Server-Sent Events)解析,直接对接 DeepSeek API。 +- `dsh-llm-pi-ai`:通过 `@earendil-works/pi-ai` 库访问同一端点(该库有自己的事件词汇)。 -它们强制执行的规则是:**凡是 StreamChunk 词汇无法同时为两个实现表达的东西,都是核心词汇的 bug**——立即暴露,而非等到下一个提供方才发现。这对孪生确定了现已记录在 `dsh-llm/src/types.ts` 中 `StreamChunk` 上的约定:usage 在 finish 之前发出、finish 之后不再有任何事件、工具调用的 `arguments` 全程为原始 JSON 字符串,以及消费方必须在两侧都处理的两条合法错误路径(从 `stream()` 抛异常,*或*以 `finish {kind:'error'|'aborted'}` 结束)。后一项分歧正是由库封装的适配器暴露出来的,单一手写适配器会将其掩盖。 +二者共同执行的规则是:**凡 StreamChunk 词汇无法为两个实现同时表达的内容,都是核心词汇的缺陷**——立即暴露,而非等到下一个提供方接入时才发现。这对孪生体确定了现已记录在 `dsh-llm/src/types.ts` 中 `StreamChunk` 上的约定:usage 在 finish 之前发出、finish 之后不再有任何事件、工具调用的 `arguments` 全程以原始 JSON 字符串传递,以及消费方必须在两侧都处理的两条合法错误路径(`stream()` 抛异常,*或者*以 `finish {kind:'error'|'aborted'}` 结束)。后一项分歧正是由基于库的适配器暴露出来的,单一手写适配器会将其隐藏。 ## 曾考虑的替代方案 -- **单一适配器**:代码更少、e2e 成本减半,但「提供方无关」的声明无法验证;词汇会默默编码 DeepSeek-via-fetch 的假设。 -- **mock 第二适配器**:更便宜,但不会触及真实提供方的协议格式(wire format)怪癖,因此证明力有限。孪生是真实对真实。 +- **单一适配器**:代码更少、e2e 成本减半,但「提供方无关」的声明无从验证;词汇会默默编码 DeepSeek-via-fetch 的假设。 +- **mock 第二适配器**:更便宜,但不会触及真实提供方的协议格式(wire format)怪癖,因此证明力有限。孪生体是真实对真实的验证。 ## 后果 -孪生使适配器和需要密钥的 e2e 维护量翻倍——两者都覆盖 V4 Flash 和 Pro 在各代表性推理模式下的表现——换来的是对 seam 中立性的持续验证和第二份实现示例。两者都使用 `apiKey`、`baseURL` 和 `models`;手写适配器暴露 `thinking`/`reasoningEffort`,pi-ai 适配器暴露一个 `reasoning` 级别。未来的一致性测试套件可以通过一份取代性 RFC 来论证退役其中一个适配器。 +孪生体使适配器和需要密钥的 e2e 维护量翻倍——两者都覆盖 V4 Flash 和 Pro 在各代表性推理(reasoning)模式下的行为——换来的是持续的 seam 中立性验证和第二份实现示例。两个适配器均使用 `apiKey`、`baseURL` 和 `models`;手写适配器暴露 `thinking`/`reasoningEffort`,pi-ai 适配器暴露一个 `reasoning` 级别。未来如果有一致性测试套件,可以通过后续 RFC 论证退役其中一个适配器。 diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml index 3858139410..c6b9eaf967 100644 --- a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-14-session-persistence.md: 4078487b71862791dd25cf2afcfc03255cfeb0be -2026-06-14-session-persistence.zh.md: 801632b56d2056b36dbf7869f5114d74599bd5d5 +2026-06-14-session-persistence.zh.md: a44ef9647ca4003bc81023a54b7e9b5945003b02 diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md index 801632b56d..a44ef9647c 100644 --- a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md @@ -1,4 +1,4 @@ -# RFC:会话持久化——基于既有 `SessionEvent` 的抽象服务 +# RFC:会话持久化作为基于现有 `SessionEvent` 的抽象服务 Status: implemented @@ -6,31 +6,31 @@ Status: implemented ## 问题 -会话此前只存在于内存中。示例插件 `session-jsonl.ts`(在两个 examples 目录中逐字节重复)是只写的遥测:它缓冲 `session/event` 并追加 JSON 行,没有读取/回放路径,没有崩溃安全性(无 fsync、无原子写入、dispose 时 fire-and-forget 地排空缓冲区),没有列表功能,也没有格式版本控制。没有任何东西能把磁盘上的历史会话重新注入一个活跃的 agent,因此持久恢复(「继续昨天的任务」)、持久 fork,以及 ACP 的 `session/load` 方法([ACP 支持](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md))都不可能实现。 +会话此前仅存在于内存中。示例插件 `session-jsonl.ts`(在两个示例中逐字节重复)是只写的遥测:它缓冲 `session/event` 并追加 JSON 行,没有读取/回放路径,没有崩溃安全性(无 fsync、无原子写入、fire-and-forget 的 dispose 排空),没有列表功能,也没有格式版本控制。没有任何机制能将磁盘上的历史会话重新注入到活跃的 agent(智能体)中,因此持久恢复("继续昨天的任务")、持久 fork 以及 ACP(Agent Client Protocol)的 `session/load` 方法([ACP 支持](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md))都无法实现。 -[事件溯源模型](2026-06-11-event-sourced-sessions.md)将仅追加日志作为唯一真源,并从中派生 LLM 历史。持久化必须忠于这一点:直接持久化既有的 `SessionEvent`,不引入需要来回转换的并行「持久化消息」类型。后端也必须可替换——当前是文件存储,将来是数据库存储——统一在一个接口之后。 +[事件溯源模型](2026-06-11-event-sourced-sessions.md)将仅追加日志作为唯一真源,并从中派生 LLM(大语言模型)历史。持久化必须忠实于这一设计:直接持久化现有的 `SessionEvent`,不引入需要来回转换的并行"持久化消息"类型。后端也必须可替换——当前用文件存储,以后用数据库存储——统一在一个接口之后。 ## 决策 持久化是一个抽象的**能力 seam**([能力 seam](2026-06-13-capability-seams.md),`dsh-bash` 模板),而非循环或核心逻辑: -1. **接口**(`dsh-session-persistence`,`ctx.sessionPersistence`):一个抽象的 `SessionPersistence` 服务,提供 `create`/`append`/`load`/`list`。其持久化单元就是既有的 `SessionEvent`(`{ type, seq, time, data }`),逐字复用,无转换类型。 -2. **实现**(`dsh-session-persistence-jsonl`):每个会话一个仅追加的 JSONL 日志(一行 `SessionHeader`,之后每行一个 `SessionEvent`,逐字保留**包括 `assistant/chunk`**)。 +1. **接口**(`dsh-session-persistence`,`ctx.sessionPersistence`):一个抽象的 `SessionPersistence` 服务,提供 `create`/`append`/`load`/`list`。其持久化单元就是现有的 `SessionEvent`(`{ type, seq, time, data }`),原样复用,无转换类型。 +2. **实现**(`dsh-session-persistence-jsonl`):每个会话一个仅追加的 JSONL 日志(一行 `SessionHeader`,之后每行一个 `SessionEvent`,逐字节保留,**包括 `assistant/chunk`**)。 -以下关键选择记录于此,因为它们是持久的、有争议的、且出人意料的: +以下关键选择记录于此,因为它们是持久性的、有争议的、且出人意料的: -- **规范持久日志逐字保留每个 `SessionEvent`,包括 `assistant/chunk`。** `deriveMessages()` 跳过 chunk,过滤 chunk 的方案(Codex 的 `policy.rs`)很有吸引力,但 `seq = log.length` 以及加载校验 `events[i].seq === i` 要求日志*连续*;过滤掉 chunk 会留下空洞,同时破坏契约和恢复功能。未来可以将过滤 chunk 的投影作为带独立重编号的派生视图,但它不是规范日志。 -- **仅追加;崩溃的轮次被关闭,而非截断。** 已刷写的 `turn/end` 之前的事件永不重写,且循环只在轮次结束时刷写。由于一个被中断的轮次可能包含大量有效工作,`load` 会保留其中连续且可解析的事件,并为未应答的工具调用追加错误结果、补一个缺失的 `step/end`,以及带 `{ kind: 'interrupted' }` 的 `turn/end`。这些合成结果使恢复后的 provider transcript 保持有效。只有不完整的最后一条记录会被丢弃;如果在最后一个真实 `turn/end` 或之前出现解析错误或序号间隙,则视为损坏,该会话不可加载。 -- **文件后端为规范实现,数据库后端为已验证的可替换方案。** `SessionEvent` 1:1 映射为一行 `(session_id, seq, type, time, data)`:`append` 是 INSERT(在一个断言连续 seq 契约的事务中),`load` 是 SELECT … ORDER BY seq。`dsh-session-persistence-sqlite` 正是如此:一个 `SessionPersistence` 子类,接口不变(opencode 在 SQLite/WAL 上运行的正是这个形状),且它通过与 JSONL 后端相同的 `runPersistenceContract` 套件——因此契约以相同的语义(惰性物化、加载时关闭中断轮次、连续 seq)约束两个后端,一次表达在文件字节上,一次表达在行上。 -- **元数据在日志之外。** 格式版本、cwd 和谱系是存储关注点,不是可回放的对话状态,因此它们存放在 `dsh-session` 拥有的 `SessionHeader` 中,通过新的只读属性 `session.header` 附加到 `Session`——永远不在 `SessionEventMap` 中,永远不会到达 `deriveMessages()`。替代方案(一个可合并扩展的 `session/meta` 事件作为日志第 0 行)被否决:日志内事件在 seed/fork 会话时可以免费携带,但元数据不是可回放状态,因此显式的日志外 header seam 是更干净的代价。(header 最初被拆分为不可变的 `SessionHeader` 加可变的 `SessionSummary`,二者的联合类型为 `SessionMeta`;可变 summary 后来因为是死状态而被移除——见 [移除可变会话摘要](../simplification/2026-06-19-drop-mutable-session-summary.md)。) -- **`ctx.agents.create()` 与 `ctx.agents.resume()` 是异步工厂;resume 还额外跨越持久化边界。** `ctx.agents.resume({ resumeSessionId })` 等待 `ctx.sessionPersistence.load`,用加载的事件重建活跃会话(使 `lastTurnNumber`/`deriveMessages` 继续),并在恢复的 id 上启动一个新 agent(不是 `${agentId}-session`)。agent loop 不会硬注入 `sessionPersistence`(那会让非持久化的演示永远挂起);当 `sessionPersistence` 不存在时,`resume` 以明确的错误拒绝。 +- **规范的持久日志逐字节保留每个 `SessionEvent`,包括 `assistant/chunk`。** `deriveMessages()` 跳过 chunk,而过滤 chunk 的方案(Codex 的 `policy.rs`)很有吸引力,但 `seq = log.length` 以及加载验证 `events[i].seq === i` 要求日志是*连续*的;过滤掉 chunk 会留下空洞,同时破坏契约和恢复功能。基于 chunk 过滤的投影可以作为派生视图在后续实现(带有自己的重新编号),但它不是规范日志。 +- **仅追加;崩溃的轮次被关闭,而非截断。** 已刷写到 `turn/end` 的事件永不被重写,且循环仅在轮次结束时刷写。由于一个被中断的轮次可能包含大量有效工作,`load` 保留其连续、可解析的事件,并为未应答的工具调用追加错误结果、补一个缺失的 `step/end`,以及带 `{ kind: 'interrupted' }` 的 `turn/end`。合成的结果保证恢复后的 provider transcript(文本记录)仍然有效。只有不完整的最后一条记录会被丢弃;在最后一个真实 `turn/end` 处或之前出现解析错误或序号间隙,属于数据损坏,会使该会话不可加载。 +- **文件后端为规范实现,数据库后端为经过验证的直接替换。** `SessionEvent` 1:1 映射到一行 `(session_id, seq, type, time, data)`:`append` 是 INSERT(在一个断言连续 seq 契约的事务中),`load` 是 SELECT … ORDER BY seq。`dsh-session-persistence-sqlite` 正是如此:一个 `SessionPersistence` 子类,接口无变化(opencode 在 SQLite/WAL 上运行的正是这个形状),且通过与 JSONL 后端相同的 `runPersistenceContract` 测试套件。该契约以相同的语义约束两个后端(惰性物化、加载时关闭中断轮次、连续 seq),一次表达在文件字节上,一次表达在数据库行上。 +- **元数据在日志之外。** 格式版本、cwd 和谱系是存储关注点,不是可回放的对话状态,因此它们存放在 `dsh-session` 拥有的 `SessionHeader` 中,并通过新的只读属性 `session.header` 附加到 `Session` 上——永远不进入 `SessionEventMap`,永远不到达 `deriveMessages()`。替代方案(一个可合并扩展的 `session/meta` 事件作为日志第 0 行)被否决:日志内事件会随 seed/fork 的会话免费携带,但元数据不是可回放状态,因此显式的日志外 header seam 是更干净的代价。(header 最初被拆分为不可变的 `SessionHeader` 加可变的 `SessionSummary`,二者的联合类型为 `SessionMeta`;可变 summary 后来因属于死状态而被移除——见 [移除可变会话摘要](../simplification/2026-06-19-drop-mutable-session-summary.md)。) +- **`ctx.agents.create()` 和 `ctx.agents.resume()` 是异步工厂;resume 还跨越持久化边界。** `ctx.agents.resume({ resumeSessionId })` 等待 `ctx.sessionPersistence.load`,用加载的事件重建活跃会话(使 `lastTurnNumber`/`deriveMessages` 得以延续),并在恢复的 id 上启动一个新 agent(不是 `${agentId}-session`)。agent loop(智能体循环)不会硬注入 `sessionPersistence`(那样会让非持久化的演示永远挂起);当 `sessionPersistence` 不存在时,`resume` 以明确的错误拒绝。 ## 曾考虑的替代方案 -上述每个关键选择在陈述时已记录了其被否决的替代方案:**过滤 chunk 的规范日志**(Codex 的 `policy.rs` 形状)——破坏连续 seq 契约;**截断崩溃的轮次**——静默销毁长时间自主运行的真实工作;**日志内 `session/meta` 事件作为第 0 行**——元数据不是可回放状态;**将 `sessionPersistence` 硬注入循环**——会让非持久化的演示永远挂起。 +上述每个关键选择都在陈述处记录了被否决的替代方案:**过滤 chunk 的规范日志**(Codex 的 `policy.rs` 形式)破坏连续 seq 契约;**截断崩溃的轮次**会静默销毁长时间自主运行中的真实工作;**日志内 `session/meta` 事件作为第 0 行**——元数据不是可回放状态;**将 `sessionPersistence` 硬注入循环**会让非持久化的演示永远挂起。 -格式版本控制:header 携带一个 `version`;`load` 拒绝任何非当前版本(不做迁移——预发布的会话格式固定在 `SESSION_FORMAT_VERSION = 0`,按 AGENTS.md 的预发布立场吸收形状变动)。坦率地说:仅追加 + 刷写对部分尾部写入(加载时容忍)是健壮的,但对行写入中途的无 fsync 断电不健壮;数据库/WAL 后端是将来更强的选项。 +格式版本控制:header 携带一个 `version`;`load` 拒绝任何非当前版本(不做迁移——预发布阶段的会话格式固定为 `SESSION_FORMAT_VERSION = 0` 并吸收形状变动,遵循 AGENTS.md 的预发布立场)。坦率地说:仅追加 + 刷写对部分尾部写入是健壮的(加载时容忍),但对行写入中途的无 fsync 断电不健壮;数据库/WAL 后端是后续更强的选项。 ## 后果 -新增两个包(package),以及 `dsh-session` 中的元数据 seam(`session.header`、`create(id?, options?)` 签名)。收获:持久恢复/fork、读取/回放路径、崩溃容忍,以及 ACP `session/load`([ACP 支持](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md))所需的基础——全部建立在既有的事件溯源日志之上,后端可在一个接口后替换。可复用的 `runPersistenceContract` 套件以相同的仅追加、连续 seq、惰性物化与可序列化语义约束每个后端。持久化完整日志还确定了事件保真度:`assistant/chunk` 保持逐字保留。 +新增两个包(package),以及 `dsh-session` 中的元数据 seam(`session.header`,`create(id?, options?)` 签名)。收益:持久恢复/fork、读取/回放路径、崩溃容忍,以及 ACP `session/load`([ACP 支持](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md))所需的基础——全部基于现有的事件溯源日志,后端在一个接口之后可替换。可复用的 `runPersistenceContract` 测试套件以相同的仅追加、连续 seq、惰性物化与可序列化语义约束每个后端。持久化完整日志还确定了事件保真度:`assistant/chunk` 保持逐字节不变。 diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml index 545fdae4ff..72eb9e3d7a 100644 --- a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-15-turn-enclosure-invariant.md: bf0789f21ba7bd928e023bb5fd844d9ec78c4bc1 -2026-06-15-turn-enclosure-invariant.zh.md: 9f6f69b923ed7feff51122c4e4040bff3c9db8ea +2026-06-15-turn-enclosure-invariant.zh.md: 644e7b975e024286d5307f586f509c2b4a9f21ea diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md index 9f6f69b923..644e7b975e 100644 --- a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md @@ -1,4 +1,4 @@ -# RFC:每个会话事件必须包含在一个轮次内 +# RFC:每个会话事件都封闭在一个轮次内 Status: implemented @@ -6,37 +6,37 @@ Status: implemented ## 问题 -持久化的会话持久化后端(在一个配套变更中引入)以**轮次**作为崩溃恢复边界:崩溃可能留下一个未关闭的最终轮次,`load` 会用一个合成的 `turn/end {kind:'interrupted'}` 将其关闭,同时保留该轮次的真实事件(见[会话持久化](2026-06-14-session-persistence.md))。这种恢复只有在没有任何*合法的*持久化事件位于轮次之外(即上一个 `turn/end` 与下一个 `turn/start` 之间的间隙)时才是良定义的,否则这类事件会被裹入下一个轮次的中断关闭中。 +持久化的会话持久化后端(在配套变更中引入)以**轮次**作为崩溃恢复边界:崩溃可能留下一个未关闭的最终轮次,`load` 会用一个合成的 `turn/end {kind:'interrupted'}` 将其关闭,同时保留该轮次的真实事件(见[会话持久化](2026-06-14-session-persistence.md))。这种恢复只有在没有任何*合法的*持久事件位于轮次之外(即上一个 `turn/end` 与下一个 `turn/start` 之间的间隙)时才是良定义的,否则这类事件会被卷入下一个轮次的中断关闭中。 -该假设并不成立。有两条路径在轮次之外记录了事件: +这一假设并不成立。有两条路径在任何轮次之外记录了事件: -1. **排队的用户消息。** agent loop(智能体循环)排空排队消息并在 `turn/start` **之前**追加 `user/message`,导致一个轮次自身的提示词落在前一个 `turn/end` 与下一个 `turn/start` 之间的间隙中。 -2. **空闲时的上下文注入。** `agent.inject()` 直接追加一条 `context/message`。它在生产环境中的实际调用方是 `dsh-tool-bash`,后者从 `ctx.bash.onTaskDone` 注入后台任务完成通知——该回调在后台 bash 任务完成时触发,经常发生在 agent **空闲**(两个轮次之间)时。 +1. **排队的用户消息。** agent loop(智能体循环)排空排队消息并在 `turn/start` **之前**追加 `user/message`——于是一个轮次自身的提示词落在了前一个 `turn/end` 与下一个 `turn/start` 之间的间隙中。 +2. **空闲时的上下文注入。** `agent.inject()` 直接追加一条 `context/message`。它在生产环境中的真实调用方是 `dsh-tool-bash`,后者从 `ctx.bash.onTaskDone` 注入后台任务完成通知——该回调在后台 bash 任务完成时触发,而这经常发生在 agent **空闲**(轮次之间)时。 -对于情况 2,如果注入的 `context/message` 是 flush/dispose 之前的最后一个事件(之后没有轮次追加 `turn/end`),`scanLog` 会将其视为崩溃残留并**在恢复时丢弃**——注入的上下文虽然已持久化到磁盘,但在重新加载时被静默丢失。情况 1 单独来看是无害的(`user/message` 之后总是紧跟它触发的轮次),但使得「什么可以出现在轮次之外」这条规则变得模糊。 +在情况 2 中,如果注入的 `context/message` 是 flush/dispose 之前的最后一个事件(之后没有轮次追加 `turn/end`),`scanLog` 会将其视为崩溃残留并在**恢复时丢弃**——注入的上下文已持久写入磁盘,但重新加载后被静默丢失。情况 1 本身无害(`user/message` 之后总会跟着它触发的轮次),但使「什么可以出现在轮次之外」这条规则变得模糊。 ## 决策 -**每个会话事件都位于一个轮次内部**——在一个 `turn/start` 与其匹配的 `turn/end` 之间。具体而言: +**每个会话事件都位于一个轮次内部**:在 `turn/start` 与其匹配的 `turn/end` 之间。具体而言: -- agent loop 在 `turn/start` **之后**(轮次内部)追加排队的 `user/message` 事件,而非在其之前。因此,这些消息一经记录,`turn/end` 就已被承诺,而现有的 finalizer 保证了这一点。 -- 在 agent **运行中**调用 `agent.inject()` 时,其 `context/message` 追加到已打开的轮次中(行为不变)。 -- 在 agent **空闲时**调用 `agent.inject()`,系统将 `context/message` 包裹在一个一次性轮次中:`turn/start{trigger:{kind:'injection'}}` → `context/message` → `turn/end{completed}`。一个新的 `injection` 变体加入可合并扩展的 `TurnTriggerMap`。 -- agent loop 每次迭代从日志推导下一个轮次编号(`lastTurnNumber(session) + 1`),而非维护一个私有计数器,因此空闲注入的一次性轮次不会与下一个真实轮次的编号冲突。 -- `dsh-invariants` 插件在开发模式下**强制执行**该不变式:在没有打开的轮次时追加 `user/message`/`context/message`/`steering/message` 会抛出 `InvariantError`。 +- agent loop 在 `turn/start` **之后**(轮次内部)追加排队的 `user/message` 事件,而非之前。因此,一旦这些消息被记录,就欠下一个 `turn/end`,既有的 finalizer 保证它被写入。 +- agent **运行中**调用 `agent.inject()` 时,`context/message` 追加到已打开的轮次中(行为不变)。 +- agent **空闲时**调用 `agent.inject()`,则将 `context/message` 包裹在一个一次性轮次中:`turn/start{trigger:{kind:'injection'}}` → `context/message` → `turn/end{completed}`。一个新的 `injection` 变体加入可合并扩展的 `TurnTriggerMap`。 +- agent loop 每次迭代从日志推导下一个轮次编号(`lastTurnNumber(session) + 1`),而不是维护一个私有计数器,这样空闲注入的一次性轮次不会与下一个真实轮次的编号冲突。 +- `dsh-invariants` 插件在开发环境中**强制执行**该不变式:在没有打开轮次的情况下追加 `user/message` / `context/message` / `steering/message` 会抛出 `InvariantError`。 -可序列化性不变式在同一个源码边界强制执行(`Session.append` 对不可 JSON 序列化的数据抛出异常),因此「什么可以进入日志」现在由一处统一管控,而非由下游恰好在监听的某个后端去发现。 +可序列化性不变式在同一源码边界处强制执行(`Session.append` 对不可 JSON 序列化的数据抛出异常),因此「什么可以进入日志」现在由一个位置统一管控,而非由下游碰巧在监听的某个后端各自发现。 ## 曾考虑的替代方案 -**放宽读取端而非约束生产端**——让 `scanLog` 提交位于已打开轮次之外的事件。否决:一条可检查的生产端规则优于一条更宽松的边界扫描逻辑,后者需要同时推理部分轮次*和*轮次间的散落事件。 +**放宽读取端而非约束生产端**——让 `scanLog` 提交位于已打开轮次之外的事件。否决:一条单一、可检查的生产端规则优于一个更宽松的边界扫描(后者需要同时推理部分轮次*和*轮次间的散落事件)。 ## 后果 -轮次现在是*唯一的*持久化/回放边界,因此[会话持久化](2026-06-14-session-persistence.md)的崩溃恢复规则是完备的,而不仅仅是充分的:一个被中断的最终轮次会被关闭(用合成的 `turn/end {interrupted}`),其真实事件被保留,且完全不存在将轮次间上下文混入其中的风险,因为不再有轮次间上下文。`scanLog` 保持简单(至多一个可能未关闭的最终轮次,永远没有散落的轮次间事件),空闲时的后台任务通知在持久化 + 恢复后得以存活。 +轮次现在是*唯一的*持久性/回放边界,因此[会话持久化](2026-06-14-session-persistence.md)的崩溃恢复规则是完备的,而不仅仅是充分的:被中断的最终轮次被关闭(用合成的 `turn/end {interrupted}`),其真实事件得以保留,且零风险将轮次间上下文混入其中,因为不存在轮次间上下文。`scanLog` 保持简洁(最多一个可能未关闭的最终轮次,绝无散落的轮次间事件),空闲时的后台任务通知在持久化 + 恢复后依然存活。 -代价:空闲时调用 `agent.inject()` 现在写入三行日志而非一行,且推导出的历史中多出一个仅包含注入上下文(无 assistant 输出)的轮次——`deriveMessages()` 本就纯粹按事件类型推导,因此渲染结果不变。`injection` 触发器是一个新的磁盘词汇值;与每一个 `SessionEventMap`/`TurnTriggerMap` 的新增项一样,它属于冻结格式的一部分。轮次内的事件顺序发生了变化(`turn/start` 现在先于 `user/message`),这对任何断言旧顺序的代码是可观测的——agent loop 自身的测试是唯一的此类消费方。 +代价:空闲时调用 `agent.inject()` 现在写入三行日志而非一行;派生的历史中多出一个仅包含注入上下文(无 assistant 输出)的轮次——`deriveMessages()` 已经纯粹按事件类型派生,因此渲染结果完全相同。`injection` 触发器是一个新的磁盘词汇值;与每次 `SessionEventMap`/`TurnTriggerMap` 的新增一样,它属于冻结格式的一部分。轮次内的事件顺序发生了变化(`turn/start` 现在先于 `user/message`),这对任何断言旧顺序的代码可观测——agent loop 自身的测试是唯一的此类消费方。 -该规则有意采用生产端强制执行 + 开发模式检查的方式,而非读取端容忍:未来的后端(SQLite/WAL)可以免费继承同样干净的边界,而在轮次外记录事件的插件会在开发模式下大声失败,而非在下次重新加载时静默丢失数据。 +该规则有意采用生产端强制、开发环境检查的方式,而非读取端容忍的方式:未来的后端(SQLite/WAL)无需额外工作即可继承同样干净的边界,而在轮次外记录事件的插件会在开发环境中大声失败,而非在下次重新加载时静默丢失数据。 -轮次内检测到的失败在 `turn/end` 之前记录。之后的 flush 失败没有合法的轮次内位置,因此通过 `agent/error` 和日志报告,而非作为会话事件追加。这保持了回放日志的平衡;持久化的运维诊断需要一个独立的遥测通道。 +轮次内检测到的失败在 `turn/end` 之前记录。后续的 flush 失败没有有效的轮次内位置,因此通过 `agent/error` 和日志报告,而非作为会话事件追加。这保持了回放日志的平衡;持久化的运维诊断需要一个独立的遥测通道。 diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml index 5d92edb79a..11faf45d26 100644 --- a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-17-filesystem-capability-seam.md: c502ae712de22e97661192057d4410c7c55ea044 -2026-06-17-filesystem-capability-seam.zh.md: 01a4318237ebbd29fe3effa3f8528b6e4a5132d6 +2026-06-17-filesystem-capability-seam.zh.md: 4e544e24c548a52bde254886a65ff2fdb559a986 diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md index 01a4318237..4e544e24c5 100644 --- a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md @@ -1,42 +1,42 @@ # RFC:文件系统能力 seam——ctx.fs、本地后端与面向模型的文件系统工具 -Status: implemented - [English](2026-06-17-filesystem-capability-seam.md) | 中文 +Status: implemented + ## 问题 -harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` / `dsh-tool-bash`),但文件系统操作即将作为面向模型的工具加入,却没有等价的 seam。如果 `read`、`write` 和 `edit` 直接使用 `node:fs`,面向模型的工具包将同时拥有文件系统执行策略、本地路径解析、原子写入行为、文本解码、符号链接行为和编辑语义。 +harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` / `dsh-tool-bash`),但文件系统操作即将作为面向模型的工具加入,却没有等价的 seam。如果 `read`、`write` 和 `edit` 直接使用 `node:fs`,面向模型的工具包将同时承担文件系统执行策略、本地路径解析、原子写入行为、文本解码、符号链接行为和编辑语义。 这把三个独立变化的关注点耦合在了一起: 1. 文件系统契约:插件可以请求哪些操作。 -2. 后端:当前是本地磁盘,未来可能是沙箱/远程/项目范围的文件系统。 +2. 后端:当前是本地磁盘,未来可能是沙箱/远程/项目作用域的文件系统。 3. 消费方接口:面向模型的 `read` / `write` / `edit` schema 与结果格式化。 -没有 `ctx.fs` 接口,将本地文件系统访问替换为沙箱或远程后端时,即使面向模型的契约应当保持稳定,也会搅动工具 schema、演示和提示词引导。这还使权限/沙箱边界更难推理:一个 `cwd` 选项看起来像沙箱,但除非有显式后端或 `tools/execute` 策略强制隔离,否则它只是一个基础路径。 +如果没有 `ctx.fs` 接口,将本地文件系统访问替换为沙箱或远程后端时,即使面向模型的契约应当保持稳定,工具 schema、演示和提示词引导也会被迫变动。这还使权限/沙箱边界更难推理:一个 `cwd` 选项看起来像沙箱,但除非有显式的后端或 `tools/execute` 策略强制隔离,否则它只是一个基础路径。 -我们需要让文件系统工具在成为公开包接口之前,以与 bash 相同的能力 seam 形态落地。 +我们需要文件系统工具在成为公开包(package)接口之前,以与 bash 相同的能力 seam 形态落地。 ## 决策 -文件系统访问是一个一等能力 seam,遵循[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md): +文件系统访问是一个一等的能力 seam,遵循[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md): 1. `@deepseek-ai/dsh-fs`(`packages/fs/fs`)拥有抽象的 `ctx.fs` 服务、文件系统词汇类型,以及 `fs/*` 策略事件词汇。 2. `@deepseek-ai/dsh-fs-local`(`packages/fs/fs-local`)提供第一个实现,以本地文件系统为后端。 -3. `@deepseek-ai/dsh-tool-fs`(`packages/fs/tool-fs`)通过 `ctx.fs` 提供面向模型的 `read`、`write` 和 `edit` 工具,并作为执行器分发 `fs/*` 事件。 +3. `@deepseek-ai/dsh-tool-fs`(`packages/fs/tool-fs`)通过 `ctx.fs` 提供面向模型的 `read`、`write` 和 `edit` 工具,是分发 `fs/*` 事件的执行器。 消费方包仅依赖接口包,从不依赖 `dsh-fs-local`。需要不同后端的部署只需为 `ctx.fs` 加载不同的提供方,无需改动工具 schema 或面向模型的提示词引导。 -先读后写/编辑与已观察状态策略是第四个包 `@deepseek-ai/dsh-fs-policy`(`packages/fs/fs-policy`),通过 `fs/*` 事件门而非 `ctx.fs` 方法贡献;加载 `dsh-tool-fs` 的部署同时加载 `dsh-fs-policy` 以获得先读后写/编辑能力。本 RFC 确立了三包 seam;策略从提供方基类拆出的决策见 [split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md),其作为事件门插件(而非方法服务)的实现见 [event-gate RFC](2026-06-26-file-context-as-event-gate.md)。本文已更新为描述最终落地的四包形态。 +读后写/编辑与观测状态策略是第四个包 `@deepseek-ai/dsh-fs-policy`(`packages/fs/fs-policy`),通过 `fs/*` 事件门控贡献,而非挂在 `ctx.fs` 上;加载 `dsh-tool-fs` 的部署同时加载 `dsh-fs-policy` 以获得读后写/编辑能力。本 RFC 确立了由三个包构成的 seam;策略从提供方基类拆出的决策由 [split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 做出,其以事件门控插件(而非方法服务)实现的方式由 [event-gate RFC](2026-06-26-file-context-as-event-gate.md) 做出。本文已更新为描述最终落地的四包形态。 -第一个后端刻意仅限本地:`dsh-fs-local` 针对宿主文件系统实现 `ctx.fs`。未来的兄弟后端可以在同一接口后面提供沙箱、远程、虚拟或项目范围的文件系统。 +第一个后端有意仅限本地:`dsh-fs-local` 基于宿主文件系统实现 `ctx.fs`。未来的兄弟后端可在同一接口之后提供沙箱、远程、虚拟或项目作用域的文件系统。 -第一个消费方刻意仅限文本文件:`dsh-tool-fs` 暴露面向模型的 `read`、`write` 和 `edit` 工具,处理 UTF-8 文本文件。未来的消费方可以添加目录列表、搜索/glob、二进制安全操作、文件监听或更高层的项目操作,只要所需能力存在于 `ctx.fs` 上,就无需改动本地后端包。直接目录列表后来由 [Add direct directory listing to the filesystem seam](2026-07-03-filesystem-directory-listing-seam.md) 添加。 +第一个消费方有意仅限文本文件:`dsh-tool-fs` 暴露面向模型的 `read`、`write` 和 `edit` 工具,处理 UTF-8 文本文件。未来的消费方可以添加目录列表、搜索/glob、二进制安全操作、文件监视或更高层的项目操作,只要 `ctx.fs` 上存在所需能力,就无需改动本地后端包。直接目录列表后来由 [Add direct directory listing to the filesystem seam](2026-07-03-filesystem-directory-listing-seam.md) 添加。 -文件系统权限和沙箱并非此拆分所隐含。本地后端从其配置的基础目录解析相对路径,但隔离策略是独立决策:要么由更严格的 `ctx.fs` 实现强制执行,要么由权限/沙箱插件包装 `tools/execute` 并在调用到达消费方之前否决。 +文件系统权限和沙箱并非此拆分所隐含。本地后端从其配置的基目录解析相对路径,但隔离策略是独立的决策:要么由更严格的 `ctx.fs` 实现强制执行,要么由权限/沙箱插件包装 `tools/execute` 并在调用到达消费方之前否决。 -先读后写/编辑与已观察状态属于 `dsh-fs-policy`,而非 `ctx.fs`。通过 `fs/*` 事件门,策略按不透明 actor 记录版本,并提供可选的变更期望;提供方原子性地强制新鲜度。`dsh-tool-fs` 发出事件但不依赖策略。详见 [split-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 与 [event-gate](2026-06-26-file-context-as-event-gate.md) RFC。 +读后写/编辑与观测状态属于 `dsh-fs-policy`,而非 `ctx.fs`。通过 `fs/*` 事件门控,策略按不透明 actor 记录版本,并提供可选的变更期望;提供方原子性地强制新鲜度。`dsh-tool-fs` 发出事件但不依赖策略。见 [split-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](2026-06-26-file-context-as-event-gate.md) RFC。 ## 包拓扑 @@ -47,11 +47,11 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` consumer interface implementation ``` -`@deepseek-ai/dsh-fs` 仅依赖 `cordis` 和来自 `@deepseek-ai/dsh-llm` 的仓库级 `HarnessError` 基类。它声明 `ctx.fs` 键、抽象 `FileSystem` 服务、后端与消费方共享的词汇类型、文件系统错误词汇,以及 `fs/*` 策略事件词汇。它不持有已观察状态存储,也不持有 owner 推导形态;事件传递一个不透明的 `object` actor,提供方从不读取它,`dsh-fs-policy` 插件在这些事件之上拥有 owner 推导形态和已观察状态存储。 +`@deepseek-ai/dsh-fs` 仅依赖 `cordis` 加上来自 `@deepseek-ai/dsh-llm` 的仓库级 `HarnessError` 基类。它声明 `ctx.fs` 键、抽象 `FileSystem` 服务、后端和消费方共享的词汇类型、文件系统错误词汇,以及 `fs/*` 策略事件词汇。它不持有观测状态存储,也不持有 owner 推导形态;事件传递一个不透明的 `object` actor,提供方从不读取它,`dsh-fs-policy` 插件在这些事件之上拥有 owner 推导形态和观测状态存储。 -`@deepseek-ai/dsh-fs-local` 依赖 `@deepseek-ai/dsh-fs` 和 `cordis`。它继承 `FileSystem`,将自身注册为 `ctx.fs`,拥有本地后端配置(如基础目录),并包含所有直接的 `node:fs` / `node:path` 访问。它不持有已观察状态存储:新鲜度是后端铸造、策略插件记录的版本令牌。 +`@deepseek-ai/dsh-fs-local` 依赖 `@deepseek-ai/dsh-fs` 和 `cordis`。它继承 `FileSystem`,将自身注册为 `ctx.fs`,拥有本地后端配置(如基目录),并包含所有直接的 `node:fs` / `node:path` 访问。它不持有观测状态存储——新鲜度是后端铸造、策略插件记录的版本令牌。 -`@deepseek-ai/dsh-tool-fs` 依赖 `@deepseek-ai/dsh-fs`、`@deepseek-ai/dsh-tools`、`@deepseek-ai/dsh-system-prompt` 和 `cordis`。它注册面向模型的工具和提示词段落。它禁止导入 `node:fs`、`node:path` 或 `@deepseek-ai/dsh-fs-local`;文件系统执行始终通过 `ctx.fs`。如果实现需要具体的 agent 或会话辅助类型,这些依赖属于 `tool-fs`;它们禁止回漏到 `dsh-fs`。 +`@deepseek-ai/dsh-tool-fs` 依赖 `@deepseek-ai/dsh-fs`、`@deepseek-ai/dsh-tools`、`@deepseek-ai/dsh-system-prompt` 和 `cordis`。它注册面向模型的工具和提示词段落。它禁止导入 `node:fs`、`node:path` 或 `@deepseek-ai/dsh-fs-local`;文件系统执行始终通过 `ctx.fs`。如果实现需要具体的 agent 或会话辅助类型,这些依赖属于 `tool-fs`;它们禁止回漏到 `dsh-fs` 中。 根 `tool-fs` 插件通过组合各工具的注册辅助函数来注册完整的文件系统工具套件(`read`、`write` 和 `edit`)。它注入 `fs`,从不导入实现包。 @@ -59,23 +59,23 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` `@deepseek-ai/dsh-fs` 拥有一个语义文件系统服务。它比 `readFile` / `writeFile` 更高层,这样 `tool-fs` 就不必重新实现路径解析、版本管理、文本解码、二进制拒绝、分页、原子替换、符号链接行为或字面编辑语义。 -该接口覆盖以下语义操作: +该接口涵盖以下语义操作: - 将模型/插件提供的路径解析为后端定义的目标。 -- 在不读取文件内容的情况下获取目标元数据。 +- 获取目标元数据而不读取文件内容。 - 从目标读取有界的 UTF-8 文本页。 - 创建或替换一个 UTF-8 文本文件。 -- 通过字面替换编辑一个已存在的 UTF-8 文本文件。 +- 通过字面替换编辑一个已有的 UTF-8 文本文件。 -提供方 seam 还承载策略所依赖的新鲜度钩子,但已观察状态存储和 owner 推导位于 `dsh-fs-policy` 插件中,而非 `ctx.fs` 上: +提供方 seam 还携带策略所依赖的新鲜度钩子——但观测状态存储和 owner 推导位于 `dsh-fs-policy` 插件中,而非 `ctx.fs` 上: -- 后端为每个目标铸造一个不透明的 `version` 令牌(在 `stat` 和每次读取/变更结果中)。 -- `writeText`/`editText` 接受一个可选的版本期望:省略它则执行无条件的裸提供方变更,提供它则在后端的原子临界区内守护变更。 -- `dsh-fs-policy` 插件在 `fs/write-intent`/`fs/edit-intent` 上决定该期望,并在 `fs/observed` 上记录已观察版本,以从不透明事件 actor 推导出的 owner 为键(通常是 `exec.agent.session`)。 +- 后端为每个目标铸造一个不透明的 `version` 令牌(在 `stat` 以及每次读取/变更结果中)。 +- `writeText`/`editText` 接受一个可选的版本期望:省略它表示无条件的裸提供方变更;提供它则在后端的原子临界区内守护变更。 +- `dsh-fs-policy` 插件在 `fs/write-intent`/`fs/edit-intent` 上决定该期望,并在 `fs/observed` 上记录观测版本,以它从不透明事件 actor 推导出的 owner 为键(通常是 `exec.agent.session`)。 -授权基于版本新鲜度,而非完整/部分视图的区分:任何读取都记录目标的版本,后续的写入/编辑只要文件仍处于该版本即被授权——因此对第 100-150 行的窗口读取可以授权对第 120 行的编辑。已观察状态存储是 `dsh-fs-policy` 内部的 `WeakMap<owner, Map<targetKey, version>>`;`dsh-fs` 不持有任何此类数据,并将 actor 视为不透明。(本 RFC 最初建模了一个带 `full`/`partial` 视图的 `FileState` 缓存放在 `ctx.fs` 上;split-fs-seam 和 event-gate RFC 将其替换为此处描述的基于新鲜度的策略插件。) +授权基于版本新鲜度,而非完整/部分视图的区分:任何读取都会记录目标的版本,后续的写入/编辑只要文件仍处于该版本就被授权——因此对第 100-150 行的窗口化读取可以授权对第 120 行的编辑。观测状态存储是 `dsh-fs-policy` 内部的 `WeakMap<owner, Map<targetKey, version>>`;`dsh-fs` 不持有任何此类数据,并将 actor 视为不透明。(本 RFC 最初建模了一个带 `full`/`partial` 视图的 `FileState` 缓存放在 `ctx.fs` 上;split-fs-seam 和 event-gate RFC 将其替换为此处描述的基于新鲜度的策略插件。) -路径解析是显式的,允许异步。本地解析可能只做路径规范化,但沙箱/远程/项目范围的后端可能需要 I/O 才能将用户提供的路径解析为稳定的目标标识。 +路径解析是显式的,允许异步。本地解析可能只做路径规范化,但沙箱/远程/项目作用域的后端可能需要 I/O 才能将用户提供的路径解析为稳定的目标标识。 解析后的目标必须至少暴露三个概念: @@ -83,19 +83,19 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` - 不透明的 `targetKey`,用于过期守护和文件状态查找。本地后端可能使用类似 realpath 的键;远程后端可能使用工作区 URI 或文件 id。消费方禁止解析或假设它是本地绝对路径。 - `displayPath`,用于面向模型/UI 的输出。根据后端不同,它可能是本地绝对路径、工作区相对路径或远程 URI。 -读取和变更结果必须包含一个不透明的文件 `version`。本地后端可以使用 mtime/size 或类 hash 令牌;远程后端可以使用修订 id。`dsh-fs-policy` 插件记录版本用于过期检查;消费方可以展示相关元数据但禁止解释版本令牌。 +读取和变更结果必须包含不透明的文件 `version`。本地后端可以使用 mtime/size 或类似 hash 的令牌;远程后端可以使用 revision id。`dsh-fs-policy` 插件记录版本用于过期检查;消费方可以展示相关元数据但禁止解释版本令牌。 -提供方返回已解码的文本:`readText` 返回整个常规文本文件,`streamText` 以流式传输相同的文本语义用于大文件。二者都负责常规文件检查;有界行/输出处理不是它们的职责——行窗口、带行号渲染和总行数统计位于执行器(`dsh-tool-fs`)中,执行器通过 `ctx.fs` 读取并渲染面向模型的窗口。提供方负责 UTF-8 解码和二进制/NUL 拒绝;它不知道行窗口或视图。 +提供方返回已解码的文本:`readText` 返回整个常规文本文件,`streamText` 为大文件流式传输相同的文本语义。两者负责常规文件检查;有界的行/输出处理不是它们的职责——行窗口化、带行号渲染和总行数统计位于执行器(`dsh-tool-fs`)中,执行器通过 `ctx.fs` 读取并渲染面向模型的窗口。提供方负责 UTF-8 解码和二进制/NUL 拒绝;它不知道行窗口或视图。 -已观察状态记录不在 `ctx.fs` 上:成功读取后执行器发出 `fs/observed`,`dsh-fs-policy` 插件为推导出的 owner 记录 `{ version }`。没有 `full`/`partial` 视图——任何窗口的读取都记录版本,新鲜度(而非视图完整性)授权后续的写入/编辑。 +观测状态记录不在 `ctx.fs` 上:成功读取后,执行器发出 `fs/observed`,`dsh-fs-policy` 插件为推导出的 owner 记录 `{ version }`。没有 `full`/`partial` 视图——任何窗口的读取都记录版本,新鲜度(而非视图完整性)授权后续的写入/编辑。 -全文件写入创建或替换 UTF-8 文本文件。后端在支持且有文档说明时可以创建父目录。已存在的非常规目标被拒绝。`writeText` 接受一个可选期望:`createIfAbsent` 创建缺失的目标并在已存在时以 `FS_NOT_OBSERVED` 拒绝(这是策略为未观察 owner 使用的路径);`replaceIfVersion` 仅在目标处于已观察版本时替换,否则 `FS_STALE_VERSION`;省略期望则为无条件的裸提供方创建或覆盖。策略插件根据 owner 的已观察状态选择提供哪个期望。 +全文件写入创建或替换 UTF-8 文本文件。后端在支持且有文档说明时可以创建父目录。已有的非常规目标被拒绝。`writeText` 接受一个可选期望:`createIfAbsent` 创建缺失的目标并拒绝已存在的(报 `FS_NOT_OBSERVED`,这是策略为未观测 owner 使用的路径);`replaceIfVersion` 仅在目标处于观测版本时替换,否则报 `FS_STALE_VERSION`;省略期望则为无条件的裸提供方创建或覆盖。策略插件根据 owner 的观测状态选择提供哪个期望。 -字面编辑是提供方原语(`editText`),而非在 `tool-fs` 中由读取加写入组合而成。字面匹配、重复匹配拒绝、CRLF 保留、二进制拒绝、可选的过期版本检查和原子读-改-写必须一起留在后端的变更临界区内。`editText` 接受相同的可选版本期望;过期检查在字面匹配之前运行,因此针对旧读取的编辑会报告 `FS_STALE_VERSION`。远程后端可以将编辑实现为原生的 compare-and-edit 操作;消费方不强制本地式组合。 +字面编辑是提供方原语(`editText`),而非在 `tool-fs` 中由读取加写入组合而成。字面匹配、重复匹配拒绝、CRLF 保留、二进制拒绝、可选的过期版本检查和原子读-改-写必须一起留在后端的变更临界区内。`editText` 接受相同的可选版本期望;过期检查在字面匹配之前运行,因此基于旧读取的编辑会报 `FS_STALE_VERSION`。远程后端可以将编辑实现为原生的 compare-and-edit 操作;消费方不强制本地风格的组合。 -策略插件(而非 `ctx.fs`)对先前观察进行门控:`edit` 要求 owner 有先前观察(否则 `FS_NOT_OBSERVED`),记录的版本作为 CAS 基础传递给 `editText`。在策略插件缺席时,`ctx.fs` 单独是一个完整的无约束 seam(无条件写入/编辑);工具从不与策略方法耦合。 +策略插件(而非 `ctx.fs`)对先前观测进行门控:`edit` 要求 owner 有先前观测(否则报 `FS_NOT_OBSERVED`),记录的版本作为 CAS 基础传给 `editText`。在策略插件缺席时,`ctx.fs` 本身是一个完整的无约束 seam(无条件写入/编辑);工具从不与策略方法耦合。 -文件系统契约失败以 `FsError extends HarnessError` 抛出,工具注册表将其转换为带结构化 `{ name, code }` 元数据的 `isError` 工具结果。`dsh-fs` 拥有此词汇,而非由每个工具各自发明消息。错误码为 `FS_NOT_FOUND`、`FS_NOT_TEXT`、`FS_STALE_VERSION`、`FS_NOT_OBSERVED`、`FS_NOT_REGULAR_FILE`、`FS_AMBIGUOUS_EDIT`、`FS_EDIT_NOT_FOUND` 和 `FS_ABORTED`。(早期草案包含 `FS_PARTIAL_OBSERVATION`;基于新鲜度的授权没有 partial/full 区分,因此已移除。目录列表相关的错误码后来由 [Add direct directory listing to the filesystem seam](2026-07-03-filesystem-directory-listing-seam.md) 添加。) +文件系统契约失败以 `FsError extends HarnessError` 抛出,工具注册表将其转换为带结构化 `{ name, code }` 元数据的 `isError` 工具结果。`dsh-fs` 拥有此词汇,而非由每个工具各自发明消息。错误码包括 `FS_NOT_FOUND`、`FS_NOT_TEXT`、`FS_STALE_VERSION`、`FS_NOT_OBSERVED`、`FS_NOT_REGULAR_FILE`、`FS_AMBIGUOUS_EDIT`、`FS_EDIT_NOT_FOUND` 和 `FS_ABORTED`。(早期草案包含 `FS_PARTIAL_OBSERVATION`;基于新鲜度的授权没有 partial/full 区分,因此已删除。目录列表相关的错误码后来由 [Add direct directory listing to the filesystem seam](2026-07-03-filesystem-directory-listing-seam.md) 添加。) ## 工具消费方行为 @@ -105,7 +105,7 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` - `read`:检查一个 UTF-8 文本文件并返回带行号的内容与分页引导。 - `write`:创建或完全替换一个 UTF-8 文本文件。 -- `edit`:通过替换字面文本更新一个已存在的 UTF-8 文本文件,默认要求唯一匹配,并允许显式的全部替换模式。 +- `edit`:通过替换字面文本更新一个已有的 UTF-8 文本文件,默认要求唯一匹配,并允许显式的全部替换模式。 每个工具遵循相同的执行形态: @@ -114,47 +114,47 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 3. 将结果格式化为面向模型的 `ContentBlock[]`。 4. 让抛出的后端/工具错误流经 `ToolRegistry.execute()`,由其转换为 `isError` 工具结果。 -该包通过 `ctx.systemPrompt.section(...)` 注册提示词引导,通过 `ctx.tools.register(...)` 注册 schema。工具 schema 仍通过 `SystemPrompt.assemble()` 和 `ToolRegistry.schemas()` 流入正常的提示词组装路径;无需修改 agent loop。 +该包通过 `ctx.systemPrompt.section(...)` 注册提示词引导,通过 `ctx.tools.register(...)` 注册 schema。工具 schema 仍通过 `SystemPrompt.assemble()` 和 `ToolRegistry.schemas()` 流入正常的提示词组装路径;无需改动 agent loop(智能体循环)。 -工具包在后端变化时保持面向模型的契约稳定:本地后端和远程后端内部可能以不同方式解析路径,但 `read` / `write` / `edit` 的 schema 不会仅因后端变化而改变。 +工具包在后端变化时保持面向模型的契约稳定:本地后端和远程后端内部可能以不同方式解析路径,但 `read` / `write` / `edit` schema 不会仅因后端变化而改变。 -默认部署要求在用 `write` 或 `edit` 更新已存在文件之前先 `read`。`tool-fs` 不通过检查名为 `read` 的工具是否运行过来实现这一点:它分发 `fs/write-intent`/`fs/edit-intent` 事件(将执行上下文作为不透明 actor 传递),`dsh-fs-policy` 插件推导 owner、对先前观察进行门控并提供版本期望。任何窗口读取都能授权后续的写入/编辑,只要文件未变。用 `write` 创建新文件不要求先前观察。 +默认部署要求在用 `write` 或 `edit` 更新已有文件之前先 `read`。`tool-fs` 不通过检查是否运行过名为 `read` 的工具来实现这一点:它分发 `fs/write-intent`/`fs/edit-intent` 事件(将执行上下文作为不透明 actor 传递),`dsh-fs-policy` 插件推导 owner、对先前观测进行门控并提供版本期望。任何窗口化读取都能授权后续的写入/编辑,只要文件未变。用 `write` 创建新文件不要求先前观测。 根插件通过组合各工具的注册辅助函数来注册完整套件。它注入 `fs`、`tools` 和 `systemPrompt`。 ## 测试 -测试遵循包边界,而非仅覆盖用户可见的工具:`dsh-fs` 中的服务 seam;`dsh-fs-local` 中通过 `ctx.fs` 接口的真实文件系统行为(解析、符号链接、流式传输、二进制/UTF-8 拒绝、无条件与版本守护写入、字面编辑语义、行尾保留、结构化 `FsError` 错误码);`dsh-tool-fs` 中针对真实本地提供方的消费方接口(仅 mock 模型/时钟,从不 mock 协作者);以及通过 `ctx.tools.execute()` 在有无 `dsh-fs-policy` 两种情况下的集成测试,通过从磁盘回读文件来验证世界状态,而非信任返回的 `ContentBlock[]`。已观察状态/owner 推导策略在 `dsh-fs-policy` 中测试,不在此处。 +测试遵循包边界,而不仅是用户可见的工具:`dsh-fs` 中的服务 seam;`dsh-fs-local` 中通过 `ctx.fs` 接口测试的真实文件系统行为(解析、符号链接、流式传输、二进制/UTF-8 拒绝、无条件和版本守护的写入、字面编辑语义、行尾保留、结构化 `FsError` 错误码);`dsh-tool-fs` 中基于真实本地提供方的消费方接口(只 mock 模型/时钟,从不 mock 协作者);以及通过 `ctx.tools.execute()` 在有和没有 `dsh-fs-policy` 的情况下进行集成测试,通过从磁盘回读文件来验证世界状态,而非信任返回的 `ContentBlock[]`。观测状态/owner 推导策略在 `dsh-fs-policy` 中测试,不在此处。 本仓库曾踩过的防御性模式类别被直接固定: -- **原子写入临时文件安全。** 写入/编辑通过目标旁边一个私有随机 `0700` 目录中的独占 owner-only(`'wx'`、`0o600`)临时文件暂存,失败时清理,最后原子 rename。这与 bash spill-file 规则一致,因为可预测的 world-readable 临时路径招致符号链接竞争和信息泄露。测试断言权限以及已存在的临时路径不会被覆盖;此原语是 seam 的常设要求。 -- **通过符号链接的 `targetKey` 同一性。** 两个输入路径解析到同一 realpath 时共享一个已观察状态条目:通过路径 A 的 `read` 满足通过符号链接路径 B 的 `edit` 的先读守护,通过一个路径的过期写入可通过另一个路径检测到。 -- **并发/过期竞争。** 两个并发的写入/编辑操作针对同一目标确定性地结算:一个成功,另一个以 `FS_STALE_VERSION` 被拒绝;成功的编辑刷新记录状态,使同一 owner 的下一次编辑可以继续。 -- **HMR 安全与 dispose。** 释放后端的 fiber 会撤回 `ctx.fs` 提供方;后续提供方启动时没有继承的状态。 +- **原子写入临时文件安全。** 写入/编辑通过目标旁边一个私有随机 `0700` 目录中的独占 owner-only(`'wx'`、`0o600`)临时文件暂存,失败时清理,最后原子 rename——与 bash 溢出文件规则一致,因为可预测的 world-readable 临时路径招致符号链接竞争和信息泄露。测试断言权限,并断言已存在的临时路径不会被覆盖;此原语是 seam 的常设要求。 +- **通过符号链接的 `targetKey` 同一性。** 两个输入路径解析到同一 realpath 时共享一个观测状态条目:通过路径 A 的 `read` 满足通过符号链接路径 B 的 `edit` 的读后编辑守护,通过一个路径的过期写入可通过另一个路径检测到。 +- **并发/过期竞争。** 对同一目标的两个并发写入/编辑操作确定性地收敛——一个成功,另一个被 `FS_STALE_VERSION` 拒绝——成功的编辑刷新记录状态,使同一 owner 的下一次编辑可以继续。 +- **HMR(热模块替换)安全与 dispose(资源释放)。** dispose 后端的 fiber 会撤回 `ctx.fs` 提供方;后续的提供方以无继承状态启动。 ## 曾考虑的替代方案 -- **面向模型的工具直接使用 `node:fs`**:工具包将同时拥有执行策略、路径解析、原子写入、文本解码和编辑语义,耦合了「问题」一节所列的三个独立变化的关注点,且任何后端替换都会搅动 schema。 -- **单一合并包 `dsh-fs-tools`**:seam 之前的形态;出于与 bash 相同的接口/实现/消费方拆分理由被否决,且合并名称从未成为公开接口。 -- **已观察状态放在 `ctx.fs` 上**:本 RFC 最初落地的形态;被 [split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate RFC](2026-06-26-file-context-as-event-gate.md) 取代:沙箱/远程后端不应继承面向模型的观察策略,因此提供方仅保留版本令牌和可选的版本守护变更。 +- **面向模型的工具直接基于 `node:fs`**:工具包将同时承担执行策略、路径解析、原子写入、文本解码和编辑语义,耦合问题部分所列的三个独立变化的关注点,且任何后端替换都会搅动 schema。 +- **单一合并包 `dsh-fs-tools`**:seam 之前的形态;以与 bash 相同的接口/实现/消费方拆分理由否决,且合并名称从未成为公开接口。 +- **观测状态放在 `ctx.fs` 上**:本 RFC 最初落地的形态;被 [split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate RFC](2026-06-26-file-context-as-event-gate.md) 取代:沙箱/远程后端不应继承面向模型的观测策略,因此提供方只保留版本令牌和可选的版本守护变更。 ## 后果 -**`cwd` 可能被误认为沙箱。** 本地后端的基础目录是解析默认值,而非自动的隔离边界。如果需要隔离,必须由后端契约或 `tools/execute` 上的权限/沙箱插件强制执行。 +**`cwd` 可能被误认为沙箱。** 本地后端的基目录是解析默认值,而非自动的隔离边界。如果需要隔离,必须由后端契约或 `tools/execute` 上的权限/沙箱插件强制执行。 -**接口可能变得过于本地化。** 如果 `ctx.fs` 返回 `absolutePath` 之类的字段,远程、沙箱或虚拟后端会变得尴尬。契约应暴露展示元数据,而不要求消费方理解宿主路径。 +**接口可能变得过于本地化。** 如果 `ctx.fs` 返回 `absolutePath` 之类的字段,远程、沙箱或虚拟后端会变得尴尬。契约应暴露显示元数据,而不要求消费方理解宿主路径。 -**接口可能变得过于薄。** 如果 `ctx.fs` 只镜像 `node:fs` 原语,`tool-fs` 将重新实现二进制检测、分页、原子写入和编辑语义。这会重新制造本 RFC 试图避免的耦合。 +**接口可能变得过于薄。** 如果 `ctx.fs` 只镜像 `node:fs` 原语,`tool-fs` 将重新实现二进制检测、分页、原子写入和编辑语义,重新制造本 RFC 试图避免的耦合。 -**编辑语义天然易受竞争影响。** 字面编辑是读-改-写操作;守护是后端的原子变更临界区加上可选的版本期望,因此并发编辑确定性地结算:一个赢,另一个得到 `FS_STALE_VERSION`。 +**编辑语义天然易受竞争影响。** 字面编辑是读-改-写操作;守护手段是后端的原子变更临界区加上可选的版本期望,因此并发编辑确定性地收敛——一个赢,另一个得到 `FS_STALE_VERSION`。 -**已观察状态不属于 `ctx.fs`。** 记录执行上下文看到了什么是工作流策略,而非原始文件系统 I/O。本 RFC 最初将其放在文件系统 seam 内;split-fs-seam RFC 随后确立:沙箱/远程后端不应继承面向模型的观察策略,并将其移入 `dsh-fs-policy` 插件。提供方 seam 仅保留写入/编辑安全在存储层真正需要的东西——后端铸造的版本令牌和可选的版本守护变更——而策略插件拥有 owner 推导、已观察状态和先读后编辑门控,通过 `fs/*` 事件实现。 +**观测状态不属于 `ctx.fs`。** 记录执行上下文看到了什么是工作流策略,而非原始文件系统 I/O。本 RFC 最初将其放在文件系统 seam 内部;split-fs-seam RFC 随后确立了沙箱/远程后端不应继承面向模型的观测策略,并将其移入 `dsh-fs-policy` 插件。提供方 seam 只保留写入/编辑安全在存储层真正需要的东西——后端铸造的版本令牌和可选的版本守护变更——而策略插件拥有 owner 推导、观测状态和基于 `fs/*` 事件的读后编辑门控。 -**`resolve` 后操作的形态每次调用多一次往返。** 每个工具可能先将路径解析为 `FsTarget`,再作为单独的 `ctx.fs` 调用发起读取/写入/编辑。对本地后端而言这可以忽略(解析是内存中的路径规范化),但远程/沙箱后端可能将每一步变为独立请求,使单次 `read` 变成两次网络往返。往返开销重要的后端可以在内部缓存或折叠解析,同时保持可观察契约不变。 +**`resolve` 然后操作的形态每次调用多一次往返。** 每个工具可能先将路径解析为 `FsTarget`,再以单独的 `ctx.fs` 调用发起读取/写入/编辑。对本地后端来说这可以忽略(解析是内存中的路径规范化),但远程/沙箱后端可能将每步变成独立请求,使单次 `read` 变为两次网络往返。往返开销重要的后端可以在内部缓存或折叠解析,同时保持可观测契约不变。 -**已观察状态持久化被推迟。** 已观察状态存在于内存中(`dsh-fs-policy` 内部的 `WeakMap`),因此恢复的会话保守地要求文件在写入/编辑前重新读取,直到未来的会话事件或持久化机制使观察可回放。 +**观测状态持久化被推迟。** 观测状态存在于内存中(`dsh-fs-policy` 内部的 `WeakMap`),因此恢复的会话保守地要求文件在写入/编辑前重新读取,直到未来的会话事件或持久化机制使观测可回放。 -**错误码成为 seam 的一部分。** `FsError` 错误码使过期版本和观察失败可通过既有的结构化错误分类体系进行机器路由。代价是 `dsh-fs` 从 `dsh-llm` 导入共享的 `HarnessError` 基类;该依赖是有意为之且仅限于错误词汇。 +**错误码成为 seam 的一部分。** `FsError` 错误码使过期版本和观测失败可通过既有的结构化错误分类体系进行机器路由。代价是 `dsh-fs` 从 `dsh-llm` 导入共享的 `HarnessError` 基类;该依赖是有意为之且限于错误词汇。 -**包拆分的代价前置。** 三包拆分在只有一个后端时就增加了样板代码。这是有意为之:文件系统访问是可能的沙箱/远程边界,在面向模型的工具发布后再改变包接口代价更高。 +**包拆分的成本前置。** 三包拆分在只有一个后端时就增加了样板代码。这是有意为之:文件系统访问是可能的沙箱/远程边界,在面向模型的工具发布后再改包接口代价更高。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml index 85783f6ea4..27f4b260ae 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-18-agent-lifecycle-and-ownership-seams.md: a70e7db8d809efd68ae770995795fc7b3d1b83d2 -2026-06-18-agent-lifecycle-and-ownership-seams.zh.md: ac42a09c70e9570d3def0f0bd056bd571b923315 +2026-06-18-agent-lifecycle-and-ownership-seams.zh.md: 3fb68336c56b5296f18b3587ea42399a05362733 diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md index ac42a09c70..3fb68336c5 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md @@ -1,12 +1,12 @@ # RFC:Agent 生命周期与所有权 seam -Status: implemented - [English](2026-06-18-agent-lifecycle-and-ownership-seams.md) | 中文 +Status: implemented + ## 问题 -ACP(Agent Client Protocol)与 tool-bash 的若干限制是同一个缺失 seam 的不同症状:插件可以通过 `ctx.agents` 创建或恢复 agent,但无法独立拥有并 dispose(资源释放)单个 agent;长时间运行的 bash 任务在执行器内部也没有稳定的所有者。ACP 在断开连接时中止并等待 agent,却无法只注销该会话的 agent;`session/cancel` 无法取消已排队但尚未开始的工作;`tool-bash` 将任务所有权保存在插件本地的 `Map` 中,因此一次 HMR(热模块替换)重载就可能让旧任务看起来无主。 +ACP(Agent Client Protocol)与 tool-bash 的若干限制是同一个缺失 seam 的症状:插件可以通过 `ctx.agents` 创建或恢复 agent(智能体),但无法独立拥有和 dispose(资源释放)单个 agent,而长时间运行的 bash 任务在执行器中也没有稳定的所有者。ACP 在断连时中止并等待 agent,却无法仅注销该会话的 agent;`session/cancel` 无法取消已入队但尚未开始的工作;`tool-bash` 将任务所有权保存在插件本地的 `Map` 中,因此一次 HMR(热模块替换)重载就可能让旧任务看起来无主。 ## 决策 @@ -14,33 +14,33 @@ ACP(Agent Client Protocol)与 tool-bash 的若干限制是同一个缺失 se ### 1. 队列感知的 `Agent.cancel(reason?)` -`cancel()` 是唯一的公开停止原语。它清除已排队的输入和 steering(中途引导)输入,中止正在执行的步骤,并设置一个在每个轮次边界检查的轮次作用域标记。因此,已排队的提示词在取消后无法启动,也无法吸收后续输入。`whenIdle()` 等待取消后的静默状态,ACP 的 `session/cancel` 映射到此方法。对空闲 agent 的 cancel 不设置标记。 +`cancel()` 是唯一的公开停止原语。它清除已入队和 steering(中途引导)输入、中止正在进行的步骤,并设置一个在每个轮次边界检查的轮次作用域标记。因此,已入队的 prompt 在取消后无法启动,也无法吸收后续输入。`whenIdle()` 等待取消后的静默状态,ACP 的 `session/cancel` 映射到此方法。对空闲状态的 cancel 不设置标记。 ### 2. `AgentHandle` 异步释放器 -`ctx.agents.create`/`resume` 与 `AgentFactory` 返回 `AgentHandle = { agent, dispose() }`。释放是消费方的能力;仅持有 `Agent` 的观察者无法拆除它。调用方 fiber 和 factory 提供方也拥有该实例,所有路径共享同一个 memoized 的拆除流程:停止循环、等待静默与 flush 完成、分离 agent 和会话,然后回收其 scope。注册表条目分离后 ID 即可复用。由配置创建的 agent 归 loop fiber 所有;ACP 存储并 dispose 每个会话的 handle。 +`ctx.agents.create`/`resume` 和 `AgentFactory` 返回 `AgentHandle = { agent, dispose() }`。释放是消费方的能力;仅持有 `Agent` 的观察者无法将其拆除。调用方 fiber 和 factory 提供方也拥有该实例,所有路径共享一个 memoize 的拆除过程:停止循环、等待静默与刷写完成、分离 agent 和会话,然后解除其 scope。ID 在注册表条目分离后变为可复用。由配置创建的 agent 归 loop fiber 所有;ACP 存储并 dispose 每个会话的 handle。 -拆除顺序对持久性至关重要。会话生命周期与循环共享一个复合 Cordis effect,因此 LIFO 释放先停止循环并等待 `agent.done`,再分离会话。如果使用兄弟 effect,它们会并发释放,可能在关闭 flush 之前移除 append 钩子。释放通知被隔离,不会中断拆除链。 +拆除顺序对持久性至关重要。会话生命周期与循环共享一个复合 Cordis effect,因此 LIFO 释放会先停止循环并等待 `agent.done`,然后再分离会话。若使用兄弟 effect,则会并发释放,可能在关闭刷写之前就移除 append 钩子。释放通知被隔离,不会中断拆除链。 -### 3. Bash 所有者令牌置于 seam 中 +### 3. Bash seam 中的所有者令牌 -后台任务的所有权归执行器持有。`BashExecSpec.owner` 携带一个可选的不透明令牌,`ownerOf(id)` 读取它,`dsh-tool-bash` 在启动时盖上调用方的会话令牌。`bash_output` 与 `bash_kill` 拒绝不匹配的调用方;完成通知通过注册表按会话令牌定位存活的 agent。将所有权保留在任务上,使得这道围栏在工具插件重载后依然有效。完成监听器仍然是 effect 作用域的,因此在重载间隙到达的通知仍可能被丢弃。 +后台任务的所有权属于执行器。`BashExecSpec.owner` 携带一个可选的不透明令牌,`ownerOf(id)` 读取它,`dsh-tool-bash` 在启动时盖上调用方的会话令牌。`bash_output` 和 `bash_kill` 拒绝不匹配的调用方;完成通知通过注册表按会话令牌定位存活的 agent。将所有权保存在任务上,使得这道隔离在工具插件重载后依然有效。完成监听器仍然是 effect 作用域的,因此在重载间隙到达的通知仍可能被丢弃。 ## 验证 -- ACP 断开连接或会话关闭后,不留下任何已注册的 agent 或 session-store 条目,包括 `session/load` 与拆除竞争的情况。 -- 在已排队的提示词启动前取消,能阻止该提示词运行或吸收下一条提示词。 +- ACP 断连或会话关闭后,不留下任何已注册的 agent 或 session-store 条目,包括 `session/load` 与拆除竞争的情况。 +- 在已入队的 prompt 启动前取消,能阻止该 prompt 运行或吸收下一条 prompt。 - 重载 `dsh-tool-bash` 不会让另一个会话读取或终止已有的后台任务,因为所有权保留在执行器上。 -- 由配置创建的 agent 仍归 loop fiber 所有,因此非 ACP 的演示无需显式管理 handle。 +- 由配置创建的 agent 仍归 loop fiber 所有,因此非 ACP 演示无需显式管理 handle。 ## 会话所有者令牌在存活 agent 中唯一 -bash 所有者令牌依赖 `session.header.id` 在存活 agent 中的唯一性。并发的同 ID 操作可以私下准备,但 `SessionStore.enter()` 拒绝重复发布,失败的事务会回滚。`tool-bash` 拥有比较策略;bash seam 存储一个不透明的 `owner` 字符串,不对其做解释。 +bash 所有者令牌依赖 `session.header.id` 在存活 agent 中的唯一性。并发的同 ID 操作可以私下准备,但 `SessionStore.enter()` 拒绝重复发布,失败的事务回滚。`tool-bash` 拥有比较策略;bash seam 存储一个不透明的 `owner` 字符串,不对其做解释。 ## 曾考虑的替代方案 - **公开的 `BashTask.owner` 字段**而非 `BashExecutor.ownerOf(id)` seam:否决。一条读取路径即可,无需冗余 API。 -- **为 agent 的会话生命周期使用兄弟 Cordis effect**:否决。fiber 卸载时兄弟 effect 并发释放(`Promise.all`),store 持有的 append 发布钩子的移除与循环的关闭 `session/flush` 产生竞争;单一复合 effect 的有序 LIFO 链才能在两条释放路径上都捕获关闭的 `turn/end`。 +- **为 agent 的会话生命周期使用兄弟 Cordis effect**:否决。fiber 卸载时并发释放兄弟 effect(`Promise.all`),store 拥有的 append 发布钩子的移除与循环的关闭 `session/flush` 产生竞争;单一复合 effect 的有序 LIFO 链才能在两条释放路径上都捕获关闭的 `turn/end`。 - **在 `cancel()` 之外另设一个仅中止步骤的 `abort()`**:最初发布过,后因无人使用而移除;`cancel()` 是唯一的公开停止原语(见[公开停止接口 RFC](../simplification/2026-06-20-public-agent-stop-surface.md))。 ## 后果 diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml index 0e2a4891d9..98b4ee0e59 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-18-session-surface.md: 31297166b735468147850a81d7fd43a8fa30a1e8 -2026-06-18-session-surface.zh.md: 9e2933a1e564b3dbb7719d55b5264f670c3b833f +2026-06-18-session-surface.zh.md: 159aefc10261ac5380701f46c3d4a367674940b1 diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md b/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md index 9e2933a1e5..159aefc102 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md @@ -1,22 +1,22 @@ -# RFC:Session surface——基于事件日志的链表,用于 LLM 消息推导 - -Status: implemented +# RFC:会话 surface——基于事件日志的链表,用于 LLM 消息派生 [English](2026-06-18-session-surface.md) | 中文 +Status: implemented + ## 问题 -事件日志是权威数据源,但历史操作此前没有持久化的共享机制。如果没有这样的机制,上下文压缩(context compaction)等插件只能通过顺序敏感的监听器改写派生请求,不留溯源记录,且每次新增操作都要修改 `deriveMessages()`。 +事件日志是权威数据源,但历史操纵此前没有持久化的共享机制。如果没有这样的机制,上下文压缩(context compaction)等插件只能通过顺序敏感的监听器改写派生请求,不留溯源信息,且每次新增操纵都要反复修改 `deriveMessages()`。 ## 决策 -新增一个 **surface**:一条从事件日志派生、带缓存的链表,由「surface 节点」(即产出 LLM 消息的那部分事件)组成,通过事件日志中的 `surfaceOp` 标记维护。 +新增一个 **surface**:一条派生的、缓存的链表,由「surface 节点」(事件中产出 LLM(大语言模型)消息的子集)组成,通过事件日志中的 `surfaceOp` 标记维护。 -### `SessionEvent` 上的两个新顶层字段 +### `SessionEvent` 新增两个顶层字段 -每个 `SessionEvent` 新增两个可选字段(与 `seq`/`time` 同属结构元数据): +每个 `SessionEvent` 获得两个可选字段(结构性元数据,与 `seq`/`time` 同级): -- **`sourceEventSeqs?: number[]`**:作为溯源来源的事件 seq 编号(例如:构成 `assistant/message` 的各 `assistant/chunk` 的 seq,或被压缩标记遮蔽的 surface 节点)。溯源是核心设计原则;没有它,replace-range 操作在回放时无法被验证。 +- **`sourceEventSeqs?: number[]`**:作为溯源来源的事件 seq 编号(例如构成 `assistant/message` 的各 `assistant/chunk` 的 seq,或被压缩标记遮蔽的 surface 节点)。溯源是核心设计原则;没有它,replace-range 操作在回放时无法被验证。 - **`surfaceOp?: SurfaceOp`**:该事件如何进入 surface。非 surface 事件不携带此字段。 ### SurfaceOp:两种操作 @@ -27,45 +27,45 @@ export type SurfaceOp = | { op: 'replace'; start: number; end: number } // shadow [start, end] inclusive ``` -1. **Append**:在尾部追加一个新节点。`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message` 使用此操作。agent loop 在所有此类追加上传入 `surfaceOp: 'append'`,并在适用时附带 `sourceEventSeqs`(例如 `assistant/message` 记录其 `assistant/chunk` 来源;`tool/result` 记录其 `tool/call` 来源)。 +1. **Append**:在尾部追加一个新节点。`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message` 使用此操作。agent loop(智能体循环)在所有此类追加上传入 `surfaceOp: 'append'`,并在适用时附带 `sourceEventSeqs`(例如 `assistant/message` 记录其 `assistant/chunk` 来源;`tool/result` 记录其 `tool/call` 来源)。 -2. **Replace**:移除从 `start` 到 `end`(两端含)的节点,并在其位置插入一个新节点。`start` 和 `end` 都必须是当前 surface 上有效的 surface 节点 seq;`start === end` 表示替换单个节点。该节点的 `sourceEventSeqs` 必须包含所有被遮蔽的 surface 节点。被遮蔽的事件仍保留在日志中,但不再出现在 surface 上。 +2. **Replace**:移除从 `start` 到 `end`(两端包含)的节点,并在其位置插入一个新节点。`start` 和 `end` 都必须是当前 surface 上有效的 surface 节点 seq;`start === end` 表示替换单个节点。该节点的 `sourceEventSeqs` 必须包含所有被遮蔽的 surface 节点。被遮蔽的事件仍留在日志中,但不再出现在 surface 上。 ### SurfaceManager:基于增量,而非全量重建 -`SurfaceManager` 类(`Session` 的私有实现)维护缓存的链表。它跟踪 `_lastProcessedSeq`,仅处理**增量**(上次访问以来的新事件),而非重新扫描整个日志。由于日志是仅追加的,先前事件不会改变;种子日志只是在首次访问时折叠的初始增量。 +`SurfaceManager` 类(`Session` 私有)维护缓存的链表。它跟踪 `_lastProcessedSeq`,仅处理**增量**(自上次访问以来的新事件),而非重新扫描整个日志。由于日志是仅追加的,先前的事件不会改变;种子日志只是在首次访问时折叠的初始增量。 无新事件时增量处理为 O(1),有新事件到达时为 O(新事件数)。 -`deriveMessages()` 在存在 surface 标记时使用 surface,否则回退到既有的线性扫描(向后兼容)。 +`deriveMessages()` 在存在 surface 标记时使用 surface,对没有标记的会话回退到既有的线性扫描(向后兼容)。 ### 持久化 -新字段作为顶层 JSON 属性序列化。JSONL 后端无需任何修改:`JSON.stringify`/`JSON.parse` 透明地保留一切。SQLite 后端的 `events` 表新增两个可空 TEXT 列(`source_event_seqs`、`surface_op`)。磁盘上的 `SCHEMA_VERSION` 递增以反映列集变化,并且按照预发布的 bump-and-reject 策略,由其他构建写入的数据库在打开时被拒绝,而非迁移(没有需要升级的持久化用户数据)。会话格式 `version` 固定为 `SESSION_FORMAT_VERSION = 0`(「不稳定/预发布」立场):可选的 surface 字段被吸收而不递增版本号。 +新字段作为顶层 JSON 属性序列化。JSONL 后端无需任何改动:`JSON.stringify`/`JSON.parse` 透明地保留一切。SQLite 后端的 `events` 表新增两个可空 TEXT 列(`source_event_seqs`、`surface_op`)。磁盘上的 `SCHEMA_VERSION` 递增以反映列集变化,并且按照预发布的 bump-and-reject 策略,由其他构建写入的数据库在打开时被拒绝而非迁移(没有需要升级的持久化用户数据)。会话格式 `version` 固定为 `SESSION_FORMAT_VERSION = 0`(「不稳定/预发布」立场):可选的 surface 字段被吸收而不递增版本号。 ### 崩溃恢复 -`repair.ts` 模块在崩溃后为孤立的工具调用合成 `tool/result` 关闭事件。这些关闭事件携带 `surfaceOp: 'append'` 和指向孤立 `tool/call` 事件的 `sourceEventSeqs`,确保重建后的 surface 有效。 +`repair.ts` 模块在崩溃后为孤立的工具调用合成 `tool/result` 闭合事件。这些闭合事件携带 `surfaceOp: 'append'` 和指向孤立 `tool/call` 事件的 `sourceEventSeqs`,确保重建的 surface 有效。 ### 不变式 -开发模式不变式插件验证:`sourceEventSeqs` 引用(非空、无重复、引用更早的事件、引用已知 seq)以及 `surfaceOp`(replace 的 `start ≤ end`、两个端点都在被跟踪的 surface 上、范围在 surface 位置上不反转、`sourceEventSeqs` 包含该范围遮蔽的每个节点)。 +开发模式下的不变式插件验证:`sourceEventSeqs` 引用(非空、无重复、引用更早的事件、引用已知 seq)以及 `surfaceOp`(replace 的 `start ≤ end`、两个端点都在被跟踪的 surface 上、范围在 surface 位置上不反转、`sourceEventSeqs` 包含该范围遮蔽的每个节点)。 -每个 surface 可达事件都必须携带 `surfaceOp`,否则它会从派生历史中消失。类型化的 `append` 重载对字面事件类型强制执行此要求;`append` 和种子构造函数中的运行时检查覆盖了宽化联合类型和加载的日志。无效种子在预发布格式策略下被拒绝而非升级。 +每个 surface 可达事件都必须携带 `surfaceOp`,否则它将从派生历史中消失。类型化的 `append` 重载对字面事件类型强制执行此规则;`append` 和种子构造函数中的运行时检查覆盖宽化联合类型和加载的日志。按照预发布格式策略,无效的种子被拒绝而非升级。 ## 曾考虑的替代方案 -- **逐插件的 `agent/request` 包装**(surface 之前的历史操作模式):监听器排序脆弱,不留持久化的变更记录,且每次新增操作都要修改核心 `deriveMessages()`。 +- **逐插件的 `agent/request` 包装**(surface 之前的历史操纵模式):监听器排序脆弱、无法持久记录改动内容,且每种新操纵都迫使核心 `deriveMessages()` 再次修改。 - **半开区间 `[start, endExclusive)` 的 replace 范围**:否决。surface 是双向链表,端点自然以节点 seq 命名,单节点替换(`start === end`)在闭区间语义下读起来更自然。 -- **脏标记触发全量重建**而非增量处理:在会话生命周期内为 O(N²)——每次单事件追加都要重新扫描所有先前事件。 +- **脏标记后全量重建**替代增量处理:在会话生命周期内为 O(N²),每次单事件追加都要重新扫描所有先前事件。 ## 后果 -- **`packages/core/session`**:新增 `surface.ts`(`SurfaceManager`)、新类型(`SurfaceOp`、`SurfaceIntent`)、`SessionEvent` 上的新字段、修改 `append()`(第三个必需参数 `SurfaceIntent`)、重构 `deriveMessages()`(以 surface 遍历作为唯一推导路径)、surface 感知的 `repair.ts`。种子构造函数拒绝缺少 `surfaceOp` 标记的 surface 可达种子事件(见「不变式」一节)。 -- **`packages/core/agent-loop`**:所有 surface 可达的追加传入 surface 选项。收集 chunk seq 用于 `assistant/message` 溯源;捕获 `tool/call` seq 用于 `tool/result` 溯源。 +- **`packages/core/session`**:新增 `surface.ts`(`SurfaceManager`)、新类型(`SurfaceOp`、`SurfaceIntent`)、`SessionEvent` 新字段、修改 `append()`(第三个必选参数 `SurfaceIntent`)、重构 `deriveMessages()`(以 surface 遍历作为唯一派生路径)、surface 感知的 `repair.ts`。种子构造函数拒绝缺少 `surfaceOp` 标记的 surface 可达种子事件(见「不变式」一节)。 +- **`packages/core/agent-loop`**:所有 surface 可达的追加操作传入 surface 选项。收集 chunk seq 用于 `assistant/message` 溯源;捕获 `tool/call` seq 用于 `tool/result` 溯源。 - **`packages/session-persistence/session-persistence-sqlite`**:`events` 表新增两个可空 TEXT 列(`source_event_seqs`、`surface_op`);`SCHEMA_VERSION` 递增(bump-and-reject,无迁移)。 -- **`packages/support/invariants`**:surface 相关的验证规则。 -- **`packages/session-persistence/session-persistence-jsonl`**:无需修改。 +- **`packages/support/invariants`**:surface 相关验证规则。 +- **`packages/session-persistence/session-persistence-jsonl`**:无需改动。 - **`packages/session-persistence/session-persistence`**:抽象接口不变。 -Surface 是未来历史操作的基础。压缩或 tool-result-prune 插件追加一个既有的消息产出事件类型(例如一条携带摘要的 `user/message`),附带 `surfaceOp: { op: 'replace', start, end }` 和覆盖被遮蔽节点的 `sourceEventSeqs`——新节点取代该范围在 surface 上的位置,而插件自身的跟踪事件(如 `compaction/start`、`compaction/end`)则不进入 surface。回放确定性地保留这一决策。 +Surface 是未来历史操纵的基础。压缩或 tool-result-prune 插件追加一个既有的消息产出事件类型(例如一条携带摘要的 `user/message`),附带 `surfaceOp: { op: 'replace', start, end }` 和覆盖被遮蔽节点的 `sourceEventSeqs`——新节点在 surface 上取代该范围的位置,而插件自身的 trace 事件(如 `compaction/start`、`compaction/end`)不进入 surface。回放以确定性方式保留该决策。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml index 566ce4ae59..f693539b91 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-18-shared-persistence-write-coordinator.md: 3fc30dc2e1382fd983d050433123f46a2cd0ed19 -2026-06-18-shared-persistence-write-coordinator.zh.md: 6c8ccef8dd5603d837dd0a9884adf9c1cd8a17d4 +2026-06-18-shared-persistence-write-coordinator.zh.md: 38e900d38cc48317836717ddeda5323cf97df993 diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md index 6c8ccef8dd..38e900d38c 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md @@ -1,44 +1,44 @@ # RFC:共享持久化写入协调器 -Status: implemented - [English](2026-06-18-shared-persistence-write-coordinator.md) | 中文 +Status: implemented + ## 问题 -`dsh-session-persistence-jsonl` 与 `dsh-session-persistence-sqlite` 有意在不同存储介质上证明同一份 `SessionPersistence` 契约,但二者的写入路径编排是重复的:per-session 状态、`session/created` 接管、后端特定的前缀读取、write-behind 缓冲区、串行化 flush 链、HMR(热模块替换)种子注入,以及 dispose(资源释放)排空。纯粹的种子前缀冲突与可串行化守卫已经迁入 seam 包;剩余的编排仍然是正确性密集的,并且相同的修复被应用了两次。代码级 diff 表明两个后端在**所有**这些逻辑上是逐字节一致或同算法的:四个 map(`states`/`buffers`/`chains`/`inits`)、`installWritePath`、`initFor`、`onCreated` 的四种分支、`flush`、`drain`、`serialize`、`adopt`、`adoptLivePrefix`、`assertVersion`,以及 `create`/`append`/`load` 骨架。唯一不同的只有存储原语(写字节 vs. INSERT 行)。 +`dsh-session-persistence-jsonl` 与 `dsh-session-persistence-sqlite` 有意在不同存储介质上证明同一份 `SessionPersistence` 契约,但它们的写入路径编排是重复的:per-session 状态、`session/created` 接管、后端特定的前缀读取、write-behind 缓冲区、序列化的 flush 链、HMR(热模块替换)种子注入与 dispose(资源释放)排空。纯粹的种子前缀碰撞检查与可序列化守卫已迁入 seam 包;剩余的编排仍然对正确性要求很高,且同样的修复被应用了两次。代码级 diff 表明两个后端在**全部**这些逻辑上要么字节相同、要么算法相同:四个 map(`states`/`buffers`/`chains`/`inits`)、`installWritePath`、`initFor`、`onCreated` 的四种分支、`flush`、`drain`、`serialize`、`adopt`、`adoptLivePrefix`、`assertVersion`,以及 `create`/`append`/`load` 的骨架。唯一的差异在于存储原语(写字节 vs. INSERT 行)。 ## 决策 -将一个后端无关的 `PersistenceCoordinator` 提取到 `dsh-session-persistence` 中。协调器统一拥有编排逻辑;每个第一方后端组合一个实例(`new PersistenceCoordinator(ctx, this)`),实现一个小型 `PersistenceBackend` 钩子接口,并将其四个公开服务方法(`create`/`append`/`load`/`list`)委托给协调器。 +将一个后端无关的 `PersistenceCoordinator` 提取到 `dsh-session-persistence` 中。协调器统一拥有编排逻辑;每个第一方后端组合一个协调器实例(`new PersistenceCoordinator(ctx, this)`),实现一个小型 `PersistenceBackend` 钩子接口,并将其四个公开服务方法(`create`/`append`/`load`/`list`)委托给协调器。 -组合,而非继承。协调器是后端持有的具体类,不是后端继承的基类。本 RFC 的风险点——「协调器不得迫使非常规后端与继承层级搏斗」——由此规避:后端只暴露钩子;它无法触及协调器的私有编排状态,且公开的 `SessionPersistence` 服务形状不变,因此第三方后端仍然可以完全不使用协调器、直接实现抽象服务。 +组合,而非继承。协调器是后端持有的具体类,不是后端继承的基类。本 RFC 的风险——「协调器不得让非常规后端与继承层级作斗争」——由此规避:后端只暴露钩子;它无法触及协调器的私有编排状态,且公开的 `SessionPersistence` 服务形状不变,因此第三方后端仍然可以完全不使用协调器、直接实现抽象服务。 ### 钩子接口(`PersistenceBackend<TornMarker>`) -六个方法(五个必需 + 一个可选生命周期钩子)——协调器与存储之间唯一的 seam: +六个方法(五个必需 + 一个可选的生命周期钩子)——协调器与存储之间唯一的 seam: -- `name`:后端标签,用于 dispose 失败时的 `AggregateError`。 -- `loadStored(id)`:按 id 读取已存储的前缀,扫描**任何**存储范围(JSONL 的每个 cwd bucket;SQLite 的 id 全局唯一)。用于恢复/加载,以及通过 `!== undefined` 实现创建冲突探测。 -- `loadLive(id, cwd)`:读取**限定于 `cwd`** 的已存储前缀。**刻意区别于 `loadStored`**:HMR live-adoption 只能接管与活跃会话**相同 cwd** 下的持久化日志;同 id 但不同 cwd 的日志是冲突而非恢复。合并这两个方法会重新引入跨 cwd 接管 bug。SQLite 忽略 `cwd`。 -- `appendBatch(meta, events, isMaterialized)`:持久地追加一个连续批次,在尚未物化时**原子地**惰性物化会话(物化写入与第一个事件批次必须一起提交——崩溃发生在二者之间时不得留下一个已物化但为空的会话;这就是为什么没有单独的 `materialize` 钩子)。 -- `commitRepair(meta, tornMarker, closers)`:使崩溃修复持久化:截断撕裂尾部(当且仅当 `tornMarker !== undefined`)并追加 `closers`。**不要求原子性**——JSONL 合理地分两步 fsync(先截断再追加),SQLite 在一个事务中完成 DELETE+INSERT。用于 `load`(截断 + 合成 closers)和 live-adoption(仅截断,`closers = []`)。 -- `list()`:列出所有已存储的元数据。 -- `close?()`:可选的生命周期清理(SQLite 关闭 db 句柄;JSONL 省略),在 dispose effect 中于静默排空**之后**被 await,确保 close 失败不会掩盖排空错误。 +- `name`——后端标签,用于 dispose 失败时的 `AggregateError`。 +- `loadStored(id)`——按 id 读取已存储的前缀,扫描**任何**存储范围(JSONL 的每个 cwd bucket;SQLite 的 id 全局唯一)。用于恢复/加载,以及通过 `!== undefined` 进行创建碰撞探测。 +- `loadLive(id, cwd)`——读取**限定于 `cwd`** 的已存储前缀。**与 `loadStored` 有意区分**:HMR live-adoption 只能接管与存活会话处于**同一 cwd** 的持久化日志;同 id 但不同 cwd 的日志是碰撞而非恢复。合并二者会重新引入跨 cwd 接管 bug。SQLite 忽略 `cwd`。 +- `appendBatch(meta, events, isMaterialized)`——持久追加一个连续批次,在尚未物化时**原子地**惰性物化会话(物化写入与首批事件必须一起提交——崩溃不得留下一个已物化但为空的会话;这就是为什么没有单独的 `materialize` 钩子)。 +- `commitRepair(meta, tornMarker, closers)`——使崩溃修复持久化:截断损坏的尾部(当且仅当 `tornMarker !== undefined`)并追加 `closers`。**不要求原子性**——JSONL 合理地分两步 fsync(先截断再追加),SQLite 在一个事务中完成 DELETE+INSERT。用于 `load`(截断 + 合成 closers)和 live-adoption(仅截断,`closers = []`)。 +- `list()`——列出所有已存储的元数据。 +- `close?()`——可选的生命周期清理(SQLite 关闭 db 句柄;JSONL 省略),在 dispose effect 中于静默排空**之后**被 await,因此 close 失败不会掩盖排空错误。 -### 不透明的撕裂标记 +### 不透明的 torn marker -保持 seam 干净的唯一设计选择:崩溃修复中的「撕裂尾部在哪里」token 对协调器是**不透明的**。协调器计算合成 closers(它拥有来自 `dsh-session` 的 `interruptedTurnClosers`),但它只测试 `tornMarker !== undefined` 并将值原样传回 `commitRepair`——从不检视其内容。每个后端选择自己的标记类型:JSONL 使用要截断到的字节偏移量,SQLite 使用要从其开始删除的 seq(两者碰巧都是 `number`)。JSONL 后端将其 `committedBytes < buffer.byteLength` 比较**折叠在钩子内部**,因此返回的标记已经是 `number | undefined`;如果不做这个折叠,协调器就必须了解字节长度。 +保持 seam 整洁的唯一设计选择:崩溃修复中「损坏尾部在哪里」的 token 对协调器是**不透明的**。协调器计算合成 closers(它拥有来自 `dsh-session` 的 `interruptedTurnClosers`),但它只测试 `tornMarker !== undefined` 并将值原样传回 `commitRepair`——从不检视其内容。每个后端选择自己的 marker 类型:JSONL 使用要截断到的字节偏移,SQLite 使用要从其开始删除的 seq(两者恰好都是 `number`)。JSONL 后端将其 `committedBytes < buffer.byteLength` 比较折叠**在钩子内部**,因此返回的 marker 已经是 `number | undefined`;如果不做这层折叠,协调器就必须了解字节长度。 ## 测试 -共享的 `runPersistenceContract`(公开 API 契约)继续为每个后端运行。新增的 `runCoordinatorContract`(`tests/coordinator-contract.ts`)覆盖写入路径编排——接管、HMR、冲突、dispose 排空、崩溃尾部修复——通过 `CoordinatorFixture`(内存参考实现 + jsonl + sqlite)为每个后端运行一次。各后端自身的测试缩减为仅覆盖存储机制(JSONL:路径安全、fsync 回滚、bucket 列举;SQLite:schema 版本、`scanRows`、事务回滚)。每个真实后端有一个 through-coordinator 的 torn-tail→load→`commitRepair` 测试(通过 `corruptTail` fixture 钩子),确保协调器的撕裂标记修复分支在 100% per-file 门禁下被覆盖——契约崩溃测试只产生合成 closers 而不产生撕裂标记,因此无法触达该分支。 +共享的 `runPersistenceContract`(公开 API 契约)继续为每个后端运行。新增的 `runCoordinatorContract`(`tests/coordinator-contract.ts`)覆盖写入路径编排——接管、HMR、碰撞、dispose 排空、崩溃尾部修复——通过 `CoordinatorFixture`(内存参考实现 + jsonl + sqlite)为每个后端运行一次。各后端自身的测试规格缩减为仅覆盖存储机制(JSONL:路径安全、fsync 回滚、bucket 列举;SQLite:schema 版本、`scanRows`、事务回滚)。每个真实后端有一个经由协调器的 torn-tail→load→`commitRepair` 测试(通过 `corruptTail` fixture(测试前置数据)钩子),确保协调器的 torn-marker 修复分支在 100% per-file 门禁下被覆盖——契约崩溃测试只产生合成 closers 而不产生 torn marker,因此无法触达该分支。 ## 曾考虑的替代方案 -- **后端继承的基类**:否决,改用组合。后端只暴露钩子,无法触及协调器的私有编排状态,且第三方后端仍然可以完全不使用协调器、直接实现抽象服务。 -- **更宽的钩子面**:每个候选钩子都被折叠掉了:没有单独的 `materialize` 钩子(物化写入必须在 `appendBatch` 内与第一个事件批次原子提交);没有单独的创建冲突探测(它就是 `loadStored(id) !== undefined`);`list()` 也不经过协调器透传(列举不需要任何编排)。 +- **后端继承的基类**——否决,改用组合:后端只暴露钩子,无法触及协调器的私有编排状态,且第三方后端仍可完全不使用协调器、直接实现抽象服务。 +- **更宽的钩子面**——每个候选钩子都被折叠掉:没有单独的 `materialize` 钩子(物化写入必须在 `appendBatch` 内与首批事件原子提交);没有单独的创建碰撞探测(即 `loadStored(id) !== undefined`);`list()` 也不经由协调器透传(列举不需要任何编排)。 ## 后果 -协调器增加了一层间接和一个不透明的撕裂标记,但将此前每个后端重复的正确性密集编排集中到一处。其钩子面保持窄小:冲突检查复用 `loadStored`,物化保持在 `appendBatch` 内原子完成,列举绕过协调器。新后端只需实现存储原语,无需复制事件-缓冲区-flush 生命周期。 +协调器增加了一层间接和一个不透明的 torn marker,但将此前每个后端重复的、对正确性要求很高的编排逻辑集中到一处。其钩子面保持窄小:碰撞检查复用 `loadStored`,物化保持在 `appendBatch` 内原子完成,列举绕过协调器。新后端只需实现存储原语,而无需复制事件-缓冲区-flush 生命周期。 diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml index 52a3ca3b01..9fc5b9299f 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-branded-ids.md: f6d066857d8904ae5343f12310266663806a0ae2 -2026-06-20-branded-ids.zh.md: 14f82c395cdf43e2f5df5b2317dda3d45c595a64 +2026-06-20-branded-ids.zh.md: 80c158e598f3007416d31a89a6704a759798e44e diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md index 14f82c395c..80c158e598 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md @@ -1,30 +1,30 @@ -# RFC:在所有应当使用品牌类型的位置推行 Branded ID - -Status: implemented +# RFC:在所有应有之处使用 branded ID [English](2026-06-20-branded-ids.md) | 中文 +Status: implemented + ## 问题 -harness 已经为三个标识符打上了品牌类型:`CallId`(`packages/llm/llm/src/brand.ts`)、`SessionId`(`packages/core/session/src/types.ts`)和 `AgentId`(`packages/core/agent/src/types.ts`),使用 `Branded<B> = string & { readonly [BRAND]: B }` 机制(由纯类型包 `@deepseek-ai/dsh-brand` 拥有,位于 `packages/util/brand/`,见其 [README](../../../../packages/util/brand/README.md)),并为每个类型提供零成本的 cast 工厂函数。`dsh-brand` 还声明了治理策略:*"品牌类型用于跨包边界且可能被混淆的 id;并非每个 string 都需要品牌类型。"* 这条策略是正确的;问题在于它只落实了一半。两个缺口使得「结构相同但语义不同」的 string 今天仍能通过类型检查。 +harness 已经为三个标识符做了 brand 处理:`CallId`(`packages/llm/llm/src/brand.ts`)、`SessionId`(`packages/core/session/src/types.ts`)和 `AgentId`(`packages/core/agent/src/types.ts`),使用 `Branded<B> = string & { readonly [BRAND]: B }` 机制(由纯类型包(package) `@deepseek-ai/dsh-brand` 拥有,位于 `packages/util/brand/`,见其 [README](../../../../packages/util/brand/README.md)),并为每个类型提供零开销的 cast 工厂。`dsh-brand` 还声明了治理策略:*"Branding 用于跨包边界且可能被混淆的 id;不是每个 string 都需要 brand。"* 这条策略是正确的;问题在于它只落实了一半。两处缺口使得结构相同但语义错误的 string 今天仍能通过类型检查器。 -**缺口 1:bash seam 中未打品牌的 ID。** `BashTask.id` 以及所有 executor/tool 边界使用裸 `string`,尽管生成的值与默认 session id 具有相同的 `name-N` 形状。模型也通过 `task_id` 返回该值,因此混淆 task id 和 session id 既是类型正确的,也是可达的。 +**缺口 1:bash seam 中未 brand 的 ID。** `BashTask.id` 以及所有执行器/工具边界使用裸 `string`,尽管生成的值与默认 session id 具有相同的 `name-N` 形状。模型还通过 `task_id` 返回该值,因此混淆 task id 和 session id 既类型正确又可达。 -bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 和 `BashExecSpec.owner: string | undefined`(`packages/bash/bash/src/types.ts`)被文档描述为刻意*不透明*的隔离键,但在所有实际调用方中,该值就是拥有者 agent 的 `session.header.id`(`callerToken = (exec) => exec.agent?.session.header.id`,见 `packages/bash/tool-bash/src/index.ts`)——即一个穿着 `string` 外衣的 `SessionId`。它被用于访问控制比较(`owner !== callerToken(exec)`),因此一个「不匹配但类型正确」的 string 在此处就是一个跨会话隔离 bug,而当前类型系统无法捕获。这正是 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案所称的「bash owner-token 别名漏洞」。 +bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 和 `BashExecSpec.owner: string | undefined`(`packages/bash/bash/src/types.ts`)被文档描述为刻意*不透明*的隔离键,但在所有实际调用方中,该值就是所属 agent(智能体)的 `session.header.id`(`callerToken = (exec) => exec.agent?.session.header.id`,位于 `packages/bash/tool-bash/src/index.ts`),即一个穿着 `string` 外衣的 `SessionId`。它被用于访问控制比较(`owner !== callerToken(exec)`),因此一个不匹配但类型正确的 string 在此处就是一个跨会话隔离 bug,而当前类型系统无法捕获。这正是 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案所称的"bash owner-token alias hole"。 -**缺口 2:既有品牌类型的侵蚀。** `CallId`、`SessionId` 和 `AgentId` 在注册表 map、公开查找参数、ACP 会话追踪和持久化协调器中退化为裸 string。在查找边界丢弃品牌类型,等于废掉了它的核心保护。 +**缺口 2:既有 brand 的侵蚀。** `CallId`、`SessionId` 和 `AgentId` 在注册表 map、公开查找参数、ACP 会话跟踪和持久化协调器中退化为裸 string。在查找边界丢弃 brand 会使其主要保护失效。 ## 决策 -纯类型变更。品牌类型是零成本 cast;运行时行为、序列化、比较和协议格式(wire format)均不变。工作分三部分,全部遵守既有的「并非每个 string 都需要」策略。 +纯类型变更。Brand 是零开销 cast;运行时行为、序列化、比较和协议格式(wire format)均不变。工作分三部分,全部遵循既有的"不是每个 string 都需要"策略。 -- **为 bash task id 打品牌。** 在 `packages/bash/bash/src/types.ts`(*拥有*该 id 的包)中添加 `BashTaskId = Branded<'BashTaskId'>` 及其同名工厂函数,从 `@deepseek-ai/dsh-brand` 导入 `Branded`,方式与 `SessionId`/`AgentId` 完全一致。品牌原语放在无依赖的 `dsh-brand` 工具包中,正是为了让 `dsh-bash` 只依赖它就能为自己的 id 打品牌——永远不需要为了获取 `Branded` 而引入 `dsh-llm`(或 `dsh-session`)。将品牌贯穿 `BashTask.id`、`BashExecutor` seam 方法(`get`/`ownerOf`/`readOutput`/`kill`)、`dsh-bash-local` 中的生成点(在创建时一次性为计数器输出打品牌),以及 `dsh-tool-bash` 的校验/访问控制面(`validateTaskId` 返回 `BashTaskId`;`task_id` 在模型 string 到达的 tool 边界处打品牌)。 +- **为 bash task id 加 brand。** 在 `packages/bash/bash/src/types.ts`(拥有该 id 的包)中添加 `BashTaskId = Branded<'BashTaskId'>` 及其同名工厂,从 `@deepseek-ai/dsh-brand` 导入 `Branded`,方式与 `SessionId`/`AgentId` 完全一致。brand 原语位于无依赖的 `dsh-brand` 工具包中,正是为了让 `dsh-bash` 仅依赖它就能为自己的 id 加 brand,而无需引入 `dsh-llm`(或 `dsh-session`)来获取 `Branded`。将其贯穿 `BashTask.id`、`BashExecutor` seam 方法(`get`/`ownerOf`/`readOutput`/`kill`)、`dsh-bash-local` 中的生成点(在创建时对计数器输出做一次 brand),以及 `dsh-tool-bash` 的校验/访问面(`validateTaskId` 返回 `BashTaskId`;`task_id` 在模型 string 到达的工具边界处被 brand)。 -- **铸造独立的 `OwnerToken` 品牌。** 在 `packages/bash/bash/src/types.ts` 中添加 `OwnerToken = Branded<'OwnerToken'>`;将 `BashExecRequest.owner` / `BashExecSpec.owner` / `BashExecutor.ownerOf` 的类型标注为 `OwnerToken | undefined`。`dsh-tool-bash` 消费方在边界处将 agent 的 `session.header.id`(一个 `SessionId`)cast 为 `OwnerToken`——这是两套词汇交汇的唯一位置。bash seam 永远不导入 `dsh-session`。(理由见下一节。) +- **铸造独立的 `OwnerToken` brand。** 在 `packages/bash/bash/src/types.ts` 中添加 `OwnerToken = Branded<'OwnerToken'>`;将 `BashExecRequest.owner` / `BashExecSpec.owner` / `BashExecutor.ownerOf` 的类型标注为 `OwnerToken | undefined`。`dsh-tool-bash` 消费方在边界处将 agent 的 `session.header.id`(一个 `SessionId`)cast 为 `OwnerToken`——这是两套词汇唯一交汇的地方。bash seam 从不导入 `dsh-session`。(理由见下一节。) -- **阻止品牌侵蚀。** 将既有品牌传播到缺口 2 列出的 `Map` 键类型和公开方法参数:`Map<SessionId, Session>`、`get(id: SessionId)`、`Map<AgentId, Agent>`、`Map<CallId, …>`、ACP 的 `SessionRecord.sessionId: SessionId` 接口、协调器的 `Map<SessionId, …>`。这是 diff 中机械性最大的部分,也是让*既有*品牌在查找处真正发挥作用(而非仅在结构体字段上标注)的关键。 +- **阻止 brand 侵蚀。** 将既有 brand 传播到缺口 2 列出的 `Map` 键类型和公开方法参数中:`Map<SessionId, Session>`、`get(id: SessionId)`、`Map<AgentId, Agent>`、`Map<CallId, …>`、ACP 的 `SessionRecord.sessionId: SessionId` 接口、协调器的 `Map<SessionId, …>`。这是 diff 中机械量最大的部分,也是让*既有* brand 在查找处真正发挥作用(而不仅仅标注在结构体字段上)的关键。 -示意形状(工厂模式与现有三个品牌完全一致): +示意形状(工厂模式与已有的三个 brand 完全一致): ```ts ignore-check import type { Branded } from '@deepseek-ai/dsh-brand' @@ -46,24 +46,24 @@ export function OwnerToken(id: string): OwnerToken { ### 为什么不把 `owner` 类型标注为 `SessionId`? -executor 将 ownership 视为不透明的,不应依赖 session 模型。独立的 `OwnerToken` 保持了这一边界,同时防止裸 string 或 task id 被当作 owner 传入。`dsh-tool-bash` 拥有访问策略,由它执行从 `SessionId` 到 `OwnerToken` 的唯一转换。 +执行器将 ownership 视为不透明的,不应依赖 session 模型。独立的 `OwnerToken` 保留了这一边界,同时防止裸 string 或 task id 被当作 owner 传入。`dsh-tool-bash` 拥有访问策略,由它执行从 `SessionId` 到 `OwnerToken` 的唯一转换。 ## 不在范围内 / 可能的扩展 -遵循「并非每个 string 都需要品牌类型」策略,刻意保持窄范围。以下每项都是合理的未来品牌候选,附有推迟理由而非承诺: +遵循"不是每个 string 都需要 brand"的策略,刻意保持窄范围。以下每项都是合理的未来 brand 候选,附带推迟理由而非承诺: -- **`ModelId`**(`GenerateOptions.model`,`LlmService` 适配器注册表键)——一个真正的跨包查找键(config → agent → llm → adapter);合理的下一个品牌,仅为控制本 RFC 的影响范围而暂不纳入。 -- **`ToolName`**(`ToolRegistry` 键)——由作者定义、人类可读,且很少与其他 id 混淆;候选强度最弱,可能不值得打品牌。 -- **`ErrorCode`**(`HarnessError.code`)——封闭词汇(`ABORTED`、`NO_ADAPTER`……),不是逐实例的 id;如果要加强类型,用 string 字面量联合类型比品牌更合适。 -- **数值序号**——轮次号、步骤号和事件 `seq` 是 `number` 而非 `string`,`Branded<string>` 不适用;可以用并行的 `number & { readonly [BRAND]: B }` 变体为它们打品牌,但它们是位置序号、很少跨边界传递,收益低。 -- **带校验的构造**——品牌工厂是纯 cast,无运行时检查,且每个边界(ACP `sessionId`、提供方发放的 `call.id`、`dsh-llm-deepseek` 中的空字符串回退)今天都信任裸 string。一个在边界对畸形输入抛异常的 `SessionId.parse()` / `isValid()` 伴生函数确实是缺口,但它是一项*运行时行为*变更,有自己的设计问题(什么算「畸形」?失败时怎么办?),应在独立 RFC 中处理,不应捆绑进这次纯类型改动。 +- **`ModelId`**(`GenerateOptions.model`,`LlmService` 适配器注册表的键):一个真正的跨包查找键(config → agent → llm → adapter);合理的下一个 brand,仅为控制本 RFC 的影响范围而暂不纳入。 +- **`ToolName`**(`ToolRegistry` 的键):由作者定义、人类可读,且很少与其他 id 混淆;最弱的候选,可能不值得加 brand。 +- **`ErrorCode`**(`HarnessError.code`):一个封闭词汇(`ABORTED`、`NO_ADAPTER`……),不是逐实例的 id;如果要做,string 字面量联合类型比 brand 更合适。 +- **数值序号**:轮次号、步骤号和事件 `seq` 是 `number` 而非 `string`,`Branded<string>` 不适用;可以用并行的 `number & { readonly [BRAND]: B }` 变体来 brand 它们,但它们是位置序号、很少跨边界传递,收益较低。 +- **带校验的构造**:brand 工厂是纯 cast,无运行时检查,且每个边界(ACP `sessionId`、提供方签发的 `call.id`、`dsh-llm-deepseek` 中的空字符串回退)今天都信任裸 string。一个在边界处对格式错误的输入抛异常的 `SessionId.parse()` / `isValid()` 配套工具确实是缺口,但它是*运行时行为*变更,有自己的设计问题(什么算"格式错误"?失败时怎么办?),应在独立 RFC 中处理,不应捆绑进这次纯类型变更。 ## 验证 -`BashTaskId` 和 `OwnerToken` 定义在 `dsh-bash` 中,贯穿 executor、本地实现和面向模型的 tool,且未引入 `dsh-session` 依赖。集合、公开参数和导出签名对 `CallId`、`SessionId`、`AgentId` 或 `BashTaskId` 使用对应的品牌类型而非裸 `string`;来自提供方、ACP 和模型的原始输入通过品牌工厂进入,而非散落的 cast。 +`BashTaskId` 和 `OwnerToken` 定义在 `dsh-bash` 中,贯穿执行器、本地实现和面向模型的工具,且未添加 `dsh-session` 依赖。集合、公开参数和导出签名对 `CallId`、`SessionId`、`AgentId` 或 `BashTaskId` 使用相应的 brand 而非裸 `string`;来自提供方、ACP 和模型的原始输入通过 brand 工厂进入,而非散落的 cast。 ## 后果 -- **两个面上的机械性改动。** 传播品牌类型涉及 bash seam(接口 + 实现 + 消费方)以及 ACP session-id 接口和持久化协调器。改动面广但严重度低:遗漏的位置是编译错误,而非静默 bug。变更可观测地是纯类型的——无快照或 e2e 行为差异。它与 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案相邻(两者都触及 session-id / owner-token 边界);即使该提案落地,`OwnerToken` 出于上述解耦理由仍与统一后的 id 保持独立。 -- **品牌类型不做校验。** 品牌类型是混淆防护,不是正确性证明:一个*错误的* session id 只要仍是格式良好的 string,就和以前一样能通过类型检查。本 RFC 不关闭这个缺口(见「不在范围内」)——它只阻止传入错误*类别*的 id 这一类错误。 -- **「在哪里停下」仍是判断题。** 为 `BashTaskId` 打品牌而不为 `ToolName`,为 `OwnerToken` 打品牌而不为 `ModelId`,是对哪些 string「可能被混淆」的品味判断。合理的评审者可能想要更多或更少;`brand.ts` 中的策略是裁决依据,本 RFC 倾向于面向模型或用于访问控制的 id。 +- **两个接口面的机械性改动。** 传播 brand 涉及 bash seam(接口 + 实现 + 消费方)以及 ACP session-id 接口和持久化协调器。改动面广但严重度低:遗漏的位置是编译错误而非静默 bug。变更可观察地为纯类型变更——无快照或 e2e 行为差异。它与 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案相邻(两者都触及 session-id / owner-token 边界);如果该提案落地,`OwnerToken` 出于上述解耦理由仍与统一后的 id 保持独立。 +- **Brand 不做校验。** Brand 是混淆防护,不是正确性证明:一个*错误的* session id 只要仍是合法的 string,就和以前一样能通过类型检查器。本 RFC 不关闭这个缺口(见"不在范围内")——它只阻止传入错误*类别*的 id 这种错误。 +- **"在哪里停下"仍是判断题。** 为 `BashTaskId` 加 brand 但不为 `ToolName` 加,为 `OwnerToken` 加但不为 `ModelId` 加,是对哪些 string"可能被混淆"的品味判断。合理的评审者可能想要更多或更少;`brand.ts` 中的策略是裁决依据,本 RFC 倾向于面向模型或用于访问控制的 id。 diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml index 992793d609..d10d531a66 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-extract-example-app-packages.md: 3a0a0f5d4b329afed72bd3c00bf880989e24fe54 -2026-06-20-extract-example-app-packages.zh.md: 9de9f79369ebad387778a0418b75dfde96b285a7 +2026-06-20-extract-example-app-packages.zh.md: 8945f0c97727479c9e847711a96fc5d18118e09e diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md index 9de9f79369..8945f0c977 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md @@ -1,57 +1,57 @@ -# RFC:将示例应用提取为 package - -Status: implemented +# RFC:将示例应用提取为独立包 [English](2026-06-20-extract-example-app-packages.md) | 中文 +Status: implemented + ## 问题 -示例目录本应是*薄*的:只包含演示的可变接线,而非演示的机制本身。在本次变更之前它是厚的。每个示例都携带一份手写的 `start.ts` 启动引导、一段基础设施前导(`timer`,以及 stdio 演示还需要的 `logger` + `hmr`)、三个共享 YAML 片段的嵌套引入(`base.yml` / `base-core.yml` / `acp-agent/acp-tail.yml`),以及每个示例各自的 `agent-loop`/持久化/系统提示词配置。真正的应用——每个 agent 都需要的服务主干——分散在叶子配置和那些 include 中。 +示例目录本应是*精简的*——只包含演示的可变接线,而非演示的基础设施。在此次变更之前,它是臃肿的。每个示例都携带一份手写的 `start.ts` 启动引导、一段基础设施前导(`timer`,以及 stdio 演示所需的 `logger` + `hmr`(热模块替换))、三个共享 YAML 片段的嵌套引用(`base.yml` / `base-core.yml` / `acp-agent/acp-tail.yml`),还有各示例自身的 `agent-loop`/persistence/system-prompt 配置。真正的应用——每个 agent(智能体)都需要的服务主干——散落在叶子配置和那些 include 中。 -叶子配置还拥有一个耦合的前门。ACP 要求 stdout 纯净,通过 `session/new` 创建 agent;stdio 需要控制台 logger 和一个预创建的 `main`。防止错误组合的唯一手段是行文中的警告,而三个 `start.ts` 文件重复了 Loader 引导和生命周期代码。 +叶子配置还拥有一个耦合的前门。ACP(Agent Client Protocol)要求 stdout 纯净,并通过 `session/new` 创建 agent;stdio 则需要一个控制台 logger 和一个预创建的 `main`。防止错误组合的唯一屏障是文档中的文字警告,而三个 `start.ts` 文件重复着 Loader 引导和生命周期代码。 ## 决策 -每个示例现在**基本上是对一个 app package 的调用**,沿着既有的[接口 / 实现 / 消费方 seam](2026-06-13-capability-seams.md) 拆分接线:**app 包拥有组合**,叶子 `cordis.yml` 只拥有**可替换的选择**(哪个 LLM 适配器、哪个 bash 执行器、模型、提示词、持久化根目录)。 +每个示例现在**主要是对一个应用包(package)的调用**,沿着既有的[接口 / 实现 / 消费方 seam](2026-06-13-capability-seams.md) 拆分接线:**应用包拥有组合**,叶子 `cordis.yml` 只拥有**可替换的选择**(哪个 LLM(大语言模型)适配器、哪个 bash 执行器、模型、提示词、持久化根目录)。 -- **`@deepseek-ai/dsh-agent-spine-demo`**([packages/examples/agent-spine-demo](../../../../packages/examples/agent-spine-demo))组合无提供方、无执行器、无 UI 的主干,并转发 loop 的 agent 列表配置。它对具体 loop 的依赖是有意为之,因为这个包组合的是主干而非扩展它;替换 loop 意味着提供另一个 bundle。 -- **`@deepseek-ai/dsh-stdio-demo`**([packages/examples/stdio-demo](../../../../packages/examples/stdio-demo))和 **`@deepseek-ai/dsh-acp-demo`**([packages/examples/acp-demo](../../../../packages/examples/acp-demo))各自内置了前门。Stdio 包含 `ui-stdio`、控制台 logger 和 `main`;ACP 包含 bridge 和 JSONL 持久化,但不含 stdout logger 或预创建的 agent。叶子可以追加插件,但安全的组合现在是默认产物。 -- **`start.ts` 已移除。** 每个 app 包暴露一个 `bin`(`dsh-stdio-demo` / `dsh-acp-demo`);`demo:*` 脚本调用它(如 `dsh-stdio-demo ./cordis.yml`)。Loader 引导尾部、`.env` 加载和 fail-loud 守卫位于共享的 [`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot) 包(在逐文件覆盖率门禁下有单元测试——见[共享 app bin 的启动胶水](../simplification/2026-07-04-share-app-bin-boot-glue.md));每个 bin 是一个薄的自执行组合,基于这些辅助函数加上自身特有的生命周期逻辑(ACP bin:快照模式选择与 stdin-dispose)。`bin.ts` 文件本身仍排除在覆盖率之外(自执行 CLI 入口,与旧的 `start.ts` 类似),由 keyless Loader 路径测试驱动。 -- **每个叶子 `cordis.yml` 精简**为后端 + 配置:LLM 适配器(带 apiKey/models 的 `llm-deepseek`,或 `llm-replay`)、bash 执行器(`bash-local`)、stdio 演示的 `hmr`(见下方修正),以及一个 app 条目承载 app 的配置(模型、系统提示词、持久化根目录——作为 app 包自身的 `Config` 暴露,由 app 将每个值路由到其接线的目标位置:stdio 路由到预创建的 agent,acp 路由到 bridge 插件)。 -- **echo-agent 折叠到 `dsh-stdio-demo`**,将 LLM 后端替换为本地的 `mock-llm`,并在叶子层添加本地的 `echo-tool`(加上 `bash-local`,由主干的 `tool-bash` 注入)——这是「替换后端、保留应用」的干净示范。`mock-llm.ts` / `echo-tool.ts` 作为示例本地的教学插件保留。 -- **`base.yml`、`base-core.yml` 和 `acp-agent/acp-tail.yml` 退役**——它们共享的主干现在位于 `dsh-agent-spine-demo`。 +- **`@deepseek-ai/dsh-agent-spine-demo`**([packages/examples/agent-spine-demo](../../../../packages/examples/agent-spine-demo))组合了不含 provider、不含执行器、不含 UI 的主干,并转发 agent loop(智能体循环)的 agent 列表配置。它对具体 loop 的依赖是有意为之,因为该包组合的是主干而非扩展主干;替换 loop 意味着提供另一个 bundle。 +- **`@deepseek-ai/dsh-stdio-demo`**([packages/examples/stdio-demo](../../../../packages/examples/stdio-demo))和 **`@deepseek-ai/dsh-acp-demo`**([packages/examples/acp-demo](../../../../packages/examples/acp-demo))各自内置了前门。Stdio 包含 `ui-stdio`、控制台 logger 和 `main`;ACP 包含 bridge 和 JSONL 持久化,但不含 stdout logger 或预创建的 agent。叶子可以添加插件,但安全的组合现在是默认产物。 +- **`start.ts` 已移除。** 每个应用包暴露一个 `bin`(`dsh-stdio-demo` / `dsh-acp-demo`);`demo:*` 脚本调用它(例如 `dsh-stdio-demo ./cordis.yml`)。Loader 引导尾部、`.env` 加载和快速失败守卫位于共享的 [`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot) 包(在逐文件覆盖率门禁下有单元测试——见[共享应用 bin 的启动胶水](../simplification/2026-07-04-share-app-bin-boot-glue.md));每个 bin 是一个精简的自执行组合,基于这些辅助函数加上其应用特有的生命周期逻辑(ACP bin:快照模式选择与 stdin-dispose)。`bin.ts` 文件本身仍被排除在覆盖率之外(自执行 CLI(命令行界面)入口,与旧的 `start.ts` 性质相同),由 keyless 的 Loader 路径测试驱动。 +- **每个叶子 `cordis.yml` 精简为**后端 + 配置:LLM 适配器(带 apiKey/models 的 `llm-deepseek`,或 `llm-replay`)、bash 执行器(`bash-local`)、stdio 演示的 `hmr`(见下方修正),以及一个承载应用配置的 app 条目(模型、系统提示词、持久化根目录——以应用包自身的 `Config` 形式暴露,由它将各值路由到应用接线的目标位置:stdio 路由到预创建的 agent,acp 路由到 bridge 插件)。 +- **echo-agent 折叠到 `dsh-stdio-demo` 上**,将 LLM 后端替换为本地的 `mock-llm`,并在叶子层添加本地的 `echo-tool`(加上 `bash-local`,由主干的 `tool-bash` 注入)——这是「替换后端、保留应用」的干净示范。`mock-llm.ts` / `echo-tool.ts` 作为示例本地的教学插件保留。 +- **`base.yml`、`base-core.yml` 和 `acp-agent/acp-tail.yml` 已退役**——它们共享的主干现在位于 `dsh-agent-spine-demo` 中。 -`bash-local` 和 LLM 适配器保持为**叶子选择**:bundle 提供 `tool-bash`(消费方 schema),叶子选择执行器实现,因此沙箱执行器或回放适配器可以在不触碰 app 的情况下替换进来。 +`bash-local` 和 LLM 适配器仍然是**叶子选择**:bundle 提供 `tool-bash`(消费方 schema),叶子选择执行器实现,因此沙箱执行器或回放适配器无需触碰应用即可替换。 ### 实现修正:`hmr` 保留为叶子条目 -提案将 `hmr` 列入 stdio app 内置的前门集群。对照代码验证后发现,将 `hmr` 内置到 `dsh-stdio-demo` 包在两方面与 Cordis 冲突,因此改为作为**叶子 `cordis.yml` 条目**交付: +提案最初将 `hmr` 列入 stdio 应用内置的前门集群。对照代码验证后发现,将 `hmr` 内置到 `dsh-stdio-demo` 包中会在两个方面与 Cordis 冲突,因此改为作为**叶子 `cordis.yml` 条目**交付: -1. `@cordisjs/plugin-hmr` 是一个仅限 Loader、仅限子进程的开发插件——其构造函数在没有 `node --expose-internals` 和活跃 `loader` 服务的情况下会抛出异常,因此只能在真实的 `demo:*`/bin 子进程中运行,无法在进程内的单元/覆盖率测试层运行。 +1. `@cordisjs/plugin-hmr` 是一个仅限 Loader、仅限子进程的开发插件——其构造函数在没有 `node --expose-internals` 和活跃的 `loader` 服务时会抛出异常,因此只能在真实的 `demo:*`/bin 子进程中运行,不能在进程内的单元/覆盖率测试层运行。 2. 进程内测试层(vitest)甚至无法*导入* vendor 的 `hmr` 模块(其 class-decorator `@Inject` 形式在 Vite 的 transform 下会失败),因此一个 `apply` 静态导入了它的包永远无法满足其主函数的逐文件 100% 覆盖率门禁。 -关键在于,`hmr` **不是**像控制台 logger 那样的 stdout 纯净隐患——在 ACP 配置中误加 `hmr` 不会破坏 JSON-RPC 帧——因此将它留在叶子不会损失耦合论证所关注的安全性。**logger**(真正的耦合)保持内置:stdio app 包含它,ACP app 省略它。 +关键在于,`hmr` **不是**像控制台 logger 那样的 stdout 纯净隐患:ACP 配置中误加 `hmr` 不会破坏 JSON-RPC 帧,因此将它留在叶子层不会损失耦合论证所关注的安全性。**logger**(真正的耦合点)保持内置:stdio 应用包含它,ACP 应用省略它。 ## 曾考虑的替代方案 -### 为什么不继续用共享 YAML include 来接线? +### 为什么不继续用共享 YAML include 来管理接线? -旧的 `base*.yml`/`acp-tail.yml` include 已经去重了*配置*,但 YAML include 无法**封装**前门耦合——它只能在注释中描述,并信任每个叶子遵守。它也无法拥有 `bin`,因此启动胶水只能在三个 `start.ts` 文件中复制。包将「ACP app 绝不向 stdout 输出日志」从行文警告变成产物的属性:叶子中没有可以写错的 logger 条目。 +旧的 `base*.yml`/`acp-tail.yml` include 已经去重了*配置*,但 YAML include 无法**封装**前门耦合——它只能在注释中描述,并信任每个叶子遵守。它也无法拥有 `bin`,因此启动胶水一直在三个 `start.ts` 文件中重复。包将「ACP 应用绝不向 stdout 输出日志」从文字警告变成了产物的属性:叶子中不存在可以写错的 logger 条目。 ## 验证 - 示例目录只包含配置、README 和测试:`start.ts`、基础设施前导和共享 YAML include 已移除。 -- `demo:echo`、`demo:repl` 和 `demo:acp` 调用 app 包的 bin。 -- 每个新包有 README 和逐文件 100% 覆盖率;每个 app 包还有一个 keyless 的真实 Loader 路径 bin 冒烟测试,用于捕获 [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md) 中描述的导出形状失败。 -- ACP 回放 transcript 保持不变,因为插件集和加载顺序未改变。 +- `demo:echo`、`demo:repl` 和 `demo:acp` 调用应用包的 bin。 +- 每个新包都有 README 和逐文件 100% 覆盖率;每个应用包还有一个 keyless 的真实 Loader 路径 bin 冒烟测试,用于捕获[事后分析 0001](../../../postmortem/0001-acp-default-export-drops-inject.md) 中描述的导出形状故障。 +- ACP 回放 transcript(文本记录)保持不变,因为插件集合和加载顺序未改变。 ## 后果 -- **裸插件树教学法。** echo-agent 的内联 `cordis.yml` 曾一次展示所有插件;主干现在藏在 bundle 后面,因此查看完整树意味着打开 `dsh-agent-spine-demo`。app 包的 README 承担了这部分教学职责。 -- **多了一层间接。** 「这个演示加载了什么?」变成了读一个 package,而非扫一份 YAML。 +- **裸插件树的教学性。** echo-agent 内联的 `cordis.yml` 曾一次展示所有插件;主干现在隐藏在 bundle 之后,查看完整树意味着打开 `dsh-agent-spine-demo`。应用包的 README 承担了这份教学职责。 +- **多了一层间接。**「这个演示加载了什么?」从扫描单个 YAML 变成了阅读一个包。 ## 相关 -- 取代 [Make the shared example base providerless](../../rejected/architecture/2026-06-20-providerless-example-base.md):一旦主干移入 `dsh-agent-spine-demo` 且 `base*.yml` 文件被删除,将 `base.yml` 重命名为无提供方核心便不再有意义。 -- 建立在[能力 seam](2026-06-13-capability-seams.md) 的接口/实现/消费方拆分之上——后端和展示层保持为叶子选择;主干是共享 bundle。 -- 与 [Reorganize packages into a modular hierarchy](2026-06-20-package-hierarchy.md) 互补:新的 app/core 包按该层级结构归入既有分组(`core` 放可复用的主干 bundle,`ui` 放 app 特有的前门)。 +- 取代 [Make the shared example base providerless](../../rejected/architecture/2026-06-20-providerless-example-base.md):一旦主干移入 `dsh-agent-spine-demo` 且 `base*.yml` 文件被删除,将 `base.yml` 重命名为无 provider 核心便不再有意义。 +- 基于 [capability-seams](2026-06-13-capability-seams.md) 的接口/实现/消费方拆分——后端和展示层保持为叶子选择;主干是共享 bundle。 +- 与 [Reorganize packages into a modular hierarchy](2026-06-20-package-hierarchy.md) 互补:新的 app/core 包按该层级结构归入既有分组(`core` 放可复用的主干 bundle,`ui` 放应用特有的前门)。 diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml index 9f89c454fc..08ab9fc7f0 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-package-hierarchy.md: faf5815222b20699a32f1af489e625ba3e891230 -2026-06-20-package-hierarchy.zh.md: 4b71cd41826e727eea19d305635c6485e18393c2 +2026-06-20-package-hierarchy.zh.md: 118367f2655bffbd270f259df4ade37a70dcb2d7 diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md index 4b71cd4182..118367f265 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md @@ -1,4 +1,4 @@ -# RFC:将包(package)重组为模块化层级结构 +# RFC:将包重组为模块化层级结构 [English](2026-06-20-package-hierarchy.md) | 中文 @@ -6,13 +6,13 @@ Status: implemented ## 问题 -`packages/` 原先是扁平的:18 个包全部位于 `packages/<name>/`,一个包的位置无法体现它是核心产品 API、可替换的能力 seam、提供方适配器、产品集成,还是示例/测试支撑。package README 带着 `FIXME(package-hierarchy)`,`scripts/publint-all.ts` 带着 `TODO(package-inventory)`,标记的正是这个问题。核心包、提供方集成、能力 seam、示例 UI 支撑和仅用于快照的回放支撑,看起来都同等基础。 +`packages/` 原先是扁平的:18 个包(package)全部位于 `packages/<name>/`,从路径上完全看不出一个包属于核心产品 API、可替换的能力 seam、提供方适配器、产品集成,还是示例/测试支撑。包的 README 带着 `FIXME(package-hierarchy)`,`scripts/publint-all.ts` 带着 `TODO(package-inventory)`,标记的正是这个问题。核心包、提供方集成、能力 seam、示例 UI 支撑和仅用于快照的回放支撑看起来同样基础。 -这不仅是外观问题。因为每个顶层包看起来都属于同一个公开接口面,未来移除更难;发布/lint/文档脚本不得不通过注释或手工维护的静态列表来编码意图,而非从布局直接读取。 +这不仅仅是外观问题。由于每个顶层包看起来都属于同一个公开接口,未来移除更加困难,而 publish/lint/doc 脚本不得不通过注释或手工维护的静态列表来编码意图,而不是从布局中直接读取。 ## 决策 -按模块角色分组,统一为 `packages/<group>/<pkg>/` 两层深度。分组目录是纯容器(没有 `package.json`);每个包保留其 `@deepseek-ai/dsh-<pkg>` 名称——这是仓库结构与维护策略,不是包重命名。 +按模块角色将包分组,统一放在 `packages/<group>/<pkg>/` 深度。分组目录是纯容器(没有 `package.json`);每个包保留其 `@deepseek-ai/dsh-<pkg>` 名称——这是仓库结构与维护策略的调整,不是包的重命名。 ```text packages/ @@ -44,32 +44,32 @@ packages/ ### 放置决策 -- **能力族使用同名嵌套。** 一个族的接口包位于 `packages/<group>/<group>/`(`llm/llm`、`bash/bash`、`session-persistence/session-persistence`),实现和消费方作为扁平兄弟。不设额外的 `adapters/`/`impls/` 子层——每个包恰好在深度 2,workspace glob 保持简洁的 `packages/*/*`,一条 `@deepseek-ai/dsh-*` tsconfig 通配符即可解析所有包(目录名唯一,使 first-on-disk-wins 无歧义)。 -- **`session` 留在 `core/`;持久化自成一族。** 会话日志是核心产品 API。其存储后端构成一个平行的能力族(`session-persistence/`),与 `llm/` 和 `bash/` 对称,而非嵌套在 `core/session/` 下。 -- **`agent-loop` 在 `core/` 中。** 它是 `agent` seam 唯一的具体实现,但作为 harness 的默认产品循环随产品发布,因此与核心主干同住。插件仍然依赖 `agent` 的词汇,从不依赖 `agent-loop`,因此循环仍可替换。 -- **`invariants` 和 `ui-stdio` 属于 `support/`,不是产品。** `invariants` 是开发模式的契约检查。`ui-stdio` 从示例中提取以便复用和满足覆盖率门禁——它与示例耦合,因此与 `llm-replay`(快照测试回放适配器)一起放在 `support/` 中。`acp` 是 `ui/` 的唯一成员,因为它是真正的产品接口面(编辑器驱动的 ACP 桥接),在结构上不同于 readline 演示辅助工具。 +- **能力族使用同名嵌套。** 一个族的接口包位于 `packages/<group>/<group>/`(`llm/llm`、`bash/bash`、`session-persistence/session-persistence`),实现和消费方作为扁平兄弟并列。不设额外的 `adapters/`/`impls/` 子层——每个包恰好在深度 2,这使 workspace glob 保持简洁的 `packages/*/*`,并让一条 `@deepseek-ai/dsh-*` tsconfig 通配符即可解析所有包(唯一的目录名使 first-on-disk-wins 无歧义)。 +- **`session` 留在 `core/`;持久化独立成族。** 会话日志是核心产品 API。其存储后端构成一个平行的能力族(`session-persistence/`),与 `llm/` 和 `bash/` 对称,而非嵌套在 `core/session/` 下。 +- **`agent-loop` 在 `core/` 中。** 它是 `agent` seam 唯一的具体实现,但作为 harness 的默认产品循环交付,因此与核心主干同处。插件仍然依赖 `agent` 的词汇,从不依赖 `agent-loop`,所以循环仍可替换。 +- **`invariants` 和 `ui-stdio` 属于 `support/`,不是产品。** `invariants` 是开发模式的契约检查。`ui-stdio` 从示例中提取出来以便复用和满足覆盖率门禁——它与示例耦合,因此与 `llm-replay`(快照测试的回放适配器)一起放在 `support/` 中。`acp` 是 `ui/` 的唯一成员,因为它是真正的产品接口(编辑器驱动的 ACP 桥接),与 readline 演示辅助工具在结构上截然不同。 -### 去重包清单 +### 去重包列表 -包清单此前在五处重复枚举。统一的深度 2 布局使大部分可以被推导出来: +包列表此前在五个地方重复枚举。统一的深度 2 布局使大部分可以被推导: -- `tsconfig.base.json` 通过一条 `@deepseek-ai/dsh-*` `paths` 通配符(每个分组列一个候选路径)映射所有包,取代逐包条目。根 `tsconfig.json` 复用该源码映射,并携带显式的 project references 以保持 package/vendor 类型检查边界完整。(这里引入了一个细节:路径候选包含 `/*/`,朴素的正则注释剥离器会误认为块注释——`scripts/doc-typecheck.ts` 正是因此通过 TypeScript 解析器读取 JSONC 配置,而非手工剥离注释。) -- `scripts/publint-all.ts` 通过读取层级结构(`packages/<group>/<pkg>`)推导出列表,解决了 `TODO(package-inventory)`。 -- `tsconfig.build.json` 的 project `references` 仍为显式列表——TypeScript project references 没有通配符形式。从 manifest 生成这些引用留作后续工作(见 [discover package inventories](../../proposed/process/2026-06-20-discover-package-inventory.md))。 +- `tsconfig.base.json` 通过一条 `@deepseek-ai/dsh-*` `paths` 通配符(每个分组列一个候选)映射所有包,取代了逐包条目。根 `tsconfig.json` 复用该源映射,并携带显式 project references 以保持 package/vendor 类型检查边界完整。(这里引入了一个细节:路径候选中包含 `/*/`,朴素的正则注释剥离器会将其误认为块注释——`scripts/doc-typecheck.ts` 正是因此通过 TypeScript 解析器读取 JSONC 配置,而非手动剥离注释。) +- `scripts/publint-all.ts` 通过读取层级结构(`packages/<group>/<pkg>`)推导列表,解决了 `TODO(package-inventory)`。 +- `tsconfig.build.json` 的 project `references` 仍为显式列表——TypeScript project references 没有通配符形式。从 manifest(元数据清单)生成这些引用留作后续工作(见 [discover package inventories](../../proposed/process/2026-06-20-discover-package-inventory.md))。 ### 新增的护栏 -两道 doc-sync/hygiene 门禁保证结构及其引用的正确性,使本次重组所需的人工检查不必再次手动重复: +两道 doc-sync/hygiene 门禁确保结构及其引用保持正确,使本次重组所需的手动检查无需日后重复: -- `scripts/verify-package-paths.ts` 标记 Markdown 或 `.ts` 注释/字符串中的 `packages/<path>` 引用:如果该路径无法解析**且**某段命名了一个真实存在的包,则视为指向已移动包的陈旧路径。如果路径命名的包在任何地方都不存在(前瞻性提案),则不报错;因此该门禁对 proposed/implemented/rejected 统一适用。 -- `scripts/check-workspace-constraints.ts` 断言 `packages/<group>/<pkg>` 形状:分组目录不含 `package.json`,没有包扁平地位于根层级或嵌套更深。分组名称保持开放——新增分组无需修改门禁;只有深度 2 的形状是固定的。 +- `scripts/verify-package-paths.ts` 标记 Markdown 或 `.ts` 注释/字符串中的 `packages/<path>` 引用,如果该引用无法解析**且**某个路径段命名了一个真实存在的包,即指向已移动包的陈旧路径。如果路径命名的包在任何地方都不存在(前瞻性提案),则不予标记,因此该门禁在 proposed/implemented/rejected 中统一适用。 +- `scripts/check-workspace-constraints.ts` 断言 `packages/<group>/<pkg>` 形状:分组目录不带 `package.json`,且没有包扁平地位于根层或嵌套更深。分组名称保持开放——添加新分组无需修改门禁;只有深度 2 的形状是固定的。 ## 曾考虑的替代方案 -- **第三层(每个族下设 `adapters/`/`impls/`)**:否决。统一深度 2 使 workspace glob 保持简洁的 `packages/*/*`,一条 `@deepseek-ai/dsh-*` tsconfig 通配符即可解析所有包。 +- **第三层(每个族下设 `adapters/`/`impls/`)**:否决。统一深度 2 使 workspace glob 保持简洁的 `packages/*/*`,并让一条 `@deepseek-ai/dsh-*` tsconfig 通配符即可解析所有包。 - **将持久化嵌套在 `core/session/` 下**:否决。存储后端构成一个平行的能力族,与 `llm/` 和 `bash/` 对称,而会话日志本身属于核心产品 API。 -- **`ui-stdio` 放在 `ui/` 下**:否决。它是与示例耦合的开发支撑,不是产品接口面;`acp` 是 `ui/` 的唯一成员,因为编辑器确实在驱动它。 +- **`ui-stdio` 放在 `ui/` 下**:否决。它是与示例耦合的开发支撑,不是产品接口;`acp` 是 `ui/` 的唯一成员,因为编辑器实际驱动它。 ## 后果 -本次重组在一次协调的变更中搅动了 import、workspace glob、文档链接、构建引用和包路径。这种搅动在发布前是可接受的(遵循 AGENTS.md 中「基础优先于爆炸半径」的立场),因为它阻止了扁平布局将支撑包固化为产品契约;而且这是一次性成本:通配符 `paths`、glob 推导的 publint 列表和形状门禁意味着新增一个包无需再做额外的结构编辑。 +本次重组在一次协调的变更中搅动了 import、workspace glob、文档链接、构建引用和包路径。这种变动在发布前是可接受的(依据 AGENTS.md 中「基础优先于爆炸半径」的立场),因为它阻止了扁平布局将支撑包固化为产品契约,且这是一次性成本:通配符 `paths`、glob 推导的 publint 列表和形状门禁意味着新增一个包无需额外的结构性编辑。 diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml index c69c49d2c7..4a0b9d6ebc 100644 --- a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-21-mandatory-app-attribution-headers.md: 4fa773e089b3a4b682e42269a66d85aeaf5c18f6 -2026-06-21-mandatory-app-attribution-headers.zh.md: 3660b8e7de977c01a19f9ed9ac9e73409f69706a +2026-06-21-mandatory-app-attribution-headers.zh.md: 42cc396b5719adb2a2d71e0e9cf0d3554c5533a5 diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md index 3660b8e7de..42cc396b57 100644 --- a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md @@ -1,84 +1,84 @@ # RFC:对提供方请求强制携带 `User-Agent` 归属标识 -Status: implemented - [English](2026-06-21-mandatory-app-attribution-headers.md) | 中文 +Status: implemented + ## 问题 -LLM(大语言模型)提供方请求应当标识发出请求的产品。这对提供方侧的技术支持、滥用调查、兼容性调试和流量分析都有价值。在本 RFC 之前,harness 只部分做到了这一点:手写的 DeepSeek 适配器发送一个手动复制的 `User-Agent` 常量(`packages/llm/llm-deepseek/src/adapter.ts`),而基于 pi-ai 的孪生适配器完全不发送 harness 自有的头部(`packages/llm/llm-pi-ai/src/adapter.ts`)。因此新适配器可以静默地遗漏归属标识,而库封装的适配器也可能与手写适配器产生偏差——尽管[孪生适配器 RFC](2026-06-13-twin-llm-adapters.md) 的存在正是为了让两种实现在提供方 seam 上保持诚实。 +LLM(大语言模型)提供方请求应当标识发出请求的产品。这对提供方侧的技术支持、滥用调查、兼容性调试和流量分析都有价值。在本 RFC 之前,harness 只做了部分工作:手写的 DeepSeek 适配器发送了一个手动复制的 `User-Agent` 常量(`packages/llm/llm-deepseek/src/adapter.ts`),而基于 pi-ai 的孪生适配器则完全不发送 harness 自有的头部(`packages/llm/llm-pi-ai/src/adapter.ts`)。因此新适配器可以悄无声息地省略归属标识,而基于库的适配器也可能与手写适配器产生偏差——尽管[孪生适配器 RFC](2026-06-13-twin-llm-adapters.md) 的存在正是为了让两种实现在提供方 seam 上保持诚实。 -直接触发点来自 OpenRouter 的 [App Attribution](https://openrouter.ai/docs/app-attribution) 文档。OpenRouter 通过 `HTTP-Referer` 加展示名/分类头部来创建应用页面和排名。这有价值,但它不是 HTTP 标准中的应用身份机制。风险在于:把 OpenRouter 的确切头部集合当作通用标准采纳,然后将提供方特定的头部泄漏到直连 DeepSeek 的请求、未来的 OpenAI/Anthropic/Vertex 适配器、测试服务器或无限期记录未知字段的代理中。 +直接触发因素来自 OpenRouter 的 [App Attribution](https://openrouter.ai/docs/app-attribution) 文档。OpenRouter 根据 `HTTP-Referer` 加上 display/category 头部来创建应用页面和排名。这有价值,但它不是 HTTP 标准中的应用身份机制。风险在于:把 OpenRouter 的精确头部集当作通用标准来采纳,然后将提供方特有的头部泄漏到直连 DeepSeek 的请求、未来的 OpenAI/Anthropic/Vertex 适配器、测试服务器或无限期记录未知字段的代理中。 ## 调研 -- **OpenRouter 的机制是提供方特定的。** 其当前文档说明应用归属通过 `HTTP-Referer`(必需)、`X-OpenRouter-Title` 和 `X-OpenRouter-Categories` 追踪;`X-Title` 仅为向后兼容而接受。其 API 参考称这些头部为可选,并说它们使应用在 OpenRouter 上可被发现。这是一份具体的 OpenRouter 契约,而非 IETF 或 OpenAI 兼容 API 标准。 -- **在 agent 工具领域,`HTTP-Referer` 是一种 OpenRouter 感知的约定,而非通用 agent 约定。** 它足够常见,以至于 OpenRouter SDK 和示例直接暴露它,面向 OpenRouter 的框架通常需要一种方式来透传它。但 ACP(Agent Client Protocol)等 agent 协议在自己的 initialize 消息中协商名称、版本和能力,而模型提供方请求仍需 HTTP 层面的身份标识。因此「在 agent 世界被接受」意味着「被 OpenRouter 集成所识别」,而非「可跨 agent 运行时或提供方移植」。 -- **编程 agent 在 `User-Agent` 中标识产品和版本。** 公开实现在环境细节和提供方特定附加头部上各有不同,但产品身份是共同契约;不存在通用的精确格式。 -- **标准化的通用客户端身份头部是 `User-Agent`。** RFC 9110 第 10.1.5 节将 `User-Agent` 定义为用户代理软件的身份标识,说明它用于互操作性报告和分析,并说用户代理应当(SHOULD)在每个请求中发送它,除非被配置为不发送。这是唯一直接匹配「哪个产品在发出这个 HTTP 请求」的标准头部。 +- **OpenRouter 的机制是提供方特有的。** 其当前文档说明应用归属通过 `HTTP-Referer`(必需)、`X-OpenRouter-Title` 和 `X-OpenRouter-Categories` 来追踪;`X-Title` 仅为向后兼容而接受。其 API 参考称这些头部为可选,并说它们使应用在 OpenRouter 上可被发现。这是一份具体的 OpenRouter 契约,而非 IETF 或 OpenAI 兼容 API 标准。 +- **在 agent 工具生态中,`HTTP-Referer` 是一种 OpenRouter 感知的约定,而非通用 agent 约定。** 它足够常见,以至于 OpenRouter SDK 和示例直接暴露它,面向 OpenRouter 的框架通常需要一种方式来透传它。但 ACP(Agent Client Protocol)等 agent 协议在自己的 initialize 消息中协商名称、版本和能力,而模型提供方请求仍需 HTTP 层面的身份标识。因此「在 agent 世界中被接受」意味着「被 OpenRouter 集成所识别」,而非「可跨 agent 运行时或提供方移植」。 +- **编程 agent 在 `User-Agent` 中标识产品和版本。** 公开实现在环境细节和提供方特有的附加头部上各有不同,但产品身份是共同契约;不存在通用的精确格式。 +- **标准化的通用客户端身份头部是 `User-Agent`。** RFC 9110 第 10.1.5 节将 `User-Agent` 定义为用户代理软件身份,说明它用于互操作性报告和分析,并说用户代理*应当*在每个请求中发送它(除非被配置为不发送)。这是唯一直接对应「哪个产品在发出此 HTTP 请求」的标准头部。 - **`Referer` 是标准的,但 OpenRouter 的 `HTTP-Referer` 不是标准字段。** RFC 9110 第 10.1.3 节将 `Referer` 定义为获取目标 URI 的来源 URI,并用大量篇幅讨论隐私限制。OpenRouter 则要求 `HTTP-Referer`,将其用作应用 URL 标识符。该名称和含义是 OpenRouter 特有的,尽管它形似标准 `Referer` 头部的 CGI 环境变量形式。 -- **`From` 是标准的,但不适合作为强制默认。** RFC 9110 第 10.1.2 节将 `From` 定义为负责用户代理的人类的电子邮件地址。机器人代理应当(SHOULD)发送它以便服务器联系运营者,但非机器人代理不应在没有用户显式配置的情况下发送它,因为存在隐私和安全策略顾虑。harness 可以后续支持运营者联系方式,但不得凭空编造或全局强制要求。 -- **请求体中的 `user` 或 `metadata` 字段不是应用归属。** 某些模型 API 暴露稳定的终端用户标识符、请求元数据、标签或项目/账户头部。这些对滥用监控、内部计费、仪表盘或链路追踪有用,但它们要么标识的是终端用户而非产品,要么是提供方特定的 body schema,要么不保证能通过 OpenAI 兼容网关转发。它们不能替代静态的应用身份头部。 -- **SDK 遥测头部标识的是 SDK,而非应用。** 官方和第三方 SDK 经常发送库/版本头部。这些帮助 SDK 维护者调试客户端,但除非应用显式提供产品归属层,否则它们不会将 harness 标识为应用。 -- **pi-ai 有一流的头部钩子。** `@earendil-works/pi-ai` 的 `StreamOptions.headers` 将调用方头部最后合并(覆盖提供方默认值),因此库封装的适配器无需包装或上游改动即可满足与手写适配器相同的协议格式(wire format)契约。mock 服务器测试套件对两个适配器都断言头部到达了线路。 +- **`From` 是标准的,但不适合作为强制默认值。** RFC 9110 第 10.1.2 节将 `From` 定义为负责用户代理的人的电子邮件地址。机器人代理*应当*发送它以便服务器联系运营者,但非机器人代理出于隐私和安全策略考虑不应在未经用户显式配置的情况下发送。harness 可以后续支持运营者联系方式,但不得凭空捏造或全局强制要求。 +- **请求体中的 `user` 或 `metadata` 字段不是应用归属。** 部分模型 API 暴露稳定的终端用户标识符、请求元数据、标签或项目/账户头部。这些对滥用监控、内部计费、仪表盘或链路追踪有用,但它们要么标识的是终端用户而非产品,要么是提供方特有的 body schema,要么不保证能通过 OpenAI 兼容网关透传。它们不能替代静态的应用身份头部。 +- **SDK 遥测头部标识的是 SDK,而非应用。** 官方和第三方 SDK 常发送库/版本头部。这些帮助 SDK 维护者调试其客户端,但除非应用显式提供产品归属层,否则它们不能标识 harness 作为应用。 +- **pi-ai 有一流的头部钩子。** `@earendil-works/pi-ai` 的 `StreamOptions.headers` 将调用方头部最后合并(覆盖提供方默认值),因此基于库的适配器无需包装或上游改动即可满足与手写适配器相同的协议格式契约。mock 服务器测试套件对两个适配器都断言头部到达了线路。 ## 决策 -在 LLM 适配器边界,提供方请求归属是强制的,且仅使用标准 `User-Agent` 头部。规则是:每个产品 LLM 适配器在每个提供方 HTTP 请求上发送一个静态、非机密的应用身份,且每个适配器都有测试证明 `User-Agent` 到达了线路(mock 服务器断言收到的头部;对于库封装的适配器,库的头部钩子喂入同一个 mock 服务器断言)。 +在 LLM 适配器边界,提供方请求归属是强制的,且仅使用标准 `User-Agent` 头部。规则:每个生产 LLM 适配器在每个提供方 HTTP 请求上发送一个静态、非机密的应用身份,且每个适配器都有测试证明 `User-Agent` 到达了线路(mock 服务器断言收到的头部;对于基于库的适配器,通过库的头部钩子馈入同一个 mock 服务器断言)。 -本 RFC **不**实现 OpenRouter 应用归属。`HTTP-Referer`、`X-OpenRouter-Title`、`X-Title` 和 `X-OpenRouter-Categories` 是 OpenRouter 特定的产品展示头部,不是提供方无关的模型请求归属。它们可以后续由 OpenRouter 适配器或显式 OpenRouter 模式提出,带有自己的隐私/产品决策、测试和文档。在那之前,即使请求指向 OpenRouter,也只发送本 RFC 的共享 `User-Agent` 归属。 +本 RFC **不**实现 OpenRouter 应用归属。`HTTP-Referer`、`X-OpenRouter-Title`、`X-Title` 和 `X-OpenRouter-Categories` 是 OpenRouter 特有的产品展示头部,不是提供方无关的模型请求归属。它们可以后续由 OpenRouter 适配器或显式 OpenRouter 模式提出,附带自己的隐私/产品决策、测试和文档。在此之前,即使请求指向 OpenRouter,也只发送本 RFC 定义的共享 `User-Agent` 归属。 -提供方无关的身份由 `dsh-llm`(`packages/llm/llm/src/attribution.ts`)拥有,而非各个适配器。`AppIdentity` 仅包含构建 `User-Agent` 所需的公开产品事实,默认的 `APP_IDENTITY` 确定了提案中留待决定的值: +提供方无关的身份由 `dsh-llm`(`packages/llm/llm/src/attribution.ts`)拥有,而非各适配器。`AppIdentity` 仅包含构建 `User-Agent` 所需的公开产品事实,默认的 `APP_IDENTITY` 确定了提案中留待决定的值: -- `User-Agent` 的产品令牌:`deepseek-harness`(与 RFC 之前的线路值以及仓库/组织身份保持连续性) -- 版本:通过 `createRequire` 从所属包的 manifest(元数据清单)读取,绝不手动复制常量 -- 应用 URL:`https://github.com/deepseek-ai/deepseek-harness-sdk`——计划中的公开主页;`attribution.ts` 中的 `FIXME` 阻塞发布,直到该仓库实际存在 +- `User-Agent` 的产品 token:`deepseek-harness`(与 RFC 之前的线路值及仓库/组织身份保持连续性) +- 版本:通过 `createRequire` 从所属包的 manifest 读取,绝不手动复制常量 +- 应用 URL:`https://github.com/deepseek-ai/deepseek-harness-sdk`——计划中的公开主页;`attribution.ts` 中的 `FIXME` 标记在该仓库实际存在之前阻塞发布 -默认值是强制的且非空。白标部署向 `attributionHeaders(identity)` 传入自己的 `AppIdentity`——覆盖 seam 就是函数参数,在有消费方需要之前不做部署配置管道——省略时回退到 harness 默认值而非抑制归属。没有逐请求 API 让模型、用户提示词、会话 id、cwd、用户邮箱、API key 所有者或本地机器身份影响这些字段。 +默认值是强制的且非空。白标部署通过向 `attributionHeaders(identity)` 传入自己的 `AppIdentity` 来覆盖——覆盖 seam 就是函数参数,在有消费方需要之前不做部署配置管道——省略时回退到 harness 默认值而非抑制归属。没有逐请求 API 允许模型、用户提示词、会话 id、cwd、用户邮箱、API key 所有者或本地机器身份影响这些字段。 -线路映射(`attributionHeaders`;代码中头部名称为小写——HTTP 字段名在线路上不区分大小写): +线路映射(`attributionHeaders`;代码中头部名称小写——HTTP 字段名在线路上不区分大小写): | 目标 | 映射 | |---|---| | 所有基于 HTTP 的适配器 | `User-Agent: {product}/{version} (+{url})`——括号中的 `+url` 注释符合 RFC 9110 保守的 product/comment 语法。 | -| 直连 DeepSeek 端点 | `User-Agent`;除非 DeepSeek 文档记录了等效契约,否则不发送 OpenRouter 专用头部。 | +| 直连 DeepSeek 端点 | `User-Agent`;除非 DeepSeek 文档化了等效契约,否则不发送 OpenRouter 特有头部。 | | OpenRouter 端点 | 目前仅 `User-Agent`。本 RFC 下不发送 `HTTP-Referer`、`X-OpenRouter-Title`、`X-Title` 或 `X-OpenRouter-Categories`。 | -| 未来提供方 | 仅 `User-Agent`,除非后续提供方特定 RFC 接受额外头部。不以类推方式复用 `HTTP-Referer`。 | +| 未来提供方 | 仅 `User-Agent`,除非后续提供方特有的 RFC 接受额外头部。不要类比复用 `HTTP-Referer`。 | -端点检测不属于本 RFC,因为此处不接受任何端点特定映射。如果后续落地 OpenRouter 支持,检测必须是显式的:要么是专用的 OpenRouter 提供方包,要么是显式的 `provider: 'openrouter'` / `attributionTarget: 'openrouter'` 配置,而非任意路径片段或模型名。 +端点检测不在本 RFC 范围内,因为此处不接受任何端点特有的映射。如果后续支持 OpenRouter,检测必须是显式的:要么是专门的 OpenRouter 提供方包,要么是显式的 `provider: 'openrouter'` / `attributionTarget: 'openrouter'` 配置,而非任意路径片段或模型名称。 ## 验证 已落地的契约: -- `dsh-llm` 为 `LlmAdapter` 作者记录了强制的 `User-Agent` 归属契约(`LlmAdapter` JSDoc、包 README,以及 `docs/core-data-structures/llm-streaming.md` 的适配器契约章节)。 +- `dsh-llm` 为 `LlmAdapter` 作者文档化了强制的 `User-Agent` 归属契约(`LlmAdapter` JSDoc、包 README,以及 `docs/core-data-structures/llm-streaming.md` 的适配器契约章节)。 - 共享辅助函数(`attributionHeaders` / `userAgent`)从包元数据构建应用身份和标准 `User-Agent` 值,适配器无需手动复制版本常量。 - `dsh-llm-deepseek` 在每个请求上发送共享的 `User-Agent`,其 mock 服务器套件断言精确值。 - `dsh-llm-pi-ai` 通过 pi-ai 的 `StreamOptions.headers` 钩子发送相同的 `User-Agent`,其 mock 服务器套件断言精确值。 -- 本 RFC 下没有适配器发送 OpenRouter 特定的归属头部(`HTTP-Referer`、`X-OpenRouter-Title`、`X-Title`、`X-OpenRouter-Categories`)。 -- 没有应用归属字段携带机密、本地路径、会话 id、提示词文本、模型输出、用户邮箱或逐用户稳定标识符。 -- 适配器 README 声明了 `User-Agent` 归属策略,并明确避免将 OpenRouter 应用归属记录为已实现行为。 +- 本 RFC 下没有适配器发送 OpenRouter 特有的归属头部(`HTTP-Referer`、`X-OpenRouter-Title`、`X-Title`、`X-OpenRouter-Categories`)。 +- 没有应用归属字段携带机密、本地路径、会话 id、提示词文本、模型输出、用户邮箱或逐用户的稳定标识符。 +- 适配器 README 声明了 `User-Agent` 归属策略,并明确避免将 OpenRouter 应用归属记录为已实现的行为。 ## 曾考虑的替代方案 -**现在就实现 OpenRouter 应用归属。** 本 RFC 否决。发送 `HTTP-Referer` 加 `X-OpenRouter-Title` 可以满足 OpenRouter 排名,但这些头部是提供方特定的产品功能,不是本 RFC 试图标准化的提供方无关模型请求归属。支持它们应当是后续显式的 OpenRouter 适配器/模式决策,而非隐藏在第一个共享归属辅助函数中。 +**现在就实现 OpenRouter 应用归属。** 本 RFC 否决。发送 `HTTP-Referer` 加 `X-OpenRouter-Title` 可以满足 OpenRouter 排名,但这些头部是提供方特有的产品功能,不是本 RFC 试图标准化的提供方无关的模型请求归属。支持它们应当是后续显式的 OpenRouter 适配器/模式决策,而非隐藏在首个共享归属辅助函数中。 -**所有地方都发 OpenRouter 头部。** 否决。这会把一份自定义 OpenRouter 契约当作通用标准,并向未要求这些字段的提供方发送语义误导的字段。还有风险把 `HTTP-Referer` 当作通用应用 URL 字段使用,尽管标准 HTTP 已有 `User-Agent` 用于产品身份、`Referer` 用于不同的浏览上下文概念。 +**向所有提供方发送 OpenRouter 头部。** 否决。这会把一份自定义的 OpenRouter 契约当作通用标准,并向未要求这些字段的提供方发送语义误导的头部。还有风险将 `HTTP-Referer` 当作通用应用 URL 字段使用,尽管标准 HTTP 已有 `User-Agent` 用于产品身份、`Referer` 用于不同的浏览上下文概念。 -**仅使用提供方账户/项目身份。** 否决。组织/项目头部、API key、云账户和计费项目标识的是谁付费或谁拥有请求,而非哪个应用在发送流量。它们也不暴露公开的应用标题/分类,不帮助 OpenRouter 等网关构建应用排名。 +**仅使用提供方账户/项目身份。** 否决。组织/项目头部、API key、云账户和计费项目标识的是谁付费或谁拥有请求,而非哪个应用在发送流量。它们也不暴露公开的应用标题/类别,无法帮助 OpenRouter 等网关构建应用排名。 -**终端用户 `user`/`metadata` 字段。** 本 RFC 否决。这些对滥用监控和客户支持有价值,但描述的是请求背后的人或租户。应用归属必须是静态产品身份,且可安全地在每个请求上发送。 +**终端用户 `user`/`metadata` 字段。** 本 RFC 否决。这些对滥用监控和客户支持有价值,但描述的是请求背后的人或租户。应用归属必须是静态的产品身份,且可安全地在每个请求上发送。 -**仅配置 opt-in 的归属。** 否决。默认关闭的设置正是适配器持续漂移的原因。策略是强制默认归属加可覆盖的公开值,而非可选归属。 +**仅配置启用的归属。** 否决。默认关闭的设置正是适配器不断漂移的原因。策略是强制默认归属加可覆盖的公开值,而非可选归属。 -**以产品命名的令牌(`deepseek-harness-sdk`)。** 曾考虑用于 `User-Agent` 令牌,因为产品名是 DeepSeek Harness SDK。`deepseek-harness` 以连续性胜出:它是提供方已经从本代码库看到的身份,与组织/仓库身份和包作用域一致,且在展示文案承载产品名的同时保持线路归属稳定。 +**以产品命名的 token(`deepseek-harness-sdk`)。** 曾考虑用于 `User-Agent` token,因为产品名是 DeepSeek Harness SDK。`deepseek-harness` 因连续性胜出:它是提供方从本代码库已经看到的身份,与组织/仓库身份和包 scope 一致,且在展示文案承载产品名的同时保持线路归属稳定。 ## 后果 -**提供方看到流量来自 harness。** 这正是目的,但意味着此前混入通用 SDK 流量的部署变得可识别。缓解措施:仅发送静态公开产品数据,并允许 fork/白标部署传入自己的 `AppIdentity`。 +**提供方看到流量来自 harness。** 这正是目的,但意味着此前混在通用 SDK 流量中的部署变得可识别。缓解措施:仅发送静态公开产品数据,并允许 fork/白标部署传入自己的 `AppIdentity`。 -**应用 URL 指向一个尚不存在的仓库。** `deepseek-ai/deepseek-harness-sdk` 是计划中的公开主页;在创建之前该 URL 是一个悬空承诺。常量上的 `FIXME` 标记阻塞发布,使其不会在未解决的情况下发版(见 `docs/development.md` 标记语义)。 +**应用 URL 指向一个尚不存在的仓库。** `deepseek-ai/deepseek-harness-sdk` 是计划中的公开主页;在它创建之前,该 URL 是一个悬空承诺。常量上的 `FIXME` 标记阻塞发布,不允许带着未解决的问题出门(见 `docs/development.md` 标记语义)。 -**不同客户端库的头部支持有差异。** 手写适配器直接设置头部;pi-ai 封装的适配器依赖 pi-ai 继续遵守 `StreamOptions.headers`(最后合并覆盖提供方默认值)。线路级 mock 服务器测试是守卫:如果 pi-ai 升级后不再投递该头部,套件变红。这对抽象层是有益的压力:一个无法设置强制头部的提供方适配器无法完整实现 harness 的 LLM 契约。 +**不同客户端库的头部支持有差异。** 手写适配器直接设置头部;基于 pi-ai 的适配器依赖 pi-ai 继续尊重 `StreamOptions.headers`(最后合并覆盖提供方默认值)。线路级 mock 服务器测试是守卫:如果 pi-ai 升级后不再投递该头部,套件会变红。这对抽象施加了有益的压力:一个无法设置强制头部的提供方适配器不能完整实现 harness 的 LLM 契约。 -**OpenRouter 排名尚未受益。** `User-Agent` 是提供方无关 HTTP 身份的正确基线,但它不会创建 OpenRouter 应用页面或排名,因为 OpenRouter 要求 `HTTP-Referer` 才能实现该产品功能。这是有意为之:公开应用市场参与是一个独立的产品决策,不是强制请求归属的前提。 +**OpenRouter 排名尚未受益。** `User-Agent` 是提供方无关的 HTTP 身份的正确基线,但它不会创建 OpenRouter 应用页面或排名,因为 OpenRouter 要求 `HTTP-Referer` 来实现该产品功能。这是有意为之:公开应用市场参与是一个独立的产品决策,不是强制请求归属的前提。 diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml index 7a69d33245..06f5fb57d8 100644 --- a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-26-file-context-as-event-gate.md: 6e78e2df5f7969b5ed9b74c0b597e2fcacbe8e82 -2026-06-26-file-context-as-event-gate.zh.md: b0806fd3e1d61a9bdaf20a728dbfcfc945013b78 +2026-06-26-file-context-as-event-gate.zh.md: d69ccdbcea4b14dbd0291cf69af0bf7d5f3fadfc diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md index b0806fd3e1..d69ccdbcea 100644 --- a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md @@ -1,4 +1,4 @@ -# RFC:将 `dsh-fs-policy` 改为事件门禁插件,而非方法接口 +# RFC:将 `dsh-fs-policy` 改为事件门控插件,而非方法接口 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 在面向模型的工具与 `ctx.fs` 提供方之间放置了 `ctx.fileContext`:`dsh-tool-fs` 注入 `fileContext`,并将每次 `read`/`write`/`edit` 都路由到它的方法。这使得 `fileContext` **处于调用路径上且不可省略**。工具不经过它就无法触及 `ctx.fs`,策略层拥有 fs I/O 和读取窗口化,而一个不需要观测状态策略的部署无法简单地移除该包——否则 `dsh-tool-fs` 将无法解析 `ctx.fileContext`。 +[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 在面向模型的工具与 `ctx.fs` 提供方之间放置了 `ctx.fileContext`:`dsh-tool-fs` 注入 `fileContext`,并将每次 `read`/`write`/`edit` 路由到它的方法。这使得 `fileContext` **位于关键路径上且不可省略**。工具不经过它就无法访问 `ctx.fs`,策略层掌控着 fs I/O 和读取窗口,而一个不需要观测状态策略的部署也无法简单地移除该包——`dsh-tool-fs` 会因无法解析 `ctx.fileContext` 而失败。 这把三件本应可分离的事情耦合在了一起: @@ -14,11 +14,11 @@ Status: implemented 2. **新鲜度/观测策略**——"编辑前必须先读"、"写入/编辑必须基于你读到的版本"。这是 `dsh-fs-policy` 插件的职责。 3. **观测状态的记录**——一个副作用,永远不应阻止工具正常运行。 -因为工具调用 `fileContext` 的方法,移除策略层是一个破坏性变更,而非优雅地失去一个*附加功能*。策略对于工具的运行是承重的,而非可选的收紧。 +由于工具调用的是 `fileContext` 方法,移除策略层就是一个破坏性变更,而非优雅地失去一个*附加*能力。策略层对工具的运行是承重性的,而非可选的收紧。 ## 决策 -反转控制流。**`dsh-tool-fs` 成为执行器,直接调用 `ctx.fs`**;**`dsh-fs-policy` 成为门禁 + 记录器插件**,通过事件参与,既不通过工具调用的方法,也不注册 `ctx.fileContext` 服务。 +反转控制流。**`dsh-tool-fs` 成为执行器,直接调用 `ctx.fs`**;**`dsh-fs-policy` 成为门控 + 记录插件**,通过事件参与,从不通过工具调用的方法,也不注册 `ctx.fileContext` 服务。 ```text tool dsh-tool-fs executor: resolves, reads windows, writes/edits via ctx.fs; @@ -31,22 +31,22 @@ provider seam dsh-fs ctx.fs: text IO + ATOMIC mutation primitives who provider dsh-fs-local local implementation of ctx.fs ``` -该模型是叠加式的:裸 `ctx.fs` 执行原子的、无约束的文本 I/O,而 `dsh-fs-policy` 在其上叠加观测状态、读后才能编辑、以及版本守卫。因此移除策略后工具仍可用,只是不受约束。正式发布的 agent 配置会加载策略;裸模式的存在是为了在服务边界保持策略可选,而非作为正常部署姿态。 +该模型是叠加式的:裸 `ctx.fs` 执行原子化、无约束的文本 I/O,而 `dsh-fs-policy` 叠加观测状态、先读后编辑和版本守卫。因此移除策略层后工具仍可用,只是不受约束。正式发布的 agent 配置会加载策略;裸模式的存在是为了让策略在服务边界保持可选,而非作为正常部署姿态。 -`dsh-tool-fs` 不再注入 `fileContext`。它注入 `fs` 以及 `tools`/`systemPrompt`。 +`dsh-tool-fs` 不再注入 `fileContext`。它注入 `fs` 和 `tools`/`systemPrompt`。 -## 策略由提供方 CAS 强制执行,而非由 `dsh-fs-policy` stat +## 策略由提供方 CAS 强制执行,而非 `dsh-fs-policy` 的 stat -`dsh-fs-policy` 强制执行"你必须基于你读到的版本来写入/编辑",**自身从不调用 `stat` 或比较版本**。它将观测到的版本作为 CAS 基准提供,让提供方的变更临界区检测陈旧: +`dsh-fs-policy` 强制执行"你必须基于你读到的版本来写入/编辑",**自身从不调用 `stat` 或比较版本**。它将观测到的版本作为 CAS 基准提供,让提供方的 mutation 临界区检测陈旧性: - "你读过这个文件吗?"是 `dsh-fs-policy` 在本地决定的唯一事项——一次 `WeakMap` 查找,无 I/O。无记录 ⇒ `FS_NOT_OBSERVED`。 -- "你读到的版本还是最新的吗?"由 **`ctx.fs.editText`/`writeText` 内部**决定,在执行 read-match-rename 的同一把原子锁中。`dsh-fs-policy` 将 `vObserved` 作为期望值传入;如果文件已变更,提供方抛出 `FS_STALE_VERSION`。 +- "你读到的版本是否仍为最新?"由 **`ctx.fs.editText`/`writeText` 内部**决定,在执行 read-match-rename 的同一个原子锁中完成。`dsh-fs-policy` 将 `vObserved` 作为期望值传入;如果文件已变更,提供方抛出 `FS_STALE_VERSION`。 -这是刻意的设计。如果 `dsh-fs-policy` 在其 waterfall(瀑布式事件)处理器中 stat 并比较版本,那么该检查与工具实际写入之间会存在 TOCTOU 间隙——文件可能在两者之间变化,因此该检查只是一个虚假保证,提供方的锁无论如何都要兜底。将版本检查放在提供方的临界区内既无竞态又零额外 `stat`。所以 `dsh-fs-policy` **不做**任何文件系统 I/O;"必须基于最新读取"的保证由 CAS *实现*,`dsh-fs-policy` 只负责选择基准(`vObserved`)并对先前观测进行门控。 +这是有意为之的。如果 `dsh-fs-policy` 在其 waterfall(瀑布式事件)处理器中 stat 并比较版本,该检查与工具实际写入之间会存在 TOCTOU 间隙——文件可能在此期间变化,因此该检查只是一个虚假保证,提供方的锁无论如何都要兜底。将版本检查放在提供方的临界区中既无竞态又无额外 `stat`。所以 `dsh-fs-policy` **不做**任何文件系统 I/O;"必须基于最近一次读取"的保证由 CAS *实现*,`dsh-fs-policy` 只负责选择基准(`vObserved`)并对先前观测进行门控。 ## 提供方契约变更:版本守卫变为可选 -为使裸提供方不受约束,其两个变更操作上的版本守卫变为**可选**——有则守卫,无则无条件: +为使裸提供方不受约束,其两个 mutation 上的版本守卫变为**可选**——传入则守卫,省略则无条件执行: ```ts ignore-check // writeText: expected is now optional. The FsWriteIntent union is UNCHANGED. @@ -62,17 +62,17 @@ editText(target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion // { version } → edit only at that version, else FS_STALE_VERSION (the current behavior) ``` -`FsWriteIntent` 联合类型本身不变——第三种"无条件"状态通过*省略* `expected` 来表达,因此两个变更操作共享一个对称的形状(`expected?`:省略 = 无守卫,提供 = 有守卫)。这对 `dsh-fs-policy` 使用的有守卫路径保持完全向后兼容;只有之前不可能的"无守卫"情况是新增的,且它是裸提供方的默认行为。无论哪种情况,变更操作仍在后端的 per-target 锁内运行,因此无条件的写入/编辑仍然是原子的(不会出现文件撕裂);"无条件"去掉的是*版本*前置条件,而非原子性。`editText` 在有守卫和无守卫路径上都将缺失的目标报告为 `FS_STALE_VERSION`,为"此刻无法编辑该目标"保留一个统一的编辑失败码。 +`FsWriteIntent` 联合类型本身不变——第三种"无条件"状态通过*省略* `expected` 来表达,因此两个 mutation 共享同一种对称形状(`expected?`:省略 = 无守卫,传入 = 有守卫)。这对 `dsh-fs-policy` 使用的有守卫路径保持完全向后兼容;只有之前不可能出现的"无守卫"情况是新增的,且它是裸提供方的默认行为。无论哪种情况,mutation 仍在后端的 per-target 锁内运行,因此无条件写入/编辑仍是原子的(不会产生撕裂文件);"无条件"去掉的是*版本*前置条件,而非原子性。`editText` 在有守卫和无守卫路径上都将缺失目标报告为 `FS_STALE_VERSION`,保持一个统一的编辑失败码表示"此刻无法编辑该目标"。 -## 事件词汇(归属 `dsh-fs`) +## 事件词汇(由 `dsh-fs` 拥有) -事件定义在 `@deepseek-ai/dsh-fs` 中,而非 `dsh-fs-policy` 中。这是解耦契约所要求的:`dsh-tool-fs` 是事件发射方,因此它必须引用事件类型,且即使 `dsh-fs-policy` 不再提供方法服务,它也必须能编译通过。`dsh-fs` 是 `dsh-tool-fs` 和 `dsh-fs-policy` 都已依赖的包,因此它是唯一能让发射方和策略监听方共享词汇而不让发射方依赖策略插件的归属地。 +事件定义在 `@deepseek-ai/dsh-fs` 中,而非 `dsh-fs-policy` 中。这是解耦契约所迫:`dsh-tool-fs` 是发射方,因此它必须引用事件类型,且即使 `dsh-fs-policy` 不再提供方法服务,它也必须能编译通过。`dsh-fs` 是 `dsh-tool-fs` 和 `dsh-fs-policy` 都已依赖的包,因此它是唯一能让发射方和策略监听方共享词汇而不让发射方依赖策略插件的归属地。 -这些事件携带既有的 `dsh-fs` 词汇(`FsTarget`、`FsVersion`、`FsWriteIntent`)加上一个不透明的 actor——而非面向模型的概念(行窗口、行号、渲染页脚均不会泄漏到此层)。 +这些事件携带既有的 `dsh-fs` 词汇(`FsTarget`、`FsVersion`、`FsWriteIntent`)加一个不透明的 actor——不携带面向模型的概念(行窗口、行号或渲染后的页脚不会泄漏到此层)。 -**两个 `fs/*` 决策事件是单槽位、先到先得的 waterfall。** `dsh-fs-policy` 不调用 `next()` 即返回,因此在默认部署中它占据该槽位;一个注册更早或使用 `prepend` 的监听器会取代该策略。权限、审计和沙箱关注点仍在可组合的 `tools/execute` waterfall 上。 +**两个 `fs/*` 决策事件是单槽、先到先得的 waterfall。** `dsh-fs-policy` 不调用 `next()` 直接返回,因此在默认部署中它占据该槽位;更早注册或使用 `prepend` 的监听器会替代该策略。权限、审计和沙箱关注点仍留在可组合的 `tools/execute` waterfall 上。 -actor 在 `dsh-fs` 中类型为 `object`——一个纯粹的不透明载体,提供方 seam 从不读取或窄化它。owner 的推导(`actor.agent?.session`)和 `{ agent?: { session? } }` 结构形状完全留在 `dsh-fs-policy` 内部,由其监听器将 `object` actor 窄化为该形状。`dsh-fs` 拥有事件名和 fs 词汇;它**不**拥有策略层的运行时 owner 结构。 +actor 在 `dsh-fs` 中类型为 `object`——一个纯粹的不透明载体,提供方 seam 从不读取或收窄它。owner 的推导(`actor.agent?.session`)和 `{ agent?: { session? } }` 结构形状完全留在 `dsh-fs-policy` 内部,由其在监听器中将 `object` actor 收窄为该形状。`dsh-fs` 拥有事件名和 fs 词汇;它**不**拥有策略层的运行时 owner 结构。 ```ts import type { FsTarget, FsVersion, FsWriteIntent } from '@deepseek-ai/dsh-fs' @@ -106,66 +106,66 @@ interface Events { } ``` -`fs/*` 决策事件是**由工具分发的无绑定 waterfall**(类似 `agent/request`,由 loop 分发且无 `this`),而非服务绑定的 waterfall(如 `llm/stream`)。分发方是 `dsh-tool-fs` 插件,它不是一个服务。 +`fs/*` 决策事件是**由工具分发的无绑定 waterfall**(类似 `agent/request`,由循环分发且无 `this`),而非服务绑定的 waterfall(如 `llm/stream`)。分发者是 `dsh-tool-fs` 插件,它不是一个服务。 ## 工具契约(`dsh-tool-fs`) -工具保留其面向模型的 schema(`read`/`write`/`edit`,逐字节不变)和 prompt 段落。prompt 引导仍以策略为先,因为加载 fs 工具的部署预期也会加载 `dsh-fs-policy`:模型仍被告知在覆写或编辑前先读取,任何说"后端"要求如此的措辞应改为说 fs-policy 插件要求如此。裸提供方的回退不改变 prompt 立场。 +工具保留其面向模型的 schema(`read`/`write`/`edit`,逐字节不变)和 prompt 段落。prompt 引导仍以策略优先,因为加载 fs 工具的部署预期也会加载 `dsh-fs-policy`:模型仍被告知在覆写或编辑前先读取,任何声称"后端"要求如此的措辞应修正为 fs-policy 插件要求如此。裸提供方回退不改变 prompt 立场。 -`dsh-tool-fs` 获得了从旧 `fileContext` 方法服务迁移来的执行器职责,包括**读取渲染**(`read-render.ts`:`buildWindow` + `formatReadOutput`、`READ_MAX_BYTES`、`READ_MAX_LINE_LENGTH`、`FileReadOutcome`/`FileTextLine`,以及 `read.ts` 中的 `STREAM_MIN_SIZE`),这些现在是工具的渲染细节,因为工具拥有了读取操作。这些读取渲染类型和辅助函数迁入 `dsh-tool-fs`;策略插件不得继续作为工具的类型依赖。 +`dsh-tool-fs` 获得从旧 `fileContext` 方法服务迁移来的执行器职责,包括**读取渲染**(`read-render.ts`:`buildWindow` + `formatReadOutput`、`READ_MAX_BYTES`、`READ_MAX_LINE_LENGTH`、`FileReadOutcome`/`FileTextLine`,以及 `read.ts` 中的 `STREAM_MIN_SIZE`),这些现在是工具的渲染细节,因为读取已由工具拥有。这些读取渲染类型和辅助函数移入 `dsh-tool-fs`;策略插件不得继续作为工具的类型依赖。 -`dsh-tool-fs` 是一个注册全部三个工具(`read`/`write`/`edit`)的单根插件,与 `dsh-tool-bash` 对齐。它注入 `fs`(加 `tools`/`systemPrompt`),从不注入 `fileContext`。(最初的提案还将每个工具作为 `/read`/`/write`/`/edit` 子路径插件暴露,以支持聚焦部署;实现时已放弃——没有消费方需要单工具部署,且子路径发布迫使引入定制的 `tsdown`/`tsconfig`/`files`/workspace-constraint 处理,而同级的工具包都不需要这些。每工具的注册辅助函数(`applyReadTool`/`applyWriteTool`/`applyEditTool`)保留为根插件组合的内部模块。) +`dsh-tool-fs` 是一个注册全部三个工具(`read`/`write`/`edit`)的单一根插件,与 `dsh-tool-bash` 相同。它注入 `fs`(加 `tools`/`systemPrompt`),从不注入 `fileContext`。(最初的提案还将每个工具作为 `/read`/`/write`/`/edit` 子路径插件暴露,供聚焦部署使用;实现时被放弃——没有消费方需要单工具部署,且子路径发布迫使引入兄弟工具包都不需要的定制 `tsdown`/`tsconfig`/`files`/workspace-constraint 处理。每工具的注册辅助函数(`applyReadTool`/`applyWriteTool`/`applyEditTool`)仍作为根插件组合的内部模块保留。) -`stat` 预算通过让 waterfall 惰性产出期望值来最小化——裸默认返回 `undefined`(无守卫),从不 stat: +通过让 waterfall 惰性产出期望值来最小化 `stat` 预算——裸默认返回 `undefined`(无守卫),从不 stat: -- **read**——一次 `stat`(类型 + 大小路由 + 版本),然后 `readText`/`streamText`,然后 `buildWindow`,然后 `emit('fs/observed', target, info.version, exec)`。旧 `fileContext.read` 中读取后的确认 `stat` 被移除;在路由 stat 和读取之间竞争的写入者最多只能使*后续*有守卫的编辑虚假地 `FS_STALE_VERSION`(快速失败:模型重新读取,从不基于错误版本写入,因为 `editText` 在其锁内重新检查)。 -- **write**——`expectation = await ctx.waterfall('fs/write-intent', target, exec, () => undefined)`,然后 `ctx.fs.writeText(target, content, expectation)`,然后 `emit('fs/observed', target, outcome.version, exec)`。**工具内零 stat**,无论是否有 `dsh-fs-policy`。 -- **edit**——`expectation = await ctx.waterfall('fs/edit-intent', target, exec, () => undefined)`,然后 `ctx.fs.editText(target, edit, expectation)`,然后 `emit('fs/observed', target, outcome.version, exec)`。**两种情况下工具内均零 stat**:裸默认为 `undefined`(无条件编辑),因此工具从不 stat 来制造基准。如果目标不存在,提供方即使在无守卫路径上也报告 `FS_STALE_VERSION`。 +- **read**——一次 `stat`(类型 + 大小路由 + 版本),然后 `readText`/`streamText`,然后 `buildWindow`,然后 `emit('fs/observed', target, info.version, exec)`。旧 `fileContext.read` 中读后确认的 `stat` 被移除;在路由 stat 和读取之间竞争的写入者最多只能使*后续*有守卫的编辑误报 `FS_STALE_VERSION`(快速失败:模型重新读取,从不基于错误版本写入,因为 `editText` 在其锁内重新检查)。 +- **write**——`expectation = await ctx.waterfall('fs/write-intent', target, exec, () => undefined)`,然后 `ctx.fs.writeText(target, content, expectation)`,然后 `emit('fs/observed', target, outcome.version, exec)`。无论是否有 `dsh-fs-policy`,**工具内零 stat**。 +- **edit**——`expectation = await ctx.waterfall('fs/edit-intent', target, exec, () => undefined)`,然后 `ctx.fs.editText(target, edit, expectation)`,然后 `emit('fs/observed', target, outcome.version, exec)`。两种情况下**工具内零 stat**:裸默认为 `undefined`(无条件编辑),因此工具从不 stat 来制造基准。如果目标不存在,提供方即使在无守卫路径上也报告 `FS_STALE_VERSION`。 -工具在每次分发时将 `exec`(工具执行上下文)作为 `actor` 参数传入,这样 `dsh-fs-policy` 就能推导其观测状态的 owner。工具不知道策略插件是否存在:它总是在 `next` thunk 中提供裸默认行为,而 `dsh-fs-policy` 在默认部署中会在 thunk 运行前短路它。 +工具在每次分发时将 `exec`(工具执行上下文)作为 `actor` 参数传入,以便 `dsh-fs-policy` 推导其观测状态的 owner。工具不知道策略插件是否存在:它始终在 `next` thunk 中提供裸默认行为,而 `dsh-fs-policy` 在默认部署中会在 thunk 运行前短路它。 -**`fs/observed` 在操作成功后触发。** 其监听器必须是同步的、不抛异常的记录器;工具不对 plain emit 做守卫,因此抛异常的监听器会在变更已成功后报告失败。异步或可失败的观测需要另一个事件契约。 +**`fs/observed` 在操作成功后触发。** 其监听器必须是同步、不抛异常的记录器;工具不对 plain emit 做保护,因此抛异常的监听器会在 mutation 已成功后报告失败。异步或可失败的观测需要另一份事件契约。 ## 策略插件契约(`dsh-fs-policy`) -`dsh-fs-policy` 是一个插件,不是服务。它不注册 `ctx.fileContext`,没有公开方法面,也不暴露 `read`/`write`/`edit`/`resolve` 方法。它通过 `ctx.on()` 注册三个监听器(每个返回一个用于 HMR(热模块替换)的 disposer(资源释放))。它维护观测状态的 `WeakMap<owner, Map<targetKey, { version }>>` 和结构化的 owner 推导(将事件中不透明的 `object` actor 窄化为自己的 `{ agent?: { session? } }` 形状),但不注入 `fs`——每个处理器只操作自己的 `WeakMap`,从不操作 `ctx.fs`。 +`dsh-fs-policy` 是插件,不是服务。它不注册 `ctx.fileContext`,没有公开方法面,不暴露 `read`/`write`/`edit`/`resolve` 方法。它通过 `ctx.on()` 注册三个监听器(每个返回一个 disposer 用于 HMR)。它维护观测状态 `WeakMap<owner, Map<targetKey, { version }>>`,以及结构化的 owner 推导(将事件中不透明的 `object` actor 收窄为自己的 `{ agent?: { session? } }` 形状),但不注入 `fs`——每个处理器只操作自己的 `WeakMap`,从不操作 `ctx.fs`。 - `fs/write-intent` 监听器:`prior = getObserved(owner, key)`;返回 `prior ? { kind: 'replaceIfVersion', version: prior.version } : { kind: 'createIfAbsent' }`。它不调用 `next()`:完全占据单一决策槽位。 - `fs/edit-intent` 监听器:`prior = getObserved(owner, key)`;如果无 `owner` 或无 `prior`,抛出 `FS_NOT_OBSERVED`;否则返回 `{ version: prior.version }`。同样不调用 `next()`。 - `fs/observed` 监听器:`record(owner, key, version)`。 -一条观测状态条目是**先前观测记录**:成功的 `read`、`write` 或 `edit` 都会 emit `fs/observed` 并记录 `{ version }`,因此条目的存在意味着"该 owner 在此版本观测过该目标",而非狭义的"已读取过"。这使得 create-then-edit 或 edit-then-edit 序列无需中间重新读取即可工作:变更操作将记录的版本刷新为自身的结果,因此下一次编辑的基准就是它刚产出的版本。`FS_NOT_OBSERVED` 只拒绝完全没有任何先前观测的编辑。owner 从 `{ agent?: { session? } }` 结构化推导;dispose(资源释放)时丢弃所有状态(HMR 安全)。 +一条观测状态条目是**先前观测记录**:成功的 `read`、`write` 或 `edit` 都会 emit `fs/observed` 并记录 `{ version }`,因此条目的存在意味着"此 owner 在此版本观测过此目标",而非狭义的"已读取过"。这使得 create-then-edit 或 edit-then-edit 序列无需中间重新读取即可工作:mutation 将记录的版本刷新为自身的结果,因此下一次编辑的基准就是它刚产出的版本。`FS_NOT_OBSERVED` 只拒绝完全没有任何先前观测的编辑。owner 从 `{ agent?: { session? } }` 结构化推导;dispose 时丢弃所有状态(HMR 安全)。 -`dsh-fs-policy` 现在是一个纯策略/记录插件,没有服务面——它只通过事件 seam 影响外部世界。这正是从 `dsh-tool-fs` 移除方法耦合的关键。 +`dsh-fs-policy` 现在是一个纯策略/记录插件,没有服务面——它只通过事件 seam 影响外界。这正是移除 `dsh-tool-fs` 方法耦合的关键。 ## 裸提供方行为(无 `dsh-fs-policy`) -这不是预期的部署姿态——加载 fs 工具的配置预期也会加载 `dsh-fs-policy`。这是工具不再耦合于策略方法服务后存在的无约束提供方下限。在 `dsh-fs-policy` 缺席时,每个 `fs/*` waterfall 都落入其 `undefined` 默认值,`fs/observed` 无监听器: +这不是预期的部署姿态——加载 fs 工具的配置预期也会加载 `dsh-fs-policy`。它是工具不再耦合于策略方法服务后所存在的无约束提供方下限。当 `dsh-fs-policy` 不存在时,每个 `fs/*` waterfall 落入其 `undefined` 默认值,`fs/observed` 无监听器: -- **read** 不变(它从不需要策略;只是 emit 了一个现在无人听取的 `fs/observed`)。 -- **write** 无条件 create-or-overwrite:`expected` 为 `undefined`,因此 `writeText` 无论文件是否存在、无论当前版本如何都直接写入。无读取前置要求,无版本检查。 -- **edit** 无条件替换文件当前内容中的字面文本:`expected` 为 `undefined`,因此 `editText` 不带版本守卫或读取前置要求即进行匹配和重写(`FS_EDIT_NOT_FOUND`/`FS_AMBIGUOUS_EDIT` 仍然适用——它们关乎字面匹配,而非新鲜度)。缺失的目标仍报告 `FS_STALE_VERSION`,与有守卫编辑路径的"此刻无法编辑该目标"错误码一致。 +- **read** 行为不变(它从不需要策略;只是 emit 了一个现在无人监听的 `fs/observed`)。 +- **write** 无条件 create-or-overwrite:`expected` 为 `undefined`,因此 `writeText` 无论文件是否存在、无论当前版本如何都直接写入。无先读要求,无版本检查。 +- **edit** 无条件替换文件当前内容中的字面文本:`expected` 为 `undefined`,因此 `editText` 无版本守卫、无先读要求地匹配并重写(`FS_EDIT_NOT_FOUND`/`FS_AMBIGUOUS_EDIT` 仍适用——它们关乎字面匹配,而非新鲜度)。缺失目标仍报告 `FS_STALE_VERSION`,与有守卫编辑路径的"此刻无法编辑该目标"错误码一致。 -两个变更操作仍然是原子的(后端的 per-target 锁是无条件的)。简单地*不存在*(而非丢失)的是 `dsh-fs-policy` 本会叠加的策略:观测状态、读后才能编辑、以及版本守卫的写入/编辑。加载 `dsh-fs-policy` 后,其监听器返回有守卫的 `expected` 值而非 `undefined`,从而叠加这些约束;裸提供方本身不变。 +两个 mutation 仍是原子的(后端的 per-target 锁是无条件的)。仅仅是*不存在*(而非丢失)的是 `dsh-fs-policy` 本会叠加的策略:观测状态、先读后编辑和版本守卫的写入/编辑。加载 `dsh-fs-policy` 后,其监听器返回有守卫的 `expected` 值而非 `undefined`,从而叠加这些约束;裸提供方本身无需任何变更。 -## 取代 +## 取代关系 -本 RFC 修正——而非撤销——[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md)。四层拆分、提供方契约和新鲜度*策略*均保留。改变的是**工具与策略层之间的耦合方式**:一个强制方法服务变成了插件拥有的事件门禁,fs I/O + 读取窗口化从 `fileContext` 上移到了 `dsh-tool-fs`。split-fs-seam RFC 中关于 `dsh-tool-fs` 注入 `fileContext` 以及 `fileContext` 拥有 `read`/`write`/`edit` 的描述已在同一变更中更新。 +本 RFC 修正——而非推翻——[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md)。四层拆分、提供方契约和新鲜度*策略*均保留。变更的是**工具与策略层之间的耦合方式**:强制性方法服务变为插件拥有的事件门控,fs I/O + 读取窗口从 `fileContext` 上移至 `dsh-tool-fs`。split-fs-seam RFC 中关于 `dsh-tool-fs` 注入 `fileContext` 以及 `fileContext` 拥有 `read`/`write`/`edit` 的描述已在同一变更中更新。 ## 验证 -测试固定了两条路径:无 `dsh-fs-policy` 时,根工具插件对 `dsh-fs-local` 启动,read、create、overwrite 和未读取的 edit 均成功;有策略时,未读取的 edit 返回 `FS_NOT_OBSERVED`,未读取的 overwrite 被 `createIfAbsent` 门控。策略做出决策后,后注册的 intent 监听器不会被触达。陈旧编辑通过提供方 CAS 失败,而策略不执行 `stat`;工具的预算在两条路径上均为 read 一次 `stat`、write 或 edit 零次 `stat`。面向模型的 schema 逐字节不变,因此快照不变。 +测试固定了两条路径:无 `dsh-fs-policy` 时,根工具插件对 `dsh-fs-local` 启动,read、create、overwrite 和未读 edit 均成功;有策略时,未读 edit 返回 `FS_NOT_OBSERVED`,未读 overwrite 被 `createIfAbsent` 门控。策略决定后,后注册的 intent 监听器不会被触达。陈旧编辑通过提供方 CAS 失败,而策略不执行 `stat`;工具预算在两条路径上保持 read 一次 `stat`、write 或 edit 零次 `stat`。面向模型的 schema 逐字节不变,因此快照不变。 ## 曾考虑的替代方案 -- **保留 `ctx.fileContext` 作为路径内方法服务**——[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 最初落地的形态;否决,因为工具不加载策略层就无法运行,使策略对基本操作是承重的,而非可选的收紧。 -- **策略侧版本检查**(`dsh-fs-policy` 在其 waterfall 处理器中 stat 并比较)——否决,因为该检查与工具实际写入之间存在 TOCTOU 间隙;提供方的变更临界区是唯一无竞态的位置,因此策略只选择 CAS 基准并对先前观测进行门控。 -- **每工具 `/read`/`/write`/`/edit` 子路径插件**——实现时放弃。没有消费方需要单工具部署,且子路径发布迫使引入定制的 `tsdown`/`tsconfig`/`files`/workspace-constraint 处理,而同级的工具包都不需要这些;每工具的注册辅助函数保留为根插件组合的内部模块。 +- **保留 `ctx.fileContext` 作为关键路径上的方法服务**——[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 最初落地的形态;否决,因为工具无法在没有策略层的情况下运行,使策略对基本操作是承重性的,而非可选的收紧。 +- **策略侧版本检查**(`dsh-fs-policy` 在其 waterfall 处理器中 stat 并比较版本)——否决,因为该检查与工具实际写入之间存在 TOCTOU 间隙;提供方的 mutation 临界区是唯一无竞态的位置,因此策略只选择 CAS 基准并对先前观测进行门控。 +- **每工具 `/read`/`/write`/`/edit` 子路径插件**——实现时放弃:没有消费方需要单工具部署,且子路径发布迫使引入兄弟工具包都不需要的定制 `tsdown`/`tsconfig`/`files`/workspace-constraint 处理;每工具的注册辅助函数仍作为根插件组合的内部模块保留。 ## 后果 -- **事件间接层取代方法调用。** 一次 waterfall + emit 不如 `await ctx.fileContext.edit(...)` 直接。收益是移除了工具对策略的方法依赖,同时保留默认策略插件;代价是多了一套事件词汇需要学习。通过将三个事件保持窄小并在每个事件上记录 default-thunk 语义来缓解。 -- **策略事件放在存储 seam 中。** `dsh-fs` 获得了两个版本决策事件加一个记录事件,尽管它"只是存储"。这是解耦的代价(发射方不能依赖策略插件)。这些事件只携带 `dsh-fs` 词汇加一个不透明的 `object` actor,不含面向模型的概念,因此 seam 不会沾染行窗口/观测策略类型和 agent/session owner 结构。 -- **单策略占位,按约定先到先得。** `fs/write-intent`/`fs/edit-intent` 槽位恰好容纳一个决策者;先注册(或 `prepend` 的)监听器获胜,其余被短路。`dsh-fs-policy` 占据该槽位是部署约定,而非事件强制的不变式——一个先注册的第二决策者会绕过它。这是可接受的,因为第二个 fs 版本策略决策者是配置错误,而非功能特性。如果未来出现*分层* fs 版本策略的需求,那是一个新 RFC(可组合的值传递 seam),而非在这些事件上静默添加第二个监听器。分层的权限/审计/沙箱拦截已有其归属:`tools/execute`。 -- **移除读取后的确认 stat** 使后续*有守卫*的编辑在读写竞争下偶尔快速失败(`FS_STALE_VERSION` → 重新读取)。这是丢失的 UX 便利,从不是正确性漏洞;提供方锁仍然阻止基于错误版本的写入。 -- **裸提供方不做读后写入/编辑检查,也不做版本检查。** 不加载 `dsh-fs-policy` 的部署允许模型无条件覆写或编辑任何现有文件。这正是保持工具独立于策略服务的刻意含义:安全纪律存在于 `dsh-fs-policy` 插件中。省略它的部署是有意选择无约束的文件系统;这不是发布 fs 工具的配置的预期姿态。 +- **事件间接层取代方法调用。** 一次 waterfall + emit 不如 `await ctx.fileContext.edit(...)` 直接。收益是移除了工具到策略的方法依赖,同时保留默认策略插件;代价是多一套事件词汇需要学习。通过保持三个事件的窄小范围并在每个事件上记录 default-thunk 语义来缓解。 +- **策略事件位于存储 seam 中。** `dsh-fs` 增加了两个版本决策事件和一个记录事件,尽管它"只是存储"。这是解耦的代价(发射方不能依赖策略插件)。这些事件只携带 `dsh-fs` 词汇加一个不透明的 `object` actor,不携带面向模型的概念,因此 seam 不沾染行窗口/观测策略类型,也不沾染 agent/session owner 结构。 +- **单一策略占位者,按约定先到先得。** `fs/write-intent`/`fs/edit-intent` 槽位恰好容纳一个决策者;先注册(或 `prepend`)的监听器获胜,其余被短路。`dsh-fs-policy` 占据该槽位是部署约定,而非事件系统强制的不变式——一个先注册的第二决策者会绕过它。这是可接受的,因为第二个 fs 版本策略决策者是配置错误,而非功能。如果未来出现*分层* fs 版本策略的需求,那是一个新 RFC(可组合的值传递 seam),而非在这些事件上静默添加第二个监听器。分层的权限/审计/沙箱拦截已有其归属:`tools/execute`。 +- **移除读后确认 stat** 使后续*有守卫*的编辑在 read/write 竞争下偶尔快速失败(`FS_STALE_VERSION` → 重新读取)。这是丢失的 UX 便利,绝非正确性漏洞;提供方锁仍阻止基于错误版本的写入。 +- **裸提供方不做先读后写/编辑,也不做版本检查。** 没有 `dsh-fs-policy` 的部署允许模型无条件覆写或编辑任何已有文件。这正是保持工具独立于策略服务的有意含义:安全纪律存在于 `dsh-fs-policy` 插件中。省略它的部署是有意选择无约束的文件系统;对于发布 fs 工具的配置而言,这不是预期的姿态。 diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml index 041271d286..3bb8d3e607 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-30-bash-stdin-env-trusted-plugin-surface.md: 72aae03361cbc088cf64f3548a43ac6253eb21eb -2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md: 5c708cb6bfed28b2164cbd1d0b1c7368bf3e1d07 +2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md: f661199048b7eaa359f792e96ac52baf8cd61fdf diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md index 5c708cb6bf..f661199048 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:bash seam 上的 stdin 与额外 env +# RFC:在 bash seam 上支持 stdin 与额外 env Status: implemented @@ -6,28 +6,28 @@ Status: implemented ## 问题 -钩子子系统运行外部钩子命令的方式与 Claude Code 和 Codex 相同:一个钩子就是一条 shell 命令,通过 **stdin 上的 JSON** 接收事件载荷,并从若干**环境变量**(`CLAUDE_PROJECT_DIR`、`CLAUDE_PLUGIN_ROOT`、`PLUGIN_ROOT`……)读取上下文。harness 在 `ctx.bash` 能力 seam 背后已经有一个完善的命令运行器([dsh-bash](../../../../packages/bash/bash) → [dsh-bash-local](../../../../packages/bash/bash-local)),具备进程组 kill、输出截断/溢出处理和凭证擦除。将它复用于钩子执行,意味着钩子桥接层无需重新实现子进程管道——但该 seam 此前没有写入 stdin 或设置额外 env 的能力。本 RFC 添加这两项输入。 +钩子子系统以 Claude Code 和 Codex 的方式运行外部钩子命令:钩子是一条 shell 命令,通过 **stdin 上的 JSON** 接收事件载荷,并从若干**环境变量**(`CLAUDE_PROJECT_DIR`、`CLAUDE_PLUGIN_ROOT`、`PLUGIN_ROOT`……)读取上下文。harness 已经在 `ctx.bash` 能力 seam 后面有一个完善的命令执行器([dsh-bash](../../../../packages/bash/bash) → [dsh-bash-local](../../../../packages/bash/bash-local)),具备进程组终止、输出截断/溢出处理和凭证擦除功能。复用它来执行钩子意味着钩子桥接层无需重新实现子进程管道——但该 seam 此前无法写入 stdin 或设置额外 env。本 RFC 添加这两个输入。 -`stdin` 和 `env` 不构成新的模型能力,因为普通 shell 语法已经能提供这两者。环境中的凭证由 `dsh-bash-local` 的子进程环境擦除机制保护,而非靠隐藏这些 seam 字段;模型工具参数是静态 JSON,不会展开 shell 变量。因此这些字段服务于受信的进程内调用方(如钩子桥接层),它们需要传递结构化输入和 `CLAUDE_*` 变量,而不必将其嵌入模型可见的 shell 文本。环境变量规则见 [defensive-patterns.md](../../../defensive-patterns.md)。 +`stdin` 和 `env` 不构成新的模型能力,因为普通 shell 语法已经能提供两者。环境凭证由 `dsh-bash-local` 的子环境擦除机制保护,而非靠隐藏这些 seam 字段;模型工具参数是静态 JSON,不会展开 shell 变量。因此这些字段服务于受信的进程内调用方(如钩子桥接层),它们需要传递结构化输入和 `CLAUDE_*` 变量,而不必将其嵌入模型可见的 shell 文本。环境变量规则见 [defensive-patterns.md](../../../defensive-patterns.md)。 ## 决策 -在 `BashExecRequest`(面向模型/插件的请求)和 `BashExecSpec`(`run`/`start` 实际执行的解析后规格)上**同时**添加 `stdin?: string` 与 `env?: Record<string, string>`,并在 `dsh-bash-local` 中贯穿:`resolve()` 原样传递,`run()`/`start()` 将它们传给 `runBash`,后者把字节写入子进程的 stdin 并合并额外 env。 +在 `BashExecRequest`(模型/插件侧请求)和 `BashExecSpec`(`run`/`start` 所作用的已解析 spec)上**同时**添加 `stdin?: string` 与 `env?: Record<string, string>`,并在 `dsh-bash-local` 中贯穿它们:`resolve()` 原样传递,`run()`/`start()` 将其传给 `runBash`,后者把字节写入子进程的 stdin 并合并额外 env。 -三个刻意的选择: +三个有意为之的选择: -1. **面向模型的工具不暴露 `stdin` 和 `env`。** Shell 语法已经覆盖这些需求,重复的参数只会增加接口面而不带来权限隔离。工具仅从声明的模型参数、signal 和 owner 构建请求;受信的进程内调用方可以直接设置 seam 字段。 +1. **模型侧工具不暴露 `stdin` 和 `env`。** Shell 语法已覆盖这些需求,重复参数只会增加接口面而不带来权限隔离。工具仅从声明的模型参数、signal 和 owner 构建请求;受信的进程内调用方可以直接设置 seam 字段。 -2. **`env` 在凭证擦除之后合并,因此调用方显式设置的条目总是胜出**——即使名称看起来像凭证。这是正确的,因为擦除的职责很窄:阻止 harness 自身 *ambient* `process.env` 中的凭证泄漏到子命令中。调用方显式设置一个变量时,它命名的是自己已持有的值(而非 ambient 密钥),因此擦除不是对它的约束。`childEnv(extra?)` 的分层为 `scrub(process.env)` → `ENV_OVERRIDES`(面向模型的 `TERM=dumb` 等)→ `extra`,后者优先。 +2. **`env` 在凭证擦除之后合并,因此调用方显式设置的条目总是胜出**——即使键名与凭证同形。这是正确的,因为擦除的职责很窄:阻止 harness 的*环境* `process.env` 凭证泄漏到被 spawn 的命令中。调用方显式设置一个变量时,它命名的是自己已持有的值(而非环境中的秘密),因此擦除不构成对它的约束。`childEnv(extra?)` 按 `scrub(process.env)` → `ENV_OVERRIDES`(对模型友好的 `TERM=dumb` 等)→ `extra` 的顺序分层,后者优先。 -3. **`stdin`/`env` 在解析后规格上是 required-absent-OK(普通 optional),而非像 `owner` 那样 required-but-nullable。** `owner` 之所以是 required-but-nullable,是因为*静默*缺失的 owner 会产生一个无主的、跨会话可读的任务——这是一个安全隐患,显式的 `undefined` 可以防范。`stdin`/`env` 没有这种风险:缺失意味着「无 stdin / 无额外 env」,这是安全的常规情况(所有模型驱动的调用都如此)。因此它们保持普通 optional,与 `signal` 一致。 +3. **`stdin`/`env` 在已解析 spec 上是 required-absent-OK(普通 optional),而非像 `owner` 那样 required-but-nullable。** `owner` 之所以是 required-but-nullable,是因为*静默*缺失的 owner 会产生一个无主、跨会话可读的任务——一个安全隐患,显式的 `undefined` 可以防范。`stdin`/`env` 没有这种风险:缺失意味着「无 stdin / 无额外 env」,这是安全的常规情况(所有模型驱动的调用都如此)。因此它们保持普通 optional,与 `signal` 一致。 -`dsh-bash-local` 仅在提供了字节时才创建 stdin 管道;否则 fd 0 保持 `/dev/null`,维持原有行为。它写入字节后关闭管道。如果子进程未读取就退出导致 `EPIPE`,则忽略该错误,因为命令退出状态和输出决定结果。 +`dsh-bash-local` 仅在有字节需要写入时才创建 stdin 管道;否则 fd 0 仍为 `/dev/null`,保持先前行为。它写入字节后关闭管道。子进程未读取即退出时产生的 `EPIPE` 被忽略,因为命令退出码和输出决定结果。 ## 曾考虑的替代方案 -**可配置的 ambient 密钥擦除。** 否决,属于推测性需求。受信调用方可以在擦除之后显式提供所需值,无需削弱默认的 ambient 保护。 +**可配置的环境秘密擦除。** 否决,属于推测性需求。受信调用方可以在擦除之后显式提供所需值,无需削弱默认的环境保护。 ## 后果 -钩子桥接层通过既有的 bash seam 传递 JSON 载荷和钩子专属变量,保留其进程组管理、截断和溢出行为。模型接口面不变,bash 工具仍是模型调用请求构建的唯一入口。相关词汇定义见 [bash 数据结构参考](../../../core-data-structures/bash.md)。 +钩子桥接层通过既有的 bash seam 传递 JSON 载荷和钩子特定变量,保留其进程组终止、截断和溢出行为。模型接口面不变,bash 工具仍是模型调用请求构建的唯一所有者。相关词汇定义见 [bash 数据结构参考](../../../core-data-structures/bash.md)。 diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml index 557ac2bab4..2416919ab7 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-30-event-domain-semantics.md: e05c238c52052454d3e01e82767cddd9af316a9d -2026-06-30-event-domain-semantics.zh.md: a5453824183aa3f71486b5dbd24ed8c056d9c854 +2026-06-30-event-domain-semantics.zh.md: 9048679ec7a7992852cce76bf43269f5499da792 diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md index a545382418..9048679ec7 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md @@ -1,4 +1,4 @@ -# RFC:事件域语义——session 是事实日志,agent 是实时表面 +# RFC:事件域语义——session 是事实日志,agent 是运行时表面 Status: implemented @@ -6,34 +6,34 @@ Status: implemented ## 问题 -harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环)(见[微内核事件分类体系 RFC](2026-06-11-microkernel-event-taxonomy.md))。随着分类体系的增长,三个事件域之间的界限变得模糊: +harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环)(见[微内核事件分类体系 RFC](2026-06-11-microkernel-event-taxonomy.md))。随着该分类体系的增长,三个事件域之间的界限变得模糊: - `session/*` 承载持久的、事件溯源的日志(`SessionEventMap`)。 -- `agent/*` 承载实时运行时信号,向插件传递 `Agent` 句柄。 +- `agent/*` 承载运行时实时信号,向插件传递 `Agent` 句柄。 - `tools/*` 承载工具注册表与执行 seam。 -两个问题促使我们明确固定这些语义。第一,若干轮次/步骤边界同时以持久的 `SessionEvent`(`turn/start`、`turn/end`、`step/start`、`step/end`)和镜像的 `agent/*` emit(`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`)两种形式存在。消费方对同一事实有两个真源,每次生命周期变更都必须同时更新两处。第二,即将到来的 Hooks 子系统需要一个统一、有文档的订阅表面:插件作者(以及基于其上构建的 Claude Code / Codex 钩子桥接)必须无需阅读循环代码就能判断应该监听会话事件还是 agent 事件,以及为什么。 +两个问题促使我们固定语义。第一,若干轮次/步骤边界同时作为持久的 `SessionEvent`(`turn/start`、`turn/end`、`step/start`、`step/end`)**和**镜像的 `agent/*` emit(`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`)存在。消费方对同一事实有两个真源,每次生命周期变更都必须同时更新两处。第二,即将到来的 Hooks 子系统需要**一个**连贯且有文档的订阅表面——插件作者(以及基于其上构建的 Claude Code / Codex 钩子桥接)必须在不阅读循环代码的情况下知道应该监听 session 事件还是 agent 事件,以及原因。 -这套词汇是拦截决策、持久的 `hook/*` 日志,以及 Claude Code 与 Codex 桥接的基础。 +这套词汇是拦截决策、持久的 `hook/*` 日志,以及 Claude Code 和 Codex 桥接的基础。 ## 决策 -**三个域,各司其职,一条边界规则。** +**三个域,各司其职,以一条边界规则统一。** -- **`session/*`——持久的、可回放的事实日志。** 拥有 `SessionEventMap`;每条记录仅含 JSON(无活对象)。每次追加触发一次 `session/event` emit,加上 `session/flush` 并行持久性检查点。它同时也是实时 transcript(文本记录)流:想要渲染或响应已发生事件的消费方在此订阅,因此实时渲染与 `session/load` 回放共享同一路径。 -- **`agent/*`——实时运行时表面。** 始终携带活的 `Agent`。两种形态:拦截型 waterfall(瀑布式事件)(`agent/request`、`agent/step-result`、`agent/turn-continuation`)可修改或否决,以及瞬态 emit(`agent/status`、`agent/error`、`agent/created`/`agent/disposed`、`agent/queued`)在持有 `Agent` 的情况下通知。轮次和步骤的**边界**不在此域——它们是持久的会话事件,从 `session/event` 读取;token 流(`assistant/chunk`)和中途引导(`steering/message`)同理。 +- **`session/*`——持久的、可回放的事实日志。** 拥有 `SessionEventMap`;每条记录仅含 JSON(无活对象)。每次追加触发一次 `session/event` emit,加上 `session/flush` 并行持久性检查点。它同时也是实时 transcript(文本记录)源:想渲染或响应已发生事件的消费方在此订阅,因此实时渲染与 `session/load` 回放共享同一路径。 +- **`agent/*`——运行时实时表面。** 始终携带活的 `Agent`。两种形态:拦截 waterfall(瀑布式事件)(`agent/request`、`agent/step-result`、`agent/turn-continuation`)可变更或否决;瞬态 emit(`agent/status`、`agent/error`、`agent/created`/`agent/disposed`、`agent/queued`)在持有 `Agent` 的情况下通知。轮次和步骤**边界**不在此处——它们是持久的 session 事件,从 `session/event` 读取;token 流(`assistant/chunk`)和中途 steering(中途引导)(`steering/message`)同理。 - **`tools/*`——工具注册表与执行 seam。** -**边界规则:** 持久的、可回放的事实是 `SessionEvent`;实时拦截或瞬态/活对象信号是 `agent`/`tools` Cordis 事件。轮次或步骤边界是持久事实,因此存在于会话日志中、从 `session/event` 流读取——不会被镜像为 `agent/*` emit。 +**边界规则:** 持久的、可回放的事实是 `SessionEvent`;实时拦截或瞬态/活对象信号是 `agent`/`tools` Cordis 事件。轮次或步骤边界是持久事实,因此存在于 session 日志中并从 `session/event` 源读取——不会被镜像为 `agent/*` emit。 -**将规则应用于边界镜像:** 全部四个边界镜像——`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`——被**移除**。没有生产消费方需要在边界处持有活的 `Agent`:ACP 桥接从 `session/event` 的 `turn/end` 加 `agent/status` 结算;唯一的 turn 镜像消费方(`dsh-ui-stdio`,一个一次性测试 REPL)已迁移为从 `session/event` 渲染边界,通过 `agent/created`→id 映射恢复简短的 agent 标签。step 镜像先被移除(它们根本没有消费方);turn 镜像在 ui-stdio 迁移后随之移除——见[移除边界镜像事件 RFC](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md),该决策由它拥有。移除这些 emit 也简化了循环的 `closeStep`/`closeTurn`(各只需一次 append,无需配对 emit)。 +**将规则应用于边界镜像:** 全部四个边界镜像——`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`——被**移除**。没有生产消费方需要在边界处获取活的 `Agent`:ACP 桥接从 `session/event` 的 `turn/end` 加 `agent/status` 结算;唯一的 turn 镜像消费方(`dsh-ui-stdio`,一个一次性测试 REPL)已迁移为从 `session/event` 渲染边界,通过 `agent/created`→id 映射恢复简短的 agent 标签。step 镜像先被移除(它们完全没有消费方);turn 镜像在 ui-stdio 迁移后随之移除,见[移除边界镜像事件 RFC](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md),该决策由它负责。移除 emit 也简化了循环的 `closeStep`/`closeTurn`(各只需一次 append,无需配对 emit)。 ## 后果 -- 循环不再 emit 任何边界镜像;`closeStep` 仅追加 `step/end`,`closeTurn` 仅追加 `turn/end`。`Session.append` 负责 post-commit observer 的隔离,因此抛出异常的边界 observer 无法改变轮次结果或饿死后续消费方;acceptance 或内部校验失败仍会在边界进入日志之前逃逸。 -- 之前通过已移除 emit 观察边界的测试现在观察持久的 `turn/start`/`turn/end`/`step/start`/`step/end` 会话事件——它们所固定的行为(边界排序、步骤计数)不变;只是读取的流切换到了权威的那一个。那些测试「抛出异常的 turn 边界 emit 监听器」的用例被删除,因为该代码路径已不存在(没有 emit 可供抛出)。按照 [AGENTS.md "tests document behavior, not golden truth"](../../../../AGENTS.md),行为与其测试一起迁移(或一起消亡)。 -- 循环仅在 `append('step/start')` 返回后才标记步骤为已打开(`stepOpen = true`)。内部 dispatch 校验在日志推送前运行,可能在不打开步骤的情况下拒绝;post-commit `session/event` observer 的失败被隔离在 `Session.append` 内部。因此该标记精确代表已提交的边界,该边界欠一个后续的 `step/end`。 -- 本 RFC 的完整实现是[简化 RFC「停止将持久边界镜像为 agent 事件」](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md):全部四个边界镜像被移除,所有消费方从 `session/event` 读取边界。`agent/steering`(不是边界镜像)不在该 RFC 范围内,由其后续 RFC [移除 `agent/steering` 镜像 emit](../simplification/2026-07-04-remove-agent-steering-mirror.md) 单独移除——它镜像的是持久的 `steering/message`。 +- 循环不再 emit 任何边界镜像;`closeStep` 仅追加 `step/end`,`closeTurn` 仅追加 `turn/end`。`Session.append` 负责 post-commit observer 隔离,因此抛出异常的边界 observer 无法改变轮次结果或饿死后续消费方;接受或内部校验失败仍会在边界进入日志之前逃逸。 +- 之前通过已移除 emit 观察边界的测试,现在观察持久的 `turn/start`/`turn/end`/`step/start`/`step/end` session 事件——它们固定的行为(边界顺序、步骤计数)不变;只是读取的源移到了规范源。那些测试「抛出异常的 turn 边界 emit 监听器」的用例被删除,因为该代码路径不再存在(没有 emit 可供抛出)。按照 [AGENTS.md「测试记录行为,而非黄金真相」](../../../../AGENTS.md),行为与其测试一同迁移(或一同消亡)。 +- 循环仅在 `append('step/start')` 返回后才标记步骤已打开(`stepOpen = true`)。内部分发校验在日志推入之前运行,可能在不打开步骤的情况下拒绝;post-commit `session/event` observer 的失败被隔离在 `Session.append` 内部。因此该标记精确表示已提交的、欠一个后续 `step/end` 的边界。 +- 完整实现见[简化 RFC「停止将持久边界镜像为 agent 事件」](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md):全部四个边界镜像被移除,所有消费方从 `session/event` 读取边界。`agent/steering`(不是边界镜像)不在该 RFC 范围内,由其后续 RFC [移除 `agent/steering` 镜像 emit](../simplification/2026-07-04-remove-agent-steering-mirror.md) 单独移除——它镜像的是持久的 `steering/message`。 - Cordis 事件目录(`docs/cordis-catalog/events.md`)重新生成以移除镜像事件。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml index fc9d825dc0..3cff8c7aca 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-02-fs-per-session-cwd.md: 00643955d918dff87241f4b240bb7e6774d21a0b -2026-07-02-fs-per-session-cwd.zh.md: ca37e1f41af53c43151ac82e1be1b76eaafdb97e +2026-07-02-fs-per-session-cwd.zh.md: 73176cde3747a2eb8c03aadbf3f419bf27173d70 diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md index ca37e1f41a..73176cde37 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md @@ -1,34 +1,34 @@ -# RFC:将文件系统路径解析基于调用方的会话 cwd - -Status: implemented +# RFC:相对文件系统路径按调用方的会话 cwd 解析 [English](2026-07-02-fs-per-session-cwd.md) | 中文 +Status: implemented + ## 问题 -ACP 桥接层为每个会话提供独立的工作区:`session/new` 将编辑器的项目目录记录为 `SessionHeader.cwd`,`dsh-tool-bash` 将每次 bash 调用的 `workdir` 默认设为调用方 agent 的 `session.header.cwd`(见 [`packages/ui/acp`](../../../../packages/ui/acp) 中的 per-session cwd RFC 相关工作,以及 `dsh-tool-bash` 中的 `resolveWorkdir`)。因此会话 A 中的 bash 命令在 A 的项目目录运行,会话 B 中的在 B 的项目目录运行——一个服务器进程,N 个工作区。 +ACP(Agent Client Protocol)桥接层为每个会话提供独立的工作区:`session/new` 将编辑器的项目目录记录为 `SessionHeader.cwd`,`dsh-tool-bash` 将每次 bash 调用的 `workdir` 默认设为调用方 agent(智能体)的 `session.header.cwd`(见 [`packages/ui/acp`](../../../../packages/ui/acp) 中的 per-session cwd RFC 工作与 `dsh-tool-bash` 中的 `resolveWorkdir`)。因此会话 A 中的 bash 命令在 A 的项目目录执行,会话 B 中的在 B 的项目目录执行——一个服务器进程,N 个工作区。 -文件系统路径解析使用的是插件加载时的单一 cwd,而 bash 使用的是会话的项目目录。因此,当编辑器项目目录与服务器启动目录不同时,相对路径的解析结果就会不一致;快照测试因为让这两个路径相同而掩盖了这个 bug。 +文件系统解析使用的是插件加载时的 cwd,而 bash 使用的是会话的项目目录。因此,当编辑器项目目录与服务器启动目录不同时,相对路径的解析结果就会不一致;快照测试因为让这两个路径相同而掩盖了这个 bug。 ## 决策 -将调用方的会话 cwd 透传到路径解析中,与 `dsh-tool-bash` 对 `workdir` 的处理方式完全一致。**调用方**(即工具)提供 cwd;提供方不读取会话或 agent。 +将调用方的会话 cwd 传入路径解析,与 `dsh-tool-bash` 对 `workdir` 的处理方式完全一致。**调用方**(即工具)提供 cwd;提供方不读取会话或 agent。 -- `FileSystem.resolve` 扩展为 `resolve(path: string, opts?: { cwd?: string }): Promise<FsTarget>`。`opts.cwd` 是相对 `path` 的解析基准;绝对 `path` 忽略它;省略 `opts.cwd` 时使用后端自身的默认值。使用 options 对象(而非位置参数 `cwd?`)为将来的解析提示留出空间,无需再次变更签名。 -- `dsh-fs-local.resolve` 使用 `resolveLocalTarget(opts?.cwd ?? this.config.cwd, path)`。`config.cwd` 仍是调用方未提供 cwd 时的默认值(非 ACP/无会话场景,以及 `process.cwd()` 本身就是工作区的单会话 stdio 演示)。 -- `dsh-tool-fs` 的 `read`/`write`/`edit` 通过共享的 `sessionCwd(exec)` 辅助函数获取会话 cwd(`exec.agent?.session.header.cwd`,与 bash 的 `resolveWorkdir` 一致),并传给 `resolve`。非 agent/无 header 的调用方返回 `undefined`,后端则应用其默认值。 +- `FileSystem.resolve` 扩展为 `resolve(path: string, opts?: { cwd?: string }): Promise<FsTarget>`。`opts.cwd` 是相对 `path` 解析时的基准目录;绝对 `path` 忽略它;省略 `opts.cwd` 则使用后端自身的默认值。采用 options 对象(而非位置参数 `cwd?`)为将来的解析提示留出空间,无需再次变更签名。 +- `dsh-fs-local.resolve` 使用 `resolveLocalTarget(opts?.cwd ?? this.config.cwd, path)`。`config.cwd` 仍作为调用方未提供 cwd 时的默认值(非 ACP/无会话场景,以及 `process.cwd()` 本身就是工作区的单会话 stdio 演示)。 +- `dsh-tool-fs` 的 `read`/`write`/`edit` 通过共享的 `sessionCwd(exec)` 辅助函数(`exec.agent?.session.header.cwd`,与 bash 的 `resolveWorkdir` 对应)获取会话 cwd,并传给 `resolve`。非 agent/无 header 的调用方得到 `undefined`,后端因此应用其默认值。 ## 曾考虑的替代方案 -### 为什么由调用方提供 cwd(而非提供方) +### 为何由调用方(而非提供方)提供 cwd -提供方 seam 不应依赖 `dsh-agent`/`dsh-session`:它是一个文本存储后端,沙箱或远程实现同样满足该接口,而它们没有「agent 会话」的概念。工具已经接收到 `ToolExecution`(`exec`),其中携带了 agent,因此工具是将 `exec → cwd` 投影并向提供方传递一个纯字符串的正确位置。这遵循「包边界处显式优于隐式」的约定:基目录作为显式参数到达提供方并由其执行,而非让提供方越界去读取它不应知道的会话。这也与 `dsh-tool-bash` 一一对应,使两个面向模型的文件操作接口以相同方式解析路径。 +提供方 seam 不得依赖 `dsh-agent`/`dsh-session`——它是一个文本存储后端,沙箱或远程实现同样满足该接口,而这些实现没有「agent 会话」的概念。工具已经接收了 `ToolExecution`(`exec`),其中携带 agent,因此工具是将 `exec → cwd` 投影并向提供方传递一个纯字符串的正确位置。这遵循「包(package)边界处显式优于隐式」的约定:基准目录作为显式参数传入,提供方据此行动,而非让提供方越界去读取它不应知晓的会话。这也与 `dsh-tool-bash` 一一对应,使两个面向模型的文件操作接口以相同方式解析路径。 -默认值只存在于**一个**地方:提供方的 `config.cwd`。`sessionCwd` 在没有会话时返回 `undefined` 而非 `process.cwd()`,因此工具永远不会制造一个提供方本来会自行选择的基目录。 +默认值只存在于**一个**地方——提供方的 `config.cwd`。`sessionCwd` 在没有会话时返回 `undefined` 而非 `process.cwd()`,因此工具永远不会自行制造一个提供方本应自行选择的基准目录。 ## 后果 -- 在 ACP 演示中,fs 工具和 bash 现在对每个会话的工作区达成一致;编辑器可以打开任意项目文件夹,两类工具都在该目录下工作。 -- `FsTarget` 的标识不变:`targetKey` 仍然是解析后绝对路径的 realpath,因此 observed-state 键控和符号链接标识不受影响——正确的 per-session cwd 产生的 key 与 bash 目标一致。 +- 在 ACP 演示中,fs 工具与 bash 现在对每个会话的工作区达成一致;编辑器可以打开任意项目目录,两类工具都在该目录下操作。 +- `FsTarget` 的标识不变:`targetKey` 仍为解析后绝对路径的 realpath,因此 observed-state 键控与符号链接标识不受影响——正确的 per-session cwd 产生与 bash 目标相同的 key。 - 向后兼容:所有现有的 `resolve(path)` 调用(均在测试中)继续正常工作;新参数是可选的。 - 单会话 stdio 演示不受影响:它不提供会话 cwd(其 agent 的会话没有 `cwd`),因此解析回退到 `config.cwd = process.cwd()`,即工作区本身。 diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml index b5dcdf42f8..0401c48e08 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-02-result-time-applied-hunk-diffs.md: 81ab8b9827ddaec39d63e2a3f8fbb864085a9ac9 -2026-07-02-result-time-applied-hunk-diffs.zh.md: 3914bb872025d7116a047dfaf3455f527e35879a +2026-07-02-result-time-applied-hunk-diffs.zh.md: 2914c4242c4246ede8588967ed36b3f6c725c607 diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md index 3914bb8720..2914c4242c 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md @@ -1,20 +1,20 @@ # RFC:结果时刻的 applied-hunk diff 用于文件变更 -Status: implemented - [English](2026-07-02-result-time-applied-hunk-diffs.md) | 中文 +Status: implemented + ## 问题 -[带标签的渲染意图联合类型](2026-07-02-tool-render-intent-union.md)为 `dsh-tool-fs` 的 write/edit 在调用时(CALL time)提供了 `card:'diff'`,纯粹从工具参数推导:write ⇒ `{oldText:null, newText:content}`(整个新文件),edit ⇒ `{oldText:old_string, newText:new_string}`(裸替换片段)。编辑器将其渲染为行内 diff,但这是一个**无上下文**的 diff:裸的 `old_string`→`new_string` 没有周围行,而一次 `replace_all` 如果触及五个分散位置,仍然只渲染为一对片段。 +[tagged render-intent union](2026-07-02-tool-render-intent-union.md) 为 `dsh-tool-fs` 的 write/edit 在调用时刻提供了 `card:'diff'`,纯粹从工具参数推导:write ⇒ `{oldText:null, newText:content}`(整个新文件),edit ⇒ `{oldText:old_string, newText:new_string}`(裸替换片段)。编辑器将其渲染为行内 diff,但这是一个**无上下文**的 diff:裸的 `old_string`→`new_string` 没有周围行,而一次触及五个分散位置的 `replace_all` 仍然渲染为一对片段。 -驱动 `claude-agent-acp` 自身的 ACP 桥接层可以看到完整编辑器 diff 的样子:变更应用后,它发出第二个 `tool_call_update`,其 diff 是**带 ±3 行上下文的 applied hunk**(`replace_all` 的每个变更位置各一个 hunk),由工具的 `structuredPatch` 重建。这个结果时刻的 hunk 正是让 Zed 在文件中*原地*展示变更(而非浮动片段)的关键。我们的工具止步于调用时片段;完成后的结果只携带纯文本 "updated successfully",没有 diff。 +在对接 `claude-agent-acp` 自身的 ACP(Agent Client Protocol) bridge 时可以看到完整编辑器 diff 的样子:变更应用后,它发出第二个 `tool_call_update`,其 diff 是**带 ±3 行上下文的 applied hunk**(`replace_all` 的每个变更位置各一个 hunk),由工具的 `structuredPatch` 重建。这个结果时刻的 hunk 正是让 Zed 在文件中**原位**显示变更(而非浮动片段)的关键。我们的工具止步于调用时刻的片段;完成后的结果只携带纯文本 "updated successfully",没有 diff。 -障碍在于一个 seam 边界:`presentResult(args, result)` 是 **`args` + 面向模型的 `result`(`{content, isError}`)的纯函数**——它在实时流式输出和会话日志回放时都会运行,因此必须具有回放确定性且不能做 I/O。它看不到文件的变更前/后内容,而 `FsEditOutcome`/`FsWriteOutcome` 只携带替换计数 + 版本,没有文本。因此既无法计算、也无法传递 applied hunk 给 presenter。 +障碍在于一个 seam 边界:`presentResult(args, result)` 是 **`args` + 面向模型的 `result`(`{content, isError}`)的纯函数**——它在实时流式输出和会话日志回放中都会运行,因此必须具备回放确定性且不能做 I/O。它看不到文件的前后内容,而 `FsEditOutcome`/`FsWriteOutcome` 只携带替换计数和版本号,没有文本。因此无法计算——甚至无法携带——applied hunk 给 presenter。 ## 决策 -新增一个**持久化的、工具私有的展示通道**,使工具的 `execute` 能附加一个结果时刻的渲染载荷并在回放中存活,并用它来承载 applied-hunk diff。 +添加一个**持久化的、工具私有的展示通道**,使工具的 `execute` 能附加一个结果时刻的渲染载荷并在回放中存活,并用它来携带 applied-hunk diff。 ### 1. 工具结果上的 `meta` 通道(core) @@ -24,38 +24,38 @@ Status: implemented type ToolExecuteReturn = ContentBlock[] | { content: ContentBlock[]; meta?: unknown } ``` -`meta` 是工具自有的 `unknown`,core 持久化它但不解释。`Session.append` 拒绝非 JSON 值,回放时将存储的载荷传回 `presentResult`;因此展示无需 I/O 或重新计算即可复现。运行时校验避免了向 tools core 添加共享的 serializable-value 依赖。 +`meta` 是工具自有的 `unknown`,core 持久化但不解释。`Session.append` 拒绝非 JSON 值,回放时将存储的载荷回传给 `presentResult`;因此展示无需 I/O 或重新计算即可复现。运行时校验避免了向 tools core 添加共享的 serializable-value 依赖。 -这是通用形态("工具附加持久化的结果展示"),而非 fs 专用——任何工具都可以使用。 +这是通用形态("工具附加持久化的结果展示"),而非 fs 特有的——任何工具都可以使用。 -### 2. 工具计算 hunk;后端返回变更前/后文本(fs) +### 2. 工具计算 hunk;后端返回 before/after(fs) -按照[能力-seam 拆分](2026-06-13-capability-seams.md),存储后端只返回**存储事实**,面向模型的工具拥有**展示**: +按照 [capability-seam 拆分](2026-06-13-capability-seams.md),存储后端只返回**存储事实**,面向模型的工具拥有**展示**: -- `dsh-fs` 扩展 `FsEditOutcome`,增加 `{ before: string; after: string }`;扩展 `FsWriteOutcome`,增加 `{ before: string | null; after: string }`(`before: null` ⇒ 新建文件,或已存在但不可 diff 的二进制/非 UTF-8 文件)。本地后端在写入时已持有两份文本;它以原始 LF 规范化文本返回,**不让任何 diff/UI 概念进入 seam**。 -- `dsh-tool-fs` 将带上下文的 hunk 存入 `meta: { diffs: FileDiff[] }`。成功的变更始终以 diff 卡片完成,因为 ACP 结果内容会替换 pending 卡片:新建或无变化的覆写回退为参数推导的全文件 diff,而编辑使用 applied hunk。失败的变更不携带 diff 元数据,正常渲染错误信息。 +- `dsh-fs` 将 `FsEditOutcome` 扩展为包含 `{ before: string; after: string }`,将 `FsWriteOutcome` 扩展为包含 `{ before: string | null; after: string }`(`before: null` 表示创建,或已存在但不可 diff 的二进制/非 UTF-8 文件)。本地后端在写入时已持有两份文本;它以原始 LF 规范化文本返回,**不让任何 diff/UI 概念进入 seam**。 +- `dsh-tool-fs` 将上下文 hunk 存入 `meta: { diffs: FileDiff[] }`。成功的变更始终以 diff 卡片完成,因为 ACP 结果内容会替换待定卡片:创建或无变化的覆写回退到由参数推导的整文件 diff,而编辑使用 applied hunk。失败的变更不携带 diff 元数据,正常渲染其错误信息。 -### 3. 桥接层渲染 `diff` 结果卡片 +### 3. Bridge 渲染 `diff` 结果卡片 -`ToolResultView` 新增 `DiffResultView { card:'diff'; title?; diffs: FileDiff[] }`;桥接层结果侧的 `switch (view.card)` 增加 `diff` 分支,发出 `{type:'diff'}` 的 `ToolCallContent` 块(与调用侧分支对称)。ACP 的 `tool_call_update.content` 在编辑器中**替换**调用时的内容,因此结果 diff **取代**调用时片段(并防止面向模型的结果文本覆盖它)——两次更新的序列(先调用片段,后结果 diff)与 `claude-agent-acp` 完全一致。 +`ToolResultView` 新增 `DiffResultView { card:'diff'; title?; diffs: FileDiff[] }`;bridge 结果侧的 `switch (view.card)` 增加 `diff` 分支,发出 `{type:'diff'}` 的 `ToolCallContent` 块(与调用侧分支对称)。ACP 的 `tool_call_update.content` 在编辑器中**替换**调用时的内容,因此结果 diff **取代**调用时刻的片段(并防止面向模型的结果文本覆盖它)——两次更新序列(先调用片段,再结果 diff)与 `claude-agent-acp` 完全一致。 ## 曾考虑的替代方案 -**手写或 vendor diff 算法。** 带上下文的 hunk 有已知的边界情况,因此 `dsh-tool-fs` 使用带类型的 [`diff`](https://www.npmjs.com/package/diff) 包,并在一个模块中规范化 `structuredPatch` 输出。本仓库的 vendor 策略适用于其框架源码,而非每个叶子工具。 +**手写或 vendor diff 算法。** 上下文 hunk 有已知的边界情况,因此 `dsh-tool-fs` 使用带类型的 [`diff`](https://www.npmjs.com/package/diff) 包,并在一个模块中规范化 `structuredPatch` 输出。仓库的 vendor 策略适用于框架源码,而非每个叶子工具库。 ## 后果 -`tool/result` 事件现在可以携带工具私有的 `meta` 载荷——属于磁盘词汇的一部分,由 `Session.append` 在运行时限制为 JSON——任何工具都可以附加持久化的结果展示而无需再改 core。diff 卡片在会话重载和快照回放时免费复现:从日志读回,从不重新计算。代价:覆写操作在内存中同时持有变更前和新文本以计算仅用于 UI 的 hunk(`TODO(overwrite-diff-bound)`),且 `dsh-tool-fs` 引入了一个小型、知名的运行时依赖。 +`tool/result` 事件现在可以携带工具私有的 `meta` 载荷——属于磁盘格式词汇的一部分,由 `Session.append` 在运行时限制为 JSON——任何工具都可以附加持久化的结果展示而无需再改 core。diff 卡片在会话重载和快照回放时免费复现:它从日志中读回,从不重新计算。代价:覆写操作在内存中同时持有旧文本和新文本以计算仅用于 UI 的 hunk(`TODO(overwrite-diff-bound)`),且 `dsh-tool-fs` 引入了一个小型、知名的运行时依赖。 ## 非目标 -- **实时增量 diff 流式输出。** hunk 在变更完成后一次性计算;没有逐按键 diff。 -- **对二进制/非 UTF-8 覆写做 diff。** 此类文件的 `before` 为 `null`(没有文本 diff 基础);写入仍然成功,结果渲染全文件 diff(`oldText: null`)而非带上下文的 hunk。 -- **重命名/移动 diff。** 仅对单个已解析路径做内容 diff。 -- **限制覆写 diff 基础的大小。** 覆写操作将整个旧文件读入内存以计算带上下文的 hunk(在已持有的新内容之上),因此非常大的文本覆写会为仅 UI 用途的 diff 分配两份文本。后续优化可以设定预读上限,超过阈值时回退到全文件/无上下文 diff;以 `TODO(overwrite-diff-bound)` 标记在读取位置。 +- **实时增量 diff 流式输出。** hunk 在变更完成后一次性计算;没有逐键 diff。 +- **对二进制/非 UTF-8 覆写做 diff。** 此类文件的 `before` 为 `null`(没有文本 diff 基础);写入仍然成功,结果渲染整文件 diff(`oldText: null`)而非上下文 hunk。 +- **重命名/移动 diff。** 仅限单个已解析路径的内容 diff。 +- **限制覆写 diff 基础的大小。** 覆写操作将整个旧文件读入内存以计算上下文 hunk(加上已持有的新内容),因此非常大的文本覆写会为仅 UI 用途的 diff 分配两份文本。未来的改进可以设定预读上限,超过阈值时回退到整文件/无上下文 diff;在读取位置以 `TODO(overwrite-diff-bound)` 跟踪。 ## 相关 -- 补齐了[带标签的渲染意图联合类型](2026-07-02-tool-render-intent-union.md)中作为非目标列出的最后一项表示差异——该 RFC 的「非目标」一节已更新,记录 applied-hunk diff 在此处交付。 -- 建立在[文件系统能力 seam](2026-06-17-filesystem-capability-seam.md)(变更前/后文本是后端返回的存储事实)和[事件溯源会话](2026-06-11-event-sourced-sessions.md)(`meta` 载荷持久化在 `tool/result` 事件上,因此回放可复现卡片)之上。 -- `meta` 通道有意设计为通用的:未来的工具(结构化搜索、数据表结果等)可以附加自己的持久化结果展示而无需再改 core。 +- 补全了 [Tagged render-intent union](2026-07-02-tool-render-intent-union.md) 中作为非目标列出的最后一项表示差异——该 RFC 的「非目标」一节已更新,记录 applied-hunk diff 在此处交付。 +- 基于[文件系统 capability seam](2026-06-17-filesystem-capability-seam.md)(before/after 是后端返回的存储事实)和[事件溯源会话](2026-06-11-event-sourced-sessions.md)(`meta` 载荷持久化在 `tool/result` 事件上,因此回放可复现卡片)。 +- `meta` 通道有意设计为通用的:未来的工具(结构化搜索、数据表结果)可以附加自己的持久化结果展示而无需再改 core。 diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml index 4c8a1f1b63..8c2f7faf6d 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-02-tool-render-intent-union.md: 8256f09f9c297658627d0c3d9e99ee1c5424b254 -2026-07-02-tool-render-intent-union.zh.md: ed46bf0a8bea1cbfbce4287e5dc48be21c8d8fb9 +2026-07-02-tool-render-intent-union.zh.md: 35bd775545c9131a20da9e7f7424506e4554eb4b diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md index ed46bf0a8b..35bd775545 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md @@ -1,4 +1,4 @@ -# RFC:用于工具调用展示的标签化 render-intent 联合类型 +# RFC:用于工具调用展示的带标签 render-intent 联合类型 Status: implemented @@ -6,17 +6,17 @@ Status: implemented ## 问题 -工具通过 `ToolDefinition` 上的两个回调 `presentCall`/`presentResult` 声明其调用在 UI(编辑器的工具调用卡片)中的渲染方式,返回 `ToolCallPresentation` / `ToolResultPresentation`,并带有可选的 `ToolTerminal` 子结构。这些类型在增量演进中变成了一个**可选字段的大杂烩**:调用侧有 `title`、`kind`、`rawInput`、`content`、`locations`、`terminal`;结果侧有 `title`、`content`、`terminal`;`ToolTerminal` 上有 `cwd`/`output`/`exitCode`/`signal`。职责划分含混不清: +工具通过 `ToolDefinition` 上的两个回调 `presentCall`/`presentResult` 声明其调用在 UI(编辑器的工具调用卡片)中如何渲染,返回 `ToolCallPresentation` / `ToolResultPresentation`,并带有一个可选的 `ToolTerminal` 子结构。这些类型在增量演进中变成了一个**可选字段的集合**:调用侧有 `title`、`kind`、`rawInput`、`content`、`locations`、`terminal`;结果侧有 `title`、`content`、`terminal`;`ToolTerminal` 上有 `cwd`/`output`/`exitCode`/`signal`。职责划分模糊不清: -- 调用侧和结果侧的 `terminal` 字段重叠,bridge 需要将一个 `content` 块、一个 `terminal` 块和 `rawInput` 按调用拼接在一起,靠临时条件逻辑缝合。 -- 哪些组合是*合法的*没有文档:一个设置了 `terminal` 的调用如果同时设置了 `content`,含义是「卡片上方的描述」;一个 generic 调用如果设置了 `terminal`,毫无意义但类型允许。类型允许无意义的状态。 -- 无法表达编辑器最需要的文件工具能力:**diff 卡片**(`{path, oldText, newText}`,Zed 将其渲染为内联 diff / 新文件预览)。`ToolCallPresentation.content` 是 *LLM* 的 `ContentBlock[]` 词汇(text/image),工具字面上无法请求一个 diff。 +- 调用侧和结果侧的 `terminal` 字段重叠,bridge 需要将每次调用的 `content` 块、`terminal` 块和 `rawInput` 用临时条件逻辑拼接在一起。 +- 哪些组合是*合法的*没有文档说明:一个设置了 `content` 的 `terminal` 调用意味着「卡片上方的描述」;一个设置了 `terminal` 的 generic 调用毫无意义但类型上可表达。类型允许无意义的状态存在。 +- 无法表达编辑器最需要的文件工具能力:**diff 卡片**(`{path, oldText, newText}`,Zed 将其渲染为内联 diff / 新文件预览)。`ToolCallPresentation.content` 使用的是 *LLM(大语言模型)* 的 `ContentBlock[]` 词汇(text/image),工具根本无法请求 diff 展示。 -`packages/core/tools/src/index.ts` 中现有的 `FIXME(tool-presentation)` 指明了修复方向:「重新设计类型,让工具一次性声明其渲染意图(例如按卡片种类的标签联合类型),而不是一堆可选字段由 bridge 拼接。」被否决的 RFC [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) 明确推迟了此事:富渲染「应当在至少有两个真实工具和两个真实消费方来验证词汇之后,以标签化 render-intent 联合类型的形式回归」。这个门槛现已达到:两个生产方族(`dsh-tool-bash`、`dsh-tool-fs`)和两个消费方(ACP bridge 实时路径 + snapshot-golden 回放路径)。 +`packages/core/tools/src/index.ts` 中已有的 `FIXME(tool-presentation)` 指出了修复方向:「重新设计类型,让工具一次性声明其渲染意图(例如按卡片种类的带标签联合类型),而非一堆由 bridge 拼接的可选字段。」被否决的 RFC [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) 明确推迟了此事:富渲染「应当在至少有两个真实工具和两个真实消费方验证词汇之后,以带标签 render-intent 联合类型的形式回归。」该条件现已满足:两个生产者族(`dsh-tool-bash`、`dsh-tool-fs`)和两个消费方(ACP bridge 实时路径 + snapshot-golden 回放路径)。 ## 决策 -用一个**以 `card` 为标签的可辨识联合类型**替代可选字段大杂烩。工具为每次调用/结果声明一个渲染意图;bridge 按标签分发。 +用一个**以 `card` 为标签的可辨识联合类型**替代可选字段集合。工具为每次调用/结果声明一个渲染意图;bridge 根据标签分发。 ```ts ignore-check type FileLocation = { path: string; line?: number } @@ -34,41 +34,41 @@ interface GenericResultView { card: 'generic'; title?: string; content?: Content interface TerminalResultView { card: 'terminal'; title?: string; output?: string; exitCode?: number; signal?: string } ``` -`card` 在每个变体上都是**必填**的:一个真正的判别字段,而非可选默认值。bridge 执行 `switch (view.card) { case 'generic': … case 'terminal': … case 'diff': … default: assertNever(view) }`。该联合类型是**封闭的**(遵循 [switch 穷举约定](../../../../AGENTS.md)):第四种渲染意图(表格、图表)无论如何都需要新的 bridge 代码来渲染,因此一个插件添加的变体如果被 bridge 静默丢弃,比编译错误更糟。添加变体会在 bridge 的 switch 处中断编译——这正是我们想要的信号。 +`card` 在每个变体上都是**必填**的——真正的判别式,而非可选默认值。bridge 执行 `switch (view.card) { case 'generic': … case 'terminal': … case 'diff': … default: assertNever(view) }`。该联合类型是**封闭的**(遵循 [switch 穷举约定](../../../../AGENTS.md)):第四种渲染意图(表格、图表)无论如何需要新的 bridge 代码来渲染,因此一个由插件添加但被 bridge 静默丢弃的变体,比编译错误更糟糕。新增变体会在 bridge 的 switch 处中断编译——这正是我们想要的信号。 -### 为什么标签联合类型优于字段大杂烩 +### 为什么带标签联合类型优于字段集合 -- **无效状态变得不可表示。** generic 卡片不能携带终端输出;terminal 卡片不能携带 diff。旧的大杂烩允许所有这些组合。 -- **bridge 按分支分发,而非拼接。** 每种卡片一个分支,各自精确产出该卡片所需的协议格式(wire format),而非协调五个交互关系未文档化的可选字段。 -- **`diff` 成为一等意图。** `dsh-tool-fs` 的 write/edit 声明 `card:'diff'`;bridge 发出 ACP `{type:'diff', path, oldText, newText}` `ToolCallContent`(已存在于 SDK 的 `ToolCallContent` 联合类型中,此前 bridge 未使用)。这是本次重设计解锁的能力。 +- **无效状态变得不可表达。** generic 卡片不能携带终端输出;terminal 卡片不能携带 diff。旧的字段集合允许所有这些组合。 +- **bridge 分发而非拼接。** 每种卡片一个分支,各自精确产出该卡片所需的协议格式(wire format),而非调和五个交互关系未文档化的可选字段。 +- **`diff` 成为一等意图。** `dsh-tool-fs` 的 write/edit 声明 `card:'diff'`;bridge 输出 ACP `{type:'diff', path, oldText, newText}` 的 `ToolCallContent`(已存在于 SDK 的 `ToolCallContent` 联合类型中,此前 bridge 未使用)。这正是本次重设计解锁的能力。 -### 生产方映射 +### 生产者映射 -- `dsh-tool-fs` read → `generic`(`kind:'read'`,附带一个 follow-along `location`);write → `diff`(`oldText:null`);edit → `diff`(`oldText:old_string || null`,`newText:new_string ?? ''`)。这与 `claude-agent-acp` 的 `toolInfoFromToolUse` Read/Write/Edit 分支逐字段对应。 +- `dsh-tool-fs` read → `generic`(`kind:'read'`,附带一个 follow-along `location`);write → `diff`(`oldText:null`);edit → `diff`(`oldText:old_string || null`,`newText:new_string ?? ''`)。这与 `claude-agent-acp` 的 `toolInfoFromToolUse` 中 Read/Write/Edit 各分支逐字段对应。 - `dsh-tool-bash` foreground → `terminal` 调用 + `terminal` 结果;`run_in_background` 和 `bash_output`/`bash_kill` → `generic`。 - `dsh-tool-todo` → `generic`。 ### 终端回退的归属 -`TerminalResultView` 只携带 `output`/`exitCode`/`signal`。不具备终端能力的 UI 需要一个围栏 ` ```console ` 文本回退;该推导移至 **bridge**(bridge 在无能力路径上将 `output` 包裹为围栏代码块),而非由工具双重编码。这使 bash 工具的结果保持单一结构化形状,并逐字节保留既有的 capability 门控行为。 +`TerminalResultView` 只携带 `output`/`exitCode`/`signal`。不具备终端能力的 UI 需要一个围栏 ` ```console ` 文本回退;该推导移至 **bridge**(在无能力路径上将 `output` 包裹在围栏代码块中),而非由工具双重编码。这使 bash 工具的结果保持单一结构化形状,并逐字节保留既有的能力门控行为。 ### 纯函数性保持不变 -`presentCall`/`presentResult` 仍然是 `args`(以及 `presentResult` 的 result)的纯函数——它们在实时流式输出和会话日志回放中都会运行,因此必须具备回放确定性。每个 view 仅从 args 推导:write 的 diff 是新文件样式(`oldText:null`),因为工具在调用时没有旧内容;edit 的 diff 是 `old_string`→`new_string`。 +`presentCall`/`presentResult` 仍然是 `args`(`presentResult` 还有 result)的纯函数——它们在实时流式输出和会话日志回放中都会运行,因此必须具备回放确定性。每个 view 仅从 args 推导:write 的 diff 是新文件风格(`oldText:null`),因为工具在调用时没有旧内容;edit 的 diff 是 `old_string`→`new_string`。 ## 相对路径显示标题 -`claude-agent-acp` 将文件卡片的标题路径相对于会话 cwd 做相对化处理(`toDisplayPath`):显示 `Read src/foo.ts` 而非 `/abs/proj/src/foo.ts`,同时保持 `locations[]`/`diff.path` **原始**(编辑器打开真实路径)。我们的 `presentCall` 是纯函数/仅依赖 args,无法看到会话 cwd,因此相对化发生在 **bridge**——bridge 已经将会话 cwd 传入工具调用渲染(与它用于解析 terminal 卡片标题的 cwd 相同)。bridge 仅对标题做相对化,通过对已知 `locations[0].path`/`diffs[0].path` 子串的精确结构化替换实现——对文件卡片类型通用,从不特判工具名。 +`claude-agent-acp` 将文件卡片标题中的路径相对于会话 cwd 做缩短处理(`toDisplayPath`)——显示 `Read src/foo.ts` 而非 `/abs/proj/src/foo.ts`——同时保持 `locations[]`/`diff.path` 为**原始路径**(编辑器打开真实路径)。我们的 `presentCall` 是纯函数/仅依赖 args,无法访问会话 cwd,因此这一相对化处理发生在 **bridge**,bridge 已经将会话 cwd 传入工具调用渲染逻辑(与它用于解析 terminal 卡片标题的 cwd 相同)。bridge 仅对标题做相对化,方式是对已知的 `locations[0].path`/`diffs[0].path` 子串做精确的结构化替换——对所有文件卡片类型通用,从不针对工具名做特殊处理。 ## 曾考虑的替代方案 -- **完全删除工具自有的展示**:即[被否决的 collapse 提案](../../rejected/simplification/2026-06-20-generic-tool-rendering.md);其结论明确推迟到两个真实工具和两个真实消费方存在后再做这个联合类型,而该门槛现已达到。 -- **可合并扩展的联合类型**(`ContentBlockMap` 模式):否决。新的渲染意图无论如何都需要新的 bridge 代码来渲染,因此一个插件添加的变体如果被 bridge 静默丢弃,比封闭联合类型在 bridge 的 `assertNever` switch 处引发的编译错误更糟。 -- **保留可选字段大杂烩**:即「问题」一节所剖析的现状:无效状态可表示、字段交互未文档化、且完全无法请求 diff 卡片。 +- **完全删除工具自有的展示**:即[被否决的 collapse 提案](../../rejected/simplification/2026-06-20-generic-tool-rendering.md);其自身的结论正是推迟到两个真实工具和两个真实消费方存在后再做此联合类型,该条件现已满足。 +- **可合并扩展的联合类型**(`ContentBlockMap` 模式):否决。新的渲染意图无论如何需要新的 bridge 代码来渲染,因此一个被 bridge 静默丢弃的插件添加变体,比封闭联合类型在 bridge 的 `assertNever` switch 处引发的编译错误更糟糕。 +- **保留可选字段集合**:即「问题」一节所剖析的现状:无效状态可表达、字段交互无文档、且完全无法请求 diff 卡片。 ## 后果 -新的渲染意图是 bridge switch 处的编译中断变更——这是有意为之:渲染代码必须在卡片种类存在之前就位。无效的卡片/字段组合现已不可表示,bash 回退推导归 bridge 所有,工具只返回一个结构化形状。第四种卡片(表格、图表)的门槛是在同一个变更中编写其 bridge 分支。 +新的渲染意图会在 bridge 的 switch 处引发编译中断——这是有意为之:渲染代码必须先于卡片种类存在。无效的卡片/字段组合现已不可表达,bash 回退推导归 bridge 所有,工具只返回一个结构化形状。第四种卡片(表格、图表)的门槛是在同一个变更中编写其 bridge 分支。 ## 非目标 @@ -76,7 +76,7 @@ interface TerminalResultView { card: 'terminal'; title?: string; output?: string ## 相关 -- 取代 [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md)(已否决——「等两个真实工具和两个真实消费方,然后做标签化 render-intent 联合类型」)中的推迟决定。该门槛现已达到;本 RFC 即是那个联合类型。 -- 由 [Result-time applied-hunk diffs](2026-07-02-result-time-applied-hunk-diffs.md) 扩展:该 RFC 增加了一个持久化的 `meta` 通道,使 write/edit 在结果时发出 `DiffResultView`(应用后的变更:带上下文行的 contextual hunk / 每个 `replace_all` 站点一个,或新建文件的整文件 diff),叠加在本联合类型的调用时 diff 卡片之上。 -- 将 `ToolTerminal` 折入 [ACP terminal and tool-call rendering](../feature/2026-06-18-acp-terminal-and-tool-rendering.md) 所描述的 `terminal` view(`_meta` terminal 卡片约定和 capability 门控不变;仅 harness 侧的展示类型改变)。 +- 取代 [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md)(已否决——「等两个真实工具和两个真实消费方,然后做带标签 render-intent 联合类型」)中的推迟决定。该条件现已满足;本 RFC 即为那个联合类型。 +- 被 [Result-time applied-hunk diffs](2026-07-02-result-time-applied-hunk-diffs.md) 扩展:后者添加了一个持久化的 `meta` 通道,使 write/edit 在结果时输出 `DiffResultView`(应用后的变更:带上下文行的 contextual hunk / 每个 `replace_all` 位点一个,或创建时的整文件 diff),叠加在本联合类型的调用时 diff 卡片之上。 +- 将 `ToolTerminal` 折入 [ACP terminal and tool-call rendering](../feature/2026-06-18-acp-terminal-and-tool-rendering.md) 所描述的 `terminal` view(`_meta` terminal 卡片约定和能力门控不变;仅 harness 侧的展示类型改变)。 - ACP SDK 的 `Diff` / `ToolCallContent` 类型支撑新的 `diff` 卡片。 diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml index 25679116f6..f589fd9ddf 100644 --- a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-03-filesystem-directory-listing-seam.md: bb8d9c4deda18b320b85d548bbd5bcb32f1c1d72 -2026-07-03-filesystem-directory-listing-seam.zh.md: a0332fe6cec576ad1c5b4722e2decb87344aeee1 +2026-07-03-filesystem-directory-listing-seam.zh.md: ccc5ca67f58537134da5c5484b3d527ba84fe8d3 diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md index a0332fe6ce..ccc5ca67f5 100644 --- a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md @@ -1,53 +1,53 @@ # RFC:为文件系统 seam 添加直接目录列举能力 -Status: implemented - [English](2026-07-03-filesystem-directory-listing-seam.md) | 中文 +Status: implemented + ## 问题 -`@deepseek-ai/dsh-fs` 是文件系统访问的提供方 seam,本地后端与未来的非本地后端共享同一个 `ctx.fs` 契约。在本次变更之前,它能解析路径、stat 目标、读取文本、流式读取文本、写入文本和编辑文本。这对面向模型的文件工具已经够用,但对于需要枚举目录而又不想直接导入 `node:fs` 的非模型侧消费方来说还不够。 +`@deepseek-ai/dsh-fs` 是文件系统访问的提供方 seam,本地后端与未来的非本地后端共享同一个 `ctx.fs` 契约。在本次变更之前,它能解析路径、stat 目标、读取文本、流式读取文本、写入文本和编辑文本。这对面向模型的文件工具已经足够,但对于需要枚举目录而又不想直接导入 `node:fs` 的非模型侧消费方来说还不够。 -直接的压力来自 skill 加载:读取单个 `SKILL.md` 已经可以走 `ctx.get('fs')`,但发现哪些 skill 根目录下包含 `<name>/SKILL.md` 或 `<name>.md` 仍需要目录枚举。如果只在 `dsh-skill` 中添加目录列举,要么保留一个直接的 Node 依赖,要么在文件系统提供方栈之外发明一个一次性的本地辅助函数。 +直接的压力来自 skill(技能)加载:读取单个 `SKILL.md` 已经可以走 `ctx.get('fs')`,但发现哪些 skill 根目录包含 `<name>/SKILL.md` 或 `<name>.md` 仍需要目录枚举。如果仅在 `dsh-skill` 中添加目录列举,要么保留对 Node 的直接依赖,要么在文件系统提供方栈之外发明一个一次性的本地辅助函数。 -本决策只添加提供方能力,不引入面向模型的 `ls`/`list` 工具,也不改变 skill 发现逻辑。那些消费方需要独立的 UX、提示词和策略决策。 +本决策只添加提供方能力,不涉及面向模型的 `ls`/`list` 工具或 skill 发现机制的变更。那些消费方需要独立的 UX、prompt 与策略决策。 ## 决策 在 `@deepseek-ai/dsh-fs` 中添加 `FileSystem.listDir(target, signal?)`。 -`listDir` 仅列举一级目录。它以稳定的名称顺序返回直接子项,包含: +`listDir` 仅列举一层目录。它以稳定的名称顺序返回直接子项,包含以下字段: -- `name`:子项的 basename。 -- `type`:`file`、`directory` 或 `other`。 -- `target`:已解析的子项 `FsTarget`。 -- `version`:可用时提供的轻量元数据。 -- `size`:可用时提供的常规文件大小。 +- `name`:子项的 basename; +- `type`:`file`、`directory` 或 `other`; +- `target`:已解析的子项 `FsTarget`; +- `version`:可用时返回的轻量元数据; +- `size`:可用时返回的常规文件大小。 它从不读取文件内容。递归遍历、glob 匹配、分页、搜索、文件监听和面向模型的渲染均有意不在范围内。 -本地后端通过 `readdir({ withFileTypes: true })`、`resolveLocalTarget` 以及元数据 `stat`/`realpath` 探测来实现。结果顺序是确定性的(`name.localeCompare`),以保持未来消费方的提示词/列表输出稳定,并提升前缀缓存复用率。 +本地后端通过 `readdir({ withFileTypes: true })`、`resolveLocalTarget` 以及元数据 `stat`/`realpath` 探测来实现。结果顺序是确定性的(`name.localeCompare`),以保持未来消费方的 prompt/列表输出稳定,并提高前缀缓存复用率。 -损坏或已消失的子项可以表示为 `type: 'other'`(不带 `version`/`size`);它们不会中止整个列举。列举目录或解析/探测子项元数据时遇到的权限或后端 I/O 故障会以结构化的 `FsError` 代码使整个列举失败: +损坏或已消失的子项可以表示为 `type: 'other'`(不带 `version`/`size`);它们不会中止整个列举。在列举目录或解析/探测子项元数据时遇到权限或后端 I/O 故障,则以结构化的 `FsError` 错误码使整个列举失败: -- `FS_NOT_FOUND`:目标不存在。 -- `FS_NOT_DIRECTORY`:目标存在但不是目录。 -- `FS_PERMISSION_DENIED`:权限不足。 -- `FS_IO_ERROR`:其他后端 I/O 故障。 +- `FS_NOT_FOUND`:目标不存在; +- `FS_NOT_DIRECTORY`:目标存在但不是目录; +- `FS_PERMISSION_DENIED`:权限不足; +- `FS_IO_ERROR`:其他后端 I/O 故障; - `FS_ABORTED`:调用被中止。 ## 曾考虑的替代方案 -**在添加 seam 的同时添加面向模型的 list 工具。** 否决。其提示词、schema 和渲染契约与提供方原语无关。 +**在添加 seam 的同时添加面向模型的 list 工具。** 否决。其 prompt、schema 和渲染契约与提供方原语相互独立。 -**让每个消费方自行枚举目录。** 否决。这会把 `dsh-skill` 等产品包绑定到 Node/本地文件系统行为上,绕过策略/远程/沙箱后端。 +**让每个消费方自行枚举目录。** 否决。这会将 `dsh-skill` 等产品包绑定到 Node/本地文件系统行为上,绕过策略/远程/沙箱后端。 -**让 `listDir` 支持递归或 glob 形式。** 暂时否决。skill 根目录发现只需要直接子项,简单的单级列举是未来消费方可以安全组合的最小后端契约。 +**让 `listDir` 支持递归或 glob 形式。** 暂时否决。skill 根发现只需要直接子项,而简单的单层列举是未来消费方可以安全组合的最小后端契约。 -**跳过元数据解析失败的子项。** 否决。API 承诺返回已解析的子项 target,因此解析子项时遇到的权限/IO 故障属于契约失败。损坏或已消失的子项是例外,因为它们仍可在不声称拥有一个活跃已解析文件的前提下被表示。 +**跳过元数据解析失败的子项。** 否决。API 承诺返回已解析的子项 target,因此解析子项时的权限/IO 故障属于契约失败。损坏或已消失的子项是例外,因为它们仍可在不声称拥有一个活跃已解析文件的前提下被表示。 ## 后果 每个文件系统后端现在必须多实现一个提供方原语。这是 harness 尚未发布时有意为之的基础工作,但也意味着未来的沙箱/远程后端需要定义等价的直接子项列举行为。 -该能力仍然面向提供方。在消费方落地之前,ACP/模型会话仍需使用 `bash` 等既有工具来列举目录。没有面向模型的 `listdir` 工具是预期行为,而非接线遗漏。 +该能力仍停留在提供方层面。在消费方落地之前,ACP(Agent Client Protocol)/模型会话仍需使用 `bash` 等既有工具来列举目录。缺少面向模型的 `listdir` 工具是预期行为,而非接线错误。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml index 8ae2221209..5c821e12fa 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-05-prompt-variables-and-tool-guidance-ownership.md: fce9d555c8843b99fdbfa7b652b46d0b88053935 -2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 5af4fca19649d4ee458eaa6a23ae7374abdd89e4 +2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 93a639a2ddac33cb1ceac57101cb6185fe6034ad diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md index 5af4fca196..93a639a2dd 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md @@ -1,72 +1,72 @@ -# RFC:提示词变量与工具指导归属 - -Status: implemented +# RFC:Prompt 变量与工具指导归属 [English](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) | 中文 +Status: implemented + ## 问题 -组装后的系统提示词有四个缺陷,同属一类:harness 已经掌握的事实在别处被手工重述,然后漂移。 +组装后的系统提示词存在四个缺陷,同属一类:harness 已知的事实在别处被手工重述,然后漂移。 -**模型无法知道自己的名字。** `AgentOptions.model` 驱动每次请求,但没有任何提示词文本携带它——也不可能携带:`dsh-system-prompt` 中的 section 是上下文全局的,而模型名称是 per-agent 的,且 `assemble()` 根本不接受任何 per-agent 输入。 +**模型无法知道自己的名字。** `AgentOptions.model` 驱动每个请求,但没有任何 prompt 文本携带它——也不可能携带:`dsh-system-prompt` 中的 section 是上下文全局的,而模型名称是 per-agent 的,`assemble()` 根本不接受任何 per-agent 输入。 -**工具指导是叶子 YAML 中的手写行文。** bash/subagent/todo_write 的使用指导存放在 `examples/coding-agent/cordis.yml` 和 `examples/acp-agent/cordis.yml` 的 `systemPrompt` 字符串中——两份漂移的副本(ACP 那份已经被删减)——而 `dsh-tool-fs` 和 `dsh-tool-web` 则以 `ctx.systemPrompt.section()` 贡献的方式持有各自的指导。加载或卸载一个工具插件意味着手动编辑每个部署的 persona;两份 YAML 都带着一条 `FIXME(config-comments)` 为这种割裂的症状道歉,stdio 的欢迎横幅也手动枚举了工具集。 +**工具指导是 leaf YAML 中的手写行文。** bash/subagent/todo_write 的使用指导存放在 `examples/coding-agent/cordis.yml` 和 `examples/acp-agent/cordis.yml` 的 `systemPrompt` 字符串里——两份漂移的副本(ACP 那份已经被删减)——而 `dsh-tool-fs` 和 `dsh-tool-web` 则通过 `ctx.systemPrompt.section()` 贡献各自的指导。加载或卸载一个工具插件意味着手动编辑每个部署的 persona;两份 YAML 都带着一条 `FIXME(config-comments)` 为这种分裂的症状道歉,stdio 的欢迎横幅也手动枚举了工具集。 -**Persona 渲染在工具指导之后。** agent loop(智能体循环)将 `agent.options.systemPrompt` 字符串拼接在已组装的 section 之后,于是模型先读到「使用 read 工具……」再读到「你是 coding-agent」——与身份优先的惯例(Claude Code、Codex)相反,且在 section 流水线之外形成了第二条组合路径。 +**Persona 渲染在工具指导之后。** agent loop(智能体循环)将 `agent.options.systemPrompt` 字符串拼接在已组装的 section 之后,于是模型先读到「Use the read tool…」再读到「You are coding-agent」——与 identity-first 约定(Claude Code、Codex)相反,且是 section 流水线之外的第二条组合路径。 -**Fork 工具的描述是假的。** `dsh-tool-subagent` 硬编码了一段为 spawn 语义撰写的描述——"a separate agent that works in its own context … it does not see this conversation"——而 `subagent_fork` 实例(其子 agent 继承父级已完成的轮次)拿到了同样的措辞;YAML 行文在带外纠正了这个谎言。小问题同族:`PromptSection.name` 文档写着"(diagnostics / dedup)",但重复项被静默接受。 +**Fork 工具的描述是假的。** `dsh-tool-subagent` 硬编码了一段为 spawn 语义编写的描述——"a separate agent that works in its own context … it does not see this conversation"——而 `subagent_fork` 实例(其子 agent 继承父级已完成的轮次)拿到了同样的措辞;YAML 行文在带外纠正了这个谎言。小问题:`PromptSection.name` 文档标注为 "(diagnostics / dedup)",但重复项被静默接受。 ## 决策 -**一条原则:提示词中的每个事实恰好有一个归属方。** 模型名称和工作区是配置/会话事实 → harness 将它们暴露为变量,persona 引用它们。每个工具的语义和何时使用 → 工具的 `description`。description 无法承载的跨调用习惯 → 工具包的 prompt section。harness 出处 → 静态的 `harness:identity` section。部署角色和行为 → 部署的 persona。 +**一条原则:prompt 中的每个事实恰好有一个归属方。** 模型名称和工作区是配置/会话事实 → harness 将它们暴露为变量,persona 引用它们。每个工具的语义和何时使用 → 工具的 `description`。description 无法承载的跨调用习惯 → 工具包(package)的 prompt section。harness 来源标识 → 静态的 `harness:identity` section。部署角色与行为 → 部署的 persona。 ### 组装上下文 -`SystemPrompt.assemble(context)` 接受一个可 merge 扩展的 `AssembleContext`。`dsh-system-prompt` 声明用于 scoped routing 的可选 `scope` 选择器,而 `dsh-agent` 通过 declaration-merge 将可选的类型化 `agent` 字段附加到其上(类型层面的 `agent → system-prompt` 边,无运行时依赖环)。循环在每一步调用 `assembleContextFor(agent)`,使两个字段标识同一个 agent;section 文本提供方可以读取该上下文,`system-prompt/assemble` waterfall(瀑布式事件)也会收到它,监听方可据此按 agent 过滤或扩展。 +`SystemPrompt.assemble(context)` 接受一个可合并扩展的 `AssembleContext`。`dsh-system-prompt` 声明可选的 `scope` 选择器用于 scoped 路由,而 `dsh-agent` 通过声明合并将可选的类型化 `agent` 字段附加到其上(类型层面的 `agent → system-prompt` 边,无运行时依赖循环)。循环在每个步骤调用 `assembleContextFor(agent)`,使两个字段标识同一个 agent;section 文本提供方可以读取该上下文,`system-prompt/assemble` waterfall(瀑布式事件)也接收它,监听器可据此按 agent 过滤或扩展。 -### 提示词变量 +### Prompt 变量 -插件通过 `ctx.systemPrompt.variable(name, provider)` 注册 `{{name}}` 值。组装时将它们解析到 waterfall 可见的变量映射中。渲染阶段拒绝:未知的 own-property 引用、注册的 provider 返回 `undefined`、格式错误的完整引用、以及仍包含闭合 `}}` 的不平衡引用;孤立的未匹配 `{{` 保留为行文,替换后的值不会被再次扫描。注册阶段拒绝无效或重复的变量名,section 名称也必须唯一。 +插件通过 `ctx.systemPrompt.variable(name, provider)` 注册 `{{name}}` 值。组装过程将它们解析到 waterfall 可见的变量映射中。渲染阶段拒绝以下情况:引用了未知的 own-property、已注册的 provider 返回 `undefined`、格式错误的完整引用、以及仍包含闭合 `}}` 的不平衡引用;孤立的未匹配 `{{` 保留为行文,替换后的值不会被重新扫描。注册阶段拒绝无效或重复的变量名,section 名称也必须唯一。 -`dsh-agent-loop` 注册两个内置变量,均为上下文 agent 的纯投影:`model`(= `options.model`)和 `cwd`(= `session.header.cwd`)。示例 persona 写 `powered by the {{model}} model`——模型名称只在 `model:` 配置键中声明一次。`{{cwd}}` 仅在 ACP 示例中演示:每个 ACP 会话携带客户端的 cwd,而配置预创建的 stdio agent 没有 cwd(在那里声称 `{{cwd}}` 的 persona 会导致该轮次失败——这是有意为之)。变量留在 loop 插件上(不同于下文的 section):它们是本循环所驱动的 agent 的运行时事实,替换循环自行提供自己的变量。 +`dsh-agent-loop` 注册两个内置变量,均为上下文 agent 的纯投影:`model`(= `options.model`)和 `cwd`(= `session.header.cwd`)。示例 persona 写 `powered by the {{model}} model`——模型名称只在 `model:` 配置键中声明一次。`{{cwd}}` 仅在 ACP 示例中演示:每个 ACP 会话携带客户端的 cwd,而配置预创建的 stdio agent 没有 cwd(在那里声称 `{{cwd}}` 的 persona 会导致该轮次失败——这是有意为之)。变量留在 loop 插件上(不同于下面的 section):它们是本循环驱动的 agent 的运行时事实,替换循环自行提供自己的变量。 ### Persona 作为 order-0 section -`dsh-system-prompt` 持有 order 为 `-100` 的 `harness:identity` 和 order 为 `0` 的已配置 `deployment:persona`,因此两者在替换循环时仍然存活。提示词渲染只有一条路径 `renderPrompt(assembly)`,`agent/pre-step` 因此能测量用于压缩(compaction)的确切提示词。agent 作用域的 `deployment:persona` 遮蔽全局默认值,允许 subagent 提供方在发布前安装 persona。约定的 order 分段为:identity `-100`、persona `0`、工具指导 `100–199`。 +`dsh-system-prompt` 拥有 order 为 `-100` 的 `harness:identity` 和 order 为 `0` 的配置 `deployment:persona`,因此两者在循环被替换时仍然存活。prompt 渲染只有一条路径 `renderPrompt(assembly)`,`agent/pre-step` 因此测量的正是用于压缩(compaction)的确切 prompt。agent 作用域的 `deployment:persona` 遮蔽全局默认值,允许 subagent provider 在发布前安装 persona。约定的 order 区间为:identity `-100`、persona `0`、工具指导 `100–199`。 ### 工具指导归属 -每个工具的语义和选择指导存放在工具描述中。Prompt section 仅承载跨调用习惯,例如检查 bash 退出标记或优先使用文件系统工具而非 shell 命令。`todo_write` 和 subagent 工具不需要 section,因为它们的描述已包含完整契约。部署 persona 只包含角色和行为。 +每个工具的语义和选择指导放在工具 description 中。prompt section 只承载跨调用习惯,例如检查 bash 退出标记或优先使用文件系统工具而非 shell 命令。`todo_write` 和 subagent 工具不需要 section,因为它们的 description 包含完整契约。部署 persona 只包含角色和行为。 ### Subagent 对话历史描述符 -`SubagentProvider.inheritsParentContext` 描述的是对话种子,而非作用域、服务、工具或权限。spawn 和 ACP 将其设为 `false`;fork 设为 `true`。`dsh-tool-subagent` 根据该标志派生工具描述和 prompt 参数描述,包括 fork 继承已完成轮次但不继承进行中轮次这一事实。提供方生命周期事件使该措辞与响应式的 provider 注册保持同步;其设计动机见 [provider-lifecycle-events RFC](2026-07-05-subagent-provider-lifecycle-events.md)。 +`SubagentProvider.inheritsParentContext` 描述的是对话种子,而非作用域、服务、工具或权限。spawn 和 ACP 将其设为 `false`;fork 设为 `true`。`dsh-tool-subagent` 根据该标志派生工具和 prompt 参数的描述,包括 fork 继承已完成轮次但不继承进行中轮次这一点。provider 生命周期事件使该措辞与响应式 provider 注册保持同步;其设计动机见 [provider-lifecycle-events RFC](2026-07-05-subagent-provider-lifecycle-events.md)。 ## 曾考虑的替代方案 -- **循环自行组合一行身份文本**——在必须保持精简的那个包里硬编码面向模型的行文("plugins, not loop changes"),且在 section 流水线之外形成第二条组合路径。(身份确实以代码字面量交付——但作为 `dsh-system-prompt` 注册的普通 section,其 `system-prompt/assemble` waterfall 仍是部署方需要移除它时的逃生阀。) -- **通过 `agent/request` waterfall 注入模型名称**——提示词文本在两处组合,且 `agent/pre-step` 的 `fullSystemPrompt` 会遗漏它,导致压缩(compaction)测量的提示词与模型实际看到的不一致。 -- **在每个 persona 中手写模型名称**——与上方一行的 `model:` 键重复,配置修改后默默失实——正是本 RFC 要治的病。 -- **宽松插值(未知引用保留原样或替换为空)**——一个拼写错误 `{{modle}}`(或一个空洞)会被送到模型,直到 transcript(文本记录)审查才有人注意到。 -- **在配置中逐实例手写 subagent 措辞**——面向模型的行文重新回到每个部署 × 每个实例,又是同一个病。**按 provider 名称匹配措辞**——`providerName` 本身是配置,重命名 provider 后会静默拿到错误的措辞。 -- **在 `apply` 时解析 provider(加载顺序要求)** 和 **仅用 section 承载 subagent 措辞(在 assemble 时惰性解析)**——provider 生命周期事件的替代方案;均在 [provider-lifecycle-events RFC](2026-07-05-subagent-provider-lifecycle-events.md) 中被否决。 +- **循环自行组合一行 identity 文本**:在必须保持精简的那个包("用插件,不改循环")中硬编码面向模型的行文,且在 section 流水线之外构成第二条组合路径。(identity 确实以代码字面量交付——但作为 `dsh-system-prompt` 注册的普通 section,其 `system-prompt/assemble` waterfall 仍是部署需要移除它时的逃生阀。) +- **通过 `agent/request` waterfall 注入模型名称**:prompt 文本在两处组合,且 `agent/pre-step` 的 `fullSystemPrompt` 会遗漏它,导致 compaction 测量的 prompt 与模型实际看到的不一致。 +- **在每个 persona 中手写模型名称**:与上方一行的 `model:` 键重复,配置修改后静默失实;正是本 RFC 要治愈的病症。 +- **宽松插值(未知引用保留原样或替换为空)**:一个拼写错误 `{{modle}}`(或一个空洞)会被发送给模型,直到 transcript(文本记录)审查时才会被发现。 +- **在配置中为每个 subagent 实例编写措辞**:面向模型的行文回到每个部署 × 实例中,重蹈 P2 病症。**根据 provider 名称选择措辞**:`providerName` 本身是配置,重命名 provider 后会静默获得错误的措辞。 +- **在 `apply` 时解析 provider(加载顺序要求)** 与 **仅用 section 承载 subagent 措辞(在 assemble 时惰性解析)**:provider 生命周期事件的替代方案;两者均在 [provider-lifecycle-events RFC](2026-07-05-subagent-provider-lifecycle-events.md) 中被否决。 ## 不在范围内 -- 更多变量(`date`、平台、git 状态)——注册表使每个变量成为拥有该事实的插件的一行贡献;本 RFC 不认领任何一个。 -- 为预创建的 stdio agent 提供配置 `cwd`(可让 stdio persona 使用 `{{cwd}}` 并按真实路径分区持久化)——推迟到 session-cwd 方案重新讨论时。 +- 更多变量(`date`、platform、git 状态):注册表使每个变量成为拥有该事实的插件的一行贡献;本 RFC 不认领任何一个。 +- 为预创建的 stdio agent 提供配置 `cwd`(可让 stdio persona 使用 `{{cwd}}` 并按真实路径分区持久化):推迟到 session-cwd 方案重新讨论时。 ## 交付的不变式 -- coding-agent 提示词通过一条组装路径渲染:identity、带插值模型名的 persona,然后是 fs/bash/web 指导。 +- coding-agent 的 prompt 通过一条组装路径依次渲染 identity、带插值模型名的 persona,然后是 fs/bash/web 指导。 - fork 和 fresh subagent 的描述反映 provider 是否继承已完成的对话轮次;工具随 provider 生命周期变化而出现、消失和重新措辞。 -- 未知、无值、格式错误或不平衡的变量引用会指名 section 并抛出异常;重复的 section、变量和工具注册也会抛出异常。 -- 快照回放与提示词无关:它按轮次和步骤索引已录制的 chunk 流,不比较发出的请求。 +- 未知、无值、格式错误或不平衡的变量引用会指明 section 名称并抛出异常;重复的 section、变量和工具注册同样抛出异常。 +- 快照回放与 prompt 无关:它按轮次和步骤索引已记录的 chunk 流,不比较发出的请求。 ## 后果 -- 组装后的提示词中每个事实现在恰好有一个归属方,叶子 YAML 中手写的工具行文已消除:加载或卸载一个工具插件不再需要编辑任何部署的 persona。 -- `{{model}}` 在组装时反映 `AgentOptions.model`。如果一个插件在 `agent/request` waterfall 中切换模型,提示词中的声明在该步骤就会过时;如果一个插件在那里**提供**模型(options.model 未设置——循环文档记载的回退路径),变量在渲染时无值,含 `{{model}}` 的 persona 会在 waterfall 运行前失败。两者的补救方式相同,且正是归属规则本身:拥有该延迟绑定模型事实的插件在 `system-prompt/assemble` waterfall 上提前声明它(`assembly.variables['model'] = …`)——一个归属方,两处声明;一个循环测试端到端固定了 supply 路径。已接受。 -- 当一个已绑定的 provider 不在位(尚未激活、已卸载、HMR(热模块替换)重载中)时,subagent 工具不存在,该窗口内的模型请求只是缺少它。这是诚实的状态——替代方案是一个描述或执行都不可信的已注册工具。 -- 严格性意味着 persona 可能在渲染时导致轮次失败(例如在无 cwd 的会话上使用 `{{cwd}}`)。失败是受控的——该轮次以 `error` 结束,循环存活——而且这是一个我们希望大声暴露的撰写错误。 -- 目前没有在 prompt 行文中转义字面 `{{name}}` 的语法;如果真实 prompt 确实需要,届时再添加。 +- 组装后的 prompt 中每个事实现在恰好有一个归属方,leaf YAML 中手工维护的工具行文已消除:加载或卸载一个工具插件不再需要编辑任何部署的 persona。 +- `{{model}}` 在组装时反映 `AgentOptions.model`。如果一个插件在 `agent/request` waterfall 中切换模型,prompt 对该步骤的声明就会过时;如果一个插件在那里**提供**模型(options.model 未设置——循环文档中记载的回退路径),变量在渲染时无值,包含 `{{model}}` 的 persona 会在 waterfall 运行前失败。两者的补救方式相同,就是归属规则本身:拥有延迟绑定模型事实的插件在 `system-prompt/assemble` waterfall 上提前声明它(`assembly.variables['model'] = …`)——一个归属方,两处声明;一个循环测试端到端固定了 supply 路径。已接受。 +- 当一个已绑定的 provider 不存在时(尚未激活、已卸载、HMR(热模块替换)重载中),subagent 工具不存在,该窗口内的模型请求中不会包含它。这是诚实的状态——替代方案是注册一个 description 或执行都不可信的工具。 +- 严格性意味着 persona 可能在渲染时导致轮次失败(例如在无 cwd 的会话上使用 `{{cwd}}`)。失败是受控的——该轮次以 `error` 结束,循环存活——且这是一个我们**希望**大声暴露的撰写错误。 +- 目前没有在 prompt 行文中转义字面 `{{name}}` 的语法;如果真实 prompt 确实需要,再行添加。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml index 7357dfe0f8..2ef938def7 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-05-reconstructable-requests.md: 0978cd8760c6a0420be1bf0a3baf6b50c1a04a13 -2026-07-05-reconstructable-requests.zh.md: 82f9cf085db3d6cd408e54a8e7cf99082d848176 +2026-07-05-reconstructable-requests.zh.md: a4864c9e795ccc0da2cbbf0ca4d17a90c029858c diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md index 82f9cf085d..a4864c9e79 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md @@ -1,4 +1,4 @@ -# RFC:每个 LLM 请求都可从会话日志重建 +# RFC:每个 LLM(大语言模型)请求都可从会话日志重建 Status: implemented @@ -6,50 +6,50 @@ Status: implemented ## 问题 -请求流水线此前不保证前缀稳定性以利用提供方缓存,会话日志也无法重建模型实际看到的内容。日志遗漏了 model、系统提示词和工具 schema,同时允许逐次调用的请求改写。因此缓存行为和回放等价性取决于碰巧加载了哪些插件。 +请求流水线未能保证前缀稳定性以利用提供方缓存,会话日志也无法重建模型实际看到的内容。日志遗漏了 model、系统提示词和工具 schema,同时允许逐次调用的请求改写。因此缓存行为和回放等价性取决于碰巧加载了哪些插件。 -快乐路径的参考形态是 MiniCode 的 `LLMClient`:一个有状态的对话客户端,随对话推进只追加、从不重建,仅在系统提示词、工具集或压缩(compaction)真正改变了模型必须看到的内容时才重置。本 RFC 回答的设计问题是:如何在不放弃事件溯源的前提下获得这种纪律。 +快乐路径的参考形态是 MiniCode 的 `LLMClient`:一个有状态的对话客户端,随对话推进只做追加而不重建,仅在系统提示词、工具集或压缩(compaction)真正改变了模型需要看到的内容时才重置。本 RFC 回答的设计问题是:如何在不放弃事件溯源的前提下获得这种纪律。 ## 决策 ### 原则 -**模型可见 ⟺ 已记录。** 凡到达模型请求的内容,都必须记录在会话日志中。可检查的推论:**循环发出的每个对话请求都是会话日志的纯函数**——任何持有日志的人都能逐字节重建它。精确的范围说明:保证覆盖循环构建的 `GenerateOptions`;提供方协议格式(wire format)字节由它推导而来,因为两个适配器的序列化在固定代码版本下都是逐消息的纯函数;直接的一次性调用(压缩的 summarize 调用)记录其信封标量(`compact/summary.{model, maxTokens}`),其输入是对已记录区域的确定性代码运算——可从日志加代码重建,通过 unfrozen-request 标记排除在不变式之外。 +**模型可见 ⟺ 已记录。** 凡到达模型请求的内容都必须记录在会话日志中。可检查的推论:**循环发出的每个对话请求都是会话日志的纯函数**——任何人持有日志即可逐字节重建请求。精确的范围声明:该保证覆盖循环构建的 `GenerateOptions`;提供方协议格式(wire format)字节由此推导而来,因为两个适配器的序列化在固定代码版本下都是逐消息的纯函数;直接的一次性调用(压缩的 summarize 调用)记录其信封标量(`compact/summary.{model, maxTokens}`),其输入是对日志区域的确定性代码运算——可从日志加代码重建,通过 unfrozen-request 标记排除在不变式之外。 -前缀缓存稳定性是推论 #1,而非标题:一个仅追加的日志经逐节点纯函数投影,在 header 不变时自然产出前一请求的追加扩展——稳定性是涌现的,不是管理出来的。逐字节精确的审计/回放是推论 #2;带*可归因*漂移的恢复与 fork 是推论 #3。 +前缀缓存稳定性是推论 #1,而非标题:一个仅追加的日志经逐节点纯函数投影,在 header 不变时自然产出前一请求的追加扩展——稳定性是涌现的,不是管理出来的。字节精确的审计/回放是推论 #2;带*可归因*漂移的恢复与 fork 是推论 #3。 ### 机制 -**消息。** `Session.deriveMessages()` 带缓存:每个 surface 节点在首次出现时通过公开的逐节点函数 `deriveEventMessage(event)` 精确投影一次;surface 改写(压缩的 `replace`——`SurfaceManager.replaceGeneration`)触发重建。调用方每次获得一个新数组,其中的消息是共享的、深度冻结的:通过投影修改已记录的历史是不可表达的(会抛异常),取代了旧的每次调用克隆隔离。外部重建器对日志前缀折叠同一个公开函数,因此不可能有两条路径产生分歧。 +**消息。** `Session.deriveMessages()` 带缓存:每个 surface 节点在首次出现时通过公开的逐节点函数 `deriveEventMessage(event)` 精确投影一次;surface 重写(压缩的 `replace`,即 `SurfaceManager.replaceGeneration`)触发重建。调用方每次获得一个新数组,底层是共享的深度冻结消息:通过投影变异已记录的历史是不可表达的(会抛异常),取代了旧的逐次调用克隆隔离。外部重建器对日志前缀折叠同一个公开函数,因此不可能有两条路径产生分歧。 -`EpochHeader` 记录请求的非历史状态:调用配置、渲染后的系统提示词、工具 schema 和会话前缀,空值规范化为缺失。`request/header` 写入完整的初始、恢复或回退快照。`request/header-delta` 通过公共前缀/后缀行裁剪编码系统提示词变更,通过按名称键控的增/删/改编码工具变更,通过完整替换编码配置或前缀变更。`foldRequestHeader`、`diffHeader` 和 `applyHeaderDelta` 是纯编解码器。每个循环实例在其首次请求时写入一个快照,以锚定进程边界。Delta 仅是优化:写入方验证往返等价性,对不可表达的变更(如纯工具重排序)回退到完整快照。 +`EpochHeader` 记录请求的非历史状态:调用配置、渲染后的系统提示词、工具 schema 和会话前缀,空值规范化为缺失。`request/header` 写入完整的初始、恢复或回退快照。`request/header-delta` 通过公共前缀/后缀行裁剪编码系统变更,通过按名称键控的增/删/改编码工具变更,通过完整替换编码配置或前缀变更。`foldRequestHeader`、`diffHeader` 和 `applyHeaderDelta` 是纯编解码器。每个循环实例在首次请求时写入一个快照以锚定进程边界。delta 只是优化:写入方验证往返等价性,对无法表达的变更(如纯工具重排序)回退到完整快照。 -每一步重建 prompt 组装。实例的第一步中,`agent/session-prefix` 用仅限请求的开场消息扩展一个冻结的空种子;结果被冻结并缓存于该循环实例。`agent/pre-step` 随后在消息快照紧接 `step/start` 之前接收组合后的前缀。首次调用配置从显式的 `AgentOptions` 出发,保留 fork 覆盖和恢复重配置;后续调用从折叠后的 header 出发。`agent/request` 只能替换那个冻结的配置种子,而模型可见的内容通过已记录的通道进入。循环记录欠写的 header 事件(前缀唯一的持久化归属),从前缀、快照和 header 构建 `GenerateOptions`,并深度冻结它,同时保持 `AbortSignal` 活跃。每实例状态仅有缓存的前缀和其锚定快照是否已写入。 +每个步骤重建 prompt 组装。在实例的首个步骤中,`agent/session-prefix` 以一个冻结的空种子为基础,用仅限请求的开场消息进行扩展;结果被冻结并缓存于该循环实例。`agent/pre-step` 随后接收组合后的前缀,消息在 `step/start` 之前立即被快照。首次调用配置从显式的 `AgentOptions` 出发,保留 fork 覆盖和恢复重配置;后续调用从折叠后的 header 出发。`agent/request` 只能替换那个冻结的配置种子,模型可见内容通过已记录的通道进入。循环记录欠下的 header 事件(前缀唯一的持久归宿),从前缀、快照和 header 构建 `GenerateOptions`,对其深度冻结但保持 `AbortSignal` 活跃。每实例状态仅有缓存的前缀和锚定快照是否已写入。 -**`step/start` 是重建边界。** 一步从该序列之前的事件派生消息。快照之后的注入加入下一次请求,事件发布期间的重入追加被拒绝。`agent/pre-step` 是当前请求所需内容的 seam。Header 重建折叠该步骤自身的 `request/header*` 事件,或在无新 header 写入时沿用前一次折叠结果。 +**`step/start` 是重建边界。** 一个步骤从该序列之前的事件推导消息。快照之后的注入加入下一次请求,事件发布期间的重入追加被拒绝。`agent/pre-step` 是当前请求所需内容的 seam。header 重建通过该步骤自身的 `request/header*` 事件折叠,或在无新 header 写入时沿用前一次折叠结果。 -**强制执行。** 在开发环境中,`dsh-invariants` 通过一个全新的 `Session` 独立重建每个循环请求,使活跃缓存无法为自身背书,然后在 `llm/stream` 处比较消息和折叠后的 header 字段。循环请求通过其冻结形态和 session id 识别;直接的一次性调用被排除。正确性依赖于序列有界的重建而非监听器顺序。带密钥的 e2e 要求首次请求之后出现正数的 cache-read token;逐步 usage 是生产信号,header 变更或压缩表现为下一步 cache-read 的下降。 +**强制执行。** 在开发环境中,`dsh-invariants` 通过一个全新的 `Session` 独立重建每个循环请求,使活跃缓存无法为自身背书,然后在 `llm/stream` 处比较消息和折叠后的 header 字段。循环请求通过其冻结形状和 session id 识别;直接的一次性调用被排除。正确性依赖于序列有界的重建,而非监听器顺序。带密钥的 e2e 要求首次请求之后有正值的 cache-read token;逐步骤用量是生产信号,header 变更或压缩表现为下一步骤的 cache-read 下降。 ### MiniCode 形态:采纳,但溯源箭头反转 -与 MiniCode 一样,对话仅追加推进,仅在模型可见状态变更时重置。与 MiniCode 不同的是,事件日志仍是真源,因为它还拥有持久化、恢复、边界、工具配对和溯源。`Session` 缓存从日志派生的消息和 header 折叠结果,使每个请求都可独立检查。 +与 MiniCode 相同,对话仅追加推进,仅在模型可见状态变更时重置。与 MiniCode 不同,事件日志仍是真源,因为它同时拥有持久化、恢复、边界、工具配对和溯源。`Session` 缓存从日志推导的消息和 header 折叠结果,使每个请求都可独立检查。 ## 曾考虑的替代方案 -- **客户端作为真源**(照搬 MiniCode):在日志之外出现第二个生效的真相——两者漂移而无人察觉;见上节。 +- **客户端作为真源**(照搬 MiniCode):在日志之外多出一个运行时真相——两者漂移而无人察觉;见上节。 - **镜像日志的有状态传输客户端**:重复对话状态,需要围绕监听器做回滚,留下未记录的编辑面,且仍无法重建请求 header。Session 拥有的缓存加已记录的 header 避免了这些分裂的真相。 -- **逐次调用的请求标量**(每次 `agent/request` 分发时传入一个可自由修改的配置):监听器可以零记账地逐次切换 model,悄然放弃本设计旨在保护的提供方缓存。配置是逐对话的已记录状态;waterfall(瀑布式事件)提议,日志记录。 -- **检测并报告**(比较连续请求,发现分歧时警告):事后捕获违规;违规请求仍可构造并发出。因接口层面的不可表达性而否决。 -- **事件驱动组装**(仅在变更信号时重新渲染):存在信号遗漏的 bug 类别——会话中途注册的工具发出 `tools/change` 而非 `system-prompt/change`,第三方提供方可能什么都不发。逐步渲染加值比较在零信号纪律下仍然健壮。 -- **Header 事件上的叙事字段**(delta 上的 `reason`/`changed` 列表):可通过 diff 连续事件派生——每个事实只有一个归属;快照携带 reason 是因为锚点的成因无法从数据本身派生。 +- **逐次调用的请求标量**(一个可自由变异的配置传给每次 `agent/request` 分发):监听器可以零记账地逐次切换 model,悄然放弃本设计旨在保护的提供方缓存。配置是逐对话的已记录状态;waterfall(瀑布式事件)提议,日志记录。 +- **检测并报告**(比较连续请求,发散时告警):事后捕获违规;违规请求仍可构造并发出。因接口层面的不可表达性而否决。 +- **事件驱动组装**(仅在变更信号时重新渲染):存在漏信号的 bug 类别——会话中途注册的工具发出 `tools/change` 而非 `system-prompt/change`,第三方提供方可能什么都不发。逐步骤渲染加值比较在零信号纪律下即可稳健工作。 +- **Header 事件上的叙事字段**(delta 上的 `reason`/`changed` 列表):可通过 diff 连续事件推导——每个事实只有一个归宿;快照携带 reason 是因为锚点的成因无法从数据推导。 ## 后果 -- 一个无法由日志解释的请求不可能被意外构造——无论是循环还是监听器;修改已构建的请求会抛异常;每次 header 变更都是一个持久的、可 diff 的日志事件。 -- 在建议通道之间做选择是变更频率决策,而本设计让稳定的那个成为结构性的:`agent/session-prefix` 的贡献在每个循环实例中只组合一次并逐字复用,因此它以零边际成本扩展可缓存前缀,且**不可能**在会话中途击穿提供方缓存;会话中途变化的内容通过仅追加的历史通道流入——`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——每个都是持久的 `context/message`,付出一次代价后即享受前缀缓存,代价是在历史和日志中累积。将会话冻结的开场内容路由到前缀,将变更通知路由到历史通道;逐步的仅限请求尾部槽位被有意放弃(无消费方,且持久追加覆盖了所有当前更新模式)。 -- 在提供方处仍需全价的内容是固有的且已记录的:压缩(其 `compact/*` 事件和 replace 节点)、真正的 prompt/工具变更(`request/header-delta`)、配置切换(同上)、带漂移的进程边界(`'resume'` 快照与前一个不同)。提供方自身的 reasoning-content 排除由服务端管理。 +- 一个日志无法解释的请求不可能被意外构造——无论是循环还是监听器;变异已构建的请求会抛异常;每个 header 变更都是持久的、可 diff 的日志事件。 +- 在建议性通道之间做选择是变更频率的决策,而本设计使稳定的那个在结构上成为默认:`agent/session-prefix` 的贡献在每个循环实例中只组合一次并逐字复用,因此以零边际成本扩展可缓存前缀,且**不可能**在会话中途击穿提供方缓存;会话中途变化的内容通过仅追加的历史通道流入——`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——每条都是持久的 `context/message`,付出一次代价后即被前缀缓存,代价是在历史和日志中累积。将会话冻结的开场内容路由到前缀,将变更通知路由到历史通道;逐步骤的仅限请求尾部槽位被有意放弃(无消费方,且持久追加覆盖了当前所有更新模式)。 +- 在提供方处仍需全价计算的内容是固有的且已记录的:压缩(其 `compact/*` 事件和 replace 节点)、真正的 prompt/工具变更(`request/header-delta`)、配置切换(同上)、带漂移的进程边界(`'resume'` 快照与前一快照不同)。提供方自身的 reasoning-content 排除由服务端管理。 - `step/start` 监听器行为变更(见上文)是对插件唯一可观察的语义变更;`agent/pre-step` 是当前请求的 seam。 -- 工具结果裁剪(计划中)无需新机制:一个已记录的单节点 surface replace(`start === end`),携带同一 `callId` 下裁剪后的 `tool/result`——属于压缩家族,回放正确,缓存击穿由相同的压力逻辑批量处理。 -- 会话日志每个对话增长一个 `request/header` 快照(系统提示词 + 工具 schema:主导项),加上真正变更时的 delta——相对于 `assistant/chunk` 的体量很小;`SESSION_FORMAT_VERSION` 保持 `0`(预发布期间的变动被吸收,后端拒绝而非迁移)。 -- 快照 golden 文件变更一次(每份 transcript 增加其 header 事件);写文件系统的 fixture 以规范化的撰写形式存储,工具参数使用 cwd 相对路径,因为回放只往返 cwd 无关的参数路径。 -- FIXME(call-config-shape):重新审视 `LlmCallConfig` 的确切字段集——哪些字段对缓存而言真正属于 epoch 级别(`model` 毫无疑问;采样标量出于谨慎放在那里),以及当适配器需要时,提供方特有的额外项(reasoning 选项、额外 body 参数)应归属何处。 +- 工具结果裁剪(计划中)无需新机制:一个已记录的单节点 surface replace(`start === end`),携带同一 `callId` 下裁剪后的 `tool/result`——属压缩家族,回放正确,缓存击穿由相同的压力逻辑批量处理。 +- 会话日志每个对话增长一个 `request/header` 快照(系统提示词 + 工具 schema:主导项),加上真正变更时的 delta——相对 `assistant/chunk` 的体量很小;`SESSION_FORMAT_VERSION` 保持 `0`(预发布期间的变动被吸收,后端拒绝而非迁移)。 +- 快照 golden 文件变更一次(每个 transcript(文本记录)增加其 header 事件);写入文件系统的 fixture(测试前置数据)以规范化的撰写形式存储,工具参数使用 cwd 相对路径,因为回放只对 cwd 无关的参数路径做往返。 +- FIXME(call-config-shape):重新审视 `LlmCallConfig` 的确切字段集——哪些字段对缓存而言真正属于 epoch 级别(`model` 毫无疑问;采样标量出于谨慎放在那里),以及当适配器需要时,提供方特定的额外项(reasoning 选项、额外 body 参数)应归属何处。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml index 1bf06ce567..74fbfda121 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-05-subagent-provider-lifecycle-events.md: 6d711f2a6d8496a8a229ec63d86dd89816efb6f8 -2026-07-05-subagent-provider-lifecycle-events.zh.md: 45eedcfdfa834722000c9f2c15e3955ced791c2f +2026-07-05-subagent-provider-lifecycle-events.zh.md: f412b031644c14ca70caae3efc72eefa9ce2c2ac diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md index 45eedcfdfa..f412b03164 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md @@ -1,36 +1,36 @@ # RFC:Subagent 提供方生命周期事件——`subagent/provider-added` / `subagent/provider-removed` -Status: implemented - [English](2026-07-05-subagent-provider-lifecycle-events.md) | 中文 +Status: implemented + ## 问题 -[prompt-variables RFC](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) 使 `dsh-tool-subagent` 从其提供方**派生**面向模型的措辞:`SubagentProvider.inheritsParentContext`(spawn/ACP 为 `false`,fork 为 `true`)同时驱动工具描述和 `prompt` 参数描述(`providerWording`),从而让 fork 工具不再在上下文继承问题上对模型撒谎。这一修复引入了跨 fiber 的数据依赖:工具描述在**工具注册时**就已固定(这是有意为之——描述是 tool-choice 引导所在之处),但提供方在自己的插件 fiber 上到达,时机不确定。 +[prompt-variables RFC](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) 让 `dsh-tool-subagent` 从其提供方**派生**面向模型的措辞:`SubagentProvider.inheritsParentContext`(spawn/ACP 为 `false`,fork 为 `true`)同时驱动工具描述和 `prompt` 参数描述(`providerWording`),使 fork 工具不再在上下文继承问题上对模型撒谎。这一修复引入了跨 fiber 的数据依赖:工具描述在**工具注册时**固定(这是有意为之——描述是 tool-choice 引导所在之处),但提供方在自己的插件 fiber 上到达,时机不确定。 -如果在工具插件的 `apply` 时刻解析提供方,就会产生隐式的加载顺序要求("在 cordis.yml 中把后端列在工具前面")。这一要求行不通,因为 Cordis Loader 并发启动同级条目,且 `Entry.init()` 不等待激活完成:一个延迟到达的后端可能导致工具 fiber 失败,即使它在配置中列在前面也是如此。Loader 不提供同级顺序保证——"异步状态不是同步状态"(见[防御性模式](../../../defensive-patterns.md))。 +如果在工具插件的 `apply` 时刻解析提供方,就会产生一个隐式的加载顺序要求("在 cordis.yml 中把后端列在工具前面")。这个要求不成立,因为 Cordis Loader 并发启动同级条目,且 `Entry.init()` 不会等待激活完成:延迟到达的后端即使列在前面,也可能让工具 fiber 失败。Loader 不提供同级顺序保证——"异步状态不是同步状态"(见[防御性模式](../../../defensive-patterns.md))。 ## 决策 -注册表将提供方的成员变动作为类型化事件广播,消费方镜像这些事件而非假设顺序: +注册表将提供方的成员变化作为类型化事件广播,消费方镜像这些事件而非假设顺序: - **`subagent/provider-added(provider)`**:一个提供方在 `ctx.subagents` 注册表中变为可解析。在注册时发出。 -- **`subagent/provider-removed(name)`**:一个提供方离开了注册表(其插件 fiber 被 dispose——卸载或 HMR 重载)。从注册的 disposer 中发出。 +- **`subagent/provider-removed(name)`**:一个提供方离开注册表(其插件 fiber 被 dispose(资源释放)——卸载或 HMR(热模块替换)重载)。从注册的 disposer 中发出。 -`dsh-tool-subagent` 镜像其命名提供方的生命周期:当提供方可用(或变为可用)时注册工具——在那一刻从该提供方派生措辞;当提供方离开时注销工具;在重新注册时(HMR 重载)重新派生。提供方不在时工具不存在,因此不可能对模型撒谎。这里**刻意不留**任何需要文档化的加载顺序要求:事件使顺序问题消失,而非将其钉死。 +`dsh-tool-subagent` 镜像其命名提供方的生命周期:当提供方可用(或变为可用)时注册工具——在那一刻从该提供方派生措辞——当提供方离开时注销工具,并在重新注册时(HMR 重载)重新派生。提供方不在时工具不存在,因此不会对模型撒谎。这里有意**不留下**任何需要文档化的加载顺序要求:事件让顺序问题消失,而非将其钉死。 -这些事件还补全了该 seam 的词汇:`ctx.subagents` 是一个命名注册表,多个委派后端(`spawn`、`fork`、`acp`)在其上共存;一个内容会被其他插件用来派生状态的注册表,应当以类型化事件广播成员变动,而非要求轮询或依赖加载顺序。 +这些事件还完善了 seam 的词汇:`ctx.subagents` 是一个命名注册表,多个委派后端(`spawn`、`fork`、`acp`)在其上共存;一个其他插件从中派生状态的注册表,应当以类型化事件广播成员变化,而非要求轮询或依赖加载顺序。 ## 曾考虑的替代方案 -- **在 `apply` 时解析提供方,不存在则抛异常**:否决。"先列后端"会声称一个 Loader 并不提供的顺序保证。 -- **重试查找(轮询直到提供方出现)**:最终会收敛,但在框架已有的机制(effect 注册 + disposal)之外自行发明了一套私有就绪协议;而且它无法感知提供方**离开**,因此 HMR 会让一个措辞描述着已 dispose 后端的工具滞留。 -- **仅在 section 中放置 subagent 措辞,在组装时延迟解析**:同样能容忍任意加载顺序,但把 tool-choice 引导移出了描述,与 prompt-variables RFC 确立的归属规则相矛盾(每个工具的语义和使用时机属于描述)。响应式注册既保持描述的权威性,又不依赖顺序。 -- **根据提供方名称而非提供方对象来确定措辞**:`providerName` 本身是配置,重命名提供方后会静默获得错误的措辞;从已解析提供方自身的 `inheritsParentContext` 派生则不会漂移。 +- **在 `apply` 时解析提供方,不存在则抛异常**:否决。"先列后端"这一要求声称了 Loader 并不存在的顺序保证。 +- **重试查找(轮询直到提供方出现)**:最终能收敛,但在框架已有的机制(effect 注册 + disposal)之外发明了一套私有就绪协议;它也无法感知提供方**离开**,因此 HMR 会遗留一个措辞描述已 dispose 后端的工具。 +- **仅在 section 中放置 subagent 措辞,在组装时惰性解析**:同样能容忍任意加载顺序,但将 tool-choice 引导移出了**描述**,与 prompt-variables RFC 建立的所有权规则相矛盾(每个工具的语义和何时使用属于描述)。响应式注册既保持描述的权威性,又不依赖顺序。 +- **根据提供方名称而非提供方对象确定措辞**:`providerName` 本身是配置,重命名后的提供方会静默获得错误的措辞;从已解析提供方自身的 `inheritsParentContext` 派生则不会漂移。 ## 后果 - 从命名提供方派生状态的消费方响应 `subagent/provider-added`/`-removed` 事件,而非在 `apply` 时读取注册表;`dsh-tool-subagent` 是参考实现。 -- **添加时大声失败;移除时按监听器隔离。** 添加监听器可以回滚注册。移除在 disposal 期间运行,因此单个监听器抛异常只会被记录,不会饿死后续镜像或扰乱拆卸流程。`start()` 仍然在每次运行时按名称解析提供方,防止陈旧工具调用已移除的后端。见[事件目录](../../../cordis-catalog/events.md)和[生产者/消费者映射](../../../event-producer-consumer.md)。 -- **工具不存在的窗口期。** 在后端 disposal 与重新注册之间(HMR 重载),模型看不到 subagent 工具。这是诚实的状态——替代方案是一个向空处派发的工具——工具注册表的 `tools/change` 事件确保 prompt 组装保持最新。 -- **两个等待中的 fiber 共享同一 `toolName` 是无效配置,且被延迟捕获。** 如果两个 `dsh-tool-subagent` 实例命名了不同的提供方但相同的 `toolName`,二者都会等待,先到达的提供方触发注册;第二个注册仅在**其**提供方到达时才抛异常。插件中的 `TODO(subagent-dup-toolname)` 记录了这一爆炸半径;工具注册表的重名拒绝机制仍是最终兜底。 +- **添加时大声失败;移除时按监听器隔离。** 添加监听器可以回滚注册。移除在 disposal 期间运行,因此单个监听器抛异常只会被记录日志,不会饿死后续镜像或干扰拆解流程。`start()` 仍在每次运行时按名称解析提供方,防止陈旧工具调用已移除的后端。见[事件目录](../../../cordis-catalog/events.md)与[生产者/消费者映射](../../../event-producer-consumer.md)。 +- **工具不存在的窗口期。** 在后端 disposal 与重新注册之间(HMR 重载期间),模型看不到 subagent 工具。这是诚实的状态——替代方案是一个向空处分发的工具——工具注册表的 `tools/change` 事件发出会保持 prompt 组装的时效性。 +- **两个等待中的 fiber 共享同一 `toolName` 是无效配置,被延迟捕获。** 如果两个 `dsh-tool-subagent` 加载实例命名了不同的提供方但相同的 `toolName`,两者都会等待,先到达的提供方先注册;第二次注册仅在**其**提供方到达时才抛异常。插件中的 `TODO(subagent-dup-toolname)` 记录了这一影响范围;工具注册表的重名拒绝机制仍是最终防线。 diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml index cc697c3e30..a051d20478 100644 --- a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-06-timeout-deadline-library.md: 9906aa7cce40ffd7b5f7082199d05edb8d0a54b2 -2026-07-06-timeout-deadline-library.zh.md: ef99a1a051f3cedbe5a2770e5bbeeebe716745c4 +2026-07-06-timeout-deadline-library.zh.md: dd1a60f9d7b91575b32e1cc85b3800cf823b6a6d diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md index ef99a1a051..dd1a60f9d7 100644 --- a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md @@ -1,22 +1,22 @@ -# RFC:共享的超时/截止时间原语,hard-kill 留给各能力自行实现 - -[English](2026-07-06-timeout-deadline-library.md) | 中文 +# RFC:共享的超时/截止时间原语,硬终止留给各能力自行实现 Status: implemented +[English](2026-07-06-timeout-deadline-library.md) | 中文 + ## 问题 -超时处理在各个承载工具的能力之间逐渐分化,而这种分化并非表面的——同一套逻辑被三种方式各自重新实现,每种都带着自己微妙的正确性负担。 +超时处理在各个承载工具的能力之间逐渐分化,而且这种分化并非表面的:同一套逻辑被以三种方式重新实现,各自带有微妙的正确性负担。 -- **bash**([packages/bash/bash-local/src/run.ts](../../../../packages/bash/bash-local/src/run.ts))在进程管道内部有一套完整、正确的超时实现:一个经配置钳位的 `timeoutMs`,两个独立触发器——用于超时的 `killTimer` 和用于上游取消的 `onAbort` 监听器——各自调用同一个 `kill()` 闭包,该闭包对进程组执行 SIGTERM→宽限期→SIGKILL 升级,以及两个正交的结果布尔值(`timedOut`、`aborted`)各自独立锁存。 -- **web_fetch**([packages/web/web-fetch-local/src/provider.ts](../../../../packages/web/web-fetch-local/src/provider.ts))有一套正确但*手工搭建*的超时:它构造一个 `AbortController`,接入 `setTimeout(() => controller.abort(new WebError(…, 'WEB_FETCH_TIMEOUT')))`,手动添加和移除上游信号监听器,在 `finally` 中清除定时器,并在 `translateAbortOrNetwork` 辅助函数中从 `signal.reason` 恢复超时原因——因为 reader 只抛出裸 `AbortError`。 -- **web_search**([packages/web/tool-web/src/search.ts](../../../../packages/web/tool-web/src/search.ts))**完全没有超时**:`WebSearchRequest`([packages/web/web/src/types.ts](../../../../packages/web/web/src/types.ts))不携带 `timeoutMs` 字段,各提供方的 `search()` 只转发 `exec.signal`。(web_search 在本 RFC 中保持无超时——见「后果」。) +- **bash**([packages/bash/bash-local/src/run.ts](../../../../packages/bash/bash-local/src/run.ts))在进程管道内部有一套完整、正确的超时实现:一个经配置钳位的 `timeoutMs`,两个独立触发器(用于超时的 `killTimer` 和用于上游取消的 `onAbort` 监听器),各自调用同一个 `kill()` 闭包对进程组执行 SIGTERM→宽限期→SIGKILL 升级,以及两个正交的结果布尔值(`timedOut`、`aborted`)独立锁存。 +- **web_fetch**([packages/web/web-fetch-local/src/provider.ts](../../../../packages/web/web-fetch-local/src/provider.ts))有一套正确但*手写*的超时:构造一个 `AbortController`,连接 `setTimeout(() => controller.abort(new WebError(…, 'WEB_FETCH_TIMEOUT')))`,手动添加和移除上游信号监听器,在 `finally` 中清除定时器,并在 `translateAbortOrNetwork` 辅助函数中从 `signal.reason` 恢复超时原因(因为 reader 只抛出裸 `AbortError`)。 +- **web_search**([packages/web/tool-web/src/search.ts](../../../../packages/web/tool-web/src/search.ts))**完全没有超时**:`WebSearchRequest`([packages/web/web/src/types.ts](../../../../packages/web/web/src/types.ts))不携带 `timeoutMs` 字段,各提供方的 `search()` 只转发 `exec.signal`。(web_search 在本次设计中保持无超时——见「后果」。) -每个新的外部进程或网络工具都要重新推导同样四件事:钳位请求值、启动定时器、将超时与上游取消融合、在出口处区分「超时」与「被取消」——而融合和原因恢复恰恰是最容易出微妙错误的部分(web_fetch 的 `signal.reason` 舞步就是证据)。与此同时,各能力执行的*终止*动作不可归约地不同:bash 杀的是 OS 进程组(工作运行在子进程中,在本运行时之外,只能通过信号触达),而 web 中止的是进程内的 `fetch`(undici 拆掉 socket)。不存在一种单一机制能停止所有这些工作。 +每个新的外部进程或网络工具都要重新推导同样四件事:钳位请求值、启动定时器、将超时与上游取消融合、在出口处区分「超时」与「已取消」。而融合与原因恢复恰恰是最容易出微妙错误的部分(web_fetch 的 `signal.reason` 处理就是证据)。与此同时,各能力执行的*终止*操作不可归约地不同:bash 杀死一个 OS 进程组(工作运行在子进程中,在本运行时之外,只能通过信号触达),而 web 中止一个进程内的 `fetch`(undici 拆除 socket)。不存在一个能停止所有能力工作的单一机制。 ## 决策 -`@deepseek-ai/dsh-timeout` 位于 `packages/util/`(与 `dsh-brand` 同级),拥有超时的*计时与分类*这一半;*终止*那一半——hard kill——留在各能力的实现中。它是一个纯函数库,**不是** Cordis 服务或插件:不接收 `ctx`、不注册任何东西、不持有跨调用状态、不发射事件。刻意不设中央「超时服务」——那样的服务必须知道如何停止每个能力的工作,而这正是微内核要排除在共享层之外的知识,也是 Codex 的 `ExecExpiration` 作用域仅限于 exec 家族所示范的。 +`@deepseek-ai/dsh-timeout` 位于 `packages/util/`(与 `dsh-brand` 同级),负责超时的*计时与分类*这一半;*终止*那一半——硬终止——留在各能力的实现中。它是一个纯函数库,**不是** Cordis 服务或插件:不接收 `ctx`、不注册任何东西、不持有跨调用状态、不发射事件。这里刻意不设中央「超时服务」,因为那样的服务必须知道如何停止每个能力的工作——而这正是微内核要排除在共享层之外的知识,也是 Codex 将 `ExecExpiration` 限定于 exec 族所示范的原则。 ### 库的对外接口 @@ -57,42 +57,42 @@ export function deadline( export function timeoutOf(x: AbortSignal | { reason?: unknown }, code?: string): TimeoutReason | undefined ``` -`deadline` 通过 `AbortSignal.any` 将上游信号与定时器融合,附加一个类型化的 `TimeoutReason`,并暴露可 dispose(资源释放)的定时器清理。非正数超时是内部的无超时哨兵,用于后端自有的后台任务;外部提示经 `clampTimeout` 后必须为正有限值。既无定时器也无上游信号时,函数返回一个永不中止的信号,但具有相同的 disposal 形状。提供方将超时原因翻译为 seam 特定的结果。`timeoutOf(signal, code)` 通过 code 限定分类范围,使外层嵌套的 deadline 被视为上游取消而非内层能力的超时。 +`deadline` 通过 `AbortSignal.any` 将上游信号与定时器融合,附加一个类型化的 `TimeoutReason`,并暴露可 dispose(资源释放)的定时器清理。非正数超时是内部的「无超时」哨兵,用于后端拥有的后台任务;外部提示经过 `clampTimeout`,必须为正有限值。既无定时器也无上游信号时,函数返回一个永不中止的信号,具有相同的 disposal 形状。提供方将超时原因转译为 seam 特定的结果。`timeoutOf(signal, code)` 限定分类范围,使外层嵌套的 deadline 被视为上游取消而非内层能力自身的超时。 -### 分工 +### 职责划分 | 关注点 | 负责方 | |---|---| -| 校验请求提示并钳位 default/max | `dsh-timeout`(`clampTimeout`)——纯算术加共享的正有限请求契约 | +| 校验请求提示并钳位默认值/最大值 | `dsh-timeout`(`clampTimeout`):纯算术加共享的正有限请求契约 | | 启动定时器、到期中止、携带 reason、与上游取消融合 | `dsh-timeout`(`deadline`) | | 清除定时器 | `dsh-timeout`(`[Symbol.dispose]`) | -| 中止后分类首个 abort reason | `dsh-timeout`(`timeoutOf`) | +| 中止后对首个 abort reason 进行分类 | `dsh-timeout`(`timeoutOf`) | | **实际终止工作** | 各能力的实现 | -| default/max *值* | 各能力的配置 | +| 默认值/最大值*数值* | 各能力的配置 | | 超时 `code` 字符串 | 各能力(`WEB_FETCH_TIMEOUT` ≠ `BASH_TIMEOUT`) | -信号只*通知*;终止始终是监听者的职责,而监听者因能力而异。bash 自己写 `addEventListener('abort', kill)`,因为 OS 进程活在本运行时之外,没有别的东西会杀它;web 把 `d.signal` 交给 `fetch`,undici 拆掉 socket。这也是文件 read/write/edit 不接受 **`timeoutMs`** 的原因:本地系统调用至多只能尽力中止,超时无法强制 `fsync`/`rename` 停下,加一个超时等于引入一个违反「显式优于隐式」的隐式默认值。两个参考 agent 出于同样的理由都不给文件 I/O 设超时。 +信号只*通知*;终止始终是监听方的职责,而监听方因能力而异。bash 自行编写 `addEventListener('abort', kill)`,因为 OS 进程存在于本运行时之外,没有别的东西会杀死它;web 将 `d.signal` 交给 `fetch`,由 undici 拆除 socket。这也是文件读/写/编辑**不接受** `timeoutMs` 的原因:本地系统调用最多只能尽力中止,超时无法强制 `fsync`/`rename` 停止,添加超时将是一个违反「显式优于隐式」的隐式默认值。两个参考 agent 出于同样的原因对文件 I/O 不设超时。 -### 各能力如何消费 +### 各能力如何消费该库 -- **web_fetch**——工具层保持校验并转发;提供方手工搭建的 controller + `setTimeout` + 手动监听器 + `finally` + `signal.reason` 恢复被提供方自有的 `deadline`/`timeoutOf` 取代。上游信号已预先中止时仍立即抛出 `WEB_ABORTED`;否则 `fetch` 使用融合后的 `d.signal` 运行,`translateAbortOrNetwork` 根据信号分类抛出的错误(`timeoutOf` → `WEB_FETCH_TIMEOUT`,否则已中止 → `WEB_ABORTED`,否则网络 → `WEB_PROVIDER_ERROR`)。公开的错误码契约不变,`TimeoutReason` 永远不会作为公开错误跨越 web seam。 -- **bash**——`resolve()` 将请求钳位为显式规格。前台 `run()` 创建 deadline 并将其信号传给进程执行,后者既有的 abort 监听器执行进程组 kill。执行器将首个 abort 分类为超时或取消。后台启动保持无超时,仅转发上游取消。 +- **web_fetch**:工具层保持校验并转发;提供方手写的 controller + `setTimeout` + 手动监听器 + `finally` + `signal.reason` 恢复被替换为提供方自有的 `deadline`/`timeoutOf`。已预先中止的上游信号仍然立即抛出 `WEB_ABORTED`;否则 `fetch` 使用融合后的 `d.signal` 运行,`translateAbortOrNetwork` 根据信号分类抛出的错误(`timeoutOf` → `WEB_FETCH_TIMEOUT`,否则已中止 → `WEB_ABORTED`,否则网络错误 → `WEB_PROVIDER_ERROR`)。公开的错误码契约不变,`TimeoutReason` 永远不会作为公开错误跨越 web seam。 +- **bash**:`resolve()` 将请求钳位为显式规格。前台 `run()` 创建 deadline 并将其信号传给进程执行,后者既有的 abort 监听器执行进程组 kill。执行器将首个 abort 分类为超时或取消。后台启动保持无超时,仅转发上游取消。 ## 后果 - `runBash` 的结果不再独立锁存 `timedOut` 和 `aborted`;超时与用户中止在进程关闭前竞争时,现在报告单一的首个 abort 原因,而非两者同时为 true。统一的 SIGTERM→宽限期→SIGKILL 终止路径不变,seam 类型 `BashRunResult` 保留两个布尔值(现在互斥),因此 `dsh-tool-bash` 的结果渲染不受影响。 -- `SpawnSpec.timeoutMs` 与 `SpawnOutcome.timedOut`/`aborted` 被移除,而非作为始终为零/始终为 false 的残留保留:`runBash` 不再拥有定时器、执行器拥有分类逻辑后,它们无处被读取。这是与字面提案形状(向 `runBash` 传 `timeoutMs: 0`)的唯一偏差;在逐文件覆盖率门禁下,一个始终为 0 且无人读取的字段是死代码。 -- web_fetch 去掉了自建的 controller/timer/listener/reason-recovery;分类器现在基于 deadline 信号(`timeoutOf` + `aborted`)而非抛出错误的形状来判断,这在请求阶段的 reject-with-reason 和读取阶段的裸 `AbortError` 两种情况下都是健壮的。 -- `AbortSignal.any` 与 `using`/`Symbol.dispose` 在此首次进入本仓库(Node ≥ 24 基线,已满足)。 +- `SpawnSpec.timeoutMs` 和 `SpawnOutcome.timedOut`/`aborted` 被移除,而非作为始终为零/始终为 false 的残余保留:由于 `runBash` 不再拥有定时器且执行器负责分类,这些字段无处被读取。这是与字面提案形状(向 `runBash` 传入 `timeoutMs: 0`)的唯一偏差;一个始终为 0 且无处读取的字段在逐文件覆盖率门禁下属于死代码。 +- web_fetch 去除了其定制的 controller/timer/listener/reason-recovery;分类器现在基于 deadline 信号(`timeoutOf` + `aborted`)而非抛出错误的形状来判断,这在请求阶段的 reject-with-reason 和读取阶段的裸 `AbortError` 两种情况下都是健壮的。 +- `AbortSignal.any` 和 `using`/`Symbol.dispose` 在此首次进入本仓库(Node ≥ 24 基线,已满足)。 -不在本 RFC 范围内,列出以标明边界:`web_search` 可以在其 tool-schema/快照覆盖率规划完成后获得可选的面向模型的 `timeout_ms`;未来基于 ripgrep 的文件系统发现工具可以在存在后消费同样的提供方自有 deadline 形状;`tools/execute` waterfall(瀑布式事件)中间件可以通过驱动 `exec.signal` 为每次工具调用设置默认 deadline——那将是一个*消费*本库的插件,仍然只做通知,hard kill 仍是各能力自己的事。 +以下内容不在本次范围内,列出以标明边界:`web_search` 可以在其 tool-schema/snapshot 覆盖率规划就绪后获得可选的面向模型的 `timeout_ms`;未来基于 ripgrep 的文件系统发现工具可以在存在后消费同样的提供方自有 deadline 形状;`tools/execute` waterfall(瀑布式事件)中间件可以通过驱动 `exec.signal` 为每次工具调用设置默认 deadline——那将是一个*消费*本库的插件,仍然只做通知,硬终止仍是各能力自己的事。 ## 曾考虑的替代方案 -**统一的超时*插件* / `ctx.timeout` 服务。** 基于微内核理由否决。一个能停止任何工具工作的服务必须理解每个能力的终止机制(进程组 SIGKILL、socket 拆除、系统调用边界检查)——这正是架构所禁止的「内核知道太多」。Codex 的 `ExecExpiration` 作用域仅限于 exec 家族,正是因为它驱动的 kill(`killpg`)是进程家族特有的;MCP 和 model-stream 各自保有自己的。不存在一个连贯的中间层能为所有东西拥有终止权,因此共享部分只能是纯计时/分类那一半——一个库,而非服务。 +**统一的超时*插件* / `ctx.timeout` 服务。** 基于微内核原则否决。一个能停止任何工具工作的服务必须理解每个能力的终止机制(进程组 SIGKILL、socket 拆除、系统调用边界检查),这正是架构所禁止的「内核知道太多」。Codex 的 `ExecExpiration` 被限定于 exec 族,正是因为它驱动的 kill(`killpg`)是进程族特有的;MCP 和 model-stream 各自保有自己的。不存在一个连贯的中间层能为所有东西拥有终止权,因此共享部分只能是纯计时/分类那一半——一个库,而非服务。 -**每个工具各自实现超时,不共享代码(之前的现状,也是 Claude Code 的选择)。** 否决,因为它已经在产生分化和重复的正确性负担:web_fetch 手工搭建的 controller/reason 逻辑正是未来每个网络/进程工具都要重新推导的,而融合 + `signal.reason` 恢复是容易出错的部分。Claude Code 容忍完全重复;本仓库有一条统一的共享中止通道(每次 `execute` 上的 `exec.signal`),使一个小型共享原语严格更干净,因此成本/收益不同。 +**每个工具各自实现超时,不共享代码(先前的现状,也是 Claude Code 的选择)。** 否决,因为它已经在产生分化和重复的正确性负担:web_fetch 手写了与未来网络/进程类工具各自需要重新推导的完全相同的 controller/reason 逻辑,而融合 + `signal.reason` 恢复正是容易出错的部分。Claude Code 容忍完全重复;本仓库有一个统一的共享 abort 通道(每次 `execute` 上的 `exec.signal`),使得一个小型共享原语严格更优,因此成本/收益不同。 -**用 `withTimeout(promise, ms)` 包装器代替信号工厂。** 否决,因为让 promise 与定时器竞争只是在 deadline 时 resolve *工具调用*的 promise,而不停止底层工作——子进程或 fetch socket 会泄漏。发出信号并要求能力去监听,才能强制一条真正的终止路径存在。这与「dispose 必须达到静止态,而非仅仅请求它」的防御性规则一致。 +**用 `withTimeout(promise, ms)` 包装器代替信号工厂。** 否决,因为让 promise 与定时器竞争只是在截止时间到达时 resolve *工具调用*的 promise,而不会停止底层工作——子进程或 fetch socket 会泄漏。分发信号并要求能力监听,才能强制一条真实的终止路径存在。这与「dispose 必须达到静止状态,而非仅仅请求它」的防御性规则一致。 -**保留 bash 独立的超时和取消触发器。** 否决,因为一个 deadline 信号移除了自建定时器并标准化了分类。竞争的原因报告先到达的那个 abort,而既有的 SIGTERM→SIGKILL 终止路径不变。 +**保留 bash 独立的超时和取消触发器。** 否决,因为一个 deadline 信号移除了定制定时器并标准化了分类。竞争的原因报告先到达的那个 abort,而既有的 SIGTERM→SIGKILL 终止路径保持不变。 diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml index 36a4652f26..31025407be 100644 --- a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-07-tool-call-timeout-policy.md: 0e69c8504dd34dfc4427bf1f3865a80be93eff9d -2026-07-07-tool-call-timeout-policy.zh.md: d842d0a3c811e7502f4d45baba49010a06c5f1a5 +2026-07-07-tool-call-timeout-policy.zh.md: 2f4eca6eff9d135aad3fe538b887402a42ac6f84 diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md index d842d0a3c8..2f4eca6eff 100644 --- a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md @@ -1,24 +1,24 @@ # RFC:工具调用超时策略作为插件 -Status: implemented - [English](2026-07-07-tool-call-timeout-policy.md) | 中文 +Status: implemented + ## 问题 -[超时/截止时间 RFC](2026-07-06-timeout-deadline-library.md) 将计时与分类原语提取到了 `@deepseek-ai/dsh-timeout`,但超时策略仍然附着在各个能力和面向模型的 schema 上。`bash` 暴露了 `timeoutMs`;`web_fetch` 暴露了 `timeout_ms`;`web_search` 没有面向模型的超时参数,尽管提供方已经遵守 `exec.signal`;未来的 grep/glob 工具要么直接导入超时库,要么自行发明超时策略。对于一个插件 SDK 来说,这是错误的编写形态:工具作者通常只需将 `exec.signal` 转发给所调用的实现,而部署策略来决定预算。 +[超时/截止时间 RFC](2026-07-06-timeout-deadline-library.md) 将计时与分类原语提取到了 `@deepseek-ai/dsh-timeout`,但超时策略仍然附着在各个能力和面向模型的 schema 上。`bash` 暴露了 `timeoutMs`;`web_fetch` 暴露了 `timeout_ms`;`web_search` 没有面向模型的超时参数,尽管提供方已经遵循 `exec.signal`;未来的 grep/glob 工具要么直接导入超时库,要么自行发明超时策略。对于一个插件 SDK 来说,这是错误的编写范式:工具作者通常只需将 `exec.signal` 转发给其调用的实现,而部署策略来决定预算。 -与此同时,仓库中并非所有超时都是面向模型的工具调用预算。钩子通过直接调用 `ctx.bash` 来执行命令钩子,而非通过 `ctx.tools.execute()`;`bash` 模型工具通过同一后端复用了前台执行、后台启动、后台轮询和钩子调用。一步到位地把所有超时都移入工具插件会混淆这些路径,并有破坏钩子超时语义的风险。 +与此同时,仓库中并非所有超时都是面向模型的工具调用预算。钩子通过直接调用 `ctx.bash` 执行命令钩子,而非通过 `ctx.tools.execute()`;`bash` 模型工具通过同一个后端复用前台执行、后台启动、后台轮询和钩子调用。一步到位地将所有超时移入工具插件会混淆这些路径,并有破坏钩子超时语义的风险。 ## 决策 -工具调用超时是一项仅适用于面向模型的工具执行的策略,由三部分组成: +工具调用超时是仅适用于面向模型的工具执行的策略,由三部分组成: -- `@deepseek-ai/dsh-timeout` 仍然是拥有 `deadline()` 和 `timeoutOf()` 的共享库。 +- `@deepseek-ai/dsh-timeout` 仍是拥有 `deadline()` 和 `timeoutOf()` 的共享库。 - `@deepseek-ai/dsh-tools` 在 `tools/pre-execute` 和 `tools/post-execute` 之间有一个环绕分发的 waterfall(瀑布式事件)`tools/execute`。 - `@deepseek-ai/dsh-timeout-policy` 从注册表读取每个工具声明的 `timeoutMs`,并通过派生新的 `exec.signal` 来包装有此声明的调用。 -执行流水线为: +执行流水线如下: ```text ctx.tools.execute(exec) @@ -30,17 +30,17 @@ ctx.tools.execute(exec) -> tools/post-execute ``` -默认行为是保守的:未声明 `timeoutMs` 的工具不会从该插件收到 `TOOL_TIMEOUT` 截止时间。 +默认行为是保守的:未声明 `timeoutMs` 的工具不会从该插件收到 `TOOL_TIMEOUT` 截止信号。 ### `tools/execute` 环绕 seam -`@deepseek-ai/dsh-tools` 声明了一个 `tools/execute` waterfall,其基础 `next()` 是「分发并规范化」的 thunk:即同一个内部 `try`/`catch`,它将抛出的工具错误(或未知工具错误)转换为 `isError` 的 `ToolExecutionResult`。监听器接收 `(exec, next)`:调用 `next()` 委托给分发(返回其结果,可选地包装),或返回替代结果以短路分发。整条流水线仍处于 `execute` 的外层 try/catch 之内,因此抛出异常的监听器会变成 `isError` 结果,永远不会导致轮次失败。 +`@deepseek-ai/dsh-tools` 声明了一个 `tools/execute` waterfall,其基础 `next()` 是带规范化的分发 thunk——即同一个内部 `try`/`catch`,将抛出的工具错误(或未知工具错误)转换为 `isError` 的 `ToolExecutionResult`。监听器接收 `(exec, next)`:调用 `next()` 委托给分发(返回其结果,可选地包装),或返回替代结果以短路分发。整个流水线仍位于 `execute` 的外层 try/catch 内,因此抛出异常的监听器会变成 `isError` 结果,而非轮次失败。 -catch 是基础 `next()` 而非 waterfall 之外的东西,这一点是关键:当提供方看到超时信号并抛出自己的上游中止错误时,注册表分发首先将其转换为正常的错误结果,然后 `timeout-policy` 才能将最终结果替换为 `TOOL_TIMEOUT`。 +catch 是基础 `next()`(而非 waterfall 之外的东西)这一点至关重要:当提供方看到超时信号并抛出自己的上游中止错误时,注册表分发首先将其转换为普通错误结果,然后 `timeout-policy` 才能将最终结果替换为 `TOOL_TIMEOUT`。 ### `timeout-policy` 插件 -该插件是 `@deepseek-ai/dsh-timeout-policy`,位于 `packages/timeout/` 分组中,是一个零配置的函数/命名空间插件(`name` / `inject` / `apply`)。每个工具的预算声明在工具自身上,而非此插件上:`ToolDefinition` 携带可选的 `timeoutMs`,由拥有该工具的插件从自身配置中设置。例如 `dsh-tool-web` 将 `fetchTimeoutMs` / `searchTimeoutMs`(默认 30000)解析到 `web_fetch` / `web_search` 的定义上: +该插件是 `@deepseek-ai/dsh-timeout-policy`,一个零配置的函数/命名空间插件(`name` / `inject` / `apply`),位于 `packages/timeout/` 组。每个工具的预算声明在工具自身,而非本插件:`ToolDefinition` 携带一个可选的 `timeoutMs`,由拥有该工具的插件从自身配置中设置。例如 `dsh-tool-web` 将 `fetchTimeoutMs` / `searchTimeoutMs`(默认 30000)解析到 `web_fetch` / `web_search` 的定义上: ```yaml - id: timeout-policy @@ -52,11 +52,11 @@ catch 是基础 `next()` 而非 waterfall 之外的东西,这一点是关键 searchTimeoutMs: 30000 ``` -超时声明在工具定义上而非自由文本的名称映射中,消除了拼错名称导致策略不生效的问题。`defineTool` 会校验预算为正有限数。分发期间,执行器派生截止时间信号,之后恢复调用方信号,并将自身的超时转换为 `TOOL_TIMEOUT`;没有预算的工具原样通过。 +超时放在工具定义上而非自由文本名称映射中,消除了拼错名称导致策略不生效的问题。`defineTool` 校验预算为正有限数。分发期间,执行器派生截止信号,之后恢复调用方信号,并将自身的超时转换为 `TOOL_TIMEOUT`;没有预算的工具原样通过。 -信号替换采用**就地修改 `exec.signal`** 的方式,而非向 `next()` 传递新对象。Cordis 的 waterfall `next()` 忽略传入的参数,使用共享的 payload 数组重新调用下游监听器(`vendor/cordis/src/events.ts`),因此 Cordis 的文档惯用法——修改共享对象再委托——是唯一能到达分发的机制。插件在 `finally` 中将 `exec.signal` 恢复为调用方的原始信号,使 `tools/post-execute` 永远不会看到此插件的(可能已中止的)截止时间信号。 +信号替换采用**就地修改 `exec.signal`** 的方式,而非向 `next()` 传递新对象。Cordis 的 waterfall `next()` 忽略传入的任何参数,并以共享的 payload 数组重新调用下游监听器(`vendor/cordis/src/events.ts`),因此 Cordis 的惯用方式——修改共享对象再委托——是唯一能到达分发的机制。插件在 `finally` 中将 `exec.signal` 恢复为调用方的原始值,使 `tools/post-execute` 永远不会看到本插件的(可能已中止的)截止信号。 -`timeout-policy` 拥有 `TOOL_TIMEOUT` 代码的两种用途:传递给 `deadline()`/`timeoutOf()` 的内部截止时间代码(作用域化,使嵌套的外层截止时间读取为普通取消),以及结构化工具结果的错误代码。其替换结果为: +`timeout-policy` 拥有 `TOOL_TIMEOUT` 代码的两种用途:传递给 `deadline()`/`timeoutOf()` 的内部截止代码(有作用域,使嵌套的外层截止读为普通取消)和结构化工具结果错误代码。其替换结果为: ```ts ignore-check function toolTimeoutResult(timeoutMs: number): ToolExecutionResult { @@ -68,44 +68,44 @@ function toolTimeoutResult(timeoutMs: number): ToolExecutionResult { } ``` -这是一个协作式截止时间。它不会通过与工具 promise 竞速来杀死任意工作;工具或其调用的能力必须遵守 `exec.signal` 并达到静止状态。因此声明 `timeoutMs` 的含义是「此工具对 `exec.signal` 是协作式的」,插件 README 将此作为契约声明。 +这是一个协作式截止。它不会通过竞争工具 promise 来杀死任意工作;工具或其调用的能力必须遵循 `exec.signal` 并达到静止状态。因此声明 `timeoutMs` 意味着「此工具与 `exec.signal` 协作」,插件 README 将此作为其契约。 -可重建性不需要新的会话事件:`TOOL_TIMEOUT` 就是该调用最终面向模型的 `tool/result`,因此现有会话日志已经记录了下一次模型请求所看到的内容和结构化 `{ name, code }` 错误。 +无需新的会话事件来保证可重建性:`TOOL_TIMEOUT` 是该调用的最终面向模型的 `tool/result`,因此现有会话日志已经记录了下一次模型请求所见的内容和结构化 `{ name, code }` 错误。 ### 现有工具适配 -`web_fetch` 和 `web_search` 已迁移。`dsh-tool-web` 保留对其面向模型 schema 的所有权,这些 schema 不暴露超时旋钮:`web_fetch` 移除了 `timeout_ms` 参数以匹配参考 agent 的形态,`web_search` 保持仅查询。工具体不导入 `@deepseek-ai/dsh-timeout`;它们将 `exec.signal` 转发给 `ctx.web`。 +`web_fetch` 和 `web_search` 已迁移。`dsh-tool-web` 保留对其面向模型 schema 的所有权,这些 schema 不暴露超时旋钮:`web_fetch` 移除了 `timeout_ms` 参数以匹配参考 agent 的形状,`web_search` 保持仅查询。工具体不导入 `@deepseek-ai/dsh-timeout`;它们将 `exec.signal` 转发给 `ctx.web`。 -`dsh-web-fetch-local` 保留一个配置的提供方级 `timeoutMs`,作为直接调用 `ctx.web.fetch()` 的调用方和配置错误部署的大资源兜底;它不拥有面向模型的超时。当 `TOOL_TIMEOUT` 信号先到达 fetch 提供方时,提供方作用域的分类将其视为上游 `WEB_ABORTED`,外层 `tools/execute` 包装器将最终工具结果替换为 `TOOL_TIMEOUT`。已发布的 web 工具部署将提供方兜底配置为高于 `timeout-policy` 预算,使工具调用策略在模型调用中通常获胜。 +`dsh-web-fetch-local` 保留一个配置级别的 `timeoutMs` 作为大型资源兜底,服务于直接调用 `ctx.web.fetch()` 的调用方和配置错误的部署;它不拥有面向模型的超时。当 `TOOL_TIMEOUT` 信号先到达 fetch 提供方时,提供方作用域的分类将其视为上游 `WEB_ABORTED`,而外层 `tools/execute` 包装器将最终工具结果替换为 `TOOL_TIMEOUT`。一个已发布的 web 工具部署将提供方兜底配置为高于 `timeout-policy` 预算,使工具调用策略在模型调用中通常胜出。 `bash` 保持当前的后端超时路径。`dsh-tool-bash` 继续暴露 `timeoutMs` 和 `run_in_background`;`dsh-bash-local` 继续使用 `@deepseek-ai/dsh-timeout` 处理 `BASH_TIMEOUT`;钩子桥接继续调用 `runHook()` 并通过 `ctx.bash` 传递 `timeoutMs`。这保持了前台/后台/钩子行为的稳定。 -`read`、`write`、`edit`、`todo_write`、`bash_output` 和 `bash_kill` 不加入工具调用超时:它们是本地文件系统或短暂的注册表/会话操作,截止时间对它们要么只能尽力而为,要么没有必要。 +`read`、`write`、`edit`、`todo_write`、`bash_output` 和 `bash_kill` 不加入工具调用超时:它们是本地文件系统或短暂的注册表/会话操作,截止时间对它们而言要么只能尽力而为,要么没有必要。 -未来面向模型的 grep/glob 工具可以基于 `ctx.bash` 实现,无需导入 `@deepseek-ai/dsh-timeout`:它将 `exec.signal` 转发给 `ctx.bash`,并声明自己的 `timeoutMs`(来自其插件配置)供执行器应用。如果 bash-local 的后端超时对此类工具造成问题,bash seam 可以后续添加调用方拥有截止时间的模式;那不在本次范围内。 +未来面向模型的 grep/glob 工具可以基于 `ctx.bash` 实现而无需导入 `@deepseek-ai/dsh-timeout`:它将 `exec.signal` 转发给 `ctx.bash`,并声明自己的 `timeoutMs`(来自其插件配置)供执行器应用。如果 bash-local 的后端超时对这类工具造成问题,bash seam 可以后续添加调用方自有截止模式;这不在本次范围内。 ## 曾考虑的替代方案 -**将插件命名为 `tool-timeout`。** 字面的 RFC 名称匹配了 `gen-tool-catalog` 完整性守卫的 `packages/*/tool-*` glob,该守卫要求每个匹配项注册一个面向模型的工具。此插件不注册任何工具——它是 `tools/execute` 的包装器——因此 `tool-*` 名称要么导致 `verify-tool-catalog` 失败,要么强制一个误导性的启动条目。包名为 `@deepseek-ai/dsh-timeout-policy`,位于新的 `packages/timeout/` 分组;cordis.yml 的 `id` 仍可为 `timeout-policy`。 +**将插件命名为 `tool-timeout`。** 字面的 RFC 名称匹配了 `gen-tool-catalog` 完整性守卫的 `packages/*/tool-*` glob,该 glob 要求每个匹配项注册一个面向模型的工具。本插件不注册任何工具——它是一个 `tools/execute` 包装器——因此 `tool-*` 名称要么导致 `verify-tool-catalog` 失败,要么强制产生一个误导性的启动条目。包(package)为 `@deepseek-ai/dsh-timeout-policy`,位于新的 `packages/timeout/` 组;cordis.yml 的 `id` 仍可为 `timeout-policy`。 -**仅保留逐工具的超时处理。** 这是 `bash` 和 `web_fetch` 的原有形态,也与 Claude Code 和 Codex 对 shell 命令的做法一致。对 web 类工具而言它不够好,因为每个新的支持超时的工具都必须自行选择校验、上限语义、文档、快照和分类。插件集中了策略和分类,同时让每个工具的 schema 专注于业务输入。 +**仅保留逐工具的超时处理。** 这是 `bash` 和 `web_fetch` 的既有形态,也与 Claude Code 和 Codex 对 shell 命令的做法一致。它对 web 类工具不利,因为每个新的支持超时的工具都必须自行选择校验方式、上限语义、文档、快照和分类。插件集中了策略和分类,让每个工具的 schema 专注于业务输入。 -**立即将所有超时策略移出 bash-local。** 长期更干净:bash-local 将变为纯子进程执行器,所有调用方拥有自己的截止时间。作为第一步它不合适,因为钩子直接调用 `ctx.bash`,而 bash 模型工具有前台/后台语义,这与工具调用的生命周期不同。保留 `BASH_TIMEOUT` 维持了这些路径的稳定,同时工具调用超时在更简单的工具上验证自身。 +**立即将所有超时策略移出 bash-local。** 长期来看更干净——bash-local 将成为纯子进程执行器,所有调用方自行管理截止时间。但作为第一步不合适,因为钩子直接调用 `ctx.bash`,且 bash 模型工具的前台/后台语义与工具调用生命周期不同。保留 `BASH_TIMEOUT` 维持了这些路径的稳定,同时让工具调用超时在更简单的工具上先行验证。 -**为所有工具使用全局默认预算。** 方便,但会让工具作者意外:任何偶然运行超过全局预算的工具在插件加载后就会开始失败。逐工具声明的预算使采纳成为有意识的行为。 +**为所有工具使用全局默认预算。** 方便,但会让工具作者意外:任何偶然运行超过全局预算的工具在插件加载后就会开始失败。逐工具声明预算使采纳成为有意的行为。 -**暴露面向模型的 `timeout_ms` 覆盖参数。** Claude Code 的 `WebFetch`/`WebSearch` 和 Codex 的 web 工具将超时排除在模型调用形态之外。模型覆盖会使超时成为提示词语义的一部分,并迫使 `timeout-policy` 引入 schema/参数剥离规则。Web 超时仅作为部署策略。 +**暴露面向模型的 `timeout_ms` 覆盖参数。** Claude Code 的 `WebFetch`/`WebSearch` 和 Codex 的 web 工具将超时排除在模型调用形状之外。模型覆盖会使超时成为提示词语义的一部分,并迫使 `timeout-policy` 引入 schema/参数剥离规则。Web 超时仅作为部署策略。 -**让 `timeout-policy` 自行匹配工具参数。** 类似「当 `bash.run_in_background` 为 true 时禁用超时」的规则引擎会使策略插件了解工具特定的参数语义。通过不将 bash 迁移到工具调用超时来避免此问题。 +**让 `timeout-policy` 自行匹配工具参数。** 诸如「当 `bash.run_in_background` 为 true 时禁用超时」之类的规则引擎会让策略插件了解工具特定的参数语义。通过不将 bash 迁移到工具调用超时来规避此问题。 -**使用 `tools/pre-execute` 加 `tools/post-execute` 代替新的环绕 seam。** pre 监听器可以启动截止时间并修改 `exec.signal`;post 监听器可以分类并替换。这不可行,因为截止时间的生命周期将跨越两个独立的 waterfall:需要 call-id 映射、在每个 pre-deny/tool-throw/post-throw/dispose 路径上清理,以及与其他监听器的排序规则。`tools/pre-execute` 也是允许/拒绝门禁,而非执行包装器。`tools/execute` 给超时一个词法作用域:启动、委托、分类、释放。 +**使用 `tools/pre-execute` 加 `tools/post-execute` 代替新的环绕 seam。** pre 监听器可以启动截止时间并修改 `exec.signal`;post 监听器可以分类并替换。这样做的问题是截止时间的生命周期会跨越两个独立的 waterfall:需要 call-id 映射、在每条 pre-deny/tool-throw/post-throw/dispose 路径上清理,以及与其他监听器的排序规则。`tools/pre-execute` 也是允许/拒绝门禁,而非执行包装器。`tools/execute` 给超时一个词法作用域:启动、委托、分类、释放。 -**使用 `Promise.race` 为非协作式工具强制超时。** 否决,原因与超时库 RFC 相同:它在底层进程、fetch 或提供方操作可能仍在运行时就将控制权返回给调用方。插件只发送信号;终止仍是实现方的责任。 +**使用 `Promise.race` 对非协作工具强制超时。** 与超时库 RFC 相同的理由否决:它在底层进程、fetch 或提供方操作可能仍在运行时就将控制权返回给调用方。插件只发送信号;终止仍是实现方的责任。 ## 后果 -- `@deepseek-ai/dsh-tools` 在有意拆分 pre/post 工具钩子的拦截 seam 之后,获得了一个环绕分发的表面。其契约是窄的:包装注册表分发,而非替代 pre 门禁或 post 结果策略;基础 `next()` 是「分发并规范化」,因此包装器永远不会看到原始的工具抛出。 -- 多个 `tools/execute` 监听器通过普通的 Cordis waterfall 顺序组合:调用 `next()` 的监听器包装下游监听器加分发;不调用 `next()` 直接返回的监听器短路它们。组合超时与未来的重试/沙箱/指标包装器的部署通过注册顺序选择语义(「超时覆盖整个重试」vs「超时覆盖每次尝试」)。 -- 按声明加入是一个有意的配置错误风险:工具可以声明 `timeoutMs` 但不遵守 `exec.signal`,这样的工具在超时时不会停止。插件契约声明:声明预算意味着协作式;web 工具在已经转发信号的工具上证明了这一模式。 -- 过渡期间 `bash` 和已迁移的 web 工具有意使用不同的超时路径:`TOOL_TIMEOUT` 是面向模型的工具调用预算,而 `BASH_TIMEOUT` 仍然是 bash 和钩子使用的 bash 后端超时。 -- 与字面提案的偏差,按已实现 RFC 规则记录:插件包名为 `@deepseek-ai/dsh-timeout-policy`(而非 `tool-timeout`),信号替换是在 `next()` 之前就地修改 `exec.signal`(而非 `next({ ...exec, signal })`,Cordis 会忽略后者),逐工具预算声明在 `ToolDefinition` 上(`timeoutMs`,由拥有该工具的插件从其配置中设置)而非在此插件的配置中按工具名映射——因此执行器是零配置的,拼错工具名不可能发生。以上三点均在「## 决策」中描述。 +- `@deepseek-ai/dsh-tools` 在有意拆分 pre/post 工具钩子的拦截 seam 之后,获得了一个环绕分发的表面。其契约是狭窄的——包装注册表分发,而非替代 pre 门禁或 post 结果策略——且基础 `next()` 是带规范化的分发,因此包装器永远不会看到原始的工具抛出。 +- 多个 `tools/execute` 监听器按普通 Cordis waterfall 顺序组合:调用 `next()` 的监听器包装下游监听器加分发;不调用 `next()` 直接返回的监听器短路它们。一个同时组合超时与未来重试/沙箱/指标包装器的部署通过注册顺序选择语义(「超时覆盖整个重试」vs「超时覆盖每次尝试」)。 +- 按声明加入是一个有意的误配置风险:工具可以声明 `timeoutMs` 但不遵循 `exec.signal`,这样的工具在超时时不会停止。插件契约声明:声明预算意味着协作;web 工具在已转发信号的工具上验证了这一模式。 +- 过渡期间 `bash` 和已迁移的 web 工具有意使用不同的超时路径:`TOOL_TIMEOUT` 是面向模型的工具调用预算,而 `BASH_TIMEOUT` 仍是 bash 和钩子使用的 bash 后端超时。 +- 与字面提案的偏差,按 implemented-RFC 规则记录:插件包为 `@deepseek-ai/dsh-timeout-policy`(而非 `tool-timeout`);信号替换是在 `next()` 之前就地修改 `exec.signal`(而非 `next({ ...exec, signal })`,Cordis 会忽略后者);逐工具预算声明在 `ToolDefinition` 上(`timeoutMs`,由拥有该工具的插件从其配置中设置),而非在本插件配置中按工具名映射——因此执行器是零配置的,拼错工具名不可能发生。以上三点均在上文「决策」一节中描述。 diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml index 7f9d0625f3..3253751754 100644 --- a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-08-agent-scope-contexts.md: f238d58d90413d36e81b34c1a2c94e1291e889de -2026-07-08-agent-scope-contexts.zh.md: dfade19709ccbf206054f414882ecff114ac1e44 +2026-07-08-agent-scope-contexts.zh.md: 0f4de12e782fc72d3761b6d46cd953ab4650654d diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md index dfade19709..0f4de12e78 100644 --- a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md @@ -6,25 +6,25 @@ Status: implemented ## 问题 -一个应用需要在多个 agent(智能体)之间共享基础设施,同时让每个 agent 拥有自己的工具、prompt 贡献、策略和监听器。共享的适配器、持久化和用户界面属于部署层面;而一个人设、工具变体或监听器往往只属于某一个 agent。 +一个应用需要在多个 agent(智能体)之间共享基础设施,同时让每个 agent 拥有自己的工具、提示词贡献、策略和监听器。共享的适配器、持久化和用户界面属于部署层面;而 persona、工具变体或监听器往往只属于某一个 agent。 -为每个 agent 建立独立的服务图会重复共享基础设施。一个全局注册图则有相反的问题:某个 agent 的专属贡献可能泄漏到无关的 agent 中。贡献者需要一种普通的注册机制,既能决定谁能看到一项贡献,又能决定何时清理它。 +为每个 agent 建立独立的服务图会重复共享基础设施。使用一个全局注册图则有相反的问题:某个 agent 特有的贡献可能泄漏到无关的 agent 中。贡献者需要一种普通的注册机制,既能决定谁可以看到某项贡献,又能决定何时清理它。 -该机制还需要一个发布边界。agent 在其本地世界完整之前不得变为可见,而拆除过程必须保留该世界直到最终工作停止。 +该机制还需要一个发布边界。agent 在其本地世界构建完成之前不得变为可见,拆除时也必须保留该本地世界直到最终工作停止。 ## 决策 -每个存活的 agent 拥有一个扁平的注册层,通过 `agent.ctx` 暴露。代码通过拥有该贡献的上下文进行注册;感知作用域的服务将部署全局注册与恰好一个匹配的 agent 层组合;操作从其真实 agent 选择该层;该层在 agent 完整的已发布生命周期内存在。 +每个存活的 agent 拥有一个扁平的注册层,通过 `agent.ctx` 暴露。代码通过拥有某项贡献的 context 进行注册;具备作用域感知的服务将部署全局注册与恰好一个匹配的 agent 层合并;操作从其真实 agent 选择该层;该层在 agent 的完整发布生命周期内存在。 -Cordis 是 SDK 底层的插件框架。Cordis **上下文(context)** 是插件用来访问服务和注册效果的对象,效果的清理跟随该上下文。[Cordis 入门](../../../cordis-primer.md)对框架有更详细的说明。 +Cordis 是 SDK 底层的插件框架。Cordis **context** 是插件用来访问服务和注册效果的对象,效果的清理跟随该 context。[Cordis 入门](../../../cordis-primer.md)对该框架有更详细的说明。 -对大多数贡献者而言,完整的契约是四条规则: +对大多数贡献者而言,完整契约是四条规则: | 问题 | 规则 | |---|---| -| 在哪里为某个 agent 注册行为? | 通过 `agent.ctx` 调用普通的注册 API | -| 某个 agent 的操作能看到什么? | 部署全局加上该 agent 的层,使用所属服务的合并规则 | -| 哪些作用域监听器会运行? | 无作用域监听器加上为该操作的 agent 注册的监听器 | +| 在哪里为某个 agent 注册行为? | 通过 `agent.ctx` 调用普通注册 API | +| 某个 agent 的操作能看到什么? | 部署全局加上该 agent 的层,按所属服务的合并规则 | +| 哪些作用域监听器会运行? | 无作用域监听器加上为该操作所属 agent 注册的监听器 | | 该层存在多久? | setup 在发布前完成;dispose 保留该层直到工作达到静止 | 作用域是扁平的。解析永远不会遍历父级或兄弟作用域,生命周期所有权也不意味着注册继承。 @@ -43,20 +43,20 @@ flowchart LR agentBLayer --> agentBView ``` -缺失的交叉边就是隔离规则:Agent A 的本地注册不会进入 Agent B 的视图,父级的注册也不会仅因为父级拥有子级的生命周期就进入子级。 +缺失的交叉边即隔离规则:Agent A 的本地注册不会进入 Agent B 的视图,父级的注册也不会仅因父级拥有子级的生命周期就进入子级。 -配套的[运行时设计 RFC](2026-07-12-agent-scope-runtime-design.md) 解释了实现与正确性推理。[subagent 组合控制 RFC](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 拥有独立的 `persona`、`toolFilter` 和 `maxDepth` 功能。 +配套的[运行时设计 RFC](2026-07-12-agent-scope-runtime-design.md) 阐述了实现与正确性推理。[subagent 组合控制 RFC](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 负责独立的 `persona`、`toolFilter` 和 `maxDepth` 功能。 ### 注册来源决定可见性与清理 -通过普通插件上下文进行的注册是部署全局的,随该插件 dispose。同一方法通过 `agent.ctx` 调用则贡献给一个 agent,随该 agent 的作用域 dispose。 +通过普通插件 context 进行的注册是部署全局的,随该插件一起 dispose(资源释放)。同一方法通过 `agent.ctx` 调用则贡献给一个 agent,随该 agent 的作用域一起 dispose。 | 注册来源 | 默认可见性 | 随谁 dispose | |---|---|---| -| 普通插件上下文 | 每个符合条件的 agent 视图 | 注册插件 | +| 普通插件 context | 每个符合条件的 agent 视图 | 注册插件 | | `agent.ctx` | 仅该 agent 的视图 | agent 作用域 | -工具、prompt 段落与变量、工具限制、守卫和作用域事件监听器都采用此契约。同名的本地值通常对该 agent 遮蔽同名的全局值;每个所属服务自行记录例外与合并行为。 +工具、提示词段落与变量、工具限制、守卫以及作用域事件监听器都遵循此契约。命名的本地值通常对该 agent 遮蔽同名全局值;各所属服务文档会说明例外与合并行为。 普通贡献者的模式是在 agent setup 期间注册完整的本地世界: @@ -89,35 +89,35 @@ await handle.dispose() ctx.tools.get('review_summary', handle.agent) // undefined: scope is gone ``` -setup 接收一个完整的受信 Cordis 上下文,因此可以组合普通的插件和服务。其契约仅限组合:通过强制转换或内部注册表调用来驱动或发布正在构建的 agent 是不受支持的。 +setup 接收一个完整的受信 Cordis context,因此可以组合普通插件和服务。其契约仅限组合:不支持通过 cast 或内部注册表调用来驱动或发布正在构建中的 agent。 ### 操作选择视图 注册来源与操作主体是两个独立的事实。通过 `agent.ctx` 调用服务决定的是新注册归属何处,并不将后续读取绑定到该 agent。 -工具查找与执行接收其服务的 agent。prompt 组装接收正在构建请求的 agent 的组装上下文。事件分发接收其领域主体。这使共享服务实例可在多个 agent 间复用,同时让每个操作的视图保持显式。 +工具查找与执行接收其所服务的 agent。提示词组装接收正在构建请求的 agent 的组装上下文。事件分发接收其领域主体。这使共享服务实例可在多个 agent 间复用,同时让每个操作的视图保持显式。 只有采纳了作用域契约的服务才会解析 agent 层。`agent.ctx` 不会自动改变任意 Cordis 服务调用的行为。 ### 作用域事件将路由与事件数据分离 -关于 Agent A 的事件通常到达无作用域监听器和 A 作用域监听器,而不到达 B 作用域监听器。没有 agent 主体的事件只到达无作用域监听器。 +关于 Agent A 的事件通常到达无作用域监听器和 A 作用域监听器,而不到达 B 作用域监听器。没有 agent 主体的事件仅到达无作用域监听器。 在 Cordis 层面,`Scoped<T>` 是一个不透明的路由接收器。它携带用于选择监听器的过滤器,但本身不是领域对象。因此事件签名将真实的 `Agent`、工具执行、审批请求或其他主体作为显式参数保留,供监听器检查。 -以 `{ global: true }` 注册的监听器有意绕过上下文受众过滤,但其清理仍跟随注册上下文。注册表成员变更通知保持不过滤,因为它们描述的是共享注册表状态而非某个 agent 的操作。生成的[事件目录](../../../cordis-catalog/events.md)是详尽的事件参考。 +以 `{ global: true }` 注册的监听器有意绕过上下文受众过滤,但其清理仍跟随注册 context。注册表成员变更通知保持不过滤,因为它们描述的是共享注册表状态而非某个 agent 的操作。生成的[事件目录](../../../cordis-catalog/events.md)是详尽的事件参考。 ### 创建最后发布,dispose 最后撤销 `ctx.agents.create()` 和 `resume()` 构建未发布的会话、作用域、agent 和驱动器。它们等待 `setup`,准入最终的会话和 agent 条目,按序公告,启动循环,然后才返回 handle。 -可选的创建信号仅在 create 或 resume 挂起期间取消工作。promise resolve 后,返回的 `AgentHandle` 拥有显式的 dispose 权。 +可选的创建信号仅在 create 或 resume 挂起期间取消工作。promise resolve 后,返回的 `AgentHandle` 拥有显式 dispose 权。 -如果加载、setup、准入或发布失败,私有事务回滚其准备的一切。使用同一调用方提供的存活 ID 的并发操作可能都到达 setup,但最终注册表条目只准入一个;所有失败者拒绝并清理其私有资源。在等待 dispose 完成后的顺序复用仍然有效。 +如果加载、setup、准入或发布失败,私有事务回滚其准备的一切。使用同一个调用方提供的存活 ID 的并发操作可能都到达 setup,但最终注册表条目只准入一个;每个失败者拒绝并清理其私有资源。在等待 dispose 完成后的顺序复用仍然有效。 -`AgentHandle.dispose()` 反转边界。它停用创建或驱动,等待同步发布解除,停止并排空驱动器和最终会话刷新,分离 agent 和会话,最后 dispose 作用域。重复或竞争的 dispose 请求合并为一个完成 promise。 +`AgentHandle.dispose()` 反转边界。它停用创建或驱动,等待同步发布解除,停止并排空驱动器和最终会话刷写,分离 agent 和会话,最后 dispose 作用域。重复或竞争的 dispose 请求合并为一个完成 promise。 -调用方的 Cordis 上下文和具体的 AgentLoop 工厂是结构性共同所有者。卸载任一方都会 dispose 事务或存活 agent。 +调用方的 Cordis context 和具体的 AgentLoop 工厂是结构性共同所有者。卸载任一方都会 dispose 事务或存活 agent。 ```mermaid flowchart TB @@ -139,25 +139,25 @@ flowchart TB ## 安全与权限是非目标 -agent 作用域组合的是受信的同进程注册。它不沙箱化插件,不定义父到子的权限格,不在创建时冻结授权,也不保证子级不能做超出父级的事。 +agent 作用域组合的是受信的同进程注册。它不沙箱化插件、不定义父到子的权限格、不在创建时冻结授权、也不保证子级不能做超出父级的事。 -父级可以拥有一个可见工具比自身更宽的子级,因为生命周期所有权不捐赠也不封顶注册。持有 Cordis 上下文的插件同样运行在同一进程中,可以直接调用可用服务。 +父级可以拥有一个可见工具比自身更广的子级,因为生命周期所有权不赠予也不限制注册。持有 Cordis context 的插件同样运行在同一进程中,可以直接调用可用服务。 -需要非升级保证的部署需要独立的权限表示、传播规则和执行检查。父集合授权、创建时授权快照、显式的未来授权 API、以及通用的能力/输出/终止标签均不在本决策范围内。 +需要非升权保证的部署需要独立的权限表示、传播规则和执行检查。父集合授权、创建时授权快照、显式未来授权 API,以及通用的能力/输出/终止标签均不在本决策范围内。 ## 曾考虑的替代方案 -被否决的设计要么将可见性与清理分离,要么只覆盖一个注册族,要么重复共享基础设施,要么将生命周期所有权与继承混为一谈。 +被否决的设计要么将可见性与清理分离,要么只覆盖一类注册,要么重复共享基础设施,要么将生命周期所有权与继承混为一谈。 -### 向每次注册传递 agent 选项 +### 向每个注册传递 agent 选项 -类似 `tools.register(definition, { agent })` 的 API 在每个注册表中重复作用域管道,并允许可见性所有权与清理所有权漂移。通过 `agent.ctx` 注册使两个事实跟随同一个 Cordis 效果所有者。 +类似 `tools.register(definition, { agent })` 的 API 在每个注册表中重复作用域管道,且允许可见性所有权与清理所有权漂移。通过 `agent.ctx` 注册使两个事实跟随同一个 Cordis effect owner。 ### 过滤事件但保持注册表全局 -监听器过滤能阻止错误的钩子运行,但无法限定工具 schema、可执行查找、prompt 段落、变量或其他已注册数据的作用域。agent 本地组合仍需临时的全局变更。 +监听器过滤可以阻止错误的钩子运行,但无法限定工具 schema、可执行查找、提示词段落、变量或其他已注册数据的作用域。agent 本地组合仍需临时的全局变更。 -### 为每个 agent 创建一个服务图 +### 为每个 agent 创建独立的服务图 所需的视图是共享部署服务加上一个本地注册层。每 agent 一个图会重复适配器,并使共享持久化、提供方注册表和应用启动复杂化。 @@ -167,6 +167,6 @@ agent 作用域组合的是受信的同进程注册。它不沙箱化插件, ## 后果 -贡献者使用一种熟悉的模式:通过插件上下文注册共享行为,通过 `agent.ctx` 注册本地行为,在操作上选择真实 agent,dispose 返回的 handle。从观察者角度看 setup 是原子的,teardown 保留本地行为直到工作停止。 +贡献者使用一种熟悉的模式:通过插件 context 注册共享行为,通过 `agent.ctx` 注册本地行为,在操作中选择真实 agent,dispose 返回的 handle。从观察者角度看 setup 是原子的,拆除则保留本地行为直到工作停止。 -代价是显式的主体选择、异步的编程式创建,以及服务需要逐个采纳作用域。扁平注册作用域有意不等于权限,subagent 组合控制作为独立功能存在,而非隐藏在作用域语义中。 +代价是显式的主体选择、异步的编程式创建,以及服务需要逐个采纳作用域。扁平注册作用域有意不等同于权限,subagent 组合控制作为独立功能存在,而非隐藏的作用域语义。 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml index c48d3db510..b0b2ec8727 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-14-acp-agent-client-protocol.md: 0bb2a2f2e307b8f23a3a9ca98edb2a2d3b5df0a8 -2026-06-14-acp-agent-client-protocol.zh.md: 19744cb9f4d4b675586d4327a1da423fdea21b77 +2026-06-14-acp-agent-client-protocol.zh.md: 7bb0e066572150c9c8fc0b94de1d5bf2d69527ee diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md index 19744cb9f4..7bb0e06657 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md @@ -1,4 +1,4 @@ -# RFC:ACP(Agent Client Protocol)支持——从外部编辑器驱动编码 agent +# RFC:Agent Client Protocol(ACP)支持——从外部编辑器驱动编码 agent [English](2026-06-14-acp-agent-client-protocol.md) | 中文 @@ -6,54 +6,54 @@ Status: implemented ## 问题 -harness 最初只通过 readline 循环暴露 agent(智能体)。该接口能传输文本,但编辑器无法以结构化方式创建或恢复会话、关联 prompt 完成状态、流式输出推理(reasoning)与工具活动、渲染工具专属 UI、请求权限,或在不干扰其他对话的情况下取消某个对话。ACP 将这些交互定义为基于 stdio 的 JSON-RPC,Zed 是用于做出具体兼容性决策的目标客户端。 +harness 最初仅通过 readline 循环暴露 agent。该接口能传输文本,但编辑器无法以结构化方式创建或恢复会话、关联 prompt 完成、流式输出推理(reasoning)与工具活动、渲染工具专属 UI、请求权限,或在不干扰其他对话的前提下取消某个对话。ACP(Agent Client Protocol)将这些交互定义为基于 stdio 的 JSON-RPC,Zed 是用于做出具体兼容性决策的目标客户端。 -桥接层必须保持 harness 既有的职责边界。它不能依赖具体的 agent loop(智能体循环)、绕过工具注册表、在编辑器中执行 shell 命令,或发明第二个会话真源。stdout 同时也是协议传输通道,因此任何意外的日志输出都会破坏连接。 +桥接层必须保持 harness 既有的所有权边界。它不能依赖具体的 agent loop(智能体循环),不能绕过工具注册表,不能在编辑器中执行 shell 命令,也不能发明第二个会话真源。stdout 同时也是协议传输通道,因此任何意外的日志输出都会破坏连接。 ## 决策 -`@deepseek-ai/dsh-acp` 是位于 `packages/ui/acp` 的 UI/客户端驱动插件。它使用 `@agentclientprotocol/sdk` 的 `AgentSideConnection`(基于 stdin/stdout),仅编程接口级服务:agent 创建/恢复工厂、会话持久化、工具注册表、用户交互,以及可选的审批/bash 能力。它不改变 agent loop,也不是能力 seam 的实现。 +`@deepseek-ai/dsh-acp` 是位于 `packages/ui/acp` 的 UI/客户端驱动插件。它使用 `@agentclientprotocol/sdk` 的 `AgentSideConnection`(基于 stdin/stdout),仅编排接口服务:agent 创建/恢复工厂、会话持久化、工具注册表、用户交互,以及可选的审批/bash 能力。它不修改 agent loop,也不是能力 seam 的实现。 桥接层实现以下稳定的会话路径: -- `initialize` 协商协议版本,声明支持 text 与 `resource_link` prompt,并声明 `loadSession`。 -- `session/new` 校验绝对路径 `cwd`,将其存入 `SessionHeader`,通过 `ctx.agents` 创建 agent,并返回组合支持的配置选项。 -- `session/load` 在构造 agent 之前,先用持久化元数据校验请求的 cwd;在异步恢复期间预留 id;将 user/assistant/tool 事件作为 ACP update 回放;并报告恢复后的 config-option fold。 -- `session/prompt` 接受 text 和 resource link,拒绝不支持或空的内容,每个会话只允许一个 in-flight prompt,并在该 prompt 所属的 `turn/end` 时结算。错误 turn 拒绝 RPC;其他关闭 turn 的原因通过一个全覆盖的 ACP stop-reason codec 映射。 +- `initialize` 协商协议版本,声明支持 text 与 `resource_link` 类型的 prompt,并声明 `loadSession` 能力。 +- `session/new` 校验绝对路径 `cwd`,将其存入 `SessionHeader`,通过 `ctx.agents` 创建 agent,并返回由组合层支持的配置选项。 +- `session/load` 在构造 agent 之前校验请求的 cwd 与持久化元数据是否一致,在异步恢复期间保留 id,将用户/助手/工具事件作为 ACP update 回放,并报告恢复后的 config-option 折叠结果。 +- `session/prompt` 接受文本和 resource link,拒绝不支持的或空的内容,每个会话同时只允许一个 in-flight prompt,并在该 prompt 所属的 `turn/end` 时结算。错误轮次拒绝 RPC;其他关闭轮次的原因通过一个全覆盖的 ACP stop-reason 编解码器映射。 - `session/cancel` 调用队列感知的 agent 取消路径,仅结算被寻址会话的 prompt。 -工具调用的呈现仍由工具自身负责。工具的 `presentCall` 和 `presentResult` 返回 `generic`、`terminal` 或 `diff` 渲染意图变体;桥接层对该联合类型做 switch 并映射到 ACP。没有 presenter 的工具获得通用回退。Bash 终端卡片使用 Zed 的能力门控 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit` 约定;harness 仍通过 `ctx.bash` 执行命令,保留沙箱、环境变量清理、任务归属和 cwd。不支持该扩展的客户端收到普通文本内容。文件系统工具提供 diff 卡片和文件位置,桥接层中没有硬编码的工具名分支。 +工具调用的展示仍由工具自身负责。工具的 `presentCall` 和 `presentResult` 返回 `generic`、`terminal` 或 `diff` 渲染意图变体;桥接层对该联合类型做 switch 并映射到 ACP。没有 presenter 的工具获得通用回退。Bash 终端卡片使用 Zed 的能力门控约定 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit`;harness 仍通过 `ctx.bash` 执行命令,保留沙箱、环境清洗、所有权和 cwd。不支持该扩展的客户端收到普通文本内容。文件系统工具提供 diff 卡片和文件位置,桥接层中无需硬编码工具名分支。 -权限处理是[用户审批 seam](2026-07-06-approval-seam.md) 上的一个 answerer,而非 ACP 中「每次工具调用都询问」的策略。一个带有 call id 的、针对桥接层所属 agent 的 `approval/request`,会变成该 agent 编辑器会话上的 `session/request_permission`,提供一次性允许/拒绝选项。非本桥接层的请求或无 call id 的请求走委托路径;answerer 缺失或失败时保持 fail-closed。决定是否询问的插件(如预执行策略或 bash 升级)拥有「是否询问」的决策权。 +权限处理是 [user-approval seam](2026-07-06-approval-seam.md) 上的一个 answerer,而非 ACP 中的「每次工具调用都询问」策略。对桥接层所属 agent 且带有 call id 的 `approval/request`,会变为该 agent 编辑器会话上的 `session/request_permission`,提供一次性允许/拒绝选项。外部请求或无 call id 的请求委托给下游;缺失或失败的 answerer 保持 fail-closed。发起询问的插件(如预执行策略或 bash 升级)拥有「是否询问」的决策权。 -当 `ctx.permission` 被组合时,桥接层从部署的预设表中暴露一个 `permission` select。出厂的 `workspace-write` 和 `danger-full-access` 预设各自捆绑一个沙箱模式与一个审批策略;无法匹配的有效旋钮组合产生只能切走的 `custom` 状态。`session/set_config_option` 通过 `PermissionService.set()` 校验,并写入两个所属旋钮事件。在 open turn 期间的切换立即追加;idle 状态下的切换在响应中叠加,并在下一次 `agent/prompt-submit` 时锚定,位于请求组装之前。在此之前它仅存于内存,因此崩溃后恢复的是持久化的 fold。ACP session mode 不被建模,因为 config option 是面向未来的协议表面;`AcpConfig.model` 仍为连接级。 +当 `ctx.permission` 被组合时,桥接层从部署的预设表中暴露一个 `permission` select。已发布的 `workspace-write` 和 `danger-full-access` 预设各自捆绑一个沙箱模式与一条审批策略;无法匹配的有效旋钮组合产生只能切走的 `custom` 状态。`session/set_config_option` 通过 `PermissionService.set()` 校验并写入两个所属旋钮事件。在开放轮次中的切换立即追加;空闲时的切换叠加在响应中,并在下一次 `agent/prompt-submit` 时锚定到开放轮次之前的请求组装阶段。在此之前它仅存于内存,因此崩溃后恢复的是持久化的折叠结果。ACP session mode 不被建模,因为 config option 是面向未来的协议表面;`AcpConfig.model` 保持连接级别。 -桥接层还提供基于 ACP 的 `UserInteractionProvider`:`ask_user_question` 请求变为所属会话上的表单引导。select、multi-select、选项描述和自定义回答覆盖语义均被保留。 +桥接层还提供基于 ACP 的 `UserInteractionProvider`:`ask_user_question` 请求变为所属会话上的表单引导。select、multi-select、选项描述与自定义回答覆盖语义均被保留。 -生命周期归属是显式的。桥接层为每个活跃会话持有一个 `AgentHandle`。断连和 Cordis dispose(资源释放)会取消待处理的 prompt、并行 dispose 每个 handle、等待循环静默和持久化刷盘,然后移除记录。流式通知失败被隔离,已消失的客户端无法破坏 agent turn。ACP 应用组合不加载 stdout logger;一个测试守卫 stdout 仅包含帧化的 JSON-RPC。 +生命周期所有权是显式的。桥接层为每个活跃会话持有一个 `AgentHandle`。断连和 Cordis dispose(资源释放)会取消待处理的 prompt,并行 dispose 所有 handle,等待循环静默与持久化刷写,然后移除记录。流通知失败被隔离,因此消失的客户端不会破坏 agent 轮次。ACP 应用组合不加载 stdout logger;一个测试守卫 stdout 仅包含帧化的 JSON-RPC。 -精确的已支持与已推迟的协议行列表见 [`packages/ui/acp/acp-feature-support.md`](../../../../packages/ui/acp/acp-feature-support.md);package README 是运维契约。 +精确的已支持与已推迟的协议行列表见 [`packages/ui/acp/acp-feature-support.md`](../../../../packages/ui/acp/acp-feature-support.md);package README 是操作契约。 ## 曾考虑的替代方案 -**在 `tools/execute` 前置一个监听器,对每个 ACP 所属调用都询问权限**:否决。这会把权限策略硬编码进 UI 桥接层,即使没有策略要求也会询问,且无法服务执行开始后才产生的审批请求。共享的用户审批 seam 将机制、询问策略和 UI answerer 分离。 +**在 `tools/execute` 监听器前置一层,对每个 ACP 所属调用都询问权限**:否决。这会将权限策略硬编码到 UI 桥接层,即使没有策略要求也会询问,且无法服务于执行开始后才产生的审批请求。共享的 user-approval seam 将机制、询问策略和 UI answerer 分离。 -**注入具体的 `agentLoop`**:否决。agent 的创建、恢复、idle 观察和 dispose 是 `dsh-agent` 上的接口级归属操作;UI 插件不需要依赖规则的例外。 +**注入具体的 `agentLoop`**:否决。agent 的创建、恢复、空闲观察与释放是 `dsh-agent` 上的接口级所有权操作;UI 插件不需要依赖规则例外。 -**通过 ACP `terminal/*` 执行 bash**:否决。那会把执行移到 harness 之外,绕过其沙箱、凭证清理、任务归属、cwd 解析和会话日志。终端元数据仅用于呈现。 +**通过 ACP `terminal/*` 执行 bash**:否决。这会将执行移到 harness 之外,绕过其沙箱、凭证清洗、任务所有权、cwd 解析与会话日志。终端元数据仅用于展示。 -**将权限预设表示为 ACP session mode**:否决。部署定义的预设已经是一个 config-option select,而 session mode 是 ACP v2 计划移除的旧接口。 +**将权限预设表示为 ACP session mode**:否决。部署定义的预设已经是一个 config-option select,而 session mode 是 ACP v2 计划移除的遗留接口。 -**防御性劫持 stdout**:否决。进程级 monkey-patching 超出 Cordis 副作用归属范围,且与协议传输竞争。应用组合拥有 stdout 纯净性。 +**防御性劫持 stdout**:否决。进程级 monkey-patching 超出 Cordis 副作用所有权范围,且与协议传输存在竞争。应用组合拥有 stdout 纯净性。 ## 后果 -编辑器可以通过一条 ACP 连接创建、加载、prompt、取消、渲染、询问和重新配置多个 harness 会话,无需依赖特定的循环实现。会话事件日志仍是回放、prompt 结算、cwd 和每会话配置的持久真源。工具呈现与人工回答通道仍是可扩展的插件契约,而非 ACP 特有行为。 +编辑器可以通过一条 ACP 连接创建、加载、提交 prompt、取消、渲染、询问和重新配置多个 harness 会话,无需依赖特定的循环实现。会话事件日志仍是回放、prompt 结算、cwd 与每会话配置的持久真源。工具展示与人工回答通道仍是可扩展的插件契约,而非 ACP 专属行为。 -桥接层有意不实现会话列表/删除/恢复/关闭能力、MCP 透传、附加目录、图片/音频/嵌入资源 prompt、运行时模型选择、plan、斜杠命令、用量更新、编辑器文件系统委托,以及 ACP 终端执行子协议。功能清单将这些记录为不支持,而非静默接受。 +桥接层有意不实现会话列表/删除/恢复/关闭能力、MCP 透传、附加目录、图片/音频/嵌入资源 prompt、运行时模型选择、plan、斜杠命令、用量更新、编辑器文件系统委托或 ACP 终端执行子协议。功能清单将这些记录为不支持,而非静默接受。 -idle 状态下的 config 选择在实时响应中是真实的,但在下一次 `agent/prompt-submit` 将其锚定到 open turn 之前不具有持久性。在该边界之前崩溃会丢失待定选择;这是保持会话事件 turn 封闭且回放安全的代价。 +空闲时的配置选择在实时响应中是真实的,但在下一次 `agent/prompt-submit` 将其锚定到开放轮次之前不具持久性。在该边界之前崩溃会丢失待定选择;这是保持会话事件封闭于轮次内且回放安全的代价。 ## 验证 -ACP 测试套件覆盖内存协议编解码、创建/加载回放、精确的 prompt 结算、取消竞态、不支持的内容、工具呈现、终端能力回退、权限结果映射、config-option 校验与持久化、多会话隔离、断连/dispose 静默,以及 HMR(热模块替换)清理。快照和 built-bin 测试检验应用组合,真实 API 的 e2e 在无 key 时自动跳过。 +ACP 测试套件覆盖内存协议编解码器、创建/加载回放、精确的 prompt 结算、取消竞争、不支持的内容、工具展示、终端能力回退、权限结果映射、config-option 校验与持久化、多会话隔离、断连/释放静默,以及 HMR(热模块替换)清理。快照测试与 built-bin 测试验证应用组合,真实 API 的 e2e 测试在无 key 时自动跳过。 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml index 312106acaf..825e4c2ed8 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-14-acp-multi-session.md: b96557d2d94711adb2183aa4f5dd8debf39c1de8 -2026-06-14-acp-multi-session.zh.md: 263e292e7161b789b8e06772deb0d2bc896f8de6 +2026-06-14-acp-multi-session.zh.md: 6a9f5e8162d46ed8719164247e22b8b9c5d26c61 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md index 263e292e71..6a9f5e8162 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md @@ -1,39 +1,39 @@ -# RFC:在单连接上多路复用并发 ACP 会话 - -Status: implemented +# RFC:在单个连接上多路复用并发 ACP 会话 [English](2026-06-14-acp-multi-session.md) | 中文 +Status: implemented + ## 问题 -一个 ACP(Agent Client Protocol)编辑器可以在同一个 agent(智能体)子进程上维持多个活跃对话。如果桥接层只允许单活跃会话,就不得不额外启动进程,也无法匹配 Zed 的客户端模型——该模型跟踪多个 session id 和并发加载。多路复用引入了隔离风险:事件、prompt 完成、取消、权限提示、配置选择以及可预测的后台任务 id 都绝不能跨越会话边界。 +一个 ACP(Agent Client Protocol)编辑器可以在同一个 agent(智能体)子进程上保持多个对话。如果桥接层只支持单活跃会话,就不得不启动额外进程,也无法匹配 Zed 的客户端模型——该模型跟踪多个 session id 和并发加载。多路复用引入了隔离风险:事件、prompt 完成、取消、权限提示、配置选择以及可预测的后台 task id 绝不能跨越会话边界。 ## 决策 -ACP 桥接层将活跃会话存储在 `Map<SessionId, SessionRecord>` 中,并维护一个 `WeakMap<Agent, SessionId>` 反向索引,供 agent 作用域的回调使用。一条记录拥有其 agent 句柄、进行中的 prompt、活跃的工具调用展示状态、待生效的空闲配置切换、会话 cwd 以及客户端能力快照。一个独立的 loading-id 集合在异步恢复之前预留每个 id,使两个流水线化的加载请求无法构造重复的 agent;不同 id 可以并发加载。 +ACP 桥接层将活跃会话存储在 `Map<SessionId, SessionRecord>` 中,并维护一个 `WeakMap<Agent, SessionId>` 反向索引,用于 agent 作用域的回调。一条记录拥有其 agent 句柄、进行中的 prompt、活跃的工具调用展示状态、待处理的空闲配置切换、会话 cwd 以及客户端能力快照。一个独立的 loading-id 集合在异步恢复之前预留每个 id,使两个流水线化的加载请求无法构造出重复的 agent;不同 id 可以并发加载。 -每个 `session/event` 和 `agent/status` 回调在发送或结算任何内容之前,先解析出所属记录。每个会话独立允许一个进行中的 prompt。prompt 记录一个日志水位线,捕获自己的 `turn/start`,并仅在匹配的 `turn/end` 到来时结算;来自已取消的先前轮次的迟到 end 不能 resolve 更新的 prompt。`session/cancel` 定位到单条记录,只调用该 agent 的队列感知取消路径。 +每个 `session/event` 和 `agent/status` 回调在发送或结算任何内容之前,先解析出所属记录。每个会话独立允许一个进行中的 prompt。prompt 记录一个日志水位线,捕获自己的 `turn/start`,并仅在匹配的 `turn/end` 到达时结算;来自已取消的前一轮次的迟到 end 不能 resolve 更新的 prompt。`session/cancel` 定位到一条记录,只调用该 agent 的队列感知取消路径。 -权限归属使用同一个反向索引。ACP `approval/request` 应答器仅向拥有发起请求的 agent 的编辑器会话发起提示,并将外部请求委托出去。用户交互引出同样按 agent 归属路由。每会话的沙箱和审批配置值仅折叠该会话自身的事件,待生效的空闲切换存储在该记录上,直到下一个轮次将其锚定。 +权限归属使用同一个反向索引。ACP `approval/request` 应答器只向拥有发起请求的 agent 的编辑器会话发起提示,并将外部请求委托出去。用户交互引出同样按 agent 归属路由。每会话的沙箱和审批配置值只折叠该会话自身的事件,待处理的空闲切换存储在该记录上,直到下一轮次将其锚定。 -后台 bash 任务携带一个不透明的 owner token,其值等于所属会话的 session id。`bash_output` 和 `bash_kill` 在读取或终止之前,会将调用方的 token 与执行器的任务归属进行比较;仅凭可预测的 task id 不授予访问权限。归属信息存储在执行器任务上,因此工具插件重载不会擦除它。 +后台 bash 任务携带一个不透明的 owner token,其值等于所属会话 id。`bash_output` 和 `bash_kill` 在读取或终止之前,将调用方的 token 与执行器的任务归属进行比较;仅凭可预测的 task id 不能获得访问权。归属信息与执行器任务一起存储,因此工具插件重载不会擦除它。 -连接拆除时清空活跃 map,将每个待结算的 prompt 以取消状态结算,并并行 dispose 所有 `AgentHandle`。每个句柄停止并等待其循环结束,在仍挂载时刷新会话,注销 agent,然后移除会话。拆除操作被 memoize 并在客户端断开与插件 dispose 之间共享。 +连接拆除时清空活跃 map,将每个待处理的 prompt 以取消状态结算,并并行 dispose(资源释放)所有 `AgentHandle`。每个句柄停止并等待其循环完成、在仍然附着时刷新会话、注销 agent 并移除会话。拆除操作被 memoize 化,由客户端断连和插件 dispose 共享。 ## 曾考虑的替代方案 -**每连接单活跃会话**:否决。它增加进程开销,与目标客户端的多会话形态相矛盾,且并未消除编辑器端的多路复用需求。 +**每连接单活跃会话**:否决。增加进程开销,与目标客户端的多会话形态相矛盾,且并未消除编辑器端的多路复用需求。 -**每会话一个 `ctx.extend()`**:否决。子上下文本身并不创建子插件 fiber,因此监听器仍属于桥接层 fiber。实际实现的桥接层使用全局监听器加显式 O(1) 解复用,以及每会话的归属记录;agent 生命周期由 `AgentHandle` 拥有。 +**每会话 `ctx.extend()`**:否决。子上下文本身不会创建子插件 fiber,因此监听器仍属于桥接层 fiber。实际实现的桥接层使用全局监听器加显式 O(1) 解复用,以及每会话拥有的记录;agent 生命周期由 `AgentHandle` 管理。 -**以 agent 对象标识作为 bash 任务归属**:否决。恢复或替换后的 agent 对象可能合法地代表同一个持久会话。不透明的 session token 才是应当在插件重载后存活的跨边界标识。 +**以 Agent 对象标识作为 bash 任务归属**:否决。恢复或替换后的 agent 对象可能合法地代表同一个持久会话。不透明的 session token 才是跨边界的标识,应当在插件重载后仍然存活。 ## 后果 -N 个会话可以并发地进行流式输出、prompt、权限请求、配置切换和后台任务运行,而不会交错或跨会话结算。一个会话中的取消或 dispose 不影响相邻会话。桥接层为此付出了显式 map 和隔离测试的代价,但它不为每个会话添加一套监听器,因此在长连接期间避免了监听器扇出。 +N 个会话可以并发地进行流式输出、prompt、权限请求、配置切换和后台任务运行,而不会交错或跨会话结算。一个会话中的取消或 dispose 不影响相邻会话。桥接层为此付出了显式 map 和隔离测试的代价,但它不会为每个会话添加一组监听器,从而避免了长连接期间的监听器扇出。 -桥接层目前仍未暴露独立关闭单个活跃会话的协议方法。当前所有记录在连接拆除时一起离开;会话关闭/恢复的生命周期能力在 ACP 功能清单中仍处于推迟状态。 +桥接层目前仍未暴露独立关闭单个活跃会话的协议方法。当前所有记录在连接拆除时一起离开;会话关闭/恢复的生命周期能力在 ACP 功能清单中仍处于延期状态。 ## 验证 -多会话测试套件通过交错更新、独立的进行中 prompt、定向取消、相同 id 与不同 id 的加载竞争、权限路由、配置隔离和拆除来驱动并发会话。工具 bash 测试证明一个会话无法读取或终止另一个会话的后台任务。 +多会话测试套件通过交错更新、独立的进行中 prompt、定向取消、相同 id 与不同 id 的加载竞争、权限路由、配置隔离以及拆除来驱动并发会话。工具 bash 测试证明一个会话无法读取或终止另一个会话的后台任务。 diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml b/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml index b7e263a61a..5aeee85382 100644 --- a/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-15-code-mode.md: c64b6d6d8442e60240fa6c849833385ed50d71ff -2026-06-15-code-mode.zh.md: f94ef61dae180bad5ec604b5c7f9552eeecff593 +2026-06-15-code-mode.zh.md: e9ae74f6629f3e34a0e97f0fa532764c70095bba diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md b/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md index f94ef61dae..e9ae74f662 100644 --- a/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md @@ -1,132 +1,132 @@ # RFC:Code Mode——模型针对工具注册表编写 TypeScript -Status: implemented - [English](2026-06-15-code-mode.md) | 中文 +Status: implemented + ## 问题 -在注册表的原生呈现方式中,agent loop(智能体循环)将每个可见能力作为 JSON Schema 函数定义广播。`ToolRegistry` 将其 schema 贡献给系统提示词组装,组装结果中的 `tools` 落到协议格式(wire format)上(也记录在请求头日志中),模型每步调用一个 `tool-call` 块,循环通过 `ctx.tools.execute()` **逐个**分发每次调用(并行工具执行是 `dsh-tools` 和 [docs/architecture.md](../../../architecture.md) 中明确标注的 open TODO),且**每个**中间 `tool-result` 都在下一次请求时重新进入模型上下文。 +在注册表的原生呈现方式下,agent loop(智能体循环)将每个可见能力以 JSON Schema 函数定义的形式通告给模型。`ToolRegistry` 将其 schema 贡献给系统提示词组装,组装结果中的 `tools` 落到协议格式(wire format)上(也记录在请求头日志中),模型每步调用一个 `tool-call` 块,循环通过 `ctx.tools.execute()` **逐个**分发每次调用(并行工具执行是 `dsh-tools` 和 [docs/architecture.md](../../../architecture.md) 中明确标注的 open TODO),且**每一个**中间 `tool-result` 都会在下一次请求时重新进入模型上下文。 -对于多步工具操作,这种方式 token 开销大且串行。模型无法组合工具——遍历结果集、根据中间值分支、扇出、后处理——每次调用都需要一次完整的模型往返,而每次往返都把整个中间结果拖回上下文,无论模型是否需要。 +对于多步工具操作,这种方式 token 开销大且串行。模型无法组合工具——遍历结果集、根据中间值分支、扇出、后处理——每次调用都需要一次完整的模型往返,而每次往返都会把完整的中间结果拖回上下文,不管模型是否需要。 -Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一种替代方案,基于一个简单观察:LLM(大语言模型)写代码比发出工具调用更擅长,因为它们见过数百万行真实代码,而见过的人造工具调用 trace 相对很少。模型不再每步发出一个工具调用,而是针对工具生成的 API 编写一段 TypeScript 程序,程序在沙箱运行时中执行,模型只取回它打印或返回的内容——而非所有中间结果。 +Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一种替代方案,基于一个简单的观察:LLM(大语言模型)编写代码的能力优于发出工具调用,因为它们见过数百万行真实代码,而人为构造的工具调用 trace 相对很少。模型不再每步发出一次工具调用,而是针对工具生成的 API 编写一段 TypeScript 程序,程序在沙箱运行时中执行,模型只策展返回的内容——仅限它 print 或 return 的部分——而非所有中间结果。 -工具呈现属于拥有工具可见性的注册表:如果把第二种呈现方式实现为事后的 waterfall(瀑布式事件)变换,正确性将依赖监听器顺序,并与[可重建请求](../../implemented/architecture/2026-07-05-reconstructable-requests.md)冲突。执行基底同样属于基础设施而非占位符:Node `worker_threads` 提供独立隔离区、空环境、堆上限以及对热同步循环的终止能力,同时契合 harness 现有的信任模型(见§信任姿态)。 +工具呈现属于掌管工具可见性的注册表:如果把第二种呈现方式实现为事后的 waterfall(瀑布式事件)变换,正确性将依赖监听器顺序,并与[可重建请求](../../implemented/architecture/2026-07-05-reconstructable-requests.md)冲突。执行基底同样属于基础设施而非占位实现:Node `worker_threads` 提供独立 isolate、空环境、堆上限以及对热同步循环的终止能力,同时契合 harness 既有的信任模型(§信任姿态)。 ## 决策 三项决策,各自在下方独立小节中展开: -1. **Code Mode 是 `ToolRegistry`(`dsh-tools`)的一等呈现模式**,通过经过校验的 `mode` 配置选择:`'native'`(默认,贡献可见能力 schema)、`'code'`(注册表仅贡献其保留的 `run_code` 传输通道加一份生成的 SDK `.d.ts` 放入系统提示词)、或 `'both'`(原生 schema 加传输通道 + SDK)。注册表在源头塑造其规范贡献;协作式 prompt 组装的结果仍具权威性,请求头日志记录的正是该返回的呈现。 +1. **Code Mode 是 `ToolRegistry`(`dsh-tools`)的一等呈现模式**,通过经校验的 `mode` 配置选择:`'native'`(默认,贡献可见能力 schema)、`'code'`(注册表仅贡献其保留的 `run_code` 传输通道加一份生成的 SDK `.d.ts` 到系统提示词中)或 `'both'`(原生 schema 加传输通道 + SDK)。注册表在源头塑造其权威贡献;协作式 prompt 组装的结果仍具权威性,记录在日志中的请求头精确反映该返回的呈现。 2. **代码执行是一个能力 seam**——`packages/code-runtime/` 包含接口包 `@deepseek-ai/dsh-code-runtime`,拥有 `ctx.codeRuntime`([能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md);消费方 = `dsh-tools`,core 消费 seam 的先例见 `agent-loop` → `dsh-llm`)。运行时对工具一无所知:它接收一段程序和命名的异步绑定,执行程序,报告 `{ value, logs, error? }`。语言和基底是后端属性,因此未来的 Python 或容器后端只是另一个实现包,而非重新设计。 -3. **交付的实现是 `@deepseek-ai/dsh-code-runtime-worker`**:每次运行启动一个全新的 Node worker 线程,对模型的 TypeScript 进行 type-strip 后执行,绑定通过消息端口桥接,环境为空,堆/输出/时间上限可配置,并支持硬终止。其信任姿态在设计上等同于 bash——不需要 unsafe-acknowledgement 标志——因为 harness 已经提供了 `dsh-bash-local`,后者以严格**更大**的环境权限执行模型编写的任意 shell 命令。 +3. **交付的实现是 `@deepseek-ai/dsh-code-runtime-worker`**:每次运行 spawn 一个全新的 Node worker 线程,对模型的 TypeScript 进行 type-strip 后执行,绑定通过 message port 桥接,环境为空,堆/输出/时间上限可配置,并支持硬终止。其信任姿态在设计上等同于 bash——无需 unsafe-acknowledgement flag——因为 harness 已经交付了 `dsh-bash-local`,后者以严格**更高**的环境权限执行模型编写的任意 shell 命令。 ### 注册表拥有模式 -`ToolRegistry` 获得一个 schemastery 校验的配置(`static Config`),这是它的第一个配置:`mode: 'native' | 'code' | 'both'`,默认 `'native'`。部署通过 `cordis.yml` 切换(`tools: { mode: code }`)——无需改代码,遵循 no-hardcoded-tunables 约定。 +`ToolRegistry` 获得一个经 schemastery 校验的配置(`static Config`),这是它的第一个配置:`mode: 'native' | 'code' | 'both'`,默认 `'native'`。部署通过 `cordis.yml` 翻转模式(`tools: { mode: code }`),无需改代码,遵循 no-hardcoded-tunables 约定。 **协议工具列表。** 注册表在 `'native'` 下贡献可见能力,在 `'code'` 下仅贡献 `run_code`,在 `'both'` 下两者都贡献。最终的 `PromptAssembly.tools` 列表记录在请求头中。`run_code` 是一个保留的呈现传输通道,位于注册和限制层之外;直接 prompt 提供方和组装 waterfall 仍各自负责自己的贡献。 -**与 `toolOrder` 的交互,预先声明:** 如果配置的 `systemPrompt.toolOrder` 命名了原生能力,则在 `mode: 'code'` 下会拒绝所有组装,因为这些名称不在该模式的协议校验范围内。这是正确行为,不是 bug:使用 Code Mode 的部署需要更新其 order 配置或移除它。 +**与 `toolOrder` 的交互,预先说明:** 如果配置的 `systemPrompt.toolOrder` 引用了原生能力名称,在 `mode: 'code'` 下会拒绝所有组装,因为那些名称不在该模式的协议校验范围内。这是正确行为而非 bug:使用 Code Mode 的部署需要更新其 order 配置或移除它。 -**SDK prompt 段落。** 在 `'code'` 和 `'both'` 下,tool-guidance order band 中的惰性 `tools:sdk` 段落为作用域内可见能力渲染 TypeScript 声明加固定的使用说明。它共享查找和执行可见性,排除 `run_code`,并按字典序排列工具以获得字节稳定的输出。 +**SDK prompt 段。** 在 `'code'` 和 `'both'` 下,tool-guidance order band 中的惰性 `tools:sdk` 段为当前 scope 的可见能力渲染 TypeScript 声明加固定的使用说明。它共享查找和执行可见性,排除 `run_code`,并按字典序排列工具以获得字节稳定的输出。 -**组装所有权。** `run_code` 和 `tools:sdk` 作为正常的组装输入进入受信任的 `system-prompt/assemble` waterfall。作用域内的 `tools:sdk` 段落可以在分发前遮蔽全局默认值,监听器可以移除或替换任一贡献。waterfall 返回的组装结果是最终的,因此修改这些输入的人有责任在部署期望 Code Mode 可用时保持协议可行;没有恢复 pass 会覆盖有意的组合。 +**组装所有权。** `run_code` 和 `tools:sdk` 作为正常的组装输入进入受信任的 `system-prompt/assemble` waterfall。一个 scoped 的 `tools:sdk` 段可以在分发前遮蔽全局默认值,监听器也可以移除或替换任一贡献。waterfall 返回的组装结果是最终的,因此修改这些输入的人有责任在部署期望 Code Mode 可用时保持协议面的完整性;没有恢复 pass 会覆盖有意的组合。 -**代码生成。** `jsonSchemaToTs()` 将 `defineTool` 的 JSON Schema 子集映射为 TypeScript,将 schema 描述带入 JSDoc,并将不支持的构造降级为 `unknown`。SDK 以带引号的对象键暴露工具,支持任意名称而无需别名或冲突处理。类型是建议性的,因为运行时在执行前会剥离类型。 +**代码生成。** `jsonSchemaToTs()` 将 `defineTool` 的 JSON Schema 子集映射为 TypeScript,将 schema 描述带入 JSDoc,不支持的构造降级为 `unknown`。SDK 将工具暴露为带引号的对象键,支持任意名称而无需别名或冲突处理。类型是建议性的,因为运行时在执行前会剥离类型。 -### run_code 工具与分发桥接 +### run_code 工具与分发桥 -在 `'code'` 和 `'both'` 下,注册表拥有 `run_code` 作为保留的呈现传输通道,带一个必需参数 `{ code: string }`。它由一个正常的 `ToolDefinition` 表示以便分发,但位于可过滤的能力层之外,因此限制规则不会意外移除 Code Mode 的唯一入口。调用遍历完整的工具流水线——`tools/pre-execute` → 单调守卫 → `tools/execute` 包裹分发 → `tools/post-execute` → 不可变的 `tools/result` 通知——与原生调用完全一致;权限插件可以在程序运行前检查程序文本,最终结果观察者看到的是归一化的外层结果。其 `execute(args, exec)`: +在 `'code'` 和 `'both'` 下,注册表拥有 `run_code` 作为保留的呈现传输通道,带一个必需参数 `{ code: string }`。它由一个正常的 `ToolDefinition` 表示以供分发,但位于可过滤的能力层之外,因此限制规则不会意外移除 Code Mode 的唯一入口。调用遍历完整的工具流水线——`tools/pre-execute` → 单调守卫 → `tools/execute` 包裹分发 → `tools/post-execute` → 不可变的 `tools/result` 通知——与原生调用完全一致;权限插件可以在程序运行前检查程序文本,最终结果观察者看到的是规范化的外层结果。其 `execute(args, exec)`: -1. **构建绑定。** 一个 run 作用域的 signal 跟随外层取消,并在 run 结算时被 abort。每个可见工具绑定对其参数做 JSON 归一化——在分发前拒绝有损值——等待序列化队列,以确定性的 call id 和外层 token 作为 `parent` 执行,并记录 `tool/code-dispatch`。成功的文本变为字符串,非文本块变为占位符;工具错误使绑定 promise reject。每个子调用保留自己的不可变执行身份,并遍历完整的工具流水线。 -2. **运行程序**:`ctx.codeRuntime.run({ program: args.code, bindings: [{ global: 'tools', functions }], signal: runController.signal })`。运行时接收的是 run 作用域的 signal 而非仅调用方的外层 signal,因此外层 run 以任何方式结算都会同时 abort 运行时内部的工作。 -3. **静默后结算。** 运行时结算后,桥接 abort 未完成的工作并排空分发队列后再返回。成功时返回捕获的输出和呈现元数据。运行时失败变为 `CodeRunFailedError`;后端拒绝使用注册表的正常错误边界。两者都产生结构化的错误结果,且 `run_code` 结算后没有子调用可以追加。 +1. **构建绑定。** 一个 run 级别的 signal 跟随外层取消,并在 run 结算时被 abort。每个可见工具绑定对参数做 JSON 规范化——在分发前拒绝有损值——等待序列化队列,以确定性的 call id 和外层 token 作为 `parent` 执行,并记录 `tool/code-dispatch`。成功的文本变为字符串,非文本块变为占位符;工具错误使绑定 promise reject。每个子调用保留自己不可变的执行标识,并遍历完整的工具流水线。 +2. **运行程序**:`ctx.codeRuntime.run({ program: args.code, bindings: [{ global: 'tools', functions }], signal: runController.signal })`。运行时接收的是 run 级别的 signal 而非仅调用方的外层 signal,因此外层 run 以任何方式结算都会同时 abort 运行时内部的工作。 +3. **静默后结算。** 运行时结算后,桥 abort 未完成的工作并排空分发队列后再返回。成功时返回捕获的输出和呈现元数据。运行时失败变为 `CodeRunFailedError`;后端拒绝使用注册表的正常错误边界。两者都产生结构化的错误结果,且 `run_code` 结算后不允许子调用追加。 -**子调用的 `additionalContext` 被省略。** 在 `run_code` 期间注入它会破坏父调用/结果的邻接性,而一个程序可以产生多个上下文。支持它需要一个复数通道或循环级别的子分发缓冲区。 +**子调用的 `additionalContext` 被省略。** 在 `run_code` 期间注入它会破坏父调用/结果的相邻性,而一个程序可以产生多个 context。支持它需要一个复数通道或循环级别的子分发缓冲区。 -**并发被序列化。** 每次 run 拥有一个分发队列,因此即使 `Promise.all` 也按提交顺序执行工具调用。结算时放弃尚未开始的排队调用。并行化需要逐工具的并发安全元数据。 +**并发被序列化。** 每次 run 拥有一个分发队列,因此即使 `Promise.all` 也按提交顺序执行工具调用。结算时放弃尚未开始的排队调用。并行化需要每个工具的并发安全元数据。 -**呈现。** `run_code` 的渲染意图按 [render-intent RFC](../../implemented/architecture/2026-07-02-tool-render-intent-union.md) 在此决定:`presentCall` → 一个 `generic` 卡片,`kind: 'execute'`,title = 程序文本,`rawInput` = 同一段程序文本;`presentResult` → 一个 `generic` 卡片,内容为捕获的输出(来自 `meta`)。程序作为 title 是因为 ACP execute 卡片可靠地渲染该字段,而某些客户端会省略 body 和 raw-input 内容。这不是 `terminal` 卡片:该卡片的语义是「工作目录中的 shell 命令」,程序不是。 +**呈现。** `run_code` 的 render intent 按 [render-intent RFC](../../implemented/architecture/2026-07-02-tool-render-intent-union.md) 在此决定:`presentCall` → 一个 `generic` 卡片,`kind: 'execute'`,title = 程序文本,`rawInput` = 同一程序文本;`presentResult` → 一个 `generic` 卡片,content 为捕获的输出(来自 `meta`)。程序作为 title 是因为 ACP execute 卡片可靠地渲染该字段,而某些客户端会省略 body 和 raw-input 内容。这不是 `terminal` 卡片:该卡片的语义是「工作目录中的 shell 命令」,程序不是。 ### 可观测性:`tool/code-dispatch` -每次子分发追加一个仅日志的 `tool/code-dispatch` 事件,包含父子 call id、工具身份、归一化参数和结果摘要。它不进入模型历史,但可供持久化和 UI 使用。追加发生在打开的 `run_code` 轮次内。没有 agent 的直接执行仍然运行,但无法记录该事件。 +每次子分发追加一个仅日志的 `tool/code-dispatch` 事件,包含父子 call id、工具标识、规范化参数和结果摘要。它不进入模型历史,但可供持久化和 UI 使用。追加发生在开放的 `run_code` 轮次内。没有 agent 的直接执行仍然运行,但无法记录该事件。 ### code-runtime seam -`packages/code-runtime/code-runtime/`——`@deepseek-ai/dsh-code-runtime`,仅依赖 `cordis`。一个抽象的 `CodeRuntime extends Service`(`super(ctx, 'codeRuntime')`)加词汇: +`packages/code-runtime/code-runtime/`——`@deepseek-ai/dsh-code-runtime`,仅依赖 `cordis`。一个抽象的 `CodeRuntime extends Service`(`super(ctx, 'codeRuntime')`)加上词汇: - `CodeRunRequest = { program: string; bindings: CodeBindingNamespace[]; signal?: AbortSignal }` - `CodeBindingNamespace = { global: string; functions: Record<string, (args: unknown) => Promise<unknown>> }`——运行时将每个命名空间作为程序内部的全局异步函数对象暴露;绑定参数和解析值必须是 structured-cloneable 的(运行时可能跨越序列化边界;我们的实现确实如此)。 -- `CodeRunResult = { value?: unknown; logs: CodeLogEntry[]; error?: CodeRunFailure }`——程序执行结果,包括异常、超时、abort 和 worker 退出,以 `error` 字段解析。`run()` 仅在调用方/seam 误用时才 reject(例如重复的绑定命名空间);消费方仍在自己的错误边界处理不合规的后端 rejection。 +- `CodeRunResult = { value?: unknown; logs: CodeLogEntry[]; error?: CodeRunFailure }`——程序执行结果,包括异常、超时、abort 和 worker 退出,都解析为 `error` 字段。`run()` 仅在调用方/seam 误用时才 reject(例如重复的绑定命名空间);消费方仍在自己的错误边界处理不合规的后端拒绝。 - `CodeLogEntry = { source: 'console' | 'stdout' | 'stderr'; level?: 'log' | 'info' | 'warn' | 'error' | 'debug'; text: string }` -- `CodeRunFailure = { kind: 'exception' | 'timeout' | 'abort' | 'worker-exit'; message: string }`——正交的结果按[防御性模式](../../../defensive-patterns.md)独立报告;超时的 run 不是异常,abort 不是超时。 -- 两个只读的后端描述符,仅供信息参考不用于门控:`language`(程序必须使用的语言——交付的后端为 `'typescript'`;Python 后端会声明自己,并在呈现侧配对自己的 SDK 生成器)和 `isolation`(交付的后端为 `'worker-thread'`;未来的为 `'process'`、`'container'` 等)。`dsh-tools` 在 MVP 中要求 `language === 'typescript'`——其代码生成输出 TS——否则组装会大声失败,与 `toolOrder` 违规时的配置错误惯用法相同(如 `mode` 为非 native 但根本没有加载 `ctx.codeRuntime`)。 +- `CodeRunFailure = { kind: 'exception' | 'timeout' | 'abort' | 'worker-exit'; message: string }`——按[防御性模式](../../../defensive-patterns.md)独立报告的正交结果;超时的 run 不是异常,abort 不是超时。 +- 两个只读的后端描述符,仅供信息参考而非门禁判定:`language`(程序必须使用的语言——交付的后端为 `'typescript'`;Python 后端会声明自己,并在呈现侧配对自己的 SDK 生成器)和 `isolation`(交付的后端为 `'worker-thread'`;未来可为 `'process'`、`'container'` 等)。`dsh-tools` 在 MVP 中要求 `language === 'typescript'`——其代码生成输出 TS——否则组装会大声失败,与 `toolOrder` 违规时的配置错误惯用法相同(如 `mode` 为非 native 但根本没有加载 `ctx.codeRuntime`)。 -请求包含所有运行时输入;实现方拥有经过校验的超时和上限默认值。注册表仅在组装 Code Mode 时查找可选的运行时,因此原生模式不依赖它。缺失或语言不兼容的运行时会大声失败。替代基底或语言可以在同一 seam 后面替换实现,配对相应的 SDK 生成器。 +请求包含所有运行时输入;实现方拥有经校验的超时和上限默认值。注册表仅在组装 Code Mode 时查找可选的运行时,因此 native 模式不依赖它。缺失或语言不兼容的运行时会大声失败。替代基底或语言可以在同一 seam 背后替换实现,配对相应的 SDK 生成器。 -### worker 线程运行时 +### worker-thread 运行时 -`@deepseek-ai/dsh-code-runtime-worker`,`packages/code-runtime/` 组的第二个包。每次 `run()`: +`@deepseek-ai/dsh-code-runtime-worker`,`packages/code-runtime/` 组的第二个包(package)。每次 `run()`: -1. **宿主侧 type-strip**,使用 Node 内置的 `stripTypeScriptTypes`(`node:module`;在本仓库的整个引擎范围 `^22.19.0 || >=24.0.0` 内可用,且保持位置不变,因此运行时错误行号与模型源码一致)。Strip-only 模式拒绝不可擦除的语法(`enum`、namespaces)——该拒绝以 `error.kind: 'exception'` 加 Node 的消息返回,SDK 说明写明「仅限可擦除 TypeScript」,模型像处理任何其他程序错误一样自我纠正。语法级别的失败永远不会 spawn worker。 -2. **每次 run spawn 一个全新 `Worker`**,来自包自身的 bootstrap 模块:`env: {}`(真正为空——比 spawn 命令的 scrubbed-env 规则更严格),`resourceLimits` 来自配置,`stdout`/`stderr` 捕获到 `logs` 而非继承。不做池化、不跨 run 共享状态:程序的世界随 worker 消亡,这使得 run 仅从日志即可重建,且状态泄漏不可表达。 -3. **在 bootstrap 中执行**:剥离类型后的程序成为一个 `AsyncFunction` 的函数体,其参数是绑定全局变量和一个捕获式 `console` shim,因此顶层 `await` 和 `return` 可用,程序的完成值即为 run 的 `value`(structured-cloneable 值原样跨越;其他值被替换为其 `util.inspect` 渲染,已文档化)。 -4. **通过消息端口桥接绑定**:worker 中的每个绑定函数发送 `{ id, global, name, args }` 并等待回复;宿主根据请求的绑定校验名称、调用、并回复 `{ id, ok, value }` 或 `{ id, ok: false, message }`(宿主侧绑定拒绝变为程序侧 rejection)。worker 侧的命名空间对象通过 `defineProperty` 构建为 null-prototype,因此名为 `__proto__`、`constructor` 或 `toString` 的绑定是普通的自有属性,不会产生原型链冲突。未知名称、重复 id 和结算后的消息被拒绝或忽略——端口协议假设对端是敌对的,因为对端运行的是模型代码。 -5. **强制独立预算。** `computeMs` 计量 worker 忙碌时间,允许慢速的 awaited 工具而不放过热循环。`maxWallMs` 限制总经过时间,包括未完成的等待。到期、取消和完成都会终止 worker。堆退出和截断被显式报告;compute、wall、heap、log 和返回值上限都是经过校验的配置。 -6. **Dispose 至静默**:服务自身的 disposal 终止进行中的 worker 并*等待*它们退出后再 resolve,遵循[防御性模式](../../../defensive-patterns.md)。 +1. **宿主侧 type-strip**,使用 Node 内置的 `stripTypeScriptTypes`(`node:module`;在本仓库的整个引擎范围 `^22.19.0 || >=24.0.0` 内可用,且保持位置不变,因此运行时错误行号与模型源码一致)。仅剥离模式拒绝不可擦除的语法(`enum`、namespaces)——该拒绝以 `error.kind: 'exception'` 加 Node 的消息返回,SDK 说明写明「仅限可擦除 TypeScript」,模型像处理其他程序错误一样自我修正。语法级失败不会 spawn worker。 +2. **每次 run spawn 一个全新 `Worker`**,来自包自身的 bootstrap 模块:`env: {}`(真正为空——比 spawn 命令的 scrubbed-env 规则更严格),`resourceLimits` 来自配置,`stdout`/`stderr` 捕获到 `logs` 而非继承。不做池化,不跨 run 保留状态:程序的世界随 worker 消亡,这使得 run 仅从日志即可重建,状态泄漏不可表达。 +3. **在 bootstrap 中执行**:剥离后的程序成为一个 `AsyncFunction` 的函数体,其参数是绑定全局变量和一个捕获式 `console` shim,因此顶层 `await` 和 `return` 可用,程序的完成值即为 run 的 `value`(structured-cloneable 值原样跨越;其他值被替换为其 `util.inspect` 渲染,已文档化)。 +4. **通过 message port 桥接绑定**:worker 中的每个绑定函数发送 `{ id, global, name, args }` 并等待回复;宿主根据请求的绑定校验名称、调用、并回复 `{ id, ok, value }` 或 `{ id, ok: false, message }`(宿主侧绑定拒绝变为程序侧 rejection)。worker 侧的命名空间对象通过 `defineProperty` 构建为 null-prototype,因此名为 `__proto__`、`constructor` 或 `toString` 的绑定是普通自有属性,而非原型链碰撞。未知名称、重复 id 和结算后消息被拒绝或忽略——端口协议假设对端是恶意的,因为对端运行的是模型代码。 +5. **强制独立预算。** `computeMs` 计量 worker 忙碌时间,允许慢速的 awaited 工具而不放过热循环。`maxWallMs` 约束总经过时间,包括未解析的等待。到期、取消和完成都终止 worker。堆退出和截断被显式报告;compute、wall、heap、log 和返回值上限是经校验的配置。 +6. **dispose 至静默**:服务自身的 dispose(资源释放)终止进行中的 worker 并*等待*其退出后再 resolve,遵循[防御性模式](../../../defensive-patterns.md)。 ### 信任姿态 -worker 运行时提供的是封闭隔离,而非安全边界:模型代码可以触及 Node API,权限与 bash 工具相当。`worker.terminate()` 停止线程但不停止它 spawn 的 OS 进程。Code Mode 使用与 bash 相同的 `tools/pre-execute` 策略门控,并额外提供空环境、堆限制、独立隔离区和对程序本身的硬终止。需要硬多租户边界的部署需要为代码和 bash 都使用容器级后端;运行时的 isolation 描述符让它们能区分该后端。 +worker 运行时提供的是隔离,而非安全边界:模型代码可以访问 Node API,权限与 bash 工具相当。`worker.terminate()` 停止线程但不停止它 spawn 的 OS 进程。Code Mode 使用与 bash 相同的 `tools/pre-execute` 策略门禁,并额外提供空环境、堆限制、独立 isolate 和对程序本身的硬终止。需要硬多租户边界的部署需要为代码和 bash 都使用容器级后端;运行时的 isolation 描述符让它们能区分该后端。 ### 模型看到的内容 -SDK 指示模型编写一个异步的可擦除 TypeScript 函数体,通过 `await tools.name(args)` 调用工具,在需要时 catch 被 reject 的工具调用,并仅返回或打印应重新进入上下文的输出。即使在 `Promise.all` 下调用仍保持顺序。声明前缀可以与原生 schema 一样大,尤其在 `'both'` 下,但对提供方缓存保持稳定。 +SDK 指示模型编写一个异步的可擦除 TypeScript 函数体,通过 `await tools.name(args)` 调用工具,在需要时捕获被拒绝的工具调用,并仅 return 或 log 应重新进入上下文的输出。即使在 `Promise.all` 下调用仍保持顺序。声明前缀可能与原生 schema 一样大,尤其在 `'both'` 下,但对提供方缓存保持稳定。 ## 后果 -切换到 `'code'` 的部署必须更新任何仅原生的 `toolOrder`。组装监听器负责维护任何被重写的协议表面的完整性。子分发保持序列化,桥接不会传播逐调用的 `additionalContext`,直到为 Code Mode 设计好这些契约。 +切换到 `'code'` 的部署必须更新任何仅限 native 的 `toolOrder`。组装监听器有责任维护任何被重写的协议面的完整性。子分发保持序列化,桥不传播每次调用的 `additionalContext`,直到为 Code Mode 设计好这些契约。 ## 测试 -- **Worker 运行时:** 真实 worker 测试覆盖输出和值捕获、失败类型、compute 和 wall 预算、敌对绑定流量、空环境、structured-clone 回退、输出上限和 disposal 至静默。一个 built-package 测试在纯 Node 下运行 worker 入口。 -- **注册表集成:** 测试覆盖代码生成、所有呈现模式、保留名称和限制规则、作用域可见性、权威组装重写、`toolOrder`、运行时兼容性失败、完整流水线子分发、parent-token 关联、序列化、取消和队列排空、JSON 归一化、错误传播、日志事件、省略的 `additionalContext` 和 HMR(热模块替换)清理。 -- **带密钥 e2e:** 真实模型在一个程序中组合两次 bash 调用;测试验证折叠的请求头、关联的分发事件、生成的文件和精选的回答。 -- **快照:** `code-mode-turn` 和 `both-mode-turn` fixture(测试前置数据)固定 SDK 段落、头部工具列表、分发事件和结果卡片。 +- **Worker 运行时:** 真实 worker 测试覆盖输出和值捕获、失败类型、compute 和 wall 预算、恶意绑定流量、空环境、structured-clone 回退、输出上限和 dispose 至静默。一个构建后包测试在纯 Node 下运行 worker 入口。 +- **注册表集成:** 测试覆盖代码生成、所有呈现模式、保留名称和限制规则、scoped 可见性、权威组装重写、`toolOrder`、运行时兼容性失败、完整流水线子分发、parent-token 关联、序列化、取消和队列排空、JSON 规范化、错误传播、日志事件、省略的 `additionalContext` 和 HMR(热模块替换)清理。 +- **带密钥 e2e:** 真实模型在一个程序中组合两次 bash 调用;测试验证折叠的请求头、关联的分发事件、结果文件和策展后的回答。 +- **快照:** `code-mode-turn` 和 `both-mode-turn` fixture(测试前置数据)固定 SDK 段、请求头工具列表、分发事件和结果卡片。 ## 曾考虑的替代方案 -**一个零核心改动的附加消费方插件。** 否决,因为 `agent/request` 在[可重建请求](../../implemented/architecture/2026-07-05-reconstructable-requests.md)下仅限 call-config,而变换已组装的工具列表需要在不拥有其配置的情况下撤销 `toolOrder` 规范化,且依赖监听器顺序。模型被提供哪些工具、以何种表示,是注册表的单一关注点:原生 schema 和 SDK 是同一可见存储的两种投影。 +**一个零核心改动的附加消费方插件。** 否决,因为 `agent/request` 在[可重建请求](../../implemented/architecture/2026-07-05-reconstructable-requests.md)下仅限 call-config,而变换已组装的工具列表需要在不拥有其配置的情况下撤销 `toolOrder` 规范化,并依赖监听器顺序。向模型提供哪些工具、以何种表示形式提供,是注册表的单一关注点:原生 schema 和 SDK 是同一个可见存储的两种投影。 -**`node:vm` 作为参考运行时,加固推迟。** 否决:`node:vm` 不是隔离(原型链逃逸可达宿主 realm)且无法中断热循环。worker 线程提供独立隔离区、空环境、`resourceLimits` 和可靠的 `terminate()`,信任等级等同于 bash,因此参考实现和生产实现是同一个包,无需 unsafe-acknowledgement 仪式。 +**`node:vm` 作为参考运行时,加固推迟。** 否决:`node:vm` 不是隔离(原型链逃逸可达宿主 realm)且无法中断热循环。worker 线程提供独立 isolate、空环境、`resourceLimits` 和可靠的 `terminate()`,信任等级等同于 bash,因此参考实现和生产实现是同一个包,无需 unsafe-acknowledgement 仪式。 -**对原生工具调用做结果省略/摘要。** 仅解决问题的上下文膨胀一半:裁剪旧 `tool-result` 作为可重建请求下的日志表面替换很容易添加,但仍然每次调用付出一次模型往返,且无法表达循环、分支或汇合。互补而非竞争;它可以在 Code Mode 下为残余的原生调用分层。 +**在原生工具调用上做结果省略/摘要。** 仅解决问题的上下文膨胀一半:裁剪旧 `tool-result` 作为可重建请求下的日志化表面替换成本低,但仍需每次调用一次模型往返,且无法表达循环、分支或汇合。互补而非竞争;它可以在 Code Mode 下为残余的原生调用分层。 -**循环中的并行原生分发。** 往返开销的另一个答案;仍是有效的未来工作(open TODO),仍被并发安全元数据阻塞,且仍无组合能力——它并行化的是模型在一步中已经决定的调用。Code Mode 的序列化队列决策使两者兼容:当元数据就绪时,原生并行分发和逐工具绑定并行化一起解锁。 +**循环中的并行原生分发。** 往返成本的另一个答案;仍是有效的未来工作(open TODO),仍被并发安全元数据阻塞,且仍无组合能力——它并行化的是模型在一步中已经决定的调用。Code Mode 的序列化队列决策保持两者兼容:当元数据就绪时,原生并行分发和每工具绑定并行化一起解锁。 -**始终排他(忠实于 Cloudflare,无模式)。** 否决,因为本 SDK 的主要消费方是编码 agent:其日常的单次调用(`bash`、`read`、`edit`)作为原生调用已经是理想的,强迫每次编辑都通过程序会加重常见场景的负担。mode 配置让忠实形式(`'code'`)只需一行配置即可启用而不强加。 +**始终排他(忠于 Cloudflare,无模式)。** 否决,因为本 SDK 的主要消费方是编码 agent:其日常的单次调用(`bash`、`read`、`edit`)作为原生调用已经是最优的,强制每次编辑都通过程序会给常见场景增加负担。mode 配置让忠实形式(`'code'`)只需一行配置即可启用,而不强加于人。 -**逐工具可见性层级(此工具原生,彼工具仅 code)。** 推迟:它需要逐工具元数据和 `'native' | 'code' | 'both'` 不具备的呈现拆分,且其设计依赖于模型在 `'both'` 下如何分配使用的证据。 +**每工具可见性分层(此工具 native,彼工具 code-only)。** 推迟:它需要每工具元数据和 `'native' | 'code' | 'both'` 不提供的呈现拆分,且其设计取决于模型在 `'both'` 下如何分配使用的证据。 -**SDK 中的消毒标识符别名**(`my-tool` → `my_tool`,Cloudflare 的做法)。否决:`declare const` 上的带引号键使每个名称可达,零别名冲突逻辑;模型处理 `tools["my-tool"](…)` 没有问题。 +**SDK 中的清洁化标识符别名**(`my-tool` → `my_tool`,Cloudflare 的做法)。否决:`declare const` 上的带引号键使每个名称可达,零别名碰撞逻辑;模型能正常处理 `tools["my-tool"](…)`。 -**REPL 风格的持久内核**(状态跨 `run_code` 调用存活)。MVP 否决:跨调用状态对会话日志不可见,破坏了每个请求是日志纯函数的可重建性保证;每次 run 全新保持了这一点。内核风格后端在未来仍可通过 seam 表达,配合自己的日志方案。 +**REPL 风格的持久内核**(状态跨 `run_code` 调用存活)。在 MVP 中否决:跨调用状态对会话日志不可见,破坏了「每个请求是日志的纯函数」这一可重建性保证;每次 run 全新保持了这一点。内核风格的后端在未来仍可通过同一 seam 表达,配合自己的日志方案。 ## 风险 -**Worker 不是硬安全边界。** 有意为之且已文档化(见§信任姿态):姿态等同于现有 bash 工具,封闭隔离超过它,门控使用相同的 seam。需要更多的部署需要未来的 `isolation: 'container'` 后端——作为 seam 的设计扩展跟踪,而非本设计的 TODO。 +**Worker 不是硬安全边界。** 有意为之且已文档化(§信任姿态):姿态等同于既有的 bash 工具,隔离程度超过它,门禁使用相同的 seam。需要更强隔离的部署需要未来的 `isolation: 'container'` 后端——作为 seam 设计的扩展点跟踪,而非本设计的 TODO。 -**`stripTypeScriptTypes` 标记为 experimental。** 它与 Node 自身原生 `.ts` 执行背后的引擎(amaro/swc)相同,在本仓库的整个引擎范围内作为 API 暴露。缓解措施:运行时的单元测试套件固定了所依赖的行为(位置保持、可擦除限制的拒绝消息形状宽松匹配),调用位于一个私有函数后面,且 `amaro`/`sucrase` 是 API 变动时的即插即用替代品。可擦除子集是面向模型的契约线,错误路径是一个可工作的反馈循环,而非死胡同。 +**`stripTypeScriptTypes` 标记为 experimental。** 它与 Node 自身原生 `.ts` 执行背后的引擎(amaro/swc)相同,在本仓库的整个引擎范围内作为 API 暴露。缓解措施:运行时的单元测试套件固定了所依赖的行为(位置保持、可擦除限制的拒绝消息形状宽松匹配),调用位于一个私有函数之后,且 `amaro`/`sucrase` 是 API 变化时的直接替代品。仅可擦除子集是面向模型的契约线,错误路径是一个可工作的反馈循环,而非死胡同。 -**SDK 的 prompt 开销,尤其在 `'both'` 下。** `.d.ts` 可以与它补充的原生 schema 相当大;`'both'` 携带两种表示。前缀稳定性 + 提供方缓存摊销了每会话开销;mode 是逐部署的;本 RFC 不做无条件节省的声明。何时偏好哪种模式的量化指导明确是上线后的学习。 +**SDK 的 prompt 成本,尤其在 `'both'` 下。** `.d.ts` 可能与它补充的原生 schema 体量相当;`'both'` 携带两种表示。前缀稳定性 + 提供方缓存摊销了每会话成本;mode 是每部署的;本 RFC 不做无条件节省的声明。何时优先使用哪种模式的量化指导明确属于上线后学习。 -**注册表范围增长。** `dsh-tools` 吸收了代码生成、一个工具、一个桥接和一个事件。通过包内的模块边界(`ts-types.ts`、`code-mode.ts` 与 `schema.ts`/`json-schema.ts`/`presentation.ts` 并列)和 seam 来约束:所有基底形状的东西都在 `ctx.codeRuntime` 后面。 +**注册表 scope 增长。** `dsh-tools` 吸收了代码生成、一个工具、一个桥和一个事件。通过包内的模块边界(`ts-types.ts`、`code-mode.ts` 与 `schema.ts`/`json-schema.ts`/`presentation.ts` 并列)和 seam 约束:所有基底相关的内容都在 `ctx.codeRuntime` 之后。 -**Structured-clone 值可以超出 JSON。** 因此工具绑定在分发前对参数做 JSON 归一化,确保每个执行的调用都可以被记录。底层运行时保持其更宽的端口契约,而更严格的消费方在自己的边界处校验。非文本子结果变为占位符。 +**Structured-clone 值可能超出 JSON。** 因此工具绑定在分发前对参数做 JSON 规范化,确保每次执行的调用都可记录。底层运行时保持其更宽的端口契约,而更严格的消费方在自己的边界处校验。非文本子结果变为占位符。 -**仅序列化的子分发。** `Promise.all` 尚未获得挂钟并行性,仅减少了往返次数;模型可能过度期望。说明中已声明;解除此限制与原生并行分发 TODO 所需的相同并发安全元数据绑定。 +**仅序列化的子分发。** `Promise.all` 尚未获得挂钟并行性,仅减少往返次数;模型可能过度期望。说明中已声明;解除此限制与原生并行分发 TODO 所需的并发安全元数据绑定。 -**预算计量读取事件循环,而非标志。** 忙碌时间轮询(`eventLoopUtilization()`)比精确 CPU 计量更粗——预算到期最多延迟一个轮询间隔——且其正确性声明(「pending dispatch 无法暂停它」)对敌对程序是承重的。两侧都有单元测试(带 pending decoy dispatch 的热循环在 `computeMs` 时死亡;idle-on-slow-binding 存活到 `maxWallMs`),轮询间隔是内部常量而非配置——部署无法将其误调为绕过。 +**预算计量读取事件循环,而非 flag。** 忙碌时间轮询(`eventLoopUtilization()`)比精确 CPU 计量更粗糙——预算到期最多延迟一个轮询间隔——且其正确性声明(「pending 的分发不能暂停它」)对恶意程序是承重的。两侧都有单元测试(带 pending 诱饵分发的热循环在 `computeMs` 处死亡;在慢绑定上空闲的程序存活到 `maxWallMs`),轮询间隔是内部常量而非配置——部署无法将其误调为绕过手段。 diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml index 6aac0209ec..f5eae41ba4 100644 --- a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-17-filesystem-tool-schemas.md: c2d3aa679599b1129a19b9082b9254ecf3103f12 -2026-06-17-filesystem-tool-schemas.zh.md: b13274c41da244d7d2a5fe6ff2064d8d5e0a9b42 +2026-06-17-filesystem-tool-schemas.zh.md: cd504a37d5ee25f6634b651d30099afe5acd6495 diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md index b13274c41d..cd504a37d5 100644 --- a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md @@ -1,24 +1,24 @@ -# RFC:文件系统工具 schema——面向模型的读/写/编辑形状 - -Status: implemented +# RFC:文件系统工具 schema——面向模型的读/写/编辑接口形状 [English](2026-06-17-filesystem-tool-schemas.md) | 中文 +Status: implemented + ## 问题 -[文件系统能力 seam RFC](../architecture/2026-06-17-filesystem-capability-seam.md) 定义了文件系统能力 seam(`ctx.fs`)、包拆分(`dsh-fs`、`dsh-fs-local`、`dsh-tool-fs`,加上 `dsh-fs-policy` 策略插件),以及 read-before-write/edit 检查所依赖的 observed-file/stale-version 策略——[split-fs-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](../architecture/2026-06-26-file-context-as-event-gate.md) 两份 RFC 随后将该策略从 `ctx.fs` 移到了 `dsh-fs-policy` 插件的 `fs/*` 事件门上。第一版文件系统工具交付剩余的决策是面向模型的 schema 表面:模型在 `read`、`write` 和 `edit` 中看到哪些参数。 +[文件系统能力 seam RFC](../architecture/2026-06-17-filesystem-capability-seam.md) 定义了文件系统能力 seam(`ctx.fs`)、包(package)拆分(`dsh-fs`、`dsh-fs-local`、`dsh-tool-fs`,加上 `dsh-fs-policy` 策略插件),以及针对 read-before-write/edit 检查的 observed-file/stale-version 策略——[split-fs-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](../architecture/2026-06-26-file-context-as-event-gate.md) RFC 后来将其从 `ctx.fs` 移至 `dsh-fs-policy` 插件的 `fs/*` 事件门上。首次文件系统工具交付剩余的决策是面向模型的 schema 接口:模型在 `read`、`write` 和 `edit` 中看到哪些参数。 -schema 应当足够小,能在 `dsh-tool-fs` 的首次实现中完成;同时又足够稳定,使未来的本地/远程/沙箱文件系统后端不会引起面向模型的接口变动。它还应避免从参考系统照搬所有选项。Claude Code 和 OpenCode 暴露了类似的核心文件工具,但在命名风格和额外 flag 上有所不同;本 RFC 为原型选择最小的共有表面。 +该 schema 应足够小,以便在 `dsh-tool-fs` 的首次实现中完成,但又足够稳定,使未来的本地/远程/沙箱文件系统后端不需要改动面向模型的接口。同时应避免从参考系统中照搬所有选项。Claude Code 和 OpenCode 暴露了类似的核心文件工具,但在命名风格和额外 flag 上有所不同;本 RFC 为原型选择最小的共有接口。 ## 决策 -`@deepseek-ai/dsh-tool-fs` 在第一版文件系统工具套件中暴露以下三个面向模型的工具: +`@deepseek-ai/dsh-tool-fs` 在首个文件系统工具套件中暴露以下三个面向模型的工具: -| Tool | 我们的 schema | Claude Code | OpenCode | 说明 | 纳入原型 | +| Tool | Our schema | Claude Code | OpenCode | Notes | Part of prototype | |---|---|---|---|---|---| -| `read` | `read(file_path, offset?, limit?)` | `Read(file_path, offset?, limit?, pages?)` | `read(filePath, offset?, limit?)` | 仅文件;`offset` 从 1 开始;首次实现不支持图片/PDF/多模态。 | 是 | -| `write` | `write(file_path, content)` | `Write(file_path, content)` | `write(content, filePath)` | 创建或覆写 UTF-8 文本。在默认 fs-policy 下,更新已有文件需要先有一次观测;新建文件则不需要。 | 是 | -| `edit` | `edit(file_path, old_string, new_string, replace_all?)` | `Edit(file_path, old_string, new_string, replace_all?)` | `edit(filePath, oldString, newString, replaceAll?)` | 字面字符串替换;默认要求唯一匹配;在默认 fs-policy 下需要先有一次观测(任何窗口化的 read 都算)。 | 是 | +| `read` | `read(file_path, offset?, limit?)` | `Read(file_path, offset?, limit?, pages?)` | `read(filePath, offset?, limit?)` | Files only; 1-indexed `offset`; no image/PDF/multimodal support in the first pass. | YES | +| `write` | `write(file_path, content)` | `Write(file_path, content)` | `write(content, filePath)` | Creates or overwrites UTF-8 text. Under the default fs-policy, updates to existing files require a prior observation; new-file creates do not. | YES | +| `edit` | `edit(file_path, old_string, new_string, replace_all?)` | `Edit(file_path, old_string, new_string, replace_all?)` | `edit(filePath, oldString, newString, replaceAll?)` | Literal string replacement; unique match required by default; under the default fs-policy requires a prior observation (any windowed read counts). | YES | schema 使用 snake_case 字段名(`file_path`、`old_string`、`new_string`、`replace_all`),与 Claude Code 及现有 DeepSeek Harness 工具 schema 示例保持一致。消费方包将这些面向模型的名称转换为 `ctx.fs` 调用和 `fs/*` 事件分发。 @@ -26,47 +26,47 @@ schema 使用 snake_case 字段名(`file_path`、`old_string`、`new_string` ### `read` -`read` 检查一个 UTF-8 文本文件并返回带行号的内容。 +`read` 检视一个 UTF-8 文本文件并返回带行号的内容。 参数: - `file_path: string`——必填。要读取的路径,由 `ctx.fs` 解析。 - `offset?: number`——可选。返回的第一行,从 1 开始。默认为第一行。 -- `limit?: number`——可选。返回的最大行数。默认值和上限是 `dsh-tool-fs` / `ctx.fs` 的实现细节。 +- `limit?: number`——可选。返回的最大行数。默认值与上限是 `dsh-tool-fs` / `ctx.fs` 的实现细节。 -首次实现的非目标: +首次实现不涉及的内容: -- 不支持 PDF `pages` 参数。 -- 不支持图片或多模态文件读取。 -- 不通过 `read` 列出目录;如有需要,目录列表将作为单独的未来工具。 +- 无 PDF `pages` 参数。 +- 无图片或多模态文件读取。 +- 不通过 `read` 列出目录;如有需要,目录列表将作为单独的后续工具。 ### `write` -`write` 创建或完全替换一个 UTF-8 文本文件。 +`write` 创建或完整替换一个 UTF-8 文本文件。 参数: - `file_path: string`——必填。要写入的路径,由 `ctx.fs` 解析。 - `content: string`——必填。要写入的完整 UTF-8 文本内容。 -在默认 fs-policy 下,用 `write` 更新已有文件需要同一执行上下文对该文件有过一次先前观测(read/write/edit);`dsh-fs-policy` 插件将观测到的版本作为 `fs/write-intent` 上的 stale guard 提供。创建新文件不需要先前观测。如果策略插件不存在,`write` 是无条件的裸提供方 create-or-overwrite。 +在默认 fs-policy 下,使用 `write` 更新已有文件需要同一执行上下文先前对该文件有过一次观测(read/write/edit);`dsh-fs-policy` 插件将观测到的版本作为 `fs/write-intent` 上的 stale guard 提供。创建新文件不需要先前观测。如果策略插件不存在,`write` 是无条件的裸提供方 create-or-overwrite。 -schema 不将 `expected_hash`、`expected_version` 或 `create_only` 暴露为面向模型的参数。stale-version 检查由后端产生的版本和策略插件的观测状态驱动,而非要求模型通过 schema 复制版本令牌。 +schema 不将 `expected_hash`、`expected_version` 或 `create_only` 作为面向模型的参数暴露。过期版本检查由后端产生的版本和策略插件的观测状态驱动,而非要求模型通过 schema 复制版本令牌。 ### `edit` -`edit` 通过替换字面文本来更新一个已有的 UTF-8 文本文件。 +`edit` 通过替换字面文本来更新已有的 UTF-8 文本文件。 参数: - `file_path: string`——必填。要编辑的路径,由 `ctx.fs` 解析。 - `old_string: string`——必填。要替换的字面文本。首次实现中空字符串无效。 -- `new_string: string`——必填。字面替换文本;空字符串表示删除匹配项。 +- `new_string: string`——必填。字面替换文本;空字符串表示删除匹配内容。 - `replace_all?: boolean`——可选。默认为 false。为 false 时,`old_string` 必须恰好匹配一处。 -`edit` 要求同一执行上下文对该文件有过一次先前观测(任何窗口化的 read 都算——授权依据是版本新鲜度,而非全文查看要求),或该上下文对该文件有过先前的 write/edit。`dsh-fs-policy` 策略插件推导所有者并将记录的版本作为 stale guard 提供;提供方的 mutation lock 强制执行。 +`edit` 要求同一执行上下文先前对该文件有过一次观测(任何窗口化的 read 都算——授权基于版本新鲜度,而非全文查看要求),或该上下文先前对该文件做过 write/edit。`dsh-fs-policy` 策略插件推导所有者并将记录的版本作为 stale guard 提供;提供方的 mutation lock 负责执行。 -首次实现拒绝 Codex 风格的 patch 语法和多模式 edit API。它使用一种严格的字面替换模式,使面向模型的契约保持简单,后端可以自行掌控精确匹配、重复匹配、行尾和 stale-version 语义。 +首次实现拒绝 Codex 风格的 patch 语法和多模式 edit API。它使用一种严格的字面替换模式,使面向模型的契约保持简单,并让后端掌控精确匹配、重复匹配、行尾和过期版本的语义。 ## 结果形状 @@ -74,17 +74,17 @@ schema 不将 `expected_hash`、`expected_version` 或 `create_only` 暴露为 默认原生投影: -| Tool | `tool-fs` 消费的结构化 `ctx.fs` 结果 | 默认模型投影 | +| Tool | Structured `ctx.fs` outcome consumed by `tool-fs` | Default model projection | |---|---|---| -| `read` | 返回的行、返回行数、总行数、目标显示路径、文件版本、部分视图标志 | 带行号的文本加分页脚注 | -| `write` | create/update 操作、目标显示路径、新文件版本 | 简洁的 create/update 成功文本 | -| `edit` | 替换次数、replace-all 标志、目标显示路径、新文件版本 | 简洁的 edit 成功文本 | +| `read` | returned lines, returned line count, total line count, target display path, file version, partial-view flag | line-numbered text plus pagination footer | +| `write` | create/update operation, target display path, new file version | concise create/update success text | +| `edit` | replacement count, replace-all flag, target display path, new file version | concise edit success text | -结构化结果不重复模型参数(如 `file_path`、`old_string` 或 `content`),除非后端已将其解析为新信息(如 `displayPath`、`targetKey` 或新版本)。token 感知的截断属于模型投影的职责,不属于后端的规范结果。 +结构化结果不会重复模型参数(如 `file_path`、`old_string` 或 `content`),除非后端已将其解析为新信息(如 `displayPath`、`targetKey` 或新版本)。面向 token 的截断属于模型投影的职责,而非后端规范结果的一部分。 -## 延后 +## 延后事项 -以下内容被明确排除在首版文件系统 schema 之外: +以下内容被明确排除在首次文件系统 schema 实现之外: - 面向模型的 `expected_hash`、`expected_version` 或 `create_only` 参数。 - 目录列表、glob、grep 和搜索工具。 @@ -95,18 +95,18 @@ schema 不将 `expected_hash`、`expected_version` 或 `create_only` 暴露为 ## 测试 -schema 测试固定每个工具的必填/可选参数集、空 `old_string` 拒绝、`replace_all` 默认值、snake_case 字段名、描述文本中对观测策略的说明,以及根插件套件注册;集成测试通过 `ctx.tools.execute()` 对真实的 `dsh-fs-local` 提供方执行全部三个工具,并验证模型参数被正确转换为预期的 `ctx.fs` 调用和 `fs/*` 分发。 +schema 测试固定每个工具的必填/可选参数集、空 `old_string` 拒绝、`replace_all` 默认值、snake_case 字段名、描述文字中对观测策略的说明,以及根插件套件注册;集成测试通过 `ctx.tools.execute()` 对真实的 `dsh-fs-local` 提供方执行全部三个工具,并验证模型参数被正确转换为预期的 `ctx.fs` 调用和 `fs/*` 分发。 ## 曾考虑的替代方案 -- **Codex 风格的 patch 语法或多模式 edit API**:否决。一种严格的字面替换模式使面向模型的契约保持简单,并让后端自行掌控精确匹配、重复匹配、行尾和 stale-version 语义。 -- **camelCase 参数名(OpenCode 风格)**:snake_case 与 Claude Code 及现有 harness 工具 schema 示例一致,且命名一旦发布即成为公开表面。 -- **面向模型的 `expected_hash` / `expected_version` / `create_only` 参数**:否决。stale 检查由后端产生的版本和策略插件的观测状态驱动,从不依赖模型复制的脆弱令牌。 +- **Codex 风格的 patch 语法或多模式 edit API**:否决。一种严格的字面替换模式使面向模型的契约保持简单,并让后端掌控精确匹配、重复匹配、行尾和过期版本的语义。 +- **camelCase 参数名(OpenCode 风格)**:snake_case 与 Claude Code 及现有 harness 工具 schema 示例一致,且命名一旦发布即成为公开接口。 +- **面向模型的 `expected_hash` / `expected_version` / `create_only` 参数**:否决。过期检查由后端产生的版本和策略插件的观测状态驱动,从不依赖模型复制的脆弱令牌。 ## 后果 -**首版 schema 有意小于 Claude Code。** 去掉 PDF pages、多模态 read、丰富的 grep/list flag 和 expected hash 字段使实现保持聚焦,但用户可能很快提出这些需求。它们将以独立 RFC 或聚焦的后续工作形式到来,而非在初始 schema 上叠加重载。 +**首版 schema 有意小于 Claude Code 的。** 去掉 PDF pages、多模态 read、丰富的 grep/list flag 和 expected hash 字段使实现保持聚焦,但用户可能很快就会提出这些需求。它们将以独立 RFC 或聚焦的后续工作形式到来,而非对初始 schema 的重载。 -**v1 没有显式的面向模型 stale guard。** schema 不要求模型提供 expected hash/version。这是有意为之:stale 检查来自后端产生的版本和 `dsh-fs-policy` 插件的观测状态,而非来自模型复制的脆弱令牌。文件系统安全失败通过 `dsh-fs` 拥有的结构化 `FsError` 代码浮现,而非通过模型提供的版本字段。 +**v1 中没有显式的面向模型的 stale guard。** schema 不要求模型提供 expected hash/version。这是有意为之:过期检查来自后端产生的版本和 `dsh-fs-policy` 插件的观测状态,而非模型复制的脆弱令牌。文件系统安全失败通过 `dsh-fs` 拥有的结构化 `FsError` 代码浮现,而非模型提供的版本字段。 -**命名成为公开表面。** 一旦发布,将 `file_path` 改为 `filePath` 或将 `old_string` 改为 `oldString` 会搅动提示词、示例和下游客户端。本 RFC 预先选定 snake_case 并将其视为稳定的面向模型契约。 +**命名成为公开接口。** 一旦发布,将 `file_path` 改为 `filePath` 或 `old_string` 改为 `oldString` 会搅动提示词、示例和下游客户端。本 RFC 预先选择 snake_case,并将其视为稳定的面向模型的契约。 diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml index 7f9212b3d3..c8ce15293a 100644 --- a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-18-acp-terminal-and-tool-rendering.md: cab89aa690c2068399ea5429a9c467410c744ce8 -2026-06-18-acp-terminal-and-tool-rendering.zh.md: 5a545b7a53f0814bc0e6071430c367047dc83f7f +2026-06-18-acp-terminal-and-tool-rendering.zh.md: 4047c493e63ac23f758de718616fd1f4bb29f7d4 diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md index 5a545b7a53..4047c493e6 100644 --- a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md @@ -1,48 +1,48 @@ -# RFC:丰富的 ACP bash 渲染——通过 `_meta` 约定实现终端卡片 - -Status: implemented +# RFC:富 ACP bash 渲染——通过 `_meta` 约定实现终端卡片 [English](2026-06-18-acp-terminal-and-tool-rendering.md) | 中文 +Status: implemented + ## 问题 -ACP 桥接层允许每个工具通过 `presentCall`/`presentResult` 自行控制调用渲染(见[工具调用 UI 展示](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md)与 `packages/core/tools`)。对于 `bash`,我们将确切命令作为 `tool_call` 标题呈现,模型的 `description` 作为内容文本块,`kind: 'execute'`,完成后的输出包裹在 ` ```console ` 围栏文本块中。 +ACP(Agent Client Protocol)桥接层允许每个工具通过 `presentCall`/`presentResult` 自行控制调用渲染(见 [tool-call UI presentation](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md) 与 `packages/core/tools`)。对于 `bash`,我们将确切命令作为 `tool_call` 标题呈现,模型的 `description` 作为一个内容文本块,`kind: 'execute'`,完成后的输出包裹在 ` ```console ` 围栏文本块中。 -参考编辑器将终端元数据渲染为一张专用卡片,包含 cwd、命令、实时风格输出和退出状态;纯文本丢失了这些结构。命令之所以作为标题,是因为执行卡片隐藏了原始输入,而人类可读的描述保留为卡片上方的独立块。 +参考编辑器将终端元数据渲染为一张专用卡片,包含 cwd、命令、实时风格的输出和退出状态;纯文本则丢失了这些结构。命令之所以作为标题,是因为执行卡片隐藏原始输入,而人类可读的描述保留为卡片上方的独立块。 ## 关键发现:agent 执行的终端使用 `_meta` 约定,而非 `terminal/create` -ACP 规范有一个*客户端侧*终端子协议:agent 调用客户端的 `terminal/create`,传入 `{ command, args, cwd, env }`,由**编辑器**执行进程,然后 agent 读取 `terminal/output` / `wait_for_exit`。这个模型不适合我们:我们的 harness 通过 `dsh-bash` 自行执行 bash(沙箱化的环境变量清洗、后台任务所有权、按会话的 cwd)。把执行路由到编辑器会绕过所有这些机制,并将执行分裂为两个后端。 +ACP 规范有一个*客户端侧*终端子协议:agent(智能体)调用客户端的 `terminal/create`(传入 `{ command, args, cwd, env }`),由**编辑器**执行进程,然后 agent 读取 `terminal/output` / `wait_for_exit`。这个模型不适合我们:我们的 harness 通过 `dsh-bash` 自行执行 bash(沙箱化的环境清理、后台任务所有权、按会话的 cwd)。将执行路由到编辑器会绕过所有这些机制,并将执行分叉到两个后端。 研究两个参考 agent(2026-06-18)发现,二者都没有为自己的 shell 工具使用 `terminal/create`——**两者都保持 agent 侧执行,并发出一套 `_meta` 约定**,由 Zed 特殊处理: -- **`claude-agent-acp`**(`tools.ts`、`acp-agent.ts`):以 `clientCapabilities._meta.terminal_output` 为门控。`tool_call` 携带 `content: [{ type: 'terminal', terminalId }]` 和 `_meta.terminal_info.{ terminal_id, cwd }`;输出/退出通过 `tool_call_update` 的 `_meta.terminal_output.{ terminal_id, data }` 和 `_meta.terminal_exit.{ terminal_id, exit_code, signal }` 到达。 -- **`codex-acp`**(`CodexToolCallMapper.ts`、`TerminalOutputMode.ts`):调用上同样携带 `terminal_info`;输出通过 `_meta.terminal_output`(完整)或 `_meta.terminal_output_delta`(增量)发送,由同一个 `_meta.terminal_output` 能力选择。 +- **`claude-agent-acp`**(`tools.ts`、`acp-agent.ts`):以 `clientCapabilities._meta.terminal_output` 为门控。`tool_call` 携带 `content: [{ type: 'terminal', terminalId }]` 与 `_meta.terminal_info.{ terminal_id, cwd }`;输出和退出通过 `tool_call_update` 的 `_meta.terminal_output.{ terminal_id, data }` 与 `_meta.terminal_exit.{ terminal_id, exit_code, signal }` 到达。 +- **`codex-acp`**(`CodexToolCallMapper.ts`、`TerminalOutputMode.ts`):调用上同样携带 `terminal_info`;输出通过 `_meta.terminal_output`(完整)或 `_meta.terminal_output_delta`(增量),由同一个 `_meta.terminal_output` 能力选择。 -Zed 侧(`crates/agent_servers/src/acp.rs`,已验证):收到 `ToolCall` 且其 `_meta.terminal_info.terminal_id` 已设置时,注册一个**仅展示**的终端(header = `terminal_info.cwd`,label = `tool_call.title`);收到 `ToolCallUpdate` 时,`_meta.terminal_output.data` 写入该终端,`_meta.terminal_exit.{exit_code,signal}` 设置状态。它将能力声明为 `clientCapabilities._meta.terminal_output = true`。`_meta` 本身是 ACP 规范认可的扩展点(在 `ToolCall`/`ToolCallUpdate` 上类型为 `{[k]: unknown} | null`);这里的*具体键*(`terminal_info`/`terminal_output`/`terminal_exit`)是 Zed 约定,不属于 ACP 规范——但它们是 Zed 集成的事实契约,也是在保持 agent 侧执行的前提下获得终端卡片的唯一途径。 +Zed 侧(`crates/agent_servers/src/acp.rs`,已验证):收到 `ToolCall` 且其 `_meta.terminal_info.terminal_id` 已设置时,注册一个**仅展示**的终端(header = `terminal_info.cwd`,label = `tool_call.title`);收到 `ToolCallUpdate` 时,`_meta.terminal_output.data` 写入该终端,`_meta.terminal_exit.{exit_code,signal}` 设置状态。客户端通过 `clientCapabilities._meta.terminal_output = true` 声明此能力。`_meta` 本身是 ACP 规范认可的扩展点(在 `ToolCall`/`ToolCallUpdate` 上类型为 `{[k]: unknown} | null`);这里的*具体键*(`terminal_info`/`terminal_output`/`terminal_exit`)是 Zed 约定,不属于 ACP 规范,但它们是 Zed 集成的事实契约,也是在保持 agent 侧执行的前提下获得终端卡片的唯一方式。 ## 决策 保持 `dsh-bash` 的 agent 侧执行;通过 `_meta` 约定渲染终端卡片,以能力声明为门控,以 ` ```console ` 文本块作为保底回退。 1. **能力声明。** `initialize` 读取 `clientCapabilities._meta.terminal_output`,桥接层按连接记住它。 -2. **提供方无关的展示词汇。** `dsh-tools` 新增一种终端形态的展示结构,工具可以返回它——提供方无关(`cwd`、输出 `data`、`exitCode`/`signal`),不含 ACP 类型。`dsh-tool-bash` 为 `bash` 返回该结构(cwd 来自解析后的工作目录;输出 + 退出从运行结果解析)。 -3. **桥接映射。** 当客户端声明了该能力时,桥接层将展示结构映射为:在 `tool_call` 上,`content:[…, {type:'terminal', terminalId}]`(工具的任何 `content`,如描述,渲染在终端块之前)+ `_meta.terminal_info.{terminal_id,cwd}`;在 `tool_call_update` 上,`_meta.terminal_output.{terminal_id,data}`(捕获的输出)+ `_meta.terminal_exit.{terminal_id, exit_code|signal}`(解析的退出),且 update 的文本 `content` 被省略(ACP 的 `tool_call_update.content` 会**替换**调用的 content 集合,因此重发围栏块会覆盖终端内容块)。`terminalId` 由 harness 的 `callId` 派生(稳定、每次调用唯一)。当能力未声明时,桥接层在调用上发送描述内容块,在 update 上发送既有的 ` ```console ` 文本内容——行为不变。 -4. **退出标记从渲染输出中解析;无新执行路径,无实时流式传输。** 输出在完成时附加(来自 agent 自身的 `tool/result`),不逐 token 流式传输。退出状态标记(`_meta.terminal_exit.{exit_code,signal}`)会被发出:纯 `presentResult(args, result)` seam 只能看到内容块,因此 `dsh-tool-bash` 通过解析 `renderResult` 追加的状态标记(`[exit code: N]` / `[killed by signal: …]`)来恢复结构化退出——解析是标记发出的精确逆操作,二者在同一文件中共同演进,一个往返测试守护这对关系。dispose 不受影响:没有新资源需要清理,因为桥接层从未创建客户端侧终端。 +2. **提供方无关的展示词汇。** `dsh-tools` 新增一种终端形态的展示结构,工具可返回它——提供方无关(`cwd`、输出 `data`、`exitCode`/`signal`),不含 ACP 类型。`dsh-tool-bash` 为 `bash` 返回该结构(cwd 来自解析后的工作目录;输出与退出从运行结果解析)。 +3. **桥接映射。** 当客户端声明了该能力时,桥接层将展示结构映射为:在 `tool_call` 上,`content:[…, {type:'terminal', terminalId}]`(工具的任何 `content`,如描述,渲染在终端块之前)+ `_meta.terminal_info.{terminal_id,cwd}`;在 `tool_call_update` 上,`_meta.terminal_output.{terminal_id,data}`(捕获的输出)+ `_meta.terminal_exit.{terminal_id, exit_code|signal}`(解析后的退出),且 update 的文本 `content` 被省略(ACP 的 `tool_call_update.content` 会**替换**调用的 content 集合,因此重新发送围栏块会覆盖终端内容块)。`terminalId` 由 harness 的 `callId` 派生(稳定、每次调用唯一)。当能力未声明时,桥接层在调用上发送描述内容块,在 update 上发送既有的 ` ```console ` 文本内容——行为不变。 +4. **退出信息从渲染输出中解析;无新执行路径,无实时流式传输。** 输出在完成时附加(来自 agent 自身的 `tool/result`),不逐 token 流式传输。退出状态(`_meta.terminal_exit.{exit_code,signal}`)确实会发出:纯 `presentResult(args, result)` seam 只能看到内容块,因此 `dsh-tool-bash` 通过解析 `renderResult` 追加的状态标记(`[exit code: N]` / `[killed by signal: …]`)来恢复结构化退出信息——解析是标记发出的精确逆操作,二者在同一文件中共同演进,一个往返测试守护这对关系。资源释放不受影响:无需新增拆除逻辑,因为桥接层从未创建客户端侧终端。 ## 曾考虑的替代方案 -- **ACP 客户端侧终端子协议(`terminal/create`)**:明确否决。编辑器将执行进程,绕过 `dsh-bash` 的环境变量清洗、后台任务所有权和按会话的 cwd,并将执行分裂为两个后端。两个参考 agent 以同样的方式否决了它(见上述关键发现);agent 侧执行加 `_meta` 约定是在保持 harness 执行策略的同时获得终端卡片的唯一形态。 -- **通过事件 schema 透传结构化退出**:否决,改用标记往返方案。纯 `presentResult(args, result)` seam 只能看到内容块,而解析是标记发出的精确逆操作,在同一文件中共同演进并由往返测试守护。 +- **ACP 客户端侧终端子协议(`terminal/create`)**:明确否决。编辑器将执行进程,绕过 `dsh-bash` 的环境清理、后台任务所有权和按会话的 cwd,并将执行分叉到两个后端。两个参考 agent 以同样的方式否决了它(见上述关键发现);agent 侧执行加 `_meta` 约定是在保持 harness 执行策略的同时获得终端卡片的唯一形态。 +- **通过事件 schema 传递结构化退出信息**:否决,改用标记往返方案。纯 `presentResult(args, result)` seam 只能看到内容块,而解析是标记发出的精确逆操作,二者在同一文件中共同演进,由往返测试守护。 ## 后果 -- **Zed 约定的 `_meta` 键。** 终端卡片依赖 Zed 特有的键(`terminal_info`/`terminal_output`/`terminal_exit`),位于 ACP 规范认可的 `_meta` 扩展点内,而非 ACP 终端子协议。不识别这些键的客户端仍然获得文本回退(能力门控确保我们只在客户端通过 `_meta.terminal_output` 声明支持时才发出这些键),因此非 Zed 客户端永远不会变差。如果 ACP 日后标准化了 agent 执行的终端,迁移到该标准并移除约定键。 -- **能力诚实。** 仅在客户端声明了 `_meta.terminal_output` 时才发出终端元数据;文本回退是对所有其他客户端的契约,绝不能退化。由一个无能力测试覆盖,断言 ` ```console ` 路径。 +- **Zed 约定的 `_meta` 键。** 终端卡片依赖 Zed 特有的键(`terminal_info`/`terminal_output`/`terminal_exit`),位于 ACP 规范认可的 `_meta` 扩展点内,而非 ACP 终端子协议。不识别这些键的客户端仍然获得文本回退(能力门控确保我们仅在客户端通过 `_meta.terminal_output` 声明支持时才发出这些键),因此非 Zed 客户端不会变差。如果 ACP 日后标准化了 agent 执行的终端,则迁移到该标准并移除约定键。 +- **能力诚实。** 仅在客户端声明了 `_meta.terminal_output` 时才发出终端元数据;文本回退是对其他所有客户端的契约,绝不可退化。由一个无能力测试覆盖,断言 ` ```console ` 路径。 - **terminalId 冲突。** 从每次调用的 `callId` 派生,保证在会话内唯一且在 call/result 对之间稳定;绝不跨调用复用。 -- **退出从渲染文本中解析。** 退出标记通过解析 `renderResult` 的状态标记来恢复 `exit_code`/`signal`,而非通过事件 schema 透传结构化退出(纯 `presentResult` seam 看不到结构化退出)。解析是标记发出的精确逆操作,位于同一文件中;一个往返测试固定了这对关系,标记格式的变更如果破坏了解析就会使测试套件失败。如果标记将来需要与退出标记的需求分歧,改为在 result 事件上暴露结构化退出。 -- **提供方无关词汇的蔓延。** 终端展示结构扩大了 `dsh-tools` 的接口面;保持其中立性(不让 ACP 类型泄漏到 `dsh-tools`),且只提供第二个 UI 消费方也会需要的丰富度。 +- **退出信息从渲染文本解析。** 退出信息通过解析 `renderResult` 的状态标记恢复 `exit_code`/`signal`,而非通过事件 schema 传递结构化退出(纯 `presentResult` seam 看不到后者)。解析是标记发出的精确逆操作,且位于同一文件中;往返测试固定了这对关系,标记格式变更若破坏解析则测试套件失败。如果标记格式日后需要与退出信息分道扬镳,则改为在 result 事件上暴露结构化退出。 +- **提供方无关词汇的蔓延。** 终端展示结构扩大了 `dsh-tools` 的接口面;保持其中立性(不让 ACP 类型泄漏到 `dsh-tools`),且只提供第二个 UI 消费方同样需要的丰富度。 -## 不在范围内 / 非目标 +## 超出范围 / 非目标 -文本块基线仍是无能力声明时的默认行为。两个后续工作有意不在此处构建,各自需要独立 RFC:**实时增量流式传输**(`_meta.terminal_output_delta`,在分片到达时发送,需要 `dsh-bash` 上的增量输出 seam),以及**命令分类**(将 `cat`/`sed` 解析为带文件位置的 `read` 卡片、将 `grep` 解析为 `search` 等,回退到终端卡片——仅展示,绝不改变实际执行的内容)。 +文本块基线仍为无能力声明时的默认行为。以下两项后续工作有意不在此处构建,各自需要单独的 RFC:**实时增量流式传输**(在分片到达时发出 `_meta.terminal_output_delta`,需要在 `dsh-bash` 上新增增量输出 seam);**命令分类**(将 `cat`/`sed` 解析为带文件位置的 `read` 卡片,将 `grep` 解析为 `search`,回退到终端卡片——仅展示,绝不改变实际执行内容)。 diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml index 211ad897f7..aff86591fb 100644 --- a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-18-compaction-capability-seam.md: 31b06905924a07a7f0c2af427d8868585966f1a7 -2026-06-18-compaction-capability-seam.zh.md: ef71b3df39f02221f1bd25beb5e026cb056b95a0 +2026-06-18-compaction-capability-seam.zh.md: 1675484ed65e5cd890f420d4bdd1e16e2a95b2ef diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md index ef71b3df39..1675484ed6 100644 --- a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md @@ -6,37 +6,37 @@ Status: implemented ## 问题 -长时间运行的 agent(智能体)对话会无限增长。随着事件日志不断累积轮次,派生出的消息历史最终逼近模型的上下文窗口——模型随即在响应中途截断(`max-tokens`)或质量退化。**压缩(compaction)**是缓解手段:用一段简洁的摘要替换一段较早的历史,保持近期上下文完整。 +长时间运行的 agent(智能体)对话会无限增长。随着事件日志不断累积轮次,派生出的消息历史最终逼近模型的上下文窗口,模型随即截断响应(`max-tokens`)或性能退化。**上下文压缩(context compaction)** 是对此的缓解手段:用一段简洁的摘要替换一批较早的历史,保持近期上下文完整。 -[会话 surface](../../implemented/architecture/2026-06-18-session-surface.md) 正是为此而建的基础设施:它是事件日志之上的链表,带有一个 `surfaceOp: { op: 'replace', start, end }` 操作,专门用于遮蔽一段节点并插入替换内容,`sourceEventSeqs` 记录来源以便决策可确定性回放。剩下的是那个*决定压缩什么、并产出摘要*的插件。 +[session surface](../../implemented/architecture/2026-06-18-session-surface.md) 正是为此而构建的基础设施:一条建立在事件日志之上的链表,带有专门设计的 `surfaceOp: { op: 'replace', start, end }` 操作,用于遮蔽一段节点并插入替换内容,`sourceEventSeqs` 记录来源以便决策可确定性地回放。剩下的是那个*决定压缩什么、并产出摘要*的插件。 -两股力量塑造了设计。第一,压缩是**可替换的**:token 计数可以是 char/4 启发式或真实 tokenizer,摘要生成可以是模型调用、模板或远程服务——这些与*何时*压缩、*压缩哪段*彼此独立变化。第二,`SurfaceEventType` 是封闭的,只有五种事件类型(`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`);只有它们可以携带 `surfaceOp`。因此一个专属的 `compaction/*` 事件**不能**出现在 surface 上——编译器拒绝在其上放 `surfaceOp`,invariants 插件在运行时也会拒绝。 +两股力量塑造了设计。第一,压缩是**可替换的**:token 计数可以是 char/4 启发式或真实 tokenizer,摘要生成可以是模型调用、模板或远程服务——它们独立于*何时*以及*压缩哪段范围*而变化。第二,`SurfaceEventType` 封闭为五种事件类型(`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`);只有这些类型可以携带 `surfaceOp`。因此一个专用的 `compaction/*` 事件**不能**出现在 surface 上——编译器拒绝在其上附加 `surfaceOp`,invariants 插件在运行时也会拒绝。 ## 决策 ### 压缩是一个能力 seam,接口与实现分离 -按照[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md),压缩以独立包(package)发布,使契约、算法和(后续的)消费方 surface 各自独立演进: +遵循[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md),压缩以独立包(package)发布,使契约、算法和(后续的)消费方 surface 各自独立演进: -1. **接口** — `@deepseek-ai/dsh-compact`:一个抽象的 `CompactService`,拥有 `ctx.compact` 键、`CompactionResult` 词汇以及 `compact/*` 会话事件。它将 `compactIfNeeded()` 和 `compactRegion()` 声明为**抽象方法**——契约阐述压缩*做什么*,而非*怎么做*。 -2. **实现** — `@deepseek-ai/dsh-compact-basic`:一个具体的 `BasicCompactService`,拥有完整算法——token 估算(每 token 字符数——`charsPerToken` 配置,默认 4——加逐块开销)、尾→头保留遍历、通过 `ctx.llm.stream()` 的摘要生成、surface 替换、锁,以及 `agent/pre-step` 自动压缩监听器。基于 tokenizer 或模板的后端是兄弟包(或覆写两个 protected 估算/摘要钩子的子类)。 +1. **接口** — `@deepseek-ai/dsh-compact`:抽象 `CompactService`,拥有 `ctx.compact` 键、`CompactionResult` 词汇以及 `compact/*` 会话事件。它将 `compactIfNeeded()` 和 `compactRegion()` 声明为**抽象方法**——契约说明压缩*做什么*,而非*怎么做*。 +2. **实现** — `@deepseek-ai/dsh-compact-basic`:具体的 `BasicCompactService`,拥有完整算法——token 估算(每 token 字符数,即 `charsPerToken` 配置,默认 4,加上每块开销)、尾→头保留遍历、通过 `ctx.llm.stream()` 进行摘要生成、surface 替换、锁,以及 `agent/pre-step` 自动压缩监听器。基于 tokenizer 或模板的后端是同级包(或覆盖两个 protected 估算/摘要钩子的子类)。 3. **消费方** — 推迟。一个 `/compact` 工具和斜杠命令将 `inject: ['compact']` 并调用契约;它们被有意排除在本 RFC 范围之外,以便 seam 先稳定下来。 -### 契约依赖 `dsh-session` 和 `dsh-llm`——有意的偏离 +### 契约依赖 `dsh-session` 和 `dsh-llm`——有意为之的偏离 -能力 seam RFC 规定接口包「只依赖 cordis」(对 `dsh-bash` 成立,其词汇是自包含的)。压缩**无法**遵守这一点:它的动词定义在 `Session` 之上(`compactRegion(session, start, end)`),其输出*就是*内容词汇(`CompactionResult.summary: ContentBlock[]`)。不引用 `Session`/`SessionEvent`(来自 `dsh-session`)和 `ContentBlock`(来自 `dsh-llm`),契约无法表达。 +能力 seam RFC 规定接口包"仅依赖 cordis"(对 `dsh-bash` 成立,因为其词汇是自包含的)。压缩**无法**遵守这一点:它的动词定义*在* `Session` 之上(`compactRegion(session, start, end)`),其输出*就是*内容词汇(`CompactionResult.summary: ContentBlock[]`)。不引用 `Session`/`SessionEvent`(来自 `dsh-session`)和 `ContentBlock`(来自 `dsh-llm`),契约就无法表达。 -这不是耦合异味——而是契约的领域本身。「只依赖 cordis」的指导原则本来就是「接口只依赖契约真正命名的东西,绝不依赖实现」的简写。`dsh-session` 和 `dsh-llm` 本身就是接口/词汇包,不是实现;`dsh-compact` 仍然不导入任何后端。seam 的真正不变式——*消费方和实现在抽象服务背后独立演进*——完好无损。 +这不是耦合异味,而是契约的领域所在。"仅 cordis"的指导原则一直是"接口仅依赖契约真正需要命名的东西,绝不依赖实现"的简写。`dsh-session` 和 `dsh-llm` 本身是接口/词汇包,不是实现;`dsh-compact` 仍然不导入任何后端。seam 的真正不变式——*消费方和实现在抽象服务背后独立演进*——完好无损。 -### 抽象的 `compactIfNeeded` / `compactRegion`,算法在后端 +### 抽象 `compactIfNeeded` / `compactRegion`,算法在后端 -早期草案将完整算法(保留遍历、token 求和、文本提取)作为接口上的具体方法,只有 `estimateContentTokens()` 和 `summarize()` 是抽象的。这会把契约重新耦合到一种策略:想要不同保留策略或不同事件排序的后端不得不与继承来的具体代码对抗。将两个核心方法都设为抽象,把所有*怎么做*的决策放在后端——它本该在那里——接口则保持为纯粹的*做什么*声明。后端内部仍有分层——`estimateContentTokens()` 和 `summarize()` 是 `protected` 钩子,子后端可以覆写而无需重新实现遍历——但这种分层是后端的私有关注,不是契约的。 +早期草案将完整算法(保留遍历、token 求和、文本提取)作为接口上的具体方法,仅 `estimateContentTokens()` 和 `summarize()` 为抽象。这会将契约重新耦合到一种策略:想要不同保留策略或不同事件排序的后端必须与继承来的具体代码对抗。将两个核心方法都设为抽象,把所有*怎么做*的决策放在后端——它本该在那里——并让接口保持为纯粹的*做什么*声明。后端内部仍有分层——`estimateContentTokens()` 和 `summarize()` 是 `protected` 钩子,子后端可以覆盖而无需重新实现遍历——但那是后端的私有关注点,不是契约的。 -`compactIfNeeded(agent, turn, step, fullSystemPrompt, signal)` 接受**必填**参数(而非最初的全可选形态)。自动压缩 seam(见下文)总是提供 agent、生命周期上下文、组装好的系统提示词(计入估算)以及轮次的 abort signal,因此可选性只会在 seam 处引入隐藏默认值。被压缩的会话来自 agent 上下文。`compactRegion(session, start, end, agent, turn, step, signal?)` 保留可选的 signal(手动调用方可以省略)。传递生命周期上下文而非具体模型,使路由 agent 保持诚实:后端的摘要请求可以走 `agent/request`,模型路由插件已在那里选择实际模型。 +`compactIfNeeded(agent, turn, step, fullSystemPrompt, signal)` 接收**必需**参数(而非最初的全可选形式)。自动压缩 seam(见下文)总是提供 agent、生命周期上下文、组装好的系统提示词(计入估算)和轮次的 abort signal,因此可选性只会在 seam 处引入隐藏的默认值。被压缩的会话来自 agent 上下文。`compactRegion(session, start, end, agent, turn, step, signal?)` 保留可选的 signal(手动调用方可以省略)。传递生命周期上下文而非具体模型,使路由 agent 保持诚实:后端的摘要请求可以走 `agent/request`,模型路由插件在那里已经选择了实际模型。 -### 自动压缩运行在 `agent/pre-step`,一个专用的 surface 变更 seam +### 自动压缩在 `agent/pre-step` 运行——一个专用的 surface 变更 seam -压缩会变更会话 surface,因此它在步骤开启之前、消息派生之前运行。`agent/request` 仍然是调用配置变换,永远不需要在 surface 变更后重建历史。 +压缩会变更 session surface,因此在步骤开启之前、消息派生之前运行。`agent/request` 保持为调用配置变换,无需在 surface 变更后重建历史。 解决方案是一个专用的循环 seam:**`agent/pre-step`**(`@mode serial`),由循环在系统组装*之后*、步骤开启(`step/start`)*之前*触发: @@ -48,29 +48,29 @@ messages = session.deriveMessages() ⟵ single derive, reflects the compaction request = waterfall agent/request ⟵ pure request transform (hooks, model switch) ``` -循环在 `agent/pre-step` 之后只派生一次消息。在 `step/start` 之前运行使压缩记录落在任何半开步骤之外,简化崩溃修复。该 seam 是 awaited 且 serial 的,因此 surface 变更不会交错;监听器返回 `void`,不使用 Cordis bail 值作为否决。 +循环在 `agent/pre-step` 之后派生一次消息。在 `step/start` 之前运行,使压缩记录位于任何半开步骤之外,简化崩溃修复。该 seam 是 awaited 且串行的,因此 surface 变更不会交错;监听器返回 `void`,不使用 Cordis bail 值作为否决。 ### 保留是轮次无关的;工具配对平衡是唯一的结构守卫 -自动压缩在**每个**步骤之前触发,而非每轮一次。这对**失控轮次存活至关重要**:一个工具密集的 ReAct 轮次每步追加一个 `assistant/message` + 一个 `tool/result`,surface 在*一轮之内*就会增长。单独一轮就可能超出窗口(「失控轮次」)——而在下一次模型调用溢出之前能挽救它的唯一时机,就是下一步的 `pre-step` 检查点。如果把压缩限制在轮次的第一步(或更糟,逐字保留整个进行中的轮次),就恰好重新打开了压缩存在的意义所要堵住的那个缺口:harness 会在最需要压缩的时候崩溃。 +自动压缩在**每个**步骤之前触发,而非每轮一次。这对**失控轮次存活至关重要**:工具密集型的 ReAct 轮次每步追加一个 `assistant/message` + 一个 `tool/result`,因此 surface 在*一轮之内*就会增长。单独一轮就可能超出窗口("失控轮次"),而在下一次模型调用溢出之前唯一能挽救的时机是下一步的 `pre-step` 检查点。如果将压缩限制在轮次的第一步(或者更糟,逐字保留整个进行中的轮次),恰好重新打开了压缩存在的意义所要堵住的缺口:harness 会在最需要压缩时崩溃。 -`compactIfNeeded` 保留估算大小达到 `retainTokens` 的最小尾部完整 surface 单元,压缩更早的节点。一个单元是一个完整的已关闭步骤或一条无步骤消息。如果 token 截断点落在步骤内部,保留范围会扩展直到截断处工具配对平衡。平衡按 surface 顺序检查,而非日志序列号,因为替换摘要在旧 surface 位置有新的序列号。`compactRegion` 拒绝将工具调用与其结果拆开的边界。进行中的轮次不享有特殊保留。 +`compactIfNeeded` 保留估算大小达到 `retainTokens` 的最小完整 surface 单元尾部,压缩更早的节点。一个单元是一个完整的已关闭步骤或一条无步骤消息。如果 token 截断点落在步骤内部,保留范围会扩展直到切割点满足工具配对平衡。平衡按 surface 顺序检查,而非日志序号,因为替换摘要在旧的 surface 位置拥有新的序号。`compactRegion` 拒绝将工具调用与其结果拆分的边界。进行中的轮次不享受特殊保留。 -因此失控轮次的压缩方式与任何其他历史完全相同:其早期*已关闭*步骤被摘要,近期步骤保持逐字。当唯一可压缩的内容只剩一个不可拆分的开放尾部步骤(其工具调用尚无结果)时,压缩拒绝执行(返回 `null`),待该步骤关闭后重试。 +因此失控轮次的压缩方式与其他历史完全相同:其早期*已关闭*步骤被摘要,近期步骤保持原样。当唯一可压缩的内容只剩一个不可拆分的开放尾部步骤(其工具调用尚无结果)时,压缩拒绝执行(返回 `null`)并在该步骤关闭后重试。 -**单单元溢出不在范围内,这是有意的。** 如果单个被保留的单元——一个已关闭步骤,或一个大型自由节点如粘贴的 `user/message`——*单独*超出预算,压缩无能为力,下一次模型调用可能超预算发出。限制单个单元的大小是另一个关注点(输出截断),在别处处理;压缩对此不作承诺,而没有这种机制的 harness 仍然可能在单个超大单元上崩溃。这里诚实地命名了这个边界,而非掩盖它。 +**单单元溢出不在范围内,这是有意为之。** 如果单个被保留的单元——一个已关闭步骤,或一个大型自由节点(如粘贴的 `user/message`)——*单独*超出预算,压缩无能为力,下一次模型调用可能超预算发出。限制单个单元的大小是另一个关注点(输出截断),在别处处理;压缩对此不作承诺,而没有这种机制的 harness 仍然可能在单个超大单元上崩溃。这里诚实地指出这一点,而非掩盖。 ### 头部锚定:一个自动检查点,始终在头部 -自动压缩始终从 surface 头部开始,将先前的检查点与新压缩的历史合并,使自动检查点始终只有一个。因此 `shadowedRange` 是位置性的而非数值序列区间:一个更新的摘要序列号可能占据更旧的 surface 位置。`shadowedSeqs` 记录权威的 surface 顺序。手动的中间范围压缩可能留下多个检查点。 +自动压缩始终从 surface 头部开始,将先前的检查点与新压缩的历史合并,因此只保留一个自动检查点。`shadowedRange` 因此是位置性的而非数值序号区间:一个较新的摘要序号可能占据较旧的 surface 位置。`shadowedSeqs` 记录权威的 surface 顺序。手动的中间范围压缩可能留下多个检查点。 ### 近似收敛不变式 -`resolveConfig` 校验数值参数但**不**基于假想的摘要长度不变式拒绝。收敛是动态的:提供方的输出上限可能被隐藏或外显的推理 token 消耗,模型可能输出不可预测大小的摘要。`maxTokens` 只是摘要调用的提供方侧生成上限;推理块在检查点存储前被剥离。如果压缩后的 surface 仍超阈值,`compactIfNeeded()` 最多额外重压缩头部检查点 `compactionRetries` 次,但每次提交的摘要必须小于它遮蔽的内容。唯一的残余情况是上述单单元溢出(一个向后取整的超大步骤可能把保留尾部推过预算)——这恰好是上面声明的范围外关注点,而非抖动 bug。 +`resolveConfig` 校验数值参数,但**不**基于虚构的摘要长度不变式来拒绝。收敛是动态的:提供方的输出上限可能被隐藏或显式的推理 token 消耗,模型可能生成不可预测大小的摘要。`maxTokens` 仅是摘要调用的提供方侧生成上限;推理块在检查点存储前被剥离。如果压缩后的 surface 仍超阈值,`compactIfNeeded()` 最多额外重压缩头部检查点 `compactionRetries` 次,但每次提交的摘要必须小于其遮蔽的内容。唯一的残余情况是上述单单元溢出(一个向后取整的超大步骤可能将保留尾部推过预算),这恰好是上述范围外的关注点,而非抖动 bug。 -### Surface 替换:`compact/*` 事件仅存于日志;一条 `user/message` 承载摘要 +### Surface 替换:`compact/*` 事件仅存在于日志;一条 `user/message` 承载摘要 -由于 `SurfaceEventType` 是封闭的,摘要不能搭载在 `compact/*` 事件上。后端改为追加一条**单独的 `user/message`**,带有 `surfaceOp: { op: 'replace', start, end }`,其 `content` 是(带框架的)摘要,其 `sourceEventSeqs` 覆盖被遮蔽的节点*以及*簿记事件。`compact/*` 事件是纯日志记录(锁 + 来源)。surface 变更位于锁**内部**——`compact/end` 是最后追加的事件: +由于 `SurfaceEventType` 是封闭的,摘要不能搭载在 `compact/*` 事件上。后端改为追加一条**单独的 `user/message`**,带有 `surfaceOp: { op: 'replace', start, end }`,其 `content` 是(带框架的)摘要,`sourceEventSeqs` 覆盖被遮蔽的节点*和*簿记事件。`compact/*` 事件是纯日志记录(锁 + 来源)。surface 变更位于锁**内部**——`compact/end` 是最后追加的事件: ``` compact/start → log-only. Acquires the lock. @@ -81,47 +81,47 @@ user/message → surfaceOp { op:'replace', start, end }. THE surface mutatio compact/end → log-only. Releases the lock (carries `error` on a recoverable failure). ``` -`deriveMessages()` 随后产出 `[summary_as_user_message, ...retained_nodes]`。复用 `user/message` 是诚实的而非变通:摘要确实*就是* user 角色的上下文。 +`deriveMessages()` 随后产出 `[summary_as_user_message, ...retained_nodes]`。复用 `user/message` 是诚实的而非变通:摘要确实*是* user 角色的上下文。 ### 检查点框架 + 增量合并(后端私有) -基础后端将摘要包装为已建立的检查点上下文,并标记它以便下一轮增量合并。原始摘要保留在 `compact/summary` 上。框架是后端策略;seam 只承诺一条替换 user 消息承载可能带框架的摘要。 +基础后端将摘要包装为已建立的检查点上下文,并标记以便下一轮增量合并。原始摘要保留在 `compact/summary` 上。框架是后端策略;seam 仅承诺一条替换 user 消息承载可能带框架的摘要。 -### 通过日志记录的锁实现阻塞,加上崩溃/可恢复失败分类 +### 通过日志记录的锁实现阻塞,加上崩溃/可恢复失败的分类 -`compact/start … compact/end` 括号的合理性,按实际承担的工作排序: +`compact/start … compact/end` 括号的存在理由,按当前实际承担的职责排序: -1. **可检测的崩溃孤儿 + 来源记录**(首要)。摘要生成是一次慢模型调用,在 `compact/start` *之后*持久化。摘要生成中途崩溃会留下一个没有匹配 `compact/end` 的 `compact/start`——一个可检测的孤儿。最后释放锁(而非最先释放)将崩溃窗口从*静默损坏*转化为可检测的孤儿。 -2. **防止并发压缩。** 如果当前轮次持有一个未匹配的 `compact/start`,`compactRegion` 拒绝启动。(循环在 awaited 的 `pre-step` 上是单线程的,因此这也是一个重入绊线——抛出的「already in progress」信号意味着真正的 bug。) +1. **可检测的崩溃孤儿 + 来源追溯**(首要)。摘要生成是一次慢速模型调用,持久化在 `compact/start` *之后*。摘要生成中途崩溃会留下一个没有匹配 `compact/end` 的 `compact/start`——一个可检测的孤儿。最后释放锁(而非最先)将崩溃窗口从*静默损坏*转变为可检测的孤儿。 +2. **防止并发压缩。** 如果当前轮次持有未匹配的 `compact/start`,`compactRegion` 拒绝启动。(循环在 awaited 的 `pre-step` 上是单线程的,因此这也是重入绊线——抛出"already in progress"表示真正的 bug。) 两种失败路径,均有文档记录: -- **崩溃**(循环在摘要生成中途死亡):一个悬空的 `compact/start`,没有关闭者。因为 `compact/*` 是**仅日志**事件,孤儿是**惰性的**——surface 替换从未落地,所以完整的未压缩历史正确派生。通用轮次修复(`interruptedTurnClosers`)用合成的 `turn/end` 关闭轮次;孤儿位于该 `turn/end` *之前*,因此轮次范围的进行中检查永远看不到它,崩溃不会卡住未来的压缩。压缩在下一个 `pre-step` 简单地重新尝试。 -- **可恢复**(摘要生成抛出异常但循环存活):后端追加带有 **`error`** 字段的 `compact/end`,surface 不受影响,模型调用继续使用完整历史。 +- **崩溃**(循环在摘要生成中途死亡):悬空的 `compact/start`,无关闭事件。由于 `compact/*` 是**仅日志**事件,孤儿是**惰性的**——surface 替换从未落地,因此完整的未压缩历史正确派生。通用轮次修复(`interruptedTurnClosers`)用合成的 `turn/end` 关闭轮次;孤儿位于该 `turn/end` *之前*,因此轮次范围内的进行中检查永远看不到它,崩溃不会卡住未来的压缩。压缩在下一个 `pre-step` 简单地重新尝试。 +- **可恢复**(摘要生成抛出异常但循环存活):后端追加带有 **`error`** 字段的 `compact/end`,surface 保持不变,模型调用以完整历史继续。 `compact/end` 保留其 `error?` 字段(与 `tool/result` 的自包含错误一致——一个事件即可区分成功与失败,无需关联兄弟事件)。没有单独的 `compact/error` 事件。 -**核心会话修复保持对压缩无感知——这是有意的。** `interruptedTurnClosers` 从不被教导 `compact/*`。如果教导它,每个未来的 `xxx/start … xxx/end` 插件对都必须修补核心模块——这恰好是能力 seam 架构存在的意义所要避免的耦合。因为仅日志的孤儿是惰性的,不需要特殊修复:通用轮次修复加上未落地 surface 变更的惰性就足够了。 +**核心 session 修复保持对压缩无感知——这是有意为之。** `interruptedTurnClosers` 从不被教导 `compact/*`。如果教导它,每个未来的 `xxx/start … xxx/end` 插件对都必须修补核心模块——这恰好是能力 seam 架构存在的意义所要避免的耦合。由于仅日志的孤儿是惰性的,不需要特殊修复:通用轮次修复加上未落地 surface 变更的惰性就足够了。 ## 曾考虑的替代方案 -- **完整算法作为接口上的具体方法**(只有估算/摘要是抽象的)——早期草案;否决,因为它把契约重新耦合到一种保留策略。两个核心方法都是抽象的;`protected` 的估算/摘要钩子是后端的私有分层,不是契约的。 -- **压缩运行在 `agent/request` waterfall(瀑布式事件)上**——早期方案;否决,因为它强制了双重派生,且交给监听器的上下文在结构上无法压缩。专用的 `agent/pre-step` seam 使分层在构造上正确。 +- **完整算法作为接口的具体方法**(仅估算/摘要为抽象)——早期草案;否决,因为它将契约重新耦合到一种保留策略。两个核心方法都是抽象的;`protected` 的估算/摘要钩子是后端的私有分层,不是契约的。 +- **在 `agent/request` waterfall(瀑布式事件)上执行压缩**——早期方案;否决,因为它强制双重派生,且将监听器上下文交给了结构上无法压缩的对象。专用的 `agent/pre-step` seam 从构造上使分层正确。 - **单独的 `compact/error` 事件**——否决:`compact/end` 保留 `error?` 字段,与 `tool/result` 的自包含错误一致——一个事件即可区分成功与失败,无需关联兄弟事件。 -- **教导核心轮次修复认识 `compact/*`**——否决:仅日志的孤儿是惰性的,而一个为每个未来 `xxx/start … xxx/end` 插件对打补丁的核心模块,恰好是能力 seam 架构存在的意义所要避免的耦合。 +- **教导核心轮次修复识别 `compact/*`**——否决:仅日志的孤儿是惰性的,为每个未来的 `xxx/start … xxx/end` 插件对修补核心模块恰好是能力 seam 架构存在的意义所要避免的耦合。 ## 后果 -- **新包**:`packages/compact/compact`(接口)和兄弟包 `compact-basic`(后端),位于 `packages/compact/` 下,接入根 tsconfig。消费方层推迟。 -- **新循环 seam**:`agent/pre-step`(`@mode serial`),在 `dsh-agent` 中声明,由 `dsh-agent-loop` 在系统组装之后、`step/start` 之前触发。这是循环的文档化变更——`docs/architecture.md` 记录了它,生成的 cordis catalog 携带其签名。 -- **`SessionEventMap`** 通过声明合并(merge-extensible)获得 `compact/start` / `compact/summary` / `compact/end`;`SurfaceEventType` **不受影响**。这些是会话事件而非 cordis `Events`,因此事件分类门禁无需新增条目。 -- **`dsh-session`** 获得工具配对平衡谓词(`isToolPairingBalanced`,位于 `tool-pairing.ts`,从包索引导出),`compactRegion`/`compactIfNeeded` 用它确保折叠区域不会拆开步骤的工具调用/结果对。surface 的 `replace` 操作和 surface 元数据运行时守卫已经存在,直接复用。 -- **`dsh-invariants`** 移除其 `surface replace: start must be <= end` 断言:头部锚定的压缩会将高序列号的替换节点放在更旧范围的*位置*,因此 `start > end` 在数值上是正常且有效的(范围是位置性的,由 surface 的 `indexOf` 检查验证,这些检查保持不变)。轮次包含不变式原样复用。 -- **接线**:`dsh-compact-basic` 在 `examples/coding-agent` 的 `cordis.yml` 中加载,使 seam 在真实演示中交付(此前未在任何地方加载)。 +- **新包**:`packages/compact/compact`(接口)和同级的 `compact-basic`(后端),位于 `packages/compact/` 下,接入根 tsconfig。消费方层推迟。 +- **新循环 seam**:`agent/pre-step`(`@mode serial`),在 `dsh-agent` 中声明,由 `dsh-agent-loop` 在系统组装之后、`step/start` 之前触发。这是对循环的文档化变更——`docs/architecture.md` 记录了它,生成的 cordis catalog 携带其签名。 +- **`SessionEventMap`** 通过声明合并(merge-extensible)获得 `compact/start` / `compact/summary` / `compact/end`;`SurfaceEventType` **未被**触及。这些是会话事件,不是 cordis `Events`,因此事件分类门禁无需新增条目。 +- **`dsh-session`** 获得工具配对平衡谓词(`isToolPairingBalanced`,位于 `tool-pairing.ts`,从包索引导出),`compactRegion`/`compactIfNeeded` 用它确保折叠区域不会拆分步骤的工具调用/结果对。surface 的 `replace` 操作和 surface 元数据运行时守卫已经存在并被复用。 +- **`dsh-invariants`** 移除其 `surface replace: start must be <= end` 断言:头部锚定的压缩将高序号替换节点放在较旧范围的*位置*上,因此 `start > end` 在数值上是正常且有效的(范围是位置性的,由 surface 的 `indexOf` 检查验证,这些检查保持不变)。轮次封闭不变式原样复用。 +- **接线**:`dsh-compact-basic` 在 `examples/coding-agent` 的 `cordis.yml` 中加载,使 seam 在真实演示中生效(此前它未被任何地方加载)。 ## 测试 -- **单元测试:** 真实 Loader 和 invariant 插件覆盖整单元保留、收敛失败、`compact/end` 的两种结果、头部锚定、开放尾部拒绝、惰性崩溃孤儿,以及在一个超大开放轮次内压缩已关闭步骤。 -- **循环测试:** 测试固定每步在 `turn/start` 和 `step/start` 之间有一次 awaited 的 `agent/pre-step`;在那里的 surface 变更落在步骤之外,并出现在单次派生的请求中。 -- **带密钥 e2e:** 真实模型和 bash 会话在降低限制下触发压缩,记录完整的 `compact/start…end` 对,缩小 surface,并完成任务。 -- **快照缺口:** 失控轮次压缩尚无法回放,因为摘要调用未记录 `assistant/chunk` 事件或 `sessionId`;交错的摘要调用回放仍是后续工作。 +- **单元测试:** 使用真实 Loader 和 invariant 插件覆盖完整单元保留、收敛失败、`compact/end` 的两种结果、头部锚定、开放尾部拒绝、惰性崩溃孤儿,以及在一个超大开放轮次内压缩已关闭步骤。 +- **循环测试:** 测试固定每步在 `turn/start` 与 `step/start` 之间有一次 awaited 的 `agent/pre-step`;在该处的 surface 变更落在步骤之外,并出现在单次派生的请求中。 +- **带密钥 e2e:** 真实模型和 bash 会话在降低的限制下触发压缩,记录完整的 `compact/start…end` 对,缩小 surface,并完成任务。 +- **快照缺口:** 失控轮次压缩尚无法回放,因为摘要调用未记录 `assistant/chunk` 事件或 `sessionId`;交错摘要调用的回放仍是后续工作。 diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml index ec702a6101..1da7113f51 100644 --- a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-21-subagent-capability-seam.md: 2bed84cd9166e8aa1ad5fa65b3afa44b8a842045 -2026-06-21-subagent-capability-seam.zh.md: a99d0fe894dca485452dd266752785a26815bb8a +2026-06-21-subagent-capability-seam.zh.md: a5917c14141dd06c14b4f45c5f6e4703f0eb661f diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md index a99d0fe894..a5917c1414 100644 --- a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md @@ -1,74 +1,74 @@ # RFC:Subagent 能力 seam -Status: implemented - [English](2026-06-21-subagent-capability-seam.md) | 中文 -> 完整 seam 已交付:`dsh-subagent` 接口、`dsh-subagent-mock` 测试后端与 `dsh-tool-subagent` 消费方;两个进程内后端(`dsh-subagent-spawn`、`dsh-subagent-fork`);嵌套 agent 快照基础设施([按会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md));以及进程外 `dsh-subagent-acp` 后端([其 RFC](2026-06-22-acp-subagent-backend.md))。 +Status: implemented + +> 完整 seam 已交付:`dsh-subagent` 接口、`dsh-subagent-mock` 测试后端与 `dsh-tool-subagent` 消费方;两个进程内后端(`dsh-subagent-spawn`、`dsh-subagent-fork`);嵌套 agent 快照基础设施([逐会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md));以及进程外后端 `dsh-subagent-acp`([其 RFC](2026-06-22-acp-subagent-backend.md))。 ## 问题 -harness 有一个长期搁置的 subagent seam:一个 agent 将工作委派给另一个 agent。意图已在 `Agent`/`AgentLoop` 接口中勾勒([packages/core/agent/src/types.ts](../../../../packages/core/agent/src/types.ts)、[packages/core/agent-loop/src/index.ts](../../../../packages/core/agent-loop/src/index.ts)):创建选项引用父 agent(fork = 用父会话的事件日志为子会话播种;spawn = 全新会话),子 agent 以 `Agent` 句柄返回,使 steering(中途引导)和事件订阅统一工作。本 RFC 实现该 seam;上方横幅列出了已交付的内容。 +harness 有一个长期搁置的 seam 用于 **subagent**:一个 agent(智能体)将工作委派给另一个 agent。这一意图在 `Agent`/`AgentLoop` 接口中已有草案([packages/core/agent/src/types.ts](../../../../packages/core/agent/src/types.ts)、[packages/core/agent-loop/src/index.ts](../../../../packages/core/agent-loop/src/index.ts)):一个创建选项引用父 agent(fork = 用父会话的事件日志初始化子会话;spawn = 全新会话),子 agent 以 `Agent` 句柄返回,使 steering(中途引导)和事件订阅可以统一工作。本 RFC 实现了这个 seam;上方横幅列出了已交付的内容。 -决定整体设计走向的核心需求是:**多种 subagent 实现必须在运行时共存**。一个父 agent 可能在同一个会话中既需要一个廉价的进程内子 agent 处理有限范围的子任务,又需要一个隔离的进程外子 agent(通过 ACP)。我们预见的传输方式: +决定整体设计走向的核心需求是:**多种 subagent 实现必须在运行时共存**。一个父 agent 可能在同一个会话中既需要一个廉价的进程内子 agent 处理有限范围的子任务,又需要一个隔离的进程外子 agent(通过 ACP(Agent Client Protocol))。我们预见的传输方式: -- **进程内**:在同一个 `Context` 上创建子 `ReactLoopAgent`(最廉价,且鉴于已有的 agent 工厂几乎零成本); +- **进程内**:在同一个 `Context` 上创建子 `ReactLoopAgent`(最廉价,且鉴于现有 agent 工厂几乎零成本); - **ACP**:作为 ACP *客户端*驱动另一个 agent 进程(可以是自身的另一个实例); -- 后续:**A2A**、**Codex app-server** 与 **Claude Code Agent SDK**——每种都与 ACP 后端相同的进程外「启动子 agent、发送提示词、流式更新、取消」形态。 +- 后续:**A2A**、**Codex app-server** 与 **Claude Code Agent SDK**——每种都与 ACP 后端相同的进程外形状:「启动子 agent、发送提示词、流式接收更新、取消」。 ## 曾考虑的替代方案 -### 为什么不用 bash seam 的形态 +### 为何不采用 bash seam 的形状 -bash seam([能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md))在每个 context 中只注册一个 `BashExecutor`;加载第二个会抛异常。这对 bash 是正确的(一台机器、一种执行命令的方式),但对这里是错的:共存才是需求。因此 subagent 服务是一个**命名提供方注册表**:每个实现以唯一名称注册,调用方按名称选取。这与 **LLM 适配器注册表**(`LlmService.registerAdapter`)同构,而非单服务的 bash 执行器。seam 仍然是三包结构(接口 / 实现 / 消费方);唯一不同的轴是「单实现 vs. 多实现」。 +bash seam([能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md))在每个 context 中只注册恰好一个 `BashExecutor`;加载第二个会抛异常。这对 bash 是正确的(一台机器、一种执行命令的方式),但对这里是错误的:共存才是需求。因此 subagent 服务是一个**命名提供方注册表**——每个实现以唯一名称注册,调用方按名称选择——镜像 **LLM(大语言模型)适配器注册表**(`LlmService.registerAdapter`),而非单服务的 bash 执行器。seam 仍然是由三个包构成的结构(接口 / 实现 / 消费方);只是「一个 vs. 多个实现」这个维度不同。 ## 决策 -### 三包 seam +### 由三个包构成的 seam -新增包组 `packages/subagent/`: +新建包(package)组 `packages/subagent/`: | 包 | 角色 | |---|---| -| `@deepseek-ai/dsh-subagent` | 接口:`SubagentService`(`ctx.subagents`)、`SubagentProvider`、`SubagentRun`、请求/结果/能力词汇表、`subagent/*` 事件 | +| `@deepseek-ai/dsh-subagent` | 接口:`SubagentService`(`ctx.subagents`)、`SubagentProvider`、`SubagentRun`、请求/结果/能力词汇、`subagent/*` 事件 | | `@deepseek-ai/dsh-subagent-spawn` | 实现:通过 `ctx.agents.create` 创建全新的进程内子 agent | -| `@deepseek-ai/dsh-subagent-fork` | 实现:以父会话日志快照为种子的进程内子 agent | +| `@deepseek-ai/dsh-subagent-fork` | 实现:用父 agent 日志快照初始化的进程内子 agent | | `@deepseek-ai/dsh-subagent-acp` | 实现:作为 ACP 客户端驱动已配置的子进程 | -| `@deepseek-ai/dsh-subagent-mock` | 支撑:脚本化的提供方,用于通过真实加载路径测试 seam | +| `@deepseek-ai/dsh-subagent-mock` | 辅助:用于通过真实加载路径测试 seam 的脚本化提供方 | | `@deepseek-ai/dsh-tool-subagent` | 消费方:基于 `ctx.subagents` 的面向模型的 `subagent` 工具 | -### 基本原语:异步 `start → SubagentRun` +### 原语:异步 `start → SubagentRun` -提供方暴露 `start(request) → Promise<SubagentRun>`。完成后发布一个就绪的子 agent 并将其运行句柄转交给调用方。一个信号覆盖就绪前后的取消;`dispose()` 取消剩余工作并等待静默。启动失败时清理部分资源,不发出生命周期事件。`start` 是传输无关的;`spawn` 仅命名全新进程内后端。 +提供方暴露 `start(request) → Promise<SubagentRun>`。完成时发布一个就绪的子 agent 并将其运行句柄转交给调用方。一个信号覆盖就绪前后的取消;`dispose()`(资源释放)取消剩余工作并等待静止。启动失败时清理部分资源,不发出生命周期事件。`start` 与传输方式无关;`spawn` 仅指代全新的进程内后端。 ### 两类可选能力,两种发现方式 -- **启动时特性**(`outputSchema`、`depthLimit`、`toolFilter`、`persona`)挂在静态 `provider.capabilities` 描述符上。服务在委派之前检查每一项请求的特性,若提供方不支持则**大声拒绝**(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不「接受后静默忽略」。它们必须在 run 存在之前被检查,这就是为什么不能做成运行时方法。 -- **运行时特性**(通过 `sendMessage` 进行 steering、通过 `resume` 进行后续交互)是 `SubagentRun` 上的**可选方法**。方法的存在即是能力,TypeScript 窄化即是发现机制:消费方不经窄化就无法调用不存在的方法,因此不存在静默降级路径,也不需要一个单独的 flags 对象来保持同步。 +- **启动时特性**(`outputSchema`、`depthLimit`、`toolFilter`、`persona`)挂在静态的 `provider.capabilities` 描述符上。服务在委派**之前**检查每个被请求的特性,如果提供方不支持则**大声拒绝**(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不接受后静默忽略。这些特性必须在 run 存在之前检查,因此不能是运行时方法。 +- **运行时特性**(通过 `sendMessage` 进行 steering、通过 `resume` 进行后续对话)是 `SubagentRun` 上的**可选方法**。方法的存在本身即为能力,TypeScript 类型收窄即为发现机制:消费方不经收窄就无法调用不存在的方法,因此不存在静默降级路径,也不需要额外的 flags 对象来保持同步。 ### Fork 与 fresh 是独立后端,而非一个 flag -全新子 agent 和 fork 子 agent 是独立的提供方,而非请求上的 flag。`dsh-subagent-spawn` 启动隔离的子 agent;`dsh-subagent-fork` 以仅包含已完成父轮次的平衡前缀为种子。进行中的轮次被排除,因为其 subagent 调用尚无结果,无法构成有效的回放历史。 +全新子 agent 与 fork 子 agent 是独立的提供方,而非请求中的一个 flag。`dsh-subagent-spawn` 启动隔离的子 agent;`dsh-subagent-fork` 用一个平衡前缀初始化子 agent,该前缀仅包含已完成的父轮次。进行中的轮次被排除,因为其 subagent 调用尚无结果,无法构成有效的回放历史。 ### 子 agent 隔离与父日志 -每个 subagent 运行在自己的 **`Session`** 中(独立 id、`parentSession` 谱系),独立持久化。父日志仅记录 spawn 的 `tool/call` 及其 `tool/result`(子 agent 的最终输出);子 agent 的内部步骤和工具调用留在子 agent 自己的会话中,从不注入父日志。这是唯一在所有传输方式下行为一致的设计:ACP 子 agent 的内部事件物理上无法注入我们的父日志,因此让进程内行为保持一致,使 seam 保持传输无关。 +每个 subagent 运行在**自己的 `Session`** 中(独立 id、`parentSession` 谱系),独立持久化。父日志仅记录 spawn `tool/call` 及其 `tool/result`(子 agent 的最终输出)——子 agent 的内部步骤和工具调用留在子 agent 自己的会话中,绝不注入父日志。这是唯一在所有传输方式下行为一致的设计:ACP 子 agent 的内部事件在物理上无法注入我们的父日志,因此让进程内行为保持一致,使 seam 真正与传输方式无关。 -### 同步收集(第一版) +### 同步收集(首版) `dsh-tool-subagent` 将其执行信号传给 `start()`,等待子 agent 结果,并在 `finally` 中 dispose 该 run。非完成态的结果变为错误结果,而非成功的部分输出。这个前台消费方不使用 run 的可选 steering 方法。 ### 提供方选择是配置,不面向模型 -`dsh-tool-subagent` 绑定到恰好一个提供方名称(`Config.provider`);模型只看到 `{ description, prompt }`。若要暴露多种传输方式,多次加载该工具插件,每次绑定不同的提供方和不同的 `toolName`(工具注册表拒绝重名)。*服务*持有多提供方注册表;*工具*选取其中一个。本版 schema 中没有 provider/type 参数。 +`dsh-tool-subagent` 绑定到恰好一个提供方名称(`Config.provider`);模型只看到 `{ description, prompt }`。若要暴露多种传输方式,请多次加载该工具插件,每次绑定不同的提供方和不同的 `toolName`(工具注册表拒绝重名)。*服务*持有多提供方注册表;*工具*选择其中一个——本版 schema 中没有 provider/type 参数。 ## 测试 -seam 通过真实的 Cordis Loader/export 路径测试,这能捕获 [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md) 中描述的 export 形状失败。注册表测试覆盖重载安全性、重名和启动时能力拒绝;嵌套 agent 场景通过[按会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md)进行无密钥回放;进程内后端还有真实循环的单元测试和带密钥的 e2e。 +seam 通过真实的 Cordis Loader/export 路径测试,这能捕获[事后分析 0001](../../../postmortem/0001-acp-default-export-drops-inject.md) 中描述的 export 形状错误。注册表测试覆盖重载安全性、重名和启动时能力拒绝;嵌套 agent 场景通过[逐会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md)进行无密钥回放;进程内后端还有真实循环的单元测试和带密钥的 e2e 测试。 ## 后果 -- **递归。** 若无限制,进程内子 agent 能看到委派工具并递归。进程内后端实现了可选的绝对深度限制和有作用域的实时全局 `toolFilter`;ACP 声明这两项能力为关闭并拒绝此类请求。[subagent 组合控制 RFC](2026-07-12-subagent-persona-tool-filter-and-depth.md) 拥有它们的确切语义和安全限制。 -- **阻塞父轮次。** 同步收集在子 agent 的整个持续期间保持父 agent 的 `runStep` 打开。这对第一版是可接受的;**后台 / 轮询 / 溢出语义推迟到未来的重新设计,该重新设计将统一 subagent 与 bash 的长时运行工具处理**(一个 sub-agent 和一个长时间运行的 `bash` 后台任务面临相同的「模型启动了一个慢操作,之后如何收集结果」问题,应共享一套机制而非各自发明)。 -- **实时进度。** 本版仅暴露生命周期事件和最终结果;逐分片的子→父更新流推迟到后台重新设计。 -- **ACP 客户端接口。** 将 ACP 子 agent 的 `fs`/`terminal` 代理回父 agent(共享工作区模式)是后续工作;第一版不声明这两项能力,子 agent 在自己的进程中自给自足。 +- **递归。** 如果不设限制,进程内子 agent 能看到委派工具并递归调用。进程内后端实现了可选的绝对深度限制和有作用域的实时全局 `toolFilter`;ACP 声明这两项能力为关闭状态,并拒绝此类请求。[subagent 组合控制 RFC](2026-07-12-subagent-persona-tool-filter-and-depth.md) 负责定义它们的确切语义和安全边界。 +- **阻塞父轮次。** 同步收集在子 agent 的整个持续时间内保持父 agent 的 `runStep` 打开。这对首版是可接受的;**后台 / 轮询 / 溢出语义推迟到未来的重新设计,该设计将统一 subagent 和 bash 的长时间运行工具处理**(一个 subagent 和一个长时间运行的 `bash` 后台任务面临相同的问题——「模型启动了一个慢操作,之后如何收集结果」——应共享一套机制,而非各自发明)。 +- **实时进度。** 本版仅暴露生命周期事件与最终结果;逐分片的子→父更新流推迟到后台重新设计时一并处理。 +- **ACP 客户端接口。** 将 ACP 子 agent 的 `fs`/`terminal` 代理回父 agent(共享工作区模式)是后续工作;首版不声明这两项能力,子 agent 在自己的进程中自行服务。 diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml index a34398b188..2939af3939 100644 --- a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-22-acp-subagent-backend.md: 7eb03ddf68f54c29524944e7b8bc801eb1724fe6 -2026-06-22-acp-subagent-backend.zh.md: 6f7b95318a2c714fea43a584ba49da00a7c12040 +2026-06-22-acp-subagent-backend.zh.md: 249f5a5ebf18d42f3d83d2159f6c2bcb52a245c3 diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md index 6f7b95318a..249f5a5ebf 100644 --- a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md @@ -1,57 +1,57 @@ # RFC:ACP subagent 后端(进程外委派) -Status: implemented - [English](2026-06-22-acp-subagent-backend.md) | 中文 +Status: implemented + ## 问题 -subagent seam(见 [seam RFC](2026-06-21-subagent-capability-seam.md))的设计使得多个后端可以按名称共存于 `ctx.subagents` 上。进程内后端(`-spawn`/`-fork`)将子 agent 作为同一个 Cordis 上下文上的第二个 `Agent` 运行——开销低,但子 agent 与父 agent 共享进程、模型客户端和工具。seam 的核心意义正是还要支持通过协议到达的进程外子 agent,以证明这层抽象能跨越进程边界泛化。本 RFC 添加第一个此类后端:一个 ACP(Agent Client Protocol)客户端。 +subagent seam([seam RFC](2026-06-21-subagent-capability-seam.md))的设计使多个后端可以按名称共存于 `ctx.subagents`。进程内后端(`-spawn`/`-fork`)将子 agent(智能体)作为第二个 `Agent` 运行在**同一个** Cordis 上下文上:开销低,但子 agent 与父 agent 共享进程、模型客户端和工具。seam 的核心意义在于同时支持通过协议到达的**进程外**子 agent,以证明该抽象能跨越进程边界泛化。本 RFC 添加第一个此类后端:一个 ACP(Agent Client Protocol)客户端。 ## 决策 -`@deepseek-ai/dsh-subagent-acp` 注册一个 `SubagentProvider`,将每个子 agent 运行在一个**派生的子进程**中,以 ACP *客户端*身份驱动。它是现有服务端桥接 `@deepseek-ai/dsh-acp`(ACP *agent*)的方向反转孪生体:桥接**应答** `initialize`/`newSession`/`prompt`;本后端**调用**它们并**实现** `Client` 回调(`sessionUpdate`、`requestPermission`)。将配置的 spawn 命令指向 `acp-agent` 示例,即可让 harness 与自身进程对话。 +`@deepseek-ai/dsh-subagent-acp` 注册一个 `SubagentProvider`,将每个子 agent 运行在一个**派生的子进程**中,并以 ACP *客户端*身份驱动它。它是现有服务端桥接 `@deepseek-ai/dsh-acp`(ACP *agent*)的方向反转孪生体:桥接**应答** `initialize`/`newSession`/`prompt`;本后端**调用**它们并**实现** `Client` 回调(`sessionUpdate`、`requestPermission`)。将配置的 spawn 命令指向 `acp-agent` 示例,即可让 harness 与自身进程通信。 -### 每次运行启动新进程 +### 每次运行启动全新进程 -每次 `start` 都 spawn 一个新子进程,运行恰好一个 ACP 会话(`initialize` → `newSession` → `prompt`),`dispose` 杀死子进程并等待其退出。这是最简单的生命周期,与进程内「每次运行一个子 agent」的形态一致。 +每次 `start` 都 spawn 一个新的子进程,运行恰好一个 ACP 会话(`initialize` → `newSession` → `prompt`),`dispose` 杀死子进程并等待其退出。这是最简单的生命周期,与进程内「每次运行一个子 agent」的形态一致。 -### 最小客户端桩 +### 最小化客户端桩 -客户端不声明任何可选能力(无 `fs`、无 `terminal`):子 agent 在自己的进程中自行处理文件/终端访问。`session/update` 通知被消费——后端累积 `agent_message_chunk` 文本作为结果输出,在本次实现中忽略其余内容(思考、工具调用卡片),仅呈现子 agent 的最终回答。`session/request_permission` 由配置的策略自动应答(`reject` 拒绝每个提示,`allow` 通过第一个 allow 形态的选项批准)——本次实现不将任何提示呈现给人类。将 `fs`/`terminal` 代理回父进程(共享工作区模式)仍是未来工作,如 seam RFC 所述。 +客户端不声明任何可选能力(无 `fs`、无 `terminal`):子 agent 在自己的进程中自行处理文件/终端访问。`session/update` 通知被消费:后端将 `agent_message_chunk` 文本累积为结果输出,在本阶段忽略其余内容(思考、工具调用卡片),仅暴露子 agent 的最终回答。`session/request_permission` 由配置的策略自动应答(`reject` 拒绝所有提示,`allow` 通过第一个允许形态的选项批准)——本阶段不向人类暴露任何权限提示。将 `fs`/`terminal` 代理回父进程(共享工作区模式)仍为后续工作,如 seam RFC 所述。 ### 无启动时能力 -提供方的 `capabilities` 全部为 `false`。进程外子 agent 无法遵守父 agent 的 `maxDepth`(它无法访问 `parent.options.subagentDepth`)或 `toolFilter`(它拥有自己的工具注册表),且本次实现未实现 `outputSchema`。服务在 `start` 运行之前就会拒绝需要上述任何能力的请求。后端仅注入 `subagents`(而非 `ctx.agents`),并忽略 `request.parent`。 +提供方的 `capabilities` 全部为 `false`。进程外子 agent 无法遵守父 agent 的 `maxDepth`(它无权访问 `parent.options.subagentDepth`)或 `toolFilter`(它拥有自己的工具注册表),本阶段也未实现 `outputSchema`。如果请求需要其中任何一项,服务在 `start` 运行前即拒绝。后端仅注入 `subagents`(而非 `ctx.agents`),并忽略 `request.parent`。 ### StopReason 映射 -ACP `StopReason` → harness `SubagentStopReason`:`end_turn`→`completed`、`max_tokens`→`max-tokens`、`refusal`→`refusal`、`cancelled`→`aborted`、`max_turn_requests`→`error`(无对等语义——任务未完成)、未知→`error`。spawn/传输/RPC 失败解析为 `error`(如果已请求取消则为 `aborted`);按 seam 契约,`result` 永远不会因子 agent 级别的失败而 reject。 +ACP `StopReason` → harness `SubagentStopReason`:`end_turn`→`completed`、`max_tokens`→`max-tokens`、`refusal`→`refusal`、`cancelled`→`aborted`、`max_turn_requests`→`error`(无对等语义,任务未完成)、未知→`error`。spawn/传输/RPC 失败解析为 `error`(如果已请求取消则为 `aborted`);按 seam 契约,`result` 在子 agent 级别失败时从不 reject。 ### 安全:清洗子进程环境 -子 agent 是独立进程,因此会继承环境变量。凭证形态的环境变量(`/KEY|SECRET|TOKEN/i`)默认**不**转发——父 harness 自身的密钥不得隐式泄漏到派生进程中(与 bash 执行器采用的策略相同)。子 agent **自身**的凭证(它需要模型密钥)通过 `config.env` **显式**提供,在清洗之后叠加,因此有意传入的 `DEEPSEEK_API_KEY` 得以保留,而偶然存在的 `AWS_SECRET_ACCESS_KEY` 不会。子进程 stderr 继承到父进程的 stderr(诊断信息自然浮现);spawn 级别的 `error` 事件(如命令不存在时的 ENOENT)被捕获并与 ACP 驱动竞争,使错误命令解析为 `error` 而非以未处理错误崩溃父进程。 +子 agent 是独立进程,因此会继承环境变量。形如凭证的环境变量(`/KEY|SECRET|TOKEN/i`)默认**不**转发——父 harness 自身的密钥不得隐式泄露到派生进程中(与 bash 执行器采用的策略相同)。子 agent **自己**的凭证(它需要模型密钥)通过 `config.env` **显式**提供,在清洗之后叠加,因此有意传入的 `DEEPSEEK_API_KEY` 得以保留,而偶然存在的 `AWS_SECRET_ACCESS_KEY` 则不会。子进程的 stderr 继承到父进程的 stderr(诊断信息自然浮现);spawn 级别的 `error` 事件(如命令不存在时的 ENOENT)被捕获并与 ACP 驱动竞速,因此错误命令解析为 `error` 而非以未处理错误崩溃父进程。 ## 测试 -- **无需密钥的单元/集成测试:** 一个脚本化的 ACP 子进程通过真实 stdio 测试 prompt/output 流、所有 stop-reason 映射、信号与 dispose 取消(包括 pre-abort、pre-session 竞态和管道断裂场景)、两种权限策略、被忽略的非消息更新、命令缺失时的清理、提供方重载,以及命名空间导出。 -- **需要密钥的 e2e 测试:** 后端 spawn 真实的 ACP 示例;其模型回答 `PONG`、写入 `proof.txt`,父进程验证该文件。 -- **快照缺口:** 每个 ACP 子 agent 是独立进程、拥有自己的回放会话,不同于进程内的按会话回放。确定性 mock-server 覆盖已有;`TODO(acp-subagent-replay)` 跟踪父 agent 对回放中子 agent 的回放支持。 +- **无需密钥的单元/集成测试:** 一个脚本化的 ACP 子进程通过真实 stdio 测试 prompt/output 流、所有 stop-reason 映射、信号与 dispose 取消(包括 pre-abort、pre-session 竞态和管道断裂场景)、两种权限策略、被忽略的非消息更新、命令缺失时的清理、提供方重载以及命名空间导出。 +- **需要密钥的 e2e 测试:** 后端 spawn 真实的 ACP 示例;其模型回答 `PONG`,写入 `proof.txt`,父进程验证该文件。 +- **快照缺口:** 每个 ACP 子 agent 是独立进程,拥有自己的回放会话,不同于进程内的按会话回放。确定性 mock 服务器覆盖率已具备;`TODO(acp-subagent-replay)` 跟踪父进程对回放中子 agent 的回放支持。 ## 曾考虑的替代方案 ### 为何继续使用 SDK 0.25.1? -后端仅需 `ClientSideConnection`、`ndJsonStream`、`PROTOCOL_VERSION` 和客户端协议类型,0.25.1 均已支持。0.28 的 fluent API 需要在 ACP 层同时迁移客户端和服务端连接类,但不会改善本后端,因此升级作为独立变更保留。 +后端只需要 `ClientSideConnection`、`ndJsonStream`、`PROTOCOL_VERSION` 和客户端协议类型,0.25.1 全部支持。0.28 的 fluent API 需要在 ACP 层同时迁移客户端和服务端连接类,却不会改善本后端,因此升级作为独立变更保留。 ### 为何不使用持久子进程? -持久进程池(跨运行复用热子进程)是一项性能优化,推迟到未来工作——它引入会话生命周期和崩溃恢复的复杂性,本次实现不需要;每次 `start` spawn 新子进程与进程内「每次运行一个子 agent」的形态一致。 +持久进程池(跨运行复用热子进程)是一项性能优化,推迟到后续工作。它增加了会话生命周期和崩溃恢复的复杂度,本阶段不需要;每次 `start` spawn 全新子进程与进程内「每次运行一个子 agent」的形态一致。 ## 后果 -每次运行都要付出一个新子进程的开销(spawn + `initialize` + `newSession`)。父 agent 仅呈现子 agent 的最终回答:`session/update` 中的思考和工具调用卡片被消费后丢弃,权限提示永远不会到达人类——由配置的策略应答。子进程环境默认经过凭证清洗,因此其自身的模型密钥须通过 `config.env` 显式提供。 +每次运行都要付出一个全新子进程的代价(spawn + `initialize` + `newSession`)。父进程仅暴露子 agent 的最终回答:`session/update` 中的思考和工具调用卡片被消费后丢弃,权限提示从不到达人类——由配置的策略应答。子进程环境默认经过凭证清洗,因此其自身的模型密钥需通过 `config.env` 显式提供。 -## 未来提供方 +## 后续提供方 同样的进程外 spawn/prompt/stream/cancel 形态可泛化到 seam RFC 中列出的其他传输方式——A2A、Codex app-server 和 Claude Code Agent SDK——每个都是按名称注册的兄弟提供方。ACP 后端证明了 seam 支持跨进程边界;其余在机制上类似。 diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml index c46a38e46f..30f57427e2 100644 --- a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-25-ask-user-question.md: 06673233038d10214f8de3d1f29766d43b575442 -2026-06-25-ask-user-question.zh.md: 01d1284dba3622984d5403f94e3edd0ba02583b6 +2026-06-25-ask-user-question.zh.md: a036220fd54e3f634ab4be80a45964b076d3fd2d diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md index 01d1284dba..a036220fd5 100644 --- a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md @@ -1,51 +1,51 @@ # RFC:ask-user 提问能力 -Status: implemented - [English](2026-06-25-ask-user-question.md) | 中文 +Status: implemented + ## 问题 -agent(智能体)有时仅凭模型推理(inference)无法安全地继续:它需要人类选择路径、确认有风险或默认的操作,或提供缺失的信息。在此变更之前,获取答案的唯一方式是模型在 assistant 文本中提问然后停止,这会打断正常的工具调用循环:agent 没有结构化的暂停手段,没有供 UI 使用的选项元数据,没有中止/错误分类体系,也没有让非 stdio 前端一致地呈现问题的方式。 +agent(智能体)有时仅凭模型推理(inference)无法安全地继续执行:它需要人类选择路径、确认有风险的或默认的操作,或者提供缺失的信息。在此变更之前,获取答案的唯一方式是模型在 assistant 文本中提问然后停止,这打断了正常的工具调用循环:agent 没有结构化的暂停方式,没有供 UI 使用的选项元数据,没有中止/错误分类体系,也没有让非 stdio 前端一致地呈现问题的途径。 -这是一个面向用户的能力,但它也跨越了包(package)边界。模型侧的工具需要一套提供方无关的请求词汇;每个 UI 表面需要决定如何展示和收集答案;agent loop(智能体循环)应保持不变,因为工具调用本身已具备正确的异步形态。 +这是一个面向用户的能力,但它也跨越了包(package)边界。面向模型的工具需要一套提供方无关的请求词汇;每个 UI 界面需要决定如何展示和收集答案;agent loop(智能体循环)应保持不变,因为工具调用本身已具备正确的异步形状。 ## 决策 -引入 `dsh-user-interaction` 作为 `ctx.userInteraction` 的提供方无关接口包,与模型侧消费方 `dsh-tool-ask-user` 一同放在 `packages/ui` 下。这一分组是有意为之:向人类提问是一种由 UI 支撑的产品能力,不属于无提供方的核心主干。seam 仍然拥有稳定的请求/应答/错误词汇,而 UI 产品表面提供收集答案的具体 provider。工具注册 `ask_user_question`,转发 `{ questions, agent, signal }`,并将 provider 计算出的结构化答案作为工具结果返回。 +引入 `dsh-user-interaction` 作为 `ctx.userInteraction` 的提供方无关接口包,与面向模型的消费方 `dsh-tool-ask-user` 一同放在 `packages/ui` 下。这一分组是有意为之的:向人类提问是一种由 UI 支撑的产品功能,不属于无提供方的核心主干。seam 仍然拥有稳定的请求/应答/错误词汇,而 UI 产品界面提供收集答案的具体 provider。该工具注册 `ask_user_question`,转发 `{ questions, agent, signal }`,并将 provider 计算出的结构化答案作为工具结果返回。 -模型侧的请求词汇有意与产品研究 schema 对齐:`ask_user_question({ questions: [{ id, question, header?, options?: [{ label, description? }], multi_select? }] })`。`id` 按问题提供并在结果中回传,使批量请求可以路由而不依赖问题文本。`label` 既是面向用户的显示文本,也是返回给模型的选中值;没有单独的 `value`,没有 `recommended`,没有 `allow_custom`,也没有 `desc` 别名。 +面向模型的请求词汇有意与产品调研 schema 对齐:`ask_user_question({ questions: [{ id, question, header?, options?: [{ label, description? }], multi_select? }] })`。`id` 按问题提供并在结果中回传,使批量请求无需依赖问题文本即可路由。`label` 既是面向用户的显示文本,也是返回给模型的选中值;没有单独的 `value`,没有 `recommended`,没有 `allow_custom`,也没有 `desc` 别名。 -provider 返回 `{ answers: [{ id, selected, custom? }] }`。`selected` 始终是选中选项 label 的数组,因此单选和 `multi_select` 的答案共享同一种结果形态。`custom` 承载自由文本的「其他」答案;无选项的问题直接收集 `custom`。当 `custom` 存在时,它覆盖所有已选选项,`selected` 为空。 +Provider 返回 `{ answers: [{ id, selected, custom? }] }`。`selected` 始终是选中选项 label 的数组,因此单选和 `multi_select` 的答案共享同一种结果形状。`custom` 承载自由文本的「其他」答案;无选项的问题直接收集 `custom`。当 `custom` 存在时,它覆盖任何已选择的选项,`selected` 为空。 -`UserInteractionError` 继承 `HarnessError`,因此 `NO_PROVIDER`、`ASK_ABORTED`、ACP 取消或会话路由缺失等失败会以可机器路由的 `{ name, code }` 工具错误形式通过 `ctx.tools.execute()` 传出。这与结构化错误分类体系一致,使模型或包装插件能区分「用户取消」与通用抛出异常。 +`UserInteractionError` 继承 `HarnessError`,因此 `NO_PROVIDER`、`ASK_ABORTED`、ACP(Agent Client Protocol)取消或会话路由缺失等失败会以机器可路由的 `{ name, code }` 工具错误形式通过 `ctx.tools.execute()` 传出。这与结构化错误分类体系一致,使模型或包装插件能够区分「用户取消」与一般的抛出异常。 ## UI 映射 -`dsh-stdio-demo` 的包内 readline 模块逐题渲染每个问题,在下一行展示每个选项的 `description`,支持以逗号/空格分隔的数字选择 `multi_select`,接受自由格式的自定义答案,并在中止、provider dispose(资源释放)或 stdin EOF 时拒绝待处理的问题。批量请求按顺序逐题询问,合并为一个答案对象返回。stdio provider 通过内部队列序列化并发请求,确保同一时刻只有一个 prompt 占用 stdin。 +`dsh-stdio-demo` 的包内 readline 模块渲染每个问题,在下一行显示每个选项的 `description`,支持以逗号/空格分隔的数字选择 `multi_select`,接受自由格式的自定义答案,并在中止、provider dispose(资源释放)或 stdin EOF 时拒绝待处理的问题。批量请求按顺序询问,作为一个答案对象整体解析。stdio provider 通过内部队列序列化并发请求,确保同一时刻只有一个提示占用 stdin。 -`dsh-acp` 为 ACP(Agent Client Protocol)会话提供同一 seam。它通过 bridge 的 `agent→sessionId` 反向映射将调用方 `Agent` 的 ask 请求路由到对应会话,并为每个问题调用 ACP `unstable_createElicitation`(携带会话作用域的表单)。单选选项变为 `choice` 字符串枚举;`multi_select` 选项变为 `choice` 数组枚举;无选项问题使用必填的 `custom` 文本字段。如果客户端同时返回 `choice` 和非空 `custom`,以 custom 答案为准。ACP `decline`/`cancel`、缺失答案、缺失会话以及客户端不支持 elicitation 的情况都会变为结构化的 `UserInteractionError`。 +`dsh-acp` 为 ACP 会话提供同一 seam。它通过 bridge 的 `agent→sessionId` 反向映射将调用方 `Agent` 的 ask 请求路由出去,并为每个问题调用 ACP `unstable_createElicitation`(附带会话范围的表单)。单选选项变为 `choice` 字符串枚举;`multi_select` 选项变为 `choice` 数组枚举;无选项的问题使用必填的 `custom` 文本字段。如果客户端同时返回 `choice` 和非空 `custom`,以 custom 答案为准。ACP `decline`/`cancel`、缺失答案、缺失会话以及客户端不支持 elicitation,都会转为结构化的 `UserInteractionError`。 ACP 映射有意使用 elicitation 而非 `session/request_permission`。`request_permission` 仍保留给独立的权限门禁:它是围绕工具执行的 yes/no 或策略式授权协议。`ask_user_question` 是一个通用的信息收集工具,支持可选的自由格式答案,因此 ACP 表单 elicitation 是更贴合的协议。bridge 的会话路由与未来的权限门禁共享,但用户意图不同。 ## 曾考虑的替代方案 -**Assistant 文本后跟一个停止的轮次。** 模型可以在纯 assistant 文本中向用户提问然后停止。这会丢失结构化的选项元数据,UI 没有提供方无关的方式来渲染选择,且下一条人类回答只能作为新的 user prompt 到达,而非作为需要答案的那次操作的结果。 +**Assistant 文本后跟一个停止的轮次。** 模型可以在纯 assistant 文本中向用户提问然后停止。这会丢失结构化选项元数据,UI 没有提供方无关的方式来渲染选择,且下一条人类回答只能作为新的 user prompt 到达,而非作为需要答案的那次操作的结果。 -**核心包拥有 ask-user 相关包。** 最初实现将 seam 和模型侧工具分别放在 `packages/core` 和 `packages/ui`,但两者描述的是同一个由 UI 支撑的人机交互能力。seam 仍然是提供方无关的,但它不是像会话、工具或 agent 注册表那样的无提供方核心基础设施。将 `dsh-user-interaction` 和 `dsh-tool-ask-user` 一起放在 `packages/ui` 下,使包结构与产品边界一致:应用和 bridge 提供人类答案的 provider,stdio 应用选择性加载模型侧工具。 +**核心拥有的 ask-user 包。** 最初实现将 seam 和面向模型的工具分别放在 `packages/core` 和 `packages/ui`,但两者描述的是同一个由 UI 支撑的人机交互功能。seam 仍然是提供方无关的,但它不是像会话、工具或 agent 注册表那样的无提供方核心基础设施。将 `dsh-user-interaction` 和 `dsh-tool-ask-user` 一起放在 `packages/ui` 下,使包的划分与产品边界一致:应用和 bridge 提供人类答案的 provider,stdio 应用选择性加载面向模型的工具。 **ACP `session/request_permission`。** 权限请求是围绕工具执行的授权;`ask_user_question` 是带可选自由格式答案的信息收集。将权限用于通用提问会混淆两个不同的产品概念,并使未来的权限门禁更难推理。 -**循环级别的暂停原语。** agent loop 已经知道如何等待工具调用并从工具结果恢复。新增一个循环特例会重复这一异步形态,并迫使每个循环实现都了解一个 UI 关注点。 +**循环级别的暂停原语。** agent loop 已经知道如何等待工具调用并从工具结果恢复。添加新的循环特殊分支会重复这一异步形状,并迫使每个循环实现都了解一个 UI 关注点。 ## 后果 -ACP elicitation 目前在 SDK 中标记为 unstable。回退仍然是结构化的:如果客户端未实现它,工具返回 `ASK_FAILED` 而非挂起。后续 ACP 稳定化可能重命名或重塑该方法;该迁移应留在 `dsh-acp` 内部,因为核心 `ctx.userInteraction` 词汇是提供方无关的。 +ACP elicitation 目前在 SDK 中标记为 unstable。回退仍然是结构化的:如果客户端未实现它,工具返回 `ASK_FAILED` 而非挂起。后续 ACP 稳定化可能重命名或重塑该方法;该迁移应限制在 `dsh-acp` 内部,因为核心 `ctx.userInteraction` 词汇是提供方无关的。 -该特性赋予模型一个强大的暂停原语,因此提示词引导很重要。工具描述告诉模型提问要简洁、尽可能使用选项。产品策略后续可以包装 `tools/execute` 来限制工具何时可用,但循环不应对其做特殊处理。 +该功能赋予模型一个强大的暂停原语,因此 prompt 引导很重要。工具描述告诉模型:提问要简洁,尽可能使用选项。产品策略后续可以包装 `tools/execute` 来限制工具何时可用,但循环不应对其做特殊处理。 -`dsh-user-interaction` 和 `dsh-tool-ask-user` 都位于 `packages/ui`,因为它们共同构成一个面向产品的人机交互能力。`agent-core` 不加载工具或 provider。`stdio-agent` 选择性加载 seam、其 readline provider 和模型侧工具。`acp-agent` 默认只保留 `userInteraction` seam/provider:ACP elicitation 支持仍取决于客户端,因此 ACP 叶子节点必须在其客户端能够完成 elicitation 请求后才有意加载模型侧工具。 +`dsh-user-interaction` 和 `dsh-tool-ask-user` 都位于 `packages/ui`,因为它们共同构成一个面向产品的人机交互能力。`agent-core` 不加载工具或 provider。`stdio-agent` 选择性加载 seam、其 readline provider 和面向模型的工具。`acp-agent` 默认只保留 `userInteraction` seam/provider:ACP elicitation 支持仍取决于客户端,因此 ACP 叶节点必须在其客户端能完成 elicitation 请求后才有意加载面向模型的工具。 ## 测试 -单元覆盖率固定了以下场景:provider 注册/释放、重复 provider 拒绝、provider 就绪前中止、空问题拒绝、通过 `ctx.tools.execute()` 的结构化工具错误、批量答案、多选答案、自定义答案,以及模型 schema(包括移除 `value`、`recommended`、`allow_custom` 和 `desc` 的验证)。`dsh-stdio-demo` 测试覆盖选项描述、排队请求、EOF/中止清理、无选项自由格式输入、无效选项重新提示、重复多选编号和批量问题流程。ACP bridge 测试驱动一个真实的内存 ACP 连接(使用真实的 `ask_user_question` 工具),验证选中选项、custom 覆盖 choice、多选和无选项自由格式 elicitation 路径能继续 agent loop。 +单元覆盖率固定了以下场景:provider 注册/释放、重复 provider 拒绝、provider 就绪前中止、空问题拒绝、通过 `ctx.tools.execute()` 传出的结构化工具错误、批量答案、多选答案、自定义答案,以及模型 schema(包括移除 `value`、`recommended`、`allow_custom` 和 `desc`)。`dsh-stdio-demo` 测试覆盖选项描述、排队请求、EOF/中止清理、无选项自由格式输入、无效选项重新提示、重复多选编号和批量问题流。ACP bridge 测试驱动一个真实的内存 ACP 连接(使用真实的 `ask_user_question` 工具),验证选中选项、custom 覆盖 choice、多选和无选项自由格式 elicitation 路径能继续 agent loop。 diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml index d2c28a3946..677df03ea6 100644 --- a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-29-todo-write-tool.md: 69f81cf6fd93df63ce53bb82c97dbac16dbbd486 -2026-06-29-todo-write-tool.zh.md: a687f5ab4bc5b9fcd5583ca4aac2857ab4c3f513 +2026-06-29-todo-write-tool.zh.md: eb3c6fb8a9ddc7d26e4a620761c96a8d35ddf469 diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md index a687f5ab4b..eb3c6fb8a9 100644 --- a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md @@ -1,4 +1,4 @@ -# RFC:`todo_write` 工具——将模型任务列表建模为事件溯源的会话状态 +# RFC:`todo_write` 工具——将模型任务列表作为事件溯源的会话状态 Status: implemented @@ -6,59 +6,59 @@ Status: implemented ## 问题 -harness 为模型提供了 bash 和 subagent 工具,但没有任何方式记录结构化的任务列表。todo 列表服务于两个同等重要的目的:引导模型规划多步骤工作并保持当前任务明确(最多一个 in_progress,有未完成工作时恰好一个),以及为人类提供实时进度清单。ACP(Agent Client Protocol)协议有原生的 `plan` sessionUpdate,编辑器(Zed)已经在渲染它,但 bridge 从未发出过。调研的每个参考编码 agent(智能体)实现(claude-code、opencode、codex、oh-my-pi、pi)都提供了某种形式的此功能;而 harness 什么都没有。 +harness 为模型提供了 bash 和 subagent 工具,却没有办法记录结构化的任务列表。todo 列表有两个同等重要的用途:引导模型规划多步骤工作并保持当前活跃任务明确(最多一个活跃,有剩余工作时恰好一个);同时为人类提供实时进度清单。ACP(Agent Client Protocol)协议原生支持 `plan` sessionUpdate,编辑器(Zed)已能渲染它,但 bridge 从未发出过。调研的所有参考编码 agent(智能体)(claude-code、opencode、codex、oh-my-pi、pi)都提供了某种形式的此功能;本 harness 此前没有。 ## 决策 -新增一个面向模型的 `todo_write(todos: [{ content, status }])` 工具,其全量列表状态以新的 `todo/write` `SessionEventMap` 变体存在于事件溯源的会话日志上。stdio UI 和 ACP bridge 都从既有的 `session/event` 渲染——ACP bridge 将列表映射为 `plan` sessionUpdate。 +新增一个面向模型的 `todo_write(todos: [{ content, status }])` 工具,其整列表状态作为新的 `todo/write` `SessionEventMap` 变体存储在事件溯源的会话日志上。stdio UI 和 ACP bridge 均从现有的 `session/event` 渲染;ACP bridge 将列表映射为 `plan` sessionUpdate。 -### 全量替换,三态 status +### 整列表替换,三态 status -模型每次调用发送**完整**列表;新列表替换旧列表(回放时 last-write-wins)。这是 claude-code V1、opencode 和 codex `update_plan` 共同使用的形态,也是模型训练最多的形态——没有逐项 id,没有 delta 协议。`status` 恰好是 `pending | in_progress | completed`:与 codex `update_plan` 相同的三元组,且关键的是**与 ACP `PlanEntryStatus` 完全一致**,因此 bridge 做 1:1 映射,无损失转换。 +模型每次调用发送**完整**列表;新列表替换旧列表(回放时 last-write-wins)。这是 claude-code V1、opencode 和 codex `update_plan` 共同采用的形状,也是模型训练最多的形状——没有逐项 id,没有 delta 协议。`status` 恰好是 `pending | in_progress | completed`:与 codex `update_plan` 相同的三元组,且关键的是**与 ACP `PlanEntryStatus` 完全一致**,bridge 因此可以 1:1 映射,无需有损转换。 ### 状态在会话日志上,而非服务 -列表以 `todo/write` 事件追加,携带完整的 `{ todos }` 快照。harness 是事件溯源的——LLM(大语言模型)历史、工具调用和轮次结构都在日志上——所以 todo 列表也在那里。这免费获得了持久性、回放和 `session/load` 重建:重新打开的会话从最后一条 `todo/write` 重新推导当前列表,ACP bridge 在加载时重新发出 `plan`,无需独立的持久化后端、无需重新注水的内存服务、无需额外接线。一个内存中的 `ctx.todos` 服务需要重新发明所有这些。 +列表作为 `todo/write` 事件追加到日志,携带完整的 `{ todos }` 快照。harness 是事件溯源的——LLM(大语言模型)历史、工具调用和轮次结构都在日志上——所以 todo 列表也在那里。这免费获得了持久性、回放和 `session/load` 重建:重新打开的会话从最后一条 `todo/write` 重新推导当前列表,ACP bridge 在加载时重新发出 `plan`,无需独立的持久化后端、无需重新注水的内存服务、无需额外接线。一个内存中的 `ctx.todos` 服务需要重新发明以上所有。 ### 不是 surface 事件 -`todo/write` 被刻意排除在 `SurfaceEventType` 之外。surface 是产出 LLM 消息历史(`deriveMessages()`)的投影;一次 todo write 不产生对话消息。因此它不携带 `surfaceOp`,不加入 surface 链表,不进入 `deriveMessages()`——它是持久的、可回放的 *UI* 状态,伴随对话传播但不属于对话的一部分。(开发模式的不变式仍要求它位于一个打开的轮次内,事实也确实如此:它在工具调用的 mid-step 阶段追加。) +`todo/write` 被有意排除在 `SurfaceEventType` 之外。surface 是产出 LLM 消息历史(`deriveMessages()`)的投影;todo write 不产生对话消息。因此它不携带 `surfaceOp`,不加入 surface 链表,不进入 `deriveMessages()`——它是持久、可回放的 *UI* 状态,与对话并行传输但不属于对话的一部分。(dev-mode 不变式仍要求它位于一个打开的轮次内,而它始终如此:它在工具调用的步骤中途追加。) -### priority 仅在 ACP 边界合成 +### Priority 仅在 ACP 边界合成 -ACP 的 `PlanEntry` 要求 `content` + `priority` + `status`,但 `TodoItem` 没有 priority——模型从不推理它。与其在 schema 中增加一个模型每次都必须提供的字段,不如让 bridge 在构建 `plan` 时为每个条目合成一个常量 `priority: 'medium'`。priority 是 ACP 协议格式(wire format)的要求,不是 harness 的概念,因此它恰好存在于需要它的边界处。 +ACP 的 `PlanEntry` 要求 `content` + `priority` + `status`,但 `TodoItem` 没有 priority——模型从不推理它。与其在 schema 中增加一个模型每次都必须提供的字段,bridge 在构建 `plan` 时为每条条目合成常量 `priority: 'medium'`。Priority 是 ACP 协议格式(wire format)的要求,不是 harness 概念,因此它恰好存在于需要它的边界上。 -### 相比 claude-code V1 去掉的字段:`activeForm`、id、priority +### 相比 claude-code V1 舍弃的字段:`activeForm`、id、priority -claude-code V1 的 item 是 `{ content, status, activeForm }`;后来(V2)增加了 id、依赖和所有权——但那只是为了支持 agent *集群*(磁盘持久化、锁保护、逐项变更)。本工具将 item 保持在最小集:`{ content, status }`。没有 `activeForm`(现在进行时标签)——UI 直接展示 `content`;没有 id——全量替换不需要稳定标识;没有 priority——见上文。每去掉一个字段,模型每次调用就少产出一项。 +claude-code V1 的条目是 `{ content, status, activeForm }`;后来(V2)增加了 id、依赖和所有权——但仅为支持 agent *集群*(磁盘持久、锁保护、逐项变更)。本工具将条目保持在最小集:`{ content, status }`。不要 `activeForm`(现在进行时标签)——UI 直接展示 `content`;不要 id——整列表替换不需要稳定标识;不要 priority——见上文。每舍弃一个字段,模型每次调用就少产出一项。 ### 单一所有者——无集群机制(YAGNI) -每个列表属于调用方 agent 会话,非 agent 调用会被拒绝。没有共享作用域、resolver 或 delta 协议。跨 agent 列表需要逐项日志 delta 和显式作用域选择,因此留作未来独立设计。 +每个列表属于调用它的 agent 会话,非 agent 调用被拒绝。没有共享作用域、resolver 或 delta 协议。跨 agent 列表需要逐项日志 delta 和显式作用域选择,因此留作未来独立设计。 ### 校验:低成本的中间路线 -schema 强制 type/required/enum。在此之上,`execute` 拒绝空 `content`、重复 `content` 以及多于一个 `in_progress` 任务。claude-code 将 single-in-progress 留给 prompt;oh-my-pi 在代码中强制。我们取中间路线:强制那些使计划*连贯*的低成本不变式(无空白任务、无重复、最多一个活跃),但将排序和保持列表最新的纪律通过工具描述留给模型。被拒绝的写入返回 `isError` 结果,模型可自行修正。 +schema 强制 type/required/enum。在此之上,`execute` 拒绝空 `content`、重复 `content`,以及超过一个 `in_progress` 任务。claude-code 将单一 in_progress 交给 prompt 约束;oh-my-pi 在代码中强制。我们取中间路线:强制执行使计划*连贯*的低成本不变式(无空任务、无重复、最多一个活跃),但将排序和保持列表最新的纪律通过工具描述交给模型。被拒绝的写入返回 `isError` 结果,使模型自行修正。 -## 为什么没有 cordis-catalog 条目 / 没有 `@mode` +## 为何没有 cordis-catalog 条目 / 没有 `@mode` -`todo/write` 是 `SessionEventMap` 的成员,不是一等的 cordis `interface Events` 事件。catalog 生成器(`scripts/gen-cordis-catalog.ts`)扫描 `interface Events` 声明;`SessionEventMap` 变体搭载既有的 `session/event` emit,不产生新的 catalog 行。因此它不携带 `@mode` 标签(生成器仅对 `interface Events` 成员要求此标签)——加上它也没有意义。 +`todo/write` 是 `SessionEventMap` 的成员,不是一等的 cordis `interface Events` 事件。catalog 生成器(`scripts/gen-cordis-catalog.ts`)扫描 `interface Events` 声明;`SessionEventMap` 变体搭载现有的 `session/event` emit,不产生新的 catalog 行。因此它不携带 `@mode` 标签(生成器仅对 `interface Events` 成员要求该标签)——添加一个毫无意义。 ## 测试 -四层,预先设计: -- **单元测试**——会话事件(append/snapshot-clone/last-write-wins/not-on-surface);工具(schema 形状、通过真实 `ctx.tools.execute` 的参数校验、值校验、事件追加与替换、非 agent 拒绝、`presentCall`、HMR 安全性);ACP `todosToPlan` 映射;stdio 渲染分支。 -- **真实 Loader 路径**——插件通过 `Loader.unwrapExports` 运行,断言命名空间导出形状存活(它有 `inject`,因此一个意外的 default 导出会在加载时崩溃——postmortem/0001)。 -- **全链路集成**——一个脚本化的 mock 模型通过真实 agent loop(智能体循环)调用 `todo_write`;`todo/write` 事件落地,第二次调用替换它。 -- **`session/load` 回放**——一条持久化的 `todo/write` 在新的 ACP bridge 加载会话时重新发出 `plan` 更新。 -- **带 key 的 e2e + 快照**——一个真实 prompt 诱导 `todo_write`;快照 golden 新增 `plan` 通知和日志事件。 +四个层级,预先设计: +- **单元测试**——会话事件(append/snapshot-clone/last-write-wins/not-on-surface);工具(schema 形状、通过真实 `ctx.tools.execute` 的参数校验、值校验、事件追加与替换、非 agent 拒绝、`presentCall`、HMR(热模块替换)安全性);ACP `todosToPlan` 映射;stdio 渲染分支。 +- **真实 Loader 路径**——插件通过 `Loader.unwrapExports` 运行,断言命名空间导出形状存活(它**有** `inject`,因此一个意外的 default 导出会在加载时崩溃——postmortem/0001)。 +- **全循环集成**——一个脚本化的 mock 模型通过真实 agent loop(智能体循环)调用 `todo_write`;`todo/write` 事件落地,第二次调用替换它。 +- **`session/load` 回放**——持久化的 `todo/write` 在新的 ACP bridge 加载会话时重新发出 `plan` 更新。 +- **带密钥 e2e + 快照**——真实 prompt 诱导一次 `todo_write`;快照 golden 获得 `plan` 通知和日志事件。 ## 曾考虑的替代方案 - **内存中的 `ctx.todos` 服务**——需要重新发明日志免费提供的持久性、回放和 `session/load` 重建。 -- **逐项 delta 协议**——仅在共享多所有者列表时需要,不在本次范围内;全量替换更简单且与参考实现一致。 -- **工具放在 `core/`**——`todo_write` 是注册在 `ctx.tools` 上的扩展工具,不属于主干;它与其他工具族一样放在自己的 `packages/todo/` 分组中。 +- **逐项 delta 协议**——仅在共享多所有者列表时需要,超出当前范围;整列表替换更简单,且与参考实现一致。 +- **工具放在 `core/` 中**——`todo_write` 是注册在 `ctx.tools` 上的扩展工具,不属于主干;它像其他工具族一样位于自己的 `packages/todo/` 分组中。 ## 后果 -todo 列表是持久的、可回放的会话状态:一条持久化的 `todo/write` 在 `session/load` 时重新向编辑器发出 `plan` 更新,日志(而非插件内存)是唯一真源。全量替换意味着每次更新一次工具调用、last-write-wins;没有需要协调的 delta 协议。事件不进入 surface,因此 todo 更新永远不会扰动推导出的模型历史——模型只看到自己的工具调用和结果。 +todo 列表是持久、可回放的会话状态:持久化的 `todo/write` 在 `session/load` 时重新发出编辑器的 `plan` 更新,日志(而非插件内存)是唯一真源。整列表替换意味着每次更新一次工具调用,last-write-wins;没有需要协调的 delta 协议。事件不进入 surface,因此 todo 更新永远不会扰动推导出的模型历史——模型只看到自己的工具调用和结果。 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml index 5402e85e81..03e276e446 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-30-hook-bridges.md: 17ff57307c34121c845592efa93c723e66c98886 -2026-06-30-hook-bridges.zh.md: 2a94d5cca2f490e4aac493fe357a825ad3b4d271 +2026-06-30-hook-bridges.zh.md: a4b8c12593cdac35deb882ba15a58876650c1653 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md index 2a94d5cca2..a4b8c12593 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md @@ -1,4 +1,4 @@ -# RFC:dsh-hooks-claude + dsh-hooks-codex——Claude Code / Codex 钩子桥接插件 +# RFC:dsh-hooks-claude + dsh-hooks-codex —— Claude Code / Codex 钩子桥接插件 Status: implemented @@ -6,65 +6,65 @@ Status: implemented ## 问题 -harness 的扩展面是其类型化的拦截 seam(见[拦截 seam RFC](2026-06-30-interception-seams.md)):所谓「原生钩子」不过是一个普通的 Cordis 插件,订阅 `agent/session-start`、`agent/prompt-submit`、`tools/pre-execute`、`tools/post-execute`、`agent/turn-continuation`、`subagent/start`、`subagent/end`。但用户带着**已有的** Claude Code(CC)和 Codex 钩子配置到来——一个 `hooks.json`(或设置文件中的 `hooks` 键)里满是 shell 命令钩子——并且希望它们原样运行。本 RFC 引入两个**桥接插件**,将外部 shell 钩子协议翻译到类型化 seam 上,基于共享的协议格式(wire format)库(见 [hook-protocol-lib RFC](2026-06-30-hook-protocol-lib.md))构建。 +harness 的扩展面是其类型化的拦截 seam(见[拦截 seam RFC](2026-06-30-interception-seams.md)):所谓「原生钩子」不过是一个普通的 Cordis 插件,订阅 `agent/session-start`、`agent/prompt-submit`、`tools/pre-execute`、`tools/post-execute`、`agent/turn-continuation`、`subagent/start`、`subagent/end`。但用户带着**既有的** Claude Code(CC)和 Codex 钩子配置到来,一个 `hooks.json`(或 settings 文件中的 `hooks` 键)里满是 shell 命令钩子,并希望它们原样运行。本 RFC 引入两个**桥接插件**,将外部 shell 钩子协议翻译到类型化 seam 上,构建于共享的协议格式(wire format)库之上(见 [hook-protocol-lib RFC](2026-06-30-hook-protocol-lib.md))。 -贯穿整个设计的定位是:**桥接是兼容性适配器,不是高级工具。**桥接能做的事(阻止工具、注入上下文、强制继续、观察 subagent),原生 Cordis 插件都能更强力地完成——有类型化返回值、完整的 `ctx`、无序列化边界。桥接存在的理由是运行外部 CC/Codex 命令钩子中被明确支持的子集。这使每个桥接保持精简:解析配置、选择匹配模式、构建每事件的 payload、调用共享库的 `runHook` + `mergeHookOutputs`,再将中性结果映射到 seam 的 Decision。各 package 的 README 记录了当前相对官方协议的不支持事件与部分字段清单。 +贯穿整个设计的定位:**桥接是兼容性适配器,不是高级工具。** 桥接能做的事(阻止工具、注入上下文、强制继续、观察 subagent),原生 Cordis 插件都能做得更强——类型化返回值、完整 `ctx`、无序列化边界。桥接存在的理由是运行外部 CC/Codex 命令钩子中被明确支持的子集。这使每个桥接保持精简:解析配置、选择匹配模式、构建每事件的 payload、调用共享库的 `runHook` + `mergeHookOutputs`,再将中性结果映射为 seam Decision。各 package 的 README 维护着当前不支持的事件和部分字段的完整清单,以官方协议为参照。 ## 决策 -`packages/hooks/` 分组下两个独立插件,各自为函数/命名空间插件(`name`/`inject`/`Config`/`apply`,无 default export——见 [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md)),仅注入 `bash`: +`packages/hooks/` 组下两个独立插件,各为 function/namespace 插件(`name`/`inject`/`Config`/`apply`,无 default export——见 [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md)),仅注入 `bash`: -- **`dsh-hooks-claude`**——CC 方言。Claude Code 当前钩子点中的七个:`SessionStart`、`UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`Stop`、`SubagentStart` 和 `SubagentStop`。拥有 CC 形状的每事件 stdin payload(基础字段为 `session_id`/`cwd`/`hook_event_name`,加上每事件特有字段)、`CLAUDE_PROJECT_DIR` 环境变量加 `${CLAUDE_PLUGIN_ROOT}`/`${CLAUDE_PROJECT_DIR}` 替换,以及字面量或正则匹配模式。CC 钩子的 stdin 带有**尾随换行**。 -- **`dsh-hooks-codex`**——Codex 当前钩子点中的五个:`PreToolUse`、`PostToolUse`、`SessionStart`、`UserPromptSubmit` 和 `Stop`。使用始终为正则的匹配模式、Codex 形状的 snake_case payload(带 `turn_id`/`model`/`permission_mode` 额外字段),写入时**不带**尾随换行,不注入 Codex 插件环境变量,不做配置时占位符替换,也没有 pre-tool 审批或重写路径。工具调用的 payload 在桥接的精简 `tool_input: { command }` 形状中携带真实的 `tool_name`。 +- **`dsh-hooks-claude`**——CC 方言。Claude Code 当前七个钩子点中的七个:`SessionStart`、`UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`Stop`、`SubagentStart` 和 `SubagentStop`。拥有 CC 形态的每事件 stdin payload(基础字段 `session_id`/`cwd`/`hook_event_name` 加每事件字段)、`CLAUDE_PROJECT_DIR` 环境变量加 `${CLAUDE_PLUGIN_ROOT}`/`${CLAUDE_PROJECT_DIR}` 替换,以及字面量或正则的匹配模式。CC 钩子的 stdin 带有**尾部换行**。 +- **`dsh-hooks-codex`**——Codex 当前五个钩子点中的五个:`PreToolUse`、`PostToolUse`、`SessionStart`、`UserPromptSubmit` 和 `Stop`。使用始终为正则的匹配模式、Codex 形态的 snake_case payload(含 `turn_id`/`model`/`permission_mode` 额外字段),写入时**不带**尾部换行,不注入 Codex 插件环境变量,不做配置时占位符替换,也没有 pre-tool 审批或重写路径。工具调用的 payload 在桥接精简后的 `tool_input: { command }` 形态中携带真实的 `tool_name`。 -### 结果 → Decision 映射 +### Outcome → Decision 映射 每个桥接将共享库返回的中性 `MergedHookOutcome` 映射到 seam 的类型化 Decision: | Seam | CC | Codex | |---|---|---| -| `agent/session-start`(emit) | additionalContext → `agent.inject()` | plain-stdout 输出 → additionalContext → `agent.inject()` | +| `agent/session-start`(emit) | additionalContext → `agent.inject()` | plain-stdout output → additionalContext → `agent.inject()` | | `agent/prompt-submit` | `deny`→`block`;仅上下文→delegate+fold | `block`→`block`;仅上下文→delegate+fold | | `tools/pre-execute` | `deny`→`deny`;`ask`→`ask` | `block`→`deny`(无 allow/ask) | | `tools/post-execute` | `deny`→`block`+feedback;仅上下文→delegate+fold | 同上 | -| `agent/turn-continuation` | 阻塞式 Stop → `continue`(reason = 下一步 steering(中途引导)) | 同上 | -| `subagent/start`(emit) | additionalContext → 注入进程内活跃子 agent;远程子 agent 没有本地注入目标 | 本桥接不支持 | +| `agent/turn-continuation` | 阻塞的 Stop → `continue`(reason = next-step steering(中途引导)) | 同上 | +| `subagent/start`(emit) | additionalContext → 注入到存活的进程内 subagent;远程 subagent 无本地注入目标 | 本桥接不支持 | | `subagent/end`(emit) | 仅观察 | 本桥接不支持 | -CC 桥接的 `ask` 结果是一条真正的权限路径,而非桥接的终态决策:`dsh-tools` 通过可选的[审批 seam](2026-07-06-approval-seam.md) 解析它。组合式 ACP 应答器会向拥有者编辑器会话发起提示,`allowed-once` 后继续执行;如果没有 ApprovalService 或应答器,调用以 `deny` 关闭。 +CC 桥接的 `ask` 结果是一条真正的权限路径,而非终态桥接决策:`dsh-tools` 通过可选的[审批 seam](2026-07-06-approval-seam.md) 来解析它。组合式 ACP 应答器向拥有该会话的编辑器会话发起提示,`allowed-once` 后继续执行;如果没有 ApprovalService 或应答器,调用以 `deny` 安全关闭。 -### 上下文来源始终是插件(错标防护) +### 上下文来源始终是插件(误标签防护) -`agent.inject()` 在缺少 `MessageSource` 时默认为 `{ kind: 'user' }`,因此每个桥接的 `inject()` 和 `HookContext` 都传入 `{ kind: 'plugin', plugin: 'hooks-claude' | 'hooks-codex' }`。单元测试覆盖率固定了最终 `context/message.source` 为插件而非用户。 +`agent.inject()` 在缺少 `MessageSource` 时默认为 `{ kind: 'user' }`,因此每个桥接的 `inject()` 和 `HookContext` 都传入 `{ kind: 'plugin', plugin: 'hooks-claude' | 'hooks-codex' }`。单元测试覆盖率固定验证结果中的 `context/message.source` 为插件而非用户。 ### 添加上下文不是否决——先 delegate,再 fold -仅含上下文的钩子必须调用 `next()` 然后将其 `additionalContext` 折入下游决策;直接返回 allow 或 accept 会绕过后续策略监听器。Post-tool 的 block 和 accept 决策都保留已添加的上下文。Prompt allow 保留上下文,而 prompt block 丢弃上下文,因为提示词从未到达模型。只有显式的钩子 denial 或 block 才会短路 waterfall(瀑布式事件)。 +仅含上下文的钩子必须调用 `next()` 然后将其 `additionalContext` 折叠进下游决策;直接返回 allow 或 accept 会绕过后续策略监听器。Post-tool 的 block 和 accept 决策都保留已添加的上下文。Prompt allow 保留上下文,而 prompt block 丢弃上下文,因为提示词从未到达模型。只有显式的钩子 denial 或 block 才会短路 waterfall(瀑布式事件)。 ### CLAUDE_PROJECT_DIR 默认为会话工作区 -Claude Code 始终导出 `CLAUDE_PROJECT_DIR`,常见的未修改钩子引用 `$CLAUDE_PROJECT_DIR` 来构造项目相对路径。显式的 `config.projectDir` 优先;当它被省略时(默认的 ACP 接线只配置 `configPath`),桥接将该环境变量按每次运行默认为 agent 的会话工作区——即钩子已经运行其中的 `session.header.cwd`——而不是留空。因此一个标准的项目相对钩子在默认配置下即可工作。 +Claude Code 始终导出 `CLAUDE_PROJECT_DIR`,常见的未修改钩子引用 `$CLAUDE_PROJECT_DIR` 来构造项目相对路径。显式的 `config.projectDir` 优先;当它被省略时(默认 ACP 接线只配置 `configPath`),桥接将该环境变量按每次运行默认为 agent(智能体)的会话工作区——即钩子已经在其中运行的 `session.header.cwd`——而非留空。这样,一个标准的项目相对路径钩子在默认配置下即可正常工作。 ### 隔离 -配置在加载时一次性解析;读取/解析失败时记录日志并不注册任何内容,而非崩溃启动(一个拼错的路径不得拖垮 agent)。CC 只运行 shell 形式的 `type: 'command'` 钩子;`http`、`mcp_tool`、`prompt` 和 `agent` 处理器被解析后跳过。Codex 只运行同步命令处理器,跳过 `async: true` 或非命令条目。emit 监听路径(`session-start`、`subagent/start`)以 detached 方式运行,其 `inject` 包裹在 `.catch` 中记录日志(抛异常的 inject 不得中断会话启动或循环)。 +配置在加载时一次性解析;读取/解析失败时记录日志并不注册任何内容,而非崩溃启动(一个拼错的路径不应拖垮 agent)。CC 桥接只运行 shell 形式的 `type: 'command'` 钩子;`http`、`mcp_tool`、`prompt` 和 `agent` 处理器被解析后跳过。Codex 桥接只运行同步命令处理器,跳过 `async: true` 或非命令条目。emit 监听路径(`session-start`、`subagent/start`)以 detached 方式运行,其 `inject` 包裹在 `.catch` 中记录日志(抛异常的 inject 不得中断会话启动或循环)。 -### 钩子的运行位置与配置来源 +### 钩子在哪里运行,配置从哪里来 -钩子在 agent 的会话工作区中运行,因此相对路径指向用户的项目。`configPath` 相对于进程启动 cwd 解析一次,适用于所有会话。按会话的项目本地发现仍推迟在 `TODO(per-session-hook-config)` 下。 +钩子在 agent 的会话工作区中运行,因此相对路径指向用户的项目。`configPath` 相对于进程启动时的 cwd 解析一次,适用于所有会话。按会话的项目本地发现仍推迟在 `TODO(per-session-hook-config)` 下。 ## 推迟的兼容性缺口 -- **工具输入重写。** CC/Codex 的 `updatedInput` 被记录日志并发出警告,但不生效——输入重写是一个推迟的一致性设计问题(见 [pre-tool-input-rewrite RFC](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)),因为预执行参数被 `tool/call` 审计、`assistant/message` 历史和 ACP/tool-bash 展示共同读取,诚实的重写是一个设计单元,而非一个字段。 -- **Stop 循环防护**(`TODO(stop-loop-guard)`)。Claude Code 提供 `stop_hook_active` 并在连续八次阻塞后覆盖钩子;Codex 提供 `stop_hook_active` 但文档中没有等效上限。两个桥接始终报告 `false`,因此一个无条件阻塞的 Stop 钩子会在每一步强制继续——钩子作者必须自行限制,直到状态追踪落地。 -- **钩子 `continue:false`(硬停止)。** 钩子可以请求终止整个运行(CC/Codex `continue:false`);共享 merge 将其折入 `MergedHookOutcome.stop`/`stopReason`,但没有桥接对其采取行动(`TODO(hook-continue-false)`)——拦截 seam 尚无「硬停止 agent」原语(Decision 阻塞/引导的是单个点,而非整个运行)。与循环防护工作一起推迟;停止请求记录在 `hook/result` 日志中,钩子在此期间保留其逐点效果(decision/上下文)。 -- **配置发现。** 路径在 `cordis.yml` 中显式指定且为进程级(见上文);完整的多层 CC/Codex 优先级遍历、按会话的项目本地发现以及信任/hash 模型均未重新实现(`TODO(per-session-hook-config)`)。 -- **Session-start / subagent-start 上下文为尽力而为(`TODO(session-start-gating)`)。** 两个钩子以 detached 方式运行于启动之外,因此其上下文在就绪时注入,但可能错过第一个请求或短命子 agent。保证首请求送达需要一个 awaited 的启动 seam。 +- **工具输入重写。** CC/Codex 的 `updatedInput` 被记录日志并发出警告,但不予执行——输入重写是一个推迟的一致性设计问题(见 [pre-tool-input-rewrite RFC](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)),因为 pre-execution 参数被 `tool/call` 审计、`assistant/message` 历史和 ACP/tool-bash 展示共同读取,诚实的重写是一个设计单元,而非一个字段。 +- **Stop 循环防护**(`TODO(stop-loop-guard)`)。Claude Code 提供 `stop_hook_active` 并在连续八次阻塞后覆盖钩子;Codex 提供 `stop_hook_active` 但未记录等效上限。两个桥接始终报告 `false`,因此一个无条件阻塞的 Stop 钩子会在每一步强制继续——在状态追踪落地之前,钩子作者必须自行限制。 +- **钩子 `continue:false`(硬停止)。** 钩子可以请求终止整个运行(CC/Codex `continue:false`);共享合并将其折叠为 `MergedHookOutcome.stop`/`stopReason`,但没有桥接对其采取行动(`TODO(hook-continue-false)`)——拦截 seam 尚无「硬停止 agent」原语(Decision 阻塞/引导的是单个点,而非整个运行)。与循环防护工作一同推迟;停止请求记录在 `hook/result` 日志中,钩子在此期间保留其逐点效果(决策/上下文)。 +- **配置发现。** 路径在 `cordis.yml` 中显式指定且为进程级(见上文);完整的多层 CC/Codex 优先级遍历、按会话的项目本地发现以及信任/hash 模型未被重新实现(`TODO(per-session-hook-config)`)。 +- **Session-start / subagent-start 上下文为尽力而为(`TODO(session-start-gating)`)。** 两个钩子以 detached 方式运行于启动过程之外,因此其上下文在就绪时注入,但可能错过首个请求或短命的 subagent。要保证首请求送达,需要一个 awaited 的启动 seam。 ## 曾考虑的替代方案 -**同一点的钩子并发执行。** 参考引擎对同一点匹配到的钩子并发运行并折叠结果。本桥接**串行**运行它们(匹配循环内逐钩子 `await`),并以相同的最严格合并策略折叠。串行是刻意的:它使每个钩子的 `hook/invoked`/`hook/result` 对在会话日志中相邻且顺序确定,而折叠对决策是顺序无关的(`deny > ask > allow`),因此结果一致。代价是延迟(钩子 *N* 等待钩子 *N−1*)且逐钩子超时不重叠——对真实配置使用的钩子数量而言可接受;如果某天配置扇出到足以影响挂钟时间,再重新审视。 +**每点钩子并发执行。** 参考引擎对一个点匹配到的钩子并发运行并折叠结果。本桥接**串行**运行(匹配循环内每个钩子 `await`),并以相同的最严格合并策略折叠。串行是刻意的:它使每个钩子的 `hook/invoked`/`hook/result` 对在会话日志中相邻且顺序确定,而折叠对决策是顺序无关的(`deny > ask > allow`),因此结果一致。代价是延迟(钩子 *N* 等待钩子 *N−1*)以及每钩子超时不重叠——对真实配置中的钩子数量可以接受;如果某配置的扇出大到影响总耗时,再重新评估。 ## 后果 -匹配语义、退出码处理与合并优先级位于 `dsh-hook-protocol`;每个桥接只负责解析配置、构建方言 payload 和映射结果。逐文件覆盖率包含配置分支加上通过真实循环、`dsh-bash-local` 和 shell 脚本的端到端映射,同时一个真实 Loader 冒烟测试守护 package 的导出形状。原生插件绕过协议格式,直接返回类型化决策。 +匹配语义、退出码处理和合并优先级位于 `dsh-hook-protocol`;每个桥接只负责解析配置、构建方言 payload 和映射结果。逐文件覆盖率包含配置分支以及通过真实循环、`dsh-bash-local` 和 shell 脚本的端到端映射,同时一个真实 Loader 冒烟测试守护 package 的导出形态。原生插件绕过协议格式,直接返回类型化决策。 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml index 22f7710469..5979186c01 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-30-hook-protocol-lib.md: 924c320f7ef9fdb55b20ff06f492addbf42d1720 -2026-06-30-hook-protocol-lib.zh.md: 2f1cf0f1e4c99eaf1172642475e3b9bc8c8aed39 +2026-06-30-hook-protocol-lib.zh.md: 81315cbe8767e9a3cc07cdef92359734e4e20f31 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md index 2f1cf0f1e4..81315cbe87 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md @@ -1,4 +1,4 @@ -# RFC:dsh-hook-protocol——Claude Code / Codex 钩子协议格式的共享核心库 +# RFC:dsh-hook-protocol——Claude Code / Codex 钩子协议格式共享核心库 [English](2026-06-30-hook-protocol-lib.md) | 中文 @@ -6,27 +6,27 @@ Status: implemented ## 问题 -钩子子系统提供两个桥接插件:一个运行用户已有的 Claude Code(CC)钩子,一个运行 Codex 钩子。研究参考实现(`~/repos/refs/claude-code`、`~/repos/refs/codex`)后发现一个决定性事实:**Codex 有意重新实现了 CC 钩子协议的一个子集。**它的引擎读取相同的 `hooks.json`,使用相同的 matcher-group 形状、相同的 exit-code/structured-stdout 输出契约,以及相同的 command-hook 执行模型——Codex 的源码甚至以 Claude 的引擎命名自己的引擎,并在注释中标注了「有意偏离」之处。因此两个桥接插件如果各自实现,将重复协议的大部分内容。 +hooks 子系统提供两个桥接插件:一个运行用户既有的 Claude Code(CC)钩子,另一个运行 Codex 钩子。研究参考实现(`~/repos/refs/claude-code`、`~/repos/refs/codex`)后发现一个决定性事实:**Codex 有意重新实现了 CC 钩子协议的一个子集。** 它的引擎读取相同的 `hooks.json`,使用相同的 matcher-group 形状、相同的 exit-code/structured-stdout 输出契约,以及相同的 command-hook 执行模型。Codex 的源码甚至以 Claude 的引擎命名,并在注释中标注了"有意偏离"之处。因此,如果不做抽取,两个桥接插件将大量重复协议逻辑。 -本 RFC 引入 `@deepseek-ai/dsh-hook-protocol`,一个**库**(不是插件——它不注册也不注入任何东西),持有两个桥接插件共同依赖的、真正相同的原语。共享与方言各自持有的部分之间的切分,是本设计的重心所在。 +本 RFC 引入 `@deepseek-ai/dsh-hook-protocol`,一个**库**(不是插件——它不注册也不注入任何东西),持有两个桥接插件共同依赖的真正相同的原语。共享与方言专属之间的分界是本设计的重心。 ## 决策 -在 `packages/hooks/` 下新建一个组,`hook-protocol` 作为纯库存在。它拥有四个原语族以及 `hook/*` 会话事件;每个桥接插件(`dsh-hooks-claude`、`dsh-hooks-codex`)拥有真正不同的部分。 +在 `packages/hooks/` 分组下新建 `hook-protocol` 作为纯库。它拥有四个原语族和 `hook/*` 会话事件;每个桥接插件(`dsh-hooks-claude`、`dsh-hooks-codex`)拥有真正不同的部分。 **共享(本库):** -- **Matcher**——`matchesMatcher(pattern, query, mode)`。两种方言唯一不同的轴被收敛到 `mode` 参数:`claude` 将纯 `[A-Za-z0-9_|]+` 模式视为字面量(管道符 = 精确匹配的交替),其他视为正则;`codex` 始终为无锚定正则。缺失/`''`/`'*'` 时匹配全部;无效正则匹配空集(绝不向循环抛出异常)。 -- **Execution**——`runHook(bash, hook, options)`。通过 `ctx.bash` seam 而非自建 spawn 运行 command hook:执行器已经提供了经过清理但可覆盖的 env、进程组 kill 和超时——正是协议所需的能力,而 `dsh-bash` 的 `stdin`/`env` 字段(正是为此添加的)是进程内桥接插件被允许使用的受信插件接口。它将桥接插件构建的 payload 序列化到 stdin(CC 时追加尾部换行),尊重钩子的 `timeoutSec`(否则使用 `DEFAULT_HOOK_TIMEOUT_MS`,即两种方言共享的 10 分钟参考默认值),且从不抛出异常(执行器的 rejection 变为 non-blocking-error 的 `HookOutput`)。 -- **Decode**——`parseHookOutput(exit, stdout, stderr)`,exit-code + structured-stdout 编解码器,产出方言无关的 `HookOutput`。Exit `0` → 宽松 JSON 解析 stdout;exit `2` → blocking error,`stderr` 作为原因(以 `decision: 'block'` 呈现,调用方无需单独的 exit-code 分支);其他 → non-blocking error。解析 CC structured-stdout 中在某条路径上有消费方的字段(`continue`/`stopReason`/`decision`/`hookSpecificOutput.{permissionDecision,additionalContext,updatedInput}`/`systemMessage`);桥接插件只尊重对其方言有意义的子集。在任何路径上都没有消费方的字段不予解析(CC 的 `suppressOutput`——钩子 stdout 在此从不进入 transcript,因此没有什么可抑制的;见 [tighten-hook-protocol-contract RFC](../simplification/2026-07-04-tighten-hook-protocol-contract.md))。 -- **Merge**——`mergeHookOutputs(outputs)`,将多个匹配钩子的输出折叠为一个最严格的 `MergedHookOutcome`:权限优先级 **deny > ask > allow**,halt 在首个 `continue:false` 时粘滞,block 原因以 `\n\n` 拼接,context/system-messages 按序累积。 -- **`hook/*` 会话事件**——`hook/invoked` / `hook/result`,通过 declaration-merge 加入 `SessionEventMap`(仅记录日志,类似 `compact/*`——不是 `SurfaceEventType`),附带 `appendHookInvoked`/`appendHookResult` 辅助函数,确保 invoked/result 配对和轮次包含关系在各桥接插件间保持一致。`appendHookResult` 还拥有持久化记录的语义——决策字符串(钩子解析出的 decision,否则在 `continue:false` 时为 `'stop'`,否则为 `'pass'`)和 500 字符的 `stderrSummary` 截断均从此处的 `HookOutput` 导出,而非在各桥接插件中分别实现。 +- **Matcher** — `matchesMatcher(pattern, query, mode)`。两种方言唯一不同的轴被收敛为 `mode` 参数:`claude` 将纯 `[A-Za-z0-9_|]+` 模式视为字面量(管道符 = 精确匹配的多选),其余视为正则;`codex` 始终是无锚定正则。缺省/`''`/`'*'` 匹配一切;无效正则匹配空集(绝不向 agent loop(智能体循环)抛异常)。 +- **Execution** — `runHook(bash, hook, options)`。通过 `ctx.bash` seam 而非自建 spawn 运行 command hook:执行器已提供清洗但可覆盖的 env、进程组 kill 和超时,正是协议所需的能力;`dsh-bash` 的 `stdin`/`env` 字段(正是为此添加的)是进程内桥接插件被允许使用的受信插件接口。它将桥接插件构建的 payload 序列化到 stdin(CC 时追加尾部换行),遵守钩子的 `timeoutSec`(否则使用 `DEFAULT_HOOK_TIMEOUT_MS`,即两种方言共享的 10 分钟参考默认值),且从不抛异常(执行器拒绝变为 non-blocking-error 的 `HookOutput`)。 +- **Decode** — `parseHookOutput(exit, stdout, stderr)`,exit-code + structured-stdout 编解码器,产出方言无关的 `HookOutput`。Exit `0` → 宽松 JSON 解析 stdout;exit `2` → blocking error,`stderr` 为原因(以 `decision: 'block'` 呈现,调用方无需单独处理 exit-code 分支);其他 → non-blocking error。解析 CC structured-stdout 中在某条路径上有消费方的字段(`continue`/`stopReason`/`decision`/`hookSpecificOutput.{permissionDecision,additionalContext,updatedInput}`/`systemMessage`);桥接插件只采纳对其方言有意义的子集。在任何路径上都没有消费方的字段不予解析(CC 的 `suppressOutput`——钩子 stdout 在此处从不进入 transcript(文本记录),因此无需抑制;见 [tighten-hook-protocol-contract RFC](../simplification/2026-07-04-tighten-hook-protocol-contract.md))。 +- **Merge** — `mergeHookOutputs(outputs)`,将多个匹配钩子的输出折叠为一个最严格的 `MergedHookOutcome`:权限优先级 **deny > ask > allow**,halt 在首个 `continue:false` 时粘滞,block reason 以 `\n\n` 拼接,context/system-messages 按序累积。 +- **`hook/*` 会话事件** — `hook/invoked` / `hook/result`,declaration-merge 进 `SessionEventMap`(仅日志,如 `compact/*`——不是 `SurfaceEventType`),配有 `appendHookInvoked`/`appendHookResult` 辅助函数,确保 invoked/result 配对与 turn 包含关系在各桥接插件间保持一致。`appendHookResult` 还拥有持久化记录的语义:decision 字符串(钩子解析出的 decision,否则 `continue:false` 时为 `'stop'`,否则为 `'pass'`)和 500 字符的 `stderrSummary` 截断均从本库的 `HookOutput` 派生,而非各桥接插件各自实现。 -**方言各自持有(桥接插件):**构建每个事件的 stdin payload(CC 的 base + per-event 字段集 vs Codex 的 snake_case 加 `turn_id`/`model` 额外字段)、方言的 env 与 `${CLAUDE_PLUGIN_ROOT}` 替换(CC)vs 无替换(Codex),以及将方言无关的 `HookOutput`/`MergedHookOutcome` 映射到 harness 的 seam 特定类型化 Decision(`PreToolDecision`、`PromptDecision`、`ContinuationDecision`、`PostToolDecision`)。 +**方言专属(桥接插件):** 构建每个事件的 stdin payload(CC 的 base+per-event 字段集 vs Codex 的 snake_case 加 `turn_id`/`model` 额外字段)、方言的 env 与 `${CLAUDE_PLUGIN_ROOT}` 替换(CC)vs 无替换(Codex),以及将方言无关的 `HookOutput`/`MergedHookOutcome` 映射为 harness seam 专属的类型化 Decision(`PreToolDecision`、`PromptDecision`、`ContinuationDecision`、`PostToolDecision`)。 ## 曾考虑的替代方案 -**一个参数化引擎。** 否决,因为 payload 构建和决策映射在方言间确实不同。Matcher、编解码器、执行、合并规则和事件保持共享;各桥接插件保留自己的 payload 和映射,使其协议格式行为在代码中可就地阅读。 +**单一参数化引擎。** 否决,因为 payload 构建与 decision 映射在方言间确实不同。Matcher、编解码器、执行、合并规则和事件保持共享;每个桥接插件保留自己的 payload 和映射,使其协议格式行为在代码中可就地阅读。 ## 后果 -每个桥接插件解析配置、构建方言 payload、调用共享的 runner 和 merge 逻辑、映射决策、追加 `hook/*` 事件。协议测试覆盖每种 matcher 模式、exit-code 与编解码器字段、runner 管道、merge 优先级和审计辅助函数,逐文件 100% 覆盖率;桥接插件测试验证库的真实加载路径。`updatedInput` 已被解析,但在 [input-rewrite 提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)落地之前仅记录日志并发出警告。 +每个桥接插件解析配置、构建方言 payload、调用共享的 runner 与 merge 逻辑、映射 decision、追加 `hook/*`。协议测试覆盖每种 matcher 模式、exit-code 与编解码器字段、runner 管道、merge 优先级和审计辅助函数,逐文件 100% 覆盖率;桥接插件测试验证库的真实加载路径。`updatedInput` 已解析但仅记录日志并发出警告,直到 [input-rewrite 提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)落地。 diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml index b40109802a..2a1efb261c 100644 --- a/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-30-interception-seams.md: fb8efe1e1c2057db13b440881f110ca7f579a81e -2026-06-30-interception-seams.zh.md: b22b3d61bd14b6708e5a063f02537e981fead0fc +2026-06-30-interception-seams.zh.md: 668b96dba282ecdcbe85cc0b1dc56c2de293b3b3 diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md b/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md index b22b3d61bd..668b96dba2 100644 --- a/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md @@ -6,55 +6,55 @@ Status: implemented ## 问题 -harness 需要一套钩子子系统:用户在生命周期节点扩展或拦截 agent(智能体),方式类似 Claude Code(CC)和 Codex。驱动本设计的关键重构是:**"原生钩子"不是一个 package**——原生钩子只是一个普通的 Cordis 插件,订阅规范的生命周期事件。因此真正的产品是一个*强大、类型完备的规范事件表面*;CC/Codex 桥接(`dsh-hooks-claude` / `dsh-hooks-codex` 包)只是把外部 shell-hook 协议映射到同一表面的翻译层。桥接能做的事,普通插件都能直接做——而且更强大(没有序列化边界、完整的 `ctx`、类型化的返回值)。 +harness 需要一套钩子子系统:用户像 Claude Code(CC)和 Codex 那样在生命周期节点扩展或管控 agent(智能体)。驱动本设计的关键视角转换是:**"原生钩子"不是一个包**——原生钩子只是一个普通的 Cordis 插件,订阅规范的生命周期事件。因此真正的产品是一个*强大、类型完备的规范事件表面*;CC/Codex 桥接(`dsh-hooks-claude` / `dsh-hooks-codex` 包)只是将外部 shell-hook 协议映射到同一表面的翻译层。桥接能做的事,普通插件可以直接做——而且更强大(无序列化边界、完整 `ctx`、类型化返回值)。 -这个表面需要为以下各阶段提供不同的契约:逐 prompt 策略(CC 的 `UserPromptSubmit`)、会话启动观测(CC 的 `SessionStart`)、工具执行前策略、环绕调度控制、工具执行后变换、最终结果观测,以及附带面向模型原因的继续。如果把这些阶段混为一谈,插件就会获得不需要的修改通道,终态也会依赖监听器顺序。[事件域语义 RFC](../architecture/2026-06-30-event-domain-semantics.md) 提供了三域规则和类型化 Decision 惯用法;本 RFC 将它们应用到生命周期 seam 上。 +该表面需要为以下场景提供各自独立的契约:逐 prompt 策略(CC 的 `UserPromptSubmit`)、会话启动观测(CC 的 `SessionStart`)、工具执行前策略、环绕调度控制、工具执行后变换、最终结果观测,以及携带面向模型的原因的继续执行。如果把这些阶段混为一谈,插件就会获得不需要的 mutation 通道,而终结性将依赖监听器的注册顺序。[事件域语义 RFC](../architecture/2026-06-30-event-domain-semantics.md) 提供了三域规则与类型化 Decision 惯用法;本 RFC 将其应用于生命周期 seam。 ## 决策 -规范表面将可变换策略、环绕调度控制与仅观测通知分离。策略 waterfall(瀑布式事件)返回小型的、seam 专属的**类型化 Decision 联合类型**;包装层返回归一化结果;通知接收不可变快照,不能影响结果。覆盖范围包括本次纳入的钩子点(`session-start`、`prompt-submit`、`pre-tool`、`post-tool`、通过 continuation 实现的 `stop`),同时将非钩子的执行策略留给独立组合。 +规范表面将可变换策略、环绕调度控制与仅观测通知分离。策略 waterfall(瀑布式事件)返回小型的、seam 专属的**类型化 Decision 联合类型**;包装层返回规范化结果;通知接收不可变快照,无法影响结果。覆盖的钩子点包括 `session-start`、`prompt-submit`、`pre-tool`、`post-tool`、通过 continuation 实现的 `stop`,同时将非钩子的执行策略留作独立可组合。 **Agent 事件**(`dsh-agent`): -- `agent/session-start(agent, source)`——emit,在第 1 轮次之前触发一次,携带 `SessionStartSource`(`startup` 表示全新/fork 创建,`resume` 表示重新加载的持久化会话;`clear`/`compact` 保留)。纯通知——它**不能**阻塞启动(这是有意的缺口:桥接用于记录/注入,不用于拦截启动)。监听器通过 `agent.inject()` 注入上下文。 -- `agent/prompt-submit(agent, content, source, next) → PromptDecision`——waterfall,在已开启的轮次内、`user/message` 追加之前,对每条出队的排队消息触发。`allow`(可选地重写 prompt `content` 或附加 `additionalContext`)或 `block`(丢弃该 prompt;循环在其位置追加一条持久的 `prompt/blocked`——见下方调度说明)。 +- `agent/session-start(agent, source)` ——emit,在第 1 轮次之前触发一次,携带 `SessionStartSource`(`startup` 表示全新/fork 创建,`resume` 表示重新加载的持久化会话;`clear`/`compact` 保留)。纯通知,**不能**阻塞启动(这是有意的空白:桥接可以记录/注入,但不管控启动)。监听器通过 `agent.inject()` 注入上下文。 +- `agent/prompt-submit(agent, content, source, next) → PromptDecision` ——waterfall,在已开启的轮次内、`user/message` 追加之前,对每条出队的排队消息触发。`allow`(可选地重写 prompt `content` 或附加 `additionalContext`)或 `block`(丢弃该 prompt;循环在其位置追加一条持久的 `prompt/blocked`——见下方调度说明)。 -**`agent/turn-continuation`** 接收并返回一个 `ContinuationDecision`。`{action:'continue', reason?}` 可携带面向模型的上下文,记录为同一轮次内的下一步 steering(中途引导)——与 `/goal` step-end-steer 模式互为类型化的孪生。 +**`agent/turn-continuation`** 接收并返回一个 `ContinuationDecision`。`{action:'continue', reason?}` 可携带面向模型的上下文,记录为同一轮次内的下一步 steering(中途引导)——与 `/goal` step-end-steer 模式互为类型化孪生。 ### 工具流水线为每个阶段赋予一种权限 -每次调用遵循 `tools/pre-execute` → guards → `tools/execute` → dispatch → `tools/post-execute` → `tools/result`。注册表快照调用方输入、物化并冻结参数、分配不透明 token。嵌套调用只携带父 token。身份始终不可变;只有 `signal` 可在环绕调度时改变。日志、UI 和工具体因此对「运行了什么」达成一致。 +每次调用遵循 `tools/pre-execute` → guards → `tools/execute` → dispatch → `tools/post-execute` → `tools/result`。注册表快照调用方输入、实体化并冻结参数、分配一个不透明 token。嵌套调用仅携带父 token。身份始终不可变;只有 `signal` 可在环绕调度时改变。日志、UI 和工具体因此对「执行了什么」达成一致。 -- **`tools/pre-execute`** 是可扩展的 waterfall 门禁。其 `PreToolDecision` 允许、拒绝或询问。拒绝跳过 `tools/execute` 和核心调度。询问通过可选的审批 seam 解析:只有 `allowed-once` 继续通过 guards 和调度;拒绝、取消、通道不可用、审批服务缺失或无 agent 调用均归一化为拒绝。每种结果仍会到达后策略和最终观测者。 -- **`ctx.tools.guard()`** 在整个 pre-execute waterfall 之后安装同步的作用域感知策略。guard 可以拒绝或弃权,永远不能强制允许,因此监听器顺序无法复活一个被最终不变式禁止的操作。 -- **`tools/execute`** 是用于超时、重试和指标插件的环绕调度 waterfall。包装层通过 `next()` 委托给核心调度,在此之前只能添加、替换或移除 `exec.signal`,并接收已归一化的抛出或未知工具结果;返回自己的有效结果可短路调度。 -- **`tools/post-execute`** 是检查/变换 waterfall。其 `PostToolDecision` 接受、以反馈阻止、可选地替换内容,或附加 `additionalContext`;对结果的就地修改不是变换通道,因为注册表从受保护的快照加上返回的 decision 重建结果。 -- **`tools/result`** 是每次变换、无损 JSON 物化和外层错误边界之后的同步受限通知。它接收相同的冻结执行身份和权威结果的不可变快照;观测者失败按监听器隔离,不能改变或拒绝 `ToolRegistry.execute()` 返回的结果。 +- **`tools/pre-execute`** 是可扩展的 waterfall 门禁。其 `PreToolDecision` 允许、拒绝或询问。拒绝跳过 `tools/execute` 与核心调度。询问通过可选的审批 seam 解析:只有 `allowed-once` 继续通过 guards 和调度;拒绝、取消、通道不可用、审批服务缺失或无 agent 调用均规范化为拒绝。每种结果仍会到达后策略与最终观测者。 +- **`ctx.tools.guard()`** 在整个 pre-execute waterfall 之后安装同步的、作用域感知的策略。guard 可以拒绝或弃权,永远不能强制允许,因此监听器顺序无法复活一个被最终不变式禁止的操作。 +- **`tools/execute`** 是用于超时、重试和指标插件的环绕调度 waterfall。包装层通过 `next()` 委托给核心调度,在此之前只能添加、替换或移除 `exec.signal`,并接收已规范化的抛出或未知工具结果;返回自己的有效结果则短路调度。 +- **`tools/post-execute`** 是检查/变换 waterfall。其 `PostToolDecision` 接受、以反馈阻止、可选地替换内容,或附加 `additionalContext`;对结果的原地 mutation 不是变换通道,因为注册表从受保护的快照加上返回的 decision 重建结果。 +- **`tools/result`** 是在所有变换、无损 JSON 实体化和外层错误边界之后的同步封闭通知。它接收相同的冻结执行身份和权威结果的不可变快照;观测者的失败按监听器隔离,无法改变或拒绝 `ToolRegistry.execute()` 返回的结果。 -核心调度和工具体位于归一化边界内,因此工具、监听器、格式错误的结果、非 JSON 结果和身份形状失败都解析为 JSON 安全的 `isError` 结果,而非逃逸出轮次。post-execute 监听器因此可以检查抛出异常的工具,最终观测者看到的恰好是调用方收到的、会话日志可持久化的内容。 +核心调度与工具体位于规范化边界内部,因此工具、监听器、格式错误的结果、非 JSON 结果和身份形状错误均解析为 JSON 安全的 `isError` 结果,而非逃逸出轮次。post-execute 监听器因此可以检查一个抛出异常的工具,最终观测者看到的正是调用方收到的、会话日志可以持久化的内容。 -**`TurnEndReason.rejected`**(`dsh-session`):整个 prompt 批次被 `prompt-submit` 阻止的轮次。 +**`TurnEndReason.rejected`**(`dsh-session`):整批 prompt 均被 `prompt-submit` 阻止的轮次。 ### 三个承重的循环决策 -1. **在 prompt 策略之前开启轮次。** 被完全阻止的批次成为零步骤的 `rejected` 轮次,保持封闭性并为 ACP 提供持久的终止事件。每次否决还记录 `prompt/blocked`(含原始 prompt 和原因),因此混合批次保留了被阻止的输入。允许的 `additionalContext` 注入到已开启的轮次中。 +1. **在 prompt 策略之前开启轮次。** 全部被阻止的批次成为零步骤的 `rejected` 轮次,保持封闭性并为 ACP(Agent Client Protocol)提供持久的终结事件。每次否决还记录 `prompt/blocked`(含原始 prompt 和原因),因此混合批次保留被阻止的输入。允许的 `additionalContext` 注入到已开启的轮次中。 -2. **Post-tool `additionalContext` 被缓冲,在所有 `tool/result` 之后追加。** `content`/`feedback` 塑造 `execute()` 返回的结果,但 `additionalContext` 是一条**独立的** `context/message`,而单个步骤可携带多个工具调用。如果在每个结果之后立即追加上下文,会产生 `result(c1) → context → result(c2)` 的交错,破坏工具调用/结果的邻接性。因此 `execute()` 将 `additionalContext` 暴露在其 `ToolExecutionResult` 上,循环为该步骤缓冲每次调用的上下文,仅在所有 `tool/result` 追加完毕后才以 `context/message` 形式追加。 +2. **Post-tool `additionalContext` 被缓冲,在所有 `tool/result` 之后追加。** `content`/`feedback` 塑造 `execute()` 返回的结果,但 `additionalContext` 是一条**独立的** `context/message`,而单个步骤可以携带多个工具调用。如果在每个结果之后立即追加上下文,会产生 `result(c1) → context → result(c2)` 的交错,破坏工具调用/结果的邻接性。因此 `execute()` 将 `additionalContext` 暴露在其 `ToolExecutionResult` 上,循环为该步骤的每次调用缓冲上下文,仅在所有 `tool/result` 追加完毕后才以 `context/message` 形式追加。 -3. **强制 `continue` 的 `reason` 通过 steering 通道入队**,使下一步骤的循环顶部 drain 将其记录为继续轮次的 steering——同一轮次内的下一*步骤* steering,而非下一*轮次*的 prompt(与既有的 `hasSteering` force-continue 覆盖一致)。 +3. **强制 `continue` 的 `reason` 通过 steering 通道入队**,使得下一步骤在循环顶部排空时将其记录为当前轮次的 steering——同一轮次内的下一*步骤* steering,而非下一*轮次*的 prompt(与现有的 `hasSteering` 强制继续覆盖一致)。 ### Pre-tool 输入重写是一个独立的一致性决策 -`PreToolDecision` 不能重写参数。历史和审计调用在执行前记录,ACP 展示读取相同的输入,因此注册表在策略之前封存参数。有效的重写必须在身份创建之前更新历史、审计、展示和执行;该契约属于[输入重写提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)。 +`PreToolDecision` 不能重写参数。历史和审计调用在执行前记录,ACP 展示读取相同的输入,因此注册表在策略之前封存参数。有效的重写必须在身份创建之前同时更新历史、审计、展示和执行;该契约属于[输入重写提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)。 ### 边界 -seam 包**不**声明 `hook/*` 会话事件(持久的钩子调用日志);那些属于 `dsh-hook-protocol`,因为原生插件使用类型化 decision 而无需外部钩子日志。原生插件集成测试(`packages/core/agent-loop/tests/interception.spec.ts`)通过真实循环组合这些 seam,不涉及 `hook/*` 协议。压缩(`PreCompact`/`PostCompact`)、Notification 和 Codex `PermissionRequest` 不在本决策范围内。[审批 seam](2026-07-06-approval-seam.md) 通过 `ctx.approval` 解析 `ask` decision,而终止的单调停止由 `agent/turn-stop` 独立负责。 +seam 包**不**声明 `hook/*` 会话事件(持久的钩子调用日志);那些属于 `dsh-hook-protocol`,因为原生插件使用类型化 decision 而无需外部钩子日志。原生插件集成测试(`packages/core/agent-loop/tests/interception.spec.ts`)通过真实循环组合这些 seam,不涉及 `hook/*` 协议。压缩(compaction)(`PreCompact`/`PostCompact`)、Notification 和 Codex `PermissionRequest` 不在本决策范围内。[审批 seam](2026-07-06-approval-seam.md) 通过 `ctx.approval` 解析 `ask` decision,而终结性的单调停止由 `agent/turn-stop` 独立负责。 ## 曾考虑的替代方案 -- **将 pre-tool 输入重写作为本 seam 集的一部分交付**——推迟,视为过度扩展信号;上文已阐述一致性问题(审计、历史和展示都读取执行前记录的 `tool/call.arguments`),[pre-tool 输入重写提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)负责该设计。 -- **将持久的 `hook/*` SessionEvent 与 seam 一起声明**——否决:原生插件使用类型化 Decision 而完全不需要钩子日志(工作示例已证明),因此持久日志属于[钩子协议库](2026-06-30-hook-protocol-lib.md),而非 seam 表面。 +- **将 pre-tool 输入重写作为本 seam 集的一部分发布**:推迟,视为越界信号;上文已阐述一致性问题(审计、历史和展示都读取执行前记录的 `tool/call.arguments`),[pre-tool 输入重写提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)负责该设计。 +- **将持久的 `hook/*` SessionEvents 与 seam 一起声明**:否决。原生插件使用类型化 Decision 而完全不需要钩子日志(实际示例已证明),因此持久日志属于[钩子协议库](2026-06-30-hook-protocol-lib.md),而非 seam 表面。 ## 后果 -规范的拦截表面实现了统一类型化,同时不给每个扩展相同的权力:钩子返回 decision,执行包装层做包装,终止 guard 只能拒绝,最终观测者只能观测。循环负责 session-start、prompt-submit、post-tool 上下文缓冲和 continuation;`dsh-tools` 负责身份封存和五阶段执行流水线。它们的契约记录在 [architecture.md](../../../architecture.md)、package README、[核心拦截 decision](../../../core-data-structures/core.md#interception-decisions) 和[工具结构](../../../core-data-structures/tools.md)中。ACP 桥接将 `rejected` 轮次映射为其 `cancelled` 编解码值,而钩子驱动的快照端到端验证可观测的桥接行为。 +规范拦截表面具有统一的类型化,同时不给每个扩展相同的权力:钩子返回 decision,执行包装层做包装,终结 guard 只能拒绝,最终观测者只能观测。循环负责 session-start、prompt-submit、post-tool 上下文缓冲和 continuation;`dsh-tools` 负责身份封存与五阶段执行流水线。它们的契约记录在 [architecture.md](../../../architecture.md)、各 package README、[核心拦截 decision](../../../core-data-structures/core.md#interception-decisions) 与[工具结构](../../../core-data-structures/tools.md)中。ACP 桥接将 `rejected` 轮次映射为其 `cancelled` 编解码值,而钩子驱动的快照端到端验证可观测的桥接行为。 diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml index 03da25497d..c05a025ca6 100644 --- a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-30-session-store-fork-api.md: 4bf5c3fe43821570fd947034358e54d0a0a602f9 -2026-06-30-session-store-fork-api.zh.md: 3dd15f5beb095fecb7fdaa7d80abcf4b99c07920 +2026-06-30-session-store-fork-api.zh.md: a3ffb881a446647861fa5fbaf57dde291838a090 diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md index 3dd15f5beb..a3ffb881a4 100644 --- a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md @@ -1,20 +1,20 @@ # RFC:SessionStore fork API -Status: implemented - [English](2026-06-30-session-store-fork-api.md) | 中文 +Status: implemented + ## 问题 -事件溯源的会话日志已经具备 fork 所需的原语:创建一个新会话并带上种子事件前缀,然后像回放一样从该种子日志推导模型历史。这个原语有意保持底层:`ctx.sessions.create(id, { seed, meta })` 接受任何合法的种子,但普通的活跃会话分支需要围绕以下问题制定策略:哪些前缀可以复制、子会话打上什么元数据、错误如何分类。 +事件溯源的会话日志已经具备 fork 所需的原语:创建一个带有种子事件前缀的新会话,然后像回放一样从该种子日志推导模型历史。这个原语有意保持底层:`ctx.sessions.create(id, { seed, meta })` 接受任何合法种子,但常规的活跃会话分支需要围绕以下问题制定策略:哪些前缀可以被复制、子会话应打上哪些元数据、以及错误如何分类。 -语义风险在于 fork 边界。一个合法的用户可见 fork 种子必须是连续的且被轮次封闭。如果在一个活跃轮次内部 fork,会复制一个未关闭的 `turn/start`,可能还有未关闭的 `step/start`,以及悬空的工具调用。这违反了轮次封闭性与 provider-transcript 不变式,并且会创建一段误导性的子会话历史——看起来像是参与了父会话中一个未完成的轮次。现有的 [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 有意解决的是另一个问题:工具触发的 subagent fork 通常发生在父轮次尚未关闭时,因此 `dsh-subagent-fork` 会将种子裁剪到父会话最后一个已完成轮次的前缀。通用的会话 fork 不应静默裁剪;它应当要么在请求的边界处 fork,要么拒绝。 +语义上的风险在于 fork 边界。一个合法的用户可见 fork 种子必须是连续的且封闭在轮次内。如果在一个活跃轮次内部 fork,会复制一个未关闭的 `turn/start`、可能还有一个未关闭的 `step/start`,以及可能悬空的工具调用。这违反了轮次封闭性与 provider-transcript 不变式,并且会创建一段误导性的子历史——看起来子会话参与了父会话中一个尚未完成的轮次。现有的 [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 有意解决的是另一个问题:工具触发的 subagent fork 通常发生在父轮次仍然打开时,因此 `dsh-subagent-fork` 会将种子裁剪到父会话最后一个已完成轮次的前缀。通用的会话 fork 不应静默裁剪;它应当要么在请求的边界处 fork,要么拒绝请求。 ## 决策 -`dsh-session` 直接在 `ctx.sessions` 上拥有普通活跃会话的 fork 能力。没有独立的 `dsh-session-fork` 包(package),也没有 `ctx.sessionFork` 服务:该 API 没有独立的后端、事件词汇、生命周期或持久化行为,所有持久性工作都委托给现有的会话存储与持久化后端。 +`dsh-session` 直接在 `ctx.sessions` 上拥有常规活跃会话 fork 的能力。不设独立的 `dsh-session-fork` 包(package),也不设 `ctx.sessionFork` 服务:该 API 没有独立的后端、事件词汇、生命周期或持久化行为,所有持久化工作都委托给现有的 session store 和持久化后端。 -存储暴露一个操作: +store 暴露一个操作: ```ts ignore-check type SessionForkSource = Session | SessionId @@ -24,20 +24,20 @@ class SessionStore extends Service { } ``` -`boundary` 是要复制到的源事件 `seq`(含该序号)。省略时默认为源会话当前的最后一个事件;对空源会话省略 `boundary` 会创建一个空的子会话。fork 专有的校验只检查请求的边界是否存在且为 `turn/end`。选定的前缀随后被深拷贝到子会话的种子中。子会话继承源会话的 `cwd`,将 `parentSession` 标记为源会话 id,并将 `seedLength` 设为复制的前缀长度。省略 `childSessionId` 时,`SessionStore` 使用其现有的 id 策略生成一个。 +`boundary` 是要复制到的源事件 `seq`(含该序号)。省略时默认为源会话当前的最后一个事件;对空源会话省略 `boundary` 则创建一个空的子会话。fork 特有的校验仅检查请求的边界是否存在且为 `turn/end`。选定的前缀随后被深拷贝到子会话的种子中。子会话继承源会话的 `cwd`,将 `parentSession` 设为源会话 id,并将 `seedLength` 设为已复制前缀的长度。省略 `childSessionId` 时,`SessionStore` 使用其现有的 id 策略生成一个。 -空前缀可以 fork;任何非空边界必须是一个安全的、已存在的、位于 `turn/end` 处的序号,无论结束原因是什么。类型化的错误区分源不存在、对象陈旧、子会话 id 重复和边界无效。更广泛的日志校验与崩溃恢复仍由其现有的负责方处理。 +空前缀可以被 fork;任何非空边界都必须是一个安全的、已存在的、位于 `turn/end` 的序号,无论结束原因为何。类型化的错误区分源缺失、对象陈旧、子 id 重复和边界无效等情况。更广泛的日志校验与崩溃恢复仍由其现有的负责方处理。 ## 曾考虑的替代方案 -**独立的 `ctx.sessionFork` 服务。** 这是第一版实现,但评审表明它过度套用了能力 seam 模式。代码没有可替换的后端、没有额外的事件面、没有独立的所有权生命周期,也没有超出 `ctx.sessions.create({ seed, meta })` 的持久化行为。保留独立包会迫使调用方发现并安装第二个服务,仅仅为了在会话存储原语之上执行策略。 +**独立的 `ctx.sessionFork` 服务。** 这是最初的实现,但评审表明它过度套用了 capability-seam 模式。代码没有可替换的后端、没有额外的事件面、没有独立的所有权生命周期,也没有超出 `ctx.sessions.create({ seed, meta })` 的持久化行为。保留独立包会迫使调用方为了在 session store 原语之上执行一层策略而去发现并安装第二个服务。 -**两个函数:`snapshot()` 加 `fork()`。** 这保留了可复用的种子/元数据计算,但唯一支持的消费方会立即创建会话。它还让接口感觉比用户实际需要的具体操作更抽象。单一的 `fork()` 加显式 `boundary` 保持了 API 的直接性,同时仍支持对先前时间点的 fork。 +**两个函数:`snapshot()` 加 `fork()`。** 这保留了一个可复用的种子/元数据计算,但唯一支持的消费方会立即创建会话。它还使接口看起来比用户实际需要的具体操作更抽象。单一的 `fork()` 加显式 `boundary` 使 API 保持直接,同时仍支持对先前时间点的 fork。 -**静默裁剪未关闭的轮次到最后一个已完成边界。** 这对 `dsh-subagent-fork` 是正确的,因为委托通常在父轮次尚未关闭时开始,子会话应只继承已完成的前缀。但对普通的用户/会话分支来说是错误的,因为它隐藏了请求的 fork 点实际上不是合法边界这一事实,并静默丢弃了父轮次的尾部。 +**静默裁剪未关闭轮次到最后一个已完成边界。** 这对 `dsh-subagent-fork` 是正确的——委托通常在父轮次仍然打开时开始,子会话应只继承已完成的前缀。但对常规的用户/会话分支而言是错误的,因为它隐藏了请求的 fork 点实际上不是合法边界这一事实,并且静默丢弃了父轮次的尾部。 ## 后果 -公开接口保持小巧且易于发现:活跃会话分支是 `ctx.sessions` 的一部分,紧邻 `create({ seed })`,而非一个独立服务或两步辅助函数对。持久化继续通过现有的 `session/created` 和 `session/flush` 行为工作:fork 出的子会话以种子事件开始生命,因此现有后端只需持久化一次该种子,并在头部保留 `parentSession` / `seedLength`。 +公开接口保持精简且易于发现:活跃会话分支是 `ctx.sessions` 的一部分,紧邻 `create({ seed })`,而非一个独立服务或一对两步辅助函数。持久化继续通过现有的 `session/created` 和 `session/flush` 行为运作:fork 出的子会话以种子事件开始生命,因此现有后端只需持久化该种子一次,并在 header 中保存 `parentSession`/`seedLength`。 -v1 范围仍排除 ACP `session/fork`、对未加载的已持久化会话的 fork、面向模型的工具,以及 subagent 重构。如果未来添加 ACP 方法,应在具备 transcript(文本记录)/快照覆盖后才广播该能力;本 RFC 不添加面向编辑器的更新,因此当前不需要 ACP 快照。fork 子会话的回放仍由现有的[种子边界测试 RFC](../../implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md) 覆盖,而本 API 获得专注的 `dsh-session` 单元测试加 JSONL 持久化覆盖。 +v1 范围仍然排除 ACP(Agent Client Protocol) `session/fork`、对未加载的已持久化会话的 fork、面向模型的工具,以及 subagent 重构。如果未来添加 ACP 方法,应在具备 transcript(文本记录)/快照覆盖后才广播该能力;本 RFC 不添加面向编辑器的更新,因此当前不需要 ACP 快照。fork 子会话的回放仍由现有的[种子边界测试 RFC](../../implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md) 覆盖,而本 API 则获得专门的 `dsh-session` 单元测试加 JSONL 持久化覆盖。 diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml index 085f5d2c5b..90b6939da2 100644 --- a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-30-subagent-observe-enrich.md: b48a1fff32130345e669a3b3b905c4fda987e41e -2026-06-30-subagent-observe-enrich.zh.md: 59dc555ce4acff30f4ba0b5929b605dc5252fe38 +2026-06-30-subagent-observe-enrich.zh.md: 8ce070001e219572658fd4e94c660de1094ddee5 diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md index 59dc555ce4..8ce070001e 100644 --- a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md @@ -1,4 +1,4 @@ -# RFC:Subagent 生命周期充实——lastAssistantMessage(仅观测) +# RFC:Subagent 生命周期丰富化——lastAssistantMessage(仅观察) Status: implemented @@ -6,26 +6,26 @@ Status: implemented ## 问题 -钩子子系统([拦截 seam RFC](2026-06-30-interception-seams.md))允许插件在生命周期节点观测和门控 agent(智能体)。Claude Code 和 Codex 都暴露了 **SubagentStart / SubagentStop** 钩子,且 CC 的钩子携带 subagent 的最终消息。harness 已经发出 `subagent/start` 和 `subagent/end` 生命周期事件([subagent 能力 seam](2026-06-21-subagent-capability-seam.md)),但其载荷极为精简(`provider`、`id`,以及 end 时的 `stopReason`)——不足以让钩子桥接层在不另行访问活跃运行的情况下报告 subagent 产出了什么。 +钩子子系统([拦截 seam RFC](2026-06-30-interception-seams.md))允许插件在生命周期节点观察和拦截 agent(智能体)。Claude Code 和 Codex 都暴露了 **SubagentStart / SubagentStop** 钩子,且 CC 的钩子携带 subagent 的最终消息。harness 已经发出 `subagent/start` 和 `subagent/end` 生命周期事件([subagent 能力 seam](2026-06-21-subagent-capability-seam.md)),但其载荷极为精简(`provider`、`id`,以及 end 时的 `stopReason`),不足以让钩子桥接层在不单独访问活跃 run 的情况下报告 subagent 产出了什么。 -本 RFC 充实 end 载荷。它刻意限定为**仅观测**:不改变控制流,不引入 waterfall(瀑布式事件)。影响运行的 subagent-stop 决策(续行、注入改变运行的内容)属于另一项更大的重新设计,不在本 RFC 范围内。 +本 RFC 丰富 end 载荷。它刻意限定为**仅观察**:不改变控制流,不引入 waterfall(瀑布式事件)。影响 run 的 subagent-stop 决策(续行、改变 run 的注入)属于另一个更大的重设计,不在本 RFC 范围内。 ## 决策 -**在 `SubagentRunEndInfo` 中添加 `lastAssistantMessage`——子 agent 的最终输出。** 在正常结算路径上,它是只读的类型化 `SubagentResult.output`,观测者无需持有运行即可看到子 agent 的产出。在基础设施拒绝、不存在 `SubagentResult` 的情况下,该字段缺失,事件报告 `stopReason: 'error'`。提供方与监听者是受信任的同进程协作者,遵守借用不可变载荷的契约。 +**在 `SubagentRunEndInfo` 中添加 `lastAssistantMessage`——子 agent 的最终输出。** 在正常结束路径上,它是只读的类型化 `SubagentResult.output`,观察者无需持有 run 即可看到子 agent 产出了什么。在基础设施拒绝(不存在 `SubagentResult`)的情况下,该字段缺失,事件报告 `stopReason: 'error'`。提供方与监听方是受信任的同进程协作者,遵守借用不可变载荷的契约。 -两个事件仍为普通 **`emit`**。异步的 `SubagentService.start()` 将结果观测附加到就绪的提供方运行上,发出 `subagent/start`,然后返回该运行;因此进程内监听者可以通过 `ctx.agents.get(info.id)` 访问已发布的子 agent,而远程提供方无需在本地注册表中有条目。提供方启动被拒绝时不发出任何事件。回调保持仅观测,逐监听者隔离确保一个坏订阅者不会阻塞活跃运行或饿死后续监听者。 +两个事件仍为普通 **`emit`**。异步的 `SubagentService.start()` 将结果观察附加到就绪的 provider run 上,发出 `subagent/start`,然后返回该 run;进程内监听方因此可以通过 `ctx.agents.get(info.id)` 访问已发布的子 agent,而远程 provider 无需在本地注册表中有对应条目。provider 启动被拒绝时不发出任何事件。回调保持仅观察,且逐监听方隔离确保一个异常订阅者不会阻塞活跃 run 或饿死后续监听方。 ## 曾考虑的替代方案 -**`agentType` subagent 类别标签**(CC 的 `subagent_type` 在 harness 中的对应物)放在请求和两个生命周期载荷上——早期草案曾包含它;评审中移除,因为它是 Claude Code 的概念,不适合我们自己的 seam(这里没有任何代码解释它,唯一的消费方是 CC 方言桥接层)。CC 桥接层改为向 Claude Code 自身的 SubagentStart/Stop `agent_type` 匹配器喂入其默认值 `"general-purpose"`,因此本 RFC 只交付一项充实:`lastAssistantMessage`。 +**`agentType` subagent 类别标签**(CC 的 `subagent_type` 在 harness 中的对应物),放在请求与两个生命周期载荷上。早期草案曾包含它;评审中移除,因为它是 Claude Code 的概念,不适合我们自己的 seam(此处没有任何逻辑解释它,唯一消费方是 CC 方言桥接层)。CC 桥接层改为直接为其 SubagentStart/Stop 的 `agent_type` matcher 填入 Claude Code 自身的默认值 `"general-purpose"`,因此本 RFC 只交付一项丰富化:`lastAssistantMessage`。 -**控制流式 `subagent/end`**——推迟;见下文。 +**控制流式 `subagent/end`**:推迟;见下文。 -## 为何仅观测,以及推迟了什么 +## 为何仅观察,以及推迟了什么 -控制流式 `subagent/end`(一个被 await 的 waterfall,返回停止/继续决策,与其他拦截 seam 一致)需要:将 `subagent/end` 从 emit 改为 waterfall、重构 `SubagentService.start` 使其在结算前 await 监听者、在进程内提供方中实现 `resume` 能力以便「继续」能真正重新运行子 agent。这属于[能力 seam RFC](2026-06-21-subagent-capability-seam.md) 已推迟的后台/steering(中途引导)subagent 重新设计(同一项重新设计还将统一 subagent 与 bash 之间的长时间运行工具处理)。本 RFC 交付钩子桥接层当前所需的仅观测充实;`FIXME(subagent-continuation)` / `TODO` 锚点标记了控制流版本在该重新设计发生时将落地的位置。 +控制流式 `subagent/end`(一个被 await 的 waterfall,返回停止/继续决策,与其他拦截 seam 一致)需要:将 `subagent/end` 从 emit 改为 waterfall、重构 `SubagentService.start` 使其在结算前 await 监听方、在进程内 provider 中实现 `resume` 能力以便「继续」能真正重新运行子 agent。这属于[能力 seam RFC](2026-06-21-subagent-capability-seam.md) 已推迟的后台/steering(中途引导)subagent 重设计(同一个重设计还将统一 subagent 与 bash 之间的长时间运行工具处理)。本 RFC 交付钩子桥接层当前所需的仅观察丰富化;`FIXME(subagent-continuation)` / `TODO` 锚点标记了控制流版本在重设计发生时的落点。 ## 后果 -钩子桥接层(或原生插件)现在可以通过订阅既有 emit 将子 agent 的 `lastAssistantMessage` 转发给 SubagentStop 处理器——无需新的控制流接口。词汇新增记录在 [docs/core-data-structures/subagent.md](../../../core-data-structures/subagent.md)(事件行文部分)和两个 subagent README 中;catalog 已重新生成。生产行为无变化——事件的触发方式与之前完全相同,end 载荷多了一个(可选的)字段——因此不需要快照或 e2e 测试变更。 +钩子桥接层(或原生插件)现在可以通过订阅既有 emit 将子 agent 的 `lastAssistantMessage` 转发给 SubagentStop 处理器,无需新的控制流接口。词汇新增记录在 [docs/core-data-structures/subagent.md](../../../core-data-structures/subagent.md)(事件行文部分)与两个 subagent README 中;catalog 已重新生成。生产行为无变化——事件触发方式与之前完全一致,end 载荷上多了一个可选字段——因此无需更新快照或 e2e 测试。 diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml index 04a6289216..25c723bde1 100644 --- a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-05-dynamic-workflows.md: 67ceebf7017f197bd800fd339b575390b3b936c1 -2026-07-05-dynamic-workflows.zh.md: 0ea8e88bfa750a9bb253c7dd3061766fe15d3630 +2026-07-05-dynamic-workflows.zh.md: 54ba0d903de228e14a53e6f64ead0f5156e61289 diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md index 0ea8e88bfa..54ba0d903d 100644 --- a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md @@ -1,80 +1,80 @@ # RFC:动态工作流——脚本驱动的多 agent 编排 seam -Status: implemented - [English](2026-07-05-dynamic-workflows.md) | 中文 +Status: implemented + ## 问题 -harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`),但需要扇出到多个独立片段的工作——跨多文件审计、迁移、多角度调研、对抗式验证——迫使模型逐轮次编排:每个中间结果都落入父上下文,计划没有持久存放处,每一步的协调都要消耗一次模型往返。Claude Code 以[动态工作流](https://code.claude.com/docs/en/workflows)的形式提供这一能力:模型编写一段 JavaScript 编排脚本,运行时执行它,由脚本(而非对话)持有循环、分支和中间结果。 +harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`),但需要扇出到多个独立部分的工作——跨多文件审计、迁移、多角度调研、对抗式验证——迫使模型逐轮次编排:每个中间结果都落入父上下文,计划无处持久存储,每一步的协调都要消耗一次模型往返。Claude Code 以 [dynamic workflows](https://code.claude.com/docs/en/workflows) 的形式提供了这一能力:模型编写一段 JavaScript 编排脚本,运行时执行它,由脚本(而非对话)持有循环、分支和中间结果。 ## 决策 -在 `packages/workflow/` 下以 bash seam 的形态(接口/实现/消费方)提供一组工作流能力,加上 subagent seam 上它所需的结构化输出基础。 +在 `packages/workflow/` 下以 bash seam 的形态(接口/实现/消费方)提供一组工作流能力,以及它在 subagent seam 上所需的结构化输出基础。 ### 脚本契约(兼容 Claude Code) -一次工作流调用包含 JSON `meta`(`name`、`description`,以及可选的 `whenToUse`/`phases`)和一段支持顶层 `await` 并返回 JSON 值的 JavaScript `script` 正文。元数据作为数据校验,从不被求值。正文接收 `agent(prompt, options)`、`parallel(thunks)`、`pipeline(items, ...stages)`、`phase(title)`、`log(message)` 和 `args`。pipeline 各阶段接收 `(prev, item, index)`,阶段间无屏障;失败的子 agent 和普通阶段错误将受影响的 item 解析为 `null` 并跳过其剩余阶段。Claude Code 的确定性限制通过 journaling 延后处理,因此兼容的脚本正文在将 meta 头移入参数后,可以使用时钟和随机数。 +一次工作流调用包含 JSON `meta`(`name`、`description`,以及可选的 `whenToUse`/`phases`)和一段支持顶层 `await` 并返回 JSON 值的 JavaScript `script` 正文。元数据作为数据校验,从不被执行。正文接收 `agent(prompt, options)`、`parallel(thunks)`、`pipeline(items, ...stages)`、`phase(title)`、`log(message)` 和 `args`。pipeline 各阶段接收 `(prev, item, index)`,阶段之间无屏障;失败的子 agent 和普通阶段错误将受影响的 item 解析为 `null` 并跳过其剩余阶段。Claude Code 的确定性限制通过日志化延迟处理,因此兼容的脚本正文在将 meta 头移入参数后可以使用时钟和随机数。 -与 Claude Code 的一处刻意**偏离**:钩子误用——未知或延后的选项(`effort`/`isolation`/`agentType`)、格式错误的参数、超出支持子集的 schema、触发上限、seam 启动失败——抛出 `fatal: true` 的 `WorkflowError`,组合器对 fatal 错误**重新抛出**而非将 item 置为 null。如果不这样做,一个拼错的选项会溶解为与子 agent 失败无法区分的 `null`——正是本仓库禁止的「接受后静默忽略」失败模式。一处**新增**:工具的 `args` 参数是 JSON 对象(裸列表会被包装为一个字段),以保持协议格式(wire format)的诚实。 +与 CC 有一处刻意的严格性**差异**:钩子误用——未知或延迟的选项(`effort`/`isolation`/`agentType`)、格式错误的参数、超出支持子集的 schema、触发上限、seam 启动失败——会抛出带 `fatal: true` 的 `WorkflowError`,组合器会**重新抛出** fatal 错误而非将 item 置为 null。如果不这样做,一个拼错的选项会悄然变成一个与子 agent 失败无法区分的 `null`——这正是本仓库禁止的「被接受后被忽略」的失败模式。另有一处新增:工具的 `args` 参数是一个 JSON **对象**(裸列表被包装为一个字段),使协议格式(wire format)保持诚实。 ### seam(dsh-workflow) -`ctx.workflows` 是 bash 形态的抽象 `WorkflowService`:每个上下文一个引擎,无命名提供方注册表(引擎是部署级替换,不是共存者)。`start(request)` 对无法启动的脚本同步抛出异常;返回的 `WorkflowRun` 的 `result` 永不 reject(失败解析为 `stopReason: 'error' | 'cancelled'`)。`workflow/*` 事件是仅供观察的 emit,携带数据快照(id + meta;`workflow/end` 不含 result 值),按监听器隔离,与 `subagent/start`/`subagent/end` 对称——控制权留在 run 的持有者手中。词汇细节见 [core-data-structures/workflow.md](../../../core-data-structures/workflow.md)。 +`ctx.workflows` 是 bash 形态的抽象 `WorkflowService`——每个上下文一个引擎,无命名提供方注册表(引擎是部署级替换,不是共存者)。`start(request)` 对无法启动的脚本同步抛出;返回的 `WorkflowRun` 的 `result` **永不** reject(失败解析为 `stopReason: 'error' | 'cancelled'`)。`workflow/*` 事件是仅观察的 emit,携带**数据快照**(id + meta;`workflow/end` 省略 result 值),按监听器隔离,与 `subagent/start`/`subagent/end` 对称——控制权留在 run 的持有者手中。词汇详情见 [core-data-structures/workflow.md](../../../core-data-structures/workflow.md)。 ### 引擎(dsh-workflow-workerthread):每次运行一个 worker 线程 -**信任前提**:工作流脚本与模型的 bash 访问享有相同信任级别。引擎约束有 bug 的脚本,保证 result 必定 settle、值 JSON 安全、取消后静默;它不防御恶意代码。vm 上下文和 worker 线程不是安全边界:脚本可以逃逸到具有进程级权限的 Node API。沙箱化需要在此 seam 之后放置一个独立进程或 isolated-vm 引擎。 +**信任前提**:工作流脚本与模型的 bash 访问具有相同的信任级别。引擎容纳有缺陷的脚本,并保证结果已 settled、值为 JSON 安全、取消后静默;它不防御恶意代码。vm 上下文和 worker 线程不是安全边界:脚本可以逃逸到具有进程级权限的 Node API。沙箱化需要在此 seam 背后使用独立进程或 isolated-vm 引擎。 -**为何选择 `node:worker_threads`**:每次运行获得一个非池化 worker。vm 上下文限制了文档化的脚本表面,而 message-port RPC 将 `agent()` 桥接到宿主侧的子循环。worker 防止脚本的同步工作阻塞宿主,提供序列化边界,并允许取消后强制终止。`isolated-vm` 因其维护状态和部署要求被否决。 +**为何选择 `node:worker_threads`**:每次运行获得一个非池化的 worker。vm 上下文限制了文档化的脚本表面,而 message-port RPC 将 `agent()` 桥接到宿主侧的子循环。worker 防止脚本的同步工作阻塞宿主,提供序列化边界,并允许取消后强制终止。`isolated-vm` 因其维护状态和部署要求被否决。 -宿主在发布前校验元数据并解析正文。私有枚举键的 payload map 定义协议格式;待启动记录、已发布的子记录、单一取消信号、worker 死亡回收、result 优先级和 dispose 静默在协议两侧维持 subagent run 契约。[agent-scope runtime-design RFC](../architecture/2026-07-12-agent-scope-runtime-design.md#workflow-children-are-pending-starts-or-published-records) 拥有这些竞态算法。 +宿主在发布前校验元数据并解析正文。私有枚举键 payload 映射定义协议格式;待启动记录、已发布子记录、单一取消信号、worker 死亡回收、结果优先级与 dispose 静默,在此协议上保持 subagent run 契约。这些竞态算法归 [agent-scope runtime-design RFC](../architecture/2026-07-12-agent-scope-runtime-design.md#workflow-children-are-pending-starts-or-published-records) 所有。 引擎暴露一条进程内 `MessageChannel` 测试路径,因为主进程 V8 覆盖率无法观测 worker 执行。 -**Meta 是数据**:经 schema 校验的 `meta` 字段以 JSON 形式到达 seam,仅做形状校验。宿主从不对元数据字面量求值——否则脚本控制的访问器会在 worker 隔离之外运行。 +**Meta 是数据**:经 schema 校验的 `meta` 字段以 JSON 形式到达 seam,仅做形状校验。宿主从不执行元数据字面量,否则脚本控制的访问器可以在 worker 隔离之外运行。 -**值边界**:`materializeFromRealm` 复制出站值,拒绝函数、symbol、嵌套 `undefined`、异域原型、循环引用、稀疏数组和非有限数。数据属性复制使 `"__proto__"` 安全;getter 正常读取,抛出异常的 getter 会大声失败。`args` 通过 `workerData` 传入,暴露前再次克隆。realm 函数被调用而非复制,抛出的值使用全量渲染器以确保 `result` 不会 reject。钩子错误是宿主 realm 的 `WorkflowError`,因此脚本按 `name` 或 `code` 分支而非 `instanceof Error`,如引擎 README 所述。并发、total-agent、item、超时和 grace 限制均为经校验的配置。 +**值边界**:`materializeFromRealm` 复制出站值,并拒绝函数、symbol、嵌套 `undefined`、异域原型、循环引用、稀疏数组和非有限数字。数据属性复制使 `"__proto__"` 安全;getter 正常读取,抛出异常的 getter 会大声失败。`args` 通过 `workerData` 传入,暴露前再次克隆。realm 函数被调用而非复制,抛出的值使用全量渲染器,因此 `result` 不会 reject。钩子错误是宿主 realm 的 `WorkflowError`,脚本应基于 `name` 或 `code` 分支而非 `instanceof Error`,如引擎 README 所述。并发、total-agent、item、超时和宽限限制均为经校验的配置。 ### 消费方(dsh-tool-workflow) -一个 `workflow` 工具,镜像 `dsh-tool-subagent` 的同步形态:启动、等待、`try/finally` dispose、abort 桥接 `exec.signal`、非 `completed` → `isError`。渲染意图:一张以调用的 `meta.name` 参数为标题的 `generic` 卡片(展示是参数的纯函数)。工具描述即面向模型的编写规范。使用策略作为工具自身的 `tool:<toolName>` prompt 段随工具一起交付(显式请求才使用的指导——工具指导存在于工具插件中,从不放在部署 persona 里);harness 没有 ultracode 风格的 effort 门控。 +一个 `workflow` 工具,镜像 `dsh-tool-subagent` 的同步形态:启动、await、`try/finally` dispose、abort 桥接 `exec.signal`、非 `completed` → `isError`。渲染意图:一张以调用的 `meta.name` 参数为标题的 `generic` 卡片(展示是参数的纯函数)。工具描述**即**面向模型的编写规范。使用策略以工具自身的 `tool:<toolName>` prompt 段落随工具发布(显式请求才使用的引导——工具引导存在于工具插件中,从不在部署 persona 中);harness 没有 ultracode 风格的 effort 门控。 ### 基础:subagent seam 上的结构化输出 -`SubagentStartRequest.outputSchema` 由 `dsh-subagent-inprocess` 为两个进程内后端实现。每个结构化子 agent 在 `child.ctx` 上获得自己的作用域捕获工具、指令和强制注册;并发子 agent 可以使用不同 schema 而不共享可变策略,dispose 子 agent 时整个附件被移除。 +`SubagentStartRequest.outputSchema` 由 `dsh-subagent-inprocess` 为两个进程内后端实现。每个结构化子 agent 在 `child.ctx` 上获得自己的作用域捕获工具、指令和强制注册;并发子 agent 可以使用不同的 schema 而不共享可变策略,dispose 子 agent 时移除整个附件。 -输出 schema 使一次 schema 有效的已提交捕获成为子 agent 成功完成的必要条件。作用域运行时呈现捕获工具和指令,仅提交成功的最终结果(包括 SDK 调用的外层 `run_code` 结果),在捕获进入 pending 状态后拒绝后续副作用,并在提交后不再请求模型步骤即停止子 agent。校验失败仍为可重试的工具错误;干净完成但没有已提交捕获的情况 settle 为错误。 +输出 schema 使一次 schema 有效的已提交捕获成为子 agent 成功完成的必要条件。作用域运行时呈现捕获工具和指令,仅提交成功的最终结果(包括 SDK 调用时外层 `run_code` 的结果),在捕获变为 pending 后拒绝后续副作用,并在提交后不再进行模型步骤即停止子 agent。校验失败仍是可重试的工具错误;没有已提交捕获的正常完成以错误结算。 -`StructuredOutputSchema` 是 `dsh-tools` 中可强制执行的原始 JSON-Schema 子集(单字符串 `type`、`properties`/`required`/`additionalProperties`、`items`、标量 `enum`/`const`),不支持的关键字会大声失败,因为该协议数据会逐字成为捕获工具的 parameters。[agent-scope runtime-design RFC](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes) 拥有组装、提交、守卫和终止停止的正确性算法。 +`StructuredOutputSchema` 是 `dsh-tools` 中可强制执行的原始 JSON-Schema 子集(单字符串 `type`、`properties`/`required`/`additionalProperties`、`items`、标量 `enum`/`const`),不支持的关键字会大声失败,因为该协议数据会逐字成为捕获工具的 parameters。组装、提交、守卫和终止停止的正确性算法归 [agent-scope runtime-design RFC](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes) 所有。 ## 测试 -worker 侧逻辑通过进程内 `MessageChannel` 运行,以便 V8 覆盖率能度量它。单元测试覆盖脚本辅助函数、fatal 与 nullable 失败、JSON 边界、上限、取消、子 agent 所有权和通过真实循环的结构化输出。built-bin 冒烟测试在纯 Node 下运行单独打包的 `lib/worker.cjs`,带 key 的 e2e 驱动真实子 agent,面向模型的工作流行为通过其所属示例进行快照覆盖。 +worker 侧逻辑通过进程内 `MessageChannel` 运行,使 V8 覆盖率能够度量它。单元测试覆盖脚本辅助函数、fatal 与 nullable 失败、JSON 边界、上限、取消、子 agent 所有权和通过真实循环的结构化输出。built-bin 冒烟测试在纯 Node 下运行单独打包的 `lib/worker.cjs`,带密钥的 e2e 驱动真实子 agent,面向模型的工作流行为通过其所属示例进行快照覆盖。 -## 延后(本轮明确的非目标) +## 延迟(本轮明确的非目标) - **后台收集**(启动工具 → run id → 完成通知 → 收集),与 bash/subagent 后台统一一起设计。 -- **Journaling + 恢复**(`resumeFromRunId`、缓存的 agent() 前缀):实现它会将 Claude Code 的确定性禁令作为脚本契约收紧重新引入(脚本今天可以读取时钟)。 -- **保存/打包的工作流**(`.deepseek/workflows/` 注册表、斜杠命令界面)和**脚本持久化到 run 目录**(tool-call 事件已经持久记录了脚本)。 -- **嵌套 `workflow()`**、**token `budget`**,以及 `effort`/`isolation`/`agentType` agent 选项(每个都以命名延后项的消息大声拒绝)。 -- **整体运行的挂钟超时**:取消总能释放调用方(result 在 grace 内 settle),因此总运行时间上限是后台重设计的策略旋钮,不是此处的正确性需求。 -- **超越 worker 线程的引擎加固**:在同一 seam 之后放置 isolated-vm 或独立进程引擎(真正的沙箱化;内存限制)。 -- **ACP 进度 UI**:基于 `workflow/*` 事件(`/workflows` 风格的视图);事件已为此存在。 -- **ACP 后端结构化输出**和 **`toolFilter`**(两者仍为能力门控 `false`)。 +- **日志化 + 恢复**(`resumeFromRunId`、缓存的 agent() 前缀):实现它会以脚本契约收紧的形式重新引入 CC 的确定性禁令(脚本目前可以读取时钟)。 +- **保存/打包的工作流**(`.deepseek/workflows/` 注册表、斜杠命令界面)和**脚本持久化到运行目录**(tool-call 事件已经持久记录了脚本)。 +- **嵌套 `workflow()`**、**token `budget`**,以及 `effort`/`isolation`/`agentType` agent 选项(每个都以命名延迟的消息大声拒绝)。 +- **整体运行的挂钟超时**:取消总能释放调用方(result 在宽限期内 settle),因此总运行时间上限是后台重设计的策略旋钮,不是此处的正确性需求。 +- **超越 worker 线程的引擎加固**:在同一 seam 背后使用 isolated-vm 或独立进程引擎(真正的沙箱化;内存限制)。 +- **ACP 进度 UI**(基于 `workflow/*` 事件的 `/workflows` 风格视图);事件已为此而存在。 +- **ACP 后端结构化输出**和 **`toolFilter`**(两者仍以能力标志 `false` 门控)。 ## 曾考虑的替代方案 -- **宿主侧的恶意值防御**(无 trap 代理拒绝、从不调用访问器的描述符遍历、realm 侧预渲染抛出值、realm 构建的 promise/array/error 克隆并带结构化 fatal 识别):否决。每项防御针对的都是信任前提所接受的作者,而线程的序列化边界已经从构造上使跨 realm 值全量化。 -- **进程内 `node:vm` 执行**:机制最简——无 RPC、无线程——但 `start()` 会在脚本首段同步切片期间阻塞调用方,首个 await 之后的同步自旋无法在进程内被杀死(vm `timeout` 仅覆盖首段切片),`dispose()` 只能在宿主循环上放弃一个未 settle 的脚本。worker 线程引擎保持相同的 vm 上下文脚本表面,同时解除宿主阻塞并使终止成为现实。 -- **后台执行作为默认**(Claude Code 的形态):延后。前台同步与 `dsh-tool-subagent` 的当前形态一致,后台语义应在 bash/subagent/workflow 之间统一设计一次,而非逐工具各做一套。 -- **工作流层为 `agent({schema})` 做 JSON 解析**:在一个消费方重复 seam 的关注点,而 seam 的能力标志仍不诚实地为 `false`。 -- **Meta 嵌入脚本内作为 `export const meta = {...}`**(Claude Code 的精确格式):保持脚本自包含且 Claude Code 脚本可直接使用,但获取 meta 需要在宿主上对模型编写的文本求值。即使是空的限时 vm 上下文,在宿主读取结果对象时也无法约束脚本控制的 getter。JSON 参数消除了扫描器、求值和宿主自旋漏洞;代价是 Claude Code 脚本的 meta 头必须移入参数(正文保持可直接使用)。 -- **`SchemaSpec` 作为 outputSchema 类型**:面向作者的 DSL 无法表达以数据形式到达的内容,且无法在不丢失转换精度的情况下对其校验。 -- **schema 对象库(zod 或仓库的 schemastery)用于结构化输出子集**:schema 是协议数据——纯 JSON,跨越 `agent({schema})` 中的 vm realm 边界,逐字落入强制工具的 parameters——正是活 schema 对象无法存在的位置;在运行时消费原始 JSON Schema 需要在其上叠加第三方转换器(zod core 只输出 JSON Schema,不做反向),且会在 schemastery 的配置角色之外引入第二种 schema 语言。 -- **ajv 做值校验**:它校验完整 JSON Schema,因此子集门控——模块的真正要点,因为每个被接受的关键字都必须是 harness 所强制执行的——无论如何仍需手写;它通过 `new Function` 编译校验器;且它将成为 dsh-tools 的首个运行时依赖,所有这些只为替换约 70 行的值遍历器,而路径限定的、报告每一处违规的错误输出无论如何都是自定义的。 -- **提供方 JSON 模式代替捕获工具**:它保证有效 JSON,不保证 schema 一致性,且它与工具调用的交互尚不明确。捕获工具保留了轮次内的校验重试。提供方侧的严格工具 schema 可以在不改变本设计的前提下进一步收窄接受的子集。 +- **宿主侧的恶意值防护**(无 trap 代理拒绝、从不调用访问器的描述符遍历、realm 侧预渲染抛出值、realm 构建的 promise/array/error 克隆加结构化 fatal 识别):否决。每项防御针对的都是信任前提所接受的作者,而线程的序列化边界已经从构造上使跨 realm 值全量化。 +- **进程内 `node:vm` 执行**:机械上最简——无 RPC、无线程——但 `start()` 会在脚本的初始同步切片期间阻塞调用方,第一个 await 之后的同步自旋无法在进程内终止(vm `timeout` 仅覆盖第一个切片),且 `dispose()` 只能在宿主循环上放弃一个未 settle 的脚本。worker 线程引擎保持相同的 vm 上下文脚本表面,同时解除宿主阻塞并使终止成为现实。 +- **后台执行作为默认**(CC 的形态):延迟。前台同步与 `dsh-tool-subagent` 的当前形态一致,后台语义应在 bash/subagent/workflow 之间统一设计一次,而非逐工具设计。 +- **工作流层为 `agent({schema})` 做 JSON 解析**:在一个消费方重复 seam 关注点,而 seam 的能力标志仍不诚实地为 `false`。 +- **Meta 嵌入脚本中作为 `export const meta = {...}`**(CC 的确切格式):保持脚本自包含且 CC 脚本可直接使用,但获取 meta 需要在宿主上执行模型编写的文本。即使一个空的限时 vm 上下文也无法约束脚本控制的 getter(当宿主读取结果对象时)。JSON 参数消除了扫描器、执行和宿主自旋漏洞;代价是 CC 脚本的 meta 头必须移入参数(正文保持可直接使用)。 +- **`SchemaSpec` 作为 outputSchema 类型**:面向作者的 DSL 无法表达以数据形式到达的内容,也无法在不丢失转换精度的情况下对其进行校验。 +- **schema 对象库(zod 或本仓库的 schemastery)用于结构化输出子集**:schema 是协议数据——纯 JSON,跨越 `agent({schema})` 中的 vm realm 边界并逐字落入强制工具的 parameters——正是活 schema 对象无法存在的位置;在运行时消费原始 JSON Schema 需要在其上加一个第三方转换器(zod core 只输出 JSON Schema,不能反向),且会在 schemastery 的配置角色旁边放置第二种 schema 语言。 +- **ajv 用于值校验**:它校验完整 JSON Schema,因此子集门控——模块的真正要点,因为每个被接受的关键字都必须是 harness 强制执行的——无论如何仍需手写;它通过 `new Function` 编译校验器;且它将成为 dsh-tools 的第一个运行时依赖,仅为替换约 70 行的值遍历器,而路径限定的、报告每一处违规的错误报告无论如何都是自定义的。 +- **提供方 JSON 模式代替捕获工具**:它保证有效 JSON,不保证 schema 一致性,且它与工具调用的交互不明确。捕获工具保留了轮次内的校验重试。提供方侧的严格工具 schema 后续可以在不改变本设计的情况下收窄接受的子集。 ## 后果 -扇出计划现在存在于可重新运行的脚本中,`outputSchema` 提供权威的结构化子 agent 结果。每次运行付出 worker 启动和 message-port RPC 的开销,但宿主启动保持非阻塞,取消可以终止 worker,序列化强制执行值边界。Worker 线程不是安全边界。无效选项会失败而非退化为 Claude Code 的 `null`;消费方通过 run 句柄保持控制,观察者仅接收快照。 +扇出计划现在存在于可重运行的脚本中,`outputSchema` 提供权威的结构化子 agent 结果。每次运行付出 worker 启动和 message-port RPC 成本,但宿主启动保持非阻塞,取消可以终止 worker,序列化强制执行值边界。worker 线程不是安全边界。无效选项快速失败而非退化为 Claude Code 的 `null`;消费方通过 run handle 保持控制权,观察者仅接收快照。 diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml b/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml index 0db4b2ac5a..3b3aed7c50 100644 --- a/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-05-skill-system.md: 6cfd1f977ae5a1e1ad646a707a4201e57d46bc38 -2026-07-05-skill-system.zh.md: d491899e03854140c93f67d11e4079a5b6525185 +2026-07-05-skill-system.zh.md: f59fd5d850a38d7324b391a116c72c4e71ef7401 diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md b/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md index d491899e03..f59fd5d850 100644 --- a/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md @@ -1,55 +1,55 @@ # RFC:Skill 系统——面向 agent 的渐进式指令披露 -Status: implemented - [English](2026-07-05-skill-system.md) | 中文 +Status: implemented + ## 问题 -各 agent 产品已趋同于一种 skill 模式:保持请求提示词精简,仅列出可用的指令包,待模型判定任务匹配时再加载完整正文。Codex、Claude Code、OpenCode 和 Kimi Code 在细节上各有不同,但都将发现元数据与完整指令分离,使工作区能承载可复用行为而无需在每个轮次支付全量提示词成本。 +Agent(智能体)产品已趋同于一种 skill(技能)模式:保持请求提示词精简,仅列出可用的指令包,当模型判定某任务匹配时再加载完整正文。Codex、Claude Code、OpenCode 与 Kimi Code 在细节上各有不同,但都将发现元数据与完整指令分离,使工作区能承载可复用的行为而无需在每个轮次支付全量提示词开销。 -DeepSeek Harness 使用同一原语,让项目级的评审指导、插件编写指导和工具使用指导存放在工作区或用户的 agent 配置旁,而非硬编码进 agent loop(智能体循环)。 +DeepSeek Harness 使用同一原语,使项目特定的评审、插件编写和工具使用指南存放在工作区或用户的 agent 配置旁,而非硬编码到 agent loop(智能体循环)中。 ## 决策 -`@deepseek-ai/dsh-skill` 是纯提供方注册表(`ctx.skills`),`@deepseek-ai/dsh-skill-local` 是随附的本地文件系统提供方,`@deepseek-ai/dsh-tool-skill` 负责会话前缀目录和面向模型的 loader 工具。`dsh-agent-spine-demo` 默认加载注册表、本地提供方和消费方,使 stdio 与 ACP 应用获得相同行为,同时嵌入式或远程提供方可在不改动注册表或消费方的前提下贡献 skill。其 `skills` 配置将 `registry`、`local` 和 `tool` 分支分别转发给对应的负责方。 +`@deepseek-ai/dsh-skill` 是纯提供方注册表(`ctx.skills`),`@deepseek-ai/dsh-skill-local` 是随附的本地文件系统提供方,`@deepseek-ai/dsh-tool-skill` 负责会话前缀目录与面向模型的 loader 工具。`dsh-agent-spine-demo` 默认加载注册表、本地提供方和消费方,使 stdio 与 ACP(Agent Client Protocol)应用获得相同行为,同时嵌入式或远程提供方可在不修改注册表或消费方的前提下贡献 skill。其 `skills` 配置将 `registry`、`local` 和 `tool` 分支分别转发给对应的所有者。 -提供方插件在 `apply()` 期间同步注册。提供方成员关系是直接由 effect 持有的状态:注册与 dispose(资源释放)同步地使已完成的目录失效,发现操作按需读取当前提供方映射,而非监听注册表变更事件。提供方目录从 awaited `list()` 调用返回排序后的候选项,远程提供方在此期间执行初始化、认证和发现,同时遵守查找的 abort signal。注册表校验每个候选项,对同名 skill 按 rank、提供方注册顺序和提供方内部顺序执行 first-wins 解析,然后按 skill 名称排序摘要以保证消费方获得确定性结果。注册表仅缓存已完成的目录快照,当提供方/运行时修订版本在发现过程中发生变化时重试,因此 unload 不会将一个陈旧、不可解析的 skill 冻结进会话前缀。运行时 `ctx.skills.register(...)` 仍作为嵌入式进程内 skill 的便捷方式保留,使用 project-over-user 优先级;`runtime` 作为注册表持有的提供方名称被保留。 +提供方插件在 `apply()` 期间同步注册。提供方成员资格是由直接 effect 持有的状态:注册与 dispose(资源释放)同步地使已完成的目录失效,发现操作按需读取当前提供方映射而非监听注册表变更事件。提供方目录从等待的 `list()` 调用返回排序后的候选项,远程提供方在此过程中执行初始化、认证和发现,同时遵守查找的 abort 信号。注册表校验每个候选项,按排名、提供方注册顺序和提供方内部顺序以先到先得方式解决同名 skill 冲突,然后按 skill 名称排序摘要以保证消费方获得确定性结果。它仅缓存已完成的目录快照,并在发现过程中提供方/运行时修订版本发生变化时重试,因此卸载操作不会将一个陈旧且不可解析的 skill 冻结到会话前缀中。运行时 `ctx.skills.register(...)` 仍作为嵌入式进程内 skill 的便捷方式保留,使用 project 优先于 user 的优先级;`runtime` 保留为注册表拥有的提供方名称。 -本地提供方按 first-wins 的 rank 顺序扫描对 cwd 敏感的项目根目录、自定义根目录和用户根目录:项目 `.dsh`、项目 `.agents`、`customSkillDirs`、用户 `.dsh`,然后是用户 `.agents`。用户 `.dsh/skills` 扫描跳过 `.system`,使系统持有的目录不被当作普通用户内容。DeepSeek Harness 不随附内置系统 skill;嵌入式或远程提供方在配置后提供额外 skill。 +本地提供方按先到先得的排名顺序扫描 cwd 敏感的项目根目录、自定义根目录和用户根目录:项目 `.dsh`、项目 `.agents`、`customSkillDirs`、用户 `.dsh`,然后是用户 `.agents`。用户 `.dsh/skills` 扫描跳过 `.system`,以免系统拥有的目录被当作普通用户内容处理。DeepSeek Harness 不随附内置系统 skill;嵌入式或远程提供方在配置后提供额外 skill。 -每个 skill 是 `<name>/SKILL.md` 或带 YAML frontmatter 的 `<name>.md`。`name` 和 `description` 为必填;`whenToUse`、`disableModelInvocation` 和 `metadata` 为可选。名称使用 kebab-case。YAML frontmatter 使用 `yaml` 包解析,而非 `js-yaml` 或手写解析器:`yaml` 是本包有限 frontmatter 需求所声明的现代解析器,手写窄解析器要么拒绝用户期望能正常工作的合法 YAML,要么膨胀为一个未经评审的 YAML 子集。 +每个 skill 是 `<name>/SKILL.md` 或带 YAML frontmatter 的 `<name>.md`。`name` 和 `description` 为必填;`whenToUse`、`disableModelInvocation` 和 `metadata` 为可选。名称采用 kebab-case。YAML frontmatter 使用 `yaml` 包(package)解析,而非 `js-yaml` 或手写解析器:`yaml` 是本包有限 frontmatter 需求已声明的现代解析器,窄解析器要么拒绝用户预期可用的合法 YAML,要么膨胀为一个未经评审的 YAML 子集。 -本地 skill 的文件系统 I/O 在加载了文件系统服务时通过 `ctx.fs` 进行:项目根目录查找使用 `resolve` 和 `stat` 探测 `.git`,根目录发现使用 `listDir`,skill 读取使用 `readText`。对于未挂载 fs seam 的最小上下文,Node 文件系统仍作为回退。缺失的根目录、不可读或格式错误的 skill 文件,以及提供方 `list()` 的瞬态失败均降级为 warn-and-skip,使单个坏源不会导致每个 agent 请求失败;格式错误的候选项仍然快速失败,因为它们违反了提供方契约。 +本地 skill 的文件系统 I/O 在加载了文件系统服务时通过 `ctx.fs` 进行:项目根目录查找使用 `resolve` 和 `stat` 探测 `.git`,根目录发现使用 `listDir`,skill 读取使用 `readText`。Node 文件系统作为后备,供在不挂载 fs seam 的最小上下文中加载 `dsh-skill-local` 时使用。缺失的根目录、不可读或格式错误的 skill 文件、以及提供方 `list()` 的瞬态失败均降级为警告并跳过,使一个坏源不会导致所有 agent 请求失败;格式错误的候选项仍然快速失败,因为它们违反了提供方契约。 -`dsh-tool-skill` 通过 [`agent/session-prefix`](2026-07-07-session-prefix.md) 贡献一条 user-role `<system-reminder>` 目录。目录仅包含排序后的 skill 名称和描述;不包含正文、路径、来源、提供方和路由提示。描述经过空白规范化、XML 转义,并受 `catalogDescriptionMaxLength` 限制,其默认值为 `500`,最小值为 `3`。会话前缀 seam 将仅用于请求的目录按 loop 实例冻结,并记录在请求头中,在不将其加入持久化历史的前提下保持可重建性。完整 skill 正文从不包含在目录中。 +`dsh-tool-skill` 通过 [`agent/session-prefix`](2026-07-07-session-prefix.md) 贡献一个 user-role `<system-reminder>` 目录。该目录仅包含排序后的 skill 名称与描述;不包含正文、路径、来源、提供方和路由提示。描述经过空白规范化、XML 转义,并受 `catalogDescriptionMaxLength` 上限约束,其默认值为 `500`,最小值为 `3`。session-prefix seam 将仅用于请求的目录按 loop 实例冻结,并记录在请求头中,在不将其加入持久化历史的前提下保持可重建性。完整的 skill 正文从不包含在目录中。 -`skill({ name })` 工具为当前 agent cwd 加载一个完整 skill,返回包含 `<skill_content name="...">`、`<skill_resources>` 和 `<skill_instructions>` 的工具结果。`resourceBase` 提供一个目录、URL 或不透明的提供方管理的基路径,用于显式引用的脚本、参考资料和资产;资源仅按需加载,不进行目录枚举。无法解析的名称报告该 skill 未知或不再可用;无效名称和标记了 `disableModelInvocation` 的 skill 保留不同的工具错误。工具结果是面向模型的披露路径。 +`skill({ name })` 工具为当前 agent cwd 加载一个完整 skill,返回包含 `<skill_content name="...">`、`<skill_resources>` 和 `<skill_instructions>` 的工具结果。`resourceBase` 提供一个目录、URL 或不透明的提供方管理的基路径,用于显式引用的脚本、参考资料和资产;资源仅按需加载,不进行目录枚举。无法解析的名称报告该 skill 未知或不再可用;无效名称和标记了 `disableModelInvocation` 的 skill 保留不同的工具错误。工具结果是面向模型的可见披露路径。 -数据结构与目录/工具契约记录在 [skills.md](../../../core-data-structures/skills.md),服务签名见生成的[服务目录](../../../cordis-catalog/services.md)。 +数据结构与目录/工具契约记录在 [skills.md](../../../core-data-structures/skills.md) 中,服务签名见生成的[服务目录](../../../cordis-catalog/services.md)。 ## 曾考虑的替代方案 **将完整 skill 正文注入每条系统提示词。** 否决,因为这破坏了渐进式披露,使每个请求都为可能不适用的指令付出代价。 -**仅将 skill 暴露为斜杠命令。** 否决,因为模型主动加载才是核心能力;斜杠/ACP 命令广播不改变发现机制。 +**仅以斜杠命令暴露 skill。** 否决,因为模型主动加载是核心能力;斜杠/ACP 命令广播不改变发现机制。 -**将本地文件系统扫描直接放在 `ctx.skills` 内。** 否决,因为编码 agent、Web agent 和未来的插件生态需要不同的 skill 来源。提供方注册表与 subagent seam 同构:注册表负责冲突解析和消费方,实现负责加载。 +**将本地文件系统扫描直接放入 `ctx.skills`。** 否决,因为编码 agent、Web agent 和未来的插件生态需要不同的 skill 来源。提供方注册表与 subagent seam 镜像:注册表拥有冲突解决和消费方,实现拥有加载。 **使用系统提示词段落。** 否决,因为渲染后的系统提示词是单一字符串,而目录是一条具有仅请求生命周期要求的 user-role `<system-reminder>` 消息。[`agent/session-prefix`](2026-07-07-session-prefix.md) 是选定的机制:它将目录置于派生历史之前,并将组合后的消息记录在请求头中。 -**将内置 DSH 编写 skill 物化到 `~/.dsh/skills/.system`。** 否决,因为打包的 skill 不应在启动时写入用户主目录,嵌入式或远程提供方在配置后提供 skill。 +**在 `~/.dsh/skills/.system` 下物化内置 DSH 编写 skill。** 否决,因为打包的 skill 不应在启动时写入用户主目录,嵌入式或远程提供方在配置后提供 skill。 -**递归发现嵌套的 `**/SKILL.md`。** 否决。扁平文件和一级目录包已覆盖配置的根目录,同时保持重复处理和目录顺序易于推理。 +**递归发现嵌套的 `**/SKILL.md`。** 否决。扁平文件和一级目录包覆盖了配置的根目录,同时使重复处理和目录顺序易于推理。 -**手写 frontmatter 解析器。** 否决,因为已接受的 schema 包含一个开放的 `metadata` 对象。窄解析器要么拒绝用户期望能正常工作的合法 YAML,要么膨胀为一个未经评审的 YAML 子集。 +**手写 frontmatter 解析器。** 否决,因为已接受的 schema 包含一个开放的 `metadata` 对象。窄解析器要么拒绝用户预期可用的合法 YAML,要么膨胀为一个未经评审的 YAML 子集。 ## 后果 -agent-core 主干包含一个会话前缀贡献者、一个本地提供方和一个面向模型的工具。skill 发现对 cwd 敏感,因此以不同会话 cwd 值创建 agent 的调用方可以按设计观察到不同的项目 skill 覆盖。 +agent-core 主干包含一个 session-prefix 贡献者、一个本地提供方和一个面向模型的工具。Skill 发现是 cwd 敏感的,因此以不同会话 cwd 值创建 agent 的调用方可以按设计观察到不同的项目 skill 覆盖。 -目录在固定的根目录集和运行时注册修订版本下是确定性的,但不监听磁盘变化;发现结果被缓存,直到运行时注册使缓存失效或进程重启。 +目录对于固定的根目录集合和运行时注册修订版本是确定性的,但不监视磁盘变化;发现结果被缓存,直到运行时注册使缓存失效或进程重启。 ## 延后 -fork 式 skill 上下文(`context: fork`)、直接用户/斜杠调用(`user-invocable`)、参数声明与提示(`arguments` 和 `argument-hint`),以及逐 skill 的工具约束(`allowed-tools` 和 `disallowed-tools`)不在已交付的契约范围内。注册表、本地提供方和面向模型的工具不解析、不广播、不强制执行这些字段。 +Fork 的 skill 上下文(`context: fork`)、直接用户/斜杠调用(`user-invocable`)、参数声明与提示(`arguments` 和 `argument-hint`)、以及逐 skill 的工具约束(`allowed-tools` 和 `disallowed-tools`)不在已交付的契约范围内。注册表、本地提供方和面向模型的工具不解析、不广播、也不执行这些字段。 diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml index 2e89e359db..8d7fa05dfc 100644 --- a/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-06-approval-seam.md: 3ef51c31216bf9f0c5d945748ab3f901ec82147c -2026-07-06-approval-seam.zh.md: cec1692d509a7c9a0680773fbdbbb18e1c90ab8c +2026-07-06-approval-seam.zh.md: 1bf679426a434c36f5363c3b70f13a8f24534df3 diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md b/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md index cec1692d50..1bf679426a 100644 --- a/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md @@ -1,4 +1,4 @@ -# RFC:审批 seam——通过应答者瀑布式事件实现一次性权限决策 +# RFC:审批 seam——基于 waterfall(瀑布式事件)应答者的一次性权限决策 Status: implemented @@ -6,17 +6,17 @@ Status: implemented ## 问题 -两个调用方需要向人类提出同一个问题——「这个具体操作可以继续吗?」:`tools/pre-execute` 的 `ask` 决策(包括 Claude-Code 钩子桥的 `permissionDecision: ask`)以及[沙箱 RFC](2026-07-06-sandbox.md) 中拒绝后的一次性升级重试。一个共享的 seam 使它们不必各自发明结果词汇、UI 路由、取消机制和审计追踪,同时保证没有 UI 的部署永远不会批准一个无法应答的请求。 +两个调用方需要向人类提出同一个问题——「这个具体操作可以继续吗?」:`tools/pre-execute` 的 `ask` 决策(包括 Claude-Code 钩子桥的 `permissionDecision: ask`)以及[沙箱 RFC](2026-07-06-sandbox.md) 中拒绝后的一次性升级重试。一个共享的 seam 使它们无需各自发明独立的结果词汇、UI 路由、取消机制和审计轨迹,同时保证没有 UI 的部署永远不会批准一个无法应答的请求。 -路由问题的本质是归属:审批提示必须到达拥有发起请求的 agent 的那个编辑器会话(ACP 桥在一条连接上复用 N 个会话),对无人拥有的 agent(进程内 subagent、测试)默认拒绝(fail-closed),并且不介入没有组合 UI 的部署(无头模式、CI)。 +路由问题的核心是归属:审批提示必须到达拥有发起请求的 agent(智能体)的编辑器会话(ACP(Agent Client Protocol)桥在一条连接上多路复用 N 个会话),对无人拥有的 agent(进程内 subagent、测试)失败关闭,并且不侵入没有组合 UI 的部署(headless、CI)。 ## 决策 -一个包 `dsh-user-approval`(`packages/ui/user-approval`),拥有词汇表和 `ctx.approval` 服务——即机制(MECHANISM)。策略(POLICY)——谁来应答、以及某个会话是否被询问——位于其外部:应答者是 `approval/request` waterfall(瀑布式事件)监听器,由拥有通道的插件注册(ACP 桥、未来的终端 UI、测试脚本),而每会话的策略层可以在任何人类介入之前做出决定。消费方(`dsh-tools` 的 ask 路由、沙箱升级门禁)将问题解析为一个封闭的结果,并从中派生各自的工具结果。刻意只用一个包,而非能力 seam 的三包拆分(见「曾考虑的替代方案」)。 +一个包 `dsh-user-approval`(`packages/ui/user-approval`),拥有词汇表和 `ctx.approval` 服务——即**机制**。**策略**——谁来应答、某个会话是否需要被询问——不在其中:应答者是 `approval/request` waterfall 监听器,由拥有通道的插件注册(ACP 桥、未来的终端 UI、测试脚本),而每会话的策略层可以在任何人类介入之前做出决定。消费方(`dsh-tools` 的 ask 路由、沙箱升级门禁)将问题解析为一个封闭结果,并从中派生各自的工具结果。刻意设计为**一个**包,而非能力 seam 的三包拆分(见「替代方案」)。 ### 部署如何使用它 -一条 `cordis.yml` 条目挂载该 seam。不加载它即为 fail-closed 退出方式:消费方在没有注册任何审批代码的情况下拒绝无法应答的请求。 +一条 `cordis.yml` 条目挂载该 seam。不加载它就是失败关闭的退出方式:消费方在没有注册任何审批代码的情况下拒绝无法应答的请求。 ```yaml - id: approval @@ -25,11 +25,11 @@ Status: implemented # policy: never # deployment default for sessions without an override; 'ask' when omitted ``` -仅有这条条目提供的是机制而非通道:没有组合应答者时,每次 ask 解析为 `unavailable`,发起 ask 的工具调用被拒绝——默认拒绝无需配置。组合 ACP 应用(`@deepseek-ai/dsh-acp-demo`,如 [acp-agent 示例的默认树](../../../../examples/acp-agent/README.md))即可闭合回路:其桥注册一个应答者,通过 `session/request_permission` 向拥有该会话的编辑器发出提示,于是钩子的 `ask` 或升级请求会以一次性 Allow/Reject 提示的形式出现在已流式输出的工具调用上。`policy: never` 是无人值守姿态——每次 ask 确定性地自动拒绝,在系统提示词中声明,无人类参与。`policy` 在插件加载时针对封闭列表做校验;其他值直接抛异常。 +仅有这条条目只提供机制,不提供通道:没有组合应答者时,每次 ask 都解析为 `unavailable`,发起请求的工具调用被拒绝——失败关闭无需配置。组合 ACP 应用(`@deepseek-ai/dsh-acp-demo`,如 [acp-agent 示例的默认树](../../../../examples/acp-agent/README.md))即可闭环:其桥注册一个应答者,通过 `session/request_permission` 向拥有该会话的编辑器发出提示,于是钩子的 `ask` 或升级请求会以一次性 Allow/Reject 提示的形式呈现,附着在已流式输出的工具调用上。`policy: never` 是无人值守姿态:每次 ask 确定性地自动拒绝,在系统提示词中声明,无人类参与。`policy` 在插件加载时对照封闭列表校验;非法值直接抛异常。 -组合后的部署观察到的行为:`allowed-once` 仅允许该次调用继续;拒绝、关闭和通道缺失以三种不同的原因拒绝,模型可以区分它们;每次 ask 都在发起请求的 agent 的会话日志上落一对持久的 `approval/asked`/`approval/decided`;授权不会在发起请求的那次调用之后持续存在。 +组合部署的可观测行为:`allowed-once` 仅允许该次调用继续;拒绝、关闭和通道缺失以三种不同原因拒绝,模型可以区分;每次 ask 在发起请求的 agent 的会话日志上落一对持久的 `approval/asked`/`approval/decided` 事件;授权不会在发起请求的调用结束后继续存在。 -以下是在此组合下的一次 ask,逐字取自沙箱示例录制的 `escalation-approved` 场景——模型请求沙箱升级,门禁发起 ask,桥向拥有该会话的编辑器发出提示,用户点击 Allow once: +以下是该组合下的一次 ask,逐字取自沙箱示例录制的 `escalation-approved` 场景——模型请求沙箱升级,门禁发起 ask,桥向拥有该会话的编辑器发出提示,用户点击 Allow once: ``` tool/call bash {"command": "printf 'escalated\n' > escalated.txt && cat escalated.txt", @@ -45,94 +45,94 @@ approval/decided {"outcome": "allowed-once"} tool/result "escalated" — this one call ran under the wider mode; the grant died with it ``` -`escalation-rejected` 的孪生场景以 `{"outcome": "rejected"}` 结束:什么都不执行,模型的结果携带发起方逐字的 fail-closed 文本(`the user rejected escalating this command to "workspace-write"`)。钩子的 `permissionDecision: ask` 走完全相同的协议;只有发起方和拒绝文本不同(§ dsh-tools 中的 Ask 路由)。无头模式下,同一请求完全跳过提示并以 `unavailable` 结算。 +`escalation-rejected` 孪生场景以 `{"outcome": "rejected"}` 结束:不执行任何操作,模型的结果携带发起方的逐字失败关闭文本(`the user rejected escalating this command to "workspace-write"`)。钩子的 `permissionDecision: ask` 走完全相同的协议;只有发起方和拒绝文本不同(§ dsh-tools 中的 Ask 路由)。在 headless 环境下,同一请求完全跳过提示,直接结算为 `unavailable`。 ### 设计细节 #### seam:机制与策略分离 -经过校验并追加 `approval/asked` 后,`request()` 解析为 `allowed-once`、`rejected`、`cancelled` 或 `unavailable`。服务借用只读请求、运行应答者 waterfall、与取消竞争,并将抛出异常或无效应答归一化为 `unavailable`。随后追加匹配的 `approval/decided`,通过 `ApprovalRequestId` 配对。 +经过校验并追加 `approval/asked` 后,`request()` 解析为 `allowed-once`、`rejected`、`cancelled` 或 `unavailable`。服务借用只读请求,运行应答者 waterfall,与取消竞速,并将抛出异常或无效应答规范化为 `unavailable`。然后追加匹配的 `approval/decided`,以 `ApprovalRequestId` 配对。 -两个审计事件都必须在一个打开的轮次内;接受或 pre-commit 追加失败会拒绝该请求。Post-commit 观察者被会话所包含。`allowed-once` 仅授权所请求的操作,服务不保留任何授权状态。 +两个审计事件都必须在一个打开的轮次内;接受或预提交追加失败会拒绝该请求。提交后的观察者由会话容纳。`allowed-once` 仅授权所请求的操作,服务不保留任何授权状态。 -应答者是 `approval/request` waterfall 监听器。监听器为其拥有的 agent 返回结果,否则调用 `next()`。没有应答者时默认为 `unavailable`;因此卸载 UI 即默认拒绝,不会留下通道。由于兄弟插件的注册顺序不确定,部署应组合一个终端应答者,仅对「决定或委托」门禁使用 `prepend`。 +应答者是 `approval/request` waterfall 监听器。监听器为它拥有的 agent 返回结果,否则调用 `next()`。没有应答者时默认为 `unavailable`;因此卸载 UI 即失败关闭,不会留下悬空通道。由于兄弟插件的注册顺序不确定,部署应组合一个终端应答者,仅对「先决策或委派」门禁使用 `prepend`。 `ApprovalRequest` 携带 agent、工具名、可选的 `callId`、原因和 signal。agent 同时路由提示和审计事件。请求使用 `dsh-llm` 的 `CallId` 而不导入 `dsh-tools`,避免包循环。工具参数被省略,因为 UI 应答者附着在已渲染的调用上。 #### dsh-tools 中的 Ask 路由 -`ToolRegistry.execute()` 在拒绝路径之前将 `ask` 发送到审批 seam。只有 `allowed-once` 才继续执行;拒绝、取消和通道不可用产生三种模型可见的不同原因。注册表按调用查找可选服务,因此缺失或未加载的服务默认拒绝,不会阻塞注册表 fiber。无 agent 的执行同样默认拒绝,因为无法路由或审计。 +`ToolRegistry.execute()` 在进入拒绝路径之前,将 `ask` 发送到审批 seam。只有 `allowed-once` 才继续执行;拒绝、取消和通道不可用产生三种模型可见的不同原因。注册表按调用查找可选服务,因此服务缺失或未加载时失败关闭,不会阻塞注册表 fiber。无 agent 的执行同样失败关闭,因为无法路由或审计。 #### 每会话策略层 -seam 拥有会话策略 `'ask' | 'never'`,遵循[沙箱 RFC](2026-07-06-sandbox.md) 中的切换契约。生效的会话或配置策略在应答者之前应用:`'never'` 在 `request()` 内部拒绝,而 `'ask'` 派发请求,无人应答时降级为 `unavailable`。系统提示词仅声明确定性的 `'never'`;叙述者报告切换,每个请求仍然收到其审计对。 +seam 拥有会话策略 `'ask' | 'never'`,遵循[沙箱 RFC](2026-07-06-sandbox.md) 中的切换契约。生效的会话或配置策略在应答者之前应用:`'never'` 在 `request()` 内部直接拒绝,`'ask'` 则派发请求,无人应答时降级为 `unavailable`。提示词仅声明确定性的 `'never'`;叙述者报告切换,每个请求仍收到其审计对。 #### ACP 应答者 -ACP 桥找到拥有该会话的编辑器,为该 `callId` 发送 `session/request_permission`,并将一次性 allow、reject 和 cancel 响应映射到 seam 词汇。未知选项永远不授权。外部 agent 和没有 `callId` 的请求通过 `next()` 委托;RPC 失败变为 `unavailable`。桥应答请求但不决定哪些调用需要审批。 +ACP 桥找到拥有该会话的编辑器,为该 `callId` 发送 `session/request_permission`,并将一次性 allow、reject、cancel 响应映射到 seam 词汇。未知选项永远不授权。外部 agent 和没有 `callId` 的请求通过 `next()` 委派;RPC 失败变为 `unavailable`。桥应答请求,但不决定哪些调用需要审批。 -应答者通过 [ACP 支持 RFC](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md) 描述的桥反向映射归属 seam 进行路由,实现了[多会话 RFC](../../implemented/feature/2026-06-14-acp-multi-session.md) 所要求的每会话权限归属。 +应答者通过 [ACP 支持 RFC](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md) 描述的桥反向映射归属 seam 进行路由,实现了[多会话 RFC](../../implemented/feature/2026-06-14-acp-multi-session.md) 要求的每会话权限归属。 #### 审计,以及模型看到什么 -`approval/asked` 和 `approval/decided` 是持久的仅日志事件。模型只看到发起方记录的 `tool/result`。每个被接受的请求追加一条匹配的决策,包括取消和被包含的应答者失败。 +`approval/asked` 和 `approval/decided` 是持久的仅日志事件。模型只看到发起方派生的已记录 `tool/result`。每个被接受的请求追加一条匹配的决策,包括取消和被容纳的应答者失败。 #### 实体与依赖 -`dsh-user-approval` 拥有固定的派发与审计机制;`dsh-tools` 发起请求,`dsh-acp` 应答。可替换的应答者作为监听器留在其通道拥有者插件中,因此三包能力拆分只会增加一个空的实现层。沙箱执行器仍然只负责传输,静态能力授权与交互式审批保持分离。 +`dsh-user-approval` 拥有固定的派发与审计机制;`dsh-tools` 发起请求,`dsh-acp` 应答。可替换的应答者作为监听器留在其通道拥有者插件中,因此三包能力拆分只会多出一个空的实现层。沙箱执行器仍然只负责传输,静态能力授权与交互式审批保持分离。 ### 测试 -- **单元/集成测试:** 覆盖先到先得的委托、fail-closed 默认值、格式错误和抛异常的应答者、取消竞争与迟到应答丢弃、观察者失败下的审计配对、不可绕过的 `'never'`、不同的工具拒绝原因,以及 ACP 每会话路由/结果映射。 -- **快照测试:** 通过沙箱升级的两个分支编排权限应答并固定 `'never'` 提示词加策略切换通知。没有组合应答者时钩子产生的 ask 仍作为 fail-closed 拒绝被覆盖。 +- **单元/集成测试:** 覆盖先到先得的委派、失败关闭默认值、畸形和抛异常的应答者、取消竞速与迟到应答丢弃、观察者失败时的审计配对、不可绕过的 `'never'`、不同的工具拒绝原因,以及 ACP 每会话路由/结果映射。 +- **快照测试:** 对沙箱升级的两个分支编排权限应答并固定 `'never'` 提示词加策略切换通知。无组合应答者时钩子产生的 ask 仍作为失败关闭拒绝被覆盖。 ## 延后 -- **`allow_always` 授权存储**——兑现持久授权意味着设计存储、范围标识(调用?路径?前缀?会话?时间窗口?)和撤销;在设计完成之前,只宣告一次性选项([沙箱 RFC](2026-07-06-sandbox.md) § 升级记录了开放的范围问题)。 -- **有组合应答者时录制的钩子产生的 ask**——升级录制了人类提示的协议格式(wire format),而当前钩子 fixture(测试前置数据)固定的是无服务拒绝;它们组合的生产者/应答者路径仍由单元测试覆盖。 -- **将子 agent 的审批路由到父会话**——`subagent-acp` 的子端自动应答自己的 `permission` 请求;将它们呈现给父端编辑器是独立的设计。 +- **`allow_always` 授权存储**:兑现持久授权意味着设计存储、作用域标识(调用?路径?前缀?会话?时间窗口?)和撤销;在设计完成之前,只展示一次性选项([沙箱 RFC](2026-07-06-sandbox.md) § Escalation 记录了开放的作用域问题)。 +- **有组合应答者时录制的钩子产生的 ask**:升级场景录制了人类提示的协议格式(wire format),而当前钩子 fixture(测试前置数据)固定的是无服务拒绝;二者组合的生产者/应答者路径仍由单元测试覆盖。 +- **将子 agent 的审批路由到父会话**:`subagent-acp` 的子侧自动应答自己的 `permission` 请求;将其呈现给父会话的编辑器是独立的设计。 ## 曾考虑的替代方案 -- **单个注册提供方而非 waterfall 监听器**:否决。`registerProvider()` 接口迫使所有组合问题——白名单预过滤、外部钩子决策者、脚本化测试应答、人类前面的策略门禁——都塞进一个提供方实现。waterfall 从运行时已有的机制中获得组合能力、缺失时默认拒绝和 HMR(热模块替换) dispose(资源释放);seam 的 JSDoc 用约定固定单决策槽语义,而非发明一个提供方注册表。 -- **在 ACP 桥中内联 `tools/pre-execute` 权限门禁**:否决。对桥拥有的每次调用都弹出提示,会把发起 ask 的策略硬编码到 UI 插件中,无法服务第二个发起方(沙箱升级发生在执行开始之后,没有 pre-execute 时机),且让钩子产生的 `ask` 决策没有共享机制。 -- **通用用户交互 seam(`ctx.userInteraction`)**:否决作为审批机制。两者共享骨架(按 agent 路由、阻塞等待人类、处理缺失),但审批的契约在每个关键维度上都更窄:封闭的结果词汇而非自由文本、附着在工具调用上的协议原生提示而非通用表单、强制的缺失时默认拒绝、以及审计事件。因此审批不走已发布的 `packages/ui/user-interaction` / `ask_user_question` 引出路径——引出表单不是权限提示,自由文本应答不是封闭结果;如果两者未来趋同,共享提供方管道仍然开放。 -- **在 `dsh-tools` 中静态可选注入**:否决。vendor 的 cordis `Inject` 类型没有可选标志——对象形式将服务名映射到拦截配置,声明的 inject 会阻塞 fiber。`ctx.get('approval')` 是文档化的机会性消费模式(`tool-bash` 的 owner-token 查找、loop 的持久化探测),按调用读取存在性,在 HMR 下无需额外机制即可正确降级。 -- **能力 seam 的三包拆分**:否决。接口/实现/消费方适合实现可替换的 seam(bash-local vs bash-sandbox)。这里服务体是固定机制,可变部分是留在各自通道拥有者中的监听器——拆分只会制造一个空的实现包(「不要预防性拆分」)。 -- **现在就提供 `allow_always`**:否决。协议可以表达它,但兑现它意味着设计授权存储、范围标识和撤销(§ 延后)。宣告一个 harness 无法兑现的选项只会制造注定失败的授权。 +- **单一注册提供方而非 waterfall 监听器**:否决。`registerProvider()` 接口迫使所有组合问题——允许列表预过滤、外部钩子决策者、脚本化测试应答、人类前面的策略门禁——都塞进一个提供方实现。waterfall 从运行时已有的机制中获得组合能力、缺失时失败关闭和 HMR(热模块替换) dispose(资源释放);seam 的 JSDoc 以约定固定单决策槽语义,而非发明一个提供方注册表。 +- **在 ACP 桥中内联 `tools/pre-execute` 权限门禁**:否决。对桥拥有的每次调用都弹出提示,会将请求**策略**硬编码进 UI 插件,无法服务第二个发起方(沙箱升级发生在执行开始之后,没有 pre-execute 时刻),且钩子产生的 `ask` 决策没有共享机制。 +- **通用用户交互 seam(`ctx.userInteraction`)**:否决作为审批机制。二者骨架相似(按 agent 路由、阻塞等待人类、处理缺失),但审批的契约在每个关键维度上都更窄:封闭的结果词汇而非自由文本、附着在工具调用上的协议原生提示而非通用表单、强制的缺失时失败关闭、以及审计事件。因此审批不走已交付的 `packages/ui/user-interaction` / `ask_user_question` 引出路径——引出表单不是权限提示,自由文本应答不是封闭结果;如果二者将来趋同,共享提供方管道仍然开放。 +- **`dsh-tools` 中的静态可选注入**:否决。vendor 的 Cordis `Inject` 类型没有 optional 标志——对象形式将服务名映射到拦截配置,声明的 inject 会阻塞 fiber。`ctx.get('approval')` 是文档化的机会性消费模式(`tool-bash` 的 owner-token 查找、loop 的持久化探测),按调用读取存在性,跨 HMR 正确降级,无需额外机制。 +- **能力 seam 的三包拆分**:否决。接口/实现/消费方适合实现可替换的 seam(bash-local vs bash-sandbox)。此处服务体是固定机制,可变部分是留在各自通道拥有者插件中的监听器——拆分只会制造一个空的实现包(「不要预防性拆分」)。 +- **现在就提供 `allow_always`**:否决。协议能表达它,但兑现它意味着设计授权存储、作用域标识和撤销(§ 延后)。展示 harness 无法兑现的选项只会制造注定失败的授权。 ## 后果 -- 只有 `allowed-once` 才会派发被询问的操作;缺失、拒绝、取消或应答失败的路径均拒绝。 +- 只有 `allowed-once` 才会派发被询问的操作;缺失、拒绝、取消或应答失败的路径一律拒绝。 - 会话归属路由提示、策略和审计事件,不跨越编辑器会话。 - 被接受的请求追加一对持久审计事件;模型只看到最终的工具结果。 -- 没有加载该服务的部署不会发出审批提示或审计事件,并在工具边界拒绝每个 `ask`。 +- 没有该服务的部署不产生审批提示或审计事件,在工具边界拒绝每一个 `ask`。 代价与已接受的局限: -- **两个急于决策的应答者争抢同一个槽位。** 兄弟插件的监听器顺序不确定,seam 无法仲裁竞争的终端应答者——通过约定缓解(每个部署一个终端应答者;仅对「决定或委托」门禁使用 `prepend`),而非事件总线不具备的优先级机制。 -- **生产环境的验证依赖单一组合。** `ask` 有两个生产者家族——钩子桥通过 `tools/pre-execute`,以及沙箱升级通过其自身门禁——协议格式录制在沙箱示例的快照套件中,因此 seam 的真实覆盖率就是这一种组合,直到更多部署组合它。 -- **归属以 `Agent` 对象同一性为键。** 应答者通过桥现有的 WeakMap 解析会话;当前所有路径在 loop 和各 seam 之间传递同一个对象,但未来如果某个边界克隆或代理了 agent,桥会委托并默认拒绝——安全但静默无 UI——届时需要改用 session-id 匹配。 +- **两个急于决策的应答者竞争同一槽位。** 兄弟插件的监听器顺序不确定,seam 无法仲裁竞争的终端应答者。通过约定缓解(每个部署一个终端应答者;仅对「先决策或委派」门禁使用 `prepend`),而非事件总线不具备的优先级机制。 +- **生产环境验证依赖单一组合。** `ask` 有两个生产者家族——钩子桥通过 `tools/pre-execute`,沙箱升级通过自己的门禁——协议格式录制在沙箱示例的快照套件中;因此在更多部署组合它之前,seam 的真实覆盖面就是这一种组合。 +- **归属以 `Agent` 对象标识为键。** 应答者通过桥已有的 WeakMap 解析会话;当前所有路径在 loop 和各 seam 之间传递同一对象,但未来如果某个边界克隆或代理了 agent,桥会委派并失败关闭——安全,但静默无 UI——届时需要改用 session-id 匹配。 ## FAQ -- **在完全没有应答者的部署中(无头模式、CI)会发生什么?** 每次 ask 穿过空的 waterfall 降级为 `unavailable`,工具调用以「no approval channel is available」原因被拒绝。默认拒绝是零监听器的默认行为,不是配置。 -- **授权能持久化吗——「始终允许」?** 不能。`allowed-once` 仅授权单次被询问的操作,服务在请求之间不存储任何东西;`allow_always` 在授权存储设计完成之前刻意不宣告(§ 延后)。 -- **模型看到审批的什么?** 只看到发起方从结果派生的工具结果——审计对永远不进入 transcript(文本记录)。三种非授权原因各不相同,模型可以区分人类说「不」、提示被关闭、以及通道缺失。 -- **谁决定一次调用是否首先发起 ask?** 策略生产者:返回 `permissionDecision: ask` 的钩子、任何 `tools/pre-execute` 监听器、或沙箱升级门禁。seam 和桥只负责路由和应答;两者都不注入自己对「什么值得弹出提示」的判断。 -- **用户关闭提示或轮次在 ask 进行中中止时会发生什么?** 关闭映射为 `cancelled`,有自己的拒绝文本。已中止的 signal 以 `cancelled` 结算而不派发;ask 进行中的中止丢弃迟到的应答——无论如何只有一对审计事件,绝不会有两对。 -- **如果客户端以 harness 从未提供的选项应答会怎样?** 除已提供的 `allow_once` 之外的任何选项都映射为 `rejected`——来自不合规客户端的未知 optionId 永远不能授权。 -- **subagent 的审批如何路由?** 没有应答者拥有的 agent 穿过整个 waterfall 委托并默认拒绝——进程内 subagent 被刻意设计为不可应答。`subagent-acp` 子端的自动应答是独立的;将子端的 ask 路由到父端编辑器已延后(§ 延后)。 -- **`policy: 'never'` 在运行时实际改变了什么?** 服务在派发任何应答者之前将该会话的每次 ask 解析为 `rejected`(在服务内部,因此没有注册顺序能绕过它);系统提示词声明该策略;切换在边界处被叙述;每次自动拒绝仍然落一对审计事件。 +- **在完全没有应答者的部署中(headless、CI)会发生什么?** 每次 ask 穿过空的 waterfall 降级为 `unavailable`,工具调用以「no approval channel is available」原因被拒绝。失败关闭是零监听器的默认行为,不是配置。 +- **授权能持久化吗——「始终允许」?** 不能。`allowed-once` 仅授权单次被询问的操作,服务在请求之间不存储任何内容;`allow_always` 在授权存储设计完成之前刻意不展示(§ 延后)。 +- **模型看到审批的什么?** 只看到发起方从结果派生的工具结果——审计对永远不进入 transcript(文本记录)。三种非授权原因各不相同,模型可以区分人类说「不」、提示被关闭、通道缺失。 +- **谁决定一次调用是否需要 ask?** 策略生产者:返回 `permissionDecision: ask` 的钩子、任何 `tools/pre-execute` 监听器、或沙箱升级门禁。seam 和桥只负责路由和应答;二者都不注入自己对「什么值得弹出提示」的判断。 +- **用户关闭提示或轮次在 ask 进行中中止时会发生什么?** 关闭映射为 `cancelled` 并携带自己的拒绝文本。已中止的 signal 直接结算为 `cancelled` 而不派发;ask 进行中的中止丢弃迟到的应答——无论哪种情况都恰好一对审计事件,绝不会两对。 +- **如果客户端以 harness 从未提供的选项应答呢?** 除已提供的 `allow_once` 之外的任何选项都映射为 `rejected`——来自不合规客户端的未知 optionId 永远不能授权。 +- **subagent 的审批如何路由?** 没有应答者拥有的 agent 穿过整个 waterfall 委派并失败关闭——进程内 subagent 被刻意设计为不可应答。`subagent-acp` 的子侧自动应答是独立的;将子 agent 的 ask 路由到父会话的编辑器已延后(§ 延后)。 +- **`policy: 'never'` 在运行时实际改变了什么?** 服务在派发任何应答者之前,将该会话的每次 ask 解析为 `rejected`(在服务内部,因此没有注册顺序能绕过它);系统提示词声明该策略;切换在边界处被叙述;每次自动拒绝仍落一对审计事件。 - **热重载或 UI 插件在会话中途卸载时会发生什么?** 应答者随其拥有的 fiber 一起 dispose,因此下一次 ask 降级为 `unavailable` 而非挂在死通道上;重新挂载会重新注册应答者,无需追赶状态。 -- **用户在哪里看到自己在批准什么?** 在工具调用本身上:提示通过 `callId` 附着在已流式输出的调用上(包含参数),并添加发起方的人类可读 `reason`;请求本身不携带参数副本。 +- **用户在哪里看到自己在批准什么?** 在工具调用本身:提示通过 `callId` 附着在已流式输出的调用上(包含参数),并添加发起方的人类可读 `reason`;请求本身不携带参数副本。 ## 先例 -本设计复用或对比的仓库内先例: +本设计复用或对照的仓库内先例: -- `fs/write-intent` 门禁(`packages/fs/fs/`)——文档化的单占位决策槽 waterfall 语义(先到先得、通过 `next()` 委托),应答者契约复用了它。 -- `hook/invoked`/`hook/result`——仅日志审计对先例,`approval/asked`/`approval/decided` 沿用了它;[钩子桥 RFC](2026-06-30-hook-bridges.md) 发布了 `permissionDecision: ask`,即第一个生产者。 +- `fs/write-intent` 门禁(`packages/fs/fs/`)——文档化的单占用决策槽 waterfall 语义(先到先得,通过 `next()` 委派),应答者契约复用了它。 +- `hook/invoked`/`hook/result`——仅日志审计对先例,`approval/asked`/`approval/decided` 沿用了它;[钩子桥 RFC](2026-06-30-hook-bridges.md) 交付了 `permissionDecision: ask`,即第一个生产者。 - [拦截 seam RFC](2026-06-30-interception-seams.md)——`tools/pre-execute` 的 `allow`/`deny`/`ask` 词汇,本 seam 服务其中的 `ask`。 - [ACP 支持 RFC](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md)——应答者路由所经过的 `WeakMap<Agent, sessionId>` 归属 seam;[多会话 RFC](../../implemented/feature/2026-06-14-acp-multi-session.md)——本设计实现的每会话权限归属阻塞项。 - 机会性 `ctx.get()` 消费模式(`tool-bash` 的 owner-token 查找、loop 的持久化探测)——`dsh-tools` 消费该 seam 而不阻塞其 fiber 的方式。 diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml index 352331b13d..0e418c8e57 100644 --- a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-06-explicit-tool-order.md: 9d94496ffdcbc4c7df820581b02e3e075ec1c0be -2026-07-06-explicit-tool-order.zh.md: fa3a5bbf83115c25f87471b8a3847b9347d42934 +2026-07-06-explicit-tool-order.zh.md: 0b020f969299799289e18ed93c81db08cabc0b2d diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md index fa3a5bbf83..0b020f9692 100644 --- a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md @@ -1,50 +1,50 @@ # RFC:显式的模型侧工具顺序 -Status: implemented - [English](2026-07-06-explicit-tool-order.md) | 中文 +Status: implemented + ## 问题 -模型侧的工具顺序此前跟随插件注册顺序,而注册顺序取决于彼此独立的插件在并发模块加载时的竞态。这一竞态导致 CI 和快照录制中产生不同的请求头。由于顺序影响请求字节、缓存和持久化的头部,需要一个显式的确定性策略。 +模型侧的工具顺序此前跟随插件注册顺序,而注册顺序取决于相互独立的插件的并发模块加载。这种竞态在 CI 和快照录制中产生了不同的请求头。由于顺序影响请求字节、缓存和持久化的 header,因此需要一个显式的确定性策略。 ## 决策 -系统提示词组装拥有模型侧工具的权威顺序,正如它已经拥有 section 顺序一样。`dsh-system-prompt` 上的 `toolOrder?: string[]` 是可选的显式策略: +系统提示词的组装逻辑拥有模型侧工具顺序的权威定义,正如它已经拥有 section 顺序的权威定义一样。`dsh-system-prompt` 上的 `toolOrder?: string[]` 是可选的显式策略: -- 列表中已注册的工具取其列出的位置。 -- 列表中的名称没有对应的已注册工具,属于配置错误。形状错误(缺少 rest 条目或名称重复)在服务构造器中快速失败;未注册的名称在每次 `assemble()` 时拒绝——这是已注册工具集存在可供检查的最早时刻(工具插件在服务构造之后注册),也是唯一的通用时刻(注册随时可能变化;Cordis 没有「所有插件已加载」事件)。在已交付的 agent loop 下,第一个轮次在任何模型请求之前就会失败——确切的影响范围见下文「后果」。 -- 已注册但不在列表中的工具,插入到 `'<unlisted-tools>'` rest 条目(`TOOL_ORDER_REST`)处,在其他未列出的工具之间按名称字典序排列。 -- 任何已收集的工具不得使用 `TOOL_ORDER_REST` 作为其 `ToolSchema.name`;组装在排序之前就会拒绝该保留名称。 -- 列表必须恰好包含一个 rest 条目,且名称不得重复。 +- 列表中已注册的工具按列表位置排列。 +- 列表中的名称没有对应的已注册工具,属于配置错误。形状错误(缺少 rest 条目或名称重复)在服务构造器中快速失败;未注册的名称则在每次 `assemble()` 时拒绝——这是已注册工具集存在并可供检查的最早时刻(工具插件在服务构造之后才注册),也是唯一的通用时刻(注册随时可能变化;Cordis 没有「所有插件已加载」事件)。在已交付的 agent loop(智能体循环)下,第一个轮次在发出任何模型请求之前就会失败——确切的影响范围见下文「后果」。 +- 已注册但不在列表中的工具,插入到 `'<unlisted-tools>'` rest 条目(`TOOL_ORDER_REST`)的位置,与其他未列出的工具按名称字典序排列。 +- 任何已收集的工具不得使用 `TOOL_ORDER_REST` 作为其 `ToolSchema.name`;组装逻辑在排序之前就会拒绝这个保留名称。 +- 列表必须恰好包含一个 rest 条目,且不得有重复名称。 - 当 `toolOrder` 未设置时,权威顺序为纯字典序(code-unit 比较,与 locale 无关),因此无需配置即可保证确定性。 -`assemble()` 在 `system-prompt/assemble` waterfall(瀑布式事件)之前规范化提供方工具,从源头消除注册顺序差异。waterfall 从这个确定性列表出发;未被改变的顺序随后流入请求头、冻结请求和重建检查,无需循环特有的排序逻辑。 +`assemble()` 在 `system-prompt/assemble` waterfall(瀑布式事件)之前对提供方工具进行规范化排序,从源头消除注册顺序的差异。waterfall 从这个确定性列表开始;不变的顺序随后流入请求头、冻结的请求和重建检查,无需 loop 特有的排序逻辑。 -范围刻意收窄:本 RFC 修复的是注册顺序竞态,而非插件行为。`system-prompt/assemble` 的监听器仍可添加、移除或重排工具——正如它可以在 section 排序之后编辑 section——并对自身输出的确定性负责;waterfall 契约已要求监听器具有确定性(可重建性不变式会捕获在构建与回放之间表现不一致的监听器)。 +范围刻意收窄:本 RFC 修复的是注册顺序竞态,而非插件行为。`system-prompt/assemble` 的监听器仍然可以添加、移除或重排工具——正如它可以在 section 排序之后编辑 section——并对自身输出的确定性负责;waterfall 契约已经要求监听器是确定性的(可重建性不变式会捕获在构建与回放之间行为不一致的监听器)。 -配置传递沿用 `persona` 的先例,`toolOrder` 与它并列:应用配置(`dsh-stdio-demo`、`dsh-acp-demo`)接受该键,并通过 `dsh-agent-spine-demo`(其 schema 是各所有者 schema 的交集)转发给 `SystemPrompt` 子服务。有一个 schemastery 细节是关键的:schemastery 数组默认为 `[]`,但省略的 `toolOrder` 必须保持 ABSENT(= 字典序),而不是变成一个显式配置的空列表(无效——缺少 rest 条目),因此链上的每个 schema 都将默认值强制为 `undefined`。 +配置传递沿用 `persona` 的先例,`toolOrder` 与之并列:应用配置(`dsh-stdio-demo`、`dsh-acp-demo`)接受该键,并通过 `dsh-agent-spine-demo`(其 schema 是各所有者 schema 的交集)转发给 `SystemPrompt` 子服务。有一个 schemastery 细节至关重要:schemastery 数组默认为 `[]`,但省略的 `toolOrder` 必须保持 ABSENT(= 字典序),而不是变成一个显式配置的空列表(无效——缺少 rest 条目),因此链路上每个 schema 都将默认值强制为 `undefined`。 ## 曾考虑的替代方案 -- **注册顺序(现状)**:并发导入竞态,依赖宿主环境(上述 CI 不稳定),评审中不可见。 -- **插件依赖图的线性化**:该关系是偏序的,独立的工具插件之间不可比较;上述不稳定发生时偏序已完全满足。 -- **每个插件在工具贡献上设 `weight`**:将顺序分散到各插件中,仍需一个无人拥有的全局编号约定(section 的 `order` 分段已经展示了这种协调成本需要手工承担)。 -- **在 `ToolRegistry.schemas()` 中排序(注册表层)**:同样确定,但注册表是一个被组装之外的更多消费方使用的成员存储;排序是 prompt 组合的关注点,而组装已经拥有 section 的组合策略。 -- **`LlmService` 配置 + 循环在记录头部前调用的 `orderTools()` 方法**:可行,但仅为在远处应用策略就增加了一个公开服务方法和一处循环改动;每个未来的请求组合者都必须记得调用。在列表诞生处规范化使无序列表不可表示,且零新增接口。 -- **在 `llm.stream()` 内部规范化**:在头部事件记录之后才运行(不稳定仍存在),且需要重建深度冻结的信封,静默地解除了重建不变式。 +- **注册顺序(现状)**:并发导入竞态,依赖宿主环境(上述 CI 抖动),评审中不可见。 +- **插件依赖图的线性化**:该关系是偏序的,独立的工具插件不可比较;抖动发生时偏序已完全满足。 +- **每个插件在其工具贡献上标注 `weight`**:将顺序分散到各插件中,仍需一个无人拥有的全局编号约定(section 的 `order` 分段已经展示了这种协调成本需要手工承担)。 +- **在 `ToolRegistry.schemas()` 中排序(注册表层)**:同样确定,但注册表是一个成员存储,被组装之外的多方消费;排序是 prompt 组合的关注点,而组装逻辑已经拥有 section 的组合策略。 +- **在 `LlmService` 上加配置 + `orderTools()` 方法,由 loop 在记录 header 前调用**:可行,但仅为在远处应用一个策略就增加了一个公开服务方法和一处 loop 改动;每个未来的请求组合者都必须记得调用。在列表诞生处进行规范化使得无序列表不可表示,且零新增接口。 +- **在 `llm.stream()` 内部规范化**:在 header 事件已记录之后才运行(抖动仍然存在),且需要重建深度冻结的信封,静默地解除了重建不变式。 - **穷举列表(无 rest 条目)**:每个新加载的工具插件都会导致启动失败;强制的 rest 条目使未列出的工具保持确定性,且其位置是显式的。 -- **启动时校验(`dsh-app-boot` 在 `loader.await()` 之后调用 `SystemPrompt.assertToolOrderSatisfied()`)**:能将配置错误变为启动死亡而非首轮失败,但需要一个公开服务方法加上通用启动胶水对单一服务的结构耦合,且无论如何不能替代组装时检查(嵌入式调用者从不运行 app boot;注册在 boot 之后仍会变化)。也没有现成事件可以承载该检查:Cordis v4 没有 ready 类事件,`loader/entry-init`/`internal/status` 在加载中途触发(与工具注册竞态——正是本 RFC 要消除的熵源),而 agent 生命周期事件不会早于组装。在 `assemble()` 设一个执行点被判定值得接受较晚的失败时刻。 +- **启动时校验(由 `dsh-app-boot` 在 `loader.await()` 之后调用 `SystemPrompt.assertToolOrderSatisfied()`)**:能将错误配置变为启动时死亡而非首轮次失败,但代价是一个公开服务方法加上通用启动胶水对单个服务的结构耦合,且无法替代组装时检查(嵌入式调用者从不运行 app boot;注册在 boot 之后仍会变化)。也没有现成事件可以承载该检查:Cordis v4 没有 ready 类事件,`loader/entry-init`/`internal/status` 在加载中途触发(与工具注册存在竞态——正是本 RFC 要消除的熵源),而 agent 生命周期事件不会早于组装。在 `assemble()` 设置单一执行点被判定值得接受较晚的失败时刻。 ## 后果 -- 每个由注册表构建的组装在任何宿主上都以确定性工具顺序开始;在没有专家监听器刻意改变的情况下,每个 `request/header` 事件和模型请求都继承该顺序。CI 与本地之间的注册顺序翻转在结构上被消除,默认为字典序。 -- 初始 `PromptAssembly.tools` 是权威的,因此 waterfall 监听器从模型侧顺序出发;提供方注册顺序在该协作 seam 之前的任何地方都不可观测。 -- 步骤之间的纯工具重排只能表示为 `request/header` 的 `'fallback'` 快照(基于名称键的 `ToolsDelta` 无法表达它);在稳定的权威顺序下,这种重排在实践中不再发生,因此 fallback 路径仅作为安全阀保留。 -- `toolOrder` 键沿 app → `agent-core` → `SystemPrompt` 转发链传递,因此部署时在 app 配置中与 `persona` 并列设置;`dsh-llm` 和 agent loop 不受影响。 -- `toolOrder` 中拼写错误或未加载的工具名称在 prompt 组装时使轮次失败,而非启动时:循环在轮次内组装(`turn/start` 之后、`step/start` 之前),因此拒绝到达轮次的外层 catch——轮次以 `error` 原因平衡关闭并携带消息,`agent/error` 镜像它,不开启步骤,不记录 `request/header`,不向适配器发出请求,agent 回到空闲。每个轮次都以相同方式失败,直到配置被修正;进程本身保持运行(与仓库规则一致:显式配置引用不得被静默忽略——执行点在组装处,因为不存在更早的通用时刻)。 -- 工具提供方返回保留的 rest 条目名称时,其 prompt 组装失败形态与未知的列出名称相同。这防止哨兵值变成歧义的真实工具,并保持「从不丢弃工具」的排序契约。 +- 每个由注册表构建的组装在任何宿主上都以确定性工具顺序开始;在没有专家监听器刻意改变的情况下,每个 `request/header` 事件和模型请求都继承该顺序。CI 与本地之间的注册顺序翻转从结构上被消除,默认为字典序。 +- 初始 `PromptAssembly.tools` 是权威的,因此 waterfall 监听器从模型侧顺序开始;提供方注册顺序在该协作 seam 之前无处可观测。 +- 步骤之间的纯工具重排只能表示为 `request/header` 的 `'fallback'` 快照(按名称索引的 `ToolsDelta` 无法表达它);在稳定的权威顺序下,这种重排在实践中不再发生,因此 fallback 路径仅作为安全阀存在。 +- `toolOrder` 键沿 app → `agent-core` → `SystemPrompt` 的转发链传递,因此部署时将其放在 app 配置中 `persona` 旁边即可;`dsh-llm` 和 agent loop 无需改动。 +- `toolOrder` 中拼错或未加载的工具名称在 prompt 组装时使轮次失败,而非启动时:loop 在轮次内部组装(`turn/start` 之后、`step/start` 之前),因此拒绝到达轮次的外层 catch——轮次以 `error` 原因平衡关闭并携带错误消息,`agent/error` 镜像该消息,不打开步骤,不记录 `request/header`,不向适配器发出请求,agent 回到空闲状态。每个轮次都以相同方式失败,直到配置被修正;进程本身保持运行(符合仓库规则:显式配置引用不得被静默忽略——执行点是组装,因为不存在更早的通用时刻)。 +- 工具提供方返回保留的 rest 条目名称时,其 prompt 组装失败形态与未知的已列名称相同。这防止哨兵值变成一个歧义的真实工具,并保持「从不丢弃工具」的排序契约。 ## 测试 -系统提示词测试覆盖字典序默认顺序、列出/rest 位置、提供方顺序无关性、共享名称、无效列表、未知或保留名称、waterfall 前的权威列表,以及监听器添加的工具不被重新排序的规则。循环测试固定跨注册排列的已记录和已分发顺序一致、通过 agent-core 和两个 app 的转发、深度冻结请求,以及在未知配置名称下的平衡轮次失败(无步骤、无头部、无适配器调用)。快照回放仅在固定的 `text-turn` 头部中保留完整的权威列表;其他 fixture(测试前置数据)继续使用 `{{tools}}`。 +系统提示词测试覆盖:字典序默认顺序、列表/rest 位置、提供方顺序无关性、共享名称、无效列表、未知或保留名称、waterfall 前的权威列表,以及监听器添加的工具不被重新排序的规则。Loop 测试固定:跨注册排列的已记录与已分发顺序一致、通过 agent-core 和两个 app 的转发、深度冻结的请求,以及在配置了未知名称时的平衡轮次失败(无步骤、无 header、无适配器调用)。快照回放仅在固定的 `text-turn` header 中保留完整的权威列表;其他 fixture(测试前置数据)继续使用 `{{tools}}`。 diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml index c36f317c2f..03a68c9166 100644 --- a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-07-mcp-client-plugin.md: 7706190257b54730532e4aa46cc9c47453c59871 -2026-07-07-mcp-client-plugin.zh.md: 4d2ea8532afbf6160a98020b8cc480e1bf683981 +2026-07-07-mcp-client-plugin.zh.md: b5fee7eff7f12de5658f0a10c32cfeed71482fdf diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md index 4d2ea8532a..b5fee7eff7 100644 --- a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md @@ -6,15 +6,15 @@ Status: implemented ## 问题 -harness 此前无法消费 MCP(Model Context Protocol)生态的工具。MCP 是工具服务器的新兴标准:GitHub、文件系统、数据库、代码搜索以及数百个社区服务器都通过 MCP 暴露工具。用户希望将 harness 指向一个或多个 MCP 服务器,让它们的工具以原生的模型可见工具形式出现,而无需为每个服务器编写胶水代码。 +harness 此前无法消费 MCP(Model Context Protocol)生态中的工具。MCP 是工具服务器的新兴标准——GitHub、文件系统、数据库、代码搜索以及数百个社区服务器都通过 MCP 暴露工具。用户希望将 harness 指向一个或多个 MCP 服务器,让其工具以原生的模型可见工具形式出现,而无需为每个服务器编写胶水代码。 -`ToolRegistry` 已经接受原始 JSON Schema 工具定义(见 `dsh-tools` README:"Raw JSON-Schema tool definitions (from MCP servers) are still accepted by `ToolRegistry.register()` directly"),扩展实操手册(cookbook)也勾勒了预期模式("MCP | one plugin per server: discover tools → `ctx.tools.register()`")。基础设施已就绪,缺的是桥接插件。 +`ToolRegistry` 已经接受原始 JSON Schema 工具定义(`dsh-tools` README 中有记录:"Raw JSON-Schema tool definitions (from MCP servers) are still accepted by `ToolRegistry.register()` directly"),扩展实操手册(cookbook)也勾勒了预期模式("MCP | one plugin per server: discover tools → `ctx.tools.register()`")。基础设施已就绪,缺的是桥接插件。 ## 决策 ### 包 -单个包 `@deepseek-ai/dsh-mcp-client`,位于 `packages/mcp/mcp-client/`。不做能力 seam 三包拆分:可预见范围内不会有第二种 MCP 客户端实现,且约定是「不要预防性拆分」(见[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md))。 +单个包(package) `@deepseek-ai/dsh-mcp-client`,位于 `packages/mcp/mcp-client/`。不做能力 seam 的三包拆分——可预见范围内不会有第二种 MCP 客户端实现,且约定是"不要预防性拆分"([能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md))。 ### SDK @@ -22,11 +22,11 @@ harness 此前无法消费 MCP(Model Context Protocol)生态的工具。MCP ### 范围 -仅 MCP 客户端(不含服务器端——ACP 已覆盖「将 harness 暴露为 agent」的角色)。仅桥接 **Tools**:Resources 和 Prompts 推迟(它们需要 harness 侧尚不存在的消费机制,且设计空间很大)。 +仅 MCP Client(不含 server 端——ACP 已承担"将 harness 暴露为 agent"的角色)。仅桥接 **Tools**——Resources 和 Prompts 延后处理(它们需要 harness 侧尚不存在的消费机制,且设计空间较大)。 ### 插件形态 -命名空间插件(具名导出 `name`/`inject`/`Config`/`apply`,无 `export default`)。`inject: ['tools']`。每个 MCP 服务器在 `cordis.yml` 中是一个插件实例:同一个包以不同配置加载 N 次,与 `dsh-tool-subagent` 相同。 +命名空间插件(具名导出 `name`/`inject`/`Config`/`apply`,无 `export default`)。`inject: ['tools']`。每个 MCP 服务器对应 `cordis.yml` 中的一个插件实例——同一个包以不同配置加载 N 次,与 `dsh-tool-subagent` 相同。 ### 配置 @@ -54,7 +54,7 @@ interface StreamableHttpConfig { type Config = StdioConfig | StreamableHttpConfig ``` -`serverName` 是稳定的本地标识,用于在模型可见名称(见下文)中为该服务器的工具划定命名空间。它有意设计为用户配置,**不是**远端的 `serverInfo.name`:远端名称是不可信输入,跨部署不唯一(同一服务器的 prod 和 staging 实例报告相同名称),且可能在服务器升级时变化——这些都不得静默地重命名模型可见工具。多个活跃实例使用相同 `serverName` 属于配置错误:后加载的实例在启动时以可操作的错误消息失败,绝不静默覆盖或跳过。短 `serverName`(如 `gh`)同时也是缩短公开名称的旋钮。 +`serverName` 是稳定的本地标识,用于在模型可见名称(见下文)中为该服务器的工具提供命名空间。它有意设计为用户配置,而**非**远端的 `serverInfo.name`:远端名称是不可信输入、跨部署不唯一(同一服务器的生产和预发布实例报告相同名称)、且可能在服务器升级时变化——这些都不得静默重命名模型可见工具。多个活跃实例使用重复的 `serverName` 属于配置错误:后加载的实例在启动时以可操作的错误消息失败,绝不静默覆盖或跳过。短 `serverName`(如 `gh`)也是缩短公开名称的调节手段。 `cordis.yml` 用法示例: @@ -83,28 +83,28 @@ type Config = StdioConfig | StreamableHttpConfig ### 生命周期 -启动时从 `cordis.yml` 加载。HMR(`@cordisjs/plugin-hmr`)提供热替换:编辑 yml 条目会触发旧实例的 dispose(断开连接、注销工具),并创建新实例(连接、发现、注册)。目前不提供运行时动态 API。公开名称是 `(serverName, rawName)` 的纯函数,因此保持 `serverName` 不变的 HMR 替换会重建完全相同的模型可见名称——会话历史和权限规则保持有效——且添加或移除一个无关服务器绝不会重命名已有工具。 +启动时从 `cordis.yml` 加载。HMR(热模块替换)(`@cordisjs/plugin-hmr`)提供热替换:编辑 yml 条目触发旧实例的 dispose(资源释放)(断开连接、注销工具),并创建新实例(连接、发现、注册)。目前不提供运行时动态 API。公开名称是 `(serverName, rawName)` 的纯函数,因此保持 `serverName` 不变的 HMR 替换会重建完全相同的模型可见名称——会话历史和权限规则保持有效——而添加或移除不相关的服务器永远不会重命名已有工具。 ### 工具发现与注册 每个 MCP 工具有两个名称: -- `rawName`:MCP `Tool.name` 的原始值,仅在协议层(`tools/call`)使用。 -- `publicName`:在 `ToolRegistry` 中注册的全局唯一模型可见名称: +- `rawName`——MCP `Tool.name` 的原始值,仅用于协议通信(`tools/call`)。 +- `publicName`——在 `ToolRegistry` 中注册的全局唯一模型可见名称: mcp__<serverName>__<rawName> -这种按服务器限定的形式是多服务器 agent 客户端的事实标准:所有被调研的终端用户产品都按服务器限定 MCP 工具([Claude Code](https://code.claude.com/docs/en/agent-sdk/mcp#tool-naming-convention) `mcp__github__list_issues`、[Codex](https://openai.com/index/unrolling-the-codex-agent-loop/) `mcp__weather__get-forecast`、[Gemini CLI](https://geminicli.com/docs/tools/mcp-server/#3-tool-naming-and-namespaces)、[VS Code](https://github.com/microsoft/vscode/blob/ab9ec62c6a61e429a9abd612ff220c3f4834c9ea/src/vs/workbench/contrib/mcp/common/mcpServer.ts#L217-L260)、[Cline](https://github.com/cline/cline/blob/52fdbb1d72f7324a28142a7ba7678d4b53c902f4/sdk/packages/core/src/extensions/mcp/name-transform.ts#L20-L35)、[Roo Code](https://github.com/RooCodeInc/Roo-Code/blob/b867ec9145750d0ae1ff7f02d35406e9bf2a0b16/src/utils/mcp-name.ts#L117-L140)、[Goose](https://github.com/block/goose/blob/b3a012cbdde854b0fe14f95b1c48543bf6517c0a/crates/goose/src/agents/extension_manager.rs#L1391-L1441)、[OpenCode](https://github.com/anomalyco/opencode/blob/d199b1bff90282a4f9cd6251b5fc7b16875a52f6/packages/opencode/src/mcp/catalog.ts#L117-L120));`mcp__<server>__<tool>` 的确切拼写沿用 Claude Code 和 Codex。`mcp__` 前缀将 MCP 注册隔离在原生工具命名空间之外,并为权限/遥测规则提供稳定的匹配形状(`mcp__*`、`mcp__github__*`)。 +这种按服务器限定的形式是多服务器 agent 客户端的事实标准——所有被调研的终端用户产品都按服务器限定 MCP 工具名([Claude Code](https://code.claude.com/docs/en/agent-sdk/mcp#tool-naming-convention) `mcp__github__list_issues`、[Codex](https://openai.com/index/unrolling-the-codex-agent-loop/) `mcp__weather__get-forecast`、[Gemini CLI](https://geminicli.com/docs/tools/mcp-server/#3-tool-naming-and-namespaces)、[VS Code](https://github.com/microsoft/vscode/blob/ab9ec62c6a61e429a9abd612ff220c3f4834c9ea/src/vs/workbench/contrib/mcp/common/mcpServer.ts#L217-L260)、[Cline](https://github.com/cline/cline/blob/52fdbb1d72f7324a28142a7ba7678d4b53c902f4/sdk/packages/core/src/extensions/mcp/name-transform.ts#L20-L35)、[Roo Code](https://github.com/RooCodeInc/Roo-Code/blob/b867ec9145750d0ae1ff7f02d35406e9bf2a0b16/src/utils/mcp-name.ts#L117-L140)、[Goose](https://github.com/block/goose/blob/b3a012cbdde854b0fe14f95b1c48543bf6517c0a/crates/goose/src/agents/extension_manager.rs#L1391-L1441)、[OpenCode](https://github.com/anomalyco/opencode/blob/d199b1bff90282a4f9cd6251b5fc7b16875a52f6/packages/opencode/src/mcp/catalog.ts#L117-L120));`mcp__<server>__<tool>` 的拼写方式与 Claude Code 和 Codex 一致。`mcp__` 前缀将 MCP 注册与原生工具的命名空间隔离,并为权限/遥测规则提供稳定的匹配模式(`mcp__*`、`mcp__github__*`)。 -1. 连接时:遍历 `client.listTools()` 的分页,推导每个工具的 `publicName`,然后通过 `ctx.tools.register()` 将其注册为原始 `ToolDefinition`。MCP 的 JSON Schema 和 description 原样透传(不做 `defineTool` DSL 转换);仅替换模型可见的 `name`。 -2. 监听 `notifications/tools/list_changed` → 重新执行同步(dispose 上一代、注册新一代)。确定性的名称意味着未变化的工具在重新同步后保持原名。 -3. 执行器闭包持有 `rawName`;公开名称从不发送给服务器,也从不被解析以恢复原始名称。 -4. 不提供 `presentCall`/`presentResult`:ACP 桥接的通用卡片回退负责渲染。 -5. 工具在系统提示词中是透明的:除名称本身外不添加 "[via MCP]" 之类的标注。 +1. 连接时:遍历 `client.listTools()` 的分页结果,推导每个工具的 `publicName`,然后通过 `ctx.tools.register()` 将其注册为原始 `ToolDefinition`。MCP 的 JSON Schema 和描述原样透传(不做 `defineTool` DSL 转换);仅替换模型可见的 `name`。 +2. 监听 `notifications/tools/list_changed` → 重新执行同步(dispose 上一代、注册新一代)。确定性命名意味着未变化的工具在重新同步后保持原名。 +3. 执行器闭包持有 `rawName`;公开名称永远不发送给服务器,也永远不被解析以还原原始名称。 +4. 无 `presentCall`/`presentResult`——ACP 桥接的通用卡片兜底负责渲染。 +5. 工具在系统提示词中是透明的——除名称本身外不附加 "[via MCP]" 标注。 ### 公开名称规范化 -MCP 允许工具名最长 128 字符且可包含 `.`;DeepSeek 的函数名契约允许 `[A-Za-z0-9_-]` 且最长 64 字符。公开名称按确定性规则规范化:非法字符替换为 `_`,当替换或截断改变了名称时,追加 `(serverName, rawName)` 标识的 12 位十六进制 SHA-256 hash,确保不同的 MCP 标识永远不会折叠为同一个公开名称: +MCP 允许工具名最长 128 字符且可包含 `.`;DeepSeek 的函数名契约允许 `[A-Za-z0-9_-]` 且最多 64 字符。公开名称按确定性规则规范化:非法字符替换为 `_`,当替换或截断改变了名称时,追加 `(serverName, rawName)` 标识的 12 位十六进制 SHA-256 hash,确保不同的 MCP 标识永远不会坍缩为同一个公开名称: ```typescript function publicToolName(serverName: string, rawName: string): string { @@ -118,97 +118,97 @@ function publicToolName(serverName: string, rawName: string): string { ### 名称冲突处理 -MCP 仅保证工具名在[单个服务器内](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names)唯一;跨服务器冲突是常态而非例外(一项[微软研究院调研](https://www.microsoft.com/en-us/research/blog/tool-space-interference-in-the-mcp-era-designing-for-agent-compatibility-at-scale/#namespacing-issues-and-naming-ambiguity)覆盖 1,470 个服务器,发现 775 个冲突工具名;仅 `search` 就出现在 32 个服务器中,官方 GitHub 服务器发布的是裸 `create_issue`)。始终启用的命名空间从结构上杜绝冲突,而非在冲突发生时再处理: +MCP 仅保证工具名在[单个服务器内](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names)唯一;跨服务器冲突是常态而非例外(一项[微软研究院调查](https://www.microsoft.com/en-us/research/blog/tool-space-interference-in-the-mcp-era-designing-for-agent-compatibility-at-scale/#namespacing-issues-and-naming-ambiguity)覆盖 1,470 个服务器,发现 775 个冲突的工具名;仅 `search` 就出现在 32 个服务器中,官方 GitHub 服务器发布的是裸名 `create_issue`)。始终启用的命名空间从结构上杜绝冲突,而非在冲突发生时再处理: - 两个服务器都发布 `search` → 共存为 `mcp__github__search` 和 `mcp__web__search`。 - 名为 `search` 的原生 harness 工具不受影响。 -- 重复的 `serverName` 配置导致后加载的实例在启动时失败(见「配置」一节)。 -- 同一服务器列出重复的工具名属于无效工具列表:同步抛出异常,上一代注册保持不变。 -- 替换期间的注册表冲突只可能意味着外部工具占用了本服务器的 `mcp__<serverName>__` 命名空间:部分生成被回滚(该服务器零工具注册),错误被醒目地记录。 +- 重复的 `serverName` 配置使后加载的实例在启动时失败(见配置一节)。 +- 服务器列出重复的工具名属于无效工具列表:同步抛出异常,上一代注册保持不变。 +- 替换期间的注册表冲突只可能意味着外部工具占据了该服务器的 `mcp__<serverName>__` 命名空间:部分代注册被回滚(该服务器零工具),并以醒目日志记录错误。 工具永远不会被静默跳过;哪些工具可用永远不取决于插件加载顺序。 ### 命名不变式 -1. 每个 MCP 工具有稳定标识 `(serverName, rawName)`;每个活跃标识恰好对应一个公开名称。 +1. 每个 MCP 工具拥有稳定标识 `(serverName, rawName)`;每个活跃标识恰好对应一个公开名称。 2. 公开名称是确定性的、全局唯一的,且满足 DeepSeek 64 字符 `[A-Za-z0-9_-]` 契约。 3. MCP `tools/call` 始终接收原始的 raw name。 -4. 连接、断开或重新同步一个无关服务器,绝不会重命名已有工具。 -5. 注册顺序绝不决定哪个工具可用。 +4. 连接、断开或重新同步不相关的服务器永远不会重命名已有工具。 +5. 注册顺序永远不决定哪个工具可用。 ### 工具执行 -为来自同一 MCP 服务器的所有工具提供统一的 `execute` 处理器: +为来自同一个 MCP 服务器的所有工具提供统一的 `execute` 处理器: -1. 解析 `rawName`(执行器闭包持有),以配置的超时调用 `client.callTool({ name: rawName, arguments }, { signal: exec.signal })`——公开名称从不发送给服务器。 +1. 解析 `rawName`(执行器闭包持有它),以配置的超时时间调用 `client.callTool({ name: rawName, arguments }, { signal: exec.signal })`——公开名称永远不发送给服务器。 2. 映射结果: - - 多个 `text` 内容块 → 以 `'\n'` 连接为单个 `TextBlock`(必要原因:`flattenText` 使用 `join('')` 不带分隔符,多个块会丢失块间边界)。 - - `image` 内容块 → 丢弃并记录 `ctx.logger.warn`(harness 没有图片内容块类型;见 [drop-image RFC](../../implemented/simplification/2026-07-04-drop-image-content-block.md))。 + - 多个 `text` 内容块 → 以 `'\n'` 连接为单个 `TextBlock`(必要原因:`flattenText` 使用 `join('')` 无分隔符,多块会丢失块间边界)。 + - `image` 内容块 → 丢弃并 `ctx.logger.warn`(harness 没有图片内容块类型;[drop-image RFC](../../implemented/simplification/2026-07-04-drop-image-content-block.md))。 - `isError: true` → 映射到 harness 的 `isError` 结果路径(`{ content: [...], isError: true }`)。 -3. 取消:`exec.signal`(来自 agent loop 的 cancel)透传给 MCP SDK 的 `callTool`,后者向服务器发送 `$/cancelRequest`。 +3. 取消:`exec.signal`(来自 agent loop(智能体循环)的取消)透传给 MCP SDK 的 `callTool`,后者向服务器发送 `$/cancelRequest`。 ### 子进程环境(stdio 传输) -复用 `dsh-subagent-acp` 的 `buildChildEnv` + `SENSITIVE_ENV_PATTERN` 清洗逻辑:过滤环境变量(剥离匹配 `/KEY|SECRET|TOKEN/i` 的凭证形变量),然后将 `config.env` 覆盖在上面。显式配置的 env 不受清洗影响。 +复用 `dsh-subagent-acp` 的 `buildChildEnv` + `SENSITIVE_ENV_PATTERN` 清洗逻辑:过滤环境变量(剥离匹配 `/KEY|SECRET|TOKEN/i` 的凭证形变量),然后将 `config.env` 覆盖合并到顶层。显式配置的 env 不受清洗影响。 -### 断开连接 / 崩溃 +### 断连 / 崩溃 不自动重连。如果 MCP 服务器进程退出或传输层关闭: 1. effect dispose → 所有已注册工具被注销(fiber 作用域的 disposer)。 2. 后续模型对这些工具的调用 → `ToolNotFoundError` → `isError: true`。 -3. 恢复方式:用户编辑 `cordis.yml`(触发 HMR 重载)或重启 harness。 +3. 恢复:用户编辑 `cordis.yml`(触发 HMR 重载)或重启 harness。 -这与 ACP subagent 的模式一致:「崩溃即终态,报告错误,清理资源,不重试。」 +这与 ACP subagent 模式一致:"崩溃即终态,报告错误,清理资源,不重试。" ## 曾考虑的替代方案 -### MCP 服务器端(向外部 MCP 客户端暴露 harness 工具) +### MCP Server 端(将 harness 工具暴露给外部 MCP 客户端) -推迟。ACP 桥接已将 harness 暴露为 agent 服务器。再加一层 MCP 服务器会用不同协议重复这一功能,而用户的首要需求是消费外部工具,而非暴露自身工具。 +延后。ACP 桥接已将 harness 暴露为 agent 服务器。再加一层 MCP server 会以不同协议重复这一功能,而用户的首要需求是消费外部工具,而非暴露自身工具。 -### 能力 seam 三包拆分(接口 / 实现 / 消费方) +### 能力 seam 三包拆分(interface / impl / consumer) -否决。可预见范围内不会有替代的 MCP 客户端实现:MCP 只有一个协议、一个 SDK。约定是「在第二种实现出现之前不要预防性拆分」。 +否决。可预见范围内不会有替代的 MCP 客户端实现——MCP 只有一个协议、一个 SDK。约定是"不要预防性拆分",直到出现第二种实现。 ### 指数退避自动重连 -v1 否决。引入复杂性(工具已注册但暂时不可用的部分可用状态),且 stdio 进程崩溃通常表明配置问题,重试无法修复。HMR 已提供手动恢复路径。如有需要,未来可作为 `reconnect: boolean` 配置项加入。 +v1 否决。引入复杂性(工具已注册但暂时不可用的部分可用状态),且 stdio 进程崩溃通常表明配置问题,重试无法修复。HMR 已提供手动恢复路径。如有需要,可在未来作为 `reconnect: boolean` 配置项添加。 ### 桥接 Resources 和 Prompts -推迟。Resources 需要 harness 侧的机制来决定何时注入内容(系统提示词?按需?模型触发?)。Prompts 需要 harness 目前缺少的「prompt 模板」概念。两者都需要独立设计;Tools 是高价值、低风险的起点。 +延后。Resources 需要 harness 侧的机制来决定何时注入内容(系统提示词?按需?模型触发?)。Prompts 需要 harness 尚不具备的"提示词模板"概念。两者都需要独立设计;Tools 是高价值、低风险的起点。 ### 原始模型可见工具名加可选 `toolPrefix` -否决。这是最初的提案,建立在「大多数 MCP 服务器已在工具名中使用语义前缀(如 `github_create_issue`)」的前提上。该前提不成立:官方 GitHub 服务器发布的是 `create_issue`,参考文件系统服务器是 `read_file`,Sentry 是 `search_issues`——且上述微软调研表明冲突在生态规模下很常见。冲突时再加前缀(或 warn-and-skip)还会使可用工具集取决于插件加载顺序,且添加一个无关服务器可能静默重命名已有工具——在对话中途使会话历史和权限规则失效。所有被调研的多服务器 agent 产品都不使用裸名称。 +否决。这是最初的提案,基于"大多数 MCP 服务器已在工具名中使用语义前缀(如 `github_create_issue`)"这一前提。该前提不成立:官方 GitHub 服务器发布的是 `create_issue`,参考文件系统服务器发布 `read_file`,Sentry 发布 `search_issues`——且上述微软调查表明冲突在生态规模下很常见。冲突时再加前缀(或 warn-and-skip)还会使可用工具集取决于插件加载顺序,且添加不相关服务器时工具可能被静默重命名——在对话中途使会话历史和权限规则失效。所有被调研的多服务器 agent 产品都不使用裸名。 ### 仅服务器命名空间(`github__create_issue`,无 `mcp__` 前缀) -v1 否决。它能防止跨服务器冲突,但无法将 MCP 注册与原生 harness 工具隔离,也放弃了 MCP 全局策略匹配形状(`mcp__*`)。前缀仅消耗 5 个字符;`mcp__<server>__<tool>` 的拼写与 Claude Code 和 Codex 一致,最大化模型的熟悉度。如果 ToolRegistry 将来增加源感知的命名空间,届时可作为命名策略变更重新考虑去掉字面前缀。 +v1 否决。它能防止跨服务器冲突,但无法将 MCP 注册与原生 harness 工具分离,也丧失了 MCP 全局策略匹配模式(`mcp__*`)。前缀仅多花 5 个字符;`mcp__<server>__<tool>` 拼写与 Claude Code 和 Codex 一致,最大化模型的熟悉度。如果 ToolRegistry 未来引入源感知命名空间,届时可作为命名策略变更重新考虑去掉字面前缀。 -### 从服务器公告的 `serverInfo.name` 推导命名空间 +### 从服务器公告的 `serverInfo.name` 派生命名空间 否决。远端名称不可信、跨部署不唯一、升级时可变;工具标识和权限规则不得静默跟随它。命名空间是本地配置。 ### 在工具结果中保留多个 TextBlock -否决。DeepSeek 序列化器中的 `flattenText()` 在将 `ContentBlock[]` 展平为协议格式(wire format)时使用 `join('')`(无分隔符)。多个 text 块会静默丢失块间边界——这是正确性 bug。所有现有工具返回单个 TextBlock;MCP 桥接遵循同样做法。 +否决。DeepSeek 序列化器中的 `flattenText()` 在将 `ContentBlock[]` 扁平化为协议格式(wire format)时使用 `join('')`(无分隔符)。多个 text 块会静默丢失块间边界——这是正确性缺陷。所有现有工具返回单个 TextBlock;MCP 桥接遵循同一做法。 ## 测试 -覆盖按层级命名;每个行为放在能表达它的最低成本层级。 +覆盖率按层级命名;每个行为放在能表达它的最低成本层级。 -- **单元测试**(`tests/mcp-client.spec.ts`、`tests/apply.spec.ts`,mock MCP SDK):`publicToolName` 算法(干净路径、规范化、截断加 hash、确定性、不同标识的分离)、raw 与 public 的协议纪律、跨服务器与原生工具共存、重复 `serverName` 加载失败与预留释放、无效工具列表拒绝、代际替换/回滚、重新同步失败时的保留、结果映射、取消、配置 schema 校验。100% 逐文件覆盖率门禁约束该包。 -- **E2E**(`tests/mcp-client.e2e.ts`,无需密钥):使用仓库内 fixture 服务器、`@modelcontextprotocol/server-everything` 和 `@modelcontextprotocol/server-filesystem` 通过 stdio 运行真实 MCP 协议,以及通过进程内 `StreamableHTTPServerTransport` 服务器运行 Streamable HTTP——命名空间下的发现、带点号名称的端到端规范化、执行往返、重复 `serverName` 拒绝、dispose(资源释放)。 -- **快照**:刻意不做。MCP 工具不引入新的 transcript 渲染面——它们注册为原始 `ToolDefinition`,通过 ACP 桥接的通用卡片回退渲染,而桥接的单元测试套件已固定了该行为(`packages/ui/acp/tests/stream-update.spec.ts`)。将 MCP 服务器加入快照示例的 `cordis.yml` 会改变已固定的 `text-turn` 系统提示词 fixture(迫使每条录制的 golden 都需要带密钥重新录制),并使每次回放依赖于 spawn 一个外部 MCP 服务器进程——而新增的渲染行为为零。如果后续变更为 MCP 工具引入专属的渲染意图,该变更届时自行命名其快照覆盖。 +- **单元测试**(`tests/mcp-client.spec.ts`、`tests/apply.spec.ts`,mock MCP SDK):`publicToolName` 算法(干净名称、规范化、截断加 hash、确定性、不同标识的分离)、raw 与 public 的协议纪律、跨服务器与原生工具共存、重复 `serverName` 加载失败与预留释放、无效工具列表拒绝、代切换/回滚、重新同步失败时的保留、结果映射、取消、配置 schema 校验。100% 逐文件覆盖率门禁约束该包。 +- **E2E**(`tests/mcp-client.e2e.ts`,无需密钥):使用真实 MCP 协议对接仓库内的 fixture(测试前置数据)服务器、`@modelcontextprotocol/server-everything` 和 `@modelcontextprotocol/server-filesystem`(stdio 传输),以及进程内 `StreamableHTTPServerTransport` 服务器(Streamable HTTP 传输)——命名空间下的发现、带点号名称的端到端规范化、执行往返、重复 `serverName` 拒绝、dispose。 +- **快照**:刻意不做。MCP 工具不引入新的 transcript(文本记录)呈现面——它们以原始 `ToolDefinition` 注册,通过 ACP 桥接的通用卡片兜底渲染,该兜底已由桥接的单元测试套件固定(`packages/ui/acp/tests/stream-update.spec.ts`)。将 MCP 服务器添加到快照示例的 `cordis.yml` 会改变已固定的 `text-turn` 系统提示词 fixture(迫使每条录制的 golden 都需要带密钥重新录制),且使每次回放依赖于 spawn 外部 MCP 服务器进程——而新增渲染行为为零。如果后续变更为 MCP 工具引入专属渲染意图,该变更届时自行声明快照覆盖。 ## 后果 -- 每个 MCP 服务器只需一条 `cordis.yml` 条目即完成集成:`serverName: filesystem` 加一条 stdio 命令(或一个 Streamable HTTP URL),就能把 `mcp__filesystem__read_file` 放入模型的工具列表,可调用,协议层使用原始的 `read_file`。 -- 公开名称是会话历史与权限/配置界面的一部分;命名算法是由测试固定的 v1 契约,发布后修改它是破坏性变更。 -- `mcp__<serverName>__` 限定符在每个名称上消耗 token。已接受:description 和 JSON Schema 在工具定义 token 中占主导,而限定符换来了稳定标识、冲突隔离和 MCP 全局策略匹配形状(`mcp__*`、`mcp__github__*`)。 -- **MCP SDK 稳定性**:`@modelcontextprotocol/sdk` 仍在演进;破坏性变更需要更新桥接。版本已固定,且该 SDK 被广泛采用(Claude Desktop、Cursor、VS Code),因此破坏性变更不太可能悄然发生。 -- **工具 schema 质量**:MCP 服务器可能暴露描述不佳的工具(模糊的 description、不完整的 JSON Schema)。harness 原样透传——垃圾进垃圾出;这是服务器作者的责任,不是桥接的责任。 -- **Stdio 进程管理**:行为异常的 MCP 服务器如果忽略信号可能卡住 dispose。Cordis fiber 的 dispose 有有界静默期;卡住的传输层最终会在框架层面超时。 -- 崩溃恢复是手动的(HMR 编辑或重启)——v1 已接受;`reconnect` 配置项作为未来工作保持开放。 +- 每个 MCP 服务器只需 `cordis.yml` 中的一条配置即完成集成:`serverName: filesystem` 加一条 stdio 命令(或一个 Streamable HTTP URL),就能将 `mcp__filesystem__read_file` 放入模型的工具列表,可调用,协议上使用原始的 `read_file`。 +- 公开名称是会话历史和权限/配置表面的一部分;命名算法是由测试固定的 v1 契约,发布后变更即为破坏性变更。 +- `mcp__<serverName>__` 限定符在每个名称上消耗 token。已接受:描述和 JSON Schema 在工具定义 token 中占主导,而限定符换来了稳定标识、冲突隔离和 MCP 全局策略匹配模式(`mcp__*`、`mcp__github__*`)。 +- **MCP SDK 稳定性**:`@modelcontextprotocol/sdk` 仍在演进中;破坏性变更需要更新桥接。版本已固定,且该 SDK 被广泛采用(Claude Desktop、Cursor、VS Code),因此破坏性变更不太可能悄然发生。 +- **工具 schema 质量**:MCP 服务器可能暴露描述不佳的工具(模糊的描述、不完整的 JSON Schema)。harness 原样透传——垃圾进垃圾出;这是服务器作者的责任,不是桥接的。 +- **Stdio 进程管理**:行为异常的 MCP 服务器如果忽略信号,可能卡住 dispose。Cordis fiber 的 dispose 有有界静默期;卡住的传输层最终在框架层面超时。 +- 崩溃恢复是手动的(HMR 编辑或重启)——v1 已接受;`reconnect` 配置作为未来工作保持开放。 diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml b/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml index fddf23cccb..038349fd78 100644 --- a/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-07-session-prefix.md: ffa0fecb86e84ed64d45b24e1b6943d421757fb2 -2026-07-07-session-prefix.zh.md: 292c74fac75d8f2c29628fc5e90c72dadcaf4fdb +2026-07-07-session-prefix.zh.md: ca38ebf337e16f4f2368ca74e394fcc1031fbf1f diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md b/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md index 292c74fac7..ca38ebf337 100644 --- a/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md @@ -1,4 +1,4 @@ -# RFC:会话前缀——置于派生历史之前的仅请求消息 +# RFC:会话前缀——派生历史之前的仅请求消息 Status: implemented @@ -6,39 +6,39 @@ Status: implemented ## 问题 -插件经常拥有一段会话级别稳定的开场内容,模型必须始终看到它:技能目录、AGENTS.md 摘要、工作区基线。在这个 seam 出现之前,harness 只提供两个归属位置,但对这类内容来说两个都不对。系统提示词是一个渲染后的单字符串:消息形态的内容(user 角色的 `<system-reminder>` 信封、多消息引导序列)放不进去,而且提供方对对话消息与系统文本的权重处理不同。持久化历史(`agent.inject()`、会话开始时的 `context/message`)会让开场内容变成永久记录:每个 `deriveMessages()` 消费方都会回放它,压缩(compaction)的保留遍历拥有它,fork 会把它以陈旧状态烘焙进去,resume 无法刷新它——一份在会话诞生时捕获的目录会比它所描述的世界活得更久。 +插件经常拥有一段会话级别稳定的开场内容,模型必须始终看到它:技能目录、AGENTS.md 摘要、工作区基线。在引入本 seam 之前,harness 为这类内容提供了两个归属位置,但两者都不合适。系统提示词是一个渲染后的单一字符串:消息形态的内容(user 角色的 `<system-reminder>` 信封、多消息引导序列)放不进去,而且提供方对会话消息和系统文本的权重处理不同。持久化历史(`agent.inject()`、会话启动时的 `context/message`)使开场内容变为永久:每个 `deriveMessages()` 消费方都会回放它,压缩(compaction)的保留遍历拥有它,fork 会将其以陈旧状态固化,resume 也无法刷新它——会话诞生时捕获的目录会比它所描述的世界活得更久。 -显而易见的第三个选项——让插件在请求发出时编辑 `messages`——被[可重建请求 RFC](../architecture/2026-07-05-reconstructable-requests.md) 禁止:每个由循环构建的请求都是会话日志的纯函数,因此承载开场内容的通道必须精确记录它所发送的内容。缺失的是一个带持久记录的仅请求消息通道。 +显而易见的第三种选项——让插件在请求发出途中编辑 `messages`——被[可重建请求 RFC](../architecture/2026-07-05-reconstructable-requests.md) 禁止:每个由循环构建的请求都是会话日志的纯函数,因此无论哪个通道承载开场内容,都必须精确记录它所发送的内容。缺失的是一个带有持久记录的仅请求消息通道。 ## 决策 -`agent/session-prefix` 是 agent 事件映射上的一个 waterfall(瀑布式事件)([`packages/core/agent/src/types.ts`](../../../../packages/core/agent/src/types.ts)):监听器接收一个冻结的空种子并返回一个扩展(规范的贡献方式是前置,`[mine, ...await next()]`,在协议格式上产生注册顺序)。循环([`packages/core/agent-loop/src/loop.ts`](../../../../packages/core/agent-loop/src/loop.ts))在每个循环实例中触发一次,延迟到该实例首次 `agent/pre-step` 之前;组合后的列表被深拷贝、深冻结、缓存在实例上,并在该实例发送的每个请求中置于**整个**派生历史之前——紧接在提供方的 system 槽位之后([协议格式顺序](../../../core-data-structures/core.md#the-request-envelope-llmcallconfig-and-the-logged-header))。 +`agent/session-prefix` 是 agent 事件映射上的一个 waterfall(瀑布式事件)([`packages/core/agent/src/types.ts`](../../../../packages/core/agent/src/types.ts)):监听器接收一个冻结的空种子并返回扩展(规范的贡献方式是前置插入 `[mine, ...await next()]`,在协议格式上产生注册顺序)。agent loop(智能体循环)([`packages/core/agent-loop/src/loop.ts`](../../../../packages/core/agent-loop/src/loop.ts))在每个循环实例中触发一次,惰性地在实例首次 `agent/pre-step` 之前执行;组合后的列表被深拷贝、深冻结、缓存在实例上,并在该实例发出的每个请求中置于**整个**派生历史之前——紧接在提供方的 system 槽位之后([协议格式顺序](../../../core-data-structures/core.md#the-request-envelope-llmcallconfig-and-the-logged-header))。 三个属性承载了这一设计: -- **仅请求,记录在 header 中。** `deriveMessages()` 从不返回前缀;它唯一的持久记录是实例锚定的 `request/header` 快照上的 `EpochHeader.messagePrefix`——可重建请求 RFC 已经为请求的非历史部分拥有的通道,因此不引入新的会话事件。开发不变式([dsh-invariants](../../../../packages/support/invariants/src/index.ts))对每个循环构建的请求重新计算 `messagePrefix + 边界派生`;未记录的前缀无法到达协议格式。 -- **按实例冻结。** 复用是结构性的,而非靠纪律保证:缓存的产物在会话中途不可变,因此提供方的 prompt 缓存在构造上成立,前缀以每步零边际成本扩展了可缓存区域。进程重启或 `ctx.agents.resume()` 是一个新实例:它重新组合,任何漂移都可归因地落在 `'resume'` header 快照上。这就是该 seam 创建的路由规则:会话冻结的开场内容走前缀;会话中途变化的内容走仅追加历史通道(`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——[拦截 seam RFC](2026-06-30-interception-seams.md)),每条都是一次性持久化的 `context/message`,之后被前缀缓存覆盖。 -- **在压力门禁之前组合。** 组合先于实例的首次 `agent/pre-step`,且 seam 将组合值传递下去:`agent/pre-step` 携带 `sessionPrefix` 参数,`CompactService.compactIfNeeded(agent, fullSystemPrompt, sessionPrefix, signal)` 将其计入 token 压力估算——如果门禁读取的是上一个实例折叠后的前缀,那么在一个贡献者增长了的 resume 或 fork 实例的首步上会低估压力,跳过压缩并发出超窗口的首请求。组合过程中如果 cancel/dispose 落入 waterfall 内部,组合结果被丢弃、永不缓存:一个感知中止的监听器的降级回退不会泄漏到后续请求中,下一轮次在活跃 signal 下重新组合。 +- **仅请求,记录在 header 中。** `deriveMessages()` 从不返回前缀;它唯一的持久记录是实例锚定的 `request/header` 快照上的 `EpochHeader.messagePrefix`——可重建请求 RFC 已为请求的非历史部分拥有的通道,因此不引入新的会话事件。开发不变式([dsh-invariants](../../../../packages/support/invariants/src/index.ts))对每个循环构建的请求重新计算 `messagePrefix + 边界派生`;未记录的前缀无法到达协议格式。 +- **按实例冻结。** 复用是结构性的,而非靠纪律保证:缓存的产物在会话中途不可变,因此提供方的 prompt 缓存从构造上成立,前缀以每步零边际成本扩展了可缓存区域。进程重启或 `ctx.agents.resume()` 产生新实例:它重新组合,任何漂移都可追溯地落在 `'resume'` header 快照上。这就是本 seam 创建的路由规则:会话冻结的开场内容走前缀;会话中途变化的内容走仅追加历史通道(`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——[拦截 seam RFC](2026-06-30-interception-seams.md)),每条都是一次性支付的持久 `context/message`,之后被前缀缓存覆盖。 +- **在压力门禁之前组合。** 组合先于实例的首次 `agent/pre-step`,且 seam 将组合值透传:`agent/pre-step` 携带 `sessionPrefix` 参数,`CompactService.compactIfNeeded(agent, fullSystemPrompt, sessionPrefix, signal)` 将其计入 token 压力估算。如果改为让门禁读取上一个实例折叠后的前缀,则在 resume 或 fork 后的实例中(贡献者可能已增长),门禁会低估压力、跳过压缩,发出超窗口的首个请求。在首次 pre-step 之前组合并将活值透传给 seam,使估算在每一步都精确。被 cancel/dispose 中断的组合(中断落在 waterfall 内部)会被丢弃,永不缓存:感知中止的监听器的降级回退不会泄漏到后续请求中,下一轮次在活信号下重新组合。 -由于组合在边界快照之前运行,组合监听器的会话追加会加入**当前**请求的派生历史。压缩在结构上无法触及前缀(或系统提示词):它重写的是表面节点,而 header 状态从不进入表面。 +由于组合在边界快照之前运行,组合监听器的会话追加会加入**当前**请求的派生历史。压缩在结构上不可能触及前缀(或系统提示词):它重写的是表面节点,而 header 状态从不进入表面。 ## 测试 -[拦截测试](../../../../packages/core/agent-loop/tests/interception.spec.ts)固定了无 header 增量时的组合一次复用、前置顺序、空前缀省略、不可变性,以及组合先于 pre-step;[取消测试](../../../../packages/core/agent-loop/tests/cancel.spec.ts)固定了丢弃与重新组合。会话编解码器、不变式和压缩测试覆盖 header 往返、请求重建和前缀感知的压力计算。快照规范化保留前缀计数,而[固定 header 场景](../testing/2026-07-06-pin-request-header-content-in-one-scenario.md)拥有内容,默认示例保持无前缀。不需要前缀专属的 e2e 测试,因为该 seam 是确定性的且与提供方无关;带密钥的[请求缓存 e2e](../../../../packages/core/agent-loop/tests/request-cache.e2e.ts) 覆盖了其缓存经济性。 +[拦截测试](../../../../packages/core/agent-loop/tests/interception.spec.ts)固定了以下行为:无 header delta 时的组合一次复用、前置插入顺序、空前缀省略、不可变性,以及组合先于 pre-step;[取消测试](../../../../packages/core/agent-loop/tests/cancel.spec.ts)固定了丢弃与重新组合。会话编解码器、不变式和压缩测试覆盖 header 往返、请求重建与前缀感知的压力核算。快照归一化保留前缀计数,[固定 header 场景](../testing/2026-07-06-pin-request-header-content-in-one-scenario.md)拥有内容,默认示例保持无前缀。无需前缀专属的 e2e 测试,因为该 seam 是确定性的且与提供方无关;带密钥的 [request-cache e2e](../../../../packages/core/agent-loop/tests/request-cache.e2e.ts) 覆盖了其缓存经济性。 ## 曾考虑的替代方案 -- **每请求 `before`/`after` 槽位,每步重新计算**(最初提出的形态:每个请求触发一次 waterfall,贡献冻结的 `before` 消息置于历史之前、新鲜的 `after` 消息置于历史之后):否决。每步重新组合 `before` 会引入静默漂移——除非每步记录一个 header 增量,否则没有东西将其锚定到日志——而 `after` 槽位位于不断增长的历史之后,其 token 在每个请求中重新支付,且其后的所有内容不可缓存。与各替代方案对比衡量,当前每种更新模式都能由持久追加更廉价地服务(支付一次,此后缓存读取),唯一没有归属的内容是会话稳定的开场——它需要的是冻结,而非重新计算。 -- **系统提示词分区**(`system-prompt/assemble`):对此类内容否决。组装渲染为单一 `system` 字符串,消息形态的开场放不进去;且系统提示词被设计为每步重新组装(变化时带 header 增量),而开场内容需要的是按实例冻结的语义。 -- **持久化历史开场**(会话开始时 `inject()`):否决。永久历史正是问题陈述中的失败模式——到处回放、可被压缩、跨 resume 陈旧。 -- **按轮次而非按实例组合**:否决。轮次边界的重新组合要么与日志静默失同步,要么强制每次变化产生一个 header 增量,且它每次触发都会破坏提供方缓存;合理的刷新点是实例边界,`'resume'` 快照已经在那里可归因地记录漂移。 -- **在首请求时延迟组合,让压缩读取折叠后的 header**(首次合入时的形态):评审中被取代。折叠值只从实例的第二个请求起才与活跃前缀匹配,因此在 resume/fork 实例的首步上,压力门禁读取的是**上一个**实例的前缀,可能低估压力。在首次 pre-step 之前组合并通过 seam 传递活跃值,使估算在每一步都精确。 -- **承载前缀的专用会话事件**:否决。header 事件在设计上就是请求的非历史记录;第二个事件会成为同一事实的第二个归属,以及又一个需要保持完整的编解码器。 +- **每请求 `before`/`after` 槽位,每步重新计算**(最初提出的形态:一个每请求触发的 waterfall,贡献冻结的 `before` 消息置于历史之前、新鲜的 `after` 消息置于历史之后):否决。每步重新组合 `before` 会引入静默漂移——除非每步记录一个 header delta,否则没有东西将其锚定到日志;`after` 槽位位于不断增长的历史之后,其 token 在每个请求中重复支付,且其后的所有内容不可缓存。对照各替代方案衡量,当前所有更新模式都能通过持久追加更廉价地满足(支付一次,此后缓存读取),而唯一没有归属的内容是会话稳定的开场——它需要的是冻结,而非重新计算。 +- **系统提示词分段**(`system-prompt/assemble`):对此类内容否决。assembly 渲染为单一 `system` 字符串,消息形态的开场放不进去;且系统提示词被设计为每步重新组装(变化时带 header delta),而开场内容需要按实例冻结的语义。 +- **持久化历史开场**(会话启动时 `inject()`):否决。永久历史正是问题陈述中的失败模式——到处被回放、可被压缩、跨 resume 陈旧。 +- **按轮次组合而非按实例组合**:否决。轮次边界的重新组合要么与日志静默失同步,要么强制每次变化都产生 header delta;且它每次触发都会破坏提供方缓存。合理的刷新点是实例边界,`'resume'` 快照已在那里可追溯地记录漂移。 +- **在首次请求时惰性组合,让压缩读取折叠后的 header**(最初合并时的形态):评审中被取代。折叠值仅从实例的第二个请求起才与活前缀匹配,因此在 resume/fork 后的实例首步,压力门禁读取的是**上一个**实例的前缀,可能低估压力。在首次 pre-step 之前组合并将活值透传给 seam,使估算在每一步都精确。 +- **专用会话事件承载前缀**:否决。header 事件按设计就是请求的非历史记录;第二个事件会为同一事实提供第二个归属,并多出一个需要保持完整的编解码器。 ## 后果 -- `agent/pre-step` 和 `CompactService.compactIfNeeded` 携带 `sessionPrefix` 参数:每个 pre-step 监听器和压缩后端都能看到真实的每实例值(所有仓库内实现在同一个变更中更新,遵循预发布立场)。 -- 内容在会话中途变化的贡献者不会被重新读取,直到下一个实例——这是设计意图。需要会话中途目录更新的部署应将变更通知路由到仅追加历史通道,支付一条持久化 `context/message`。 -- 被放弃的 `after` 槽位使请求尾部没有仅请求通道;仓库中没有任何东西需要它,且加回它会重新引入该设计旨在避免的每步重复支付成本。 -- `request/header-delta` 的 `messagePrefix` 分支(整数组替换,空数组编码向缺失的过渡)为编解码器完备性而存在;循环从不行使它,因为缓存的前缀在实例内不可变。 -- 空组合是规范的缺失状态:无贡献者的部署不记录额外 header 字节,其请求就是裸派生。 +- `agent/pre-step` 与 `CompactService.compactIfNeeded` 携带 `sessionPrefix` 参数:每个 pre-step 监听器和压缩后端都能看到真实的按实例值(所有仓库内实现在同一个变更中更新,遵循预发布立场)。 +- 贡献者的内容在会话中途变化时,直到下一个实例才会被重新读取——这是设计意图。需要会话中途目录更新的部署,应将变更通知路由到仅追加历史通道,支付一条持久 `context/message`。 +- 被放弃的 `after` 槽位意味着请求尾部附近没有仅请求通道;仓库中没有任何功能需要它,且恢复它会重新引入本设计旨在避免的每步重复支付成本。 +- `request/header-delta` 的 `messagePrefix` 分支(整数组替换,空数组编码向缺失的过渡)为编解码器完整性而存在;循环从不触发它,因为缓存的前缀在实例内不可变。 +- 空组合即为规范缺失:无贡献者的部署不记录额外的 header 字节,其请求就是裸派生。 diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml index 03817c1073..5c62772145 100644 --- a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-08-repeat-tool-guard.md: 04d5d077a42b54ca7dc04a1efc9ea2f4034b642b -2026-07-08-repeat-tool-guard.zh.md: e20bd06a6902f9fadb77a90e719aaf703d7067cc +2026-07-08-repeat-tool-guard.zh.md: 917d958ca1019eb464b72b0201219de9dde7f658 diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md index e20bd06a69..917d958ca1 100644 --- a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md @@ -6,32 +6,32 @@ Status: implemented ## 问题 -模型陷入循环时会反复发出参数逐字节相同的工具调用——重新运行一个失败的 grep、重新读取一个未变化的文件、轮询一个已经给出答案的命令——每一轮往返都消耗 token、挂钟时间和(对付费 API 而言)金钱,却不带来新信息。harness 目前没有任何机制能察觉这一点:循环没有步骤预算,没有插件追踪调用重复,模型只有在碰巧自行改变行为时才能脱困。这种失败模式真实存在且易于检测——[pi-repeat-tool-guard](https://github.com/Kingwl/pi-repeat-tool-guard) 正是将此作为 pi coding-agent 扩展发布的:统计连续相同调用次数,超过阈值后追加一条 `<system-reminder>` 告知模型停止重复、改变策略。 +模型陷入循环时,会以字节级相同的参数反复发起同一个工具调用——重新运行一条失败的 grep、重新读取一个未变化的文件、轮询一条已经给出答案的命令——每一轮往返都消耗 token、挂钟时间以及(对付费 API 而言)金钱,却不带来新信息。harness 目前没有任何机制能察觉这一点:循环没有步骤预算,没有插件追踪调用重复,模型只有在碰巧改变自身行为时才能跳出。这种失败模式真实存在且检测成本极低——[pi-repeat-tool-guard](https://github.com/Kingwl/pi-repeat-tool-guard) 正是以 pi coding-agent 扩展的形式提供了这一功能:统计连续相同调用次数,超过阈值后追加一条 `<system-reminder>` 告诉模型停止重复并换个方向。 -harness 已经具备 pi 扩展所用的全部 seam,且更好:[拦截 seam RFC](2026-06-30-interception-seams.md) 赋予 `tools/post-execute` 一种正式途径,可以在已完成的调用上附加面向模型的上下文;循环缓冲并注入该上下文,保持调用/结果的邻接关系;注入的上下文是一条已记录的 `context/message`——因此原生守卫无需新增会话事件即可满足「模型可见 ⟺ 已记录」规则。缺的只是插件本身。 +harness 已经具备 pi 扩展所使用的全部 seam,而且更好:[拦截 seam RFC](2026-06-30-interception-seams.md) 赋予 `tools/post-execute` 一种经过认可的方式,将面向模型的上下文附加到已完成的调用上;循环缓冲并注入该上下文,同时保持调用/结果的邻接关系;注入的上下文是一条已记录的 `context/message`——因此原生守卫无需新增会话事件即可满足「模型可见 ⟺ 已记录」规则。缺少的只是插件本身。 ## 决策 -守卫是一个循环卫生插件,而非面向模型的工具。它统计对同一工具以相同规范化参数发起的连续调用次数,并在配置的阈值处注入建议性提醒。它从不延迟、阻塞或改写调用;模型自行决定是否换一种方式重试或结束。 +该守卫是一个循环卫生插件,而非面向模型的工具。它统计对同一工具以相同规范化参数发起的连续调用次数,并在配置的阈值处注入建议性提醒。它从不延迟、阻止或改写调用;模型自行决定是换种方式重试还是结束。 -该插件为 `@deepseek-ai/dsh-repeat-tool-guard`,位于 `packages/guard/repeat-tool-guard/`,开辟 `guard/` 分组用于循环卫生插件(单包分组有先例:[todo-write RFC](2026-06-29-todo-write-tool.md) 发布了 `todo/tool-todo`)。它注册三个监听器,所有状态保存在以 `AgentId` 为键的插件局部 map 中——工具注册表是 context 级别的单例,其 waterfall(瀑布式事件)交错所有 agent 的调用(subagent 运行在同一 context 上),因此按 agent 分键是正确性要求,而非锦上添花。 +插件为 `@deepseek-ai/dsh-repeat-tool-guard`,位于 `packages/guard/repeat-tool-guard/`,开辟 `guard/` 分组用于循环卫生插件(单包(package)分组有先例:[todo-write RFC](2026-06-29-todo-write-tool.md) 发布了 `todo/tool-todo`)。它注册三个监听器,所有状态保存在以 `AgentId` 为键的插件局部 map 中——工具注册表是 context 级别的单例,其 waterfall(瀑布式事件)交错所有 agent(智能体)的调用(subagent 运行在同一个 context 上),因此按 agent 分键是正确性要求,而非锦上添花。 -- **`tools/post-execute`(waterfall)**——唯一的检测点。监听器同时接收 `(exec, result)`,因此计数和提醒投递无需跨事件的 pending map(pi 扩展需要 pending map 仅因其 `tool_call`/`tool_result` 钩子是独立事件)。它始终通过 `next()` 委托,当命中阈值时,将提醒折叠到下游决策的 `additionalContext` 上——这正是[钩子桥接](2026-06-30-hook-bridges.md)已在使用的「观察并丰富」姿态,遵守 waterfall 契约。计数放在此处而非 `tools/pre-execute`,是因为 post-execute 也会为被拒绝的调用触发(`ToolRegistry.execute` 将 deny 路由到同一流水线),而模型反复锤击一个被拒绝的调用恰恰是值得打破的循环。 +- **`tools/post-execute`(waterfall)**——唯一的检测点。监听器同时接收 `(exec, result)`,因此计数和提醒投递无需跨事件的 pending map(pi 扩展需要它,仅因为其 `tool_call`/`tool_result` 钩子是分开的事件)。它始终通过 `next()` 委托,当命中阈值时,将提醒折叠到下游决策的 `additionalContext` 上——这正是[钩子桥接](2026-06-30-hook-bridges.md)已采用的「观察并丰富」姿态,遵守 waterfall 契约。计数放在此处而非 `tools/pre-execute`,因为 post-execute 也会为被拒绝的调用触发(`ToolRegistry.execute` 将 deny 路由到同一条流水线),而模型反复敲击一个被拒绝的调用恰恰是值得打破的循环。 - **`agent/prompt-submit`(waterfall)**——纯重置钩子:通过 `next()` 委托,清除提交 agent 的链。用户介入改变了上下文;跨越介入的重复不是循环。 -- **`agent/status`(emit)**——在 `disposed` 时丢弃该 agent 的状态,限制 map 在 harness 生命周期内的增长。 +- **`agent/status`(emit)**——在 `disposed` 时丢弃该 agent 的状态,使 map 在 harness 生命周期内有界。 ### 检测语义 -链的键为 `(tool name, canonical arguments)`;与前一次被追踪的调用相同则递增该 agent 的连续计数器,不同则重置为 1。规范化方式为深度键排序加 `JSON.stringify`:`ToolExecution.arguments` 按构造即为循环中 `JSON.parse` 的输出(或参数 JSON 格式错误时的原始字符串回退,其本身也是可比较的值),因此 pi 原版对 bigint/循环引用/`undefined` 的处理在此没有输入,被有意去除。 +链的键是 `(tool name, canonical arguments)`;与前一个被追踪调用相同的调用递增该 agent 的连续计数器,不同的被追踪调用将其重置为 1。规范化方式为深度键排序加 `JSON.stringify`:`ToolExecution.arguments` 按构造就是循环中 `JSON.parse` 的输出(或格式错误的参数 JSON 的原始字符串回退,其本身也是可比较的值),因此 pi 原版对 bigint/循环引用/`undefined` 的处理在此没有输入,被有意去除。 -两条刻意的规则,均记录在[包 README](../../../../packages/guard/repeat-tool-guard/README.md) 中,因为它们是读者不看文档会猜测的行为: +两条刻意的规则,均记录在[包 README](../../../../packages/guard/repeat-tool-guard/README.md) 中,因为它们是读者否则只能猜测的行为: -- **未追踪的调用对链透明。** 被 `include`/`exclude` 排除的调用既不递增也不重置计数器,因此 `grep X → todo_write → grep X` 在 `todo_write` 被排除时仍计为两次连续的 `grep X`。这正是排除有用的原因——夹在循环中的记账工具不得洗白循环——也是 pi 扩展的(未文档化的)语义,有意保留并写明。 +- **未追踪的调用对链透明。** 被 `include`/`exclude` 排除的调用既不递增也不重置计数器,因此 `grep X → todo_write → grep X` 在 `todo_write` 被排除时仍计为两次连续的 `grep X`。这正是排除功能有用的原因——穿插在循环中的簿记工具不得为循环洗白——也是 pi 扩展的(未文档化的)语义,有意保留并明确写下。 - **没有 agent 的调用被忽略。** 直接调用 `ctx.tools.execute()` 的调用方(测试、非循环消费方)没有可提醒的模型,也没有可作键的 `AgentId`。 ### 提醒投递 -提醒使用 `additionalContext` 并标注插件来源,保留原始 `tool/result`。首次阈值发出简短提示;后续阈值包含工具名、计数和有长度上限的参数预览,而比较仍使用完整的规范化字符串。已有的下游上下文在守卫的 source 下拼接,因为 `HookContext` 支持单一 source。 +提醒使用带插件 source 的 `additionalContext`,保留原始 `tool/result`。第一个阈值发出简短提示;后续阈值包含工具名、计数和有界的参数预览,而比较仍使用完整的规范化字符串。已有的下游上下文在守卫的 source 下拼接,因为 `HookContext` 只支持一个 source。 ### 配置 @@ -45,32 +45,32 @@ harness 已经具备 pi 扩展所用的全部 seam,且更好:[拦截 seam RF argumentsPreviewChars: 500 # default; cap on arguments quoted in the detailed reminder ``` -`thresholds` 在加载时校验,空列表、非整数、小于 2 的值或重复值都会抛出异常——配置错误大声失败,取代 pi 原版的静默回退到默认值。`include`/`exclude` 条目支持 `*` 通配符。模式是对调用时实际存在的工具名的谓词,而非对注册表条目的引用,因此匹配不到任何当前已注册工具的条目不是错误——与 `toolOrder` 的引用检查不同,`exclude: [mcp_*]` 在未加载 MCP 工具的部署中必须保持有效。 +`thresholds` 在加载时校验,遇到空列表、非整数、小于 2 的值或重复项时抛出异常——配置错误快速失败,取代 pi 原版的静默回退到默认值。`include`/`exclude` 条目支持 `*` 通配符。模式是对调用时实际存在的工具的谓词,而非对注册表条目的引用,因此匹配不到当前已注册工具的条目不是错误——与 `toolOrder` 的引用检查不同,`exclude: [mcp_*]` 在未加载 MCP 工具的部署中也必须保持有效。 ## 测试 -- **单元测试:** 使用脚本化适配器的真实循环覆盖计数与重置规则、未追踪透明性、dispose 清理、按 agent 隔离、规范化参数键序、升级、被拒绝的调用、无 agent 执行、通配符转义、无效配置,以及下游阻塞或替换决策,达到逐文件 100% 覆盖率。 -- **快照测试:** keyless 的 `repeat-tool-guard` 场景发出五次相同的 `todo_write` 调用,将第三次的温和提醒和第五次的详细提醒固定在 ACP 输出和会话日志中。该插件在实时示例中加载,但在其他场景中保持静默。 -- **E2e:** 无;该插件是确定性的且与提供方无关,其 seam 契约由各自的所有者覆盖。 +- **单元测试:** 使用脚本化适配器的真实循环,覆盖计数与重置规则、未追踪透明性、dispose(资源释放)清理、按 agent 隔离、规范化参数键序、升级、被拒绝的调用、无 agent 执行、通配符转义、无效配置,以及下游 block 或 replacement 决策,达到逐文件 100% 覆盖率。 +- **快照测试:** keyless 的 `repeat-tool-guard` 场景发起五次相同的 `todo_write` 调用,在 ACP 输出和会话日志中固定第三次调用的温和提醒与第五次调用的详细提醒。该插件在实时示例中加载,但在其他场景中保持静默。 +- **E2e 测试:** 无。该插件是确定性的且与提供方无关,其 seam 契约由各自的所有者覆盖。 ## 曾考虑的替代方案 -- **将提醒追加到工具结果中**(`accept` 并替换 `content`——pi 扩展的机制,它修改结果内容是因为那是其 API 提供的唯一通道):否决。这会让已记录的 `tool/result` 对工具实际返回的内容撒谎,而 `additionalContext` 正是为 post-execute 评注设计的独立正式通道,循环级缓冲保持了调用/结果的邻接关系。 -- **在 `tools/pre-execute` 中计数并使用 pending-reminder map**(pi 的两阶段形态):否决。post-execute 单独就能同时看到 `(exec, result)` 且也会为被拒绝的调用触发,因此一个监听器、无跨事件状态,以更少的机制覆盖严格更多的尝试。 -- **在最高阈值升级为 `block`**:在初始范围内否决。阻塞调用会惩罚合理的相同重复(轮询长时间运行的终端、重新检查 agent 预期会变化的文件),而建议性提醒让模型保持控制权。待有证据后重新审视;决策形状(`PostToolDecision`)已支持此选项。 -- **通过 CC/Codex 桥接的按部署外部钩子**(`PostToolUse` 脚本):否决作为最终答案。它对单个部署有效,但一个已发布、有单元测试、可通过 `cordis.yml` 配置的插件才是 harness 原生形式,且无逐调用的子进程开销。 -- **在 `agent-loop` 中设置循环级步骤或重复预算**:否决。「用插件,不改循环」;硬性步骤预算是更粗粒度的正交控制,需要单独的提案。 -- **模糊/近似相同检测**(路径归一化、相似但不完全相同的参数):否决。规范化后的精确匹配廉价、确定性强且可向模型解释;相似度阈值会引入误报,在复杂度得到证据支撑之前不应引入。 -- **将包放在 `core/`**:否决。core 是产品主干;行为守卫是可选的叶子插件,`todo/` 先例表明每个插件家族用一个小型专属分组。 +- **将提醒追加到工具结果中**(以替换 `content` 的方式 `accept`——pi 扩展的机制,它修补结果内容是因为那是其 API 提供的唯一通道):否决。这会让已记录的 `tool/result` 对工具实际返回的内容撒谎,而 `additionalContext` 的存在正是作为 post-execute 评注的独立认可通道,循环级缓冲保持了调用/结果的邻接关系。 +- **在 `tools/pre-execute` 中计数并使用 pending-reminder map**(pi 的两阶段形态):否决。post-execute 单独就能同时看到 `(exec, result)` 且也为被拒绝的调用触发,因此一个监听器、无跨事件状态即可以更少的机制覆盖严格更多的尝试。 +- **在最高阈值升级为 `block`**:在初始范围内否决。阻止调用会惩罚合法的相同重复(轮询长时间运行的终端、重新检查 agent 预期会变化的文件),而建议性提醒让模型保持控制权。待有证据后重新审视;决策形状(`PostToolDecision`)已支持此选项。 +- **通过 CC/Codex 桥接的逐部署外部钩子**(一个 `PostToolUse` 脚本):否决作为最终答案。它对单个部署有效,但一个已发布、有单元测试、可通过 `cordis.yml` 配置的插件才是 harness 原生的形式,且没有逐调用的子进程开销。 +- **在 `agent-loop` 中设置循环级步骤或重复预算**:否决。「用插件,不改循环」;硬性步骤预算是一种更粗粒度的正交控制,需要自己的提案。 +- **模糊/近似相同检测**(路径归一化、相似但不完全相同的参数):否决。规范化后的精确匹配成本低、确定性强、且可向模型解释;相似度阈值引入误报风险,需要证据才能换取复杂度。 +- **将包放在 `core/`**:否决。core 是产品主干;行为守卫是可选的叶子插件,`todo/` 的先例是每个插件族一个小型专属分组。 ## 后果 -- 提醒在设计上是建议性的:有意重复相同调用的幂等轮询模式在超过阈值后仍会收到提示,减压阀是配置(`thresholds`、`exclude`)加上提醒文本中明确允许「在已收集足够证据时结束」的措辞。每次触发在下一次请求中增加提醒 token 开销;阈值限制了触发频率。 -- 链状态仅存于内存:从持久化恢复的会话以全新的链开始,因此跨越恢复的循环比实时循环更晚收到提醒——可接受,守卫是启发式提示而非已记录的不变式,持久化计数器状态带来的收益不值得其复杂度。 -- 当多个 post-execute 生产者在同一次调用上附加上下文时,折叠在守卫的 `source` 下拼接;插件间的顺序遵循监听器注册顺序。该 seam 无法表示混合来源——这是继承自 `HookContext` 的限制,不属于本插件。 +- 提醒在设计上是建议性的:有意重复相同调用的幂等轮询模式仍会在超过阈值后收到提示,减压阀是配置(`thresholds`、`exclude`)加上明确允许「在已收集足够证据时结束」的提醒文本。每次触发在下一次请求中增加提醒 token 的开销;阈值限制了触发频率。 +- 链状态仅存于内存:从持久化恢复的会话以全新的链开始,因此跨越恢复的循环比实时循环更晚收到提醒——可以接受,守卫是启发式提示而非已记录的不变式,持久化计数器状态带来的收益不值得其复杂度。 +- 当多个 post-execute 生产者在同一次调用上附加上下文时,折叠在守卫的 `source` 下拼接;插件间的顺序遵循监听器注册顺序。该 seam 无法表示混合来源——这是继承自 `HookContext` 的限制,不归本插件所有。 -## 延后 +## 延后事项 -- 上下文压缩(compaction)不重置链:压缩后的历史改变了模型所见,但重复风险通常在压缩后仍然存在。 -- 在高阈值升级为 `block` 未实现;`PostToolDecision` 已支持此选项,待证据出现后可启用。 -- subagent 的链按 agent 隔离;在出现具体需求之前不引入共享机制。 +- 压缩(compaction)不重置链:压缩后的历史改变了模型所见的内容,但重复风险通常在压缩后仍然存在。 +- 在高阈值升级为 `block` 未实现;`PostToolDecision` 已支持此选项,待证据到来时启用。 +- subagent 的链按 agent 隔离;在出现具体用例之前不提供共享机制。 diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml index e667e7a029..ba1e1f60be 100644 --- a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-08-self-referential-cordis-toolset.md: 62b97dc4bdbd0e0b5b1f67f77c763065c79964ed -2026-07-08-self-referential-cordis-toolset.zh.md: ce220d256dbb3d43514702e57e71728fdc82a788 +2026-07-08-self-referential-cordis-toolset.zh.md: 44648d7a3f195f2dc84121c0d014e5193484b106 diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md index ce220d256d..44648d7a3f 100644 --- a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md @@ -1,82 +1,82 @@ -# RFC:自引用 Cordis 工具集 - -Status: implemented +# RFC:自引用 cordis 工具集 [English](2026-07-08-self-referential-cordis-toolset.md) | 中文 +Status: implemented + ## 问题 -本 harness 中的一切都是 Cordis 插件,但运行在该插件运行时内部的 agent(智能体)既看不到也碰不到它:它无法枚举周围的服务和事件,无法在会话中途为自己添加新工具,也无法组合自己发明的能力。把这种能力交给模型值得探索——一个能审视并修改自身运行时的自引用 agent——但它同时引出三个正确性问题,而本设计的核心正是回答这些问题,而非单纯的「让模型执行代码」机制。 +本 harness 中的一切都是 cordis 插件,但运行在该插件运行时内部的 agent(智能体)既看不到也碰不到它:它无法枚举周围的服务和事件,无法在会话中途为自己添加新工具,也无法组合自己发明的能力。赋予模型这种能力值得探索——一个能审视并修改自身运行时的自引用 agent——但这同时引发三个正确性问题,本设计的核心正是回答这些问题,而非单纯的「让模型执行代码」机制。 -第一,模型编写的注册必须在注册发生时就被校验:格式错误的工具 schema 必须在注册时失败,而非等到后续请求尝试将其组装进提示词时才暴露。第二,模型编写的代码需要调用它从未见过源码的服务 API——猜测方法签名,更糟的是猜测返回值形状,会耗费大量盲目试探步骤。第三,模型挂载的一切都必须完全可 dispose(资源释放):模型可以按需释放,宿主插件重载时普通的插件生命周期也能释放,否则长会话会积累遗留的监听器和工具。 +第一,模型编写的注册必须在注册发生时就完成校验:格式错误的工具 schema 必须在注册时失败,而不是等到后续请求尝试将其组装进提示词时才报错。第二,模型编写的代码需要调用它从未见过源码的服务 API——靠猜测方法签名、更糟糕的是猜测返回值结构,会消耗大量盲目试探的步骤。第三,模型挂载的一切都必须完全可释放:模型可以按需释放,普通的插件生命周期在宿主插件重载时也会释放,否则长会话会积累遗留的监听器和工具。 ## 决策 -该工具集以 [`@deepseek-ai/dsh-tool-cordis`](../../../../packages/cordis/tool-cordis/README.md) 发布——一个新的顶层 `packages/cordis/` 分组——并由 [`examples/cordis-agent`](../../../../examples/cordis-agent/README.md) 演示。它为模型提供三个工具,操作模型自身运行其中的活跃 Cordis 运行时:审视它、向其中挂载模型编写的插件、再将它们 dispose。 +该工具集以 [`@deepseek-ai/dsh-tool-cordis`](../../../../packages/cordis/tool-cordis/README.md) 发布——一个新的顶层 `packages/cordis/` 分组——并由 [`examples/cordis-agent`](../../../../examples/cordis-agent/README.md) 演示。它为模型提供三个工具,操作模型自身运行其中的活跃 cordis 运行时:审视它、将模型编写的插件挂载进去、再将其释放。 -vm 隔离了意外的全局污染,上下文门面隐藏了框架内部实现。二者都不限制已暴露服务的权限:一个挂载可以调用 `ctx.bash` 以宿主执行器的权限运行命令,也能触及真实文件系统和网络服务。这是一个需要主动启用的开发工具,信任等级与 bash 等同,既不是安全边界,也不是产品默认配置。 +vm 隔离了意外的全局污染,上下文门面隐藏了框架内部细节。但二者都不限制已暴露服务的权限:一个挂载可以调用 `ctx.bash` 以宿主执行器的权限运行命令,也能访问真实的文件系统和网络服务。这是一个需要显式启用的开发工具,信任等级与 bash 相当,不是安全边界,也不是产品默认配置。 ### 三个工具 | 工具 | 契约 | |---|---| -| `cordis_inspect` | 对活跃运行时的只读报告,每个 `what` 值对应一个 Markdown 段落(省略 `what` 则返回全部段落)。从不修改状态。 | -| `cordis_mount` | 在 `node:vm` 沙箱中执行 `code`(一个异步 JavaScript 函数体);代码必须 `return` 一个 Cordis 插件,该插件作为 `cordis-dynamic` 分组 fiber 的子节点挂载,并以一个新生成的 id(`dyn-1`、`dyn-2`、……)追踪。 | -| `cordis_unmount` | 按 id dispose 一个动态挂载,并等待 disposal 达到静止——该插件所做的每一项注册都被撤销,而不仅仅是请求停止。 | +| `cordis_inspect` | 对活跃运行时的只读报告,每个 `what` 值对应一个 Markdown 段落(省略 `what` 则输出全部段落)。从不产生变更。 | +| `cordis_mount` | 在 `node:vm` 沙箱中执行 `code`(一个异步 JavaScript 函数的函数体);代码必须 `return` 一个 cordis 插件,该插件作为 `cordis-dynamic` 分组 fiber 的子节点挂载,并以一个新 id(`dyn-1`、`dyn-2`……)跟踪。 | +| `cordis_unmount` | 按 id 释放一个动态挂载,并等到释放达到静止状态后才返回——该插件所做的每一项注册都被撤销,而不仅仅是请求停止。 | -`cordis_inspect` 的段落:`services`(每个已提供的 ctx 服务及其所属 fiber,非活跃的 owner 会被标记)、`plugins`(来自 `ctx.registry` 的所有已加载插件的扁平列表及其生命周期状态——展示加载了哪些能力,刻意不展示树形结构)、`tools`(模型可调用的工具)、`dynamic`(挂载表:id、名称、状态、提供的服务、等待的服务)、`api`(来自生成目录的活跃服务签名及其引用的类型形状)、`events`(harness 事件及其分发模式和签名)。面向模型的工具描述携带模型在调用时所需的操作规则;[生成的工具目录](../../../tool-catalog.md)是其完整渲染。 +`cordis_inspect` 的段落:`services`(每个已提供的 ctx 服务及其所属 fiber,非活跃的所有者会被标记)、`plugins`(来自 `ctx.registry` 的所有已加载插件的扁平列表及其生命周期状态——展示加载了哪些能力,刻意不展示树形结构)、`tools`(模型可调用的工具)、`dynamic`(挂载表:id、名称、状态、提供的服务、等待的服务)、`api`(来自生成目录的活跃服务签名及其引用的类型形状)和 `events`(harness 事件及其分发模式和签名)。面向模型的工具描述携带了模型在调用时所需的操作规则;[生成的工具目录](../../../tool-catalog.md)是其完整呈现。 ### 沙箱语义 -挂载代码作为异步函数体在一个新的 vm realm 中运行。其文档化的接口面将文件、网络、进程和定时器访问引导至 Cordis 服务,使挂载保持可审视和可 dispose。宿主 realm 的辅助手段仍使 Node 逃逸成为可能,与信任姿态一致。`vmTimeoutMs` 仅约束同步执行部分。 +挂载代码以异步函数体的形式在一个新的 vm realm 中运行。其文档化的接口面将文件、网络、进程和定时器访问引导至 Cordis 服务,使挂载保持可审视和可释放。宿主 realm 的辅助手段仍然使 Node 逃逸成为可能,这与信任姿态一致。`vmTimeoutMs` 仅约束同步执行部分。 -沙箱全局变量刻意精简:一个带标签的直通 `console`(在宿主 stdout/stderr 上输出 `[cordis:<id>] …`,使得挂载调用结束很久后触发的监听器仍能输出到用户可见之处)、`harness.defineTool` / `harness.registerTool` 注册对、新 vm 上下文缺少的编码原语(`btoa`/`atob` 作为宿主闭包封装 `Buffer`——这是一个经过批准的例外,`Buffer` 本身从不暴露——加上 `TextEncoder`/`TextDecoder`),以及对被扣留的 Node API 的可调用陷阱(`require`、`setTimeout`/`setInterval`/`setImmediate`/`clearTimeout`/`clearInterval`、`fetch`),调用时抛出错误并指名 Cordis 替代方案。只有函数形状的全局变量被陷阱拦截;`process` 和 `Buffer` 保持 `undefined`,使 `typeof` 特性探测保持惰性而非触发抛出异常的访问器。 +沙箱全局变量刻意精简:一个带标签的直写 `console`(在宿主 stdout/stderr 上输出 `[cordis:<id>] …`,这样在挂载调用之后很久才触发的监听器输出仍能落到用户可见的地方)、`harness.defineTool` / `harness.registerTool` 注册对、新 vm 上下文缺少的编码原语(`btoa`/`atob` 作为基于 `Buffer` 的宿主闭包——这是一个经过审批的例外,`Buffer` 本身从不暴露——加上 `TextEncoder`/`TextDecoder`),以及对被扣留的 Node API 的可调用陷阱(`require`、`setTimeout`/`setInterval`/`setImmediate`/`clearTimeout`/`clearInterval`、`fetch`),这些陷阱会抛出一条重定向消息指明 cordis 替代方案。只有函数形态的全局变量才设陷阱;`process` 和 `Buffer` 保持 `undefined`,这样 `typeof` 特性探测保持惰性而不会引爆一个抛异常的访问器。 -挂载代码通过三道控制跨越 vm 边界。双 realm `instanceof` 同时识别宿主和 vm 对象。`harness.defineTool` 将结果规范化为宿主 realm 的 JSON,并在记录日志前校验 `ToolExecuteReturn` 形状。挂载的插件接收一个白名单上下文门面,而非原始或直通的 `Context`;框架管道和以 context 为值的返回会被拒绝。服务读取要求声明 `inject`,保持 Cordis 的激活和卸载语义。`ctx.tools.get` 仅暴露 schema 视图,使挂载代码无法绕过 `ToolRegistry.execute` 直接调用定义。 +挂载代码通过三道控制跨越 vm 边界。双 realm `instanceof` 同时识别宿主和 vm 对象。`harness.defineTool` 将结果规范化为宿主 realm 的 JSON,并在记录日志前校验 `ToolExecuteReturn` 形状。挂载的插件接收的是一个白名单上下文门面,而非原始或透传的 `Context`;框架管道和以 context 为值的返回会被拒绝。服务读取需要声明 `inject`,保留 Cordis 的激活与卸载语义。`ctx.tools.get` 仅暴露 schema 视图,因此挂载代码无法绕过 `ToolRegistry.execute` 直接调用定义。 -边界将无歧义的 JSON-Schema 形式规范化为 `SchemaSpec`,包括对象包装、`integer` 和可选字段。无效词汇会失败并给出可接受的替代方案。解析错误、TypeScript 错误、缺少 return、Node API 错误和重复工具错误会包含相关源代码行或纠正性契约,但不叙述实现内部细节。 +边界将无歧义的 JSON-Schema 形式规范化为 `SchemaSpec`,包括对象包装器、`integer` 和可选字段。无效词汇会报错并给出可接受的替代方案。解析错误、TypeScript 错误、缺少 return、Node API 误用和重复工具名等错误信息包含相关源码行或纠正性契约,不叙述实现内部细节。 ### 动态分组与挂载生命周期 -所有动态挂载都是工具插件下方一个 `cordis-dynamic` 分组的子节点,因此普通的 fiber disposal 即可处理重载和卸载。挂载会等待 settlement;启动失败会在返回错误前 dispose 该 fiber。已 settle 但处于 pending 状态的挂载仍然可见,并列出其缺失的注入。`cordis_unmount` 等待挂载 fiber 的 disposal。 +所有动态挂载都是工具插件下方 `cordis-dynamic` 分组的子节点,因此普通的 fiber 释放即可处理重载和卸载。挂载会等待 settlement;启动失败时在返回错误前释放 fiber。已 settle 但处于 pending 状态的挂载仍然可见,并列出其缺失的注入。`cordis_unmount` 等待挂载 fiber 的释放完成。 ### 通过 provide/inject 实现跨挂载组合 -挂载之间通过普通的 Cordis 服务语义相互关联,以各自的 id 作为生命周期句柄:挂载 A 调用 `ctx.provide('foo', value)`,挂载 B 声明 `inject: ['foo']` 并在 `foo` 存在的瞬间激活;如果 B 先挂载,它会保持 pending 状态并列出缺失的服务;卸载 A 会使 B 回到 pending(其注册被撤销),之后重新 provide 会通过一个新的沙箱门面重新运行 B 的 `apply`;重复 provide 会大声失败并指名拥有该服务的 fiber。一个 realm 注意事项:挂载提供的服务值是 vm realm 对象——从任何地方调用其方法都能工作,但消费方不得假设其上有宿主原型。 +挂载之间通过普通的 cordis 服务语义相互关联,以各自的 id 作为生命周期句柄:挂载 A 调用 `ctx.provide('foo', value)`,挂载 B 声明 `inject: ['foo']` 并在 `foo` 存在的瞬间激活;如果 B 先挂载,它保持 pending 状态并列出缺失的服务;卸载 A 使 B 回到 pending(其注册被撤销),之后重新 provide 会通过一个新的沙箱门面重新运行 B 的 `apply`;重复 provide 会明确报错并指出拥有该服务的 fiber。一个 realm 注意事项:由挂载 provide 的服务值是 vm realm 对象——从任何地方调用其方法都能工作,但消费方不得假设它具有宿主原型。 ### 生成的 API 目录 -`cordis_inspect` 从生成的目录而非重复的表格提供 API 和事件数据。生成器复用 Cordis 目录的 AST 扫描,输出服务摘要、签名、事件模式、引用的类型声明和继承的上下文接口面。有歧义的类型名被省略,过大的声明被标记为截断。 +`cordis_inspect` 从生成的目录提供 API 和事件数据,而非维护一份重复的表格。生成器复用 Cordis 目录的 AST 扫描,输出服务摘要、签名、事件模式、引用的类型声明以及继承的 context 接口面。有歧义的类型名被省略,过大的声明被标记为截断。 -新鲜度像所有生成产物一样受门禁保护:`pnpm run verify-cordis-api`(在 `doc-sync` 中)在内存中重新生成并在有任何 diff 时失败,因此修改了公开签名的 JSDoc 变更在不重新生成模型所读目录的情况下无法发布。运行时,inspect 工具将目录与活跃运行时取交集而非直接转储:有目录条目的活跃服务渲染摘要 + 签名,没有目录条目的活跃服务(挂载提供的)渲染名称 + 所属 fiber,有目录条目但没有活跃提供方的服务简要列出,引用的类型形状随后附上。 +新鲜度像所有生成产物一样受门禁约束:`pnpm run verify-cordis-api`(在 `doc-sync` 中)在内存中重新生成并在有任何 diff 时失败,因此修改了公开签名的 JSDoc 变更如果不重新生成模型读取的目录就无法合入。运行时 inspect 工具将目录与活跃运行时取交集而非直接转储:有目录条目的活跃服务渲染摘要 + 签名,没有目录条目的活跃服务(挂载提供的)渲染名称 + 所属 fiber,有目录条目但无活跃提供方的服务简要列出,引用的类型形状随后附上。 ### 配置、渲染与可观测性 -该插件暴露一个配置字段,由 schemastery 校验并记录在[配置目录](../../../config-catalog.md)中:`vmTimeoutMs`(默认 5000),挂载代码同步执行部分的毫秒上限。工具名称、`cordis-dynamic` 分组名和 `dyn-` id 前缀是结构性词汇,保持固定。三个工具均按[工具实操手册](../../../cookbook/adding-a-tool.md)渲染为 `generic` 卡片(`cordis_inspect` 为 `read`,`cordis_mount` 为 `execute` 并将代码作为 `rawInput` 携带,`cordis_unmount` 为 `delete`),不覆盖 `presentResult`。 +该插件暴露一个配置字段,由 schemastery 校验并记录在[配置目录](../../../config-catalog.md)中:`vmTimeoutMs`(默认 5000),挂载代码同步执行部分的毫秒上限。工具名、`cordis-dynamic` 分组名和 `dyn-` id 前缀是结构性词汇,保持固定。三个工具均按[工具实操手册](../../../cookbook/adding-a-tool.md)渲染为 `generic` 卡片(`cordis_inspect` 为 `read`,`cordis_mount` 为 `execute` 并将代码作为 `rawInput` 携带,`cordis_unmount` 为 `delete`),不覆盖 `presentResult`。 -「模型可见 ⟺ 已记录」成立,且不引入新的会话事件类型:挂载或卸载仅通过其自身的 `tool/call` / `tool/result` 对可见(循环会记录它),而挂载引起的工具集变化则由循环在 schema 在步骤间变化时已有的请求头 delta 日志记录。刻意不设 `cordis/mount` 溯源事件——它只会重复工具调用对已记录的内容。动态挂载是进程生命周期的,不是会话状态:恢复持久化的会话会重建对话但不会重新挂载插件。 +「模型可见 ⟺ 已记录」成立,且无需新的会话事件类型:挂载或卸载仅通过其自身的 `tool/call` / `tool/result` 对可见(循环会记录它们),而挂载引起的工具集变化由循环在 schema 在步骤间发生变化时已有的 request-header delta 记录。刻意不设 `cordis/mount` 溯源事件——它只会重复工具调用对已记录的内容。动态挂载是进程生命周期的,不是会话状态:恢复一个持久化的会话会重建对话,但不会重新挂载插件。 ## 曾考虑的替代方案 -**用结构化的逐能力注册工具替代 `cordis_mount`。** 最诱人的替代方案是一个带有显式 `name` / `description` / `parameters` / `code` 字段的 `cordis_register_tool`(以及兄弟工具 `cordis_register_listener`、`cordis_register_service`、……),而非单一的「挂载一个插件」原语。否决原因:它唯一的真正优势——对最常见的单一场景省去插件样板——不足以抵偿其代价,而单一的挂载原语能一次性覆盖所有能力。 +**用结构化的逐能力注册工具替代 `cordis_mount`。** 最具吸引力的替代方案是一个带有显式 `name` / `description` / `parameters` / `code` 字段的 `cordis_register_tool`(以及兄弟工具 `cordis_register_listener`、`cordis_register_service`……),而非单一的「挂载一个插件」原语。否决原因:它唯一的真正优势——对最常见的单一场景免去插件样板代码——不足以抵偿其代价,而单一的 mount 原语能一次性覆盖所有能力。 | 维度 | 结构化逐能力工具 | 单一 `cordis_mount` | |---|---|---| -| Schema 正确性 | `parameters` 仍是模型编写的 JSON 对象,需要 SchemaSpec 校验,只是提前了一步 | 同样的校验在沙箱边界运行,同样的指导性错误 | -| 代码字段 | `execute` 体仍是 vm 中模型编写的 JS;realm 和服务调用正确性问题不变 | 一个沙箱、一条规范化路径、一道受守护的注册 | -| 能力覆盖面 | 仅限工具;监听器、服务、`inject` 关系各需另一个结构化工具——接口面无限增长 | 一套词汇(一个 Cordis 插件)覆盖当前和未来的所有效果 | -| 跨挂载组合 | 在工具注册载荷中无法表达 | 原生 `provide`/`inject`,普通 Cordis 语义 | -| 可审视性 | 注册的东西在插件列表中无法作为插件展示 | 模型挂载的东西正是 `cordis_inspect` 渲染的东西 | -| 模型易用性 | 对最常见的单一场景有优势(无插件样板) | 通过挂载描述中的规范示例加上教导正确做法的边界错误来缓解 | +| Schema 正确性 | `parameters` 仍然是模型编写的 JSON 对象,需要 SchemaSpec 校验,只是提前了一步 | 同样的校验在沙箱边界运行,同样的指导性错误信息 | +| 代码字段 | `execute` 函数体仍然是 vm 中模型编写的 JS;realm 和服务调用的正确性问题不变 | 一个沙箱、一条规范化路径、一处受保护的注册 | +| 能力覆盖面 | 仅限工具;监听器、服务、`inject` 关系各需另一个结构化工具——接口面无限增长 | 一套词汇(cordis 插件)覆盖当前和未来的所有效果 | +| 跨挂载组合 | 在工具注册载荷中无法表达 | 原生 `provide`/`inject`,普通的 cordis 语义 | +| 可审视性 | 注册的东西无法在插件列表中显示为插件 | 模型挂载的正是 `cordis_inspect` 渲染的 | +| 模型人机工程学 | 对最常见的单一场景有优势(无插件样板) | 通过 mount 描述中的规范示例加边界错误信息教会正确调用来缓解 | -因此,正确性投入放在能一次性覆盖所有能力的地方:通过 `cordis_inspect` 暴露的生成 API 目录,以及沙箱边界校验——其错误消息教导正确的调用方式。结构化注册工具日后仍可作为语法糖添加,合成挂载代码即可;本设计不排斥它。 +因此正确性投入放在能一次性为所有能力带来回报的地方:通过 `cordis_inspect` 呈现的生成 API 目录,以及沙箱边界校验(其错误信息教会正确的调用方式)。结构化注册工具日后仍可作为语法糖添加,由它合成 mount 代码;本设计不排斥这一可能。 -**在工具中手工维护服务/事件参考。** inspect 工具的第一版携带了一张手写的服务方法签名表。它被生成的 `api-catalog.ts` 取代,因为手写表在签名变化的瞬间就会与 JSDoc 脱节,且没有门禁检测这种漂移;而生成产物的新鲜度由与文档使用同一 AST 的检查来保证。 +**在工具中手工维护服务/事件参考。** inspect 工具的第一版携带了一份手写的服务方法签名表。它被生成的 `api-catalog.ts` 取代,因为手写表在签名变化的瞬间就会与 JSDoc 脱节且没有门禁约束这种漂移,而生成产物的新鲜度由文档使用的同一套 AST 检查。 -**新增 `cordis/mount` 会话事件。** 记录每次挂载(源码、名称)的持久溯源事件有明确先例(`hook/invoked`、`compact/start`)。v1 中否决:挂载和卸载已经作为 `tool/call` / `tool/result` 对可见,工具集变化已经作为请求头 delta 被记录,因此专用事件只会重复记录。如果审计用例需要将挂载溯源与工具调用分离,日后仍可添加。 +**新增 `cordis/mount` 会话事件。** 一个持久的溯源事件记录每次挂载(源码、名称)有明确先例(`hook/invoked`、`compact/start`)。v1 中予以否决:挂载和卸载已经作为 `tool/call` / `tool/result` 对可见,工具集变化已经作为 request-header delta 被记录,因此专用事件只会重复记录。如果审计用例需要将挂载溯源从工具调用中分离出来,日后仍可添加。 -**加固的 / 能力受限的沙箱。** 拦截 Node 内置模块并向挂载代码提供白名单门面而非原始 context,可能暗示意图是为安全而沙箱化。明确声明并非如此:陷阱和门面收窄的是挂载代码所见的*接口面*——将其引导至 Cordis 服务、远离易泄漏的 Node 内置模块和框架内部——目的是正确性和封堵未守护的 context 逃逸,但门面暴露的能力(`ctx.bash`、`ctx.fs`、`ctx.web`)触及真实运行时,因此它不是安全边界。真正的安全边界(独立进程、权限提示)对一个开发/主动启用的工具集来说超出范围,且与其核心目标——将活跃运行时交给模型——相悖。 +**加固的/能力受限的沙箱。** 对 Node 内置模块设陷阱并向挂载代码提供白名单门面而非原始 context,可能暗示意图是为安全而沙箱化。这里明确不是:陷阱和门面收窄的是挂载代码所见的*接口面*——将其引导至 cordis 服务、远离易泄漏的 Node 内置模块和框架内部——目的是正确性和封堵未受保护的 context 逃逸,但门面暴露的能力(`ctx.bash`、`ctx.fs`、`ctx.web`)触及真实运行时,因此它不是安全边界。真正的安全边界(独立进程、权限提示)超出了一个开发/显式启用工具集的范围,且会与其核心目的——将活跃运行时交给模型——相冲突。 ## 后果 -该工具集是刻意需要主动启用的,具有完全权限的 `ctx`,因此部署方采用它的意识程度与采用 bash 工具相同。以下事实由工具描述直接告知模型:waterfall(瀑布式事件)监听器(如 `tools/pre-execute`)如果不调用 `next()` 就返回,会否决整条链,因此挂载的监听器可以瘫痪 agent 自身的工具分发([waterfall 语义](../../../cordis-primer.md#cordis-waterfall-semantics));挂载代码在当前轮次的工具调用内运行,因此 await 任何只在该轮次结束后才 resolve 的东西会死锁;`vmTimeoutMs` 仅约束同步执行;挂载不会在会话恢复后存活。 +该工具集是刻意的显式启用设计,具有完全特权的 `ctx`,因此部署方采用它的意识程度应与 bash 工具相当。以下几个事实由工具描述直接告知模型:一个 waterfall(瀑布式事件)监听器(如 `tools/pre-execute`)如果不调用 `next()` 就返回,会否决整条链,因此一个挂载的监听器可以瘫痪 agent 自身的工具分发([waterfall 语义](../../../cordis-primer.md#cordis-waterfall-semantics));挂载代码在当前轮次的工具调用内运行,因此 await 任何只在该轮次结束后才 resolve 的东西会导致死锁;`vmTimeoutMs` 仅约束同步执行;挂载不会在会话恢复后存活。 diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml b/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml index eef8b3d86c..c824942f12 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-10-session-query-service.md: 8b742ac19fea21d8404f5f44aa64f8c3cb3efccc -2026-07-10-session-query-service.zh.md: 43175b05d82ad758a16e516f3fd8b7b650f9d762 +2026-07-10-session-query-service.zh.md: 73f47d0cc0306b3dcb6552c686f8f1a71ffbdc87 diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md b/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md index 43175b05d8..73f47d0cc0 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md @@ -1,43 +1,43 @@ # RFC:精确会话查询服务 -Status: implemented - [English](2026-07-10-session-query-service.md) | 中文 +Status: implemented + ## 问题 -会话历史存在于两处:当前的 `SessionStore` 对象和可选的持久化后端。需要精确检查的消费方如果不借助统一服务,就得各自重复实现活跃/持久化优先级、持久化生命周期处理、原始事件 surface 分类和防御性克隆。检查点之间持久状态可能落后于活跃日志,因此单靠持久化并不是可信的当前数据源。 +会话历史存在于两处:当前的 `SessionStore` 对象与可选的持久化后端。需要精确检查的消费方若无统一服务,就不得不各自重复实现活跃/持久化优先级判定、持久化生命周期处理、原始事件的 surface 分类以及防御性克隆。在检查点之间,持久化状态可能落后于活跃日志,因此仅靠持久化并非当前状态的可靠来源。 -全文搜索与此相关但规模大得多。在真正的后端出现之前就设计提供方注册、抽取、同步、失效、排序和游标契约,会产生两个投机性的状态机:一个在接口服务中,另一个在最终的数据库包中。 +全文搜索与此相关,但规模大得多。在真实后端尚不存在时就设计提供方注册、提取、同步、失效、排序和游标契约,会产生两个投机性的状态机:一个在接口服务中,另一个在最终的数据库包(package)中。 ## 决策 -`@deepseek-ai/dsh-session-query` 拥有 `ctx.sessionQuery`:一个面向单一逻辑语料库的小型可信精确读取服务。它暴露 `listSessions()`、`listEvents(sessionId)` 和有界的 `readEvent(request)`。它不暴露过滤器、血缘/溯源遍历、文本抽取器、搜索请求、提供方注册或派生索引同步。 +`@deepseek-ai/dsh-session-query` 拥有 `ctx.sessionQuery`,这是一个小型的、受信任的精确读取服务,面向单一逻辑语料库。它暴露 `listSessions()`、`listEvents(sessionId)` 和有界的 `readEvent(request)`。它不暴露过滤器、血缘或溯源遍历、文本提取器、搜索请求、提供方注册或派生索引同步。 -该服务动态观察可选的 `ctx.sessionPersistence` 绑定,但不保留持久化缓存或失效监听器。每次跨语料库列举都向活跃后端请求权威元数据,然后叠加一份新鲜的活跃 store 列表。id 匹配的条目合并为一条 `SessionRecord`:活跃 header 优先,`live`/`persisted` 独立报告来源可用性。不可变 header 不一致时报 `SESSION_QUERY_SOURCE_CONFLICT`。 +该服务动态观察可选的 `ctx.sessionPersistence` 绑定,但不保留持久化缓存或失效监听器。每次跨语料库列表操作向活跃后端请求权威元数据,然后叠加一份新鲜的活跃 store 列表。id 匹配的条目合并为一条 `SessionRecord`:活跃 header 优先,`live`/`persisted` 各自独立报告来源可用性。不可变 header 不一致时产生 `SESSION_QUERY_SOURCE_CONFLICT`。 -精确目标读取首先检查活跃 store,快照活跃 header 和事件日志。此路径从不查询持久化,因此持久化后端故障不会使已知的活跃历史变得不可读。当活跃 store 中无目标时,服务列举当前持久化元数据、证明该 id 存在、加载它,并在列举/加载的 header 不一致时拒绝。所有返回的 header 和事件都经过一次 structured-clone 边界。 +精确目标读取首先检查活跃 store,快照活跃 header 与事件日志。此路径从不查询持久化,因此持久化后端故障不会导致已知的活跃历史不可读。若活跃 store 中无目标,服务列出当前持久化元数据、证明该 id 存在、加载它,并在列表/加载 header 不一致时拒绝。所有返回的 header 与事件都经过一次 structured-clone 边界。 ## Surface 语义 -`dsh-session` 导出 `foldSurface(events)`,`SurfaceManager` 对其增量缓存使用相同的转换函数。fold 返回分离的当前节点以及每次替换实际移除的 seq。`listEvents()` 利用该结果将每个原始事件分类为 `current`、`shadowed` 或 `log-only`,使检查结果不会在位置替换语义上与 model-history 推导产生分歧。 +`dsh-session` 导出 `foldSurface(events)`,`SurfaceManager` 使用相同的转换函数维护其增量缓存。fold 返回分离的当前节点以及每次替换实际移除的 seq。`listEvents()` 利用该结果将每个原始事件分类为 `current`、`shadowed` 或 `log-only`,使检查结果不会在位置替换语义上与 model-history 推导产生分歧。 -`readEvent()` 返回完整的目标事件以及按连续 seq 排列的原始邻居。`before` 和 `after` 默认为零,各自受 `readWindowMax`(默认 50)约束。结果携带克隆的 `SessionHeader` 而非来源可用性记录,因为判断活跃目标的 persisted 标志会违反「活跃精确读取不依赖持久化健康状态」这一保证。 +`readEvent()` 返回完整的目标加上按连续 seq 排列的原始相邻事件。`before` 和 `after` 默认为零,各自受 `readWindowMax`(默认 50)约束。结果携带克隆的 `SessionHeader` 而非来源可用性记录,因为判断活跃目标的 persisted 标志会违反「活跃精确读取不依赖持久化健康状态」这一保证。 ## 安全边界 -该服务是上下文范围内的可信基础设施,而非授权层。未来面向模型的历史工具或人类 UI 将施加显式的调用方/会话作用域。本阶段不添加面向模型的工具,也不改变 transcript(文本记录)或快照 surface。 +该服务是上下文级别的受信任基础设施,而非授权层。未来面向模型的历史工具或人类 UI 将施加显式的调用方/会话范围。本阶段不添加面向模型的工具,也不改变 transcript(文本记录)或快照的 surface。 ## 曾考虑的替代方案 -- **让每个消费方自行实现逻辑语料库解析**:否决。来源优先级、冲突处理、可选服务生命周期、克隆和 surface 分类是共享的正确性规则。 -- **只查询持久化**:否决。检查点之间持久化可能落后于当前活跃日志。 -- **缓存持久化元数据并监听写入/删除**:否决。精确读取可以直接询问权威来源,而缓存失效在规模尚未要求之前就引入了生命周期和并发状态。 +- **将逻辑语料库解析直接放在每个消费方中**:否决。来源优先级、冲突处理、可选服务生命周期、克隆与 surface 分类是共享的正确性规则。 +- **仅查询持久化**:否决。检查点可能落后于当前活跃日志。 +- **缓存持久化元数据并监听写入/删除**:否决。精确读取可以直接询问权威来源,而缓存失效在规模尚未要求时就引入了生命周期与并发状态。 - **现在就定义提供方无关的搜索协议**:否决。目前没有提供方消费它。第一个 SQLite FTS 包应自行拥有一个协调/事务状态机;只有当第二个实现证明了边界时,才提取更小的共享 seam。 -- **在第一阶段就包含血缘、溯源和通用过滤器**:否决。当前没有消费方需要它们,且规范日志足以在有证据时再行添加。 +- **在第一阶段就包含血缘、溯源和通用过滤器**:否决。当前没有消费方需要它们,且规范日志足以在日后有证据时再行添加。 ## 后果 -第一阶段只有一个来源解析状态变量:当前挂载的持久化服务。没有提供方队列、指纹、抽取器注册表、观察代次或派生索引更新。精确读取在纯活跃部署中仍然可用,在持久化存在时具有确定性。 +第一阶段只有一个来源解析状态变量:当前挂载的持久化服务。没有提供方队列、指纹、提取器注册表、观察代次或派生索引更新。精确读取在纯活跃部署中仍然可用,在持久化存在时具有确定性。 -跨语料库列举和持久化精确读取每次调用都执行后端 I/O。这是有意为之:正确性来自当前权威状态,面向规模的搜索属于第二阶段的数据库。全文搜索在该包定义并实现其完整契约之前不可用。 +跨语料库列表与持久化精确读取在每次调用时执行后端 I/O。这是有意为之:正确性来自当前权威状态,面向规模的搜索属于第二阶段的数据库。在该包定义并实现其完整契约之前,全文搜索不可用。 diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml index ad328eaaaa..6675490bb9 100644 --- a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-12-subagent-persona-tool-filter-and-depth.md: 368f3a3592c5e241bb9357d4d4ce32e175c3de45 -2026-07-12-subagent-persona-tool-filter-and-depth.zh.md: 6c1ce8ac08fe3d37c400d489808e592570ebd6c7 +2026-07-12-subagent-persona-tool-filter-and-depth.zh.md: cc78a472df014ce1eb9114277e0520c7e9c051bb diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md index 6c1ce8ac08..cc78a472df 100644 --- a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md @@ -1,94 +1,94 @@ -# RFC:配置 subagent 的 persona、工具可见性与深度 - -Status: implemented +# RFC:配置 subagent 的人设、工具可见性与深度 [English](2026-07-12-subagent-persona-tool-filter-and-depth.md) | 中文 +Status: implemented + ## 问题 -一个可复用的 subagent 提供方解决的是「如何运行子 agent」的问题,但不同的委派工具需要不同的子 agent 行为。某个部署可能需要一个评审者 persona、一组仅限研究的工具集,或一个硬性递归上限,而不必为每种组合都创建新的提供方。 +一个可复用的 subagent 提供方解决的是「如何运行子 agent(智能体)」的问题,但不同的委派工具需要不同的子 agent 行为。某个部署可能需要评审者人设、仅限研究的工具集,或硬性递归上限,而不必为每种组合创建新的提供方。 -这些控制影响子 agent 的第一次模型请求,因此不能在子 agent 可见之后才安装。它们还需要提供方诚实地声明支持:ACP 后端不能静默接受一个仅适用于进程内的工具过滤器,而过滤器也不应在所有插件运行于同一可信进程时被描述为安全边界。 +这些控制影响子 agent 的第一次模型请求,因此不能在子 agent 可见之后再安装。它们还需要提供方的诚实支持:ACP(Agent Client Protocol)后端不能默默接受一个仅限进程内的工具过滤器,而过滤器在所有插件运行于同一可信进程的情况下也不应被描述为安全边界。 ## 决策 -subagent 启动有三个独立的组合控制:`persona`、`toolFilter` 和 `maxDepth`。提供方声明对每个控制的支持,服务在启动运行前拒绝不支持的请求,而进程内提供方在子 agent 尚未发布时安装所请求的组合。 +subagent 启动有三个独立的组合控制:`persona`、`toolFilter` 和 `maxDepth`。提供方声明对每个控制的支持情况,服务在启动运行之前拒绝不受支持的请求,进程内提供方在子 agent 尚未发布时安装所请求的组合。 这些控制回答不同的问题: | 控制 | 问题 | 结果 | |---|---|---| -| `persona` | 哪些角色指令替换该子 agent 的部署 persona? | 一个子 agent 局部的 prompt 段落遮蔽 `deployment:persona` | -| `toolFilter` | 哪些部署全局工具进入该子 agent 的可见工具视图? | 一个有作用域的限制在添加子 agent 局部工具之前过滤全局工具 | -| `maxDepth` | 这棵委派树最深可以长到多少层? | 当子 agent 深度超过绝对上限时,启动请求被拒绝 | +| `persona` | 什么角色指令替换该子 agent 的部署人设? | 一个子 agent 局部的 prompt 段落遮蔽 `deployment:persona` | +| `toolFilter` | 部署全局工具中哪些进入该子 agent 的可见工具视图? | 一个有作用域的限制在添加子 agent 局部工具之前过滤全局工具 | +| `maxDepth` | 这棵委派树最深可以长到多少层? | 子 agent 深度超过绝对上限时,启动请求被拒绝 | -`dsh-tool-subagent` 将这些控制作为插件配置暴露,并将它们复制到每个创建的请求中。直接调用 `SubagentService` 的调用方可以按请求选择。提供方能力描述符仍然是后端能否兑现各字段的真源。 +`dsh-tool-subagent` 将这些控制作为插件配置暴露,并复制到它创建的每个请求中。直接调用 `SubagentService` 的调用方可以按请求选择这些控制。提供方的能力描述符仍然是后端能否兑现各字段的真源。 -### Persona 是有作用域的遮蔽 +### 人设是有作用域的遮蔽 -persona 控制改变一个子 agent 而不改变部署级别的 prompt 组装。在未发布的设置阶段,进程内提供方在子 agent 作用域中注册一个名为 `deployment:persona` 的段落;普通的最具体者胜出解析规则仅在该子 agent 的组装中替换全局段落。 +人设控制改变一个子 agent 的行为,而不改变部署级的 prompt 组装。在未发布的设置阶段,进程内提供方在子 agent 作用域中注册一个名为 `deployment:persona` 的段落;普通的最具体者优先解析规则仅在该子 agent 的组装中替换全局段落。 -其值具有与部署 persona 相同的严格模板语义。省略时通过全局层继承部署段落;显式空字符串则以空段落遮蔽全局 persona。父 agent 和兄弟 agent 的 persona 永远不会进入子 agent 的扁平作用域。 +其值与部署人设具有相同的严格模板语义。省略时通过全局层继承部署段落;显式空字符串则以空段落遮蔽全局人设。父级和兄弟级的人设永远不会进入子 agent 的扁平作用域。 -这使用的是正常的系统提示词注册机制,而非第二条 persona 通道。因此第一次 prompt 看到的命名贡献与后续 prompt 和 prompt 检查工具看到的相同。 +这使用的是常规的系统提示词注册机制,而非第二条人设通道。因此第一次 prompt 看到的命名贡献与后续 prompt 和 prompt 检查工具看到的一致。 -### 工具过滤是一条实时的全局视图规则 +### 工具过滤是一条作用于全局视图的活规则 -工具过滤器同时控制能力可见性与可执行查找。进程内提供方在发布前于子 agent 作用域中安装 `ToolRegistry.restrict()`,注册表的单一解析器将相同结果应用于协议格式(wire format)的工具 schema、查找、执行和 Code Mode SDK 生成。独立注册的系统提示词段落不在 `ToolRegistry` 内,因此过滤一个工具不会移除该插件的独立指导文本。 +工具过滤同时控制能力可见性和可执行查找。进程内提供方在发布前于子 agent 作用域中安装 `ToolRegistry.restrict()`,注册表的单一解析器对协议格式(wire format)的工具 schema、查找、执行和 Code Mode SDK 生成施加相同的结果。独立注册的系统提示词段落不在 `ToolRegistry` 内,因此过滤一个工具不会移除该插件的独立指导文本。 解析遵循以下规则: -1. 每个限制对实时的部署全局工具注册表先应用 `allow` 再应用 `deny`。 -2. 多个限制取交集,因此每个已安装的限制都必须放行一个全局工具。 +1. 每条限制对活跃的部署全局工具注册表先应用 `allow` 再应用 `deny`。 +2. 多条限制取交集,因此每条已安装的限制都必须放行一个全局工具。 3. 子 agent 作用域的工具在全局过滤之后添加,可以遮蔽一个已放行的全局工具。 -4. 保留的 `run_code` 呈现和其他作用域局部的协议贡献不在全局过滤器范围内。 +4. 保留的 `run_code` 呈现和其他作用域局部的协议贡献不受全局过滤器影响。 -当过滤器既不提供 `allow` 也不提供 `deny`,或命名了当前全局可限制集合之外的内容(包括仅作用域局部或保留的名称)时,配置会大声失败。`allow: []` 是合法的,它有意隐藏所有全局工具。这些检查能捕获拼写错误,并防止配置在无法影响所命名条目时看起来有效。 +当过滤器既未提供 `allow` 也未提供 `deny`,或命名了当前全局可限制集合之外的内容(包括仅作用域局部或保留名称)时,配置会显式失败。`allow: []` 合法,且有意隐藏所有全局工具。这些检查能捕获拼写错误,并防止配置在无法影响所命名条目时看起来仍然有效。 -全局注册表保持实时。仅 deny 的过滤器会放行后续注册的全局名称(除非显式 deny 该名称);allow 列表会排除后续注册的全局名称(除非显式 allow 该名称)。移除一个全局工具会将其从所有解析视图中移除。这些语义在保持热注册的同时,使 allow 与 deny 的区别显式化。 +全局注册表保持活跃。仅 deny 的过滤器会放行后来注册的全局名称(除非显式 deny 该名称);allow 列表会排除后来注册的全局名称(除非显式 allow 该名称)。移除一个全局工具会将其从所有已解析视图中移除。这些语义在保持热注册的同时,使 allow 与 deny 的区别显式化。 ### 深度是绝对的树上限 -深度限制独立于工具可见性来约束递归委派。顶层 agent 的深度为零;进程内子 agent 的深度为其父 agent 经验证的深度加一。`maxDepth` 是一个绝对的非负安全整数,当推导出的子 agent 深度大于上限时,启动在子 agent 所有权开始之前即被拒绝。 +深度限制独立于工具可见性来约束递归委派。顶层 agent 深度为零;进程内子 agent 的深度为其父级已验证深度加一。`maxDepth` 是一个绝对的非负安全整数,当推导出的子 agent 深度大于上限时,启动在子 agent 所有权开始之前即被拒绝。 -每个公开入口都验证值域,而不依赖单一的面向模型的配置路径。负值、小数、负零、非有限值、不安全整数、格式错误的已存储父深度以及推导溢出都会被拒绝。省略上限则该机制不约束深度。 +每个公开入口都自行验证值域,而非依赖单一的面向模型配置路径。负值、小数、负零、非有限值、不安全整数、格式错误的存储父级深度以及推导溢出均被拒绝。省略上限时,此机制不约束深度。 -部署可以组合深度与过滤。例如,可以在深度一时保留委派工具可见但设置 `maxDepth: 1`,或在子 agent 中完全 deny 委派工具。两种选择都不改变提供方的对话历史行为。 +部署可以组合深度与过滤。例如,可以在深度一时保持委派工具可见但设置 `maxDepth: 1`,或在子 agent 中完全 deny 委派工具。两种选择都不改变提供方的对话历史行为。 ### 能力门控保持提供方诚实 -能力将请求的特性与提供方实现分离。`SubagentCapabilities` 声明 `persona`、`toolFilter` 和 `depthLimit`;`SubagentService.start()` 在调用提供方之前,对照这些标志检查请求中的每个字段。 +能力将请求的特性与提供方实现分离。`SubagentCapabilities` 声明 `persona`、`toolFilter` 和 `depthLimit`;`SubagentService.start()` 在调用提供方之前,对照这些标志检查请求中每个存在的字段。 -这使得 spawn 和 fork 提供方可以共享进程内实现,而外部提供方只声明自己能强制执行的部分。请求永远不会静默降级:选择一个不支持的控制会产生 `UNSUPPORTED_CAPABILITY`,不会有运行或生命周期事件存在。 +这使 spawn 和 fork 提供方可以共享进程内实现,而外部提供方只声明自己能强制执行的部分。请求永远不会静默降级:选择不受支持的控制会产生 `UNSUPPORTED_CAPABILITY`,不会有运行或生命周期事件存在。 -### 未发布的设置使第一次请求正确 +### 未发布设置使第一次请求正确 -所有子 agent 局部的组合在子 agent 变得可观察之前完成。进程内提供方向 agent 创建提供一个设置回调;该回调在子 agent 作用域中安装 persona、工具限制和结构化输出贡献。只有设置成功后,创建才会发布会话和 agent 并允许驱动器启动。 +所有子 agent 局部的组合在子 agent 变得可观察之前完成。进程内提供方向 agent 创建提供一个设置回调;该回调在子 agent 作用域中安装人设、工具限制和结构化输出贡献。只有设置成功后,创建才发布会话和 agent 并允许驱动器启动。 -设置失败会回滚私有的子 agent。没有观察者能获取到一个「第一次 prompt 使用了部署 persona 或未过滤工具集、后续 prompt 才使用请求配置」的子 agent。 +设置失败会回滚私有子 agent。没有观察者能获取到一个「第一次 prompt 使用了部署人设或未过滤工具集、后续 prompt 才使用所请求配置」的子 agent。 ## 可见性不是授权 -这些控制组合的是可信的同进程行为;它们不授权行为。`toolFilter` 改变工具注册表解析出的子 agent 视图,但它不创建父到子的授权格,不要求子 agent 是父 agent 的子集,不沙箱化插件,也不阻止持有另一个 Cordis 上下文的代码直接调用服务。 +这些控制组合的是同一可信进程内的行为,而非授权行为。`toolFilter` 改变工具注册表解析出的子 agent 视图,但它不创建父到子的授权格,不要求子 agent 是其父级的子集,不沙箱化插件,也不阻止持有另一个 Cordis 上下文的代码直接调用服务。 -特别地,子 agent 局部工具在全局过滤之后添加,可能不在父 agent 的视图中。仅 deny 的子 agent 也能看到 deny 列表未命名的后续全局工具。这些是有意的实时组合语义,而非不可提权保证。 +具体而言,子 agent 局部工具在全局过滤之后添加,可能不在父级视图中。仅 deny 的子 agent 也能看到 deny 列表未命名的后来全局工具。这些是有意的活组合语义,而非不可升级保证。 -安全设计需要独立的授权表示、传播规则和执行时强制点。创建时的授权快照、父集合子集授权、显式的未来授权 API,以及通用的能力/输出/终止标签都不在本特性范围内。 +安全设计需要独立的授权表示、传播规则和执行时强制点。创建时的授权快照、父级子集授权、显式的未来授权 API,以及通用的能力/输出/终止标签均不在本特性范围内。 ## 曾考虑的替代方案 -**为每个 persona 或工具集创建一个提供方。** 这会使共享相同传输和生命周期实现的提供方成倍增加,使动态部署配置变得笨拙,且仍然需要递归机制。提供方的职责仍然是执行传输;请求承载每个子 agent 的组合。 +**为每种人设或工具集创建一个提供方。** 这会使共享相同传输和生命周期实现的提供方成倍增加,使动态部署配置变得笨拙,且仍需要递归机制。提供方的职责是执行传输;请求承载每个子 agent 的组合。 -**复制父 agent 的完整工具视图。** 注册作用域设计上是扁平的,生命周期所有权不意味着可见性继承。复制已解析的视图还会冻结动态全局注册,并在未完整定义任一契约的情况下混淆组合与授权。 +**复制父级的完整工具视图。** 注册作用域设计上是扁平的,生命周期所有权不意味着可见性继承。复制已解析视图还会冻结动态全局注册,并在未完整定义任一契约的情况下混淆组合与授权。 -**在子 agent 创建时快照允许的全局工具。** 冻结的 allow 集合使未来注册一律不可用,但它改变了热注册语义并开启了授权设计。已实现的过滤器保持为实时注册表谓词,并直接记录 allow 与 deny 的行为。 +**在子 agent 创建时快照允许的全局工具。** 冻结的 allow 集合使未来注册统一不可用,但它改变了热注册语义并开启了授权设计。已实现的过滤器保持为活跃的注册表谓词,并直接记录 allow 与 deny 的行为。 -**仅隐藏工具 schema。** 仅呈现层的过滤让模型可以通过 Code Mode 或伪造调用执行一个 prompt 声称不存在的工具。改为由一个解析器同时管控呈现与执行。 +**仅隐藏工具 schema。** 仅呈现层的过滤让模型可以通过 Code Mode 或伪造调用执行一个 prompt 声称不存在的工具。改为由一个解析器同时管控呈现和执行。 -**仅用工具过滤来阻止递归。** 移除委派工具有用但依赖特定提供方,且无法保护直接的服务调用方或替代委派工具。绝对深度是一个独立的结构性约束。 +**仅用工具过滤来阻止递归。** 移除委派工具有用但依赖特定提供方,且不保护直接服务调用方或替代委派工具。绝对深度是独立的结构性约束。 ## 后果 -贡献者可以配置子 agent 的角色、可见全局工具和递归深度,而无需定义新的提供方。能力检查在所有权开始前失败,未发布的设置使第一次请求一致,单一工具解析器防止呈现/执行漂移。 +贡献者可以配置子 agent 的角色、可见全局工具和递归深度,而无需定义新的提供方。能力检查在所有权开始之前失败,未发布设置使第一次请求一致,单一工具解析器防止呈现/执行漂移。 -代价是部署方必须理解实时 allow/deny 行为以及可见性与授权的区别。提供方作者必须准确声明每个支持的控制,进程内提供方必须在发布前安装所有请求的贡献。这些控制有意不解决安全隔离或父到子的不可提权问题。 +代价是部署方必须理解活跃的 allow/deny 行为以及可见性与授权的区别。提供方作者必须准确声明每个受支持的控制,进程内提供方必须在发布前安装所有请求的贡献。这些控制有意不解决安全隔离或父到子的不可升级问题。 diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml index 31c5a1b2e0..120abae517 100644 --- a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-doc-sync-enforcement.md: 44ea84daddcae73ce07b0a8240f83ee9945e449d -2026-06-11-doc-sync-enforcement.zh.md: e7abe2d87fd97211f653b63ddb8818077532af48 +2026-06-11-doc-sync-enforcement.zh.md: c739e9661bb926c772f1d5399529a813ac59991c diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md index e7abe2d87f..c739e9661b 100644 --- a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md @@ -1,32 +1,32 @@ # RFC:Doc-sync 强制 -Status: implemented - [English](2026-06-11-doc-sync-enforcement.md) | 中文 +Status: implemented + ## 问题 -AGENTS.md 承诺文档与代码严格同步,但这一承诺此前只靠肉眼验证。评审曾两次发现漂移:一次是实操手册(cookbook)示例与类型策略矛盾,一次是 README 引用了错误的 `registerAdapter` 调用。失去同步的文档比没有文档更糟;而本代码库主要由 agent 构建,agent 对门禁的遵从远比对行文的遵从可靠(机械质量门禁)。有两类文档漂移可以被机械检查:不再能编译的代码块,以及重复了 `interface Events` 声明的事件分类体系表。 +AGENTS.md 承诺文档与代码严格同步,但这一承诺此前仅靠人眼核查。评审曾两次发现漂移:一次是实操手册(cookbook)示例与类型策略矛盾,一次是 README 引用了错误的 `registerAdapter` 调用。失去同步的文档比没有文档更糟;而本代码库主要由 agent(智能体)构建,agent 遵守门禁远比遵守行文约定可靠(机械质量门禁)。有两类文档漂移可以被机械检查:不再能编译的代码块,以及与 `interface Events` 声明重复的事件分类体系表。 ## 决策 两道门禁,沿用既有的 `scripts/` 风格(tsx ESM,每个脚本一项职责): -1. **`doc-typecheck`** 从 `README.md`、`docs/**` 和 `packages/*/README.md` 中提取所有 ` ```ts ` 围栏代码块,写入一个继承根 `tsconfig.json` 的临时项目,然后用 `tsc -b` 编译。临时项目复用源码的 `paths` 映射和根 project references,因此文档示例能看到源码,而 vendor 代码仍在其自身的 tsconfig 设置下被检查。刻意作为草图的代码块可以用显式的 ` ```ts ignore-check ` 信息字符串退出检查;脚本会报告退出比例,超过一半则失败,防止逃生口悄悄变成常态。 -2. **`verify-event-taxonomy`** 从 `packages/*/src` 的 `interface Events` 块中提取事件名,再从 `docs/architecture.md` 的分类体系表中提取事件名,断言两个集合完全一致。只校验、不生成:表格保留手写的 Mode/Purpose 列,只检查名称集合。(落地此门禁时发现了表格缺失的三个事件:`tools/change`、`llm/adapter-change`、`system-prompt/change`。)**已被取代**:[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)取代了此门禁及其 `architecture.md` 表格,改为完全生成的 `docs/cordis-catalog/events.md` + `docs/cordis-catalog/services.md` 及其 `verify-cordis-catalog` 新鲜度门禁。本文的其他门禁(`doc-typecheck` 以及下文修订的 `verify-md-wrap`)不受影响。 +1. **`doc-typecheck`** 从 `README.md`、`docs/**` 和 `packages/*/README.md` 中提取所有 ` ```ts ` 围栏代码块,写入一个继承根 `tsconfig.json` 的临时项目,然后用 `tsc -b` 编译。临时项目复用源码的 `paths` 映射和根 project references,因此文档示例能看到源码,而 vendor 代码仍在其自身的 tsconfig 设置下被检查。刻意作为草图的代码块可通过显式的 ` ```ts ignore-check ` 信息字符串来 opt-out;脚本会报告 opt-out 比例,超过一半即失败,防止该豁免机制悄然成为常态。 +2. **`verify-event-taxonomy`** 从 `packages/*/src` 中的 `interface Events` 块和 `docs/architecture.md` 中的分类体系表分别提取事件名称,断言两个集合完全一致。只校验,不生成:表格保留手写的 Mode/Purpose 列,仅检查名称集合。(落地此门禁时发现了表格遗漏的三个事件:`tools/change`、`llm/adapter-change`、`system-prompt/change`。)**已被取代**:由[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)取代。此门禁及其 `architecture.md` 表格已退役,取而代之的是完全生成的 `docs/cordis-catalog/events.md` + `docs/cordis-catalog/services.md` 及其 `verify-cordis-catalog` 新鲜度门禁。本 RFC 中的其他门禁(`doc-typecheck` 以及下文修订中的 `verify-md-wrap`)不受影响。 -两者通过一个共享的 `doc-sync` package.json 脚本运行,lefthook pre-push 钩子和 CI 都调用它([机械质量门禁](2026-06-11-quality-gates.md):钩子和 CI 调用相同的脚本,因此门禁在推送前就在本地触发,而不仅仅在推送后)。它们在 `pnpm run typecheck` 之后运行,后者校验 doc-typecheck 所引用的 package/vendor 构建图。 +两者通过一个共享的 doc-sync(文档同步门禁)`package.json` 脚本运行,lefthook pre-push 钩子和 CI 都调用它([机械质量门禁](2026-06-11-quality-gates.md):钩子与 CI 调用相同脚本,因此门禁在推送前就在本地触发,而非仅在推送后)。它们在 `pnpm run typecheck` 之后运行,后者校验 doc-typecheck 所引用的 package/vendor 构建图。 -**修订(2026-06-17):** 第三道门禁 **`verify-md-wrap`** 后来也被纳入 `doc-sync`。它用 `mdast-util-from-markdown` + GFM 解析范围内的每个 Markdown 文件(`README.md`、`docs/**`、`packages/*/README.md`,加上 `AGENTS.md` / `packages/AGENTS.md`),对任何跨越多行的 `paragraph` 节点报错,强制执行 docs/AGENTS.md 中「一个段落一个物理行」的写作规则。同样遵循只校验不生成的原则:它报告硬换行,从不重写,因此不会引入格式化噪音。`doc-sync` 现在包含三道门禁。 +**修订(2026-06-17):** 第三道门禁 **`verify-md-wrap`** 随后被纳入 `doc-sync`。它使用 `mdast-util-from-markdown` + GFM 解析范围内的每个 Markdown 文件(`README.md`、`docs/**`、`packages/*/README.md`,加上 `AGENTS.md` / `packages/AGENTS.md`),如果任何 `paragraph` 节点跨越多个源码行则失败,从而强制执行 docs/AGENTS.md 中「一个段落一个物理行」的写作规则。同样遵循只校验不生成的原则:它报告硬换行但从不重写,因此不会引入格式化噪音。`doc-sync` 现在包含三道门禁。 ## 曾考虑的替代方案 -- **API-extractor 黄金报告**([已推迟的提案](../../proposed/process/2026-06-11-api-extractor-reports.md)):有意推迟。对于评审者已经能看到源码 diff 的内部 monorepo 而言价值不高,且依赖笨重、配置繁琐。 -- **从源码生成分类体系表**而非校验名称:否决,机制比问题本身更重;表格保留手写的 Mode/Purpose 列,直到[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)完全取代了这项检查。 +- **API-extractor 金标报告**([已推迟的提案](../../proposed/process/2026-06-11-api-extractor-reports.md)):有意推迟。对于评审者已能直接看到源码 diff 的内部 monorepo 而言价值有限,且依赖重、配置繁琐。 +- **从源码生成分类体系表**而非仅校验名称:否决,机制比问题本身更重;表格保留了手写的 Mode/Purpose 列,直到[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)完全取代了这项检查。 ## 后果 -- 可机械检查的文档漂移现在会让 pre-push 钩子和 CI 失败,而非等待评审者发现。这是「机械门禁优于行文约定」原则的一个实例。 -- 让文档代码片段可编译需要少量 stub import 或 `declare`;`ignore-check` 比例必须保持低位,否则门禁形同虚设(比例守卫强制执行这一点)。 -- 分类体系检查仅限名称:Mode 或 Purpose 列的错误仍需人工评审。 -- 如果这些包(package)将来对外发布,API 报告仍可重新考虑。 +- 可检查类别的文档漂移现在会让 pre-push 钩子和 CI 失败,而非等待评审者发现。这是「机械门禁优于行文约定」原则的一个实例。 +- 让文档代码片段可编译需要少量 stub import/`declare`;`ignore-check` 比例必须保持低位,否则门禁形同虚设(比例守卫强制执行此约束)。 +- 分类体系检查仅限名称——Mode 或 Purpose 列的错误仍需人工评审。 +- 如果 package 未来对外发布,API 报告方案仍可重新考虑。 diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml index addb813047..ba5bb828a2 100644 --- a/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-quality-gates.md: 9862dc019dd6ff3b4639983821256395d0ee7b77 -2026-06-11-quality-gates.zh.md: 7a9dd7cead0e7a4964a44b650664ceb7ff570c7b +2026-06-11-quality-gates.zh.md: a9c17bb700db091d21f7930942a8f3bbf55958a0 diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md b/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md index 7a9dd7cead..a9c17bb700 100644 --- a/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md @@ -1,28 +1,28 @@ # RFC:以机械质量门禁取代行文约定 -Status: implemented - [English](2026-06-11-quality-gates.md) | 中文 +Status: implemented + ## 问题 -本代码库主要由 coding agent 开发。相比行文约定,agent 遵守强制门禁的可靠性远高得多;而当劳动由 agent 完成时,「工作量大」不构成成本论据。早期证据:未通过类型检查的测试被提交了(vitest 不做类型检查),只在评审时才被发现。 +本代码库主要由 coding agent(智能体)开发。相比行文约定,agent 遵守强制门禁的可靠性远高得多;而当劳动由 agent 承担时,「工作量大」不构成成本论据。早期证据:未通过类型检查的测试被提交(vitest 不做类型检查),仅在评审中才被发现。 ## 决策 -AGENTS.md 中的每一项承诺都对应一条退出码非零的命令,同时接入 git 钩子和 CI,两者调用相同的 package.json 脚本: +AGENTS.md 中的每一条承诺都对应一个以非零退出码表示失败的命令,通过 git 钩子和 CI 调用同一套 package.json 脚本来执行: -- 最严格的 TypeScript(`noUncheckedIndexedAccess`、`exactOptionalPropertyTypes` 等);示例、测试和脚本通过根目录 no-emit `tsconfig.json` 在 CI 中进行类型检查,而 package/vendor 代码保持在各自 project-reference 边界之后。 -- ESLint strict-type-checked + @stylistic(作为强制执行的项目风格),包括文件内重复逻辑检查;vendor 代码排除在外。 -- jscpd 检测 package 生产 TypeScript 和仓库脚本中的跨文件克隆;窄范围的源码区间例外用于记录有意为之的并行实现。 -- `packages/*/*/src` 的逐文件 100% 覆盖率(v8);不可达的防御性守卫保留 `/* v8 ignore */ ` 并注明理由,而非删除。 -- knip(死代码/依赖)、publint(包正确性)、workspace 约束(workspace 规则:private、cordis peer+dev、统一版本、ESM),以及对构建出的包声明文件进行 NodeNext 消费方类型检查。 -- lefthook pre-commit(lint 暂存文件、类型检查、vendor manifest 守卫)和 pre-push(测试、hygiene);CI 在 Node 22.19/24/26 上运行完整矩阵,外加一个端到端驱动 echo-agent 的演示冒烟测试。 +- 最严格的 TypeScript 配置(`noUncheckedIndexedAccess`、`exactOptionalPropertyTypes` 等);示例、测试和脚本通过根目录的 no-emit `tsconfig.json` 在 CI 中进行类型检查,而 package/vendor 代码保持在各自 project-reference 边界之后。 +- ESLint strict-type-checked + @stylistic(作为强制执行的统一代码风格),包括文件内重复逻辑检查;vendor 代码排除在外。 +- jscpd 检测 package 生产 TypeScript 与仓库脚本中的跨文件克隆;窄范围的源码区间例外用于记录有意为之的并行实现。 +- `packages/*/*/src` 下按文件 100% 覆盖率(v8);不可达的防御性守卫使用 `/* v8 ignore */` 并注明理由,而非删除。 +- knip(死代码/依赖)、publint(包(package)正确性)、workspace 约束(workspace 规则:private、cordis peer+dev、统一版本、ESM),以及对构建出的包声明文件进行 NodeNext 消费方类型检查。 +- lefthook pre-commit(lint 暂存文件、类型检查、vendor manifest(元数据清单)守卫)和 pre-push(测试、hygiene);CI 在 Node 22.19/24/26 上运行完整矩阵,外加一个驱动 echo-agent 端到端的演示冒烟测试。 ## 后果 -- 约定在 agent 更替后仍然存续;违规在本地快速失败。 +- 约定在 agent 更替中得以存续;违规在本地快速失败。 - 门禁本身也是需要维护的代码;配置变更与其他变更一样需要评审。 -- 100% 覆盖率的压力可能催生无断言的测试——变异测试是计划中的对冲手段(见[变异测试提案](../../proposed/testing/2026-06-11-mutation-testing.md))。 +- 100% 覆盖率的压力可能催生无断言的测试——变异测试是计划中的对策(见[变异测试提案](../../proposed/testing/2026-06-11-mutation-testing.md))。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml index d7062a1c20..92dd0f65b6 100644 --- a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-tsdown-over-dumble.md: c16ac691a9452d952303cf73b40693447d25015c -2026-06-11-tsdown-over-dumble.zh.md: 637a15a49bf22a0dd006039dd1ae2d0ea8120424 +2026-06-11-tsdown-over-dumble.zh.md: 5e9dc5242225e4420e1faa6ef19c8e8b9b3fdbcd diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md index 637a15a49b..5e9dc52422 100644 --- a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md @@ -1,30 +1,30 @@ -# RFC:用 tsdown 替代 dumble 进行 JS 打包 - -Status: implemented +# RFC:使用 tsdown 替代 dumble 进行 JS 打包 [English](2026-06-11-tsdown-over-dumble.md) | 中文 +Status: implemented + ## 问题 -初始构建使用 **dumble**——cordiverse 的零配置 esbuild 包装层,上游 Cordis 本身也用它构建——与 vendor 包的约定最大程度对齐(它读取每个 package.json,从 `exports` 字段推断入口和格式)。但 dumble 作为本仓库的承重工具是一个隐患:v0.2.x,每周约 530 次 npm 下载,实质上只有一位维护者,而且由于它没有 workspace 模式,我们不得不通过一个自定义编排脚本(`scripts/build.ts`)来调用它。 +最初的构建使用 **dumble**,即 cordiverse 的零配置 esbuild 包装层——上游 Cordis 自身也用它构建——与 vendor 包(package)的约定最大程度对齐(它读取每个 package.json 并从 `exports` 字段推断入口/格式)。但 dumble 作为本仓库的承重工具存在隐患:v0.2.x,每周约 530 次 npm 下载,实质上只有一位维护者,而且由于它没有 workspace 模式,我们不得不通过自定义编排脚本(`scripts/build.ts`)来调用它。 -目前构建产物只对 `pnpm run build` + publint 有意义(尚无包发布;开发/测试/演示通过 tsx 直接运行未打包的源码),因此切换成本现在最低,一旦包开始发布就只会更高。 +目前构建产物只在 `pnpm run build` + publint 中有意义(尚未发布任何包;开发/测试/演示通过 tsx 直接运行未打包的源码),因此切换成本现在最低,一旦包开始发布就只会更高。 ## 决策 用 **tsdown**(基于 rolldown,每周约 250 万次下载,VoidZero 支持,活跃发布)替代 dumble: -- 根目录 `tsdown.config.ts`,配置 `workspace: ['vendor/*', 'packages/*/*']`(显式 glob 将打包范围限定在 vendor Cordis 和 TypeScript 包树;`workspace: true` 还会发现示例 manifest 和不需要打包的 workspace 成员)。 -- 共享形态:入口 `lib/types/index.js`,`outDir: 'lib'`,ESM,`platform: node`,`target: es2024`,`fixedExtension: false`(对 `"type": "module"` 的包保持 `.js` 扩展名),`dts: false`(声明文件由 tsc -b 负责),`clean: false`(lib/ 同时存放 TSC 的 `lib/types` 中间产物树)。入口最初是 `src/index.ts`;[TSC 优先构建 RFC](2026-06-17-ts-build-config.md) 后来将 tsdown 改为打包 TSC 输出的 JS,使 TypeScript 转换行为来自同一个编译器。 -- vendor/ 中有两个逐包覆盖配置(属于我们的修改,与重新生成的 tsconfig 一样;记录在 vendor/README.md 中):schemastery(通过 `outExtensions` 输出双格式 `.mjs`/`.cjs`)、logger-console(两次单入口 pass,使共享基类内联到每个入口而非生成 hash 命名的 chunk,与上游发布形态一致)。 -- 删除 `scripts/build.ts`;`pnpm run build` = `tsc -b tsconfig.build.json && tsdown`。 +- 根目录 `tsdown.config.ts`,配置 `workspace: ['vendor/*', 'packages/*/*']`(显式 glob 将打包范围限定在 vendor 的 Cordis 与 TypeScript 包目录树内;`workspace: true` 还会发现示例 manifest 和不需要打包的 workspace 成员)。 +- 共享形态:入口 `lib/types/index.js`,`outDir: 'lib'`,ESM,`platform: node`,`target: es2024`,`fixedExtension: false`(为 `"type": "module"` 的包保持 `.js` 扩展名),`dts: false`(声明文件由 tsc -b 负责),`clean: false`(lib/ 同时存放 TSC 的 `lib/types` 中间产物树)。入口最初是 `src/index.ts`;[TSC 优先构建 RFC](2026-06-17-ts-build-config.md) 后来将 tsdown 改为打包 TSC 输出的 JS,使 TypeScript 转换行为统一来自一个编译器。 +- vendor/ 中有两个按包覆盖的配置(属于我们自己的修改,与重新生成的 tsconfig 类似;记录在 vendor/README.md 中):schemastery(通过 `outExtensions` 输出双格式 `.mjs`/`.cjs`)、logger-console(两次单入口 pass,使共享基类被内联到每个入口而非生成哈希命名的 chunk,与上游发布形态一致)。 +- `scripts/build.ts` 删除;`pnpm run build` = `tsc -b tsconfig.build.json && tsdown`。 ## 曾考虑的替代方案 -- **直接编写 esbuild 脚本**:最成熟的引擎,零包装层风险,但需要手动维护 tsdown workspace 模式自动提供的逐包规格表。 -- **pkgroll**:理念上最接近的直接替代品,但每周仅 78k 下载且基于 Rollup:维护前景严格弱于 tsdown。 -- **保留 dumble**:与上游完美对齐,但 bus factor 不可接受。 +- **直接编写 esbuild 脚本**:最成熟的引擎,零包装层风险,但需要手动维护 tsdown workspace 模式自动提供的按包规格表。 +- **pkgroll**:理念上最接近的直接替代品,但每周仅 78k 下载且基于 Rollup,维护前景严格弱于 tsdown。 +- **保留 dumble**:与上游完美对齐,但巴士因子不可接受。 ## 后果 -运行时打包产物仍遵循 dumble 时代的公开入口形态(`lib/index.js`,加上包特有的变体如 `schemastery` 的 `lib/index.mjs`/`lib/index.cjs` 和 `logger-console` 的 `lib/browser.js`);声明文件现在按 [TSC 优先构建 RFC](2026-06-17-ts-build-config.md) 放在 `lib/types` 下。外部依赖仍来自各包的 dependencies/peerDependencies。我们放弃了 dumble 的 exports 字段推断能力:入口形态非默认的新包需要一个逐包的 `tsdown.config.ts`,而不能仅靠 package.json 字段。未来选项:如果 `tsc -b` 成为瓶颈,tsdown 也可以接管声明文件打包(isolatedDeclarations);那将是一个新的 RFC。 +运行时打包产物仍遵循 dumble 时代的公开入口形态(`lib/index.js`,以及按包特定的变体,如 `schemastery` 的 `lib/index.mjs`/`lib/index.cjs` 和 `logger-console` 的 `lib/browser.js`);声明文件现在位于 `lib/types` 下,见 [TSC 优先构建 RFC](2026-06-17-ts-build-config.md)。外部依赖仍来自各包的 dependencies/peerDependencies。我们放弃了 dumble 的 exports 字段推断功能:新增的非默认形态的包需要编写按包的 `tsdown.config.ts`,而不能仅靠 package.json 字段。未来可选方向:如果 `tsc -b` 成为瓶颈,tsdown 还可以接管声明文件打包(isolatedDeclarations);那将是一个新的 RFC。 diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml index baaef0f47c..b71b7d025d 100644 --- a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-vendor-cordis-as-source.md: 39506300dec73d0c9eb1b7b2246caa23f1b10f7f -2026-06-11-vendor-cordis-as-source.zh.md: 1c942291481f50f602d6733e3c25a892885d47fe +2026-06-11-vendor-cordis-as-source.zh.md: 0e794d97c4d535b74279bab11bda519e7da2e366 diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md index 1c94229148..0e794d97c4 100644 --- a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md @@ -1,27 +1,27 @@ -# RFC:以源码形式收录 Cordis,而非 npm 依赖 - -Status: implemented +# RFC:将 Cordis 以源码形式收录,而非作为 npm 依赖 [English](2026-06-11-vendor-cordis-as-source.md) | 中文 +Status: implemented + ## 问题 -DeepSeek Harness SDK 基于 Cordis 框架构建。本仓库启动时,Cordis core 处于 4.0.0-rc.6(一个发布候选版本);harness 依赖框架内部实现(fiber 生命周期、effect dispose(资源释放)、waterfall(瀑布式事件)分发),这些行为的精确语义直接关系到 agent loop(智能体循环)的正确性保证。 +DeepSeek Harness SDK 构建于 Cordis 框架之上。本仓库启动时,Cordis core 处于 4.0.0-rc.6(一个候选发布版本);harness 依赖框架内部实现(fiber 生命周期、dispose(资源释放)、waterfall(瀑布式事件)分发),其确切行为直接关系到 agent loop(智能体循环)的正确性保证。 ## 决策 -将所需的 Cordis 包(core、loader、include、group、timer、hmr、logger-console)及 cordiverse 基础库(cosmokit、schemastery)以源码形式扁平复制到 `vendor/`,保留其原始 npm 包名,使 workspace 解析透明。真正的第三方依赖(js-yaml、chokidar、@standard-schema/spec 等)仍留在 npm。 +将所需的 Cordis 包(core、loader、include、group、timer、hmr、logger-console)与 cordiverse 基础库(cosmokit、schemastery)以源码形式复制到 `vendor/`,扁平化放置,保留其原始 npm 包名以实现透明的 workspace 解析。真正的第三方依赖(js-yaml、chokidar、@standard-schema/spec 等)仍从 npm 获取。 -`vendor/README.md` 是 manifest(元数据清单):记录每个包的上游仓库 + commit SHA,以及一份详尽的本地修改日志。pre-commit 守卫(`scripts/check-vendor-manifest.sh`)会拒绝未在同一次提交中更新 manifest 的 vendor 源码改动。 +`vendor/README.md` 是 manifest(元数据清单):记录每个包(package)的上游仓库 + commit SHA,以及一份详尽的本地修改日志。pre-commit 守卫(`scripts/check-vendor-manifest.sh`)会拒绝未在同一次提交中更新 manifest 的 vendor 源码变更。 ## 曾考虑的替代方案 -- **依赖 npm 包**:否决。core 处于发布候选阶段,且 harness 依赖框架内部实现(fiber 生命周期、effect dispose、waterfall 分发),agent loop 的正确性保证取决于这些行为的精确语义;上游 RC 版本升级可能在没有本地修复路径的情况下破坏它们。 -- **传递性地收录所有依赖**:否决。真正的第三方依赖(js-yaml、chokidar、@standard-schema/spec 等)仍留在 npm;只有内部实现对我们有影响的框架层才被纳入自有管理。 +- **依赖 npm 包**:否决。core 处于候选发布阶段,harness 依赖框架内部实现(fiber 生命周期、dispose、waterfall 分发),agent loop 的正确性保证取决于这些行为的确切表现;上游 RC 版本升级可能在没有本地修复路径的情况下破坏它们。 +- **递归收录所有传递依赖**:否决。真正的第三方依赖(js-yaml、chokidar、@standard-schema/spec 等)仍从 npm 获取;只有内部实现对我们有影响的框架层才需要自行持有。 ## 后果 -- harness 完全拥有其框架层:可审计、可打补丁、版本锁定。上游 RC 无法破坏我们,框架 bug 可以在仓库内直接修复。 -- 上游同步是手动的(manifest 中记录了操作步骤)。修改日志使 diff 面始终可知。 -- vendor 包保留上游代码风格;lint 与严格性门禁将其排除(它们的 tsconfig 在本地放宽了我们较新的编译器 flag)。 -- 从第一天起就存在一个本地补丁:移除了 HMR 的 locale-YAML 导入(运行时 YAML 导入钩子未被收录)。 +- harness 完全持有其框架层:可审计、可打补丁、版本锁定。上游 RC 无法影响我们,框架 bug 可以在仓库内直接修复。 +- 上游同步是手动操作(流程记录在 manifest 中)。修改日志使 diff 范围始终可知。 +- 收录的包保留上游代码风格;lint 与严格性门禁将其排除(它们的 tsconfig 在本地放宽了我们较新的编译器选项)。 +- 从第一天起就有一个本地补丁:移除了 hmr 的 locale-YAML 导入(运行时 YAML 导入钩子未被收录)。 diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml index c2b598e0db..ec328ff0e0 100644 --- a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-16-pnpm-over-yarn.md: 6e7a6e1f53056e36f54f44b87b305afa593da549 -2026-06-16-pnpm-over-yarn.zh.md: 809f10dbd63d347eccb4d00641a39da51788ee9f +2026-06-16-pnpm-over-yarn.zh.md: ba63575909f2bafbbad2102c85d6bede77999997 diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md index 809f10dbd6..ba63575909 100644 --- a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md @@ -1,43 +1,43 @@ -# RFC:以 pnpm 替代 Yarn 4 作为包管理器 - -Status: implemented +# RFC:使用 pnpm 替代 Yarn 4 作为包管理器 [English](2026-06-16-pnpm-over-yarn.md) | 中文 +Status: implemented + ## 问题 -本仓库最初使用 **Yarn 4** 搭配 `node-modules` linker 发布——这是一个刻意保守的选择:行为类似 npm 的扁平布局,同时提供 Yarn 的 workspace 和 `yarn constraints`。它能用。但 Yarn 4 的 Plug'n'Play 血统使得 `node-modules` linker 成为非主流模式,而更广泛的 JS 生态——工具默认值、CI action、Corepack 示例、贡献者熟悉度——正日益以 pnpm 为中心。对于一个主要由 agent 构建、偶尔有人类贡献者阅读的仓库来说,「大多数工具和人所预期的包管理器」具有实际价值:更少的意外、更成熟的故障路径、更多可直接复用的答案。 +本仓库最初使用 **Yarn 4** 搭配 `node-modules` 链接器启动。这是一个刻意保守的选择:行为类似 npm 的扁平布局,同时享有 Yarn 的 workspaces 和 `yarn constraints`。它能正常工作。但 Yarn 4 源自 Plug'n'Play 的血统,使得 `node-modules` 链接器成为非主流模式;而更广泛的 JS 生态——工具默认值、CI action、Corepack 示例、贡献者的熟悉度——正日益以 pnpm 为中心。对于一个主要由 agent(智能体)构建、偶尔有人类贡献者阅读的仓库而言,「大多数工具和人所期望的包管理器」具有实际价值:更少的意外、更成熟的故障路径、更多可直接复用的解答。 -切换成本目前处于最低点。本仓库尚无任何包发布(所有 package 均为 `private: true`);开发/测试/演示全部通过 tsx **未构建**运行,因此包管理器只需做到 (a) 解析并链接 `node_modules`,(b) 运行 workspace 脚本,(c) 强制执行 workspace 约束。唯一的 Yarn 专属资产是 `yarn.config.cjs`(`@yarnpkg/types` 约束引擎),体量小且可机械地重新表达。这与 [tsdown 决策](2026-06-11-tsdown-over-dumble.md)的逻辑一致:趁爆炸半径还小,把承重工具换成生态更健康的选项。 +切换成本目前处于最低点。本仓库尚无任何包(package)发布(每个包都是 `private: true`);开发/测试/演示全部通过 tsx **未构建**运行,因此包管理器只需做到:(a) 解析并链接 `node_modules`,(b) 运行 workspace 脚本,(c) 强制执行 workspace 约束。唯一的 Yarn 特有资产是 `yarn.config.cjs`(`@yarnpkg/types` 约束引擎),体量小且可机械地重新表达。这与 [tsdown 决策](2026-06-11-tsdown-over-dumble.md)的逻辑一致:在爆炸半径尚小时,将承重工具换为生态更健康的选项。 ## 决策 -采用 **pnpm 11.7.0**,通过 `packageManager` 字段固定、经 Corepack 安装(与 Yarn 使用的机制相同): +采用 **pnpm 11.7.0**,通过 `packageManager` 字段固定版本,经 Corepack 安装(与 Yarn 使用的机制相同): -- **Workspace** 从 `package.json` 的 `workspaces` 数组加 `.yarnrc.yml` 迁移到 `pnpm-workspace.yaml`(`vendor/*`、`packages/*`——相同的 glob;`examples/*` 保持非 workspace,与先前设置及 tsdown 的显式 glob 一致)。 -- **严格符号链接 linker**(pnpm 默认)取代 Yarn 的 hoisted `node-modules` linker。我们刻意**不**添加 `node-linker=hoisted` / `shamefully-hoist` 逃生口:pnpm 的非扁平 `node_modules` 会让幽灵依赖(引用未声明的传递依赖)大声失败,这对一个以机械门禁为整体质量策略的仓库而言是一个*优点*(见[机械质量门禁](2026-06-11-quality-gates.md))。门禁套件——类型检查、lint、测试、构建、knip——是安全网,证明不存在此类幽灵引用。 -- **构建脚本白名单。** pnpm 10+ 不运行依赖的生命周期脚本,除非显式列入白名单。`pnpm-workspace.yaml` 携带一份显式的 `allowBuilds` 映射(`esbuild`、`lefthook`、`@google/genai`、`protobufjs`)——与本仓库对模型/工具输出已有的供应链加固姿态一致,现在将其扩展到安装时的代码执行。`peerDependencyRules.allowedVersions.typescript: '>=5 <7'` 消除仓库内 TypeScript 的良性 peer 范围警告。 -- **约束变为包管理器无关。** `yarn.config.cjs`(导入 `@yarnpkg/types`、使用 `Yarn.workspaces()` / `workspace.set()`)被 `scripts/check-workspace-constraints.ts` 取代——一个纯 tsx 脚本,以 `pnpm run constraints` 运行。它在相同的 `vendor` + `packages` 范围上强制执行完全相同的不变式:所有 package `private: true`;`@deepseek-ai/dsh-*` 包将 `cordis` 同时声明为对等依赖(peer dependency)和 dev 依赖且范围匹配、使用根 `package.json` 的版本、设置 `type: module`;vendor 包仅检查 privacy。 -- 所有 CI、lefthook 钩子、`package.json` 脚本和文档中的 `yarn …` 动词统一改为 `pnpm …` / `pnpm run …`。`yarn.lock` → `pnpm-lock.yaml`(lockfile v9)。`.gitignore` 将 `.yarn/` 换为 `.pnpm-store/`。vendor README(如 `vendor/cordis/README.md`)按 Vendoring Policy 保留其上游的 `yarn` 示例不动。 +- **Workspaces** 从 `package.json` 的 `workspaces` 数组 + `.yarnrc.yml` 迁移到 `pnpm-workspace.yaml`(`vendor/*`、`packages/*`——同样的 glob;`examples/*` 保持非 workspace,与先前设置及 tsdown 的显式 glob 一致)。 +- **严格符号链接链接器**(pnpm 默认)取代 Yarn 的提升式 `node-modules` 链接器。我们刻意**不**添加 `node-linker=hoisted` / `shamefully-hoist` 逃生口:pnpm 的非扁平 `node_modules` 会让幻影依赖(引用未声明的传递依赖)大声失败,这对于一个以机械门禁为核心质量保障的仓库(见[机械质量门禁](2026-06-11-quality-gates.md))是一项*优势*。门禁套件(typecheck、lint、test、build、knip)是证明不存在此类幻影导入的安全网。 +- **构建脚本白名单。** pnpm 10+ 不运行依赖的生命周期脚本,除非将其加入白名单。`pnpm-workspace.yaml` 携带一份显式的 `allowBuilds` 映射(`esbuild`、`lefthook`、`@google/genai`、`protobufjs`)——与本仓库对模型/工具输出已有的供应链加固姿态一致,现在也应用于安装时的代码执行。`peerDependencyRules.allowedVersions.typescript: '>=5 <7'` 消除仓库内 TypeScript 的良性 peer 范围警告。 +- **约束变为包管理器无关。** `yarn.config.cjs`(导入 `@yarnpkg/types`,使用 `Yarn.workspaces()` / `workspace.set()`)被 `scripts/check-workspace-constraints.ts` 取代——一个纯 tsx 脚本,通过 `pnpm run constraints` 运行。它在相同的 `vendor` + `packages` 范围上强制执行完全相同的不变式:每个包 `private: true`;`@deepseek-ai/dsh-*` 包将 `cordis` 同时声明为对等依赖(peer dependency)和 dev 依赖且范围一致、使用根 `package.json` 的版本、设置 `type: module`;vendor 包仅检查 privacy。 +- 所有 CI、lefthook 钩子、`package.json` 脚本和文档中的 `yarn …` 动词变为 `pnpm …` / `pnpm run …`。`yarn.lock` → `pnpm-lock.yaml`(lockfile v9)。`.gitignore` 将 `.yarn/` 换为 `.pnpm-store/`。vendor README(如 `vendor/cordis/README.md`)按 Vendoring Policy 保持其上游 `yarn` 示例不变。 ## 曾考虑的替代方案 -- **保留 Yarn 4**:零变动,但押注于使用者更少的 linker 模式和绑定单一包管理器的约束引擎。 -- **npm workspaces**:无处不在,但没有约束机制,monorepo 人体工学也更弱。 -- **pnpm 搭配 hoisted linker**:迁移更平滑,但放弃了幽灵依赖安全性——而这正是迁移的首要正确性理由。 +- **保留 Yarn 4**——零变动,但押注于使用率较低的链接器模式和一个绑定单一包管理器的约束引擎。 +- **npm workspaces**——无处不在,但没有约束方案,monorepo 人体工学也较弱。 +- **pnpm 搭配提升式链接器**——迁移更平滑,但放弃了幻影依赖安全性,而这正是迁移的核心正确性理由。 ## 后果 -约束检查失去了 Yarn 的自动**修复**能力(`workspace.set()` 可以就地改写 manifest);tsx 脚本仅做检查,不通过时以非零退出码加消息退出。这是可接受的:CI 从未运行过 `--fix`,且需要手动改一行的情况很少。贡献者现在为 pnpm 而非 Yarn 运行 `corepack enable`;`pnpm exec lefthook install` 取代 `yarn lefthook install`(`postinstall` 钩子仍会运行 `lefthook install`)。 +约束检查失去了 Yarn 的自动**修复**能力(`workspace.set()` 能原地改写 manifest);tsx 脚本仅做检查,不通过时以非零退出码和消息退出。这是可接受的:CI 从未运行过 `--fix`,且需要手动编辑的情况很少。贡献者现在为 pnpm 而非 Yarn 运行 `corepack enable`;`pnpm exec lefthook install` 取代 `yarn lefthook install`(`postinstall` 钩子仍会运行 `lefthook install`)。 性能(迁移时在开发 NFS 文件系统上测量;单次运行样本,方差大——仅供方向性参考,非基准测试套件): | 场景 | Yarn 4 | pnpm 11 | |---|---|---| -| Cold (empty cache/store, no `node_modules`) | ~14 s | ~16 s | -| Warm relink (cache/store warm, `node_modules` removed) | ~12–14 s | ~15–22 s | -| Frozen, `node_modules` present (no-op revalidate) | ~2–8 s | ~0.5–7 s | +| 冷启动(空缓存/store,无 `node_modules`) | ~14 s | ~16 s | +| 热重链接(缓存/store 已热,`node_modules` 已删除) | ~12–14 s | ~15–22 s | +| 冻结,`node_modules` 存在(无操作重验证) | ~2–8 s | ~0.5–7 s | -在快速本地磁盘上,pnpm 的内容寻址 store 通常在冷/热安装上胜出,尤其在多次 checkout 的**磁盘占用**上优势明显(一个全局 store 通过硬链接进入每个 `node_modules`,而 Yarn 每个 worktree 复制约 279 MB——部分开发者日常保持约 10 个或更多 worktree)。这一去重优势在上述迁移时数据中**未**体现,因为测试 store 和 `node_modules` 位于不同文件系统,硬链接失效;在单文件系统的开发机或 CI 缓存上该优势成立。诚实的总结:在我们的 NFS 开发文件系统上,安装速度在噪声范围内不分伯仲;迁移的理由是生态对齐、幽灵依赖安全性和跨 checkout 磁盘去重——而非原始安装时间的胜出。 +在快速本地磁盘上,pnpm 的内容寻址 store 通常在冷/热安装中胜出,尤其在多个检出之间的**磁盘占用**方面优势明显(一个全局 store 通过硬链接接入每个 `node_modules`,而 Yarn 每个 worktree 复制约 279 MB——部分开发者经常为本仓库保持约 10 个或更多 worktree)。该去重优势在上述迁移时数据中**未能**体现,因为测试 store 和 `node_modules` 位于不同文件系统,硬链接失效;在单文件系统的开发机或 CI 缓存上则适用。诚实的总结:在我们的 NFS 开发文件系统上,安装速度在噪声范围内不分伯仲;迁移的理由是生态对齐、幻影依赖安全性和跨检出磁盘去重,而非原始安装时间的胜出。 -所有质量门禁(约束、类型检查、lint、doc-sync、100% test:coverage、构建、knip、publint、echo-agent 演示冒烟测试)在 pnpm 上原样通过,这是 linker 切换未引入幽灵依赖破坏的正确性证明。 +所有质量门禁(constraints、typecheck、lint、doc-sync、test:coverage 100%、build、knip、publint、echo-agent 演示冒烟测试)在 pnpm 上原样通过,这是链接器切换未引入幻影依赖破坏的正确性证明。 diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml b/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml index 9858ce0f2e..92e8c81d4b 100644 --- a/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-17-ts-build-config.md: cf70014b5873f74da8476c21dd71feedb956f59f -2026-06-17-ts-build-config.zh.md: f70619de5a48c7040e816c54d21f81772a51a90f +2026-06-17-ts-build-config.zh.md: d3dd0fb13edd22f1ae365286cbf8144fa0bc3f69 diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md b/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md index f70619de5a..d3dd0fb13e 100644 --- a/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md @@ -1,47 +1,46 @@ -# RFC:以 TSC 为核心的构建与统一 tsconfig - -Status: implemented +# RFC:TSC 优先的构建与单一 tsconfig [English](2026-06-17-ts-build-config.md) | 中文 +Status: implemented + ## 问题 -当时的 TypeScript 构建与类型检查配置存在以下问题: +此前的 TypeScript 构建与类型检查配置存在以下问题: -- `build` 使用 `tsc` 将 `packages/<group>/<pkg>` 和 `vendor/*` 下的 `.ts` 转换为 `.d.ts`,再用 `tsdown` 将 `.ts` 转换为打包后的 `.js`。这导致两个工具各自做一次 TypeScript 转换。 -- `typecheck` 倾向于通过一个根级 typecheck 配置来校验 package、vendor 源码、示例、测试和脚本。 +- `build` 使用 `tsc` 将 `packages/<group>/<pkg>` 和 `vendor/*` 下的 `.ts` 转换为 `.d.ts` 文件,然后使用 `tsdown` 将 `.ts` 转换为打包后的 `.js` 文件。这导致两个工具各自执行 TypeScript 转换。 +- `typecheck` 倾向于通过一个根目录的 typecheck 配置来校验 package、vendor 源码、示例、测试和脚本。 -目标是让 build 和 typecheck 使用一致的 tsconfig 边界与 TypeScript 解析/转换行为。build 应通过同一个编译器和配置生成 `.js`、`.d.ts`、`.js.map` 和 `.d.ts.map`,使发布产物与类型校验保持一致。 +目标是让构建与类型检查使用一致的 tsconfig 边界和 TypeScript 解析/转换行为。构建应通过单一编译器和配置生成 `.js`、`.d.ts`、`.js.map` 和 `.d.ts.map`,使发布产物与类型校验保持一致。 -验证过程中发现了若干具体技术问题和可能的路径: +验证过程中发现了若干具体的技术问题和可能的路径: -- `tsdown` 使用 `oxc` 做 TypeScript 转换,其行为与 `tsc` 不同。 +- `tsdown` 使用 `oxc` 进行 TypeScript 转换,其行为与 `tsc` 不同。 - `tsdown` 输出的打包 `.d.ts` 与 Cordis 内部的相对模块增强(module augmentation)结构冲突。 - - tsc 的输出受 `allowImportingTsExtensions` 影响,因此需要确保生成的 `.js` 不会 import `.ts` 文件,且生成的 `.d.ts` 保留 NodeNext/Node16 可接受的显式相对说明符。为此,包内相对导入在 TypeScript 源码中使用显式 `.ts` 说明符,由 `rewriteRelativeImportExtensions` 在输出的 JS 中将其改写为 `.js`。 - - `tsdown` 输出的打包 `.js` 与 `tsc -b` 逐文件输出的 `.js` 行为不同,例如 decorator 转换行为。 -- `vendor/*/src`、示例、测试和脚本无法全部以 plain-include 方式放入一个根级严格程序。 - - 在根级严格配置下直接对 `vendor/*/src` 做类型检查,会触发大量不属于本项目的类型错误。 - - `packages/*/*` 对 `vendor` 的依赖解析到 `vendor/*/lib`,以适应不同的 tsconfig 严格度。 - + - `tsc` 的输出受 `allowImportingTsExtensions` 影响,因此需要确保生成的 `.js` 文件不会导入 `.ts` 文件,且生成的 `.d.ts` 文件保留 NodeNext/Node16 接受的显式相对说明符。为此,包内相对导入在 TypeScript 源码中使用显式 `.ts` 说明符,由 `rewriteRelativeImportExtensions` 在输出的 JS 中将其重写为 `.js`。 + - `tsdown` 输出的打包 `.js` 与 `tsc -b` 逐文件输出的 `.js` 行为不同,例如装饰器转换行为。 +- `vendor/*/src`、示例、测试和脚本无法全部以 plain-include 方式纳入一个根目录的严格程序。 + - 在根目录严格配置下直接对 `vendor/*/src` 做类型检查,会触发大量不属于本项目所有权范围的类型错误。 + - `packages/*/*` 对 `vendor` 的包依赖解析到 `vendor/*/lib`,以适应不同的 tsconfig 严格度。 ## 决策 包内相对导入使用显式 `.ts` 说明符。 -`pnpm run build` 分两阶段: +`pnpm run build` 是两阶段构建: -- 阶段 1:`tsc -b tsconfig.build.json` 将逐模块的 `.js`、声明文件 `.d.ts`、JS sourcemap `.js.map` 和声明 sourcemap `.d.ts.map` 输出到各包的 `lib/types`。这是权威的 TypeScript 编译结果。发布时保留 `.d.ts` / `.d.ts.map`,忽略 `.js` / `.js.map`。 - - 构建项目使用 `tsc -b` 编译的 project-reference 图。例如,根 `tsconfig.build.json` 引用包和 vendor 的 tsconfig,校验并输出包/vendor 的构建结果。 -- 阶段 2:bundler 读取 `lib/types` 下输出的 JS,将打包后的运行时入口写为 `lib/index.js` 或 `lib/index.mjs`(沿用当前行为)。此阶段仅做打包,不得读取 TypeScript 源码,也不得输出声明文件。 +- 阶段 1:`tsc -b tsconfig.build.json` 将逐模块的 `.js`、声明文件 `.d.ts`、JS sourcemap `.js.map` 和声明 sourcemap `.d.ts.map` 输出到各 package 的 `lib/types`。这是权威的 TypeScript 编译结果。发布时保留 `.d.ts` / `.d.ts.map`,忽略 `.js` / `.js.map`。 + - 构建项目使用 `tsc -b` 编译的 project-reference 图。例如,根 `tsconfig.build.json` 引用 package 和 vendor 的 tsconfig,校验并输出 package/vendor 的构建结果。 +- 阶段 2:打包器读取 `lib/types` 下输出的 JS,将打包后的运行时入口写为 `lib/index.js` 或 `lib/index.mjs`(沿用当前行为)。此阶段仅做打包,禁止读取 TypeScript 源码或输出声明文件。 `tsdown` 不再负责 TypeScript 编译或声明文件输出。 `pnpm run typecheck` 以 build 模式运行根 `tsconfig.json`。 -- 根 `tsconfig.json` 是唯一的开发/类型检查项目。它以 `noEmit` 检查示例、测试和脚本,并通过 references 校验包/vendor 源码。 -- 被引用的包/vendor 项目保持与 build 相同的输出行为,因此 typecheck 可以刷新它们的 `lib/types` 产物,而无需使用单独的 no-emit 图。项目特有的严格度设置放在各自的 `packages/*/*/tsconfig.json` 或 `vendor/*/tsconfig.json` 中。 -- 根 no-emit 项目禁用 `rewriteRelativeImportExtensions`;它不输出任何文件,且包含跨 project-reference 边界导入 helper 的测试。包/vendor 的输出项目保持该改写启用。 +- 根 `tsconfig.json` 是唯一的开发/类型检查项目。它以 `noEmit` 方式检查示例、测试和脚本,并通过 references 校验 package/vendor 源码。 +- 被引用的 package/vendor 项目保持与 build 相同的输出行为,因此 typecheck 可以刷新它们的 `lib/types` 输出,而无需使用独立的 no-emit 图。项目特定的严格度变更放在各自的 `packages/*/*/tsconfig.json` 或 `vendor/*/tsconfig.json` 中。 +- 根 no-emit 项目禁用 `rewriteRelativeImportExtensions`;它不输出任何文件,且包含跨 project-reference 边界导入 helper 的测试。package/vendor 的 emit 项目保持重写开启。 -命令编排如下: +命令编排结构如下: ```sh pnpm run build: @@ -59,20 +58,20 @@ tsc -b tsconfig.json ## 曾考虑的替代方案 -- **继续使用 `tsdown`/oxc 作为 TypeScript 转换器**:oxc 的转换行为与 `tsc` 不同(decorator 转换有差异、打包 JS 与逐文件输出不同),且其打包 `.d.ts` 与 Cordis 内部的相对模块增强结构冲突。 -- **一个根级严格程序覆盖包、vendor、示例、测试和脚本**:vendor 源码在根级严格 flag 下会触发不属于本项目的类型错误;带有各项目独立严格度的 project references 才是可行的边界。 +- **继续使用 `tsdown`/oxc 作为 TypeScript 转换器**:oxc 的转换行为与 `tsc` 不同(装饰器转换有差异、打包 JS 与逐文件输出不同),且其打包 `.d.ts` 与 Cordis 内部的相对模块增强结构冲突。 +- **用一个根目录严格程序覆盖 package、vendor、示例、测试和脚本**:vendor 源码在根目录严格标志下会触发不属于本项目所有权范围的类型错误;带有逐项目严格度的 project references 才是可行的边界。 ## 后果 构建职责更加清晰: -- `packages/<group>/<pkg>` 和 `vendor/*` 下的每个模块都有一个本地 tsconfig,同时服务于 build、typecheck 以及直接运行源码的工具(如 `tsx` 和 `vitest`)。 -- `build` 命令使用 `tsconfig.build.json`。`tsc -b` 负责可发布的逐模块 `.js` 和 `.d.ts` 输出,bundler 只负责 `lib/index.*`。 - - `lib/types/*.d.ts` 和 `.d.ts.map` 是发布用的声明文件产物。 +- `packages/<group>/<pkg>` 和 `vendor/*` 下的每个模块有一份本地 tsconfig,同时服务于构建、类型检查和直接运行源码的工具(如 `tsx` 和 `vitest`)。 +- `build` 命令使用 `tsconfig.build.json`。`tsc -b` 负责可发布的逐模块 `.js` 和 `.d.ts` 输出,打包器仅负责 `lib/index.*`。 + - `lib/types/*.d.ts` 和 `.d.ts.map` 是发布用的声明输出。 - `lib/types/*.d.ts` 使用显式 `.ts` 相对说明符,TypeScript 的 NodeNext/Node16 解析器会将其映射到同级的 `.d.ts` 文件。 - - `lib/types/*.js` 仅作为 bundler 输入,不得用作运行时入口或公开导入目标。 - - `lib/index.*` 是发布用的运行时产物,由 bundler(当前为 `tsdown`)生成。 -- `pnpm run verify-node-next-types` 扫描构建出的声明文件,检查是否存在缺少文件扩展名的相对说明符,然后以 `moduleResolution: "NodeNext"` 对构建出的 `types`/`exports` 表面进行临时外部 ESM 消费方的类型检查,使声明说明符的回归在发布前即被捕获。 -- `typecheck` 命令使用 `tsconfig.json`。示例、测试和脚本由根 no-emit 项目检查,包和 vendor 模块保持与 `build` 相同的输出行为。包和 vendor 源码始终处于 project-reference 边界之后。 + - `lib/types/*.js` 仅作为打包器输入,禁止用作运行时入口或公开导入目标。 + - `lib/index.*` 是发布用的运行时输出,由打包器(当前为 `tsdown`)生成。 +- `pnpm run verify-node-next-types` 扫描构建出的声明文件,检查是否存在缺少文件扩展名的相对说明符,然后以 `moduleResolution: "NodeNext"` 对构建出的 `types`/`exports` 接口进行临时外部 ESM 消费方的类型检查,确保声明说明符的回归在发布前被捕获。 +- `typecheck` 命令使用 `tsconfig.json`。示例、测试和脚本由根 no-emit 项目检查,package 和 vendor 模块保持与 `build` 相同的输出行为。package 和 vendor 源码始终处于 project-reference 边界之后。 -Cordis vendor 副本现在与上游多了一处类型结构差异。上游同步时,必须重新应用该差异或明确将其退役。 +Cordis 的 vendor 副本现在与上游多了一处类型结构差异。在上游同步时,该差异必须被重新应用或明确废弃。 diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml index 3773aca2f5..2b7b62f141 100644 --- a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-18-markdown-cross-link-lint.md: c802b4071abf652824647e4417cde3f518776353 -2026-06-18-markdown-cross-link-lint.zh.md: abbb5930acb18287effc7c47009b9e3e910f6c89 +2026-06-18-markdown-cross-link-lint.zh.md: 917580ffce71258896f3d23ef7efef4be0176949 diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md index abbb5930ac..917580ffce 100644 --- a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md @@ -1,33 +1,33 @@ -# RFC:Markdown 交叉链接有效性 lint - -Status: implemented +# RFC:Markdown 交叉链接有效性检查 [English](2026-06-18-markdown-cross-link-lint.md) | 中文 +Status: implemented + ## 问题 -本仓库的文档通过相对路径互相链接:`[topic](../implemented/2026-…-….md)`、`[the cookbook](adding-a-tool.md)`、`[architecture.md](../../architecture.md)`。此前没有任何机制验证这些目标是否存在。一次重命名或移动会悄无声息地打断所有入站链接,直到读者点击时才会发现。[Doc-sync 强制](2026-06-11-doc-sync-enforcement.md)已经将两类文档漂移机械化了(不可编译的代码块、陈旧的事件分类体系表),[verify-md-wrap](2026-06-11-doc-sync-enforcement.md) 处理了第三类(硬换行的行文段落),但死链接是第四类同样可机械检查的问题,此前仍靠肉眼验证。 +本仓库的文档通过相对路径互相链接:`[topic](../implemented/2026-…-….md)`、`[the cookbook](adding-a-tool.md)`、`[architecture.md](../../architecture.md)`。此前没有任何机制验证这些目标是否存在。重命名或移动文件会静默破坏所有指向它的链接,且在读者点击之前不可见。[Doc-sync 强制](2026-06-11-doc-sync-enforcement.md)已经将两类文档漂移机械化(无法编译的代码块、陈旧的事件分类表),[verify-md-wrap](2026-06-11-doc-sync-enforcement.md) 覆盖了第三类(硬换行的段落),但死链是第四类同样可机械检查、却仍靠肉眼验证的问题。 -直接触发本门禁的案例是引入它的那次 RFC 目录重组:将 `docs/adr/` + `docs/rfc/` 统一为一个 `docs/rfc/`,下设 `proposed/`、`implemented/`、`rejected/` 子目录,手动改写了约四十条文档间链接。任何一条路径的手误都会让断链随代码一起合入,而没有任何东西能拦住它。 +触发本门禁的直接案例是引入它的那次 RFC 目录重组:将 `docs/adr/` + `docs/rfc/` 统一为一个 `docs/rfc/`,下设 `proposed/`/`implemented/`/`rejected/` 子目录,手动改写了约四十条文档间链接。任何一个手误路径都会让一条死链随代码入库,而没有任何东西能拦住它。 ## 决策 新增第四道 `doc-sync` 门禁 `verify-md-links`(`scripts/verify-md-links.ts`),风格与 `verify-md-wrap` 一致(tsx ESM、基于 AST、只验证不生成): -- 用 `mdast-util-from-markdown` + GFM 解析范围内的每个 Markdown 文件,遍历所有 `link`、`image` 和 `definition` 节点。 -- 仅当目标是**相对路径**时才检查。跳过带协议的 URL(`https:`、`mailto:` 等)、协议相对路径(`//host`)、根绝对路径(`/path`——在 checkout 中没有稳定基准)以及纯页内锚点(`#section`)。去除 `#fragment`/`?query`,相对于链接所在文件的目录解析路径,并断言该路径在磁盘上存在。 -- 只报告,不改写;发现第一条断链即以非零状态退出。 +- 使用 `mdast-util-from-markdown` + GFM 解析每个范围内的 Markdown 文件,遍历所有 `link`、`image` 和 `definition` 节点。 +- 仅当目标是**相对路径**时才检查。跳过带协议的 URL(`https:`、`mailto:` 等)、协议相对路径(`//host`)、根绝对路径(`/path`,在检出目录中没有稳定基准)以及纯页内锚点(`#section`)。剥除 `#fragment`/`?query`,相对于链接所在文件的目录解析路径,并断言目标在磁盘上存在。 +- 只报告、不改写;发现第一条死链即以非零状态退出。 -范围与其他门禁一致,另加 AGENTS.md 对和 `.agents/skills/` 下仓库自有的 agent skill Markdown(这些 skill 文件交叉链接到 docs 目录树,因此本次重组也改写了其中的链接):`README.md`、`docs/**/*.md`、`packages/*/README.md`、`AGENTS.md`、`packages/AGENTS.md`、`.agents/skills/**/*.md`,按真实路径去重(`CLAUDE.md` 符号链接解析到 AGENTS.md 文件)。该门禁接入 lefthook pre-push 钩子和 CI 都会运行的 `doc-sync` 脚本,因此断链在推送前就会在本地失败——与[机械质量门禁](2026-06-11-quality-gates.md)保持一致。 +范围与其他门禁一致,另外加上 AGENTS.md 对和 `.agents/skills/` 下仓库自有的 agent skill Markdown(这些 skill 文件交叉链接到 docs 目录,因此本次重组也改写了其中的链接):`README.md`、`docs/**/*.md`、`packages/*/README.md`、`AGENTS.md`、`packages/AGENTS.md`、`.agents/skills/**/*.md`,按真实路径去重(`CLAUDE.md` 符号链接解析到 AGENTS.md 文件)。它接入 lefthook pre-push 钩子和 CI 都会运行的 `doc-sync` 脚本,因此死链在推送前就会在本地失败——与[机械化质量门禁](2026-06-11-quality-gates.md)一致。 -本门禁检查的是**文件存在性**,而非锚点有效性:链接到一个真实文件但带有 `#wrong-heading` 片段的仍然通过(文件可解析;片段被剥离)。 +本门禁检查的是**文件存在性**,而非锚点有效性:指向一个真实文件但带有 `#wrong-heading` 片段的链接仍会通过(文件可解析;片段被剥除)。 ## 曾考虑的替代方案 -**锚点级有效性检查**:更重且价值更低;实际造成问题的是文件级死链接。这一范围裁剪是有意为之:作者在链接到某个锚点时自行验证 `#fragment`。 +**锚点级有效性检查**:更重且价值更低;实际造成问题的是文件级死链。这一范围裁剪是有意为之:作者在链接到某个锚点时自行验证 `#fragment`。 ## 后果 -- 重命名或移动导致交叉链接悬空时,pre-push 钩子和 CI 会立即失败,而不是等读者点击死链接才发现。这使得引入本门禁的 RFC 重组具有自验证性:同一个 PR 既改写了四十条链接,也加入了证明无一悬空的检查。 -- `doc-sync` 链中多了一个快速 tsx 脚本;无新增依赖(mdast/GFM 技术栈已在 devDependencies 中供 `verify-md-wrap` 使用)。 -- 本门禁强制的约定——通过可机械检查的相对链接交叉引用文档,而非裸文字或编号——记录在 [docs/AGENTS.md](../../../AGENTS.md) 中,让作者知道这道门禁的存在及其原因。 +- 重命名或移动文件导致交叉链接悬空时,现在会在 pre-push 钩子和 CI 中失败,而不是等读者点击死链才发现。这使得引入本门禁的 RFC 重组具备自验证能力:改写四十条链接的同一个 PR 也添加了证明无一悬空的检查。 +- `doc-sync` 链中多了一个快速 tsx 脚本;无新增依赖(mdast/GFM 技术栈已作为 `verify-md-wrap` 的 devDependencies 存在)。 +- 本门禁强制的约定——通过可机械检查的相对链接引用文档,而非裸文本或编号——记录在 [docs/AGENTS.md](../../../AGENTS.md) 中,让作者知晓门禁的存在与原因。 diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml index 2421ac85fc..4345634014 100644 --- a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-core-data-structures-catalog.md: 5f1232f2f0d0644d4043af217a7177451155030b -2026-06-20-core-data-structures-catalog.zh.md: d35a4d9d32eb59971bbf8b105d01dd38c0811fb0 +2026-06-20-core-data-structures-catalog.zh.md: 8ad4453890d8be5dc4e743d1f6f9aa6a9330ed17 diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md index d35a4d9d32..8ad4453890 100644 --- a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md @@ -6,55 +6,55 @@ Status: implemented ## 问题 -想要理解 harness 的读者可以在 [architecture.md](../../../architecture.md) 中找到它的*行为*(服务映射、会话/轮次/步骤生命周期、事件分类体系),但没有一个集中的地方描述它的*词汇*——那些行为所操作的数据结构。类型定义只存在于源码中,散落在各个 `packages/*/src/types.ts` 里,因此要理解「什么是 `Message`、`SessionEvent`、`StreamChunk`」就意味着直接阅读声明。一份行文目录会有帮助,但如果目录是对类型定义的转述或粘贴复制,那么字段一改它就会腐烂——而一份失去同步的类型文档比没有更糟,因为读者会信任它。 +一位想要理解 harness 的读者,可以在 [architecture.md](../../../architecture.md) 中找到它的*行为*(服务映射、session/turn/step 生命周期、事件分类体系),但没有一个集中的地方描述它的*词汇*——即行为所操作的数据结构。类型形状只存在于源码中,分散在各个 `packages/*/src/types.ts` 里,因此要理解「什么是 `Message`、`SessionEvent`、`StreamChunk`」就得直接阅读声明。一份行文目录会有帮助,但如果目录是对类型定义的转述或粘贴复制,那么字段一改它就会腐烂——而失去同步的类型文档比没有更糟,因为读者会信任它。 -因此这项工作包含两个交织的问题:**这样一份目录应当收录什么**(范围界定问题:一个 harness 有数十个跨包(package)的类型,全部堆上去对谁都没帮助),以及**如何防止粘贴的类型定义漂移**(持久性问题)。本 RFC 记录这两项决策。它的姊妹篇 [生成式 Cordis 事件 + 服务目录](2026-06-20-generated-cordis-catalog.md) 是*接线*轴向的补充:本篇编目数据结构,那篇编目移动它们的事件与服务。 +因此这项工作包含两个交织的问题:**这样的目录应当收录什么**(范围界定问题——一个 harness 有数十个跨包类型,全部堆上去对谁都没帮助),以及**如何防止粘贴的类型定义漂移**(持久性问题)。本 RFC 记录两项决策。它的姊妹篇 [生成式 Cordis 事件 + 服务目录](2026-06-20-generated-cordis-catalog.md) 是*接线*轴的补充:本篇编目数据结构,那篇编目传递数据结构的事件与服务。 ## 决策 -新建 `docs/core-data-structures/` 目录编目词汇,并新增 `verify-type-equiv` doc-sync(文档同步门禁)门禁,确保每一处粘贴的类型定义与源码逐字节一致。 +新建 `docs/core-data-structures/` 文件夹编目词汇,并新增 `verify-type-equiv` doc-sync(文档同步门禁)门禁,确保每处粘贴的类型定义与源码逐字节一致。 -### 什么算「核心」——主干与 seam 的分界线 +### 何为"核心"——主干与 seam 的分界线 -范围界定不是自上而下拍板的,而是将候选定义逐一对照具体的边界类型反复测试,直到一条规则在所有案例中都成立。决定性的测试是 `BashExecRequest`/`BashExecSpec`/`BashRunResult`:bash 是一个能力 *seam*,不属于 agent loop 主干;如果这些算「核心」,那「核心」就等于*所有跨包词汇*,目录就是一份平铺的全量转储;如果它们不算,「核心」就意味着*中央主干*,bash 词汇属于子页面。后者胜出,由此确定了整体结构:一个**分层目录**,而非一份平铺文档。 +范围界定并非自上而下拍定,而是将候选定义逐一对照具体的边界类型反复测试,直到一条规则在所有案例中都成立。决定性的测试是 `BashExecRequest`/`BashExecSpec`/`BashRunResult`:bash 是一个能力 *seam*,不属于 agent loop(智能体循环)主干;如果这些算"核心",那么"核心"就意味着*所有跨包词汇*,目录沦为平铺罗列;如果不算,"核心"就意味着*中央主干*,bash 词汇归入子页面。后者胜出,由此确定了整体结构:一个**分层文件夹**,而非一份平铺文档。 -解决剩余案例的规则:***你编写、持有或接收的类型是核心;为其提供类型推导、渲染或持久化的机制是子页面细节。*** 逐一验证如下: +确定其余案例的规则是:***你编写、持有或接收的类型是核心;为其提供类型推导、渲染或持久化的机制是子页面细节。*** 逐一验证如下: -- 一个数据结构是**核心**的,如果它流经 agent loop 主干——无论加载了哪些插件,循环在每个轮次都持有、派生、流式输出或记录它(`Message`、`StreamChunk`、`SessionEvent`、`Agent` 句柄)——**或者**它是插件作者面向某条流水线编写的唯一标题类型(`ToolDefinition`)。 -- `ToolDefinition` 是核心(它是每个工具作者编写的东西),**即使循环从不持有它**——对于这一个标题类型,撰写重要性覆盖了严格的「流经主干」规则。但它的类型推导机制——`SchemaSpec`/`InferArgs` DSL——是子页面细节(你编写的是 `ToolDefinition`;为其提供类型推导的机制你不直接接触)。这就是主干与 seam 分界线的精确表述。 -- `ToolSchema` 是核心(它是 `GenerateOptions` 的字段,而 `GenerateOptions` 是流经每个步骤的模型请求),即使它在概念上属于工具流水线——当*流经主干*与*概念归属*冲突时,前者胜出。 +- 一个数据结构是**核心**的,如果它流经 agent loop 主干——无论加载了哪些插件,循环在每个轮次都会持有、派生、流式输出或记录它(`Message`、`StreamChunk`、`SessionEvent`、`Agent` 句柄)——**或者**它是插件作者面对某条流水线时编写的唯一标志性类型(`ToolDefinition`)。 +- `ToolDefinition` 是核心(它是每个工具作者编写的东西),**即使循环从不持有它**——对于这一个标志性类型,撰写重要性压过了严格的"流经主干"规则。但它的类型推导机制——`SchemaSpec`/`InferArgs` DSL——是子页面细节(你编写的是 `ToolDefinition`;为其提供类型推导的机制你并不直接接触)。这就是主干与 seam 分界线的精确表述。 +- `ToolSchema` 是核心(它是 `GenerateOptions` 的一个字段,而 `GenerateOptions` 是流经每个步骤的模型请求),即使它在概念上属于工具流水线——当*流经主干*与*概念归属*冲突时,前者胜出。 - 工具展示词汇(`ToolCallView`/`ToolResultView` 等)、`SessionPersistence` 持久性 seam 以及 bash 词汇是子页面。 -`core.md` 是一份**自包含的主干文档**:它给出每个主干结构的确切类型定义,配以最少的行文,并链接到各 seam 细节的子页面。子页面包括 `llm-streaming.md`、`session.md`、`persistence.md`(沿内存模型与持久性 seam 的分界从 session 中拆出)、`tools.md` 和 `bash.md`。 +`core.md` 是一份**自包含的主干文档**:它给出每个主干结构的确切类型定义,辅以最少的行文,并链接到子页面获取各 seam 的细节。子页面包括 `llm-streaming.md`、`session.md`、`persistence.md`(沿内存模型与持久性 seam 的分界线从 session 拆出)、`tools.md` 和 `bash.md`。 -### `ts type-equiv` 机制——逐字且防漂移 +### `ts type-equiv` 机制——既逐字又防漂移 -持久性要求很具体:文档应展示**逐字**的当前类型定义(让读者看到真实形状,而非转述),**并且**机械地保证与源码一致。仓库已经能编译围栏 ` ```ts ` 块(`doc-typecheck`),但一个真正通过类型检查的块需要 import 噪音,且只能证明*可赋值性*而非*逐字节相等*——一个改了名但类型相同的字段仍能通过。因此: +持久性需求很具体:文档应当展示**当前类型定义的原文**(让读者看到真实形状,而非转述),**并且**机械地保证与源码一致。仓库已经能编译围栏 ` ```ts ` 块(`doc-typecheck`),但一个真正可编译的块需要 import 噪音,且只证明*可赋值性*而非*字节相等*——一个类型相同但改了名的字段会通过。因此: -- 类型定义逐字粘贴到专用的 ` ```ts type-equiv ` 围栏中。`doc-typecheck` 识别该围栏并跳过它(裸定义不能独立编译),并**将其排除在 opt-out 比例之外**——它是一个独立检查的类别,而非未检查的草稿。 -- 新增 `scripts/verify-type-equiv.ts`,通过 TypeScript 解析器提取每个块,并对声明的符号断言**逐字源码匹配**——之所以选择这种方式而非编译式 `_Check` 可赋值性断言,正是因为逐字节相等而非可赋值性才是我们需要的属性。 -- 来源信息保存在中央 `scripts/type-equiv.manifest.json`(`{ doc, symbol, source }` 条目)中,**而非**行文中的指令注释。脚本强制执行 **1:1 对应**:每个 type-equiv 块恰好有一条 manifest 条目,反之亦然;因此不会有块被静默漏检,也不会有条目腐烂。 -- 接入 `doc-sync`,因此与其他文档门禁在同一个 lefthook pre-push 和 CI 路径中运行。 +- 类型定义逐字粘贴到专用的 ` ```ts type-equiv ` 围栏中。`doc-typecheck` 识别该围栏并跳过它(裸定义不能独立编译),且**将其排除在 opt-out 比例之外**——它是一个独立检查的类别,而非未检查的草稿。 +- 新增的 `scripts/verify-type-equiv.ts` 通过 TypeScript 解析器提取每个块,并断言其与声明的符号**逐字节匹配源码**——之所以选择这种方式而非编译式 `_Check` 可赋值性断言,正是因为我们需要的属性是字节相等,而非可赋值性。 +- 来源信息存放在集中的 `scripts/type-equiv.manifest.json`(`{ doc, symbol, source }` 条目)中,**而非**行文中的指令注释。脚本强制执行 **1:1 对应**:每个 type-equiv 块恰好有一条 manifest 条目,反之亦然;因此一个块永远不会被静默漏检,一条条目也永远不会腐烂。 +- 接入 `doc-sync`,因此与其他文档门禁在同一条 lefthook pre-push 和 CI 路径中运行。 ### 维护是作者的职责,门禁作为兜底 -`verify-type-equiv` 能捕获已记录类型的*粘贴漂移*,但无法告诉你一个全新的核心类型没有被记录。因此 AGENTS.md 和 `dsh-code-review` skill 已更新,要求在变更添加或重塑已记录类型时同步更新目录——门禁处理漂移,人处理新增表面。 +`verify-type-equiv` 能捕获已记录类型的*粘贴漂移*,但无法告诉你一个全新的核心类型没有被记录。因此 AGENTS.md 和 `dsh-code-review` skill(技能)已更新,要求在变更添加或重塑已记录类型时同步更新目录——门禁处理漂移,人处理新增表面。 ## 曾考虑的替代方案 -- **平铺转储所有跨包词汇**:`BashExecRequest` 测试案例否决了它。如果 seam 词汇算「核心」,目录对谁都没帮助;分层的主干与 seam 结构胜出。 -- **编译式 `_Check` 可赋值性断言**替代逐字源码匹配:否决,因为逐字节相等而非可赋值性才是我们需要的属性——一个改了名但类型相同的字段能通过可赋值性检查。 -- **来源信息作为行文中的指令注释**:否决,改用中央 manifest;其强制的 1:1 对应确保不会有块被静默漏检,也不会有条目腐烂。 +- **平铺罗列所有跨包词汇**:`BashExecRequest` 测试案例否决了它。如果 seam 词汇算"核心",目录对谁都没帮助;分层的主干与 seam 结构胜出。 +- **编译式 `_Check` 可赋值性断言**替代逐字节源码匹配:否决,因为我们需要的属性是字节相等而非可赋值性——一个类型相同但改了名的字段会通过可赋值性检查。 +- **来源信息作为行文中的指令注释**:否决,改用集中 manifest;其强制的 1:1 对应确保一个块永远不会被静默漏检,一条条目也永远不会腐烂。 ## 验证教训 主干与 seam 规则在采纳前经过了 `BashExecRequest`、工具 schema 与定义、schema DSL、展示类型以及 session/persistence 拆分的逐一测试。 -`verify-type-equiv` 必须扫描完整的 Markdown 范围,而不仅是 manifest 中列出的文档。否则未登记的 `type-equiv` 块会逃脱所声称的一对一检查。因此门禁将此类块报告为遗留块。本 RFC 将这条快速失败的扫描规则与主干/seam 分界和逐字匹配决策一并记录;生成式 Cordis 目录在[其 RFC](2026-06-20-generated-cordis-catalog.md) 中有对称的设计记录。 +`verify-type-equiv` 必须扫描完整的 Markdown 范围,而不仅仅是 manifest 中列出的文档。否则一个未登记的 `type-equiv` 块会逃脱所声称的一对一检查。因此门禁将此类块报告为遗留块。本 RFC 将这条快速失败的扫描规则与主干-seam 分界线和逐字节匹配决策一并记录;生成式 Cordis 目录在[其 RFC](2026-06-20-generated-cordis-catalog.md) 中有对称的设计记录。 ## 后果 -- 词汇现在有了一个**不会静默漂移**的唯一归属地:源码中的字段重命名会在 pre-push 钩子和 CI 中使 `verify-type-equiv` 失败,直到粘贴内容被刷新。 -- 主干与 seam 分界线是一个可复用的范围界定工具,而非一次性决策:同一条「你编写/持有/接收的东西是核心;为其提供类型推导/渲染/持久化的机制是细节」规则,后来也被用于界定事件/服务目录的 harness 层与继承层分层。 -- `ts type-equiv` 围栏是继 ` ```ts `(编译)和 ` ```ts ignore-check `(草稿)之后的第三种文档块类别。后续又新增了第四种 ` ```ts cordis-catalog `(生成签名),复用了相同的跳过并排除处理。 +- 词汇现在有了一个**不会静默漂移**的唯一归属:源码中的字段重命名会在 pre-push 钩子和 CI 中导致 `verify-type-equiv` 失败,直到粘贴内容被刷新。 +- 主干与 seam 分界线是一个可复用的范围界定工具,而非一次性的:同一条「你编写/持有/接收的东西是核心;为其提供类型推导/渲染/持久化的机制是细节」规则,后来也被用于界定事件/服务目录的 harness 层与继承层分层。 +- ` ```ts type-equiv ` 围栏是继 ` ```ts `(编译)和 ` ```ts ignore-check `(草稿)之后的第三种文档块类别。后续的姊妹门禁又增加了第四种 ` ```ts cordis-catalog `(生成签名),复用了相同的跳过并排除处理。 - 添加或重塑核心类型现在附带一项文档义务,作者必须履行(门禁无法检测缺失的*新*类型),由 `dsh-code-review` 检查清单兜底。 diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml index ee4e1d24fc..9f7e982ff7 100644 --- a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-generated-cordis-catalog.md: 6b451e31965f8f00210aa927ed236fed28699351 -2026-06-20-generated-cordis-catalog.zh.md: 9c7150ff5f12d4d9e4a13158acdf8f52e84fd95a +2026-06-20-generated-cordis-catalog.zh.md: 5550d07b5f5635d1da6496e35049c5725329e114 diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md index 9c7150ff5f..5550d07b5f 100644 --- a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC:生成式 Cordis 事件 + 服务目录 +# RFC:生成式 Cordis 事件与服务目录 Status: implemented @@ -6,36 +6,36 @@ Status: implemented ## 问题 -插件作者需要两个参考面,而此前没有任何单一文档能提供:他们可以监听的每一个 Cordis **事件**(含精确签名与分发模式),以及他们可以调用的每一个 `ctx.<key>` **服务**(含精确接口)。相关信息已经存在,但散落各处:`docs/architecture.md` 中一张手工维护的事件分类*表格*(名称 + 行文描述的 Mode/Purpose,由 `verify-event-taxonomy` 做名称集合校验)、一张服务映射表(8 行角色描述),以及 `interface Events` / `interface Context` 声明本身。分类表还有一个盲区:它无法捕获全新的*未记录*事件——名称集合校验器只检查两侧已有的名称。 +插件作者需要两个参考面,而此前没有任何单一文档能提供:他们可以监听的每一个 Cordis **事件**(含精确签名与分发模式),以及他们可以调用的每一个 `ctx.<key>` **服务**(含精确接口)。相关信息虽然存在,但散落各处:`docs/architecture.md` 中一张手工维护的事件分类*表格*(名称 + 行文描述的 Mode/Purpose,由 `verify-event-taxonomy` 做名称集合校验)、一张服务映射表(8 行角色描述),以及 `interface Events` / `interface Context` 声明本身。分类表格还有一个盲区:它无法捕获全新的*未记录*事件——名称集合校验器只检查两侧已有的名称。 -这是[核心数据结构目录](../../../core-data-structures/core.md)([对应 RFC](2026-06-20-core-data-structures-catalog.md))在连线轴上的互补件:那份目录记录 agent loop 流转的*数据结构*(经校验的手工粘贴);本目录记录流转它们的*事件与服务*。 +这是 [core-data-structures 目录](../../../core-data-structures/core.md)([其 RFC](2026-06-20-core-data-structures-catalog.md))在连线轴上的补充:后者编目的是 agent loop(智能体循环)流转的*数据结构*(经校验的手工粘贴);本 RFC 编目的是移动这些数据结构的*事件与服务*。 ## 决策 -从源码生成目录,而非手工维护表格再校验子集。 +从源码生成目录,取代手工维护表格并校验子集的方式。 -`scripts/gen-cordis-catalog.ts` 使用 TypeScript 编译器 API,从声明和源码 JSDoc 分别输出事件参考与服务参考。事件包含分发模式;服务包含公开签名。确定性的 `--write` 与 `--check` 模式使两个页面成为生成产物,新鲜度由 doc-sync 强制。 +`scripts/gen-cordis-catalog.ts` 使用 TypeScript 编译器 API,从声明和源码 JSDoc 分别输出事件参考与服务参考。事件包含分发模式;服务包含公开签名。确定性的 `--write` 和 `--check` 模式使两个页面成为生成产物,新鲜度由 `doc-sync`(文档同步门禁)强制保障。 -纯生成在这里是正确的,因为代码库足够规范,AST 即全部真相:每个事件/服务名称都是字符串字面量,能往返映射到一个静态声明——没有动态命名的事件,也没有仅运行时存在的服务。因此生成的文档不可能出错,并且从结构上消除了未记录事件的缺口(生成器枚举源码,而非检查手写子集)。 +纯生成在此处是正确的,因为代码库足够规范,AST 就是全部事实:每个事件/服务名称都是字符串字面量,可以往返映射到静态声明——不存在动态命名的事件,也不存在仅运行时的服务。因此生成的文档不可能出错,且从结构上消除了未记录事件的缺口(生成器枚举源码,而非校验手写子集)。 具体选择: -- **`@mode` 标签,交叉校验。** 每个 harness 事件的 JSDoc 携带显式的 `@mode emit|waterfall|parallel|serial` 标签;缺少标签时生成器直接报错。当签名形状具有结论性时——尾部参数为 `next: () => …` 在结构上即为 waterfall——生成器断言标签与之一致,矛盾时直接报错。emit/parallel/serial 的区分在结构上不可见(`session/flush` 返回 `Promise<void> | void` 且无 `next`,有序的 `agent/pre-step` 检查点亦然),因此信任标签。撰写规则见 [AGENTS.md](../../../../AGENTS.md)。 -- **分层范围。** harness 层(8 个 `@deepseek-ai/dsh-*` 服务及其事件)从源码完整渲染。继承层(cordis-core 的 `ctx.on/emit/effect/provide/…` + `internal/*` 事件 + loader/HMR/timer)是插件同样可见的固定 vendor 源;它以精简形式渲染(名称 + 一行说明 + 源码指针),数据来自生成器中的一张手工策展表,而**不是**遍历 vendor AST——cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段(`root`、`baseUrl`、`logger`),且 vendor 表面仅在有意的 vendor 同步时才变化。 -- **交叉链接到数据结构目录。** 签名中出现的类型名(`GenerateOptions`、`StreamChunk`、`ToolDefinition` 等)链接到记录该类型的核心数据结构页面。映射是生成器中一个小型手工策展的 const,而**不是** `type-equiv.manifest.json`——后者记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 -- **专用围栏。** 签名块使用 ` ```ts cordis-catalog ` 信息字符串,`doc-typecheck` 识别并跳过它(裸签名片段不能独立编译),不计入 opt-out 比例——与 `type-equiv` 块的处理方式相同。 +- **`@mode` 标签,交叉校验。** 每个 harness 事件的 JSDoc 携带一个显式的 `@mode emit|waterfall|parallel|serial` 标签;缺少标签时生成器直接报错。当签名形状具有决定性时——尾部参数为 `next: () => …` 在结构上即为 waterfall(瀑布式事件)——生成器断言标签与之一致,矛盾时直接报错。emit/parallel/serial 的区别在结构上不可见(`session/flush` 返回 `Promise<void> | void` 且无 `next`,有序的 `agent/pre-step` 检查点亦然),因此信任标签。编写规则见 [AGENTS.md](../../../../AGENTS.md)。 +- **分层范围。** harness 层(8 个 `@deepseek-ai/dsh-*` 服务及其事件)从源码完整渲染。继承层(cordis-core 的 `ctx.on/emit/effect/provide/…` + `internal/*` 事件 + loader/hmr/timer)是插件同样可见的固定 vendor 源码;它从生成器中一张人工维护的表格简洁渲染(名称 + 一行描述 + 源码指针),而**非**遍历 vendor AST。原因是 cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段(`root`、`baseUrl`、`logger`),且 vendor 接口面仅在有意的 vendor 同步时才变化。 +- **交叉链接到数据结构目录。** 签名中的类型名(`GenerateOptions`、`StreamChunk`、`ToolDefinition` 等)链接到记录该类型的 core-data-structures 页面。映射是生成器中一个小型的人工维护常量,而**非** `type-equiv.manifest.json`——后者记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 +- **专用围栏。** 签名块使用 ` ```ts cordis-catalog ` 信息字符串,`doc-typecheck` 识别后跳过(裸签名片段不能独立编译),并排除在 opt-out 比例之外——与 `type-equiv` 块获得相同待遇。 -本决策**取代** [doc-sync 强制](2026-06-11-doc-sync-enforcement.md)中的事件分类部分:`verify-event-taxonomy` 及其 `docs/architecture.md` 表格退役(architecture.md 的标题保留,正文改为指向目录;服务映射角色表作为策展行文保留)。doc-typecheck、verify-md-wrap、verify-md-links 与 verify-type-equiv 不受影响。 +本决策**取代** [doc-sync 强制](2026-06-11-doc-sync-enforcement.md)中事件分类的那一半:`verify-event-taxonomy` 及其 `docs/architecture.md` 表格退役(architecture.md 的标题保留,正文改为指向目录;服务映射的角色表格作为人工行文保留)。doc-typecheck、verify-md-wrap、verify-md-links 和 verify-type-equiv 不受影响。 ## 曾考虑的替代方案 -- **校验而非生成(退役的分类检查所做的事)**:*仅对此表面*反转了方向。这里的数据可以机械地完整获取,因此生成严格强于名称集合校验(完整签名、不会漂移、能捕获未记录事件)。 -- **遍历 vendor AST 以获取继承层**:否决,改用策展表。cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段,且固定的 vendor 表面仅在有意同步时才变化。 -- **复用 `type-equiv.manifest.json` 作为签名交叉链接映射**:否决,改用小型手工策展 const。manifest 记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 +- **校验而非生成(退役的分类检查所做的事)**:*仅对本参考面*反转了这一策略。此处的数据可以机械地完整获取,因此生成严格强于对手工表格做名称集合校验(完整签名、不会漂移、能捕获未记录事件)。 +- **遍历 vendor AST 以获取继承层**:否决,改用人工维护表格。cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段,且固定的 vendor 接口面仅在有意同步时才变化。 +- **复用 `type-equiv.manifest.json` 作为签名交叉链接映射**:否决,改用小型人工维护常量。manifest 记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 ## 后果 -- 目录不会漂移:源码变化而已提交文件未反映时,`verify-cordis-catalog` 在 pre-push 钩子和 CI 中失败。新事件缺少 `@mode` 标签、或标签与签名矛盾时,生成器直接报错。 -- 事件的行文描述现在只有一个归属地——声明处的 JSDoc。JSDoc 写得薄,目录条目就薄,这迫使作者在源头做好文档(生成器是 AGENTS.md「每个导出都有语义 JSDoc」规则的强制函数)。 -- 继承层是手工摘要的,因此 vendor 同步若增加或重命名了 cordis-core 事件或 `ctx` 成员,需要同步编辑 `gen-cordis-catalog.ts` 中的策展表。这是不遍历固定 vendor 源的有意代价;变化很少,且在生成器中有明确标注。 -- `verify-event-taxonomy.ts` 被删除,`docs/architecture.md` 的事件表格消失;之前链接到特定表格行的人现在会落到生成目录上。 +- 目录不会漂移:源码变更而已提交文件未反映时,`verify-cordis-catalog` 在 pre-push 钩子和 CI 中失败。新事件缺少 `@mode` 标签,或标签与签名矛盾,生成器直接报错。 +- 事件的行文描述现在有了唯一归属地——声明处的 JSDoc。JSDoc 写得单薄,目录条目就单薄,这迫使作者在源码处做好文档(生成器是 AGENTS.md「每个导出都有语义 JSDoc」规则的强制函数)。 +- 继承层是手工摘要,因此 vendor 同步若新增或重命名了 cordis-core 事件或 `ctx` 成员,需要同步编辑 `gen-cordis-catalog.ts` 中的人工维护表格。这是不遍历固定 vendor 源码的有意代价;它很少变化,且在生成器中有明确标注。 +- `verify-event-taxonomy.ts` 被删除,`docs/architecture.md` 的事件表格也已移除;之前链接到特定表格行的人现在会落在生成目录上。 diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml index 97b96e7315..cc4642657c 100644 --- a/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-rfc-classification.md: 201852a209be7f40b05de45d148a36b9185767a3 -2026-06-20-rfc-classification.zh.md: 38eb920ac216e69087f0c84c95cdd9effca7b9b3 +2026-06-20-rfc-classification.zh.md: 554ac8014719c99ed447a33ff843c40fde761eed diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md b/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md index 38eb920ac2..554ac80147 100644 --- a/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md @@ -1,48 +1,48 @@ # RFC:通过路径编码的子目录对 RFC 进行分类 -Status: implemented - [English](2026-06-20-rfc-classification.md) | 中文 +Status: implemented + ## 问题 -`docs/rfc/` 此前仅按**生命周期**分组:`proposed/`/`implemented/`/`rejected/`。没有任何机制记录每篇 RFC 属于哪一*类*决策。索引是每个生命周期下的一个扁平列表,无法按需筛选「所有精简类」或「所有测试策略类」决策。同一天落地的一批精简类 RFC 让这个缺口变得具体:浏览 `proposed/` 的读者无法在不逐一打开文件的情况下区分新能力、移除和工具策略变更。 +`docs/rfc/` 过去仅按**生命周期**分组 RFC:`proposed/`/`implemented/`/`rejected/`。没有任何机制记录每个 RFC 属于哪一*类*决策。索引在每个生命周期下只是一个扁平列表,无法按需筛选「所有简化类」或「所有测试策略类」决策。一批简化类 RFC 在同一天落地后,这个缺口变得具体:浏览 `proposed/` 的读者无法在不逐一打开文件的情况下区分新能力、移除和工具策略变更。 -本仓库的一贯倾向是[机械质量门禁优先于行文指南](2026-06-11-quality-gates.md):不被机器检查的约定终将腐烂。因此这里的分类体系必须可强制执行,而非靠自觉的文件头。 +本仓库一贯的倾向是[机械质量门禁优于行文规范](2026-06-11-quality-gates.md):不被机器检查的约定终将腐烂。因此这里的分类方案必须可强制执行,而非靠自觉的文件头。 ## 决策 -增加第二个维度——RFC 的**类别**——并将其编码在路径中:`{lifecycle}/{class}/yyyy-mm-dd-topic.md`。文件夹*就是*标签。文件的位置声明其类别,封闭集合是「这些文件夹且仅限这些」,而既有的 [verify-md-links](2026-06-18-markdown-cross-link-lint.md) 门禁已经保护了移动文件所需的路径重写。 +增加第二个维度——RFC 的**类别**——并将其编码在路径中:`{lifecycle}/{class}/yyyy-mm-dd-topic.md`。文件夹本身就是标签。文件的位置声明其类别,封闭集合是「这些文件夹且仅限这些」,而既有的 [verify-md-links](2026-06-18-markdown-cross-link-lint.md) 门禁已经保护了移动文件所需的路径重写。 ### 六个类别的封闭集合 -| 类别 | 覆盖范围 | +| 类别 | 涵盖范围 | |---|---| | `feature` | 面向用户或模型的新能力。 | -| `bug-fix` | 修正缺陷或弥补事后复盘暴露的缺口。 | -| `simplification` | 移除代码、行为或接口面,不增加新能力。 | -| `architecture` | 关于**交付源码**的结构性决策:包之间的关系、运行时词汇是什么。 | -| `process` | 围绕代码的工具、策略或工作流,不涉及运行时行为。 | +| `bug-fix` | 修正缺陷或填补事后复盘暴露的空白。 | +| `simplification` | 移除代码、行为或对外表面积,不引入新能力。 | +| `architecture` | 关于**交付源码**的结构性决策——包(package)之间的关系、运行时词汇。 | +| `process` | 围绕代码的工具、策略或工作流,而非运行时行为。 | | `testing` | 测试基础设施与策略。 | -`architecture` 与 `process` 的分界线:**architecture** 关乎我们交付的源码;**process** 关乎围绕源码的工具与工作流。本 RFC 本身是一项 `process` 决策——它改变的是仓库的组织方式和门禁,而非 harness 在运行时的行为——因此它位于 `implemented/process/` 下。 +`architecture` 与 `process` 的分界线:**architecture** 关乎我们交付的源码;**process** 关乎围绕源码的工具与工作流。本 RFC 本身是一个 `process` 决策——它改变的是仓库的组织方式和门禁,而非 harness 的运行时行为——因此它位于 `implemented/process/` 下。 ### 两道门禁 -两者都是 `doc-sync` 的成员,风格与 `verify-md-wrap` 一致(tsx ESM,只校验不生成,首个违规即以非零退出码退出): +两者都是 `doc-sync`(文档同步门禁)的成员,风格与 `verify-md-wrap` 一致(tsx ESM,只校验不生成,首个违规即以非零退出码退出): -- **`scripts/verify-rfc-classification.ts`**:封闭集合与索引新鲜度(freshness)。它断言每个生命周期文件夹下的文件都位于规范集合中的某个类别文件夹内(直接放在生命周期根目录的 `.md`,或未知的类别文件夹,都会失败),并断言生成的 [INDEX.md](../../INDEX.md) 与从目录树重新渲染的结果逐字节一致(见[生成 RFC 索引表](2026-07-04-generate-rfc-index-tables.md))。规范类别集合以 `const` 形式定义在 `scripts/rfc-index.ts` 中——这是与生成器共享的机器真源——[README](../../README.md) 以行文形式记录它;类别*描述*保持手写,索引则是生成的。 -- **`scripts/verify-doc-refs.ts`**:源码注释中的文档引用。RFC 路径不仅在 Markdown 中被引用,也出现在 TypeScript 文档注释中(根相对路径,如 `docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md`)。`verify-md-links` 从未扫描过这些引用,因此重组可能会悄悄使它们变成悬空引用。此门禁扫描 `packages/**` 和 `examples/**` 下仓库自有的 `.ts` 文件(排除构建产物 `lib/` 和 `vendor/`),查找 `docs/….md` 形式的 token,将每个根相对路径解析并断言其存在。它要求 `.md` 扩展名,因此无扩展名的行文引用(`docs/postmortem/0001`、`docs/architecture.md § Extending The Harness`)不受影响。 +- **`scripts/verify-rfc-classification.ts`**——封闭集合与索引新鲜度。它断言生命周期文件夹下的每个文件都位于规范集合中的某个类别文件夹内(生命周期根目录下的散落 `.md` 或未知类别文件夹均判定失败),并断言生成的 [INDEX.md](../../INDEX.md) 与从目录树重新渲染的结果逐字节一致(见[生成 RFC 索引表](2026-07-04-generate-rfc-index-tables.md))。规范类别集合以 `const` 形式定义在 `scripts/rfc-index.ts` 中——这是与生成器共享的机器真源——而 [README](../../README.md) 以行文形式记录它;类别*描述*保持手写,索引由机器生成。 +- **`scripts/verify-doc-refs.ts`**——源码注释中的文档引用。RFC 路径不仅被 Markdown 引用,也被 TypeScript 文档注释引用(以仓库根为起点的路径,如 `docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md`)。`verify-md-links` 从未扫描过这些引用,因此重组可能使它们静默失效。此门禁扫描 `packages/**` 和 `examples/**` 下仓库自有的 `.ts` 文件(排除构建产物 `lib/` 和 `vendor/`),查找 `docs/….md` 形式的 token,将每个以仓库根为起点的路径解析并断言其存在。它要求 `.md` 扩展名,因此无扩展名的行文引用(`docs/postmortem/0001`、`docs/architecture.md § Extending The Harness`)不受影响。 ## 曾考虑的替代方案 -- **在每个文件中加一行 `Classification:` 行文**(紧挨 `Status:`),由门禁解析。可行,但它把路径已经能承载的事实重复到了文件内,而且这一行可能与所在文件夹不一致。路径编码让标签与其存储合二为一——没有需要保持同步的东西。 -- **设立 `refactor` 类别。**它与 `simplification` 几乎完全重叠;唯一有人试图用来区分的标准是「可观测行为是否改变?」,而 `simplification` 已经编码了这一点(它不改变)。一个类别,不要两个。 -- **从文件系统自动生成索引。**此处最初否决,以保持索引手写;后来被[生成 RFC 索引表](2026-07-04-generate-rfc-index-tables.md)取代——当堆叠的提案波使手写表格成为仓库中冲突最频繁的文档区域后,列表改为完全生成的 [INDEX.md](../../INDEX.md),而 README 行文保持人工策展。 +- **在每个文件中添加 `Classification:` 行文行**(紧邻 `Status:`),由门禁解析。可行,但它将路径已能承载的事实重复到文件中,且行内容可能与所在文件夹不一致。路径编码使标签与其存储合二为一,没有需要保持同步的东西。 +- **设立 `refactor` 类别。** 与 `simplification` 几乎完全重叠;唯一有人试图用来区分的标准是「可观察行为是否改变?」,而 `simplification` 已经编码了这一点(它不改变)。一个类别即可,无需两个。 +- **从文件系统自动生成索引。** 此处最初否决,以保持索引手写;后被[生成 RFC 索引表](2026-07-04-generate-rfc-index-tables.md)取代——当堆叠的提案潮使手写表格成为仓库中冲突最频繁的文档区域后,列表改为完全生成的 [INDEX.md](../../INDEX.md),而 README 行文保持人工维护。 ## 后果 -- 每篇 RFC 现在都位于一个类别文件夹下,索引在每个生命周期内按类别分组。读者扫一个标题就能看到所有精简类或所有测试类决策。 -- `doc-sync` 链中多了两个快速 tsx 脚本;无新增依赖(mdast/GFM 栈已因 `verify-md-wrap`/`verify-md-links` 而存在)。 -- 新增类别是一个刻意的动作:修改 `scripts/rfc-index.ts` 中的 `const` 以及 [Classification 章节](../../README.md#classification),而不是仅仅 `mkdir` 一个文件夹。门禁会拒绝未知文件夹,因此临时类别无法悄悄混入。 -- 源码注释中的文档引用现在也受门禁保护:一个被移动或重命名的文档如果被 `.ts` 注释引用,pre-push 钩子就会失败,从而封堵了 `verify-md-links` 在结构上无法看到的一类漂移。 +- 每个 RFC 现在都位于一个类别文件夹下,索引在每个生命周期内按类别分组。读者只需扫一个标题即可看到所有简化类或所有测试类决策。 +- `doc-sync` 链中多了两个快速 tsx 脚本;无新依赖(mdast/GFM 栈已因 `verify-md-wrap`/`verify-md-links` 而存在)。 +- 新增类别是一个刻意的动作:修改 `scripts/rfc-index.ts` 中的 `const` 和 [Classification 章节](../../README.md#classification),而非仅仅 `mkdir` 一个文件夹。门禁拒绝未知文件夹,因此临时类别无法悄悄混入。 +- 源码注释中的文档引用现在也受门禁保护——一个被移动或重命名的文档如果被 `.ts` 注释引用,pre-push 钩子就会失败,堵住了 `verify-md-links` 在结构上无法看到的一类漂移。 diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml index 852f69db42..8ecca3648d 100644 --- a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-02-tool-schema-catalog.md: 9a99fafd36b3546be4f51a7cd9e9a47fdaaf4c2d -2026-07-02-tool-schema-catalog.zh.md: 373c681fa5870696645b138f12cad7f296434184 +2026-07-02-tool-schema-catalog.zh.md: 5860d1617ce6592c8665e4cb59304b0f6d35c99a diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md index 373c681fa5..5860d1617c 100644 --- a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md @@ -1,55 +1,55 @@ # RFC:生成式工具 schema 目录(启动并采集) -Status: implemented - [English](2026-07-02-tool-schema-catalog.md) | 中文 +Status: implemented + ## 问题 -仓库此前没有一份统一的参考,列出实际暴露给模型的工具名称、描述与 JSON Schema。源码声明分散各处且在运行时组合,而既有的 Cordis 目录和数据结构目录覆盖的是接线与词汇,而非工具本身。 +仓库此前没有一份统一的参考文档来记录实际暴露给模型的工具名称、描述与 JSON Schema。源码声明分散各处且在运行时组合,而既有的 Cordis 目录和数据结构目录覆盖的是接线与词汇,而非工具。 ## 决策 -通过**启动每个工具插件并读取其注册的 schema** 来生成目录,而非解析源码。`scripts/gen-tool-catalog.ts` 将每个已发布的工具包(package)挂载到一个全新的 Cordis `Context` 上(带 `SystemPrompt` + `ToolRegistry` 以及插件 `apply` 所读取的注入 seam),调用 `ctx.tools.schemas()`(即发送给模型的 `ToolSchema[]`),dispose 上下文,然后为每个包渲染一个 `## <package>` 小节,每个工具对应一个 ` ```json ` 的 `parameters` 块。它沿用 `gen-cordis-catalog` / `gen-module-graph` 的 CLI 形态:默认 `--write` 重新生成,`--check` 在已提交副本陈旧时失败,输出是确定性的(按 manifest 排序,工具按名称排序)。`verify-tool-catalog`(即 `--check`)运行在 doc-sync 内部,因此新鲜度门禁与其他文档门禁一样在 lefthook pre-push 和 CI 路径中触发。 +通过**启动每个工具插件并读取其注册的 schema** 来生成目录,而非解析源码。`scripts/gen-tool-catalog.ts` 将每个已发布的工具包(package)挂载到一个新的 Cordis `Context`(带 `SystemPrompt` + `ToolRegistry` 以及插件 `apply` 所读取的注入 seam),调用 `ctx.tools.schemas()`(即发送给模型的 `ToolSchema[]`),dispose(资源释放)该 context,然后为每个包渲染一个 `## <package>` 小节,每个工具一个 ` ```json ` 的 `parameters` 块。它与 `gen-cordis-catalog` / `gen-module-graph` 的 CLI(命令行界面)形态一致:默认 `--write` 重新生成,`--check` 在已提交副本陈旧时失败,输出是确定性的(按 manifest(元数据清单)排序,工具按名称排序)。`verify-tool-catalog`(即 `--check`)在 doc-sync(文档同步门禁)内运行,因此新鲜度门禁在 lefthook pre-push 和 CI 路径中与其他文档门禁一同触发。 -### 为什么启动而非解析(核心论点) +### 为何启动而非解析(核心要点) -Cordis 目录是纯 TypeScript AST 遍历,因为每个事件/服务名都是字符串字面量,能往返映射到静态声明——AST 就是全部事实。**工具 schema 不是静态可知的**,因此同样的技术会产出一份说谎的文档: +Cordis 目录是纯 TypeScript AST 遍历,因为每个事件/服务名都是字符串字面量,可以往返映射到静态声明——AST 即全部事实。**工具 schema 在静态层面不可知**,因此同样的技术会产出一份说谎的文档: - `tool-todo` 写了 `enum: [...STATUSES]`——对一个运行时 `const` 的展开。AST 看到的是展开表达式,而非 `["pending","in_progress","completed"]`。 -- 每段 description 都由字符串**拼接**构建(`'…' + '…'`)。AST 看到的是拼接节点,而非模型实际读到的最终文本。 -- `tool-subagent` 的工具名是 `config.toolName ?? 'subagent'`——加载时选定,不是字面量。 -- MCP 插件可以通过 `ctx.tools.register()` 直接注册**原始 JSON Schema**,完全不经过 `defineTool`,因此结构化枚举 `defineTool(` 调用点会漏计。 +- 每条 description 都通过字符串**拼接**构建(`'…' + '…'`)。AST 看到的是拼接节点,而非模型实际读到的最终文本。 +- `tool-subagent` 的工具名是 `config.toolName ?? 'subagent'`——加载时选定,并非字面量。 +- MCP 插件可以通过 `ctx.tools.register()` 直接注册**原始 JSON Schema**,完全不经过 `defineTool`,因此结构化枚举 `defineTool(` 调用点会遗漏。 -唯一忠实的真源是插件加载后注册表实际持有的 schema。启动即是[测试策略](../../../testing.md)中「验证世界,而非自我报告」这一原则在文档生成器上的应用:读取已发布的产物,而非对它的重新推导。 +唯一忠实的真源是插件加载后注册表实际持有的 schema。启动是[测试策略](../../../testing.md)中「验证世界,而非自我报告」这一原则在文档生成器上的应用:读取已发布的产物,而非对它的再推导。 -### 恢复「不会静默遗漏」 +### 恢复「不会静默遗漏」的保证 -启动有一项 AST 遍历不具备的代价:没有源码声明集合可供枚举,因此新增的工具包可能被遗忘。一道**完整性守卫**恢复了这一保证——`assertManifestComplete` 对 `packages/` 下所有 `tool-*` 包做 glob,若有任何一个不在生成器的启动 manifest 中则硬报错。新增工具包会导致生成器失败,进而导致 doc-sync 失败,直到该包被注册。这与 Cordis 生成器通过枚举源码免费获得的结构性保证相同,只是为启动式生成器重新实现了一遍。 +启动有一项 AST 遍历不存在的代价:没有源码声明集合可供枚举,新工具包可能被遗忘。一个**完整性守卫**恢复了这项保证——`assertManifestComplete` 对 `packages/` 下所有 `tool-*` 包进行 glob,若有任何一个不在生成器的启动 manifest 中则直接报错。新工具包在注册之前会导致生成器失败,进而导致 doc-sync 失败。这与 Cordis 生成器通过枚举源码免费获得的结构性属性相同,只是为基于启动的生成器重新实现了一遍。 -### 手工维护的启动 manifest 是不可约减的策略 +### 手动维护的启动 manifest 是不可化约的策略 -文件系统负责发现工具包清单,完整性守卫负责拒绝遗漏。`TOOL_PACKAGES` 仍然为每个包持有一份显式的启动配方,因为所需的 seam 实现和配置是**策略**,不是能从目录布局或注入名称安全推断的事实。 +文件系统负责发现工具包清单,完整性守卫负责拒绝遗漏。`TOOL_PACKAGES` 仍然为每个包持有一份显式的启动配方,因为所需的 seam 实现和配置属于策略,不是能从目录布局或注入名称安全推断的事实。 ### 范围 -`packages/*/tool-*` 下已发布的产品级工具包,各以默认配置启动:`dsh-tool-bash`(`bash`、`bash_output`、`bash_kill`)、`dsh-tool-todo`(`todo_write`)、`dsh-tool-subagent`(`subagent`)。`examples/` 下的演示工具(`echo`)被排除,与 Cordis 目录的 packages-only 范围一致——演示工具不属于读者所要查阅的产品接口。 +`packages/*/tool-*` 下已发布的产品工具包,每个以默认配置启动:`dsh-tool-bash`(`bash`、`bash_output`、`bash_kill`)、`dsh-tool-todo`(`todo_write`)、`dsh-tool-subagent`(`subagent`)。`examples/` 下的演示工具(`echo`)被排除,与 Cordis 目录仅覆盖 packages 的范围一致——演示工具不属于读者所查阅的产品接口。 -目录的单位是包,而非每个已配置的工具实例。每个包以默认配置启动一次;加载时的别名(如 `subagent_fork`)会注明,但不枚举每种部署排列。部署清单是一个独立的、无界的接口。 +目录的单位是包,而非每个配置化的工具实例。每个包以默认配置启动一次;加载时的别名(如 `subagent_fork`)会注明,但不枚举所有部署排列。部署清单是一个独立的、无界的接口。 ### 使用普通 `json` 围栏 -schema 块使用 ` ```json `,而非自定义的 `ts` 系围栏。`doc-typecheck` 只提取 `ts*` 围栏,因此 JSON 块对它不可见——无需 `BlockKind` 接线(不同于 Cordis 目录的 `ts cordis-catalog` 围栏,后者必须加入白名单以避免裸签名片段被编译)。 +schema 块使用 ` ```json `,而非自定义的 `ts` 系围栏。`doc-typecheck` 只提取 `ts*` 围栏,因此 JSON 块对它不可见——无需 `BlockKind` 接线(不同于 Cordis 目录的 `ts cordis-catalog` 围栏,后者需要加入白名单以避免裸签名片段被编译)。 ## 曾考虑的替代方案 -- **纯 TypeScript AST 遍历,如 Cordis 目录**:工具 schema 不是静态可知的(见上文核心论点):运行时展开、字符串拼接、配置选定的名称,以及原始 `ctx.tools.register()` 注册,都会让 AST 推导出的文档说谎。 -- **从各包的 inject 推断启动配方**:[发现包清单提案](../../proposed/process/2026-06-20-discover-package-inventory.md)所警告的「过于聪明」的路径;配方保持手写策略,清单由文件系统发现并受完整性守卫保护。 +- **纯 TypeScript AST 遍历,如 Cordis 目录**:工具 schema 在静态层面不可知(见上文核心要点):运行时展开、字符串拼接、配置选定的名称,以及原始 `ctx.tools.register()` 注册,都会让 AST 推导出的文档说谎。 +- **从各包的 inject 推断启动配方**:属于[发现包清单提案](../../proposed/process/2026-06-20-discover-package-inventory.md)所警告的「过度聪明」路径;配方保持为手写策略,清单由文件系统发现并由完整性守卫把关。 - **为 schema 块使用自定义 `ts` 系围栏**:不必要。普通 ` ```json ` 围栏对 `doc-typecheck` 不可见,无需 `BlockKind` 白名单。 ## 后果 -- 目录不会漂移:工具 schema 变更而已提交文件未反映时,`verify-tool-catalog` 在 pre-push 钩子和 CI 中失败。新增 `tool-*` 包未加入 manifest 时,完整性守卫直接报错。 -- 工具描述文本只有一个归属地——源码中 `defineTool` 的 `description`——生成的条目质量完全取决于它,与 Cordis 目录对事件 JSDoc 施加的推动力相同。 -- 生成器导入并执行工作区包(这是仓库中第一个这样做的脚本;其他脚本只读取文本)。它通过根 `tsconfig` 的 `paths` 映射在 `tsx` 下运行,走的是演示和测试所用的同一条未构建源码路径,因此不需要构建步骤。 -- 未来某个工具背后新增能力 seam 时,意味着 manifest 中新增一条配方条目(需要挂载哪些 seam)。这是上文明确指出的手写代价;仅在新增工具包时才需变更。 +- 目录不会漂移:工具 schema 变更而已提交文件未反映,`verify-tool-catalog` 会在 pre-push 钩子和 CI 中失败。新 `tool-*` 包未加入 manifest 则完整性守卫直接报错。 +- 工具描述文本有唯一归属——源码中 `defineTool` 的 `description`——生成的条目质量取决于它,与 Cordis 目录对事件 JSDoc 施加的强制力相同。 +- 生成器导入并执行工作区包(这是仓库中第一个这样做的脚本;其他脚本只读文本)。它通过根 `tsconfig` 的 `paths` 映射在 `tsx` 下运行,使用与演示和测试相同的未构建源码路径,因此不需要构建步骤。 +- 未来某个工具背后新增一个能力 seam,意味着 manifest 中需要新增一条配方条目(声明要挂载哪些 seam)。这正是上文指出的有意为之的手写成本;仅在新增工具包时才需变更。 diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml index 7b522b590b..6b19ed7740 100644 --- a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-03-documentation-graph-atlas.md: d10b57e5114684ab0a2caed66fa84b84959bdf12 -2026-07-03-documentation-graph-atlas.zh.md: 8473bc27994bb33eac61659196acc53b69a16449 +2026-07-03-documentation-graph-atlas.zh.md: 6edcfbdbbc3af5808e60888acad04919ce681396 diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md index 8473bc2799..6edcfbdbbc 100644 --- a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md @@ -1,69 +1,69 @@ -# RFC:面向维护者和 SDK 用户的文档关系图索引 - -Status: implemented +# RFC:面向维护者与 SDK 用户的文档关系图索引 [English](2026-07-03-documentation-graph-atlas.md) | 中文 +Status: implemented + ## 问题 -仓库此前已有若干高可信度的文档面,各自覆盖不同维度:[module-graph.md](../../../module-graph.md) 由 package 的 `peerDependencies` 生成;生成的 [Cordis 事件目录](../../../cordis-catalog/events.md)和[服务目录](../../../cordis-catalog/services.md)由 Cordis 的 `Events` 与 `Context` 声明生成;[tool-catalog.md](../../../tool-catalog.md) 通过启动已发布的工具插件生成;[core-data-structures/](../../../core-data-structures/core.md) 使用 `ts type-equiv` 块保持粘贴的类型定义与源码同步。 +仓库已有若干高可信度的文档面,各自覆盖不同维度:[module-graph.md](../../../module-graph.md) 由包(package)的 `peerDependencies` 生成;生成的 [Cordis events](../../../cordis-catalog/events.md) 与 [services](../../../cordis-catalog/services.md) 目录由 Cordis 的 `Events` 和 `Context` 声明生成;[tool-catalog.md](../../../tool-catalog.md) 通过启动已发布的 tool 插件生成;[core-data-structures/](../../../core-data-structures/core.md) 使用 `ts type-equiv` 块保持粘贴的类型定义与源码同步。 -这些参考资料是准确的,但它们大多是目录。维护者仍需自行综合关系:哪些 package 构成一条能力 seam、哪个应用捆绑了具体的主干、哪个事件是持久的而哪个是实时的、钩子或策略插件可以在哪里拦截工作、以及哪个面向模型的工具依赖哪个服务。SDK 用户从另一个角度面临同样的问题:「我想要某种行为,该安装或加载哪个 package?该扩展哪个事件/服务/工具?」 +这些参考文档是准确的,但大多是目录式的。维护者仍需自行综合关系:哪些包构成一个能力 seam、哪个应用组装了具体的主干、哪些事件是持久的而哪些是实时的、钩子或策略插件在哪里可以拦截工作、以及哪个面向模型的工具依赖哪个服务。SDK 用户从另一个角度面临同样的问题:「我想要某种行为,应该安装或加载哪个包?应该扩展哪个事件/服务/工具?」 -钩子子系统使事件的生产者/消费者拓扑与拦截点变得更加重要;文件系统 seam 使能力 seam、策略否决、工具呈现和 SDK 组装路径变得更加重要。如果关系图仅限于一个小的 bash/todo/subagent 表面,它们会立刻陈旧。 +钩子子系统使事件的生产者/消费者拓扑与拦截点变得更加重要;文件系统 seam 使能力 seam、策略否决、工具呈现与 SDK 组装路径变得更加重要。如果关系图的范围仅限于一个小的 bash/todo/subagent 表面,它们会立即陈旧。 ## 决策 -新增生成的关系图文档,索引位于 [docs/graph-atlas.md](../../../graph-atlas.md),由专门的生成器产出,并由 `pnpm run verify-doc-graphs` 及既有的目录新鲜度检查(作为 `doc-sync` 的一环)进行验证。 +新增生成的关系图文档,索引位于 [docs/graph-atlas.md](../../../graph-atlas.md),由专用生成器产出,并通过 `pnpm run verify-doc-graphs` 及既有的目录新鲜度检查(作为 `doc-sync` 的一环)进行验证。 -该索引是既有目录之上的关系层。它不替代精确的参考资料,而是链接到它们并解释各部分如何组合在一起。 +该索引是既有目录之上的关系层。它不取代精确的参考文档,而是链接到它们并解释各部分如何组合在一起。 ### 维护模式 每个关系图页面声明一种维护模式: -- **生成(Generated)**:所有节点和边均从源码发现;如果已提交的产物陈旧,`--check` 失败。 -- **混合生成(Hybrid generated)**:源码发现清单,一份小型 manifest 对不可约的策略进行分类,完整性守卫在发现的条目未被分类时失败。 -- **人工维护(Curated)**:图表解释设计意图、时序或归属;它由生成器输出以保证关系图文档作为一个可重新生成的整体,但内容是有意撰写的。 +- **Generated(生成)**:所有节点和边均从源码发现;如果已提交的产物陈旧,`--check` 失败。 +- **Hybrid generated(混合生成)**:源码发现清单,一个小型 manifest 对不可约的策略进行分类,完整性守卫在发现的条目未被分类时失败。 +- **Curated(人工策划)**:图表解释设计意图、时序或归属;它由生成器输出以使关系图文档保持为可重新生成的整体,但内容是有意撰写的。 -### 首批交付的索引 +### 首批发布的索引 -首批索引链接十个关系面。package 拓扑与工具-package 能力映射位于既有的生成目录中(这些目录已拥有相应事实);其余的专项图表由 `scripts/gen-doc-graphs.ts` 生成。 +首批索引链接十个关系面。包拓扑与工具-包能力映射位于已有的生成目录中(这些目录已拥有相应事实);其余聚焦图表由 `scripts/gen-doc-graphs.ts` 生成。 | 关系图 | 维护模式 | 真源 | |---|---|---| -| [模块依赖图](../../../module-graph.md) | 生成 | `packages/*/*/package.json` 的 peer dependencies 加 package 分组路径 | -| [工具 schema 目录与 package 映射](../../../tool-catalog.md) | 生成 | 启动采集的工具 schema 加工具-package 的服务/副作用元数据 | -| [能力 seam 与核心服务](../../../capability-seams.md) | 混合生成 | Cordis 服务声明加 `gen-doc-graphs.ts` 中的角色 manifest | -| [echo-agent 应用组合](../../../../examples/echo-agent/composition.md) | 混合生成 | `examples/echo-agent/cordis.yml` 插件列表加人工维护的应用/bundle 展开 | -| [coding-agent 应用组合](../../../../examples/coding-agent/composition.md) | 混合生成 | `examples/coding-agent/cordis.yml` 插件列表加人工维护的应用/bundle 展开 | -| [acp-agent 应用组合](../../../../examples/acp-agent/composition.md) | 混合生成 | `examples/acp-agent/cordis.yml` 插件列表加人工维护的应用/bundle 展开 | -| [事件生产者/消费者矩阵](../../../event-producer-consumer.md) | 混合生成 | Cordis 事件声明、AST 扫描的 `ctx.on/emit/parallel/serial/waterfall` 调用点,以及显式的动态分发覆盖 | -| [agent 轮次与步骤生命周期](../../../agent-lifecycle.md) | 人工维护 | architecture.md 的循环生命周期、Cordis 目录链接与会话事件语义 | -| [工具执行流水线](../../../tool-execution-pipeline.md) | 人工维护 | 工具流水线语义与 `tools/execute` waterfall(瀑布式事件) | -| [ACP 快照回放](../../../../packages/ui/acp/snapshot-replay.md) | 人工维护 | 快照 harness 行为 | +| [模块依赖图](../../../module-graph.md) | generated | `packages/*/*/package.json` 的 peer dependencies 加包分组路径 | +| [工具 schema 目录与包映射](../../../tool-catalog.md) | generated | 启动收集的工具 schema 加工具-包的服务/副作用元数据 | +| [能力 seam 与核心服务](../../../capability-seams.md) | hybrid generated | Cordis 服务声明加 `gen-doc-graphs.ts` 中的角色 manifest | +| [echo-agent 应用组合](../../../../examples/echo-agent/composition.md) | hybrid generated | `examples/echo-agent/cordis.yml` 插件列表加人工策划的应用/bundle 展开 | +| [coding-agent 应用组合](../../../../examples/coding-agent/composition.md) | hybrid generated | `examples/coding-agent/cordis.yml` 插件列表加人工策划的应用/bundle 展开 | +| [acp-agent 应用组合](../../../../examples/acp-agent/composition.md) | hybrid generated | `examples/acp-agent/cordis.yml` 插件列表加人工策划的应用/bundle 展开 | +| [事件生产者/消费者矩阵](../../../event-producer-consumer.md) | hybrid generated | Cordis 事件声明、AST 扫描的 `ctx.on/emit/parallel/serial/waterfall` 调用点,以及显式的动态分发覆盖 | +| [agent 轮次与步骤生命周期](../../../agent-lifecycle.md) | curated | architecture.md 的循环生命周期、Cordis 目录链接与会话事件语义 | +| [工具执行流水线](../../../tool-execution-pipeline.md) | curated | 工具流水线语义与 `tools/execute` waterfall(瀑布式事件) | +| [ACP 快照回放](../../../../packages/ui/acp/snapshot-replay.md) | curated | 快照 harness 行为 | -### 为什么由生成器拥有这些文档 +### 为什么由生成器拥有文档 -package 拓扑留在 `gen-module-graph.ts`,工具-package 能力映射留在 `gen-tool-catalog.ts`,因为这些生成器已经拥有权威事实和新鲜度门禁。`gen-doc-graphs.ts` 拥有其余关系页面和索引。代价是人工维护的图表需要在 TypeScript 字符串块中编辑,而非直接编辑 Markdown。对首批交付而言这是可接受的,因为面向用户的产物仍是纯 Markdown/Mermaid;如果撰写体验比可重新生成更重要,未来可以将人工维护的页面拆分出来。 +包拓扑留在 `gen-module-graph.ts`,工具-包能力映射留在 `gen-tool-catalog.ts`,因为这些生成器已经拥有权威事实和新鲜度门禁。`gen-doc-graphs.ts` 拥有其余关系页面和索引。代价是人工策划的图表需要在 TypeScript 字符串块中编辑,而非直接编辑 Markdown。对于首版来说这是可接受的,因为面向用户的产物仍然是纯 Markdown/Mermaid;未来如果撰写体验比可重新生成更重要,可以将人工策划的页面拆分出去。 ### 完整性守卫 -混合生成的页面在其 manifest 陈旧时必须显式失败: +混合生成的页面在其 manifest 陈旧时必须显式报错: -- 模块图读取每个 package 的 `peerDependencies`,并按 `packages/<group>/<pkg>` 路径对 package 分组。 -- 工具目录通过启动采集已发布的工具,并从同一份 manifest(其完整性守卫已在检查)渲染 package/服务/副作用映射。 -- 能力 seam 图导入 Cordis 服务收集器,断言每个被发现的 harness `ctx.<key>` 都已在 `SERVICE_ROLES` 中分类,且每个已分类的 key 仍然存在。 -- 事件生产者/消费者矩阵标记为混合生成,因为 subagent 生命周期事件有意使用 `ctx.events.dispatch` 实现逐监听器隔离;这些动态边是显式覆盖而非无声遗漏。 -- `verify-mermaid` 用 Mermaid 自身的解析器解析仓库中每个 ` ```mermaid ` 围栏,因此语法错误会在本地和 CI 的 `doc-sync` 中失败,而不是在 GitHub 渲染时才显示为损坏的图表。 +- 模块图读取每个包的 `peerDependencies`,并按 `packages/<group>/<pkg>` 路径对包进行分组。 +- 工具目录通过启动收集已发布的工具,并从同一份 manifest 渲染包/服务/副作用映射(其完整性守卫已在检查该 manifest)。 +- 能力 seam 图导入 Cordis 服务收集器,断言每个发现的 harness `ctx.<key>` 都已在 `SERVICE_ROLES` 中分类,且每个已分类的 key 仍然存在。 +- 事件生产者/消费者矩阵标记为 hybrid,因为 subagent 生命周期事件有意使用 `ctx.events.dispatch` 实现逐监听器隔离;这些动态边是显式覆盖而非无声遗漏。 +- `verify-mermaid` 使用 Mermaid 自身的解析器解析仓库中每个 ` ```mermaid ` 围栏,因此语法错误在本地和 CI 的 `doc-sync` 阶段即被捕获,而非在 GitHub 渲染时才显示为损坏的图表。 ## 曾考虑的替代方案 -已提交的图表使用 Mermaid,因为 GitHub 在 Markdown 中原生渲染它,且不引入新的文档构建依赖;密集的多对多数据(如事件生产者/消费者关系)则使用 Markdown 表格。**PlantUML、托管图表服务和生成的 SVG** 曾被考虑,但在 Mermaid 成为瓶颈之前有意不采用。 +已提交的图表使用 Mermaid,因为 GitHub 在 Markdown 中原生渲染它且不引入新的文档构建依赖;密集的多对多数据(如事件生产者/消费者关系)改用 Markdown 表格。**PlantUML、托管图表服务和生成的 SVG** 曾被考虑,但在 Mermaid 成为瓶颈之前有意不采用。 ## 后果 -- 维护者获得了拓扑、seam、事件流、生命周期、应用组合和快照行为的可视化入口。 -- SDK 用户获得了从用例到 package 组合的路径,而不仅仅是自底向上的 package 参考。 -- `doc-sync` 现在包含 `verify-doc-graphs` 和 `verify-mermaid`,因此关系图漂移和 Mermaid 语法错误与其他文档新鲜度门禁一同被捕获。 +- 维护者获得了拓扑、seam、事件流、生命周期、应用组合与快照行为的可视化入口。 +- SDK 用户获得了从用例到包组合的路径,而非仅有自底向上的包参考。 +- `doc-sync` 现在包含 `verify-doc-graphs` 和 `verify-mermaid`,因此关系图漂移和 Mermaid 语法错误与其他文档新鲜度门禁一起被捕获。 - 未来的文件系统和钩子工作有了承载新复杂度的具体位置:文件系统应扩展能力文档和工具目录,钩子应扩展事件矩阵和工具执行流水线。 diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml index 18408700a9..80b4958372 100644 --- a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-cordis-jsdoc-completeness-gate.md: 44a0ddce9c929deac3e03bb421aec1d5145e65ba -2026-07-04-cordis-jsdoc-completeness-gate.zh.md: 6fea7f96a62295bd37e778a0aadd1e9ee6c8f2b4 +2026-07-04-cordis-jsdoc-completeness-gate.zh.md: 073054072748bf6cfed09cdcc222087bcc0ed929 diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md index 6fea7f96a6..0730540727 100644 --- a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md @@ -1,41 +1,41 @@ -# RFC:Cordis 接口的 JSDoc 完整性门禁 - -Status: implemented +# RFC:针对 Cordis 对外服务接口的 JSDoc 完整性门禁 [English](2026-07-04-cordis-jsdoc-completeness-gate.md) | 中文 +Status: implemented + ## 问题 -生成的 Cordis 目录已强制检查事件的 dispatch 模式,但未检查服务与事件契约的完整性。方法可以缺少描述,参数或返回值可以在跨插件 API 接口上不写文档——而这恰恰是 IDE 引导最重要的地方。 +生成的 Cordis 目录此前强制了事件分发模式,但未强制要求完整的服务与事件契约。方法可以缺少描述,参数或返回值可以在跨插件 API 接口上不写文档——而这恰恰是 IDE 引导最重要的地方。 -AGENTS.md 规则("每个导出都有解释语义的 JSDoc")只能靠评审以行文方式检查;本仓库的既定偏好是将不变式编码为机械门禁。"Cordis 服务函数与事件"这一范围有一个精确的机器定义,只有目录生成器知道:事件是 `declare module 'cordis'` 内 `interface Events` 的成员,服务接口是每个 `interface Context` 键所指向的类的公开方法。ESLint 规则看不到这层映射;生成器在每次运行时都会计算它。 +AGENTS.md 中的规则(「每个导出都有解释语义的 JSDoc」)只能靠评审以行文形式检查;本仓库的既定偏好是将不变式编码为机械门禁。「Cordis 服务函数与事件」这一范围有精确的机器定义,只有目录生成器知道:事件是 `declare module 'cordis'` 内 `interface Events` 的成员,服务接口是每个 `interface Context` 键所指向的类的公开方法。ESLint 规则看不到这层映射;生成器在每次运行时计算它。 ## 决策 -扩展 `scripts/gen-cordis-catalog.ts`——同一次遍历、同一个 `@mode` 先例——对其目录化的所有内容强制 JSDoc 完整性。`verify-cordis-catalog` 运行在 `doc-sync` 内部,CI 和 lefthook pre-push 钩子都已执行 `doc-sync`,因此门禁无需新增任何接线(质量门禁原则:单一真源)。 +扩展 `scripts/gen-cordis-catalog.ts`(同一次遍历、同一个 `@mode` 先例),对其编目的所有内容强制 JSDoc 完整性。`verify-cordis-catalog` 在 `doc-sync`(文档同步门禁)内运行,CI 和 lefthook pre-push 钩子都已执行 `doc-sync`,因此门禁无需新增任何接线(质量门禁原则:单一真源)。 契约如下: -- **事件**需要描述文字,并为每个**载荷参数**提供非空 `@param`。载荷参数是签名中承载事件数据的参数;`this` 接收者注解和尾部的 waterfall `next` 免检——`next` 是 dispatch 机制,其语义已由 `@mode waterfall` 标签(及其结构交叉检查)拥有,逐事件重述只是样板。对免检参数写文档是允许的;门禁只检查缺失。 -- **服务类**需要类级 JSDoc,每个公开方法需要描述文字、每个参数一个非空 `@param`,以及一个非空 `@returns`(除非标注的返回类型是 `void`/`Promise<void>`,此时 `@returns` 可选——解析时机可能值得记录——但从不强制要求)。 +- **事件**需要描述性文字,以及为每个**载荷参数**提供非空的 `@param`。载荷参数是携带事件数据的签名参数;`this` 接收者注解和尾部的 waterfall(瀑布式事件) `next` 免检——`next` 是分发机制,其语义已由 `@mode waterfall` 标签(及其结构交叉检查)拥有,逐事件重述只是样板代码。为免检参数写文档是允许的;只有缺失才被检查。 +- **服务类**需要类级 JSDoc,每个公开方法需要描述性文字、为每个参数提供非空的 `@param`,以及非空的 `@returns`——除非标注的返回类型是 `void`/`Promise<void>`(此时 `@returns` 可选——resolve 时机有时值得记录——但从不强制要求)。 - **陈旧标签报错**:`@param` 命名了一个不存在的参数即为违规,与 `@mode` 与签名矛盾的检查对称。标签描述必须非空;超出此范围的语义质量由评审负责。 -- **遍历可检查的显式性**:门禁是纯 AST 遍历(不使用类型检查器),因此服务方法必须显式标注返回类型(推断的返回类型无法分类),接口参数必须是简单标识符(解构模式没有名字供 `@param` 匹配)。 -- **违规聚合**为一条错误信息,列出所有违规项——修复时一次看到全部。此前快速失败的 `@mode` 检查也移入同一份聚合报告,消息文本不变。 +- **遍历可检查的显式性**:门禁是纯 AST 遍历(不使用类型检查器),因此服务方法必须显式标注返回类型(推断的返回类型无法分类),接口参数必须是简单标识符(解构模式没有名称供 `@param` 匹配)。 +- **违规聚合**为一条错误信息,列出所有违规项——修复时一次看到完整清单。此前快速失败的 `@mode` 检查也移入同一份聚合报告,消息文本不变。 -这些标签**仅用于门禁强制**:`parseJsDoc` 现在在遇到第一个块标签时截止描述文字(标准 JSDoc 语义,同时也防止多行标签描述泄漏到目录中成为正文),因此 `@param`/`@returns` 永远不会改变渲染出的目录。 +这些标签**仅用于强制检查**:`parseJsDoc` 现在在遇到第一个块标签时截止描述性文字(标准 JSDoc 语义,同时也防止多行标签描述泄漏到目录中充当正文),因此 `@param`/`@returns` 不会改变渲染出的目录。 -`packages/core/agent/tests/gen-cordis-catalog.spec.ts` 中的负向路径测试用合成 fixture(测试前置数据)驱动 `collectEvents`/`collectServices`,证明每个守卫都能触发且免检规则成立。撰写规则写在根 [AGENTS.md](../../../../AGENTS.md) 约定条目中,与 `@mode` 规则并列。 +`packages/core/agent/tests/gen-cordis-catalog.spec.ts` 中的负路径测试对合成 fixture(测试前置数据)运行 `collectEvents`/`collectServices`,验证每条守卫都会触发且免检规则成立。撰写规则写在根 [AGENTS.md](../../../../AGENTS.md) 的约定条目中,与 `@mode` 规则并列。 ## 曾考虑的替代方案 -- **ESLint 规则**:看不到范围的机器定义(哪些 `interface Events` 成员、哪些 `ctx.<key>` 类构成 Cordis 接口);目录生成器在每次运行时恰好计算这层映射,因此门禁放在那里。 -- **将标签渲染到目录中**:曾考虑将服务部分重构为逐方法条目,但有意推迟:方法文档的消费场景是源码 JSDoc 加 IDE 悬浮提示,目录保持索引定位。 -- **逃生标签**:不设。接口面小且经过策划(采纳时 12 个服务、57 个方法、27 个事件),重点在于检查不可豁免。 +- **ESLint 规则**:无法看到该范围的机器定义(哪些 `interface Events` 成员、哪些 `ctx.<key>` 类构成 Cordis 对外服务接口);目录生成器在每次运行时恰好计算这层映射,因此门禁放在那里。 +- **将标签渲染到目录中**:曾考虑将服务部分重构为逐方法条目,但有意推迟:方法文档的消费场景是源码 JSDoc 加 IDE 悬停,目录保持索引定位。 +- **逃逸标签**:不设。该接口面小且经过策展(采纳时 12 个服务、57 个方法、27 个事件),要点在于检查不可豁免。 ## 后果 -- 新增事件或服务方法如果参数或返回值未写文档,就无法合入:生成器拒绝重新生成,`verify-cordis-catalog` 在 pre-push 和 CI 中失败。采纳时发现的约 139 处缺口在同一个变更中补齐,门禁以绿色状态落地。 -- 服务接口必须显式标注返回类型并使用标识符参数。两项约束在采纳时均未构成负担(所有方法已有标注;不存在解构的 seam 参数);二者现在都是承重要求,违反时会被机械发现。 -- AGENTS.md 的通用 JSDoc 规则("一行能说清就写一行")在此接口上获得一条更严格的特例:只有当方法无参数且返回 void 时,一行摘要才仍然足够。 -- 对 `next` 或 `this` 写 `@param` 合法但不检查——这是有意的不对称:门禁强制载荷契约,拒绝索要样板。 -- 标签不改变渲染出的目录(正文在第一个块标签处截止)。如果日后需要方法级渲染,那是目录设计的独立决策,不是本门禁的缺口。 +- 新增事件或服务方法时,若参数或返回值未写文档则无法落地:生成器拒绝重新生成,`verify-cordis-catalog` 在 pre-push 和 CI 中失败。采纳时发现的约 139 处缺口在同一个变更中补齐,门禁以绿色状态落地。 +- 服务接口必须显式标注返回类型并使用标识符参数。两项约束在采纳时均未构成限制(所有方法已有标注;不存在解构的 seam 参数);但二者现在是承重要求,违反时会被机械检测到。 +- AGENTS.md 中通用的 JSDoc 规则(「一行能说清就用一行」)在此接口上获得了更严格的特例:仅当方法无参数且返回 void 时,一行摘要才足够。 +- 为 `next` 或 `this` 写 `@param` 合法但不检查——这是有意的不对称:门禁强制载荷契约,拒绝要求样板代码。 +- 渲染出的目录不受这些标签影响(正文在第一个块标签处截止)。如果后续需要方法级渲染,那是一个独立的目录设计决策,而非本门禁的缺口。 diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml index 5d1764cea6..d6465ad8c1 100644 --- a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-doc-tiers-and-budgets.md: ca9da847849f61f2fb244932e657cca8fec69696 -2026-07-04-doc-tiers-and-budgets.zh.md: 37447d11de181a007bcea23e29084aefd97b1ab5 +2026-07-04-doc-tiers-and-budgets.zh.md: ae34e3f04d7986f78d1b3ceeaacb3bc4c7bc64f5 diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md index 37447d11de..ae34e3f04d 100644 --- a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md @@ -1,28 +1,28 @@ # RFC:文档分层、预算与上限门禁 -Status: implemented - [English](2026-07-04-doc-tiers-and-budgets.md) | 中文 +Status: implemented + ## 问题 -尽管已有写作指导,常设文档仍然积累了重复的规则、重述的事件、重复的 package 地图和陈旧的 RFC 摘要。由于仅靠评审无法阻止这种膨胀,仓库需要在文档分类体系之外再加一道机械化的预算。 +尽管已有写作指导,常设文档仍然积累了重复的规则、重述的事故、重复的包(package)映射和陈旧的 RFC 摘要。仅靠评审无法阻止这种膨胀,因此仓库需要在文档分类体系之外增加一道机械化的预算约束。 ## 决策 -- **分层分类体系,每条事实只有一个归属。** [docs/AGENTS.md](../../../AGENTS.md) 是文档标准:它为每个 Markdown 层级指定唯一职责(常设指令、系统地图、类型目录、决策记录、事件故事、实操手册(cookbook)、package 契约、生成目录、工作流),禁止在归属层级之外重述事实(应改为链接),并附带一份在撰写或评审任何文档时使用的冗余检查清单。 -- **窄范围、硬约束的预算门禁。** [scripts/verify-doc-budgets.ts](../../../../scripts/verify-doc-budgets.ts) 加入 doc-sync:凡列入 [scripts/doc-budgets.manifest.json](../../../../scripts/doc-budgets.manifest.json) 的文档都必须低于其字数上限(`wc -w` 语义,整个文件),且已设预算的文件若缺失也会使门禁失败,防止重命名时预算被静默遗留。范围有意仅限于容易膨胀的常设文档:根目录与子树的 `AGENTS.md`、`architecture.md`、`packages/README.md`,以及它们将内容分流到的常设策略文档(`docs/testing.md`、`docs/defensive-patterns.md`)。参考文档、RFC 和 package README 不设预算:当每一行都是事实时,长度是合理的,由评审加冗余检查清单管控。 -- **上限是只进不退的执行红线。** 上限设定在文档当前大小的至少 5% 以上(留出操作余量,使日常措辞修改不会触发门禁,而真正的膨胀仍会被拦截),并随着文档被压缩到目标预算(根 `AGENTS.md` ≤ 1,500 词;`architecture.md` ≤ 1,800;子树 `AGENTS.md` ≤ 600;`packages/README.md` ≤ 600)而保持该余量向下收紧——与[翻译配对 `required` 清单](2026-07-02-bilingual-docs-and-pairing-gate.md)的推进机制相同。门禁变红时,修复方式是按分类体系迁移或精简内容;只有在 PR 描述中给出明确理由时才允许提高上限,manifest diff 本身即为可评审的动作。 -- **轻量工作流 skill,契约在文档中。** [.agents/skills/dsh-doc-standards](../../../../.agents/skills/dsh-doc-standards/SKILL.md) 承载归位/审计/红灯修复工作流,并将文档标准作为真源——与 [dsh-translate-docs](../../../../.agents/skills/dsh-translate-docs/SKILL.md) 对 i18n 契约的分工方式相同。 +- **分层分类体系,每条事实只有一个归属地。** [docs/AGENTS.md](../../../AGENTS.md) 是文档标准:它为每个 Markdown 层级指定唯一职责(常设指令、系统地图、类型目录、决策记录、事故叙事、实操手册、逐包契约、生成目录、工作流),禁止在归属层级之外重述事实(应以链接代替),并附带一份在撰写或评审任何文档时使用的冗余检查清单。 +- **窄范围、硬约束的预算门禁。** [scripts/verify-doc-budgets.ts](../../../../scripts/verify-doc-budgets.ts) 加入 `doc-sync`(文档同步门禁):[scripts/doc-budgets.manifest.json](../../../../scripts/doc-budgets.manifest.json) 中列出的每篇文档都必须低于其字数上限(`wc -w` 语义,整个文件),且受预算约束的文件如果缺失也会导致门禁失败,防止重命名后预算被静默遗留。范围刻意限定为容易膨胀的常设文档:根目录和子树的 `AGENTS.md`、`architecture.md`、`packages/README.md`,以及它们将内容分流到的常设策略文档(`docs/testing.md`、`docs/defensive-patterns.md`)。参考文档、RFC 和 package README 不设预算:当每一行都是事实时,长度是合理的,由评审加冗余检查清单来管控。 +- **上限是只进不退的执行红线。** 上限设定为文档当前字数的至少 105%(留出工作余量,使日常措辞调整能通过,而真正的膨胀仍会触发门禁),并随着文档被精简到目标预算而同步下调、保持该余量(根 `AGENTS.md` ≤ 1,500 词;`architecture.md` ≤ 1,800;子树 `AGENTS.md` ≤ 600;`packages/README.md` ≤ 600)。推进机制与[翻译配对的 `required` 清单](2026-07-02-bilingual-docs-and-pairing-gate.md)相同。门禁变红时,修复方式是按分类体系迁移或压缩内容;只有在 PR(Pull Request)描述中给出明确理由时才允许提高上限,manifest(元数据清单)的 diff 本身即为可评审的动作。 +- **轻量工作流 skill(技能),契约在文档中。** [.agents/skills/dsh-doc-standards](../../../../.agents/skills/dsh-doc-standards/SKILL.md) 承载放置/审计/红灯修复工作流,并将文档标准作为真源,与 [dsh-translate-docs](../../../../.agents/skills/dsh-translate-docs/SKILL.md) 对 i18n 契约的分工方式一致。 ## 曾考虑的替代方案 -- **仅靠 skill 与评审纪律,不设门禁**:否决。上述膨胀正是在既有的现状规则和评审者注意力下发生的;一条没有机械后盾的行文规则在这里已被证明守不住,而本仓库自身的[质量门禁立场](2026-06-11-quality-gates.md)说的是:值得保持的不变式就值得编码。 -- **对所有文档层级设置宽泛门禁**:否决。一刀切的上限恰恰惩罚了那些正当的长文档(如功能矩阵或类型目录,每一行都是事实,例如 `packages/ui/acp/acp-feature-support.md`),并产生逐文件的例外修改,训练贡献者无脑批准上调。 -- **将标准放在 skill 内部**:否决。契约放在文档中,工作流放在 skill 中;如果标准被塞进 SKILL.md,那些不调用该 skill 而直接编辑文档的 agent 就看不到它,而 `docs/AGENTS.md` 已经作为子树指令被加载给所有在 `docs/` 下工作的人。 +- **仅靠 skill 和评审纪律,不设门禁**:否决。上述膨胀正是在现行规则和评审注意力已经存在的情况下发生的;一条没有机械后盾的行文规则在此处已被证明无法维持,而本仓库自身的[质量门禁立场](2026-06-11-quality-gates.md)认为值得保持的不变式就值得编码。 +- **对所有文档层级全面设限**:否决。一刀切的上限恰好惩罚了那些正当的长文档(如特性矩阵或类型目录,每一行都是事实,例如 `packages/ui/acp/acp-feature-support.md`),并产生逐文件的例外变更,训练贡献者机械地批准提限。 +- **将标准放在 skill 内部**:否决。契约归文档,工作流归 skill;如果标准被塞进 SKILL.md,那些不调用该 skill 而直接编辑文档的 agent(智能体)就看不到它,而 `docs/AGENTS.md` 已经作为子树指令被任何在 `docs/` 下工作的人加载。 ## 后果 -- 向已设预算的文档添加内容现在需要置换:将新增内容迁移到其分类归属处并留下指针,或精简既有行文为其腾出空间。只增不减会导致 CI 失败。 -- 将文档压缩到目标预算的重写以堆叠的后续 PR 落地,每个合并时都将 manifest 中的上限向下收紧;在各自落地之前,文档的冻结上限仅阻止进一步膨胀。 -- 字数是一个粗糙的代理指标,这是有意接受的:它无法判断质量,但它恰好在内容被添加的那一刻强制触发迁移决策——而那正是作者拥有足够上下文来正确归位内容的时刻。 +- 向受预算约束的文档添加内容现在需要置换:将新增内容迁移到其分类体系归属地并留下指针,或压缩现有行文来腾出空间。只增不减会导致 CI 失败。 +- 精简到目标预算的重写以堆叠的后续 PR 落地,每次合并时同步下调 manifest 中的上限;在各自落地之前,文档冻结的上限仅阻止进一步膨胀。 +- 字数是一个粗糙的代理指标,这是有意接受的:它无法判断质量,但它在内容被添加的那一刻强制触发迁移决策,而那正是作者拥有足够上下文来正确放置内容的时刻。 diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml index 814ca38546..8d410ae5f8 100644 --- a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-generate-rfc-index-tables.md: 6a8888eda8b7cf7105a44802774bf49d6463952d -2026-07-04-generate-rfc-index-tables.zh.md: 42ae64306aa1d5cf9117ca2b4d698a5d8effdeec +2026-07-04-generate-rfc-index-tables.zh.md: aad1652edc9de81a70a7a391700f63be9499035c diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md index 42ae64306a..aad1652edc 100644 --- a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md @@ -1,34 +1,34 @@ # RFC:生成 RFC 索引表 -Status: implemented - [English](2026-07-04-generate-rfc-index-tables.md) | 中文 +Status: implemented + ## 问题 -RFC 索引中按生命周期/按类别的表格所列信息完全可推导:RFC 的路径编码了生命周期与类别,文件名编码了首次提出日期,H1 标题即为标题。手工维护这些事实的副本恰恰是本仓库文档中冲突最频繁的热点:每一波提案都向同几行追加行,因此并行的 RFC 分支恰好在此处冲突,而在其他所有地方都没有分歧;每次冲突都要手动合并那些文件系统本已知晓内容的行。[分类 RFC](2026-06-20-rfc-classification.md) 最初为了策展目的保留手写索引,但 README 中真正需要策展的部分是行文,而行文从不冲突;冲突的只有机械表格。 +RFC 索引中按生命周期/按分类的表格所列信息完全可以推导:RFC 的路径编码了生命周期与分类,文件名编码了首次提出日期,H1 标题承载了标题文本。这些信息的手工维护副本也是仓库中冲突最频繁的文档热点:每一波提案都在同几行后追加新行,因此并发的 RFC 分支恰好在此处冲突,而其他地方完全一致;每次冲突都要手工合并那些文件系统本已知晓的行。[分类 RFC](2026-06-20-rfc-classification.md) 最初为了可策展性而保留手写索引,但 README 中真正需要策展的是行文,而行文从不冲突;冲突的只有机械表格。 ## 决策 -保留策展行文;生成列表。表格位于 [`docs/rfc/INDEX.md`](../../INDEX.md),是一个**完全生成的文件**;策展行文留在 README.md 中,README.md 不包含任何索引行。[`scripts/rfc-index.ts`](../../../../scripts/rfc-index.ts) 是共享的真源:树遍历器(拥有封闭的生命周期/类别集合与结构规则,包括 H1 可解析的要求)和渲染器(行来自 H1 标题并去除 `RFC: ` 前缀,加上文件名日期,按日期再按文件名排序,以 `### {Class}` 分节、按规范类别顺序分组)。两个轻量消费方共享它: +保留策展行文;生成列表。表格位于 [`docs/rfc/INDEX.md`](../../INDEX.md),是一个**完全生成的文件**——策展行文留在 README.md 中,README.md 不包含任何索引行。[`scripts/rfc-index.ts`](../../../../scripts/rfc-index.ts) 是共享的真源:树遍历器(拥有封闭的生命周期/分类集合与结构规则,包括对可解析 H1 的要求)和渲染器(行来自 H1 标题并去掉 `RFC: ` 前缀,加上文件名日期,按日期再按文件名排序,以 `### {Class}` 分节、按规范分类顺序分组)。两个轻量消费方共享它: - [`scripts/gen-rfc-index.ts`](../../../../scripts/gen-rfc-index.ts)(`pnpm run gen-rfc-index`)从目录树完整重写 INDEX.md。 -- [`scripts/verify-rfc-classification.ts`](../../../../scripts/verify-rfc-classification.ts)(doc-sync 的一个成员)检查结构,断言已提交的 INDEX.md 与新鲜渲染结果逐字节一致(与 `gen-cordis-catalog`/`verify-cordis-catalog` 模式相同),并拒绝在策展 README 中出现索引格式的行。新鲜度检查涵盖了索引完整性检查:从磁盘生成的表格在定义上就是完整且标题正确的。 +- [`scripts/verify-rfc-classification.ts`](../../../../scripts/verify-rfc-classification.ts)(doc-sync(文档同步门禁)的一个成员)检查结构,断言已提交的 INDEX.md 与新鲜渲染结果逐字节一致(`gen-cordis-catalog`/`verify-cordis-catalog` 模式),并拒绝在策展 README 中出现索引格式的行。新鲜度检查涵盖了索引完整性检查:从磁盘生成的表格在定义上就是完整的、标题正确的。 -添加、移动或删除一个 RFC 只需编辑 RFC 文件本身并运行生成器;分类 RFC 的「否决替代方案」记录中带有取代关系的交叉链接。 +添加、移动或删除一个 RFC 只需编辑 RFC 文件本身并运行生成器;分类 RFC 的「已否决替代方案」记录中带有替代关系的交叉链接。 ## 曾考虑的替代方案 ### 为什么不在 README.md 内使用标记分隔区域? -最初落地的形态:生成器在 README.md 中的 `gen-rfc-index` 标记注释之间、每个 `## {Lifecycle}` 标题下拼接表格。在 README 同时吸收了文件内格式契约([统一格式 RFC](2026-07-05-uniform-rfc-format.md))之后,被整文件 INDEX.md 方案取代:一个门面 README 承载数百行生成行,会淹没其策展行文;而拼接机制(标记对、标题检查、区域外行检测)的存在只是为了保护策展文本——专用的生成文件根本不包含策展文本。 +最初落地的形态是:生成器将表格拼接到 README.md 中 `gen-rfc-index` 标记注释之间、各 `## {Lifecycle}` 标题之下。在 README 同时吸收了文件内格式契约([统一格式 RFC](2026-07-05-uniform-rfc-format.md))之后,被整文件 INDEX.md 方案取代:一个门面 README 承载数百行生成内容会淹没其策展行文,而拼接机制(标记对、标题检查、区域外行检测)的存在仅仅是为了保护策展文本——专用的生成文件根本不包含这类文本。 -### 为什么不采用纯校验模式? +### 为什么不采用纯校验器模式? -纯校验能捕获错误,但每次提案编辑仍然要在手工维护的表格中触碰共享热点;对于一行纯机械内容,校验失败比生成器更令人烦恼:作者已经命名并放置了文件,索引副本不增加任何信息。这与 [package-inventory 提案](../../proposed/process/2026-06-20-discover-package-inventory.md) 对 tsconfig references 和 knip stanzas 所做的「手工列表 vs. 推导」判断相同——应用于这张确实会冲突的列表。 +校验器能捕获错误,但每次提案编辑仍然要在手工维护的表格中触碰共享热点;对于纯机械的行,校验器失败比生成器更令人烦恼:作者已经命名并放置了文件,索引副本不增加任何信息。这与 [package-inventory 提案](../../proposed/process/2026-06-20-discover-package-inventory.md) 对 tsconfig references 和 knip stanzas 所做的手写列表与推导之间的判断一致——应用于这张确实会冲突的列表。 ## 后果 - 生成文件是显式的:其横幅标注了生成器名称,文件内没有需要保护的策展区域,且生成器在目录树结构无效时拒绝运行。 -- 格式错误或缺失的 H1 在生成器和门禁中都是硬错误:H1 现在是承重的,它是索引标题的来源。 -- 并行的 RFC 分支通过重新运行生成器来解决索引冲突,而非手动合并行。 +- 格式错误或缺失的 H1 在生成器和门禁中都是硬错误——H1 现在是索引标题的承重来源。 +- 并发的 RFC 分支通过重新运行生成器解决索引冲突,从不手工合并行。 diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml index d824b18b5d..5851ab8d1c 100644 --- a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-persistence-log-catalog.md: f8f831ca0470cf3b5c7634550115e67f7deac840 -2026-07-04-persistence-log-catalog.zh.md: d8cd5f74e24968fa2ad01f128dafe8c867f3406c +2026-07-04-persistence-log-catalog.zh.md: 1daa76e2b23484ad6434f6a55482672abf456eb7 diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md index d8cd5f74e2..1daa76e2b2 100644 --- a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md @@ -6,31 +6,31 @@ Status: implemented ## 问题 -`SessionEventMap` 是磁盘上的词汇(vocabulary),但其声明分散在所属的 session 包与声明合并中。生成式持久化目录是每个事件及其 payload 的唯一参考;手工维护的表格会漂移,已被移除。这些记录不是 Cordis 事件:观察者通过唯一的 `session/event` 总线事件接收它们,因此 Cordis 目录无法覆盖。生成器会发现所有声明,doc-sync(文档同步门禁)新鲜度门禁会拒绝遗漏或陈旧的输出。 +`SessionEventMap` 是磁盘上的词汇,但其声明分散在拥有它的 session 包(package)与声明合并中。生成式持久化目录是所有事件与 payload 的唯一参考;手工维护的表格会漂移,已被移除。这些记录不是 Cordis 事件,观察者通过单一的 `session/event` 总线事件接收它们,因此 Cordis 目录无法覆盖。生成器发现所有声明,doc-sync(文档同步门禁)的新鲜度门禁拒绝遗漏或陈旧的输出。 ## 决策 -从源码生成 `docs/persistence-catalog.md`,配以新鲜度门禁,作为第四个参考面:持久化会话日志可以包含的*记录*,与 Cordis 目录(接线)、核心数据结构(词汇)和工具目录(工具)互补。 +从源码生成 `docs/persistence-catalog.md`,配合新鲜度门禁,作为第四个参考面:持久化会话日志可以包含的*记录*,与 Cordis 目录(接线)、核心数据结构(词汇)和工具目录(工具)互补。 -`gen-persistence-catalog.ts` 使用 TypeScript AST 扫描所有所属的和声明合并的 `SessionEventMap`。它渲染源码 JSDoc、payload 类型、派生的 surface 徽章、参考链接和源码位置。doc-sync 新鲜度检查会拒绝任何词汇变更后未重新生成目录的情况。 +`gen-persistence-catalog.ts` 使用 TypeScript AST 扫描所有拥有方与声明合并的 `SessionEventMap`。它渲染源码 JSDoc、payload 类型、派生的 surface 徽章、参考链接与源码位置。doc-sync 新鲜度检查会拒绝任何词汇变更后未重新生成目录的情况。 具体选择: -- **JSDoc 完整性,强制执行。** 每个成员必须携带描述性文字:JSDoc 即为目录条目,与 Cordis 目录对总线事件施加的强制函数相同。成员上的 `@mode` 标签是硬错误:dispatch mode 属于 Cordis 总线事件,日志事件没有 mode;该标签会被误读为「此事件以 mode X 在总线上触发」。违规项聚合为一条错误,列出所有违规者。 -- **surface 徽章由派生得出,而非手工列举。** `SurfaceEventType`(产生 LLM 消息且可能携带 `surfaceOp` 的子集)从所属包中的 union 声明解析而来;union 成员如果命名了一个未声明的事件,则为硬错误(否则一个陈旧的 union 成员会静默地不标注任何事件)。其余一律渲染为 **log-only**。 -- **专用围栏。** payload 块使用 ` ```ts persistence-catalog ` 信息字符串,`doc-typecheck` 识别并跳过它,不计入 opt-out 比例——与 `ts cordis-catalog` 的处理方式相同(裸 payload 片段不能独立编译)。 -- **仓库范围。** 目录枚举本仓库中的包,与兄弟目录的 packages-only 范围一致;下游插件可以合并更多事件类型,但它们在设计上不在目录范围内。遍历过程用硬错误保护自身假设:所属的顶层 `interface SessionEventMap` 必须是 `@deepseek-ai/dsh-session` 中唯一的导出声明(一个无关的、局部的或重复的同名接口不能被当作磁盘词汇编入目录);任何声明不得携带 `extends`(继承的键会加入 `keyof SessionEventMap` 却没有对应的目录行);每个成员必须是带有显式 payload 类型的属性签名(方法形式的成员会加入 `keyof` 却被静默遍历跳过);跨声明的重复成员会失败。 +- **JSDoc 完整性,强制执行。** 每个成员必须带有描述性文字——JSDoc 即为目录条目,与 Cordis 目录对总线事件施加的强制机制相同。成员上的 `@mode` 标签是硬错误:dispatch mode 属于 Cordis 总线事件,日志事件没有 mode,该标签会被误读为「此事件以模式 X 在总线上触发」。违规项聚合为一条错误,列出所有违规者。 +- **surface 徽章由派生得出,而非手工列举。** `SurfaceEventType`(产生 LLM(大语言模型)消息且可能携带 `surfaceOp` 的子集)从拥有方包中的 union 声明解析;如果 union 成员命名了一个未声明的事件,则为硬错误(否则陈旧的 union 成员会静默地不标注任何内容)。其余一律渲染为 **log-only**。 +- **专用围栏。** payload 块使用 ` ```ts persistence-catalog ` 信息字符串,`doc-typecheck` 识别并跳过它,不计入 opt-out 比例——与 `ts cordis-catalog` 的处理方式相同(裸 payload 片段无法独立编译)。 +- **仓库范围。** 目录枚举本仓库中的包,与兄弟文档的 packages-only 范围一致;下游插件可以合并更多事件类型,它们在设计上不在目录范围内。遍历过程用硬错误保护自身假设:拥有方的顶层 `interface SessionEventMap` 必须是 `@deepseek-ai/dsh-session` 中唯一的导出声明(无关的、局部的或同名重复的接口不能被当作磁盘词汇编入目录);任何声明不得携带 `extends`(继承的键会加入 `keyof SessionEventMap` 却没有对应的目录行);每个成员必须是带有显式 payload 类型的属性签名(方法形式的成员会加入 `keyof` 却在静默遍历中被漏过);跨声明的重复成员也会失败。 -这取代了手工副本:session.md 的 `hook/*` 表格、compact README 的事件表格、hook-protocol README 的 payload 列表,以及 session README 的名称列表现在链接到目录,而非重述 payload(周围的语义行文保留原位)。hook-protocol 合并成员上两个多余的 `@mode emit` 标签已被移除——新门禁将其拒绝为它们本来就是的类别错误。 +本方案取代了手工副本:session.md 的 `hook/*` 表格、精简版 README 的事件表格、hook-protocol README 的 payload 条目列表,以及 session README 的名称列表现在链接到目录,而不再重述 payload(周围的语义说明文字保留原位)。hook-protocol 合并成员上的两个误加的 `@mode emit` 标签已被移除——新门禁将它们作为类别错误拒绝。 ## 曾考虑的替代方案 -- **基于启动的生成器(如工具目录的方式)**:日志词汇完全是静态的,AST 遍历无需启动任何东西即可读取全部真相。 -- **保留手工副本**:手工副本只能检查作者已经写下的名称;目录落地时 session README 的合并说明已经漂移。 +- **基于启动的生成器(类似工具目录)**:日志词汇完全是静态的,AST 遍历无需启动任何东西即可读取全部真相。 +- **保留手工副本**:手工副本只能检查作者已经写下的名称;目录落地时,session README 的合并说明已经漂移。 ## 后果 -- 目录不可能漂移:词汇变更而已提交文件未反映的,`verify-persistence-catalog` 在 pre-push 钩子和 CI 中会失败;新合并的事件如果没有 JSDoc,生成器直接报错——插件不能再添加未文档化的磁盘记录类型。 -- 事件描述有唯一归属地:声明处的 JSDoc。JSDoc 写得薄,目录条目就薄,这对作者形成在源头写文档的压力。 +- 目录不会漂移:词汇变更若未反映在已提交的文件中,`verify-persistence-catalog` 会在 pre-push 钩子和 CI 中失败;新合并的事件若缺少 JSDoc,生成器直接报错——插件不再能添加未文档化的磁盘记录类型。 +- 事件描述有唯一归属地,即声明处的 JSDoc;JSDoc 写得单薄,目录条目就单薄,这迫使作者在源头做好文档。 - `SurfaceEventType` union 现在对文档具有结构性承载作用:重命名事件而不更新 union(或反过来)会导致生成器失败,而不仅仅是编译器失败。 -- 徽章派生假设 union 始终是一组封闭的字符串字面量且只有一个所有者;如果重构偏离了这一形状,必须在同一个变更中更新生成器。 +- 徽章派生假设 union 始终是一组封闭的字符串字面量且只有一个拥有方;如果重构偏离了这一形状,必须在同一个变更中更新生成器。 diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml index bb326da2d8..a5e22d0911 100644 --- a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-05-uniform-rfc-format.md: f67c61c0b627950cf07e7d57672324308a9462ec -2026-07-05-uniform-rfc-format.zh.md: a11cba1c343f150a67c1af4a04a8d89480185207 +2026-07-05-uniform-rfc-format.zh.md: b175c2d5b7537e793a61c95b6524d08bc4216384 diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md index a11cba1c34..b175c2d5b7 100644 --- a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md @@ -1,30 +1,30 @@ -# RFC:为 RFC 统一一种有门禁保障的文件内格式 - -Status: implemented +# RFC:RFC 的统一受门禁约束的文件内格式 [English](2026-07-05-uniform-rfc-format.md) | 中文 +Status: implemented + ## 问题 -RFC 的路径已编码了生命周期与分类,但文件内容仍然混杂着不同的标题风格、状态格式、ADR 模板与提案模板,以及已实施记录中残留的提案时期章节。作者复制手边找到的任何邻居文件作为模板,而生命周期迁移可以跳过必要的改写,因为没有门禁强制执行文件内契约。 +RFC 的路径已经编码了生命周期和分类,但文件内容仍然混杂着不同的标题风格、状态格式、ADR 与 proposal 模板,以及已实现记录中残留的 proposal 时期的章节。作者随手复制找到的任何邻近文件,生命周期迁移时可以跳过必要的改写,因为没有门禁强制执行文件内契约。 ## 决策 -[README.md § The file format](../../README.md#the-file-format) 即为文件内契约:头部块(`# RFC: <title>` 加上不含日期、与所在文件夹一致的 `Status:` 枚举,其唯一内容是否决原因);按生命周期区分的正文骨架(所有阶段都以 `Problem` 开头;`proposed/` 中使用 `Proposal`/`Acceptance criteria`/`Risks`;`implemented/` 中使用现在时的 `Decision`/`Consequences` 且禁止提案时期标题;`rejected/` 中冻结提案形态);强制的 `Alternatives considered` 章节;以及规范的章节词汇表——在这些固定章节之间,自定义的技术章节保持自由格式。`pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../../../scripts/verify-rfc-format.ts))作为 doc-sync(文档同步门禁)的一环强制执行每一条机械化条款,因此跳过改写的生命周期迁移现在会导致 CI 失败,而非依赖评审者的记忆。 +[README.md § The file format](../../README.md#the-file-format) 即文件内契约:头部块(`# RFC: <title>` 加上无日期、与所在文件夹一致的 `Status:` 枚举,唯一的正文内容是 rejection reason);按生命周期区分的正文骨架(所有阶段都以 `Problem` 开头;`proposed/` 中为 `Proposal`/`Acceptance criteria`/`Risks`;`implemented/` 中为现在时态的 `Decision`/`Consequences` 且禁止 proposal 时期的标题;`rejected/` 中冻结 proposal 形态);必须包含 `Alternatives considered` 章节;以及规范的章节词汇表,其间的自定义技术章节保持自由形式。`pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../../../scripts/verify-rfc-format.ts))作为 doc-sync(文档同步门禁)的一环强制执行每条机械化条款,因此生命周期迁移时跳过改写现在会让 CI 失败,而不是依赖评审者的记忆。 -整个语料库在定义格式的同一个变更中完成了规范化——这是预发布阶段的立场:不设过渡期,不容忍双格式并存。唯一的祖父条款针对内容而非格式:替代方案只记录已有的,不凭空编造;因此如果一篇格式定义之前的 RFC 的替代方案无法从记录中重建,它会携带 `rfc-format: alternatives-not-recorded` 注释,门禁仅对日期早于本 RFC 的文件接受该注释。 +整个语料库在定义格式的同一个变更中完成了规范化,这是预发布阶段的立场:没有过渡期,不容忍双格式并存。唯一的祖父条款针对内容而非格式:替代方案是记录下来的,不是凭空编造的;因此如果一篇格式定义前的 RFC 的替代方案无法从记录中重建,它会携带 `rfc-format: alternatives-not-recorded` 这条精确注释,门禁仅对日期早于本 RFC 的文件接受该注释。 ## 曾考虑的替代方案 -- **完全刚性模板**(每个生命周期一套固定章节顺序,所有 RFC 重构以适配):否决。大型设计 RFC 携带八到十五个自定义技术章节(包拓扑、协议格式契约、schema),这些是承重内容而非漂移;刚性顺序会迫使当下进行破坏性改写,并永远与模板对抗。 -- **仅规范化头部**(H1 与 Status,正文不动):否决。技术债标记指出的正是*正文*的体裁分裂,让 `Context`/`Decision` 与 `Problem`/`Proposal` 无限期并存什么也解决不了。 -- **不设 Status 行**(文件夹本身就是状态;三篇最新的格式定义前 RFC(及其中一篇的中文对侧文件)省略了该行):否决,保留自描述文件。当初促使去掉该行的漂移风险,已被「门禁将该行与文件夹做一致性校验」所消除。 -- **带日期的状态**(`Status: implemented (accepted YYYY-MM-DD)`):否决。接受日期属于叙述性历史,写作规则将其排除在文档之外;文件名承载首次提出日期,git 承载其余信息,门禁能检查日期格式但永远无法检查其真实性。 -- **裸 `# <title>` H1**:否决。`RFC: ` 前缀是语料库中的多数形式,且在文件脱离目录树阅读时能自描述体裁;索引生成器会剥离它,因此索引行无论哪种写法都一样。 -- **`## What we give up` 作为已实施记录的收尾章节**(README 自身用来描述 RFC 所记录内容的措辞):否决。它只命名了代价,而诚实的后果章节同时记录权衡所换来的收益。 -- **约定而无门禁**(写下契约,靠评审强制执行):否决。slop checklist 已通过约定禁止在 `implemented/` 中使用规范体措辞,而十九个文件展示了纯靠约定在这里能达到什么效果。 -- **独立的 `FORMAT.md` 契约文件**:最初落在此处;在生成索引迁出至 [INDEX.md](../../INDEX.md) 后折入 README.md:表格移走后 README 重新有了空间,一个前门同时承载布局、分类与格式,优于将契约拆分到两个文件。 +- **完全刚性的模板**(每个生命周期一个固定章节序列,所有 RFC 重构以适配):否决。大型设计 RFC 包含八到十五个自定义技术章节(包拓扑、协议格式契约、schema),这些是承重内容而非漂移;刚性序列会立即强制破坏性改写,并永远带来与模板的对抗。 +- **仅规范化头部**(H1 和 Status,正文不动):否决。债务标记指出的是*正文*的体裁分裂,让 `Context`/`Decision` 与 `Problem`/`Proposal` 无限期并存什么也解决不了。 +- **不设 Status 行**(文件夹本身就是状态;格式定义前最新的三篇 RFC(以及其中一篇的中文对侧文件)省略了该行):否决,保留自描述文件。省略 Status 行的动机是防止漂移,而将该行与文件夹做门禁校验即可消除漂移风险。 +- **带日期的 Status**(`Status: implemented (accepted YYYY-MM-DD)`):否决。接受日期属于叙述性历史,写作规则将其排除在文档之外;文件名承载首次提出日期,git 承载其余信息;门禁能检查日期格式,但永远无法检查其真实性。 +- **裸 `# <title>` H1**:否决。`RFC: ` 前缀是语料库中的多数形式,且在文件脱离目录树被阅读时能自描述体裁;索引生成器会剥离前缀,因此索引行无论哪种写法都一样。 +- **`## What we give up` 作为 implemented 的结尾章节**(README 自身对 RFC 记录内容的措辞):否决。它只命名了代价,而诚实的后果章节同样记录这笔权衡换来了什么。 +- **只有约定没有门禁**(写下契约,靠评审强制执行):否决。slop checklist 已经通过约定禁止在 `implemented/` 中使用 spec 语气,而十九个文件展示了仅靠约定在此处能达到什么效果。 +- **独立的 `FORMAT.md` 契约文件**:最初的落地位置;在生成索引迁出到 [INDEX.md](../../INDEX.md) 之后折入 README.md:表格移走后 README 重新有了空间,一个前门同时承载布局、分类和格式,优于将契约拆分到两个文件。 ## 后果 -每篇 RFC 现在多了少许结构成本,而强制的 `Alternatives considered` 章节是有意为之的摩擦:一个不记录被否决方案的决策,会招来 RFC 本应防止的反复讨论。格式定义前的 RFC 若其替代方案无法重建,则永久携带祖父条款注释——这是记录上的诚实空白,而非编造的理由。doc-sync 新增一道门禁,在生命周期文件夹之间迁移 RFC 现在是迁移时的实际工作(即迁移本就欠下的正文改写),而非无人追踪的延后清理。三十九个技术债标记已全部消除,由它们等待的模板所解决。 +每篇 RFC 现在需要略多一些结构,而必须包含 `Alternatives considered` 章节是刻意的摩擦:一个没有记录被否决方案的决策,会招致 RFC 本来就是为了防止的重新争论。格式定义前的 RFC 如果替代方案无法重建,则永久携带祖父条款注释,这是记录上的诚实缺口,而非编造的理由。`doc-sync` 增加一道门禁,将 RFC 在生命周期文件夹之间迁移现在是迁移时的实际工作(即迁移本就欠下的正文改写),而非无人追踪的延后清理。三十九个债务标记已全部消除,由它们等待的模板所解决。 diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml index dd08d60974..b79ff4cf97 100644 --- a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-06-export-surface-jsdoc-gate.md: fd255cc6212d7f6f919ad23f999fa68b01478a73 -2026-07-06-export-surface-jsdoc-gate.zh.md: 02a5c2682095c66818a51cc14fd565111b7e6e80 +2026-07-06-export-surface-jsdoc-gate.zh.md: 796b5bb8f3a2a890986c73511bb63e167c831a5f diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md index 02a5c26820..796b5bb8f3 100644 --- a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md @@ -1,45 +1,45 @@ # RFC:导出表面 JSDoc 门禁 -Status: implemented - [English](2026-07-06-export-surface-jsdoc-gate.md) | 中文 +Status: implemented + ## 问题 -[cordis JSDoc 完整性门禁](2026-07-04-cordis-jsdoc-completeness-gate.md)使 cordis 表面上的未文档化参数和返回值不再可能——`interface Events` 成员与 `ctx.<key>` 服务类——但那只是插件作者所导入内容的一小部分。AGENTS.md 中「每个导出(及非显而易见的方法)都应有 JSDoc 说明语义」这条规则在其他地方仍然只能靠评审以行文方式检查,而且没有任何机制要求普通导出函数带 `@param`/`@returns`。采纳时的一次调查发现 34 个包中有 203 个文档不完整的模块级导出:seam 相关辅助函数(`runBash`、`readForEdit`、`htmlToMarkdown`)、格式编解码器、整个未文档化的接口和类型别名——正是 IDE 消费方悬停时看到的那些名字。 +[Cordis JSDoc 完整性门禁](2026-07-04-cordis-jsdoc-completeness-gate.md)使得 Cordis 表面上的参数和返回值不可能缺少文档——`interface Events` 成员和 `ctx.<key>` 服务类——但这只是插件作者所导入内容的一小部分。AGENTS.md 中的规则「每个导出(以及非显而易见的方法)都必须有解释语义的 JSDoc」在其他地方只能靠评审以行文方式检查,而且没有任何机制要求普通导出函数带 `@param`/`@returns`。采纳时的一次调查发现 34 个包(package)中有 203 个文档不完整的模块级导出:seam 相关辅助函数(`runBash`、`readForEdit`、`htmlToMarkdown`)、格式编解码器、完全无文档的接口和类型别名——恰恰是 IDE 消费方悬停查看的那些名称。 ## 决策 -新增门禁 `scripts/verify-export-jsdoc.ts`(`pnpm run verify-export-jsdoc`,接入 doc-sync,与 `verify-cordis-catalog` 并列),遍历每个 `packages/<group>/<pkg>/src/` 目录树下所有模块级导出名。解析与检查辅助函数从 `gen-cordis-catalog.ts` 移入共享的 `scripts/jsdoc.ts`,因此「已文档化」在两个表面上含义一致:描述文本在第一个块标签处截止,每个可检查参数需要非空 `@param`,非 void 的**已标注**返回值需要非空 `@returns`,过时的 `@param` 报错,违规汇总为一份报告。 +新增门禁 `scripts/verify-export-jsdoc.ts`(`pnpm run verify-export-jsdoc`,接入 `doc-sync`(文档同步门禁),与 `verify-cordis-catalog` 并列),遍历每个 `packages/<group>/<pkg>/src/` 目录树下的所有模块级导出名称。解析与检查辅助函数从 `gen-cordis-catalog.ts` 移入共享的 `scripts/jsdoc.ts`,使得「已文档化」在两个表面上含义一致:描述性文字在第一个块标签处截止、每个可检查参数需要非空 `@param`、非 void 且有显式标注的返回值需要非空 `@returns`、过时的 `@param` 报错,违规项汇总为一份报告。 按声明类型划分的契约: -- 每个导出名都需要带有非空描述文本的 JSDoc。 -- 函数类导出(函数声明;以函数初始化器或行内可调用标注的 const;非标识符的函数默认导出)遵循完整的函数契约,分类前会剥离包装表达式(括号、`as`/`satisfies` 转型、非空断言)。如果 const 的声明器标注了一个**命名**类型(`export const f: Handler = …`),则签名契约推迟到该类型自身的声明,`@returns` 可选;行内 `(x: T) => U` 标注或单调用签名字面量即为表面签名本身,适用完整契约;而字面量中混合了调用/构造签名与其他成员的情况则直接拒绝(没有单一签名可供标签对照——请提取命名类型)。 -- 导出类需要类级别的描述文本;公开方法(包括静态方法——可通过导出名访问)遵循函数契约;公开属性和访问器需要描述文本(get/set 对由 getter 覆盖)。重载实现免检——由签名承载文档。 -- 导出的接口、类型别名和枚举需要声明级别的描述文本;成员级别的强制有意推迟(承载关键成员契约的 seam 服务类已在 cordis 门禁下)。 -- 导出的命名空间递归检查(在 ambient `declare` 命名空间内,每个成员隐式导出);命名空间本身仅在不与同名已文档化声明合并时才需要描述文本(Config 命名空间惯用法只需文档化插件一次)。 -- `declare module` / `declare global` 体和 `export … from` 再导出语句被跳过:augmentation 不是包的导出,再导出的定义在其定义处检查。`export import X = N.member` 别名文档化**自身**——其目标可能是遍历不会访问的非导出命名空间成员——且仅支持纯描述文本的目标类型:可调用、类或命名空间目标携带别名描述文本无法承载的签名/成员契约,门禁拒绝此类情况并要求直接导出该声明。 -- 其余一切按**封闭**原则失败:`export =` 直接拒绝;基类从未命名的参数即使作为绑定模式仍保留 `@param` 义务;调度未识别的导出语句类型本身即为违规——没有任何导出形式能因遗漏而免检。 +- 每个导出名称都需要带有非空描述文字的 JSDoc。 +- 函数类导出(函数声明;初始化器为函数或带有内联可调用标注的 const;非标识符的函数默认导出)遵循完整的函数契约,分类前会剥离包装表达式(括号、`as`/`satisfies` 类型断言、非空断言)。如果 const 声明器标注了一个具名类型(`export const f: Handler = …`),签名契约推迟到该类型自身的声明处,`@returns` 保持可选;内联的 `(x: T) => U` 标注或单调用签名字面量本身就是表面签名,适用完整契约;而混合了调用/构造签名与其他成员的字面量则直接拒绝(没有单一签名可供标签对照——请提取具名类型)。 +- 导出类需要类级别的描述文字;公开方法(包括静态方法——可通过导出名称访问)遵循函数契约;公开属性和访问器需要描述文字(get/set 对由 getter 覆盖)。重载实现体免检——签名承载文档。 +- 导出接口、类型别名和枚举需要声明级别的描述文字;成员级别的强制有意推迟(承载关键成员契约的 seam 服务类已在 Cordis 门禁之下)。 +- 导出命名空间递归检查(在 ambient `declare` 命名空间内,每个成员隐式导出);命名空间本身仅在不与同名的已文档化声明合并时才需要描述文字(Config-namespace 惯用法只需文档化插件一次)。 +- `declare module`/`declare global` 体和 `export … from` 重导出语句被跳过:augmentation 不是包的导出,重导出的定义在其定义处检查。`export import X = N.member` 别名需要文档化**自身**——其目标可能是遍历不会访问的非导出命名空间成员——且门禁仅支持纯描述文字的目标类型:可调用、类或命名空间目标携带别名描述文字无法承载的签名/成员契约,门禁会拒绝并要求直接导出该声明。 +- 其余情况按封闭原则失败:`export =` 直接拒绝;基类从未命名的参数即使作为绑定模式仍需 `@param`;dispatch 不识别的导出语句类型本身就是违规——没有任何导出形式能因遗漏而免检。 -三类豁免避免门禁要求样板代码,精神与 cordis 门禁的 `this`/`next` 豁免一致(对已豁免的名字主动写文档是允许的;只有缺失才不被检查): +三类豁免避免门禁要求样板代码,精神与 Cordis 门禁的 `this`/`next` 豁免一致(为已豁免的名称编写文档是允许的;只有缺失才不被检查): -- **继承成员。**重写从基类声明继承文档。新增的公开表面仍需文档:新增参数、将 protected 成员公开重写、或在 void 基类之上给出具体返回值。继承查找与推断返回值分类是门禁唯一需要类型检查器的工作;其他检查使用 AST。 -- **插件协议槽位。**顶层 `name` / `inject` / `reusable` / `Config` const 与 `apply` 入口,以及插件类上作为静态成员的相同槽位,属于框架协议:其形状由 cordis 固定,模块文档注释加 `interface Config` 承载插件的真实语义。 -- **构造函数**,与 cordis 门禁一致:插件类由框架构造,类文档承载全部说明。 +- **继承成员。** 重写从其基类声明继承文档。新增的公开表面仍需文档:新增参数、将 protected 成员公开重写、或在 void 基类之上返回具体类型。继承查找和推断返回值分类是门禁唯一需要类型检查器的工作;其他检查使用 AST。 +- **插件协议槽位。** 顶层的 `name`/`inject`/`reusable`/`Config` 常量和 `apply` 入口,以及插件类上的同名静态成员,属于框架协议:其形状由 Cordis 固定,模块文档注释加 `interface Config` 承载插件的真实语义。 +- **构造函数**,与 Cordis 门禁一致:插件类由框架构造,类文档承载全部说明。 -`collectExportJsdocViolations()` 返回违规列表(CLI 在非空时以 exit 1 退出),因此 `packages/core/agent/tests/verify-export-jsdoc.spec.ts` 中的负路径测试直接对发现结果断言,通过 fixture 包驱动每一种拒绝和每一种豁免。 +`collectExportJsdocViolations()` 返回违规列表(CLI 在非空时以 1 退出),因此 `packages/core/agent/tests/verify-export-jsdoc.spec.ts` 中的负路径测试直接断言发现项,通过 fixture(测试前置数据)包驱动每一种拒绝和每一种豁免。 ## 曾考虑的替代方案 -- **eslint-plugin-jsdoc**(`require-jsdoc`/`require-param`/`require-returns`):覆盖了机械核心,但无法表达本仓库的契约:继承成员豁免需要跨包类型解析,协议槽位和命名空间合并惯用法是 cordis 特有的,而完整性语义(标签前描述文本、过时标签报错、聚合报告)已在 `scripts/jsdoc.ts` 中与 catalog 生成器共享一处。两套微妙不同的「已文档化」定义正是本仓库「一处为家」规则要防止的失败模式。 -- **扩展 `gen-cordis-catalog.ts`**:catalog 生成器渲染一个精选表面并门禁其新鲜度(freshness);仓库级遍历没有 catalog 可渲染。共享辅助函数但保持遍历分离,使每个门禁的职责清晰可读。 -- **强制接口/类型别名的成员文档**:推迟。这会将检查表面扩大到大量自描述字段,而承载关键成员契约的 seam 类已在门禁下。如果评审中出现成员文档漂移再重新考虑。 +- **eslint-plugin-jsdoc**(`require-jsdoc`/`require-param`/`require-returns`):覆盖了机械核心,但无法表达本仓库的契约。继承成员豁免需要跨包的类型解析,协议槽位和命名空间合并惯用法是 Cordis 特有的,而完整性语义(标签前描述文字、过时标签报错、汇总报告)已在 `scripts/jsdoc.ts` 中与 catalog 生成器共享。两套微妙不同的「已文档化」定义,正是本仓库「单一归属」规则所要防止的失败模式。 +- **扩展 `gen-cordis-catalog.ts`**:catalog 生成器渲染一个精选表面并守卫其新鲜度;仓库级遍历没有 catalog 可渲染。共享辅助函数、保持遍历独立,使每个门禁的职责清晰可读。 +- **强制接口/类型别名的成员文档**:推迟。这会使检查表面成倍增长,而这些成员大多是自描述的字段;承载关键成员契约的 seam 服务类已有门禁。如果评审中出现成员文档漂移再重新考虑。 ## 后果 -- 新导出不能在无文档的情况下落地:`verify-export-jsdoc` 使 doc-sync 失败,而 pre-push 和 CI 已经运行 doc-sync。采纳时发现的 203 处缺口在同一个变更中补齐,因此门禁以绿色状态落地。 -- 导出函数必须标注返回类型(采纳时已全面覆盖,现在成为承载性要求),且在 `@param` 需要命名的地方使用标识符参数。 -- seam 文档是权威的:实现从继承链继承文档,值得保留在实现上的行为说明是补充,而非必需。 -- 门禁构建一个 `ts.Program`(约 6 秒)——唯一需要类型解析的文档门禁;在已经编译文档片段的 doc-sync 中可以接受。 -- 协议槽位名在模块顶层按约定保留;一个碰巧名为 `apply` 或 `Config` 的非协议导出会免检——已接受,记录于此。 +- 新增导出不能在无文档的情况下合入:`verify-export-jsdoc` 使 `doc-sync` 失败,而 pre-push 和 CI 已运行 `doc-sync`。采纳时发现的 203 处缺口在同一个变更中补齐,门禁以绿色状态落地。 +- 导出函数必须标注返回类型(采纳时已全面满足,现在成为门禁依赖),并在 `@param` 需要命名参数时使用标识符参数。 +- seam 文档是权威的:实现从其继承链继承文档,值得保留在实现上的行为说明是补充,而非必需。 +- 门禁构建一个 `ts.Program`(约 6 秒)——唯一需要类型解析的文档门禁;在已编译文档片段的 `doc-sync` 内可以接受。 +- 协议槽位名称按约定保留在模块顶层;一个恰好命名为 `apply` 或 `Config` 的非协议导出将不被检查——已接受,记录于此。 diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml index 394c2494ac..ccfbb1cc49 100644 --- a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-06-generated-config-catalog.md: 50ba0dc70b0d8ea54a4f93911f3a087806774626 -2026-07-06-generated-config-catalog.zh.md: 2dd0cbe5303f08aa2f3300c6f8613a7823c2bc78 +2026-07-06-generated-config-catalog.zh.md: 87a861bab394ec268fb3c870e848db37fa4d6fcf diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md index 2dd0cbe530..87a861bab3 100644 --- a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md @@ -6,35 +6,35 @@ Status: implemented ## 问题 -仓库此前没有以源码为后盾的插件配置参考。各 package 的 README 对字段的记录方式不一致,没有列举哪些包可被加载,也没有校验运行时 schema 是否与声明的配置类型一致。 +仓库此前没有以源码为后盾的插件配置参考。各 package 的 README 对字段的记录方式不一致,未列举哪些包可被加载,也未校验运行时 schema 与声明的配置类型是否一致。 ## 决策 -`scripts/gen-config-catalog.ts` 从每个插件声明的配置类型与 JSDoc 生成 [docs/config-catalog.md](../../../config-catalog.md),包含注入要求、引用类型链接和源码指针。package 内部类型被传递性地包含;workspace 和外部类型以链接或名称引用。确定性的 `--write` 和 `--check` 模式使提交到仓库的页面成为一个生成产物(artifact)。 +`scripts/gen-config-catalog.ts` 从每个插件声明的配置类型与 JSDoc 生成 [docs/config-catalog.md](../../../config-catalog.md),包含注入要求、引用类型链接和源码指针。包内局部类型被传递性地包含;workspace 和外部类型以链接或名称形式引用。确定性的 `--write` 和 `--check` 模式使提交到仓库的页面成为一个生成产物。 -此处采用纯 AST 生成是正确的,原因与事件/服务目录相同,也与工具目录不同:配置类型是静态声明,仓库中每个 schemastery schema 都是静态的 `z.object`/`z.intersect` 字面量,因此源码就是全部真相——配置表面没有任何部分是运行时组合的。 +此处采用纯 AST 生成是正确的,原因与 events/services catalog 相同,而与 tool catalog 不同:配置类型是静态声明,仓库中每个 schemastery schema 都是静态的 `z.object`/`z.intersect` 字面量,因此源码即全部真相——配置表面没有任何部分是运行时组合的。 具体选择: -- **配置类型取自第二参数类型。** 目录记录的是 `apply(ctx, config)` / 服务构造函数 `(ctx, config)` 的声明参数类型——即 Cordis 实际传入的值——而非按命名约定定位的 `Config` 导出。这使得遍历是全量的:无论接口名为 `AcpConfig` 还是 `BasicCompactConfig`,无论类型声明在兄弟文件中,还是插件根本没有校验 schema,都能正常工作。 -- **分类是全量的。** 每个 `packages/<group>/<pkg>` 条目都会被解析(镜像 Loader 的 `unwrapExports`(`exports.default ?? exports`)),归入以下之一:可配置插件、无配置插件、抽象 seam 类或库——各自渲染在独立章节中——无法归类的条目会硬错误。新 package 不可能被静默地遗漏。 -- **逐字段 JSDoc 强制要求。** 粘贴的声明中每个属性(包括嵌套的类型字面量)都需要非空的 JSDoc 描述,否则生成失败。粘贴本身就是文档,因此这与事件目录通过 `@mode` 施加的强制函数相同:源码文档不足时门禁失败,而非产出一份单薄的目录。 -- **Schema 键与声明类型交叉检查。** 生成器通过本地和 workspace 类型解析嵌套的对象与数组路径。确定缺失的路径会失败;无法枚举的外部或动态形状则跳过。检查有意设计为单向的,因为声明类型可能包含从 loader 配置中排除的运行时专用字段。 +- **配置类型是第二参数的类型。** catalog 记录的是 `apply(ctx, config)` / 服务构造函数 `(ctx, config)` 的声明参数类型——即 Cordis 实际传入的值——而非按命名约定定位的 `Config` 导出。这使得遍历是全量的:无论接口叫 `AcpConfig` 还是 `BasicCompactConfig`,无论类型声明在兄弟文件中,还是插件完全没有验证 schema,都能正常工作。 +- **分类是全量的。** 每个 `packages/<group>/<pkg>` 条目都会被解析(镜像 Loader 的 `unwrapExports`:`exports.default ?? exports`),归入可配置插件、无配置插件、抽象 seam 类或库之一——各自渲染在独立小节中——无法归类的条目直接报错。新 package 不可能被悄悄遗漏。 +- **逐字段 JSDoc 强制要求。** 粘贴的声明中每个属性(包括嵌套的类型字面量)都需要非空的 JSDoc 描述,否则生成失败。粘贴本身就是文档,因此这与 events catalog 通过 `@mode` 施加的强制函数相同:源码文档过于单薄时门禁报错,而非产出单薄的 catalog。 +- **Schema 键与声明类型做比对。** 生成器通过局部和 workspace 类型解析嵌套的对象与数组路径。确定缺失的路径报错;无法枚举的外部或动态形状则跳过。比对有意设计为单向的,因为声明类型可能包含被排除在 loader 配置之外的运行时专用字段。 - **专用围栏。** 粘贴的声明使用 ` ```ts config-catalog ` 信息字符串,`doc-typecheck` 会跳过它(引用了导入类型的孤立声明无法独立编译),并将其排除在 opt-out 比例之外——与 `cordis-catalog` 和 `persistence-catalog` 围栏的处理方式相同。 -- **单文件 `docs/config-catalog.md`**,而非一个单文件目录:该页面服务于单一受众(`cordis.yml` 的编写者),只有一个维度,不同于 `cordis-catalog/`(它包含两个并列页面)。 +- **单文件 `docs/config-catalog.md`**,而非一个单文件目录:该页面面向单一受众(`cordis.yml` 的编写者),只有一个维度,不同于 `cordis-catalog/`(其中包含两个并列页面)。 -各 package README 的 `## Config` 章节保留。这种重叠是有意接受的:README 是精心策划的逐 package 契约(部署上下文中的配置语义,连同限制与扩展点),目录则是穷举式的生成枚举。因为目录是生成的,二者之间的分歧说明 README 有误,修复方式是编辑 README——目录不会漂移。 +各 package README 中的 `## Config` 小节保留。重叠是有意接受的:README 是经过策划的逐包契约(在部署上下文中描述配置语义,连同限制与扩展点),catalog 则是穷举式的生成枚举。由于 catalog 是生成的,二者不一致时说明 README 有误,修复方式是编辑 README——catalog 不会漂移。 ## 曾考虑的替代方案 -- **合成式逐字段渲染**:为每个字段生成一个项目符号列表、表格或带注释的 YAML 片段,由解析后的 JSDoc 加 schema 元数据组装。否决,改用逐字粘贴:带 JSDoc 的接口本身就是以其原始形式撰写的契约,合成渲染器会重新格式化它不拥有的行文,增加一层可能歪曲原意的渲染。 -- **运行时启动 + schema 内省(如工具目录的做法)**:否决。此处没有任何内容是运行时组合的,而且 schema 本身对配置表面的文档化不足(行文记录的默认值、运行时专用字段、完全没有 schema 的插件)。启动只会增加脆弱性而不增加真相。 -- **双向 schema/接口相等性检查**:否决,改用子集检查。声明类型合理地包含 schema 拒绝从配置接受的成员(运行时专用的 seam)。 -- **在同一变更中废弃 README 的 `## Config` 章节**:否决。接受的重叠使逐 package 契约在原地可读,而一次清扫需要先把每个 README 的额外事实折入字段 JSDoc——这是可分离的工作,目录不依赖它。 +- **合成式逐字段渲染**:为每个字段生成项目符号列表、表格或带注释的 YAML 片段,从解析的 JSDoc 加 schema 元数据组装。否决,改用逐字粘贴:接口连同其 JSDoc 本身就是以原始形式撰写的契约,合成渲染器会重新格式化它不拥有的行文,增加一个可能歪曲原意的渲染层。 +- **运行时启动 + schema 内省(如 tool catalog 所做的那样)**:否决。此处没有任何内容是运行时组合的,且 schema 本身对配置表面的文档化不足(以行文记录的默认值、运行时专用字段、完全没有 schema 的插件)。启动只会增加脆弱性而不增加真相。 +- **双向 schema/接口等价检查**:否决,改用子集检查。声明类型合理地包含 schema 拒绝从配置接受的成员(运行时专用 seam)。 +- **在同一变更中废除 README `## Config` 小节**:否决。保留可接受的重叠使逐包契约在原处可读,而清理工作需要先把每个 README 的额外事实折入字段 JSDoc——这是可分离的工作,catalog 不依赖它。 ## 后果 -- 目录不会漂移:源码变化而提交的文件未反映时,`verify-config-catalog` 在 pre-push 和 CI 中失败。未记录的配置字段、无法解析的引用类型名称、或 schema 键在配置类型中缺失,都会导致生成器直接报错。 -- 配置行文现在在声明处有了强制函数:编写新的配置字段意味着编写其 JSDoc,而 JSDoc 会逐字成为目录条目。 -- 生成器对无法静态遍历的形状硬错误——别名化的 package 内部配置导入、非 `object`/`intersect` 组合构建的 schema、未列入的全局类型名。引入这样的形状就必须同时教会生成器(否则该形状不能进入仓库),这正是设计意图:目录始终是全部真相。 -- `gen-cordis-catalog.ts` 导出其 JSDoc/指针辅助函数与 `LINK_MAP` 供复用,因此两个目录以相同方式交叉链接类型,新增一条 link-map 条目同时服务于两者。 +- catalog 不会漂移:源码变更而提交的文件未反映时,`verify-config-catalog` 在 pre-push 和 CI 中报错。未文档化的配置字段、无法解析的引用类型名、或 schema 键在配置类型中缺失,都会直接导致生成器报错。 +- 配置行文现在有了声明处的强制函数:编写新配置字段意味着编写其 JSDoc,而该 JSDoc 将逐字成为 catalog 条目。 +- 生成器对无法静态遍历的形状直接报错——别名化的包内配置导入、非 `object`/`intersect` 组合构建的 schema、未列入的全局类型名。引入此类形状时必须同时教会生成器(否则该形状不能进入仓库),这正是设计意图:catalog 始终是全部真相。 +- `gen-cordis-catalog.ts` 导出其 JSDoc/指针辅助函数与 `LINK_MAP` 供复用,因此两个 catalog 以相同方式交叉链接类型,新增一条 link-map 条目同时服务于两者。 diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml index d7db5cac08..815cf98e72 100644 --- a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-06-node-engine-floor.md: 561b6b4a124b6eaa8e2ba0756a835e35519b30b8 -2026-07-06-node-engine-floor.zh.md: c6ace7a1296b5e3049ff4ef55f29b689fce7f4ff +2026-07-06-node-engine-floor.zh.md: 21af2da919754b1ae4667b46ef2f65c14a279b49 diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md index c6ace7a129..21af2da919 100644 --- a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md @@ -1,39 +1,39 @@ # RFC:将 Node LTS 引擎下限提升至 22.19 -Status: implemented - [English](2026-07-06-node-engine-floor.md) | 中文 +Status: implemented + ## 问题 -根 `engines.node` 范围中的 Node 22 分支是对已安装工作区的契约,而不仅仅是 harness 源码直接调用的运行时 API 的契约。该分支的下限不得低于工作区在该分支上安装的依赖所声明的 package `engines.node`;否则 `pnpm install --engine-strict` 会在一个被宣传的 LTS 版本上失败,而非严格模式的安装则会在依赖所支持的运行时范围之外运行。 +根 `engines.node` 范围中的 Node 22 分支是对已安装工作区的契约,而不仅仅是 harness 源码直接调用的运行时 API 的契约。它不得低于工作区在该分支上安装的依赖所声明的 package `engines.node`;否则 `pnpm install --engine-strict` 会在一个已宣传的 LTS 版本上失败,而非严格模式的安装则会在依赖所支持的运行时范围之外运行。 ## 决策 -将 `engines.node` 设为 `^22.19.0 || >=24.0.0`,并在 keyless CI 兼容性矩阵中测试 `['22.19', 24, 26]`。每个矩阵分支都运行 TypeScript 类型检查加一次 keyless 的源码模式 worker 冒烟测试,因此引擎下限同时通过完整的源码类型检查和真实的未构建运行时路径得到验证。真实 API 的 e2e 工作流保持在 Node 24 上运行,因为它验证的是 API 集成而非运行时下限。 +将 `engines.node` 设为 `^22.19.0 || >=24.0.0`,并在 keyless CI 兼容性矩阵中测试 `['22.19', 24, 26]`。每条矩阵分支都运行 TypeScript 类型检查加一次 keyless 的源码模式 worker 冒烟测试,因此引擎下限通过完整的源码类型检查和真实的未构建运行时路径两条路径得到验证。真实 API 的 e2e 工作流保持在 Node 24 上,因为它验证的是 API 集成而非运行时下限。 -两项 Node 特性决定了源码运行时的下限: +两个 Node 特性决定了源码运行时的门槛: -- **`node:sqlite`**:`packages/session-persistence/session-persistence-sqlite` 在顶层执行 `import { DatabaseSync } from 'node:sqlite'`。该模块在 **22.13**(LTS)和 **23.4**(Current)取消了 `--experimental-sqlite` flag 要求;在此之前,导入它会在加载时抛出异常。 -- **原生 TypeScript 类型剥离**:`packages/examples/stdio-demo/tests/built-bin.e2e.ts` 冒烟测试在纯 `node`(无 tsx)下启动已发布的 `lib/bin.js`,并加载示例的 `.ts` 插件(`mock-llm.ts`、`echo-tool.ts`)。类型剥离从 **22.18**(LTS)和 **23.6**(Current)起成为默认行为;在此之前需要 `--experimental-strip-types`。 +- **`node:sqlite`**:`packages/session-persistence/session-persistence-sqlite` 在顶层执行 `import { DatabaseSync } from 'node:sqlite'`。该模块在 **22.13**(LTS)和 **23.4**(Current)取消了 `--experimental-sqlite` 标志要求;在此之前,导入它会在加载时抛出异常。 +- **原生 TypeScript 类型剥离**:`packages/examples/stdio-demo/tests/built-bin.e2e.ts` 冒烟测试在纯 `node`(不用 tsx)下启动已发布的 `lib/bin.js`,并加载示例的 `.ts` 插件(`mock-llm.ts`、`echo-tool.ts`)。类型剥离从 **22.18**(LTS)和 **23.6**(Current)起成为默认行为;在此之前需要 `--experimental-strip-types`。 -这些源码特性在 22.x 线上于 **22.18** 全部就绪,但已安装的 Pi 适配器依赖将宣传的 LTS 下限进一步抬高。`@deepseek-ai/dsh-llm-pi-ai` 依赖 `@earendil-works/pi-ai@0.79.3`,后者的 package 声明 `engines.node >=22.19.0`,因此 LTS 下限为 **22.19**。24.x 分支保持 `>=24.0.0`。该不连续范围完全排除 Node 23:Node 23.0–23.5 仍有至少一项源码特性需要 flag,而 23 线是非 LTS/已 EOL,宣传 `>=23.6` 只会增加一个已死的发布线和一个不应被任何部署使用的 CI 分支。 +这些源码特性在 22.x 线上于 **22.18** 全部就绪,但已安装的 Pi 适配器依赖将宣传的 LTS 下限进一步提高。`@deepseek-ai/dsh-llm-pi-ai` 依赖 `@earendil-works/pi-ai@0.79.3`,后者的 package 声明 `engines.node >=22.19.0`,因此 LTS 下限为 **22.19**。24.x 分支保持 `>=24.0.0`。该不相交范围完全排除了 Node 23:Node 23.0–23.5 至少还有一个源码特性需要标志,而 23 线是非 LTS/已 EOL 的,宣传 `>=23.6` 会增加一条已终止的发布线和一条 CI 分支,而没有任何部署应当使用它。 -`@types/node` 继续固定在 22.x 线(`^22.20.0`),以匹配 LTS 支持线:如果使用了 Node 23+/24+/25+ 才有的 API,`tsc` 会在所有机器和类型检查门禁中报错,而不是编译通过后存活到只有下限矩阵分支才能捕获的运行时失败。整棵树目前在 Node 22 类型表面上类型检查全部通过,因此这个固定没有代价。 +`@types/node` 继续固定在 22.x 线(`^22.20.0`),以匹配 LTS 支持线:使用 Node 23+/24+/25+ 的 API 会在所有机器和类型检查门禁中导致 `tsc` 失败,而不是编译通过、直到仅下限矩阵分支才能捕获的运行时错误才暴露。目前整个代码树在 Node 22 类型表面上类型检查全部通过,因此这一固定没有任何代价。 ## 后果 - 宣传的 LTS 分支不再低于 Pi 适配器依赖的下限。 -- CI 用 Node 22.19 直接验证 Node 22 LTS 下限,Node 24 分支保持 `node: 24`,Node 26 用于下一个偶数线;每个分支都对源码图做类型检查,并实际启动未构建的工作流 worker。 -- built-bin 冒烟测试不需要版本条件 flag:在 22.19 上类型剥离已是默认行为,因此测试保持其文档记录的纯 `node lib/bin.js` 路径。 -- 未来如有依赖或源码 API 抬高运行时下限,必须在同一个变更中同步修改 `engines.node`、兼容性矩阵与本 RFC。 +- CI 通过 Node 22.19 直接验证 Node 22 LTS 下限,Node 24 分支保持 `node: 24`,Node 26 用于下一个偶数线;每条分支都对源码图执行类型检查,并实际启动未构建的工作流 worker。 +- built-bin 冒烟测试无需版本条件标志:在 22.19 上类型剥离已是默认行为,因此测试保持其文档所述的纯 `node lib/bin.js` 路径。 +- 未来如果有依赖或源码 API 提高运行时下限,必须在同一个变更中同步修改 `engines.node`、兼容性矩阵和本 RFC。 ## 曾考虑的替代方案 - **保持 `^22.18.0 || >=24.0.0`。** 否决:它宣传的 LTS 版本低于 Pi 适配器依赖的下限。`@earendil-works/pi-ai@0.79.3` 要求 `>=22.19.0`。 -- **降级或固定 `@earendil-works/pi-ai` 以保留 22.18 的宣传范围。** 否决:当前的 Pi 适配器依赖是工作区的预期组成部分,且 22.19 仍在 Node 22 LTS 线内。 -- **下限设为 `>=22.13`(`node:sqlite` 边界),在 22.13–22.17 的 built-bin 冒烟测试中加 `--experimental-strip-types`。** 否决:为一个窄范围增加版本条件测试 flag,并将对实验性 flag 的依赖伪装成正式支持。Pi 适配器依赖已经要求更高的 LTS 下限。 -- **开放式 `>=22.19`。** 否决:它宣传支持 Node 23.0–23.5,而在这些版本上 `node:sqlite`(直到 23.4)或类型剥离(直到 23.6)仍需 flag。 -- **包含 Node 23.6+(`^22.19.0 || >=23.6.0`)。** 否决:23.6+ 确实能无 flag 运行两项源码特性,但 Node 23 已 end-of-life;宣传一个已死的发布线只会增加一个范围项和一个 CI 分支,用于一个不应被任何部署使用的运行时。 -- **矩阵用 `[22, 24, 26]` 而非固定 `22.19`。** 否决:浮动的主版本号条目会随时间上漂,悄然不再验证所声明的 LTS 下限。 -- **让 `@types/node` 超前于下限(`^25`)。** 否决:类型定义超前于运行时下限会让仅 Node 24/25 才有的 API 编译通过,仅在 22.x 上运行时才失败。将 `@types/node` 固定在 22.x 线上,会把这种情况变成所有环境下的编译错误。 +- **降级或固定 `@earendil-works/pi-ai` 以保留 22.18 的宣传范围。** 否决:当前 Pi 适配器依赖是预期工作区的一部分,且 22.19 仍在 Node 22 LTS 线内。 +- **下限 `>=22.13`(`node:sqlite` 边界)加上在 22.13–22.17 的 built-bin 冒烟测试中使用 `--experimental-strip-types`。** 否决:它为一个狭窄范围增加了版本条件测试标志,并将实验性标志依赖包装为正式支持。Pi 适配器依赖已经要求更高的 LTS 下限。 +- **开放式 `>=22.19`。** 否决:它宣传支持 Node 23.0–23.5,而在这些版本上 `node:sqlite`(直到 23.4)或类型剥离(直到 23.6)仍需标志。 +- **包含 Node 23.6+(`^22.19.0 || >=23.6.0`)。** 否决:23.6+ 确实能无标志运行两个源码特性,但 Node 23 已 end-of-life;宣传一条已终止的发布线会增加一个范围项和一条 CI 分支,而没有任何部署应当使用该运行时。 +- **矩阵 `[22, 24, 26]` 而非固定 `22.19`。** 否决:浮动的主版本号条目会随时间上漂,悄然不再验证所声明的 LTS 下限。 +- **将 `@types/node` 保持在下限之前(`^25`)。** 否决:类型定义超前于运行时下限会让仅 Node 24/25 才有的 API 编译通过,仅在 22.x 上运行时才失败。将 `@types/node` 固定在 22.x 线上可将此类问题转化为所有环境下的编译错误。 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml index 81369745d3..7abfb8a8ed 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-06-parallel-github-ci-gates.md: 890adf58ac8a20a39806aa028d035cb253d5a4f1 -2026-07-06-parallel-github-ci-gates.zh.md: 02502b1005a1f8e6f9f539878c792a9f0585e926 +2026-07-06-parallel-github-ci-gates.zh.md: 47562ed6a83b650a3275b4045c39c4de6d2ecac6 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md index 02502b1005..47562ed6a8 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md @@ -1,41 +1,41 @@ # RFC:并行 GitHub CI 门禁 -Status: implemented - [English](2026-07-06-parallel-github-ci-gates.md) | 中文 +Status: implemented + ## 问题 -keyless GitHub CI 门禁大多彼此正交:类型检查、lint、文档新鲜度、覆盖率、快照回放、构建、包发布卫生检查、demo 冒烟测试和 built-bin 冒烟测试各自因不同原因失败,且不需要彼此的运行时状态。将它们串成一条有序命令链,工作流的挂钟时间等于所有门禁之和;而将每个叶子门禁拆成独立的 GitHub job,则会重复 checkout、Node 搭建、pnpm restore 和 install 工作,直到编排开销本身成为瓶颈。 +keyless GitHub CI 门禁大多相互正交:类型检查、lint、文档新鲜度、覆盖率、快照回放、构建、包发布卫生检查、demo 冒烟测试与 built-bin 冒烟测试各自因不同原因失败,彼此不需要对方的运行时状态。将它们串成一条有序命令链,工作流的挂钟时间等于所有门禁之和;而把每个叶子门禁拆成独立的 GitHub job,则会重复 checkout、Node 设置、pnpm restore 和 install 工作,直到编排开销本身成为瓶颈。 -难点在于产物边界。`publint`、`verify-node-next-types` 和 built-bin 冒烟测试需要构建出的 `lib/` 输出,而大多数门禁只需要源码和依赖。盲目扇出要么让这些产物消费方在 `pnpm run build` 输出声明文件和 bundle 之前就开始执行,要么在每个依赖产物的 job 中重复构建。 +难点在于产物边界。`publint`、`verify-node-next-types` 和 built-bin 冒烟测试需要构建出的 `lib/` 输出,而大多数门禁只需要源码和依赖。盲目扇出要么让这些产物消费方在 `pnpm run build` 输出声明文件和 bundle 之前就开始竞跑,要么在每个依赖产物的 job 中重复构建。 ## 决策 [CI](../../../../.github/workflows/ci.yml) 将 keyless 检查分组为若干宽粒度的主运行时 lane,外加一个兼容性矩阵。工作流文件拥有当前 lane 和运行时清单的定义权。 -每个 lane 委托给 [scripts/run-gates.ts](../../../../scripts/run-gates.ts),后者以有界并发调度独立门禁,并为每个门禁打印一个可归因的结果块。产物消费方在各自 lane 内依赖一次 build;兼容性 job 则将类型检查与一次真实的未构建 worker 启动相结合,以覆盖运行时特定的 loader 行为。 +每个 lane 委托给 [scripts/run-gates.ts](../../../../scripts/run-gates.ts),该脚本以有界并发调度独立门禁,并为每个门禁打印一个可归因的结果块。产物消费方依赖其所在 lane 内的一次 build,而兼容性 job 将类型检查与一次真实的未构建 worker 启动结合,以覆盖运行时特定的 loader 行为。 -生成的 `.sessions/` 日志和 `.doc-typecheck-*` 临时目录被 lint 忽略。聚合的本地 CI 模式仍在 lint 之后运行 demo 冒烟测试;而拆分后的 GitHub 静态 lane 可以直接运行 demo 冒烟测试,因为 lint 已隔离在自己的 lane 中。 +生成的 `.sessions/` 日志和 `.doc-typecheck-*` 临时目录被 lint 忽略。聚合的本地 CI 模式仍在 lint 之后运行 demo 冒烟测试,而拆分后的 GitHub static lane 可以直接运行 demo 冒烟测试,因为 lint 已隔离在自己的 lane 中。 -构建输出在 Node 24 产物 lane 中只生成一次。产物消费方(`publint`、`verify-node-next-types` 和 built-bin 冒烟测试)声明对 `build` 的依赖,因此没有 upload/download 交接,消费方也不可能抢在声明文件或 bundle 之前执行。CI 覆盖率报告仅为文本格式,本地覆盖率则保留 HTML 报告。 +构建输出在 Node 24 的产物 lane 中只生成一次。产物消费方(`publint`、`verify-node-next-types` 和 built-bin 冒烟测试)声明对 `build` 的依赖,因此没有 upload/download 交接,消费方也不可能在声明文件或 bundle 就绪之前抢跑。CI 覆盖率报告仅输出文本,本地覆盖率则保留 HTML 报告。 -两个工作流都缓存 pnpm store。真实 API 工作流使用共享的有界 Vitest 文件池,而非为每组测试单独开 job。 +两个工作流都缓存 pnpm store。真实 API 工作流使用共享的有界 Vitest 文件池,而非为每组测试单独开一个 job。 ## 曾考虑的替代方案 -- **在 Node 矩阵中保留完整串行链**:最容易理解,但会重复执行不产生 Node 版本特定信号的仓库级门禁,且让每个 PR 等待所有门禁之和。 -- **每个门禁各开一个 GitHub job**:最大化 GitHub 可见的扇出,但产生过多 check,且对运行时间短于 runner 准备时间的门禁反复支付 setup/install 开销。 -- **将构建产物上传给依赖产物的 job**:在多 job 间保持正确性,但增加了 artifact upload/download 时间,且在产物消费方可以通过主 job 内的本地依赖运行时仍保持工作流过宽。 -- **并发运行 `typecheck` 和 `build`**:向调度器暴露更多工作,但两者都调用 `tsc -b`;在它们之间共享增量构建状态是一场不必要的竞争,换来的挂钟收益很小。 -- **使用无界的真实 API e2e 并行度**:否决。该套件包含大量真实模型/工具场景;worker 池需要一个显式的 `DSH_E2E_MAX_WORKERS` 上限,这样 CI 和本地运行都能扇出而不会把配额或资源问题隐藏在不稳定的限流失败背后。 +- **在 Node 矩阵中保留完整串行链**:最容易推理,但会重复执行不产生 Node 版本特定信号的仓库级门禁,且让每个 PR 等待所有门禁的总和。 +- **每个门禁作为独立 GitHub job 运行**:最大化 GitHub 可见的扇出,但产生过多 check,且对运行时间短于 runner 准备时间的门禁而言,重复的 setup/install 开销得不偿失。 +- **将构建产物上传给依赖产物的 job**:在多 job 间保持正确性,但增加了 artifact upload/download 时间,且当产物消费方可以在主 job 内通过本地依赖排序运行时,工作流仍然过宽。 +- **并发运行 `typecheck` 与 `build`**:向调度器暴露更多工作,但两个命令都调用 `tsc -b`;在它们之间共享增量构建状态是一场不必要的竞争,换来的挂钟收益很小。 +- **使用无界的真实 API e2e 并行度**:否决。该套件包含大量真实模型/工具场景;worker 池需要一个显式的 `DSH_E2E_MAX_WORKERS` 上限,使 CI 和本地运行都能扇出,同时不会把配额或资源问题隐藏在不稳定的限流失败背后。 ## 后果 -PR 反馈以少量 GitHub check 呈现,每个宽粒度 job 内部包含结构化的逐门禁日志块。这使 runner setup 开销可控、Actions UI 紧凑,代价是失去了每个叶子门禁各自独立的 status check。 +PR 反馈以少量 GitHub check 的形式呈现,每个宽粒度 job 内部包含结构化的逐门禁日志块。这将 runner 设置开销控制在有限范围内,并保持 Actions UI 紧凑,代价是失去了每个叶子门禁独立的状态标记。 -宽粒度 lane 拆分比单一主 job 更频繁地重复 checkout、setup 和 install。这一 setup 开销是有意为之:在 GitHub 托管 runner 上,将 lint、覆盖率和快照回放放在同一个进程池中运行会严重超额占用 CPU,以至于单 job 的关键路径反而长于重复 setup 的方案。 +宽 lane 拆分比单一主 job 更频繁地重复 checkout、setup 和 install。这一设置开销是有意为之的:在 GitHub 托管 runner 上,将 lint、覆盖率和快照回放放在同一个进程池中运行会严重超额占用 CPU,以至于单 job 的关键路径比重复设置还要长。 -这种拆分引入了一项维护义务:当 `package.json` 增删属于 CI 的门禁时,[scripts/run-gates.ts](../../../../scripts/run-gates.ts) 需要相应增删叶子。这一义务是有意的,因为该 runner 是同一套门禁词汇的并行执行计划,而非独立的质量策略。 +这种拆分引入了一项维护义务:当 `package.json` 新增或移除一个应纳入 CI 的门禁时,[scripts/run-gates.ts](../../../../scripts/run-gates.ts) 需要添加或删除对应的叶子。这一义务是有意为之的,因为该 runner 是同一套门禁词汇的并行执行计划,而非独立的质量策略。 -兼容性信号窄于主 Node 24 信号。它证明源码图在每个宣称支持的运行时上能通过类型检查、且真实的未构建 workflow-worker 启动路径能正常执行,而不必重复文档、覆盖率、发布卫生、快照回放和其他不因 Node 版本而异的冒烟检查。 +兼容性信号比主 Node 24 信号更窄。它证明源码图在每个声明支持的运行时上都能通过类型检查,且真实的未构建 workflow-worker 启动路径能够执行,而不必重复文档、覆盖率、发布、快照回放以及那些不因 Node 版本而异的无关冒烟测试。 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml index 3adf939f24..6475a65971 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-06-parallel-pre-push-gates.md: 8a8813f2f3f6726ab2ab028757406d366ceb8b6d -2026-07-06-parallel-pre-push-gates.zh.md: 36207e522982990c193f9fe909faf380de53bca6 +2026-07-06-parallel-pre-push-gates.zh.md: 6ee3a8003853092d75cda9908bfae13ee0d4c7a2 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md index 36207e5229..6ee3a80038 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md @@ -1,42 +1,42 @@ # RFC:并行 pre-push 门禁 -Status: implemented - [English](2026-07-06-parallel-pre-push-gates.md) | 中文 +Status: implemented + ## 问题 -pre-push 钩子是分支离开本地机器前的最后一道检查点,因此它的挂钟时间直接影响贡献者是否愿意保持启用并信任其信号。Lefthook 已经能并行运行顶层 job,但 `pnpm run hygiene` 和 `pnpm run doc-sync` 这类聚合 job 在单个 job 内部隐藏了长串的顺序执行链。因此钩子可以配置为并行,却仍在等待那些成员彼此独立的串行子命令。 +pre-push 钩子是分支离开本地机器前的最后一道检查点,因此它的挂钟时间直接影响贡献者是否愿意保持启用并信任其信号。Lefthook 已经能并行运行顶层 job,但 `pnpm run hygiene` 和 `pnpm run doc-sync` 等聚合 job 在单个 job 内部隐藏了长串的顺序执行链。钩子因此可能在配置上看似并行,实际仍在等待那些成员彼此独立却串行执行的子命令。 -把这些成员直接展平到 `lefthook.yml` 只能解决本地钩子的问题。CI 有同样的调度问题,而在 YAML 中重复一份长长的叶子列表会让未来的脚本改动有两处可能漂移。 +将这些成员直接展平到 `lefthook.yml` 只能解决本地钩子的问题。CI 面临同样的调度问题,而在 YAML 中复制一长串叶子列表会让未来的脚本改动有两处可能漂移。 -`publint` 在更低一层也有同样的形态。每个包独立地针对自身的 manifest 和构建产物做 lint,但运行器按顺序逐个遍历所有包。在本仓库中,这意味着一个包发布门禁消耗的时间与包数量成正比,尽管各检查之间并不共享可变状态。 +`publint` 在更低一层也有同样的形态。每个包(package)独立地根据自身 manifest(元数据清单)和构建产物做 lint,但 runner 按顺序遍历所有包。在本仓库中,这意味着一个包发布门禁的耗时与包的数量成正比,尽管各检查之间并不共享可变状态。 ## 决策 -[lefthook.yml](../../../../lefthook.yml) 保留一个名为 `full check` 的 pre-push job,运行 `pnpm run check:pre-push`。该包脚本委托给 [scripts/run-gates.ts](../../../../scripts/run-gates.ts),即 CI 使用的同一个有界调度器。 +[lefthook.yml](../../../../lefthook.yml) 保留一个名为 `full check` 的 pre-push job,运行 `pnpm run check:pre-push`。该 package 脚本委托给 [scripts/run-gates.ts](../../../../scripts/run-gates.ts),即 CI 使用的同一个有界调度器。 -`pre-push` 模式展开为以下叶子门禁:单元测试套件、快照测试套件、构建、`hygiene` 成员、`doc-sync` 成员,以及 module-graph 新鲜度。叶子列表保持与包脚本相同的门禁词汇(包括 RFC 分类和 RFC 格式),运行器并发调度独立检查,并为每个门禁打印一个计时/输出块。 +`pre-push` 模式展开为以下叶子门禁:单元测试套件、快照测试套件、构建、`hygiene` 成员、`doc-sync` 成员,以及 module-graph 新鲜度。叶子列表保持与 package 脚本相同的门禁词汇,包括 RFC 分类和 RFC 格式,同时 runner 并发调度独立检查,并为每个门禁打印一个计时/输出块。 -构建门禁使钩子在干净 worktree 上也能自给自足。`publint` 和 `verify-node-next-types` 等待构建产物,而仅依赖源码的门禁继续并行执行。 +构建门禁使钩子在干净的 worktree 上也能自足运行。`publint` 和 `verify-node-next-types` 等待构建产物就绪,而仅依赖源码的门禁继续并行执行。 -[scripts/publint-all.ts](../../../../scripts/publint-all.ts) 从 `packages/<group>/<pkg>` 发现包列表,并使用大小取自 `availableParallelism()` 的 worker 池运行 `publint`。`DSH_PUBLINT_CONCURRENCY` 可以为资源配置不同的本地机器和 CI runner 设置 worker 数量上限或提高上限。结果按包缓冲,并按确定性的包顺序打印,因此并行执行不会打乱每个包的日志块。 +[scripts/publint-all.ts](../../../../scripts/publint-all.ts) 从 `packages/<group>/<pkg>` 发现包列表,并使用大小取自 `availableParallelism()` 的 worker 池运行 `publint`。`DSH_PUBLINT_CONCURRENCY` 可为资源配置不同的本地机器和 CI runner 设定或提高 worker 数量上限。结果按包缓冲,并以确定性的包顺序打印,因此并行执行不会打乱各包的日志块。 -聚合包脚本仍然是临时本地运行的真源。调度器是对其成员门禁的并行执行计划,而非替代词汇。 +聚合 package 脚本仍然是临时本地运行的真源。调度器是对其成员门禁的并行执行计划,而非替代词汇。 ## 曾考虑的替代方案 -- **在钩子中保留聚合的 `hygiene` 和 `doc-sync` job**:配置更简单,但 pre-push 的大部分挂钟时间仍然花在 lefthook 看不到也无法调度的串行命令链内部。 -- **为每个叶子门禁声明一个 lefthook job**:通过 lefthook 原生的 job 模型暴露并行性,但会让钩子文件承载一份 CI 无法复用的长成员列表。 -- **要求开发者在推送前手动构建**:省去一个钩子门禁,但会导致 `publint` 在干净 worktree 上失败,并把最后的本地检查点从可运行的检查降格为一项约定。 +- **在钩子中保留聚合的 `hygiene` 和 `doc-sync` job**:配置更简单,但 pre-push 的大部分挂钟时间仍然消耗在 lefthook 看不到也无法调度的串行命令链内部。 +- **为每个叶子门禁声明一个 lefthook job**:通过 lefthook 原生 job 模型暴露并行性,但会让钩子文件承载一长串成员列表,CI 无法复用。 +- **要求开发者在推送前手动构建**:可以省去一个钩子门禁,但会导致 `publint` 在干净 worktree 上失败,并把最后的本地检查点从可运行的检查降级为一种约定。 - **在 shell 脚本中使用后台子命令**:能并行化工作,但会丢失 lefthook 的 job 名称、逐 job 计时和失败分组,且信号处理更难推理。 -- **为每个包声明一个 publint lefthook job**:暴露最大并行度,但会把钩子变成一份手工维护的包清单,恰好在新增包时漂移。 -- **以无界并发运行 publint**:仅在小型机器上以赌进程数、内存压力、包 tarball 创建和日志可读性为代价来最小化耗时。 +- **为每个包声明一个 publint lefthook job**:暴露最大并行度,但会让钩子变成一份手动维护的包清单,恰好在新增包时漂移。 +- **以无界并发运行 publint**:仅在小型机器上以赌注方式最小化耗时,代价是进程数、内存压力、包 tarball 创建和日志可读性的风险。 ## 后果 -钩子的关键路径变为最慢的那个实际门禁,而非隐藏门禁链的总和。Lefthook 报告一个 `full check` job,运行器在该 job 内部报告逐门禁计时,因此本地检查点慢时仍能指出主导耗时的那个门禁。 +钩子的关键路径变为最慢的单个真实门禁,而非隐藏门禁链的总和。Lefthook 报告一个 `full check` job,runner 在该 job 内部报告逐门禁计时,因此本地检查点偏慢时仍能指向主导耗时的那个门禁。 -钩子文件保持简短,重复的成员列表集中在 [scripts/run-gates.ts](../../../../scripts/run-gates.ts) 中,CI 和 pre-push 可以共享。代价是一个自定义调度器脚本(而非纯 lefthook 配置),外加本地 pre-push 路径中的一次构建。 +钩子文件保持简短,重复的成员列表集中在 [scripts/run-gates.ts](../../../../scripts/run-gates.ts) 中,CI 和 pre-push 可以共享。代价是引入一个自定义调度器脚本(而非纯 lefthook 配置),外加本地 pre-push 路径中的一次构建。 -`publint-all.ts` 变为异步代码,缓冲命令输出而非实时继承 stdio。收益是包级并行、稳定的输出顺序,以及一个用于资源调优的环境变量。 +`publint-all.ts` 变为异步代码,缓冲命令输出而非实时继承 stdio。收益是包级别的并行性、稳定的输出顺序,以及一个用于资源调优的环境变量。 diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml index bd24f4a6c1..81355776bb 100644 --- a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-10-readme-known-limitations-gate.md: b7f45421bf0d4d50ec1a19941934e782f52e7926 -2026-07-10-readme-known-limitations-gate.zh.md: 4dd8db1df9b0b2be73e7ae6a64e11b8dabc2add1 +2026-07-10-readme-known-limitations-gate.zh.md: dc023ac43890d8aaaefaece2e592001629e2a74e diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md index 4dd8db1df9..dc023ac438 100644 --- a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md @@ -1,29 +1,29 @@ -# RFC:在每个 package README 中设置受门禁保护的「已知限制」章节 - -Status: implemented +# RFC:在每个 package README 中设置受门禁保护的 Known Limitations 章节 [English](2026-07-10-readme-known-limitations-gate.md) | 中文 +Status: implemented + ## 问题 -[文档标准](../../../AGENTS.md)将限制事项归属于 package README。如果没有统一的格式,缺失的章节无法区分「经过审计确认无限制」和「忘记写了」,而各式各样的标题也让仓库级搜索无从下手。 +[文档标准](../../../AGENTS.md)将限制事项指定在 package README 中记录。如果没有统一的格式,缺失的章节无法区分「经审计确认无此内容」与「忘了写文档」,而标题写法不一致也会妨碍全仓库搜索。 ## 决策 -`packages/<group>/<pkg>/package.json` 下的每个 package manifest(元数据清单)都有一个同级 README,其中包含规范的 `## Known Limitations and Deferred Work` 章节。该章节的条目记录该 package 拥有的持久性消费方缺口与非显而易见的维护约束;普通的清理工作留在源码 TODO 或所属 RFC 中。[`verify-package-readme-limitations` 门禁](../../../../scripts/verify-package-readme-limitations.ts)从 manifest 推导 package 集合,拒绝缺少 README 的情况,并要求恰好有一个规范的 h2 标题且至少包含一个顶级条目。近似标题(如 "Limitations"、"Deferred"、"What is NOT here" 或 "Non-goals")会导致失败。 +`packages/<group>/<pkg>/package.json` 下的每个包(package)manifest(元数据清单)都有一个同目录的 README,其中包含规范的 `## Known Limitations and Deferred Work` 章节。该章节的条目记录该包拥有的持久性消费方缺口与非显而易见的维护者约束;常规清理工作仍留在源码 TODO 或所属 RFC 中。[`verify-package-readme-limitations` 门禁](../../../../scripts/verify-package-readme-limitations.ts)从 manifest 推导包集合,拒绝缺少 README 的情况,并要求恰好有一个规范的 h2 标题且至少包含一个顶级条目。近似标题(如 "Limitations"、"Deferred"、"What is NOT here" 或 "Non-goals")会导致失败。 -如果一个 package 确实没有需要声明的限制,则将其列入 `NO_LIMITATIONS` 并省略该章节。新增限制时必须移除该条目;重命名或删除条目会失败,因为每个条目必须对应一个被扫描的 package。 +如果一个包确实没有需要声明的限制事项,则将其列入 `NO_LIMITATIONS` 并省略该章节。新增限制事项时须移除该条目;重命名或移除条目会失败,因为每个条目都必须对应一个被扫描的包。 -门禁检查存在性、格式和白名单。覆盖率与准确性由文档标准和[行文标准](../../../../.agents/skills/dsh-prose-standard/SKILL.md)下的评审负责。常设规则见 [packages/AGENTS.md](../../../../packages/AGENTS.md)。 +门禁检查的是存在性、格式与白名单。覆盖面和准确性由文档标准与 [prose 标准](../../../../.agents/skills/dsh-prose-standard/SKILL.md)下的评审负责。常设规则见 [packages/AGENTS.md](../../../../packages/AGENTS.md)。 ## 曾考虑的替代方案 -- **自由格式标题**:无法统一搜索,仍然需要近似标题检测。 -- **要求空章节或写 "None."**:样板文字可能在 package 新增限制后仍然残留;白名单使「确认无限制」显式且可评审。 -- **施加字数上限**:合理的限制条目数量因 package 而异,因此由评审管控这一不设预算的 README 层级。 +- **自由格式标题**:无法统一搜索,仍需近似标题检测。 +- **要求空章节或写 "None."**:样板文字可能在包新增限制事项后仍然残留;白名单使「确无限制」这一状态显式且可评审。 +- **设置字数上限**:合理的限制事项数量因包而异,因此由评审管控这一不设预算的 README 层级。 ## 后果 -- 新 package 要么声明符合条件的限制事项,要么显式加入白名单;缺失、漂移或空白的章节会在本地和 CI 的 `doc-sync` 中失败。 -- 门禁向 `doc-sync` 新增一个无外部依赖的 TypeScript 脚本。 -- 重命名被强制的标题需要同时修改脚本和所有 package README。 +- 新建的包须声明符合条件的限制事项,或显式加入白名单;缺失、漂移或空的章节会在本地和 CI 的 `doc-sync` 中失败。 +- 门禁为 `doc-sync` 新增一个无外部依赖的 TypeScript 脚本。 +- 重命名受强制的标题需要同时修改脚本和所有 package README。 diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml index 7796a46dfc..9e9b379eb9 100644 --- a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-12-package-model-experience-contract.md: 036efbc9510d6d0ae9e3c52a5ba8f39647adc4c9 -2026-07-12-package-model-experience-contract.zh.md: 6ee96f3befbb2ead7196f412dccf915f475cfc6d +2026-07-12-package-model-experience-contract.zh.md: b1efa712bc4f6fa7b23c0afe965e56eabf068d97 diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md index 6ee96f3bef..b1efa712bc 100644 --- a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md @@ -1,33 +1,33 @@ -# RFC:包(package)模型体验契约 - -Status: implemented +# RFC:Package Model Experience 契约 [English](2026-07-12-package-model-experience-contract.md) | 中文 +Status: implemented + ## 问题 -一个包的 README 可以解释 API 和运行时机制,却不回答主导 agent harness(智能体框架)行为与成本的核心问题:这个包中有什么内容会进入模型请求、在什么条件下进入、以及这些 token 会保留多久。在插件架构中,这一缺失尤其难以审计。消费方可能把后端结果转为工具消息,策略插件可能把成功替换为错误,压缩(compaction)可能移除旧历史,agent 作用域的注册可能改变某个 agent 的提示词或 schema 而对其他 agent 毫无影响。因此只阅读名义上面向模型的包会遗漏真实的上下文影响,而逐依赖阅读源码对于日常评审又过于昂贵。 +一个 package(包)的 README 可以解释 API 和运行时机制,却不回答那个主导 agent harness(智能体框架)行为与成本的问题:本 package 中有什么内容会进入模型请求、在什么条件下进入、以及这些 token 会保留多久。在插件架构中,这一缺失尤其难以审计。消费方可能把后端结果转为工具消息,策略插件可能把成功替换为错误,上下文压缩(context compaction)可能移除旧历史,agent 作用域的注册可能改变某个 agent 的提示词或 schema 而其他 agent 不受影响。因此,只阅读名义上面向模型的 package 会遗漏真实的上下文影响,而跨所有依赖阅读源码对日常评审来说又太昂贵。 ## 决策 -每个具有面向模型或模型相邻契约的 workspace 包 README,都以规范的 [Model Experience 章节](../../../cookbook/adding-a-package.md#4-write-the-package-readme)结尾,紧接在 `## Known Limitations and Deferred Work` 之前;如果包在 no-limitations 允许列表上,则以 Model Experience 本身结尾。经审计确认为模型无关的通用包通过 `NO_MODEL_EXPERIENCE_SECTION` 省略该章节。 +每个具有面向模型或模型相邻契约的 workspace package README,在末尾、`## Known Limitations and Deferred Work` 之前放置规范的 [Model Experience 章节](../../../cookbook/adding-a-package.md#4-write-the-package-readme);位于 no-limitations 允许列表上的 package 以 Model Experience 本身作为末尾章节。经审计确认为模型无关的通用 package 通过 `NO_MODEL_EXPERIENCE_SECTION` 省略该章节。 -具有直接、条件性、有上限、生命周期性、多表面或辅助模型效应的包,每个上下文表面使用一个 H3。每个 H3 说明相关模型接收到什么内容、何时接收,并对 token 效应进行分类。包所拥有的稳定文本逐字引用:系统提示词及其他长文本使用嵌套 H4 加 `markdown` 围栏,短文本则以行内形式保留,带命名的插值占位符。工具 schema 表面链接到生成的[工具目录](../../../tool-catalog.md)中对应的锚点章节,只陈述组合或配置差异;仅在运行时定义的则说明目录为何未收录。数据依赖和提供方拥有的文本以摘要形式呈现。agent 作用域的可见性须显式标注;当作用域可以隐藏提示词而不隐藏 schema(或反之)时,提示词和 schema 表面保持分开记录。 +具有直接、条件性、有上限、生命周期性、多表面或辅助模型效应的 package,每个上下文表面使用一个 H3。每个 H3 说明相关模型接收到什么内容以及何时接收,然后对 token 效应进行分类。由 package 拥有的稳定文本逐字引用:系统提示词行文和其他长字面量使用嵌套 H4 加 `markdown` 围栏,短字面量则以行内形式呈现并使用命名插值占位符。工具 schema 表面链接到生成的[工具目录](../../../tool-catalog.md)中对应的锚定章节,仅说明组合或配置差异;仅在运行时定义的工具则解释为何目录中未收录。数据依赖和提供方拥有的文本以摘要形式描述。agent 作用域的可见性须显式说明;当作用域可以隐藏其中一个而不影响另一个时,提示词表面与 schema 表面保持分开。 -没有模型上下文效应的包,或其路径完全由另一个包渲染的包,使用验证器审计过的单句形式:`None, as ` 或 `Indirectly, through `。纯传输和无 ctx key 的测试支持包在不产生模型绑定内容时使用 none 形式。提供方后端即使会截断或过滤数据,也使用 indirect 形式;组装 bundle 在所有效应由具名子包拥有时同样使用 indirect 形式。这些句子定位贡献所在,而不重述消费方的内容。结构化章节同样只记录包自身拥有的输入、转换和差异。 +没有模型上下文效应的 package,或其路径完全由另一个 package 渲染的 package,使用验证器审计过的单句形式:`None, as ` 或 `Indirectly, through `。纯传输和无密钥的测试支持 package 在不创建模型绑定内容时使用 none 形式。提供方后端即使对数据进行上限或过滤,也使用 indirect 形式;组装 bundle 在命名子 package 拥有全部效应时同样使用 indirect 形式。这些句子定位贡献所在,而不重述消费方的内容。结构化章节同样只记录 package 自身拥有的输入、变换和差异。 -`verify-package-readme-model-experience` 发现包的 manifest 并验证三种分类、规范的末尾章节顺序、必填字段、具体的文本证据、嵌套的逐字块以及锚定的工具目录链接。它在 `doc-sync` 和并行门禁运行器中运行。覆盖面、链接相关性和事实准确性仍由评审把关。 +`verify-package-readme-model-experience` 发现 package manifest(元数据清单)并验证三种分类、规范的末尾章节顺序、必填字段、具体字面量证据、嵌套逐字块和锚定的工具目录链接。它在 doc-sync(文档同步门禁)和并行门禁运行器中执行。覆盖面、链接相关性和事实准确性仍由评审把关。 ## 曾考虑的替代方案 -- **只记录注册了提示词或工具的包**:否决。后端、策略插件、适配器、持久化、作用域和压缩都会改变 token 的内容或生命周期,却不拥有面向模型的 schema。 -- **从源码生成一份中央上下文成本目录**:否决。AST 能找到注册点,但无法推断语义条件,例如历史保留、输出截断、父子可见性或辅助模型边界。包 README 是实现本地的契约;中央副本会增加又一个漂移面。 -- **要求给出数值 token 计数**:否决。精确计数取决于所选模型的 tokenizer、适配器序列化方式、配置和运行时数据。稳定的契约是增长形态:每请求固定、每调用条件性、保留、替换、有上限或零直接。 -- **使用三列表格**:否决。精确的源文本和条件性结果形态使单元格过于密集、难以扫读。重复的子章节为每个上下文表面提供可读的纵向空间,同时保留相同的字段。 -- **允许所有零影响包省略该章节**:否决。无约束的缺失在「经审计的零影响」和「忘了写文档」之间是歧义的。省略仅限于在验证器中以理由具名的模型无关通用包;模型相邻的零影响包保留一句显式说明。 -- **要求经审计的零影响或简单间接包也使用完整结构化形式**:否决。围绕一个事实重复标签没有意义。一句受门禁约束的句子在保持显式覆盖的同时免去了仪式感。 -- **只有约定、没有门禁**:否决。仓库级契约必须覆盖未来的每个包;评审者的记忆无法可靠地检测到遗漏的 README 章节。 +- **只记录注册提示词或工具的 package**:否决。后端、策略插件、适配器、持久化、作用域和压缩都会改变 token 的内容或生命周期,却不拥有面向模型的 schema。 +- **从源码生成一份集中式上下文成本目录**:否决。AST 能找到注册点,但无法推断语义条件,如历史保留、输出截断、父子可见性或辅助模型边界。package README 是实现本地的契约;集中副本会增加又一个漂移面。 +- **要求给出精确 token 数**:否决。精确数量取决于所选模型的 tokenizer、适配器序列化方式、配置和运行时数据。稳定的契约是增长形状:每请求固定、每调用条件性、保留、替换、有上限或零直接影响。 +- **使用三列表格**:否决。精确的源文本和条件性结果形状使单元格密集且难以扫读。重复的子章节为每个上下文表面提供可读的纵向空间,同时保留相同的字段。 +- **允许所有零影响 package 省略该章节**:否决。无约束的缺失在「经审计的零影响」和「忘记写文档」之间有歧义。省略仅限于在验证器中以理由命名的模型无关通用 package;模型相邻的零影响 package 保留一句显式说明。 +- **对审计过的零影响或简单间接 package 也要求完整结构化形式**:否决。围绕一个事实重复标签没有意义。受门禁约束的单句保留了显式覆盖而无需繁文缛节。 +- **只有约定而无门禁**:否决。仓库级契约必须覆盖未来的每个 package;评审者的记忆无法可靠地检测到遗漏的 README 章节。 ## 后果 -评审者可以从任何面向模型或模型相邻的包出发,看到它对会话模型、子模型和辅助调用的贡献,而无需重建完整的插件图。token 预算工作可以区分每次请求的重复开销与数据依赖的历史,agent 作用域的变更有了显式的文档检查点。包作者在模型可见行为变化时维护一个或多个紧凑的上下文表面块,或一句经分类的句子;经审计的通用包不带无关的模型样板文字。结构化字段不承诺提供方精确的 token 计数;测量仍然是模型和负载特定的,而文档化的增长形态与可见性契约保持稳定。 +评审者可以从任何面向模型或模型相邻的 package 出发,直接看到它对会话模型、子模型和辅助调用的贡献,无需重建完整的插件图。token 预算工作可以区分每次请求的重复开销与数据依赖的历史,agent 作用域的变更有了显式的文档检查点。package 作者在模型可见行为变更时维护一个或多个紧凑的上下文表面块或一句分类说明;经审计的通用 package 不承载无关的模型样板文字。结构化字段不承诺提供方精确的 token 数;测量仍然是模型和负载特定的,而文档化的增长与可见性契约保持稳定。 diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml index f88f300193..7d48003ed6 100644 --- a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-19-drop-mutable-session-summary.md: 0d790191906a9128ad12d40526fde3b9f8fa939f -2026-06-19-drop-mutable-session-summary.zh.md: 97293c296cd74b5a33ce7e1ebe473c970ee95d57 +2026-06-19-drop-mutable-session-summary.zh.md: 6b234eb0dbdf764223e078519c810216c28603be diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md index 97293c296c..6b234eb0db 100644 --- a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md @@ -6,30 +6,30 @@ Status: implemented ## 问题 -[会话持久化 seam](../architecture/2026-06-14-session-persistence.md) 将会话的日志外元数据拆分为 `dsh-session` 拥有的两种类型:一个不可变的 `SessionHeader`(`version`、`id`、`createdAt`、`cwd?`、`parentSession?`),在创建时一次性写入;一个可变的 `SessionSummary`(`updatedAt`、`title?`、`firstPrompt?`),「无需触碰仅追加日志即可更新」。二者的联合类型为 `SessionMeta = SessionHeader & SessionSummary`,抽象的 `SessionPersistence` 服务为此多出第七个方法 `update(id, summary)`,用于重写摘要。各后端各自实现可变存储:JSONL 在日志旁写一个独立的原子 `.summary.json` **伴随文件**(临时写入 + rename,尽力而为);SQLite 在追加事务内更新 `updated_at`/`title`/`first_prompt` **列**。 +[session-persistence seam](../architecture/2026-06-14-session-persistence.md) 将会话的日志外元数据拆分为 `dsh-session` 拥有的两种类型:一个不可变的 `SessionHeader`(`version`、`id`、`createdAt`、`cwd?`、`parentSession?`),在创建时一次性写入;一个可变的 `SessionSummary`(`updatedAt`、`title?`、`firstPrompt?`),「可在不触碰仅追加日志的情况下更新」。二者的联合类型为 `SessionMeta = SessionHeader & SessionSummary`,抽象的 `SessionPersistence` 服务为此多出第七个方法 `update(id, summary)`,用于重写摘要。各后端各自实现可变存储:JSONL 在日志旁写一个独立的原子 `.summary.json` **伴随文件**(临时写入 + rename,尽力保证);SQLite 在追加事务内更新 `updated_at`/`title`/`first_prompt` **列**。 -摘要的设计初衷是服务于未来的会话选择器(通过 `updatedAt` 排序、用 `title`/`firstPrompt` 预览)。该选择器从未实现。对整个仓库的审计表明,`SessionSummary` 的全部表面积都是**死状态**: +摘要是为未来的会话选择器设计的(通过 `updatedAt` 排序近期会话,用 `title`/`firstPrompt` 做预览)。该选择器从未实现。对整个仓库的审计表明,`SessionSummary` 的全部表面积都是**死状态**: -- `SessionPersistence.update()` 的**生产调用方为零**(所有 `.update(` 命中都是 `createHash().update()` 或测试代码)。 +- `SessionPersistence.update()` **零个生产调用方**(所有 `.update(` 匹配都是 `createHash().update()` 或测试代码)。 - `firstPrompt` 在生产代码中**从未被读取**。 -- `title` 确实在 ACP bridge 中被读取,但来源是工具调用的 **presenter**(`present.title`),而非存储的会话元数据。 -- `updatedAt` **没有消费方**:`list()` 唯一的生产调用方读取的是 `meta.cwd`(`SessionHeader` 字段),用于在 `session/load` 时校验工作区;resume 读取的是 `createdAt`/`cwd`/`parentSession`,全部是 header 字段。 -- 决定性的事实:活跃的 `Session.header` 早已被类型化为 `SessionHeader` 而非 `SessionMeta`——摘要从未存在于活跃会话对象上;它只存在于持久化层,除了自身的契约测试之外无人写入、无人读取。 +- `title` 确实在 ACP 桥接层被读取过,但读的是工具调用的 **presenter**(`present.title`),从未读取存储的会话元数据。 +- `updatedAt` **没有消费方**:`list()` 唯一的生产调用方读取的是 `meta.cwd`(`SessionHeader` 字段),用于在 `session/load` 时校验工作区;恢复会话读取的是 `createdAt`/`cwd`/`parentSession`——全是 header 字段。 +- 决定性的一点:活跃的 `Session.header` 类型本来就是 `SessionHeader` 而非 `SessionMeta`——摘要从未存在于活跃会话对象上;它只存在于持久化层,除了自身的契约测试外无人写入、无人读取。 ## 决策 -彻底删除可变的会话摘要。`SessionSummary` 与 `SessionMeta` 这个名称一并移除;后端存储和返回的元数据仅为 `SessionHeader`。`SessionPersistence.update()` 从抽象服务和所有后端中移除。JSONL 去掉整套伴随文件机制(`writeSidecar`/`readSidecar`/`touchSummary`/`removeSidecars`/`sidecarPath` 以及 load/list 的覆盖逻辑);SQLite 删除 `updated_at`/`title`/`first_prompt` 列及每次追加时的 `updated_at` 更新,其 `SCHEMA_VERSION` 从 `1 → 2`。 +彻底删除可变的会话摘要。`SessionSummary` 与 `SessionMeta` 这个名称一并移除;后端存储和返回的元数据仅为 `SessionHeader`。`SessionPersistence.update()` 从抽象服务和所有后端中移除。JSONL 去掉整套伴随文件机制(`writeSidecar`/`readSidecar`/`touchSummary`/`removeSidecars`/`sidecarPath` 以及 load/list 的覆盖逻辑);SQLite 去掉 `updated_at`/`title`/`first_prompt` 列以及每次追加时的 `updated_at` 更新,其 `SCHEMA_VERSION` 从 `1 → 2`。 -摘要原本要提供的一切,在消费方真正需要时都**可从仅追加日志中派生**(`firstPrompt` = 第一条 `user/message`;最近活跃时间 = 最后一个事件的 `time` 或文件 mtime),或者已经存在于不可变的 header 中(`createdAt`、`cwd`)。唯一*不可*派生的——用户*手动编辑*的标题——没有任何实现,纯属 YAGNI;如果未来真有功能需要,它可以作为独立的日志事件或 header 字段回归。 +摘要原本要提供的一切,在消费方真正需要时都**可从仅追加日志中派生**(`firstPrompt` = 第一条 `user/message`;近期度 = 最后一个事件的 `time` 或文件 mtime),或者已经存在于不可变 header 中(`createdAt`、`cwd`)。唯一不可派生的是用户*手动编辑*的标题,但它从未实现,纯属 YAGNI;如果未来真有功能需要,它可以作为独立的日志事件或 header 字段回归。 -将此记录为决策,是因为它**持久**(收窄了一个公开服务契约和两个后端的磁盘格式)、**有争议**(摘要是有意的前瞻性设计,不是意外产物)、**出人意料**(未来读者看到 `SessionHeader` 而原始 RFC 描述的是 `SessionMeta`,否则会疑惑摘要为何消失)。它还为[共享持久化写入协调器](../architecture/2026-06-18-shared-persistence-write-coordinator.md)扫清了障碍:没有可变摘要,协调器的钩子接口就不需要 `updateSummary` 钩子,JSONL 伴随文件与 SQLite 列之间的持久性差异也随之消失,两个后端的写入路径得以收敛。 +将此记录为决策,原因有三:**持久性**(它收窄了一个公开服务契约和跨两个后端的磁盘格式)、**争议性**(摘要是有意的前瞻性设计,而非意外产物)、**意外性**(未来读者看到 `SessionHeader` 而原始 RFC 描述的是 `SessionMeta`,否则会疑惑摘要为何消失)。它还为 [shared persistence write coordinator](../architecture/2026-06-18-shared-persistence-write-coordinator.md) 扫清了障碍:没有可变摘要后,协调器的钩子接口无需 `updateSummary` 钩子,JSONL 伴随文件与 SQLite 列之间的持久性分歧也随之消失,两个后端的写入路径得以统一。 ## 无需迁移 -这是未发布的软件(见[根 AGENTS.md](../../../../AGENTS.md)「预发布立场:地基优先于爆炸半径」一节),因此不存在需要保留的磁盘数据库或日志。SQLite 不迁移 v1 数据库:`openDatabase` 守卫现在拒绝任何非当前版本的磁盘 `user_version`(`onDisk !== 0 && onDisk !== SCHEMA_VERSION`),无论更旧还是更新,因此陈旧的 v1 数据库会被干净地拒绝,而非在新列集上半读半错。新建数据库写入当前版本号;这是唯一需要工作的路径。 +这是未发布的软件(见[根 AGENTS.md](../../../../AGENTS.md)「Pre-release stance: foundation over blast radius」一节),因此没有需要保留的磁盘数据库或日志。SQLite 不迁移 v1 数据库:`openDatabase` 守卫现在拒绝任何非当前版本的磁盘 `user_version`(`onDisk !== 0 && onDisk !== SCHEMA_VERSION`),无论更旧还是更新,因此陈旧的 v1 数据库会被干净地拒绝,而非在新列集下被半读取。新建数据库写入当前版本号;这是唯一需要正常工作的路径。 ## 后果 -未来的会话选择器现在必须从日志派生预览和排序信息(或重新引入一个类型化字段),而不能直接读取现成的摘要行。这是正确的代价:为一个不存在的功能维护缓存,是每个后端都要承担的死重,也是每个契约测试都要断言的负担。这一原则——**通过的测试固定的是当前行为,不一定是正确行为;行为可能是过去妥协的产物**——现已作为独立约定记录在[根 AGENTS.md](../../../../AGENTS.md) 中,本次变更即为其实例。 +未来的会话选择器现在必须从日志派生预览/排序信息(或重新引入一个类型化字段),而不能直接读取现成的摘要行。这是正确的代价:为一个尚不存在的功能维护缓存,是每个后端都要付出维护成本、每个契约测试都要付出断言成本的死重。这一原则——**通过的测试固定的是当前行为,不一定是正确行为;行为可能是过去妥协的产物**——现已作为独立约定记录在[根 AGENTS.md](../../../../AGENTS.md) 中,本次变更即为其实例。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml index 0e73dbfe7e..807d67d2fc 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-collapse-trace-only-session-events.md: 9156c2ab356b1c46758d9d2047d491cd1952cbc4 -2026-06-20-collapse-trace-only-session-events.zh.md: f2ecfbf46d8d70cf478d57eae2ed3a18ea8746fa +2026-06-20-collapse-trace-only-session-events.zh.md: c4555f3a772096fc36de968d5d3085f5a2e879f3 diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md index f2ecfbf46d..c4555f3a77 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md @@ -6,39 +6,39 @@ Status: implemented ## 问题 -会话事件词汇中包含一些一等事件,它们既不属于可回放的对话历史,在生产环境中也几乎没有消费方。`usage` 在模型流式分片中已经存在,但循环又额外追加了一个独立的 `usage` 事件。`error` 与 `turn/end { kind: 'error', message, code }` 中的循环失败原因重复;ACP(Agent Client Protocol)结算读取的是 turn-end 原因,ACP 渲染忽略 `error` 事件,`deriveMessages()` 也跳过它。 +会话事件词汇中包含一些一等事件,它们不属于可回放的对话历史,在生产环境中几乎没有消费方。`usage` 已经作为模型流分片存在,之后循环又追加了一个独立的 `usage` 事件。`error` 与 `turn/end { kind: 'error', message, code }` 中的循环失败原因重复;ACP(Agent Client Protocol)结算读取 turn-end 原因,ACP 渲染忽略 `error` 事件,`deriveMessages()` 也跳过它。 -这些事件让规范的 transcript(文本记录)看起来比实际更像遥测数据。它们增加了事件变体、不变式、测试、快照和持久化用例,但作为独立记录并不承载实际负荷。它们携带的事实仍然有用:token 用量应当保留以供核算,错误的步骤编号也不应悄然消失。简化的方式是将这些事实折叠进消费方本就必须理解的邻近事件,而非减少记录的信息量。 +这些事件让规范的 transcript(文本记录)看起来比实际更像遥测数据。它们增加了事件变体、不变式、测试、快照和持久化用例,但作为独立记录并不承载实际功能。它们携带的事实仍然有用:token 用量应当保留以供计费,错误的步骤编号也不应悄然消失。简化的方式是将这些事实折叠进消费方本已必须理解的邻近事件,而非减少记录的信息量。 ## 决策 -仅在信息已被保留、无需并行记录的位置移除独立的追踪事件: +仅在信息已被保留、无需并行记录的情况下,移除独立的追踪事件: -- 成功步骤的 usage 折叠进对应的 `assistant/message`(`assistant/message { turn, step, content, usage? }`),使组装好的模型输出与其核算信息一同传递。 -- 失败或中止的步骤如果有 usage 但没有 assistant 内容,则将 usage 挂在一个空内容的 `assistant/message` 上(下方实现说明给出了无信息丢失的证明)——不会有任何已持久化的 usage 分片失去表示。 -- 独立 `error` 事件中的步骤编号折叠进 `turn/end.reason`(当 `kind: 'error'` 时:`{ kind: 'error', step, message, code? }`)——`turn/end` 是 ACP 和恢复机制已在消费的持久化轮次结果。 -- `agent/error` 和日志保留用于实时诊断;`turn/end` 之后不再有第二条会话日志错误记录。 +- 成功步骤的 usage 折叠进匹配的 `assistant/message`(`assistant/message { turn, step, content, usage? }`),使组装好的模型输出与其计费信息一同传递。 +- 失败或中止的步骤如果有 usage 但没有 assistant 内容,则将 usage 放在一个空内容的 `assistant/message` 上(下方实现说明给出了无信息丢失的证明)——不会有已持久化的 usage 分片无处安放。 +- 独立 `error` 事件中的步骤编号折叠进 `turn/end.reason`(当 `kind: 'error'` 时:`{ kind: 'error', step, message, code? }`)——`turn/end` 是 ACP 和恢复机制已经消费的持久轮次结果。 +- `agent/error` 与日志保留用于实时诊断;`turn/end` 之后不再有第二条会话日志错误记录。 -用户对话日志包含渲染、恢复、审计和核算交互所需的全部信息,消费方无需对账重复的追踪行。 +用户对话日志包含渲染、恢复、审计和计费所需的全部信息,消费方无需协调重复的追踪行。 ## 曾考虑的替代方案 -**保留独立行作为遥测**:这些事件让规范的 transcript 看起来比实际更像遥测数据,代价是增加了事件变体、不变式、测试、快照和持久化用例,却没有消费方使用。如果分析需求真正出现,正确的形态是投影辅助工具或带有独立保留策略的专用遥测存储,而非在对话日志中放置重复的追踪行。 +**保留独立行作为遥测**——这些事件让规范 transcript 看起来比实际更像遥测数据,代价是增加了事件变体、不变式、测试、快照和持久化用例,却没有任何消费方使用。如果分析需求真正出现,正确的形态是投影辅助工具或带有独立保留策略的专用遥测存储,而非对话日志中的重复追踪行。 ## 验证 -`SessionEventMap` 不再包含独立的 `usage` 或 `error`;循环不再追加独立的 usage 事件,持久化的失败通过 `turn/end { kind: 'error', step, message, code? }` 记录;ACP 快照和持久化测试断言不存在仅追踪行;录制的 fixture(测试前置数据)已采用新事件形状,会话格式版本固定为 `0`(按预发布格式策略,后端拒绝任何非 `0` 的存储日志);文档说明了 token 用量和操作错误的观测位置。 +`SessionEventMap` 不再包含独立的 `usage` 或 `error`;agent loop(智能体循环)不再追加独立的 usage 事件,持久性失败通过 `turn/end { kind: 'error', step, message, code? }` 记录;ACP 快照和持久化测试断言不存在仅追踪行;已录制的 fixture(测试前置数据)使用新事件形状,会话格式版本固定为 `0`(后端按预发布格式策略拒绝任何非 `0` 的存储日志);文档说明了 token 用量和操作错误的观测位置。 ## 后果 -消费方不能再从规范日志中筛选独立的 `usage` 或步骤级 `error` 行,必须从承载它们的 assistant/failure 事件中读取这些事实。只有当实现 PR 证明相同的事实仍然存在时,这才是合理的简化;否则独立事件应当保留。 +消费方不能再从规范日志中筛选独立的 `usage` 或步骤级 `error` 行,必须从承载它们的 assistant/failure 事件中读取这些事实。只有在实现 PR(Pull Request)证明相同事实仍然存在的前提下,这才是合理的简化;否则独立事件应予保留。 ## 实现说明 按提案交付,有一处范围细化(遵循 AGENTS.md「RFC 是提案,不是金科玉律」): -- **空内容的 `assistant/message` 承载 usage,无数据丢失。** 提案要求的证明(不会有已持久化的 usage 分片失去表示)落在 max-tokens 路径上:一个被截断的步骤有 usage 但内容为空(例如只有一个被丢弃的工具调用),此前会发出独立的 `usage`。现在它记录一条空内容的 `assistant/message { content: [], usage }`。为避免这向提供方 transcript 注入一个无内容的虚假 assistant 轮次,`deriveMessages()` 跳过空内容的 `assistant/message` 事件。一个回归测试断言 usage 仍有表示,且派生历史未被破坏。 +- **空内容 `assistant/message` 承载 usage,无数据丢失。** 提案要求的证明(不会有已持久化的 usage 分片无处安放)落在 max-tokens 路径上:一个被截断的步骤有 usage 但内容为空(例如只有一个被丢弃的工具调用),以前会发出独立的 `usage`。现在它记录一个空内容的 `assistant/message { content: [], usage }`。为防止这向 provider transcript 注入一个无内容的虚假 assistant 轮次,`deriveMessages()` 跳过空内容的 `assistant/message` 事件。回归测试断言 usage 仍被表示,且派生历史未被破坏。 -**格式版本。** 此变更改动了持久化事件,但预发布会话格式仍固定为 `0`,拒绝任何其他版本且不做迁移。`dsh-session` 拥有写入方和加载校验使用的常量。单调递增的格式版本从首次正式发布开始。 +**格式版本。** 此变更影响已持久化的事件,但预发布会话格式仍固定为 `0`,拒绝任何其他版本且不做迁移。`dsh-session` 拥有写入方和加载校验使用的常量。单调递增的格式版本从首次正式发布开始。 -Usage 现在通过 `assistant/message.usage` 观测;操作错误的步骤编号通过 `turn/end.reason`(当 `kind: 'error'` 时)观测。`agent/error` 加日志用于实时诊断,保持不变。 +Usage 现在通过 `assistant/message.usage` 观测;操作错误的步骤编号通过 `turn/end.reason`(当 `kind: 'error'` 时)观测。`agent/error` 与日志用于实时诊断,保持不变。 diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml index 8586b4051e..dbb62e578d 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-unconsumed-llm-adapter-change-event.md: efe90c0197671ef4385ce517540b4b238962c3b5 -2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md: 13f01566472a030cc9d4f97f6e4438fe4c3ecbf8 +2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md: b26610cfe273820112113c73b9313557cd78262c diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md index 13f0156647..b26610cfe2 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md @@ -1,4 +1,4 @@ -# RFC:移除无消费方的 `llm/adapter-change` 事件 +# RFC:移除未被消费的 `llm/adapter-change` 事件 Status: implemented @@ -6,31 +6,31 @@ Status: implemented ## 问题 -`LlmService.registerAdapter()` 在注册和 dispose(资源释放)时发射 `llm/adapter-change`([packages/llm/llm/src/index.ts](../../../../packages/llm/llm/src/index.ts))。在 `packages/*/src` 和 `examples/*/src` 中 grep `llm/adapter-change`,只能找到声明、发射点、文档和测试;没有任何生产代码监听它。 +`LlmService.registerAdapter()` 在注册和 dispose(资源释放)时发出 `llm/adapter-change` 事件([packages/llm/llm/src/index.ts](../../../../packages/llm/llm/src/index.ts))。在 `packages/*/src` 和 `examples/*/src` 中搜索 `llm/adapter-change`,只能找到声明、emit 站点、文档和测试;没有任何生产环境的监听器订阅它。 -这与 `tools/change` 和 `system-prompt/change` 不同。后两个事件目前同样无消费方,但它们是合理的注册表变更信号,未来的实时工具/提示词 UI 可能用到。LLM 适配器注册更像是启动时的实现细节:适配器不是用户可见的面板,真正的模型调用拦截 seam 是 `llm/stream`。保留一个没有监听者的 adapter-change 事件,是 [drop-the-dead-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 模式在更小尺度上的重复。 +这与 `tools/change` 和 `system-prompt/change` 不同。后两个事件目前同样未被消费,但它们是合理的注册表变更信号,未来可能服务于实时工具/提示词 UI。LLM(大语言模型)适配器注册更接近启动时的实现细节:适配器不是用户可见的面板,真正的模型调用拦截 seam 是 `llm/stream`。保留一个没有监听器的 adapter-change 事件,是在更小规模上重复 [drop-the-dead-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 的模式。 -这个事件并非零成本。`registerAdapter()` 在发射 `llm/adapter-change` 之前先 yield 回滚 disposer,这样抛异常的监听者会回退变更而不是泄漏一条适配器条目;包里还有测试覆盖这条监听者抛异常的路径。这种防御性排序所保护的失败模式,只有测试才能触发。 +这个事件并非零成本。`registerAdapter()` 在发出 `llm/adapter-change` 之前先 yield 回滚 disposer,这样抛出异常的监听器会回退变更而非泄漏适配器条目;包内还有针对该监听器抛出路径的测试。这种防御性排序保护的是一个只有测试才能触发的失败模式。 ## 决策 -只移除 `llm/adapter-change`:`dsh-llm` 的 `interface Events` 中的声明、`ctx.emit('llm/adapter-change')` 调用,以及 `LlmService.registerAdapter` JSDoc 中「在注册和 dispose 时发射 `llm/adapter-change`」的描述。`registerAdapter()` 的 effect generator 保留变更与回滚 disposer(用于 HMR(热模块替换)/dispose),但去掉仅为已移除事件而存在的监听者抛异常回滚排序。适配器 disposer 测试断言返回的 disposer 能移除适配器,不再订阅该事件;监听者抛异常的回滚测试随其主题一同移除。[docs/architecture.md](../../../architecture.md) 和 [packages/llm/llm/README.md](../../../../packages/llm/llm/README.md) 中的事件分类体系在同一个变更中更新。 +仅移除 `llm/adapter-change`:`dsh-llm` 的 `interface Events` 中的声明、`ctx.emit('llm/adapter-change')` 调用,以及 `LlmService.registerAdapter` JSDoc 中的 "Emits `llm/adapter-change` on registration and disposal" 语句。`registerAdapter()` 的 effect generator 保留变更与回滚 disposer 以支持 HMR(热模块替换)/dispose,但去掉了仅为已移除事件而存在的监听器抛出回滚排序。适配器 disposer 测试断言返回的 disposer 能移除适配器,而不再订阅该事件;监听器抛出回滚测试随其主题一同移除。[docs/architecture.md](../../../architecture.md) 和 [packages/llm/llm/README.md](../../../../packages/llm/llm/README.md) 中的事件分类体系在同一个变更中更新。 ## 曾考虑的替代方案 ### 为什么不移除所有注册表变更事件? -一个注册表主动广播变更的微内核是一种自洽的约定。`tools/change` 和 `system-prompt/change` 在 UI 能实时刷新可用工具或提示词段落时可能变得有用。本 RFC 在有合理的面向用户消费方的地方保留该约定,仅裁掉当前和可预见未来都没有明确消费方的 adapter-change 事件。 +一个注册表主动广播变更的微内核是一种自洽的约定。`tools/change` 和 `system-prompt/change` 在 UI 能实时刷新可用工具或提示词段落时可能变得有用。本 RFC 保留该约定中有合理的面向用户消费方的部分,仅裁掉当前和可预见未来消费方都不明确的 adapter-change 事件。 -如果将来需要 LLM 适配器浏览器或动态模型选择器,届时再连同消费方一起重新引入该事件,并给出比「something changed」更清晰的 payload。 +如果将来需要 LLM 适配器浏览器或动态模型选择器用到此信号,届时再连同消费方一起重新引入,并提供比「something changed」更清晰的 payload。 ## 验证 -`llm/adapter-change` 及其发射点已移除,重新生成的 cordis catalog 是最新的;HMR 安全性保持(dispose 一个贡献 fiber 会移除对应适配器);`tools/change` 和 `system-prompt/change` 仍有文档和测试;没有任何生产路径的可观测行为发生变化——ACP 快照 golden 和 echo-agent 冒烟测试逐字节不变。 +`llm/adapter-change` 及其 emit 已移除,重新生成的 cordis catalog 是最新的;HMR 安全性保持(dispose 一个贡献 fiber 会移除对应适配器);`tools/change` 和 `system-prompt/change` 仍有文档和测试;没有任何生产路径的可观察行为发生变化——ACP(Agent Client Protocol)快照 golden 和 echo-agent 冒烟测试逐字节未变。 ## 后果 -- **移除一个已文档化的发射事件属于公开接口变更。** 它出现在分类体系表中,读起来像是有意为之的 API。但「已声明并发射」不等于「有消费方」——这正是当初移除可变 summary 时所依据的同一区分。分类体系表在同一个变更中更新,因此文档不会漂移。 -- **注册表变更约定变得不均匀。** 这是可以接受的,因为 LLM 适配器注册与工具或提示词段落不是同一层面的用户可见概念。不均匀但诚实,胜过统一但空转。 +- **移除一个已文档化的 emit 事件属于公开接口变更。** 它出现在分类体系表中,读起来像有意设计的 API。但「已声明且已发出」不等于「已被消费」——这与移除可变 summary 时的判断依据相同。分类体系表在同一个变更中更新,因此文档不会漂移。 +- **注册表变更约定变得不均匀。** 这是可接受的,因为 LLM 适配器注册与工具或提示词段落不是同一层面的面向用户概念。不均匀但诚实,胜过统一但无用。 -这是一个小裁剪,但它退役了一条守护着不存在的消费方的常设正确性不变式。 +这是一个小裁剪,但它退役了一条守护着并不存在的消费方的正确性不变式。 diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml index 46b752f26a..0d895a2b35 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-unconsumed-llm-assembled-surfaces.md: c8999dd0e19b2c8eaff854c8ff544bae2fc068b6 -2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md: 090d3e779e3e7a9f1f0a65af7740ad685f723cf6 +2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md: de297a8cb64d9002fce2c857fd3caa5f2b25f43a diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md index 090d3e779e..de297a8cb6 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md @@ -1,4 +1,4 @@ -# RFC:移除未被消费的 LLM 组装便利接口 +# RFC:移除未被消费的 LLM 组装便捷接口 Status: implemented @@ -9,31 +9,31 @@ Status: implemented `LlmService`([packages/llm/llm/src/index.ts](../../../../packages/llm/llm/src/index.ts))在模型之上暴露了三个调用接口: - `stream()`:原始 `StreamChunk`,通过 `llm/stream` waterfall(瀑布式事件)分发。 -- `streamBlocks()`:一个"便利视图",将 chunk 送入 `BlockAssembler` 并按流顺序 yield 已组装完成的 `ContentBlock`([index.ts:137-144](../../../../packages/llm/llm/src/index.ts))。 -- `generate()`:一个完整组装的 `GenerateResult`,通过第二个 `llm/generate` waterfall 分发([index.ts:151-157](../../../../packages/llm/llm/src/index.ts))。 +- `streamBlocks()`:一个「便捷视图」,将分片送入 `BlockAssembler` 并按流顺序产出已组装的 `ContentBlock`([index.ts:137-144](../../../../packages/llm/llm/src/index.ts))。 +- `generate()`:一个完整组装的 `GenerateResult`,通过第二条 `llm/generate` waterfall 分发([index.ts:151-157](../../../../packages/llm/llm/src/index.ts))。 -LLM(大语言模型)服务唯一的生产消费方是 agent loop(智能体循环),它只使用 `stream()`:将原始 chunk 送入自己的 `BlockAssembler`,以便在并行组装的同时记录 chunk 用于回放保真([packages/core/agent-loop/src/loop.ts](../../../../packages/core/agent-loop/src/loop.ts) 中的 `ctx.llm.stream(req)` 步骤)。在 `packages/*/src` 和 `examples/*/src` 中搜索 `streamBlocks` 与 `ctx.llm.generate`,找不到任何生产调用方。引用它们的只有服务方法定义、文档和测试;适配器测试用 `generate()` 作为便利驱动,但它们完全可以通过同一个 assembler 辅助函数手动消费 `stream()`,无需保留一个公开的生产 API。 +LLM(大语言模型)服务唯一的生产消费方是 agent loop(智能体循环),它只使用 `stream()`:将原始分片送入自己的 `BlockAssembler`,以便在并行组装的同时记录分片,保证回放保真度([packages/core/agent-loop/src/loop.ts](../../../../packages/core/agent-loop/src/loop.ts),`ctx.llm.stream(req)` 步骤)。在 `packages/*/src` 和 `examples/*/src` 中 grep `streamBlocks` 与 `ctx.llm.generate`,找不到任何生产调用方。仅有的引用来自服务方法定义、文档和测试;适配器测试用 `generate()` 作为便捷驱动,但它们完全可以通过同一个 assembler 辅助函数手动消费 `stream()`,无需为此保留一个公开的生产 API。 -这与 [drop-mutable-session-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 是同一模式:拥有测试契约的组装视图 API,消费方只有测试而非生产代码。它们是为"不关心 token 级增量"的消费方预先构建的,但唯一的真实消费方恰恰需要增量,以便持久化高保真的回放数据。 +这与 [drop-mutable-session-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 是同一模式:拥有经过测试的契约的组装视图 API,消费方却只有测试而非生产代码。它们是为「不关心 token 级增量」的消费方预设的,但唯一的真实消费方恰恰需要增量,以便持久化高保真回放数据。 -`streamBlocks()` 拖带了 `BlockAssembler` 中一块专用逻辑:`flushReady()` 和 `flushRemaining()`([packages/llm/llm/src/assembler.ts:138-168](../../../../packages/llm/llm/src/assembler.ts))以及 `flushed` 游标字段,仅为支持按序增量 yield 而存在。`generate()` 拖带了 `GenerateResult`、`BlockAssembler.result()` 以及 `llm/generate` waterfall——在同一底层流之上多出的第二个拦截面。agent loop 对 assembler 的使用仅限 `push()` / `message()` / `usage` / `finish`,不涉及流式 flush 或一次性服务组装。 +`streamBlocks()` 拖带了 `BlockAssembler` 的一块专用逻辑:`flushReady()` 与 `flushRemaining()`([packages/llm/llm/src/assembler.ts:138-168](../../../../packages/llm/llm/src/assembler.ts))以及 `flushed` 游标字段,仅为支持按序增量产出而存在。`generate()` 拖带了 `GenerateResult`、`BlockAssembler.result()` 以及 `llm/generate` waterfall——在同一底层流之上的第二个拦截面。agent loop 对 assembler 的使用仅限于 `push()` / `message()` / `usage` / `finish`,不涉及流式 flush 或一次性服务组装。 ## 决策 -`stream()` 是唯一的公开 LLM 调用接口。移除 `streamBlocks`、`generate`、其事件/结果类型,以及仅被该路径使用的 assembler 辅助方法。适配器测试通过本地辅助函数对公开的 stream 进行组装,`BlockAssembler` 只保留有生产消费方的操作。 +`stream()` 是唯一的公开 LLM 调用接口。移除 `streamBlocks`、`generate`、其事件/结果类型,以及仅被该路径使用的 assembler 辅助方法。适配器测试通过本地辅助函数对公开的 stream 进行组装;`BlockAssembler` 仅保留有生产消费方的操作。 ## 曾考虑的替代方案 -**保留 `generate()` 作为仅供测试的便利方法**:否决。适配器测试通过共享 assembler 手动消费 `stream()`,走的是与生产相同的流式路径;一个唯一调用方是测试的公开方法,正是[移除可变摘要先例](2026-06-19-drop-mutable-session-summary.md)所清退的死接口形态。未来如果有消费方需要不带增量的组装块,届时再引入一个有真实消费方的专用辅助方法。 +**保留 `generate()` 作为仅供测试的便捷方法**:否决。适配器测试通过共享 assembler 手动消费 `stream()`,走的是与生产完全相同的流式路径;一个唯一调用方只有测试的公开方法,正是 [drop-mutable-summary 先例](2026-06-19-drop-mutable-session-summary.md)所淘汰的死接口形态。未来如果有消费方需要不带增量的组装块,届时再为该消费方引入一个聚焦的辅助方法。 ## 验证 -`streamBlocks`、`generate`、`llm/generate` 以及仅被它们使用的 assembler 辅助方法已全部移除,无新增死导出;两个真实适配器通过 `stream()` 加共享 assembler 得到充分测试;agent loop 行为不变(ACP 快照 golden 文件无变化);README、架构文档与模块文档中不再提及被移除的接口。 +`streamBlocks`、`generate`、`llm/generate` 及其独占的 assembler 辅助方法已移除,无新增死导出;两个真实适配器通过 `stream()` 和共享 assembler 得到验证;agent loop 行为不变(ACP 快照 golden 文件无变化);README、架构文档与模块文档中不再提及已移除的接口。 ## 后果 -- **从一个核心词汇包中移除了公开方法。** 未来如果有插件需要不带增量的组装块,它需要直接调用 `stream()` 并使用 `BlockAssembler`,或在有真实消费方时重新引入一个专用辅助方法。鉴于预发布阶段「基础优先于投机性未来」的立场([AGENTS.md](../../../../AGENTS.md)),现在正是清除仅供测试的公开形状的正确时机。 -- **适配器测试变得更显式。** 它们失去了便利的 `generate()` 包装层,但这是有益的压力:测试走的是与生产相同的流式路径。 -- **waterfall 使用方失去 `llm/generate`。** 不存在生产监听者。未来的缓存/重试/日志插件应包装 `llm/stream`,它仍是唯一的提供方调用路径。 +- **从一个核心词汇包中移除了公开方法。** 未来如果有插件需要不带增量的组装块,它需要直接调用 `stream()` 并使用 `BlockAssembler`,或在有真实消费方时重新引入一个聚焦的辅助方法。鉴于预发布阶段「基础优先于预设未来」的立场([AGENTS.md](../../../../AGENTS.md)),现在正是裁剪仅供测试的公开接口的合适时机。 +- **适配器测试变得更显式。** 它们失去了便捷的 `generate()` 包装层,但这是有益的压力:测试走的是与生产相同的流式路径。 +- **waterfall 使用者失去 `llm/generate`。** 不存在生产监听者。未来的缓存/重试/日志插件应包装 `llm/stream`,它仍然是唯一的提供方调用路径。 -变更规模不大,但它干净地从 LLM 包中移除了投机性的接口面积,为生产和测试留下唯一一份模型调用契约。 +改动规模不大,但它从 LLM 包中干净地移除了预设的接口面积,为生产和测试留下唯一一份模型调用契约。 diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml index 20c7e3718a..e995e57540 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-prune-dead-seam-methods.md: cb3eb576dbae209ddccbea7f42a80ef09f842887 -2026-06-20-prune-dead-seam-methods.zh.md: d3c658ea2ce994e640ec4fd2cf5f74d82f695e69 +2026-06-20-prune-dead-seam-methods.zh.md: 988da3c44d8860d89f090f0ea9e2af49ae9007dd diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md index d3c658ea2c..988da3c44d 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md @@ -1,43 +1,43 @@ -# RFC:清理持久化 seam 中的无用方法 +# RFC:从 persistence seam 中移除无用方法 [English](2026-06-20-prune-dead-seam-methods.md) | 中文 Status: implemented -> **实现说明:** 最终只移除了 `SessionPersistence.has()` 和 `.delete()`。`BashExecutor.get()` 和 `.list()` 保留,因为移除它们的单行查找接口需要在消费方引入大量额外的完成状态跟踪机制。它们的 id 品牌化由 [branded-ids RFC](../architecture/2026-06-20-branded-ids.md) 覆盖。 +> **实现说明:** 最终只移除了 `SessionPersistence.has()` 和 `.delete()`。`BashExecutor.get()` 和 `.list()` 保留,因为移除它们的单行查询接口需要在消费方引入大量额外的完成状态追踪机制。它们的 id 品牌化由 [branded-ids RFC](../architecture/2026-06-20-branded-ids.md) 覆盖。 ## 问题 -一个能力 seam([接口/实现/消费方](../../implemented/architecture/2026-06-13-capability-seams.md))携带了没有任何消费方调用的抽象方法。seam 存在的意义是让实现与消费方独立演进,但一个没有消费方编程依赖的方法不是 seam,而是投机性的接口面——每个实现仍然必须实现并测试它。 +一个能力 seam([接口/实现/消费方](../../implemented/architecture/2026-06-13-capability-seams.md))承载着没有任何消费方调用的抽象方法。seam 的存在是为了让实现与消费方独立演进,但一个没有消费方编程依赖的方法不是 seam,而是每个实现仍须实现和测试的投机性接口面。 ### `SessionPersistence.has()` 与 `.delete()` -抽象服务在 create/append 之外声明了更多操作:`load`、`list`、`has`、`delete`。`ctx.sessionPersistence` 的生产消费方只用到两个:agent loop(智能体循环)的恢复路径调用 `load()`([packages/core/agent-loop/src/index.ts:176](../../../../packages/core/agent-loop/src/index.ts)),ACP 桥接层为 `session/list` 调用 `list()`([packages/ui/acp/src/index.ts:494](../../../../packages/ui/acp/src/index.ts))。在 `packages/*/src` 和 `examples/` 中 grep 所有 `sessionPersistence.*` / `persistence.*` 用法,找不到对该服务的 `has(` 或 `delete(` 调用。`packages/ui/acp/src/index.ts` 中的 `.has(`/`.delete(` 调用作用于内存中的 `SessionStore` 和一个本地的 loading id `Set`,而非持久化服务。`has`/`delete` 的唯一调用方是契约测试套件和各后端的 spec。 +该抽象服务在 create/append 之外声明了更多操作:`load`、`list`、`has`、`delete`。`ctx.sessionPersistence` 的生产消费方只用了两个:agent loop(智能体循环)的恢复路径调用 `load()`([packages/core/agent-loop/src/index.ts:176](../../../../packages/core/agent-loop/src/index.ts)),ACP(Agent Client Protocol)桥接层为 `session/list` 调用 `list()`([packages/ui/acp/src/index.ts:494](../../../../packages/ui/acp/src/index.ts))。在 `packages/*/src` 和 `examples/` 中 grep 所有 `sessionPersistence.*` / `persistence.*` 的使用,找不到对该服务的 `has(` 或 `delete(` 调用。`packages/ui/acp/src/index.ts` 中的 `.has(`/`.delete(` 调用作用于内存中的 `SessionStore` 和一个本地的 loading id `Set`,而非 persistence。`has`/`delete` 的唯一调用者是契约测试套件和各后端的 spec。 -`has()` 不仅仅是未使用——它还是共享协调器中最复杂的分支:一个 tracked-vs-untracked 双探测(`loadLive(id, cwd)` 用于活跃跟踪的会话,`loadStored(id)` 用于未跟踪的会话),附带多行注释说明理由。`delete()` 则拖带了 `deleteStored` 后端钩子,每个后端都必须实现它。这与 [drop-mutable-session-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 是同一模式:契约测试覆盖了两者,但没有任何发布代码会问「这个会话是否已持久化?」或删除一个会话。 +`has()` 不仅是未使用——它还是共享协调器中最复杂的分支:一个 tracked-vs-untracked 双探测(`loadLive(id, cwd)` 用于活跃追踪的会话,`loadStored(id)` 用于未追踪的会话),附带多行注释说明理由。`delete()` 则拖带了 `deleteStored` 后端钩子,每个后端都必须实现它。这与 [drop-mutable-session-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 是同一模式:契约测试覆盖了两者,但没有任何发布代码会问「这个会话是否已持久化?」或删除一个会话。 ## 决策 没有消费方使用的方法被移除——从抽象 seam、实现,以及仅为覆盖它们而存在的契约/spec 测试套件中移除: -- `SessionPersistence.has()` / `.delete()` 已移除:抽象声明、协调器的 `has`/`delete`/`deleteCore`,以及 `PersistenceBackend.deleteStored` 钩子(jsonl 和 sqlite 各自实现 `deleteStored` 仅仅是为了满足该钩子——那些实现也一并移除)。后端属于[双后端](../../implemented/architecture/2026-06-14-session-persistence.md)设计,本身不在本 RFC 范围内;移除它们为无消费方实现的钩子是移除钩子的一部分,而非后端重设计。 -- 所有文档和源码注释中的引用都已更新为存活的四方法、仅含 `list()` 的契约——不仅是字面的 `has(`/`delete(`/`deleteStored` 拼写,还包括 `{@link has}`/`{@link delete}` JSDoc 链接和「六个公开方法」之类的计数——涉及 seam 和后端 README、[docs/architecture.md](../../../architecture.md)、[session-persistence](../../implemented/architecture/2026-06-14-session-persistence.md) 与 [write-coordinator](../../implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md) RFC,以及协调器/后端的 JSDoc。 +- `SessionPersistence.has()` / `.delete()` 已移除:抽象声明、协调器的 `has`/`delete`/`deleteCore`,以及 `PersistenceBackend.deleteStored` 钩子(jsonl 和 sqlite 各自实现 `deleteStored` 仅为满足该钩子——这些实现也一并移除)。后端属于[双后端](../../implemented/architecture/2026-06-14-session-persistence.md)设计,本身不在本次范围内;移除它们为无消费方实现的钩子是移除钩子的一部分,而非后端重新设计。 +- 所有文档和源码注释中的引用都已更新为存留的四方法、仅含 `list()` 的契约——不仅是字面的 `has(`/`delete(`/`deleteStored` 拼写,还包括 `{@link has}`/`{@link delete}` JSDoc 链接和「六个公开方法」之类的计数——涉及 seam 和后端 README、[docs/architecture.md](../../../architecture.md)、[session-persistence](../../implemented/architecture/2026-06-14-session-persistence.md) 和 [write-coordinator](../../implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md) RFC,以及协调器/后端的 JSDoc。 ## 曾考虑的替代方案 ### 为什么不以「seam 应当完整」为由保留? -「持久化 seam 理应提供 delete」这种直觉是真实的——而它恰恰是预发布阶段所警惕的投机完整性([AGENTS.md](../../../../AGENTS.md):为正确的基础优化,而非为你并不拥有的假想调用方优化)。`delete()` 只是一个方法,等到消费方真正需要时再加回来即可:一个删除旧会话的会话管理 UI 会需要它——到那时再加,针对该 UI 的真实需求设计(软删除?级联?确认?),而非现在猜测。 +「persistence seam 理应提供 delete」这种直觉是真实的——但它恰恰是预发布阶段所警惕的投机性完整([AGENTS.md](../../../../AGENTS.md):为正确的基础优化,而非为你并不拥有的假想调用者优化)。`delete()` 是一个方法,等消费方真正需要时再加回来即可:一个删除旧会话的会话管理 UI 会需要它——到那时再加,基于该 UI 的真实需求来设计(软删除?级联?确认?),而非现在猜测。 -在有活跃消费方时重新加入一个 seam 方法,成本低且设计更优,因为消费方锁定了契约。无人使用地携带它,意味着每个实现(以及未来的每个后端)都必须实现并测试一个什么也不做的方法。 +在有活跃消费方的情况下重新添加一个 seam 方法,成本低且设计更优,因为消费方锚定了契约。在无人使用的情况下保留它,意味着每个实现(以及未来的每个后端)都必须实现和测试一个无实际作用的方法。 ## 验证 -`has`/`delete`/`deleteStored` 已从持久化 seam、实现和契约测试套件中移除,没有新增无用导出;剩余操作(`create`/`append`/`load`/`list`)未受影响,ACP `session/list` 和崩溃恢复行为完全一致;seam README 和 `docs/architecture.md` 只列出存活的方法。 +`has`/`delete`/`deleteStored` 已从 persistence seam、实现和契约测试套件中移除,没有新增无用导出;剩余操作(`create`/`append`/`load`/`list`)未受影响,ACP `session/list` 和崩溃恢复行为完全一致;seam README 和 `docs/architecture.md` 仅列出存留的方法。 ## 后果 -- **`delete()` 是产品最终会需要的那类操作。** 确实如此——但「最终」正是关键。现在删除、等有真实消费方时再加回来,严格优于发布一份猜测的契约。双后端各自去掉了一个 `deleteStored` 实现,这是在本来不在范围内的包中的有限改动。 -- **低耦合。** 移除局限于持久化 seam + 实现 + 测试;没有跨包消费方引用被移除的方法,因此文档之外没有涟漪效应。 +- **`delete()` 是产品最终会需要的操作。** 确实如此,但「最终」正是关键。现在删除、将来基于真实消费方重新添加,严格优于发布一份猜测的契约。两个后端各自减少了一个 `deleteStored` 实现,这是在本次范围之外的包中的有限改动。 +- **低耦合。** 移除局限于 persistence seam + 实现 + 测试;没有跨包消费方引用被移除的方法,因此除文档外没有涟漪效应。 规模不大,但它将 seam 从「实现必须为无人提供什么」恢复为「恰好是消费方使用的东西」。 diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml index dd5dd8e4e1..68ba79e73a 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-public-agent-stop-surface.md: 8c371911616b0a156156355b2ca15d795cfd21e5 -2026-06-20-public-agent-stop-surface.zh.md: 31deaa3649026a7579702e8e47edfdf05d2543ae +2026-06-20-public-agent-stop-surface.zh.md: bbd61fa1738fda64ec5e068dae84062163937c1a diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md index 31deaa3649..bbd61fa173 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md @@ -1,39 +1,39 @@ # RFC:保留单一公开停止原语 -[English](2026-06-20-public-agent-stop-surface.md) | 中文 - Status: implemented +[English](2026-06-20-public-agent-stop-surface.md) | 中文 + > **实现说明:** 仅移除了 `abort()`。`whenIdle()` 予以保留,因为它是公开的静默信号,能安全处理等待者结算与替换轮次竞态;消费方不应从状态转换中自行重建该行为。 ## 问题 -公开的 `Agent` 句柄暴露了两种重叠的方式来停止进行中的工作:`abort(reason?)` 与 `cancel(reason?)`。`abort()` 仅终止当前正在执行的步骤,不影响队列中的工作;`cancel()` 清除队列中的工作与 steering(中途引导),终止正在运行的步骤,并处理步骤前竞态。在生产环境中,ACP(Agent Client Protocol)使用 `cancel()` 实现 `session/cancel`,而生命周期所有者通过 `AgentHandle.dispose()` 拆除 agent。没有生产调用方需要裸 `abort()`。 +公开的 `Agent` 句柄暴露了两种重叠的方式来停止进行中的工作:`abort(reason?)` 和 `cancel(reason?)`。`abort()` 仅终止当前步骤,不影响队列中的工作;`cancel()` 清除队列中的工作和 steering(中途引导)工作、中止正在运行的步骤,并处理步骤前竞态。在生产环境中,ACP(Agent Client Protocol)使用 `cancel()` 实现 `session/cancel`,而生命周期所有者通过 `AgentHandle.dispose()` 销毁 agent(智能体)。没有生产调用方需要裸 `abort()`。 -`abort()` 与 `cancel()` 的区别是真实存在的:`abort()` 保留队列中的提示词和 steering,而 `cancel()` 丢弃它们。但没有已发布的代码调用过公开的 `abort()` 动词。agent loop(智能体循环)自身的停止路径(`cancel()` 与 dispose)直接终止当前 `AbortController`,而非经由 `Agent.abort()` 路由。大多数调用 `abort()` 的测试实际上中断的是空队列,可以改用 `cancel(reason)`;那个刻意依赖队列保留的 steering 重投递测试则直接驱动进行中的 `AbortController`,因为 `cancel()` 会丢弃它试图证明在步骤终止后仍存活的队列 steering。无参 `abort()` 的默认原因(`'aborted'`)随动词一起删除,而非意外保留;`cancel()` 保留自己的默认值 `'cancelled'`。 +`abort()`/`cancel()` 的区别是真实存在的:`abort()` 保留队列中的提示词和 steering,而 `cancel()` 丢弃它们。但没有任何已上线的代码调用过公开的 `abort()` 动词。循环自身的停止路径(`cancel()` 和 disposal)直接中止当前 `AbortController`,而不经由 `Agent.abort()` 路由。大多数调用 `abort()` 的测试中断的是空队列,可以改用 `cancel(reason)`;那个刻意依赖队列保留的 steering 重投递测试则直接驱动进行中的 `AbortController`,因为 `cancel()` 会丢弃它试图证明在步骤中止后仍存活的已排队 steering。无参 `abort()` 的默认原因(`'aborted'`)随该动词一起删除,而非被意外保留;`cancel()` 保留自己的 `'cancelled'` 默认值。 -多余的公开接口面使 agent loop 不得不承载一个本质上是拆除内部机制的公开动词:`abort()` 必须被文档描述为与队列感知的取消不同,尽管 UI 取消几乎总是需要更广义的操作。 +多余的公开接口使得循环不得不承载一个本质上属于内部拆卸的公开动词:`abort()` 必须被文档描述为有别于队列感知的取消,尽管 UI 取消几乎总是需要更广泛的操作。 ## 决策 -`cancel()` 是 `Agent` 上唯一的公开*停止*原语。生命周期所有者使用 `AgentHandle.dispose()` 停止并注销 agent;非所有者使用 `cancel()` 放弃当前与队列中的工作。实现内部保留一个私有 abort controller,但它不属于面向插件的 `Agent` 契约。 +`cancel()` 是 `Agent` 上唯一的公开*停止*原语。生命周期所有者使用 `AgentHandle.dispose()` 停止并注销 agent;非所有者使用 `cancel()` 放弃当前和队列中的工作。实现内部保留一个私有的 abort controller,但它不属于面向插件的 `Agent` 契约。 -`whenIdle()` 作为公开的静默观测原语**予以保留**(agent 脱离 `running` 状态后 resolve;已处于 idle 时立即 resolve;dispose 后等待循环退出)。它不是停止动词;它是非所有者观测停止*完成*而无需 dispose agent 的方式。它的活跃消费方是 ACP 和通过此公开 seam 等待结算的 agent 测试(`packages/ui/acp/tests`、`packages/core/agent-loop/tests`);生产环境的 ACP 桥接层拥有其 agent 并通过 `AgentHandle.dispose()` 拆除它们,因此 `packages/ui/acp/src` 本身没有 `whenIdle()` 调用。 +`whenIdle()` **保留**为公开的静默观测原语(agent 从 `running` 状态稳定后 resolve,已处于 idle 时立即 resolve,dispose 后等待循环退出)。它不是停止动词;它是非所有者在不 dispose agent 的前提下观测停止*完成*的方式。它的活跃消费方是 ACP 和通过此公开 seam 等待结算的 agent 测试(`packages/ui/acp/tests`、`packages/core/agent-loop/tests`);生产环境的 ACP 桥接层拥有其 agent 并通过 `AgentHandle.dispose()` 销毁它们,因此 `packages/ui/acp/src` 本身没有 `whenIdle()` 调用。 -公开的 `abort()` 被删除,连同将其作为独立 API 测试的用例以及将步骤级终止描述为嵌入特性的文档。空队列终止测试迁移到 `cancel(reason)`,仍然验证取消行为;测试对象为 agent loop 内部 `AbortController` 的测试通过包内类型转换直接驱动该 controller 的私有字段;仅固定已移除的无参 `abort()` 默认值的测试随方法一起删除。disposer 仍为异步,仍等待循环停止。 +公开的 `abort()` 被删除,连同将其作为独立 API 测试的用例以及将步骤级中止描述为嵌入特性的文档。空队列中止测试迁移到 `cancel(reason)`,仍然验证取消行为;以循环内部 `AbortController` 为测试对象的用例通过包内类型转换直接驱动该 controller 的私有字段;仅固定已移除的无参 `abort()` 默认值的测试随方法一起删除。disposer 仍为异步,仍等待循环停止。 ## 曾考虑的替代方案 -**同时移除 `whenIdle()`**:最初提案的形态,在对照代码验证前提后被推翻(上方的实现说明记录了完整过程):它是承重的静默原语,强迫消费方手动观测 `running`→`idle` 转换正是防御性模式所警告的脆弱路径。 +**同时移除 `whenIdle()`**:最初提案的形态,在对照代码验证前提后被推翻(上方的实现说明记录了完整过程):它是承重的静默原语,迫使消费方手动观测 `running`→`idle` 转换正是防御性模式所警告的脆弱路径。 ## 验证 -`Agent` 不再暴露公开的 `abort()`,而 `cancel()`、`whenIdle()` 与 `steer()` 保留;ACP 取消调用 `cancel()`;拆除通过 handle disposal 等待静默,`whenIdle()` 为非所有者观测者在静默时 resolve;测试套件覆盖取消与 disposal 作为两条受支持的停止路径。 +`Agent` 不再暴露公开的 `abort()`,而 `cancel()`、`whenIdle()` 和 `steer()` 保留;ACP 取消调用 `cancel()`;拆卸通过 handle disposal 等待静默,`whenIdle()` 在静默时为非所有者观测者 resolve;测试套件覆盖取消和 disposal 作为两条受支持的停止路径。 ## 后果 -未来的插件无法通过公开接口仅终止当前模型/工具步骤而保留队列中的提示词。如果该用例变为现实需求,它应当带着一个具名消费方和更窄的契约重新引入。目前它只是把一个私有循环机制暴露为公开接口的潜在泛化。 +未来的插件无法通过公开接口仅中止当前模型/工具步骤而保留队列中的提示词。如果该用例变为现实需求,它应当带着一个具名消费方和更窄的契约回归。目前它是将私有循环机制保持公开的潜在泛化。 ## 相关 -本 RFC 仅移除冗余的停止动词。中途 steering 仍是有意保留的消息路径;静默观测仍通过 `whenIdle()` 提供。最终的公开接口面为 `send()`、`steer()`、`inject()`、`cancel()`、`whenIdle()`、status、options、session 与 identity。 +本 RFC 仅移除冗余的停止动词。中途 steering 仍是有意保留的消息路径;静默观测仍通过 `whenIdle()` 提供。最终的公开接口为 `send()`、`steer()`、`inject()`、`cancel()`、`whenIdle()`、status、options、session 和 identity。 diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml index 4f09cbbc3b..ec11d8ea9a 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-remove-agent-boundary-mirror-events.md: 46b5e43951885915d4c3dd3f867ced6c31d32035 -2026-06-20-remove-agent-boundary-mirror-events.zh.md: dd6952ec8923c17d703fc6850197bef09b1c0ee7 +2026-06-20-remove-agent-boundary-mirror-events.zh.md: 15be07f43997b1d899f0297d311c3ad83f088ee0 diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md index dd6952ec89..15be07f439 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md @@ -1,32 +1,32 @@ # RFC:停止将持久化边界镜像为 agent 事件 -Status: implemented - [English](2026-06-20-remove-agent-boundary-mirror-events.md) | 中文 +Status: implemented + ## 问题 -agent loop(智能体循环)曾通过可回放的 `SessionEvent` 日志和实时 `agent/*` 镜像两条路径暴露持久化的轮次与步骤边界。消费方不得不在两个表达同一事实的来源之间做选择,并协调二者的时序。ACP(Agent Client Protocol)和持久化层已经使用事件日志;stdio UI 是唯一仍在消费镜像事件的组件,而它也已经从 `session/event` 渲染工具调用和工具结果。 +agent loop(智能体循环)通过可回放的 `SessionEvent` 日志和实时 `agent/*` 镜像两条路径暴露持久化的轮次与步骤边界。消费方不得不在同一事实的两个来源之间做选择,并协调二者的时序。ACP(Agent Client Protocol)和持久化层已经使用日志;stdio UI 是唯一仍在消费镜像的组件,而它已经从 `session/event` 渲染工具调用和工具结果。 -这种重复并非零成本。每次生命周期变更都要同时更新会话事件、镜像事件、文档、不变式、测试和快照预期。重复的边界事件还使失败排序变得微妙:一个轮次可能在实时 `agent/turn-end` 监听器运行之前就已被持久化关闭,因此边界之后的监听器失败在日志中已没有合法的位置可插入,只能带外报告。 +这种重复并非零成本。每次生命周期变更都需要同时更新会话事件、镜像事件、文档、不变式、测试和快照预期。重复的边界事件还使失败排序变得微妙:一个轮次可能在实时 `agent/turn-end` 监听器运行之前就已被持久化关闭,因此边界之后的监听器失败在日志中已没有合法位置可以插入,只能带外上报。 ## 决策 -让 `session/event` 成为唯一的实时边界/transcript(文本记录)流。需要渲染轮次、工具调用、工具结果、助手消息和持久化边界的消费方统一订阅 `session/event`,从持久化层使用的同一套事件词汇派生 UI。 +将 `session/event` 作为唯一的实时边界/transcript(文本记录)流。需要渲染轮次、工具调用、工具结果、助手消息和持久化边界的消费方统一订阅 `session/event`,从持久化层使用的同一套事件词汇中派生 UI。 -移除 `agent/turn-start`、`agent/turn-end`、`agent/step-start` 和 `agent/step-end`。边界消费方改为订阅 `session/event`。需要 agent 标签的 UI 通过 `agent/created` 和 `agent/disposed` 维护一份 session 到 agent 的映射,因为持久化的 `turn/start` 携带轮次编号但不携带 agent id。 +移除 `agent/turn-start`、`agent/turn-end`、`agent/step-start` 和 `agent/step-end`。边界消费方改为订阅 `session/event`。如果 UI 需要 agent 标签,则通过 `agent/created` 和 `agent/disposed` 维护一份 session 到 agent 的映射,因为持久化的 `turn/start` 携带轮次编号但不携带 agent id。 -步骤镜像没有消费方,已由 [event-domain-semantics RFC](../architecture/2026-06-30-event-domain-semantics.md) 率先移除。该决策保留了轮次镜像供 stdio UI 使用;本 RFC 在将测试 REPL 迁移到 `session/event` 加 id 映射之后,将轮次镜像也一并移除。 +步骤镜像已无消费方,由 [event-domain-semantics RFC](../architecture/2026-06-30-event-domain-semantics.md) 先行移除。该决策保留了轮次镜像供 stdio UI 使用;本 RFC 在将测试 REPL 迁移到 `session/event` 加 id 映射之后,将轮次镜像也一并移除。 ## 范围:移除什么、不移除什么 -本决策仅涉及持久化的轮次与步骤边界。`agent/steering` 镜像的是一条控制记录,`agent/stream-chunk` 镜像的是 token 流,因此各自单独处理:见 [steering](2026-07-04-remove-agent-steering-mirror.md) 和 [stream chunks](2026-07-02-remove-stream-chunk-mirror.md)。`agent/created`、`agent/disposed`、`agent/status`、`agent/error` 和 `agent/queued` 仍作为实时生命周期或控制事件保留,而非 transcript 镜像;排队的输入可能在任何持久化事件产生之前就被取消。 +本决策仅涉及持久化的轮次与步骤边界。`agent/steering` 镜像的是一条控制记录,`agent/stream-chunk` 镜像的是 token 流,因此各自单独处理:[steering](2026-07-04-remove-agent-steering-mirror.md) 与 [stream chunks](2026-07-02-remove-stream-chunk-mirror.md)。`agent/created`、`agent/disposed`、`agent/status`、`agent/error` 和 `agent/queued` 仍作为实时生命周期或控制事件保留,而非 transcript 镜像;排队中的输入可能在任何持久化事件产生之前就被取消。 ## 曾考虑的替代方案 -- **在同一个变更中移除 `agent/steering`**:否决,因为它镜像的是控制记录而非边界。 -- **为 stdio UI 保留轮次镜像**:否决,因为 UI 可以渲染 `session/event` 并从 id 映射中恢复 agent 标签。 +- **在同一个变更中一并移除 `agent/steering`**:否决,因为它是控制记录的镜像而非边界镜像。 +- **为 stdio UI 保留轮次镜像**:否决,因为 UI 可以渲染 `session/event` 并通过 id 映射恢复 agent 标签。 ## 后果 -插件不再能从便捷的 `Agent` 优先事件中观察轮次/步骤边界。它必须订阅 `session/event` 或自行维护 session 到 agent 的关联。这是可接受的取舍:边界消费方不应依赖一条可能与持久化日志产生漂移的第二事件源。 +插件不再能从便捷的 `Agent` 优先事件中观察轮次/步骤边界,必须订阅 `session/event` 或自行维护 session 到 agent 的关联。这是可接受的取舍:边界消费方不应依赖一条可能与持久化日志产生漂移的第二事件源。 diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml index f096620016..aecab4f6b5 100644 --- a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-26-fsspec-style-fs-seam.md: 493af9341177aaaed4cdca03a3c20f326c5c4dac -2026-06-26-fsspec-style-fs-seam.zh.md: ba6a366990f749c5fb84e30142965dc5a2d1d0b7 +2026-06-26-fsspec-style-fs-seam.zh.md: 4aa9b260396c22433ea9a4c9af0b4101fa6895e7 diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md index ba6a366990..4aa9b26039 100644 --- a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md @@ -1,21 +1,21 @@ -# RFC:拆分文件系统 seam——提供方文本变更与 `dsh-fs-policy` 插件 - -Status: implemented +# RFC:拆分文件系统 seam——提供方文本变更操作与 `dsh-fs-policy` 插件 [English](2026-06-26-fsspec-style-fs-seam.md) | 中文 +Status: implemented + ## 问题 -[filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) 引入的文件系统能力目前让一个抽象 `FileSystem` 服务同时承担两类职责: +[filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) 中引入的文件系统能力目前让一个抽象的 `FileSystem` 服务承担两类不同的职责: -1. **提供方操作**——解析目标、stat/版本元数据、文本读取/流式读取、原子写入,以及带守卫的字面编辑。 -2. **面向 agent 的策略**——行窗口、字面编辑语义,以及读后写/编辑的 observed-state。 +1. **提供方操作**——解析目标、stat/版本元数据、文本读取/流式读取、原子写入,以及受保护的字面编辑。 +2. **面向 agent(智能体)的策略**——行窗口、字面编辑语义,以及读后写/编辑的观测状态。 -这导致每个未来的后端都要重新实现面向模型的读取语义和观测策略。`readPage` 返回带行号的行和视图元数据;基类服务按 owner 存储文件状态,并区分 `full` 与 `partial` 读取。这些是有用的策略,但它们不是文件系统提供方的原语。字面文本变更则不同:版本守卫、字面匹配、歧义检测与原子重写必须在提供方变更边界内保持一体,但当前的 `applyEdit` 命名及其周围的 seam 把这个提供方操作绑定到了旧的读后编辑策略形状上。 +这导致每个未来的后端都要重新实现面向模型的读取语义和观测策略。`readPage` 返回带行号的行和视图元数据;基础服务按 owner 存储文件状态,并区分 `full` 与 `partial` 读取。这些是有用的策略,但它们不是文件系统提供方的原语。字面文本变更则不同:版本守卫、字面匹配、歧义检测与原子重写必须留在提供方的变更边界内,但当前的 `applyEdit` 命名及其周围的 seam 将这一提供方操作绑定到了旧的读后编辑策略形状上。 -这还造成了一个真实的 UX 死胡同:窗口化读取记录 `view: partial`,而 partial 视图无法授权 `edit`。一个模型读取了大文件的第 100-150 行,除非先获得一次 `full` 读取,否则无法编辑第 120 行——而对于超过读取上限的文件,full 读取可能不可行。字面编辑真正需要的只是新鲜度:被匹配的字节必须仍来自模型所读的那个版本。 +这还造成了一个真实的用户体验死胡同:窗口化读取记录 `view: partial`,而 partial 视图无法授权 `edit`。一个模型读取了大文件的第 100-150 行,如果想编辑第 120 行,就必须先获取一次 `full` 读取,而对于超过读取上限的文件这可能做不到。字面编辑实际上只需要新鲜度:被匹配的字节仍然来自模型所读取的那个版本即可。 -旧 RFC 已经推迟了独立的 `@deepseek-ai/dsh-fs-policy` 包。本 RFC 构建该层,并让 `ctx.fs` 贴近 fsspec 风格的存储原语(`info`/`cat`/`open`),但不将其变成完整的 fsspec。 +旧 RFC 已经推迟了独立的 `@deepseek-ai/dsh-fs-policy` 包(package)。本 RFC 构建该层,并让 `ctx.fs` 贴近 fsspec 风格的存储原语(`info`/`cat`/`open`),但不将其变成完整的 fsspec。 ## 决策 @@ -28,13 +28,13 @@ provider seam dsh-fs ctx.fs: text IO + atomic mutation primitives (op provider dsh-fs-local local implementation of ctx.fs ``` -`dsh-tool-fs` 保持相同的面向模型的 `read`/`write`/`edit` schema。它是执行器:注入 `fs`(不是策略服务)并直接访问 `ctx.fs`,拥有读取窗口化逻辑,并派发 `fs/*` 事件以便 `dsh-fs-policy` 进行门控和记录。 +`dsh-tool-fs` 保持相同的面向模型的 `read`/`write`/`edit` schema。它是执行器:注入 `fs`(不是策略服务)并直接访问 `ctx.fs`,拥有读取窗口化逻辑,并分发 `fs/*` 事件以便 `dsh-fs-policy` 进行门控和记录。 本 RFC 决定了四层拆分、提供方契约和新鲜度策略。工具↔策略的**耦合方式**随后由[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 细化:`dsh-fs-policy` 是一个门控**插件**,通过 `fs/*` 事件参与而非提供 `ctx.fileContext` 方法服务,因此工具不与它产生方法耦合,读取窗口化与 fs I/O 留在 `dsh-tool-fs` 中。本文描述的是最终落地的事件门控形态;提供方的版本守卫是可选的(省略 = 无条件裸提供方)。 ## 提供方契约 -`@deepseek-ai/dsh-fs` 收缩为提供方文本 IO 加带守卫的文本变更: +`@deepseek-ai/dsh-fs` 收缩为提供方文本 IO 加受保护的文本变更: ```ts ignore-check abstract resolve(path: string): Promise<FsTarget> @@ -55,76 +55,76 @@ type FsWriteIntent = | { kind: 'replaceIfVersion'; version: FsVersion } ``` -`stat` 返回元数据而非内容。`version` 是新鲜度令牌;`type` 让执行器在读取前拒绝目录/特殊文件;`size` 让 `read` 工具无需通过失败来探测即可选择 `readText` 还是 `streamText`。返回 `undefined` 表示目标不存在。 +`stat` 返回元数据而非内容。`version` 是新鲜度令牌;`type` 让执行器在读取前拒绝目录/特殊文件;`size` 让 `read` 工具无需通过失败探测即可选择 `readText` 还是 `streamText`。`undefined` 表示目标不存在。 `readText` 读取整个常规文本文件。`streamText` 以相同的文本语义流式读取大文件。两个提供方原语负责常规文件检查、UTF-8 解码、二进制/NUL 拒绝以及 `FS_NOT_TEXT`;策略层从不处理原始字节,也不重新实现跨分片解码。`readText` 是小文件/直接全文件原语,而面向模型的大文件读取使用 `streamText`。 -`writeText` 是原子性的临时文件 + rename,带有显式的写入意图。`createIfAbsent` 创建不存在的目标,对已存在的目标以 `FS_NOT_OBSERVED` 拒绝;这是 owner 没有先前读取时使用的路径。`replaceIfVersion` 仅在目标以观测到的版本存在时替换;目标不存在或版本不匹配时抛出 `FS_STALE_VERSION`。 +`writeText` 是原子的临时文件 + rename,带有显式的写入期望。`createIfAbsent` 创建不存在的目标,对已存在的目标以 `FS_NOT_OBSERVED` 拒绝;这是 owner 没有先前读取时使用的路径。`replaceIfVersion` 仅在目标以观测到的版本存在时替换;目标不存在或版本不匹配时抛出 `FS_STALE_VERSION`。 -`editText` 是提供方级别的带守卫文本变更。启用守卫时,它先验证目标仍以 `expected.version` 存在,然后读取当前文本、应用字面替换并原子写入。陈旧检查必须在字面匹配之前发生,这样基于旧读取的编辑会报告 `FS_STALE_VERSION`,而不是对更新内容做匹配后报告 `FS_EDIT_NOT_FOUND` 或 `FS_AMBIGUOUS_EDIT`。将此原语保留在提供方 seam 上,保持了后端本地锁定能力,也让未来的远程后端可以实现原生的 compare-and-edit 而无需策略层拉取整个文件。 +`editText` 是提供方级别的受保护文本变更。启用守卫时,它首先验证目标仍以 `expected.version` 存在,然后读取当前文本、应用字面替换并原子写入。过期检查必须在字面匹配之前发生,这样基于旧读取的编辑会报告 `FS_STALE_VERSION`,而不是对更新内容进行匹配后报告 `FS_EDIT_NOT_FOUND` 或 `FS_AMBIGUOUS_EDIT`。将此原语保留在提供方 seam 上,保持了后端本地锁定的能力,也让未来的远程后端能够实现原生的 compare-and-edit,而无需策略层拉取整个文件。 -这是一个*文本存储* seam,刻意比字节级 fsspec(`cat`/`open` 返回原始字节)高半层。UTF-8 解码、二进制/NUL 拒绝、带守卫的全文件写入和带守卫的字面文本编辑都在提供方内完成,使策略层从不接触原始字节、不重新实现跨分片解码、也不将陈旧检查与变更临界区分离。面向模型的概念仍然不下沉到提供方:行窗口、带行号的行、渲染的页脚、observed-state 存储都不会泄漏下去。 +这是一个*文本存储* seam,刻意比字节级 fsspec(`cat`/`open` 返回原始字节)高半个层次。UTF-8 解码、二进制/NUL 拒绝、受保护的全文件写入和受保护的字面文本编辑都在提供方内完成,因此策略层从不接触原始字节、不重新实现跨分片解码、也不将过期检查与变更临界区分离。面向模型的概念仍然不下沉到提供方:行窗口、带行号的行、渲染的页脚、观测状态存储都不会泄漏下去。 -从 `dsh-fs` 中删除:`readPage`、`FsExpectation`、`FsView`、`FsStateSource`、`FsReadRequest`、`FsTextLine`、行/窗口常量、`formatReadBody`,以及 observed-state `WeakMap`。`applyEdit` 被更窄的提供方原语 `editText` 取代,后者的契约是版本守卫的字面文本变更,而非策略层的读取授权。`FS_PARTIAL_OBSERVATION` 错误码也从 `FsErrorCode` 分类体系中移除:新鲜度授权没有 partial/full 之分,因此没有任何场景会抛出它。`FsTargetKey` 和 `FsVersion` 按照既有的 [branded-ids RFC](../../implemented/architecture/2026-06-20-branded-ids.md) 成为品牌化的不透明 id。 +从 `dsh-fs` 中删除的内容:`readPage`、`FsExpectation`、`FsView`、`FsStateSource`、`FsReadRequest`、`FsTextLine`、行/窗口常量、`formatReadBody`,以及观测状态 `WeakMap`。`applyEdit` 被更窄的提供方原语 `editText` 取代,后者的契约是版本守卫的字面文本变更,而非策略层的读取授权。`FS_PARTIAL_OBSERVATION` 错误码也从 `FsErrorCode` 分类体系中移除:新鲜度授权没有 partial/full 之分,因此没有什么能触发它。`FsTargetKey` 和 `FsVersion` 按照既有的 [branded-ids RFC](../../implemented/architecture/2026-06-20-branded-ids.md) 成为品牌化的不透明 id。 ## 策略契约 -`@deepseek-ai/dsh-fs-policy` 是一个插件而非服务:它不注册任何 `ctx.*` 键,也不注入任何东西。它拥有写入/编辑新鲜度策略和 observed-state——这些不属于 `FileSystem` 提供方基类(否则沙箱化/远程后端会继承它无需承担的面向模型的观测策略)。它通过执行器派发的 `fs/*` 事件门控来贡献这些策略。(本 RFC 最初提出了一个具体的 `ctx.fileContext` 方法服务,带 `read`/`write`/`edit` 方法;[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 将其细化为此处描述的门控插件,使工具从不与策略产生方法耦合。) +`@deepseek-ai/dsh-fs-policy` 是一个插件,不是服务:它不注册任何 `ctx.*` 键,也不注入任何东西。它拥有写入/编辑新鲜度策略和观测状态,这些不属于 `FileSystem` 提供方基类(否则沙箱/远程后端会继承它无需承载的面向模型的观测策略)。它通过执行器分发的 `fs/*` 事件门控贡献该策略。(本 RFC 最初提出了一个具体的 `ctx.fileContext` 方法服务,带有 `read`/`write`/`edit` 方法;[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 将其改造为此处描述的门控插件,使工具从不与策略产生方法耦合。) -Observed state 以 `WeakMap<owner, Map<targetKey, FsVersion>>` 形式存在于此。当且仅当 owner 读取、写入或编辑过该目标时条目才存在(每次成功都会发出 `fs/observed`),因此条目的存在*本身就是*先前观测记录——没有单独的 `hasRead` 标志。owner 从不透明的事件 actor(`{ agent?: { session? } }`)结构化派生,该形状定义在 `dsh-fs-policy` 中而非 `dsh-fs` 中。 +观测状态以 `WeakMap<owner, Map<targetKey, FsVersion>>` 的形式存放于此。当且仅当 owner 读取、写入或编辑过该目标时,条目才存在(每次成功都会发出 `fs/observed`),因此条目的存在*本身就是*先前观测的记录——没有单独的 `hasRead` 标志。owner 从不透明的事件 actor(`{ agent?: { session? } }`)结构化派生,该形状定义在 `dsh-fs-policy` 中而非 `dsh-fs` 中。 该插件决定三个 `fs/*` 事件: - `fs/write-intent`——无先前观测 ⇒ `{ kind: 'createIfAbsent' }`(只有新文件可以盲创建);有先前观测 ⇒ `{ kind: 'replaceIfVersion', version: vObserved }`(已有文件仅在自观测以来未变时才替换)。单槽决策;不调用 `next()`。 -- `fs/edit-intent`——要求 owner 有先前观测(否则 `FS_NOT_OBSERVED`);返回 `{ version: vObserved }` 作为 CAS 基础。它不实现字面替换——它授权并提供版本,提供方的变更临界区负责应用守卫,因此基于同一观测版本的并发编辑仍然是一个赢/一个陈旧。 -- `fs/observed`——在成功的读取/写入/编辑后为该 owner+target 记录 `{ version }`。同步、仅副作用的 `WeakMap.set`。 +- `fs/edit-intent`——要求 owner 有先前观测(否则 `FS_NOT_OBSERVED`);返回 `{ version: vObserved }` 作为 CAS 基础。它不实现字面替换——它授权并提供版本,提供方的变更临界区负责应用守卫,因此基于同一观测版本的并发编辑仍然是一赢一过期。 +- `fs/observed`——在成功的读取/写入/编辑后,为该 owner+target 记录 `{ version }`。同步、仅副作用的 `WeakMap.set`。 -该插件不做任何文件系统 I/O:「你是否观测过这个文件?」是一次 `WeakMap` 查找,而「你读到的版本是否仍然是当前版本?」在 `ctx.fs.editText`/`writeText` 内部的同一原子锁中决定(该锁同时执行变更)——插件只提供 `vObserved` 作为基础。 +该插件不做任何文件系统 I/O:「你是否观测过此文件?」是一次 `WeakMap` 查找,而「你读取的版本是否仍然是当前版本?」在 `ctx.fs.editText`/`writeText` 内部、与执行变更相同的原子锁中决定——插件只提供 `vObserved` 作为基础。 ## 工具契约 -`dsh-tool-fs` 保持相同的 schema 和提示词表面。`read` 仍暴露 `file_path`、`offset` 和 `limit`;`write` 和 `edit` 不变。它是执行器:验证模型参数,通过 `ctx.fs` 直接读取/写入/编辑,拥有行窗口化和结果渲染(`N: text`、页脚、`<path>/<content>` 信封),并派发 `fs/*` 事件。 +`dsh-tool-fs` 保持相同的 schema 和提示词表面。`read` 仍然暴露 `file_path`、`offset` 和 `limit`;`write` 和 `edit` 不变。它是执行器:验证模型参数,通过 `ctx.fs` 直接读取/写入/编辑,拥有行窗口化和结果渲染(`N: text`、页脚、`<path>/<content>` 信封),并分发 `fs/*` 事件。 -每次变更先派发其 intent waterfall(瀑布式事件)并以 `undefined` 作为裸提供方默认值,然后调用 `ctx.fs`,再发出 `fs/observed`:例如 `write` 执行 `ctx.waterfall('fs/write-intent', target, exec, () => undefined)` → `ctx.fs.writeText(target, content, intent)` → `ctx.emit('fs/observed', …)`。`read` 做一次 stat、读取/流式读取、构建窗口,然后发出 `fs/observed`。将 `exec` 作为 actor 传入,让 `dsh-fs-policy` 无需工具深入策略即可派生 owner。 +每个变更操作先分发其 intent waterfall(瀑布式事件),带有 `undefined` 裸提供方默认值,然后调用 `ctx.fs`,再发出 `fs/observed`。例如 `write` 执行 `ctx.waterfall('fs/write-intent', target, exec, () => undefined)` → `ctx.fs.writeText(target, content, intent)` → `ctx.emit('fs/observed', …)`。`read` 先 stat 一次,然后读取/流式读取,构建窗口,最后发出 `fs/observed`。将 `exec` 作为 actor 传递,让 `dsh-fs-policy` 无需工具深入策略即可派生 owner。 -由于策略通过带 `undefined` 默认值的事件贡献,`dsh-tool-fs` 不与 `dsh-fs-policy` 产生方法耦合:插件不存在时,每个 intent waterfall 落入 `undefined`(无条件裸提供方写入/编辑),`fs/observed` 无监听者。加载插件后即叠加读后写/编辑策略。 +由于策略通过带有 `undefined` 默认值的事件贡献,`dsh-tool-fs` 不与 `dsh-fs-policy` 产生方法耦合:在插件缺席时,每个 intent waterfall 都落到 `undefined`(无条件裸提供方写入/编辑),`fs/observed` 没有监听器。加载插件后即可叠加读后写/编辑策略。 ## 并发边界 -进程内更新是安全的:本地后端保持既有的按目标变更锁,因此版本检查-然后-rename 是串行化的,失败的更新看到 `FS_STALE_VERSION`。 +进程内更新是安全的:本地后端保持既有的按目标变更锁,因此版本检查-然后-rename 是串行化的,失败的更新会看到 `FS_STALE_VERSION`。 -进程内创建由同一按目标变更锁守卫:两个调用者以 `createIfAbsent` 竞争时串行化,一个创建成功,下一个看到目标已存在并收到 `FS_NOT_OBSERVED`。跨进程创建仅尽力而为;本地的 stat-then-rename 守卫无法在所有未来后端上提供可移植的排他创建保证。 +进程内创建由同一个按目标变更锁保护:两个调用者以 `createIfAbsent` 竞争时串行化,一个创建成功,另一个看到目标已存在并收到 `FS_NOT_OBSERVED`。跨进程创建仅为尽力而为;本地的 stat-then-rename 守卫无法在所有未来后端上提供可移植的排他创建保证。 -跨进程写入是尽力新鲜度加原子替换:`mtime:size` 通常能捕获编辑器保存,但同一时刻相同大小的写入可能遗漏;原子性的 temp+rename 防止文件撕裂但不能防止所有丢失更新。 +跨进程写入是尽力而为的新鲜度加原子替换:`mtime:size` 通常能捕获编辑器保存,但同一 tick 相同大小的写入可能遗漏;原子的 temp+rename 防止文件撕裂但不能防止所有丢失更新。 ## 取代 -本 RFC 逆转了 [filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) 的两项决策,并收窄了第三项: +本 RFC 逆转了 [filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) 中的两项决策,并收窄了第三项: -- 读后写/编辑策略从 `ctx.fs` 移出,进入 `dsh-fs-policy` 插件(在 `fs/*` 事件门控上)。 +- 读后写/编辑策略从 `ctx.fs` 移出,进入 `dsh-fs-policy` 插件(通过 `fs/*` 事件门控)。 - 文本读取不再返回后端编号的行记录或 `full`/`partial` 视图;授权基于版本新鲜度,因此窗口化读取在文件未变时即可授权编辑。 -- 字面编辑不再位于旧的 `applyEdit` API 之后(该 API 混合了后端变更与 seam 拥有的观测策略)。它作为 `editText` 保留为提供方原语,因为版本守卫 + 字面匹配 + 原子重写必须在提供方的变更临界区内保持一体,以确保正确的错误归因和并发行为。 +- 字面编辑不再位于旧的 `applyEdit` API 之后(该 API 混合了后端变更与 seam 拥有的观测策略)。它作为 `editText` 保留为提供方原语,因为版本守卫 + 字面匹配 + 原子重写必须留在提供方的变更临界区内。 保留的内容:接口/实现/消费方纪律、消费方不导入后端规则、后端定义的 target/version/display 元数据、原子本地写入,以及共享的 `FsError` 分类体系。 ## 验证 -`dsh-fs` 精确暴露 `resolve`/`stat`/`readText`/`streamText`/`writeText`/`editText`(`stat` 返回 `FsInfo | undefined`,`writeText` 接受 `FsWriteIntent`),已删除的类型/原语不再存在;`dsh-fs-local` 不携带行、视图或 `formatReadBody` 逻辑;面向模型的 schema 逐字节未变。测试固定了以下行为:窗口化读取可以授权对未变文件的后续编辑;基于陈旧读取的编辑在尝试字面匹配之前报告 `FS_STALE_VERSION`;版本 CAS 行为得到保持;观测契约成立(通过 `read` 工具的读取记录 observed-state;直接的 `ctx.fs` 读取不记录);`dsh-fs-policy` 具有 HMR/dispose 覆盖率。 +`dsh-fs` 精确暴露 `resolve`/`stat`/`readText`/`streamText`/`writeText`/`editText`(`stat` 返回 `FsInfo | undefined`,`writeText` 接受 `FsWriteIntent`),已删除的类型/原语不再存在;`dsh-fs-local` 不包含行、视图或 `formatReadBody` 逻辑;面向模型的 schema 保持逐字节不变。测试固定了以下行为:窗口化读取授权对未变文件的后续编辑;基于过期读取的编辑在尝试字面匹配之前报告 `FS_STALE_VERSION`;版本 CAS 行为得以保留;观测契约成立(`read` 工具的读取记录观测状态;直接 `ctx.fs` 读取不记录);`dsh-fs-policy` 具有 HMR(热模块替换)/dispose(资源释放)覆盖率。 ## 后续扩展 -该 seam 后来由 [Add direct directory listing to the filesystem seam](../architecture/2026-07-03-filesystem-directory-listing-seam.md) 扩展了直接目录列表功能。该后续工作单独跟踪,以使本 RFC 的验收标准继续描述最初交付的 fsspec 风格改造。 +该 seam 后来由 [Add direct directory listing to the filesystem seam](../architecture/2026-07-03-filesystem-directory-listing-seam.md) 扩展了直接目录列表功能。该后续工作单独跟踪,以使本 RFC 的验收标准继续描述最初交付的 fsspec 风格重构。 ## 曾考虑的替代方案 -- **字节级 fsspec(`cat`/`open` 返回原始字节)**——否决:该 seam 刻意定位为文本存储,比字节级高半层,使 UTF-8 解码、二进制/NUL 拒绝和带守卫的文本变更在提供方内只实现一次,策略层从不接触原始字节,也不将陈旧检查与变更临界区分离。 -- **具体的 `ctx.fileContext` 方法服务**——本 RFC 最初的策略形态;由[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 改造为门控插件,使工具从不与策略产生方法耦合。 -- **将 `readPage` 和 `full`/`partial` 视图授权保留在提供方上**——改造前的形态,即「取代」一节所逆转的内容:视图完整性不是编辑安全所需的信号,版本新鲜度才是;视图规则使超过读取上限的大文件无法编辑。 +- **字节级 fsspec(`cat`/`open` 返回原始字节)**:否决。该 seam 刻意定位为文本存储,比字节级高半个层次,这样 UTF-8 解码、二进制/NUL 拒绝和受保护的文本变更只在提供方实现一次,策略层从不接触原始字节,也不将过期检查与变更临界区分离。 +- **具体的 `ctx.fileContext` 方法服务**:本 RFC 最初的策略形态;被[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 改造为门控插件,使工具从不与策略产生方法耦合。 +- **在提供方保留 `readPage` 和 `full`/`partial` 视图授权**:「取代」一节所逆转的重构前形态。视图完整性不是编辑安全所需的,版本新鲜度才是;而视图规则使超过读取上限的大文件无法编辑。 ## 后果 - 新增第四个 fs 包和一个新的插件层。这是有意为之:它是此前推迟的策略层,而非第二个抽象后端 seam。 -- 直接使用 `ctx.fs` 会绕过策略:直接的 `ctx.fs.readText` 不发出 `fs/observed`,因此在默认策略下,后续的 `edit` 会以 `FS_NOT_OBSERVED` 拒绝,直到通过 `read` 工具读取该文件。该失败是显式且有文档记录的。 -- 大文件行窗口化从后端移至 `dsh-tool-fs` 中的 `read` 工具;文本解码和二进制拒绝留在 `ctx.fs.streamText` 中,因此这只是窗口化逻辑的迁移,不是第二套文本 IO 实现。 -- 将 `editText` 保留在提供方 seam 上意味着每个后端都必须实现字面替换契约。这是有意为之:该操作不是纯存储,但陈旧守卫 + 字面匹配 + 原子重写是必须保持一体的单元,以确保正确的错误归因和并发行为。该契约应保持窄且仅限文本,以便未来后端可以原生实现或通过全文件重写实现。 -- 新鲜度允许在窗口化读取后执行全文件 `write`。这比旧的视图检查更弱,但避免了大文件无法编辑的问题;提示词引导仍然不鼓励盲目的全文件替换。 +- 直接使用 `ctx.fs` 会绕过策略:直接 `ctx.fs.readText` 不发出 `fs/observed`,因此在默认策略下,后续 `edit` 会以 `FS_NOT_OBSERVED` 拒绝,直到通过 `read` 工具读取该文件。这一失败是显式且有文档记录的。 +- 大文件行窗口化从后端移至 `dsh-tool-fs` 中的 `read` 工具;文本解码和二进制拒绝留在 `ctx.fs.streamText` 中,因此这只是窗口化逻辑的迁移,而非第二套文本 IO 实现。 +- 将 `editText` 保留在提供方 seam 上意味着每个后端都必须实现字面替换契约。这是有意为之:该操作不是纯存储,但过期守卫 + 字面匹配 + 原子重写是必须保持在一起的单元,以确保正确的错误归因和并发行为。该契约应保持窄且仅限文本,以便未来后端可以原生实现或通过全文件重写实现。 +- 新鲜度允许在窗口化读取后进行全文件 `write`。这比旧的视图检查更弱,但避免了大文件无法编辑的问题;提示词引导仍然不鼓励盲目的全文件替换。 diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml index ca87af6f9a..a9b8b58f67 100644 --- a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-02-remove-stream-chunk-mirror.md: 1ec633b09c8e53ae7145a49061aced191a9aa765 -2026-07-02-remove-stream-chunk-mirror.zh.md: 83674658d24621b12a866262bb58dde166bedf2d +2026-07-02-remove-stream-chunk-mirror.zh.md: 7cf8a5d056c1bb4193263c58a8e4258173fe8b4e diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md index 83674658d2..7cf8a5d056 100644 --- a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md @@ -1,12 +1,12 @@ # RFC:停止将 token 流镜像为 agent 事件 -Status: implemented - [English](2026-07-02-remove-stream-chunk-mirror.md) | 中文 +Status: implemented + ## 问题 -agent loop(智能体循环)将模型的每个 token 增量同时记录为持久的 `assistant/chunk` 会话事件,并发射一个携带相同数据的并行实时 `agent/stream-chunk` Cordis 事件。在 `packages/core/agent-loop/src/loop.ts` 中,两者仅相隔一行: +agent loop(智能体循环)将模型的每个 token delta 同时记录为持久的 `assistant/chunk` 会话事件,并发射一个携带相同数据的并行实时 `agent/stream-chunk` Cordis 事件。在 `packages/core/agent-loop/src/loop.ts` 中,二者仅相隔一行: ```ts ignore-check const chunkEvent = session.append('assistant/chunk', { turn, step, chunk }) @@ -17,17 +17,17 @@ ctx.emit('agent/stream-chunk', agent, turn, step, chunk) // ← the mirror - 持久事件:`assistant/chunk: { turn, step, chunk }`。 - 实时发射:`agent/stream-chunk(agent, turn, step, chunk)`——相同的 `StreamChunk`,相同的 `turn`/`step`。 -实时发射相比会话事件唯一多出的东西是实时的 `Agent` 句柄,而唯一的消费方丢弃了它(其处理函数签名为 `(_agent, _turn, _step, chunk)`)。 +实时发射相比会话事件唯一多出的东西是实时的 `Agent` 句柄,而唯一的消费方直接丢弃了它(其处理函数签名为 `(_agent, _turn, _step, chunk)`)。 -这与[边界镜像移除](2026-06-20-remove-agent-boundary-mirror-events.md)为轮次/步骤边界消除的重复如出一辙:消费方对同一个持久事实有两个真源,每次修改都必须同时触及两处。那份 RFC 将分片流推迟处理(「`assistant/chunk` 的持久化仍然是承重的,因此分片流后续可以作为镜像来评估,但那是一个独立的决策」),而非一并打包。本 RFC 就是那个独立的决策。 +这与[边界镜像移除](2026-06-20-remove-agent-boundary-mirror-events.md)为 turn/step 边界消除的重复如出一辙:消费方对同一个持久事实有两个真源,每次变更都要同时修改两处。那份 RFC 将 chunk 流推迟处理(「`assistant/chunk` 的持久化仍然是承重的,因此 chunk 流后续可以作为镜像来评估,但那是一个独立决策」),而非一并纳入。本 RFC 即是那个独立决策。 -推迟所依赖的前提已经尘埃落定:分片持久化是权威的,且将保留。停止持久化分片、仅保留瞬态实时流事件的提案已被[否决](../../rejected/simplification/2026-06-20-assembled-assistant-messages-only.md)——高保真回放、部分失败的流以及快照回放都依赖持久化的 `assistant/chunk` 流。因此 `session/event` 上的 `assistant/chunk` 是持久的、承重的 token 流,而 `agent/stream-chunk` 是它的纯冗余镜像。 +推迟所依赖的前提已经明确:chunk 持久化是权威的,且将保留。停止持久化 chunk、仅保留瞬态实时流事件的提案已被[否决](../../rejected/simplification/2026-06-20-assembled-assistant-messages-only.md)——高保真回放、部分失败的流以及快照回放都依赖持久化的 `assistant/chunk` 序列。因此 `session/event` 上的 `assistant/chunk` 是持久的、承重的 token 流,而 `agent/stream-chunk` 是它的纯冗余镜像。 ## 决策 -从 agent 事件分类体系中移除 `agent/stream-chunk`。token 流通过 `session/event` 以 `assistant/chunk` 的形式读取——持久化和回放已经使用的正是同一条流。`session/event` 是唯一的实时 transcript(文本记录)流(assistant 分片、轮次/步骤边界、工具活动、todo)。 +从 agent 事件分类体系中移除 `agent/stream-chunk`。token 流通过 `session/event` 以 `assistant/chunk` 的形式读取——持久化与回放已经使用的正是同一个序列。`session/event` 是唯一的实时 transcript(文本记录)流(assistant chunk、turn/step 边界、工具活动、todo)。 -**消费方。** 唯一重要的生产消费方——ACP 桥接层(`dsh-acp`,真正面向编辑器的流式输出接口)——已经从 `session/event` 渲染 `assistant/chunk`,从未使用 `agent/stream-chunk`,因此不受影响。stdio UI(`dsh-ui-stdio`,一个一次性的测试 REPL)是唯一的实时消费方;它在边界迁移时已经有了 `session/event` 监听器,因此其分片渲染被折叠进该监听器的 `assistant/chunk` 分支。合并为一个监听器还消除了一个潜在隐患:`inReasoning` dim-SGR 标志此前在两个独立的监听器(`agent/stream-chunk` 和 `session/event`)之间共享,分片与边界在该标志上竞争时没有确定的顺序;单一监听器按追加顺序处理,使交错变为确定性的。 +**消费方。** 唯一重要的生产消费方——ACP 桥接(`dsh-acp`,面向编辑器的真实流式输出接口)——已经从 `session/event` 渲染 `assistant/chunk`,从未使用 `agent/stream-chunk`,因此不受影响。stdio UI(`dsh-ui-stdio`,一个一次性的测试 REPL)是唯一的实时消费方;它在边界迁移时已经有了 `session/event` 监听器,因此其 chunk 渲染被折叠进该监听器作为 `assistant/chunk` 分支。合并为一个监听器还消除了一个潜在隐患:`inReasoning` dim-SGR 标志此前在两个独立监听器(`agent/stream-chunk` 和 `session/event`)之间共享,chunk 与边界在该标志上竞争时没有确定的顺序;单一监听器按追加顺序处理,使交错变为确定性的。 ## 范围 @@ -35,13 +35,13 @@ ctx.emit('agent/stream-chunk', agent, turn, step, chunk) // ← the mirror 未触及: - `assistant/chunk`(持久会话事件)——权威的 token 流,原样保留。本 RFC 移除的是实时镜像,而非持久化(持久化移除提案已被单独否决,见上文)。 -- `agent/steering`——本决策未触及(它是控制信号,不是 token 流)。其持久孪生事件是 `steering/message`,镜像发射由其自己的后续 RFC 移除:[移除 `agent/steering` 镜像发射](2026-07-04-remove-agent-steering-mirror.md)。 +- `agent/steering`——本决策未触及(它是控制信号,不是 token 流)。其持久孪生事件是 `steering/message`,镜像发射由其自身的后续 RFC 移除:[移除 `agent/steering` 镜像发射](2026-07-04-remove-agent-steering-mirror.md)。 - `agent/status`、`agent/error`、`agent/created`/`agent/disposed`、`agent/queued`、`agent/session-start`——生命周期/控制事件,不是 transcript 数据,也没有持久副本。 ## 曾考虑的替代方案 -**移除持久化、仅保留瞬态实时流**——反向裁剪,已被[单独否决](../../rejected/simplification/2026-06-20-assembled-assistant-messages-only.md):高保真回放、部分失败的流以及快照回放都依赖持久化的 `assistant/chunk` 流。这一点既已确定,实时发射就是配对中冗余的那一半。 +**移除持久化、仅保留瞬态实时流**——反向裁剪,已被[单独否决](../../rejected/simplification/2026-06-20-assembled-assistant-messages-only.md):高保真回放、部分失败的流以及快照回放都依赖持久化的 `assistant/chunk` 序列。在此前提确定后,实时发射才是配对中冗余的那一半。 ## 后果 -插件不再能从以 `Agent` 为首参的事件观察 token 增量。它应订阅 `session/event` 并过滤 `assistant/chunk`(如需 `Agent` 句柄,可从 `agent/created`/`agent/disposed` 构建的 session-id→agent 映射中恢复,与边界消费方的做法完全一致)。没有任何生产消费方在分片时需要实时的 `Agent`;这与边界镜像移除所做的权衡完全相同,是可接受的。 +插件不再能通过以 `Agent` 为首参的事件观察 token delta。它需要订阅 `session/event` 并过滤 `assistant/chunk`(如需 `Agent` 句柄,可通过 `agent/created`/`agent/disposed` 构建的 session-id→agent 映射恢复,与边界消费方已有的做法完全一致)。没有任何生产消费方在 chunk 时需要实时的 `Agent`;这与边界镜像移除所做的权衡相同,是可接受的。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml index 776f41a858..9b195da18b 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-drop-image-content-block.md: 8222880b61c225c39a1e132353c5f343fb90cb4b -2026-07-04-drop-image-content-block.zh.md: d1379d69a0c5056cdfcc744182cd9b6c52f222d5 +2026-07-04-drop-image-content-block.zh.md: cb9372e50863193cd579c0bf8de991810db95206 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md index d1379d69a0..cb9372e508 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md @@ -1,29 +1,29 @@ # RFC:移除 `image` 内容块,直到有路径能真正处理它 -Status: implemented - [English](2026-07-04-drop-image-content-block.md) | 中文 +Status: implemented + ## 问题 -`ImageBlock`(`packages/llm/llm/src/types.ts`)没有任何生产环境的生产者,而每条路径上的每个消费方都将其**丢弃**:DeepSeek 适配器的序列化器跳过 image 块(这是文档中注明的 MVP 限制);pi-ai 转换器因无法表示而跳过;ACP 编解码器既不声明 image prompt 能力、也不向外转发 image 块,并且对入站的 image prompt 内容直接**拒绝**;压缩(compaction)估算器对其收取一个固定 token 常量并渲染为 `[image]`。此时构造的 `ImageBlock` 会在协议格式(wire format)上静默消失——词汇表声明了一种没有任何路径兑现的能力,这正是 `AGENTS.md` 防御性模式所警告的静默数据丢失形态。唯一的构造点是用于固定 skip/drop/estimate 分支的测试。 +`ImageBlock`(`packages/llm/llm/src/types.ts`)没有任何生产环境的生产者,而每条路径上的每个消费方都将其**丢弃**:deepseek 适配器的序列化器跳过 image 块(这是文档中注明的 MVP 限制);pi-ai 转换器因无法表示而跳过;ACP 编解码器既不宣告 image prompt 能力、也不向外转发 image 块,并且会拒绝入站的 image prompt 内容;压缩(compaction)估算器对其收取一个固定 token 常量并渲染为 `[image]`。此时构造的 `ImageBlock` 会在协议格式(wire format)上静默消失——词汇宣告了一种没有任何路径兑现的能力,这正是 AGENTS.md 防御性模式所警告的静默数据丢失形态。唯一的构造调用出现在测试中,用于覆盖 skip/drop/estimate 分支。 ## 决策 -移除 `ImageBlock`、其 map 条目,以及适配器、ACP 渲染和压缩中的 image 专用分支。在同一个变更中更新所属词汇文档与生成的引用。未知的扩展块仍然覆盖 default 分支,ACP 继续独立于 harness 词汇拒绝入站 image prompt 内容。 +移除 `ImageBlock`、其 map 条目,以及适配器、ACP 渲染和压缩中的 image 专用分支。在同一个变更中更新所属的词汇文档与生成的引用。未知扩展块仍然覆盖默认分支,ACP 继续独立于 harness 词汇拒绝入站的 image prompt 内容。 ## 曾考虑的替代方案 ### 为什么不保留? -当适配器、ACP 与压缩全部支持 image 时,`ContentBlockMap` 可以重新引入它。保留一个唯一实现是拒绝的核心类型,等于向外声明一个不可用的接口;移除则让生产者在编译期立即失败。 +当适配器、ACP 和压缩全部支持 image 时,`ContentBlockMap` 可以重新引入。保留一个唯一实现就是拒绝的核心类型,等于宣告一个不可用的对外服务接口;移除后,生产者会立即得到编译期错误。 -记录在案的回退方案(假设评审决定保留该槽位):保留 `ImageBlock`,但将每处静默跳过替换为显式拒绝,并在词汇文档中记录该策略——静默丢弃是唯一没有辩护者的状态。评审最终决定移除;此回退方案作为文档化的替代方案保留,以备该槽位在完整功能之前回归。 +评审中记录的回退方案(假如评审决定保留该槽位):保留 `ImageBlock`,但将所有静默跳过替换为显式拒绝,并在词汇文档中记录该策略——静默丢弃是唯一没有辩护者的状态。评审最终决定移除;此回退方案作为文档化的替代方案保留,以备该槽位在完整功能就绪之前回归。 ## 验证 -RFC 记录之外没有任何地方构造 harness `ImageBlock`。ACP 独立的入站 image 拒绝仍有测试覆盖,而适配器、编解码器与压缩的 default 分支则通过插件定义的块类型覆盖。 +RFC 记录之外没有任何地方构造 harness 的 `ImageBlock`。ACP 独立的入站 image 拒绝仍有测试覆盖,适配器、编解码器和压缩的默认分支则通过插件定义的块类型来覆盖。 ## 后果 -日后重新添加核心词汇类型会同时涉及多个包——但这种协调变更正是真正的多模态功能所需的形态(适配器映射、ACP 能力声明、压缩定价),而当前并没有什么需要保留的实现。 +日后重新添加核心词汇类型需要同时改动多个包(package)——但这种协调变更本就是真正的多模态功能所需的形态(适配器映射、ACP 能力宣告、压缩定价),而当前并不存在需要保留的实现。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml index 028162c527..3dabffc3a4 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-drop-inert-request-knobs.md: d5484aa5ec64f89ce705ddd0a434c2c4dfbad460 -2026-07-04-drop-inert-request-knobs.zh.md: 877b073c4693f0c87b5f25003a1d043743b658fa +2026-07-04-drop-inert-request-knobs.zh.md: 9bd13cd024bc0e2ba7795a190d77063c3457fe98 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md index 877b073c46..9bd13cd024 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md @@ -1,4 +1,4 @@ -# RFC:移除 `GenerateOptions.prefill` 与 `ToolSchema.strict`——无可用端到端路径的请求旋钮 +# RFC:移除 `GenerateOptions.prefill` 与 `ToolSchema.strict`——无端到端可用路径的请求旋钮 [English](2026-07-04-drop-inert-request-knobs.md) | 中文 @@ -6,30 +6,30 @@ Status: implemented ## 问题 -两个请求契约旋钮贯穿了整条请求流水线,但都无法产生任何效果: +两个请求契约旋钮贯穿了整条请求流水线,却都无法产生任何效果: -- **`prefill`**(`packages/llm/llm/src/types.ts`)没有生产环境的赋值方:agent loop(智能体循环)组装的只有 `model`/`system`/`tools`/`messages` 加 `sessionId`/`signal`,上下文压缩(context compaction)后端只追加 `maxTokens`;而且**两个**适配器都拒绝它:`packages/llm/llm-deepseek/src/serialize.ts` 和 `packages/llm/llm-pi-ai/src/adapter.ts` 各自在 `prefill` 非 undefined 时抛出 `LlmError('UNSUPPORTED')`。该字段全部可观测行为就是两个 throw,各由一个适配器测试固定。DeepSeek 的 chat-prefix completion 是一个 Beta 功能,使用的 base URL 两个适配器都未指向。 -- **`strict`**(`ToolSchema`,同一文件)贯穿了 `DefineToolOptions`/`defineTool`(`packages/core/tools/src/schema.ts`)、注册表的 `schemas()` 白名单(`packages/core/tools/src/index.ts`)、deepseek 协议格式(wire format)映射(`packages/llm/llm-deepseek/src/serialize.ts`,其 wire-type 注释记录了 strict 模式需要适配器未使用的 `/beta` base URL)、`packages/llm/llm-pi-ai/src/adapter.ts` 中的逐工具 payload 修补,以及 tool-catalog 渲染器(`scripts/gen-tool-catalog.ts`)中的条件 `Strict:` 行。没有任何已发布的工具设置过它:在所有 `tool-*` 包 src 和 `examples/` 中 `rg` 搜索,`strict:` 的生产方为零;唯一的赋值方是 dsh-tools 单元测试。 +- **`prefill`**(`packages/llm/llm/src/types.ts`)没有生产级的 setter:agent loop(智能体循环)组装的是 `model`/`system`/`tools`/`messages` 加 `sessionId`/`signal`,上下文压缩(context compaction)后端只追加 `maxTokens`;而且**两个**适配器都拒绝它:`packages/llm/llm-deepseek/src/serialize.ts` 和 `packages/llm/llm-pi-ai/src/adapter.ts` 各自在 `prefill` 非 undefined 时抛出 `LlmError('UNSUPPORTED')`。该字段的全部可观测行为就是两个 throw,各由一条适配器测试固定。DeepSeek 的 chat-prefix completion 是一个 Beta 功能,运行在两个适配器都未指向的 base URL 上。 +- **`strict`**(`ToolSchema`,同一文件)穿过了 `DefineToolOptions`/`defineTool`(`packages/core/tools/src/schema.ts`)、注册表的 `schemas()` 允许列表(`packages/core/tools/src/index.ts`)、deepseek 协议格式(wire format)映射(`packages/llm/llm-deepseek/src/serialize.ts`,其 wire-type 注释记录了 strict 模式需要适配器未使用的 `/beta` base URL)、`packages/llm/llm-pi-ai/src/adapter.ts` 中的逐工具 payload 修补逻辑,以及 tool-catalog 渲染器(`scripts/gen-tool-catalog.ts`)中的条件 `Strict:` 行。没有任何已发布的工具设置过它——在所有 `tool-*` 包的 src 和 `examples/` 中执行 `rg` 搜索,`strict:` 的生产者为零;唯一的 setter 出现在 dsh-tools 单元测试中。 -两个旋钮在适配器间是对称的,因此移除时两个孪生适配器一并清理——[孪生适配器设计](../architecture/2026-06-13-twin-llm-adapters.md)不受影响。 +两个旋钮在适配器间是对称的,因此移除操作将它们从两个孪生适配器中一并剥离——[孪生适配器设计](../architecture/2026-06-13-twin-llm-adapters.md)不受影响。 ## 决策 -- 从 `GenerateOptions` 中移除 `prefill`,同时移除两个适配器的 UNSUPPORTED 守卫、固定这些 throw 的测试、[core.md](../../../core-data-structures/core.md) 中的粘贴行,以及适配器 README 中记录拒绝行为的行。实操手册(Cookbook)中的 UNSUPPORTED 指导([adding-an-llm-adapter.md](../../../cookbook/adding-an-llm-adapter.md))改为泛化表述——你的提供方无法兑现的 `GenerateOptions` 字段应抛出 `LlmError(..., 'UNSUPPORTED')`——而不再以 prefill 为例。[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的后果部分将 prefill 记录为「受生产方门控」而非「已有归属」,遵照 [implemented/AGENTS.md](../AGENTS.md)。 -- 从 `ToolSchema`、`DefineToolOptions`、`defineTool`、`schemas()` 白名单、deepseek 序列化器分支及其 wire-type 字段、以及 tool-catalog 渲染器的 `Strict:` 行中移除 `strict`。pi-ai 的 payload 修补简化为无条件擦除 pi-ai 自身的逐工具 strict 默认值(pi-ai 在每个序列化工具上打 `strict: false`;手写的孪生适配器不发送此字段,因此擦除逻辑为保持协议格式对等而保留,由其序列化器测试固定)。赋值测试和 core.md 粘贴行已移除;`GenerateOptions` 与 `ToolSchema` 在 `scripts/type-equiv.manifest.json` 中保留各自的行,因为两个类型本身仍然存在,只是少了一个字段。 +- 从 `GenerateOptions` 中移除 `prefill`,同时移除两个适配器的 UNSUPPORTED 守卫、固定这些 throw 的测试、[core.md](../../../core-data-structures/core.md) 中的粘贴行,以及适配器 README 中记录拒绝行为的行。实操手册(cookbook)中的 UNSUPPORTED 指引([adding-an-llm-adapter.md](../../../cookbook/adding-an-llm-adapter.md))改为泛化表述——你的 provider 无法兑现的 `GenerateOptions` 字段应抛出 `LlmError(..., 'UNSUPPORTED')`——而不再以 prefill 为例。[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的后果部分将 prefill 记录为「受 producer 门控」而非「已有归属」,依据 [implemented/AGENTS.md](../AGENTS.md)。 +- 从 `ToolSchema`、`DefineToolOptions`、`defineTool`、`schemas()` 允许列表、deepseek 序列化分支及其 wire-type 字段,以及 tool-catalog 渲染器的 `Strict:` 行中移除 `strict`。pi-ai 的 payload 修补逻辑简化为对 pi-ai 自身逐工具 strict 默认值的无条件清除(pi-ai 在每个序列化的工具上打 `strict: false`;手写的孪生适配器不发送此字段,因此清除逻辑为保持协议格式对等而保留,由其序列化器测试固定)。setter 测试和 core.md 粘贴行已移除;`GenerateOptions` 与 `ToolSchema` 在 `scripts/type-equiv.manifest.json` 中保留各自的行,因为两个类型只是少了一个字段,本身仍然存在。 -本 RFC 有意**不**触及 `temperature`、`stop` 或 `maxTokens`:这些字段被两个适配器端到端地兑现,是 `agent/request` 上请求变更钩子插件的自然首选目标。 +本 RFC 有意**不**触碰 `temperature`、`stop` 或 `maxTokens`:它们在两个适配器中都被端到端地兑现,是 `agent/request` 上请求变更钩子插件的自然首选目标。 ## 曾考虑的替代方案 ### 为什么不保留? -「显式的 UNSUPPORTED throw 是诚实的契约行为」——但一个旋钮在两个孪生适配器中的唯一实现都是拒绝,它什么也不承诺;删除它反而升级了失败模式:意外的赋值从运行时 throw 变为编译错误。「strict schema 遵循是官方文档记录的提供方功能,且管道完整」——但一个旋钮在有已发布工具设置它**且**有端点兑现它之前,都不是产品表面;今天两者都不成立。二者各自随其第一个真实生产方回归:`prefill` 随实现了 chat-prefix completion 的适配器(以及对不支持它的适配器的明确策略)一起回来,`strict` 随需要它的工具和 beta 端点方案一起回来。 +「显式的 UNSUPPORTED throw 是诚实的契约行为」——但一个在两个孪生适配器中唯一的实现就是拒绝的旋钮,什么也没承诺;删除它反而升级了失败模式:意外的 setter 变成编译错误而非运行时 throw。「Strict schema 遵循是官方文档记载的 provider 功能,且管道完整」——但一个旋钮在有已发布的工具设置它**并且**有端点兑现它之前,不构成产品表面;今天两者都不成立。它们各自随首个真实 producer 回归:`prefill` 随实现了 chat-prefix completion 的适配器(以及对不支持该功能的适配器的明确策略)一起回来;`strict` 随需要它的工具和 beta 端点方案一起回来。 ## 验证 -`rg prefill` 仅返回 RFC 记录(本文与[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的 producer-gated 后果);在 tool-schema 范围内 `rg strict` 仅返回本 RFC、保留的 pi-ai 擦除逻辑,以及无关行文(如 `strictEqual`)。两个适配器的契约测试在移除守卫后通过,pi-ai 修补仍然擦除库的 strict 默认值——协议格式对等由其序列化器测试固定。 +`rg prefill` 仅返回 RFC 记录(本 RFC 与[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 中 producer-gated 的后果);在 tool-schema 范围内执行 `rg strict` 仅返回本 RFC、保留的 pi-ai 清除逻辑,以及 `strictEqual` 等无关文本。两个适配器的契约测试在移除守卫后通过,pi-ai 修补逻辑仍然清除库的 strict 默认值——协议格式对等由其序列化器测试固定。 ## 后果 -已发布的钩子桥接不设置任何请求字段,而请求变更插件(`agent/request` waterfall(瀑布式事件)监听器)使用的是 `temperature`/`stop`(保留且可用),而非适配器拒绝的字段。如果 chat-prefix completion 或 strict 模式成为产品功能,重新添加将随适配器/端点工作一起落地,届时契约能说明实际发生了什么,而非「所有人都 throw」。 +已发布的钩子桥接不设置任何请求字段,而请求变更插件(`agent/request` waterfall(瀑布式事件)监听器)使用的是 `temperature`/`stop`(保留且可用),而非适配器拒绝的字段。如果 chat-prefix completion 或 strict 模式成为产品功能,重新添加将随适配器/端点工作一起落地,届时契约能说明实际发生了什么,而不是「所有人都 throw」。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml index 429f89095a..fb1161ae18 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-drop-unconsumed-web-observation-surface.md: c48ff5b80c916cd6cc04d6a8339a8555d05b0d40 -2026-07-04-drop-unconsumed-web-observation-surface.zh.md: ce8a108450ed9e9308066ab45b8f000dc20fde39 +2026-07-04-drop-unconsumed-web-observation-surface.zh.md: 4988a5aa77604f528cc23409a3c2290c890a7f5a diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md index ce8a108450..4988a5aa77 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:移除未被消费的 web 观测面——`providers-change` 事件与 status 方法 +# RFC:移除未被消费的 web 观测接口——`providers-change` 事件与 status 方法 Status: implemented @@ -6,29 +6,29 @@ Status: implemented ## 问题 -`WebService` 暴露了一组没有任何生产代码观测的观测面: +`WebService` 暴露了一组没有任何生产代码观测的观测接口: -- **`web/providers-change`**(`packages/web/web/src/index.ts`)在每次 provider 注册和 dispose(资源释放)时声明并发射。每个注册 effect 的回滚 yield 被刻意排在 emit 之前,唯一目的是让一个抛异常的 change listener 能回退注册。该事件在包自身的两个单元测试之外没有任何 listener(其中一个测试的存在就是为了固定那个回滚顺序)。 -- **`searchStatus()` / `fetchStatus()` 与 `WebCapabilityStatus` 联合类型**(同一个包)没有任何生产调用方:`dsh-tool-web` 直接通过 `ctx.web.search()`/`fetch()` 执行,并将不可用状态以 seam 在执行时抛出的结构化 `WebError` 错误码呈现(`packages/web/tool-web/src/search.ts`、`packages/web/tool-web/src/fetch.ts`);唯一的 status 调用方是 web 包自身的测试。`packages/web/tool-web/README.md` 与 [architecture.md](../../../architecture.md) 中的行文声称工具「只读取聚合的 `searchStatus()`/`fetchStatus()`」——这种漂移之所以存活,仅仅因为没有什么机制会拿行文与调用点做比对。 +- **`web/providers-change`**(`packages/web/web/src/index.ts`)在每次 provider 注册和 dispose(资源释放)时声明并发出,且每个注册 effect 的回滚 yield 被刻意排在 emit 之前,唯一目的是让抛出异常的 change listener 能回退注册。在该包自身的两个单元测试之外没有任何 listener(其中一个测试的存在仅仅是为了固定那个回滚顺序)。 +- **`searchStatus()` / `fetchStatus()` 与 `WebCapabilityStatus` 联合类型**(同一个包)没有任何生产调用方:`dsh-tool-web` 通过 `ctx.web.search()`/`fetch()` 直接执行,并将不可用性表现为 seam 在执行时抛出的结构化 `WebError` 错误码(`packages/web/tool-web/src/search.ts`、`packages/web/tool-web/src/fetch.ts`);唯一的 status 调用方是 web 包自身的测试。`packages/web/tool-web/README.md` 和 [architecture.md](../../../architecture.md) 中的行文声称该工具「只读取聚合的 `searchStatus()`/`fetchStatus()`」——这是一处漂移,仅因没有机制检查行文与调用点的一致性而幸存。 -seam 自身的设计使两个观测面都失去了消费方:工具注册跟随产品 ENABLEMENT 而非 provider 可用性(`packages/web/tool-web/src/index.ts`),provider 选择在执行时解析、从不缓存——因此没有需要失效的缓存、没有需要重算的注册集合,也没有调用方需要一个独立于「执行并路由结构化错误」的可用性探针。HMR(热模块替换)清理由 effect disposer 自身承载。 +seam 自身的设计使这两个接口天然没有消费方:工具注册跟随产品 ENABLEMENT 而非 provider 可用性(`packages/web/tool-web/src/index.ts`),provider 选择在执行时解析且从不缓存——因此没有需要失效的缓存、没有需要重算的注册集合、也没有调用方需要一个有别于「执行并路由结构化错误」的可用性探测。HMR(热模块替换)清理由 effect disposer 自身承载。 -这与[移除未被消费的 `llm/adapter-change` 事件](../../implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md)如出一辙:那次从 `LlmService` 移除了相同的通知形态、相同的回滚先于 emit 机制,以及相同的 listener-throw 测试。该 RFC 的保留/裁剪判据——保留 `tools/change`(因为它有合理的面向用户的工具列表消费方),裁剪启动期后端注册表信号——把 web provider 注册表信号明确归入裁剪一侧;status 方法则是同一判断应用于拉取面而非推送面。 +这与 [移除未被消费的 `llm/adapter-change` 事件](../../implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md) 如出一辙:那个 RFC 从 `LlmService` 中移除了相同的通知形态、相同的 rollback-before-emit 机制和相同的 listener-throw 测试。该 RFC 的保留/裁剪判据——为 `tools/change` 保留其合理的面向用户的工具列表消费方,裁剪启动时的后端注册表信号——将 web provider 注册表明确归入裁剪一侧;status 方法是同一判断应用于 pull 接口而非 push 接口。 ## 决策 -移除注册表变更事件、聚合 status 方法与类型,以及它们的专属测试。provider 私有的 status 保留用于执行时选择。面向调用方的覆盖率现在断言成功执行或结构化的选择错误,web 相关文档描述该按需调用契约。 +移除注册表变更事件、聚合 status 方法与类型,以及它们的专属测试。provider 私有的 status 保留用于执行时选择。面向调用方的覆盖率现在断言成功执行或结构化的选择错误,web 文档描述该按需调用契约。 ## 曾考虑的替代方案 ### 为什么不保留? -web seam RFC 当初有意指定了两者——事件作为最小的 HMR 可见性信号,status 方法作为工具的聚合诊断——且未来的 provider 状态面板是可以想象的。但同一 RFC 的其他选择使它们失去了消费方:按需派生的选择与基于 enablement 的注册使得没有消费方**能**需要它们;已交付的工具展示了真实模式(执行并路由结构化错误);漂移的 README 语句表明承诺的消费方从未实现。按照 AGENTS.md 的原则「RFC 是提案,不是金科玉律」,这些正是该提案中被代码证明过度延伸的部分;未来的观测者重新引入它实际消费的最小信号或查询,由该消费方塑造其形态。 +web seam RFC 有意指定了两者——事件作为最小的 HMR 可见性信号,status 方法作为工具的聚合诊断——且未来的 provider 状态面板是可以想象的。但同一 RFC 的其他设计选择使它们失去了消费方:按需派生的选择与基于 enablement 的注册使得没有消费方**能**需要这两者;已交付的工具展示了真实模式(执行并路由结构化错误);漂移的 README 语句表明承诺的消费方从未实现。按 AGENTS.md「RFC 是提案,不是金科玉律」的原则,这些是该提案中代码已证明过度设计的部分;未来的观测者按其实际消费的需求重新引入最小的信号或查询,由该消费方塑造其形态。 ## 验证 -`providers-change`、`searchStatus`、`fetchStatus` 和 `WebCapabilityStatus` 在 RFC 历史之外不再有任何拼写残留;catalog 是最新的(`verify-cordis-catalog` 绿色);注册/释放的 HMR 安全测试通过执行行为证明清理正确;tool-web README 与架构段落描述了工具实际拥有的执行时错误路由契约。 +在 RFC 历史之外不再有 `providers-change`、`searchStatus`、`fetchStatus` 或 `WebCapabilityStatus` 的拼写残留;catalog 是最新的(`verify-cordis-catalog` 绿色);注册/释放的 HMR 安全测试通过执行行为证明清理正确;tool-web README 与 architecture 段落描述了工具实际拥有的执行时错误路由契约。 ## 后果 -未来如果有 provider 选择器 UI 或诊断面板需要变更通知或 status 查询,它会重新添加自己实际消费的最小观测面;相同的判断及其反转条件已记录在 LLM 先例中。 +未来若有 provider 选择器 UI 或诊断面板需要变更通知或 status 查询,它将重新添加自身所消费的最小接口;相同的判断及其反转条件已记录在 LLM(大语言模型)先例中。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml index dfa01c3e89..4ca47feeee 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-fold-stdio-ui-helper.md: 8d26af190a957b424960519f77cbe132291c74de -2026-07-04-fold-stdio-ui-helper.zh.md: 879cce0d40e396b56f1a961b5ff190bab4fd70dd +2026-07-04-fold-stdio-ui-helper.zh.md: 795edf082258a56d3c11afbbb8de8cfa0e74e74e diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md index 879cce0d40..795edf0822 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md @@ -1,28 +1,28 @@ # RFC:将 stdio UI 辅助模块折入 stdio 应用 -Status: implemented - [English](2026-07-04-fold-stdio-ui-helper.md) | 中文 +Status: implemented + ## 问题 -readline UI 曾是一个完整的包(`@deepseek-ai/dsh-ui-stdio`,位于 `packages/support/`),其唯一的运行时导入方是应用包 `@deepseek-ai/dsh-stdio-demo`。示例通过加载该应用来使用 readline UI,从不自行组合这个辅助模块;仓库中所有其他引用都是因为包边界存在而存在的机械性或描述性表面:manifest 与 tsconfig 条目、生成的 module-graph 行、依赖图与 README 行,以及命名该包的文档注释。ui 分组 README 记录了 support 放置的理由("主要为示例和覆盖率门禁而存在——`ui/` 保留给作为产品交付的界面"),这留下了一个持续的张力:一个已交付的产品应用依赖一个被文档标注为非产品表面的 support 包。 +readline UI 曾是一个完整的包(`packages/support/` 下的 `@deepseek-ai/dsh-ui-stdio`),其唯一的运行时导入方是应用包 `@deepseek-ai/dsh-stdio-demo`。示例通过加载应用来使用 readline UI,从不自行组合该辅助模块;仓库中所有其他引用都是因为包边界存在而存在的机械性或描述性表面:manifest(元数据清单)与 tsconfig 条目、生成的 module-graph 行、依赖图与 README 行,以及命名该包的文档注释。ui 组 README 记录了 support 放置的理由("主要为示例和覆盖率门禁而存在,`ui/` 保留给作为产品交付的界面"),这留下了一个持续的张力:一个已交付的产品应用依赖一个被明确标注为非产品表面的 support 包。 -这条边界带来的是包元数据、workspace 与 tsconfig 引用、module-graph 行、README 条目,以及 publint 表面——服务于一个并不可独立替换的辅助模块:stdio 应用的前门集群总是包含 readline UI,且没有其他东西能有意义地消费它。 +这条边界换来的是:包元数据、workspace 与 tsconfig 引用、module-graph 行、README 条目,以及 publint 表面——服务于一个并不可独立替换的辅助模块:stdio 应用的前门集群始终包含 readline UI,且没有其他消费方能有意义地使用它。 ## 决策 -该辅助模块以终端通道插件的形式存在于 `@deepseek-ai/dsh-stdio` 中(`packages/ui/stdio/src/index.ts`):`createStdioChat`、其 `StdioRuntime` 测试 seam 及单元测试(`packages/ui/stdio/tests/stdio.spec.ts`、`readline.spec.ts`)一并迁入,因此 EOF 处理、渲染、dispose(资源释放)以及 piped-vs-TTY 行为在按文件覆盖率门禁下仍有单元测试覆盖,且无需劫持进程全局对象。该模块保持具名的 `name`/`inject`/`Config`/`apply` 导出形状——即应用通过 `ctx.plugin(uiStdio, …)` 挂载时消费的契约——而 `examples/echo-agent` 与 `examples/coding-agent` 中的 keyless Loader 路径冒烟测试继续证明组合树能通过真实 Loader 启动(stdio 包的插件形状单元测试套件固定了显式的 `unwrapExports` 断言,因为缺少 `inject` 的 bundle 会跳过一个意外的 default 导出而非崩溃)。 +该辅助模块作为终端通道插件存放在 `@deepseek-ai/dsh-stdio` 中(`packages/ui/stdio/src/index.ts`):`createStdioChat`、其 `StdioRuntime` 测试 seam 及单元测试(`packages/ui/stdio/tests/stdio.spec.ts`、`readline.spec.ts`)一并迁入,因此 EOF 处理、渲染、dispose(资源释放)以及管道/TTY 行为在按文件覆盖率门禁下仍有单元测试覆盖,且无需劫持进程全局对象。该模块保留具名的 `name`/`inject`/`Config`/`apply` 导出形状——即应用的 `ctx.plugin(uiStdio, …)` 挂载所消费的契约——而 `examples/echo-agent` 与 `examples/coding-agent` 中的 keyless Loader 路径冒烟测试继续证明组合树能通过真实 Loader 启动(stdio 包的插件形状单元测试套件固定了显式的 `unwrapExports` 断言,因为缺少 `inject` 的 bundle 会跳过一个意外的 default 导出而不是崩溃)。 -`packages/support/ui-stdio` 包已删除:manifest、tsconfig 引用、module-graph 行与 README 行均已清理;原先命名该包的文档注释(示例 e2e 模块文档、`packages/README.md`、support 与 todo README、[ui 分组 README](../../../../packages/ui/README.md))现在描述的是包内模块。 +`packages/support/ui-stdio` 包已移除:manifest、tsconfig 引用、module-graph 行与 README 行均已删除;曾命名该包的文档注释(示例 e2e 模块文档、`packages/README.md`、support 与 todo README、[ui 组 README](../../../../packages/ui/README.md))现在描述的是包内模块。 ## 曾考虑的替代方案 -### 为什么不将其提升到 `ui/`? +### 为什么不将其提升到 `ui/` 而是折入? -提升可以解决 support 与产品之间的错位,同时保留包边界——但只有在 readline UI 是一个可独立替换的集成或拥有第二个组合方时才是正确选择,而消费方普查表明两者都不成立。结构化的 ACP 桥接保持独立包,因为它是产品协议表面,拥有自己的契约和快照层级;readline 辅助模块只是一个应用前门的脚手架。在正式发布前重新拆出的成本很低:如果未来有第二个产品应用需要 readline UI,届时再拆出,由那个消费方来塑造包契约。 +提升可以解决 support 与 product 之间的错位,同时保留边界——只有在 readline UI 是一个可独立替换的集成或有第二个组合方时才是正确选择,而消费方普查表明两者皆非。结构化的 ACP 桥接保留为独立包,因为它是具有自身契约和快照层级的产品协议表面;readline 辅助模块只是一个应用前门的脚手架。在发布前重新拆分成本很低:如果将来有第二个产品应用需要 readline UI,届时再拆出来,由那个消费方来塑造包契约。 ## 后果 -- stdio 应用完整拥有自己的前门;一个叶子 `cordis.yml` 仍然只加载一个应用包,演示的形状没有变化。 +- stdio 应用完整拥有自己的前门;叶子 `cordis.yml` 仍然只加载一个应用包,演示的形态没有变化。 - 未来如果有独立的终端 UI 需要将该辅助模块作为包使用,届时由那个第二消费方驱动重新引入,而非仓库为假设性的复用保留一条边界。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml index f710b62445..ef7e3c8092 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-prune-producerless-vocabulary-variants.md: 271b97f6217a2694f36b7fe7339eab6176dba9e5 -2026-07-04-prune-producerless-vocabulary-variants.zh.md: 5d75c0327e2faf5e6e37f8db959509161beda702 +2026-07-04-prune-producerless-vocabulary-variants.zh.md: 2fe8d41a011c37919bd01022d5be6d309b865bf7 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md index 5d75c0327e..2fe8d41a01 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md @@ -1,33 +1,33 @@ -# RFC:清理无生产者的词汇变体(块缓存提示、`agent` 消息来源、`continuation` 轮次触发器) - -Status: implemented +# RFC:裁剪无生产者的词汇变体(块缓存提示、`agent` 消息来源、`continuation` 轮次触发器) [English](2026-07-04-prune-producerless-vocabulary-variants.md) | 中文 +Status: implemented + ## 问题 -合并可扩展的词汇映射表设计上通过声明合并来增长,代码库已在 `TurnEndReasonMap`(`packages/core/session/src/types.ts`)上声明了准入策略:像 `refusal` 这样的变体「在适配器或循环首次发出它之前,有意不加入」。三个已声明的词汇项违反了这一策略——每个都既无生产者也无消费方,其中两个甚至没有测试: +可合并扩展的词汇映射表设计上通过声明合并来增长,代码库已在 `TurnEndReasonMap`(`packages/core/session/src/types.ts`)上明确了准入策略:像 `refusal` 这样的变体「在适配器或循环首次发出它之前,有意不纳入」。三个已声明的词汇项违反了该策略——每个都既无生产者也无消费方,其中两个甚至没有测试: -- **`CacheHint` 及其 `cache?: CacheHint` 块字段**,位于 `TextBlock`/`ToolResultBlock`(`packages/llm/llm/src/types.ts`;image block 上还有第三个同类字段,随 image block 一起移除——见[移除 image 的 RFC](2026-07-04-drop-image-content-block.md))。没有任何地方构造过带 `cache:` 的块——src、测试和文档粘贴全部搜索为空——两个适配器也都不读 `.cache`:DeepSeek 的 prompt 缓存是自动的,适配器只从响应中映射出 `prompt_cache_hit_tokens`,从不向请求中发送提示。这是 Anthropic 风格的 `cache_control` 接口面,却没有任何提供方能兑现它。 -- **`MessageSourceMap.agent`**(`{ kind: 'agent'; agentId: string }`,同一文件)。零个构造点,测试中也没有。它预期的生产者在上线时并未使用它:subagent 后端将父级的 prompt 发送给子级时不带 `source`,因此日志中记录为 `{ kind: 'user' }`,通用信封渲染器在插值 `source.kind` 时也从不按它路由。 -- **`TurnTriggerMap.continuation`**(`packages/core/session/src/types.ts`)。agent loop(智能体循环)在结构上不可能发出它——续写发生在一个轮次*内部*作为后续步骤,从不作为新轮次——循环只构造 `message` 和 `injection` 触发器。唯一的写入者是一个手工构建的测试 fixture(测试前置数据)(`packages/support/llm-replay/tests/llm-replay.spec.ts`),它只需要一个任意的非 message 触发器,`injection` 触发器同样满足需求;唯一的生产环境触发器读取者 ACP 桥接层只过滤 `kind === 'message'`。 +- **`CacheHint` 及其 `cache?: CacheHint` 块字段**,位于 `TextBlock`/`ToolResultBlock`(`packages/llm/llm/src/types.ts`;image block 上还有第三个同类字段,已随 image block 一起移除——见[移除 image block 的 RFC](2026-07-04-drop-image-content-block.md))。没有任何地方构造过带 `cache:` 的块——src、测试和文档粘贴全部搜索为空——两个适配器也都不读 `.cache`:DeepSeek 的 prompt 缓存是自动的,适配器只从响应中映射出 `prompt_cache_hit_tokens`,从不向请求中发送提示。这是 Anthropic 风格的 `cache_control` 接口面,却没有能兑现它的提供方。 +- **`MessageSourceMap.agent`**(`{ kind: 'agent'; agentId: string }`,同一文件)。零个构造点,包括测试在内。它预期的生产者在实现时并未使用它:subagent 后端将父级的 prompt 发送给子级时不带 `source`,因此记录为 `{ kind: 'user' }`,通用信封渲染器在插值 `source.kind` 时也从未对其做路由。 +- **`TurnTriggerMap.continuation`**(`packages/core/session/src/types.ts`)。agent loop(智能体循环)在结构上不可能发出它——continuation 发生在一个轮次*内部*作为后续步骤,而非作为新轮次——循环只构造 `message` 和 `injection` 触发器。唯一的写入者是一个手工构建的测试 fixture(测试前置数据),它只需要一个任意的非 message 触发器(`packages/support/llm-replay/tests/llm-replay.spec.ts`),`injection` 触发器同样满足需求;唯一的生产环境触发器读取方 ACP 桥接层只过滤 `kind === 'message'`。 ## 决策 -删除 `CacheHint`、其 `cache?` 块字段、`agent` 消息来源变体和 `continuation` 轮次触发器变体:已发布的词汇不再包含它们。llm-replay fixture 改用 `injection` 触发器(任何非 `message` 触发器都能满足其用途)。[core.md](../../../core-data-structures/core.md) 和 [session.md](../../../core-data-structures/session.md) 中的 type-equiv 粘贴与裁剪后的映射表一致——两个符号保留在 `scripts/type-equiv.manifest.json` 中,因为每个映射表只是少了一个成员——[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的「后果」部分将缓存提示记录为「受生产者门控」而非「已有归属」,遵照 [implemented/AGENTS.md](../AGENTS.md)。 +删除 `CacheHint`、其 `cache?` 块字段、`agent` 消息来源变体与 `continuation` 轮次触发器变体:发布的词汇表不再包含它们。llm-replay fixture 改用 `injection` 触发器(任何非 `message` 触发器均满足其用途)。[core.md](../../../core-data-structures/core.md) 和 [session.md](../../../core-data-structures/session.md) 中的 type-equiv 粘贴与裁剪后的映射表一致——两个符号保留在 `scripts/type-equiv.manifest.json` 中,因为每个映射表本身仍然存在,只是少了一个成员——[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的后果部分将缓存提示记录为「受生产者门控」而非「已有归属」,依照 [implemented/AGENTS.md](../AGENTS.md)。 -每个变体在获得真正的生产者之日回归,这正是映射表设计上的增长方式:缓存功能连同传输它的适配器一起重新添加 `cache`;subagent 归属连同打标的后端和路由它的消费方一起重新添加 `agent`;真正启动新轮次的自动续写功能连同发出它的插件一起重新添加 `continuation`。 +每个变体在获得真正的生产者之日回归,这正是映射表设计的增长方式:缓存功能连同传输它的适配器一起重新添加 `cache`;subagent 归属连同打标的后端和路由它的消费方一起重新添加 `agent`;真正启动新轮次的自动续行功能连同发出它的插件一起重新添加 `continuation`。 ## 曾考虑的替代方案 ### 为什么不保留它们? -[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 将「缓存提示……已有归属」列为设计后果,预留的槽位确实能传达意图。但一个空槽位是契约面,每个实现和消费方都必须考虑它(我的适配器是否必须兑现 `cache`?我的渲染器是否必须路由 `agent` 来源?),而兄弟映射表自身的 JSDoc 已经拒绝了「无发出者的预留」——`refusal` 和 `max_turn_requests` 被标注为*当有东西首次发出它们时*再添加的变体,而非提前声明。对已声明但无生产者的变体执行同一标准,才能让词汇表有意义:如果它在映射表里,就一定有东西在生产它。 +[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 将「缓存提示……已有归属」列为设计后果,预留槽位确实能表达意图。但一个空槽位是每个实现和消费方都必须考虑的契约面(我的适配器需要兑现 `cache` 吗?我的渲染器需要路由 `agent` 来源吗?),而同族映射表自身的 JSDoc 已经拒绝了「无发出者的预留」——`refusal` 和 `max_turn_requests` 被明确标注为*当某物首次发出它们时*再添加的变体,而非提前声明。对已声明但无生命的变体施加同样的标准,使词汇表具有实际意义:如果它在映射表中,就一定有东西在生产它。 ## 验证 -`rg` 搜索 `CacheHint`、`agent` 消息来源的拼写和 `continuation` 触发器的拼写,只返回 RFC 记录(本文,以及[移除 image 的 RFC](2026-07-04-drop-image-content-block.md) 中关于 image block 自身 `cache` 字段的描述);llm-replay fixture 使用 `injection` 触发器断言相同的回放行为;核心数据结构粘贴与 type-equiv manifest(元数据清单)保持同步。 +对 `CacheHint`、`agent` 消息来源拼写和 `continuation` 触发器拼写执行 `rg` 搜索,结果仅返回 RFC 记录(本文,以及[移除 image block 的 RFC](2026-07-04-drop-image-content-block.md) 中关于 image block 自身 `cache` 字段的说明);llm-replay fixture 使用 `injection` 触发器断言了相同的回放行为;core-data-structures 粘贴与 type-equiv manifest 保持同步。 ## 后果 -没有运行时行为改变——本来就没有任何东西能构造这些值。镜像事件的移除([边界镜像 RFC](2026-06-20-remove-agent-boundary-mirror-events.md)、[流式分片镜像 RFC](2026-07-02-remove-stream-chunk-mirror.md))只涉及瞬态的 `agent/*` 事件,从不触及持久化词汇,因此不存在冲突。其他地方准入策略已经生效:`rejected`、`prompt/blocked` 和 `hook/invoked`/`hook/result` 各自都有活跃的生产者——本 RFC 将同一标准延伸到缺少生产者的三个变体。image block 自身的 `cache?` 字段属于[移除 image 的 RFC](2026-07-04-drop-image-content-block.md),随该块一起移除;本 RFC 覆盖的是保留下来的块类型上的两个字段。 +没有任何运行时行为改变——本来就没有东西能构造这些值。镜像事件的移除([boundary-mirror RFC](2026-06-20-remove-agent-boundary-mirror-events.md)、[stream-chunk RFC](2026-07-02-remove-stream-chunk-mirror.md))只涉及瞬态的 `agent/*` 事件,从不涉及持久词汇,因此不存在冲突。其他地方准入策略已经成立:`rejected`、`prompt/blocked` 和 `hook/invoked`/`hook/result` 各自都有活跃的生产者——本 RFC 将同一标准延伸到缺少生产者的三个变体。image block 自身的 `cache?` 字段属于[移除 image block 的 RFC](2026-07-04-drop-image-content-block.md),已随该块一起移除;本 RFC 覆盖的是留存块类型上的两个字段。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml index 3a4db54e54..428dfb9379 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-prune-write-only-fs-surface.md: ac2cbcc282b848b26a3d5d327e0ab54612b5ac91 -2026-07-04-prune-write-only-fs-surface.zh.md: 799847aa77599a292c1aa48e150aae99fa130ae3 +2026-07-04-prune-write-only-fs-surface.zh.md: e854df76cae74033404aa9cc1986fdd118f19b10 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md index 799847aa77..e854df76ca 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md @@ -1,32 +1,32 @@ -# RFC:从 fs seam 中移除只写字段与一个无效路由旋钮 - -Status: implemented +# RFC:从 fs seam 中移除只写字段与一个无效的路由旋钮 [English](2026-07-04-prune-write-only-fs-surface.md) | 中文 +Status: implemented + ## 问题 -[fs seam 拆分](2026-06-26-fsspec-style-fs-seam.md)将读取路由与策略从后端移入 `dsh-tool-fs` 和 `dsh-fs-policy`。四处接口保留了拆分前的形态——每次调用都填充,却无人读取: +[fs seam 拆分](2026-06-26-fsspec-style-fs-seam.md)将读取路由与策略从后端移至 `dsh-tool-fs` 和 `dsh-fs-policy`。有四处接口保留了拆分前的形态——每次调用都填充,却无人读取: -1. **`dsh-fs-local` 中的 `STREAM_MIN_SIZE` + `FsIoInternals.streamMinSize`**——*在本次变更之前已被"无硬编码可调参数"审计移除,该审计将路由阈值改为 `dsh-tool-fs` 的 `readStreamMinSize` 配置;此处记录是为了完整呈现整个裁剪。*原始位置(`packages/fs/fs-local/src/fsio.ts`,从 `packages/fs/fs-local/src/index.ts` 再导出):包括 fs-local 自身源码和测试在内,全仓库零读取者。后端不做读取路由——`readWholeText`/`streamWholeText` 是调用方自行选择的独立原语——真正的路由常量在消费方(`packages/fs/tool-fs/src/read.ts`,与 `info.size` 比较)。10 MiB 这个事实有两份镜像;后端那份是死代码,而该旋钮的 JSDoc 声称提供一个并不存在的"读取路由"覆盖。 -2. **`FsTarget.inputPath`**(`packages/fs/fs/src/types.ts`):每个后端和每个测试 fake 都必须编造一个"仅用于诊断"的值,而生产环境零读取者——策略插件和所有错误消息使用的是 `targetKey`/`displayPath`。`listDir` 的生产者暴露了语义摇摆:目录子项拿到的是裸条目名,这不是任何人的"输入路径"。 -3. **`FsEditOutcome.replacements` + `.replaceAll`**(`packages/fs/fs/src/types.ts`):`replacements` 生产环境零读取者(单匹配策略本身保留——它由后端内部的 `FS_AMBIGUOUS_EDIT`/`FS_EDIT_NOT_FOUND` 抛出强制执行,错误消息保留了内部计数);`replaceAll` 仅被 `packages/fs/tool-fs/src/edit.ts` 中的 `formatEditOutput` 读取——作为工具已持有的 `replace_all` 参数的回声。精简后,`FsEditOutcome` 变为 `{ version, before, after }`,与 `FsWriteOutcome` 中真正由后端发现的字段对齐。 -4. **`FileReadOutcome.limit` + `.version`**(`packages/fs/tool-fs/src/read-render.ts`):由读取工具填充,但 `formatReadOutput` 只渲染 `offset`/`lines`/`totalLines`/`truncatedByBytes`,而 `fs/observed` 事件直接使用 `info.version`,不使用 outcome 的副本。 +1. **`dsh-fs-local` 中的 `STREAM_MIN_SIZE` + `FsIoInternals.streamMinSize`**——*在本次变更之前已被「禁止硬编码可调参数」审计移除,该审计将路由阈值改为 `dsh-tool-fs` 的 `readStreamMinSize` 配置;此处记录是为了完整呈现整次清理。* 原始位置(`packages/fs/fs-local/src/fsio.ts`,从 `packages/fs/fs-local/src/index.ts` 重导出):包括 fs-local 自身源码和测试在内,全仓库零读取者。后端没有读取路由——`readWholeText`/`streamWholeText` 是调用方自行选择的两个独立原语——真正的路由常量位于消费方(`packages/fs/tool-fs/src/read.ts`,与 `info.size` 比较)。同一个 10 MiB 事实的两份镜像;后端那份是死代码,且该旋钮的 JSDoc 声称提供一个实际不存在的「read routing」覆盖。 +2. **`FsTarget.inputPath`**(`packages/fs/fs/src/types.ts`):每个后端和每个测试 mock 都必须为这个「仅供诊断」的字段编造一个值,而生产环境零读取者——策略插件和所有错误消息使用的是 `targetKey`/`displayPath`。`listDir` 的生产者暴露了语义上的摇摆:目录子项得到的是裸条目名,这不是任何人的「input」。 +3. **`FsEditOutcome.replacements` + `.replaceAll`**(`packages/fs/fs/src/types.ts`):`replacements` 生产环境零读取者(单匹配策略本身保留——它由后端内部 `FS_AMBIGUOUS_EDIT`/`FS_EDIT_NOT_FOUND` 抛出来强制执行,错误消息保留了内部计数);`replaceAll` 仅被 `packages/fs/tool-fs/src/edit.ts` 中的 `formatEditOutput` 读取——作为工具本身已持有的 `replace_all` 参数的回声。精简后,`FsEditOutcome` 变为 `{ version, before, after }`,与 `FsWriteOutcome` 中真正由后端发现的字段对齐。 +4. **`FileReadOutcome.limit` + `.version`**(`packages/fs/tool-fs/src/read-render.ts`):由读取工具填充,但 `formatReadOutput` 只渲染 `offset`/`lines`/`totalLines`/`truncatedByBytes`,且 `fs/observed` 事件发射直接使用 `info.version` 而非 outcome 的副本。 ## 决策 -删除 fs-local 常量及其再导出和 `streamMinSize` 旋钮(`FsIoInternals` 中剩余的旋钮确实被原子写入测试使用);从 `FsTarget` 中移除 `inputPath`;将 `FsEditOutcome` 精简为 `{ version, before, after }`,并将 `replaceAll` 从解析后的参数传给 `formatEditOutput`;从 `FileReadOutcome` 中移除 `limit`/`version`。[filesystem.md](../../../core-data-structures/filesystem.md) 中的粘贴内容、`packages/fs/fs/README.md`,以及那些不得不编造被移除字段的测试 fake 随类型一起精简。 +删除 fs-local 的常量及其重导出,以及 `streamMinSize` 旋钮(`FsIoInternals` 中剩余的旋钮确实被原子写入测试使用);从 `FsTarget` 中移除 `inputPath`;将 `FsEditOutcome` 精简为 `{ version, before, after }`,并将 `replaceAll` 从解析后的参数传入 `formatEditOutput`;从 `FileReadOutcome` 中移除 `limit`/`version`。[filesystem.md](../../../core-data-structures/filesystem.md) 中的粘贴内容、`packages/fs/fs/README.md`,以及那些不得不为已移除字段编造值的测试 mock,都随类型一起缩减。 ## 曾考虑的替代方案 ### 为什么不保留? -未来的权限/隔离层可能需要解析前的路径来生成错误文本——但它需要的是*请求*,每个调用点仍然持有请求。"替换了 N 处"可能成为面向模型的文本——那是需要时再设计的行为变更,且后端内部的计数为其错误消息保留着。读取页脚可能展示 `limit`——页脚展示的一切已经可以从 `lines`/`totalLines` 推导。与此同时,当前和未来的每个后端(远程、原生)都必须编造无人消费的协议格式(wire format)字段,每个测试 fake 都必须满足它们。 +未来的权限/隔离层可能需要解析前的路径来生成错误文本——但它需要的是*请求*,每个调用点仍然持有请求。「替换了 N 处」可能成为面向模型的文本——这是一个需要时再设计的行为变更,且后端内部的计数为其错误消息而保留。读取页脚可能展示 `limit`——但页脚展示的一切已经可以从 `lines`/`totalLines` 推导。与此同时,每个现有和未来的后端(远程、原生)都必须编造无人消费的协议字段,每个测试 mock 都必须满足它们。 ## 验证 -被移除的接口已不存在——`dsh-fs-local` 中的 `STREAM_MIN_SIZE`/`streamMinSize`、`FsTarget.inputPath`、`FsEditOutcome.replacements`/`.replaceAll`、`FileReadOutcome.limit`/`.version`——而请求侧的 `replaceAll`(`FsEditRequest`)和其他 outcome 类型上的 version 字段未受影响;测试 fake 随类型一起精简。`formatEditOutput` 在 `replace_all` 两个分支下的输出文本不变,因此没有快照 golden 被搅动。 +被移除的接口已消失——`dsh-fs-local` 中的 `STREAM_MIN_SIZE`/`streamMinSize`、`FsTarget.inputPath`、`FsEditOutcome.replacements`/`.replaceAll`,以及 `FileReadOutcome.limit`/`.version`——而请求侧的 `replaceAll`(`FsEditRequest`)和其他 outcome 类型上的 version 字段未受影响;测试 mock 随类型一起缩减。`formatEditOutput` 在 `replace_all` 两个分支下输出的文本不变,因此没有快照黄金文件被搅动。 ## 后果 -后端不增加新义务;它们卸下了四个无人消费的字段。fs 发现工作(glob/grep 工具)触及相同的 `dsh-fs` 类型文件——这是文本层面而非设计层面的重叠,可以机械地解决。 +后端不增加新义务,反而卸下了四个无人消费的字段。fs 发现功能(glob/grep 工具)涉及相同的 `dsh-fs` 类型文件——这是文本层面而非设计层面的重叠,可以机械地合并解决。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml index 1e1c22f3c1..be2b32be56 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-remove-agent-steering-mirror.md: 311f0f8ffd278adf71a35617b900d4d16037055a -2026-07-04-remove-agent-steering-mirror.zh.md: 4ceb31a0263a7c386ceed071d3f0db315c7a9f23 +2026-07-04-remove-agent-steering-mirror.zh.md: 24198afb0714863867f4d7e17ae19ea8af6a88bd diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md index 4ceb31a026..24198afb07 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md @@ -1,4 +1,4 @@ -# RFC:移除 `agent/steering` 镜像事件发射 +# RFC:移除 `agent/steering` 镜像 emit [English](2026-07-04-remove-agent-steering-mirror.md) | 中文 @@ -6,28 +6,28 @@ Status: implemented ## 问题 -`agent/steering` 是最后一个仍存在的、对持久会话事件的瞬态镜像。循环的 steering 排空逻辑先追加持久事件 `steering/message { turn, content, source }`,紧接着下一行就发射 `agent/steering(agent, turn, content, source)`——同一个事实以 fire-and-forget 事件的形式重复一遍(`packages/core/agent-loop/src/loop.ts`,`drainSteering`)。它在生产环境中没有任何监听者:唯一的订阅方是一个循环回归测试,断言该发射携带了 `source`——而这个事实在上一行的持久事件中已经记录。 +`agent/steering` 是最后一个仍存在的、对持久会话事件的瞬态镜像。agent loop(智能体循环)的 steering(中途引导)drain 逻辑先追加持久事件 `steering/message { turn, content, source }`,紧接着下一行就 emit `agent/steering(agent, turn, content, source)`——同一个事实以 fire-and-forget 事件的形式重复发出(`packages/core/agent-loop/src/loop.ts`,`drainSteering`)。它在生产环境中没有任何监听者:唯一的订阅方是一个 agent loop 回归测试,断言 emit 携带了 `source`——而这同一个事实已经由上一行的持久事件记录。 -`agent/steering` 以相同的 payload 复制了紧邻其前的持久事件 `steering/message`。`agent/queued` 则保留为纯 live 信号,因为它在持久化之前触发,覆盖了可能在进入日志前被取消的工作。 +`agent/steering` 以相同的 payload 重复了紧接其前的持久事件 `steering/message`。`agent/queued` 仍保留为纯瞬态信号,因为它在持久化之前触发,覆盖了可能在进入日志前被取消的工作。 -steering(中途引导)承载着真实的生产流量:钩子桥的轮次续行决策通过 `inbox.steer()` 注入原因,落地为持久的 `steering/message` 事件,钩子矩阵的 golden 文件固定了这些事件。所有这些消费方观察的都是持久事件,没有任何消费方观察镜像。 +steering 承载着真实的生产流量:hook bridge 的轮次续行决策通过 `inbox.steer()` 注入理由,落地为持久的 `steering/message` 事件,hook-matrix 的 golden 文件对此进行固定——所有这些消费方观察的都是持久事件。没有任何消费方观察镜像事件。 ## 决策 -`agent/steering` 从 agent 事件分类体系中移除:`packages/core/agent/src/types.ts` 中的声明(及其在 live-events JSDoc 列表中的提及)、`drainSteering` 中的发射(随之移除的还有当时已无用的 `ctx` 参数)、`packages/core/agent/README.md` 中的对应行,以及循环伪代码块中的发射行(`packages/core/agent-loop/src/loop.ts` 模块文档与 [architecture.md](../../../architecture.md));Cordis catalog 重新生成后不再包含它。唯一的回归测试改为在持久事件 `steering/message` 上固定 source 保持——它所固定的事实存在于日志中。 +`agent/steering` 从 agent 事件分类体系中移除:`packages/core/agent/src/types.ts` 中的声明(及其在 live-events JSDoc 列表中的提及)、`drainSteering` 中的 emit(随之移除的还有当时已无用的 `ctx` 参数)、`packages/core/agent/README.md` 中的对应行,以及 loop 伪代码块中的 emit 行(`packages/core/agent-loop/src/loop.ts` 模块文档与 [architecture.md](../../../architecture.md));Cordis catalog 重新生成后不再包含它。唯一的回归测试改为在持久事件 `steering/message` 上固定 source 保持性——它所固定的事实存在于日志中。 -三份已实施的 RFC 曾声明保留该事件,每份均按 [implemented/AGENTS.md](../AGENTS.md) 修订,指向本 RFC 作为移除记录:[boundary RFC](2026-06-20-remove-agent-boundary-mirror-events.md) 的保留列表条目、[stream-chunk RFC](2026-07-02-remove-stream-chunk-mirror.md) 的范围条款,以及 [event-domain-semantics RFC](../architecture/2026-06-30-event-domain-semantics.md) 的瞬态发射枚举。 +三份已实施的 RFC 曾声明保留该事件,每份均按 [implemented/AGENTS.md](../AGENTS.md) 的要求修订,指向本 RFC 作为移除记录:[boundary RFC](2026-06-20-remove-agent-boundary-mirror-events.md) 的保留列表条目、[stream-chunk RFC](2026-07-02-remove-stream-chunk-mirror.md) 的范围条款,以及 [event-domain-semantics RFC](../architecture/2026-06-30-event-domain-semantics.md) 的瞬态 emit 枚举。 ## 曾考虑的替代方案 ### 为什么不保留? -"它是控制信号,不是边界事件"——但分类体系的实际区分维度是「镜像 vs 纯 live」,而非「控制 vs 边界」,而这个事件属于镜像。需要入队时通知的消费方有 `agent/queued`(带 steering flag);需要排空时通知的消费方本质上是在请求 `steering/message` 被追加的那一刻,而 `session/event` 以相同 payload 加上持久性提供了这一点。被否决的 [retire-mid-turn-steering RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md) 捍卫的是 steering **能力**——`steer()`、持久事件、续行强制——本次移除对这些全部不动。 +"它是控制信号,不是边界事件"——但分类体系的操作性区分是「镜像 vs. 纯瞬态」,而非「控制 vs. 边界」,而这个事件属于镜像。需要入队时通知的消费方有 `agent/queued`(带 steering flag);需要 drain 时通知的消费方,本质上是在请求 `steering/message` 被追加的那一刻,而 `session/event` 以相同 payload 加上持久性提供了这一通知。被否决的 [retire-mid-turn-steering RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md) 捍卫的是 steering **能力**——`steer()`、持久事件、续行强制——本次移除对这些全部保持不变。 ## 验证 -`agent/steering` 这一拼写仅存在于 RFC 行文中(本 RFC、上述三份修订后的 RFC,以及冻结的[被否决 steering 能力 RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md),其文本记录了它所拒绝的提案);catalog 已重新生成;重定向后的测试在 `steering/message` 上固定 source 保持。 +`agent/steering` 这一拼写仅存于 RFC 行文中(本 RFC、上述三份修订的 RFC,以及冻结的[被否决的 steering 能力 RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md),其文本记录了它所拒绝的提案);catalog 已重新生成;重定向后的测试在 `steering/message` 上固定 source 保持性。 ## 后果 -没有需要迁移的生产监听者。两种 live 通知需求都保留了归属:入队时通知归 `agent/queued`(带 `steering` flag),排空时通知归 `session/event`(持久的 `steering/message` 落地时触发)。 +生产环境中没有需要迁移的监听者,两种瞬态通知需求各有归宿:入队时由 `agent/queued`(带 `steering` flag)承载,drain 时由 `session/event` 在持久事件 `steering/message` 落地时承载。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml index 16316292cd..6a470484f3 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-share-app-bin-boot-glue.md: afaa61fe909f3dbf900337518969410780020a88 -2026-07-04-share-app-bin-boot-glue.zh.md: 2a022fbb8dcdf6977ede81780a87c570715ce441 +2026-07-04-share-app-bin-boot-glue.zh.md: 33fe2f27df9c8b172e4296ece0720813f9775f86 diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md index 2a022fbb8d..33fe2f27df 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md @@ -1,27 +1,27 @@ -# RFC:共享应用 bin 的启动胶水代码,不再维护两份副本 - -Status: implemented +# RFC:共享应用 bin 的启动胶水代码,而非维护两份副本 [English](2026-07-04-share-app-bin-boot-glue.md) | 中文 +Status: implemented + ## 问题 -stdio 和 ACP bin 各自重复了环境加载、fail-loud 处理、入口校验与启动逻辑,包括微妙的 Loader 失败行为。两份副本已经发生漂移,且位于自执行文件中、被排除在单元测试覆盖率之外,导致其中的辅助导出无法被复用。 +stdio 和 ACP 两个 bin 各自重复了环境加载、fail-loud 处理、入口校验与启动逻辑,包括微妙的 Loader 失败行为。两份副本已经发生漂移,且位于自执行文件中、被排除在单元测试覆盖率之外,导致其导出的辅助函数无法被复用。 ## 决策 -辅助逻辑只存在一处:[`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot)(`packages/ui/app-boot`,归入 `ui` 组,因为 bin 是已发布产物,其运行时依赖本身也必须是已发布的,而非 `support/`)。包含:`resolveConfigPath`(快照感知,两个 bin 共用的唯一路径解析器)、`loadEnv`、`installFailLoud`、`assertEntriesLoaded` 和 `boot`,每个函数都按 bin 的诊断前缀参数化,并在其副作用 seam(warn sink、process 切片)处可注入,使单元测试套件能覆盖每个分支——包括 `boot()` 在进程内驱动真实 Loader、使用相对路径 specifier 的配置,涵盖已就绪树的正常路径和无 fiber 入口的拒绝路径。该包(package)启用了逐文件 100% 覆盖率门禁;Loader 失败的经验知识只有一个归属地。 +辅助函数只存在一处:[`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot)(`packages/ui/app-boot`,归入 `ui` 分组,因为 bin 是已发布产物,其运行时依赖本身也必须是已发布的包,而非 `support/`)。包含:`resolveConfigPath`(快照感知,两个 bin 共用的唯一路径解析器)、`loadEnv`、`installFailLoud`、`assertEntriesLoaded` 与 `boot`,每个函数都通过 bin 的诊断前缀参数化,并在其副作用 seam(warn sink、process slice)处支持注入,使单元测试套件能覆盖每个分支——包括 `boot()` 在进程内驱动真实 Loader、使用相对路径 specifier 配置的场景,既覆盖已稳定树的正常路径,也覆盖无 fiber 入口的拒绝路径。该包启用逐文件 100% 覆盖率门禁;Loader 失败的相关知识只有一个归属地。 -每个 `bin.ts` 是一个精简的自执行组合:在共享辅助逻辑之上叠加各自应用特有的生命周期(ACP bin:replay 模式下跳过环境加载与 stdin-EOF dispose;stdio bin:无额外逻辑)。bin 文件仍然被排除在覆盖率之外且不导出任何内容;已发布产物的防护措施不变——built-bin 冒烟测试仍然在一个 node_modules 形状的临时目录下用原生 node 运行每个 bin(现在也 symlink 了 `ui/app-boot`),并仍然断言缺少配置时的非零退出码,遵循「真实入口路径意味着已发布产物」的防御模式。[extract-example-app-packages RFC](../architecture/2026-06-20-extract-example-app-packages.md) 中关于 bin 归属的事实已相应修订。 +每个 `bin.ts` 是一个精简的自执行组合,基于共享辅助函数加上各自特有的应用生命周期(ACP bin:replay 模式下跳过 env 加载与 stdin-EOF dispose;stdio bin:无额外逻辑)。bin 文件仍被排除在覆盖率之外且不导出任何内容;已发布产物的守卫不变——built-bin 冒烟测试仍在 node_modules 形状的临时目录中以原生 node 运行每个 bin(现在也符号链接了 `ui/app-boot`),并仍断言缺少配置时的非零退出码,遵循「真实入口路径即已发布产物」的防御模式。[extract-example-app-packages RFC](../architecture/2026-06-20-extract-example-app-packages.md) 中关于 bin 归属的事实已相应修订。 ## 曾考虑的替代方案 -### 为什么不保留重复? +### 为何不保留重复? -bin 被定位为独立拥有的已发布产物,而新增一个包有固定开销(manifest、README、tsconfig reference、publint 表面积),与去重的代码行数相当。但创建 bin 的那份 RFC 从未权衡过应用间共享——它把三个示例 `start.ts` 副本合并**进**了 bin 就止步了;漂移是已观察到的事实;而覆盖率缺口的论点独立于去重论点:这是仓库中唯一被豁免于逐文件 100% 门禁的非平凡运行时逻辑。记录在案的回退方案(仅将纯逻辑提取为各应用模块)可以结束豁免,但会保留两个经验知识归属地。 +bin 被定位为独立拥有的已发布产物,而新增一个包(package)带来的固定开销(manifest(元数据清单)、README、tsconfig reference、publint 表面积)与去重的代码行数相当。但创建 bin 的那份 RFC 从未权衡过应用间共享的可能——它将三份示例 `start.ts` 副本合并进 bin 后便止步了;漂移是已观察到的事实;而覆盖率缺口的论据独立于去重论据:这是仓库中唯一免于逐文件 100% 门禁的非平凡运行时逻辑。记录在案的备选方案(仅将纯逻辑提取为各应用自己的模块)虽能终结豁免,但会保留两个知识归属地。 ## 后果 -- 启动胶水代码的变更(新增守卫、修复解析)只需落地一次,两个已发布 bin 自动继承;bin 之间不会再次漂移。 -- `dsh-app-boot` 保持依赖精简(cordis + loader/include 对)——它是启动机制,不是应用接口。 -- bin 自身的文件是近乎平凡的组合;所有带分支的逻辑都在覆盖率门禁之下。 +- 启动胶水代码的变更(新增守卫、修复路径解析)只需落地一次,两个已发布 bin 自动继承;bin 之间不会再次漂移。 +- `dsh-app-boot` 保持轻量依赖(cordis + loader/include 对)——它是启动机制,不是应用表面积。 +- bin 自身的文件几乎是平凡的组合;所有含分支的逻辑都在覆盖率门禁之下。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml index 38cd3003a8..95c2fdbf50 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-tighten-hook-protocol-contract.md: df438516b836315902378afe7f4fd09e512c0966 -2026-07-04-tighten-hook-protocol-contract.zh.md: decc6ba86131f6d1930eb51a1267a9668d91dcb2 +2026-07-04-tighten-hook-protocol-contract.zh.md: 256da42993c8581e8bce861ecbfac22dbf5f0545 diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md index decc6ba861..256da42993 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md @@ -1,4 +1,4 @@ -# RFC:收紧 hook 协议契约——dialect、废弃字段、双重默认值与 lib 拥有的 `hook/result` 语义 +# RFC:收紧 hook-protocol 契约——dialect、废弃字段、双重默认值与 lib 拥有的 `hook/result` 语义 [English](2026-07-04-tighten-hook-protocol-contract.md) | 中文 @@ -8,25 +8,25 @@ Status: implemented `dsh-hook-protocol`/bridge 契约中有四处遗漏了 [subagent-observe-enrich RFC](../feature/2026-06-30-subagent-observe-enrich.md) 所记录的纪律——该 RFC 因缺乏消费方而移除了 `agentType` 生命周期字段,以下四处未通过同样的检验: -1. **`HookDialect` 的 `'native'` 变体**(`packages/hooks/hook-protocol/src/types.ts`)没有任何生产者——bridge 只打 `'claude'` 和 `'codex'` 标记;唯一的 `'native'` 构造出现在 lib 自身的单元测试中。该字段自己的 JSDoc 将 `dialect` 定义为「执行它的 bridge」,而 native 不是 bridge:[interception-seams RFC](../feature/2026-06-30-interception-seams.md) 记录了 native 钩子不是一个 package,且「native 插件已经可以直接使用类型化的 Decisions」而无需持久化的 hook 日志;旗舰 native 插件的工作示例也正是如此断言的(完全没有 `hook/*` 事件)。 -2. **`HookOutput.suppressOutput`**(同一文件)被 codec 解析后在所有路径上都被丢弃:没有 bridge 分支、没有 merge fold、没有 warn、没有 deferred-list 行——在所有「被解析但未兑现」的同类字段中,它是唯一没有明确延期声明的(`updatedInput` → 一条 warn 日志加 [pre-tool-input-rewrite 提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md);`systemMessage` → 一条 warn 日志加 README deferred 行;`continue`/`stopReason` → 一个 `TODO(hook-continue-false)` 锚点加 `'stop'` decision 记录)。从结构上看根本没有什么可 suppress 的:hook 的 stdout 从不进入任何 transcript(文本记录)(上下文仅通过 `additionalContext` 流入;日志只记录 `decision`/`stderrSummary`),因此 hook 作者设置 `suppressOutput: true` 得到的是无声的空操作,连 warn 都没有。 -3. **`defaultTimeoutMs` 在两个 bridge 配置中被双重默认,使用浮动字面量**——一个 schema `.default(600_000)` 加一个 `?? 600_000` 回退(`packages/hooks/hooks-claude/src/index.ts`、`packages/hooks/hooks-codex/src/index.ts`),每个 bridge 为同一个协议级常量提供两个归属,两个 bridge 可能在共享默认值上悄然分歧。*本提案最初的补救——彻底删除该配置项——被 no-hardcoded-tunables 审计取代,后者保留了该配置项作为 bridge 拥有的显式配置(并在旁边新增了 `stderrSummaryMaxChars`);剩下需要修复的是字面量的归属。* -4. **`hook/result` 的语义存在于两个 bridge 中(各一份),而非拥有该事件的 lib。** `summarize()`——stderr 截断规则——在 `packages/hooks/hooks-claude/src/index.ts` 和 `packages/hooks/hooks-codex/src/index.ts` 中逐字节相同,decision 字符串规则 `output.decision ?? (output.continue === false ? 'stop' : 'pass')` 也是如此;然而 `dsh-hook-protocol` 声明了 `hook/result`、将 `stderrSummary` 文档化为「已截断」却不拥有截断逻辑,将 decision 值文档化却不拥有映射逻辑。如果某个 bridge 漂移(不同的上限、不同的回退),共享的持久化事件的语义就会悄然分叉。 +1. **`HookDialect` 的 `'native'` 变体**(`packages/hooks/hook-protocol/src/types.ts`)没有任何生产者——bridge 只会标记 `'claude'` 和 `'codex'`;唯一构造 `'native'` 的地方是 lib 自身的单元测试。该字段的 JSDoc 将 `dialect` 定义为「运行它的 bridge」,而 native 并非 bridge:[interception-seams RFC](../feature/2026-06-30-interception-seams.md) 记录了 native hook 不是一个 package,且「native 插件已经可以直接使用类型化的 Decisions」而无需持久化 hook 日志;旗舰 native-plugin 示例也正是如此断言的(完全没有 `hook/*` 事件)。 +2. **`HookOutput.suppressOutput`**(同一文件)被 codec 解析后在所有路径上均被丢弃:没有 bridge 分支处理它、没有 merge fold、没有 warn、没有 deferred-list 行——在所有「被解析但未兑现」的同类字段中它是唯一没有明确延期声明的(`updatedInput` → 一条 warn 日志加 [pre-tool-input-rewrite 提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md);`systemMessage` → 一条 warn 日志加 README deferred 行;`continue`/`stopReason` → 一个 `TODO(hook-continue-false)` 锚点加 `'stop'` decision 记录)。从结构上看根本无物可抑制:hook stdout 从不进入任何 transcript(文本记录)(上下文仅通过 `additionalContext` 流入;日志只记录 `decision`/`stderrSummary`),因此 hook 作者设置 `suppressOutput: true` 得到的是无声的空操作,且无任何警告。 +3. **`defaultTimeoutMs` 在两个 bridge 配置中以浮动字面量双重默认**——schema 的 `.default(600_000)` 加上一个 `?? 600_000` 回退(`packages/hooks/hooks-claude/src/index.ts`、`packages/hooks/hooks-codex/src/index.ts`),一个协议级常量在每个 bridge 中有两个归属地,两个 bridge 可能在共享默认值上悄然分歧。*提案最初的补救措施是彻底删除该旋钮,但被 no-hardcoded-tunables 审计所取代:审计保留了该旋钮作为 bridge 拥有的显式配置(并在旁边新增了 `stderrSummaryMaxChars`);剩下要修的是字面量的归属地。* +4. **`hook/result` 的语义存在于两个 bridge 中(各一份),而非拥有该事件的 lib。** `summarize()`——stderr 截断规则——在 `packages/hooks/hooks-claude/src/index.ts` 与 `packages/hooks/hooks-codex/src/index.ts` 中逐字节相同;decision 字符串规则 `output.decision ?? (output.continue === false ? 'stop' : 'pass')` 同样如此。然而 `dsh-hook-protocol` 声明了 `hook/result`、在文档中将 `stderrSummary` 描述为「已截断」却不拥有截断逻辑,记录了 decision 值却不拥有映射逻辑。如果某个 bridge 漂移(不同的上限、不同的回退),共享持久化事件的语义就会悄然分叉。 ## 决策 -`HookDialect` 是封闭的 bridge 集合,`'claude' | 'codex'`;`HookOutput` 移除不受支持的 `suppressOutput`。`hook/result.durationMs` 保留为持久化的审计计时,仅在快照中做归一化。参考默认值各只存在一处:`DEFAULT_HOOK_TIMEOUT_MS` 和 `DEFAULT_STDERR_SUMMARY_MAX_CHARS`。`HookResultRecord` 与 `appendHookResult` 为两个 bridge 统一拥有 stderr 摘要化和 decision 推导逻辑。`BLOCKING_EXIT_CODE` 为 codec 内部常量。 +`HookDialect` 是封闭的 bridge 集合:`'claude' | 'codex'`;`HookOutput` 移除了不受支持的 `suppressOutput`。`hook/result.durationMs` 保留为持久化的审计计时,仅在快照中做归一化。参考默认值各只存在一处:`DEFAULT_HOOK_TIMEOUT_MS` 与 `DEFAULT_STDERR_SUMMARY_MAX_CHARS`。`HookResultRecord` 与 `appendHookResult` 为两个 bridge 统一拥有 stderr 摘要化和 decision 推导逻辑。`BLOCKING_EXIT_CODE` 为 codec 内部常量。 ## 曾考虑的替代方案 -### 为什么不保留? +### 为什么不保留它们? -不受支持的词汇(vocabulary)可以在真正有消费方时回归。`durationMs` 保留,因为持久化的审计计时独立于当前是否有读取者而有价值。Bridge 特有的 payload 构造留在各自 bridge 中,而共享的持久化事件归一化属于协议库。 +不受支持的词汇可以在真正有消费方时回归。`durationMs` 保留,因为持久化的审计计时独立于当前是否有读取方而有价值。Bridge 特有的 payload 构造留在各自 bridge 中,而共享持久化事件的归一化属于协议库。 ## 验证 -`HookDialect` 只包含 Claude 和 Codex,`suppressOutput` 在源码、解析字段文档和归一化逻辑中均不存在。`durationMs` 保留在事件和 fixture(测试前置数据)中,回放时做擦除。`600_000` 和 `500` 默认值各只在协议库中出现一次,per-hook 超时覆盖仍然生效,两个 bridge 的测试套件都验证了库拥有的 stderr 截断和 decision 规则。 +`HookDialect` 仅包含 Claude 和 Codex,`suppressOutput` 在源码、已解析字段文档和归一化逻辑中均不存在。`durationMs` 保留在事件和 fixture(测试前置数据)中,回放时做清洗。`600_000` 和 `500` 两个默认值各只在协议库中出现一次;per-hook 超时覆盖仍然生效;两个 bridge 的测试套件均验证了由库拥有的 stderr 截断和 decision 规则。 ## 后果 -`dialect`、`suppressOutput`、可调参数与语义变更在协议格式(wire format)和 golden 文件上不可见。代价是 `dsh-hook-protocol` 和两个 bridge 的代码变动——在预发布阶段这很廉价,且比让持久化事件语义的两份副本各自老化要廉价得多。 +`dialect`、`suppressOutput`、可调参数与语义的变更在协议格式(wire format)和 golden 文件中均不可见。代价是 `dsh-hook-protocol` 与两个 bridge 的代码变动——在预发布阶段这很廉价,且比让持久化事件语义的两份副本各自老化要廉价得多。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml index f91d18a48e..aa5df52a6a 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-trim-acp-bridge-unreachable-surface.md: 6decb494dcbfd348777577002187007597a8c374 -2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: 77e22f75c96704ee0379c45d2ed23167df047324 +2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: 9d588e6f1132869ead60586b4df6844400307863 diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md index 77e22f75c9..9d588e6f11 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md @@ -1,26 +1,26 @@ -# RFC:裁剪不可达的 ACP bridge 接口——品牌旋钮与 kind 嗅探回退 - -Status: implemented +# RFC:裁剪不可达的 ACP 桥接层表面——品牌配置项与 kind 嗅探回退 [English](2026-07-04-trim-acp-bridge-unreachable-surface.md) | 中文 +Status: implemented + ## 问题 -`dsh-acp` 有两处接口在任何已交付的配置下都不可达: +`dsh-acp` 有两处对外表面在任何已交付的配置中都不可达: -1. **`AcpConfig.agentName` / `agentVersion`**(`packages/ui/acp/src/index.ts`)。已交付的 app 包(package)只向 bridge 传入 `{ model }`(`packages/examples/acp-demo/src/index.ts`),因此唯一的生产配置面——叶子 `cordis.yml`——根本无法设置这两个旋钮;它们只能通过直接挂载 bridge 来设置,而只有单元测试这样做。所有快照 golden(包括 hook-matrix 场景)都固定了 schema 默认值(`deepseek-harness-acp` / `0.0.1`)。这对字段还带着一条活跃的 `TODO(double-default)`:字面量存在两份(schema 的 `.default(...)` 加 `??` 回退),TODO 要求选定一个归属。 -2. **`toolKindFor` 名称启发式**(同一文件)在通用回退路径中对 `bash*`/`read*`/`write`/`edit*` 工具名做了特殊处理。自 [render-intent union](../architecture/2026-07-02-tool-render-intent-union.md) 以来,这些分支匹配到的每个第一方工具都自带 `presentCall` 并携带其 kind,而没有 presenter 的生产工具(`subagent`、`subagent_fork`)本来就落入 `other`。这些分支在生产中可达的唯一情况是:某个工具拒绝自行呈现其调用——`presentCall` 抛出异常(containment 回退),或模型参数未通过工具 schema 导致 `defineTool` 的 `presentCall` 包装层返回 `undefined`(例如 `bash` 调用缺少必需的 `description`)——而 bridge 自身的模块文档明确声明了该启发式所违反的设计规则:「bridge 从不对工具名做特殊处理」。 +1. **`AcpConfig.agentName` / `agentVersion`**(`packages/ui/acp/src/index.ts`)。已交付的 app 包(`packages/examples/acp-demo/src/index.ts`)只向桥接层传递 `{ model }`,因此没有任何叶子 `cordis.yml`(唯一的生产配置表面)能设置这两个配置项;它们只有通过直接挂载桥接层才能设置,而只有单元测试这样做。所有快照 golden(包括 hook-matrix 场景)都固定了 schema 默认值(`deepseek-harness-acp` / `0.0.1`)。这对字段还带着一个活跃的 `TODO(double-default)`:字面量存在两份(schema 的 `.default(...)` 加 `??` 回退),TODO 要求选定一个归属。 +2. **`toolKindFor` 名称启发式**(同一文件)在通用回退路径中对 `bash*`/`read*`/`write`/`edit*` 工具名做了特殊处理。自 [render-intent union](../architecture/2026-07-02-tool-render-intent-union.md) 以来,这些分支匹配到的每个第一方工具都自带 `presentCall` 并携带其 kind,而没有 presenter 的生产工具(`subagent`、`subagent_fork`)本来就落入 `other`。这些分支只有在工具拒绝自行呈现调用时才在生产中可达:`presentCall` 抛出异常(容错回退),或模型参数未通过工具 schema 导致 `defineTool` 的 `presentCall` 包装层返回 `undefined`(例如 `bash` 调用缺少必需的 `description`)。而桥接层自身的模块文档明确声明了该启发式所违反的设计规则:"桥接层绝不对工具名做特殊处理"。 ## 决策 -在初始化时硬编码现有的握手标识 `{ name: 'deepseek-harness-acp', version: '0.0.1' }`,移除不可达的配置字段与重复默认值。在两处 presenter 回退中,将 `toolKindFor` 替换为中性的 `'other'`。正常的第一方呈现不受影响;格式错误或失败的呈现现在渲染一张诚实的通用卡片,而非从工具名推断 kind。初始化测试和快照固定握手标识;只有 `hook-codex-posttool-block` 中格式错误的调用改变了回退卡片的 kind。 +在初始化时硬编码现有的握手标识 `{ name: 'deepseek-harness-acp', version: '0.0.1' }`,移除不可达的配置字段与重复默认值。在两个 presenter 回退处,将 `toolKindFor` 替换为中性的 `'other'`。正常的第一方呈现不受影响;格式错误或失败的呈现现在会渲染一个诚实的通用卡片,而非从工具名推断 kind。初始化测试和快照固定握手标识;只有 `hook-codex-posttool-block` 中格式错误的调用改变了回退卡片的 kind。 ## 曾考虑的替代方案 ### 为什么不保留? -品牌旋钮可以在 app 包将其暴露给部署时回归。从未知工具名推断呈现方式违反了 render-intent 契约;中性回退卡片还能为格式错误的调用和损坏的 presenter 保留原始输入。 +品牌配置可以在 app 包将其暴露给部署环境时再回来。从未知工具名推断呈现方式违反了 render-intent 契约;中性回退卡片还能为格式错误的调用和损坏的 presenter 保留原始输入。 ## 后果 -除上述回退渲染的取舍外无其他影响——退化路径下,中性卡片比推断出的第一方卡片更易于诊断。 +除上述回退渲染的取舍外没有其他影响——退化路径下,中性卡片比推断出的第一方卡片更易于诊断。 diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml index b423b59448..593cb8a50e 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-12-drop-unconsumed-skill-provider-events.md: 5ec9d201939b8f58334647353f599361bd2e58a0 -2026-07-12-drop-unconsumed-skill-provider-events.zh.md: 8ab2a5f55b2a1eed676b28a1ca7804d6237f63fd +2026-07-12-drop-unconsumed-skill-provider-events.zh.md: 15dbfedb07afa36b677074c403812d0f164c8bd5 diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md index 8ab2a5f55b..15dbfedb07 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md @@ -1,29 +1,29 @@ # RFC:移除无消费方的 skill 提供方事件 -Status: implemented - [English](2026-07-12-drop-unconsumed-skill-provider-events.md) | 中文 +Status: implemented + ## 问题 -skill(技能)注册表产出了两个通知事件,但在生产代码中没有任何监听方。生成的生产者/消费方矩阵以及精确的事件名搜索表明,`skill/provider-added` 和 `skill/provider-removed` 只出现在声明、发射点、测试、生成目录和行文中。 +skill(技能)注册表产出两个通知事件,但没有生产环境的监听方。生成的生产者/消费方矩阵以及对事件名的精确搜索表明,`skill/provider-added` 与 `skill/provider-removed` 仅出现在声明、emit 站点、测试、生成的 catalog 和行文中。 -skill 发现按需读取当前提供方映射表,提供方注册同步清除已完成的目录缓存,await 后的修订检查防止陈旧的发现结果进入缓存。没有兄弟插件通过这些事件等待 skill 提供方,不同于 `subagent/provider-added` 的实际消费方(它容忍兄弟并发加载)。 +skill 发现按需读取当前的提供方映射表,提供方注册时同步清除已完成的 catalog,而 await 后的版本检查阻止了陈旧的发现结果进入缓存。没有兄弟插件通过这些事件等待 skill 提供方——与之形成对比的是活跃的 `subagent/provider-added` 消费方,它容忍兄弟并发加载。 -`tools/change` 和 `system-prompt/change` 明确不在本提案范围内。既有的简化决策将它们保留为面向实时工具和提示词 UI 的有意观测点,且自引用的已挂载插件已在使用 `tools/change`。本提案同样不改动 `subagent/provider-added`/`removed`,因为 `tool-subagent` 有生产级的生命周期消费方。 +`tools/change` 与 `system-prompt/change` 明确不在本提案范围内。既有的简化决策将它们保留为面向实时工具和提示词 UI 的有意观测点,且自引用的已挂载插件已在使用 `tools/change`。本提案同样不改动 `subagent/provider-added`/`removed`,因为 `tool-subagent` 有生产环境的生命周期消费方。 ## 决策 -skill 注册表不再声明和发射提供方成员变更事件。提供方的注册与 dispose(资源释放)仍为 effect 拥有的直接状态变更,同步使已完成的目录缓存失效;查找与发现按需读取当前提供方映射表。测试通过提供方查找和收集的输出来观察清理行为,而非生命周期通知。 +skill 注册表不再声明和 emit 提供方成员变更事件。提供方的注册与 dispose(资源释放)仍为 effect 所有的直接状态变更,同步使已完成的 catalog 失效;查找与发现按需读取当前提供方映射表。测试通过提供方查找和收集到的输出来观察清理行为,而非依赖生命周期通知。 -生成的事件目录、API 目录与生产者/消费方矩阵不再包含已删除的通知。skill 系统 RFC 和包文档通过 effect 拥有的直接状态及缓存失效契约来描述注册行为。 +生成的事件 catalog、API catalog 与生产者/消费方矩阵不再包含已删除的通知。skill 系统 RFC 与包文档通过 effect 所有的直接状态及缓存失效契约来描述注册行为。 ## 曾考虑的替代方案 -**为未来插件保留 skill 提供方通知。** 第三方插件可能想观察提供方的可用性,但直接提供方注册与按需查找才是扩展契约;当前没有消费方需要推送信号。如果未来出现兄弟加载竞态,可以像 subagent 注册表那样引入一个带有该消费方实际所需的身份与就绪语义的通知。 +**为未来插件保留 skill 提供方通知。** 第三方插件可能想观察提供方的可用性,但直接提供方注册与按需查找才是扩展契约;当前没有消费方需要推送信号。如果将来出现兄弟加载竞态,可以像 subagent 注册表那样,引入一个带有该消费方实际所需的身份与就绪语义的通知。 ## 后果 -生成的事件矩阵中不再有 `skill/provider-added` 或 `skill/provider-removed` 的行。skill 发现、直接运行时注册、提供方 effect 回滚/dispose、缓存失效与注册表查找清理均保留;随事件一起消失的是监听器触发的回滚。`tools/change`、`system-prompt/change` 以及已被消费的 subagent 提供方生命周期事件不受影响。 +生成的事件矩阵中不再有 `skill/provider-added` 或 `skill/provider-removed` 的行。skill 发现、直接运行时注册、提供方 effect 回滚/dispose、缓存失效与注册表查找清理保持不变;监听方触发的回滚随事件一起消失。`tools/change`、`system-prompt/change` 以及已被消费的 subagent 提供方生命周期事件不受影响。 -预发布消费方失去 skill 提供方观测点,但仍保留贡献 skill 的两种方式:直接运行时注册与提供方注册。未来若有消费方需要实时的提供方可用性信息,须新增一个带有其实际所需的身份与就绪语义的专用通知。 +预发布消费方失去 skill 提供方观测点,但仍保留两种贡献 skill 的方式:直接运行时注册与提供方注册。未来若有消费方需要实时的提供方可用性信息,必须新增一个带有其实际所需的身份与就绪语义的专用通知。 diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml index 6c0c1f9108..7413576228 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-12-prune-unused-web-seam-fields.md: b4773c2706cf6d18ea4bb96720cd6c932cdf8942 -2026-07-12-prune-unused-web-seam-fields.zh.md: 1beb9e597c4b990f2c4aaaf3e34e71027c3f3fb7 +2026-07-12-prune-unused-web-seam-fields.zh.md: 2c18fbcb440ce85798c8f36cdc5dc649149d8ba9 diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md index 1beb9e597c..2c18fbcb44 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md @@ -1,27 +1,27 @@ # RFC:裁剪 web seam 中未使用的字段 -Status: implemented - [English](2026-07-12-prune-unused-web-seam-fields.md) | 中文 +Status: implemented + ## 问题 -web 能力携带了一组 request/result/status 值,每个已交付的实现都填充了它们,但没有生产消费方读取。`WebSearchResult.providerId`、`query` 和 `WebFetchResult.providerId` 是结果回显;`tool-web` 只格式化 content/sources/truncation 或 final URL/status/body/truncation,其他运行时也不读取这些字段。搜索提供方返回 `WebProviderStatus.reason`,但可用性检查只看 `available`,并有意输出一条通用的不可用诊断。 +web 能力携带的 request/result/status 值,虽然每个已交付的实现都会填充,但没有任何生产环境的消费方读取它们。`WebSearchResult.providerId`、`query`与 `WebFetchResult.providerId` 是结果回显;`tool-web` 只格式化 content/sources/truncation 或最终 URL/status/body/truncation,没有其他运行时读取这些字段。搜索提供方返回 `WebProviderStatus.reason`,但可用性检查只看 `available`,并有意输出一条通用的不可用诊断信息。 -`WebFetchRequest.timeoutMs` 同样没有生产调用方设置。`tool-web` 只提供 URL,用工具定义的超时加 `exec.signal` 作为调用方截止时间,并依赖本地提供方的配置默认值作为兜底。这个未使用的按请求超时覆盖迫使 `web-fetch-local` 暴露 `maxTimeoutMs`、钳位两个超时源,并为没有产品路径能选中的优先级规则编写文档和测试。`WebExecContext` 则是另一个单字段包装层:每个调用方分配 `{ signal }`,每个提供方立即解包 `exec?.signal`;不存在第二个执行控制字段。 +`WebFetchRequest.timeoutMs` 同样从未被生产调用方设置。`tool-web` 只提供 URL,使用工具定义的 timeout 加 `exec.signal` 作为调用方截止时间,并依赖本地提供方的配置默认值作为兜底。这个未使用的逐请求覆盖迫使 `web-fetch-local` 暴露 `maxTimeoutMs`、对两个 timeout 来源做 clamp,并为没有任何产品路径能选中的优先级规则编写文档和测试。`WebExecContext` 则是另一个单字段包装层:每个调用方分配 `{ signal }`,每个提供方立即解包 `exec?.signal`;不存在第二个执行控制字段。 ## 决策 -web seam 省略搜索/抓取的 `providerId` 结果回显和搜索 `query` 回显;调用方本身已持有请求和提供方选择信息。提供方以返回布尔值的方法暴露可用性。抓取请求不再有按请求超时或 `maxTimeoutMs` 钳位;本地提供方保留其可配置的默认超时,工具保留自身的截止时间。提供方方法接收一个直接的可选 `AbortSignal`,而非单字段的 `WebExecContext` 包装层。 +web seam 移除搜索/抓取结果中的 `providerId` 回显和搜索的 `query` 回显;调用方本身已持有请求和提供方选择信息。提供方以返回布尔值的方法暴露可用性。抓取请求不再有逐请求 timeout 或 `maxTimeoutMs` clamp;本地提供方保留其可配置的默认 timeout,工具保留自身的截止时间。提供方方法直接接收一个可选的 `AbortSignal`,而非单字段的 `WebExecContext` 包装层。 -所有 web 实现和面向模型的工具使用更小的契约。接口/实现/消费方的包拆分、提供方选择、来源引用、最终 URL/状态数据、截断报告与安全限制保持不变。 +所有 web 实现与面向模型的工具使用更精简的契约。接口/实现/消费方的包(package)拆分、提供方选择、来源引用、最终 URL/状态数据、截断报告与安全限制保持不变。 ## 曾考虑的替代方案 -**保留自描述结果、按请求截止时间和可扩展的执行上下文对象。** 结果回显可以帮助通用遥测,请求超时可以帮助受信的编程调用方,包装层对象为未来的控制留出空间。但这样的消费方或第二字段并不存在;在每个提供方中携带重复的身份信息、第二套截止时间策略以及包装/解包管道,使当前契约更难实现和解释。如果遥测或按调用的预算控制到来,它应当定义哪个截止时间获胜、在哪里观测提供方身份,以及多个控制是否足以证明上下文对象的存在。 +**保留自描述结果、逐请求截止时间与可扩展的执行上下文对象。** 结果回显可以帮助通用遥测,请求级 timeout 可以帮助受信的程序化调用方,包装层则为未来的控制字段留出空间。但目前不存在这样的消费方或第二个字段;在每个提供方中携带重复的身份标识、第二套截止时间策略以及包装/解包管道,使当前契约更难实现和解释。如果遥测或逐调用预算控制到来,届时应当定义哪个截止时间优先、在哪里观测提供方身份,以及多个控制字段是否足以证明需要一个上下文对象。 ## 后果 -保留下来的每个 web request/result 字段都被生产代码消费或为执行提供方请求所必需。工具可见的搜索/抓取输出、提供方回退、中止行为、配置的超时兜底、截断与引用仍被覆盖,无需请求超时优先级分支或执行上下文包装层。 +保留下来的每个 web request/result 字段,要么被生产代码消费,要么是执行提供方请求所必需的。工具可见的搜索/抓取输出、提供方回退、中止行为、可配置的 timeout 兜底、截断与引用仍然被覆盖,无需请求级 timeout 优先级分支或执行上下文包装层。 -预发布的编程调用方失去结果来源回显和按请求的抓取截止时间。提供方仍有部署可配置的超时并尊重取消信号,因此这次精简移除的是可配置性而非安全边界。 +预发布阶段的程序化调用方失去了结果来源回显和逐请求的抓取截止时间。提供方仍具备部署级可配置 timeout 并尊重取消信号,因此这次精简移除的是可配置性,而非安全边界。 diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml index 34850593d6..cc2bf1f23f 100644 --- a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-property-based-testing.md: 169989746ea5114b1f35e7ebe35a02e8aeb0f782 -2026-06-11-property-based-testing.zh.md: 9e1532c02bb2c46c40577af7275d6aabbb2f9a4f +2026-06-11-property-based-testing.zh.md: 4f2303010f44279c4edd0ec5a509b71f8aad606b diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md index 9e1532c02b..4f2303010f 100644 --- a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md @@ -4,26 +4,26 @@ Status: implemented [English](2026-06-11-property-based-testing.md) | 中文 -> 将原始提案与决策记录合并为一篇。首次运行即发现了 BlockAssembler 的重复 `block-end` 真实 bug。 +> 将原始提案与同一主题的决策记录合并为一篇。首次运行即发现了 BlockAssembler 重复 `block-end` 的真实 bug。 ## 问题 -基于示例的测试只能固定我们想到的用例。harness 的核心是协议形态的代码:分片流、事件日志、schema 转换、收件箱调度。这类代码的输入空间是组合爆炸的,有趣的 bug 藏在没人写过示例的交错序列里。佐证:一个 block 组装的排序 bug 曾在 happy path 100% 行覆盖率下存活。逐文件 100% 覆盖率只能证明每行都跑过,不能证明每种交错都正确。 +基于示例的测试只能固定我们想到的用例。harness 的核心是协议形态的代码:分片流、事件日志、schema 转换、收件箱调度。这些场景的输入空间是组合式的,有趣的 bug 藏在没人写过示例的交错序列中。佐证:一个块组装的排序 bug 曾在 happy path 100% 行覆盖率下存活。逐文件 100% 覆盖率证明每一行都跑过了,但不能证明每种交错都是正确的。 ## 决策 -引入 `fast-check`(根 devDependency),在每个协议形态的包中编写一个 `tests/properties.spec.ts`。生成器调优为*逼真但对抗性*的输入(而非均匀噪声),`numRuns` 控制在本地套件总耗时远低于约 10 秒。失败时打印可复现的 seed。(原始提案还草拟了一个夜间 CI job,以 100 倍迭代运行;该部分未交付——属性测试套件仅在常规 `push`/`pull_request` CI 中运行,定时高迭代 job 仍属可能的后续工作。) +引入 `fast-check`(作为根 devDependency),在每个协议形态的包(package)中编写一个 `tests/properties.spec.ts`。生成器调优为*逼真但对抗性*的输入(而非均匀噪声),`numRuns` 控制在本地套件总耗时远低于约 10 秒。失败时打印可复现的 seed。(原始提案还草拟了一个夜间 CI job,以 100 倍迭代运行;该部分未交付。属性测试套件仅在常规的 `push`/`pull_request` CI 中运行,定时高迭代 job 仍属可能的后续工作。) -- **dsh-llm / BlockAssembler:** 任意分片流(合法 + 畸形:重复索引、滞后分片、缺少 block-start)。不变式:`blocks()` 数量 ≤ 出现过的不同索引数;重组幂等(`blocks()` 在重复调用间稳定,且 `message().content` 与之一致);`blocks()` 从不抛异常且只产出合法的 content-block 标签;`finish` 反映最后一个 `finish` 分片,无 `finish` 分片时默认为 `{kind:'stop'}`。 -- **dsh-session:** 任意事件日志。不变式:`deriveMessages` 确定性;从 seed 回放结果一致;seq 严格单调递增;非消息事件不影响派生历史;派生内容与日志解耦。 -- **dsh-tools:** 任意 `SchemaSpec`。不变式:JSON Schema 的 `required` 等于每层 `required:true` 的键集合;转换是全函数;**并且与[运行时参数校验](../architecture/2026-06-11-runtime-arg-validation.md)组合验证**——满足 spec 的生成参数通过 `validateArgs`,定向破坏(删除 required 键、顶层非 object)被拒绝。这封堵了 validator 与 `InferArgs` 漂移的风险。 -- **dsh-agent-loop:** 任意发送调度,对接一个永不耗尽的适配器,通过 `agent/status` settle 信号驱动(无挂钟 sleep)。不变式:无消息丢失;轮次编号严格递增;状态转换始终在合法状态机上。 +- **dsh-llm / BlockAssembler:** 任意分片流(合法 + 畸形:重复索引、滞后分片、缺少 block-start)。不变式:`blocks()` 计数 ≤ 已见到的不同索引数;重组幂等(`blocks()` 在重复调用间稳定,且 `message().content` 与之一致);`blocks()` 从不抛异常且仅产出合法的 content-block 标签;`finish` 反映最后一个 `finish` 分片,无 `finish` 分片时默认为 `{kind:'stop'}`。 +- **dsh-session:** 任意事件日志。不变式:`deriveMessages` 确定性;从 seed 回放结果一致;seq 严格单调递增;非消息事件不影响推导出的历史;推导出的内容与日志解耦。 +- **dsh-tools:** 任意 `SchemaSpec`。不变式:JSON Schema 的 `required` 等于每一层 `required:true` 的键集;转换是全函数;**并且与[运行时参数校验](../architecture/2026-06-11-runtime-arg-validation.md)组合验证**——满足 spec 的生成参数通过 `validateArgs`,而定向破坏(删除必填键、顶层非对象)被拒绝。这封堵了 validator 与 `InferArgs` 漂移的风险。 +- **dsh-agent-loop:** 任意发送调度,对接一个永不耗尽的适配器,通过 `agent/status` settle 信号驱动(无挂钟 sleep)。不变式:无消息丢失;轮次编号严格递增;状态转换保持在合法状态机上。 ## 后果 -- 生成器质量是价值杠杆——生成器偏向小索引池和短字符串,使碰撞与交错频繁出现。 -- **已经产出回报:** BlockAssembler 的流测试发现了一个真实 bug——同一索引的重复 `block-end` 覆写了已刷出的块,导致流式前缀与最终 `blocks()` 不一致。已修复(首次关闭生效,与既有的滞后分片规则一致),并附带专门的回归测试。 -- 属性测试因超时而 flake 是一个发现,不应重试了事。agent loop 的属性测试在设计上是确定性的(通过 `agent/status` settle),因此挂起即为真实缺陷。 -- 属性测试是示例测试的补充而非替代;示例测试固定特定分支,服务于 100% 覆盖率门禁。 +- 生成器质量是价值杠杆——生成器偏向小索引池和短字符串,使碰撞与交错频繁发生。 +- **已经产出回报:** BlockAssembler 流测试发现了一个真实 bug——同一索引的重复 `block-end` 覆盖了已刷出的块,导致流式前缀与最终 `blocks()` 不一致。已修复(首次关闭生效,与既有的滞后分片规则一致),并附带一个专门的回归测试。 +- 属性测试因超时而 flake 是一个发现,不应通过重试消除。循环属性测试在设计上是确定性的(通过 `agent/status` settle),因此挂起即为真实缺陷。 +- 属性测试是对示例测试的补充而非替代;示例测试固定特定分支,服务于 100% 覆盖率门禁。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml index 8014cd6b63..1dfb26a628 100644 --- a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-19-acp-snapshot-tests.md: 0b93c99932a33bca9945dd88ce45f4a1e100ccfc -2026-06-19-acp-snapshot-tests.zh.md: dc0aeb102039d3261ad6bbbb21321ca2b6ef5ec3 +2026-06-19-acp-snapshot-tests.zh.md: 26c583ba47b8ec10ab3d0e2102a8b791549fda38 diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md index dc0aeb1020..26c583ba47 100644 --- a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md @@ -6,11 +6,11 @@ Status: implemented ## 问题 -单元测试无法覆盖完整的 ACP 子进程 transcript(文本记录),而真实 API 测试既不确定又依赖密钥。因此,面向编辑器的 `session/update` 输出可能在单元覆盖率全绿的情况下发生回归,正如 [default-export 事后分析](../../../postmortem/0001-acp-default-export-drops-inject.md)所展示的那样。 +单元测试无法覆盖完整的 ACP(Agent Client Protocol)子进程 transcript(文本记录),而真实 API 测试既不确定又需要密钥。因此,面向编辑器的 `session/update` 输出可能在单元覆盖率全绿的情况下发生回归,正如 [default-export 事后分析](../../../postmortem/0001-acp-default-export-drops-inject.md)所揭示的那样。 -全 transcript 测试的阻塞点在于模型:agent(智能体)的输出由非确定性的 LLM(大语言模型)驱动,而每次运行都命中真实 API 的密钥门控测试既不确定也无法在 CI 中运行。我们需要真实运行的保真度,同时具备 fixture(测试前置数据)的确定性。 +全 transcript 测试的阻塞因素在于模型:agent 的输出由非确定性的 LLM(大语言模型)驱动,而每次运行都命中真实 API 的密钥门控测试既不确定也无法在 CI 中运行。我们需要真实运行的保真度与 fixture(测试前置数据)的确定性兼得。 -本 RFC 记录了添加第三层测试——**快照测试**——的决策,以及使其确定、CI 中无需密钥且维护成本低的设计选择。 +本 RFC 记录了新增第三层测试——**快照测试**——的决策,以及使其具备确定性、CI 中无需密钥、维护成本低的设计选择。 ## 决策 @@ -18,11 +18,11 @@ Status: implemented ### fixture 即持久化的会话 JSONL -每个场景的 `session.jsonl` 从一次真实运行中采集。`assistant/chunk` 事件重现模型流;工具、消息和边界事件捕获 harness 行为。一份普通的会话产物因此同时充当回放源和行为 golden。 +每个场景的 `session.jsonl` 从一次真实运行中采集。`assistant/chunk` 事件重现模型流;tool、message 和 boundary 事件捕获 harness 行为。一份普通的会话产物因此同时充当回放源和行为 golden。 ### 回放从日志推导模型脚本 -`llm-replay` 短路了提供方无关的 `llm/stream` waterfall(瀑布式事件)。`deriveReplayScript()` 按 `(turn, step)` 对已录制的 chunk 分组,每次模型调用服务一组。循环每步发起一次流调用,因此分组是精确的,且无需特殊处理即可包含 error finish chunk。 +`llm-replay` 短路了提供方无关的 `llm/stream` waterfall(瀑布式事件)。`deriveReplayScript()` 按 `(turn, step)` 对已录制的 chunk 分组,每次模型调用服务一组。agent loop(智能体循环)每个 step 发起一次流调用,因此分组精确对应,错误结束 chunk 也无需特殊处理。 ### 内存中的回放条目遵守完整的 LLM 契约 @@ -34,32 +34,32 @@ Status: implemented | { kind: 'hang' } ``` -日志推导出 chunk 条目。流开始前的抛出和挂起没有可重建的 chunk 表示,因此这些场景提供 `replay.override.json`。throw 条目可以包含前缀 chunk 以表示流中途失败。显式覆盖避免了从有损的 turn-end reason 推断适配器行为。 +日志推导出 chunk 条目。流开始前的抛出和挂起没有可重建的 chunk 表示,因此这些场景提供 `replay.override.json`。throw 条目可以包含前缀 chunk 以模拟流中途失败。显式覆盖避免了从有损的轮次结束原因推断适配器行为。 ### 位置式回放,单个在途流 -回放是位置式的,因此每个场景只允许一个在途模型流。并发会话快照需要按请求键索引的条目。调用顺序变化需要重新录制,fixture 缺失或耗尽时会大声失败。 +回放是位置式的,因此每个场景只允许一个在途模型流。并发会话快照需要按请求键索引的条目。调用顺序变更需要重新录制,fixture 缺失或耗尽时立即报错。 ### 录制采集日志;无密钥回放需要无提供方的配置 -录制使用真实的 `llm-deepseek` 适配器和 JSONL 持久化后端运行场景,然后将产出的 `.jsonl` 复制到场景目录。逐事件追加是持久的,但 harness 在采集前会优雅关闭子进程(关闭 stdin → `await ctx.dispose()`),确保最终事件已刷出。`llm-replay` 本身不做录制——它只负责回放。 +录制使用真实的 `llm-deepseek` 适配器和 JSONL 持久化后端运行场景,然后将产出的 `.jsonl` 复制到场景目录。逐事件追加是持久的,但 harness 在采集前会优雅关闭子进程(关闭 stdin → `await ctx.dispose()`),确保最终事件已刷盘。`llm-replay` 本身不做录制,它只负责回放。 -回放使用 `cordis.snapshot.yml` 覆盖层,将真实适配器替换为 `llm-replay`,同时保留活跃的组合。录制使用普通配置和 harness 提供的持久化根目录。回放模式跳过 `.env` 加载,因此一个意外存在的 API key 不会触发真实调用。见[单一源配置 RFC](2026-07-04-single-source-acp-replay-config.md)。 +回放使用 `cordis.snapshot.yml` 覆盖配置,将真实适配器替换为 `llm-replay`,同时保留活跃的组合。录制使用普通配置和 harness 提供的持久化根目录。回放模式跳过 `.env` 加载,因此一个意外存在的 API key 不会触发真实调用。见[单源配置 RFC](2026-07-04-single-source-acp-replay-config.md)。 ### 两个表面:归一化后比对 快照运行断言**两个**归一化后的表面,因为 harness 的外部表面是不同的: -1. **stdout transcript**——编辑器看到的帧化 `session/update` JSON-RPC。捕获 ACP bridge 的事件→update 转换(`streamSessionEventUpdate`)中的回归。与已提交的 `stdout.golden.jsonl` 比对。 -2. **重新持久化的会话 JSONL**,归一化后与 `session.jsonl` 比对。同一份 fixture 既是回放源也是期望日志。提示词文本被擦除;每个 header 类别一个场景固定可读的 prompt 和工具内容,见 [header-pinning RFC](2026-07-06-pin-request-header-content-in-one-scenario.md)。覆盖场景的模型行为完全来自其伴随记录。 +1. **stdout transcript**——编辑器看到的带帧 `session/update` JSON-RPC。捕获 ACP bridge 事件→update 转换(`streamSessionEventUpdate`)中的回归。与已提交的 `stdout.golden.jsonl` 比对。 +2. **重新持久化的会话 JSONL**,归一化后与 `session.jsonl` 比对。同一份 fixture 既是回放源也是预期日志。提示词文本被擦除;每个 header 类别一个场景固定可读的 prompt 和 tool 内容,见 [header-pinning RFC](2026-07-06-pin-request-header-content-in-one-scenario.md)。覆盖场景的模型行为完全来自其伴随文件。 -两个表面互补:stdout 覆盖 bridge 投影,JSONL 覆盖投影所省略的循环、工具和边界结构。 +两个表面互补:stdout 覆盖 bridge 投影,JSONL 覆盖投影所省略的 loop、tool 和 boundary 结构。 -归一化替换会话 ID、cwd、protocol-id、时间戳、路径和进程易变值,同时保留确定性序列号。场景将真实 bash 使用限制在稳定命令上。stdout golden 保持协议格式(wire format)的 JSONL,每行原始数据必须能解析为 JSON。Vitest 只更新 stdout golden;归一化后的会话相等性检查从不覆写回放 fixture。 +归一化替换 session、cwd、protocol-id、时间戳、路径和进程相关的易变值,同时保留确定性序列号。场景将真实 bash 使用限制在稳定命令范围内。stdout golden 保持协议格式(wire format)的 JSONL,每一行原始数据必须可解析为 JSON。Vitest 只更新 stdout golden;归一化后的会话相等性检查从不覆盖回放 fixture。 -### 隔离:当前靠归一化,后续可沙箱 +### 隔离:当前靠归一化,后续可加沙箱 -工具确定性来自临时 cwd、擦除的环境变量、全新的非登录 shell、受限命令和归一化。它不声称具备 OS 级隔离。如果需要更强的层级,沙箱执行器可以通过既有的[能力 seam](../architecture/2026-06-13-capability-seams.md) 替换本地后端。 +工具的确定性来自临时 cwd、擦除的环境变量、全新的非登录 shell、受限命令和归一化。它不声称具备操作系统级隔离。如果需要更强的隔离层级,可通过既有的[能力 seam](../architecture/2026-06-13-capability-seams.md) 将沙箱执行器替换本地后端。 ### 回放插件是独立的包 @@ -67,16 +67,16 @@ Status: implemented ### 两个子命令,回放在默认门禁中 -`pnpm run test:snapshot` 无密钥回放已提交的 fixture;`test:snapshot:record` 使用真实 API 并重写采集到的会话日志和 stdout golden。fixture 缺失时大声失败。每个场景携带 `input.json`、`stdout.golden.jsonl` 和 `session.jsonl`;无模型场景使用仅含 header 的日志。`replay.override.json` 仅在标记为 `overridden` 的场景中必需,因为它的存在会替换推导出的回放。fixture 守卫拒绝缺失、不匹配和遗留的文件。两个命令都接受场景过滤器。 +`pnpm run test:snapshot` 无需密钥地回放已提交的 fixture;`test:snapshot:record` 使用真实 API 并重写采集到的会话日志和 stdout golden。fixture 缺失时立即报错。每个场景携带 `input.json`、`stdout.golden.jsonl` 和 `session.jsonl`;无模型场景使用仅含 header 的日志。`replay.override.json` 仅在标记为 `overridden` 的场景中必需,因为它的存在会替换推导出的回放。fixture 守卫拒绝缺失、不匹配和遗留的文件。两个命令均接受场景过滤器。 ## 曾考虑的替代方案 -- **手写的模型 chunk `llm.json`**:早期草案;复用真实会话日志使 fixture 成为系统的真实产物而非手工构建的 mock,并兼作行为 golden。 -- **字节级 HTTP 录制库(Polly/nock/MSW)**:否决。适配器相关、与流式 SSE 配合笨拙,且层级低于被测对象。 -- **从 `turn/end {kind:'error'|'aborted'}` 合成 throw/cancel 条目**:否决。这会将 `llm-replay` 耦合到循环内部的 turn 关闭语义,且 `turn/end` reason 是有损的(无法区分抛出的 401 和 finish-error);显式的 `replay.override.json` 伴随记录是更干净的 seam。 +- **手工编写的模型 chunk `llm.json`**:早期草案的做法。复用真实会话日志使 fixture 成为系统的真实产物而非手工构建的 mock,并兼作行为 golden。 +- **字节级 HTTP 录制库(Polly/nock/MSW)**:否决。与适配器耦合,处理流式 SSE(Server-Sent Events)时笨拙,且层级低于被测对象。 +- **从 `turn/end {kind:'error'|'aborted'}` 合成 throw/cancel 条目**:否决。这会将 `llm-replay` 耦合到 loop 内部的轮次关闭语义,且 `turn/end` 原因是有损的(无法区分抛出的 401 与 finish-error);显式的 `replay.override.json` 伴随文件是更清晰的 seam。 ## 后果 -新层级为每个场景添加经评审的 input、session、stdout、可选 override 和可选 workspace fixture。workspace 种子在录制和回放时都被复制到临时 cwd。作为回报,该层级通过真实的 Loader 和工具组合提供确定性的无密钥 transcript 覆盖。子进程、input、workspace、归一化和回放 harness 可以支持 ACP 以外的示例。 +新测试层为每个场景增加了经评审的 input、session、stdout、可选 override 和可选 workspace fixture。workspace 种子在录制和回放时都会被复制到临时 cwd。作为回报,该层通过真实的 Loader 和 tool 组合提供确定性的无密钥 transcript 覆盖。子进程、input、workspace、归一化和回放 harness 可以支持 ACP 之外的示例。 -本 RFC 与[拟议的确定性 RFC](../../proposed/testing/2026-06-11-deterministic-and-stress-testing.md) 相关但不取代它:该提案的「通用回放 fixture」在每次测试后重新推导会话*消息历史*(一个内部一致性不变式),而快照测试固定的是*外部协议输出*。二者互补:一个守护事件溯源不变式,另一个守护面向编辑器的契约。 +本 RFC 与[拟议的确定性 RFC](../../proposed/testing/2026-06-11-deterministic-and-stress-testing.md) 相关但不取代它:该提案的「通用回放 fixture」在每次测试后重新推导会话的*消息历史*(一项内部一致性不变式),而快照测试固定的是*外部协议输出*。二者互补:一个守护事件溯源不变式,另一个守护面向编辑器的契约。 diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml index fadd3e4a52..591f51750a 100644 --- a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-19-real-api-e2e-ci.md: 3b5995a3e060ef9b4b1639b5c7fb17c819e73150 -2026-06-19-real-api-e2e-ci.zh.md: 4d4b38cd5989426482b773da79b3a44cec90f747 +2026-06-19-real-api-e2e-ci.zh.md: 78bab7c1e00125bfbe11b8f08eeeff3f2b7723b1 diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md index 4d4b38cd59..78bab7c1e0 100644 --- a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md @@ -1,100 +1,100 @@ # RFC:在 CI 中对外部 DeepSeek API 运行真实 API e2e 测试 -Status: implemented - [English](2026-06-19-real-api-e2e-ci.md) | 中文 +Status: implemented + ## 问题 -按照既定策略,harness 高度依赖真实 API 测试:[docs/testing.md](../../../testing.md) 论证了无密钥测试套件只能验证管道连通性而非产品行为,[ACP inject 事后分析](../../../postmortem/0001-acp-default-export-drops-inject.md)是现成的证据——178 个无密钥测试全绿,而真实编辑器会话一启动就崩溃。真实 API e2e 套件(`pnpm run test:e2e`,即 `*.e2e.ts` 文件)正是为了弥合这一缺口:它驱动 agent 对接线上 DeepSeek API——真实模型调用、真实 bash 工具、多轮对话、恢复、ACP-over-stdio。 +按照策略,harness 高度依赖真实 API 测试:[docs/testing.md](../../../testing.md) 论证了无密钥套件只能验证管道连通性而非产品本身,[ACP inject 事后分析](../../../postmortem/0001-acp-default-export-drops-inject.md)是现成的证据——178 个无密钥测试全绿,而真实编辑器会话一启动就崩溃。真实 API e2e 套件(`pnpm run test:e2e`,即 `*.e2e.ts` 文件)正是为弥合这一差距而存在的:它驱动 agent(智能体)对接实时 DeepSeek API——真实模型调用、真实 bash 工具、多轮次对话、恢复、ACP-over-stdio。 -默认门禁([.github/workflows/ci.yml](../../../../.github/workflows/ci.yml))刻意不携带密钥:它不含 secret,可供 fork 运行。`test:e2e` 在无密钥时自动跳过(`describe.skipIf(!process.env.DEEPSEEK_API_KEY)`),因此把它加到 ci.yml 只会报绿而不会真正执行真实套件。要让真实 API 覆盖率成为合并信号,需要一个独立的、携带 secret 的工作流。 +默认门禁([.github/workflows/ci.yml](../../../../.github/workflows/ci.yml))刻意无密钥:不携带 secret,可供 fork 运行。`test:e2e` 在无密钥时自动跳过(`describe.skipIf(!process.env.DEEPSEEK_API_KEY)`),因此将其加入该工作流只会报绿而不会真正执行真实套件。要让真实 API 覆盖率成为合并信号,需要一个独立的、携带 secret 的工作流。 -本 RFC 记录的决策是:新增一个**第二个、消费 secret 的工作流**来在 CI 中运行真实 API 套件。同时,由于这是向一个未来可能公开的仓库引入首个 CI secret,属于安全/隔离决策,本文一并记录其依赖的威胁模型以及仓库公开后会发生什么变化。 +本 RFC 记录的决策是:添加一个**第二个、消费 secret 的工作流**来在 CI 中运行真实 API 套件。由于这是向一个未来可能公开的仓库引入首个 CI secret,属于安全/隔离决策,本文同时记录其依赖的威胁模型以及仓库公开后的变化。 ## 决策 -新增专用工作流 [.github/workflows/e2e.yml](../../../../.github/workflows/e2e.yml),与 ci.yml 分离。它仅在受信事件上使用仓库 secret 对外部 API 运行 `pnpm run test:e2e`,并设有预检步骤:secret 缺失时以显式失败替代假绿。无密钥工作流保持独立,使可 fork 的质量门禁与消费 secret 的真实 API 门禁各自拥有不同的触发和凭证策略。 +添加一个专用工作流 [.github/workflows/e2e.yml](../../../../.github/workflows/e2e.yml),与 ci.yml 分离。它仅使用 repo secret 对外部 API 运行 `pnpm run test:e2e`,仅在可信事件上触发,并带有一个 preflight 检查:将缺失的 secret 转化为明确的失败而非虚假的绿色。无密钥工作流保持独立,使可 fork 的质量门禁与消费 secret 的真实 API 门禁各自拥有不同的触发和凭证策略。 ### 独立工作流,而非 ci.yml 中的一个 job -ci.yml 的价值在于它无密钥、可 fork、始终绿色:任何贡献者(包括外部 fork)都能获得完整的无密钥信号,secret 不在其爆炸半径内。在那里添加消费 secret 的 job 会将这个始终绿色的门禁耦合到凭证可用性和不同的触发策略上。将携带 secret 的工作放在独立文件中,隔离了 secret、触发和并发策略,并为 fork 保留了 ci.yml 的特性。不同的生命周期 → 不同的文件。 +ci.yml 的价值在于它无密钥、可 fork、始终为绿:任何贡献者(包括外部 fork)都能获得完整的无密钥信号,secret 不在爆炸半径内。在其中添加消费 secret 的 job 会将这个始终为绿的门禁耦合到凭证可用性和不同的触发策略上。将携带 secret 的工作放在独立文件中,隔离了 secret、触发和并发策略,并为 fork 保留了 ci.yml 的特性。不同的生命周期→不同的文件。 -### 成本不是约束,可靠性才是 +### 约束不是成本,而是可靠性 -内部推理成本不是限制因素,因此工作流以覆盖率和信号为优化目标。它在多种触发条件和每个受信 PR 上运行所有匹配的 `*.e2e.ts` 文件,落实 [docs/testing.md](../../../testing.md) 的 with-key 策略。 +内部推理(inference)成本不是限制因素,因此工作流以覆盖率和信号为优化目标。它在多个触发条件和每个可信 PR(Pull Request)上运行所有匹配的 `*.e2e.ts` 文件,落实 [docs/testing.md](../../../testing.md) 的有密钥策略。 -### 触发条件:仅受信事件 +### 触发条件:仅限可信事件 -`workflow_dispatch` + `push` 到 `main`/`master` + 每日定时 `schedule`(`17 0 * * *`,即北京时间 08:17)+ `pull_request`。push 提供合并后信号;schedule 捕获外部 API 漂移;dispatch 是手动逃生口;受信 pull request 获得合并前门禁。该合并前信号有意接受 § 安全性 中描述的更大密钥暴露面。 +`workflow_dispatch` + `push` 到 `main`/`master` + 每夜 `schedule`(`17 0 * * *`,即北京时间 08:17)+ `pull_request`。push 提供合并后信号;schedule 捕捉外部 API 漂移;dispatch 是手动逃生通道;可信 pull request 获得合并前门禁。该合并前信号有意接受 § 安全性中描述的更大密钥暴露面。 -### 不受信 PR 的门禁 +### 不可信 PR 的门禁 -GitHub 对两类 PR 隐藏仓库 secret:来自 **fork** 的 PR,以及 **Dependabot** PR(同仓库分支,因此 `head.repo.fork == false`,但 secret 仍被隐藏)。job 级 `if:` 对两者都跳过整个 job: +GitHub 对两类 PR 扣留 repo secret:来自 **fork** 的 PR,以及 **Dependabot** PR(同仓库分支,`head.repo.fork == false`,但 secret 仍被扣留)。一个 job 级 `if:` 对两者都跳过整个 job: ``` github.event_name != 'pull_request' || !(github.event.pull_request.head.repo.fork || github.event.pull_request.user.login == 'dependabot[bot]') ``` -Dependabot 子句基于 PR **作者**(`pull_request.user.login`)而非 `github.actor`(运行触发者):维护者重新打开或重跑 Dependabot PR 时,`github.actor` 会变成人类,但 PR 仍然无密钥;基于作者的判断在这种情况下依然正确。被 **job 级** `if:` 跳过的 job 报告为*成功*检查(不同于工作流/触发级跳过,后者保持 pending),因此如果需要,可以安全地将此工作流标记为 required status check——fork/Dependabot PR 的跳过但绿色的检查不会阻塞合并。 +Dependabot 子句基于 PR **作者**(`pull_request.user.login`)而非 `github.actor`(运行触发者):维护者重新打开或重跑 Dependabot PR 时,`github.actor` 会变成人类,但该 PR 仍然无密钥;基于作者的判断在这种情况下依然正确。被 **job 级** `if:` 跳过的 job 报告为*成功*检查(不同于工作流/触发级跳过会保持 pending),因此如果需要将此工作流标记为 required status check 也是安全的——fork/Dependabot PR 的跳过但绿色的检查不会阻塞合并。 -该门禁是一个*干净跳过的便利措施*,而非 secret 的安全边界(见 § 安全性——边界是 GitHub 自身在 `pull_request` 下对 fork 的 secret 隐藏机制)。没有这个门禁,fork 仍然无法读取密钥;它们只会遇到一个令人困惑的预检硬失败并浪费计算资源。 +该门禁是一个*干净跳过的便利措施*,而非 secret 的安全边界(见 § 安全性——边界是 GitHub 自身在 `pull_request` 下对 fork 的 secret 扣留机制)。没有该门禁,fork 仍然无法读取密钥;只是会遇到令人困惑的 preflight 硬失败并浪费计算资源。 -### 预检:大声失败,绝不假绿 +### Preflight:大声失败,绝不虚假为绿 -由于 job 仅在 secret 预期存在的受信事件上运行,预检是无条件的存在性检查:密钥为空 → `exit 1` 并附带 `::error::` 注解指明需要配置的 secret 名称。这是让自跳过套件可以安全用作门禁的关键。没有它,被删除/重命名/配置错误的 secret 会让 `test:e2e` 跳过所有真实套件并报告全绿——整个安全网的静默退化。这个守卫将「secret 缺失」从不可见的假通过变为可见的失败。(其正确性已在实际中验证:secret 存在之前的运行恰好在此步骤失败。) +由于 job 仅在 secret 应当存在的可信事件上运行,preflight 是一个无条件的存在性检查:密钥为空→`exit 1` 并附带 `::error::` 注解指明需要配置的 secret 名称。这是让自跳过套件可以安全地作为门禁的关键。没有它,被删除/重命名/错误配置的 secret 会让 `test:e2e` 跳过所有真实套件并报告全绿——整个安全网的静默退化。该守卫将「secret 缺失」从不可见的虚假通过转化为可见的失败。(其正确性已在实际中验证:secret 存在之前的运行恰好在此步骤失败。) ### Secret 映射与卫生 -仓库 secret 命名为 `DEEPSEEK_API_KEY_EXTERNAL`;它被映射到适配器和测试读取的 `DEEPSEEK_API_KEY` 环境变量(`process.env.DEEPSEEK_API_KEY`)。独立的 secret 名称记录了意图(这是*外部*公开 API 密钥,不是内部端点密钥),并允许内部端点密钥日后无冲突地共存。以下卫生选择均为防御性设计: +repo secret 命名为 `DEEPSEEK_API_KEY_EXTERNAL`;映射到适配器和测试读取的 `DEEPSEEK_API_KEY` 环境变量(`process.env.DEEPSEEK_API_KEY`)。独立的 secret 名称记录了意图(这是*外部*公开 API 密钥,不是内部端点密钥),并允许内部端点密钥日后无冲突地共存。以下卫生选择均为防御性设计: -- **步骤级 secret。** `DEEPSEEK_API_KEY` 仅在预检和 e2e 步骤的 `env:` 中设置,绝不在 job 级设置——因此 checkout/setup-node/install 永远看不到它。依赖中被入侵的安装时生命周期脚本无法读取不在其环境中的 secret。 -- **`permissions: contents: read`。** 该 job 仅读取仓库以运行测试;不需要写权限(不写 PR 评论、不写 status),因此 `GITHUB_TOKEN` 降至最小权限。 -- **`DEEPSEEK_BASE_URL` 固定**为 e2e 步骤上的 `https://api.deepseek.com`。适配器在未设置时会默认使用此值([packages/llm/llm-deepseek/src/index.ts](../../../../packages/llm/llm-deepseek/src/index.ts) 中的 `PUBLIC_BASE_URL`),但显式固定具有自文档化和密封性——一个意外的仓库根目录 `.env`(`vitest.e2e.config.ts` 如果存在会加载它)无法静默地将运行重定向到其他端点。 -- **不回显 secret。** 预检仅打印 `DEEPSEEK_API_KEY present.`——不打印值或长度。 +- **Step 级 secret。** `DEEPSEEK_API_KEY` 仅在 preflight 和 e2e 步骤的 `env:` 中设置,从不在 job 级设置——因此 checkout/setup-node/install 永远看不到它。依赖中被入侵的安装时生命周期脚本无法读取不在其环境中的 secret。 +- **`permissions: contents: read`。** job 仅读取仓库以运行测试;不需要写权限(无 PR 评论、无 status 写入),因此 `GITHUB_TOKEN` 降至最小权限。 +- **`DEEPSEEK_BASE_URL` 固定**为 e2e 步骤上的 `https://api.deepseek.com`。适配器在未设置时会默认使用此值([packages/llm/llm-deepseek/src/index.ts](../../../../packages/llm/llm-deepseek/src/index.ts) `PUBLIC_BASE_URL`),但显式固定具有自文档性和密封性——仓库根目录的 `.env`(`vitest.e2e.config.ts` 存在时会加载)无法静默地将运行重定向到其他端点。 +- **不回显 secret。** preflight 仅打印 `DEEPSEEK_API_KEY present.`——不打印值或长度。 ### 范围与运行时形态 -该 job 仅在 Node 24 上运行 `test:e2e`;无密钥门禁和版本兼容性属于主 CI 工作流。测试通过 workspace paths 映射以未构建形式运行,使用有界可配置的 worker 池、逐测试重试和 job 超时。被取代的 PR 运行会被取消,而 push 和定时运行完整执行以提供合并后信号。 +job 仅在 Node 24 上运行 `test:e2e`;无密钥门禁和版本兼容性属于主 CI 工作流。测试通过 workspace paths 映射以未构建形式运行,使用有界的可配置 worker 池、逐测试重试和 job 超时。被取代的 PR 运行会被取消,而 push 和 schedule 运行完整执行以提供合并后信号。 ## 安全性 -仓库的首个 CI secret 需要一份记录在案的威胁模型,因为同仓库 PR、fork PR 和 Dependabot PR 之间的访问权限不同,且仓库公开后会发生变化。 +仓库的首个 CI secret 需要一份记录在案的威胁模型,因为同仓库 PR、fork PR 和 Dependabot PR 的访问权限各不相同,且仓库公开后会发生变化。 -### 今天谁能触及 secret(私有仓库) +### 当前谁能触及 secret(私有仓库) -- **无写权限(fork PR):不能。** 两个独立事实阻止了它。第一,工作流使用 `pull_request` 而**非** `pull_request_target`——GitHub 不会将仓库 secret 传递给 fork PR 的 `pull_request` 运行,因此 `secrets.DEEPSEEK_API_KEY_EXTERNAL` 在 fork runner 上解析为空。第二,`if:` 门禁完全跳过 fork PR。secret 隐藏机制是真正的边界;门禁是纵深防御和用户体验。 -- **写(push)权限:能。** 同仓库分支 PR 会收到 secret,因此有写权限的作者可以修改测试代码(或安装生命周期脚本,或其分支上的工作流 YAML)来窃取密钥。这是 **GitHub Actions 固有的,并非本文引入的**:任何对任何仓库有 push 权限的人都可以通过编写工作流来窃取该仓库的任何 Actions secret。写权限 ⇒ secret 访问权,始终如此。缓解措施在于谁被授予写权限以及分支保护,而非本文件。 +- **无写权限(fork PR):不能。** 两个独立事实阻止了它。第一,工作流使用 `pull_request` 而**非** `pull_request_target`——GitHub 不会将 repo secret 传递给 fork PR 的 `pull_request` 运行,因此 `secrets.DEEPSEEK_API_KEY_EXTERNAL` 在 fork runner 上解析为空。第二,`if:` 门禁完全跳过 fork PR。secret 扣留是真正的边界;门禁是纵深防御和用户体验。 +- **有写(push)权限:能。** 同仓库分支 PR 会收到 secret,因此有写权限的作者可以修改测试代码(或安装生命周期脚本,或其分支上的工作流 YAML)来窃取密钥。这**是 GitHub Actions 的固有特性,并非本文引入的**:任何对任何仓库有 push 权限的人都可以通过编写工作流来窃取该仓库的任何 Actions secret。写权限⇒secret 访问权,始终如此。缓解措施在于谁被授予写权限以及分支保护,而非本文件。 -因此「任何能开 PR 的人都能窃取它」是错误的:只有写权限集合内的人能,而该集合本来就能窃取仓库持有的任何 secret。 +因此「任何能开 PR 的人都能窃取它」是错误的:只有写权限集合内的人能,而这些人本来就能窃取仓库持有的任何 secret。 ### `pull_request` 触发器增加的残余暴露面 -由于启用了 PR 运行,密钥会在合并前被交给**写权限作者 PR 分支上的代码**。这比 `push` + `schedule` + `workflow_dispatch` 的暴露面更大,为了在受信写权限集合内获得合并前信号而被接受。如果这一权衡发生变化,可以去掉 `pull_request` 触发器,同时保留合并后、每夜和按需覆盖。 +由于启用了 PR 运行,密钥会在合并前被交给**写权限作者 PR 分支上的代码**。这比 `push` + `schedule` + `workflow_dispatch` 的暴露面更大,为在可信写权限集合内获得合并前信号而接受。如果这一权衡发生变化,可移除 `pull_request` 触发器,同时保留合并后、每夜和按需覆盖。 -### 仓库公开后会发生什么变化 +### 仓库公开后的变化 -**通过本工作流**,secret 对公众仍然受保护:`pull_request` 在公开仓库上行为一致——fork PR(现在任何人都能开)仍然收不到 secret,且在公开仓库上 GitHub 额外要求维护者批准 fork PR 运行,即使批准后运行也不会获得 secret(批准运行不等于交出密钥)。写权限集合不因可见性改变,因此内部人员的现实也不变。 +**通过本工作流**,secret 对公众仍然受保护:`pull_request` 在公开仓库上行为一致——fork PR(现在任何人都能开)仍然收不到 secret,且在公开仓库上 GitHub 额外要求维护者批准 fork PR 运行,即使批准后运行也不会获得 secret(批准运行不等于交出密钥)。写权限集合不因可见性改变而改变,因此内部人员的现实也不变。 变差的是*周边*模型,以下是翻转可见性之前需要处理的事项: -- **日志变为全球可读。** 今天泄露给组织成员的粗心 secret 回显,在公开后会泄露给整个互联网并在几分钟内被爬取。secret 处理纪律(不回显值/长度——已完成)的重要性大幅提升。 -- **`pull_request_target` 陷阱变为灾难性的。** 如果有人为了「修复」PR 运行而将触发器切换为 `pull_request_target`,工作流将在 base 仓库上下文中运行不受信的 fork 代码**并携带** secret——完整的密钥泄露向量。这在私有仓库上尚可容忍,在公开仓库上则是灾难。e2e.yml 中触发器上的 `SECURITY —` 注释禁止此更改并指向本文。 -- **翻转时轮换密钥。** 该密钥曾存在于私有仓库的 CI 中;将公开视为「假设已暴露」,在那一刻轮换 `DEEPSEEK_API_KEY_EXTERNAL`。 -- **将 secret 置于控制之下。** 确认 Settings → Actions → *"Send secrets to workflows from fork pull requests"* 保持**关闭**(这是唯一能真正打破 fork 边界的设置),并考虑将密钥移入带有 required reviewers 的 GitHub **Environment**,使即使已合并的代码也只在受控条件下使用它,且轮换有一个统一的归属。 +- **日志变为全球可读。** 今天泄露给组织成员的粗心 secret 回显,公开后会泄露给整个互联网并在数分钟内被爬取。secret 处理纪律(不回显值/长度——已做到)的重要性大幅提升。 +- **`pull_request_target` 陷阱变为灾难性的。** 如果有人为了「修复」PR 运行而将触发器切换为 `pull_request_target`,工作流将在 base-repo 上下文中运行不可信的 fork 代码并**携带** secret——完整的密钥泄露向量。在私有仓库中这勉强无害,在公开仓库中则是灾难。e2e.yml 中触发器上的 `SECURITY —` 注释禁止此更改并指向本文。 +- **翻转时轮换密钥。** 密钥曾存在于私有仓库的 CI 中;将公开视为「假定已暴露」,在那一刻轮换 `DEEPSEEK_API_KEY_EXTERNAL`。 +- **将 secret 置于控制之下。** 确认 Settings → Actions → *"Send secrets to workflows from fork pull requests"* 保持**关闭**(这是唯一真正会打破 fork 边界的设置),并考虑将密钥移入带有 required reviewers 的 GitHub **Environment**,使即使已合并的代码也只在受控条件下使用它,且轮换有单一归属。 -以上均不需要修改工作流即可公开仓库;它们是运维步骤加上已添加的 `pull_request_target` 守卫注释。 +以上均不需要修改工作流即可公开;它们是运维步骤加上已添加的 `pull_request_target` 守卫注释。 ## 曾考虑的替代方案 -- **在 ci.yml 中添加消费 secret 的 job**:否决。它会将无密钥、可 fork、始终绿色的门禁耦合到凭证可用性和不同的触发/并发策略上;不同的生命周期,不同的文件。 -- **省略 `pull_request` 触发器**(更小的密钥暴露面):为了合并前信号而否决;安全性一节承载了被接受的暴露分析。 +- **在 ci.yml 中添加消费 secret 的 job**:否决。会将无密钥、可 fork、始终为绿的门禁耦合到凭证可用性和不同的触发/并发策略上;不同的生命周期,不同的文件。 +- **省略 `pull_request` 触发器**(更小的密钥暴露面):为获得合并前信号而否决;安全性章节承载了已接受的暴露分析。 ## 后果 -新增一个 CI 工作流和仓库首个需要维护的 secret。真实 API 套件现在成为合并门禁(受信 PR 上的合并前门禁、main 分支上的合并后门禁)并每夜运行,因此 agent 与外部 API 交互中的真实故障会在 CI 中浮现,而非仅在开发者的本地运行中出现——代价是每个受信 PR 和合并都会产生真实(但内部免费)的 API 调用。预检使 secret 配置错误变为自我通告而非静默禁用安全网。 +新增一个 CI 工作流和仓库的首个需要维护的 secret。真实 API 套件现在作为合并门禁(可信 PR 上的合并前门禁、主分支上的合并后门禁)并每夜运行,因此 agent 与外部 API 交互中的真实故障会在 CI 中浮现,而非仅在开发者的本地运行中出现——代价是每个可信 PR 和合并都会产生真实的(但内部免费的)API 调用。preflight 使 secret 配置错误变为自我通告而非静默禁用安全网。 -本设计携带一个记录在案的约束面:`pull_request` 触发器的密钥暴露权衡(去掉它以加固)、`if:` 门禁对基于作者的 Dependabot 判断的依赖,以及对 `pull_request_target` 的硬性禁止。上述公开清单是运维伴侣——本 RFC 是未来维护者在更改触发器集合或翻转仓库可见性之前应重新阅读的地方,而非从头重新推导 fork/secret 模型。 +本设计携带一个记录在案的约束面:`pull_request` 触发器的密钥暴露权衡(移除以加固)、`if:` 门禁对基于作者的 Dependabot 判断的依赖,以及对 `pull_request_target` 的硬性禁止。上述公开清单是运维伴侣——本 RFC 是未来维护者在更改触发器集合或翻转仓库可见性之前应重读的地方,而非从头重新推导 fork/secret 模型。 -定时触发器在仓库不活跃 60 天后会自动禁用(GitHub 行为);push/PR/dispatch 是后备,活跃的 monorepo 不会触及此限制。假设 runner 可出站访问 `https://api.deepseek.com`——GitHub 托管的 `ubuntu-latest` 具备此条件;出站受限的自托管 runner 需要在依赖每夜运行之前确认连通性。 +schedule 触发器在仓库不活跃 60 天后会自动禁用(GitHub 行为);push/PR/dispatch 是后备,活跃的 monorepo 不会触及此限制。假设 runner 对 `https://api.deepseek.com` 有出站连通性——GitHub 托管的 `ubuntu-latest` 具备此条件;受出站限制的自托管 runner 需要在依赖每夜运行之前确认连通性。 diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml index 592c10b7e0..6e63ef2e55 100644 --- a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-remove-redundant-snapshot-log-goldens.md: badd32d4479ac6d44bb7be3cd262cba57b1b3a38 -2026-06-20-remove-redundant-snapshot-log-goldens.zh.md: 35e4a698cbd19bcceb97df714d2b6bfb371c155a +2026-06-20-remove-redundant-snapshot-log-goldens.zh.md: b791fbcc971eb1340f0d43ef6a60ebb29e4711f9 diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md index 35e4a698cb..b791fbcc97 100644 --- a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md @@ -6,32 +6,32 @@ Status: implemented ## 问题 -模型驱动的 ACP 快照场景同时包含 `session.jsonl` 和 `session.golden.jsonl`。对于普通录制场景,`session.jsonl` 是从真实运行中采集的回放 fixture(测试前置数据),回放测试将新持久化的日志归一化后与 `session.golden.jsonl` 比较。在当前 fixture 中,普通录制场景的归一化录制日志与归一化 golden 完全相同。 +模型驱动的 ACP(Agent Client Protocol)快照场景同时包含 `session.jsonl` 和 `session.golden.jsonl`。对于普通录制场景,`session.jsonl` 是从真实运行中采集的回放 fixture(测试前置数据),回放测试对新持久化的日志做归一化后与 `session.golden.jsonl` 比较。在当前 fixture 中,普通录制场景的归一化录制日志与归一化 golden 完全一致。 -手工编写的覆盖场景(`error-finish`、`cancel`)目前使用 `replay.override.json` 驱动模型行为,并保留 `session.jsonl` 作为最小占位 fixture,而 `session.golden.jsonl` 存放预期的持久化日志。覆盖文件是一个 `ReplayEntry` 对象的 JSON 数组:`{ "kind": "chunks", "chunks": StreamChunk[] }`、`{ "kind": "throw", "chunks": StreamChunk[], "message": string, "code": string, "status"?: number }` 或 `{ "kind": "hang" }`。这种拆分同样没有必要:当覆盖 sidecar 存在时,`llm-replay` 会替换派生的脚本,不需要从 `session.jsonl` 获取模型分片,因此 `session.jsonl` 仍然可以充当该场景的预期会话日志产物。 +手工编写的覆盖场景(`error-finish`、`cancel`)目前使用 `replay.override.json` 驱动模型行为,并保留 `session.jsonl` 作为最小占位 fixture,而 `session.golden.jsonl` 存放预期的持久化日志。覆盖文件是一个 `ReplayEntry` 对象的 JSON 数组:`{ "kind": "chunks", "chunks": StreamChunk[] }`、`{ "kind": "throw", "chunks": StreamChunk[], "message": string, "code": string, "status"?: number }` 或 `{ "kind": "hang" }`。这种拆分同样是多余的:当覆盖 sidecar 存在时,`llm-replay` 会替换派生脚本,不需要从 `session.jsonl` 获取模型分片,因此 `session.jsonl` 仍可作为该场景的预期会话日志产物。 ## 决策 -彻底移除 `session.golden.jsonl` 概念。每个场景最多只有一个提交的会话日志产物 `session.jsonl`: +彻底移除 `session.golden.jsonl` 概念。每个场景最多只有一个提交到仓库的会话日志产物,即 `session.jsonl`: -- 对于录制场景,`session.jsonl` 仍是原始采集的日志。回放仍从中派生模型分片,快照测试将回放运行的归一化持久化日志与归一化后的 `session.jsonl` 比较。 -- 对于手工编写的覆盖场景,`replay.override.json` 驱动模型行为,`session.jsonl` 存放预期产出的会话日志。当覆盖文件存在时回放适配器会忽略 fixture 中的模型分片,因此同一个文件既可作为预期日志,又不影响回放行为。 -- 对于无模型场景,`session.jsonl` 可以保留为启动 `llm-replay` 所需的最小 fixture;除非该场景创建了持久化会话,否则无需进行会话日志比较。 +- 对于录制场景,`session.jsonl` 仍是原始采集的日志。回放仍从中派生模型分片,快照测试将回放运行归一化后的持久化日志与归一化后的 `session.jsonl` 进行比较。 +- 对于手工编写的覆盖场景,`replay.override.json` 驱动模型行为,`session.jsonl` 存放预期产出的会话日志。当覆盖文件存在时,回放适配器不从 fixture 获取模型分片,因此同一个文件既可作为预期日志,又不影响回放行为。 +- 对于无模型场景,`session.jsonl` 可保留为引导 `llm-replay` 所需的最小 fixture;除非场景创建了持久化会话,否则无需进行会话日志比较。 -stdout golden 保持不变;它们是面向编辑器的投影,与会话 fixture 并不冗余。 +stdout golden 保持不变;它们是面向编辑器的投影,与会话 fixture 不构成冗余。 ## 曾考虑的替代方案 -**基于共享(回放运行)上下文对两侧进行归一化**:否决。`normalizeSessionLog` 通过精确字符串匹配擦除 cwd,因此 fixture 中录制的 cwd 不会被擦除,每次比较都会失败。两侧各自基于自身 header 派生的上下文进行归一化——下方的实现说明描述了具体机制。 +**对两侧基于共享的(回放运行)上下文做归一化**:否决。`normalizeSessionLog` 通过精确字符串匹配擦除 cwd,因此 fixture 中录制的 cwd 不会被擦除,每次比较都会失败。两侧各自基于自身 header 派生的上下文做归一化——下方的实现说明描述了具体机制。 ## 验证 -`session.golden.jsonl` 不再出现在快照 harness、fixture、遗留文件守卫或文档中的任何位置;快照测试对每个模型场景都从 `session.jsonl` 派生预期会话日志;手工编写的 sidecar 场景将其预期产出的日志提交为 `session.jsonl`,并以 `replay.override.json` 作为模型行为覆盖;遗留 fixture 守卫知道每种场景类型需要哪些文件。[ACP 快照测试 RFC](../../implemented/testing/2026-06-19-acp-snapshot-tests.md) 描述了精简后的 fixture 集合。 +`session.golden.jsonl` 在快照 harness、fixture、遗留文件守卫和文档中均不再出现;快照测试对每个模型场景都从 `session.jsonl` 派生预期会话日志;手工编写的 sidecar 场景将预期产出的日志作为 `session.jsonl` 提交,并以 `replay.override.json` 作为模型行为覆盖;遗留 fixture 守卫知道每种场景类型需要哪些文件。[ACP 快照测试 RFC](../../implemented/testing/2026-06-19-acp-snapshot-tests.md) 描述了精简后的 fixture 集合。 ## 后果 -评审人失去了一个让预期持久化日志在视觉上与回放 fixture 分离的产物名称。stdout golden 仍然保护编辑器 transcript(文本记录),将回放输出与 `session.jsonl` 比较则在不重复文件的前提下保留了 agent loop(智能体循环)/持久化的回归检查。 +评审者失去了一个让预期持久化日志在视觉上与回放 fixture 分离的产物名称。stdout golden 仍保护编辑器 transcript(文本记录),将回放输出与 `session.jsonl` 比较则在不重复文件的前提下保留了循环/持久化的回归检查。 ## 实现说明 -两侧各自基于自身 header 值进行归一化,因为录制与回放具有不同的 id、路径和时间戳。`fixtureContext()` 从 fixture 的 header 派生 fixture 上下文,使已归一化的 fixture 具有幂等性。会话日志使用普通相等比较而非文件快照更新,因此比较过程永远不会改写 fixture。 +两侧各自基于自身 header 值做归一化,因为录制与回放具有不同的 id、路径和时间戳。`fixtureContext()` 从 fixture 的 header 派生上下文,使已归一化的 fixture 具有幂等性。会话日志使用普通相等比较而非文件快照更新,因此比较过程不会改写 fixture。 diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml index 73c068be2c..f3bddc661c 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-22-fork-child-replay-seed-boundary.md: a0bf064508107a23147df1a6c824c53a3906c43e -2026-06-22-fork-child-replay-seed-boundary.zh.md: 7ee6c3d373ff5e598efa82d5c8fbad6b8e162aeb +2026-06-22-fork-child-replay-seed-boundary.zh.md: 3825cce806c036c7fa21641a2f0b7cc0533d84bf diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md index 7ee6c3d373..3825cce806 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md @@ -1,18 +1,18 @@ -# RFC:持久化 seed 边界以确保 fork 子会话回放路由正确 - -Status: implemented +# RFC:持久化 seed 边界以确保 fork 子会话回放正确路由 [English](2026-06-22-fork-child-replay-seed-boundary.md) | 中文 +Status: implemented + ## 问题 -[逐会话快照回放 RFC](2026-06-22-subagent-snapshot-replay.md) 让快照层表达了嵌套 agent 的结构:一个父会话加上每个进程内 subagent 各一份录制日志,每份日志以调用方会话为键独立回放为自己的脚本。该 RFC 在 §Scope 末尾提到 fork 快照是「一个简单的后续补充,不是键控方案的缺口」。这个说法对 fork 子会话而言是错的——问题不在键控,而在*脚本推导*。 +[逐会话快照回放 RFC](2026-06-22-subagent-snapshot-replay.md) 让快照层表达了嵌套 agent(智能体)的形状:一个父会话加上每个进程内 subagent 各一份已录制的日志,各自作为独立脚本回放、以调用方会话为键。该 RFC 指出(§ Scope 末尾条目)fork 快照是「一个平凡的后续补充,不是键控方案的缺口」。这对 fork 子会话而言是错的——问题不在键控,而在*脚本推导*。 -subagent 脚本由 [`deriveReplayScript`](../../../../packages/support/llm-replay) 从录制的会话日志推导而来:它按 `(turn, step)` 对日志中的 `assistant/chunk` 事件分组,每次 `stream()` 调用对应一条回放条目。对 **spawn** 子会话而言这是正确的,因为其日志只包含自己的模型调用。 +subagent 脚本由 [`deriveReplayScript`](../../../../packages/support/llm-replay) 从已录制的会话日志推导:它按 `(turn, step)` 对日志中的 `assistant/chunk` 事件分组,每次 `stream()` 调用对应一条回放条目。对 **spawn** 子会话而言这是正确的,因为其日志只包含自身的模型调用。 -**fork** 子会话不同。fork 后端用*父会话日志中一段平衡的已完成轮次前缀*([`dsh-subagent-inprocess`](../../../../packages/subagent/subagent-inprocess))来初始化子会话,而这段 seed 会成为子会话持久化的 `log`(`Session` 构造函数将 seed 复制到 `this.log`)。因此 fork 子会话的 `.jsonl` 以**父会话**的事件开头——包括父会话的 `assistant/chunk` 事件——之后才是子会话自己的轮次。 +**fork** 子会话不同。fork 后端用*父日志的一段平衡的已完成轮次前缀*([`dsh-subagent-inprocess`](../../../../packages/subagent/subagent-inprocess))来播种子会话,而该 seed 会成为子会话持久化的 `log`(`Session` 构造函数将 seed 复制进 `this.log`)。因此 fork 子会话的 `.jsonl` 以**父会话**的事件开头——包括父会话的 `assistant/chunk` 事件——之后才是子会话自身的轮次。 -如果从 fork 子会话的完整日志推导脚本,就会把**父会话**录制的响应当作**子会话**的模型调用来回放:活跃的 fork 子会话第一次调用 `stream()` 时,会收到父会话的第一段 chunk 序列而非自己的。目前录制的场景全部是 spawn,所以这个问题从未触发——但 fork 快照会静默地路由错误,而这恰恰是快照层存在的意义所要捕获的那类 bug。 +从 fork 子会话的完整日志推导脚本,会把**父会话**的已录制响应当作**子会话**的模型调用来回放:实际运行的 fork 子会话第一次调用 `stream()` 时,会收到父会话的第一段 chunk 序列而非自身的。目前已录制的场景全部是 spawn,所以这从未触发——但 fork 快照会静默地错误路由,恰好属于快照层存在的意义所要捕获的那类 bug。 ## 决策 @@ -20,30 +20,30 @@ subagent 脚本由 [`deriveReplayScript`](../../../../packages/support/llm-repla ### 1. 会话头部的 `seedLength` -`SessionHeader` 新增可选字段 `seedLength: number`:表示前导多少个事件是通过 seed 继承而来、而非本会话产生的。fork 后端在创建子会话时设置它(= seed 前缀长度);新建的 spawn 子会话不设置(等价于 0)。该字段通过 `CreateSessionOptions.meta`(以及 `CreateAgentOptions.meta`)传递,在 `SessionStore.prepare` 中设置。 +`SessionHeader` 新增可选字段 `seedLength: number`——表示有多少前导事件是通过 seed 继承而来、而非本会话产生的。fork 后端在创建子会话时设置它(= 播种前缀的长度);全新的 spawn 子会话不设置(等同于 0)。它通过 `CreateSessionOptions.meta`(及 `CreateAgentOptions.meta`)传递,在 `SessionStore.prepare` 中设置。 -`seedLength` 是**显式**的,从不从 `seed.length` 推断。重建(resume/load)时用会话的完整存储日志作为 seed,此时 `seed.length` 是全长而非原始边界——重建路径改为从加载的 header 中取回持久化的 `seedLength`。(形状与 `createdAt` 相同:重建时显式保留,而非重新默认为当前时间。) +`seedLength` 是**显式**的,绝不从 `seed.length` 推断。重建(resume/load)时用会话的完整已存储日志作为 seed,此时 `seed.length` 是全长而非原始边界——resume 路径改为从加载的 header 中取回持久化的 `seedLength`。(形状与 `createdAt` 相同:重建时显式保留,而非重新默认为当前时间。) -### 2. 两个持久化后端都完整往返 +### 2. 两个持久化后端均完整往返 - **JSONL**:header 行上的 `seedLength` 字段(`toHeaderLine`/`fromHeaderLine`)。 - **SQLite**:`sessions` 表上的 `seed_length` 列。 -包含 `seed_length`、`source_event_seqs` 和 `surface_op` 的 SQLite 布局为 schema version 4。更早的 version 3 布局存在歧义,因此按预发布政策,所有非当前 `user_version` 均直接拒绝,不做迁移。 +包含 `seed_length`、`source_event_seqs` 和 `surface_op` 的 SQLite 布局为 schema version 4。更早的 version 3 布局存在歧义,因此在预发布策略下,所有非当前 `user_version` 均直接拒绝,不做迁移。 -### 3. 回放在边界之后推导子会话脚本 +### 3. 回放从边界之后推导子会话脚本 -`dsh-llm-replay` 的 `parseSessionHeader` 现在也读取 `seedLength`(缺失 ⇒ 0),`loadSessionScripts` 从 `parseSessionLog(text).slice(seedLength)` 推导子会话的条目——即边界处及之后的事件,也就是子会话自己的模型调用。对 spawn 子会话而言 `seedLength` 为 0,这是一个空操作,因此 spawn 场景逐字节不变。 +`dsh-llm-replay` 的 `parseSessionHeader` 现在也读取 `seedLength`(缺失则为 0),`loadSessionScripts` 从 `parseSessionLog(text).slice(seedLength)` 推导子会话条目——即边界及之后的事件,也就是子会话自身的模型调用。对 spawn 子会话而言 `seedLength` 为 0,此操作是空操作,spawn 场景逐字节不变。 -这关闭了路由正确性的缺口,两个录制的 fork 场景对其进行了端到端验证——见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md)。 +这关闭了路由正确性的缺口,两个已录制的 fork 场景对其进行端到端验证——见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md)。 ## 曾考虑的替代方案 -- **在 `llm-replay` 中启发式推导边界**(seed 前缀是连续的父事件,止于子会话第一条 `user/message` 之前的最后一个 `turn/end`)。否决:在测试 harness 中用脆弱的启发式重新推导一个生产者已经知道的事实。在源头(fork 后端)持久化边界,是「包边界处显式优于隐式」规则跨持久化边界的应用——子会话 fixture 的读取方永远不需要重建继承在哪里结束。 -- **固定格式版本而不递增**(事件日志使用的 `SESSION_FORMAT_VERSION = 0`「不稳定」策略)。对 SQLite *表*布局否决:`SCHEMA_VERSION` 是单调递增并拒绝旧版的旋钮(一小组值得区分的修订),与事件词汇的 `version` 不同。新增列正是它所版本化的那种破坏性表结构变更,因此递增。 +- **在 `llm-replay` 中启发式推导边界**(播种前缀是连续的父事件,止于子会话第一条 `user/message` 之前的最后一个 `turn/end`)。否决:在测试 harness 中用脆弱的启发式重新推导一个生产者已经知道的事实。在源头(fork 后端)持久化边界,是「在包(package)seam 处显式优于隐式」这条规则跨越持久化边界的应用——子会话 fixture(测试前置数据)的读取者永远不需要重建继承在哪里结束。 +- **固定格式版本而不递增**(事件日志使用的 `SESSION_FORMAT_VERSION = 0`「不稳定」姿态)。对 SQLite *表*布局否决:`SCHEMA_VERSION` 是单调递增并拒绝旧版的旋钮(一组小的、值得区分的修订),与事件词汇表的 `version` 不同。新增列正是它所版本化的那种破坏性表变更,因此需要递增。 ## 后果 -- 在 core 与两个后端之间新增一个持久化的 header 字段;核心数据结构目录(`persistence.md`)在同一个变更中更新(其 `SessionHeader` / `CreateSessionOptions` 的 `type-equiv` 块)。 +- core 与两个后端新增一个持久化 header 字段;核心数据结构目录(`persistence.md`)在同一变更中更新(其 `SessionHeader` / `CreateSessionOptions` 的 `type-equiv` 块)。 - 既有的 schema v2 SQLite 数据库在打开时被拒绝(预发布阶段无用户数据)。 -- spawn 回放不变(`seedLength` 为 0)。fork 回放现在将子会话路由到自己的脚本;由 `llm-replay` 测试中的一个回归用例覆盖(一个子会话 fixture,其 seed 前缀包含父会话的 chunk——推导出的子会话脚本必须排除它,不做 slice 时该用例为红),以及一个持久化往返测试(两个后端,通过共享的 coordinator 契约)。 +- spawn 回放不变(`seedLength` 为 0)。fork 回放现在将子会话路由到自身的脚本;由 `llm-replay` 测试中的一个回归用例覆盖(一个子会话 fixture,其播种前缀包含父会话的 chunk——推导出的子会话脚本必须排除它,不做 slice 时该用例为红)以及一个持久化往返测试(两个后端,通过共享的 coordinator 契约)。 diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml index 7312eb5cab..d262a105ce 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-22-fork-snapshot-scenarios.md: baca94d6a1071ec38ee20ca841fc3472a870b1a2 -2026-06-22-fork-snapshot-scenarios.zh.md: 227d54cc2bb2e66a391dddd29a7f2593cb02f7e2 +2026-06-22-fork-snapshot-scenarios.zh.md: b6f3f6a6f318a343d5e32573d39f11f59b509ee3 diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md index 227d54cc2b..b6f3f6a6f3 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md @@ -1,31 +1,31 @@ # RFC:记录 fork 与混合 spawn+fork 快照场景 -[English](2026-06-22-fork-snapshot-scenarios.md) | 中文 - Status: implemented +[English](2026-06-22-fork-snapshot-scenarios.md) | 中文 + ## 问题 -[seed-boundary RFC](2026-06-22-fork-child-replay-seed-boundary.md) 让 fork 子会话的回放路由正确工作了:`dsh-llm-replay` 从子会话持久化的 `seedLength` 边界处或之后的事件推导出子会话的脚本,因此 fork 子会话继承的父会话前缀不会被当作子会话自身的模型调用来回放。但该 RFC 交付时**没有录制 fork 场景**:切片逻辑仅由 `llm-replay` 的单元测试(一个合成的子会话 fixture(测试前置数据))和一个持久化往返测试覆盖。全 transcript(文本记录)快照层——那个启动真实 `acp-agent` 并回放端到端嵌套 transcript 的网——只有 spawn 子会话(`subagent-spawn`、`subagent-multi`)。一个让单元测试保持绿色的 fork 路由回归,仍然会逃过专为捕获 transcript 回归而建的那一层。 +[seed-boundary RFC](2026-06-22-fork-child-replay-seed-boundary.md) 使 fork 子会话的回放路由正确运作:`dsh-llm-replay` 从子会话持久化的 `seedLength` 边界处或之后的事件推导出子会话的脚本,因此 fork 子会话继承的父会话前缀不会被当作子会话自身的模型调用来回放。但该 RFC 交付时**没有记录 fork 场景**——该切片仅由 `llm-replay` 的单元测试(一个合成的子会话 fixture(测试前置数据))和一个持久化往返测试覆盖。全 transcript(文本记录)快照层(即启动真实 `acp-agent` 并回放端到端嵌套 transcript 的那张网)只有 spawn 子会话(`subagent-spawn`、`subagent-multi`)。如果一个 fork 路由回归让单元测试保持绿色,它仍然会逃过专为捕获 transcript 回归而建的那一层。 -表达 fork 场景所需的快照基础设施已经就位:两个进程内后端都通过 `cordis.yml` / `cordis.snapshot.yml` 接入为两个面向模型的工具(`subagent` → spawn、`subagent_fork` → fork),harness 收集每个子会话的日志,回放按 `seedLength` 为键转发每个子会话的 fixture。缺少的只是一个*录制好的场景*来驱动 fork 子会话走完这条路径。 +表达 fork 场景所需的快照基础设施已经就位:两个进程内后端都在 `cordis.yml` / `cordis.snapshot.yml` 中以两个面向模型的工具接入(`subagent` → spawn、`subagent_fork` → fork),harness 会收集每个子会话的日志,回放按 `seedLength` 为键转发各子会话的 fixture。缺少的是一个**已记录的场景**来驱动 fork 子会话走完这条路径。 ## 决策 -对真实 API 录制两个场景,均在默认门禁中以 keyless 方式回放: +针对真实 API 记录两个场景,均在默认门禁中以无密钥方式回放: -- **`subagent-fork`**:父会话完成一个轮次以建立一个事实,然后通过 `subagent_fork` 委派一个子任务。fork 子会话继承对话(其日志携带非零 `seedLength`),因此能从父会话的上下文中作答。这是聚焦的回归守卫:子会话 fixture 的 `seedLength` 就是回放切片所依赖的边界,来自真实 fork 的录制而非手工合成。 -- **`subagent-mixed`**:父会话完成一个轮次,然后在同一个 transcript 中分别通过 `subagent`(全新的 spawn 子会话,`seedLength` 为 0)和 `subagent_fork`(fork 子会话,非零 `seedLength`)各委派一次。这是 seed-boundary 和 per-session-replay 两份 RFC 都提到的「未来补充」的混合 spawn+fork 场景:一个 transcript 同时覆盖两种传输方式和切片的两个分支(`seedLength` 0 = 无操作,`seedLength > 0` = 裁掉继承的前缀),两个子会话按 `createdAt` 排序为先 spawn 后 fork。 +- **`subagent-fork`**:父会话完成一个轮次以建立一个事实,然后通过 `subagent_fork` 委派一个子任务。fork 子会话继承对话(其日志携带非零 `seedLength`),因此可以从父会话的上下文中作答。这是聚焦的回归守卫:子会话 fixture 的 `seedLength` 就是回放切片所依赖的边界,来自真实 fork 的记录而非手工合成。 +- **`subagent-mixed`**:父会话完成一个轮次,然后在同一个 transcript 中分别通过 `subagent`(全新的 spawn 子会话,`seedLength` 为 0)和 `subagent_fork`(fork 子会话,`seedLength` 非零)各委派一次。这是 seed-boundary 和 per-session-replay 两份 RFC 都列为后续补充的混合 spawn+fork 场景:一个 transcript 同时覆盖两种传输方式和切片的两个分支(`seedLength` 0 = 无操作,`seedLength > 0` = 裁剪继承的前缀),两个子会话按 `createdAt` 排序为先 spawn 后 fork。 ### 为什么需要一个已完成的第一轮次 -fork 后端用父会话的**已完成轮次的平衡前缀**([`completedTurnPrefix`](../../../../packages/subagent/subagent-fork))来填充子会话种子。如果父会话在第一个轮次就 fork,则没有已完成的轮次可继承,种子为空(≡ 全新 spawn,`seedLength` 为 0),这**不会**覆盖切片逻辑。因此两个场景都使用两条提示词输入:第一条提示词完成一个轮次(建立一个 codeword 供子会话稍后回忆),第二条委派 fork。子会话 transcript 中回忆出的 codeword 只是模型行为的附带结果;真正承载验证的产物是子会话 fixture 中录制的 `seedLength`,回放切片消费的正是它。 +fork 后端用父会话的**已完成轮次的平衡前缀**([`completedTurnPrefix`](../../../../packages/subagent/subagent-fork))来初始化子会话。如果父会话在第一轮次就 fork,则没有已完成的轮次可继承,seed 为空(等价于全新 spawn,`seedLength` 为 0),这**不会**覆盖切片逻辑。因此两个场景都使用双 prompt 输入:第一个 prompt 完成一个轮次(建立一个 codeword,子会话稍后被要求回忆它),第二个 prompt 委派 fork。子会话 transcript 中回忆出的 codeword 只是模型行为的附带产物;真正承载验证的产物是子会话 fixture 中记录的 `seedLength`,回放切片消费的正是它。 ## 后果 -- fork 路由切片现在由全 transcript 层守卫,而不仅仅是单元测试。移除 `slice(seedLength)`(回放整个子会话日志)会让**两个**新场景变红——fork 子会话收到的是父会话录制的 chunk 而非自己的——证明守卫确实生效(场景落地时已验证红→绿)。 -- `subagent-mixed` 是第一个在同一个 transcript 中驱动两个*不同* subagent 后端的快照场景,同时覆盖了跨 spawn 和 fork 子会话的 per-session 回放键控。 -- 进程外(ACP)subagent 回放是另一种形态(每个子会话是独立进程、有自己的回放),仍以 `TODO(acp-subagent-replay)` 跟踪——本文场景仅限进程内。 -- 重新录制(`pnpm run test:snapshot:record`)会从真实 API 重新生成全部四个 fork/spawn fixture;两个新场景在没有 key 时与所有录制场景一样自动跳过。 +- fork 路由切片现在由全 transcript 层守卫,而不仅仅是单元测试。移除 `slice(seedLength)`(回放整个子会话日志)会让**两个**新场景变红——fork 子会话收到的是父会话记录的 chunk 而非自己的——证明守卫确实生效(场景落地时已验证红→绿)。 +- `subagent-mixed` 是第一个在同一个 transcript 中驱动两种**不同** subagent 后端的快照场景,同时覆盖了跨 spawn 和 fork 子会话的 per-session 回放键控。 +- 进程外(ACP)subagent 回放形态不同(每个子会话是独立进程、有自己的回放),仍以 `TODO(acp-subagent-replay)` 跟踪——本文场景仅限进程内。 +- 重新录制(`pnpm run test:snapshot:record`)会从真实 API 重新生成全部四个 fork/spawn fixture;两个新场景在无密钥时自动跳过,与所有已录制场景一致。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml index 9ce1aefb81..8bea2c8a5e 100644 --- a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-22-subagent-snapshot-replay.md: fbb2e5b93cced118a24f5560f229e2dc341bf3b2 -2026-06-22-subagent-snapshot-replay.zh.md: fd4ba0c109d77fdf9b64e25de74d3da577ce5a9b +2026-06-22-subagent-snapshot-replay.zh.md: 6514a0bcb5db3948f6d8f4693b17a74e4a9ad926 diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md index fd4ba0c109..6514a0bcb5 100644 --- a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md @@ -1,58 +1,58 @@ # RFC:嵌套 agent 的逐会话快照回放 -Status: implemented - [English](2026-06-22-subagent-snapshot-replay.md) | 中文 +Status: implemented + ## 问题 -快照测试层(`pnpm run test:snapshot`)启动真实的 `acp-agent` 子进程,通过 [`dsh-llm-replay`](../../../../packages/support/llm-replay) 回放录制的会话,并将归一化后的 stdout transcript(文本记录)与重新持久化的会话日志同提交的 golden 文件做 diff。这是唯一一个端到端验证完整编辑器侧 transcript 的测试层。 +快照测试层(`pnpm run test:snapshot`)启动真实的 `acp-agent` 子进程,通过 [`dsh-llm-replay`](../../../../packages/support/llm-replay) 回放录制的会话,并将归一化后的 stdout transcript(文本记录)与重新持久化的会话日志对已提交的金标文件做 diff。这是唯一一个端到端验证完整编辑器侧 transcript 的测试层。 -它最初为**单会话单进程**而建,这一假设硬编码在两处: +该层最初为每个进程只有一个会话而构建,这一假设硬编码在两处: -- **`dsh-llm-replay` 没有任何键控。** 它用一个全局游标,将第 N 次 `llm/stream` 调用对应到单一录制序列的第 N 条。当父 agent 和进程内 subagent 同时在一个 context 上流式输出时,调用交错,单一游标会把子 agent 的脚本交给父 agent(反之亦然)。 -- **harness 只收割一份日志。** `findSessionLog` 遍历 sessions 根目录,返回找到的**第一个** `.jsonl`。subagent 作为同一 cwd bucket 中的第二个 `Session` 运行、拥有自己的日志,因此子 agent 的 transcript 被静默丢弃。 +- **`dsh-llm-replay` 没有做任何键控。** 它用一个全局游标,将第 N 次 `llm/stream` 调用对应到单一录制序列的第 N 条。当父 agent 和一个进程内 subagent 在同一个上下文上同时流式输出时,调用交错,单一游标会把子 agent 的脚本发给父 agent(反之亦然)。 +- **harness 只收集一份日志。** `findSessionLog` 遍历 sessions 根目录,返回找到的第一个 `.jsonl`。subagent 作为第二个 `Session` 运行,在同一个 cwd bucket 下有自己的日志,因此子 agent 的 transcript 被静默丢弃。 -这正是 [subagent seam RFC](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 中记录的 `TODO(subagent-snapshots)` 延期项:进程内后端(PR2)已有单元测试和 e2e 覆盖,但全 transcript 快照层在本基础设施落地之前无法表达嵌套 agent 的形态。本 RFC 即为该堆叠后续。 +这就是 [subagent seam RFC](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 中记录的 `TODO(subagent-snapshots)` 延期项:进程内后端(PR2)已有单元测试和 e2e 覆盖,但全 transcript 快照层在本基础设施就绪之前无法表达嵌套 agent 的形态。本 RFC 即为该堆叠后续。 ## 决策 -回放按**调用方会话**键控,harness 收割**所有**会话日志。 +回放按**调用方会话**键控,harness 收集**所有**会话日志。 -### 1. 调用方会话 id 随模型请求传递 +### 1. 调用方会话 id 附着在模型请求上 -`GenerateOptions` 新增可选字段 `sessionId`,在请求组装时从 `agent.session.id` 打入。适配器忽略它;`llm/stream` 监听器用它按发起方会话路由。其类型为 `Branded<'SessionId'>`(来自 `dsh-brand`)而非 `dsh-session` 的 `SessionId`,因为后者所在包导入了 `dsh-llm` 的 `Message`,反向导入会形成循环。两个类型等价,会话 id 赋值无需强制转换。将 brand 移入专用 ids 包属于独立工作,因为它会触及所有 id 导入。 +`GenerateOptions` 新增可选字段 `sessionId`,在请求组装时从 `agent.session.id` 赋值。适配器忽略它;`llm/stream` 监听器用它按发起会话路由。其类型为 `Branded<'SessionId'>`(来自 `dsh-brand`)而非 `dsh-session` 的 `SessionId`,因为后者所在包(package)导入了 `dsh-llm` 的 `Message`,反向导入会形成循环。两个类型等价,因此会话 id 赋值无需类型转换。将 brand 移到一个专用 ids 包属于独立工作,因为它会影响所有 id 导入。 ### 2. 回放按首次调用顺序将活跃会话绑定到录制脚本 -嵌套场景录制不止一份日志:父会话(`session.jsonl`)加每个 subagent 子会话各一份(`session.1.jsonl`、……)。`dsh-llm-replay` 全部加载,为每个录制会话推导一份脚本,并按 header 中的 `createdAt` 排序(父会话先于子会话创建)。 +嵌套场景录制多份日志:父会话(`session.jsonl`)加每个 subagent 子会话各一份(`session.1.jsonl`……)。`dsh-llm-replay` 全部加载,为每个录制会话派生一份脚本,并按 header 中的 `createdAt` 排序(父会话先于子会话创建)。 -活跃会话 id 每次运行都是全新随机值,永远不等于录制时的 id,因此活跃会话无法通过 id 相等绑定脚本。取而代之的是**首次调用顺序**绑定:第一个发起模型调用的活跃会话认领排序第一的脚本(即父会话——`createdAt` 最早,且必然最先流式输出,因为它必须先运行一个轮次才能委派),下一个新活跃会话认领下一份脚本,依此类推。之后每个会话独立推进自己的游标。 +活跃会话 id 每次运行都是全新随机值,永远不等于录制时的 id,因此活跃会话无法通过 id 相等绑定到脚本。取而代之的是**首次调用顺序**绑定:第一个发起任何模型调用的活跃会话认领第一份有序脚本(即父会话:`createdAt` 最早,且必然最先流式输出,因为它必须先运行一个轮次才能委派),下一个新活跃会话认领下一份脚本,依此类推。此后每个会话独立推进自己的游标。 -这按**谁在调用**键控,而非按全局调用顺序——因此即使 subagent 将来并发运行或在后台运行也保持正确(全局游标会导致交错)。不携带 `sessionId` 的调用(直接在单元测试中调用 `stream()`)被视为一个匿名会话、绑定到主脚本,因此单会话路径的行为与旧版逐字节一致。活跃会话数多于录制脚本数是一个 fail-loud 错误(出现了未录制的 subagent),绝不会静默误路由。 +这种方式按**谁在调用**键控,而非按全局调用顺序。因此即使 subagent 将来并发或在后台运行(全局游标会导致交错),它仍然正确。不携带 `sessionId` 的调用(直接在单元测试中调用 `stream()`)被视为一个匿名会话、绑定到主脚本,因此单会话路径与旧行为逐字节一致。活跃会话数多于录制脚本数时会快速失败报错(出现了未录制的 subagent),绝不会静默错误路由。 -子 fixture 按 `createdAt` 排序,在兄弟会话严格顺序执行时与调用顺序一致。id 平局打破只是让退化碰撞确定化。并发或后台子会话必须引入显式的首次调用序号,而非依赖时间戳。 +子 fixture(测试前置数据)按 `createdAt` 排序,在兄弟会话严格顺序执行时与调用顺序一致。id 平局打破仅使退化碰撞具有确定性。并发或后台子会话必须引入显式的首次调用序号,而非依赖时间戳。 ## 曾考虑的替代方案 -曾考虑并否决的方案是将父子日志**按调用顺序合并**为一份全局脚本(仅在进程内 subagent 严格嵌套执行——父 agent 阻塞等待子 agent——时才正确)。对当前的同步切面更简单,但把「父阻塞于子」这一不变式烤死了;未来的后台/并发 subagent 会打破它,而逐会话键控不会。 +曾考虑但否决的方案是:**将父子日志按调用顺序合并**为一份全局脚本(仅在进程内 subagent 执行严格嵌套——父 agent 阻塞等待子 agent——时才正确)。对当前的同步裁剪而言更简单,但将「父阻塞于子」这一不变式固化了进去;未来若引入后台/并发 subagent 就会失效。逐会话键控则不会。 -### 3. harness 收割所有日志,主会话优先 +### 3. harness 收集所有日志,主会话优先 -`harvestSessionLogs` 收集 sessions 根目录下每个 cwd bucket 中的所有 `.jsonl`(JSONL 后端将父会话与同 cwd 的子会话放在同一 bucket),解析各自的 header,并按主会话优先排序:顶层会话(无 `parentSession`)在前,子会话按 `createdAt` 升序排列。`RunResult.sessionLogs` 是复数结果;spec 在录制时将每份日志写回 fixture(`session.jsonl` + `session.<n>.jsonl`),在回放时将每份收割的日志与对应 fixture 做 diff。归一化器已接受复数会话 id 并折叠任何游离 UUID,因此无需修改归一化器。 +`harvestSessionLogs` 收集 sessions 根目录下每个 cwd bucket 中的所有 `.jsonl`(JSONL 后端将父会话与同 cwd 的子会话放在同一个 bucket),解析各自的 header,并按主会话优先排序:顶层会话(无 `parentSession`)在前,各子会话按 `createdAt` 升序排列。`RunResult.sessionLogs` 是复数结果;spec 在录制时将每份日志写回对应 fixture(`session.jsonl` + `session.<n>.jsonl`),在回放时将每份收集到的日志与其 fixture 做 diff。归一化器已支持复数会话 id 并会折叠任何游离 UUID,因此无需修改归一化器。 ### 4. 场景 新增两个嵌套场景,均对真实 API 录制: -- **`subagent-spawn`**:父 agent 通过 `subagent` 工具将一个子任务委派给一个新 spawn 子会话(2 个会话)。 -- **`subagent-multi`**:父 agent 委派两个子任务,各自交给独立的 spawn 子会话(3 个会话),以三份并行脚本和同一父会话下两个子会话的 `createdAt` 排序来压测逐会话键控。 +- **`subagent-spawn`**:父 agent 通过 `subagent` 工具将一个子任务委派给一个新 spawn 的子 agent(2 个会话)。 +- **`subagent-multi`**:父 agent 委派两个子任务,各自交给自己的 spawn 子 agent(3 个会话),以三份并行脚本和同一父 agent 下两个子会话的 `createdAt` 排序来压测逐会话键控。 两者均在默认门禁中以 keyless 方式回放。 ## 后果 -- `TODO(subagent-snapshots)` 延期项已解决:嵌套 agent transcript 现在是快照的一等形态。 -- `GenerateOptions.sessionId` 是一个小而诚实的 core-seam 新增,在回放之外也有用(遥测、请求路由)。 -- `subagent` 工具绑定到单一提供方,因此 `subagent-multi` 中的两个子会话都是 spawn(全新)。键控按会话路由而非按后端路由,因此对 fork 也已正确。但脚本*推导*并非如此:fork 子会话的日志以种子化的父前缀(父会话的 `assistant/chunk` 事件)开头,从整份日志推导脚本会把父会话的响应当作子会话的来回放。这一正确性缺口通过持久化种子边界来弥合——见 [Persist the seed boundary so fork-child replay routes correctly](2026-06-22-fork-child-replay-seed-boundary.md)——录制的 fork 与混合 spawn+fork 场景现在通过一份 transcript 同时验证两种传输方式(见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md))。 -- 进程外(ACP)subagent 是完全不同的回放形态(每个子 agent 是独立进程、有自己的 replay),作为 `TODO(acp-subagent-replay)` 记录在 PR3 计划中。 +- `TODO(subagent-snapshots)` 延期项已解决:嵌套 agent 的 transcript 现在是快照层的一等形态。 +- `GenerateOptions.sessionId` 是一个小而诚实的 core-seam 新增,在回放之外同样有用(遥测、请求路由)。 +- `subagent` 工具绑定到单一提供方,因此 `subagent-multi` 中的两个子 agent 都是 spawn(全新创建)。键控按会话路由而非按后端路由,因此对 fork 同样正确。但脚本**派生**逻辑此前不正确:fork 子会话的日志以种子化的父前缀(父会话的 `assistant/chunk` 事件)开头,如果从完整日志派生脚本,就会把父 agent 的响应当作子 agent 的来回放。这一正确性缺口通过持久化种子边界来弥合——见 [Persist the seed boundary so fork-child replay routes correctly](2026-06-22-fork-child-replay-seed-boundary.md)——录制的 fork 与混合 spawn+fork 场景现在通过一份 transcript 同时验证两种传输方式(见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md))。 +- 进程外(ACP)subagent 是完全不同的回放形态(每个子 agent 是自己的进程、有自己的回放),作为 `TODO(acp-subagent-replay)` 记录在 PR3 计划中。 diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml index 10cfb7320c..a0daca4800 100644 --- a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-hook-snapshot-matrix.md: 8505e82fb681975c7506102a3eb858a29ccc11c8 -2026-07-04-hook-snapshot-matrix.zh.md: 6bd4b65b6ba2e16f8433fb0e67ae7ca4eb6a470e +2026-07-04-hook-snapshot-matrix.zh.md: 9a9f085400e938bc15c171f652d65f7bcdfa518f diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md index 6bd4b65b6b..9a9f085400 100644 --- a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md @@ -1,4 +1,4 @@ -# RFC:钩子快照矩阵——覆盖两种桥接的端到端金标测试 +# RFC:Hook 快照矩阵——覆盖两种 bridge 的端到端 golden 测试 Status: implemented @@ -6,45 +6,45 @@ Status: implemented ## 问题 -钩子桥接——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude)(7 个 Claude Code 钩子点)与 [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex)(5 个 Codex 钩子点)——将外部钩子命令映射到 harness 的拦截 seam 上。它们拥有深度的单元测试与覆盖率规格覆盖(每个决策分支、每种 payload 方言,均对 mock seam 驱动),外加一个需要密钥的 e2e 测试(`hooks.e2e.ts`,一次真实的 `PreToolUse` 拦截)。但全 transcript(文本记录)快照层——那张真正启动 `acp-agent` 子进程、无密钥回放录制会话、并将归一化的 ACP stdout 与重新持久化的日志对比已提交金标的网——只覆盖了**一个**钩子:Claude 的 `UserPromptSubmit` 拦截(`hook-cc-promptsubmit-block`)。 +hook bridge——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude)(7 个 Claude Code hook 点)和 [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex)(5 个 Codex 点)——将外部 hook 命令映射到 harness 的拦截 seam 上。它们拥有深度的单元测试和 coverage-spec 覆盖率(每个决策分支、每种 payload 方言,均对 mock 的 seam 驱动),外加一个需要密钥的 e2e 测试(`hooks.e2e.ts`,一次真实的 `PreToolUse` 拦截)。但完整 transcript(文本记录)快照层:那张真正启动 `acp-agent` 子进程、无密钥回放录制会话、并将规范化的 ACP stdout 与重新持久化的日志与已提交 golden 做 diff 的网,只覆盖了**一个** hook:Claude 的 `UserPromptSubmit` 拦截(`hook-cc-promptsubmit-block`)。 -这正是 mock 单元测试在结构上无法替代的层级:它让真实的桥接翻译真实钩子进程的结果,送入真实的 seam 决策,再由真实的 agent loop(智能体循环)做出反应,渲染结果与编辑器所见完全一致。一个桥接翻译或循环结构的回归,即使让所有单元测试保持绿色,也会在除那一个钩子点之外的所有点上逃逸——而对于 Codex 桥接,ACP 示例甚至没有加载它,因此没有任何 Codex 钩子能端到端触发。 +这正是 mock 单元测试在结构上无法替代的层级:它验证的是真实 bridge 将真实 hook 进程的结果翻译到真实 seam 决策,再到真实 agent loop(智能体循环)的反应,渲染结果与编辑器看到的完全一致。一个 bridge 翻译或 loop 结构的回归,即使让所有单元测试保持绿色,也会在除那一个 hook 点之外的所有点上逃逸;而对于 Codex bridge,ACP 示例甚至没有加载它,因此没有任何 Codex hook 能端到端触发。 ## 决策 实现由两个耦合部分组成: -### 1. ACP 示例同时加载两种钩子桥接 +### 1. ACP 示例同时加载两种 hook bridge -`examples/acp-agent/cordis.yml` 与 `cordis.snapshot.yml` 现在在 `dsh-hooks-claude` 之外同时加载 `dsh-hooks-codex`,各自指向自己的配置文件(Claude 用 `./hooks.json`,Codex 用 `./codex-hooks.json`——两种方言无法共用一个文件)。这是一个真正的产品表面变更,而非仅测试用的接线:交付的 ACP 服务器(以及 `demo:acp` 入口)现在同时携带两种桥接。 +`examples/acp-agent/cordis.yml` 和 `cordis.snapshot.yml` 现在同时加载 `dsh-hooks-codex` 与 `dsh-hooks-claude`,各自指向自己的配置文件(Claude 用 `./hooks.json`,Codex 用 `./codex-hooks.json`——两种方言无法共用一个文件)。这是一个真正的产品接口变更,而非仅用于测试的接线:交付的 ACP 服务器(以及 `demo:acp` 入口)现在同时携带两种 bridge。 -这是安全的,因为配置文件不存在时桥接是**静默空操作**:`apply()` 捕获读取失败、通过 `ctx.logger` 记录日志、不注册任何东西——零监听器、零会话事件。`acp-agent` 应用不挂载 stdout logger,因此该警告不会到达 ACP JSON-RPC 通道。只需要 Claude 钩子的场景(或真实项目)只提供 `hooks.json`;Codex 桥接找不到 `codex-hooks.json` 便自行消失。这已通过实验验证:两种桥接同时加载时,所有既有快照(均未提供 `codex-hooks.json`)逐字节一致。 +这是安全的,因为配置文件不存在时 bridge 是**静默无操作**的:`apply()` 捕获读取失败、通过 `ctx.logger` 记录日志、不注册任何东西——零监听器、零会话事件。`acp-agent` 应用不附带 stdout logger,因此警告不会到达 ACP JSON-RPC 通道。只需要 Claude hook 的场景(或真实项目)只提供 `hooks.json`;Codex bridge 找不到 `codex-hooks.json` 便自动消失。这已通过实验验证:在两种 bridge 同时加载的情况下,所有既有快照(均不附带 `codex-hooks.json`)逐字节一致。 -同时加载是让快照层能够在产品交付的同一个真实应用上对每种方言进行测试的最低要求。录制(启动 `cordis.yml`)天然加载两者,回放以同样方式继承:`cordis.snapshot.yml` 是 `cordis.yml` 的 include-overlay,仅替换 llm 条目(见 [single-source the acp-agent replay config](2026-07-04-single-source-acp-replay-config.md)),因此添加到运行时配置树的桥接无需第二次编辑即出现在回放树中。 +同时加载是让快照层能够在产品交付的同一个真实应用上验证每种方言的最低要求。录制(启动 `cordis.yml`)天然加载两者,回放以同样方式继承:`cordis.snapshot.yml` 是 `cordis.yml` 的 include-overlay,只替换 llm 入口(见[单一来源 acp-agent 回放配置](2026-07-04-single-source-acp-replay-config.md)),因此添加到运行时树的 bridge 无需第二次编辑即出现在回放树中。 -### 2. 每个钩子点 × 其标志性结果各一个快照场景,覆盖两种方言 +### 2. 每个 hook 点 × 其主要结果各一个快照场景,覆盖两种方言 `examples/acp-agent/tests/snapshots/` 下共 13 个场景,命名为 `hook-<dialect>-<point>-<outcome>`: - **手工编写、无模型轮次**(无密钥、无 sidecar——派生的回放脚本为空;比对的是携带 `hook/*` 事件的 `rejected` 轮次):`hook-cc-promptsubmit-block`、`hook-codex-promptsubmit-block`。 -- **对真实 API 录制、录制期间钩子活跃**(模型对决策的反应是捕获的 transcript 的一部分,此后无密钥回放):`hook-{cc,codex}-promptsubmit-context`(allow + additionalContext 折叠)、`hook-cc-pretool-deny` / `hook-codex-pretool-block`(deny → `isError` 工具结果)、`hook-cc-pretool-ask`(ask → 降级为 deny 并附带 approval-required 原因)、`hook-{cc,codex}-posttool-block`(block 并附反馈)、`hook-{cc,codex}-posttool-context`(accept + additionalContext)、`hook-{cc,codex}-stop-continue`(阻塞式 Stop 钩子通过 steering(中途引导)强制多走一步)。 +- **对真实 API 录制、录制期间 hook 活跃**(模型对决策的反应是捕获的 transcript 的一部分,此后无密钥回放):`hook-{cc,codex}-promptsubmit-context`(allow + additionalContext 折叠)、`hook-cc-pretool-deny` / `hook-codex-pretool-block`(deny → `isError` 工具结果)、`hook-cc-pretool-ask`(ask → 降级为 deny 并附带 approval-required 原因)、`hook-{cc,codex}-posttool-block`(block 并附带反馈)、`hook-{cc,codex}-posttool-context`(accept + additionalContext)、`hook-{cc,codex}-stop-continue`(阻塞性 Stop hook 通过 steering(中途引导)强制多走一步)。 -每个钩子命令只输出**固定字面字符串**(无时间戳/pid/`$RANDOM`/cwd 回显);快照归一化器擦除 `hook/result` 携带的唯一易变字段(`durationMs`)。`Stop` 场景通过标记文件(`.stop_fired`)自限,使 force-continue 不会循环——`stop_hook_active` 循环守卫仍是桥接的一个 `TODO`,因此无条件的 Stop 钩子会对每一步都 force-continue。 +每个 hook 命令只输出**固定字面量字符串**(无时间戳/pid/`$RANDOM`/cwd 回显);快照规范化器擦除 `hook/result` 携带的唯一不稳定字段(`durationMs`)。`Stop` 场景通过标记文件(`.stop_fired`)自限,使 force-continue 不会循环——`stop_hook_active` 循环守卫仍是 bridge 的一个 `TODO`,因此无条件的 Stop hook 会在每一步都 force-continue。 -### 三个钩子点被有意排除在快照之外 +### 三个 hook 点被有意排除在快照之外 -在构建矩阵过程中发现,记录在此是因为这是一个决策而非疏漏: +在构建矩阵过程中发现,记录于此是因为这些遗漏是决策而非疏忽: -- **`SessionStart` 与 `SubagentStart`** 通过一个分离的、尽力而为的 `void runPoint(...).then(agent.inject())` 注入上下文,**没有轮次绑定**。产生的 `context/message` 与它所先于的工作(首次模型请求/子 agent 的首轮)存在竞争,落在日志中的位置不确定。录制的金标甚至在自身回放时都无法复现——10 次回放稳定性检查对两者均 10/10 失败。它们留在桥接的单元覆盖中,单元测试直接驱动 seam 而无时序竞争。(如果注入将来变为轮次绑定且确定性的——`TODO(session-start-gating)` 所指的方向——这些点就可以纳入快照。) -- **`SubagentStop`** 是纯观察:其 `subagent/end` 处理器不传递轮次(因此无 `hook/*` 日志事件)、不做注入。它对 transcript **什么都不写**,因此金标会与无钩子运行逐字节一致,永远无法被证明失败——一道咬不到人的守卫。它留在单元覆盖中(`bridge.spec.ts` 已断言该纯观察调用)。 +- **`SessionStart` 与 `SubagentStart`** 通过一个分离的、尽力而为的 `void runPoint(...).then(agent.inject())` 注入上下文,**没有**轮次绑定。由此产生的 `context/message` 与它所先于的工作(首次模型请求/子 agent 的首轮)存在竞争,落在日志中的位置不确定。录制的 golden 甚至无法在自身回放中复现——10 次回放稳定性检查对两者均 10/10 失败。它们留在 bridge 的单元覆盖率中,单元测试直接驱动 seam 而无时序竞争。(如果注入将来变为轮次绑定且确定性的——`TODO(session-start-gating)` 所指的方向——它们就可以纳入快照。) +- **`SubagentStop`** 是纯观察性的:其 `subagent/end` 处理器不传递轮次(因此无 `hook/*` 日志事件)、不做注入。它对 transcript **不写入任何内容**,因此 golden 与无 hook 运行逐字节一致,永远无法被证明失败——一道永远不会触发的守卫。它留在单元覆盖率中(`bridge.spec.ts` 已断言了纯观察调用)。 -因此该矩阵覆盖了所有具有**确定性、可观测 transcript 足迹**的钩子点,涵盖两种方言。 +因此,该矩阵覆盖了所有具有**确定性、可观测** transcript 足迹的 hook 点,涵盖两种方言。 ## 后果 -- 每个具有可观测 transcript 的桥接 seam 映射现在都在全 transcript 层、在真实应用中、为两种方言设有守卫——包括此前完全没有端到端覆盖的 Codex 桥接。录制的金标捕获了模型对 denied/blocked/force-continued 轮次的真实反应,这是手工编写的 transcript 只能猜测的。 -- block 场景无需密钥(无模型轮次);其余场景从录制的 fixture(测试前置数据)无密钥回放。`pnpm run test:snapshot:record` 从真实 API 重新生成录制的 fixture,无密钥时像所有录制场景一样自动跳过。 -- prove-red 纪律成立:篡改钩子配置的输出(例如修改 deny 原因)会使其场景在回放时变红——钩子进程在回放期间**真实运行**(只有模型被回放),因此金标守卫的是实际的 hook→seam→loop 路径,而非它的 mock。 -- `acp-agent` 演示现在加载了一个通常会空操作的 Codex 桥接(典型项目中没有 `codex-hooks.json`),这正是预期的 fail-soft 行为,而非代价。 +- 每个具有可观测 transcript 的 bridge seam 映射现在都在完整 transcript 层级、在真实应用中、对两种方言受到守护——包括此前完全没有端到端覆盖率的 Codex bridge。录制的 golden 捕获了模型对 deny/block/force-continue 轮次的真实反应,这是手工编写的 transcript 只能猜测的。 +- block 场景无需密钥(无模型轮次);其余场景从录制的 fixture(测试前置数据)无密钥回放。`pnpm run test:snapshot:record` 从真实 API 重新生成录制的 fixture,无密钥时自动跳过,与所有录制场景一致。 +- prove-red 纪律成立:篡改 hook 配置的输出(例如修改 deny 原因)会使其场景在回放时变红——hook 进程在回放期间**真实运行**(只有模型被回放),因此 golden 守护的是实际的 hook→seam→loop 路径,而非它的 mock。 +- `acp-agent` 演示现在加载了一个通常会无操作的 Codex bridge(典型项目中没有 `codex-hooks.json`),这正是预期的柔性失败行为,而非代价。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml index 642ba7f9ad..4aa9340c22 100644 --- a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-single-source-acp-replay-config.md: 922bdcced50f8e289449e05b51774f202228b0f8 -2026-07-04-single-source-acp-replay-config.zh.md: d27ea0d3b7227f0fb5f349478591962dd5fe8030 +2026-07-04-single-source-acp-replay-config.zh.md: b347186f362fa5454f7bd5106c2e261cb8a00b61 diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md index d27ea0d3b7..b347186f36 100644 --- a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md @@ -1,27 +1,27 @@ -# RFC:将 acp-agent 回放配置收归单一来源 - -Status: implemented +# RFC:将 acp-agent 回放配置改为单一来源 [English](2026-07-04-single-source-acp-replay-config.md) | 中文 +Status: implemented + ## 问题 -`examples/acp-agent` 曾维护两份手写配置:`cordis.yml`(线上树)和一份 `cordis.snapshot.yml`,后者逐条镜像前者、仅替换 LLM 后端。去掉注释后,全部差异只是八行 `llm-deepseek` 段落换成两行 `llm-replay` 段落。每次应用形态变更都要改两遍,且没有门禁保证对称性:如果两份副本漂移,快照层会静默地测试一个与实际交付不同的应用——正是快照层本身要消除的[「单元全绿、产品却坏」类缺口](../../../postmortem/0001-acp-default-export-drops-inject.md),在更高一层被重新引入,唯一的防线是评审者的警觉。 +`examples/acp-agent` 曾维护两份手写配置:`cordis.yml`(正式运行树)和 `cordis.snapshot.yml`(逐条镜像前者,仅替换 LLM(大语言模型)后端)。去掉注释后,全部差异只是八行的 `llm-deepseek` 段落换成两行的 `llm-replay` 段落。每次应用结构变更都要改两遍,且没有门禁保障对称性:一旦两份副本漂移,快照层就会悄悄测试一个与实际交付不同的应用——正是快照层本要消除的["单元测试全绿、产品却坏了"这类缺口](../../../postmortem/0001-acp-default-export-drops-inject.md),在上一层被重新引入,唯一的防线是评审者的警觉。 ## 决策 -`cordis.snapshot.yml` include 线上配置,按 id 和 name 禁用指定的 DeepSeek 适配器,并插入回放适配器。因此除此之外的所有条目均来自交付树。回放时选择 overlay;录制仍然启动 `cordis.yml`,加载守卫允许被有意禁用的条目。 +`cordis.snapshot.yml` include 正式配置,通过 id 和 name 禁用指定的 DeepSeek 适配器,并插入回放适配器。其余所有条目因此来自正式运行树。回放时选择 overlay;录制仍然启动 `cordis.yml`,加载守卫允许被有意禁用的条目。 -overlay 依赖的一个 vendor 插件事实(有意为之):include 在加载文件时应用 `patches`——其 `refresh()`/`internal/update` 路径重读时不重新打补丁——这恰好满足一次性回放启动的需要(回放应用不加载 `hmr`,也没有东西在运行中改写配置)。快照套件即为证明:所有场景在 overlay 上原样通过,包括逐字节一致的 golden 文件。 +overlay 依赖一个 vendor 插件的事实,这是有意为之:include 在加载文件时应用 `patches`,其 `refresh()`/`internal/update` 路径重读时不会重新打补丁。这恰好满足一次性回放启动的需要(回放应用不加载 `hmr`,也没有东西在运行中改写配置)。快照套件即为证明:所有场景在 overlay 上原样通过,包括逐字节一致的 golden 文件。 ## 曾考虑的替代方案 -### 为什么不选这些方案? +### 为何不采用这些替代方案? -保留完整的双份配置并加一道对称性校验门禁是记录在案的兜底方案——它能消除静默漂移这一类问题,但仍保留一份 125 行的近似副本,其全部内容只是一个条目的差异,且随应用每增加一个插件而增长。在 bin 侧做替换(解析配置、替换条目、删除文件)会把 YAML 手术放进发布产物,并将回放差异移出视野;overlay 方案让差异保持声明式、可读、且紧邻基础配置——这正是双份配置的支持者真正想要的教学价值。 +保留完整的双副本并加一道对称性校验门禁是记录在案的退路——它能消除静默漂移这一类问题,但仍保留一份 125 行的近乎复制品,其全部内容只是一个条目的差异,且随应用每增加一个插件而增长。在 bin 侧做替换(解析配置、替换条目、删除文件)则会把 YAML 手术放进发布产物,并把回放差异藏到视线之外;overlay 让差异保持声明式、可读,且紧邻基础配置——这正是双副本支持者真正看重的教学价值。 ## 后果 -- 向 `cordis.yml` 添加的插件无需第二次编辑即进入回放树;漂移类问题从结构上消除,而非仅靠门禁拦截。 -- overlay 依赖条目携带稳定的 `id:`。禁用补丁上的 `name` 断言防止误定位(id 被复用时补丁跳过而非禁用错误的插件)。id **重命名**会使补丁退化为跳过,其警告需要一个回放应用有意不具备的 logger——可观察的结果是一条无用的无密钥 `llm-deepseek` 条目与 `llm-replay` 并存,回放输出仍然正确(`llm-replay` 拥有流的短路权);这属于留给评审发现的配置腐烂,而非错误的快照。顶层插入的条目若 id 与已有条目冲突,通过 loader 的 id map 以 last-wins 解析——当前配置无冲突,新增补丁行才是引入冲突的位置。 -- 如果未来回放树需要第二处分歧(另一个后端被替换),只需多加一行补丁,而非再 fork 一份文件。 +- 向 `cordis.yml` 添加插件即自动进入回放树,无需第二次编辑;漂移这一类问题从结构上消失,而非靠门禁拦截。 +- overlay 依赖条目携带稳定的 `id:`。禁用补丁上的 `name` 断言防止误定位(id 被复用时补丁跳过而非禁用错误的插件)。如果 id 被**重命名**,补丁退化为跳过,其警告需要一个回放应用有意不具备的 logger——可观测结果是一条无效的无密钥 `llm-deepseek` 条目与 `llm-replay` 并存,回放输出仍然正确(`llm-replay` 拥有流的短路权);这属于配置腐烂,留给评审发现,不会产生错误的快照。顶层插入一个 id 与既有条目冲突的新条目时,loader 的 id map 以后者为准;当前配置无冲突,新增补丁行才是引入冲突的场所。 +- 如果未来回放树需要第二处差异(另一个后端被替换),只需多加一行补丁,而非再 fork 一份文件。 diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml index 3ee0a6df6d..3b2d92e28c 100644 --- a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-06-pin-request-header-content-in-one-scenario.md: 5ccaa23a268114c5ba37ec153f4960b47df13bfd -2026-07-06-pin-request-header-content-in-one-scenario.zh.md: f5ef5e056bb2c05d14ed71315f31c962237db72c +2026-07-06-pin-request-header-content-in-one-scenario.zh.md: 909968430dc3e648e09eeeedd47436c35b90b870 diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md index f5ef5e056b..909968430d 100644 --- a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md @@ -1,35 +1,35 @@ -# RFC:在单一快照场景中固定 request-header 内容 - -[English](2026-07-06-pin-request-header-content-in-one-scenario.md) | 中文 +# RFC:在单个快照场景中固定请求头内容 Status: implemented +[English](2026-07-06-pin-request-header-content-in-one-scenario.md) | 中文 + ## 问题 -ACP(Agent Client Protocol)快照测试套件需要证明每个 `request/header` 中实际发送的组合系统提示词和工具 schema 列表,但如果在每个 `session.jsonl` 中重复这些内容,一次提示词或 schema 编辑就会改写数十条巨大的单行 JSON 记录。保留一份原始 header 可以避免重复,但提示词的评审体验仍然很差:行文被 JSON 转义到一行里,与数千字符的工具 schema 混在一起。 +一个 ACP(Agent Client Protocol)快照测试套件需要证明每个 `request/header` 中实际发送的组合系统提示词与工具 schema 列表,但如果在每个 `session.jsonl` 中重复这些内容,一次提示词或 schema 编辑就会改写数十条巨大的单行 JSON 记录。保留一份原始 header 可以避免重复,但提示词的评审体验仍然很差:行文被 JSON 转义到一行中,与数千字符的工具 schema 混在一起。 ## 决策 -每个 header 组合类别恰好有一个场景被标记为 `pinsHeader`。其目录按评审格式拆分固定内容:`system-prompt.golden.md` 以普通 Markdown 存放归一化后的组合提示词,`tool-schemas.golden.json` 以结构化 JSON 存放完整的初始 schema 及后续 schema 变更,`session.jsonl` 保留 config、reason 和任何模型可见的前缀,同时将 `header.system` 和 `header.tools` 存为 `"{{system}}"` / `"{{tools}}"`。其余所有 JSONL 使用相同的提示词和工具 token,并同样对 session-prefix 内容做 token 化。固定机制实现在 [`dsh-acp-snapshot`](../../../../packages/support/acp-snapshot/README.md) 中,其套件工厂强制每个类别只有一个 pin。 +每个 header 组合类别恰好有一个场景被标记为 `pinsHeader`。其目录按评审格式拆分固定内容:`system-prompt.golden.md` 以普通 Markdown 存放归一化后的组合提示词,`tool-schemas.golden.json` 以结构化 JSON 存放完整的初始 schema 及后续 schema 变更,而 `session.jsonl` 保留 config、reason 及任何模型可见的前缀,同时将 `header.system` 和 `header.tools` 存为 `"{{system}}"` / `"{{tools}}"`。其余所有 JSONL 使用相同的提示词和工具 token,并同样对会话前缀内容做 token 化处理。固定机制实现在 [`dsh-acp-snapshot`](../../../../packages/support/acp-snapshot/README.md) 中,其套件工厂强制每个类别只有一个固定场景。 -纯净的 `scrubSystemPrompts` 和 `scrubToolSchemas` 归一化器应用于所有存储的 session fixture(测试前置数据),独立地对初始 header 内容和 header-delta 批量内容做 token 化。`scrubRequestHeaders` 还为非固定场景对 session-prefix 内容做 token 化,同时保留结构性事实:system-delta 的位置与数量、增删改的工具名称、前缀消息数量、字段存在性、config 和 reason。record 和 refresh 的回写操作在写入 JSONL 前应用相应的 scrub,并从归一化的实时 header 和 delta 重新生成两个 sidecar 文件,因此两条路径都不会将提示词/schema 批量内容重新引入 JSONL,也不会让评审产物变陈旧。 +纯粹的 `scrubSystemPrompts` 和 `scrubToolSchemas` 归一化器应用于每个存储的会话 fixture(测试前置数据),独立地对初始 header 内容和 header-delta 批量内容做 token 化。`scrubRequestHeaders` 还为非固定场景的会话前缀内容做 token 化,同时保留结构性事实:system-delta 的位置与数量、新增/移除/变更的工具名称、前缀消息数量、字段存在性、config 和 reason。record 与 refresh 的回写操作在写入 JSONL 前应用相应的 scrub,并从归一化后的实时 header 和 delta 重新生成两个 sidecar 文件,因此两条路径都不会把提示词/schema 批量内容重新引入 JSONL,也不会让评审产物变陈旧。 -守卫使这一拆分自我强制。在磁盘上:每个 `session*.jsonl` 都是提示词和 schema 两个 scrubber 的不动点;只有非固定 fixture(测试前置数据)还必须是完整 header scrub 的不动点;两个 sidecar 恰好存在于固定 fixture 旁边,采用规范的换行终止格式;每个类别有且仅有一个 pin。在运行时:由 parent、spawn 子进程、fork 子进程、初始请求或恢复产生的每个 `request/header`,在易变值归一化后必须与重建的 pin 匹配;固定运行的提示词和 schema delta 也必须与其 sidecar 匹配。如果 header 缺少字符串类型的 prompt、缺少数组类型的工具列表,或出现未声明的 `request/header-delta`,则立即报错。 +守卫机制使这一拆分自我强制。在磁盘上:每个 `session*.jsonl` 都是提示词和 schema 两个 scrubber 的不动点;只有非固定 fixture 还必须是完整 header scrub 的不动点;两个 sidecar 文件恰好存在于固定 fixture 旁边,采用规范的换行终止格式;每个类别有且仅有一个固定场景。在运行时:由 parent、spawn 子会话、fork 子会话、初始请求或 resume 产生的每个 `request/header`,在经过易变值归一化后必须与重建的固定内容匹配;固定运行的提示词和 schema delta 也必须与其 sidecar 匹配。如果 header 没有字符串类型的 prompt、没有数组类型的工具列表,或包含未声明的 `request/header-delta`,则立即失败并报错。 -一个 pin 覆盖整个套件,因为每个会话(parent、spawn 子进程、fork 子进程)组合出的工具列表完全相同、提示词除 cwd 外完全相同,而一致性守卫会在这一前提不再成立时立即使套件失败。如果 header 组合在设计上变为会话相关的(例如受限的 subagent 工具集),则分化出的形状获得自己的固定场景。 +一个固定场景覆盖整个套件,因为每个会话(parent、spawn 子会话、fork 子会话)组合出的工具列表完全相同、提示词除 cwd 外完全相同,而一致性守卫会在这一前提不再成立时立即使套件失败。如果 header 组合将来在设计上变为会话相关的(例如受限的 subagent 工具集),那么分歧的形态将获得自己的固定场景。 ## 曾考虑的替代方案 - **每次变更重新录制或手动编辑所有 fixture**:保留了精确的 header,但行为差异被重复的提示词和 schema 内容淹没。 -- **仅在比较时 scrub,fixture 保持原始状态**:比较能通过,但已提交的 fixture 保留着陈旧的重复内容,下次录制时整体改写。存储 token 诚实地表明每个 JSONL 没有固定什么。 -- **全部 scrub,不做任何固定**:丢失了组合 header 实际发送内容(提示词组装、已注册工具顺序、完整 schema)的唯一端到端记录。生成的工具目录只孤立地记录每个工具;只有真实 fixture 能固定组合后的完整集合。 -- **将完整的 pin 全部保留在 JSONL 中**:消除了套件级重复,但提示词和 schema 变更仍然表现为一行转义文本。Markdown 和结构化 JSON 为各自的内容提供了自然的评审格式,同时不削弱重建 header 的断言。 -- **精简会话日志本身(记录内容摘要,header 存到别处)**:违反可重建契约:产品日志必须逐比特重现每个请求(见[可重建请求 RFC](../architecture/2026-07-05-reconstructable-requests.md))。header 体积是测试产物的问题,在测试归一化中解决;线上日志不受影响。 +- **仅在比较时 scrub,fixture 保持原始内容**:比较能通过,但已提交的 fixture 保留着陈旧的重复内容,下次录制时会整体重写。存储 token 诚实地表明每个 JSONL 没有固定什么。 +- **全部 scrub,不做任何固定**:丢失了组合 header 实际发送内容(提示词组装、已注册工具顺序、完整 schema)的唯一端到端记录。生成的工具目录只孤立地记录每个工具;只有真实 fixture 才能固定组合后的完整集合。 +- **将完整固定内容全部保留在 JSONL 中**:消除了套件范围的重复,但提示词和 schema 变更仍然是一行转义文本。Markdown 和结构化 JSON 为每种内容提供其自然的评审格式,同时不削弱重建 header 的断言。 +- **精简会话日志本身(记录内容摘要,将 header 存放在别处)**:违反可重建性契约:产品日志必须逐位重现每个请求([可重建请求 RFC](../architecture/2026-07-05-reconstructable-requests.md))。header 体积是测试产物的问题,在测试归一化中解决;线上日志不受影响。 ## 验证 -套件针对拆分后的 pin 回放每个场景。单元覆盖率检验独立 scrubber 和完整 scrubber、两种 sidecar 格式、record/refresh 重新生成、归一化的提示词/schema 提取、不动点强制、必需文件对称性、重建 header 的一致性,以及 delta 拒绝。 +套件针对拆分后的固定内容回放每个场景。单元测试覆盖率涵盖独立 scrubber 和完整 scrubber、两种 sidecar 格式、record/refresh 重新生成、归一化提示词/schema 提取、不动点强制、必需文件对称性、重建 header 一致性以及 delta 拒绝。 ## 后果 -系统提示词的变更在每个受影响的组合类别中产生一个面向行的 Markdown diff;工具描述的变更在每个类别中产生一个结构化 JSON diff;普通的行为 fixture 不受影响。session fixture 以 token 显示被省略的内容,运行时一致性守卫使每个拆分 pin 对其类别中的所有会话具有权威性。每个固定场景携带两个生成的、换行规范化的 sidecar 文件。 +系统提示词变更在每个受影响的组合类别中产生一个面向行的 Markdown diff;工具描述变更在每个类别中产生一个结构化 JSON diff;普通行为 fixture 不受影响。会话 fixture 对省略的内容显示 token,运行时一致性守卫使每个拆分固定场景对其类别内的所有会话具有权威性。每个固定场景携带两个生成的、换行规范化的 sidecar 文件。 diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml index d888da4d05..c582f34c23 100644 --- a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-08-shared-acp-snapshot-package.md: 81714191a704af1a9ed029fb8004deac88e39427 -2026-07-08-shared-acp-snapshot-package.zh.md: 2a7c3091c731ded61bed939c8ae0a323123daac9 +2026-07-08-shared-acp-snapshot-package.zh.md: f80c8e49e80e9bf287c84c0ff4fb00377fad5175 diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md index 2a7c3091c7..f80c8e49e8 100644 --- a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md @@ -1,38 +1,38 @@ -# RFC:将 ACP 快照测试套件提取为支持包 - -Status: implemented +# RFC:将 ACP 快照套件提取为支持包 [English](2026-07-08-shared-acp-snapshot-package.md) | 中文 +Status: implemented + ## 问题 -ACP 快照层([快照 RFC](2026-06-19-acp-snapshot-tests.md))由三个位于某个示例测试目录内的模块构成:`snapshot-harness.ts`(启动真实 bin 子进程、通过 ACP JSON-RPC 驱动它、收集持久化日志)、`snapshot-normalize.ts`(纯粹的 golden 归一化器),以及 `acp.snapshot.ts` 中约 150 行的场景主体与 fixture(测试前置数据)守卫(record/replay 模式、stdout-golden 与日志比对、pinned-header 一致性守卫、orphan/required-file/single-pin 元测试)。 +ACP 快照层([快照 RFC](2026-06-19-acp-snapshot-tests.md))由位于某个示例测试目录中的三个模块构成:`snapshot-harness.ts`(启动真实 bin 子进程,通过 ACP JSON-RPC 驱动它,收集持久化日志)、`snapshot-normalize.ts`(纯粹的 golden 规范化器),以及 `acp.snapshot.ts` 中约 150 行的场景主体加 fixture(测试前置数据)守卫(record/replay 模式、stdout-golden 与日志比对、pinned-header 一致性守卫、orphan/required-file/single-pin 元测试)。 -第二个 ACP 示例只能复制 record、归一化与收集逻辑,而这些逻辑必须保持一致。`examples/` 下的代码还处于包(package)覆盖率门禁之外,且原有 harness 只能取消权限请求。共享包使这些机制纳入度量,并允许场景脚本化地指定审批答案。 +第二个 ACP 示例只能复制 record、规范化和收集逻辑,而这些逻辑必须保持一致。`examples/` 下的代码也不在包(package)覆盖率门禁范围内,且原始 harness 只能取消权限请求。共享包使这些机制纳入度量,并允许场景脚本化地提供审批答案。 ## 决策 -机制代码位于 [`packages/support/acp-snapshot`](../../../../packages/support/acp-snapshot/README.md)(`@deepseek-ai/dsh-acp-snapshot`);示例的 `*.snapshot.ts` 只包含场景表、agent 路径和一次工厂调用,配合自己的 `snapshots/` fixture 与 `cordis.snapshot.yml` 覆盖层([单源 replay 配置](2026-07-04-single-source-acp-replay-config.md))。读取 `DSH_SNAPSHOT` 留在该边界——库接收的是已解析的 `mode`。 +这些机制位于 [`packages/support/acp-snapshot`](../../../../packages/support/acp-snapshot/README.md)(`@deepseek-ai/dsh-acp-snapshot`);示例的 `*.snapshot.ts` 只包含场景表、agent 路径和一次工厂调用,依赖自己的 `snapshots/` fixture 与 `cordis.snapshot.yml` overlay([单源 replay 配置](2026-07-04-single-source-acp-replay-config.md))。读取 `DSH_SNAPSHOT` 留在边缘层——库接收的是已解析的 `mode`。 -**`src/harness.ts`** 提供 `runScenario` 及其脚本/结果类型,以 agent 的 bin 路径和配置路径为参数。权限答案构成一个 FIFO 队列,按稳定的 option kind(而非随机的 option id)索引。缺少答案时取消该请求;不可用的 kind 取消 agent 请求并使场景失败。 +**`src/harness.ts`** 提供 `runScenario` 及其脚本/结果类型,以 agent 的 bin 和配置路径为参数。权限答案构成一个 FIFO 队列,以稳定的 option kind(而非随机的 option id)为键。缺少答案时取消该请求;不可用的 kind 取消 agent 请求并使场景失败。 -**`src/normalize.ts`**:纯归一化器,按策略不含钩子。当未来的事件携带新的易变字段(如审批耗时),共享归一化器在同一个变更中学会它,保持「归一化」的含义只有一个归属地,而非各套件各自扩展清洗逻辑。 +**`src/normalize.ts`** 是纯规范化器,按策略不含钩子:当未来某个事件携带新的易变字段(例如审批耗时),共享规范化器在同一个变更中学会它,保持「规范化」的含义只有一个归属,而非各套件各自扩展清洗逻辑。 -**`src/suite.ts`**:`Scenario` 类型与 `defineAcpSnapshotSuite(options)`,注册逐场景比对、record/refresh 的 fixture 回写、header pin 及其实时一致性守卫,以及 fixture 守卫块(无 orphan 场景目录、必需文件齐全、每个 class 恰好一个 pin、每个 JSONL 是 `scrubSystemPrompts` 的不动点、非 pinning 的 fixture 也是 `scrubRequestHeaders` 的不动点)。pinned-header 契约([pinned-header RFC](2026-07-06-pin-request-header-content-in-one-scenario.md))按套件生效:每个 header class 恰好标记一个 `pinsHeader` 场景,其 `system-prompt.golden.md` 与 JSONL 工具列表将组合后的 header 拆分为可评审的产物;一致性守卫将二者与该 class 中每个实时 header 进行比对。纯辅助函数(`childFixturePaths`、`fixtureContext`、`normalizedHeaders`、`normalizedSystemPrompts`、`formatSystemPromptSnapshot`、`headerDeltaCount`)从模块导出,以便直接进行单元覆盖。 +**`src/suite.ts`** 提供 `Scenario` 类型与 `defineAcpSnapshotSuite(options)`,注册逐场景比对、record/refresh 的 fixture 回写、header pin 及其实时一致性守卫,以及 fixture 守卫块(无 orphan 场景目录、必需文件齐全、每个 class 恰好一个 pin、每个 JSONL 是 `scrubSystemPrompts` 的不动点、非 pinning fixture 也是 `scrubRequestHeaders` 的不动点)。pinned-header 契约([pinned-header RFC](2026-07-06-pin-request-header-content-in-one-scenario.md))按套件划分:每个 header class 恰好标记一个 `pinsHeader` 场景,其 `system-prompt.golden.md` 与 JSONL 工具列表将组合后的 header 拆分为可评审的产物;一致性守卫将二者与该 class 中每个实时 header 进行比对。纯辅助函数(`childFixturePaths`、`fixtureContext`、`normalizedHeaders`、`normalizedSystemPrompts`、`formatSystemPromptSnapshot`、`headerDeltaCount`)从模块导出,以便直接进行单元覆盖。 ## 曾考虑的替代方案 -- **将模块复制到每个示例中**:正是本 RFC 要阻止的分叉。record/guard 逻辑恰恰是必须在各套件间逐字节一致的代码,而 examples 在覆盖率门禁之外,因此每份副本也无法被度量。 -- **在 `examples/` 下建共享模块目录**:代码仍在覆盖率门禁之外,且需要跨示例边界的相对导入,违背包名导入约定;`examples/` 的叶子节点按设计保持精简。 -- **在 `dsh-acp-demo` 中导出 `/testing` 子路径**:将测试基础设施耦合到产品包的公开接口与依赖集中;`packages/support/` 正是为真实但兼容性要求较低的开发/测试包而设,`dsh-llm-replay` 是先例,本包是其补全。 -- **导出原始测试体函数而非套件工厂**:每个示例将重新拥有 `describe`/`it` 骨架(每套件约 80 行注册样板),却无灵活性收益;工厂让消费方只需一张场景表加一次调用,导出的纯辅助函数在工厂设计内保留了单元可测性。 -- **可注入的 ACP `Client` 工厂取代声明式 `permissionAnswers`**:灵活性最大化,但将 SDK 客户端构造泄漏给每个消费方,并在正被统一的层面重新引入逐示例漂移;声明式队列让 `input.json` 保持为唯一的脚本化接口,且可被 golden 归一化。 -- **泛化到 ACP 之外(传输无关的快照 harness)**:不存在第二种传输;harness 端到端都是 ACP 形态(SDK 客户端、JSON-RPC 帧、`session/update` 等待器),推测性的抽象会在没有消费方之前就拆出一个 seam。 +- **将模块复制到每个示例中**:正是本 RFC 要防止的 fork。record/守卫逻辑恰恰是必须在各套件间保持逐字节一致的代码,而示例不在覆盖率门禁范围内,因此每份副本也无法被度量。 +- **在 `examples/` 下建共享模块目录**:代码仍在覆盖率门禁之外,且需要跨示例边界的相对导入,违反包名导入约定;`examples/` 的叶子节点按设计应保持轻薄。 +- **`dsh-acp-demo` 的 `/testing` 子路径导出**:将测试基础设施耦合到产品包的对外服务接口与依赖集中;`packages/support/` 的存在正是为了真实但兼容性承诺较低的开发/测试包,`dsh-llm-replay` 是先例,本包与之配套。 +- **导出原始测试体函数而非套件工厂**:每个示例将重新拥有 `describe`/`it` 骨架(每套件约 80 行注册样板),却无灵活性收益;工厂使消费方只需一张场景表加一次调用,而导出的纯辅助函数在工厂设计内保留了可单元测试性。 +- **可注入的 ACP `Client` 工厂,而非声明式 `permissionAnswers`**:灵活性最大,但将 SDK 客户端构造泄露给每个消费方,并在正被统一的层面重新引入逐示例漂移;声明式队列使 `input.json` 成为唯一的脚本化界面,且可被 golden 规范化。 +- **泛化到 ACP 之外(传输无关的快照 harness)**:不存在第二种传输方式;harness 端到端都是 ACP 形态(SDK 客户端、JSON-RPC 帧、`session/update` 等待器),推测性的抽象将是一个超前于任何消费方的 seam 拆分。 ## 测试 -提取保留了所有既有 ACP golden 的每一个字节。包的 `src/` 通过脚本化的 ACP 子进程实现逐文件 100% 覆盖:harness 测试覆盖每个步骤操作、两个预期错误分支、权限选择/回退/不可能选项、环境变量转发、工作区种子注入与收集排序/噪声/回退;suite 测试对已提交的合成 fixture 执行 replay,并对临时副本执行 record,加上纯辅助函数的测试。两个结构上不可达的守卫保留了有理由的覆盖率排除。fake agent 将 `session/new` 的 cwd 替换进日志,包括 Darwin 的 `/var` realpath 行为,与真实 bin 一致。 +提取保留了所有既有 ACP golden 字节。包的 `src/` 通过脚本化的 ACP 子进程达到逐文件 100% 覆盖率:harness 测试覆盖每个步骤操作、两条预期错误分支、权限选择/回退/不可能选项、环境变量转发、workspace 种子注入、收集排序/噪声/回退;suite 测试对已提交的合成 fixture 执行 replay,并对临时副本执行 record,同时覆盖纯辅助函数。两个结构上不可达的守卫保留了有理由的覆盖率排除。fake agent 将 `session/new` 的 cwd 替换到日志中,包括 Darwin 的 `/var` realpath 行为,与真实 bin 一致。 ## 后果 -新示例只需一张场景表加 fixture 即可获得完整的快照层——sandbox 分支从 master 合并后添加自己的套件(自己的 pin 场景、自己的覆盖层、通过 `test:snapshot:record` 生成 fixture、通过 `permissionAnswers` 指定审批答案)。代价:`suite.ts` 导入 vitest,因此该包只能在 vitest 运行中被导入——这是其他包没有的形态,已在其 README 中声明;每个套件 pin 自己的约 8 KB header fixture(真正不同的组合理应有自己的 pin;相同的组合会被该套件的一致性守卫捕获);e2e 启动器的重复仍然存在(`TODO(acp-test-harness)`)——当该迁移落地时,harness 是提取目标。 +新示例只需一张场景表加 fixture 即可获得完整快照层——sandbox 分支从 master 合入后添加自己的套件(自己的 pin 场景、自己的 overlay、通过 `test:snapshot:record` 生成 fixture、通过 `permissionAnswers` 提供审批答案)。代价:`suite.ts` 导入 vitest,因此该包只能在 vitest 运行中导入——这是其他包没有的形态,已在其 README 中声明;每个套件 pin 自己约 8 KB 的 header fixture(真正不同的组合值得拥有自己的 pin;相同的组合会被该套件的一致性守卫捕获);e2e launcher 的重复仍然存在(`TODO(acp-test-harness)`)——当该迁移落地时,harness 即为提取目标。 diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml index 5b46f88338..59f21c938e 100644 --- a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-16-typed-event-schemas.md: 8d14c3b2d90d8dcf295e122e95267c2c0d7b2a17 -2026-06-16-typed-event-schemas.zh.md: 87bd6b89a2332b7a3a609a9c36d1e9835e42a0b1 +2026-06-16-typed-event-schemas.zh.md: 34f46a87058b409ecdab38d851654db49d87e201 diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md index 87bd6b89a2..34f46a8705 100644 --- a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md @@ -1,4 +1,4 @@ -# RFC:事件词汇的运行时 schema(Zod 与 merge-extensible-map 模式之争) +# RFC:事件词汇的运行时 schema(Zod 与 merge-extensible-map 模式之辩) [English](2026-06-16-typed-event-schemas.md) | 中文 @@ -6,72 +6,72 @@ Status: proposed ## 问题 -harness 将其核心词汇——内容块、消息来源、结束原因、轮次触发器、轮次结束原因与会话事件——建模为 **merge-extensible map**:一个 TypeScript `interface`(如 `SessionEventMap`、`ContentBlockMap`),插件通过声明合并对其扩展,公开联合类型以 `Map[keyof Map]` 派生。这是本仓库的通用扩展模式,记录在 [docs/architecture.md](../../../architecture.md) 中("The same merge-extensible-map pattern is used for `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`"),并被 `defineTool` 的 `InferArgs` DSL 与 `assertNever` 穷尽性约定所依赖。 +harness 将其核心词汇——内容块、消息来源、结束原因、轮次触发器、轮次结束原因与会话事件——建模为 **merge-extensible map**:一个 TypeScript `interface`(如 `SessionEventMap`、`ContentBlockMap`),插件通过声明合并对其扩展,公开联合类型则以 `Map[keyof Map]` 派生。这是本仓库的通用扩展模式,记录在 [docs/architecture.md](../../../architecture.md) 中("The same merge-extensible-map pattern is used for `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`"),`defineTool` 的 `InferArgs` DSL 和 `assertNever` 穷举约定都依赖于它。 -该模式**仅存在于编译期**。类型在运行时消失:没有 schema 对象可供校验传入值、解析不可信输入或在运行时枚举。[会话持久化契约](../../implemented/architecture/2026-06-14-session-persistence.md)暴露了两个后果: +该模式**仅存在于编译期**。类型在运行时消失:没有 schema 对象可供校验传入值、解析不可信输入或在运行时枚举变体。[会话持久化契约](../../implemented/architecture/2026-06-14-session-persistence.md)暴露了两个后果: -1. **持久化将 `event.data` 视为不透明 JSON。** JSONL/SQLite 后端对每个事件逐字 `JSON.stringify`/`JSON.parse`;唯一的运行时守卫是 `isJsonValue`(往返可序列化性——拒绝 BigInt、函数、循环引用、非有限数等),而**不是**结构校验。一个损坏但仍为合法 JSON 的事件数据(字段类型错误、字段缺失)会静默往返,只有在之后被消费方的 `switch` 处理时才可能被发现。 -2. **插件新增的变体没有运行时契约。** 一个通过声明合并添加新 `SessionEventMap` 键的插件,在自身代码中获得了编译期类型,但没有任何机制校验它产出的值是否匹配它声明的形状——无论在生产端、持久化边界还是重新加载时。 +1. **持久化将 `event.data` 视为不透明 JSON。** JSONL/SQLite 后端对每个事件逐字 `JSON.stringify`/`JSON.parse`;唯一的运行时守卫是 `isJsonValue`(往返可序列化性检查:拒绝 BigInt、函数、循环引用、非有限数等),而**非**结构校验。一个损坏但仍为合法 JSON 的事件数据(字段类型错误、字段缺失)会静默往返,只有在后续消费方的 `switch` 中才可能被捕获。 +2. **插件新增变体没有运行时契约。** 一个通过声明合并添加新 `SessionEventMap` 键的插件,在自身代码中获得了编译期类型,但没有任何机制校验它产出的值是否符合它所声明的形状——无论是在生产者处、持久化边界处还是重新加载时。 -由此引出问题:事件词汇是否应迁移到 **Zod** 或其他运行时 schema 库,使持久化边界与插件边界拥有运行时 schema 而非被擦除的类型。 +由此引出问题:事件词汇是否应迁移到 **Zod** 或其他运行时 schema 库,使持久化和插件边界拥有运行时 schema 而非被擦除的类型。 -本 RFC 界定这一问题的范围,不提出具体实现。 +本 RFC 界定该问题的范围,不提出具体实现。 -## 为什么这不是一个持久化变更 +## 为什么这不是一个持久化层的改动 -很容易把「用 Zod 做序列化」理解为对 `dsh-session-persistence-jsonl/src/format.ts` 的局部改动。但它不是,原因在于一个结构性事实:**插件无法通过声明合并扩展一个 Zod schema。** 声明合并是 TypeScript 的编译期机制;Zod schema 是运行时值。要用 Zod 校验事件,你需要一个**运行时注册表**,每个产出事件的包向其贡献自己的 schema(如 `ctx.sessionEvents.register('compaction/marker', z.object({…}))`),每个消费方从中读取。这个注册表——而非持久化后端——将成为词汇的真源,取代 merge-extensible interface。 +很容易把「用 Zod 做序列化」理解为对 `dsh-session-persistence-jsonl/src/format.ts` 的局部修改。但它不是,原因在于一个结构性事实:**插件无法对 Zod schema 进行声明合并。** 声明合并是 TypeScript 编译期机制;Zod schema 是运行时值。要用 Zod 校验事件,就需要一个**运行时注册表**,每个产出事件的包(package)向其贡献自己的 schema(如 `ctx.sessionEvents.register('compaction/marker', z.object({…}))`),每个消费方从中读取。这个注册表——而非持久化后端——将成为词汇的真源,取代 merge-extensible interface。 -因此真正的提案是:**用运行时 schema 注册表替换编译期的 merge-extensible-map 模式,覆盖全仓库。** 这是一次核心词汇的重新设计。 +因此,真正的提案是:**用运行时 schema 注册表替换编译期的 merge-extensible-map 模式,范围覆盖整个仓库。** 这是一次核心词汇的重新设计。 -## 影响范围(实测) +## 影响范围(已度量) 将事件/词汇表面迁移到运行时 schema,至少涉及: -- **六个 merge-extensible map**(约 370 行核心类型):`ContentBlockMap`、`MessageSourceMap`、`FinishReasonMap`(在 `dsh-llm` 中);`TurnTriggerMap`、`TurnEndReasonMap`、`SessionEventMap`(在 `dsh-session` 中)。 -- **约 10 个 `declare module` 扩展点**,分布在 `dsh-agent`、`dsh-agent-loop`、`dsh-bash`、`dsh-llm`、`dsh-session`、`dsh-session-persistence`、`dsh-system-prompt`、`dsh-tools` 中——每个都将从声明合并改为运行时 `register()` 调用。 -- **事件生产端**——agent loop 中 16 处 `session.append(...)` 调用点——形状不变,但现在在边界处被校验。 -- **约 7 个 switch 消费方**,按这些联合类型分支:`deriveMessages`(`dsh-session`)、`BlockAssembler`(`dsh-llm`)、`dsh-invariants` 插件、两个 LLM 适配器(`dsh-llm-deepseek`、`dsh-llm-pi-ai`)以及工具 schema 层(`dsh-tools`)。`assertNever` 对封闭联合的穷尽性 vs 对可扩展联合的 fall-through 约定(一条已文档化的 lint 规则)需要重新考量——运行时变体不具备静态穷尽性。 -- **`defineTool` 的 `InferArgs` DSL**(`dsh-tools`),它从编译期 schema 规格派生零强制转换的 `execute` 参数类型——这是当前方案的标杆用例。 -- **文档**:architecture.md(该模式被描述为基础性的)、[开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md),以及任何引用该模式的 RFC。 +- **六个 merge-extensible map**(约 370 行核心类型):`ContentBlockMap`、`MessageSourceMap`、`FinishReasonMap`(位于 `dsh-llm`);`TurnTriggerMap`、`TurnEndReasonMap`、`SessionEventMap`(位于 `dsh-session`)。 +- **约 10 处 `declare module` 扩展点**,分布在 `dsh-agent`、`dsh-agent-loop`、`dsh-bash`、`dsh-llm`、`dsh-session`、`dsh-session-persistence`、`dsh-system-prompt`、`dsh-tools` 各包中——每处都将从声明合并改为运行时 `register()` 调用。 +- **事件生产者**——agent loop(智能体循环)中 16 处 `session.append(...)` 调用——形状不变,但现在在边界处被校验。 +- **约 7 个 switch 消费方**,对这些联合类型进行分支:`deriveMessages`(`dsh-session`)、`BlockAssembler`(`dsh-llm`)、`dsh-invariants` 插件、两个 LLM(大语言模型)适配器(`dsh-llm-deepseek`、`dsh-llm-pi-ai`)以及工具 schema 层(`dsh-tools`)。`assertNever` 对封闭联合类型的穷举 vs 对可扩展联合类型的 fall-through 约定(一条已记录的 lint 规则)需要重新考量——运行时变体在静态层面不可穷举。 +- **`defineTool` 的 `InferArgs` DSL**(`dsh-tools`),它从编译期 schema 规范派生出零类型转换的 `execute` 参数类型——这是当前方案的标杆用例。 +- **文档**:architecture.md(该模式被描述为基础性的)、[dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md),以及所有引用该模式的 RFC。 -这是一次仓库级别的词汇重新设计,不是持久化的实现细节。 +这是一次仓库级别的词汇重新设计,而非持久化的实现细节。 ## 曾考虑的替代方案 -### A. 维持现状——merge-extensible 类型 + 持久化边界的 `isJsonValue` -保留编译期模式。持久化继续使用不透明 JSON + 可序列化性守卫。插件通过声明合并扩展;事件*形状*的正确性由生产方负责,在编译期由 TypeScript 强制,在开发模式下由 `dsh-invariants` 插件的结构检查强制。 +### A. 维持现状——merge-extensible 类型 + 持久化边界处 `isJsonValue` +保留编译期模式。持久化继续使用不透明 JSON + 可序列化性守卫。插件通过声明合并扩展;事件*形状*的正确性由生产者负责,编译期由 TypeScript 保证,开发模式下由 `dsh-invariants` 插件的结构检查保证。 -- **优点**:零变更;插件扩展只需一行 `interface` 声明合并,具备完整类型推断且无运行时注册仪式;无新运行时依赖;`defineTool` DSL 与 `assertNever` 穷尽性保持正常工作。 +- **优点**:零变动;插件扩展只需一行 `interface` 增补,享有完整类型推断,无需运行时注册仪式;无新运行时依赖;`defineTool` DSL 与 `assertNever` 穷举继续工作。 - **缺点**:持久化边界和插件 seam 处无运行时结构校验;格式错误但仍为合法 JSON 的数据被延迟捕获。 -### B. 仅对 header/封闭形状做校验(schemastery),事件保持不透明 -仅对那些已有手写类型守卫的真正封闭形状加强校验——例如 JSONL 的 `HeaderLine` 守卫(`isHeaderLine`)——使用 **schemastery**(本仓库现有的 schema 库,已用于每个插件的 `static Config`)。merge-extensible 事件联合保持不变。 +### B. 仅对头部/封闭形状做校验(schemastery),事件仍为不透明 +仅对那些已有手写类型守卫的真正封闭形状加以收紧——例如 JSONL 的 `HeaderLine` 守卫(`isHeaderLine`)——使用 **schemastery**(仓库现有的 schema 库,已用于每个插件的 `static Config`)。merge-extensible 事件联合类型保持不变。 -- **优点**:改动小,契合既有约定(schemastery,非新库);用声明式 schema 替换封闭形状上的手写守卫;无核心重设计。 -- **缺点**:不解决事件数据的校验问题;仅固定的元数据记录得到改善。 +- **优点**:改动小,契合现有约定(schemastery,而非新库);用声明式 schema 替换封闭形状上的手写守卫;无核心重新设计。 +- **缺点**:不解决事件数据校验问题;仅固定的元数据记录得到改善。 ### C. 为整个词汇建立运行时 schema 注册表(Zod 或 schemastery) -用运行时注册表替换 merge-extensible map,生产方向其贡献 schema,持久化/消费方据其校验。 +用运行时注册表替换 merge-extensible map,生产者向其贡献 schema,持久化/消费路径据此校验。 -- **优点**:持久化边界与插件 seam 处有真正的运行时校验;单一真源;支持通用工具(自动生成文档、模糊测试、协议格式检查)。 -- **缺点**:上述完整影响范围;**Zod 目前不是直接依赖**(仅作为 `@earendil-works/pi-ai` 的传递依赖),本仓库选定的 schema 库是 **schemastery**——广泛引入 Zod 本身就是一个依赖决策;声明合并的人体工学(一行插件扩展、完整推断)被运行时注册 + 手动类型接线取代;`assertNever` 穷尽性保证弱化(运行时变体不具备静态穷尽性)。 +- **优点**:持久化边界和插件 seam 处获得真正的运行时校验;单一真源;可支撑通用工具(自动生成文档、模糊测试、协议格式检查)。 +- **缺点**:上述全部影响范围;**Zod 目前不是直接依赖**(仅作为 `@earendil-works/pi-ai` 的传递依赖),仓库选定的 schema 库是 **schemastery**——广泛引入 Zod 本身就是一个依赖决策;声明合并的人体工学(一行插件扩展、完整推断)被运行时注册 + 手动类型接线取代;`assertNever` 穷举保证弱化(运行时变体在静态层面不可穷举)。 ## 提案 -暂缓。如果需要在持久化边界做运行时校验,**方案 B**(用 schemastery 校验封闭的 header 与元数据形状)是既有约定内的适度步骤。**方案 C** 是一项架构决策,需要自己的实现 RFC,包括在 Zod 与 schemastery 之间做出选择。 +推迟。如果需要在持久化边界做运行时校验,**方案 B**(对封闭的头部和元数据形状使用 schemastery)是现有约定下的适度步骤。**方案 C** 是一个架构决策,需要自己的实现 RFC,其中包括 Zod 与 schemastery 之间的选择。 ## 验收标准 -- 方案 C 只能通过自己的实现 RFC 推进,绝不作为持久化的附带效果。 -- 如果采纳方案 B,封闭的 header/元数据形状(JSONL 的 `isHeaderLine` 守卫及同类)改用 schemastery 校验以替代手写守卫,merge-extensible map 保持不变。 +- 方案 C 只能通过自己的实现 RFC 推进,绝不能作为持久化的附带改动。 +- 如果采纳方案 B,封闭的头部/元数据形状(JSONL 的 `isHeaderLine` 守卫及同类)改用 schemastery 校验,替代手写守卫,merge-extensible map 保持不动。 ## 风险 -- 暂缓意味着事件 `data` 在持久化边界仍无结构校验:格式错误但仍为合法 JSON 的数据被延迟捕获,由消费方的 `switch` 处理——这是现状的代价,有意接受。 -- 如果方案 C 最终被采纳,人体工学损失是实际的:一行声明合并变为运行时注册加手动类型接线,`assertNever` 的静态穷尽性保证弱化。 +- 推迟意味着事件 `data` 在持久化边界处仍无结构校验:格式错误但仍为合法 JSON 的数据被延迟捕获,由消费方的 `switch` 兜底——这是现状的代价,有意接受。 +- 如果方案 C 最终被采纳,人体工学的损失是真实的:一行声明合并变为运行时注册加手动类型接线,`assertNever` 的静态穷举保证弱化。 ## 待解问题 -- 如果采用注册表,schema 库选 **schemastery**(已在依赖树中,已是配置 schema 库)还是 **Zod**(生态更丰富,目前仅为传递依赖)?同时维护两个 schema 库本身就是成本。 -- 能否采用混合方案:保留编译期推断(使 `defineTool` 和插件 DX 不受影响),同时为每个变体添加*可选*的运行时 schema,仅在持久化/协议边界校验而非每次进程内 append 时校验? -- `dsh-invariants` 插件在开发模式下是否已覆盖了足够多的运行时形状缺口,使得边界校验仅在面对真正不可信的输入(如重新加载被外部修改的日志)时才有必要? +- 如果采用注册表,库选 **schemastery**(已在仓库中,已作为配置 schema 库)还是 **Zod**(生态更丰富,目前仅为传递依赖)?同时维护两个 schema 库本身就是一种成本。 +- 能否采用混合方案:保留编译期推断(使 `defineTool` 和插件开发体验不受影响),同时为每个变体添加*可选*的运行时 schema,仅在持久化/协议边界校验,而非每次进程内 append 都校验? +- `dsh-invariants` 插件在开发模式下是否已覆盖了足够多的运行时形状缺口,使得边界校验仅在面对真正不可信输入(重新加载外部修改过的日志)时才有必要? diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml index edc5a3604d..290a729be7 100644 --- a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-generic-long-running-tool-runtime.md: ea773a651b5aeec87179aac2ed419f176486977f -2026-06-20-generic-long-running-tool-runtime.zh.md: d50eb6858c11b9c98817b24bfe40f4e2c780f4b9 +2026-06-20-generic-long-running-tool-runtime.zh.md: 25c1b282b19bb7da08b552485e348c23b11dcecf diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md index d50eb6858c..25c1b282b1 100644 --- a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md @@ -1,43 +1,43 @@ -# RFC:提取通用的长时运行工具运行时 - -[English](2026-06-20-generic-long-running-tool-runtime.md) | 中文 +# RFC:提取通用的长时间运行工具运行时 Status: proposed +[English](2026-06-20-generic-long-running-tool-runtime.md) | 中文 + ## 问题 -bash 能力 seam 同时支持前台命令和长时运行的后台任务。后台支持体量不小:抽象执行器暴露 `start`、`get`、`ownerOf`、`list`、`readOutput`、`kill` 和 `onTaskDone`;本地执行器跟踪任务、增量读取、owner token、进程清理和完成监听器;模型侧看到三个工具(`bash`、`bash_output`、`bash_kill`);工具插件将完成通知注入回所属 agent 的会话。本地执行器用 owner token 隔离任务访问,因为可预测的全局 task id 会带来跨会话的读取/终止风险。 +bash 能力 seam 同时支持前台命令和长时间运行的后台任务。后台支持体量不小:抽象执行器暴露 `start`、`get`、`ownerOf`、`list`、`readOutput`、`kill` 和 `onTaskDone`;本地执行器负责跟踪任务、增量读取、owner token、进程清理和完成监听;模型侧看到三个工具(`bash`、`bash_output`、`bash_kill`);工具插件将完成通知注入回所属 agent(智能体)的会话。本地执行器用 owner token 隔离任务访问,因为可预测的全局 task id 会带来跨会话的读取/终止风险。 -[工具实操手册](../../../cookbook/adding-a-tool.md)已经指出了真正的设计异味:后台 bash 实质上是寄居在一个工具内部的通用长时运行工具基础设施。如果未来的工具也需要后台执行、轮询、终止、所有权和完成通知,这些语义不应藏在 `dsh-bash` 里。 +[工具实操手册](../../../cookbook/adding-a-tool.md)已经指出了真正的设计异味:后台 bash 本质上是寄居在单个工具内部的通用长时间运行工具基础设施。如果未来的工具也需要后台执行、轮询、终止、所有权和完成通知,这些语义不应藏在 `dsh-bash` 里。 ## 提案 -将长时运行任务的语义从 bash 上方抽出,放入一个与工具无关的运行时。bash 仍然能运行后台命令,但不再拥有 task id、ownership token、轮询、取消、完成通知以及模型侧「读取/终止此任务」命令等通用概念。 +将长时间运行任务的语义从 bash 上移到一个与工具无关的运行时中。bash 仍然能运行后台命令,但不再拥有 task id、ownership token、轮询、取消、完成通知以及模型侧「读取/终止此任务」命令等通用概念。 该运行时应拥有: -- 稳定的 task id 与 owner token,按调用方的会话/agent 键控。 -- 注册一个长时运行任务,附带增量输出的生产者和一个完成 promise。 +- 稳定的 task id 和 owner token,按调用方的会话/agent 做键。 +- 注册一个长时间运行任务,附带增量输出的生产者和一个完成 promise。 - 通用的 read/cancel/list 操作,对所有工具使用相同的跨会话授权规则。 - 向所属会话注入完成通知。 -- 待处理/运行中/已完成任务状态的展示钩子,bash 只提供命令特有的标签和输出格式化。 +- 针对 pending/running/completed 任务状态的展示钩子,bash 只提供命令特有的标签和输出格式化。 -`dsh-bash` 随后只保留 bash 特有的执行契约:将请求解析为命令规格、运行前台命令,或启动进程并将其流/进程句柄交给通用运行时。`dsh-tool-bash` 保留模型侧的命令工具,但后续操作变为通用的长时运行工具操作(或 bash 向其注册的共享工具层),而非定制的 `bash_output`/`bash_kill` 管道。 +`dsh-bash` 保留 bash 特有的执行契约:将请求解析为命令规格、运行前台命令,或启动进程并将其流/进程句柄交给通用运行时。`dsh-tool-bash` 保留模型侧的命令工具,但后续操作变为通用的长时间运行工具操作,或者 bash 向其注册的共享工具,而不是专属的 `bash_output`/`bash_kill` 管道。 ## 当前 seam 消费情况 -当前消费方划分清晰:`dsh-tool-bash` 使用完整的前台/后台 seam,而钩子桥接只使用前台的 `resolve` 和 `run`(带受信的 `stdin` 与 `env`)。`get` 和 `list` 仅在测试中使用;`BashTask.done` 仅在实现内部用于 dispose(资源释放),生产环境的完成通知走 `onTaskDone`。提取出的运行时应暴露单一的公开完成机制,保留钩子所需的简单前台路径,并决定后台的 `timeoutMs` 是否属于 `start`。如果运行时拥有进程 spawn,还应集中处理目前重复的凭证清洗逻辑。 +当前消费方划分清晰:`dsh-tool-bash` 使用完整的前台/后台 seam,而钩子桥接层只使用前台的 `resolve` 和 `run`(带受信的 `stdin` 和 `env`)。`get` 和 `list` 仅在测试中使用;`BashTask.done` 仅在实现内部用于 dispose(资源释放),生产环境的完成通知使用 `onTaskDone`。提取出的运行时应暴露一个公开的完成机制,保留钩子所需的简单前台路径,并决定后台的 `timeoutMs` 是否属于 `start`。如果它拥有进程 spawn 的职责,还应集中处理目前重复的凭证清洗逻辑。 ## 验收标准 -- bash 特有的包不再定义通用的任务注册表、owner-token 授权、轮询、取消或完成通知机制。 -- 一个共享的长时运行任务服务或工具层拥有这些语义,并作为未来任何具备后台能力的工具的文档化路径。 -- bash 的后台行为仍可通过共享层使用,测试证明跨会话隔离依然成立。 -- ACP 和快照 fixture(测试前置数据)通过共享的任务词汇渲染后台 bash,而非通过 bash 独有的生命周期语义。 -- [工具实操手册](../../../cookbook/adding-a-tool.md)将长时运行工具指向共享运行时,而非告诉每个工具自行发明任务协议。 +- bash 特有的包(package)不再定义通用的任务注册表、owner-token 授权、轮询、取消或完成通知机制。 +- 一个共享的长时间运行任务服务或工具层拥有这些语义,并被文档化为未来任何具备后台能力的工具的接入路径。 +- bash 后台行为仍可通过共享层使用,测试证明跨会话隔离依然成立。 +- ACP 和快照 fixture(测试前置数据)通过共享任务词汇渲染后台 bash,而非通过 bash 专属的生命周期语义。 +- [工具实操手册](../../../cookbook/adding-a-tool.md)将长时间运行工具指向共享运行时,而不是让每个工具自行发明任务协议。 ## 风险 -bash 包失去了对一个已经可用的后台任务实现的本地所有权,实施 PR 可能暂时搅动模型侧的工具名称或 transcript(文本记录)展示。如果最终结果是留下一份后台任务契约、而非让每个未来的长时运行工具克隆 bash 的私有协议,这种搅动是值得的。 +bash 包失去了对一个已经可用的后台任务实现的本地所有权,实现 PR(Pull Request)可能暂时搅动模型侧的工具名称或 transcript(文本记录)展示。如果最终结果是留下一份后台任务契约,而不是让每个未来的长时间运行工具克隆 bash 的私有协议,这种搅动是值得的。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml index 2c12df37b1..ccab930c8f 100644 --- a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-30-pre-tool-input-rewrite.md: add84bfc76434eb25870f09e71860279663d291e -2026-06-30-pre-tool-input-rewrite.zh.md: c636cf42d5c55f0ee1192a46283f8cdbe8c4cadc +2026-06-30-pre-tool-input-rewrite.zh.md: 13d66208be07992fd414f2984c493557ad1e87a3 diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md index c636cf42d5..13d66208be 100644 --- a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md @@ -1,53 +1,53 @@ -# RFC:工具执行前输入改写——一致性设计 - -[English](2026-06-30-pre-tool-input-rewrite.md) | 中文 +# RFC:工具执行前输入重写——一致性设计 Status: proposed +[English](2026-06-30-pre-tool-input-rewrite.md) | 中文 + ## 问题 -[拦截 seam RFC](../../implemented/feature/2026-06-30-interception-seams.md) 将 `tools/pre-execute` 定义为一道 allow/deny/ask 门禁,作用于身份已受保护、参数已被深度冻结的执行对象。Claude Code 的 `PreToolUse` 钩子还提供了 `updatedInput`,因此忠实的桥接需要一个显式的改写机制。改写不能是对现有执行对象的可变逃逸口:它必须保持持久化历史、审计记录、展示层与实际执行值之间的一致性。 +[拦截 seam RFC](../../implemented/feature/2026-06-30-interception-seams.md) 将 `tools/pre-execute` 定义为一道针对执行的允许/拒绝/询问门禁,此时执行的身份标识已受保护、参数已被深度冻结。Claude Code 的 `PreToolUse` 钩子还提供了 `updatedInput`,因此忠实的桥接需要一个显式的重写机制。重写不能是对现有执行对象的可变逃逸口:它必须保持持久化历史、审计记录、展示层与实际执行值之间的一致性。 ## 问题本质:执行前参数的三个读取方 -在 agent loop(智能体循环)中,工具调用的参数在工具执行之前就已被提交到日志并被活跃消费方读取: +在 agent loop(智能体循环)中,工具调用的参数在工具执行**之前**就已提交到日志并被实时消费方读取: -1. **`assistant/message`** 在工具分发之前追加——它是 `deriveMessages()` 回放时的模型历史来源,因此携带的是模型自身生成的工具调用参数。 +1. **`assistant/message`** 在工具分发之前追加——它是 `deriveMessages()` 回放时的模型历史来源,因此携带模型自身输出的工具调用参数。 2. **`tool/call`** 是持久化的审计记录,在 `ctx.tools.execute()` 之前追加。 -3. **展示层实时读取 `tool/call.arguments`**:ACP 桥接会记住这些参数并传给 `presentResult`;`dsh-tool-bash` 从中派生卡片标题、rawInput、cwd 以及终端/后台的处理方式。 +3. **展示层实时读取 `tool/call.arguments`**:ACP(Agent Client Protocol)桥接记住这些参数并传给 `presentResult`;`dsh-tool-bash` 从中派生卡片标题、rawInput、cwd 以及终端/后台处理方式。 -如果只做执行层面的改写,UI 会展示一条命令而实际运行的是另一条,并且结果会对着错误的参数渲染。注册表目前阻止了这种失败模式:它对 `arguments` 做 structured-clone 并深度冻结,将执行身份属性设为不可写,且不暴露任何可替换它们的测试 shim 或监听路径。改写设计必须保持这一受保护的身份边界,而非削弱它。 +如果只做执行层面的重写,UI 会显示一条命令而实际运行的是另一条,并且结果会对着错误的参数渲染。注册表目前通过以下方式防止这种失败模式:对 `arguments` 做 structured-clone 并深度冻结,将执行身份属性设为不可写,且不暴露任何可替换它们的测试 shim 或监听路径。重写设计必须维护这一受保护的身份边界,而非削弱它。 ## 提案 -改写是一次「身份构造前的一致性事务」。当钩子提供 `updatedInput` 时,有效值必须在注册表构造不可变的 `ToolExecution` 之前确定,并原子性地反映到全部三个读取方: +重写是一个「身份标识创建前的一致性事务」。当钩子提供 `updatedInput` 时,有效值必须在注册表构造其不可变的 `ToolExecution` 之前确定,并且必须原子地反映到全部三个读取方: -- `tool/call` 审计事件记录**改写后**的参数(原始参数保留在一个 sidecar 字段中用于审计追踪——钩子改变了调用,原始参数和生效参数都是值得保留的事实)。 -- 派生历史中的 `assistant/message` 必须与实际执行一致——待评估的选项:就地改写 assistant 消息中的工具调用块(改变模型「看到自己说过的话」),或记录一条单独的修正由下一次请求携带。CC 的模型是让模型看到改写已生效。 -- 展示层(`presentCall`/`presentResult`)读取改写后的参数,UI 展示的是实际运行的内容。 +- `tool/call` 审计事件记录**重写后**的参数(原始参数保留在一个伴随字段中,作为审计线索——钩子修改了调用,原始参数与生效参数都是值得保留的事实)。 +- 派生历史中的 `assistant/message` 必须与实际执行一致。待评估的选项:就地重写 assistant 消息中的工具调用块(改变模型「看到自己说了什么」),或记录一条单独的修正让下一次请求携带。Claude Code 的模型是让模型看到重写已生效。 +- 展示层(`presentCall`/`presentResult`)读取重写后的参数,使 UI 显示实际运行的内容。 -在 `PreToolDecision` 当前的触发点上做扩展不够:此时两条持久化记录都已存在,执行身份已受保护。实现必须要么将相关决策移到日志提交之前,要么在待处理的模型调用上增加一个专门的更早期改写决策。当循环将生效参数提交到历史和审计之后,再按常规构造不可变执行对象,并照常运行现有的 allow/deny/ask 与工具流水线。 +在 `PreToolDecision` 当前的触发点上做扩展是不够的:此时两条持久化记录已经存在,执行身份已受保护。实现必须将相关决策移到日志提交之前,或者增加一个专门的、更早的重写决策点来处理待定的模型调用。agent loop 将生效参数提交到历史和审计之后,再构造普通的不可变执行对象,并照常运行现有的允许/拒绝/询问和工具流水线。 ## 曾考虑的替代方案 ### 为什么不直接修改执行对象? -允许 pre-execute 监听器赋值 `exec.arguments` 只能提供执行层面的改写,模型历史、审计和展示层不会跟着变。保持身份受保护使得这种局部行为无法被表达。在一致性事务实现之前,CC/Codex 桥接对 `updatedInput` 只做日志记录并发出警告,而非声称已兑现;循环分发处的 `TODO(pre-tool-input-rewrite)` 锚定了这个缺失的更早阶段。 +允许 pre-execute 监听器赋值 `exec.arguments` 只能提供执行层面的重写,模型历史、审计和展示层不会随之改变。保持身份标识受保护使得这种局部行为不可表达。在一致性事务实现之前,CC/Codex 桥接对 `updatedInput` 记录日志并发出警告,而非声称已兑现;循环分发点的 `TODO(pre-tool-input-rewrite)` 标记了缺失的更早阶段。 ## 验收标准 -- 请求的改写在 `ToolExecution` 身份创建之前完成解析,并原子性地反映到全部三个读取方:`tool/call` 审计记录改写后的参数(原始参数保留在 sidecar 字段)、派生历史与实际执行一致、展示层渲染改写后的参数。 -- 生效的 `ToolExecution.arguments` 在 pre-policy、guards、dispatch、post-policy 和最终观测的全过程中保持深度冻结且不可写;不引入任何可变 shim。 -- CC/Codex 桥接兑现 `updatedInput`,不再输出忠实但降级的警告。 +- 请求的重写在 `ToolExecution` 身份标识创建之前解决,并原子地反映到全部三个读取方:`tool/call` 审计记录重写后的参数(原始参数保留在伴随字段中)、派生历史与实际执行一致、展示层渲染重写后的参数。 +- 生效的 `ToolExecution.arguments` 在 pre-policy、守卫、分发、post-policy 和最终观测全程保持深度冻结且不可写;不引入任何可变 shim。 +- CC/Codex 桥接兑现 `updatedInput`,不再记录忠实但降级的警告。 ## 风险 -- 改写 `assistant/message` 中的工具调用块会改变模型「看到自己说过的话」;是否有提供方在回放时拒绝这种改写,是一个必须在决策形态冻结前通过实验验证的开放问题。 -- 更早期的改写阶段改变了 `assistant/message`、`tool/call`、钩子审计事件与执行之间的顺序关系;设计必须固定这一顺序,同时不削弱轮次封闭性或 call/result 邻接性。 +- 重写 `assistant/message` 中的工具调用块会改变模型「看到自己说了什么」;是否有提供方在回放时拒绝这种改动,是一个需要通过实验确定的开放问题,必须在决策形状冻结之前解决。 +- 更早的重写阶段改变了 `assistant/message`、`tool/call`、钩子审计事件与执行之间的顺序关系;设计必须固定这一顺序,同时不削弱轮次封闭性或调用/结果邻接性。 ## 开放问题 -- 改写 `assistant/message` 中的工具调用块是否会破坏某些提供方在回放时的预期?还是记录一条单独的修正更安全? -- 原始参数是否应保留在 `tool/call` 事件(审计)上?如果是,放在哪个字段? -- 改写决策是移到日志提交之前,还是成为一个专门的更早期 seam?现有的 pre-tool allow/deny 钩子如何避免运行两次? -- 这与未来的权限 `ask` 流程(用户批准一个被改写的调用)如何交互? +- 重写 `assistant/message` 中的工具调用块是否会破坏某些提供方在回放时的预期?还是单独的修正更安全? +- 原始参数是否应保留在 `tool/call` 事件(审计)上?如果是,放在什么字段? +- 重写决策是移到日志提交之前,还是成为一个专门的更早 seam?现有的 pre-tool 允许/拒绝钩子如何避免运行两次? +- 这与未来的权限 `ask` 流程(用户批准一个被重写的调用)如何交互? diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml index d7b4dcf71f..ab362ca036 100644 --- a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-07-claude-code-and-codex-subagent-backends.md: 1ebf01dd8df0980f6c464be8b27033bdfab942f3 -2026-07-07-claude-code-and-codex-subagent-backends.zh.md: 0ed5b42bc9d60b54ac610a8f34f8261f3aeefaed +2026-07-07-claude-code-and-codex-subagent-backends.zh.md: dd26a49962ee46a8ce0965557ff3dbd5805fdcfe diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md index 0ed5b42bc9..dd26a49962 100644 --- a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md @@ -1,4 +1,4 @@ -# RFC:Claude Code 与 Codex subagent 后端(进程外委派至外部编码 agent) +# RFC:Claude Code 与 Codex subagent 后端(向外部编码 agent 的进程外委派) [English](2026-07-07-claude-code-and-codex-subagent-backends.md) | 中文 @@ -6,84 +6,84 @@ Status: proposed ## 问题 -为 Claude Code 和 Codex 添加隔离的 subagent 提供方。既有的[命名提供方 seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 和 [ACP 后端](../../implemented/feature/2026-06-22-acp-subagent-backend.md)已确立了进程边界的形状。harness 的一个轮次应当能够将一个自包含的任务委派给上述任一产品,并接收其最终回答,同时不暴露父进程的密钥,也不继承来自 `~/.claude` 或 `~/.codex` 的宿主配置。 +为 Claude Code 和 Codex 添加隔离的 subagent 提供方。既有的[命名提供方 seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 和 [ACP 后端](../../implemented/feature/2026-06-22-acp-subagent-backend.md)已确立了进程边界的形状。harness 的一个轮次应能将一个自包含任务委派给上述任一产品,并接收其最终答案,同时不暴露父进程的密钥,也不继承来自 `~/.claude` 或 `~/.codex` 的宿主配置。 -## 方案 +## 提案 两个兄弟提供方包(ACP 后端的结构变体),加一次提取: -- `@deepseek-ai/dsh-subagent-claude-code`:通过 `@anthropic-ai/claude-agent-sdk` 的 `query()` 驱动一个 Claude Code 子进程(SDK 在父进程中运行,并将其捆绑的 `claude` CLI 作为子进程 spawn)。提供方名称 `claude-code`:子进程是 Claude Code 这个**产品**,而非 Anthropic 模型适配器——"claude" 保留给未来的 `dsh-llm` 适配器。 -- `@deepseek-ai/dsh-subagent-codex`:spawn `codex app-server`,通过其 JSON-RPC-over-stdio 协议,使用包内一个手写的换行 JSON 客户端(约 200–300 行)驱动一个 thread/turn。 -- `@deepseek-ai/dsh-subagent-process`:纯库(`subagent-inprocess` 先例),提取 `dsh-subagent-acp` 已有且两个新后端都需要的内容:凭证环境清洗(`SENSITIVE_ENV_PATTERN`/`buildChildEnv`)、EOF → SIGTERM → SIGKILL 的 dispose 阶梯,以及新的隔离配置目录辅助函数(`mkdtemp` 创建、尽力删除)。ACP 后端迁移到该库上;`bash-local` 的兄弟副本保持不动以限制变更范围。 +- `@deepseek-ai/dsh-subagent-claude-code`:通过 `@anthropic-ai/claude-agent-sdk` 的 `query()` 驱动一个 Claude Code 子进程(SDK 在父进程中运行,并将其内置的 `claude` CLI 作为子进程 spawn)。提供方名称为 `claude-code`:子进程是 Claude Code 这个**产品**,而非 Anthropic 模型适配器——"claude" 保留给未来的 `dsh-llm` 适配器。 +- `@deepseek-ai/dsh-subagent-codex`:spawn `codex app-server`,通过其 JSON-RPC-over-stdio 协议驱动一个 thread/turn,使用包内一个手写的换行 JSON 客户端(约 200–300 行)。 +- `@deepseek-ai/dsh-subagent-process`:纯库(沿用 `subagent-inprocess` 的先例),提取 `dsh-subagent-acp` 已有且两个新后端都需要的内容:凭证环境清洗(`SENSITIVE_ENV_PATTERN`/`buildChildEnv`)、EOF → SIGTERM → SIGKILL 的 dispose 阶梯,以及新的隔离配置目录辅助函数(`mkdtemp` 创建、尽力删除)。ACP 后端迁移到该库上;`bash-local` 的兄弟副本保持不动以限制变更范围。 -两个提供方遵循 ACP 后端契约:每次 `start` 创建一个全新子进程、一次 prompt 往返、不继承父上下文也不声明可选能力、忽略 `request.parent` 和 `request.agentOptions`、使用随机品牌 agent id。`result` 永不 reject;子进程失败映射为 stop reason,原始错误送入 logger。每个提供方在不同的工具名下挂载 `dsh-tool-subagent`。工具结果是唯一新增的模型可见产物,因此不需要新的会话事件;工作区变更仍是 transcript 回放之外的环境副作用。 +两个提供方遵循 ACP 后端契约:每次 `start` 创建一个全新子进程、一次 prompt 往返、不继承父上下文也不声明可选能力、忽略 `request.parent` 和 `request.agentOptions`、使用随机的品牌化 agent id。`result` 从不 reject;子进程失败映射为 stop reason,原始错误送入 logger。每个提供方以不同的工具名挂载 `dsh-tool-subagent`。工具结果是唯一新增的模型可见产物,因此无需新的会话事件;工作区变更仍是 transcript(文本记录)回放之外的环境副作用。 ## 已验证的接口事实(固定版本) -两个集成面在本提案之前均已针对固定实现进行了验证——读取类型与捆绑源码、运行 keyless spike——而非仅依赖厂商文档。固定版本是验证基线,不是运行时契约:后端不执行运行时版本探测(无 `codex --version` 门控、无 SDK 版本嗅探)。兼容性在开发时强制执行——每次依赖升级都重跑 keyless 套件以验证真实加载路径——运行时则通过大声失败来保障:协议层的意外通过 `onError` 结算为 `error`,绝不静默异常。 +两个集成面在本提案之前均已针对固定版本进行了验证——阅读类型与打包源码、运行无需密钥的 spike——而非仅依赖厂商文档。固定版本是验证基线,不是运行时契约:后端不执行运行时版本探测(无 `codex --version` 门禁、无 SDK 版本嗅探)。兼容性在开发时强制执行——每次依赖升级都会针对真实加载路径重跑无密钥套件——在运行时则通过大声失败来保障:协议层面的意外通过 `onError` 结算为 `error`,绝不静默异常。 -**`@anthropic-ai/claude-agent-sdk` 0.3.202。** `options.env` 会**替换**子进程环境(不与 `process.env` 合并),这正是清洗所需的行为。`settingSources` 默认加载所有文件系统设置——隔离要求显式传入 `[]`。结果子类型为 `success` | `error_during_execution` | `error_max_turns` | `error_max_budget_usd` | `error_max_structured_output_retries`。中止时 SDK 自行升级 CLI 子进程:立即关闭 stdin,若子进程忽略则约 2 秒后发送 SIGTERM(已观察到;无残留进程)——无需自定义 kill 回退。`outputFormat: {type: 'json_schema'}` 和 `agents` 选项已存在,为 seam 的 `outputSchema` 能力和命名 subagent 类型提供了未来着陆点;二者均不在本 RFC 范围内。 +**`@anthropic-ai/claude-agent-sdk` 0.3.202。** `options.env` 会**替换**子进程环境(不与 `process.env` 合并),恰好满足清洗需求。`settingSources` 默认加载所有文件系统设置——隔离要求显式传入 `[]`。结果子类型为 `success` | `error_during_execution` | `error_max_turns` | `error_max_budget_usd` | `error_max_structured_output_retries`。中止时 SDK 自行升级 CLI 子进程:立即关闭 stdin,约 2 秒后若子进程未退出则发送 SIGTERM(已观察到;无残留进程)——无需自定义 kill 回退。`outputFormat: {type: 'json_schema'}` 和 `agents` 选项已存在,为 seam 的 `outputSchema` 能力和命名 subagent 类型提供了未来着陆点;两者均不在本 RFC 范围内。 **codex CLI 0.142.5,`codex app-server`(v2 词汇)。** LF 分隔的 JSON,JSON-RPC 2.0 形状但省略 `"jsonrpc"` 头。 - 生命周期:`initialize{clientInfo}` + `initialized` → `thread/start`(接受 `cwd`、`model`、`sandbox`、`approvalPolicy`、`ephemeral`;未认证即可成功)→ `turn/start{threadId, input:[{type:'text',text}]}` 立即返回一个 `inProgress` 的 turn;终止信号是携带 `Turn{status: completed|interrupted|failed|inProgress, error}` 的 `turn/completed` 通知。 -- 审批为服务端发起的请求——`item/commandExecution/requestApproval`、`item/fileChange/requestApproval`、`item/permissions/requestApproval`、`item/tool/requestUserInput`、`mcpServer/elicitation/request`——以 `accept`/`decline` 系列决策应答。 -- 认证:`account/login/start{type:'apiKey', apiKey}` 是一等 RPC,`account/read` 报告 `requiresOpenaiAuth`——且未认证的 `turn/start` 不会快速失败(它会挂在重试中),因此后端必须预检认证并大声结算 `error`,而非等待 turn。 -- 隔离:`CODEX_HOME` 重定向被尊重(`initialize` 响应会回显它,测试可据此断言隔离),且 `ephemeral: true` 的 thread 完全不留会话文件。 +- 审批是服务端发起的请求——`item/commandExecution/requestApproval`、`item/fileChange/requestApproval`、`item/permissions/requestApproval`、`item/tool/requestUserInput`、`mcpServer/elicitation/request`——以 `accept`/`decline` 系列决策应答。 +- 认证:`account/login/start{type:'apiKey', apiKey}` 是一等 RPC,`account/read` 报告 `requiresOpenaiAuth`——且未认证的 `turn/start` 不会快速失败(它会挂在重试中),因此后端**必须**预检认证状态,并在失败时大声结算为 `error`,而非等待 turn。 +- 隔离:`CODEX_HOME` 重定向被尊重(`initialize` 响应会回显它,测试可据此断言隔离),`ephemeral: true` 的 thread 不留任何会话文件。 ## 隔离与凭证 -认证仅使用 API key。每次运行使用一个全新的配置目录(Claude Code 用 `CLAUDE_CONFIG_DIR` 配合 `settingSources: []`,Codex 用 `CODEX_HOME`),dispose 时尽力删除;配置也可选择一个持久目录。共享的子进程环境辅助函数转发 `PATH`、`HOME`、`TMPDIR`、locale、代理设置等普通值,移除凭证形状的名称,并叠加显式的 `config.env`。Claude Code 通过该叠加接收 API key,Codex 则通过 `account/login/start` 接收,而非手写认证文件。 +认证方式仅限 API key。每次运行使用一个全新的配置目录(Claude Code 用 `CLAUDE_CONFIG_DIR` 配合 `settingSources: []`,Codex 用 `CODEX_HOME`),dispose 时尽力删除;配置也可以选择一个持久目录。共享的子进程环境辅助函数转发 `PATH`、`HOME`、`TMPDIR`、locale 和代理设置等普通值,移除凭证形态的名称,并叠加显式的 `config.env`。Claude Code 通过该叠加接收 API key,而 Codex 通过 `account/login/start` 接收,而非手写认证文件。 ## 权限与审批策略 -每个后端暴露其引擎的原生策略词汇。Claude Code 默认 `permissionMode: default` 配合 `permission: reject`;Codex 默认 `sandboxMode: read-only`、`approvalPolicy: never`,以及相同的拒绝回退。示例可选择启用 `acceptEdits` 或 `workspace-write`。已知的审批、用户输入和 elicitation 请求接收配置的应答;未知方法接收 method-not-found,未知通知被消费。没有 prompt 到达人类,子进程也不会因等待不可用的输入而无限挂起。 +每个后端暴露其引擎原生的策略词汇。Claude Code 默认 `permissionMode: default` 配合 `permission: reject`;Codex 默认 `sandboxMode: read-only`、`approvalPolicy: never`,以及相同的拒绝回退。示例可选择启用 `acceptEdits` 或 `workspace-write`。已知的审批、用户输入和 elicitation 请求接收配置的应答;未知方法接收 method-not-found,未知通知被消费。没有 prompt 到达人类,子进程也不会因等待不可用的输入而无限挂起。 ## StopReason 映射 -Claude Code:`success` → `completed`;`error_max_turns`、`error_during_execution`、`error_max_budget_usd`、`error_max_structured_output_retries` → `error`(与 ACP 对 `max_turn_requests` 的处理对齐:未完成的任务不算成功);生成器中止 → `aborted`;未知值 → `error`。Codex:`Turn.status` `completed` → `completed`;`interrupted` → `aborted`;`failed` 且 `codexErrorInfo: 'contextWindowExceeded'` → `max-tokens`,其他 `failed` → `error`;传输/spawn/认证预检失败 → `error`(若已请求取消则为 `aborted`)。两者中,`cancel()` 采用 ACP 形状:标志位 + abort/interrupt + 一个 cancel-settled 竞争分支,使不合作的子进程无法阻塞结果。 +Claude Code:`success` → `completed`;`error_max_turns`、`error_during_execution`、`error_max_budget_usd`、`error_max_structured_output_retries` → `error`(与 ACP 对 `max_turn_requests` 的处理对齐:未完成的任务不是成功);生成器中止 → `aborted`;未知值 → `error`。Codex:`Turn.status` 为 `completed` → `completed`;`interrupted` → `aborted`;`failed` 且 `codexErrorInfo: 'contextWindowExceeded'` → `max-tokens`,其他 `failed` → `error`;传输/spawn/认证预检失败 → `error`(若已请求取消则为 `aborted`)。两者中,`cancel()` 采用 ACP 形状:标志位 + abort/interrupt + 一个 cancel-settled 竞争分支,使不合作的子进程无法阻塞结果。 -活性姿态,明确声明:teardown 时序是配置项,turn 时长不是。两个后端将 dispose 阶梯的宽限期作为带默认值的已验证配置字段(ACP 后端的 `disposeEofGraceMs`/`disposeGraceMs` 形状,由提取库承载),但刻意**不设** turn 时长或启动超时——与 ACP 一致:turn 期间的活性由调用方通过 `cancel()`/abort signal 掌控,subagent turn 合理地可达数分钟,且 Codex 认证预检已消除了唯一经验证的必然挂起场景;需要墙钟上限的部署从父进程取消即可。 +活性姿态,明确声明:teardown 时序是配置项,turn 时长不是。两个后端将 dispose 阶梯的宽限期作为带默认值的已验证配置字段(ACP 后端的 `disposeEofGraceMs`/`disposeGraceMs` 形状,由提取库承载),但**刻意不设** turn 时长或启动超时——与 ACP 一致:turn 期间的活性由调用方通过 `cancel()`/abort signal 掌控,subagent turn 合理地可达数分钟,而 Codex 认证预检消除了唯一已验证的必然挂起场景;需要墙钟上限的部署从父侧取消即可。 ## 测试 每个适用层级都要求覆盖: -- **Keyless 单元/集成:** 通过真实 SDK 驱动一个假 Claude CLI,通过真实 wire 客户端驱动一个脚本化的 Codex app-server。在逐文件 100% 覆盖率下,覆盖往返、每个 stop 映射、两条取消路径及预中止、权限策略、未知消息、spawn 失败、reload 清理、导出形状、清洗后的环境、临时目录删除,以及 Codex 认证预检失败。 -- **带 key 的 e2e:** 每个真实引擎在 `acceptEdits` 或 `workspace-write` 下执行文件操作;跳过时命名缺失的二进制文件或 key,并断言无残留子进程。 -- **快照:** 以 `TODO(claude-code-subagent-replay)` 和 `TODO(codex-subagent-replay)` 延后,等待 [subagent 回放 RFC](../../implemented/testing/2026-06-22-subagent-snapshot-replay.md) 描述的进程特定回放形状。 +- **无密钥单元/集成测试:** 通过真实 SDK 驱动一个假 Claude CLI,通过真实协议客户端驱动一个脚本化的 Codex app-server。在逐文件 100% 覆盖率下,验证往返、每种 stop 映射、两条取消路径及预中止、权限策略、未知消息、spawn 失败、reload 清理、导出形状、清洗后的环境、临时目录删除,以及 Codex 认证预检失败。 +- **有密钥 e2e 测试:** 每个真实引擎在 `acceptEdits` 或 `workspace-write` 下执行文件操作;跳过时命名缺失的二进制或密钥,并断言无残留子进程。 +- **快照测试:** 标记为 `TODO(claude-code-subagent-replay)` 和 `TODO(codex-subagent-replay)` 推迟,等待 [subagent 回放 RFC](../../implemented/testing/2026-06-22-subagent-snapshot-replay.md) 描述的进程特定回放形状。 ## 曾考虑的替代方案 -### 为什么不用官方 `@openai/codex-sdk` 而是手写客户端? +### 为什么不用官方 `@openai/codex-sdk` 而手写客户端? -dispose 阶梯和环境清洗要求拥有子进程(spawn 参数、env、信号、exit 等待);SDK 隐藏了进程。协议格式极其简单(LF JSON),形状可按固定版本生成(`codex app-server generate-json-schema`),且仓库先例(`hook-protocol`)是自有精简协议核心而非包装他人运行时。SDK 能节省协议演进的维护成本,但代价是失去本后端存在的意义所在的精确控制。 +dispose 阶梯和环境清洗要求拥有子进程(spawn 参数、env、信号、exit 等待);SDK 隐藏了进程。协议格式极其简单(LF JSON),形状可按固定版本生成(`codex app-server generate-json-schema`),仓库先例(`hook-protocol`)是拥有薄协议核心而非包装他人的运行时。SDK 能节省协议演进的维护成本,但代价是失去本后端存在的意义所在的精确控制。 ### 为什么不用模型可见的 `subagent_type` 参数(单一 Task 风格工具)? -Claude Code 自己的 Task 工具将 subagent 类型放在模型可见的 schema 中,选择一个 prompt + 工具集人格。这里的选择是在**执行引擎**之间做出的,而只有部署者知道哪些引擎配置了凭证——因此选择留在部署配置中,保持 `dsh-tool-subagent` 文档化的一提供方一工具契约。人格式的类型选择器应当是针对工具的独立 RFC,而非后端。 +Claude Code 自身的 Task 工具将 subagent 类型放在模型可见的 schema 中,选择一个 prompt + 工具集人格。这里的选择是在**执行引擎**之间做出的,而只有部署者知道哪些引擎配置了凭证——因此选择留在部署配置层,保持 `dsh-tool-subagent` 文档中的「一个提供方对应一个工具」契约。人格风格的类型选择器应是针对工具的另一个 RFC,而非针对后端。 -### 为什么不用登录态凭证和用户自己的配置? +### 为什么不用登录态凭证和用户自身的配置? -继承 `~/.claude` / `~/.codex`(订阅登录、用户设置、skill、MCP 服务器)会让子进程行为依赖宿主机状态,并在 ACP 后端和 bash 执行器确立的「凭证通过 `config.env` 显式进入,绝不隐式继承」规则上打一个隐式例外。仅 API key 加强制配置目录隔离保持了运行的可复现性;需要共享状态的部署可以刻意将配置目录字段指向一个持久目录。 +继承 `~/.claude` / `~/.codex`(订阅登录、用户设置、skill、MCP 服务器)会使子进程行为依赖宿主机状态,并在 ACP 后端和 bash 执行器确立的「凭证通过 `config.env` 显式进入,绝不隐式继承」规则上打开一个隐式例外。仅 API key 加强制配置目录隔离使运行可复现;需要共享状态的部署可以有意将配置目录字段指向一个持久目录。 -### 为什么不为 Claude Code keyless 测试注入一个驱动 seam? +### 为什么不为 Claude Code 无密钥测试注入驱动层 seam? -注入一个假 `query()` 会 mock 我们自己的边界,使真实 SDK 加载路径未被测试(docs/testing.md 中的 real-over-mock 策略)。曾考虑此方案的风险——SDK↔CLI 的 stream-json 控制协议是内部的——已被 spike 消除:假 CLI harness 今天能对着真实固定版本的 SDK 工作。如果 SDK 升级破坏了 mock,keyless 套件会让升级 PR 失败,这正是门禁在发挥作用。 +注入假的 `query()` 会 mock 我们自己的边界,使真实 SDK 加载路径未被测试(docs/testing.md 中的 real-over-mock 策略)。曾考虑此方案的风险——SDK↔CLI 的 stream-json 控制协议是内部实现——已被 spike 消除:假 CLI harness 今天能对真实固定版本的 SDK 正常工作。如果 SDK 升级破坏了 mock,无密钥套件会让升级 PR 失败,这正是门禁在发挥作用。 ### 为什么不用 ACP 适配器(如 `claude-code-acp`)复用既有后端? -社区 shim 将两个引擎包装为 ACP,这会让它们在 `dsh-subagent-acp` 上变成「仅配置」。但这在 harness 与引擎之间插入了一个非官方第三方层,抹掉了本 RFC 暴露的原生控制面(permissionMode、sandboxMode/approvalPolicy、配置目录隔离、apiKey RPC),并以 shim 的发布节奏换取第一方协议的稳定性。第一方接口——Agent SDK 和 app-server——才是受支持的集成点。 +社区 shim 将两个引擎包装为 ACP,这会使它们在 `dsh-subagent-acp` 上变成「仅配置」。但这在 harness 与引擎之间插入了一个非官方的第三方层,抹去了本 RFC 暴露的原生控制面(permissionMode、sandboxMode/approvalPolicy、配置目录隔离、apiKey RPC),并以 shim 的发布节奏替换了第一方协议的稳定性。第一方接口——Agent SDK 和 app-server——才是受支持的集成点。 ## 验收标准 -在同时配置了两个引擎和 key 的机器上:一个 REPL 驱动的模型通过 `subagent_claude_code` 完成一个真实文件任务,通过 `subagent_codex` 完成另一个,工具结果为子进程的最终回答,父会话日志中仅有 `tool/call` + `tool/result`。Keyless 套件在无凭证环境中以逐文件 100% 覆盖率通过,断言隔离(清洗后的子进程 env、dispose 后无残留临时配置目录)以及 `~/.claude` / `~/.codex` 的存在与否不影响子进程行为。取消父轮次后,两个后端在有界时间内静默,无残留子进程。e2e 套件干净地自跳过,命名缺失的前置条件。 +在两个引擎和密钥均已配置的机器上:一个 REPL 驱动的模型通过 `subagent_claude_code` 完成一个真实文件任务,通过 `subagent_codex` 完成另一个,工具结果为子进程的最终答案,父会话日志中仅有 `tool/call` + `tool/result`。无密钥套件在无凭证环境下以逐文件 100% 覆盖率通过,断言隔离(清洗后的子进程环境、dispose 后无残留临时配置目录),并断言 `~/.claude` / `~/.codex` 的存在与否不影响子进程行为。取消父轮次后,两个后端在有界时间内静默,无残留子进程。e2e 套件干净地自跳过,命名缺失的前置条件。 ## 风险 -- `codex app-server` 以 CLI flag 标记为实验性,其 v1/v2 词汇共存;客户端固定 0.142.5、仅实现 v2、消费未知方法/通知而不崩溃,但未来 codex 升级仍可能迫使返工(每次升级重新生成 schema 并重跑 keyless 套件——这是上述「不做运行时版本探测」立场背后的开发时强制执行)。 -- Claude Code 假 CLI mock 依赖一个内部协议:任何 SDK 升级都必须通过 keyless 套件,控制协议的破坏性变更意味着返工 mock(回退方案:上面否决的驱动注入 seam 成为逃生口)。 -- SDK 的 optionalDependencies 每平台约 280MB——已接受,且限制在单个后端包内。 -- SDK 的 SIGKILL 分支(EOF→SIGTERM 之后)未被观察到,信任其存在;e2e 保留无残留进程断言。 -- Codex 是部署前置条件(无 npm 捆绑的二进制文件);缺失或不兼容的二进制文件表现为大声的 spawn/协议 `error`,而非版本探测。 -- 每次运行付出一个全新子进程的代价,且仅最终回答浮出——思考、工具卡片和用量被消费后丢弃;池化、中间进度浮出、`sendMessage`/`resume`、通过 SDK 的 `outputFormat` 实现 `outputSchema`、以及通过 SDK 的 `agents` 选项实现命名 subagent 类型,均为刻意延后。 +- `codex app-server` 被 CLI 标记为实验性,其 v1/v2 词汇共存;客户端固定 0.142.5、仅实现 v2、对未知方法/通知消费而不崩溃,但未来 codex 升级仍可能迫使返工(每次升级重新生成 schema 并重跑无密钥套件——这是上述「不做运行时版本探测」立场背后的开发时强制执行)。 +- Claude Code 假 CLI mock 依赖一个内部协议:任何 SDK 升级都必须通过无密钥套件,控制协议的破坏性变更意味着返工 mock(回退方案:上面否决的驱动注入 seam 成为逃生舱口)。 +- SDK 的 optionalDependencies 每平台约 280MB——已接受,限制在单个后端包内。 +- SDK 的 SIGKILL 分支(EOF→SIGTERM 之后)未被观察到,信任其实现;e2e 保留无残留进程断言。 +- Codex 是部署前置条件(无 npm 内置二进制);缺失或不兼容的二进制以大声的 spawn/协议 `error` 呈现,而非版本探测。 +- 每次运行付出一个全新子进程的代价,且仅最终答案浮出——思考、工具卡片和用量被消费后丢弃;连接池、中间进度浮出、`sendMessage`/`resume`、通过 SDK 的 `outputFormat` 实现 `outputSchema`、以及通过 SDK 的 `agents` 选项实现命名 subagent 类型,均为刻意推迟。 diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml index d9853d91fe..a86bcca889 100644 --- a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-08-interactive-side-sessions.md: 250a906d9ec339399a0e0e29e70b2b8dc189fa72 -2026-07-08-interactive-side-sessions.zh.md: 17d416e2297320e8dfa238569230ecdec91dfa32 +2026-07-08-interactive-side-sessions.zh.md: d86a2b69232bc8ccad78555911b44cf727780e0c diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md index 17d416e229..d86a2b6923 100644 --- a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md @@ -1,41 +1,41 @@ # RFC:交互式侧会话与合并回写 -Status: proposed - [English](2026-07-08-interactive-side-sessions.md) | 中文 +Status: proposed + ## 问题 -用户可能希望在不改变当前会话主上下文的前提下探索一个问题。现有原语无法提供这种产品形态:[session-store fork](../../implemented/feature/2026-06-30-session-store-fork-api.md) 创建的是一个无关联的会话,而 [fork subagent](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 是模型驱动的任务,其 transcript(文本记录)会折叠为一条工具结果。两者都不能给用户一个独立的对话,也都不能将结论带着来源信息写回父会话。 +用户可能希望在不改变当前会话主上下文的前提下,探索一个来自活跃会话的问题。现有原语无法提供这种产品形态:[session-store fork](../../implemented/feature/2026-06-30-session-store-fork-api.md) 创建的是一个无关联的会话,而 [fork subagent](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 是模型驱动的任务,其 transcript(文本记录)会折叠为一条工具结果。两者都不能给用户一个独立的对话,也都不能将结论带着出处信息记录回父会话。 ## 提案 -**侧会话(side session)** 是一个普通的活跃会话,从源会话最后一个已完成轮次处 fork 而来,附属于自己的 agent,以只读顾问的角色运行,并能够**合并回写**一条精炼笔记。 +**侧会话(side session)** 是一个普通的活跃会话,从源会话的最后一个已完成轮次 fork 而来,绑定到自己的 agent,定位为只读顾问,并能**合并回写**一条精简笔记。 -- **Fork 并附属:** 以父会话的均衡已完成轮次前缀创建子会话,并在其元数据中标记 `parentSession` 与 `seedLength`。这组合了 `ctx.agents.create({ seed, meta })`;不新增核心服务或 session-store 方法。 -- **顾问框架:** 创建后注入一条插件来源的 `context/message`,告知子会话只做解释,不执行变更或继续任务。保持系统提示词逐字节一致,以保留提供方对继承历史的前缀缓存。 -- **合并回写:** 向子会话请求一条有长度上限的交还内容,然后向父会话注入一条插件来源的 `context/message`。父会话的下一次请求会在其日志位置看到它,保持回放与[请求可重建性](../../implemented/architecture/2026-07-05-reconstructable-requests.md),无需新增会话事件。 -- **呈现:** 调用方式、会话切换与交还内容的渲染属于首个客户端拥有的界面。本 RFC 仅规定与界面无关的机制。 +- **Fork 并绑定:** 以父会话的平衡已完成轮次前缀创建子会话,并在其元数据中标记 `parentSession` 与 `seedLength`。这组合了 `ctx.agents.create({ seed, meta })`;不新增核心服务或 session-store 方法。 +- **顾问定位:** 创建后注入一条插件来源的 `context/message`,告知子会话只做解释,不执行变更或继续任务。保持系统提示词逐字节一致,可在继承的历史上保留提供方的前缀缓存。 +- **合并回写:** 向子会话请求一条有长度上限的 handback,然后向父会话注入一条插件来源的 `context/message`。父会话的下一次请求在其日志位置看到该消息,保持回放与[请求可重建性](../../implemented/architecture/2026-07-05-reconstructable-requests.md),无需新增会话事件。 +- **呈现:** 调用方式、会话切换与 handback 渲染属于首个客户端拥有的界面。本 RFC 仅规定与界面无关的机制。 -回退产品化、会话树视图、面向模型的侧会话工具,以及 `forkName`/`mergedInto` 元数据不在本 RFC 范围内。一次 live-adapter 原型验证了源日志隔离、继承上下文、多轮子会话交互,以及合并回写在父会话下一轮次中的可见性。 +回退产品化、会话树视图、面向模型的侧会话工具,以及 `forkName`/`mergedInto` 元数据均不在本 RFC 范围内。一次 live-adapter spike 已验证了源日志隔离、继承上下文、多轮子会话交互,以及合并回写在父会话下一轮次中的可见性。 ## 曾考虑的替代方案 -- **使用 subagent seam:** 否决。侧会话是用户驱动的、客户端可见的,且可能比父会话的一个轮次存活更久;subagent 是模型驱动的运行,返回一条工具结果。 -- **修改子会话的系统提示词:** 默认否决,因为任何字节变化都会从第零个 token 起使前缀缓存失效。部署方仍可选择更强的隔离。 -- **新增 `sidechat/*` 事件:** 推迟。插件来源的 `context/message` 已经提供持久性、来源信息与回放能力;只有当某个界面需要区分渲染时,专用事件才有正当理由。 -- **现在就绑定协议界面:** 否决。当前 UI 由客户端拥有。实时呈现最终必须从持久化消息派生,以确保回放渲染出相同的记录。 +- **使用 subagent seam:** 否决。侧会话是用户驱动的、客户端可见的,且可能存活超过父会话的一个轮次;subagent 是模型驱动的运行,返回一条工具结果。 +- **修改子会话的系统提示词:** 默认否决,因为任何字节变化都会从第零个 token 起使前缀缓存失效。部署方仍可选择这种更强的隔离方式。 +- **新增 `sidechat/*` 事件:** 延后。插件来源的 `context/message` 已提供持久性、出处与回放能力;只有当某个界面需要差异化渲染时,专用事件才有正当理由。 +- **现在就绑定一个协议界面:** 否决。当前 UI 由客户端拥有。实时呈现最终必须从持久消息派生,以使回放渲染出相同的记录。 ## 验收标准 -- Fork 不改动源会话,并创建一个子会话,子会话具有均衡的已完成轮次前缀、`parentSession`、`seedLength`,以及逐字节一致的系统提示词。 -- 顾问框架在子会话追加历史的头部恰好添加一条插件来源的 `context/message`,而非修改其系统提示词。 +- Fork 不改变源会话,创建的子会话具有平衡的已完成轮次前缀、`parentSession`、`seedLength`,以及逐字节一致的系统提示词。 +- 顾问定位在子会话追加历史的头部恰好添加一条插件来源的 `context/message`,而非修改其系统提示词。 - 合并回写恰好添加一条有长度上限的 `context/message`,来源为 `plugin: sidechat`;父会话的下一次请求与回放在相同位置看到它。 -- 父会话与子会话并发运行,日志与流之间无串扰。 +- 父会话与子会话并发运行,日志和流之间无串扰。 - 单元测试覆盖 fork/attach 与合并回写;快照覆盖率随首个绑定界面一起落地。 ## 风险 -- 只读行为在 `tools/pre-execute` 拒绝门禁强制执行之前仅为建议性的;[拦截 seam](../../implemented/feature/2026-06-30-interception-seams.md) 可以在不改变本机制的前提下添加该门禁。 -- 经过压缩(compaction)的源会话 fork 出的是其压缩视图,因此绑定界面应当告知用户:子会话继承的是摘要而非被替换的轮次。 -- 反复的交还内容会消耗父会话上下文。每次合并的长度上限约束了单条笔记的大小;后续整合属于压缩的职责。 +- 只读行为在 `tools/pre-execute` 拒绝门禁强制执行之前仅为建议性质;[拦截 seam](../../implemented/feature/2026-06-30-interception-seams.md) 可在不改变本机制的前提下添加该门禁。 +- 经过压缩(compaction)的源会话 fork 出的是其压缩视图,因此绑定的界面应当告知用户子会话继承的是摘要而非被替换的轮次。 +- 反复的 handback 会消耗父会话上下文。每次合并的长度上限约束了单条笔记的大小;后续的合并整理属于上下文压缩的职责。 diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml index 349767710c..ab712ad131 100644 --- a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-10-sqlite-session-query-provider.md: 8b67baf420433feca9d5cd09d58852bb9b1545a9 -2026-07-10-sqlite-session-query-provider.zh.md: de97e59ac6f2f90a738ff5c8b9c2872d54ba3954 +2026-07-10-sqlite-session-query-provider.zh.md: ad6b44363ab54b66b597941adb13938f27971bd5 diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md index de97e59ac6..ad6b44363a 100644 --- a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md @@ -6,48 +6,48 @@ Status: proposed ## 问题 -精确读取服务 `ctx.sessionQuery` 有意不维护派生索引。大规模持久化的历史记录需要全文搜索,而不能在每次查询时扫描所有事件;同时,当前活跃会话需要一个比上次持久性检查点更新的覆盖层。搜索还需要具体的排序、摘要片段、过滤、分页、取消以及重建行为。 +精确读取的 `ctx.sessionQuery` 服务有意不维护派生索引。大规模持久化的历史记录需要全文搜索,而不是每次查询都扫描全部事件;当前的活跃会话则需要一个比上一次持久性检查点更新的覆盖层。搜索还需要具体的排序、摘要片段、过滤、分页、取消以及重建行为。 -如果把这些关注点拆分到一个推测性的 provider 协调器和一个数据库实现中,会产生两个耦合的协调状态机。第一个真实实现应当将源观察、提取、SQLite 事务、generation 管理和查询作为一个完整生命周期来拥有。 +如果把这些关注点拆分到一个推测性的 provider 协调器和一个数据库实现之间,会产生两个耦合的协调状态机。第一个真实实现应当将源观察、提取、SQLite 事务、generation 管理和查询作为一个完整的生命周期来拥有。 ## 提案 -在精确读取包旁新增 `@deepseek-ai/dsh-session-query-sqlite`。该包将暴露一个搜索服务或以其实际消费方所需的最小 API 扩展现有服务族;第一阶段不预先承诺 provider 注册协议。它将依赖 `ctx.sessions` 和可选的 `ctx.sessionPersistence`,拥有一个独立的派生 SQLite 数据库,并复用规范的 `foldSurface()` 分类。 +在精确读取包(exact-read package)旁新增 `@deepseek-ai/dsh-session-query-sqlite`。该包将暴露一个搜索服务,或以其实际消费方所需的最小 API 扩展服务族;第一阶段不预先承诺 provider 注册协议。它将依赖 `ctx.sessions` 和可选的 `ctx.sessionPersistence`,拥有一个独立的派生 SQLite 数据库,并复用规范的 `foldSurface()` 分类。 -实现拥有一个串行化的协调/数据库事务状态机。一次事务观察权威的持久化元数据和活跃快照,提取语义文档,更新派生表,推进相关的游标 generation,并执行或启用相应的查询。没有第二个服务维护并行的指纹、脏标记、活跃 ID 集合或失效 generation。 +实现拥有一个串行化的协调/数据库事务状态机。一次事务观察权威的持久化元数据和活跃快照,提取语义文档,更新派生表,推进相关的游标 generation,并执行或启用对应的查询。没有第二个服务维护并行的指纹、脏标记、活跃 ID 集合或失效 generation。 -持久化文档在重启后保留。活跃覆盖层是连接局部的,为同一会话遮蔽持久化行,在活跃所有者或数据库关闭时消失。派生数据库与规范持久化分离,因此索引重置、损坏、分词器变更和 schema 变动不会危及持久的对话日志。 +持久化文档在重启后存活。活跃覆盖层是连接本地的,对同一会话的持久化行进行遮蔽,在活跃所有者或数据库关闭时消失。派生数据库与规范持久化分离,确保索引重置、损坏、分词器变更和 schema 变动不会危及持久化的对话日志。 ## 随实现确定的搜索语义 -实现必须从可执行的用例出发定义跨会话和会话内两种搜索范围。每个可搜索事件是一个文档,包含会话元数据、事件元数据、surface 分类、归一化语义文本和有界的纯文本摘要片段。会话级结果按其最强匹配事件分组;数值化的后端分数保持私有。 +实现必须从可执行的用例出发定义跨会话和会话内两种搜索范围。每个可搜索事件是一个文档,包含会话元数据、事件元数据、surface 分类、归一化的语义文本和有界的纯文本摘要片段。会话级结果按其最强匹配事件分组;数值化的后端分数保持私有。 -过滤器在排序之前编译为参数化 SQL。查询语法作为数据处理。排序包含稳定的平局字段。不透明游标绑定到归一化的请求形状和最小相关 generation;不相关的会话变更不应使会话内游标失效。取消操作必须停止调用方等待,并在运行时允许的范围内中断 SQLite 工作。 +过滤器在排序之前编译为参数化 SQL。查询语法被视为数据。排序包含稳定的平局字段。不透明游标绑定到归一化的请求形状和最小相关 generation;不相关的会话变更不应使会话内游标失效。取消操作必须停止调用方等待,并在运行时允许的范围内中断 SQLite 工作。 -分词器选择仍是一个实现实验。FTS5 trigram 支持子串召回,但会拒绝短于三字符的有用词项并增大索引体积;提案在将其纳入契约之前,必须对比默认 Unicode 分词器做基准测试。 +分词器选择仍是实现层面的实验。FTS5 trigram 支持子串召回,但会拒绝短于三个字符的有用词项并增大索引体积;提案在将其写入契约之前,必须对该权衡与默认 Unicode 分词器进行基准测试。 ## 提取与协调 -该包首先为消息、推理(reasoning)、工具调用/结果、被拦截的提示词、上下文、steering(中途引导)、待办事项和错误/状态详情提供第一方语义提取。结构性事件和流式分片不贡献文档。未知的声明合并事件/内容类型保持不可搜索,除非有真实的扩展消费方证明需要公开的提取器注册表。 +该包首先为以下内容提供第一方语义提取:消息、reasoning、工具调用/结果、被阻止的提示词、上下文、steering(中途引导)、待办事项和错误/状态详情。结构性事件和流式分片不贡献文档。未知的声明合并事件/内容类型保持不可搜索,除非有真实的扩展消费方证明需要公开的提取器注册表。 -协调可以使用稳定指纹来避免重写未变更的持久化会话,但指纹的计算和存储由数据库包拥有。当源观察或提取失败时,它绝不能报告某行为最新。provider-schema 不匹配只重置派生数据库;普通的源变更使用事务性 upsert/delete。已挂载但不可读的持久化使受影响的搜索失败,但不影响规范写入或已知的活跃精确读取。 +协调可以使用稳定指纹来避免重写未变更的持久化会话,但数据库包拥有指纹的计算和存储。当源观察或提取失败时,它绝不能报告某行为最新。provider-schema 不匹配只重置派生数据库;普通的源变更使用事务性 upsert/delete。已挂载但不可读的持久化层使受影响的搜索失败,但不影响规范写入或已知的活跃精确读取。 ## 曾考虑的替代方案 -- **在规范持久化数据库中添加 FTS 表**:否决。可重建的索引不应与权威日志共享 schema/重置/故障边界。 -- **在第一阶段重新引入 provider 协调**:否决。只有一个计划中的实现,没有证据表明存在稳定的多 provider seam。 -- **立即持久化活跃覆盖层**:否决。活跃事件在现有检查点提交之前不是规范的。 -- **返回 BM25 分数**:否决。提供方特有的数值尺度在语料变化时不稳定。 +- **将 FTS 表添加到规范持久化数据库中**:否决,因为可重建的索引不应与权威日志共享 schema/重置/故障边界。 +- **重新引入第一阶段的 provider 协调**:否决,因为只有一个计划中的实现,且没有证据表明存在稳定的多 provider seam。 +- **立即持久化活跃覆盖层**:否决,因为活跃事件在现有检查点提交之前不是规范的。 +- **返回 BM25 分数**:否决,因为 provider 特定的数值尺度在语料变化时不稳定。 ## 验收标准 -- 重启测试覆盖未变更、新增、已变更和已删除的持久化会话,且不重建整个索引。 -- 重新打开时保留持久化行并移除活跃行;活跃行先遮蔽、后显露其持久化基底。 +- 重启测试覆盖未变更、新增、变更和删除的持久化会话,且不重建整个索引。 +- 重新打开时保留持久化行并移除活跃行;活跃行先遮蔽、后显露其持久化基础。 - 测试覆盖两种搜索范围、元数据过滤、surface 默认值、摘要片段、转义、确定性平局、分页、范围内的陈旧游标、取消、动态持久化挂载/卸载,以及事务失败后的恢复。 - schema 不匹配只重置派生数据库。 -- 一个无 key 的端到端测试将真实的持久化后端与真实的 SQLite 搜索包组合使用。 -- 在移入 `implemented/` 之前,本 RFC 须修订为实际实现的分词器和公开 API。 +- 一个 keyless 的端到端测试将真实的持久化后端与真实的 SQLite 搜索包组合使用。 +- 在移至 `implemented/` 之前,本 RFC 须修订为实际实现的分词器和公开 API。 ## 风险 -单一所有者比提供方无关的 seam 更简单,但初期可复用性较低。这是有意为之:第二个真实后端能揭示应当抽取什么。SQLite 运行时差异可能影响 FTS 排序和摘要片段,因此测试只能固定契约控制的排序和呈现。独立数据库增加了配置和生命周期工作,但保全了规范存储的安全边界。 +单一所有者比提供方无关的 seam 更简单,但初期可复用性较低。这是有意为之:第二个真实后端可以揭示应当抽取什么。SQLite 运行时差异可能影响 FTS 排序和摘要片段,因此测试只能固定契约控制的排序和呈现。独立数据库增加了配置和生命周期工作,但保全了规范存储的安全边界。 diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml index 6b40707fbf..a90fafdf8b 100644 --- a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-13-stream-workflow-progress-through-tool-calls.md: 525f2793052a80d82de29d2d370cfd747d002af6 -2026-07-13-stream-workflow-progress-through-tool-calls.zh.md: b5cc86df3ca42e513bda7e56b485a8287f275613 +2026-07-13-stream-workflow-progress-through-tool-calls.zh.md: 8dcb4aea2de50cdd278c702c9f6c85ab66e6be34 diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md index b5cc86df3c..8dcb4aea2d 100644 --- a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md @@ -6,38 +6,38 @@ Status: proposed ## 问题 -工作流引擎有意为 run、phase、narration 和子 agent 进度发出成对平衡的 `workflow/*` 观察事件,但目前没有生产消费方呈现它们。因此编辑器在最终结果到来之前只显示一张 pending 状态的工作流工具卡片,尽管引擎已经报告了当前活跃的 phase、脚本日志内容以及哪些子 agent 已启动或已完成。[dynamic-workflows 决策](../../implemented/feature/2026-07-05-dynamic-workflows.md)明确将 ACP 进度 UI 保留给这条事件流。 +工作流引擎有意为 run、phase、narration 和子 agent(智能体)进度发出成对的 `workflow/*` observation 事件,但目前没有生产消费方呈现这些事件。因此,编辑器在最终结果返回之前只显示一张 pending 状态的工作流工具卡片,尽管引擎已经报告了当前活跃的 phase、脚本日志内容以及哪些子 agent 已启动或已结束。[dynamic-workflows 决策](../../implemented/feature/2026-07-05-dynamic-workflows.md)明确将 ACP(Agent Client Protocol)进度 UI 保留给这一事件流。 -如果让 `dsh-acp` 直接监听工作流事件,会反转能力边界:通用的 UI 桥接层将依赖一个可选的工作流包(package),并对一个工具名做特殊处理。工具流水线已经拥有实时更新所需的路由信息(agent 和 call id),但只暴露了纯粹的 pending/final 展示器,因此长时间运行的工具没有提供方无关的方式在二者之间报告瞬态 UI 状态。 +如果让 `dsh-acp` 直接监听工作流事件,就会反转能力边界:通用的 UI 桥接层将依赖一个可选的工作流包(package),并对一个工具名做特殊处理。工具流水线已经拥有实时更新所需的路由信息(agent 和 call id),但只暴露了纯粹的 pending/final 展示器,因此长时间运行的工具没有提供方无关的方式在二者之间报告瞬态 UI 状态。 ## 提案 -为 `dsh-tools` 添加一条实时进度通道。注册表持有的 `ToolExecution` 新增 `reportProgress(view): boolean`,其中 `view` 是一个独立的、提供方无关的通用进度快照,包含可选的替换标题和面向 UI 的内容块。进度不能改变调用的 args 派生卡片标签、kind、原始输入、locations、terminal intent 或 diff intent;它只更新初始选定的展示形式中的实时标题/内容。执行活跃期间,该方法校验并快照 view,然后派发一个受限的、agent 作用域的 `tools/progress` 观察事件,携带权威的执行标识与快照。一旦 final-result 处理开始,方法返回 `false` 且不再派发,确保迟到的异步报告者无法覆盖终态卡片。观察者异常被记录但不会导致工具失败。 +为 `dsh-tools` 添加一条实时进度通道。注册表所有的 `ToolExecution` 新增 `reportProgress(view): boolean`,其中 `view` 是一个独立的、提供方无关的通用进度快照,包含可选的替换标题和面向 UI 的内容块。进度不能更改调用的 args 派生卡片标签、kind、原始输入、locations、terminal intent 或 diff intent;它只更新在最初选定的展示方式内的实时标题/内容。当执行处于活跃状态时,该方法校验并快照 view,然后分发一个受限的、agent 作用域的 `tools/progress` observation,携带权威的执行标识与快照。一旦 final-result 处理开始,方法返回 `false` 且不再分发,因此迟到的异步报告者无法覆盖终态卡片。观察者异常会被记录日志,不会导致工具失败。 -`dsh-acp` 以通用方式消费 `tools/progress`。它通过现有的 agent-to-session 映射解析执行所属的 agent,并为同一 call id 发出一条 in-progress 的 `tool_call_update`。由于报告仅在工具执行流水线内部可用,持久化的 `tool/call` 及其 ACP `tool_call` 始终先于第一条 update;在 `tools/result` 之前关闭报告者确保没有进度更新出现在 completed/failed 卡片之后。进度是实时 UI 状态而非模型输入或持久历史:会话回放继续从 `tool/call` 和 `tool/result` 重建 pending 与 final 卡片,无需重放瞬态更新。 +`dsh-acp` 以通用方式消费 `tools/progress`。它通过既有的 agent-to-session 映射解析执行所属的 agent,并为同一 call id 发出 in-progress 的 `tool_call_update`。由于报告仅在工具执行流水线内可用,持久化的 `tool/call` 及其 ACP `tool_call` 始终先于第一条 update;在 `tools/result` 之前关闭报告者,确保进度更新不会出现在 completed/failed 卡片之后。进度是实时 UI 状态,而非模型输入或持久历史:会话回放继续从 `tool/call` 和 `tool/result` 重建 pending 与 final 卡片,无需重放瞬态更新。 -`dsh-tool-workflow` 成为第一个生产者。每次工具执行在调用 `ctx.workflows.start()` 之前安装一个紧凑的事件捕获器,因为合法的引擎可能在 `start()` 内部同步发出进度。在调用返回之前,捕获器将观察到的事件按 `WorkflowRunInfo.id` 归约为候选状态;随后选取返回的 `WorkflowRun.id`、丢弃其他候选、报告累积的快照,并将后续匹配事件直接路由。如果 `start()` 抛出异常,捕获器被 dispose,其候选被丢弃。这在不向 `WorkflowStartRequest` 添加观察者关联、也不要求进度等到 `start()` 返回的前提下,保持了引擎的可替换性。 +`dsh-tool-workflow` 成为第一个生产者。每次工具执行在调用 `ctx.workflows.start()` 之前安装一个紧凑的事件捕获器,因为合法的引擎可能在 `start()` 内部同步发出进度。在调用返回之前,捕获器将观察到的事件按 `WorkflowRunInfo.id` 归约为候选状态;随后选取返回的 `WorkflowRun.id`,丢弃其他候选,报告累积的快照,并将后续匹配事件直接路由。如果 `start()` 抛出异常,捕获器被 dispose(资源释放),其候选状态被丢弃。这在不向 `WorkflowStartRequest` 添加观察者关联、也不要求进度等到 `start()` 返回的前提下,保持了引擎的可替换性。 -归约器消费现有的 start、phase、log、agent-start、agent-end 和 end 事件,报告一个替换快照,包含当前 phase、最新日志行、活跃子 agent 标签,以及 completed/failed/cancelled 计数。它不累积 narration transcript;已完成的子 agent 离开活跃集合、转为计数。`workflow/end`、工具结算或插件 dispose 移除归约器条目和事件捕获器。六种工作流事件、它们的元数据、成对的子 agent 生命周期、run handle、取消通道和观察者隔离保持不变;第三方观察者可继续直接消费它们。 +归约器消费既有的 start、phase、log、agent-start、agent-end 和 end 事件,报告一个替换快照,包含当前 phase、最新日志行、活跃子 agent 标签以及 completed/failed/cancelled 计数。它不累积 narration transcript(文本记录);已结束的子 agent 离开活跃集合,变为计数器。`workflow/end`、工具结算或插件 dispose 移除归约器条目和事件捕获器。六种工作流事件及其元数据、成对的子 agent 生命周期、run handle、取消通道和观察者隔离保持不变;第三方观察者可继续直接消费这些事件。 -更新工具执行/展示文档、生成的事件与 API 目录、工作流包文档以及工作流数据结构目录。ACP 集成覆盖率必须使用脚本化的模型边界对真实的工作流工具和 worker seam 进行测试;主 ACP 快照套件新增一个 workflow-progress 场景,因为此变更改变了面向编辑器的 transcript。 +更新工具执行/展示文档、生成的事件与 API 目录、工作流包文档以及工作流数据结构目录。ACP 集成覆盖率必须使用脚本化的模型边界测试真实的工作流工具和 worker seam;主 ACP 快照套件新增一个 workflow-progress 场景,因为这改变了面向编辑器的 transcript。 ## 曾考虑的替代方案 -**删除工作流观察面。** 在 [collapse-workflow 简化提案](../../rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md)中被否决:这些事件及其平衡的生命周期是有意设计的,缺失的部分是消费方。 +**删除工作流 observation 表面。** 在 [collapse-workflow 简化提案](../../rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md)中被否决:这些事件及其成对生命周期是有意设计的,缺少的是消费方。 -**让 ACP 直接了解工作流。** 这可以将 `WorkflowRunInfo` 映射到会话和卡片,但会使通用桥接层依赖一个可选能力,并绕过「工具拥有展示意图」的规则。工具进度通道为所有长时间运行的工具解决了同样的路由问题。 +**让 ACP 直接了解工作流。** 这可以将 `WorkflowRunInfo` 映射到会话和卡片,但会使通用桥接层依赖一个可选能力,并绕过「工具拥有展示意图」的规则。工具进度通道为每个长时间运行的工具解决了相同的路由问题。 -**将每次进度更新持久化为会话事件。** 这会使实时 narration 可回放,但会用一种权威持久结果已由 tool call/result 对表达的状态永久膨胀日志。如果可恢复的工作流进度成为产品需求,它需要一个工作流日志化设计,而非伪装成持久事实的 UI 快照。 +**将每条进度更新持久化为会话事件。** 这会使实时 narration 可回放,但会用一种状态永久膨胀日志,而该状态的权威持久结果已经是工具调用/结果对。如果可恢复的工作流进度成为产品需求,需要一个工作流日志化设计,而非伪装成持久事实的 UI 快照。 ## 验收标准 -- `ToolExecution.reportProgress()` 由注册表持有、agent 作用域、快照化、观察者隔离,且在终态处理开始后返回 `false` 而不派发。 -- ACP 将进度路由到正确实时会话中的正确调用;不同会话中的并发工作流不能串扰,且 `tool_call_update` 不会出现在其 `tool_call` 之前或终态更新之后。 -- 工作流进度显示当前 phase、最新日志行、活跃子 agent 和结果计数,同时保持所有现有 `workflow/*` 事件和 run 语义;一个在 `start()` 内部同步发出 start、phase、log、child 和 end 事件的 seam 测试引擎不会丢失任何归约器状态。 +- `ToolExecution.reportProgress()` 由注册表所有、agent 作用域、快照化、观察者隔离,且在终态处理开始后返回 `false` 而不分发。 +- ACP 将进度路由到正确的实时会话中的正确调用;不同会话中的并发工作流不能串扰,且 `tool_call_update` 不会出现在其 `tool_call` 之前或终态更新之后。 +- 工作流进度显示当前 phase、最新日志行、活跃子 agent 和结果计数,同时保留所有既有 `workflow/*` 事件和 run 语义;一个在 `start()` 内部同步发出 start、phase、log、child 和 end 事件的 seam 测试引擎不会丢失任何归约器状态。 - 取消、worker 死亡、工具失败、会话关闭和插件 dispose 释放归约器状态;回放仅发出持久的 pending/final 卡片对。 - 单元测试、工作流集成测试、ACP 集成测试、快照、类型检查、覆盖率、doc-sync、module-graph、构建和 hygiene 门禁全部通过。 ## 风险 -此变更向工具 seam 添加了一个公开的实时进度方法和事件,因此实现方必须精确维护 active/terminal 边界,并在观察者看到快照之前将其分离。pre-start 捕获器可能短暂观察到无关的工作流 run,因此它仅按 run id 持有紧凑的候选状态,并在 `start()` 返回后立即丢弃所有不匹配的候选。一个工作流可能发出大量进度变更;有界归约器避免了 transcript 增长,但在关联之后仍会为每个有意义的事件发送一次 UI 更新。如果实测客户端需要合并更新,必须通过带默认值的、经过校验的桥接配置实现,而非硬编码的节流。瞬态进度在回放时有意消失,因此最终的工具结果仍是唯一持久的工作流卡片内容。 +本提案向工具 seam 添加了一个公开的实时进度方法和事件,因此实现方必须精确维护 active/terminal 边界,并在观察者看到快照之前将其分离。pre-start 捕获器可能短暂观察到无关的工作流 run,因此它仅按 run id 持有紧凑的候选状态,并在 `start()` 返回后立即丢弃所有不匹配的候选。一个工作流可能发出大量进度变更;有界归约器避免了 transcript 增长,但在关联完成后仍会为每个有意义的事件发送一条 UI 更新。如果经测量的客户端需要合并更新,这必须是一个带默认值的、经过校验的桥接配置,而非硬编码的节流。瞬态进度在回放时有意消失,因此最终工具结果仍是唯一持久的工作流卡片内容。 diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml index 26c31b7471..fc5effd89a 100644 --- a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-api-extractor-reports.md: 0f3f736ba662fd6366eb8d7f26887fb319b2b563 -2026-06-11-api-extractor-reports.zh.md: 3c472d64bc96c7fffa784c091f8a7a70bb0beb56 +2026-06-11-api-extractor-reports.zh.md: cf0eb3f9edbcfb2ae862f075af0628e716693a86 diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md index 3c472d64bc..cf0eb3f9ed 100644 --- a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md @@ -4,29 +4,29 @@ Status: proposed -> 从最初的「Doc-sync 与 API 报告」RFC(2026-06-11)中拆出。第 1、2 部分(文档块类型检查、事件分类体系校验)已交付——见 [doc-sync 强制](../../implemented/process/2026-06-11-doc-sync-enforcement.md)。本文是被推迟的第 3 部分,作为独立提案保留。 +> 从最初的「Doc-sync 与 API 报告」RFC(2026-06-11)中拆出。第 1–2 部分(文档块类型检查、事件分类体系校验)已交付,见 [doc-sync 强制](../../implemented/process/2026-06-11-doc-sync-enforcement.md)。本文是被推迟的第 3 部分,作为独立提案保留。 ## 问题 -公开 API 的变更是不可见的:没有任何机制让「这个 commit 改变了公开接口」成为一个显式、可评审的事实。评审者阅读 diff 时可能遗漏一个导出类型新增了字段或方法签名发生了变化。 +公开 API 的变更是不可见的:没有任何机制将「此次提交改变了公开接口」变为一个显式、可评审的事实。评审者阅读 diff 时可能遗漏某个导出类型新增了字段,或某个方法签名发生了变化。 ## 提案 -使用 api-extractor(或 `tsc --emitDeclarationOnly` 加一份归一化的公开接口导出)为每个包(package)生成一份签入仓库的 `etc/<pkg>.api.md`;如果重新生成的结果与签入版本不同,CI 失败。这样每一次公开 API 变更都会变成评审者(或评审 agent)必须看到的一行 diff。 +使用 api-extractor(或 `tsc --emitDeclarationOnly` 加一份规范化的公开接口导出)为每个包(package)生成一份签入仓库的 `etc/<pkg>.api.md`;CI 在重新生成结果与已签入报告不一致时失败。这样,每一次公开 API 变更都会成为评审者(或评审 agent(智能体))必须看到的一行 diff。 ## 曾考虑的替代方案 -**`tsc --emitDeclarationOnly` 加一份归一化的公开接口导出**:如果 api-extractor 被证明过重,这是更轻量的机制;两者都满足本提案所需的「签入仓库、可 diff」的报告形态。 +**`tsc --emitDeclarationOnly` 加规范化的公开接口导出**:如果 api-extractor 过于笨重,这是更轻量的机制;两者都能满足提案所需的「签入仓库、可 diff」的报告形态。 ## 验收标准 -- 每个包有一份签入仓库的 `etc/<pkg>.api.md`;重新生成结果与已提交报告不同时 CI 失败。 +- 每个包都有一份签入仓库的 `etc/<pkg>.api.md`;CI 在重新生成结果与已提交报告不一致时失败。 - 公开 API 变更(新增导出、字段放宽、签名变化)在评审中以报告 diff 行的形式可见。 ## 风险 -该依赖重且难伺候——这正是它被推迟的原因——且报告格式会随编译器升级而变动,在各包尚未发布的阶段增加了一个收益甚微的维护面。 +该依赖笨重且难以调教(这正是它被推迟的原因),且报告格式会随编译器升级而变动,增加一个维护面;在各包尚未发布的阶段,收益有限。 ## 推迟原因 -在 doc-sync 落地时被推迟:对于评审者已经能看到源码 diff 的内部 monorepo 而言价值有限,且依赖重、难伺候。如果这些包将来对外发布,届时一份稳定、可 diff 的公开接口报告才值得其维护成本。 +在 doc-sync 落地时被推迟:对于一个内部 monorepo,评审者已经能看到源码 diff,价值不高;且依赖笨重、难以调教。如果各包将来对外发布,再重新评估——届时一份稳定、可 diff 的公开接口报告才值得其维护成本。 diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml index 8aa3f297cd..094c2c349b 100644 --- a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-architectural-conformance.md: 40858d049af2df1928e27280238d0b198a5202f7 -2026-06-11-architectural-conformance.zh.md: d61751210ef78b26e05a05efae4d5abccbfd2e5c +2026-06-11-architectural-conformance.zh.md: b68355dc1c04a4f807efdb95f813159cb7f9f178 diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md index d61751210e..b68355dc1c 100644 --- a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md @@ -6,31 +6,31 @@ Status: proposed ## 问题 -两项架构保证目前仅存在于行文中:(1)任何包不得依赖具体的 loop 包([微内核承诺](../../implemented/architecture/2026-06-11-microkernel-event-taxonomy.md));(2)每个 LlmAdapter 都正确地遵循 chunk 协议。两者都应当机械化([质量门禁原则](../../implemented/process/2026-06-11-quality-gates.md))。 +目前有两项架构保证仅存在于行文中:(1)没有任何东西依赖具体的 loop 包([微内核承诺](../../implemented/architecture/2026-06-11-microkernel-event-taxonomy.md));(2)每个 LlmAdapter 都正确地遵循 chunk 协议。二者都应当是机械化的([质量门禁原则](../../implemented/process/2026-06-11-quality-gates.md))。 ## 提案 **dependency-cruiser** 配合以下规则: -- `packages/*`(agent-loop 自身的测试和 examples/ 除外)禁止导入 `@deepseek-ai/dsh-agent-loop`。 +- `packages/*`(除 agent-loop 自身的 tests 和 examples/ 外)禁止导入 `@deepseek-ai/dsh-agent-loop`。 - 禁止跨包深层导入(`@deepseek-ai/dsh-*/src/...` 路径)——只允许使用公开入口点。 -- packages/ 内禁止任何导入循环。 +- packages/ 内禁止导入循环。 - `vendor/*` 禁止从 `packages/*` 导入。 -- 分层:dsh-llm 不导入其他 dsh 包;dsh-session 只导入 dsh-llm;以此类推(即 packages/README.md 中的依赖表,强制执行)。 +- 分层:dsh-llm 不导入其他 dsh 包;dsh-session 仅导入 dsh-llm;以此类推(packages/README.md 中的依赖表,强制执行)。 -**适配器一致性套件**位于 dsh-llm(`@deepseek-ai/dsh-llm/conformance`):一个可复用的 vitest 套件,以适配器工厂为参数,断言 chunk 协议契约——每个 block 的 index 单调递增、`block-end` 之后该 index 不再有 delta、恰好一个 `finish`、usage 至多出现一次、每个 `tool-call-delta` 携带 call id、abort 被及时响应。当前对 mock 运行;DeepSeek V4 适配器从第一天起继承该套件。可选地提供一个 dev 模式的 `strictAdapter()` 包装层,在 debug flag 下于运行时强制执行相同约束(与 [dev 模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)配对)。 +**适配器一致性套件**位于 dsh-llm(`@deepseek-ai/dsh-llm/conformance`):一个可复用的 vitest 套件,以适配器工厂为参数,断言 chunk 协议契约——每个 block 内 index 单调递增、`block-end` 之后该 index 不再有 delta、恰好一个 `finish`、usage 至多出现一次、每个 `tool-call-delta` 携带 call id、abort 被及时响应。当前对 mock 运行;DeepSeek V4 适配器从第一天起继承该套件。可选地提供一个 dev 模式的 `strictAdapter()` 包装层,在 debug flag 下于运行时强制执行相同规则(与 [dev 模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md) 配对)。 ## 计划 -先落地 dependency-cruiser 配置与 CI 步骤(约一小时工作量,永久保证);一致性套件随其首个消费方测试(针对 MockAdapter)一起落地,并作为 V4 适配器阶段的前置条件。 +先落地 dependency-cruiser 配置与 CI 步骤(约一小时工作量,换来永久保证);一致性套件随其首个消费方测试(针对 MockAdapter)一起落地,并作为 V4 适配器阶段的前置条件。 ## 验收标准 - dependency-cruiser 在 CI 中运行上述规则族;违规导入导致构建失败。 -- 一致性套件对 mock 适配器和两个正式适配器运行通过;新适配器包通过调用该套件并传入自己的工厂即可继承测试。 +- 一致性套件对 mock 适配器和两个正式适配器运行,新适配器包通过调用该套件并传入自己的工厂即可继承测试。 ## 风险 -随着包的增加需要维护 dep-cruiser 规则——应保持规则基于模式(`dsh-*`)而非逐一枚举。 +随着包的增加,dep-cruiser 规则需要维护——规则应基于模式(`dsh-*`)而非逐一枚举。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml index 5ac9f62fee..62e4b4aa6f 100644 --- a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-supply-chain-and-vendor-drift.md: 306e185e9175e3e7af24455cf95167f54b3d1c17 -2026-06-11-supply-chain-and-vendor-drift.zh.md: 1aeb0a8eff3f335bc87c05742acc4502a19bf3c5 +2026-06-11-supply-chain-and-vendor-drift.zh.md: a840e766c49182d7a9ca648acbbab1a2762688f5 diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md index 1aeb0a8eff..a840e766c4 100644 --- a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md @@ -1,4 +1,4 @@ -# RFC:供应链检查与 vendor 漂移校验 +# RFC:供应链检查与 vendor 漂移验证 [English](2026-06-11-supply-chain-and-vendor-drift.md) | 中文 @@ -6,30 +6,30 @@ Status: proposed ## 问题 -vendor manifest([vendor 化决策](../../implemented/process/2026-06-11-vendor-cordis-as-source.md))在提交时只做*正向*强制(vendor 代码变更 ⇒ manifest 更新),但没有任何机制校验 manifest 的*声明*:即 vendor/ 确实等于「上游指定 SHA 的代码 + 日志中记录的修改」。此外,少量真正的 npm 依赖也没有安全公告监控或更新节奏。 +vendor manifest(元数据清单)(见[引入 vendor 的决策](../../implemented/process/2026-06-11-vendor-cordis-as-source.md))在提交时仅在**正向**强制执行(vendor 变更 ⇒ manifest 更新),但没有任何机制验证 manifest 的**声明**:即 vendor/ 确实等于上游指定 SHA 的内容加上所记录的修改。此外,少量真正的 npm 依赖也没有安全公告监控或更新节奏。 ## 提案 -1. **Vendor 漂移检查**(夜间 CI):以 manifest 中的 SHA 浅克隆上游仓库,复制对应 package 的源码,与 `vendor/*/src` 做 diff。除非 diff 与日志中的本地修改一致(每项修改保存为一个入库的 patch 文件,使日志条目成为可校验的产物而非纯文字),否则 job 失败。 -2. **依赖安全公告**:对 lockfile 运行 osv-scanner(或 `pnpm audit`),按计划调度 + 在涉及 lockfile 的 PR 上触发。 -3. **许可证清单**:一个脚本断言每个 vendor 化的 package 都携带 LICENSE 文件,且 package.json 的 `license` 字段与 vendor/README.md 中的清单一致(我们混合了 vendor 化的 MIT 与自有的 BSD-3)。作为 CI 步骤运行。 -4. **Renovate**(或一个定时 agent 任务)以小 PR 提议 npm 依赖更新,这些 PR 走完整门禁套件;vendor 化的 package 排除在外(它们的更新遵循 manifest 同步流程,理想情况下作为半自动化的 agent 工作流:拉取上游、重新应用 patch、运行门禁、打开 PR 并更新 manifest 表格)。 +1. **Vendor 漂移检查**(夜间 CI):以 manifest 中记录的 SHA 浅克隆上游仓库,复制对应的 package 源码,与 `vendor/*/src` 做 diff。除非 diff 与已记录的本地修改一致(每项修改以签入的 patch 文件保存——日志条目从行文描述变为可验证的产物),否则任务失败。 +2. **依赖安全公告**:对 lockfile 运行 osv-scanner(或 `pnpm audit`),按计划定期执行,并在涉及 lockfile 变更的 PR 上触发。 +3. **许可证清单**:一个脚本断言每个 vendor 包都携带其 LICENSE 文件,且 package.json 的 `license` 字段与 vendor/README.md 中的清单一致(我们混合了 vendor 的 MIT 与自有的 BSD-3)——作为 CI 步骤运行。 +4. **Renovate**(或定时 agent 任务)以小 PR 的形式提议 npm 依赖更新,这些 PR 走完整门禁套件;vendor 包不在其列(它们的更新遵循 manifest 同步流程,理想情况下是半自动化的 agent 工作流:拉取上游、重新应用 patch、运行门禁、以更新后的 manifest 表格开 PR)。 ## 计划 -3 最简单,先做。1 需要 CI 能通过网络访问上游仓库(私有镜像,需要 token),并将现有两项已记录的修改转为 patch 文件。2 和 4 属于配置工作。 +第 3 项最简单,先做。第 1 项需要 CI 能通过网络访问上游仓库(私有仓库,需要 token),并将现有两项已记录的修改转换为 patch 文件。第 2 项和第 4 项是配置工作。 ## 曾考虑的替代方案 -- **用 `pnpm audit` 代替 osv-scanner**:两者都满足安全公告扫描的需求;具体选择推迟到实现阶段决定。 -- **用定时 agent 任务代替 Renovate**:在「以小 PR 提议更新并走完整门禁」这件事上效果等价;vendor 化的 package 无论哪种方案都排除在外(它们的更新遵循 manifest 同步流程)。 +- **用 `pnpm audit` 替代 osv-scanner**:两者都满足安全公告扫描的需求;具体选择推迟到实现阶段决定。 +- **用定时 agent 任务替代 Renovate**:在提议小型更新 PR 并走完整门禁套件方面效果等价;vendor 包无论哪种方案都不在其列(它们的更新遵循 manifest 同步流程)。 ## 验收标准 -- 许可证清单脚本在 CI 中运行,缺少 LICENSE 或 `license` 字段与 `vendor/README.md` 清单矛盾时失败。 -- 夜间漂移 job 从 manifest SHA 加入库 patch 文件重建 `vendor/`,出现任何无法解释的 diff 时失败。 -- 安全公告扫描按计划对 lockfile 运行,并在涉及 lockfile 的 PR 上运行。 +- 许可证清单脚本在 CI 中运行,缺少 LICENSE 或 `license` 字段与 `vendor/README.md` 中的清单矛盾时失败。 +- 夜间漂移任务从 manifest SHA 加签入的 patch 文件重建 `vendor/`,出现任何无法解释的 diff 时失败。 +- 安全公告扫描按计划定期运行,并在涉及 lockfile 变更的 PR 上运行。 ## 风险 -上游仓库是私有镜像;CI 凭证与可用性是漂移检查的主要阻力。如果受阻,改为本地定时 agent 任务而非 CI 运行。 +上游仓库是私有镜像;CI 凭证与可用性是漂移检查的主要阻力。如果受阻,可改为本地定时 agent 任务而非 CI。 diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml index f08e3c5dff..ddaafef6da 100644 --- a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-discover-package-inventory.md: 22b3e9acbe4dad8ef829d0dd30415c516031d66b -2026-06-20-discover-package-inventory.zh.md: 8b62d42d2d514f60016690ba55d5ce77a50b3aff +2026-06-20-discover-package-inventory.zh.md: 4eeaed9ed6b390608095281775883f8e7a52e954 diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md index 8b62d42d2d..4eeaed9ed6 100644 --- a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md @@ -1,36 +1,36 @@ -# RFC:通过发现机制获取包清单,取代静态列表维护 - -[English](2026-06-20-discover-package-inventory.md) | 中文 +# RFC:通过发现机制获取包清单,而非维护静态列表 Status: proposed +[English](2026-06-20-discover-package-inventory.md) | 中文 + ## 问题 -包(package)与门禁的清单在 TypeScript project references、package 文档、CI 行文、Knip 覆盖项以及快照场景元数据中反复出现。其中大部分只是重述包布局、manifest 数据、聚合命令内容或 fixture(测试前置数据)文件。每新增一个包或场景,都会产生本可避免的同步点。 +包(package)与门禁清单在 TypeScript project references、包文档、CI 描述、Knip 覆盖项以及快照场景元数据中反复出现。大多数只是重述包布局、manifest 数据、聚合命令内容或 fixture(测试前置数据)文件。因此每新增一个包或场景都会产生本可避免的同步点。 -[包层级结构](../../implemented/architecture/2026-06-20-package-hierarchy.md)已经手动消除了其中若干:`scripts/publint-all.ts` 现在从 `packages/<group>/<pkg>` 布局推导清单,两份 `tsconfig` 的 `paths` 映射也合并为一个 `@deepseek-ai/dsh-*` 通配符。剩下的是无法用 glob 消除的清单——主要是 `tsconfig.build.json` 的 project `references`,TypeScript 要求它是一个显式数组(没有通配符形式)。 +[包层级结构](../../implemented/architecture/2026-06-20-package-hierarchy.md)已经手动消除了其中若干:`scripts/publint-all.ts` 现在从 `packages/<group>/<pkg>` 布局推导列表,两份 `tsconfig` 的 `paths` 映射也合并为一个 `@deepseek-ai/dsh-*` 通配符。剩下的是无法用 glob 消除的清单,主要是 `tsconfig.build.json` 的 project `references`——TypeScript 要求它是显式数组(没有通配符形式)。 -静态列表在编码策略时是合理的;当它们只是重复 `package.json`、workspace glob 或包层级结构中已有的 manifest 数据或布局事实时,就是无谓的摩擦。 +当静态列表编码的是策略时,它们是合理的;当它们只是重复 `package.json`、workspace glob 或包层级结构中已有的 manifest 数据或布局事实时,就是不必要的摩擦。 ## 提案 -让剩余的包/门禁清单可被发现。一个唯一的权威来源——`packages/<group>/<pkg>` 层级结构加上 package manifest——应当驱动 `tsconfig.build.json` 的 `references`、模块图以及任何全量包列表,并配合一个生成加校验步骤(沿用现有的 `gen-module-graph` / `gen-cordis-catalog` 模式:生成器写入产物,`--check` 模式在 `hygiene`/`doc-sync` 中检测已提交副本是否陈旧)。模块图生成器已经在读取 package manifest。`doc-sync` 应当成为定义并打印其子门禁的唯一命令,文档链接到该命令而非重述第二份清单。 +让剩余的包/门禁清单可被发现。一个唯一的权威来源——`packages/<group>/<pkg>` 层级结构加上包 manifest(元数据清单)——应当驱动 `tsconfig.build.json` 的 `references`、模块图以及任何全量包列表,并配合一个生成加校验步骤(沿用现有的 `gen-module-graph` / `gen-cordis-catalog` 模式:生成器写出产物,`hygiene`/doc-sync(文档同步门禁)中的 `--check` 模式在提交副本陈旧时报错)。模块图生成已经在读取包 manifest。`doc-sync` 应当成为定义并打印其子门禁的唯一命令,文档链接到该命令而非重述第二份列表。 -层级结构不需要编码一个包的所有信息,但应当编码宽泛的维护策略:core/product 包、集成包、能力 seam 包与 support/test/example 包不应在脚本能区分它们之前先要求一份手工维护的例外清单。 +层级结构不需要编码关于包的所有事实,但应当编码宽泛的维护策略:core/product 包、集成包、能力 seam 包与 support/test/example 包不应在脚本能区分它们之前先要求一份手工维护的例外列表。 -有两项被编目的内容根本不需要生成器:把 e2e 入口 glob 折入 knip 的默认 stanza 即可直接删除各包的重述;`childSessions` 可以从每个场景的 fixture 目录发现,让场景表只声明策略(`recorded`、`hasModelTurn`、`comparesLog`)。而即便这些策略字段,今天也在追踪可从 fixture 推导的事实(`comparesLog` ⟺ 已提交的日志在表头行之后有内容;`recorded` ⟺ `hasModelTurn` 且没有 `replay.override.json` 兄弟文件),因此每个新场景类别都在不断添加 fixture 目录已经能回答的开关。 +有两类编目项根本不需要生成器:将 e2e 入口 glob 折入 knip 的默认配置段即可直接删除逐包的重复声明;`childSessions` 可从每个场景的 fixture 目录发现,使场景表只需声明策略(`recorded`、`hasModelTurn`、`comparesLog`)。而且即便是这些策略字段,今天也在追踪可从 fixture 推导的事实(`comparesLog` ⟺ 已提交的日志在头行之后还有条目;`recorded` ⟺ `hasModelTurn` 且没有 `replay.override.json` 兄弟文件),因此每个新场景类都在不断添加 fixture 目录本身已经能回答的开关。 ## 验收标准 -- `tsconfig.build.json` 的 project `references` 由层级结构生成(生成器输出它们;`--check` 门禁在已提交副本陈旧时失败),而非手工维护。 -- 新增一个包不需要为任何门禁编辑静态包列表。 +- `tsconfig.build.json` 的 project `references` 由层级结构生成(生成器输出它们;`--check` 门禁在提交副本陈旧时报错),而非手工维护。 +- 新增一个包时,不需要为任何门禁编辑静态包列表。 - 文档描述真源,而非重复生成的清单。 - CI 调用聚合命令,由这些命令自行管理其子门禁列表。 -- `knip.json` 仅在编码真实信息(额外入口文件、被忽略的依赖)时才携带 per-package 覆盖项,绝不重述默认 stanza。 +- `knip.json` 仅在编码真实信息(额外入口文件、被忽略的依赖)时才携带逐包覆盖项,绝不重述默认配置段。 - 快照场景只声明策略,不声明可从其 fixture 目录发现的事实。 ## 风险 -发现脚本可能变得过于精巧。实现应保持朴素:读取 manifest、按显式字段过滤、打印解析后的列表、出错时大声报错。收益在于消除手工清单漂移,而非发明一套构建系统。 +发现脚本可能变得过于精巧。实现应当保持朴素:读取 manifest、按显式字段过滤、打印解析后的列表、出错时大声报错。收益在于消除手工清单的漂移,而非发明一套构建系统。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml index db8dc2d650..dde7a0ad32 100644 --- a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-unify-agent-and-session-id.md: 3a6daa411673003eb1c3017e7a717ae4bf98b735 -2026-06-20-unify-agent-and-session-id.zh.md: c931831c028e3147bfb84ed4fdeefe83037e92f4 +2026-06-20-unify-agent-and-session-id.zh.md: 6b1b996879125c6ab85aed7ba419aff15d077b42 diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md index c931831c02..6b1b996879 100644 --- a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md @@ -6,37 +6,37 @@ Status: proposed ## 问题 -agent 工厂为每个活跃的 agent/会话对维护两个 id:`agentId`(`AgentRegistry` 的路由句柄)和 `sessionId`(事件溯源与持久化日志的身份标识)。`CreateAgentOptions` 接收两者;`ResumeAgentOptions` 接收 `agentId` 加 `resumeSessionId`;进程内 subagent 铸造两个独立的 UUID,尽管血缘关系另行记录。 +agent 工厂为每个活跃的 agent/session 对维护两个 id:`agentId`(`AgentRegistry` 的路由句柄)和 `sessionId`(事件溯源与持久化日志的标识)。`CreateAgentOptions` 接收两者;`ResumeAgentOptions` 接收 `agentId` 加 `resumeSessionId`;进程内 subagent 各自铸造两个独立的 UUID,尽管血缘关系另行记录。 -ACP(Agent Client Protocol)已经对两个身份使用同一个值。二者在配置创建的 agent、恢复的会话和进程内子 agent 中才出现分歧,但没有任何生产路径会将一个活跃 agent 重新关联到多个会话,或让一个会话经过多个 agent id。Stdio 保留 `labelBySession` 仅仅是为了从会话事件中恢复 agent 标签,而钩子同时暴露两个值让使用者自行对齐。 +ACP(Agent Client Protocol)已经对这两个标识使用同一个值。它们在配置创建的 agent(智能体)、恢复的会话和进程内子 agent 中才出现分歧,但没有任何生产路径会把一个活跃 agent 重新关联到多个会话,或让一个会话经过多个 agent id。Stdio 保留 `labelBySession` 仅仅是为了从会话事件中恢复 agent 标签,而钩子同时暴露两个值让使用者自行调和。 -[agent 作用域运行时](../../implemented/architecture/2026-07-12-agent-scope-runtime-design.md)没有与身份相关的预留状态:创建和恢复使用同一个 `AgentCreationTransaction`,两个注册表条目使用相同的 final-entry 碰撞规则。分离的 id 并未复制活跃性、回滚或静默机制。统一后删除一个调用方提供的 id、每个进程内子 agent 的一个 UUID 以及剩余的翻译路径,而不改变事务生命周期;同时使活跃 agent 注册表强制执行后台任务所有权所使用的会话身份。 +[agent-scope 运行时](../../implemented/architecture/2026-07-12-agent-scope-runtime-design.md)没有与标识相关的保留状态:创建和恢复使用同一个 `AgentCreationTransaction`,两个注册表条目都使用相同的 final-entry 碰撞规则。分离的 id 并不会使活跃性、回滚或静默机制产生重复。统一后删除一个调用方提供的 id、每个进程内子 agent 的一个 UUID 以及剩余的转换路径,而不改变事务生命周期;同时使活跃 agent 注册表强制执行后台任务所有权所使用的会话标识。 -`Session` 另外同时暴露 `Session.id` 和 `Session.header.id`,尽管构造时要求二者一致。持久化边界必须校验这一重复值,消费方必须在同一事实的两个归属位置之间做选择。 +`Session` 另外同时暴露 `Session.id` 和 `Session.header.id`,尽管构造时要求二者必须一致。持久化边界必须校验这个重复值,消费方必须在同一事实的两个归属位置之间做选择。 ## 提案 -对 agent 注册表条目和 `session.header.id` 使用同一个 id。`CreateAgentOptions` 为两个最终条目接受一个身份标识;恢复操作以被恢复的 session id 注册 agent;subagent 创建铸造一个合并后的 id;`Session` 只保留一个身份归属位置。保留当前的事务、final-entry 碰撞检查、exact-entry 摘除、回滚与静默机制;仅移除唯一职责是在两个 id 之间做翻译的 map 和字段。 +对 agent 注册表条目和 `session.header.id` 使用同一个 id。`CreateAgentOptions` 为两个最终条目接收一个标识;恢复操作以被恢复的 session id 注册 agent;subagent 创建铸造一个合并后的 id;`Session` 只保留一个标识归属位置。保留当前的事务、final-entry 碰撞检查、exact-entry 摘除、回滚与静默机制;仅移除唯一职责是在两个 id 之间做转换的 map 和字段。 -配置驱动的路径必须先确定其恢复还是创建的策略。目前它使用一个稳定的 agent 标签加一个带 UUID 后缀的新 session id,以避免在下次运行时与已有的持久化日志碰撞。统一后它必须明确选择:恢复一个固定 id、铸造一个新的合并 id,或将该策略暴露出来;实现不得默默做出选择。 +配置驱动的路径必须先确定其恢复还是创建的策略。当前它使用一个稳定的 agent 标签加一个带 UUID 后缀的新 session id,以避免在下次运行时与已有的持久化日志碰撞。统一后,它必须明确选择:恢复一个固定 id、铸造一个新的合并 id,还是将该策略暴露出来;实现不得默默做出选择。 -`agent/created` 和 `agent/disposed` 不在本提案范围内。它们是发布生命周期事件而非身份别名;移除它们需要单独的生产方-消费方审计与决策。 +`agent/created` 和 `agent/disposed` 不在本提案范围内。它们是发布生命周期事件而非标识别名;移除它们需要单独的生产方-消费方审计与决策。 ## 曾考虑的替代方案 -**保留分离的路由身份与日志身份。** 一个稳定的配置 agent 标签搭配一个新的对话,是这种区分的真实用途。如果确实需要该显示或路由身份,则应否决本提案,转而显式强制 session id 唯一性,而不是将翻译隐藏在另一个 map 中。 +**保留分离的路由标识与日志标识。** 一个稳定的配置 agent 标签配合一个新的对话,是这种区分的真实用途。如果确实需要该显示或路由标识,请否决本提案,转而显式强制 session id 唯一性,而不是把转换隐藏在另一个 map 中。 ## 验收标准 -- agent 创建/恢复与 subagent 创建只携带一个身份标识;`Session` 将其存储在一个位置。 -- 创建事务保留 final-entry 碰撞、exact-entry 摘除、回滚与静默保证,且不依赖与身份相关的生命周期状态。 -- ACP、stdio、钩子、bash 所有权、持久化与血缘关系无需 agent/session id 翻译。 -- 配置驱动的恢复还是创建策略是显式的,并在持久化重启场景中得到覆盖。 +- agent 创建/恢复与 subagent 创建只携带一个标识;`Session` 将其存储在一个位置。 +- 创建事务在不依赖标识相关生命周期状态的前提下,保留 final-entry 碰撞、exact-entry 摘除、回滚与静默保证。 +- ACP、stdio、钩子、bash 所有权、持久化与血缘关系无需进行 agent/session id 转换。 +- 配置驱动的恢复还是创建策略是显式的,并在持久化重启场景下得到覆盖。 - `agent/created` 和 `agent/disposed` 仅在单独的生产方-消费方审计之后才变更。 - 类型检查、覆盖率、快照、doc-sync、module-graph 校验、构建与 hygiene 全部通过。 ## 风险 -统一后将无法再拥有一个跨多个会话日志的稳定 actor 身份,包括未来可能的交接或 fork(保留 actor 但更换会话)。重新引入该设计需要一个新的显式 actor 身份。统一还使一个持久化的、可能由客户端选择的 session id 成为注册表句柄,并改变每个创建/恢复调用点和 fixture(测试前置数据)。 +统一后将无法再拥有一个跨多个会话日志的稳定 actor 标识,包括未来可能出现的、在保留 actor 的同时切换会话的 handoff 或 fork 场景。重新引入该设计将需要一个新的显式 actor 标识。统一还使一个持久化的、可能由客户端选定的 session id 成为注册表句柄,并改变每个创建/恢复的调用点与 fixture(测试前置数据)。 -配置重启策略是阻塞性的设计决策:固定的合并 id 可能与其已有日志碰撞,而每次运行生成新 id 则放弃了稳定的配置标签。如果确实需要独立的 actor 身份或稳定标签/新会话的配对,则应否决本提案,保留分离的 id 并加上显式的唯一性守卫。 +配置重启策略是阻塞性的设计决策:固定的合并 id 可能与已有日志碰撞,而每次运行生成新 id 则放弃了稳定的配置标签。如果确实需要独立的 actor 标识或稳定标签/新会话的配对,请否决本提案,保留分离的 id 并加上显式的唯一性守卫。 diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml index 1d5522f5b3..4420b2dd27 100644 --- a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-prune-dead-core-spine-surface.md: c46fe464e8627dcfc39a1d3fbb38a9cbd84269cf -2026-07-04-prune-dead-core-spine-surface.zh.md: 86830904ef0d1262d4cc132fb8d4b6a50e033e1d +2026-07-04-prune-dead-core-spine-surface.zh.md: 67e89a580b086a08aed702d9e0b87bdb6e32c944 diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md index 86830904ef..67e89a580b 100644 --- a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:裁剪无用的公开接口与结果面 +# RFC:裁剪无用的公开与结果接口 Status: proposed @@ -6,57 +6,57 @@ Status: proposed ## 问题 -若干包根导出、结果字段和便利方法没有生产消费方。它们之所以存活,要么是因为测试通过公开入口导入内部实现,要么是因为某个类型预设了一个从未出现的调用者。每一项单独看都很小,但合在一起,它们扩大了 SDK 契约、生成的目录、文档和回归矩阵,却没有支撑任何已交付的路径。 +若干包根导出、结果字段和便利方法没有生产消费方。它们之所以存活,要么是因为测试通过公开入口导入了内部实现,要么是因为某个类型预期了一个从未出现的调用者。每一项单独看都很小,但合在一起,它们扩大了 SDK 契约、生成的 catalog、文档和回归矩阵,却没有支撑任何已交付的路径。 -生产语料库是 `packages/*/*/src`、示例源码/配置和运行时脚本。测试、package README 和 RFC 行文是发布的证据,但不是固定的调用者。`cordis_inspect` 使 `packages/cordis/tool-cordis/src/api-catalog.ts` 对模型可见,`cordis_mount` 可以通过受保护的真实服务代理调用注入的服务,因此被编目的服务方法和返回形状是真正的动态产品面。下表因此区分了「没有固定的仓库内调用者」与「不可达」:涉及编目词汇的行有意收缩模型编写的 mount 所能发现和调用的内容,而包根的实现辅助函数并不通过该服务门面可达。精确符号搜索得出以下清单: +生产语料库是 `packages/*/*/src`、示例源码/配置和运行时脚本。测试、包(package) README 和 RFC 行文是发布的证据,但不是固定调用者。`cordis_inspect` 使 `packages/cordis/tool-cordis/src/api-catalog.ts` 对模型可见,`cordis_mount` 可以通过受保护的真实服务代理调用注入的服务,因此 catalog 中的服务方法和返回形状是真正的动态产品接口。下表因此区分「没有固定的仓库调用者」与「不可达」:涉及 catalog 词汇的行有意收缩模型编写的 mount 能发现和调用的内容,而包根实现辅助函数并不通过该服务门面可达。精确符号搜索得出以下清单: -| 接口面 | 生产证据 | 简化方式 | +| 接口 | 生产证据 | 简化方式 | | --- | --- | --- | -| `SurfaceManager.invalidate()` | 仅其单元测试调用;seeding 在惰性创建的 manager 存在之前就已完成,且会话从不替换其日志引用。 | 删除该方法及其不可能触发的整体替换契约。 | -| `ToolExecutionResult.callId` | 每个钩子已经接收不可变的 `ToolExecution`;循环和 ACP(Agent Client Protocol)通过 call/session 事件关联。没有消费方读取这个重复的结果字段。 | 移除该字段、复制/不匹配守卫,以及证明该重复不会不一致的测试。 | -| `ReactLoopAgent` 根导出 | 包外的具名导入都是测试;生产代码面向 `Agent` 编程,通过 `ctx.agents` 创建/恢复。 | 返回/接口类型为 `Agent`,将具体循环类设为包内部;保留有意为之的同步纯配置 `AgentLoop.create()` 路径。 | -| `workflow-workerthread` 的 protocol/runtime/session 再导出与具名 `WorkerWorkflowEngine` | 所有包名消费方使用默认引擎;workflow RFC 已将 worker 协议格式定义为私有。 | 保留默认插件类/配置契约;移除重复的具名类导出,将协议模块设为源码私有。 | -| `code-runtime-worker` 的 protocol/bootstrap 再导出 | 包外的生产/e2e 消费方使用 `WorkerCodeRuntime` 和配置,而非 `BootstrapPort`、`PatchableStream` 或 worker 消息/启动类型。 | 保留运行时类/配置契约,将其协议格式/bootstrap 词汇设为源码私有。 | -| ACP 的 translation/presenter 根导出 | `agentOptions`、`streamSessionEventUpdate`、`todosToPlan`、`ToolPresenter`、`nullToolPresenter` 和 `TerminalRendering` 仅有同文件或 ACP 测试消费方;唯一的包外生产消费方挂载的是插件命名空间。 | 保留 `name`、`inject`、`Config`、`AcpConfig` 和 `apply`;将 translation/presentation 辅助函数设为源码私有,在包内测试。 | -| `providerWording` 和 `completedTurnPrefix` 根导出 | 各有一个同包生产调用者;仅 balanced-prefix 辅助函数有一个同包白盒测试。 | 设为源码私有,通过 provider 行为测试。 | -| `depthOf`、`SubagentDepthError`、`SENSITIVE_ENV_PATTERN`、`waitForExit` 和 `exitsWithin` 根导出 | 生产 subagent 后端消费的是进程内 runner 和子进程构造/释放辅助函数,而非这些强制/测试内部实现。 | 保留深度/环境/退出行为,但将辅助函数和 error/regex 设为源码私有;通过 spawn 和释放来测试。 | -| `PersistenceCoordinator.inits`、后端 `inits` 访问器、`seedCoversPrefix` 和 `assertSerializable` | 访问器为白盒测试而存在;`seedCoversPrefix` 没有包外生产导入者;`assertSerializable` 没有生产调用者,且与 coordinator append 边界的无损快照重复。 | 通过 `session/flush` 观察初始化,将 `seedCoversPrefix` 设为源码私有,删除 `assertSerializable`。保留两个后端、`SessionHeader` 和 SQLite 的版本契约。 | -| `LlmError.status` 与 replay status | 适配器/replay 填充它,但生产分支基于稳定的 error code/message,从不读取原始 status。 | 移除未读字段和 replay 管道,同时保留错误分类。 | +| `SurfaceManager.invalidate()` | 只有其单元测试调用它;seeding 在惰性创建的 manager 存在之前就已完成,且会话从不替换其日志引用。 | 删除它及其不可能触发的整体替换契约。 | +| `ToolExecutionResult.callId` | 每个钩子已经接收不可变的 `ToolExecution`;循环和 ACP(Agent Client Protocol)通过 call/session 事件关联。没有消费方读取这个重复的结果字段。 | 移除该字段、复制/不匹配守卫,以及证明该重复不可能不一致的测试。 | +| `ReactLoopAgent` 根导出 | 包外的命名导入都是测试;生产代码面向 `Agent` 编程,通过 `ctx.agents` 创建/恢复。 | 返回/接口类型为 `Agent`,将具体循环类改为包内部;保留有意设计的同步、仅配置的 `AgentLoop.create()` 路径。 | +| `workflow-workerthread` 的 protocol/runtime/session 再导出与命名的 `WorkerWorkflowEngine` | 每个包名消费方都使用默认引擎;workflow RFC 已将 worker 协议格式(wire format)定义为私有。 | 保留默认插件类/配置契约;移除重复的命名类导出,将协议模块保持为源码私有。 | +| `code-runtime-worker` 的 protocol/bootstrap 再导出 | 包外的生产/e2e 消费方使用 `WorkerCodeRuntime` 和配置,而非 `BootstrapPort`、`PatchableStream` 或 worker 消息/启动类型。 | 保留运行时类/配置契约,将其协议格式/bootstrap 词汇改为源码私有。 | +| ACP 的 translation/presenter 根导出 | `agentOptions`、`streamSessionEventUpdate`、`todosToPlan`、`ToolPresenter`、`nullToolPresenter` 和 `TerminalRendering` 只有同文件或 ACP 测试消费方;唯一的包外生产消费方挂载的是插件命名空间。 | 保留 `name`、`inject`、`Config`、`AcpConfig` 和 `apply`;将 translation/presentation 辅助函数改为源码私有,在包内测试。 | +| `providerWording` 与 `completedTurnPrefix` 根导出 | 各有一个同包生产调用者;只有 balanced-prefix 辅助函数有一个同包白盒测试。 | 改为源码私有,测试 provider 行为。 | +| `depthOf`、`SubagentDepthError`、`SENSITIVE_ENV_PATTERN`、`waitForExit` 与 `exitsWithin` 根导出 | 生产 subagent 后端消费的是进程内 runner 和子进程构造/dispose(资源释放)辅助函数,而非这些强制/测试内部实现。 | 保留深度/环境/退出行为,但将辅助函数和 error/regex 改为源码私有;通过 spawn 和 dispose 测试。 | +| `PersistenceCoordinator.inits`、后端 `inits` 访问器、`seedCoversPrefix` 与 `assertSerializable` | 访问器为白盒测试而存在;`seedCoversPrefix` 没有包外生产导入者;`assertSerializable` 没有生产调用者,且与 coordinator append 边界的无损快照重复。 | 通过 `session/flush` 观察初始化,将 `seedCoversPrefix` 改为源码私有,删除 `assertSerializable`。保留两个后端、`SessionHeader` 和 SQLite 的版本契约。 | +| `LlmError.status` 与 replay status | 适配器/replay 填充它,但生产分支基于稳定的 error code/message 判断,从不读取原始 status。 | 移除未读字段和 replay 管道,保留错误分类。 | | `BlockAssembler.push()` 返回值 | 两个生产调用者都忽略返回的已完成块。 | 返回 `void`;保留有意公开的 `blocks()`/`message()` 契约。 | -| `compactRegion` 的独立 `session` 参数 | 固定调用者传入的对象与 `agent.session` 已经是同一个;模型可见的 mount API 也能调用该方法,但接受两个身份允许挂载的插件提供不一致的配对。 | 保留手动区域 seam,同时有意将其收窄为以 `agent.session` 为唯一真源。 | -| `CompactionResult.startSeq`、`summarySeq`、`endSeq` 和 `summary` | 生产消费方只读取 shadowed range/seq/token 统计;持久日志拥有摘要和事件标识。 | 移除四个结果回显,同时保留两个共享的 transcript(文本记录)渲染器。 | -| `BasicCompactService` 的 estimation/summarization 可见性 | 没有包外生产调用者调用这五个方法;已实现的 RFC 仅将 `estimateContentTokens()` 和 `summarize()` 列为子类钩子。 | 将这两个方法设为 `protected`,将三个仅用于编排的估算器设为 private。 | -| `CodeLogEntry.source`/`level` 和 `RunCodeMeta.dispatches` | 所有生产消费方将日志映射为文本;没有 presenter/模型路径读取其他字段或持久化的 dispatch 计数。 | 将 code-runtime 日志改为字符串(或纯文本条目),移除 result-meta dispatch 管道;保留用于生成确定性 dispatch id 的本地计数器。 | -| `ToolNotFoundError.toolName`、`SystemPrompt.config` 和 `BashTask.command` | 每个存储的公开值都没有生产读取者。 | 移除未读字段,同时保留错误消息、已解析的配置行为和任务生命周期。 | -| 后端包根实现辅助函数 | 下方精确清单仅通过相对同包导入调用。生产命名空间导入挂载的是保留的插件契约,不读取这些属性;具名根消费方是测试。 | 保留每个适配器/提供方/服务及其配置/错误契约;停止在包根导出所列辅助函数/常量。 | -| 消费方包根实现辅助函数 | 下方精确清单仅有同包生产调用者。生产命名空间导入挂载插件契约,不读取辅助属性;具名根消费方是测试。 | 保留插件契约和稳定错误码;将测试移至包内模块或公开行为,停止在包根导出所列辅助函数。 | +| `compactRegion` 的独立 `session` 参数 | 固定调用者传入的对象与 `agent.session` 上已有的是同一个;模型可见的 mount API 也能调用该方法,但接受两个身份允许挂载的插件提供不一致的配对。 | 保留手动 region seam,同时有意将其收窄为以 `agent.session` 为唯一真源。 | +| `CompactionResult.startSeq`、`summarySeq`、`endSeq` 与 `summary` | 生产消费方只读取 shadowed range/seq/token 统计;持久日志拥有 summary 和事件标识。 | 移除四个结果回显,保留两个共享的 transcript(文本记录)渲染器。 | +| `BasicCompactService` 的 estimation/summarization 可见性 | 没有包外生产调用者调用这五个方法;已实现的 RFC 只将 `estimateContentTokens()` 和 `summarize()` 命名为子类钩子。 | 将这两个方法改为 `protected`,其余三个编排专用的估算器改为 private。 | +| `CodeLogEntry.source`/`level` 与 `RunCodeMeta.dispatches` | 每个生产消费方都将日志映射为文本;没有 presenter/模型路径读取其他字段或持久化的 dispatch 计数。 | 将 code-runtime 日志改为字符串(或纯文本条目),移除 result-meta 的 dispatch 管道;保留用于生成确定性 dispatch id 的本地计数器。 | +| `ToolNotFoundError.toolName`、`SystemPrompt.config` 与 `BashTask.command` | 每个存储的公开值都没有生产读取者。 | 移除未读字段,保留错误消息、已解析的配置行为和任务生命周期。 | +| 后端包根实现辅助函数 | 下方精确清单仅通过相对路径的同包导入调用。生产命名空间导入挂载的是保留的插件契约,不读取这些属性;命名根消费方都是测试。 | 保留每个适配器/provider/服务及其配置/错误契约;停止在包根导出所列辅助函数/常量。 | +| 消费方包根实现辅助函数 | 下方精确清单只有同包生产调用者。生产命名空间导入挂载的是插件契约,不读取辅助属性;命名根消费方都是测试。 | 保留插件契约和稳定的错误码;将测试迁移到包内模块或公开行为,停止在包根导出所列辅助函数。 | ### 分组辅助导出清单 -- `dsh-llm-deepseek`:`httpErrorCode`、`serializeMessages`、`serializeRequest`、`DONE`、`parseSse`、`mapFinishReason`、`mapUsage` 和 `translate`;`dsh-llm-pi-ai`:`buildModel`、`mapStopReason`、`mapUsage`、`toPiContext` 和 `toStreamChunks`。 -- `dsh-bash-local`:`DEFAULT_GRACE_MS`、`ENV_OVERRIDES`、`killGroup`、`OutputCollector` 和 `runBash`;`dsh-bash-sandbox`:`shellQuote`、`classifyDenial` 和 `classifyRunnerFailure`;`dsh-sandbox-local`:`bwrapProfileArgs`、`landlockProfileArgs` 和 `seatbeltProfileArgs`。公开的可变测试注入字段及其类型不在本提案范围内。 -- `dsh-fs-local`:`applyLiteralEdit`、`listDirectory`、`probe`、`readForEdit`、`readTextForDiff`、`readWholeText`、`resolveLocalTarget`、`restoreLineEndings`、`streamWholeText` 和 `writeFileAtomic`。 -- `dsh-web-fetch-local`:`classifyContentType`、`decoderForCharset`、`isSameOrigin`、`parseCharset` 和 `validateFetchUrl`;`dsh-web-search-exa`:`mapExaResponse` 和 `mapExaResult`;`dsh-web-search-deepseek`:`citationSnippets` 和 `mapAnthropicResponse`;`dsh-web-search-perplexity`:`mapPerplexityResponse` 和 `mapPerplexityResult`。 -- `dsh-tool-fs`:`READ_LIMIT`、`STREAM_MIN_SIZE`、`READ_MAX_BYTES`、`READ_MAX_LINE_LENGTH`、`DIFF_CONTEXT`、`applyReadTool`、`parseReadArgs`、`applyWriteTool`、`formatWriteOutput`、`parseWriteArgs`、`applyEditTool`、`formatEditOutput`、`parseEditArgs`、`buildWindow`、`formatReadOutput`、`computeHunkDiffs` 和 `diffsFromMeta`。 -- `dsh-tool-web`:`WEB_SEARCH_MAX_RESULTS`、`applyWebSearchTool`、`formatSearchOutput`、`parseSearchArgs`、`presentSearchCall`、`applyWebFetchTool`、`formatFetchOutput`、`parseFetchArgs`、`presentFetchCall`、`renderBody` 和 `htmlToMarkdown`;`dsh-timeout-policy`:`toolTimeoutResult`;`dsh-compact-basic`:`resolveConfig`;`dsh-tool-bash`:`renderResult`。 +- `dsh-llm-deepseek`:`httpErrorCode`、`serializeMessages`、`serializeRequest`、`DONE`、`parseSse`、`mapFinishReason`、`mapUsage` 与 `translate`;`dsh-llm-pi-ai`:`buildModel`、`mapStopReason`、`mapUsage`、`toPiContext` 与 `toStreamChunks`。 +- `dsh-bash-local`:`DEFAULT_GRACE_MS`、`ENV_OVERRIDES`、`killGroup`、`OutputCollector` 与 `runBash`;`dsh-bash-sandbox`:`shellQuote`、`classifyDenial` 与 `classifyRunnerFailure`;`dsh-sandbox-local`:`bwrapProfileArgs`、`landlockProfileArgs` 与 `seatbeltProfileArgs`。公开的可变测试注入字段及其类型不在本提案范围内。 +- `dsh-fs-local`:`applyLiteralEdit`、`listDirectory`、`probe`、`readForEdit`、`readTextForDiff`、`readWholeText`、`resolveLocalTarget`、`restoreLineEndings`、`streamWholeText` 与 `writeFileAtomic`。 +- `dsh-web-fetch-local`:`classifyContentType`、`decoderForCharset`、`isSameOrigin`、`parseCharset` 与 `validateFetchUrl`;`dsh-web-search-exa`:`mapExaResponse` 与 `mapExaResult`;`dsh-web-search-deepseek`:`citationSnippets` 与 `mapAnthropicResponse`;`dsh-web-search-perplexity`:`mapPerplexityResponse` 与 `mapPerplexityResult`。 +- `dsh-tool-fs`:`READ_LIMIT`、`STREAM_MIN_SIZE`、`READ_MAX_BYTES`、`READ_MAX_LINE_LENGTH`、`DIFF_CONTEXT`、`applyReadTool`、`parseReadArgs`、`applyWriteTool`、`formatWriteOutput`、`parseWriteArgs`、`applyEditTool`、`formatEditOutput`、`parseEditArgs`、`buildWindow`、`formatReadOutput`、`computeHunkDiffs` 与 `diffsFromMeta`。 +- `dsh-tool-web`:`WEB_SEARCH_MAX_RESULTS`、`applyWebSearchTool`、`formatSearchOutput`、`parseSearchArgs`、`presentSearchCall`、`applyWebFetchTool`、`formatFetchOutput`、`parseFetchArgs`、`presentFetchCall`、`renderBody` 与 `htmlToMarkdown`;`dsh-timeout-policy`:`toolTimeoutResult`;`dsh-compact-basic`:`resolveConfig`;`dsh-tool-bash`:`renderResult`。 ## 提案 -以一次有界的、协调的公开接口面清理,移除或降级上述每一行。更新 package README、JSDoc、生成的 API/事件目录、type-equiv 记录、必要时的 exports map 以及测试,使测试通过所属的公开 seam 来验证行为,而非保留仅为测试而存在的入口点。不折叠任何能力 seam、LLM(大语言模型)适配器、持久化后端或生命周期静默契约。 +以一次有界的、协调的公开接口清理,移除或降级上述每一行。同步更新包 README、JSDoc、生成的 API/事件 catalog、type-equiv 记录、必要的 exports map 以及测试,使测试通过所属的公开 seam 验证行为,而非保留仅为测试而存在的入口。不折叠任何能力 seam、LLM(大语言模型)适配器、持久化后端或生命周期静默契约。 ## 曾考虑的替代方案 -**保留测试便利函数和自包含结果字段为公开。** 公开辅助函数可以让白盒测试更方便,自包含的结果字段看起来更符合人体工学,未来的嵌入者可能需要具体循环类或枚举方法。这些好处是假设性的;今天它们让每一处实现和文档都要解释没有已交付调用者能观察到的状态。真正的消费方可以引入它所需的最小契约,其所有权和失败语义已知。 +**保留测试便利函数和自包含的结果字段为公开。** 公开辅助函数可以让白盒测试更方便,自包含的结果字段看起来更符合人体工学,未来的嵌入者可能需要具体循环类或枚举方法。这些好处是假设性的;当前它们让每处实现和文档都要解释没有已交付调用者能观察到的状态。真正的消费方可以引入它所需的最小契约,其所有权和失败语义明确。 -**为模型编写的 mount 保留所有编目成员。** 自引用工具集是一条真实的通用消费路径,而非生成文档的噪音。然而,它的价值来自准确、可组合的服务面,而非无限期保留重复字段或不一致的参数对;上述每一项编目收缩都移除了在同一次执行、agent(智能体)或结果上其他位置已可获得的事实,并在同一个变更中更新 API 参考。 +**保留所有 catalog 成员以供模型编写的 mount 使用。** 自引用工具集是一条真实的通用消费路径,而非生成文档的噪音。然而,它的价值来自准确、可组合的服务接口,而非无限期保留重复字段或不一致的参数对;上述每一项 catalog 收缩都移除了在同一 execution、agent 或 result 上其他位置已可获得的事实,并在同一变更中更新 API 参考。 ## 验收标准 -- 精确符号搜索显示被移除的接口面不出现在本 RFC 和任何已实现 RFC 修正案之外。 -- 本 RFC 列出的每一项接口面均已按指定方式移除或降级;清单之外有意保留的扩展/测试契约不受影响。 -- 工具执行、压缩(compaction)、两个 LLM 适配器、两个持久化后端、工作流隔离以及 agent 创建/恢复保持其已交付行为。 -- 类型检查、覆盖率、快照、doc-sync(文档同步门禁)、module-graph 校验、构建和 hygiene 全部通过。 +- 精确符号搜索显示:在本 RFC 及任何已实现 RFC 修正之外,没有被移除的接口。 +- 本 RFC 列出的每个接口均按指定方式缺失或降级;清单之外有意保留的扩展/测试契约不变。 +- 工具执行、上下文压缩(context compaction)、两个 LLM 适配器、两个持久化后端、workflow 隔离以及 agent 创建/恢复保持其已交付行为。 +- 类型检查、覆盖率、快照、doc-sync、module-graph 校验、构建和 hygiene 通过。 ## 风险 -大多数移除在编译时可见但运行时无影响。压缩参数清理有意禁止 session/context 不匹配,同时保留手动区域 seam。外部预发布嵌入者和现有模型编写的 mount 可能导入更少的辅助函数、传入更少的参数或接收更窄的结果形状;这是有意的产品接口面收缩,而非仅仅是生成目录的清理。仓库尚未发布,因此承载不受支持的接口面才是更大的基础成本。 +大多数移除在编译时可见但对运行时无影响。上下文压缩参数清理有意禁止 session/context 不匹配,同时保留手动 region seam。外部预发布嵌入者和现有模型编写的 mount 可能导入更少的辅助函数、传递更少的参数或接收更窄的结果形状;这是有意的产品接口收缩,而非仅仅是生成 catalog 的清理。仓库尚未发布,因此承载不受支持的接口才是更大的基础成本。 diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml index f7a882d65c..2e91f9e9c2 100644 --- a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-12-simplify-session-log-representation.md: 52720231d6e4cbe0cbb412332cd016ba63f83569 -2026-07-12-simplify-session-log-representation.zh.md: 468f9a565177089c8d49c06e8d490ab56980054a +2026-07-12-simplify-session-log-representation.zh.md: 1286a7d3c571fac66310a613c548920c3f25812d diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md index 468f9a5651..1286a7d3c5 100644 --- a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md @@ -6,33 +6,33 @@ Status: proposed ## 问题 -会话日志维护着两种表示,其机制开销超出了消费方的实际需求:伪链表 surface 与自定义请求头增量编码。 +会话日志维护着两种表示,其机制复杂度超出了消费方的实际需求:一个伪链表 surface 和自定义的请求头增量。 -`SurfaceManager` 将同一顺序存储在数组、seq 映射和可变的 `prev`/`next` 链接三处。生产代码从不读取 `prev`;压缩(compaction)唯一一次读取 `next` 是取数组位置的后继。替换操作已经使用 `indexOf`,因此链接并未使其主要操作达到常数时间。一个 seq 数组加线性替换查找具有相同的渐近替换开销,且只有一种表示需要校验。 +`SurfaceManager` 用一个数组、一个 seq 映射和可变的 `prev`/`next` 链接存储相同的顺序。生产代码从不读取 `prev`;压缩(compaction)唯一的 `next` 读取是取数组位置的后继。替换操作已经使用 `indexOf`,因此链接并未让其主要操作达到常数时间。一个 seq 数组加线性替换查找具有相同的渐近替换开销,且只有一种表示需要验证。 -请求头子系统实现了自定义的 system/tool 增量编解码器与传输决策层,尽管其契约声明增量只是编码优化而非可重建性要求。在每个 agent loop 实例边界保留 initial/resume 完整快照,然后在该实例的组装头发生变化时写入一条规范的完整 `request/header`,即可保留回放能力,同时删除 `SystemDelta`、`ToolsDelta`、往返 fallback 以及持久化的 `request/header-delta` 变体。编解码器专用词汇随编解码器一起消失,并非因为其各分支本身无效。 +请求头子系统实现了一套自定义的 system/tool 增量编解码器和传输决策层,尽管其契约声明增量只是编码优化,而非可重建性要求。在每个 agent loop(智能体循环)实例边界保留初始/恢复的完整快照,然后在该实例的组装头发生变化时写入一条规范的完整 `request/header`,即可保留回放能力,同时删除 `SystemDelta`、`ToolsDelta`、往返回退逻辑以及持久化的 `request/header-delta` 变体。编解码器专属的词汇随编解码器一起消失,并非因为其各分支本身无效。 -本提案有意保留 append 与 replacement 的 `sourceEventSeqs`、崩溃恢复溯源,以及所有 `SessionStartSource` 变体:已实施的 RFC 赋予了这些字段审计/拦截角色,零当前读者不足以推翻这一点。 +本提案有意保留追加和替换的 `sourceEventSeqs`、崩溃恢复来源信息以及所有 `SessionStartSource` 变体:已实施的 RFC 赋予这些字段审计/拦截角色,零当前读者这一事实不足以推翻它们。 ## 提案 -将 `SurfaceManager.nodes` 改为事件序列号的 `readonly number[]`,移除公开的 `SurfaceNode` 形状。保留内部的 replace-generation 信号;更新工具配对平衡与压缩调用方,使其通过数组值/索引获取前驱、后继与替换范围,移除节点链接与 seq-to-node 映射。将锚点后的请求头增量替换为规范的完整变更头快照,移除增量编解码器/事件/测试;initial 与 resume 锚点即使折叠后的头未变也仍为完整快照。 +将 `SurfaceManager.nodes` 改为事件序列号的 `readonly number[]`,移除公开的 `SurfaceNode` 形状。保留内部的替换代信号;更新 tool 配对平衡和压缩调用方,使其通过数组值/索引获取前驱、后继和替换范围,移除节点链接和 seq-to-node 映射。用规范的完整变更头快照替代锚点后的头增量,移除增量编解码器/事件/测试;初始和恢复锚点即使折叠后的头未变也仍为完整快照。 -修订会话 surface 与可重建请求的 RFC 中描述已移除编码的部分。更新事件类型/不变式、请求日志/回放、持久化 fixture(测试前置数据)、生成的 catalog、包文档与快照。将编解码器专用的 `fallback` 原因替换为显式的 `change` 原因(用于锚点后的完整快照),以区别于保留的 `initial` 与 `resume` 锚点。 +修订 session-surface 和 reconstructable-request RFC 中描述已移除编码的部分。更新事件类型/不变式、请求日志/回放、持久化 fixture(测试前置数据)、生成的 catalog、包文档和快照。将编解码器专属的 `fallback` 原因替换为锚点后完整快照的显式 `change` 原因,使其与保留的 `initial` 和 `resume` 锚点区分开来。 -`SESSION_FORMAT_VERSION` 有意保持为 `0`,因此包含 `request/header-delta` 的旧 v0 日志在增量折叠被删除后,若不做处理将通过版本检查并静默丢失头变更。seed/load 校验必须在格式边界处拒绝该遗留事件并快速失败;不添加兼容折叠或迁移。 +`SESSION_FORMAT_VERSION` 有意保持在 `0`,因此一份包含 `request/header-delta` 的旧 v0 日志在增量折叠被删除后,本会通过版本检查并静默丢失头变更。seed/load 校验必须在格式边界处拒绝该遗留事件并显式报错;不添加兼容性折叠或迁移。 ## 曾考虑的替代方案 -**保留链表节点与紧凑增量以备未来规模。** 链接可能有助于未来的游标 API,增量在大型工具 schema 仅有少量变化时能减小日志体积。但没有已发布的游标使用这些链接,而完整快照以磁盘空间换取显著更简单的正确性。如果头部体积确实成为问题,可以基于真实 trace 设计压缩方案或经过度量的规范增量方案。 +**保留链表节点和紧凑增量以备未来扩展。** 链接可能有助于未来的游标 API,增量在大型工具 schema 仅有少量变化时可以缩减日志。但没有已发布的游标使用这些链接,而完整快照以磁盘空间换取了显著更简单的正确性。如果头部体积确实成为问题,可以基于真实 trace 设计压缩方案或经过度量的规范增量方案。 ## 验收标准 -- `SurfaceManager.nodes` 是一个有序 seq 数组,没有 `SurfaceNode`、链接字段或 seq-to-node 映射;增量追加处理与内部 replace-generation 信号保留。 +- `SurfaceManager.nodes` 是一个有序 seq 数组,没有 `SurfaceNode`、链接字段或 seq-to-node 映射;增量追加处理和内部替换代信号保留。 - 回放完整变更头快照能重建出完全相同的请求;不再存在任何 header-delta 事件/类型/编解码器。 -- 包含遗留 `request/header-delta` 的 v0 seed 或持久化日志在回放前被拒绝,JSONL 与 SQLite 加载路径均有覆盖。 -- 新形状的 v0 JSONL/SQLite 回放、溯源、崩溃恢复、压缩、快照、不变式、类型检查、覆盖率、doc-sync、构建与 hygiene 全部通过。 +- 包含遗留 `request/header-delta` 的 v0 seed 或持久化日志在回放前被拒绝,JSONL 和 SQLite 加载路径均有覆盖率。 +- 新形状的 v0 JSONL/SQLite 回放、来源信息、崩溃恢复、压缩、快照、不变式、类型检查、覆盖率、doc-sync 和 hygiene 全部通过。 ## 风险 -完整头会增加日志体积,线性替换查找在非常大的 surface 上可能更慢。替换操作目前已经是线性的,因为实现调用了 `indexOf`;只有在真实 trace 表明更简单的数组成为瓶颈时才应添加基准测试。由于格式版本保持为 `0`,如果遗漏了对遗留事件的显式拒绝,后果将是静默数据损坏而非类型错误;因此快速失败的加载测试是本提案的组成部分,而非可选的清理工作。 +完整头会增加日志体积,线性替换查找在非常大的 surface 上可能更慢。替换操作已经是线性的,因为实现调用了 `indexOf`;只有当真实 trace 表明更简单的数组成为瓶颈时才应添加基准测试。由于格式版本保持为 `0`,如果遗漏了对遗留事件的显式拒绝,后果将是静默数据损坏而非类型错误;因此显式报错的加载测试是本提案的组成部分,而非可选的清理工作。 diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml index 3e3afa30d0..13dc3e72b9 100644 --- a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-deterministic-and-stress-testing.md: e4ed7043d1880b55dd7d77b3e09a81dd58739a70 -2026-06-11-deterministic-and-stress-testing.zh.md: d933c1dda329b95573b7a5a3fbe3a61ef94390cb +2026-06-11-deterministic-and-stress-testing.zh.md: 4e4ee9d28025a43349b702e399096535539a91d2 diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md index d933c1dda3..4e4ee9d280 100644 --- a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md @@ -6,28 +6,28 @@ Status: proposed ## 问题 -若干 agent loop(智能体循环)测试通过 `setTimeout(30)` 睡眠来同步——这是一笔不稳定性债务,浪费 agent 重试周期,还可能掩盖排序 bug。另一方面,我们的核心架构承诺(任何会话日志回放后都能得到完全相同的派生历史)目前只在两个测试中断言,但在*所有地方*断言的成本很低。此外,inbox 唤醒竞态只被手动验证过一次,没有任何东西持续地重新验证它。 +若干 agent loop(智能体循环)测试通过 `setTimeout(30)` 睡眠来同步——这是一笔不稳定性债务,浪费 agent 的重试周期,还可能掩盖时序 bug。另外,我们的核心架构承诺(任何会话日志回放后都能得到相同的派生历史)目前只在两个测试中断言,但在**所有**测试中断言的成本极低。此外,inbox 唤醒竞态只被手动验证过一次,没有任何机制持续复验。 ## 提案 三项措施: -1. **测试中禁止挂钟睡眠。** 将 `setTimeout(N)` 等待替换为事件驱动等待(现有的 `waitForIdle` 模式,扩展为 `waitForStatus`、`waitForEvent(n)`),或在需要测试时间本身时使用 vitest fake timers。通过 lint 规则强制:禁止在 `packages/*/tests` 中使用 `setTimeout`,白名单辅助模块除外。 -2. **通用回放 fixture(测试前置数据)。** 一个共享的测试辅助函数包装 agent loop harness,使得每个测试结束后,agent 的会话日志被回放到一个全新的 Session 中,并自动断言 `deriveMessages()` 相等。这样该不变式在每次 CI 运行中会被检查数百次(覆盖套件产生的所有场景),而非仅两次。 -3. **夜间竞态压力测试。** 一个 CI job 以 `vitest --repeat=200`(加 `--shuffle`)运行 agent-loop 和 inbox 套件,以暴露调度依赖的失败;发现的任何不稳定测试都作为 bug 修复,绝不靠重试掩盖。 +1. **测试中禁止挂钟睡眠。** 将 `setTimeout(N)` 等待替换为事件驱动等待(既有的 `waitForIdle` 模式,扩展为 `waitForStatus`、`waitForEvent(n)`),或在需要测试时间本身时使用 vitest 的 fake timer。通过 lint 规则强制执行:禁止在 `packages/*/tests` 中使用 `setTimeout`,白名单辅助模块除外。 +2. **通用回放 fixture(测试前置数据)。** 一个共享测试辅助函数包装 agent loop harness,使每个测试结束后,agent 的会话日志被回放到一个全新的 Session 中,并自动断言 `deriveMessages()` 相等。这样该不变式在每次 CI 运行中会被套件产生的所有场景检查数百次,而非仅两次。 +3. **夜间竞态压力测试。** 一个 CI job 以 `vitest --repeat=200`(加 `--shuffle`)运行 agent-loop 和 inbox 套件,以暴露调度依赖的失败;发现的任何不稳定测试都视为 bug 修复,绝不靠重试掩盖。 ## 计划 -措施 1 和 2 一起落地(它们改动相同的辅助模块);在套件消除所有睡眠之后再添加夜间 job,使重复运行足够快。 +措施 1 和 2 一起落地(它们改动相同的辅助模块);在套件消除所有睡眠后再添加夜间 job,以确保重复运行速度快。 ## 验收标准 -- `packages/*/tests` 中不再有 `setTimeout`(白名单辅助模块除外),由 lint 规则强制。 -- 共享 harness 对每个测试的会话日志进行回放,将其注入全新的 `Session` 并自动断言 `deriveMessages()` 相等,覆盖整个套件。 -- 夜间 job 以 `--repeat` 和 `--shuffle` 运行 agent-loop 和 inbox 套件;发现的不稳定测试作为 bug 分诊处理,绝不靠重试掩盖。 +- `packages/*/tests` 中不再有 `setTimeout`(白名单辅助模块除外),由 lint 规则强制执行。 +- 共享 harness 将每个测试的会话日志回放到全新的 `Session` 中,并自动断言 `deriveMessages()` 相等,覆盖整个套件。 +- 夜间 job 以 `--repeat` 和 `--shuffle` 运行 agent-loop 和 inbox 套件;发现的不稳定测试作为 bug 分诊,绝不靠重试掩盖。 ## 风险 -Fake timers 与 agent loop 中的 Promise 调度存在微妙交互——优先使用事件驱动等待;仅在测试 timer 服务行为本身时才使用 fake timers。 +Fake timer 与 agent loop 中的 Promise 调度存在微妙交互——优先使用事件驱动等待;仅在测试 timer 服务行为本身时才使用 fake timer。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml index 3f6c6157fa..3bf5967b45 100644 --- a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-mutation-testing.md: 344263d1c91a5e6c83320f367bf76ed6f7ef5a49 -2026-06-11-mutation-testing.zh.md: aa89b3335a143b6f34858bdc2f3344a6a7d758d9 +2026-06-11-mutation-testing.zh.md: 28bb7253c12827dbcddd141481f26f60b3a72b7a diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md index aa89b3335a..28bb7253c1 100644 --- a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md @@ -1,4 +1,4 @@ -# RFC:变异测试作为覆盖率的制衡 +# RFC:变异测试作为覆盖率的制衡手段 [English](2026-06-11-mutation-testing.md) | 中文 @@ -6,31 +6,31 @@ Status: proposed ## 问题 -逐文件 100% 覆盖率门禁(见[质量门禁决策](../../implemented/process/2026-06-11-quality-gates.md))证明的是每一行都在测试中*被执行*了,而非任何断言会在该行出错时有所察觉。在 agent 编写测试的场景下,覆盖率压力可能催生「执行但无断言」的测试。变异测试衡量的正是覆盖率无法衡量的:测试套件是否能*杀死*被刻意注入的缺陷。 +逐文件 100% 覆盖率门禁([质量门禁决策](../../implemented/process/2026-06-11-quality-gates.md))证明每一行代码在测试中都被*执行*了,但不能证明如果该行出错,任何断言会注意到。在 agent(智能体)编写测试的场景下,覆盖率压力可能产出「执行但不断言」的测试。变异测试衡量的正是覆盖率无法衡量的:测试套件是否能*杀死*被刻意注入的缺陷。 ## 提案 在 `packages/*/src` 上运行 Stryker(`@stryker-mutator/vitest-runner`): -- **PR 粒度的增量运行**(仅变更文件),作为 CI job:调优后足够快,可以作为合并门禁。 -- **每夜全量运行**,跟踪变异分数;先记录基线,再将阈值设为观测到的基线值并只升不降(与覆盖率策略一致:阈值只收紧)。 -- 存活的变异体是待办工作项:agent 选取一个存活体、编写杀死它的测试、循环往复——一个形态良好的自主循环。 -- 等价变异体(可证明不改变行为的)加带理由的排除注解,与 `/* v8 ignore */` 策略对称。 +- **PR 范围的增量运行**(仅变更文件),作为一个 CI job。调优后速度足以作为合并门禁。 +- **每夜全量运行**,跟踪变异分数;先记录基线,再将阈值设为观测到的基线并只升不降(与覆盖率策略一致:阈值只收紧)。 +- 存活的变异体是待办项:agent 选取一个存活体、编写杀死它的测试、循环往复——一个形态良好的自主循环。 +- 等价变异体(可证明不改变行为的)加注释排除并附理由,与 `/* v8 ignore */` 策略一致。 ## 计划 1. 添加 Stryker 配置,范围限定在一个包(llm:最小、最具算法性),测量运行时间。 2. 扩展到所有包;在配置中记录基线分数。 -3. 接入每夜 job;当运行时间可接受后,添加 PR 粒度的增量 job。 +3. 接入每夜 job;运行时间可接受后再添加 PR 范围的增量 job。 ## 验收标准 -- Stryker 配置在 `packages/*/src` 上以 vitest runner 运行;每夜 job 记录变异分数,且当分数低于记录的基线时,运行失败(阈值只升不降)。 -- PR 粒度的增量运行在运行时间可接受后作为合并门禁;或者明确保持仅每夜运行,并将该结论记录于此。 -- 等价变异体带有附理由的排除注解,与 `/* v8 ignore */` 策略对称。 +- Stryker 配置在 `packages/*/src` 上以 vitest runner 运行;每夜 job 记录变异分数,当分数低于记录的基线时,通过只升不降的阈值使运行失败。 +- PR 范围的增量运行在运行时间可接受后作为合并门禁;或者明确保持仅每夜运行,并将该结论记录于此。 +- 等价变异体带有注释排除及理由,与 `/* v8 ignore */` 策略一致。 ## 风险 -运行时间:变异测试开销大;逐文件 100% 覆盖率有所帮助(每个变异体至少会被执行到)。如果 PR 粒度的运行始终太慢,则保持仅每夜运行,依赖分数只升不降的机制。 +运行时间:变异测试开销大;逐文件 100% 覆盖率有所帮助(每个变异体至少会被执行到)。如果 PR 范围的运行始终过慢,则保持仅每夜运行,依赖分数只升不降的机制。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml index 3c2a50a714..f7c21ad005 100644 --- a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-11-immutable-public-surfaces.md: 68472d9817f0de22777314927f05f90949903723 -2026-06-11-immutable-public-surfaces.zh.md: e067b48d9a936133abdf149fbb9ff626c9411851 +2026-06-11-immutable-public-surfaces.zh.md: 7dc42ef9ff07682c1bbac1ca61caba49596cb7bc diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md index e067b48d9a..7dc42ef9ff 100644 --- a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md @@ -2,28 +2,28 @@ [English](2026-06-11-immutable-public-surfaces.md) | 中文 -Status: rejected — the pervasive `DeepReadonly<T>` type flip is replaced by source-owned runtime immutability in `Session` plus relational development assertions. See [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md). +Status: rejected — 全面使用 `DeepReadonly<T>` 类型翻转的方案已被替换为 `Session` 中由源拥有的运行时不可变性加关系型开发断言。见[源拥有的会话不可变性与开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)。 ## 问题 -被否决的提案针对的是一个所有权漏洞:仅靠 `readonly SessionEvent[]` 类型无法封堵该漏洞,因为数组元素在运行时仍然可变,一次类型断言或纯 JavaScript 就能改写嵌套的历史记录。最终实现的设计在 `Session` 中通过物化并深度冻结每个已接受的事件、返回冻结的数组快照来封堵该漏洞。进行中的 prompt waterfall(瀑布式事件)被有意保留为可变,因此不可变性是一条所有权边界,而非一条覆盖全局的类型规则。 +被否决的提案针对的是一个所有权漏洞:仅靠 `readonly SessionEvent[]` 类型无法封堵该漏洞,因为其元素在运行时仍然可变,类型强制转换或纯 JavaScript 代码可以改写嵌套的历史记录。已实现的设计在 `Session` 中封堵了这一漏洞:对每个被接受的事件进行物化并深度冻结,返回冻结的数组快照。进行中的 prompt waterfall(瀑布式事件)有意保持可变换,因此不可变性是一条所有权边界,而非一条全局类型规则。 ## 提案 -> **实际实现方式不同——见 Status 行与 [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)。** 下文的 `DeepReadonly<T>` 设计已被否决:它仅在编译期生效、对消费方噪音大、且可被 cast 绕过。`Session` 改为在每次组合中对已接受的事件和公开日志快照进行快照与深度冻结;`deriveMessages()` 返回分离的冻结投影;开发插件检查跨记录与跨 seam 的关系约束。 +> **实际采用了不同的实现方式——见 Status 行与[源拥有的会话不可变性与开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)。** 下文的 `DeepReadonly<T>` 设计已被否决:它仅在编译期生效、对消费方噪音大、且可被强制转换绕过。`Session` 改为在每次组合中对已接受的事件和公开日志快照进行快照与深度冻结;`deriveMessages()` 返回分离的冻结投影;开发插件检查跨记录与跨 seam 的关系。 -在类型层面将不可变性施加于「变异即腐败」的位置: +在类型层面为「突变即损坏」的场景引入不可变性: -- `SessionEvent` 数据在从会话**输出**时(`events`、`session/event` 监听器)变为 `DeepReadonly`;`append()` 仍接受普通可变输入。一个 `DeepReadonly<T>` 工具类型放入 dsh-llm,与 brand/never 辅助类型并列。 -- `deriveMessages()` 返回深度只读的消息;agent loop(智能体循环)在将可变请求交给 `agent/request` waterfall 之前先克隆一份(在 waterfall 中变异是被允许的——克隆使边界显式且廉价,每步仅一次)。 -- `PromptAssembly` 在其 waterfall 流程中保持可变(被允许),但注册表的内部 section 列表在每次组装时被克隆(已有此行为)。 +- `SessionEvent` 数据在从会话**输出**时(`events`、`session/event` 监听器)变为 `DeepReadonly`;`append()` 仍接受普通可变输入。一个 `DeepReadonly<T>` 工具类型放在 dsh-llm 中,与 brand/never 辅助类型相邻。 +- `deriveMessages()` 返回深度只读的消息;agent loop(智能体循环)在将可变请求交给 `agent/request` waterfall 之前先克隆(该处的突变是被允许的——克隆使边界显式且代价低廉,每个步骤仅一次)。 +- `PromptAssembly` 在其 waterfall 流经期间保持可变(被允许),但注册表内部的 section 列表在每次组装时被克隆(已有此行为)。 ## 计划 -引入 `DeepReadonly`,翻转会话的读取路径,并修复消费方由此产生的编译错误。 +引入 `DeepReadonly`,翻转会话的读取路径,并修复消费方中由此产生的编译错误。 ## 风险 -`DeepReadonly` 类型会在 waterfall 边界处产生噪音错误——因为变异在那里正是 API 的一部分。应将可变/只读边界严格限定在「已记录 vs 进行中」,并在会话 README 中加以说明。 +`DeepReadonly` 类型在 waterfall 边界处(突变本身就是 API 的地方)可能产生噪音较大的错误。应将可变/只读边界精确地划在「已记录 vs 进行中」,并在 session README 中加以说明。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml index ba7de6f475..11ed0efa0b 100644 --- a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-providerless-example-base.md: be5122ec6665dcea15619f3cb4b3ed3a2fa03972 -2026-06-20-providerless-example-base.zh.md: 011636bbdfb782a5b6e4c03695cd0a4a428993d5 +2026-06-20-providerless-example-base.zh.md: f01451f719f0fe1bbb50806aea40086e7fe08350 diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md index 011636bbdf..f01451f719 100644 --- a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md @@ -1,4 +1,4 @@ -# RFC:使共享示例基础配置不依赖提供方 +# RFC:使共享示例基础配置与提供方无关 [English](2026-06-20-providerless-example-base.md) | 中文 @@ -6,26 +6,26 @@ Status: rejected — superseded by [Extract example apps into packages](../../im ## 问题 -示例曾有两个共享基础文件:`examples/base-core.yml` 不依赖任何模型提供方,而 `examples/base.yml` 在此核心之上加入了真实的 `llm-deepseek` 适配器。快照回放需要搭配 `llm-replay` 使用那个提供方无关的核心,因为在没有 key 的情况下加载真实适配器会抛错。常规演示则需要真实适配器。结果是命名倒挂:名为 `base.yml` 的文件并非所有示例的可复用基础,而真正的基础反而叫 `base-core.yml`。 +示例曾有两个共享基础文件:`examples/base-core.yml` 与提供方无关,而 `examples/base.yml` 在该核心基础上加入了真实的 `llm-deepseek` 适配器。快照回放需要与提供方无关的核心配合 `llm-replay` 使用,因为在没有密钥的情况下加载真实适配器会抛出异常。常规演示则需要真实适配器。结果是命名与实际含义倒挂:名为 `base.yml` 的文件并非所有示例可复用的基础,而真正的基础反倒是 `base-core.yml`。 -这种拆分可以理解,但它让每次解释配置都变得更长。它还导致了别扭的测试搭建方式:keyless 冒烟测试需要携带一个假 API key 才能让适配器启动,尽管模型根本不会被调用。 +这种拆分可以理解,但它让每次解释配置都变得更冗长。它还导致了别扭的测试搭建方式,例如无密钥冒烟测试不得不携带一个虚拟 API key,仅仅为了让适配器能启动——尽管模型根本不会被调用。 ## 提案 -将提供方无关的核心重命名为 `examples/base.yml`,让适配器选择在每个具体示例中显式声明。编码与 ACP 真实配置添加一小段 `llm-deepseek` include 或本地块;快照配置添加 `llm-replay`。删除 `examples/base-core.yml`。 +将与提供方无关的核心重命名为 `examples/base.yml`,让适配器选择在每个具体示例中显式声明。编码和 ACP 真实配置添加一小段 `llm-deepseek` include 或本地块;快照配置添加 `llm-replay`。删除 `examples/base-core.yml`。 -共享基础应当只包含提供方无关的服务与工具:`llm`、会话、系统提示词、工具、agent、不变式、bash 执行器与 bash 工具 schema。任何选择模型提供方的内容都属于叶子配置。 +共享基础应仅包含提供方无关的服务与工具:`llm`、会话、系统提示词、工具、agent、不变式、bash 执行器和 bash 工具 schema。任何涉及模型提供方选择的内容都应放在叶子配置中。 ## 验收标准 -- `examples/base.yml` 不依赖任何提供方。 +- `examples/base.yml` 与提供方无关。 - `examples/base-core.yml` 已删除。 - 真实演示配置显式添加 DeepSeek 适配器。 -- 快照回放配置引入同一个提供方无关的基础及其回放适配器。 -- [examples README](../../../../examples/README.md)、各示例的 README 与 RFC 引用不再解释"base = base-core 加适配器"。 +- 快照回放配置 include 同一个与提供方无关的基础,并加入其回放适配器。 +- [examples README](../../../../examples/README.md)、各示例 README 及 RFC 引用不再解释「base = base-core 加适配器」。 ## 放弃了什么 -真实演示失去了一层便利:每个都必须显式引入适配器。对示例而言这是正确的默认值,因为适配器选择是可变部分,而提供方无关的接线才是共享的产品核心。 +真实演示失去了一层便利:每个演示都必须显式引入适配器。对于示例而言这是正确的默认行为,因为适配器选择是可变部分,而与提供方无关的接线才是共享的产品核心。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml index 243b308c50..ec03777980 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-assembled-assistant-messages-only.md: 7605f286cf5914a127f5f8e2b77490648b42cc30 -2026-06-20-assembled-assistant-messages-only.zh.md: e282c5bd74fd3b854c85112d64de44a5470007bc +2026-06-20-assembled-assistant-messages-only.zh.md: 05f15ffadba4607bc64fdf2f7eefdbcc41cf03a3 diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md index e282c5bd74..05f15ffadb 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md @@ -1,36 +1,36 @@ -# RFC:只持久化已组装的 assistant 消息,不持久化流式分片 - -Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement. +# RFC:仅持久化组装后的 assistant 消息,不存储流式分片 [English](2026-06-20-assembled-assistant-messages-only.md) | 中文 +Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement. + ## 问题 -当前的规范会话日志会逐条持久化模型流出的每个 `assistant/chunk`。[会话持久化 RFC](../../implemented/architecture/2026-06-14-session-persistence.md) 选择这一方案是为了 token 级别的回放保真度和连续的 `seq`,但代价日益增长:JSONL fixture(测试前置数据)被大量微小的 delta 记录占据;快照场景通过分组 chunk 事件来回放模型;ACP 加载时需要从 chunk 重建先前的 assistant 输出;任何未来的日志读取方都必须区分持久的消息历史与 token 级别的追踪。 +当前的规范会话日志会持久化模型流式输出的每一个 `assistant/chunk`。[会话持久化 RFC](../../implemented/architecture/2026-06-14-session-persistence.md) 选择这一方案是为了 token 级别的回放保真度和连续的 `seq`,但其代价日益增长:JSONL fixture(测试前置数据)被大量微小的 delta 记录占据,快照场景通过分组 chunk 事件来回放模型,ACP(Agent Client Protocol)加载时从 chunk 重建先前的 assistant 输出,而任何未来的日志读取方都必须区分持久的消息历史与 token 级别的追踪。 -对于成功完成并组装出完整内容的步骤,agent loop(智能体循环)已经追加了一条 `assistant/message`。这正是 `deriveMessages()` 用来构造下一次模型请求的事件。换言之,正常的可恢复对话状态已经存在,无需 chunk;chunk 是实时渲染和确定性测试的产物,不是必需的对话历史。失败或中止的流则不同:部分 assistant 输出可能仅以 chunk 形式存在,而空的 max-token 步骤可能根本不产生 `assistant/message`。 +对于成功组装出完整内容的步骤,agent loop(智能体循环)已经追加了一条 `assistant/message`。这正是 `deriveMessages()` 用来构造下一次模型请求的事件。换言之,正常的可恢复会话状态无需 chunk 即已具备;chunk 是实时渲染和确定性测试的产物,不是必需的会话历史。失败或中止的流则不同:部分 assistant 输出可能仅以 chunk 形式存在,而空的 max-token 步骤可能根本不产生 `assistant/message`。 ## 提案 -停止在规范会话日志中存储 `assistant/chunk`。持久日志只保留 `assistant/message`、`tool/call`、`tool/result`、保留的 `usage`,以及轮次边界。实时 UI 仍可通过一个刻意设计为瞬态的流事件接收 token 增量。快照回放应将其模型脚本移入显式的 fixture 伴随文件,或从已记录的适配器产物派生,而不是把规范的用户会话当作 token 磁带。需要部分失败流输出的场景必须在回放 fixture 中记录该输出。 +停止在规范会话日志中存储 `assistant/chunk`。持久日志保留 `assistant/message`、`tool/call`、`tool/result`、`usage`(如保留)以及轮次边界。实时 UI 仍可通过一个刻意设计为瞬态的流事件接收 token 增量。快照回放应将其模型脚本移入显式的 fixture 伴随文件,或从记录的适配器产物中派生,而非将规范的用户会话当作 token 磁带。需要部分失败流输出的场景必须在回放 fixture 中记录该输出。 -ACP 的 `session/load` 可以将先前的 assistant 消息作为完整内容块回放,而不是模拟原始的 token 流。加载的 transcript(文本记录)不必重现每一个历史 delta;它必须展示相同的已完成 assistant 内容,并以有效的提供方历史恢复对话。 +ACP `session/load` 可以将先前的 assistant 消息作为完整内容块回放,而非模拟原始的 token 流。加载后的 transcript(文本记录)无需重现每一个历史 delta;它必须展示相同的已完成 assistant 内容,并以有效的 provider 历史恢复运行。 ## 验收标准 -- `SessionEventMap` 移除 `assistant/chunk`,或在需要过渡性实时事件时将其标记为不持久化。 -- [会话持久化文档](../../../../packages/session-persistence/session-persistence/README.md)不再要求逐条存储每个流式分片。 -- `llm-replay` 与 ACP 快照使用显式的回放 fixture 格式或伴随文件来承载模型 chunk。 +- `SessionEventMap` 移除 `assistant/chunk`,或在需要过渡性实时事件时将其标记为非持久化。 +- [会话持久化文档](../../../../packages/session-persistence/session-persistence/README.md)不再要求逐字存储每个流式分片。 +- `llm-replay` 和 ACP 快照使用显式的回放 fixture 格式或伴随文件来存储模型 chunk。 - `session/load` 从 `assistant/message` 渲染已完成的 assistant 消息。 - 存储的日志大幅缩小,且在没有 chunk 空洞的情况下保持 `seq` 连续。 - 会话格式版本与已记录的 fixture 一并刷新;按预发布格式策略拒绝非当前版本的存储日志。 ## 放弃了什么 -规范的用户会话不再能重建旧轮次的精确 token 流。它还会丢失失败或中止流的部分 assistant 输出,除非有其他事件或 fixture 记录了它。对于当前的恢复、加载和快照契约而言,这是过大的信息损失。需要精确确定性流的测试应当自行拥有该 fixture,前提是生产会话日志为用户可见的恢复保留了足够的保真度。 +规范的用户会话不再能重建旧轮次的精确 token 流。它也会丢失失败或中止流的部分 assistant 输出,除非另有事件或 fixture 记录。对于当前的恢复、加载和快照契约而言,这是过大的信息损失。需要精确确定性流的测试应当直接拥有该 fixture,前提是生产会话日志为用户可见的恢复保留了足够的保真度。 ## 相关 -本 RFC 取代[会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md)中关于 chunk 持久化的决策,并影响 [ACP 快照测试](../../implemented/testing/2026-06-19-acp-snapshot-tests.md)——其当前的回放插件从 `assistant/chunk` 事件派生脚本。 +本 RFC 取代 [会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md) 中关于 chunk 持久化的决策,并影响 [ACP 快照测试](../../implemented/testing/2026-06-19-acp-snapshot-tests.md)——其当前的回放插件从 `assistant/chunk` 事件派生脚本。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml index 9d083a9f72..35f0ecedd9 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-acp-session-load.md: 39f24d313db6083db45ff6fbc4a84f504e7714cb -2026-06-20-drop-acp-session-load.zh.md: 003c66636a75e21199f3c3ac600867cf9b73b87c +2026-06-20-drop-acp-session-load.zh.md: b7339f492d5f6b7e2daab5820dada0fa2b5fe823 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md index 003c66636a..b7339f492d 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md @@ -1,29 +1,29 @@ -# RFC:移除 ACP session/load,待恢复功能具备产品形态后再引入 - -Status: rejected — Zed is the current target ACP client, advertises and exercises load-capable sessions, and keeps pending-load state for concurrent `session/load`. The bridge should keep `session/load` and make the resume contract solid. +# RFC:移除 ACP session/load,直到 resume 具备产品形态 [English](2026-06-20-drop-acp-session-load.md) | 中文 +Status: rejected — Zed 是当前目标 ACP 客户端,它声明并使用支持 load 的会话,且为并发 `session/load` 维护 pending-load 状态。bridge 应保留 `session/load` 并使 resume 契约更加稳固。 + ## 问题 -ACP(Agent Client Protocol)当前通告 `loadSession: true` 并实现了 `session/load`:向 bridge 注入持久化能力、校验 cwd 与存储元数据的一致性、从持久化日志重建 agent、并向客户端回放先前的 transcript(文本记录)更新。这条路径有自己的竞态处理、loading-id 守卫、回放展示逻辑和测试。它还依赖规范日志保留足够的 UI 数据来重建旧的分片和工具展示。 +ACP(Agent Client Protocol)声明 `loadSession: true` 并实现 `session/load`:向 bridge 注入持久化能力、校验 cwd 与存储元数据的一致性、从持久化日志重建 agent(智能体),并向客户端回放先前的 transcript(文本记录)更新。该路径有自己的竞态处理、loading-id 守卫、回放展示逻辑和测试。它还依赖规范日志保留足够的 UI 数据,以重建旧的分片和工具展示。 -持久化本身仍是基础能力,但编辑器可见的恢复功能尚未经过产品流程设计。目前没有会话选择器、没有标题/预览元数据,对加载失败或部分加载也没有清晰的用户体验。bridge 正在为一个仅由测试、文档和当前目标客户端的会话模型所使用的功能承担复杂度。 +持久化仍然是基础能力,但编辑器可见的 resume 尚未经过产品流程设计。目前没有会话选择器、没有标题/预览元数据,也没有明确的加载失败或部分加载的用户体验。bridge 正在为一个仅被测试、文档和当前目标客户端的会话模型所使用的功能付出复杂度代价。 ## 提案 -暂时只支持新建会话。`initialize` 通告 `loadSession: false` 或省略该能力,`session/load` 不予支持。持久化仍可供 agent loop(智能体循环)和测试使用;如果其他消费方需要,恢复功能仍可作为底层工厂存在。编辑器 bridge 应在具备真正的会话选择 UX 和稳定的加载 transcript 契约后,再重新引入 `session/load`。 +当前阶段,ACP 仅启动全新会话。`initialize` 声明 `loadSession: false` 或省略该能力,`session/load` 不予支持。持久化仍可供 agent loop(智能体循环)和测试使用;如果其他消费方需要,resume 仍可作为底层工厂存在。编辑器 bridge 应在具备真正的会话选择 UX 和稳定的 load transcript 契约后,再重新引入 `session/load`。 ## 验收标准 - ACP 不再仅为 `session/load` 注入 `sessionPersistence`。 -- `initialize` 不通告加载支持。 -- `session/load` 处理器、loading-id 追踪、已加载会话的 cwd 预检以及加载回放测试全部移除。 -- 快照 fixture(测试前置数据)不再依赖加载回放的展示逻辑。 -- [ACP 文档](../../../../packages/ui/acp/README.md)仅描述新建会话的支持。 +- `initialize` 不再声明 load 支持。 +- `session/load` handler、loading-id 追踪、已加载会话的 cwd 预检以及 load 回放测试均被移除。 +- 快照 fixture(测试前置数据)不再依赖 load 回放展示。 +- [ACP 文档](../../../../packages/ui/acp/README.md)仅描述全新会话的支持。 -## 放弃了什么 +## 放弃的能力 -编辑器无法通过 ACP 重新打开先前持久化的会话。这确实是一个有价值的产品功能,但当前实现超前于 UX 设计,且将 bridge 绑定在 token 级别的日志回放上。保留持久化但移除编辑器加载,将 bridge 收窄到它当前能干净呈现的工作流。 +编辑器无法通过 ACP 重新打开先前持久化的会话。这确实是一项产品功能,但当前实现超前于 UX 设计,且将 bridge 绑定到 token 级别的日志回放。保留持久化但移除编辑器 load,可将 bridge 收窄到它当前能干净呈现的工作流。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml index 61557e984b..16827c901b 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-acp-terminal-meta.md: 4ae3b31824ece850da0ddbc004e97b21e3cb9aad -2026-06-20-drop-acp-terminal-meta.zh.md: 62341ccae728d981400fdc22b8ec7380bbb3faf2 +2026-06-20-drop-acp-terminal-meta.zh.md: f5b3e0a4e1f37445a0b0dcbf7426806a1de89763 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md index 62341ccae7..f5b3e0a4e1 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md @@ -1,31 +1,31 @@ # RFC:移除 ACP 终端 `_meta` 渲染 -Status: rejected — Zed is the current target client, and the terminal `_meta` convention is intentional Zed UX with a plain ACP fallback for other clients. - [English](2026-06-20-drop-acp-terminal-meta.md) | 中文 +Status: rejected — Zed 是当前目标客户端,终端 `_meta` 约定是有意为之的 Zed UX 设计,同时为其他客户端提供纯 ACP(Agent Client Protocol)回退路径。 + ## 问题 -ACP(Agent Client Protocol)桥接层通过 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit` 实现了一套 Zed 专属的终端卡片约定。已实现的[富 ACP bash 渲染 RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 有意避开了 ACP 客户端侧的 `terminal/create`(因为 bash 执行属于 harness 的职责),但仍采用了参考 agent 的纯展示用 `_meta` 约定。这为 Zed 带来了更好的卡片效果,代价是桥接层状态、能力协商、终端 id、特殊的 update 映射、文本回退测试,以及 `dsh-tool-bash` 中的 exit-pill 解析。 +ACP 桥接层通过 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit` 实现了一套 Zed 特有的终端卡片约定。已实现的[富 ACP bash 渲染 RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 刻意回避了 ACP 客户端侧的 `terminal/create`(因为 bash 执行属于 harness 职责),但仍采用了参考 agent(智能体)的纯展示 `_meta` 约定。这在 Zed 中带来了更好的卡片效果,代价是桥接状态、能力协商、终端 id、特殊的 update 映射、文本回退测试,以及 `dsh-tool-bash` 中的 exit-pill 解析。 -回退路径已经存在:将工具调用和完成输出渲染为普通的 ACP 内容块。非 Zed 客户端本来就依赖这条路径,但 Zed 终端卡片是当前目标客户端的功能,而非投机性的装饰。 +回退路径已经存在:将工具调用和完成输出渲染为普通 ACP 内容块。非 Zed 客户端本来就依赖这条路径,但 Zed 终端卡片是当前目标客户端的功能特性,而非推测性装饰。 ## 提案 -忽略 `clientCapabilities._meta.terminal_output`,通过普通 ACP 内容路径渲染 bash 结果。执行仍留在 agent 侧,通过 `dsh-bash` 完成;只移除与展示相关的终端元数据。如果 ACP 日后标准化了 agent 执行的终端,或产品决定 Zed 专属展示值得维护成本,终端卡片可以回归。 +忽略 `clientCapabilities._meta.terminal_output`,通过纯 ACP 内容路径渲染 bash 结果。执行仍由 agent 侧的 `dsh-bash` 完成;仅移除展示相关的终端元数据。如果 ACP 日后标准化了 agent 执行的终端,或产品决定 Zed 特有展示值得其维护成本,终端卡片可以再回来。 -本提案比[收拢工具自有 UI 展示](2026-06-20-generic-tool-rendering.md)更窄:如果通用的 `presentCall`/`presentResult` 保留,本提案不动它们,只移除终端子形态和 `_meta` 映射。 +本提案比[收拢工具自有 UI 展示](2026-06-20-generic-tool-rendering.md)更窄:如果通用的 `presentCall`/`presentResult` 保留,本提案不影响它们,只移除终端子形态与 `_meta` 映射。 ## 验收标准 - ACP 不再读取或存储 `_meta.terminal_output` 能力状态。 -- `TerminalRendering`、终端 id、终端 cwd 解析以及 `_meta.terminal_*` update 映射从 `@deepseek-ai/dsh-acp` 中消失。 -- `ToolTerminal` 从 `@deepseek-ai/dsh-tools` 中消失,或在展示清理中因无使用而删除。 +- `TerminalRendering`、终端 id、终端 cwd 解析与 `_meta.terminal_*` update 映射从 `@deepseek-ai/dsh-acp` 中消失。 +- `ToolTerminal` 从 `@deepseek-ai/dsh-tools` 中消失,或在展示清理中因未使用而删除。 - Bash 结果展示不再为终端 pill 解析退出状态。 -- 已实现的[富 ACP bash 渲染 RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 保留在 `implemented/` 中作为已交付的历史记录,如被本提案取代则互相交叉引用。 +- 已实现的[富 ACP bash 渲染 RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 作为已交付历史保留在 `implemented/` 中;如被本提案取代,则加上交叉链接。 ## 放弃的内容 -Zed 用户将失去专属终端卡片:没有 cwd 头部、终端展示或 exit pill。他们仍能以普通内容形式看到命令和输出。在 ACP 桥接层尚未发布、`_meta` 键仍是约定而非标准的阶段,这是合理的简化。 +Zed 用户将失去专用终端卡片:没有 cwd 头部、终端展示或 exit pill。他们仍能以纯内容形式看到命令和输出。在 ACP 桥接层尚未发布、`_meta` 键只是约定而非标准的阶段,这是合理的简化。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml index f0ed7ad2b5..de324b8de2 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-bash-output-spill-files.md: bbc26c645cefb1659012ca0debda78fc6850d276 -2026-06-20-drop-bash-output-spill-files.zh.md: 1439616bf55ad388e69ba693cbc7c130f4e2fc8c +2026-06-20-drop-bash-output-spill-files.zh.md: 43b6029a68542d03027b61424a2a3024ace200d5 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md index 1439616bf5..43b6029a68 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md @@ -1,20 +1,20 @@ # RFC:移除 bash 完整输出溢出文件 -Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output. - [English](2026-06-20-drop-bash-output-spill-files.md) | 中文 +Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output. + ## 问题 -`dsh-bash-local` 在内存中保留有界的输出,并将大体积的 stdout/stderr 流溢出到私有临时文件。这要求维护一个私有目录、创建仅所有者可读的随机文件、处理关闭失败、按字节偏移增量读取、报告有损读取、在面向模型的文本中渲染路径,以及清理纪律。当输出被截断时,工具会告诉模型去读取一个本地溢出路径。 +`dsh-bash-local` 在内存中保留有界的输出,并将大体量的 stdout/stderr 流溢出到私有临时文件。这要求一个私有目录、仅所有者可写的随机文件创建、关闭失败处理、基于字节偏移的增量读取、有损读取报告、在面向模型的文本中渲染路径,以及清理纪律。当输出被截断时,该工具会告知模型去读取一个本地溢出路径。 -这解决了一个真实问题,但方式狭窄且有泄漏。溢出路径是一个暴露在模型输出中的进程本地文件系统产物,而非具备作用域访问、保留策略或 UI 能力的持久化 harness 产物。它还使后台任务的读取变得复杂,因为有损增量读取必须指向一到两个溢出文件。 +这解决了一个真实问题,但方式狭隘且有泄漏。溢出路径是一个暴露在模型输出中的进程级文件系统产物,而非具有作用域访问控制、保留策略或 UI 支持的持久化 harness 产物。它还使后台任务的读取变得复杂,因为有损增量读取必须指向一个或两个溢出文件。 ## 提案 -保留尾部截断,移除完整输出溢出文件。bash 结果包含有界的尾部内容加一个明确的截断标记;不输出路径。如果用户需要恢复完整输出,则添加一个通用的产物/blob 服务(具备显式的所有权、清理和 UI 渲染),再让 bash 将大体积输出附加到该服务。 +保留尾部截断,移除完整输出溢出文件。bash 结果包含有界的尾部内容加一个明确的截断标记;不输出路径。如果用户需要恢复完整输出,则添加一个通用的产物/blob 服务(具有明确的所有权、清理和 UI 渲染),然后让 bash 将大体量输出附加到该服务。 -本提案可以独立于[通用长时运行工具运行时](../../proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md)落地。如果后台任务保留,`bash_output` 仍应报告输出已被丢弃,但不再公布溢出路径。 +本提案可以独立于[通用长时间运行工具运行时](../../proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md)落地。如果后台任务保留,`bash_output` 仍应报告输出已被丢弃,但不再提供溢出路径。 ## 验收标准 @@ -24,8 +24,8 @@ Status: rejected — full-output recovery is a real bash behavior. A future arti - 测试覆盖尾部截断,不再断言完整输出文件的内容。 - [docs/defensive-patterns.md](../../../defensive-patterns.md) 中的安全指导不再将私有溢出文件视为面向模型的接口。 -## 放弃了什么 +## 放弃的能力 -模型或用户无法再从临时文件恢复大体积命令输出中被省略的前缀。在真正的产物服务出现之前,这是可接受的。当前的溢出路径为一个生命周期和权限都未经设计的功能引入了过多的定制机制。 +模型或用户无法再从临时文件恢复大体量命令输出中被省略的前缀。在真正的产物服务出现之前,这是可以接受的。当前的溢出路径为一个生命周期和权限均未经设计的功能引入了过多的定制机制。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml index 51d6027a24..7396bcf5aa 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-durable-step-boundaries.md: fba8ad4211db69d3a04d253fd9544caca0f538c6 -2026-06-20-drop-durable-step-boundaries.zh.md: 9ffa12cfba697f1e3bc9059529d0fdf97f595705 +2026-06-20-drop-durable-step-boundaries.zh.md: e389c5506b03a472c74853f3b73c21681f96287f diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md index 9ffa12cfba..e389c5506b 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md @@ -1,32 +1,32 @@ # RFC:移除持久化的步骤边界事件 +Status: rejected — `step/end` is the durable indication that a model step finished, and keeping the symmetric `step/start` / `step/end` pair makes crash repair, invariants, and transcript inspection clearer than inferring completion from adjacent step-scoped events. + [English](2026-06-20-drop-durable-step-boundaries.md) | 中文 -Status: rejected — `step/end` 是模型步骤已完成的持久化标识,保留对称的 `step/start` / `step/end` 对,在崩溃恢复、不变式检查和 transcript(文本记录)审查方面,都比从相邻的步骤级事件推断完成状态更清晰。 - ## 问题 -会话日志存储了 `step/start` 和 `step/end` 事件,尽管每个步骤级事件本身已携带 `{ turn, step }`:assistant 分片、assistant 消息、工具调用、工具结果、token 用量和错误。`deriveMessages()` 忽略步骤边界,ACP(Agent Client Protocol)在 UI 层也忽略它们,主要消费方是不变式检查、测试、快照 golden 文件和崩溃恢复。 +会话日志存储了 `step/start` 和 `step/end` 事件,尽管每个步骤作用域的事件本身已经携带 `{ turn, step }`:assistant 分片、assistant 消息、工具调用、工具结果、用量和错误。`deriveMessages()` 忽略步骤边界,ACP(Agent Client Protocol)在 UI 层面也忽略它们,主要消费方是不变式检查、测试、快照 golden 文件和崩溃恢复。 -被否决的论点是:边界事件让日志更像仪式而非信息。实际上,`step/end` 是具体信息:读者无需从下一个事件推导,就能判断一次模型请求是已完成、已崩溃还是正在被修复。同样,一条孤立的 `step/start` 对于「模型请求已发起但在产出任何分片之前就失败了」的场景也有用。 +被否决的论点是:边界事件使日志更像仪式而非信息。实际上,`step/end` 是具体信息:读者无需从下一个事件推导状态,就能判断一次模型请求是已完成、已崩溃还是正在修复。同样,一个孤立的 `step/start` 对于「模型请求已发起但在产生任何分片之前就失败了」的场景也有价值。 ## 提案 -以轮次作为唯一的持久化边界。从 `SessionEventMap` 中移除 `step/start` 和 `step/end`;保留步骤级事件上用于分组的数值 `step` 字段。agent loop(智能体循环)递增步骤计数器,并以该编号记录步骤级事件,但不再追加开/关边界事件。消费方通过共享 `(turn, step)` 的连续事件推断步骤分组。 +将轮次作为唯一的持久化边界。从 `SessionEventMap` 中移除 `step/start` 和 `step/end`;在需要分组的事件上保留数值型 `step` 字段。agent loop(智能体循环)递增步骤计数器并以该编号记录步骤作用域的事件,但不再追加开/关边界事件。消费方通过共享 `(turn, step)` 的连续事件推断步骤分组。 -不变式插件应强制步骤级事件在一个已打开的轮次内具有有效的正整数步骤编号,而非要求它们被独立的边界记录包围。崩溃恢复不应合成 `step/end`;如果一个被中断的轮次被保留,恢复路径仍可关闭该轮次而无需捏造步骤边界记录。 +不变式插件应当强制步骤作用域的事件在一个已打开的轮次内具有有效的正整数步骤编号,而非要求独立的边界记录包围它们。崩溃恢复不应合成 `step/end`;如果一个被中断的轮次被保留,修复路径仍然可以关闭该轮次而无需捏造步骤边界记录。 ## 验收标准 - `SessionEventMap` 不再包含 `step/start` 或 `step/end`。 -- agent loop 不再有 `closeStep()` 终结路径。 +- agent loop 中不再有 `closeStep()` 终结路径。 - ACP 快照和持久化契约 fixture(测试前置数据)不再期望步骤边界行。 -- `deriveMessages()` 和回放从步骤级事件推导出相同的消息历史。 -- [事件分类体系文档](../../../architecture.md)将轮次描述为持久化边界,将步骤描述为步骤级记录上的一个字段。 +- `deriveMessages()` 和回放从步骤作用域的事件推导出相同的消息历史。 +- [事件分类体系文档](../../../architecture.md)将轮次描述为持久化边界,将步骤描述为步骤作用域记录上的一个字段。 - 会话格式版本和已记录的 fixture 被刷新;按预发布格式策略,非当前版本的已存储日志被拒绝。 ## 放弃了什么 -日志不再将「一次模型请求已发起但进程在产出任何事件之前就终止了」记录为持久化事实,也不再有显式的「此步骤已完成」标记。在会话日志仍是持久化回放与审计表面的当下,这一损失不可接受。 +日志不再将「一次模型请求已发起但进程死亡前未产生任何事件」记录为持久化事实,也不再有显式的「此步骤已完成」标记。在会话日志仍是持久化回放与审计表面的当下,这一损失不可接受。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml index aeb154fbb1..f2aab138ee 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-drop-unused-session-lineage.md: 4200532726a27e257e09f927240846f20a0b30ad -2026-06-20-drop-unused-session-lineage.zh.md: c20f964317a1924c3cbc36b7f7838f3a207a65c1 +2026-06-20-drop-unused-session-lineage.zh.md: 1524987111f12a9c6e2014723bb1cb4c87bcf940 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md index c20f964317..1524987111 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md @@ -1,18 +1,18 @@ # RFC:移除未使用的会话血缘元数据 -Status: rejected — `parentSession` is part of the documented fork/sub-agent seam and is already preserved by the agent/session resume path. The field is future-facing, but it is not accidental dead state. - [English](2026-06-20-drop-unused-session-lineage.md) | 中文 +Status: rejected — `parentSession` 是已文档化的 fork/subagent seam 的一部分,且已被 agent(智能体)/session 恢复路径保留。该字段面向未来,但并非意外的死状态。 + ## 问题 -`SessionHeader.parentSession` 记录新会话从哪个会话 fork 而来。它在 `dsh-session` 中定义,被持久化后端保存,在 resume 路径中被复制,作为血缘元数据被文档记录,并有往返测试覆盖。然而仓库中没有任何已上线的 fork UI 或 subagent 流程读取它。计划中的 subagent/fork seam 仍是一个 TODO,因此该字段目前只是被存储的未来形状。 +`SessionHeader.parentSession` 记录新会话从哪个会话 fork 而来。它在 `dsh-session` 中定义,被持久化后端保留,在恢复流程中复制,作为血缘元数据被文档记录,并有往返测试覆盖。然而仓库中没有任何生产环境的 fork UI 或 subagent 流程读取它。计划中的 subagent/fork seam 仍是 TODO,因此该字段目前只是预存的未来形状。 -单文件的代价虽小,但在整个格式中分布广泛:每个后端 schema 和元数据序列化器都在保存一个尚无已完成功能读取的值。由于 header 是一份磁盘契约,即便是占位字段也会成为未来重构必须维护、迁移或有意打破的东西。 +单个文件的成本虽小,但在格式层面影响面广:每个后端 schema 和元数据序列化器都在保留一个尚无已完成功能读取的值。由于 header 是磁盘契约,即使是占位字段也会成为未来重构必须维护、迁移或有意打破的东西。 ## 提案 -从 `SessionHeader` 中移除 `parentSession`,直到真正的 fork/resume 功能需要血缘信息时再引入。如果存在相应 API,fork 仍然可以用先前事件来初始化新会话,但持久化的父指针应当与读取它的功能和解释它的 UX 一同引入。 +从 `SessionHeader` 中移除 `parentSession`,直到真正的 fork/恢复功能需要血缘信息时再引入。如果存在相应 API,fork 仍然可以用先前事件来初始化新会话,但持久化的父指针应当与读取它的功能和解释它的 UX 一同引入。 如果血缘信息回归,届时再决定它应放在不可变 header 中、会话图索引中,还是作为一等事件。当前字段不应预先锁定那个设计。 @@ -20,12 +20,12 @@ Status: rejected — `parentSession` is part of the documented fork/sub-agent se - `SessionHeader` 仅包含 version、id、createdAt 和可选的 cwd。 - JSONL 与 SQLite 元数据 schema 不再存储 parent-session id。 -- resume 和 list API 不再往返传递 `parentSession`。 +- 恢复与列表 API 不再往返传递 `parentSession`。 - 文档和测试移除没有生产消费方支撑的 fork 血缘声明。 -- 会话格式版本、后端 schema 版本和录制的 fixture(测试前置数据)按需刷新;按预发布格式策略,非当前版本的已存储数据将被拒绝,不提供迁移路径。 +- 会话格式版本、后端 schema 版本与记录的 fixture(测试前置数据)按需刷新;按预发布格式策略,非当前版本的存储数据将被拒绝,不提供迁移路径。 ## 放弃了什么 -代码库失去一个为未来 fork/subagent UX 准备好的血缘钩子。这是有意为之。该字段在功能存在时很容易重新引入,而未发布的立场允许格式变更无需迁移。 +代码库失去了一个为未来 fork/subagent UX 预备的现成血缘钩子。这是有意为之。该字段在功能存在时很容易重新引入,而未发布的立场允许格式变更无需迁移。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml index bb1af91b9b..8442da7f7e 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-fold-session-persistence-interface.md: 695cd679c67f3e0a9f901c671c33e9507ecbe279 -2026-06-20-fold-session-persistence-interface.zh.md: 1ef93fb64cc27eeeb465136dc7dac6e751a7ccfc +2026-06-20-fold-session-persistence-interface.zh.md: 38f79f833fb5d95e4d9f392de627ee16b17cb997 diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md index 1ef93fb64c..38f79f833f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md @@ -1,4 +1,4 @@ -# RFC:将持久化接口合入 dsh-session +# RFC:将持久化接口合并进 dsh-session Status: rejected — the separate persistence interface package is the intended modular capability seam for durable backends. Folding it into `dsh-session` would reduce package count at the cost of a cleaner backend boundary. @@ -6,26 +6,26 @@ Status: rejected — the separate persistence interface package is the intended ## 问题 -`dsh-session-persistence` 是一个接口包(package),其核心概念已由 `dsh-session` 拥有:`SessionHeader`、`SessionEvent`、`SessionId`、`session/event` 和 `session/flush`。该包额外引入了抽象的 `SessionPersistence` 服务、共享写协调器和契约辅助工具。后端包依赖它,`agent-loop` 则需要可选地发现一个兄弟服务来实现恢复。 +`dsh-session-persistence` 是一个接口包(package),其核心概念已经由 `dsh-session` 拥有:`SessionHeader`、`SessionEvent`、`SessionId`、`session/event` 与 `session/flush`。该包额外添加了抽象的 `SessionPersistence` 服务、共享写入协调器和契约辅助工具。后端包依赖它,`agent-loop`(智能体循环)也需要可选地查找一个同级服务来实现恢复。 -当持久化还是一个全新的可替换后端设计时,能力 seam 的拆分是合理的。但在可变摘要被移除之后,这个接口包基本上只是包装了会话日志自身的存储关注点。保持独立可能带来的仪式感多于清晰度。 +当持久化还是一个全新的可替换后端设计时,能力 seam 的拆分是合理的。但在可变摘要被移除之后,这个接口包基本上只是包装了会话日志自身的存储关切。继续保持独立可能带来的仪式感多于清晰度。 ## 提案 将抽象的 `SessionPersistence` 服务、协调器和持久化契约辅助工具移入 `dsh-session`。JSONL 和 SQLite 仍作为独立的后端包,注册由 session 包拥有的服务。这样既保留了后端可替换性,又删除了一个支撑包和一条跨包 seam。 -实施 PR(Pull Request)应更新[能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md) 指南,补充此例外:持久化不同于 bash 或 LLM(大语言模型),因为它的词汇和生命周期事件本身就是 session 包的核心领域。 +实施 PR(Pull Request)应更新[能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md) 指南,补充此例外:持久化不同于 bash 或 LLM(大语言模型),因为它的词汇和生命周期事件本就属于 session 包的核心领域。 ## 验收标准 - `@deepseek-ai/dsh-session-persistence` 作为包被移除。 - `dsh-session` 导出持久化服务类型、协调器和契约辅助工具。 - JSONL 和 SQLite 后端包直接依赖 `dsh-session`。 -- `agent-loop` 的恢复功能使用由 session 包拥有的服务键。 -- [会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md)、[共享持久化写协调器](../../implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)与[包文档](../../../../packages/session-persistence/session-persistence/README.md)说明后端实现为何仍保持独立。 +- `agent-loop` 的恢复功能使用 session 包拥有的服务键。 +- [会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md)、[共享持久化写入协调器](../../implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)与[包文档](../../../../packages/session-persistence/session-persistence/README.md)说明后端实现为何仍保持独立。 ## 放弃了什么 -`dsh-session` 变得更重:它同时拥有内存日志和持久化接口。这就是取舍。如果第三方持久化后端已经形成公开生态,独立的接口包会是更清晰的 SDK 边界;但在预发布阶段,多出的包看起来像是在有外部消费方之前的过度抽象。 +`dsh-session` 变得更重:它同时拥有内存日志和持久化接口。这就是代价。如果第三方持久化后端已经形成公开生态,独立的接口包会是更清晰的 SDK 边界;但在预发布阶段,在尚无外部消费方时,多出的包看起来更像是过早的抽象。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml index db3ac5d979..3af32eacdd 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-generic-tool-rendering.md: 07102ed3b12d7f587b1d12f0e240c1202a2e1cdd -2026-06-20-generic-tool-rendering.zh.md: 86ea52545a79ff975fc6b9c5d080e111a2750290 +2026-06-20-generic-tool-rendering.zh.md: d2c8c745f0ac04a01eb72b50fd1b63cb655afe36 diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md index 86ea52545a..d2c8c745f0 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md @@ -6,30 +6,30 @@ Status: rejected — tool-owned presentation should wait for more real tools bef ## 问题 -工具可以定义 `presentCall()` 和 `presentResult()` 回调,返回 `ToolCallPresentation`、`ToolResultPresentation` 以及可选的 `ToolTerminal` 字段。代码本身已标记出设计的混乱:title、kind、raw input、content、terminal cwd、terminal output、exit code 和 signal 逐步堆积成一堆可选字段。ACP(Agent Client Protocol)随后维护 pending call 状态以将 result 与原始 args 配对,在 `session/load` 时创建仅用于回放的 presenter,并将 terminal 子字段映射为 Zed 特有的 `_meta`。`dsh-tool-bash` 甚至从已渲染的文本中反向解析退出状态,因为纯回放安全的 presenter 已经拿不到结构化的 `BashRunResult`。 +工具可以定义 `presentCall()` 和 `presentResult()` 回调,返回 `ToolCallPresentation`、`ToolResultPresentation` 以及可选的 `ToolTerminal` 字段。代码本身就标记了这个设计的混乱:title、kind、raw input、content、terminal cwd、terminal output、exit code 和 signal 逐步增长为一堆可选字段。ACP(Agent Client Protocol)随后维护 pending call 状态以将 result 与原始 args 配对,在 `session/load` 时创建仅用于回放的 presenter,并将 terminal 子字段映射为 Zed 特有的 `_meta`。`dsh-tool-bash` 甚至从渲染后的文本中反向解析退出状态,因为纯回放安全的 presenter 已经拿不到结构化的 `BashRunResult`。 -真正的一方使用场景是 ACP 的 bash 展示。这不足以作为冻结一个跨包 UI 展示 API 的依据。 +真正的第一方用途是为 ACP 提供 bash 展示。这不足以作为冻结一个跨包 UI 展示 API 的依据。 ## 提案 -暂时移除工具自有的 UI 展示回调。规范的工具事件已经携带工具名称、原始参数字符串、结果内容与错误状态。UI 从这些字段渲染一个通用的工具卡片。工具特有的富展示可以在至少有两个真实工具和两个真实消费方来验证词汇后,以 tagged render-intent union 的形式回归。 +暂时移除工具自有的 UI 展示回调。规范的工具事件已经携带工具名、原始参数字符串、结果内容和错误状态。UI 从这些字段渲染一个通用的工具卡片。工具特有的富展示可以在至少有两个真实工具和两个真实消费方来验证词汇之后,以带标签的 render-intent union 形式回归。 ## 曾考虑的替代方案 -一个更小的替代方案是在单个 PR(Pull Request)中将当前的可选字段包替换为一个显式 union;但如果目标是简化,更彻底的做法是删除回调、保留通用路径。 +作为更小的替代方案,可以在一个 PR(Pull Request)中将当前的可选字段集合替换为一个显式 union;但如果目标是简化,更彻底的做法是删除回调、保留通用路径。 ## 验收标准 - `ToolDefinition` 移除 `presentCall` 和 `presentResult`。 - `ToolCallPresentation`、`ToolResultPresentation`、`ToolTerminal` 和 `ToolCallKind` 消失,除非一个最小的通用 UI 类型仍需要其中之一。 -- ACP 不再维护 presenter pending 状态,也不在实时流式输出/加载回放期间调用工具回调。 -- `dsh-tool-bash` 不再解析已渲染文本来恢复退出状态以生成 UI pill。 -- 快照 golden 展示通用工具卡片和文本结果。 +- ACP 不再维护 presenter pending 状态,也不再在实时流式输出/加载回放期间调用工具回调。 +- `dsh-tool-bash` 不再解析渲染文本来恢复退出状态以供 UI pill 使用。 +- 快照 golden 文件展示通用工具卡片和文本结果。 ## 放弃了什么 -Bash 失去其自定义的终端风格卡片和模型撰写的描述位置。回退方案仍然合理:命令作为工具输入展示,输出作为文本展示。富展示应在产品拥有足够的 UI/工具多样性、足以支撑一份稳定的展示契约时再行设计。 +Bash 失去其自定义的终端风格卡片和模型生成描述的放置位置。回退方案仍然合理:命令作为工具输入展示,输出作为文本展示。富展示应当在产品拥有足够的 UI/工具多样性、足以支撑一份稳定的展示契约时再行设计。 ## 相关 -本 RFC 是[移除 ACP terminal 元数据](2026-06-20-drop-acp-terminal-meta.md)的宽泛版本。如果本 RFC 被接受,那个更窄的 RFC 就不再需要。 +这是[移除 ACP terminal 元数据](2026-06-20-drop-acp-terminal-meta.md)的宽泛版本。如果本 RFC 被接受,那个更窄的 RFC 就不再必要。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml index 62eb41dc9a..a944072e9f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-retire-mid-turn-steering.md: bf78125ec175aa9152789bdccd1f8e8a16863a5b -2026-06-20-retire-mid-turn-steering.zh.md: 03af2b24916a5d1a479dc06a30d54003dfa7f156 +2026-06-20-retire-mid-turn-steering.zh.md: a56e112df37bdeb75ca808f76beabe1fec8b1b7b diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md index 03af2b2491..a56e112df3 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md @@ -1,37 +1,37 @@ -# RFC:废除中途 steering(中途引导) - -Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. +# RFC:移除轮次中途引导 [English](2026-06-20-retire-mid-turn-steering.md) | 中文 +Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. + ## 问题 -agent(智能体)暴露了两条用户消息路径,看起来相近但生命周期语义不同:`send()` 将一条普通用户轮次排入队列,而 `steer()` 在当前运行轮次的步骤之间注入一条消息,空闲时则回退为 `send()`。这一区别渗透到整个栈:`Agent.steer()` 是公开 API,会话日志有持久化的 `steering/message` 事件,agent 事件分类体系有 `agent/steering`,循环在排队消息 FIFO 之外还维护一个 steering FIFO,取消操作需要清空两个队列,`deriveMessages()` 必须将 steering 渲染为带标签的合成用户消息而非普通提示词。 +agent(智能体)暴露了两条用户消息路径,外观相近但生命周期语义不同:`send()` 将一条普通用户轮次排入队列,而 `steer()` 在当前运行轮次的步骤之间注入一条消息,空闲时则回退为 `send()`。这一区分贯穿整个栈:`Agent.steer()` 是公开 API;会话日志有持久化的 `steering/message` 事件;agent 事件分类体系有 `agent/steering`;agent loop(智能体循环)在排队消息 FIFO 之外还维护一个 steering FIFO;取消操作需要清空两个队列;`deriveMessages()` 必须将 steering 渲染为带标签的合成用户消息,而非普通提示词。 -continuation seam 放大了这一成本。`agent/turn-continuation` 默认为 `hadToolCalls || steeringInjected`,因此同一轮次内的 steering 消息即使模型没有请求工具调用也能强制循环再次调用模型。注释中提到了未来的 `/goal`、`/loop` 和预算守卫用途,但当前仓库没有生产级监听器;只有测试注册了该 waterfall(瀑布式事件)。另外,唯一调用 `steer()` 的生产 UI 是 stdio 演示。ACP 在轮次运行期间已经通过普通队列发送提示词。 +续行 seam 进一步放大了成本。`agent/turn-continuation` 默认条件为 `hadToolCalls || steeringInjected`,因此同一轮次内的 steering(中途引导)消息即使模型未请求工具调用,也会强制循环再次调用模型。注释中提到了未来 `/goal`、`/loop` 和预算守卫的用途,但当前仓库没有生产级监听器;只有测试注册了该 waterfall(瀑布式事件)。另外,唯一调用 `steer()` 的生产 UI 是 stdio 演示。ACP(Agent Client Protocol)在轮次运行期间已经通过普通队列发送提示词。 ## 提案 -暂时删除中途用户 steering。`Agent.send()` 成为提交用户内容的唯一公开方式;当 agent 正在运行时,内容等待下一轮次。循环仅因工具调用而在轮次内继续,而非因为用户在某步骤运行期间输入了内容。想要中断当前轮次的调用方使用 `cancel()` 再 `send()`。 +暂时删除轮次中途的用户 steering。`Agent.send()` 成为提交用户内容的唯一公开方式;当 agent 正在运行时,内容等待下一个轮次。循环仅因工具调用而在轮次内继续,不因用户在某个步骤运行期间输入内容而继续。调用方若要中断当前轮次,使用 `cancel()` 后再 `send()`。 -移除 `Agent.steer()`、steering FIFO、`steering/message`、`agent/steering`、由 steering 驱动的 continuation,以及区分排队消息与 steering 消息的取消逻辑。在同一变更中移除 `agent/turn-continuation`,除非实现 PR 发现了生产级监听器;没有 steering 之后,当前仓库不再有具体的 continuation 消费方。如果将来真正的预算或 goal 插件需要强制 continuation,应以该插件为具体消费方重新引入一个更窄的 seam。 +移除 `Agent.steer()`、steering FIFO、`steering/message`、`agent/steering`、由 steering 驱动的续行逻辑,以及取消操作中区分排队消息与 steering 消息的逻辑。除非实现 PR 发现了生产级监听器,否则在同一变更中一并移除 `agent/turn-continuation`;没有 steering 后,当前仓库不再有具体的续行消费方。如果将来真正的预算或目标插件需要强制续行,应以该插件为具体消费方重新引入一个更窄的 seam。 ## 验收标准 - `Agent` 暴露唯一的用户消息入口 `send()`。 - 持久化会话事件词汇不再包含 `steering/message`。 -- `deriveMessages()` 渲染普通用户消息和上下文注入,不再有 steering 标签路径。 -- 循环只有一个排队消息 FIFO,没有同轮次用户消息 continuation 路径。 -- `agent/turn-continuation` 被移除或收窄到一个具名的生产级消费方。 -- stdio UI 和文档将运行期间的输入描述为排入下一轮次的输入。 -- 会话格式版本和录制的 fixture(测试前置数据)已刷新;按预发布格式策略拒绝非当前版本的存储日志。 +- `deriveMessages()` 渲染普通用户消息和上下文注入,不存在 steering 标签路径。 +- 循环只有一个排队消息 FIFO,没有同轮次用户消息续行路径。 +- `agent/turn-continuation` 被移除,或收窄到有具名的生产级消费方。 +- stdio UI 和文档将运行期间的输入描述为「排入下一轮次的输入」。 +- 会话格式版本和已录制的 fixture(测试前置数据)已刷新;非当前版本的存储日志按预发布格式策略被拒绝。 ## 放弃了什么 -用户无法在模型处于工具步骤之间时添加同轮次 steering 内容。这种行为在理论上对「你已经在工作了,顺便也考虑一下 X」有用,但它不是 ACP 今天暴露的行为,而且它使轮次边界变得更难推理。更简单的行为是合理的:用户输入成为下一条提示词,取消仍是替换进行中工作的显式手段。 +用户无法在模型处于工具步骤之间时添加同轮次 steering 内容。这种行为在理论上对「你已经在工作了,也考虑一下 X」的场景有用,但它不是 ACP 当前暴露的行为,且使轮次边界更难推理。更简单的行为是合理的:用户输入成为下一条提示词,取消操作仍是替换进行中工作的显式手段。 ## 相关 -本提案与[删除持久化步骤边界](2026-06-20-drop-durable-step-boundaries.md)天然配对,因为移除同轮次 steering 和 `agent/turn-continuation` 之后,工具调用成为一个轮次包含多个模型步骤的唯一原因。 +本提案与[移除持久化步骤边界](2026-06-20-drop-durable-step-boundaries.md)天然配对,因为移除同轮次 steering 和 `agent/turn-continuation` 后,工具调用成为一个轮次包含多个模型步骤的唯一原因。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml index aa8c2bbf58..57044817c0 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-single-session-acp-bridge.md: b7b52ca4df2d118358303745f4484e3e40a242b3 -2026-06-20-single-session-acp-bridge.zh.md: 2f00067fffcbd7a74f403c6247b290ac09a846b8 +2026-06-20-single-session-acp-bridge.zh.md: bd287f79475433e4d5e502ef30abd5d14410e633 diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md index 2f00067fff..bd287f7947 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md @@ -1,4 +1,4 @@ -# RFC:将 ACP 桥接恢复为每连接单会话 +# RFC:将 ACP 桥接恢复为每连接一个活跃会话 [English](2026-06-20-single-session-acp-bridge.md) | 中文 @@ -6,21 +6,21 @@ Status: rejected — Zed 是当前目标 ACP 客户端,其 ACP 实现明确支 ## 问题 -ACP 桥接现已支持在一条 JSON-RPC 连接上承载多个活跃会话。这一能力带来了多条目会话映射、反向的会话/agent 查找、逐会话的提示词状态、加载中 id、每个事件的解复用、跨会话的销毁,以及未来权限提示与后台任务的隔离问题。早先的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)仍在跟踪未完成的权限归属部分;本 RFC 是与之竞争的简化路径。 +ACP(Agent Client Protocol)桥接现在支持在一条 JSON-RPC 连接上承载多个活跃会话。这一能力带来了多条目会话映射、反向会话/agent(智能体)查找、逐会话的 prompt 状态、加载中 id、每条事件的解复用、跨会话拆除,以及未来权限提示与后台任务的隔离问题。较早的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)仍在追踪未完成的权限归属部分;本 RFC 是与之竞争的简化路径。 -产品目标已证明它需要在一个 harness 进程上承载并发的编辑器对话:Zed 的 ACP 连接拥有多个会话和加载状态。快照回放层仍然避免并发模型流,因为其回放条目是位置敏感的;这是测试 fixture 的局限,不是移除桥接多路复用的理由。 +产品目标已经证明它需要在一个 harness 进程上承载并发的编辑器对话:Zed 的 ACP 连接拥有多个会话和加载状态。快照回放层仍然避免并发模型流,因为其回放条目是位置相关的;这是测试 fixture(测试前置数据)的局限,而非移除桥接多路复用的理由。 ## 提案 -将 ACP 的作用域收回到每连接一个活跃会话。`session/new` 或 `session/load` 创建唯一的会话记录;在现有会话被 dispose 或连接关闭之前,第二个活跃会话请求将被拒绝。如果编辑器需要多个聊天标签页,可以启动多个 agent 子进程,直到桥接具备具体的多会话 UX 和权限模型。 +将 ACP 的范围收回到每连接一个活跃会话。`session/new` 或 `session/load` 创建唯一的会话记录;在现有会话被 dispose(资源释放)或连接关闭之前,第二个活跃会话请求将被拒绝。如果编辑器需要多个聊天标签页,可以启动多个 agent 子进程,直到桥接具备具体的多会话 UX 和权限模型。 -在单个 `SessionRecord | undefined` 即可满足需求的地方,移除多会话映射和解复用逻辑。桥接仍可保留使销毁行为正确的 agent/会话生命周期 seam;简化仅针对在同一传输层上多路复用多个活跃会话这一点。 +移除多会话映射和解复用逻辑,改用单一的 `SessionRecord | undefined` 即可。桥接仍可保留使 dispose 正确的 agent/会话生命周期 seam;简化仅针对在同一传输层上多路复用多个活跃会话这一点。 ## 验收标准 -- ACP 每连接仅有一条活跃会话记录。 +- ACP 每连接只有一条活跃会话记录。 - 当该记录存在时,`session/new` 和 `session/load` 拒绝请求。 -- 事件处理器不再跨 `Map<sessionId, record>` 解复用。 +- 事件处理器不再在 `Map<sessionId, record>` 上做解复用。 - 多会话测试被移除,或移至继续支持多路复用的提案下。 - 既有的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)更新为链接本 RFC,并继续作为当前方向。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml index 32aca9d1e8..19a66353c7 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-06-20-truncate-interrupted-turns.md: e17cb20f0185fe5d47d0a5ca18b7a389951fbadd -2026-06-20-truncate-interrupted-turns.zh.md: 9ded51b29323be452bd67901dea2ba7b309a9903 +2026-06-20-truncate-interrupted-turns.zh.md: 48aeae650f867fb4629db33a448dd6cbaea60ae0 diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md index 9ded51b293..48aeae650f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md @@ -1,4 +1,4 @@ -# RFC:加载时截断被中断的末尾轮次 +# RFC:加载时截断被中断的最终轮次 Status: rejected — a single turn can contain substantial real work, including many steps and large tool output. Preserving interrupted turns is preferable to silently dropping that tail on load. @@ -6,31 +6,31 @@ Status: rejected — a single turn can contain substantial real work, including ## 问题 -当前的持久化契约会保留最后一个已持久写入但从未关闭的轮次。加载时,`interruptedTurnClosers()` 扫描尾部,为未应答的工具调用合成错误的 `tool/result` 事件,在步骤未关闭时追加 `step/end`,追加 `turn/end { kind: 'interrupted' }`,并要求后端持久提交这段修复。协调器、JSONL 后端、SQLite 后端、会话事件词汇、不变式、文档和测试都对这条合成关闭路径建了模。 +当前的持久化契约会保留已持久写入但从未关闭的最终轮次。加载时,`interruptedTurnClosers()` 扫描尾部,为未应答的工具调用合成 error `tool/result` 事件,在 step 处于打开状态时追加 `step/end`,追加 `turn/end { kind: 'interrupted' }`,并要求后端持久提交这次修复。协调器、JSONL 后端、SQLite 后端、会话事件词汇、不变式、文档和测试都对这条合成关闭路径进行了建模。 -这是为了保留上一次崩溃轮次的部分工作而引入的大量机制。它还会生造从未发生过的事件。合成的工具结果有用处(它使提供方历史保持合法),但也意味着恢复后的日志中包含了没有任何工具产出过的、模型可见的文本。当前设计在尚无已发布产品、也没有真实的恢复 UX 来证明部分轮次恢复确有价值的情况下,就优化了最大化的尾部保留。 +这是一套庞大的机制,只为保留上次崩溃轮次中的部分工作。它还会凭空创造从未发生过的事件。合成的工具结果虽然有用(因为它使 provider 历史保持合法),但也意味着恢复后的日志中包含了模型可见、却并非任何工具产出的文本。当前设计在尚无已发布产品、也没有真实恢复 UX 来证明部分轮次恢复确有价值的情况下,就优化了最大化尾部保留。 ## 提案 -加载时只保留到最后一个已完成的轮次。后端仍然容忍并截断撕裂的末尾记录,但如果解析出的持久前缀在一个已打开的 `turn/start` 之后结束,规范的修复方式是丢弃上一个 `turn/end` 之后的所有事件。不合成 `tool/result`,不合成 `step/end`,不追加 `turn/end { interrupted }`,也不需要 `interrupted` 轮次结束原因。 +加载时只保留最后一个已完成的轮次。后端仍然容忍并截断撕裂的最终记录,但如果解析出的持久前缀止于一个打开的 `turn/start` 之后,规范的修复方式是丢弃上一个 `turn/end` 之后的所有事件。不合成 `tool/result`,不合成 `step/end`,不追加 `turn/end { interrupted }`,也不引入 `interrupted` 轮次结束原因。 -这使持久化的轮次边界变得简单:一个已完成的 `turn/end` 就是检查点。最后一个检查点之后的内容都是崩溃尾部。下一次提示词从最后一个已知合法的提供方 transcript 恢复,而非从部分重建的末尾轮次恢复。 +这使持久化的轮次边界变得简单:一个已完成的 `turn/end` 就是检查点。最后一个检查点之后的内容都是崩溃尾部。下一次 prompt 从最后一个已知合法的 provider transcript(文本记录)恢复,而不是从部分重建的最终轮次恢复。 ## 验收标准 - `TurnEndReasonMap` 移除 `interrupted` 变体。 -- `interruptedTurnClosers()` 及其测试消失。 -- 持久化协调器的修复钩子截断后端特定的撕裂/未关闭尾部状态,不追加关闭事件。 -- [会话持久化文档](../../../../packages/session-persistence/session-persistence/README.md)说明加载返回到最后一个已完成轮次,不包含部分末尾轮次。 -- 快照测试与契约测试随其所固定的行为一起更新。 -- 会话格式版本与已记录的 fixture(测试前置数据)一并刷新;按预发布格式策略,非当前版本的存储日志被拒绝,不提供迁移路径。 +- `interruptedTurnClosers()` 及其测试删除。 +- 持久化协调器的修复钩子截断后端特有的撕裂/打开尾部状态,不追加关闭事件。 +- [会话持久化文档](../../../../packages/session-persistence/session-persistence/README.md)说明加载返回最后一个已完成的轮次,不包含部分最终轮次。 +- 快照与契约测试随其所固定的行为一同更新。 +- 会话格式版本与记录的 fixture(测试前置数据)刷新;按预发布格式策略,非当前版本的存储日志被拒绝,不提供迁移路径。 -## 放弃了什么 +## 放弃的内容 -一次崩溃可能丢失末尾轮次中的真实工作:上一个 `turn/end` 之后追加的助手文本、工具调用和工具输出。这是有意为之的简化。产品尚未发布,末尾轮次恢复的语义未经用户验证,而一个干净的「已完成轮次即检查点」模型在解释、测试和实现上都容易得多。未来如果需要「恢复部分崩溃工作」功能,应当设计为一个面向用户的显式恢复视图,而非静默插入规范 transcript 的合成事件。 +崩溃可能丢失最终轮次中的真实工作:上一个 `turn/end` 之后追加的助手文本、工具调用和工具输出。这是有意为之的简化。产品尚未发布,最终轮次恢复的语义未经用户验证,而一个干净的「已完成轮次即检查点」模型在解释、测试和实现上都容易得多。未来若需「恢复部分崩溃工作」功能,应设计为面向用户的显式恢复视图,而非静默插入规范 transcript 的合成事件。 ## 相关 -本 RFC 是对[会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md)和[轮次封闭不变式](../../implemented/architecture/2026-06-15-turn-enclosure-invariant.md)的直接简化。它还移除了持久化步骤边界事件的大部分动机,使 [drop durable step boundary events](2026-06-20-drop-durable-step-boundaries.md) 的变更范围更小。 +本提案是对[会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md)与[轮次封闭不变式](../../implemented/architecture/2026-06-15-turn-enclosure-invariant.md)的直接简化。它还移除了持久化 step 边界事件的大部分动机,使[移除持久化 step 边界事件](2026-06-20-drop-durable-step-boundaries.md)的改动更小。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml index c61b774371..915d56d0e8 100644 --- a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-04-prune-unimplemented-subagent-vocabulary.md: 3c86f11564d85b423fe59d784c6bf69959fb3907 -2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: ad8c8541ca682be6e71b6fe4ae166c3b65d14cdf +2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: 84ff6f15ff2c9b3a13240997ab3c7b5cf2ab7263 diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md index ad8c8541ca..84ff6f15ff 100644 --- a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md @@ -1,39 +1,39 @@ -# RFC:裁剪 subagent seam 中未实现的词汇 - -Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below stands as the record of what is currently unimplemented. +# RFC:裁剪未实现的 subagent seam 词汇 [English](2026-07-04-prune-unimplemented-subagent-vocabulary.md) | 中文 +Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below stands as the record of what is currently unimplemented. + ## 问题 -[subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 交付了一套两层能力设计:由服务在启动时检查的能力 flag,以及 `SubagentRun` 上的可选运行时方法。三项启动时特性和两个可选运行时方法均无实现、无调用方: +[subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 交付了一套两层能力设计:启动时由服务检查的能力 flag,以及 `SubagentRun` 上的可选运行时方法。三个启动时特性和两个可选运行时方法的实现数与调用数均为零: -- **`outputSchema`/`structured` 与 `toolFilter`**(`SubagentCapabilities`、`SubagentStartRequest`、`SubagentResult`,位于 `packages/subagent/subagent/src/types.ts`):每个真实提供方都声明 `outputSchema: false, toolFilter: false`(`packages/subagent/subagent-spawn/src/index.ts`、`packages/subagent/subagent-fork/src/index.ts`、`packages/subagent/subagent-acp/src/index.ts`);唯一的生产环境 `ctx.subagents.start` 调用方(`packages/subagent/tool-subagent/src/index.ts`)构建 `{ prompt, parent, signal?, agentOptions? }`,结构上无法设置这两项;`structured` 仅由测试 mock(`packages/support/subagent-mock`)为其自身 spec 产出。服务的能力检查包含两行 assert,唯一的执行者是拒绝测试。 -- **`SubagentRun.sendMessage` / `SubagentRun.resume`**(同一文件):没有任何提供方实现——连 mock 也没有;spawn spec 断言的是它们的*缺席*。 +- **`outputSchema`/`structured` 与 `toolFilter`**(`SubagentCapabilities`、`SubagentStartRequest`、`SubagentResult`,位于 `packages/subagent/subagent/src/types.ts`):每个真实提供方都声明 `outputSchema: false, toolFilter: false`(`packages/subagent/subagent-spawn/src/index.ts`、`packages/subagent/subagent-fork/src/index.ts`、`packages/subagent/subagent-acp/src/index.ts`);唯一的生产环境 `ctx.subagents.start` 调用方(`packages/subagent/tool-subagent/src/index.ts`)构造 `{ prompt, parent, signal?, agentOptions? }`,结构上无法设置这两个字段;`structured` 仅由测试 mock(`packages/support/subagent-mock`)为其自身 spec 产出。服务的能力检查包含两行 assert,其唯一执行者是拒绝测试。 +- **`SubagentRun.sendMessage` / `SubagentRun.resume`**(同一文件):没有任何提供方实现——包括 mock 也没有;spawn spec 断言的正是它们的*缺失*。 -`dsh-subagent` 依赖 `dsh-tools` 的唯一原因是 `outputSchema` 的 `SchemaSpec` 类型。三个后续 subagent 工作流(per-session 快照回放、fork seed 边界、ACP 后端)都围绕这块表面落地,却没有增长出哪怕一个消费方。 +`dsh-subagent` 依赖 `dsh-tools` 的唯一原因是 `outputSchema` 的 `SchemaSpec` 类型。三个后续 subagent 工作流(per-session 快照回放、fork seed 边界、ACP(Agent Client Protocol) 后端)都围绕这块接口面落地,却没有增长出哪怕一个消费方。 ## 提案 -从 seam 中移除 `outputSchema`/`structured`、`toolFilter`、`sendMessage` 和 `resume`;将 `SubagentCapabilities` 缩减为 `{ depthLimit }`;删除两行能力 assert、三个提供方上的 all-false flag、mock 的 structured 分支及其 `capabilities`/`structured` 配置旋钮,以及为固定被移除表面而存在的测试(两行拒绝测试、spawn 缺席测试、mock structured spec)。从 `packages/subagent/subagent/package.json` 中删除 `dsh-tools` 的 peer/dev 依赖。更新 [subagent.md](../../../core-data-structures/subagent.md) 中的粘贴内容与 type-equiv manifest,以及 `packages/subagent/subagent`、`packages/subagent/subagent-spawn`、`packages/subagent/subagent-fork` 和 `packages/support/subagent-mock` 的 README 相关行。实现 PR 按 [implemented/AGENTS.md](../../implemented/AGENTS.md) 修订 seam RFC 的能力目录。 +从 seam 中移除 `outputSchema`/`structured`、`toolFilter`、`sendMessage` 与 `resume`;将 `SubagentCapabilities` 缩减为 `{ depthLimit }`;删除两行能力 assert、三个提供方上的 all-false flag、mock 的 structured 分支及其 `capabilities`/`structured` 配置项,以及为固定被移除接口面而存在的测试(两行拒绝测试、spawn 缺失测试、mock structured spec)。从 `packages/subagent/subagent/package.json` 中删除 `dsh-tools` 的 peer/dev 依赖。更新 [subagent.md](../../../core-data-structures/subagent.md) 中的粘贴内容与 type-equiv manifest(元数据清单),以及 `packages/subagent/subagent`、`packages/subagent/subagent-spawn`、`packages/subagent/subagent-fork` 和 `packages/support/subagent-mock` 的 README 相关行。实现 PR(Pull Request)按照 [implemented/AGENTS.md](../../implemented/AGENTS.md) 修订 seam RFC 的能力目录。 -**保留** `depthLimit`/`maxDepth` 与能力检查。进程内后端强制执行该限制,尽管当前发布的工具尚未设置它。递归是已知的 seam 风险,因此恰当的后续工作是补上工具默认值,而非删除正在工作的强制逻辑。 +**保留** `depthLimit`/`maxDepth` 与能力检查。进程内后端已强制执行该限制,尽管当前发布的 tool 尚未设置它。递归是已知的 seam 风险,因此恰当的后续工作是提供一个 tool 默认值,而非删除正在工作的强制逻辑。 -审视过但有意不动的相邻表面:`SubagentService.getProvider()`/`list()` 只有测试 harness 消费方,但 [prune-dead-seam-methods 实现说明](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md) 记录了完全相同的形态曾从 bash executor 中移除后又被回退——测试 harness 对于一个在已跟踪 map 上的单行访问器而言就是消费方。`SubagentRunEndInfo.lastAssistantMessage` 是一个已记录的保留项([subagent-observe-enrich RFC](../../implemented/feature/2026-06-30-subagent-observe-enrich.md) 的评审删除了 `agentType` 但有意保留了它,因为它是进程外子 agent 唯一的最终消息通道);它当前未接通的桥接转发是一个待弥合的缺口或待记录的消费方,不是本 RFC 要裁剪的表面。 +审视过但有意不动的相邻接口面:`SubagentService.getProvider()`/`list()` 仅有测试 harness 消费方,但 [prune-dead-seam-methods 实现说明](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md) 恰好记录了这种形态从 bash executor 中被移除后又被回退的经过——对于一个基于已跟踪 map 的单行访问器而言,测试 harness 就是消费方。`SubagentRunEndInfo.lastAssistantMessage` 是一个已记录的保留项([subagent-observe-enrich RFC](../../implemented/feature/2026-06-30-subagent-observe-enrich.md) 的评审删除了 `agentType` 但有意保留了它,因为它是进程外子 agent(智能体)唯一的最终消息通道);它当前未接通的桥接转发是一个待补的缺口或待记录的消费方,不是本 RFC 要裁剪的接口面。 -这是 [从持久化 seam 裁剪死方法](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md) 在 seam 词汇层面的回声:每个实现都必须为无人声明的成员——甚至更弱,因为这里连一个实现都不存在。 +这是[从持久化 seam 裁剪死方法](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md)在 seam 词汇层面的回响:每个实现都必须为无人声明的成员,甚至更弱,因为这里连一个实现都没有。 ## 曾考虑的替代方案 ### 为什么不保留? -两类能力的设计是 seam RFC 的核心亮点,日后重新添加 `outputSchema` 会涉及多个文件。但该设计以 `depthLimit` 作为活跃示例、以 RFC 作为记录仍然成立;而且 seam RFC 本身承认已交付的 `toolFilter` 形态是错的(真正的强制需要在子 agent 的上下文中设置 `tools/pre-execute` deny,而非 schema 过滤)——该 deny 原语已存在于拦截 seam 上,因此面向真实实现提供方重新添加时,将固定一份比当前推测性契约更好的契约。 +两类能力的设计是 seam RFC 的核心亮点,日后重新添加 `outputSchema` 会涉及多个文件。但该设计以 `depthLimit` 作为活跃示例、以 RFC 作为记录仍然成立;而且 seam RFC 本身承认已交付的 `toolFilter` 形态是错误的(真正的强制需要在子 agent 上下文中实施 `tools/pre-execute` deny,而非 schema 过滤)——该 deny 原语已存在于拦截 seam 上,因此基于真实实现提供方重新添加时,将固定出一份比当前推测性契约更好的契约。 ## 验收标准 -- 被移除的拼写仅出现在本 RFC 和修订后的 seam RFC 中;`SubagentCapabilities` 为 `{ depthLimit: boolean }`;`dsh-tools` 依赖边已消除(`hygiene` 绿)。 -- 深度强制测试不变且绿。 +- 被移除的拼写仅出现在本 RFC 和修订后的 seam RFC 中;`SubagentCapabilities` 为 `{ depthLimit: boolean }`;`dsh-tools` 依赖边已消除(`hygiene` 绿色)。 +- 深度强制测试不变且绿色。 ## 风险 -subagent 生命周期事件在结束载荷上携带 `lastAssistantMessage`——该增强位于服务模块中,不在本 RFC 缩减的 seam 词汇范围内;observe-enrich RFC 记录了因缺乏消费方而删除 `agentType` 兄弟字段的判断:本 RFC 延续的正是这一判断。CC hooks 桥接是这些生命周期事件的第一个外部消费方,它只读取事件载荷,不触及本文移除的任何表面;observe-enrich RFC 中延期的控制流重设计将实现 `resume` 列为自身的未来工作——恰好是本 RFC 模式所预期的重新添加触发点。 +subagent 生命周期事件在结束载荷上携带 `lastAssistantMessage`——该增强位于服务模块中,不在本 RFC 缩减的 seam 词汇范围内;observe-enrich RFC 记录了因缺少消费方而删除 `agentType` 兄弟字段的判断,本 RFC 延续了这一判断。CC hooks 桥接是这些生命周期事件的第一个外部消费方,它只读取事件载荷,不涉及本文移除的任何接口面;observe-enrich RFC 推迟的控制流重设计将实现 `resume` 列为自身的未来工作——恰好是本 RFC 模式所预期的重新添加触发点。 diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml index 96bb401556..98bc1e4bab 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-12-collapse-workflow-to-foreground-core.md: 78b67c10ac39fddaf4ea76ca90d5cbf760fe5866 -2026-07-12-collapse-workflow-to-foreground-core.zh.md: 567da63e86b24dbedfd6fb50da0984c9866bd9cb +2026-07-12-collapse-workflow-to-foreground-core.zh.md: 28b0af0a70110d39572fafac521a555c62ebb3f5 diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md index 567da63e86..28b0af0a70 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md @@ -1,39 +1,39 @@ -# RFC:将工作流收缩至实际使用的前台核心 - -Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it. +# RFC:将工作流收缩至已使用的前台核心 [English](2026-07-12-collapse-workflow-to-foreground-core.md) | 中文 +Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it. + ## 问题 -工作流能力执行前台 JavaScript 来编排 subagent,但它同时携带了一套无人消费的进度观测系统。没有任何生产环境的监听器订阅六个 `workflow/*` 事件中的任何一个;监听器仅存在于工作流测试中。尽管如此,seam 仍定义了 run/phase/agent outcome 载荷,worker 仍发送 phase/log/agent 生命周期协议消息,host 通过一个 `liveAgents` 配对账本转发它们,引擎维护 run id 的唯一目的就是关联这些通知。 +工作流能力执行前台 JavaScript 来编排 subagent,但它同时携带了一套无人消费的进度观测系统。没有任何生产环境的监听器订阅六个 `workflow/*` 事件中的任何一个;监听器仅存在于工作流测试中。尽管如此,seam 定义了 run/phase/agent outcome 载荷,worker 发送 phase/log/agent 生命周期协议消息,host 通过一个 `liveAgents` 配对账本转发它们,引擎维护 run id 仅仅是为了关联这些通知。 -这套进度词汇不仅未被使用,而且在不重新设计的情况下无法服务于它唯一的具名未来消费方。`WorkflowRunInfo` 包含 `{id, meta}` 但没有父 agent、会话或工具调用标识,而面向模型的工具从不暴露 run id。一个全局 ACP 监听器无法将事件路由到正确的客户端会话。`meta.phases` 从未被查询,`phase(title)` 不会对其做校验,phase 的 `detail`/`model` 和 agent 的 `label`/`phase` 只喂给事件,`whenToUse` 被校验和复制但从未被渲染或用于选择。`phase()` 和 `log()` 仍然跨越 worker 边界,尽管没有接收方。 +这套进度词汇不仅仅是未被使用;它在不经重新设计的情况下也无法服务于其唯一已命名的未来消费方。`WorkflowRunInfo` 包含 `{id, meta}` 但没有父 agent(智能体)、会话或工具调用标识,而面向模型的工具也从不暴露 run id。一个全局 ACP(Agent Client Protocol)监听器无法将事件路由到正确的客户端会话。`meta.phases` 从未被查询,`phase(title)` 不对其做校验,phase 的 `detail`/`model` 和 agent 的 `label`/`phase` 仅供事件消费,`whenToUse` 被校验和复制但从未被渲染或用于选择。`phase()` 和 `log()` 仍然跨越 worker 边界,尽管没有接收方。 -live handle 在观察者消失后仍重复事件时代的数据。`WorkflowRun.id` 没有非事件消费方,而工具读取 `run.meta.name` 只是为了渲染一个它已经以 `args.meta.name` 形式持有的值;两者都不属于执行/取消 handle。 +live handle 在观测者消失后仍重复事件时代的数据。`WorkflowRun.id` 没有非事件消费方,而工具读取 `run.meta.name` 只是为了渲染一个它已经以 `args.meta.name` 形式持有的值;两者都不属于执行/取消 handle。 -取消也为一个同步启动提供了两条公开通道。`WorkflowStartRequest.signal` 被传给 worker host,而唯一的生产调用方另外将同一个 signal 桥接到 `WorkflowRun.cancel()`。因为 `start()` 在控制权让出之前就返回了 run,不存在需要请求时取消的就绪窗口;重复的 signal 增加了 host 的 listener/disarm 状态却没有消除任何竞态。 +取消机制也为一个同步启动提供了两条公开通道。`WorkflowStartRequest.signal` 被传递给 worker host,而唯一的生产调用方另外将同一个 signal 桥接到 `WorkflowRun.cancel()`。因为 `start()` 在控制权让出之前就返回了 run,不存在需要请求时取消的就绪窗口;重复的 signal 增加了 host 的 listener/disarm 状态却没有封堵任何竞态。 -`WorkflowError.fatal` 是同类投机分支的微缩版:每个生产环境的构造都是 fatal 的,`fatal: false` 仅存在于测试中,组合子已经通过 `instanceof` 区分工作流失败。 +`WorkflowError.fatal` 是同一种推测性分支的微缩版:所有生产环境的构造都是 fatal 的,`fatal: false` 仅存在于测试中,组合子已经通过 `instanceof` 区分工作流失败。 ## 提案 -保留实际使用的核心:`agent(prompt, { schema, model })`、`parallel`、`pipeline`、`args`、并发/agent 上限、取消、有界 dispose、结构化结果、worker 隔离,以及前台工具收集。移除所有 `workflow/*` 事件及其仅服务于事件的 info/outcome 类型;移除 `phase()`、`log()`、agent 的 `label`/`phase`、phase 声明、`whenToUse` 及其 worker 消息/host 观察者;将工作流元数据收缩为工具实际使用的 name;移除仅服务于事件的 run id/meta 快照以及合成的 agent-end 账本。将 `WorkflowRun` 收缩为 `result`、`cancel()` 和 `dispose()`;工具渲染请求方持有的 name。移除 `WorkflowStartRequest.signal` 及 worker host 的 input-signal listener/disarm 状态,保留调用方从自身 abort signal 到 `run.cancel()` 的桥接。将 `WorkflowError` 变为单一的 fatal 错误类,不再有布尔模式或 `isFatalWorkflowError()` 辅助函数。 +保留已使用的核心:`agent(prompt, { schema, model })`、`parallel`、`pipeline`、`args`、并发/agent 上限、取消、有界 dispose(资源释放)、结构化结果、worker 隔离与前台工具收集。移除所有 `workflow/*` 事件及其仅供事件使用的 info/outcome 类型;移除 `phase()`、`log()`、agent 的 `label`/`phase`、phase 声明、`whenToUse` 及其 worker 消息/host 观测者;将工作流元数据收缩为工具实际使用的 name;移除仅供事件使用的 run id/meta 快照与合成的 agent-end 账本。将 `WorkflowRun` 收缩为 `result`、`cancel()` 和 `dispose()`;工具渲染请求方持有的 name。移除 `WorkflowStartRequest.signal` 及 worker host 的 input-signal listener/disarm 状态,保留调用方从其 abort signal 到 `run.cancel()` 的桥接。将 `WorkflowError` 变为单一的 fatal 错误类,不再有布尔模式或 `isFatalWorkflowError()` 辅助函数。 -修订已实施的动态工作流 RFC,并更新 seam/tool/worker README、工具 schema、生成的 catalog 与包依赖图、worker type-equiv 记录、单元测试,以及工作流快照/header fixture。如果未来委托进度 UI 工作,应从一份命名了父 agent/会话/工具调用的关联契约出发,而非原样复活此协议。 +修订已实施的 dynamic-workflow RFC,并更新 seam/tool/worker README、工具 schema、生成的 catalog 与 package 依赖图、worker type-equiv 记录、单元测试以及工作流快照/header fixture(测试前置数据)。如果进度 UI 工作被立项,应从一份命名了父 agent/会话/工具调用的关联契约出发,而非原样复活这套协议。 ## 曾考虑的替代方案 -**为未来 UI 保留预建的观测词汇。** 当前形状类似 Claude Code 的动态工作流元数据,host 有意地将每个转发的 agent start 与 worker 的 end 或合成的终端 end 配对。移除它意味着放弃形状兼容性,使进度 UI 成为一项全新的设计任务;但现有载荷仍然缺少可路由的归属信息,因此仅靠平衡的生命周期也无法在不重新设计的情况下让具名的 ACP 消费方可行。 +**为未来 UI 保留预建的观测词汇。** 当前形态类似 Claude Code 的 dynamic-workflow 元数据,host 有意地将每个转发的 agent start 与 worker 的 end 或一个合成的终止 end 配对。移除它意味着放弃形态兼容性,使进度 UI 成为一项全新的设计任务;但现有载荷仍缺少可路由的归属信息,因此仅靠平衡的生命周期也无法在不重新设计的情况下让已命名的 ACP 消费方可行。 ## 验收标准 - 工作流公开 seam 仅包含有生产消费方的执行、取消、结果与 dispose 契约。 -- 不再保留任何工作流事件、phase/log 协议消息、run-id 生成器、仅服务于进度的元数据、host 配对账本或 fatal 模式分支。 +- 不再保留任何工作流事件、phase/log 协议消息、run-id 生成器、仅供进度使用的元数据、host 配对账本或 fatal 模式分支。 - run handle 不再有 id/meta 回显,取消在同步 `start()` 返回后只有一条持有者拥有的通道。 -- parallel/pipeline 行为、上限、取消静默、worker 隔离、结构化输出以及面向模型的工作流场景保持覆盖率。 +- parallel/pipeline 行为、上限、取消静默、worker 隔离、结构化输出与面向模型的工作流场景保持测试覆盖。 - 类型检查、覆盖率、快照、doc-sync、module-graph 校验、构建与 hygiene 全部通过。 ## 风险 -这是对工作流 DSL、事件分类体系、handle 与 start request 的编译可见收缩。现有提供描述性元数据的工作流调用,以及使用 `phase`、`log` 或 label 的脚本,必须相应精简;程序化调用方需自行将 abort 源桥接到返回的 handle;未来的观察者必须添加一个关联性更好的 seam。使工作流真正有用的执行语义不变。 +这是对工作流 DSL、事件分类体系、handle 与 start request 的编译可见收缩。现有提供描述性元数据的工作流调用,以及使用 `phase`、`log` 或 label 的脚本,都必须相应精简;程序化调用方需自行将 abort source 桥接到返回的 handle;未来的观测者必须添加一个关联性更好的 seam。使工作流有用的执行语义不变。 diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml index 1fb7c5343a..a9c24674bf 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 2026-07-12-prune-unused-skill-registry-surface.md: 3e8c009871c3d609612b4a01edc2048ddedfad0d -2026-07-12-prune-unused-skill-registry-surface.zh.md: 1412e3cfac1adbb8b563ad50edb08c53a719feb8 +2026-07-12-prune-unused-skill-registry-surface.zh.md: deaea2ca53d4ed2ac5141013f969f621d3202875 diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md index 1412e3cfac..deaea2ca53 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md @@ -1,29 +1,29 @@ -# RFC:裁剪未使用的 skill 注册表接口 - -Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins. +# RFC:裁剪 skill 注册表中未使用的接口 [English](2026-07-12-prune-unused-skill-registry-surface.md) | 中文 +Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins. + ## 问题 -skill 服务的嵌入式运行时子系统没有任何生产调用方调用 `ctx.skills.register()`。它引入了一个保留的 `runtime` 提供方名称、一套运行时 map/rank/source、重复策略、缓存键中的第二个 revision、规范化逻辑、dispose 函数和测试,而这些都与每个已交付 skill 实际使用的提供方 seam 并行存在。`SkillSummary.whenToUse` 以及 candidate/definition 上的 `path` 被解析和复制,但没有任何生产消费方读取它们:模型目录只渲染 name/description,资源加载使用 `resourceBase`,提供方自行管理其定位符。刻意开放的 `metadata` 扩展点保留不动。 +skill(技能)服务的嵌入式运行时子系统中,`ctx.skills.register()` 没有任何生产调用方。它引入了一个保留的 `runtime` 提供方名称、一套运行时 map/rank/source、重复策略、缓存键中的第二个 revision、规范化逻辑、dispose(资源释放)器以及相应测试——而所有已交付的 skill 都只使用提供方 seam。`SkillSummary.whenToUse` 和 candidate/definition 的 `path` 被解析和复制,但没有任何生产消费方读取它们:模型目录只渲染 name/description,资源加载使用 `resourceBase`,提供方自行管理其定位器。有意开放的 `metadata` 扩展点保留不动。 ## 提案 -移除 `SkillService.register()`、`SkillRegistration`、运行时伪提供方及保留名称规则、运行时 revision/缓存分支,以及仅用于运行时的 source/rank 规范化逻辑。需要嵌入式 skill 的测试改为注册一个小型真实提供方。保留 `providerRevision` 作为进行中的发现纪元,但已完成的目录仅以 cwd 为键:每次提供方变更都同步清除缓存,await 之后的 revision 比较已能阻止插入陈旧结果。从 skill 契约和本地提供方副本中移除 `whenToUse`、`SkillCandidate.path` 和 `SkillDefinition.path`,同时保留提供方的 locator/root 路径;保留 `metadata`、`disableModelInvocation`、`source`、`provider`、`locator` 和 `resourceBase`,它们要么是刻意的扩展词汇,要么是生产中被消费的字段。 +移除 `SkillService.register()`、`SkillRegistration`、运行时伪提供方及保留名称规则、运行时 revision/缓存分支,以及仅用于运行时的 source/rank 规范化逻辑。需要嵌入式 skill 的测试改为注册一个小型真实提供方。保留 `providerRevision` 作为进行中的发现 epoch,但已完成的目录缓存仅以 cwd 为键:每次提供方变更同步清除缓存,await 之后的 revision 比较已能阻止插入陈旧结果。从 skill 契约和 local-provider 副本中移除 `whenToUse`、`SkillCandidate.path` 与 `SkillDefinition.path`,同时保留提供方的 locator/root 路径;保留 `metadata`、`disableModelInvocation`、`source`、`provider`、`locator` 和 `resourceBase`,因为它们要么是有意开放的扩展词汇,要么是生产消费的字段。 -同步修订 skill 系统 RFC、README、JSDoc、目录文件和测试。agent 作用域的系统提示词段落、工具提供方和变量明确不在本提案范围内:[agent 作用域贡献者契约](../../implemented/architecture/2026-07-08-agent-scope-contexts.md)有意允许在 `setup(agentCtx)` 期间通过 agent 拥有的上下文注册这三者,因此仓库内没有固定的作用域注册并不能证明无人消费。 +同步修订 skill 系统 RFC、README、JSDoc、目录文件与测试。agent(智能体)作用域的系统提示词段、工具提供方和变量明确不在本提案范围内:[agent 作用域贡献者契约](../../implemented/architecture/2026-07-08-agent-scope-contexts.md)有意允许在 `setup(agentCtx)` 期间通过 agent 拥有的上下文注册这三者,因此仓库内没有固定的作用域注册并不能证明它们未被使用。 ## 曾考虑的替代方案 -**为嵌入方保留运行时 skill 注册。** 这是已实现的 skill RFC 中一个刻意设计的同步直接定义便利接口。一个小型提供方包装层可以在 effect 拥有的生命周期下暴露相同的嵌入数据,但它必须实现异步 `list()`/`get()`、携带提供方身份、并接受提供方的重复语义。本提案选择保留一条统一的提供方路径,而非维护第二套排序、校验、缓存失效和查找路径。 +**保留面向嵌入方的运行时 skill 注册。** 这是已实现的 skill RFC 中有意提供的同步直接定义便利接口。一个小型提供方包装层可以在 effect 拥有的生命周期下暴露相同的嵌入数据,但它必须实现异步 `list()`/`get()`、携带提供方身份,并接受提供方的重复语义。本提案选择只保留一条统一的提供方路径,而非维护第二套排序、校验、缓存失效与查找路径。 ## 验收标准 -- skill 收集只有一条提供方驱动的路径;已完成缓存的键仅为 cwd;revision 纪元仅用于进行中的失效;保留的 skill 字段要么有生产读取方,要么有记录在案的刻意扩展契约。 -- agent 作用域的 prompt 段落、变量、工具提供方、工具守卫,以及原生模式和 Code Mode 下的结构化输出提交行为保持不变。 -- 类型检查、覆盖率、快照、doc-sync、module-graph 校验、构建和 hygiene 全部通过。 +- skill 收集只有一条提供方驱动的路径,已完成缓存仅以 cwd 为键,revision epoch 仅用于进行中的失效检测;保留的 skill 字段要么有生产读取方,要么有记录在案的有意扩展契约。 +- agent 作用域的提示词段、变量、工具提供方、工具守卫,以及原生模式和 Code Mode 下的 structured-output 提交行为保持不变。 +- 类型检查、覆盖率、快照、doc-sync(文档同步门禁)、module-graph 校验、构建与 hygiene 全部通过。 ## 风险 -这是对预发布 skill 注册表的一次编译可见的收缩。外部编程式 `list()`/`get()` 消费方将失去 `whenToUse` 路由提示和 candidate/definition 上的 `path`;已交付的模型目录从未渲染它们,资源解析保留了显式的 `resourceBase` 加上提供方自有的不透明 locator,但这些字段在可观测性上并不等价。skill 本地的 frontmatter 解析必须继续保留并校验所支持的 metadata schema,外部提供方仍可提供嵌入式、文件系统、远程或其他 skill 来源。 +这是对预发布 skill 注册表的编译可见收缩。外部编程式 `list()`/`get()` 消费方将失去 `whenToUse` 路由提示和 candidate/definition 的 `path`;已交付的模型目录从未渲染它们,资源解析保留了显式的 `resourceBase` 加上提供方自有的不透明 locator,但这些字段并非观测等价。skill 本地 frontmatter 解析必须继续保留并校验所支持的 metadata schema,外部提供方仍可提供嵌入式、文件系统、远程或其他 skill 来源。 From 84f752234d246afd604acadd653620f7d6cb5541 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:09:53 +0800 Subject: [PATCH 075/368] test: make LSP canonical fixture cross-platform --- packages/lsp/tool-lsp/tests/tool-lsp.spec.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/lsp/tool-lsp/tests/tool-lsp.spec.ts b/packages/lsp/tool-lsp/tests/tool-lsp.spec.ts index c594bdb525..de7a5319ef 100644 --- a/packages/lsp/tool-lsp/tests/tool-lsp.spec.ts +++ b/packages/lsp/tool-lsp/tests/tool-lsp.spec.ts @@ -130,23 +130,24 @@ describe('tool-lsp execution', () => { }) it('keeps all acquired locations in the canonical value when presentation is capped', async () => { + const cappedWorkspaceRoot = resolve('/virtual/capped-workspace') const locations = [ - { uri: 'file:///ws/a.ts', range: { start: { line: 0, character: 0 }, end: { line: 0, character: 1 } } }, - { uri: 'file:///ws/b.ts', range: { start: { line: 1, character: 2 }, end: { line: 1, character: 3 } } }, + { uri: pathToFileURL(join(cappedWorkspaceRoot, 'a.ts')).href, range: { start: { line: 0, character: 0 }, end: { line: 0, character: 1 } } }, + { uri: pathToFileURL(join(cappedWorkspaceRoot, 'b.ts')).href, range: { start: { line: 1, character: 2 }, end: { line: 1, character: 3 } } }, ] const { ctx } = await mount(stubProvider(() => ({ kind: 'locations', locations, - resolvedWorkspaceRoot: '/ws', + resolvedWorkspaceRoot: cappedWorkspaceRoot, })), { maxLocations: 1 }) - const result = await call(ctx, { operation: 'findReferences', file_path: 'a.ts', line: 1, character: 1 }, '/ws') + const result = await call(ctx, { operation: 'findReferences', file_path: 'a.ts', line: 1, character: 1 }, cappedWorkspaceRoot) expect(result.content[0]).toEqual({ type: 'text', text: 'a.ts:1:1\n… 1 more location omitted (limit 1).', }) expect(result).toMatchObject({ isError: false, - value: { kind: 'locations', locations, resolvedWorkspaceRoot: '/ws' }, + value: { kind: 'locations', locations, resolvedWorkspaceRoot: cappedWorkspaceRoot }, }) }) From 0852d5ab63b0a24ae2ca2edf91792f10377a3322 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:24:36 +0800 Subject: [PATCH 076/368] test: stabilize deep Code Mode worker coverage Give the real-worker binding stress case an explicit CI budget and keep the forged-completion program pending so bootstrap cannot publish a competing normal completion. --- .../code-runtime/code-runtime-worker/tests/runtime.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index c4dfefff91..bae0c3d4a6 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -92,7 +92,7 @@ describe('WorkerCodeRuntime — programs and bindings (real workers)', () => { cursor = Array.isArray(cursor) ? cursor[0] : undefined } expect(cursor).toBe('leaf') - }) + }, 15_000) it('reports non-erasable syntax as an exception without spawning a worker', async () => { const { runtime } = await setup() @@ -484,7 +484,9 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { const { parentPort } = await import('node:worker_threads'); let value = null; for (let depth = 0; depth < 3_000; depth++) value = [value]; - parentPort.postMessage({ type: 'done', value }); + setTimeout(() => { parentPort.postMessage({ type: 'done', value }) }, 25); + // Prevent bootstrap's normal undefined completion from racing the forged terminal. + await new Promise(() => {}); `, bindings: [], }) From 5fe5a6bc78088c818e8854b036e563745e94154f Mon Sep 17 00:00:00 2001 From: Turtle <turtle1999@deepseek.com> Date: Wed, 22 Jul 2026 18:30:04 +0800 Subject: [PATCH 077/368] docs(cordis-tutorial): drop 'What belongs in config' section --- docs/cordis-tutorial/05-config.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/cordis-tutorial/05-config.md b/docs/cordis-tutorial/05-config.md index 3716c2d5e5..09aaf8971d 100644 --- a/docs/cordis-tutorial/05-config.md +++ b/docs/cordis-tutorial/05-config.md @@ -65,10 +65,6 @@ ValidationError: invalid config: The plugin's fiber goes to FAILED, and this tutorial's launcher exits with status 1 after printing the error. A plugin should also reject schema-valid config that names an unavailable resource or provider as soon as it can resolve that reference. -## What belongs in config - -The harness convention, useful for any Cordis app: **anything two deployments may want to set differently is a config field**, not a constant in the plugin. Timeouts, model ids, directory roots, thresholds — the test is whether `cordis.yml` can change the value without a code edit. Compare `timeoutMs` on [`dsh-bash-local`](../../packages/bash/bash-local/src/index.ts) in the [headless example](../../examples/headless-agent/cordis.yml). - ## Computed config values The loader used in this repo supports a `!!js` tag for config values that must be computed at load time, such as reading an API key from the environment: From 2cbb7848a76c9deda97fbb1fb8d90075fe5d8190 Mon Sep 17 00:00:00 2001 From: Turtle <turtle1999@deepseek.com> Date: Wed, 22 Jul 2026 18:37:13 +0800 Subject: [PATCH 078/368] docs(cordis-tutorial): trim API-key aside from full-agent pointer --- docs/cordis-tutorial/07-into-the-harness.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cordis-tutorial/07-into-the-harness.md b/docs/cordis-tutorial/07-into-the-harness.md index 8b3f8dc893..d25419afd5 100644 --- a/docs/cordis-tutorial/07-into-the-harness.md +++ b/docs/cordis-tutorial/07-into-the-harness.md @@ -89,7 +89,7 @@ The logger fired first: `tools/result` is emitted as part of result materializat ## From here to a full agent -A real agent is this composition plus more plugins: an LLM adapter, the agent loop, persistence, a front end. Compare [examples/headless-agent/cordis.yml](../../examples/headless-agent/cordis.yml) — you can read every entry in it now. Add your `greet-tool.ts` to a copy of that file and, with a `DEEPSEEK_API_KEY` in the root `.env`, the model can actually call your tool. +A real agent is this composition plus more plugins: an LLM adapter, the agent loop, persistence, a front end. Compare [examples/headless-agent/cordis.yml](../../examples/headless-agent/cordis.yml) — you can read every entry in it now. Add your `greet-tool.ts` to a copy of that file. Where to go next: From d6f478488d068f76a064f4130a1604d3e65f8410 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:40:24 +0800 Subject: [PATCH 079/368] test: allow deep worker checks under Windows coverage --- .../code-runtime/code-runtime-worker/tests/runtime.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index bae0c3d4a6..ff630e51f1 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -92,7 +92,7 @@ describe('WorkerCodeRuntime — programs and bindings (real workers)', () => { cursor = Array.isArray(cursor) ? cursor[0] : undefined } expect(cursor).toBe('leaf') - }, 15_000) + }, 60_000) it('reports non-erasable syntax as an exception without spawning a worker', async () => { const { runtime } = await setup() @@ -500,7 +500,7 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { } expect(depth).toBe(3_000) expect(value).toBeNull() - }) + }, 60_000) it('turns forged over-limit error text into output-limit at the host', async () => { const { runtime } = await setup({ maxOutputBytes: 64 }) From 6599acdee88acdafb5f25e30c953d4ef35d7e2da Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Wed, 22 Jul 2026 03:40:46 -0700 Subject: [PATCH 080/368] docs(i18n): add the core.md pair (long-doc lane, v4 pipeline) --- docs/core-data-structures/core.i18n.yaml | 6 + docs/core-data-structures/core.md | 2 + docs/core-data-structures/core.zh.md | 403 ++++++++++++++++++++++ scripts/translation-pairing.manifest.json | 1 + 4 files changed, 412 insertions(+) create mode 100644 docs/core-data-structures/core.i18n.yaml create mode 100644 docs/core-data-structures/core.zh.md diff --git a/docs/core-data-structures/core.i18n.yaml b/docs/core-data-structures/core.i18n.yaml new file mode 100644 index 0000000000..8017a93ecd --- /dev/null +++ b/docs/core-data-structures/core.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +core.md: 7ace373ae549b86f21151610719940100d6348d0 +core.zh.md: d6467c12e1d64624357fcb8b37688b484bc23b0c diff --git a/docs/core-data-structures/core.md b/docs/core-data-structures/core.md index 8926a8a998..7ace373ae5 100644 --- a/docs/core-data-structures/core.md +++ b/docs/core-data-structures/core.md @@ -1,5 +1,7 @@ # Core Data Structures +English | [中文](core.zh.md) + This folder catalogs the **data structures** of the DeepSeek Harness — what each core type represents, its literal shape, and where the full detail lives. It complements [architecture.md](../architecture.md), which describes *behavior* (the service map, the session/turn/step lifecycle, the event taxonomy); this page describes the *vocabulary* that behavior moves around. ## What counts as "core" diff --git a/docs/core-data-structures/core.zh.md b/docs/core-data-structures/core.zh.md new file mode 100644 index 0000000000..d6467c12e1 --- /dev/null +++ b/docs/core-data-structures/core.zh.md @@ -0,0 +1,403 @@ +# 核心数据结构 + +[English](core.md) | 中文 + +本目录编目 DeepSeek Harness 的**数据结构**:每个核心类型代表什么、它的字面形状,以及完整细节在哪里。它与 [architecture.md](../architecture.md) 互补——后者描述*行为*(服务映射、会话/轮次/步骤生命周期、事件分类体系);本页描述行为所操作的*词汇*。 + +## 什么算"核心" + +harness 是一个微内核:一个极小的核心加上众多插件。大多数类型属于某一个插件或某一项能力。但有少数类型构成**主干**——agent loop(智能体循环)及其事件在*每一个*轮次中使用的语言,无论加载了哪些可选插件。这些就是"核心"。 + +精确地说,一个数据结构是**核心**的,当且仅当满足以下条件之一: + +1. 它流经 agent loop 主干——循环在每个轮次中持有、派生、流式输出或记录它(`Message`、`StreamChunk`、`SessionEvent`、`Agent` 句柄本身),与当前加载了哪些插件无关;**或者** +2. 它是插件作者面向某条流水线编写的唯一标题类型——`ToolDefinition`(每个工具*是什么*)。 + +其他一切都记录在**子页面**上,而非本页。划线的规则是:*你编写、持有或接收的类型是核心;为它提供类型推导、渲染或持久化的机制是子页面细节。*因此 `ToolDefinition` 是核心,但为它提供类型推导的 `SchemaSpec`/`InferArgs` DSL、为它提供渲染意图的 `ToolCallView`/`ToolResultView` 词汇,以及存储事件日志的 `SessionPersistence` seam 都不是——它们分别在下列子页面中。 + +| 子页面 | 负责内容 | +|---|---| +| [llm-streaming.md](llm-streaming.md) | `StreamChunk` 协议格式(wire format)+ 适配器契约(adapter contract)、`BlockAssembler`、`LlmAdapter` seam | +| [scope.md](scope.md) | 作用域注册标识、dispatch 载体,以及拥有的 `Scope` 上下文 | +| [session.md](session.md) | 完整的 `SessionEventMap` 变体目录、`TurnTrigger`/`TurnEndReason`、`deriveMessages()`、轮次封闭不变式 | +| [persistence.md](persistence.md) | 持久性 seam:`SessionPersistence`、JSONL + SQLite 后端、`session/flush`、崩溃恢复、`SessionHeader` | +| [session-query.md](session-query.md) | 逻辑会话/事件记录与有界精确事件读取 | +| [system-prompt.md](system-prompt.md) | 逐次组装的上下文、工具提供方结果、prompt 段落与协作式组装 | +| [tools.md](tools.md) | `ToolDefinition` 完整字段、schema DSL、`ToolExecution`/`ToolResult`、工具展示 UI 类型,以及受保护的执行流水线 | +| [user-interaction.md](user-interaction.md) | UI 支持的人工问答 seam:`AskUserQuestionRequest`、answer/options 词汇、provider API、错误分类体系 | +| [approval.md](approval.md) | 一次性用户审批 seam:`ApprovalRequest`、`ApprovalOutcome`、逐会话策略、审计与 answerer 契约 | +| [bash.md](bash.md) | bash 执行器 seam:`BashExecRequest`/`Spec`、`BashRunResult`、后台 `BashTask` | +| [sandbox.md](sandbox.md) | 进程隔离 seam:文件效果模式、`SandboxPolicy`、`ConfinedArgv`、强制执行与 fail-closed 错误 | +| [code-runtime.md](code-runtime.md) | 代码执行 seam:`CodeRunRequest`/`Result`、绑定命名空间、捕获日志、`CodeRunFailure` 分类体系 | +| [filesystem.md](filesystem.md) | 文件系统 seam:`FsTarget`、读/写/编辑结果、观测到的文件状态、`FsErrorCode` | +| [skills.md](skills.md) | skill 服务:发现优先级、`SkillSummary`/`SkillDefinition`、会话前缀目录、面向模型的 `skill` 加载 | +| [compaction.md](compaction.md) | 压缩(compaction)seam:`compact/*` 会话事件、`CompactionResult`、`CompactService` 接口 | +| [subagent.md](subagent.md) | subagent seam:命名提供方注册表、`SubagentStartRequest`/`Result`/`Run`、启动时与运行时能力拆分 | +| [web.md](web.md) | Web 访问 seam:`WebSearchRequest`/`Result`、`WebFetchRequest`/`Result`、`WebFetchBody`、provider 可用性、`WebError` | +| [workflow.md](workflow.md) | 工作流 seam:`WorkflowStartRequest`、`WorkflowMeta`、`WorkflowRun`/`Result`、`workflow/*` 事件载荷、`WorkflowError` 致命性 | + +> 本页的类型定义**逐字**粘贴自源码,并由 `pnpm run verify-type-equiv` 进行漂移检查(见 [development.md](../development.md#documenting-types-verbatim-ts-type-equiv))。为可读性省略了行内 JSDoc;完整契约请跟随源码链接查看。 + +FIXME(catalog-verbs): the drift gate covers only the nouns (the pasted type shapes); every method surface on these pages is hand-written prose. core-data-structures should probably also generate the *verbs* — the public methods of the cataloged classes — so a signature change cannot silently outdate the catalog. + +## `…Map → derived-union` 模式 + +harness 中几乎所有可扩展的和类型都遵循同一形状:一个以判别标签为键的接口(`…Map`),联合类型由 `keyof` 派生。插件通过**声明合并**添加变体——无需修改拥有该类型的包。 + +```ts ignore-check +// The pattern, schematically: +interface ThingMap { + 'a': { kind: 'a'; /* … */ } + 'b': { kind: 'b'; /* … */ } +} +type ThingKind = keyof ThingMap // 'a' | 'b' +type Thing = ThingMap[keyof ThingMap] // the discriminated union + +// A plugin extends it without touching the source package: +declare module '@deepseek-ai/dsh-llm' { + interface ThingMap { + 'c': { kind: 'c'; /* … */ } + } +} +``` + +六个规范 map 使用此模式;插件作者扩展它们: + +| Map | 包(package) | 派生 | 目录 | +|---|---|---|---| +| `ContentBlockMap` | dsh-llm | `ContentBlock` | [下文](#content-blocks-and-messages) | +| `MessageSourceMap` | dsh-llm | `MessageSource` | [下文](#content-blocks-and-messages) | +| `FinishReasonMap` | dsh-llm | `FinishReason` | [下文](#the-model-request-and-result) | +| `TurnTriggerMap` | dsh-session | `TurnTrigger` | [session.md](session.md) | +| `TurnEndReasonMap` | dsh-session | `TurnEndReason` | [session.md](session.md) | +| `SessionEventMap` | dsh-session | `SessionEvent` | [session.md](session.md) | + +消费方最常 `switch` 的两个大型判别联合类型是:**`StreamChunk`**(流式协议)和 **`SessionEvent`**(日志条目)。按仓库约定,对标签做 `switch`——不要链式 `if`——这样每个分支都能窄化类型,拼错的标签会编译失败。 + +## 品牌化 ID + +跨包边界的 ID 是**品牌化**的——结构上是字符串,但在类型层面不可互换(`AgentId` 不能传给期望 `CallId` 的地方)。构造通过每个类型专属的工厂函数;比较、日志和 JSON 行为与普通字符串一致。 + +`Branded<B>` 原语位于自己的纯类型包 [dsh-brand](../../packages/util/brand)(无运行时代码,不依赖 harness 包),因此任何包都可以为自己拥有的 ID 品牌化,而无需依赖不相关的能力包(例如 dsh-bash 仅通过 dsh-brand 品牌化 `BashTaskId`/`OwnerToken`,从不引入 dsh-llm)。 + +Source: [`packages/util/brand/src/index.ts`](../../packages/util/brand/src/index.ts) + +```ts type-equiv +type Branded<B extends string> = string & { readonly [BRAND]: B } +``` + +三个核心 ID:`CallId`(关联工具调用与其结果;dsh-llm)、`SessionId`(dsh-session)、`AgentId`(dsh-agent)。每个都是 `Branded<'CallId'>` 等加上同名工厂函数。能力 seam 也品牌化自己的 ID——见 [bash.md](bash.md) 中的 `BashTaskId`/`OwnerToken`。 + +## 内容块与消息 + +一段对话由 `Message` 组成;一条消息是一个类型化**内容块**的数组。块的联合类型从 `ContentBlockMap` 派生。 + +Source: [`packages/llm/llm/src/types.ts`](../../packages/llm/llm/src/types.ts) + +```ts type-equiv +interface ContentBlockMap { + 'text': TextBlock + 'reasoning': ReasoningBlock + 'tool-call': ToolCallBlock + 'tool-result': ToolResultBlock +} +``` + +各块接口(完整字段见源码):`TextBlock`(`text`)、`ReasoningBlock`(thinking,区别于可见文本)、`ToolCallBlock`(`id: CallId`、`name`、原始 JSON `arguments`)、`ToolResultBlock`(`toolCallId`、嵌套 `content: ContentBlock[]`、`isError?`)。`ContentBlock = ContentBlockMap[ContentBlockType]`。核心集仅限于每条交付路径都尊重的块——多模态内容(图像、音频等)没有核心块类型;需要的功能通过可合并扩展的 map 添加,同时提供适配器/UI/压缩支持。 + +`Message` 是角色加块: + +```ts type-equiv +interface Message { + role: 'system' | 'user' | 'assistant' + content: ContentBlock[] +} +``` + +消息来源本身也是一个可合并扩展的和类型: + +```ts type-equiv +interface MessageSourceMap { + user: { kind: 'user' } + plugin: { kind: 'plugin'; plugin: string } +} +``` + +## 流式输出 + +适配器发出原始**分片**协议;循环记录分片(回放保真度),同时将同一批分片送入 `BlockAssembler` 以重建块和消息。`StreamChunk` 是基于 `type` 的封闭判别联合——`block-start`、`text-delta`、`reasoning-delta`、`tool-call-delta`、`block-end`、`usage`、`finish`。 + +完整联合类型、适配器契约(usage-before-finish、原始 JSON 工具参数、两条认可的错误路径)和 `BlockAssembler` 在 **[llm-streaming.md](llm-streaming.md)** 中。 + +## 模型请求 + +一次模型调用是一个完全组装好的 `GenerateOptions`。适配器以原始 `StreamChunk` 流作答;消费方用 `BlockAssembler` 组装它(见 [llm-streaming.md](llm-streaming.md))。 + +Source: [`packages/llm/llm/src/types.ts`](../../packages/llm/llm/src/types.ts) + +```ts type-equiv +interface GenerateOptions { + model: string + /** + * Ordered conversation messages, exactly as the provider sees them (after + * the `system` slot). A loop-built request assembles them as + * `EpochHeader.messagePrefix` + the derived history (dsh-agent-loop); a + * hand-built one-shot passes any list. + */ + messages: Message[] + /** System prompt text (adapters map to the provider's system slot). */ + system?: string + /** Tool schemas (adapters map to the provider's `tools` field). */ + tools?: ToolSchema[] + temperature?: number + maxTokens?: number + /** + * Stop sequences: generation halts as soon as the model produces any one of + * these strings (adapters map to the provider's stop field, e.g. OpenAI + * `stop`). The stop string itself is not included in the output. + */ + stop?: string[] + signal?: AbortSignal + /** + * Session identity stamped by the loop for listener routing. Adapters ignore + * it; replay uses it to keep concurrent parent and child cursors independent. + */ + sessionId?: Branded<'SessionId'> +} +``` + +模型停止生成的原因是一个可合并扩展的结束原因: + +```ts type-equiv +interface FinishReasonMap { + 'stop': { kind: 'stop' } + 'tool-calls': { kind: 'tool-calls' } + 'max-tokens': { kind: 'max-tokens' } + 'aborted': { kind: 'aborted' } + 'error': { kind: 'error'; message: string; code?: string } +} +``` + +`FinishReason = FinishReasonMap[keyof FinishReasonMap]`。`TokenUsage`(逐调用计量,含不相交的缓存字段)详见 [llm-streaming.md](llm-streaming.md)。 + +`GenerateOptions.tools` 携带 `ToolSchema`——工具的 JSON Schema 描述,发送给模型。它声明在 dsh-llm(而非 dsh-tools)中,正是因为它是循环每一步组装请求的一部分: + +```ts type-equiv +interface ToolSchema { + name: string + description: string + /** JSON Schema object for the arguments. */ + parameters: Record<string, unknown> +} +``` + +面向模型的 `ToolSchema` 是协议格式;产出它的已注册 `ToolDefinition`(schema + `execute`)在 [tools.md](tools.md) 中。 + +### 请求信封:`LlmCallConfig` 与记录的 header + +循环从已记录的状态构建每个请求。`EpochHeader` 记录调用配置、渲染后的 prompt、权威的返回工具顺序(由 `toolOrder` 配置,未设置时按字典序)以及会话前缀,通过 `request/header` 快照和 delta 实现。结合派生历史,这使得请求可从会话日志重建。见 [session.md](session.md#the-request-header-events-requestheader-and-requestheader-delta) 和[可重建请求 RFC](../rfc/implemented/architecture/2026-07-05-reconstructable-requests.md)。 + +`agent/request` 接收一个冻结的 call-config 种子,可以返回替换值。`agent/session-prefix` 在每个循环实例中组合一次仅用于请求的前缀消息,header 记录实际使用的确切结果。到达 `llm/stream` 的请求已被深度冻结,因此突变会抛出异常。 + +在协议格式上,循环构建的请求按此顺序读取:`system` 槽位(渲染后的 prompt 组装)→ `messagePrefix`(冻结的会话前缀)→ 派生历史——边界快照,其尾部在轮次首步是最新的 `user/message`,在后续步骤是上一步的工具结果。前缀从不进入派生历史;它的持久记录是 header 事件,开发不变式针对每个循环构建的请求精确重算此等式。 + +FIXME(call-config-shape): revisit the exact definition of this type — which fields are genuinely epoch-level for cache purposes (`model` certainly; the sampling scalars sit here out of caution), and where provider-specific extras (reasoning options, extra body params) belong when an adapter needs them. + +```ts type-equiv +interface LlmCallConfig { + model: string + temperature?: number + maxTokens?: number + stop?: string[] +} +``` + +## 会话 + +`Session` 是一份类型化 `SessionEvent` 的**仅追加日志**——唯一的真源。LLM(大语言模型)消息历史从日志*派生*(`deriveMessages()`),而非单独存储。事件词汇从 `SessionEventMap` 派生: + +Source: [`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) + +```ts type-equiv +type SessionEvent<T extends SessionEventType = SessionEventType> = { + [K in SessionEventType]: { + type: K + /** Monotonic sequence number within the session. */ + seq: number + /** Unix epoch milliseconds. */ + time: number + data: SessionEventMap[K] + } & (K extends SurfaceEventType ? { + /** + * Seq numbers of events that are provenance sources of this event + * (e.g. the `assistant/chunk` seqs that built an `assistant/message`, + * or the surface nodes shadowed by a compaction replace node). + */ + sourceEventSeqs?: number[] + /** How this event entered the surface; absent for non-surface events. */ + surfaceOp?: SurfaceOp + } : object) +}[T] +``` + +十五个事件变体(`turn/start`、`turn/end`、`step/start`、`step/end`、`user/message`、`prompt/blocked`、`context/message`、`assistant/chunk`、`assistant/message`、`tool/call`、`tool/result`、`steering/message`、`todo/write`、`request/header`、`request/header-delta`)、`deriveMessages()` 投影规则、`TurnTrigger`/`TurnEndReason` 原因,以及轮次封闭不变式在 **[session.md](session.md)** 中。日志如何持久化——`SessionPersistence` seam、JSONL/SQLite 后端、`session/flush` 检查点、崩溃恢复和 `SessionHeader`——在 **[persistence.md](persistence.md)** 中。 + +## Agent 句柄 + +`Agent` 是每个插件(UI、钩子、编排器)面向编程的接口。具体实现是 dsh-agent-loop 中的 `ReactLoopAgent`;循环之外没有任何东西依赖该实现。 + +Source: [`packages/core/agent/src/types.ts`](../../packages/core/agent/src/types.ts) + +```ts type-equiv +interface Agent { + readonly id: AgentId + readonly options: AgentOptions + readonly session: Session + readonly status: AgentStatus + + /** + * The agent's scope context (`@deepseek-ai/dsh-scope`, key = this agent): + * registrations through it — tools, prompt sections/variables, listeners, + * restrictions — are visible to this agent only and unwind when it is + * disposed; `agent.ctx.on('agent/…')` listeners fire only for this agent. + */ + readonly ctx: Context + + /** + * Queue a user message. Starts a turn when idle; otherwise waits for the next + * turn. Content and the resolved source are accepted as one detached, + * deeply-frozen lossless-JSON record before notification or enqueue, so + * caller or `agent/queued` listener in-place mutation cannot change later + * log/model input. Throws synchronously when either value is not losslessly + * JSON-serializable; `agent/prompt-submit` may still return an explicit + * replacement. + */ + send(content: ContentBlock[], options?: SendOptions): void + + /** + * Steer a running turn: content is injected between steps of the current + * turn. Uses the same owned-value and synchronous-validation boundary as + * {@link send}; when idle, behaves exactly like that method. + */ + steer(content: ContentBlock[], options?: SendOptions): void + + /** + * Inject in-session context (file-change notices, skill content, cron + * notifications, …): appends a `context/message` session event the next model + * request sees at its chronological position, rendered as tagged synthetic + * context rather than a user prompt. Does not run the model. + * + * Turn-enclosure (the turn-enclosure RFC): an inject while a turn is open joins that turn; + * an inject while idle wraps its `context/message` in a one-shot `injection` + * turn (`turn/start` → `context/message` → `turn/end`) and checkpoints it for + * durability, so every event stays inside a turn and a persistence backend + * never loses a between-turn notice. The idle checkpoint is fire-and-forget + * (inject is synchronous): a failing flush is reported via `agent/error` + * (step `0`) and the logger, never thrown into the caller. + * + * Live-adapter review has validated the tagged-envelope rendering against + * current DeepSeek behavior; provider-specific mismatches belong in that + * adapter, not in the canonical session vocabulary. + */ + inject(content: ContentBlock[], options?: SendOptions): void + + /** + * Cancel ALL pending work for the agent. `cancel()`: + * + * - clears the queued FIFO (un-started prompts never run) and the steering + * FIFO (steering for the cancelled turn is dropped, not re-enqueued); + * - aborts the in-flight step if one is running (the turn ends `aborted`); + * - drops a turn that is about to start (a `cancel()` landing in the + * pre-step window — after a `send()` queued but before the loop flips to + * `running`, or after `running` is emitted but before the first step) so + * that queued prompt does not run and cannot be batched into the cancelled + * turn. + * + * After `cancel()`, `whenIdle()` resolves on the post-cancel quiescent state. + * `cancel()` on an idle agent with nothing queued or running is a safe no-op + * — it does NOT arm anything that would drop a later legitimate prompt. + */ + cancel(reason?: string): void + + /** + * Resolve once the agent has reached quiescence after settling out of + * `running`, or immediately if it is already idle with no queued work. A + * non-owner's quiescence-observation hook: a consumer that does NOT own the + * agent's lifecycle awaits this to proceed only after queued/running work has + * fully stopped, rather than returning while the driver is still streaming or + * about to start a queued turn — without itself tearing the agent down. (A + * lifecycle OWNER does not need it: `AgentHandle.dispose()` already awaits the + * loop-exit promise directly as part of stopping and unregistering. So this is + * for a non-owning observer — e.g. a test awaiting a turn to settle, or a + * monitor — that wants the settle signal but must not dispose the agent.) + * + * "Quiescence", not merely "status changed": a disposed agent emits + * `agent/status('disposed')` from inside its disposer, BEFORE the driver loop + * has unwound — so `whenIdle()` resolving on `disposed` must wait for the loop + * to actually exit (the implementation chains the loop-exit promise), not just + * observe the status flip. A mid-step disposal that never reaches `idle` still + * unblocks the await this way. + */ + whenIdle(): Promise<void> + + // Subagent delegation is realized on top of this interface by the + // `@deepseek-ai/dsh-subagent` seam, not by a method here: a backend creates + // the child through `ctx.agents.create` (fork seeds the child Session with a + // balanced prefix of the parent's log via `CreateAgentOptions.seed`; spawn + // starts fresh) and drives it as an ordinary Agent handle, so steer() and + // event subscription work uniformly. See docs/core-data-structures/subagent.md. +} +``` + +`AgentStatus` 为 `'idle' | 'running' | 'disposed'`,`AgentId` 是品牌化的。`AgentOptions` 可合并扩展,当前包含 `model?`。Persona 属于 `dsh-system-prompt`:agent 作用域的 `deployment:persona` 可以遮蔽全局默认值。 + +[事件分类体系](../architecture.md#event)拥有 `agent/*` 生命周期、检查点和 waterfall(瀑布式事件)契约。轮次和步骤边界是持久的会话事件,而非 agent 发射。 + +## 拦截决策 + +每个 `agent/*` 拦截 waterfall 返回一个小型的、seam 特定的类型化联合——统一的 Decision 惯用法(工具 seam 的 `PreToolDecision`/`PostToolDecision` 在 [tools.md](tools.md) 中遵循相同形状)。CC/Codex 钩子桥将其 `permissionDecision`/`decision`/`continue`/`additionalContext` 字段映射到这些类型上;原生插件直接返回它们。它们共享一个面向模型的上下文信封 `HookContext`,通过 `inject()` 作为 `context/message` 注入,因此携带一个必需的 `source`(缺少 source 会默认为 `{kind:'user'}`,将插件上下文错误标记为用户提示词)。 + +Source: [`packages/core/agent/src/types.ts`](../../packages/core/agent/src/types.ts) + +```ts type-equiv +interface HookContext { + content: ContentBlock[] + source: MessageSource +} +``` + +`agent/prompt-submit` 返回 `PromptDecision`(允许一条已出队的排队消息——可选地重写其 `content` 或附加 `additionalContext`——或阻止它;一个批次中所有 prompt 都被阻止时,会打开一个零步骤轮次并以 `rejected` 结束): + +```ts type-equiv +type PromptDecision = + | { kind: 'allow'; content?: ContentBlock[]; additionalContext?: HookContext } + | { kind: 'block'; reason: string } +``` + +`agent/turn-continuation` 返回 `ContinuationDecision`(循环的默认行为是:当步骤有工具调用或 steering(中途引导)被注入时 `continue`,否则 `stop`;`continue` 的 `reason` 被记录为同一轮次中下一步的 steering——类型化的 `/goal` 模式): + +```ts type-equiv +type ContinuationDecision = + | { action: 'stop' } + | { action: 'continue'; reason?: HookContext } +``` + +`agent/turn-stop` 返回仅停止的 `ContinuationStop` 子集或 `undefined`。循环在折叠普通决策、其 reason 和待处理 steering 之后调用此串行检查点;stop 是终态,会丢弃待处理的 steering。 + +```ts type-equiv +type ContinuationStop = Extract<ContinuationDecision, { action: 'stop' }> +``` + +`agent/session-start` 携带 `SessionStartSource`(会话生命周期为何开始;桥接层据此匹配其 SessionStart): + +```ts type-equiv +type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact' +``` + +`agent/session-prefix` 在每个循环实例中组合一次 `Message[]`。深度冻结的结果被记录在请求 header 中,并前置于每次派生历史,使其成为会话稳定开场白的归属。恢复的实例会重新组合;会话中途的变更使用仅追加的上下文通道。该 waterfall 直接返回内容,因为它是贡献而非决策。 + +## `ToolDefinition` + +唯一属于核心的流水线编写类型:每个已注册工具*是什么*——一个面向模型的 `ToolSchema` 加上一个 `execute` 函数和可选的 UI 展示器。工具作者很少手动构造它(`defineTool` DSL 会用类型化参数构建),但它是注册表持有、循环分发所经过的契约。 + +其完整字段、`defineTool`/`SchemaSpec`/`InferArgs` 类型化 schema DSL、`ToolExecution`/`ToolExecutionResult` waterfall 形状,以及工具展示 UI 词汇在 **[tools.md](tools.md)** 中。 diff --git a/scripts/translation-pairing.manifest.json b/scripts/translation-pairing.manifest.json index be766dbaad..60ceaa876b 100644 --- a/scripts/translation-pairing.manifest.json +++ b/scripts/translation-pairing.manifest.json @@ -14,6 +14,7 @@ "docs/core-data-structures/bash.md", "docs/core-data-structures/code-runtime.md", "docs/core-data-structures/compaction.md", + "docs/core-data-structures/core.md", "docs/core-data-structures/filesystem.md", "docs/core-data-structures/llm-streaming.md", "docs/core-data-structures/persistence.md", From 515d13db7f26d9cd8317612a5c406039ce64f3ab Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Wed, 22 Jul 2026 03:42:25 -0700 Subject: [PATCH 081/368] docs(i18n): add code-mode and web-capability-seam pairs (long-doc lane) --- .../2026-06-24-web-capability-seam.i18n.yaml | 6 + .../2026-06-24-web-capability-seam.md | 2 + .../2026-06-24-web-capability-seam.zh.md | 334 ++++++++++++++++++ scripts/translation-pairing.manifest.json | 1 + 4 files changed, 343 insertions(+) create mode 100644 docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md diff --git a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml new file mode 100644 index 0000000000..7a19846a47 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-06-24-web-capability-seam.md: 3d0cdd89bb8366749ee0b3959244db1c57c0ccaa +2026-06-24-web-capability-seam.zh.md: 1cb1169f99b6eed22bcca650e0b3fe184f331307 diff --git a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md index 2909ccd0e6..3d0cdd89bb 100644 --- a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md +++ b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md @@ -1,5 +1,7 @@ # RFC: Web capability seam - stable tools over multiple providers +English | [中文](2026-06-24-web-capability-seam.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md new file mode 100644 index 0000000000..1cb1169f99 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md @@ -0,0 +1,334 @@ +# RFC:Web 能力 seam——稳定的工具覆盖多个提供方 + +Status: implemented + +[English](2026-06-24-web-capability-seam.md) | 中文 + +## 问题 + +harness 需要面向模型的 web 工具,但不能将模型契约绑定到某一家厂商的 API 形状上。搜索是当前的压力点:从一开始就同时支持 Exa 搜索和 Perplexity 搜索——两种刻意不同的提供方形状(Exa 返回扁平的 `results[]`,每项包含 `{title, url, highlights, publishedDate}`;Perplexity 返回一段生成式回答加引用列表)——正是用来证明归一化的 seam 并非只是镜像某一家厂商。Fetch 是另一项独立能力:匿名公开 HTTP(S) fetch 后端涉及传输、安全、重定向、解码和大小限制等关注点,与提供方支撑的搜索并不相同。 + +面向模型的接口必须保持稳定,而后端可以更换。更换搜索提供方不应改变模型发起查询的方式;更换 fetch 实现不应改变模型请求 URL 的方式。反过来,提供方包也不应仅仅因为自己有额外的提供方特有旋钮就暴露自己的面向模型工具 schema。 + +如果把搜索和 fetch 直接放进 `dsh-tool-web`,面向模型的工具就要同时承担提供方选择、后端请求映射、传输策略、结果归一化、prompt 引导、展示和 schema 注册。让每个提供方注册自己的工具则有相反的问题:工具的可用性、名称、描述和参数将取决于恰好加载了哪些提供方包,提供方特有字段会泄漏到模型契约中。 + +还有一个提供方选择的问题。现有的 `tool-bash` 和 `tool-fs` 可以依赖 Cordis 的 `inject`,因为只有一个后端服务键。Web 有两项独立能力(`search` 和 `fetch`),每项能力可能有多个提供方。`inject: ['web']` 能证明 seam 存在,但不能证明存在可用的搜索或 fetch 提供方,也无法定义多个提供方注册时谁胜出。 + +## 决策 + +Web 访问是一个一等能力 seam,遵循[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md): + +1. `@deepseek-ai/dsh-web`(`packages/web/web`)拥有 `ctx.web`、提供方注册、提供方选择、共享的请求/结果词汇,以及 web 特有的错误。 +2. 提供方包实现具体后端并向 `ctx.web` 注册能力,例如 `@deepseek-ai/dsh-web-search-exa`、`@deepseek-ai/dsh-web-search-perplexity`、`@deepseek-ai/dsh-web-search-deepseek` 和 `@deepseek-ai/dsh-web-fetch-local`。 +3. `@deepseek-ai/dsh-tool-web`(`packages/web/tool-web`)拥有面向模型的 `web_search` 和 `web_fetch` 工具 schema、prompt 段落、参数校验、结果格式化,以及通过 `ctx.web` 实现的工具展示。 + +提供方不注册工具。提供方注册能力。`dsh-tool-web` 是面向模型的名称、描述、prompt 引导、JSON Schema、展示的唯一所有者。 + +搜索和 fetch 是两个独立工具,但属于同一个 web 访问 seam。`ctx.web` 为两个并行注册表统一拥有提供方选择、abort/错误词汇和部署配置。它们的请求 schema 和提供方逻辑保持独立;共享的服务是触达 web 的产品边界。 + +`dsh-tool-web` 在产品启用了相应工具且 `ctx.web` seam 存在时注册面向模型的 web 工具。后端可用性是执行时关注点,而非 schema 注册时关注点: + +- `web_search` 在产品/应用启用了 web 搜索时注册,`web_fetch` 在启用了 web fetch 时注册。 +- 工具绝不会仅仅因为其选定的提供方缺失、配置错误、缺少凭证、存在歧义或暂时不可用就被注销。 +- 提供方在执行时解析,当选定的能力无法运行时返回结构化的 `WebError`。 + +这使模型 schema 保持稳定,而不将插件加载顺序、凭证状态或 HMR(热模块替换)时序纳入面向模型的契约。如果 web 搜索已启用但不存在可用的搜索提供方,`web_search` 仍然可见,执行时以结构化的 `WebError`(如 `WEB_PROVIDER_UNAVAILABLE` 或 `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`)失败。如果某个提供方在 `dsh-tool-web` 之后出现,下一次执行即可使用它而无需更改 schema。如果某个提供方在调用过程中消失,执行以结构化的 `WebError` 失败,而不是静默选择另一个提供方或回退到 `UNKNOWN_TOOL`。 + +该 seam 刻意不暴露任何观察面——没有注册表变更事件,也没有聚合的能力状态查询。不可用性是调用方通过执行观察到的事实:`search()`/`fetch()` 在调用时解析提供方,并抛出命名了失败原因的结构化 `WebError`。[观察面 RFC](../simplification/2026-07-04-drop-unconsumed-web-observation-surface.md) 记录了这一判断:基于调用的派生选择与基于启用的注册使得没有消费方需要变更信号或独立于执行和错误路由的可用性探测;未来的提供方状态面板会重新引入它实际消费的最小信号或查询。 + +## 包拓扑 + +由三个包构成的接口/实现/消费方拆分沿用 bash 和 filesystem 的模式,但*接口*包更接近 LLM(大语言模型) seam。`LlmService`(`packages/llm/llm/src/index.ts`)是一个按名称键控的提供方注册表:`registerAdapter(models, adapter)` 将适配器存入 `Map`、返回 disposer、对重复键抛出 `DUPLICATE_ADAPTER`、在解析时抛出 `NO_ADAPTER`。`ctx.web` 沿用该注册表形状,但有两种能力类别和更丰富的选择策略(配置的提供方 id,或在恰好只有一个可用提供方注册时自动选择),因此执行时抛出的 `WebError` 能解释搜索或 fetch 能力为何无法运行。 + +依赖方向与 bash 和 filesystem 一致: + +```text +@deepseek-ai/dsh-tool-web --depends on--> @deepseek-ai/dsh-web <--depends on-- @deepseek-ai/dsh-web-search-exa + consumer interface implementation + <--depends on-- @deepseek-ai/dsh-web-search-perplexity + implementation + <--depends on-- @deepseek-ai/dsh-web-search-deepseek + implementation + <--depends on-- @deepseek-ai/dsh-web-fetch-local + implementation +``` + +运行时,提供方包向 `ctx.web` 注册能力;`tool-web` 向 `ctx.tools` 注册稳定的工具并通过 seam 执行: + +```mermaid +flowchart LR + exa["@deepseek-ai/dsh-web-search-exa"] -->|registerSearchProvider| web["@deepseek-ai/dsh-web / ctx.web"] + perplexity["@deepseek-ai/dsh-web-search-perplexity"] -->|registerSearchProvider| web + deepseek["@deepseek-ai/dsh-web-search-deepseek"] -->|registerSearchProvider| web + fetchLocal["@deepseek-ai/dsh-web-fetch-local"] -->|registerFetchProvider| web + toolWeb["@deepseek-ai/dsh-tool-web"] -->|search/fetch| web + toolWeb -->|ctx.tools.register| webSearch["tool: web_search"] + toolWeb -->|ctx.tools.register| webFetch["tool: web_fetch"] +``` + +`@deepseek-ai/dsh-web` 仅依赖 Cordis 和底层 harness 支持。它声明 `ctx.web`、提供方接口、请求/结果类型、提供方可用性契约和错误码。它不导入 tool、agent、session、LLM 或提供方包。 + +提供方包仅依赖 `dsh-web` 和 Cordis。它们拥有凭证、端点、协议格式映射、解析和 `WebError` 转换,使用平台 `fetch`。每个提供方注入共享服务并注册后端;只有 `dsh-web` 拥有 `ctx.web` 键。提供方私有的协议形状不会产生对 `ctx.llm` 或 Cordis HTTP 服务的依赖。 + +`@deepseek-ai/dsh-tool-web` 依赖 `@deepseek-ai/dsh-web`、`@deepseek-ai/dsh-tools`、`@deepseek-ai/dsh-system-prompt` 和 Cordis。它从不导入具体的提供方包。 + +## `ctx.web` 契约 + +`ctx.web` 是一个提供方注册表加上一个带提供方选择的执行面。注册表部分与 `LlmService` 保持接近:每种能力类别一个 `Map<id, provider>`,`registerSearchProvider`/`registerFetchProvider` 方法返回 disposer,重复 id 抛出 `WebError`,执行时解析在选定提供方缺失或不可用时抛出异常。权威签名见 `packages/web/web/src/types.ts`;seam 的形状: + +```ts +interface WebSearchProvider { + readonly id: string + available(): boolean + search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult> +} + +interface WebFetchProvider { + readonly id: string + available(): boolean + fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult> +} + +interface WebService { + registerSearchProvider(provider: WebSearchProvider): () => void + registerFetchProvider(provider: WebFetchProvider): () => void + + search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult> + fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult> +} +``` + +可选的 signal 是执行控制,而非业务输入:`tool-web` 直接传递 `exec.signal`,使轮次取消、工具超时和 agent dispose(资源释放)能到达提供方的网络请求、流读取器和高开销解码。seam 不传递 `ToolExecution`——否则 `dsh-web` 就要依赖 `dsh-tools`。 + +提供方 id 是稳定字符串,在各自的能力类别内唯一。注册重复的搜索提供方 id 或重复的 fetch 提供方 id 会失败,而非静默替换旧提供方。提供方注册返回 disposer,沿用现有的 `ctx.tools.register()`/`ctx.systemPrompt.section()` 模式:变更包裹在 `ctx.effect()` 中,注册随贡献它的 fiber 一起拆除。 + +## 提供方可用性与选择 + +提供方可用性与能力选择是两个独立概念,但都保持最小化。提供方仅报告该具体实现是否可用,通过廉价的本地检查(如凭证是否存在、端点配置是否可解析)。提供方的 `available()` 禁止发起网络调用。 + +`LlmService` 完全没有状态类型:可用性通过注册表成员资格加解析时抛出来表达。`ctx.web` 遵循同样的纪律。seam 不暴露聚合的能力状态查询——`search()`/`fetch()` 在每次调用时根据配置的提供方 id、已注册的提供方和每个提供方廉价的本地 `available()` 布尔值派生选择结果,选择失败就是执行时抛出的结构化 `WebError`。需要知道某项能力能否运行的调用方通过执行并路由该错误来获知;没有任何东西作为可变服务状态存储。 + +该布尔值是选择的输入,而非健康系统。`tool-web` 从不直接调用提供方的 `available()`——它进入 seam 的唯一路径是 `search()`/`fetch()`——因此选择策略只有一个所有者。 + +选择不得依赖注册顺序。Cordis 加载顺序、配置排列和 HMR 时序不是产品语义。 + +| 情况 | 执行行为 | +|---|---| +| 配置的提供方 id 已注册且 `available() === true` | 运行该提供方 | +| 配置的提供方 id 未注册 | 以 `WEB_PROVIDER_CONFIGURED_MISSING` 失败 | +| 配置的提供方 id 已注册但不可用 | 以 `WEB_PROVIDER_CONFIGURED_UNAVAILABLE` 失败 | +| 未配置提供方 id,且该类别恰好有一个已注册且可用的提供方 | 运行该唯一提供方 | +| 未配置提供方 id,且该类别无已注册提供方 | 以 `WEB_PROVIDER_UNAVAILABLE` 失败 | +| 未配置提供方 id,且该类别有多个可用提供方已注册 | 以 `WEB_PROVIDER_AMBIGUOUS` 失败,而非按注册顺序选择 | +| 未配置提供方 id,且有提供方存在但均不可用 | 以 `WEB_PROVIDER_UNAVAILABLE` 失败 | + +「唯一提供方自动选择」规则面向测试、演示和简单部署。产品配置设置显式提供方 id: + +```yaml +- id: web + name: '@deepseek-ai/dsh-web' + config: + searchProvider: exa + fetchProvider: local-http + +- id: web-search-exa + name: '@deepseek-ai/dsh-web-search-exa' + +- id: web-search-perplexity + name: '@deepseek-ai/dsh-web-search-perplexity' + +- id: web-search-deepseek + name: '@deepseek-ai/dsh-web-search-deepseek' + +- id: web-fetch-local + name: '@deepseek-ai/dsh-web-fetch-local' + +- id: tool-web + name: '@deepseek-ai/dsh-tool-web' +``` + +运维覆盖走同一条显式选择路径:`DSH_WEB_SEARCH_PROVIDER=perplexity` 等同于配置 `searchProvider: perplexity`,而非 `dsh-tool-web` 内部的隐式优先级链。 + +`ctx.web.search()` 和 `ctx.web.fetch()` 在执行时按上述选择规则解析提供方。如果选定的能力不可用,它们抛出带有结构化代码的 `WebError`,如 `WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE` 或 `WEB_PROVIDER_AMBIGUOUS`。如果未显式配置提供方且不存在可用提供方,执行错误是通用的 `WEB_PROVIDER_UNAVAILABLE` 情况;刻意不提供对每个不可用提供方的诊断汇总。 + +## 搜索请求与结果 schema + +面向模型的 `web_search` 工具很小。唯一的面向模型参数是: + +- `query`:必填字符串。 + +`max_results` 不暴露给模型。它是 `dsh-tool-web` 层的决策:工具设定结果上限——`searchMaxResults` 插件配置,默认 `8`(与 OpenCode 的 Exa 默认值对齐),类似 `dsh-tool-fs` 的 `readLimit`——并作为 `WebSearchRequest` 上的 `maxResults` 传给 seam。将其排除在模型 schema 之外意味着模型只需提问,产品控制返回多少上下文;该字段日后可以提升为面向模型的参数而不破坏 seam。 + +`maxResults` 沿 tool → seam → provider 流动,上限在返回路径上强制执行: + +- `dsh-tool-web` 拥有该值并将其放在 `WebSearchRequest.maxResults` 上。 +- `ctx.web` 将请求原样传递给选定的提供方。 +- 当提供方的 API 支持结果数量控制时(Exa 的 `numResults`),提供方在请求层应用 `maxResults`,作为成本/延迟优化。 +- `ctx.web` 在结果上强制执行上限:如果提供方返回的 source 数量超过 `maxResults`——因为其 API 没有结果数量控制(Perplexity)或忽略了提示——seam 将 `sources[]` 截断到 `maxResults` 并在返回前将 `WebSearchResult.truncated` 设为 `true`。这使上限成为面向模型层可以依赖的单一跨提供方保证,而非每个提供方都必须记得遵守的东西。 + +seam 请求不携带提供方特有的控制——没有 Perplexity 模型选择、搜索时效性、域名过滤器、Exa `livecrawl`、Exa `type`、区域提示、生成式回答预算或搜索深度。只有当某个字段具有提供方无关的语义,且工具 schema 和选定的提供方都能诚实地遵守时,才会添加。 + +```ts +interface WebSearchRequest { + readonly query: string + /** Upper bound on returned sources; the seam truncates to it. Omitted = no bound. `dsh-tool-web` always sets it. */ + readonly maxResults?: number +} + +interface WebSearchResult { + readonly content?: string + readonly sources: readonly WebSearchSource[] + readonly truncated: boolean +} + +interface WebSearchSource { + readonly url: string + readonly title?: string + readonly snippet?: string + readonly publishedAt?: string +} +``` + +`content` 是可选的提供方生成的回答文本、搜索上下文或摘要。`sources[]` 是可移植的引用面。source 必有 URL;title、snippet 和 `publishedAt` 可选,因为并非每个提供方都返回它们。`title` 不是必填:Perplexity 风格的引用可能只提供 URL,强制适配器编造标题会让 seam 说谎。`dsh-tool-web` 渲染 `title ?? hostname(url)` 风格的回退标签用于展示。`publishedAt` 是可选的发布/抓取时间戳,为 ISO-8601 字符串——Exa 在每条结果上以 `publishedDate` 返回它,Perplexity 在搜索结果上返回 `date`,因此它是真实的提供方数据而非派生值;seam 以字符串形式传递,日期解析留给消费方。 + +Exa 搜索将提供方扁平 `results[]` 的每一项映射为 `WebSearchSource`:`url` ← `url`、`title` ← `title`、`snippet` ← 第一个 `highlights[]` 条目(没有 highlight 的条目没有可移植的 snippet,被丢弃)、`publishedAt` ← `publishedDate`。Exa 不返回提供方生成的回答,因此 `content` 省略。Perplexity 搜索将 `choices[0].message.content` 映射为 `content`,并优先使用结构化的顶层 `search_results[]` 作为 `sources[]`——`url` ← `url`、`title` ← `title`、`snippet` ← `snippet`(常为空)、`publishedAt` ← `date`——仅在 `search_results` 缺失时回退到纯 URL 的 `citations[]` 数组(这些 source 只有 `url`)。如果提供方返回的结构化字段少于 seam 支持的,适配器省略那些可选字段。 + +完整页面获取仍是 `web_fetch(url)` 的职责。搜索 snippet 是发现上下文,不是获取到的页面正文。 + +## Fetch 请求与结果 schema + +`web_fetch` 的实现是一个匿名公开 HTTP(S) fetch 提供方 `local-http`。它从具体 URL 获取字节,应用下述基本传输卫生措施(仅 http/https、拒绝 URL 中的凭证、字节/时间上限、跨源重定向阻断),解码文本内容,并仅返回最小的模型可用结果:最终 URL、状态码、正文和截断标志。它不携带浏览器 cookie、编辑器凭证、git 凭证、内部认证令牌,也不隐式访问私有服务。(完整的 SSRF/私有网络阻断推迟——见[推迟工作](#deferred-work)。) + +seam 请求比 OpenCode 的面向模型工具更小: + +- `url`:必填 HTTP(S) URL。 + +seam 请求刻意不包含逐调用超时、`format`、`prompt` 或提供方特有的提取控制。取消通过直接的可选执行信号实现,fetch 提供方拥有一个部署配置的超时兜底。`format` 是对已获取资源的展示决策;`prompt` 是更高层的 LLM 摘要指令;Firecrawl、Exa、Tavily 或 Parallel 等提取 API 可能不暴露具体的 HTTP 响应。如果产品日后需要提供方支撑的页面提取,那是一个独立的 `web_extract` 能力或对本 seam 的刻意扩展——提取语义绝不通过将每个 HTTP 字段设为可选来偷渡进 `web_fetch`。 + +HTTP 状态码是已获取资源状态的一部分,不自动构成工具失败。成功的网络获取一个 `404` 或 `500` 响应会返回带有状态码和有界解码正文(当内容类型受支持时)的 `WebFetchResult`。`WebError` 用于无法安全获取或表示资源的失败:无效或被阻断的 URL、重定向策略违规、超时、abort、响应过大、不支持的内容类型、提供方失败或网络失败。 + +```ts +interface WebFetchRequest { + readonly url: string +} + +interface WebFetchResult { + readonly url: string + readonly statusCode: number + readonly body: WebFetchBody + readonly truncated: boolean +} + +type WebFetchBody = + | { readonly kind: 'html'; readonly content: string } + | { readonly kind: 'text'; readonly content: string } +``` + +`WebFetchResult.url` 是允许的重定向之后的最终 URL。请求 URL 已在 `WebFetchRequest` 中,因此没有单独的 `requestedUrl`/`finalUrl` 对。 + +`WebFetchBody` 是封闭的可辨识联合类型,因为正文类别需要 seam、提供方和工具三方协调变更,而非独立的插件扩展。穷举 switch 使新类别在每个渲染器处编译失败,直到被处理。独立的对象分支为类别特有字段留出空间。 + +提供方负责安全的资源获取:URL 校验、HTTP 传输、重定向策略、超时、abort 传播、字节上限、字符集解码、内容类型分类和二进制拒绝。`dsh-tool-web` 负责展示:HTML 转 Markdown、HTML 转纯文本、面向模型的截断格式化,以及未来的摘要。 + +fetch 提供方的资源控制: + +- 仅接受 `http:` 和 `https:` URL;拒绝 URL 中的凭证。 +- 强制执行最大 URL 长度、响应字节上限、解码正文字符上限、超时和重定向跳数上限。 +- Abort 信号传播到网络获取和高开销解码。 +- 仅自动跟随同源重定向;跨源重定向以 `WEB_REDIRECT_BLOCKED` 失败,要求一次新的工具调用,从而触发新的提供方/权限决策。(Claude Code 的 WebFetch 使用同样的模型——它不自动跟随跨主机重定向,而是将重定向目标返回给模型以发起新调用。) +- 请求携带显式的产品 User-Agent,而非静默伪装浏览器。 + +SSRF/私有网络防护(阻断私有、回环、链路本地、多播及其他非公开目的地,通过先 DNS 解析再验证 IP 来防御 rebinding,并在重定向的每一跳重新验证)**推迟**——见[推迟工作](#deferred-work)。在其落地之前,`web_fetch` 是一个 SSRF 原语,不得在能触达敏感内部网络目标的部署中启用。 + +## 工具消费方行为 + +`dsh-tool-web` 拥有两个 `ToolDefinition`:`web_search` 和 `web_fetch`。它拥有面向模型的 JSON Schema、snake_case 参数名、prompt 段落、结果渲染为 `ContentBlock[]`、`presentCall` 和 `presentResult`。 + +`dsh-tool-web` 禁止枚举提供方或直接调用提供方的 `available()`。它进入 seam 的唯一路径是 `ctx.web.search()`/`ctx.web.fetch()`。这将提供方选择保持在单一层;否则工具包可能判定某个提供方可用,而执行时解析出不同的状态。 + +工具注册是最小化的稳定同步:插件启动时,`dsh-tool-web` 的 `Config`(`search?: boolean`、`fetch?: boolean`,均默认 `true`)启用或禁用每个 web 工具;已启用的工具通过基于 effect 的注册表以 fiber 作用域的 disposer 注册;任何工具都不会仅因其选定的提供方缺失、不可用或存在歧义而被 dispose;dispose `tool-web` fiber 时自动拆除其注册。 + +提供方可用性变化影响执行结果和诊断信息,而非面向模型的 schema 是否存在。如果产品完全不需要 web 工具,在配置中禁用 `dsh-tool-web` 或单个 web 工具即可;如果需要 web 工具但后端配置有误,模型在执行时看到结构化的工具错误。 + +prompt 引导解释了语义分工——`web_search` 用于发现和获取当前信息,`web_fetch` 用于模型需要特定 URL 内容的场景——prompt 和工具结果告诉模型用 Markdown 链接引用相关 URL。 + +面向模型的输出以文本为先,因为工具结果是 `ContentBlock[]`,但 seam 的产出保持结构化,以便 UI 展示和未来的适配器无需解析渲染后的文本。 + +## 错误 + +`dsh-web` 定义 `WebError extends HarnessError`,带有稳定的错误码,仅覆盖调用方可能合理分支的状态: + +- `WEB_PROVIDER_UNAVAILABLE` +- `WEB_PROVIDER_CONFIGURED_MISSING` +- `WEB_PROVIDER_CONFIGURED_UNAVAILABLE` +- `WEB_PROVIDER_AMBIGUOUS` +- `WEB_DUPLICATE_PROVIDER` +- `WEB_INVALID_URL` +- `WEB_BLOCKED_URL` +- `WEB_REDIRECT_BLOCKED` +- `WEB_FETCH_TOO_LARGE` +- `WEB_FETCH_TIMEOUT` +- `WEB_ABORTED` +- `WEB_UNSUPPORTED_CONTENT_TYPE` +- `WEB_PROVIDER_ERROR` + +`WEB_DUPLICATE_PROVIDER` 在 `registerSearchProvider`/`registerFetchProvider` 发现该能力类别中已有相同 id 时同步抛出(类似 `LlmService` 的 `DUPLICATE_ADAPTER`);它是注册时的编程错误而非执行结果,但共享 `WebError` 码空间,使调用方看到统一的分类体系。`WEB_PROVIDER_ERROR` 是提供方自身失败通过 seam 浮出的兜底码,包括 `web-fetch-local` 中的网络/传输失败(DNS、连接拒绝、TLS);刻意不设单独的 `WEB_NETWORK` 码——提供方设置描述性消息,使模型和日志能区分网络失败与提供方 API 失败。 + +工具执行让这些错误流经 `ToolRegistry.execute()`,后者已将 `HarnessError` 转换为带结构化元数据的错误工具结果。模型得到可读的错误消息;钩子、测试和 UI 代码可以根据稳定的错误码路由。 + +## 测试 + +每一层在自己的 seam 处固定:`dsh-web` 中的注册/选择/截断/abort 契约与 `WebError` 码;每个提供方基于录制的 fixture(测试前置数据)的请求/响应映射(Perplexity fixture 包含纯 URL 引用,以保持可选 source 字段的诚实性),加上每个真实提供方的自跳过带密钥冒烟测试;`web-fetch-local` 中的真实本地 HTTP 行为;`dsh-tool-web` 中通过真实工具注册表的启用驱动注册、结构化执行错误和结果格式化。一个真实 Loader 冒烟测试守护两种导出形状([事后分析 0001](../../../postmortem/0001-acp-default-export-drops-inject.md)):`dsh-web` 是默认导出的服务,而提供方和 `tool-web` 是命名空间插件,误加 `export default` 会丢失 `inject`。 + +## 曾考虑的替代方案 + +### 让每个提供方注册自己的面向模型工具 + +这与最灵活的提供方插件系统一致:每个提供方可以暴露其完整的原生 schema。在 harness 中被否决,因为它将面向模型的名称、描述、prompt 引导和结果格式化的所有权交给了提供方包。多个搜索提供方会产生重复的工具名或提供方特有的工具名,模型将学到后端细节而非稳定的产品能力。 + +### 将提供方调度直接放在 `dsh-tool-web` 中 + +这类似 OpenCode 的本地 web 搜索:一个稳定的 `websearch` 工具在内部调度到 Exa 或 Parallel。对于小型产品路径可以接受,但作为 harness 基础是错误的。工具包将拥有提供方选择、凭证、请求映射、传输、响应解析和展示,使得在不将 Exa 和 Perplexity 的差异烘焙进工具 schema 的情况下难以添加它们。 + +### 将搜索和 fetch 拆为两个 seam(`dsh-search`、`dsh-fetch`) + +很有吸引力,因为两半不共享请求 schema 和业务逻辑,各自能干净地映射到 bash/fs 的三包模板上,且 `WebService` 上的 `Search`/`Fetch` 方法对重复也会消失。否决,因为共享的机制——提供方 id 注册表、不依赖注册顺序的选择策略、abort 传播、`WebError` 分类体系,以及面向产品的「这个 harness 如何触达 web」配置面——是真实存在的,否则会在两个几乎相同的 seam 之间重复。一个 `ctx.web` 中间层给产品一个统一的注入和配置对象,给提供方选择一个唯一的所有者。代价是并行的 `searchX`/`fetchX` 方法对,这是有意接受的。 + +### 选择第一个注册的提供方 + +否决。注册顺序不是产品策略。它可能随配置顺序、插件加载、HMR 或重构而变化。提供方选择必须是显式的,或仅在恰好只有一个可用提供方时自动选择。 + +### 将 Firecrawl/Exa/Tavily/Parallel 提取视为 fetch + +在第一版中否决。这些提供方通常返回提取或摘要后的内容,而非具体的 HTTP 响应。如果产品需要提取,日后设计 `web_extract` 或刻意扩展 fetch seam。 + +### 镜像 Claude Code 的 `url + prompt` WebFetch 形状 + +在 seam 层面否决。`prompt` 将 fetch 变成 LLM 摘要,并将公开 web 获取耦合到模型提供方。harness seam 应当确定性地获取和解码;`dsh-tool-web` 日后可以将摘要作为展示模式提供,而无需让 `ctx.web` 依赖 `ctx.llm`。 + +## 后果 + +**搜索 schema 刻意精简。** Exa 和 Perplexity 都暴露了有用的提供方特有控制;只有当某个控制能以提供方无关的方式定义、且工具注册和提供方执行都能诚实遵守时,才会添加。 + +**Perplexity 引用可能稀疏。** 一条引用可能只有 URL。将 `title` 和 `snippet` 设为可选使 seam 保持诚实,但意味着 `tool-web` 需要渲染回退标签。 + +**稳定的工具注册将配置错误推迟到执行时。** 当产品启用了 web 访问时,保持工具可见是正确的;但期望 web 搜索可用的产品应用应当醒目地浮出结构化的 `WEB_PROVIDER_CONFIGURED_MISSING`/`WEB_PROVIDER_CONFIGURED_UNAVAILABLE`/`WEB_PROVIDER_AMBIGUOUS` 失败,使用户不会在模型调用工具后才发现配置问题。 + +**提供方状态可能在启动后变化。** 一个工具可能在步骤开始时组装的请求中可见,但在执行前失去其提供方。执行路径重新解析并以结构化错误失败。 + +**Fetch 是网络边界,不仅仅是只读工具。** `web_fetch` 能触达敏感网络目标或通过 URL 外泄数据。仅交付基本传输卫生措施(仅 http/https、拒绝凭证、字节/时间上限、跨源重定向阻断);SSRF/私有网络阻断推迟(见[推迟工作](#deferred-work)),因此在其落地之前,`web_fetch` 不得在能触达内部目标的环境中启用。 + +**大量 web 内容可能损害上下文质量。** 提供方强制执行字节/字符上限并报告 `truncated`;`tool-web` 格式化有界的模型输出,附带清晰的继续或后续引导。 + +## 推迟工作 + +- `web_fetch` 的 SSRF/私有网络防护:阻断私有、回环、链路本地、多播及其他非公开目的地,使 `web_fetch` 不再是 SSRF 原语。正确实现不仅仅是 URL 字符串检查——需要先 DNS 解析再连接到已验证的 IP(防御 DNS rebinding/TOCTOU)、跨重定向的每跳重新验证,以及 IPv6 边缘处理(私有范围、IPv4 映射地址)。所调研的参考实现均未做 IP 级阻断(OpenCode 做前缀检查后直接 fetch;Claude Code 依赖集中式主机名黑名单加「私有 URL 会失败」的 prompt),因此没有可复制的实现,且这是 harness 唯一的 SSRF 防线——值得一次专门的设计/spike。在其落地之前,`web_fetch` 只能在无法触达敏感内部目标的部署中启用。 +- `pdf` `WebFetchBody` 类别:`local-http` 提供方将可文本提取的 PDF 解码(尽力而为、有上限、`truncated`)为 `{ kind: 'pdf'; content; pageCount? }` 分支,`tool-web` 渲染它。这是 fetch 而非 `web_extract`——PDF 获取是具体的 HTTP 200 加确定性的本地解码,不是提供方侧对非 HTTP 资源的提取。添加它是跨 `dsh-web`(声明分支)、提供方(解码 + 将「二进制拒绝」收窄为「拒绝二进制,但可文本提取的 PDF 除外」;需要 OCR 的扫描/图片 PDF 不在范围内)和 `tool-web`(渲染)的协调变更。封闭的 `WebFetchBody` 联合类型使消费方在新分支被处理之前编译失败。 +- 提供方支撑的提取作为独立的 `web_extract` 能力,而非静默扩展 `web_fetch`。 +- 推迟的权限系统落地后的权限策略集成。 +- `query` 和 `maxResults` 之外的提供方无关搜索控制,待 Exa 和 Perplexity 都能诚实遵守时再添加。 + +## 开放问题 + +- 产品应用包是否应在启动时探测 web 配置(当 web 被显式配置时将 `WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE` 和 `WEB_PROVIDER_AMBIGUOUS` 视为致命错误),还是将配置错误留到首次执行时浮出? +- 推迟的权限系统落地后,公开 web 访问的权限策略应放在哪里:`tools/execute` 上的专用 web 权限插件、提供方配置,还是两者兼有? diff --git a/scripts/translation-pairing.manifest.json b/scripts/translation-pairing.manifest.json index 86368ef25d..c836ec18de 100644 --- a/scripts/translation-pairing.manifest.json +++ b/scripts/translation-pairing.manifest.json @@ -58,6 +58,7 @@ "docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md", "docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md", "docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md", + "docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md", "docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md", "docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md", "docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md", From 1f9633a8cef43cf548e5300e08e99fd3bcc7f9a3 Mon Sep 17 00:00:00 2001 From: Turtle <turtle1999@deepseek.com> Date: Wed, 22 Jul 2026 18:59:05 +0800 Subject: [PATCH 082/368] =?UTF-8?q?docs(cordis-tutorial):=20address=20revi?= =?UTF-8?q?ew=20=E2=80=94=20effect-wrap=20demo=20timer,=20drop=20entry-ord?= =?UTF-8?q?er=20promise,=20stable=20ids=20in=20HMR=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/cordis-tutorial/01-first-plugin.md | 2 +- docs/cordis-tutorial/02-lifecycle-and-effects.md | 15 ++++++++++----- docs/cordis-tutorial/06-composition-and-hmr.md | 14 +++++++++----- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/docs/cordis-tutorial/01-first-plugin.md b/docs/cordis-tutorial/01-first-plugin.md index cd4f060b03..084f9964e1 100644 --- a/docs/cordis-tutorial/01-first-plugin.md +++ b/docs/cordis-tutorial/01-first-plugin.md @@ -26,7 +26,7 @@ This tutorial's launcher assembles the application from configuration. Create `c - name: './hello.ts' ``` -The file is a list of plugin entries. `name` is a module specifier — a relative path or an npm package name — and the loader mounts each entry in order. +The file is a list of plugin entries. `name` is a module specifier — a relative path or an npm package name — and the loader mounts every entry. Entries start concurrently, so list position guarantees nothing about which plugin loads first; ordering comes from service dependencies (`inject`, [chapter 3](03-services.md)), not from position in the file. ## Run it diff --git a/docs/cordis-tutorial/02-lifecycle-and-effects.md b/docs/cordis-tutorial/02-lifecycle-and-effects.md index 4f3534a0eb..68a0f12ec8 100644 --- a/docs/cordis-tutorial/02-lifecycle-and-effects.md +++ b/docs/cordis-tutorial/02-lifecycle-and-effects.md @@ -27,11 +27,16 @@ function heartbeat(ctx: Context) { export function apply(ctx: Context) { // Mount a child plugin and keep its fiber to dispose it later. const fiber = ctx.plugin(heartbeat) - setTimeout(async () => { - await fiber.dispose() - console.log('disposed') - process.exit(0) - }, 700) + // The demo timer is itself an effect: if THIS plugin is unloaded first, + // the pending callback is cancelled instead of firing on a dead app. + ctx.effect(() => { + const timer = setTimeout(async () => { + await fiber.dispose() + console.log('disposed') + process.exit(0) + }, 700) + return () => clearTimeout(timer) + }) } ``` diff --git a/docs/cordis-tutorial/06-composition-and-hmr.md b/docs/cordis-tutorial/06-composition-and-hmr.md index dd5020db0a..b11fdbe45c 100644 --- a/docs/cordis-tutorial/06-composition-and-hmr.md +++ b/docs/cordis-tutorial/06-composition-and-hmr.md @@ -25,12 +25,16 @@ Because unloading releases effects ([chapter 2](02-lifecycle-and-effects.md)) an In `tmp/cordis-tutorial`, write `cordis.yml`: ```yaml -- name: '@cordisjs/plugin-logger-console' -- name: '@cordisjs/plugin-timer' -- name: '@cordisjs/plugin-hmr' +- id: logger + name: '@cordisjs/plugin-logger-console' +- id: timer + name: '@cordisjs/plugin-timer' +- id: hmr + name: '@cordisjs/plugin-hmr' config: root: ['.'] -- name: './hello.ts' +- id: hello + name: './hello.ts' ``` Two support plugins joined the list: HMR logs through the Cordis logger service, so without a console exporter you would not see its messages, and it `inject`s the `timer` service for debouncing — without `@cordisjs/plugin-timer` it sits in PENDING forever, silently. That silence is the subject of the next section. @@ -50,7 +54,7 @@ hello from my first plugin hello from my EDITED plugin ``` -The old instance unloaded (all its effects unwound), the new code loaded, `apply` ran again. Stop the process with Ctrl-C. Editing `cordis.yml` itself is also picked up: the loader diffs entries by `id` and mounts, unmounts, or reconfigures only what changed. +The old instance unloaded (all its effects unwound), the new code loaded, `apply` ran again. Stop the process with Ctrl-C. Editing `cordis.yml` itself is also picked up: the loader diffs entries by `id` and mounts, unmounts, or reconfigures only what changed. This is why the entries above carry explicit `id`s — an entry without one gets a generated id on every read, so after any config-file edit it counts as removed-plus-added and remounts even if its own lines did not change. ## Diagnosing a plugin that never loads From ef2de530ffd597a1be3efc42ef4b21695effa74b Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 19:09:27 +0800 Subject: [PATCH 083/368] fix(code-runtime): flatten worker JSON transport --- ...-20-code-mode-typed-tool-returns.i18n.yaml | 4 +- ...2026-07-20-code-mode-typed-tool-returns.md | 8 +- ...6-07-20-code-mode-typed-tool-returns.zh.md | 8 +- docs/config-catalog.md | 2 +- .../code-runtime-worker/README.md | 4 +- .../code-runtime-worker/src/bootstrap.ts | 19 +- .../code-runtime-worker/src/index.ts | 17 +- .../code-runtime-worker/src/protocol.ts | 16 +- .../code-runtime-worker/src/worker-json.ts | 181 ++++++++++++++++++ .../tests/bootstrap.spec.ts | 44 +++-- .../code-runtime-worker/tests/runtime.spec.ts | 13 +- .../tests/source-worker.compat.spec.ts | 5 +- .../tests/worker-json.spec.ts | 89 ++++++++- 13 files changed, 352 insertions(+), 58 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml index a84e69c18e..9ce72eca05 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml @@ -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 -2026-07-20-code-mode-typed-tool-returns.md: 2f7b39ddaa3d4f2441a9061583bb60dbb4c8e14c -2026-07-20-code-mode-typed-tool-returns.zh.md: 9842897cb372d04b4b09679ed13062511347cdc2 +2026-07-20-code-mode-typed-tool-returns.md: 9c24b2cdf493ffb904de16e6816438379afd4211 +2026-07-20-code-mode-typed-tool-returns.zh.md: 33d89b1014589535379ecff0821b7574c4dfde9e diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md index 2f7b39ddaa..9c24b2cdf4 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md @@ -53,7 +53,7 @@ Before dispatch the bridge snapshots binding arguments as lossless JSON and make The worker exposes the actual `ToolCallError` constructor used for `tools` binding failures, so `error instanceof ToolCallError` works. The error has the standard `Error` message plus the exact `toolName`; it deliberately omits `ToolFailure.info`, error codes, and Native content. This is an exception contract for control flow, not a failure union for programmatic classification. -Binding arguments and resolutions are revalidated as lossless JSON on both sides of the hostile worker protocol and cross through structured clone with no byte cap. Both snapshot boundaries traverse iteratively, so valid nesting has no JavaScript call-stack depth cap. The dependency-light runtime seam names its structural equivalent `CodeJsonValue` so it need not depend on the session-owned canonical type; the generated SDK and tool API use `JsonValue`. Intermediate values are not prompt-truncated, context-spilled, or persisted. This preserves full acquired search, workflow, task, filesystem, and MCP values for programmatic filtering while leaving provider and executor acquisition limits truthful. +Binding arguments and resolutions are revalidated as lossless JSON on both sides of the hostile worker protocol and have no byte cap. Before crossing through structured clone, each detached value is encoded as a flat pre-order token stream whose transport nesting is bounded; the receiver rebuilds it iteratively. Valid application nesting therefore has neither a JavaScript call-stack depth cap nor a platform-specific nested structured-clone limit. The dependency-light runtime seam names its structural equivalent `CodeJsonValue` so it need not depend on the session-owned canonical type; the generated SDK and tool API use `JsonValue`. Intermediate values are not prompt-truncated, context-spilled, or persisted. This preserves full acquired search, workflow, task, filesystem, and MCP values for programmatic filtering while leaving provider and executor acquisition limits truthful. ### Outer result and output ledger @@ -63,7 +63,7 @@ The runtime accepts an exact lossless JSON completion of any root. Returning `un Logs stream eagerly so a terminated run can retain output already admitted. Native stdout and stderr writes that bypass the worker's patched stream slots use independent pipes, so terminal settlement continues bounded capture until worker termination completes before materializing the result. When the cap is crossed, the runtime returns an explicit bounded failure with the fitting captured prefix. That outer result then traverses the ordinary `run_code` rendering and spill policy, which may save the captured text and expose its configured head/tail preview. The spill layer cannot recover bytes the runtime rejected beyond the hard cap. -Compute time, wall time, worker heap, cancellation, and fresh-worker isolation remain independent limits. The outer ledger never charges intermediate bindings, so structured-clone cost and available process or worker memory are their practical bounds. +Compute time, wall time, worker heap, cancellation, and fresh-worker isolation remain independent limits. The outer ledger never charges intermediate bindings, so snapshotting, flat-wire encoding and decoding, structured-clone cost, and available process or worker memory are their practical bounds. ### Typed handles and lifetime @@ -97,14 +97,14 @@ Keyless real-worker integration tests pin the two handle workflows that prose re Code programs can compose tools through stable values instead of reverse-engineering Native prose. Native and Both Mode retain their existing text and editor presentation, while Code Mode receives output-schema types and exact runtime JSON. Tool authors must treat the canonical value as their programmatic API and put display-only formatting in the renderer. -The worker performs structured cloning and lossless validation but does not make intermediate values cheap or durable. Outer overflow is an explicit failed run, and error handling remains intentionally human-guided rather than a versioned code union. +The worker performs bounded-depth flat-wire transport and lossless validation but does not make intermediate values cheap or durable. Outer overflow is an explicit failed run, and error handling remains intentionally human-guided rather than a versioned code union. ## Known Limitations and Deferred Work - Subagent and workflow caller-defined structured outputs remain object-rooted through consumer-level guards even though tool outputs may use any JSON root. - Post-execute has separate value and presentation projections; replacing content is not a confidentiality mechanism, so policy must block or replace the value to hide it from programmatic callers. - Intermediate canonical values are execution-local and unavailable to replay because durable events persist only presentation and bounded summaries. -- Intermediate values have no byte cap and can exhaust process or worker memory through retention or structured-clone cost. +- Intermediate values have no byte cap and can exhaust process or worker memory through retention, flat-wire copies, or structured-clone cost. - The 64 MiB hard cap applies only to outer output; spill cannot recover bytes rejected beyond that cap. - Provider or executor acquisition limits may already have discarded source data before a canonical value reaches Code Mode. - Unsupported MCP output schemas fall back to `JsonValue`; richer Native multimedia projection is deferred. diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md index 9842897cb3..33d89b1014 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md @@ -53,7 +53,7 @@ declare const tools: { worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造函数,因此 `error instanceof ToolCallError` 能够成立。该错误包含标准的 `Error` 消息和确切的 `toolName`,并有意省略 `ToolFailure.info`、错误代码与 Native 内容。这是一项用于控制流的异常契约,而不是供程序分类的失败联合。 -绑定参数与绑定返回值会在不可信 worker 协议的两端重新校验为无损 JSON,再通过结构化克隆传输,且不设字节上限。两处快照边界均采用迭代方式遍历,因此有效嵌套不受 JavaScript 调用栈深度上限限制。为保持依赖轻量,运行时 seam 将结构等价类型命名为 `CodeJsonValue`,从而无需依赖会话侧拥有的规范类型;生成的 SDK 和工具 API 则使用 `JsonValue`。这些值不会经过提示词截断、上下文输出落盘或持久化。因此,程序可以完整筛选已经采集的搜索、工作流、任务、文件系统与 MCP 值,同时提供方和执行器的采集上限仍会实际生效。 +绑定参数与绑定返回值会在不可信 worker 协议的两端重新校验为无损 JSON,且不设字节上限。每个分离后的值在通过结构化克隆跨越边界前,都会编码为扁平的前序 token 流,其传输结构的嵌套深度有界;接收方再以迭代方式重建该值。因此,有效应用数据的嵌套深度既不受 JavaScript 调用栈深度上限限制,也不受特定平台对嵌套结构化克隆施加的上限限制。为保持依赖轻量,运行时 seam 将结构等价类型命名为 `CodeJsonValue`,从而无需依赖会话侧拥有的规范类型;生成的 SDK 和工具 API 则使用 `JsonValue`。这些值不会经过提示词截断、上下文输出落盘或持久化。因此,程序可以完整筛选已经采集的搜索、工作流、任务、文件系统与 MCP 值,同时提供方和执行器的采集上限仍会实际生效。 ### 外层结果与输出账本 @@ -63,7 +63,7 @@ worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造 日志会在产生时立即流出,因此运行被终止时仍可保留已经纳入额度的输出。绕过 worker 中已改写流写入入口的原生 stdout 和 stderr 写入会经由彼此独立的管道传输,因此运行时在终态结算期间仍会继续在上限内捕获输出,直至 worker 完全终止,然后才组装结果。超过上限后,运行时会返回一个显式的有界失败,并携带可容纳的已捕获前缀。该外层结果随后通过普通的 `run_code` 渲染与输出落盘策略;策略可以保存已捕获的文本,并暴露其配置指定的头尾预览。输出落盘层无法恢复运行时在硬上限之外拒绝的字节。 -计算时间、墙钟时间、worker 堆内存、取消和每次运行使用全新 worker 的隔离仍是互相独立的限制。外层账本从不计入中间绑定值,因此这些值实际受结构化克隆开销以及进程或 worker 可用内存限制。 +计算时间、墙钟时间、worker 堆内存、取消和每次运行使用全新 worker 的隔离仍是互相独立的限制。外层账本从不计入中间绑定值,因此生成快照、扁平协议格式的编码与解码、结构化克隆开销,以及进程或 worker 的可用内存构成了这些值的实际边界。 ### 类型化句柄与生命周期 @@ -97,14 +97,14 @@ worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造 Code Mode 程序可以通过稳定值组合工具,无需逆向解析 Native 自然语言。Native 和 Both Mode 保留现有文本与编辑器展示,Code Mode 则获得输出 schema 类型和精确的运行时 JSON。工具作者必须把规范值视为程序化 API,并将仅用于展示的格式化放入渲染器。 -worker 会执行结构化克隆和无损校验,但不会降低中间值的开销,也不会使其具备持久性。外层输出溢出会显式导致运行失败,错误处理则有意由人类引导,而不是依赖带版本的错误代码联合。 +worker 会以嵌套深度有界的扁平协议格式传输数据并执行无损校验,但不会降低中间值的开销,也不会使其具备持久性。外层输出溢出会显式导致运行失败,错误处理则有意由人类引导,而不是依赖带版本的错误代码联合。 ## 已知限制与延后工作 - 即使工具输出可以采用任意 JSON 根,subagent 和工作流中由调用方定义的结构化输出仍通过消费方级别的门禁保持对象根限制。 - Post-execute 分别提供值投影与展示投影;替换内容不是保密机制,因此策略若需向程序化调用方隐藏内容,就必须阻止调用或替换值。 - 中间规范值仅存在于执行期间,无法用于回放,因为持久事件只存储展示和有界摘要。 -- 中间值没有字节上限,可能因保留成本或结构化克隆开销而耗尽进程或 worker 内存。 +- 中间值没有字节上限,可能因值的保留、扁平协议格式副本或结构化克隆开销而耗尽进程或 worker 内存。 - 64 MiB 硬上限只适用于外层输出;输出落盘无法恢复超出该上限后被拒绝的字节。 - 提供方或执行器的采集上限可能在规范值到达 Code Mode 前就已丢弃部分源数据。 - 不支持的 MCP 输出 schema 会回退为 `JsonValue`;更丰富的 Native 多媒体投影留待后续实现。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index a9c8e70105..10a4430ff2 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -301,7 +301,7 @@ export interface Config { } ``` -Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:22`](../packages/code-runtime/code-runtime-worker/src/index.ts) +Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:24`](../packages/code-runtime/code-runtime-worker/src/index.ts) ## `@deepseek-ai/dsh-compact-basic` diff --git a/packages/code-runtime/code-runtime-worker/README.md b/packages/code-runtime/code-runtime-worker/README.md index 3e69d0ae0f..f4e7e6ebda 100644 --- a/packages/code-runtime/code-runtime-worker/README.md +++ b/packages/code-runtime/code-runtime-worker/README.md @@ -22,14 +22,14 @@ Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at - **Type-strip host-side, in execution context** — the program is wrapped in an async-function shell, stripped with `node:module`'s `stripTypeScriptTypes` (erasable syntax only — `enum`/namespaces are rejected as a program `exception` and no worker spawns), and sliced back out byte-positioned; it then executes as the body of an `AsyncFunction`, so top-level `await`/`return` work. - **The port assumes a hostile peer** — model code can reach `parentPort` and forge traffic, so every inbound message is shape-validated and REBUILT before anything reads it (`null`, primitives, junk types, and malformed payloads drop without a throw; forged extra fields never ride along), the host answers each call id at most once, resolves binding names as OWN properties only (a forged `constructor` cannot walk a prototype chain), drops post-settlement replies, and validates every binding resolution and completion as lossless JSON. Forged `log`/`done` messages cannot bypass the outer cap: the host repeats validation and accounts every admitted log plus the completion or diagnostic. Worker-side namespaces are null-prototype with `defineProperty`, so `__proto__`-shaped binding names are ordinary keys. - **Two independent budgets, because the peer is hostile** — `computeMs` meters the worker's MEASURED busy time (`worker.performance.eventLoopUtilization()` polling): a hot loop cannot hide behind a pending decoy dispatch, and a program awaiting a slow tool accrues nothing. `maxWallMs` backstops what busy time cannot see (awaiting a promise nobody resolves). Both funnel into `worker.terminate()`, which ends hot synchronous loops too; heap overflow surfaces as the worker's OOM exit (`kind: 'worker-exit'`). -- **Intermediate binding values are complete JSON** — binding arguments and resolutions cross by structured clone after iterative lossless-JSON validation and have no byte or call-stack depth cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. +- **Intermediate binding values are complete JSON** — binding arguments and resolutions undergo iterative lossless-JSON validation, flatten into a bounded-depth pre-order wire value for structured clone, and rebuild iteratively on the other side. They have no byte, JavaScript call-stack, or nested structured-clone depth cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. - **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. Native writes that bypass the patched stream slots arrive on pipes independent of the completion port; settlement therefore continues bounded pipe capture until worker termination completes before materializing the result. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure diagnostic. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. - **Empty environment** — the worker gets `env: {}` and `execArgv: []`: no ambient credentials (stronger than the scrubbed-env rule for spawned commands) and no inherited loader flags. - **Dispose to quiescence** — teardown fails in-flight runs as `abort` and AWAITS each worker's exit before resolving. ## The worker entry, unbuilt and built -Source mode loads erasable-only `src/worker.ts` through Node's native type stripping. Its transitive runtime closure contains only Node built-ins and relative source modules, so a fresh checkout never requires a sibling workspace package's unbuilt `lib/` export. The worker-local JSON snapshotter is parity-tested against the session-owned canonical boundary; the host repeats canonical validation after structured clone. Built mode passes the sibling `lib/worker.cjs` as a filesystem path because pkg's VFS Worker hook expects CommonJS; the same path works under ordinary Node. `tests/built-lib.e2e.ts` pins the real load path required by [docs/testing.md](../../../docs/testing.md). +Source mode loads erasable-only `src/worker.ts` through Node's native type stripping. Its transitive runtime closure contains only Node built-ins and relative source modules, so a fresh checkout never requires a sibling workspace package's unbuilt `lib/` export. The worker-local JSON snapshotter is parity-tested against the session-owned canonical boundary; both sides flatten and rebuild validated values around the message port so application nesting never reaches structured clone. Built mode passes the sibling `lib/worker.cjs` as a filesystem path because pkg's VFS Worker hook expects CommonJS; the same path works under ordinary Node. `tests/built-lib.e2e.ts` pins the real load path required by [docs/testing.md](../../../docs/testing.md). The SDK surface is the default/named `WorkerCodeRuntime` class plus `Config`. The operational `./worker` subpath exists only as the packaged spawn entry; the wire protocol and bootstrap helpers are source-private implementation details. diff --git a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts index 28c0919749..bb021370ca 100644 --- a/packages/code-runtime/code-runtime-worker/src/bootstrap.ts +++ b/packages/code-runtime/code-runtime-worker/src/bootstrap.ts @@ -8,7 +8,7 @@ import { inspect } from 'node:util' import type { DoneMessage, ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts' import { jsonValueBytesUpTo } from './output-json.ts' -import { snapshotCodeJsonValue } from './worker-json.ts' +import { decodeWorkerJson, encodeWorkerJson, snapshotCodeJsonValue } from './worker-json.ts' /** The port surface the bootstrap needs — satisfied by `parentPort` and by the tests' fake. */ export interface BootstrapPort { @@ -152,7 +152,7 @@ export function truncateUtf8Bytes(text: string, maxBytes: number): string { * * @param value - the program's completion value. * @param maxOutputBytes - the byte cap for the outer result. - * @returns the done-message fragment: `{}` for `undefined`, else `{ value }`. + * @returns the done-message fragment: `{}` for `undefined`, else a flat wire `{ value }`. */ export function prepareCompletion(value: unknown, maxOutputBytes: number): Omit<DoneMessage, 'type'> { if (value === undefined) return {} @@ -168,7 +168,7 @@ export function prepareCompletion(value: unknown, maxOutputBytes: number): Omit< if (jsonValueBytesUpTo(snapshot, maxOutputBytes) === undefined) { return { error: { kind: 'output-limit', message: `outer output exceeded ${maxOutputBytes} bytes` } } } - return { value: snapshot } + return { value: encodeWorkerJson(snapshot) } } /** One awaited binding call's settlement handles, keyed by call id in the pending map. */ @@ -208,8 +208,13 @@ export function wireReplies(port: BootstrapPort, pending: Map<number, PendingCal const entry = pending.get(message.id) if (!entry) return pending.delete(message.id) - if (message.ok) entry.resolve(message.value) - else entry.reject(new Error(message.message)) + if (message.ok) { + const value = decodeWorkerJson(message.value) + if (value === undefined) entry.reject(new Error('binding resolution must be lossless JSON')) + else entry.resolve(value) + } else { + entry.reject(new Error(message.message)) + } }) } @@ -238,7 +243,7 @@ export function makeNamespaces( Object.defineProperty(namespace, name, { enumerable: true, value: (args: unknown): Promise<unknown> => { - let detached: unknown + let detached: ReturnType<typeof snapshotCodeJsonValue> try { detached = snapshotCodeJsonValue(args) } catch { @@ -254,7 +259,7 @@ export function makeNamespaces( }, }) try { - port.postMessage({ type: 'call', id, global, name, args: detached }) + port.postMessage({ type: 'call', id, global, name, args: encodeWorkerJson(detached) }) } catch (error: unknown) { pending.delete(id) const message = `binding arguments must be structured-cloneable: ${error instanceof Error ? error.message : String(error)}` diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index 568d6558ca..80511754e6 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -17,6 +17,8 @@ import type { CodeBindingFunction, CodeJsonValue, CodeRunFailure, CodeRunRequest import { snapshotJsonValue } from '@deepseek-ai/dsh-session' import type { ReplyMessage, WorkerBootData, WorkerToHost } from './protocol.ts' import { jsonStringBytesUpTo, jsonValueBytesUpTo, truncateJsonStringBytes } from './output-json.ts' +import { decodeWorkerJson, encodeWorkerJson } from './worker-json.ts' +import type { WorkerJsonWire } from './worker-json.ts' /** Plugin config: every execution cap, changeable from `cordis.yml` (no hardcoded tunables). */ export interface Config { @@ -142,7 +144,7 @@ function parseWorkerMessage(raw: unknown): WorkerToHost | undefined { switch (m.type) { case 'call': { if (typeof m.id !== 'number' || typeof m.global !== 'string' || typeof m.name !== 'string') return undefined - return { type: 'call', id: m.id, global: m.global, name: m.name, args: m.args } + return { type: 'call', id: m.id, global: m.global, name: m.name, args: m.args as WorkerJsonWire } } case 'log': { if (typeof m.text !== 'string') return undefined @@ -150,7 +152,7 @@ function parseWorkerMessage(raw: unknown): WorkerToHost | undefined { } case 'output-limit': return { type: 'output-limit' } case 'done': { - if (m.error === undefined) return { type: 'done', ...m.value !== undefined ? { value: m.value } : {} } + if (m.error === undefined) return { type: 'done', ...m.value !== undefined ? { value: m.value as WorkerJsonWire } : {} } const error = m.error if (typeof error !== 'object' || error === null) return undefined const { kind, message } = error as Record<string, unknown> @@ -409,10 +411,7 @@ export class WorkerCodeRuntime extends CodeRuntime { finish(() => output.success([...logs, ...strayLogs])) return } - // The worker-thread boundary has already structured-cloned this - // hostile value, so accessors and proxies cannot survive to throw - // during the lossless-JSON snapshot. - const value = snapshotJsonValue(message.value) as CodeJsonValue | undefined + const value = decodeWorkerJson(message.value) if (value === undefined) { finish(() => output.failure([...logs, ...strayLogs], { kind: 'invalid-output', message: 'program completion must be lossless JSON' })) } else { @@ -442,9 +441,7 @@ export class WorkerCodeRuntime extends CodeRuntime { reply({ type: 'reply', id: message.id, ok: false, message: `unknown binding ${JSON.stringify(`${message.global}.${message.name}`)}` }) return } - // Structured clone has already removed accessors and proxies, so the - // host can repeat the lossless snapshot without a reflective throw. - const args = snapshotJsonValue(message.args) as CodeJsonValue | undefined + const args = decodeWorkerJson(message.args) if (args === undefined) { reply({ type: 'reply', id: message.id, ok: false, message: 'binding arguments must be lossless JSON' }) return @@ -461,7 +458,7 @@ export class WorkerCodeRuntime extends CodeRuntime { if (value === undefined) { reply({ type: 'reply', id: message.id, ok: false, message: 'binding resolution must be lossless JSON' }) } else { - reply({ type: 'reply', id: message.id, ok: true, value }) + reply({ type: 'reply', id: message.id, ok: true, value: encodeWorkerJson(value) }) } } catch (error: unknown) { reply({ type: 'reply', id: message.id, ok: false, message: messageOf(error) }) diff --git a/packages/code-runtime/code-runtime-worker/src/protocol.ts b/packages/code-runtime/code-runtime-worker/src/protocol.ts index a76515a78c..8d8ec54b60 100644 --- a/packages/code-runtime/code-runtime-worker/src/protocol.ts +++ b/packages/code-runtime/code-runtime-worker/src/protocol.ts @@ -5,6 +5,8 @@ * @module @deepseek-ai/dsh-code-runtime-worker/src/protocol */ +import type { WorkerJsonWire } from './worker-json.ts' + /** What the host hands the worker at spawn, via `workerData`. */ export interface WorkerBootData { /** The type-stripped (plain JS) program body. */ @@ -24,8 +26,8 @@ interface CallMessage { global: string /** The function name within the namespace. */ name: string - /** The single argument, structured-clone-plain. */ - args: unknown + /** The single argument as a flat lossless-JSON wire value. */ + args: WorkerJsonWire } /** Worker → host: captured text, streamed eagerly so output survives a mid-run termination (timeout, abort, OOM). */ @@ -43,13 +45,13 @@ interface OutputLimitMessage { * Worker → host: the program settled. `error` carries a program exception * (the only failure the bootstrap itself can report — budgets, aborts, and * substrate death are observed host-side). `value` is present only on a - * clean completion that produced one (already size-capped and - * clone-safe per the bootstrap's value preparation). Logs are NOT carried - * here — they streamed eagerly as {@link LogMessage}s. + * clean completion that produced one, as a flat wire value already + * size-capped and lossless per the bootstrap. Logs are NOT carried here — + * they streamed eagerly as {@link LogMessage}s. */ export interface DoneMessage { type: 'done' - value?: unknown + value?: WorkerJsonWire error?: { kind: 'exception' | 'invalid-output' | 'output-limit'; message: string } } @@ -58,5 +60,5 @@ export type WorkerToHost = CallMessage | LogMessage | OutputLimitMessage | DoneM /** Host → worker: the answer to one {@link CallMessage}. */ export type ReplyMessage = - | { type: 'reply'; id: number; ok: true; value: unknown } + | { type: 'reply'; id: number; ok: true; value: WorkerJsonWire } | { type: 'reply'; id: number; ok: false; message: string } diff --git a/packages/code-runtime/code-runtime-worker/src/worker-json.ts b/packages/code-runtime/code-runtime-worker/src/worker-json.ts index 105cc2a646..7ef4526321 100644 --- a/packages/code-runtime/code-runtime-worker/src/worker-json.ts +++ b/packages/code-runtime/code-runtime-worker/src/worker-json.ts @@ -150,4 +150,185 @@ export function snapshotCodeJsonValue(value: unknown): CodeJsonValue | undefined } return root } + +interface ArrayWireToken { + kind: 'array' + length: number +} + +interface ObjectWireToken { + kind: 'object' + keys: string[] +} + +type WorkerJsonToken = null | boolean | number | string | ArrayWireToken | ObjectWireToken + +/** + * A pre-order, bounded-depth transport for one lossless JSON value. Container + * markers and scalar leaves share one flat token array, so `worker_threads` + * never has to structured-clone the value's application nesting. + */ +export type WorkerJsonWire = WorkerJsonToken[] + +/** + * Flatten one validated JSON value for the worker-thread message port. + * @param value - the lossless JSON value to transport. + * @returns a pre-order token stream whose own nesting is bounded. + */ +export function encodeWorkerJson(value: CodeJsonValue): WorkerJsonWire { + const wire: WorkerJsonWire = [] + const pending: CodeJsonValue[] = [value] + for (let current = pending.pop(); current !== undefined; current = pending.pop()) { + if (current === null || typeof current === 'boolean' || typeof current === 'number' || typeof current === 'string') { + wire.push(current) + continue + } + if (Array.isArray(current)) { + wire.push({ kind: 'array', length: current.length }) + for (let index = current.length - 1; index >= 0; index--) { + const item = current[index] + if (item === undefined) throw new Error('cannot encode a sparse JSON array') + pending.push(item) + } + continue + } + const keys = Object.keys(current) + wire.push({ kind: 'object', keys }) + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index] + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) throw new Error('cannot encode a missing JSON object key') + const item = current[key] + if (item === undefined) throw new Error('cannot encode an undefined JSON object property') + pending.push(item) + } + } + return wire +} + +type DecodeFrame = + | { kind: 'array'; target: CodeJsonValue[]; length: number; index: number } + | { kind: 'object'; target: Record<string, CodeJsonValue>; keys: string[]; index: number } + +/** Whether an array contains exactly its dense indexed slots and `length`. */ +function isDenseArray(value: unknown[]): boolean { + if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false + for (let index = 0; index < value.length; index++) { + if (!Object.hasOwn(value, index)) return false + } + return true +} + +/** Return one exact container marker, or reject any extra/missing fields. */ +function containerToken(value: object): ArrayWireToken | ObjectWireToken | undefined { + if (Array.isArray(value) || !hasPlainObjectPrototype(value)) return undefined + const keys = enumerableStringKeys(value) + if (keys === undefined) return undefined + const token = value as Record<string, unknown> + if (token.kind === 'array') { + if (keys.length !== 2 || !keys.includes('kind') || !keys.includes('length')) return undefined + const length = token.length + return typeof length === 'number' && Number.isSafeInteger(length) && length >= 0 + ? { kind: 'array', length } + : undefined + } + if (token.kind === 'object') { + if (keys.length !== 2 || !keys.includes('kind') || !keys.includes('keys')) return undefined + const objectKeys = token.keys + if (!Array.isArray(objectKeys) || !isDenseArray(objectKeys)) return undefined + const unique = new Set<string>() + const normalizedKeys: string[] = [] + for (const key of objectKeys as unknown[]) { + if (typeof key !== 'string' || unique.has(key)) return undefined + unique.add(key) + normalizedKeys.push(key) + } + return { kind: 'object', keys: normalizedKeys } + } + return undefined +} + +/** + * Rebuild one lossless JSON value from the flat worker-thread wire format. + * Malformed or incomplete traffic returns `undefined`; traversal is iterative + * and therefore independent of the transported value's application depth. + * @param input - untrusted message-port payload. + * @returns the detached JSON value, or `undefined` when the wire is invalid. + */ +export function decodeWorkerJson(input: unknown): CodeJsonValue | undefined { + try { + if (!Array.isArray(input) || !isDenseArray(input) || input.length === 0) return undefined + const wire = input as unknown[] + const frames: DecodeFrame[] = [] + let root: CodeJsonValue | undefined + let rootAssigned = false + + const attach = (value: CodeJsonValue): boolean => { + const parent = frames.at(-1) + if (!parent) { + if (rootAssigned) return false + root = value + rootAssigned = true + return true + } + /* v8 ignore next -- completed frames are popped before another token can attach. */ + if (parent.index >= (parent.kind === 'array' ? parent.length : parent.keys.length)) return false + if (parent.kind === 'array') { + parent.target.push(value) + } else { + const key = parent.keys[parent.index] + /* v8 ignore next -- object frames are built from validated keys and their exact length. */ + if (key === undefined) return false + Object.defineProperty(parent.target, key, { + value, + enumerable: true, + configurable: true, + writable: true, + }) + } + parent.index += 1 + return true + } + + for (let tokenIndex = 0; tokenIndex < wire.length; tokenIndex++) { + const token = wire[tokenIndex] + let value: CodeJsonValue + let frame: DecodeFrame | undefined + if (token === null || typeof token === 'boolean' || typeof token === 'string') { + value = token + } else if (typeof token === 'number') { + if (!Number.isFinite(token) || Object.is(token, -0)) return undefined + value = token + } else { + if (typeof token !== 'object') return undefined + const marker = containerToken(token) + if (!marker) return undefined + const remainingTokens = wire.length - tokenIndex - 1 + if (marker.kind === 'array') { + if (marker.length > remainingTokens) return undefined + const target: CodeJsonValue[] = [] + value = target + if (marker.length > 0) frame = { kind: 'array', target, length: marker.length, index: 0 } + } else { + if (marker.keys.length > remainingTokens) return undefined + const target: Record<string, CodeJsonValue> = {} + value = target + if (marker.keys.length > 0) frame = { kind: 'object', target, keys: marker.keys, index: 0 } + } + } + if (!attach(value)) return undefined + if (frame) frames.push(frame) + while (frames.length > 0) { + const current = frames.at(-1) + /* v8 ignore next -- the loop condition guarantees a final frame. */ + if (current === undefined) break + if (current.index < (current.kind === 'array' ? current.length : current.keys.length)) break + frames.pop() + } + } + return frames.length === 0 ? root : undefined + } catch { + return undefined + } +} /* jscpd:ignore-end */ diff --git a/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts b/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts index 300b08d85f..78af789169 100644 --- a/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/bootstrap.spec.ts @@ -3,6 +3,7 @@ import { EventEmitter } from 'node:events' import { LogBuffer, makeConsoleShim, makeNamespaces, captureStreamWrites, prepareCompletion, runWorkerMain, ToolCallError, truncateUtf8Bytes, wireReplies } from '../src/bootstrap.ts' import type { BootstrapPort, PatchableStream, PendingCall } from '../src/bootstrap.ts' import type { ReplyMessage, WorkerToHost } from '../src/protocol.ts' +import { decodeWorkerJson, encodeWorkerJson } from '../src/worker-json.ts' /** * An in-process stand-in for the worker's parentPort: the test plays the @@ -37,6 +38,11 @@ class FakePort implements BootstrapPort { done(): WorkerToHost | undefined { return this.sent.find(message => message.type === 'done') } + + doneValue(): unknown { + const done = this.done() + return done?.type === 'done' && done.value !== undefined ? decodeWorkerJson(done.value) : undefined + } } function fakeStreams(): { stdout: PatchableStream; stderr: PatchableStream } { @@ -127,7 +133,7 @@ describe('captureStreamWrites', () => { describe('prepareCompletion', () => { it('omits undefined and passes lossless JSON values exactly', () => { expect(prepareCompletion(undefined, 100)).toEqual({}) - expect(prepareCompletion({ a: [1, 'two'] }, 100)).toEqual({ value: { a: [1, 'two'] } }) + expect(prepareCompletion({ a: [1, 'two'] }, 100)).toEqual({ value: encodeWorkerJson({ a: [1, 'two'] }) }) }) it('turns every lossy completion shape into invalid-output', () => { @@ -149,7 +155,7 @@ describe('prepareCompletion', () => { }) it('measures the exact JSON serialization at and over the boundary', () => { - expect(prepareCompletion('€', 5)).toEqual({ value: '€' }) + expect(prepareCompletion('€', 5)).toEqual({ value: encodeWorkerJson('€') }) expect(prepareCompletion('€', 4)).toEqual({ error: { kind: 'output-limit', message: 'outer output exceeded 4 bytes' }, }) @@ -178,9 +184,20 @@ describe('truncateUtf8Bytes', () => { }) describe('makeNamespaces', () => { + it('rejects a malformed success reply instead of resolving a lossy binding value', async () => { + const port = new FakePort() + const pending = new Map<number, PendingCall>() + wireReplies(port, pending) + const result = new Promise<unknown>((resolve, reject) => { pending.set(1, { resolve, reject }) }) + port.deliver({ type: 'reply', id: 1, ok: true, value: [undefined] as never }) + await expect(result).rejects.toThrow('binding resolution must be lossless JSON') + }) + it('exposes prototype-colliding names as ordinary own properties', async () => { const port = new FakePort() - port.respond = message => message.type === 'call' ? { type: 'reply', id: message.id, ok: true, value: `${message.name}-ok` } : undefined + port.respond = message => message.type === 'call' + ? { type: 'reply', id: message.id, ok: true, value: encodeWorkerJson(`${message.name}-ok`) } + : undefined const pending = new Map<number, PendingCall>() wireReplies(port, pending) const [tools] = makeNamespaces({ namespaces: [{ global: 'tools', names: ['__proto__', 'constructor', 'toString'] }] }, port, pending, { value: 1 }) as [Record<string, (args: unknown) => Promise<unknown>>] @@ -268,14 +285,18 @@ describe('makeNamespaces', () => { describe('runWorkerMain', () => { it('runs a program end-to-end: bindings, console, return value', async () => { const port = new FakePort() - port.respond = message => message.type === 'call' ? { type: 'reply', id: message.id, ok: true, value: (message.args as { n: number }).n * 2 } : undefined + port.respond = (message) => { + if (message.type !== 'call') return undefined + const args = decodeWorkerJson(message.args) as { n: number } + return { type: 'reply', id: message.id, ok: true, value: encodeWorkerJson(args.n * 2) } + } await runWorkerMain(port, { ...BOOT, code: 'const doubled = await tools.double({ n: 21 }); console.log("got", doubled); return { doubled };', namespaces: [{ global: 'tools', names: ['double'] }], }, fakeStreams()) expect(port.logs()).toEqual(['got 42']) - expect(port.done()).toEqual({ type: 'done', value: { doubled: 42 } }) + expect(port.doneValue()).toEqual({ doubled: 42 }) }) it('reports worker-side log capture overflow before completing', async () => { @@ -287,7 +308,7 @@ describe('runWorkerMain', () => { }, fakeStreams()) expect(port.sent).toContainEqual({ type: 'log', text: '1234' }) expect(port.sent).toContainEqual({ type: 'output-limit' }) - expect(port.done()).toEqual({ type: 'done', value: null }) + expect(port.doneValue()).toBeNull() }) it('reports a thrown program error on the done message', async () => { @@ -318,10 +339,7 @@ describe('runWorkerMain', () => { code: 'try { await tools.x({}) } catch (error) { return { caught: error instanceof ToolCallError, name: error.name, toolName: error.toolName, message: error.message } }', namespaces: [{ global: 'tools', names: ['x'] }], }, fakeStreams()) - expect(port.done()).toEqual({ - type: 'done', - value: { caught: true, name: 'ToolCallError', toolName: 'x', message: 'denied by host' }, - }) + expect(port.doneValue()).toEqual({ caught: true, name: 'ToolCallError', toolName: 'x', message: 'denied by host' }) expect(new ToolCallError('x', 'nope')).toMatchObject({ name: 'ToolCallError', toolName: 'x', message: 'nope' }) }) @@ -330,15 +348,15 @@ describe('runWorkerMain', () => { port.respond = (message) => { if (message.type !== 'call') return undefined // Deliver a stray reply first; the real one follows. - port.deliver({ type: 'reply', id: 9_999, ok: true, value: 'stray' }) - return { type: 'reply', id: message.id, ok: true, value: 'real' } + port.deliver({ type: 'reply', id: 9_999, ok: true, value: encodeWorkerJson('stray') }) + return { type: 'reply', id: message.id, ok: true, value: encodeWorkerJson('real') } } await runWorkerMain(port, { ...BOOT, code: 'return await tools.x({})', namespaces: [{ global: 'tools', names: ['x'] }], }, fakeStreams()) - expect(port.done()).toEqual({ type: 'done', value: 'real' }) + expect(port.doneValue()).toBe('real') }) it('captures raw stream writes through the patched process streams', async () => { diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index ff630e51f1..f0c8fcf98f 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -92,7 +92,7 @@ describe('WorkerCodeRuntime — programs and bindings (real workers)', () => { cursor = Array.isArray(cursor) ? cursor[0] : undefined } expect(cursor).toBe('leaf') - }, 60_000) + }, 15_000) it('reports non-erasable syntax as an exception without spawning a worker', async () => { const { runtime } = await setup() @@ -371,7 +371,7 @@ describe('WorkerCodeRuntime — budgets and containment (real workers)', () => { const { parentPort } = await import('node:worker_threads'); const write = (text) => Object.getPrototypeOf(process.stdout).write.call(process.stdout, text); write('late-pipe-' + 'x'.repeat(100_000)); - parentPort.postMessage({ type: 'done', value: 'done' }); + parentPort.postMessage({ type: 'done', value: ['done'] }); for (;;) {} `, bindings: [], @@ -438,7 +438,7 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { program: ` const { parentPort } = await import('node:worker_threads'); for (let i = 0; i < 50; i++) parentPort.postMessage({ type: 'log', text: 'F'.repeat(100), forged: true }); - parentPort.postMessage({ type: 'done', value: 'V'.repeat(100000) }); + parentPort.postMessage({ type: 'done', value: ['V'.repeat(100000)] }); for (;;) {} `, bindings: [], @@ -482,8 +482,9 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { const result = await runtime.run({ program: ` const { parentPort } = await import('node:worker_threads'); - let value = null; - for (let depth = 0; depth < 3_000; depth++) value = [value]; + const value = []; + for (let depth = 0; depth < 3_000; depth++) value.push({ kind: 'array', length: 1 }); + value.push(null); setTimeout(() => { parentPort.postMessage({ type: 'done', value }) }, 25); // Prevent bootstrap's normal undefined completion from racing the forged terminal. await new Promise(() => {}); @@ -500,7 +501,7 @@ describe('WorkerCodeRuntime — hostile programs (real workers)', () => { } expect(depth).toBe(3_000) expect(value).toBeNull() - }, 60_000) + }, 15_000) it('turns forged over-limit error text into output-limit at the host', async () => { const { runtime } = await setup({ maxOutputBytes: 64 }) diff --git a/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts b/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts index ee35b0e990..6ef2775114 100644 --- a/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/source-worker.compat.spec.ts @@ -3,6 +3,7 @@ import { tmpdir } from 'node:os' import { join } from 'node:path' import { Worker } from 'node:worker_threads' import { expect, it } from 'vitest' +import { decodeWorkerJson } from '../src/worker-json.ts' /** * Prove the unbuilt worker is a self-contained source closure. Copying it out @@ -28,7 +29,9 @@ it('boots the source worker without workspace package outputs', async () => { worker?.once('error', reject) }) - expect(message).toEqual({ type: 'done', value: { answer: 42 } }) + expect(message).toMatchObject({ type: 'done' }) + const value = typeof message === 'object' && message !== null ? (message as { value?: unknown }).value : undefined + expect(decodeWorkerJson(value)).toEqual({ answer: 42 }) } finally { if (worker) await worker.terminate() await rm(directory, { recursive: true, force: true }) diff --git a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts index 8481747c4b..012cc1204a 100644 --- a/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/worker-json.spec.ts @@ -1,7 +1,7 @@ import { runInNewContext } from 'node:vm' import { describe, expect, it } from 'vitest' import { snapshotJsonValue } from '@deepseek-ai/dsh-session' -import { snapshotCodeJsonValue } from '../src/worker-json.ts' +import { decodeWorkerJson, encodeWorkerJson, snapshotCodeJsonValue } from '../src/worker-json.ts' describe('snapshotCodeJsonValue', () => { it('matches the canonical scalar boundary', () => { @@ -142,3 +142,90 @@ describe('snapshotCodeJsonValue', () => { expect(snapshotCodeJsonValue({ after: true })).toEqual({ after: true }) }) }) + +describe('flat worker JSON wire', () => { + it('round-trips every JSON root while preserving object keys and container order', () => { + const withPrototypeKey = Object.create(null) as Record<string, unknown> + withPrototypeKey.__proto__ = { safe: true } + const values = [null, false, true, 1.25, 'text', [], {}, [1, { nested: [2] }], withPrototypeKey] + for (const value of values) { + const snapshot = snapshotCodeJsonValue(value) + expect(snapshot).not.toBeUndefined() + expect(decodeWorkerJson(encodeWorkerJson(snapshot!))).toEqual(snapshot) + } + const decoded = decodeWorkerJson(encodeWorkerJson(snapshotCodeJsonValue(withPrototypeKey)!)) as Record<string, unknown> + expect(Object.hasOwn(decoded, '__proto__')).toBe(true) + expect(decoded.__proto__).toEqual({ safe: true }) + }) + + it('round-trips deep values through a bounded-depth token array', () => { + let value: unknown = 'leaf' + for (let depth = 0; depth < 5_000; depth++) value = [value] + const snapshot = snapshotCodeJsonValue(value)! + const wire = encodeWorkerJson(snapshot) + expect(wire).toHaveLength(5_001) + + let cursor = decodeWorkerJson(wire) + for (let depth = 0; depth < 5_000; depth++) { + expect(Array.isArray(cursor)).toBe(true) + cursor = Array.isArray(cursor) ? cursor[0] : undefined + } + expect(cursor).toBe('leaf') + }) + + it('rejects malformed, incomplete, lossy, sparse, decorated, and throwing wire values', () => { + const sparse = new Array(1) + const compensatedSparse = new Array(1) + Object.defineProperty(compensatedSparse, 'extra', { value: true }) + const decorated: unknown[] = [null] + Object.defineProperty(decorated, 'extra', { value: true }) + const throwing: unknown[] = [] + Object.defineProperty(throwing, 0, { enumerable: true, get: () => { throw new Error('wire getter') } }) + const decoratedKeys: unknown[] = ['x'] + Object.defineProperty(decoratedKeys, 'extra', { value: true }) + const foreignMarker: Record<string, unknown> = { kind: 'array', length: 0 } + Object.setPrototypeOf(foreignMarker, {}) + const hiddenMarker = Object.defineProperty({ kind: 'array', length: 0 }, 'hidden', { value: true }) + + for (const value of [ + undefined, + null, + {}, + [], + sparse, + compensatedSparse, + decorated, + throwing, + [undefined], + [-0], + [Number.NaN], + [Number.POSITIVE_INFINITY], + [1, 2], + [[]], + [foreignMarker], + [hiddenMarker], + [{ kind: 'unknown' }], + [{ kind: 'array' }], + [{ kind: 'array', length: '1' }], + [{ kind: 'array', length: -1 }], + [{ kind: 'array', length: Number.MAX_SAFE_INTEGER + 1 }], + [{ kind: 'array', length: 1 }], + [{ kind: 'array', length: 2 }, { kind: 'array', length: 1 }, null], + [{ kind: 'array', length: 0, extra: true }], + [{ kind: 'object' }], + [{ kind: 'object', keys: 'x' }], + [{ kind: 'object', keys: decoratedKeys }], + [{ kind: 'object', keys: [1] }], + [{ kind: 'object', keys: ['x', 'x'] }, 1, 2], + [{ kind: 'object', keys: ['x'] }], + [{ kind: 'object', keys: [], extra: true }], + ]) { + expect(decodeWorkerJson(value)).toBeUndefined() + } + }) + + it('rejects invalid values passed through a forged static type', () => { + expect(() => encodeWorkerJson([undefined] as never)).toThrow(/sparse JSON array/) + expect(() => encodeWorkerJson({ value: undefined } as never)).toThrow(/undefined JSON object property/) + }) +}) From 0b1857904a3bad8e8e90ae832c755b936fe0cadf Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Wed, 22 Jul 2026 04:20:18 -0700 Subject: [PATCH 084/368] =?UTF-8?q?docs(i18n):=20add=20agent-scope=20and?= =?UTF-8?q?=20sandbox=20pairs=20=E2=80=94=20the=20batch=20is=20complete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 最后两篇超长 RFC 经流式通道产出(代理会掐非流式长请求),v4 流水 线同一契约;至此 185 篇批次全部配对,pairing 194 对全绿。 --- ...07-12-agent-scope-runtime-design.i18n.yaml | 6 + .../2026-07-12-agent-scope-runtime-design.md | 2 + ...026-07-12-agent-scope-runtime-design.zh.md | 392 ++++++++++++++++++ .../feature/2026-07-06-sandbox.i18n.yaml | 6 + .../implemented/feature/2026-07-06-sandbox.md | 2 + .../feature/2026-07-06-sandbox.zh.md | 212 ++++++++++ scripts/translation-pairing.manifest.json | 2 + 7 files changed, 622 insertions(+) create mode 100644 docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml create mode 100644 docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md create mode 100644 docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml create mode 100644 docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md diff --git a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml new file mode 100644 index 0000000000..5f2ed7f3bc --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-12-agent-scope-runtime-design.md: 5fe44f2b0a79d91ce0e32a687ed183a5ffaef284 +2026-07-12-agent-scope-runtime-design.zh.md: 6e4f09e6780858c90b0cfbcf8709eca4c79ee414 diff --git a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md index 2c3126793f..5fe44f2b0a 100644 --- a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md +++ b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md @@ -1,5 +1,7 @@ # RFC: Agent-scope runtime design and correctness +English | [中文](2026-07-12-agent-scope-runtime-design.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md new file mode 100644 index 0000000000..6e4f09e678 --- /dev/null +++ b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md @@ -0,0 +1,392 @@ +# RFC:Agent 作用域运行时设计与正确性 + +[English](2026-07-12-agent-scope-runtime-design.md) | 中文 + +Status: implemented + +## 问题 + +[agent 作用域契约](2026-07-08-agent-scope-contexts.md)对贡献者而言很简单:通过 `agent.ctx` 注册,解析出一个全局加单 agent 的视图,仅在 setup 完成后发布,并保持作用域直到工作停止。运行时必须在协作式插件框架、异步创建、可重入监听器、持久化会话提交以及 worker 或进程故障等场景下维护这份契约。 + +主要的设计风险是为每个竞态条件引入第二套机制。独立的预留、就绪哨兵、取消中继、快照层和保护注册表可能镜像同一个事实,直到没有读者能分辨哪个才是权威的。这些机制还会诱使运行时把可信的类型化调用当作敌对的序列化边界来处理。 + +实现需要足够的状态来维护真实的所有权和结算边界,但不能更多。正确性审查者必须能够从接受、发布到拆除,沿着一条事实链跟踪下去,而无需在并行的表示之间做调和。 + +## 决策 + +运行时对每个独立事实使用一种机制。作用域路由有一个不透明载体;每个活跃的注册表对象有一条入口记录;每个创建或恢复操作有一个事务;类型化的同进程调用借用 readonly 值;真实数据边界只物化一次;协作式 prompt 组装的结果即为权威;worker/进程代码仅在不同所有者确实可能竞争时才保留独立的终止态和静默态。 + +该设计可概括为七项选择: + +| 问题 | 权威机制 | +|---|---| +| 选择全局加某个 agent 的注册 | 不透明作用域键与路由载体 | +| 拥有一个活跃的 agent 或会话 | 由其 disposer 捕获的单条注册表入口 | +| 协调创建/恢复 | 单个 `AgentCreationTransaction` | +| 保护持久化、队列、模型或协议格式数据 | 在该边界处一次性物化 | +| 在同一进程内传递类型化值 | Readonly 借用契约 | +| 组合模型可见的 prompt 与工具表面 | 单个共享工具视图加权威的 assembly-waterfall 结果 | +| 协调 subagent、worker 和进程关闭 | 单个取消信号加该边界独立的终止态/静默态事实 | + +本 RFC 余下部分按依赖顺序展开这些选择:Cordis 机制、作用域路由、创建与会话提交、工具与 prompt、subagent 与工作流,最后是可执行检查。 + +[7 月 8 日 RFC](2026-07-08-agent-scope-contexts.md) 仍然是贡献者契约。独立的 [subagent 组合控制 RFC](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 拥有 `persona`、`toolFilter` 和 `maxDepth`;本文仅讨论它们的 setup 如何融入生命周期。 + +## Cordis 模型:context、fiber、effect、receiver 与 waterfall + +理解实现需要五个 Cordis 概念。Context 选择服务和注册所有权;fiber 是一个活跃的插件或子生命周期;effect 将清理逻辑附加到 fiber;event receiver 选择监听器;waterfall(瀑布式事件)让监听器按顺序变换或否决一个操作。 + +### Context 是贯穿单个服务图的所有权路径 + +所有 agent 共享一个 Cordis 服务图。派生的 context 不会克隆 `ToolRegistry`、`SystemPrompt`、持久化或模型适配器;它改变的是:通过该 context 进行的注册如何被标记,以及哪些 effect 拥有其清理逻辑。 + +`agent.ctx` 就是这样一个派生 context。服务调用仍然到达共享实例,而注册操作可以检查其调用 context 并将贡献存储在最近的作用域键下。普通的插件 context 不携带作用域键,因此注册到全局。 + +### Fiber 与 effect 使清理成为结构性的 + +Cordis fiber 是插件或子 context 被激活时创建的活跃实例。其状态记录该生命周期是 active、unloading、failed 还是 disposed。`ctx.effect()` 和 `ctx.on()` 返回 disposer,同时将这些 disposer 附加到注册所在的 fiber,因此卸载一个插件或 agent 作用域会移除通过该 context 注册的一切,无需单独的清单。 + +vendor 中的 Cordis fiber 实现在任意 setup 或 `internal/plugin` 观察者运行之前就建立了所有权。可重入的卸载可以看到已启动的子 fiber 或 effect,拒绝卸载开始后添加的 effect,并通过一个公开的一次性 disposer 加入已启动的清理。拆除观察者被逐个隔离,因此一个回调无法阻止结构性清理。 + +这些是框架生命周期保证,而非 agent 特有的策略。Agent 创建依赖它们,因为 setup 可以激活任意插件并同步重入所有者的 dispose。 + +### Receiver 路由监听器;waterfall 组合决策 + +Cordis 使用 dispatch receiver(`this`)过滤监听器,而 harness 的监听器需要一个显式的 agent、execution、request 或其他主体。`Scoped<T>` 标记作用域事件声明所期望的 receiver,但运行时载体刻意不暴露主体 API。 + +因此,产品辅助函数构造载体并单独传递领域主体。这防止监听器路由变成另一套对象模型,并使事件签名在不了解载体内部的情况下也可理解。 + +Cordis waterfall 是中间件风格的 dispatch。每个监听器接收 `next()`:调用它则委托给剩余监听器和基础操作,不调用则否决或替换下游结果。Waterfall 驱动 prompt 组装和工具策略;普通 emit 事件同步通知,parallel 事件等待所有监听器但没有否决结果。 + +## 作用域路由:一个不透明键选择一层 + +scope 包实现了 Cordis 路由所需的最小对象。其载体仅持有一个组合的服务过滤器和作用域谓词,而包私有地记录不透明键,并单独暴露作用域 fiber 的静默 disposer。 + +### 作用域标识使用对象标识 + +`ScopeKey` 是一个按标识比较的不透明对象。Harness 使用活跃的 `Agent` 作为自身的键,但该原语与领域无关,支持其他作用域所有者。 + +`createScope(parent, key)` 返回一个作用域,其 `ctx` 共享父级的服务,其 effect 被标记为该键。`scopeOf(ctx)` 读取最近的注册键。`scopeTarget(base, key)` 创建 event receiver,其过滤器保留 base receiver 的 Cordis 服务过滤器,然后接纳无作用域的监听器和具有该确切键的监听器。 + +Receiver 是一个小型载体而非领域对象的透明代理。需要 agent 的代码接收显式的事件参数;需要注册所有权的代码接收 `agent.ctx`。 + +### 注册表读取叠加一个精确映射 + +作用域感知的注册表将全局贡献与按标识键索引的局部贡献分开存储。读取解析全局层和至多一个局部层;它从不遍历父级链。 + +每个服务保留其领域规则。命名 prompt 值和工具使用局部遮蔽,工具限制在添加局部工具之前过滤全局,事件选择监听器受众而非注册数据。Scope 提供标识和所有权,而非通用的合并算法。 + +### 融合 dispatch 辅助函数防止主体漂移 + +`agentEvents(context, agent)` 构造 agent 的载体并注入同一个 agent 作为事件主体。Session、tool、approval、prompt 和 subagent 服务同样从它们已拥有的对象派生路由,而非接受一个无关的键。 + +类型标记拒绝普通的裸 receiver 误用,开发环境不变式覆盖直接 JavaScript 或强制转换的 dispatch。主体保持显式,因为路由正确性和有用的事件数据是不同的关注点。 + +## Agent 创建:一个事务拥有完整操作 + +创建和恢复是一个具有多个阶段的异步生命周期,而非多个生命周期。`AgentCreationTransaction` 拥有调用方和工厂的活跃性、可选取消、私有资源、发布、回滚,以及每个所有者观察到的记忆化拆除。 + +### 注册表入口是唯一的活跃标识记录 + +AgentRegistry 和 SessionStore 各为每个活跃对象保留一条入口。入口持有稳定 ID、对象、作用域载体,以及属于该对象的少量发布或追加状态。 + +detach 闭包捕获其确切入口。它仅在映射仍指向该入口时才删除,因此旧的 disposer 无法删除一个复用相同 ID 的后续对象。注册表不会重读可变的调用方对象来决定标识。 + +没有预留 API。调用方提供的 ID 在最终入口时被接纳。并发的同 ID 操作可能都完成私有 setup;恰好一个最终 `enter()` 成功,每个失败者回滚其私有资源。前一个 disposer 达到静默后,顺序复用即为有效。 + +### 事务在等待之前就拥有准备工作 + +事务在持久化加载或 setup 可能挂起之前,就被安装到调用方的 Cordis context 和具体的 AgentLoop 工厂下。它还在公开操作结算之前观察可选的创建/恢复信号。 + +创建准备一个新 Session。恢复加载并验证持久化的 Session,然后准备相同的活跃会话标识。两条路径随后构建作用域、agent 和 driver,并调用相同的 setup/发布算法。 + +工厂存储具体的 trace 目标,但通过调用方绑定的 Cordis trace 调用它们。这保留了依赖来源和调用方所有权,而不堆叠 trace 代理。 + +### Setup 是私有世界内的可信组合 + +Setup 接收完整的子 context,可以等待插件激活。它可以注册工具、prompt 段、限制、监听器和其他 effect,但公开契约不支持通过强制转换或内部注册表调用来驱动或发布正在创建中的 agent。 + +事务将异步加载和 setup 与停用进行竞争,而非无限等待外部代码拥有的 promise。如果取消或所有者卸载获胜,即使外部 promise 永不结算,公开创建也会在事务拥有的清理之后拒绝。 + +### 发布有一条有序的提交路径 + +发布按观察者所需的顺序接纳和宣告资源: + +1. 入口 session。 +2. 入口 agent。 +3. 宣告 `session/created`。 +4. 宣告 `agent/created`。 +5. 启用公开驱动。 +6. 发射 `agent/session-start`。 +7. 启动 driver。 + +Agent 在两个注册表和创建通知都达成一致之前绝不驱动。同步监听器可以否决或 dispose 一个所有者;事务记录发布进行中,并等待该回调栈展开后再继续拆除。每个已开始的创建宣告在回滚期间都有匹配的销毁宣告。 + +以下序列图隔离了非显而易见的竞态:同步创建监听器可以在发布调用栈仍拥有两个注册表入口时请求 dispose。拆除必须立即停用,但要等待该栈展开后才停止和分离任何东西。 + +```mermaid +sequenceDiagram + participant Tx as AgentCreationTransaction + participant Registries + participant Listener as Synchronous listener + participant Driver + + Tx->>Tx: mark publication in progress + Tx->>Registries: announce agent/created + Registries->>Listener: invoke inside the same call stack + Listener->>Tx: dispose reentrantly + Tx->>Tx: deactivate, teardown waits for publication + Tx-->>Listener: disposal request accepted + Listener-->>Registries: return + Registries-->>Tx: announcement unwound + Tx->>Tx: resolve publication settlement + Tx->>Driver: stop and drain + Tx->>Registries: detach agent, then session + Tx->>Tx: dispose scope and resolve teardown +``` + +### 拆除在撤销注册之前保留工作 + +每个拆除请求加入一条记忆化路径。顺序为: + +1. 停用创建或驱动,让同步发布完成。 +2. 停止并排空 driver,包括空闲注入刷新。 +3. 分离 agent。 +4. 分离 session。 +5. Dispose agent 作用域。 +6. 退役事务所有权追踪。 + +此顺序让最终的 agent 和 session 事件能使用匹配的作用域监听器,并使持久化观察者在最终刷新完成前保持附加。作用域 dispose 放在最后,因为注册撤销是外部可见的生命期边界。 + +## 会话追加:物化、验证、提交、通知 + +会话事件跨越持久化边界,因此追加操作拥有其数据。算法的其余部分使用一条附加的入口和一个提交点。 + +### 持久化数据一次性物化 + +Session 头部、种子和追加的事件是无损 JSON 数据。Session 构造函数或追加路径在存储前物化并验证它们,并暴露冻结的快照,因此后续调用方的修改无法改变持久化、回放或模型重建。 + +这是一个真实的所有权边界:值离开调用方,可能被持久化,且必须在之后重建相同的请求。这比类型化的同进程回调或注册表定义有意更严格。 + +### 提交前监听器可以否决;提交后观察者不能 + +追加遵循一个序列: + +1. 物化持久化事件和表面意图。 +2. 声明 SessionEntry 并拒绝该入口上的重入追加。 +3. 解析作用域回调并运行内部不变式验证。 +4. 恰好推送一次;这是提交点。 +5. 逐个通知每个观察者,隔离同步和异步失败。 +6. 释放追加状态并兑现发布期间请求的 detach。 + +没有观察者错误能让已提交的事件看起来未提交,一个坏的监听器也无法饿死后续监听器。Session 不变式在提交前暂存其转换,仅当同一事件到达被隔离的提交后观察者时才应用。 + +`flush()` 启动每个持久化监听器并等待所有结果后再报告失败。这种有意的 all-settled 行为防止同步失败饿死另一个后端或最终刷新。 + +## 信任边界:仅在所有权真正变更时复制 + +运行时区分类型化的进程内契约与序列化及持久化边界。这是值和回调的主要简化规则。 + +| 边界 | 所有权规则 | +|---|---| +| 同进程内的类型化服务/插件调用 | 借用 readonly 值和回调 | +| 解析的插件配置或外部文件 | 验证语义和结构输入 | +| 队列中的收件箱消息 | 在异步消费前物化 | +| 模型/工具 JSON 输入或输出 | 在模型/工具边界处物化 | +| 持久化会话或持久化数据 | 在提交前物化并验证 | +| Worker、进程或协议格式消息 | 序列化、验证并拥有解码后的值 | + +测试中构造恶意 getter、在交接后替换类型化回调、或强制转换伪造服务对象的做法本身不定义生产契约。运行时在数据跨越解析器、队列、模型、持久化、文件、worker、进程或协议格式(wire format)边界时保留检查,并在可信进程内依赖 readonly 类型加插件纪律。 + +回调隔离与数据所有权是分开的。监听器是任意扩展代码,即使其参数是可信的也可能抛出异常;发布和提交后路径仍按其事件契约隔离失败。 + +## 工具与 prompt:单一视图、权威组装、已提交的结果 + +工具展示和执行共享一个私有解析器。Prompt 组装仍然是可信的协作式组合:注册表提供有序输入,assembly waterfall 的返回值就是 agent loop(智能体循环)记录和发送的内容。执行仅在策略或结果结算必须单调时才使用独立的单向边界。 + +### 一个解析器定义工具视图 + +私有解析器应用当前展示模式、活跃的全局限制、精确的局部叠加和局部遮蔽。Schema、查找、执行、Code Mode SDK 生成和限制验证都使用该解析器或其限制前的全局名称视图。 + +[subagent 组合控制 RFC](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md#tool-filtering-is-one-live-global-view-rule) 拥有用户可见的 allow/deny 语义。实现要求是一致性:被过滤掉的全局工具不能通过另一条查找路径仍可执行,局部遮蔽的定义就是被展示和执行的同一个定义。 + +`ToolRestriction` 接受 readonly 的 allow/deny 名称并将其编译为内部集合。多个限制取交集。公开的 `visible()` 和 `knownNames()` 方法是不必要的,因为只有注册表需要中间视图。 + +### 工具执行拥有标识和边界物化 + +注册表为每次执行分配一个新的带品牌的 `Symbol` token。嵌套的 Code Mode 调用将外层 token 作为 `parent` 携带,因此结构化输出可以通过标识将内层捕获与其外层 `run_code` 结果关联。 + +注册表分配的新 Symbol 提供无碰撞的执行标识,无需 WeakSet 成员注册表。调用方无法通过 `ToolExecutionInput` 提供执行自身的 token;它们仅在注册表创建后接收流水线拥有的 `ToolExecution`。这是一个可信的类型化契约,而非针对任意强制转换或 JavaScript 调用方的运行时防御。 + +参数在模型/工具 JSON 进入流水线时一次性物化。Pre-、around- 和 post-execute 监听器操作类型化的 execution 和决策。Call ID 关联、审批、单调守卫和 Code Mode 嵌套仍然是显式的关系检查。 + +在最后一个 post-execute 监听器之后,注册表一次性物化并冻结被接受的最终结果。每个同步的 `tools/result` 观察者接收该确切的已提交对象,观察者失败被逐个隔离。外层流水线失败被规范化为已提交的错误结果,因此观察者可以丢弃针对同一权威边界的暂存工作。 + +### Assembly waterfall 拥有最终的模型可见组合 + +SystemPrompt 首先将全局加 agent 的段、变量和工具提供方解析为确定性的注册表贡献。作用域过滤的 `system-prompt/assemble` waterfall 随后可以重排、替换、添加或移除任何段、变量或 schema。其返回的组装结果即为权威;没有后续的恢复步骤,普通 prompt 段、工具定义或提供方结果上也没有终态元数据。 + +这是一个可信的同进程扩展 seam,而非权限边界。修改 Code Mode 的 `run_code` schema 或 `tools:sdk` 指令,或结构化子级的捕获 schema 或指令的监听器,有责任在其返回的组装中保持协议的一致性。ToolRegistry 仍然保留 `run_code` 不受普通工具注册和限制影响,因为那些是注册表不变式,但 assembly 中间件仍然可以自由变换最终的模型可见表面。 + +Scope 直接解决了真正的隔离问题。结构化输出贡献注册在子级的精确作用域中,而 Code Mode 从同一个已解析的工具视图派生其传输和 SDK。第二套命名保护系统需要另一套所有权和碰撞规则来覆盖任意 schema 提供方(包括有意贡献重复名称的提供方),却不创建新的信任边界。 + +### 结构化输出仅提交权威结果 + +结构化输出将子作用域组合与两阶段执行提交相结合。子级在发布前注册其 `structured_output` 工具和指令;可信的 assembly 监听器可以变换这些普通贡献,并有责任在期望子级完成时保持协议。工具体验证候选值并按当前 `ToolExecution` 暂存,但成功捕获仅由不可变的 `tools/result` 观察决定。 + +对于原生调用,观察者仅在该确切执行的最终结果成功时才删除暂存并提交其值。因此 post-execute 阻止或外层流水线失败不会留下已捕获的值。 + +对于 Code Mode SDK 调用,内层成功结果记录 `{ parentToken, value }` 而非提交。观察者等待 token 匹配 `parentToken` 的 `run_code` 执行,仅在该外层最终结果也成功时才提交。程序失败、运行时中止或外层 post-policy 拒绝会丢弃待定值。 + +一旦值处于待定或已提交状态,作用域单调守卫拒绝后续工具调用。提交后,普通串行的 `agent/turn-stop` 监听器在 continuation 和 steering(中途引导)已折叠之后返回停止决策。Schema 验证失败仍然是普通的 `INVALID_ARGS` 工具错误,子级可以在同一轮次内重试。 + +纯 Code Mode 的注册表贡献从原生 wire schema 中省略 `structured_output`,并通过生成的 SDK 暴露它。Assembly waterfall 可以有意改变该展示;执行仍然针对子作用域定义进行验证,监听器拥有其创建的任何替代模型可见路由的一致性。 + +### 三个执行边界有意设为单向 + +Prompt 组装有意是协作式的,但三个执行事实在其可扩展阶段之后需要单向结算: + +| 边界 | 最终权力 | 为何普通监听器顺序不够 | +|---|---|---| +| 工具 pre-policy | 单调拒绝 | 后续监听器不得重新允许已被拒绝的调用 | +| 工具结果 | 观察不可变的已提交结果 | 结构化输出必须仅提交实际逃出流水线的结果 | +| 轮次 continuation | 在普通 continuation 折叠之后停止 | 已提交的终端输出必须结束轮次 | + +`ToolGuard` 是单调策略注册表。已提交的工具观察是上述被隔离的 `tools/result` 点。终端结构化输出监听普通串行的 `agent/turn-stop` 折叠,在正常 continuation 和 steering 决策之后;类型化的监听器契约不需要公开的 `strictSerial()` dispatcher。 + +### Skill 和 approval 服务信任类型化调用方 + +Skill 注册表定义和 approval 策略是 readonly 的同进程契约。它们的服务不克隆回调对象,也不防御交接后的回调替换。 + +Skill 仍然验证外部 skill 文件和解析的提供方输出,通过调用 agent 的工具视图路由目录,并精确 dispose 注册。Approval 仍然解析策略、观察取消、按 `request.agent` 路由 `approval/request`、记录持久化审计对,并隔离应答者和提交后观察者的失败。 + +## Subagent:就绪即 start promise + +Subagent 启动有一次所有权转移。提供方拥有部分资源直到其 start promise 以一个就绪的已发布 run 兑现;调用方拥有返回的 run 并必须 dispose 它。 + +### 服务契约有一个取消通道 + +`SubagentProvider.start()` 和 `SubagentService.start()` 返回 `Promise<SubagentRun>`。Promise 仅在后端建立了它所承诺的子级之后才兑现,因此调用方和 `subagent/start` 观察者从不需要第二个 `run.started` 就绪 promise。 + +`SubagentStartRequest.signal` 是必需的。中止它会在启动期间和就绪之后请求取消。`SubagentRun.dispose()` 也请求取消并等待静默。没有单独的公开 `run.cancel()` 通道。 + +可选的 `sendMessage()` 支持能接受 steering 的活跃后端。可选的 `resume()` 返回 `Promise<SubagentRun>`,因为恢复的子级有相同的异步就绪边界。 + +服务在调用提供方之前验证提供方能力和请求语义。提供方拒绝在拒绝逃出之前清理所有部分资源,且不发射 `subagent/start`/`subagent/end` 对。兑现之后,服务附加结果观察、发射作用域 start 并返回 run。提供方移除阻止后续 start,但不撤销提供方已接受的 run。 + +### 进程内提供方复用核心事务 + +Spawn 和 fork 共享一个进程内 driver。它通过 `parent.ctx` 创建子级,将必需的 signal 传入核心创建事务,并在未发布的 setup 期间安装 persona、工具限制和结构化输出贡献。 + +提供方等待创建并仅返回已发布的 run。在交接时,核心创建分离其仅用于创建的 abort 监听器;提供方在安装活跃 run 监听器之前立即重新检查 signal,因此在那个窄窗口中的 abort 会 dispose 新句柄而非逃脱取消。父级拆除跟随子级,因为操作属于 `parent.ctx`;提供方卸载阻止新 start 但不成为已接受 run 的第二个撤销所有者。Run disposer 取消子级并等待 AgentHandle 的有序拆除。 + +Spawn 使用空会话种子。Fork 使用经验证的已完成轮次前缀。对话种子仅改变历史,不导入作用域、工具、服务或权限。 + +### ACP 提供方拥有进程直到就绪或清理 + +ACP 提供方跨越真实的进程和协议格式边界,因此它保留验证、环境清洗、消息序列化、abort/进程竞争和 kill-to-exit 静默。 + +Start 仅在 `initialize` 和 `newSession` 成功后才 resolve。Abort、spawn 失败、RPC 失败或无效启动响应在拒绝前回收进程。就绪后,result 映射 ACP prompt 结果和流式输出;dispose 请求取消、关闭连接并通过一条记忆化路径等待进程退出。 + +## 工作流与 ACP UI:仅保留独立的异步事实 + +Worker 和编辑器桥接比同进程注册表需要更多状态,因为消息、进程死亡和渲染可以独立结算。它们的状态围绕这些真实事实组织,而非重复的取消协议。 + +### 工作流子级是待定 start 或已发布记录 + +工作流宿主保持待定的提供方 start promise 和已发布的子级记录。子级仅在异步 `SubagentService.start()` 兑现时才从待定变为已发布;被拒绝的 start 清理其部分提供方工作且不产生子级生命周期对。 + +一个宿主拥有的 AbortController 向待定和活跃子级提供必需的 signal。关闭工作流准入中止该 signal,因此没有重复的 `ChildCancel` worker RPC 或显式的宿主侧 `run.cancel()` 扇出。静默等待待定 start 和已发布子级 dispose 两者。 + +Worker 边界仍然序列化请求和结果。宿主保留首个终端结果仲裁、精确的子级计数、worker 死亡处理、优雅终止、迟到/重复消息拒绝和有界清理,因为结果接收、worker 退出和子级静默是真正独立的事实。 + +### 终端结果与物理清理保持分离 + +工作流结果按公开优先级规则记录首个被接受的终端结果。该结果选定后清理可以继续:活跃子级仍需 dispose,worker 仍需终止,慢速外部后端可能超出配置的优雅期限。 + +公开 dispose 在调用回调之前声明其记忆化 promise。Worker 死亡在处理任何排队的迟到子级请求之前关闭准入,合成缺失的生命周期结束,并启动子级/进程清理而不重写已声明的结果。 + +### ACP prompt 结算不依赖渲染成功 + +ACP UI 直接将 prompt 与其观察到的轮次关联。它不从 `logWatermark` 扫描,也不使用会话状态作为第二个调和预言机。 + +Prompt 处理在 transcript(文本记录)渲染的 `finally` 中结算关联。渲染失败可以导致展示失败,但不能跳过 prompt 结算或让会话永久处于进行中状态。对同一持久化的调用方提供的会话 ID 的并发加载仍被排除,因为那是真实的持久化标识竞争,而非 UUID 碰撞问题。 + +## 正确性强制 + +该设计通过类型、运行时逃逸点、生成的契约和行为测试来强制执行。没有哪一层被要求证明它无法观察到的东西。 + +### 类型使常规路径难以误用 + +Readonly 契约描述借用的同进程值。`Scoped<T>` 标记 event receiver,`agentEvents()` 融合载体和主体,工具输入省略注册表拥有的 token,subagent 异步返回类型直接暴露就绪性。 + +TypeScript 无法管控 JavaScript 强制转换、直接 Cordis dispatch、进程消息或持久化文件,因此运行时强制保留在这些逃逸点。 + +### 运行时不变式覆盖跨服务事实 + +不变式插件验证每个声明的作用域事件使用带标记的载体,以及暴露主体的事件族使用匹配的键。Session trace 验证在追加提交前暂存,并在同一事件提交后推进。 + +该插件不通过扫描注册表来管控可信 setup,也不拒绝通过强制转换构造的 prompt assembly 对象。这些检查会将组合契约变成推测性的运行时机制,却不保护真实的外部边界。 + +### 生成的产物使公开契约保持对齐 + +事件目录、服务目录、生产者/消费者矩阵、配置目录、模块图、工具目录、type-equiv 块和作用域事件解析器映射都是从源码生成或受新鲜度门禁约束的。[TypeScript 语义门禁 RFC](../process/2026-07-14-typescript-program-backed-semantic-gates.md) 拥有 Program 构造、语义事件发现和解析器生成规则。 + +行为测试固定了作用域路由和 dispose、最终入口碰撞清理、发布回滚、有序静默、持久化前/后提交行为、跨展示和执行的活跃工具过滤、协作式 prompt 组装、原生和 Code Mode 中的结构化输出提交、异步 subagent 启动和信号取消、worker 终端仲裁、ACP 结算和进程拆除。 + +## 曾考虑的替代方案 + +[7 月 8 日 RFC](2026-07-08-agent-scope-contexts.md#alternatives-considered) 拥有公开扁平作用域契约的替代方案。此处的替代方案关注实现形态。 + +### 使用透明代理作为作用域载体 + +模拟主体的代理必须保持属性、可调用、可构造、私有字段、描述符和代理不变式行为,而监听器路由从不需要这些。一个小型不透明载体保持过滤器和键,而显式事件参数携带主体。 + +### 在 setup 前预留 agent 和 session ID + +预留防止重复的私有 setup 工作,但需要跨服务能力、释放排序、废弃预留清理和已准备对象绑定。ID 由调用方提供,并发复用是调用方错误;最终入口可以选择赢家,而失败的事务干净地回滚。 + +### 对每个类型化的同进程参数做快照 + +通用复制防御有状态 getter 和违反 readonly 契约的调用方,但增加分配、重复验证器和可能遗忘复制的路径。物化属于解析器、队列、模型、持久化、worker、进程和协议格式边界——即所有权真正变更的地方。 + +### 为就绪、取消和 dispose 提供独立控制器 + +并行哨兵可能都镜像一个操作是否活跃。一个事务或 start promise 拥有操作;独立 promise 仅在发布展开、外部工作、终端结果和物理静默可以独立结算时才保留。 + +### 保留同步 subagent start 加 `run.started` + +这将提供方接受与就绪分离,迫使每个消费方注册部分 run、附加结果观察、等待就绪并清理就绪失败。异步 start promise 使提供方到调用方的所有权转移本身成为就绪边界。 + +### 在 assembly 之后恢复选定的 prompt 或工具贡献 + +Waterfall 之后的恢复步骤会在文档化的协作式 seam 之后创建第二套组合规则。正确分配规范的存在或缺失还需要为任意工具 schema 提供方制定所有权和碰撞规则,而这些提供方的普通输出可能包含重复名称。作用域注册已经提供了所需的按 agent 隔离,可信的 assembly 监听器拥有其返回内容的协议一致性,因此命名恢复增加了机制却不建立独立边界。 + +### 用同进程加固替代 worker/进程生命周期守卫 + +Worker 消息、进程死亡和持久化输入确实跨越所有权和序列化边界。首个结果仲裁、验证、环境清洗和静默进程清理即使在敌对的同进程回调机制不存在时仍然必要。 + +## 后果 + +实现更小,其证明与所有权图具有相同的形状。一个键选择一层,一条入口拥有一个活跃注册表对象,一个事务拥有创建,一个解析器拥有工具视图,一个异步 promise 转移 subagent 所有权。 + +### 设计保证的内容 + +- 作用域贡献仅在其精确的 agent 视图中可见,并随该作用域一起 dispose。 +- 创建和恢复不暴露部分配置的句柄;最终入口的失败者和发布失败清理每个已准备的资源。 +- Dispose 在 driver 排空和最终会话工作期间保留作用域监听器和持久化,然后撤销作用域。 +- 持久化、队列、模型、worker、进程和协议格式的值在其真实边界处被拥有;类型化的同进程值遵循 readonly 契约。 +- ToolRegistry 的展示、查找和执行在专家 assembly 变换之前解析相同的活跃视图,已提交的结果有一个不可变的观察点。 +- 注册表贡献是确定性输入,而可信的 assembly waterfall 拥有最终的模型可见组合。 +- Subagent start 仅返回就绪的 run,必需的 signal 取消待定或活跃的工作,dispose 到达后端的静默契约。 +- Worker/进程结果优先级和清理在死亡、迟到消息和有界拆除下保持正确。 + +### 代价与局限 + +作用域感知服务仍然维护全局和按标识键索引的映射,操作必须显式携带其真实 agent。异步创建/恢复和 subagent start 要求调用方等待所有权转移并 dispose 返回的句柄。 + +可信的 `system-prompt/assemble` 监听器可以移除或替换 Code Mode 和结构化输出协议片段。这是有意为之:监听器拥有最终组合,必须保持部署期望仍可用的任何协议。 + +该设计信任同进程中的类型化插件。它不防御任意强制转换、有状态 getter、违反 readonly 契约的修改,或插件有意在支持的组合 API 之外使用环境服务访问。 + +[安全与权限非目标](2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals)仍然是根本性的。这些机制证明注册组合、发布和生命期所有权;它们不证明隔离或父到子的非升级。 diff --git a/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml new file mode 100644 index 0000000000..8c97f0b5ee --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-06-sandbox.md: 29985b9336e7a190c90dc0e9c3b3aa78b6197e8e +2026-07-06-sandbox.zh.md: 4285ae4ceb81ee57dc3ab3d51467f9267743e06e diff --git a/docs/rfc/implemented/feature/2026-07-06-sandbox.md b/docs/rfc/implemented/feature/2026-07-06-sandbox.md index 28f2066ee9..29985b9336 100644 --- a/docs/rfc/implemented/feature/2026-07-06-sandbox.md +++ b/docs/rfc/implemented/feature/2026-07-06-sandbox.md @@ -1,5 +1,7 @@ # RFC: The subprocess sandbox — confinement seam, native runners, escalation, and per-session modes +English | [中文](2026-07-06-sandbox.zh.md) + Status: implemented ## Problem diff --git a/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md b/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md new file mode 100644 index 0000000000..4285ae4ceb --- /dev/null +++ b/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md @@ -0,0 +1,212 @@ +# RFC:子进程沙箱——约束 seam、原生 runner、升级机制与按会话模式 + +Status: implemented + +[English](2026-07-06-sandbox.md) | 中文 + +## 问题 + +一个编码 agent 需要如下产品路径:bash 子进程(以及依附其上的钩子命令)默认在受限的文件沙箱下执行;当且仅当沙箱实际拒绝了某个操作时,模型可以为同一操作请求一次用户批准,获批后以更宽的权限重试一次。本设计刻意不声称覆盖所有工具:fs/web/todo 在进程内执行,`execve` 包装对它们毫无意义(§ 进程内工具);跨工具族的统一边界属于分阶段后续工作(§ 延迟阶段)。如果没有共享词汇,每个工具都会各自重新发明批准字段、拒绝解析、重试匹配和权限状态提示。 + +harness 是一个 SDK,因此约束必须是开发者可**组合**的能力:是否启用沙箱、每个平台使用哪个后端,都应作为一等条目写在叶子 `cordis.yml` 中,而非藏在某个执行器的私有机制里。而首选 runner `bwrap` 恰恰在沙箱最重要的主机上不可用(精简容器、禁用了非特权 userns、LSM 拒绝 `mount`),因此备选 runner 必须随 SDK 一起交付,而不能假设主机已有。 + +仅有约束还留下两个缺口。拒绝后没有升级路径就是死路:模型只能放弃,这会迫使运维人员全局配置 `workspace-write` 或 `danger-full-access`,从而使沙箱形同虚设。而模型可见的旋钮(沙箱模式、批准策略)在 agent 生命周期内会变化——ACP 用户切换按会话设置、运维人员在进程停止期间编辑 `cordis.yml`——模型绝不能基于过时的信念行动:每次请求时的实际状态是什么、agent 存活期间发生了什么变化、无人看管时又发生了什么变化,都需要有明确答案。 + +## 决策 + +一个 seam、一条按平台的本地后端链、一个消费方,加上两个上层杠杆:按调用的升级路径与按会话的运行时模式。以下所有内容均从叶子 `cordis.yml` 组合而来;不触及 `agent-loop`。范围有意限定:本 RFC 命名但不设计的阶段——按会话工作区根目录、跨工具族 fs 强制、`subagent-acp` 消费方、更多环境、Windows 链——列在 § 延迟阶段,各自是后续设计,而非配置旋钮。 + +### 部署方式 + +四条 `cordis.yml` 条目即可将一个无约束的编码 agent 转变为沙箱产品路径;[`examples/acp-agent`](../../../../examples/acp-agent/README.md) 默认使用此组合: + +```yaml +- id: sandbox + name: '@deepseek-ai/dsh-sandbox-local' # the per-platform runner provider (ctx.sandbox) +- id: bash + name: '@deepseek-ai/dsh-bash-sandbox' # the confined executor, replacing dsh-bash-local behind ctx.bash + config: + mode: workspace-write # the deployment default every session starts from + workspaceRoot: !!js process.cwd() # the boundary workspace-write may write under +- id: approval + name: '@deepseek-ai/dsh-user-approval' # the escalation gate's channel (the approval RFC) + config: + policy: ask +- id: permission + name: '@deepseek-ai/dsh-permission' # one product-facing select over both mechanism knobs +``` + +这一替换对 `ctx.bash` 的所有消费方透明:bash 工具、钩子命令和后台任务照常运行,通过提供方返回的包装 argv spawn。删除 `sandbox` 和 `permission` 条目、将 `bash` 替换为 `@deepseek-ai/dsh-bash-local` 即为退出——执行恢复为无约束,升级字段从工具 schema 中消失,因为它们是基于已挂载执行器的能力门控,而非基于配置。仅省略 `approval` 则保留约束但以自身错误文本关闭每次升级;`permission` 还要求 approval seam 和约束执行器同时存在,因此部分组合的 preset 层在加载时即大声失败。 + +配置错误大声失败:`mode` 不在封闭词汇中时在插件加载时被拒绝;主机上没有可用后端时在 `confine()` 阶段(命令 spawn 之前)抛出结构化的 `SANDBOX_UNAVAILABLE`,而非降级为无约束执行。`dsh-sandbox-local` 上的 `runnerCommand` 是运维人员对一个 bwrap 兼容 runner 的显式断言(跳过链和探测);它同时充当 keyless 测试的确定性 fake-runner seam。 + +被拒绝的文件操作返回 `[sandbox: file access denied under <mode> mode]` 标记,并附带不要绕过拒绝的指令。约束执行器添加配对的 `sandbox_permissions` 和 `justification` 字段,用于一次经批准的重试,该重试必须严格宽于会话的有效模式。授权仅放宽该次重试;拒绝则不执行任何内容,返回 `the user rejected escalating this command to "<mode>"`,且不允许再次请求。提示词不声明沙箱模式,以避免基于常驻标签的预防性拒绝。当 `dsh-permission` 被组合时,ACP 暴露一个 `Permissions` 选择器,其 preset 同时写入两个旋钮事件;不匹配的旋钮组合显示为仅可切换离开的 `custom`。只有切换到确定性的 `'never'` 批准策略才会在提示词中声明并叙述。 + +### 设计细节 + +#### 范围界定 + +OS 子进程约束适用于 bash 执行器(包括钩子命令),后续还将适用于 ACP subagent 子进程。文件系统、web 和其他工具在进程内执行,需要在各自的 seam 层面实施策略;argv 包装无法约束一个闭包了 `ctx` 的函数。既有的 bash request/spec 拆分承载按调用的覆盖,而 `tools/pre-execute` 和 approval seam 负责人的决策。 + +#### seam:`ctx.sandbox` + +`dsh-sandbox` 拥有词汇和 `SandboxProvider` 契约:`confine(argv, policy)` 返回调用方应当 spawn 的替代 argv(经过包装,使进程及其所有子进程在约束下运行),加上所选后端达到的 `enforcement` 完整度、其拒绝方言(`denialSignatures`,该后端内核在拒绝文件操作时打印到 stderr 的子串)、以及其 runner 失败方言(`runnerFailureSignatures`,runner **本身**失败——因而命令从未运行——时的自我标识方式);没有可用后端时抛出失败关闭的 `SANDBOX_UNAVAILABLE` 错误,绝不静默放行。词汇:`SandboxMode`(`read-only` / `workspace-write` / `danger-full-access`,仅限文件操作——不声称覆盖网络和进程可见性)、`SandboxEnforcement`(`full` / `partial`)、`SandboxPolicy`(mode + workspace root)。 + +策略随每次**调用**而非提供方携带:两个消费方可以在同一时刻以不同策略约束(bash 在 `read-only` 下运行,而一个受约束的子 agent 保持其状态目录可写),且经批准的升级重试是一次带有更宽策略的新调用——在配置固定的提供方模式下无法表达。 + +该 seam 仅约束**同世界**子进程:后端共享主机的文件系统和内核。容器、microVM 和远程执行器不是此 seam 的后端——它们以环境一致的组替换整个能力实现(`ctx.bash`、`ctx.fs`),因为一个 bash 在容器中运行而 fs 工具写主机的 agent 生活在两个割裂的世界中。 + +留待需要时再决定:网络限制是作为独立的 `network_mode` 到来,还是在某个 runner 同时强制两者后合并进 `sandbox_mode`;以及 `SandboxPolicy` 是现在就增加额外的可写根授权(launcher 已支持 `--rw <path>`),还是等到升级机制需要时再加。 + +#### 本地后端与随附 launcher + +`dsh-sandbox-local` 在提供方生命周期内选择一个平台 runner 并缓存结论。Linux 功能性探测 `bwrap` 然后 Landlock;macOS 使用 Seatbelt。不支持的平台和不可用的 runner 失败关闭。每次包装携带后端特定的拒绝签名和 runner 失败签名,以便 `dsh-bash-sandbox` 区分被拒绝的文件操作与损坏的沙箱。`runnerCommand` 作为运维人员对 bwrap 形状 runner 的断言跳过选择,但缺失或不可执行的命令仍被归类为沙箱失败,绝不无约束地运行负载。 + +launcher 是一个约 300 行的 C 程序(纯 C11,直接使用 Landlock UAPI——除静态链接的 musl 外无其他库,因此审计面仅为该文件加内核的稳定 syscall 契约):`--ro <path>` / `--rw <path>` 授权,`--`,被包装的 argv;它在自身上安装规则集并 `exec`(规则集跨 `execve` 继承,且它在限制前设置 `no_new_privs`);`--probe` 在一个短生命周期子进程中强制最大规则集,仅当内核确实强制时才以 0 退出;launcher 失败以 125 退出且不 exec。 + +Landlock launcher 通过 [`node-addon-landlock-run`](https://www.npmjs.com/package/node-addon-landlock-run) 交付,平台二进制由 npm 选择。该包(package)拥有路径解析、探测和 CLI flag;harness 将沙箱模式映射为授权。将入口点与其二进制一起版本化,使探测解析和启动语法保持对齐。 + +FIXME: Revisit the separate-repository boundary and try to maintain the launcher source and its platform package family inside this monorepo, so the native release surface and harness contract evolve together. + +后端 profile 共享模式契约但在必要的主机授权上有所不同。Landlock 和 Seatbelt 在 read-only 模式下仅允许 `/dev/null`;workspace-write 还允许各自所需的主机临时目录根。每次包装携带后端特定的拒绝签名。Landlock 在较旧的 ABI 无法管控所有操作时报告 partial enforcement,而成功的 bwrap 和 Seatbelt profile 报告 full enforcement。 + +#### bash 消费方 + +`dsh-bash-sandbox` 复用本地进程执行,并请求 `ctx.sandbox` 包装确切的 bash argv。内核拒绝是独立于退出状态的结果事实,仅从所选包装的 stderr 方言推断。Runner 失败优先于拒绝,因为它意味着命令从未运行:前台调用抛出 `SANDBOX_UNAVAILABLE`,而已结算的后台任务为 `bash_output` 设置 `sandbox.runnerFailed`。这使损坏的约束与任务失败和强制拒绝保持区分。 + +模型看到的仅是结果事实:静态工具描述解释拒绝标记(`[sandbox: file access denied under <mode> mode]`),鼓励尝试可能被拒绝的命令,并禁止绕过拒绝重试;当升级字段被公布时,被拒绝的结果还额外携带升级提示本身,使被认可的同轮次重试在决策点被提示,而非依赖模型回忆描述(§ 升级机制)。没有提示词段落声明沙箱模式(§ 按会话模式)。 + +#### 升级机制:拒绝后一次经批准的更宽重试 + +`BashExecRequest.sandboxMode` 是可选的按调用输入;解析后的 spec 使该字段显式。`BashExecutor.sandboxMode` 公布已挂载的执行器能否兑现它,因此只有约束组合才暴露升级。seam 接受任何显式模式;工具拥有「仅更宽」的升级规则。非沙箱执行器诚实地保持无约束。 + +`SandboxBashExecutor.resolve()` 盖章有效模式——升级授权 > 会话覆盖 > 配置默认——使 `run()`/`start()` 读取 spec 而非配置。`danger-full-access` 分支、confine 调用和结果事实都以 spec 的模式为键,且按任务的事实 map 携带每个任务的模式及其包装事实(`notifyTaskDone()` 从 map 条目盖章):一次升级调用——前台或后台——报告它**实际**运行的模式,而每个邻居保持自己的。 + +当约束执行器被挂载时,`bash` 公布配对的 `sandbox_permissions` 和 `justification` 字段。schema 暴露完整的封闭升级词汇,因为有效模式是按会话的;执行拒绝任何不严格宽于该调用有效模式的目标。批准在执行之前解析。`allowed-once` 仅将授权模式盖章到该请求上,而 `rejected`、`cancelled`、`unavailable`、缺失的 approval 服务或缺失的 agent 都以各自不同的结果文本失败关闭。授权不持久化。 + +升级是对被拒绝命令的同轮次重试,使用最窄的足够 `sandbox_permissions` 和一个 `justification`;批准提示是同意步骤。它必须基于实际的拒绝,除非会话已观察到相同的被拒绝访问;禁用或被拒绝的批准终结该命令。重试、批准决策和结果使用既有的工具和批准事件。`dsh-tool-bash` 拥有请求动作,因为执行器 seam 既没有 agent 也没有用户交互所需的 call id。 + +留待后续阶段处理:授权的范围标识超出沙箱模式之外是什么——确切的调用、路径、命令前缀、会话、时间窗口——这是 `allow_always` 授权存储在该选项可被公布之前必须回答的问题;以及如何为通过 `bash_output` 延迟到达的 `run_in_background` 拒绝定义升级。 + +#### 按会话模式:会话日志即存储 + +``` +effective(session) = findLast(the session's own knob events)?.value ?? the composition-config default +``` + +默认值是组合配置(`cordis.yml`)——运维人员拥有,进程范围。运行时切换是**会话范围**的覆盖,记录为该会话自身日志中的一条仅日志事件。重启免疫(恢复会话时回放其日志,覆盖自然恢复,无需追赶机制)和多会话隔离(一个编辑器标签页的 `workspace-write` 不会干扰另一个的 `read-only`)都是构造性的自然结果,且不存在任何外部配置存储。 + +**每个旋钮一种事件,由其领域拥有**——这是每个既有事件族已遵循的可合并扩展 `SessionEventMap` 惯用法(`dsh-user-approval` 中的 `approval/*`、hooks 包中的 `hook/*`): + +```ts +interface SessionEventMap { + 'bash/sandbox-mode': { mode: 'read-only' | 'workspace-write' | 'danger-full-access' } + 'approval/policy': { policy: 'ask' | 'never' } +} +``` + +每个拥有者导出相同的三件套:事件声明、纯 fold(`effectiveSandboxMode(events)` / `effectiveApprovalPolicy(events)`——一个 `findLast`,类型化到领域的封闭联合),以及**唯一的**写入路径(`setSandboxMode(session, mode)` / `setApprovalPolicy(session, policy)`——切换即其事件;没有任何东西在带外修改状态)。无共享拥有者服务、无通用 facts map、无注册表:第三个旋钮只需将约 40 行模式复制到自己的包中。执行在两侧都遵循 fold——bash 工具的按调用盖章将其作为 § 升级机制优先级链的中间层读取,approval seam 的 `'never'` 门控是[批准 RFC](2026-07-06-approval-seam.md) 同一模式的另一侧。 + +沙箱模式不在提示词中叙述;拒绝结果在需要时报告模式,避免基于常驻标签的预防性拒绝。批准策略不同:只有 `'never'` 被声明,因为自动拒绝在行为上与用户的「不」无法区分。策略变更通知被合并,由下一个 pre-step 递送,重启后有基于日志的回退。通知来源从事件位置推断:最后一个 request header 之后的旋钮事件是用户驱动的;未记录的漂移是运维人员或配置驱动的。 + +**编辑器界面**是协议原生的 [Session Config Options](https://agentclientprotocol.com/protocol/session-config-options)——该规范对 session modes 的替代(计划在 ACP v2 中移除),已有 SDK 类型。当 `ctx.permission` 被组合时,bridge 在 `session/new` 和 `session/load` 中公布一个 `permission` 选择器(category `mode`);其选项是部署的 preset 表,其 `currentValue` 是 `PermissionService.current()` 对会话日志加组合默认值的结果。随附的 `workspace-write` 和 `danger-full-access` preset 各自捆绑一个沙箱模式与一个批准策略,并写入两个领域 setter;preset 表之外的旋钮组合报告为仅可切换离开的 `custom`。`session/set_config_option` 通过 permission 服务验证并切换,然后返回完整的刷新状态(规范契约)。 + +**轮次封闭是提交边界。**开放轮次中的切换立即追加。空闲切换保持在 bridge 记录上待定,在下一次 prompt 提交时、assembly 或执行之前追加到开放轮次中;每个旋钮以最后写入为准。开放性来自日志边界而非 `agent.status`,setter 不从 `session/event` 监听器内追加,因为那会重排后续观察者。锚定之前,响应叠加待定值。崩溃丢弃它,重新加载返回持久 fold。 + +#### 进程内工具 + +fs/web/todo 在进程内执行,因此它们的沙箱语义是各自 seam 层面的策略:fs 意图门控按共享模式词汇决策(§ 延迟阶段,跨工具族),使 `read-only` 成为真正的边界而非仅限 bash 的近似——在此之前契约诚实地如此声明。没有通用的按工具沙箱运行时:主机中介的工具仅通过返回主机验证的声明式效果来离开进程,那是一次重写而非包装。 + +FIXME: Revisit this tool-local boundary. The follow-up design needs to determine whether sandboxing becomes a global harness capability that applies uniformly to every tool, instead of expressing in-process enforcement independently at each tool seam. + +### 测试 + +- **单元测试:**固定平台选择和 profile、失败关闭的 runner 分类、按调用事实、升级验证和结果、permission preset fold 和写入透传、叙述器合并、ACP 公布和验证、轮次封闭的配置写入。 +- **Keyless 真实 runner:**在提供方和 bash 消费方层面对 bwrap、Landlock 和 Seatbelt 执行真实文件系统效果测试;packed-install 覆盖率证明注册表 launcher 保持可执行。真实 ACP 组合固定 permission 切换并拒绝未知 preset。CI 拒绝静默全跳过。 +- **With-key:**驱动真实模型、runner、bridge 应答器和磁盘效果通过授权和拒绝的升级;不可用的凭证或 runner 自动跳过。 +- **快照:**固定 permission config-option 协议格式(wire format)、preset 和旋钮事件、prompt delta 和通知、以及两个脚本化的 approval 分支。快照模式以无约束启动,使无关 fixture(测试前置数据)保持平台无关;策略场景显式切换。真实拒绝 stderr 留在平台测试中,因为其方言是 runner 特定的。 + +## 延迟阶段 + +每个阶段在被拾起时获得完整设计,对照当时的代码验证,并在其涉及的层级带上单元测试、真实 API e2e 和快照覆盖率落地。 + +- **按会话工作区根目录**——执行器的写入边界在其生命周期内保持配置固定,而每个 ACP 会话有自己的 cwd;按会话根目录一旦设计完成即搭载同一个按调用策略载体。 +- **跨工具族边界**——fs 意图门控按共享模式决策,使 `read-only`/`workspace-write` 成为 bash 之外的真正边界。 +- **第二个消费方**——`subagent-acp` 可选地约束子 agent(按调用策略;默认无约束——子 agent 必须写入自己的持久化)。 +- **更多环境**——环境一致的能力组示例(如 bash+fs 对一个容器)。 +- **Windows 链**——`PLATFORM_CHAINS.win32` 保留为空(失败关闭);填充它意味着来自 AppContainer/restricted-token 家族的约束 runner,从其自己的仓库按 `node-addon-landlock-run` 模板交付,加上其 profile 方言和拒绝/runner 失败签名。 + +## 曾考虑的替代方案 + +- **命令字符串启发式预检**:否决。无法理解展开/子进程/符号链接;严格尝试(运行它,让内核决定)是唯一可信的拒绝信号。 +- **即使平台仅有一个后端也功能性探测**:否决。探测用于在候选者之间仲裁;只有一个时无需决策,且探测开销对每个会话的首次约束命令征税(对未来重量级后端而言代价过高)。runner 自身执行时的失败关闭拒绝加 `runnerFailureSignatures` 分类承载了安全属性。 +- **提交构建好的 launcher 二进制**:否决。diff 中的二进制不可审查且膨胀历史;经审查的源码 + 原生 CI 构建 + launcher 仓库的字节固定发布演练使二进制远离所有代码树。 +- **安装时编译 launcher**:否决。将 C 工具链强加给每个消费方;仅在碰巧有编译器时才存在的备选不是备选。 +- **从一个构建器交叉编译两种架构**:否决。仅为重建两个约 70 KB 的二进制就需要携带一个固定的交叉工具链(rustup targets、zig 或容器镜像);每架构的原生 runner 已存在,各自构建自己的平台包(`node-addon-require-builtin` 模式,launcher 仓库自己的流水线)。 +- **无备选(bwrap 或失败关闭)**:否决。将失败集中在沙箱最重要的主机上,最终因放弃而降级到 `danger-full-access`。 +- **将机制保留在 `dsh-bash-sandbox` 内部**:否决。阻塞既有的第二个消费方,使未来阶段从一个 bash 插件的配置中读取模式,且无法表达升级。 +- **提供方上的配置固定模式**:否决。每进程一个模式;无法服务具有不同策略的并发消费方,也无法表达一次性放宽重试。 +- **一个接口同时覆盖容器/VM**:否决。`confine(argv)` 预设共享文件系统;环境隔离是作为一致组部署的能力兄弟后端。 +- **通用 ToolRuntime 包装任何工具**:否决。对进程内工具(闭包了 `ctx`)机械上不成立;声明式效果重写对 fs/web/todo 而言不合理。 +- **在执行器内部(`dsh-bash-sandbox`)请求批准**:否决。没有可路由的 `agent`,没有可附加 prompt 的 `callId`;添加它们会让传输 seam 了解会话和 UI——工具层持有两者并拥有面向模型的词汇。 +- **同一工具调用内自动重试**:否决。日志无法重建的隐藏重入:一个 `tool/call` 会产生两次具有不同策略的执行——重试是一次**新的**带有自身参数和结果事实的已记录调用。 +- **无条件公布升级字段**:否决。在 `dsh-bash-local` 下它们是死杠杆——公布 harness 无法兑现的选项会制造注定失败的授权;能力门控仅需注册时一次读取。 +- **默认值相对的升级阶梯(仅公布比执行器注册时默认值更宽的模式)**:否决。按会话覆盖使默认值成为错误的基线——切换到比默认值更窄的会话恰恰失去它需要的杠杆,而在 `danger-full-access` 默认值下字段完全消失,同时一个被覆盖为 `read-only` 的会话仍处于约束中却没有升级路径。枚举固定封闭的目标词汇;严格放宽是针对会话有效模式的按调用执行检查。 +- **按会话动态工具 schema**:否决。schema 设计上是注册表全局的(一套 assembly 词汇、固定 header 快照契约),按会话重新注册只能买到执行时严格放宽检查已保证的东西,代价是按会话的 schema 表面和每次切换的 header 变动。 +- **将重试硬匹配到先前的拒绝**:否决。命令字符串同一性脆弱(引号、`workdir`、env 前缀、作为失败阶段重试的管道)——要么误拒诚实的重试,要么被轻易满足;真正的边界是人看到命令 + 理由。仅在 `allow_always` 授权存储需要机器可检查的范围时才重新考虑。 +- **通用 `env/state` facts map 加拥有者服务**:否决。approval 和 sandbox 独立组合,因此任何一方的状态都不应拖入第三个包;单键 fold 各自是一个 `findLast`,拥有者服务自然消解;没有跨旋钮的不变式,因此原子多键补丁无收益。 +- **通过 `agent/user-message` + 总线事件叙述**:否决。它预设了一个不存在的轮次入口 seam(真正的 seam 是 `agent/prompt-submit`),而 pre-step 的位置以一个监听器同时服务合并的轮次入口通知和轮中即时性约束。 +- **提示词中常驻声明沙箱模式(+ 切换叙述器)**:先交付后移除,基于实际证据:当每个请求中都有 `Bash commands run under the "read-only" file sandbox.` 时,模型拒绝**尝试**被拒绝后可升级的工作(首次手动会话中十二个轮次有五个以零工具调用结束),将沙箱变成了软锁定。拒绝标记在需要时命名模式,升级字段承载恢复路径;批准旋钮保留其声明,因为自动拒绝在行为上与人的「不」无法区分。 +- **用专门的簿记事件追踪「上次告知」**:否决。`request/header*` fold 已记录模型看到的确切 prompt;将封闭的候选句子解析回来替代了第二条簿记流——事件仅在它们**本身即为存储**时才需要。 +- **ACP session modes 而非 config options**:否决。preset 已经是一个部署定义的 config-option 选择器,且 modes 计划在 ACP v2 中移除。 + +## 后果 + +已交付并固定的内容——测试中的各层级分别保障: + +- 被拒绝的命令以 `sandbox_permissions` + `justification` 重试时,通过组合的应答器链提示用户;授权使**该次**调用在更宽模式下运行(结果事实如此报告),而其他所有调用保持各自的有效模式;每种非授权结果产生各自不同的错误文本且不执行任何内容。 +- 升级字段恰好在已挂载的执行器约束时存在;不严格宽于调用有效模式的请求以自身文本失败关闭且不提示任何人;没有 ApprovalService 的部署对升级调用失败关闭,对普通调用不影响。 +- 系统提示词从不声明沙箱模式(批准 `'never'` 策略是唯一被声明的旋钮),且整个交互——header、旋钮事件、通知、批准、结果——仅从会话日志即可重建,除两个旋钮事件外无额外事件类型。 +- N 次空闲切换每个旋钮最多产生一个锚定事件(净零序列不锚定任何事件——客户端回显当前选择的无操作推送不记录任何内容);批准策略切换最多以一条合并通知叙述;轮中沙箱切换由下一次调用的盖章兑现。 +- 恢复的会话的覆盖生效并报告给编辑器,无需特殊处理;进程停止期间变更的默认值在会话的首个新请求前被叙述,归因于运维人员。 +- 两个并发会话永远看不到彼此的状态、通知或配置选项。 +- `agent-loop` 未被触及——一切搭载 `systemPrompt.section`、`SessionEventMap` 合并、`agent.inject()`、`agent/pre-step`、`agent/prompt-submit` 和 ACP handler 表面。 + +代价与已接受的限制: + +- **单一包装的幻觉被有意放弃。**`tools/pre-execute` 包装加 prompt 约定无法解决沙箱批准——正确的设计需要结构化拒绝、原生 runner 探测、按调用策略承载和一致的跨工具族强制,本设计为此付出了代价。 +- **`read-only` 尚不是跨工具族边界。**在 fs 意图门控按共享模式决策之前,该声明仅对 bash 成立;契约诚实地如此声明(§ 进程内工具)。 +- **Windows 没有后端。**其链槽保留为空——失败关闭,绝不穿透;填充它是延迟阶段。 +- **Seatbelt 层级依赖 Apple 已弃用但仍交付的 `sandbox-exec` CLI。**作为 darwin 的唯一候选,它无需探测即被选中,因此未来移除会在执行时作为 runner 失败分类浮现——重新抛出 `SANDBOX_UNAVAILABLE`,命令从未运行;失败关闭,绝不开放。 +- **Landlock 约束的完整度取决于运行内核的 ABI。**报告为 `enforcement: 'partial'` 而非拒绝——这是有意的权衡,使备选在旧内核主机上仍可用。 +- **launcher 作为注册表依赖到达。**通过其自身仓库的发布流水线(经审查的 C 源码、原生 CI 构建器、字节固定的发布演练)加上本仓库的版本固定获得信任——真实内核 e2e 测试腿是通过安装字节为行为背书的。 +- **模型可能过度请求。**在没有拒绝依据的情况下升级,或在 `workspace-write` 足够时选择 `danger-full-access`:描述引导且枚举强制阶梯,但人的 prompt 是实际门控;`approval/asked` 原因使过度请求可审计,且 `prepend` 策略应答器可以自动拒绝部署永远不想要的模式。 +- **公布的目标集是静态的,而有效模式是按会话的**(schema 是注册表全局的)——已处于最宽模式的会话仍被提供这些字段。构造上无害:执行时的严格放宽检查(而非枚举)是安全边界——非放宽请求以自身文本失败且不提示任何人。 +- **授权的升级不等于可工作的沙箱。**不可用的后端即使对授权升级到约束模式也仍然失败关闭——在平台没有链或所有探测失败时于 `confine()` 阶段,在未探测的唯一 runner 拒绝时于执行阶段(归类为沙箱失败而非命令失败)——而授权的 `danger-full-access` 运行根本不触及提供方:此时授权(而非探测)是权威。 +- **空闲切换存在于 bridge 内存中,直到下一次 prompt 提交锚定它。**该窗口内的崩溃将其回退(在 `session/load` 时报告),且永不再提交 prompt 的会话永不持久化它——已接受,loop 拥有的空闲提交轮次留作未来工作(如果持久性成为需求)。 +- **批准叙述器的重启基线解析 prompt 文本。**封闭的候选句子由写入模块本身拥有,因此措辞变更是同一文件中写入器+解析器的协调编辑;header 早于该段落的会话静默采用当前策略而不发通知。 +- **批准段落仍是动态 prompt 表面**(`'never'` 切换会破坏该会话的提供方 prompt 前缀缓存)。已接受:策略切换罕见,且模型基于过时的 `'never'` 行动更糟。沙箱旋钮不再触及 prompt。 +- **模型可能持有关于沙箱模式的过时信念**(没有任何东西宣布切换)。有意接受:下一次尝试的标记或成功会纠正它,而宣布的观察到的失败模式——预防性拒绝——比一次浪费的重试更糟。 + +## FAQ + +- **一个命令返回了 `[sandbox: file access denied under read-only mode]`——它失败了吗?**它**运行了**,内核拒绝了一个文件操作:拒绝是与退出码正交的结果事实。教学禁止绕过它重试;唯一被认可的动作是以升级请求重试同一命令一次。 +- **如何区分损坏的沙箱与失败的命令?**Runner 失败在分类中优先于拒绝:匹配包装的 `runnerFailureSignatures` 的失败运行意味着命令**从未运行**——前台重新抛出结构化的 `SANDBOX_UNAVAILABLE` 并附带 runner 的 stderr 行,后台任务盖章 `sandbox.runnerFailed` 并渲染自己的标记。损坏的沙箱永远不会被读作失败的命令,且命令永远不会无约束运行。 +- **在没有后端的平台上会发生什么——今天的 Windows?**`confine()` 抛出失败关闭的 `SANDBOX_UNAVAILABLE`,命令永不 spawn;`win32` 是保留的**空**链,由测试固定为同样失败关闭,直到 Windows runner 填充它(§ 延迟阶段)。 +- **`bwrap` 已安装在我的主机上但不可用(禁用了非特权 userns、LSM 拒绝 `mount`)——会发生什么?**链探测是功能性的——它构建并强制一个真实 profile 而非检查 `--version`——因此存在但不可用的 `bwrap` 探测失败,选择落到注册表安装的 Landlock launcher,结论在提供方生命周期内缓存。 +- **沙箱限制网络或进程可见性吗?**不——`SandboxMode` 仅声称文件操作;bwrap profile 刻意不 unshare pid,没有后端声称网络。网络限制是否成为自己的旋钮留在 § seam 中开放。 +- **哪些工具实际在约束下运行?**通过 `ctx.bash` 的 OS 子进程——bash 工具,以及传递性的钩子命令。fs/web/todo 在进程内执行,`execve` 包装对它们机械上毫无意义;它们的 `read-only` 语义随跨工具族延迟阶段到来,在此之前契约诚实地声明仅限 bash。 +- **授权的升级会持久化吗?或覆盖后台任务吗?**都不会:授权被请求它的那次调用(前台或后台)消耗,该次调用报告它实际运行的模式,而每个邻居保持自己的。如何为通过 `bash_output` 延迟浮现的后台拒绝**定义**升级,留在 § 升级机制中开放。 +- **编辑器的模式切换何时生效?**轮中:立即追加,由下一次调用的盖章兑现。空闲:保持在 bridge 的会话记录上,在下一次 `agent/prompt-submit` 时锚定到其开放轮次中,N 次切换合并为最多一个事件(净零则无);锚定前崩溃回退它,`session/load` 报告真实状态。模型不被告知——其下一个命令直接在新模式下运行。 +- **重启后什么存活——如果运维人员在进程停止期间改了配置默认值呢?**覆盖从会话日志回放(`effective = fold ?? config`),因此恢复的会话以零追赶机制保持其模式;离线漂移的默认值以与切换相同的方式改变行为(批准策略因被声明,还额外以运维人员/配置归因叙述)。 +- **结果上的 `enforcement: 'partial'` 是什么意思?**所选后端强制其内核 ABI 管控的子集——例如 ABI v3 之前的 Landlock 不管控路径 truncate——并以结构化方式如此声明而非拒绝主机;探测的报告行区分各种情况。bwrap 和 Seatbelt profile 构造上管控所有承诺的文件操作,因此始终报告 `full`。 + +## 先例 + +本设计复制或对比的仓库内先例: + +- [能力 seam RFC](../architecture/2026-06-13-capability-seams.md)——接口/实现/消费方拆分与「不要过早拆分」的时机规则(第二个消费方满足了该规则)。 +- `dsh-bash` 的 request/spec 拆分及其 `owner` 字段([bash 词汇目录](../../../core-data-structures/bash.md))——`sandboxMode` 搭载的按调用载体模板,以及显式 `resolve()` 默认约定。 +- [批准 seam RFC](2026-07-06-approval-seam.md)——升级请求通过的通道;其应答器 waterfall(瀑布式事件)、审计对和单包理由记录在那里。 +- [事件溯源会话](../architecture/2026-06-11-event-sourced-sessions.md)与[轮次封闭不变式](../architecture/2026-06-15-turn-enclosure-invariant.md)——按会话模式 fold 所依赖的日志即存储基础,以及锚定设计遵守的提交边界。 +- [拦截 seam RFC](2026-06-30-interception-seams.md)——`tools/pre-execute` 词汇,升级门控刻意不复用它(升级调用没有自己的 pre-execute 时刻)。 diff --git a/scripts/translation-pairing.manifest.json b/scripts/translation-pairing.manifest.json index c836ec18de..0459512d1e 100644 --- a/scripts/translation-pairing.manifest.json +++ b/scripts/translation-pairing.manifest.json @@ -73,6 +73,7 @@ "docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md", "docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md", "docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md", + "docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md", "docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md", "docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md", "docs/rfc/implemented/feature/2026-06-15-code-mode.md", @@ -92,6 +93,7 @@ "docs/rfc/implemented/feature/2026-07-05-skill-system.md", "docs/rfc/implemented/feature/2026-07-06-approval-seam.md", "docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md", + "docs/rfc/implemented/feature/2026-07-06-sandbox.md", "docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md", "docs/rfc/implemented/feature/2026-07-07-session-prefix.md", "docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md", From 994bb4b07c261cf031c690ca15ee28cfd17e663c Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 19:57:44 +0800 Subject: [PATCH 085/368] fix(code-mode): render deep results iteratively --- ...-20-code-mode-typed-tool-returns.i18n.yaml | 4 +- ...2026-07-20-code-mode-typed-tool-returns.md | 6 +- ...6-07-20-code-mode-typed-tool-returns.zh.md | 6 +- docs/config-catalog.md | 5 +- docs/core-data-structures/code-runtime.md | 2 +- .../code-runtime-worker/README.md | 2 +- .../code-runtime-worker/src/index.ts | 7 +- .../code-runtime-worker/tests/runtime.spec.ts | 2 +- packages/core/tools/README.md | 2 +- packages/core/tools/src/code-mode.ts | 87 ++++++++++++++++++- packages/core/tools/tests/code-mode.spec.ts | 34 +++++++- 11 files changed, 138 insertions(+), 19 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml index 9ce72eca05..843feb7a4c 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.i18n.yaml @@ -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 -2026-07-20-code-mode-typed-tool-returns.md: 9c24b2cdf493ffb904de16e6816438379afd4211 -2026-07-20-code-mode-typed-tool-returns.zh.md: 33d89b1014589535379ecff0821b7574c4dfde9e +2026-07-20-code-mode-typed-tool-returns.md: f902aa4ff8cdaa0979f09850ea15deede5fdf576 +2026-07-20-code-mode-typed-tool-returns.zh.md: 4bdec90960e270f5be03b0a4c30d7c829dd27f6a diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md index 9c24b2cdf4..f902aa4ff8 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md @@ -57,9 +57,9 @@ Binding arguments and resolutions are revalidated as lossless JSON on both sides ### Outer result and output ledger -The runtime accepts an exact lossless JSON completion of any root. Returning `undefined` omits the completion; returning `null` is an explicit result. `run_code` exposes the canonical outer value `{ logs: string[], result?: JsonValue }`. Its Native renderer emits logs first, renders a string result raw, and pretty-prints every other JSON root. +The runtime accepts an exact lossless JSON completion of any root. Returning `undefined` omits the completion; returning `null` is an explicit result. `run_code` exposes the canonical outer value `{ logs: string[], result?: JsonValue }`. Its Native renderer emits logs first, renders a string result raw, and renders every other JSON root with an iterative pretty printer. Total indentation is capped at ten characters and deeper subtrees remain compact, preserving the established shallow text while keeping traversal stack-safe and formatted size linear in the canonical JSON size. -`WorkerCodeRuntime` replaces the former independent log and value caps with configurable `maxOutputBytes`, defaulting to `67_108_864` bytes. The worker preflights the detached completion with bounded JSON measurement, and one host-side hostile-peer ledger accounts the JSON serialization of the outer logs array plus either the completion value or failure diagnostic. Neither stage materializes an over-limit serialized completion. A result at or below the cap is exact. A completion that cannot survive lossless JSON snapshotting fails as `invalid-output`; a value or combined logs/value outcome over the cap fails as `output-limit` rather than becoming inspected or truncated text. +`WorkerCodeRuntime` replaces the former independent log and value caps with configurable `maxOutputBytes`, defaulting to `67_108_864` bytes. The worker preflights the detached completion with bounded JSON measurement, and one host-side hostile-peer ledger accounts the JSON serialization of the outer log-array plus either the completion-value or failure-message payload. Fixed `CodeRunResult` field names, braces, the bounded error-kind tag, and later presentation whitespace are deliberately outside this variable-payload ledger. Neither stage materializes an over-limit serialized completion. A result at or below the cap is exact. A completion that cannot survive lossless JSON snapshotting fails as `invalid-output`; a value or combined logs/value outcome over the cap fails as `output-limit` rather than becoming inspected or truncated text. Logs stream eagerly so a terminated run can retain output already admitted. Native stdout and stderr writes that bypass the worker's patched stream slots use independent pipes, so terminal settlement continues bounded capture until worker termination completes before materializing the result. When the cap is crossed, the runtime returns an explicit bounded failure with the fitting captured prefix. That outer result then traverses the ordinary `run_code` rendering and spill policy, which may save the captured text and expose its configured head/tail preview. The spill layer cannot recover bytes the runtime rejected beyond the hard cap. @@ -105,7 +105,7 @@ The worker performs bounded-depth flat-wire transport and lossless validation bu - Post-execute has separate value and presentation projections; replacing content is not a confidentiality mechanism, so policy must block or replace the value to hide it from programmatic callers. - Intermediate canonical values are execution-local and unavailable to replay because durable events persist only presentation and bounded summaries. - Intermediate values have no byte cap and can exhaust process or worker memory through retention, flat-wire copies, or structured-clone cost. -- The 64 MiB hard cap applies only to outer output; spill cannot recover bytes rejected beyond that cap. +- The 64 MiB hard cap applies only to the outer variable payloads, excluding fixed result-envelope syntax and presentation whitespace; spill cannot recover bytes rejected beyond that cap. - Provider or executor acquisition limits may already have discarded source data before a canonical value reaches Code Mode. - Unsupported MCP output schemas fall back to `JsonValue`; richer Native multimedia projection is deferred. - There is one result card per outer `run_code`, never per nested call. diff --git a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md index 33d89b1014..4bdec90960 100644 --- a/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md +++ b/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.zh.md @@ -57,9 +57,9 @@ worker 暴露的是真正用于 `tools` 绑定失败的 `ToolCallError` 构造 ### 外层结果与输出账本 -运行时接受以任意 JSON 类型为根的精确无损完成值。返回 `undefined` 表示省略完成值;返回 `null` 则是显式结果。`run_code` 暴露规范外层值 `{ logs: string[], result?: JsonValue }`。其 Native 渲染器先输出日志;字符串结果保持原文,其他所有 JSON 根值采用美化格式输出。 +运行时接受以任意 JSON 类型为根的精确无损完成值。返回 `undefined` 表示省略完成值;返回 `null` 则是显式结果。`run_code` 暴露规范外层值 `{ logs: string[], result?: JsonValue }`。其 Native 渲染器先输出日志;字符串结果保持原文,其他所有 JSON 根值则使用迭代式美化渲染器。总缩进长度上限为 10 个字符,更深的子树保持紧凑格式,既保留既有的浅层文本,又确保遍历不受调用栈深度限制,且格式化输出大小与规范 JSON 大小呈线性关系。 -`WorkerCodeRuntime` 以可配置的 `maxOutputBytes` 取代彼此独立的日志与值上限,默认值为 `67_108_864` 字节。worker 会先用有界 JSON 计量对分离后的完成值执行预检,宿主侧则为不可信对端维护一份统一账本,计入外层日志数组以及完成值或失败诊断的 JSON 序列化大小。这两个阶段都不会实际生成超出上限的完成值序列化结果。结果不超过上限时会保持精确。完成值无法通过无损 JSON 快照时,以 `invalid-output` 失败;值本身或日志与值的组合超过上限时,以 `output-limit` 失败,而不会变成检查格式化后或截断的文本。 +`WorkerCodeRuntime` 以可配置的 `maxOutputBytes` 取代彼此独立的日志与值上限,默认值为 `67_108_864` 字节。worker 会先用有界 JSON 计量对分离后的完成值执行预检,宿主侧则为不可信对端维护一份统一账本,计入外层日志数组的 JSON 序列化大小,以及完成值或失败消息的可变负载。固定的 `CodeRunResult` 字段名、花括号、有界的错误类型标签及后续展示空白有意不计入这份可变负载账本。这两个阶段都不会实际生成超出上限的完成值序列化结果。结果不超过上限时会保持精确。完成值无法通过无损 JSON 快照时,以 `invalid-output` 失败;值本身或日志与值的组合超过上限时,以 `output-limit` 失败,而不会变成检查格式化后或截断的文本。 日志会在产生时立即流出,因此运行被终止时仍可保留已经纳入额度的输出。绕过 worker 中已改写流写入入口的原生 stdout 和 stderr 写入会经由彼此独立的管道传输,因此运行时在终态结算期间仍会继续在上限内捕获输出,直至 worker 完全终止,然后才组装结果。超过上限后,运行时会返回一个显式的有界失败,并携带可容纳的已捕获前缀。该外层结果随后通过普通的 `run_code` 渲染与输出落盘策略;策略可以保存已捕获的文本,并暴露其配置指定的头尾预览。输出落盘层无法恢复运行时在硬上限之外拒绝的字节。 @@ -105,7 +105,7 @@ worker 会以嵌套深度有界的扁平协议格式传输数据并执行无损 - Post-execute 分别提供值投影与展示投影;替换内容不是保密机制,因此策略若需向程序化调用方隐藏内容,就必须阻止调用或替换值。 - 中间规范值仅存在于执行期间,无法用于回放,因为持久事件只存储展示和有界摘要。 - 中间值没有字节上限,可能因值的保留、扁平协议格式副本或结构化克隆开销而耗尽进程或 worker 内存。 -- 64 MiB 硬上限只适用于外层输出;输出落盘无法恢复超出该上限后被拒绝的字节。 +- 64 MiB 硬上限只适用于外层可变负载,不计固定的结果封装语法与展示空白;输出落盘无法恢复超出该上限后被拒绝的字节。 - 提供方或执行器的采集上限可能在规范值到达 Code Mode 前就已丢弃部分源数据。 - 不支持的 MCP 输出 schema 会回退为 `JsonValue`;更丰富的 Native 多媒体投影留待后续实现。 - 每个外层 `run_code` 只有一张结果卡片,嵌套调用不会各自生成卡片。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 10a4430ff2..70e90d42c4 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -294,7 +294,10 @@ export interface Config { * nobody will resolve). */ maxWallMs?: number - /** Hard cap for the combined serialized outer logs, completion value, and failure diagnostic. */ + /** + * Hard cap for serialized log-array, completion-value, and failure-message payloads; + * fixed result-envelope syntax is excluded. + */ maxOutputBytes?: number /** The worker's max old-generation heap in MiB (`resourceLimits`); overflow kills the worker, surfacing as kind `'worker-exit'`. */ maxOldGenerationSizeMb?: number diff --git a/docs/core-data-structures/code-runtime.md b/docs/core-data-structures/code-runtime.md index 715134d328..d9ddc6c9eb 100644 --- a/docs/core-data-structures/code-runtime.md +++ b/docs/core-data-structures/code-runtime.md @@ -97,7 +97,7 @@ type CodeBindingFunction = (args: unknown) => Promise<CodeJsonValue> ## Captured output and the failure taxonomy -Logs are plain strings in emission order. The runtime captures the program's console and stream output, but channel and console-method metadata are not part of the seam because consumers render only the text. Implementations cap the serialized outer logs plus completion or diagnostic; overflow is an explicit failure rather than in-band value substitution. +Logs are plain strings in emission order. The runtime captures the program's console and stream output, but channel and console-method metadata are not part of the seam because consumers render only the text. Implementations cap the serialized outer log-array plus completion-value or failure-message payload; fixed result-envelope syntax and consumer presentation whitespace are not part of that variable-payload ledger. Overflow is an explicit failure rather than in-band value substitution. Failure kinds are **orthogonal outcomes reported independently** (per [defensive-patterns](../defensive-patterns.md)): a budget expiry is not an exception, an abort is not a timeout, and a substrate death (e.g. OOM) is neither: diff --git a/packages/code-runtime/code-runtime-worker/README.md b/packages/code-runtime/code-runtime-worker/README.md index f4e7e6ebda..4936903d2a 100644 --- a/packages/code-runtime/code-runtime-worker/README.md +++ b/packages/code-runtime/code-runtime-worker/README.md @@ -23,7 +23,7 @@ Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at - **The port assumes a hostile peer** — model code can reach `parentPort` and forge traffic, so every inbound message is shape-validated and REBUILT before anything reads it (`null`, primitives, junk types, and malformed payloads drop without a throw; forged extra fields never ride along), the host answers each call id at most once, resolves binding names as OWN properties only (a forged `constructor` cannot walk a prototype chain), drops post-settlement replies, and validates every binding resolution and completion as lossless JSON. Forged `log`/`done` messages cannot bypass the outer cap: the host repeats validation and accounts every admitted log plus the completion or diagnostic. Worker-side namespaces are null-prototype with `defineProperty`, so `__proto__`-shaped binding names are ordinary keys. - **Two independent budgets, because the peer is hostile** — `computeMs` meters the worker's MEASURED busy time (`worker.performance.eventLoopUtilization()` polling): a hot loop cannot hide behind a pending decoy dispatch, and a program awaiting a slow tool accrues nothing. `maxWallMs` backstops what busy time cannot see (awaiting a promise nobody resolves). Both funnel into `worker.terminate()`, which ends hot synchronous loops too; heap overflow surfaces as the worker's OOM exit (`kind: 'worker-exit'`). - **Intermediate binding values are complete JSON** — binding arguments and resolutions undergo iterative lossless-JSON validation, flatten into a bounded-depth pre-order wire value for structured clone, and rebuild iteratively on the other side. They have no byte, JavaScript call-stack, or nested structured-clone depth cap. They never enter the outer-output ledger or model context; provider/executor acquisition bounds and process/worker memory remain the limits. -- **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. Native writes that bypass the patched stream slots arrive on pipes independent of the completion port; settlement therefore continues bounded pipe capture until worker termination completes before materializing the result. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure diagnostic. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. +- **Logs stream eagerly into one outer ledger** — console/stdout/stderr text crosses the port in emission order, so a timed-out or killed program still shows what it printed. Native writes that bypass the patched stream slots arrive on pipes independent of the completion port; settlement therefore continues bounded pipe capture until worker termination completes before materializing the result. `maxOutputBytes` accounts the JSON serialization of the outer `logs` array plus the completion value or failure-message payload; fixed `CodeRunResult` field names, braces, the bounded error-kind tag, and later presentation whitespace are outside that variable-payload ledger. At or below the cap the exact value returns; a lossy completion is `invalid-output`, and a combined overflow is `output-limit` rather than a substituted inspected string. The failure retains the fitting captured prefix and later follows the normal outer `run_code` spill policy. - **Empty environment** — the worker gets `env: {}` and `execArgv: []`: no ambient credentials (stronger than the scrubbed-env rule for spawned commands) and no inherited loader flags. - **Dispose to quiescence** — teardown fails in-flight runs as `abort` and AWAITS each worker's exit before resolving. diff --git a/packages/code-runtime/code-runtime-worker/src/index.ts b/packages/code-runtime/code-runtime-worker/src/index.ts index 80511754e6..4f842e69eb 100644 --- a/packages/code-runtime/code-runtime-worker/src/index.ts +++ b/packages/code-runtime/code-runtime-worker/src/index.ts @@ -38,7 +38,10 @@ export interface Config { * nobody will resolve). */ maxWallMs?: number - /** Hard cap for the combined serialized outer logs, completion value, and failure diagnostic. */ + /** + * Hard cap for serialized log-array, completion-value, and failure-message payloads; + * fixed result-envelope syntax is excluded. + */ maxOutputBytes?: number /** The worker's max old-generation heap in MiB (`resourceLimits`); overflow kills the worker, surfacing as kind `'worker-exit'`. */ maxOldGenerationSizeMb?: number @@ -56,7 +59,7 @@ type ResolvedConfig = Required<Config> */ const ELU_POLL_INTERVAL_MS = 25 -/** Smallest cap that can represent the empty logs array plus an empty JSON failure diagnostic. */ +/** Smallest cap that can represent the counted payloads: an empty logs array plus an empty JSON failure message. */ const MIN_OUTPUT_BYTES = 4 /** ECMAScript reserved words that cannot be async-function parameter names — rejected as binding globals. */ diff --git a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts index f0c8fcf98f..45b45520e0 100644 --- a/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts +++ b/packages/code-runtime/code-runtime-worker/tests/runtime.spec.ts @@ -656,7 +656,7 @@ describe('WorkerCodeRuntime — seam misuse and lifecycle', () => { await expect(ctx.plugin(WorkerCodeRuntime, { computeMs: -1 })).rejects.toThrow(/positive number/) }) - it('requires maxOutputBytes to fit the smallest outer failure envelope', async () => { + it('requires maxOutputBytes to fit the smallest counted outer payloads', async () => { const ctx = new Context() await expect(ctx.plugin(WorkerCodeRuntime, { maxOutputBytes: 3 })).rejects.toThrow(/safe integer of at least 4/) await expect(ctx.plugin(WorkerCodeRuntime, { maxOutputBytes: 4.5 })).rejects.toThrow(/safe integer of at least 4/) diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 8151d79787..a55c9ae519 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -117,7 +117,7 @@ Under `code` or `both`, the registry exposes the reserved `run_code` transport a - **The SDK section** (`tools:sdk`, order 150): a lazy prompt section regenerating, at each assembly, `JsonValue`, exact `ToolArgsMap` / `ToolOutputMap`, `ToolName`, the `ToolCallError` declaration, and a mapped `tools` namespace for the calling scope's visible end capabilities (exotic names via quoted keys), plus fixed usage instructions. Deterministic — lexicographic tool order, byte-identical text for an unchanged tool set (prefix-cache-friendly). The codegen (`jsonSchemaToTs`, exported) handles every unified schema construct and degrades unsupported raw constructs to `unknown`, never throwing during prompt assembly. - **The dispatch bridge** (`run_code`'s execute): every binding call is snapshotted as lossless JSON before dispatch (`undefined`, `BigInt`, cycles, sparse arrays, `-0`, and exotic objects reject that one call), serialized through a per-run queue (even `Promise.all` executes underlying calls one at a time in submission order), given the outer execution's opaque token as `parent`, and run through the complete pre-execute → guards → execute → post-execute → result pipeline. A success returns the final canonical value after policy; a failure reaches the worker as one message and becomes `ToolCallError(toolName, message)`. Each sub-call is logged as a `tool/code-dispatch` session event with deterministic id `<parent>:code:<n>` and a bounded Native-content summary; `deriveMessages()` does not surface that event or persist the value. Token correlation lets commit-style observers defer an inner success until the final `run_code` result without exposing the live outer execution; ordinary tool side effects are not rolled back. Every sub-call `additionalContexts` entry is deferred through the outer `ToolRunContext` in dispatch order; the loop appends those contexts only after the parent `run_code` result, preserving adjacency and retaining each source/meta even when the program later fails. - **Settlement discipline**: the bridge owns a run-scoped abort that follows the outer signal in and fires when the run settles for any reason, so a budget expiry aborts an in-flight sub-tool instead of orphaning it; the bridge then drains its queue BEFORE returning, so every `tool/code-dispatch` lands inside the open turn. A failed run throws `CodeRunFailedError` (`code: 'CODE_RUN_FAILED'`, message = the failure kind + captured logs), which the pipeline converts to a structured `isError` the model self-corrects from. -- **Result boundary**: intermediate binding values cross the worker boundary whole and have no per-binding byte cap. `run_code` returns canonical `{ logs: string[], result?: JsonValue }`; strings render raw, every other present JSON root renders as pretty JSON, `null` remains explicit, and absent `result` means the program returned `undefined`. The worker's configurable `maxOutputBytes` (default 64 MiB) applies only to the combined serialized outer logs, completion, or failure diagnostic; invalid and over-limit completions fail explicitly, and only this outer result is eligible for ordinary spill. +- **Result boundary**: intermediate binding values cross the worker boundary whole and have no per-binding byte cap. `run_code` returns canonical `{ logs: string[], result?: JsonValue }`; strings render raw, every other present JSON root renders through a stack-safe pretty JSON traversal whose total indentation is capped at ten characters (deeper subtrees stay compact), `null` remains explicit, and absent `result` means the program returned `undefined`. The worker's configurable `maxOutputBytes` (default 64 MiB) applies only to the combined serialized outer log-array, completion-value, or failure-message payloads; fixed result-envelope syntax and presentation whitespace are outside that ledger. Invalid and over-limit completions fail explicitly, and only this outer result is eligible for ordinary spill. ### Parallel execution diff --git a/packages/core/tools/src/code-mode.ts b/packages/core/tools/src/code-mode.ts index 4d05236e18..44a9839b02 100644 --- a/packages/core/tools/src/code-mode.ts +++ b/packages/core/tools/src/code-mode.ts @@ -102,9 +102,94 @@ function jsonNormalizeArgs(value: unknown): { dispatched: unknown; logged: unkno return { dispatched: structuredClone(snapshot), logged: structuredClone(snapshot) } } +/** Two-space JSON presentation, matching the existing shallow `run_code` text contract. */ +const JSON_INDENT = ' ' + +/** + * ECMAScript caps `JSON.stringify`'s `space` string at ten characters. The + * renderer also caps TOTAL indentation there, compacting deeper subtrees, so + * formatted output remains linear in the canonical JSON size. + */ +const MAX_JSON_INDENT_CHARS = 10 + +/** A pending fragment in the iterative JSON presentation traversal. */ +type JsonRenderTask = + | { kind: 'text'; text: string } + | { kind: 'value'; value: JsonValue; depth: number; compact: boolean } + +/** Render one non-string JSON root without recursive traversal or unbounded indentation growth. */ +function renderJsonValue(value: Exclude<JsonValue, string>): string { + const chunks: string[] = [] + const tasks: JsonRenderTask[] = [{ kind: 'value', value, depth: 0, compact: false }] + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'text') { + chunks.push(task.text) + continue + } + + const current = task.value + if (current === null || typeof current === 'boolean' || typeof current === 'number') { + chunks.push(String(current)) + continue + } + if (typeof current === 'string') { + chunks.push(JSON.stringify(current)) + continue + } + + const compact = task.compact || (task.depth + 1) * JSON_INDENT.length > MAX_JSON_INDENT_CHARS + const childDepth = task.depth + 1 + if (Array.isArray(current)) { + chunks.push('[') + if (current.length === 0) { + chunks.push(']') + continue + } + tasks.push({ kind: 'text', text: compact ? ']' : `\n${JSON_INDENT.repeat(task.depth)}]` }) + for (let index = current.length - 1; index >= 0; index--) { + const item = current[index] + /* v8 ignore next -- canonical JsonValue arrays are dense. */ + if (item === undefined) throw new Error('cannot render a sparse JSON array') + tasks.push({ kind: 'value', value: item, depth: childDepth, compact }) + tasks.push({ + kind: 'text', + text: compact + ? index === 0 ? '' : ',' + : `${index === 0 ? '\n' : ',\n'}${JSON_INDENT.repeat(childDepth)}`, + }) + } + continue + } + + const keys = Object.keys(current) + chunks.push('{') + if (keys.length === 0) { + chunks.push('}') + continue + } + tasks.push({ kind: 'text', text: compact ? '}' : `\n${JSON_INDENT.repeat(task.depth)}}` }) + for (let index = keys.length - 1; index >= 0; index--) { + const key = keys[index] + /* v8 ignore next -- the loop is bounded by the captured key count. */ + if (key === undefined) throw new Error('cannot render a missing JSON object key') + const item = current[key] + /* v8 ignore next -- canonical JsonValue records contain no undefined properties. */ + if (item === undefined) throw new Error('cannot render an undefined JSON object property') + tasks.push({ kind: 'value', value: item, depth: childDepth, compact }) + tasks.push({ + kind: 'text', + text: compact + ? `${index === 0 ? '' : ','}${JSON.stringify(key)}:` + : `${index === 0 ? '\n' : ',\n'}${JSON_INDENT.repeat(childDepth)}${JSON.stringify(key)}: `, + }) + } + } + return chunks.join('') +} + /** Render one present program completion value for the model-facing result text. */ function renderValue(value: JsonValue): string { - return typeof value === 'string' ? value : JSON.stringify(value, null, 2) + return typeof value === 'string' ? value : renderJsonValue(value) } /** The run_code result's `meta` payload (JSON-serializable; `presentResult` narrows it back). */ diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index 70f86ef87d..20e9c7e223 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -10,7 +10,7 @@ import ToolRegistry, { CodeRunFailedError, RUN_CODE_NAME, TOOL_ABORTED_BEFORE_DI import type { Config, PostToolDecision, ToolExecutionResult } from '@deepseek-ai/dsh-tools' import type { Agent } from '@deepseek-ai/dsh-agent' import { Session, SessionId } from '@deepseek-ai/dsh-session' -import type { SessionEventMap } from '@deepseek-ai/dsh-session' +import type { JsonValue, SessionEventMap } from '@deepseek-ai/dsh-session' const testToolSignal = new AbortController().signal @@ -860,10 +860,17 @@ describe('the run_code dispatch bridge', () => { it('renders every non-string JSON root as pretty JSON while preserving strings raw', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) - runtime.behavior = () => Promise.resolve({ logs: [], value: { n: 42 } }) - expect((await runCode(ctx, 'object')).content[0]).toEqual({ type: 'text', text: '{\n "n": 42\n}' }) + runtime.behavior = () => Promise.resolve({ logs: [], value: { n: 42, ok: true } }) + expect((await runCode(ctx, 'object')).content[0]).toEqual({ type: 'text', text: '{\n "n": 42,\n "ok": true\n}' }) + runtime.behavior = () => Promise.resolve({ logs: [], value: {} }) + expect((await runCode(ctx, 'empty object')).content[0]).toEqual({ type: 'text', text: '{}' }) + const nested = { outer: [{ inner: true }] } + runtime.behavior = () => Promise.resolve({ logs: [], value: nested }) + expect((await runCode(ctx, 'nested')).content[0]).toEqual({ type: 'text', text: JSON.stringify(nested, null, 2) }) runtime.behavior = () => Promise.resolve({ logs: [], value: ['x', 2] }) expect((await runCode(ctx, 'array')).content[0]).toEqual({ type: 'text', text: '[\n "x",\n 2\n]' }) + runtime.behavior = () => Promise.resolve({ logs: [], value: [] }) + expect((await runCode(ctx, 'empty array')).content[0]).toEqual({ type: 'text', text: '[]' }) runtime.behavior = () => Promise.resolve({ logs: [], value: null }) expect((await runCode(ctx, 'null')).content[0]).toEqual({ type: 'text', text: 'null' }) runtime.behavior = () => Promise.resolve({ logs: [], value: 'raw' }) @@ -874,6 +881,27 @@ describe('the run_code dispatch bridge', () => { expect(absent.isError ? undefined : absent.value).toEqual({ logs: [] }) }) + it('renders deeply nested JSON without recursive traversal or quadratic indentation', async () => { + const { ctx, runtime } = await setup({ mode: 'code' }) + let value: JsonValue = { + emptyArray: [], + emptyObject: {}, + pair: ['leaf', 2], + record: { first: true, second: null }, + } + for (let depth = 0; depth < 5_000; depth++) value = [value] + runtime.behavior = () => Promise.resolve({ logs: [], value }) + + const result = await runCode(ctx, 'deep result') + + expect(result.isError).toBe(false) + const text = (result.content[0] as { type: 'text'; text: string }).text + expect(text.startsWith('[\n [\n [')).toBe(true) + expect(text).toContain('"leaf"') + expect(text.endsWith(']')).toBe(true) + expect(text.length).toBeLessThan(11_000) + }) + it('short-circuits a pre-aborted outer signal before the code runtime', async () => { const { ctx, runtime } = await setup({ mode: 'code' }) const calls = registerEcho(ctx) From 93f1eaa9726d40be58c745f3d9aa887f0afd36b9 Mon Sep 17 00:00:00 2001 From: Yichen Jiang <jyc132780208@sina.com> Date: Wed, 22 Jul 2026 20:28:40 +0800 Subject: [PATCH 086/368] fix(gui): keep sidebar controls when collapsed --- ...2-collapsed-sidebar-control-rail.i18n.yaml | 6 ++ ...26-07-22-collapsed-sidebar-control-rail.md | 29 ++++++ ...07-22-collapsed-sidebar-control-rail.zh.md | 29 ++++++ apps/web/tests/smoke-fixture.e2e.ts | 25 ++++- packages/client/ui-layout/README.md | 2 +- .../ui-layout/src/client/AppFrame.module.css | 9 +- .../client/ui-layout/src/client/AppFrame.tsx | 6 +- .../client/ui-layout/src/client/columns.ts | 20 ++-- packages/client/ui-layout/src/client/index.ts | 3 +- .../client/ui-layout/tests/app-frame.spec.tsx | 11 ++- .../client/ui-layout/tests/columns.spec.ts | 23 +++-- packages/client/ui-sidebar/README.md | 4 +- .../src/client/SidebarRoot.module.css | 22 +++++ .../ui-sidebar/src/client/SidebarRoot.tsx | 96 ++++++++++++------- .../ui-sidebar/src/client/contract/slots.ts | 2 + .../client/ui-sidebar/src/client/index.ts | 1 + .../client/ui-sidebar/tests/apply.spec.tsx | 8 +- .../ui-sidebar/tests/sidebar-root.spec.tsx | 20 +++- 18 files changed, 240 insertions(+), 76 deletions(-) create mode 100644 .agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.i18n.yaml create mode 100644 .agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.md create mode 100644 .agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.zh.md diff --git a/.agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.i18n.yaml new file mode 100644 index 0000000000..5ae814d291 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-22-collapsed-sidebar-control-rail.md: 27e7d0e18a20b2ea6de8128f9c3518279ec21aca +2026-07-22-collapsed-sidebar-control-rail.zh.md: bfbb5230f952e49960142bb5ce090dc6753487ec diff --git a/.agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.md b/.agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.md new file mode 100644 index 0000000000..27e7d0e18a --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.md @@ -0,0 +1,29 @@ +# Agent Note: A collapsed sidebar retains its control rail + +Status: implemented + +English | [中文](2026-07-22-collapsed-sidebar-control-rail.zh.md) + +## Problem + +The sidebar close action persisted `open: false`, and the layout mapped that preference to a zero-width grid track. The only sidebar toggle and the settings entry both lived inside that clipped track, so closing the sidebar removed every visible recovery control. Reloading preserved the closed preference and reproduced the lockout. + +## Decision + +The layout maps a closed sidebar to the fixed `SIDEBAR_COLLAPSED` width of 60px: one 28px icon control between the sidebar's 16px horizontal paddings. The compact rail participates in the concession solver and retains its right border, while the stored expanded width remains untouched. + +`AppFrame` marks the sidebar collapsed from the persisted `open` preference rather than from a zero resolved width. It keeps the sidebar slot mounted but removes the resize handle while collapsed. + +`SidebarRoot` subscribes to the derived open boolean. Its collapsed render removes the brand, creation controls, search, and session tree from the rendered and accessibility trees; the top control changes to `Expand sidebar`, and the bottom `Settings` control remains in the rail. + +## Alternatives considered + +- **Render an expand button over the center column** — rejected because it recovers only the toggle, not the persistent settings area, and splits sidebar chrome across two package owners. +- **Keep a zero-width grid track and let the rail overflow it** — rejected because the rail would overlap the center column and leave hit testing and responsive geometry disconnected from the grid. +- **Keep the complete sidebar tree mounted and hide it with clipping** — rejected because hidden controls remain in the semantic tree and continue subscribing and rendering even though only two controls belong in the collapsed state. + +## Consequences + +- A collapsed sidebar reserves 60px instead of yielding the entire width to the center column. Expanding restores the persisted width and drag behavior. +- The settings entry remains visible but retains its existing placeholder behavior; this change does not introduce an account or settings screen. +- Layout solver tests pin the compact width, sidebar component tests pin the visible controls, and the keyless real-bundle web smoke test pins collapse and recovery through the assembled client. diff --git a/.agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.zh.md b/.agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.zh.md new file mode 100644 index 0000000000..bfbb5230f9 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-07-22-collapsed-sidebar-control-rail.zh.md @@ -0,0 +1,29 @@ +# Agent Note: 侧边栏折叠后保留控制栏 + +Status: implemented + +[English](2026-07-22-collapsed-sidebar-control-rail.md) | 中文 + +## 问题 + +侧边栏关闭操作会持久化 `open: false`,布局再将该偏好映射为宽度为零的网格轨道。侧边栏唯一的开关与设置入口都位于这个被裁切的轨道内,因此关闭侧边栏会移除所有可见的恢复控件。页面重新加载时仍会读取关闭偏好,从而再次陷入无法恢复的状态。 + +## 决策 + +布局将关闭的侧边栏映射为固定的 `SIDEBAR_COLLAPSED` 宽度 60px:在侧边栏两侧各 16px 的水平内边距之间放置一个 28px 的图标控件。紧凑控制栏参与空间收缩求解,并保留右侧边框;已存储的展开宽度保持不变。 + +`AppFrame` 根据持久化的 `open` 偏好标记侧边栏是否折叠,而不是根据求解后的宽度是否为零来判断。它让侧边栏插槽保持挂载,但在折叠时移除尺寸调整手柄。 + +`SidebarRoot` 订阅派生的布尔型打开状态。折叠状态下的渲染会将品牌标识、创建控件、搜索框和会话树从渲染树与可访问性树中移除;顶部控件变为 `Expand sidebar`,底部的 `Settings` 控件则留在控制栏中。 + +## 曾考虑的替代方案 + +- **在中心列上方渲染展开按钮**:不予采纳,因为这只能恢复开关,无法保留常驻设置区域,同时还会让侧边栏 UI 由两个包(package)分别持有。 +- **保留宽度为零的网格轨道,让控制栏溢出显示**:不予采纳,因为控制栏会与中心列重叠,还会使命中测试和响应式几何关系脱离网格布局。 +- **保持完整侧边栏树挂载,并通过裁切将其隐藏**:不予采纳,因为隐藏控件仍留在语义树中,而且会继续订阅和渲染,尽管折叠状态下只需要两个控件。 + +## 后果 + +- 折叠的侧边栏占用 60px,而不是把全部宽度让给中心列。展开时恢复持久化宽度与拖动行为。 +- 设置入口持续可见,但保留既有占位行为;本次改动不提供账户或设置页面。 +- 布局求解器测试固定紧凑宽度,侧边栏组件测试固定可见控件,基于真实构建产物的无密钥 Web 冒烟测试则通过组装后的客户端固定折叠与恢复行为。 diff --git a/apps/web/tests/smoke-fixture.e2e.ts b/apps/web/tests/smoke-fixture.e2e.ts index 0c32be5310..d6ec80d7ad 100644 --- a/apps/web/tests/smoke-fixture.e2e.ts +++ b/apps/web/tests/smoke-fixture.e2e.ts @@ -1,9 +1,9 @@ // Keyless boot-chain smoke over the REAL carrier: startWebServer + web-plugins // registry surface + __DSH_BOOT__ injection + built shell dist in a real // chromium. First describe: manifest injection + fail-loud half. Second -// describe: the settled success pass — five REAL tsdown bundles (the -// infrastructure four + layout) load through the DI chain in ?fixture mode -// and the three-column frame appears in one flip. The full conversation +// describe: the settled success pass — six REAL tsdown bundles (the +// infrastructure four + layout/sidebar) load through the DI chain in ?fixture +// mode and the three-column frame appears in one flip. The full conversation // round lands in smoke-real under the W5 real-host standard. import { existsSync } from 'node:fs' import { fileURLToPath } from 'node:url' @@ -17,13 +17,14 @@ import { DIST_INDEX, probeFreePort, requireDist, saveFailureShot } from './suppo const bundlePath = (dir: string): string => fileURLToPath(new URL(`../../../packages/client/${dir}/lib/client.js`, import.meta.url)) -/** id ↔ bundle table for the success pass (immediately four + layout). */ +/** id ↔ bundle table for the success pass (immediately four + layout/sidebar). */ const REAL_PLUGINS: { id: string; dir: string; inject: string[]; immediately?: boolean }[] = [ { id: '@deepseek-ai/dsh-client-connection', dir: 'connection', inject: [], immediately: true }, { id: '@deepseek-ai/dsh-client-runtime', dir: 'runtime', inject: ['@deepseek-ai/dsh-client-connection'], immediately: true }, { id: '@deepseek-ai/dsh-client-ui-theme', dir: 'ui-theme', inject: [], immediately: true }, { id: '@deepseek-ai/dsh-client-i18n', dir: 'i18n', inject: [], immediately: true }, { id: '@deepseek-ai/dsh-client-ui-layout', dir: 'ui-layout', inject: ['@deepseek-ai/dsh-client-runtime'] }, + { id: '@deepseek-ai/dsh-client-ui-sidebar', dir: 'ui-sidebar', inject: ['@deepseek-ai/dsh-client-ui-layout'] }, ] /** Manifest served by the fake registry: one live bundle row, one missing row. */ @@ -90,7 +91,7 @@ describe('web boot chain (keyless, real carrier)', () => { }) }) -describe('web boot chain success pass (keyless, five real bundles, ?fixture)', () => { +describe('web boot chain success pass (keyless, six real bundles, ?fixture)', () => { const missing = REAL_PLUGINS.filter((p) => !existsSync(bundlePath(p.dir))) let server: Awaited<ReturnType<typeof startWebServer>> let browser: Browser @@ -139,6 +140,20 @@ describe('web boot chain success pass (keyless, five real bundles, ?fixture)', ( const owners = await page.evaluate(() => [...document.querySelectorAll('style[data-plugin]')].map((s) => (s as HTMLElement).dataset['plugin'])) expect(owners).toContain('@deepseek-ai/dsh-client-ui-layout') + expect(owners).toContain('@deepseek-ai/dsh-client-ui-sidebar') + }) + + it('collapsed sidebar keeps a 60px rail with expand and settings controls', async () => { + const frame = page.locator('[class*="frame"]') + const firstTrack = async (): Promise<string> => (await frame.evaluate( + (el) => getComputedStyle(el).gridTemplateColumns)).split(' ')[0]! + await page.getByRole('button', { name: 'Collapse sidebar' }).click() + expect(await firstTrack()).toBe('60px') + await expect(page.getByRole('button', { name: 'Expand sidebar' }).isVisible()).resolves.toBe(true) + await expect(page.getByRole('button', { name: 'Settings' }).isVisible()).resolves.toBe(true) + await page.getByRole('button', { name: 'Expand sidebar' }).click() + expect(await firstTrack()).toBe('300px') + await expect(page.getByRole('button', { name: 'Collapse sidebar' }).isVisible()).resolves.toBe(true) }) it('stayed clean: no page errors across the whole load chain', () => { diff --git a/packages/client/ui-layout/README.md b/packages/client/ui-layout/README.md index 6c935f4b9d..f0755c3234 100644 --- a/packages/client/ui-layout/README.md +++ b/packages/client/ui-layout/README.md @@ -1,6 +1,6 @@ # @deepseek-ai/dsh-client-ui-layout -Shell plugin: three-column AppFrame (drag handles, concession chain) + ctx.layout viewing-state service (nav, panel widths, persist); defines the sidebar/conversation/details/conversation.empty slots. Contract: api-contracts v3 §5. +Shell plugin: three-column AppFrame (drag handles, concession chain) + ctx.layout viewing-state service (nav, panel widths, persist); defines the sidebar/conversation/details/conversation.empty slots. A closed sidebar retains a 60px control rail while details closes to zero width. Contract: api-contracts v3 §5. Slot declarations use the composed-props entry form (`owner` share, no full `props`): the exported OwnerShare contracts are `SidebarOwnerProps` / `ConvOwnerProps` / `DetailsOwnerProps` / `EmptyOwnerProps` — registrants reference them via `OwnerOf<'sidebar' | ...>` and compose their own injected share locally. The `conversation` entry authorizes `conversation.empty` delegation through `children`. diff --git a/packages/client/ui-layout/src/client/AppFrame.module.css b/packages/client/ui-layout/src/client/AppFrame.module.css index b7a03c7f2f..8be0ef0107 100644 --- a/packages/client/ui-layout/src/client/AppFrame.module.css +++ b/packages/client/ui-layout/src/client/AppFrame.module.css @@ -27,13 +27,8 @@ border-left: 1px solid var(--dsw-alias-border-l2); } -/* Collapsed columns keep children mounted; the border must not paint a 1px seam. - Flags live on the frame — DetailsColumn renders inside the provider body and - does not know its own width. */ -.frame[data-sidebar-collapsed] .sidebarCol { - border-right: none; -} - +/* The details subtree stays mounted at zero width, so its border must not paint + a 1px seam. The collapsed sidebar instead retains a bordered compact rail. */ .frame[data-details-collapsed] .detailsCol { border-left: none; } diff --git a/packages/client/ui-layout/src/client/AppFrame.tsx b/packages/client/ui-layout/src/client/AppFrame.tsx index a7efd09311..de771d5120 100644 --- a/packages/client/ui-layout/src/client/AppFrame.tsx +++ b/packages/client/ui-layout/src/client/AppFrame.tsx @@ -137,12 +137,14 @@ export function AppFrame(props: AppFrameProps) { ref={frameRef} className={css.frame} style={{ gridTemplateColumns: `${cols.sidebar}px minmax(0, 1fr) ${cols.details}px` }} - data-sidebar-collapsed={cols.sidebar === 0 || undefined} + data-sidebar-collapsed={!sidebar.open || undefined} data-details-collapsed={cols.details === 0 || undefined} > <div className={css.sidebarCol}>{props.sidebar}</div> {props.children} - {cols.sidebar > 0 && <DragHandle left={cols.sidebar} onStart={onSidebarStart} onDrag={onSidebarDrag} />} + {sidebar.open && cols.sidebar > 0 + ? <DragHandle left={cols.sidebar} onStart={onSidebarStart} onDrag={onSidebarDrag} /> + : null} {cols.details > 0 && <DragHandle left={viewport - cols.details} onStart={onDetailsStart} onDrag={onDetailsDrag} />} </div> ) diff --git a/packages/client/ui-layout/src/client/columns.ts b/packages/client/ui-layout/src/client/columns.ts index b6950c19e3..4d45d41874 100644 --- a/packages/client/ui-layout/src/client/columns.ts +++ b/packages/client/ui-layout/src/client/columns.ts @@ -1,9 +1,9 @@ /** * Pure concession-chain column solver for the three-column AppFrame. * Chain order is fixed by contract: keep center >= CENTER_MIN by shrinking - * details first, then sidebar, then auto-closing details (derived zero width — - * persisted open/width preferences are never rewritten, so widening the window - * restores them). Center absorbs any remaining deficit as the last resort. + * details first, then sidebar, then auto-closing details. A closed sidebar + * keeps its compact rail; persisted open/width preferences are never rewritten, + * so widening the window restores them. Center absorbs any remaining deficit. */ /** Panel viewing state consumed by the solver (mirrors LayoutService PanelState). */ @@ -21,6 +21,8 @@ export const SIDEBAR_MIN = 240 export const SIDEBAR_MAX = 420 /** Sidebar width before any user drag. */ export const SIDEBAR_DEFAULT = 300 +/** Closed-sidebar rail: one 28px control between 16px horizontal paddings. */ +export const SIDEBAR_COLLAPSED = 60 /** Details drag clamp floor. */ export const DETAILS_MIN = 300 /** Details drag clamp ceiling. */ @@ -47,13 +49,11 @@ export function clampWidth(px: number, min: number, max: number): number { * @param viewport - available frame width in px. * @param sidebar - sidebar preference (open flag + persisted width). * @param details - details preference (open flag + persisted width). - * @returns resolved widths; details 0 means visually closed (never unmounted). + * @returns resolved widths; details 0 means visually closed, while a closed sidebar keeps its compact rail. */ export function computeColumns(viewport: number, sidebar: PanelInput, details: PanelInput): Columns { - const want = (p: PanelInput, min: number, max: number): number => - p.open ? clampWidth(p.width, min, max) : 0 - const s0 = want(sidebar, SIDEBAR_MIN, SIDEBAR_MAX) - const d0 = want(details, DETAILS_MIN, DETAILS_MAX) + const s0 = sidebar.open ? clampWidth(sidebar.width, SIDEBAR_MIN, SIDEBAR_MAX) : SIDEBAR_COLLAPSED + const d0 = details.open ? clampWidth(details.width, DETAILS_MIN, DETAILS_MAX) : 0 // Step 1: everything fits at preferred widths. if (s0 + d0 + CENTER_MIN <= viewport) return { sidebar: s0, center: viewport - s0 - d0, details: d0 } @@ -63,14 +63,14 @@ export function computeColumns(viewport: number, sidebar: PanelInput, details: P if (s0 + d1 + CENTER_MIN <= viewport) return { sidebar: s0, center: CENTER_MIN, details: d1 } // Step 3: shrink sidebar toward its minimum. - const s1 = s0 === 0 ? 0 : Math.max(SIDEBAR_MIN, viewport - d1 - CENTER_MIN) + const s1 = sidebar.open ? Math.max(SIDEBAR_MIN, viewport - d1 - CENTER_MIN) : SIDEBAR_COLLAPSED if (s1 + d1 + CENTER_MIN <= viewport) return { sidebar: s1, center: CENTER_MIN, details: d1 } // Step 4: auto-close details (derived — preferences untouched). With the // details pressure gone the sidebar concession is re-solved from preference. if (d1 > 0) { if (s0 + CENTER_MIN <= viewport) return { sidebar: s0, center: viewport - s0, details: 0 } - const s2 = s0 === 0 ? 0 : Math.max(SIDEBAR_MIN, viewport - CENTER_MIN) + const s2 = sidebar.open ? Math.max(SIDEBAR_MIN, viewport - CENTER_MIN) : SIDEBAR_COLLAPSED return { sidebar: s2, center: Math.max(0, viewport - s2), details: 0 } } diff --git a/packages/client/ui-layout/src/client/index.ts b/packages/client/ui-layout/src/client/index.ts index e07c5d9896..3f9801c67b 100644 --- a/packages/client/ui-layout/src/client/index.ts +++ b/packages/client/ui-layout/src/client/index.ts @@ -13,7 +13,8 @@ import { LayoutService } from './service.ts' export { AppFrame, CenterColumn, DetailsColumn, type AppFrameProps } from './AppFrame.tsx' export { clampWidth, computeColumns, - CENTER_MIN, DETAILS_DEFAULT, DETAILS_MAX, DETAILS_MIN, SIDEBAR_DEFAULT, SIDEBAR_MAX, SIDEBAR_MIN, + CENTER_MIN, DETAILS_DEFAULT, DETAILS_MAX, DETAILS_MIN, + SIDEBAR_COLLAPSED, SIDEBAR_DEFAULT, SIDEBAR_MAX, SIDEBAR_MIN, type Columns, type PanelInput, } from './columns.ts' export { LayoutService, type NavState, type PanelState, type ViewId } from './service.ts' diff --git a/packages/client/ui-layout/tests/app-frame.spec.tsx b/packages/client/ui-layout/tests/app-frame.spec.tsx index dfc49be327..be9d056a02 100644 --- a/packages/client/ui-layout/tests/app-frame.spec.tsx +++ b/packages/client/ui-layout/tests/app-frame.spec.tsx @@ -10,7 +10,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { act, cleanup, render } from '@testing-library/react' import { createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' import { AppFrame, CenterColumn, DetailsColumn, type PanelState } from '@deepseek-ai/dsh-client-ui-layout/client' -import { clampWidth } from '@deepseek-ai/dsh-client-ui-layout/client' +import { clampWidth, SIDEBAR_COLLAPSED } from '@deepseek-ai/dsh-client-ui-layout/client' /** Observer stub: captures the callback so tests can fire resizes manually. */ let fireResize: (() => void) | null = null @@ -119,6 +119,15 @@ describe('AppFrame', () => { expect(frame.hasAttribute('data-details-collapsed')).toBe(true) }) + it('closed sidebar keeps its compact rail and mounted slot content', () => { + const { frame, sidebar, getByTestId } = mountFrame() + act(() => { sidebar.update((d) => { d.open = false }) }) + expect(tracks(frame)).toEqual([SIDEBAR_COLLAPSED, 360]) + expect(getByTestId('sidebar-content')).toBeTruthy() + expect(frame.hasAttribute('data-sidebar-collapsed')).toBe(true) + expect(frame.querySelectorAll('[class*="handle"]')).toHaveLength(1) + }) + it('viewport shrink triggers the concession chain via ResizeObserver', () => { const { frame } = mountFrame() frameWidth = 1250 diff --git a/packages/client/ui-layout/tests/columns.spec.ts b/packages/client/ui-layout/tests/columns.spec.ts index 49d351a6d4..6a4ccc92ce 100644 --- a/packages/client/ui-layout/tests/columns.spec.ts +++ b/packages/client/ui-layout/tests/columns.spec.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest' import { CENTER_MIN, clampWidth, computeColumns, - DETAILS_DEFAULT, DETAILS_MIN, SIDEBAR_DEFAULT, SIDEBAR_MIN, + DETAILS_DEFAULT, DETAILS_MIN, SIDEBAR_COLLAPSED, SIDEBAR_DEFAULT, SIDEBAR_MIN, } from '@deepseek-ai/dsh-client-ui-layout/client' const open = (width: number) => ({ open: true, width }) @@ -21,8 +21,9 @@ describe('computeColumns', () => { expect(cols).toEqual({ sidebar: 300, center: 1920 - 300 - 360, details: 360 }) }) - it('closed panels contribute zero width', () => { - expect(computeColumns(1920, closed(300), closed(360))).toEqual({ sidebar: 0, center: 1920, details: 0 }) + it('closed sidebar keeps its compact rail while details contributes zero width', () => { + expect(computeColumns(1920, closed(300), closed(360))) + .toEqual({ sidebar: SIDEBAR_COLLAPSED, center: 1920 - SIDEBAR_COLLAPSED, details: 0 }) }) it('preferences beyond the clamp range are clamped before solving', () => { @@ -69,10 +70,14 @@ describe('computeColumns', () => { }) it('sidebar-closed narrow window: details concedes then auto-closes', () => { - const fits = computeColumns(DETAILS_MIN + CENTER_MIN, closed(300), open(DETAILS_DEFAULT)) - expect(fits).toEqual({ sidebar: 0, center: CENTER_MIN, details: DETAILS_MIN }) - const starved = computeColumns(DETAILS_MIN + CENTER_MIN - 1, closed(300), open(DETAILS_DEFAULT)) - expect(starved).toEqual({ sidebar: 0, center: DETAILS_MIN + CENTER_MIN - 1, details: 0 }) + const fits = computeColumns(SIDEBAR_COLLAPSED + DETAILS_MIN + CENTER_MIN, closed(300), open(DETAILS_DEFAULT)) + expect(fits).toEqual({ sidebar: SIDEBAR_COLLAPSED, center: CENTER_MIN, details: DETAILS_MIN }) + const starved = computeColumns(SIDEBAR_COLLAPSED + DETAILS_MIN + CENTER_MIN - 1, closed(300), open(DETAILS_DEFAULT)) + expect(starved).toEqual({ + sidebar: SIDEBAR_COLLAPSED, + center: DETAILS_MIN + CENTER_MIN - 1, + details: 0, + }) }) it('tiny viewport: both panels yield everything to center', () => { @@ -93,8 +98,8 @@ describe('computeColumns', () => { describe('computeColumns — degenerate viewports', () => { it('sidebar closed and viewport below CENTER_MIN: details auto-closes, center takes all', () => { - // Reaches step 4's re-solve with s0 = 0 (the closed-sidebar arm). + // Reaches step 4's re-solve with the compact rail as the sidebar floor. expect(computeColumns(500, closed(300), open(DETAILS_DEFAULT))) - .toEqual({ sidebar: 0, center: 500, details: 0 }) + .toEqual({ sidebar: SIDEBAR_COLLAPSED, center: 500 - SIDEBAR_COLLAPSED, details: 0 }) }) }) diff --git a/packages/client/ui-sidebar/README.md b/packages/client/ui-sidebar/README.md index 25f840ab3d..2650b6836b 100644 --- a/packages/client/ui-sidebar/README.md +++ b/packages/client/ui-sidebar/README.md @@ -1,8 +1,8 @@ # @deepseek-ai/dsh-client-ui-sidebar -Sidebar plugin: session multi-level tree (cwd grouping + parentId nesting), search, by-workspace grouping, state dots, three creation entries. Contract: api-contracts v3 §6. +Sidebar plugin: session multi-level tree (cwd grouping + parentId nesting), search, by-workspace grouping, state dots, three creation entries. Its collapsed render keeps the expand control and settings entry in the layout-owned compact rail. Contract: api-contracts v3 §6. -`src/client/contract/slots.ts` is the single-domain contract file: `SidebarRootInjected` (the registrant's own injected share — tree hook, current-session hook, actions) and `SidebarRootComponentProps = OwnerOf<'sidebar'> & SidebarRootInjected` (the owner share referenced from ui-layout's slot declaration, never re-stated). `apply` registers SidebarRoot cast-free against that composition; the inject factory binds layout/sessions off `RootBinding<ClientContext>`. +`src/client/contract/slots.ts` is the single-domain contract file: `SidebarRootInjected` (the registrant's own injected share — tree hook, current-session/sidebar-open hooks, actions) and `SidebarRootComponentProps = OwnerOf<'sidebar'> & SidebarRootInjected` (the owner share referenced from ui-layout's slot declaration, never re-stated). `apply` registers SidebarRoot cast-free against that composition; the inject factory binds layout/sessions off `RootBinding<ClientContext>`. ## Model Experience diff --git a/packages/client/ui-sidebar/src/client/SidebarRoot.module.css b/packages/client/ui-sidebar/src/client/SidebarRoot.module.css index 5fdcbce74c..c8f0a08964 100644 --- a/packages/client/ui-sidebar/src/client/SidebarRoot.module.css +++ b/packages/client/ui-sidebar/src/client/SidebarRoot.module.css @@ -15,6 +15,28 @@ font-size: 14px; } +/* Closed state is a persistent rail: the layout reserves exactly the root's + horizontal padding plus one icon control. */ +.root.collapsed { + gap: 0; +} + +.collapsed .headerBlock { + padding-bottom: 0; +} + +.collapsed .logoRow { + justify-content: center; + padding-inline: 0; +} + +.collapsed .foot { + justify-content: center; + width: 28px; + margin-top: auto; + padding: 0; +} + /* Header block (figma 133:7630): logo row + New Session, gap 16, padBottom 12. */ .headerBlock { flex: none; diff --git a/packages/client/ui-sidebar/src/client/SidebarRoot.tsx b/packages/client/ui-sidebar/src/client/SidebarRoot.tsx index 01c8fbfcd4..5a4866bc4f 100644 --- a/packages/client/ui-sidebar/src/client/SidebarRoot.tsx +++ b/packages/client/ui-sidebar/src/client/SidebarRoot.tsx @@ -24,12 +24,10 @@ const GROUP_BY_ITEMS = [ { id: 'status', label: 'Status', disabled: true }, ] -/** - * Render the sidebar column. - * @param props - composed slot props (owner share + injected surface, contract/slots.ts). - * @returns the sidebar element tree. - */ -export function SidebarRoot({ useTree, useCurrent, actions, tree }: SidebarRootComponentProps) { +type SidebarBodyProps = Pick<SidebarRootComponentProps, 'useTree' | 'useCurrent' | 'actions' | 'tree'> + +/** Expanded-only content; unmounting drops tree/current subscriptions while the rail is collapsed. */ +function SidebarBody({ useTree, useCurrent, actions, tree }: SidebarBodyProps) { const rows = useTree((s) => s.rows) const query = useTree((s) => s.query) const groupBy = useTree((s) => s.groupBy) @@ -47,32 +45,7 @@ export function SidebarRoot({ useTree, useCurrent, actions, tree }: SidebarRootC } return ( - <div className={css.root}> - <div className={css.headerBlock}> - <div className={css.logoRow}> - <span className={css.brand}> - {/* Wordmark svg not extracted yet (figma 88:8932) — text stands in at the same ink. */} - <FishLogo size={23} /> - <span className={css.wordmark}>deepseek</span> - <span className={css.badge}>HARNESS</span> - </span> - <button - type="button" - className={css.iconButton} - aria-label="Collapse sidebar" - onClick={() => { actions.toggleSidebar() }} - > - <IconPanelLeftOutline16 /> - </button> - </div> - - <button type="button" className={css.newSession} onClick={() => { actions.create() }}> - <IconNewChatOutline16 size={14} /> - New Session - </button> - </div> - - <div className={css.listArea}> + <div className={css.listArea}> <div className={css.sectionHeader}> <span className={css.sectionLabel}>WorkSpace</span> <Menu @@ -153,11 +126,66 @@ export function SidebarRoot({ useTree, useCurrent, actions, tree }: SidebarRootC ))} </div> <span className={css.fade} /> + </div> + ) +} + +/** + * Render the sidebar column. + * @param props - composed slot props (owner share + injected surface, contract/slots.ts). + * @returns the sidebar element tree. + */ +export function SidebarRoot(props: SidebarRootComponentProps) { + const open = props.useSidebarOpen() + + return ( + <div className={clsx(css.root, !open && css.collapsed)}> + <div className={css.headerBlock}> + <div className={css.logoRow}> + {open + ? ( + <span className={css.brand}> + {/* Wordmark svg not extracted yet (figma 88:8932) — text stands in at the same ink. */} + <FishLogo size={23} /> + <span className={css.wordmark}>deepseek</span> + <span className={css.badge}>HARNESS</span> + </span> + ) + : null} + <button + type="button" + className={css.iconButton} + aria-label={open ? 'Collapse sidebar' : 'Expand sidebar'} + onClick={() => { props.actions.toggleSidebar() }} + > + <IconPanelLeftOutline16 /> + </button> + </div> + + {open + ? ( + <button type="button" className={css.newSession} onClick={() => { props.actions.create() }}> + <IconNewChatOutline16 size={14} /> + New Session + </button> + ) + : null} </div> - <div className={clsx(css.foot)} role="button" tabIndex={0} aria-label="Settings"> + {open + ? ( + <SidebarBody + useTree={props.useTree} + useCurrent={props.useCurrent} + actions={props.actions} + tree={props.tree} + /> + ) + : null} + + <div className={css.foot} role="button" tabIndex={0} aria-label="Settings"> <IconSettingsOutline14 /> - Settings + {open ? <span>Settings</span> : null} </div> </div> ) diff --git a/packages/client/ui-sidebar/src/client/contract/slots.ts b/packages/client/ui-sidebar/src/client/contract/slots.ts index 4d1e0dd7f4..4a5d33f7b5 100644 --- a/packages/client/ui-sidebar/src/client/contract/slots.ts +++ b/packages/client/ui-sidebar/src/client/contract/slots.ts @@ -37,6 +37,8 @@ export type SidebarRootInjected = { useTree: SnapshotSelectorHook<SidebarTreeState> /** Current session selector (row highlight); undefined selects nothing. */ useCurrent: () => SessionId | undefined + /** Sidebar open selector; the collapsed render keeps only persistent rail controls. */ + useSidebarOpen: () => boolean actions: SidebarActions tree: SidebarTreeActions } diff --git a/packages/client/ui-sidebar/src/client/index.ts b/packages/client/ui-sidebar/src/client/index.ts index fab3bc4836..91600c3621 100644 --- a/packages/client/ui-sidebar/src/client/index.ts +++ b/packages/client/ui-sidebar/src/client/index.ts @@ -45,6 +45,7 @@ export function apply(ctx: ClientContext): void { return { useTree: tree.store.useSelector, useCurrent: () => layout.current.useSelector(s => s.sessionId), + useSidebarOpen: () => layout.sidebar.useSelector(s => s.open), actions: { open: (id) => { layout.open(id) }, create: (cwd) => { diff --git a/packages/client/ui-sidebar/tests/apply.spec.tsx b/packages/client/ui-sidebar/tests/apply.spec.tsx index ea029c6709..ac4b794466 100644 --- a/packages/client/ui-sidebar/tests/apply.spec.tsx +++ b/packages/client/ui-sidebar/tests/apply.spec.tsx @@ -31,10 +31,12 @@ async function bench() { byId: { [sid('a')]: { id: sid('a'), title: 'alpha', cwd: '/proj', running: false, updatedAt: 1 } }, }) const sessions = { list, create: vi.fn(async () => sid('minted')) } + const sidebar = createSnapshotStore({ open: true, width: 300 }) const layout = { current: createSnapshotStore<{ sessionId?: SessionId }>({}), + sidebar, open: vi.fn(), - toggleSidebar: vi.fn(), + toggleSidebar: vi.fn(() => { sidebar.update((d) => { d.open = !d.open }) }), } ctx.provide('sessions', sessions) ctx.provide('layout', layout) @@ -83,6 +85,10 @@ describe('apply', () => { act(() => { fireEvent.click(screen.getByLabelText('Collapse sidebar')) }) expect(layout.toggleSidebar).toHaveBeenCalledOnce() + expect(screen.getByLabelText('Expand sidebar')).toBeTruthy() + expect(screen.getByLabelText('Settings')).toBeTruthy() + act(() => { fireEvent.click(screen.getByLabelText('Expand sidebar')) }) + expect(layout.toggleSidebar).toHaveBeenCalledTimes(2) act(() => { fireEvent.click(screen.getByText('proj')) }) act(() => { fireEvent.click(screen.getByText('alpha')) }) diff --git a/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx b/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx index db03c672dd..bddacca286 100644 --- a/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx +++ b/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx @@ -51,20 +51,22 @@ function mount(...summaries: SessionSummary[]) { const list = createSnapshotStore<SessionListState>(listStateOf(...summaries)) const tree: SidebarTreeStore = createSidebarTreeStore({ list }) const current = createSnapshotStore<{ id: SessionId | undefined }>({ id: undefined }) + const sidebar = createSnapshotStore({ open: true }) const actions: SidebarActions = { open: vi.fn((id: SessionId) => { current.update((d) => { d.id = id }) }), create: vi.fn(), - toggleSidebar: vi.fn(), + toggleSidebar: vi.fn(() => { sidebar.update((d) => { d.open = !d.open }) }), } const utils = render( <SidebarRoot useTree={tree.store.useSelector} useCurrent={() => current.useSelector((s) => s.id)} + useSidebarOpen={() => sidebar.useSelector((s) => s.open)} actions={actions} tree={tree} />, ) - return { list, tree, current, actions, ...utils } + return { list, tree, current, sidebar, actions, ...utils } } const projectData = () => [ @@ -139,10 +141,22 @@ describe('SidebarRoot', () => { expect(actions.create).toHaveBeenLastCalledWith('/proj') }) - it('collapse button and group-by menu behave', () => { + it('collapsed rail keeps the expand and settings controls', () => { const { actions } = mount(...projectData()) act(() => { fireEvent.click(screen.getByLabelText('Collapse sidebar')) }) expect(actions.toggleSidebar).toHaveBeenCalledOnce() + expect(screen.getByLabelText('Expand sidebar')).toBeTruthy() + expect(screen.getByLabelText('Settings')).toBeTruthy() + expect(screen.queryByText('HARNESS')).toBeNull() + expect(screen.queryByText('New Session')).toBeNull() + act(() => { fireEvent.click(screen.getByLabelText('Expand sidebar')) }) + expect(actions.toggleSidebar).toHaveBeenCalledTimes(2) + expect(screen.getByLabelText('Collapse sidebar')).toBeTruthy() + expect(screen.getByText('New Session')).toBeTruthy() + }) + + it('group-by menu behaves', () => { + mount(...projectData()) expect(screen.queryByText('Update')).toBeNull() act(() => { fireEvent.click(screen.getByLabelText('Group by')) }) expect(screen.getByText('Update')).toBeTruthy() From 34194f0cd5653a5f0e1b55692bac9d20d973e876 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 20:51:13 +0800 Subject: [PATCH 087/368] fix(tools): make schema traversal stack-safe --- ...20-unified-json-value-schema-dsl.i18n.yaml | 4 +- ...026-07-20-unified-json-value-schema-dsl.md | 4 +- ...-07-20-unified-json-value-schema-dsl.zh.md | 4 +- packages/cordis/tool-cordis/README.md | 2 +- packages/cordis/tool-cordis/src/guard.ts | 434 ++++++++++++------ .../cordis/tool-cordis/tests/mount.spec.ts | 94 ++++ packages/core/tools/README.md | 2 +- packages/core/tools/src/index.ts | 6 +- packages/core/tools/src/json-schema.ts | 402 +++++++++++----- packages/core/tools/src/schema.ts | 236 +++++++--- packages/core/tools/src/ts-types.ts | 215 +++++++-- packages/core/tools/tests/json-schema.spec.ts | 19 + packages/core/tools/tests/schema.spec.ts | 17 + packages/core/tools/tests/tools.spec.ts | 37 +- packages/core/tools/tests/ts-types.spec.ts | 11 + 15 files changed, 1143 insertions(+), 344 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml index ae5592ef01..2f7a4b1adb 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.i18n.yaml @@ -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 -2026-07-20-unified-json-value-schema-dsl.md: 6a3dc21a7ae76ba8f84f5b3edf8306285a02a683 -2026-07-20-unified-json-value-schema-dsl.zh.md: 77ac599e6713563528d0382dfecff83071488930 +2026-07-20-unified-json-value-schema-dsl.md: e735472ee0ac6a696462aa7598d57fce04aa9c3e +2026-07-20-unified-json-value-schema-dsl.zh.md: dd34817a6d047b14346b35ba6c4bce0290ad7feb diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md index 6a3dc21a7a..e735472ee0 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.md @@ -12,7 +12,7 @@ Tool parameters used a small author DSL while subagent/workflow structured outpu `dsh-tools` owns one JSON-value schema vocabulary with two representations. `ValueSchemaSpec` is the author form for any JSON root; `ParameterSchemaSpec` is its implicit object-property-map form with per-property `required: true`. `JsonSchemaNode` is the raw wire form. Both support string, finite number, integer, boolean, null, array, object, type-correct scalar `enum`/`const`, and exact-one `oneOf`; `{ type: 'json' }` is author-only sugar for an annotation-only unconstrained raw node. -An explicit author object must declare `additionalProperties: true | false`. The implicit parameter root and raw JSON Schema preserve the standard open default. `InferValue<S>` and `InferArgs<P>` derive TypeScript values from the same declarations that `valueSchemaSpecToJsonSchema()` and `parameterSchemaSpecToJsonSchema()` compile. `assertSupportedJsonSchema()` rejects unsupported or misplaced keywords, and `validateJsonSchemaValue()` enforces the accepted subset against the lossless `JsonValue` boundary: no `undefined`, negative zero, non-finite numbers, sparse arrays, cycles, exotic objects, functions, symbols, or other coercive values. Intrinsic plain Object and Array containers remain plain across JavaScript realms; subclasses remain exotic. Validation and snapshot traversal are iterative, so valid nesting is limited by available memory rather than the JavaScript call stack. +An explicit author object must declare `additionalProperties: true | false`. The implicit parameter root and raw JSON Schema preserve the standard open default. `InferValue<S>` and `InferArgs<P>` derive TypeScript values from the same declarations that `valueSchemaSpecToJsonSchema()` and `parameterSchemaSpecToJsonSchema()` compile. `assertSupportedJsonSchema()` rejects unsupported or misplaced keywords, and `validateJsonSchemaValue()` enforces the accepted subset against the lossless `JsonValue` boundary: no `undefined`, negative zero, non-finite numbers, sparse arrays, cycles, exotic objects, functions, symbols, or other coercive values. Intrinsic plain Object and Array containers remain plain across JavaScript realms; subclasses remain exotic. Author compilation, raw-schema assertion, value validation, schema-to-TypeScript rendering, registry detachment, and dynamic Cordis cross-realm normalization and cloning use explicit work stacks, so valid nesting is limited by available memory rather than the JavaScript call stack. Object-rooting is a consumer rule rather than a vocabulary restriction. Subagent and workflow caller-defined structured outputs use `assertObjectJsonSchema()` and `ObjectJsonSchema`; tool outputs may use any root. Dynamic Cordis registrations rebuild realm-foreign schemas into host-owned JSON, preserve raw-wrapper openness, and require direct-DSL object openness before calling the same compiler. @@ -29,4 +29,4 @@ Object-rooting is a consumer rule rather than a vocabulary restriction. Subagent - Output declarations can infer object, array, scalar, or null roots; subagent/workflow structured outputs remain object-rooted at their existing seams. - Explicit object openness and type-correct literal constraints make malformed declarations fail during authoring or registration rather than during a later model call. - Raw tools may still register broader JSON Schema directly, but unified code generation treats unsupported schemas as unknown instead of pretending to enforce them. -- Runtime and compile-time tests cover every root, exact-one overlap/no-match behavior, raw open defaults, explicit openness, lossy JSON values, and inference. +- Runtime and compile-time tests cover every root, exact-one overlap/no-match behavior, raw open defaults, explicit openness, lossy JSON values, inference, and deep nesting across core and dynamic projections. diff --git a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md index 77ac599e67..dd34817a6d 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-20-unified-json-value-schema-dsl.zh.md @@ -12,7 +12,7 @@ Status: implemented `dsh-tools` 以两种表示形式统一管理一套 JSON 值 schema 词汇。`ValueSchemaSpec` 是可描述任意 JSON 根类型的作者侧形式;`ParameterSchemaSpec` 是其隐式对象属性映射形式,每个属性可标记 `required: true`。`JsonSchemaNode` 是原始协议表示。两种形式都支持字符串、有限数值、整数、布尔值、null、数组、对象、类型正确的标量 `enum`/`const`,以及要求恰好匹配一个分支的 `oneOf`;`{ type: 'json' }` 仅是作者侧语法糖,会编译为仅含注解、不施加约束的原始节点。 -显式的作者侧对象必须声明 `additionalProperties: true | false`。隐式参数根对象和原始 JSON Schema 保留标准的默认开放语义。`InferValue<S>` 和 `InferArgs<P>` 根据同一份声明推导 TypeScript 值,`valueSchemaSpecToJsonSchema()` 和 `parameterSchemaSpecToJsonSchema()` 也将这些声明编译为 JSON Schema。`assertSupportedJsonSchema()` 会拒绝不受支持或位置错误的关键字;`validateJsonSchemaValue()` 则以无损 `JsonValue` 边界校验受支持的子集,不允许 `undefined`、负零、非有限数、稀疏数组、循环引用、非普通对象、函数、symbol 及其他需要强制转换的值。内建的普通 Object 和 Array 容器跨 JavaScript 运行域后仍视为普通容器;其子类仍视为非普通对象。校验和快照遍历均以迭代方式执行,因此合法嵌套的深度上限由可用内存决定,而非 JavaScript 调用栈。 +显式的作者侧对象必须声明 `additionalProperties: true | false`。隐式参数根对象和原始 JSON Schema 保留标准的默认开放语义。`InferValue<S>` 和 `InferArgs<P>` 根据同一份声明推导 TypeScript 值,`valueSchemaSpecToJsonSchema()` 和 `parameterSchemaSpecToJsonSchema()` 也将这些声明编译为 JSON Schema。`assertSupportedJsonSchema()` 会拒绝不受支持或位置错误的关键字;`validateJsonSchemaValue()` 则以无损 `JsonValue` 边界校验受支持的子集,不允许 `undefined`、负零、非有限数、稀疏数组、循环引用、非普通对象、函数、symbol 及其他需要强制转换的值。内建的普通 Object 和 Array 容器跨 JavaScript 运行域后仍视为普通容器;其子类仍视为非普通对象。作者侧 schema 编译、原始 schema 断言、值校验、schema 到 TypeScript 的渲染、注册表数据分离,以及动态 Cordis 的跨运行域规范化与克隆均使用显式工作栈,因此合法嵌套的深度上限由可用内存决定,而非 JavaScript 调用栈。 对象根限制属于消费方规则,不属于 schema 词汇本身。subagent 和工作流中由调用方定义的结构化输出通过 `assertObjectJsonSchema()` 和 `ObjectJsonSchema` 保持对象根限制;工具输出可以使用任意根类型。动态 Cordis 注册会把跨 JavaScript 运行域传入的 schema 重建为当前运行时持有的 JSON,保留原始包装层的默认开放语义,并要求直接使用 DSL 声明的对象明确选择开放方式,然后再调用同一编译器。 @@ -29,4 +29,4 @@ Status: implemented - 输出声明可以推导对象、数组、标量或 null 根类型;subagent/工作流的结构化输出仍在其现有服务边界保持对象根限制。 - 显式的对象开放方式和类型正确的字面量约束会让格式错误的声明在编写或注册阶段快速失败,而不是拖到后续模型调用时才失败。 - 原始工具仍可直接注册范围更广的 JSON Schema,但统一代码生成会把不受支持的 schema 视为未知类型,不会假装自己能够强制执行。 -- 运行时和编译期测试覆盖所有根类型、恰好匹配一个分支时的重叠/无匹配行为、原始 schema 的默认开放语义、显式开放方式、有损 JSON 值和类型推导。 +- 运行时和编译期测试覆盖所有根类型、恰好匹配一个分支时的重叠/无匹配行为、原始 schema 的默认开放语义、显式开放方式、有损 JSON 值、类型推导,以及核心投影和动态投影中的深层嵌套。 diff --git a/packages/cordis/tool-cordis/README.md b/packages/cordis/tool-cordis/README.md index 7819cb8c2c..babf259761 100644 --- a/packages/cordis/tool-cordis/README.md +++ b/packages/cordis/tool-cordis/README.md @@ -12,7 +12,7 @@ Exact model-facing schemas: [the generated tool catalog](../../../docs/tool-cata ## Trust stance -The sandbox isolates globals but is not a security boundary. Node globals are absent or redirect to Cordis services such as `ctx.fs`, `ctx.web`, and `ctx.bash`, and writes to `globalThis` stay local, but host-realm helpers make escape possible. Mounted plugins receive a façade without framework internals, yet its allowed services affect the live runtime. Treat this toolset like bash access; see the [design and trust stance](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). +The sandbox isolates globals but is not a security boundary. Node globals are absent or redirect to Cordis services such as `ctx.fs`, `ctx.web`, and `ctx.bash`, and writes to `globalThis` stay local, but host-realm helpers make escape possible. Mounted plugins receive a façade without framework internals, yet its allowed services affect the live runtime. Dynamic tool schemas and annotations cross the realm through iterative JSON cloning and schema normalization, so valid deep declarations are memory-bounded rather than call-stack-bounded. Treat this toolset like bash access; see the [design and trust stance](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). ## Config diff --git a/packages/cordis/tool-cordis/src/guard.ts b/packages/cordis/tool-cordis/src/guard.ts index 2ebba0fbd8..bf225948be 100644 --- a/packages/cordis/tool-cordis/src/guard.ts +++ b/packages/cordis/tool-cordis/src/guard.ts @@ -57,45 +57,105 @@ function hasPlainArrayPrototype(value: unknown[]): boolean { } /* jscpd:ignore-end */ +/** Where one cloned JSON value is installed. */ +type CloneDestination = + | { kind: 'root' } + | { kind: 'array'; target: unknown[]; index: number } + | { kind: 'object'; target: Record<string, unknown>; key: string } + +/** Deferred work for stack-safe cross-realm JSON cloning. */ +type CloneTask = + | { kind: 'visit'; value: unknown; path: string; destination: CloneDestination } + | { kind: 'array-item'; source: unknown[]; index: number; path: string; target: unknown[] } + | { kind: 'leave'; source: object } + /** Materialize realm-foreign lossless JSON without allowing JSON.stringify coercions. */ -function cloneJson(value: unknown, path: string, seen = new Set<object>()): unknown { - if (value === null || typeof value === 'string' || typeof value === 'boolean') return value - if (typeof value === 'number') { - if (Number.isFinite(value) && !Object.is(value, -0)) return value - throw new Error(`harness.defineTool ${path} must be lossless JSON data`) - } - if (typeof value !== 'object') throw new Error(`harness.defineTool ${path} must be lossless JSON data`) - if (seen.has(value)) throw new Error(`harness.defineTool ${path} must be lossless JSON data`) - seen.add(value) - try { - if (Array.isArray(value)) { - if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) { - throw new Error(`harness.defineTool ${path} must be lossless JSON data`) - } - const output: unknown[] = [] - for (let index = 0; index < value.length; index++) { - if (!Object.hasOwn(value, index)) throw new Error(`harness.defineTool ${path} must be lossless JSON data`) - output.push(cloneJson(value[index], `${path}[${index}]`, seen)) - } - return output +function cloneJson(value: unknown, path: string): unknown { + const ancestors = new Set<object>() + let root: unknown + const assign = (destination: CloneDestination, item: unknown): void => { + if (destination.kind === 'root') { + root = item + return } - if (!isPlainRecord(value)) throw new Error(`harness.defineTool ${path} must be lossless JSON data`) - if (Reflect.ownKeys(value).some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(value, key))) { - throw new Error(`harness.defineTool ${path} must be lossless JSON data`) + if (destination.kind === 'array') { + destination.target[destination.index] = item + return + } + Object.defineProperty(destination.target, destination.key, { + value: item, + enumerable: true, + configurable: true, + writable: true, + }) + } + const reject = (at: string): never => { + throw new Error(`harness.defineTool ${at} must be lossless JSON data`) + } + + const tasks: CloneTask[] = [{ kind: 'visit', value, path, destination: { kind: 'root' } }] + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + ancestors.delete(task.source) + continue + } + if (task.kind === 'array-item') { + if (!Object.hasOwn(task.source, task.index)) reject(task.path) + tasks.push({ + kind: 'visit', + value: task.source[task.index], + path: `${task.path}[${task.index}]`, + destination: { kind: 'array', target: task.target, index: task.index }, + }) + continue + } + + const current = task.value + if (current === null || typeof current === 'string' || typeof current === 'boolean') { + assign(task.destination, current) + continue + } + if (typeof current === 'number') { + if (!Number.isFinite(current) || Object.is(current, -0)) reject(task.path) + assign(task.destination, current) + continue + } + if (typeof current !== 'object' || ancestors.has(current)) reject(task.path) + + if (Array.isArray(current)) { + if (!hasPlainArrayPrototype(current) || Reflect.ownKeys(current).length !== current.length + 1) reject(task.path) + const output: unknown[] = [] + assign(task.destination, output) + ancestors.add(current) + tasks.push({ kind: 'leave', source: current }) + for (let index = current.length - 1; index >= 0; index--) { + tasks.push({ kind: 'array-item', source: current, index, path: task.path, target: output }) + } + continue + } + if (!isPlainRecord(current)) reject(task.path) + const record = current as Record<string, unknown> + if (Reflect.ownKeys(record).some(key => typeof key !== 'string' || !Object.prototype.propertyIsEnumerable.call(record, key))) { + reject(task.path) } const output: Record<string, unknown> = {} - for (const [key, entry] of Object.entries(value)) { - Object.defineProperty(output, key, { - value: cloneJson(entry, `${path}.${key}`, seen), - enumerable: true, - configurable: true, - writable: true, + assign(task.destination, output) + ancestors.add(record) + tasks.push({ kind: 'leave', source: record }) + const entries = Object.entries(record) + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index] + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) continue + tasks.push({ + kind: 'visit', + value: entry[1], + path: `${task.path}.${entry[0]}`, + destination: { kind: 'object', target: output, key: entry[0] }, }) } - return output - } finally { - seen.delete(value) } + return root } /** Copy and realm-materialize the shared annotation vocabulary. */ @@ -160,111 +220,229 @@ function normalizeRequiredNames(value: unknown, properties: Record<string, unkno return names } -/** Normalize one implicit property map. */ +/** Mutable holder used only while one normalized property-map root is unresolved. */ +interface NormalizeRoot { + value?: Record<string, unknown> +} + +/** Where a normalized value node is installed. */ +type NormalizeValueDestination = + | { kind: 'property'; target: Record<string, unknown>; key: string } + | { kind: 'item'; target: Record<string, unknown> } + | { kind: 'one-of'; target: Record<string, unknown>[]; index: number } + +/** Where a normalized property map is installed. */ +type NormalizeMapDestination = + | { kind: 'root'; holder: NormalizeRoot } + | { kind: 'properties'; target: Record<string, unknown> } + +/** Deferred work for stack-safe sandbox schema normalization. */ +type NormalizeTask = + | { + kind: 'map' + entries: Record<string, unknown> + path: string + requiredNames: ReadonlySet<string> + raw: boolean + destination: NormalizeMapDestination + } + | { + kind: 'value' + value: unknown + path: string + forceRequired: boolean + raw: boolean + parameterProperty: boolean + destination: NormalizeValueDestination + } + | { kind: 'leave'; value: object } + +/** Install one normalized node without `__proto__` assignment semantics. */ +function assignNormalizedValue(destination: NormalizeValueDestination, value: Record<string, unknown>): void { + if (destination.kind === 'property') { + Object.defineProperty(destination.target, destination.key, { + value, + enumerable: true, + configurable: true, + writable: true, + }) + } else if (destination.kind === 'item') { + destination.target.items = value + } else { + destination.target[destination.index] = value + } +} + +/** Install one normalized property map at its root or containing object. */ +function assignNormalizedMap(destination: NormalizeMapDestination, value: Record<string, unknown>): void { + if (destination.kind === 'root') destination.holder.value = value + else destination.target.properties = value +} + +/** Normalize one implicit property map and all descendants with explicit work frames. */ function normalizePropertyMap( entries: Record<string, unknown>, path: string, requiredNames: ReadonlySet<string>, raw: boolean, ): Record<string, unknown> { - const spec: Record<string, unknown> = {} - for (const [key, prop] of Object.entries(entries)) { - Object.defineProperty(spec, key, { - value: normalizeValueSchema(prop, `${path}.${key}`, requiredNames.has(key), raw, true), - enumerable: true, - configurable: true, - writable: true, - }) - } - return spec -} - -/** Normalize one property or nested value schema into the host realm. */ -function normalizeValueSchema( - value: unknown, - path: string, - forceRequired = false, - raw = false, - parameterProperty = false, -): Record<string, unknown> { - if (!isPlainRecord(value)) { - throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec property object`) - } - const requiredKey = parameterProperty && !raw ? ['required'] : [] - if (parameterProperty && raw && Object.hasOwn(value, 'required') && value.type !== 'object') { - throw new Error(`harness.defineTool ${path}.required belongs to the containing raw object schema`) - } - if (parameterProperty && !raw && Object.hasOwn(value, 'required') && value.required !== true) { - throw new Error(`harness.defineTool ${path}.required must be true when present`) - } - const prop: Record<string, unknown> = {} - if (forceRequired || value.required === true) prop.required = true - copyAnnotations(value, prop, path) - - if (Object.hasOwn(value, 'oneOf')) { - assertSchemaKeys(value, path, ['oneOf', ...requiredKey, ...ANNOTATION_KEYS]) - if (!Array.isArray(value.oneOf)) throw new Error(`harness.defineTool ${path}.oneOf must contain at least two schemas`) - prop.oneOf = value.oneOf.map((branch, index) => normalizeValueSchema(branch, `${path}.oneOf[${index}]`, false, raw)) - return prop - } - - if (raw && !Object.hasOwn(value, 'type')) { - assertSchemaKeys(value, path, ANNOTATION_KEYS) - prop.type = 'json' - return prop - } - if (!SCHEMA_TYPES.has(value.type) || raw && value.type === 'json') { - throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES} (got ${JSON.stringify(value.type)})`) - } - const type = value.type - prop.type = type - - switch (type) { - case 'object': { - assertSchemaKeys(value, path, ['type', 'properties', 'additionalProperties', ...requiredKey, ...(raw ? ['required'] : []), ...ANNOTATION_KEYS]) - if (!raw && (!Object.hasOwn(value, 'additionalProperties') || typeof value.additionalProperties !== 'boolean')) { - throw new Error(`harness.defineTool ${path}.additionalProperties must be explicitly true or false`) - } - if (raw && Object.hasOwn(value, 'additionalProperties') && typeof value.additionalProperties !== 'boolean') { - throw new Error(`harness.defineTool ${path}.additionalProperties must be a boolean`) - } - if (raw && Object.hasOwn(value, 'required') && value.required === undefined) { - throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`) - } - prop.additionalProperties = raw ? value.additionalProperties ?? true : value.additionalProperties - if (Object.hasOwn(value, 'properties')) { - if (!isPlainRecord(value.properties)) throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`) - const nestedRequired = raw ? normalizeRequiredNames(value.required, value.properties, `${path}.required`) : new Set<string>() - prop.properties = normalizePropertyMap(value.properties, `${path}.properties`, nestedRequired, raw) - } else if (raw && value.required !== undefined) { - normalizeRequiredNames(value.required, {}, `${path}.required`) - } - return prop + const holder: NormalizeRoot = {} + const ancestors = new Set<object>() + const tasks: NormalizeTask[] = [{ + kind: 'map', + entries, + path, + requiredNames, + raw, + destination: { kind: 'root', holder }, + }] + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + ancestors.delete(task.value) + continue } - case 'array': - assertSchemaKeys(value, path, ['type', 'items', ...requiredKey, ...ANNOTATION_KEYS]) - if (Object.hasOwn(value, 'items')) prop.items = normalizeValueSchema(value.items, `${path}.items`, false, raw) - return prop - case 'string': - case 'number': - case 'integer': - case 'boolean': - case 'null': - assertSchemaKeys(value, path, ['type', 'enum', 'const', ...requiredKey, ...ANNOTATION_KEYS]) - if (Object.hasOwn(value, 'enum')) { - prop.enum = Array.isArray(value.enum) - ? value.enum.map((entry, index) => cloneJson(entry, `${path}.enum[${index}]`)) - : value.enum + if (task.kind === 'map') { + if (ancestors.has(task.entries)) throw new Error(`harness.defineTool ${task.path} is circular`) + ancestors.add(task.entries) + const spec: Record<string, unknown> = {} + assignNormalizedMap(task.destination, spec) + tasks.push({ kind: 'leave', value: task.entries }) + const mapEntries = Object.entries(task.entries) + for (let index = mapEntries.length - 1; index >= 0; index--) { + const entry = mapEntries[index] + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) continue + tasks.push({ + kind: 'value', + value: entry[1], + path: `${task.path}.${entry[0]}`, + forceRequired: task.requiredNames.has(entry[0]), + raw: task.raw, + parameterProperty: true, + destination: { kind: 'property', target: spec, key: entry[0] }, + }) } - if (Object.hasOwn(value, 'const')) prop.const = cloneJson(value.const, `${path}.const`) - return prop - case 'json': - assertSchemaKeys(value, path, ['type', ...requiredKey, ...ANNOTATION_KEYS]) - return prop - /* v8 ignore next 2 -- SCHEMA_TYPES narrows this closed switch before dispatch. */ - default: - throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES}`) + continue + } + + const { value, path } = task + if (!isPlainRecord(value)) { + throw new Error(`harness.defineTool ${path} must be a ParameterSchemaSpec property object`) + } + if (ancestors.has(value)) throw new Error(`harness.defineTool ${path} is circular`) + ancestors.add(value) + const requiredKey = task.parameterProperty && !task.raw ? ['required'] : [] + if (task.parameterProperty && task.raw && Object.hasOwn(value, 'required') && value.type !== 'object') { + throw new Error(`harness.defineTool ${path}.required belongs to the containing raw object schema`) + } + if (task.parameterProperty && !task.raw && Object.hasOwn(value, 'required') && value.required !== true) { + throw new Error(`harness.defineTool ${path}.required must be true when present`) + } + const prop: Record<string, unknown> = {} + assignNormalizedValue(task.destination, prop) + tasks.push({ kind: 'leave', value }) + if (task.forceRequired || value.required === true) prop.required = true + copyAnnotations(value, prop, path) + + if (Object.hasOwn(value, 'oneOf')) { + assertSchemaKeys(value, path, ['oneOf', ...requiredKey, ...ANNOTATION_KEYS]) + if (!Array.isArray(value.oneOf)) throw new Error(`harness.defineTool ${path}.oneOf must contain at least two schemas`) + const oneOf: Record<string, unknown>[] = [] + prop.oneOf = oneOf + for (let index = value.oneOf.length - 1; index >= 0; index--) { + tasks.push({ + kind: 'value', + value: value.oneOf[index], + path: `${path}.oneOf[${index}]`, + forceRequired: false, + raw: task.raw, + parameterProperty: false, + destination: { kind: 'one-of', target: oneOf, index }, + }) + } + continue + } + + if (task.raw && !Object.hasOwn(value, 'type')) { + assertSchemaKeys(value, path, ANNOTATION_KEYS) + prop.type = 'json' + continue + } + if (!SCHEMA_TYPES.has(value.type) || task.raw && value.type === 'json') { + throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES} (got ${JSON.stringify(value.type)})`) + } + const type = value.type + prop.type = type + + switch (type) { + case 'object': { + assertSchemaKeys(value, path, ['type', 'properties', 'additionalProperties', ...requiredKey, ...(task.raw ? ['required'] : []), ...ANNOTATION_KEYS]) + if (!task.raw && (!Object.hasOwn(value, 'additionalProperties') || typeof value.additionalProperties !== 'boolean')) { + throw new Error(`harness.defineTool ${path}.additionalProperties must be explicitly true or false`) + } + if (task.raw && Object.hasOwn(value, 'additionalProperties') && typeof value.additionalProperties !== 'boolean') { + throw new Error(`harness.defineTool ${path}.additionalProperties must be a boolean`) + } + if (task.raw && Object.hasOwn(value, 'required') && value.required === undefined) { + throw new Error(`harness.defineTool ${path}.required must be an array of declared property names`) + } + prop.additionalProperties = task.raw ? value.additionalProperties ?? true : value.additionalProperties + if (Object.hasOwn(value, 'properties')) { + const properties = value.properties + if (!isPlainRecord(properties)) throw new Error(`harness.defineTool ${path}.properties must be an object of schemas`) + const nestedRequired = task.raw + ? normalizeRequiredNames(value.required, properties, `${path}.required`) + : new Set<string>() + tasks.push({ + kind: 'map', + entries: properties, + path: `${path}.properties`, + requiredNames: nestedRequired, + raw: task.raw, + destination: { kind: 'properties', target: prop }, + }) + } else if (task.raw && value.required !== undefined) { + normalizeRequiredNames(value.required, {}, `${path}.required`) + } + break + } + case 'array': + assertSchemaKeys(value, path, ['type', 'items', ...requiredKey, ...ANNOTATION_KEYS]) + if (Object.hasOwn(value, 'items')) { + tasks.push({ + kind: 'value', + value: value.items, + path: `${path}.items`, + forceRequired: false, + raw: task.raw, + parameterProperty: false, + destination: { kind: 'item', target: prop }, + }) + } + break + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': + assertSchemaKeys(value, path, ['type', 'enum', 'const', ...requiredKey, ...ANNOTATION_KEYS]) + if (Object.hasOwn(value, 'enum')) { + prop.enum = Array.isArray(value.enum) + ? Array.from(value.enum, (entry, index) => cloneJson(entry, `${path}.enum[${index}]`)) + : value.enum + } + if (Object.hasOwn(value, 'const')) prop.const = cloneJson(value.const, `${path}.const`) + break + case 'json': + assertSchemaKeys(value, path, ['type', ...requiredKey, ...ANNOTATION_KEYS]) + break + /* v8 ignore next 2 -- SCHEMA_TYPES narrows this closed switch before dispatch. */ + default: + throw new Error(`harness.defineTool ${path} must declare a valid type: ${VALID_TYPES}`) + } } + /* v8 ignore next -- the root map task assigns before scheduling descendants. */ + return holder.value ?? {} } function markDynamicTool(tool: ToolDefinition): DynamicToolDefinition { diff --git a/packages/cordis/tool-cordis/tests/mount.spec.ts b/packages/cordis/tool-cordis/tests/mount.spec.ts index 22df219b1b..347e87c76a 100644 --- a/packages/cordis/tool-cordis/tests/mount.spec.ts +++ b/packages/cordis/tool-cordis/tests/mount.spec.ts @@ -274,6 +274,59 @@ describe('cordis_mount', () => { }) }) + it('normalizes and snapshots deeply nested sandbox schemas and annotations stack-safely', async () => { + const ctx = await setup() + const depth = 5_000 + const result = await call(ctx, 'cordis_mount', { + code: ` + return { + name: 'deep-unified-schema', + inject: ['tools'], + apply(ctx) { + let choice = { type: 'string' } + let example = 'leaf' + for (let index = 0; index < ${depth}; index++) { + choice = { oneOf: [choice, { type: 'null' }] } + example = [example] + } + harness.registerTool(ctx, harness.defineTool({ + name: 'deep_unified_schema_tool', + description: 'deep unified nodes', + parameters: { + choice: { ...choice, required: true }, + any: { type: 'json', default: example }, + }, + async execute() { return [] }, + })) + }, + } + `, + }) + expect(result.isError).toBe(false) + + const parameters = ctx.tools.schemas().find(s => s.name === 'deep_unified_schema_tool')!.parameters as { + properties: Record<string, Record<string, unknown>> + } + let choice = parameters.properties.choice! + let choiceDepth = 0 + while (Array.isArray(choice.oneOf)) { + choice = choice.oneOf[0] as Record<string, unknown> + choiceDepth++ + } + let example: unknown = parameters.properties.any!.default + let exampleDepth = 0 + while (Array.isArray(example)) { + example = example[0] + exampleDepth++ + } + expect({ choiceDepth, choice, exampleDepth, example }).toEqual({ + choiceDepth: depth, + choice: { type: 'string' }, + exampleDepth: depth, + example: 'leaf', + }) + }) + it('normalizes unconstrained and closed nested nodes from a raw JSON Schema wrapper', async () => { const ctx = await setup() const result = await call(ctx, 'cordis_mount', { @@ -372,6 +425,47 @@ describe('cordis_mount', () => { expect(text(result)).toContain(message) }) + it.each([ + [ + ` + const parameters = {} + const item = { type: 'array' } + item.items = item + parameters.item = item + `, + 'parameters.item.items is circular', + ], + [ + ` + const parameters = {} + const item = { type: 'object', additionalProperties: true, properties: parameters } + parameters.item = item + `, + 'parameters.item.properties is circular', + ], + ])('rejects circular sandbox schemas without exhausting the call stack', async (declaration, message) => { + const ctx = await setup() + const result = await call(ctx, 'cordis_mount', { + code: ` + return { + name: 'circular-schema', + inject: ['tools'], + apply(ctx) { + ${declaration} + harness.registerTool(ctx, harness.defineTool({ + name: 'circular_schema_tool', + description: 'circular', + parameters, + async execute() { return [] }, + })) + }, + } + `, + }) + expect(result.isError).toBe(true) + expect(text(result)).toContain(message) + }) + it('preserves literal __proto__ keys in sandbox schemas and annotations', async () => { const ctx = await setup() const result = await call(ctx, 'cordis_mount', { diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index bc1f9ffeac..2105120241 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -84,7 +84,7 @@ ctx.tools.register(defineTool({ })) ``` -The unified schema DSL uses `ParameterSchemaSpec` for the implicit open parameter object and `ValueSchemaSpec` for any JSON-value root. It supports `string`, `number`, `integer`, `boolean`, `null`, `array`, `object`, author-only `json`, and exact-one `oneOf`; scalar `enum`/`const` values are type-correct. Every explicit DSL object declares `additionalProperties: true | false`, while the implicit parameter root and raw JSON Schema keep the standard open default. +The unified schema DSL uses `ParameterSchemaSpec` for the implicit open parameter object and `ValueSchemaSpec` for any JSON-value root. It supports `string`, `number`, `integer`, `boolean`, `null`, `array`, `object`, author-only `json`, and exact-one `oneOf`; scalar `enum`/`const` values are type-correct. Every explicit DSL object declares `additionalProperties: true | false`, while the implicit parameter root and raw JSON Schema keep the standard open default. Compilation, validation, registry detachment, and schema-to-TypeScript rendering use explicit work stacks, so valid deep schemas are memory-bounded rather than call-stack-bounded. A `defineTool` definition validates model arguments before execution and turns missing required values, wrong primitives, invalid enum members, and nested violations into `ToolArgsError` (`INVALID_ARGS`) for the normal error-result path. The implicit parameter root is open; an explicit object accepts extra keys only with `additionalProperties: true`, and a closed object with no declared properties accepts only `{}`. Raw JSON Schema objects remain open unless they explicitly set `additionalProperties: false`. Defaults are not applied; open objects without `properties` and arrays without `items` receive only a container type check. Raw-registered tools own their validation. diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 36d2fdd645..5ce9378762 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -773,10 +773,14 @@ export class ToolRegistry extends Service { /** Project one definition onto the model-facing schema fields. */ private schemaOf(definition: ToolDefinition, detachParameters: boolean): ToolSchema { const { name, description, parameters } = definition + const detached = detachParameters ? snapshotJsonValue(parameters) : parameters + if (detached === undefined) { + throw new Error(`tool "${name}" parameters must be lossless JSON before schema projection`) + } return { name, description, - parameters: detachParameters ? structuredClone(parameters) : parameters, + parameters: detached, } } diff --git a/packages/core/tools/src/json-schema.ts b/packages/core/tools/src/json-schema.ts index d849572789..d84b788aef 100644 --- a/packages/core/tools/src/json-schema.ts +++ b/packages/core/tools/src/json-schema.ts @@ -116,18 +116,70 @@ function scalarMatches(type: JsonSchemaScalarType, value: unknown): value is Jso } } -/** Collect every violation for one raw schema node. */ -function checkSchemaNode(node: unknown, path: string, violations: string[], seen: Set<object>): void { - if (!isPlainJsonRecord(node)) { - violations.push(`${path} must be a schema object`) - return +/** Deferred work for the stack-safe raw-schema walk. */ +type SchemaWalkTask = + | { kind: 'enter'; node: unknown; path: string } + | { kind: 'leave'; node: object } + | { kind: 'one-of-tail'; node: Record<string, unknown>; path: string } + | { kind: 'object-tail'; node: Record<string, unknown>; path: string; properties: unknown } + +/** Keywords that are invalid beside `oneOf`. */ +const ONE_OF_SIBLING_KEYWORDS = ['properties', 'required', 'additionalProperties', 'items', 'enum', 'const'] as const + +/** Validate object-only fields after its property schemas have been visited. */ +function checkObjectSchemaTail( + node: Record<string, unknown>, + path: string, + properties: unknown, + violations: string[], +): void { + const required = node.required + if (Object.hasOwn(node, 'required')) { + if (!Array.isArray(required) || required.some(entry => typeof entry !== 'string')) { + violations.push(`${path}.required must be an array of strings`) + } else { + const declared = isPlainJsonRecord(properties) ? properties : {} + for (const key of required as string[]) { + if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names "${key}" which is not in properties`) + } + } } - if (seen.has(node)) { - violations.push(`${path} is circular`) - return + if (Object.hasOwn(node, 'additionalProperties') && typeof node.additionalProperties !== 'boolean') { + violations.push(`${path}.additionalProperties must be a boolean`) } - seen.add(node) - try { +} + +/** Collect every violation for one raw schema tree without using the JavaScript call stack. */ +function checkSchemaNode(root: unknown, rootPath: string, violations: string[], seen: Set<object>): void { + const tasks: SchemaWalkTask[] = [{ kind: 'enter', node: root, path: rootPath }] + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + seen.delete(task.node) + continue + } + if (task.kind === 'one-of-tail') { + for (const key of ONE_OF_SIBLING_KEYWORDS) { + if (Object.hasOwn(task.node, key)) violations.push(`${task.path}.${key} is not supported beside oneOf`) + } + continue + } + if (task.kind === 'object-tail') { + checkObjectSchemaTail(task.node, task.path, task.properties, violations) + continue + } + + const { node, path } = task + if (!isPlainJsonRecord(node)) { + violations.push(`${path} must be a schema object`) + continue + } + if (seen.has(node)) { + violations.push(`${path} is circular`) + continue + } + seen.add(node) + tasks.push({ kind: 'leave', node }) + for (const key of Object.keys(node)) { if (CONSTRAINT_KEYWORDS.has(key)) continue if (ANNOTATION_KEYWORDS.has(key)) { @@ -151,28 +203,26 @@ function checkSchemaNode(node: unknown, path: string, violations: string[], seen const hasOneOf = Object.hasOwn(node, 'oneOf') if (hasType && hasOneOf) { violations.push(`${path} cannot declare both type and oneOf`) - return + continue } if (!hasType && !hasOneOf) { - for (const key of ['properties', 'required', 'additionalProperties', 'items', 'enum', 'const']) { + for (const key of ONE_OF_SIBLING_KEYWORDS) { if (Object.hasOwn(node, key)) violations.push(`${path}.${key} requires type or oneOf`) } - return + continue } if (hasOneOf) { const oneOf = node.oneOf + tasks.push({ kind: 'one-of-tail', node, path }) if (!Array.isArray(oneOf) || oneOf.length < 2) { violations.push(`${path}.oneOf must be an array of at least two schemas`) } else { - for (let index = 0; index < oneOf.length; index++) { - checkSchemaNode(oneOf[index], `${path}.oneOf[${index}]`, violations, seen) + for (let index = oneOf.length - 1; index >= 0; index--) { + tasks.push({ kind: 'enter', node: oneOf[index], path: `${path}.oneOf[${index}]` }) } } - for (const key of ['properties', 'required', 'additionalProperties', 'items', 'enum', 'const']) { - if (Object.hasOwn(node, key)) violations.push(`${path}.${key} is not supported beside oneOf`) - } - return + continue } const type = node.type @@ -180,7 +230,7 @@ function checkSchemaNode(node: unknown, path: string, violations: string[], seen violations.push(Array.isArray(type) ? `${path}.type must be a single type string (type arrays are not supported)` : `${path}.type must be one of ${SCHEMA_TYPES.join('/')}`) - return + continue } const schemaType = type as JsonSchemaType const allowedFor: Record<string, JsonSchemaType[]> = { @@ -200,33 +250,24 @@ function checkSchemaNode(node: unknown, path: string, violations: string[], seen switch (schemaType) { case 'object': { const properties = node.properties + tasks.push({ kind: 'object-tail', node, path, properties }) if (Object.hasOwn(node, 'properties')) { if (!isPlainJsonRecord(properties)) { violations.push(`${path}.properties must be an object of schemas`) } else { - for (const [key, child] of Object.entries(properties)) { - checkSchemaNode(child, `${path}.properties.${key}`, violations, seen) + const entries = Object.entries(properties) + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index] + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) continue + tasks.push({ kind: 'enter', node: entry[1], path: `${path}.properties.${entry[0]}` }) } } } - const required = node.required - if (Object.hasOwn(node, 'required')) { - if (!Array.isArray(required) || required.some(entry => typeof entry !== 'string')) { - violations.push(`${path}.required must be an array of strings`) - } else { - const declared = isPlainJsonRecord(properties) ? properties : {} - for (const key of required as string[]) { - if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names "${key}" which is not in properties`) - } - } - } - if (Object.hasOwn(node, 'additionalProperties') && typeof node.additionalProperties !== 'boolean') { - violations.push(`${path}.additionalProperties must be a boolean`) - } break } case 'array': { - if (Object.hasOwn(node, 'items')) checkSchemaNode(node.items, `${path}.items`, violations, seen) + if (Object.hasOwn(node, 'items')) tasks.push({ kind: 'enter', node: node.items, path: `${path}.items` }) break } case 'string': @@ -238,10 +279,8 @@ function checkSchemaNode(node: unknown, path: string, violations: string[], seen const enumValid = Array.isArray(allowed) && allowed.length > 0 && allowed.every(entry => scalarMatches(schemaType, entry)) - if (Object.hasOwn(node, 'enum')) { - if (!enumValid) { - violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`) - } + if (Object.hasOwn(node, 'enum') && !enumValid) { + violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`) } const constValid = scalarMatches(schemaType, node.const) if (Object.hasOwn(node, 'const')) { @@ -256,8 +295,6 @@ function checkSchemaNode(node: unknown, path: string, violations: string[], seen /* v8 ignore next -- schemaType was narrowed from the closed SCHEMA_TYPES table above. */ default: assertNever(schemaType, 'JsonSchemaType') } - } finally { - seen.delete(node) } } @@ -308,81 +345,57 @@ function propertyPath(path: string, key: string): string { return path === '' ? key : `${path}.${key}` } -/** Contain hostile getters/proxies so validation remains total for arbitrary values. */ -function checkValue(node: JsonSchemaNode, value: unknown, path: string): string[] { - if (node.type !== undefined && !(SCHEMA_TYPES as readonly unknown[]).includes(node.type)) { - return checkValueUnchecked(node, value, path) - } - try { - return checkValueUnchecked(node, value, path) - } catch { - return [`"${diagnosticPath(path)}" must be a lossless JSON value`] +/** One child evaluation deferred by a container or exact-one union frame. */ +interface ValueChild { + readonly node: JsonSchemaNode + readonly value: unknown + readonly path: string +} + +/** Explicit call frame for stack-safe schema-value validation. */ +interface ValueFrame { + readonly node: JsonSchemaNode + readonly value: unknown + readonly path: string + catches: boolean + phase: 'start' | 'children' + kind?: 'oneOf' | 'object' | 'array' + children: ValueChild[] + childIndex: number + violations: string[] + tailViolations: string[] + matches: number +} + +/** The generic exception-containment diagnostic owned by one valid schema node. */ +function losslessValueViolation(path: string): string[] { + return [`"${diagnosticPath(path)}" must be a lossless JSON value`] +} + +/** Append diagnostics without spreading a potentially wide child result as call arguments. */ +function appendViolations(target: string[], source: readonly string[]): void { + for (const violation of source) target.push(violation) +} + +/** Initialize one validation frame with empty aggregation state. */ +function valueFrame(node: JsonSchemaNode, value: unknown, path: string): ValueFrame { + return { + node, + value, + path, + catches: false, + phase: 'start', + children: [], + childIndex: 0, + violations: [], + tailViolations: [], + matches: 0, } } -/** Collect value violations for one trusted schema node after the exception boundary. */ -function checkValueUnchecked(node: JsonSchemaNode, value: unknown, path: string): string[] { - if (node.oneOf !== undefined) { - const matches = node.oneOf.filter(branch => checkValue(branch, value, path).length === 0).length - return matches === 1 ? [] : [`"${diagnosticPath(path)}" must match exactly one oneOf branch (matched ${matches})`] - } - if (node.type === undefined) { - return safelyIsJsonValue(value) ? [] : [`"${diagnosticPath(path)}" must be a lossless JSON value`] - } - - switch (node.type) { - case 'object': { - if (!isPlainJsonRecord(value)) return [`"${diagnosticPath(path)}" must be an object`] - const violations: string[] = [] - const properties = node.properties ?? {} - for (const key of node.required ?? []) { - if (!Object.hasOwn(value, key) || value[key] === undefined) violations.push(`missing required property "${propertyPath(path, key)}"`) - } - for (const [key, child] of Object.entries(properties)) { - if (!Object.hasOwn(value, key) || value[key] === undefined) continue - violations.push(...checkValue(child, value[key], propertyPath(path, key))) - } - if (node.additionalProperties === false) { - for (const key of Object.keys(value)) { - if (!Object.hasOwn(properties, key)) violations.push(`"${propertyPath(path, key)}" is not a declared property (additionalProperties: false)`) - } - } - if (violations.length > 0) return violations - return safelyIsJsonValue(value) ? [] : [`"${diagnosticPath(path)}" must be a lossless JSON object`] - } - case 'array': { - if (!Array.isArray(value)) return [`"${diagnosticPath(path)}" must be an array`] - const items = node.items - const violations = items === undefined - ? [] - : value.flatMap((entry, index) => checkValue(items, entry, `${path}[${index}]`)) - if (violations.length > 0) return violations - return safelyIsJsonValue(value) ? [] : [`"${diagnosticPath(path)}" must be a dense lossless JSON array`] - } - case 'string': { - if (typeof value !== 'string') return [`"${diagnosticPath(path)}" must be a string`] - break - } - case 'number': { - if (typeof value !== 'number') return [`"${diagnosticPath(path)}" must be a number`] - if (!isJsonNumber(value)) return [`"${diagnosticPath(path)}" must be a finite JSON number`] - break - } - case 'integer': { - if (!isJsonNumber(value) || !Number.isInteger(value)) return [`"${diagnosticPath(path)}" must be an integer`] - break - } - case 'boolean': { - if (typeof value !== 'boolean') return [`"${diagnosticPath(path)}" must be a boolean`] - break - } - case 'null': { - if (value !== null) return [`"${diagnosticPath(path)}" must be null`] - break - } - default: return assertNever(node.type, 'JsonSchemaType') - } - if (node.enum !== undefined && !node.enum.includes(value)) { +/** Validate one scalar node after its primitive type check. */ +function checkScalarValue(node: JsonSchemaNode, value: unknown, path: string): string[] { + if (node.enum !== undefined && !node.enum.includes(value as JsonSchemaScalar)) { return [`"${diagnosticPath(path)}" must be one of ${JSON.stringify(node.enum)}`] } if (Object.hasOwn(node, 'const') && value !== node.const) { @@ -391,6 +404,165 @@ function checkValueUnchecked(node: JsonSchemaNode, value: unknown, path: string) return [] } +/** Validate one trusted schema/value pair with explicit frames rather than recursive calls. */ +function checkValue(schema: JsonSchemaNode, value: unknown, path: string): string[] { + const frames: ValueFrame[] = [valueFrame(schema, value, path)] + let rootResult: string[] | undefined + + const receive = (result: string[]): void => { + const parent = frames.at(-1) + if (parent === undefined) { + rootResult = result + return + } + if (parent.kind === 'oneOf') { + if (result.length === 0) parent.matches++ + } else { + appendViolations(parent.violations, result) + } + } + const finish = (result: string[]): void => { + frames.pop() + receive(result) + } + + while (frames.length > 0) { + const frame = frames.at(-1) + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === undefined) break + try { + if (frame.phase === 'children') { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex] + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === undefined) throw new Error('missing schema-value child frame') + frame.childIndex++ + frames.push(valueFrame(child.node, child.value, child.path)) + continue + } + if (frame.kind === 'oneOf') { + finish(frame.matches === 1 ? [] : [`"${diagnosticPath(frame.path)}" must match exactly one oneOf branch (matched ${frame.matches})`]) + continue + } + appendViolations(frame.violations, frame.tailViolations) + if (frame.violations.length > 0) { + finish(frame.violations) + } else if (frame.kind === 'object') { + finish(safelyIsJsonValue(frame.value) ? [] : [`"${diagnosticPath(frame.path)}" must be a lossless JSON object`]) + } else { + finish(safelyIsJsonValue(frame.value) ? [] : [`"${diagnosticPath(frame.path)}" must be a dense lossless JSON array`]) + } + continue + } + + const nodeType = frame.node.type + frame.catches = !(nodeType !== undefined && !(SCHEMA_TYPES as readonly unknown[]).includes(nodeType)) + const oneOf = frame.node.oneOf + if (oneOf !== undefined) { + frame.kind = 'oneOf' + frame.children = Array.from(oneOf, branch => ({ node: branch, value: frame.value, path: frame.path })) + frame.childIndex = 0 + frame.matches = 0 + frame.phase = 'children' + continue + } + if (nodeType === undefined) { + finish(safelyIsJsonValue(frame.value) ? [] : losslessValueViolation(frame.path)) + continue + } + + switch (nodeType) { + case 'object': { + if (!isPlainJsonRecord(frame.value)) { + finish([`"${diagnosticPath(frame.path)}" must be an object`]) + break + } + const properties = frame.node.properties ?? {} + const violations: string[] = [] + for (const key of frame.node.required ?? []) { + if (!Object.hasOwn(frame.value, key) || frame.value[key] === undefined) { + violations.push(`missing required property "${propertyPath(frame.path, key)}"`) + } + } + const children: ValueChild[] = [] + for (const [key, child] of Object.entries(properties)) { + if (!Object.hasOwn(frame.value, key) || frame.value[key] === undefined) continue + children.push({ node: child, value: frame.value[key], path: propertyPath(frame.path, key) }) + } + const tailViolations: string[] = [] + if (frame.node.additionalProperties === false) { + for (const key of Object.keys(frame.value)) { + if (!Object.hasOwn(properties, key)) { + tailViolations.push(`"${propertyPath(frame.path, key)}" is not a declared property (additionalProperties: false)`) + } + } + } + frame.kind = 'object' + frame.children = children + frame.childIndex = 0 + frame.violations = violations + frame.tailViolations = tailViolations + frame.phase = 'children' + break + } + case 'array': { + if (!Array.isArray(frame.value)) { + finish([`"${diagnosticPath(frame.path)}" must be an array`]) + break + } + const items = frame.node.items + const children = items === undefined + ? [] + : frame.value.flatMap((entry, index): ValueChild[] => [{ node: items, value: entry, path: `${frame.path}[${index}]` }]) + frame.kind = 'array' + frame.children = children + frame.childIndex = 0 + frame.violations = [] + frame.phase = 'children' + break + } + case 'string': + finish(typeof frame.value === 'string' + ? checkScalarValue(frame.node, frame.value, frame.path) + : [`"${diagnosticPath(frame.path)}" must be a string`]) + break + case 'number': + finish(typeof frame.value !== 'number' + ? [`"${diagnosticPath(frame.path)}" must be a number`] + : !isJsonNumber(frame.value) + ? [`"${diagnosticPath(frame.path)}" must be a finite JSON number`] + : checkScalarValue(frame.node, frame.value, frame.path)) + break + case 'integer': + finish(!isJsonNumber(frame.value) || !Number.isInteger(frame.value) + ? [`"${diagnosticPath(frame.path)}" must be an integer`] + : checkScalarValue(frame.node, frame.value, frame.path)) + break + case 'boolean': + finish(typeof frame.value === 'boolean' + ? checkScalarValue(frame.node, frame.value, frame.path) + : [`"${diagnosticPath(frame.path)}" must be a boolean`]) + break + case 'null': + finish(frame.value === null + ? checkScalarValue(frame.node, frame.value, frame.path) + : [`"${diagnosticPath(frame.path)}" must be null`]) + break + default: + finish(assertNever(nodeType, 'JsonSchemaType')) + } + } catch (error) { + let failed = frames.pop() + while (failed !== undefined && !failed.catches) failed = frames.pop() + if (failed === undefined) throw error + receive(losslessValueViolation(failed.path)) + } + } + + /* v8 ignore next -- every root frame finishes or throws. */ + return rootResult ?? losslessValueViolation(path) +} + /** * Validate a candidate value against an asserted raw schema. The function is * total for arbitrary values and returns path-qualified violations. diff --git a/packages/core/tools/src/schema.ts b/packages/core/tools/src/schema.ts index 9f52eb6e33..36fd444b64 100644 --- a/packages/core/tools/src/schema.ts +++ b/packages/core/tools/src/schema.ts @@ -180,66 +180,172 @@ function assertAuthorKeys(source: Record<string, unknown>, path: string, allowed } } -/** Compile one implicit property map, collecting per-property requiredness. */ -function compilePropertyMap( - input: unknown, - path: string, - seen: Set<object>, -): { properties: Record<string, JsonSchemaNode>; required?: string[] } { - if (!isPlainJsonRecord(input)) authorError(`${path} must be an object of value schemas`) - if (seen.has(input)) authorError(`${path} is circular`) - seen.add(input) - try { - const properties: Record<string, JsonSchemaNode> = {} - const required: string[] = [] - for (const [key, property] of Object.entries(input)) { - if (!isPlainJsonRecord(property)) authorError(`${path}.${key} must be a value schema object`) - if (Object.hasOwn(property, 'required') && property.required !== true) { - authorError(`${path}.${key}.required must be true when present`) - } - Object.defineProperty(properties, key, { - value: compileValueSchema(property, `${path}.${key}`, seen, true), +/** Compiled form of one implicit property map. */ +interface CompiledPropertyMap { + properties: Record<string, JsonSchemaNode> + required?: string[] +} + +/** Mutable holder used only while an iterative compilation root is unresolved. */ +interface CompileRoot<T> { + value?: T +} + +/** Where one compiled value node is installed. */ +type NodeDestination = + | { kind: 'root'; holder: CompileRoot<JsonSchemaNode> } + | { kind: 'property'; target: Record<string, JsonSchemaNode>; key: string } + | { kind: 'item'; target: JsonSchemaNode } + | { kind: 'one-of'; target: JsonSchemaNode[]; index: number } + +/** Where one compiled property map is installed. */ +type PropertyMapDestination = + | { kind: 'root'; holder: CompileRoot<CompiledPropertyMap> } + | { kind: 'object'; target: JsonSchemaNode } + +/** Deferred work for stack-safe author-schema compilation. */ +type CompileTask = + | { kind: 'value'; input: unknown; path: string; allowRequired: boolean; destination: NodeDestination } + | { kind: 'property-map'; input: unknown; path: string; destination: PropertyMapDestination } + | { + kind: 'property' + property: unknown + path: string + key: string + properties: Record<string, JsonSchemaNode> + required: string[] + } + | { + kind: 'property-map-tail' + compiled: CompiledPropertyMap + required: string[] + destination: PropertyMapDestination + } + | { kind: 'leave'; input: object } + +/** Install a compiled node without giving `__proto__` assignment semantics. */ +function assignCompiledNode(destination: NodeDestination, node: JsonSchemaNode): void { + switch (destination.kind) { + case 'root': + destination.holder.value = node + break + case 'property': + Object.defineProperty(destination.target, destination.key, { + value: node, enumerable: true, configurable: true, writable: true, }) - if (property.required === true) required.push(key) - } - return required.length > 0 ? { properties, required } : { properties } - } finally { - seen.delete(input) + break + case 'item': + destination.target.items = node + break + case 'one-of': + destination.target[destination.index] = node + break } } -/** Compile one author node without applying any consumer root restriction. */ -function compileValueSchema( - input: unknown, - path: string, - seen: Set<object>, - allowRequired = false, -): JsonSchemaNode { - if (!isPlainJsonRecord(input)) authorError(`${path} must be a value schema object`) - if (seen.has(input)) authorError(`${path} is circular`) - seen.add(input) - try { - const authorKeys = [...ANNOTATION_KEYS, ...(allowRequired ? ['required'] : [])] +/** Install a compiled property map at its root or containing object node. */ +function assignCompiledPropertyMap(destination: PropertyMapDestination, compiled: CompiledPropertyMap): void { + if (destination.kind === 'root') { + destination.holder.value = compiled + } else { + destination.target.properties = compiled.properties + } +} + +/** Execute an author-schema compilation task graph without recursive descent. */ +function runSchemaCompiler(initial: CompileTask): void { + const seen = new Set<object>() + const tasks: CompileTask[] = [initial] + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (task.kind === 'leave') { + seen.delete(task.input) + continue + } + if (task.kind === 'property-map-tail') { + if (task.required.length > 0) { + task.compiled.required = task.required + if (task.destination.kind === 'object') task.destination.target.required = task.required + } + continue + } + if (task.kind === 'property') { + if (!isPlainJsonRecord(task.property)) authorError(`${task.path} must be a value schema object`) + if (Object.hasOwn(task.property, 'required') && task.property.required !== true) { + authorError(`${task.path}.required must be true when present`) + } + if (task.property.required === true) task.required.push(task.key) + tasks.push({ + kind: 'value', + input: task.property, + path: task.path, + allowRequired: true, + destination: { kind: 'property', target: task.properties, key: task.key }, + }) + continue + } + if (task.kind === 'property-map') { + if (!isPlainJsonRecord(task.input)) authorError(`${task.path} must be an object of value schemas`) + if (seen.has(task.input)) authorError(`${task.path} is circular`) + seen.add(task.input) + const compiled: CompiledPropertyMap = { properties: {} } + const required: string[] = [] + assignCompiledPropertyMap(task.destination, compiled) + tasks.push({ kind: 'leave', input: task.input }) + tasks.push({ kind: 'property-map-tail', compiled, required, destination: task.destination }) + const entries = Object.entries(task.input) + for (let index = entries.length - 1; index >= 0; index--) { + const entry = entries[index] + /* v8 ignore next -- the loop is bounded by the captured entry count. */ + if (entry === undefined) continue + tasks.push({ + kind: 'property', + property: entry[1], + path: `${task.path}.${entry[0]}`, + key: entry[0], + properties: compiled.properties, + required, + }) + } + continue + } + + const { input, path } = task + if (!isPlainJsonRecord(input)) authorError(`${path} must be a value schema object`) + if (seen.has(input)) authorError(`${path} is circular`) + seen.add(input) + const authorKeys = [...ANNOTATION_KEYS, ...(task.allowRequired ? ['required'] : [])] const node: JsonSchemaNode = {} + assignCompiledNode(task.destination, node) + tasks.push({ kind: 'leave', input }) if (Object.hasOwn(input, 'oneOf')) { assertAuthorKeys(input, path, [...authorKeys, 'oneOf', 'type']) if (Object.hasOwn(input, 'type')) authorError(`${path} cannot declare both type and oneOf`) if (!Array.isArray(input.oneOf)) authorError(`${path}.oneOf must be an array of at least two value schemas`) - node.oneOf = input.oneOf.map((branch, index) => compileValueSchema(branch, `${path}.oneOf[${index}]`, seen)) + const branches: JsonSchemaNode[] = [] + node.oneOf = branches copyAnnotations(input, node) - return node + for (let index = input.oneOf.length - 1; index >= 0; index--) { + tasks.push({ + kind: 'value', + input: input.oneOf[index], + path: `${path}.oneOf[${index}]`, + allowRequired: false, + destination: { kind: 'one-of', target: branches, index }, + }) + } + continue } switch (input.type) { case 'json': assertAuthorKeys(input, path, [...authorKeys, 'type']) copyAnnotations(input, node) - return node - case 'object': { + break + case 'object': assertAuthorKeys(input, path, [...authorKeys, 'type', 'properties', 'additionalProperties']) if (!Object.hasOwn(input, 'additionalProperties') || typeof input.additionalProperties !== 'boolean') { authorError(`${path}.additionalProperties must be explicitly true or false`) @@ -248,18 +354,28 @@ function compileValueSchema( copyAnnotations(input, node) node.additionalProperties = input.additionalProperties if (Object.hasOwn(input, 'properties')) { - const compiled = compilePropertyMap(input.properties, `${path}.properties`, seen) - node.properties = compiled.properties - if (compiled.required !== undefined) node.required = compiled.required + tasks.push({ + kind: 'property-map', + input: input.properties, + path: `${path}.properties`, + destination: { kind: 'object', target: node }, + }) } - return node - } + break case 'array': assertAuthorKeys(input, path, [...authorKeys, 'type', 'items']) node.type = 'array' copyAnnotations(input, node) - if (Object.hasOwn(input, 'items')) node.items = compileValueSchema(input.items, `${path}.items`, seen) - return node + if (Object.hasOwn(input, 'items')) { + tasks.push({ + kind: 'value', + input: input.items, + path: `${path}.items`, + allowRequired: false, + destination: { kind: 'item', target: node }, + }) + } + break case 'string': case 'number': case 'integer': @@ -274,15 +390,29 @@ function compileValueSchema( : input.enum as JsonSchemaScalar[] } if (Object.hasOwn(input, 'const')) node.const = input.const as JsonSchemaScalar - return node + break default: - return authorError(`${path}.type must be string/number/integer/boolean/null/array/object/json, or use oneOf`) + authorError(`${path}.type must be string/number/integer/boolean/null/array/object/json, or use oneOf`) } - } finally { - seen.delete(input) } } +/** Compile one implicit property map, collecting per-property requiredness. */ +function compilePropertyMap(input: unknown, path: string): CompiledPropertyMap { + const holder: CompileRoot<CompiledPropertyMap> = {} + runSchemaCompiler({ kind: 'property-map', input, path, destination: { kind: 'root', holder } }) + /* v8 ignore next -- the root task assigns before scheduling any descendants. */ + return holder.value ?? authorError(`${path} did not compile`) +} + +/** Compile one author node without applying any consumer root restriction. */ +function compileValueSchema(input: unknown, path: string): JsonSchemaNode { + const holder: CompileRoot<JsonSchemaNode> = {} + runSchemaCompiler({ kind: 'value', input, path, allowRequired: false, destination: { kind: 'root', holder } }) + /* v8 ignore next -- the root task assigns before scheduling any descendants. */ + return holder.value ?? authorError(`${path} did not compile`) +} + /** * Compile one author-facing value schema to the enforced raw JSON Schema * subset. The author-only `json` node becomes an annotation-only schema. @@ -290,7 +420,7 @@ function compileValueSchema( * @returns The asserted raw schema projection. */ export function valueSchemaSpecToJsonSchema(spec: ValueSchemaSpec): JsonSchemaNode { - const schema = compileValueSchema(spec, 'schema', new Set()) + const schema = compileValueSchema(spec, 'schema') assertSupportedJsonSchema(schema) return schema } @@ -301,7 +431,7 @@ export function valueSchemaSpecToJsonSchema(spec: ValueSchemaSpec): JsonSchemaNo * @returns An object-rooted raw schema with no implicit-root openness override. */ export function parameterSchemaSpecToJsonSchema(spec: ParameterSchemaSpec): ParameterJsonSchema { - const compiled = compilePropertyMap(spec, 'parameters', new Set()) + const compiled = compilePropertyMap(spec, 'parameters') const schema: ParameterJsonSchema = { type: 'object', properties: compiled.properties, diff --git a/packages/core/tools/src/ts-types.ts b/packages/core/tools/src/ts-types.ts index 39cec5665e..6fa1a99c49 100644 --- a/packages/core/tools/src/ts-types.ts +++ b/packages/core/tools/src/ts-types.ts @@ -8,7 +8,7 @@ import type { ToolSchema } from '@deepseek-ai/dsh-llm' import { assertSupportedJsonSchema } from './json-schema.ts' -import type { JsonSchemaScalar } from './json-schema.ts' +import type { JsonSchemaNode, JsonSchemaScalar } from './json-schema.ts' /** Property names that are valid bare TS identifiers; anything else is quoted. */ const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/ @@ -47,9 +47,181 @@ function renderConstrainedScalar(node: Record<string, unknown>, type: string): s return broad } -/** Parenthesize a union or object intersection before applying `[]`. */ -function arrayItem(type: string): string { - return type.includes('|') || type.includes('&') ? `(${type})[]` : `${type}[]` +/** A composable type document that can be flattened without recursive string concatenation. */ +interface TypeDocument { + readonly parts: readonly (string | TypeDocument)[] + readonly containsUnionOrIntersection: boolean +} + +/** Build one document from captured parts while retaining the legacy array-parenthesization test. */ +function typeDocumentFrom(parts: readonly (string | TypeDocument)[]): TypeDocument { + return { + parts, + containsUnionOrIntersection: parts.some(part => typeof part === 'string' + ? part.includes('|') || part.includes('&') + : part.containsUnionOrIntersection), + } +} + +/** Build a small document without an intermediate array at each call site. */ +function typeDocument(...parts: (string | TypeDocument)[]): TypeDocument { + return typeDocumentFrom(parts) +} + +/** Flatten a nested document with an explicit work stack. */ +function flattenTypeDocument(document: TypeDocument): string { + const chunks: string[] = [] + const tasks: (string | TypeDocument)[] = [document] + for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { + if (typeof task === 'string') { + chunks.push(task) + continue + } + for (let index = task.parts.length - 1; index >= 0; index--) { + const part = task.parts[index] + /* v8 ignore next -- the loop is bounded by the captured part count. */ + if (part !== undefined) tasks.push(part) + } + } + return chunks.join('') +} + +/** One explicit call frame for stack-safe schema-to-TypeScript rendering. */ +interface SchemaRenderFrame { + readonly node: JsonSchemaNode + readonly indent: number + phase: 'start' | 'children' + kind?: 'oneOf' | 'array' | 'object' + children: { node: JsonSchemaNode; indent: number }[] + childIndex: number + childDocuments: TypeDocument[] + entries: [string, JsonSchemaNode][] +} + +/** Initialize one schema-render frame with empty aggregation state. */ +function schemaRenderFrame(node: JsonSchemaNode, indent: number): SchemaRenderFrame { + return { node, indent, phase: 'start', children: [], childIndex: 0, childDocuments: [], entries: [] } +} + +/** Render an already asserted schema to a composable document. */ +function renderSupportedSchema(schema: JsonSchemaNode, indent: number): TypeDocument { + const frames: SchemaRenderFrame[] = [schemaRenderFrame(schema, indent)] + let rootDocument: TypeDocument | undefined + const finish = (document: TypeDocument): void => { + frames.pop() + const parent = frames.at(-1) + if (parent === undefined) rootDocument = document + else parent.childDocuments.push(document) + } + + while (frames.length > 0) { + const frame = frames.at(-1) + /* v8 ignore next -- the loop condition guarantees a current frame. */ + if (frame === undefined) break + if (frame.phase === 'children') { + if (frame.childIndex < frame.children.length) { + const child = frame.children[frame.childIndex] + /* v8 ignore next -- childIndex is bounded by children.length. */ + if (child === undefined) throw new Error('missing schema render child') + frame.childIndex++ + frames.push(schemaRenderFrame(child.node, child.indent)) + continue + } + if (frame.kind === 'oneOf') { + const parts: (string | TypeDocument)[] = [] + for (let index = 0; index < frame.childDocuments.length; index++) { + if (index > 0) parts.push(' | ') + const child = frame.childDocuments[index] + /* v8 ignore next -- child documents correspond one-to-one with children. */ + if (child !== undefined) parts.push(child) + } + finish(typeDocumentFrom(parts)) + continue + } + if (frame.kind === 'array') { + const child = frame.childDocuments[0] + /* v8 ignore next -- array frames always schedule exactly one child. */ + if (child === undefined) throw new Error('missing array item type') + finish(child.containsUnionOrIntersection + ? typeDocument('(', child, ')[]') + : typeDocument(child, '[]')) + continue + } + + const required = new Set(frame.node.required) + const parts: (string | TypeDocument)[] = ['{'] + for (let index = 0; index < frame.entries.length; index++) { + const entry = frame.entries[index] + const child = frame.childDocuments[index] + /* v8 ignore next -- object entries and child documents have the same length. */ + if (entry === undefined || child === undefined) throw new Error('missing object property type') + const [name, prop] = entry + for (const line of docLines(prop.description, frame.indent + 1)) parts.push('\n', line) + parts.push('\n', `${pad(frame.indent + 1)}${renderKey(name)}${required.has(name) ? '' : '?'}: `, child, ';') + } + parts.push('\n', `${pad(frame.indent)}}`) + const declared = typeDocumentFrom(parts) + finish(frame.node.additionalProperties === false + ? declared + : typeDocument(declared, ' & Record<string, JsonValue>')) + continue + } + + const node = frame.node + if (node.oneOf !== undefined) { + frame.kind = 'oneOf' + frame.children = Array.from(node.oneOf, child => ({ node: child, indent: frame.indent })) + frame.childIndex = 0 + frame.childDocuments = [] + frame.phase = 'children' + continue + } + if (node.type === undefined) { + finish(typeDocument('JsonValue')) + continue + } + switch (node.type) { + case 'string': + case 'number': + case 'integer': + case 'boolean': + case 'null': + finish(typeDocument(renderConstrainedScalar(node as Record<string, unknown>, node.type))) + break + case 'array': + if (node.items === undefined) { + finish(typeDocument('JsonValue[]')) + } else { + frame.kind = 'array' + frame.children = [{ node: node.items, indent: frame.indent }] + frame.childIndex = 0 + frame.childDocuments = [] + frame.phase = 'children' + } + break + case 'object': { + const open = node.additionalProperties !== false + const entries = Object.entries(node.properties ?? {}) + if (entries.length === 0) { + finish(typeDocument(open ? 'Record<string, JsonValue>' : 'Record<string, never>')) + } else { + frame.kind = 'object' + frame.entries = entries + frame.children = entries.map(([, child]) => ({ node: child, indent: frame.indent + 1 })) + frame.childIndex = 0 + frame.childDocuments = [] + frame.phase = 'children' + } + break + } + /* v8 ignore next -- assertSupportedJsonSchema narrowed this closed type union. */ + default: + finish(typeDocument('unknown')) + } + } + + /* v8 ignore next -- every root frame produces one document. */ + return rootDocument ?? typeDocument('unknown') } /** @@ -63,43 +235,10 @@ function arrayItem(type: string): string { export function jsonSchemaToTs(schema: unknown, indent = 0): string { try { assertSupportedJsonSchema(schema) + return flattenTypeDocument(renderSupportedSchema(schema, indent)) } catch { return 'unknown' } - const node = schema as Record<string, unknown> - if (Object.hasOwn(node, 'oneOf')) { - return (node.oneOf as unknown[]).map(branch => jsonSchemaToTs(branch, indent)).join(' | ') - } - if (!Object.hasOwn(node, 'type')) return 'JsonValue' - switch (node.type) { - case 'string': return renderConstrainedScalar(node, 'string') - case 'number': return renderConstrainedScalar(node, 'number') - case 'integer': return renderConstrainedScalar(node, 'integer') - case 'boolean': return renderConstrainedScalar(node, 'boolean') - case 'null': return renderConstrainedScalar(node, 'null') - case 'array': { - return arrayItem(Object.hasOwn(node, 'items') ? jsonSchemaToTs(node.items, indent) : 'JsonValue') - } - case 'object': { - const properties = node.properties - const open = node.additionalProperties !== false - if (properties === undefined) return open ? 'Record<string, JsonValue>' : 'Record<string, never>' - const entries = Object.entries(properties as Record<string, unknown>) - if (entries.length === 0) return open ? 'Record<string, JsonValue>' : 'Record<string, never>' - const required = new Set(node.required as string[] | undefined) - const lines: string[] = ['{'] - for (const [name, prop] of entries) { - const description = (prop as Record<string, unknown>).description - lines.push(...docLines(description, indent + 1)) - lines.push(`${pad(indent + 1)}${renderKey(name)}${required.has(name) ? '' : '?'}: ${jsonSchemaToTs(prop, indent + 1)};`) - } - lines.push(`${pad(indent)}}`) - const declared = lines.join('\n') - return open ? `${declared} & Record<string, JsonValue>` : declared - } - /* v8 ignore next -- assertSupportedJsonSchema narrowed this closed type union. */ - default: return 'unknown' - } } /** The fixed model-facing usage contract rendered above the declarations (see the Code Mode Agent Note's "What the model sees"). */ diff --git a/packages/core/tools/tests/json-schema.spec.ts b/packages/core/tools/tests/json-schema.spec.ts index 8be1bbd35d..67b5501fe0 100644 --- a/packages/core/tools/tests/json-schema.spec.ts +++ b/packages/core/tools/tests/json-schema.spec.ts @@ -214,6 +214,14 @@ describe('the enforced raw JSON Schema subset', () => { .toEqual(['schema.properties.at must be a schema object']) }) + it('asserts deeply nested raw unions without using the JavaScript call stack', () => { + const depth = 5_000 + let schema: JsonSchemaNode = { type: 'string' } + for (let index = 0; index < depth; index++) schema = { oneOf: [schema, { type: 'null' }] } + + expect(() => { assertSupportedJsonSchema(schema) }).not.toThrow() + }) + it('uses own-property semantics for required declarations', () => { expect(violationsOf({ type: 'object', properties: {}, required: ['toString'] })) .toEqual(['schema.required names "toString" which is not in properties']) @@ -322,6 +330,17 @@ describe('validateJsonSchemaValue', () => { expect(validateJsonSchemaValue(overlap, 1.5)).toEqual([]) }) + it('validates deeply nested exact-one unions without using the JavaScript call stack', () => { + const depth = 5_000 + let schema: JsonSchemaNode = { type: 'string' } + for (let index = 0; index < depth; index++) schema = { oneOf: [schema, { type: 'null' }] } + assertSupportedJsonSchema(schema) + + expect(validateJsonSchemaValue(schema, 'leaf')).toEqual([]) + expect(validateJsonSchemaValue(schema, 42)) + .toEqual(['"value" must match exactly one oneOf branch (matched 0)']) + }) + it('an unconstrained schema accepts only lossless JSON values', () => { const anyJson = asserted({}) for (const value of [null, true, 1, 'x', [1], { x: null }]) { diff --git a/packages/core/tools/tests/schema.spec.ts b/packages/core/tools/tests/schema.spec.ts index 8de826aade..b16c0689b0 100644 --- a/packages/core/tools/tests/schema.spec.ts +++ b/packages/core/tools/tests/schema.spec.ts @@ -92,6 +92,23 @@ describe('the unified author schema DSL', () => { expect(() => parameterSchemaSpecToJsonSchema(properties as ParameterSchemaSpec)).toThrow(/circular/) }) + it('compiles deeply nested author unions without using the JavaScript call stack', () => { + const depth = 5_000 + let spec: unknown = { type: 'string' } + for (let index = 0; index < depth; index++) spec = { oneOf: [spec, { type: 'null' }] } + + const compiled = valueSchemaSpecToJsonSchema(spec as ValueSchemaSpec) + + let cursor = compiled + let layers = 0 + while (cursor.oneOf !== undefined) { + cursor = cursor.oneOf[0]! + layers++ + } + expect(layers).toBe(depth) + expect(cursor).toEqual({ type: 'string' }) + }) + it('preserves a property literally named __proto__ as schema data', () => { const properties = Object.create(null) as ParameterSchemaSpec properties.__proto__ = { type: 'string', required: true } diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index c1c920fed2..0150a10a2b 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -8,7 +8,7 @@ import ToolRegistry, { defineTool, JsonSchemaError, parameterSchemaSpecToJsonSchema, validateArgs, ToolArgsError, ToolNotFoundError, TOOL_ABORTED, TOOL_ABORTED_BEFORE_DISPATCH, type InferArgs, type JsonValue, type ParameterSchemaSpec, type PreToolDecision, type PostToolDecision, - type ToolDispatchExecution, type ToolExecutionResult, + type JsonSchemaNode, type ToolDispatchExecution, type ToolExecutionResult, } from '@deepseek-ai/dsh-tools' const testToolSignal = new AbortController().signal @@ -1289,6 +1289,41 @@ describe('ToolRegistry', () => { }]) }) + it('schemas() snapshots deeply nested parameters without using structured-clone recursion', async () => { + const ctx = await setup() + const depth = 5_000 + let nested: JsonSchemaNode = { type: 'string' } + for (let index = 0; index < depth; index++) nested = { oneOf: [nested, { type: 'null' }] } + ctx.tools.register({ + ...echoTool, + name: 'deep-schema', + parameters: { type: 'object', properties: { nested } }, + }) + + const projected = ctx.tools.schemas()[0]!.parameters as JsonSchemaNode + + let cursor = projected.properties!.nested! + let layers = 0 + while (cursor.oneOf !== undefined) { + cursor = cursor.oneOf[0]! + layers++ + } + expect(layers).toBe(depth) + expect(cursor).toEqual({ type: 'string' }) + }) + + it('rejects schema projection when a raw registration is not lossless JSON', async () => { + const ctx = await setup() + ctx.tools.register({ + ...echoTool, + name: 'lossy-schema', + parameters: { type: 'object', default: Number.NaN }, + }) + + expect(() => ctx.tools.schemas()) + .toThrow('tool "lossy-schema" parameters must be lossless JSON before schema projection') + }) + it('rejects a non-positive or non-finite registration timeout', async () => { const ctx = await setup() expect(() => ctx.tools.register({ ...echoTool, name: 'zero-timeout', timeoutMs: 0 })) diff --git a/packages/core/tools/tests/ts-types.spec.ts b/packages/core/tools/tests/ts-types.spec.ts index 14b14f7ecd..078081f49e 100644 --- a/packages/core/tools/tests/ts-types.spec.ts +++ b/packages/core/tools/tests/ts-types.spec.ts @@ -93,6 +93,17 @@ describe('jsonSchemaToTs', () => { expect(rendered).not.toContain('tool-*/ over') expect(rendered).toContain(String.raw`tool-*\/ over`) }) + + it('renders deeply nested unions without using the JavaScript call stack', () => { + const depth = 5_000 + let schema: unknown = { type: 'string' } + for (let index = 0; index < depth; index++) schema = { oneOf: [schema, { type: 'null' }] } + + const rendered = jsonSchemaToTs(schema) + + expect(rendered.startsWith('string | null')).toBe(true) + expect(rendered.length).toBe('string'.length + depth * ' | null'.length) + }) }) describe('renderToolsSdk', () => { From 92f4a3341ec8962cef9318d10d5390e3d4fd9d39 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:07:02 +0800 Subject: [PATCH 088/368] test(snapshots): record canonical diff metadata --- .../tests/snapshots/session-sandbox-root/session.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/acp-agent/tests/snapshots/session-sandbox-root/session.jsonl b/examples/acp-agent/tests/snapshots/session-sandbox-root/session.jsonl index 1abfd3ba7d..e92adbafb9 100644 --- a/examples/acp-agent/tests/snapshots/session-sandbox-root/session.jsonl +++ b/examples/acp-agent/tests/snapshots/session-sandbox-root/session.jsonl @@ -14,7 +14,7 @@ {"type":"assistant/chunk","seq":12,"time":1784567324143,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":13,"time":1784567324144,"data":{"turn":1,"step":1,"content":[{"type":"tool-call","id":"call_session_root","name":"write","arguments":"{\"file_path\":\"session-root.txt\",\"content\":\"session root\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":10,"outputTokens":5}},"sourceEventSeqs":[8,9,10,11,12],"surfaceOp":"append"} {"type":"tool/call","seq":14,"time":1784567324145,"data":{"turn":1,"step":1,"callId":"call_session_root","name":"write","arguments":"{\"file_path\":\"session-root.txt\",\"content\":\"session root\"}"}} -{"type":"tool/result","seq":15,"time":1784567324155,"data":{"turn":1,"step":1,"callId":"call_session_root","content":[{"type":"text","text":"<path>/Users/cty/acp-snap-cwd-MABAjO/session-root.txt</path>\n<type>file</type>\n<content>\nCreated file\n</content>"}],"isError":false},"sourceEventSeqs":[14],"surfaceOp":"append"} +{"type":"tool/result","seq":15,"time":1784567324155,"data":{"turn":1,"step":1,"callId":"call_session_root","content":[{"type":"text","text":"<path>/Users/cty/acp-snap-cwd-MABAjO/session-root.txt</path>\n<type>file</type>\n<content>\nCreated file\n</content>"}],"isError":false,"meta":{"diffs":[]}},"sourceEventSeqs":[14],"surfaceOp":"append"} {"type":"step/end","seq":16,"time":1784567324157,"data":{"turn":1,"step":1}} {"type":"step/start","seq":17,"time":1784567324157,"data":{"turn":1,"step":2}} {"type":"assistant/chunk","seq":18,"time":1784567324157,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"text"}}} From 3fd5d5dc2b895f0e2ee0e4db0de66dfdd648ea3b Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:11:02 +0800 Subject: [PATCH 089/368] docs(i18n): address core translation review --- docs/defensive-patterns.i18n.yaml | 4 ++-- docs/defensive-patterns.zh.md | 2 +- docs/glossary.i18n.yaml | 4 ++-- docs/glossary.zh.md | 30 +++++++++++++++++++++++++++--- docs/i18n/README.i18n.yaml | 4 ++-- docs/i18n/README.md | 2 +- docs/i18n/README.zh.md | 2 +- docs/testing.i18n.yaml | 4 ++-- docs/testing.md | 6 +++--- docs/testing.zh.md | 23 +++++++++++++++-------- 10 files changed, 56 insertions(+), 25 deletions(-) diff --git a/docs/defensive-patterns.i18n.yaml b/docs/defensive-patterns.i18n.yaml index 96bb5de13f..b39cad3e24 100644 --- a/docs/defensive-patterns.i18n.yaml +++ b/docs/defensive-patterns.i18n.yaml @@ -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 -defensive-patterns.md: fda0be0d2d3b7fa099162123b3d219673eebd07d -defensive-patterns.zh.md: f6e4712a4a239c954193f63f32285037eb6d4f0e +defensive-patterns.md: 349b916df6f7544300dacd578acf42668d9436ac +defensive-patterns.zh.md: 19565f54595195a52d1b49ff487294945171ae2d diff --git a/docs/defensive-patterns.zh.md b/docs/defensive-patterns.zh.md index f6e4712a4a..19565f5459 100644 --- a/docs/defensive-patterns.zh.md +++ b/docs/defensive-patterns.zh.md @@ -14,7 +14,7 @@ ## 异步状态不是同步状态 -`agent.send()` 不会在返回前翻转状态;后台任务的完成与轮次边界存在竞争;`reader.close()` 在 EOF 和 dispose(资源释放)两种情况下都会触发。切勿基于一个刚刚请求的状态来控制流程——应以实际触发的事件/promise(`agent/status`、`task.done`)驱动生命周期,并观察状态转换(先看到 `running` 再看到 `idle`),而非计数你假定与轮次一一对应的操作(循环会批量处理排队消息)。这条守则是双向的:如果等待的转换永远不会发生(EOF 时没有提交过任何工作 → 永远不会进入 `running`),等待就会挂起——请显式处理「无需等待」的分支。 +`agent.send()` 不会在返回前翻转状态;后台任务的完成与轮次边界存在竞争;`reader.close()` 在 EOF 和 dispose(资源释放)两种情况下都会触发。切勿基于一个刚刚请求的状态来控制流程——应以实际触发的事件/promise(`agent/status`、`task.done`)驱动生命周期,并观察状态转换(先看到 `running` 再看到 `idle`),而不是把状态当作单次发送的结果:多个排队发送会在同一个 `running` 区间内连续运行多个轮次,而取消或资源释放可能丢弃尚未启动的项。这条守则是双向的:如果等待的转换永远不会发生(EOF 时没有提交过任何工作 → 永远不会进入 `running`),等待就会挂起——请显式处理「无需等待」的分支。 ## Dispose 必须达到静止,而不仅仅是请求停止 diff --git a/docs/glossary.i18n.yaml b/docs/glossary.i18n.yaml index fe099eb156..6352220975 100644 --- a/docs/glossary.i18n.yaml +++ b/docs/glossary.i18n.yaml @@ -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 -glossary.md: 23eebc5793e8232482a796f5bde1e794f0556208 -glossary.zh.md: a233f926ba3af0a4e90de90bf21d68a2244c3ea6 +glossary.md: c1931c0e0c630d05f5bd4fc3f30720f858f1175e +glossary.zh.md: f8f3c9489a8be94de7fb3f021dd70bea7a399d73 diff --git a/docs/glossary.zh.md b/docs/glossary.zh.md index a233f926ba..f8f3c9489a 100644 --- a/docs/glossary.zh.md +++ b/docs/glossary.zh.md @@ -2,9 +2,9 @@ [English](glossary.md) | 中文 -DeepSeek Harness SDK 的领域词汇对每个概念使用唯一的规范术语。各术语通过标准 Markdown 锚点互相链接;实现细节留在各 package README 与 RFC 中。 +DeepSeek Harness SDK 的领域词汇为每个概念规定一个规范术语。各术语通过标准 Markdown 锚点链接到相应条目;实现细节留在各包(package)的 README 与 Agent Note(agent 决策记录)中。 -FIXME(glossary-completeness): Expand this glossary before the first release so it covers the SDK's other core and capability subsystems, not only agent scope. +FIXME(glossary-completeness): 首次发布前扩充本术语表,使其覆盖 SDK 的其他核心与能力子系统,而非仅限于 agent scope。 ## agent-scope @@ -16,4 +16,28 @@ FIXME(glossary-completeness): Expand this glossary before the first release so i - **shadowing**:最具体者胜出的名称解析:一个有范围的工具/片段/变量仅在该 scope 内替换同名的全局对应项。这是按 agent 定制 persona 和按 agent 定制工具变体的机制。 - **restriction / scope-local 注册**:restriction(`tools.restrict`)为单个 scope 过滤全局工具表面(多个 restriction 取交集组合);scope-local 注册在过滤之后合并。被过滤掉的全局工具既不出现在提示词中,也拒绝执行,与不存在的工具无法区分。 - **setup window**:创建者组装 agent 有范围世界的创建时隙(`CreateAgentOptions.setup`):在 scope 和 agent 对象已存在、但 agent 或会话尚未发布、`agent/session-start` 尚未触发、首次提示词尚未组装之前。setup 只做注册,从不驱动 agent。 -- **lineage**:以数据形式携带的父子关系事实(`parentSession`、`subagentDepth`);从不影响可见性。<a id="lineage"></a> +- **lineage**:以数据形式携带的父子关系事实(`parentSession`、持久的 `delegationDepth`、运行时 `subagentDepth`);从不影响可见性。<a id="lineage"></a> + +## 目标 + +- **目标**:附着在现有会话上的单个持久完成目标,带有按修订号演进的 `active` / `paused` / `blocked` / `complete` 阶段和目标回合上限;`blocked` 保留策略代码与说明。目标是一种状态,不是调度器,也不是一段独立对话;会话日志仍是其真源。 +- **目标回合**:为当前目标接纳的一次续行周期。同会话驱动器将目标回合具体化为一个来源为目标的[轮次](#turn),其中可以包含多个步骤;同一会话中无关的人类轮次不消耗目标回合上限。<a id="goal-round"></a> +- **目标激活**:续行消费方接纳下一个目标回合的进程本地权限。激活态为 `armed` 或 `disarmed`;它有意不参与持久回放,因此恢复和 fork 后,必须由人类随后通过 `/goal` 或模型工具授权恢复变更,自动工作才可开始。 + +## 人类命令 + +- **人类命令**:以斜杠开头的指令,由面向人类的适配器通过 `ctx.commands` 解释并执行,不会成为模型消息。它既不同于面向模型的工具,也不同于通过 `ctx.bash` 执行 shell 命令。 +- **命令平面**:由 UI 适配器与命令插件拥有的发现、解析、分发、取消和结果渲染。除非处理器另行改变持久领域,否则命令输出属于 UI 状态。 +- **目标命令**:`/goal` 是由 `dsh-command-goal` 提供的人类命令;它直接观察或更改当前目标,而目标领域拥有每条持久且模型可见的记录。 + +## 循环层级 + +- **轮次**:会话中一次对已接纳输入的排空过程,在模型及其工具停止工作或终止策略介入后结束。<a id="turn"></a> +- **步骤**:一次模型请求,以及由模型响应引发的工具执行;一个轮次包含一个或多个步骤。<a id="step"></a> +- **回合**:包含一个轮次的外层策略迭代,例如一个[目标回合](#goal-round)或一次全新 agent Ralph 尝试。回合计数器属于该策略,并不统计会话内的每个轮次。<a id="round"></a> + +## Ralph + +- **Ralph 循环**:一次面向不可变目标的前台全新 agent 工作流运行。它是由工作流和 subagent 原语组合而成的面向模型的工具策略,不是同会话目标、agent loop(智能体循环)模式、调度器或通用工作流脚本功能。<a id="ralph-loop"></a> +- **Ralph 回合**:[Ralph 循环](#ralph-loop)中的一个全新子会话。子会话不接收父会话或此前子会话的对话种子;共享工作区和一份有界的 [Ralph 交接](#ralph-handoff)承载跨回合状态。<a id="ralph-round"></a> +- **Ralph 交接**:从一个仍需继续的 Ralph 回合传给下一回合的规范化、有界结构化报告,包含状态、摘要、证据、后续步骤和阻塞说明。它补充共享工作区,而不取代工作区的权威地位。<a id="ralph-handoff"></a> diff --git a/docs/i18n/README.i18n.yaml b/docs/i18n/README.i18n.yaml index 2a72aaa53e..224c3e6314 100644 --- a/docs/i18n/README.i18n.yaml +++ b/docs/i18n/README.i18n.yaml @@ -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 -README.md: c4ddf44ad2497b4ff371918356ab1ec0698c7049 -README.zh.md: 4a31af4fdee4db2d0362cf9117a6eef4fea32393 +README.md: 16c036c98176f5410fe24fc24348177c84ad47a6 +README.zh.md: b37eeea99564d602523a4ebe379de38750dbc1ba diff --git a/docs/i18n/README.md b/docs/i18n/README.md index c4ddf44ad2..16c036c981 100644 --- a/docs/i18n/README.md +++ b/docs/i18n/README.md @@ -40,7 +40,7 @@ The gate's limit, stated plainly: **a green gate means the pair was confirmed co **Excluded** (never paired, and the gate rejects a `.zh.md` or `.i18n.yaml` for them): -- `docs/cordis-catalog/`, `docs/tool-catalog/`, `docs/config-catalog.md`, `docs/persistence-catalog.md`, and `docs/module-graph.md` — generated files; their generators emit English only today, so a hand-written translation would go stale on every regeneration. The planned follow-up is to teach the generators to emit Chinese alongside English, at which point these leave the exclusion list. +- `docs/cordis-catalog/`, `docs/tool-catalog/`, `docs/config-catalog.md`, `docs/persistence-catalog.md`, `docs/module-graph.md`, `docs/agent-lifecycle.md`, `docs/capability-seams.md`, `docs/event-producer-consumer.md`, `docs/graph-atlas.md`, and `docs/tool-execution-pipeline.md` — generated files; their generators emit English only today, so a hand-written translation would go stale on every regeneration. The planned follow-up is to teach the generators to emit Chinese alongside English, at which point these leave the exclusion list. - `docs/AGENTS.md` and `.agents/notes/**/AGENTS.md` — agent instructions, maintained in English only like the root `AGENTS.md`. - `docs/i18n/terminology.md` and [style-samples.md](style-samples.md) — both are bilingual by construction. - [translation-prompt.md](translation-prompt.md) — the automated pipeline's prompt template; its body is machine-consumed verbatim, so a paired translation would change pipeline behavior. diff --git a/docs/i18n/README.zh.md b/docs/i18n/README.zh.md index 4a31af4fde..b37eeea995 100644 --- a/docs/i18n/README.zh.md +++ b/docs/i18n/README.zh.md @@ -40,7 +40,7 @@ **排除**(永不配对,门禁拒绝为它们建 `.zh.md` 或 `.i18n.yaml`): -- `docs/cordis-catalog/`、`docs/tool-catalog/`、`docs/config-catalog.md`、`docs/persistence-catalog.md` 与 `docs/module-graph.md`——生成文件;生成器目前只输出英文,手写译文在每次重新生成时必然陈旧。计划中的后续工作是让生成器同时输出中文,届时这些文件移出排除清单。 +- `docs/cordis-catalog/`、`docs/tool-catalog/`、`docs/config-catalog.md`、`docs/persistence-catalog.md`、`docs/module-graph.md`、`docs/agent-lifecycle.md`、`docs/capability-seams.md`、`docs/event-producer-consumer.md`、`docs/graph-atlas.md` 与 `docs/tool-execution-pipeline.md`——生成文件;生成器目前只输出英文,手写译文在每次重新生成时必然陈旧。计划中的后续工作是让生成器同时输出中文,届时这些文件移出排除清单。 - `docs/AGENTS.md` 与 `.agents/notes/**/AGENTS.md`——agent 指令,与根 `AGENTS.md` 一样只以英文维护。 - `docs/i18n/terminology.md` 与 [style-samples.md](style-samples.md)——二者本身即为中英对照文档。 - [translation-prompt.md](translation-prompt.md)——自动翻译流水线的 prompt 模板;正文逐字进入模型请求,配对翻译会改变流水线行为。 diff --git a/docs/testing.i18n.yaml b/docs/testing.i18n.yaml index e91d6712ea..8ef18d76b6 100644 --- a/docs/testing.i18n.yaml +++ b/docs/testing.i18n.yaml @@ -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 -testing.md: ddb9da0b38e5dc9cc75ede81ec157c4744fd11c2 -testing.zh.md: 8a37a9eaffbf19b205e3b98e7609464133060cf2 +testing.md: 1de3a0754dadbad1f36a9fc8c19b8ba77071bd54 +testing.zh.md: c557dfd91bca436a9c969cde6e2a0b24237e3146 diff --git a/docs/testing.md b/docs/testing.md index 22a678a230..1de3a0754d 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -9,15 +9,15 @@ How this repo tests, tier by tier, and the rules that keep a green suite meaning - **Unit** (`pnpm run test`): vitest over `packages|examples/*/tests/**/*.spec.ts`, colocated with what they test. Every registry gets an HMR-safety test (dispose the contributing fiber, assert cleanup). Prefer edge cases, error paths, event ordering, concurrency races, and permanent contract regressions (see `packages/core/agent-loop/tests/contract-regressions.spec.ts`). - **Coverage gate** (`pnpm run test:coverage`): the gating run, per-file 100% on `packages/*/*/src`. An uncovered line is often dead code the gate is correctly flagging for deletion, not a missing test to bolt on. Line coverage is necessary, never sufficient — it proves lines ran, not that the feature works as shipped. - **Real-API e2e** (`pnpm run test:e2e`): with-key tests against live provider APIs — the DeepSeek model plus provider-specific smokes that gate on their own keys (`EXA_API_KEY`, `PERPLEXITY_API_KEY`, …); each suite self-skips without its key so keyless CI stays green ([real-API e2e Agent Note](../.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.md)). -- **Snapshot** (`pnpm run test:snapshot`): transport-specific keyless expected outputs cover external presentation. ACP suites boot the real example subprocess, replay a recorded session, and diff normalized JSON-RPC plus the re-persisted log ([ACP snapshot Agent Note](../.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md)); the headless suite independently pins `stream-json` through its real one-shot subprocess. TUI completed journeys replay recorded primary/child JSONL through the real agent loop and tools before projecting ANSI into semantic terminal-state expected outputs; package-local snapshots retain transient renderer states, and a real PTY conversation covers the process boundary ([TUI snapshot Agent Note](../.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md)). Use `pnpm run test:snapshot:record` when a model transcript must change and `pnpm run test:snapshot:refresh` when committed replay input remains correct; review every JSONL and expected-output diff. System-prompt/tool-schema content is pinned by one ACP scenario (`text-turn`) and tokenized in every other fixture, so a prompt or schema edit churns one committed line ([pinned-header Agent Note](../.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md)). +- **Snapshot** (`pnpm run test:snapshot`): keyless expected outputs cover external presentation. ACP boots the real example, replays a recorded session, and diffs normalized JSON-RPC plus the re-persisted log ([ACP snapshot Agent Note](../.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md)); headless pins `stream-json` through its real one-shot process. TUI journeys replay primary/child JSONL through the real loop and tools, then project ANSI into semantic terminal-state outputs; package snapshots retain transient states and a real PTY covers the process boundary ([TUI snapshot Agent Note](../.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md)). Use `pnpm run test:snapshot:record` when a model transcript changes and `pnpm run test:snapshot:refresh` when replay input remains valid; review every JSONL and expected-output diff. One ACP scenario (`text-turn`) pins full system-prompt/tool-schema content; other fixtures tokenize it so an edit churns one line ([pinned-header Agent Note](../.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md)). ## The with-key policy: inference is cheap here -We are DeepSeek — do not ration real-API tests. A no-key test proves plumbing; only a with-key run proves the agent works against a real model. Write many: file-writing prompts, multi-turn conversations, tool use, cancellation mid-stream. Highest-value are **smoke tests** that boot the real example, send one real prompt, and check the world — they catch the "green unit tests, broken product" class that mocks structurally cannot ([postmortem 0001](postmortem/0001-acp-default-export-drops-inject.md)). The self-skip exists only so secretless CI and keyless contributors aren't blocked; it is not a cost signal. Every example ships both a keyless smoke and a with-key smoke ([examples/AGENTS.md](../examples/AGENTS.md)). +We are DeepSeek — do not ration real-API tests. A no-key test proves plumbing; only a with-key run proves the agent works against a real model. Cover file-writing prompts, multi-turn conversations, tool use, and mid-stream cancellation. Highest-value are **smoke tests** that boot the real example, send one prompt, and check the world — they catch the "green unit tests, broken product" class that mocks cannot ([postmortem 0001](postmortem/0001-acp-default-export-drops-inject.md)). Self-skip keeps secretless CI and keyless contributors unblocked; it is not a cost signal. Every example ships keyless and with-key smokes ([examples/AGENTS.md](../examples/AGENTS.md)). ## Prefer the real implementation over a mock -Mock only the genuinely expensive or non-deterministic boundary (the LLM adapter, the network, the clock); keep everything downstream real. A hand-rolled stand-in proves the bridge moves bytes, not that the shipping tool behaves as asserted — the two drift while the test stays green. Example: bridge tool-call tests run the scripted mock MODEL but the real tool + real executor (`makeBridgeHarness({ withBash: true })` plugs `dsh-bash-local` + `dsh-tool-bash` and runs an actual `echo`). +Mock only the expensive or non-deterministic boundary (LLM adapter, network, clock); keep everything downstream real. A hand-rolled stand-in proves the bridge moves bytes, not that the shipping tool behaves as asserted. Bridge tool-call tests use the scripted mock model with the real tool and executor: `makeBridgeHarness({ withBash: true })` plugs in `dsh-bash-local` and `dsh-tool-bash`, then runs `echo`. Recovery tests separate pre/post-chunk failures by step and prove failed chunks derive no message or tool side effect. Cover exhaustion, cancellation, policy composition, persistence, status, wire counts, transport-closing idle timeouts, and shipping Loader composition. diff --git a/docs/testing.zh.md b/docs/testing.zh.md index 8a37a9eaff..c557dfd91b 100644 --- a/docs/testing.zh.md +++ b/docs/testing.zh.md @@ -2,22 +2,24 @@ [English](testing.md) | 中文 -本文说明本仓库的分层测试方式,以及保持绿色测试套件有意义的规则。命令见根目录 [AGENTS.md](../AGENTS.md);关联的 RFC 承载设计动机。 +本文说明本仓库的分层测试方式,以及保持绿色测试套件有意义的规则。命令见根目录 [AGENTS.md](../AGENTS.md);相关 Agent Note(agent 决策记录)承载设计动机。 ## 层级 - **单元测试**(`pnpm run test`):vitest 运行 `packages|examples/*/tests/**/*.spec.ts`,与被测代码同目录。每个注册表都有一个 HMR(热模块替换)安全测试(dispose(资源释放)贡献的 fiber,断言清理完成)。优先覆盖边界情况、错误路径、事件顺序、并发竞态,以及永久性契约回归(见 `packages/core/agent-loop/tests/contract-regressions.spec.ts`)。 - **覆盖率门禁**(`pnpm run test:coverage`):门禁级运行,对 `packages/*/*/src` 按文件 100% 覆盖。未覆盖的行往往是门禁正确标记出的死代码(应删除),而非需要补写的测试。行覆盖率是必要条件,但永远不是充分条件:它证明行被执行过,不证明功能按交付预期工作。 -- **真实 API e2e**(`pnpm run test:e2e`):带密钥测试,调用真实提供方 API。包括 DeepSeek 模型以及各提供方特有的冒烟测试(各自依赖自己的密钥:`EXA_API_KEY`、`PERPLEXITY_API_KEY` 等);缺少密钥时各套件自动跳过,keyless CI 保持绿色([真实 API e2e RFC](rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md))。 -- **快照测试**(`pnpm run test:snapshot`):启动真实示例子进程,在无密钥环境下回放录制的会话,将归一化的 stdout 与重新持久化的日志与已提交的 golden 文件做 diff([快照 RFC](rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md))。当模型 transcript(文本记录)需要变更时使用 `pnpm run test:snapshot:record`;当已提交的 transcript 仍是正确的 mock LLM(大语言模型)输入、只需无密钥重写回放 golden 时使用 `pnpm run test:snapshot:refresh`。请审查 golden diff。系统提示词/工具 schema 内容由**一个**场景(`text-turn`)固定,其余 fixture(测试前置数据)中以 token 化形式引用,因此 prompt 或 schema 的修改只影响一行已提交内容([pinned-header RFC](rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md))。 +- **真实 API e2e**(`pnpm run test:e2e`):带密钥测试调用真实提供方 API,包括 DeepSeek 模型以及各提供方特有的冒烟测试;这些测试各自由自己的密钥控制(`EXA_API_KEY`、`PERPLEXITY_API_KEY` 等),缺少密钥时套件会自动跳过,使 keyless CI 保持绿色([真实 API e2e Agent Note](../.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.md))。 +- **快照**(`pnpm run test:snapshot`):无密钥预期输出覆盖对外呈现。ACP 启动真实示例、回放录制会话,并对归一化 JSON-RPC 与重新持久化的日志执行 diff([ACP 快照 Agent Note](../.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md));headless 通过真实单次运行进程固定 `stream-json`。TUI 旅程通过真实循环与工具回放主会话与子会话 JSONL,再将 ANSI 投影为语义化终端状态输出;包(package)级快照保留瞬态状态,真实 PTY 覆盖进程边界([TUI 快照 Agent Note](../.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md))。当模型 transcript(文本记录)发生变化时使用 `pnpm run test:snapshot:record`,回放输入仍然有效时使用 `pnpm run test:snapshot:refresh`;请审查每一处 JSONL 与预期输出差异。一个 ACP 场景(`text-turn`)固定完整的系统提示词与工具 schema 内容;其他 fixture(测试前置数据)将其 token 化,因此修改只会扰动一行([pinned-header Agent Note](../.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md))。 ## 带密钥策略:推理在这里很便宜 -我们是 DeepSeek,不要吝惜真实 API 测试。无密钥测试只能证明管道通畅;只有带密钥运行才能证明 agent(智能体)在真实模型面前能正常工作。请大量编写:文件写入 prompt、多轮次对话、工具调用、流中取消。价值最高的是**冒烟测试**:启动真实示例、发送一条真实 prompt、检查外部世界的状态。它们能捕获「单元测试全绿、产品却坏了」这一类 mock 在结构上无法发现的问题([事后分析 0001](postmortem/0001-acp-default-export-drops-inject.md))。自动跳过机制的存在仅仅是为了不阻塞无密钥的 CI 和无密钥的贡献者,它不是成本信号。每个示例都附带一个 keyless 冒烟测试,并且——除非本身就不需要密钥——还附带一个带密钥冒烟测试([examples/AGENTS.md](../examples/AGENTS.md))。 +我们是 DeepSeek,不要吝惜真实 API 测试。无密钥测试只能证明底层通路;只有带密钥运行才能证明 agent(智能体)能对接真实模型正常工作。覆盖文件写入提示词、多轮对话、工具使用和流中取消。价值最高的是**冒烟测试**:启动真实示例、发送一条提示词,并检查外部世界;它们能捕获「单元测试全绿、产品却坏了」这一类 mock 无法发现的问题([事故复盘 0001](postmortem/0001-acp-default-export-drops-inject.md))。自动跳过让无密钥 CI 和无密钥贡献者不受阻塞;它不是成本信号。每个示例都提供无密钥和带密钥冒烟测试([examples/AGENTS.md](../examples/AGENTS.md))。 ## 优先使用真实实现而非 mock -只在真正昂贵或不确定的边界处 mock(LLM 适配器、网络、时钟);下游一切保持真实。手写的替身只能证明桥接层在搬运字节,不能证明交付的工具行为符合断言——两者会漂移,而测试继续绿着。例如:bridge 工具调用测试运行脚本化的 mock 模型,但使用真实的 tool + 真实的执行器(`makeBridgeHarness({ withBash: true })` 接入 `dsh-bash-local` + `dsh-tool-bash` 并执行真正的 `echo`)。 +只 mock 开销高或不确定的边界(LLM(大语言模型)适配器、网络、时钟);下游一切保持真实。手写替身只能证明桥接层在搬运字节,不能证明交付的工具行为符合断言。桥接工具调用测试将脚本化 mock 模型与真实工具和执行器配合使用:`makeBridgeHarness({ withBash: true })` 接入 `dsh-bash-local` 与 `dsh-tool-bash`,然后运行 `echo`。 + +恢复测试按步骤区分分片前与分片后的失败,并证明失败分片不会派生出消息或工具副作用。覆盖耗尽、取消、策略组合、持久化、状态、协议计数、会关闭传输的空闲超时,以及交付的 Loader 组合。 ## 验证外部世界,而非自我报告 @@ -27,9 +29,14 @@ e2e 断言应重新运行命令或从外部重新读取文件;对 agent 自身 - 产品可见的插件必须有一个非单元的真实组合测试。手动构建的 `ctx.plugin(...)` 套件不够:通过 Loader 和 app/process 启动仅用于测试的 `cordis.yml`,只 mock 外部/不确定边界,断言模型可见的请求/日志、持久状态或用户可见输出。不要把 opt-in 选项混入交付默认值。 - 一个守卫只有在回归真的能让它失败时才有效。对于没有 `inject` 的插件(bundle/组合插件),Loader 冒烟测试在导出形状损坏时仍然绿着——需要添加显式的 `expect('default' in mod).toBe(false)` 加 `unwrapExports` 往返断言,并证明它有效:引入回归、观察变红、回退。 -- 「真实入口路径」指已发布的产物:package 的 `bin` 指向在普通 `node` 下运行的构建产物 `lib/bin.js`,tsx 会掩盖问题(竞态、模块解析、吞掉的加载失败以 exit 0 退出)。同样适用于构建后的 package 在运行时解析的任何非 index 运行时入口(worker-thread 运行时的兄弟文件 `lib/worker.cjs`)。保持构建产物冒烟测试绿色(`packages/ui/*/tests/built-bin.e2e.ts`、`packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts`),并断言真正缺失的配置以非零退出码退出。 -- 从临时 cwd spawn 示例的 e2e 测试需要设置 `TSX_TSCONFIG_PATH` 为仓库根目录的 tsconfig,否则会静默回退到陈旧的构建产物 `lib/`([examples/AGENTS.md](../examples/AGENTS.md))。 +- 「真实入口路径」指已发布的产物:包的 `bin` 所运行的是构建后的 `lib/bin.js`,并由普通 `node` 执行,从而暴露 tsx 会掩盖的失败(等待稳定时的竞态、模块解析、被吞掉的加载失败)。同样的规则适用于非 index 运行时入口(worker-thread 的同级文件 `lib/worker.cjs`),也适用于多个 bundle 共享的单例模块(`packages/ui/jsonrpc/tests/built-scope-carrier.e2e.ts`)。保持构建产物冒烟测试绿色(`packages/ui/*/tests/built-bin.e2e.ts`、`packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts`),并断言真正缺失的配置以非零状态退出。 + +## 测试子进程启动模式 + +- CI 与已有构建产物的测试通道通过共享双模式启动器,从构建后的 `lib/` 运行每个示例或 Cordis 配置子进程。不要为这些子进程手写 `--import tsx`。 +- 不加载 Cordis 的协议与操作系统 fixture 直接通过 Node 运行使用可擦除语法的 `.ts` 文件,不经过 tsx 或根路径映射。 +- 只有测试对象本身是源码路径解析时,才可以选择 `src`;在测试中写明这一契约。 ## 何时需要快照测试 -任何影响编辑器侧 transcript 或端到端 agent UX 的变更——ACP bridge、agent loop(智能体循环)的可观测输出、工具呈现——都需要在所属示例的快照套件中添加或更新场景(`examples/<name>/tests/snapshots/`,基于 [`dsh-acp-snapshot`](../packages/support/acp-snapshot/README.md) 套件工厂的场景表;`examples/acp-agent` 是主套件),或在 PR 中说明为何不适用。新的能力 seam、生命周期形态或 transcript 表面在计划阶段就要列出各层级的覆盖方案,并验证 harness 能够表达它——harness 的缺口是排期工作,不是构建中途的意外。 +每项非平凡的模型可见或人类可见变更,都必须在同一 PR 中,通过可运行示例所属的快照套件添加或更新无密钥场景。包测试、e2e 断言、mock 与仅测试组合、PR 理由都不能取代组装后的 transcript;必要时应扩展 harness。ACP 接口使用 `examples/<name>/tests/snapshots/`,即基于 [`dsh-acp-snapshot`](../packages/support/acp-snapshot/README.md) 套件工厂的场景表(`examples/acp-agent` 为主套件);`examples/headless-agent` 拥有 `stream-json` 快照与回放 fixture。已完成的交互式终端旅程使用 `examples/tui-agent/tests/snapshots/` 下由 JSONL 驱动的场景;瞬态呈现使用包内语义矩阵,输入、Loader 选择或终端清理发生变化时还要添加 PTY 用例。新的能力 seam、生命周期形态或 transcript 呈现接口在计划阶段就要列出每个覆盖层级,并在实现前验证 harness 能够表达它们。 From f72db5ac7b42e82ccc19f8d2c427828829d2a941 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:19:12 +0800 Subject: [PATCH 090/368] docs(i18n): address core data review --- docs/core-data-structures/bash.i18n.yaml | 2 +- docs/core-data-structures/bash.zh.md | 2 +- .../code-runtime.i18n.yaml | 2 +- docs/core-data-structures/code-runtime.zh.md | 2 +- .../core-data-structures/compaction.i18n.yaml | 2 +- docs/core-data-structures/compaction.zh.md | 2 +- docs/core-data-structures/core.i18n.yaml | 2 +- docs/core-data-structures/core.zh.md | 2 +- .../core-data-structures/filesystem.i18n.yaml | 2 +- docs/core-data-structures/filesystem.zh.md | 4 +- .../llm-streaming.i18n.yaml | 2 +- docs/core-data-structures/llm-streaming.zh.md | 2 +- docs/core-data-structures/scope.i18n.yaml | 2 +- docs/core-data-structures/scope.zh.md | 2 +- docs/core-data-structures/session.i18n.yaml | 2 +- docs/core-data-structures/session.zh.md | 4 +- docs/core-data-structures/subagent.i18n.yaml | 2 +- docs/core-data-structures/subagent.zh.md | 6 +- docs/core-data-structures/tools.i18n.yaml | 2 +- docs/core-data-structures/tools.zh.md | 6 +- docs/core-data-structures/web.i18n.yaml | 2 +- docs/core-data-structures/web.zh.md | 2 +- docs/core-data-structures/workflow.i18n.yaml | 2 +- docs/core-data-structures/workflow.zh.md | 2 +- ...-acp-default-export-drops-inject.i18n.yaml | 2 +- ...0001-acp-default-export-drops-inject.zh.md | 8 +- ...ession-disabled-filesystem-tools.i18n.yaml | 2 +- ...expression-disabled-filesystem-tools.zh.md | 2 +- docs/postmortem/README.i18n.yaml | 2 +- docs/postmortem/README.zh.md | 10 +- docs/rfc/README.i18n.yaml | 2 +- docs/rfc/README.zh.md | 8 +- scripts/type-equiv.manifest.json | 130 +++++++++++++++++- 33 files changed, 180 insertions(+), 46 deletions(-) diff --git a/docs/core-data-structures/bash.i18n.yaml b/docs/core-data-structures/bash.i18n.yaml index eba38e8f77..601c350359 100644 --- a/docs/core-data-structures/bash.i18n.yaml +++ b/docs/core-data-structures/bash.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write bash.md: 7b5c779b832ef5be6591e626980f7f22db54f239 -bash.zh.md: 8a209b4853e44d1846460c41f4d5b9a43082a65b +bash.zh.md: c4d27efa8344727e3a77c928b331ec570c2716eb diff --git a/docs/core-data-structures/bash.zh.md b/docs/core-data-structures/bash.zh.md index 8a209b4853..c4d27efa83 100644 --- a/docs/core-data-structures/bash.zh.md +++ b/docs/core-data-structures/bash.zh.md @@ -112,7 +112,7 @@ interface BashExecSpec { 受信的进程内插件使用 `stdin` 和 `env` 传递钩子载荷与钩子专用变量。面向模型的 bash 工具从其命名的 schema 字段构造请求,不暴露这两个输入,因为 shell 语法本身已提供等价能力;测试防止未来出现 `...args` 展开。这是请求形状的纪律约束,而非安全边界:`dsh-bash-local` 无论这些字段如何都会清洗环境凭证,然后叠加调用方已持有的显式值。见 [bash stdin/env RFC](../rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md)。 -该 seam 处理的两个 id 都是[品牌化的](core.md)(零成本 `string` 品牌,与 `SessionId`/`AgentId` 相同的机制):`BashTaskId`(被跟踪的后台任务,由本地执行器生成 `bash-N`)和 `OwnerToken`(不透明的隔离键)。`OwnerToken` 刻意是一个与 `SessionId` **不同**的品牌,而非别名:bash seam 是一个能力 seam,不得知道 owner token *意味着*什么,因此它从不导入 `dsh-session` 的词汇。`dsh-tool-bash` 消费方是唯一将拥有者 agent 的 `SessionId` 转换为 `OwnerToken` 的边界。对两者施加品牌化,可以防止裸 `string`(或在需要 `OwnerToken` 的地方传入 `BashTaskId`,反之亦然)在面向模型的 `task_id` 路径上通过类型检查。 +该 seam 处理的两个 id 都是[品牌化的](core.md)(零成本 `string` 品牌,与 `SessionId`/`AgentId` 相同的机制):`BashTaskId`(被跟踪的后台任务,由本地执行器生成 `bash-N`)和 `OwnerToken`(不透明的隔离键)。`OwnerToken` 刻意是一个与 `SessionId` 不同的品牌,而非别名:bash seam 是一个能力 seam,不得知道 owner token *意味着*什么,因此它从不导入 `dsh-session` 的词汇。`dsh-tool-bash` 消费方是唯一将拥有者 agent 的 `SessionId` 转换为 `OwnerToken` 的边界。对两者施加品牌化,可以防止裸 `string`(或在需要 `OwnerToken` 的地方传入 `BashTaskId`,反之亦然)在面向模型的 `task_id` 路径上通过类型检查。 ## 前台运行:`BashRunResult` diff --git a/docs/core-data-structures/code-runtime.i18n.yaml b/docs/core-data-structures/code-runtime.i18n.yaml index 7c9ef2a7a3..918b3f5738 100644 --- a/docs/core-data-structures/code-runtime.i18n.yaml +++ b/docs/core-data-structures/code-runtime.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write code-runtime.md: 28152947d0853fb10228c472ca3e121e77b7b598 -code-runtime.zh.md: 8270d12e7cce8c3b2443da9de268d95cf9d692d8 +code-runtime.zh.md: 7d5750e0c245ba97ed7ece6083464382109e10fd diff --git a/docs/core-data-structures/code-runtime.zh.md b/docs/core-data-structures/code-runtime.zh.md index 8270d12e7c..7d5750e0c2 100644 --- a/docs/core-data-structures/code-runtime.zh.md +++ b/docs/core-data-structures/code-runtime.zh.md @@ -82,4 +82,4 @@ interface CodeRunFailure { ## 服务 -`CodeRuntime`(`ctx.codeRuntime`,抽象服务,定义于 [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts))由 `run(request)` 加两个只读描述符组成:`language`(程序必须使用的语言,`'typescript'` 是已知值;生成语言相关展示的消费方据此切换,遇到无法展示的语言时应显式报错)和 `isolation`(执行基底,`'worker-thread'`、`'process'`、`'container'`;仅为诊断标签,**不构成安全承诺**)。实现必须保证各次运行彼此隔离(无跨运行状态),且 dispose(资源释放)至静默:进行中的运行在 teardown 完成前被终止并等待结束。 +`CodeRuntime`(`ctx.codeRuntime`,抽象服务,定义于 [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts))由 `run(request)` 加两个只读描述符组成:`language`(程序必须使用的语言,`'typescript'` 是已知值;生成语言相关展示的消费方据此切换,遇到无法展示的语言时应显式报错)和 `isolation`(执行基底,`'worker-thread'`、`'process'`、`'container'`;仅为诊断标签,**不构成安全承诺**)。实现必须保证各次运行彼此隔离(无跨运行状态),并在 dispose(资源释放)时等待系统完全停稳:teardown 完成前,进行中的运行都已终止并等待结束。 diff --git a/docs/core-data-structures/compaction.i18n.yaml b/docs/core-data-structures/compaction.i18n.yaml index a0a32275e6..f1673efb53 100644 --- a/docs/core-data-structures/compaction.i18n.yaml +++ b/docs/core-data-structures/compaction.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write compaction.md: e82cc103932ad05e68bc5311dec23c3f2c1a7ce4 -compaction.zh.md: ad8b524a1984357b5bb911b59300a194407bdbb9 +compaction.zh.md: bae6e9aa385efe0a7722c2b360c0b88e87a1a779 diff --git a/docs/core-data-structures/compaction.zh.md b/docs/core-data-structures/compaction.zh.md index ad8b524a19..bae6e9aa38 100644 --- a/docs/core-data-structures/compaction.zh.md +++ b/docs/core-data-structures/compaction.zh.md @@ -8,7 +8,7 @@ ## `compact/*` 会话事件 -上下文压缩通过声明合并为 [`SessionEventMap`](session.md) 扩展了三种事件类型。三者均为**仅日志**事件:它们记录压缩锁及其来源信息,永远不进入 surface。`SurfaceEventType` 被刻意**不**扩展(只有产生消息的事件才到达模型),因此摘要本身搭载在一条独立的 `user/message` 上,带有 `surfaceOp: { op: 'replace', start, end }`——唯一的 surface 变更。关于为何复用 `user/message` 是诚实的做法而非权宜之计,见 RFC。 +上下文压缩通过声明合并为 [`SessionEventMap`](session.md) 扩展了三种事件类型。三者均为**仅日志**事件:它们记录压缩锁及其来源信息,永远不进入 surface。`SurfaceEventType` 被刻意不扩展(只有产生消息的事件才到达模型),因此摘要本身搭载在一条独立的 `user/message` 上,带有 `surfaceOp: { op: 'replace', start, end }`——唯一的 surface 变更。关于为何复用 `user/message` 是诚实的做法而非权宜之计,见 RFC。 | 事件 | 载荷 | 作用 | |---|---|---| diff --git a/docs/core-data-structures/core.i18n.yaml b/docs/core-data-structures/core.i18n.yaml index 8017a93ecd..a1eaa5e393 100644 --- a/docs/core-data-structures/core.i18n.yaml +++ b/docs/core-data-structures/core.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write core.md: 7ace373ae549b86f21151610719940100d6348d0 -core.zh.md: d6467c12e1d64624357fcb8b37688b484bc23b0c +core.zh.md: 0212dee3587d8a67bcd484a67f078d7195f6eef7 diff --git a/docs/core-data-structures/core.zh.md b/docs/core-data-structures/core.zh.md index d6467c12e1..0212dee358 100644 --- a/docs/core-data-structures/core.zh.md +++ b/docs/core-data-structures/core.zh.md @@ -13,7 +13,7 @@ harness 是一个微内核:一个极小的核心加上众多插件。大多数 1. 它流经 agent loop 主干——循环在每个轮次中持有、派生、流式输出或记录它(`Message`、`StreamChunk`、`SessionEvent`、`Agent` 句柄本身),与当前加载了哪些插件无关;**或者** 2. 它是插件作者面向某条流水线编写的唯一标题类型——`ToolDefinition`(每个工具*是什么*)。 -其他一切都记录在**子页面**上,而非本页。划线的规则是:*你编写、持有或接收的类型是核心;为它提供类型推导、渲染或持久化的机制是子页面细节。*因此 `ToolDefinition` 是核心,但为它提供类型推导的 `SchemaSpec`/`InferArgs` DSL、为它提供渲染意图的 `ToolCallView`/`ToolResultView` 词汇,以及存储事件日志的 `SessionPersistence` seam 都不是——它们分别在下列子页面中。 +其他一切都记录在**子页面**上,而非本页。划线的规则是:*你编写、持有或接收的类型是核心;为它提供类型推导、渲染或持久化的机制是子页面细节*。因此 `ToolDefinition` 是核心,但为它提供类型推导的 `SchemaSpec`/`InferArgs` DSL、为它提供渲染意图的 `ToolCallView`/`ToolResultView` 词汇,以及存储事件日志的 `SessionPersistence` seam 都不是——它们分别在下列子页面中。 | 子页面 | 负责内容 | |---|---| diff --git a/docs/core-data-structures/filesystem.i18n.yaml b/docs/core-data-structures/filesystem.i18n.yaml index 4e3d400339..843abd6dc6 100644 --- a/docs/core-data-structures/filesystem.i18n.yaml +++ b/docs/core-data-structures/filesystem.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write filesystem.md: 8bdc2323a0bf63588e01520926f093538fee4912 -filesystem.zh.md: 1b636dd35e3c614d87973c617ea052058995e0e0 +filesystem.zh.md: 86b18af783899ed857f059b6b7cdb740ea357798 diff --git a/docs/core-data-structures/filesystem.zh.md b/docs/core-data-structures/filesystem.zh.md index 1b636dd35e..86b18af783 100644 --- a/docs/core-data-structures/filesystem.zh.md +++ b/docs/core-data-structures/filesystem.zh.md @@ -121,7 +121,7 @@ interface FileReadOutcome { ## 已观测文件状态(策略插件) -已观测状态是 `dsh-fs-policy` 插件内部持有的 `WeakMap<owner, Map<targetKey, { version }>>`。当且仅当所有者已读取、写入或编辑过该目标时(每次成功都 emit `fs/observed`),条目才存在,因此其存在本身就是先前观测的记录——没有单独的 `hasRead` 标志,也没有视图区分。所有者从事件 actor 推导(通常是 `exec.agent.session`),被视为不透明且从不读取。成功的 read/write/edit 会刷新该所有者对应的已记录版本;dispose(资源释放)时丢弃全部数据(HMR(热模块替换)安全)。 +已观测状态是 `dsh-fs-policy` 插件内部持有的 `WeakMap<owner, Map<targetKey, { version }>>`。**当且仅当**所有者已读取、写入或编辑过该目标时(每次成功都 emit `fs/observed`),条目才存在,因此其存在本身就是先前观测的记录——没有单独的 `hasRead` 标志,也没有视图区分。所有者从事件 actor 推导(通常是 `exec.agent.session`),被视为不透明且从不读取。成功的 read/write/edit 会刷新该所有者对应的已记录版本;dispose(资源释放)时丢弃全部数据(HMR(热模块替换)安全)。 ## 错误分类体系(提供方 seam) @@ -146,4 +146,4 @@ type FsErrorCode = ## 服务与插件 -`FileSystem`(`ctx.fs`,抽象)拥有提供方原语:`resolve`、`stat`、`readText`、`streamText`、`listDir`、`writeText` 和 `editText`。`dsh-fs-policy` 不注册任何服务——它是一个通过 `fs/*` 事件门控叠加策略的插件:它裁决 write/edit intent waterfall(提供 `createIfAbsent`/`replaceIfVersion`/`{ version }` 或抛出 `FS_NOT_OBSERVED`),并在 `fs/observed` 上记录。执行器是 `dsh-tool-fs`:它通过 `ctx.fs` 读取/写入/编辑,分发 waterfall,并 emit 记录事件。生成的接线目录在 [services.md](../cordis-catalog/services.md#ctxfs--filesystem-abstract-seam) 中展示确切的 `ctx.fs` 签名。 +`FileSystem`(`ctx.fs`,抽象)拥有提供方原语:`resolve`、`stat`、`readText`、`streamText`、`listDir`、`writeText` 和 `editText`。`dsh-fs-policy` **不注册任何服务**——它是一个通过 `fs/*` 事件门控叠加策略的插件:它裁决 write/edit intent waterfall(提供 `createIfAbsent`/`replaceIfVersion`/`{ version }` 或抛出 `FS_NOT_OBSERVED`),并在 `fs/observed` 上记录。执行器是 `dsh-tool-fs`:它通过 `ctx.fs` 读取/写入/编辑,分发 waterfall,并 emit 记录事件。生成的接线目录在 [services.md](../cordis-catalog/services.md#ctxfs--filesystem-abstract-seam) 中展示确切的 `ctx.fs` 签名。 diff --git a/docs/core-data-structures/llm-streaming.i18n.yaml b/docs/core-data-structures/llm-streaming.i18n.yaml index f9cd711351..b06be9dfa6 100644 --- a/docs/core-data-structures/llm-streaming.i18n.yaml +++ b/docs/core-data-structures/llm-streaming.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write llm-streaming.md: ffd276b4647be8d10afcab0fb3c3f6daad790d20 -llm-streaming.zh.md: 4cb87c9fe65e264f9ce2f39d6ea3b5c6183d5cc1 +llm-streaming.zh.md: ea11f47e1148d21c2f23a648002c9413103628f1 diff --git a/docs/core-data-structures/llm-streaming.zh.md b/docs/core-data-structures/llm-streaming.zh.md index 4cb87c9fe6..ea11f47e11 100644 --- a/docs/core-data-structures/llm-streaming.zh.md +++ b/docs/core-data-structures/llm-streaming.zh.md @@ -23,7 +23,7 @@ type StreamChunk = ## 适配器契约 -每个适配器**必须**遵守以下规则,每个消费方可以依赖它们: +每个适配器必须遵守以下规则,每个消费方可以依赖它们: - **`usage` 在 `finish` 之前,`finish` 之后不再有任何分片。** 将两者都推迟到提供方的流结束标记,这样尾部的 usage-only 分片就不会违反顺序。 - **工具调用的 `arguments` 全程保持原始 JSON 字符串。** 部分片段通过 `argumentsDelta` 流式传输;如果提供方返回的是已解析的对象,适配器在 `block-end` 时重新序列化为字符串。 diff --git a/docs/core-data-structures/scope.i18n.yaml b/docs/core-data-structures/scope.i18n.yaml index a9467c71da..6d3acddaff 100644 --- a/docs/core-data-structures/scope.i18n.yaml +++ b/docs/core-data-structures/scope.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write scope.md: f95594329ee9ac83da2efcc31df377c53e64331a -scope.zh.md: 277fa4ec5c365e5ff3ee6d9baeae525d3dfc9f96 +scope.zh.md: be423e62def89e03f15d438b9fd9db6fd41b68f3 diff --git a/docs/core-data-structures/scope.zh.md b/docs/core-data-structures/scope.zh.md index 277fa4ec5c..be423e62de 100644 --- a/docs/core-data-structures/scope.zh.md +++ b/docs/core-data-structures/scope.zh.md @@ -22,7 +22,7 @@ type Scoped<T extends object> = object & { readonly [ScopedBrand]: T } ## 拥有所有权的注册上下文 -`Scope` 将带标签的注册上下文与两个拆卸接口配对。`rawDispose` 保留有序复合 effect 所需的精确 Cordis disposer 身份;`dispose()` 是面向直接调用方和竞争调用方的公共静默边界,用于 dispose(资源释放)。 +`Scope` 将带标签的注册上下文与两个拆卸接口配对。`rawDispose` 保留有序复合 effect 所需的精确 Cordis disposer 身份;`dispose()` 是面向直接调用方和竞态调用方的公共停稳边界。 ```ts type-equiv interface Scope { diff --git a/docs/core-data-structures/session.i18n.yaml b/docs/core-data-structures/session.i18n.yaml index 23b16e8d66..33e1d86f7d 100644 --- a/docs/core-data-structures/session.i18n.yaml +++ b/docs/core-data-structures/session.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write session.md: 796abebbc31a54c7c341028cf0a09031ae59cd78 -session.zh.md: b55ff3b7fe9c3a5f65dc46addf266dc1e5430116 +session.zh.md: 04bfe84f079762091e7c4a4d77db69c053e6ea30 diff --git a/docs/core-data-structures/session.zh.md b/docs/core-data-structures/session.zh.md index b55ff3b7fe..04bfe84f07 100644 --- a/docs/core-data-structures/session.zh.md +++ b/docs/core-data-structures/session.zh.md @@ -122,7 +122,7 @@ export interface EpochHeader { } ``` -规范形式:空的系统提示词、空的工具列表和空的会话前缀均为 ABSENT 字段,与请求构建方式一致。`messagePrefix` 是 `agent/session-prefix` waterfall(瀑布式事件)产物的持久记录(请求 = `messagePrefix` + 派生历史);每个 agent loop(智能体循环)实例组合一次,由该实例的快照锚定,因此实际上 loop 不会产生前缀 delta。delta 分支(整数组替换,空数组编码「回到无前缀」的转换)存在是为了编解码的完备性。其他 delta payload(`SystemDelta`:公共前缀/后缀行裁剪;`ToolsDelta`:按名称键控的增/删/改)与事件一起定义在 [`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts)。 +规范形式:空的系统提示词、空的工具列表和空的会话前缀均为 ABSENT 字段,与请求构建方式一致。`messagePrefix` 是 `agent/session-prefix` waterfall(瀑布式事件)产物的持久记录(请求 = `messagePrefix + derived history`);每个 agent loop(智能体循环)实例组合一次,由该实例的快照锚定,因此实际上 loop 不会产生前缀 delta。delta 分支(整数组替换,空数组编码「回到无前缀」的转换)存在是为了编解码的完备性。其他 delta payload(`SystemDelta`:公共前缀/后缀行裁剪;`ToolsDelta`:按名称键控的增/删/改)与事件一起定义在 [`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts)。 ## `SessionEvent<T>`:一条日志条目 @@ -175,7 +175,7 @@ export type SurfaceOp = | { op: 'replace'; start: number; end: number } ``` -`'append'` 是正常的尾部追加路径。`replace` 遮蔽从 `start` 到 `end`(含两端)的 surface 节点(两者都必须是有效的 surface 节点 seq),并在其位置插入新节点。 +`'append'` 是正常的尾部追加路径。`replace` 遮蔽从 `start` 到 `end`(含两端)的 surface 节点(两者都必须是有效的 surface 节点 seq;`start === end` 时只替换一个节点),并在其位置插入新节点。 ### `SurfaceIntent`:`session.append()` 的参数 diff --git a/docs/core-data-structures/subagent.i18n.yaml b/docs/core-data-structures/subagent.i18n.yaml index 6d4a5fdaf2..ed154e096c 100644 --- a/docs/core-data-structures/subagent.i18n.yaml +++ b/docs/core-data-structures/subagent.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write subagent.md: eb9160abaee26969aecdc533fb9fd56fae18b7fa -subagent.zh.md: c8f680217a9f62f245a4de81cbc546deba87bbed +subagent.zh.md: b6a6bfbe61f5d2d3e0eb3bdc3aabed4b8b89317f diff --git a/docs/core-data-structures/subagent.zh.md b/docs/core-data-structures/subagent.zh.md index c8f680217a..b6a6bfbe61 100644 --- a/docs/core-data-structures/subagent.zh.md +++ b/docs/core-data-structures/subagent.zh.md @@ -64,9 +64,11 @@ interface SubagentStopReasonMap { } ``` +<a id="a-live-run-subagentrun"></a> + ## 活跃 run:`SubagentRun` -`SubagentRun` 是消费方持有的、指向一个就绪子 agent 的句柄。消费方 await `result` 并始终 dispose(资源释放)该 run 以达到静止状态。子 agent 失败时以非 completed 的 stop reason resolve;只有不可表示的基础设施故障才会 reject。可选的 `sendMessage` 和 `resume` 方法通过自身的存在来公布运行时能力。 +`SubagentRun` 是消费方持有的、指向一个就绪子 agent 的句柄。消费方 await `result` 并始终 dispose(资源释放)该 run,直至其完全停稳。子 agent 失败时以非 completed 的 stop reason resolve;只有不可表示的基础设施故障才会 reject。可选的 `sendMessage` 和 `resume` 方法通过自身的存在来公布运行时能力。 ```ts type-equiv interface SubagentRun { @@ -91,7 +93,7 @@ interface SubagentProvider { } ``` -`start()` 仅在 run 就绪时 fulfill。服务观察其 result、发出 `subagent/start`,并返回同一个 run;rejection 意味着提供方已自行清理,不发出生命周期配对事件。进程内子 agent 可通过 `ctx.agents` 发现,远程子 agent 则不必如此。`subagent/end` 报告最终输出或基础设施故障。两个事件均为仅观察事件,包含监听器异常。 +`start()` 仅在 run 就绪时 fulfill。服务观察其 result、发出 `subagent/start`,并返回同一个 run;rejection 意味着提供方已自行清理,不发出生命周期配对事件。进程内子 agent 可通过 `ctx.agents` 发现,远程子 agent 则不必如此。`subagent/end` 报告最终输出或基础设施故障。两个事件均为仅观察事件;每个监听器异常都会被独立隔离。 ## 进程内后端:深度与种子 diff --git a/docs/core-data-structures/tools.i18n.yaml b/docs/core-data-structures/tools.i18n.yaml index 1b2db95b67..7f55967dcb 100644 --- a/docs/core-data-structures/tools.i18n.yaml +++ b/docs/core-data-structures/tools.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write tools.md: f8be67054cd81027d4b751329948a784fa4f0ed9 -tools.zh.md: 8b77259b37b0e4c2118cc91af0e6dc3ca27c0479 +tools.zh.md: 27066180bc3a3666e4ef5c789034adc0a82e05b8 diff --git a/docs/core-data-structures/tools.zh.md b/docs/core-data-structures/tools.zh.md index 8b77259b37..27066180bc 100644 --- a/docs/core-data-structures/tools.zh.md +++ b/docs/core-data-structures/tools.zh.md @@ -46,7 +46,7 @@ interface ToolDefinition extends ToolSchema { ## 类型化 schema DSL -插件作者为每个属性编写带有布尔值 `required: true` 的规格,类型层面的辅助工具将规格映射为 `execute` 的参数类型——零类型断言。该 DSL 是为 `ToolDefinition` 提供类型的*机制*;它有意作为子页面细节,而非核心内容。 +插件作者为每个属性编写带有布尔值 `required: true` 的规格,类型层面的辅助工具将规格映射为 `execute` 的参数类型——零类型断言。该 DSL 是*提供类型推导的机制*,作用于 `ToolDefinition`;它有意作为子页面细节,而非核心内容。 源码:[`packages/core/tools/src/schema.ts`](../../packages/core/tools/src/schema.ts) @@ -193,7 +193,7 @@ type PostToolDecision = ## 结构化输出 schema 子集 -调用方用来向 subagent 要求机器可读结果的词汇(`SubagentStartRequest.outputSchema`,见 [subagent.md](subagent.md#the-start-request)),或工作流 `agent()` 调用使用的词汇。它有意**不是**完整的 JSON Schema:schema 原样传给模型作为强制工具的 `parameters`,产出的值由 `validateStructuredValue` 在客户端校验——因此每个被接受的关键字都必须是校验器实际执行的,`assertSupportedOutputSchema` 会大声拒绝其他任何内容(`OutputSchemaError`,列出所有违规项)。两个遍历器仅推理自有可枚举属性(JSON 不携带其他内容),并拒绝会有损序列化的非纯对象(`Date`、`Map`)。 +调用方用来向 subagent 要求机器可读结果的词汇(`SubagentStartRequest.outputSchema`,见 [subagent.md](subagent.md#the-start-request)),或工作流 `agent()` 调用使用的词汇。它有意不是完整的 JSON Schema:schema 原样传给模型作为强制工具的 `parameters`,产出的值由 `validateStructuredValue` 在客户端校验——因此每个被接受的关键字都必须是校验器实际执行的,`assertSupportedOutputSchema` 会大声拒绝其他任何内容(`OutputSchemaError`,列出所有违规项)。两个遍历器仅推理自有可枚举属性(JSON 不携带其他内容),并拒绝会有损序列化的非纯对象(`Date`、`Map`)。 ```ts type-equiv type StructuredScalar = string | number | boolean | null @@ -230,7 +230,7 @@ type StructuredOutputSchema = StructuredSchemaNode & { type: 'object' } 工具希望其调用在 UI 中如何呈现(编辑器工具调用卡片、CLI 日志行),提供方无关,使工具在不依赖任何客户端协议的情况下描述自身。`presentCall`/`presentResult` 返回一个 **`card` 标签的渲染意图**——一个可辨识联合类型,UI 桥接层据此分发: - `ToolCallView`(待执行):`{ card: 'generic', title, kind?, rawInput?, content?, locations? }`(默认卡片;`locations` 是 `{ path, line? }[]`,表示调用读取/修改的文件,供编辑器跟随)、`{ card: 'terminal', title, description?, cwd? }`(shell 命令→终端卡片)、或 `{ card: 'diff', title, diffs, locations? }`(文件创建/修改→行内 diff 卡片;`diffs` 是 `{ path, oldText, newText }[]`,新文件时 `oldText: null`)。 -- `ToolResultView`(已完成):`{ card: 'generic', title?, content? }`、`{ card: 'terminal', title?, output?, exitCode?, signal? }`(捕获的运行输出 + 退出状态;有能力的 UI 显示退出状态标签,无能力的 UI 获得桥接层从 `output` 派生的围栏 ` ```console ` 回退)、或 `{ card: 'diff', title?, diffs }`(已完成的文件变更→要展示的变更,通常是从变更前后内容计算出带上下文行的已应用 hunk,或在没有前像时的整文件 diff——例如文件创建。`tool_call_update` 的内容会**替换**调用的内容,因此变更工具即使与调用时的片段重复也要返回此卡片,以防结果文本覆盖 diff)。 +- `ToolResultView`(已完成):`{ card: 'generic', title?, content? }`、`{ card: 'terminal', title?, output?, exitCode?, signal? }`(捕获的运行输出 + 退出状态;有能力的 UI 显示退出状态标签,无能力的 UI 获得桥接层从 `output` 派生的围栏 ` ```console ` 回退)、或 `{ card: 'diff', title?, diffs }`(已完成的文件变更→要展示的变更,通常是从变更前后内容计算出带上下文行的已应用 hunk,或在没有前像时的整文件 diff——例如文件创建。`tool_call_update` 的内容会替换调用的内容,因此变更工具即使与调用时的片段重复也要返回此卡片,以防结果文本覆盖 diff)。 `ToolCallKind`(`'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other'`)为 generic 卡片选择图标。`FileLocation`(`{ path, line? }`)和 `FileDiff`(`{ path, oldText, newText }`)是共享的文件卡片词汇。该设计固定在[渲染意图联合类型 RFC](../rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md) 中;ACP 桥接层将 `diff` 卡片映射为 `{ type: 'diff' }` 内容块,将 `terminal` 卡片映射为 `_meta` 终端约定,并将文件卡片的标题相对于会话 cwd 做相对化处理。 diff --git a/docs/core-data-structures/web.i18n.yaml b/docs/core-data-structures/web.i18n.yaml index 7c248359a9..05d23f25a4 100644 --- a/docs/core-data-structures/web.i18n.yaml +++ b/docs/core-data-structures/web.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write web.md: 74db18835df02ef233f78ad7fbfec5d9b26d58e6 -web.zh.md: 7b94aa457985075c79052aeef66b2e46eac5b49d +web.zh.md: c5b99b72bc9ce1be19ebcad5ffad61fa256e1509 diff --git a/docs/core-data-structures/web.zh.md b/docs/core-data-structures/web.zh.md index 7b94aa4579..c5b99b72bc 100644 --- a/docs/core-data-structures/web.zh.md +++ b/docs/core-data-structures/web.zh.md @@ -73,7 +73,7 @@ type WebFetchBody = ## 提供方可用性 -提供方的 `available(): boolean` 是一个廉价的**本地**检查(凭证是否存在、配置是否可解析),**禁止发起网络调用**。它是执行时选择的输入,而非健康检查系统:`search()`/`fetch()` 读取它以选出可用的提供方,选择失败以结构化的 `WebError` 呈现给调用方路由——其 code 和 message 携带可分支的细节(缺失的 id 或有歧义的候选集)。 +提供方的 `available(): boolean` 是一个廉价的本地检查(凭证是否存在、配置是否可解析),**禁止发起网络调用**。它是执行时选择的输入,而非健康检查系统:`search()`/`fetch()` 读取它以选出可用的提供方,选择失败以结构化的 `WebError` 呈现给调用方路由——其 code 和 message 携带可分支的细节(缺失的 id 或有歧义的候选集)。 选择从不依赖注册顺序、配置顺序或 HMR(热模块替换)顺序:一项能力要么有显式的提供方 id(配置 `searchProvider`/`fetchProvider`,或填充同一字段的对应环境变量),要么在恰好只有一个可用提供方注册时自动选择;多个可用提供方且未配置 id 时为 `WEB_PROVIDER_AMBIGUOUS`,而非先注册先赢。 diff --git a/docs/core-data-structures/workflow.i18n.yaml b/docs/core-data-structures/workflow.i18n.yaml index c06899bc74..19a2d0db9e 100644 --- a/docs/core-data-structures/workflow.i18n.yaml +++ b/docs/core-data-structures/workflow.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write workflow.md: 1571723c172fe851e89550e4ed8588ddb14088a0 -workflow.zh.md: 68a5ff9b6ddf43145966e60706a42a758ea260ba +workflow.zh.md: 553d8fa8122b3c9f0cd29840cb2a72d9d5ae6e83 diff --git a/docs/core-data-structures/workflow.zh.md b/docs/core-data-structures/workflow.zh.md index 68a5ff9b6d..553d8fa812 100644 --- a/docs/core-data-structures/workflow.zh.md +++ b/docs/core-data-structures/workflow.zh.md @@ -50,7 +50,7 @@ interface WorkflowResult { ## 活跃运行:`WorkflowRun` -脚本执行期间消费方持有的句柄。消费方 await `result`,可中途 `cancel`,且*必须*在每条路径上 `dispose`。`result` 不会 reject:脚本失败以 `stopReason: 'error'` resolve;一旦运行被取消,即使脚本本身永不 settle,它也会在引擎的有界宽限期内 settle(引擎强制以 `cancelled` settle;worker-thread 引擎随后终止脚本的 worker),因此消费方 await `result` 不会在取消后卡死。`dispose()` = cancel + 有界 settle + 子 agent 静默;它不会因脚本卡死而挂起。 +脚本执行期间消费方持有的句柄。消费方 await `result`,可中途 `cancel`,且必须在每条路径上 `dispose`。`result` 不会 reject:脚本失败以 `stopReason: 'error'` resolve;一旦运行被取消,即使脚本本身永不 settle,它也会在引擎的有界宽限期内 settle(引擎强制以 `cancelled` settle;worker-thread 引擎随后终止脚本的 worker),因此消费方 await `result` 不会在取消后卡死。`dispose()` = cancel + 有界 settle + 等待子 agent 停稳;它不会因脚本卡死而挂起。 ```ts type-equiv interface WorkflowRun { diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml b/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml index f36c38cf0a..2affb91142 100644 --- a/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml +++ b/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 0001-acp-default-export-drops-inject.md: 6a71d8d7ef72e3110a99774b180f3de7115ef622 -0001-acp-default-export-drops-inject.zh.md: 1d97f1140a9595ac7e304b5a1600c3cbc47292f1 +0001-acp-default-export-drops-inject.zh.md: d12feca2eb1a35b68e191945562aabe25e043e37 diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.zh.md b/docs/postmortem/0001-acp-default-export-drops-inject.zh.md index 1d97f1140a..d12feca2eb 100644 --- a/docs/postmortem/0001-acp-default-export-drops-inject.zh.md +++ b/docs/postmortem/0001-acp-default-export-drops-inject.zh.md @@ -1,4 +1,4 @@ -# 事后分析 0001:ACP 服务器在连接时崩溃——`export default` 丢弃了插件的 `inject` +# 事故复盘(postmortem) 0001:ACP 服务器在连接时崩溃——`export default` 丢弃了插件的 `inject` [English](0001-acp-default-export-drops-inject.md) | 中文 @@ -20,7 +20,7 @@ ACP 服务器无法创建或加载任何一个会话——而这正是编辑器 - bridge(RFC 010)落地时附带完整的单元测试套件(codec、内存传输、基于属性的协议形状测试、失败路径、HMR(热模块替换))、一个需要 key 的真实 API e2e 测试,以及一个无需 key 的 stdout 纯净性 e2e 测试。全部绿色,100% 覆盖率。 - 真实 Zed 会话在 `session/new` 上立即失败,报错 `cannot get property "agents" without inject`。 -- 调查最初追踪了一个 Cordis「traceable/shadow」理论(看似合理,且该机制确实存在——见 Bug #2),随后在 vendor 的 `reflect.ts` 中对实际 fiber 遍历做了插桩,并运行了真实子进程。trace 显示 throw 发生在 `apply()` 第 179 行、**插件加载时**,位于 ROOT fiber 且没有 shadow——推翻了 shadow 理论对 `session/new` 的解释。 +- 调查最初追踪了一个 Cordis「traceable/shadow」理论(看似合理,且该机制确实存在——见 Bug #2),随后在 vendor 的 `reflect.ts` 中对实际 fiber 遍历做了插桩,并运行了真实子进程。trace 显示 throw 发生在 `apply()` 第 179 行、*插件加载时*,位于 ROOT fiber 且没有 shadow——推翻了 shadow 理论对 `session/new` 的解释。 - 找到根因 #1:一行多余的 `export default apply`。删除后 `session/new` 修复。 - 删除后暴露了 Bug #2:`session/load` 仍然在 `sessionPersistence` 上抛错——这是一个真正不同的机制(shadow 遍历),通过隔离修复并重新运行真实子进程得到确认。 @@ -57,7 +57,7 @@ unwrapExports(exports: any) { 修复 #1 后,`session/new` 正常工作,但 `session/load` 仍然抛出 `cannot get property "sessionPersistence" without inject`。这个问题*确实*是 Cordis 的 traceable/shadow 机制,值得精确理解。 -`session/load` 调用 `agents.resume(...)`,后者委托给 `AgentLoop.resume()`,其中读取了 `this.ctx.sessionPersistence`。`AgentLoop` 的 `static inject` 故意**不**包含 `sessionPersistence`——注入它会导致非持久化的演示永远挂起,等待一个永远不会加载的后端。该服务由一个独立的兄弟插件/fiber 提供,以机会性方式读取。 +`session/load` 调用 `agents.resume(...)`,后者委托给 `AgentLoop.resume()`,其中读取了 `this.ctx.sessionPersistence`。`AgentLoop` 的 `static inject` 故意不包含 `sessionPersistence`——注入它会导致非持久化的演示永远挂起,等待一个永远不会加载的后端。该服务由一个独立的兄弟插件/fiber 提供,以机会性方式读取。 Cordis 中的服务访问通过上下文代理(`vendor/cordis/src/reflect.ts`)进行。当通过从外部 fiber 获取的 *traceable 代理*调用服务方法时(此处:bridge fiber 调用 `ctx.agents.resume`,注册表返回 `this.factory`——即 `AgentLoop`——重新包装为绑定到调用方的新 traceable 代理),`createShadowMethod`(`vendor/cordis/src/utils.ts`)将 `this` 重新绑定到一个 *shadow* 对象,其 `ctx` 携带 `[symbols.shadow]` 指向 `AgentLoop` 自身的构造上下文。在 `resume` 内部,`this.ctx.sessionPersistence` 的解析从 shadow 的 fiber 开始遍历: @@ -108,6 +108,6 @@ if (!ctx.fiber.runtime) return ctx.reflect.get(prop, false) // ← direct glob ## 经验教训 - 命名空间插件与 default export 在 Cordis Loader 下互斥。选择命名空间形式(`name`/`inject`/`Config`/`apply`),不要添加 `export default`——`unwrapExports` 会丢弃命名空间。 -- 对于插件机会性读取但**未**在 `static inject` 中声明的服务,使用 `ctx.get(name)`,绝不使用 `ctx.<name>`。属性代理通过仅向祖先方向的 fiber 遍历解析,经由外部 shadow 时会失败;`ctx.get(name)` 是拓扑无关的查找(且默认严格——非活跃后端读取为 `undefined`,而非在 teardown 过程中被交出)。 +- 对于插件机会性读取但未在 `static inject` 中声明的服务,使用 `ctx.get(name)`,绝不使用 `ctx.<name>`。属性代理通过仅向祖先方向的 fiber 遍历解析,经由外部 shadow 时会失败;`ctx.get(name)` 是拓扑无关的查找(且默认严格——非活跃后端读取为 `undefined`,而非在 teardown 过程中被交出)。 - 手动构建插件的测试无法验证插件的加载方式。至少一个测试必须端到端地驱动真实的 Loader/export 路径。当核心操作不调用模型时,该测试无需 API key——因此它属于 CI,而非 key 门控之后。 - 相信 trace,不要相信理论。优雅的 shadow 解释是真实的,但它是*第二个* bug;*第一个*是一行导出错误,在数小时看似合理但实际错误的推理之后,一个 fiber 遍历的 `console.error` 在几分钟内就找到了它。 diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml index 533c899345..34b22884f8 100644 --- a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write 0002-js-expression-disabled-filesystem-tools.md: 43e57a6bd1b68f38c47eeda3c3abb8455024b350 -0002-js-expression-disabled-filesystem-tools.zh.md: 35bd54bb6f1551b5927c00184306141417803eaf +0002-js-expression-disabled-filesystem-tools.zh.md: ce091a4f6bd19dd9ccb9100583e92589998a1906 diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md index 35bd54bb6f..ce091a4f6b 100644 --- a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md @@ -1,4 +1,4 @@ -# 事后分析 0002:文件系统快照工具被永久禁用 +# 事故复盘(postmortem) 0002:文件系统快照工具被永久禁用 [English](0002-js-expression-disabled-filesystem-tools.md) | 中文 diff --git a/docs/postmortem/README.i18n.yaml b/docs/postmortem/README.i18n.yaml index 9fd5399786..1fb6e7d64f 100644 --- a/docs/postmortem/README.i18n.yaml +++ b/docs/postmortem/README.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write README.md: 4dc59e4f5e70f51c4c0baa64fbe34b213f2a7c3d -README.zh.md: e9ea00dacf3fde6f4d04c9a3b6dd5beeb7929660 +README.zh.md: b959566d6e2659957d9b6b121303cc4d0e7c4c4e diff --git a/docs/postmortem/README.zh.md b/docs/postmortem/README.zh.md index e9ea00dacf..b959566d6e 100644 --- a/docs/postmortem/README.zh.md +++ b/docs/postmortem/README.zh.md @@ -1,14 +1,14 @@ -# 事后分析 +# 事故复盘(postmortem) [English](README.md) | 中文 -事件复盘:一个 bug 到达了它不该到达的地方(真实用户、已合并的 PR(Pull Request)、已发布的版本),值得关注的是*为什么我们的流程放过了它*,而不仅仅是那一行修复。 +事故复盘:一个 bug 到达了它不该到达的地方(真实用户、已合并的 PR(Pull Request)、已发布的版本),值得关注的是*为什么我们的流程放过了它*,而不仅仅是那一行修复。 -事后分析不是 [RFC](../rfc/README.md)(RFC 记录一个经过深思熟虑的设计决策及其被否决的替代方案,或提出未来工作)。它是一份回顾性的失败记录:什么坏了、机制是什么、为什么每道安全网都没拦住、以及加了哪些具体的防护措施使同类 bug 下次能被显式暴露。 +事故复盘不是 [RFC](../rfc/README.md)(RFC 记录一个经过深思熟虑的设计决策及其被否决的替代方案,或提出未来工作)。它是一份回顾性的失败记录:什么坏了、机制是什么、为什么每道安全网都没拦住、以及加了哪些具体的防护措施使同类 bug 下次能被显式暴露。 -当一个 bug 满足以下条件时,请撰写事后分析:**隐蔽**(机制不显而易见,即使是细心的工程师也得费力重新推导)、**系统性**(逃逸的原因是测试/工具/约定的缺口,而非一次性的笔误)、**重新发现的代价高**(它消耗了真实的调试时间,且下次还会如此)。请链接该事后分析所推动建立的防护措施(测试、AGENTS.md 规则、ADR)。 +当一个 bug 满足以下条件时,请撰写事故复盘:**隐蔽**(机制不显而易见,即使是细心的工程师也得费力重新推导)、**系统性**(逃逸的原因是测试/工具/约定的缺口,而非一次性的笔误)、**重新发现的代价高**(它消耗了真实的调试时间,且下次还会如此)。请链接该事故复盘所推动建立的防护措施(测试、AGENTS.md 规则、ADR)。 -每篇事后分析以一段**摘要**开头:一个简短段落,让忙碌的读者在三十秒内吸收要点——什么坏了、用直白的话说根因是什么、为什么逃逸了、持久的教训是什么——然后才是后续的详细「概述 / 时间线 / 根因 / 防护措施」各节。 +每篇事故复盘以一段**摘要**开头:一个简短段落,让忙碌的读者在三十秒内吸收要点——什么坏了、用直白的话说根因是什么、为什么逃逸了、持久的教训是什么——然后才是后续的详细「概述 / 时间线 / 根因 / 防护措施」各节。 | # | 标题 | |---|---| diff --git a/docs/rfc/README.i18n.yaml b/docs/rfc/README.i18n.yaml index 8d007fe169..680bf965c7 100644 --- a/docs/rfc/README.i18n.yaml +++ b/docs/rfc/README.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write README.md: 9014579f3a98be907885332a0c815bca5c96855c -README.zh.md: cf258dc9ae1d73bf89d6a82c9bf246152c15e8b4 +README.zh.md: 3ed8b5a03c7f5888a331d0220a7b7c7fb6cd68e2 diff --git a/docs/rfc/README.zh.md b/docs/rfc/README.zh.md index cf258dc9ae..3ed8b5a03c 100644 --- a/docs/rfc/README.zh.md +++ b/docs/rfc/README.zh.md @@ -16,6 +16,8 @@ 文件名中的日期是该主题**首次提出**的时间(以 git 历史为准)。RFC 之间的交叉引用使用相对 Markdown 链接(`[topic](../../implemented/architecture/2026-…-….md)`),从不使用纯文字或编号,这样既可机械检查,也能在文件夹间移动时保持有效。 +<a id="classification"></a> + ## 分类 每份 RFC 属于 `scripts/rfc-index.ts` 中封闭集合里的一个路径编码类别;分类门禁拒绝其他文件夹。[INDEX.md](INDEX.md) 由路径、标题和文件名日期生成,其新鲜度受门禁保护。新增类别需要同时更新规范集合与本节。见[分类 RFC](implemented/process/2026-06-20-rfc-classification.md) 与[索引生成 RFC](implemented/process/2026-07-04-generate-rfc-index-tables.md)。 @@ -23,7 +25,7 @@ | 类别 | 覆盖范围 | |---|---| | `feature` | 面向用户或模型的新能力。 | -| `bug-fix` | 修正缺陷或弥补事后复盘发现的缺口。 | +| `bug-fix` | 修正缺陷或弥补事故复盘(postmortem)发现的缺口。 | | `simplification` | 在不增加能力的前提下移除代码、行为或对外表面积。 | | `architecture` | 关于**交付源码**的结构性决策:包之间的关系、运行时词汇。 | | `process` | 代码**周边**的工具、策略或工作流——门禁、包管理器、vendor 化——不涉及运行时行为。 | @@ -35,7 +37,9 @@ 当一个决策具备以下三个特征时,请写一份 RFC:**持久性**(它的影响超出单个函数或包)、**争议性**(存在一个合理工程师可能选择的真实替代方案)、**意外性**(未来读者否则会问「为什么要这样做」)。对未来重大工作的提案从 `proposed/` 开始;已经做出的决策从 `implemented/` 开始。选择与决策匹配的类别文件夹(见[分类](#classification))。 -以下情况**不要**写 RFC:机械性或局部的选择(一个变量名、一次单文件重构);已由门禁或 AGENTS.md 中的约定强制执行并解释的事项;代码中标记为 `TODO(...)` 的临时决策——将其记为 TODO,待稳定后再升级为 RFC。RFC 永远不会被编辑为一个*不同的决策*:用新 RFC 取代旧的,并互相链接。(编辑 `implemented/` RFC 以跟踪其已做出的决策现在*位于*何处——移动的文件、重命名的包——不是不同的决策,这是必需的而非禁止的;见 [implemented/AGENTS.md](implemented/AGENTS.md)。) +以下情况不要写 RFC:机械性或局部的选择(一个变量名、一次单文件重构);已由门禁或 AGENTS.md 中的约定强制执行并解释的事项;代码中标记为 `TODO(...)` 的临时决策——将其记为 TODO,待稳定后再升级为 RFC。RFC 永远不会被编辑为一个*不同的决策*:用新 RFC 取代旧的,并互相链接。(编辑 `implemented/` RFC 以跟踪其已做出的决策现在*位于*何处——移动的文件、重命名的包——不是不同的决策,这是必需的而非禁止的;见 [implemented/AGENTS.md](implemented/AGENTS.md)。) + +<a id="the-file-format"></a> ## 文件格式 diff --git a/scripts/type-equiv.manifest.json b/scripts/type-equiv.manifest.json index 51d98c659e..9840d08659 100644 --- a/scripts/type-equiv.manifest.json +++ b/scripts/type-equiv.manifest.json @@ -145,6 +145,134 @@ { "doc": "docs/core-data-structures/workflow.md", "symbol": "WorkflowStartRequest", "source": "packages/workflow/workflow/src/types.ts" }, { "doc": "docs/core-data-structures/workflow.md", "symbol": "WorkflowMeta", "source": "packages/workflow/workflow/src/types.ts" }, { "doc": "docs/core-data-structures/workflow.md", "symbol": "WorkflowResult", "source": "packages/workflow/workflow/src/types.ts" }, - { "doc": "docs/core-data-structures/workflow.md", "symbol": "WorkflowRun", "source": "packages/workflow/workflow/src/types.ts" } + { "doc": "docs/core-data-structures/workflow.md", "symbol": "WorkflowRun", "source": "packages/workflow/workflow/src/types.ts" }, + + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "Branded", "source": "packages/util/brand/src/index.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "ContentBlockMap", "source": "packages/llm/llm/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "Message", "source": "packages/llm/llm/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "MessageSourceMap", "source": "packages/llm/llm/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "FinishReasonMap", "source": "packages/llm/llm/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "GenerateOptions", "source": "packages/llm/llm/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "ToolSchema", "source": "packages/llm/llm/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "LlmCallConfig", "source": "packages/llm/llm/src/call-config.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "SessionEvent", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "Agent", "source": "packages/core/agent/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "HookContext", "source": "packages/core/agent/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "PromptDecision", "source": "packages/core/agent/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "ContinuationDecision", "source": "packages/core/agent/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "ContinuationStop", "source": "packages/core/agent/src/types.ts" }, + { "doc": "docs/core-data-structures/core.zh.md", "symbol": "SessionStartSource", "source": "packages/core/agent/src/types.ts" }, + { "doc": "docs/core-data-structures/scope.zh.md", "symbol": "ScopeKey", "source": "packages/core/scope/src/index.ts" }, + { "doc": "docs/core-data-structures/scope.zh.md", "symbol": "Scoped", "source": "packages/core/scope/src/index.ts" }, + { "doc": "docs/core-data-structures/scope.zh.md", "symbol": "Scope", "source": "packages/core/scope/src/index.ts" }, + { "doc": "docs/core-data-structures/system-prompt.zh.md", "symbol": "AssembleContext", "source": "packages/core/system-prompt/src/index.ts" }, + { "doc": "docs/core-data-structures/system-prompt.zh.md", "symbol": "PromptSection", "source": "packages/core/system-prompt/src/index.ts" }, + { "doc": "docs/core-data-structures/system-prompt.zh.md", "symbol": "ToolProviderResult", "source": "packages/core/system-prompt/src/index.ts" }, + { "doc": "docs/core-data-structures/llm-streaming.zh.md", "symbol": "StreamChunk", "source": "packages/llm/llm/src/types.ts" }, + { "doc": "docs/core-data-structures/llm-streaming.zh.md", "symbol": "TokenUsage", "source": "packages/llm/llm/src/types.ts" }, + { "doc": "docs/core-data-structures/llm-streaming.zh.md", "symbol": "ContentBlockMap", "source": "packages/llm/llm/src/types.ts" }, + { "doc": "docs/core-data-structures/llm-streaming.zh.md", "symbol": "AppIdentity", "source": "packages/llm/llm/src/attribution.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "SessionEventMap", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "EpochHeader", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "TodoItem", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "SessionEvent", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "TurnTriggerMap", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "TurnEndReasonMap", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "SurfaceEventType", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "SurfaceOp", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "SurfaceIntent", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "SurfaceNode", "source": "packages/core/session/src/surface.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "SurfaceFoldReplacement", "source": "packages/core/session/src/surface.ts" }, + { "doc": "docs/core-data-structures/session.zh.md", "symbol": "SurfaceFoldResult", "source": "packages/core/session/src/surface.ts" }, + { "doc": "docs/core-data-structures/persistence.zh.md", "symbol": "SessionHeader", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/persistence.zh.md", "symbol": "CreateSessionOptions", "source": "packages/core/session/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.zh.md", "symbol": "SessionEventSurface", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.zh.md", "symbol": "SessionRecord", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.zh.md", "symbol": "SessionEventRecord", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.zh.md", "symbol": "SessionQueryErrorCode", "source": "packages/session-query/session-query/src/config.ts" }, + { "doc": "docs/core-data-structures/session-query.zh.md", "symbol": "SessionEventReadRequest", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/session-query.zh.md", "symbol": "SessionEventWindow", "source": "packages/session-query/session-query/src/types.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "ToolDefinition", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "SchemaProp", "source": "packages/core/tools/src/schema.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "SchemaSpec", "source": "packages/core/tools/src/schema.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "InferArgs", "source": "packages/core/tools/src/schema.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "ToolExecutionToken", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "ToolExecutionInput", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "ToolExecution", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "ToolGuard", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "ToolRestriction", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "ToolExecutionResult", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "PreToolDecision", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "PostToolDecision", "source": "packages/core/tools/src/index.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "StructuredScalar", "source": "packages/core/tools/src/json-schema.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "StructuredSchemaType", "source": "packages/core/tools/src/json-schema.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "StructuredSchemaNode", "source": "packages/core/tools/src/json-schema.ts" }, + { "doc": "docs/core-data-structures/tools.zh.md", "symbol": "StructuredOutputSchema", "source": "packages/core/tools/src/json-schema.ts" }, + { "doc": "docs/core-data-structures/user-interaction.zh.md", "symbol": "AskUserQuestionOption", "source": "packages/ui/user-interaction/src/index.ts" }, + { "doc": "docs/core-data-structures/user-interaction.zh.md", "symbol": "AskUserQuestionItem", "source": "packages/ui/user-interaction/src/index.ts" }, + { "doc": "docs/core-data-structures/user-interaction.zh.md", "symbol": "AskUserQuestionRequest", "source": "packages/ui/user-interaction/src/index.ts" }, + { "doc": "docs/core-data-structures/user-interaction.zh.md", "symbol": "AskUserQuestionAnswerItem", "source": "packages/ui/user-interaction/src/index.ts" }, + { "doc": "docs/core-data-structures/user-interaction.zh.md", "symbol": "AskUserQuestionAnswer", "source": "packages/ui/user-interaction/src/index.ts" }, + { "doc": "docs/core-data-structures/user-interaction.zh.md", "symbol": "UserInteractionProvider", "source": "packages/ui/user-interaction/src/index.ts" }, + { "doc": "docs/core-data-structures/user-interaction.zh.md", "symbol": "UserInteractionError", "source": "packages/ui/user-interaction/src/index.ts" }, + { "doc": "docs/core-data-structures/approval.zh.md", "symbol": "ApprovalRequestId", "source": "packages/ui/user-approval/src/index.ts" }, + { "doc": "docs/core-data-structures/approval.zh.md", "symbol": "ApprovalOutcome", "source": "packages/ui/user-approval/src/index.ts" }, + { "doc": "docs/core-data-structures/approval.zh.md", "symbol": "ApprovalPolicy", "source": "packages/ui/user-approval/src/index.ts" }, + { "doc": "docs/core-data-structures/approval.zh.md", "symbol": "ApprovalRequest", "source": "packages/ui/user-approval/src/index.ts" }, + { "doc": "docs/core-data-structures/bash.zh.md", "symbol": "BashExecRequest", "source": "packages/bash/bash/src/types.ts" }, + { "doc": "docs/core-data-structures/bash.zh.md", "symbol": "BashExecSpec", "source": "packages/bash/bash/src/types.ts" }, + { "doc": "docs/core-data-structures/bash.zh.md", "symbol": "BashRunResult", "source": "packages/bash/bash/src/types.ts" }, + { "doc": "docs/core-data-structures/bash.zh.md", "symbol": "BashSandboxInfo", "source": "packages/bash/bash/src/types.ts" }, + { "doc": "docs/core-data-structures/bash.zh.md", "symbol": "CollectedOutput", "source": "packages/bash/bash/src/types.ts" }, + { "doc": "docs/core-data-structures/bash.zh.md", "symbol": "BashTask", "source": "packages/bash/bash/src/types.ts" }, + { "doc": "docs/core-data-structures/bash.zh.md", "symbol": "BashTaskRead", "source": "packages/bash/bash/src/types.ts" }, + { "doc": "docs/core-data-structures/sandbox.zh.md", "symbol": "SandboxMode", "source": "packages/sandbox/sandbox/src/index.ts" }, + { "doc": "docs/core-data-structures/sandbox.zh.md", "symbol": "ConfinedSandboxMode", "source": "packages/sandbox/sandbox/src/index.ts" }, + { "doc": "docs/core-data-structures/sandbox.zh.md", "symbol": "SandboxEnforcement", "source": "packages/sandbox/sandbox/src/index.ts" }, + { "doc": "docs/core-data-structures/sandbox.zh.md", "symbol": "SandboxPolicy", "source": "packages/sandbox/sandbox/src/index.ts" }, + { "doc": "docs/core-data-structures/sandbox.zh.md", "symbol": "ConfinedArgv", "source": "packages/sandbox/sandbox/src/index.ts" }, + { "doc": "docs/core-data-structures/code-runtime.zh.md", "symbol": "CodeRunRequest", "source": "packages/code-runtime/code-runtime/src/types.ts" }, + { "doc": "docs/core-data-structures/code-runtime.zh.md", "symbol": "CodeRunResult", "source": "packages/code-runtime/code-runtime/src/types.ts" }, + { "doc": "docs/core-data-structures/code-runtime.zh.md", "symbol": "CodeBindingNamespace", "source": "packages/code-runtime/code-runtime/src/types.ts" }, + { "doc": "docs/core-data-structures/code-runtime.zh.md", "symbol": "CodeBindingFunction", "source": "packages/code-runtime/code-runtime/src/types.ts" }, + { "doc": "docs/core-data-structures/code-runtime.zh.md", "symbol": "CodeRunFailure", "source": "packages/code-runtime/code-runtime/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsTarget", "source": "packages/fs/fs/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsTargetKey", "source": "packages/fs/fs/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsVersion", "source": "packages/fs/fs/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsInfo", "source": "packages/fs/fs/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsDirEntry", "source": "packages/fs/fs/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsWriteIntent", "source": "packages/fs/fs/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsWriteOutcome", "source": "packages/fs/fs/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsEditRequest", "source": "packages/fs/fs/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsEditOutcome", "source": "packages/fs/fs/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsErrorCode", "source": "packages/fs/fs/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FsPolicyExec", "source": "packages/fs/fs-policy/src/types.ts" }, + { "doc": "docs/core-data-structures/filesystem.zh.md", "symbol": "FileReadOutcome", "source": "packages/fs/tool-fs/src/read-render.ts" }, + { "doc": "docs/core-data-structures/skills.zh.md", "symbol": "SkillSource", "source": "packages/skill/skill/src/index.ts" }, + { "doc": "docs/core-data-structures/skills.zh.md", "symbol": "SkillResourceBase", "source": "packages/skill/skill/src/index.ts" }, + { "doc": "docs/core-data-structures/skills.zh.md", "symbol": "SkillSummary", "source": "packages/skill/skill/src/index.ts" }, + { "doc": "docs/core-data-structures/skills.zh.md", "symbol": "SkillCandidate", "source": "packages/skill/skill/src/index.ts" }, + { "doc": "docs/core-data-structures/skills.zh.md", "symbol": "SkillDefinition", "source": "packages/skill/skill/src/index.ts" }, + { "doc": "docs/core-data-structures/skills.zh.md", "symbol": "SkillRegistration", "source": "packages/skill/skill/src/index.ts" }, + { "doc": "docs/core-data-structures/skills.zh.md", "symbol": "SkillLookupOptions", "source": "packages/skill/skill/src/index.ts" }, + { "doc": "docs/core-data-structures/skills.zh.md", "symbol": "SkillProvider", "source": "packages/skill/skill/src/index.ts" }, + { "doc": "docs/core-data-structures/skills.zh.md", "symbol": "Config", "source": "packages/skill/skill/src/index.ts" }, + { "doc": "docs/core-data-structures/compaction.zh.md", "symbol": "CompactionResult", "source": "packages/compact/compact/src/types.ts" }, + { "doc": "docs/core-data-structures/subagent.zh.md", "symbol": "SubagentCapabilities", "source": "packages/subagent/subagent/src/types.ts" }, + { "doc": "docs/core-data-structures/subagent.zh.md", "symbol": "SubagentStartRequest", "source": "packages/subagent/subagent/src/types.ts" }, + { "doc": "docs/core-data-structures/subagent.zh.md", "symbol": "SubagentResult", "source": "packages/subagent/subagent/src/types.ts" }, + { "doc": "docs/core-data-structures/subagent.zh.md", "symbol": "SubagentStopReasonMap", "source": "packages/subagent/subagent/src/types.ts" }, + { "doc": "docs/core-data-structures/subagent.zh.md", "symbol": "SubagentRun", "source": "packages/subagent/subagent/src/types.ts" }, + { "doc": "docs/core-data-structures/subagent.zh.md", "symbol": "SubagentProvider", "source": "packages/subagent/subagent/src/types.ts" }, + { "doc": "docs/core-data-structures/web.zh.md", "symbol": "WebSearchRequest", "source": "packages/web/web/src/types.ts" }, + { "doc": "docs/core-data-structures/web.zh.md", "symbol": "WebSearchResult", "source": "packages/web/web/src/types.ts" }, + { "doc": "docs/core-data-structures/web.zh.md", "symbol": "WebSearchSource", "source": "packages/web/web/src/types.ts" }, + { "doc": "docs/core-data-structures/web.zh.md", "symbol": "WebFetchRequest", "source": "packages/web/web/src/types.ts" }, + { "doc": "docs/core-data-structures/web.zh.md", "symbol": "WebFetchResult", "source": "packages/web/web/src/types.ts" }, + { "doc": "docs/core-data-structures/web.zh.md", "symbol": "WebFetchBody", "source": "packages/web/web/src/types.ts" }, + { "doc": "docs/core-data-structures/workflow.zh.md", "symbol": "WorkflowStartRequest", "source": "packages/workflow/workflow/src/types.ts" }, + { "doc": "docs/core-data-structures/workflow.zh.md", "symbol": "WorkflowMeta", "source": "packages/workflow/workflow/src/types.ts" }, + { "doc": "docs/core-data-structures/workflow.zh.md", "symbol": "WorkflowResult", "source": "packages/workflow/workflow/src/types.ts" }, + { "doc": "docs/core-data-structures/workflow.zh.md", "symbol": "WorkflowRun", "source": "packages/workflow/workflow/src/types.ts" } ] } From 1a39953f69eccde7ff35180eabb70be9aba5060e Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:29:39 +0800 Subject: [PATCH 091/368] docs(i18n): address RFC translation review --- ...6-06-11-content-block-vocabulary.i18n.yaml | 4 +- .../2026-06-11-content-block-vocabulary.md | 4 +- .../2026-06-11-content-block-vocabulary.zh.md | 2 +- .../2026-06-11-custom-schema-dsl.i18n.yaml | 4 +- .../2026-06-11-custom-schema-dsl.md | 4 +- .../2026-06-11-custom-schema-dsl.zh.md | 4 +- ...ev-invariants-over-deep-readonly.i18n.yaml | 4 +- ...06-11-dev-invariants-over-deep-readonly.md | 4 +- ...11-dev-invariants-over-deep-readonly.zh.md | 2 +- ...026-06-11-event-sourced-sessions.i18n.yaml | 4 +- .../2026-06-11-event-sourced-sessions.md | 4 +- .../2026-06-11-event-sourced-sessions.zh.md | 8 +-- ...06-11-microkernel-event-taxonomy.i18n.yaml | 4 +- .../2026-06-11-microkernel-event-taxonomy.md | 4 +- ...026-06-11-microkernel-event-taxonomy.zh.md | 2 +- ...026-06-11-runtime-arg-validation.i18n.yaml | 4 +- .../2026-06-11-runtime-arg-validation.md | 4 +- .../2026-06-11-runtime-arg-validation.zh.md | 2 +- ...-06-11-structured-error-taxonomy.i18n.yaml | 4 +- .../2026-06-11-structured-error-taxonomy.md | 4 +- ...2026-06-11-structured-error-taxonomy.zh.md | 2 +- ...-tool-schemas-in-prompt-assembly.i18n.yaml | 4 +- ...6-06-11-tool-schemas-in-prompt-assembly.md | 4 +- ...6-11-tool-schemas-in-prompt-assembly.zh.md | 2 +- .../2026-06-13-capability-seams.i18n.yaml | 4 +- .../2026-06-13-capability-seams.md | 4 +- .../2026-06-13-capability-seams.zh.md | 8 +-- .../2026-06-13-twin-llm-adapters.i18n.yaml | 4 +- .../2026-06-13-twin-llm-adapters.md | 4 +- .../2026-06-13-twin-llm-adapters.zh.md | 2 +- .../2026-06-14-session-persistence.i18n.yaml | 4 +- .../2026-06-14-session-persistence.md | 4 +- .../2026-06-14-session-persistence.zh.md | 4 +- ...6-06-15-turn-enclosure-invariant.i18n.yaml | 4 +- .../2026-06-15-turn-enclosure-invariant.md | 4 +- .../2026-06-15-turn-enclosure-invariant.zh.md | 4 +- ...06-17-filesystem-capability-seam.i18n.yaml | 4 +- .../2026-06-17-filesystem-capability-seam.md | 4 +- ...026-06-17-filesystem-capability-seam.zh.md | 18 ++--- ...nt-lifecycle-and-ownership-seams.i18n.yaml | 4 +- ...-18-agent-lifecycle-and-ownership-seams.md | 4 +- ...-agent-lifecycle-and-ownership-seams.zh.md | 6 +- .../2026-06-18-session-surface.i18n.yaml | 4 +- .../2026-06-18-session-surface.md | 4 +- .../2026-06-18-session-surface.zh.md | 6 +- ...ed-persistence-write-coordinator.i18n.yaml | 4 +- ...18-shared-persistence-write-coordinator.md | 4 +- ...shared-persistence-write-coordinator.zh.md | 18 ++--- .../2026-06-20-branded-ids.i18n.yaml | 4 +- .../architecture/2026-06-20-branded-ids.md | 4 +- .../architecture/2026-06-20-branded-ids.zh.md | 14 ++-- ...-20-extract-example-app-packages.i18n.yaml | 4 +- ...2026-06-20-extract-example-app-packages.md | 4 +- ...6-06-20-extract-example-app-packages.zh.md | 6 +- .../2026-06-20-package-hierarchy.i18n.yaml | 4 +- .../2026-06-20-package-hierarchy.md | 4 +- .../2026-06-20-package-hierarchy.zh.md | 6 +- ...andatory-app-attribution-headers.i18n.yaml | 4 +- ...06-21-mandatory-app-attribution-headers.md | 4 +- ...21-mandatory-app-attribution-headers.zh.md | 10 +-- .../2026-06-24-web-capability-seam.i18n.yaml | 4 +- .../2026-06-24-web-capability-seam.md | 4 +- .../2026-06-24-web-capability-seam.zh.md | 2 +- ...06-26-file-context-as-event-gate.i18n.yaml | 4 +- .../2026-06-26-file-context-as-event-gate.md | 4 +- ...026-06-26-file-context-as-event-gate.zh.md | 6 +- ...stdin-env-trusted-plugin-surface.i18n.yaml | 4 +- ...0-bash-stdin-env-trusted-plugin-surface.md | 4 +- ...ash-stdin-env-trusted-plugin-surface.zh.md | 2 +- ...026-06-30-event-domain-semantics.i18n.yaml | 4 +- .../2026-06-30-event-domain-semantics.md | 4 +- .../2026-06-30-event-domain-semantics.zh.md | 8 +-- .../2026-07-02-fs-per-session-cwd.i18n.yaml | 4 +- .../2026-07-02-fs-per-session-cwd.md | 4 +- .../2026-07-02-fs-per-session-cwd.zh.md | 8 +-- ...2-result-time-applied-hunk-diffs.i18n.yaml | 4 +- ...26-07-02-result-time-applied-hunk-diffs.md | 4 +- ...07-02-result-time-applied-hunk-diffs.zh.md | 10 +-- ...6-07-02-tool-render-intent-union.i18n.yaml | 4 +- .../2026-07-02-tool-render-intent-union.md | 4 +- .../2026-07-02-tool-render-intent-union.zh.md | 2 +- ...ilesystem-directory-listing-seam.i18n.yaml | 4 +- ...07-03-filesystem-directory-listing-seam.md | 4 +- ...03-filesystem-directory-listing-seam.zh.md | 6 +- ...bles-and-tool-guidance-ownership.i18n.yaml | 4 +- ...t-variables-and-tool-guidance-ownership.md | 4 +- ...ariables-and-tool-guidance-ownership.zh.md | 12 ++-- ...6-07-05-reconstructable-requests.i18n.yaml | 4 +- .../2026-07-05-reconstructable-requests.md | 4 +- .../2026-07-05-reconstructable-requests.zh.md | 4 +- ...bagent-provider-lifecycle-events.i18n.yaml | 4 +- ...7-05-subagent-provider-lifecycle-events.md | 4 +- ...5-subagent-provider-lifecycle-events.zh.md | 16 ++--- ...6-07-06-timeout-deadline-library.i18n.yaml | 4 +- .../2026-07-06-timeout-deadline-library.md | 4 +- .../2026-07-06-timeout-deadline-library.zh.md | 2 +- ...6-07-07-tool-call-timeout-policy.i18n.yaml | 4 +- .../2026-07-07-tool-call-timeout-policy.md | 4 +- .../2026-07-07-tool-call-timeout-policy.zh.md | 10 +-- .../2026-07-08-agent-scope-contexts.i18n.yaml | 4 +- .../2026-07-08-agent-scope-contexts.md | 4 +- .../2026-07-08-agent-scope-contexts.zh.md | 2 +- ...07-12-agent-scope-runtime-design.i18n.yaml | 4 +- .../2026-07-12-agent-scope-runtime-design.md | 4 +- ...026-07-12-agent-scope-runtime-design.zh.md | 6 +- ...-06-14-acp-agent-client-protocol.i18n.yaml | 4 +- .../2026-06-14-acp-agent-client-protocol.md | 4 +- ...2026-06-14-acp-agent-client-protocol.zh.md | 6 +- .../2026-06-14-acp-multi-session.i18n.yaml | 4 +- .../feature/2026-06-14-acp-multi-session.md | 4 +- .../2026-06-14-acp-multi-session.zh.md | 6 +- .../feature/2026-06-15-code-mode.i18n.yaml | 4 +- .../feature/2026-06-15-code-mode.md | 4 +- .../feature/2026-06-15-code-mode.zh.md | 8 +-- ...26-06-17-filesystem-tool-schemas.i18n.yaml | 4 +- .../2026-06-17-filesystem-tool-schemas.md | 4 +- .../2026-06-17-filesystem-tool-schemas.zh.md | 16 ++--- ...-acp-terminal-and-tool-rendering.i18n.yaml | 4 +- ...6-06-18-acp-terminal-and-tool-rendering.md | 4 +- ...6-18-acp-terminal-and-tool-rendering.zh.md | 8 +-- ...06-18-compaction-capability-seam.i18n.yaml | 4 +- .../2026-06-18-compaction-capability-seam.md | 4 +- ...026-06-18-compaction-capability-seam.zh.md | 4 +- ...6-06-21-subagent-capability-seam.i18n.yaml | 4 +- .../2026-06-21-subagent-capability-seam.md | 4 +- .../2026-06-21-subagent-capability-seam.zh.md | 8 +-- .../2026-06-22-acp-subagent-backend.i18n.yaml | 4 +- .../2026-06-22-acp-subagent-backend.md | 4 +- .../2026-06-22-acp-subagent-backend.zh.md | 12 ++-- .../2026-06-25-ask-user-question.i18n.yaml | 4 +- .../feature/2026-06-25-ask-user-question.md | 4 +- .../2026-06-25-ask-user-question.zh.md | 6 +- .../2026-06-29-todo-write-tool.i18n.yaml | 4 +- .../feature/2026-06-29-todo-write-tool.md | 4 +- .../feature/2026-06-29-todo-write-tool.zh.md | 8 +-- .../feature/2026-06-30-hook-bridges.i18n.yaml | 4 +- .../feature/2026-06-30-hook-bridges.md | 4 +- .../feature/2026-06-30-hook-bridges.zh.md | 4 +- .../2026-06-30-hook-protocol-lib.i18n.yaml | 4 +- .../feature/2026-06-30-hook-protocol-lib.md | 4 +- .../2026-06-30-hook-protocol-lib.zh.md | 8 +-- .../2026-06-30-interception-seams.i18n.yaml | 4 +- .../feature/2026-06-30-interception-seams.md | 4 +- .../2026-06-30-interception-seams.zh.md | 6 +- ...026-06-30-session-store-fork-api.i18n.yaml | 4 +- .../2026-06-30-session-store-fork-api.md | 4 +- .../2026-06-30-session-store-fork-api.zh.md | 6 +- ...26-06-30-subagent-observe-enrich.i18n.yaml | 4 +- .../2026-06-30-subagent-observe-enrich.md | 4 +- .../2026-06-30-subagent-observe-enrich.zh.md | 2 +- .../2026-07-05-dynamic-workflows.i18n.yaml | 4 +- .../feature/2026-07-05-dynamic-workflows.md | 4 +- .../2026-07-05-dynamic-workflows.zh.md | 12 ++-- .../feature/2026-07-05-skill-system.i18n.yaml | 4 +- .../feature/2026-07-05-skill-system.md | 4 +- .../feature/2026-07-05-skill-system.zh.md | 6 +- .../2026-07-06-approval-seam.i18n.yaml | 4 +- .../feature/2026-07-06-approval-seam.md | 4 +- .../feature/2026-07-06-approval-seam.zh.md | 6 +- .../2026-07-06-explicit-tool-order.i18n.yaml | 4 +- .../feature/2026-07-06-explicit-tool-order.md | 4 +- .../2026-07-06-explicit-tool-order.zh.md | 6 +- .../feature/2026-07-06-sandbox.i18n.yaml | 4 +- .../implemented/feature/2026-07-06-sandbox.md | 4 +- .../feature/2026-07-06-sandbox.zh.md | 72 +++++++++---------- .../2026-07-07-mcp-client-plugin.i18n.yaml | 4 +- .../feature/2026-07-07-mcp-client-plugin.md | 4 +- .../2026-07-07-mcp-client-plugin.zh.md | 4 +- .../2026-07-07-session-prefix.i18n.yaml | 4 +- .../feature/2026-07-07-session-prefix.md | 4 +- .../feature/2026-07-07-session-prefix.zh.md | 10 +-- .../2026-07-08-repeat-tool-guard.i18n.yaml | 4 +- .../feature/2026-07-08-repeat-tool-guard.md | 4 +- .../2026-07-08-repeat-tool-guard.zh.md | 2 +- ...-self-referential-cordis-toolset.i18n.yaml | 4 +- ...6-07-08-self-referential-cordis-toolset.md | 4 +- ...7-08-self-referential-cordis-toolset.zh.md | 6 +- ...2026-07-10-session-query-service.i18n.yaml | 4 +- .../2026-07-10-session-query-service.md | 4 +- .../2026-07-10-session-query-service.zh.md | 6 +- ...nt-persona-tool-filter-and-depth.i18n.yaml | 4 +- ...-subagent-persona-tool-filter-and-depth.md | 4 +- ...bagent-persona-tool-filter-and-depth.zh.md | 6 +- .../2026-06-11-doc-sync-enforcement.i18n.yaml | 4 +- .../2026-06-11-doc-sync-enforcement.md | 4 +- .../2026-06-11-doc-sync-enforcement.zh.md | 8 +-- .../2026-06-11-quality-gates.i18n.yaml | 4 +- .../process/2026-06-11-quality-gates.md | 4 +- .../process/2026-06-11-quality-gates.zh.md | 8 +-- .../2026-06-11-tsdown-over-dumble.i18n.yaml | 4 +- .../process/2026-06-11-tsdown-over-dumble.md | 4 +- .../2026-06-11-tsdown-over-dumble.zh.md | 6 +- ...26-06-11-vendor-cordis-as-source.i18n.yaml | 4 +- .../2026-06-11-vendor-cordis-as-source.md | 4 +- .../2026-06-11-vendor-cordis-as-source.zh.md | 6 +- .../2026-06-16-pnpm-over-yarn.i18n.yaml | 4 +- .../process/2026-06-16-pnpm-over-yarn.md | 4 +- .../process/2026-06-16-pnpm-over-yarn.zh.md | 6 +- .../2026-06-17-ts-build-config.i18n.yaml | 4 +- .../process/2026-06-17-ts-build-config.md | 4 +- .../process/2026-06-17-ts-build-config.zh.md | 8 +-- ...6-06-18-markdown-cross-link-lint.i18n.yaml | 4 +- .../2026-06-18-markdown-cross-link-lint.md | 4 +- .../2026-06-18-markdown-cross-link-lint.zh.md | 8 +-- ...-20-core-data-structures-catalog.i18n.yaml | 4 +- ...2026-06-20-core-data-structures-catalog.md | 4 +- ...6-06-20-core-data-structures-catalog.zh.md | 6 +- ...6-06-20-generated-cordis-catalog.i18n.yaml | 4 +- .../2026-06-20-generated-cordis-catalog.md | 4 +- .../2026-06-20-generated-cordis-catalog.zh.md | 6 +- .../2026-06-20-rfc-classification.i18n.yaml | 4 +- .../process/2026-06-20-rfc-classification.md | 4 +- .../2026-06-20-rfc-classification.zh.md | 10 +-- .../2026-07-02-tool-schema-catalog.i18n.yaml | 4 +- .../process/2026-07-02-tool-schema-catalog.md | 4 +- .../2026-07-02-tool-schema-catalog.zh.md | 10 +-- ...-07-03-documentation-graph-atlas.i18n.yaml | 4 +- .../2026-07-03-documentation-graph-atlas.md | 4 +- ...2026-07-03-documentation-graph-atlas.zh.md | 6 +- ...4-cordis-jsdoc-completeness-gate.i18n.yaml | 4 +- ...26-07-04-cordis-jsdoc-completeness-gate.md | 4 +- ...07-04-cordis-jsdoc-completeness-gate.zh.md | 8 +-- ...2026-07-04-doc-tiers-and-budgets.i18n.yaml | 4 +- .../2026-07-04-doc-tiers-and-budgets.md | 4 +- .../2026-07-04-doc-tiers-and-budgets.zh.md | 6 +- ...-07-04-generate-rfc-index-tables.i18n.yaml | 4 +- .../2026-07-04-generate-rfc-index-tables.md | 4 +- ...2026-07-04-generate-rfc-index-tables.zh.md | 8 +-- ...26-07-04-persistence-log-catalog.i18n.yaml | 4 +- .../2026-07-04-persistence-log-catalog.md | 4 +- .../2026-07-04-persistence-log-catalog.zh.md | 2 +- .../2026-07-05-uniform-rfc-format.i18n.yaml | 4 +- .../process/2026-07-05-uniform-rfc-format.md | 4 +- .../2026-07-05-uniform-rfc-format.zh.md | 8 +-- ...-07-06-export-surface-jsdoc-gate.i18n.yaml | 4 +- .../2026-07-06-export-surface-jsdoc-gate.md | 4 +- ...2026-07-06-export-surface-jsdoc-gate.zh.md | 10 +-- ...6-07-06-generated-config-catalog.i18n.yaml | 4 +- .../2026-07-06-generated-config-catalog.md | 4 +- .../2026-07-06-generated-config-catalog.zh.md | 2 +- .../2026-07-06-node-engine-floor.i18n.yaml | 4 +- .../process/2026-07-06-node-engine-floor.md | 4 +- .../2026-07-06-node-engine-floor.zh.md | 6 +- ...6-07-06-parallel-github-ci-gates.i18n.yaml | 4 +- .../2026-07-06-parallel-github-ci-gates.md | 4 +- .../2026-07-06-parallel-github-ci-gates.zh.md | 6 +- ...26-07-06-parallel-pre-push-gates.i18n.yaml | 4 +- .../2026-07-06-parallel-pre-push-gates.md | 4 +- .../2026-07-06-parallel-pre-push-gates.zh.md | 6 +- ...10-readme-known-limitations-gate.i18n.yaml | 4 +- ...026-07-10-readme-known-limitations-gate.md | 4 +- ...-07-10-readme-known-limitations-gate.zh.md | 6 +- ...ackage-model-experience-contract.i18n.yaml | 4 +- ...07-12-package-model-experience-contract.md | 4 +- ...12-package-model-experience-contract.zh.md | 8 +-- ...-19-drop-mutable-session-summary.i18n.yaml | 4 +- ...2026-06-19-drop-mutable-session-summary.md | 4 +- ...6-06-19-drop-mutable-session-summary.zh.md | 8 +-- ...llapse-trace-only-session-events.i18n.yaml | 4 +- ...6-20-collapse-trace-only-session-events.md | 4 +- ...0-collapse-trace-only-session-events.zh.md | 2 +- ...onsumed-llm-adapter-change-event.i18n.yaml | 4 +- ...rop-unconsumed-llm-adapter-change-event.md | 4 +- ...-unconsumed-llm-adapter-change-event.zh.md | 2 +- ...nconsumed-llm-assembled-surfaces.i18n.yaml | 4 +- ...-drop-unconsumed-llm-assembled-surfaces.md | 4 +- ...op-unconsumed-llm-assembled-surfaces.zh.md | 2 +- ...26-06-20-prune-dead-seam-methods.i18n.yaml | 4 +- .../2026-06-20-prune-dead-seam-methods.md | 4 +- .../2026-06-20-prune-dead-seam-methods.zh.md | 6 +- ...-06-20-public-agent-stop-surface.i18n.yaml | 4 +- .../2026-06-20-public-agent-stop-surface.md | 4 +- ...2026-06-20-public-agent-stop-surface.zh.md | 2 +- ...ove-agent-boundary-mirror-events.i18n.yaml | 4 +- ...-20-remove-agent-boundary-mirror-events.md | 4 +- ...-remove-agent-boundary-mirror-events.zh.md | 6 +- .../2026-06-26-fsspec-style-fs-seam.i18n.yaml | 4 +- .../2026-06-26-fsspec-style-fs-seam.md | 4 +- .../2026-06-26-fsspec-style-fs-seam.zh.md | 20 +++--- ...07-02-remove-stream-chunk-mirror.i18n.yaml | 4 +- .../2026-07-02-remove-stream-chunk-mirror.md | 4 +- ...026-07-02-remove-stream-chunk-mirror.zh.md | 6 +- ...6-07-04-drop-image-content-block.i18n.yaml | 4 +- .../2026-07-04-drop-image-content-block.md | 4 +- .../2026-07-04-drop-image-content-block.zh.md | 8 +-- ...6-07-04-drop-inert-request-knobs.i18n.yaml | 4 +- .../2026-07-04-drop-inert-request-knobs.md | 4 +- .../2026-07-04-drop-inert-request-knobs.zh.md | 12 ++-- ...consumed-web-observation-surface.i18n.yaml | 4 +- ...drop-unconsumed-web-observation-surface.md | 4 +- ...p-unconsumed-web-observation-surface.zh.md | 4 +- .../2026-07-04-fold-stdio-ui-helper.i18n.yaml | 4 +- .../2026-07-04-fold-stdio-ui-helper.md | 4 +- .../2026-07-04-fold-stdio-ui-helper.zh.md | 6 +- ...producerless-vocabulary-variants.i18n.yaml | 4 +- ...-prune-producerless-vocabulary-variants.md | 4 +- ...une-producerless-vocabulary-variants.zh.md | 6 +- ...7-04-prune-write-only-fs-surface.i18n.yaml | 4 +- .../2026-07-04-prune-write-only-fs-surface.md | 4 +- ...26-07-04-prune-write-only-fs-surface.zh.md | 6 +- ...-04-remove-agent-steering-mirror.i18n.yaml | 4 +- ...2026-07-04-remove-agent-steering-mirror.md | 4 +- ...6-07-04-remove-agent-steering-mirror.zh.md | 8 +-- ...26-07-04-share-app-bin-boot-glue.i18n.yaml | 4 +- .../2026-07-04-share-app-bin-boot-glue.md | 4 +- .../2026-07-04-share-app-bin-boot-glue.zh.md | 6 +- ...4-tighten-hook-protocol-contract.i18n.yaml | 4 +- ...26-07-04-tighten-hook-protocol-contract.md | 4 +- ...07-04-tighten-hook-protocol-contract.zh.md | 6 +- ...m-acp-bridge-unreachable-surface.i18n.yaml | 4 +- ...-04-trim-acp-bridge-unreachable-surface.md | 4 +- ...-trim-acp-bridge-unreachable-surface.zh.md | 6 +- ...unconsumed-skill-provider-events.i18n.yaml | 4 +- ...2-drop-unconsumed-skill-provider-events.md | 4 +- ...rop-unconsumed-skill-provider-events.zh.md | 6 +- ...-12-prune-unused-web-seam-fields.i18n.yaml | 4 +- ...2026-07-12-prune-unused-web-seam-fields.md | 4 +- ...6-07-12-prune-unused-web-seam-fields.zh.md | 6 +- ...026-06-11-property-based-testing.i18n.yaml | 4 +- .../2026-06-11-property-based-testing.md | 4 +- .../2026-06-11-property-based-testing.zh.md | 4 +- .../2026-06-19-acp-snapshot-tests.i18n.yaml | 4 +- .../testing/2026-06-19-acp-snapshot-tests.md | 4 +- .../2026-06-19-acp-snapshot-tests.zh.md | 2 +- .../2026-06-19-real-api-e2e-ci.i18n.yaml | 4 +- .../testing/2026-06-19-real-api-e2e-ci.md | 4 +- .../testing/2026-06-19-real-api-e2e-ci.zh.md | 6 +- ...e-redundant-snapshot-log-goldens.i18n.yaml | 4 +- ...0-remove-redundant-snapshot-log-goldens.md | 4 +- ...emove-redundant-snapshot-log-goldens.zh.md | 2 +- ...-fork-child-replay-seed-boundary.i18n.yaml | 4 +- ...6-06-22-fork-child-replay-seed-boundary.md | 4 +- ...6-22-fork-child-replay-seed-boundary.zh.md | 6 +- ...26-06-22-fork-snapshot-scenarios.i18n.yaml | 4 +- .../2026-06-22-fork-snapshot-scenarios.md | 4 +- .../2026-06-22-fork-snapshot-scenarios.zh.md | 8 +-- ...6-06-22-subagent-snapshot-replay.i18n.yaml | 4 +- .../2026-06-22-subagent-snapshot-replay.md | 4 +- .../2026-06-22-subagent-snapshot-replay.zh.md | 10 +-- .../2026-07-04-hook-snapshot-matrix.i18n.yaml | 4 +- .../2026-07-04-hook-snapshot-matrix.md | 4 +- .../2026-07-04-hook-snapshot-matrix.zh.md | 14 ++-- ...-single-source-acp-replay-config.i18n.yaml | 4 +- ...6-07-04-single-source-acp-replay-config.md | 4 +- ...7-04-single-source-acp-replay-config.zh.md | 8 +-- ...t-header-content-in-one-scenario.i18n.yaml | 4 +- ...-request-header-content-in-one-scenario.md | 4 +- ...quest-header-content-in-one-scenario.zh.md | 2 +- ...7-08-shared-acp-snapshot-package.i18n.yaml | 4 +- .../2026-07-08-shared-acp-snapshot-package.md | 4 +- ...26-07-08-shared-acp-snapshot-package.zh.md | 6 +- .../2026-06-16-typed-event-schemas.i18n.yaml | 4 +- .../2026-06-16-typed-event-schemas.md | 4 +- .../2026-06-16-typed-event-schemas.zh.md | 8 +-- ...eneric-long-running-tool-runtime.i18n.yaml | 4 +- ...06-20-generic-long-running-tool-runtime.md | 4 +- ...20-generic-long-running-tool-runtime.zh.md | 2 +- ...026-06-30-pre-tool-input-rewrite.i18n.yaml | 4 +- .../2026-06-30-pre-tool-input-rewrite.md | 4 +- .../2026-06-30-pre-tool-input-rewrite.zh.md | 6 +- ...code-and-codex-subagent-backends.i18n.yaml | 4 +- ...claude-code-and-codex-subagent-backends.md | 4 +- ...ude-code-and-codex-subagent-backends.zh.md | 16 ++--- ...-07-08-interactive-side-sessions.i18n.yaml | 4 +- .../2026-07-08-interactive-side-sessions.md | 4 +- ...2026-07-08-interactive-side-sessions.zh.md | 6 +- ...10-sqlite-session-query-provider.i18n.yaml | 4 +- ...026-07-10-sqlite-session-query-provider.md | 4 +- ...-07-10-sqlite-session-query-provider.zh.md | 6 +- ...flow-progress-through-tool-calls.i18n.yaml | 4 +- ...am-workflow-progress-through-tool-calls.md | 4 +- ...workflow-progress-through-tool-calls.zh.md | 6 +- ...2026-06-11-api-extractor-reports.i18n.yaml | 4 +- .../2026-06-11-api-extractor-reports.md | 4 +- .../2026-06-11-api-extractor-reports.zh.md | 6 +- ...-06-11-architectural-conformance.i18n.yaml | 4 +- .../2026-06-11-architectural-conformance.md | 4 +- ...2026-06-11-architectural-conformance.zh.md | 6 +- ...11-supply-chain-and-vendor-drift.i18n.yaml | 4 +- ...026-06-11-supply-chain-and-vendor-drift.md | 4 +- ...-06-11-supply-chain-and-vendor-drift.zh.md | 8 +-- ...06-20-discover-package-inventory.i18n.yaml | 4 +- .../2026-06-20-discover-package-inventory.md | 4 +- ...026-06-20-discover-package-inventory.zh.md | 4 +- ...06-20-unify-agent-and-session-id.i18n.yaml | 4 +- .../2026-06-20-unify-agent-and-session-id.md | 4 +- ...026-06-20-unify-agent-and-session-id.zh.md | 6 +- ...04-prune-dead-core-spine-surface.i18n.yaml | 4 +- ...026-07-04-prune-dead-core-spine-surface.md | 4 +- ...-07-04-prune-dead-core-spine-surface.zh.md | 2 +- ...plify-session-log-representation.i18n.yaml | 4 +- ...-12-simplify-session-log-representation.md | 4 +- ...-simplify-session-log-representation.zh.md | 6 +- ...deterministic-and-stress-testing.i18n.yaml | 4 +- ...-06-11-deterministic-and-stress-testing.md | 4 +- ...-11-deterministic-and-stress-testing.zh.md | 8 +-- .../2026-06-11-mutation-testing.i18n.yaml | 4 +- .../testing/2026-06-11-mutation-testing.md | 4 +- .../testing/2026-06-11-mutation-testing.zh.md | 6 +- ...-06-11-immutable-public-surfaces.i18n.yaml | 4 +- .../2026-06-11-immutable-public-surfaces.md | 4 +- ...2026-06-11-immutable-public-surfaces.zh.md | 8 +-- ...-06-20-providerless-example-base.i18n.yaml | 4 +- .../2026-06-20-providerless-example-base.md | 4 +- ...2026-06-20-providerless-example-base.zh.md | 6 +- ...ssembled-assistant-messages-only.i18n.yaml | 4 +- ...06-20-assembled-assistant-messages-only.md | 4 +- ...20-assembled-assistant-messages-only.zh.md | 6 +- ...2026-06-20-drop-acp-session-load.i18n.yaml | 4 +- .../2026-06-20-drop-acp-session-load.md | 4 +- .../2026-06-20-drop-acp-session-load.zh.md | 6 +- ...026-06-20-drop-acp-terminal-meta.i18n.yaml | 4 +- .../2026-06-20-drop-acp-terminal-meta.md | 4 +- .../2026-06-20-drop-acp-terminal-meta.zh.md | 6 +- ...-20-drop-bash-output-spill-files.i18n.yaml | 4 +- ...2026-06-20-drop-bash-output-spill-files.md | 4 +- ...6-06-20-drop-bash-output-spill-files.zh.md | 6 +- ...-20-drop-durable-step-boundaries.i18n.yaml | 4 +- ...2026-06-20-drop-durable-step-boundaries.md | 4 +- ...6-06-20-drop-durable-step-boundaries.zh.md | 2 +- ...6-20-drop-unused-session-lineage.i18n.yaml | 4 +- .../2026-06-20-drop-unused-session-lineage.md | 4 +- ...26-06-20-drop-unused-session-lineage.zh.md | 6 +- ...ld-session-persistence-interface.i18n.yaml | 4 +- ...6-20-fold-session-persistence-interface.md | 4 +- ...0-fold-session-persistence-interface.zh.md | 2 +- ...026-06-20-generic-tool-rendering.i18n.yaml | 4 +- .../2026-06-20-generic-tool-rendering.md | 4 +- .../2026-06-20-generic-tool-rendering.zh.md | 6 +- ...6-06-20-retire-mid-turn-steering.i18n.yaml | 4 +- .../2026-06-20-retire-mid-turn-steering.md | 4 +- .../2026-06-20-retire-mid-turn-steering.zh.md | 6 +- ...-06-20-single-session-acp-bridge.i18n.yaml | 4 +- .../2026-06-20-single-session-acp-bridge.md | 4 +- ...2026-06-20-single-session-acp-bridge.zh.md | 6 +- ...06-20-truncate-interrupted-turns.i18n.yaml | 4 +- .../2026-06-20-truncate-interrupted-turns.md | 4 +- ...026-06-20-truncate-interrupted-turns.zh.md | 2 +- ...nimplemented-subagent-vocabulary.i18n.yaml | 4 +- ...prune-unimplemented-subagent-vocabulary.md | 4 +- ...ne-unimplemented-subagent-vocabulary.zh.md | 6 +- ...apse-workflow-to-foreground-core.i18n.yaml | 4 +- ...12-collapse-workflow-to-foreground-core.md | 4 +- ...collapse-workflow-to-foreground-core.zh.md | 6 +- ...ne-unused-skill-registry-surface.i18n.yaml | 4 +- ...-12-prune-unused-skill-registry-surface.md | 4 +- ...-prune-unused-skill-registry-surface.zh.md | 6 +- 447 files changed, 1106 insertions(+), 1106 deletions(-) diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml index 7ddbc75586..fb029f04fe 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml @@ -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 -2026-06-11-content-block-vocabulary.md: 9414bda624fa6e5fc7e9b11b7a738d32b269af6b -2026-06-11-content-block-vocabulary.zh.md: 764791cbef65c2031b8337af4f4cb6835e9d312a +2026-06-11-content-block-vocabulary.md: 6a90813ec90c6522a88a09d3536ce0cef8250238 +2026-06-11-content-block-vocabulary.zh.md: c9c65ae7e556cdf4eced0d45051862ff87fcd0fe diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md index 9414bda624..6a90813ec9 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.md @@ -1,9 +1,9 @@ # RFC: Provider-neutral content-block vocabulary owned by dsh-llm -English | [中文](2026-06-11-content-block-vocabulary.zh.md) - Status: implemented +English | [中文](2026-06-11-content-block-vocabulary.zh.md) + ## Problem The harness needs one internal language for messages that the loop, session log, and all plugins speak. diff --git a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md index 764791cbef..c9c65ae7e5 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md @@ -1,4 +1,4 @@ -# RFC:由 dsh-llm 拥有的提供方无关内容块词汇 +# RFC: 由 dsh-llm 拥有的提供方无关内容块词汇 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml index 6e7b3a2125..c08b4133de 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml @@ -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 -2026-06-11-custom-schema-dsl.md: 4c4d572b15d5e474e00e99fc5e7dd89240251c63 -2026-06-11-custom-schema-dsl.zh.md: eca0428d46ba3b3a4beac0cf9e8f02a9fa198388 +2026-06-11-custom-schema-dsl.md: 34c018b779d45c5eadb7337cb060c43b6f8d09b1 +2026-06-11-custom-schema-dsl.zh.md: 674a6b1a0b67617ffb4ab919899aa108c646a489 diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md index 4c4d572b15..34c018b779 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.md @@ -1,9 +1,9 @@ # RFC: Custom typed tool-schema DSL instead of schemastery -English | [中文](2026-06-11-custom-schema-dsl.zh.md) - Status: implemented +English | [中文](2026-06-11-custom-schema-dsl.zh.md) + ## Problem Tool parameters must reach the model as standard JSON Schema while giving tool authors typed `execute(args)` without casts. Schemastery already serves plugin config, but the tool-author API needs per-property `required: true` booleans rather than JSON Schema's separate `required` array. diff --git a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md index eca0428d46..674a6b1a0b 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md @@ -1,4 +1,4 @@ -# RFC:使用自定义类型化 tool-schema DSL 替代 schemastery +# RFC: 使用自定义类型化 tool-schema DSL 替代 schemastery Status: implemented @@ -14,7 +14,7 @@ Status: implemented ## 曾考虑的替代方案 -**Schemastery**(已作为 vendor 引入,用于插件 Config)经评估后被否决:它面向的是基于 StandardSchema 的校验/转换,而非 JSON Schema **生成**,因此会增加间接层却无法干净地产出协议格式(wire format)。 +**Schemastery**(已作为 vendor 引入,用于插件 Config)经评估后被否决:它面向的是基于 StandardSchema 的校验/转换,而非 JSON Schema *生成*,因此会增加间接层却无法干净地产出协议格式(wire format)。 ## 后果 diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml index 0758761505..2df4576e59 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml @@ -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 -2026-06-11-dev-invariants-over-deep-readonly.md: dc89b5b66d02bde2f4fe2794e04b76ecdeac62ae -2026-06-11-dev-invariants-over-deep-readonly.zh.md: 2c3c9e221b42f4b45216d09e825a41b1be3bcee9 +2026-06-11-dev-invariants-over-deep-readonly.md: 01a9e45fac77d2513924e78566a44a6059dd9d28 +2026-06-11-dev-invariants-over-deep-readonly.zh.md: 8f8db9f5bb095b8fc9c600b741c16d630a6c8167 diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md index dc89b5b66d..01a9e45fac 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md @@ -1,9 +1,9 @@ # RFC: Source-owned session immutability and dev-mode invariants -English | [中文](2026-06-11-dev-invariants-over-deep-readonly.zh.md) - Status: implemented +English | [中文](2026-06-11-dev-invariants-over-deep-readonly.zh.md) + ## Problem The session log needs two different protections: immutable ownership of each stored fact, and checks for relationships among facts across time and service seams. Conflating them in an optional development plugin would leave production history vulnerable; trying to express both through TypeScript readonly types would not create a runtime boundary or describe relational rules. diff --git a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md index 2c3c9e221b..8f8db9f5bb 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md @@ -1,4 +1,4 @@ -# RFC:源端拥有的会话不可变性与开发模式不变式 +# RFC: 源端拥有的会话不可变性与开发模式不变式 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml index e7645f5f8d..747bbf3ab0 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml @@ -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 -2026-06-11-event-sourced-sessions.md: 04ff974826ffbc9052c7eb9f5794bc16557241f9 -2026-06-11-event-sourced-sessions.zh.md: 12d6aedcc32b4d93f0dbe010854bcd3a0721703f +2026-06-11-event-sourced-sessions.md: c1460b84c5928a53537a5f6a51f41c4d5b101a12 +2026-06-11-event-sourced-sessions.zh.md: 938404524cd23a5a5b3d6d0b7fd5020df3d35a51 diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md index 04ff974826..c1460b84c5 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.md @@ -1,9 +1,9 @@ # RFC: Event-sourced sessions with derived message history -English | [中文](2026-06-11-event-sourced-sessions.zh.md) - Status: implemented +English | [中文](2026-06-11-event-sourced-sessions.zh.md) + ## Problem The MVP requires strict event-based tracing with fully replayable sessions (严格的基于事件的trace、logging系统,session完全可回放). diff --git a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md index 12d6aedcc3..938404524c 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md @@ -1,9 +1,9 @@ -# RFC:事件溯源的会话与派生消息历史 - -[English](2026-06-11-event-sourced-sessions.md) | 中文 +# RFC: 事件溯源的会话与派生消息历史 Status: implemented +[English](2026-06-11-event-sourced-sessions.md) | 中文 + ## 问题 MVP 要求严格的基于事件的追踪,以及完全可回放的会话(严格的基于事件的 trace、logging 系统,session 完全可回放)。 @@ -14,7 +14,7 @@ MVP 要求严格的基于事件的追踪,以及完全可回放的会话(严 追加操作是同步的(热路径从不阻塞于 I/O);`session/event` 是同步通知;持久化插件在后台缓冲写入,并在每个轮次结束时触发的 `session/flush` 检查点处等待排空。 -顺序契约:agent loop(智能体循环)先追加到会话,再发出对应的 Cordis 事件;`agent/step-result` waterfall(瀑布式事件)在 `assistant/message` 追加之前运行,因此日志记录的是工具调度实际使用的消息。回归测试固定了这一顺序。 +顺序契约:agent loop(智能体循环)*先*追加到会话,再发出对应的 Cordis 事件;`agent/step-result` waterfall(瀑布式事件)在 `assistant/message` 追加之前运行,因此日志记录的是工具调度实际使用的消息。回归测试固定了这一顺序。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml index 8634a86f36..107aab3c75 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml @@ -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 -2026-06-11-microkernel-event-taxonomy.md: c66968257a5a6304f187ccb5b9a162aa143e608d -2026-06-11-microkernel-event-taxonomy.zh.md: 7becf5872aee16fe21b4acbbc61920ed91c40f44 +2026-06-11-microkernel-event-taxonomy.md: 47e363f949b506756d9b20ee7dc53ca81e3f5e4d +2026-06-11-microkernel-event-taxonomy.zh.md: 3b0aa54108bf8737e6fe341c7b0797a554d328ec diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md index c66968257a..47e363f949 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md @@ -1,9 +1,9 @@ # RFC: Microkernel — extension via Cordis event taxonomy, one concrete loop -English | [中文](2026-06-11-microkernel-event-taxonomy.zh.md) - Status: implemented +English | [中文](2026-06-11-microkernel-event-taxonomy.zh.md) + ## Problem The product principle is "everything is a plugin": hooks, /goal, /loop, dynamic workflows, compaction, sandboxing, permissions, UI, persistence, MCP, skills must all be writable as plugins without modifying the core. diff --git a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md index 7becf5872a..3b0aa54108 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md @@ -1,4 +1,4 @@ -# RFC:微内核——通过 Cordis 事件分类体系实现扩展,唯一具体循环 +# RFC: 微内核——通过 Cordis 事件分类体系实现扩展,唯一具体循环 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml index 9ae6b5d602..0fa22e5594 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml @@ -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 -2026-06-11-runtime-arg-validation.md: 6da117643166d304bee1d368a314cc1602cac828 -2026-06-11-runtime-arg-validation.zh.md: 5f41ff99a2d56f39ff8d61191d92dc782f163c82 +2026-06-11-runtime-arg-validation.md: 82d01263225ce719e80631d1890f0a6cc328119d +2026-06-11-runtime-arg-validation.zh.md: 4bd6720f7ec87fcef028ba94f445a5210f1b0d7a diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md index 6da1176431..82d0126322 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.md @@ -1,9 +1,9 @@ # RFC: Runtime arg validation at the model boundary -English | [中文](2026-06-11-runtime-arg-validation.zh.md) - Status: implemented +English | [中文](2026-06-11-runtime-arg-validation.zh.md) + ## Problem `defineTool` ([the custom schema DSL](2026-06-11-custom-schema-dsl.md)) gives tool authors a typed `execute(args)` via the `InferArgs<S>` mapping. But that type is a compile-time claim about a value that arrives at runtime as model-generated JSON: nothing forced the model to honor the schema, so a malformed call — missing a required key, a string where a number was declared, an enum value outside the set — reached `execute` typed-in-name-only. The tool body then either crashed on the bad shape (a generic stack trace the model can't act on) or, worse, silently misbehaved. Meanwhile the converter already encodes the exact structure a validator would need to walk. diff --git a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md index 5f41ff99a2..4bd6720f7e 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md @@ -1,4 +1,4 @@ -# RFC:模型边界处的运行时参数校验 +# RFC: 模型边界处的运行时参数校验 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml index aa6cdb26ff..4a381ba271 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml @@ -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 -2026-06-11-structured-error-taxonomy.md: 2baf88a1f942215e79561e565f455276c80178c4 -2026-06-11-structured-error-taxonomy.zh.md: 90b0fdd7f6c8b4f0565c6538c2ddd4cb31680c38 +2026-06-11-structured-error-taxonomy.md: 5a5f75038b6124457d2d4d08cbe0bec80415a387 +2026-06-11-structured-error-taxonomy.zh.md: d5a45a447ca00d48cb8366911a10f34c584d915c diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md index 2baf88a1f9..5a5f75038b 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.md @@ -1,9 +1,9 @@ # RFC: Structured error taxonomy -English | [中文](2026-06-11-structured-error-taxonomy.zh.md) - Status: implemented +English | [中文](2026-06-11-structured-error-taxonomy.zh.md) + ## Problem Failures crossed seams as bare strings. A tool error flattened to a text block — name, code, and stack lost — so a future sandbox/retry plugin couldn't tell ENOENT from EACCES, and the model got less actionable feedback than it could. A non-Error throw degraded further: the loop wrapped it in `new Error(String(x))`, dropping any code. And `LlmError` was the only typed error in the system, with no shared base, so there was nothing for a consumer to `instanceof` against generically. diff --git a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md index 90b0fdd7f6..d5a45a447c 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md @@ -1,4 +1,4 @@ -# RFC:结构化错误分类体系 +# RFC: 结构化错误分类体系 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml index 5f5b2ef266..57fe989a5d 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml @@ -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 -2026-06-11-tool-schemas-in-prompt-assembly.md: 443e6f20115e5a76001b4466c2d756675adbd886 -2026-06-11-tool-schemas-in-prompt-assembly.zh.md: 03624b98fabdedf691f3fb448cc5f37ba5a649ef +2026-06-11-tool-schemas-in-prompt-assembly.md: 260d56ffab054d874e13eb34eac029bf59b381fc +2026-06-11-tool-schemas-in-prompt-assembly.zh.md: 5ae98dfac676574d00f34580ec079bb6a8f2331f diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md index 443e6f2011..260d56ffab 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.md @@ -1,9 +1,9 @@ # RFC: Tool schemas are part of the system-prompt assembly -English | [中文](2026-06-11-tool-schemas-in-prompt-assembly.zh.md) - Status: implemented +English | [中文](2026-06-11-tool-schemas-in-prompt-assembly.zh.md) + ## Problem On the wire, tool schemas travel in a dedicated `tools` field of the model request, not in prompt text. Architecturally, though, "what the model is told it can do" is one coherent concern: prompt sections and the tool list are assembled from the same plugin contributions and consumed at the same moment. diff --git a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md index 03624b98fa..5ae98dfac6 100644 --- a/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md @@ -1,4 +1,4 @@ -# RFC:工具 schema 是系统提示词组装的一部分 +# RFC: 工具 schema 是系统提示词组装的一部分 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml index d0eac81287..fcdc63390f 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.i18n.yaml @@ -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 -2026-06-13-capability-seams.md: e9d417dbd2bafcaece39601b12dbb310feb1e19b -2026-06-13-capability-seams.zh.md: c569f3df083ec48bd05e6be2d3a1e5875fde362f +2026-06-13-capability-seams.md: f10182737347fc54ff3fd06edb299e569397773d +2026-06-13-capability-seams.zh.md: e65d2f31eb80ce80e92b3e4bbb4d5b8948185c44 diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md index e9d417dbd2..f101827373 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.md @@ -1,9 +1,9 @@ # RFC: Capability seams — interface / implementation / consumer split -English | [中文](2026-06-13-capability-seams.zh.md) - Status: implemented +English | [中文](2026-06-13-capability-seams.zh.md) + ## Problem The harness has swappable capabilities — bash execution today, sandboxed/remote executors and alternative model providers tomorrow. A capability has three concerns that change at different rates and for different reasons: the *contract* (what the capability is), the *implementation* (how it runs), and the *consumer surface* (what the model and other plugins program against). Bundling them in one package couples those rates of change — swapping a local executor for a sandboxed one would churn the tool schemas the model sees, even though the model-facing contract never changed. diff --git a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md index c569f3df08..e65d2f31eb 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-13-capability-seams.zh.md @@ -1,9 +1,9 @@ -# RFC:能力 seam——接口/实现/消费方三分 - -[English](2026-06-13-capability-seams.md) | 中文 +# RFC: 能力 seam——接口/实现/消费方三分 Status: implemented +[English](2026-06-13-capability-seams.md) | 中文 + ## 问题 harness 具有可替换的能力:当前是 bash 执行,未来会有沙箱化/远程执行器和替代模型提供方。一项能力涉及三个关注点,它们以不同速率、因不同原因变化:*契约*(这项能力是什么)、*实现*(它如何运行)、*消费方接口*(模型和其他插件面向什么编程)。将三者捆绑在一个包(package)中会耦合这些变化速率——把本地执行器换成沙箱化执行器时,模型看到的工具 schema 也会被搅动,尽管面向模型的契约从未改变。 @@ -25,7 +25,7 @@ harness 具有可替换的能力:当前是 bash 执行,未来会有沙箱化 ## 曾考虑的替代方案 - **单一合并包**:否决。因为它重新耦合了三分设计本要分离的三种变化速率(这正是拆分的意义所在)。 -- **`@cordisjs/plugin-capability`**:这是完全不同的维度。它是一个权限/能力*安全*服务(具名权限加继承,通过 `ctx.capability.test` 对会话进行检测),是延后的权限/沙箱工作(`tools/pre-execute` deny/ask seam)的候选方案,**不是**替换实现的机制。混淆这两个「能力」概念正是本 RFC 所指出的陷阱。 +- **`@cordisjs/plugin-capability`**:这是完全不同的维度。它是一个权限/能力*安全*服务(具名权限加继承,通过 `ctx.capability.test` 对会话进行检测),是延后的权限/沙箱工作(`tools/pre-execute` deny/ask seam)的候选方案,不是替换实现的机制。混淆这两个「能力」概念正是本 RFC 所指出的陷阱。 ## 后果 diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml index df04a14d6a..545aae3758 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml @@ -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 -2026-06-13-twin-llm-adapters.md: 4efefcf4e2f6b1d60567ba3bfed7ae1ea53a7a4e -2026-06-13-twin-llm-adapters.zh.md: 6cabd95c5361afdea5b33ffdee34a5acb6026f7f +2026-06-13-twin-llm-adapters.md: edd7080e2a16e9f1af2ebd56a4265040dc970c17 +2026-06-13-twin-llm-adapters.zh.md: 2087d498f65326fa0a2cb74be409a926a5e343f5 diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md index 4efefcf4e2..edd7080e2a 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.md @@ -1,9 +1,9 @@ # RFC: Two LLM adapters as a design-verification twin -English | [中文](2026-06-13-twin-llm-adapters.zh.md) - Status: implemented +English | [中文](2026-06-13-twin-llm-adapters.zh.md) + ## Problem `dsh-llm` owns a provider-neutral streaming vocabulary — the `StreamChunk` protocol (`block-start`, `text-delta`, `reasoning-delta`, `tool-call-delta`, `block-end`, `usage`, `finish`) and the content-block types ([the content-block vocabulary](2026-06-11-content-block-vocabulary.md)). A vocabulary defined against a single adapter risks baking that adapter's quirks into the "neutral" contract: anything the one implementation happens to do becomes the de-facto spec, and the abstraction is unverified until a second provider arrives — by which point the leak is expensive to fix. diff --git a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md index 6cabd95c53..2087d498f6 100644 --- a/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md @@ -1,4 +1,4 @@ -# RFC:以两个 LLM 适配器作为设计验证孪生体 +# RFC: 以两个 LLM 适配器作为设计验证孪生体 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml index c6b9eaf967..aa7fe88f24 100644 --- a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.i18n.yaml @@ -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 -2026-06-14-session-persistence.md: 4078487b71862791dd25cf2afcfc03255cfeb0be -2026-06-14-session-persistence.zh.md: a44ef9647ca4003bc81023a54b7e9b5945003b02 +2026-06-14-session-persistence.md: a50c076746981892239304266194d1e8e309574f +2026-06-14-session-persistence.zh.md: d609e663bd9e36f74bf34404c021a30f54d3bd76 diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md index 4078487b71..a50c076746 100644 --- a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.md @@ -1,9 +1,9 @@ # RFC: Session persistence as an abstract service over the existing `SessionEvent` -English | [中文](2026-06-14-session-persistence.zh.md) - Status: implemented +English | [中文](2026-06-14-session-persistence.zh.md) + ## Problem Sessions lived only in memory. The example `session-jsonl.ts` plugin (duplicated byte-for-byte in both examples) was write-only telemetry: it buffered `session/event` and appended JSON lines, with no read/replay path, no crash-safety (no fsync, no atomic write, a fire-and-forget dispose drain), no listing, and no format versioning. Nothing could rehydrate a past session from disk into a live agent, so durable resume ("continue yesterday's task"), durable forking, and the ACP `session/load` method ([ACP support](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md)) were all impossible. diff --git a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md index a44ef9647c..d609e663bd 100644 --- a/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-14-session-persistence.zh.md @@ -1,4 +1,4 @@ -# RFC:会话持久化作为基于现有 `SessionEvent` 的抽象服务 +# RFC: 会话持久化作为基于现有 `SessionEvent` 的抽象服务 Status: implemented @@ -23,7 +23,7 @@ Status: implemented - **仅追加;崩溃的轮次被关闭,而非截断。** 已刷写到 `turn/end` 的事件永不被重写,且循环仅在轮次结束时刷写。由于一个被中断的轮次可能包含大量有效工作,`load` 保留其连续、可解析的事件,并为未应答的工具调用追加错误结果、补一个缺失的 `step/end`,以及带 `{ kind: 'interrupted' }` 的 `turn/end`。合成的结果保证恢复后的 provider transcript(文本记录)仍然有效。只有不完整的最后一条记录会被丢弃;在最后一个真实 `turn/end` 处或之前出现解析错误或序号间隙,属于数据损坏,会使该会话不可加载。 - **文件后端为规范实现,数据库后端为经过验证的直接替换。** `SessionEvent` 1:1 映射到一行 `(session_id, seq, type, time, data)`:`append` 是 INSERT(在一个断言连续 seq 契约的事务中),`load` 是 SELECT … ORDER BY seq。`dsh-session-persistence-sqlite` 正是如此:一个 `SessionPersistence` 子类,接口无变化(opencode 在 SQLite/WAL 上运行的正是这个形状),且通过与 JSONL 后端相同的 `runPersistenceContract` 测试套件。该契约以相同的语义约束两个后端(惰性物化、加载时关闭中断轮次、连续 seq),一次表达在文件字节上,一次表达在数据库行上。 - **元数据在日志之外。** 格式版本、cwd 和谱系是存储关注点,不是可回放的对话状态,因此它们存放在 `dsh-session` 拥有的 `SessionHeader` 中,并通过新的只读属性 `session.header` 附加到 `Session` 上——永远不进入 `SessionEventMap`,永远不到达 `deriveMessages()`。替代方案(一个可合并扩展的 `session/meta` 事件作为日志第 0 行)被否决:日志内事件会随 seed/fork 的会话免费携带,但元数据不是可回放状态,因此显式的日志外 header seam 是更干净的代价。(header 最初被拆分为不可变的 `SessionHeader` 加可变的 `SessionSummary`,二者的联合类型为 `SessionMeta`;可变 summary 后来因属于死状态而被移除——见 [移除可变会话摘要](../simplification/2026-06-19-drop-mutable-session-summary.md)。) -- **`ctx.agents.create()` 和 `ctx.agents.resume()` 是异步工厂;resume 还跨越持久化边界。** `ctx.agents.resume({ resumeSessionId })` 等待 `ctx.sessionPersistence.load`,用加载的事件重建活跃会话(使 `lastTurnNumber`/`deriveMessages` 得以延续),并在恢复的 id 上启动一个新 agent(不是 `${agentId}-session`)。agent loop(智能体循环)不会硬注入 `sessionPersistence`(那样会让非持久化的演示永远挂起);当 `sessionPersistence` 不存在时,`resume` 以明确的错误拒绝。 +- **`ctx.agents.create()` 和 `ctx.agents.resume()` 是异步工厂;resume 还跨越持久化边界。** `ctx.agents.resume({ resumeSessionId })` 等待 `ctx.sessionPersistence.load`,用加载的事件重建活跃会话(使 `lastTurnNumber`/`deriveMessages` 得以延续),并在恢复的 id 上启动一个新 agent(不是 `${agentId}-session`)。agent loop(智能体循环)不会硬注入 `sessionPersistence`(那样会让非持久化的演示永远挂起);当它不存在时,`resume` 以明确的错误拒绝。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml index 72eb9e3d7a..cf8898285a 100644 --- a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml @@ -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 -2026-06-15-turn-enclosure-invariant.md: bf0789f21ba7bd928e023bb5fd844d9ec78c4bc1 -2026-06-15-turn-enclosure-invariant.zh.md: 644e7b975e024286d5307f586f509c2b4a9f21ea +2026-06-15-turn-enclosure-invariant.md: 26ae1890e481288b3be17f97db14c332f69be4b8 +2026-06-15-turn-enclosure-invariant.zh.md: 1946f829100e39afed826b8cf3ba82d22058c27d diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md index bf0789f21b..26ae1890e4 100644 --- a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md @@ -1,9 +1,9 @@ # RFC: Every session event is enclosed in a turn -English | [中文](2026-06-15-turn-enclosure-invariant.zh.md) - Status: implemented +English | [中文](2026-06-15-turn-enclosure-invariant.zh.md) + ## Problem A durable session-persistence backend (added in a companion change) uses the **turn** as its crash-recovery boundary: a crash can leave an unclosed final turn, which `load` closes with a synthetic `turn/end {kind:'interrupted'}` while preserving the turn's real events (see [session persistence](2026-06-14-session-persistence.md)). This recovery is only well-defined if nothing *legitimately* durable sits OUTSIDE a turn — between the last `turn/end` and the next `turn/start` — since such an event would be swept into the next turn's interrupted close. diff --git a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md index 644e7b975e..1946f82910 100644 --- a/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md @@ -1,4 +1,4 @@ -# RFC:每个会话事件都封闭在一个轮次内 +# RFC: 每个会话事件都封闭在一个轮次内 Status: implemented @@ -10,7 +10,7 @@ Status: implemented 这一假设并不成立。有两条路径在任何轮次之外记录了事件: -1. **排队的用户消息。** agent loop(智能体循环)排空排队消息并在 `turn/start` **之前**追加 `user/message`——于是一个轮次自身的提示词落在了前一个 `turn/end` 与下一个 `turn/start` 之间的间隙中。 +1. **排队的用户消息。** agent loop(智能体循环)排空排队消息并在 `turn/start` *之前*追加 `user/message`——于是一个轮次自身的提示词落在了前一个 `turn/end` 与下一个 `turn/start` 之间的间隙中。 2. **空闲时的上下文注入。** `agent.inject()` 直接追加一条 `context/message`。它在生产环境中的真实调用方是 `dsh-tool-bash`,后者从 `ctx.bash.onTaskDone` 注入后台任务完成通知——该回调在后台 bash 任务完成时触发,而这经常发生在 agent **空闲**(轮次之间)时。 在情况 2 中,如果注入的 `context/message` 是 flush/dispose 之前的最后一个事件(之后没有轮次追加 `turn/end`),`scanLog` 会将其视为崩溃残留并在**恢复时丢弃**——注入的上下文已持久写入磁盘,但重新加载后被静默丢失。情况 1 本身无害(`user/message` 之后总会跟着它触发的轮次),但使「什么可以出现在轮次之外」这条规则变得模糊。 diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml index 11faf45d26..62ab944e40 100644 --- a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml @@ -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 -2026-06-17-filesystem-capability-seam.md: c502ae712de22e97661192057d4410c7c55ea044 -2026-06-17-filesystem-capability-seam.zh.md: 4e544e24c548a52bde254886a65ff2fdb559a986 +2026-06-17-filesystem-capability-seam.md: c87c8a44d2e956a9613039378d26f72e8ee97ee7 +2026-06-17-filesystem-capability-seam.zh.md: 4864e77ced5c078fc8c1e970a2ff88c78a37af2a diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md index c502ae712d..c87c8a44d2 100644 --- a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.md @@ -1,9 +1,9 @@ # RFC: Filesystem capability seam — ctx.fs, local backend, and model-facing filesystem tools -English | [中文](2026-06-17-filesystem-capability-seam.zh.md) - Status: implemented +English | [中文](2026-06-17-filesystem-capability-seam.zh.md) + ## Problem The harness has a concrete `bash` capability seam (`dsh-bash` / `dsh-bash-local` / `dsh-tool-bash`), but filesystem operations are about to be added as model-facing tools without an equivalent seam. If `read`, `write`, and `edit` directly use `node:fs`, the model-facing tool package will own filesystem execution policy, local path resolution, atomic write behavior, text decoding, symlink behavior, and edit semantics all at once. diff --git a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md index 4e544e24c5..4864e77ced 100644 --- a/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md @@ -1,9 +1,9 @@ -# RFC:文件系统能力 seam——ctx.fs、本地后端与面向模型的文件系统工具 - -[English](2026-06-17-filesystem-capability-seam.md) | 中文 +# RFC: 文件系统能力 seam——ctx.fs、本地后端与面向模型的文件系统工具 Status: implemented +[English](2026-06-17-filesystem-capability-seam.md) | 中文 + ## 问题 harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` / `dsh-tool-bash`),但文件系统操作即将作为面向模型的工具加入,却没有等价的 seam。如果 `read`、`write` 和 `edit` 直接使用 `node:fs`,面向模型的工具包将同时承担文件系统执行策略、本地路径解析、原子写入行为、文本解码、符号链接行为和编辑语义。 @@ -80,10 +80,10 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 解析后的目标必须至少暴露三个概念: - 原始输入路径,用于诊断。 -- 不透明的 `targetKey`,用于过期守护和文件状态查找。本地后端可能使用类似 realpath 的键;远程后端可能使用工作区 URI 或文件 id。消费方禁止解析或假设它是本地绝对路径。 +- 不透明的 `targetKey`,用于陈旧守护和文件状态查找。本地后端可能使用类似 realpath 的键;远程后端可能使用工作区 URI 或文件 id。消费方禁止解析或假设它是本地绝对路径。 - `displayPath`,用于面向模型/UI 的输出。根据后端不同,它可能是本地绝对路径、工作区相对路径或远程 URI。 -读取和变更结果必须包含不透明的文件 `version`。本地后端可以使用 mtime/size 或类似 hash 的令牌;远程后端可以使用 revision id。`dsh-fs-policy` 插件记录版本用于过期检查;消费方可以展示相关元数据但禁止解释版本令牌。 +读取和变更结果必须包含不透明的文件 `version`。本地后端可以使用 mtime/size 或类似 hash 的令牌;远程后端可以使用 revision id。`dsh-fs-policy` 插件记录版本用于陈旧检查;消费方可以展示相关元数据但禁止解释版本令牌。 提供方返回已解码的文本:`readText` 返回整个常规文本文件,`streamText` 为大文件流式传输相同的文本语义。两者负责常规文件检查;有界的行/输出处理不是它们的职责——行窗口化、带行号渲染和总行数统计位于执行器(`dsh-tool-fs`)中,执行器通过 `ctx.fs` 读取并渲染面向模型的窗口。提供方负责 UTF-8 解码和二进制/NUL 拒绝;它不知道行窗口或视图。 @@ -91,7 +91,7 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 全文件写入创建或替换 UTF-8 文本文件。后端在支持且有文档说明时可以创建父目录。已有的非常规目标被拒绝。`writeText` 接受一个可选期望:`createIfAbsent` 创建缺失的目标并拒绝已存在的(报 `FS_NOT_OBSERVED`,这是策略为未观测 owner 使用的路径);`replaceIfVersion` 仅在目标处于观测版本时替换,否则报 `FS_STALE_VERSION`;省略期望则为无条件的裸提供方创建或覆盖。策略插件根据 owner 的观测状态选择提供哪个期望。 -字面编辑是提供方原语(`editText`),而非在 `tool-fs` 中由读取加写入组合而成。字面匹配、重复匹配拒绝、CRLF 保留、二进制拒绝、可选的过期版本检查和原子读-改-写必须一起留在后端的变更临界区内。`editText` 接受相同的可选版本期望;过期检查在字面匹配之前运行,因此基于旧读取的编辑会报 `FS_STALE_VERSION`。远程后端可以将编辑实现为原生的 compare-and-edit 操作;消费方不强制本地风格的组合。 +字面编辑是提供方原语(`editText`),而非在 `tool-fs` 中由读取加写入组合而成。字面匹配、重复匹配拒绝、CRLF 保留、二进制拒绝、可选的陈旧版本检查和原子读-改-写必须一起留在后端的变更临界区内。`editText` 接受相同的可选版本期望;陈旧检查在字面匹配之前运行,因此基于旧读取的编辑会报 `FS_STALE_VERSION`。远程后端可以将编辑实现为原生的 compare-and-edit 操作;消费方不强制本地风格的组合。 策略插件(而非 `ctx.fs`)对先前观测进行门控:`edit` 要求 owner 有先前观测(否则报 `FS_NOT_OBSERVED`),记录的版本作为 CAS 基础传给 `editText`。在策略插件缺席时,`ctx.fs` 本身是一个完整的无约束 seam(无条件写入/编辑);工具从不与策略方法耦合。 @@ -129,8 +129,8 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 本仓库曾踩过的防御性模式类别被直接固定: - **原子写入临时文件安全。** 写入/编辑通过目标旁边一个私有随机 `0700` 目录中的独占 owner-only(`'wx'`、`0o600`)临时文件暂存,失败时清理,最后原子 rename——与 bash 溢出文件规则一致,因为可预测的 world-readable 临时路径招致符号链接竞争和信息泄露。测试断言权限,并断言已存在的临时路径不会被覆盖;此原语是 seam 的常设要求。 -- **通过符号链接的 `targetKey` 同一性。** 两个输入路径解析到同一 realpath 时共享一个观测状态条目:通过路径 A 的 `read` 满足通过符号链接路径 B 的 `edit` 的读后编辑守护,通过一个路径的过期写入可通过另一个路径检测到。 -- **并发/过期竞争。** 对同一目标的两个并发写入/编辑操作确定性地收敛——一个成功,另一个被 `FS_STALE_VERSION` 拒绝——成功的编辑刷新记录状态,使同一 owner 的下一次编辑可以继续。 +- **通过符号链接的 `targetKey` 同一性。** 两个输入路径解析到同一 realpath 时共享一个观测状态条目:通过路径 A 的 `read` 满足通过符号链接路径 B 的 `edit` 的读后编辑守护,通过一个路径的陈旧写入可通过另一个路径检测到。 +- **并发/陈旧竞争。** 对同一目标的两个并发写入/编辑操作确定性地收敛——一个成功,另一个被 `FS_STALE_VERSION` 拒绝——成功的编辑刷新记录状态,使同一 owner 的下一次编辑可以继续。 - **HMR(热模块替换)安全与 dispose(资源释放)。** dispose 后端的 fiber 会撤回 `ctx.fs` 提供方;后续的提供方以无继承状态启动。 ## 曾考虑的替代方案 @@ -155,6 +155,6 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` **观测状态持久化被推迟。** 观测状态存在于内存中(`dsh-fs-policy` 内部的 `WeakMap`),因此恢复的会话保守地要求文件在写入/编辑前重新读取,直到未来的会话事件或持久化机制使观测可回放。 -**错误码成为 seam 的一部分。** `FsError` 错误码使过期版本和观测失败可通过既有的结构化错误分类体系进行机器路由。代价是 `dsh-fs` 从 `dsh-llm` 导入共享的 `HarnessError` 基类;该依赖是有意为之且限于错误词汇。 +**错误码成为 seam 的一部分。** `FsError` 错误码使陈旧版本和观测失败可通过既有的结构化错误分类体系进行机器路由。代价是 `dsh-fs` 从 `dsh-llm` 导入共享的 `HarnessError` 基类;该依赖是有意为之且限于错误词汇。 **包拆分的成本前置。** 三包拆分在只有一个后端时就增加了样板代码。这是有意为之:文件系统访问是可能的沙箱/远程边界,在面向模型的工具发布后再改包接口代价更高。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml index 27f4b260ae..34098ed665 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml @@ -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 -2026-06-18-agent-lifecycle-and-ownership-seams.md: a70e7db8d809efd68ae770995795fc7b3d1b83d2 -2026-06-18-agent-lifecycle-and-ownership-seams.zh.md: 3fb68336c56b5296f18b3587ea42399a05362733 +2026-06-18-agent-lifecycle-and-ownership-seams.md: c37578020366dd40250c061e34a86d2de6907e19 +2026-06-18-agent-lifecycle-and-ownership-seams.zh.md: 1f3cb609da5508d22046f445e08a75dc5a7901cd diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md index a70e7db8d8..c375780203 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md @@ -1,9 +1,9 @@ # RFC: Agent lifecycle and ownership seams -English | [中文](2026-06-18-agent-lifecycle-and-ownership-seams.zh.md) - Status: implemented +English | [中文](2026-06-18-agent-lifecycle-and-ownership-seams.zh.md) + ## Problem Several ACP and tool-bash limitations were symptoms of the same missing seam: plugins could create or resume agents through `ctx.agents`, but they could not own and dispose one agent independently, and long-running bash tasks carried no stable owner in the executor itself. ACP aborted and awaited agents on disconnect but could not unregister just that session's agent; `session/cancel` could not cancel queued-but-not-yet-started work; and `tool-bash` kept task ownership in a plugin-local `Map`, so an HMR reload could make an old task look unowned. diff --git a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md index 3fb68336c5..1f3cb609da 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md @@ -1,9 +1,9 @@ -# RFC:Agent 生命周期与所有权 seam - -[English](2026-06-18-agent-lifecycle-and-ownership-seams.md) | 中文 +# RFC: Agent 生命周期与所有权 seam Status: implemented +[English](2026-06-18-agent-lifecycle-and-ownership-seams.md) | 中文 + ## 问题 ACP(Agent Client Protocol)与 tool-bash 的若干限制是同一个缺失 seam 的症状:插件可以通过 `ctx.agents` 创建或恢复 agent(智能体),但无法独立拥有和 dispose(资源释放)单个 agent,而长时间运行的 bash 任务在执行器中也没有稳定的所有者。ACP 在断连时中止并等待 agent,却无法仅注销该会话的 agent;`session/cancel` 无法取消已入队但尚未开始的工作;`tool-bash` 将任务所有权保存在插件本地的 `Map` 中,因此一次 HMR(热模块替换)重载就可能让旧任务看起来无主。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml index 98b4ee0e59..c319a372fe 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.i18n.yaml @@ -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 -2026-06-18-session-surface.md: 31297166b735468147850a81d7fd43a8fa30a1e8 -2026-06-18-session-surface.zh.md: 159aefc10261ac5380701f46c3d4a367674940b1 +2026-06-18-session-surface.md: bcad236eaa2bead3c140e7a12772729710d43f83 +2026-06-18-session-surface.zh.md: 2ec60501c183d1bdab22ceb67b7f6aa0040ae82b diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.md b/docs/rfc/implemented/architecture/2026-06-18-session-surface.md index 31297166b7..bcad236eaa 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-session-surface.md +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.md @@ -1,9 +1,9 @@ # RFC: Session surface — a linked list over the event log for LLM message derivation -English | [中文](2026-06-18-session-surface.zh.md) - Status: implemented +English | [中文](2026-06-18-session-surface.zh.md) + ## Problem The event log is authoritative, but history manipulation had no durable shared mechanism. Plugins such as compaction would otherwise rewrite derived requests through order-sensitive listeners, leave no provenance, and require repeated changes to `deriveMessages()`. diff --git a/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md b/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md index 159aefc102..2ec60501c1 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-18-session-surface.zh.md @@ -1,9 +1,9 @@ -# RFC:会话 surface——基于事件日志的链表,用于 LLM 消息派生 - -[English](2026-06-18-session-surface.md) | 中文 +# RFC: 会话 surface——基于事件日志的链表,用于 LLM 消息派生 Status: implemented +[English](2026-06-18-session-surface.md) | 中文 + ## 问题 事件日志是权威数据源,但历史操纵此前没有持久化的共享机制。如果没有这样的机制,上下文压缩(context compaction)等插件只能通过顺序敏感的监听器改写派生请求,不留溯源信息,且每次新增操纵都要反复修改 `deriveMessages()`。 diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml index f693539b91..e960781d12 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml @@ -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 -2026-06-18-shared-persistence-write-coordinator.md: 3fc30dc2e1382fd983d050433123f46a2cd0ed19 -2026-06-18-shared-persistence-write-coordinator.zh.md: 38e900d38cc48317836717ddeda5323cf97df993 +2026-06-18-shared-persistence-write-coordinator.md: 7648c6f8e43fb8c78f881838aa4d476aba209dca +2026-06-18-shared-persistence-write-coordinator.zh.md: 19f583c2f3d78fcdac1378cfe00e49c0be943eb1 diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md index 3fc30dc2e1..7648c6f8e4 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md @@ -1,9 +1,9 @@ # RFC: Shared persistence write coordinator -English | [中文](2026-06-18-shared-persistence-write-coordinator.zh.md) - Status: implemented +English | [中文](2026-06-18-shared-persistence-write-coordinator.zh.md) + ## Problem `dsh-session-persistence-jsonl` and `dsh-session-persistence-sqlite` intentionally prove the same `SessionPersistence` contract over different storage media, but their write-path orchestration was duplicated: per-session state, `session/created` adoption, backend-specific prefix reads, write-behind buffers, serialized flush chains, HMR seeding, and dispose drains. The pure seed-prefix collision and serializability guards had already moved into the seam package; the remaining orchestration was still correctness-heavy and received the same fixes twice. A code-level diff showed the two backends were byte-identical — or same-algorithm — for ALL of it: the four maps (`states`/`buffers`/`chains`/`inits`), `installWritePath`, `initFor`, `onCreated`'s four cases, `flush`, `drain`, `serialize`, `adopt`, `adoptLivePrefix`, `assertVersion`, and the `create`/`append`/`load` skeletons. Only the storage primitives (write bytes vs. INSERT rows) differed. diff --git a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md index 38e900d38c..19f583c2f3 100644 --- a/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md @@ -1,12 +1,12 @@ -# RFC:共享持久化写入协调器 - -[English](2026-06-18-shared-persistence-write-coordinator.md) | 中文 +# RFC: 共享持久化写入协调器 Status: implemented +[English](2026-06-18-shared-persistence-write-coordinator.md) | 中文 + ## 问题 -`dsh-session-persistence-jsonl` 与 `dsh-session-persistence-sqlite` 有意在不同存储介质上证明同一份 `SessionPersistence` 契约,但它们的写入路径编排是重复的:per-session 状态、`session/created` 接管、后端特定的前缀读取、write-behind 缓冲区、序列化的 flush 链、HMR(热模块替换)种子注入与 dispose(资源释放)排空。纯粹的种子前缀碰撞检查与可序列化守卫已迁入 seam 包;剩余的编排仍然对正确性要求很高,且同样的修复被应用了两次。代码级 diff 表明两个后端在**全部**这些逻辑上要么字节相同、要么算法相同:四个 map(`states`/`buffers`/`chains`/`inits`)、`installWritePath`、`initFor`、`onCreated` 的四种分支、`flush`、`drain`、`serialize`、`adopt`、`adoptLivePrefix`、`assertVersion`,以及 `create`/`append`/`load` 的骨架。唯一的差异在于存储原语(写字节 vs. INSERT 行)。 +`dsh-session-persistence-jsonl` 与 `dsh-session-persistence-sqlite` 有意在不同存储介质上证明同一份 `SessionPersistence` 契约,但它们的写入路径编排是重复的:per-session 状态、`session/created` 接管、后端特定的前缀读取、write-behind 缓冲区、序列化的 flush 链、HMR(热模块替换)种子注入与 dispose(资源释放)排空。纯粹的种子前缀碰撞检查与可序列化守卫已迁入 seam 包;剩余的编排仍然对正确性要求很高,且同样的修复被应用了两次。代码级 diff 表明两个后端在全部这些逻辑上要么字节相同、要么算法相同:四个 map(`states`/`buffers`/`chains`/`inits`)、`installWritePath`、`initFor`、`onCreated` 的四种分支、`flush`、`drain`、`serialize`、`adopt`、`adoptLivePrefix`、`assertVersion`,以及 `create`/`append`/`load` 的骨架。唯一的差异在于存储原语(写字节 vs. INSERT 行)。 ## 决策 @@ -19,16 +19,16 @@ Status: implemented 六个方法(五个必需 + 一个可选的生命周期钩子)——协调器与存储之间唯一的 seam: - `name`——后端标签,用于 dispose 失败时的 `AggregateError`。 -- `loadStored(id)`——按 id 读取已存储的前缀,扫描**任何**存储范围(JSONL 的每个 cwd bucket;SQLite 的 id 全局唯一)。用于恢复/加载,以及通过 `!== undefined` 进行创建碰撞探测。 -- `loadLive(id, cwd)`——读取**限定于 `cwd`** 的已存储前缀。**与 `loadStored` 有意区分**:HMR live-adoption 只能接管与存活会话处于**同一 cwd** 的持久化日志;同 id 但不同 cwd 的日志是碰撞而非恢复。合并二者会重新引入跨 cwd 接管 bug。SQLite 忽略 `cwd`。 -- `appendBatch(meta, events, isMaterialized)`——持久追加一个连续批次,在尚未物化时**原子地**惰性物化会话(物化写入与首批事件必须一起提交——崩溃不得留下一个已物化但为空的会话;这就是为什么没有单独的 `materialize` 钩子)。 +- `loadStored(id)`——按 id 读取已存储的前缀,扫描任何存储范围(JSONL 的每个 cwd bucket;SQLite 的 id 全局唯一)。用于恢复/加载,以及通过 `!== undefined` 进行创建碰撞探测。 +- `loadLive(id, cwd)`——读取限定于 `cwd` 的已存储前缀。**与 `loadStored` 有意区分**:HMR live-adoption 只能接管与存活会话处于同一 cwd 的持久化日志;同 id 但不同 cwd 的日志是碰撞而非恢复。合并二者会重新引入跨 cwd 接管 bug。SQLite 忽略 `cwd`。 +- `appendBatch(meta, events, isMaterialized)`——持久追加一个连续批次,在尚未物化时原子地惰性物化会话(物化写入与首批事件必须一起提交——崩溃不得留下一个已物化但为空的会话;这就是为什么没有单独的 `materialize` 钩子)。 - `commitRepair(meta, tornMarker, closers)`——使崩溃修复持久化:截断损坏的尾部(当且仅当 `tornMarker !== undefined`)并追加 `closers`。**不要求原子性**——JSONL 合理地分两步 fsync(先截断再追加),SQLite 在一个事务中完成 DELETE+INSERT。用于 `load`(截断 + 合成 closers)和 live-adoption(仅截断,`closers = []`)。 - `list()`——列出所有已存储的元数据。 -- `close?()`——可选的生命周期清理(SQLite 关闭 db 句柄;JSONL 省略),在 dispose effect 中于静默排空**之后**被 await,因此 close 失败不会掩盖排空错误。 +- `close?()`——可选的生命周期清理(SQLite 关闭 db 句柄;JSONL 省略),在 dispose effect 中于静默排空之后被 await,因此 close 失败不会掩盖排空错误。 ### 不透明的 torn marker -保持 seam 整洁的唯一设计选择:崩溃修复中「损坏尾部在哪里」的 token 对协调器是**不透明的**。协调器计算合成 closers(它拥有来自 `dsh-session` 的 `interruptedTurnClosers`),但它只测试 `tornMarker !== undefined` 并将值原样传回 `commitRepair`——从不检视其内容。每个后端选择自己的 marker 类型:JSONL 使用要截断到的字节偏移,SQLite 使用要从其开始删除的 seq(两者恰好都是 `number`)。JSONL 后端将其 `committedBytes < buffer.byteLength` 比较折叠**在钩子内部**,因此返回的 marker 已经是 `number | undefined`;如果不做这层折叠,协调器就必须了解字节长度。 +保持 seam 整洁的唯一设计选择:崩溃修复中「损坏尾部在哪里」的 token 对协调器是不透明的。协调器计算合成 closers(它拥有来自 `dsh-session` 的 `interruptedTurnClosers`),但它只测试 `tornMarker !== undefined` 并将值原样传回 `commitRepair`——从不检视其内容。每个后端选择自己的 marker 类型:JSONL 使用要截断到的字节偏移,SQLite 使用要从其开始删除的 seq(两者恰好都是 `number`)。JSONL 后端将其 `committedBytes < buffer.byteLength` 比较折叠在钩子内部,因此返回的 marker 已经是 `number | undefined`;如果不做这层折叠,协调器就必须了解字节长度。 ## 测试 diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml index 9fc5b9299f..7d33e94f0a 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.i18n.yaml @@ -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 -2026-06-20-branded-ids.md: f6d066857d8904ae5343f12310266663806a0ae2 -2026-06-20-branded-ids.zh.md: 80c158e598f3007416d31a89a6704a759798e44e +2026-06-20-branded-ids.md: aab47a1413451edb707ae797e5b99cda6e34efad +2026-06-20-branded-ids.zh.md: 1ccfda3282069510bcdbfbddf4546305fd0923a5 diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md index f6d066857d..aab47a1413 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.md @@ -1,9 +1,9 @@ # RFC: Branded IDs everywhere they belong -English | [中文](2026-06-20-branded-ids.zh.md) - Status: implemented +English | [中文](2026-06-20-branded-ids.zh.md) + ## Problem The harness already brands three identifiers — `CallId` (`packages/llm/llm/src/brand.ts`), `SessionId` (`packages/core/session/src/types.ts`), and `AgentId` (`packages/core/agent/src/types.ts`) — using the `Branded<B> = string & { readonly [BRAND]: B }` machinery (owned by the type-only `@deepseek-ai/dsh-brand` package at `packages/util/brand/` — see its [README](../../../../packages/util/brand/README.md)) and a zero-cost cast factory per type. `dsh-brand` also states the governing policy: *"Branding is for ids that cross package boundaries and could plausibly be confused; not every string needs a brand."* That policy is right; the problem is that it is only half-applied. Two gaps let a structurally-identical-but-semantically-wrong string slip through the type checker today. diff --git a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md index 80c158e598..1ccfda3282 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-20-branded-ids.zh.md @@ -1,16 +1,16 @@ -# RFC:在所有应有之处使用 branded ID - -[English](2026-06-20-branded-ids.md) | 中文 +# RFC: 在所有应有之处使用 branded ID Status: implemented +[English](2026-06-20-branded-ids.md) | 中文 + ## 问题 harness 已经为三个标识符做了 brand 处理:`CallId`(`packages/llm/llm/src/brand.ts`)、`SessionId`(`packages/core/session/src/types.ts`)和 `AgentId`(`packages/core/agent/src/types.ts`),使用 `Branded<B> = string & { readonly [BRAND]: B }` 机制(由纯类型包(package) `@deepseek-ai/dsh-brand` 拥有,位于 `packages/util/brand/`,见其 [README](../../../../packages/util/brand/README.md)),并为每个类型提供零开销的 cast 工厂。`dsh-brand` 还声明了治理策略:*"Branding 用于跨包边界且可能被混淆的 id;不是每个 string 都需要 brand。"* 这条策略是正确的;问题在于它只落实了一半。两处缺口使得结构相同但语义错误的 string 今天仍能通过类型检查器。 **缺口 1:bash seam 中未 brand 的 ID。** `BashTask.id` 以及所有执行器/工具边界使用裸 `string`,尽管生成的值与默认 session id 具有相同的 `name-N` 形状。模型还通过 `task_id` 返回该值,因此混淆 task id 和 session id 既类型正确又可达。 -bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 和 `BashExecSpec.owner: string | undefined`(`packages/bash/bash/src/types.ts`)被文档描述为刻意*不透明*的隔离键,但在所有实际调用方中,该值就是所属 agent(智能体)的 `session.header.id`(`callerToken = (exec) => exec.agent?.session.header.id`,位于 `packages/bash/tool-bash/src/index.ts`),即一个穿着 `string` 外衣的 `SessionId`。它被用于访问控制比较(`owner !== callerToken(exec)`),因此一个不匹配但类型正确的 string 在此处就是一个跨会话隔离 bug,而当前类型系统无法捕获。这正是 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案所称的"bash owner-token alias hole"。 +bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 和 `BashExecSpec.owner: string | undefined`(`packages/bash/bash/src/types.ts`)被文档描述为刻意*不透明*的隔离键,但在所有实际调用方中,该值就是所属 agent(智能体)的 `session.header.id`(`callerToken = (exec) => exec.agent?.session.header.id`,位于 `packages/bash/tool-bash/src/index.ts`),即一个穿着 `string` 外衣的 `SessionId`。它被用于访问控制比较(`owner !== callerToken(exec)`),因此一个不匹配但类型正确的 string 在此处就是一个跨会话隔离 bug,而当前类型系统无法捕获。这正是 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案所称的以 `session.header.id` 作为 owner 的别名缺口("bash owner-token alias hole")。 **缺口 2:既有 brand 的侵蚀。** `CallId`、`SessionId` 和 `AgentId` 在注册表 map、公开查找参数、ACP 会话跟踪和持久化协调器中退化为裸 string。在查找边界丢弃 brand 会使其主要保护失效。 @@ -18,7 +18,7 @@ bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 纯类型变更。Brand 是零开销 cast;运行时行为、序列化、比较和协议格式(wire format)均不变。工作分三部分,全部遵循既有的"不是每个 string 都需要"策略。 -- **为 bash task id 加 brand。** 在 `packages/bash/bash/src/types.ts`(拥有该 id 的包)中添加 `BashTaskId = Branded<'BashTaskId'>` 及其同名工厂,从 `@deepseek-ai/dsh-brand` 导入 `Branded`,方式与 `SessionId`/`AgentId` 完全一致。brand 原语位于无依赖的 `dsh-brand` 工具包中,正是为了让 `dsh-bash` 仅依赖它就能为自己的 id 加 brand,而无需引入 `dsh-llm`(或 `dsh-session`)来获取 `Branded`。将其贯穿 `BashTask.id`、`BashExecutor` seam 方法(`get`/`ownerOf`/`readOutput`/`kill`)、`dsh-bash-local` 中的生成点(在创建时对计数器输出做一次 brand),以及 `dsh-tool-bash` 的校验/访问面(`validateTaskId` 返回 `BashTaskId`;`task_id` 在模型 string 到达的工具边界处被 brand)。 +- **为 bash task id 加 brand。** 在 `packages/bash/bash/src/types.ts`(*拥有*该 id 的包)中添加 `BashTaskId = Branded<'BashTaskId'>` 及其同名工厂,从 `@deepseek-ai/dsh-brand` 导入 `Branded`,方式与 `SessionId`/`AgentId` 完全一致。brand 原语位于无依赖的 `dsh-brand` 工具包中,正是为了让 `dsh-bash` 仅依赖它就能为自己的 id 加 brand,而无需引入 `dsh-llm`(或 `dsh-session`)来获取 `Branded`。将其贯穿 `BashTask.id`、`BashExecutor` seam 方法(`get`/`ownerOf`/`readOutput`/`kill`)、`dsh-bash-local` 中的生成点(在创建时对计数器输出做一次 brand),以及 `dsh-tool-bash` 的校验/访问面(`validateTaskId` 返回 `BashTaskId`;`task_id` 在模型 string 到达的工具边界处被 brand)。 - **铸造独立的 `OwnerToken` brand。** 在 `packages/bash/bash/src/types.ts` 中添加 `OwnerToken = Branded<'OwnerToken'>`;将 `BashExecRequest.owner` / `BashExecSpec.owner` / `BashExecutor.ownerOf` 的类型标注为 `OwnerToken | undefined`。`dsh-tool-bash` 消费方在边界处将 agent 的 `session.header.id`(一个 `SessionId`)cast 为 `OwnerToken`——这是两套词汇唯一交汇的地方。bash seam 从不导入 `dsh-session`。(理由见下一节。) @@ -46,7 +46,7 @@ export function OwnerToken(id: string): OwnerToken { ### 为什么不把 `owner` 类型标注为 `SessionId`? -执行器将 ownership 视为不透明的,不应依赖 session 模型。独立的 `OwnerToken` 保留了这一边界,同时防止裸 string 或 task id 被当作 owner 传入。`dsh-tool-bash` 拥有访问策略,由它执行从 `SessionId` 到 `OwnerToken` 的唯一转换。 +执行器将 ownership 视为不透明的,不应依赖 session 模型。独立的 `OwnerToken` 保留了这一边界,同时防止裸 string 或 task id 被当作 owner 传入。`dsh-tool-bash` 拥有访问策略,由它执行来自 `SessionId` 的唯一转换。 ## 不在范围内 / 可能的扩展 @@ -65,5 +65,5 @@ export function OwnerToken(id: string): OwnerToken { ## 后果 - **两个接口面的机械性改动。** 传播 brand 涉及 bash seam(接口 + 实现 + 消费方)以及 ACP session-id 接口和持久化协调器。改动面广但严重度低:遗漏的位置是编译错误而非静默 bug。变更可观察地为纯类型变更——无快照或 e2e 行为差异。它与 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案相邻(两者都触及 session-id / owner-token 边界);如果该提案落地,`OwnerToken` 出于上述解耦理由仍与统一后的 id 保持独立。 -- **Brand 不做校验。** Brand 是混淆防护,不是正确性证明:一个*错误的* session id 只要仍是合法的 string,就和以前一样能通过类型检查器。本 RFC 不关闭这个缺口(见"不在范围内")——它只阻止传入错误*类别*的 id 这种错误。 +- **Brand 不做校验。** Brand 是混淆防护,不是正确性证明:一个*错误的* session id 只要仍是合法的 string,就和以前一样能通过类型检查器。本 RFC 不关闭这个缺口(见"不在范围内")——它只阻止这类*类别*错误:传入错误*种类*的 id。 - **"在哪里停下"仍是判断题。** 为 `BashTaskId` 加 brand 但不为 `ToolName` 加,为 `OwnerToken` 加但不为 `ModelId` 加,是对哪些 string"可能被混淆"的品味判断。合理的评审者可能想要更多或更少;`brand.ts` 中的策略是裁决依据,本 RFC 倾向于面向模型或用于访问控制的 id。 diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml index d10d531a66..602102a219 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml @@ -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 -2026-06-20-extract-example-app-packages.md: 3a0a0f5d4b329afed72bd3c00bf880989e24fe54 -2026-06-20-extract-example-app-packages.zh.md: 8945f0c97727479c9e847711a96fc5d18118e09e +2026-06-20-extract-example-app-packages.md: b0dd1fe32b2389578d3f3bd3672435923eb1a5d1 +2026-06-20-extract-example-app-packages.zh.md: 9f47c98c9c54357a304490e3d4075fad6cea855a diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md index 3a0a0f5d4b..b0dd1fe32b 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.md @@ -1,9 +1,9 @@ # RFC: Extract example apps into packages -English | [中文](2026-06-20-extract-example-app-packages.zh.md) - Status: implemented +English | [中文](2026-06-20-extract-example-app-packages.zh.md) + ## Problem An example folder is supposed to be *thin* — the variable wiring of a demo, not the demo's machinery. Before this change it was thick. Each example carried a hand-rolled `start.ts` boot bootstrap, an infra preamble (`timer`, and — for the stdio demos — `logger` + `hmr`), nested includes of three shared YAML fragments (`base.yml` / `base-core.yml` / `acp-agent/acp-tail.yml`), and per-example `agent-loop`/persistence/system-prompt config. The actual app — the spine of services every agent needs — was spread across the leaf and those includes. diff --git a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md index 8945f0c977..9f47c98c9c 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md @@ -1,9 +1,9 @@ -# RFC:将示例应用提取为独立包 - -[English](2026-06-20-extract-example-app-packages.md) | 中文 +# RFC: 将示例应用提取为独立包 Status: implemented +[English](2026-06-20-extract-example-app-packages.md) | 中文 + ## 问题 示例目录本应是*精简的*——只包含演示的可变接线,而非演示的基础设施。在此次变更之前,它是臃肿的。每个示例都携带一份手写的 `start.ts` 启动引导、一段基础设施前导(`timer`,以及 stdio 演示所需的 `logger` + `hmr`(热模块替换))、三个共享 YAML 片段的嵌套引用(`base.yml` / `base-core.yml` / `acp-agent/acp-tail.yml`),还有各示例自身的 `agent-loop`/persistence/system-prompt 配置。真正的应用——每个 agent(智能体)都需要的服务主干——散落在叶子配置和那些 include 中。 diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml index 08ab9fc7f0..05549751eb 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml @@ -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 -2026-06-20-package-hierarchy.md: faf5815222b20699a32f1af489e625ba3e891230 -2026-06-20-package-hierarchy.zh.md: 118367f2655bffbd270f259df4ade37a70dcb2d7 +2026-06-20-package-hierarchy.md: a06e963d118d895cc55a0f5e378bbf12678f3491 +2026-06-20-package-hierarchy.zh.md: a136f15a4197645b06fa0a68564a9e0464af1cba diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md index faf5815222..a06e963d11 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.md @@ -1,9 +1,9 @@ # RFC: Reorganize packages into a modular hierarchy -English | [中文](2026-06-20-package-hierarchy.zh.md) - Status: implemented +English | [中文](2026-06-20-package-hierarchy.zh.md) + ## Problem `packages/` was flat: 18 packages all sat at `packages/<name>/`, so a package's location said nothing about whether it was core product API, a swappable capability seam, a provider adapter, a product integration, or example/test support. The package README carried a `FIXME(package-hierarchy)` and `scripts/publint-all.ts` a `TODO(package-inventory)` flagging exactly this. Core packages, provider integrations, capability seams, example UI support, and snapshot-only replay support all looked equally foundational. diff --git a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md index 118367f265..a136f15a41 100644 --- a/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-20-package-hierarchy.zh.md @@ -1,9 +1,9 @@ -# RFC:将包重组为模块化层级结构 - -[English](2026-06-20-package-hierarchy.md) | 中文 +# RFC: 将包重组为模块化层级结构 Status: implemented +[English](2026-06-20-package-hierarchy.md) | 中文 + ## 问题 `packages/` 原先是扁平的:18 个包(package)全部位于 `packages/<name>/`,从路径上完全看不出一个包属于核心产品 API、可替换的能力 seam、提供方适配器、产品集成,还是示例/测试支撑。包的 README 带着 `FIXME(package-hierarchy)`,`scripts/publint-all.ts` 带着 `TODO(package-inventory)`,标记的正是这个问题。核心包、提供方集成、能力 seam、示例 UI 支撑和仅用于快照的回放支撑看起来同样基础。 diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml index 4a0b9d6ebc..decd9cec05 100644 --- a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml @@ -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 -2026-06-21-mandatory-app-attribution-headers.md: 4fa773e089b3a4b682e42269a66d85aeaf5c18f6 -2026-06-21-mandatory-app-attribution-headers.zh.md: 42cc396b5719adb2a2d71e0e9cf0d3554c5533a5 +2026-06-21-mandatory-app-attribution-headers.md: 132c827b48693af85fde67cf9d2d71cc84e853c6 +2026-06-21-mandatory-app-attribution-headers.zh.md: 9bba6d912b0b9bb33174c1ebb51a84dfdb47af0f diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md index 4fa773e089..132c827b48 100644 --- a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md @@ -1,9 +1,9 @@ # RFC: Mandatory `User-Agent` attribution for provider requests -English | [中文](2026-06-21-mandatory-app-attribution-headers.zh.md) - Status: implemented +English | [中文](2026-06-21-mandatory-app-attribution-headers.zh.md) + ## Problem LLM provider requests should identify the product making them. That is useful for provider-side support, abuse investigation, compatibility debugging, and traffic analytics. Before this RFC the harness only partially did this: the hand-rolled DeepSeek adapter sent a hand-copied `User-Agent` constant (`packages/llm/llm-deepseek/src/adapter.ts`), while the pi-ai-backed twin sent no harness-owned headers at all (`packages/llm/llm-pi-ai/src/adapter.ts`). New adapters could therefore omit attribution silently, and a library-backed adapter could drift from the hand-rolled adapter even though [the twin-adapter RFC](2026-06-13-twin-llm-adapters.md) exists to keep the provider seam honest across both implementations. diff --git a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md index 42cc396b57..9bba6d912b 100644 --- a/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md @@ -1,9 +1,9 @@ -# RFC:对提供方请求强制携带 `User-Agent` 归属标识 - -[English](2026-06-21-mandatory-app-attribution-headers.md) | 中文 +# RFC: 对提供方请求强制携带 `User-Agent` 归属标识 Status: implemented +[English](2026-06-21-mandatory-app-attribution-headers.md) | 中文 + ## 问题 LLM(大语言模型)提供方请求应当标识发出请求的产品。这对提供方侧的技术支持、滥用调查、兼容性调试和流量分析都有价值。在本 RFC 之前,harness 只做了部分工作:手写的 DeepSeek 适配器发送了一个手动复制的 `User-Agent` 常量(`packages/llm/llm-deepseek/src/adapter.ts`),而基于 pi-ai 的孪生适配器则完全不发送 harness 自有的头部(`packages/llm/llm-pi-ai/src/adapter.ts`)。因此新适配器可以悄无声息地省略归属标识,而基于库的适配器也可能与手写适配器产生偏差——尽管[孪生适配器 RFC](2026-06-13-twin-llm-adapters.md) 的存在正是为了让两种实现在提供方 seam 上保持诚实。 @@ -15,9 +15,9 @@ LLM(大语言模型)提供方请求应当标识发出请求的产品。这 - **OpenRouter 的机制是提供方特有的。** 其当前文档说明应用归属通过 `HTTP-Referer`(必需)、`X-OpenRouter-Title` 和 `X-OpenRouter-Categories` 来追踪;`X-Title` 仅为向后兼容而接受。其 API 参考称这些头部为可选,并说它们使应用在 OpenRouter 上可被发现。这是一份具体的 OpenRouter 契约,而非 IETF 或 OpenAI 兼容 API 标准。 - **在 agent 工具生态中,`HTTP-Referer` 是一种 OpenRouter 感知的约定,而非通用 agent 约定。** 它足够常见,以至于 OpenRouter SDK 和示例直接暴露它,面向 OpenRouter 的框架通常需要一种方式来透传它。但 ACP(Agent Client Protocol)等 agent 协议在自己的 initialize 消息中协商名称、版本和能力,而模型提供方请求仍需 HTTP 层面的身份标识。因此「在 agent 世界中被接受」意味着「被 OpenRouter 集成所识别」,而非「可跨 agent 运行时或提供方移植」。 - **编程 agent 在 `User-Agent` 中标识产品和版本。** 公开实现在环境细节和提供方特有的附加头部上各有不同,但产品身份是共同契约;不存在通用的精确格式。 -- **标准化的通用客户端身份头部是 `User-Agent`。** RFC 9110 第 10.1.5 节将 `User-Agent` 定义为用户代理软件身份,说明它用于互操作性报告和分析,并说用户代理*应当*在每个请求中发送它(除非被配置为不发送)。这是唯一直接对应「哪个产品在发出此 HTTP 请求」的标准头部。 +- **标准化的通用客户端身份头部是 `User-Agent`。** RFC 9110 第 10.1.5 节将 `User-Agent` 定义为用户代理软件身份,说明它用于互操作性报告和分析,并说用户代理应当在每个请求中发送它(除非被配置为不发送)。这是唯一直接对应「哪个产品在发出此 HTTP 请求」的标准头部。 - **`Referer` 是标准的,但 OpenRouter 的 `HTTP-Referer` 不是标准字段。** RFC 9110 第 10.1.3 节将 `Referer` 定义为获取目标 URI 的来源 URI,并用大量篇幅讨论隐私限制。OpenRouter 则要求 `HTTP-Referer`,将其用作应用 URL 标识符。该名称和含义是 OpenRouter 特有的,尽管它形似标准 `Referer` 头部的 CGI 环境变量形式。 -- **`From` 是标准的,但不适合作为强制默认值。** RFC 9110 第 10.1.2 节将 `From` 定义为负责用户代理的人的电子邮件地址。机器人代理*应当*发送它以便服务器联系运营者,但非机器人代理出于隐私和安全策略考虑不应在未经用户显式配置的情况下发送。harness 可以后续支持运营者联系方式,但不得凭空捏造或全局强制要求。 +- **`From` 是标准的,但不适合作为强制默认值。** RFC 9110 第 10.1.2 节将 `From` 定义为负责用户代理的人的电子邮件地址。机器人代理应当发送它以便服务器联系运营者,但非机器人代理出于隐私和安全策略考虑不应在未经用户显式配置的情况下发送。harness 可以后续支持运营者联系方式,但不得凭空捏造或全局强制要求。 - **请求体中的 `user` 或 `metadata` 字段不是应用归属。** 部分模型 API 暴露稳定的终端用户标识符、请求元数据、标签或项目/账户头部。这些对滥用监控、内部计费、仪表盘或链路追踪有用,但它们要么标识的是终端用户而非产品,要么是提供方特有的 body schema,要么不保证能通过 OpenAI 兼容网关透传。它们不能替代静态的应用身份头部。 - **SDK 遥测头部标识的是 SDK,而非应用。** 官方和第三方 SDK 常发送库/版本头部。这些帮助 SDK 维护者调试其客户端,但除非应用显式提供产品归属层,否则它们不能标识 harness 作为应用。 - **pi-ai 有一流的头部钩子。** `@earendil-works/pi-ai` 的 `StreamOptions.headers` 将调用方头部最后合并(覆盖提供方默认值),因此基于库的适配器无需包装或上游改动即可满足与手写适配器相同的协议格式契约。mock 服务器测试套件对两个适配器都断言头部到达了线路。 diff --git a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml index 7a19846a47..b164c4c0f7 100644 --- a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml @@ -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 -2026-06-24-web-capability-seam.md: 3d0cdd89bb8366749ee0b3959244db1c57c0ccaa -2026-06-24-web-capability-seam.zh.md: 1cb1169f99b6eed22bcca650e0b3fe184f331307 +2026-06-24-web-capability-seam.md: fdb611be9efbf29717e41ffa2db86c55258ebe2e +2026-06-24-web-capability-seam.zh.md: f5db538f0565c4fc5667dcbec0791579246d238d diff --git a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md index 3d0cdd89bb..fdb611be9e 100644 --- a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md +++ b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.md @@ -1,9 +1,9 @@ # RFC: Web capability seam - stable tools over multiple providers -English | [中文](2026-06-24-web-capability-seam.zh.md) - Status: implemented +English | [中文](2026-06-24-web-capability-seam.zh.md) + ## Problem The harness needs model-facing web tools without binding the model contract to one vendor's API shape. Search is the immediate pressure point: supporting both Exa search and Perplexity search from the start — two deliberately different provider shapes (Exa returns a flat `results[]` of `{title, url, highlights, publishedDate}`; Perplexity returns a generated answer plus citations) — is what proves the normalized seam does not just mirror one vendor. Fetch is a separate capability: an anonymous public HTTP(S) fetch backend has transport, security, redirect, decoding, and size-limit concerns that are not the same as provider-backed search. diff --git a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md index 1cb1169f99..f5db538f05 100644 --- a/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-24-web-capability-seam.zh.md @@ -1,4 +1,4 @@ -# RFC:Web 能力 seam——稳定的工具覆盖多个提供方 +# RFC: Web 能力 seam——稳定的工具覆盖多个提供方 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml index 06f5fb57d8..609b27aa6a 100644 --- a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml @@ -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 -2026-06-26-file-context-as-event-gate.md: 6e78e2df5f7969b5ed9b74c0b597e2fcacbe8e82 -2026-06-26-file-context-as-event-gate.zh.md: d69ccdbcea4b14dbd0291cf69af0bf7d5f3fadfc +2026-06-26-file-context-as-event-gate.md: ac9a8bcbc5bfda2b35cae4993497273608abf35b +2026-06-26-file-context-as-event-gate.zh.md: eda637f9adf8346779c70d59575863bf7e1162c9 diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md index 6e78e2df5f..ac9a8bcbc5 100644 --- a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.md @@ -1,9 +1,9 @@ # RFC: Make `dsh-fs-policy` an event-gate plugin, not a method interface -English | [中文](2026-06-26-file-context-as-event-gate.zh.md) - Status: implemented +English | [中文](2026-06-26-file-context-as-event-gate.zh.md) + ## Problem [The split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) put `ctx.fileContext` between the model-facing tools and the `ctx.fs` provider: `dsh-tool-fs` injects `fileContext` and routes every `read`/`write`/`edit` through its methods. That makes `fileContext` **in-path and mandatory**. The tool cannot reach `ctx.fs` without it, the policy layer owns the fs I/O and the read windowing, and a deployment that does not want observed-state policy cannot simply drop the package — `dsh-tool-fs` would fail to resolve `ctx.fileContext`. diff --git a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md index d69ccdbcea..eda637f9ad 100644 --- a/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md @@ -1,4 +1,4 @@ -# RFC:将 `dsh-fs-policy` 改为事件门控插件,而非方法接口 +# RFC: 将 `dsh-fs-policy` 改为事件门控插件,而非方法接口 Status: implemented @@ -72,7 +72,7 @@ editText(target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion **两个 `fs/*` 决策事件是单槽、先到先得的 waterfall。** `dsh-fs-policy` 不调用 `next()` 直接返回,因此在默认部署中它占据该槽位;更早注册或使用 `prepend` 的监听器会替代该策略。权限、审计和沙箱关注点仍留在可组合的 `tools/execute` waterfall 上。 -actor 在 `dsh-fs` 中类型为 `object`——一个纯粹的不透明载体,提供方 seam 从不读取或收窄它。owner 的推导(`actor.agent?.session`)和 `{ agent?: { session? } }` 结构形状完全留在 `dsh-fs-policy` 内部,由其在监听器中将 `object` actor 收窄为该形状。`dsh-fs` 拥有事件名和 fs 词汇;它**不**拥有策略层的运行时 owner 结构。 +actor 在 `dsh-fs` 中类型为 `object`——一个纯粹的不透明载体,提供方 seam 从不读取或收窄它。owner 的推导(`actor.agent?.session`)和 `{ agent?: { session? } }` 结构形状完全留在 `dsh-fs-policy` 内部,由其在监听器中将 `object` actor 收窄为该形状。`dsh-fs` 拥有事件名和 fs 词汇;它不拥有策略层的运行时 owner 结构。 ```ts import type { FsTarget, FsVersion, FsWriteIntent } from '@deepseek-ai/dsh-fs' @@ -154,7 +154,7 @@ interface Events { ## 验证 -测试固定了两条路径:无 `dsh-fs-policy` 时,根工具插件对 `dsh-fs-local` 启动,read、create、overwrite 和未读 edit 均成功;有策略时,未读 edit 返回 `FS_NOT_OBSERVED`,未读 overwrite 被 `createIfAbsent` 门控。策略决定后,后注册的 intent 监听器不会被触达。陈旧编辑通过提供方 CAS 失败,而策略不执行 `stat`;工具预算在两条路径上保持 read 一次 `stat`、write 或 edit 零次 `stat`。面向模型的 schema 逐字节不变,因此快照不变。 +测试固定了两条路径:无 `dsh-fs-policy` 时,根工具插件对 `dsh-fs-local` 启动,read、create、overwrite 和未读 edit 均成功;有策略时,未读 edit 返回 `FS_NOT_OBSERVED`,未读 overwrite 被 `createIfAbsent` 门控。策略决定后,后注册的 intent 监听器不会被触达。陈旧编辑通过提供方 CAS 失败,而策略不执行 `stat`;工具预算在两条路径上保持 read 一次 `stat`,write 或 edit 均为零次。面向模型的 schema 逐字节不变,因此快照不变。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml index 3bb8d3e607..d4d7cb2482 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml @@ -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 -2026-06-30-bash-stdin-env-trusted-plugin-surface.md: 72aae03361cbc088cf64f3548a43ac6253eb21eb -2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md: f661199048b7eaa359f792e96ac52baf8cd61fdf +2026-06-30-bash-stdin-env-trusted-plugin-surface.md: 712c17532bc1e6b95479aec5b544bc7e296952ec +2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md: db50f08dae30aa0c43e741a4f27f948f712954e0 diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md index 72aae03361..712c17532b 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md @@ -1,9 +1,9 @@ # RFC: stdin + extra env on the bash seam -English | [中文](2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md) - Status: implemented +English | [中文](2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md) + ## Problem The hooks subsystem runs external hook commands the way Claude Code and Codex do: a hook is a shell command that receives its event payload as **JSON on stdin** and reads context from a handful of **environment variables** (`CLAUDE_PROJECT_DIR`, `CLAUDE_PLUGIN_ROOT`, `PLUGIN_ROOT`, …). The harness already has a perfectly good command runner behind the `ctx.bash` capability seam ([dsh-bash](../../../../packages/bash/bash) → [dsh-bash-local](../../../../packages/bash/bash-local)), with process-group kills, output truncation/spill, and a credential scrub. Reusing it for hook execution means a hook bridge does not re-implement subprocess plumbing — but the seam had no way to write stdin or set extra env. This RFC adds those two inputs. diff --git a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md index f661199048..db50f08dae 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:在 bash seam 上支持 stdin 与额外 env +# RFC: 在 bash seam 上支持 stdin 与额外 env Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml index 2416919ab7..1b064ea80a 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml @@ -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 -2026-06-30-event-domain-semantics.md: e05c238c52052454d3e01e82767cddd9af316a9d -2026-06-30-event-domain-semantics.zh.md: 9048679ec7a7992852cce76bf43269f5499da792 +2026-06-30-event-domain-semantics.md: a9d33a7bfb549e1ec2102c23af78f91d9ae4b904 +2026-06-30-event-domain-semantics.zh.md: dc7390e3d2e1cda3469fa77389d0d6ad39b7a713 diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md index e05c238c52..a9d33a7bfb 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.md @@ -1,9 +1,9 @@ # RFC: Event-domain semantics — session is the fact log, agent is the live surface -English | [中文](2026-06-30-event-domain-semantics.zh.md) - Status: implemented +English | [中文](2026-06-30-event-domain-semantics.zh.md) + ## Problem The harness extends the agent loop through a Cordis event taxonomy (see [the microkernel event-taxonomy RFC](2026-06-11-microkernel-event-taxonomy.md)). As that taxonomy grew, the line between the three event domains blurred: diff --git a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md index 9048679ec7..dc7390e3d2 100644 --- a/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md +++ b/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md @@ -1,4 +1,4 @@ -# RFC:事件域语义——session 是事实日志,agent 是运行时表面 +# RFC: 事件域语义——session 是事实日志,agent 是运行时表面 Status: implemented @@ -12,7 +12,7 @@ harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环) - `agent/*` 承载运行时实时信号,向插件传递 `Agent` 句柄。 - `tools/*` 承载工具注册表与执行 seam。 -两个问题促使我们固定语义。第一,若干轮次/步骤边界同时作为持久的 `SessionEvent`(`turn/start`、`turn/end`、`step/start`、`step/end`)**和**镜像的 `agent/*` emit(`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`)存在。消费方对同一事实有两个真源,每次生命周期变更都必须同时更新两处。第二,即将到来的 Hooks 子系统需要**一个**连贯且有文档的订阅表面——插件作者(以及基于其上构建的 Claude Code / Codex 钩子桥接)必须在不阅读循环代码的情况下知道应该监听 session 事件还是 agent 事件,以及原因。 +两个问题促使我们固定语义。第一,若干轮次/步骤边界同时作为持久的 `SessionEvent`(`turn/start`、`turn/end`、`step/start`、`step/end`)和镜像的 `agent/*` emit(`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`)存在。消费方对同一事实有两个真源,每次生命周期变更都必须同时更新两处。第二,即将到来的 Hooks 子系统需要一个连贯且有文档的订阅表面——插件作者(以及基于其上构建的 Claude Code / Codex 钩子桥接)必须在不阅读循环代码的情况下知道应该监听 session 事件还是 agent 事件,以及原因。 这套词汇是拦截决策、持久的 `hook/*` 日志,以及 Claude Code 和 Codex 桥接的基础。 @@ -21,7 +21,7 @@ harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环) **三个域,各司其职,以一条边界规则统一。** - **`session/*`——持久的、可回放的事实日志。** 拥有 `SessionEventMap`;每条记录仅含 JSON(无活对象)。每次追加触发一次 `session/event` emit,加上 `session/flush` 并行持久性检查点。它同时也是实时 transcript(文本记录)源:想渲染或响应已发生事件的消费方在此订阅,因此实时渲染与 `session/load` 回放共享同一路径。 -- **`agent/*`——运行时实时表面。** 始终携带活的 `Agent`。两种形态:拦截 waterfall(瀑布式事件)(`agent/request`、`agent/step-result`、`agent/turn-continuation`)可变更或否决;瞬态 emit(`agent/status`、`agent/error`、`agent/created`/`agent/disposed`、`agent/queued`)在持有 `Agent` 的情况下通知。轮次和步骤**边界**不在此处——它们是持久的 session 事件,从 `session/event` 读取;token 流(`assistant/chunk`)和中途 steering(中途引导)(`steering/message`)同理。 +- **`agent/*`——运行时实时表面。** 始终携带活的 `Agent`。两种形态:拦截 waterfall(瀑布式事件)(`agent/request`、`agent/step-result`、`agent/turn-continuation`)可变更或否决;瞬态 emit(`agent/status`、`agent/error`、`agent/created`/`agent/disposed`、`agent/queued`)在持有 `Agent` 的情况下通知。轮次和步骤边界不在此处——它们是持久的 session 事件,从 `session/event` 读取;token 流(`assistant/chunk`)和中途 steering(中途引导)(`steering/message`)同理。 - **`tools/*`——工具注册表与执行 seam。** **边界规则:** 持久的、可回放的事实是 `SessionEvent`;实时拦截或瞬态/活对象信号是 `agent`/`tools` Cordis 事件。轮次或步骤边界是持久事实,因此存在于 session 日志中并从 `session/event` 源读取——不会被镜像为 `agent/*` emit。 @@ -31,7 +31,7 @@ harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环) ## 后果 - 循环不再 emit 任何边界镜像;`closeStep` 仅追加 `step/end`,`closeTurn` 仅追加 `turn/end`。`Session.append` 负责 post-commit observer 隔离,因此抛出异常的边界 observer 无法改变轮次结果或饿死后续消费方;接受或内部校验失败仍会在边界进入日志之前逃逸。 -- 之前通过已移除 emit 观察边界的测试,现在观察持久的 `turn/start`/`turn/end`/`step/start`/`step/end` session 事件——它们固定的行为(边界顺序、步骤计数)不变;只是读取的源移到了规范源。那些测试「抛出异常的 turn 边界 emit 监听器」的用例被删除,因为该代码路径不再存在(没有 emit 可供抛出)。按照 [AGENTS.md「测试记录行为,而非黄金真相」](../../../../AGENTS.md),行为与其测试一同迁移(或一同消亡)。 +- 之前通过已移除 emit 观察边界的测试,现在观察持久的 `turn/start`/`turn/end`/`step/start`/`step/end` session 事件——它们固定的行为(边界顺序、步骤计数)不变;只是读取的源移到了规范源。那些测试*抛出异常的 turn 边界 emit 监听器*的用例被删除,因为该代码路径不再存在(没有 emit 可供抛出)。按照 [AGENTS.md「测试记录行为,而非黄金真相」](../../../../AGENTS.md),行为与其测试一同迁移(或一同消亡)。 - 循环仅在 `append('step/start')` 返回后才标记步骤已打开(`stepOpen = true`)。内部分发校验在日志推入之前运行,可能在不打开步骤的情况下拒绝;post-commit `session/event` observer 的失败被隔离在 `Session.append` 内部。因此该标记精确表示已提交的、欠一个后续 `step/end` 的边界。 - 完整实现见[简化 RFC「停止将持久边界镜像为 agent 事件」](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md):全部四个边界镜像被移除,所有消费方从 `session/event` 读取边界。`agent/steering`(不是边界镜像)不在该 RFC 范围内,由其后续 RFC [移除 `agent/steering` 镜像 emit](../simplification/2026-07-04-remove-agent-steering-mirror.md) 单独移除——它镜像的是持久的 `steering/message`。 - Cordis 事件目录(`docs/cordis-catalog/events.md`)重新生成以移除镜像事件。 diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml index 3cff8c7aca..1af8dd8fe3 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml @@ -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 -2026-07-02-fs-per-session-cwd.md: 00643955d918dff87241f4b240bb7e6774d21a0b -2026-07-02-fs-per-session-cwd.zh.md: 73176cde3747a2eb8c03aadbf3f419bf27173d70 +2026-07-02-fs-per-session-cwd.md: 2513294d6bc991ee39155bbf20869829cca1a188 +2026-07-02-fs-per-session-cwd.zh.md: 2c3957113642fe2bf7b3a4f2b6186246b32aff3f diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md index 00643955d9..2513294d6b 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md @@ -1,9 +1,9 @@ # RFC: Resolve filesystem paths against the caller's session cwd -English | [中文](2026-07-02-fs-per-session-cwd.zh.md) - Status: implemented +English | [中文](2026-07-02-fs-per-session-cwd.zh.md) + ## Problem The ACP bridge gives every session its own workspace: `session/new` records the editor's project directory as `SessionHeader.cwd`, and `dsh-tool-bash` defaults each bash call's `workdir` to the calling agent's `session.header.cwd` (see [the per-session cwd RFC work in `packages/ui/acp`](../../../../packages/ui/acp) and `resolveWorkdir` in `dsh-tool-bash`). So a bash command in session A runs in A's project, and in session B runs in B's — one server process, N workspaces. diff --git a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md index 73176cde37..2c39571136 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md @@ -1,9 +1,9 @@ -# RFC:相对文件系统路径按调用方的会话 cwd 解析 - -[English](2026-07-02-fs-per-session-cwd.md) | 中文 +# RFC: 相对文件系统路径按调用方的会话 cwd 解析 Status: implemented +[English](2026-07-02-fs-per-session-cwd.md) | 中文 + ## 问题 ACP(Agent Client Protocol)桥接层为每个会话提供独立的工作区:`session/new` 将编辑器的项目目录记录为 `SessionHeader.cwd`,`dsh-tool-bash` 将每次 bash 调用的 `workdir` 默认设为调用方 agent(智能体)的 `session.header.cwd`(见 [`packages/ui/acp`](../../../../packages/ui/acp) 中的 per-session cwd RFC 工作与 `dsh-tool-bash` 中的 `resolveWorkdir`)。因此会话 A 中的 bash 命令在 A 的项目目录执行,会话 B 中的在 B 的项目目录执行——一个服务器进程,N 个工作区。 @@ -24,7 +24,7 @@ ACP(Agent Client Protocol)桥接层为每个会话提供独立的工作区 提供方 seam 不得依赖 `dsh-agent`/`dsh-session`——它是一个文本存储后端,沙箱或远程实现同样满足该接口,而这些实现没有「agent 会话」的概念。工具已经接收了 `ToolExecution`(`exec`),其中携带 agent,因此工具是将 `exec → cwd` 投影并向提供方传递一个纯字符串的正确位置。这遵循「包(package)边界处显式优于隐式」的约定:基准目录作为显式参数传入,提供方据此行动,而非让提供方越界去读取它不应知晓的会话。这也与 `dsh-tool-bash` 一一对应,使两个面向模型的文件操作接口以相同方式解析路径。 -默认值只存在于**一个**地方——提供方的 `config.cwd`。`sessionCwd` 在没有会话时返回 `undefined` 而非 `process.cwd()`,因此工具永远不会自行制造一个提供方本应自行选择的基准目录。 +默认值只存在于一个地方——提供方的 `config.cwd`。`sessionCwd` 在没有会话时返回 `undefined` 而非 `process.cwd()`,因此工具永远不会自行制造一个提供方本应自行选择的基准目录。 ## 后果 diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml index 0401c48e08..d05c13ff78 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml @@ -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 -2026-07-02-result-time-applied-hunk-diffs.md: 81ab8b9827ddaec39d63e2a3f8fbb864085a9ac9 -2026-07-02-result-time-applied-hunk-diffs.zh.md: 2914c4242c4246ede8588967ed36b3f6c725c607 +2026-07-02-result-time-applied-hunk-diffs.md: fd02951f21319be2933bf3ffaddeb96bc2a6819c +2026-07-02-result-time-applied-hunk-diffs.zh.md: 4ed9a29bb023343cab28b8114453d17408bc429a diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md index 81ab8b9827..fd02951f21 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md @@ -1,9 +1,9 @@ # RFC: Result-time applied-hunk diffs for file mutations -English | [中文](2026-07-02-result-time-applied-hunk-diffs.zh.md) - Status: implemented +English | [中文](2026-07-02-result-time-applied-hunk-diffs.zh.md) + ## Problem The [tagged render-intent union](2026-07-02-tool-render-intent-union.md) gave `dsh-tool-fs` write/edit a `card:'diff'` at CALL time, derived purely from the tool's args: write ⇒ `{oldText:null, newText:content}` (the whole new file), edit ⇒ `{oldText:old_string, newText:new_string}` (the bare replaced snippet). An editor renders that as an inline diff, but it is a **context-free** diff — the bare `old_string`→`new_string` with no surrounding lines, and a `replace_all` that touched five scattered sites still renders as one snippet pair. diff --git a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md index 2914c4242c..4ed9a29bb0 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md @@ -1,14 +1,14 @@ -# RFC:结果时刻的 applied-hunk diff 用于文件变更 - -[English](2026-07-02-result-time-applied-hunk-diffs.md) | 中文 +# RFC: 结果时刻的 applied-hunk diff 用于文件变更 Status: implemented +[English](2026-07-02-result-time-applied-hunk-diffs.md) | 中文 + ## 问题 [tagged render-intent union](2026-07-02-tool-render-intent-union.md) 为 `dsh-tool-fs` 的 write/edit 在调用时刻提供了 `card:'diff'`,纯粹从工具参数推导:write ⇒ `{oldText:null, newText:content}`(整个新文件),edit ⇒ `{oldText:old_string, newText:new_string}`(裸替换片段)。编辑器将其渲染为行内 diff,但这是一个**无上下文**的 diff:裸的 `old_string`→`new_string` 没有周围行,而一次触及五个分散位置的 `replace_all` 仍然渲染为一对片段。 -在对接 `claude-agent-acp` 自身的 ACP(Agent Client Protocol) bridge 时可以看到完整编辑器 diff 的样子:变更应用后,它发出第二个 `tool_call_update`,其 diff 是**带 ±3 行上下文的 applied hunk**(`replace_all` 的每个变更位置各一个 hunk),由工具的 `structuredPatch` 重建。这个结果时刻的 hunk 正是让 Zed 在文件中**原位**显示变更(而非浮动片段)的关键。我们的工具止步于调用时刻的片段;完成后的结果只携带纯文本 "updated successfully",没有 diff。 +在对接 `claude-agent-acp` 自身的 ACP(Agent Client Protocol) bridge 时可以看到完整编辑器 diff 的样子:变更应用后,它发出第二个 `tool_call_update`,其 diff 是**带 ±3 行上下文的 applied hunk**(`replace_all` 的每个变更位置各一个 hunk),由工具的 `structuredPatch` 重建。这个结果时刻的 hunk 正是让 Zed 在文件中*原位*显示变更(而非浮动片段)的关键。我们的工具止步于调用时刻的片段;完成后的结果只携带纯文本 "updated successfully",没有 diff。 障碍在于一个 seam 边界:`presentResult(args, result)` 是 **`args` + 面向模型的 `result`(`{content, isError}`)的纯函数**——它在实时流式输出和会话日志回放中都会运行,因此必须具备回放确定性且不能做 I/O。它看不到文件的前后内容,而 `FsEditOutcome`/`FsWriteOutcome` 只携带替换计数和版本号,没有文本。因此无法计算——甚至无法携带——applied hunk 给 presenter。 @@ -37,7 +37,7 @@ type ToolExecuteReturn = ContentBlock[] | { content: ContentBlock[]; meta?: unkn ### 3. Bridge 渲染 `diff` 结果卡片 -`ToolResultView` 新增 `DiffResultView { card:'diff'; title?; diffs: FileDiff[] }`;bridge 结果侧的 `switch (view.card)` 增加 `diff` 分支,发出 `{type:'diff'}` 的 `ToolCallContent` 块(与调用侧分支对称)。ACP 的 `tool_call_update.content` 在编辑器中**替换**调用时的内容,因此结果 diff **取代**调用时刻的片段(并防止面向模型的结果文本覆盖它)——两次更新序列(先调用片段,再结果 diff)与 `claude-agent-acp` 完全一致。 +`ToolResultView` 新增 `DiffResultView { card:'diff'; title?; diffs: FileDiff[] }`;bridge 结果侧的 `switch (view.card)` 增加 `diff` 分支,发出 `{type:'diff'}` 的 `ToolCallContent` 块(与调用侧分支对称)。ACP 的 `tool_call_update.content` 在编辑器中替换调用时的内容,因此结果 diff **取代**调用时刻的片段(并防止面向模型的结果文本覆盖它)——两次更新序列(先调用片段,再结果 diff)与 `claude-agent-acp` 完全一致。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml index 8c2f7faf6d..607ff343ce 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml @@ -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 -2026-07-02-tool-render-intent-union.md: 8256f09f9c297658627d0c3d9e99ee1c5424b254 -2026-07-02-tool-render-intent-union.zh.md: 35bd775545c9131a20da9e7f7424506e4554eb4b +2026-07-02-tool-render-intent-union.md: 6b828c32fb79f43c0f974f2c9f032e11430de5b4 +2026-07-02-tool-render-intent-union.zh.md: 8c44178ca3e8986579e7ed696aec2f900705e9ad diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md index 8256f09f9c..6b828c32fb 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md @@ -1,9 +1,9 @@ # RFC: Tagged render-intent union for tool-call presentation -English | [中文](2026-07-02-tool-render-intent-union.zh.md) - Status: implemented +English | [中文](2026-07-02-tool-render-intent-union.zh.md) + ## Problem A tool declares how its calls render in a UI (an editor's tool-call card) through two callbacks, `presentCall`/`presentResult` on `ToolDefinition`, returning `ToolCallPresentation` / `ToolResultPresentation` with an optional `ToolTerminal` sub-shape. These grew incrementally into a **bag of optional fields**: `title`, `kind`, `rawInput`, `content`, `locations`, `terminal` on the call; `title`, `content`, `terminal` on the result; `cwd`/`output`/`exitCode`/`signal` on `ToolTerminal`. The split of responsibility is muddy: diff --git a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md index 35bd775545..8c44178ca3 100644 --- a/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md @@ -1,4 +1,4 @@ -# RFC:用于工具调用展示的带标签 render-intent 联合类型 +# RFC: 用于工具调用展示的带标签 render-intent 联合类型 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml index f589fd9ddf..b28a70da27 100644 --- a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml @@ -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 -2026-07-03-filesystem-directory-listing-seam.md: bb8d9c4deda18b320b85d548bbd5bcb32f1c1d72 -2026-07-03-filesystem-directory-listing-seam.zh.md: ccc5ca67f58537134da5c5484b3d527ba84fe8d3 +2026-07-03-filesystem-directory-listing-seam.md: 8920e54993eb1402bd310d6ce78fb9866de628c9 +2026-07-03-filesystem-directory-listing-seam.zh.md: 5ca9b195d4bf5c1450c60451dd469a19dd54166f diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md index bb8d9c4ded..8920e54993 100644 --- a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.md @@ -1,9 +1,9 @@ # RFC: Add direct directory listing to the filesystem seam -English | [中文](2026-07-03-filesystem-directory-listing-seam.zh.md) - Status: implemented +English | [中文](2026-07-03-filesystem-directory-listing-seam.zh.md) + ## Problem `@deepseek-ai/dsh-fs` is the provider seam for filesystem access, with local and future non-local backends behind the same `ctx.fs` contract. Before this change it could resolve paths, stat targets, read text, stream text, write text, and edit text. That was enough for model-facing file tools, but not for non-model-facing consumers that need to enumerate directories without importing `node:fs`. diff --git a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md index ccc5ca67f5..5ca9b195d4 100644 --- a/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md @@ -1,9 +1,9 @@ -# RFC:为文件系统 seam 添加直接目录列举能力 - -[English](2026-07-03-filesystem-directory-listing-seam.md) | 中文 +# RFC: 为文件系统 seam 添加直接目录列举能力 Status: implemented +[English](2026-07-03-filesystem-directory-listing-seam.md) | 中文 + ## 问题 `@deepseek-ai/dsh-fs` 是文件系统访问的提供方 seam,本地后端与未来的非本地后端共享同一个 `ctx.fs` 契约。在本次变更之前,它能解析路径、stat 目标、读取文本、流式读取文本、写入文本和编辑文本。这对面向模型的文件工具已经足够,但对于需要枚举目录而又不想直接导入 `node:fs` 的非模型侧消费方来说还不够。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml index 5c821e12fa..1ea6573424 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml @@ -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 -2026-07-05-prompt-variables-and-tool-guidance-ownership.md: fce9d555c8843b99fdbfa7b652b46d0b88053935 -2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 93a639a2ddac33cb1ceac57101cb6185fe6034ad +2026-07-05-prompt-variables-and-tool-guidance-ownership.md: 1819a730b214270304a8feb103a7f26e9c8d6e6e +2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 4211241b1b24fd461f5341bf8d777007a7a36482 diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md index fce9d555c8..1819a730b2 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md @@ -1,9 +1,9 @@ # RFC: Prompt variables and tool-guidance ownership -English | [中文](2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md) - Status: implemented +English | [中文](2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md) + ## Problem The assembled system prompt had four defects, all of one family: facts the harness already knows were restated by hand somewhere else, and drifted. diff --git a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md index 93a639a2dd..4211241b1b 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md @@ -1,9 +1,9 @@ -# RFC:Prompt 变量与工具指导归属 - -[English](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) | 中文 +# RFC: Prompt 变量与工具指导归属 Status: implemented +[English](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) | 中文 + ## 问题 组装后的系统提示词存在四个缺陷,同属一类:harness 已知的事实在别处被手工重述,然后漂移。 @@ -32,7 +32,7 @@ Status: implemented ### Persona 作为 order-0 section -`dsh-system-prompt` 拥有 order 为 `-100` 的 `harness:identity` 和 order 为 `0` 的配置 `deployment:persona`,因此两者在循环被替换时仍然存活。prompt 渲染只有一条路径 `renderPrompt(assembly)`,`agent/pre-step` 因此测量的正是用于压缩(compaction)的确切 prompt。agent 作用域的 `deployment:persona` 遮蔽全局默认值,允许 subagent provider 在发布前安装 persona。约定的 order 区间为:identity `-100`、persona `0`、工具指导 `100–199`。 +`dsh-system-prompt` 拥有 order 为 `-100` 的 `harness:identity` 和 order 为 0 的配置 `deployment:persona`,因此两者在循环被替换时仍然存活。prompt 渲染只有一条路径 `renderPrompt(assembly)`,`agent/pre-step` 因此测量的正是用于压缩(compaction)的确切 prompt。agent 作用域的 `deployment:persona` 遮蔽全局默认值,允许 subagent provider 在发布前安装 persona。约定的 order 区间为:identity `-100`、persona `0`、工具指导 `100–199`。 ### 工具指导归属 @@ -66,7 +66,7 @@ Status: implemented ## 后果 - 组装后的 prompt 中每个事实现在恰好有一个归属方,leaf YAML 中手工维护的工具行文已消除:加载或卸载一个工具插件不再需要编辑任何部署的 persona。 -- `{{model}}` 在组装时反映 `AgentOptions.model`。如果一个插件在 `agent/request` waterfall 中切换模型,prompt 对该步骤的声明就会过时;如果一个插件在那里**提供**模型(options.model 未设置——循环文档中记载的回退路径),变量在渲染时无值,包含 `{{model}}` 的 persona 会在 waterfall 运行前失败。两者的补救方式相同,就是归属规则本身:拥有延迟绑定模型事实的插件在 `system-prompt/assemble` waterfall 上提前声明它(`assembly.variables['model'] = …`)——一个归属方,两处声明;一个循环测试端到端固定了 supply 路径。已接受。 +- `{{model}}` 在组装时反映 `AgentOptions.model`。如果一个插件在 `agent/request` waterfall 中切换模型,prompt 对该步骤的声明就会过时;如果一个插件在那里提供模型(options.model 未设置——循环文档中记载的回退路径),变量在渲染时无值,包含 `{{model}}` 的 persona 会在 waterfall 运行前失败。两者的补救方式相同,就是归属规则本身:拥有延迟绑定模型事实的插件在 `system-prompt/assemble` waterfall 上提前声明它(`assembly.variables['model'] = …`)——一个归属方,两处声明;一个循环测试端到端固定了 supply 路径。已接受。 - 当一个已绑定的 provider 不存在时(尚未激活、已卸载、HMR(热模块替换)重载中),subagent 工具不存在,该窗口内的模型请求中不会包含它。这是诚实的状态——替代方案是注册一个 description 或执行都不可信的工具。 -- 严格性意味着 persona 可能在渲染时导致轮次失败(例如在无 cwd 的会话上使用 `{{cwd}}`)。失败是受控的——该轮次以 `error` 结束,循环存活——且这是一个我们**希望**大声暴露的撰写错误。 +- 严格性意味着 persona 可能在渲染时导致轮次失败(例如在无 cwd 的会话上使用 `{{cwd}}`)。失败是受控的——该轮次以 `error` 结束,循环存活——且这是一个我们希望大声暴露的撰写错误。 - 目前没有在 prompt 行文中转义字面 `{{name}}` 的语法;如果真实 prompt 确实需要,再行添加。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml index 2ef938def7..11d51bfef5 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml @@ -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 -2026-07-05-reconstructable-requests.md: 0978cd8760c6a0420be1bf0a3baf6b50c1a04a13 -2026-07-05-reconstructable-requests.zh.md: a4864c9e795ccc0da2cbbf0ca4d17a90c029858c +2026-07-05-reconstructable-requests.md: b07dbceaf6f3ecad64a464df6b97ee2a32284768 +2026-07-05-reconstructable-requests.zh.md: cb57d0915547b8a38b6afde7e36bec36c86e19c3 diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md index 0978cd8760..b07dbceaf6 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md @@ -1,9 +1,9 @@ # RFC: Every LLM request is reconstructable from the session log -English | [中文](2026-07-05-reconstructable-requests.zh.md) - Status: implemented +English | [中文](2026-07-05-reconstructable-requests.zh.md) + ## Problem The request pipeline did not guarantee prefix stability for provider caching, and the session log could not reconstruct what the model saw. It omitted model, system prompt, and tool schemas while allowing per-call request rewrites. Cache behavior and replay equivalence therefore depended on whichever plugins happened to be loaded. diff --git a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md index a4864c9e79..cb57d09155 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.zh.md @@ -1,4 +1,4 @@ -# RFC:每个 LLM(大语言模型)请求都可从会话日志重建 +# RFC: 每个 LLM(大语言模型)请求都可从会话日志重建 Status: implemented @@ -46,7 +46,7 @@ Status: implemented ## 后果 - 一个日志无法解释的请求不可能被意外构造——无论是循环还是监听器;变异已构建的请求会抛异常;每个 header 变更都是持久的、可 diff 的日志事件。 -- 在建议性通道之间做选择是变更频率的决策,而本设计使稳定的那个在结构上成为默认:`agent/session-prefix` 的贡献在每个循环实例中只组合一次并逐字复用,因此以零边际成本扩展可缓存前缀,且**不可能**在会话中途击穿提供方缓存;会话中途变化的内容通过仅追加的历史通道流入——`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——每条都是持久的 `context/message`,付出一次代价后即被前缀缓存,代价是在历史和日志中累积。将会话冻结的开场内容路由到前缀,将变更通知路由到历史通道;逐步骤的仅限请求尾部槽位被有意放弃(无消费方,且持久追加覆盖了当前所有更新模式)。 +- 在建议性通道之间做选择是变更频率的决策,而本设计使稳定的那个在结构上成为默认:`agent/session-prefix` 的贡献在每个循环实例中只组合一次并逐字复用,因此以零边际成本扩展可缓存前缀,且不可能在会话中途击穿提供方缓存;会话中途变化的内容通过仅追加的历史通道流入——`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——每条都是持久的 `context/message`,付出一次代价后即被前缀缓存,代价是在历史和日志中累积。将会话冻结的开场内容路由到前缀,将变更通知路由到历史通道;逐步骤的仅限请求尾部槽位被有意放弃(无消费方,且持久追加覆盖了当前所有更新模式)。 - 在提供方处仍需全价计算的内容是固有的且已记录的:压缩(其 `compact/*` 事件和 replace 节点)、真正的 prompt/工具变更(`request/header-delta`)、配置切换(同上)、带漂移的进程边界(`'resume'` 快照与前一快照不同)。提供方自身的 reasoning-content 排除由服务端管理。 - `step/start` 监听器行为变更(见上文)是对插件唯一可观察的语义变更;`agent/pre-step` 是当前请求的 seam。 - 工具结果裁剪(计划中)无需新机制:一个已记录的单节点 surface replace(`start === end`),携带同一 `callId` 下裁剪后的 `tool/result`——属压缩家族,回放正确,缓存击穿由相同的压力逻辑批量处理。 diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml index 74fbfda121..1de1e4c13d 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml @@ -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 -2026-07-05-subagent-provider-lifecycle-events.md: 6d711f2a6d8496a8a229ec63d86dd89816efb6f8 -2026-07-05-subagent-provider-lifecycle-events.zh.md: f412b031644c14ca70caae3efc72eefa9ce2c2ac +2026-07-05-subagent-provider-lifecycle-events.md: b5300706ce4c53a6d348a86803d221a4dcca9632 +2026-07-05-subagent-provider-lifecycle-events.zh.md: 8694612e5e3d4d65117896e337c170f47b31abb0 diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md index 6d711f2a6d..b5300706ce 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.md @@ -1,9 +1,9 @@ # RFC: Subagent provider-lifecycle events — `subagent/provider-added` / `subagent/provider-removed` -English | [中文](2026-07-05-subagent-provider-lifecycle-events.zh.md) - Status: implemented +English | [中文](2026-07-05-subagent-provider-lifecycle-events.zh.md) + ## Problem [The prompt-variables RFC](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) makes `dsh-tool-subagent` DERIVE its model-facing wording from its provider: `SubagentProvider.inheritsParentContext` (spawn/ACP `false`, fork `true`) drives both the tool description and the `prompt` parameter description (`providerWording`), so the fork tool stops lying about context inheritance. That fix created a cross-fiber data dependency: a tool's description is fixed at TOOL REGISTRATION (deliberately — the description is where tool-choice guidance lives), but the provider arrives on its own plugin fiber, on no particular schedule. diff --git a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md index f412b03164..8694612e5e 100644 --- a/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md @@ -1,12 +1,12 @@ -# RFC:Subagent 提供方生命周期事件——`subagent/provider-added` / `subagent/provider-removed` - -[English](2026-07-05-subagent-provider-lifecycle-events.md) | 中文 +# RFC: Subagent 提供方生命周期事件——`subagent/provider-added` / `subagent/provider-removed` Status: implemented +[English](2026-07-05-subagent-provider-lifecycle-events.md) | 中文 + ## 问题 -[prompt-variables RFC](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) 让 `dsh-tool-subagent` 从其提供方**派生**面向模型的措辞:`SubagentProvider.inheritsParentContext`(spawn/ACP 为 `false`,fork 为 `true`)同时驱动工具描述和 `prompt` 参数描述(`providerWording`),使 fork 工具不再在上下文继承问题上对模型撒谎。这一修复引入了跨 fiber 的数据依赖:工具描述在**工具注册时**固定(这是有意为之——描述是 tool-choice 引导所在之处),但提供方在自己的插件 fiber 上到达,时机不确定。 +[prompt-variables RFC](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) 让 `dsh-tool-subagent` 从其提供方派生面向模型的措辞:`SubagentProvider.inheritsParentContext`(spawn/ACP 为 `false`,fork 为 `true`)同时驱动工具描述和 `prompt` 参数描述(`providerWording`),使 fork 工具不再在上下文继承问题上对模型撒谎。这一修复引入了跨 fiber 的数据依赖:工具描述在工具注册时固定(这是有意为之——描述是 tool-choice 引导所在之处),但提供方在自己的插件 fiber 上到达,时机不确定。 如果在工具插件的 `apply` 时刻解析提供方,就会产生一个隐式的加载顺序要求("在 cordis.yml 中把后端列在工具前面")。这个要求不成立,因为 Cordis Loader 并发启动同级条目,且 `Entry.init()` 不会等待激活完成:延迟到达的后端即使列在前面,也可能让工具 fiber 失败。Loader 不提供同级顺序保证——"异步状态不是同步状态"(见[防御性模式](../../../defensive-patterns.md))。 @@ -17,15 +17,15 @@ Status: implemented - **`subagent/provider-added(provider)`**:一个提供方在 `ctx.subagents` 注册表中变为可解析。在注册时发出。 - **`subagent/provider-removed(name)`**:一个提供方离开注册表(其插件 fiber 被 dispose(资源释放)——卸载或 HMR(热模块替换)重载)。从注册的 disposer 中发出。 -`dsh-tool-subagent` 镜像其命名提供方的生命周期:当提供方可用(或变为可用)时注册工具——在那一刻从该提供方派生措辞——当提供方离开时注销工具,并在重新注册时(HMR 重载)重新派生。提供方不在时工具不存在,因此不会对模型撒谎。这里有意**不留下**任何需要文档化的加载顺序要求:事件让顺序问题消失,而非将其钉死。 +`dsh-tool-subagent` 镜像其命名提供方的生命周期:当提供方可用(或变为可用)时注册工具——在那一刻从该提供方派生措辞——当提供方离开时注销工具,并在重新注册时(HMR 重载)重新派生。提供方不在时工具不存在,因此不会对模型撒谎。这里有意不留下任何需要文档化的加载顺序要求:事件让顺序问题消失,而非将其钉死。 这些事件还完善了 seam 的词汇:`ctx.subagents` 是一个命名注册表,多个委派后端(`spawn`、`fork`、`acp`)在其上共存;一个其他插件从中派生状态的注册表,应当以类型化事件广播成员变化,而非要求轮询或依赖加载顺序。 ## 曾考虑的替代方案 - **在 `apply` 时解析提供方,不存在则抛异常**:否决。"先列后端"这一要求声称了 Loader 并不存在的顺序保证。 -- **重试查找(轮询直到提供方出现)**:最终能收敛,但在框架已有的机制(effect 注册 + disposal)之外发明了一套私有就绪协议;它也无法感知提供方**离开**,因此 HMR 会遗留一个措辞描述已 dispose 后端的工具。 -- **仅在 section 中放置 subagent 措辞,在组装时惰性解析**:同样能容忍任意加载顺序,但将 tool-choice 引导移出了**描述**,与 prompt-variables RFC 建立的所有权规则相矛盾(每个工具的语义和何时使用属于描述)。响应式注册既保持描述的权威性,又不依赖顺序。 +- **重试查找(轮询直到提供方出现)**:最终能收敛,但在框架已有的机制(effect 注册 + disposal)之外发明了一套私有就绪协议;它也无法感知提供方离开,因此 HMR 会遗留一个措辞描述已 dispose 后端的工具。 +- **仅在 section 中放置 subagent 措辞,在组装时惰性解析**:同样能容忍任意加载顺序,但将 tool-choice 引导移出了描述,与 prompt-variables RFC 建立的所有权规则相矛盾(每个工具的语义和何时使用属于描述)。响应式注册既保持描述的权威性,又不依赖顺序。 - **根据提供方名称而非提供方对象确定措辞**:`providerName` 本身是配置,重命名后的提供方会静默获得错误的措辞;从已解析提供方自身的 `inheritsParentContext` 派生则不会漂移。 ## 后果 @@ -33,4 +33,4 @@ Status: implemented - 从命名提供方派生状态的消费方响应 `subagent/provider-added`/`-removed` 事件,而非在 `apply` 时读取注册表;`dsh-tool-subagent` 是参考实现。 - **添加时大声失败;移除时按监听器隔离。** 添加监听器可以回滚注册。移除在 disposal 期间运行,因此单个监听器抛异常只会被记录日志,不会饿死后续镜像或干扰拆解流程。`start()` 仍在每次运行时按名称解析提供方,防止陈旧工具调用已移除的后端。见[事件目录](../../../cordis-catalog/events.md)与[生产者/消费者映射](../../../event-producer-consumer.md)。 - **工具不存在的窗口期。** 在后端 disposal 与重新注册之间(HMR 重载期间),模型看不到 subagent 工具。这是诚实的状态——替代方案是一个向空处分发的工具——工具注册表的 `tools/change` 事件发出会保持 prompt 组装的时效性。 -- **两个等待中的 fiber 共享同一 `toolName` 是无效配置,被延迟捕获。** 如果两个 `dsh-tool-subagent` 加载实例命名了不同的提供方但相同的 `toolName`,两者都会等待,先到达的提供方先注册;第二次注册仅在**其**提供方到达时才抛异常。插件中的 `TODO(subagent-dup-toolname)` 记录了这一影响范围;工具注册表的重名拒绝机制仍是最终防线。 +- **两个等待中的 fiber 共享同一 `toolName` 是无效配置,被延迟捕获。** 如果两个 `dsh-tool-subagent` 加载实例命名了不同的提供方但相同的 `toolName`,两者都会等待,先到达的提供方先注册;第二次注册仅在其提供方到达时才抛异常。插件中的 `TODO(subagent-dup-toolname)` 记录了这一影响范围;工具注册表的重名拒绝机制仍是最终防线。 diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml index a051d20478..57b6fca44e 100644 --- a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml @@ -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 -2026-07-06-timeout-deadline-library.md: 9906aa7cce40ffd7b5f7082199d05edb8d0a54b2 -2026-07-06-timeout-deadline-library.zh.md: dd1a60f9d7b91575b32e1cc85b3800cf823b6a6d +2026-07-06-timeout-deadline-library.md: e8a688fbd5285c5e177eca5339bb204e2e4b01bc +2026-07-06-timeout-deadline-library.zh.md: 427aa4e10fe90a69b8773ed739d92e37754a4998 diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md index 9906aa7cce..e8a688fbd5 100644 --- a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.md @@ -1,9 +1,9 @@ # RFC: A shared timeout/deadline primitive, with hard-kill left to each capability -English | [中文](2026-07-06-timeout-deadline-library.zh.md) - Status: implemented +English | [中文](2026-07-06-timeout-deadline-library.zh.md) + ## Problem Timeout handling was drifting apart across the tool-bearing capabilities, and the divergence was not superficial — it was the same logic re-implemented three ways, each with its own subtle correctness burden. diff --git a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md index dd1a60f9d7..427aa4e10f 100644 --- a/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md @@ -1,4 +1,4 @@ -# RFC:共享的超时/截止时间原语,硬终止留给各能力自行实现 +# RFC: 共享的超时/截止时间原语,硬终止留给各能力自行实现 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml index 31025407be..1d65850a78 100644 --- a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml @@ -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 -2026-07-07-tool-call-timeout-policy.md: 0e69c8504dd34dfc4427bf1f3865a80be93eff9d -2026-07-07-tool-call-timeout-policy.zh.md: 2f4eca6eff9d135aad3fe538b887402a42ac6f84 +2026-07-07-tool-call-timeout-policy.md: 20e0b5d70166404e034c0d0ece75cec61cab0df9 +2026-07-07-tool-call-timeout-policy.zh.md: 00b85ce9e2e7ae4ba31a9770beefce9c2eb8c319 diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md index 0e69c8504d..20e0b5d701 100644 --- a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.md @@ -1,9 +1,9 @@ # RFC: Tool-call timeout policy as a plugin -English | [中文](2026-07-07-tool-call-timeout-policy.zh.md) - Status: implemented +English | [中文](2026-07-07-tool-call-timeout-policy.zh.md) + ## Problem The [timeout/deadline RFC](2026-07-06-timeout-deadline-library.md) extracted the timing-and-classification primitive into `@deepseek-ai/dsh-timeout`, but timeout policy was still attached to individual capabilities and model-facing schemas. `bash` exposed `timeoutMs`; `web_fetch` exposed `timeout_ms`; `web_search` had no model-facing timeout even though providers already honor `exec.signal`; a future grep/glob tool would either import the timeout library directly or invent its own timeout policy. That is the wrong authoring shape for a plugin SDK: a tool author should normally forward `exec.signal` to the implementation it calls, and deployment policy should decide the budget. diff --git a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md index 2f4eca6eff..00b85ce9e2 100644 --- a/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md @@ -1,9 +1,9 @@ -# RFC:工具调用超时策略作为插件 - -[English](2026-07-07-tool-call-timeout-policy.md) | 中文 +# RFC: 工具调用超时策略作为插件 Status: implemented +[English](2026-07-07-tool-call-timeout-policy.md) | 中文 + ## 问题 [超时/截止时间 RFC](2026-07-06-timeout-deadline-library.md) 将计时与分类原语提取到了 `@deepseek-ai/dsh-timeout`,但超时策略仍然附着在各个能力和面向模型的 schema 上。`bash` 暴露了 `timeoutMs`;`web_fetch` 暴露了 `timeout_ms`;`web_search` 没有面向模型的超时参数,尽管提供方已经遵循 `exec.signal`;未来的 grep/glob 工具要么直接导入超时库,要么自行发明超时策略。对于一个插件 SDK 来说,这是错误的编写范式:工具作者通常只需将 `exec.signal` 转发给其调用的实现,而部署策略来决定预算。 @@ -36,7 +36,7 @@ ctx.tools.execute(exec) `@deepseek-ai/dsh-tools` 声明了一个 `tools/execute` waterfall,其基础 `next()` 是带规范化的分发 thunk——即同一个内部 `try`/`catch`,将抛出的工具错误(或未知工具错误)转换为 `isError` 的 `ToolExecutionResult`。监听器接收 `(exec, next)`:调用 `next()` 委托给分发(返回其结果,可选地包装),或返回替代结果以短路分发。整个流水线仍位于 `execute` 的外层 try/catch 内,因此抛出异常的监听器会变成 `isError` 结果,而非轮次失败。 -catch 是基础 `next()`(而非 waterfall 之外的东西)这一点至关重要:当提供方看到超时信号并抛出自己的上游中止错误时,注册表分发首先将其转换为普通错误结果,然后 `timeout-policy` 才能将最终结果替换为 `TOOL_TIMEOUT`。 +catch 是基础 `next`(而非 waterfall 之外的东西)这一点至关重要:当提供方看到超时信号并抛出自己的上游中止错误时,注册表分发首先将其转换为普通错误结果,然后 `timeout-policy` 才能将最终结果替换为 `TOOL_TIMEOUT`。 ### `timeout-policy` 插件 @@ -108,4 +108,4 @@ function toolTimeoutResult(timeoutMs: number): ToolExecutionResult { - 多个 `tools/execute` 监听器按普通 Cordis waterfall 顺序组合:调用 `next()` 的监听器包装下游监听器加分发;不调用 `next()` 直接返回的监听器短路它们。一个同时组合超时与未来重试/沙箱/指标包装器的部署通过注册顺序选择语义(「超时覆盖整个重试」vs「超时覆盖每次尝试」)。 - 按声明加入是一个有意的误配置风险:工具可以声明 `timeoutMs` 但不遵循 `exec.signal`,这样的工具在超时时不会停止。插件契约声明:声明预算意味着协作;web 工具在已转发信号的工具上验证了这一模式。 - 过渡期间 `bash` 和已迁移的 web 工具有意使用不同的超时路径:`TOOL_TIMEOUT` 是面向模型的工具调用预算,而 `BASH_TIMEOUT` 仍是 bash 和钩子使用的 bash 后端超时。 -- 与字面提案的偏差,按 implemented-RFC 规则记录:插件包为 `@deepseek-ai/dsh-timeout-policy`(而非 `tool-timeout`);信号替换是在 `next()` 之前就地修改 `exec.signal`(而非 `next({ ...exec, signal })`,Cordis 会忽略后者);逐工具预算声明在 `ToolDefinition` 上(`timeoutMs`,由拥有该工具的插件从其配置中设置),而非在本插件配置中按工具名映射——因此执行器是零配置的,拼错工具名不可能发生。以上三点均在上文「决策」一节中描述。 +- 与字面提案的偏差,按 implemented-RFC 规则记录:插件包为 `@deepseek-ai/dsh-timeout-policy`(而非 `tool-timeout`);信号替换是在 `next()` 之前就地修改 `exec.signal`(而非 `next({ ...exec, signal })`,Cordis 会忽略后者);逐工具预算声明在 `ToolDefinition` 上(`timeoutMs`,由拥有该工具的插件从其配置中设置),而非在本插件配置中按工具名映射——因此执行器是零配置的,拼错工具名不可能发生。以上三点均在上文 `## Decision` 中描述。 diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml index 3253751754..fda6a0406b 100644 --- a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml @@ -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 -2026-07-08-agent-scope-contexts.md: f238d58d90413d36e81b34c1a2c94e1291e889de -2026-07-08-agent-scope-contexts.zh.md: 0f4de12e782fc72d3761b6d46cd953ab4650654d +2026-07-08-agent-scope-contexts.md: b67d51f06f74f0460f76e9fc4b45699d00b7db46 +2026-07-08-agent-scope-contexts.zh.md: e37ea60418095cb34d354150aed79a937b1b3552 diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md index f238d58d90..b67d51f06f 100644 --- a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md @@ -1,9 +1,9 @@ # RFC: The agent is a registration scope -English | [中文](2026-07-08-agent-scope-contexts.zh.md) - Status: implemented +English | [中文](2026-07-08-agent-scope-contexts.zh.md) + ## Problem One application needs to share infrastructure across many agents while letting each agent have its own tools, prompt contributions, policies, and listeners. Shared adapters, persistence, and user interfaces belong to the deployment; a persona, tool variant, or listener often belongs to one agent. diff --git a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md index 0f4de12e78..e37ea60418 100644 --- a/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md @@ -1,4 +1,4 @@ -# RFC:agent 即注册作用域 +# RFC: agent 即注册作用域 Status: implemented diff --git a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml index 5f2ed7f3bc..c2a5189641 100644 --- a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml +++ b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml @@ -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 -2026-07-12-agent-scope-runtime-design.md: 5fe44f2b0a79d91ce0e32a687ed183a5ffaef284 -2026-07-12-agent-scope-runtime-design.zh.md: 6e4f09e6780858c90b0cfbcf8709eca4c79ee414 +2026-07-12-agent-scope-runtime-design.md: 1940423db9364f56ab8a13e4d636f492f97f2d54 +2026-07-12-agent-scope-runtime-design.zh.md: bbfb06db7eb886f7bc34cdb8607729fb892cf5ba diff --git a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md index 5fe44f2b0a..1940423db9 100644 --- a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md +++ b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md @@ -1,9 +1,9 @@ # RFC: Agent-scope runtime design and correctness -English | [中文](2026-07-12-agent-scope-runtime-design.zh.md) - Status: implemented +English | [中文](2026-07-12-agent-scope-runtime-design.zh.md) + ## Problem The [agent-scope contract](2026-07-08-agent-scope-contexts.md) is simple for contributors: register through `agent.ctx`, resolve one global-plus-agent view, publish only after setup, and retain the scope until work stops. The runtime must preserve that contract across a cooperative plugin framework, asynchronous creation, reentrant listeners, durable session commits, and worker or process failure. diff --git a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md index 6e4f09e678..bbfb06db7e 100644 --- a/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md +++ b/docs/rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md @@ -1,9 +1,9 @@ -# RFC:Agent 作用域运行时设计与正确性 - -[English](2026-07-12-agent-scope-runtime-design.md) | 中文 +# RFC: Agent 作用域运行时设计与正确性 Status: implemented +[English](2026-07-12-agent-scope-runtime-design.md) | 中文 + ## 问题 [agent 作用域契约](2026-07-08-agent-scope-contexts.md)对贡献者而言很简单:通过 `agent.ctx` 注册,解析出一个全局加单 agent 的视图,仅在 setup 完成后发布,并保持作用域直到工作停止。运行时必须在协作式插件框架、异步创建、可重入监听器、持久化会话提交以及 worker 或进程故障等场景下维护这份契约。 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml index b0b2ec8727..f42c8c462e 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml @@ -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 -2026-06-14-acp-agent-client-protocol.md: 0bb2a2f2e307b8f23a3a9ca98edb2a2d3b5df0a8 -2026-06-14-acp-agent-client-protocol.zh.md: 7bb0e066572150c9c8fc0b94de1d5bf2d69527ee +2026-06-14-acp-agent-client-protocol.md: 50ad2620de1dada78c4a20101b631cc5b0e9f3d1 +2026-06-14-acp-agent-client-protocol.zh.md: c4b73c00083d63e5c024953cd8c9d8dbd94d6b0a diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md index 0bb2a2f2e3..50ad2620de 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md @@ -1,9 +1,9 @@ # RFC: Agent Client Protocol (ACP) support — drive the coding agent from external editors -English | [中文](2026-06-14-acp-agent-client-protocol.zh.md) - Status: implemented +English | [中文](2026-06-14-acp-agent-client-protocol.zh.md) + ## Problem The harness originally exposed agents only through a readline loop. That surface could carry text, but it gave an editor no structured way to create or resume sessions, correlate prompt completion, stream reasoning and tool activity, render tool-specific UI, ask for permission, or cancel one conversation without disturbing another. ACP defines those interactions as JSON-RPC over stdio, and Zed is the target client used to make concrete compatibility decisions. diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md index 7bb0e06657..c4b73c0008 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md @@ -1,9 +1,9 @@ -# RFC:Agent Client Protocol(ACP)支持——从外部编辑器驱动编码 agent - -[English](2026-06-14-acp-agent-client-protocol.md) | 中文 +# RFC: Agent Client Protocol(ACP)支持——从外部编辑器驱动编码 agent Status: implemented +[English](2026-06-14-acp-agent-client-protocol.md) | 中文 + ## 问题 harness 最初仅通过 readline 循环暴露 agent。该接口能传输文本,但编辑器无法以结构化方式创建或恢复会话、关联 prompt 完成、流式输出推理(reasoning)与工具活动、渲染工具专属 UI、请求权限,或在不干扰其他对话的前提下取消某个对话。ACP(Agent Client Protocol)将这些交互定义为基于 stdio 的 JSON-RPC,Zed 是用于做出具体兼容性决策的目标客户端。 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml index 825e4c2ed8..5a79faa4da 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml @@ -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 -2026-06-14-acp-multi-session.md: b96557d2d94711adb2183aa4f5dd8debf39c1de8 -2026-06-14-acp-multi-session.zh.md: 6a9f5e8162d46ed8719164247e22b8b9c5d26c61 +2026-06-14-acp-multi-session.md: a71f2d3d2daff3c8fae460e414d1f50facd5538f +2026-06-14-acp-multi-session.zh.md: 8b5ba46e949480d450f13aadad3ea82e0e048161 diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md index b96557d2d9..a71f2d3d2d 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.md @@ -1,9 +1,9 @@ # RFC: Multiplex concurrent ACP sessions over one connection -English | [中文](2026-06-14-acp-multi-session.zh.md) - Status: implemented +English | [中文](2026-06-14-acp-multi-session.zh.md) + ## Problem An ACP editor can keep several conversations alive over one agent subprocess. A single-active-session bridge would force extra processes and would not match Zed's client model, which tracks multiple session ids and concurrent loads. Multiplexing introduces isolation risks: events, prompt completion, cancellation, permission prompts, config selections, and predictable background-task ids must never cross session boundaries. diff --git a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md index 6a9f5e8162..8b5ba46e94 100644 --- a/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md +++ b/docs/rfc/implemented/feature/2026-06-14-acp-multi-session.zh.md @@ -1,9 +1,9 @@ -# RFC:在单个连接上多路复用并发 ACP 会话 - -[English](2026-06-14-acp-multi-session.md) | 中文 +# RFC: 在单个连接上多路复用并发 ACP 会话 Status: implemented +[English](2026-06-14-acp-multi-session.md) | 中文 + ## 问题 一个 ACP(Agent Client Protocol)编辑器可以在同一个 agent(智能体)子进程上保持多个对话。如果桥接层只支持单活跃会话,就不得不启动额外进程,也无法匹配 Zed 的客户端模型——该模型跟踪多个 session id 和并发加载。多路复用引入了隔离风险:事件、prompt 完成、取消、权限提示、配置选择以及可预测的后台 task id 绝不能跨越会话边界。 diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml b/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml index 5aeee85382..6beb8d876f 100644 --- a/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.i18n.yaml @@ -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 -2026-06-15-code-mode.md: c64b6d6d8442e60240fa6c849833385ed50d71ff -2026-06-15-code-mode.zh.md: e9ae74f6629f3e34a0e97f0fa532764c70095bba +2026-06-15-code-mode.md: fb95f3010121fa432b3ac24e6aa477b1205a0ba7 +2026-06-15-code-mode.zh.md: 2da6628c1842bfd507c62d4b66a91f323e6fd0e7 diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.md b/docs/rfc/implemented/feature/2026-06-15-code-mode.md index c64b6d6d84..fb95f30101 100644 --- a/docs/rfc/implemented/feature/2026-06-15-code-mode.md +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.md @@ -1,9 +1,9 @@ # RFC: Code Mode — the model writes TypeScript against the tool registry -English | [中文](2026-06-15-code-mode.zh.md) - Status: implemented +English | [中文](2026-06-15-code-mode.zh.md) + ## Problem In the registry's native presentation, the agent loop advertises every visible capability as a JSON-schema function definition. `ToolRegistry` contributes its schemas to the system-prompt assembly, the assembly's `tools` land on the wire (and in the logged request header), the model invokes one `tool-call` block per step, and the loop dispatches each call through `ctx.tools.execute()` **sequentially** (parallel tool execution is an explicit open TODO in `dsh-tools` and [docs/architecture.md](../../../architecture.md)), with **every** intermediate `tool-result` re-entering the model's context on the next request. diff --git a/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md b/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md index e9ae74f662..2da6628c18 100644 --- a/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md +++ b/docs/rfc/implemented/feature/2026-06-15-code-mode.zh.md @@ -1,9 +1,9 @@ -# RFC:Code Mode——模型针对工具注册表编写 TypeScript - -[English](2026-06-15-code-mode.md) | 中文 +# RFC: Code Mode——模型针对工具注册表编写 TypeScript Status: implemented +[English](2026-06-15-code-mode.md) | 中文 + ## 问题 在注册表的原生呈现方式下,agent loop(智能体循环)将每个可见能力以 JSON Schema 函数定义的形式通告给模型。`ToolRegistry` 将其 schema 贡献给系统提示词组装,组装结果中的 `tools` 落到协议格式(wire format)上(也记录在请求头日志中),模型每步调用一个 `tool-call` 块,循环通过 `ctx.tools.execute()` **逐个**分发每次调用(并行工具执行是 `dsh-tools` 和 [docs/architecture.md](../../../architecture.md) 中明确标注的 open TODO),且**每一个**中间 `tool-result` 都会在下一次请求时重新进入模型上下文。 @@ -20,7 +20,7 @@ Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一 1. **Code Mode 是 `ToolRegistry`(`dsh-tools`)的一等呈现模式**,通过经校验的 `mode` 配置选择:`'native'`(默认,贡献可见能力 schema)、`'code'`(注册表仅贡献其保留的 `run_code` 传输通道加一份生成的 SDK `.d.ts` 到系统提示词中)或 `'both'`(原生 schema 加传输通道 + SDK)。注册表在源头塑造其权威贡献;协作式 prompt 组装的结果仍具权威性,记录在日志中的请求头精确反映该返回的呈现。 2. **代码执行是一个能力 seam**——`packages/code-runtime/` 包含接口包 `@deepseek-ai/dsh-code-runtime`,拥有 `ctx.codeRuntime`([能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md);消费方 = `dsh-tools`,core 消费 seam 的先例见 `agent-loop` → `dsh-llm`)。运行时对工具一无所知:它接收一段程序和命名的异步绑定,执行程序,报告 `{ value, logs, error? }`。语言和基底是后端属性,因此未来的 Python 或容器后端只是另一个实现包,而非重新设计。 -3. **交付的实现是 `@deepseek-ai/dsh-code-runtime-worker`**:每次运行 spawn 一个全新的 Node worker 线程,对模型的 TypeScript 进行 type-strip 后执行,绑定通过 message port 桥接,环境为空,堆/输出/时间上限可配置,并支持硬终止。其信任姿态在设计上等同于 bash——无需 unsafe-acknowledgement flag——因为 harness 已经交付了 `dsh-bash-local`,后者以严格**更高**的环境权限执行模型编写的任意 shell 命令。 +3. **交付的实现是 `@deepseek-ai/dsh-code-runtime-worker`**:每次运行 spawn 一个全新的 Node worker 线程,对模型的 TypeScript 进行 type-strip 后执行,绑定通过 message port 桥接,环境为空,堆/输出/时间上限可配置,并支持硬终止。其信任姿态在设计上等同于 bash——无需 unsafe-acknowledgement flag——因为 harness 已经交付了 `dsh-bash-local`,后者以严格*更高*的环境权限执行模型编写的任意 shell 命令。 ### 注册表拥有模式 diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml index f5eae41ba4..b3ed1ae8ee 100644 --- a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml @@ -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 -2026-06-17-filesystem-tool-schemas.md: c2d3aa679599b1129a19b9082b9254ecf3103f12 -2026-06-17-filesystem-tool-schemas.zh.md: cd504a37d5ee25f6634b651d30099afe5acd6495 +2026-06-17-filesystem-tool-schemas.md: dba96157a0df548e4f153a0e233238af7400c087 +2026-06-17-filesystem-tool-schemas.zh.md: 3c135de9fa81fb333abc5fa6001a7ce7d7525a9d diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md index c2d3aa6795..dba96157a0 100644 --- a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.md @@ -1,9 +1,9 @@ # RFC: Filesystem tool schemas — model-facing read/write/edit shapes -English | [中文](2026-06-17-filesystem-tool-schemas.zh.md) - Status: implemented +English | [中文](2026-06-17-filesystem-tool-schemas.zh.md) + ## Problem [The filesystem capability-seam RFC](../architecture/2026-06-17-filesystem-capability-seam.md) defines the filesystem capability seam (`ctx.fs`), the package split (`dsh-fs`, `dsh-fs-local`, `dsh-tool-fs`, plus the `dsh-fs-policy` policy plugin), and the observed-file/stale-version policy for read-before-write/edit checks — which the [split-fs-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) and [event-gate](../architecture/2026-06-26-file-context-as-event-gate.md) RFCs moved off `ctx.fs` into the `dsh-fs-policy` plugin on the `fs/*` event gate. The remaining decision for the first filesystem tool delivery is the model-facing schema surface: what arguments the model sees for `read`, `write`, and `edit`. diff --git a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md index cd504a37d5..3c135de9fa 100644 --- a/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md +++ b/docs/rfc/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md @@ -1,9 +1,9 @@ -# RFC:文件系统工具 schema——面向模型的读/写/编辑接口形状 - -[English](2026-06-17-filesystem-tool-schemas.md) | 中文 +# RFC: 文件系统工具 schema——面向模型的读/写/编辑接口形状 Status: implemented +[English](2026-06-17-filesystem-tool-schemas.md) | 中文 + ## 问题 [文件系统能力 seam RFC](../architecture/2026-06-17-filesystem-capability-seam.md) 定义了文件系统能力 seam(`ctx.fs`)、包(package)拆分(`dsh-fs`、`dsh-fs-local`、`dsh-tool-fs`,加上 `dsh-fs-policy` 策略插件),以及针对 read-before-write/edit 检查的 observed-file/stale-version 策略——[split-fs-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](../architecture/2026-06-26-file-context-as-event-gate.md) RFC 后来将其从 `ctx.fs` 移至 `dsh-fs-policy` 插件的 `fs/*` 事件门上。首次文件系统工具交付剩余的决策是面向模型的 schema 接口:模型在 `read`、`write` 和 `edit` 中看到哪些参数。 @@ -51,7 +51,7 @@ schema 使用 snake_case 字段名(`file_path`、`old_string`、`new_string` 在默认 fs-policy 下,使用 `write` 更新已有文件需要同一执行上下文先前对该文件有过一次观测(read/write/edit);`dsh-fs-policy` 插件将观测到的版本作为 `fs/write-intent` 上的 stale guard 提供。创建新文件不需要先前观测。如果策略插件不存在,`write` 是无条件的裸提供方 create-or-overwrite。 -schema 不将 `expected_hash`、`expected_version` 或 `create_only` 作为面向模型的参数暴露。过期版本检查由后端产生的版本和策略插件的观测状态驱动,而非要求模型通过 schema 复制版本令牌。 +schema 不将 `expected_hash`、`expected_version` 或 `create_only` 作为面向模型的参数暴露。陈旧版本检查由后端产生的版本和策略插件的观测状态驱动,而非要求模型通过 schema 复制版本令牌。 ### `edit` @@ -66,7 +66,7 @@ schema 不将 `expected_hash`、`expected_version` 或 `create_only` 作为面 `edit` 要求同一执行上下文先前对该文件有过一次观测(任何窗口化的 read 都算——授权基于版本新鲜度,而非全文查看要求),或该上下文先前对该文件做过 write/edit。`dsh-fs-policy` 策略插件推导所有者并将记录的版本作为 stale guard 提供;提供方的 mutation lock 负责执行。 -首次实现拒绝 Codex 风格的 patch 语法和多模式 edit API。它使用一种严格的字面替换模式,使面向模型的契约保持简单,并让后端掌控精确匹配、重复匹配、行尾和过期版本的语义。 +首次实现拒绝 Codex 风格的 patch 语法和多模式 edit API。它使用一种严格的字面替换模式,使面向模型的契约保持简单,并让后端掌控精确匹配、重复匹配、行尾和陈旧版本的语义。 ## 结果形状 @@ -99,14 +99,14 @@ schema 测试固定每个工具的必填/可选参数集、空 `old_string` 拒 ## 曾考虑的替代方案 -- **Codex 风格的 patch 语法或多模式 edit API**:否决。一种严格的字面替换模式使面向模型的契约保持简单,并让后端掌控精确匹配、重复匹配、行尾和过期版本的语义。 +- **Codex 风格的 patch 语法或多模式 edit API**:否决。一种严格的字面替换模式使面向模型的契约保持简单,并让后端掌控精确匹配、重复匹配、行尾和陈旧版本的语义。 - **camelCase 参数名(OpenCode 风格)**:snake_case 与 Claude Code 及现有 harness 工具 schema 示例一致,且命名一旦发布即成为公开接口。 -- **面向模型的 `expected_hash` / `expected_version` / `create_only` 参数**:否决。过期检查由后端产生的版本和策略插件的观测状态驱动,从不依赖模型复制的脆弱令牌。 +- **面向模型的 `expected_hash` / `expected_version` / `create_only` 参数**:否决。陈旧检查由后端产生的版本和策略插件的观测状态驱动,从不依赖模型复制的脆弱令牌。 ## 后果 **首版 schema 有意小于 Claude Code 的。** 去掉 PDF pages、多模态 read、丰富的 grep/list flag 和 expected hash 字段使实现保持聚焦,但用户可能很快就会提出这些需求。它们将以独立 RFC 或聚焦的后续工作形式到来,而非对初始 schema 的重载。 -**v1 中没有显式的面向模型的 stale guard。** schema 不要求模型提供 expected hash/version。这是有意为之:过期检查来自后端产生的版本和 `dsh-fs-policy` 插件的观测状态,而非模型复制的脆弱令牌。文件系统安全失败通过 `dsh-fs` 拥有的结构化 `FsError` 代码浮现,而非模型提供的版本字段。 +**v1 中没有显式的面向模型的 stale guard。** schema 不要求模型提供 expected hash/version。这是有意为之:陈旧检查来自后端产生的版本和 `dsh-fs-policy` 插件的观测状态,而非模型复制的脆弱令牌。文件系统安全失败通过 `dsh-fs` 拥有的结构化 `FsError` 代码浮现,而非模型提供的版本字段。 **命名成为公开接口。** 一旦发布,将 `file_path` 改为 `filePath` 或 `old_string` 改为 `oldString` 会搅动提示词、示例和下游客户端。本 RFC 预先选择 snake_case,并将其视为稳定的面向模型的契约。 diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml index c8ce15293a..b25f0bf18b 100644 --- a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml @@ -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 -2026-06-18-acp-terminal-and-tool-rendering.md: cab89aa690c2068399ea5429a9c467410c744ce8 -2026-06-18-acp-terminal-and-tool-rendering.zh.md: 4047c493e63ac23f758de718616fd1f4bb29f7d4 +2026-06-18-acp-terminal-and-tool-rendering.md: 9bcb65a1e0b316d0b596a80816647d46ccfca782 +2026-06-18-acp-terminal-and-tool-rendering.zh.md: 3899e3ed21b386b1652736bc3de41d338efaa30e diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md index cab89aa690..9bcb65a1e0 100644 --- a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md @@ -1,9 +1,9 @@ # RFC: Rich ACP bash rendering — the terminal card via the `_meta` convention -English | [中文](2026-06-18-acp-terminal-and-tool-rendering.zh.md) - Status: implemented +English | [中文](2026-06-18-acp-terminal-and-tool-rendering.zh.md) + ## Problem The ACP bridge lets each tool own its call rendering via `presentCall`/`presentResult` (see [tool-call UI presentation](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md) and `packages/core/tools`). For `bash` we surface the exact command as the `tool_call` title, the model's `description` as a content text block, `kind: 'execute'`, and the completed output wrapped in a fenced ` ```console ` text block. diff --git a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md index 4047c493e6..3899e3ed21 100644 --- a/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md +++ b/docs/rfc/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md @@ -1,9 +1,9 @@ -# RFC:富 ACP bash 渲染——通过 `_meta` 约定实现终端卡片 - -[English](2026-06-18-acp-terminal-and-tool-rendering.md) | 中文 +# RFC: 富 ACP bash 渲染——通过 `_meta` 约定实现终端卡片 Status: implemented +[English](2026-06-18-acp-terminal-and-tool-rendering.md) | 中文 + ## 问题 ACP(Agent Client Protocol)桥接层允许每个工具通过 `presentCall`/`presentResult` 自行控制调用渲染(见 [tool-call UI presentation](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md) 与 `packages/core/tools`)。对于 `bash`,我们将确切命令作为 `tool_call` 标题呈现,模型的 `description` 作为一个内容文本块,`kind: 'execute'`,完成后的输出包裹在 ` ```console ` 围栏文本块中。 @@ -27,7 +27,7 @@ Zed 侧(`crates/agent_servers/src/acp.rs`,已验证):收到 `ToolCall` 1. **能力声明。** `initialize` 读取 `clientCapabilities._meta.terminal_output`,桥接层按连接记住它。 2. **提供方无关的展示词汇。** `dsh-tools` 新增一种终端形态的展示结构,工具可返回它——提供方无关(`cwd`、输出 `data`、`exitCode`/`signal`),不含 ACP 类型。`dsh-tool-bash` 为 `bash` 返回该结构(cwd 来自解析后的工作目录;输出与退出从运行结果解析)。 -3. **桥接映射。** 当客户端声明了该能力时,桥接层将展示结构映射为:在 `tool_call` 上,`content:[…, {type:'terminal', terminalId}]`(工具的任何 `content`,如描述,渲染在终端块之前)+ `_meta.terminal_info.{terminal_id,cwd}`;在 `tool_call_update` 上,`_meta.terminal_output.{terminal_id,data}`(捕获的输出)+ `_meta.terminal_exit.{terminal_id, exit_code|signal}`(解析后的退出),且 update 的文本 `content` 被省略(ACP 的 `tool_call_update.content` 会**替换**调用的 content 集合,因此重新发送围栏块会覆盖终端内容块)。`terminalId` 由 harness 的 `callId` 派生(稳定、每次调用唯一)。当能力未声明时,桥接层在调用上发送描述内容块,在 update 上发送既有的 ` ```console ` 文本内容——行为不变。 +3. **桥接映射。** 当客户端声明了该能力时,桥接层将展示结构映射为:在 `tool_call` 上,`content:[…, {type:'terminal', terminalId}]`(工具的任何 `content`,如描述,渲染在终端块之前)+ `_meta.terminal_info.{terminal_id,cwd}`;在 `tool_call_update` 上,`_meta.terminal_output.{terminal_id,data}`(捕获的输出)+ `_meta.terminal_exit.{terminal_id, exit_code|signal}`(解析后的退出),且 update 的文本 `content` 被省略(ACP 的 `tool_call_update.content` 会替换调用的 content 集合,因此重新发送围栏块会覆盖终端内容块)。`terminalId` 由 harness 的 `callId` 派生(稳定、每次调用唯一)。当能力未声明时,桥接层在调用上发送描述内容块,在 update 上发送既有的 ` ```console ` 文本内容——行为不变。 4. **退出信息从渲染输出中解析;无新执行路径,无实时流式传输。** 输出在完成时附加(来自 agent 自身的 `tool/result`),不逐 token 流式传输。退出状态(`_meta.terminal_exit.{exit_code,signal}`)确实会发出:纯 `presentResult(args, result)` seam 只能看到内容块,因此 `dsh-tool-bash` 通过解析 `renderResult` 追加的状态标记(`[exit code: N]` / `[killed by signal: …]`)来恢复结构化退出信息——解析是标记发出的精确逆操作,二者在同一文件中共同演进,一个往返测试守护这对关系。资源释放不受影响:无需新增拆除逻辑,因为桥接层从未创建客户端侧终端。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml index aff86591fb..d99478bc53 100644 --- a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml @@ -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 -2026-06-18-compaction-capability-seam.md: 31b06905924a07a7f0c2af427d8868585966f1a7 -2026-06-18-compaction-capability-seam.zh.md: 1675484ed65e5cd890f420d4bdd1e16e2a95b2ef +2026-06-18-compaction-capability-seam.md: e88b3fd8267f65bba136398df9c439e371237912 +2026-06-18-compaction-capability-seam.zh.md: 75049079a2d85e27301e53b891228c1cbc87fac3 diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md index 31b0690592..e88b3fd826 100644 --- a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.md @@ -1,9 +1,9 @@ # RFC: Compaction as a capability seam (abstract contract + basic backend) -English | [中文](2026-06-18-compaction-capability-seam.zh.md) - Status: implemented +English | [中文](2026-06-18-compaction-capability-seam.zh.md) + ## Problem A long-running agent conversation grows without bound. As the event log accumulates turns, the derived message history eventually approaches the model's context window — the model then truncates mid-response (`max-tokens`) or degrades. **Compaction** is the mitigation: replace a run of older history with a concise summary, keeping recent context intact. diff --git a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md index 1675484ed6..75049079a2 100644 --- a/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md +++ b/docs/rfc/implemented/feature/2026-06-18-compaction-capability-seam.zh.md @@ -1,4 +1,4 @@ -# RFC:压缩作为能力 seam(抽象契约 + 基础后端) +# RFC: 压缩作为能力 seam(抽象契约 + 基础后端) Status: implemented @@ -66,7 +66,7 @@ request = waterfall agent/request ⟵ pure request transform (hooks, model s ### 近似收敛不变式 -`resolveConfig` 校验数值参数,但**不**基于虚构的摘要长度不变式来拒绝。收敛是动态的:提供方的输出上限可能被隐藏或显式的推理 token 消耗,模型可能生成不可预测大小的摘要。`maxTokens` 仅是摘要调用的提供方侧生成上限;推理块在检查点存储前被剥离。如果压缩后的 surface 仍超阈值,`compactIfNeeded()` 最多额外重压缩头部检查点 `compactionRetries` 次,但每次提交的摘要必须小于其遮蔽的内容。唯一的残余情况是上述单单元溢出(一个向后取整的超大步骤可能将保留尾部推过预算),这恰好是上述范围外的关注点,而非抖动 bug。 +`resolveConfig` 校验数值参数,但不基于虚构的摘要长度不变式来拒绝。收敛是动态的:提供方的输出上限可能被隐藏或显式的推理 token 消耗,模型可能生成不可预测大小的摘要。`maxTokens` 仅是摘要调用的提供方侧生成上限;推理块在检查点存储前被剥离。如果压缩后的 surface 仍超阈值,`compactIfNeeded()` 最多额外重压缩头部检查点 `compactionRetries` 次,但每次提交的摘要必须小于其遮蔽的内容。唯一的残余情况是上述单单元溢出(一个向后取整的超大步骤可能将保留尾部推过预算),这恰好是上述范围外的关注点,而非抖动 bug。 ### Surface 替换:`compact/*` 事件仅存在于日志;一条 `user/message` 承载摘要 diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml index 1da7113f51..20172e4369 100644 --- a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml @@ -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 -2026-06-21-subagent-capability-seam.md: 2bed84cd9166e8aa1ad5fa65b3afa44b8a842045 -2026-06-21-subagent-capability-seam.zh.md: a5917c14141dd06c14b4f45c5f6e4703f0eb661f +2026-06-21-subagent-capability-seam.md: ff8ca7d6292055715d94b3878860bffafb8a8057 +2026-06-21-subagent-capability-seam.zh.md: c11623531c753cd454621f450f33cff5edbbf815 diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md index 2bed84cd91..ff8ca7d629 100644 --- a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md @@ -1,9 +1,9 @@ # RFC: Subagent capability seam -English | [中文](2026-06-21-subagent-capability-seam.zh.md) - Status: implemented +English | [中文](2026-06-21-subagent-capability-seam.zh.md) + > The full seam is shipped: the `dsh-subagent` interface, the `dsh-subagent-mock` test backend, and the `dsh-tool-subagent` consumer; the two in-process backends (`dsh-subagent-spawn`, `dsh-subagent-fork`); the nested-agent snapshot infrastructure ([per-session snapshot replay](../testing/2026-06-22-subagent-snapshot-replay.md)); and the out-of-process `dsh-subagent-acp` backend ([its RFC](2026-06-22-acp-subagent-backend.md)). ## Problem diff --git a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md index a5917c1414..c11623531c 100644 --- a/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md +++ b/docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.zh.md @@ -1,9 +1,9 @@ -# RFC:Subagent 能力 seam - -[English](2026-06-21-subagent-capability-seam.md) | 中文 +# RFC: Subagent 能力 seam Status: implemented +[English](2026-06-21-subagent-capability-seam.md) | 中文 + > 完整 seam 已交付:`dsh-subagent` 接口、`dsh-subagent-mock` 测试后端与 `dsh-tool-subagent` 消费方;两个进程内后端(`dsh-subagent-spawn`、`dsh-subagent-fork`);嵌套 agent 快照基础设施([逐会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md));以及进程外后端 `dsh-subagent-acp`([其 RFC](2026-06-22-acp-subagent-backend.md))。 ## 问题 @@ -43,7 +43,7 @@ bash seam([能力 seam](../../implemented/architecture/2026-06-13-capability-s ### 两类可选能力,两种发现方式 -- **启动时特性**(`outputSchema`、`depthLimit`、`toolFilter`、`persona`)挂在静态的 `provider.capabilities` 描述符上。服务在委派**之前**检查每个被请求的特性,如果提供方不支持则**大声拒绝**(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不接受后静默忽略。这些特性必须在 run 存在之前检查,因此不能是运行时方法。 +- **启动时特性**(`outputSchema`、`depthLimit`、`toolFilter`、`persona`)挂在静态的 `provider.capabilities` 描述符上。服务在委派之前检查每个被请求的特性,如果提供方不支持则**大声拒绝**(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不接受后静默忽略。这些特性必须在 run 存在之前检查,因此不能是运行时方法。 - **运行时特性**(通过 `sendMessage` 进行 steering、通过 `resume` 进行后续对话)是 `SubagentRun` 上的**可选方法**。方法的存在本身即为能力,TypeScript 类型收窄即为发现机制:消费方不经收窄就无法调用不存在的方法,因此不存在静默降级路径,也不需要额外的 flags 对象来保持同步。 ### Fork 与 fresh 是独立后端,而非一个 flag diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml index 2939af3939..99c3a2b5e9 100644 --- a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml @@ -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 -2026-06-22-acp-subagent-backend.md: 7eb03ddf68f54c29524944e7b8bc801eb1724fe6 -2026-06-22-acp-subagent-backend.zh.md: 249f5a5ebf18d42f3d83d2159f6c2bcb52a245c3 +2026-06-22-acp-subagent-backend.md: c02b027177ae96d75ff0d3dcac227145fe71b340 +2026-06-22-acp-subagent-backend.zh.md: 2b4db4e20fd872d21ffb72b1c2a4432c6f0103a9 diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md index 7eb03ddf68..c02b027177 100644 --- a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.md @@ -1,9 +1,9 @@ # RFC: ACP subagent backend (out-of-process delegation) -English | [中文](2026-06-22-acp-subagent-backend.zh.md) - Status: implemented +English | [中文](2026-06-22-acp-subagent-backend.zh.md) + ## Problem The subagent seam ([the seam RFC](2026-06-21-subagent-capability-seam.md)) was built so multiple backends coexist by name on `ctx.subagents`. The in-process backends (`-spawn`/`-fork`) run a child as a second `Agent` on the SAME cordis context — cheap, but the child shares the parent's process, model client, and tools. The seam's whole point was to also support an OUT-OF-PROCESS child reached over a protocol, proving the abstraction generalizes across a process boundary. This RFC adds the first such backend: an Agent Client Protocol (ACP) client. diff --git a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md index 249f5a5ebf..2b4db4e20f 100644 --- a/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md +++ b/docs/rfc/implemented/feature/2026-06-22-acp-subagent-backend.zh.md @@ -1,16 +1,16 @@ -# RFC:ACP subagent 后端(进程外委派) - -[English](2026-06-22-acp-subagent-backend.md) | 中文 +# RFC: ACP subagent 后端(进程外委派) Status: implemented +[English](2026-06-22-acp-subagent-backend.md) | 中文 + ## 问题 -subagent seam([seam RFC](2026-06-21-subagent-capability-seam.md))的设计使多个后端可以按名称共存于 `ctx.subagents`。进程内后端(`-spawn`/`-fork`)将子 agent(智能体)作为第二个 `Agent` 运行在**同一个** Cordis 上下文上:开销低,但子 agent 与父 agent 共享进程、模型客户端和工具。seam 的核心意义在于同时支持通过协议到达的**进程外**子 agent,以证明该抽象能跨越进程边界泛化。本 RFC 添加第一个此类后端:一个 ACP(Agent Client Protocol)客户端。 +subagent seam([seam RFC](2026-06-21-subagent-capability-seam.md))的设计使多个后端可以按名称共存于 `ctx.subagents`。进程内后端(`-spawn`/`-fork`)将子 agent(智能体)作为第二个 `Agent` 运行在同一个 Cordis 上下文上:开销低,但子 agent 与父 agent 共享进程、模型客户端和工具。seam 的核心意义在于同时支持通过协议到达的进程外子 agent,以证明该抽象能跨越进程边界泛化。本 RFC 添加第一个此类后端:一个 ACP(Agent Client Protocol)客户端。 ## 决策 -`@deepseek-ai/dsh-subagent-acp` 注册一个 `SubagentProvider`,将每个子 agent 运行在一个**派生的子进程**中,并以 ACP *客户端*身份驱动它。它是现有服务端桥接 `@deepseek-ai/dsh-acp`(ACP *agent*)的方向反转孪生体:桥接**应答** `initialize`/`newSession`/`prompt`;本后端**调用**它们并**实现** `Client` 回调(`sessionUpdate`、`requestPermission`)。将配置的 spawn 命令指向 `acp-agent` 示例,即可让 harness 与自身进程通信。 +`@deepseek-ai/dsh-subagent-acp` 注册一个 `SubagentProvider`,将每个子 agent 运行在一个派生的子进程中,并以 ACP *客户端*身份驱动它。它是现有服务端桥接 `@deepseek-ai/dsh-acp`(ACP *agent*)的方向反转孪生体:桥接应答 `initialize`/`newSession`/`prompt`;本后端调用它们并实现 `Client` 回调(`sessionUpdate`、`requestPermission`)。将配置的 spawn 命令指向 `acp-agent` 示例,即可让 harness 与自身进程通信。 ### 每次运行启动全新进程 @@ -30,7 +30,7 @@ ACP `StopReason` → harness `SubagentStopReason`:`end_turn`→`completed`、` ### 安全:清洗子进程环境 -子 agent 是独立进程,因此会继承环境变量。形如凭证的环境变量(`/KEY|SECRET|TOKEN/i`)默认**不**转发——父 harness 自身的密钥不得隐式泄露到派生进程中(与 bash 执行器采用的策略相同)。子 agent **自己**的凭证(它需要模型密钥)通过 `config.env` **显式**提供,在清洗之后叠加,因此有意传入的 `DEEPSEEK_API_KEY` 得以保留,而偶然存在的 `AWS_SECRET_ACCESS_KEY` 则不会。子进程的 stderr 继承到父进程的 stderr(诊断信息自然浮现);spawn 级别的 `error` 事件(如命令不存在时的 ENOENT)被捕获并与 ACP 驱动竞速,因此错误命令解析为 `error` 而非以未处理错误崩溃父进程。 +子 agent 是独立进程,因此会继承环境变量。形如凭证的环境变量(`/KEY|SECRET|TOKEN/i`)默认不转发——父 harness 自身的密钥不得隐式泄露到派生进程中(与 bash 执行器采用的策略相同)。子 agent 自己的凭证(它需要模型密钥)通过 `config.env` 显式提供,在清洗之后叠加,因此有意传入的 `DEEPSEEK_API_KEY` 得以保留,而偶然存在的 `AWS_SECRET_ACCESS_KEY` 则不会。子进程的 stderr 继承到父进程的 stderr(诊断信息自然浮现);spawn 级别的 `error` 事件(如命令不存在时的 ENOENT)被捕获并与 ACP 驱动竞速,因此错误命令解析为 `error` 而非以未处理错误崩溃父进程。 ## 测试 diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml index 30f57427e2..1feca9e724 100644 --- a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.i18n.yaml @@ -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 -2026-06-25-ask-user-question.md: 06673233038d10214f8de3d1f29766d43b575442 -2026-06-25-ask-user-question.zh.md: a036220fd54e3f634ab4be80a45964b076d3fd2d +2026-06-25-ask-user-question.md: e28d34e7b13eb8920db1eb77f4cc66aec58c3525 +2026-06-25-ask-user-question.zh.md: 86194b4eeca2761b0af412f1510a688ef48b0422 diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md index 0667323303..e28d34e7b1 100644 --- a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.md @@ -1,9 +1,9 @@ # RFC: Ask-user question capability -English | [中文](2026-06-25-ask-user-question.zh.md) - Status: implemented +English | [中文](2026-06-25-ask-user-question.zh.md) + ## Problem The agent sometimes cannot proceed safely from model inference alone: it needs the human to choose a path, confirm a risky/default action, or provide missing information. Before this change, the only way to get that answer was for the model to ask in assistant text and then stop, which broke the normal tool-call loop: the agent had no structured way to pause, no option metadata for UIs, no abort/error taxonomy, and no way for non-stdio front doors to present the question consistently. diff --git a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md index a036220fd5..86194b4eec 100644 --- a/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md +++ b/docs/rfc/implemented/feature/2026-06-25-ask-user-question.zh.md @@ -1,9 +1,9 @@ -# RFC:ask-user 提问能力 - -[English](2026-06-25-ask-user-question.md) | 中文 +# RFC: ask-user 提问能力 Status: implemented +[English](2026-06-25-ask-user-question.md) | 中文 + ## 问题 agent(智能体)有时仅凭模型推理(inference)无法安全地继续执行:它需要人类选择路径、确认有风险的或默认的操作,或者提供缺失的信息。在此变更之前,获取答案的唯一方式是模型在 assistant 文本中提问然后停止,这打断了正常的工具调用循环:agent 没有结构化的暂停方式,没有供 UI 使用的选项元数据,没有中止/错误分类体系,也没有让非 stdio 前端一致地呈现问题的途径。 diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml index 677df03ea6..cacdff7448 100644 --- a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml @@ -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 -2026-06-29-todo-write-tool.md: 69f81cf6fd93df63ce53bb82c97dbac16dbbd486 -2026-06-29-todo-write-tool.zh.md: eb3c6fb8a9ddc7d26e4a620761c96a8d35ddf469 +2026-06-29-todo-write-tool.md: 7147440ec0cdb0b53093c371828d1987c17aabb0 +2026-06-29-todo-write-tool.zh.md: 7602ac8434963c84f089fe99a6f1e973c05e5bef diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md index 69f81cf6fd..7147440ec0 100644 --- a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.md @@ -1,9 +1,9 @@ # RFC: The `todo_write` tool — model task list as event-sourced session state -English | [中文](2026-06-29-todo-write-tool.zh.md) - Status: implemented +English | [中文](2026-06-29-todo-write-tool.zh.md) + ## Problem The harness gives the model bash and subagent tools but no way to record a structured task list. A todo list serves two co-equal purposes: it steers the model to plan multi-step work and keep the active task unambiguous (at most one active, exactly one while work remains), and it gives the human a live progress checklist. The ACP protocol has a native `plan` sessionUpdate that editors (Zed) already render, but the bridge never emitted one. Every reference coding agent surveyed (claude-code, opencode, codex, oh-my-pi, pi) ships some form of this; the harness had nothing. diff --git a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md index eb3c6fb8a9..7602ac8434 100644 --- a/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md +++ b/docs/rfc/implemented/feature/2026-06-29-todo-write-tool.zh.md @@ -1,4 +1,4 @@ -# RFC:`todo_write` 工具——将模型任务列表作为事件溯源的会话状态 +# RFC: `todo_write` 工具——将模型任务列表作为事件溯源的会话状态 Status: implemented @@ -14,7 +14,7 @@ harness 为模型提供了 bash 和 subagent 工具,却没有办法记录结 ### 整列表替换,三态 status -模型每次调用发送**完整**列表;新列表替换旧列表(回放时 last-write-wins)。这是 claude-code V1、opencode 和 codex `update_plan` 共同采用的形状,也是模型训练最多的形状——没有逐项 id,没有 delta 协议。`status` 恰好是 `pending | in_progress | completed`:与 codex `update_plan` 相同的三元组,且关键的是**与 ACP `PlanEntryStatus` 完全一致**,bridge 因此可以 1:1 映射,无需有损转换。 +模型每次调用发送完整列表;新列表替换旧列表(回放时 last-write-wins)。这是 claude-code V1、opencode 和 codex `update_plan` 共同采用的形状,也是模型训练最多的形状——没有逐项 id,没有 delta 协议。`status` 恰好是 `pending | in_progress | completed`:与 codex `update_plan` 相同的三元组,且关键的是**与 ACP `PlanEntryStatus` 完全一致**,bridge 因此可以 1:1 映射,无需有损转换。 ### 状态在会话日志上,而非服务 @@ -38,7 +38,7 @@ claude-code V1 的条目是 `{ content, status, activeForm }`;后来(V2) ### 校验:低成本的中间路线 -schema 强制 type/required/enum。在此之上,`execute` 拒绝空 `content`、重复 `content`,以及超过一个 `in_progress` 任务。claude-code 将单一 in_progress 交给 prompt 约束;oh-my-pi 在代码中强制。我们取中间路线:强制执行使计划*连贯*的低成本不变式(无空任务、无重复、最多一个活跃),但将排序和保持列表最新的纪律通过工具描述交给模型。被拒绝的写入返回 `isError` 结果,使模型自行修正。 +schema 强制 type/required/enum。在此之上,`execute` 拒绝为空或重复的 `content`,以及超过一个 `in_progress` 任务。claude-code 将单一 in_progress 交给 prompt 约束;oh-my-pi 在代码中强制。我们取中间路线:强制执行使计划*连贯*的低成本不变式(无空任务、无重复、最多一个活跃),但将排序和保持列表最新的纪律通过工具描述交给模型。被拒绝的写入返回 `isError` 结果,使模型自行修正。 ## 为何没有 cordis-catalog 条目 / 没有 `@mode` @@ -48,7 +48,7 @@ schema 强制 type/required/enum。在此之上,`execute` 拒绝空 `content` 四个层级,预先设计: - **单元测试**——会话事件(append/snapshot-clone/last-write-wins/not-on-surface);工具(schema 形状、通过真实 `ctx.tools.execute` 的参数校验、值校验、事件追加与替换、非 agent 拒绝、`presentCall`、HMR(热模块替换)安全性);ACP `todosToPlan` 映射;stdio 渲染分支。 -- **真实 Loader 路径**——插件通过 `Loader.unwrapExports` 运行,断言命名空间导出形状存活(它**有** `inject`,因此一个意外的 default 导出会在加载时崩溃——postmortem/0001)。 +- **真实 Loader 路径**——插件通过 `Loader.unwrapExports` 运行,断言命名空间导出形状存活(它有 `inject`,因此一个意外的 default 导出会在加载时崩溃——postmortem/0001)。 - **全循环集成**——一个脚本化的 mock 模型通过真实 agent loop(智能体循环)调用 `todo_write`;`todo/write` 事件落地,第二次调用替换它。 - **`session/load` 回放**——持久化的 `todo/write` 在新的 ACP bridge 加载会话时重新发出 `plan` 更新。 - **带密钥 e2e + 快照**——真实 prompt 诱导一次 `todo_write`;快照 golden 获得 `plan` 通知和日志事件。 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml index 03e276e446..fe4a29a063 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.i18n.yaml @@ -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 -2026-06-30-hook-bridges.md: 17ff57307c34121c845592efa93c723e66c98886 -2026-06-30-hook-bridges.zh.md: a4b8c12593cdac35deb882ba15a58876650c1653 +2026-06-30-hook-bridges.md: c3b268bb4062c3e31acc6cdfc7641b0d1a24c47a +2026-06-30-hook-bridges.zh.md: 57ccfae2f75858254352838049516aca3668d083 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md index 17ff57307c..c3b268bb40 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.md @@ -1,9 +1,9 @@ # RFC: dsh-hooks-claude + dsh-hooks-codex — the Claude Code / Codex hook bridges -English | [中文](2026-06-30-hook-bridges.zh.md) - Status: implemented +English | [中文](2026-06-30-hook-bridges.zh.md) + ## Problem The harness's extension surface is its typed interception seams ([the interception-seams RFC](2026-06-30-interception-seams.md)): a "native hook" is just an ordinary cordis plugin subscribing to `agent/session-start`, `agent/prompt-submit`, `tools/pre-execute`, `tools/post-execute`, `agent/turn-continuation`, `subagent/start`, `subagent/end`. But users arrive with **existing** Claude Code (CC) and Codex hook configs — a `hooks.json` (or a settings file's `hooks` key) full of shell-command hooks — and want those to run unmodified. This RFC introduces the two **bridge plugins** that translate that external shell-hook protocol onto the typed seams, built on the shared wire-protocol library ([the hook-protocol-lib RFC](2026-06-30-hook-protocol-lib.md)). diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md index a4b8c12593..57ccfae2f7 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-bridges.zh.md @@ -1,4 +1,4 @@ -# RFC:dsh-hooks-claude + dsh-hooks-codex —— Claude Code / Codex 钩子桥接插件 +# RFC: dsh-hooks-claude + dsh-hooks-codex —— Claude Code / Codex 钩子桥接插件 Status: implemented @@ -15,7 +15,7 @@ harness 的扩展面是其类型化的拦截 seam(见[拦截 seam RFC](2026-06 `packages/hooks/` 组下两个独立插件,各为 function/namespace 插件(`name`/`inject`/`Config`/`apply`,无 default export——见 [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md)),仅注入 `bash`: - **`dsh-hooks-claude`**——CC 方言。Claude Code 当前七个钩子点中的七个:`SessionStart`、`UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`Stop`、`SubagentStart` 和 `SubagentStop`。拥有 CC 形态的每事件 stdin payload(基础字段 `session_id`/`cwd`/`hook_event_name` 加每事件字段)、`CLAUDE_PROJECT_DIR` 环境变量加 `${CLAUDE_PLUGIN_ROOT}`/`${CLAUDE_PROJECT_DIR}` 替换,以及字面量或正则的匹配模式。CC 钩子的 stdin 带有**尾部换行**。 -- **`dsh-hooks-codex`**——Codex 当前五个钩子点中的五个:`PreToolUse`、`PostToolUse`、`SessionStart`、`UserPromptSubmit` 和 `Stop`。使用始终为正则的匹配模式、Codex 形态的 snake_case payload(含 `turn_id`/`model`/`permission_mode` 额外字段),写入时**不带**尾部换行,不注入 Codex 插件环境变量,不做配置时占位符替换,也没有 pre-tool 审批或重写路径。工具调用的 payload 在桥接精简后的 `tool_input: { command }` 形态中携带真实的 `tool_name`。 +- **`dsh-hooks-codex`**——Codex 当前五个钩子点中的五个:`PreToolUse`、`PostToolUse`、`SessionStart`、`UserPromptSubmit` 和 `Stop`。使用始终为正则的匹配模式、Codex 形态的 snake_case payload(含 `turn_id`/`model`/`permission_mode` 额外字段),写入时不带尾部换行,不注入 Codex 插件环境变量,不做配置时占位符替换,也没有 pre-tool 审批或重写路径。工具调用的 payload 在桥接精简后的 `tool_input: { command }` 形态中携带真实的 `tool_name`。 ### Outcome → Decision 映射 diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml index 5979186c01..f745911340 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml @@ -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 -2026-06-30-hook-protocol-lib.md: 924c320f7ef9fdb55b20ff06f492addbf42d1720 -2026-06-30-hook-protocol-lib.zh.md: 81315cbe8767e9a3cc07cdef92359734e4e20f31 +2026-06-30-hook-protocol-lib.md: bd00c35ee2a1a1075ecae936af21508004f606b8 +2026-06-30-hook-protocol-lib.zh.md: 59b473e2a4e6f2dd95fa7bb7046848b036e5466a diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md index 924c320f7e..bd00c35ee2 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.md @@ -1,9 +1,9 @@ # RFC: dsh-hook-protocol — the shared Claude Code / Codex hook wire-protocol core -English | [中文](2026-06-30-hook-protocol-lib.zh.md) - Status: implemented +English | [中文](2026-06-30-hook-protocol-lib.zh.md) + ## Problem The hooks subsystem ships two bridge plugins: one that runs a user's existing Claude Code (CC) hooks, one for Codex hooks. Studying the reference implementations (`~/repos/refs/claude-code`, `~/repos/refs/codex`) surfaced a decisive fact: **Codex deliberately reimplements a SUBSET of the CC hook protocol.** Its engine reads the same `hooks.json`, uses the same matcher-group shape, the same exit-code/structured-stdout output contract, and the same command-hook execution model — Codex's source even names the engine after Claude's and comments where it "intentionally diverges." So the two bridges would otherwise duplicate the bulk of the protocol. diff --git a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md index 81315cbe87..59b473e2a4 100644 --- a/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-hook-protocol-lib.zh.md @@ -1,9 +1,9 @@ -# RFC:dsh-hook-protocol——Claude Code / Codex 钩子协议格式共享核心库 - -[English](2026-06-30-hook-protocol-lib.md) | 中文 +# RFC: dsh-hook-protocol——Claude Code / Codex 钩子协议格式共享核心库 Status: implemented +[English](2026-06-30-hook-protocol-lib.md) | 中文 + ## 问题 hooks 子系统提供两个桥接插件:一个运行用户既有的 Claude Code(CC)钩子,另一个运行 Codex 钩子。研究参考实现(`~/repos/refs/claude-code`、`~/repos/refs/codex`)后发现一个决定性事实:**Codex 有意重新实现了 CC 钩子协议的一个子集。** 它的引擎读取相同的 `hooks.json`,使用相同的 matcher-group 形状、相同的 exit-code/structured-stdout 输出契约,以及相同的 command-hook 执行模型。Codex 的源码甚至以 Claude 的引擎命名,并在注释中标注了"有意偏离"之处。因此,如果不做抽取,两个桥接插件将大量重复协议逻辑。 @@ -16,7 +16,7 @@ hooks 子系统提供两个桥接插件:一个运行用户既有的 Claude Cod **共享(本库):** - **Matcher** — `matchesMatcher(pattern, query, mode)`。两种方言唯一不同的轴被收敛为 `mode` 参数:`claude` 将纯 `[A-Za-z0-9_|]+` 模式视为字面量(管道符 = 精确匹配的多选),其余视为正则;`codex` 始终是无锚定正则。缺省/`''`/`'*'` 匹配一切;无效正则匹配空集(绝不向 agent loop(智能体循环)抛异常)。 -- **Execution** — `runHook(bash, hook, options)`。通过 `ctx.bash` seam 而非自建 spawn 运行 command hook:执行器已提供清洗但可覆盖的 env、进程组 kill 和超时,正是协议所需的能力;`dsh-bash` 的 `stdin`/`env` 字段(正是为此添加的)是进程内桥接插件被允许使用的受信插件接口。它将桥接插件构建的 payload 序列化到 stdin(CC 时追加尾部换行),遵守钩子的 `timeoutSec`(否则使用 `DEFAULT_HOOK_TIMEOUT_MS`,即两种方言共享的 10 分钟参考默认值),且从不抛异常(执行器拒绝变为 non-blocking-error 的 `HookOutput`)。 +- **Execution** — `runHook(bash, hook, options)`。通过 `ctx.bash` seam 而非自建 `spawn` 运行 command hook:执行器已提供清洗但可覆盖的 env、进程组 kill 和超时,正是协议所需的能力;`dsh-bash` 的 `stdin`/`env` 字段(正是为此添加的)是进程内桥接插件被允许使用的受信插件接口。它将桥接插件构建的 payload 序列化到 stdin(CC 时追加尾部换行),遵守钩子的 `timeoutSec`(否则使用 `DEFAULT_HOOK_TIMEOUT_MS`,即两种方言共享的 10 分钟参考默认值),且从不抛异常(执行器拒绝变为 non-blocking-error 的 `HookOutput`)。 - **Decode** — `parseHookOutput(exit, stdout, stderr)`,exit-code + structured-stdout 编解码器,产出方言无关的 `HookOutput`。Exit `0` → 宽松 JSON 解析 stdout;exit `2` → blocking error,`stderr` 为原因(以 `decision: 'block'` 呈现,调用方无需单独处理 exit-code 分支);其他 → non-blocking error。解析 CC structured-stdout 中在某条路径上有消费方的字段(`continue`/`stopReason`/`decision`/`hookSpecificOutput.{permissionDecision,additionalContext,updatedInput}`/`systemMessage`);桥接插件只采纳对其方言有意义的子集。在任何路径上都没有消费方的字段不予解析(CC 的 `suppressOutput`——钩子 stdout 在此处从不进入 transcript(文本记录),因此无需抑制;见 [tighten-hook-protocol-contract RFC](../simplification/2026-07-04-tighten-hook-protocol-contract.md))。 - **Merge** — `mergeHookOutputs(outputs)`,将多个匹配钩子的输出折叠为一个最严格的 `MergedHookOutcome`:权限优先级 **deny > ask > allow**,halt 在首个 `continue:false` 时粘滞,block reason 以 `\n\n` 拼接,context/system-messages 按序累积。 - **`hook/*` 会话事件** — `hook/invoked` / `hook/result`,declaration-merge 进 `SessionEventMap`(仅日志,如 `compact/*`——不是 `SurfaceEventType`),配有 `appendHookInvoked`/`appendHookResult` 辅助函数,确保 invoked/result 配对与 turn 包含关系在各桥接插件间保持一致。`appendHookResult` 还拥有持久化记录的语义:decision 字符串(钩子解析出的 decision,否则 `continue:false` 时为 `'stop'`,否则为 `'pass'`)和 500 字符的 `stderrSummary` 截断均从本库的 `HookOutput` 派生,而非各桥接插件各自实现。 diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml index 2a1efb261c..1079a59599 100644 --- a/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.i18n.yaml @@ -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 -2026-06-30-interception-seams.md: fb8efe1e1c2057db13b440881f110ca7f579a81e -2026-06-30-interception-seams.zh.md: 668b96dba282ecdcbe85cc0b1dc56c2de293b3b3 +2026-06-30-interception-seams.md: 66e1c2374936c794bd5f791547c283f0fb59fb23 +2026-06-30-interception-seams.zh.md: fb2f1528a8e72a2f6b8b07679c8631b1b0a4f2d8 diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.md b/docs/rfc/implemented/feature/2026-06-30-interception-seams.md index fb8efe1e1c..66e1c23749 100644 --- a/docs/rfc/implemented/feature/2026-06-30-interception-seams.md +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.md @@ -1,9 +1,9 @@ # RFC: Interception seams — the typed-Decision surface a hook programs against -English | [中文](2026-06-30-interception-seams.zh.md) - Status: implemented +English | [中文](2026-06-30-interception-seams.zh.md) + ## Problem The harness needs a hooks subsystem: users extend or gate the agent at lifecycle points the way Claude Code (CC) and Codex do. The key reframe driving this design is that **"native hooks" are not a package** — a native hook is just an ordinary Cordis plugin subscribing to the canonical lifecycle events. So the real product is a *powerful, well-typed canonical event surface*; the CC/Codex bridges (the `dsh-hooks-claude` / `dsh-hooks-codex` packages) are merely translators that map an external shell-hook protocol onto that same surface. Anything a bridge can do, a plain plugin can do directly — more powerfully (no serialization boundary, full `ctx`, typed returns). diff --git a/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md b/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md index 668b96dba2..fb2f1528a8 100644 --- a/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-interception-seams.zh.md @@ -1,4 +1,4 @@ -# RFC:拦截 seam——钩子编程所面对的类型化 Decision 表面 +# RFC: 拦截 seam——钩子编程所面对的类型化 Decision 表面 Status: implemented @@ -15,7 +15,7 @@ harness 需要一套钩子子系统:用户像 Claude Code(CC)和 Codex 那 规范表面将可变换策略、环绕调度控制与仅观测通知分离。策略 waterfall(瀑布式事件)返回小型的、seam 专属的**类型化 Decision 联合类型**;包装层返回规范化结果;通知接收不可变快照,无法影响结果。覆盖的钩子点包括 `session-start`、`prompt-submit`、`pre-tool`、`post-tool`、通过 continuation 实现的 `stop`,同时将非钩子的执行策略留作独立可组合。 **Agent 事件**(`dsh-agent`): -- `agent/session-start(agent, source)` ——emit,在第 1 轮次之前触发一次,携带 `SessionStartSource`(`startup` 表示全新/fork 创建,`resume` 表示重新加载的持久化会话;`clear`/`compact` 保留)。纯通知,**不能**阻塞启动(这是有意的空白:桥接可以记录/注入,但不管控启动)。监听器通过 `agent.inject()` 注入上下文。 +- `agent/session-start(agent, source)` ——emit,在第 1 轮次之前触发一次,携带 `SessionStartSource`(`startup` 表示全新/fork 创建,`resume` 表示重新加载的持久化会话;`clear`/`compact` 保留)。纯通知,不能阻塞启动(这是有意的空白:桥接可以记录/注入,但不管控启动)。监听器通过 `agent.inject()` 注入上下文。 - `agent/prompt-submit(agent, content, source, next) → PromptDecision` ——waterfall,在已开启的轮次内、`user/message` 追加之前,对每条出队的排队消息触发。`allow`(可选地重写 prompt `content` 或附加 `additionalContext`)或 `block`(丢弃该 prompt;循环在其位置追加一条持久的 `prompt/blocked`——见下方调度说明)。 **`agent/turn-continuation`** 接收并返回一个 `ContinuationDecision`。`{action:'continue', reason?}` 可携带面向模型的上下文,记录为同一轮次内的下一步 steering(中途引导)——与 `/goal` step-end-steer 模式互为类型化孪生。 @@ -38,7 +38,7 @@ harness 需要一套钩子子系统:用户像 Claude Code(CC)和 Codex 那 1. **在 prompt 策略之前开启轮次。** 全部被阻止的批次成为零步骤的 `rejected` 轮次,保持封闭性并为 ACP(Agent Client Protocol)提供持久的终结事件。每次否决还记录 `prompt/blocked`(含原始 prompt 和原因),因此混合批次保留被阻止的输入。允许的 `additionalContext` 注入到已开启的轮次中。 -2. **Post-tool `additionalContext` 被缓冲,在所有 `tool/result` 之后追加。** `content`/`feedback` 塑造 `execute()` 返回的结果,但 `additionalContext` 是一条**独立的** `context/message`,而单个步骤可以携带多个工具调用。如果在每个结果之后立即追加上下文,会产生 `result(c1) → context → result(c2)` 的交错,破坏工具调用/结果的邻接性。因此 `execute()` 将 `additionalContext` 暴露在其 `ToolExecutionResult` 上,循环为该步骤的每次调用缓冲上下文,仅在所有 `tool/result` 追加完毕后才以 `context/message` 形式追加。 +2. **Post-tool `additionalContext` 被缓冲,在所有 `tool/result` 之后追加。** `content`/`feedback` 塑造 `execute()` 返回的结果,但 `additionalContext` 是一条独立的 `context/message`,而单个步骤可以携带多个工具调用。如果在每个结果之后立即追加上下文,会产生 `result(c1) → context → result(c2)` 的交错,破坏工具调用/结果的邻接性。因此 `execute()` 将 `additionalContext` 暴露在其 `ToolExecutionResult` 上,循环为该步骤的每次调用缓冲上下文,仅在所有 `tool/result` 追加完毕后才以 `context/message` 形式追加。 3. **强制 `continue` 的 `reason` 通过 steering 通道入队**,使得下一步骤在循环顶部排空时将其记录为当前轮次的 steering——同一轮次内的下一*步骤* steering,而非下一*轮次*的 prompt(与现有的 `hasSteering` 强制继续覆盖一致)。 diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml index c05a025ca6..b06ccc29d9 100644 --- a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml @@ -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 -2026-06-30-session-store-fork-api.md: 4bf5c3fe43821570fd947034358e54d0a0a602f9 -2026-06-30-session-store-fork-api.zh.md: a3ffb881a446647861fa5fbaf57dde291838a090 +2026-06-30-session-store-fork-api.md: c5359a30124aabf0f9f809ffe899c6ad5fca8051 +2026-06-30-session-store-fork-api.zh.md: 62f399df41488143a66069fdd5a36ddb3e62421f diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md index 4bf5c3fe43..c5359a3012 100644 --- a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.md @@ -1,9 +1,9 @@ # RFC: SessionStore fork API -English | [中文](2026-06-30-session-store-fork-api.zh.md) - Status: implemented +English | [中文](2026-06-30-session-store-fork-api.zh.md) + ## Problem The event-sourced session log already has the primitive a fork needs: create a new session with a seed event prefix, then derive model history from that seeded log exactly as replay does. That primitive is intentionally low-level: `ctx.sessions.create(id, { seed, meta })` accepts any valid seed, but ordinary live-session branching needs policy around which prefix can be copied, which metadata is stamped on the child, and how errors are classified. diff --git a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md index a3ffb881a4..62f399df41 100644 --- a/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-session-store-fork-api.zh.md @@ -1,9 +1,9 @@ -# RFC:SessionStore fork API - -[English](2026-06-30-session-store-fork-api.md) | 中文 +# RFC: SessionStore fork API Status: implemented +[English](2026-06-30-session-store-fork-api.md) | 中文 + ## 问题 事件溯源的会话日志已经具备 fork 所需的原语:创建一个带有种子事件前缀的新会话,然后像回放一样从该种子日志推导模型历史。这个原语有意保持底层:`ctx.sessions.create(id, { seed, meta })` 接受任何合法种子,但常规的活跃会话分支需要围绕以下问题制定策略:哪些前缀可以被复制、子会话应打上哪些元数据、以及错误如何分类。 diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml index 90b6939da2..cb9c05d033 100644 --- a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml @@ -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 -2026-06-30-subagent-observe-enrich.md: b48a1fff32130345e669a3b3b905c4fda987e41e -2026-06-30-subagent-observe-enrich.zh.md: 8ce070001e219572658fd4e94c660de1094ddee5 +2026-06-30-subagent-observe-enrich.md: 1e20ddff5473a23f3ed560246fbd06f8090852ae +2026-06-30-subagent-observe-enrich.zh.md: 6bc00c9a8f1d3656fbbfc482e3e6b66020298dd9 diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md index b48a1fff32..1e20ddff54 100644 --- a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.md @@ -1,9 +1,9 @@ # RFC: Subagent lifecycle enrichment — lastAssistantMessage (observe-only) -English | [中文](2026-06-30-subagent-observe-enrich.zh.md) - Status: implemented +English | [中文](2026-06-30-subagent-observe-enrich.zh.md) + ## Problem The hooks subsystem ([interception seams RFC](2026-06-30-interception-seams.md)) lets a plugin observe and gate the agent at lifecycle points. Claude Code and Codex both expose **SubagentStart / SubagentStop** hooks, and CC's carry the subagent's final message. The harness already emits `subagent/start` and `subagent/end` lifecycle events ([the subagent capability-seam](2026-06-21-subagent-capability-seam.md)), but their payloads were minimal (`provider`, `id`, and on end `stopReason`) — not enough for a hooks bridge to report WHAT a subagent produced without separately reaching for the live run. diff --git a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md index 8ce070001e..6bc00c9a8f 100644 --- a/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md +++ b/docs/rfc/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md @@ -1,4 +1,4 @@ -# RFC:Subagent 生命周期丰富化——lastAssistantMessage(仅观察) +# RFC: Subagent 生命周期丰富化——lastAssistantMessage(仅观察) Status: implemented diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml index 25c723bde1..bcf9d40b91 100644 --- a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml @@ -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 -2026-07-05-dynamic-workflows.md: 67ceebf7017f197bd800fd339b575390b3b936c1 -2026-07-05-dynamic-workflows.zh.md: 54ba0d903de228e14a53e6f64ead0f5156e61289 +2026-07-05-dynamic-workflows.md: e6f2ab9a4fc5f5403a7739495be7d82ebce3ec0d +2026-07-05-dynamic-workflows.zh.md: 82234c2405f972f2c42c58be6772f55eda500455 diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md index 67ceebf701..e6f2ab9a4f 100644 --- a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md @@ -1,9 +1,9 @@ # RFC: Dynamic workflows — a script-driven multi-agent orchestration seam -English | [中文](2026-07-05-dynamic-workflows.zh.md) - Status: implemented +English | [中文](2026-07-05-dynamic-workflows.zh.md) + ## Problem The harness can delegate ONE task to ONE child (`dsh-tool-subagent`), but work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — forces the model to orchestrate turn by turn: every intermediate result lands in the parent context, the plan lives nowhere durable, and coordination costs a model round-trip per step. Claude Code ships this capability as [dynamic workflows](https://code.claude.com/docs/en/workflows): the model writes a JavaScript orchestration script, a runtime executes it, and the script — not the conversation — holds the loop, the branching, and the intermediate results. diff --git a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md index 54ba0d903d..82234c2405 100644 --- a/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md +++ b/docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.zh.md @@ -1,9 +1,9 @@ -# RFC:动态工作流——脚本驱动的多 agent 编排 seam - -[English](2026-07-05-dynamic-workflows.md) | 中文 +# RFC: 动态工作流——脚本驱动的多 agent 编排 seam Status: implemented +[English](2026-07-05-dynamic-workflows.md) | 中文 + ## 问题 harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`),但需要扇出到多个独立部分的工作——跨多文件审计、迁移、多角度调研、对抗式验证——迫使模型逐轮次编排:每个中间结果都落入父上下文,计划无处持久存储,每一步的协调都要消耗一次模型往返。Claude Code 以 [dynamic workflows](https://code.claude.com/docs/en/workflows) 的形式提供了这一能力:模型编写一段 JavaScript 编排脚本,运行时执行它,由脚本(而非对话)持有循环、分支和中间结果。 @@ -16,11 +16,11 @@ harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`) 一次工作流调用包含 JSON `meta`(`name`、`description`,以及可选的 `whenToUse`/`phases`)和一段支持顶层 `await` 并返回 JSON 值的 JavaScript `script` 正文。元数据作为数据校验,从不被执行。正文接收 `agent(prompt, options)`、`parallel(thunks)`、`pipeline(items, ...stages)`、`phase(title)`、`log(message)` 和 `args`。pipeline 各阶段接收 `(prev, item, index)`,阶段之间无屏障;失败的子 agent 和普通阶段错误将受影响的 item 解析为 `null` 并跳过其剩余阶段。Claude Code 的确定性限制通过日志化延迟处理,因此兼容的脚本正文在将 meta 头移入参数后可以使用时钟和随机数。 -与 CC 有一处刻意的严格性**差异**:钩子误用——未知或延迟的选项(`effort`/`isolation`/`agentType`)、格式错误的参数、超出支持子集的 schema、触发上限、seam 启动失败——会抛出带 `fatal: true` 的 `WorkflowError`,组合器会**重新抛出** fatal 错误而非将 item 置为 null。如果不这样做,一个拼错的选项会悄然变成一个与子 agent 失败无法区分的 `null`——这正是本仓库禁止的「被接受后被忽略」的失败模式。另有一处新增:工具的 `args` 参数是一个 JSON **对象**(裸列表被包装为一个字段),使协议格式(wire format)保持诚实。 +与 CC 有一处刻意的严格性差异:钩子误用——未知或延迟的选项(`effort`/`isolation`/`agentType`)、格式错误的参数、超出支持子集的 schema、触发上限、seam 启动失败——会抛出带 `fatal: true` 的 `WorkflowError`,组合器会重新抛出 fatal 错误而非将 item 置为 null。如果不这样做,一个拼错的选项会悄然变成一个与子 agent 失败无法区分的 `null`——这正是本仓库禁止的「被接受后被忽略」的失败模式。另有一处新增:工具的 `args` 参数是一个 JSON 对象(裸列表被包装为一个字段),使协议格式(wire format)保持诚实。 ### seam(dsh-workflow) -`ctx.workflows` 是 bash 形态的抽象 `WorkflowService`——每个上下文一个引擎,无命名提供方注册表(引擎是部署级替换,不是共存者)。`start(request)` 对无法启动的脚本同步抛出;返回的 `WorkflowRun` 的 `result` **永不** reject(失败解析为 `stopReason: 'error' | 'cancelled'`)。`workflow/*` 事件是仅观察的 emit,携带**数据快照**(id + meta;`workflow/end` 省略 result 值),按监听器隔离,与 `subagent/start`/`subagent/end` 对称——控制权留在 run 的持有者手中。词汇详情见 [core-data-structures/workflow.md](../../../core-data-structures/workflow.md)。 +`ctx.workflows` 是 bash 形态的抽象 `WorkflowService`——每个上下文一个引擎,无命名提供方注册表(引擎是部署级替换,不是共存者)。`start(request)` 对无法启动的脚本同步抛出;返回的 `WorkflowRun` 的 `result` 永不 reject(失败解析为 `stopReason: 'error' | 'cancelled'`)。`workflow/*` 事件是仅观察的 emit,携带数据快照(id + meta;`workflow/end` 省略 result 值),按监听器隔离,与 `subagent/start`/`subagent/end` 对称——控制权留在 run 的持有者手中。词汇详情见 [core-data-structures/workflow.md](../../../core-data-structures/workflow.md)。 ### 引擎(dsh-workflow-workerthread):每次运行一个 worker 线程 @@ -38,7 +38,7 @@ harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`) ### 消费方(dsh-tool-workflow) -一个 `workflow` 工具,镜像 `dsh-tool-subagent` 的同步形态:启动、await、`try/finally` dispose、abort 桥接 `exec.signal`、非 `completed` → `isError`。渲染意图:一张以调用的 `meta.name` 参数为标题的 `generic` 卡片(展示是参数的纯函数)。工具描述**即**面向模型的编写规范。使用策略以工具自身的 `tool:<toolName>` prompt 段落随工具发布(显式请求才使用的引导——工具引导存在于工具插件中,从不在部署 persona 中);harness 没有 ultracode 风格的 effort 门控。 +一个 `workflow` 工具,镜像 `dsh-tool-subagent` 的同步形态:启动、await、`try/finally` dispose、abort 桥接 `exec.signal`、非 `completed` → `isError`。渲染意图:一张以调用的 `meta.name` 参数为标题的 `generic` 卡片(展示是参数的纯函数)。工具描述即面向模型的编写规范。使用策略以工具自身的 `tool:<toolName>` prompt 段落随工具发布(显式请求才使用的引导——工具引导存在于工具插件中,从不在部署 persona 中);harness 没有 ultracode 风格的 effort 门控。 ### 基础:subagent seam 上的结构化输出 diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml b/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml index 3b3aed7c50..31fb9e006f 100644 --- a/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.i18n.yaml @@ -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 -2026-07-05-skill-system.md: 6cfd1f977ae5a1e1ad646a707a4201e57d46bc38 -2026-07-05-skill-system.zh.md: f59fd5d850a38d7324b391a116c72c4e71ef7401 +2026-07-05-skill-system.md: f39b5f5766eadf7c0a7bfd3f887aca60f69477af +2026-07-05-skill-system.zh.md: 0aff262792a6f8a38a02475d6975510d5aae5da5 diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.md b/docs/rfc/implemented/feature/2026-07-05-skill-system.md index 6cfd1f977a..f39b5f5766 100644 --- a/docs/rfc/implemented/feature/2026-07-05-skill-system.md +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.md @@ -1,9 +1,9 @@ # RFC: Skill system — progressive disclosure instructions for agents -English | [中文](2026-07-05-skill-system.zh.md) - Status: implemented +English | [中文](2026-07-05-skill-system.zh.md) + ## Problem Agent products have converged on a skill pattern: keep the request prompt small by listing only available instruction bundles, then load the full body when the model decides a task matches. Codex, Claude Code, OpenCode, and Kimi Code differ in details, but all separate discovery metadata from complete instructions so a workspace can carry reusable behavior without paying the full prompt cost on every turn. diff --git a/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md b/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md index f59fd5d850..0aff262792 100644 --- a/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md +++ b/docs/rfc/implemented/feature/2026-07-05-skill-system.zh.md @@ -1,9 +1,9 @@ -# RFC:Skill 系统——面向 agent 的渐进式指令披露 - -[English](2026-07-05-skill-system.md) | 中文 +# RFC: Skill 系统——面向 agent 的渐进式指令披露 Status: implemented +[English](2026-07-05-skill-system.md) | 中文 + ## 问题 Agent(智能体)产品已趋同于一种 skill(技能)模式:保持请求提示词精简,仅列出可用的指令包,当模型判定某任务匹配时再加载完整正文。Codex、Claude Code、OpenCode 与 Kimi Code 在细节上各有不同,但都将发现元数据与完整指令分离,使工作区能承载可复用的行为而无需在每个轮次支付全量提示词开销。 diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml index 8d7fa05dfc..fe71c00352 100644 --- a/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.i18n.yaml @@ -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 -2026-07-06-approval-seam.md: 3ef51c31216bf9f0c5d945748ab3f901ec82147c -2026-07-06-approval-seam.zh.md: 1bf679426a434c36f5363c3b70f13a8f24534df3 +2026-07-06-approval-seam.md: dedcc2022382af7a614023e4354b77f1c15cd92f +2026-07-06-approval-seam.zh.md: 193461a2e5c3c14efe4b1565656cc38baab11fcb diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.md b/docs/rfc/implemented/feature/2026-07-06-approval-seam.md index 3ef51c3121..dedcc20223 100644 --- a/docs/rfc/implemented/feature/2026-07-06-approval-seam.md +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.md @@ -1,9 +1,9 @@ # RFC: The approval seam — one-shot permission decisions over a waterfall of answerers -English | [中文](2026-07-06-approval-seam.zh.md) - Status: implemented +English | [中文](2026-07-06-approval-seam.zh.md) + ## Problem Two callers need to put one question — "may this specific action proceed?" — to a human: `tools/pre-execute`'s `ask` decision (including the Claude-Code hook bridge's `permissionDecision: ask`) and the [sandbox RFC](2026-07-06-sandbox.md)'s post-denial one-shot escalation retry. A shared seam keeps them from inventing separate outcome vocabularies, UI routing, cancellation, and audit trails, while guaranteeing that a deployment with no UI can never grant an unanswerable request. diff --git a/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md b/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md index 1bf679426a..193461a2e5 100644 --- a/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md +++ b/docs/rfc/implemented/feature/2026-07-06-approval-seam.zh.md @@ -1,4 +1,4 @@ -# RFC:审批 seam——基于 waterfall(瀑布式事件)应答者的一次性权限决策 +# RFC: 审批 seam——基于 waterfall(瀑布式事件)应答者的一次性权限决策 Status: implemented @@ -12,7 +12,7 @@ Status: implemented ## 决策 -一个包 `dsh-user-approval`(`packages/ui/user-approval`),拥有词汇表和 `ctx.approval` 服务——即**机制**。**策略**——谁来应答、某个会话是否需要被询问——不在其中:应答者是 `approval/request` waterfall 监听器,由拥有通道的插件注册(ACP 桥、未来的终端 UI、测试脚本),而每会话的策略层可以在任何人类介入之前做出决定。消费方(`dsh-tools` 的 ask 路由、沙箱升级门禁)将问题解析为一个封闭结果,并从中派生各自的工具结果。刻意设计为**一个**包,而非能力 seam 的三包拆分(见「替代方案」)。 +一个包 `dsh-user-approval`(`packages/ui/user-approval`),拥有词汇表和 `ctx.approval` 服务——即机制。策略——谁来应答、某个会话是否需要被询问——不在其中:应答者是 `approval/request` waterfall 监听器,由拥有通道的插件注册(ACP 桥、未来的终端 UI、测试脚本),而每会话的策略层可以在任何人类介入之前做出决定。消费方(`dsh-tools` 的 ask 路由、沙箱升级门禁)将问题解析为一个封闭结果,并从中派生各自的工具结果。刻意设计为一个包,而非能力 seam 的三包拆分(见「替代方案」)。 ### 部署如何使用它 @@ -95,7 +95,7 @@ ACP 桥找到拥有该会话的编辑器,为该 `callId` 发送 `session/reque ## 曾考虑的替代方案 - **单一注册提供方而非 waterfall 监听器**:否决。`registerProvider()` 接口迫使所有组合问题——允许列表预过滤、外部钩子决策者、脚本化测试应答、人类前面的策略门禁——都塞进一个提供方实现。waterfall 从运行时已有的机制中获得组合能力、缺失时失败关闭和 HMR(热模块替换) dispose(资源释放);seam 的 JSDoc 以约定固定单决策槽语义,而非发明一个提供方注册表。 -- **在 ACP 桥中内联 `tools/pre-execute` 权限门禁**:否决。对桥拥有的每次调用都弹出提示,会将请求**策略**硬编码进 UI 插件,无法服务第二个发起方(沙箱升级发生在执行开始之后,没有 pre-execute 时刻),且钩子产生的 `ask` 决策没有共享机制。 +- **在 ACP 桥中内联 `tools/pre-execute` 权限门禁**:否决。对桥拥有的每次调用都弹出提示,会将请求策略硬编码进 UI 插件,无法服务第二个发起方(沙箱升级发生在执行开始之后,没有 pre-execute 时刻),且钩子产生的 `ask` 决策没有共享机制。 - **通用用户交互 seam(`ctx.userInteraction`)**:否决作为审批机制。二者骨架相似(按 agent 路由、阻塞等待人类、处理缺失),但审批的契约在每个关键维度上都更窄:封闭的结果词汇而非自由文本、附着在工具调用上的协议原生提示而非通用表单、强制的缺失时失败关闭、以及审计事件。因此审批不走已交付的 `packages/ui/user-interaction` / `ask_user_question` 引出路径——引出表单不是权限提示,自由文本应答不是封闭结果;如果二者将来趋同,共享提供方管道仍然开放。 - **`dsh-tools` 中的静态可选注入**:否决。vendor 的 Cordis `Inject` 类型没有 optional 标志——对象形式将服务名映射到拦截配置,声明的 inject 会阻塞 fiber。`ctx.get('approval')` 是文档化的机会性消费模式(`tool-bash` 的 owner-token 查找、loop 的持久化探测),按调用读取存在性,跨 HMR 正确降级,无需额外机制。 - **能力 seam 的三包拆分**:否决。接口/实现/消费方适合实现可替换的 seam(bash-local vs bash-sandbox)。此处服务体是固定机制,可变部分是留在各自通道拥有者插件中的监听器——拆分只会制造一个空的实现包(「不要预防性拆分」)。 diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml index 0e418c8e57..53215fce5e 100644 --- a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml @@ -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 -2026-07-06-explicit-tool-order.md: 9d94496ffdcbc4c7df820581b02e3e075ec1c0be -2026-07-06-explicit-tool-order.zh.md: 0b020f969299799289e18ed93c81db08cabc0b2d +2026-07-06-explicit-tool-order.md: b5f37239efc856866f08d93ab80eba91145a34db +2026-07-06-explicit-tool-order.zh.md: eca75499c2505c9cac0135ddb2ffc8cdd989b100 diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md index 9d94496ffd..b5f37239ef 100644 --- a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md @@ -1,9 +1,9 @@ # RFC: Explicit model-facing tool order -English | [中文](2026-07-06-explicit-tool-order.zh.md) - Status: implemented +English | [中文](2026-07-06-explicit-tool-order.zh.md) + ## Problem Model-facing tool order followed plugin registration order, which depends on concurrent module loading for otherwise independent plugins. That race produced different request headers in CI and snapshot recordings. Because order affects request bytes, caching, and the durable header, it needs an explicit deterministic policy. diff --git a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md index 0b020f9692..eca75499c2 100644 --- a/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md +++ b/docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.zh.md @@ -1,9 +1,9 @@ -# RFC:显式的模型侧工具顺序 - -[English](2026-07-06-explicit-tool-order.md) | 中文 +# RFC: 显式的模型侧工具顺序 Status: implemented +[English](2026-07-06-explicit-tool-order.md) | 中文 + ## 问题 模型侧的工具顺序此前跟随插件注册顺序,而注册顺序取决于相互独立的插件的并发模块加载。这种竞态在 CI 和快照录制中产生了不同的请求头。由于顺序影响请求字节、缓存和持久化的 header,因此需要一个显式的确定性策略。 diff --git a/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml b/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml index 8c97f0b5ee..87137ea20f 100644 --- a/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-06-sandbox.i18n.yaml @@ -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 -2026-07-06-sandbox.md: 29985b9336e7a190c90dc0e9c3b3aa78b6197e8e -2026-07-06-sandbox.zh.md: 4285ae4ceb81ee57dc3ab3d51467f9267743e06e +2026-07-06-sandbox.md: 0df97717c9166d5160189c840b108acecd3d3291 +2026-07-06-sandbox.zh.md: 164e44f6b7c84d8f279b0146cc3c74299a51d1fa diff --git a/docs/rfc/implemented/feature/2026-07-06-sandbox.md b/docs/rfc/implemented/feature/2026-07-06-sandbox.md index 29985b9336..0df97717c9 100644 --- a/docs/rfc/implemented/feature/2026-07-06-sandbox.md +++ b/docs/rfc/implemented/feature/2026-07-06-sandbox.md @@ -1,9 +1,9 @@ # RFC: The subprocess sandbox — confinement seam, native runners, escalation, and per-session modes -English | [中文](2026-07-06-sandbox.zh.md) - Status: implemented +English | [中文](2026-07-06-sandbox.zh.md) + ## Problem A coding agent needs this product path: bash subprocesses — and the hook commands that ride them — execute under a restricted file sandbox by default; if and only if the sandbox actually denies an operation, the model may request one user approval for that same operation and, once granted, retry it once with wider permissions. An every-tool boundary is deliberately NOT the claim: fs/web/todo execute in-process where an `execve` wrapper is meaningless (§ In-process tools), and the cross-family boundary is staged follow-up work (§ Deferred phases). Without a shared vocabulary, every tool reinvents approval fields, denial parsing, retry matching, and permission-state hints. diff --git a/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md b/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md index 4285ae4ceb..164e44f6b7 100644 --- a/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md +++ b/docs/rfc/implemented/feature/2026-07-06-sandbox.zh.md @@ -1,4 +1,4 @@ -# RFC:子进程沙箱——约束 seam、原生 runner、升级机制与按会话模式 +# RFC: 子进程沙箱——约束 seam、原生 runner、升级机制与按会话模式 Status: implemented @@ -8,7 +8,7 @@ Status: implemented 一个编码 agent 需要如下产品路径:bash 子进程(以及依附其上的钩子命令)默认在受限的文件沙箱下执行;当且仅当沙箱实际拒绝了某个操作时,模型可以为同一操作请求一次用户批准,获批后以更宽的权限重试一次。本设计刻意不声称覆盖所有工具:fs/web/todo 在进程内执行,`execve` 包装对它们毫无意义(§ 进程内工具);跨工具族的统一边界属于分阶段后续工作(§ 延迟阶段)。如果没有共享词汇,每个工具都会各自重新发明批准字段、拒绝解析、重试匹配和权限状态提示。 -harness 是一个 SDK,因此约束必须是开发者可**组合**的能力:是否启用沙箱、每个平台使用哪个后端,都应作为一等条目写在叶子 `cordis.yml` 中,而非藏在某个执行器的私有机制里。而首选 runner `bwrap` 恰恰在沙箱最重要的主机上不可用(精简容器、禁用了非特权 userns、LSM 拒绝 `mount`),因此备选 runner 必须随 SDK 一起交付,而不能假设主机已有。 +harness 是一个 SDK,因此约束必须是开发者可组合的能力:是否启用沙箱、每个平台使用哪个后端,都应作为一等条目写在叶子 `cordis.yml` 中,而非藏在某个执行器的私有机制里。而首选 runner `bwrap` 恰恰在沙箱最重要的主机上不可用(精简容器、禁用了非特权 userns、LSM 拒绝 `mount`),因此备选 runner 必须随 SDK 一起交付,而不能假设主机已有。 仅有约束还留下两个缺口。拒绝后没有升级路径就是死路:模型只能放弃,这会迫使运维人员全局配置 `workspace-write` 或 `danger-full-access`,从而使沙箱形同虚设。而模型可见的旋钮(沙箱模式、批准策略)在 agent 生命周期内会变化——ACP 用户切换按会话设置、运维人员在进程停止期间编辑 `cordis.yml`——模型绝不能基于过时的信念行动:每次请求时的实际状态是什么、agent 存活期间发生了什么变化、无人看管时又发生了什么变化,都需要有明确答案。 @@ -50,11 +50,11 @@ OS 子进程约束适用于 bash 执行器(包括钩子命令),后续还 #### seam:`ctx.sandbox` -`dsh-sandbox` 拥有词汇和 `SandboxProvider` 契约:`confine(argv, policy)` 返回调用方应当 spawn 的替代 argv(经过包装,使进程及其所有子进程在约束下运行),加上所选后端达到的 `enforcement` 完整度、其拒绝方言(`denialSignatures`,该后端内核在拒绝文件操作时打印到 stderr 的子串)、以及其 runner 失败方言(`runnerFailureSignatures`,runner **本身**失败——因而命令从未运行——时的自我标识方式);没有可用后端时抛出失败关闭的 `SANDBOX_UNAVAILABLE` 错误,绝不静默放行。词汇:`SandboxMode`(`read-only` / `workspace-write` / `danger-full-access`,仅限文件操作——不声称覆盖网络和进程可见性)、`SandboxEnforcement`(`full` / `partial`)、`SandboxPolicy`(mode + workspace root)。 +`dsh-sandbox` 拥有词汇和 `SandboxProvider` 契约:`confine(argv, policy)` 返回调用方应当 spawn 的替代 argv(经过包装,使进程及其所有子进程在约束下运行),加上所选后端达到的 `enforcement` 完整度、其拒绝方言(`denialSignatures`,该后端内核在拒绝文件操作时打印到 stderr 的子串)、以及其 runner 失败方言(`runnerFailureSignatures`,runner 本身失败——因而命令从未运行——时的自我标识方式);没有可用后端时抛出失败关闭的 `SANDBOX_UNAVAILABLE` 错误,绝不静默放行。词汇:`SandboxMode`(`read-only` / `workspace-write` / `danger-full-access`,仅限文件操作——不声称覆盖网络和进程可见性)、`SandboxEnforcement`(`full` / `partial`)、`SandboxPolicy`(mode + workspace root)。 -策略随每次**调用**而非提供方携带:两个消费方可以在同一时刻以不同策略约束(bash 在 `read-only` 下运行,而一个受约束的子 agent 保持其状态目录可写),且经批准的升级重试是一次带有更宽策略的新调用——在配置固定的提供方模式下无法表达。 +策略随每次调用而非提供方携带:两个消费方可以在同一时刻以不同策略约束(bash 在 `read-only` 下运行,而一个受约束的子 agent 保持其状态目录可写),且经批准的升级重试是一次带有更宽策略的新调用——在配置固定的提供方模式下无法表达。 -该 seam 仅约束**同世界**子进程:后端共享主机的文件系统和内核。容器、microVM 和远程执行器不是此 seam 的后端——它们以环境一致的组替换整个能力实现(`ctx.bash`、`ctx.fs`),因为一个 bash 在容器中运行而 fs 工具写主机的 agent 生活在两个割裂的世界中。 +该 seam 仅约束同世界子进程:后端共享主机的文件系统和内核。容器、microVM 和远程执行器不是此 seam 的后端——它们以环境一致的组替换整个能力实现(`ctx.bash`、`ctx.fs`),因为一个 bash 在容器中运行而 fs 工具写主机的 agent 生活在两个割裂的世界中。 留待需要时再决定:网络限制是作为独立的 `network_mode` 到来,还是在某个 runner 同时强制两者后合并进 `sandbox_mode`;以及 `SandboxPolicy` 是现在就增加额外的可写根授权(launcher 已支持 `--rw <path>`),还是等到升级机制需要时再加。 @@ -80,7 +80,7 @@ FIXME: Revisit the separate-repository boundary and try to maintain the launcher `BashExecRequest.sandboxMode` 是可选的按调用输入;解析后的 spec 使该字段显式。`BashExecutor.sandboxMode` 公布已挂载的执行器能否兑现它,因此只有约束组合才暴露升级。seam 接受任何显式模式;工具拥有「仅更宽」的升级规则。非沙箱执行器诚实地保持无约束。 -`SandboxBashExecutor.resolve()` 盖章有效模式——升级授权 > 会话覆盖 > 配置默认——使 `run()`/`start()` 读取 spec 而非配置。`danger-full-access` 分支、confine 调用和结果事实都以 spec 的模式为键,且按任务的事实 map 携带每个任务的模式及其包装事实(`notifyTaskDone()` 从 map 条目盖章):一次升级调用——前台或后台——报告它**实际**运行的模式,而每个邻居保持自己的。 +`SandboxBashExecutor.resolve()` 盖章有效模式——升级授权 > 会话覆盖 > 配置默认——使 `run()`/`start()` 读取 spec 而非配置。`danger-full-access` 分支、confine 调用和结果事实都以 spec 的模式为键,且按任务的事实 map 携带每个任务的模式及其包装事实(`notifyTaskDone()` 从 map 条目盖章):一次升级调用——前台或后台——报告它实际运行的模式,而每个邻居保持自己的。 当约束执行器被挂载时,`bash` 公布配对的 `sandbox_permissions` 和 `justification` 字段。schema 暴露完整的封闭升级词汇,因为有效模式是按会话的;执行拒绝任何不严格宽于该调用有效模式的目标。批准在执行之前解析。`allowed-once` 仅将授权模式盖章到该请求上,而 `rejected`、`cancelled`、`unavailable`、缺失的 approval 服务或缺失的 agent 都以各自不同的结果文本失败关闭。授权不持久化。 @@ -94,7 +94,7 @@ FIXME: Revisit the separate-repository boundary and try to maintain the launcher effective(session) = findLast(the session's own knob events)?.value ?? the composition-config default ``` -默认值是组合配置(`cordis.yml`)——运维人员拥有,进程范围。运行时切换是**会话范围**的覆盖,记录为该会话自身日志中的一条仅日志事件。重启免疫(恢复会话时回放其日志,覆盖自然恢复,无需追赶机制)和多会话隔离(一个编辑器标签页的 `workspace-write` 不会干扰另一个的 `read-only`)都是构造性的自然结果,且不存在任何外部配置存储。 +默认值是组合配置(`cordis.yml`)——运维人员拥有,进程范围。运行时切换是会话范围的覆盖,记录为该会话自身日志中的一条仅日志事件。重启免疫(恢复会话时回放其日志,覆盖自然恢复,无需追赶机制)和多会话隔离(一个编辑器标签页的 `workspace-write` 不会干扰另一个的 `read-only`)都是构造性的自然结果,且不存在任何外部配置存储。 **每个旋钮一种事件,由其领域拥有**——这是每个既有事件族已遵循的可合并扩展 `SessionEventMap` 惯用法(`dsh-user-approval` 中的 `approval/*`、hooks 包中的 `hook/*`): @@ -105,13 +105,13 @@ interface SessionEventMap { } ``` -每个拥有者导出相同的三件套:事件声明、纯 fold(`effectiveSandboxMode(events)` / `effectiveApprovalPolicy(events)`——一个 `findLast`,类型化到领域的封闭联合),以及**唯一的**写入路径(`setSandboxMode(session, mode)` / `setApprovalPolicy(session, policy)`——切换即其事件;没有任何东西在带外修改状态)。无共享拥有者服务、无通用 facts map、无注册表:第三个旋钮只需将约 40 行模式复制到自己的包中。执行在两侧都遵循 fold——bash 工具的按调用盖章将其作为 § 升级机制优先级链的中间层读取,approval seam 的 `'never'` 门控是[批准 RFC](2026-07-06-approval-seam.md) 同一模式的另一侧。 +每个拥有者导出相同的三件套:事件声明、纯 fold(`effectiveSandboxMode(events)` / `effectiveApprovalPolicy(events)`——一个 `findLast`,类型化到领域的封闭联合),以及唯一的写入路径(`setSandboxMode(session, mode)` / `setApprovalPolicy(session, policy)`——切换即其事件;没有任何东西在带外修改状态)。无共享拥有者服务、无通用 facts map、无注册表:第三个旋钮只需将约 40 行模式复制到自己的包中。执行在两侧都遵循 fold——bash 工具的按调用盖章将其作为 § 升级机制优先级链的中间层读取,approval seam 的 `'never'` 门控是[批准 RFC](2026-07-06-approval-seam.md) 同一模式的另一侧。 沙箱模式不在提示词中叙述;拒绝结果在需要时报告模式,避免基于常驻标签的预防性拒绝。批准策略不同:只有 `'never'` 被声明,因为自动拒绝在行为上与用户的「不」无法区分。策略变更通知被合并,由下一个 pre-step 递送,重启后有基于日志的回退。通知来源从事件位置推断:最后一个 request header 之后的旋钮事件是用户驱动的;未记录的漂移是运维人员或配置驱动的。 **编辑器界面**是协议原生的 [Session Config Options](https://agentclientprotocol.com/protocol/session-config-options)——该规范对 session modes 的替代(计划在 ACP v2 中移除),已有 SDK 类型。当 `ctx.permission` 被组合时,bridge 在 `session/new` 和 `session/load` 中公布一个 `permission` 选择器(category `mode`);其选项是部署的 preset 表,其 `currentValue` 是 `PermissionService.current()` 对会话日志加组合默认值的结果。随附的 `workspace-write` 和 `danger-full-access` preset 各自捆绑一个沙箱模式与一个批准策略,并写入两个领域 setter;preset 表之外的旋钮组合报告为仅可切换离开的 `custom`。`session/set_config_option` 通过 permission 服务验证并切换,然后返回完整的刷新状态(规范契约)。 -**轮次封闭是提交边界。**开放轮次中的切换立即追加。空闲切换保持在 bridge 记录上待定,在下一次 prompt 提交时、assembly 或执行之前追加到开放轮次中;每个旋钮以最后写入为准。开放性来自日志边界而非 `agent.status`,setter 不从 `session/event` 监听器内追加,因为那会重排后续观察者。锚定之前,响应叠加待定值。崩溃丢弃它,重新加载返回持久 fold。 +**轮次封闭是提交边界。** 开放轮次中的切换立即追加。空闲切换保持在 bridge 记录上待定,在下一次 prompt 提交时、assembly 或执行之前追加到开放轮次中;每个旋钮以最后写入为准。开放性来自日志边界而非 `agent.status`,setter 不从 `session/event` 监听器内追加,因为那会重排后续观察者。锚定之前,响应叠加待定值。崩溃丢弃它,重新加载返回持久 fold。 #### 进程内工具 @@ -121,10 +121,10 @@ FIXME: Revisit this tool-local boundary. The follow-up design needs to determine ### 测试 -- **单元测试:**固定平台选择和 profile、失败关闭的 runner 分类、按调用事实、升级验证和结果、permission preset fold 和写入透传、叙述器合并、ACP 公布和验证、轮次封闭的配置写入。 -- **Keyless 真实 runner:**在提供方和 bash 消费方层面对 bwrap、Landlock 和 Seatbelt 执行真实文件系统效果测试;packed-install 覆盖率证明注册表 launcher 保持可执行。真实 ACP 组合固定 permission 切换并拒绝未知 preset。CI 拒绝静默全跳过。 -- **With-key:**驱动真实模型、runner、bridge 应答器和磁盘效果通过授权和拒绝的升级;不可用的凭证或 runner 自动跳过。 -- **快照:**固定 permission config-option 协议格式(wire format)、preset 和旋钮事件、prompt delta 和通知、以及两个脚本化的 approval 分支。快照模式以无约束启动,使无关 fixture(测试前置数据)保持平台无关;策略场景显式切换。真实拒绝 stderr 留在平台测试中,因为其方言是 runner 特定的。 +- **单元测试:** 固定平台选择和 profile、失败关闭的 runner 分类、按调用事实、升级验证和结果、permission preset fold 和写入透传、叙述器合并、ACP 公布和验证、轮次封闭的配置写入。 +- **Keyless 真实 runner:** 在提供方和 bash 消费方层面对 bwrap、Landlock 和 Seatbelt 执行真实文件系统效果测试;packed-install 覆盖率证明注册表 launcher 保持可执行。真实 ACP 组合固定 permission 切换并拒绝未知 preset。CI 拒绝静默全跳过。 +- **With-key:** 驱动真实模型、runner、bridge 应答器和磁盘效果通过授权和拒绝的升级;不可用的凭证或 runner 自动跳过。 +- **快照:** 固定 permission config-option 协议格式(wire format)、preset 和旋钮事件、prompt delta 和通知、以及两个脚本化的 approval 分支。快照模式以无约束启动,使无关 fixture(测试前置数据)保持平台无关;策略场景显式切换。真实拒绝 stderr 留在平台测试中,因为其方言是 runner 特定的。 ## 延迟阶段 @@ -149,22 +149,22 @@ FIXME: Revisit this tool-local boundary. The follow-up design needs to determine - **一个接口同时覆盖容器/VM**:否决。`confine(argv)` 预设共享文件系统;环境隔离是作为一致组部署的能力兄弟后端。 - **通用 ToolRuntime 包装任何工具**:否决。对进程内工具(闭包了 `ctx`)机械上不成立;声明式效果重写对 fs/web/todo 而言不合理。 - **在执行器内部(`dsh-bash-sandbox`)请求批准**:否决。没有可路由的 `agent`,没有可附加 prompt 的 `callId`;添加它们会让传输 seam 了解会话和 UI——工具层持有两者并拥有面向模型的词汇。 -- **同一工具调用内自动重试**:否决。日志无法重建的隐藏重入:一个 `tool/call` 会产生两次具有不同策略的执行——重试是一次**新的**带有自身参数和结果事实的已记录调用。 +- **同一工具调用内自动重试**:否决。日志无法重建的隐藏重入:一个 `tool/call` 会产生两次具有不同策略的执行——重试是一次新的带有自身参数和结果事实的已记录调用。 - **无条件公布升级字段**:否决。在 `dsh-bash-local` 下它们是死杠杆——公布 harness 无法兑现的选项会制造注定失败的授权;能力门控仅需注册时一次读取。 - **默认值相对的升级阶梯(仅公布比执行器注册时默认值更宽的模式)**:否决。按会话覆盖使默认值成为错误的基线——切换到比默认值更窄的会话恰恰失去它需要的杠杆,而在 `danger-full-access` 默认值下字段完全消失,同时一个被覆盖为 `read-only` 的会话仍处于约束中却没有升级路径。枚举固定封闭的目标词汇;严格放宽是针对会话有效模式的按调用执行检查。 - **按会话动态工具 schema**:否决。schema 设计上是注册表全局的(一套 assembly 词汇、固定 header 快照契约),按会话重新注册只能买到执行时严格放宽检查已保证的东西,代价是按会话的 schema 表面和每次切换的 header 变动。 - **将重试硬匹配到先前的拒绝**:否决。命令字符串同一性脆弱(引号、`workdir`、env 前缀、作为失败阶段重试的管道)——要么误拒诚实的重试,要么被轻易满足;真正的边界是人看到命令 + 理由。仅在 `allow_always` 授权存储需要机器可检查的范围时才重新考虑。 - **通用 `env/state` facts map 加拥有者服务**:否决。approval 和 sandbox 独立组合,因此任何一方的状态都不应拖入第三个包;单键 fold 各自是一个 `findLast`,拥有者服务自然消解;没有跨旋钮的不变式,因此原子多键补丁无收益。 - **通过 `agent/user-message` + 总线事件叙述**:否决。它预设了一个不存在的轮次入口 seam(真正的 seam 是 `agent/prompt-submit`),而 pre-step 的位置以一个监听器同时服务合并的轮次入口通知和轮中即时性约束。 -- **提示词中常驻声明沙箱模式(+ 切换叙述器)**:先交付后移除,基于实际证据:当每个请求中都有 `Bash commands run under the "read-only" file sandbox.` 时,模型拒绝**尝试**被拒绝后可升级的工作(首次手动会话中十二个轮次有五个以零工具调用结束),将沙箱变成了软锁定。拒绝标记在需要时命名模式,升级字段承载恢复路径;批准旋钮保留其声明,因为自动拒绝在行为上与人的「不」无法区分。 -- **用专门的簿记事件追踪「上次告知」**:否决。`request/header*` fold 已记录模型看到的确切 prompt;将封闭的候选句子解析回来替代了第二条簿记流——事件仅在它们**本身即为存储**时才需要。 +- **提示词中常驻声明沙箱模式(+ 切换叙述器)**:先交付后移除,基于实际证据:当每个请求中都有 `Bash commands run under the "read-only" file sandbox.` 时,模型拒绝尝试被拒绝后可升级的工作(首次手动会话中十二个轮次有五个以零工具调用结束),将沙箱变成了软锁定。拒绝标记在需要时命名模式,升级字段承载恢复路径;批准旋钮保留其声明,因为自动拒绝在行为上与人的「不」无法区分。 +- **用专门的簿记事件追踪「上次告知」**:否决。`request/header*` fold 已记录模型看到的确切 prompt;将封闭的候选句子解析回来替代了第二条簿记流——事件仅在它们本身即为存储时才需要。 - **ACP session modes 而非 config options**:否决。preset 已经是一个部署定义的 config-option 选择器,且 modes 计划在 ACP v2 中移除。 ## 后果 已交付并固定的内容——测试中的各层级分别保障: -- 被拒绝的命令以 `sandbox_permissions` + `justification` 重试时,通过组合的应答器链提示用户;授权使**该次**调用在更宽模式下运行(结果事实如此报告),而其他所有调用保持各自的有效模式;每种非授权结果产生各自不同的错误文本且不执行任何内容。 +- 被拒绝的命令以 `sandbox_permissions` + `justification` 重试时,通过组合的应答器链提示用户;授权使该次调用在更宽模式下运行(结果事实如此报告),而其他所有调用保持各自的有效模式;每种非授权结果产生各自不同的错误文本且不执行任何内容。 - 升级字段恰好在已挂载的执行器约束时存在;不严格宽于调用有效模式的请求以自身文本失败关闭且不提示任何人;没有 ApprovalService 的部署对升级调用失败关闭,对普通调用不影响。 - 系统提示词从不声明沙箱模式(批准 `'never'` 策略是唯一被声明的旋钮),且整个交互——header、旋钮事件、通知、批准、结果——仅从会话日志即可重建,除两个旋钮事件外无额外事件类型。 - N 次空闲切换每个旋钮最多产生一个锚定事件(净零序列不锚定任何事件——客户端回显当前选择的无操作推送不记录任何内容);批准策略切换最多以一条合并通知叙述;轮中沙箱切换由下一次调用的盖章兑现。 @@ -175,31 +175,31 @@ FIXME: Revisit this tool-local boundary. The follow-up design needs to determine 代价与已接受的限制: - **单一包装的幻觉被有意放弃。**`tools/pre-execute` 包装加 prompt 约定无法解决沙箱批准——正确的设计需要结构化拒绝、原生 runner 探测、按调用策略承载和一致的跨工具族强制,本设计为此付出了代价。 -- **`read-only` 尚不是跨工具族边界。**在 fs 意图门控按共享模式决策之前,该声明仅对 bash 成立;契约诚实地如此声明(§ 进程内工具)。 -- **Windows 没有后端。**其链槽保留为空——失败关闭,绝不穿透;填充它是延迟阶段。 -- **Seatbelt 层级依赖 Apple 已弃用但仍交付的 `sandbox-exec` CLI。**作为 darwin 的唯一候选,它无需探测即被选中,因此未来移除会在执行时作为 runner 失败分类浮现——重新抛出 `SANDBOX_UNAVAILABLE`,命令从未运行;失败关闭,绝不开放。 -- **Landlock 约束的完整度取决于运行内核的 ABI。**报告为 `enforcement: 'partial'` 而非拒绝——这是有意的权衡,使备选在旧内核主机上仍可用。 -- **launcher 作为注册表依赖到达。**通过其自身仓库的发布流水线(经审查的 C 源码、原生 CI 构建器、字节固定的发布演练)加上本仓库的版本固定获得信任——真实内核 e2e 测试腿是通过安装字节为行为背书的。 -- **模型可能过度请求。**在没有拒绝依据的情况下升级,或在 `workspace-write` 足够时选择 `danger-full-access`:描述引导且枚举强制阶梯,但人的 prompt 是实际门控;`approval/asked` 原因使过度请求可审计,且 `prepend` 策略应答器可以自动拒绝部署永远不想要的模式。 +- **`read-only` 尚不是跨工具族边界。** 在 fs 意图门控按共享模式决策之前,该声明仅对 bash 成立;契约诚实地如此声明(§ 进程内工具)。 +- **Windows 没有后端。** 其链槽保留为空——失败关闭,绝不穿透;填充它是延迟阶段。 +- **Seatbelt 层级依赖 Apple 已弃用但仍交付的 `sandbox-exec` CLI。** 作为 darwin 的唯一候选,它无需探测即被选中,因此未来移除会在执行时作为 runner 失败分类浮现——重新抛出 `SANDBOX_UNAVAILABLE`,命令从未运行;失败关闭,绝不开放。 +- **Landlock 约束的完整度取决于运行内核的 ABI。** 报告为 `enforcement: 'partial'` 而非拒绝——这是有意的权衡,使备选在旧内核主机上仍可用。 +- **launcher 作为注册表依赖到达。** 通过其自身仓库的发布流水线(经审查的 C 源码、原生 CI 构建器、字节固定的发布演练)加上本仓库的版本固定获得信任——真实内核 e2e 测试腿是通过安装字节为行为背书的。 +- **模型可能过度请求。** 在没有拒绝依据的情况下升级,或在 `workspace-write` 足够时选择 `danger-full-access`:描述引导且枚举强制阶梯,但人的 prompt 是实际门控;`approval/asked` 原因使过度请求可审计,且 `prepend` 策略应答器可以自动拒绝部署永远不想要的模式。 - **公布的目标集是静态的,而有效模式是按会话的**(schema 是注册表全局的)——已处于最宽模式的会话仍被提供这些字段。构造上无害:执行时的严格放宽检查(而非枚举)是安全边界——非放宽请求以自身文本失败且不提示任何人。 -- **授权的升级不等于可工作的沙箱。**不可用的后端即使对授权升级到约束模式也仍然失败关闭——在平台没有链或所有探测失败时于 `confine()` 阶段,在未探测的唯一 runner 拒绝时于执行阶段(归类为沙箱失败而非命令失败)——而授权的 `danger-full-access` 运行根本不触及提供方:此时授权(而非探测)是权威。 -- **空闲切换存在于 bridge 内存中,直到下一次 prompt 提交锚定它。**该窗口内的崩溃将其回退(在 `session/load` 时报告),且永不再提交 prompt 的会话永不持久化它——已接受,loop 拥有的空闲提交轮次留作未来工作(如果持久性成为需求)。 -- **批准叙述器的重启基线解析 prompt 文本。**封闭的候选句子由写入模块本身拥有,因此措辞变更是同一文件中写入器+解析器的协调编辑;header 早于该段落的会话静默采用当前策略而不发通知。 +- **授权的升级不等于可工作的沙箱。** 不可用的后端即使对授权升级到约束模式也仍然失败关闭——在平台没有链或所有探测失败时于 `confine()` 阶段,在未探测的唯一 runner 拒绝时于执行阶段(归类为沙箱失败而非命令失败)——而授权的 `danger-full-access` 运行根本不触及提供方:此时授权(而非探测)是权威。 +- **空闲切换存在于 bridge 内存中,直到下一次 prompt 提交锚定它。** 该窗口内的崩溃将其回退(在 `session/load` 时报告),且永不再提交 prompt 的会话永不持久化它——已接受,loop 拥有的空闲提交轮次留作未来工作(如果持久性成为需求)。 +- **批准叙述器的重启基线解析 prompt 文本。** 封闭的候选句子由写入模块本身拥有,因此措辞变更是同一文件中写入器+解析器的协调编辑;header 早于该段落的会话静默采用当前策略而不发通知。 - **批准段落仍是动态 prompt 表面**(`'never'` 切换会破坏该会话的提供方 prompt 前缀缓存)。已接受:策略切换罕见,且模型基于过时的 `'never'` 行动更糟。沙箱旋钮不再触及 prompt。 - **模型可能持有关于沙箱模式的过时信念**(没有任何东西宣布切换)。有意接受:下一次尝试的标记或成功会纠正它,而宣布的观察到的失败模式——预防性拒绝——比一次浪费的重试更糟。 ## FAQ -- **一个命令返回了 `[sandbox: file access denied under read-only mode]`——它失败了吗?**它**运行了**,内核拒绝了一个文件操作:拒绝是与退出码正交的结果事实。教学禁止绕过它重试;唯一被认可的动作是以升级请求重试同一命令一次。 -- **如何区分损坏的沙箱与失败的命令?**Runner 失败在分类中优先于拒绝:匹配包装的 `runnerFailureSignatures` 的失败运行意味着命令**从未运行**——前台重新抛出结构化的 `SANDBOX_UNAVAILABLE` 并附带 runner 的 stderr 行,后台任务盖章 `sandbox.runnerFailed` 并渲染自己的标记。损坏的沙箱永远不会被读作失败的命令,且命令永远不会无约束运行。 -- **在没有后端的平台上会发生什么——今天的 Windows?**`confine()` 抛出失败关闭的 `SANDBOX_UNAVAILABLE`,命令永不 spawn;`win32` 是保留的**空**链,由测试固定为同样失败关闭,直到 Windows runner 填充它(§ 延迟阶段)。 -- **`bwrap` 已安装在我的主机上但不可用(禁用了非特权 userns、LSM 拒绝 `mount`)——会发生什么?**链探测是功能性的——它构建并强制一个真实 profile 而非检查 `--version`——因此存在但不可用的 `bwrap` 探测失败,选择落到注册表安装的 Landlock launcher,结论在提供方生命周期内缓存。 -- **沙箱限制网络或进程可见性吗?**不——`SandboxMode` 仅声称文件操作;bwrap profile 刻意不 unshare pid,没有后端声称网络。网络限制是否成为自己的旋钮留在 § seam 中开放。 -- **哪些工具实际在约束下运行?**通过 `ctx.bash` 的 OS 子进程——bash 工具,以及传递性的钩子命令。fs/web/todo 在进程内执行,`execve` 包装对它们机械上毫无意义;它们的 `read-only` 语义随跨工具族延迟阶段到来,在此之前契约诚实地声明仅限 bash。 -- **授权的升级会持久化吗?或覆盖后台任务吗?**都不会:授权被请求它的那次调用(前台或后台)消耗,该次调用报告它实际运行的模式,而每个邻居保持自己的。如何为通过 `bash_output` 延迟浮现的后台拒绝**定义**升级,留在 § 升级机制中开放。 -- **编辑器的模式切换何时生效?**轮中:立即追加,由下一次调用的盖章兑现。空闲:保持在 bridge 的会话记录上,在下一次 `agent/prompt-submit` 时锚定到其开放轮次中,N 次切换合并为最多一个事件(净零则无);锚定前崩溃回退它,`session/load` 报告真实状态。模型不被告知——其下一个命令直接在新模式下运行。 -- **重启后什么存活——如果运维人员在进程停止期间改了配置默认值呢?**覆盖从会话日志回放(`effective = fold ?? config`),因此恢复的会话以零追赶机制保持其模式;离线漂移的默认值以与切换相同的方式改变行为(批准策略因被声明,还额外以运维人员/配置归因叙述)。 -- **结果上的 `enforcement: 'partial'` 是什么意思?**所选后端强制其内核 ABI 管控的子集——例如 ABI v3 之前的 Landlock 不管控路径 truncate——并以结构化方式如此声明而非拒绝主机;探测的报告行区分各种情况。bwrap 和 Seatbelt profile 构造上管控所有承诺的文件操作,因此始终报告 `full`。 +- **一个命令返回了 `[sandbox: file access denied under read-only mode]`——它失败了吗?** 它运行了,内核拒绝了一个文件操作:拒绝是与退出码正交的结果事实。教学禁止绕过它重试;唯一被认可的动作是以升级请求重试同一命令一次。 +- **如何区分损坏的沙箱与失败的命令?** Runner 失败在分类中优先于拒绝:匹配包装的 `runnerFailureSignatures` 的失败运行意味着命令从未运行——前台重新抛出结构化的 `SANDBOX_UNAVAILABLE` 并附带 runner 的 stderr 行,后台任务盖章 `sandbox.runnerFailed` 并渲染自己的标记。损坏的沙箱永远不会被读作失败的命令,且命令永远不会无约束运行。 +- **在没有后端的平台上会发生什么——今天的 Windows?** `confine()` 抛出失败关闭的 `SANDBOX_UNAVAILABLE`,命令永不 spawn;`win32` 是保留的空链,由测试固定为同样失败关闭,直到 Windows runner 填充它(§ 延迟阶段)。 +- **`bwrap` 已安装在我的主机上但不可用(禁用了非特权 userns、LSM 拒绝 `mount`)——会发生什么?** 链探测是功能性的——它构建并强制一个真实 profile 而非检查 `--version`——因此存在但不可用的 `bwrap` 探测失败,选择落到注册表安装的 Landlock launcher,结论在提供方生命周期内缓存。 +- **沙箱限制网络或进程可见性吗?** 不——`SandboxMode` 仅声称文件操作;bwrap profile 刻意不 unshare pid,没有后端声称网络。网络限制是否成为自己的旋钮留在 § seam 中开放。 +- **哪些工具实际在约束下运行?** 通过 `ctx.bash` 的 OS 子进程——bash 工具,以及传递性的钩子命令。fs/web/todo 在进程内执行,`execve` 包装对它们机械上毫无意义;它们的 `read-only` 语义随跨工具族延迟阶段到来,在此之前契约诚实地声明仅限 bash。 +- **授权的升级会持久化吗?或覆盖后台任务吗?** 都不会:授权被请求它的那次调用(前台或后台)消耗,该次调用报告它实际运行的模式,而每个邻居保持自己的。如何为通过 `bash_output` 延迟浮现的后台拒绝定义升级,留在 § 升级机制中开放。 +- **编辑器的模式切换何时生效?** 轮中:立即追加,由下一次调用的盖章兑现。空闲:保持在 bridge 的会话记录上,在下一次 `agent/prompt-submit` 时锚定到其开放轮次中,N 次切换合并为最多一个事件(净零则无);锚定前崩溃回退它,`session/load` 报告真实状态。模型不被告知——其下一个命令直接在新模式下运行。 +- **重启后什么存活——如果运维人员在进程停止期间改了配置默认值呢?** 覆盖从会话日志回放(`effective = fold ?? config`),因此恢复的会话以零追赶机制保持其模式;离线漂移的默认值以与切换相同的方式改变行为(批准策略因被声明,还额外以运维人员/配置归因叙述)。 +- **结果上的 `enforcement: 'partial'` 是什么意思?** 所选后端强制其内核 ABI 管控的子集——例如 ABI v3 之前的 Landlock 不管控路径 truncate——并以结构化方式如此声明而非拒绝主机;探测的报告行区分各种情况。bwrap 和 Seatbelt profile 构造上管控所有承诺的文件操作,因此始终报告 `full`。 ## 先例 diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml index 03a68c9166..360ea648dc 100644 --- a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml @@ -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 -2026-07-07-mcp-client-plugin.md: 7706190257b54730532e4aa46cc9c47453c59871 -2026-07-07-mcp-client-plugin.zh.md: b5fee7eff7f12de5658f0a10c32cfeed71482fdf +2026-07-07-mcp-client-plugin.md: 99159d6ac31fb8ef74b28a7048392d0e22124b5a +2026-07-07-mcp-client-plugin.zh.md: e4c61f173956a928c4030fc53796324b924f32d9 diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md index 7706190257..99159d6ac3 100644 --- a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.md @@ -1,9 +1,9 @@ # RFC: MCP client plugin — connect to external MCP servers and bridge their tools -English | [中文](2026-07-07-mcp-client-plugin.zh.md) - Status: implemented +English | [中文](2026-07-07-mcp-client-plugin.zh.md) + ## Problem The harness had no way to consume tools from the MCP (Model Context Protocol) ecosystem. MCP is the emerging standard for tool servers — GitHub, filesystem, databases, code search, and hundreds of community servers expose tools via MCP. Users want to point the harness at one or more MCP servers and have their tools appear as native model-facing tools, without writing per-server glue code. diff --git a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md index b5fee7eff7..e4c61f1739 100644 --- a/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md +++ b/docs/rfc/implemented/feature/2026-07-07-mcp-client-plugin.zh.md @@ -1,4 +1,4 @@ -# RFC:MCP 客户端插件——连接外部 MCP 服务器并桥接其工具 +# RFC: MCP 客户端插件——连接外部 MCP 服务器并桥接其工具 Status: implemented @@ -54,7 +54,7 @@ interface StreamableHttpConfig { type Config = StdioConfig | StreamableHttpConfig ``` -`serverName` 是稳定的本地标识,用于在模型可见名称(见下文)中为该服务器的工具提供命名空间。它有意设计为用户配置,而**非**远端的 `serverInfo.name`:远端名称是不可信输入、跨部署不唯一(同一服务器的生产和预发布实例报告相同名称)、且可能在服务器升级时变化——这些都不得静默重命名模型可见工具。多个活跃实例使用重复的 `serverName` 属于配置错误:后加载的实例在启动时以可操作的错误消息失败,绝不静默覆盖或跳过。短 `serverName`(如 `gh`)也是缩短公开名称的调节手段。 +`serverName` 是稳定的本地标识,用于在模型可见名称(见下文)中为该服务器的工具提供命名空间。它有意设计为用户配置,而非远端的 `serverInfo.name`:远端名称是不可信输入、跨部署不唯一(同一服务器的生产和预发布实例报告相同名称)、且可能在服务器升级时变化——这些都不得静默重命名模型可见工具。多个活跃实例使用重复的 `serverName` 属于配置错误:后加载的实例在启动时以可操作的错误消息失败,绝不静默覆盖或跳过。短 `serverName`(如 `gh`)也是缩短公开名称的调节手段。 `cordis.yml` 用法示例: diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml b/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml index 038349fd78..02d6f23514 100644 --- a/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.i18n.yaml @@ -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 -2026-07-07-session-prefix.md: ffa0fecb86e84ed64d45b24e1b6943d421757fb2 -2026-07-07-session-prefix.zh.md: ca38ebf337e16f4f2368ca74e394fcc1031fbf1f +2026-07-07-session-prefix.md: 81868c5b0c17c03aa1ebad788c8604dd30d1ce17 +2026-07-07-session-prefix.zh.md: 7d93d8190ce51fcbdc1b67e20fbdb4f4ea8e14c8 diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.md b/docs/rfc/implemented/feature/2026-07-07-session-prefix.md index ffa0fecb86..81868c5b0c 100644 --- a/docs/rfc/implemented/feature/2026-07-07-session-prefix.md +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.md @@ -1,9 +1,9 @@ # RFC: The session prefix — request-only messages in front of the derived history -English | [中文](2026-07-07-session-prefix.zh.md) - Status: implemented +English | [中文](2026-07-07-session-prefix.zh.md) + ## Problem A plugin often owns a session-stable opener the model must always see — a skills catalog, an AGENTS.md digest, a workspace baseline. Before this seam the harness offered two homes, and both are wrong for that content. The system prompt is one rendered string: message-shaped content (a user-role `<system-reminder>` envelope, a multi-message primer) does not fit it, and providers weight conversation messages differently from system text. Durable history (`agent.inject()`, a `context/message` at session start) makes the opener permanent: every `deriveMessages()` consumer replays it, the compaction retention walk owns it, forks bake it in stale, and a resume cannot refresh it — a catalog captured at session birth outlives the world it described. diff --git a/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md b/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md index ca38ebf337..7d93d8190c 100644 --- a/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md +++ b/docs/rfc/implemented/feature/2026-07-07-session-prefix.zh.md @@ -1,4 +1,4 @@ -# RFC:会话前缀——派生历史之前的仅请求消息 +# RFC: 会话前缀——派生历史之前的仅请求消息 Status: implemented @@ -12,15 +12,15 @@ Status: implemented ## 决策 -`agent/session-prefix` 是 agent 事件映射上的一个 waterfall(瀑布式事件)([`packages/core/agent/src/types.ts`](../../../../packages/core/agent/src/types.ts)):监听器接收一个冻结的空种子并返回扩展(规范的贡献方式是前置插入 `[mine, ...await next()]`,在协议格式上产生注册顺序)。agent loop(智能体循环)([`packages/core/agent-loop/src/loop.ts`](../../../../packages/core/agent-loop/src/loop.ts))在每个循环实例中触发一次,惰性地在实例首次 `agent/pre-step` 之前执行;组合后的列表被深拷贝、深冻结、缓存在实例上,并在该实例发出的每个请求中置于**整个**派生历史之前——紧接在提供方的 system 槽位之后([协议格式顺序](../../../core-data-structures/core.md#the-request-envelope-llmcallconfig-and-the-logged-header))。 +`agent/session-prefix` 是 agent 事件映射上的一个 waterfall(瀑布式事件)([`packages/core/agent/src/types.ts`](../../../../packages/core/agent/src/types.ts)):监听器接收一个冻结的空种子并返回扩展(规范的贡献方式是前置插入 `[mine, ...await next()]`,在协议格式上产生注册顺序)。agent loop(智能体循环)([`packages/core/agent-loop/src/loop.ts`](../../../../packages/core/agent-loop/src/loop.ts))在每个循环实例中触发一次,惰性地在实例首次 `agent/pre-step` 之前执行;组合后的列表被深拷贝、深冻结、缓存在实例上,并在该实例发出的每个请求中置于整个派生历史之前——紧接在提供方的 system 槽位之后([协议格式顺序](../../../core-data-structures/core.md#the-request-envelope-llmcallconfig-and-the-logged-header))。 三个属性承载了这一设计: -- **仅请求,记录在 header 中。** `deriveMessages()` 从不返回前缀;它唯一的持久记录是实例锚定的 `request/header` 快照上的 `EpochHeader.messagePrefix`——可重建请求 RFC 已为请求的非历史部分拥有的通道,因此不引入新的会话事件。开发不变式([dsh-invariants](../../../../packages/support/invariants/src/index.ts))对每个循环构建的请求重新计算 `messagePrefix + 边界派生`;未记录的前缀无法到达协议格式。 +- **仅请求,记录在 header 中。** `deriveMessages()` 从不返回前缀;它唯一的持久记录是实例锚定的 `request/header` 快照上的 `EpochHeader.messagePrefix`——可重建请求 RFC 已为请求的非历史部分拥有的通道,因此不引入新的会话事件。开发不变式([dsh-invariants](../../../../packages/support/invariants/src/index.ts))对每个循环构建的请求重新计算 `messagePrefix + boundary derivation`;未记录的前缀无法到达协议格式。 - **按实例冻结。** 复用是结构性的,而非靠纪律保证:缓存的产物在会话中途不可变,因此提供方的 prompt 缓存从构造上成立,前缀以每步零边际成本扩展了可缓存区域。进程重启或 `ctx.agents.resume()` 产生新实例:它重新组合,任何漂移都可追溯地落在 `'resume'` header 快照上。这就是本 seam 创建的路由规则:会话冻结的开场内容走前缀;会话中途变化的内容走仅追加历史通道(`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——[拦截 seam RFC](2026-06-30-interception-seams.md)),每条都是一次性支付的持久 `context/message`,之后被前缀缓存覆盖。 - **在压力门禁之前组合。** 组合先于实例的首次 `agent/pre-step`,且 seam 将组合值透传:`agent/pre-step` 携带 `sessionPrefix` 参数,`CompactService.compactIfNeeded(agent, fullSystemPrompt, sessionPrefix, signal)` 将其计入 token 压力估算。如果改为让门禁读取上一个实例折叠后的前缀,则在 resume 或 fork 后的实例中(贡献者可能已增长),门禁会低估压力、跳过压缩,发出超窗口的首个请求。在首次 pre-step 之前组合并将活值透传给 seam,使估算在每一步都精确。被 cancel/dispose 中断的组合(中断落在 waterfall 内部)会被丢弃,永不缓存:感知中止的监听器的降级回退不会泄漏到后续请求中,下一轮次在活信号下重新组合。 -由于组合在边界快照之前运行,组合监听器的会话追加会加入**当前**请求的派生历史。压缩在结构上不可能触及前缀(或系统提示词):它重写的是表面节点,而 header 状态从不进入表面。 +由于组合在边界快照之前运行,组合监听器的会话追加会加入当前请求的派生历史。压缩在结构上不可能触及前缀(或系统提示词):它重写的是表面节点,而 header 状态从不进入表面。 ## 测试 @@ -32,7 +32,7 @@ Status: implemented - **系统提示词分段**(`system-prompt/assemble`):对此类内容否决。assembly 渲染为单一 `system` 字符串,消息形态的开场放不进去;且系统提示词被设计为每步重新组装(变化时带 header delta),而开场内容需要按实例冻结的语义。 - **持久化历史开场**(会话启动时 `inject()`):否决。永久历史正是问题陈述中的失败模式——到处被回放、可被压缩、跨 resume 陈旧。 - **按轮次组合而非按实例组合**:否决。轮次边界的重新组合要么与日志静默失同步,要么强制每次变化都产生 header delta;且它每次触发都会破坏提供方缓存。合理的刷新点是实例边界,`'resume'` 快照已在那里可追溯地记录漂移。 -- **在首次请求时惰性组合,让压缩读取折叠后的 header**(最初合并时的形态):评审中被取代。折叠值仅从实例的第二个请求起才与活前缀匹配,因此在 resume/fork 后的实例首步,压力门禁读取的是**上一个**实例的前缀,可能低估压力。在首次 pre-step 之前组合并将活值透传给 seam,使估算在每一步都精确。 +- **在首次请求时惰性组合,让压缩读取折叠后的 header**(最初合并时的形态):评审中被取代。折叠值仅从实例的第二个请求起才与活前缀匹配,因此在 resume/fork 后的实例首步,压力门禁读取的是上一个实例的前缀,可能低估压力。在首次 pre-step 之前组合并将活值透传给 seam,使估算在每一步都精确。 - **专用会话事件承载前缀**:否决。header 事件按设计就是请求的非历史记录;第二个事件会为同一事实提供第二个归属,并多出一个需要保持完整的编解码器。 ## 后果 diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml index 5c62772145..0daf9b2490 100644 --- a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml @@ -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 -2026-07-08-repeat-tool-guard.md: 04d5d077a42b54ca7dc04a1efc9ea2f4034b642b -2026-07-08-repeat-tool-guard.zh.md: 917d958ca1019eb464b72b0201219de9dde7f658 +2026-07-08-repeat-tool-guard.md: e422ae70f61b6c77bf6517bc5eb840afc171d82c +2026-07-08-repeat-tool-guard.zh.md: eedb36f448bbca220e023a7609e1d9666fadb8e9 diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md index 04d5d077a4..e422ae70f6 100644 --- a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md @@ -1,9 +1,9 @@ # RFC: Repeat-tool-call guard plugin -English | [中文](2026-07-08-repeat-tool-guard.zh.md) - Status: implemented +English | [中文](2026-07-08-repeat-tool-guard.zh.md) + ## Problem A model stuck in a loop re-issues the same tool call with byte-identical arguments — re-running a failing grep, re-reading an unchanged file, polling a command that already gave its answer — and each round trip burns tokens, wall-clock, and (for paid APIs) money without adding information. The harness has nothing that notices: the loop has no step budget, no plugin tracks call repetition, and the model only escapes when it happens to vary its own behavior. The failure mode is real and cheap to detect — [pi-repeat-tool-guard](https://github.com/Kingwl/pi-repeat-tool-guard) ships exactly this as a pi coding-agent extension: count consecutive identical calls and, past a threshold, append a `<system-reminder>` telling the model to stop repeating itself and change course. diff --git a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md index 917d958ca1..eedb36f448 100644 --- a/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md +++ b/docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.zh.md @@ -1,4 +1,4 @@ -# RFC:重复工具调用守卫插件 +# RFC: 重复工具调用守卫插件 Status: implemented diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml index ba1e1f60be..45ea89f234 100644 --- a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml @@ -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 -2026-07-08-self-referential-cordis-toolset.md: 62b97dc4bdbd0e0b5b1f67f77c763065c79964ed -2026-07-08-self-referential-cordis-toolset.zh.md: 44648d7a3f195f2dc84121c0d014e5193484b106 +2026-07-08-self-referential-cordis-toolset.md: c79bc09dde85d79adc5435f3e08c702cab1369d9 +2026-07-08-self-referential-cordis-toolset.zh.md: e6cada0530652cfb40e7ea1edadf1b12e0f07e77 diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md index 62b97dc4bd..c79bc09dde 100644 --- a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md @@ -1,9 +1,9 @@ # RFC: The self-referential cordis toolset -English | [中文](2026-07-08-self-referential-cordis-toolset.zh.md) - Status: implemented +English | [中文](2026-07-08-self-referential-cordis-toolset.zh.md) + ## Problem Everything in this harness is a cordis plugin, but the agent running inside that plugin runtime cannot see or touch it: it cannot enumerate the services and events around it, cannot extend itself with a new tool mid-session, and cannot compose capabilities it invents. Handing the model that power is worth exploring — a self-referential agent that inspects and modifies its own runtime — but it raises three correctness problems at once, and the design is about answering them rather than the raw "let the model run code" mechanic. diff --git a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md index 44648d7a3f..e6cada0530 100644 --- a/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md +++ b/docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md @@ -1,9 +1,9 @@ -# RFC:自引用 cordis 工具集 - -[English](2026-07-08-self-referential-cordis-toolset.md) | 中文 +# RFC: 自引用 cordis 工具集 Status: implemented +[English](2026-07-08-self-referential-cordis-toolset.md) | 中文 + ## 问题 本 harness 中的一切都是 cordis 插件,但运行在该插件运行时内部的 agent(智能体)既看不到也碰不到它:它无法枚举周围的服务和事件,无法在会话中途为自己添加新工具,也无法组合自己发明的能力。赋予模型这种能力值得探索——一个能审视并修改自身运行时的自引用 agent——但这同时引发三个正确性问题,本设计的核心正是回答这些问题,而非单纯的「让模型执行代码」机制。 diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml b/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml index c824942f12..30fa8ab09e 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.i18n.yaml @@ -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 -2026-07-10-session-query-service.md: 8b742ac19fea21d8404f5f44aa64f8c3cb3efccc -2026-07-10-session-query-service.zh.md: 73f47d0cc0306b3dcb6552c686f8f1a71ffbdc87 +2026-07-10-session-query-service.md: 8c990f4407d91c0be1fc01046e34aa3e76076ed4 +2026-07-10-session-query-service.zh.md: ea0d2d52668fb40b97621884f635cb03dea6f663 diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.md b/docs/rfc/implemented/feature/2026-07-10-session-query-service.md index 8b742ac19f..8c990f4407 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.md +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.md @@ -1,9 +1,9 @@ # RFC: Exact session query service -English | [中文](2026-07-10-session-query-service.zh.md) - Status: implemented +English | [中文](2026-07-10-session-query-service.zh.md) + ## Problem Session history exists in two places: current `SessionStore` objects and an optional persistence backend. Consumers that need exact inspection would otherwise duplicate live-versus-persisted precedence, persistence lifecycle handling, raw-event surface classification, and defensive cloning. Durable state can lag the live log between checkpoints, so persistence alone is not a truthful current source. diff --git a/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md b/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md index 73f47d0cc0..ea0d2d5266 100644 --- a/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md +++ b/docs/rfc/implemented/feature/2026-07-10-session-query-service.zh.md @@ -1,9 +1,9 @@ -# RFC:精确会话查询服务 - -[English](2026-07-10-session-query-service.md) | 中文 +# RFC: 精确会话查询服务 Status: implemented +[English](2026-07-10-session-query-service.md) | 中文 + ## 问题 会话历史存在于两处:当前的 `SessionStore` 对象与可选的持久化后端。需要精确检查的消费方若无统一服务,就不得不各自重复实现活跃/持久化优先级判定、持久化生命周期处理、原始事件的 surface 分类以及防御性克隆。在检查点之间,持久化状态可能落后于活跃日志,因此仅靠持久化并非当前状态的可靠来源。 diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml index 6675490bb9..65e180d55d 100644 --- a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml @@ -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 -2026-07-12-subagent-persona-tool-filter-and-depth.md: 368f3a3592c5e241bb9357d4d4ce32e175c3de45 -2026-07-12-subagent-persona-tool-filter-and-depth.zh.md: cc78a472df014ce1eb9114277e0520c7e9c051bb +2026-07-12-subagent-persona-tool-filter-and-depth.md: c88695d4444008bff69fcb10e3cf33c7b8820b9b +2026-07-12-subagent-persona-tool-filter-and-depth.zh.md: 1efbbce57274c11b2811ebe844c9cd80f81f407f diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md index 368f3a3592..c88695d444 100644 --- a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md @@ -1,9 +1,9 @@ # RFC: Configure subagent persona, tool visibility, and depth -English | [中文](2026-07-12-subagent-persona-tool-filter-and-depth.zh.md) - Status: implemented +English | [中文](2026-07-12-subagent-persona-tool-filter-and-depth.zh.md) + ## Problem A reusable subagent provider answers how to run a child, but different delegation tools need different child behavior. One deployment may want a reviewer persona, a research-only tool set, or a hard recursion bound without creating a new provider for every combination. diff --git a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md index cc78a472df..1efbbce572 100644 --- a/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md +++ b/docs/rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md @@ -1,9 +1,9 @@ -# RFC:配置 subagent 的人设、工具可见性与深度 - -[English](2026-07-12-subagent-persona-tool-filter-and-depth.md) | 中文 +# RFC: 配置 subagent 的人设、工具可见性与深度 Status: implemented +[English](2026-07-12-subagent-persona-tool-filter-and-depth.md) | 中文 + ## 问题 一个可复用的 subagent 提供方解决的是「如何运行子 agent(智能体)」的问题,但不同的委派工具需要不同的子 agent 行为。某个部署可能需要评审者人设、仅限研究的工具集,或硬性递归上限,而不必为每种组合创建新的提供方。 diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml index 120abae517..1e877bfba3 100644 --- a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml @@ -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 -2026-06-11-doc-sync-enforcement.md: 44ea84daddcae73ce07b0a8240f83ee9945e449d -2026-06-11-doc-sync-enforcement.zh.md: c739e9661bb926c772f1d5399529a813ac59991c +2026-06-11-doc-sync-enforcement.md: cb238291f9ff5ba5d6333cdf2fe75a43fe3e8eea +2026-06-11-doc-sync-enforcement.zh.md: a443cfcd6f9bd17ae1512683ff8cd82411fb8590 diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md index 44ea84dadd..cb238291f9 100644 --- a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.md @@ -1,9 +1,9 @@ # RFC: Doc-sync enforcement -English | [中文](2026-06-11-doc-sync-enforcement.zh.md) - Status: implemented +English | [中文](2026-06-11-doc-sync-enforcement.zh.md) + ## Problem AGENTS.md promises that docs and code stay strictly in sync, but the promise was verified by eyeball. Review caught drift twice — a cookbook example contradicting the type policy, and a README citing the wrong `registerAdapter` call. Out-of-sync docs are worse than no docs, and this codebase is built primarily by agents that follow gates far more reliably than prose (mechanical quality gates). Two classes of doc drift are mechanically checkable: code blocks that no longer compile, and the event-taxonomy table that duplicates the `interface Events` declarations. diff --git a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md index c739e9661b..a443cfcd6f 100644 --- a/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-doc-sync-enforcement.zh.md @@ -1,9 +1,9 @@ -# RFC:Doc-sync 强制 - -[English](2026-06-11-doc-sync-enforcement.md) | 中文 +# RFC: Doc-sync 强制 Status: implemented +[English](2026-06-11-doc-sync-enforcement.md) | 中文 + ## 问题 AGENTS.md 承诺文档与代码严格同步,但这一承诺此前仅靠人眼核查。评审曾两次发现漂移:一次是实操手册(cookbook)示例与类型策略矛盾,一次是 README 引用了错误的 `registerAdapter` 调用。失去同步的文档比没有文档更糟;而本代码库主要由 agent(智能体)构建,agent 遵守门禁远比遵守行文约定可靠(机械质量门禁)。有两类文档漂移可以被机械检查:不再能编译的代码块,以及与 `interface Events` 声明重复的事件分类体系表。 @@ -15,7 +15,7 @@ AGENTS.md 承诺文档与代码严格同步,但这一承诺此前仅靠人眼 1. **`doc-typecheck`** 从 `README.md`、`docs/**` 和 `packages/*/README.md` 中提取所有 ` ```ts ` 围栏代码块,写入一个继承根 `tsconfig.json` 的临时项目,然后用 `tsc -b` 编译。临时项目复用源码的 `paths` 映射和根 project references,因此文档示例能看到源码,而 vendor 代码仍在其自身的 tsconfig 设置下被检查。刻意作为草图的代码块可通过显式的 ` ```ts ignore-check ` 信息字符串来 opt-out;脚本会报告 opt-out 比例,超过一半即失败,防止该豁免机制悄然成为常态。 2. **`verify-event-taxonomy`** 从 `packages/*/src` 中的 `interface Events` 块和 `docs/architecture.md` 中的分类体系表分别提取事件名称,断言两个集合完全一致。只校验,不生成:表格保留手写的 Mode/Purpose 列,仅检查名称集合。(落地此门禁时发现了表格遗漏的三个事件:`tools/change`、`llm/adapter-change`、`system-prompt/change`。)**已被取代**:由[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)取代。此门禁及其 `architecture.md` 表格已退役,取而代之的是完全生成的 `docs/cordis-catalog/events.md` + `docs/cordis-catalog/services.md` 及其 `verify-cordis-catalog` 新鲜度门禁。本 RFC 中的其他门禁(`doc-typecheck` 以及下文修订中的 `verify-md-wrap`)不受影响。 -两者通过一个共享的 doc-sync(文档同步门禁)`package.json` 脚本运行,lefthook pre-push 钩子和 CI 都调用它([机械质量门禁](2026-06-11-quality-gates.md):钩子与 CI 调用相同脚本,因此门禁在推送前就在本地触发,而非仅在推送后)。它们在 `pnpm run typecheck` 之后运行,后者校验 doc-typecheck 所引用的 package/vendor 构建图。 +两者通过一个共享的 `doc-sync`(文档同步门禁)package.json 脚本运行,lefthook pre-push 钩子和 CI 都调用它([机械质量门禁](2026-06-11-quality-gates.md):钩子与 CI 调用相同脚本,因此门禁在推送前就在本地触发,而非仅在推送后)。它们在 `pnpm run typecheck` 之后运行,后者校验 doc-typecheck 所引用的 package/vendor 构建图。 **修订(2026-06-17):** 第三道门禁 **`verify-md-wrap`** 随后被纳入 `doc-sync`。它使用 `mdast-util-from-markdown` + GFM 解析范围内的每个 Markdown 文件(`README.md`、`docs/**`、`packages/*/README.md`,加上 `AGENTS.md` / `packages/AGENTS.md`),如果任何 `paragraph` 节点跨越多个源码行则失败,从而强制执行 docs/AGENTS.md 中「一个段落一个物理行」的写作规则。同样遵循只校验不生成的原则:它报告硬换行但从不重写,因此不会引入格式化噪音。`doc-sync` 现在包含三道门禁。 diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml index ba5bb828a2..be4c70583e 100644 --- a/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.i18n.yaml @@ -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 -2026-06-11-quality-gates.md: 9862dc019dd6ff3b4639983821256395d0ee7b77 -2026-06-11-quality-gates.zh.md: a9c17bb700db091d21f7930942a8f3bbf55958a0 +2026-06-11-quality-gates.md: 2d6b6815e80a728cb61a86e9f7a488340fe06fc9 +2026-06-11-quality-gates.zh.md: f5088811f8562f5103740d39b48bd14c6d1da00c diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.md b/docs/rfc/implemented/process/2026-06-11-quality-gates.md index 9862dc019d..2d6b6815e8 100644 --- a/docs/rfc/implemented/process/2026-06-11-quality-gates.md +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.md @@ -1,9 +1,9 @@ # RFC: Mechanical quality gates over prose guidelines -English | [中文](2026-06-11-quality-gates.zh.md) - Status: implemented +English | [中文](2026-06-11-quality-gates.zh.md) + ## Problem This codebase is developed primarily by coding agents. Agents follow enforced gates far more reliably than prose conventions, and "a lot of work" is not a cost argument when agents do the labor. Early evidence: tests that didn't typecheck shipped (vitest doesn't typecheck) and were only caught by a review. diff --git a/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md b/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md index a9c17bb700..f5088811f8 100644 --- a/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-quality-gates.zh.md @@ -1,9 +1,9 @@ -# RFC:以机械质量门禁取代行文约定 - -[English](2026-06-11-quality-gates.md) | 中文 +# RFC: 以机械质量门禁取代行文约定 Status: implemented +[English](2026-06-11-quality-gates.md) | 中文 + ## 问题 本代码库主要由 coding agent(智能体)开发。相比行文约定,agent 遵守强制门禁的可靠性远高得多;而当劳动由 agent 承担时,「工作量大」不构成成本论据。早期证据:未通过类型检查的测试被提交(vitest 不做类型检查),仅在评审中才被发现。 @@ -15,7 +15,7 @@ AGENTS.md 中的每一条承诺都对应一个以非零退出码表示失败的 - 最严格的 TypeScript 配置(`noUncheckedIndexedAccess`、`exactOptionalPropertyTypes` 等);示例、测试和脚本通过根目录的 no-emit `tsconfig.json` 在 CI 中进行类型检查,而 package/vendor 代码保持在各自 project-reference 边界之后。 - ESLint strict-type-checked + @stylistic(作为强制执行的统一代码风格),包括文件内重复逻辑检查;vendor 代码排除在外。 - jscpd 检测 package 生产 TypeScript 与仓库脚本中的跨文件克隆;窄范围的源码区间例外用于记录有意为之的并行实现。 -- `packages/*/*/src` 下按文件 100% 覆盖率(v8);不可达的防御性守卫使用 `/* v8 ignore */` 并注明理由,而非删除。 +- `packages/*/*/src` 下按文件 100% 覆盖率(v8);不可达的防御性守卫使用 `/* v8 ignore */ ` 并注明理由,而非删除。 - knip(死代码/依赖)、publint(包(package)正确性)、workspace 约束(workspace 规则:private、cordis peer+dev、统一版本、ESM),以及对构建出的包声明文件进行 NodeNext 消费方类型检查。 - lefthook pre-commit(lint 暂存文件、类型检查、vendor manifest(元数据清单)守卫)和 pre-push(测试、hygiene);CI 在 Node 22.19/24/26 上运行完整矩阵,外加一个驱动 echo-agent 端到端的演示冒烟测试。 diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml index 92dd0f65b6..bb496d19e3 100644 --- a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml @@ -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 -2026-06-11-tsdown-over-dumble.md: c16ac691a9452d952303cf73b40693447d25015c -2026-06-11-tsdown-over-dumble.zh.md: 5e9dc5242225e4420e1faa6ef19c8e8b9b3fdbcd +2026-06-11-tsdown-over-dumble.md: b1ce354b9b2baa042d8aa1be2a8de171ed4adfef +2026-06-11-tsdown-over-dumble.zh.md: 4bdd9939901ef376f2f6ccded609b644a4698495 diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md index c16ac691a9..b1ce354b9b 100644 --- a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.md @@ -1,9 +1,9 @@ # RFC: tsdown for JS bundling instead of dumble -English | [中文](2026-06-11-tsdown-over-dumble.zh.md) - Status: implemented +English | [中文](2026-06-11-tsdown-over-dumble.zh.md) + ## Problem The initial build used **dumble**, the cordiverse zero-config esbuild wrapper that upstream Cordis itself builds with — maximum alignment with the vendored packages' conventions (it reads each package.json and infers entries/formats from the `exports` field). But dumble is a liability as a load-bearing tool in this repo: v0.2.x, ~530 npm downloads/week, effectively one maintainer, and we were invoking it through a custom orchestration script (`scripts/build.ts`) because it has no workspace mode. diff --git a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md index 5e9dc52422..4bdd993990 100644 --- a/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-tsdown-over-dumble.zh.md @@ -1,9 +1,9 @@ -# RFC:使用 tsdown 替代 dumble 进行 JS 打包 - -[English](2026-06-11-tsdown-over-dumble.md) | 中文 +# RFC: 使用 tsdown 替代 dumble 进行 JS 打包 Status: implemented +[English](2026-06-11-tsdown-over-dumble.md) | 中文 + ## 问题 最初的构建使用 **dumble**,即 cordiverse 的零配置 esbuild 包装层——上游 Cordis 自身也用它构建——与 vendor 包(package)的约定最大程度对齐(它读取每个 package.json 并从 `exports` 字段推断入口/格式)。但 dumble 作为本仓库的承重工具存在隐患:v0.2.x,每周约 530 次 npm 下载,实质上只有一位维护者,而且由于它没有 workspace 模式,我们不得不通过自定义编排脚本(`scripts/build.ts`)来调用它。 diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml index b71b7d025d..339d733f07 100644 --- a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml @@ -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 -2026-06-11-vendor-cordis-as-source.md: 39506300dec73d0c9eb1b7b2246caa23f1b10f7f -2026-06-11-vendor-cordis-as-source.zh.md: 0e794d97c4d535b74279bab11bda519e7da2e366 +2026-06-11-vendor-cordis-as-source.md: 6e1af616785411a20496334fb35e0c7a3bc41b43 +2026-06-11-vendor-cordis-as-source.zh.md: bb9413fbba34e9a7040fd2e0a1bbcff1ba2345ff diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md index 39506300de..6e1af61678 100644 --- a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.md @@ -1,9 +1,9 @@ # RFC: Vendor Cordis as source, not npm dependencies -English | [中文](2026-06-11-vendor-cordis-as-source.zh.md) - Status: implemented +English | [中文](2026-06-11-vendor-cordis-as-source.zh.md) + ## Problem DeepSeek Harness SDK is built on the Cordis framework. Cordis core was at 4.0.0-rc.6 (a release candidate) when this repo started; the harness depends on framework internals (fiber lifecycle, effect disposal, waterfall dispatch) whose exact behavior matters to the agent loop's correctness guarantees. diff --git a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md index 0e794d97c4..bb9413fbba 100644 --- a/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md +++ b/docs/rfc/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md @@ -1,9 +1,9 @@ -# RFC:将 Cordis 以源码形式收录,而非作为 npm 依赖 - -[English](2026-06-11-vendor-cordis-as-source.md) | 中文 +# RFC: 将 Cordis 以源码形式收录,而非作为 npm 依赖 Status: implemented +[English](2026-06-11-vendor-cordis-as-source.md) | 中文 + ## 问题 DeepSeek Harness SDK 构建于 Cordis 框架之上。本仓库启动时,Cordis core 处于 4.0.0-rc.6(一个候选发布版本);harness 依赖框架内部实现(fiber 生命周期、dispose(资源释放)、waterfall(瀑布式事件)分发),其确切行为直接关系到 agent loop(智能体循环)的正确性保证。 diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml index ec328ff0e0..41084092d0 100644 --- a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml @@ -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 -2026-06-16-pnpm-over-yarn.md: 6e7a6e1f53056e36f54f44b87b305afa593da549 -2026-06-16-pnpm-over-yarn.zh.md: ba63575909f2bafbbad2102c85d6bede77999997 +2026-06-16-pnpm-over-yarn.md: f5787dc3019f2c474761972afb11deb42f3950e0 +2026-06-16-pnpm-over-yarn.zh.md: 0f5acd13f6f113a569fbe4e7b92df62309c76537 diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md index 6e7a6e1f53..f5787dc301 100644 --- a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.md @@ -1,9 +1,9 @@ # RFC: pnpm as the package manager instead of Yarn 4 -English | [中文](2026-06-16-pnpm-over-yarn.zh.md) - Status: implemented +English | [中文](2026-06-16-pnpm-over-yarn.zh.md) + ## Problem The repo shipped on **Yarn 4** with the `node-modules` linker — a deliberately conservative choice that behaves like npm's flat layout while giving us Yarn's workspaces and `yarn constraints`. It worked. But Yarn 4's Plug'n'Play heritage makes the `node-modules` linker the off-the-beaten-path mode, and the broader JS ecosystem — tooling defaults, CI actions, Corepack examples, contributor familiarity — increasingly centers on pnpm. For a repo that is built primarily by agents and read by occasional human contributors, "the package manager most tools and people expect" has real value: fewer surprises, better-trodden failure paths, more copy-pasteable answers. diff --git a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md index ba63575909..0f5acd13f6 100644 --- a/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md +++ b/docs/rfc/implemented/process/2026-06-16-pnpm-over-yarn.zh.md @@ -1,9 +1,9 @@ -# RFC:使用 pnpm 替代 Yarn 4 作为包管理器 - -[English](2026-06-16-pnpm-over-yarn.md) | 中文 +# RFC: 使用 pnpm 替代 Yarn 4 作为包管理器 Status: implemented +[English](2026-06-16-pnpm-over-yarn.md) | 中文 + ## 问题 本仓库最初使用 **Yarn 4** 搭配 `node-modules` 链接器启动。这是一个刻意保守的选择:行为类似 npm 的扁平布局,同时享有 Yarn 的 workspaces 和 `yarn constraints`。它能正常工作。但 Yarn 4 源自 Plug'n'Play 的血统,使得 `node-modules` 链接器成为非主流模式;而更广泛的 JS 生态——工具默认值、CI action、Corepack 示例、贡献者的熟悉度——正日益以 pnpm 为中心。对于一个主要由 agent(智能体)构建、偶尔有人类贡献者阅读的仓库而言,「大多数工具和人所期望的包管理器」具有实际价值:更少的意外、更成熟的故障路径、更多可直接复用的解答。 diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml b/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml index 92e8c81d4b..413c51c906 100644 --- a/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.i18n.yaml @@ -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 -2026-06-17-ts-build-config.md: cf70014b5873f74da8476c21dd71feedb956f59f -2026-06-17-ts-build-config.zh.md: d3dd0fb13edd22f1ae365286cbf8144fa0bc3f69 +2026-06-17-ts-build-config.md: 9a75bcc3f043576f1cb793c38e0166aa0a010f68 +2026-06-17-ts-build-config.zh.md: c0f6bd40f3f0b06e79b9dc9f9c7812481413374c diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.md b/docs/rfc/implemented/process/2026-06-17-ts-build-config.md index cf70014b58..9a75bcc3f0 100644 --- a/docs/rfc/implemented/process/2026-06-17-ts-build-config.md +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.md @@ -1,9 +1,9 @@ # RFC: TSC-first build and one tsconfig -English | [中文](2026-06-17-ts-build-config.zh.md) - Status: implemented +English | [中文](2026-06-17-ts-build-config.zh.md) + ## Problem The current TypeScript build and typecheck setup had these issues: diff --git a/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md b/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md index d3dd0fb13e..c0f6bd40f3 100644 --- a/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md +++ b/docs/rfc/implemented/process/2026-06-17-ts-build-config.zh.md @@ -1,9 +1,9 @@ -# RFC:TSC 优先的构建与单一 tsconfig - -[English](2026-06-17-ts-build-config.md) | 中文 +# RFC: TSC 优先的构建与单一 tsconfig Status: implemented +[English](2026-06-17-ts-build-config.md) | 中文 + ## 问题 此前的 TypeScript 构建与类型检查配置存在以下问题: @@ -17,7 +17,7 @@ Status: implemented - `tsdown` 使用 `oxc` 进行 TypeScript 转换,其行为与 `tsc` 不同。 - `tsdown` 输出的打包 `.d.ts` 与 Cordis 内部的相对模块增强(module augmentation)结构冲突。 - - `tsc` 的输出受 `allowImportingTsExtensions` 影响,因此需要确保生成的 `.js` 文件不会导入 `.ts` 文件,且生成的 `.d.ts` 文件保留 NodeNext/Node16 接受的显式相对说明符。为此,包内相对导入在 TypeScript 源码中使用显式 `.ts` 说明符,由 `rewriteRelativeImportExtensions` 在输出的 JS 中将其重写为 `.js`。 + - tsc 的输出受 `allowImportingTsExtensions` 影响,因此需要确保生成的 `.js` 文件不会导入 `.ts` 文件,且生成的 `.d.ts` 文件保留 NodeNext/Node16 接受的显式相对说明符。为此,包内相对导入在 TypeScript 源码中使用显式 `.ts` 说明符,由 `rewriteRelativeImportExtensions` 在输出的 JS 中将其重写为 `.js`。 - `tsdown` 输出的打包 `.js` 与 `tsc -b` 逐文件输出的 `.js` 行为不同,例如装饰器转换行为。 - `vendor/*/src`、示例、测试和脚本无法全部以 plain-include 方式纳入一个根目录的严格程序。 - 在根目录严格配置下直接对 `vendor/*/src` 做类型检查,会触发大量不属于本项目所有权范围的类型错误。 diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml index 2b7b62f141..0f0677a911 100644 --- a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml @@ -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 -2026-06-18-markdown-cross-link-lint.md: c802b4071abf652824647e4417cde3f518776353 -2026-06-18-markdown-cross-link-lint.zh.md: 917580ffce71258896f3d23ef7efef4be0176949 +2026-06-18-markdown-cross-link-lint.md: f7ab6a4fd2b2c5cadaeabd5ef0c89f1097b5b44d +2026-06-18-markdown-cross-link-lint.zh.md: 61187042a3a0d3535479ffe3a796b6c1fdb82f5e diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md index c802b4071a..f7ab6a4fd2 100644 --- a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.md @@ -1,9 +1,9 @@ # RFC: Markdown cross-link validity linting -English | [中文](2026-06-18-markdown-cross-link-lint.zh.md) - Status: implemented +English | [中文](2026-06-18-markdown-cross-link-lint.zh.md) + ## Problem Docs in this repo link to each other by relative path — `[topic](../implemented/2026-…-….md)`, `[the cookbook](adding-a-tool.md)`, `[architecture.md](../../architecture.md)`. Nothing verified those targets exist. A rename or a move silently breaks every inbound link, and the break is invisible until a reader clicks it. [Doc-sync enforcement](2026-06-11-doc-sync-enforcement.md) already mechanized two classes of doc drift (uncompilable code blocks, a stale event-taxonomy table) and [verify-md-wrap](2026-06-11-doc-sync-enforcement.md) a third (hard-wrapped prose) — but a dead cross-link is a fourth, equally mechanical class that was still verified by eyeball. diff --git a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md index 917580ffce..61187042a3 100644 --- a/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md +++ b/docs/rfc/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md @@ -1,9 +1,9 @@ -# RFC:Markdown 交叉链接有效性检查 - -[English](2026-06-18-markdown-cross-link-lint.md) | 中文 +# RFC: Markdown 交叉链接有效性检查 Status: implemented +[English](2026-06-18-markdown-cross-link-lint.md) | 中文 + ## 问题 本仓库的文档通过相对路径互相链接:`[topic](../implemented/2026-…-….md)`、`[the cookbook](adding-a-tool.md)`、`[architecture.md](../../architecture.md)`。此前没有任何机制验证这些目标是否存在。重命名或移动文件会静默破坏所有指向它的链接,且在读者点击之前不可见。[Doc-sync 强制](2026-06-11-doc-sync-enforcement.md)已经将两类文档漂移机械化(无法编译的代码块、陈旧的事件分类表),[verify-md-wrap](2026-06-11-doc-sync-enforcement.md) 覆盖了第三类(硬换行的段落),但死链是第四类同样可机械检查、却仍靠肉眼验证的问题。 @@ -20,7 +20,7 @@ Status: implemented 范围与其他门禁一致,另外加上 AGENTS.md 对和 `.agents/skills/` 下仓库自有的 agent skill Markdown(这些 skill 文件交叉链接到 docs 目录,因此本次重组也改写了其中的链接):`README.md`、`docs/**/*.md`、`packages/*/README.md`、`AGENTS.md`、`packages/AGENTS.md`、`.agents/skills/**/*.md`,按真实路径去重(`CLAUDE.md` 符号链接解析到 AGENTS.md 文件)。它接入 lefthook pre-push 钩子和 CI 都会运行的 `doc-sync` 脚本,因此死链在推送前就会在本地失败——与[机械化质量门禁](2026-06-11-quality-gates.md)一致。 -本门禁检查的是**文件存在性**,而非锚点有效性:指向一个真实文件但带有 `#wrong-heading` 片段的链接仍会通过(文件可解析;片段被剥除)。 +本门禁检查的是*文件存在性*,而非锚点有效性:指向一个真实文件但带有 `#wrong-heading` 片段的链接仍会通过(文件可解析;片段被剥除)。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml index 4345634014..7b498b0a81 100644 --- a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml @@ -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 -2026-06-20-core-data-structures-catalog.md: 5f1232f2f0d0644d4043af217a7177451155030b -2026-06-20-core-data-structures-catalog.zh.md: 8ad4453890d8be5dc4e743d1f6f9aa6a9330ed17 +2026-06-20-core-data-structures-catalog.md: 933844d0f442306af238bfc459372b1c97414f87 +2026-06-20-core-data-structures-catalog.zh.md: 620457b28d6b4aa36ec139da7bcd892ed78e2673 diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md index 5f1232f2f0..933844d0f4 100644 --- a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.md @@ -1,9 +1,9 @@ # RFC: Core-data-structures catalog and the `ts type-equiv` drift gate -English | [中文](2026-06-20-core-data-structures-catalog.zh.md) - Status: implemented +English | [中文](2026-06-20-core-data-structures-catalog.zh.md) + ## Problem A reader trying to understand the harness could find its *behavior* in [architecture.md](../../../architecture.md) (the service map, the session/turn/step lifecycle, the event taxonomy) but had no single place describing its *vocabulary* — the data structures that behavior moves around. The type shapes lived only in source, scattered across `packages/*/src/types.ts`, so understanding "what is a `Message`, a `SessionEvent`, a `StreamChunk`" meant reading the declarations directly. A prose catalog would help, but a catalog that paraphrases or paste-copies type definitions rots the instant a field changes — and an out-of-sync type doc is worse than none, because a reader trusts it. diff --git a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md index 8ad4453890..620457b28d 100644 --- a/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-06-20-core-data-structures-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC:核心数据结构目录与 `ts type-equiv` 漂移门禁 +# RFC: 核心数据结构目录与 `ts type-equiv` 漂移门禁 Status: implemented @@ -22,7 +22,7 @@ Status: implemented - 一个数据结构是**核心**的,如果它流经 agent loop 主干——无论加载了哪些插件,循环在每个轮次都会持有、派生、流式输出或记录它(`Message`、`StreamChunk`、`SessionEvent`、`Agent` 句柄)——**或者**它是插件作者面对某条流水线时编写的唯一标志性类型(`ToolDefinition`)。 - `ToolDefinition` 是核心(它是每个工具作者编写的东西),**即使循环从不持有它**——对于这一个标志性类型,撰写重要性压过了严格的"流经主干"规则。但它的类型推导机制——`SchemaSpec`/`InferArgs` DSL——是子页面细节(你编写的是 `ToolDefinition`;为其提供类型推导的机制你并不直接接触)。这就是主干与 seam 分界线的精确表述。 -- `ToolSchema` 是核心(它是 `GenerateOptions` 的一个字段,而 `GenerateOptions` 是流经每个步骤的模型请求),即使它在概念上属于工具流水线——当*流经主干*与*概念归属*冲突时,前者胜出。 +- `ToolSchema` 是核心(它是流经每个步骤的模型请求 `GenerateOptions` 的一个字段),即使它在概念上属于工具流水线——当*流经主干*与*概念归属*冲突时,前者胜出。 - 工具展示词汇(`ToolCallView`/`ToolResultView` 等)、`SessionPersistence` 持久性 seam 以及 bash 词汇是子页面。 `core.md` 是一份**自包含的主干文档**:它给出每个主干结构的确切类型定义,辅以最少的行文,并链接到子页面获取各 seam 的细节。子页面包括 `llm-streaming.md`、`session.md`、`persistence.md`(沿内存模型与持久性 seam 的分界线从 session 拆出)、`tools.md` 和 `bash.md`。 @@ -56,5 +56,5 @@ Status: implemented - 词汇现在有了一个**不会静默漂移**的唯一归属:源码中的字段重命名会在 pre-push 钩子和 CI 中导致 `verify-type-equiv` 失败,直到粘贴内容被刷新。 - 主干与 seam 分界线是一个可复用的范围界定工具,而非一次性的:同一条「你编写/持有/接收的东西是核心;为其提供类型推导/渲染/持久化的机制是细节」规则,后来也被用于界定事件/服务目录的 harness 层与继承层分层。 -- ` ```ts type-equiv ` 围栏是继 ` ```ts `(编译)和 ` ```ts ignore-check `(草稿)之后的第三种文档块类别。后续的姊妹门禁又增加了第四种 ` ```ts cordis-catalog `(生成签名),复用了相同的跳过并排除处理。 +- `ts type-equiv` 围栏是继 ` ```ts `(编译)和 ` ```ts ignore-check `(草稿)之后的第三种文档块类别。后续的姊妹门禁又增加了第四种 ` ```ts cordis-catalog `(生成签名),复用了相同的跳过并排除处理。 - 添加或重塑核心类型现在附带一项文档义务,作者必须履行(门禁无法检测缺失的*新*类型),由 `dsh-code-review` 检查清单兜底。 diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml index 9f7e982ff7..13f31c3ebe 100644 --- a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml @@ -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 -2026-06-20-generated-cordis-catalog.md: 6b451e31965f8f00210aa927ed236fed28699351 -2026-06-20-generated-cordis-catalog.zh.md: 5550d07b5f5635d1da6496e35049c5725329e114 +2026-06-20-generated-cordis-catalog.md: 8b979764c1ae6693b77817fc84381e40e56f8d36 +2026-06-20-generated-cordis-catalog.zh.md: 608ab3e0429fab43abec634ce0955f46306d8529 diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md index 6b451e3196..8b979764c1 100644 --- a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.md @@ -1,9 +1,9 @@ # RFC: Generated cordis events + services catalog -English | [中文](2026-06-20-generated-cordis-catalog.zh.md) - Status: implemented +English | [中文](2026-06-20-generated-cordis-catalog.zh.md) + ## Problem A plugin author needs two reference surfaces that no single document gave them: every cordis **event** they can listen to (with its exact signature and dispatch mode) and every `ctx.<key>` **service** they can call (with its exact interface). The pieces existed but were scattered — a hand-maintained event-taxonomy *table* in `docs/architecture.md` (names + prose Mode/Purpose, name-set-checked by `verify-event-taxonomy`), a Service-map table (8 rows of role prose), and the `interface Events` / `interface Context` declarations themselves. The taxonomy table also could not catch a brand-new *undocumented* event: a name-set verifier only checks the names that are already in the table on both sides. diff --git a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md index 5550d07b5f..608ab3e042 100644 --- a/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-06-20-generated-cordis-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC:生成式 Cordis 事件与服务目录 +# RFC: 生成式 Cordis 事件与服务目录 Status: implemented @@ -21,8 +21,8 @@ Status: implemented 具体选择: - **`@mode` 标签,交叉校验。** 每个 harness 事件的 JSDoc 携带一个显式的 `@mode emit|waterfall|parallel|serial` 标签;缺少标签时生成器直接报错。当签名形状具有决定性时——尾部参数为 `next: () => …` 在结构上即为 waterfall(瀑布式事件)——生成器断言标签与之一致,矛盾时直接报错。emit/parallel/serial 的区别在结构上不可见(`session/flush` 返回 `Promise<void> | void` 且无 `next`,有序的 `agent/pre-step` 检查点亦然),因此信任标签。编写规则见 [AGENTS.md](../../../../AGENTS.md)。 -- **分层范围。** harness 层(8 个 `@deepseek-ai/dsh-*` 服务及其事件)从源码完整渲染。继承层(cordis-core 的 `ctx.on/emit/effect/provide/…` + `internal/*` 事件 + loader/hmr/timer)是插件同样可见的固定 vendor 源码;它从生成器中一张人工维护的表格简洁渲染(名称 + 一行描述 + 源码指针),而**非**遍历 vendor AST。原因是 cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段(`root`、`baseUrl`、`logger`),且 vendor 接口面仅在有意的 vendor 同步时才变化。 -- **交叉链接到数据结构目录。** 签名中的类型名(`GenerateOptions`、`StreamChunk`、`ToolDefinition` 等)链接到记录该类型的 core-data-structures 页面。映射是生成器中一个小型的人工维护常量,而**非** `type-equiv.manifest.json`——后者记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 +- **分层范围。** harness 层(8 个 `@deepseek-ai/dsh-*` 服务及其事件)从源码完整渲染。继承层(cordis-core 的 `ctx.on/emit/effect/provide/…` + `internal/*` 事件 + loader/hmr/timer)是插件同样可见的固定 vendor 源码;它从生成器中一张人工维护的表格简洁渲染(名称 + 一行描述 + 源码指针),而非遍历 vendor AST。原因是 cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段(`root`、`baseUrl`、`logger`),且 vendor 接口面仅在有意的 vendor 同步时才变化。 +- **交叉链接到数据结构目录。** 签名中的类型名(`GenerateOptions`、`StreamChunk`、`ToolDefinition` 等)链接到记录该类型的 core-data-structures 页面。映射是生成器中一个小型的人工维护常量,而非 `type-equiv.manifest.json`——后者记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 - **专用围栏。** 签名块使用 ` ```ts cordis-catalog ` 信息字符串,`doc-typecheck` 识别后跳过(裸签名片段不能独立编译),并排除在 opt-out 比例之外——与 `type-equiv` 块获得相同待遇。 本决策**取代** [doc-sync 强制](2026-06-11-doc-sync-enforcement.md)中事件分类的那一半:`verify-event-taxonomy` 及其 `docs/architecture.md` 表格退役(architecture.md 的标题保留,正文改为指向目录;服务映射的角色表格作为人工行文保留)。doc-typecheck、verify-md-wrap、verify-md-links 和 verify-type-equiv 不受影响。 diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml b/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml index cc4642657c..c9a4c3a6e9 100644 --- a/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.i18n.yaml @@ -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 -2026-06-20-rfc-classification.md: 201852a209be7f40b05de45d148a36b9185767a3 -2026-06-20-rfc-classification.zh.md: 554ac8014719c99ed447a33ff843c40fde761eed +2026-06-20-rfc-classification.md: 6975b74dbaa9ca9379f23b537133323cb694958a +2026-06-20-rfc-classification.zh.md: 423d5c87eb9e2cb07ed18834f4c15ffa1ac1983e diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.md b/docs/rfc/implemented/process/2026-06-20-rfc-classification.md index 201852a209..6975b74dba 100644 --- a/docs/rfc/implemented/process/2026-06-20-rfc-classification.md +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.md @@ -1,9 +1,9 @@ # RFC: Classify RFCs by kind via path-encoded subdirectories -English | [中文](2026-06-20-rfc-classification.zh.md) - Status: implemented +English | [中文](2026-06-20-rfc-classification.zh.md) + ## Problem `docs/rfc/` grouped RFCs by **lifecycle** only — `proposed/` / `implemented/` / `rejected/`. Nothing recorded what *kind* of decision each RFC was. The index was one flat list per lifecycle, with no way to scan "show me every simplification" or "every testing-strategy decision." A wave of simplification RFCs landing on the same day made the gap concrete: a reader skimming `proposed/` could not tell a new capability from a removal from a tooling-policy change without opening each file. diff --git a/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md b/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md index 554ac80147..423d5c87eb 100644 --- a/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md +++ b/docs/rfc/implemented/process/2026-06-20-rfc-classification.zh.md @@ -1,9 +1,9 @@ -# RFC:通过路径编码的子目录对 RFC 进行分类 - -[English](2026-06-20-rfc-classification.md) | 中文 +# RFC: 通过路径编码的子目录对 RFC 进行分类 Status: implemented +[English](2026-06-20-rfc-classification.md) | 中文 + ## 问题 `docs/rfc/` 过去仅按**生命周期**分组 RFC:`proposed/`/`implemented/`/`rejected/`。没有任何机制记录每个 RFC 属于哪一*类*决策。索引在每个生命周期下只是一个扁平列表,无法按需筛选「所有简化类」或「所有测试策略类」决策。一批简化类 RFC 在同一天落地后,这个缺口变得具体:浏览 `proposed/` 的读者无法在不逐一打开文件的情况下区分新能力、移除和工具策略变更。 @@ -12,7 +12,7 @@ Status: implemented ## 决策 -增加第二个维度——RFC 的**类别**——并将其编码在路径中:`{lifecycle}/{class}/yyyy-mm-dd-topic.md`。文件夹本身就是标签。文件的位置声明其类别,封闭集合是「这些文件夹且仅限这些」,而既有的 [verify-md-links](2026-06-18-markdown-cross-link-lint.md) 门禁已经保护了移动文件所需的路径重写。 +增加第二个维度——RFC 的**类别**——并将其编码在路径中:`{lifecycle}/{class}/yyyy-mm-dd-topic.md`。文件夹本身*就是*标签。文件的位置声明其类别,封闭集合是「这些文件夹且仅限这些」,而既有的 [verify-md-links](2026-06-18-markdown-cross-link-lint.md) 门禁已经保护了移动文件所需的路径重写。 ### 六个类别的封闭集合 @@ -22,7 +22,7 @@ Status: implemented | `bug-fix` | 修正缺陷或填补事后复盘暴露的空白。 | | `simplification` | 移除代码、行为或对外表面积,不引入新能力。 | | `architecture` | 关于**交付源码**的结构性决策——包(package)之间的关系、运行时词汇。 | -| `process` | 围绕代码的工具、策略或工作流,而非运行时行为。 | +| `process` | **围绕**代码的工具、策略或工作流,而非运行时行为。 | | `testing` | 测试基础设施与策略。 | `architecture` 与 `process` 的分界线:**architecture** 关乎我们交付的源码;**process** 关乎围绕源码的工具与工作流。本 RFC 本身是一个 `process` 决策——它改变的是仓库的组织方式和门禁,而非 harness 的运行时行为——因此它位于 `implemented/process/` 下。 diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml index 8ecca3648d..80865d0269 100644 --- a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml @@ -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 -2026-07-02-tool-schema-catalog.md: 9a99fafd36b3546be4f51a7cd9e9a47fdaaf4c2d -2026-07-02-tool-schema-catalog.zh.md: 5860d1617ce6592c8665e4cb59304b0f6d35c99a +2026-07-02-tool-schema-catalog.md: fe7ec47ac89c157482f612a374ca8773d7d0867f +2026-07-02-tool-schema-catalog.zh.md: 1567ff5dd5c53da501a86412d0e29127d33d29f6 diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md index 9a99fafd36..fe7ec47ac8 100644 --- a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md @@ -1,9 +1,9 @@ # RFC: Generated tool-schema catalog (boot-and-harvest) -English | [中文](2026-07-02-tool-schema-catalog.zh.md) - Status: implemented +English | [中文](2026-07-02-tool-schema-catalog.zh.md) + ## Problem The repository had no single reference for the names, descriptions, and JSON Schemas actually exposed to the model. Source declarations are scattered and runtime-composed, while the existing Cordis and data-structure catalogs cover wiring and vocabulary rather than tools. diff --git a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md index 5860d1617c..1567ff5dd5 100644 --- a/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.zh.md @@ -1,16 +1,16 @@ -# RFC:生成式工具 schema 目录(启动并采集) - -[English](2026-07-02-tool-schema-catalog.md) | 中文 +# RFC: 生成式工具 schema 目录(启动并采集) Status: implemented +[English](2026-07-02-tool-schema-catalog.md) | 中文 + ## 问题 仓库此前没有一份统一的参考文档来记录实际暴露给模型的工具名称、描述与 JSON Schema。源码声明分散各处且在运行时组合,而既有的 Cordis 目录和数据结构目录覆盖的是接线与词汇,而非工具。 ## 决策 -通过**启动每个工具插件并读取其注册的 schema** 来生成目录,而非解析源码。`scripts/gen-tool-catalog.ts` 将每个已发布的工具包(package)挂载到一个新的 Cordis `Context`(带 `SystemPrompt` + `ToolRegistry` 以及插件 `apply` 所读取的注入 seam),调用 `ctx.tools.schemas()`(即发送给模型的 `ToolSchema[]`),dispose(资源释放)该 context,然后为每个包渲染一个 `## <package>` 小节,每个工具一个 ` ```json ` 的 `parameters` 块。它与 `gen-cordis-catalog` / `gen-module-graph` 的 CLI(命令行界面)形态一致:默认 `--write` 重新生成,`--check` 在已提交副本陈旧时失败,输出是确定性的(按 manifest(元数据清单)排序,工具按名称排序)。`verify-tool-catalog`(即 `--check`)在 doc-sync(文档同步门禁)内运行,因此新鲜度门禁在 lefthook pre-push 和 CI 路径中与其他文档门禁一同触发。 +通过**启动每个工具插件并读取其注册的 schema** 来生成目录,而非解析源码。`scripts/gen-tool-catalog.ts` 将每个已发布的工具包(package)挂载到一个新的 Cordis `Context`(带 `SystemPrompt` + `ToolRegistry` 以及插件 `apply` 所读取的注入 seam),调用 `ctx.tools.schemas()`(即发送给模型的 `ToolSchema[]`),dispose(资源释放)该 context,然后为每个包渲染一个 `## <package>` 小节,每个工具一个 ` ```json ` 的 `parameters` 块。它与 `gen-cordis-catalog` / `gen-module-graph` 的 CLI(命令行界面)形态一致:默认 `--write` 重新生成,`--check` 在已提交副本陈旧时失败,输出是确定性的(按 manifest(元数据清单)排序,工具按名称排序)。`verify-tool-catalog`(即 `--check`)在 `doc-sync`(文档同步门禁)内运行,因此新鲜度门禁在 lefthook pre-push 和 CI 路径中与其他文档门禁一同触发。 ### 为何启动而非解析(核心要点) @@ -25,7 +25,7 @@ Cordis 目录是纯 TypeScript AST 遍历,因为每个事件/服务名都是 ### 恢复「不会静默遗漏」的保证 -启动有一项 AST 遍历不存在的代价:没有源码声明集合可供枚举,新工具包可能被遗忘。一个**完整性守卫**恢复了这项保证——`assertManifestComplete` 对 `packages/` 下所有 `tool-*` 包进行 glob,若有任何一个不在生成器的启动 manifest 中则直接报错。新工具包在注册之前会导致生成器失败,进而导致 doc-sync 失败。这与 Cordis 生成器通过枚举源码免费获得的结构性属性相同,只是为基于启动的生成器重新实现了一遍。 +启动有一项 AST 遍历不存在的代价:没有源码声明集合可供枚举,新工具包可能被遗忘。一个**完整性守卫**恢复了这项保证——`assertManifestComplete` 对 `packages/` 下所有 `tool-*` 包进行 glob,若有任何一个不在生成器的启动 manifest 中则直接报错。新工具包在注册之前会导致生成器失败,进而导致 `doc-sync` 失败。这与 Cordis 生成器通过枚举源码免费获得的结构性属性相同,只是为基于启动的生成器重新实现了一遍。 ### 手动维护的启动 manifest 是不可化约的策略 diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml index 6b19ed7740..d5ad8c6180 100644 --- a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml @@ -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 -2026-07-03-documentation-graph-atlas.md: d10b57e5114684ab0a2caed66fa84b84959bdf12 -2026-07-03-documentation-graph-atlas.zh.md: 6edcfbdbbc3af5808e60888acad04919ce681396 +2026-07-03-documentation-graph-atlas.md: 3cb8e685452a5b013798d0c3f661fca218b3d69d +2026-07-03-documentation-graph-atlas.zh.md: f03268c63c6d834c59af6cf831a34e5a5eaf40d7 diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md index d10b57e511..3cb8e68545 100644 --- a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.md @@ -1,9 +1,9 @@ # RFC: Documentation graph index for maintainers and SDK users -English | [中文](2026-07-03-documentation-graph-atlas.zh.md) - Status: implemented +English | [中文](2026-07-03-documentation-graph-atlas.zh.md) + ## Problem The repo already had several high-trust documentation surfaces, each on a different axis: [module-graph.md](../../../module-graph.md) is generated from package `peerDependencies`, the generated [Cordis events](../../../cordis-catalog/events.md) and [services](../../../cordis-catalog/services.md) catalogs are generated from Cordis `Events` and `Context` declarations, [tool-catalog.md](../../../tool-catalog.md) is generated by booting shipped tool plugins, and [core-data-structures/](../../../core-data-structures/core.md) uses `ts type-equiv` blocks to keep pasted type definitions synchronized with source. diff --git a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md index 6edcfbdbbc..f03268c63c 100644 --- a/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md +++ b/docs/rfc/implemented/process/2026-07-03-documentation-graph-atlas.zh.md @@ -1,9 +1,9 @@ -# RFC:面向维护者与 SDK 用户的文档关系图索引 - -[English](2026-07-03-documentation-graph-atlas.md) | 中文 +# RFC: 面向维护者与 SDK 用户的文档关系图索引 Status: implemented +[English](2026-07-03-documentation-graph-atlas.md) | 中文 + ## 问题 仓库已有若干高可信度的文档面,各自覆盖不同维度:[module-graph.md](../../../module-graph.md) 由包(package)的 `peerDependencies` 生成;生成的 [Cordis events](../../../cordis-catalog/events.md) 与 [services](../../../cordis-catalog/services.md) 目录由 Cordis 的 `Events` 和 `Context` 声明生成;[tool-catalog.md](../../../tool-catalog.md) 通过启动已发布的 tool 插件生成;[core-data-structures/](../../../core-data-structures/core.md) 使用 `ts type-equiv` 块保持粘贴的类型定义与源码同步。 diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml index 80b4958372..520426ca4b 100644 --- a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml @@ -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 -2026-07-04-cordis-jsdoc-completeness-gate.md: 44a0ddce9c929deac3e03bb421aec1d5145e65ba -2026-07-04-cordis-jsdoc-completeness-gate.zh.md: 073054072748bf6cfed09cdcc222087bcc0ed929 +2026-07-04-cordis-jsdoc-completeness-gate.md: 8eaa997eb734b32e7e4a45d96def15dc541af1d5 +2026-07-04-cordis-jsdoc-completeness-gate.zh.md: a49189b3162fbd0eba9e043c683f0fc56d0bf7d6 diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md index 44a0ddce9c..8eaa997eb7 100644 --- a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.md @@ -1,9 +1,9 @@ # RFC: JSDoc completeness gate for the cordis surface -English | [中文](2026-07-04-cordis-jsdoc-completeness-gate.zh.md) - Status: implemented +English | [中文](2026-07-04-cordis-jsdoc-completeness-gate.zh.md) + ## Problem The generated Cordis catalog enforced event dispatch modes but not complete service and event contracts. Methods could lack descriptions, and parameters or returns could be undocumented on the cross-plugin API surface where IDE guidance matters most. diff --git a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md index 0730540727..a49189b316 100644 --- a/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md @@ -1,9 +1,9 @@ -# RFC:针对 Cordis 对外服务接口的 JSDoc 完整性门禁 - -[English](2026-07-04-cordis-jsdoc-completeness-gate.md) | 中文 +# RFC: 针对 Cordis 对外服务接口的 JSDoc 完整性门禁 Status: implemented +[English](2026-07-04-cordis-jsdoc-completeness-gate.md) | 中文 + ## 问题 生成的 Cordis 目录此前强制了事件分发模式,但未强制要求完整的服务与事件契约。方法可以缺少描述,参数或返回值可以在跨插件 API 接口上不写文档——而这恰恰是 IDE 引导最重要的地方。 @@ -12,7 +12,7 @@ AGENTS.md 中的规则(「每个导出都有解释语义的 JSDoc」)只能 ## 决策 -扩展 `scripts/gen-cordis-catalog.ts`(同一次遍历、同一个 `@mode` 先例),对其编目的所有内容强制 JSDoc 完整性。`verify-cordis-catalog` 在 `doc-sync`(文档同步门禁)内运行,CI 和 lefthook pre-push 钩子都已执行 `doc-sync`,因此门禁无需新增任何接线(质量门禁原则:单一真源)。 +扩展 `scripts/gen-cordis-catalog.ts`(同一次遍历、同一个 `@mode` 先例),对其编目的所有内容强制 JSDoc 完整性。`verify-cordis-catalog` 在 `doc-sync`(文档同步门禁)内运行,CI 和 lefthook pre-push 钩子都已执行该命令,因此门禁无需新增任何接线(质量门禁原则:单一真源)。 契约如下: diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml index d6465ad8c1..15039922c5 100644 --- a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml @@ -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 -2026-07-04-doc-tiers-and-budgets.md: ca9da847849f61f2fb244932e657cca8fec69696 -2026-07-04-doc-tiers-and-budgets.zh.md: ae34e3f04d7986f78d1b3ceeaacb3bc4c7bc64f5 +2026-07-04-doc-tiers-and-budgets.md: ddbce540c68b9b35bb7e6a48b8db8abbc3a7a398 +2026-07-04-doc-tiers-and-budgets.zh.md: d3f08d337af34b5def41792232330180123dd585 diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md index ca9da84784..ddbce540c6 100644 --- a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.md @@ -1,9 +1,9 @@ # RFC: Documentation tiers, budgets, and the ceiling gate -English | [中文](2026-07-04-doc-tiers-and-budgets.zh.md) - Status: implemented +English | [中文](2026-07-04-doc-tiers-and-budgets.zh.md) + ## Problem Standing docs accumulated repeated rules, retold incidents, duplicated package maps, and stale RFC summaries despite existing writing guidance. Because review alone did not prevent that growth, the repository needed a mechanical budget alongside its documentation taxonomy. diff --git a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md index ae34e3f04d..d3f08d337a 100644 --- a/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md @@ -1,9 +1,9 @@ -# RFC:文档分层、预算与上限门禁 - -[English](2026-07-04-doc-tiers-and-budgets.md) | 中文 +# RFC: 文档分层、预算与上限门禁 Status: implemented +[English](2026-07-04-doc-tiers-and-budgets.md) | 中文 + ## 问题 尽管已有写作指导,常设文档仍然积累了重复的规则、重述的事故、重复的包(package)映射和陈旧的 RFC 摘要。仅靠评审无法阻止这种膨胀,因此仓库需要在文档分类体系之外增加一道机械化的预算约束。 diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml index 8d410ae5f8..da8988c6ea 100644 --- a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.i18n.yaml @@ -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 -2026-07-04-generate-rfc-index-tables.md: 6a8888eda8b7cf7105a44802774bf49d6463952d -2026-07-04-generate-rfc-index-tables.zh.md: aad1652edc9de81a70a7a391700f63be9499035c +2026-07-04-generate-rfc-index-tables.md: 5d5ae258583e0fae7dcb44a23c4b41446bd233d2 +2026-07-04-generate-rfc-index-tables.zh.md: fa611e4337075501fe097fe8fc68a878a855a7c0 diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md index 6a8888eda8..5d5ae25858 100644 --- a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.md @@ -1,9 +1,9 @@ # RFC: Generate the RFC index tables -English | [中文](2026-07-04-generate-rfc-index-tables.zh.md) - Status: implemented +English | [中文](2026-07-04-generate-rfc-index-tables.zh.md) + ## Problem The RFC index's per-lifecycle/per-class tables list facts that are fully derivable: an RFC's path encodes lifecycle and class, its filename encodes the first-proposed date, and its H1 carries the title. A hand-maintained copy of those facts is also the repo's highest-contention docs hotspot: every proposal wave appends rows to the same few lines, so concurrent RFC branches conflict precisely there while agreeing everywhere else, and each conflict is resolved by hand-merging rows whose content the filesystem already knows. [The classification RFC](2026-06-20-rfc-classification.md) originally kept the index hand-written for curation's sake — but the curated part of the README is the prose, and the prose never conflicts; only the mechanical tables do. diff --git a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md index aad1652edc..fa611e4337 100644 --- a/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-generate-rfc-index-tables.zh.md @@ -1,9 +1,9 @@ -# RFC:生成 RFC 索引表 - -[English](2026-07-04-generate-rfc-index-tables.md) | 中文 +# RFC: 生成 RFC 索引表 Status: implemented +[English](2026-07-04-generate-rfc-index-tables.md) | 中文 + ## 问题 RFC 索引中按生命周期/按分类的表格所列信息完全可以推导:RFC 的路径编码了生命周期与分类,文件名编码了首次提出日期,H1 标题承载了标题文本。这些信息的手工维护副本也是仓库中冲突最频繁的文档热点:每一波提案都在同几行后追加新行,因此并发的 RFC 分支恰好在此处冲突,而其他地方完全一致;每次冲突都要手工合并那些文件系统本已知晓的行。[分类 RFC](2026-06-20-rfc-classification.md) 最初为了可策展性而保留手写索引,但 README 中真正需要策展的是行文,而行文从不冲突;冲突的只有机械表格。 @@ -13,7 +13,7 @@ RFC 索引中按生命周期/按分类的表格所列信息完全可以推导: 保留策展行文;生成列表。表格位于 [`docs/rfc/INDEX.md`](../../INDEX.md),是一个**完全生成的文件**——策展行文留在 README.md 中,README.md 不包含任何索引行。[`scripts/rfc-index.ts`](../../../../scripts/rfc-index.ts) 是共享的真源:树遍历器(拥有封闭的生命周期/分类集合与结构规则,包括对可解析 H1 的要求)和渲染器(行来自 H1 标题并去掉 `RFC: ` 前缀,加上文件名日期,按日期再按文件名排序,以 `### {Class}` 分节、按规范分类顺序分组)。两个轻量消费方共享它: - [`scripts/gen-rfc-index.ts`](../../../../scripts/gen-rfc-index.ts)(`pnpm run gen-rfc-index`)从目录树完整重写 INDEX.md。 -- [`scripts/verify-rfc-classification.ts`](../../../../scripts/verify-rfc-classification.ts)(doc-sync(文档同步门禁)的一个成员)检查结构,断言已提交的 INDEX.md 与新鲜渲染结果逐字节一致(`gen-cordis-catalog`/`verify-cordis-catalog` 模式),并拒绝在策展 README 中出现索引格式的行。新鲜度检查涵盖了索引完整性检查:从磁盘生成的表格在定义上就是完整的、标题正确的。 +- [`scripts/verify-rfc-classification.ts`](../../../../scripts/verify-rfc-classification.ts)(`doc-sync`(文档同步门禁)的一个成员)检查结构,断言已提交的 INDEX.md 与新鲜渲染结果逐字节一致(`gen-cordis-catalog`/`verify-cordis-catalog` 模式),并拒绝在策展 README 中出现索引格式的行。新鲜度检查涵盖了索引完整性检查:从磁盘生成的表格在定义上就是完整的、标题正确的。 添加、移动或删除一个 RFC 只需编辑 RFC 文件本身并运行生成器;分类 RFC 的「已否决替代方案」记录中带有替代关系的交叉链接。 diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml index 5851ab8d1c..7aba38dbc9 100644 --- a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml @@ -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 -2026-07-04-persistence-log-catalog.md: f8f831ca0470cf3b5c7634550115e67f7deac840 -2026-07-04-persistence-log-catalog.zh.md: 1daa76e2b23484ad6434f6a55482672abf456eb7 +2026-07-04-persistence-log-catalog.md: d92666fc8bafcf42542940fe399d9a3ece20c173 +2026-07-04-persistence-log-catalog.zh.md: a3524b251522050567be240f28944872e725a24e diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md index f8f831ca04..d92666fc8b 100644 --- a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md @@ -1,9 +1,9 @@ # RFC: Generated persistence log event catalog -English | [中文](2026-07-04-persistence-log-catalog.zh.md) - Status: implemented +English | [中文](2026-07-04-persistence-log-catalog.zh.md) + ## Problem `SessionEventMap` is the on-disk vocabulary, but its declarations are split across the owning session package and declaration merges. The generated persistence catalog is the single reference for every event and payload; hand-maintained tables drift and are removed. These records are not Cordis events—observers receive them through the single `session/event` bus event—so the Cordis catalog cannot cover them. The generator discovers all declarations and the doc-sync freshness gate rejects omissions or stale output. diff --git a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md index 1daa76e2b2..a3524b2515 100644 --- a/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC:生成式持久化日志事件目录 +# RFC: 生成式持久化日志事件目录 Status: implemented diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml index a5e22d0911..188ebf1019 100644 --- a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.i18n.yaml @@ -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 -2026-07-05-uniform-rfc-format.md: f67c61c0b627950cf07e7d57672324308a9462ec -2026-07-05-uniform-rfc-format.zh.md: b175c2d5b7537e793a61c95b6524d08bc4216384 +2026-07-05-uniform-rfc-format.md: 9688ad6566e88372508bbfd8d032ab6d02568716 +2026-07-05-uniform-rfc-format.zh.md: eab2505e64b813f698b4356bc52a796cbd66b948 diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md index f67c61c0b6..9688ad6566 100644 --- a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md @@ -1,9 +1,9 @@ # RFC: One gated in-file format for RFCs -English | [中文](2026-07-05-uniform-rfc-format.zh.md) - Status: implemented +English | [中文](2026-07-05-uniform-rfc-format.zh.md) + ## Problem RFC paths encoded lifecycle and class, but file contents still mixed headings, status formats, ADR and proposal templates, and proposal-era sections in implemented records. Authors copied whichever neighbor they found, and lifecycle moves could skip the required rewrite because no gate enforced an in-file contract. diff --git a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md index b175c2d5b7..eab2505e64 100644 --- a/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md +++ b/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.zh.md @@ -1,16 +1,16 @@ -# RFC:RFC 的统一受门禁约束的文件内格式 - -[English](2026-07-05-uniform-rfc-format.md) | 中文 +# RFC: RFC 的统一受门禁约束的文件内格式 Status: implemented +[English](2026-07-05-uniform-rfc-format.md) | 中文 + ## 问题 RFC 的路径已经编码了生命周期和分类,但文件内容仍然混杂着不同的标题风格、状态格式、ADR 与 proposal 模板,以及已实现记录中残留的 proposal 时期的章节。作者随手复制找到的任何邻近文件,生命周期迁移时可以跳过必要的改写,因为没有门禁强制执行文件内契约。 ## 决策 -[README.md § The file format](../../README.md#the-file-format) 即文件内契约:头部块(`# RFC: <title>` 加上无日期、与所在文件夹一致的 `Status:` 枚举,唯一的正文内容是 rejection reason);按生命周期区分的正文骨架(所有阶段都以 `Problem` 开头;`proposed/` 中为 `Proposal`/`Acceptance criteria`/`Risks`;`implemented/` 中为现在时态的 `Decision`/`Consequences` 且禁止 proposal 时期的标题;`rejected/` 中冻结 proposal 形态);必须包含 `Alternatives considered` 章节;以及规范的章节词汇表,其间的自定义技术章节保持自由形式。`pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../../../scripts/verify-rfc-format.ts))作为 doc-sync(文档同步门禁)的一环强制执行每条机械化条款,因此生命周期迁移时跳过改写现在会让 CI 失败,而不是依赖评审者的记忆。 +[README.md § The file format](../../README.md#the-file-format) 即文件内契约:头部块(`# RFC: <title>` 加上无日期、与所在文件夹一致的 `Status:` 枚举,唯一的正文内容是 rejection reason);按生命周期区分的正文骨架(所有阶段都以 `Problem` 开头;`proposed/` 中为 `Proposal`/`Acceptance criteria`/`Risks`;`implemented/` 中为现在时态的 `Decision`/`Consequences` 且禁止 proposal 时期的标题;`rejected/` 中冻结 proposal 形态);必须包含 `Alternatives considered` 章节;以及规范的章节词汇表,其间的自定义技术章节保持自由形式。`pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../../../scripts/verify-rfc-format.ts))作为 `doc-sync`(文档同步门禁)的一环强制执行每条机械化条款,因此生命周期迁移时跳过改写现在会让 CI 失败,而不是依赖评审者的记忆。 整个语料库在定义格式的同一个变更中完成了规范化,这是预发布阶段的立场:没有过渡期,不容忍双格式并存。唯一的祖父条款针对内容而非格式:替代方案是记录下来的,不是凭空编造的;因此如果一篇格式定义前的 RFC 的替代方案无法从记录中重建,它会携带 `rfc-format: alternatives-not-recorded` 这条精确注释,门禁仅对日期早于本 RFC 的文件接受该注释。 diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml index b79ff4cf97..ed24da934e 100644 --- a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml @@ -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 -2026-07-06-export-surface-jsdoc-gate.md: fd255cc6212d7f6f919ad23f999fa68b01478a73 -2026-07-06-export-surface-jsdoc-gate.zh.md: 796b5bb8f3a2a890986c73511bb63e167c831a5f +2026-07-06-export-surface-jsdoc-gate.md: c2543fe50320da70c9d75bb4a16df3b110b50c47 +2026-07-06-export-surface-jsdoc-gate.zh.md: 98cb057cc1a661d2f51b8215609fc280d549c103 diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md index fd255cc621..c2543fe503 100644 --- a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md @@ -1,9 +1,9 @@ # RFC: Export-surface JSDoc gate -English | [中文](2026-07-06-export-surface-jsdoc-gate.zh.md) - Status: implemented +English | [中文](2026-07-06-export-surface-jsdoc-gate.zh.md) + ## Problem The [cordis JSDoc completeness gate](2026-07-04-cordis-jsdoc-completeness-gate.md) made undocumented parameters and results impossible on the cordis surface — `interface Events` members and `ctx.<key>` service classes — but that surface is a fraction of what a plugin author imports. The AGENTS.md rule "every export (and non-obvious method) has a JSDoc explaining semantics" stayed prose-checkable only by review everywhere else, and nothing at all asked for `@param`/`@returns` on ordinary exported functions. A survey at adoption found 203 under-documented module-level exports across 34 packages: seam-adjacent helpers (`runBash`, `readForEdit`, `htmlToMarkdown`), format codecs, whole undocumented interfaces and type aliases — exactly the names an IDE consumer hovers. diff --git a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md index 796b5bb8f3..98cb057cc1 100644 --- a/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md @@ -1,9 +1,9 @@ -# RFC:导出表面 JSDoc 门禁 - -[English](2026-07-06-export-surface-jsdoc-gate.md) | 中文 +# RFC: 导出表面 JSDoc 门禁 Status: implemented +[English](2026-07-06-export-surface-jsdoc-gate.md) | 中文 + ## 问题 [Cordis JSDoc 完整性门禁](2026-07-04-cordis-jsdoc-completeness-gate.md)使得 Cordis 表面上的参数和返回值不可能缺少文档——`interface Events` 成员和 `ctx.<key>` 服务类——但这只是插件作者所导入内容的一小部分。AGENTS.md 中的规则「每个导出(以及非显而易见的方法)都必须有解释语义的 JSDoc」在其他地方只能靠评审以行文方式检查,而且没有任何机制要求普通导出函数带 `@param`/`@returns`。采纳时的一次调查发现 34 个包(package)中有 203 个文档不完整的模块级导出:seam 相关辅助函数(`runBash`、`readForEdit`、`htmlToMarkdown`)、格式编解码器、完全无文档的接口和类型别名——恰恰是 IDE 消费方悬停查看的那些名称。 @@ -19,7 +19,7 @@ Status: implemented - 导出类需要类级别的描述文字;公开方法(包括静态方法——可通过导出名称访问)遵循函数契约;公开属性和访问器需要描述文字(get/set 对由 getter 覆盖)。重载实现体免检——签名承载文档。 - 导出接口、类型别名和枚举需要声明级别的描述文字;成员级别的强制有意推迟(承载关键成员契约的 seam 服务类已在 Cordis 门禁之下)。 - 导出命名空间递归检查(在 ambient `declare` 命名空间内,每个成员隐式导出);命名空间本身仅在不与同名的已文档化声明合并时才需要描述文字(Config-namespace 惯用法只需文档化插件一次)。 -- `declare module`/`declare global` 体和 `export … from` 重导出语句被跳过:augmentation 不是包的导出,重导出的定义在其定义处检查。`export import X = N.member` 别名需要文档化**自身**——其目标可能是遍历不会访问的非导出命名空间成员——且门禁仅支持纯描述文字的目标类型:可调用、类或命名空间目标携带别名描述文字无法承载的签名/成员契约,门禁会拒绝并要求直接导出该声明。 +- `declare module`/`declare global` 体和 `export … from` 重导出语句被跳过:augmentation 不是包的导出,重导出的定义在其定义处检查。`export import X = N.member` 别名需要文档化自身——其目标可能是遍历不会访问的非导出命名空间成员——且门禁仅支持纯描述文字的目标类型:可调用、类或命名空间目标携带别名描述文字无法承载的签名/成员契约,门禁会拒绝并要求直接导出该声明。 - 其余情况按封闭原则失败:`export =` 直接拒绝;基类从未命名的参数即使作为绑定模式仍需 `@param`;dispatch 不识别的导出语句类型本身就是违规——没有任何导出形式能因遗漏而免检。 三类豁免避免门禁要求样板代码,精神与 Cordis 门禁的 `this`/`next` 豁免一致(为已豁免的名称编写文档是允许的;只有缺失才不被检查): @@ -38,7 +38,7 @@ Status: implemented ## 后果 -- 新增导出不能在无文档的情况下合入:`verify-export-jsdoc` 使 `doc-sync` 失败,而 pre-push 和 CI 已运行 `doc-sync`。采纳时发现的 203 处缺口在同一个变更中补齐,门禁以绿色状态落地。 +- 新增导出不能在无文档的情况下合入:`verify-export-jsdoc` 使 `doc-sync` 失败,而 pre-push 和 CI 已运行该门禁。采纳时发现的 203 处缺口在同一个变更中补齐,门禁以绿色状态落地。 - 导出函数必须标注返回类型(采纳时已全面满足,现在成为门禁依赖),并在 `@param` 需要命名参数时使用标识符参数。 - seam 文档是权威的:实现从其继承链继承文档,值得保留在实现上的行为说明是补充,而非必需。 - 门禁构建一个 `ts.Program`(约 6 秒)——唯一需要类型解析的文档门禁;在已编译文档片段的 `doc-sync` 内可以接受。 diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml index ccfbb1cc49..18aecd24ad 100644 --- a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml @@ -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 -2026-07-06-generated-config-catalog.md: 50ba0dc70b0d8ea54a4f93911f3a087806774626 -2026-07-06-generated-config-catalog.zh.md: 87a861bab394ec268fb3c870e848db37fa4d6fcf +2026-07-06-generated-config-catalog.md: 77c2007d4b5cd28efcfe391c2de712db3b5c107e +2026-07-06-generated-config-catalog.zh.md: 4d9b190b770432111287cedee5992d5822197feb diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md index 50ba0dc70b..77c2007d4b 100644 --- a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md @@ -1,9 +1,9 @@ # RFC: Generated plugin config catalog -English | [中文](2026-07-06-generated-config-catalog.zh.md) - Status: implemented +English | [中文](2026-07-06-generated-config-catalog.zh.md) + ## Problem The repository had no source-backed reference for plugin configuration. Package READMEs documented fields inconsistently, did not enumerate which packages are loadable, and did not verify that runtime schemas agree with declared config types. diff --git a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md index 87a861bab3..4d9b190b77 100644 --- a/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-generated-config-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC:生成式插件配置目录 +# RFC: 生成式插件配置目录 Status: implemented diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml index 815cf98e72..e324b52b3f 100644 --- a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.i18n.yaml @@ -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 -2026-07-06-node-engine-floor.md: 561b6b4a124b6eaa8e2ba0756a835e35519b30b8 -2026-07-06-node-engine-floor.zh.md: 21af2da919754b1ae4667b46ef2f65c14a279b49 +2026-07-06-node-engine-floor.md: f7764c408374a329c9390635e1b92ae9a4fd9dee +2026-07-06-node-engine-floor.zh.md: c46bf5168007b97878319e5f333b5bb1ab1d8f2a diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md index 561b6b4a12..f7764c4083 100644 --- a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.md @@ -1,9 +1,9 @@ # RFC: Raise the Node LTS engine floor to 22.19 -English | [中文](2026-07-06-node-engine-floor.zh.md) - Status: implemented +English | [中文](2026-07-06-node-engine-floor.zh.md) + ## Problem The Node 22 branch of the root `engines.node` range is a contract for the installed workspace, not only for the runtime APIs the harness source calls directly. It must be no lower than package `engines.node` declarations for dependencies the workspace installs on that branch; otherwise `pnpm install --engine-strict` fails at an advertised LTS version, and non-strict installs run outside a dependency's supported runtime. diff --git a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md index 21af2da919..c46bf51680 100644 --- a/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-node-engine-floor.zh.md @@ -1,9 +1,9 @@ -# RFC:将 Node LTS 引擎下限提升至 22.19 - -[English](2026-07-06-node-engine-floor.md) | 中文 +# RFC: 将 Node LTS 引擎下限提升至 22.19 Status: implemented +[English](2026-07-06-node-engine-floor.md) | 中文 + ## 问题 根 `engines.node` 范围中的 Node 22 分支是对已安装工作区的契约,而不仅仅是 harness 源码直接调用的运行时 API 的契约。它不得低于工作区在该分支上安装的依赖所声明的 package `engines.node`;否则 `pnpm install --engine-strict` 会在一个已宣传的 LTS 版本上失败,而非严格模式的安装则会在依赖所支持的运行时范围之外运行。 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml index 7abfb8a8ed..40132b2b97 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml @@ -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 -2026-07-06-parallel-github-ci-gates.md: 890adf58ac8a20a39806aa028d035cb253d5a4f1 -2026-07-06-parallel-github-ci-gates.zh.md: 47562ed6a83b650a3275b4045c39c4de6d2ecac6 +2026-07-06-parallel-github-ci-gates.md: 6a9bd339304c8efac7a29bdbe745270ab9661396 +2026-07-06-parallel-github-ci-gates.zh.md: 24fdf27822aac7640fbeaf602fa8dd84277083fa diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md index 890adf58ac..6a9bd33930 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.md @@ -1,9 +1,9 @@ # RFC: Parallel GitHub CI gates -English | [中文](2026-07-06-parallel-github-ci-gates.zh.md) - Status: implemented +English | [中文](2026-07-06-parallel-github-ci-gates.zh.md) + ## Problem The keyless GitHub CI gates are mostly orthogonal: typecheck, lint, documentation freshness, coverage, snapshot replay, build, package-publication hygiene, demo smoke, and built-bin smoke fail for different reasons and do not need each other's runtime state. Running them as one ordered command chain makes the workflow wall clock equal the sum of those gates, while splitting every leaf gate into its own GitHub job repeats checkout, Node setup, pnpm restore, and install work until orchestration overhead becomes the bottleneck. diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md index 47562ed6a8..24fdf27822 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md @@ -1,9 +1,9 @@ -# RFC:并行 GitHub CI 门禁 - -[English](2026-07-06-parallel-github-ci-gates.md) | 中文 +# RFC: 并行 GitHub CI 门禁 Status: implemented +[English](2026-07-06-parallel-github-ci-gates.md) | 中文 + ## 问题 keyless GitHub CI 门禁大多相互正交:类型检查、lint、文档新鲜度、覆盖率、快照回放、构建、包发布卫生检查、demo 冒烟测试与 built-bin 冒烟测试各自因不同原因失败,彼此不需要对方的运行时状态。将它们串成一条有序命令链,工作流的挂钟时间等于所有门禁之和;而把每个叶子门禁拆成独立的 GitHub job,则会重复 checkout、Node 设置、pnpm restore 和 install 工作,直到编排开销本身成为瓶颈。 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml index 6475a65971..e3e1c0d234 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml @@ -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 -2026-07-06-parallel-pre-push-gates.md: 8a8813f2f3f6726ab2ab028757406d366ceb8b6d -2026-07-06-parallel-pre-push-gates.zh.md: 6ee3a8003853092d75cda9908bfae13ee0d4c7a2 +2026-07-06-parallel-pre-push-gates.md: cf032f8dfedd88a7d6be87999fd9786a9efbb2e8 +2026-07-06-parallel-pre-push-gates.zh.md: 776faf1f46c6490f1935727612225414dd258aa3 diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md index 8a8813f2f3..cf032f8dfe 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.md @@ -1,9 +1,9 @@ # RFC: Parallel pre-push gates -English | [中文](2026-07-06-parallel-pre-push-gates.zh.md) - Status: implemented +English | [中文](2026-07-06-parallel-pre-push-gates.zh.md) + ## Problem The pre-push hook is the last local checkpoint before a branch leaves the machine, so its wall clock directly shapes whether contributors keep it enabled and trust its signal. Lefthook already runs top-level jobs in parallel, but aggregate jobs such as `pnpm run hygiene` and `pnpm run doc-sync` hide long sequential chains inside one job. The hook can therefore be configured as parallel while still waiting on serial subcommands whose members are independent. diff --git a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md index 6ee3a80038..776faf1f46 100644 --- a/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md +++ b/docs/rfc/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md @@ -1,9 +1,9 @@ -# RFC:并行 pre-push 门禁 - -[English](2026-07-06-parallel-pre-push-gates.md) | 中文 +# RFC: 并行 pre-push 门禁 Status: implemented +[English](2026-07-06-parallel-pre-push-gates.md) | 中文 + ## 问题 pre-push 钩子是分支离开本地机器前的最后一道检查点,因此它的挂钟时间直接影响贡献者是否愿意保持启用并信任其信号。Lefthook 已经能并行运行顶层 job,但 `pnpm run hygiene` 和 `pnpm run doc-sync` 等聚合 job 在单个 job 内部隐藏了长串的顺序执行链。钩子因此可能在配置上看似并行,实际仍在等待那些成员彼此独立却串行执行的子命令。 diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml index 81355776bb..69cfd7e0db 100644 --- a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml @@ -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 -2026-07-10-readme-known-limitations-gate.md: b7f45421bf0d4d50ec1a19941934e782f52e7926 -2026-07-10-readme-known-limitations-gate.zh.md: dc023ac43890d8aaaefaece2e592001629e2a74e +2026-07-10-readme-known-limitations-gate.md: 1aad1d40285f295833c2b1bd7d5c2e71bb780f34 +2026-07-10-readme-known-limitations-gate.zh.md: 4b3904fac3f980f9d005907775618cd28778a6fe diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md index b7f45421bf..1aad1d4028 100644 --- a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md @@ -1,9 +1,9 @@ # RFC: A gated Known-Limitations section in every package README -English | [中文](2026-07-10-readme-known-limitations-gate.zh.md) - Status: implemented +English | [中文](2026-07-10-readme-known-limitations-gate.zh.md) + ## Problem The [documentation standard](../../../AGENTS.md) assigns limitations to package READMEs. Without a shared shape, an omitted section cannot distinguish an audited absence from forgotten documentation, and variant headings prevent a repository-wide search. diff --git a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md index dc023ac438..4b3904fac3 100644 --- a/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md +++ b/docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md @@ -1,9 +1,9 @@ -# RFC:在每个 package README 中设置受门禁保护的 Known Limitations 章节 - -[English](2026-07-10-readme-known-limitations-gate.md) | 中文 +# RFC: 在每个 package README 中设置受门禁保护的 Known Limitations 章节 Status: implemented +[English](2026-07-10-readme-known-limitations-gate.md) | 中文 + ## 问题 [文档标准](../../../AGENTS.md)将限制事项指定在 package README 中记录。如果没有统一的格式,缺失的章节无法区分「经审计确认无此内容」与「忘了写文档」,而标题写法不一致也会妨碍全仓库搜索。 diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml index 9e9b379eb9..4a0af0834e 100644 --- a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml @@ -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 -2026-07-12-package-model-experience-contract.md: 036efbc9510d6d0ae9e3c52a5ba8f39647adc4c9 -2026-07-12-package-model-experience-contract.zh.md: b1efa712bc4f6fa7b23c0afe965e56eabf068d97 +2026-07-12-package-model-experience-contract.md: 28a1c75ca6f451b4ca2f6da6abf36f72c5d43b31 +2026-07-12-package-model-experience-contract.zh.md: 77fa7a67847ed186b65db57b6dda378a93b94d92 diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md index 036efbc951..28a1c75ca6 100644 --- a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.md @@ -1,9 +1,9 @@ # RFC: Package Model Experience contract -English | [中文](2026-07-12-package-model-experience-contract.zh.md) - Status: implemented +English | [中文](2026-07-12-package-model-experience-contract.zh.md) + ## Problem A package README can explain APIs and runtime mechanics without answering the question that dominates an agent harness's behavior and cost: what from this package reaches a model request, under which conditions, and how long those tokens remain. The omission is especially hard to audit in a plugin architecture. A consumer may turn a backend result into a tool message, a policy plugin may replace success with an error, compaction may remove old history, and an agent-scoped registration may change one agent's prompt or schemas while leaving every other agent unchanged. Reading only the nominally model-facing packages therefore misses real context effects, while reading source across every dependency is too expensive for routine review. diff --git a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md index b1efa712bc..77fa7a6784 100644 --- a/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md +++ b/docs/rfc/implemented/process/2026-07-12-package-model-experience-contract.zh.md @@ -1,9 +1,9 @@ -# RFC:Package Model Experience 契约 - -[English](2026-07-12-package-model-experience-contract.md) | 中文 +# RFC: Package Model Experience 契约 Status: implemented +[English](2026-07-12-package-model-experience-contract.md) | 中文 + ## 问题 一个 package(包)的 README 可以解释 API 和运行时机制,却不回答那个主导 agent harness(智能体框架)行为与成本的问题:本 package 中有什么内容会进入模型请求、在什么条件下进入、以及这些 token 会保留多久。在插件架构中,这一缺失尤其难以审计。消费方可能把后端结果转为工具消息,策略插件可能把成功替换为错误,上下文压缩(context compaction)可能移除旧历史,agent 作用域的注册可能改变某个 agent 的提示词或 schema 而其他 agent 不受影响。因此,只阅读名义上面向模型的 package 会遗漏真实的上下文影响,而跨所有依赖阅读源码对日常评审来说又太昂贵。 @@ -16,7 +16,7 @@ Status: implemented 没有模型上下文效应的 package,或其路径完全由另一个 package 渲染的 package,使用验证器审计过的单句形式:`None, as ` 或 `Indirectly, through `。纯传输和无密钥的测试支持 package 在不创建模型绑定内容时使用 none 形式。提供方后端即使对数据进行上限或过滤,也使用 indirect 形式;组装 bundle 在命名子 package 拥有全部效应时同样使用 indirect 形式。这些句子定位贡献所在,而不重述消费方的内容。结构化章节同样只记录 package 自身拥有的输入、变换和差异。 -`verify-package-readme-model-experience` 发现 package manifest(元数据清单)并验证三种分类、规范的末尾章节顺序、必填字段、具体字面量证据、嵌套逐字块和锚定的工具目录链接。它在 doc-sync(文档同步门禁)和并行门禁运行器中执行。覆盖面、链接相关性和事实准确性仍由评审把关。 +`verify-package-readme-model-experience` 发现 package manifest(元数据清单)并验证三种分类、规范的末尾章节顺序、必填字段、具体字面量证据、嵌套逐字块和锚定的工具目录链接。它在 `doc-sync`(文档同步门禁)和并行门禁运行器中执行。覆盖面、链接相关性和事实准确性仍由评审把关。 ## 曾考虑的替代方案 diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml index 7d48003ed6..d94f825076 100644 --- a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml @@ -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 -2026-06-19-drop-mutable-session-summary.md: 0d790191906a9128ad12d40526fde3b9f8fa939f -2026-06-19-drop-mutable-session-summary.zh.md: 6b234eb0dbdf764223e078519c810216c28603be +2026-06-19-drop-mutable-session-summary.md: 0f005a78045869d62eb141c9bce8af037671b687 +2026-06-19-drop-mutable-session-summary.zh.md: a33b057c2177258e0e3e2c0c3f78176835acb070 diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md index 0d79019190..0f005a7804 100644 --- a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.md @@ -1,9 +1,9 @@ # RFC: Drop the mutable session summary -English | [中文](2026-06-19-drop-mutable-session-summary.zh.md) - Status: implemented +English | [中文](2026-06-19-drop-mutable-session-summary.zh.md) + ## Problem The [session-persistence seam](../architecture/2026-06-14-session-persistence.md) split a session's out-of-log metadata into two types owned by `dsh-session`: an immutable `SessionHeader` (`version`, `id`, `createdAt`, `cwd?`, `parentSession?`) written once at creation, and a mutable `SessionSummary` (`updatedAt`, `title?`, `firstPrompt?`) "updateable without touching the append-only log". Their union was `SessionMeta = SessionHeader & SessionSummary`, and the abstract `SessionPersistence` service carried a seventh method — `update(id, summary)` — for rewriting the summary. Each backend implemented the mutable store its own way: JSONL wrote a separate atomic `.summary.json` **sidecar** beside the log (temp-write + rename, best-effort), SQLite kept `updated_at`/`title`/`first_prompt` **columns** bumped inside the append transaction. diff --git a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md index 6b234eb0db..a33b057c21 100644 --- a/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md @@ -1,4 +1,4 @@ -# RFC:移除可变的会话摘要 +# RFC: 移除可变的会话摘要 Status: implemented @@ -12,7 +12,7 @@ Status: implemented - `SessionPersistence.update()` **零个生产调用方**(所有 `.update(` 匹配都是 `createHash().update()` 或测试代码)。 - `firstPrompt` 在生产代码中**从未被读取**。 -- `title` 确实在 ACP 桥接层被读取过,但读的是工具调用的 **presenter**(`present.title`),从未读取存储的会话元数据。 +- `title` *确实*在 ACP 桥接层被读取过,但读的是工具调用的 **presenter**(`present.title`),从未读取存储的会话元数据。 - `updatedAt` **没有消费方**:`list()` 唯一的生产调用方读取的是 `meta.cwd`(`SessionHeader` 字段),用于在 `session/load` 时校验工作区;恢复会话读取的是 `createdAt`/`cwd`/`parentSession`——全是 header 字段。 - 决定性的一点:活跃的 `Session.header` 类型本来就是 `SessionHeader` 而非 `SessionMeta`——摘要从未存在于活跃会话对象上;它只存在于持久化层,除了自身的契约测试外无人写入、无人读取。 @@ -20,13 +20,13 @@ Status: implemented 彻底删除可变的会话摘要。`SessionSummary` 与 `SessionMeta` 这个名称一并移除;后端存储和返回的元数据仅为 `SessionHeader`。`SessionPersistence.update()` 从抽象服务和所有后端中移除。JSONL 去掉整套伴随文件机制(`writeSidecar`/`readSidecar`/`touchSummary`/`removeSidecars`/`sidecarPath` 以及 load/list 的覆盖逻辑);SQLite 去掉 `updated_at`/`title`/`first_prompt` 列以及每次追加时的 `updated_at` 更新,其 `SCHEMA_VERSION` 从 `1 → 2`。 -摘要原本要提供的一切,在消费方真正需要时都**可从仅追加日志中派生**(`firstPrompt` = 第一条 `user/message`;近期度 = 最后一个事件的 `time` 或文件 mtime),或者已经存在于不可变 header 中(`createdAt`、`cwd`)。唯一不可派生的是用户*手动编辑*的标题,但它从未实现,纯属 YAGNI;如果未来真有功能需要,它可以作为独立的日志事件或 header 字段回归。 +摘要原本要提供的一切,在消费方真正需要时都**可从仅追加日志中派生**(`firstPrompt` = 第一条 `user/message`;近期度 = 最后一个事件的 `time` 或文件 mtime),或者已经存在于不可变 header 中(`createdAt`、`cwd`)。唯一*不可*派生的是用户*手动编辑*的标题,但它从未实现,纯属 YAGNI;如果未来真有功能需要,它可以作为独立的日志事件或 header 字段回归。 将此记录为决策,原因有三:**持久性**(它收窄了一个公开服务契约和跨两个后端的磁盘格式)、**争议性**(摘要是有意的前瞻性设计,而非意外产物)、**意外性**(未来读者看到 `SessionHeader` 而原始 RFC 描述的是 `SessionMeta`,否则会疑惑摘要为何消失)。它还为 [shared persistence write coordinator](../architecture/2026-06-18-shared-persistence-write-coordinator.md) 扫清了障碍:没有可变摘要后,协调器的钩子接口无需 `updateSummary` 钩子,JSONL 伴随文件与 SQLite 列之间的持久性分歧也随之消失,两个后端的写入路径得以统一。 ## 无需迁移 -这是未发布的软件(见[根 AGENTS.md](../../../../AGENTS.md)「Pre-release stance: foundation over blast radius」一节),因此没有需要保留的磁盘数据库或日志。SQLite 不迁移 v1 数据库:`openDatabase` 守卫现在拒绝任何非当前版本的磁盘 `user_version`(`onDisk !== 0 && onDisk !== SCHEMA_VERSION`),无论更旧还是更新,因此陈旧的 v1 数据库会被干净地拒绝,而非在新列集下被半读取。新建数据库写入当前版本号;这是唯一需要正常工作的路径。 +这是未发布的软件(见[根 AGENTS.md](../../../../AGENTS.md)「Pre-release stance: foundation over blast radius」一节),因此没有需要保留的磁盘数据库或日志。SQLite 不迁移 v1 数据库:`openDatabase` 守卫现在拒绝任何非当前版本的磁盘 `user_version`(`onDisk !== 0 && onDisk !== SCHEMA_VERSION`),无论更旧*还是*更新,因此陈旧的 v1 数据库会被干净地拒绝,而非在新列集下被半读取。新建数据库写入当前版本号;这是唯一需要正常工作的路径。 ## 后果 diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml index 807d67d2fc..784b07f47b 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml @@ -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 -2026-06-20-collapse-trace-only-session-events.md: 9156c2ab356b1c46758d9d2047d491cd1952cbc4 -2026-06-20-collapse-trace-only-session-events.zh.md: c4555f3a772096fc36de968d5d3085f5a2e879f3 +2026-06-20-collapse-trace-only-session-events.md: c446f43d887088fcf562305fcc2dad37465fb124 +2026-06-20-collapse-trace-only-session-events.zh.md: eda7f738abbaced393f2588867f9dcd8e86e2386 diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md index 9156c2ab35..c446f43d88 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.md @@ -1,9 +1,9 @@ # RFC: Fold trace-only session facts into load-bearing events -English | [中文](2026-06-20-collapse-trace-only-session-events.zh.md) - Status: implemented +English | [中文](2026-06-20-collapse-trace-only-session-events.zh.md) + ## Problem The session event vocabulary includes first-class events that are not part of replayable conversation history and have little or no production consumption. `usage` is already present as a model stream chunk before the loop also appends a separate `usage` event. `error` duplicates the `turn/end { kind: 'error', message, code }` reason for loop failures; ACP settlement reads the turn-end reason, ACP rendering ignores the `error` event, and `deriveMessages()` skips it. diff --git a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md index c4555f3a77..eda7f738ab 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md @@ -1,4 +1,4 @@ -# RFC:将仅用于追踪的会话事实折叠进承载性事件 +# RFC: 将仅用于追踪的会话事实折叠进承载性事件 Status: implemented diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml index dbb62e578d..7534bcc2da 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml @@ -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 -2026-06-20-drop-unconsumed-llm-adapter-change-event.md: efe90c0197671ef4385ce517540b4b238962c3b5 -2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md: b26610cfe273820112113c73b9313557cd78262c +2026-06-20-drop-unconsumed-llm-adapter-change-event.md: 657e5f08c02e1e03eedeccf8a30b8bc851201615 +2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md: fbc2248c8357dbff3f5f5008647c14c23a66d5b0 diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md index efe90c0197..657e5f08c0 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md @@ -1,9 +1,9 @@ # RFC: Drop the unconsumed `llm/adapter-change` event -English | [中文](2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md) - Status: implemented +English | [中文](2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md) + ## Problem `LlmService.registerAdapter()` emits `llm/adapter-change` on registration and disposal ([packages/llm/llm/src/index.ts](../../../../packages/llm/llm/src/index.ts)). Grepping `llm/adapter-change` across `packages/*/src` and `examples/*/src` finds only the declaration, emit sites, docs, and tests; no production listener subscribes to it. diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md index b26610cfe2..fbc2248c83 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md @@ -1,4 +1,4 @@ -# RFC:移除未被消费的 `llm/adapter-change` 事件 +# RFC: 移除未被消费的 `llm/adapter-change` 事件 Status: implemented diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml index 0d895a2b35..f9986e5608 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml @@ -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 -2026-06-20-drop-unconsumed-llm-assembled-surfaces.md: c8999dd0e19b2c8eaff854c8ff544bae2fc068b6 -2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md: de297a8cb64d9002fce2c857fd3caa5f2b25f43a +2026-06-20-drop-unconsumed-llm-assembled-surfaces.md: ead3a8c094b0fc0b4bd01671bd4a1165dd555ea2 +2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md: 16704b511151c329622e58c3b5f6b2cff330f366 diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md index c8999dd0e1..ead3a8c094 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.md @@ -1,9 +1,9 @@ # RFC: Drop unconsumed assembled LLM convenience surfaces -English | [中文](2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md) - Status: implemented +English | [中文](2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md) + ## Problem `LlmService` ([packages/llm/llm/src/index.ts](../../../../packages/llm/llm/src/index.ts)) exposes three call surfaces over a model: diff --git a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md index de297a8cb6..16704b5111 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md @@ -1,4 +1,4 @@ -# RFC:移除未被消费的 LLM 组装便捷接口 +# RFC: 移除未被消费的 LLM 组装便捷接口 Status: implemented diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml index e995e57540..b777318d66 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml @@ -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 -2026-06-20-prune-dead-seam-methods.md: cb3eb576dbae209ddccbea7f42a80ef09f842887 -2026-06-20-prune-dead-seam-methods.zh.md: 988da3c44d8860d89f090f0ea9e2af49ae9007dd +2026-06-20-prune-dead-seam-methods.md: fc656f4fc46837a75fa6c34c2de18cffde954ef3 +2026-06-20-prune-dead-seam-methods.zh.md: 2b8b2afea97aa28d32d55a9def217a593e9dbc7d diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md index cb3eb576db..fc656f4fc4 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md @@ -1,9 +1,9 @@ # RFC: Prune dead methods from the persistence seam -English | [中文](2026-06-20-prune-dead-seam-methods.zh.md) - Status: implemented +English | [中文](2026-06-20-prune-dead-seam-methods.zh.md) + > **Implementation note:** Only `SessionPersistence.has()` and `.delete()` were removed. `BashExecutor.get()` and `.list()` remain because removing their one-line lookup surface required substantially more completion-tracking machinery in consumers. Their id branding is covered by the [branded-ids RFC](../architecture/2026-06-20-branded-ids.md). ## Problem diff --git a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md index 988da3c44d..2b8b2afea9 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md @@ -1,9 +1,9 @@ -# RFC:从 persistence seam 中移除无用方法 - -[English](2026-06-20-prune-dead-seam-methods.md) | 中文 +# RFC: 从 persistence seam 中移除无用方法 Status: implemented +[English](2026-06-20-prune-dead-seam-methods.md) | 中文 + > **实现说明:** 最终只移除了 `SessionPersistence.has()` 和 `.delete()`。`BashExecutor.get()` 和 `.list()` 保留,因为移除它们的单行查询接口需要在消费方引入大量额外的完成状态追踪机制。它们的 id 品牌化由 [branded-ids RFC](../architecture/2026-06-20-branded-ids.md) 覆盖。 ## 问题 diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml index 68ba79e73a..eec7c0f05d 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml @@ -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 -2026-06-20-public-agent-stop-surface.md: 8c371911616b0a156156355b2ca15d795cfd21e5 -2026-06-20-public-agent-stop-surface.zh.md: bbd61fa1738fda64ec5e068dae84062163937c1a +2026-06-20-public-agent-stop-surface.md: d34f21be66892e261f1435070aaf9b478c8dc7cd +2026-06-20-public-agent-stop-surface.zh.md: a510d39044048637c2462fd1d97eb3474931761a diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md index 8c37191161..d34f21be66 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.md @@ -1,9 +1,9 @@ # RFC: Keep one public stop primitive -English | [中文](2026-06-20-public-agent-stop-surface.zh.md) - Status: implemented +English | [中文](2026-06-20-public-agent-stop-surface.zh.md) + > **Implementation note:** Only `abort()` was removed. `whenIdle()` remains because it is the public quiescence signal and safely handles waiter settlement and replacement-turn races; consumers should not reconstruct that behavior from status transitions. ## Problem diff --git a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md index bbd61fa173..a510d39044 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:保留单一公开停止原语 +# RFC: 保留单一公开停止原语 Status: implemented diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml index ec11d8ea9a..16911f7c70 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml @@ -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 -2026-06-20-remove-agent-boundary-mirror-events.md: 46b5e43951885915d4c3dd3f867ced6c31d32035 -2026-06-20-remove-agent-boundary-mirror-events.zh.md: 15be07f43997b1d899f0297d311c3ad83f088ee0 +2026-06-20-remove-agent-boundary-mirror-events.md: 0ea8512ca6b66b2e8ab8cf2746bdc65d79caa9d4 +2026-06-20-remove-agent-boundary-mirror-events.zh.md: 30632bf223cb41c18f62c18a544ff42f70af1136 diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md index 46b5e43951..0ea8512ca6 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md @@ -1,9 +1,9 @@ # RFC: Stop mirroring durable boundaries as agent events -English | [中文](2026-06-20-remove-agent-boundary-mirror-events.zh.md) - Status: implemented +English | [中文](2026-06-20-remove-agent-boundary-mirror-events.zh.md) + ## Problem The loop exposed durable turn and step boundaries through both the replayable `SessionEvent` log and live `agent/*` mirrors. Consumers had to choose between two sources for the same fact and reconcile their timing. ACP and persistence already used the log; the stdio UI was the only remaining mirror consumer and already rendered tool calls and results from `session/event`. diff --git a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md index 15be07f439..30632bf223 100644 --- a/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md @@ -1,9 +1,9 @@ -# RFC:停止将持久化边界镜像为 agent 事件 - -[English](2026-06-20-remove-agent-boundary-mirror-events.md) | 中文 +# RFC: 停止将持久化边界镜像为 agent 事件 Status: implemented +[English](2026-06-20-remove-agent-boundary-mirror-events.md) | 中文 + ## 问题 agent loop(智能体循环)通过可回放的 `SessionEvent` 日志和实时 `agent/*` 镜像两条路径暴露持久化的轮次与步骤边界。消费方不得不在同一事实的两个来源之间做选择,并协调二者的时序。ACP(Agent Client Protocol)和持久化层已经使用日志;stdio UI 是唯一仍在消费镜像的组件,而它已经从 `session/event` 渲染工具调用和工具结果。 diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml index aecab4f6b5..f1fa61c3c2 100644 --- a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml @@ -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 -2026-06-26-fsspec-style-fs-seam.md: 493af9341177aaaed4cdca03a3c20f326c5c4dac -2026-06-26-fsspec-style-fs-seam.zh.md: 4aa9b260396c22433ea9a4c9af0b4101fa6895e7 +2026-06-26-fsspec-style-fs-seam.md: 7b5e61481eeca9556de58cf3d6f8fe935b2eefb5 +2026-06-26-fsspec-style-fs-seam.zh.md: 72d37c196df99d110ea59c5108dc9de084669c8b diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md index 493af93411..7b5e61481e 100644 --- a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.md @@ -1,9 +1,9 @@ # RFC: Split the filesystem seam — provider text mutations plus the `dsh-fs-policy` plugin -English | [中文](2026-06-26-fsspec-style-fs-seam.zh.md) - Status: implemented +English | [中文](2026-06-26-fsspec-style-fs-seam.zh.md) + ## Problem The filesystem capability from [filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) currently makes one abstract `FileSystem` service own two different jobs: diff --git a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md index 4aa9b26039..72d37c196d 100644 --- a/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md +++ b/docs/rfc/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md @@ -1,9 +1,9 @@ -# RFC:拆分文件系统 seam——提供方文本变更操作与 `dsh-fs-policy` 插件 - -[English](2026-06-26-fsspec-style-fs-seam.md) | 中文 +# RFC: 拆分文件系统 seam——提供方文本变更操作与 `dsh-fs-policy` 插件 Status: implemented +[English](2026-06-26-fsspec-style-fs-seam.md) | 中文 + ## 问题 [filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) 中引入的文件系统能力目前让一个抽象的 `FileSystem` 服务承担两类不同的职责: @@ -30,7 +30,7 @@ provider dsh-fs-local local implementation of ctx.fs `dsh-tool-fs` 保持相同的面向模型的 `read`/`write`/`edit` schema。它是执行器:注入 `fs`(不是策略服务)并直接访问 `ctx.fs`,拥有读取窗口化逻辑,并分发 `fs/*` 事件以便 `dsh-fs-policy` 进行门控和记录。 -本 RFC 决定了四层拆分、提供方契约和新鲜度策略。工具↔策略的**耦合方式**随后由[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 细化:`dsh-fs-policy` 是一个门控**插件**,通过 `fs/*` 事件参与而非提供 `ctx.fileContext` 方法服务,因此工具不与它产生方法耦合,读取窗口化与 fs I/O 留在 `dsh-tool-fs` 中。本文描述的是最终落地的事件门控形态;提供方的版本守卫是可选的(省略 = 无条件裸提供方)。 +本 RFC 决定了四层拆分、提供方契约和新鲜度策略。工具↔策略的耦合方式随后由[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 细化:`dsh-fs-policy` 是一个门控插件,通过 `fs/*` 事件参与而非提供 `ctx.fileContext` 方法服务,因此工具不与它产生方法耦合,读取窗口化与 fs I/O 留在 `dsh-tool-fs` 中。本文描述的是最终落地的事件门控形态;提供方的版本守卫是可选的(省略 = 无条件裸提供方)。 ## 提供方契约 @@ -61,9 +61,9 @@ type FsWriteIntent = `writeText` 是原子的临时文件 + rename,带有显式的写入期望。`createIfAbsent` 创建不存在的目标,对已存在的目标以 `FS_NOT_OBSERVED` 拒绝;这是 owner 没有先前读取时使用的路径。`replaceIfVersion` 仅在目标以观测到的版本存在时替换;目标不存在或版本不匹配时抛出 `FS_STALE_VERSION`。 -`editText` 是提供方级别的受保护文本变更。启用守卫时,它首先验证目标仍以 `expected.version` 存在,然后读取当前文本、应用字面替换并原子写入。过期检查必须在字面匹配之前发生,这样基于旧读取的编辑会报告 `FS_STALE_VERSION`,而不是对更新内容进行匹配后报告 `FS_EDIT_NOT_FOUND` 或 `FS_AMBIGUOUS_EDIT`。将此原语保留在提供方 seam 上,保持了后端本地锁定的能力,也让未来的远程后端能够实现原生的 compare-and-edit,而无需策略层拉取整个文件。 +`editText` 是提供方级别的受保护文本变更。启用守卫时,它首先验证目标仍以 `expected.version` 存在,然后读取当前文本、应用字面替换并原子写入。陈旧检查必须在字面匹配之前发生,这样基于旧读取的编辑会报告 `FS_STALE_VERSION`,而不是对更新内容进行匹配后报告 `FS_EDIT_NOT_FOUND` 或 `FS_AMBIGUOUS_EDIT`。将此原语保留在提供方 seam 上,保持了后端本地锁定的能力,也让未来的远程后端能够实现原生的 compare-and-edit,而无需策略层拉取整个文件。 -这是一个*文本存储* seam,刻意比字节级 fsspec(`cat`/`open` 返回原始字节)高半个层次。UTF-8 解码、二进制/NUL 拒绝、受保护的全文件写入和受保护的字面文本编辑都在提供方内完成,因此策略层从不接触原始字节、不重新实现跨分片解码、也不将过期检查与变更临界区分离。面向模型的概念仍然不下沉到提供方:行窗口、带行号的行、渲染的页脚、观测状态存储都不会泄漏下去。 +这是一个*文本存储* seam,刻意比字节级 fsspec(`cat`/`open` 返回原始字节)高半个层次。UTF-8 解码、二进制/NUL 拒绝、受保护的全文件写入和受保护的字面文本编辑都在提供方内完成,因此策略层从不接触原始字节、不重新实现跨分片解码、也不将陈旧检查与变更临界区分离。面向模型的概念仍然不下沉到提供方:行窗口、带行号的行、渲染的页脚、观测状态存储都不会泄漏下去。 从 `dsh-fs` 中删除的内容:`readPage`、`FsExpectation`、`FsView`、`FsStateSource`、`FsReadRequest`、`FsTextLine`、行/窗口常量、`formatReadBody`,以及观测状态 `WeakMap`。`applyEdit` 被更窄的提供方原语 `editText` 取代,后者的契约是版本守卫的字面文本变更,而非策略层的读取授权。`FS_PARTIAL_OBSERVATION` 错误码也从 `FsErrorCode` 分类体系中移除:新鲜度授权没有 partial/full 之分,因此没有什么能触发它。`FsTargetKey` 和 `FsVersion` 按照既有的 [branded-ids RFC](../../implemented/architecture/2026-06-20-branded-ids.md) 成为品牌化的不透明 id。 @@ -76,7 +76,7 @@ type FsWriteIntent = 该插件决定三个 `fs/*` 事件: - `fs/write-intent`——无先前观测 ⇒ `{ kind: 'createIfAbsent' }`(只有新文件可以盲创建);有先前观测 ⇒ `{ kind: 'replaceIfVersion', version: vObserved }`(已有文件仅在自观测以来未变时才替换)。单槽决策;不调用 `next()`。 -- `fs/edit-intent`——要求 owner 有先前观测(否则 `FS_NOT_OBSERVED`);返回 `{ version: vObserved }` 作为 CAS 基础。它不实现字面替换——它授权并提供版本,提供方的变更临界区负责应用守卫,因此基于同一观测版本的并发编辑仍然是一赢一过期。 +- `fs/edit-intent`——要求 owner 有先前观测(否则 `FS_NOT_OBSERVED`);返回 `{ version: vObserved }` 作为 CAS 基础。它不实现字面替换——它授权并提供版本,提供方的变更临界区负责应用守卫,因此基于同一观测版本的并发编辑仍然是一赢一陈旧。 - `fs/observed`——在成功的读取/写入/编辑后,为该 owner+target 记录 `{ version }`。同步、仅副作用的 `WeakMap.set`。 该插件不做任何文件系统 I/O:「你是否观测过此文件?」是一次 `WeakMap` 查找,而「你读取的版本是否仍然是当前版本?」在 `ctx.fs.editText`/`writeText` 内部、与执行变更相同的原子锁中决定——插件只提供 `vObserved` 作为基础。 @@ -109,7 +109,7 @@ type FsWriteIntent = ## 验证 -`dsh-fs` 精确暴露 `resolve`/`stat`/`readText`/`streamText`/`writeText`/`editText`(`stat` 返回 `FsInfo | undefined`,`writeText` 接受 `FsWriteIntent`),已删除的类型/原语不再存在;`dsh-fs-local` 不包含行、视图或 `formatReadBody` 逻辑;面向模型的 schema 保持逐字节不变。测试固定了以下行为:窗口化读取授权对未变文件的后续编辑;基于过期读取的编辑在尝试字面匹配之前报告 `FS_STALE_VERSION`;版本 CAS 行为得以保留;观测契约成立(`read` 工具的读取记录观测状态;直接 `ctx.fs` 读取不记录);`dsh-fs-policy` 具有 HMR(热模块替换)/dispose(资源释放)覆盖率。 +`dsh-fs` 精确暴露 `resolve`/`stat`/`readText`/`streamText`/`writeText`/`editText`(`stat` 返回 `FsInfo | undefined`,`writeText` 接受 `FsWriteIntent`),已删除的类型/原语不再存在;`dsh-fs-local` 不包含行、视图或 `formatReadBody` 逻辑;面向模型的 schema 保持逐字节不变。测试固定了以下行为:窗口化读取授权对未变文件的后续编辑;基于陈旧读取的编辑在尝试字面匹配之前报告 `FS_STALE_VERSION`;版本 CAS 行为得以保留;观测契约成立(`read` 工具的读取记录观测状态;直接 `ctx.fs` 读取不记录);`dsh-fs-policy` 具有 HMR(热模块替换)/dispose(资源释放)覆盖率。 ## 后续扩展 @@ -117,7 +117,7 @@ type FsWriteIntent = ## 曾考虑的替代方案 -- **字节级 fsspec(`cat`/`open` 返回原始字节)**:否决。该 seam 刻意定位为文本存储,比字节级高半个层次,这样 UTF-8 解码、二进制/NUL 拒绝和受保护的文本变更只在提供方实现一次,策略层从不接触原始字节,也不将过期检查与变更临界区分离。 +- **字节级 fsspec(`cat`/`open` 返回原始字节)**:否决。该 seam 刻意定位为文本存储,比字节级高半个层次,这样 UTF-8 解码、二进制/NUL 拒绝和受保护的文本变更只在提供方实现一次,策略层从不接触原始字节,也不将陈旧检查与变更临界区分离。 - **具体的 `ctx.fileContext` 方法服务**:本 RFC 最初的策略形态;被[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 改造为门控插件,使工具从不与策略产生方法耦合。 - **在提供方保留 `readPage` 和 `full`/`partial` 视图授权**:「取代」一节所逆转的重构前形态。视图完整性不是编辑安全所需的,版本新鲜度才是;而视图规则使超过读取上限的大文件无法编辑。 @@ -126,5 +126,5 @@ type FsWriteIntent = - 新增第四个 fs 包和一个新的插件层。这是有意为之:它是此前推迟的策略层,而非第二个抽象后端 seam。 - 直接使用 `ctx.fs` 会绕过策略:直接 `ctx.fs.readText` 不发出 `fs/observed`,因此在默认策略下,后续 `edit` 会以 `FS_NOT_OBSERVED` 拒绝,直到通过 `read` 工具读取该文件。这一失败是显式且有文档记录的。 - 大文件行窗口化从后端移至 `dsh-tool-fs` 中的 `read` 工具;文本解码和二进制拒绝留在 `ctx.fs.streamText` 中,因此这只是窗口化逻辑的迁移,而非第二套文本 IO 实现。 -- 将 `editText` 保留在提供方 seam 上意味着每个后端都必须实现字面替换契约。这是有意为之:该操作不是纯存储,但过期守卫 + 字面匹配 + 原子重写是必须保持在一起的单元,以确保正确的错误归因和并发行为。该契约应保持窄且仅限文本,以便未来后端可以原生实现或通过全文件重写实现。 +- 将 `editText` 保留在提供方 seam 上意味着每个后端都必须实现字面替换契约。这是有意为之:该操作不是纯存储,但陈旧守卫 + 字面匹配 + 原子重写是必须保持在一起的单元,以确保正确的错误归因和并发行为。该契约应保持窄且仅限文本,以便未来后端可以原生实现或通过全文件重写实现。 - 新鲜度允许在窗口化读取后进行全文件 `write`。这比旧的视图检查更弱,但避免了大文件无法编辑的问题;提示词引导仍然不鼓励盲目的全文件替换。 diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml index a9b8b58f67..99d356c3e8 100644 --- a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml @@ -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 -2026-07-02-remove-stream-chunk-mirror.md: 1ec633b09c8e53ae7145a49061aced191a9aa765 -2026-07-02-remove-stream-chunk-mirror.zh.md: 7cf8a5d056c1bb4193263c58a8e4258173fe8b4e +2026-07-02-remove-stream-chunk-mirror.md: 74843cf49c043d46d44266a7bb0d8c953a749b6f +2026-07-02-remove-stream-chunk-mirror.zh.md: 1b460b4600442535d2572770449ce4dbcc836fe8 diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md index 1ec633b09c..74843cf49c 100644 --- a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.md @@ -1,9 +1,9 @@ # RFC: Stop mirroring the token stream as an agent event -English | [中文](2026-07-02-remove-stream-chunk-mirror.zh.md) - Status: implemented +English | [中文](2026-07-02-remove-stream-chunk-mirror.zh.md) + ## Problem The loop records every model token delta as a durable `assistant/chunk` session event AND emitted a parallel live `agent/stream-chunk` Cordis event carrying the identical data. In `packages/core/agent-loop/src/loop.ts` the two sat one line apart: diff --git a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md index 7cf8a5d056..1b460b4600 100644 --- a/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md @@ -1,9 +1,9 @@ -# RFC:停止将 token 流镜像为 agent 事件 - -[English](2026-07-02-remove-stream-chunk-mirror.md) | 中文 +# RFC: 停止将 token 流镜像为 agent 事件 Status: implemented +[English](2026-07-02-remove-stream-chunk-mirror.md) | 中文 + ## 问题 agent loop(智能体循环)将模型的每个 token delta 同时记录为持久的 `assistant/chunk` 会话事件,并发射一个携带相同数据的并行实时 `agent/stream-chunk` Cordis 事件。在 `packages/core/agent-loop/src/loop.ts` 中,二者仅相隔一行: diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml index 9b195da18b..8a31f5ee11 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml @@ -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 -2026-07-04-drop-image-content-block.md: 8222880b61c225c39a1e132353c5f343fb90cb4b -2026-07-04-drop-image-content-block.zh.md: cb9372e50863193cd579c0bf8de991810db95206 +2026-07-04-drop-image-content-block.md: 145f805cbe335d3b8275bef6a2bb1fcbe1bd3df3 +2026-07-04-drop-image-content-block.zh.md: ba77caeba4cb1fdd3ff95f4cd498c87cdf1aa227 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md index 8222880b61..145f805cbe 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.md @@ -1,9 +1,9 @@ # RFC: Drop the `image` content block until a path can honor it -English | [中文](2026-07-04-drop-image-content-block.zh.md) - Status: implemented +English | [中文](2026-07-04-drop-image-content-block.zh.md) + ## Problem `ImageBlock` (`packages/llm/llm/src/types.ts`) had no production producer, and every consumer on every path DROPPED it: the deepseek adapter's serializer skipped image blocks (a documented MVP limitation), the pi-ai converter skipped them as unrepresentable, the ACP codec neither advertises image prompt capability nor forwarded image blocks outbound and REJECTS image prompt content inbound, and the compaction estimator charged a flat token constant and rendered `[image]`. An `ImageBlock` constructed then would silently vanish from the wire — the vocabulary advertised a capability no path honored, which is the silent-data-loss shape AGENTS.md's defensive patterns warn against. The only constructors anywhere were tests pinning the skip/drop/estimate branches. diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md index cb9372e508..ba77caeba4 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-image-content-block.zh.md @@ -1,12 +1,12 @@ -# RFC:移除 `image` 内容块,直到有路径能真正处理它 - -[English](2026-07-04-drop-image-content-block.md) | 中文 +# RFC: 移除 `image` 内容块,直到有路径能真正处理它 Status: implemented +[English](2026-07-04-drop-image-content-block.md) | 中文 + ## 问题 -`ImageBlock`(`packages/llm/llm/src/types.ts`)没有任何生产环境的生产者,而每条路径上的每个消费方都将其**丢弃**:deepseek 适配器的序列化器跳过 image 块(这是文档中注明的 MVP 限制);pi-ai 转换器因无法表示而跳过;ACP 编解码器既不宣告 image prompt 能力、也不向外转发 image 块,并且会拒绝入站的 image prompt 内容;压缩(compaction)估算器对其收取一个固定 token 常量并渲染为 `[image]`。此时构造的 `ImageBlock` 会在协议格式(wire format)上静默消失——词汇宣告了一种没有任何路径兑现的能力,这正是 AGENTS.md 防御性模式所警告的静默数据丢失形态。唯一的构造调用出现在测试中,用于覆盖 skip/drop/estimate 分支。 +`ImageBlock`(`packages/llm/llm/src/types.ts`)没有任何生产环境的生产者,而每条路径上的每个消费方都将其丢弃:deepseek 适配器的序列化器跳过 image 块(这是文档中注明的 MVP 限制);pi-ai 转换器因无法表示而跳过;ACP 编解码器既不宣告 image prompt 能力、也不向外转发 image 块,并且会拒绝入站的 image prompt 内容;压缩(compaction)估算器对其收取一个固定 token 常量并渲染为 `[image]`。此时构造的 `ImageBlock` 会在协议格式(wire format)上静默消失——词汇宣告了一种没有任何路径兑现的能力,这正是 AGENTS.md 防御性模式所警告的静默数据丢失形态。唯一的构造调用出现在测试中,用于覆盖 skip/drop/estimate 分支。 ## 决策 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml index 3dabffc3a4..429e5ae268 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml @@ -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 -2026-07-04-drop-inert-request-knobs.md: d5484aa5ec64f89ce705ddd0a434c2c4dfbad460 -2026-07-04-drop-inert-request-knobs.zh.md: 9bd13cd024bc0e2ba7795a190d77063c3457fe98 +2026-07-04-drop-inert-request-knobs.md: 86d0dfefe1bdfb0c49b5b9080935441d16dd2223 +2026-07-04-drop-inert-request-knobs.zh.md: f7d969378af7e070ecee82e8ea1a569c61208208 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md index d5484aa5ec..86d0dfefe1 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md @@ -1,9 +1,9 @@ # RFC: Drop `GenerateOptions.prefill` and `ToolSchema.strict` — request knobs with no working end-to-end path -English | [中文](2026-07-04-drop-inert-request-knobs.zh.md) - Status: implemented +English | [中文](2026-07-04-drop-inert-request-knobs.zh.md) + ## Problem Two request-contract knobs rode the whole request pipeline, yet neither could do anything: diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md index 9bd13cd024..f7d969378a 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md @@ -1,14 +1,14 @@ -# RFC:移除 `GenerateOptions.prefill` 与 `ToolSchema.strict`——无端到端可用路径的请求旋钮 - -[English](2026-07-04-drop-inert-request-knobs.md) | 中文 +# RFC: 移除 `GenerateOptions.prefill` 与 `ToolSchema.strict`——无端到端可用路径的请求旋钮 Status: implemented +[English](2026-07-04-drop-inert-request-knobs.md) | 中文 + ## 问题 两个请求契约旋钮贯穿了整条请求流水线,却都无法产生任何效果: -- **`prefill`**(`packages/llm/llm/src/types.ts`)没有生产级的 setter:agent loop(智能体循环)组装的是 `model`/`system`/`tools`/`messages` 加 `sessionId`/`signal`,上下文压缩(context compaction)后端只追加 `maxTokens`;而且**两个**适配器都拒绝它:`packages/llm/llm-deepseek/src/serialize.ts` 和 `packages/llm/llm-pi-ai/src/adapter.ts` 各自在 `prefill` 非 undefined 时抛出 `LlmError('UNSUPPORTED')`。该字段的全部可观测行为就是两个 throw,各由一条适配器测试固定。DeepSeek 的 chat-prefix completion 是一个 Beta 功能,运行在两个适配器都未指向的 base URL 上。 +- **`prefill`**(`packages/llm/llm/src/types.ts`)没有生产级的 setter:agent loop(智能体循环)组装的是 `model`/`system`/`tools`/`messages` 加 `sessionId`/`signal`,上下文压缩(context compaction)后端只追加 `maxTokens`;而且两个适配器都拒绝它:`packages/llm/llm-deepseek/src/serialize.ts` 和 `packages/llm/llm-pi-ai/src/adapter.ts` 各自在 `prefill` 非 undefined 时抛出 `LlmError('UNSUPPORTED')`。该字段的全部可观测行为就是两个 throw,各由一条适配器测试固定。DeepSeek 的 chat-prefix completion 是一个 Beta 功能,运行在两个适配器都未指向的 base URL 上。 - **`strict`**(`ToolSchema`,同一文件)穿过了 `DefineToolOptions`/`defineTool`(`packages/core/tools/src/schema.ts`)、注册表的 `schemas()` 允许列表(`packages/core/tools/src/index.ts`)、deepseek 协议格式(wire format)映射(`packages/llm/llm-deepseek/src/serialize.ts`,其 wire-type 注释记录了 strict 模式需要适配器未使用的 `/beta` base URL)、`packages/llm/llm-pi-ai/src/adapter.ts` 中的逐工具 payload 修补逻辑,以及 tool-catalog 渲染器(`scripts/gen-tool-catalog.ts`)中的条件 `Strict:` 行。没有任何已发布的工具设置过它——在所有 `tool-*` 包的 src 和 `examples/` 中执行 `rg` 搜索,`strict:` 的生产者为零;唯一的 setter 出现在 dsh-tools 单元测试中。 两个旋钮在适配器间是对称的,因此移除操作将它们从两个孪生适配器中一并剥离——[孪生适配器设计](../architecture/2026-06-13-twin-llm-adapters.md)不受影响。 @@ -18,13 +18,13 @@ Status: implemented - 从 `GenerateOptions` 中移除 `prefill`,同时移除两个适配器的 UNSUPPORTED 守卫、固定这些 throw 的测试、[core.md](../../../core-data-structures/core.md) 中的粘贴行,以及适配器 README 中记录拒绝行为的行。实操手册(cookbook)中的 UNSUPPORTED 指引([adding-an-llm-adapter.md](../../../cookbook/adding-an-llm-adapter.md))改为泛化表述——你的 provider 无法兑现的 `GenerateOptions` 字段应抛出 `LlmError(..., 'UNSUPPORTED')`——而不再以 prefill 为例。[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的后果部分将 prefill 记录为「受 producer 门控」而非「已有归属」,依据 [implemented/AGENTS.md](../AGENTS.md)。 - 从 `ToolSchema`、`DefineToolOptions`、`defineTool`、`schemas()` 允许列表、deepseek 序列化分支及其 wire-type 字段,以及 tool-catalog 渲染器的 `Strict:` 行中移除 `strict`。pi-ai 的 payload 修补逻辑简化为对 pi-ai 自身逐工具 strict 默认值的无条件清除(pi-ai 在每个序列化的工具上打 `strict: false`;手写的孪生适配器不发送此字段,因此清除逻辑为保持协议格式对等而保留,由其序列化器测试固定)。setter 测试和 core.md 粘贴行已移除;`GenerateOptions` 与 `ToolSchema` 在 `scripts/type-equiv.manifest.json` 中保留各自的行,因为两个类型只是少了一个字段,本身仍然存在。 -本 RFC 有意**不**触碰 `temperature`、`stop` 或 `maxTokens`:它们在两个适配器中都被端到端地兑现,是 `agent/request` 上请求变更钩子插件的自然首选目标。 +本 RFC 有意不触碰 `temperature`、`stop` 或 `maxTokens`:它们在两个适配器中都被端到端地兑现,是 `agent/request` 上请求变更钩子插件的自然首选目标。 ## 曾考虑的替代方案 ### 为什么不保留? -「显式的 UNSUPPORTED throw 是诚实的契约行为」——但一个在两个孪生适配器中唯一的实现就是拒绝的旋钮,什么也没承诺;删除它反而升级了失败模式:意外的 setter 变成编译错误而非运行时 throw。「Strict schema 遵循是官方文档记载的 provider 功能,且管道完整」——但一个旋钮在有已发布的工具设置它**并且**有端点兑现它之前,不构成产品表面;今天两者都不成立。它们各自随首个真实 producer 回归:`prefill` 随实现了 chat-prefix completion 的适配器(以及对不支持该功能的适配器的明确策略)一起回来;`strict` 随需要它的工具和 beta 端点方案一起回来。 +「显式的 UNSUPPORTED throw 是诚实的契约行为」——但一个在两个孪生适配器中唯一的实现就是拒绝的旋钮,什么也没承诺;删除它反而升级了失败模式:意外的 setter 变成编译错误而非运行时 throw。「Strict schema 遵循是官方文档记载的 provider 功能,且管道完整」——但一个旋钮在有已发布的工具设置它并且有端点兑现它之前,不构成产品表面;今天两者都不成立。它们各自随首个真实 producer 回归:`prefill` 随实现了 chat-prefix completion 的适配器(以及对不支持该功能的适配器的明确策略)一起回来;`strict` 随需要它的工具和 beta 端点方案一起回来。 ## 验证 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml index fb1161ae18..d86354d68a 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml @@ -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 -2026-07-04-drop-unconsumed-web-observation-surface.md: c48ff5b80c916cd6cc04d6a8339a8555d05b0d40 -2026-07-04-drop-unconsumed-web-observation-surface.zh.md: 4988a5aa77604f528cc23409a3c2290c890a7f5a +2026-07-04-drop-unconsumed-web-observation-surface.md: ba97076eef385cd218517f233ed44f86d3f7eb7a +2026-07-04-drop-unconsumed-web-observation-surface.zh.md: 83c2e786d4edde7b7c94cf2c028b14e20da842b4 diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md index c48ff5b80c..ba97076eef 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md @@ -1,9 +1,9 @@ # RFC: Drop the unconsumed web observation surface — the `providers-change` event and the status methods -English | [中文](2026-07-04-drop-unconsumed-web-observation-surface.zh.md) - Status: implemented +English | [中文](2026-07-04-drop-unconsumed-web-observation-surface.zh.md) + ## Problem `WebService` exposes an observation surface no production code observes: diff --git a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md index 4988a5aa77..83c2e786d4 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:移除未被消费的 web 观测接口——`providers-change` 事件与 status 方法 +# RFC: 移除未被消费的 web 观测接口——`providers-change` 事件与 status 方法 Status: implemented @@ -23,7 +23,7 @@ seam 自身的设计使这两个接口天然没有消费方:工具注册跟随 ### 为什么不保留? -web seam RFC 有意指定了两者——事件作为最小的 HMR 可见性信号,status 方法作为工具的聚合诊断——且未来的 provider 状态面板是可以想象的。但同一 RFC 的其他设计选择使它们失去了消费方:按需派生的选择与基于 enablement 的注册使得没有消费方**能**需要这两者;已交付的工具展示了真实模式(执行并路由结构化错误);漂移的 README 语句表明承诺的消费方从未实现。按 AGENTS.md「RFC 是提案,不是金科玉律」的原则,这些是该提案中代码已证明过度设计的部分;未来的观测者按其实际消费的需求重新引入最小的信号或查询,由该消费方塑造其形态。 +web seam RFC 有意指定了两者——事件作为最小的 HMR 可见性信号,status 方法作为工具的聚合诊断——且未来的 provider 状态面板是可以想象的。但同一 RFC 的其他设计选择使它们失去了消费方:按需派生的选择与基于 enablement 的注册使得没有消费方能需要这两者;已交付的工具展示了真实模式(执行并路由结构化错误);漂移的 README 语句表明承诺的消费方从未实现。按 AGENTS.md「RFC 是提案,不是金科玉律」的原则,这些是该提案中代码已证明过度设计的部分;未来的观测者按其实际消费的需求重新引入最小的信号或查询,由该消费方塑造其形态。 ## 验证 diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml index 4ca47feeee..a43d663e93 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml @@ -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 -2026-07-04-fold-stdio-ui-helper.md: 8d26af190a957b424960519f77cbe132291c74de -2026-07-04-fold-stdio-ui-helper.zh.md: 795edf082258a56d3c11afbbb8de8cfa0e74e74e +2026-07-04-fold-stdio-ui-helper.md: ab42f1d131f6c657edf078d953c646b7970e9782 +2026-07-04-fold-stdio-ui-helper.zh.md: 2ad6abf3d5fb5ae6cdd852f8b5ec7e061e62b8ed diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md index 8d26af190a..ab42f1d131 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md @@ -1,9 +1,9 @@ # RFC: Fold the stdio UI helper into the stdio app -English | [中文](2026-07-04-fold-stdio-ui-helper.zh.md) - Status: implemented +English | [中文](2026-07-04-fold-stdio-ui-helper.zh.md) + ## Problem The readline UI was a whole package (`@deepseek-ai/dsh-ui-stdio` under `packages/support/`) whose only runtime importer was the app package `@deepseek-ai/dsh-stdio-demo`. The examples reach the readline UI by loading the app, never by composing the helper themselves; every other repo reference was mechanical or descriptive surface that existed BECAUSE the package boundary existed — manifest and tsconfig entries, generated module-graph rows, dependency-graph and README rows, and doc comments naming the package. The ui group README recorded the support placement rationale ("exists chiefly for the examples and the coverage gate — `ui/` is reserved for surfaces shipped as product"), which left a standing tension: a shipped product app depending on a support package documented as NOT product surface. diff --git a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md index 795edf0822..2ad6abf3d5 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md @@ -1,9 +1,9 @@ -# RFC:将 stdio UI 辅助模块折入 stdio 应用 - -[English](2026-07-04-fold-stdio-ui-helper.md) | 中文 +# RFC: 将 stdio UI 辅助模块折入 stdio 应用 Status: implemented +[English](2026-07-04-fold-stdio-ui-helper.md) | 中文 + ## 问题 readline UI 曾是一个完整的包(`packages/support/` 下的 `@deepseek-ai/dsh-ui-stdio`),其唯一的运行时导入方是应用包 `@deepseek-ai/dsh-stdio-demo`。示例通过加载应用来使用 readline UI,从不自行组合该辅助模块;仓库中所有其他引用都是因为包边界存在而存在的机械性或描述性表面:manifest(元数据清单)与 tsconfig 条目、生成的 module-graph 行、依赖图与 README 行,以及命名该包的文档注释。ui 组 README 记录了 support 放置的理由("主要为示例和覆盖率门禁而存在,`ui/` 保留给作为产品交付的界面"),这留下了一个持续的张力:一个已交付的产品应用依赖一个被明确标注为非产品表面的 support 包。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml index ef7e3c8092..1d12fb892b 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml @@ -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 -2026-07-04-prune-producerless-vocabulary-variants.md: 271b97f6217a2694f36b7fe7339eab6176dba9e5 -2026-07-04-prune-producerless-vocabulary-variants.zh.md: 2fe8d41a011c37919bd01022d5be6d309b865bf7 +2026-07-04-prune-producerless-vocabulary-variants.md: f1b80e35b9004e40fb0ffdd08310310848912d09 +2026-07-04-prune-producerless-vocabulary-variants.zh.md: 9e7b55256ba5bda0474fd9056eea9a96beaf8096 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md index 271b97f621..f1b80e35b9 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md @@ -1,9 +1,9 @@ # RFC: Prune producer-less vocabulary variants (block cache hints, the `agent` message source, the `continuation` turn trigger) -English | [中文](2026-07-04-prune-producerless-vocabulary-variants.zh.md) - Status: implemented +English | [中文](2026-07-04-prune-producerless-vocabulary-variants.zh.md) + ## Problem The merge-extensible vocabulary maps are designed to grow by declaration merging, and the codebase already states the admission policy on `TurnEndReasonMap` (`packages/core/session/src/types.ts`): a variant like `refusal` is "deliberately omitted until" an adapter or loop first emits it. Three declared vocabulary items violated that policy — each had no producer and no consumer, and two had not even a test: diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md index 2fe8d41a01..9e7b55256b 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md @@ -1,9 +1,9 @@ -# RFC:裁剪无生产者的词汇变体(块缓存提示、`agent` 消息来源、`continuation` 轮次触发器) - -[English](2026-07-04-prune-producerless-vocabulary-variants.md) | 中文 +# RFC: 裁剪无生产者的词汇变体(块缓存提示、`agent` 消息来源、`continuation` 轮次触发器) Status: implemented +[English](2026-07-04-prune-producerless-vocabulary-variants.md) | 中文 + ## 问题 可合并扩展的词汇映射表设计上通过声明合并来增长,代码库已在 `TurnEndReasonMap`(`packages/core/session/src/types.ts`)上明确了准入策略:像 `refusal` 这样的变体「在适配器或循环首次发出它之前,有意不纳入」。三个已声明的词汇项违反了该策略——每个都既无生产者也无消费方,其中两个甚至没有测试: diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml index 428dfb9379..a595aef18a 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml @@ -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 -2026-07-04-prune-write-only-fs-surface.md: ac2cbcc282b848b26a3d5d327e0ab54612b5ac91 -2026-07-04-prune-write-only-fs-surface.zh.md: e854df76cae74033404aa9cc1986fdd118f19b10 +2026-07-04-prune-write-only-fs-surface.md: f41619ecde1bbf2a1d6d8f8d769409f624fc22c7 +2026-07-04-prune-write-only-fs-surface.zh.md: afcf1aad28db056997930162539a57bb08bbe815 diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md index ac2cbcc282..f41619ecde 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md @@ -1,9 +1,9 @@ # RFC: Prune write-only fields and a dead routing knob from the fs seam -English | [中文](2026-07-04-prune-write-only-fs-surface.zh.md) - Status: implemented +English | [中文](2026-07-04-prune-write-only-fs-surface.zh.md) + ## Problem The [fs seam split](2026-06-26-fsspec-style-fs-seam.md) moved read routing and policy out of the backend into `dsh-tool-fs` and `dsh-fs-policy`. Four pieces of surface kept the pre-split shape — populated on every call, read by nobody: diff --git a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md index e854df76ca..afcf1aad28 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md @@ -1,9 +1,9 @@ -# RFC:从 fs seam 中移除只写字段与一个无效的路由旋钮 - -[English](2026-07-04-prune-write-only-fs-surface.md) | 中文 +# RFC: 从 fs seam 中移除只写字段与一个无效的路由旋钮 Status: implemented +[English](2026-07-04-prune-write-only-fs-surface.md) | 中文 + ## 问题 [fs seam 拆分](2026-06-26-fsspec-style-fs-seam.md)将读取路由与策略从后端移至 `dsh-tool-fs` 和 `dsh-fs-policy`。有四处接口保留了拆分前的形态——每次调用都填充,却无人读取: diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml index be2b32be56..ca0bd62294 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml @@ -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 -2026-07-04-remove-agent-steering-mirror.md: 311f0f8ffd278adf71a35617b900d4d16037055a -2026-07-04-remove-agent-steering-mirror.zh.md: 24198afb0714863867f4d7e17ae19ea8af6a88bd +2026-07-04-remove-agent-steering-mirror.md: fbd13b3d43b0052bcdeffd7f94caa341e1f636c5 +2026-07-04-remove-agent-steering-mirror.zh.md: 185cc5601a7406e0d801afd877e9d97eaaa12a0c diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md index 311f0f8ffd..fbd13b3d43 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.md @@ -1,9 +1,9 @@ # RFC: Remove the `agent/steering` mirror emit -English | [中文](2026-07-04-remove-agent-steering-mirror.zh.md) - Status: implemented +English | [中文](2026-07-04-remove-agent-steering-mirror.zh.md) + ## Problem `agent/steering` was the last remaining transient mirror of a durable session event. The loop's steering drain appends the durable `steering/message { turn, content, source }` and, on the very next line, emitted `agent/steering(agent, turn, content, source)` — the identical fact as a fire-and-forget event (`packages/core/agent-loop/src/loop.ts`, `drainSteering`). It had zero production listeners: the only subscriber anywhere was a loop regression test asserting the emit carried `source` — the same fact the durable event already records one line above. diff --git a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md index 24198afb07..185cc5601a 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md @@ -1,9 +1,9 @@ -# RFC:移除 `agent/steering` 镜像 emit - -[English](2026-07-04-remove-agent-steering-mirror.md) | 中文 +# RFC: 移除 `agent/steering` 镜像 emit Status: implemented +[English](2026-07-04-remove-agent-steering-mirror.md) | 中文 + ## 问题 `agent/steering` 是最后一个仍存在的、对持久会话事件的瞬态镜像。agent loop(智能体循环)的 steering(中途引导)drain 逻辑先追加持久事件 `steering/message { turn, content, source }`,紧接着下一行就 emit `agent/steering(agent, turn, content, source)`——同一个事实以 fire-and-forget 事件的形式重复发出(`packages/core/agent-loop/src/loop.ts`,`drainSteering`)。它在生产环境中没有任何监听者:唯一的订阅方是一个 agent loop 回归测试,断言 emit 携带了 `source`——而这同一个事实已经由上一行的持久事件记录。 @@ -22,7 +22,7 @@ steering 承载着真实的生产流量:hook bridge 的轮次续行决策通 ### 为什么不保留? -"它是控制信号,不是边界事件"——但分类体系的操作性区分是「镜像 vs. 纯瞬态」,而非「控制 vs. 边界」,而这个事件属于镜像。需要入队时通知的消费方有 `agent/queued`(带 steering flag);需要 drain 时通知的消费方,本质上是在请求 `steering/message` 被追加的那一刻,而 `session/event` 以相同 payload 加上持久性提供了这一通知。被否决的 [retire-mid-turn-steering RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md) 捍卫的是 steering **能力**——`steer()`、持久事件、续行强制——本次移除对这些全部保持不变。 +"它是控制信号,不是边界事件"——但分类体系的操作性区分是「镜像 vs. 纯瞬态」,而非「控制 vs. 边界」,而这个事件属于镜像。需要入队时通知的消费方有 `agent/queued`(带 steering flag);需要 drain 时通知的消费方,本质上是在请求 `steering/message` 被追加的那一刻,而 `session/event` 以相同 payload 加上持久性提供了这一通知。被否决的 [retire-mid-turn-steering RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md) 捍卫的是 steering *能力*——`steer()`、持久事件、续行强制——本次移除对这些全部保持不变。 ## 验证 diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml index 6a470484f3..788e1735b5 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml @@ -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 -2026-07-04-share-app-bin-boot-glue.md: afaa61fe909f3dbf900337518969410780020a88 -2026-07-04-share-app-bin-boot-glue.zh.md: 33fe2f27df9c8b172e4296ece0720813f9775f86 +2026-07-04-share-app-bin-boot-glue.md: 31666e74bb0bb0086de85e6a3afafbc2f73a6e52 +2026-07-04-share-app-bin-boot-glue.zh.md: d18f83be0f76774e39a1e54f1ea2db3c1c1b7688 diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md index afaa61fe90..31666e74bb 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md @@ -1,9 +1,9 @@ # RFC: Share the app bins' boot glue instead of maintaining twin copies -English | [中文](2026-07-04-share-app-bin-boot-glue.zh.md) - Status: implemented +English | [中文](2026-07-04-share-app-bin-boot-glue.zh.md) + ## Problem The stdio and ACP bins duplicated environment loading, fail-loud handling, entry validation, and boot logic, including subtle Loader failure behavior. Their copies had already drifted and lived in self-executing files excluded from unit coverage, making their helper exports unusable. diff --git a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md index 33fe2f27df..d18f83be0f 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md @@ -1,9 +1,9 @@ -# RFC:共享应用 bin 的启动胶水代码,而非维护两份副本 - -[English](2026-07-04-share-app-bin-boot-glue.md) | 中文 +# RFC: 共享应用 bin 的启动胶水代码,而非维护两份副本 Status: implemented +[English](2026-07-04-share-app-bin-boot-glue.md) | 中文 + ## 问题 stdio 和 ACP 两个 bin 各自重复了环境加载、fail-loud 处理、入口校验与启动逻辑,包括微妙的 Loader 失败行为。两份副本已经发生漂移,且位于自执行文件中、被排除在单元测试覆盖率之外,导致其导出的辅助函数无法被复用。 diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml index 95c2fdbf50..b2926299df 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml @@ -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 -2026-07-04-tighten-hook-protocol-contract.md: df438516b836315902378afe7f4fd09e512c0966 -2026-07-04-tighten-hook-protocol-contract.zh.md: 256da42993c8581e8bce861ecbfac22dbf5f0545 +2026-07-04-tighten-hook-protocol-contract.md: 92ed629edaa0364d88955458f39f6280322e79c7 +2026-07-04-tighten-hook-protocol-contract.zh.md: 9b5b19d7ad522fdf74eb330c259d8dee03bee604 diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md index df438516b8..92ed629eda 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.md @@ -1,9 +1,9 @@ # RFC: Tighten the hook-protocol contract — dialect, discarded fields, double defaults, and lib-owned `hook/result` semantics -English | [中文](2026-07-04-tighten-hook-protocol-contract.zh.md) - Status: implemented +English | [中文](2026-07-04-tighten-hook-protocol-contract.zh.md) + ## Problem Four pieces of the `dsh-hook-protocol`/bridge contract missed the discipline the [subagent-observe-enrich RFC](../feature/2026-06-30-subagent-observe-enrich.md) records — it dropped an `agentType` lifecycle field for lacking a consumer, and these failed the same test: diff --git a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md index 256da42993..9b5b19d7ad 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md @@ -1,9 +1,9 @@ -# RFC:收紧 hook-protocol 契约——dialect、废弃字段、双重默认值与 lib 拥有的 `hook/result` 语义 - -[English](2026-07-04-tighten-hook-protocol-contract.md) | 中文 +# RFC: 收紧 hook-protocol 契约——dialect、废弃字段、双重默认值与 lib 拥有的 `hook/result` 语义 Status: implemented +[English](2026-07-04-tighten-hook-protocol-contract.md) | 中文 + ## 问题 `dsh-hook-protocol`/bridge 契约中有四处遗漏了 [subagent-observe-enrich RFC](../feature/2026-06-30-subagent-observe-enrich.md) 所记录的纪律——该 RFC 因缺乏消费方而移除了 `agentType` 生命周期字段,以下四处未通过同样的检验: diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml index aa5df52a6a..f0afae419b 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml @@ -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 -2026-07-04-trim-acp-bridge-unreachable-surface.md: 6decb494dcbfd348777577002187007597a8c374 -2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: 9d588e6f1132869ead60586b4df6844400307863 +2026-07-04-trim-acp-bridge-unreachable-surface.md: 05a62c92ec1553e6eb0b14adc86f8aa1b89827e5 +2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: 851198eee0559013429ef4eb5491cd7f97217c46 diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md index 6decb494dc..05a62c92ec 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md @@ -1,9 +1,9 @@ # RFC: Trim unreachable ACP bridge surface — the branding knobs and the kind-sniffing fallback -English | [中文](2026-07-04-trim-acp-bridge-unreachable-surface.zh.md) - Status: implemented +English | [中文](2026-07-04-trim-acp-bridge-unreachable-surface.zh.md) + ## Problem Two pieces of `dsh-acp` surface were unreachable from any shipped configuration: diff --git a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md index 9d588e6f11..851198eee0 100644 --- a/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md @@ -1,9 +1,9 @@ -# RFC:裁剪不可达的 ACP 桥接层表面——品牌配置项与 kind 嗅探回退 - -[English](2026-07-04-trim-acp-bridge-unreachable-surface.md) | 中文 +# RFC: 裁剪不可达的 ACP 桥接层表面——品牌配置项与 kind 嗅探回退 Status: implemented +[English](2026-07-04-trim-acp-bridge-unreachable-surface.md) | 中文 + ## 问题 `dsh-acp` 有两处对外表面在任何已交付的配置中都不可达: diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml index 593cb8a50e..3644236c38 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml @@ -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 -2026-07-12-drop-unconsumed-skill-provider-events.md: 5ec9d201939b8f58334647353f599361bd2e58a0 -2026-07-12-drop-unconsumed-skill-provider-events.zh.md: 15dbfedb07afa36b677074c403812d0f164c8bd5 +2026-07-12-drop-unconsumed-skill-provider-events.md: 90157c03e5df05c98b992ce1dbefea26f4865ce7 +2026-07-12-drop-unconsumed-skill-provider-events.zh.md: 19fec4b827b89b4127b749a9c77715baf39dd00a diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md index 5ec9d20193..90157c03e5 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.md @@ -1,9 +1,9 @@ # RFC: Drop unconsumed skill provider events -English | [中文](2026-07-12-drop-unconsumed-skill-provider-events.zh.md) - Status: implemented +English | [中文](2026-07-12-drop-unconsumed-skill-provider-events.zh.md) + ## Problem Two skill-registry notifications are produced but have no production listener. The generated producer/consumer matrix and exact event-name searches find only declarations, emit sites, tests, generated catalogs, and prose for `skill/provider-added` and `skill/provider-removed`. diff --git a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md index 15dbfedb07..19fec4b827 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md @@ -1,9 +1,9 @@ -# RFC:移除无消费方的 skill 提供方事件 - -[English](2026-07-12-drop-unconsumed-skill-provider-events.md) | 中文 +# RFC: 移除无消费方的 skill 提供方事件 Status: implemented +[English](2026-07-12-drop-unconsumed-skill-provider-events.md) | 中文 + ## 问题 skill(技能)注册表产出两个通知事件,但没有生产环境的监听方。生成的生产者/消费方矩阵以及对事件名的精确搜索表明,`skill/provider-added` 与 `skill/provider-removed` 仅出现在声明、emit 站点、测试、生成的 catalog 和行文中。 diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml index 7413576228..703539b152 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml @@ -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 -2026-07-12-prune-unused-web-seam-fields.md: b4773c2706cf6d18ea4bb96720cd6c932cdf8942 -2026-07-12-prune-unused-web-seam-fields.zh.md: 2c18fbcb440ce85798c8f36cdc5dc649149d8ba9 +2026-07-12-prune-unused-web-seam-fields.md: 9fd05da282c22d78dc98e232ef2c23cd6e9c4ea3 +2026-07-12-prune-unused-web-seam-fields.zh.md: 650b6b74c808c719bcea9783c60064936427ffee diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md index b4773c2706..9fd05da282 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.md @@ -1,9 +1,9 @@ # RFC: Prune unused web seam fields -English | [中文](2026-07-12-prune-unused-web-seam-fields.zh.md) - Status: implemented +English | [中文](2026-07-12-prune-unused-web-seam-fields.zh.md) + ## Problem The web capability carries request/result/status values that every shipped implementation populates but no production consumer reads. `WebSearchResult.providerId` and `query` and `WebFetchResult.providerId` are result echoes; `tool-web` formats only content/sources/truncation or final URL/status/body/truncation, and no other runtime reads them. Search providers return `WebProviderStatus.reason`, but resolution checks only `available` and intentionally emits a generic unavailable diagnostic. diff --git a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md index 2c18fbcb44..650b6b74c8 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md +++ b/docs/rfc/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md @@ -1,9 +1,9 @@ -# RFC:裁剪 web seam 中未使用的字段 - -[English](2026-07-12-prune-unused-web-seam-fields.md) | 中文 +# RFC: 裁剪 web seam 中未使用的字段 Status: implemented +[English](2026-07-12-prune-unused-web-seam-fields.md) | 中文 + ## 问题 web 能力携带的 request/result/status 值,虽然每个已交付的实现都会填充,但没有任何生产环境的消费方读取它们。`WebSearchResult.providerId`、`query`与 `WebFetchResult.providerId` 是结果回显;`tool-web` 只格式化 content/sources/truncation 或最终 URL/status/body/truncation,没有其他运行时读取这些字段。搜索提供方返回 `WebProviderStatus.reason`,但可用性检查只看 `available`,并有意输出一条通用的不可用诊断信息。 diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml index cc2bf1f23f..22d74d7424 100644 --- a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.i18n.yaml @@ -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 -2026-06-11-property-based-testing.md: 169989746ea5114b1f35e7ebe35a02e8aeb0f782 -2026-06-11-property-based-testing.zh.md: 4f2303010f44279c4edd0ec5a509b71f8aad606b +2026-06-11-property-based-testing.md: 153584d3a2b77c8f2d103db02646f18a9d424b57 +2026-06-11-property-based-testing.zh.md: e11d11f7db9eee97ab81bc678afab5d0fea36bf9 diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md index 169989746e..153584d3a2 100644 --- a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.md @@ -1,9 +1,9 @@ # RFC: Property-based testing for protocol-shaped code -English | [中文](2026-06-11-property-based-testing.zh.md) - Status: implemented +English | [中文](2026-06-11-property-based-testing.zh.md) + > Merges the original proposal and the decision record for one topic. It found a real BlockAssembler duplicate-`block-end` bug on first run. ## Problem diff --git a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md index 4f2303010f..e11d11f7db 100644 --- a/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md +++ b/docs/rfc/implemented/testing/2026-06-11-property-based-testing.zh.md @@ -1,4 +1,4 @@ -# RFC:对协议形态代码进行基于属性的测试 +# RFC: 对协议形态代码进行基于属性的测试 Status: implemented @@ -14,7 +14,7 @@ Status: implemented 引入 `fast-check`(作为根 devDependency),在每个协议形态的包(package)中编写一个 `tests/properties.spec.ts`。生成器调优为*逼真但对抗性*的输入(而非均匀噪声),`numRuns` 控制在本地套件总耗时远低于约 10 秒。失败时打印可复现的 seed。(原始提案还草拟了一个夜间 CI job,以 100 倍迭代运行;该部分未交付。属性测试套件仅在常规的 `push`/`pull_request` CI 中运行,定时高迭代 job 仍属可能的后续工作。) -- **dsh-llm / BlockAssembler:** 任意分片流(合法 + 畸形:重复索引、滞后分片、缺少 block-start)。不变式:`blocks()` 计数 ≤ 已见到的不同索引数;重组幂等(`blocks()` 在重复调用间稳定,且 `message().content` 与之一致);`blocks()` 从不抛异常且仅产出合法的 content-block 标签;`finish` 反映最后一个 `finish` 分片,无 `finish` 分片时默认为 `{kind:'stop'}`。 +- **dsh-llm / BlockAssembler:** 任意分片流(合法 + 畸形:重复索引、滞后分片、缺少 block-start)。不变式:`blocks()` 计数 ≤ 已见到的不同索引数;重组幂等(`blocks()` 在重复调用间稳定,且 `message().content` 与之一致);`blocks()` 从不抛异常且仅产出合法的 content-block 标签;`finish` 反映最后一个 `finish` 分片,无此类分片时默认为 `{kind:'stop'}`。 - **dsh-session:** 任意事件日志。不变式:`deriveMessages` 确定性;从 seed 回放结果一致;seq 严格单调递增;非消息事件不影响推导出的历史;推导出的内容与日志解耦。 - **dsh-tools:** 任意 `SchemaSpec`。不变式:JSON Schema 的 `required` 等于每一层 `required:true` 的键集;转换是全函数;**并且与[运行时参数校验](../architecture/2026-06-11-runtime-arg-validation.md)组合验证**——满足 spec 的生成参数通过 `validateArgs`,而定向破坏(删除必填键、顶层非对象)被拒绝。这封堵了 validator 与 `InferArgs` 漂移的风险。 - **dsh-agent-loop:** 任意发送调度,对接一个永不耗尽的适配器,通过 `agent/status` settle 信号驱动(无挂钟 sleep)。不变式:无消息丢失;轮次编号严格递增;状态转换保持在合法状态机上。 diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml index 1dfb26a628..10573d8e31 100644 --- a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml @@ -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 -2026-06-19-acp-snapshot-tests.md: 0b93c99932a33bca9945dd88ce45f4a1e100ccfc -2026-06-19-acp-snapshot-tests.zh.md: 26c583ba47b8ec10ab3d0e2102a8b791549fda38 +2026-06-19-acp-snapshot-tests.md: c336b4864b73b8db29c0a8bb983d974348a9515a +2026-06-19-acp-snapshot-tests.zh.md: bc9488562b0698b172ccffff74815a893acf722d diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md index 0b93c99932..c336b4864b 100644 --- a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md @@ -1,9 +1,9 @@ # RFC: ACP snapshot tests — record-once / replay-deterministic -English | [中文](2026-06-19-acp-snapshot-tests.zh.md) - Status: implemented +English | [中文](2026-06-19-acp-snapshot-tests.zh.md) + ## Problem Unit tests do not exercise the complete ACP subprocess transcript, while real-API tests are nondeterministic and key-gated. Editor-facing `session/update` output can therefore regress despite green unit coverage, as the [default-export postmortem](../../../postmortem/0001-acp-default-export-drops-inject.md) demonstrated. diff --git a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md index 26c583ba47..bc9488562b 100644 --- a/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md +++ b/docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md @@ -1,4 +1,4 @@ -# RFC:ACP 快照测试——一次录制 / 确定性回放 +# RFC: ACP 快照测试——一次录制 / 确定性回放 Status: implemented diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml index 591f51750a..bb98e02fd7 100644 --- a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml @@ -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 -2026-06-19-real-api-e2e-ci.md: 3b5995a3e060ef9b4b1639b5c7fb17c819e73150 -2026-06-19-real-api-e2e-ci.zh.md: 78bab7c1e00125bfbe11b8f08eeeff3f2b7723b1 +2026-06-19-real-api-e2e-ci.md: cc3e14e2d411dfa4cc68132f649f4ed26ab1de1d +2026-06-19-real-api-e2e-ci.zh.md: 58a2a87541fd5b73b8272aa729f9dd09a429e4b4 diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md index 3b5995a3e0..cc3e14e2d4 100644 --- a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md @@ -1,9 +1,9 @@ # RFC: Real-API e2e in CI against the external DeepSeek API -English | [中文](2026-06-19-real-api-e2e-ci.zh.md) - Status: implemented +English | [中文](2026-06-19-real-api-e2e-ci.zh.md) + ## Problem The harness leans hard on real-API tests by policy: [docs/testing.md](../../../testing.md) argues that a no-key suite proves the plumbing but not the product, and the [ACP inject postmortem](../../../postmortem/0001-acp-default-export-drops-inject.md) is the standing proof — 178 keyless tests stayed green while a real editor session crashed instantly. The real-API e2e suite (`pnpm run test:e2e`, the `*.e2e.ts` files) exists precisely to close that gap: it drives the agent against the live DeepSeek API — real model calls, real bash tools, multi-turn, resume, ACP-over-stdio. diff --git a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md index 78bab7c1e0..58a2a87541 100644 --- a/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md +++ b/docs/rfc/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md @@ -1,9 +1,9 @@ -# RFC:在 CI 中对外部 DeepSeek API 运行真实 API e2e 测试 - -[English](2026-06-19-real-api-e2e-ci.md) | 中文 +# RFC: 在 CI 中对外部 DeepSeek API 运行真实 API e2e 测试 Status: implemented +[English](2026-06-19-real-api-e2e-ci.md) | 中文 + ## 问题 按照策略,harness 高度依赖真实 API 测试:[docs/testing.md](../../../testing.md) 论证了无密钥套件只能验证管道连通性而非产品本身,[ACP inject 事后分析](../../../postmortem/0001-acp-default-export-drops-inject.md)是现成的证据——178 个无密钥测试全绿,而真实编辑器会话一启动就崩溃。真实 API e2e 套件(`pnpm run test:e2e`,即 `*.e2e.ts` 文件)正是为弥合这一差距而存在的:它驱动 agent(智能体)对接实时 DeepSeek API——真实模型调用、真实 bash 工具、多轮次对话、恢复、ACP-over-stdio。 diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml index 6e63ef2e55..5f59fbacf1 100644 --- a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.i18n.yaml @@ -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 -2026-06-20-remove-redundant-snapshot-log-goldens.md: badd32d4479ac6d44bb7be3cd262cba57b1b3a38 -2026-06-20-remove-redundant-snapshot-log-goldens.zh.md: b791fbcc971eb1340f0d43ef6a60ebb29e4711f9 +2026-06-20-remove-redundant-snapshot-log-goldens.md: 18d0a4491eb10a3b4dc56d3d63285c219ba6a00a +2026-06-20-remove-redundant-snapshot-log-goldens.zh.md: 5675c69862b6052ed3f3e4710461cc1478b9fa7d diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md index badd32d447..18d0a4491e 100644 --- a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.md @@ -1,9 +1,9 @@ # RFC: Use `session.jsonl` as the only snapshot session-log artifact -English | [中文](2026-06-20-remove-redundant-snapshot-log-goldens.zh.md) - Status: implemented +English | [中文](2026-06-20-remove-redundant-snapshot-log-goldens.zh.md) + ## Problem Model-driving ACP snapshot scenarios ship both `session.jsonl` and `session.golden.jsonl`. For normal recorded scenarios, `session.jsonl` is the replay fixture harvested from a real run, and the replay test normalizes the newly persisted log and compares it to `session.golden.jsonl`. In the current fixtures, the normalized recorded log and normalized golden are identical for the ordinary recorded scenarios. diff --git a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md index b791fbcc97..5675c69862 100644 --- a/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md +++ b/docs/rfc/implemented/testing/2026-06-20-remove-redundant-snapshot-log-goldens.zh.md @@ -1,4 +1,4 @@ -# RFC:使用 `session.jsonl` 作为唯一的快照会话日志产物 +# RFC: 使用 `session.jsonl` 作为唯一的快照会话日志产物 Status: implemented diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml index f3bddc661c..cfae43ecf0 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml @@ -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 -2026-06-22-fork-child-replay-seed-boundary.md: a0bf064508107a23147df1a6c824c53a3906c43e -2026-06-22-fork-child-replay-seed-boundary.zh.md: 3825cce806c036c7fa21641a2f0b7cc0533d84bf +2026-06-22-fork-child-replay-seed-boundary.md: 28ce76309da2dca7076dd11211229a0631d11db3 +2026-06-22-fork-child-replay-seed-boundary.zh.md: 92b60589b4cfe9668a1542405693cec8d29eceaf diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md index a0bf064508..28ce76309d 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md @@ -1,9 +1,9 @@ # RFC: Persist the seed boundary so fork-child replay routes correctly -English | [中文](2026-06-22-fork-child-replay-seed-boundary.zh.md) - Status: implemented +English | [中文](2026-06-22-fork-child-replay-seed-boundary.zh.md) + ## Problem The [per-session snapshot replay RFC](2026-06-22-subagent-snapshot-replay.md) made the snapshot tier express a nested-agent shape: a parent plus one recorded log per in-process subagent, each replayed as its own script keyed by calling session. It noted (§ Scope, final bullet) that a fork snapshot was "a trivial future addition, not a gap in the keying." That was wrong about a fork child specifically — not the keying, but the *script derivation*. diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md index 3825cce806..92b60589b4 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md @@ -1,9 +1,9 @@ -# RFC:持久化 seed 边界以确保 fork 子会话回放正确路由 - -[English](2026-06-22-fork-child-replay-seed-boundary.md) | 中文 +# RFC: 持久化 seed 边界以确保 fork 子会话回放正确路由 Status: implemented +[English](2026-06-22-fork-child-replay-seed-boundary.md) | 中文 + ## 问题 [逐会话快照回放 RFC](2026-06-22-subagent-snapshot-replay.md) 让快照层表达了嵌套 agent(智能体)的形状:一个父会话加上每个进程内 subagent 各一份已录制的日志,各自作为独立脚本回放、以调用方会话为键。该 RFC 指出(§ Scope 末尾条目)fork 快照是「一个平凡的后续补充,不是键控方案的缺口」。这对 fork 子会话而言是错的——问题不在键控,而在*脚本推导*。 diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml index d262a105ce..e487e40249 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml @@ -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 -2026-06-22-fork-snapshot-scenarios.md: baca94d6a1071ec38ee20ca841fc3472a870b1a2 -2026-06-22-fork-snapshot-scenarios.zh.md: b6f3f6a6f318a343d5e32573d39f11f59b509ee3 +2026-06-22-fork-snapshot-scenarios.md: a5324cbfa13b79c0ea60b74b689f1b19db99a725 +2026-06-22-fork-snapshot-scenarios.zh.md: 543382db86eb50b5f278a99de74586a13bff9eb7 diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md index baca94d6a1..a5324cbfa1 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.md @@ -1,9 +1,9 @@ # RFC: Record fork and mixed spawn+fork snapshot scenarios -English | [中文](2026-06-22-fork-snapshot-scenarios.zh.md) - Status: implemented +English | [中文](2026-06-22-fork-snapshot-scenarios.zh.md) + ## Problem The [seed-boundary RFC](2026-06-22-fork-child-replay-seed-boundary.md) made fork-child replay route correctly: `dsh-llm-replay` derives a child's script from the events at or after its persisted `seedLength` boundary, so a fork child's inherited parent prefix is not replayed as the child's own model calls. But it shipped with **no recorded fork scenario** — the slice was exercised only by `llm-replay`'s unit tests (a synthetic child fixture) and a persistence round-trip test. The full-transcript snapshot tier, the one net that boots the real `acp-agent` and replays an end-to-end nested transcript, had only spawn children (`subagent-spawn`, `subagent-multi`). A fork-routing regression that left the unit tests green would still have escaped the tier built to catch transcript regressions. diff --git a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md index b6f3f6a6f3..543382db86 100644 --- a/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md +++ b/docs/rfc/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md @@ -1,4 +1,4 @@ -# RFC:记录 fork 与混合 spawn+fork 快照场景 +# RFC: 记录 fork 与混合 spawn+fork 快照场景 Status: implemented @@ -8,7 +8,7 @@ Status: implemented [seed-boundary RFC](2026-06-22-fork-child-replay-seed-boundary.md) 使 fork 子会话的回放路由正确运作:`dsh-llm-replay` 从子会话持久化的 `seedLength` 边界处或之后的事件推导出子会话的脚本,因此 fork 子会话继承的父会话前缀不会被当作子会话自身的模型调用来回放。但该 RFC 交付时**没有记录 fork 场景**——该切片仅由 `llm-replay` 的单元测试(一个合成的子会话 fixture(测试前置数据))和一个持久化往返测试覆盖。全 transcript(文本记录)快照层(即启动真实 `acp-agent` 并回放端到端嵌套 transcript 的那张网)只有 spawn 子会话(`subagent-spawn`、`subagent-multi`)。如果一个 fork 路由回归让单元测试保持绿色,它仍然会逃过专为捕获 transcript 回归而建的那一层。 -表达 fork 场景所需的快照基础设施已经就位:两个进程内后端都在 `cordis.yml` / `cordis.snapshot.yml` 中以两个面向模型的工具接入(`subagent` → spawn、`subagent_fork` → fork),harness 会收集每个子会话的日志,回放按 `seedLength` 为键转发各子会话的 fixture。缺少的是一个**已记录的场景**来驱动 fork 子会话走完这条路径。 +表达 fork 场景所需的快照基础设施已经就位:两个进程内后端都在 `cordis.yml` / `cordis.snapshot.yml` 中以两个面向模型的工具接入(`subagent` → spawn、`subagent_fork` → fork),harness 会收集每个子会话的日志,回放按 `seedLength` 为键转发各子会话的 fixture。缺少的是一个*已记录的场景*来驱动 fork 子会话走完这条路径。 ## 决策 @@ -19,12 +19,12 @@ Status: implemented ### 为什么需要一个已完成的第一轮次 -fork 后端用父会话的**已完成轮次的平衡前缀**([`completedTurnPrefix`](../../../../packages/subagent/subagent-fork))来初始化子会话。如果父会话在第一轮次就 fork,则没有已完成的轮次可继承,seed 为空(等价于全新 spawn,`seedLength` 为 0),这**不会**覆盖切片逻辑。因此两个场景都使用双 prompt 输入:第一个 prompt 完成一个轮次(建立一个 codeword,子会话稍后被要求回忆它),第二个 prompt 委派 fork。子会话 transcript 中回忆出的 codeword 只是模型行为的附带产物;真正承载验证的产物是子会话 fixture 中记录的 `seedLength`,回放切片消费的正是它。 +fork 后端用父会话的**已完成轮次的平衡前缀**([`completedTurnPrefix`](../../../../packages/subagent/subagent-fork))来初始化子会话。如果父会话在第一轮次就 fork,则没有已完成的轮次可继承,seed 为空(等价于全新 spawn,`seedLength` 为 0),这不会覆盖切片逻辑。因此两个场景都使用双 prompt 输入:第一个 prompt 完成一个轮次(建立一个 codeword,子会话稍后被要求回忆它),第二个 prompt 委派 fork。子会话 transcript 中回忆出的 codeword 只是模型行为的附带产物;真正承载验证的产物是子会话 fixture 中记录的 `seedLength`,回放切片消费的正是它。 ## 后果 - fork 路由切片现在由全 transcript 层守卫,而不仅仅是单元测试。移除 `slice(seedLength)`(回放整个子会话日志)会让**两个**新场景变红——fork 子会话收到的是父会话记录的 chunk 而非自己的——证明守卫确实生效(场景落地时已验证红→绿)。 -- `subagent-mixed` 是第一个在同一个 transcript 中驱动两种**不同** subagent 后端的快照场景,同时覆盖了跨 spawn 和 fork 子会话的 per-session 回放键控。 +- `subagent-mixed` 是第一个在同一个 transcript 中驱动两种*不同* subagent 后端的快照场景,同时覆盖了跨 spawn 和 fork 子会话的 per-session 回放键控。 - 进程外(ACP)subagent 回放形态不同(每个子会话是独立进程、有自己的回放),仍以 `TODO(acp-subagent-replay)` 跟踪——本文场景仅限进程内。 - 重新录制(`pnpm run test:snapshot:record`)会从真实 API 重新生成全部四个 fork/spawn fixture;两个新场景在无密钥时自动跳过,与所有已录制场景一致。 diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml index 8bea2c8a5e..c8d42599e1 100644 --- a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml @@ -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 -2026-06-22-subagent-snapshot-replay.md: fbb2e5b93cced118a24f5560f229e2dc341bf3b2 -2026-06-22-subagent-snapshot-replay.zh.md: 6514a0bcb5db3948f6d8f4693b17a74e4a9ad926 +2026-06-22-subagent-snapshot-replay.md: 89fc4e8d4d267fd4df373a7fd82b8c6e742be6ea +2026-06-22-subagent-snapshot-replay.zh.md: 7dc234ab9c6e3bb1facd78e98aad15005d158325 diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md index fbb2e5b93c..89fc4e8d4d 100644 --- a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.md @@ -1,9 +1,9 @@ # RFC: Per-session snapshot replay for nested agents -English | [中文](2026-06-22-subagent-snapshot-replay.zh.md) - Status: implemented +English | [中文](2026-06-22-subagent-snapshot-replay.zh.md) + ## Problem The snapshot tier (`pnpm run test:snapshot`) boots the real `acp-agent` subprocess, replays a recorded session through [`dsh-llm-replay`](../../../../packages/support/llm-replay), and diffs the normalized stdout transcript + re-persisted session log against committed goldens. It is the only tier that exercises the full editor-facing transcript end to end. diff --git a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md index 6514a0bcb5..7dc234ab9c 100644 --- a/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md +++ b/docs/rfc/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md @@ -1,9 +1,9 @@ -# RFC:嵌套 agent 的逐会话快照回放 - -[English](2026-06-22-subagent-snapshot-replay.md) | 中文 +# RFC: 嵌套 agent 的逐会话快照回放 Status: implemented +[English](2026-06-22-subagent-snapshot-replay.md) | 中文 + ## 问题 快照测试层(`pnpm run test:snapshot`)启动真实的 `acp-agent` 子进程,通过 [`dsh-llm-replay`](../../../../packages/support/llm-replay) 回放录制的会话,并将归一化后的 stdout transcript(文本记录)与重新持久化的会话日志对已提交的金标文件做 diff。这是唯一一个端到端验证完整编辑器侧 transcript 的测试层。 @@ -29,7 +29,7 @@ Status: implemented 活跃会话 id 每次运行都是全新随机值,永远不等于录制时的 id,因此活跃会话无法通过 id 相等绑定到脚本。取而代之的是**首次调用顺序**绑定:第一个发起任何模型调用的活跃会话认领第一份有序脚本(即父会话:`createdAt` 最早,且必然最先流式输出,因为它必须先运行一个轮次才能委派),下一个新活跃会话认领下一份脚本,依此类推。此后每个会话独立推进自己的游标。 -这种方式按**谁在调用**键控,而非按全局调用顺序。因此即使 subagent 将来并发或在后台运行(全局游标会导致交错),它仍然正确。不携带 `sessionId` 的调用(直接在单元测试中调用 `stream()`)被视为一个匿名会话、绑定到主脚本,因此单会话路径与旧行为逐字节一致。活跃会话数多于录制脚本数时会快速失败报错(出现了未录制的 subagent),绝不会静默错误路由。 +这种方式按谁在调用键控,而非按全局调用顺序。因此即使 subagent 将来并发或在后台运行(全局游标会导致交错),它仍然正确。不携带 `sessionId` 的调用(直接在单元测试中调用 `stream()`)被视为一个匿名会话、绑定到主脚本,因此单会话路径与旧行为逐字节一致。活跃会话数多于录制脚本数时会快速失败报错(出现了未录制的 subagent),绝不会静默错误路由。 子 fixture(测试前置数据)按 `createdAt` 排序,在兄弟会话严格顺序执行时与调用顺序一致。id 平局打破仅使退化碰撞具有确定性。并发或后台子会话必须引入显式的首次调用序号,而非依赖时间戳。 @@ -54,5 +54,5 @@ Status: implemented - `TODO(subagent-snapshots)` 延期项已解决:嵌套 agent 的 transcript 现在是快照层的一等形态。 - `GenerateOptions.sessionId` 是一个小而诚实的 core-seam 新增,在回放之外同样有用(遥测、请求路由)。 -- `subagent` 工具绑定到单一提供方,因此 `subagent-multi` 中的两个子 agent 都是 spawn(全新创建)。键控按会话路由而非按后端路由,因此对 fork 同样正确。但脚本**派生**逻辑此前不正确:fork 子会话的日志以种子化的父前缀(父会话的 `assistant/chunk` 事件)开头,如果从完整日志派生脚本,就会把父 agent 的响应当作子 agent 的来回放。这一正确性缺口通过持久化种子边界来弥合——见 [Persist the seed boundary so fork-child replay routes correctly](2026-06-22-fork-child-replay-seed-boundary.md)——录制的 fork 与混合 spawn+fork 场景现在通过一份 transcript 同时验证两种传输方式(见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md))。 +- `subagent` 工具绑定到单一提供方,因此 `subagent-multi` 中的两个子 agent 都是 spawn(全新创建)。键控按会话路由而非按后端路由,因此对 fork 同样正确。但脚本*派生*逻辑此前不正确:fork 子会话的日志以种子化的父前缀(父会话的 `assistant/chunk` 事件)开头,如果从完整日志派生脚本,就会把父 agent 的响应当作子 agent 的来回放。这一正确性缺口通过持久化种子边界来弥合——见 [Persist the seed boundary so fork-child replay routes correctly](2026-06-22-fork-child-replay-seed-boundary.md)——录制的 fork 与混合 spawn+fork 场景现在通过一份 transcript 同时验证两种传输方式(见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md))。 - 进程外(ACP)subagent 是完全不同的回放形态(每个子 agent 是自己的进程、有自己的回放),作为 `TODO(acp-subagent-replay)` 记录在 PR3 计划中。 diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml index a0daca4800..8c06af4e98 100644 --- a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml @@ -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 -2026-07-04-hook-snapshot-matrix.md: 8505e82fb681975c7506102a3eb858a29ccc11c8 -2026-07-04-hook-snapshot-matrix.zh.md: 9a9f085400e938bc15c171f652d65f7bcdfa518f +2026-07-04-hook-snapshot-matrix.md: b365992c01e081e5698e81a9ff9682e9b8166ce6 +2026-07-04-hook-snapshot-matrix.zh.md: bcb8e5ba55a14dd0c299dac161146a19f18201eb diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md index 8505e82fb6..b365992c01 100644 --- a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.md @@ -1,9 +1,9 @@ # RFC: Hook snapshot matrix — end-to-end goldens for both bridges -English | [中文](2026-07-04-hook-snapshot-matrix.zh.md) - Status: implemented +English | [中文](2026-07-04-hook-snapshot-matrix.zh.md) + ## Problem The hook bridges — [`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude) (7 Claude Code hook points) and [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex) (5 Codex points) — map external hook commands onto the harness interception seams. They carry deep unit and coverage-spec coverage (every decision arm, every payload dialect, driven against a mocked seam) plus one key-gated e2e (`hooks.e2e.ts`, a live `PreToolUse` block). But the full-transcript snapshot tier — the one net that boots the real `acp-agent` subprocess, replays a recorded session keyless, and diffs the normalized ACP stdout + re-persisted log against committed goldens — covered exactly ONE hook: a Claude `UserPromptSubmit` block (`hook-cc-promptsubmit-block`). diff --git a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md index 9a9f085400..bcb8e5ba55 100644 --- a/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md +++ b/docs/rfc/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md @@ -1,4 +1,4 @@ -# RFC:Hook 快照矩阵——覆盖两种 bridge 的端到端 golden 测试 +# RFC: Hook 快照矩阵——覆盖两种 bridge 的端到端 golden 测试 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -hook bridge——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude)(7 个 Claude Code hook 点)和 [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex)(5 个 Codex 点)——将外部 hook 命令映射到 harness 的拦截 seam 上。它们拥有深度的单元测试和 coverage-spec 覆盖率(每个决策分支、每种 payload 方言,均对 mock 的 seam 驱动),外加一个需要密钥的 e2e 测试(`hooks.e2e.ts`,一次真实的 `PreToolUse` 拦截)。但完整 transcript(文本记录)快照层:那张真正启动 `acp-agent` 子进程、无密钥回放录制会话、并将规范化的 ACP stdout 与重新持久化的日志与已提交 golden 做 diff 的网,只覆盖了**一个** hook:Claude 的 `UserPromptSubmit` 拦截(`hook-cc-promptsubmit-block`)。 +hook bridge——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude)(7 个 Claude Code hook 点)和 [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex)(5 个 Codex 点)——将外部 hook 命令映射到 harness 的拦截 seam 上。它们拥有深度的单元测试和 coverage-spec 覆盖率(每个决策分支、每种 payload 方言,均对 mock 的 seam 驱动),外加一个需要密钥的 e2e 测试(`hooks.e2e.ts`,一次真实的 `PreToolUse` 拦截)。但完整 transcript(文本记录)快照层:那张真正启动 `acp-agent` 子进程、无密钥回放录制会话、并将规范化的 ACP stdout 与重新持久化的日志与已提交 golden 做 diff 的网,只覆盖了一个 hook:Claude 的 `UserPromptSubmit` 拦截(`hook-cc-promptsubmit-block`)。 这正是 mock 单元测试在结构上无法替代的层级:它验证的是真实 bridge 将真实 hook 进程的结果翻译到真实 seam 决策,再到真实 agent loop(智能体循环)的反应,渲染结果与编辑器看到的完全一致。一个 bridge 翻译或 loop 结构的回归,即使让所有单元测试保持绿色,也会在除那一个 hook 点之外的所有点上逃逸;而对于 Codex bridge,ACP 示例甚至没有加载它,因此没有任何 Codex hook 能端到端触发。 @@ -29,22 +29,22 @@ hook bridge——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude) - **手工编写、无模型轮次**(无密钥、无 sidecar——派生的回放脚本为空;比对的是携带 `hook/*` 事件的 `rejected` 轮次):`hook-cc-promptsubmit-block`、`hook-codex-promptsubmit-block`。 - **对真实 API 录制、录制期间 hook 活跃**(模型对决策的反应是捕获的 transcript 的一部分,此后无密钥回放):`hook-{cc,codex}-promptsubmit-context`(allow + additionalContext 折叠)、`hook-cc-pretool-deny` / `hook-codex-pretool-block`(deny → `isError` 工具结果)、`hook-cc-pretool-ask`(ask → 降级为 deny 并附带 approval-required 原因)、`hook-{cc,codex}-posttool-block`(block 并附带反馈)、`hook-{cc,codex}-posttool-context`(accept + additionalContext)、`hook-{cc,codex}-stop-continue`(阻塞性 Stop hook 通过 steering(中途引导)强制多走一步)。 -每个 hook 命令只输出**固定字面量字符串**(无时间戳/pid/`$RANDOM`/cwd 回显);快照规范化器擦除 `hook/result` 携带的唯一不稳定字段(`durationMs`)。`Stop` 场景通过标记文件(`.stop_fired`)自限,使 force-continue 不会循环——`stop_hook_active` 循环守卫仍是 bridge 的一个 `TODO`,因此无条件的 Stop hook 会在每一步都 force-continue。 +每个 hook 命令只输出固定字面量字符串(无时间戳/pid/`$RANDOM`/cwd 回显);快照规范化器擦除 `hook/result` 携带的唯一不稳定字段(`durationMs`)。`Stop` 场景通过标记文件(`.stop_fired`)自限,使 force-continue 不会循环——`stop_hook_active` 循环守卫仍是 bridge 的一个 `TODO`,因此无条件的 Stop hook 会在每一步都 force-continue。 ### 三个 hook 点被有意排除在快照之外 在构建矩阵过程中发现,记录于此是因为这些遗漏是决策而非疏忽: -- **`SessionStart` 与 `SubagentStart`** 通过一个分离的、尽力而为的 `void runPoint(...).then(agent.inject())` 注入上下文,**没有**轮次绑定。由此产生的 `context/message` 与它所先于的工作(首次模型请求/子 agent 的首轮)存在竞争,落在日志中的位置不确定。录制的 golden 甚至无法在自身回放中复现——10 次回放稳定性检查对两者均 10/10 失败。它们留在 bridge 的单元覆盖率中,单元测试直接驱动 seam 而无时序竞争。(如果注入将来变为轮次绑定且确定性的——`TODO(session-start-gating)` 所指的方向——它们就可以纳入快照。) -- **`SubagentStop`** 是纯观察性的:其 `subagent/end` 处理器不传递轮次(因此无 `hook/*` 日志事件)、不做注入。它对 transcript **不写入任何内容**,因此 golden 与无 hook 运行逐字节一致,永远无法被证明失败——一道永远不会触发的守卫。它留在单元覆盖率中(`bridge.spec.ts` 已断言了纯观察调用)。 +- **`SessionStart` 与 `SubagentStart`** 通过一个分离的、尽力而为的 `void runPoint(...).then(agent.inject())` 注入上下文,没有轮次绑定。由此产生的 `context/message` 与它所先于的工作(首次模型请求/子 agent 的首轮)存在竞争,落在日志中的位置不确定。录制的 golden 甚至无法在自身回放中复现——10 次回放稳定性检查对两者均 10/10 失败。它们留在 bridge 的单元覆盖率中,单元测试直接驱动 seam 而无时序竞争。(如果注入将来变为轮次绑定且确定性的——`TODO(session-start-gating)` 所指的方向——它们就可以纳入快照。) +- **`SubagentStop`** 是纯观察性的:其 `subagent/end` 处理器不传递轮次(因此无 `hook/*` 日志事件)、不做注入。它对 transcript 不写入任何内容,因此 golden 与无 hook 运行逐字节一致,永远无法被证明失败——一道永远不会触发的守卫。它留在单元覆盖率中(`bridge.spec.ts` 已断言了纯观察调用)。 -因此,该矩阵覆盖了所有具有**确定性、可观测** transcript 足迹的 hook 点,涵盖两种方言。 +因此,该矩阵覆盖了所有具有确定性、可观测 transcript 足迹的 hook 点,涵盖两种方言。 ## 后果 - 每个具有可观测 transcript 的 bridge seam 映射现在都在完整 transcript 层级、在真实应用中、对两种方言受到守护——包括此前完全没有端到端覆盖率的 Codex bridge。录制的 golden 捕获了模型对 deny/block/force-continue 轮次的真实反应,这是手工编写的 transcript 只能猜测的。 - block 场景无需密钥(无模型轮次);其余场景从录制的 fixture(测试前置数据)无密钥回放。`pnpm run test:snapshot:record` 从真实 API 重新生成录制的 fixture,无密钥时自动跳过,与所有录制场景一致。 -- prove-red 纪律成立:篡改 hook 配置的输出(例如修改 deny 原因)会使其场景在回放时变红——hook 进程在回放期间**真实运行**(只有模型被回放),因此 golden 守护的是实际的 hook→seam→loop 路径,而非它的 mock。 +- prove-red 纪律成立:篡改 hook 配置的输出(例如修改 deny 原因)会使其场景在回放时变红——hook 进程在回放期间真实运行(只有模型被回放),因此 golden 守护的是实际的 hook→seam→loop 路径,而非它的 mock。 - `acp-agent` 演示现在加载了一个通常会无操作的 Codex bridge(典型项目中没有 `codex-hooks.json`),这正是预期的柔性失败行为,而非代价。 <!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml index 4aa9340c22..733f3a2115 100644 --- a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml @@ -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 -2026-07-04-single-source-acp-replay-config.md: 922bdcced50f8e289449e05b51774f202228b0f8 -2026-07-04-single-source-acp-replay-config.zh.md: b347186f362fa5454f7bd5106c2e261cb8a00b61 +2026-07-04-single-source-acp-replay-config.md: 51cbd54d45408df1548c9cc2522b07b5ffaac110 +2026-07-04-single-source-acp-replay-config.zh.md: 2aec0e0e46007be243c0386fc0fca92065ce3c9e diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md index 922bdcced5..51cbd54d45 100644 --- a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.md @@ -1,9 +1,9 @@ # RFC: Single-source the acp-agent replay config -English | [中文](2026-07-04-single-source-acp-replay-config.zh.md) - Status: implemented +English | [中文](2026-07-04-single-source-acp-replay-config.zh.md) + ## Problem `examples/acp-agent` shipped two hand-maintained configs: `cordis.yml` (the live tree) and a `cordis.snapshot.yml` that mirrored it entry-for-entry with only the llm backend swapped — stripped of comments, the entire difference was the eight-line `llm-deepseek` stanza versus the two-line `llm-replay` stanza. Every app-shape change had to be made twice, and nothing gated the symmetry: if the copies drifted, the snapshot tier would silently exercise a different app than the one that ships — the ["green units, broken product" class of gap](../../../postmortem/0001-acp-default-export-drops-inject.md) the snapshot tier exists to close, reintroduced one level up, with reviewer vigilance as the only defense. diff --git a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md index b347186f36..2aec0e0e46 100644 --- a/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md +++ b/docs/rfc/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md @@ -1,9 +1,9 @@ -# RFC:将 acp-agent 回放配置改为单一来源 - -[English](2026-07-04-single-source-acp-replay-config.md) | 中文 +# RFC: 将 acp-agent 回放配置改为单一来源 Status: implemented +[English](2026-07-04-single-source-acp-replay-config.md) | 中文 + ## 问题 `examples/acp-agent` 曾维护两份手写配置:`cordis.yml`(正式运行树)和 `cordis.snapshot.yml`(逐条镜像前者,仅替换 LLM(大语言模型)后端)。去掉注释后,全部差异只是八行的 `llm-deepseek` 段落换成两行的 `llm-replay` 段落。每次应用结构变更都要改两遍,且没有门禁保障对称性:一旦两份副本漂移,快照层就会悄悄测试一个与实际交付不同的应用——正是快照层本要消除的["单元测试全绿、产品却坏了"这类缺口](../../../postmortem/0001-acp-default-export-drops-inject.md),在上一层被重新引入,唯一的防线是评审者的警觉。 @@ -23,5 +23,5 @@ overlay 依赖一个 vendor 插件的事实,这是有意为之:include 在 ## 后果 - 向 `cordis.yml` 添加插件即自动进入回放树,无需第二次编辑;漂移这一类问题从结构上消失,而非靠门禁拦截。 -- overlay 依赖条目携带稳定的 `id:`。禁用补丁上的 `name` 断言防止误定位(id 被复用时补丁跳过而非禁用错误的插件)。如果 id 被**重命名**,补丁退化为跳过,其警告需要一个回放应用有意不具备的 logger——可观测结果是一条无效的无密钥 `llm-deepseek` 条目与 `llm-replay` 并存,回放输出仍然正确(`llm-replay` 拥有流的短路权);这属于配置腐烂,留给评审发现,不会产生错误的快照。顶层插入一个 id 与既有条目冲突的新条目时,loader 的 id map 以后者为准;当前配置无冲突,新增补丁行才是引入冲突的场所。 +- overlay 依赖条目携带稳定的 `id:`。禁用补丁上的 `name` 断言防止误定位(id 被复用时补丁跳过而非禁用错误的插件)。如果 id 被重命名,补丁退化为跳过,其警告需要一个回放应用有意不具备的 logger——可观测结果是一条无效的无密钥 `llm-deepseek` 条目与 `llm-replay` 并存,回放输出仍然正确(`llm-replay` 拥有流的短路权);这属于配置腐烂,留给评审发现,不会产生错误的快照。顶层插入一个 id 与既有条目冲突的新条目时,loader 的 id map 以后者为准;当前配置无冲突,新增补丁行才是引入冲突的场所。 - 如果未来回放树需要第二处差异(另一个后端被替换),只需多加一行补丁,而非再 fork 一份文件。 diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml index 3b2d92e28c..dfb09d507a 100644 --- a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml @@ -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 -2026-07-06-pin-request-header-content-in-one-scenario.md: 5ccaa23a268114c5ba37ec153f4960b47df13bfd -2026-07-06-pin-request-header-content-in-one-scenario.zh.md: 909968430dc3e648e09eeeedd47436c35b90b870 +2026-07-06-pin-request-header-content-in-one-scenario.md: 0166b459fbb8d883f07fb195bdd5e025d70349de +2026-07-06-pin-request-header-content-in-one-scenario.zh.md: 1ca7df68fc743b919c6769ae8fa40ea16eb3d88a diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md index 5ccaa23a26..0166b459fb 100644 --- a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md @@ -1,9 +1,9 @@ # RFC: Pin request-header content in one snapshot scenario -English | [中文](2026-07-06-pin-request-header-content-in-one-scenario.zh.md) - Status: implemented +English | [中文](2026-07-06-pin-request-header-content-in-one-scenario.zh.md) + ## Problem An ACP snapshot suite needs to prove the exact composed system prompt and tool-schema list sent in each `request/header`, but duplicating that content inside every `session.jsonl` makes a prompt or schema edit rewrite dozens of giant one-line JSON records. Keeping one raw header avoids the duplication but still makes prompt review poor: prose is JSON-escaped onto one line and mixed with thousands of characters of tool schemas. diff --git a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md index 909968430d..1ca7df68fc 100644 --- a/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md +++ b/docs/rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md @@ -1,4 +1,4 @@ -# RFC:在单个快照场景中固定请求头内容 +# RFC: 在单个快照场景中固定请求头内容 Status: implemented diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml index c582f34c23..e8c8a129b8 100644 --- a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml @@ -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 -2026-07-08-shared-acp-snapshot-package.md: 81714191a704af1a9ed029fb8004deac88e39427 -2026-07-08-shared-acp-snapshot-package.zh.md: f80c8e49e80e9bf287c84c0ff4fb00377fad5175 +2026-07-08-shared-acp-snapshot-package.md: c378222804251761a1b04f59c35799a97a1525f1 +2026-07-08-shared-acp-snapshot-package.zh.md: cda7a578d4643800736ff159a6427d3a0e3e0fae diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md index 81714191a7..c378222804 100644 --- a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.md @@ -1,9 +1,9 @@ # RFC: Extract the ACP snapshot suite into a support package -English | [中文](2026-07-08-shared-acp-snapshot-package.zh.md) - Status: implemented +English | [中文](2026-07-08-shared-acp-snapshot-package.zh.md) + ## Problem The ACP snapshot tier ([snapshot RFC](2026-06-19-acp-snapshot-tests.md)) was built from three modules living inside one example's test directory: `snapshot-harness.ts` (boot the real bin subprocess, drive it over ACP JSON-RPC, harvest the persisted logs), `snapshot-normalize.ts` (the pure golden normalizers), and the ~150-line scenario body plus fixture guards in `acp.snapshot.ts` (record/replay modes, the stdout-golden and log compares, the pinned-header uniformity guard, the orphan/required-file/single-pin meta-tests). diff --git a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md index f80c8e49e8..cda7a578d4 100644 --- a/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md +++ b/docs/rfc/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md @@ -1,9 +1,9 @@ -# RFC:将 ACP 快照套件提取为支持包 - -[English](2026-07-08-shared-acp-snapshot-package.md) | 中文 +# RFC: 将 ACP 快照套件提取为支持包 Status: implemented +[English](2026-07-08-shared-acp-snapshot-package.md) | 中文 + ## 问题 ACP 快照层([快照 RFC](2026-06-19-acp-snapshot-tests.md))由位于某个示例测试目录中的三个模块构成:`snapshot-harness.ts`(启动真实 bin 子进程,通过 ACP JSON-RPC 驱动它,收集持久化日志)、`snapshot-normalize.ts`(纯粹的 golden 规范化器),以及 `acp.snapshot.ts` 中约 150 行的场景主体加 fixture(测试前置数据)守卫(record/replay 模式、stdout-golden 与日志比对、pinned-header 一致性守卫、orphan/required-file/single-pin 元测试)。 diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml index 59f21c938e..b355adb77d 100644 --- a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml @@ -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 -2026-06-16-typed-event-schemas.md: 8d14c3b2d90d8dcf295e122e95267c2c0d7b2a17 -2026-06-16-typed-event-schemas.zh.md: 34f46a87058b409ecdab38d851654db49d87e201 +2026-06-16-typed-event-schemas.md: 93e470218e810c9c9370dd1c7cae5420c93fa7bf +2026-06-16-typed-event-schemas.zh.md: bca4265527507750abe5b8c114f14508cee91cb9 diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md index 8d14c3b2d9..93e470218e 100644 --- a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.md @@ -1,9 +1,9 @@ # RFC: Runtime schemas for the event vocabulary (Zod vs the merge-extensible-map pattern) -English | [中文](2026-06-16-typed-event-schemas.zh.md) - Status: proposed +English | [中文](2026-06-16-typed-event-schemas.zh.md) + ## Problem The harness models its core vocabulary — content blocks, message sources, finish reasons, turn triggers, turn-end reasons, and session events — as **merge-extensible maps**: a TypeScript `interface` (e.g. `SessionEventMap`, `ContentBlockMap`) that plugins augment via declaration merging, with the public union derived as `Map[keyof Map]`. This is the repo's universal extension pattern, documented in [docs/architecture.md](../../../architecture.md) ("The same merge-extensible-map pattern is used for `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`") and relied on by the `defineTool` `InferArgs` DSL and the `assertNever` exhaustiveness convention. diff --git a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md index 34f46a8705..bca4265527 100644 --- a/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md +++ b/docs/rfc/proposed/architecture/2026-06-16-typed-event-schemas.zh.md @@ -1,16 +1,16 @@ -# RFC:事件词汇的运行时 schema(Zod 与 merge-extensible-map 模式之辩) - -[English](2026-06-16-typed-event-schemas.md) | 中文 +# RFC: 事件词汇的运行时 schema(Zod 与 merge-extensible-map 模式之辩) Status: proposed +[English](2026-06-16-typed-event-schemas.md) | 中文 + ## 问题 harness 将其核心词汇——内容块、消息来源、结束原因、轮次触发器、轮次结束原因与会话事件——建模为 **merge-extensible map**:一个 TypeScript `interface`(如 `SessionEventMap`、`ContentBlockMap`),插件通过声明合并对其扩展,公开联合类型则以 `Map[keyof Map]` 派生。这是本仓库的通用扩展模式,记录在 [docs/architecture.md](../../../architecture.md) 中("The same merge-extensible-map pattern is used for `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`"),`defineTool` 的 `InferArgs` DSL 和 `assertNever` 穷举约定都依赖于它。 该模式**仅存在于编译期**。类型在运行时消失:没有 schema 对象可供校验传入值、解析不可信输入或在运行时枚举变体。[会话持久化契约](../../implemented/architecture/2026-06-14-session-persistence.md)暴露了两个后果: -1. **持久化将 `event.data` 视为不透明 JSON。** JSONL/SQLite 后端对每个事件逐字 `JSON.stringify`/`JSON.parse`;唯一的运行时守卫是 `isJsonValue`(往返可序列化性检查:拒绝 BigInt、函数、循环引用、非有限数等),而**非**结构校验。一个损坏但仍为合法 JSON 的事件数据(字段类型错误、字段缺失)会静默往返,只有在后续消费方的 `switch` 中才可能被捕获。 +1. **持久化将 `event.data` 视为不透明 JSON。** JSONL/SQLite 后端对每个事件逐字 `JSON.stringify`/`JSON.parse`;唯一的运行时守卫是 `isJsonValue`(往返可序列化性检查:拒绝 BigInt、函数、循环引用、非有限数等),而非结构校验。一个损坏但仍为合法 JSON 的事件数据(字段类型错误、字段缺失)会静默往返,只有在后续消费方的 `switch` 中才可能被捕获。 2. **插件新增变体没有运行时契约。** 一个通过声明合并添加新 `SessionEventMap` 键的插件,在自身代码中获得了编译期类型,但没有任何机制校验它产出的值是否符合它所声明的形状——无论是在生产者处、持久化边界处还是重新加载时。 由此引出问题:事件词汇是否应迁移到 **Zod** 或其他运行时 schema 库,使持久化和插件边界拥有运行时 schema 而非被擦除的类型。 diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml index 290a729be7..b98f0fa227 100644 --- a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml @@ -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 -2026-06-20-generic-long-running-tool-runtime.md: ea773a651b5aeec87179aac2ed419f176486977f -2026-06-20-generic-long-running-tool-runtime.zh.md: 25c1b282b19bb7da08b552485e348c23b11dcecf +2026-06-20-generic-long-running-tool-runtime.md: 9b83a4443d6d654cda75c72fba3369a16be078e2 +2026-06-20-generic-long-running-tool-runtime.zh.md: c1684be4fd5c1c3c9d913e063f4ba66bb6064459 diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md index ea773a651b..9b83a4443d 100644 --- a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -1,9 +1,9 @@ # RFC: Extract a generic long-running tool runtime -English | [中文](2026-06-20-generic-long-running-tool-runtime.zh.md) - Status: proposed +English | [中文](2026-06-20-generic-long-running-tool-runtime.zh.md) + ## Problem The bash capability seam supports both foreground commands and long-running background tasks. Background support is large: the abstract executor exposes `start`, `get`, `ownerOf`, `list`, `readOutput`, `kill`, and `onTaskDone`; the local executor tracks tasks, incremental reads, owner tokens, process cleanup, and completion listeners; the model sees three tools (`bash`, `bash_output`, `bash_kill`); the tool plugin injects completion notices back into the owning agent's session. The local executor fences task access behind owner tokens because predictable global task ids are a cross-session read/kill hazard. diff --git a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md index 25c1b282b1..c1684be4fd 100644 --- a/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md +++ b/docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md @@ -1,4 +1,4 @@ -# RFC:提取通用的长时间运行工具运行时 +# RFC: 提取通用的长时间运行工具运行时 Status: proposed diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml index ccab930c8f..3412d91229 100644 --- a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml @@ -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 -2026-06-30-pre-tool-input-rewrite.md: add84bfc76434eb25870f09e71860279663d291e -2026-06-30-pre-tool-input-rewrite.zh.md: 13d66208be07992fd414f2984c493557ad1e87a3 +2026-06-30-pre-tool-input-rewrite.md: 85ece78f3bf188b3b702b1af539256747c1cfab2 +2026-06-30-pre-tool-input-rewrite.zh.md: 6a5c2b52627d21476b96448dc120155eab7f2223 diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md index add84bfc76..85ece78f3b 100644 --- a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.md @@ -1,9 +1,9 @@ # RFC: Pre-tool input rewrite — a consistent design -English | [中文](2026-06-30-pre-tool-input-rewrite.zh.md) - Status: proposed +English | [中文](2026-06-30-pre-tool-input-rewrite.zh.md) + ## Problem The [interception-seams RFC](../../implemented/feature/2026-06-30-interception-seams.md) defines `tools/pre-execute` as an allow/deny/ask gate over an execution whose identity is already protected and whose arguments are deeply frozen. Claude Code's `PreToolUse` hook also offers `updatedInput`, so a faithful bridge needs an explicit rewrite mechanism. A rewrite cannot be a mutation escape hatch on the existing execution object: it must keep the durable history, audit record, presentation, and executed value consistent. diff --git a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md index 13d66208be..6a5c2b5262 100644 --- a/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md +++ b/docs/rfc/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md @@ -1,4 +1,4 @@ -# RFC:工具执行前输入重写——一致性设计 +# RFC: 工具执行前输入重写——一致性设计 Status: proposed @@ -10,7 +10,7 @@ Status: proposed ## 问题本质:执行前参数的三个读取方 -在 agent loop(智能体循环)中,工具调用的参数在工具执行**之前**就已提交到日志并被实时消费方读取: +在 agent loop(智能体循环)中,工具调用的参数在工具执行之前就已提交到日志并被实时消费方读取: 1. **`assistant/message`** 在工具分发之前追加——它是 `deriveMessages()` 回放时的模型历史来源,因此携带模型自身输出的工具调用参数。 2. **`tool/call`** 是持久化的审计记录,在 `ctx.tools.execute()` 之前追加。 @@ -22,7 +22,7 @@ Status: proposed 重写是一个「身份标识创建前的一致性事务」。当钩子提供 `updatedInput` 时,有效值必须在注册表构造其不可变的 `ToolExecution` 之前确定,并且必须原子地反映到全部三个读取方: -- `tool/call` 审计事件记录**重写后**的参数(原始参数保留在一个伴随字段中,作为审计线索——钩子修改了调用,原始参数与生效参数都是值得保留的事实)。 +- `tool/call` 审计事件记录重写后的参数(原始参数保留在一个伴随字段中,作为审计线索——钩子修改了调用,原始参数与生效参数都是值得保留的事实)。 - 派生历史中的 `assistant/message` 必须与实际执行一致。待评估的选项:就地重写 assistant 消息中的工具调用块(改变模型「看到自己说了什么」),或记录一条单独的修正让下一次请求携带。Claude Code 的模型是让模型看到重写已生效。 - 展示层(`presentCall`/`presentResult`)读取重写后的参数,使 UI 显示实际运行的内容。 diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml index ab362ca036..e3ec2ad677 100644 --- a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml @@ -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 -2026-07-07-claude-code-and-codex-subagent-backends.md: 1ebf01dd8df0980f6c464be8b27033bdfab942f3 -2026-07-07-claude-code-and-codex-subagent-backends.zh.md: dd26a49962ee46a8ce0965557ff3dbd5805fdcfe +2026-07-07-claude-code-and-codex-subagent-backends.md: 5585ea30a5ba1b4200f096069a28ccf1c3cef727 +2026-07-07-claude-code-and-codex-subagent-backends.zh.md: 2a6dd2cdea34cb777df5455f0bc12dc7073ff2a2 diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md index 1ebf01dd8d..5585ea30a5 100644 --- a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.md @@ -1,9 +1,9 @@ # RFC: Claude Code and Codex subagent backends (out-of-process delegation to external coding agents) -English | [中文](2026-07-07-claude-code-and-codex-subagent-backends.zh.md) - Status: proposed +English | [中文](2026-07-07-claude-code-and-codex-subagent-backends.zh.md) + ## Problem Add isolated subagent providers for Claude Code and Codex. The existing [named-provider seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) and [ACP backend](../../implemented/feature/2026-06-22-acp-subagent-backend.md) establish the process-boundary shape. A harness turn should be able to delegate a self-contained task to either product and receive its final answer without exposing parent secrets or inheriting host configuration from `~/.claude` or `~/.codex`. diff --git a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md index dd26a49962..2a6dd2cdea 100644 --- a/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md +++ b/docs/rfc/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md @@ -1,9 +1,9 @@ -# RFC:Claude Code 与 Codex subagent 后端(向外部编码 agent 的进程外委派) - -[English](2026-07-07-claude-code-and-codex-subagent-backends.md) | 中文 +# RFC: Claude Code 与 Codex subagent 后端(向外部编码 agent 的进程外委派) Status: proposed +[English](2026-07-07-claude-code-and-codex-subagent-backends.md) | 中文 + ## 问题 为 Claude Code 和 Codex 添加隔离的 subagent 提供方。既有的[命名提供方 seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 和 [ACP 后端](../../implemented/feature/2026-06-22-acp-subagent-backend.md)已确立了进程边界的形状。harness 的一个轮次应能将一个自包含任务委派给上述任一产品,并接收其最终答案,同时不暴露父进程的密钥,也不继承来自 `~/.claude` 或 `~/.codex` 的宿主配置。 @@ -12,7 +12,7 @@ Status: proposed 两个兄弟提供方包(ACP 后端的结构变体),加一次提取: -- `@deepseek-ai/dsh-subagent-claude-code`:通过 `@anthropic-ai/claude-agent-sdk` 的 `query()` 驱动一个 Claude Code 子进程(SDK 在父进程中运行,并将其内置的 `claude` CLI 作为子进程 spawn)。提供方名称为 `claude-code`:子进程是 Claude Code 这个**产品**,而非 Anthropic 模型适配器——"claude" 保留给未来的 `dsh-llm` 适配器。 +- `@deepseek-ai/dsh-subagent-claude-code`:通过 `@anthropic-ai/claude-agent-sdk` 的 `query()` 驱动一个 Claude Code 子进程(SDK 在父进程中运行,并将其内置的 `claude` CLI 作为子进程 spawn)。提供方名称为 `claude-code`:子进程是 Claude Code 这个*产品*,而非 Anthropic 模型适配器——"claude" 保留给未来的 `dsh-llm` 适配器。 - `@deepseek-ai/dsh-subagent-codex`:spawn `codex app-server`,通过其 JSON-RPC-over-stdio 协议驱动一个 thread/turn,使用包内一个手写的换行 JSON 客户端(约 200–300 行)。 - `@deepseek-ai/dsh-subagent-process`:纯库(沿用 `subagent-inprocess` 的先例),提取 `dsh-subagent-acp` 已有且两个新后端都需要的内容:凭证环境清洗(`SENSITIVE_ENV_PATTERN`/`buildChildEnv`)、EOF → SIGTERM → SIGKILL 的 dispose 阶梯,以及新的隔离配置目录辅助函数(`mkdtemp` 创建、尽力删除)。ACP 后端迁移到该库上;`bash-local` 的兄弟副本保持不动以限制变更范围。 @@ -22,13 +22,13 @@ Status: proposed 两个集成面在本提案之前均已针对固定版本进行了验证——阅读类型与打包源码、运行无需密钥的 spike——而非仅依赖厂商文档。固定版本是验证基线,不是运行时契约:后端不执行运行时版本探测(无 `codex --version` 门禁、无 SDK 版本嗅探)。兼容性在开发时强制执行——每次依赖升级都会针对真实加载路径重跑无密钥套件——在运行时则通过大声失败来保障:协议层面的意外通过 `onError` 结算为 `error`,绝不静默异常。 -**`@anthropic-ai/claude-agent-sdk` 0.3.202。** `options.env` 会**替换**子进程环境(不与 `process.env` 合并),恰好满足清洗需求。`settingSources` 默认加载所有文件系统设置——隔离要求显式传入 `[]`。结果子类型为 `success` | `error_during_execution` | `error_max_turns` | `error_max_budget_usd` | `error_max_structured_output_retries`。中止时 SDK 自行升级 CLI 子进程:立即关闭 stdin,约 2 秒后若子进程未退出则发送 SIGTERM(已观察到;无残留进程)——无需自定义 kill 回退。`outputFormat: {type: 'json_schema'}` 和 `agents` 选项已存在,为 seam 的 `outputSchema` 能力和命名 subagent 类型提供了未来着陆点;两者均不在本 RFC 范围内。 +**`@anthropic-ai/claude-agent-sdk` 0.3.202。** `options.env` 会替换子进程环境(不与 `process.env` 合并),恰好满足清洗需求。`settingSources` 默认加载所有文件系统设置——隔离要求显式传入 `[]`。结果子类型为 `success` | `error_during_execution` | `error_max_turns` | `error_max_budget_usd` | `error_max_structured_output_retries`。中止时 SDK 自行升级 CLI 子进程:立即关闭 stdin,约 2 秒后若子进程未退出则发送 SIGTERM(已观察到;无残留进程)——无需自定义 kill 回退。`outputFormat: {type: 'json_schema'}` 和 `agents` 选项已存在,为 seam 的 `outputSchema` 能力和命名 subagent 类型提供了未来着陆点;两者均不在本 RFC 范围内。 **codex CLI 0.142.5,`codex app-server`(v2 词汇)。** LF 分隔的 JSON,JSON-RPC 2.0 形状但省略 `"jsonrpc"` 头。 - 生命周期:`initialize{clientInfo}` + `initialized` → `thread/start`(接受 `cwd`、`model`、`sandbox`、`approvalPolicy`、`ephemeral`;未认证即可成功)→ `turn/start{threadId, input:[{type:'text',text}]}` 立即返回一个 `inProgress` 的 turn;终止信号是携带 `Turn{status: completed|interrupted|failed|inProgress, error}` 的 `turn/completed` 通知。 - 审批是服务端发起的请求——`item/commandExecution/requestApproval`、`item/fileChange/requestApproval`、`item/permissions/requestApproval`、`item/tool/requestUserInput`、`mcpServer/elicitation/request`——以 `accept`/`decline` 系列决策应答。 -- 认证:`account/login/start{type:'apiKey', apiKey}` 是一等 RPC,`account/read` 报告 `requiresOpenaiAuth`——且未认证的 `turn/start` 不会快速失败(它会挂在重试中),因此后端**必须**预检认证状态,并在失败时大声结算为 `error`,而非等待 turn。 +- 认证:`account/login/start{type:'apiKey', apiKey}` 是一等 RPC,`account/read` 报告 `requiresOpenaiAuth`——且未认证的 `turn/start` 不会快速失败(它会挂在重试中),因此后端必须预检认证状态,并在失败时大声结算为 `error`,而非等待 turn。 - 隔离:`CODEX_HOME` 重定向被尊重(`initialize` 响应会回显它,测试可据此断言隔离),`ephemeral: true` 的 thread 不留任何会话文件。 ## 隔离与凭证 @@ -43,7 +43,7 @@ Status: proposed Claude Code:`success` → `completed`;`error_max_turns`、`error_during_execution`、`error_max_budget_usd`、`error_max_structured_output_retries` → `error`(与 ACP 对 `max_turn_requests` 的处理对齐:未完成的任务不是成功);生成器中止 → `aborted`;未知值 → `error`。Codex:`Turn.status` 为 `completed` → `completed`;`interrupted` → `aborted`;`failed` 且 `codexErrorInfo: 'contextWindowExceeded'` → `max-tokens`,其他 `failed` → `error`;传输/spawn/认证预检失败 → `error`(若已请求取消则为 `aborted`)。两者中,`cancel()` 采用 ACP 形状:标志位 + abort/interrupt + 一个 cancel-settled 竞争分支,使不合作的子进程无法阻塞结果。 -活性姿态,明确声明:teardown 时序是配置项,turn 时长不是。两个后端将 dispose 阶梯的宽限期作为带默认值的已验证配置字段(ACP 后端的 `disposeEofGraceMs`/`disposeGraceMs` 形状,由提取库承载),但**刻意不设** turn 时长或启动超时——与 ACP 一致:turn 期间的活性由调用方通过 `cancel()`/abort signal 掌控,subagent turn 合理地可达数分钟,而 Codex 认证预检消除了唯一已验证的必然挂起场景;需要墙钟上限的部署从父侧取消即可。 +活性姿态,明确声明:teardown 时序是配置项,turn 时长不是。两个后端将 dispose 阶梯的宽限期作为带默认值的已验证配置字段(ACP 后端的 `disposeEofGraceMs`/`disposeGraceMs` 形状,由提取库承载),但刻意不设 turn 时长或启动超时——与 ACP 一致:turn 期间的活性由调用方通过 `cancel()`/abort signal 掌控,subagent turn 合理地可达数分钟,而 Codex 认证预检消除了唯一已验证的必然挂起场景;需要墙钟上限的部署从父侧取消即可。 ## 测试 @@ -61,7 +61,7 @@ dispose 阶梯和环境清洗要求拥有子进程(spawn 参数、env、信号 ### 为什么不用模型可见的 `subagent_type` 参数(单一 Task 风格工具)? -Claude Code 自身的 Task 工具将 subagent 类型放在模型可见的 schema 中,选择一个 prompt + 工具集人格。这里的选择是在**执行引擎**之间做出的,而只有部署者知道哪些引擎配置了凭证——因此选择留在部署配置层,保持 `dsh-tool-subagent` 文档中的「一个提供方对应一个工具」契约。人格风格的类型选择器应是针对工具的另一个 RFC,而非针对后端。 +Claude Code 自身的 Task 工具将 subagent 类型放在模型可见的 schema 中,选择一个 prompt + 工具集人格。这里的选择是在执行引擎之间做出的,而只有部署者知道哪些引擎配置了凭证——因此选择留在部署配置层,保持 `dsh-tool-subagent` 文档中的「一个提供方对应一个工具」契约。人格风格的类型选择器应是针对工具的另一个 RFC,而非针对后端。 ### 为什么不用登录态凭证和用户自身的配置? diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml index a86bcca889..b7300fc7f3 100644 --- a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml @@ -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 -2026-07-08-interactive-side-sessions.md: 250a906d9ec339399a0e0e29e70b2b8dc189fa72 -2026-07-08-interactive-side-sessions.zh.md: d86a2b69232bc8ccad78555911b44cf727780e0c +2026-07-08-interactive-side-sessions.md: ac29f80b31492ce79512cc4d08e33480e0ac6258 +2026-07-08-interactive-side-sessions.zh.md: 5d0ef101dc23febefec881b12fcbb5ba4dcf8be9 diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md index 250a906d9e..ac29f80b31 100644 --- a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.md @@ -1,9 +1,9 @@ # RFC: Interactive side sessions and merge-back -English | [中文](2026-07-08-interactive-side-sessions.zh.md) - Status: proposed +English | [中文](2026-07-08-interactive-side-sessions.zh.md) + ## Problem A user may want to explore a question from a live session without changing its main context. Existing primitives do not expose that product shape: [session-store fork](../../implemented/feature/2026-06-30-session-store-fork-api.md) creates an unattached session, while [fork subagents](../../implemented/feature/2026-06-21-subagent-capability-seam.md) are model-driven tasks whose transcript collapses into one tool result. Neither gives the user a separate conversation, and neither records a conclusion back into the parent with provenance. diff --git a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md index d86a2b6923..5d0ef101dc 100644 --- a/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md +++ b/docs/rfc/proposed/feature/2026-07-08-interactive-side-sessions.zh.md @@ -1,9 +1,9 @@ -# RFC:交互式侧会话与合并回写 - -[English](2026-07-08-interactive-side-sessions.md) | 中文 +# RFC: 交互式侧会话与合并回写 Status: proposed +[English](2026-07-08-interactive-side-sessions.md) | 中文 + ## 问题 用户可能希望在不改变当前会话主上下文的前提下,探索一个来自活跃会话的问题。现有原语无法提供这种产品形态:[session-store fork](../../implemented/feature/2026-06-30-session-store-fork-api.md) 创建的是一个无关联的会话,而 [fork subagent](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 是模型驱动的任务,其 transcript(文本记录)会折叠为一条工具结果。两者都不能给用户一个独立的对话,也都不能将结论带着出处信息记录回父会话。 diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml index ab712ad131..5a09704cff 100644 --- a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml @@ -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 -2026-07-10-sqlite-session-query-provider.md: 8b67baf420433feca9d5cd09d58852bb9b1545a9 -2026-07-10-sqlite-session-query-provider.zh.md: ad6b44363ab54b66b597941adb13938f27971bd5 +2026-07-10-sqlite-session-query-provider.md: d1901ab0e37e8f92af322facac0cb48988d1ffe7 +2026-07-10-sqlite-session-query-provider.zh.md: 7a86d7294183eec57c3495a182f1403f84c27363 diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md index 8b67baf420..d1901ab0e3 100644 --- a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.md @@ -1,9 +1,9 @@ # RFC: SQLite FTS5 session search -English | [中文](2026-07-10-sqlite-session-query-provider.zh.md) - Status: proposed +English | [中文](2026-07-10-sqlite-session-query-provider.zh.md) + ## Problem The exact-read `ctx.sessionQuery` service deliberately has no derived index. Large persisted histories need full-text search without scanning every event on every query, while current live sessions need an overlay newer than the last durability checkpoint. Search also needs concrete ranking, snippets, filters, pagination, cancellation, and rebuild behavior. diff --git a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md index ad6b44363a..7a86d72941 100644 --- a/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md +++ b/docs/rfc/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md @@ -1,9 +1,9 @@ -# RFC:SQLite FTS5 会话搜索 - -[English](2026-07-10-sqlite-session-query-provider.md) | 中文 +# RFC: SQLite FTS5 会话搜索 Status: proposed +[English](2026-07-10-sqlite-session-query-provider.md) | 中文 + ## 问题 精确读取的 `ctx.sessionQuery` 服务有意不维护派生索引。大规模持久化的历史记录需要全文搜索,而不是每次查询都扫描全部事件;当前的活跃会话则需要一个比上一次持久性检查点更新的覆盖层。搜索还需要具体的排序、摘要片段、过滤、分页、取消以及重建行为。 diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml index a90fafdf8b..802373dd50 100644 --- a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml @@ -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 -2026-07-13-stream-workflow-progress-through-tool-calls.md: 525f2793052a80d82de29d2d370cfd747d002af6 -2026-07-13-stream-workflow-progress-through-tool-calls.zh.md: 8dcb4aea2de50cdd278c702c9f6c85ab66e6be34 +2026-07-13-stream-workflow-progress-through-tool-calls.md: c4fe68974bf774306038e3bd2ba3e29e06de3492 +2026-07-13-stream-workflow-progress-through-tool-calls.zh.md: b6a3ccbc89bebaae92641a10aea9a9a05b38a293 diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md index 525f279305..c4fe68974b 100644 --- a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.md @@ -1,9 +1,9 @@ # RFC: Stream workflow progress through tool calls -English | [中文](2026-07-13-stream-workflow-progress-through-tool-calls.zh.md) - Status: proposed +English | [中文](2026-07-13-stream-workflow-progress-through-tool-calls.zh.md) + ## Problem The workflow engine intentionally emits balanced `workflow/*` observation events for run, phase, narration, and child-agent progress, but no production consumer presents them. Editors therefore show one pending workflow tool card until the final result even while the engine already reports which phase is active, what the script logged, and which children started or settled. The [dynamic-workflows decision](../../implemented/feature/2026-07-05-dynamic-workflows.md) explicitly reserves ACP progress UI for this event stream. diff --git a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md index 8dcb4aea2d..b6a3ccbc89 100644 --- a/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md +++ b/docs/rfc/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md @@ -1,9 +1,9 @@ -# RFC:通过工具调用流式传输工作流进度 - -[English](2026-07-13-stream-workflow-progress-through-tool-calls.md) | 中文 +# RFC: 通过工具调用流式传输工作流进度 Status: proposed +[English](2026-07-13-stream-workflow-progress-through-tool-calls.md) | 中文 + ## 问题 工作流引擎有意为 run、phase、narration 和子 agent(智能体)进度发出成对的 `workflow/*` observation 事件,但目前没有生产消费方呈现这些事件。因此,编辑器在最终结果返回之前只显示一张 pending 状态的工作流工具卡片,尽管引擎已经报告了当前活跃的 phase、脚本日志内容以及哪些子 agent 已启动或已结束。[dynamic-workflows 决策](../../implemented/feature/2026-07-05-dynamic-workflows.md)明确将 ACP(Agent Client Protocol)进度 UI 保留给这一事件流。 diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml index fc5effd89a..f7f98a72bb 100644 --- a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml @@ -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 -2026-06-11-api-extractor-reports.md: 0f3f736ba662fd6366eb8d7f26887fb319b2b563 -2026-06-11-api-extractor-reports.zh.md: cf0eb3f9edbcfb2ae862f075af0628e716693a86 +2026-06-11-api-extractor-reports.md: 26562267d188ab2427075c6fccf0ee4b24d63d99 +2026-06-11-api-extractor-reports.zh.md: 33e80abc6e9689cf90f3c851039144a53418137e diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md index 0f3f736ba6..26562267d1 100644 --- a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.md @@ -1,9 +1,9 @@ # RFC: API extractor reports -English | [中文](2026-06-11-api-extractor-reports.zh.md) - Status: proposed +English | [中文](2026-06-11-api-extractor-reports.zh.md) + > Split out from the original "Doc-sync and API reports" RFC (2026-06-11). Parts 1-2 (doc-block typechecking, event-taxonomy verification) shipped — see [doc-sync enforcement](../../implemented/process/2026-06-11-doc-sync-enforcement.md). This is the deferred part 3, kept as a standalone proposal. ## Problem diff --git a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md index cf0eb3f9ed..33e80abc6e 100644 --- a/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md +++ b/docs/rfc/proposed/process/2026-06-11-api-extractor-reports.zh.md @@ -1,9 +1,9 @@ -# RFC:API extractor 报告 - -[English](2026-06-11-api-extractor-reports.md) | 中文 +# RFC: API extractor 报告 Status: proposed +[English](2026-06-11-api-extractor-reports.md) | 中文 + > 从最初的「Doc-sync 与 API 报告」RFC(2026-06-11)中拆出。第 1–2 部分(文档块类型检查、事件分类体系校验)已交付,见 [doc-sync 强制](../../implemented/process/2026-06-11-doc-sync-enforcement.md)。本文是被推迟的第 3 部分,作为独立提案保留。 ## 问题 diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml index 094c2c349b..b358826e19 100644 --- a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.i18n.yaml @@ -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 -2026-06-11-architectural-conformance.md: 40858d049af2df1928e27280238d0b198a5202f7 -2026-06-11-architectural-conformance.zh.md: b68355dc1c04a4f807efdb95f813159cb7f9f178 +2026-06-11-architectural-conformance.md: aad11b9e4bcbd31465cb0c4a507654971e24e843 +2026-06-11-architectural-conformance.zh.md: 59684bd01a133755a3d7efd90832f6f268037920 diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md index 40858d049a..aad11b9e4b 100644 --- a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.md @@ -1,9 +1,9 @@ # RFC: Architectural conformance — dependency rules and the adapter kit -English | [中文](2026-06-11-architectural-conformance.zh.md) - Status: proposed +English | [中文](2026-06-11-architectural-conformance.zh.md) + ## Problem Two architectural guarantees currently live only in prose: (1) nothing depends on the concrete loop package ([the microkernel promise](../../implemented/architecture/2026-06-11-microkernel-event-taxonomy.md)), and (2) every LlmAdapter speaks the chunk protocol correctly. Both should be mechanical ([the quality-gates principle](../../implemented/process/2026-06-11-quality-gates.md)). diff --git a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md index b68355dc1c..59684bd01a 100644 --- a/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md +++ b/docs/rfc/proposed/process/2026-06-11-architectural-conformance.zh.md @@ -1,9 +1,9 @@ -# RFC:架构一致性——依赖规则与适配器套件 - -[English](2026-06-11-architectural-conformance.md) | 中文 +# RFC: 架构一致性——依赖规则与适配器套件 Status: proposed +[English](2026-06-11-architectural-conformance.md) | 中文 + ## 问题 目前有两项架构保证仅存在于行文中:(1)没有任何东西依赖具体的 loop 包([微内核承诺](../../implemented/architecture/2026-06-11-microkernel-event-taxonomy.md));(2)每个 LlmAdapter 都正确地遵循 chunk 协议。二者都应当是机械化的([质量门禁原则](../../implemented/process/2026-06-11-quality-gates.md))。 diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml index 62e4b4aa6f..7e89d07146 100644 --- a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml @@ -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 -2026-06-11-supply-chain-and-vendor-drift.md: 306e185e9175e3e7af24455cf95167f54b3d1c17 -2026-06-11-supply-chain-and-vendor-drift.zh.md: a840e766c49182d7a9ca648acbbab1a2762688f5 +2026-06-11-supply-chain-and-vendor-drift.md: 97f5a3f999936faf81a67fe69c91f773400cb447 +2026-06-11-supply-chain-and-vendor-drift.zh.md: 0a8441c104ca4779a79b36361ea5d84f5cd09aca diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md index 306e185e91..97f5a3f999 100644 --- a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.md @@ -1,9 +1,9 @@ # RFC: Supply chain checks and vendor drift verification -English | [中文](2026-06-11-supply-chain-and-vendor-drift.zh.md) - Status: proposed +English | [中文](2026-06-11-supply-chain-and-vendor-drift.zh.md) + ## Problem The vendor manifest ([the vendoring decision](../../implemented/process/2026-06-11-vendor-cordis-as-source.md)) is enforced at commit time in the *forward* direction (vendored change ⇒ manifest update) but nothing verifies the manifest's *claims*: that vendor/ actually equals upstream-at-SHA plus exactly the logged modifications. And the handful of true npm dependencies have no advisory monitoring or update cadence. diff --git a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md index a840e766c4..0a8441c104 100644 --- a/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md +++ b/docs/rfc/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md @@ -1,12 +1,12 @@ -# RFC:供应链检查与 vendor 漂移验证 - -[English](2026-06-11-supply-chain-and-vendor-drift.md) | 中文 +# RFC: 供应链检查与 vendor 漂移验证 Status: proposed +[English](2026-06-11-supply-chain-and-vendor-drift.md) | 中文 + ## 问题 -vendor manifest(元数据清单)(见[引入 vendor 的决策](../../implemented/process/2026-06-11-vendor-cordis-as-source.md))在提交时仅在**正向**强制执行(vendor 变更 ⇒ manifest 更新),但没有任何机制验证 manifest 的**声明**:即 vendor/ 确实等于上游指定 SHA 的内容加上所记录的修改。此外,少量真正的 npm 依赖也没有安全公告监控或更新节奏。 +vendor manifest(元数据清单)(见[引入 vendor 的决策](../../implemented/process/2026-06-11-vendor-cordis-as-source.md))在提交时仅在*正向*强制执行(vendor 变更 ⇒ manifest 更新),但没有任何机制验证 manifest 的*声明*:即 vendor/ 确实等于上游指定 SHA 的内容加上所记录的修改。此外,少量真正的 npm 依赖也没有安全公告监控或更新节奏。 ## 提案 diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml index ddaafef6da..678dcb4abe 100644 --- a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml @@ -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 -2026-06-20-discover-package-inventory.md: 22b3e9acbe4dad8ef829d0dd30415c516031d66b -2026-06-20-discover-package-inventory.zh.md: 4eeaed9ed6b390608095281775883f8e7a52e954 +2026-06-20-discover-package-inventory.md: 6729b8ea4386b1595139a2827a95cf3b072e8c94 +2026-06-20-discover-package-inventory.zh.md: 71a6fdf97255932dcff11b574ef7c67ef5a39313 diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md index 22b3e9acbe..6729b8ea43 100644 --- a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md @@ -1,9 +1,9 @@ # RFC: Discover package inventories instead of maintaining static lists -English | [中文](2026-06-20-discover-package-inventory.zh.md) - Status: proposed +English | [中文](2026-06-20-discover-package-inventory.zh.md) + ## Problem Package and gate inventories are repeated across TypeScript project references, package docs, CI prose, Knip overrides, and snapshot scenario metadata. Most restate package layout, manifest data, aggregate command contents, or fixture files. Each new package or scenario therefore creates avoidable synchronization points. diff --git a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md index 4eeaed9ed6..71a6fdf972 100644 --- a/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md +++ b/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.zh.md @@ -1,4 +1,4 @@ -# RFC:通过发现机制获取包清单,而非维护静态列表 +# RFC: 通过发现机制获取包清单,而非维护静态列表 Status: proposed @@ -14,7 +14,7 @@ Status: proposed ## 提案 -让剩余的包/门禁清单可被发现。一个唯一的权威来源——`packages/<group>/<pkg>` 层级结构加上包 manifest(元数据清单)——应当驱动 `tsconfig.build.json` 的 `references`、模块图以及任何全量包列表,并配合一个生成加校验步骤(沿用现有的 `gen-module-graph` / `gen-cordis-catalog` 模式:生成器写出产物,`hygiene`/doc-sync(文档同步门禁)中的 `--check` 模式在提交副本陈旧时报错)。模块图生成已经在读取包 manifest。`doc-sync` 应当成为定义并打印其子门禁的唯一命令,文档链接到该命令而非重述第二份列表。 +让剩余的包/门禁清单可被发现。一个唯一的权威来源——`packages/<group>/<pkg>` 层级结构加上包 manifest(元数据清单)——应当驱动 `tsconfig.build.json` 的 `references`、模块图以及任何全量包列表,并配合一个生成加校验步骤(沿用现有的 `gen-module-graph` / `gen-cordis-catalog` 模式:生成器写出产物,`hygiene`/`doc-sync`(文档同步门禁)中的 `--check` 模式在提交副本陈旧时报错)。模块图生成已经在读取包 manifest。`doc-sync` 应当成为定义并打印其子门禁的唯一命令,文档链接到该命令而非重述第二份列表。 层级结构不需要编码关于包的所有事实,但应当编码宽泛的维护策略:core/product 包、集成包、能力 seam 包与 support/test/example 包不应在脚本能区分它们之前先要求一份手工维护的例外列表。 diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml index dde7a0ad32..1c1c0eb757 100644 --- a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml @@ -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 -2026-06-20-unify-agent-and-session-id.md: 3a6daa411673003eb1c3017e7a717ae4bf98b735 -2026-06-20-unify-agent-and-session-id.zh.md: 6b1b996879125c6ab85aed7ba419aff15d077b42 +2026-06-20-unify-agent-and-session-id.md: 9cec898a2df9418b3533c776779c88fc50bc7dcb +2026-06-20-unify-agent-and-session-id.zh.md: 39e78db0b886d1e0b13afe2337697a184af478ed diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md index 3a6daa4116..9cec898a2d 100644 --- a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.md @@ -1,9 +1,9 @@ # RFC: Unify the agent id and the session id -English | [中文](2026-06-20-unify-agent-and-session-id.zh.md) - Status: proposed +English | [中文](2026-06-20-unify-agent-and-session-id.zh.md) + ## Problem The agent factory carries two ids for each live agent/session pair: `agentId`, the `AgentRegistry` routing handle, and `sessionId`, the event-sourced and persisted-log identity. `CreateAgentOptions` takes both; `ResumeAgentOptions` takes `agentId` plus `resumeSessionId`; in-process subagents mint two independent UUIDs despite recording lineage separately. diff --git a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md index 6b1b996879..39e78db0b8 100644 --- a/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md +++ b/docs/rfc/proposed/simplification/2026-06-20-unify-agent-and-session-id.zh.md @@ -1,9 +1,9 @@ -# RFC:统一 agent id 与 session id - -[English](2026-06-20-unify-agent-and-session-id.md) | 中文 +# RFC: 统一 agent id 与 session id Status: proposed +[English](2026-06-20-unify-agent-and-session-id.md) | 中文 + ## 问题 agent 工厂为每个活跃的 agent/session 对维护两个 id:`agentId`(`AgentRegistry` 的路由句柄)和 `sessionId`(事件溯源与持久化日志的标识)。`CreateAgentOptions` 接收两者;`ResumeAgentOptions` 接收 `agentId` 加 `resumeSessionId`;进程内 subagent 各自铸造两个独立的 UUID,尽管血缘关系另行记录。 diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml index 4420b2dd27..d828a634b5 100644 --- a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml @@ -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 -2026-07-04-prune-dead-core-spine-surface.md: c46fe464e8627dcfc39a1d3fbb38a9cbd84269cf -2026-07-04-prune-dead-core-spine-surface.zh.md: 67e89a580b086a08aed702d9e0b87bdb6e32c944 +2026-07-04-prune-dead-core-spine-surface.md: 59bbfa181a08b998c52ef63afbc63fd5226294a6 +2026-07-04-prune-dead-core-spine-surface.zh.md: 953cb3bc7b30affd505564ac427632732dd9374e diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md index c46fe464e8..59bbfa181a 100644 --- a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md @@ -1,9 +1,9 @@ # RFC: Prune dead public and result surface -English | [中文](2026-07-04-prune-dead-core-spine-surface.zh.md) - Status: proposed +English | [中文](2026-07-04-prune-dead-core-spine-surface.zh.md) + ## Problem Several package-root exports, result fields, and convenience methods have no production consumer. They survive because tests import internals through public entry points or because a type anticipated a caller that never arrived. Each item is small in isolation, but together they enlarge the SDK contract, generated catalogs, documentation, and regression matrix without enabling a shipped path. diff --git a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md index 67e89a580b..953cb3bc7b 100644 --- a/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md +++ b/docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md @@ -1,4 +1,4 @@ -# RFC:裁剪无用的公开与结果接口 +# RFC: 裁剪无用的公开与结果接口 Status: proposed diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml index 2e91f9e9c2..ff2ae238ba 100644 --- a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml @@ -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 -2026-07-12-simplify-session-log-representation.md: 52720231d6e4cbe0cbb412332cd016ba63f83569 -2026-07-12-simplify-session-log-representation.zh.md: 1286a7d3c571fac66310a613c548920c3f25812d +2026-07-12-simplify-session-log-representation.md: dd8e7f319098bcdca9a844f5665583a3aa25ae80 +2026-07-12-simplify-session-log-representation.zh.md: c759b87bbb13903744a8f6bbb139ab71e1c0f39b diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md index 52720231d6..dd8e7f3190 100644 --- a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.md @@ -1,9 +1,9 @@ # RFC: Simplify session-log representation -English | [中文](2026-07-12-simplify-session-log-representation.zh.md) - Status: proposed +English | [中文](2026-07-12-simplify-session-log-representation.zh.md) + ## Problem The session log maintains two representations that cost more machinery than their consumers require: a pseudo-linked surface and custom request-header deltas. diff --git a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md index 1286a7d3c5..c759b87bbb 100644 --- a/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md +++ b/docs/rfc/proposed/simplification/2026-07-12-simplify-session-log-representation.zh.md @@ -1,9 +1,9 @@ -# RFC:简化会话日志表示 - -[English](2026-07-12-simplify-session-log-representation.md) | 中文 +# RFC: 简化会话日志表示 Status: proposed +[English](2026-07-12-simplify-session-log-representation.md) | 中文 + ## 问题 会话日志维护着两种表示,其机制复杂度超出了消费方的实际需求:一个伪链表 surface 和自定义的请求头增量。 diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml index 13dc3e72b9..4c6aa9f685 100644 --- a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml @@ -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 -2026-06-11-deterministic-and-stress-testing.md: e4ed7043d1880b55dd7d77b3e09a81dd58739a70 -2026-06-11-deterministic-and-stress-testing.zh.md: 4e4ee9d28025a43349b702e399096535539a91d2 +2026-06-11-deterministic-and-stress-testing.md: c629567fd16158a0bd081e7e7850fb3e6d5f1631 +2026-06-11-deterministic-and-stress-testing.zh.md: aaa170725f9d3d2457d6f418dce7bc53feda2ab7 diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md index e4ed7043d1..c629567fd1 100644 --- a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.md @@ -1,9 +1,9 @@ # RFC: Deterministic tests, the replay invariant fixture, and race stress -English | [中文](2026-06-11-deterministic-and-stress-testing.zh.md) - Status: proposed +English | [中文](2026-06-11-deterministic-and-stress-testing.zh.md) + ## Problem Several loop tests synchronize with `setTimeout(30)` sleeps — flakiness debt that wastes agent cycles on retries and can mask ordering bugs. Separately, our core architectural promise (any session log replays to identical derived history) is asserted in two tests but is cheap to assert *everywhere*. And the inbox wakeup race was verified by hand exactly once; nothing re-verifies it continuously. diff --git a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md index 4e4ee9d280..aaa170725f 100644 --- a/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md +++ b/docs/rfc/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md @@ -1,12 +1,12 @@ -# RFC:确定性测试、回放不变式 fixture 与竞态压力测试 - -[English](2026-06-11-deterministic-and-stress-testing.md) | 中文 +# RFC: 确定性测试、回放不变式 fixture 与竞态压力测试 Status: proposed +[English](2026-06-11-deterministic-and-stress-testing.md) | 中文 + ## 问题 -若干 agent loop(智能体循环)测试通过 `setTimeout(30)` 睡眠来同步——这是一笔不稳定性债务,浪费 agent 的重试周期,还可能掩盖时序 bug。另外,我们的核心架构承诺(任何会话日志回放后都能得到相同的派生历史)目前只在两个测试中断言,但在**所有**测试中断言的成本极低。此外,inbox 唤醒竞态只被手动验证过一次,没有任何机制持续复验。 +若干 agent loop(智能体循环)测试通过 `setTimeout(30)` 睡眠来同步——这是一笔不稳定性债务,浪费 agent 的重试周期,还可能掩盖时序 bug。另外,我们的核心架构承诺(任何会话日志回放后都能得到相同的派生历史)目前只在两个测试中断言,但在*所有*测试中断言的成本极低。此外,inbox 唤醒竞态只被手动验证过一次,没有任何机制持续复验。 ## 提案 diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml index 3bf5967b45..ce9a12799f 100644 --- a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.i18n.yaml @@ -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 -2026-06-11-mutation-testing.md: 344263d1c91a5e6c83320f367bf76ed6f7ef5a49 -2026-06-11-mutation-testing.zh.md: 28bb7253c12827dbcddd141481f26f60b3a72b7a +2026-06-11-mutation-testing.md: 20b24de385b944c27f4bdc0fc70f335d827f50a0 +2026-06-11-mutation-testing.zh.md: 780d3417cce48ee19ac8e3dc3b74d78b8e2a4c0f diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md index 344263d1c9..20b24de385 100644 --- a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.md @@ -1,9 +1,9 @@ # RFC: Mutation testing as the coverage counterweight -English | [中文](2026-06-11-mutation-testing.zh.md) - Status: proposed +English | [中文](2026-06-11-mutation-testing.zh.md) + ## Problem The per-file 100% coverage gate ([the quality-gates decision](../../implemented/process/2026-06-11-quality-gates.md)) proves every line *executes* under test — not that any assertion would notice if the line were wrong. Under agent-written tests, coverage pressure can produce execution-without-assertion. Mutation testing measures what coverage cannot: whether the suite *kills* deliberately injected bugs. diff --git a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md index 28bb7253c1..780d3417cc 100644 --- a/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md +++ b/docs/rfc/proposed/testing/2026-06-11-mutation-testing.zh.md @@ -1,9 +1,9 @@ -# RFC:变异测试作为覆盖率的制衡手段 - -[English](2026-06-11-mutation-testing.md) | 中文 +# RFC: 变异测试作为覆盖率的制衡手段 Status: proposed +[English](2026-06-11-mutation-testing.md) | 中文 + ## 问题 逐文件 100% 覆盖率门禁([质量门禁决策](../../implemented/process/2026-06-11-quality-gates.md))证明每一行代码在测试中都被*执行*了,但不能证明如果该行出错,任何断言会注意到。在 agent(智能体)编写测试的场景下,覆盖率压力可能产出「执行但不断言」的测试。变异测试衡量的正是覆盖率无法衡量的:测试套件是否能*杀死*被刻意注入的缺陷。 diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml index f7c21ad005..31b046d91a 100644 --- a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml @@ -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 -2026-06-11-immutable-public-surfaces.md: 68472d9817f0de22777314927f05f90949903723 -2026-06-11-immutable-public-surfaces.zh.md: 7dc42ef9ff07682c1bbac1ca61caba49596cb7bc +2026-06-11-immutable-public-surfaces.md: c807b036bb57bd5e64290fd59bf422c4732e9080 +2026-06-11-immutable-public-surfaces.zh.md: 9ff40436915e194848ba163ed80fefe84a1b3da4 diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md index 68472d9817..c807b036bb 100644 --- a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.md @@ -1,9 +1,9 @@ # RFC: Deep-readonly public surfaces -English | [中文](2026-06-11-immutable-public-surfaces.zh.md) - Status: rejected — the pervasive `DeepReadonly<T>` type flip is replaced by source-owned runtime immutability in `Session` plus relational development assertions. See [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md). +English | [中文](2026-06-11-immutable-public-surfaces.zh.md) + ## Problem The rejected proposal targeted an ownership hole that a `readonly SessionEvent[]` type alone cannot close: its elements remain mutable at runtime, so a cast or plain JavaScript can rewrite nested history. The implemented design closes that hole in `Session` by materializing and deep-freezing every accepted event and returning frozen array snapshots. In-flight prompt waterfalls remain intentionally transformable, so immutability is an ownership boundary rather than a blanket type rule. diff --git a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md index 7dc42ef9ff..9ff4043691 100644 --- a/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md +++ b/docs/rfc/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md @@ -1,9 +1,9 @@ -# RFC:深度只读的公开接口 +# RFC: 深度只读的公开接口 + +Status: rejected — the pervasive `DeepReadonly<T>` type flip is replaced by source-owned runtime immutability in `Session` plus relational development assertions. See [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md). [English](2026-06-11-immutable-public-surfaces.md) | 中文 -Status: rejected — 全面使用 `DeepReadonly<T>` 类型翻转的方案已被替换为 `Session` 中由源拥有的运行时不可变性加关系型开发断言。见[源拥有的会话不可变性与开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md)。 - ## 问题 被否决的提案针对的是一个所有权漏洞:仅靠 `readonly SessionEvent[]` 类型无法封堵该漏洞,因为其元素在运行时仍然可变,类型强制转换或纯 JavaScript 代码可以改写嵌套的历史记录。已实现的设计在 `Session` 中封堵了这一漏洞:对每个被接受的事件进行物化并深度冻结,返回冻结的数组快照。进行中的 prompt waterfall(瀑布式事件)有意保持可变换,因此不可变性是一条所有权边界,而非一条全局类型规则。 @@ -14,7 +14,7 @@ Status: rejected — 全面使用 `DeepReadonly<T>` 类型翻转的方案已被 在类型层面为「突变即损坏」的场景引入不可变性: -- `SessionEvent` 数据在从会话**输出**时(`events`、`session/event` 监听器)变为 `DeepReadonly`;`append()` 仍接受普通可变输入。一个 `DeepReadonly<T>` 工具类型放在 dsh-llm 中,与 brand/never 辅助类型相邻。 +- `SessionEvent` 数据在从会话输出时(`events`、`session/event` 监听器)变为 `DeepReadonly`;`append()` 仍接受普通可变输入。一个 `DeepReadonly<T>` 工具类型放在 dsh-llm 中,与 brand/never 辅助类型相邻。 - `deriveMessages()` 返回深度只读的消息;agent loop(智能体循环)在将可变请求交给 `agent/request` waterfall 之前先克隆(该处的突变是被允许的——克隆使边界显式且代价低廉,每个步骤仅一次)。 - `PromptAssembly` 在其 waterfall 流经期间保持可变(被允许),但注册表内部的 section 列表在每次组装时被克隆(已有此行为)。 diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml index 11ed0efa0b..e4d9370aa8 100644 --- a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml @@ -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 -2026-06-20-providerless-example-base.md: be5122ec6665dcea15619f3cb4b3ed3a2fa03972 -2026-06-20-providerless-example-base.zh.md: f01451f719f0fe1bbb50806aea40086e7fe08350 +2026-06-20-providerless-example-base.md: ca9d391172067aca980b5b0fbc17141320c6839e +2026-06-20-providerless-example-base.zh.md: fb64e4a0b5295e0d56e7cd598c230f56219ba77e diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md index be5122ec66..ca9d391172 100644 --- a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.md @@ -1,9 +1,9 @@ # RFC: Make the shared example base providerless -English | [中文](2026-06-20-providerless-example-base.zh.md) - Status: rejected — superseded by [Extract example apps into packages](../../implemented/architecture/2026-06-20-extract-example-app-packages.md), which moves the spine into a `dsh-agent-spine-demo` bundle and deletes the `base*.yml` files, so there is no shared base YAML left to rename. +English | [中文](2026-06-20-providerless-example-base.zh.md) + ## Problem The examples had two shared base files: `examples/base-core.yml` was providerless, while `examples/base.yml` included that core plus the real `llm-deepseek` adapter. Snapshot replay needs the providerless core with `llm-replay`, because loading the real adapter without a key throws. The normal demos need the real adapter. The result was a naming inversion: the file named `base.yml` was not the reusable base for all examples, while the true base was `base-core.yml`. diff --git a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md index f01451f719..fb64e4a0b5 100644 --- a/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md +++ b/docs/rfc/rejected/architecture/2026-06-20-providerless-example-base.zh.md @@ -1,9 +1,9 @@ -# RFC:使共享示例基础配置与提供方无关 - -[English](2026-06-20-providerless-example-base.md) | 中文 +# RFC: 使共享示例基础配置与提供方无关 Status: rejected — superseded by [Extract example apps into packages](../../implemented/architecture/2026-06-20-extract-example-app-packages.md), which moves the spine into a `dsh-agent-spine-demo` bundle and deletes the `base*.yml` files, so there is no shared base YAML left to rename. +[English](2026-06-20-providerless-example-base.md) | 中文 + ## 问题 示例曾有两个共享基础文件:`examples/base-core.yml` 与提供方无关,而 `examples/base.yml` 在该核心基础上加入了真实的 `llm-deepseek` 适配器。快照回放需要与提供方无关的核心配合 `llm-replay` 使用,因为在没有密钥的情况下加载真实适配器会抛出异常。常规演示则需要真实适配器。结果是命名与实际含义倒挂:名为 `base.yml` 的文件并非所有示例可复用的基础,而真正的基础反倒是 `base-core.yml`。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml index ec03777980..c203585372 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml @@ -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 -2026-06-20-assembled-assistant-messages-only.md: 7605f286cf5914a127f5f8e2b77490648b42cc30 -2026-06-20-assembled-assistant-messages-only.zh.md: 05f15ffadba4607bc64fdf2f7eefdbcc41cf03a3 +2026-06-20-assembled-assistant-messages-only.md: 48f45ba08f77e2efd79bd999e262afad313bbdfe +2026-06-20-assembled-assistant-messages-only.zh.md: 44d94b3bc3d9c9f0f6c3bb8a2554664c4f5f5c59 diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md index 7605f286cf..48f45ba08f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.md @@ -1,9 +1,9 @@ # RFC: Persist assembled assistant messages, not stream chunks -English | [中文](2026-06-20-assembled-assistant-messages-only.zh.md) - Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement. +English | [中文](2026-06-20-assembled-assistant-messages-only.zh.md) + ## Problem The canonical session log currently persists every `assistant/chunk` exactly as streamed by the model. The [session persistence RFC](../../implemented/architecture/2026-06-14-session-persistence.md) chose this for token-level replay fidelity and contiguous `seq`, but the cost has grown: JSONL fixtures are dominated by tiny delta records, snapshot scenarios replay the model by grouping chunk events, ACP load reconstructs prior assistant output from chunks, and any future log reader must distinguish durable message history from token-level trace. diff --git a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md index 05f15ffadb..44d94b3bc3 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md @@ -1,9 +1,9 @@ -# RFC:仅持久化组装后的 assistant 消息,不存储流式分片 - -[English](2026-06-20-assembled-assistant-messages-only.md) | 中文 +# RFC: 仅持久化组装后的 assistant 消息,不存储流式分片 Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement. +[English](2026-06-20-assembled-assistant-messages-only.md) | 中文 + ## 问题 当前的规范会话日志会持久化模型流式输出的每一个 `assistant/chunk`。[会话持久化 RFC](../../implemented/architecture/2026-06-14-session-persistence.md) 选择这一方案是为了 token 级别的回放保真度和连续的 `seq`,但其代价日益增长:JSONL fixture(测试前置数据)被大量微小的 delta 记录占据,快照场景通过分组 chunk 事件来回放模型,ACP(Agent Client Protocol)加载时从 chunk 重建先前的 assistant 输出,而任何未来的日志读取方都必须区分持久的消息历史与 token 级别的追踪。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml index 35f0ecedd9..764ea5f4e9 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml @@ -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 -2026-06-20-drop-acp-session-load.md: 39f24d313db6083db45ff6fbc4a84f504e7714cb -2026-06-20-drop-acp-session-load.zh.md: b7339f492d5f6b7e2daab5820dada0fa2b5fe823 +2026-06-20-drop-acp-session-load.md: 93a2791d10b589cfdee5ecc48922722fe27c1c8a +2026-06-20-drop-acp-session-load.zh.md: 94de0a5aa0436dbee8e78fc2dd6de72c98216768 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md index 39f24d313d..93a2791d10 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.md @@ -1,9 +1,9 @@ # RFC: Drop ACP session/load until resume has a product shape -English | [中文](2026-06-20-drop-acp-session-load.zh.md) - Status: rejected — Zed is the current target ACP client, advertises and exercises load-capable sessions, and keeps pending-load state for concurrent `session/load`. The bridge should keep `session/load` and make the resume contract solid. +English | [中文](2026-06-20-drop-acp-session-load.zh.md) + ## Problem ACP advertises `loadSession: true` and implements `session/load` by injecting persistence into the bridge, validating cwd against stored metadata, reconstructing an agent from the persisted log, and replaying prior transcript updates to the client. That path has its own race handling, loading-id guard, replay presenter logic, and tests. It also depends on the canonical log retaining enough UI data to reconstruct old chunks and tool presentations. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md index b7339f492d..94de0a5aa0 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md @@ -1,9 +1,9 @@ -# RFC:移除 ACP session/load,直到 resume 具备产品形态 +# RFC: 移除 ACP session/load,直到 resume 具备产品形态 + +Status: rejected — Zed is the current target ACP client, advertises and exercises load-capable sessions, and keeps pending-load state for concurrent `session/load`. The bridge should keep `session/load` and make the resume contract solid. [English](2026-06-20-drop-acp-session-load.md) | 中文 -Status: rejected — Zed 是当前目标 ACP 客户端,它声明并使用支持 load 的会话,且为并发 `session/load` 维护 pending-load 状态。bridge 应保留 `session/load` 并使 resume 契约更加稳固。 - ## 问题 ACP(Agent Client Protocol)声明 `loadSession: true` 并实现 `session/load`:向 bridge 注入持久化能力、校验 cwd 与存储元数据的一致性、从持久化日志重建 agent(智能体),并向客户端回放先前的 transcript(文本记录)更新。该路径有自己的竞态处理、loading-id 守卫、回放展示逻辑和测试。它还依赖规范日志保留足够的 UI 数据,以重建旧的分片和工具展示。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml index 16827c901b..81bb11c433 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml @@ -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 -2026-06-20-drop-acp-terminal-meta.md: 4ae3b31824ece850da0ddbc004e97b21e3cb9aad -2026-06-20-drop-acp-terminal-meta.zh.md: f5b3e0a4e1f37445a0b0dcbf7426806a1de89763 +2026-06-20-drop-acp-terminal-meta.md: e52187d9786ed44ef4b60aedf5396c19a2e8e872 +2026-06-20-drop-acp-terminal-meta.zh.md: a5f4d7bc1f9d3d050c23990e89610d3eaed5bf70 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md index 4ae3b31824..e52187d978 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.md @@ -1,9 +1,9 @@ # RFC: Drop ACP terminal `_meta` rendering -English | [中文](2026-06-20-drop-acp-terminal-meta.zh.md) - Status: rejected — Zed is the current target client, and the terminal `_meta` convention is intentional Zed UX with a plain ACP fallback for other clients. +English | [中文](2026-06-20-drop-acp-terminal-meta.zh.md) + ## Problem The ACP bridge implements a Zed-specific terminal-card convention through `_meta.terminal_info`, `_meta.terminal_output`, and `_meta.terminal_exit`. The implemented [rich ACP bash rendering RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) deliberately avoided ACP's client-side `terminal/create` because bash execution belongs in the harness, but still adopted the reference agents' display-only `_meta` convention. That gives a nicer Zed card at the cost of bridge state, capability negotiation, terminal ids, special update mapping, text fallback tests, and exit-pill parsing in `dsh-tool-bash`. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md index f5b3e0a4e1..a5f4d7bc1f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md @@ -1,9 +1,9 @@ -# RFC:移除 ACP 终端 `_meta` 渲染 +# RFC: 移除 ACP 终端 `_meta` 渲染 + +Status: rejected — Zed is the current target client, and the terminal `_meta` convention is intentional Zed UX with a plain ACP fallback for other clients. [English](2026-06-20-drop-acp-terminal-meta.md) | 中文 -Status: rejected — Zed 是当前目标客户端,终端 `_meta` 约定是有意为之的 Zed UX 设计,同时为其他客户端提供纯 ACP(Agent Client Protocol)回退路径。 - ## 问题 ACP 桥接层通过 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit` 实现了一套 Zed 特有的终端卡片约定。已实现的[富 ACP bash 渲染 RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 刻意回避了 ACP 客户端侧的 `terminal/create`(因为 bash 执行属于 harness 职责),但仍采用了参考 agent(智能体)的纯展示 `_meta` 约定。这在 Zed 中带来了更好的卡片效果,代价是桥接状态、能力协商、终端 id、特殊的 update 映射、文本回退测试,以及 `dsh-tool-bash` 中的 exit-pill 解析。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml index de324b8de2..304c4a62ac 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml @@ -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 -2026-06-20-drop-bash-output-spill-files.md: bbc26c645cefb1659012ca0debda78fc6850d276 -2026-06-20-drop-bash-output-spill-files.zh.md: 43b6029a68542d03027b61424a2a3024ace200d5 +2026-06-20-drop-bash-output-spill-files.md: 939f99072eace71405ae96e270d5438e75713c1c +2026-06-20-drop-bash-output-spill-files.zh.md: 4a868b1971dc3abcb4a9d0442ffc6e74f5246d00 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md index bbc26c645c..939f99072e 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.md @@ -1,9 +1,9 @@ # RFC: Drop bash full-output spill files -English | [中文](2026-06-20-drop-bash-output-spill-files.zh.md) - Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output. +English | [中文](2026-06-20-drop-bash-output-spill-files.zh.md) + ## Problem `dsh-bash-local` keeps bounded in-memory output and spills large stdout/stderr streams into private temp files. That requires a private directory, random owner-only file creation, close-failure handling, byte-offset incremental reads, lossy read reporting, path rendering in model-facing text, and cleanup discipline. The tool then tells the model to read a local spill path when output was truncated. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md index 43b6029a68..4a868b1971 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md @@ -1,9 +1,9 @@ -# RFC:移除 bash 完整输出溢出文件 - -[English](2026-06-20-drop-bash-output-spill-files.md) | 中文 +# RFC: 移除 bash 完整输出溢出文件 Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output. +[English](2026-06-20-drop-bash-output-spill-files.md) | 中文 + ## 问题 `dsh-bash-local` 在内存中保留有界的输出,并将大体量的 stdout/stderr 流溢出到私有临时文件。这要求一个私有目录、仅所有者可写的随机文件创建、关闭失败处理、基于字节偏移的增量读取、有损读取报告、在面向模型的文本中渲染路径,以及清理纪律。当输出被截断时,该工具会告知模型去读取一个本地溢出路径。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml index 7396bcf5aa..131544ab6d 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml @@ -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 -2026-06-20-drop-durable-step-boundaries.md: fba8ad4211db69d3a04d253fd9544caca0f538c6 -2026-06-20-drop-durable-step-boundaries.zh.md: e389c5506b03a472c74853f3b73c21681f96287f +2026-06-20-drop-durable-step-boundaries.md: 16fdf17c3bc8907745df17e8a105d7978eafb274 +2026-06-20-drop-durable-step-boundaries.zh.md: 5613a84d5f1b5cf87109a2e04a4cb350ffd650a8 diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md index fba8ad4211..16fdf17c3b 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.md @@ -1,9 +1,9 @@ # RFC: Drop durable step boundary events -English | [中文](2026-06-20-drop-durable-step-boundaries.zh.md) - Status: rejected — `step/end` is the durable indication that a model step finished, and keeping the symmetric `step/start` / `step/end` pair makes crash repair, invariants, and transcript inspection clearer than inferring completion from adjacent step-scoped events. +English | [中文](2026-06-20-drop-durable-step-boundaries.zh.md) + ## Problem The session log stores `step/start` and `step/end` events even though every step-scoped event already carries `{ turn, step }`: assistant chunks, assistant messages, tool calls, tool results, usage, and errors. `deriveMessages()` ignores step boundaries, ACP ignores them for UI, and the main consumers are invariants, tests, snapshot goldens, and crash repair. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md index e389c5506b..5613a84d5f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md @@ -1,4 +1,4 @@ -# RFC:移除持久化的步骤边界事件 +# RFC: 移除持久化的步骤边界事件 Status: rejected — `step/end` is the durable indication that a model step finished, and keeping the symmetric `step/start` / `step/end` pair makes crash repair, invariants, and transcript inspection clearer than inferring completion from adjacent step-scoped events. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml index f2aab138ee..3302d9bef1 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml @@ -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 -2026-06-20-drop-unused-session-lineage.md: 4200532726a27e257e09f927240846f20a0b30ad -2026-06-20-drop-unused-session-lineage.zh.md: 1524987111f12a9c6e2014723bb1cb4c87bcf940 +2026-06-20-drop-unused-session-lineage.md: 5f76baf33fa50fc1aff9a0ab43262f063aa8e51b +2026-06-20-drop-unused-session-lineage.zh.md: 79decbb40d93f0798189d4a131197db132549f1c diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md index 4200532726..5f76baf33f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.md @@ -1,9 +1,9 @@ # RFC: Drop unused session lineage metadata -English | [中文](2026-06-20-drop-unused-session-lineage.zh.md) - Status: rejected — `parentSession` is part of the documented fork/sub-agent seam and is already preserved by the agent/session resume path. The field is future-facing, but it is not accidental dead state. +English | [中文](2026-06-20-drop-unused-session-lineage.zh.md) + ## Problem `SessionHeader.parentSession` records the session a new session was forked from. It is defined in `dsh-session`, preserved by persistence backends, copied through resume, documented as lineage metadata, and covered by round-trip tests. The repo has no production fork UI or sub-agent flow that reads it. The planned sub-agent/fork seam is still a TODO, so the field is currently stored future shape. diff --git a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md index 1524987111..79decbb40d 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md @@ -1,9 +1,9 @@ -# RFC:移除未使用的会话血缘元数据 +# RFC: 移除未使用的会话血缘元数据 + +Status: rejected — `parentSession` is part of the documented fork/sub-agent seam and is already preserved by the agent/session resume path. The field is future-facing, but it is not accidental dead state. [English](2026-06-20-drop-unused-session-lineage.md) | 中文 -Status: rejected — `parentSession` 是已文档化的 fork/subagent seam 的一部分,且已被 agent(智能体)/session 恢复路径保留。该字段面向未来,但并非意外的死状态。 - ## 问题 `SessionHeader.parentSession` 记录新会话从哪个会话 fork 而来。它在 `dsh-session` 中定义,被持久化后端保留,在恢复流程中复制,作为血缘元数据被文档记录,并有往返测试覆盖。然而仓库中没有任何生产环境的 fork UI 或 subagent 流程读取它。计划中的 subagent/fork seam 仍是 TODO,因此该字段目前只是预存的未来形状。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml index 8442da7f7e..adb3407f9f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml @@ -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 -2026-06-20-fold-session-persistence-interface.md: 695cd679c67f3e0a9f901c671c33e9507ecbe279 -2026-06-20-fold-session-persistence-interface.zh.md: 38f79f833fb5d95e4d9f392de627ee16b17cb997 +2026-06-20-fold-session-persistence-interface.md: 3e9bb277ccd0b6319081cd1aac289db764f41e58 +2026-06-20-fold-session-persistence-interface.zh.md: 13a8945fcaa5529f6d4dc156b0dc1016ab6da62d diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md index 695cd679c6..3e9bb277cc 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.md @@ -1,9 +1,9 @@ # RFC: Fold the persistence interface into dsh-session -English | [中文](2026-06-20-fold-session-persistence-interface.zh.md) - Status: rejected — the separate persistence interface package is the intended modular capability seam for durable backends. Folding it into `dsh-session` would reduce package count at the cost of a cleaner backend boundary. +English | [中文](2026-06-20-fold-session-persistence-interface.zh.md) + ## Problem `dsh-session-persistence` is an interface package whose main concepts are already owned by `dsh-session`: `SessionHeader`, `SessionEvent`, `SessionId`, `session/event`, and `session/flush`. The package adds the abstract `SessionPersistence` service, the shared write coordinator, and contract helpers. Backend packages depend on it, and `agent-loop` has to optionally find a sibling service for resume. diff --git a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md index 38f79f833f..13a8945fca 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md @@ -1,4 +1,4 @@ -# RFC:将持久化接口合并进 dsh-session +# RFC: 将持久化接口合并进 dsh-session Status: rejected — the separate persistence interface package is the intended modular capability seam for durable backends. Folding it into `dsh-session` would reduce package count at the cost of a cleaner backend boundary. diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml index 3af32eacdd..83244e5741 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml @@ -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 -2026-06-20-generic-tool-rendering.md: 07102ed3b12d7f587b1d12f0e240c1202a2e1cdd -2026-06-20-generic-tool-rendering.zh.md: d2c8c745f0ac04a01eb72b50fd1b63cb655afe36 +2026-06-20-generic-tool-rendering.md: 77d06968a24211835d1ff5db2541efdeb8227878 +2026-06-20-generic-tool-rendering.zh.md: ab032864a5304d6781d990d1f805fe9d280c1655 diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md index 07102ed3b1..77d06968a2 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.md @@ -1,9 +1,9 @@ # RFC: Collapse tool-owned UI presentation -English | [中文](2026-06-20-generic-tool-rendering.zh.md) - Status: rejected — tool-owned presentation should wait for more real tools before being generalized or deleted. Bash and ACP currently need the existing richer presentation path. +English | [中文](2026-06-20-generic-tool-rendering.zh.md) + ## Problem Tools can define `presentCall()` and `presentResult()` callbacks that return `ToolCallPresentation`, `ToolResultPresentation`, and optional `ToolTerminal` fields. The code itself flags the design as muddy: title, kind, raw input, content, terminal cwd, terminal output, exit code, and signal grew incrementally into a bag of optional fields. ACP then maintains pending call state to pair a result with the original args, creates replay-only presenters on `session/load`, and maps terminal subfields into Zed-specific `_meta`. `dsh-tool-bash` even parses exit status back out of rendered text because the pure replay-safe presenter no longer has the structured `BashRunResult`. diff --git a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md index d2c8c745f0..ab032864a5 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md @@ -1,9 +1,9 @@ -# RFC:收拢工具自有的 UI 展示逻辑 - -[English](2026-06-20-generic-tool-rendering.md) | 中文 +# RFC: 收拢工具自有的 UI 展示逻辑 Status: rejected — tool-owned presentation should wait for more real tools before being generalized or deleted. Bash and ACP currently need the existing richer presentation path. +[English](2026-06-20-generic-tool-rendering.md) | 中文 + ## 问题 工具可以定义 `presentCall()` 和 `presentResult()` 回调,返回 `ToolCallPresentation`、`ToolResultPresentation` 以及可选的 `ToolTerminal` 字段。代码本身就标记了这个设计的混乱:title、kind、raw input、content、terminal cwd、terminal output、exit code 和 signal 逐步增长为一堆可选字段。ACP(Agent Client Protocol)随后维护 pending call 状态以将 result 与原始 args 配对,在 `session/load` 时创建仅用于回放的 presenter,并将 terminal 子字段映射为 Zed 特有的 `_meta`。`dsh-tool-bash` 甚至从渲染后的文本中反向解析退出状态,因为纯回放安全的 presenter 已经拿不到结构化的 `BashRunResult`。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml index a944072e9f..96425f0390 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml @@ -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 -2026-06-20-retire-mid-turn-steering.md: bf78125ec175aa9152789bdccd1f8e8a16863a5b -2026-06-20-retire-mid-turn-steering.zh.md: a56e112df37bdeb75ca808f76beabe1fec8b1b7b +2026-06-20-retire-mid-turn-steering.md: 2c4d686942d2bfa8016bb60d55624dc59a933c1a +2026-06-20-retire-mid-turn-steering.zh.md: 2196d7d1d1f1bff39e8e0f03cf9910ab41434d2a diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md index bf78125ec1..2c4d686942 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.md @@ -1,9 +1,9 @@ # RFC: Retire mid-turn steering -English | [中文](2026-06-20-retire-mid-turn-steering.zh.md) - Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. +English | [中文](2026-06-20-retire-mid-turn-steering.zh.md) + ## Problem The agent exposes two user-message paths that look close but have different lifecycle semantics: `send()` queues a normal user turn, while `steer()` injects a message between steps of the currently running turn and falls back to `send()` when idle. That distinction leaks through the whole stack: `Agent.steer()` is public API, the session log has a durable `steering/message` event, the agent event taxonomy has `agent/steering`, the loop maintains a steering FIFO beside the queued-message FIFO, cancellation clears both queues, and `deriveMessages()` has to render steering as a tagged synthetic user message rather than a normal prompt. diff --git a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md index a56e112df3..2196d7d1d1 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md @@ -1,9 +1,9 @@ -# RFC:移除轮次中途引导 - -[English](2026-06-20-retire-mid-turn-steering.md) | 中文 +# RFC: 移除轮次中途引导 Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. +[English](2026-06-20-retire-mid-turn-steering.md) | 中文 + ## 问题 agent(智能体)暴露了两条用户消息路径,外观相近但生命周期语义不同:`send()` 将一条普通用户轮次排入队列,而 `steer()` 在当前运行轮次的步骤之间注入一条消息,空闲时则回退为 `send()`。这一区分贯穿整个栈:`Agent.steer()` 是公开 API;会话日志有持久化的 `steering/message` 事件;agent 事件分类体系有 `agent/steering`;agent loop(智能体循环)在排队消息 FIFO 之外还维护一个 steering FIFO;取消操作需要清空两个队列;`deriveMessages()` 必须将 steering 渲染为带标签的合成用户消息,而非普通提示词。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml index 57044817c0..b3e62c79cd 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml @@ -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 -2026-06-20-single-session-acp-bridge.md: b7b52ca4df2d118358303745f4484e3e40a242b3 -2026-06-20-single-session-acp-bridge.zh.md: bd287f79475433e4d5e502ef30abd5d14410e633 +2026-06-20-single-session-acp-bridge.md: 8aa8f5d605154f697086dd5d432bbe9bd79c5dcd +2026-06-20-single-session-acp-bridge.zh.md: a056bc5acfab9d48259670170a964e8358df866c diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md index b7b52ca4df..8aa8f5d605 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.md @@ -1,9 +1,9 @@ # RFC: Return the ACP bridge to one live session per connection -English | [中文](2026-06-20-single-session-acp-bridge.zh.md) - Status: rejected — Zed is the current target ACP client and its ACP implementation is explicitly multi-session: it stores live sessions in a `HashMap<SessionId, AcpSession>`, tracks `pending_sessions`, joins concurrent loads for the same id, and tests close-during-load behavior. +English | [中文](2026-06-20-single-session-acp-bridge.zh.md) + ## Problem The ACP bridge now supports multiple live sessions on one JSON-RPC connection. That capability brings multi-entry session maps, reverse session/agent lookups, per-session prompt state, loading ids, demux for every event, cross-session teardown, and isolation concerns for future permission prompts and background tasks. The older [multi-session ACP proposal](../../implemented/feature/2026-06-14-acp-multi-session.md) still tracks the unfinished permission-ownership piece; this RFC is the competing simplification path. diff --git a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md index bd287f7947..a056bc5acf 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md @@ -1,9 +1,9 @@ -# RFC:将 ACP 桥接恢复为每连接一个活跃会话 +# RFC: 将 ACP 桥接恢复为每连接一个活跃会话 + +Status: rejected — Zed is the current target ACP client and its ACP implementation is explicitly multi-session: it stores live sessions in a `HashMap<SessionId, AcpSession>`, tracks `pending_sessions`, joins concurrent loads for the same id, and tests close-during-load behavior. [English](2026-06-20-single-session-acp-bridge.md) | 中文 -Status: rejected — Zed 是当前目标 ACP 客户端,其 ACP 实现明确支持多会话:它将活跃会话存储在 `HashMap<SessionId, AcpSession>` 中,跟踪 `pending_sessions`,对同一 id 的并发加载进行合并,并测试加载期间关闭的行为。 - ## 问题 ACP(Agent Client Protocol)桥接现在支持在一条 JSON-RPC 连接上承载多个活跃会话。这一能力带来了多条目会话映射、反向会话/agent(智能体)查找、逐会话的 prompt 状态、加载中 id、每条事件的解复用、跨会话拆除,以及未来权限提示与后台任务的隔离问题。较早的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)仍在追踪未完成的权限归属部分;本 RFC 是与之竞争的简化路径。 diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml index 19a66353c7..1c341c252c 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml @@ -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 -2026-06-20-truncate-interrupted-turns.md: e17cb20f0185fe5d47d0a5ca18b7a389951fbadd -2026-06-20-truncate-interrupted-turns.zh.md: 48aeae650f867fb4629db33a448dd6cbaea60ae0 +2026-06-20-truncate-interrupted-turns.md: dd8475771fcd9fdd0910bd37480a50679e87911c +2026-06-20-truncate-interrupted-turns.zh.md: 7fcd7292c8c53ebf4d784cdb79a1be58960f763c diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md index e17cb20f01..dd8475771f 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.md @@ -1,9 +1,9 @@ # RFC: Truncate interrupted final turns on load -English | [中文](2026-06-20-truncate-interrupted-turns.zh.md) - Status: rejected — a single turn can contain substantial real work, including many steps and large tool output. Preserving interrupted turns is preferable to silently dropping that tail on load. +English | [中文](2026-06-20-truncate-interrupted-turns.zh.md) + ## Problem The current persistence contract preserves a final turn that was durably written but never closed. On load, `interruptedTurnClosers()` scans the tail, synthesizes error `tool/result` events for unanswered tool calls, appends a `step/end` when a step is open, appends `turn/end { kind: 'interrupted' }`, and asks the backend to durably commit that repair. The coordinator, JSONL backend, SQLite backend, session event vocabulary, invariants, docs, and tests all model this synthetic close path. diff --git a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md index 48aeae650f..7fcd7292c8 100644 --- a/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md +++ b/docs/rfc/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md @@ -1,4 +1,4 @@ -# RFC:加载时截断被中断的最终轮次 +# RFC: 加载时截断被中断的最终轮次 Status: rejected — a single turn can contain substantial real work, including many steps and large tool output. Preserving interrupted turns is preferable to silently dropping that tail on load. diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml index 915d56d0e8..cd0677dac6 100644 --- a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml @@ -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 -2026-07-04-prune-unimplemented-subagent-vocabulary.md: 3c86f11564d85b423fe59d784c6bf69959fb3907 -2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: 84ff6f15ff2c9b3a13240997ab3c7b5cf2ab7263 +2026-07-04-prune-unimplemented-subagent-vocabulary.md: 1621bc1feee8bf98478242f002d9d1dca16878f5 +2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: b26ffee4764cd5a5937ef0436fa30c7c0eeba87a diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md index 3c86f11564..1621bc1fee 100644 --- a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md @@ -1,9 +1,9 @@ # RFC: Prune the unimplemented subagent seam vocabulary -English | [中文](2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md) - Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below stands as the record of what is currently unimplemented. +English | [中文](2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md) + ## Problem The [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) shipped a two-tier capability design: start-time capability flags checked by the service, and optional runtime methods on `SubagentRun`. Three start-time features and both optional runtime methods have zero implementations and zero callers: diff --git a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md index 84ff6f15ff..b26ffee476 100644 --- a/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md +++ b/docs/rfc/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md @@ -1,9 +1,9 @@ -# RFC:裁剪未实现的 subagent seam 词汇 - -[English](2026-07-04-prune-unimplemented-subagent-vocabulary.md) | 中文 +# RFC: 裁剪未实现的 subagent seam 词汇 Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below stands as the record of what is currently unimplemented. +[English](2026-07-04-prune-unimplemented-subagent-vocabulary.md) | 中文 + ## 问题 [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 交付了一套两层能力设计:启动时由服务检查的能力 flag,以及 `SubagentRun` 上的可选运行时方法。三个启动时特性和两个可选运行时方法的实现数与调用数均为零: diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml index 98bc1e4bab..b6d3903ddd 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml @@ -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 -2026-07-12-collapse-workflow-to-foreground-core.md: 78b67c10ac39fddaf4ea76ca90d5cbf760fe5866 -2026-07-12-collapse-workflow-to-foreground-core.zh.md: 28b0af0a70110d39572fafac521a555c62ebb3f5 +2026-07-12-collapse-workflow-to-foreground-core.md: eaf8a4a22766e06b743a7b91d2a607eb6c8e67d9 +2026-07-12-collapse-workflow-to-foreground-core.zh.md: 4b1f4ebbec852386ca4577a38a9bd41b7529e500 diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md index 78b67c10ac..eaf8a4a227 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.md @@ -1,9 +1,9 @@ # RFC: Collapse workflows to the exercised foreground core -English | [中文](2026-07-12-collapse-workflow-to-foreground-core.zh.md) - Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it. +English | [中文](2026-07-12-collapse-workflow-to-foreground-core.zh.md) + ## Problem The workflow capability executes foreground JavaScript that composes subagents, but it also carries an unconsumed progress-observation system. No production listener subscribes to any of the six `workflow/*` events; listeners exist only in workflow tests. Nevertheless the seam defines run/phase/agent outcome payloads, the worker sends phase/log/agent lifecycle protocol messages, the host forwards them through a `liveAgents` pairing ledger, and the engine maintains run ids solely to correlate those notifications. diff --git a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md index 28b0af0a70..4b1f4ebbec 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md +++ b/docs/rfc/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md @@ -1,9 +1,9 @@ -# RFC:将工作流收缩至已使用的前台核心 - -[English](2026-07-12-collapse-workflow-to-foreground-core.md) | 中文 +# RFC: 将工作流收缩至已使用的前台核心 Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it. +[English](2026-07-12-collapse-workflow-to-foreground-core.md) | 中文 + ## 问题 工作流能力执行前台 JavaScript 来编排 subagent,但它同时携带了一套无人消费的进度观测系统。没有任何生产环境的监听器订阅六个 `workflow/*` 事件中的任何一个;监听器仅存在于工作流测试中。尽管如此,seam 定义了 run/phase/agent outcome 载荷,worker 发送 phase/log/agent 生命周期协议消息,host 通过一个 `liveAgents` 配对账本转发它们,引擎维护 run id 仅仅是为了关联这些通知。 diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml index a9c24674bf..0c7d9feb75 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml @@ -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 -2026-07-12-prune-unused-skill-registry-surface.md: 3e8c009871c3d609612b4a01edc2048ddedfad0d -2026-07-12-prune-unused-skill-registry-surface.zh.md: deaea2ca53d4ed2ac5141013f969f621d3202875 +2026-07-12-prune-unused-skill-registry-surface.md: 5b90deca8681373b2cc2befa3ab341084f924a3d +2026-07-12-prune-unused-skill-registry-surface.zh.md: 7b0e24f49688ed61f2ac4bff93b4c3f85117a170 diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md index 3e8c009871..5b90deca86 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.md @@ -1,9 +1,9 @@ # RFC: Prune unused skill registry surface -English | [中文](2026-07-12-prune-unused-skill-registry-surface.zh.md) - Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins. +English | [中文](2026-07-12-prune-unused-skill-registry-surface.zh.md) + ## Problem The skill service's embedded-runtime subsystem has zero production caller of `ctx.skills.register()`. It adds a reserved `runtime` provider name, a runtime map/rank/source, duplicate policy, a second revision in cache keys, normalization, disposers, and tests alongside the provider seam every shipped skill already uses. `SkillSummary.whenToUse` and candidate/definition `path` are parsed and copied but never read by a production consumer: the model catalog renders name/description, resource loading uses `resourceBase`, and providers own their locator. The deliberately open `metadata` extension point stays. diff --git a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md index deaea2ca53..7b0e24f496 100644 --- a/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md +++ b/docs/rfc/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md @@ -1,9 +1,9 @@ -# RFC:裁剪 skill 注册表中未使用的接口 - -[English](2026-07-12-prune-unused-skill-registry-surface.md) | 中文 +# RFC: 裁剪 skill 注册表中未使用的接口 Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins. +[English](2026-07-12-prune-unused-skill-registry-surface.md) | 中文 + ## 问题 skill(技能)服务的嵌入式运行时子系统中,`ctx.skills.register()` 没有任何生产调用方。它引入了一个保留的 `runtime` 提供方名称、一套运行时 map/rank/source、重复策略、缓存键中的第二个 revision、规范化逻辑、dispose(资源释放)器以及相应测试——而所有已交付的 skill 都只使用提供方 seam。`SkillSummary.whenToUse` 和 candidate/definition 的 `path` 被解析和复制,但没有任何生产消费方读取它们:模型目录只渲染 name/description,资源加载使用 `resourceBase`,提供方自行管理其定位器。有意开放的 `metadata` 扩展点保留不动。 From 57a47b1fb3812488c6cbec4c5a6242fc543baf1f Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:37:20 +0800 Subject: [PATCH 092/368] fix(pty): close review lifecycle gaps --- ...06-20-generic-long-running-tool-runtime.md | 10 +- ...26-07-16-persistent-pty-sessions.i18n.yaml | 4 +- .../2026-07-16-persistent-pty-sessions.md | 31 ++-- .../2026-07-16-persistent-pty-sessions.zh.md | 31 ++-- docs/config-catalog.md | 21 ++- docs/cordis-catalog/services.md | 11 +- docs/core-data-structures/tasks.md | 7 + docs/event-producer-consumer.md | 2 +- docs/module-graph.md | 10 +- examples/acp-agent/pty.cordis.snapshot.yml | 2 + .../tests/snapshots/pty-tools/session.jsonl | 2 +- .../snapshots/pty-tools/stdout.expected.jsonl | 2 +- .../headless-agent/pty.cordis.snapshot.yml | 2 + .../tests/snapshots/pty-tools/session.jsonl | 2 +- .../pty-tools/stream-json.expected.jsonl | 2 +- .../cordis/tool-cordis/src/api-catalog.ts | 8 +- packages/pty/pty-local/README.md | 6 +- packages/pty/pty-local/package.json | 2 + packages/pty/pty-local/src/index.ts | 20 ++- packages/pty/pty-local/src/sanitize.ts | 41 ++++- packages/pty/pty-local/src/session.ts | 163 ++++++++++++------ packages/pty/pty-local/tests/index.spec.ts | 101 ++++++++++- packages/pty/pty-local/tests/local.spec.ts | 33 ++++ packages/pty/pty-local/tests/sanitize.spec.ts | 16 +- packages/pty/pty-local/tests/session.spec.ts | 99 ++++++++++- packages/pty/pty-local/tsconfig.json | 6 + packages/pty/pty/README.md | 4 +- packages/pty/pty/src/index.ts | 36 +++- packages/pty/pty/tests/service.spec.ts | 40 ++++- packages/pty/tool-pty/README.md | 15 +- packages/pty/tool-pty/package.json | 5 + packages/pty/tool-pty/src/index.ts | 54 ++++-- packages/pty/tool-pty/src/render.ts | 92 ++++++++-- packages/pty/tool-pty/tests/render.spec.ts | 54 ++++-- packages/pty/tool-pty/tests/tools.spec.ts | 51 +++++- packages/pty/tool-pty/tsconfig.json | 3 + packages/tasks/tasks/README.md | 4 +- packages/tasks/tasks/src/index.ts | 7 + packages/tasks/tasks/src/types.ts | 7 + packages/tasks/tasks/tests/tasks.spec.ts | 23 ++- packages/tasks/tool-tasks/README.md | 4 +- packages/tasks/tool-tasks/package.json | 8 +- packages/tasks/tool-tasks/src/index.ts | 52 +++++- .../tasks/tool-tasks/tests/tool-tasks.spec.ts | 22 ++- packages/tasks/tool-tasks/tsconfig.json | 3 + pnpm-lock.yaml | 13 ++ python/sdk-runtime/package.json | 1 + 47 files changed, 940 insertions(+), 192 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md index 4db0d78910..11425939c3 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -21,7 +21,9 @@ Long-running tools are producers. `dsh-tool-bash` adapts a `BashProcess` into in ## Runtime contract -The literal types live in the [task data-structure catalog](../../../../docs/core-data-structures/tasks.md). A producer calls `ctx.tasks.start()` with a kind, label, optional owning `Agent`, and a `run()` function. The runtime completes all failable preflight work before calling `run()` and invokes it once. After `run()` returns hooks, registration commits without another failable step; a producer cannot start work that lacks a collectable task id. +The literal types live in the [task data-structure catalog](../../../../docs/core-data-structures/tasks.md). A producer calls `ctx.tasks.start()` with a kind, label, optional owning `Agent`, optional positive `outputLimitBytes`, and a `run()` function. The runtime completes all failable preflight work before calling `run()` and invokes it once. After `run()` returns hooks, registration commits without another failable step; a producer cannot start work that lacks a collectable task id. + +`outputLimitBytes` is producer-owned presentation policy, not a registry buffer. The registry validates and projects it unchanged into `TaskSnapshot`; generic control surfaces apply the cap to complete model-facing output after adding their own status or notice metadata. Omitting it preserves the existing surface behavior, so the runtime does not impose a hidden default on unrelated producer families. The producer hooks define three responsibilities: @@ -73,11 +75,11 @@ Stream reads share one task-scoped consuming cursor because the owning model is The system prompt tells the model to retain task ids, continue independent work instead of busy-polling or duplicating a running task, collect relevant tasks before its final answer, and kill work that no longer matters. Completion injects a logged `context/message` into the exact owner's session; it becomes durable context for the next request but does not wake an idle agent. -The runtime marks a terminal task `reported` when a read or wait delivers it, when a live waiter has claimed delivery at settlement, or when the model explicitly kills it. Reported tasks do not inject redundant completion notices. Listener failures are logged independently, do not stop later listeners, and are not awaited by waiters or teardown. +The runtime marks a terminal task `reported` when a read or wait delivers it, when a live waiter has claimed delivery at settlement, or when the model explicitly kills it. Reported tasks do not inject redundant completion notices. Listener failures are logged independently, do not stop later listeners, and are not awaited by waiters or teardown. When a snapshot carries `outputLimitBytes`, `dsh-tool-tasks` reserves space for status or notice suffixes, preserves UTF-8 boundaries, and reuses an existing producer truncation marker rather than duplicating it. ## Producer opt-in -Each producer owns whether its schema exposes `run_in_background` through defaulted config. `dsh-tool-bash` and each `dsh-tool-subagent` instance use `enableRunInBackground`, defaulting to true. A disabled instance omits the parameter and also rejects a forced background argument at execution because the generic argument validator permits undeclared keys. Schema omission advertises the capability; the execution check enforces it. +Each producer owns whether its schema exposes `run_in_background` through defaulted config. `dsh-tool-bash`, `dsh-tool-pty`, and each `dsh-tool-subagent` instance use `enableRunInBackground`, defaulting to true. A disabled instance omits the parameter and also rejects a forced background argument at execution because the generic argument validator permits undeclared keys. Schema omission advertises the capability; the execution check enforces it. `ctx.tasks` does not rewrite producer schemas. A bundle forwards configuration only for producers it owns. If a background call reaches `start()` without an attached surface, the runtime fence fails before execution. @@ -119,7 +121,7 @@ Authorization, not unguessability, is the access boundary, and ids do not derive ## Testing -Unit coverage pins preflight atomicity, per-kind ids, stream and final reads, wait timeout and abort races, cancellation, first-wins settlement, listener containment, notice suppression, owner isolation, stale owner instances, owner cleanup, service teardown, and the no-surface fence. Producer tests cover bash process mapping, subagent startup cancellation, terminal mapping, and disposal. Snapshot coverage pins the control-tool schemas and prompt guidance. +Unit coverage pins preflight atomicity, per-kind ids, output-limit validation and projection, complete UTF-8 result bounds, stream and final reads, wait timeout and abort races, cancellation, first-wins settlement, listener containment, notice suppression, owner isolation, stale owner instances, owner cleanup, service teardown, and the no-surface fence. Producer tests cover bash process mapping, subagent startup cancellation, terminal mapping, and disposal. Snapshot coverage pins the control-tool schemas and prompt guidance. ## Consequences diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index f58ed600f0..627e46ace5 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml @@ -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 -2026-07-16-persistent-pty-sessions.md: 76354891f557974b953a1b0b805d94330c9f6e69 -2026-07-16-persistent-pty-sessions.zh.md: 86200d70c6eda815a440c44e8b55457b0424edb6 +2026-07-16-persistent-pty-sessions.md: 8d279fea2e606894e4e8856a706113c0ea173e98 +2026-07-16-persistent-pty-sessions.zh.md: 9e81cad7357bc37856dc74ed5654744d70981a06 diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index 76354891f5..8d279fea2e 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -34,14 +34,14 @@ Idle detection is backend behavior, not a second public seam. A remote or contai There are no plugin-load auto-start sessions. `terminal_open` creates a session only during an agent tool call, when ownership and the owning event-sourced session are known. A future declarative startup feature must compose through unpublished agent setup rather than create shared global terminals. -Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). +Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. ### Security and process boundary A registered `shell` backend constrains how a terminal starts; it does not constrain commands typed after startup. `dsh-pty-local` therefore applies two protections before spawning: - It builds a scrubbed child environment using the same credential-shaped-name policy as `bash-local`, removing ambient `*KEY*`, `*SECRET*`, `*TOKEN*`, and harness-managed variables unless an explicit trusted mapping supplies them. -- It requires `ctx.sandbox` and the shared `ctx.sandboxPolicy`. At spawn, the backend resolves the owner's effective session mode over the deployment default and wraps the shell argv once; that mode and workspace root remain the process boundary for the PTY lifetime. `danger-full-access` is the existing explicit unconfined choice rather than a PTY-specific bypass. +- It requires `ctx.sandbox` and the shared `ctx.sandboxPolicy`. At spawn, the backend resolves the owner's effective session mode over the deployment default and wraps the shell argv once; that mode and workspace root remain the process boundary for the PTY lifetime. A write that would change the effective `sandbox/mode` is rejected before commit while the owner has any open PTY or unpublished spawn, with an instruction to wait for creation to settle and close those sessions first; same-effective-mode writes remain valid. The pending reservation spans backend setup through publication, so there is no race in which a wider terminal appears after a downgrade. `danger-full-access` is the existing explicit unconfined choice rather than a PTY-specific bypass. Sandboxing confines local process effects but does not make arbitrary shell input safe: network calls and other external side effects remain governed by deployment policy. Tool descriptions state that PTY sessions are less auditable than one-shot tools and should be used only when persistence or interactive stdin is necessary. @@ -58,19 +58,21 @@ The implementation uses only public `node-pty` capabilities: child PID, `data` a | `terminal_close` | Close one session and await process-tree quiescence | `{ killed }` | | `terminal_list` | List the caller's live sessions | owner-scoped session summaries | -`terminal_send({ sessionId, text, submit?, run_in_background? })` treats `text` as UTF-8 bytes and resolves `submit` to `true` in the tool implementation. When `submit` is true it writes the platform Enter sequence after the text; when false it writes only the text, allowing control characters and REPL fragments without hidden content heuristics. +The ACP render contract is exact and location-free. `terminal_send` uses terminal call/result cards only for foreground sends; its background form is generic `execute`. `terminal_open`, `terminal_read`, `terminal_signal`, `terminal_close`, and `terminal_list` use generic `execute`, `read`, `execute`, `delete`, and `read` cards respectively. No PTY tool emits `locations`. -Foreground sends return a bounded rendered delta and two independent facts: `waitReason` (`stdin_read | inferred_idle | timeout | session_exit`) and `sessionStatus` (`running` or `exited` with exit code or signal). `session_exit` refers to the PTY's top-level shell process, not an arbitrary foreground command whose status the shell consumes. A timeout never implies process exit. +`terminal_send({ sessionId, text, submit?, run_in_background? })` treats `text` as UTF-8 bytes and resolves `submit` to `true` in the tool implementation. When `submit` is true it writes the platform Enter sequence after the text; when false it writes only the text, allowing control characters and REPL fragments without hidden content heuristics. `enableRunInBackground` defaults to true; false removes `run_in_background` from the schema and rejects the same undeclared argument if a caller forces it through execution. -With `run_in_background: true`, `dsh-tool-pty` registers the in-flight send on `ctx.tasks` and returns immediately with `taskId`. `task_output(wait: true)` waits, reads incremental output, and records the final result; `task_kill` forwards cancellation as `SIGINT` and escalates only through the PTY backend's owned teardown path. If the task surface is absent, background mode fails before writing input. No PTY-specific `sleep` tool or general wake-up seam is added. +Foreground sends return a bounded rendered delta and two independent facts: `waitReason` (`stdin_read | inferred_idle | timeout | session_exit`) and `sessionStatus` (`running` or `exited` with exit code or signal). `session_exit` refers to the PTY's top-level shell process, not an arbitrary foreground command whose status the shell consumes. A timeout never implies process exit. `dsh-tool-pty.maxResultBytes` defaults to 262144 and caps the complete UTF-8 result after wait, session, pagination, truncation, and generic task-status wrappers; the renderer reserves suffix space and preserves code-point boundaries instead of treating the backend payload cap as the final model bound. -`terminal_read` pages backward from the newest retained line. The backend enforces both line and UTF-8 byte caps on retained scrollback and the complete returned value, so one oversized line cannot bypass the bound. `truncated` distinguishes retention loss from an ordinary viewport delta. +With `run_in_background: true`, `dsh-tool-pty` registers the in-flight send on `ctx.tasks` and returns immediately with `taskId`. The producer places `maxResultBytes` on the task snapshot so `task_output`, terminal kill status, and completion notices enforce the same complete-result cap after generic metadata. `task_output(wait: true)` waits, reads incremental output, and records the final result; `task_kill` resolves the current foreground PGID and delivers a real `SIGINT`, including when the application has disabled terminal `ISIG`, and escalates only through the PTY backend's owned teardown path. If the task surface is absent, background mode fails before writing input. No PTY-specific `sleep` tool or general wake-up seam is added. + +`terminal_read` pages backward from the newest retained line. The backend enforces both line and UTF-8 byte caps on retained scrollback and the returned page payload, so one oversized line cannot bypass the backend bound; the tool then caps the fully rendered page including pagination and truncation metadata. `truncated` distinguishes retention loss from an ordinary viewport delta. `terminal_signal` accepts the closed set `SIGINT | SIGTERM | SIGKILL | SIGTSTP | SIGHUP`. The backend resolves the terminal foreground process group at execution time. `SIGKILL` is rejected when that group is the top-level shell, directing the caller to `terminal_close`; a failed group lookup fails the operation instead of signaling a guessed PID. ### Local readiness detection -The local backend first recognizes a private OSC prompt marker emitted by its controlled bash startup, then runs three bounded fallback tiers. The marker is removed before output reaches the model and avoids a fixed silence delay for ordinary shell commands on both platforms. Unpublished startup does not accept zero-output silence as readiness; timeout rejects the spawn. All timings are validated config fields: `pollIntervalMs`, `exactProbeAfterMs`, `idleSilenceMs`, and `timeoutMs`. +The local backend first recognizes a private OSC prompt marker emitted by its controlled bash startup, then requires printable prompt text after that marker before declaring prompt readiness and runs three bounded fallback tiers. Carrying that state across data callbacks covers macOS delivery where the OSC marker and `PS1` arrive separately; the marker alone can no longer publish an empty MOTD. The marker is removed before output reaches the model and avoids a fixed silence delay for ordinary shell commands on both platforms. Unpublished startup does not accept zero-output silence as readiness; timeout rejects the spawn. All timings are validated config fields: `pollIntervalMs`, `exactProbeAfterMs`, `idleSilenceMs`, and `timeoutMs`. On Linux, the inspector reads the shell's terminal foreground PGID from `/proc/<shellPid>/stat`, enumerates every process and thread in that process group, and probes their current syscalls. A positive Tier 1 result requires an observed stdin wait: direct `read(0)`, a permitted read of a `select`/`pselect6` or `poll`/`ppoll` argument containing fd 0, or an epoll interest list containing fd 0. Unreadable process memory and unrecognized syscalls are misses, never positive guesses. Architecture tables contain only syscall numbers defined by the corresponding Linux UAPI; unsupported architectures skip Tier 1. @@ -78,7 +80,7 @@ On macOS there is no exact syscall tier. Output silence returns `inferred_idle` Tier 2 returns `inferred_idle` after `idleSilenceMs` without output. A sleeping or network-blocked command can therefore look ready. Tier 3 returns `timeout` after `timeoutMs` so a foreground tool call cannot hold the agent indefinitely. The result preserves the distinction; callers may wait through `ctx.tasks`, signal the foreground group, or inspect from another session. -`node-pty` data notifications feed one streaming decoder and terminal parser. Parser carry state handles UTF-8 and terminal query sequences split across chunks. The implementation normalizes line-oriented output and detects alternate-screen entry, but it does not promise correct interaction with a full-screen application. +`node-pty` data notifications feed one terminal parser. Parser carry state handles control sequences and a trailing carriage return split across callbacks, so a divided CRLF produces one newline rather than a pagination-changing blank line. The implementation normalizes line-oriented output, but it does not promise correct interaction with a full-screen application. ### Model-visible output and durability @@ -88,9 +90,9 @@ Background sends use the existing task completion notice and `task_output` resul ### Process-tree teardown -The top-level `node-pty` child is the ownership anchor. On close, the backend stops callbacks, snapshots that PID and its transitive descendants by parent PID in children-first order, sends `SIGTERM`, closes the PTY, waits for quiescence, then sends `SIGKILL` to verified survivors after configurable `disposeGraceMs` and waits for them to leave the process table. Every captured PID includes process-start identity so reuse cannot redirect escalation. +The top-level `node-pty` child is the ownership anchor. On close, the backend stops callbacks, snapshots its transitive descendants by parent PID in children-first order, sends `SIGTERM`, waits, rescans for children forked during shutdown, sends `SIGKILL` to the remaining descendant tree, and verifies that every descendant left the process table while the shell is still alive to reap it. Only then does it stop the shell with its own TERM/grace/KILL sequence. Every captured PID includes process-start identity so reuse cannot redirect escalation. -Teardown reports root exit and survivor cleanup independently. It does not claim success merely because the shell exited; disposal resolves only after no captured tree member remains or returns a structured cleanup failure naming the survivors. Service disposal still clears its backend, reservation, and owner-detacher registries when a close fails. It never broadens ownership to every member of the root PID's POSIX session. +Teardown reports root exit and survivor cleanup independently. It does not claim success merely because the shell exited; disposal resolves only after no captured tree member remains or returns a cleanup failure naming the survivors. A failed close is not cached forever: the registry and local session retain their closing fence but allow a later close to retry after the external survivor condition changes. Service disposal still clears its backend, reservation, and owner-detacher registries when a close fails. It never broadens ownership to every member of the root PID's POSIX session. ### Composition and rollout @@ -115,9 +117,12 @@ plugins: timeoutMs: 30000 disposeGraceMs: 3000 '@deepseek-ai/dsh-tool-pty': + config: + enableRunInBackground: true + maxResultBytes: 262144 ``` -The package ships concise tool guidance explaining persistent state, owner isolation, uncertain idle results, cleanup, and the preference for existing one-shot tools when interaction is unnecessary. It does not add a global system-prompt recommendation or mount PTY in shipped defaults; dedicated ACP and headless snapshot overlays exercise the opt-in composition. +The package ships concise tool guidance explaining persistent state, owner isolation, uncertain idle results, cleanup, and the preference for existing one-shot tools when interaction is unnecessary. It does not mount PTY in the base shipped examples: PTY is opt-in through the dedicated composition, while ACP and headless snapshot overlays exercise it. Within an enabled `dsh-tool-pty` instance, the six tools and `run_in_background` are enabled by default; deployments may disable only the background argument with config. ### Deferred work @@ -147,9 +152,9 @@ The package ships concise tool guidance explaining persistent state, owner isola ## Verification -- Per-file coverage pins owner fencing, concurrent reservations, lifecycle cleanup, readiness tiers, sanitizer carry state, UTF-8 bounds, task integration, schemas, and render intents. +- Per-file coverage pins owner fencing, concurrent reservations, sandbox-mode change rejection, retriable lifecycle cleanup, readiness tiers, sanitizer carry state, complete UTF-8 bounds, task integration, schemas, and exact render intents. - Linux process fixtures cover non-leader and non-main-thread stdin waits, unreadable process state, supported syscall tables, unsupported architectures, and false-positive rejection; macOS inspector logic is injected into the same unit suite. -- Real `node-pty` tests exercise shell state, shared sandbox policy, environment scrubbing, signals, a TERM-ignoring descendant, and immediate post-disposal quiescence on supported hosts. +- Real `node-pty` tests exercise shell state, shared sandbox policy, environment scrubbing, raw-mode foreground `SIGINT`, a TERM-ignoring descendant, and immediate post-disposal quiescence on supported hosts. - A Loader-driven `cordis.yml` test mounts the real three-package composition, while ACP and headless snapshots pin the six schemas, bounded results, error rendering, and terminal/generic cards through opt-in overlays. - Package contracts, the architecture map, core data structures, generated catalogs, and the website API describe the same shipped surface. - The repository CI-equivalent sequence owns type, lint, coverage, snapshot, documentation, build, hygiene, demo, and built-entry verification. diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index 86200d70c6..9e81cad735 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -34,14 +34,14 @@ idle 检测属于后端行为,不是第二条公共 seam。远程或容器后 实现不提供插件加载期 auto-start 会话。`terminal_open` 只在 agent 工具调用期间创建会话,此时所有权和所属的事件溯源会话都已确定。未来的声明式启动功能必须通过尚未发布的 agent setup 组合,而不能创建全局共享终端。 -agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。 +agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 ### 安全与进程边界 注册的 `shell` 后端只约束终端如何启动,不约束启动后输入的命令。因此 `dsh-pty-local` 在 spawn 前应用两层保护: - 它使用与 `bash-local` 相同的凭证形态名称策略构建清洗后的子进程环境,移除环境中的 `*KEY*`、`*SECRET*`、`*TOKEN*` 和 harness 管理的变量,除非显式的可信映射提供这些值。 -- 它要求 `ctx.sandbox` 和共享的 `ctx.sandboxPolicy`。后端在 spawn 时,以部署默认值为底折叠 owner 的有效 session mode,并只包装一次 shell argv;该 mode 与 workspace root 在 PTY 的整个生命周期中充当进程边界。`danger-full-access` 是现有的显式无约束选择,不另设 PTY 私有 bypass。 +- 它要求 `ctx.sandbox` 和共享的 `ctx.sandboxPolicy`。后端在 spawn 时,以部署默认值为底折叠 owner 的有效 session mode,并只包装一次 shell argv;该 mode 与 workspace root 在 PTY 的整个生命周期中充当进程边界。只要 owner 有任何已打开的 PTY 或尚未发布的 spawn,任何会改变生效 `sandbox/mode` 的写入都会在提交前被拒绝,并提示先等待创建操作结算,再关闭这些会话;不会改变生效模式的写入仍然有效。这项进行中的预留从后端 setup 持续到发布完成,因此不存在降级后又出现权限更宽的终端这一竞态。`danger-full-access` 是现有的显式无约束选择,不另设 PTY 私有 bypass。 沙箱限制本地进程副作用,但不会让任意 shell 输入自动安全:网络调用和其他外部副作用仍由部署策略治理。工具描述会说明 PTY 会话比一次性工具更难审计,只应在确实需要持久状态或交互式 stdin 时使用。 @@ -58,19 +58,21 @@ agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出 | `terminal_close` | 关闭一个会话并等待进程树静默退出 | `{ killed }` | | `terminal_list` | 列出调用方的活会话 | 按 owner 隔离的会话摘要 | -`terminal_send({ sessionId, text, submit?, run_in_background? })` 将 `text` 视为 UTF-8 字节,并由工具实现在解析阶段把 `submit` 默认成 `true`。`submit` 为 true 时先写入文本,再写入平台 Enter 序列;为 false 时只写文本,使控制字符和 REPL 片段无需隐藏的内容启发式即可发送。 +ACP 渲染契约精确且不携带位置信息。`terminal_send` 只为前台发送使用 terminal 调用卡片和结果卡片;后台形式使用通用 `execute` 卡片。`terminal_open`、`terminal_read`、`terminal_signal`、`terminal_close` 和 `terminal_list` 分别使用通用 `execute`、`read`、`execute`、`delete` 和 `read` 卡片。所有 PTY 工具都不发出 `locations`。 -前台发送返回有界的渲染增量和两个独立事实:`waitReason`(`stdin_read | inferred_idle | timeout | session_exit`)与 `sessionStatus`(`running`,或携带退出码或信号的 `exited`)。`session_exit` 指 PTY 顶层 shell 进程退出,不指由 shell 消费状态的任意前台命令。timeout 从不意味着进程已经退出。 +`terminal_send({ sessionId, text, submit?, run_in_background? })` 将 `text` 视为 UTF-8 字节,并由工具实现在解析阶段把 `submit` 默认成 `true`。`submit` 为 true 时先写入文本,再写入平台 Enter 序列;为 false 时只写文本,使控制字符和 REPL 片段无需隐藏的内容启发式即可发送。`enableRunInBackground` 默认为 true;设为 false 时,schema 中会移除 `run_in_background`,调用方即使强行把这个未声明参数传入执行流程,也会被拒绝。 -当 `run_in_background: true` 时,`dsh-tool-pty` 在 `ctx.tasks` 上注册进行中的发送,并立即返回 `taskId`。`task_output(wait: true)` 负责等待、读取增量输出并记录最终结果;`task_kill` 将取消转发为 `SIGINT`,只有 PTY 后端拥有的 teardown 路径可以升级信号。若 task 对外接口不存在,后台模式必须在写入输入前失败。设计不新增 PTY 专用的 `sleep` 工具或通用唤醒 seam。 +前台发送返回有界的渲染增量和两个独立事实:`waitReason`(`stdin_read | inferred_idle | timeout | session_exit`)与 `sessionStatus`(`running`,或携带退出码或信号的 `exited`)。`session_exit` 指 PTY 顶层 shell 进程退出,不指由 shell 消费状态的任意前台命令。timeout 从不意味着进程已经退出。`dsh-tool-pty.maxResultBytes` 默认为 262144;完整 UTF-8 结果在加入等待与会话状态、分页与截断元数据以及通用 task 状态包装后,仍受该值限制。渲染器会为后缀预留空间并保持代码点边界,而不会把后端载荷上限当作面向模型结果的最终上限。 -`terminal_read` 从最新保留行向后分页。后端同时对保留的 scrollback 和完整返回值执行行数与 UTF-8 字节上限,因此单个超长行无法绕过限制。`truncated` 用于区分保留数据丢失与普通 viewport 增量。 +当 `run_in_background: true` 时,`dsh-tool-pty` 在 `ctx.tasks` 上注册进行中的发送,并立即返回 `taskId`。生产方把 `maxResultBytes` 写入 task 快照,使 `task_output`、kill 返回的终态状态和完成通知在加上通用元数据后,仍对完整结果执行同一上限。`task_output(wait: true)` 负责等待、读取增量输出并记录最终结果;`task_kill` 会解析当前前台 PGID 并发送真正的 `SIGINT`,即使应用已禁用终端 `ISIG` 也同样如此,且后续升级仍只通过 PTY 后端拥有的 teardown 路径进行。若 task 对外接口不存在,后台模式必须在写入输入前失败。设计不新增 PTY 专用的 `sleep` 工具或通用唤醒 seam。 + +`terminal_read` 从最新保留行向后分页。后端同时对保留的 scrollback 和返回页载荷执行行数与 UTF-8 字节上限,因此单个超长行无法绕过后端上限;工具随后再限制包含分页与截断元数据的完整渲染页。`truncated` 用于区分保留数据丢失与普通 viewport 增量。 `terminal_signal` 接受闭合集 `SIGINT | SIGTERM | SIGKILL | SIGTSTP | SIGHUP`。后端在执行时解析终端前台进程组。当目标组是顶层 shell 时拒绝 `SIGKILL`,并指引调用方使用 `terminal_close`;进程组解析失败时操作直接失败,而不是向猜测的 PID 发送信号。 ### 本地就绪检测 -本地后端先识别受控 bash 启动时发出的私有 OSC prompt marker,再执行 3 个有界 fallback 层级。marker 在输出到达模型前被移除,使两个平台上的普通 shell 命令都无需固定等待静默阈值。尚未发布的 startup 不会把零输出静默视为就绪;timeout 会拒绝 spawn。所有时间参数都是经校验的配置字段:`pollIntervalMs`、`exactProbeAfterMs`、`idleSilenceMs` 和 `timeoutMs`。 +本地后端先识别受控 bash 启动时发出的私有 OSC prompt marker,并且只有在该 marker 后出现可打印的 prompt 文本时才据此声明 prompt 就绪;除此之外,它还运行 3 个有界 fallback 层级。在 data callback 之间保留这项状态,可以适配 macOS 分开交付 OSC marker 与 `PS1` 的情况;单独的 marker 不会发布空 MOTD。marker 在输出到达模型前被移除,使两个平台上的普通 shell 命令都无需固定等待静默阈值。尚未发布的 startup 不会把零输出静默视为就绪;timeout 会拒绝 spawn。所有时间参数都是经校验的配置字段:`pollIntervalMs`、`exactProbeAfterMs`、`idleSilenceMs` 和 `timeoutMs`。 在 Linux 上,检查器从 `/proc/<shellPid>/stat` 读取 shell 的终端前台 PGID,枚举该进程组中的每个进程与线程,并检查它们当前的 syscall。Tier 1 只有观察到 stdin 等待才返回正结果:直接 `read(0)`、获准读取且含 fd 0 的 `select`/`pselect6` 或 `poll`/`ppoll` 参数,或者含 fd 0 的 epoll interest list。无法读取的进程内存和未识别的 syscall 都是 miss,绝不作为正向猜测。架构表只包含对应 Linux UAPI 定义的 syscall number;不支持的架构跳过 Tier 1。 @@ -78,7 +80,7 @@ macOS 没有精确 syscall 层。任何前台进程组输出静默都会返回 ` Tier 2 在持续 `idleSilenceMs` 没有输出后返回 `inferred_idle`,因此 sleep 或网络阻塞的命令可能看似 ready。Tier 3 在 `timeoutMs` 后返回 `timeout`,避免前台工具调用无限占住 agent。结果保留这些区别;调用方可以通过 `ctx.tasks` 等待、向前台组发信号,或从另一个会话排查。 -`node-pty` data 通知进入同一个流式 decoder 和终端 parser。parser 的 carry 状态处理跨 chunk 的 UTF-8 与终端查询序列。当前实现只规范化行式输出并检测 alternate-screen 进入,不承诺正确操作全屏应用。 +`node-pty` data 通知进入同一个终端 parser。parser 的 carry state 会处理跨 callback 的控制序列和位于 callback 末尾的回车;因此,即使 CRLF 被拆开,也只会生成一个换行,而不会产生改变分页的空行。实现会规范化行式输出,但不承诺正确操作全屏应用。 ### 模型可见输出与持久性 @@ -88,9 +90,9 @@ Tier 2 在持续 `idleSilenceMs` 没有输出后返回 `inferred_idle`,因此 ### 进程树 teardown -顶层 `node-pty` 子进程是所有权锚点。关闭时,后端先停止 callback,再按父 PID 以子进程优先顺序捕获该 PID 及其传递子进程、发送 `SIGTERM`、关闭 PTY 并等待静默,然后在可配置的 `disposeGraceMs` 后向已验证的存活者发送 `SIGKILL`,并等待它们离开进程表。每个捕获的 PID 都包含进程启动身份,避免 PID 复用把升级信号发给无关进程。 +顶层 `node-pty` 子进程是所有权锚点。关闭时,后端先停止 callback,再按父 PID 以子进程优先顺序捕获其传递子进程、发送 `SIGTERM` 并等待,然后重新扫描关停期间 fork 出的子进程,向剩余子孙进程树发送 `SIGKILL`,并在 shell 仍存活、可以回收这些进程时,验证每个子孙进程都已离开进程表。完成这些步骤后,后端才用 shell 自身的 TERM、宽限等待、KILL 序列停止 shell。每个捕获的 PID 都包含进程启动身份,避免 PID 复用把升级信号发给无关进程。 -teardown 独立报告根进程退出与存活进程清理。它不会只因 shell 退出就声称成功;dispose 只有在已捕获的进程树成员全部消失后才完成,否则返回结构化清理失败并列出存活者。即使某个 close 失败,服务 dispose 仍会清空其后端、预留与 owner detacher 注册表。所有权绝不会扩大到根 PID 所属 POSIX 会话的全部成员。 +teardown 独立报告根进程退出与存活进程清理。它不会只因 shell 退出就声称成功;dispose 只有在已捕获的进程树成员全部消失后才完成,否则返回清理失败并列出存活者。失败的 close 不会永久缓存:注册表与本地会话会保留关闭围栏,但在外部存活进程状态改变后允许后续 close 重试。即使某个 close 失败,服务 dispose 仍会清空其后端、预留与 owner detacher 注册表。所有权绝不会扩大到根 PID 所属 POSIX 会话的全部成员。 ### 组合与推行 @@ -115,9 +117,12 @@ plugins: timeoutMs: 30000 disposeGraceMs: 3000 '@deepseek-ai/dsh-tool-pty': + config: + enableRunInBackground: true + maxResultBytes: 262144 ``` -包提供简洁的工具指引,说明持久状态、owner 隔离、不确定的 idle 结果、清理,以及无需交互时优先使用现有一次性工具。它不增加全局 system prompt 推荐,也不在已发布的默认配置中挂载 PTY;专用 ACP 与 headless 快照 overlay 覆盖 opt-in 组合。 +包提供简洁的工具指引,说明持久状态、owner 隔离、不确定的 idle 结果、清理,以及无需交互时优先使用现有一次性工具。已发布的基础示例不挂载 PTY:PTY 仅通过专用组合 opt-in,ACP 与 headless 快照 overlay 覆盖该组合。`dsh-tool-pty` 实例一旦启用,6 个工具和 `run_in_background` 就会默认启用;部署可通过配置仅禁用后台参数。 ### 推迟的工作 @@ -147,9 +152,9 @@ plugins: ## 验证 -- 每文件覆盖率固定 owner 隔离、并发预留、生命周期清理、就绪层级、sanitizer carry state、UTF-8 上限、task 集成、schema 和 render intent。 +- 每文件覆盖率固定 owner 隔离、并发预留、沙箱模式变更拒绝、可重试的生命周期清理、就绪层级、sanitizer carry state、完整 UTF-8 结果上限、task 集成、schema 和精确 render intent。 - Linux 进程 fixture 覆盖非 leader 与非主线程的 stdin 等待、不可读进程状态、受支持的 syscall 表、不支持的架构和误报拒绝;同一单元测试套件通过注入覆盖 macOS 检查器逻辑。 -- 真实 `node-pty` 测试在受支持宿主上覆盖 shell 状态、共享沙箱策略、环境清洗、信号、忽略 `SIGTERM` 的子进程,以及 dispose 返回后立即静默。 +- 真实 `node-pty` 测试在受支持宿主上覆盖 shell 状态、共享沙箱策略、环境清洗、raw mode 下的前台 `SIGINT`、忽略 `SIGTERM` 的子进程,以及 dispose 返回后立即静默。 - Loader 驱动的 `cordis.yml` 测试挂载真实三包组合;ACP 与 headless 快照通过 opt-in overlay 固定 6 个 schema、有界结果、错误渲染和 terminal/generic card。 - 包契约、架构图、核心数据结构、生成目录和 website API 描述同一个已发布接口。 - 仓库 CI 等价序列负责类型、lint、覆盖率、快照、文档、构建、hygiene、demo 和 built-entry 验证。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 76afd7d68a..34d69c5227 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -802,7 +802,7 @@ Source: [`packages/plan/plan-mode/src/index.ts:57`](../packages/plan/plan-mode/s ## `@deepseek-ai/dsh-pty-local` -Requires: `pty` · `sandbox` · `sandboxPolicy` +Requires: `agents` · `pty` · `sandbox` · `sandboxPolicy` ```ts config-catalog /** Public plugin configuration. */ @@ -1339,6 +1339,22 @@ export interface Config { Source: [`packages/lsp/tool-lsp/src/index.ts:58`](../packages/lsp/tool-lsp/src/index.ts) +## `@deepseek-ai/dsh-tool-pty` + +Requires: `pty` · `tools` · `systemPrompt` + +```ts config-catalog +/** Model-facing terminal tool configuration. */ +export interface Config { + /** Expose `run_in_background` and accept background sends (default true). */ + enableRunInBackground?: boolean + /** Maximum UTF-8 bytes in one complete terminal or task-output result. */ + maxResultBytes?: number +} +``` + +Source: [`packages/pty/tool-pty/src/index.ts:33`](../packages/pty/tool-pty/src/index.ts) + ## `@deepseek-ai/dsh-tool-ralph` Requires: `tools` · `workflows` · `subagents` · `systemPrompt` @@ -1443,7 +1459,7 @@ export interface Config { } ``` -Source: [`packages/tasks/tool-tasks/src/index.ts:21`](../packages/tasks/tool-tasks/src/index.ts) +Source: [`packages/tasks/tool-tasks/src/index.ts:22`](../packages/tasks/tool-tasks/src/index.ts) ## `@deepseek-ai/dsh-tool-web` @@ -1840,7 +1856,6 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co - `@deepseek-ai/dsh-tasks` ([`packages/tasks/tasks/src/index.ts`](../packages/tasks/tasks/src/index.ts)) - `@deepseek-ai/dsh-timeout-policy` — requires `tools` ([`packages/timeout/timeout-policy/src/index.ts`](../packages/timeout/timeout-policy/src/index.ts)) - `@deepseek-ai/dsh-tool-ask-user` — requires `tools` · `userInteraction` ([`packages/ui/tool-ask-user/src/index.ts`](../packages/ui/tool-ask-user/src/index.ts)) -- `@deepseek-ai/dsh-tool-pty` — requires `pty` · `tools` · `systemPrompt` ([`packages/pty/tool-pty/src/index.ts`](../packages/pty/tool-pty/src/index.ts)) - `@deepseek-ai/dsh-tool-todo` — requires `tools` ([`packages/todo/tool-todo/src/index.ts`](../packages/todo/tool-todo/src/index.ts)) - `@deepseek-ai/dsh-user-interaction` ([`packages/ui/user-interaction/src/index.ts`](../packages/ui/user-interaction/src/index.ts)) diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index d7ca6cb602..15d32e9089 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -787,6 +787,13 @@ listBackends(): string[] */ async spawn(owner: Agent, request: PtySpawnRequest, signal?: AbortSignal): Promise<PtySpawnResult> +/** + * Test whether an exact owner has a published session or unpublished spawn. + * @param owner - exact live owner to inspect. + * @returns true across the entire spawn-to-close interval, with no publication gap. + */ +hasOwnerActivity(owner: Agent): boolean + /** * Start one exclusive interactive send. * @param owner - exact session owner. @@ -833,7 +840,7 @@ list(owner: Agent): PtySessionSnapshot[] Types: [Agent](../core-data-structures/core.md) · [PtyBackend](../core-data-structures/pty.md) · [PtyReadRequest](../core-data-structures/pty.md) · [PtyReadResult](../core-data-structures/pty.md) · [PtySendOperation](../core-data-structures/pty.md) · [PtySendRequest](../core-data-structures/pty.md) · [PtySessionId](../core-data-structures/pty.md) · [PtySessionSnapshot](../core-data-structures/pty.md) · [PtySignal](../core-data-structures/pty.md) · [PtySignalResult](../core-data-structures/pty.md) · [PtySpawnRequest](../core-data-structures/pty.md) · [PtySpawnResult](../core-data-structures/pty.md) -Source: [`packages/pty/pty/src/index.ts:95`](../../packages/pty/pty/src/index.ts) +Source: [`packages/pty/pty/src/index.ts:91`](../../packages/pty/pty/src/index.ts) ## `ctx.sandbox` — `SandboxProvider` (abstract seam) @@ -1404,7 +1411,7 @@ attachSurface(name: string): () => void Types: [Agent](../core-data-structures/core.md) · [TaskDoneListener](../core-data-structures/tasks.md) · [TaskId](../core-data-structures/tasks.md) · [TaskRead](../core-data-structures/tasks.md) · [TaskSnapshot](../core-data-structures/tasks.md) · [TaskStart](../core-data-structures/tasks.md) -Source: [`packages/tasks/tasks/src/index.ts:76`](../../packages/tasks/tasks/src/index.ts) +Source: [`packages/tasks/tasks/src/index.ts:77`](../../packages/tasks/tasks/src/index.ts) ## `ctx.tokenMeter` — `TokenMeterService` diff --git a/docs/core-data-structures/tasks.md b/docs/core-data-structures/tasks.md index 491f380166..2c7555b84d 100644 --- a/docs/core-data-structures/tasks.md +++ b/docs/core-data-structures/tasks.md @@ -34,6 +34,11 @@ interface TaskStart { kind: TaskKind /** One-line model-facing label (the command; the delegation description). */ label: string + /** + * Optional UTF-8 byte cap for each complete model-facing completion notice or + * output read, including control-surface status metadata. + */ + outputLimitBytes?: number /** * Owning live agent. Access is fenced by its session id, and agent disposal * cancels and awaits the task. The instance must be the one currently @@ -104,6 +109,8 @@ interface TaskSnapshot { kind: TaskKind /** The producer-supplied one-line label. */ label: string + /** Producer-owned cap for complete model-facing notices and output reads. */ + outputLimitBytes?: number /** * Owner session id used for authorization and correlation; absent for * unowned tasks. Completion listeners receive the exact {@link Agent} diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index d7f4123b91..100362892f 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -57,7 +57,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | Event string | Dispatchers | Listeners | | --- | --- | --- | -| `internal/dispatch` | - | [`compact`](../packages/compact/compact), [`fs`](../packages/fs/fs), [`goal`](../packages/goal/goal), [`goal-session`](../packages/goal/goal-session), [`hook-protocol`](../packages/hooks/hook-protocol), [`llm-retry`](../packages/llm/llm-retry), [`permission`](../packages/ui/permission), [`plan-mode`](../packages/plan/plan-mode), `runtime`, [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`time-context`](../packages/context/time-context), [`tool-todo`](../packages/todo/tool-todo), [`tools`](../packages/core/tools), [`user-approval`](../packages/ui/user-approval), [`workflow`](../packages/workflow/workflow) | +| `internal/dispatch` | - | [`compact`](../packages/compact/compact), [`fs`](../packages/fs/fs), [`goal`](../packages/goal/goal), [`goal-session`](../packages/goal/goal-session), [`hook-protocol`](../packages/hooks/hook-protocol), [`llm-retry`](../packages/llm/llm-retry), [`permission`](../packages/ui/permission), [`plan-mode`](../packages/plan/plan-mode), [`pty-local`](../packages/pty/pty-local), `runtime`, [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`time-context`](../packages/context/time-context), [`tool-todo`](../packages/todo/tool-todo), [`tools`](../packages/core/tools), [`user-approval`](../packages/ui/user-approval), [`workflow`](../packages/workflow/workflow) | | `internal/plugin` | - | `webserver` | | `internal/status` | - | [`agent`](../packages/core/agent) | | `slots/changed` | `runtime` (`emit`) | - | diff --git a/docs/module-graph.md b/docs/module-graph.md index ca4848477f..86b2ed9fbe 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -434,10 +434,12 @@ flowchart TD pkg_permission --> pkg_sandbox_policy pkg_permission --> pkg_session pkg_permission --> pkg_user_approval + pkg_pty_local --> pkg_agent pkg_pty_local --> pkg_invariants pkg_pty_local --> pkg_pty pkg_pty_local --> pkg_sandbox pkg_pty_local --> pkg_sandbox_policy + pkg_pty_local --> pkg_session pkg_agent_loop --> pkg_agent pkg_agent_loop --> pkg_invariants pkg_agent_loop --> pkg_llm @@ -563,11 +565,13 @@ flowchart TD pkg_tool_pty --> pkg_invariants pkg_tool_pty --> pkg_llm pkg_tool_pty --> pkg_pty + pkg_tool_pty --> pkg_retention pkg_tool_pty --> pkg_system_prompt pkg_tool_pty --> pkg_tasks pkg_tool_pty --> pkg_tools pkg_tool_tasks --> pkg_agent pkg_tool_tasks --> pkg_invariants + pkg_tool_tasks --> pkg_retention pkg_tool_tasks --> pkg_system_prompt pkg_tool_tasks --> pkg_tasks pkg_tool_tasks --> pkg_tools @@ -808,7 +812,7 @@ flowchart TD | [`session-title-all-messages-llm`](../packages/session-title/session-title-all-messages-llm) | `session-title` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-title`](../packages/session-title/session-title), [`session-title-llm`](../packages/session-title/session-title-llm) | | [`session-title-first-message-llm`](../packages/session-title/session-title-first-message-llm) | `session-title` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-title`](../packages/session-title/session-title), [`session-title-llm`](../packages/session-title/session-title-llm) | | [`permission`](../packages/ui/permission) | `ui` | [`bash`](../packages/bash/bash), [`invariants`](../packages/support/invariants), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`user-approval`](../packages/ui/user-approval) | -| [`pty-local`](../packages/pty/pty-local) | `pty` | [`invariants`](../packages/support/invariants), [`pty`](../packages/pty/pty), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy) | +| [`pty-local`](../packages/pty/pty-local) | `pty` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`pty`](../packages/pty/pty), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session) | | [`agent-loop`](../packages/core/agent-loop) | `core` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) | | [`tool-goal`](../packages/goal/tool-goal) | `goal` | [`agent`](../packages/core/agent), [`goal`](../packages/goal/goal), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) | | [`tool-bash`](../packages/bash/tool-bash) | `bash` | [`agent`](../packages/core/agent), [`bash`](../packages/bash/bash), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`paths`](../packages/util/paths), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session-persistence`](../packages/session-persistence/session-persistence), [`system-prompt`](../packages/core/system-prompt), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools), [`user-approval`](../packages/ui/user-approval) | @@ -829,8 +833,8 @@ flowchart TD | [`repeat-tool-guard`](../packages/guard/repeat-tool-guard) | `guard` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`tools`](../packages/core/tools) | | [`tool-lsp`](../packages/lsp/tool-lsp) | `lsp` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`lsp`](../packages/lsp/lsp), [`system-prompt`](../packages/core/system-prompt), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) | | [`mcp-client`](../packages/mcp/mcp-client) | `mcp` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`tools`](../packages/core/tools) | -| [`tool-pty`](../packages/pty/tool-pty) | `pty` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`pty`](../packages/pty/pty), [`system-prompt`](../packages/core/system-prompt), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools) | -| [`tool-tasks`](../packages/tasks/tool-tasks) | `tasks` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`system-prompt`](../packages/core/system-prompt), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools) | +| [`tool-pty`](../packages/pty/tool-pty) | `pty` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`pty`](../packages/pty/pty), [`retention`](../packages/util/retention), [`system-prompt`](../packages/core/system-prompt), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools) | +| [`tool-tasks`](../packages/tasks/tool-tasks) | `tasks` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`retention`](../packages/util/retention), [`system-prompt`](../packages/core/system-prompt), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools) | | [`tool-workflow`](../packages/workflow/tool-workflow) | `workflow` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) | | [`subagent-acp`](../packages/subagent/subagent-acp) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-subprocess`](../packages/subagent/subagent-subprocess) | | [`subagent-inprocess`](../packages/subagent/subagent-inprocess) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) | diff --git a/examples/acp-agent/pty.cordis.snapshot.yml b/examples/acp-agent/pty.cordis.snapshot.yml index 9ef3ff6418..07e4605375 100644 --- a/examples/acp-agent/pty.cordis.snapshot.yml +++ b/examples/acp-agent/pty.cordis.snapshot.yml @@ -14,6 +14,8 @@ name: './pty-snapshot-backend.mjs' - id: tool-pty name: '@deepseek-ai/dsh-tool-pty' + config: + maxResultBytes: 64 - id: llm-replay name: '@deepseek-ai/dsh-llm-replay' config: diff --git a/examples/acp-agent/tests/snapshots/pty-tools/session.jsonl b/examples/acp-agent/tests/snapshots/pty-tools/session.jsonl index f3157d811b..5694ae4343 100644 --- a/examples/acp-agent/tests/snapshots/pty-tools/session.jsonl +++ b/examples/acp-agent/tests/snapshots/pty-tools/session.jsonl @@ -21,7 +21,7 @@ {"type":"assistant/chunk","seq":19,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":20,"time":0,"data":{"turn":1,"step":2,"content":[{"type":"tool-call","id":"pty-send","name":"terminal_send","arguments":"{\"sessionId\":\"pty-1\",\"text\":\"printf 'PTY_OK\\\\n'\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-pro"},"usage":{"inputTokens":10,"outputTokens":5}},"sourceEventSeqs":[15,16,17,18,19],"surfaceOp":"append"} {"type":"tool/call","seq":21,"time":0,"data":{"turn":1,"step":2,"callId":"pty-send","name":"terminal_send","arguments":"{\"sessionId\":\"pty-1\",\"text\":\"printf 'PTY_OK\\\\n'\"}"}} -{"type":"tool/result","seq":22,"time":0,"data":{"turn":1,"step":2,"callId":"pty-send","content":[{"type":"text","text":"printf 'PTY_OK\\n'\nPTY_OK\ndsh> \n[wait: stdin_read]\n[session: running]"}],"isError":false,"meta":{"viewport":"printf 'PTY_OK\\n'\nPTY_OK\ndsh> ","waitReason":"stdin_read","sessionStatus":{"kind":"running"},"truncated":false}},"sourceEventSeqs":[21],"surfaceOp":"append"} +{"type":"tool/result","seq":22,"time":0,"data":{"turn":1,"step":2,"callId":"pty-send","content":[{"type":"text","text":"K\ndsh> \n[wait: stdin_read]\n[session: running]\n[output truncated]"}],"isError":false,"meta":{"viewport":"printf 'PTY_OK\\n'\nPTY_OK\ndsh> ","waitReason":"stdin_read","sessionStatus":{"kind":"running"},"truncated":false}},"sourceEventSeqs":[21],"surfaceOp":"append"} {"type":"step/end","seq":23,"time":0,"data":{"turn":1,"step":2}} {"type":"step/start","seq":24,"time":0,"data":{"turn":1,"step":3}} {"type":"assistant/chunk","seq":25,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}} diff --git a/examples/acp-agent/tests/snapshots/pty-tools/stdout.expected.jsonl b/examples/acp-agent/tests/snapshots/pty-tools/stdout.expected.jsonl index 94cb1f180e..6ecaac24c6 100644 --- a/examples/acp-agent/tests/snapshots/pty-tools/stdout.expected.jsonl +++ b/examples/acp-agent/tests/snapshots/pty-tools/stdout.expected.jsonl @@ -5,7 +5,7 @@ {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"pty-spawn","title":"Open terminal main","kind":"execute","status":"in_progress"}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"pty-spawn","status":"completed","content":[{"type":"content","content":{"type":"text","text":"started terminal session pty-1 (main) [type: shell]\ndsh> "}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"pty-send","title":"printf 'PTY_OK\\n'","kind":"execute","status":"in_progress","rawInput":"printf 'PTY_OK\\n'","content":[{"type":"content","content":{"type":"text","text":"Terminal pty-1"}},{"type":"terminal","terminalId":"pty-send"}],"_meta":{"terminal_info":{"terminal_id":"pty-send","cwd":"{{cwd}}"}}}}} -{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"pty-send","status":"completed","_meta":{"terminal_output":{"terminal_id":"pty-send","data":"printf 'PTY_OK\\n'\nPTY_OK\ndsh> \n[wait: stdin_read]\n[session: running]"}}}}} +{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"pty-send","status":"completed","_meta":{"terminal_output":{"terminal_id":"pty-send","data":"K\ndsh> \n[wait: stdin_read]\n[session: running]\n[output truncated]"}}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"pty-read","title":"Read terminal pty-1","kind":"read","status":"in_progress","rawInput":{"sessionId":"pty-1","offset":0,"count":20}}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"pty-read","status":"completed","content":[{"type":"content","content":{"type":"text","text":"dsh> printf 'PTY_OK\\n'\nPTY_OK\ndsh> \n[lines: 0-3 of 3]"}}]}}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"pty-signal","title":"Signal terminal pty-missing","kind":"execute","status":"in_progress","rawInput":{"sessionId":"pty-missing","signal":"SIGINT"}}}} diff --git a/examples/headless-agent/pty.cordis.snapshot.yml b/examples/headless-agent/pty.cordis.snapshot.yml index f7fcea389a..0de292a8f9 100644 --- a/examples/headless-agent/pty.cordis.snapshot.yml +++ b/examples/headless-agent/pty.cordis.snapshot.yml @@ -14,5 +14,7 @@ name: '../acp-agent/pty-snapshot-backend.mjs' - id: tool-pty name: '@deepseek-ai/dsh-tool-pty' + config: + maxResultBytes: 64 - id: llm-replay name: '@deepseek-ai/dsh-llm-replay' diff --git a/examples/headless-agent/tests/snapshots/pty-tools/session.jsonl b/examples/headless-agent/tests/snapshots/pty-tools/session.jsonl index bad2f0353d..d91782e1e2 100644 --- a/examples/headless-agent/tests/snapshots/pty-tools/session.jsonl +++ b/examples/headless-agent/tests/snapshots/pty-tools/session.jsonl @@ -21,7 +21,7 @@ {"type":"assistant/chunk","seq":19,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}} {"type":"assistant/message","seq":20,"time":0,"data":{"turn":1,"step":2,"content":[{"type":"tool-call","id":"pty-send","name":"terminal_send","arguments":"{\"sessionId\":\"pty-1\",\"text\":\"printf 'PTY_OK\\\\n'\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":10,"outputTokens":5}},"sourceEventSeqs":[15,16,17,18,19],"surfaceOp":"append"} {"type":"tool/call","seq":21,"time":0,"data":{"turn":1,"step":2,"callId":"pty-send","name":"terminal_send","arguments":"{\"sessionId\":\"pty-1\",\"text\":\"printf 'PTY_OK\\\\n'\"}"}} -{"type":"tool/result","seq":22,"time":0,"data":{"turn":1,"step":2,"callId":"pty-send","content":[{"type":"text","text":"printf 'PTY_OK\\n'\nPTY_OK\ndsh> \n[wait: stdin_read]\n[session: running]"}],"isError":false,"meta":{"viewport":"printf 'PTY_OK\\n'\nPTY_OK\ndsh> ","waitReason":"stdin_read","sessionStatus":{"kind":"running"},"truncated":false}},"sourceEventSeqs":[21],"surfaceOp":"append"} +{"type":"tool/result","seq":22,"time":0,"data":{"turn":1,"step":2,"callId":"pty-send","content":[{"type":"text","text":"K\ndsh> \n[wait: stdin_read]\n[session: running]\n[output truncated]"}],"isError":false,"meta":{"viewport":"printf 'PTY_OK\\n'\nPTY_OK\ndsh> ","waitReason":"stdin_read","sessionStatus":{"kind":"running"},"truncated":false}},"sourceEventSeqs":[21],"surfaceOp":"append"} {"type":"step/end","seq":23,"time":0,"data":{"turn":1,"step":2}} {"type":"step/start","seq":24,"time":0,"data":{"turn":1,"step":3}} {"type":"assistant/chunk","seq":25,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}} diff --git a/examples/headless-agent/tests/snapshots/pty-tools/stream-json.expected.jsonl b/examples/headless-agent/tests/snapshots/pty-tools/stream-json.expected.jsonl index b4db490cb2..ab37662dde 100644 --- a/examples/headless-agent/tests/snapshots/pty-tools/stream-json.expected.jsonl +++ b/examples/headless-agent/tests/snapshots/pty-tools/stream-json.expected.jsonl @@ -20,7 +20,7 @@ {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":19,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":20,"time":0,"data":{"turn":1,"step":2,"content":[{"type":"tool-call","id":"pty-send","name":"terminal_send","arguments":"{\"sessionId\":\"pty-1\",\"text\":\"printf 'PTY_OK\\\\n'\"}"}],"provenance":{"provider":"deepseek","model":"deepseek-v4-flash"},"usage":{"inputTokens":10,"outputTokens":5}},"sourceEventSeqs":[15,16,17,18,19],"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":21,"time":0,"data":{"turn":1,"step":2,"callId":"pty-send","name":"terminal_send","arguments":"{\"sessionId\":\"pty-1\",\"text\":\"printf 'PTY_OK\\\\n'\"}"}}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":22,"time":0,"data":{"turn":1,"step":2,"callId":"pty-send","content":[{"type":"text","text":"printf 'PTY_OK\\n'\nPTY_OK\ndsh> \n[wait: stdin_read]\n[session: running]"}],"isError":false,"meta":{"viewport":"printf 'PTY_OK\\n'\nPTY_OK\ndsh> ","waitReason":"stdin_read","sessionStatus":{"kind":"running"},"truncated":false}},"sourceEventSeqs":[21],"surfaceOp":"append"}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":22,"time":0,"data":{"turn":1,"step":2,"callId":"pty-send","content":[{"type":"text","text":"K\ndsh> \n[wait: stdin_read]\n[session: running]\n[output truncated]"}],"isError":false,"meta":{"viewport":"printf 'PTY_OK\\n'\nPTY_OK\ndsh> ","waitReason":"stdin_read","sessionStatus":{"kind":"running"},"truncated":false}},"sourceEventSeqs":[21],"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":23,"time":0,"data":{"turn":1,"step":2}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":24,"time":0,"data":{"turn":1,"step":3}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":25,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}} diff --git a/packages/cordis/tool-cordis/src/api-catalog.ts b/packages/cordis/tool-cordis/src/api-catalog.ts index 7a8e8abdf3..a454623486 100644 --- a/packages/cordis/tool-cordis/src/api-catalog.ts +++ b/packages/cordis/tool-cordis/src/api-catalog.ts @@ -402,6 +402,10 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ signature: 'async spawn(owner: Agent, request: PtySpawnRequest, signal?: AbortSignal): Promise<PtySpawnResult>', jsDoc: '/**\n * Create and publish one owner-scoped session after backend setup succeeds.\n * @param owner - exact registered Agent that owns access and cleanup.\n * @param request - backend type plus optional owner-local name and cwd.\n * @param signal - cancellation of unpublished setup.\n * @returns published identity, metadata, status, and MOTD.\n */', }, + { + signature: 'hasOwnerActivity(owner: Agent): boolean', + jsDoc: '/**\n * Test whether an exact owner has a published session or unpublished spawn.\n * @param owner - exact live owner to inspect.\n * @returns true across the entire spawn-to-close interval, with no publication gap.\n */', + }, { signature: 'startSend(owner: Agent, id: PtySessionId, request: PtySendRequest): PtySendOperation', jsDoc: '/**\n * Start one exclusive interactive send.\n * @param owner - exact session owner.\n * @param id - target PTY identity.\n * @param request - explicit text, submit behavior, and cancellation.\n * @returns live operation handle for foreground await or task registration.\n */', @@ -1854,11 +1858,11 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'TaskSnapshot', - declaration: 'export interface TaskSnapshot {\n id: TaskId;\n kind: TaskKind;\n label: string;\n ownerSession?: SessionId;\n status: TaskStatus;\n detail?: string;\n startedAt: number;\n finishedAt?: number;\n reported: boolean;\n}', + declaration: 'export interface TaskSnapshot {\n id: TaskId;\n kind: TaskKind;\n label: string;\n outputLimitBytes?: number;\n ownerSession?: SessionId;\n status: TaskStatus;\n detail?: string;\n startedAt: number;\n finishedAt?: number;\n reported: boolean;\n}', }, { name: 'TaskStart', - declaration: 'export interface TaskStart {\n kind: TaskKind;\n label: string;\n owner?: Agent;\n run(): TaskHooks;\n}', + declaration: 'export interface TaskStart {\n kind: TaskKind;\n label: string;\n outputLimitBytes?: number;\n owner?: Agent;\n run(): TaskHooks;\n}', }, { name: 'TaskStatus', diff --git a/packages/pty/pty-local/README.md b/packages/pty/pty-local/README.md index 00cd1b8b00..32b2721074 100644 --- a/packages/pty/pty-local/README.md +++ b/packages/pty/pty-local/README.md @@ -4,9 +4,11 @@ Local `node-pty` backend for `ctx.pty`. It starts an interactive shell under the ## Plugin (`pty-local`) -The plugin injects `pty`, `sandbox`, and `sandboxPolicy`, then registers the configured backend type (`shell`). `danger-full-access` starts the shell directly; confined modes wrap the exact shell argv through `ctx.sandbox`. The current session-level sandbox override is resolved at spawn and remains fixed for the PTY lifetime. +The plugin injects `agents`, `pty`, `sandbox`, and `sandboxPolicy`, then registers the configured backend type (`shell`). `danger-full-access` starts the shell directly; confined modes wrap the exact shell argv through `ctx.sandbox`. The effective session mode is resolved at spawn. A change to a different effective mode is rejected before its `sandbox/mode` event commits while that owner has an open PTY or a spawn in progress; wait for creation to settle and close the sessions before changing modes, so a terminal opened with wider access cannot survive a downgrade. -Linux readiness combines a foreground-verified private bash prompt marker, foreground-process-group syscall inspection, silence fallback, and absolute timeout. macOS uses the verified prompt marker plus silence/timeout because it has no `/proc` syscall surface. Unrecognized or unreadable process state is never a positive exact-idle signal. During unpublished startup, a fallback requires observed output; zero-output silence cannot publish an empty session, and timeout rejects the spawn. Incomplete terminal-control sequences are bounded by `maxReadBytes` and discarded through their terminator after crossing that limit. +Linux readiness combines a foreground-verified private bash prompt marker, foreground-process-group syscall inspection, silence fallback, and absolute timeout. macOS uses the verified prompt marker plus silence/timeout because it has no `/proc` syscall surface. A marker is not ready until printable prompt text arrives, including when the OSC marker and `PS1` are split across data callbacks. Unrecognized or unreadable process state is never a positive exact-idle signal. During unpublished startup, a fallback requires observed output; zero-output silence cannot publish an empty session, and timeout rejects the spawn. Incomplete terminal-control sequences are bounded by `maxReadBytes` and discarded through their terminator after crossing that limit; a trailing carriage return is carried across callbacks so split CRLF becomes one newline. + +Send cancellation resolves the current foreground process group and delivers a real `SIGINT`; it never emulates interruption by writing `\x03`, so raw-mode programs remain cancellable. Close sends `SIGTERM` to descendants, waits, rescans and sends `SIGKILL` to the remaining tree, verifies that descendants left the process table while the shell can still reap them, and only then stops the shell. A survivor failure does not cache a permanently rejected close; a later close retries the teardown. ## Model Experience diff --git a/packages/pty/pty-local/package.json b/packages/pty/pty-local/package.json index 339c3916ad..fb26d845e5 100644 --- a/packages/pty/pty-local/package.json +++ b/packages/pty/pty-local/package.json @@ -30,10 +30,12 @@ }, "license": "BSD-3-Clause", "peerDependencies": { + "@deepseek-ai/dsh-agent": "^0.0.1", "@deepseek-ai/dsh-invariants": "^0.0.1", "@deepseek-ai/dsh-pty": "^0.0.1", "@deepseek-ai/dsh-sandbox": "^0.0.1", "@deepseek-ai/dsh-sandbox-policy": "^0.0.1", + "@deepseek-ai/dsh-session": "^0.0.1", "cordis": "^4.0.0-rc.7" }, "dependencies": { diff --git a/packages/pty/pty-local/src/index.ts b/packages/pty/pty-local/src/index.ts index 0b99d1b058..706a1bba7a 100644 --- a/packages/pty/pty-local/src/index.ts +++ b/packages/pty/pty-local/src/index.ts @@ -7,6 +7,7 @@ import { Context } from 'cordis' import * as nodePty from 'node-pty' import type { IPtyForkOptions } from 'node-pty' +import type { Session, SessionEvent } from '@deepseek-ai/dsh-session' import type { PtyBackend, PtyBackendSpawnSpec } from '@deepseek-ai/dsh-pty' import type { SandboxMode } from '@deepseek-ai/dsh-sandbox' import { effectiveSandboxMode } from '@deepseek-ai/dsh-sandbox-policy' @@ -20,8 +21,8 @@ export type { Config as PtyLocalConfig } from './config.ts' /** Cordis plugin name. */ export const name = 'pty-local' -/** Required services: registry plus the one shared confinement policy. */ -export const inject = ['pty', 'sandbox', 'sandboxPolicy'] +/** Required services: owner/PTY registries plus the one shared confinement policy. */ +export const inject = ['agents', 'pty', 'sandbox', 'sandboxPolicy'] const SENSITIVE_ENV_PATTERN = /KEY|SECRET|TOKEN/i @@ -73,7 +74,7 @@ export class LocalPtyBackend implements PtyBackend { } async spawn(spec: PtyBackendSpawnSpec): Promise<LocalPtySession> { - if (spec.signal?.aborted === true) throw new Error('PTY spawn aborted') + spec.signal?.throwIfAborted() const argv = spawnArgv(this.ctx, this.config, spec) const file = argv[0] if (file === undefined) throw new Error('pty-local: sandbox returned empty argv') @@ -105,4 +106,17 @@ export function apply(ctx: Context, config: Config): void { validateConfig(config) const inspector = createProcessInspector() ctx.pty.registerBackend(new LocalPtyBackend(ctx, config, inspector)) + ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') return + const [session, event] = args as [Session, SessionEvent] + if (event.type !== 'sandbox/mode') return + const currentMode = effectiveSandboxMode(session.events) ?? ctx.sandboxPolicy.defaultMode + if (event.data.mode === currentMode) return + const owner = ctx.agents.get(session.id) + if (owner === undefined) return + if (!ctx.pty.hasOwnerActivity(owner)) return + throw new Error( + `cannot change sandbox mode from "${currentMode}" to "${event.data.mode}" while persistent terminal sessions are open or being created; wait for creation to settle and close them first`, + ) + }, { global: true }) } diff --git a/packages/pty/pty-local/src/sanitize.ts b/packages/pty/pty-local/src/sanitize.ts index 6e109f6115..cc22c29c01 100644 --- a/packages/pty/pty-local/src/sanitize.ts +++ b/packages/pty/pty-local/src/sanitize.ts @@ -9,6 +9,8 @@ export const PROMPT_MARKER_PREFIX = '133;D;' export interface SanitizedChunk { text: string prompt: boolean + /** Present when printable text followed the latest owned prompt marker. */ + promptText?: true } /** @@ -20,6 +22,8 @@ export class TerminalSanitizer { private pending = '' private discardMode: 'osc' | 'csi' | undefined private discardOscEscape = false + private trailingCarriageReturn = false + private awaitingPromptText = false constructor(private readonly maxPendingBytes: number) {} @@ -32,15 +36,24 @@ export class TerminalSanitizer { this.pending += this.discardPrefix(chunk) let text = '' let prompt = false + let promptText = false let index = 0 + const appendText = (value: string): boolean => { + text += value + if (this.awaitingPromptText && value.replace(/[\r\n\x07]/g, '').length > 0) { + this.awaitingPromptText = false + return true + } + return false + } while (index < this.pending.length) { const escape = this.pending.indexOf('\x1b', index) if (escape < 0) { - text += this.pending.slice(index) + promptText = appendText(this.pending.slice(index)) || promptText index = this.pending.length break } - text += this.pending.slice(index, escape) + promptText = appendText(this.pending.slice(index, escape)) || promptText if (escape + 1 >= this.pending.length) { index = escape break @@ -59,7 +72,11 @@ export class TerminalSanitizer { } const terminatorBytes = this.pending[end - 1] === '\x07' ? 1 : 2 const content = this.pending.slice(escape + 2, end - terminatorBytes) - if (content.startsWith(PROMPT_MARKER_PREFIX)) prompt = true + if (content.startsWith(PROMPT_MARKER_PREFIX)) { + prompt = true + promptText = false + this.awaitingPromptText = true + } index = end continue } @@ -82,7 +99,7 @@ export class TerminalSanitizer { } this.pending = this.pending.slice(index) this.enforcePendingBound() - return { text: normalizeTerminalText(text), prompt } + return { text: this.normalizeText(text), prompt, ...promptText ? { promptText: true } : {} } } /** @@ -94,7 +111,21 @@ export class TerminalSanitizer { this.pending = '' this.discardMode = undefined this.discardOscEscape = false - return normalizeTerminalText(text) + this.awaitingPromptText = false + const normalized = this.normalizeText(text) + if (!this.trailingCarriageReturn) return normalized + this.trailingCarriageReturn = false + return `${normalized}\n` + } + + private normalizeText(text: string): string { + let complete = this.trailingCarriageReturn ? `\r${text}` : text + this.trailingCarriageReturn = false + if (complete.endsWith('\r')) { + complete = complete.slice(0, -1) + this.trailingCarriageReturn = true + } + return normalizeTerminalText(complete) } private enforcePendingBound(): void { diff --git a/packages/pty/pty-local/src/session.ts b/packages/pty/pty-local/src/session.ts index 52863db674..a1e638e0d2 100644 --- a/packages/pty/pty-local/src/session.ts +++ b/packages/pty/pty-local/src/session.ts @@ -17,7 +17,7 @@ import type { PtyWaitReason, } from '@deepseek-ai/dsh-pty' import type { ResolvedConfig } from './config.ts' -import type { ProcessInspector } from './process-inspector.ts' +import type { ProcessIdentity, ProcessInspector } from './process-inspector.ts' import { TerminalSanitizer } from './sanitize.ts' function delay(ms: number): Promise<void> { @@ -148,9 +148,11 @@ export class LocalPtySession implements PtyBackendSession { private activeTimer: NodeJS.Timeout | undefined private activeAbort: (() => void) | undefined private promptSeen = false + private promptTextSeen = false private shellPgid: number | undefined private initializing = false private lastOutputAt = Date.now() + private closing = false private closePromise: Promise<void> | undefined constructor( @@ -190,21 +192,20 @@ export class LocalPtySession implements PtyBackendSession { } startSend(request: PtySendRequest): PtySendOperation { - if (this.closePromise !== undefined) throw new Error('PTY session is closing') + if (this.closing) throw new Error('PTY session is closing') if (this.statusValue.kind === 'exited') throw new Error('PTY session has exited') if (this.active !== undefined) throw new Error('PTY session already has an active send') if (request.signal?.aborted === true) throw new Error('PTY send aborted before write') - const operation = new LocalSendOperation(this.config.maxReadBytes, Date.now(), () => { - try { - this.terminal.write('\x03') - } catch (error: unknown) { - operation.fail(error) - } - }) + const operation = new LocalSendOperation( + this.config.maxReadBytes, + Date.now(), + () => { this.interrupt(operation) }, + ) this.active = operation this.lastOutputAt = Date.now() this.promptSeen = false + this.promptTextSeen = false if (request.signal !== undefined) { const onAbort = (): void => { operation.cancel() } @@ -267,8 +268,15 @@ export class LocalPtySession implements PtyBackendSession { } close(reason: string): Promise<void> { - this.closePromise ??= this.closeOnce(reason) - return this.closePromise + this.closing = true + if (this.closePromise !== undefined) return this.closePromise + const closing = this.closeOnce(reason).catch((error: unknown) => { + this.closePromise = undefined + this.failActive(error) + throw error + }) + this.closePromise = closing + return closing } private onData(data: string): void { @@ -279,8 +287,11 @@ export class LocalPtySession implements PtyBackendSession { if (this.shellPgid === undefined) this.shellPgid = foregroundPgid if (foregroundPgid !== undefined && foregroundPgid === this.shellPgid) { this.promptSeen = true + this.promptTextSeen = sanitized.promptText === true this.lastOutputAt = Date.now() } + } else if (this.promptSeen && sanitized.promptText === true) { + this.promptTextSeen = true } } @@ -297,7 +308,7 @@ export class LocalPtySession implements PtyBackendSession { this.settleActive('session_exit') return } - if (this.promptSeen && Date.now() - this.lastOutputAt >= this.config.pollIntervalMs) { + if (this.promptSeen && this.promptTextSeen && Date.now() - this.lastOutputAt >= this.config.pollIntervalMs) { this.settleActive('stdin_read') return } @@ -337,58 +348,98 @@ export class LocalPtySession implements PtyBackendSession { this.active = undefined } + private failActive(error: unknown): void { + const operation = this.active + if (operation === undefined) return + this.clearActive() + operation.fail(error) + } + + private interrupt(operation: LocalSendOperation): void { + if (this.active !== operation) return + try { + const pgid = this.inspector.foregroundPgid(this.pid) + if (pgid === undefined) throw new Error(`cannot resolve foreground process group for PTY ${this.pid}`) + this.inspector.signalGroup(pgid, 'SIGINT') + } catch (error: unknown) { + this.failActive(error) + } + } + + private survivors(members: ProcessIdentity[]): ProcessIdentity[] { + return members.filter(member => this.inspector.isAlive(member)) + } + + private descendants(): ProcessIdentity[] { + return this.inspector.processTree(this.pid).filter(member => member.pid !== this.pid) + } + + private async waitForExit(members: ProcessIdentity[]): Promise<ProcessIdentity[]> { + const deadline = Date.now() + this.config.disposeGraceMs + let survivors = this.survivors(members) + while (survivors.length > 0 && Date.now() < deadline) { + await delay(Math.min(25, Math.max(1, deadline - Date.now()))) + survivors = this.survivors(members) + } + return survivors + } + + private signalMembers(members: ProcessIdentity[], signal: 'SIGTERM' | 'SIGKILL'): void { + for (const member of members) { + try { + this.inspector.signalProcess(member, signal) + } catch (_alreadyExitedDuringSignal) { + // Identity is rechecked by the inspector; a same-tick exit is success. + } + } + } + + private async stopDescendants(): Promise<ProcessIdentity[]> { + let members = this.descendants() + this.signalMembers(members, 'SIGTERM') + await this.waitForExit(members) + // A TERM-handling descendant may have forked while winding down. Rescan + // while the shell can still reap every member, then kill the fresh tree. + members = this.descendants() + this.signalMembers(members, 'SIGKILL') + await this.waitForExit(members) + return this.descendants().filter(member => this.inspector.isAlive(member)) + } + + private async stopShell(): Promise<void> { + try { + this.terminal.kill('SIGTERM') + } catch (_topLevelAlreadyExitedDuringTerm) { + // The exit notification remains authoritative. + } + if (this.statusValue.kind === 'running') { + await Promise.race([this.exitPromise.promise, delay(this.config.disposeGraceMs)]) + } + if (this.statusValue.kind === 'running') { + try { + this.terminal.kill('SIGKILL') + } catch (_topLevelAlreadyExitedDuringKill) { + // The exit notification remains authoritative. + } + await Promise.race([this.exitPromise.promise, delay(this.config.disposeGraceMs)]) + } + if (this.statusValue.kind === 'running') { + throw new Error(`PTY cleanup failed; surviving pids: ${this.pid}`) + } + } + private async closeOnce(reason: string): Promise<void> { this.dataDisposable.dispose() // Stop readiness polling but retain the active operation: teardown settles // it as session_exit below, so an in-flight send is never mis-settled as // stdin_read/inferred_idle/timeout during the grace period. this.stopPolling() - const members = this.inspector.processTree(this.pid) - for (const member of members) { - try { - this.inspector.signalProcess(member, 'SIGTERM') - } catch (_alreadyExitedDuringTerm) { - // Identity is rechecked by the inspector; a same-tick exit is success. - } - } - try { - this.terminal.kill('SIGTERM') - } catch (_topLevelAlreadyExited) { - // onExit or identity checks below remain authoritative. - } - - const deadline = Date.now() + this.config.disposeGraceMs - let survivors = members.filter(member => this.inspector.isAlive(member)) - while (survivors.length > 0 && Date.now() < deadline) { - await delay(Math.min(25, this.config.disposeGraceMs)) - survivors = members.filter(member => this.inspector.isAlive(member)) - } - for (const survivor of survivors) { - try { - this.inspector.signalProcess(survivor, 'SIGKILL') - } catch (_alreadyExitedDuringKill) { - // Final identity check below decides success. - } - } - try { - this.terminal.kill('SIGKILL') - } catch (_topLevelAlreadyKilled) { - // The root may already have delivered onExit. - } - - const killDeadline = Date.now() + this.config.disposeGraceMs - survivors = members.filter(member => this.inspector.isAlive(member)) - while (survivors.length > 0 && Date.now() < killDeadline) { - await delay(Math.min(25, this.config.disposeGraceMs)) - survivors = members.filter(member => this.inspector.isAlive(member)) - } - const exitWaitMs = Math.max(0, killDeadline - Date.now()) - await Promise.race([this.exitPromise.promise, delay(exitWaitMs)]) - survivors = members.filter(member => this.inspector.isAlive(member)) - this.settleActive('session_exit') - this.exitDisposable.dispose() + const survivors = await this.stopDescendants() if (survivors.length > 0) { throw new Error(`PTY cleanup failed (${reason}); surviving pids: ${survivors.map(member => member.pid).join(', ')}`) } + await this.stopShell() + this.settleActive('session_exit') + this.exitDisposable.dispose() } } diff --git a/packages/pty/pty-local/tests/index.spec.ts b/packages/pty/pty-local/tests/index.spec.ts index 1273824033..55cc134787 100644 --- a/packages/pty/pty-local/tests/index.spec.ts +++ b/packages/pty/pty-local/tests/index.spec.ts @@ -2,12 +2,14 @@ import { describe, expect, it, vi } from 'vitest' import type { IPty, IPtyForkOptions } from 'node-pty' import { Context } from 'cordis' import Loader from '@cordisjs/plugin-loader' -import { Session, SessionId } from '@deepseek-ai/dsh-session' +import SessionStore, { Session, SessionId } from '@deepseek-ai/dsh-session' +import AgentRegistry from '@deepseek-ai/dsh-agent' import type { Agent } from '@deepseek-ai/dsh-agent' import SandboxProvider from '@deepseek-ai/dsh-sandbox' import type { ConfinedArgv, SandboxPolicy } from '@deepseek-ai/dsh-sandbox' -import SandboxPolicyService from '@deepseek-ai/dsh-sandbox-policy' +import SandboxPolicyService, { setSandboxMode } from '@deepseek-ai/dsh-sandbox-policy' import PtyService, { PtySessionId } from '@deepseek-ai/dsh-pty' +import type { PtyBackendSession } from '@deepseek-ai/dsh-pty' import { LocalPtyBackend } from '@deepseek-ai/dsh-pty-local' import * as ptyLocal from '@deepseek-ai/dsh-pty-local' import type { ResolvedConfig } from '@deepseek-ai/dsh-pty-local/src/config.ts' @@ -69,8 +71,9 @@ describe('LocalPtyBackend startup rollback', () => { await ctx.plugin(SandboxPolicyService, { mode: 'read-only', workspaceRoot: '/tmp' }) const backend = new LocalPtyBackend(ctx, config(), inspector) const controller = new AbortController() - controller.abort() - await expect(backend.spawn(spec(agent(ctx), controller.signal))).rejects.toThrow('spawn aborted') + const abortReason = new Error('spawn aborted') + controller.abort(abortReason) + await expect(backend.spawn(spec(agent(ctx), controller.signal))).rejects.toBe(abortReason) await expect(backend.spawn(spec(agent(ctx)))).rejects.toThrow('empty argv') }) @@ -169,12 +172,13 @@ describe('pty-local plugin shape', () => { const loader = Object.create(Loader.prototype) as Loader const unwrapped = loader.unwrapExports(ptyLocal) as Record<string, unknown> expect(unwrapped.name).toBe('pty-local') - expect(unwrapped.inject).toEqual(['pty', 'sandbox', 'sandboxPolicy']) + expect(unwrapped.inject).toEqual(['agents', 'pty', 'sandbox', 'sandboxPolicy']) expect(unwrapped.Config).toBeDefined() }) it('validates config and registers the configured backend', async () => { const ctx = new Context() + await ctx.plugin(AgentRegistry) await ctx.plugin(PtyService) await ctx.plugin(EmptySandbox) await ctx.plugin(SandboxPolicyService, { mode: 'danger-full-access', workspaceRoot: '/tmp' }) @@ -183,4 +187,91 @@ describe('pty-local plugin shape', () => { await fiber.dispose() expect(ctx.pty.listBackends()).toEqual([]) }) + + it('ignores unrelated session events and mode changes without a live owner', async () => { + const ctx = new Context() + await ctx.plugin(SessionStore) + await ctx.plugin(AgentRegistry) + await ctx.plugin(PtyService) + await ctx.plugin(EmptySandbox) + await ctx.plugin(SandboxPolicyService, { mode: 'danger-full-access', workspaceRoot: '/tmp' }) + await ctx.plugin(ptyLocal, config()) + + const session = ctx.sessions.create(SessionId('unowned-mode')) + expect(() => { + session.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } }) + }).not.toThrow() + expect(() => { setSandboxMode(session, 'read-only') }).not.toThrow() + }) + + it('rejects an effective sandbox-mode change until the owner closes live terminals', async () => { + const ctx = new Context() + await ctx.plugin(SessionStore) + await ctx.plugin(AgentRegistry) + await ctx.plugin(PtyService) + await ctx.plugin(EmptySandbox) + await ctx.plugin(SandboxPolicyService, { mode: 'danger-full-access', workspaceRoot: '/tmp' }) + await ctx.plugin(ptyLocal, config()) + + const session = ctx.sessions.create(SessionId('mode-owner')) + const owner: Agent = { + id: session.id, options: {}, session, status: 'idle', ctx, + send() {}, steer() {}, inject() {}, cancel() {}, whenIdle: () => Promise.resolve(), + } + ctx.agents.register(owner) + const backendSession = { + motd: '', + startSend: () => { throw new Error('unused') }, + read: () => { throw new Error('unused') }, + signal: () => Promise.resolve({ delivered: true, targetPgid: 1 }), + status: () => ({ kind: 'running' as const }), + close: () => Promise.resolve(), + } satisfies PtyBackendSession + ctx.pty.registerBackend({ type: 'stub', spawn: () => Promise.resolve(backendSession) }) + const created = await ctx.pty.spawn(owner, { type: 'stub' }) + + expect(() => { setSandboxMode(session, 'danger-full-access') }).not.toThrow() + expect(() => { setSandboxMode(session, 'read-only') }).toThrow( + 'cannot change sandbox mode from "danger-full-access" to "read-only" while persistent terminal sessions are open or being created; wait for creation to settle and close them first', + ) + expect(session.events.filter(event => event.type === 'sandbox/mode')).toHaveLength(1) + + await ctx.pty.kill(owner, created.sessionId) + expect(() => { setSandboxMode(session, 'read-only') }).not.toThrow() + expect(session.events.filter(event => event.type === 'sandbox/mode')).toHaveLength(2) + }) + + it('also fences sandbox-mode changes across unpublished PTY creation', async () => { + const ctx = new Context() + await ctx.plugin(SessionStore) + await ctx.plugin(AgentRegistry) + await ctx.plugin(PtyService) + await ctx.plugin(EmptySandbox) + await ctx.plugin(SandboxPolicyService, { mode: 'danger-full-access', workspaceRoot: '/tmp' }) + await ctx.plugin(ptyLocal, config()) + + const session = ctx.sessions.create(SessionId('pending-mode-owner')) + const owner: Agent = { + id: session.id, options: {}, session, status: 'idle', ctx, + send() {}, steer() {}, inject() {}, cancel() {}, whenIdle: () => Promise.resolve(), + } + ctx.agents.register(owner) + const gate = Promise.withResolvers<PtyBackendSession>() + ctx.pty.registerBackend({ type: 'slow', spawn: () => gate.promise }) + const spawning = ctx.pty.spawn(owner, { type: 'slow' }) + + expect(ctx.pty.hasOwnerActivity(owner)).toBe(true) + expect(() => { setSandboxMode(session, 'read-only') }).toThrow('open or being created') + gate.resolve({ + motd: '', + startSend: () => { throw new Error('unused') }, + read: () => { throw new Error('unused') }, + signal: () => Promise.resolve({ delivered: true, targetPgid: 1 }), + status: () => ({ kind: 'running' as const }), + close: () => Promise.resolve(), + }) + const created = await spawning + await ctx.pty.kill(owner, created.sessionId) + expect(ctx.pty.hasOwnerActivity(owner)).toBe(false) + }) }) diff --git a/packages/pty/pty-local/tests/local.spec.ts b/packages/pty/pty-local/tests/local.spec.ts index 0ff5aebf35..182e2aae19 100644 --- a/packages/pty/pty-local/tests/local.spec.ts +++ b/packages/pty/pty-local/tests/local.spec.ts @@ -7,6 +7,7 @@ import { Session, SessionId } from '@deepseek-ai/dsh-session' import AgentRegistry from '@deepseek-ai/dsh-agent' import type { Agent } from '@deepseek-ai/dsh-agent' import PtyService from '@deepseek-ai/dsh-pty' +import type { PtySendOperation } from '@deepseek-ai/dsh-pty' import SandboxProvider from '@deepseek-ai/dsh-sandbox' import type { ConfinedArgv, SandboxPolicy } from '@deepseek-ai/dsh-sandbox' import SandboxPolicyService from '@deepseek-ai/dsh-sandbox-policy' @@ -62,6 +63,16 @@ async function harness(mode: 'danger-full-access' | 'workspace-write') { return { ctx, root, agent, fiber, sandbox: ctx.sandbox as PassthroughSandbox } } +async function waitForOutput(operation: PtySendOperation, expected: string): Promise<void> { + const deadline = Date.now() + 2_000 + let output = '' + while (!output.includes(expected) && Date.now() < deadline) { + output += operation.readOutput().delta + if (!output.includes(expected)) await new Promise(resolve => setTimeout(resolve, 10)) + } + expect(output).toContain(expected) +} + describe('pty-local real shell', () => { it('persists cwd and environment across sends, scrubs secrets, and closes', async () => { const previous = process.env.DSH_TEST_SECRET @@ -119,4 +130,26 @@ describe('pty-local real shell', () => { await ctx.pty.kill(agent, created.sessionId) expect(() => process.kill(pid, 0)).toThrow() }, 10_000) + + it('cancels a raw-mode foreground process with a real SIGINT', async () => { + const { ctx, agent } = await harness('danger-full-access') + const created = await ctx.pty.spawn(agent, { type: 'shell' }) + const controller = new AbortController() + const foreground = ctx.pty.startSend(agent, created.sessionId, { + text: 'python3 -c \'import signal,sys,termios,time; signal.signal(signal.SIGINT, lambda *_: (print("SIGINT_SEEN", flush=True), sys.exit(0))); attrs=termios.tcgetattr(0); attrs[3] &= ~termios.ISIG; termios.tcsetattr(0, termios.TCSANOW, attrs); print("RAW_READY", flush=True); time.sleep(60)\'', + submit: true, + signal: controller.signal, + }) + await waitForOutput(foreground, 'RAW_READY') + controller.abort() + const result = await foreground.done + expect(result.waitReason).toBe('stdin_read') + const after = await ctx.pty.startSend(agent, created.sessionId, { + text: 'echo AFTER_SIGINT', + submit: true, + }).done + expect(after.viewport).toContain('AFTER_SIGINT') + expect(after.waitReason).toBe('stdin_read') + await ctx.pty.kill(agent, created.sessionId) + }, 10_000) }) diff --git a/packages/pty/pty-local/tests/sanitize.spec.ts b/packages/pty/pty-local/tests/sanitize.spec.ts index eee994e1e5..4da4ab0d73 100644 --- a/packages/pty/pty-local/tests/sanitize.spec.ts +++ b/packages/pty/pty-local/tests/sanitize.spec.ts @@ -7,7 +7,7 @@ describe('TerminalSanitizer', () => { expect(sanitizer.push('red\x1b[3')).toEqual({ text: 'red', prompt: false }) expect(sanitizer.push('1m text\x1b[0m\r\n')).toEqual({ text: ' text\n', prompt: false }) expect(sanitizer.push('\x1b]133;')).toEqual({ text: '', prompt: false }) - expect(sanitizer.push('D;0\x07dsh> ')).toEqual({ text: 'dsh> ', prompt: true }) + expect(sanitizer.push('D;0\x07dsh> ')).toEqual({ text: 'dsh> ', prompt: true, promptText: true }) }) it('drops unrelated OSC, short escapes, BEL, and incomplete trailing escape', () => { @@ -25,6 +25,20 @@ describe('TerminalSanitizer', () => { expect(normalizeTerminalText('a\r\nb\rc\x07')).toBe('a\nb\nc') }) + it('carries a trailing carriage return across data chunks and flushes standalone CR', () => { + const sanitizer = new TerminalSanitizer(64) + expect(sanitizer.push('a\r')).toEqual({ text: 'a', prompt: false }) + expect(sanitizer.push('\nb')).toEqual({ text: '\nb', prompt: false }) + expect(sanitizer.push('\r')).toEqual({ text: '', prompt: false }) + expect(sanitizer.flush()).toBe('\n') + }) + + it('reports printable prompt text that follows a marker in a later chunk', () => { + const sanitizer = new TerminalSanitizer(64) + expect(sanitizer.push('\x1b]133;D;0\x07')).toEqual({ text: '', prompt: true }) + expect(sanitizer.push('dsh> ')).toEqual({ text: 'dsh> ', prompt: false, promptText: true }) + }) + it('bounds and discards unterminated control sequences through their terminators', () => { const oscBel = new TerminalSanitizer(8) expect(oscBel.push(`\x1b]0;${'x'.repeat(16)}`)).toEqual({ text: '', prompt: false }) diff --git a/packages/pty/pty-local/tests/session.spec.ts b/packages/pty/pty-local/tests/session.spec.ts index 562aaf4eb3..42d634e368 100644 --- a/packages/pty/pty-local/tests/session.spec.ts +++ b/packages/pty/pty-local/tests/session.spec.ts @@ -15,6 +15,7 @@ class FakeTerminal { kills: string[] = [] throwWrite = false throwKill = false + autoExitOnKill = true private dataListeners = new Set<(data: string) => void>() private exitListeners = new Set<(event: { exitCode: number; signal?: number }) => void>() @@ -44,7 +45,7 @@ class FakeTerminal { kill(signal?: string): void { if (this.throwKill) throw new Error('kill failed') this.kills.push(signal ?? 'SIGHUP') - this.emitExit(0, signal === 'SIGKILL' ? 9 : 15) + if (this.autoExitOnKill) this.emitExit(0, signal === 'SIGKILL' ? 9 : 15) } resize() {} @@ -148,7 +149,7 @@ describe('LocalPtySession readiness and output', () => { expect(() => session.startSend({ text: '', submit: false })).toThrow('has exited') }) - it('cancels with Ctrl-C, observes AbortSignal, and contains write failures', async () => { + it('cancels with foreground-group SIGINT, observes AbortSignal, and contains write failures', async () => { vi.useFakeTimers() const terminal = new FakeTerminal() const inspector = new FakeInspector() @@ -159,7 +160,8 @@ describe('LocalPtySession readiness and output', () => { const operation = session.startSend({ text: 'sleep', submit: true, signal: controller.signal }) expect(() => session.startSend({ text: 'again', submit: true })).toThrow('active send') controller.abort() - expect(terminal.writes.at(-1)).toBe('\x03') + expect(inspector.groups).toContainEqual([456, 'SIGINT']) + expect(terminal.writes).not.toContain('\x03') terminal.emitData('\x1b]133;D;130\x07dsh> ') await vi.advanceTimersByTimeAsync(10) await operation.done @@ -196,11 +198,13 @@ describe('LocalPtySession readiness and output', () => { operationInternal.append('') const sessionInternal = session as unknown as { pollReadiness(operation: PtySendOperation): void + interrupt(operation: PtySendOperation): void statusValue: PtySessionStatus appendOutput(text: string): void } sessionInternal.appendOutput('') sessionInternal.pollReadiness({} as PtySendOperation) + sessionInternal.interrupt({} as PtySendOperation) sessionInternal.statusValue = { kind: 'exited', exitCode: 2, signal: null } sessionInternal.pollReadiness(operation) await operation.done @@ -212,12 +216,23 @@ describe('LocalPtySession readiness and output', () => { expect(unknown.status()).toEqual({ kind: 'exited', exitCode: 1, signal: null }) const cancelTerminal = new FakeTerminal() - const cancel = new LocalPtySession(cancelTerminal.asPty(), new FakeInspector(), config()) + const cancelInspector = new FakeInspector() + const cancel = new LocalPtySession(cancelTerminal.asPty(), cancelInspector, config()) await initialize(cancel, cancelTerminal) const cancellable = cancel.startSend({ text: '', submit: false }) - cancelTerminal.throwWrite = true + cancelInspector.throwGroup = true expect(cancellable.cancel()).toBe(true) - await expect(cancellable.done).rejects.toThrow('write failed') + await expect(cancellable.done).rejects.toThrow('group failed') + expect(cancellable.cancel()).toBe(false) + + const missingGroupTerminal = new FakeTerminal() + const missingGroupInspector = new FakeInspector() + const missingGroup = new LocalPtySession(missingGroupTerminal.asPty(), missingGroupInspector, config()) + await initialize(missingGroup, missingGroupTerminal) + missingGroupInspector.pgid = undefined + const unresolved = missingGroup.startSend({ text: '', submit: false }) + expect(unresolved.cancel()).toBe(true) + await expect(unresolved.done).rejects.toThrow('cannot resolve foreground process group') }) it('does not treat zero-output startup silence as readiness and fails on startup timeout', async () => { @@ -239,6 +254,23 @@ describe('LocalPtySession readiness and output', () => { await timedOut }) + it('waits for printable prompt text when the startup marker is split from PS1', async () => { + vi.useFakeTimers() + const terminal = new FakeTerminal() + const session = new LocalPtySession(terminal.asPty(), new FakeInspector(), config()) + let settled = false + const initializing = session.initialize().then(() => { settled = true }) + + terminal.emitData('\x1b]133;D;0\x07') + await vi.advanceTimersByTimeAsync(20) + expect(settled).toBe(false) + + terminal.emitData('dsh> ') + await vi.advanceTimersByTimeAsync(10) + await initializing + expect(session.motd).toBe('dsh> ') + }) + it('trusts prompt markers only while the startup shell owns the foreground group', async () => { vi.useFakeTimers() const terminal = new FakeTerminal() @@ -328,14 +360,15 @@ describe('LocalPtySession bounds, signals, and teardown', () => { // readiness poll would otherwise mis-settle this as stdin_read once close // begins, so teardown must stop polling before its grace period. terminal.emitData('\x1b]133;D;0\x07dsh> ') - terminal.throwKill = true + terminal.autoExitOnKill = false const closing = session.close('mid-send') - await vi.advanceTimersByTimeAsync(60) + await vi.advanceTimersByTimeAsync(20) + terminal.emitExit(0, 15) expect((await operation.done).waitReason).toBe('session_exit') await closing }) - it('waits for SIGKILL recipients to leave the process table after the shell exits', async () => { + it('keeps the shell alive until SIGKILL recipients leave the process table', async () => { vi.useFakeTimers() const terminal = new FakeTerminal() const inspector = new FakeInspector() @@ -348,11 +381,59 @@ describe('LocalPtySession bounds, signals, and teardown', () => { const closing = session.close('test').then(() => { settled = true }) await vi.advanceTimersByTimeAsync(20) expect(inspector.processes).toContainEqual([124, 'SIGKILL']) + expect(terminal.kills).toEqual([]) expect(settled).toBe(false) inspector.alive.delete(124) await vi.advanceTimersByTimeAsync(20) await closing + expect(terminal.kills).toEqual(['SIGTERM']) expect(settled).toBe(true) }) + + it('rescans for descendants forked during TERM before stopping the shell', async () => { + const terminal = new FakeTerminal() + const inspector = new FakeInspector() + let reads = 0 + inspector.processTree = () => { + reads += 1 + if (reads === 1) { + inspector.alive.add(124) + return [{ pid: 124, started: 'first' }] + } + if (reads === 2) { + inspector.alive.add(125) + return [{ pid: 125, started: 'late' }] + } + return [] + } + const session = new LocalPtySession(terminal.asPty(), inspector, config()) + + await session.close('test') + + expect(inspector.processes).toEqual([[124, 'SIGTERM'], [125, 'SIGKILL']]) + expect(terminal.kills).toEqual(['SIGTERM']) + }) + + it('allows teardown to retry after a descendant-survivor failure', async () => { + vi.useFakeTimers() + const terminal = new FakeTerminal() + const inspector = new FakeInspector() + inspector.members = [{ pid: 124, started: 'child' }] + inspector.alive.add(124) + inspector.removeOnSignal = false + const session = new LocalPtySession(terminal.asPty(), inspector, config({ disposeGraceMs: 10 })) + + const first = session.close('first') + const rejected = expect(first).rejects.toThrow('surviving pids: 124') + await vi.advanceTimersByTimeAsync(25) + await rejected + expect(terminal.kills).toEqual([]) + + inspector.alive.delete(124) + const second = session.close('retry') + expect(second).not.toBe(first) + await second + expect(terminal.kills).toEqual(['SIGTERM']) + }) }) diff --git a/packages/pty/pty-local/tsconfig.json b/packages/pty/pty-local/tsconfig.json index 06b5dcd4e7..45a03248db 100644 --- a/packages/pty/pty-local/tsconfig.json +++ b/packages/pty/pty-local/tsconfig.json @@ -17,6 +17,12 @@ { "path": "../../../vendor/schemastery" }, + { + "path": "../../core/agent" + }, + { + "path": "../../core/session" + }, { "path": "../pty" }, diff --git a/packages/pty/pty/README.md b/packages/pty/pty/README.md index 3620d8eaab..6916a4ef82 100644 --- a/packages/pty/pty/README.md +++ b/packages/pty/pty/README.md @@ -5,10 +5,12 @@ Owner-scoped persistent PTY seam. `PtyService` registers as `ctx.pty`, mints opa ## Contract - Backends register one stable `type` and return an unpublished `PtyBackendSession`; failed or cancelled setup must clean partial resources. +- Spawn cancellation preserves the caller's exact abort reason. Service disposal and owner loss remain distinct machine-routable failures after backend setup. +- `hasOwnerActivity(owner)` spans unpublished setup through final close, so lifecycle policy can fence the exact owner without a publication race. - A successful spawn publishes one `PtySessionId`. The optional `name` is owner-local display metadata, never authority. - One session accepts at most one live send operation. Reads and signals may observe it; another send fails until the operation settles. - `PtySendResult.waitReason` and `sessionStatus` are independent. `session_exit` describes the top-level PTY process, not an arbitrary foreground command. -- `kill()` and disposal resolve only after the backend's captured process tree is quiescent. A cleanup failure rejects instead of claiming success. +- `kill()` and disposal resolve only after the backend's captured process tree is quiescent. A cleanup failure rejects instead of claiming success and leaves the close retriable. The seam contains no `node-pty`, sandbox, tool-schema, prompt, task, or terminal-rendering policy. Implementations own terminal mechanics; consumers own model presentation and optional background-task registration. diff --git a/packages/pty/pty/src/index.ts b/packages/pty/pty/src/index.ts index 7bef5f709f..e809f50e3e 100644 --- a/packages/pty/pty/src/index.ts +++ b/packages/pty/pty/src/index.ts @@ -77,10 +77,6 @@ export function PtySessionId(value: string): PtySessionId { return value as PtySessionId } -function isAborted(signal: AbortSignal | undefined): boolean { - return signal?.aborted === true -} - interface SessionRecord { readonly id: PtySessionId readonly owner: Agent @@ -96,6 +92,7 @@ export class PtyService extends Service { private readonly backends = new Map<string, PtyBackend>() private readonly sessions = new Map<PtySessionId, SessionRecord>() private readonly reservedNames = new Map<Agent, Set<string>>() + private readonly pendingSpawns = new Map<Agent, number>() private readonly ownerCleanups = new Map<Agent, () => Promise<void> | void>() private readonly disposedOwners = new WeakSet<Agent>() private nextId = 0 @@ -142,13 +139,13 @@ export class PtyService extends Service { */ async spawn(owner: Agent, request: PtySpawnRequest, signal?: AbortSignal): Promise<PtySpawnResult> { this.assertActive() + signal?.throwIfAborted() this.ensureOwnerCleanup(owner) const backend = this.backends.get(request.type) if (backend === undefined) throw new PtyError(`no PTY backend registered for "${request.type}"`, 'NO_BACKEND') if (request.name !== undefined && request.name.length === 0) throw new Error('PTY session name must be non-empty') - if (isAborted(signal)) throw new Error('PTY spawn aborted') - const releaseName = this.reserveName(owner, request.name) + const releaseSpawn = this.reserveSpawn(owner) const sessionId = PtySessionId(`pty-${++this.nextId}`) let session: PtyBackendSession | undefined try { @@ -160,7 +157,11 @@ export class PtyService extends Service { ...request.cwd !== undefined ? { cwd: request.cwd } : {}, ...signal !== undefined ? { signal } : {}, }) - if (this.disposing || isAborted(signal) || !this.isLiveOwner(owner)) { + signal?.throwIfAborted() + if (this.disposing) { + throw new PtyError('PTY service is disposing', 'SERVICE_DISPOSING') + } + if (!this.isLiveOwner(owner)) { throw new PtyError('PTY owner is no longer live', 'OWNER_NOT_LIVE') } const record: SessionRecord = { @@ -184,10 +185,21 @@ export class PtyService extends Service { } throw error } finally { + releaseSpawn() releaseName() } } + /** + * Test whether an exact owner has a published session or unpublished spawn. + * @param owner - exact live owner to inspect. + * @returns true across the entire spawn-to-close interval, with no publication gap. + */ + hasOwnerActivity(owner: Agent): boolean { + return (this.pendingSpawns.get(owner) ?? 0) > 0 + || [...this.sessions.values()].some(record => record.owner === owner) + } + /** * Start one exclusive interactive send. * @param owner - exact session owner. @@ -302,6 +314,15 @@ export class PtyService extends Service { } } + private reserveSpawn(owner: Agent): () => void { + this.pendingSpawns.set(owner, (this.pendingSpawns.get(owner) ?? 0) + 1) + return () => { + const remaining = (this.pendingSpawns.get(owner) ?? 1) - 1 + if (remaining === 0) this.pendingSpawns.delete(owner) + else this.pendingSpawns.set(owner, remaining) + } + } + private expectOwned(owner: Agent, id: PtySessionId): SessionRecord { const record = this.sessions.get(id) if (record === undefined) throw new PtyError(`unknown PTY session ${id}`, 'NO_SESSION') @@ -339,6 +360,7 @@ export class PtyService extends Service { } finally { this.backends.clear() this.reservedNames.clear() + this.pendingSpawns.clear() const cleanups = [...this.ownerCleanups.values()] this.ownerCleanups.clear() await Promise.all(cleanups.map(cleanup => Promise.resolve(cleanup()))) diff --git a/packages/pty/pty/tests/service.spec.ts b/packages/pty/pty/tests/service.spec.ts index 17b0302ea6..21587163f6 100644 --- a/packages/pty/pty/tests/service.spec.ts +++ b/packages/pty/pty/tests/service.spec.ts @@ -178,8 +178,9 @@ describe('PtyService ownership and lifecycle', () => { const created = await ctx.pty.spawn(owner, { type: 'stub', name: 'main' }) await expect(ctx.pty.spawn(owner, { type: 'stub', name: '' })).rejects.toThrow('must be non-empty') const aborted = new AbortController() - aborted.abort() - await expect(ctx.pty.spawn(owner, { type: 'stub' }, aborted.signal)).rejects.toThrow('spawn aborted') + const abortReason = new Error('spawn aborted') + aborted.abort(abortReason) + await expect(ctx.pty.spawn(owner, { type: 'stub' }, aborted.signal)).rejects.toBe(abortReason) await expect(ctx.pty.spawn(owner, { type: 'stub', name: 'main' })).rejects.toMatchObject({ code: 'DUPLICATE_NAME' }) const operation = ctx.pty.startSend(owner, created.sessionId, { text: 'echo hi', submit: true }) @@ -211,6 +212,41 @@ describe('PtyService ownership and lifecycle', () => { expect(session.closed).toEqual(['PTY spawn rolled back']) }) + it('preserves caller cancellation when a pending backend spawn completes', async () => { + const ctx = await harness() + const gate = Promise.withResolvers<PtyBackendSession>() + const session = new StubSession() + ctx.pty.registerBackend({ type: 'slow', spawn: () => gate.promise }) + const owner = stubAgent(ctx, 'owner') + ctx.agents.register(owner) + const controller = new AbortController() + const reason = new Error('cancelled by caller') + + const pending = ctx.pty.spawn(owner, { type: 'slow' }, controller.signal) + controller.abort(reason) + gate.resolve(session) + + await expect(pending).rejects.toBe(reason) + expect(session.closed).toEqual(['PTY spawn rolled back']) + expect(ctx.agents.get(owner.id)).toBe(owner) + }) + + it('rolls back an unpublished backend session when service disposal wins', async () => { + const ctx = await harness() + const gate = Promise.withResolvers<PtyBackendSession>() + const session = new StubSession() + ctx.pty.registerBackend({ type: 'slow', spawn: () => gate.promise }) + const owner = stubAgent(ctx, 'owner') + ctx.agents.register(owner) + + const pending = ctx.pty.spawn(owner, { type: 'slow' }) + await disposePtyService(ctx) + gate.resolve(session) + + await expect(pending).rejects.toMatchObject({ code: 'SERVICE_DISPOSING' }) + expect(session.closed).toEqual(['PTY spawn rolled back']) + }) + it('keeps independent reservations and handles provider failure before publication', async () => { const ctx = await harness() const firstGate = Promise.withResolvers<PtyBackendSession>() diff --git a/packages/pty/tool-pty/README.md b/packages/pty/tool-pty/README.md index 5a0edca33a..0857c5d3ee 100644 --- a/packages/pty/tool-pty/README.md +++ b/packages/pty/tool-pty/README.md @@ -2,7 +2,16 @@ Six model-facing tools over `ctx.pty`: `terminal_open`, `terminal_send`, `terminal_read`, `terminal_signal`, `terminal_close`, and `terminal_list`. Every operation requires the exact initiating `Agent`, so a model cannot address another agent's terminal even if it learns the id. -`terminal_send(run_in_background: true)` reuses `ctx.tasks`; task preflight occurs before any terminal write, completion is collected with `task_output`, and `task_kill` requests `Ctrl-C`. Foreground sends use terminal ACP cards; lifecycle, history, signal, and list calls use generic cards. +`terminal_send(run_in_background: true)` reuses `ctx.tasks`; task preflight and the PTY service's exclusive per-session send reservation occur before the task id is returned, completion is collected with `task_output`, and `task_kill` delivers `SIGINT` to the foreground process group. Foreground sends use terminal ACP call/result cards. Background sends use a generic execute card; open, read, signal, close, and list use generic `execute`, `read`, `execute`, `delete`, and `read` cards respectively. None declares source locations. + +## Config + +| key | default | meaning | +|---|---:|---| +| `enableRunInBackground` | `true` | expose and accept `run_in_background`; false omits the schema field and rejects a forced undeclared argument | +| `maxResultBytes` | `262144` | UTF-8 cap for each complete terminal result or PTY task output after wait, session, pagination, truncation, and task-status metadata | + +Both values are validated at load. When a result exceeds `maxResultBytes`, rendering reserves space for control metadata and a truncation marker when they fit; cuts preserve UTF-8 boundaries. ## Model Experience @@ -44,11 +53,11 @@ Prefix-stable while tool visibility and definitions are unchanged. #### What the model sees -Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Results remain in session history until compaction; incremental task reads do not repeat consumed output. +Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Every complete result is capped by `maxResultBytes`, including generic task status text. Results remain in session history until compaction; incremental task reads do not repeat consumed output. #### Token effect -Data-dependent and bounded by the backend; each returned result remains in history until compaction. +Data-dependent and bounded by `maxResultBytes`; each returned result remains in history until compaction. #### KV Cache effect diff --git a/packages/pty/tool-pty/package.json b/packages/pty/tool-pty/package.json index 6bc602699c..2d36fb5c9b 100644 --- a/packages/pty/tool-pty/package.json +++ b/packages/pty/tool-pty/package.json @@ -26,11 +26,15 @@ "src" ], "license": "BSD-3-Clause", + "dependencies": { + "schemastery": "^3.18.0" + }, "peerDependencies": { "@deepseek-ai/dsh-agent": "^0.0.1", "@deepseek-ai/dsh-invariants": "^0.0.1", "@deepseek-ai/dsh-llm": "^0.0.1", "@deepseek-ai/dsh-pty": "^0.0.1", + "@deepseek-ai/dsh-retention": "^0.0.1", "@deepseek-ai/dsh-system-prompt": "^0.0.1", "@deepseek-ai/dsh-tasks": "^0.0.1", "@deepseek-ai/dsh-tools": "^0.0.1", @@ -44,6 +48,7 @@ "@deepseek-ai/dsh-llm": "workspace:^", "@deepseek-ai/dsh-pty": "workspace:^", "@deepseek-ai/dsh-pty-local": "workspace:^", + "@deepseek-ai/dsh-retention": "workspace:^", "@deepseek-ai/dsh-sandbox": "workspace:^", "@deepseek-ai/dsh-sandbox-policy": "workspace:^", "@deepseek-ai/dsh-session": "workspace:^", diff --git a/packages/pty/tool-pty/src/index.ts b/packages/pty/tool-pty/src/index.ts index f145102dea..edb8102a79 100644 --- a/packages/pty/tool-pty/src/index.ts +++ b/packages/pty/tool-pty/src/index.ts @@ -5,6 +5,7 @@ */ import { Context } from 'cordis' +import z from 'schemastery' import type { Agent } from '@deepseek-ai/dsh-agent' import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { PtySessionId } from '@deepseek-ai/dsh-pty' @@ -12,7 +13,7 @@ import type { PtySendResult, PtySessionId as PtySessionIdType, PtySignal } from import type {} from '@deepseek-ai/dsh-tasks' import { defineTool } from '@deepseek-ai/dsh-tools' import type { ToolExecutionResult, ToolResult } from '@deepseek-ai/dsh-tools' -import { renderList, renderRead, renderSend, renderSendRead, renderSpawn } from './render.ts' +import { boundTerminalText, renderList, renderRead, renderSend, renderSendRead, renderSpawn } from './render.ts' declare module '@deepseek-ai/dsh-tasks' { interface TaskKindMap { @@ -25,6 +26,23 @@ export const name = 'tool-pty' /** Required capability, registry, and prompt services. */ export const inject = ['pty', 'tools', 'systemPrompt'] +/** Default cap for one complete model-facing terminal result. */ +export const DEFAULT_MAX_RESULT_BYTES = 256 * 1024 + +/** Model-facing terminal tool configuration. */ +export interface Config { + /** Expose `run_in_background` and accept background sends (default true). */ + enableRunInBackground?: boolean + /** Maximum UTF-8 bytes in one complete terminal or task-output result. */ + maxResultBytes?: number +} + +/** Schemastery configuration for the terminal tool consumer. */ +export const Config: z<Config> = z.object({ + enableRunInBackground: z.boolean().default(true), + maxResultBytes: z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER).default(DEFAULT_MAX_RESULT_BYTES), +}) + interface SpawnArgs { type: string name?: string @@ -62,8 +80,8 @@ function sessionId(args: SessionArgs): PtySessionIdType { return PtySessionId(args.sessionId) } -function textResult(text: string): ContentBlock[] { - return [{ type: 'text', text }] +function textResult(text: string, maxBytes: number): ContentBlock[] { + return [{ type: 'text', text: boundTerminalText(text, maxBytes) }] } function rawResultText(result: ToolResult): string | undefined { @@ -79,7 +97,12 @@ function sendDetail(result: PtySendResult): string { } /** Register all terminal tools and the minimal usage guidance. */ -export function apply(ctx: Context): void { +export function apply(ctx: Context, config: Config = {}): void { + const enableRunInBackground = config.enableRunInBackground ?? true + const maxResultBytes = config.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES + if (!Number.isSafeInteger(maxResultBytes) || maxResultBytes <= 0) { + throw new Error('tool-pty: maxResultBytes must be a positive safe integer') + } ctx.systemPrompt.section({ name: 'tool:pty', order: 106, @@ -101,7 +124,7 @@ export function apply(ctx: Context): void { ...args.name !== undefined ? { name: args.name } : {}, ...args.cwd !== undefined ? { cwd: args.cwd } : {}, }, exec.signal) - return textResult(renderSpawn(result)) + return textResult(renderSpawn(result, maxResultBytes), maxResultBytes) }, presentCall: (args) => { const parsed = args @@ -111,18 +134,22 @@ export function apply(ctx: Context): void { ctx.tools.register(defineTool({ name: 'terminal_send', - description: 'Send text to a persistent terminal. By default Enter is submitted and the call waits for a prompt, stdin wait, output silence, timeout, or session exit. Background mode returns a task id for task_output/task_kill.', + description: 'Send text to a persistent terminal. By default Enter is submitted and the call waits for a prompt, stdin wait, output silence, timeout, or session exit.' + + (enableRunInBackground ? ' Background mode returns a task id for task_output/task_kill.' : ''), parameters: { sessionId: { type: 'string', required: true, description: 'Terminal session id returned by terminal_open or terminal_list.' }, text: { type: 'string', required: true, description: 'UTF-8 text to write to the terminal.' }, submit: { type: 'boolean', description: 'Submit Enter after text (default true). Set false for control characters or incomplete REPL input.' }, - run_in_background: { type: 'boolean', description: 'Return a task id immediately; collect with task_output or stop with task_kill.' }, + ...enableRunInBackground + ? { run_in_background: { type: 'boolean' as const, description: 'Return a task id immediately; collect with task_output or stop with task_kill.' } } + : {}, }, async execute(args: SendArgs, exec): Promise<ToolExecutionResult> { const owner = requireAgent(exec.agent) const id = sessionId(args) const request = { text: args.text, submit: args.submit ?? true } if (args.run_in_background === true) { + if (!enableRunInBackground) throw new Error('background terminal sends are disabled by tool-pty configuration') const tasks = ctx.get('tasks') if (tasks === undefined) throw new Error('background terminal sends require @deepseek-ai/dsh-tasks and @deepseek-ai/dsh-tool-tasks') let cancelRequested = false @@ -130,6 +157,7 @@ export function apply(ctx: Context): void { kind: 'pty-send', label: `${id}: ${args.text || '(input)'}`, owner, + outputLimitBytes: maxResultBytes, run: () => { const operation = ctx.pty.startSend(owner, id, request) return { @@ -145,12 +173,12 @@ export function apply(ctx: Context): void { } }, }) - return { content: textResult(`started background task ${taskId}`), isError: false } + return { content: textResult(`started background task ${taskId}`, maxResultBytes), isError: false } } const operation = ctx.pty.startSend(owner, id, { ...request, signal: exec.signal }) const result = await operation.done if (exec.signal.aborted) throw new Error('terminal send aborted') - return { content: textResult(renderSend(result)), isError: false, meta: result } + return { content: textResult(renderSend(result, maxResultBytes), maxResultBytes), isError: false, meta: result } }, presentCall(args) { const parsed = args as Partial<SendArgs> @@ -179,7 +207,7 @@ export function apply(ctx: Context): void { ...args.offset !== undefined ? { offset: args.offset } : {}, ...args.count !== undefined ? { count: args.count } : {}, }) - return Promise.resolve(textResult(renderRead(result))) + return Promise.resolve(textResult(renderRead(result, maxResultBytes), maxResultBytes)) }, presentCall: args => ({ card: 'generic', title: `Read terminal ${(args).sessionId}`, kind: 'read', rawInput: args }), })) @@ -193,7 +221,7 @@ export function apply(ctx: Context): void { }, async execute(args: SignalArgs, exec) { const result = await ctx.pty.signal(requireAgent(exec.agent), sessionId(args), args.signal) - return textResult(`delivered ${args.signal} to foreground process group ${result.targetPgid}`) + return textResult(`delivered ${args.signal} to foreground process group ${result.targetPgid}`, maxResultBytes) }, presentCall: args => ({ card: 'generic', title: `Signal terminal ${(args as SignalArgs).sessionId}`, kind: 'execute', rawInput: args }), })) @@ -207,7 +235,7 @@ export function apply(ctx: Context): void { async execute(args: SessionArgs, exec) { const id = sessionId(args) const closed = await ctx.pty.kill(requireAgent(exec.agent), id) - return textResult(closed ? `closed terminal session ${id}` : `terminal session ${id} was already closing`) + return textResult(closed ? `closed terminal session ${id}` : `terminal session ${id} was already closing`, maxResultBytes) }, presentCall: args => ({ card: 'generic', title: `Close terminal ${(args).sessionId}`, kind: 'delete' }), })) @@ -217,7 +245,7 @@ export function apply(ctx: Context): void { description: 'List persistent terminal sessions owned by the current agent.', parameters: {}, execute(_args: Record<string, never>, exec) { - return Promise.resolve(textResult(renderList(ctx.pty.list(requireAgent(exec.agent))))) + return Promise.resolve(textResult(renderList(ctx.pty.list(requireAgent(exec.agent)), maxResultBytes), maxResultBytes)) }, presentCall: () => ({ card: 'generic', title: 'List terminal sessions', kind: 'read' }), })) diff --git a/packages/pty/tool-pty/src/render.ts b/packages/pty/tool-pty/src/render.ts index bed176e890..0930d205ad 100644 --- a/packages/pty/tool-pty/src/render.ts +++ b/packages/pty/tool-pty/src/render.ts @@ -1,57 +1,128 @@ /** Model and ACP rendering for persistent terminal tool results. */ +import { TextRetainer } from '@deepseek-ai/dsh-retention' import type { PtyReadResult, PtySendRead, PtySendResult, PtySessionSnapshot, PtySpawnResult } from '@deepseek-ai/dsh-pty' +const encoder = new TextEncoder() +const TRUNCATED = '\n[output truncated]' + +function byteLength(text: string): number { + return encoder.encode(text).byteLength +} + +function retain(text: string, maxBytes: number, kind: 'head' | 'tail'): string { + const retainer = new TextRetainer({ kind, maxBytes }) + retainer.push(text) + return retainer.finish().text +} + +function fitWithSuffix(content: string, suffix: string, maxBytes: number): string { + const fixedBytes = byteLength(suffix) + if (fixedBytes >= maxBytes) return retain(suffix, maxBytes, 'tail') + return `${retain(content, maxBytes - fixedBytes, 'tail')}${suffix}` +} + +function fitWithPrefix(prefix: string, content: string, maxBytes: number): string { + const fixed = `${prefix}${TRUNCATED}` + const fixedBytes = byteLength(fixed) + if (fixedBytes >= maxBytes) return retain(fixed, maxBytes, 'head') + return `${prefix}${retain(content, maxBytes - fixedBytes, 'tail')}${TRUNCATED}` +} + +function boundBodyWithSuffix( + content: string, + metadata: string, + upstreamTruncated: boolean, + maxBytes: number, +): string { + const suffix = `${metadata}${upstreamTruncated ? TRUNCATED : ''}` + const complete = `${content}${suffix}` + if (byteLength(complete) <= maxBytes) return complete + return fitWithSuffix(content, `${metadata}${TRUNCATED}`, maxBytes) +} + +/** + * Bound one complete terminal acknowledgement while preserving UTF-8 cuts. + * @param text - complete acknowledgement text. + * @param maxBytes - positive final result cap. + * @returns bounded text with a truncation marker when it fits. + */ +export function boundTerminalText(text: string, maxBytes: number): string { + if (byteLength(text) <= maxBytes) return text + const markerBytes = byteLength(TRUNCATED) + if (markerBytes >= maxBytes) return retain(TRUNCATED, maxBytes, 'tail') + return `${retain(text, maxBytes - markerBytes, 'head')}${TRUNCATED}` +} + /** * Render one created session and its bounded MOTD. * @param result - published spawn result. + * @param maxBytes - complete UTF-8 result cap. * @returns Model-facing session acknowledgement. */ -export function renderSpawn(result: PtySpawnResult): string { +export function renderSpawn(result: PtySpawnResult, maxBytes: number): string { const label = result.name === undefined ? result.sessionId : `${result.sessionId} (${result.name})` - return `started terminal session ${label} [type: ${result.type}]\n${result.motd || '(no startup output)'}` + const prefix = `started terminal session ${label} [type: ${result.type}]\n` + const motd = result.motd || '(no startup output)' + const complete = `${prefix}${motd}` + return byteLength(complete) <= maxBytes ? complete : fitWithPrefix(prefix, motd, maxBytes) } /** * Render one settled interactive send. * @param result - settled send outcome. + * @param maxBytes - complete UTF-8 result cap. * @returns Terminal output plus wait/session markers. */ -export function renderSend(result: PtySendResult): string { +export function renderSend(result: PtySendResult, maxBytes: number): string { const output = result.viewport || '(no new output)' const status = result.sessionStatus.kind === 'running' ? 'running' : `exited code=${result.sessionStatus.exitCode ?? 'null'} signal=${result.sessionStatus.signal ?? 'null'}` - return `${output}\n[wait: ${result.waitReason}]\n[session: ${status}]${result.truncated ? '\n[output truncated]' : ''}` + return boundBodyWithSuffix( + output, + `\n[wait: ${result.waitReason}]\n[session: ${status}]`, + result.truncated, + maxBytes, + ) } /** * Render one incremental background operation read. * @param read - consuming operation delta. - * @returns Delta plus truncation marker when needed. + * @returns Delta plus its upstream truncation marker. The generic task control + * applies the producer's complete-result cap after adding task status. */ export function renderSendRead(read: PtySendRead): string { - return `${read.delta}${read.truncated ? `${read.delta.endsWith('\n') || read.delta.length === 0 ? '' : '\n'}[output truncated]` : ''}` + const separator = read.delta.endsWith('\n') || read.delta.length === 0 ? '' : '\n' + return `${read.delta}${read.truncated ? `${separator}[output truncated]` : ''}` } /** * Render one bounded historical page. * @param result - retained scrollback page. + * @param maxBytes - complete UTF-8 result cap. * @returns Page text plus pagination and truncation markers. */ -export function renderRead(result: PtyReadResult): string { +export function renderRead(result: PtyReadResult, maxBytes: number): string { const output = result.text || '(no retained output)' - return `${output}\n[lines: ${result.lineBegin}-${result.lineEnd} of ${result.totalLines}]${result.truncated ? '\n[output truncated]' : ''}` + return boundBodyWithSuffix( + output, + `\n[lines: ${result.lineBegin}-${result.lineEnd} of ${result.totalLines}]`, + result.truncated, + maxBytes, + ) } /** * Render owner-visible live sessions. * @param sessions - fresh owner-scoped snapshots. + * @param maxBytes - complete UTF-8 result cap. * @returns One line per session or the empty marker. */ -export function renderList(sessions: PtySessionSnapshot[]): string { +export function renderList(sessions: PtySessionSnapshot[], maxBytes: number): string { if (sessions.length === 0) return '(no terminal sessions)' - return sessions.map((session) => { + const text = sessions.map((session) => { const name = session.name === undefined ? '' : ` (${session.name})` const pid = session.pid === undefined ? '' : ` pid=${session.pid}` const status = session.status.kind === 'running' @@ -59,4 +130,5 @@ export function renderList(sessions: PtySessionSnapshot[]): string { : `exited code=${session.status.exitCode ?? 'null'} signal=${session.status.signal ?? 'null'}` return `${session.sessionId}${name} [${session.type}] ${status}${pid}` }).join('\n') + return boundBodyWithSuffix(text, '', false, maxBytes) } diff --git a/packages/pty/tool-pty/tests/render.spec.ts b/packages/pty/tool-pty/tests/render.spec.ts index 33b288ab5f..b02ba3b8ef 100644 --- a/packages/pty/tool-pty/tests/render.spec.ts +++ b/packages/pty/tool-pty/tests/render.spec.ts @@ -1,23 +1,23 @@ import { describe, expect, it } from 'vitest' import { PtySessionId } from '@deepseek-ai/dsh-pty' -import { renderList, renderRead, renderSend, renderSendRead, renderSpawn } from '@deepseek-ai/dsh-tool-pty/src/render.ts' +import { boundTerminalText, renderList, renderRead, renderSend, renderSendRead, renderSpawn } from '@deepseek-ai/dsh-tool-pty/src/render.ts' describe('tool-pty rendering', () => { it('renders spawn with and without names or MOTD', () => { - expect(renderSpawn({ sessionId: PtySessionId('pty-1'), type: 'shell', status: { kind: 'running' }, motd: '' })) + expect(renderSpawn({ sessionId: PtySessionId('pty-1'), type: 'shell', status: { kind: 'running' }, motd: '' }, 1024)) .toBe('started terminal session pty-1 [type: shell]\n(no startup output)') - expect(renderSpawn({ sessionId: PtySessionId('pty-2'), name: 'main', type: 'shell', pid: 2, status: { kind: 'running' }, motd: 'ready' })) + expect(renderSpawn({ sessionId: PtySessionId('pty-2'), name: 'main', type: 'shell', pid: 2, status: { kind: 'running' }, motd: 'ready' }, 1024)) .toContain('pty-2 (main)') }) it('renders running, exited, empty, and truncated sends', () => { - expect(renderSend({ viewport: '', waitReason: 'timeout', sessionStatus: { kind: 'running' }, truncated: true })) + expect(renderSend({ viewport: '', waitReason: 'timeout', sessionStatus: { kind: 'running' }, truncated: true }, 1024)) .toBe('(no new output)\n[wait: timeout]\n[session: running]\n[output truncated]') - expect(renderSend({ viewport: 'bye', waitReason: 'session_exit', sessionStatus: { kind: 'exited', exitCode: null, signal: 'SIGTERM' }, truncated: false })) + expect(renderSend({ viewport: 'bye', waitReason: 'session_exit', sessionStatus: { kind: 'exited', exitCode: null, signal: 'SIGTERM' }, truncated: false }, 1024)) .toContain('exited code=null signal=SIGTERM') - expect(renderSend({ viewport: 'bye', waitReason: 'session_exit', sessionStatus: { kind: 'exited', exitCode: 2, signal: null }, truncated: false })) + expect(renderSend({ viewport: 'bye', waitReason: 'session_exit', sessionStatus: { kind: 'exited', exitCode: 2, signal: null }, truncated: false }, 1024)) .toContain('exited code=2 signal=null') - expect(renderSend({ viewport: 'bye', waitReason: 'session_exit', sessionStatus: { kind: 'exited', exitCode: null, signal: null }, truncated: false })) + expect(renderSend({ viewport: 'bye', waitReason: 'session_exit', sessionStatus: { kind: 'exited', exitCode: null, signal: null }, truncated: false }, 1024)) .toContain('exited code=null signal=null') expect(renderSendRead({ delta: '', truncated: true })).toBe('[output truncated]') expect(renderSendRead({ delta: 'x', truncated: true })).toBe('x\n[output truncated]') @@ -26,14 +26,48 @@ describe('tool-pty rendering', () => { }) it('renders history and every list status shape', () => { - expect(renderRead({ text: '', totalLines: 0, lineBegin: 0, lineEnd: 0, truncated: true })) + expect(renderRead({ text: '', totalLines: 0, lineBegin: 0, lineEnd: 0, truncated: true }, 1024)) .toBe('(no retained output)\n[lines: 0-0 of 0]\n[output truncated]') - expect(renderList([])).toBe('(no terminal sessions)') + expect(renderList([], 1024)).toBe('(no terminal sessions)') expect(renderList([ { sessionId: PtySessionId('pty-1'), type: 'shell', status: { kind: 'running' } }, { sessionId: PtySessionId('pty-2'), name: 'done', type: 'shell', pid: 9, status: { kind: 'exited', exitCode: 2, signal: null } }, { sessionId: PtySessionId('pty-3'), type: 'shell', status: { kind: 'exited', exitCode: null, signal: 'SIGTERM' } }, { sessionId: PtySessionId('pty-4'), type: 'shell', status: { kind: 'exited', exitCode: null, signal: null } }, - ])).toBe('pty-1 [shell] running\npty-2 (done) [shell] exited code=2 signal=null pid=9\npty-3 [shell] exited code=null signal=SIGTERM\npty-4 [shell] exited code=null signal=null') + ], 1024)).toBe('pty-1 [shell] running\npty-2 (done) [shell] exited code=2 signal=null pid=9\npty-3 [shell] exited code=null signal=SIGTERM\npty-4 [shell] exited code=null signal=null') + }) + + it('bounds complete UTF-8 results while retaining terminal metadata when it fits', () => { + const send = renderSend({ + viewport: `prefix-${'界'.repeat(40)}`, + waitReason: 'stdin_read', + sessionStatus: { kind: 'running' }, + truncated: false, + }, 64) + expect(Buffer.byteLength(send)).toBeLessThanOrEqual(64) + expect(send).toContain('[wait: stdin_read]') + expect(send).toContain('[output truncated]') + + const read = renderRead({ + text: 'x'.repeat(200), totalLines: 20, lineBegin: 0, lineEnd: 10, truncated: false, + }, 48) + expect(Buffer.byteLength(read)).toBeLessThanOrEqual(48) + expect(read).toContain('[lines: 0-10 of 20]') + + expect(Buffer.byteLength(renderSpawn({ + sessionId: PtySessionId('pty-1'), type: 'shell', status: { kind: 'running' }, motd: 'x'.repeat(200), + }, 32))).toBeLessThanOrEqual(32) + + const boundedSpawn = renderSpawn({ + sessionId: PtySessionId('pty-1'), type: 'shell', status: { kind: 'running' }, motd: 'x'.repeat(200), + }, 96) + expect(boundedSpawn).toContain('started terminal session pty-1') + expect(boundedSpawn).toContain('[output truncated]') + + expect(Buffer.byteLength(renderSend({ + viewport: 'x'.repeat(200), waitReason: 'stdin_read', sessionStatus: { kind: 'running' }, truncated: false, + }, 8))).toBeLessThanOrEqual(8) + expect(boundTerminalText('x'.repeat(200), 8)).toHaveLength(8) + expect(boundTerminalText('x'.repeat(200), 32).endsWith('[output truncated]')).toBe(true) }) }) diff --git a/packages/pty/tool-pty/tests/tools.spec.ts b/packages/pty/tool-pty/tests/tools.spec.ts index 5adcaea441..d6023a4d17 100644 --- a/packages/pty/tool-pty/tests/tools.spec.ts +++ b/packages/pty/tool-pty/tests/tools.spec.ts @@ -31,20 +31,23 @@ class StubSession implements PtyBackendSession { autoSettle = true rejectOperation = false closeGate: PromiseWithResolvers<undefined> | undefined + viewport = 'command output' + delta = 'live output' + deltaTruncated = false startSend(_request: PtySendRequest): PtySendOperation { let settle!: () => void let reject!: (error: unknown) => void let cancelled = false const done = new Promise<void>((resolve, rejectPromise) => { settle = resolve; reject = rejectPromise }).then(() => ({ - viewport: cancelled ? '^C' : 'command output', + viewport: cancelled ? '^C' : this.viewport, waitReason: 'stdin_read' as const, sessionStatus: this.statusValue, truncated: false, })) const operation: PtySendOperation = { done, - readOutput: () => ({ delta: 'live output', truncated: false }), + readOutput: () => ({ delta: this.delta, truncated: this.deltaTruncated }), cancel: () => { if (cancelled) return false cancelled = true @@ -87,7 +90,13 @@ function stubBackend() { return { backend, sessions } } -async function setup(tasks: boolean) { +async function setup(tasks: boolean, config: ToolPty.Config = {}) { + const base = await setupBase(tasks) + await base.ctx.plugin(ToolPty, config) + return base +} + +async function setupBase(tasks: boolean) { const ctx = new Context() await ctx.plugin(SystemPrompt) await ctx.plugin(ToolRegistry) @@ -99,7 +108,6 @@ async function setup(tasks: boolean) { await ctx.plugin(TaskService) await ctx.plugin(ToolTasks) } - await ctx.plugin(ToolPty) return { ctx, stub, agent: fakeAgent(ctx, tasks ? 'with-tasks' : 'foreground') } } @@ -172,6 +180,24 @@ describe('tool-pty foreground surface', () => { expect(ctx.tools.get('terminal_close')?.presentCall?.({ sessionId: 'pty-1' })).toMatchObject({ card: 'generic', title: 'Close terminal pty-1' }) expect(ctx.tools.get('terminal_list')?.presentCall?.({})).toMatchObject({ card: 'generic', title: 'List terminal sessions' }) }) + + it('configuration-gates background sends and validates the final result bound', async () => { + const disabled = await setup(true, { enableRunInBackground: false }) + const definition = disabled.ctx.tools.get('terminal_send') + expect(definition?.parameters).not.toHaveProperty('properties.run_in_background') + expect(definition?.description).not.toContain('Background mode') + await call(disabled.ctx, 'terminal_open', { type: 'stub' }, disabled.agent) + expect((await call(disabled.ctx, 'terminal_send', { + sessionId: 'pty-1', text: 'work', run_in_background: true, + }, disabled.agent)).isError).toBe(true) + + const defaults = await setupBase(false) + ToolPty.apply(defaults.ctx) + expect(defaults.ctx.tools.get('terminal_send')?.parameters).toHaveProperty('properties.run_in_background') + + const invalid = await setupBase(false) + expect(() => { ToolPty.apply(invalid.ctx, { maxResultBytes: 0 }) }).toThrow('maxResultBytes') + }) }) describe('tool-pty task integration', () => { @@ -184,6 +210,23 @@ describe('tool-pty task integration', () => { expect(text(output)).toContain('[status: completed, wait: stdin_read]') }) + it('bounds foreground and background results after terminal and task metadata', async () => { + const { ctx, agent, stub } = await setup(true, { maxResultBytes: 64 }) + await call(ctx, 'terminal_open', { type: 'stub' }, agent) + stub.sessions[0]!.viewport = '界'.repeat(100) + const foreground = await call(ctx, 'terminal_send', { sessionId: 'pty-1', text: 'foreground' }, agent) + expect(Buffer.byteLength(text(foreground))).toBeLessThanOrEqual(64) + + stub.sessions[0]!.delta = '界'.repeat(100) + stub.sessions[0]!.deltaTruncated = true + await call(ctx, 'terminal_send', { sessionId: 'pty-1', text: 'background', run_in_background: true }, agent) + const background = await call(ctx, 'task_output', { task_id: 'pty-send-1', wait: true }, agent) + expect(Buffer.byteLength(text(background))).toBeLessThanOrEqual(64) + expect(text(background)).toContain('[status: completed') + expect(text(background).match(/\[output truncated\]/g)).toHaveLength(1) + expect(text(background)).toContain('[output truncated]\n[status: completed') + }) + it('rejects pre-aborted background calls, maps task cancellation, and contains operation failure', async () => { const { ctx, agent, stub } = await setup(true) await call(ctx, 'terminal_open', { type: 'stub' }, agent) diff --git a/packages/pty/tool-pty/tsconfig.json b/packages/pty/tool-pty/tsconfig.json index 7ba9633c2c..9674519034 100644 --- a/packages/pty/tool-pty/tsconfig.json +++ b/packages/pty/tool-pty/tsconfig.json @@ -14,6 +14,9 @@ { "path": "../../../vendor/cordis" }, + { + "path": "../../util/retention" + }, { "path": "../pty" }, diff --git a/packages/tasks/tasks/README.md b/packages/tasks/tasks/README.md index 37d342e0fe..1d9ce2b249 100644 --- a/packages/tasks/tasks/README.md +++ b/packages/tasks/tasks/README.md @@ -4,7 +4,7 @@ The process-local background task registry (`ctx.tasks`). It gives long-running ## Service API -- `start(spec): TaskId` validates the control surface, spec, and exact live owner before calling the producer's `run()` once. A starter throw leaves nothing registered; successful return commits without another failable step. +- `start(spec): TaskId` validates the control surface, spec, exact live owner, and optional positive `outputLimitBytes` before calling the producer's `run()` once. A starter throw leaves nothing registered; successful return commits without another failable step. - `get(id, caller?)` and `list(caller?)` return non-consuming snapshots. Listing includes only caller-owned and unowned tasks. - `read(id, caller?)` consumes the single cursor for stream tasks and reads terminal output idempotently for final-output tasks. - `kill(id, caller?, reason?)` invokes producer cancellation before changing status. A cancellation throw leaves the task running; success changes it to `stopping` and marks terminal delivery reported. @@ -14,6 +14,8 @@ The process-local background task registry (`ctx.tasks`). It gives long-running Owned access compares the task's `SessionId` with the caller's. Ids such as `bash-1` are predictable, so this fence is the boundary. Unowned tasks are open to callers and last until service disposal. +`outputLimitBytes` is producer-owned model-presentation policy carried unchanged into snapshots. A control surface applies it after adding status or notice metadata; the registry does not rewrite producer output or invent a default for producers that omit it. + ## Lifecycle Tasks belong to their owner and backend, not the producer tool fiber, so producer and surface reloads do not stop them. The first task for an owner attaches one awaited effect to the exact `Agent` scope. Owner disposal cancels that object's tasks, awaits producer quiescence, and removes their snapshots; reused agent or session ids cannot redirect an old cleanup. diff --git a/packages/tasks/tasks/src/index.ts b/packages/tasks/tasks/src/index.ts index 457f5473a3..16f0807656 100644 --- a/packages/tasks/tasks/src/index.ts +++ b/packages/tasks/tasks/src/index.ts @@ -42,6 +42,7 @@ interface TrackedTask { id: TaskId kind: TaskKind label: string + outputLimitBytes: number | undefined /** Exact lifecycle owner; session-id authorization is derived from it. */ owner: Agent | undefined cancel: (reason?: string) => void @@ -104,6 +105,10 @@ export class TaskService extends Service { } if (spec.kind.length === 0) throw new Error('invalid task kind: expected a non-empty string') if (spec.label.length === 0) throw new Error('invalid task label: expected a non-empty string') + if (spec.outputLimitBytes !== undefined + && (!Number.isSafeInteger(spec.outputLimitBytes) || spec.outputLimitBytes <= 0)) { + throw new Error(`invalid outputLimitBytes: expected a positive safe integer, got ${JSON.stringify(spec.outputLimitBytes)}`) + } if (spec.owner !== undefined) this.ensureOwnerCleanup(spec.owner) const hooks = spec.run() @@ -117,6 +122,7 @@ export class TaskService extends Service { id, kind: spec.kind, label: spec.label, + outputLimitBytes: spec.outputLimitBytes, owner: spec.owner, cancel: hooks.cancel.bind(hooks), readOutput: hooks.readOutput?.bind(hooks), @@ -329,6 +335,7 @@ export class TaskService extends Service { id: task.id, kind: task.kind, label: task.label, + ...task.outputLimitBytes !== undefined ? { outputLimitBytes: task.outputLimitBytes } : {}, ...ownerSession !== undefined ? { ownerSession } : {}, status: task.status, ...task.detail !== undefined ? { detail: task.detail } : {}, diff --git a/packages/tasks/tasks/src/types.ts b/packages/tasks/tasks/src/types.ts index 96316260ec..d722f3fce6 100644 --- a/packages/tasks/tasks/src/types.ts +++ b/packages/tasks/tasks/src/types.ts @@ -61,6 +61,11 @@ export interface TaskStart { kind: TaskKind /** One-line model-facing label (the command; the delegation description). */ label: string + /** + * Optional UTF-8 byte cap for each complete model-facing completion notice or + * output read, including control-surface status metadata. + */ + outputLimitBytes?: number /** * Owning live agent. Access is fenced by its session id, and agent disposal * cancels and awaits the task. The instance must be the one currently @@ -109,6 +114,8 @@ export interface TaskSnapshot { kind: TaskKind /** The producer-supplied one-line label. */ label: string + /** Producer-owned cap for complete model-facing notices and output reads. */ + outputLimitBytes?: number /** * Owner session id used for authorization and correlation; absent for * unowned tasks. Completion listeners receive the exact {@link Agent} diff --git a/packages/tasks/tasks/tests/tasks.spec.ts b/packages/tasks/tasks/tests/tasks.spec.ts index 0d3eae8338..34506b3a47 100644 --- a/packages/tasks/tasks/tests/tasks.spec.ts +++ b/packages/tasks/tasks/tests/tasks.spec.ts @@ -44,13 +44,19 @@ function producer(overrides: Partial<Omit<TaskStart, 'run'> & TaskHooks> = {}) { let settle!: (outcome: TaskOutcome) => void let reject!: (error: unknown) => void const cancels: (string | undefined)[] = [] - const { kind = 'bash', label = 'sleep 60', owner, ...hookOverrides } = overrides + const { kind = 'bash', label = 'sleep 60', owner, outputLimitBytes, ...hookOverrides } = overrides const hooks: TaskHooks = { cancel(reason) { cancels.push(reason) }, done: new Promise<TaskOutcome>((res, rej) => { settle = res; reject = rej }), ...hookOverrides, } - const spec: TaskStart = { kind, label, ...owner !== undefined ? { owner } : {}, run: () => hooks } + const spec: TaskStart = { + kind, + label, + ...owner !== undefined ? { owner } : {}, + ...outputLimitBytes !== undefined ? { outputLimitBytes } : {}, + run: () => hooks, + } return { spec, settle, reject, cancels } } @@ -85,10 +91,11 @@ describe('TaskService.start', () => { .toThrow('background tasks unavailable: no control surface is attached (load @deepseek-ai/dsh-tool-tasks)') }) - it('rejects an empty kind and an empty label', async () => { + it('rejects an empty kind, empty label, and invalid output limit', async () => { const ctx = await harness() expect(() => ctx.tasks.start(producer({ kind: '' as TaskKind }).spec)).toThrow('invalid task kind') expect(() => ctx.tasks.start(producer({ label: '' }).spec)).toThrow('invalid task label') + expect(() => ctx.tasks.start(producer({ outputLimitBytes: 0 }).spec)).toThrow('outputLimitBytes') }) it('issues kind-prefixed ids from per-kind counters', async () => { @@ -118,6 +125,16 @@ describe('TaskService reads and settlement', () => { expect(read.snapshot.finishedAt).toBeTypeOf('number') }) + it('projects a producer-owned model output limit into reads and snapshots', async () => { + const ctx = await harness() + const p = producer({ outputLimitBytes: 64, readOutput: () => 'delta' }) + const id = ctx.tasks.start(p.spec) + expect(ctx.tasks.read(id)).toMatchObject({ + text: 'delta', snapshot: { outputLimitBytes: 64 }, + }) + expect(ctx.tasks.get(id)).toMatchObject({ outputLimitBytes: 64 }) + }) + it('final-output kinds read empty while live, the outcome output idempotently once settled', async () => { const ctx = await harness() const p = producer({ kind: 'subagent', label: 'research task' }) diff --git a/packages/tasks/tool-tasks/README.md b/packages/tasks/tool-tasks/README.md index 7e1ab82971..f4a3475786 100644 --- a/packages/tasks/tool-tasks/README.md +++ b/packages/tasks/tool-tasks/README.md @@ -10,6 +10,8 @@ The model-facing control surface for `ctx.tasks`: three kind-independent tools, All three use generic ACP cards: `read` for output and list, `execute` for kill. +When a producer supplies `outputLimitBytes`, `task_output`, terminal `task_kill`, and completion notices cap the complete UTF-8 result after adding status or notice text. The output tail and control suffix are retained when they fit; an existing producer truncation marker is reused rather than duplicated. Producers that omit the field retain the existing unbounded control-surface behavior. + ## Completion notices An unreported completion injects `background task <id> (<kind>: <label>) finished [status: ...]. Read its output with task_output.` into the exact owner's session. Injection is durable context for the next request, not a wake-up. A kill or terminal read/wait marks delivery reported and suppresses the redundant notice; owner-disposal races are contained. @@ -67,7 +69,7 @@ Reads return output or `(no new output)` followed by `[status: <status>]` and op #### Token effect -Results and notices remain in parent history until compaction. Stream reads do not repeat consumed output. +Results and notices remain in parent history until compaction. Stream reads do not repeat consumed output; a producer-supplied `outputLimitBytes` bounds each complete read or notice. #### KV Cache effect diff --git a/packages/tasks/tool-tasks/package.json b/packages/tasks/tool-tasks/package.json index fc1f96417d..2e03fb26a2 100644 --- a/packages/tasks/tool-tasks/package.json +++ b/packages/tasks/tool-tasks/package.json @@ -26,21 +26,23 @@ "src" ], "license": "BSD-3-Clause", + "dependencies": { + "schemastery": "^3.18.0" + }, "peerDependencies": { "@deepseek-ai/dsh-agent": "^0.0.1", "@deepseek-ai/dsh-invariants": "^0.0.1", + "@deepseek-ai/dsh-retention": "^0.0.1", "@deepseek-ai/dsh-system-prompt": "^0.0.1", "@deepseek-ai/dsh-tasks": "^0.0.1", "@deepseek-ai/dsh-tools": "^0.0.1", "cordis": "^4.0.0-rc.6" }, - "dependencies": { - "schemastery": "^3.18.0" - }, "devDependencies": { "@deepseek-ai/dsh-agent": "workspace:^", "@deepseek-ai/dsh-invariants": "workspace:^", "@deepseek-ai/dsh-llm": "workspace:^", + "@deepseek-ai/dsh-retention": "workspace:^", "@deepseek-ai/dsh-session": "workspace:^", "@deepseek-ai/dsh-system-prompt": "workspace:^", "@deepseek-ai/dsh-tasks": "workspace:^", diff --git a/packages/tasks/tool-tasks/src/index.ts b/packages/tasks/tool-tasks/src/index.ts index 2d556cada9..cee88db859 100644 --- a/packages/tasks/tool-tasks/src/index.ts +++ b/packages/tasks/tool-tasks/src/index.ts @@ -8,6 +8,7 @@ import type { Context } from 'cordis' import z from 'schemastery' +import { TextRetainer } from '@deepseek-ai/dsh-retention' import { defineTool } from '@deepseek-ai/dsh-tools' import type { GenericCallView } from '@deepseek-ai/dsh-tools' import { TaskId } from '@deepseek-ai/dsh-tasks' @@ -41,6 +42,28 @@ export function statusLine(snapshot: TaskSnapshot): string { : `[status: ${snapshot.status}]` } +const encoder = new TextEncoder() + +function retainTail(text: string, maxBytes: number): string { + const retainer = new TextRetainer({ kind: 'tail', maxBytes }) + retainer.push(text) + return retainer.finish().text +} + +function fitWithSuffix( + content: string, + suffix: string, + maxBytes: number | undefined, + omitted: string, +): string { + const complete = `${content}${suffix}` + if (maxBytes === undefined || encoder.encode(complete).byteLength <= maxBytes) return complete + const fixed = `${content.endsWith(omitted.trimStart()) ? '' : omitted}${suffix}` + const fixedBytes = encoder.encode(fixed).byteLength + if (fixedBytes >= maxBytes) return retainTail(fixed, maxBytes) + return `${retainTail(content, maxBytes - fixedBytes)}${fixed}` +} + /** Validate the non-empty constraint that SchemaSpec cannot express. */ function validateTaskId(value: string): TaskId { if (value.length === 0) { @@ -75,8 +98,13 @@ export function apply(ctx: Context, config: Config): void { ctx.tasks.onTaskDone((snapshot, owner) => { if (snapshot.reported || owner === undefined) return try { + const prefix = `background task ${snapshot.id} (${snapshot.kind}: ${snapshot.label})` + const suffix = ` finished ${statusLine(snapshot)}. Read its output with task_output.` owner.inject( - [{ type: 'text', text: `background task ${snapshot.id} (${snapshot.kind}: ${snapshot.label}) finished ${statusLine(snapshot)}. Read its output with task_output.` }], + [{ + type: 'text', + text: fitWithSuffix(prefix, suffix, snapshot.outputLimitBytes, '\n[notice truncated]'), + }], { source: { kind: 'plugin', plugin: 'tool-tasks' } }, ) } catch (error: unknown) { @@ -106,8 +134,16 @@ export function apply(ctx: Context, config: Config): void { } const read = ctx.tasks.read(id, exec.agent) const body = read.text.length > 0 ? read.text : '(no new output)' - const separator = body.endsWith('\n') ? '' : '\n' - return [{ type: 'text', text: `${body}${separator}${statusLine(read.snapshot)}` }] + const content = body.endsWith('\n') ? body.slice(0, -1) : body + return [{ + type: 'text', + text: fitWithSuffix( + content, + `\n${statusLine(read.snapshot)}`, + read.snapshot.outputLimitBytes, + '\n[output truncated]', + ), + }] }, presentCall: args => presentTaskCall(`Read output from background task ${args.task_id}`, 'read', args.task_id), })) @@ -139,7 +175,15 @@ export function apply(ctx: Context, config: Config): void { if (result === 'already-finished') { // A snapshot describes terminal state without consuming pending output. const snapshot = ctx.tasks.get(id, exec.agent) - return Promise.resolve([{ type: 'text', text: `task ${id} had already finished ${statusLine(snapshot)}` }]) + return Promise.resolve([{ + type: 'text', + text: fitWithSuffix( + `task ${id} had already finished`, + ` ${statusLine(snapshot)}`, + snapshot.outputLimitBytes, + '\n[notice truncated]', + ), + }]) } return Promise.resolve([{ type: 'text', text: `requested cancellation of task ${id}` }]) }, diff --git a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts index 4c09845eae..886a1866fe 100644 --- a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts +++ b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts @@ -52,13 +52,19 @@ function detachAgent(agent: Agent): void { function producer(overrides: Partial<Omit<TaskStart, 'run'> & TaskHooks> = {}) { let settle!: (outcome: TaskOutcome) => void const cancels: (string | undefined)[] = [] - const { kind = 'bash', label = 'sleep 60', owner, ...hookOverrides } = overrides + const { kind = 'bash', label = 'sleep 60', owner, outputLimitBytes, ...hookOverrides } = overrides const hooks: TaskHooks = { cancel(reason) { cancels.push(reason) }, done: new Promise<TaskOutcome>((res) => { settle = res }), ...hookOverrides, } - const spec: TaskStart = { kind, label, ...owner !== undefined ? { owner } : {}, run: () => hooks } + const spec: TaskStart = { + kind, + label, + ...owner !== undefined ? { owner } : {}, + ...outputLimitBytes !== undefined ? { outputLimitBytes } : {}, + run: () => hooks, + } return { spec, settle, cancels } } @@ -131,6 +137,18 @@ describe('task_output', () => { expect(text(await call(ctx, 'task_output', { task_id: 'subagent-1' }))).toBe('the answer\n[status: completed, completed]') }) + it('applies a producer limit to the complete body and status result', async () => { + const { ctx } = await setup() + ctx.tasks.start(producer({ + outputLimitBytes: 48, + readOutput: () => '界'.repeat(100), + }).spec) + + const output = text(await call(ctx, 'task_output', { task_id: 'bash-1' })) + expect(Buffer.byteLength(output)).toBeLessThanOrEqual(48) + expect(output).toContain('[status: running]') + }) + it('wait: true blocks until settlement and reports the terminal state', async () => { const { ctx } = await setup() const p = producer({ kind: 'subagent', label: 'research' }) diff --git a/packages/tasks/tool-tasks/tsconfig.json b/packages/tasks/tool-tasks/tsconfig.json index feab4f3be8..cff642796c 100644 --- a/packages/tasks/tool-tasks/tsconfig.json +++ b/packages/tasks/tool-tasks/tsconfig.json @@ -17,6 +17,9 @@ { "path": "../../../vendor/schemastery" }, + { + "path": "../../util/retention" + }, { "path": "../../core/agent" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f60725e0a..72f219d305 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2360,6 +2360,10 @@ importers: version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5) packages/pty/tool-pty: + dependencies: + schemastery: + specifier: ^3.18.0 + version: 3.18.0 devDependencies: '@cordisjs/plugin-include': specifier: workspace:^ @@ -2382,6 +2386,9 @@ importers: '@deepseek-ai/dsh-pty-local': specifier: workspace:^ version: link:../pty-local + '@deepseek-ai/dsh-retention': + specifier: workspace:^ + version: link:../../util/retention '@deepseek-ai/dsh-sandbox': specifier: workspace:^ version: link:../../sandbox/sandbox @@ -3260,6 +3267,9 @@ importers: '@deepseek-ai/dsh-llm': specifier: workspace:^ version: link:../../llm/llm + '@deepseek-ai/dsh-retention': + specifier: workspace:^ + version: link:../../util/retention '@deepseek-ai/dsh-session': specifier: workspace:^ version: link:../../core/session @@ -4109,6 +4119,9 @@ importers: '@deepseek-ai/dsh-repeat-tool-guard': specifier: workspace:^ version: link:../../packages/guard/repeat-tool-guard + '@deepseek-ai/dsh-retention': + specifier: workspace:^ + version: link:../../packages/util/retention '@deepseek-ai/dsh-sandbox': specifier: workspace:^ version: link:../../packages/sandbox/sandbox diff --git a/python/sdk-runtime/package.json b/python/sdk-runtime/package.json index b794f84368..88bedc2ffc 100644 --- a/python/sdk-runtime/package.json +++ b/python/sdk-runtime/package.json @@ -43,6 +43,7 @@ "@deepseek-ai/dsh-permission": "workspace:^", "@deepseek-ai/dsh-paths": "workspace:^", "@deepseek-ai/dsh-repeat-tool-guard": "workspace:^", + "@deepseek-ai/dsh-retention": "workspace:^", "@deepseek-ai/dsh-sandbox": "workspace:^", "@deepseek-ai/dsh-sandbox-policy": "workspace:^", "@deepseek-ai/dsh-scope": "workspace:^", From 01622abde7f19c2bf6cc1f1a3c772ff6f55e2fb8 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:58:05 +0800 Subject: [PATCH 093/368] docs(i18n): refresh core data translations after merge --- .agents/notes/README.i18n.yaml | 4 +- .agents/notes/README.zh.md | 46 +- docs/core-data-structures/approval.i18n.yaml | 4 +- docs/core-data-structures/approval.zh.md | 26 +- docs/core-data-structures/bash.i18n.yaml | 4 +- docs/core-data-structures/bash.zh.md | 236 +++-- .../code-runtime.i18n.yaml | 4 +- docs/core-data-structures/code-runtime.zh.md | 38 +- .../core-data-structures/compaction.i18n.yaml | 4 +- docs/core-data-structures/compaction.zh.md | 52 +- docs/core-data-structures/core.i18n.yaml | 4 +- docs/core-data-structures/core.zh.md | 335 ++++--- .../core-data-structures/filesystem.i18n.yaml | 4 +- docs/core-data-structures/filesystem.zh.md | 114 ++- .../llm-streaming.i18n.yaml | 4 +- docs/core-data-structures/llm-streaming.zh.md | 152 ++- .../persistence.i18n.yaml | 4 +- docs/core-data-structures/persistence.zh.md | 66 +- docs/core-data-structures/sandbox.i18n.yaml | 4 +- docs/core-data-structures/sandbox.zh.md | 71 +- docs/core-data-structures/scope.i18n.yaml | 4 +- docs/core-data-structures/scope.zh.md | 30 +- .../session-query.i18n.yaml | 4 +- docs/core-data-structures/session-query.zh.md | 109 ++- docs/core-data-structures/session.i18n.yaml | 4 +- docs/core-data-structures/session.zh.md | 407 ++++++-- docs/core-data-structures/skills.i18n.yaml | 4 +- docs/core-data-structures/skills.zh.md | 47 +- docs/core-data-structures/subagent.i18n.yaml | 4 +- docs/core-data-structures/subagent.zh.md | 155 +++- .../system-prompt.i18n.yaml | 4 +- docs/core-data-structures/system-prompt.zh.md | 24 +- docs/core-data-structures/tools.i18n.yaml | 4 +- docs/core-data-structures/tools.zh.md | 182 +++- .../user-interaction.i18n.yaml | 4 +- .../user-interaction.zh.md | 15 +- docs/core-data-structures/web.i18n.yaml | 4 +- docs/core-data-structures/web.zh.md | 53 +- docs/core-data-structures/workflow.i18n.yaml | 4 +- docs/core-data-structures/workflow.zh.md | 65 +- ...-acp-default-export-drops-inject.i18n.yaml | 4 +- ...0001-acp-default-export-drops-inject.zh.md | 2 +- ...ession-disabled-filesystem-tools.i18n.yaml | 4 +- ...expression-disabled-filesystem-tools.zh.md | 8 +- docs/postmortem/README.i18n.yaml | 4 +- docs/postmortem/README.zh.md | 2 +- scripts/type-equiv.manifest.json | 867 +++++++++++++++++- 47 files changed, 2685 insertions(+), 509 deletions(-) diff --git a/.agents/notes/README.i18n.yaml b/.agents/notes/README.i18n.yaml index 680bf965c7..7344c11eec 100644 --- a/.agents/notes/README.i18n.yaml +++ b/.agents/notes/README.i18n.yaml @@ -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 -README.md: 9014579f3a98be907885332a0c815bca5c96855c -README.zh.md: 3ed8b5a03c7f5888a331d0220a7b7c7fb6cd68e2 +README.md: 4db9f16956b9c569cf5f9b53f04cb650f6058668 +README.zh.md: b98d54ca64ed6150ddfc9f25c98ac64fe9a344f0 diff --git a/.agents/notes/README.zh.md b/.agents/notes/README.zh.md index 3ed8b5a03c..b98d54ca64 100644 --- a/.agents/notes/README.zh.md +++ b/.agents/notes/README.zh.md @@ -1,32 +1,34 @@ -# RFC +# Agent Notes [English](README.md) | 中文 -这里存放一类设计文档。**RFC** 记录塑造本代码库的决策或提案:代码和文档无法承载的*为什么*以及*放弃了什么*。完整列表见生成的 [INDEX.md](INDEX.md);本文件是契约:RFC 存放在哪里、何时需要写一份,以及[文件内格式](#the-file-format)。 +这里存放一类设计文档。**Agent Note(agent 决策记录)** 记录塑造本代码库的决策或提案:代码和文档无法承载的*为什么*以及*放弃了什么*。本文件是入口和契约:Agent Note 存放在哪里、何时需要写一份,以及[文件内格式](#the-file-format)。 ## 布局与命名 -每份 RFC 有两个维度,都编码在其**路径**中:`{lifecycle}/{class}/yyyy-mm-dd-topic-title.md`。 +每份 Agent Note 有两个维度,都编码在其**路径**中:`{lifecycle}/{class}/yyyy-mm-dd-topic-title.md`。 -- **生命周期**(顶层文件夹)是 RFC 的状态,RFC 随状态变化在文件夹之间移动: +- **生命周期**(顶层文件夹)是 Agent Note 的状态,Agent Note 随状态变化在文件夹之间移动: - **`proposed/`**:实施前评审的提案;尚未构建(或仅部分构建)。 - - **`implemented/`**:决策已交付。文件记录做了什么决定、否决了什么,并**与实际交付的内容保持同步**:当代码后续移动文件、重命名包(package)或更改键名/默认值时,RFC 在同一个变更中同步更新(仅限事实——路径、名称、结构——而非决策本身)。见 [implemented/AGENTS.md](implemented/AGENTS.md)。 + - **`implemented/`**:决策已交付。文件记录做了什么决定、否决了什么,并**与实际交付的内容保持同步**:当代码后续移动文件、重命名包(package)或更改键名/默认值时,Agent Note 在同一个变更中同步更新(仅限事实——路径、名称、结构——而非决策本身)。见 [implemented/AGENTS.md](implemented/AGENTS.md)。 - **`rejected/`**:提案经过讨论后被否决。保留以备查阅,避免同一问题被反复争论。 - **类别**(嵌套文件夹)是决策的*种类*——见下方[分类](#classification)。 -文件名中的日期是该主题**首次提出**的时间(以 git 历史为准)。RFC 之间的交叉引用使用相对 Markdown 链接(`[topic](../../implemented/architecture/2026-…-….md)`),从不使用纯文字或编号,这样既可机械检查,也能在文件夹间移动时保持有效。 +文件名中的日期是该主题**首次提出**的时间(以 git 历史为准)。Agent Note 之间的交叉引用使用相对 Markdown 链接(`[topic](../../implemented/architecture/2026-…-….md)`),从不使用纯文字或编号,这样既可机械检查,也能在文件夹间移动时保持有效。 + +目录树就是清单:浏览其生命周期/类别文件夹,或搜索仓库即可。请勿添加集中式 `INDEX.md`;设计理由见[不设索引的 Agent Note](implemented/process/2026-07-19-remove-generated-agent-note-index.md)。 <a id="classification"></a> ## 分类 -每份 RFC 属于 `scripts/rfc-index.ts` 中封闭集合里的一个路径编码类别;分类门禁拒绝其他文件夹。[INDEX.md](INDEX.md) 由路径、标题和文件名日期生成,其新鲜度受门禁保护。新增类别需要同时更新规范集合与本节。见[分类 RFC](implemented/process/2026-06-20-rfc-classification.md) 与[索引生成 RFC](implemented/process/2026-07-04-generate-rfc-index-tables.md)。 +每份 Agent Note 属于 `scripts/agent-note-tree.ts` 中封闭集合里的一个路径编码类别;分类门禁拒绝其他文件夹。新增类别需要同时更新规范集合与本节。见[分类 Agent Note](implemented/process/2026-06-20-agent-note-classification.md)。 | 类别 | 覆盖范围 | |---|---| -| `feature` | 面向用户或模型的新能力。 | +| `feature` | 面向用户或模型的新功能。 | | `bug-fix` | 修正缺陷或弥补事故复盘(postmortem)发现的缺口。 | -| `simplification` | 在不增加能力的前提下移除代码、行为或对外表面积。 | +| `simplification` | 在不增加功能的前提下移除代码、行为或对外表面积。 | | `architecture` | 关于**交付源码**的结构性决策:包之间的关系、运行时词汇。 | | `process` | 代码**周边**的工具、策略或工作流——门禁、包管理器、vendor 化——不涉及运行时行为。 | | `testing` | 测试基础设施与策略。 | @@ -35,22 +37,22 @@ ## 何时需要写一份 -当一个决策具备以下三个特征时,请写一份 RFC:**持久性**(它的影响超出单个函数或包)、**争议性**(存在一个合理工程师可能选择的真实替代方案)、**意外性**(未来读者否则会问「为什么要这样做」)。对未来重大工作的提案从 `proposed/` 开始;已经做出的决策从 `implemented/` 开始。选择与决策匹配的类别文件夹(见[分类](#classification))。 +每个非平凡变更都必须在同一 PR 中新增或更新至少一份 Agent Note。如果变更修改了行为、架构、跨文件或跨包契约、流程或工具、测试策略、磁盘、协议或配置格式,或者其他维护者可能合理重新审视的决策,就属于非平凡变更。对未来重大工作的提案从 `proposed/` 开始;已经做出的决策从 `implemented/` 开始。选择与决策匹配的类别文件夹(见[分类](#classification))。 -以下情况不要写 RFC:机械性或局部的选择(一个变量名、一次单文件重构);已由门禁或 AGENTS.md 中的约定强制执行并解释的事项;代码中标记为 `TODO(...)` 的临时决策——将其记为 TODO,待稳定后再升级为 RFC。RFC 永远不会被编辑为一个*不同的决策*:用新 RFC 取代旧的,并互相链接。(编辑 `implemented/` RFC 以跟踪其已做出的决策现在*位于*何处——移动的文件、重命名的包——不是不同的决策,这是必需的而非禁止的;见 [implemented/AGENTS.md](implemented/AGENTS.md)。) +更新已经拥有该决策的 Agent Note 即可满足规则;不要创建重复记录。只有不涉及行为、契约、结构、流程或理由变化的纯机械性或局部编辑才可豁免。Agent Note 永远不会被编辑为一个*不同的决策*:用新 Agent Note 取代旧的,并互相链接。编辑 `implemented/` Agent Note 以跟踪其现有决策的所在位置是必需的,而非禁止的;见 [implemented/AGENTS.md](implemented/AGENTS.md)。 <a id="the-file-format"></a> ## 文件格式 -每份 RFC 遵循统一的文件内格式,由 `pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../scripts/verify-rfc-format.ts),`doc-sync`(文档同步门禁)的一环)强制执行;该格式的设计动机及其否决的替代方案见[统一格式 RFC](implemented/process/2026-07-05-uniform-rfc-format.md)。 +每份 Agent Note 遵循统一的文件内格式,由 `pnpm run verify-agent-note-format`([scripts/verify-agent-note-format.ts](../../scripts/verify-agent-note-format.ts),`doc-sync`(文档同步门禁)的一环)强制执行;该格式的设计动机及其否决的替代方案见[统一格式 Agent Note](implemented/process/2026-07-05-uniform-agent-note-format.md)。 ### 头部块 -每份 RFC 的前三行严格为: +每份 Agent Note 的前三行严格为: ```markdown -# RFC: <title> +# Agent Note: <title> Status: <status> ``` @@ -61,11 +63,11 @@ Status: <status> - `Status: implemented` - `Status: rejected — <why, in one line>` -状态行不带日期、不带括号补充说明:文件名记录首次提出日期,git 记录其余一切;「以修订形式接受」之类的说明属于正文内容(在陈述决策的地方说明修订)。拒绝原因是唯一带内容的状态,因为读者查阅被否决的 RFC 时,结论正是他们要找的。 +状态行不带日期、不带括号补充说明:文件名记录首次提出日期,git 记录其余一切;「以修订形式接受」之类的说明属于正文内容(在陈述决策的地方说明修订)。拒绝原因是唯一带内容的状态,因为读者查阅被否决的 Agent Note 时,结论正是他们要找的。 ### 正文骨架 -每份 RFC 的正文以 `## Problem` 开头:动机,写法上不依赖解决方案即可独立成文。后续内容取决于生命周期;固定章节使用以下规范名称且仅限这些名称,而真正独特的技术章节(包拓扑、协议契约、schema 等)在必需章节之间可自由组织。 +每份 Agent Note 的正文以 `## Problem` 开头:动机,写法上不依赖解决方案即可独立成文。后续内容取决于生命周期;固定章节使用以下规范名称且仅限这些名称,而真正独特的技术章节(包拓扑、协议契约、schema 等)在必需章节之间可自由组织。 #### `proposed/` @@ -90,20 +92,20 @@ Status: <status> ## Consequences ``` -`## Decision` 以现在时态描述已交付的现实,整个文件按 [implemented/AGENTS.md](implemented/AGENTS.md) 的要求与之保持同步。`## Consequences` 记录权衡的代价**与**收益。提案阶段的标题在此属于规格用语,门禁会拒绝它们:`## Proposal`、`## Plan`、`## Migration plan` 和 `## Acceptance criteria` 不得出现在 implemented RFC 中(原因见 [slop 检查清单](../AGENTS.md))。`## Testing`、`## Deferred` 或 `## Related` 章节在陈述现在时态的事实时是允许的。 +`## Decision` 以现在时态描述已交付的现实,整个文件按 [implemented/AGENTS.md](implemented/AGENTS.md) 的要求与之保持同步。`## Consequences` 记录权衡的代价**与**收益。提案阶段的标题在此属于规格用语,门禁会拒绝它们:`## Proposal`、`## Plan`、`## Migration plan` 和 `## Acceptance criteria` 不得出现在 implemented Agent Note 中(原因见 [slop 检查清单](../../docs/AGENTS.md))。`## Testing`、`## Deferred` 或 `## Related` 章节在陈述现在时态的事实时是允许的。 #### `rejected/` -被否决的 RFC 是冻结的提案:保留提案时的所有章节(包括 `## Acceptance criteria` 或 `## Plan`),结论写在 `Status:` 行上。仅头部块、`## Problem` 开头、`## Proposal` 章节以及下方的「曾考虑的替代方案」强制要求适用。 +被否决的 Agent Note 是冻结的提案:保留提案时的所有章节(包括 `## Acceptance criteria` 或 `## Plan`),结论写在 `Status:` 行上。仅头部块、`## Problem` 开头、`## Proposal` 章节以及下方的「曾考虑的替代方案」强制要求适用。 ### 曾考虑的替代方案——必需 -每份 RFC 都必须包含 `## Alternatives considered` 章节:每个真实的替代方案及其落选原因,每个替代方案用一个加粗引导的段落,或对争议较大的替代方案用 `### Why not <X>?` 子节。记录决策时不记录它击败了什么,就是在邀请反复争论——正是 RFC 存在的意义所要防止的。 +每份 Agent Note 都必须包含 `## Alternatives considered` 章节:每个真实的替代方案及其落选原因,每个替代方案用一个加粗引导的段落,或对争议较大的替代方案用 `### Why not <X>?` 子节。记录决策时不记录它击败了什么,就是在邀请反复争论——正是这些 Agent Note 存在的意义所要防止的。 -替代方案是记录下来的,不是凭空编造的。日期早于 2026-07-05 且替代方案无法从记录中重建的 RFC,在该章节位置放置以下精确注释,门禁仅对格式规范之前的文件接受此注释: +替代方案是记录下来的,不是凭空编造的。日期早于 2026-07-05 且替代方案无法从记录中重建的 Agent Note,在该章节位置放置以下精确注释,门禁仅对格式规范之前的文件接受此注释: ```markdown -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> ``` ### 在生命周期之间移动 @@ -112,4 +114,4 @@ Status: <status> ### 中文对侧文件 -`.zh.md` 对侧文件按 [i18n 契约](../i18n/README.md)逐章节镜像其英文兄弟文件的结构;机器检查的头部标记(`# RFC: ` 和 `Status:` 行)保持英文原样不翻译。格式门禁跳过 `.zh.md` 文件——配对门禁负责它们的一致性。 +`.zh.md` 对侧文件按 [i18n 契约](../../docs/i18n/README.md)逐章节镜像其英文兄弟文件的结构;机器检查的头部标记(`# Agent Note: ` 和 `Status:` 行)保持英文原样不翻译。格式门禁跳过 `.zh.md` 文件——配对门禁负责它们的一致性。 diff --git a/docs/core-data-structures/approval.i18n.yaml b/docs/core-data-structures/approval.i18n.yaml index 9a644ee85a..c6bfeafaf9 100644 --- a/docs/core-data-structures/approval.i18n.yaml +++ b/docs/core-data-structures/approval.i18n.yaml @@ -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 -approval.md: 772582955145092f3d483c297f7704b2b8506375 -approval.zh.md: 706613b84784d81cf112622059c755e815c23f16 +approval.md: c9b411e38508fc7e8ac2e2dd923d9c8cc2f475a3 +approval.zh.md: ee593298fece8b2782228f2e93c5509871e15166 diff --git a/docs/core-data-structures/approval.zh.md b/docs/core-data-structures/approval.zh.md index 706613b847..ee593298fe 100644 --- a/docs/core-data-structures/approval.zh.md +++ b/docs/core-data-structures/approval.zh.md @@ -8,15 +8,23 @@ ## 标识与结果 -每个请求获得一个全新的 `ApprovalRequestId`。该品牌类型将 `approval/asked` 和 `approval/decided` 审计事件配对,同时确保审批 id 不会与 tool-call、session 或 agent id 混用。 +每个请求都会获得一个全新的 `ApprovalRequestId`。该品牌类型将 `approval/asked` 与 `approval/decided` 审计事件配对,同时不会让审批 id 与工具调用 id 或 agent/session id 互换。 ```ts type-equiv +/** + * Pairs one `approval/asked` audit event with its `approval/decided`. + * Service-issued (one fresh id per {@link ApprovalService.request} call). + */ type ApprovalRequestId = Branded<'ApprovalRequestId'> ``` `ApprovalOutcome` 是闭合的,且默认拒绝。`allowed-once` 仅授权所询问的那一个操作;调用方对 `rejected`、`cancelled` 和 `unavailable` 均执行拒绝。缺失、无所有权、抛异常或不合规的应答者会产生 `unavailable`,而非放行。 ```ts type-equiv +/** + * Closed approval outcomes: a one-shot grant, explicit rejection, withdrawn + * request, or unavailable answerer. Callers fail closed on `unavailable`. + */ type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable' ``` @@ -25,6 +33,18 @@ type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable' `ApprovalPolicy` 决定在交互式应答者运行之前发生什么。`ask` 委托给组合的应答者链,链的无应答默认值为 `unavailable`;`never` 确定性地返回 `rejected`,不分发任何应答者。生效值为会话日志中最后一条 `approval/policy` 事件,回退到服务配置。`setApprovalPolicy(session, policy)` 是唯一的写入路径,因此回放能重建覆盖值。 ```ts type-equiv +/** + * A session's approval policy — what happens to an {@link ApprovalService} + * ask BEFORE any interactive answerer sees it: + * + * - `'ask'` (the default) — delegate to the composed answerers; with none + * composed the chain falls through to the fail-closed `'unavailable'` + * (exactly today's behavior). + * - `'never'` — never prompt anyone: every ask resolves `'rejected'` + * deterministically. The strict headless stance (CI, unattended runs) and + * the only policy value stated in the system prompt — unlike `'ask'`, its + * outcome is knowable without asking, so stating it cannot overclaim. + */ type ApprovalPolicy = 'ask' | 'never' ``` @@ -35,6 +55,10 @@ type ApprovalPolicy = 'ask' | 'never' `ApprovalRequest` 以足够精确的方式标识 agent 和工具操作,以便路由和审计该问题。它有意省略工具参数:应答者通过 `callId` 将提示附加到已流式输出的工具调用上,而非渲染一份可能漂移的副本。 ```ts type-equiv +/** + * Readonly same-process permission question. `callId` links to an already + * presented tool call, so arguments are not duplicated here. + */ interface ApprovalRequest { /** * The agent on whose behalf the question is asked. Routes the question (a diff --git a/docs/core-data-structures/bash.i18n.yaml b/docs/core-data-structures/bash.i18n.yaml index 601c350359..168c96a10a 100644 --- a/docs/core-data-structures/bash.i18n.yaml +++ b/docs/core-data-structures/bash.i18n.yaml @@ -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 -bash.md: 7b5c779b832ef5be6591e626980f7f22db54f239 -bash.zh.md: c4d27efa8344727e3a77c928b331ec570c2716eb +bash.md: 35cf2061588907dde41123efb01e453eb9cc929d +bash.zh.md: 56e5ae7b6231575a6b591093724d5560ade27056 diff --git a/docs/core-data-structures/bash.zh.md b/docs/core-data-structures/bash.zh.md index c4d27efa83..56e5ae7b62 100644 --- a/docs/core-data-structures/bash.zh.md +++ b/docs/core-data-structures/bash.zh.md @@ -2,21 +2,48 @@ [English](bash.md) | 中文 -Bash 执行 seam:典型的[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md) 示例,拆分为三个包(package):接口([dsh-bash](../../packages/bash/bash),`ctx.bash`)、实现([dsh-bash-local](../../packages/bash/bash-local),本地子进程)和消费方([dsh-tool-bash](../../packages/bash/tool-bash),`bash`/`bash_output`/`bash_kill` 工具 schema)。Bash 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此处而非 [core.md](core.md)。沙箱化、容器化或远程后端是实现同一接口的兄弟包。 +bash 执行 seam 分为接口([dsh-bash](../../packages/bash/bash),`ctx.bash`)、实现([dsh-bash-local](../../packages/bash/bash-local) 与 [dsh-bash-sandbox](../../packages/bash/bash-sandbox))和消费方([dsh-tool-bash](../../packages/bash/tool-bash),即 `bash` schema)。通用后台任务的 id、所有权与控制位于 [tasks.md](tasks.md);本 seam 返回一个不含任务概念的进程句柄。 源码:[`packages/bash/bash/src/types.ts`](../../packages/bash/bash/src/types.ts) -## 请求与规格:`resolve()` 拆分 +## 受管 shell 环境命名空间 -该 seam 将**面向模型/插件的请求**(`workdir`/`timeoutMs` 可选,由配置填充)与**执行器实际执行的完全解析规格**(这些字段为必填)分离。工具层在二者之间调用 `ctx.bash.resolve(request)`。这是本仓库「在包边界处显式优于隐式」规则的具体体现:阅读 `BashExecSpec` 的人永远不会疑惑工作目录从何而来。 +`DSH_*` 变量是归 Harness 所有的子进程事实。面向模型的 bash 工具通过 `ctx.bashEnv` 收集它们,再经由 `BashExecRequest.dshEnv` 传递;执行器在合并当前快照之前会移除继承而来的 `DSH_*` 名称。 ```ts type-equiv +/** One environment key inside the managed {@link DSH_ENV_PREFIX} namespace. */ +type DshEnvironmentKey = `${typeof DSH_ENV_PREFIX}${string}` +``` + +```ts type-equiv +/** Trusted DeepSeek Harness variables for one bash execution. */ +type DshEnvironment = Readonly<Record<DshEnvironmentKey, string>> +``` + +## 请求与规格:`resolve()` 拆分 + +该 seam 将**面向模型/插件的请求**(`workdir`/`timeoutMs`/`stdoutMaxBytes` 可选,由配置或请求策略补全)与执行器实际使用的**完全解析后的 spec**(这些字段均为必填)分开。工具层在二者之间调用 `ctx.bash.resolve(request)`——这具体落实了仓库的「包 seam 上显式优于隐式」规则:`BashExecSpec` 的读者不必猜测工作目录或输出预算来自何处。 + +```ts type-equiv +/** + * A caller's execution REQUEST: `workdir` and `timeoutMs` are optional and + * filled by {@link BashExecutor.resolve} from the implementation's config. + * This is the model-/plugin-facing shape; pass it to `resolve()` to obtain a + * fully-resolved {@link BashExecSpec}. + */ interface BashExecRequest { command: string /** Working directory override (default: implementation-configured). */ workdir?: string | undefined /** Timeout override in milliseconds (implementations cap it). */ timeoutMs?: number | undefined + /** + * Foreground stdout capture budget in bytes. Absent uses the executor's + * default output cap. Trusted in-process consumers use this when they must + * parse complete stdout up to their own bounded limit; the model-facing bash + * tool does not expose it as a parameter. + */ + stdoutMaxBytes?: number | undefined /** Abort signal — implementations kill the command when it fires. */ signal?: AbortSignal | undefined /** @@ -28,115 +55,92 @@ interface BashExecRequest { */ stdin?: string | undefined /** - * Extra environment entries for the command, merged AFTER the - * implementation's credential scrub (so an explicit entry here is honored even - * when its name matches the scrub pattern — the caller named a value it holds, - * not the harness's ambient secret). Set by in-process plugins (the hooks - * bridges set `CLAUDE_PROJECT_DIR`, `CLAUDE_PLUGIN_ROOT`, …); the model-facing - * bash tool does not expose it as a parameter (a model that needs an env var - * uses shell syntax like `FOO=bar cmd`). + * Ordinary environment entries for the command, merged after the credential + * scrub. `DSH_*` is reserved for {@link dshEnv} and implementations reject it + * here. Set by in-process plugins (the hooks bridges set + * `CLAUDE_PROJECT_DIR`, `CLAUDE_PLUGIN_ROOT`, …); the model-facing bash tool + * does not expose it as a parameter. */ env?: Record<string, string> | undefined /** - * Opaque OWNER token for a background task — the consumer's isolation key - * (the tool layer passes the owning agent's `session.header.id`). The - * executor stores it on the task and exposes it via {@link BashExecutor.ownerOf}; - * the executor itself NEVER interprets it (no access policy lives in the - * seam — that is the consumer's job). Absent for foreground runs and for an - * ownerless background start (a non-agent caller). + * Harness-owned `DSH_*` variables for this execution. Executors discard + * ambient `DSH_*` entries before merging this snapshot, so an unavailable + * current fact cannot inherit a stale value from the harness process, and + * reject non-`DSH_*` names supplied through this managed channel. */ - owner?: OwnerToken | undefined - /** - * Explicit per-call sandbox-policy input, overriding the executor's - * configured default mode for THIS call. Never a silent default: a - * consumer sets it only from an explicit policy source — an - * `'allowed-once'` grant a human just issued through `ctx.approval` (the - * escalation flow in the sandbox RFC § Escalation, which outranks), or the - * session's standing override folded from its own `bash/sandbox-mode` - * events (the sandbox RFC § Per-session mode switching — the user's recorded per-session - * choice). A sandboxing executor confines THIS call under the given mode; - * a non-sandboxing executor carries the field and confines nothing (the - * tool layer stamps neither escalation nor overrides without a sandboxing - * executor — see {@link BashExecutor.sandboxMode}). - */ - sandboxMode?: SandboxMode | undefined + dshEnv?: DshEnvironment | undefined + /** Fully resolved per-call sandbox policy; sandboxing executors default it. */ + sandboxPolicy?: SandboxExecutionPolicy | undefined } ``` ```ts type-equiv +/** + * A resolved execution spec. {@link BashExecutor.resolve} fills and caps the + * required fields; {@link BashExecutor.start} ignores `timeoutMs` because + * background processes have no executor timeout. + */ interface BashExecSpec { command: string workdir: string timeoutMs: number + /** + * Resolved foreground stdout capture budget in bytes. `run()` uses it for + * stdout; background tasks and stderr keep the executor's own output cap. + */ + stdoutMaxBytes: number /** Abort signal — implementations kill the command when it fires. */ signal?: AbortSignal | undefined - /** - * Bytes to write to the command's stdin (then close it), carried through - * verbatim from {@link BashExecRequest.stdin}. OPTIONAL on the resolved spec - * (unlike `owner`): it has no config default, so a missing one means "no - * stdin" — the safe, ordinary case — not a silent footgun, so it stays a - * plain optional rather than required-but-nullable (see the request field). - */ + /** Bytes to write to stdin before closing it; absent means no stdin. */ stdin?: string | undefined /** - * Extra environment entries, carried through verbatim from - * {@link BashExecRequest.env} and merged by the implementation AFTER its - * credential scrub (an explicit entry wins even when its name matches the - * scrub pattern). OPTIONAL on the spec for the same reason as `stdin` — no - * config default, absent means "no extra env". + * Ordinary environment entries carried through from + * {@link BashExecRequest.env}. `DSH_*` remains reserved for {@link dshEnv}. + * OPTIONAL on the spec for the same reason as `stdin`: absent means no + * ordinary extra environment. */ env?: Record<string, string> | undefined - /** - * Opaque owner token, REQUIRED-but-nullable (mirrors `workdir`/`timeoutMs` - * being required on the resolved spec): {@link BashExecutor.resolve} carries - * the request's `owner` through, defaulting a missing one to `undefined`. A - * required field makes a forgotten owner a VISIBLE `undefined` rather than a - * silently-absent property that yields an unowned (cross-session-readable) - * task. `start()` stores it; `run()` (foreground) ignores it. - */ - owner: OwnerToken | undefined - /** - * The sandbox mode this call executes under, REQUIRED-but-nullable for the - * same visibility reason as `owner`. A sandboxing executor's `resolve()` - * stamps the effective mode (the request's explicit override, else its - * configured default) so `run()`/`start()` read the spec, never the config; - * a non-sandboxing executor carries the request value through verbatim and - * ignores it (`undefined` under such an executor means what its README says: - * unconfined execution). - */ - sandboxMode: SandboxMode | undefined + /** Managed `DSH_*` snapshot; implementations reject ordinary names. */ + dshEnv?: DshEnvironment | undefined + /** Resolved sandbox policy; ignored by executors that do not confine. */ + sandboxPolicy: SandboxExecutionPolicy | undefined } ``` -`owner` token 是隔离键:执行器存储它但从不解释它(访问策略是消费方的职责),因此一个 agent 启动的后台任务不会被跨会话读取。必填但可空的字段使遗忘的 owner 成为一个可见的 `undefined`,而非一个静默无主的任务。 +`stdin` 和 `env` 是受信任的进程内插件输入,不由 `dsh-tool-bash` 暴露。本地执行器会先清除环境中的凭据,再合并调用方显式提供的 env。见 [bash-stdin-env Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md)。 -受信的进程内插件使用 `stdin` 和 `env` 传递钩子载荷与钩子专用变量。面向模型的 bash 工具从其命名的 schema 字段构造请求,不暴露这两个输入,因为 shell 语法本身已提供等价能力;测试防止未来出现 `...args` 展开。这是请求形状的纪律约束,而非安全边界:`dsh-bash-local` 无论这些字段如何都会清洗环境凭证,然后叠加调用方已持有的显式值。见 [bash stdin/env RFC](../rfc/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md)。 - -该 seam 处理的两个 id 都是[品牌化的](core.md)(零成本 `string` 品牌,与 `SessionId`/`AgentId` 相同的机制):`BashTaskId`(被跟踪的后台任务,由本地执行器生成 `bash-N`)和 `OwnerToken`(不透明的隔离键)。`OwnerToken` 刻意是一个与 `SessionId` 不同的品牌,而非别名:bash seam 是一个能力 seam,不得知道 owner token *意味着*什么,因此它从不导入 `dsh-session` 的词汇。`dsh-tool-bash` 消费方是唯一将拥有者 agent 的 `SessionId` 转换为 `OwnerToken` 的边界。对两者施加品牌化,可以防止裸 `string`(或在需要 `OwnerToken` 的地方传入 `BashTaskId`,反之亦然)在面向模型的 `task_id` 路径上通过类型检查。 +`stdoutMaxBytes` 同样仅供受信任插件使用。它让前台消费方能在有界解析预算内请求完整 stdout,而不会改变 stderr、后台任务或面向模型的 bash 工具的常规输出上限。 ## 前台运行:`BashRunResult` 一次已完成(或被终止)的前台运行的结果。正交的结果**独立报告**:一个进程可以同时超时并以退出码 0 退出(因为它捕获了信号),因此 `timedOut`、`aborted`、`signal` 和 `exitCode` 各自独立为一个字段;调用方永远不会把一次被截断的运行误读为干净的成功。 ```ts type-equiv +/** The outcome of one completed (or killed) foreground run. */ interface BashRunResult { /** Exit code; null when the process died from a signal. */ exitCode: number | null /** Terminating signal (e.g. 'SIGTERM'); null on normal exit. */ signal: NodeJS.Signals | null - /** True when the executor's own timeout killed the command. */ + /** + * True when the executor's own timeout was the FIRST cause to cut the command + * short. Mutually exclusive with {@link aborted}: one fused deadline drives + * both the timeout and the caller's cancellation, so a timeout and an abort + * racing before process close report the single first-abort cause, not both + * (see the [timeout-library Agent Note](../../../../.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.md)). + */ timedOut: boolean - /** True when the caller's AbortSignal killed the command. */ + /** + * True when the caller's `AbortSignal` was the FIRST cause to kill the command + * (and it was not the executor's own timeout). Mutually exclusive with + * {@link timedOut} — see there for the first-cause classification. + */ aborted: boolean /** The effective timeout applied to this run (after defaulting/capping). */ timeoutMs: number stdout: CollectedOutput stderr: CollectedOutput - /** - * Sandbox facts, present iff a sandboxing executor ran the command — an - * unsandboxed executor (e.g. `dsh-bash-local`) never sets it. See - * {@link BashSandboxInfo} for the `denied` classification semantics. - */ + /** Sandbox execution facts, absent for an unsandboxed executor. */ sandbox?: BashSandboxInfo } ``` @@ -144,6 +148,7 @@ interface BashRunResult { 每个流是一个 `CollectedOutput`:(可能被截断的)文本加恢复信息。截断时,`text` 是**尾部**,完整流溢出到一个私有文件: ```ts type-equiv +/** One captured stream: the (possibly truncated) text plus recovery info. */ interface CollectedOutput { /** Collected text — the TAIL of the stream when truncated. */ text: string @@ -156,79 +161,70 @@ interface CollectedOutput { ## 文件沙箱:`BashSandboxInfo` -消费沙箱的执行器(`dsh-bash-sandbox`)通过 `BashExecutor.sandboxMode` 暴露其配置的回退模式。工具层折叠每个 agent 会话的持久 `bash/sandbox-mode` 覆盖,将生效模式印到请求上,并可为一次用户批准的严格更宽调用替换它。它刻意既不声明当前模式也不叙述切换过程;拒绝结果会指明该命令实际运行时所处的模式。模式/执行词汇由 [`@deepseek-ai/dsh-sandbox` seam](sandbox.md) 拥有并编目,其提供方包装执行器的 argv;模式仅管控文件效果,不涉及网络或进程可见性。 +消费 sandbox 的执行器通过 `BashExecutor.sandboxMode` 暴露其已配置的模式回退值。工具层请求 [`@deepseek-ai/dsh-sandbox-policy`](../../packages/sandbox/sandbox-policy/README.md),把每个调用会话的持久 `sandbox/mode` 覆盖值与不可变 cwd 解析为 `BashExecRequest.sandboxPolicy`;经用户批准、严格更宽松的调用只替换模式。模式/root/enforcement 词汇归 [`@deepseek-ai/dsh-sandbox` seam](sandbox.md) 所有;模式仅管辖文件效果。 -沙箱化运行始终在 `BashRunResult.sandbox` 上报告其执行时的事实:`denied` 是执行器对失败的保守分类——判定为沙箱导致(退出失败且 stderr 携带文件系统权限特征——从不是干净退出或信号终止),从收集到的 stderr 尾部读取;`enforcement` 报告所选后端对该模式文件效果的管控完整程度(`SandboxEnforcement = 'full' | 'partial'`:`partial` 表示较旧的 Landlock ABI 仅管控所请求访问的子集;`danger-full-access` 下不存在此字段,因为没有任何限制);`runnerFailed` 标记与拒绝相反的情况——沙箱运行器本身失败、命令从未执行(仅在已结算的后台任务上标记;前台运行通过抛出 `SANDBOX_UNAVAILABLE` 错误暴露同一状况): +sandbox 化运行会报告其模式、保守的拒绝分类与强制执行完整度。`runnerFailed` 标记命令运行前 sandbox runner 已失败;前台执行会抛出 `SANDBOX_UNAVAILABLE`,而已结束的后台进程只能通过其事实通道报告。 ```ts type-equiv +/** + * Sandbox facts for one run, present iff a sandboxing executor handled it. + * Facts are reported independently of process exit status so callers can + * distinguish command failures from policy denials and runner failures. + */ interface BashSandboxInfo { /** The mode the command actually ran under. */ mode: SandboxMode - /** - * True when the executor classifies this run's failure as the sandbox - * denying a file operation. The classification is CONSERVATIVE (a failed - * exit whose stderr carries a filesystem-permission signature) and reads - * the COLLECTED stderr — the bounded in-memory tail per - * {@link CollectedOutput} semantics, so a signature that survives only in a - * spill file is missed toward `denied: false`. A plain command failure - * keeps `denied: false` even under a sandboxed mode. - */ + /** Whether the sandbox denied a file operation. */ denied: boolean - /** - * How completely the runner enforced `mode`'s file effects — see - * {@link SandboxEnforcement}. Absent exactly when `mode` is - * `danger-full-access`: nothing is confined, so there is no enforcement to - * report. - */ + /** How completely the selected runner enforced the requested mode. */ enforcement?: SandboxEnforcement - /** - * True when the executor classifies this failure as the SANDBOX RUNNER - * itself failing (missing binary, refused profile, fail-closed refusal - * before exec) — the command NEVER RAN; this is a sandbox failure, not a - * task failure, and it outranks `denied` (a runner's own error text can - * contain denial words). Only ever stamped on settled BACKGROUND tasks: a - * foreground run surfaces the same condition as the thrown - * `SANDBOX_UNAVAILABLE` error instead (the foreground path has an error - * channel; a settled task's facts are its only channel). - */ + /** Whether the sandbox runner failed before the command could run. */ runnerFailed?: boolean } ``` -还有一个词汇完成整幅图景:`SANDBOX_UNAVAILABLE` 错误码(由 [sandbox seam](sandbox.md) 拥有)是 `ctx.sandbox` 提供方在受限模式没有可用后端时抛出的错误,执行器将其传播。所选运行器拒绝其 profile 时也触发同一快速失败的前台错误;已结算的后台任务则记录 `runnerFailed`。模型在结果中接收拒绝/运行器事实,仅在拒绝标记指明模式时才获知生效模式,并可通过 `sandbox_permissions` 加 `justification` 请求一次严格更宽的重试;`ctx.approval` 必须在任何执行之前批准该确切调用。完整的策略与切换设计见 [sandbox RFC](../rfc/implemented/feature/2026-07-06-sandbox.md)。 +最后一项补全了这套词汇:当受限模式没有可用后端时,`ctx.sandbox` 提供方会抛出、执行器会传播由 [sandbox seam](sandbox.md) 所有的 `SANDBOX_UNAVAILABLE` 错误码。选定的 runner 拒绝其 profile 时会触达同一个故障关闭的前台错误;已结束的后台任务则记录 `runnerFailed`。模型会在结果中收到拒绝/runner 事实,仅当拒绝标记指出生效模式时才得知该模式,并可通过 `sandbox_permissions` 加 `justification` 请求一次性、严格更宽松的重试;执行任何操作前,`ctx.approval` 必须批准该次确切调用。完整的策略与切换设计见 [sandbox Agent Note](../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。 -## 后台任务:`BashTask` +## 后台进程:`BashProcess` -通过 `start()` 启动的长时间运行命令被跟踪为 `BashTask`。`BashTaskStatus` 为 `'running' | 'completed' | 'killed'`;`done` 在底层进程关闭时 resolve,从不 reject。沙箱化执行器在任务结算后标记 `sandbox`(分类针对已结算任务收集到的 stderr 运行),因此该字段在运行中以及非沙箱化执行器下不存在。 +`start()` 返回不含 id 或所有者的句柄。`dsh-tool-bash` 将它适配为 `ctx.tasks.start()` hooks;随后由通用运行时拥有任务标识与生命周期。`done` 在进程关闭时 resolve 且绝不 reject;进程结束后仍可读取,并且 sandbox 事实会在 `done` resolve 前写入。 ```ts type-equiv -interface BashTask { - readonly id: BashTaskId - status: BashTaskStatus +/** + * A background process handle returned by {@link BashExecutor.start}. It is the + * only access path; buffered output remains readable after exit. Executor + * disposal kills running processes and awaits {@link done}. + */ +interface BashProcess { + /** Process lifecycle state (settled exactly once). */ + status: BashProcessStatus /** Exit code once finished (null = killed by signal / still running). */ exitCode: number | null /** Terminating signal name, when signal-killed. */ signal: NodeJS.Signals | null - /** Resolves when the underlying process closes (never rejects). */ + /** Resolves when the underlying process closes (never rejects — a spawn failure settles as `killed` with the error on stderr). */ readonly done: Promise<void> - /** - * Sandbox facts for this task's execution, stamped by a sandboxing executor - * once the task settles and BEFORE completion listeners are notified — an - * `onTaskDone` consumer and a `done` awaiter both see it. Denial - * classification runs against the settled task's collected stderr, so the - * field cannot exist earlier: absent while the task is running and under an - * executor that does not sandbox. See {@link BashSandboxInfo} for the - * `denied` semantics. - */ + /** Sandbox facts, stamped once a confined process settles. */ sandbox?: BashSandboxInfo + /** + * Read output produced since the previous read (consuming — consecutive + * reads never re-deliver). Reads that lost data flag `lossy` and point at + * full-stream spill files when available. + */ + readOutput(): BashProcessRead + /** + * Kill the process group. Returns false when it had already finished + * (no-op); idempotent. + */ + kill(): boolean } ``` -`readOutput()` 返回增量的 `BashTaskRead`:自上次读取以来产生的输出,附带一个 `lossy` 标志指示截断是否丢弃了未读字节: +`readOutput()` 返回增量 delta 与 spill 恢复事实: ```ts type-equiv -interface BashTaskRead { - task: BashTask +/** One incremental {@link BashProcess.readOutput} read. */ +interface BashProcessRead { /** Output produced since the previous read (stderr in a marked section). */ delta: string /** True when truncation dropped unread bytes the delta cannot include. */ @@ -242,4 +238,4 @@ interface BashTaskRead { ## 服务 -`BashExecutor`(`ctx.bash`,抽象——定义于 [`packages/bash/bash/src/index.ts`](../../packages/bash/bash/src/index.ts))遵循 `LlmService`/`LlmAdapter` 的拆分模式:`resolve`(请求→规格)、`run`(前台)、`start`(后台)、`get`/`ownerOf`/`list`/`readOutput`/`kill`,以及 `onTaskDone`(`BashTaskListener` 完成回调)。spawn 的命令获得一个**清洗后的 env**(丢弃 `*KEY*`/`*SECRET*`/`*TOKEN*`),溢出文件使用一个权限为 0700 的私有目录(随机文件名、仅所有者可打开)。模型输出永远不会获得环境变量或可预测路径。提供这一切的实现是 `dsh-bash-local`;调用它的面向模型的 `bash`/`bash_output`/`bash_kill` schema 位于 `dsh-tool-bash`(并通过[工具展示词汇](tools.md#tool-presentation-ui-vocabulary)作为终端呈现)。 +`BashExecutor` 拥有 `resolve`、前台 `run`、后台进程 `start` 以及 `sandboxMode` 能力事实。`dsh-bash-local` 拥有进程组、超时/中止处理、有界收集器、spill 文件、凭据清除以及 dispose 后完全停稳。`dsh-tool-bash` 拥有面向模型的渲染,并将后台句柄适配到[通用任务运行时](tasks.md)。 diff --git a/docs/core-data-structures/code-runtime.i18n.yaml b/docs/core-data-structures/code-runtime.i18n.yaml index 918b3f5738..21bf3ee3e0 100644 --- a/docs/core-data-structures/code-runtime.i18n.yaml +++ b/docs/core-data-structures/code-runtime.i18n.yaml @@ -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 -code-runtime.md: 28152947d0853fb10228c472ca3e121e77b7b598 -code-runtime.zh.md: 7d5750e0c245ba97ed7ece6083464382109e10fd +code-runtime.md: a984c0f6422defc879086ff95eb94048aaa6e285 +code-runtime.zh.md: c3989fa10814139fefe91e99d9b050c1e851f8ed diff --git a/docs/core-data-structures/code-runtime.zh.md b/docs/core-data-structures/code-runtime.zh.md index 7d5750e0c2..c3989fa108 100644 --- a/docs/core-data-structures/code-runtime.zh.md +++ b/docs/core-data-structures/code-runtime.zh.md @@ -2,7 +2,7 @@ [English](code-runtime.md) | 中文 -代码执行 seam:一个[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md),其接口([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)运行一段模型编写的程序,对接宿主提供的异步绑定,并报告程序的打印输出与返回值。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此,而非 [core.md](core.md)。后端因执行基底和源语言而异,二者都是服务上的只读描述符;worker-thread 后端与工具注册表消费方(Code Mode)在 [Code Mode RFC](../rfc/implemented/feature/2026-06-15-code-mode.md) 中定义。 +代码执行 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):其接口([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)针对宿主提供的异步 binding 运行一段模型编写的程序,并报告其打印内容与返回值。代码执行是**一项可选能力**,不属于 agent loop 主干,因此其词汇定义在此而非 [core.md](core.md) 中。各后端的执行基底与源语言不同,这两项均为服务上的只读描述符;worker-thread 后端和工具注册表消费方(Code Mode)由 [Code Mode Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) 规定。 源码:[`packages/code-runtime/code-runtime/src/types.ts`](../../packages/code-runtime/code-runtime/src/types.ts) @@ -11,6 +11,12 @@ `CodeRunRequest` 携带**运行时所需的一切**。按照「包(package)边界处显式优于隐式」的规则,默认值(时间预算、输出上限)来自实现的已校验配置,绝不是 `run()` 内部隐藏的 `??`: ```ts type-equiv +/** + * One run: the program source plus everything the runtime acts on. Per the + * explicit-over-implicit convention, defaulting (time budgets, output caps) + * is the implementation's validated config — a request carries no optional + * tuning knobs for a hidden `??` to fill in. + */ interface CodeRunRequest { /** * The program source, in the runtime's {@link ../index.ts | language}. It @@ -33,6 +39,11 @@ interface CodeRunRequest { 结果将错误报告为一个**字段**,而非 `run()` 的 rejection。报告失败的程序是调用方的职责,不走异常路径(与 `BashExecutor.run` 的 resolve-on-failure 契约一致): ```ts type-equiv +/** + * The outcome of one run. An error is a FIELD on a resolved result, never a + * rejection of `run()` — reporting a failed program is the caller's job, not + * an exception path. + */ interface CodeRunResult { /** * The program's completion value (its top-level `return`), when it ran to @@ -53,6 +64,13 @@ interface CodeRunResult { 每个 `CodeBindingNamespace` 在程序内成为一个由异步可调用函数组成的全局对象(Code Mode 消费方传入一个:`tools`)。参数与返回值必须可 structured-clone(运行时可能跨序列化边界桥接调用),且运行时将绑定名视为不可信输入(`__proto__` 是普通自有属性,绝不会发生原型碰撞): ```ts type-equiv +/** + * A named group of {@link CodeBindingFunction}s the runtime exposes to the + * program as one global object (e.g. `tools`). Function names are arbitrary + * strings — a runtime must treat names like `__proto__` or `constructor` as + * ordinary own properties (null-prototype construction), never as prototype + * collisions. + */ interface CodeBindingNamespace { /** The global identifier the program sees (must be a valid JS identifier). */ global: string @@ -62,6 +80,14 @@ interface CodeBindingNamespace { ``` ```ts type-equiv +/** + * One host-side function exposed to the program as an async callable. The + * runtime bridges calls to it (possibly across a serialization boundary), so + * `args` and the resolution value MUST be structured-cloneable; a runtime + * rejects a non-cloneable value with a descriptive error rather than + * corrupting the run. A rejection of this function surfaces inside the + * program as a rejection of the corresponding call. + */ type CodeBindingFunction = (args: unknown) => Promise<unknown> ``` @@ -72,6 +98,16 @@ type CodeBindingFunction = (args: unknown) => Promise<unknown> 失败类型是**正交的结果,独立报告**(见 [defensive-patterns](../defensive-patterns.md)):预算耗尽不是异常,中止不是超时,基底崩溃(如 OOM)也不是二者中的任何一个: ```ts type-equiv +/** + * Why a run failed. The kinds are orthogonal outcomes reported independently + * (per docs/defensive-patterns.md): a budget expiry is not an exception, an + * abort is not a timeout, and a substrate death is neither. + * + * - `'exception'` — the program threw or failed to parse/transform. + * - `'timeout'` — an implementation-owned budget expired; the message says which. + * - `'abort'` — {@link CodeRunRequest.signal} fired. + * - `'worker-exit'` — the execution substrate died without settling (e.g. OOM). + */ interface CodeRunFailure { /** The failure class (see the interface doc for each kind's meaning). */ kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' diff --git a/docs/core-data-structures/compaction.i18n.yaml b/docs/core-data-structures/compaction.i18n.yaml index f1673efb53..99025fabab 100644 --- a/docs/core-data-structures/compaction.i18n.yaml +++ b/docs/core-data-structures/compaction.i18n.yaml @@ -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 -compaction.md: e82cc103932ad05e68bc5311dec23c3f2c1a7ce4 -compaction.zh.md: bae6e9aa385efe0a7722c2b360c0b88e87a1a779 +compaction.md: 20513bdac5a10cb634c892f42600d2f016801e09 +compaction.zh.md: 67cd89add48761d269da4034bb7f3f3752e9a1ed diff --git a/docs/core-data-structures/compaction.zh.md b/docs/core-data-structures/compaction.zh.md index bae6e9aa38..67cd89add4 100644 --- a/docs/core-data-structures/compaction.zh.md +++ b/docs/core-data-structures/compaction.zh.md @@ -2,18 +2,18 @@ [English](compaction.md) | 中文 -上下文压缩(context compaction)的 seam 是一个[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md),按 bash 式拆分:接口([dsh-compact](../../packages/compact/compact),`ctx.compact`)、实现(后端,如 [dsh-compact-basic](../../packages/compact/compact-basic))、消费方(一个 `/compact` 工具,暂缓实现)。上下文压缩是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此处,而非 [core.md](core.md)。基于 tokenizer 或模板的后端是实现同一接口的兄弟包。与 bash 不同的是,该接口必然依赖 `dsh-session` 和 `dsh-llm`:它的动词定义在 `Session` 之上,输出使用 `ContentBlock` 词汇(见[上下文压缩能力 seam RFC](../rfc/implemented/feature/2026-06-18-compaction-capability-seam.md))。 +压缩 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md),与 bash 一样分为接口([dsh-compact](../../packages/compact/compact),`ctx.compact`)、实现(例如 [dsh-compact-basic](../../packages/compact/compact-basic) 后端)和消费方(延期实现的 `/compact` 工具)。压缩是**一项可选能力**,不属于 agent loop 主干,因此其词汇定义在此而非 [core.md](core.md) 中。基于 tokenizer 或模板的后端是实现同一接口的兄弟包。与 bash 不同,该接口必然依赖 `dsh-session` 和 `dsh-llm`:其动词作用于 agent 所有的 `Session`,而其持久摘要事件使用 `ContentBlock` 词汇(见[压缩能力 seam Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md))。 源码:[`packages/compact/compact/src/types.ts`](../../packages/compact/compact/src/types.ts) ## `compact/*` 会话事件 -上下文压缩通过声明合并为 [`SessionEventMap`](session.md) 扩展了三种事件类型。三者均为**仅日志**事件:它们记录压缩锁及其来源信息,永远不进入 surface。`SurfaceEventType` 被刻意不扩展(只有产生消息的事件才到达模型),因此摘要本身搭载在一条独立的 `user/message` 上,带有 `surfaceOp: { op: 'replace', start, end }`——唯一的 surface 变更。关于为何复用 `user/message` 是诚实的做法而非权宜之计,见 RFC。 +压缩通过声明合并为 [`SessionEventMap`](session.md) 扩展三种事件类型。三者都**仅写入日志**——记录压缩锁及其 provenance,绝不进入 surface。这里有意不扩展 `SurfaceEventType`(只有产生消息的事件才到达模型),因此摘要本身承载在另一条带有 `surfaceOp: { op: 'replace', start, end }` 的 `user/message` 上——这是摘要压缩执行的唯一 surface 变更。关于复用 `user/message` 为何是如实建模而非权宜之计,见对应 Agent Note。 | 事件 | 载荷 | 作用 | |---|---|---| | `compact/start` | `{ turn }` | 获取日志记录的锁 | -| `compact/summary` | `{ summary, shadowedRange, shadowedSeqs, shadowedTokenCount, model, maxTokens? }` | 来源信息:摘要块、被遮蔽的 surface 边界对(`start`/`end` seq,是位置跨度而非数值区间)、按 surface 顺序排列的被遮蔽 seq、估算的 token 数量,以及摘要调用的信封(`model`,加上生效时的生成上限)。记录这些信息使得单次请求可从日志加代码重建(reconstructability RFC) | +| `compact/summary` | `{ summary, shadowedRange, shadowedSeqs, shadowedTokenCount, provider, model, maxTokens? }` | provenance:摘要 block、被遮蔽的 surface 边界对(`start`/`end` seq——位置跨度,而非数值区间)、按 surface 顺序排列的被遮蔽 seq、估算 token 数,以及摘要调用的 envelope(`provider`、`model`,若有生成上限则还包括该上限)——写入日志后,该一次性请求可由日志 + 代码重建(见可重建性 Agent Note) | | `compact/end` | `{ turn, error? }` | 释放锁(摘要调用抛出异常时设置 `error`) | 锁括住**整个**操作:先追加 `compact/start`,然后执行摘要生成、写入 `compact/summary` 来源记录与 `user/message` 替换,最后才追加 `compact/end`。最后释放锁意味着操作中途崩溃会表现为可检测的遗留锁(有 `compact/start` 而无匹配的 `compact/end`),而非一个虚假声称压缩已完成的 `compact/end`。 @@ -22,9 +22,10 @@ ## `CompactionResult` -一次成功的压缩返回给调用方的内容:三个追加的 `compact/*` 事件的 seq、摘要块,以及被遮蔽的范围/seq 和估算的 token 数量。 +成功压缩向调用方返回:记账事件 seq、原始摘要、被遮蔽的范围与 seq,以及估算 token 数。 ```ts type-equiv +/** Result of a successful compaction operation. */ interface CompactionResult { /** The seq of the appended `compact/start` event. */ startSeq: number @@ -52,6 +53,45 @@ interface CompactionResult { ## 服务 -`CompactService` 暴露 `compactIfNeeded(...)` 用于压力触发的压缩(不需要压缩时返回 `null`),以及 `compactRegion(...)` 用于对显式的闭区间 surface 范围进行压缩。pre-step 调用方提供 agent、完整 prompt、会话前缀和 abort signal;实现必须将该 signal 转发给摘要生成。估算、保留策略、事件排序与摘要生成均为后端策略。 +自动调用方会说明策略为何运行;实现可以比普通压力更激进地处理已确认的溢出。 -自动压缩在串行的 `agent/pre-step` 时运行,位于步骤和请求推导之前,因此可以在替换 surface 节点的同时将 trace 事件保持在步骤之外。区域边界保持工具调用/结果配对,但不保持完整轮次,允许一个超大轮次中已关闭的早期步骤被压缩。保留策略与失败处理的细节由 `dsh-compact-basic` 负责。 +```ts type-equiv +/** Why automatic policy is asking a backend to consider compaction. */ +type CompactionTrigger = 'pressure' | 'context-overflow' +``` + +`CompactService` 暴露 `compactIfNeeded(agent, trigger, signal)` 以执行自动 `pressure` 或 `context-overflow` 策略;没有可安全执行的工作时返回 `null`。它还针对显式、两端均包含的 surface 范围暴露 `compactRegion(...)`。实现必须把传入的 signal 转发给摘要流程。该 seam 不拥有计价 API:单例 [`ctx.tokenMeter`](token-meter.md) 直接拥有估算与回放,而 `dsh-compact-basic` 拥有保留策略、事件排序、按路由执行的摘要调用及其配置。 + +压力压缩在串行 `agent/post-step` 中运行:此时成功的 assistant 输出、工具结果、缓冲 context 和 steering 已持久化,但 `step/end` 尚未发生。一旦压力或规范化溢出满足条件,compact-basic 会在选择范围前调用可选的 [`ctx.toolResultPrune`](../../packages/compact/compact-tool-result-prune/README.md),再通过 `ctx.tokenMeter` 重新测量,并且可以在不生成摘要的情况下推进 surface。失败请求的恢复在失败 step 关闭后通过 `agent/request-error` 运行;仅当 surface replacement generation 前进时才批准一个带新编号的 step 重试,即便后续摘要工作在剪枝后抛异常亦如此;取消仍然优先。区域边界保持工具调用/结果配对,但不保持整个 turn,因此一个过大 turn 中较早关闭的 step 可以被压缩。`dsh-compact-basic` 拥有阈值、保留尾部策略、溢出上限与失败处理。 + +该 seam 导出 `toolPairingBalancedBefore(session, seq)` 与 `toolPairingBalancedAfter(session, seq)`,用于这些边缘检查。两者都会验证当前 surface 成员关系,并拒绝缺失的 seq 与孤立结果;其缓存语义由[包契约](../../packages/compact/compact/README.md#tool-pairing-boundaries)规定。 + +## 工具结果剪枝产出 + +可选的工具结果剪枝服务会报告每次持久内容替换以及 Unicode code point 的总减少量。其公开结果类型位于 [`compact-tool-result-prune/src/types.ts`](../../packages/compact/compact-tool-result-prune/src/types.ts)。 + +```ts type-equiv +/** Provenance and size accounting for one landed surface replacement. */ +interface PrunedEntry { + /** Full-fidelity tool-result event shadowed by the replacement. */ + readonly originalSeq: number + /** Newly appended pruned tool-result event. */ + readonly replacementSeq: number + /** Tool call shared by the original and replacement. */ + readonly callId: CallId + /** Original text size in Unicode code points. */ + readonly charsBefore: number + /** Replacement text size in Unicode code points. */ + readonly charsAfter: number +} +``` + +```ts type-equiv +/** Aggregate outcome of one stable-surface pruning pass. */ +interface PruneResult { + /** Replacements in the snapshotted surface order. */ + readonly pruned: readonly PrunedEntry[] + /** Total Unicode code points removed across replacements. */ + readonly charsRemoved: number +} +``` diff --git a/docs/core-data-structures/core.i18n.yaml b/docs/core-data-structures/core.i18n.yaml index a1eaa5e393..c4c4fcf9d3 100644 --- a/docs/core-data-structures/core.i18n.yaml +++ b/docs/core-data-structures/core.i18n.yaml @@ -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 -core.md: 7ace373ae549b86f21151610719940100d6348d0 -core.zh.md: 0212dee3587d8a67bcd484a67f078d7195f6eef7 +core.md: e39650c5cc6769cd5cebe7901f92130ea57920e7 +core.zh.md: 4ab9f849ecbc30603b5c6b2875f9e9457c073c46 diff --git a/docs/core-data-structures/core.zh.md b/docs/core-data-structures/core.zh.md index 0212dee358..4ab9f849ec 100644 --- a/docs/core-data-structures/core.zh.md +++ b/docs/core-data-structures/core.zh.md @@ -18,27 +18,31 @@ harness 是一个微内核:一个极小的核心加上众多插件。大多数 | 子页面 | 负责内容 | |---|---| | [llm-streaming.md](llm-streaming.md) | `StreamChunk` 协议格式(wire format)+ 适配器契约(adapter contract)、`BlockAssembler`、`LlmAdapter` seam | +| [token-meter.md](token-meter.md) | 不可变的标量与位置回放度量,附带已消费日志修订号 | | [scope.md](scope.md) | 作用域注册标识、dispatch 载体,以及拥有的 `Scope` 上下文 | +| [goal.md](goal.md) | 持久 goal 标识、生命周期快照、激活、变更记录与 round 归属 | +| [commands.md](commands.md) | 人类命令 seam:定义、适配器发现、直接调用、结果与解析视图 | | [session.md](session.md) | 完整的 `SessionEventMap` 变体目录、`TurnTrigger`/`TurnEndReason`、`deriveMessages()`、轮次封闭不变式 | | [persistence.md](persistence.md) | 持久性 seam:`SessionPersistence`、JSONL + SQLite 后端、`session/flush`、崩溃恢复、`SessionHeader` | -| [session-query.md](session-query.md) | 逻辑会话/事件记录与有界精确事件读取 | +| [session-query.md](session-query.md) | 逻辑记录、有界精确事件读取与关系追踪 | +| [session-title.md](session-title.md) | 持久标题快照、来源 provenance 与异步提供方契约 | | [system-prompt.md](system-prompt.md) | 逐次组装的上下文、工具提供方结果、prompt 段落与协作式组装 | | [tools.md](tools.md) | `ToolDefinition` 完整字段、schema DSL、`ToolExecution`/`ToolResult`、工具展示 UI 类型,以及受保护的执行流水线 | | [user-interaction.md](user-interaction.md) | UI 支持的人工问答 seam:`AskUserQuestionRequest`、answer/options 词汇、provider API、错误分类体系 | | [approval.md](approval.md) | 一次性用户审批 seam:`ApprovalRequest`、`ApprovalOutcome`、逐会话策略、审计与 answerer 契约 | -| [bash.md](bash.md) | bash 执行器 seam:`BashExecRequest`/`Spec`、`BashRunResult`、后台 `BashTask` | -| [sandbox.md](sandbox.md) | 进程隔离 seam:文件效果模式、`SandboxPolicy`、`ConfinedArgv`、强制执行与 fail-closed 错误 | +| [bash.md](bash.md) | bash 执行器 seam:`BashExecRequest`/`Spec`、`BashRunResult`、后台 `BashProcess` 句柄 | +| [sandbox.md](sandbox.md) | 每会话策略解析与进程约束 seam:文件效果模式、执行/提供方策略、`ConfinedArgv`、强制执行与故障关闭错误 | | [code-runtime.md](code-runtime.md) | 代码执行 seam:`CodeRunRequest`/`Result`、绑定命名空间、捕获日志、`CodeRunFailure` 分类体系 | | [filesystem.md](filesystem.md) | 文件系统 seam:`FsTarget`、读/写/编辑结果、观测到的文件状态、`FsErrorCode` | +| [lsp.md](lsp.md) | LSP 导航 seam:`LspQueryRequest`/`Result`、`LspProvider`/`Service`、四种操作、`LspError` | | [skills.md](skills.md) | skill 服务:发现优先级、`SkillSummary`/`SkillDefinition`、会话前缀目录、面向模型的 `skill` 加载 | | [compaction.md](compaction.md) | 压缩(compaction)seam:`compact/*` 会话事件、`CompactionResult`、`CompactService` 接口 | | [subagent.md](subagent.md) | subagent seam:命名提供方注册表、`SubagentStartRequest`/`Result`/`Run`、启动时与运行时能力拆分 | | [web.md](web.md) | Web 访问 seam:`WebSearchRequest`/`Result`、`WebFetchRequest`/`Result`、`WebFetchBody`、provider 可用性、`WebError` | +| [spill.md](spill.md) | spill 存储 seam:`SaveTextSpill`、`SpillOwner`/`SpillSource`、`SpillRef`、品牌类型 `SpillLocator` | | [workflow.md](workflow.md) | 工作流 seam:`WorkflowStartRequest`、`WorkflowMeta`、`WorkflowRun`/`Result`、`workflow/*` 事件载荷、`WorkflowError` 致命性 | -> 本页的类型定义**逐字**粘贴自源码,并由 `pnpm run verify-type-equiv` 进行漂移检查(见 [development.md](../development.md#documenting-types-verbatim-ts-type-equiv))。为可读性省略了行内 JSDoc;完整契约请跟随源码链接查看。 - -FIXME(catalog-verbs): the drift gate covers only the nouns (the pasted type shapes); every method surface on these pages is hand-written prose. core-data-structures should probably also generate the *verbs* — the public methods of the cataloged classes — so a signature change cannot silently outdate the catalog. +> 这些页面上的类型声明及其 JSDoc 与源码等价,并由 `pnpm run verify-type-equiv` 检查漂移(见 [development.md](../development.md#documenting-types-verbatim-ts-type-equiv))。普通 block 保留完整声明;`public-api` block 保留去除实现体的公开 class 声明。Cordis 服务使用生成的[服务目录](../cordis-catalog/services.md)。 ## `…Map → derived-union` 模式 @@ -76,25 +80,30 @@ declare module '@deepseek-ai/dsh-llm' { ## 品牌化 ID -跨包边界的 ID 是**品牌化**的——结构上是字符串,但在类型层面不可互换(`AgentId` 不能传给期望 `CallId` 的地方)。构造通过每个类型专属的工厂函数;比较、日志和 JSON 行为与普通字符串一致。 +跨越包边界的 ID 都经过**品牌化**——结构上是字符串,但在类型层面不可互换(不能把 `SessionId` 传给需要 `CallId` 的位置)。每种类型通过各自的工厂构造;比较、日志记录和 JSON 行为与普通字符串相同。 -`Branded<B>` 原语位于自己的纯类型包 [dsh-brand](../../packages/util/brand)(无运行时代码,不依赖 harness 包),因此任何包都可以为自己拥有的 ID 品牌化,而无需依赖不相关的能力包(例如 dsh-bash 仅通过 dsh-brand 品牌化 `BashTaskId`/`OwnerToken`,从不引入 dsh-llm)。 +`Branded<B>` 原语位于独立的纯类型包 [dsh-brand](../../packages/util/brand) 中(没有运行时代码,也不依赖 Harness 包),因此任何包都能品牌化其拥有的 id,而无需依赖无关的能力包。 -Source: [`packages/util/brand/src/index.ts`](../../packages/util/brand/src/index.ts) +源码:[`packages/util/brand/src/index.ts`](../../packages/util/brand/src/index.ts) ```ts type-equiv +/** A string carrying a compile-time-only brand `B`. */ type Branded<B extends string> = string & { readonly [BRAND]: B } ``` -三个核心 ID:`CallId`(关联工具调用与其结果;dsh-llm)、`SessionId`(dsh-session)、`AgentId`(dsh-agent)。每个都是 `Branded<'CallId'>` 等加上同名工厂函数。能力 seam 也品牌化自己的 ID——见 [bash.md](bash.md) 中的 `BashTaskId`/`OwnerToken`。 +两个核心 ID 是 `CallId`(关联工具调用及其结果;dsh-llm)和 `SessionId`(活跃 agent 与持久 session 共享的标识;dsh-session)。能力包也会品牌化各自的 id,例如 [tasks.md](tasks.md) 中的 `TaskId`。 ## 内容块与消息 一段对话由 `Message` 组成;一条消息是一个类型化**内容块**的数组。块的联合类型从 `ContentBlockMap` 派生。 -Source: [`packages/llm/llm/src/types.ts`](../../packages/llm/llm/src/types.ts) +源码:[`packages/llm/llm/src/types.ts`](../../packages/llm/llm/src/types.ts) ```ts type-equiv +/** + * Merge-extensible content blocks keyed by `type`. New core blocks must land + * with adapter, UI, and compaction support. + */ interface ContentBlockMap { 'text': TextBlock 'reasoning': ReasoningBlock @@ -105,18 +114,44 @@ interface ContentBlockMap { 各块接口(完整字段见源码):`TextBlock`(`text`)、`ReasoningBlock`(thinking,区别于可见文本)、`ToolCallBlock`(`id: CallId`、`name`、原始 JSON `arguments`)、`ToolResultBlock`(`toolCallId`、嵌套 `content: ContentBlock[]`、`isError?`)。`ContentBlock = ContentBlockMap[ContentBlockType]`。核心集仅限于每条交付路径都尊重的块——多模态内容(图像、音频等)没有核心块类型;需要的功能通过可合并扩展的 map 添加,同时提供适配器/UI/压缩支持。 -`Message` 是角色加块: +`Message` 由角色和 block 组成。由循环派生的 assistant 消息携带其持久 provider/model 标识,以及可选的适配器私有回放元数据: ```ts type-equiv +/** Provider ownership and adapter-private replay data for an assistant message. */ +interface AssistantProvenance { + /** Provider route that produced the message. */ + provider: string + /** Provider model id that produced the message. */ + model: string + /** + * Lossless-JSON adapter state needed to replay the provider response. + * `LlmService` exposes it to a target adapter only when that adapter instance + * currently owns both this historical provider and the target provider. + */ + replayState?: unknown +} +``` + +```ts type-equiv +/** + * A single message in a conversation history. Loop-derived assistant messages + * always carry provenance; callers may omit it on hand-built foreign history. + */ interface Message { role: 'system' | 'user' | 'assistant' content: ContentBlock[] + /** Present only on assistant messages produced by a routed adapter. */ + provenance?: AssistantProvenance } ``` 消息来源本身也是一个可合并扩展的和类型: ```ts type-equiv +/** + * Where a message (or injected content) came from. + * Merge-extensible sum type — plugins add their own `kind`s. + */ interface MessageSourceMap { user: { kind: 'user' } plugin: { kind: 'plugin'; plugin: string } @@ -133,10 +168,49 @@ interface MessageSourceMap { 一次模型调用是一个完全组装好的 `GenerateOptions`。适配器以原始 `StreamChunk` 流作答;消费方用 `BlockAssembler` 组装它(见 [llm-streaming.md](llm-streaming.md))。 -Source: [`packages/llm/llm/src/types.ts`](../../packages/llm/llm/src/types.ts) +源码:[`packages/llm/llm/src/types.ts`](../../packages/llm/llm/src/types.ts) + +提供方与模型发现使用小型、提供方中立的描述符。模型目录仅供参考:路由仍以已注册提供方为键,适配器也可以接受未列出的模型 id。 ```ts type-equiv +/** Display metadata for one registered provider route. */ +interface LlmProviderInfo { + /** Provider route key used by {@link GenerateOptions.provider}. */ + id: string + /** Human-readable provider name for selectors and diagnostics. */ + name: string +} +``` + +```ts type-equiv +/** One adapter-discovered model; catalog membership is advisory, not request validation. */ +interface LlmModelInfo { + /** Provider route that owns this model entry. */ + provider: string + /** Model id passed to {@link GenerateOptions.model}. */ + id: string + /** Human-readable model name for selectors. */ + name: string + /** Optional user-facing distinction from otherwise similar models. */ + description?: string +} +``` + +对正确性敏感的模型容量与参考目录分开查询,并归服务该确切路由的适配器所有。 + +```ts type-equiv +/** Provider-owned context capacity for one exact provider/model route. */ +interface LlmModelContext { + /** Maximum combined request and response context in tokens. */ + contextWindow: number +} +``` + +```ts type-equiv +/** A single model request, fully assembled. */ interface GenerateOptions { + /** Registered provider route selecting the adapter instance. */ + provider: string model: string /** * Ordered conversation messages, exactly as the provider sees them (after @@ -163,18 +237,28 @@ interface GenerateOptions { * it; replay uses it to keep concurrent parent and child cursors independent. */ sessionId?: Branded<'SessionId'> + /** + * Provider-neutral classification for an auxiliary model call. Adapters may + * map the purpose to model-hidden transport metadata. Ordinary conversation + * requests leave it unset. + */ + purpose?: 'compaction' } ``` -模型停止生成的原因是一个可合并扩展的结束原因: +模型响应为何停止由可合并扩展的原因表示。提供方终态失败携带流式契约的 [`LlmFailure`](llm-streaming.md#llmfailure): ```ts type-equiv +/** + * Why a model response stopped. + * Merge-extensible so adapters can surface provider-specific reasons. + */ interface FinishReasonMap { 'stop': { kind: 'stop' } 'tool-calls': { kind: 'tool-calls' } 'max-tokens': { kind: 'max-tokens' } - 'aborted': { kind: 'aborted' } - 'error': { kind: 'error'; message: string; code?: string } + 'aborted': { kind: 'aborted'; failure: LlmFailure } + 'error': { kind: 'error'; failure: LlmFailure } } ``` @@ -183,6 +267,13 @@ interface FinishReasonMap { `GenerateOptions.tools` 携带 `ToolSchema`——工具的 JSON Schema 描述,发送给模型。它声明在 dsh-llm(而非 dsh-tools)中,正是因为它是循环每一步组装请求的一部分: ```ts type-equiv +/** + * JSON-schema description of a tool, as sent to the model. + * + * Declared here (not in dsh-tools) because it is part of {@link GenerateOptions}; + * dsh-tools' ToolDefinition and dsh-system-prompt's PromptAssembly both import + * it from this package. + */ interface ToolSchema { name: string description: string @@ -195,16 +286,22 @@ interface ToolSchema { ### 请求信封:`LlmCallConfig` 与记录的 header -循环从已记录的状态构建每个请求。`EpochHeader` 记录调用配置、渲染后的 prompt、权威的返回工具顺序(由 `toolOrder` 配置,未设置时按字典序)以及会话前缀,通过 `request/header` 快照和 delta 实现。结合派生历史,这使得请求可从会话日志重建。见 [session.md](session.md#the-request-header-events-requestheader-and-requestheader-delta) 和[可重建请求 RFC](../rfc/implemented/architecture/2026-07-05-reconstructable-requests.md)。 +循环从已记录状态构建每个请求。`EpochHeader` 通过完整的 `request/header` 快照记录调用配置、渲染后的 prompt、权威返回工具顺序(由 `toolOrder` 配置;未配置时按字典序)以及 session prefix。结合派生历史,请求便可由会话日志重建。见 [session.md](session.md#the-request-header-event-requestheader) 与[可重建性 Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.md)。 -`agent/request` 接收一个冻结的 call-config 种子,可以返回替换值。`agent/session-prefix` 在每个循环实例中组合一次仅用于请求的前缀消息,header 记录实际使用的确切结果。到达 `llm/stream` 的请求已被深度冻结,因此突变会抛出异常。 +`agent/request` 接收冻结的调用配置种子,并可返回替代值以切换提供方、模型或采样参数。`agent/session-prefix` 为每个循环实例组合一次仅用于请求的 prefix 消息,header 记录实际使用的确切结果。到达 `llm/stream` 的请求会被深度冻结,因此变更会抛异常;请求还携带进程本地循环标识,使观察者不会把单独记录的冻结辅助调用误认成对话请求。 在协议格式上,循环构建的请求按此顺序读取:`system` 槽位(渲染后的 prompt 组装)→ `messagePrefix`(冻结的会话前缀)→ 派生历史——边界快照,其尾部在轮次首步是最新的 `user/message`,在后续步骤是上一步的工具结果。前缀从不进入派生历史;它的持久记录是 header 事件,开发不变式针对每个循环构建的请求精确重算此等式。 -FIXME(call-config-shape): revisit the exact definition of this type — which fields are genuinely epoch-level for cache purposes (`model` certainly; the sampling scalars sit here out of caution), and where provider-specific extras (reasoning options, extra body params) belong when an adapter needs them. +FIXME(call-config-shape):重新审视此类型的精确定义——出于缓存目的,哪些字段确实属于 epoch 层级(`model` 肯定属于;采样标量目前出于谨慎放在这里),以及适配器需要时,提供方特有的额外项(推理选项、额外 body 参数)应归属何处。 ```ts type-equiv +/** + * Provider + model + sampling scalars of one conversation's requests. Every field maps + * 1:1 onto the same-named `GenerateOptions` field; the loop builds requests + * from the logged header rather than accepting these per call. + */ interface LlmCallConfig { + provider: string model: string temperature?: number maxTokens?: number @@ -216,9 +313,22 @@ interface LlmCallConfig { `Session` 是一份类型化 `SessionEvent` 的**仅追加日志**——唯一的真源。LLM(大语言模型)消息历史从日志*派生*(`deriveMessages()`),而非单独存储。事件词汇从 `SessionEventMap` 派生: -Source: [`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) +源码:[`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) ```ts type-equiv +/** + * One immutable entry in the session log. + * + * A proper discriminated union over `type` (not independent `type`/`data` + * unions), so `switch (event.type)` narrows `event.data` without casts. + * + * The {@link sourceEventSeqs} and {@link surfaceOp} fields are conditional: + * they only exist on {@link SurfaceEventType} variants (`user/message`, + * `assistant/message`, `tool/result`, `context/message`, `steering/message`). + * Non-surface events (boundary markers, chunks, usage, errors) never carry + * surface metadata — the compiler enforces this at `Session.append()` + * call sites. + */ type SessionEvent<T extends SessionEventType = SessionEventType> = { [K in SessionEventType]: { type: K @@ -231,7 +341,9 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = { /** * Seq numbers of events that are provenance sources of this event * (e.g. the `assistant/chunk` seqs that built an `assistant/message`, - * or the surface nodes shadowed by a compaction replace node). + * or the surface nodes shadowed by a compaction replace node). An + * `assistant/message` may carry a present empty array for a known empty + * provider stream; omission means unrecorded provenance. */ sourceEventSeqs?: number[] /** How this event entered the surface; absent for non-surface events. */ @@ -240,157 +352,166 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = { }[T] ``` -十五个事件变体(`turn/start`、`turn/end`、`step/start`、`step/end`、`user/message`、`prompt/blocked`、`context/message`、`assistant/chunk`、`assistant/message`、`tool/call`、`tool/result`、`steering/message`、`todo/write`、`request/header`、`request/header-delta`)、`deriveMessages()` 投影规则、`TurnTrigger`/`TurnEndReason` 原因,以及轮次封闭不变式在 **[session.md](session.md)** 中。日志如何持久化——`SessionPersistence` seam、JSONL/SQLite 后端、`session/flush` 检查点、崩溃恢复和 `SessionHeader`——在 **[persistence.md](persistence.md)** 中。 +十四种事件变体(`turn/start`、`turn/end`、`step/start`、`step/end`、`user/message`、`prompt/blocked`、`context/message`、`assistant/chunk`、`assistant/message`、`tool/call`、`tool/result`、`steering/message`、`todo/write`、`request/header`)、`deriveMessages()` 投影规则、`TurnTrigger`/`TurnEndReason` 原因以及 turn enclosure 不变量都在 **[session.md](session.md)** 中。日志如何持久化——`SessionPersistence` seam、JSONL/SQLite 后端、`session/flush` checkpoint、崩溃恢复与 `SessionHeader`——则在 **[persistence.md](persistence.md)** 中。 ## Agent 句柄 -`Agent` 是每个插件(UI、钩子、编排器)面向编程的接口。具体实现是 dsh-agent-loop 中的 `ReactLoopAgent`;循环之外没有任何东西依赖该实现。 +`Agent` 是每个插件(UI、hook、orchestrator)面向编程的 surface。具体实现为 dsh-agent-loop 包内部细节;循环外没有任何组件依赖它。 -Source: [`packages/core/agent/src/types.ts`](../../packages/core/agent/src/types.ts) +源码:[`packages/core/agent/src/types.ts`](../../packages/core/agent/src/types.ts) + +`InjectOptions` 在普通消息归属信息之外,扩展了对模型隐藏的持久 JSON 元数据: ```ts type-equiv +/** Options specific to durable synthetic context injection. */ +interface InjectOptions extends SendOptions { + /** Opaque JSON state retained in the session event but hidden from the model. */ + meta?: JsonValue +} +``` + +```ts type-equiv +/** Stable runtime cause accepted by {@link Agent.cancel}. */ +type AgentCancelCause = + | { readonly kind: 'user' } + | { readonly kind: 'parent' } +``` + +```ts type-equiv +/** Public agent handle; its concrete implementation is internal to `@deepseek-ai/dsh-agent-loop`. */ interface Agent { - readonly id: AgentId + /** The single identity shared with {@link session}. */ + readonly id: SessionId readonly options: AgentOptions readonly session: Session readonly status: AgentStatus - - /** - * The agent's scope context (`@deepseek-ai/dsh-scope`, key = this agent): - * registrations through it — tools, prompt sections/variables, listeners, - * restrictions — are visible to this agent only and unwind when it is - * disposed; `agent.ctx.on('agent/…')` listeners fire only for this agent. - */ + /** Agent-scoped context; its contributions are agent-local, unwind on disposal, and reject registration afterward. */ readonly ctx: Context /** - * Queue a user message. Starts a turn when idle; otherwise waits for the next - * turn. Content and the resolved source are accepted as one detached, - * deeply-frozen lossless-JSON record before notification or enqueue, so - * caller or `agent/queued` listener in-place mutation cannot change later - * log/model input. Throws synchronously when either value is not losslessly - * JSON-serializable; `agent/prompt-submit` may still return an explicit - * replacement. + * Queue one detached, frozen lossless-JSON item. If claimed, it is the sole + * ordinary message in its FIFO-ordered turn; the next claimed item waits for + * that turn's checkpoint. + * Invalid input throws synchronously before notification or enqueue. */ send(content: ContentBlock[], options?: SendOptions): void /** - * Steer a running turn: content is injected between steps of the current - * turn. Uses the same owned-value and synchronous-validation boundary as - * {@link send}; when idle, behaves exactly like that method. + * Submit steering while the agent is `running`. An open turn records it at + * the next steering checkpoint before a request or continuation decision; + * policy may stop before another step. After turn close and its checkpoint, + * any remainder is queued for a later turn; terminal `agent/turn-stop`, + * cancellation, or disposal may discard it. Uses the same synchronous + * snapshot-and-validation boundary as {@link send}; when idle, delegates to it. */ steer(content: ContentBlock[], options?: SendOptions): void /** - * Inject in-session context (file-change notices, skill content, cron - * notifications, …): appends a `context/message` session event the next model - * request sees at its chronological position, rendered as tagged synthetic - * context rather than a user prompt. Does not run the model. - * - * Turn-enclosure (the turn-enclosure RFC): an inject while a turn is open joins that turn; - * an inject while idle wraps its `context/message` in a one-shot `injection` - * turn (`turn/start` → `context/message` → `turn/end`) and checkpoints it for - * durability, so every event stays inside a turn and a persistence backend - * never loses a between-turn notice. The idle checkpoint is fire-and-forget - * (inject is synchronous): a failing flush is reported via `agent/error` - * (step `0`) and the logger, never thrown into the caller. - * - * Live-adapter review has validated the tagged-envelope rendering against - * current DeepSeek behavior; provider-specific mismatches belong in that - * adapter, not in the canonical session vocabulary. + * Append detached model-facing context without running the model. An open-turn + * injection joins at the current log position unless the current tool batch is + * executing; then it waits FIFO until that batch settles and drains before turn + * close even when interrupted. Idle injection uses a one-shot turn and durability + * checkpoint. Disposal awaits idle checkpoints; flush failures report through `agent/error`. */ - inject(content: ContentBlock[], options?: SendOptions): void + inject(content: ContentBlock[], options?: InjectOptions): void /** - * Cancel ALL pending work for the agent. `cancel()`: - * - * - clears the queued FIFO (un-started prompts never run) and the steering - * FIFO (steering for the cancelled turn is dropped, not re-enqueued); - * - aborts the in-flight step if one is running (the turn ends `aborted`); - * - drops a turn that is about to start (a `cancel()` landing in the - * pre-step window — after a `send()` queued but before the loop flips to - * `running`, or after `running` is emitted but before the first step) so - * that queued prompt does not run and cannot be batched into the cancelled - * turn. - * - * After `cancel()`, `whenIdle()` resolves on the post-cancel quiescent state. - * `cancel()` on an idle agent with nothing queued or running is a safe no-op - * — it does NOT arm anything that would drop a later legitimate prompt. + * Clear all queued and steering work, including items waiting to start, and + * abort the active turn. An effective call first emits + * `agent/cancel-requested` with the resolved typed cause. The first cause wins + * for the active turn, and `whenIdle()` resolves after cancellation reaches + * quiescence. Omission means `{ kind: 'user' }`. Idle cancellation is a no-op + * and does not arm later work. The active turn snapshots and freezes the cause. + * @param cause - the stable caller intent carried by the current turn signal. */ - cancel(reason?: string): void + cancel(cause?: AgentCancelCause): void - /** - * Resolve once the agent has reached quiescence after settling out of - * `running`, or immediately if it is already idle with no queued work. A - * non-owner's quiescence-observation hook: a consumer that does NOT own the - * agent's lifecycle awaits this to proceed only after queued/running work has - * fully stopped, rather than returning while the driver is still streaming or - * about to start a queued turn — without itself tearing the agent down. (A - * lifecycle OWNER does not need it: `AgentHandle.dispose()` already awaits the - * loop-exit promise directly as part of stopping and unregistering. So this is - * for a non-owning observer — e.g. a test awaiting a turn to settle, or a - * monitor — that wants the settle signal but must not dispose the agent.) - * - * "Quiescence", not merely "status changed": a disposed agent emits - * `agent/status('disposed')` from inside its disposer, BEFORE the driver loop - * has unwound — so `whenIdle()` resolving on `disposed` must wait for the loop - * to actually exit (the implementation chains the loop-exit promise), not just - * observe the status flip. A mid-step disposal that never reaches `idle` still - * unblocks the await this way. - */ + /** Resolve at idle quiescence; disposal waits for driver exit rather than only the status transition. */ whenIdle(): Promise<void> - // Subagent delegation is realized on top of this interface by the - // `@deepseek-ai/dsh-subagent` seam, not by a method here: a backend creates - // the child through `ctx.agents.create` (fork seeds the child Session with a - // balanced prefix of the parent's log via `CreateAgentOptions.seed`; spawn - // starts fresh) and drives it as an ordinary Agent handle, so steer() and - // event subscription work uniformly. See docs/core-data-structures/subagent.md. } ``` -`AgentStatus` 为 `'idle' | 'running' | 'disposed'`,`AgentId` 是品牌化的。`AgentOptions` 可合并扩展,当前包含 `model?`。Persona 属于 `dsh-system-prompt`:agent 作用域的 `deployment:persona` 可以遮蔽全局默认值。 +`AgentStatus` 为 `'idle' | 'running' | 'disposed'`,`SessionId` 是品牌类型。`running` 描述整个驱动器的排空区间,可能跨越 turn 关闭、其持久化 checkpoint 以及连续的排队 turn;它不能证明某个 turn 仍然打开。`AgentOptions` 可合并扩展:core 声明 `provider?` 与 `model?`(在 `agent/request` 后,分发要求两者都存在)。Persona 归 `dsh-system-prompt` 所有:agent 作用域的 `deployment:persona` 可以遮蔽全局默认值。 -[事件分类体系](../architecture.md#event)拥有 `agent/*` 生命周期、检查点和 waterfall(瀑布式事件)契约。轮次和步骤边界是持久的会话事件,而非 agent 发射。 +cause 是由 TypeScript 强制约束的同进程输入。活跃持有者会把其判别字段复制到仅运行时的 `AbortSignal.reason`;该值在发布 `turn/end` 前退役。`agentInterruptReasonOf(signal)` 无需查询环境中的 initiator 状态,即可识别 `user`、`parent` 与仅用于生命周期的 `disposed`。持久 `turn/end` 保留粗粒度 `{ kind: 'aborted' }` 结果;若需记录请求 provenance,应使用单独的持久事件,而不是让终态结果承担额外含义。 + +[事件分类](../architecture.md#event)拥有 `agent/*` 生命周期、checkpoint 与 waterfall 契约。Turn 和 step 边界是持久 session 事件,而不是 agent emit。 + +## 发起 Agent + +`ctx.agents` 携带的进程本地 initiator 就是上面的确切 `Agent`,不是单独的 frame 或复制的标识。环境中存在该值既不能证明存活,也不代表授权;其生命周期与边界规则由 [initiator 作用域决策](../../.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md)规定。 ## 拦截决策 -每个 `agent/*` 拦截 waterfall 返回一个小型的、seam 特定的类型化联合——统一的 Decision 惯用法(工具 seam 的 `PreToolDecision`/`PostToolDecision` 在 [tools.md](tools.md) 中遵循相同形状)。CC/Codex 钩子桥将其 `permissionDecision`/`decision`/`continue`/`additionalContext` 字段映射到这些类型上;原生插件直接返回它们。它们共享一个面向模型的上下文信封 `HookContext`,通过 `inject()` 作为 `context/message` 注入,因此携带一个必需的 `source`(缺少 source 会默认为 `{kind:'user'}`,将插件上下文错误标记为用户提示词)。 +每个 `agent/*` 拦截 waterfall 都返回一个小型、特定于 seam 的类型化联合——统一的 Decision 惯用形状([tools.md](tools.md) 中工具 seam 的 `PreToolDecision`/`PostToolDecision` 也采用相同形状)。CC/Codex hook bridge 把其 `permissionDecision`/`decision`/`continue`/`additionalContext` 字段映射到这些联合上;原生插件则直接返回它们。Prompt 与工具后决策共享一种面向模型的 context 形状 `HookContext`;它通过 `inject()` 作为 `context/message` 注入,因此必须携带 `source`(缺少 source 会默认成 `{kind:'user'}`,从而把插件 context 错标为用户 prompt)。其中的 `content` 作为 user-role 消息逐字到达模型,而 JSON `meta` 持久保存插件状态但不向模型暴露。两种决策都携带 `additionalContexts[]`,使每一项保留各自的 provenance 与元数据。Continuation reason 则是 steering 消息,并有意使用更窄的 content/source 形状。 -Source: [`packages/core/agent/src/types.ts`](../../packages/core/agent/src/types.ts) +源码:[`packages/core/agent/src/types.ts`](../../packages/core/agent/src/types.ts) ```ts type-equiv +/** Model-facing context injected by a listener; `source` prevents plugin text from being labeled as user input. */ interface HookContext { content: ContentBlock[] source: MessageSource + /** Opaque JSON state retained in the session event but hidden from the model. */ + meta?: JsonValue } ``` -`agent/prompt-submit` 返回 `PromptDecision`(允许一条已出队的排队消息——可选地重写其 `content` 或附加 `additionalContext`——或阻止它;一个批次中所有 prompt 都被阻止时,会打开一个零步骤轮次并以 `rejected` 结束): +`agent/prompt-submit` 返回 `PromptDecision`(允许 turn 已领取的排队消息——可选地改写其 `content` 或附加 `additionalContexts`——或者记录 `prompt/blocked` 并以 `rejected` 结束这个零 step turn): ```ts type-equiv +/** + * Prompt interception result. `allow.content` replaces the prompt and each + * `additionalContexts` entry becomes a separate context message. `block` + * records a durable `prompt/blocked` and ends the claimed prompt's zero-step + * turn as rejected. + */ type PromptDecision = - | { kind: 'allow'; content?: ContentBlock[]; additionalContext?: HookContext } + | { kind: 'allow'; content?: ContentBlock[]; additionalContexts?: HookContext[] } | { kind: 'block'; reason: string } ``` -`agent/turn-continuation` 返回 `ContinuationDecision`(循环的默认行为是:当步骤有工具调用或 steering(中途引导)被注入时 `continue`,否则 `stop`;`continue` 的 `reason` 被记录为同一轮次中下一步的 steering——类型化的 `/goal` 模式): +`agent/turn-continuation` 返回 `ContinuationDecision`(step 有工具调用或注入了 steering 时,循环默认为 `continue`,否则为 `stop`;`continue` 的 `reason` 会记录为同一 turn 中下一 step 的 steering,因此不携带 context 元数据——即类型化 `/goal` 模式): ```ts type-equiv +/** Turn continuation override; a continue reason is recorded as next-step steering in the same turn. */ type ContinuationDecision = | { action: 'stop' } - | { action: 'continue'; reason?: HookContext } + | { action: 'continue'; reason?: { content: ContentBlock[]; source: MessageSource } } ``` +`agent/request-error` 接收确切的原始 `RequestError`、其不可变 `LlmFailure`、在连续序列中已批准另一次请求的不可变失败列表、turn signal 以及 `next()`。恢复插件按 `failure.code` 路由,而不是按活跃错误的消息路由;每项策略只统计自身的 code,一次成功请求会清空历史: + +```ts type-equiv +/** Model-request failure with an optional machine-routable provider code. */ +type RequestError = Error & { code?: string } +``` + +它返回 `RequestErrorDecision`;`retry` 在恢复 listener 的持久变更之后打开一个带新编号的 step,而 `fail` 在 `turn/end` 上保留结构化失败: + +```ts type-equiv +/** Failed-request recovery decision; `retry` opens another numbered step while listeners delegate by calling `next()`. */ +type RequestErrorDecision = { action: 'fail' } | { action: 'retry' } +``` + +`agent/post-step` 会在 assistant 输出、真实或合成的工具结果、缓冲 context 与 steering 持久化之后、`step/end` 之前被 await。被取消的工具批次在排空后携带 aborted signal 到达这里;其签名为 `(agent, turn, step, signal)`,可回放事实保留在 session 日志中,而不是瞬态 payload 中。 + `agent/turn-stop` 返回仅停止的 `ContinuationStop` 子集或 `undefined`。循环在折叠普通决策、其 reason 和待处理 steering 之后调用此串行检查点;stop 是终态,会丢弃待处理的 steering。 ```ts type-equiv +/** + * The terminal subset of {@link ContinuationDecision}. A listener on + * `agent/turn-stop` returns this to make the already-composed continuation + * outcome terminal; `undefined` abstains. + */ type ContinuationStop = Extract<ContinuationDecision, { action: 'stop' }> ``` `agent/session-start` 携带 `SessionStartSource`(会话生命周期为何开始;桥接层据此匹配其 SessionStart): ```ts type-equiv +/** Why a session lifecycle began; seeded creates are `startup`, while persisted loads are `resume`. */ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact' ``` diff --git a/docs/core-data-structures/filesystem.i18n.yaml b/docs/core-data-structures/filesystem.i18n.yaml index 843abd6dc6..69cb43d21d 100644 --- a/docs/core-data-structures/filesystem.i18n.yaml +++ b/docs/core-data-structures/filesystem.i18n.yaml @@ -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 -filesystem.md: 8bdc2323a0bf63588e01520926f093538fee4912 -filesystem.zh.md: 86b18af783899ed857f059b6b7cdb740ea357798 +filesystem.md: 3c9b041da92e71cd20429e8b1549c0b8e6f2436d +filesystem.zh.md: 11e386c98e671f4147419eec587399a5a3bb0d07 diff --git a/docs/core-data-structures/filesystem.zh.md b/docs/core-data-structures/filesystem.zh.md index 86b18af783..11e386c98e 100644 --- a/docs/core-data-structures/filesystem.zh.md +++ b/docs/core-data-structures/filesystem.zh.md @@ -13,8 +13,17 @@ 每个操作首先将用户提供的路径解析为不透明的后端目标。消费方可以显示 `displayPath`,但禁止解析 `targetKey`(一个品牌化的不透明 id),也不得假设它是本地绝对路径。 ```ts type-equiv +/** + * A path resolved by a backend into a stable identity. `resolve()` produces + * this; every other operation takes it. + */ interface FsTarget { + /** Opaque key for stale guards and target lookup. */ targetKey: FsTargetKey + /** + * Path for model/UI-facing output. May be a local absolute path, + * workspace-relative path, or remote URI depending on the backend. + */ displayPath: string } ``` @@ -22,19 +31,59 @@ interface FsTarget { 后端拥有文件版本 token,即 write/edit 所守卫的新鲜度 token。策略插件存储它们以进行陈旧检查;消费方不解释其内容。两个 id 都是品牌化的不透明字符串。 ```ts type-equiv +/** + * Opaque key for stale guards and target lookup. The local backend uses a + * realpath-like string; a remote backend might use a workspace URI or file id. + * Consumers MUST NOT parse it or assume it is a local absolute path. + */ type FsTargetKey = Branded<'FsTargetKey'> ``` ```ts type-equiv +/** + * Opaque file-version token — the freshness token a write/edit guards against. + * The local backend derives it from high-resolution stat identity and freshness + * fields; a remote backend might use a revision id. The policy layer records it + * for stale checks; consumers may display related metadata but MUST NOT + * interpret this token. + */ type FsVersion = Branded<'FsVersion'> ``` `stat` 返回元数据(从不返回内容),目标不存在时返回 `undefined`。`type` 让工具在读取前拒绝目录或特殊文件;`size` 让工具无需通过失败探测即可选择 `readText` 还是 `streamText`。 ```ts type-equiv +/** + * Metadata about a target — what {@link FileSystem.stat} returns. Lets the + * policy layer reject directories/special files before reading and choose + * `readText` vs `streamText` from `size` without probing by failure. `version` + * is the freshness token. `undefined` from `stat` means the target is absent. + */ interface FsInfo { + /** Opaque freshness token of the target right now. */ version: FsVersion + /** Whether the target is a regular file, a directory, or something else. */ type: 'file' | 'directory' | 'other' + /** Byte size of a regular file, when the backend can report it. */ + size?: number +} +``` + +`lstat` 是路径层级、不跟随链接的元数据原语。它接收路径而不是 `FsTarget`,因为 `resolve` 会有意跟随 symlink 以产生稳定标识;需要检查信任边界的消费方可以先调用 `lstat`,在解析前拒绝 `symlink`。 + +```ts type-equiv +/** + * Metadata about a path without following the final path component when it is a + * symbolic link. Unlike {@link FsInfo}, this path-level probe can report + * `symlink` so consumers with trust-boundary rules can reject repository-owned + * links before resolving a target. + */ +interface FsPathInfo { + /** Opaque freshness token of the path entry right now. */ + version: FsVersion + /** Whether the path entry is a regular file, directory, symlink, or other. */ + type: 'file' | 'directory' | 'symlink' | 'other' + /** Byte size of the path entry, when the backend can report it. */ size?: number } ``` @@ -42,11 +91,20 @@ interface FsInfo { `listDir` 按稳定的名称顺序返回直接子条目。每个条目携带子项的 basename、类型、已解析目标,以及后端能报告时的廉价元数据。它禁止读取文件内容,因此 `size` 仅用于普通文件,`version` 来自元数据。已损坏或已消失的子项可以作为 `other` 返回且不带元数据;列出或解析子项元数据时的权限或后端 I/O 失败会以 `FS_PERMISSION_DENIED` 或 `FS_IO_ERROR` 使整个列表操作失败。 ```ts type-equiv +/** + * One direct child returned by {@link FileSystem.listDir}. Listing returns + * metadata and resolved targets only; it must not read file contents. + */ interface FsDirEntry { + /** Basename of the child inside the listed directory. */ name: string + /** Whether the child is a regular file, a directory, or something else. */ type: 'file' | 'directory' | 'other' + /** Resolved child target for follow-up operations. */ target: FsTarget + /** Opaque freshness token when the backend can report metadata cheaply. */ version?: FsVersion + /** Byte size of a regular file, when the backend can report it. */ size?: number } ``` @@ -56,16 +114,33 @@ interface FsDirEntry { `writeText` 和 `editText` 的版本守卫都是可选的:省略它执行无条件(裸提供方)变更,提供它则启用守卫。`writeText` 的守卫是 `FsWriteIntent`:`createIfAbsent` 在目标缺失时创建,目标已存在时以 `FS_NOT_OBSERVED` 拒绝;`replaceIfVersion` 仅在目标存在且版本匹配时替换,否则报 `FS_STALE_VERSION`。省略 `expected` 则无条件创建或覆盖。联合类型本身只包含两种有守卫的意图;「无守卫」通过省略表达,因此 write 和 edit 共享同一个对称的 `expected?` 形状。 ```ts type-equiv +/** + * Guarded write intent. `createIfAbsent` rejects an existing target with + * `FS_NOT_OBSERVED`; `replaceIfVersion` rejects absence or mismatch with + * `FS_STALE_VERSION`. Omitting the intent from `writeText` means unconditional + * create-or-overwrite, not a third union arm. + */ type FsWriteIntent = | { kind: 'createIfAbsent' } | { kind: 'replaceIfVersion'; version: FsVersion } ``` ```ts type-equiv +/** Outcome of a full-file write. */ interface FsWriteOutcome { + /** Whether the write created a new file or replaced an existing one. */ operation: 'create' | 'update' + /** Opaque version of the file after the write. */ version: FsVersion + /** + * The file's content BEFORE the write, or `null` when the file did not exist + * (a create) or was undiffable (binary/non-UTF-8). LF-normalized storage text + * (the diff basis), never a diff — a consumer computes the result-time + * contextual diff from `before`/`after` when `before` is present, else falls + * back to a whole-file diff. + */ before: string | null + /** The file's content AFTER the write, LF-normalized to share `before`'s diff basis. */ after: string } ``` @@ -73,17 +148,29 @@ interface FsWriteOutcome { `editText` 是提供方级别的变更操作,而非在别处组合的 `read` 加 `write`。带守卫时,它在字面匹配之前先验证预期版本(因此对陈旧内容的编辑报 `FS_STALE_VERSION`,而非对更新内容的匹配失败);不带守卫时,它编辑当前内容。无论哪种路径,它都应用替换并原子写入——将匹配、行尾处理、陈旧检查和原子替换保持在一个变更临界区内——目标缺失时两条路径都报 `FS_STALE_VERSION`。 ```ts type-equiv +/** A literal-replacement edit request. */ interface FsEditRequest { + /** Literal non-empty text to replace. Must match exactly (after line-ending normalization). */ oldString: string + /** Literal replacement text. An empty string deletes the matched text. */ newString: string + /** Replace every match instead of requiring exactly one. */ replaceAll: boolean } ``` ```ts type-equiv +/** Outcome of a literal edit. */ interface FsEditOutcome { + /** Opaque version of the file after the edit. */ version: FsVersion + /** + * The file's content BEFORE the edit. Raw storage text (LF-normalized by the + * backend), never a diff — a consumer computes the result-time contextual diff + * (the applied hunk with context) from `before`/`after`. + */ before: string + /** The file's content AFTER the edit. */ after: string } ``` @@ -99,8 +186,20 @@ interface FsEditOutcome { 策略插件只需要足够的执行上下文,通过收窄 `fs/*` 事件携带的不透明 `object` actor 来推导观测状态的所有者。`ToolExecution` 满足此形状,因此 `dsh-tool-fs` 将其执行对象作为 actor 直接传递,而无需让 `dsh-fs-policy` 导入 tool、agent 或 session 包。 ```ts type-equiv +/** + * Minimal structural view of a tool execution the policy plugin needs to derive + * an observed-state owner. `@deepseek-ai/dsh-tools`' `ToolExecution` satisfies + * this shape, so the tool passes its `exec` straight through as the opaque + * `object` actor on the `fs/*` events; this plugin narrows that actor to this + * shape without importing `dsh-tools`, `dsh-agent`, or `dsh-session`. + * + * The owner is `agent.session` when present. It is treated as an opaque object + * identity (a `WeakMap` key); this package never reads any of its fields. + */ interface FsPolicyExec { + /** The agent on whose behalf the call runs, when there is one. */ agent?: { + /** The session that owns observed-file state, used as an opaque key. */ session?: object } } @@ -111,10 +210,15 @@ interface FsPolicyExec { 文本读取受行窗口、字节上限和后端限制约束。面向模型的 `read` 工具渲染的结果纯粹是展示性的;不存在 `full`/`partial` 视图区分——授权基于新鲜度(工具直接用 stat 的版本 emit `fs/observed`),因此任何窗口化读取在文件未变时都能授权后续的 write/edit。读取窗口化与此结果形状位于 `dsh-tool-fs`(拥有读取操作的执行器)中,而非策略插件中。 ```ts type-equiv +/** Outcome of a bounded text read — what {@link formatReadOutput} renders. */ interface FileReadOutcome { + /** 1-based first line requested. */ offset: number + /** Returned lines, already numbered. */ lines: FileTextLine[] + /** Total line count in the file, unless `truncatedByBytes` stopped scanning early. */ totalLines: number + /** Whether selected output hit the byte cap before EOF or the requested limit. */ truncatedByBytes?: true } ``` @@ -128,12 +232,18 @@ interface FileReadOutcome { 文件系统故障使用稳定的 `FsErrorCode` 字符串,由 `FsError`(`HarnessError`)携带。工具注册表在错误结果上保留 `{ name, code }`,使重试、权限和 UI 层可以按 code 分支而无需解析文本。 ```ts type-equiv +/** + * Stable, machine-routable codes for filesystem failures. Carried on + * {@link FsError}; the tool registry surfaces `{ name, code }` on `isError` + * results so retry/permission/UI layers can branch without parsing messages. + */ type FsErrorCode = | 'FS_NOT_FOUND' | 'FS_NOT_DIRECTORY' | 'FS_NOT_TEXT' | 'FS_NOT_REGULAR_FILE' | 'FS_PERMISSION_DENIED' + | 'FS_SANDBOX_DENIED' | 'FS_IO_ERROR' | 'FS_STALE_VERSION' | 'FS_NOT_OBSERVED' @@ -142,8 +252,8 @@ type FsErrorCode = | 'FS_ABORTED' ``` -`FS_NOT_DIRECTORY`、`FS_PERMISSION_DENIED` 和 `FS_IO_ERROR` 用于目录列表操作,分别区分目标存在但不是目录、列表被拒绝、以及意外的后端 I/O 故障。`FS_NOT_OBSERVED` 表示策略插件对该所有者没有先前观测记录(或 `createIfAbsent` 遇到了已存在的文件)。`FS_STALE_VERSION` 表示后端版本不再匹配已观测版本(或 edit 遇到了缺失的目标)。新鲜度授权没有 partial/full 区分,因此不存在 `FS_PARTIAL_OBSERVATION`。 +目录列表使用 `FS_NOT_DIRECTORY`、`FS_PERMISSION_DENIED` 与 `FS_IO_ERROR` 区分已存在但并非目录的目标、被拒绝的列表操作和意外的后端 I/O 失败。`FS_SANDBOX_DENIED` 是强制执行 sandbox 的后端(`dsh-fs-sandbox`)所作的策略拒绝——模式边界拒绝了写入/编辑——与 `FS_PERMISSION_DENIED`(宿主内核拒绝)不同。`FS_NOT_OBSERVED` 表示策略插件没有此所有者的先前观察记录(或 `createIfAbsent` 遇到了现有文件)。`FS_STALE_VERSION` 表示后端版本不再与观察到的版本匹配(或编辑操作遇到缺失目标)。新鲜度授权没有部分/完整之分,因此不存在 `FS_PARTIAL_OBSERVATION`。 ## 服务与插件 -`FileSystem`(`ctx.fs`,抽象)拥有提供方原语:`resolve`、`stat`、`readText`、`streamText`、`listDir`、`writeText` 和 `editText`。`dsh-fs-policy` **不注册任何服务**——它是一个通过 `fs/*` 事件门控叠加策略的插件:它裁决 write/edit intent waterfall(提供 `createIfAbsent`/`replaceIfVersion`/`{ version }` 或抛出 `FS_NOT_OBSERVED`),并在 `fs/observed` 上记录。执行器是 `dsh-tool-fs`:它通过 `ctx.fs` 读取/写入/编辑,分发 waterfall,并 emit 记录事件。生成的接线目录在 [services.md](../cordis-catalog/services.md#ctxfs--filesystem-abstract-seam) 中展示确切的 `ctx.fs` 签名。 +`FileSystem`(`ctx.fs`,abstract)拥有提供方原语:`resolve`、`stat`、`lstat`、`readText`、`streamText`、`listDir`、`writeText` 与 `editText`。`dsh-fs-policy` **不注册服务**——它是一个通过 `fs/*` 事件门禁添加策略的插件:对写入/编辑意图 waterfall 作出决策(提供 `createIfAbsent`/`replaceIfVersion`/`{ version }`,或抛出 `FS_NOT_OBSERVED`),并在 `fs/observed` 上记录。执行器是 `dsh-tool-fs`:它通过 `ctx.fs` 读取/写入/编辑,分发 waterfall,并 emit 记录事件。生成的 wiring 目录在 [services.md](../cordis-catalog/services.md#ctxfs--filesystem-abstract-seam) 中展示确切的 `ctx.fs` 签名。 diff --git a/docs/core-data-structures/llm-streaming.i18n.yaml b/docs/core-data-structures/llm-streaming.i18n.yaml index b06be9dfa6..22691c44f4 100644 --- a/docs/core-data-structures/llm-streaming.i18n.yaml +++ b/docs/core-data-structures/llm-streaming.i18n.yaml @@ -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 -llm-streaming.md: ffd276b4647be8d10afcab0fb3c3f6daad790d20 -llm-streaming.zh.md: ea11f47e1148d21c2f23a648002c9413103628f1 +llm-streaming.md: cb99c935aea2dc9cc769e3056fdb98a2e5c9eacb +llm-streaming.zh.md: 5dc270acc97cdeac8cf24a36c443d550e14122dc diff --git a/docs/core-data-structures/llm-streaming.zh.md b/docs/core-data-structures/llm-streaming.zh.md index ea11f47e11..5dc270acc9 100644 --- a/docs/core-data-structures/llm-streaming.zh.md +++ b/docs/core-data-structures/llm-streaming.zh.md @@ -11,6 +11,13 @@ 一个流式响应交错包含多种类型的块(文本、推理(reasoning)、多个工具调用)。`index` 将每个 delta 关联到其所属块;`block-end` 携带完整组装好的 `ContentBlock`,消费方无需自行重新组装 delta。这是一个**封闭的**可辨识联合类型:对 `type` 的 `switch` 以 `assertNever` 结尾,因此新增变体会在每个必须处理它的消费方处触发编译错误。 ```ts type-equiv +/** + * Raw streaming protocol emitted by adapters. + * Block indexes correlate interleaved deltas, and `block-end` carries the + * assembled block. Adapters emit usage before the terminal finish and nothing + * afterward; tool arguments remain raw JSON strings. Failures either throw or + * end with `error`/`aborted`, and consumers must handle both paths. + */ type StreamChunk = | { type: 'block-start'; index: number; blockType: ContentBlockType } | { type: 'text-delta'; index: number; text: string } @@ -18,7 +25,32 @@ type StreamChunk = | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string } | { type: 'block-end'; index: number; block: ContentBlock } | { type: 'usage'; usage: TokenUsage } - | { type: 'finish'; reason: FinishReason } + | { + type: 'finish' + reason: FinishReason + /** Adapter-private lossless-JSON state for replaying a successful response. */ + replayState?: unknown + } +``` + +## `LlmFailure` + +每个抛出的失败或 final-adapter 带内失败都会规范化为一种可序列化、提供方中立的 payload。`providerRetryAfterMs` 是经校验、由提供方请求的正数延迟,而不是重试决策;`ProviderRequestId` 是用于诊断的不透明品牌字符串。 + +```ts type-equiv +/** Serializable provider-boundary facts; policy decides whether they are retryable. */ +interface LlmFailure { + /** Human-readable provider or transport failure. */ + readonly message: string + /** Stable provider-neutral machine-routing code. */ + readonly code: string + /** HTTP status observed at the provider boundary, when available. */ + readonly status?: number + /** Provider-requested delay in milliseconds, when valid and available. */ + readonly providerRetryAfterMs?: number + /** Opaque provider-issued request identifier for diagnostics. */ + readonly requestId?: ProviderRequestId +} ``` ## 适配器契约 @@ -27,28 +59,50 @@ type StreamChunk = - **`usage` 在 `finish` 之前,`finish` 之后不再有任何分片。** 将两者都推迟到提供方的流结束标记,这样尾部的 usage-only 分片就不会违反顺序。 - **工具调用的 `arguments` 全程保持原始 JSON 字符串。** 部分片段通过 `argumentsDelta` 流式传输;如果提供方返回的是已解析的对象,适配器在 `block-end` 时重新序列化为字符串。 -- **两条许可的错误路径。** 失败可以从 `stream()` 中 THROW(传输/协议错误),**或者**以 `finish {kind:'error'|'aborted'}` 结束流(提供方带内错误,适用于无法在流中途抛出异常的适配器)。消费方必须同时处理*两种*情况。agent loop(智能体循环)将 finish-error/aborted 转化为轮次错误,绝不会为失败的步骤记录一条正常完成的 assistant 消息。 +- **两条受支持的错误路径,一种事实形状。** 失败可以从 `stream()` 抛出(传输/协议错误),**或者**以 `finish {kind:'error'|'aborted', failure}` 结束流(无法在流中途抛异常的适配器用它表示提供方带内错误)。`LlmError.failure` 携带同一个 `LlmFailure`。final adapter 边界保留被抛出的确切 `Error` 对象,并将不可变事实关联到该调用;agent loop 关闭失败的 step,再把错误、事实与不可变的先前已重试事实提供给 `agent/request-error`。若未恢复,结构化失败会成为 turn 错误,并且该次尝试不会提交正常 assistant 消息或工具副作用。 +- **一次适配器调用就是一次提供方尝试。** 适配器禁用库重试。agent 层恢复会打开另一个持久、带编号的 step;直接调用 `ctx.llm.stream()` 的调用方仍然只尝试一次。 +- **提供方停顿在传输层受到时限约束。** 两个已交付的远程适配器都暴露正数且有限的 `streamIdleTimeoutMs`,默认五分钟。watchdog 只在 iterator `next()` 尚未完成时启动,整个请求使用同一个稳定 signal,把自身到期映射为 `TIMEOUT`,并把更早发生的调用方中止保留为 `ABORTED`。 +- **上下文溢出只有一个规范 code。** 两个 DeepSeek 适配器都通过 `isContextWindowExceededError()` 对提供方的显式细节分类并暴露 `CONTEXT_WINDOW_EXCEEDED`,无论失败以抛出的 HTTP `LlmError` 还是带内 finish error 到达。消费方按 code 路由,绝不依赖提供方文本。 - **每个提供方 HTTP 请求都携带应用归属头。** 适配器发送 `attributionHeaders()`(见下文)作为 `User-Agent` 基线,并通过协议级测试加以证明(mock 服务器断言收到的 header,或对基于库的适配器使用库的 header 钩子)。 +- **回放状态归适配器所有。** 成功的 `finish` 可以携带重建提供方原生响应所需的无损 JSON 状态。除非 `agent/step-result` listener 改写了内容,否则循环会将其与组装后的 assistant 消息一起存储。后续请求中,仅当历史提供方与目标提供方当前注册到完全相同的适配器实例时,`LlmService` 才会传递该状态。该适配器负责校验状态并拥有所有跨模型或跨提供方转换;其他适配器只会收到提供方中立的内容与 provenance,不会收到私有状态。 -这份契约正是两个适配器作为刻意配对存在的原因:`dsh-llm-deepseek`(手写 fetch/SSE(Server-Sent Events))与 `dsh-llm-pi-ai`(通过 `@earendil-works/pi-ai` 访问同一端点)。两套独立内部实现共享一份契约,正是将协议固定下来的方式:基于库的适配器无法在流中途抛出异常,因此它走通了手写适配器可能不会走到的 finish-chunk 错误路径。 +该契约由两个有意保持独立的实现锁定:`dsh-llm-deepseek`(手写 fetch/SSE)和 `dsh-llm-pi-ai`(通过 `@earendil-works/pi-ai` 实现的通用多提供方适配器)。基于库的适配器覆盖 finish-chunk 错误路径,而传输边界测试证明每个空闲 watchdog 都会停止其实际请求。 ## `AppIdentity`:应用归属 -每个适配器向提供方发送的静态公开应用标识([`packages/llm/llm/src/attribution.ts`](../../packages/llm/llm/src/attribution.ts))。`attributionHeaders(identity?)` 仅将其映射为标准 `User-Agent` header;本契约有意不支持 OpenRouter 特有的应用归属 header。默认的 `APP_IDENTITY` 从 package manifest(元数据清单)获取版本号;每个字段都是公开的产品事实,不含密钥、路径、会话 id 或用户级标识符,且任何请求级信息都不得影响这些值。设计依据见 [Mandatory `User-Agent` attribution](../rfc/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 +每个适配器都会向提供方发送的静态公开应用标识([`packages/llm/llm/src/attribution.ts`](../../packages/llm/llm/src/attribution.ts))。`attributionHeaders(identity?)` 只把它映射到标准 `User-Agent` header;该契约有意不支持 OpenRouter 特有的应用归属 header。默认 `APP_IDENTITY` 从包 manifest 获取版本;每个字段都是公开产品事实——不含 secret、路径、session id 或逐用户标识,且任何逐请求信息都不得影响这些值。设计理由见[强制 `User-Agent` 归属](../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 ```ts type-equiv +/** + * Static public application identity sent to LLM providers. + * + * Every field is a public product fact, safe on every request: no secrets, + * local paths, session ids, prompt text, or per-user identifiers belong here, + * and nothing per-request may influence the values. + */ interface AppIdentity { + /** `User-Agent` product token (lowercase, hyphenated). */ product: string + /** Product version; sourced from package metadata, never hand-copied. */ version: string + /** Public home URL of the app, used as the `User-Agent` comment. */ url: string } ``` ## `TokenUsage` -单次调用的 token 用量统计。各计数**互不重叠**:`inputTokens` 仅为未缓存的输入;缓存命中的输入单独报告,计费输入是三者之和。如果提供方将缓存命中合并到单一的 prompt 总量中(如 DeepSeek 的 `prompt_tokens`),适配器需将其减回去。 +逐调用 token 记账。各计数**互不重叠**:`inputTokens` 只包含未缓存输入;缓存输入单独报告,计费输入是三者之和。若提供方把缓存命中折入单一 prompt 总数(如 DeepSeek 的 `prompt_tokens`),适配器会再将其扣除。`reasoningTokens` 存在时只是信息性细节,已经包含在 `outputTokens` 中;汇总时不得重复相加。 ```ts type-equiv +/** + * Token accounting for one model call (cache fields are optional). + * + * Counts are DISJOINT: `inputTokens` is uncached input only; cached input is + * reported separately as `cacheReadTokens`/`cacheWriteTokens` (billed input = + * sum of the three). Adapters whose providers fold cache hits into a total + * prompt count (DeepSeek's `prompt_tokens`) subtract them out. + */ interface TokenUsage { inputTokens: number outputTokens: number @@ -60,15 +114,99 @@ interface TokenUsage { ## `BlockAssembler` -`BlockAssembler`([`packages/llm/llm/src/assembler.ts`](../../packages/llm/llm/src/assembler.ts))是唯一的共享实现,将 `StreamChunk` 流折叠回 `ContentBlock` 列表与最终的 `Message`。agent loop 记录原始分片(保证回放保真度),同时将相同的分片送入 assembler,因此权威日志保留了 token 级细节,而派生消息可确定性地重建。需要组装结果而不想重新实现折叠逻辑的消费方使用它。 +`BlockAssembler`([`packages/llm/llm/src/assembler.ts`](../../packages/llm/llm/src/assembler.ts))是唯一的共享实现,负责把 `StreamChunk` 流折叠回 `ContentBlock`、usage、finish reason 与 replay state。循环在记录原始 chunk 的同时,把同一批 chunk 送入 assembler,再将组装后的 assistant 内容连同其 provider/model provenance 一起存储。需要组装结果、又不想重新实现 fold 的消费方使用它。 + +```ts public-api +/** + * Incrementally assembles raw {@link StreamChunk}s into complete + * {@link ContentBlock}s and a final assistant {@link Message}. + * + * The agent loop feeds it while logging raw chunks for replay fidelity, then + * reads `blocks()` / `message()` / `usage` / `finish` once the stream ends. + * + * Tolerant of delta-only protocols (no block-start/end); deltas arriving for + * an index already closed by `block-end` are ignored (malformed stream) so a + * misbehaving adapter cannot grow memory or corrupt a completed block. + */ +declare class BlockAssembler { + /** + * Feed one chunk into the assembly state. + * @param chunk - the next raw chunk, in stream order. + */ + push(chunk: StreamChunk): void; + /** + * Assemble all blocks seen so far, in stream order. + * @returns one block per seen index; an open block assembles from its + * accumulated deltas (an unknown block type never closed by `block-end` throws). + */ + blocks(): ContentBlock[]; + /** Usage from the `usage` chunk; undefined until one arrives. */ + get usage(): TokenUsage | undefined; + /** Finish reason from the `finish` chunk; `{kind: 'stop'}` when the stream ended without one. */ + get finish(): FinishReason; + /** Adapter-private replay state from the terminal finish chunk, if any. */ + get replayState(): unknown; + /** + * The assembled assistant message. + * @returns an assistant-role message over `blocks()` (same open-block assembly rules). + */ + message(): Message; +} +``` ## seam -`LlmAdapter` 是提供方 seam:继承它、实现 `stream()`、通过 `ctx.llm.registerAdapter(models, adapter)` 注册。`block-start`/`block-end` 的 `index` 关联加上 assembler 意味着适配器只需发出格式正确的分片,块重组不是各适配器需要操心的事。消费方接口(`ctx.llm.stream()`)与 `llm/stream` waterfall(瀑布式事件)在 [architecture.md § Content blocks and streaming](../architecture.md#content-blocks-and-streaming-dsh-llm) 中描述。 +`LlmAdapter` 是提供方 seam:创建子类、实现 `stream()`,再用 `ctx.llm.registerAdapter(providers, adapter)` 注册一个适配器实例。`GenerateOptions.provider` 选择已注册适配器;`GenerateOptions.model` 会传给该适配器,无需在生命周期启动时注册。重复提供方路由会原子失败。可选的 `providerInfo()` 与异步 `listModels()` 方法为 `LlmService.listProviders()` / `listModels()` 提供分离的 selector 元数据。该目录仅供参考,不是请求白名单:适配器仍是权威,并可接受未列出的模型 id。单独的 `resolveModelContext()` 查询会暴露确切路由上对正确性敏感的容量信息,但不会让目录成员关系具有权威性;缺失表示元数据未知,而不是路由无效。适配器查找发生在 `llm/stream` waterfall 的终端 continuation,因此 listener 可以在查找前短路调用,或路由一个可变的一次性请求。`block-start` / `block-end` 的 `index` 关联与 assembler 共同意味着适配器只需 emit 格式正确的 chunk——block 重组不是每个适配器各自的问题。消费方 surface(`ctx.llm.stream()`)与 `llm/stream` waterfall 见 [architecture.md § 内容 block 与流式传输](../architecture.md#content-blocks-and-streaming-dsh-llm)。 + +```ts public-api +/** + * Provider-wire adapter for the harness message and stream vocabulary. Register implementations + * with `ctx.llm.registerAdapter(providers, adapter)`. Every provider HTTP request must include + * `attributionHeaders()`; prove that at the wire or library header-hook boundary. The hand-rolled + * DeepSeek and pi-ai adapters intentionally exercise this contract through different internals. + */ +declare abstract class LlmAdapter { + /** + * Describe one provider route owned by this adapter. + * @param provider - a route passed to `registerAdapter()` for this instance. + * @returns detached display metadata whose id must equal `provider`. + */ + providerInfo(provider: string): LlmProviderInfo; + /** + * List models this adapter can currently advertise for one owned provider. + * The result is advisory: an adapter may accept unlisted model ids, and + * consumers must not turn absence into request rejection. + * @param _provider - one provider route owned by this adapter. + * @returns discoverable models in adapter-preferred order. + */ + listModels(_provider: string): Promise<readonly LlmModelInfo[]>; + /** + * Resolve context capacity for one model accepted by this adapter. Absence + * means the adapter does not know the capacity, not that routing is invalid. + * @param _provider - one provider route owned by this adapter. + * @param _model - exact model id passed to {@link GenerateOptions.model}. + * @returns provider-owned context metadata, or `undefined` when unavailable. + */ + resolveModelContext( + _provider: string, + _model: string, + ): Promise<LlmModelContext | undefined>; + /** + * Stream one model call as raw chunks. The only required method. + * @param options - the fully-assembled request; implementations must honor `options.signal`. + * @returns the chunk stream, obeying the adapter contract documented on `StreamChunk`. + */ + abstract stream(options: GenerateOptions): AsyncIterable<StreamChunk>; +} +``` `ContentBlockType`(`index` 关联块所携带的键集合)派生自 `ContentBlockMap`: ```ts type-equiv +/** + * Merge-extensible content blocks keyed by `type`. New core blocks must land + * with adapter, UI, and compaction support. + */ interface ContentBlockMap { 'text': TextBlock 'reasoning': ReasoningBlock diff --git a/docs/core-data-structures/persistence.i18n.yaml b/docs/core-data-structures/persistence.i18n.yaml index 3072063a43..d8baef895b 100644 --- a/docs/core-data-structures/persistence.i18n.yaml +++ b/docs/core-data-structures/persistence.i18n.yaml @@ -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 -persistence.md: ce7a21a5613da903a9bddd339e122bf9f899d2bd -persistence.zh.md: 33ddda66aacc21f847dfd45702b11b5381711cce +persistence.md: d4bb4ed1b65eb74ff03483bf3a71a1736300834e +persistence.zh.md: 93a418b3b06dbf0d42978900ef79a0fb86ac15f7 diff --git a/docs/core-data-structures/persistence.zh.md b/docs/core-data-structures/persistence.zh.md index 33ddda66aa..93a418b3b0 100644 --- a/docs/core-data-structures/persistence.zh.md +++ b/docs/core-data-structures/persistence.zh.md @@ -4,16 +4,34 @@ 事件日志的**持久性 seam**。[session.md](session.md) 描述了内存中的 `Session`:仅追加的 `SessionEvent` 日志即为真源。本页描述如何使该日志持久化:抽象的 `SessionPersistence` 服务、它的后端、flush 检查点、崩溃恢复,以及随日志一同存储的元数据头。日志承载的事件词汇在生成的[持久化日志事件目录](../persistence-catalog.md)中逐项列举。 -该 seam 是典型的[能力 seam](../rfc/implemented/architecture/2026-06-13-capability-seams.md):一个抽象服务([dsh-session-persistence](../../packages/session-persistence/session-persistence),`ctx.sessionPersistence`)在已有的 `SessionEvent` 之上定义 create/append/load/list 操作,**没有并行的持久化类型**,以及两个可互换的后端,它们通过同一套 `runPersistenceContract` 测试。详见 [session-persistence RFC](../rfc/implemented/architecture/2026-06-14-session-persistence.md)。 +该 seam 是典型的[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):一个抽象服务([dsh-session-persistence](../../packages/session-persistence/session-persistence),`ctx.sessionPersistence`)在现有 `SessionEvent` 上定义 locate/create/append/load/list——**没有平行的持久化类型**——以及两个可互换、通过同一套 `runPersistenceContract` 的后端。见 [session-persistence Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-06-14-session-persistence.md)。 ## flush 检查点 -`session/event` 是一个*同步*通知;持久化插件对其进行缓冲(write-behind),并在 agent loop(智能体循环)于每个轮次结束时触发的 `session/flush` 检查点处排空缓冲区。flush 使用 `ctx.parallel`(被 await):一个轮次的事件在下一个轮次开始前已被持久提交,轮次边界即提交边界。flush 拒绝时通过 `agent/error` 和 logger 报告,而非作为会话事件(那样会落在提交边界之后),因此后端保留其缓冲事件等待下一次 flush。 +`session/event` 是一个*同步*通知;持久化插件会将其缓冲(write-behind)至 `session/flush`。循环会 await 普通 turn 的 checkpoint 后再领取下一个队列项;同步的 idle `inject()` 会调度自己的 checkpoint 而不阻塞 `send()`,dispose 仍会将其排空。成功 flush 会把已关闭 turn 作为一个单元持久提交;被拒绝的 flush 通过 `agent/error` 与 logger 报告——绝不会作为已关闭 turn 之后的 session 事件——而后端会保留已缓冲事件供下次 flush 使用。 ## 崩溃恢复保留被中断的轮次 后端重新加载一个在轮次中途崩溃的日志时,会发现一个已打开的 `turn/start` 却没有 `turn/end`。它**不会**截断日志:在长周期任务中,单个轮次可能非常庞大(许多步骤、大量工具输出),而这些事件在崩溃前已被持久追加。后端改为用一个合成的 `turn/end { reason: { kind: 'interrupted' } }` 关闭这个遗留轮次,保持日志平衡与轮次闭合不变式。`interrupted` 是唯一一个不由循环发出的 `TurnEndReason`(见 [session.md](session.md#why-a-turn-ended-turnendreasonmap))。 +## `SessionLocation`——可选的逐会话制品目标 + +`SessionPersistence.locate(meta)` 会同步解析一个归后端所有的独立制品,而不会读取、创建或 flush 它。JSONL 返回其绝对目标路径;SQLite 因各 session 共享一个数据库而返回 `undefined`。因此,返回的路径可能指向尚不存在、或还不包含当前未 flush turn 的文件;它是位置提示,不是授权或新鲜度保证。 + +```ts type-equiv +/** + * A backend-resolved, per-session local artifact location. The path is an + * absolute target path and can name an artifact that has not materialized yet. + * Consumers must treat it as a location hint, never as an authorization token. + */ +interface SessionLocation { + /** Backend-specific artifact kind, for example `jsonl`. */ + readonly kind: string + /** Absolute path to this session's backend-owned artifact. */ + readonly path: string +} +``` + ## `SessionHeader`:日志旁的元数据 每个会话的元数据与事件日志**分开**存储:格式版本、cwd、血统与 seed 边界是存储层关注点而非对话事件,因此不进入 `SessionEventMap`,也不会到达 `deriveMessages()`。header 通过 `session.header` 附加到 `Session` 上。 @@ -21,6 +39,9 @@ 源码:[`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts) ```ts type-equiv +/** + * Immutable validated storage metadata, kept outside the conversation event log. + */ interface SessionHeader { /** * On-disk format version, stamped from {@link SESSION_FORMAT_VERSION} when the @@ -37,43 +58,42 @@ interface SessionHeader { /** The session this one was forked from (seed lineage), if any. */ readonly parentSession?: SessionId /** - * How many leading events were INHERITED via a seed rather than produced by - * this session — the seed boundary. Set when a fork seeds a child with a - * prefix of the parent's log (= the seeded prefix length); absent/0 means the - * session produced all its own events. Persisted so a reload reconstructs the - * boundary instead of re-deriving it from the full stored log, and so a replay - * harness can skip the inherited prefix when deriving the child's OWN script - * (the seeded events are the parent's, not this child's model calls). + * How many leading events were inherited through a seed. Persisting this + * boundary lets resume and replay distinguish parent history from child work. */ readonly seedLength?: number + /** + * Delegation depth: absent (zero) for a top-level session, parent depth + 1 + * for a subagent child. Persisted so a recursion budget survives restart and + * resume — a runtime-only depth would reset a resumed child to top-level. + */ + readonly delegationDepth?: number } ``` ## `CreateSessionOptions`:seed 与元数据 -通过 store 创建 `Session` 时接受 `seed`(回放/fork 已有事件日志)和 `meta`(store 折叠进 `SessionHeader` 的存储层字段)。store 填充 `version`/`id` 并默认 `createdAt`;调用方提供经过校验的绝对路径 `cwd`、`parentSession` 血统、`seedLength` seed 边界,以及仅在重建持久化会话时提供的原始 `createdAt` 以保留其值。 +通过 store 创建 `Session` 时会接收 `seed`(回放/fork 现有事件日志)与 `meta`(store 折叠进 `SessionHeader` 的存储层字段)。store 填充 `version`/`id` 并为 `createdAt` 提供默认值;调用方提供已校验的绝对 `cwd`、`parentSession` 谱系、`seedLength` 种子边界、`delegationDepth`,以及——仅在重建已持久化 session 时——需要保留的原始 `createdAt`。 ```ts type-equiv +/** + * Options for creating a {@link Session} via the store. `seed` replays/forks + * an existing event log; `meta` carries the caller-supplied storage fields the + * store folds into a {@link SessionHeader}. + */ interface CreateSessionOptions { /** Events to seed the new session with (replay/fork). */ readonly seed?: readonly SessionEvent[] /** - * Creation metadata. The store fills in `version`/`id` and defaults - * `createdAt` to now; the caller supplies the storage-level fields (validated - * absolute `cwd`, `parentSession` lineage, the seed boundary `seedLength`, and - * — when reconstructing a persisted session — the original `createdAt` to - * preserve it). - * - * `seedLength` is EXPLICIT, not inferred from `seed.length`: a reconstruction - * (resume/load) seeds the WHOLE stored log, so its `seed.length` is the full - * length, not the original boundary — the caller must pass the persisted - * boundary back. A fresh fork passes its actual seeded-prefix length. + * Storage metadata read once before publication. `seedLength` is explicit + * because a resumed seed contains the full stored log, not only its inherited prefix. */ readonly meta?: { readonly cwd?: string readonly parentSession?: SessionId readonly createdAt?: number readonly seedLength?: number + readonly delegationDepth?: number } } ``` @@ -82,9 +102,9 @@ interface CreateSessionOptions { ## 后端 -两者实现相同的抽象 `SessionPersistence`(在 `SessionEvent` 之上提供 create/append/load/list),并通过 `runPersistenceContract`,证明该 seam 真正与后端无关: +两者都实现同一个抽象 `SessionPersistence`(在 `SessionEvent` 上执行 locate/create/append/load/list),并通过 `runPersistenceContract`,证明该 seam 确实与后端无关: -- **[dsh-session-persistence-jsonl](../../packages/session-persistence/session-persistence-jsonl)**:每个会话一个仅追加的 JSONL 日志,具备崩溃安全的原子写入、上述中断轮次崩溃恢复,以及读取/回放路径。 +- **[dsh-session-persistence-jsonl](../../packages/session-persistence/session-persistence-jsonl)**——每个 session 一份仅追加的逻辑 JSONL 日志,默认存储为带 checksum 的连续 Zstandard frame,也可配置为原始行;支持崩溃安全的原子写入、中断 turn 恢复以及读取/回放路径。 - **[dsh-session-persistence-sqlite](../../packages/session-persistence/session-persistence-sqlite)**:基于 `node:sqlite`,每个 `SessionEvent` 一行。行结构 `(session_id, seq, type, time, data, source_event_seqs, surface_op)` 与事件 1:1 映射(包含可选的 surface 元数据),因此没有需要保持同步的并行持久化 schema。 -多个后端共享同一磁盘会话时,通过[共享持久化写协调器](../rfc/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)协调写入。 +共享同一磁盘 session 的多个后端通过[共享持久化写入协调器](../../.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)协调写入。 diff --git a/docs/core-data-structures/sandbox.i18n.yaml b/docs/core-data-structures/sandbox.i18n.yaml index e68f9b2c75..1bd49e2273 100644 --- a/docs/core-data-structures/sandbox.i18n.yaml +++ b/docs/core-data-structures/sandbox.i18n.yaml @@ -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 -sandbox.md: be8e3cd60681077ff5036915fd99520fe9685140 -sandbox.zh.md: ca21c09e7f3d0756f78d7bd1581b9b4b03a43815 +sandbox.md: 9bc05fa06f22fdc9ac9e8aacd482c1e7c2f2edec +sandbox.zh.md: dd02041dea998221f1fa7549cb829791137b5088 diff --git a/docs/core-data-structures/sandbox.zh.md b/docs/core-data-structures/sandbox.zh.md index ca21c09e7f..dd02041dea 100644 --- a/docs/core-data-structures/sandbox.zh.md +++ b/docs/core-data-structures/sandbox.zh.md @@ -11,39 +11,90 @@ `SandboxMode` 仅管控文件系统效果。`read-only` 拒绝所有写入(必需的 `/dev/null` 接收器除外);`workspace-write` 允许在工作区根目录及后端承诺的临时区域下写入;`danger-full-access` 绕过隔离。网络与进程可见性不在此处的定义范围内。 ```ts type-equiv +/** + * File-effect policy for confined processes. `read-only` permits only required + * sinks such as `/dev/null`; `workspace-write` also permits the workspace and a + * backend-defined temp area; `danger-full-access` bypasses confinement. Network + * and process visibility are outside this vocabulary. + */ type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access' ``` 只有前两种模式可以发送给提供方。`danger-full-access` 的消费方直接 spawn 原始 argv,不调用 `ctx.sandbox`。 ```ts type-equiv +/** A confining (non-`danger-full-access`) mode — the modes a {@link SandboxPolicy} can carry. */ type ConfinedSandboxMode = Exclude<SandboxMode, 'danger-full-access'> ``` 强制执行程度是一个报告事实。`full` 表示后端管控了该模式承诺的所有文件效果;`partial` 表示活跃后端或较旧的内核 ABI 仅管控其中一个子集,因此要求绝对保证的消费方必须拒绝或向上暴露这一区别。 ```ts type-equiv +/** + * Enforcement completeness for this host. `partial` means an active backend or + * older kernel ABI cannot govern every promised file effect; callers requiring + * an absolute boundary must not treat it as `full`. + */ type SandboxEnforcement = 'full' | 'partial' ``` ## 逐调用策略 -策略在每次调用时完全解析并随调用携带。这使得并发消费方和一次性提权重试能够向同一个提供方请求不同的边界,而无需修改提供方状态。 +完整执行策略会按每次能力调用解析并携带。它包括 `danger-full-access`,因此消费方可以只解析一次策略,再决定是否绕过约束。普通工具调用从调用 session 的不可变 cwd 派生 `workspaceRoot`;部署配置是没有 agent 时的回退值。root 会先按文件系统语义规范化,再做词法规范化,因此包含 `symlink/..` 的 cwd 会标识所生成进程实际运行的目录。 ```ts type-equiv -interface SandboxPolicy { +/** + * The complete file-effect policy resolved for one capability call. The root + * is carried even under modes that do not consume it so callers can resolve + * policy once before choosing the enforcement path. + */ +interface SandboxExecutionPolicy { /** The file-effect mode this execution runs under. */ - mode: ConfinedSandboxMode + mode: SandboxMode /** Absolute root directory `workspace-write` may write under. */ workspaceRoot: string } ``` +`ctx.sandboxPolicy.resolve()` 接收活跃 session;对于已批准的重试,还接收显式模式。该服务拥有优先级与 root 回退规则,使 bash 和 fs 不必重复实现。 + +```ts type-equiv +/** Inputs that select the sandbox policy for one capability call. */ +interface SandboxPolicyRequest { + /** Calling session; its immutable cwd becomes the workspace boundary. */ + session?: Session + /** Explicit approved mode override, which outranks session policy. */ + mode?: SandboxMode +} +``` + +只有受约束的执行会到达 `ctx.sandbox`;其提供方策略在保留同一 root 的同时收窄模式。这使并发 session、消费方与一次性提权重试可以向同一提供方请求不同边界,而无需改变提供方状态。 + +```ts type-equiv +/** + * What one confined execution is allowed to touch — carried PER CALL, not + * fixed on the provider: two consumers may confine under different policies + * at the same instant (bash under `read-only` while a confined child agent + * needs its state directory writable), and an approved escalated retry is a + * new call with a wider policy. Defaulting/resolution is an explicit step at + * the consumer boundary; the provider treats the policy as fully specified. + */ +interface SandboxPolicy extends SandboxExecutionPolicy { + /** The file-effect mode this execution runs under. */ + mode: ConfinedSandboxMode +} +``` + ## 包装后的 argv 与分类方言 `ConfinedArgv` 是消费方实际 spawn 的内容。除了替换后的 argv,它还携带后端的强制执行事实和两种正交的 stderr 方言。`denialSignatures` 用于识别沙箱正常工作时被隔离命令被阻止的情况。`runnerFailureSignatures` 用于识别沙箱运行器在执行命令之前拒绝或失败的情况;消费方应先检查后者,将其作为沙箱基础设施故障上报,而非普通任务失败。 ```ts type-equiv +/** + * A {@link SandboxProvider.confine} result: the argv to spawn in place of + * the caller's own, plus the enforcement completeness the selected backend + * achieves for it. + */ interface ConfinedArgv { /** The wrapped argv (runner, profile, separator, then the caller's argv). */ argv: string[] @@ -59,17 +110,9 @@ interface ConfinedArgv { */ denialSignatures: readonly string[] /** - * How the RUNNER ITSELF failing identifies itself: case-insensitive stderr - * substrings produced when the sandbox binary is missing, refuses its - * profile, or fails closed before exec'ing the command (`bwrap: `, - * `landlock-run: `, `sandbox-exec: ` — each covers both the runner's own - * error prefix and the shell's runner-not-found message). ORTHOGONAL to - * {@link denialSignatures}: a denial is the confined COMMAND being blocked - * (the sandbox working as designed); a runner failure means the command - * NEVER RAN and must surface as a sandbox failure, not a task failure — - * consumers check these signatures FIRST (a runner's own error text may - * contain denial words, e.g. an unopenable grant root reporting - * `Permission denied`). + * Case-insensitive signatures for runner failure before command execution. + * Consumers check these before denial signatures: runner failure means the + * command never ran, while denial means confinement worked and blocked it. */ runnerFailureSignatures: readonly string[] } diff --git a/docs/core-data-structures/scope.i18n.yaml b/docs/core-data-structures/scope.i18n.yaml index 6d3acddaff..4067956fe6 100644 --- a/docs/core-data-structures/scope.i18n.yaml +++ b/docs/core-data-structures/scope.i18n.yaml @@ -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 -scope.md: f95594329ee9ac83da2efcc31df377c53e64331a -scope.zh.md: be423e62def89e03f15d438b9fd9db6fd41b68f3 +scope.md: 73a697f2843293daffff85dabf4656346f7dcd04 +scope.zh.md: b5cc21cfb3d3dbb3890d179f9a813dccb1c318ec diff --git a/docs/core-data-structures/scope.zh.md b/docs/core-data-structures/scope.zh.md index be423e62de..b5cc21cfb3 100644 --- a/docs/core-data-structures/scope.zh.md +++ b/docs/core-data-structures/scope.zh.md @@ -2,21 +2,27 @@ [English](scope.md) | 中文 -[scope 包(package)](../../packages/core/scope)提供身份标识与载体词汇,使一个注册上下文同时表达逐 agent(智能体)的可见性与共享的生命周期归属。它是一个库级原语,而非 Cordis 服务;[agent-scope 运行时设计 RFC](../rfc/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#scope-routing-one-opaque-key-selects-one-layer) 阐述了实现原理,包的 [README](../../packages/core/scope/README.md) 说明了可调用 API 与过滤语义。 +[scope 包](../../packages/core/scope)提供 identity、carrier 与 scoped-layer 词汇,使同一个注册 context 同时代表逐 agent 可见性和共享生命周期所有权。它是库原语,而不是 Cordis 服务;生命周期设计理由由 [agent-scope 运行时设计 Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#scope-routing-one-opaque-key-selects-one-layer)规定,registry-layer 决策由[共享存储 Agent Note](../../.agents/notes/implemented/architecture/2026-07-12-scoped-layers-store.md)规定,可调用 API 与过滤语义则由包 [README](../../packages/core/scope/README.md)规定。 -源码:[`packages/core/scope/src/index.ts`](../../packages/core/scope/src/index.ts)。 +源码:[`packages/core/scope/src/index.ts`](../../packages/core/scope/src/index.ts) 与 [`packages/core/scope/src/store.ts`](../../packages/core/scope/src/store.ts)。 ## 身份标识与分发载体 `ScopeKey` 是一个不透明的对象身份标识。已交付的 agent loop(智能体循环)使用活跃的 `Agent` 对象作为自身的 key,但该原语从不检视该对象。 ```ts type-equiv +/** An opaque, identity-compared scope key. */ type ScopeKey = object ``` `Scoped<T>` 是编译期品牌标记,标注在 `scopeTarget(base, key)` 返回的不透明路由接收器上。作用域过滤的事件声明要求以此载体作为 `this` 类型,而真正的事件主体仍作为显式参数传入。 ```ts type-equiv +/** + * A routing-only event receiver built by {@link scopeTarget}. The type + * parameter records the subject type for dispatch checking; the carrier does + * not expose the subject's properties. Event payloads carry the real subject. + */ type Scoped<T extends object> = object & { readonly [ScopedBrand]: T } ``` @@ -25,9 +31,29 @@ type Scoped<T extends object> = object & { readonly [ScopedBrand]: T } `Scope` 将带标签的注册上下文与两个拆卸接口配对。`rawDispose` 保留有序复合 effect 所需的精确 Cordis disposer 身份;`dispose()` 是面向直接调用方和竞态调用方的公共停稳边界。 ```ts type-equiv +/** A minted registration scope and its quiescent disposal boundaries. */ interface Scope { + /** Context through which scope-owned registrations are made. */ ctx: Context + /** Exact Cordis disposer, used when nesting this scope in an ordered composite effect. */ rawDispose: () => Promise<void> | void + /** Dispose every scope-owned registration; racing calls await the same completion. */ dispose(): Promise<void> } ``` + +## 带作用域的注册表层 + +`ScopeLayer` 表示一个注册表在全局或确切作用域层级的完整贡献。具体 layer 可以聚合多个具名与匿名 table;整个 layer 为空时,`ScopedLayers` 可以回收带作用域状态,而不会丢弃兄弟 table。 + +```ts type-equiv +/** One scope's aggregate contribution to a registry. */ +interface ScopeLayer { + /** Whether every table in this layer is empty. */ + isEmpty(): boolean +} +``` + +`ScopedLayers<L>` 拥有立即创建的全局 layer,以及惰性创建的确切作用域 layer。读取不会创建 layer:`peek(undefined)` 表示没有 overlay,而 `merge()` 会物化按插入顺序排列的全局具名 entry,随后是带作用域的 shadow。注册使用同一个 context 表示可见性与 Cordis effect 所有权,在可选通知前收集一个同步 undo,返回 Cordis 的确切 disposer,并且只在带作用域 layer 的完整 `ScopeLayer` 为空时回收它。 + +`NamedEntries<V>` 提供按插入顺序的查找与 live iteration,重复错误由调用方所有。`AnonymousEntries<V>` 为每次 append 分配唯一标识,使相等的值仍相互独立。迭代在同一非空 table generation 内保持 live;排空 table 会让现有 iterator 与后续插入脱离。两者都返回幂等的确切 entry undo;共享的 `EntryValues` 实现接口不公开。 diff --git a/docs/core-data-structures/session-query.i18n.yaml b/docs/core-data-structures/session-query.i18n.yaml index ff5bae0fba..297fdf7748 100644 --- a/docs/core-data-structures/session-query.i18n.yaml +++ b/docs/core-data-structures/session-query.i18n.yaml @@ -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 -session-query.md: 444f2bb2256a43df7bd8521dfe234f771eec7181 -session-query.zh.md: 70f9737a702f84074962d9d1c7ac49a7c119f8cf +session-query.md: 4f977b933225e4873466a379171ec3db2596a14e +session-query.zh.md: 864dd213102c1452337e66800db4cb828a1edb8b diff --git a/docs/core-data-structures/session-query.zh.md b/docs/core-data-structures/session-query.zh.md index 70f9737a70..864dd21310 100644 --- a/docs/core-data-structures/session-query.zh.md +++ b/docs/core-data-structures/session-query.zh.md @@ -2,7 +2,7 @@ [English](session-query.md) | 中文 -对实时优先的逻辑会话语料库进行精确读取。[包(package)契约](../../packages/session-query/session-query)定义了源优先级、动态可选持久化、克隆、surface 分类、有界窗口与类型化错误。全文搜索是另一个拟议的 SQLite 阶段。 +对优先使用 live 数据的逻辑 session 集合执行精确读取与关系追踪。[包契约](../../packages/session-query/session-query)拥有来源优先级、动态可选持久化、克隆、surface 分类、有界窗口、追踪校验与类型化失败。全文搜索属于另一个拟议的 SQLite 包。 源码:[`packages/session-query/session-query/src/types.ts`](../../packages/session-query/session-query/src/types.ts) @@ -11,58 +11,153 @@ `SessionRecord` 由跨语料库列表返回。它独立于克隆后的实时优先 header 暴露源可用性。`SessionEventRecord` 是轻量的原始日志投影;分类使用与 model-history 推导相同的 `foldSurface()` 状态转换。 ```ts type-equiv -export type SessionEventSurface = 'current' | 'shadowed' | 'log-only' +/** Whether an event is current model context, replaced context, or raw-log-only. */ +type SessionEventSurface = 'current' | 'shadowed' | 'log-only' ``` ```ts type-equiv -export interface SessionRecord { +/** Lightweight identity and source availability for one logical session. */ +interface SessionRecord { + /** Cloned session header selected from the live-preferred corpus. */ header: SessionHeader + /** Whether the id currently exists in `ctx.sessions`. */ live: boolean + /** Whether the active persistence backend currently materializes the id. */ persisted: boolean } ``` ```ts type-equiv -export interface SessionEventRecord { +/** Lightweight metadata for one event within a logical session. */ +interface SessionEventRecord { + /** Session that owns the event. */ sessionId: SessionId + /** Monotonic event seq within the session. */ seq: number + /** Discriminant of the session event. */ type: SessionEventType + /** Event timestamp in Unix epoch milliseconds. */ time: number + /** Event placement in the folded session surface. */ surface: SessionEventSurface } ``` +## Session 谱系 + +`SessionLineageTrace` 按由近及远的顺序携带已知 parent,并携带一片由直接 descendant 递归嵌套而成的森林。完整性判别字段使已知 root 与缺失 parent 互斥。 + +```ts type-equiv +/** Recursive descendant node in a session-lineage trace. */ +interface SessionLineageNode { + /** Detached logical-corpus record for this descendant. */ + session: SessionRecord + /** Direct children, each carrying its own recursive descendants. */ + descendants: SessionLineageNode[] +} +``` + +```ts type-equiv +/** Known ancestry and descendants for one logical session. */ +type SessionLineageTrace = { + /** Detached record for the session that was traced. */ + target: SessionRecord + /** Known parents from the immediate parent outward. */ + ancestors: SessionRecord[] + /** Complete known descendant trees rooted at the target's direct children. */ + descendants: SessionLineageNode[] +} & ( + | { + /** The complete parent chain is present in the logical corpus. */ + complete: true + /** Detached record at the top of the complete lineage. */ + root: SessionRecord + } + | { + /** The parent chain leaves the visible logical corpus. */ + complete: false + /** First parent id that is not present in the logical corpus. */ + unresolvedParentId: SessionId + } +) +``` + ## 有界事件读取 请求指定一个原始 seq 及可选的邻近数量。结果携带 `SessionHeader` 而非可用性标志,使已知的实时目标可以独立于持久化健康状态。 ```ts type-equiv -export interface SessionEventReadRequest { +/** Request for one event plus raw neighboring log context. */ +interface SessionEventReadRequest { + /** Session that owns the target event. */ sessionId: SessionId + /** Target event seq. */ seq: number + /** Number of preceding raw events to include. */ before?: number + /** Number of following raw events to include. */ after?: number } ``` ```ts type-equiv -export interface SessionEventWindow { +/** Full target event and a bounded raw-log window. */ +interface SessionEventWindow { + /** Cloned header for the live-preferred source read. */ session: SessionHeader + /** Full cloned target event. */ target: SessionEvent + /** Full cloned events from `startSeq` through `endSeq`. */ events: SessionEvent[] + /** First seq included in `events`. */ startSeq: number + /** Last seq included in `events`. */ endSeq: number } ``` +## 事件关系 + +事件追踪会区分位置性的 surface 替换与已记录 provenance。除 `replacementChain` 外,每个 seq 列表都包含直接链接;该链从目标沿直接 replacer 追踪到最终的位置替换。 + +```ts type-equiv +/** Request for direct surface and provenance relationships around one event. */ +interface SessionEventTraceRequest { + /** Session that owns the target event. */ + sessionId: SessionId + /** Target event seq. */ + seq: number +} +``` + +```ts type-equiv +/** Direct surface and provenance relationships for one event. */ +interface SessionEventTrace { + /** Lightweight target record. */ + target: SessionEventRecord + /** Immediate positional replacement event, when the target was shadowed. */ + replacedBy?: number + /** Positional replacers from the immediate replacement to the final replacement. */ + replacementChain: number[] + /** Surface nodes directly removed when the target itself performed a replacement. */ + replacedEventSeqs: number[] + /** Direct logged provenance sources in their recorded order. */ + sourceEventSeqs: number[] + /** Later events that directly name the target as a provenance source, in log order. */ + derivedEventSeqs: number[] +} +``` + ## 错误 封闭的 code 联合类型区分请求校验、目标缺失、surface 日志格式错误、可选后端故障与矛盾的源元数据。 ```ts type-equiv -export type SessionQueryErrorCode = +/** Stable machine-routable failure taxonomy for exact session reads and traces. */ +type SessionQueryErrorCode = | 'SESSION_QUERY_EVENT_NOT_FOUND' | 'SESSION_QUERY_INVALID_CONFIG' + | 'SESSION_QUERY_INVALID_LINEAGE' | 'SESSION_QUERY_INVALID_SURFACE' | 'SESSION_QUERY_INVALID_WINDOW' | 'SESSION_QUERY_PERSISTENCE_FAILED' diff --git a/docs/core-data-structures/session.i18n.yaml b/docs/core-data-structures/session.i18n.yaml index 33e1d86f7d..8f2f0b2f8a 100644 --- a/docs/core-data-structures/session.i18n.yaml +++ b/docs/core-data-structures/session.i18n.yaml @@ -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 -session.md: 796abebbc31a54c7c341028cf0a09031ae59cd78 -session.zh.md: 04bfe84f079762091e7c4a4d77db69c053e6ea30 +session.md: d3c6ab65df29ef0df504a0a01219e36ebad8e8fd +session.zh.md: 7d5e03f6b8d74e7b2dc0097acb1f5f78f6d3af6e diff --git a/docs/core-data-structures/session.zh.md b/docs/core-data-structures/session.zh.md index 04bfe84f07..7d5e03f6b8 100644 --- a/docs/core-data-structures/session.zh.md +++ b/docs/core-data-structures/session.zh.md @@ -11,30 +11,54 @@ 仅追加的事件类型。可通过声明合并扩展:插件通过 declaration merging 声明额外的事件类型。例如[上下文压缩(context compaction) seam](compaction.md) 添加了 `compact/start` / `compact/summary` / `compact/end`,`@deepseek-ai/dsh-hook-protocol` 添加了仅记录日志的 `hook/invoked` / `hook/result` 溯源事件,用于钩子桥接。与 `compact/*` 一样,这些都不是 `SurfaceEventType`(没有 `surfaceOp`)。生成的[持久化日志事件目录](../persistence-catalog.md)列举了所有成员(核心与合并扩展的),包含其 payload、surface 标记与声明位置。 ```ts type-equiv +/** + * The merge-extensible, append-only source of truth for an agent interaction. + * Message history is derived from this log. Every event is lossless JSON and + * sequence numbers stay contiguous, including raw chunks, so persistence can + * store the canonical log verbatim. + */ interface SessionEventMap { + /** + * Opens turn `turn`. `trigger` records what started it — one claimed queued + * message or an idle-time injection. The turn is the durability/replay + * boundary: every event sits between a `turn/start` and its matching + * `turn/end` (the turn-enclosure invariant). + */ 'turn/start': { turn: number; trigger: TurnTrigger } + /** + * Closes turn `turn` with the {@link TurnEndReason} that ended it. The loop + * awaits `session/flush` after an ordinary turn ends before claiming the next + * queued item. Success commits the turn; rejection is reported live and does + * not prevent later work. + */ 'turn/end': { turn: number; reason: TurnEndReason } + /** Opens step `step` of turn `turn` — one model call plus the tool executions it requested. */ 'step/start': { turn: number; step: number } + /** Closes step `step` of turn `turn`. */ 'step/end': { turn: number; step: number } - /** A user-visible prompt (queued message drained at turn start). */ + /** A user-visible prompt (the queued message claimed for this turn). */ 'user/message': { content: ContentBlock[]; source: MessageSource } /** - * A queued prompt an `agent/prompt-submit` listener VETOED — the durable - * record of a blocked prompt and why. Appended in place of the `user/message` - * the prompt would have become, so the block survives replay even in a MIXED - * batch where another queued prompt is allowed (there the turn does not end - * `rejected`, so the boundary reason alone would not preserve it). `content` - * is the original prompt the listener rejected; `reason` is the veto text - * ({@link PromptDecision} `block.reason`). NOT a {@link SurfaceEventType}: a - * blocked prompt produces no LLM message and never reaches `deriveMessages()`. + * Durable record of a prompt veto and its reason. It is log-only: the blocked + * prompt never enters the model-visible surface, and its turn runs zero steps. */ 'prompt/blocked': { content: ContentBlock[]; source: MessageSource; reason: string } /** * In-session context injection (file-change notices, subdir AGENTS.md, * skill content, cron notifications, …). Rendered into the derived history - * as tagged synthetic context — NOT a user prompt. + * as a synthetic user-role message carrying `content` verbatim — NOT a + * user prompt. `meta` is durable JSON state omitted from the model + * projection; it is also the intended channel for any future framing + * directive (a producer declares the frame, a dedicated renderer applies it — + * see the deferred note in + * ../../../../.agents/notes/implemented/simplification/2026-07-20-unwrap-injected-content-envelopes.md), + * so the surface keeps projecting `content` verbatim rather than wrapping it. */ - 'context/message': { content: ContentBlock[]; source: MessageSource } + 'context/message': { + content: ContentBlock[] + source: MessageSource + meta?: JsonValue + } /** Raw stream chunk — token-level replay fidelity. */ 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk } /** @@ -43,69 +67,85 @@ interface SessionEventMap { * the model output and its accounting travel together (there is no separate * usage record). `usage` is absent when the adapter reported none. */ - 'assistant/message': { turn: number; step: number; content: ContentBlock[]; usage?: TokenUsage } + 'assistant/message': { turn: number; step: number; content: ContentBlock[]; provenance: AssistantProvenance; usage?: TokenUsage } + /** + * The model requested one tool invocation: `name` with the raw `arguments` + * JSON string exactly as the model produced it (unparsed). `callId` pairs the + * call with its `tool/result`. + */ 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string } + /** + * A completed tool call's model-facing result, plus an optional tool-private + * `meta` presentation payload. `meta` is opaque to the core (`unknown` — the + * producing tool owns its shape and reads it back in `presentResult`) but MUST + * be JSON-serializable: `Session.append` runtime-validates all event data with + * `isJsonValue`, so a non-serializable `meta` is rejected at the source, and the + * durable log reproduces the identical card on replay. Absent unless the tool + * attaches one (e.g. `dsh-tool-fs` carries its result-time contextual diff here). + */ 'tool/result': { turn: number; step: number; callId: CallId; content: ContentBlock[]; isError: boolean; error?: { name: string; code: string }; meta?: unknown } /** Steering content injected between steps of a running turn. */ 'steering/message': { turn: number; content: ContentBlock[]; source: MessageSource } - /** - * The agent's whole todo list, carried as a full snapshot and replaced - * wholesale on each write — the current list is the most recent `todo/write` - * (last-write-wins on replay, no fold). Appended by an owning agent via - * `session.append('todo/write', { todos })`. - * - * NOT a {@link SurfaceEventType}: it produces no LLM message and never reaches - * `deriveMessages()`, so it carries no `surfaceOp` and stays off the surface — - * it is durable, replayable UI state, distinct from the conversation history. - * It is a `SessionEventMap` member riding the existing `session/event` emit, - * not a first-class Cordis `interface Events` notification, so it has no - * cordis-catalog row. - */ + /** Whole-list snapshot; latest write wins on replay. Log-only UI state; never derived history. */ 'todo/write': { todos: TodoItem[] } /** - * Full snapshot of the {@link EpochHeader} the NEXT request is built under, - * with the {@link RequestHeaderReason} it was recorded whole. Appended by - * the loop inside the step, before dispatch, on a loop instance's first - * request-building step (`'initial'`/`'resume'`) or when a delta failed its - * round-trip guard (`'fallback'`); always records what the request actually - * used, post-`agent/request`. Anchors the header fold: reconstruction reads - * the latest snapshot and applies the deltas after it. NOT a - * {@link SurfaceEventType}: it produces no LLM message — it is the request - * envelope, logged so every request is a pure function of the session log - * (the reconstructability RFC). + * Full header for the next request, appended inside its step before dispatch. + * It is log-only; the latest snapshot reconstructs the request header. */ 'request/header': { header: EpochHeader; reason: RequestHeaderReason } - /** - * Amendment to the folded {@link EpochHeader}: system line-trim, name-keyed - * tools delta, whole replacement config, or whole replacement session - * prefix (an EMPTY array encodes the transition to "none"). The - * writer verifies `applyHeaderDelta(previous, delta)` reproduces the new - * header exactly and falls back to a `'fallback'` `request/header` snapshot - * when it cannot, so a logged delta ALWAYS round-trips. NOT a - * {@link SurfaceEventType}. - */ - 'request/header-delta': { system?: SystemDelta; tools?: ToolsDelta; config?: LlmCallConfig; messagePrefix?: Message[] } } ``` +### `OutOfBandSessionEventMap`:受限的带外追加显式准入 + +仅属于 `SessionEventMap` 并不表示事件可以脱离 agent loop 的常规生命周期追加。事件所有方必须通过声明合并将同一键加入这个空标记映射,`ctx.sessions.appendOutOfBand()` 才会接受该事件;派生类型还会排除所有 surface 事件。被接受的更新会并入已打开的轮次;如果没有打开的轮次,系统则为它创建一个边界配平且已刷新完成的零步骤轮次。 + +```ts type-equiv +/** + * Marker map for plugin-owned log-only events accepted by + * `SessionStore.appendOutOfBand()`. A plugin extends this map with the same key + * it adds to {@link SessionEventMap}; surface and lifecycle events stay + * ineligible unless their owner explicitly opts them into this narrow seam. + */ +interface OutOfBandSessionEventMap {} +``` + ### `TodoItem`:一条待办项 -`todo/write` 事件全量快照的单元。刻意保持精简:一行 `content` 加一个三态 `status`(无 id、无优先级、无 `activeForm`)。列表在每次写入时整体替换,因此条目不需要稳定标识;三态 status 恰好是 ACP(Agent Client Protocol)的 `PlanEntryStatus`,UI 桥接层可以将待办列表 1:1 映射到 ACP `plan`(再合成 ACP 额外要求的优先级)。见 [todo_write RFC](../rfc/implemented/feature/2026-06-29-todo-write-tool.md)。 +这是 `todo/write` 事件全量列表快照中的单元。它有意保持精简:一行 `content` 加一个三态 `status`(没有 id、优先级或 `activeForm`);列表在每次写入时整体替换,因此条目无需稳定标识,而这三个状态值恰好对应 ACP 的 `PlanEntryStatus`,所以 UI 桥接层可以将待办列表一一映射为 ACP `plan`(并合成 ACP 额外要求的优先级)。见 [todo_write Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-06-29-todo-write-tool.md)。 ```ts type-equiv -export interface TodoItem { +/** + * One entry in an agent's todo list — the unit of the `todo/write` + * {@link SessionEventMap} event's whole-list snapshot. + * + * Deliberately minimal: a human-readable `content` line and a three-state + * `status`. No id, priority, or `activeForm` — the list is replaced wholesale + * on every write (last-write-wins), so entries need no stable identity, and the + * status triple is exactly the ACP `PlanEntryStatus`, so a UI bridge can map a + * todo list onto an ACP `plan` 1:1 (synthesizing the priority ACP additionally + * requires). + */ +interface TodoItem { + /** What this task is — a short imperative line shown in the UI. */ content: string + /** Lifecycle state. `in_progress` marks the single task being worked now. */ status: 'pending' | 'in_progress' | 'completed' } ``` -### 请求头事件:`request/header` 与 `request/header-delta` +### 请求头事件:`request/header` -请求信封(`EpochHeader`:调用配置 + 渲染后的系统提示词 + 组装好的工具 schema + 会话前缀)是被记录到日志中的会话状态,使得每次对话请求都是日志的纯函数(可重建性 RFC)。`request/header` 快照(reason 为 `'initial' | 'resume' | 'fallback'`)在对话诞生、进程边界和 delta 编码回退时锚定折叠点;`request/header-delta` 事件在运行中修正它。`foldRequestHeader(events)` 可重建任一请求构建时所用的 header;写入器在记录每个 delta 前都会做往返验证,因此格式正确的日志总能折叠。两者都不是 `SurfaceEventType`,不产生 LLM 消息。 +请求信封(即 `EpochHeader`:调用配置 + 渲染后的系统提示词 + 已组装的工具 schema + 会话前缀)会作为会话状态写入日志,因此每个对话请求都是日志的纯函数(见可重建性 Agent Note)。带有 reason `'initial'` 或 `'resume'` 的完整 `request/header` 快照记录每个 agent loop 实例的边界;之后请求发生变化时,系统会以 reason `'change'` 记录另一份完整快照。`foldRequestHeader(events)` 通过选择最新快照重建请求头。该事件不是 `SurfaceEventType`,不产生 LLM 消息。 ```ts type-equiv -export interface EpochHeader { - /** The conversation's call configuration (model + sampling scalars). */ +/** + * Logged request state outside derived history: call config, system prompt, + * tools, and prefix. The latest full `request/header` snapshot reconstructs it; + * canonical empty optional fields are absent. + */ +interface EpochHeader { + /** The conversation's call configuration (provider, model, and sampling scalars). */ config: LlmCallConfig /** Rendered system prompt text; absent for a system-less request. */ system?: string @@ -122,13 +162,26 @@ export interface EpochHeader { } ``` -规范形式:空的系统提示词、空的工具列表和空的会话前缀均为 ABSENT 字段,与请求构建方式一致。`messagePrefix` 是 `agent/session-prefix` waterfall(瀑布式事件)产物的持久记录(请求 = `messagePrefix + derived history`);每个 agent loop(智能体循环)实例组合一次,由该实例的快照锚定,因此实际上 loop 不会产生前缀 delta。delta 分支(整数组替换,空数组编码「回到无前缀」的转换)存在是为了编解码的完备性。其他 delta payload(`SystemDelta`:公共前缀/后缀行裁剪;`ToolsDelta`:按名称键控的增/删/改)与事件一起定义在 [`packages/core/session/src/types.ts`](../../packages/core/session/src/types.ts)。 +规范形式:空系统提示词、空工具列表和空会话前缀都表示为字段缺失,与请求构建方式一致。`messagePrefix` 是 `agent/session-prefix` waterfall(瀑布式事件)产物的持久记录(请求 = `messagePrefix + derived history`);每个 agent loop(智能体循环)实例只组合一次,并包含在该实例记录的每份完整快照中。包含已移除的 `request/header-delta` 事件或完整快照原因为 `fallback` 的旧版 v0 日志,会在 seed、append 和持久化加载边界被拒绝,而不会以不完整方式回放。 ## `SessionEvent<T>`:一条日志条目 基于 `type` 的真正可辨识联合(而非独立的 `type`/`data` 联合),因此 `switch (event.type)` 能直接收窄 `event.data`,无需类型断言。`seq` 是日志中的单调递增位置(`seq = log.length`);`time` 为 epoch 毫秒。 ```ts type-equiv +/** + * One immutable entry in the session log. + * + * A proper discriminated union over `type` (not independent `type`/`data` + * unions), so `switch (event.type)` narrows `event.data` without casts. + * + * The {@link sourceEventSeqs} and {@link surfaceOp} fields are conditional: + * they only exist on {@link SurfaceEventType} variants (`user/message`, + * `assistant/message`, `tool/result`, `context/message`, `steering/message`). + * Non-surface events (boundary markers, chunks, usage, errors) never carry + * surface metadata — the compiler enforces this at `Session.append()` + * call sites. + */ type SessionEvent<T extends SessionEventType = SessionEventType> = { [K in SessionEventType]: { type: K @@ -141,7 +194,9 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = { /** * Seq numbers of events that are provenance sources of this event * (e.g. the `assistant/chunk` seqs that built an `assistant/message`, - * or the surface nodes shadowed by a compaction replace node). + * or the surface nodes shadowed by a compaction replace node). An + * `assistant/message` may carry a present empty array for a known empty + * provider stream; omission means unrecorded provenance. */ sourceEventSeqs?: number[] /** How this event entered the surface; absent for non-surface events. */ @@ -152,14 +207,21 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = { `SessionEventType = keyof SessionEventMap`。由于 `SessionEventMap` 可通过合并扩展,对 `SessionEvent` 的 switch 语句禁止使用 `assertNever`:插件添加的变体是合法的未知值;处理已知 case 后在 `default` 中放行。 +对于 `assistant/message`,存在的 `sourceEventSeqs: []` 表示提供方流已知且完整地为空;字段缺失则表示旧格式或其他未记录溯源信息的情况。agent loop 会为每次成功的模型调用写入该字段;其他 surface 事件只要包含该字段,其列表就必须非空。 + ## Surface 类型 -五种产生消息的类型(`SurfaceEventType`:`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`)携带 surface 元数据,声明它们如何加入派生的 surface 链表。见 [session surface RFC](../rfc/implemented/architecture/2026-06-18-session-surface.md)。 +五种产生消息的类型(`SurfaceEventType`:`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`)携带 surface 元数据,用来声明它们如何加入有序的派生 surface。见 [session surface Agent Note](../../.agents/notes/implemented/architecture/2026-06-18-session-surface.md)。 ### `SurfaceEventType`:事件类型中产生消息的子集 ```ts type-equiv -export type SurfaceEventType = +/** + * The subset of {@link SessionEventType} values whose events produce LLM + * messages and are eligible to appear on the ordered surface. Only these + * event types may carry {@link SurfaceOp} and {@link SessionEvent.sourceEventSeqs}. + */ +type SurfaceEventType = | 'user/message' | 'assistant/message' | 'tool/result' @@ -170,64 +232,221 @@ export type SurfaceEventType = ### `SurfaceOp`:事件如何进入 surface ```ts type-equiv -export type SurfaceOp = +/** + * How a session event entered the ordered surface. Only valid on + * {@link SurfaceEventType} events. + * + * - `'append'`: added to the tail — normal path for user/assistant/tool/context + * messages. + * - `{ op: 'replace', start, end }`: replaces surface nodes from `start` + * (inclusive) through `end` (inclusive) with this node. Both must exist as + * surface nodes in the current surface. `start === end` replaces a single + * node. The node's {@link SessionEvent.sourceEventSeqs} must include every + * shadowed surface node. Used by compaction and possible other manipulations. + */ +type SurfaceOp = | 'append' | { op: 'replace'; start: number; end: number } ``` -`'append'` 是正常的尾部追加路径。`replace` 遮蔽从 `start` 到 `end`(含两端)的 surface 节点(两者都必须是有效的 surface 节点 seq;`start === end` 时只替换一个节点),并在其位置插入新节点。 +`'append'` 是常规的尾部追加路径。`replace` 会遮蔽从 `start` 到 `end`(含两端)的 surface 条目(两者都必须是有效的 surface seq;`start === end` 时仅替换单个条目),并在原位置插入新事件。 ### `SurfaceIntent`:`session.append()` 的参数 ```ts type-equiv -export interface SurfaceIntent { +/** + * Surface placement and provenance for {@link Session.append}. Required on + * message-producing events and forbidden on log-only events. + */ +interface SurfaceIntent { surfaceOp: SurfaceOp + /** + * Complete known provenance source set. `assistant/message` may use a + * present empty array for a known empty provider stream; omission means its + * provenance was not recorded. Other surface events require a non-empty set + * when this field is present. + */ sourceEventSeqs?: number[] } ``` 对 `SurfaceEventType` 事件必填:每个产生消息的事件都必须声明它如何加入 surface(派生历史的唯一来源)。非 surface 类型在编译期拒绝此参数。 -### `SurfaceNode`:surface 链表中的一个节点 +此处适用相同的溯源区分:只有 `assistant/message` 可以携带存在但为空的 `sourceEventSeqs`;省略该字段并不表示其源流为空。 + +### `SessionSurface`:实时只读 surface 投影 + +`Session.surface` 返回会话稳定的 `SessionSurface` 视图。同一个增量管理器在提交前校验追加候选事件,并根据已提交事件推进该投影;调用方可以观察成员关系和替换代次,但不能调用校验。 ```ts type-equiv -export interface SurfaceNode { - seq: number - prev: number | null - next: number | null +/** Readonly live projection of the message-producing session events. */ +interface SessionSurface { + /** Current surface event sequences in model-visible order. */ + readonly nodes: readonly number[] + /** Monotonic count of committed positional replacements. */ + readonly replaceGeneration: number } ``` ### `SurfaceFoldReplacement` 与 `SurfaceFoldResult`:完整的 surface 回放 -`foldSurface(events)` 返回当前分离的节点,以及每个声明的替换范围实际遮蔽的节点 seq。`SurfaceManager` 对其增量缓存使用相同的转换函数。 +`foldSurface(events)` 返回一份独立的当前事件 seq 列表,以及每个声明的替换范围实际遮蔽的 seq。实时管理器复用同一套状态转换,但不保留替换历史。每提交一次替换,其 `replaceGeneration` 就递增一次,使增量消费方能够区分纯尾部增长与重写。 ```ts type-equiv -export interface SurfaceFoldReplacement { +/** One replacement operation observed while folding a session surface. */ +interface SurfaceFoldReplacement { + /** Seq of the event that replaced the prior surface range. */ seq: number + /** Declared inclusive start seq of the replaced surface range. */ start: number + /** Declared inclusive end seq of the replaced surface range. */ end: number + /** Actual surface entries removed by the operation, in surface order. */ shadowedSeqs: number[] } ``` ```ts type-equiv -export interface SurfaceFoldResult { - nodes: SurfaceNode[] +/** Complete result of replaying the surface operations in a session log. */ +interface SurfaceFoldResult { + /** Current surface event sequences in model-visible order. */ + nodes: number[] + /** Replacement operations in event order. */ replacements: SurfaceFoldReplacement[] } ``` +## `Session` public API + +去除方法体的声明与源码中的普通类保持同步,覆盖其公共构造函数、状态访问器、追加边界和历史投影。存储操作仍由生成的 [`ctx.sessions` 服务目录](../cordis-catalog/services.md#ctxsessions--sessionstore)记录。 + +```ts public-api +/** + * An event-sourced session: an append-only log of {@link SessionEvent}s. + * + * Plain class (not a Service) — create instances via `ctx.sessions.create()`. + * Seeding with an existing event log replays/forks a session. + */ +declare class Session { + /** The ordered surface over this session's event log. */ + get surface(): SessionSurface; + /** + * Detached, deep-frozen creation metadata (format version, cwd, lineage, + * seed boundary). Supplied by the store via `ctx.sessions.create()`. When a + * `Session` is constructed bare (tests, ad-hoc replay), a minimal header is + * synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so + * `session.header` is always present. Kept out of the event log — it is a + * storage concern, not replayable conversation state. + */ + readonly header: SessionHeader; + /** The session identity, derived from its durable header's single copy. */ + get id(): SessionId; + constructor(id: SessionId, seed?: readonly SessionEvent[], header?: SessionHeader); + /** + * An immutable snapshot of the append-only event log. The snapshot is reused + * until the next append; a previously returned array does not grow later. + * Events and their nested data are deep-frozen at acceptance, so neither a + * cast nor ordinary JavaScript can rewrite durable history. + */ + get events(): readonly SessionEvent[]; + /** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */ + get seq(): number; + /** + * Append one typed event to the log and synchronously notify observers via + * the store-owned, module-private publication hooks. The hot path never blocks + * on I/O — persistence plugins buffer asynchronously. Once the event enters + * the log, the append is committed: observer failures are logged and + * contained per listener, so they do not change the return value or prevent + * later listeners from observing the same accepted event. + * + * @param type - The event type (key of {@link SessionEventMap}). + * @param data - The event payload; must be JSON-serializable. + * @param opts - Surface metadata: `surfaceOp` controls how the event enters + * the ordered surface; `sourceEventSeqs` records provenance (the seq + * numbers of events this one derives from). REQUIRED for + * {@link SurfaceEventType} events (every message-producing event must + * declare how it joins the surface, the sole source of derived history) and + * rejected by the compiler for non-surface types like `turn/start` or + * `assistant/chunk`. + * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of + * `data` that entered the log, so reading `event.data` back sees the logged + * value, never the caller's still-mutable input. + * @throws if `data` or surface metadata is not losslessly JSON-serializable + * (BigInt, function, symbol, undefined, negative zero, non-finite number, + * circular reference, sparse array, or an exotic object such as + * Map/Set/Date/class instance), or when the candidate violates the + * canonical surface contract (marker shape and eligibility, unique + * earlier provenance, positional replacement validity, and complete + * shadowed-node coverage). One recursive pass reads, validates, and + * copies each nested value once, so a stateful getter cannot supply one value + * to validation and another to storage. The event log is the durable source + * of truth, so a bad event fails at the append site rather than later during + * a backend flush. A synchronous internal dispatch validation failure or an + * append reentered while this acceptance/publication boundary is open also + * rejects before the log changes. + */ + append<T extends SessionEventType>( + type: T, + data: SessionEventMap[T], + ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent] : [] + ): SessionEvent<T>; + /** + * The {@link EpochHeader} in force after the log's last header event — the + * header the NEXT request will be compared against — or undefined before + * the first `request/header` snapshot. The live, incrementally-maintained + * form of `foldRequestHeader(session.events)`: each header event is folded + * once, when first seen, so a per-step read costs O(new events). + * @returns the folded header, or undefined when no header event exists yet. + */ + requestHeader(): EpochHeader | undefined; + /** + * Derive the LLM message history by walking the ordered sequences of + * message-producing events maintained by `surfaceOp` markers. The + * surface is the single source of derived history: every message-producing + * append records its `surfaceOp`, so a raw event with no marker (a chunk, a + * turn boundary) is correctly absent, and a compaction `replace` deletes the + * shadowed nodes from the derivation. The projection rules are + * {@link deriveEventMessage}, folded per node. + * + * CACHED: each surface node is projected exactly once, when first seen — a + * call costs O(new nodes), and a surface rewrite (a `replace`; + * {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is + * a fresh snapshot per call (later appends never grow an array a caller + * already holds); the `Message` objects in it are SHARED and **deep-frozen**. + * Their content reuses the already frozen durable event data, so the cache + * needs no second deep clone and consumers still cannot mutate the log. + * @returns a fresh array of the shared, frozen derived history. + */ + deriveMessages(): Message[]; + /** + * Project a single event into the LLM message it derives to, or null when + * it produces none — a non-surface event (chunk, boundary, log-only record) + * or an empty-content assistant/message (which exists only to host usage). + * The per-node pure function {@link deriveMessages} folds over the surface; + * an external reconstructor (or the dev invariant) folds the same function + * over a log prefix's surface to rebuild the exact messages any request was + * built from (the reconstructability Agent Note). The returned message wrapper is + * fresh; its content reuses the logged event's already deep-frozen durable + * data, so changing the wrapper cannot rewrite the log and changing content + * throws. + * @param event - the event to project. + * @returns the derived message, or null when the event produces none. + */ + deriveEventMessage(event: SessionEvent): Message | null; +} +``` + ## 派生历史:`deriveMessages()` 与 `deriveEventMessage()` `Session.deriveMessages()` 将事件日志投影为模型看到的 `Message[]`。它是缓存的(每个 surface 节点在首次出现时投影一次;surface 重写触发重建)且冻结的(每次调用返回一个新数组,引用共享的深冻结消息,因此通过投影修改已记录的历史在类型上不可表达)。`deriveEventMessage(event)` 是折叠所应用的逐节点纯函数,公开暴露以便外部重建器和开发不变式检查能以完全相同的规则投影日志前缀,不会与缓存产生分歧。投影规则: - `user/message` → 一条 user 消息。 -- `assistant/message` → 一条 assistant 消息。原始 `assistant/chunk` 事件是回放/UI 数据,在派生中被**跳过**(组装后的消息才是权威的)。**空内容**的 `assistant/message` 也被跳过:一个因 max-tokens 截断且无内容的步骤仍会记录 `assistant/message` 以承载其 `usage`,但无内容的 assistant 轮次不得进入提供方的 transcript(文本记录)。 +- `assistant/message` → 一条 assistant 消息,包含事件的提供方/模型溯源信息和可选的适配器私有回放状态。原始 `assistant/chunk` 事件属于回放/UI 数据,在派生时会被**跳过**(组装后的消息才是权威)。**内容为空的** `assistant/message` 也会跳过:因 max-tokens 而截断且无内容的步骤仍会记录一条 `assistant/message` 以承载用量和溯源信息,但无内容的 assistant 轮次不得进入提供方 transcript(文本记录)。 - `tool/result` → 一条携带 `tool-result` 块的 user 消息。 -- `context/message`、`steering/message` → 以 user 角色、按时间顺序插入的消息,包裹在标记信封中(`<context source="…">…</context>`),即「系统提醒」模式;模型通过信封区分它们与真实提示词。 +- `context/message` → 按时间顺序在相应位置生成一条 user-role 消息,并原样承载其 `content`。可选的 JSON `meta` 保留在事件日志中,绝不渲染。 +- `steering/message` → 按时间顺序在相应位置生成一条 user-role 消息,并原样承载其内容。 -其他一切(`turn/*`、`step/*`)是结构性事件,不投影为消息。token 用量通过 `assistant/message.usage` 观察(产生该用量的步骤);操作错误的步骤号在 `turn/end.reason` 中(`kind: 'error'` 时)。 +其余所有事件(`turn/*`、`step/*`、插件所有的 `llm/retry`)均为结构信息,不会投影为消息。token 记账读取每个步骤的 `assistant/chunk { type: 'usage' }` 记录;如果没有用量分片,则将 `assistant/message.usage` 作为已提交步骤的后备。失败的模型请求尝试没有 assistant 消息,因此其用量分片是持久化的记账记录。操作错误的步骤号记录在 `turn/end.reason`(`kind: 'error'`)中;如果是最终模型请求失败,其中包含规范化的 `LlmFailure` 事实,其他实时错误则包含消息/代码。由于这一尚未发布的格式有意不提供兼容性承诺,seed/load 校验会拒绝缺少提供方和模型的请求头,以及缺少提供方/模型溯源信息的 assistant 消息,而不会猜测历史数据应走的提供方路由。 ## 活跃会话 fork API @@ -240,6 +459,10 @@ export interface SurfaceFoldResult { ## 轮次的触发原因:`TurnTriggerMap` ```ts type-equiv +/** + * What started a turn. + * Merge-extensible sum type (same pattern as MessageSourceMap). + */ interface TurnTriggerMap { message: { kind: 'message'; source: MessageSource } /** @@ -256,57 +479,57 @@ interface TurnTriggerMap { ## 轮次的结束原因:`TurnEndReasonMap` +`aborted` 有意作为一种粗粒度的持久结果:它只记录取消中断了实时轮次,不记录是哪个运行时调用方发起取消。仅属于运行时的调用方词汇由 [`AgentCancelCause`](core.md#the-agent-handle) 定义;未来若有审计需求,应新增独立的控制请求事件,而非让终止结果承载这一信息。 + ```ts type-equiv +/** + * Why a turn ended. Merge-extensible sum type. + */ interface TurnEndReasonMap { completed: { kind: 'completed' } - aborted: { kind: 'aborted'; reason?: string } + /** A cancellation request interrupted the live turn. */ + aborted: { kind: 'aborted' } /** * The turn failed: a step threw or the model reported a failure. `step` is the * step number the failure occurred on (the operational error's location — the * single durable record of an in-turn failure; live diagnostics also fire via - * `agent/error`). `code` is the error's code when one was attached. + * `agent/error`). Final model-request failures retain their normalized facts + * as one `failure`; other turn failures retain their live Error message/code. */ - error: { kind: 'error'; step: number; message: string; code?: string } + error: { kind: 'error'; step: number } & ( + | { failure: LlmFailure; message?: never; code?: never } + | { message: string; code?: string; failure?: never } + ) disposed: { kind: 'disposed' } + /** At least one step reached its output-token ceiling, even if a plugin continued the turn. */ 'max-tokens': { kind: 'max-tokens' } /** - * The turn's entire prompt batch was BLOCKED before any step ran — every - * drained queued message was vetoed by an `agent/prompt-submit` listener (a - * hook). The turn still opened (so the boundary stays balanced and the block - * is a durable in-turn fact), but ran zero steps. `reason` carries the block - * message from the vetoing decision. Distinct from `aborted` (a user-driven - * cancel) and `error` (a failure): the prompt was rejected by policy, not - * interrupted or broken. A UI renders it as "prompt blocked by hook". + * Policy blocked the turn's claimed prompt before the first step. The + * zero-step turn still records a balanced durable boundary and veto reason. */ rejected: { kind: 'rejected'; reason: string } /** - * The turn never ended on its own: the process crashed mid-turn and a - * persistence backend later closed the orphaned (open) turn on reload so the - * log stays balanced. SYNTHESIZED by the backend's crash-recovery repair — no - * loop ever emits this. Its events are real (they were durably appended before - * the crash) and are PRESERVED, not discarded: a single turn can be huge in a - * long-horizon task (many steps, large tool output), so truncating it would - * lose real work. The marker records that the turn was cut short, not that the - * model completed it. See the session-persistence RFC. + * A persistence backend closed a crash-orphaned turn on reload. The loop never + * emits this marker, and the events recorded before the crash remain intact. */ interrupted: { kind: 'interrupted' } } ``` -`max-tokens` 对应同名的模型调用 `FinishReason`:轮次中任何一个步骤出现 `max-tokens`,整个轮次就以 `max-tokens` 结束而非 `completed`(截断事实优先于后续的继续),消费方据此区分正常停止与被截断的情况。但这仅相对于 `completed` 而言:`disposed`/`aborted`/`error` 结果优先级更高。`rejected` 是一个零步骤轮次,其整批提示词被 `agent/prompt-submit` 钩子阻止(ACP 桥接层将其映射为 `cancelled`)。`interrupted` 是唯一不由 loop 发出的原因,由崩溃恢复合成(见 [persistence.md](persistence.md))。两个 map 均可通过合并扩展。 +`max-tokens` 与模型调用中同名的 `FinishReason` 对应:只要轮次内有任何步骤以 `max-tokens` 结束,整个轮次就以 `max-tokens` 而不是 `completed` 结束(即使之后继续执行,截断事实仍优先),让消费方能够区分正常停止和截断停止;但它只优先于 `completed`,`disposed`/`aborted`/`error` 结果的优先级更高。`rejected` 表示一个零步骤轮次,其已认领的提示词被 `agent/prompt-submit` 钩子阻止(ACP 桥接层将其映射为 `cancelled`)。`interrupted` 是唯一不会由任何 loop 发出的原因:它由崩溃恢复合成(见 [persistence.md](persistence.md))。两个 map 均可通过合并扩展。 ## 轮次封闭不变式 -每个会话事件都存在于一个轮次**内部**(位于 `turn/start` 与其对应的 `turn/end` 之间)。loop 在 `turn/start` *之后*追加排队的 `user/message` 事件;空闲时的 `agent.inject()` 将其 `context/message` 包裹在一个一次性的 `injection` 轮次中。这使得轮次成为唯一的持久性/回放边界:后端可以将最后一个 `turn/end` 之后的任何内容视为中断崩溃的尾部,而不会误丢合法记录的轮次间上下文。`dsh-invariants` 插件在开发环境中强制执行此不变式(在无打开轮次时追加消息事件会抛出异常)。见[轮次封闭不变式 RFC](../rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md)。 +每个会话事件都位于一个轮次**之内**(在 `turn/start` 和对应的 `turn/end` 之间)。loop 在 `turn/start` *之后*追加已排队的 `user/message` 事件;空闲时的 `agent.inject()` 会用一次性的 `injection` 轮次包住其 `context/message`;没有打开的轮次时,`appendOutOfBand()` 同样会用一个轮次包住符合条件的仅日志事件。这使轮次成为唯一的持久性/回放边界:后端可以将最后一个 `turn/end` 之后的任何内容视为崩溃中断尾部,而不会丢失合法记录在轮次之间的上下文。可选的 `dsh-session/invariant` 配套插件通过 `ctx.invariants` 在开发环境中强制此不变式(消息事件若位于打开的轮次之外便会抛出)。见[轮次封闭不变式 Agent Note](../../.agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.md)。 ## 插件贡献的仅日志事件 插件可以通过 declaration merging 添加额外的 `SessionEventMap` 类型。这些是**仅日志**事件:不是 `SurfaceEventType`(不携带 `surfaceOp`,不参与派生历史),但与所有事件一样,必须位于一个打开的轮次内。完整的逐事件枚举(核心与插件贡献的,含 payload 与溯源信息)见生成的[持久化日志事件目录](../persistence-catalog.md);压缩 seam 的 `compact/*` 语义在 [compaction.md](compaction.md) 中讨论。 -钩子桥接的 `hook/invoked` / `hook/result` 溯源对(来自 `@deepseek-ai/dsh-hook-protocol`)通过 `handlerId` 关联。轮次中的钩子点(`PreToolUse`/`PostToolUse`/`UserPromptSubmit`/`Stop`)在 loop 打开的轮次内触发,因此其 `hook/*` 记录天然满足轮次封闭。`SessionStart` 不产生 `hook/*` 记录(其注入的 `context/message` 就是持久证据),因为它没有打开的轮次来容纳记录(见[钩子桥接 RFC](../rfc/implemented/feature/2026-06-30-hook-bridges.md))。 +钩子桥接层的 `hook/invoked` / `hook/result` 溯源对(来自 `@deepseek-ai/dsh-hook-protocol`)通过 `handlerId` 关联。轮次中间的钩子点(`PreToolUse`/`PostToolUse`/`UserPromptSubmit`/`Stop`)在 loop 已打开的轮次内触发,因此其 `hook/*` 记录天然位于轮次之内。`SessionStart` 不生成 `hook/*` 记录:它注入的 `context/message` 已是持久证据,而且当时没有已打开的轮次可容纳该记录(见[钩子桥接 Agent Note](../../.agents/notes/implemented/feature/2026-06-30-hook-bridges.md))。 ## 持久性契约 -持久化后端所依赖的约定:持久日志逐字保存每个事件,**包括** `assistant/chunk`。`seq` 必须保持连续,因此不能从规范日志中过滤掉 chunk。所有 `event.data` 必须可 JSON 序列化;`Session.append` 在源头强制执行此约束(对不可序列化的数据抛出异常),因此坏事件永远不会进入日志,`session.events` 始终等于后端能持久化的内容。添加一个携带不可序列化数据的事件类型,或破坏不变式插件所检查的 turn/step 嵌套结构,都是对磁盘格式的破坏性变更。 +持久化后端依赖的契约如下:持久日志原样保存每个事件,**包括** `assistant/chunk`;`seq` 必须连续,因此不能从规范日志中过滤分片。所有 `event.data` 都必须可序列化为 JSON;`Session.append` 会从源头强制这一要求(遇到不可序列化数据时抛出),因此错误事件绝不会进入日志,`session.events` 始终与后端可持久化的内容一致。新增携带不可序列化数据的事件类型,或破坏会话不变式配套插件所检查的轮次/步骤嵌套,会构成磁盘格式的破坏性变更。 消费此契约的后端见 [persistence.md](persistence.md)。 diff --git a/docs/core-data-structures/skills.i18n.yaml b/docs/core-data-structures/skills.i18n.yaml index 32c97d6b0a..e71bfaa45c 100644 --- a/docs/core-data-structures/skills.i18n.yaml +++ b/docs/core-data-structures/skills.i18n.yaml @@ -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 -skills.md: b0a847cec05651b63e63de96423170a0fd7ca2a9 -skills.zh.md: 201bf53e95b5cbf5f8873217acca3c478cf30860 +skills.md: fc9599713dcfddec9719ed746b66ea0217b86cf5 +skills.zh.md: ef67f06b69ac321d1d8bea4ef962a9ac4f6be2dd diff --git a/docs/core-data-structures/skills.zh.md b/docs/core-data-structures/skills.zh.md index 201bf53e95..ef67f06b69 100644 --- a/docs/core-data-structures/skills.zh.md +++ b/docs/core-data-structures/skills.zh.md @@ -13,9 +13,25 @@ 重名按 rank、提供方顺序、本地顺序依次解决;摘要按名称排序。`list()` 拒绝时记录日志并跳过,不缓存降级后的目录;格式错误的候选项快速失败。 ```ts type-equiv +/** Provider interface for one source of skills, such as local directories or a remote registry. */ interface SkillProvider { + /** Unique provider name in the `ctx.skills` registry. */ readonly name: string + /** + * List available skill candidates for the current lookup context. Provider + * plugins register synchronously during `apply()`; remote initialization, + * authentication, and discovery are awaited inside this method. Implementations + * should settle promptly when `options.signal` aborts. + * @param options - lookup options; `cwd` selects workspace-sensitive skills and `signal` cancels work. + * @returns provider candidates with precedence ranks and opaque locators. + */ readonly list: (options: SkillLookupOptions) => Promise<readonly SkillCandidate[]> + /** + * Load a complete skill body for a previously listed candidate. + * @param candidate - the winning candidate originally returned by this provider. + * @param options - lookup options; `cwd` selects workspace-sensitive skills and `signal` cancels work. + * @returns the full skill body, or `undefined` if it is no longer loadable. + */ readonly get: (candidate: SkillCandidate, options: SkillLookupOptions) => Promise<SkillDefinition | undefined> } ``` @@ -39,6 +55,7 @@ interface SkillProvider { skill 名称为 kebab-case(`^[a-z0-9]+(?:-[a-z0-9]+)*$`)。本地提供方接受目录包(`<name>/SKILL.md`)和扁平 Markdown 文件(`<name>.md`)。嵌套递归的 `**/SKILL.md` 发现有意不在 v1 范围内。 ```ts type-equiv +/** Origin bucket for a skill contribution. The value is prompt-visible metadata, not precedence by itself. */ type SkillSource = 'project-dsh' | 'project-agents' | 'runtime' | 'user-dsh' | 'user-agents' | 'custom' | (string & {}) ``` @@ -47,13 +64,21 @@ type SkillSource = 'project-dsh' | 'project-agents' | 'runtime' | 'user-dsh' | ' `SkillSummary` 是注册表中可供模型调用的摘要形状。消费方自行选择渲染哪些字段;会话目录仅使用 `name` 和 `description`,从不使用 body 或绝对文件路径。`disableModelInvocation` 将 skill 从模型列表中隐藏,但允许受信代码按名称加载。 ```ts type-equiv +/** Model-visible skill metadata returned by `ctx.skills.list()` and rendered into request guidance. */ interface SkillSummary { + /** Kebab-case identifier used with the `skill` tool. */ readonly name: string + /** Short routing description shown to the model. */ readonly description: string + /** Optional extra routing guidance shown to the model. */ readonly whenToUse?: string + /** Whether the skill is hidden from model listings while remaining loadable by trusted callers. */ readonly disableModelInvocation?: boolean + /** Discovery source that produced this winning skill. */ readonly source: SkillSource + /** Provider that owns this skill body. */ readonly provider: string + /** Provider-specific base for relative resources. */ readonly resourceBase?: SkillResourceBase } ``` @@ -61,10 +86,15 @@ interface SkillSummary { `SkillCandidate` 是提供方到注册表的形状。`locator` 是提供方的不透明状态;注册表只存储它并在调用获胜提供方的 `get()` 时传回。 ```ts type-equiv +/** Provider catalog entry used by the registry to merge and later load skills. */ interface SkillCandidate extends SkillSummary { + /** Lower ranks win duplicate skill names before provider registration order is considered. */ readonly rank: number + /** Opaque provider-owned handle passed back to `provider.get()`. */ readonly locator: unknown + /** Absolute file path when the provider has one. */ readonly path?: string + /** Parsed optional metadata object from provider-specific skill frontmatter. */ readonly metadata?: Readonly<Record<string, unknown>> } ``` @@ -72,6 +102,7 @@ interface SkillCandidate extends SkillSummary { `SkillDefinition` 是 `ctx.skills.get()` 返回的完整解析结果,供 `skill` 工具使用。`resourceBase` 告知工具如何为本地、URL 或提供方管理的 skill 渲染相对资源引导。 ```ts type-equiv +/** Optional provider-specific base used by loaded skill bodies to resolve relative resources. */ type SkillResourceBase = | { readonly kind: 'directory'; readonly path: string } | { readonly kind: 'url'; readonly url: string } @@ -79,9 +110,13 @@ type SkillResourceBase = ``` ```ts type-equiv +/** Complete parsed skill definition, including the body loaded by `ctx.skills.get()`. */ interface SkillDefinition extends SkillSummary { + /** Markdown instruction body after any provider-specific metadata removal. */ readonly content: string + /** Absolute file path when the skill came from disk. */ readonly path?: string + /** Parsed optional metadata object from frontmatter. */ readonly metadata?: Readonly<Record<string, unknown>> } ``` @@ -89,9 +124,8 @@ interface SkillDefinition extends SkillSummary { 运行时 skill 使用相同的完整形状,参与相同的先到先得收集顺序。返回的 disposer 移除该贡献并使发现缓存失效。 ```ts type-equiv -type SkillRegistration = Omit<SkillDefinition, 'provider'> & { - readonly provider?: string -} +/** Runtime skill contribution accepted by `ctx.skills.register()`. */ +type SkillRegistration = Omit<SkillDefinition, 'provider'> & { readonly provider?: string } ``` ## 查找与配置 @@ -99,8 +133,11 @@ type SkillRegistration = Omit<SkillDefinition, 'provider'> & { skill 查找对 cwd 敏感,因为提供方可能暴露工作区本地的 skill;可选的 signal 为调用方取消提供方的工作。提供方接收与缓存标识和加载相同的只读选项对象。取消在目录选择前后(包括缓存命中时)都会检查,并与发现和完整定义加载竞争。如果找不到 git root,本地提供方将所提供的 cwd 本身视为项目根目录。 ```ts type-equiv +/** Caller context used for cwd-sensitive and abortable provider work. */ interface SkillLookupOptions { + /** Workspace selector for the current lookup. */ readonly cwd?: string | undefined + /** Abort discovery or loading work for the current caller. */ readonly signal?: AbortSignal | undefined } ``` @@ -108,13 +145,15 @@ interface SkillLookupOptions { 注册表只拥有其发现缓存上限。本地提供方拥有文件系统根目录(`dshHome`、`agentsHome` 与 `customSkillDirs`)。消费方拥有其目录描述上限。 ```ts type-equiv +/** Skill registry configuration. */ interface Config { + /** Maximum number of completed cwd/provider catalogs kept in memory. */ readonly collectCacheMaxEntries?: number } ``` ## 会话目录与工具契约 -`dsh-tool-skill` 通过 `agent/session-prefix` 贡献一条 user-role 的 `<system-reminder>`。目录包含排序后的 skill `name` 和经过规范化、XML 转义的 `description`;不包含 body、路径、来源、提供方和路由提示。前缀发现通过 `SkillLookupOptions` 转发调用方的 abort signal。`catalogDescriptionMaxLength` 是消费方配置的描述上限,默认值 `500`,整数最小值 `3`。其仅请求级别、记录于 header 的生命周期由 [session-prefix RFC](../rfc/implemented/feature/2026-07-07-session-prefix.md) 定义。 +`dsh-tool-skill` 通过 `agent/session-prefix` 贡献一条 user-role `<system-reminder>`。目录只包含已排序的 skill `name` 和规范化、经 XML 转义的 `description`;不包含正文、路径、来源、提供方或路由提示。Prefix 发现通过 `SkillLookupOptions` 转发调用方的 abort signal。`catalogDescriptionMaxLength` 是消费方用于 description 上限的配置,默认值为 `500`,整数最小值为 `3`。其仅用于请求、记录在 header 中的生命周期由 [session-prefix Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-07-07-session-prefix.md)定义。 面向模型的 `skill({ name })` 工具校验 kebab-case 名称,为调用方 agent 的 cwd 加载完整定义,将未解析的 skill 报告为 unknown 或 no longer available,拒绝 `disableModelInvocation` 的 skill,并返回包含 `<skill_content name="...">`、`<skill_resources>` 和 `<skill_instructions>` 的工具结果。`resourceBase` 仅按需解析显式引用的脚本、参考资料和资产;加载结果不枚举 skill 目录。工具结果是模型获取完整指令的可见路径。 diff --git a/docs/core-data-structures/subagent.i18n.yaml b/docs/core-data-structures/subagent.i18n.yaml index ed154e096c..f7cf2d81de 100644 --- a/docs/core-data-structures/subagent.i18n.yaml +++ b/docs/core-data-structures/subagent.i18n.yaml @@ -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 -subagent.md: eb9160abaee26969aecdc533fb9fd56fae18b7fa -subagent.zh.md: b6a6bfbe61f5d2d3e0eb3bdc3aabed4b8b89317f +subagent.md: 97d6862c10a0757c41472f207f857c25f3f5d50f +subagent.zh.md: 1e88562aed99122750e9d137cb0b722d4c38c36b diff --git a/docs/core-data-structures/subagent.zh.md b/docs/core-data-structures/subagent.zh.md index b6a6bfbe61..1e88562aed 100644 --- a/docs/core-data-structures/subagent.zh.md +++ b/docs/core-data-structures/subagent.zh.md @@ -4,7 +4,7 @@ subagent seam:一个 agent(智能体)将工作委派给子 agent。与 [bash](bash.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。但它在一个维度上与其他所有 seam 不同:**同一上下文中可共存多个提供方实现**,按名称注册(`ctx.subagents`),而 bash 只允许一个执行器。注册表的形状参照 [LLM 适配器注册表](llm-streaming.md),而非单服务的 bash 执行器。 -接口:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。实现为兄弟包(`dsh-subagent-spawn`、`-fork`、`-acp`);面向模型的消费方是 [dsh-tool-subagent](../../packages/subagent/tool-subagent)。提案与设计动机见 [subagent RFC](../rfc/implemented/feature/2026-06-21-subagent-capability-seam.md)。 +接口:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。实现为兄弟包(`dsh-subagent-spawn`、`-fork`、`-acp`);面向模型的消费方是 [dsh-tool-subagent](../../packages/subagent/tool-subagent)。提案与设计理由见 [subagent Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md)。 源码:[`packages/subagent/subagent/src/types.ts`](../../packages/subagent/subagent/src/types.ts) @@ -13,10 +13,22 @@ subagent seam:一个 agent(智能体)将工作委派给子 agent。与 [ba 提供方通过一个静态描述符公布其**启动时**特性,服务在 run 存在之前即行检查;如果请求依赖提供方不具备的特性,会被大声拒绝(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不会被接受后静默忽略。**运行时**特性(steering(中途引导)、resume)则是 [`SubagentRun`](#a-live-run-subagentrun) 上的可选方法——方法的存在即为能力,TypeScript 的类型收窄即为发现机制。 ```ts type-equiv +/** + * Which START-TIME features a provider supports. Checked by the service before delegating to + * {@link SubagentProvider.start}: a request that needs a capability the chosen provider lacks + * is rejected with a typed error rather than accepted-then-ignored (the "fail loud, no silent + * degradation" rule). These static flags cover features needed before a run exists; runtime + * capabilities such as steering and resume are optional {@link SubagentRun} methods whose presence + * is the capability. + */ interface SubagentCapabilities { + /** Honor {@link SubagentStartRequest.outputSchema} (structured final output). */ readonly outputSchema: boolean + /** Enforce {@link SubagentStartRequest.maxDepth} (recursion cap). */ readonly depthLimit: boolean + /** Enforce {@link SubagentStartRequest.toolFilter} (child tool scoping). */ readonly toolFilter: boolean + /** Honor {@link SubagentStartRequest.persona} (a per-child persona). */ readonly persona: boolean } ``` @@ -26,28 +38,89 @@ interface SubagentCapabilities { 工具层根据模型输入和自身配置构建此请求;服务在 `start` 之前针对指定提供方进行校验。必填的 `parent` 提供会话 cwd、谱系与委派深度。可选的 output schema、depth、tool filter 和 persona 需要对应的能力 flag 匹配。不支持的 schema 在启动时即失败;进程内后端将 filter 和 persona 的作用域限定在子 agent 创建阶段,并通过强制 capture tool 实现所支持的 object-rooted schema。 ```ts type-equiv +/** + * What a caller asks for when starting a subagent. The tool layer builds this + * from the model's `{ description, prompt }` plus its own config; the service + * validates {@link SubagentCapabilities} against the named provider, then + * passes it to {@link SubagentProvider.start}. + */ interface SubagentStartRequest { + /** The task/prompt for the child agent (a user message in the child session). */ readonly prompt: ContentBlock[] + /** + * The spawning ("parent") agent — the one whose tool call started this + * subagent. REQUIRED: in-process backends read `parent.session.header` for + * the working directory, the `parentSession` lineage to stamp on the child, + * and the parent's delegation depth. The out-of-process backend (ACP) reads + * exactly one field — the session header's cwd, the child's workspace when + * no deployment `cwd` override is configured; nothing else crosses the + * process boundary. + */ readonly parent: Agent + /** + * Cancellation signal from the spawning context (the tool's `exec.signal`). + * This is the canonical cancellation channel both before and after startup: + * a provider rejects `start()` after cleaning partial resources when it + * fires before publication, and cancels a published child when it fires + * afterward. + */ readonly signal: AbortSignal + /** Per-child agent options (model and plugin-defined extension fields). */ readonly agentOptions?: AgentOptions + /** + * Object-rooted JSON Schema within `assertSupportedOutputSchema`'s enforced subset. Start rejects + * unsupported schemas or providers without the capability. Data must be plain host-realm JSON; + * a successful child returns the matching value as {@link SubagentResult.structured}. + */ readonly outputSchema?: StructuredOutputSchema + /** + * Optional absolute delegation-depth cap for the child being started: its + * computed depth must be less than or equal to this non-negative safe + * integer. Requires {@link SubagentCapabilities.depthLimit}; rejected at + * start otherwise. + */ readonly maxDepth?: number + /** + * Optional child tool scoping. Requires {@link SubagentCapabilities.toolFilter}; + * rejected at start otherwise. In-process backends apply it as a scoped + * `tools.restrict()` in the child's creation window: the named tools vanish + * from the child's prompt AND refuse to execute (one visibility), with loud + * unknown-name validation. + */ readonly toolFilter?: ToolRestriction + /** + * Optional per-child persona. Requires {@link SubagentCapabilities.persona}; + * rejected at start otherwise. In-process backends register it as a scoped + * `deployment:persona` section on the child, SHADOWING the deployment's + * persona for this child alone — same template semantics as the deployment + * persona (strict `{{…}}` interpolation against the registered variables). + */ readonly persona?: string } ``` -`signal` 是就绪前后唯一的取消通道。[subagent 组合控制 RFC](../rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 负责 persona、运行时全局工具过滤、绝对深度以及「可见性而非权限」的设计理由。 +`signal` 是就绪前后唯一的取消通道。[subagent 组合控制 Agent Note](../../.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md)规定 persona、live 全局工具过滤、绝对深度以及「可见性而非权限」的设计理由。 ## 终态结果:`SubagentResult` 一次 run 的最终产出,由 `SubagentRun.result` resolve。`structured` 仅在请求了 `outputSchema` 且成功满足时才存在;请求 schema 不保证一定能得到它,当子 agent 失败或结束时未产出有效 capture 时,提供方可能返回 `stopReason: 'error'`。非 `completed` 的 `stopReason` 意味着 `output` 可能不完整——消费方将其映射为 `isError` 的工具结果,而非将部分输出报告为成功。 ```ts type-equiv +/** + * The terminal outcome of a subagent run, resolved by {@link SubagentRun.result}. + */ interface SubagentResult { + /** The child's final assistant output (the last assistant message's content). */ readonly output: ContentBlock[] + /** + * The structured result after a requested `outputSchema` was successfully + * satisfied. Requesting a schema does not guarantee presence: a provider can + * end with `stopReason: 'error'` when the child fails or finishes without a + * valid capture. Shape is validated against the request schema by the + * provider; `unknown` here because the seam is schema-agnostic. + */ readonly structured?: unknown + /** Why the run ended. A non-`completed` reason means `output` may be partial. */ readonly stopReason: SubagentStopReason } ``` @@ -55,11 +128,22 @@ interface SubagentResult { `SubagentStopReason` 是一个[可合并扩展的派生联合类型](core.md#the-map--derived-union-pattern)——后端可以添加变体,因此消费方应对已知 case 分支处理,将未知的终态原因视为失败: ```ts type-equiv +/** + * Why a subagent run ended. Merge-extensible (a backend may add variants); + * consumers branch on the known cases and fall through `default`. The known + * cases mirror the harness turn-end vocabulary so the tool layer can map a + * non-`completed` result to an `isError` tool result. + */ interface SubagentStopReasonMap { + /** The child finished its turn normally. */ completed: 'completed' + /** The run was cancelled by its request signal or by disposal. */ aborted: 'aborted' + /** The child failed (model error, transport error). */ error: 'error' + /** The child hit its token ceiling before finishing. */ 'max-tokens': 'max-tokens' + /** The child declined the task. */ refusal: 'refusal' } ``` @@ -71,33 +155,94 @@ interface SubagentStopReasonMap { `SubagentRun` 是消费方持有的、指向一个就绪子 agent 的句柄。消费方 await `result` 并始终 dispose(资源释放)该 run,直至其完全停稳。子 agent 失败时以非 completed 的 stop reason resolve;只有不可表示的基础设施故障才会 reject。可选的 `sendMessage` 和 `resume` 方法通过自身的存在来公布运行时能力。 ```ts type-equiv +/** + * Child handle returned only after readiness. Consumers await {@link result} and must always + * {@link dispose} to cancel remaining work and reach quiescence. Optional methods are runtime + * capability discovery; narrow their presence before calling. + */ interface SubagentRun { - readonly id: AgentId + /** + * Parent-scoped run id. For a local run, this MUST equal the published child + * session id, whose `parentSession` records `request.parent.session.id`; a + * remote provider mints an id unique in the parent namespace. + */ + readonly id: SessionId + /** + * The exact published in-process child, or `undefined` for a remote run. + * When present, its id is {@link id}; the provider retains no ownership + * implication beyond the run's ordinary {@link dispose} contract. + */ + readonly localAgent: Agent | undefined + /** + * Resolves with the child's terminal {@link SubagentResult} when the run + * settles. Does NOT reject on a child-level failure — a model/transport + * failure resolves with `stopReason: 'error'` so the consumer maps it to an + * `isError` tool result. Rejects only on an infrastructure fault the seam + * cannot represent as a stop reason. + */ readonly result: Promise<SubagentResult> + /** + * Cancel remaining work, reach child quiescence, and release the run's + * resources (in-process: dispose the owned agent and remove its session; + * ACP: kill and reap the subprocess). Idempotent. + */ dispose(): Promise<void> + /** + * OPTIONAL (steering capability): send additional content to the running + * child between steps. Present only on providers that support live steering. + */ sendMessage?(content: ContentBlock[]): void + /** + * OPTIONAL (resume capability): send a follow-up task to a settled child, + * continuing its session, and return a fresh run for the continuation. + */ resume?(content: ContentBlock[]): Promise<SubagentRun> } ``` +本地 run 必须在 `start()` fulfill 前发布一个普通子 agent/session,将该子 session id 作为 `SubagentRun.id` 返回,以 `localAgent` 暴露确切子 agent,并在子 agent 的 `parentSession` header 中记录 `request.parent.session.id`。运行时所有权可以把子 agent 放在 parent、提供方或 root 作用域下。远程提供方则返回 parent 作用域的生命周期 id 与 `localAgent: undefined`。 + ## 提供方 seam:`SubagentProvider` 每个提供方是一个具名的子 agent 传输层,多个提供方可以共存。服务在 `start()` 之前校验请求的启动时能力。`inheritsParentContext` 仅描述对话种子注入(`fork`:true;`spawn` 和 `acp`:false),使消费方能生成准确的面向模型的措辞,而不暗示继承了工具、服务或权限。 ```ts type-equiv +/** + * A subagent backend: one transport for running a child agent (in-process + * spawn/fork, ACP to another process, …). Implementations register under a + * unique name via {@link SubagentService.registerProvider}; multiple providers + * coexist in one context (unlike the single-implementation bash seam). The + * Providers are trusted same-process implementations; callers treat their + * descriptors and returned values as borrowed immutable data. + */ interface SubagentProvider { + /** Unique registry name (e.g. `spawn`, `fork`, `acp`). */ readonly name: string + /** The start-time features this provider supports (see {@link SubagentCapabilities}). */ readonly capabilities: SubagentCapabilities + /** + * Whether the child sees the parent's completed-turn prefix. This is descriptive, not a + * service-validated start capability: the model-facing tool derives truthful wording from it. + * It says nothing about tool registration, injected services, or authority inheritance. + */ readonly inheritsParentContext: boolean + /** + * Establish a child and return its handle only after publication. The + * service has already validated that every requested start-time capability + * is supported, so an implementation may assume e.g. `request.maxDepth` is + * honorable when present. If setup fails or `request.signal` aborts before + * fulfillment, the provider owns and cleans all partial resources before this + * promise rejects. Ownership transfers to the caller only on fulfillment. + */ start(request: SubagentStartRequest): Promise<SubagentRun> } ``` -`start()` 仅在 run 就绪时 fulfill。服务观察其 result、发出 `subagent/start`,并返回同一个 run;rejection 意味着提供方已自行清理,不发出生命周期配对事件。进程内子 agent 可通过 `ctx.agents` 发现,远程子 agent 则不必如此。`subagent/end` 报告最终输出或基础设施故障。两个事件均为仅观察事件;每个监听器异常都会被独立隔离。 +`start()` 仅在 run 就绪时 fulfill。服务铸造唯一 `runId`,从提供方的确切 `localAgent` 快照 `local`,观察结果,emit `subagent/start`,并返回同一个 run;rejection 意味着提供方已清理,且不会 emit 生命周期事件对。配对的 `subagent/end` 携带相同标识与最终输出或基础设施失败。两个事件都仅用于观察,每个 listener 异常都会被独立隔离。 ## 进程内后端:深度与种子 spawn 和 fork 后端通过 `parent.ctx` 创建一个普通 agent,将取消信号传入核心创建流程,并通过 `AgentHandle` 进行 dispose。移除提供方会阻止新的 start,但不会撤销已接受的 run。每个子 agent 获得一个新的扁平作用域,而非继承父级注册。深度与 fork 种子注入复用既有的 agent 和会话词汇: -- **委派深度**是一个可合并扩展的 `AgentOptions.subagentDepth` 字段(顶层 agent 为 `0`,子 agent 为 parent + 1)。只有 `undefined` 表示顶层;所有已存储的值必须是非负安全整数。该字段归 seam 所有——循环既不设置也不读取它——因此嵌套 spawn 会校验父级的已存储深度,拒绝超出安全整数域的派生子深度,并在定义了绝对 `request.maxDepth` 上限时将其施加于子 agent。 +- **委派深度**由持久 `SessionHeader.delegationDepth` 与可合并扩展的运行时字段 `AgentOptions.subagentDepth` 共同表示;缺失表示顶层深度为零,存在的较大值具有权威性。两个字段都归该 seam 所有——循环既不设置也不读取它们——因此进程内子 agent 会持久保存 parent 深度 + 1,resume 无法降低深度,而且每次 start 都会拒绝超出安全整数域、或高于已定义绝对 `request.maxDepth` 上限的派生深度。 - **Fork 种子注入**使用 `CreateAgentOptions.seed`(一个 `SessionEvent[]` 前缀,经由 `AgentLoop.createAgent` → `ctx.sessions.prepare({ seed })` 传递,与 `resume` 使用的原语相同)。fork 后端传入父级日志的一段*平衡的已完成轮次前缀*——父级事件直到并包括其最后一个 `turn/end`——因此种子从 0 连续,[invariants](../../packages/support/invariants) 回放可以接受它(进行中的、未平衡的轮次被排除在外)。 diff --git a/docs/core-data-structures/system-prompt.i18n.yaml b/docs/core-data-structures/system-prompt.i18n.yaml index f2918af35f..8e68fc099b 100644 --- a/docs/core-data-structures/system-prompt.i18n.yaml +++ b/docs/core-data-structures/system-prompt.i18n.yaml @@ -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 -system-prompt.md: 175f2af407e5c39a24f0f8f8e4e664063b897ead -system-prompt.zh.md: 8827ac0b915915f716643e0a9e04edaacedbc868 +system-prompt.md: 63a750c74300b4353f132d3dae9da52a10631f23 +system-prompt.zh.md: 748e9e4406fe8ca1071aa87f5926bd043378ccdb diff --git a/docs/core-data-structures/system-prompt.zh.md b/docs/core-data-structures/system-prompt.zh.md index 8827ac0b91..748e9e4406 100644 --- a/docs/core-data-structures/system-prompt.zh.md +++ b/docs/core-data-structures/system-prompt.zh.md @@ -8,11 +8,18 @@ ## 组装上下文 -`AssembleContext` 标识一次组装所解析的作用域层。它可通过合并扩展:`dsh-agent` 添加可选的活跃 `agent` 字段,`assembleContextFor(agent)` 同时设置该字段与 `scope`。 +`AssembleContext` 标识一次组装所解析的作用域 layer,并可携带该请求的显式控制 signal。它可合并扩展:`dsh-agent` 添加可选的 live `agent` 字段,`assembleContextFor(agent, signal)` 则一起设置这些显式字段。裸组装既没有 scope,也没有 signal。 ```ts type-equiv +/** Merge-extensible context for one prompt assembly. */ interface AssembleContext { + /** + * Scope whose providers and waterfall listeners participate. When absent, + * only global providers and subject-less listeners participate. + */ scope?: ScopeKey + /** Explicit control signal for the turn that requested this assembly, when any. */ + signal?: AbortSignal } ``` @@ -21,8 +28,11 @@ interface AssembleContext { `ToolProviderResult.schemas` 是当前组装中对模型可见的工具集合。`knownNames` 是提供方在限制前的名称全集,用于区分「配置名拼写错误」与「已知工具在此作用域中被有意隐藏」。 ```ts type-equiv +/** Tool schemas visible in one assembly and their pre-restriction name set. */ interface ToolProviderResult { + /** The schemas this provider contributes to THIS assembly. */ readonly schemas: readonly ToolSchema[] + /** The pre-restriction name universe for config validation (defaults to `schemas`' names). */ readonly knownNames?: readonly string[] } ``` @@ -32,9 +42,21 @@ interface ToolProviderResult { `PromptSection` 是一份只读的同进程注册契约。其文本可以是静态的,也可以从当前组装上下文动态解析。 ```ts type-equiv +/** One contributed section of the system prompt (registry input). */ interface PromptSection { + /** Unique name — a duplicate registration throws (see {@link SystemPrompt.section}). */ readonly name: string + /** + * Sections are concatenated in ascending order. Convention: `-100` is the + * harness identity, `0` the deployment persona, tool guidance uses 100–199; + * other negative orders also render before the persona. + */ readonly order: number + /** + * Static text or a provider evaluated at each assembly with that assembly's + * {@link AssembleContext}. The text may reference `{{variable}}`s — they are + * interpolated later, by {@link renderPrompt}. + */ readonly text: string | ((context: AssembleContext) => string) } ``` diff --git a/docs/core-data-structures/tools.i18n.yaml b/docs/core-data-structures/tools.i18n.yaml index 7f55967dcb..2f09ee1e2d 100644 --- a/docs/core-data-structures/tools.i18n.yaml +++ b/docs/core-data-structures/tools.i18n.yaml @@ -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 -tools.md: f8be67054cd81027d4b751329948a784fa4f0ed9 -tools.zh.md: 27066180bc3a3666e4ef5c789034adc0a82e05b8 +tools.md: ce14a37da33f89b8b90d6d8e70756f94e3d690dd +tools.zh.md: 869480fc38688a15a8681648903e1a4a0959c79d diff --git a/docs/core-data-structures/tools.zh.md b/docs/core-data-structures/tools.zh.md index 27066180bc..869480fc38 100644 --- a/docs/core-data-structures/tools.zh.md +++ b/docs/core-data-structures/tools.zh.md @@ -8,11 +8,21 @@ ## `ToolDefinition` — 一个已注册的工具 -一个 `ToolSchema`(面向模型的字段)加上 `execute` 函数和可选的 UI 展示器。注册表持有这些定义;agent loop(智能体循环)通过它们分派调用。注册表的 `schemas()` 通过显式白名单构建面向模型的 `ToolSchema[]`——`execute`/`presentCall`/`presentResult` 绝不能泄漏到模型请求中。 +由一个 `ToolSchema`(面向模型的字段)、`execute` 函数、仅供宿主使用的调度器元数据和可选 UI 展示函数组成。注册表持有这些定义,循环通过它们分派调用。注册表的 `schemas()` 通过显式允许列表构建面向模型的 `ToolSchema[]`;`execute`/`timeoutMs`/`isConcurrencySafe`/`presentCall`/`presentResult` 绝不能泄漏到模型请求中。 ```ts type-equiv +/** A registered tool: its schema plus the execution function. */ interface ToolDefinition extends ToolSchema { - execute(args: unknown, exec: ToolExecution): Promise<ToolExecuteReturn> + /** + * Run one accepted call. Async work must observe or forward `exec.signal` and + * settle only after its owned work reaches quiescence. The registry preserves + * caller cancellation through around-dispatch signal replacement and does + * not abandon this promise, but it cannot hard-kill same-process code. + * @param args - losslessly snapshotted, frozen model arguments. + * @param exec - execution identity, cancellation signal, and context deferral. + * @returns model-facing content plus optional private presentation metadata. + */ + execute(args: unknown, exec: ToolRunContext): Promise<ToolExecuteReturn> /** * Cooperative tool-call timeout budget in milliseconds. Omit for no deadline. * Enforced by `@deepseek-ai/dsh-timeout-policy` (a `tools/execute` wrapper); it @@ -21,6 +31,20 @@ interface ToolDefinition extends ToolSchema { * cooperative implementation that can reach quiescence when the signal aborts. */ timeoutMs?: number + /** + * Pure synchronous classifier for overlap with sibling tool calls. Only + * `true` opts in; omission, exceptions, non-`true` returns, and invalid + * `defineTool` arguments are exclusive. This metadata is never model-visible. + * + * Opted-in executions must not mutate parent-owned state. Shared state must + * tolerate concurrent dispatch; recorder races are permitted only when they + * commute or fail closed. See the + * [parallel-tool-call Agent Note](../../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md) + * for the full contract. + * @param args - parsed arguments; `defineTool` validates before calling. + * @returns Whether this call may join a parallel group. + */ + isConcurrencySafe?(args: unknown): boolean /** * Optional: how to present the PENDING state of one call in a UI, derived from * the call's `args` (parsed arguments, `unknown` — the tool validates/narrows @@ -51,6 +75,7 @@ interface ToolDefinition extends ToolSchema { 源码:[`packages/core/tools/src/schema.ts`](../../packages/core/tools/src/schema.ts) ```ts type-equiv +/** One schema-spec property entry. */ interface SchemaProp { type: SchemaType /** Per-property required flag (NOT the JSON Schema top-level required array). */ @@ -59,7 +84,10 @@ interface SchemaProp { description?: string /** Enum of allowed values (strings only). */ enum?: string[] - /** Default value. */ + /** + * Model-visible JSON Schema default annotation. Validation does not apply it; + * dynamic tool mounts may supply it even though first-party definitions do not. + */ default?: unknown /** Nested properties for type: 'object'. */ properties?: SchemaSpec @@ -69,12 +97,29 @@ interface SchemaProp { ``` ```ts type-equiv +/** + * The author-facing parameter schema: a shallow map of property name to + * {@link SchemaProp}. Required-ness is a per-property boolean (`required: + * true`), not a separate array. + */ type SchemaSpec = Record<string, SchemaProp> ``` `SchemaType` 是原始联合类型 `'string' | 'number' | 'boolean' | 'object' | 'array'`。`InferArgs<S>` 将一个 `SchemaSpec` 映射为 TS 参数类型——`required: true` 的属性成为必选键,其余为真正的可选: ```ts type-equiv +/** + * Infer the TS argument type for a complete {@link SchemaSpec}. + * + * Properties marked `required: true` are required keys; all others are + * genuinely optional keys (`?`), so callers may omit them entirely. + * + * Example: + * ```ts + * type Args = InferArgs<{ path: { type: 'string'; required: true }; limit: { type: 'number' } }> + * // → { path: string; limit?: number } + * ``` + */ type InferArgs<S extends SchemaSpec> = Simplify< & { [K in RequiredKeys<S>]: InferPropValue<S[K]> } & { [K in Exclude<keyof S, RequiredKeys<S>>]?: InferPropValue<S[K]> } @@ -90,54 +135,126 @@ type InferArgs<S extends SchemaSpec> = Simplify< `ToolRestriction` 仅作用于实时的部署全局工具层。注册表将 readonly 名称编译为私有集合,对多个限制取交集,再叠加作用域本地工具。仅 deny 的过滤器允许后续未列出的全局工具通过,而 allow 列表则排除它们。 ```ts type-equiv +/** + * Per-scope filter over global tools. Restrictions intersect and do not affect + * scoped registrations or the reserved Code Mode transport. + */ interface ToolRestriction { + /** Global tool names that stay visible; everything else is removed. */ readonly allow?: readonly string[] + /** Global tool names removed from visibility. */ readonly deny?: readonly string[] } ``` ## 执行:可扩展的 waterfall(瀑布式事件)加单调策略 -`ctx.tools.execute()` 接收调用方拥有的 `ToolExecutionInput`,将其解析后的 JSON 参数一次性物化为流水线拥有的 `ToolExecution`,然后依次通过 `tools/pre-execute`(可重排的 allow/deny/ask waterfall)→ 已注册的单调 guard → `tools/execute`(around-dispatch 包装层)→ `tools/post-execute`(检查/替换结果)→ `tools/result`(不可变的权威结果)。最终产出为 `ToolExecutionResult`。 +`ctx.tools.execute()` 接受由调用方拥有且包含必需 readonly `signal` 的 `ToolExecutionInput`,将其解析后的 JSON 参数一次性物化为流水线拥有的 `ToolExecution`,然后让调用依次经过 `tools/pre-execute`(可重排的 allow/deny/ask waterfall)→ 已注册的单调 guard → `tools/execute`(环绕分派包装层)→ `tools/post-execute`(检查/替换结果)→ `tools/result`(不可变的权威结果)。只有 `tools/execute` 视图可以替换必需的 signal。最终产出为 `ToolExecutionResult`。 ```ts type-equiv +/** Opaque call identity that permits correlation without exposing mutable execution state. */ type ToolExecutionToken = symbol & { readonly [toolExecutionTokenBrand]: true } ``` ```ts type-equiv +/** + * Caller-supplied description of one tool call. {@link ToolRegistry.execute} + * adds the registry-owned token to form a pipeline {@link ToolExecution}; + * callers do not choose that token. + */ interface ToolExecutionInput { readonly callId: CallId readonly name: string - /** Parsed JSON arguments (unknown — tools validate their own input). */ + /** Losslessly JSON-serializable parsed arguments (tools validate their own schema). */ readonly arguments: unknown /** The agent on whose behalf the call runs (set by the agent loop). */ readonly agent?: Agent /** * Opaque token of the enclosing transport execution, when one exists. Code * Mode sets this on SDK sub-dispatches so commit-style observers can wait for - * the outer `run_code` outcome without receiving its live mutable execution. - */ + * the outer `run_code` outcome without receiving its live mutable execution. + */ readonly parent?: ToolExecutionToken - signal?: AbortSignal + /** Required caller-owned cancellation for this invocation. */ + readonly signal: AbortSignal } ``` +工具函数体接收运行时扩展。`deferContext()` 是组合工具的通道:它记录嵌套分派产生的上下文,而不会在外层调用尚未结束时注入这些上下文。 + ```ts type-equiv +/** + * Runtime context handed to a tool implementation after the registry has + * accepted a {@link ToolExecution}. A composite tool uses + * {@link deferContext} to ferry context produced by nested dispatches back to + * the outer result; the loop appends it only after the outer `tool/result`. + */ +interface ToolRunContext extends ToolExecution { + /** + * Defer one nested-dispatch context until this tool's final result reaches + * the agent loop. Contexts retain their individual source and metadata and + * are emitted in call order. + */ + deferContext(context: HookContext): void +} +``` + +agent loop(智能体循环)向注册表查询每个待处理调用的执行模式,并据此形成独占屏障和滚动池并行执行: + +```ts type-equiv +/** + * Scheduling mode for one pending call. `parallel` may overlap with siblings; + * `exclusive` runs alone and forms an ordering barrier. + */ +type ToolExecutionMode = + | { kind: 'parallel' } + | { kind: 'exclusive' } +``` + +```ts type-equiv +/** + * One pending tool call inside the registry pipeline. Parsed arguments cross + * one lossless-JSON materialization boundary before policy and are deep-frozen; + * call identity, the caller signal, and the registry-assigned {@link token} are + * readonly. The registry freezes the complete object before `tools/result` + * observers run. + */ interface ToolExecution extends ToolExecutionInput { /** Registry-assigned identity shared with nested calls only as their opaque `parent` token. */ readonly token: ToolExecutionToken } ``` -`ToolExecutionToken` 是一个不透明的运行时 `Symbol`,仅用于身份比较。在策略执行之前,`execute()` 物化并冻结参数、拒绝非 JSON 输入、分配 token。身份字段和可选的 parent token 保持 readonly;只有 `signal` 可以在分派前后变化。最终观察者接收到的是冻结的执行身份。 +```ts type-equiv +/** + * Around-dispatch view of a {@link ToolExecution}. A `tools/execute` wrapper + * may replace the signal for its delegated lifetime, but it cannot remove it. + * The registry fuses every replacement with the captured caller signal. + */ +interface ToolDispatchExecution extends Omit<ToolExecution, 'signal'> { + /** Cancellation signal visible to the next wrapper or tool body. */ + signal: AbortSignal +} +``` + +`ToolExecutionToken` 是不透明的运行时 `Symbol`,仅用于身份比较。策略执行前,`execute()` 会物化并冻结参数、拒绝非 JSON 输入并分配 token。身份字段、调用方必需的 signal 和可选的 parent token 均保持 readonly。`ToolDispatchExecution` 包装层可以替换 signal 但不能移除;注册表会在调用工具函数体前重新融合调用方的 signal。最终观察者接收冻结的执行身份。 `ToolGuard` 是感知作用域的最终预分派策略。其形状有意不包含 allow 结果:`undefined` 保留 waterfall 的决策,而返回的 reason 只能缩减权限,因此后续监听器无法撤销它。 ```ts type-equiv +/** + * A monotonic execution guard evaluated after every `tools/pre-execute` + * listener and before the tool body. Returning a reason denies the call; + * returning `undefined` leaves it unchanged. Because guards have no allow + * result, listener ordering cannot turn a denial back into permission. + * @param execution - the identity-protected call after extensible pre-execute policy completed. + * @returns a final denial reason, or `undefined` to leave the call allowed. + */ type ToolGuard = (execution: Readonly<ToolExecution>) => string | undefined ``` ```ts type-equiv +/** The outcome of one tool call. */ interface ToolExecutionResult { content: ContentBlock[] isError: boolean @@ -148,16 +265,10 @@ interface ToolExecutionResult { */ error?: ToolErrorInfo /** - * Extra model-facing context a `tools/post-execute` listener attached for the - * NEXT request (Claude Code's PostToolUse `additionalContext`). It is NOT part - * of this call's `content` — `content`/`feedback` shape the tool RESULT, but - * `additionalContext` is a SEPARATE `context/message`. A step can carry - * multiple tool calls, so the loop BUFFERS every call's `additionalContext` - * and appends them only AFTER all `tool/result`s for the step, keeping - * tool-call/result adjacency intact. Carried on the result purely to ferry it - * from `execute()` up to the loop's per-step buffer. + * Model-facing context for the next request, separate from this tool result. The loop + * accepts it into the active-batch FIFO, then appends after recorded results even if interrupted. */ - additionalContext?: HookContext + additionalContexts?: HookContext[] /** * The tool-private presentation payload from a successful `execute` (the object * return form). Threaded onto the `tool/result` session event and back into @@ -175,6 +286,12 @@ interface ToolExecutionResult { 每个拦截 waterfall 返回一个类型化的 **Decision**(与 `agent/*` seam 共享的惯用模式)。`tools/pre-execute` 监听器接收 `(exec, next)` 并返回 `PreToolDecision`;`tools/execute` 包装层返回 `ToolExecutionResult`;`tools/post-execute` 监听器接收 `(exec, result, next)` 并返回 `PostToolDecision`: ```ts type-equiv +/** + * Pre-dispatch decision. `allow` runs the call; `deny` materializes an error; + * `ask` runs only after an approval service returns `allowed-once` and otherwise + * denies. Input rewriting is excluded because arguments are already logged and + * presented. + */ type PreToolDecision = | { kind: 'allow' } | { kind: 'deny'; reason: string } @@ -182,9 +299,13 @@ type PreToolDecision = ``` ```ts type-equiv +/** + * Post-dispatch decision: accept or replace content, attach context for the next + * request, or block by turning corrective feedback into an error result. + */ type PostToolDecision = - | { kind: 'accept'; content?: ContentBlock[]; additionalContext?: HookContext } - | { kind: 'block'; feedback: ContentBlock[]; additionalContext?: HookContext } + | { kind: 'accept'; content?: ContentBlock[]; additionalContexts?: HookContext[] } + | { kind: 'block'; feedback: ContentBlock[]; additionalContexts?: HookContext[] } ``` 调用 `next()` 获取默认决策,或直接返回一个决策以短路。前置策略可以 deny 或 ask;只有 `allowed-once` 才继续执行,而未授权、缺少审批通道或服务、或无 agent 的请求都会变为拒绝。Guard 仍可施加最终拒绝。参数不可被改写,因为历史记录、审计、UI 和执行必须保持一致。 @@ -196,25 +317,41 @@ type PostToolDecision = 调用方用来向 subagent 要求机器可读结果的词汇(`SubagentStartRequest.outputSchema`,见 [subagent.md](subagent.md#the-start-request)),或工作流 `agent()` 调用使用的词汇。它有意不是完整的 JSON Schema:schema 原样传给模型作为强制工具的 `parameters`,产出的值由 `validateStructuredValue` 在客户端校验——因此每个被接受的关键字都必须是校验器实际执行的,`assertSupportedOutputSchema` 会大声拒绝其他任何内容(`OutputSchemaError`,列出所有违规项)。两个遍历器仅推理自有可枚举属性(JSON 不携带其他内容),并拒绝会有损序列化的非纯对象(`Date`、`Map`)。 ```ts type-equiv +/** The scalar values `enum`/`const` may carry (finite numbers only). */ type StructuredScalar = string | number | boolean | null ``` ```ts type-equiv +/** The `type` keywords the subset accepts. */ type StructuredSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null' ``` ```ts type-equiv +/** + * One node of the structured-output schema subset. Recursive via `properties` + * and `items`; see the module doc for the exact keyword semantics. + */ interface StructuredSchemaNode { type: StructuredSchemaType + /** Nested property schemas (`type: 'object'` only). */ properties?: Record<string, StructuredSchemaNode> + /** Required property names; each must appear in `properties`. */ required?: string[] + /** `false` rejects undeclared keys; absent/`true` allows them (JSON Schema default). */ additionalProperties?: boolean + /** Item schema (`type: 'array'` only); absent ⇒ any JSON items. */ items?: StructuredSchemaNode + /** Allowed values (scalar types only). */ enum?: StructuredScalar[] + /** The single allowed value (scalar types only). */ const?: StructuredScalar + /** Annotation, ignored for validation. */ description?: string + /** Annotation, ignored for validation. */ title?: string + /** Annotation, ignored for validation (must still be JSON data). */ default?: unknown + /** Annotation, ignored for validation (must still be JSON data). */ examples?: unknown } ``` @@ -222,6 +359,7 @@ interface StructuredSchemaNode { schema 是一个以 object 为根的节点(`enum`/`const` 仅限标量;`description`/`title`/`default`/`examples` 是注解,允许但忽略,但仍要求为 JSON 数据——它们随协议传输): ```ts type-equiv +/** A structured-output schema: an OBJECT-rooted {@link StructuredSchemaNode}. */ type StructuredOutputSchema = StructuredSchemaNode & { type: 'object' } ``` @@ -232,6 +370,6 @@ type StructuredOutputSchema = StructuredSchemaNode & { type: 'object' } - `ToolCallView`(待执行):`{ card: 'generic', title, kind?, rawInput?, content?, locations? }`(默认卡片;`locations` 是 `{ path, line? }[]`,表示调用读取/修改的文件,供编辑器跟随)、`{ card: 'terminal', title, description?, cwd? }`(shell 命令→终端卡片)、或 `{ card: 'diff', title, diffs, locations? }`(文件创建/修改→行内 diff 卡片;`diffs` 是 `{ path, oldText, newText }[]`,新文件时 `oldText: null`)。 - `ToolResultView`(已完成):`{ card: 'generic', title?, content? }`、`{ card: 'terminal', title?, output?, exitCode?, signal? }`(捕获的运行输出 + 退出状态;有能力的 UI 显示退出状态标签,无能力的 UI 获得桥接层从 `output` 派生的围栏 ` ```console ` 回退)、或 `{ card: 'diff', title?, diffs }`(已完成的文件变更→要展示的变更,通常是从变更前后内容计算出带上下文行的已应用 hunk,或在没有前像时的整文件 diff——例如文件创建。`tool_call_update` 的内容会替换调用的内容,因此变更工具即使与调用时的片段重复也要返回此卡片,以防结果文本覆盖 diff)。 -`ToolCallKind`(`'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other'`)为 generic 卡片选择图标。`FileLocation`(`{ path, line? }`)和 `FileDiff`(`{ path, oldText, newText }`)是共享的文件卡片词汇。该设计固定在[渲染意图联合类型 RFC](../rfc/implemented/architecture/2026-07-02-tool-render-intent-union.md) 中;ACP 桥接层将 `diff` 卡片映射为 `{ type: 'diff' }` 内容块,将 `terminal` 卡片映射为 `_meta` 终端约定,并将文件卡片的标题相对于会话 cwd 做相对化处理。 +`ToolCallKind`(`'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other'`)用于为通用卡片选择图标。`FileLocation`(`{ path, line? }`)与 `FileDiff`(`{ path, oldText, newText }`)是共享的文件卡片词汇。该设计由[渲染意图联合类型 Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md)固定;ACP 桥接层将 `diff` 卡片映射为 `{ type: 'diff' }` 内容块,将 `terminal` 卡片映射为 `_meta` 终端约定,并根据会话 cwd 将文件卡片标题转换为相对路径。 -完整的展示字段文档见 [`packages/core/tools/src/presentation.ts`](../../packages/core/tools/src/presentation.ts)。bash 工具自身的 schema(`bash`/`bash_output`/`bash_kill`)及其驱动的执行器见 [bash.md](bash.md)。 +完整的展示字段文档见 [`packages/core/tools/src/presentation.ts`](../../packages/core/tools/src/presentation.ts)。`bash` schema 与执行器见 [bash.md](bash.md);通用后台控制见 [tasks.md](tasks.md)。 diff --git a/docs/core-data-structures/user-interaction.i18n.yaml b/docs/core-data-structures/user-interaction.i18n.yaml index d0c0b33ce5..7a135fdf88 100644 --- a/docs/core-data-structures/user-interaction.i18n.yaml +++ b/docs/core-data-structures/user-interaction.i18n.yaml @@ -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 -user-interaction.md: 47e0e26cd0a5201185dd252a882496456a9c3edd -user-interaction.zh.md: e7d2f27b8729a7694008d1ae7e21bdccae6058dd +user-interaction.md: c7684879c6b81d75e2737857279e68e30626bfa4 +user-interaction.zh.md: e1772fdd9427829027e108b38093c6c04c23f041 diff --git a/docs/core-data-structures/user-interaction.zh.md b/docs/core-data-structures/user-interaction.zh.md index e7d2f27b87..e1772fdd94 100644 --- a/docs/core-data-structures/user-interaction.zh.md +++ b/docs/core-data-structures/user-interaction.zh.md @@ -2,7 +2,7 @@ [English](user-interaction.md) | 中文 -[dsh-user-interaction](../../packages/ui/user-interaction) 的用户交互 seam。它是提供方无关的词汇,工具或权限插件在需要人类回答后 agent(智能体)才能继续时使用这套词汇。UI 表面提供活跃的 `UserInteractionProvider`:`dsh-stdio-demo` 在 readline 中渲染问题,`dsh-acp` 将其映射为 ACP(Agent Client Protocol)表单征询。 +[dsh-user-interaction](../../packages/ui/user-interaction) 的用户交互 seam。它是工具或权限插件需要人类回答后 agent 才能继续时所使用的、提供方中立的词汇。UI surface 提供活跃的 `UserInteractionProvider`:`dsh-tui` 使用键盘驱动的 overlay,`dsh-acp` 则把问题映射为 ACP 表单 elicitation。 源码:[`packages/ui/user-interaction/src/index.ts`](../../packages/ui/user-interaction/src/index.ts) @@ -11,6 +11,7 @@ `AskUserQuestionOption` 是可选择项的形状。`label` 是面向用户的选项文字,同时也是面向模型的选中值;`description` 是可选的 UI 帮助文本。 ```ts type-equiv +/** One selectable answer offered to the user. */ interface AskUserQuestionOption { /** User-facing label. */ label: string @@ -21,14 +22,17 @@ interface AskUserQuestionOption { ## 问题条目 -`AskUserQuestionItem` 是请求中的一个问题。模型提供一个稳定的 `id`,回答时原样回传,使批量问题可路由。 +`AskUserQuestionItem` 是请求中的一个问题。调用方提供稳定的 `id`,它会随答案原样返回,使批量问题仍可路由。可选的 `detail` 携带辅助文本;提供方会将其随问题渲染,但不会放入可选 option label。 ```ts type-equiv +/** One question in a user-interaction request. */ interface AskUserQuestionItem { - /** Stable model-provided question id, echoed in the answer. */ + /** Stable caller-provided question id, echoed in the answer. */ id: string /** The question to display. */ question: string + /** Optional supporting detail rendered with the question but kept out of option labels. */ + detail?: string /** Optional short heading/group label. */ header?: string /** Optional choices the UI can render as a menu. */ @@ -43,6 +47,7 @@ interface AskUserQuestionItem { `AskUserQuestionRequest` 是跨包(package)的请求。`questions` 是数组,这样 UI 可以在一个流程中呈现相关提示,同时保持每个回答有稳定的 id。 ```ts type-equiv +/** Request for a human answer. */ interface AskUserQuestionRequest { /** Questions to display. */ questions: AskUserQuestionItem[] @@ -58,6 +63,7 @@ interface AskUserQuestionRequest { 提供方为每个已回答的问题 id 返回一条回答。`selected` 包含选中的选项标签,`custom` 在用户输入自由文本时携带「其他」回答。当 `custom` 存在时,`selected` 为空;自定义文本是对选中项的覆盖,而非补充。 ```ts type-equiv +/** Answer to one question. */ interface AskUserQuestionAnswerItem { /** The answered question id. */ id: string @@ -69,6 +75,7 @@ interface AskUserQuestionAnswerItem { ``` ```ts type-equiv +/** The human's answer. */ interface AskUserQuestionAnswer { /** Structured answers keyed by question id. */ answers: AskUserQuestionAnswerItem[] @@ -80,6 +87,7 @@ interface AskUserQuestionAnswer { 同一上下文中只能有一个活跃的提供方。提供方注册绑定到 effect,因此 HMR(热模块替换)或 dispose(资源释放)会移除当前活跃的 UI。 ```ts type-equiv +/** UI-side provider for user questions. */ interface UserInteractionProvider { ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer> } @@ -90,6 +98,7 @@ interface UserInteractionProvider { `UserInteractionError` 继承 `HarnessError`,因此 `ctx.tools.execute()` 会保留 `{ name, code }`,用于面向模型的工具失败,如 `EMPTY_QUESTIONS`、`NO_PROVIDER`、`ASK_ABORTED` 或 ACP 侧取消。 ```ts type-equiv +/** Stable error taxonomy for user-interaction failures. */ class UserInteractionError extends HarnessError { constructor(message: string, code: string, options?: ErrorOptions) { super(message, code, options) diff --git a/docs/core-data-structures/web.i18n.yaml b/docs/core-data-structures/web.i18n.yaml index 05d23f25a4..efcc7b3258 100644 --- a/docs/core-data-structures/web.i18n.yaml +++ b/docs/core-data-structures/web.i18n.yaml @@ -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 -web.md: 74db18835df02ef233f78ad7fbfec5d9b26d58e6 -web.zh.md: c5b99b72bc9ce1be19ebcad5ffad61fa256e1509 +web.md: 20d07240c9d9fea2f1f5abbac810f349a3e81f9b +web.zh.md: d4d9259db5c834349c1cf9c72ed5c74b0a02b32b diff --git a/docs/core-data-structures/web.zh.md b/docs/core-data-structures/web.zh.md index c5b99b72bc..d4d9259db5 100644 --- a/docs/core-data-structures/web.zh.md +++ b/docs/core-data-structures/web.zh.md @@ -2,7 +2,7 @@ [English](web.md) | 中文 -Web 访问 seam 是一个[能力 seam](../rfc/implemented/architecture/2026-06-24-web-capability-seam.md),在一个 `ctx.web` 服务上横跨**两项能力**(搜索与抓取),分布在多个包(package)中:接口([dsh-web](../../packages/web/web),`ctx.web` + 提供方注册表)、实现([dsh-web-search-exa](../../packages/web/web-search-exa)、[dsh-web-search-perplexity](../../packages/web/web-search-perplexity)、[dsh-web-search-deepseek](../../packages/web/web-search-deepseek)、[dsh-web-fetch-local](../../packages/web/web-fetch-local)),以及消费方([dsh-tool-web](../../packages/web/tool-web),`web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此,而非 [core.md](core.md)。更换搜索提供方不会改变模型发起查询的方式,更换抓取实现也不会改变模型请求 URL 的方式。 +Web 访问 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md),在同一个 `ctx.web` 服务上横跨**两项能力**(search 与 fetch),并拆分到多个包:接口([dsh-web](../../packages/web/web),`ctx.web` + 提供方注册表)、实现([dsh-web-search-exa](../../packages/web/web-search-exa)、[dsh-web-search-perplexity](../../packages/web/web-search-perplexity)、[dsh-web-search-deepseek](../../packages/web/web-search-deepseek)、[dsh-web-fetch-local](../../packages/web/web-fetch-local))与消费方([dsh-tool-web](../../packages/web/tool-web),即 `web_search`/`web_fetch` 工具 schema)。Web 是**一项可选能力**,不属于 agent loop 主干,因此其词汇定义在此而非 [core.md](core.md) 中。更换 search 提供方不会改变模型请求 query 的方式,更换 fetch 实现也不会改变模型请求 URL 的方式。 源码:[`packages/web/web/src/types.ts`](../../packages/web/web/src/types.ts) @@ -15,20 +15,37 @@ Web 访问 seam 是一个[能力 seam](../rfc/implemented/architecture/2026-06-2 面向模型的工具参数仅为一个 `query`;`maxResults` 是消费方自有的上限(`dsh-tool-web` 的 `searchMaxResults` 配置,默认 `8`),通过 seam 传递并在返回时强制执行——如果提供方返回超量,seam 截断 `sources[]` 并设置 `truncated`。 ```ts type-equiv +/** + * What one search-capable backend can return. The model-facing argument is just + * a query; `maxResults` is a `dsh-tool-web`-layer bound passed through unchanged + * and enforced on the way back by the seam (see {@link WebSearchResult}). + */ interface WebSearchRequest { readonly query: string /** * Upper bound on returned sources; the seam truncates to it. Omitted = no - * bound. `dsh-tool-web` always sets it. + * bound. `dsh-tool-web` always sets it. A provider whose API supports a + * result-count control (Exa's `numResults`) should apply it at the request + * layer as a cost/latency optimization; the seam enforces the bound + * regardless. */ readonly maxResults?: number } ``` ```ts type-equiv +/** + * Normalized search outcome. `content` is optional provider-generated answer + * text or summary (Exa returns none; Perplexity returns a generated answer). + * `sources[]` is the portable citation surface. `truncated` is set by the seam + * when it cut `sources[]` down to `maxResults`. + */ interface WebSearchResult { + /** Optional provider-generated answer text, search context, or summary. */ readonly content?: string + /** Citeable sources, already truncated to the request's `maxResults`. */ readonly sources: readonly WebSearchSource[] + /** True when the seam dropped sources to honor `maxResults`. */ readonly truncated: boolean } ``` @@ -36,10 +53,17 @@ interface WebSearchResult { `content` 是提供方可选生成的回答文本(Exa 和 DeepSeek 不返回;Perplexity 返回生成式回答)。`sources[]` 是可移植的引用表面。一个 source 必有 `url`;`title`/`snippet`/`publishedAt` 可选,因为并非每个提供方都返回它们——Perplexity 的引用可能只有 URL,强迫适配器编造其余字段会让 seam 说谎。`dsh-tool-web` 渲染时使用 `title ?? hostname(url)`。 ```ts type-equiv +/** + * One citeable source. A source always has a URL; `title`, `snippet`, and + * `publishedAt` are optional because not every provider returns them — forcing + * adapters to invent them would make the seam lie (Perplexity citations may be + * URL-only). `dsh-tool-web` renders `title ?? hostname(url)` for display. + */ interface WebSearchSource { readonly url: string readonly title?: string readonly snippet?: string + /** Publication/crawl timestamp as a provider-supplied ISO-8601 string. */ readonly publishedAt?: string } ``` @@ -47,6 +71,12 @@ interface WebSearchSource { ## 抓取请求与结果 ```ts type-equiv +/** + * What one fetch-capable backend is asked to retrieve. The request deliberately + * omits timeout, format, prompt, and extraction controls: cancellation is a + * direct execution argument, while presentation and higher-level LLM concerns + * belong outside safe retrieval. + */ interface WebFetchRequest { readonly url: string } @@ -55,10 +85,20 @@ interface WebFetchRequest { HTTP 状态码是被抓取资源状态的一部分,不自动视为失败:成功的网络抓取返回 `404`/`500` 时,仍产出一个带状态码和有界解码 body 的 `WebFetchResult`。`url` 是经过允许的重定向后的最终 URL。`WebError` 仅用于无法安全获取或表示资源的情况。 ```ts type-equiv +/** + * Normalized fetch outcome. A successful network fetch of a non-2xx response is + * a result, not an error: the status code is part of the fetched resource + * state. {@link WebError} is reserved for failures to safely retrieve or + * represent the resource. + */ interface WebFetchResult { + /** The final URL after allowed redirects (the request URL is in the request). */ readonly url: string + /** HTTP status code of the fetched response. */ readonly statusCode: number + /** Decoded body, classified by content kind. */ readonly body: WebFetchBody + /** True when the provider capped the decoded body. */ readonly truncated: boolean } ``` @@ -66,6 +106,15 @@ interface WebFetchResult { `WebFetchBody` 是 `dsh-web` 拥有的**封闭**可辨识联合类型(不是可合并扩展的 map):提供方解码 kind,`dsh-tool-web` 渲染它,因此新增一个 kind 是已知包之间的协调变更,而非插件扩展。消费方对 `kind` 做 `switch` 并以 `default: assertNever(...)` 结尾,所以新增 kind 会在每个消费方处编译失败,直到被处理。即使各分支当前字段一致,每个分支仍保持独立的对象字面量,为将来分支特有字段留出空间(例如未来 `pdf` body 的 `pageCount`)。 ```ts type-equiv +/** + * The decoded body of a fetched resource. A CLOSED discriminated union owned by + * `dsh-web`: the provider decodes the kind and `dsh-tool-web` renders it, so a + * new kind is a coordinated change across known packages, not a plugin + * extension. Consumers `switch` on `kind` ending in `default: assertNever(...)` + * so adding a kind breaks compilation at every consumer until handled. Each arm + * stays its own object literal even where fields coincide today, leaving room + * for arm-specific fields later (a `pdf` body's `pageCount`). + */ type WebFetchBody = | { readonly kind: 'html'; readonly content: string } | { readonly kind: 'text'; readonly content: string } diff --git a/docs/core-data-structures/workflow.i18n.yaml b/docs/core-data-structures/workflow.i18n.yaml index 19a2d0db9e..cb0bf7e961 100644 --- a/docs/core-data-structures/workflow.i18n.yaml +++ b/docs/core-data-structures/workflow.i18n.yaml @@ -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 -workflow.md: 1571723c172fe851e89550e4ed8588ddb14088a0 -workflow.zh.md: 553d8fa8122b3c9f0cd29840cb2a72d9d5ae6e83 +workflow.md: 8d271b89e71de6f6bef548aa8da61402ef9ada6e +workflow.zh.md: 335f08cefe057bdc0d0f78a90e8301d5e457aae7 diff --git a/docs/core-data-structures/workflow.zh.md b/docs/core-data-structures/workflow.zh.md index 553d8fa812..335f08cefe 100644 --- a/docs/core-data-structures/workflow.zh.md +++ b/docs/core-data-structures/workflow.zh.md @@ -4,20 +4,44 @@ 工作流 seam:一个 agent(智能体)运行由模型编写的编排脚本(SCRIPT),扇出 subagent。与 [subagent](subagent.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此处而非 [core.md](core.md)。与 subagent 注册表不同,它采用 bash 形态:每个上下文只有一个引擎实现提供 `ctx.workflows`;没有命名提供方注册表(第二个引擎是插件替换,而非共存)。 -接口:[dsh-workflow](../../packages/workflow/workflow)(`ctx.workflows` + 下文词汇)。实现是 [dsh-workflow-workerthread](../../packages/workflow/workflow-workerthread)(一个 `node:worker_threads` 引擎:每次运行一个 worker,脚本的 vm 上下文在其中执行);面向模型的消费方是 [dsh-tool-workflow](../../packages/workflow/tool-workflow)。提案与设计动机见[动态工作流 RFC](../rfc/implemented/feature/2026-07-05-dynamic-workflows.md)。 +接口:[dsh-workflow](../../packages/workflow/workflow)(`ctx.workflows` + 下文词汇)。实现是 [dsh-workflow-workerthread](../../packages/workflow/workflow-workerthread)(一个 `node:worker_threads` 引擎——每个 run 一个 worker,脚本的 vm context 位于其中);面向模型的消费方是 [dsh-tool-workflow](../../packages/workflow/tool-workflow)。提案与设计理由见 [dynamic-workflows Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md)。 源码:[`packages/workflow/workflow/src/types.ts`](../../packages/workflow/workflow/src/types.ts) ## 启动请求 -调用方启动一次运行时提交的内容。工具层从模型的 `{ script, meta, args }` 调用加上发起调用的 agent 构建此请求;`meta` 和 `args` 是纯 JSON 数据(引擎在任何代码执行之前对 `meta` 做形状校验,不通过则立即报错:永远不会为了获取 meta 而执行脚本文本)。`parent` 是必填项:脚本 spawn 的每个子 agent 都归属于它(cwd、血统与深度通过 [subagent seam](subagent.md) 传递)。 +调用方启动 run 时提出的请求。普通 workflow 工具根据模型的 `{ script, meta, args }` 调用与发起调用的 agent 构建它;专用消费方还可以为该 run 选择一个引擎级 `subagentProvider` 并调低 `maxTotalAgents`,但脚本无法观察或替换这两项策略。`meta` 与 `args` 是普通 JSON 数据(引擎会对 `meta` 做形状校验,并在任何内容运行前大声拒绝——绝不会通过求值脚本文本来获取它)。`parent` 是必填字段——脚本生成的每个子 agent 都归属于它(cwd、谱系与深度通过 [subagent seam](subagent.md) 流转)。 ```ts type-equiv +/** + * What a caller asks for when starting a workflow run. `meta` and `args` are + * plain JSON DATA by the seam contract (the tool builds both from the model's + * schema-validated call; the engine validates `meta`'s shape and rejects loud + * before anything runs) — an engine never evaluates script text to obtain + * them. `parent` is REQUIRED — every `agent()` the script spawns is + * attributed to it (cwd, lineage, depth flow through the subagent seam). + */ interface WorkflowStartRequest { + /** The plain-JS script body (top-level await allowed; ends with `return <json-value>`). */ script: string + /** The workflow's identity block, as plain JSON data (shape-validated by the engine). */ meta: WorkflowMeta + /** Optional input exposed verbatim to the script as the `args` global. */ args?: unknown + /** + * Optional engine-wide child-provider override for this run. The workflow + * script cannot observe or replace it; omission uses the engine's configured + * provider. + */ + subagentProvider?: string + /** + * Optional per-run total-child ceiling. Implementations reject values above + * their deployment ceiling before publishing the run. + */ + maxTotalAgents?: number + /** The agent on whose behalf the run executes (parent of every child). */ parent: Agent + /** Cancels the run when aborted (the tool's `exec.signal`). */ signal?: AbortSignal } ``` @@ -27,10 +51,21 @@ interface WorkflowStartRequest { 作为数据附在启动请求上的身份块(工具的 `meta` 参数;字段词汇与 Claude Code 动态工作流的 meta 块一致)。`phases` 仅用于进度展示:`phase()` 调用与标题匹配,供观察者使用;不暗示任何执行结构。 ```ts type-equiv +/** + * The script's identity block, provided as plain JSON data alongside the + * script body (the model-facing tool carries it as its `meta` parameter) and + * validated by the engine before the body runs. `name`/`description` are + * required; the rest is optional annotation. The field vocabulary matches the + * Claude Code dynamic-workflows meta block. + */ interface WorkflowMeta { + /** Short kebab-case workflow name (display + persistence key). */ name: string + /** One-line description of what the workflow does. */ description: string + /** Optional guidance on when this workflow applies (shown in listings). */ whenToUse?: string + /** Optional phase declarations matched by `phase()` calls. */ phases?: WorkflowPhase[] } ``` @@ -40,10 +75,27 @@ interface WorkflowMeta { 一次运行的结果,由 `WorkflowRun.result` resolve。`value` 是脚本的物化返回值——纯宿主域 JSON 数据(脚本无返回值时为 `null`)——仅在 `completed` 时有意义。`stopReason` 是封闭联合类型(引擎所有;消费方可穷举):`completed` | `cancelled` | `error`。非 `completed` 的原因在 `error` 中携带失败信息,消费方将其映射为 `isError` 工具结果,而非把部分输出当作成功上报。 ```ts type-equiv +/** + * The outcome of one run, resolved by {@link WorkflowRun.result}. `value` is + * the script's materialized return value (plain host-realm JSON data; `null` + * when the script returned `undefined`) — meaningful only for `completed`. + * A non-`completed` reason carries the failure in `error`; the consumer maps + * it to an `isError` tool result rather than reporting partial output. + */ interface WorkflowResult { + /** The script's return value (host JSON data; `null` for no return). */ value: unknown + /** Why the run settled. */ stopReason: WorkflowStopReason + /** The failure message (present iff `stopReason` is not `completed`). */ error?: string + /** + * How many `agent()` calls the run accepted over its whole lifetime. On a + * graceful settlement this is the script-side count (calls still queued for + * a concurrency slot included); on a termination path (grace force-settle, + * worker death) it degrades to the host-observed count — calls queued + * inside a terminated script are unknowable then. + */ agentsStarted: number } ``` @@ -53,11 +105,20 @@ interface WorkflowResult { 脚本执行期间消费方持有的句柄。消费方 await `result`,可中途 `cancel`,且必须在每条路径上 `dispose`。`result` 不会 reject:脚本失败以 `stopReason: 'error'` resolve;一旦运行被取消,即使脚本本身永不 settle,它也会在引擎的有界宽限期内 settle(引擎强制以 `cancelled` settle;worker-thread 引擎随后终止脚本的 worker),因此消费方 await `result` 不会在取消后卡死。`dispose()` = cancel + 有界 settle + 等待子 agent 停稳;它不会因脚本卡死而挂起。 ```ts type-equiv +/** + * Holder-owned live workflow. `result` never rejects and settles within the + * engine's cancellation grace; failures resolve through `stopReason`. Consumers + * may cancel and must call idempotent `dispose()` on every path to await bounded + * script settlement and child quiescence. + */ interface WorkflowRun { readonly id: WorkflowRunId + /** The validated meta block (available before the body runs). */ readonly meta: WorkflowMeta readonly result: Promise<WorkflowResult> + /** Cancel the run: children abort, pending hooks reject, the script dies at its next await (or is force-settled at the grace). */ cancel(reason?: string): void + /** Cancel + bounded-grace settle; safe to call on every path (idempotent). */ dispose(): Promise<void> } ``` diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml b/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml index 2affb91142..bc2b7d097a 100644 --- a/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml +++ b/docs/postmortem/0001-acp-default-export-drops-inject.i18n.yaml @@ -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 -0001-acp-default-export-drops-inject.md: 6a71d8d7ef72e3110a99774b180f3de7115ef622 -0001-acp-default-export-drops-inject.zh.md: d12feca2eb1a35b68e191945562aabe25e043e37 +0001-acp-default-export-drops-inject.md: ab3efc880cb5290dc149b6bacb276ccf581968c1 +0001-acp-default-export-drops-inject.zh.md: caf60dc086e892af4ae3563b0bf073c7e6373602 diff --git a/docs/postmortem/0001-acp-default-export-drops-inject.zh.md b/docs/postmortem/0001-acp-default-export-drops-inject.zh.md index d12feca2eb..caf60dc086 100644 --- a/docs/postmortem/0001-acp-default-export-drops-inject.zh.md +++ b/docs/postmortem/0001-acp-default-export-drops-inject.zh.md @@ -26,7 +26,7 @@ ACP 服务器无法创建或加载任何一个会话——而这正是编辑器 ## 根因 #1——`export default apply` 丢弃了插件的 `inject`(导致 `session/new` 崩溃) -`packages/ui/acp/src/index.ts` 是一个*命名空间插件*:它将 `name`、`inject`、`Config` 和 `apply` 作为独立的命名导出——与仓库中其他所有插件(`invariants`、`llm-deepseek`、`tool-bash`、`stdio-chat` 等)形状相同。但它*还*多了一行其他插件都没有的代码: +`packages/ui/acp/src/index.ts` 是一个*命名空间插件*:它将 `name`、`inject`、`Config` 和 `apply` 作为独立的命名导出——与仓库中其他所有插件(`invariants`、`llm-deepseek`、`tool-bash`、`tui` 等)形状相同。但它*还*多了一行其他插件都没有的代码: ```ts ignore-check export const name = 'acp' diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml index 34b22884f8..21f7000078 100644 --- a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.i18n.yaml @@ -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 -0002-js-expression-disabled-filesystem-tools.md: 43e57a6bd1b68f38c47eeda3c3abb8455024b350 -0002-js-expression-disabled-filesystem-tools.zh.md: ce091a4f6bd19dd9ccb9100583e92589998a1906 +0002-js-expression-disabled-filesystem-tools.md: 30ff9d920821a8d55c4bea5f120f1aeeca6634b3 +0002-js-expression-disabled-filesystem-tools.zh.md: d171ce7fe0fea830375f7494be2aac38630c8d6a diff --git a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md index ce091a4f6b..d171ce7fe0 100644 --- a/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +++ b/docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md @@ -6,7 +6,7 @@ Status: resolved ## 概要 -ACP(Agent Client Protocol)示例试图通过 `disabled: !!js ...` 有条件地启用文件系统插件,但 Cordis 仅在插件 `config` 内部对 JavaScript 表达式求值。原始的表达式对象为 truthy,因此文件系统栈始终处于禁用状态。快照刷新随后将 `UNKNOWN_TOOL` 结果接受为新的 golden 基准。修复方案改用显式的文件系统 overlay,并增加了静态配置守卫和快照结果守卫。 +ACP(Agent Client Protocol)示例试图通过 `disabled: !!js ...` 有条件地启用文件系统插件,但 Cordis 仅在插件 `config` 内部对 JavaScript 表达式求值。原始的表达式对象为 truthy,因此文件系统栈始终处于禁用状态。快照刷新随后将 `UNKNOWN_TOOL` 结果接受为新的预期输出。修复方案改用显式的文件系统 overlay,并增加了静态配置守卫和快照结果守卫。 ## 摘要 @@ -24,7 +24,7 @@ Cordis Include 将每个 `!!js` 标量解析为一个表达式对象。Loader - PR #261 整合了 ACP 组合并刷新了文件系统快照,同时引入了条件式文件系统入口。 - 所有单元测试、覆盖率、快照、文档、构建和 hygiene 检查均通过。 -- 对刷新后的文件系统 golden 的评审发现了通用的失败卡片和结构化的 `UNKNOWN_TOOL` 结果。 +- 对刷新后的文件系统预期输出的评审发现了通用的失败卡片和结构化的 `UNKNOWN_TOOL` 结果。 - 一次真实的 Loader 启动确认:每个 `disabled` 值仍为表达式对象,每个文件系统 fiber 均未创建。 ## 根因 @@ -38,10 +38,10 @@ Cordis Include 将每个 `!!js` 标量解析为一个表达式对象。Loader - 文件系统场景启动 `fs.cordis.yml`:一个显式的固定全权限 overlay,配有对应的 replay 配置和独立的 request-header 类。 - [`AGENTS.md`](../../AGENTS.md) 与 [Cordis 入门](../cordis-primer.md#loader-configuration)明确说明 `!!js` 仅在插件 `config` 内有效,条件式组合应使用 overlay。 - `verify-cordis-config` 解析仓库中的 Cordis YAML,拒绝 Loader 入口元数据中的表达式节点(包括 include patch 和插入的入口)。 -- `dsh-acp-snapshot` 在新鲜运行和已提交的会话 fixture 中拒绝结构化的 `UNKNOWN_TOOL` 结果,防止其成为被接受的 golden 基准。 +- `dsh-acp-snapshot` 在新鲜运行和已提交的会话 fixture 中拒绝结构化的 `UNKNOWN_TOOL` 结果,防止其被提交为预期输出。 ## 教训 - 语法上被接受的配置值不一定在该位置被求值;应记录并验证插值边界。 -- 快照刷新是 fixture 的生产过程,不是正确性审查。诸如已注册工具缺失这类语义上不可能的结果,需要独立于 golden 的断言。 +- 快照刷新是 fixture 的生产过程,不是正确性审查。诸如已注册工具缺失这类语义上不可能的结果,需要独立于预期输出的断言。 - 权限控制只应描述其实际管辖的能力。组合时的文件系统访问无法安全地跟随运行时的 bash-only 预设。 diff --git a/docs/postmortem/README.i18n.yaml b/docs/postmortem/README.i18n.yaml index 1fb6e7d64f..6673537b87 100644 --- a/docs/postmortem/README.i18n.yaml +++ b/docs/postmortem/README.i18n.yaml @@ -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 -README.md: 4dc59e4f5e70f51c4c0baa64fbe34b213f2a7c3d -README.zh.md: b959566d6e2659957d9b6b121303cc4d0e7c4c4e +README.md: df0e2fcb8540aeed005153dbecc451d781ca5ff1 +README.zh.md: 1b099919720867dbc8b6766121bff22d3f221c4c diff --git a/docs/postmortem/README.zh.md b/docs/postmortem/README.zh.md index b959566d6e..1b09991972 100644 --- a/docs/postmortem/README.zh.md +++ b/docs/postmortem/README.zh.md @@ -4,7 +4,7 @@ 事故复盘:一个 bug 到达了它不该到达的地方(真实用户、已合并的 PR(Pull Request)、已发布的版本),值得关注的是*为什么我们的流程放过了它*,而不仅仅是那一行修复。 -事故复盘不是 [RFC](../rfc/README.md)(RFC 记录一个经过深思熟虑的设计决策及其被否决的替代方案,或提出未来工作)。它是一份回顾性的失败记录:什么坏了、机制是什么、为什么每道安全网都没拦住、以及加了哪些具体的防护措施使同类 bug 下次能被显式暴露。 +事故复盘不是 [Agent Note(agent 决策记录)](../../.agents/notes/README.md)(Agent Note 记录一个经过深思熟虑的设计决策及其被否决的替代方案,或提出未来工作)。它是一份回顾性的失败记录:什么坏了、机制是什么、为什么每道安全网都没拦住、以及加了哪些具体的防护措施使同类 bug 下次能被显式暴露。 当一个 bug 满足以下条件时,请撰写事故复盘:**隐蔽**(机制不显而易见,即使是细心的工程师也得费力重新推导)、**系统性**(逃逸的原因是测试/工具/约定的缺口,而非一次性的笔误)、**重新发现的代价高**(它消耗了真实的调试时间,且下次还会如此)。请链接该事故复盘所推动建立的防护措施(测试、AGENTS.md 规则、ADR)。 diff --git a/scripts/type-equiv.manifest.json b/scripts/type-equiv.manifest.json index 2ac67aa892..12b3359f1e 100644 --- a/scripts/type-equiv.manifest.json +++ b/scripts/type-equiv.manifest.json @@ -131,7 +131,11 @@ "symbol": "Scope", "source": "packages/core/scope/src/index.ts" }, - { "doc": "docs/core-data-structures/scope.md", "symbol": "ScopeLayer", "source": "packages/core/scope/src/store.ts" }, + { + "doc": "docs/core-data-structures/scope.md", + "symbol": "ScopeLayer", + "source": "packages/core/scope/src/store.ts" + }, { "doc": "docs/core-data-structures/goal.md", "symbol": "GoalRef", @@ -284,7 +288,11 @@ "symbol": "SessionEventMap", "source": "packages/core/session/src/types.ts" }, - { "doc": "docs/core-data-structures/session.md", "symbol": "OutOfBandSessionEventMap", "source": "packages/core/session/src/types.ts" }, + { + "doc": "docs/core-data-structures/session.md", + "symbol": "OutOfBandSessionEventMap", + "source": "packages/core/session/src/types.ts" + }, { "doc": "docs/core-data-structures/session.md", "symbol": "EpochHeader", @@ -411,18 +419,61 @@ "symbol": "SessionEventTrace", "source": "packages/session-query/session-query/src/types.ts" }, - - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleProviderId", "source": "packages/session-title/session-title/src/index.ts" }, - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleModelProvenance", "source": "packages/session-title/session-title/src/index.ts" }, - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleSource", "source": "packages/session-title/session-title/src/index.ts" }, - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleEventData", "source": "packages/session-title/session-title/src/index.ts" }, - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleSnapshot", "source": "packages/session-title/session-title/src/index.ts" }, - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleLlmRequestEventData", "source": "packages/session-title/session-title-llm/src/index.ts" }, - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleUserMessage", "source": "packages/session-title/session-title/src/index.ts" }, - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleAutomaticMode", "source": "packages/session-title/session-title/src/index.ts" }, - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleProviderRequest", "source": "packages/session-title/session-title/src/index.ts" }, - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleProviderResult", "source": "packages/session-title/session-title/src/index.ts" }, - { "doc": "docs/core-data-structures/session-title.md", "symbol": "SessionTitleProvider", "source": "packages/session-title/session-title/src/index.ts" }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleProviderId", + "source": "packages/session-title/session-title/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleModelProvenance", + "source": "packages/session-title/session-title/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleSource", + "source": "packages/session-title/session-title/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleEventData", + "source": "packages/session-title/session-title/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleSnapshot", + "source": "packages/session-title/session-title/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleLlmRequestEventData", + "source": "packages/session-title/session-title-llm/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleUserMessage", + "source": "packages/session-title/session-title/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleAutomaticMode", + "source": "packages/session-title/session-title/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleProviderRequest", + "source": "packages/session-title/session-title/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleProviderResult", + "source": "packages/session-title/session-title/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-title.md", + "symbol": "SessionTitleProvider", + "source": "packages/session-title/session-title/src/index.ts" + }, { "doc": "docs/core-data-structures/tools.md", "symbol": "ToolDefinition", @@ -992,6 +1043,794 @@ "doc": "docs/core-data-structures/lsp.md", "symbol": "LspService", "source": "packages/lsp/lsp/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "Branded", + "source": "packages/util/brand/src/index.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "ContentBlockMap", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "AssistantProvenance", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "Message", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "MessageSourceMap", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "FinishReasonMap", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "LlmProviderInfo", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "LlmModelInfo", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "LlmModelContext", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "GenerateOptions", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "ToolSchema", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "LlmCallConfig", + "source": "packages/llm/llm/src/call-config.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "SessionEvent", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "AgentCancelCause", + "source": "packages/core/agent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "InjectOptions", + "source": "packages/core/agent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "Agent", + "source": "packages/core/agent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "HookContext", + "source": "packages/core/agent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "PromptDecision", + "source": "packages/core/agent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "ContinuationDecision", + "source": "packages/core/agent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "RequestError", + "source": "packages/core/agent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "RequestErrorDecision", + "source": "packages/core/agent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "ContinuationStop", + "source": "packages/core/agent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/core.zh.md", + "symbol": "SessionStartSource", + "source": "packages/core/agent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/scope.zh.md", + "symbol": "ScopeKey", + "source": "packages/core/scope/src/index.ts" + }, + { + "doc": "docs/core-data-structures/scope.zh.md", + "symbol": "Scoped", + "source": "packages/core/scope/src/index.ts" + }, + { + "doc": "docs/core-data-structures/scope.zh.md", + "symbol": "Scope", + "source": "packages/core/scope/src/index.ts" + }, + { + "doc": "docs/core-data-structures/scope.zh.md", + "symbol": "ScopeLayer", + "source": "packages/core/scope/src/store.ts" + }, + { + "doc": "docs/core-data-structures/system-prompt.zh.md", + "symbol": "AssembleContext", + "source": "packages/core/system-prompt/src/index.ts" + }, + { + "doc": "docs/core-data-structures/system-prompt.zh.md", + "symbol": "PromptSection", + "source": "packages/core/system-prompt/src/index.ts" + }, + { + "doc": "docs/core-data-structures/system-prompt.zh.md", + "symbol": "ToolProviderResult", + "source": "packages/core/system-prompt/src/index.ts" + }, + { + "doc": "docs/core-data-structures/llm-streaming.zh.md", + "symbol": "StreamChunk", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/llm-streaming.zh.md", + "symbol": "LlmFailure", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/llm-streaming.zh.md", + "symbol": "TokenUsage", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/llm-streaming.zh.md", + "symbol": "ContentBlockMap", + "source": "packages/llm/llm/src/types.ts" + }, + { + "doc": "docs/core-data-structures/llm-streaming.zh.md", + "symbol": "AppIdentity", + "source": "packages/llm/llm/src/attribution.ts" + }, + { + "doc": "docs/core-data-structures/llm-streaming.zh.md", + "symbol": "BlockAssembler", + "source": "packages/llm/llm/src/assembler.ts", + "projection": "public-api" + }, + { + "doc": "docs/core-data-structures/llm-streaming.zh.md", + "symbol": "LlmAdapter", + "source": "packages/llm/llm/src/index.ts", + "projection": "public-api" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "SessionEventMap", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "OutOfBandSessionEventMap", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "EpochHeader", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "TodoItem", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "SessionEvent", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "TurnTriggerMap", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "TurnEndReasonMap", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "SurfaceEventType", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "SurfaceOp", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "SurfaceIntent", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "SessionSurface", + "source": "packages/core/session/src/surface.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "SurfaceFoldReplacement", + "source": "packages/core/session/src/surface.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "SurfaceFoldResult", + "source": "packages/core/session/src/surface.ts" + }, + { + "doc": "docs/core-data-structures/session.zh.md", + "symbol": "Session", + "source": "packages/core/session/src/index.ts", + "projection": "public-api" + }, + { + "doc": "docs/core-data-structures/persistence.zh.md", + "symbol": "SessionHeader", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/persistence.zh.md", + "symbol": "CreateSessionOptions", + "source": "packages/core/session/src/types.ts" + }, + { + "doc": "docs/core-data-structures/persistence.zh.md", + "symbol": "SessionLocation", + "source": "packages/session-persistence/session-persistence/src/index.ts" + }, + { + "doc": "docs/core-data-structures/session-query.zh.md", + "symbol": "SessionEventSurface", + "source": "packages/session-query/session-query/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session-query.zh.md", + "symbol": "SessionRecord", + "source": "packages/session-query/session-query/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session-query.zh.md", + "symbol": "SessionEventRecord", + "source": "packages/session-query/session-query/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session-query.zh.md", + "symbol": "SessionLineageNode", + "source": "packages/session-query/session-query/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session-query.zh.md", + "symbol": "SessionLineageTrace", + "source": "packages/session-query/session-query/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session-query.zh.md", + "symbol": "SessionQueryErrorCode", + "source": "packages/session-query/session-query/src/config.ts" + }, + { + "doc": "docs/core-data-structures/session-query.zh.md", + "symbol": "SessionEventReadRequest", + "source": "packages/session-query/session-query/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session-query.zh.md", + "symbol": "SessionEventWindow", + "source": "packages/session-query/session-query/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session-query.zh.md", + "symbol": "SessionEventTraceRequest", + "source": "packages/session-query/session-query/src/types.ts" + }, + { + "doc": "docs/core-data-structures/session-query.zh.md", + "symbol": "SessionEventTrace", + "source": "packages/session-query/session-query/src/types.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "ToolDefinition", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "SchemaProp", + "source": "packages/core/tools/src/schema.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "SchemaSpec", + "source": "packages/core/tools/src/schema.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "InferArgs", + "source": "packages/core/tools/src/schema.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "ToolExecutionToken", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "ToolExecutionInput", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "ToolExecution", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "ToolDispatchExecution", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "ToolExecutionMode", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "ToolRunContext", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "ToolGuard", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "ToolRestriction", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "ToolExecutionResult", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "PreToolDecision", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "PostToolDecision", + "source": "packages/core/tools/src/index.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "StructuredScalar", + "source": "packages/core/tools/src/json-schema.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "StructuredSchemaType", + "source": "packages/core/tools/src/json-schema.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "StructuredSchemaNode", + "source": "packages/core/tools/src/json-schema.ts" + }, + { + "doc": "docs/core-data-structures/tools.zh.md", + "symbol": "StructuredOutputSchema", + "source": "packages/core/tools/src/json-schema.ts" + }, + { + "doc": "docs/core-data-structures/user-interaction.zh.md", + "symbol": "AskUserQuestionOption", + "source": "packages/ui/user-interaction/src/types.ts" + }, + { + "doc": "docs/core-data-structures/user-interaction.zh.md", + "symbol": "AskUserQuestionItem", + "source": "packages/ui/user-interaction/src/types.ts" + }, + { + "doc": "docs/core-data-structures/user-interaction.zh.md", + "symbol": "AskUserQuestionRequest", + "source": "packages/ui/user-interaction/src/index.ts" + }, + { + "doc": "docs/core-data-structures/user-interaction.zh.md", + "symbol": "AskUserQuestionAnswerItem", + "source": "packages/ui/user-interaction/src/types.ts" + }, + { + "doc": "docs/core-data-structures/user-interaction.zh.md", + "symbol": "AskUserQuestionAnswer", + "source": "packages/ui/user-interaction/src/types.ts" + }, + { + "doc": "docs/core-data-structures/user-interaction.zh.md", + "symbol": "UserInteractionProvider", + "source": "packages/ui/user-interaction/src/index.ts" + }, + { + "doc": "docs/core-data-structures/user-interaction.zh.md", + "symbol": "UserInteractionError", + "source": "packages/ui/user-interaction/src/index.ts" + }, + { + "doc": "docs/core-data-structures/approval.zh.md", + "symbol": "ApprovalRequestId", + "source": "packages/ui/user-approval/src/types.ts" + }, + { + "doc": "docs/core-data-structures/approval.zh.md", + "symbol": "ApprovalOutcome", + "source": "packages/ui/user-approval/src/types.ts" + }, + { + "doc": "docs/core-data-structures/approval.zh.md", + "symbol": "ApprovalPolicy", + "source": "packages/ui/user-approval/src/index.ts" + }, + { + "doc": "docs/core-data-structures/approval.zh.md", + "symbol": "ApprovalRequest", + "source": "packages/ui/user-approval/src/index.ts" + }, + { + "doc": "docs/core-data-structures/bash.zh.md", + "symbol": "DshEnvironmentKey", + "source": "packages/bash/bash/src/types.ts" + }, + { + "doc": "docs/core-data-structures/bash.zh.md", + "symbol": "DshEnvironment", + "source": "packages/bash/bash/src/types.ts" + }, + { + "doc": "docs/core-data-structures/bash.zh.md", + "symbol": "BashExecRequest", + "source": "packages/bash/bash/src/types.ts" + }, + { + "doc": "docs/core-data-structures/bash.zh.md", + "symbol": "BashExecSpec", + "source": "packages/bash/bash/src/types.ts" + }, + { + "doc": "docs/core-data-structures/bash.zh.md", + "symbol": "BashRunResult", + "source": "packages/bash/bash/src/types.ts" + }, + { + "doc": "docs/core-data-structures/bash.zh.md", + "symbol": "BashSandboxInfo", + "source": "packages/bash/bash/src/types.ts" + }, + { + "doc": "docs/core-data-structures/bash.zh.md", + "symbol": "CollectedOutput", + "source": "packages/bash/bash/src/types.ts" + }, + { + "doc": "docs/core-data-structures/bash.zh.md", + "symbol": "BashProcess", + "source": "packages/bash/bash/src/types.ts" + }, + { + "doc": "docs/core-data-structures/bash.zh.md", + "symbol": "BashProcessRead", + "source": "packages/bash/bash/src/types.ts" + }, + { + "doc": "docs/core-data-structures/sandbox.zh.md", + "symbol": "SandboxMode", + "source": "packages/sandbox/sandbox/src/index.ts" + }, + { + "doc": "docs/core-data-structures/sandbox.zh.md", + "symbol": "ConfinedSandboxMode", + "source": "packages/sandbox/sandbox/src/index.ts" + }, + { + "doc": "docs/core-data-structures/sandbox.zh.md", + "symbol": "SandboxExecutionPolicy", + "source": "packages/sandbox/sandbox/src/index.ts" + }, + { + "doc": "docs/core-data-structures/sandbox.zh.md", + "symbol": "SandboxEnforcement", + "source": "packages/sandbox/sandbox/src/index.ts" + }, + { + "doc": "docs/core-data-structures/sandbox.zh.md", + "symbol": "SandboxPolicy", + "source": "packages/sandbox/sandbox/src/index.ts" + }, + { + "doc": "docs/core-data-structures/sandbox.zh.md", + "symbol": "SandboxPolicyRequest", + "source": "packages/sandbox/sandbox-policy/src/index.ts" + }, + { + "doc": "docs/core-data-structures/sandbox.zh.md", + "symbol": "ConfinedArgv", + "source": "packages/sandbox/sandbox/src/index.ts" + }, + { + "doc": "docs/core-data-structures/code-runtime.zh.md", + "symbol": "CodeRunRequest", + "source": "packages/code-runtime/code-runtime/src/types.ts" + }, + { + "doc": "docs/core-data-structures/code-runtime.zh.md", + "symbol": "CodeRunResult", + "source": "packages/code-runtime/code-runtime/src/types.ts" + }, + { + "doc": "docs/core-data-structures/code-runtime.zh.md", + "symbol": "CodeBindingNamespace", + "source": "packages/code-runtime/code-runtime/src/types.ts" + }, + { + "doc": "docs/core-data-structures/code-runtime.zh.md", + "symbol": "CodeBindingFunction", + "source": "packages/code-runtime/code-runtime/src/types.ts" + }, + { + "doc": "docs/core-data-structures/code-runtime.zh.md", + "symbol": "CodeRunFailure", + "source": "packages/code-runtime/code-runtime/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsTarget", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsTargetKey", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsVersion", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsInfo", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsPathInfo", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsDirEntry", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsWriteIntent", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsWriteOutcome", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsEditRequest", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsEditOutcome", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsErrorCode", + "source": "packages/fs/fs/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FsPolicyExec", + "source": "packages/fs/fs-policy/src/types.ts" + }, + { + "doc": "docs/core-data-structures/filesystem.zh.md", + "symbol": "FileReadOutcome", + "source": "packages/fs/tool-fs/src/read-render.ts" + }, + { + "doc": "docs/core-data-structures/skills.zh.md", + "symbol": "SkillSource", + "source": "packages/skill/skill/src/index.ts" + }, + { + "doc": "docs/core-data-structures/skills.zh.md", + "symbol": "SkillResourceBase", + "source": "packages/skill/skill/src/index.ts" + }, + { + "doc": "docs/core-data-structures/skills.zh.md", + "symbol": "SkillSummary", + "source": "packages/skill/skill/src/index.ts" + }, + { + "doc": "docs/core-data-structures/skills.zh.md", + "symbol": "SkillCandidate", + "source": "packages/skill/skill/src/index.ts" + }, + { + "doc": "docs/core-data-structures/skills.zh.md", + "symbol": "SkillDefinition", + "source": "packages/skill/skill/src/index.ts" + }, + { + "doc": "docs/core-data-structures/skills.zh.md", + "symbol": "SkillRegistration", + "source": "packages/skill/skill/src/index.ts" + }, + { + "doc": "docs/core-data-structures/skills.zh.md", + "symbol": "SkillLookupOptions", + "source": "packages/skill/skill/src/index.ts" + }, + { + "doc": "docs/core-data-structures/skills.zh.md", + "symbol": "SkillProvider", + "source": "packages/skill/skill/src/index.ts" + }, + { + "doc": "docs/core-data-structures/skills.zh.md", + "symbol": "Config", + "source": "packages/skill/skill/src/index.ts" + }, + { + "doc": "docs/core-data-structures/compaction.zh.md", + "symbol": "CompactionResult", + "source": "packages/compact/compact/src/types.ts" + }, + { + "doc": "docs/core-data-structures/compaction.zh.md", + "symbol": "CompactionTrigger", + "source": "packages/compact/compact/src/index.ts" + }, + { + "doc": "docs/core-data-structures/compaction.zh.md", + "symbol": "PrunedEntry", + "source": "packages/compact/compact-tool-result-prune/src/types.ts" + }, + { + "doc": "docs/core-data-structures/compaction.zh.md", + "symbol": "PruneResult", + "source": "packages/compact/compact-tool-result-prune/src/types.ts" + }, + { + "doc": "docs/core-data-structures/subagent.zh.md", + "symbol": "SubagentCapabilities", + "source": "packages/subagent/subagent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/subagent.zh.md", + "symbol": "SubagentStartRequest", + "source": "packages/subagent/subagent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/subagent.zh.md", + "symbol": "SubagentResult", + "source": "packages/subagent/subagent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/subagent.zh.md", + "symbol": "SubagentStopReasonMap", + "source": "packages/subagent/subagent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/subagent.zh.md", + "symbol": "SubagentRun", + "source": "packages/subagent/subagent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/subagent.zh.md", + "symbol": "SubagentProvider", + "source": "packages/subagent/subagent/src/types.ts" + }, + { + "doc": "docs/core-data-structures/web.zh.md", + "symbol": "WebSearchRequest", + "source": "packages/web/web/src/types.ts" + }, + { + "doc": "docs/core-data-structures/web.zh.md", + "symbol": "WebSearchResult", + "source": "packages/web/web/src/types.ts" + }, + { + "doc": "docs/core-data-structures/web.zh.md", + "symbol": "WebSearchSource", + "source": "packages/web/web/src/types.ts" + }, + { + "doc": "docs/core-data-structures/web.zh.md", + "symbol": "WebFetchRequest", + "source": "packages/web/web/src/types.ts" + }, + { + "doc": "docs/core-data-structures/web.zh.md", + "symbol": "WebFetchResult", + "source": "packages/web/web/src/types.ts" + }, + { + "doc": "docs/core-data-structures/web.zh.md", + "symbol": "WebFetchBody", + "source": "packages/web/web/src/types.ts" + }, + { + "doc": "docs/core-data-structures/workflow.zh.md", + "symbol": "WorkflowStartRequest", + "source": "packages/workflow/workflow/src/types.ts" + }, + { + "doc": "docs/core-data-structures/workflow.zh.md", + "symbol": "WorkflowMeta", + "source": "packages/workflow/workflow/src/types.ts" + }, + { + "doc": "docs/core-data-structures/workflow.zh.md", + "symbol": "WorkflowResult", + "source": "packages/workflow/workflow/src/types.ts" + }, + { + "doc": "docs/core-data-structures/workflow.zh.md", + "symbol": "WorkflowRun", + "source": "packages/workflow/workflow/src/types.ts" } ] } From c701fad75d0b4387b38e304541a8006df5ed9639 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:02:10 +0800 Subject: [PATCH 094/368] docs(i18n): sync session durability translation --- docs/core-data-structures/session.i18n.yaml | 4 ++-- docs/core-data-structures/session.zh.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/core-data-structures/session.i18n.yaml b/docs/core-data-structures/session.i18n.yaml index 8f2f0b2f8a..c60415915a 100644 --- a/docs/core-data-structures/session.i18n.yaml +++ b/docs/core-data-structures/session.i18n.yaml @@ -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 -session.md: d3c6ab65df29ef0df504a0a01219e36ebad8e8fd -session.zh.md: 7d5e03f6b8d74e7b2dc0097acb1f5f78f6d3af6e +session.md: d6bdc4bfc523cdeb8036fd32b6b60e90ec51f678 +session.zh.md: ad9ed471185350603976d4baffa9e56bf09c831a diff --git a/docs/core-data-structures/session.zh.md b/docs/core-data-structures/session.zh.md index 7d5e03f6b8..ad9ed47118 100644 --- a/docs/core-data-structures/session.zh.md +++ b/docs/core-data-structures/session.zh.md @@ -530,6 +530,6 @@ interface TurnEndReasonMap { ## 持久性契约 -持久化后端依赖的契约如下:持久日志原样保存每个事件,**包括** `assistant/chunk`;`seq` 必须连续,因此不能从规范日志中过滤分片。所有 `event.data` 都必须可序列化为 JSON;`Session.append` 会从源头强制这一要求(遇到不可序列化数据时抛出),因此错误事件绝不会进入日志,`session.events` 始终与后端可持久化的内容一致。新增携带不可序列化数据的事件类型,或破坏会话不变式配套插件所检查的轮次/步骤嵌套,会构成磁盘格式的破坏性变更。 +持久化后端依赖的契约如下:持久日志无损保存每个事件,**包括** `assistant/chunk`;`seq` 必须连续,因此不能从规范日志中过滤分片。后端可以为事件批次选择自己的存储编码,只要 `load` 返回与追加时完全一致的事件即可(JSONL 后端可选启用的打包分片行就是此类编码;见 [persistence.md](persistence.md))。所有 `event.data` 都必须可序列化为 JSON;`Session.append` 会从源头强制这一要求(遇到不可序列化数据时抛出),因此错误事件绝不会进入日志,`session.events` 始终与后端可持久化的内容一致。新增携带不可序列化数据的事件类型,或破坏会话不变式配套插件所检查的轮次/步骤嵌套,会构成磁盘格式的破坏性变更。 消费此契约的后端见 [persistence.md](persistence.md)。 From 342e94d2d0462b1bae72064d1e9f13ecb929604a Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:04:46 +0800 Subject: [PATCH 095/368] fix(schema): use inferred PTY presentation args --- packages/pty/tool-pty/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pty/tool-pty/src/index.ts b/packages/pty/tool-pty/src/index.ts index f145102dea..b12db3a277 100644 --- a/packages/pty/tool-pty/src/index.ts +++ b/packages/pty/tool-pty/src/index.ts @@ -195,7 +195,7 @@ export function apply(ctx: Context): void { const result = await ctx.pty.signal(requireAgent(exec.agent), sessionId(args), args.signal) return textResult(`delivered ${args.signal} to foreground process group ${result.targetPgid}`) }, - presentCall: args => ({ card: 'generic', title: `Signal terminal ${(args as SignalArgs).sessionId}`, kind: 'execute', rawInput: args }), + presentCall: args => ({ card: 'generic', title: `Signal terminal ${args.sessionId}`, kind: 'execute', rawInput: args }), })) ctx.tools.register(defineTool({ From a03ed8d60b66b1ab44a816b304853b751158775f Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:08:22 +0800 Subject: [PATCH 096/368] test(schema): refresh PTY tool header fixture --- .../snapshots/pty-tools/tool-schemas.expected.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/acp-agent/tests/snapshots/pty-tools/tool-schemas.expected.json b/examples/acp-agent/tests/snapshots/pty-tools/tool-schemas.expected.json index d466996ed1..529b1419da 100644 --- a/examples/acp-agent/tests/snapshots/pty-tools/tool-schemas.expected.json +++ b/examples/acp-agent/tests/snapshots/pty-tools/tool-schemas.expected.json @@ -11,6 +11,7 @@ "description": "Questions to ask the user before continuing.", "items": { "type": "object", + "additionalProperties": true, "properties": { "id": { "type": "string", @@ -29,6 +30,7 @@ "description": "Optional choices to show the user. If you recommend one, put it first and append \"(Recommended)\" to that label.", "items": { "type": "object", + "additionalProperties": true, "properties": { "label": { "type": "string", @@ -494,6 +496,7 @@ "description": "The COMPLETE task list, replacing any previous list.", "items": { "type": "object", + "additionalProperties": true, "properties": { "content": { "type": "string", @@ -568,7 +571,7 @@ }, { "name": "workflow", - "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", + "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.", "parameters": { "type": "object", "properties": { @@ -579,6 +582,7 @@ "meta": { "type": "object", "description": "The workflow identity block (plain JSON — never code).", + "additionalProperties": true, "properties": { "name": { "type": "string", @@ -597,6 +601,7 @@ "description": "Optional phase declarations matched by phase() calls.", "items": { "type": "object", + "additionalProperties": true, "properties": { "title": { "type": "string", @@ -628,7 +633,8 @@ }, "args": { "type": "object", - "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})." + "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).", + "additionalProperties": true } }, "required": [ From 90ac883512636aecfe9cda25a66c99ca1c0e73ba Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:17:53 +0800 Subject: [PATCH 097/368] fix(pty): close retained lifecycle review gaps --- docs/config-catalog.md | 2 +- packages/pty/pty-local/README.md | 4 +- packages/pty/pty-local/src/index.ts | 46 +++++++---- packages/pty/pty-local/src/session.ts | 29 +++++-- packages/pty/pty-local/tests/index.spec.ts | 80 ++++++++++++------- packages/pty/pty-local/tests/session.spec.ts | 22 +++++ packages/tasks/tool-tasks/src/index.ts | 12 ++- .../tasks/tool-tasks/tests/tool-tasks.spec.ts | 10 +++ 8 files changed, 149 insertions(+), 56 deletions(-) diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 0577d29ad9..4e1dcae987 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -803,7 +803,7 @@ Source: [`packages/plan/plan-mode/src/index.ts:57`](../packages/plan/plan-mode/s ## `@deepseek-ai/dsh-pty-local` -Requires: `agents` · `pty` · `sandbox` · `sandboxPolicy` +Requires: `pty` · `sandbox` · `sandboxPolicy` ```ts config-catalog /** Public plugin configuration. */ diff --git a/packages/pty/pty-local/README.md b/packages/pty/pty-local/README.md index 32b2721074..34e3beadec 100644 --- a/packages/pty/pty-local/README.md +++ b/packages/pty/pty-local/README.md @@ -4,11 +4,11 @@ Local `node-pty` backend for `ctx.pty`. It starts an interactive shell under the ## Plugin (`pty-local`) -The plugin injects `agents`, `pty`, `sandbox`, and `sandboxPolicy`, then registers the configured backend type (`shell`). `danger-full-access` starts the shell directly; confined modes wrap the exact shell argv through `ctx.sandbox`. The effective session mode is resolved at spawn. A change to a different effective mode is rejected before its `sandbox/mode` event commits while that owner has an open PTY or a spawn in progress; wait for creation to settle and close the sessions before changing modes, so a terminal opened with wider access cannot survive a downgrade. +The plugin injects `pty`, `sandbox`, and `sandboxPolicy`, then registers the configured backend type (`shell`). `danger-full-access` starts the shell directly; confined modes wrap the exact shell argv through `ctx.sandbox`. The effective session mode is resolved at spawn. A change to a different effective mode is rejected before its `sandbox/mode` event commits while that owner has an open PTY or a spawn in progress; the fence is attached to the exact owner and therefore outlives a local-provider reload that retains existing sessions. Wait for creation to settle and close the sessions before changing modes, so a terminal opened with wider access cannot survive a downgrade. Linux readiness combines a foreground-verified private bash prompt marker, foreground-process-group syscall inspection, silence fallback, and absolute timeout. macOS uses the verified prompt marker plus silence/timeout because it has no `/proc` syscall surface. A marker is not ready until printable prompt text arrives, including when the OSC marker and `PS1` are split across data callbacks. Unrecognized or unreadable process state is never a positive exact-idle signal. During unpublished startup, a fallback requires observed output; zero-output silence cannot publish an empty session, and timeout rejects the spawn. Incomplete terminal-control sequences are bounded by `maxReadBytes` and discarded through their terminator after crossing that limit; a trailing carriage return is carried across callbacks so split CRLF becomes one newline. -Send cancellation resolves the current foreground process group and delivers a real `SIGINT`; it never emulates interruption by writing `\x03`, so raw-mode programs remain cancellable. Close sends `SIGTERM` to descendants, waits, rescans and sends `SIGKILL` to the remaining tree, verifies that descendants left the process table while the shell can still reap them, and only then stops the shell. A survivor failure does not cache a permanently rejected close; a later close retries the teardown. +Send cancellation resolves the current foreground process group and delivers a real `SIGINT`; it never emulates interruption by writing `\x03`, so raw-mode programs remain cancellable. Close sends `SIGTERM` to descendants, waits, then sends `SIGKILL` to the union of captured survivors and newly scanned descendants so reparenting cannot hide a process from teardown. It verifies that every retained identity left the process table while the shell can still reap it and only then stops the shell. A survivor failure does not cache a permanently rejected close; a later close retries the teardown. ## Model Experience diff --git a/packages/pty/pty-local/src/index.ts b/packages/pty/pty-local/src/index.ts index 706a1bba7a..db4de5de28 100644 --- a/packages/pty/pty-local/src/index.ts +++ b/packages/pty/pty-local/src/index.ts @@ -7,6 +7,7 @@ import { Context } from 'cordis' import * as nodePty from 'node-pty' import type { IPtyForkOptions } from 'node-pty' +import type { Agent } from '@deepseek-ai/dsh-agent' import type { Session, SessionEvent } from '@deepseek-ai/dsh-session' import type { PtyBackend, PtyBackendSpawnSpec } from '@deepseek-ai/dsh-pty' import type { SandboxMode } from '@deepseek-ai/dsh-sandbox' @@ -21,10 +22,37 @@ export type { Config as PtyLocalConfig } from './config.ts' /** Cordis plugin name. */ export const name = 'pty-local' -/** Required services: owner/PTY registries plus the one shared confinement policy. */ -export const inject = ['agents', 'pty', 'sandbox', 'sandboxPolicy'] +/** Required services: PTY registry plus the one shared confinement policy. */ +export const inject = ['pty', 'sandbox', 'sandboxPolicy'] const SENSITIVE_ENV_PATTERN = /KEY|SECRET|TOKEN/i +interface SandboxModeFenceState { + pty: Context['pty'] + sandboxPolicy: Context['sandboxPolicy'] +} + +const sandboxModeFences = new WeakMap<Agent, SandboxModeFenceState>() + +function ensureSandboxModeFence(ctx: Context, owner: Agent): void { + const existing = sandboxModeFences.get(owner) + if (existing !== undefined) { + existing.pty = ctx.pty + existing.sandboxPolicy = ctx.sandboxPolicy + return + } + const state: SandboxModeFenceState = { pty: ctx.pty, sandboxPolicy: ctx.sandboxPolicy } + sandboxModeFences.set(owner, state) + owner.ctx.on('internal/dispatch', (_mode, eventName, args) => { + if (eventName !== 'session/event') return + const [session, event] = args as [Session, SessionEvent] + if (session !== owner.session || event.type !== 'sandbox/mode') return + const currentMode = effectiveSandboxMode(session.events) ?? state.sandboxPolicy.defaultMode + if (event.data.mode === currentMode || !state.pty.hasOwnerActivity(owner)) return + throw new Error( + `cannot change sandbox mode from "${currentMode}" to "${event.data.mode}" while persistent terminal sessions are open or being created; wait for creation to settle and close them first`, + ) + }, { global: true }) +} function childEnvironment(spec: PtyBackendSpawnSpec): NodeJS.ProcessEnv { const env: NodeJS.ProcessEnv = {} @@ -75,6 +103,7 @@ export class LocalPtyBackend implements PtyBackend { async spawn(spec: PtyBackendSpawnSpec): Promise<LocalPtySession> { spec.signal?.throwIfAborted() + ensureSandboxModeFence(this.ctx, spec.owner) const argv = spawnArgv(this.ctx, this.config, spec) const file = argv[0] if (file === undefined) throw new Error('pty-local: sandbox returned empty argv') @@ -106,17 +135,4 @@ export function apply(ctx: Context, config: Config): void { validateConfig(config) const inspector = createProcessInspector() ctx.pty.registerBackend(new LocalPtyBackend(ctx, config, inspector)) - ctx.on('internal/dispatch', (_mode, eventName, args) => { - if (eventName !== 'session/event') return - const [session, event] = args as [Session, SessionEvent] - if (event.type !== 'sandbox/mode') return - const currentMode = effectiveSandboxMode(session.events) ?? ctx.sandboxPolicy.defaultMode - if (event.data.mode === currentMode) return - const owner = ctx.agents.get(session.id) - if (owner === undefined) return - if (!ctx.pty.hasOwnerActivity(owner)) return - throw new Error( - `cannot change sandbox mode from "${currentMode}" to "${event.data.mode}" while persistent terminal sessions are open or being created; wait for creation to settle and close them first`, - ) - }, { global: true }) } diff --git a/packages/pty/pty-local/src/session.ts b/packages/pty/pty-local/src/session.ts index a1e638e0d2..99bf142174 100644 --- a/packages/pty/pty-local/src/session.ts +++ b/packages/pty/pty-local/src/session.ts @@ -394,16 +394,31 @@ export class LocalPtySession implements PtyBackendSession { } } + private unionMembers(...groups: ProcessIdentity[][]): ProcessIdentity[] { + const members: ProcessIdentity[] = [] + const seen = new Set<string>() + for (const group of groups) { + for (const member of group) { + const key = JSON.stringify([member.pid, member.started]) + if (seen.has(key)) continue + seen.add(key) + members.push(member) + } + } + return members + } + private async stopDescendants(): Promise<ProcessIdentity[]> { - let members = this.descendants() - this.signalMembers(members, 'SIGTERM') - await this.waitForExit(members) + const captured = this.descendants() + this.signalMembers(captured, 'SIGTERM') + const capturedSurvivors = await this.waitForExit(captured) // A TERM-handling descendant may have forked while winding down. Rescan - // while the shell can still reap every member, then kill the fresh tree. - members = this.descendants() + // while the shell can still reap every member, then kill both the fresh + // tree and captured survivors that were reparented out of that tree. + const members = this.unionMembers(capturedSurvivors, this.descendants()) this.signalMembers(members, 'SIGKILL') - await this.waitForExit(members) - return this.descendants().filter(member => this.inspector.isAlive(member)) + const survivors = await this.waitForExit(members) + return this.survivors(this.unionMembers(survivors, this.descendants())) } private async stopShell(): Promise<void> { diff --git a/packages/pty/pty-local/tests/index.spec.ts b/packages/pty/pty-local/tests/index.spec.ts index 55cc134787..9c28484adf 100644 --- a/packages/pty/pty-local/tests/index.spec.ts +++ b/packages/pty/pty-local/tests/index.spec.ts @@ -9,7 +9,6 @@ import SandboxProvider from '@deepseek-ai/dsh-sandbox' import type { ConfinedArgv, SandboxPolicy } from '@deepseek-ai/dsh-sandbox' import SandboxPolicyService, { setSandboxMode } from '@deepseek-ai/dsh-sandbox-policy' import PtyService, { PtySessionId } from '@deepseek-ai/dsh-pty' -import type { PtyBackendSession } from '@deepseek-ai/dsh-pty' import { LocalPtyBackend } from '@deepseek-ai/dsh-pty-local' import * as ptyLocal from '@deepseek-ai/dsh-pty-local' import type { ResolvedConfig } from '@deepseek-ai/dsh-pty-local/src/config.ts' @@ -64,6 +63,30 @@ function spec(owner: Agent, signal?: AbortSignal) { } } +function stubLocalSession(initialize: () => Promise<void> = () => Promise.resolve()): LocalPtySession { + return { + motd: '', + initialize, + startSend: () => { throw new Error('unused') }, + read: () => { throw new Error('unused') }, + signal: () => Promise.resolve({ delivered: true, targetPgid: 1 }), + status: () => ({ kind: 'running' as const }), + close: () => Promise.resolve(), + } as unknown as LocalPtySession +} + +function registerStubLocalBackend(ctx: Context, createSession: () => LocalPtySession) { + return ctx.inject(['pty', 'sandbox', 'sandboxPolicy'], (providerCtx) => { + providerCtx.pty.registerBackend(new LocalPtyBackend( + providerCtx, + { ...config(), backendType: 'stub' }, + inspector, + (() => ({})) as never, + createSession, + )) + }) +} + describe('LocalPtyBackend startup rollback', () => { it('rejects pre-aborted setup and empty sandbox argv', async () => { const ctx = new Context() @@ -172,7 +195,7 @@ describe('pty-local plugin shape', () => { const loader = Object.create(Loader.prototype) as Loader const unwrapped = loader.unwrapExports(ptyLocal) as Record<string, unknown> expect(unwrapped.name).toBe('pty-local') - expect(unwrapped.inject).toEqual(['agents', 'pty', 'sandbox', 'sandboxPolicy']) + expect(unwrapped.inject).toEqual(['pty', 'sandbox', 'sandboxPolicy']) expect(unwrapped.Config).toBeDefined() }) @@ -204,39 +227,45 @@ describe('pty-local plugin shape', () => { expect(() => { setSandboxMode(session, 'read-only') }).not.toThrow() }) - it('rejects an effective sandbox-mode change until the owner closes live terminals', async () => { + it('keeps the owner-lifetime sandbox fence after the local provider unloads', async () => { const ctx = new Context() await ctx.plugin(SessionStore) await ctx.plugin(AgentRegistry) await ctx.plugin(PtyService) - await ctx.plugin(EmptySandbox) + await ctx.plugin(RecordingSandbox) await ctx.plugin(SandboxPolicyService, { mode: 'danger-full-access', workspaceRoot: '/tmp' }) - await ctx.plugin(ptyLocal, config()) const session = ctx.sessions.create(SessionId('mode-owner')) + const ownerFiber = await ctx.plugin(() => {}) const owner: Agent = { - id: session.id, options: {}, session, status: 'idle', ctx, + id: session.id, options: {}, session, status: 'idle', ctx: ownerFiber.ctx, send() {}, steer() {}, inject() {}, cancel() {}, whenIdle: () => Promise.resolve(), } ctx.agents.register(owner) - const backendSession = { - motd: '', - startSend: () => { throw new Error('unused') }, - read: () => { throw new Error('unused') }, - signal: () => Promise.resolve({ delivered: true, targetPgid: 1 }), - status: () => ({ kind: 'running' as const }), - close: () => Promise.resolve(), - } satisfies PtyBackendSession - ctx.pty.registerBackend({ type: 'stub', spawn: () => Promise.resolve(backendSession) }) + const providerFiber = await registerStubLocalBackend(ctx, () => stubLocalSession()) const created = await ctx.pty.spawn(owner, { type: 'stub' }) + const unrelated = ctx.sessions.create(SessionId('unrelated-mode')) + expect(() => { setSandboxMode(unrelated, 'read-only') }).not.toThrow() + expect(() => { + session.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } }) + }).not.toThrow() + expect(() => { setSandboxMode(session, 'danger-full-access') }).not.toThrow() + await providerFiber.dispose() + expect(ctx.pty.listBackends()).toEqual([]) expect(() => { setSandboxMode(session, 'read-only') }).toThrow( 'cannot change sandbox mode from "danger-full-access" to "read-only" while persistent terminal sessions are open or being created; wait for creation to settle and close them first', ) expect(session.events.filter(event => event.type === 'sandbox/mode')).toHaveLength(1) + const replacementFiber = await registerStubLocalBackend(ctx, () => stubLocalSession()) + const second = await ctx.pty.spawn(owner, { type: 'stub' }) + await replacementFiber.dispose() + expect(() => { setSandboxMode(session, 'read-only') }).toThrow('open or being created') + await ctx.pty.kill(owner, created.sessionId) + await ctx.pty.kill(owner, second.sessionId) expect(() => { setSandboxMode(session, 'read-only') }).not.toThrow() expect(session.events.filter(event => event.type === 'sandbox/mode')).toHaveLength(2) }) @@ -246,30 +275,23 @@ describe('pty-local plugin shape', () => { await ctx.plugin(SessionStore) await ctx.plugin(AgentRegistry) await ctx.plugin(PtyService) - await ctx.plugin(EmptySandbox) + await ctx.plugin(RecordingSandbox) await ctx.plugin(SandboxPolicyService, { mode: 'danger-full-access', workspaceRoot: '/tmp' }) - await ctx.plugin(ptyLocal, config()) const session = ctx.sessions.create(SessionId('pending-mode-owner')) + const ownerFiber = await ctx.plugin(() => {}) const owner: Agent = { - id: session.id, options: {}, session, status: 'idle', ctx, + id: session.id, options: {}, session, status: 'idle', ctx: ownerFiber.ctx, send() {}, steer() {}, inject() {}, cancel() {}, whenIdle: () => Promise.resolve(), } ctx.agents.register(owner) - const gate = Promise.withResolvers<PtyBackendSession>() - ctx.pty.registerBackend({ type: 'slow', spawn: () => gate.promise }) - const spawning = ctx.pty.spawn(owner, { type: 'slow' }) + const gate = Promise.withResolvers<undefined>() + await registerStubLocalBackend(ctx, () => stubLocalSession(() => gate.promise)) + const spawning = ctx.pty.spawn(owner, { type: 'stub' }) expect(ctx.pty.hasOwnerActivity(owner)).toBe(true) expect(() => { setSandboxMode(session, 'read-only') }).toThrow('open or being created') - gate.resolve({ - motd: '', - startSend: () => { throw new Error('unused') }, - read: () => { throw new Error('unused') }, - signal: () => Promise.resolve({ delivered: true, targetPgid: 1 }), - status: () => ({ kind: 'running' as const }), - close: () => Promise.resolve(), - }) + gate.resolve(undefined) const created = await spawning await ctx.pty.kill(owner, created.sessionId) expect(ctx.pty.hasOwnerActivity(owner)).toBe(false) diff --git a/packages/pty/pty-local/tests/session.spec.ts b/packages/pty/pty-local/tests/session.spec.ts index 42d634e368..b3a536696d 100644 --- a/packages/pty/pty-local/tests/session.spec.ts +++ b/packages/pty/pty-local/tests/session.spec.ts @@ -415,6 +415,28 @@ describe('LocalPtySession bounds, signals, and teardown', () => { expect(terminal.kills).toEqual(['SIGTERM']) }) + it('retains captured survivors that are reparented out of the teardown rescan', async () => { + vi.useFakeTimers() + const terminal = new FakeTerminal() + const inspector = new FakeInspector() + const captured = { pid: 124, started: 'captured' } + let reads = 0 + inspector.alive.add(captured.pid) + inspector.processTree = () => reads++ === 0 ? [captured] : [] + inspector.signalProcess = (identity, signal) => { + inspector.processes.push([identity.pid, signal]) + if (signal === 'SIGKILL') inspector.alive.delete(identity.pid) + } + const session = new LocalPtySession(terminal.asPty(), inspector, config({ disposeGraceMs: 20 })) + + const closing = session.close('test') + await vi.advanceTimersByTimeAsync(25) + await closing + + expect(inspector.processes).toEqual([[124, 'SIGTERM'], [124, 'SIGKILL']]) + expect(terminal.kills).toEqual(['SIGTERM']) + }) + it('allows teardown to retry after a descendant-survivor failure', async () => { vi.useFakeTimers() const terminal = new FakeTerminal() diff --git a/packages/tasks/tool-tasks/src/index.ts b/packages/tasks/tool-tasks/src/index.ts index cee88db859..01f2092485 100644 --- a/packages/tasks/tool-tasks/src/index.ts +++ b/packages/tasks/tool-tasks/src/index.ts @@ -171,10 +171,10 @@ export function apply(ctx: Context, config: Config): void { }, execute(args, exec) { const id = validateTaskId(args.task_id) + const snapshot = ctx.tasks.get(id, exec.agent) const result = ctx.tasks.kill(id, exec.agent, args.reason) if (result === 'already-finished') { // A snapshot describes terminal state without consuming pending output. - const snapshot = ctx.tasks.get(id, exec.agent) return Promise.resolve([{ type: 'text', text: fitWithSuffix( @@ -185,7 +185,15 @@ export function apply(ctx: Context, config: Config): void { ), }]) } - return Promise.resolve([{ type: 'text', text: `requested cancellation of task ${id}` }]) + return Promise.resolve([{ + type: 'text', + text: fitWithSuffix( + `requested cancellation of task ${id}`, + '', + snapshot.outputLimitBytes, + '\n[notice truncated]', + ), + }]) }, presentCall: args => presentTaskCall(`Kill background task ${args.task_id}`, 'execute', args.task_id), })) diff --git a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts index 886a1866fe..0256ac1cf8 100644 --- a/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts +++ b/packages/tasks/tool-tasks/tests/tool-tasks.spec.ts @@ -213,6 +213,16 @@ describe('task_kill', () => { expect(p.cancels).toEqual(['superseded']) }) + it('applies the producer output limit to a cancellation acknowledgement', async () => { + const { ctx } = await setup() + const p = producer({ outputLimitBytes: 8 }) + ctx.tasks.start(p.spec) + + const result = await call(ctx, 'task_kill', { task_id: 'bash-1' }) + expect(Buffer.byteLength(text(result))).toBeLessThanOrEqual(8) + expect(p.cancels).toEqual([undefined]) + }) + it('reports an already-finished task without consuming its pending delta', async () => { const { ctx } = await setup() let delta = 'unread tail' From e3112be7626f371679f47995e95d8d654bcbb113 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:23:01 +0800 Subject: [PATCH 098/368] feat(tools): canonicalize terminal outputs --- ...0-canonical-tool-output-contract.i18n.yaml | 4 +- ...26-07-20-canonical-tool-output-contract.md | 1 + ...07-20-canonical-tool-output-contract.zh.md | 1 + packages/pty/tool-pty/README.md | 2 + packages/pty/tool-pty/src/index.ts | 158 ++++++++++++++++-- packages/pty/tool-pty/src/render.ts | 54 +++++- packages/pty/tool-pty/tests/tools.spec.ts | 55 +++++- 7 files changed, 245 insertions(+), 30 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml index 9c50189a08..d106745e70 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.i18n.yaml @@ -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 -2026-07-20-canonical-tool-output-contract.md: c05be75d6a207d9d026b9a75cf50d841292929fe -2026-07-20-canonical-tool-output-contract.zh.md: cf22921c6fd0ec74fbbfd2cfbddd1c4a3379b4f2 +2026-07-20-canonical-tool-output-contract.md: 4099568de5dcc21a89b7873d4a6d4c7e9c62f8e4 +2026-07-20-canonical-tool-output-contract.zh.md: 01b50ef7493ea6548cd238f55e445a702e4d78b3 diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md index c05be75d6a..4099568de5 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.md @@ -48,6 +48,7 @@ The first-party tools preserve their existing Native text while returning domain | `web_search` / `web_fetch` | The normalized `WebSearchResult` / `WebFetchResult` | | `lsp` | `{ kind: "locations", locations, resolvedWorkspaceRoot }` or `{ kind: "hover", hover }` | | `bash` | `{ kind: "background", taskId }` or `{ kind: "foreground" } & BashRunResult` | +| `terminal_open` / `terminal_list` / `terminal_send` / `terminal_read` / `terminal_signal` / `terminal_close` | Public session snapshots, bounded read/send DTOs, signal/close outcomes, or a background task handle | | `task_output` / `task_list` / `task_kill` | Public task snapshots without owner or notification bookkeeping | | `subagent` | Background task handle or `{ kind: "foreground", runId, output: JsonValue[] }` | | `workflow` / `ralph` | `{ runId, agentsStarted, result: JsonValue }` | diff --git a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md index cf22921c6f..01b50ef749 100644 --- a/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-20-canonical-tool-output-contract.zh.md @@ -48,6 +48,7 @@ type ToolExecutionResult = | `web_search` / `web_fetch` | 归一化后的 `WebSearchResult` / `WebFetchResult` | | `lsp` | `{ kind: "locations", locations, resolvedWorkspaceRoot }` 或 `{ kind: "hover", hover }` | | `bash` | `{ kind: "background", taskId }` 或 `{ kind: "foreground" } & BashRunResult` | +| `terminal_open` / `terminal_list` / `terminal_send` / `terminal_read` / `terminal_signal` / `terminal_close` | 公开会话快照、有界的读取/发送 DTO、信号/关闭操作结果,或后台任务句柄 | | `task_output` / `task_list` / `task_kill` | 不含所有者或通知账务字段的公开任务快照 | | `subagent` | 后台任务句柄或 `{ kind: "foreground", runId, output: JsonValue[] }` | | `workflow` / `ralph` | `{ runId, agentsStarted, result: JsonValue }` | diff --git a/packages/pty/tool-pty/README.md b/packages/pty/tool-pty/README.md index 5a0edca33a..eba7c9f2fc 100644 --- a/packages/pty/tool-pty/README.md +++ b/packages/pty/tool-pty/README.md @@ -46,6 +46,8 @@ Prefix-stable while tool visibility and definitions are unchanged. Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Results remain in session history until compaction; incremental task reads do not repeat consumed output. +Programmatic callers receive typed session snapshots, bounded send/read DTOs, signal and close outcomes, or `{ kind: "background", taskId }`; Native rendering preserves the text above. + #### Token effect Data-dependent and bounded by the backend; each returned result remains in history until compaction. diff --git a/packages/pty/tool-pty/src/index.ts b/packages/pty/tool-pty/src/index.ts index b12db3a277..3d9495d5ae 100644 --- a/packages/pty/tool-pty/src/index.ts +++ b/packages/pty/tool-pty/src/index.ts @@ -6,12 +6,11 @@ import { Context } from 'cordis' import type { Agent } from '@deepseek-ai/dsh-agent' -import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { PtySessionId } from '@deepseek-ai/dsh-pty' import type { PtySendResult, PtySessionId as PtySessionIdType, PtySignal } from '@deepseek-ai/dsh-pty' import type {} from '@deepseek-ai/dsh-tasks' import { defineTool } from '@deepseek-ai/dsh-tools' -import type { ToolExecutionResult, ToolResult } from '@deepseek-ai/dsh-tools' +import type { ToolResult } from '@deepseek-ai/dsh-tools' import { renderList, renderRead, renderSend, renderSendRead, renderSpawn } from './render.ts' declare module '@deepseek-ai/dsh-tasks' { @@ -50,6 +49,41 @@ interface SignalArgs extends SessionArgs { signal: PtySignal } +const SESSION_STATUS_SCHEMA = { + oneOf: [ + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'running' }, + }, + }, + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'exited' }, + exitCode: { required: true, oneOf: [{ type: 'integer' }, { type: 'null' }] }, + signal: { required: true, oneOf: [{ type: 'string' }, { type: 'null' }] }, + }, + }, + ], +} as const + +const SESSION_SNAPSHOT_PROPERTIES = { + sessionId: { type: 'string', required: true }, + name: { type: 'string' }, + type: { type: 'string', required: true }, + pid: { type: 'integer' }, + status: { ...SESSION_STATUS_SCHEMA, required: true }, +} as const + +const SESSION_SNAPSHOT_SCHEMA = { + type: 'object', + additionalProperties: false, + properties: SESSION_SNAPSHOT_PROPERTIES, +} as const + function requireAgent(agent: Agent | undefined): Agent { if (agent === undefined) throw new Error('terminal tools require an initiating agent') return agent @@ -62,10 +96,6 @@ function sessionId(args: SessionArgs): PtySessionIdType { return PtySessionId(args.sessionId) } -function textResult(text: string): ContentBlock[] { - return [{ type: 'text', text }] -} - function rawResultText(result: ToolResult): string | undefined { if (result.content.length !== 1) return undefined const block = result.content[0] @@ -94,6 +124,17 @@ export function apply(ctx: Context): void { name: { type: 'string', description: 'Optional owner-local display name such as "main" or "gdb".' }, cwd: { type: 'string', description: 'Initial working directory. Defaults to the deployment workspace root.' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + ...SESSION_SNAPSHOT_PROPERTIES, + motd: { type: 'string', required: true }, + }, + }, + render: (_args, value) => [{ type: 'text', text: renderSpawn(value) }], + }, async execute(args: SpawnArgs, exec) { if (args.type.length === 0) throw new Error('type must be a non-empty string') const result = await ctx.pty.spawn(requireAgent(exec.agent), { @@ -101,7 +142,7 @@ export function apply(ctx: Context): void { ...args.name !== undefined ? { name: args.name } : {}, ...args.cwd !== undefined ? { cwd: args.cwd } : {}, }, exec.signal) - return textResult(renderSpawn(result)) + return result }, presentCall: (args) => { const parsed = args @@ -118,7 +159,50 @@ export function apply(ctx: Context): void { submit: { type: 'boolean', description: 'Submit Enter after text (default true). Set false for control characters or incomplete REPL input.' }, run_in_background: { type: 'boolean', description: 'Return a task id immediately; collect with task_output or stop with task_kill.' }, }, - async execute(args: SendArgs, exec): Promise<ToolExecutionResult> { + output: { + schema: { + oneOf: [ + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'background' }, + taskId: { type: 'string', required: true }, + }, + }, + { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'foreground' }, + viewport: { type: 'string', required: true }, + waitReason: { + type: 'string', + required: true, + enum: ['stdin_read', 'inferred_idle', 'timeout', 'session_exit'], + }, + sessionStatus: { ...SESSION_STATUS_SCHEMA, required: true }, + truncated: { type: 'boolean', required: true }, + }, + }, + ], + }, + render: (_args, value) => [{ + type: 'text', + text: value.kind === 'background' + ? `started background task ${value.taskId}` + : renderSend(value), + }], + presentationMeta: (_args, value) => value.kind === 'foreground' + ? { + viewport: value.viewport, + waitReason: value.waitReason, + sessionStatus: value.sessionStatus, + truncated: value.truncated, + } + : null, + }, + async execute(args: SendArgs, exec) { const owner = requireAgent(exec.agent) const id = sessionId(args) const request = { text: args.text, submit: args.submit ?? true } @@ -145,12 +229,12 @@ export function apply(ctx: Context): void { } }, }) - return { content: textResult(`started background task ${taskId}`), isError: false } + return { kind: 'background' as const, taskId } } const operation = ctx.pty.startSend(owner, id, { ...request, signal: exec.signal }) const result = await operation.done if (exec.signal.aborted) throw new Error('terminal send aborted') - return { content: textResult(renderSend(result)), isError: false, meta: result } + return { kind: 'foreground' as const, ...result } }, presentCall(args) { const parsed = args as Partial<SendArgs> @@ -174,12 +258,26 @@ export function apply(ctx: Context): void { offset: { type: 'number', description: 'Newest-relative line offset (default 0).' }, count: { type: 'number', description: 'Requested line count (default 500; backend caps apply).' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + text: { type: 'string', required: true }, + totalLines: { type: 'integer', required: true }, + lineBegin: { type: 'integer', required: true }, + lineEnd: { type: 'integer', required: true }, + truncated: { type: 'boolean', required: true }, + }, + }, + render: (_args, value) => [{ type: 'text', text: renderRead(value) }], + }, execute(args: ReadArgs, exec) { const result = ctx.pty.read(requireAgent(exec.agent), sessionId(args), { ...args.offset !== undefined ? { offset: args.offset } : {}, ...args.count !== undefined ? { count: args.count } : {}, }) - return Promise.resolve(textResult(renderRead(result))) + return Promise.resolve(result) }, presentCall: args => ({ card: 'generic', title: `Read terminal ${(args).sessionId}`, kind: 'read', rawInput: args }), })) @@ -191,9 +289,19 @@ export function apply(ctx: Context): void { sessionId: { type: 'string', required: true, description: 'Terminal session id.' }, signal: { type: 'string', required: true, enum: ['SIGINT', 'SIGTERM', 'SIGKILL', 'SIGTSTP', 'SIGHUP'], description: 'Signal to deliver. Shell-targeted SIGKILL is rejected; use terminal_close.' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + delivered: { type: 'boolean', required: true, const: true }, + targetPgid: { type: 'integer', required: true }, + }, + }, + render: (args, value) => [{ type: 'text', text: `delivered ${args.signal} to foreground process group ${value.targetPgid}` }], + }, async execute(args: SignalArgs, exec) { - const result = await ctx.pty.signal(requireAgent(exec.agent), sessionId(args), args.signal) - return textResult(`delivered ${args.signal} to foreground process group ${result.targetPgid}`) + return ctx.pty.signal(requireAgent(exec.agent), sessionId(args), args.signal) }, presentCall: args => ({ card: 'generic', title: `Signal terminal ${args.sessionId}`, kind: 'execute', rawInput: args }), })) @@ -204,10 +312,26 @@ export function apply(ctx: Context): void { parameters: { sessionId: { type: 'string', required: true, description: 'Terminal session id.' }, }, + output: { + schema: { + type: 'object', + additionalProperties: false, + properties: { + sessionId: { type: 'string', required: true }, + outcome: { type: 'string', required: true, enum: ['closed', 'already-closing'] }, + }, + }, + render: (_args, value) => [{ + type: 'text', + text: value.outcome === 'closed' + ? `closed terminal session ${value.sessionId}` + : `terminal session ${value.sessionId} was already closing`, + }], + }, async execute(args: SessionArgs, exec) { const id = sessionId(args) const closed = await ctx.pty.kill(requireAgent(exec.agent), id) - return textResult(closed ? `closed terminal session ${id}` : `terminal session ${id} was already closing`) + return { sessionId: id, outcome: closed ? 'closed' as const : 'already-closing' as const } }, presentCall: args => ({ card: 'generic', title: `Close terminal ${(args).sessionId}`, kind: 'delete' }), })) @@ -216,8 +340,12 @@ export function apply(ctx: Context): void { name: 'terminal_list', description: 'List persistent terminal sessions owned by the current agent.', parameters: {}, + output: { + schema: { type: 'array', items: SESSION_SNAPSHOT_SCHEMA }, + render: (_args, value) => [{ type: 'text', text: renderList(value) }], + }, execute(_args: Record<string, never>, exec) { - return Promise.resolve(textResult(renderList(ctx.pty.list(requireAgent(exec.agent))))) + return Promise.resolve(ctx.pty.list(requireAgent(exec.agent))) }, presentCall: () => ({ card: 'generic', title: 'List terminal sessions', kind: 'read' }), })) diff --git a/packages/pty/tool-pty/src/render.ts b/packages/pty/tool-pty/src/render.ts index bed176e890..ea1f31bbe0 100644 --- a/packages/pty/tool-pty/src/render.ts +++ b/packages/pty/tool-pty/src/render.ts @@ -1,13 +1,55 @@ /** Model and ACP rendering for persistent terminal tool results. */ -import type { PtyReadResult, PtySendRead, PtySendResult, PtySessionSnapshot, PtySpawnResult } from '@deepseek-ai/dsh-pty' +interface RenderedSessionStatusRunning { + kind: 'running' +} + +interface RenderedSessionStatusExited { + kind: 'exited' + exitCode: number | null + signal: string | null +} + +type RenderedSessionStatus = RenderedSessionStatusRunning | RenderedSessionStatusExited + +interface RenderedSessionSnapshot { + sessionId: string + name?: string + type: string + pid?: number + status: RenderedSessionStatus +} + +interface RenderedSpawnResult extends RenderedSessionSnapshot { + motd: string +} + +interface RenderedSendResult { + viewport: string + waitReason: 'stdin_read' | 'inferred_idle' | 'timeout' | 'session_exit' + sessionStatus: RenderedSessionStatus + truncated: boolean +} + +interface RenderedSendRead { + delta: string + truncated: boolean +} + +interface RenderedReadResult { + text: string + totalLines: number + lineBegin: number + lineEnd: number + truncated: boolean +} /** * Render one created session and its bounded MOTD. * @param result - published spawn result. * @returns Model-facing session acknowledgement. */ -export function renderSpawn(result: PtySpawnResult): string { +export function renderSpawn(result: RenderedSpawnResult): string { const label = result.name === undefined ? result.sessionId : `${result.sessionId} (${result.name})` return `started terminal session ${label} [type: ${result.type}]\n${result.motd || '(no startup output)'}` } @@ -17,7 +59,7 @@ export function renderSpawn(result: PtySpawnResult): string { * @param result - settled send outcome. * @returns Terminal output plus wait/session markers. */ -export function renderSend(result: PtySendResult): string { +export function renderSend(result: RenderedSendResult): string { const output = result.viewport || '(no new output)' const status = result.sessionStatus.kind === 'running' ? 'running' @@ -30,7 +72,7 @@ export function renderSend(result: PtySendResult): string { * @param read - consuming operation delta. * @returns Delta plus truncation marker when needed. */ -export function renderSendRead(read: PtySendRead): string { +export function renderSendRead(read: RenderedSendRead): string { return `${read.delta}${read.truncated ? `${read.delta.endsWith('\n') || read.delta.length === 0 ? '' : '\n'}[output truncated]` : ''}` } @@ -39,7 +81,7 @@ export function renderSendRead(read: PtySendRead): string { * @param result - retained scrollback page. * @returns Page text plus pagination and truncation markers. */ -export function renderRead(result: PtyReadResult): string { +export function renderRead(result: RenderedReadResult): string { const output = result.text || '(no retained output)' return `${output}\n[lines: ${result.lineBegin}-${result.lineEnd} of ${result.totalLines}]${result.truncated ? '\n[output truncated]' : ''}` } @@ -49,7 +91,7 @@ export function renderRead(result: PtyReadResult): string { * @param sessions - fresh owner-scoped snapshots. * @returns One line per session or the empty marker. */ -export function renderList(sessions: PtySessionSnapshot[]): string { +export function renderList(sessions: readonly RenderedSessionSnapshot[]): string { if (sessions.length === 0) return '(no terminal sessions)' return sessions.map((session) => { const name = session.name === undefined ? '' : ` (${session.name})` diff --git a/packages/pty/tool-pty/tests/tools.spec.ts b/packages/pty/tool-pty/tests/tools.spec.ts index 5adcaea441..b054a7be90 100644 --- a/packages/pty/tool-pty/tests/tools.spec.ts +++ b/packages/pty/tool-pty/tests/tools.spec.ts @@ -124,13 +124,50 @@ describe('tool-pty foreground surface', () => { const spawned = await call(ctx, 'terminal_open', { type: 'stub', name: 'main' }, agent) expect(text(spawned)).toContain('started terminal session pty-1 (main)') - expect(text(await call(ctx, 'terminal_list', {}, agent))).toContain('pty-1 (main) [stub] running pid=42') - expect(text(await call(ctx, 'terminal_read', { sessionId: 'pty-1' }, agent))).toContain('history\n[lines: 0-1 of 1]') - expect(text(await call(ctx, 'terminal_signal', { sessionId: 'pty-1', signal: 'SIGINT' }, agent))).toBe('delivered SIGINT to foreground process group 10') + expect(spawned).toMatchObject({ + isError: false, + value: { + sessionId: 'pty-1', + name: 'main', + type: 'stub', + pid: 42, + status: { kind: 'running' }, + motd: 'stub prompt', + }, + }) + const listed = await call(ctx, 'terminal_list', {}, agent) + expect(text(listed)).toContain('pty-1 (main) [stub] running pid=42') + expect(listed).toMatchObject({ isError: false, value: [{ sessionId: 'pty-1', name: 'main', type: 'stub', pid: 42, status: { kind: 'running' } }] }) + const read = await call(ctx, 'terminal_read', { sessionId: 'pty-1' }, agent) + expect(text(read)).toContain('history\n[lines: 0-1 of 1]') + expect(read).toMatchObject({ isError: false, value: { text: 'history', totalLines: 1, lineBegin: 0, lineEnd: 1, truncated: false } }) + const signalled = await call(ctx, 'terminal_signal', { sessionId: 'pty-1', signal: 'SIGINT' }, agent) + expect(text(signalled)).toBe('delivered SIGINT to foreground process group 10') + expect(signalled).toMatchObject({ isError: false, value: { delivered: true, targetPgid: 10 } }) const sent = await call(ctx, 'terminal_send', { sessionId: 'pty-1', text: 'echo hi' }, agent) expect(text(sent)).toContain('command output\n[wait: stdin_read]\n[session: running]') - expect(text(await call(ctx, 'terminal_close', { sessionId: 'pty-1' }, agent))).toBe('closed terminal session pty-1') - expect(text(await call(ctx, 'terminal_list', {}, agent))).toBe('(no terminal sessions)') + expect(sent).toMatchObject({ + isError: false, + value: { + kind: 'foreground', + viewport: 'command output', + waitReason: 'stdin_read', + sessionStatus: { kind: 'running' }, + truncated: false, + }, + meta: { + viewport: 'command output', + waitReason: 'stdin_read', + sessionStatus: { kind: 'running' }, + truncated: false, + }, + }) + const closed = await call(ctx, 'terminal_close', { sessionId: 'pty-1' }, agent) + expect(text(closed)).toBe('closed terminal session pty-1') + expect(closed).toMatchObject({ isError: false, value: { sessionId: 'pty-1', outcome: 'closed' } }) + const empty = await call(ctx, 'terminal_list', {}, agent) + expect(text(empty)).toBe('(no terminal sessions)') + expect(empty).toMatchObject({ isError: false, value: [] }) }) it('fails without an initiating agent and rejects background before writing', async () => { @@ -178,7 +215,9 @@ describe('tool-pty task integration', () => { it('registers a generic task and exposes incremental output', async () => { const { ctx, agent } = await setup(true) await call(ctx, 'terminal_open', { type: 'stub' }, agent) - expect(text(await call(ctx, 'terminal_send', { sessionId: 'pty-1', text: 'build', run_in_background: true }, agent))).toBe('started background task pty-send-1') + const started = await call(ctx, 'terminal_send', { sessionId: 'pty-1', text: 'build', run_in_background: true }, agent) + expect(text(started)).toBe('started background task pty-send-1') + expect(started).toMatchObject({ isError: false, value: { kind: 'background', taskId: 'pty-send-1' } }) const output = await call(ctx, 'task_output', { task_id: 'pty-send-1', wait: true }, agent) expect(text(output)).toContain('live output') expect(text(output)).toContain('[status: completed, wait: stdin_read]') @@ -224,7 +263,9 @@ describe('tool-pty task integration', () => { const second = call(ctx, 'terminal_close', { sessionId: 'pty-1' }, agent) stub.sessions[0]!.closeGate?.resolve(undefined) await first - expect(text(await second)).toBe('terminal session pty-1 was already closing') + const result = await second + expect(text(result)).toBe('terminal session pty-1 was already closing') + expect(result).toMatchObject({ isError: false, value: { sessionId: 'pty-1', outcome: 'already-closing' } }) }) it('renders an exited session detail for background completion', async () => { From 17b979253222261a5a5ba5122a31ac7df6fa9db3 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:24:43 +0800 Subject: [PATCH 099/368] refactor(tools): share terminal task schema --- packages/pty/tool-pty/src/index.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/pty/tool-pty/src/index.ts b/packages/pty/tool-pty/src/index.ts index 3d9495d5ae..9aedd4c649 100644 --- a/packages/pty/tool-pty/src/index.ts +++ b/packages/pty/tool-pty/src/index.ts @@ -84,6 +84,15 @@ const SESSION_SNAPSHOT_SCHEMA = { properties: SESSION_SNAPSHOT_PROPERTIES, } as const +const BACKGROUND_TASK_OUTPUT_SCHEMA = { + type: 'object', + additionalProperties: false, + properties: { + kind: { type: 'string', required: true, const: 'background' }, + taskId: { type: 'string', required: true }, + }, +} as const + function requireAgent(agent: Agent | undefined): Agent { if (agent === undefined) throw new Error('terminal tools require an initiating agent') return agent @@ -162,14 +171,7 @@ export function apply(ctx: Context): void { output: { schema: { oneOf: [ - { - type: 'object', - additionalProperties: false, - properties: { - kind: { type: 'string', required: true, const: 'background' }, - taskId: { type: 'string', required: true }, - }, - }, + BACKGROUND_TASK_OUTPUT_SCHEMA, { type: 'object', additionalProperties: false, From b8aa1507cd913da4eb90701ad1bf9645cac4eaa6 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:28:14 +0800 Subject: [PATCH 100/368] docs(pty): keep model experience field canonical --- packages/pty/tool-pty/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/pty/tool-pty/README.md b/packages/pty/tool-pty/README.md index eba7c9f2fc..de4633fed6 100644 --- a/packages/pty/tool-pty/README.md +++ b/packages/pty/tool-pty/README.md @@ -44,9 +44,7 @@ Prefix-stable while tool visibility and definitions are unchanged. #### What the model sees -Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Results remain in session history until compaction; incremental task reads do not repeat consumed output. - -Programmatic callers receive typed session snapshots, bounded send/read DTOs, signal and close outcomes, or `{ kind: "background", taskId }`; Native rendering preserves the text above. +Spawn returns the id and bounded MOTD. Send/read return bounded terminal text plus readiness/history markers. Background mode returns a generic task id. Results remain in session history until compaction; incremental task reads do not repeat consumed output. Programmatic callers receive typed session snapshots, bounded send/read DTOs, signal and close outcomes, or `{ kind: "background", taskId }`; Native rendering preserves the text above. #### Token effect From 03889cee1af5a761976e7dceab87a1af4546194c Mon Sep 17 00:00:00 2001 From: Yichen Jiang <jyc132780208@sina.com> Date: Wed, 22 Jul 2026 23:39:50 +0800 Subject: [PATCH 101/368] feat(gui): add ask-user question composer --- .../feature/2026-06-25-ask-user-question.md | 10 +- apps/web/tests/smoke-fixture.e2e.ts | 53 ++- apps/web/tests/smoke-real.e2e.ts | 4 +- docs/config-catalog.md | 1 + docs/core-data-structures/user-interaction.md | 4 +- docs/module-graph.md | 3 + .../client/connection/src/client/fixture.ts | 61 +++- .../client/connection/tests/fixture.spec.ts | 37 +- .../src/client/sessions/conversation.ts | 11 +- .../runtime/src/client/sessions/session.ts | 33 +- packages/client/runtime/tests/fake-api.ts | 7 +- packages/client/runtime/tests/session.spec.ts | 24 ++ packages/client/ui-conversation/README.md | 4 +- .../ui-conversation/src/client/apply.ts | 3 + .../src/client/chat/ChatView.tsx | 4 +- .../src/client/chat/PendingCard.tsx | 20 +- .../src/client/contract/slots.ts | 10 +- .../ui-conversation/src/client/index.ts | 13 +- .../src/client/skeleton/ConversationRoot.tsx | 43 ++- .../ui-conversation/tests/chat-view.spec.tsx | 11 +- .../tests/coverage-tails.spec.tsx | 11 +- .../tests/skeleton-branches.spec.tsx | 7 +- .../ui-conversation/tests/skeleton.spec.tsx | 32 +- packages/client/ui-question/README.md | 20 ++ packages/client/ui-question/package.json | 66 ++++ .../src/client/QuestionComposer.module.css | 329 ++++++++++++++++++ .../src/client/QuestionComposer.tsx | 308 ++++++++++++++++ .../client/ui-question/src/client/index.ts | 47 +++ .../client/ui-question/src/css-modules.d.ts | 4 + packages/client/ui-question/src/index.ts | 17 + packages/client/ui-question/src/invariant.ts | 31 ++ .../ui-question/tests/browser-plugin.spec.ts | 58 +++ .../ui-question/tests/node-plugin.spec.ts | 28 ++ .../tests/question-composer.spec.tsx | 198 +++++++++++ packages/client/ui-question/tsconfig.json | 43 +++ packages/client/ui-question/tsdown.config.ts | 3 + .../client/ui-trajectory/tests/views.spec.tsx | 16 +- packages/host/apiproxy/src/api/rpc.schema.ts | 1 + packages/host/apiproxy/src/api/rpc.ts | 1 + .../host/apiproxy/tests/rpc-schemas.spec.ts | 1 + packages/host/runtime/README.md | 8 +- packages/host/runtime/package.json | 2 + packages/host/runtime/src/api-proxy.ts | 154 +++++++- packages/host/runtime/src/boot.ts | 2 + packages/host/runtime/src/web-plugins.ts | 11 +- .../host/runtime/tests/api-proxy-cold.spec.ts | 3 + .../host/runtime/tests/api-proxy-view.spec.ts | 2 + .../host/runtime/tests/host-runtime.spec.ts | 175 +++++++++- .../host/runtime/tests/web-plugins.e2e.ts | 17 +- .../host/runtime/tests/web-plugins.spec.ts | 6 +- packages/host/runtime/tsconfig.json | 3 + packages/ui/user-interaction/README.md | 2 +- packages/ui/user-interaction/src/types.ts | 2 +- pnpm-lock.yaml | 52 +++ .../verify-package-readme-model-experience.ts | 1 + tsconfig.base.json | 1 + tsconfig.build.json | 1 + tsconfig.client.json | 1 + 58 files changed, 1905 insertions(+), 115 deletions(-) create mode 100644 packages/client/ui-question/README.md create mode 100644 packages/client/ui-question/package.json create mode 100644 packages/client/ui-question/src/client/QuestionComposer.module.css create mode 100644 packages/client/ui-question/src/client/QuestionComposer.tsx create mode 100644 packages/client/ui-question/src/client/index.ts create mode 100644 packages/client/ui-question/src/css-modules.d.ts create mode 100644 packages/client/ui-question/src/index.ts create mode 100644 packages/client/ui-question/src/invariant.ts create mode 100644 packages/client/ui-question/tests/browser-plugin.spec.ts create mode 100644 packages/client/ui-question/tests/node-plugin.spec.ts create mode 100644 packages/client/ui-question/tests/question-composer.spec.tsx create mode 100644 packages/client/ui-question/tsconfig.json create mode 100644 packages/client/ui-question/tsdown.config.ts diff --git a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.md b/.agents/notes/implemented/feature/2026-06-25-ask-user-question.md index e1c5d03c08..cd1a423499 100644 --- a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.md +++ b/.agents/notes/implemented/feature/2026-06-25-ask-user-question.md @@ -14,12 +14,16 @@ Introduce `dsh-user-interaction` as the provider-neutral interface package for ` The model-facing request vocabulary is deliberately aligned with the product-research schema: `ask_user_question({ questions: [{ id, question, header?, options?: [{ label, description? }], multi_select? }] })`. `id` is supplied per question and echoed in the result so a batch can be routed without relying on question text. `label` is both user-facing display text and the selected value returned to the model; there is no separate `value`, no `recommended`, no `allow_custom`, and no `desc` alias. -Providers return `{ answers: [{ id, selected, custom? }] }`. `selected` is always an array of selected option labels, so single-select and `multi_select` answers share one result shape. `custom` carries a free-text "Other" answer; optionless questions collect `custom` directly. When `custom` is present, it overrides any selected choices and `selected` is empty. +Providers return `{ answers: [{ id, selected, custom? }] }`. `selected` is always an array of selected option labels, so single-select and `multi_select` answers share one result shape. `custom` carries a free-text "Other" answer; optionless questions collect `custom` directly. When `custom` is present, it overrides any selected choices and `selected` is empty. A provider that supports partial completion represents a deliberately skipped item with the existing `{ id, selected: [] }` shape, preserving the other answers without extending the tool result vocabulary. `UserInteractionError` extends `HarnessError`, so failures such as `NO_PROVIDER`, `ASK_ABORTED`, ACP cancellation, or missing session routing survive `ctx.tools.execute()` as machine-routable `{ name, code }` tool errors. This matches the structured-error taxonomy and lets the model or a wrapping plugin distinguish "user cancelled" from a generic thrown exception. ## UI mappings +`dsh web` mounts `dsh-client-ui-question`, whose host half opts the Web product into the model-facing tool and whose browser half registers a `question` entry in the conversation-owned keyed composer slot. `createApiProxy` implements the Web provider with a process-memory pending table keyed by a host-minted rpcId. It registers the wait before broadcasting `question/requested`, replays the same id on every mux reopen, validates the session and complete answer batch before claiming it, and broadcasts `question/resolved` after answer, cancellation, abort, or disposal. Claiming deletes the entry synchronously, so the first valid response wins and duplicate or late responses return `not-pending`. + +The Web composer shows one question at a time while retaining every request in the session object layer. It supports single-select, multi-select, optionless or explicit custom answers, description text, and a visual recommendation badge without selecting the recommendation automatically. Single-select choices advance to the next item immediately, and Enter submits when every item is answered or explicitly skipped; Enter during IME composition only confirms the input candidate. The footer skips only the current item and preserves earlier drafts; the close control rejects the whole tool call with `ASK_CANCELLED`. The normal composer returns only after the host's resolved frame removes the pending item. + `dsh-tui` renders each question as a keyboard overlay, shows option descriptions, supports single- and multi-select choices plus free-form custom answers, and rejects pending questions on abort, provider disposal, or terminal shutdown. Batched and simultaneous requests are queued so one overlay owns keyboard focus at a time. `dsh-acp` provides the same seam for ACP sessions. It resolves the calling `Agent` through `ownedRecord`, requiring the forward session-map record at `agent.session.id` to own that exact agent object, and calls ACP `unstable_createElicitation` with a session-scoped form for each question. Single-select options become a `choice` string enum; `multi_select` options become a `choice` array enum; optionless questions use a required `custom` text field. If the client returns both `choice` and non-empty `custom`, the custom answer wins. ACP `decline`/`cancel`, a missing answer, a missing session, and a client without elicitation support all become structured `UserInteractionError`s. @@ -42,8 +46,8 @@ ACP elicitation is currently marked unstable in the SDK. The fallback is still s The feature gives the model a powerful pause primitive, so prompt guidance matters. The tool description tells the model to ask concise questions and use options when possible. Product policy can later wrap `tools/execute` to restrict when the tool is allowed, but the loop should not special-case it. -`dsh-user-interaction` and `dsh-tool-ask-user` both live in `packages/ui` because they form one product-facing human-interaction capability. `agent-core` does not load either the tool or a provider. `dsh-tui-demo` opts into the seam, TUI provider, and model-facing tool. `acp-agent` keeps only the `userInteraction` seam/provider by default: ACP elicitation support is still client-dependent, so an ACP leaf must opt into the model-facing tool deliberately once its client can complete elicitation requests. +`dsh-user-interaction` and `dsh-tool-ask-user` both live in `packages/ui` because they form one product-facing human-interaction capability. `agent-core` does not load either the tool or a provider. `dsh-tui-demo` opts into the seam, TUI provider, and model-facing tool. `dsh web` boots the seam/provider in the host runtime and exposes the tool through the selected Web question plugin. `acp-agent` keeps only the `userInteraction` seam/provider by default: ACP elicitation support is still client-dependent, so an ACP leaf must opt into the model-facing tool deliberately once its client can complete elicitation requests. ## Testing -Unit coverage pins provider registration/disposal, duplicate-provider rejection, abort-before-provider, empty-question rejection, structured tool errors through `ctx.tools.execute()`, batched answers, multi-select answers, custom answers, and the model schema including the removal of `value`, `recommended`, `allow_custom`, and `desc`. TUI tests cover option descriptions, queued requests, shutdown/abort cleanup, optionless free-form input, invalid choices, duplicate multi-select selections, and batched question flows. ACP bridge tests drive a real in-memory ACP connection with the real `ask_user_question` tool and verify selected-option, custom-overrides-choice, multi-select, and optionless free-form elicitation paths continue the agent loop. +Unit coverage pins provider registration/disposal, duplicate-provider rejection, abort-before-provider, empty-question rejection, structured tool errors through `ctx.tools.execute()`, batched answers, multi-select answers, custom answers, explicit per-item skips, and the model schema including the removal of `value`, `recommended`, `allow_custom`, and `desc`. TUI tests cover option descriptions, queued requests, shutdown/abort cleanup, optionless free-form input, invalid choices, duplicate multi-select selections, and batched question flows. ACP bridge tests drive a real in-memory ACP connection with the real `ask_user_question` tool and verify selected-option, custom-overrides-choice, multi-select, and optionless free-form elicitation paths continue the agent loop. Web tests pin stable-id replay, response validation, first-wins settlement, duplicate and late responses, whole-request cancellation versus owner abort, single-select advance, IME-safe Enter submission, per-item skip preservation, composer takeover, structured batch submission, and restoration of the normal composer. diff --git a/apps/web/tests/smoke-fixture.e2e.ts b/apps/web/tests/smoke-fixture.e2e.ts index 0c32be5310..5f2d870a4c 100644 --- a/apps/web/tests/smoke-fixture.e2e.ts +++ b/apps/web/tests/smoke-fixture.e2e.ts @@ -1,10 +1,10 @@ // Keyless boot-chain smoke over the REAL carrier: startWebServer + web-plugins // registry surface + __DSH_BOOT__ injection + built shell dist in a real // chromium. First describe: manifest injection + fail-loud half. Second -// describe: the settled success pass — five REAL tsdown bundles (the -// infrastructure four + layout) load through the DI chain in ?fixture mode -// and the three-column frame appears in one flip. The full conversation -// round lands in smoke-real under the W5 real-host standard. +// describe: the settled success pass — all nine REAL tsdown bundles load +// through the DI chain in ?fixture mode, the three-column frame appears in +// one flip, and the resident question completes through the real UI stack. +// The full model round lands in smoke-real under the W5 real-host standard. import { existsSync } from 'node:fs' import { fileURLToPath } from 'node:url' import type { Browser, Page } from 'playwright' @@ -17,13 +17,17 @@ import { DIST_INDEX, probeFreePort, requireDist, saveFailureShot } from './suppo const bundlePath = (dir: string): string => fileURLToPath(new URL(`../../../packages/client/${dir}/lib/client.js`, import.meta.url)) -/** id ↔ bundle table for the success pass (immediately four + layout). */ +/** id ↔ bundle table for the success pass (the complete Web UI assembly). */ const REAL_PLUGINS: { id: string; dir: string; inject: string[]; immediately?: boolean }[] = [ { id: '@deepseek-ai/dsh-client-connection', dir: 'connection', inject: [], immediately: true }, { id: '@deepseek-ai/dsh-client-runtime', dir: 'runtime', inject: ['@deepseek-ai/dsh-client-connection'], immediately: true }, { id: '@deepseek-ai/dsh-client-ui-theme', dir: 'ui-theme', inject: [], immediately: true }, { id: '@deepseek-ai/dsh-client-i18n', dir: 'i18n', inject: [], immediately: true }, { id: '@deepseek-ai/dsh-client-ui-layout', dir: 'ui-layout', inject: ['@deepseek-ai/dsh-client-runtime'] }, + { id: '@deepseek-ai/dsh-client-ui-sidebar', dir: 'ui-sidebar', inject: ['@deepseek-ai/dsh-client-ui-layout'] }, + { id: '@deepseek-ai/dsh-client-ui-conversation', dir: 'ui-conversation', inject: ['@deepseek-ai/dsh-client-ui-layout'] }, + { id: '@deepseek-ai/dsh-client-ui-question', dir: 'ui-question', inject: ['@deepseek-ai/dsh-client-ui-conversation'] }, + { id: '@deepseek-ai/dsh-client-ui-trajectory', dir: 'ui-trajectory', inject: ['@deepseek-ai/dsh-client-ui-conversation'] }, ] /** Manifest served by the fake registry: one live bundle row, one missing row. */ @@ -90,7 +94,7 @@ describe('web boot chain (keyless, real carrier)', () => { }) }) -describe('web boot chain success pass (keyless, five real bundles, ?fixture)', () => { +describe('web boot chain success pass (keyless, nine real bundles, ?fixture)', () => { const missing = REAL_PLUGINS.filter((p) => !existsSync(bundlePath(p.dir))) let server: Awaited<ReturnType<typeof startWebServer>> let browser: Browser @@ -141,6 +145,43 @@ describe('web boot chain success pass (keyless, five real bundles, ?fixture)', ( expect(owners).toContain('@deepseek-ai/dsh-client-ui-layout') }) + it('renders and completes the resident question through the composer slot', async () => { + onTestFailed(() => saveFailureShot(page, 'smoke-question-composer')) + await page.getByText('fixture', { exact: true }).click() + await page.locator('[role="treeitem"]').nth(1).click() + const composer = page.locator('[data-question-rpc-id]') + await composer.waitFor({ timeout: 15_000 }) + expect({ + question: await composer.getByRole('heading').innerText(), + progress: await composer.getByText('1 / 3', { exact: true }).innerText(), + options: await composer.getByRole('radio').allTextContents(), + custom: await composer.getByRole('button', { name: '其他,请填写自定义答案' }).innerText(), + }).toMatchInlineSnapshot(` + { + "custom": "其他,请填写自定义答案", + "options": [ + "1工程落地型推荐更看重能直接做 runtime、tool executor、sandbox、trace 和线上问题排查。", + "2研究潜力型更看重 Agent 理解、训练评测思路和长期成长空间。", + "3均衡型同时要求工程能力和 Agent 认知,但可能筛选门槛更高。", + ], + "progress": "1 / 3", + "question": "你现在更想招哪类 Agent/Harness 候选人?", + } + `) + + await composer.getByRole('radio', { name: '工程落地型' }).click() + await composer.getByText('2 / 3', { exact: true }).waitFor() + await composer.getByRole('button', { name: '跳过本题', exact: true }).click() + await composer.getByRole('checkbox', { name: '系统设计' }).click() + await composer.getByRole('checkbox', { name: 'Agent 产品判断' }).click() + await composer.getByRole('checkbox', { name: 'Agent 产品判断' }).press('Enter') + + await composer.waitFor({ state: 'detached' }) + const restoredInput = page.locator('textarea[placeholder]') + await restoredInput.waitFor() + expect(await restoredInput.getAttribute('placeholder')).toBe('回复生成中,可停止后再输入') + }) + it('stayed clean: no page errors across the whole load chain', () => { expect(pageErrors).toEqual([]) }) diff --git a/apps/web/tests/smoke-real.e2e.ts b/apps/web/tests/smoke-real.e2e.ts index 4e280af0c7..8af42072f8 100644 --- a/apps/web/tests/smoke-real.e2e.ts +++ b/apps/web/tests/smoke-real.e2e.ts @@ -75,10 +75,10 @@ async function detailsTrack(page: Page): Promise<number> { return Number(cols.split(' ').pop()!.replace('px', '')) } -// Readiness gate: `dsh web` serves ALL eight manifest plugins; until every UI +// Readiness gate: `dsh web` serves ALL nine manifest plugins; until every UI // plugin's client bundle exists and exports apply, the loader fail-louds and // the frame never appears. -const UI_PLUGIN_DIRS = ['connection', 'runtime', 'ui-theme', 'i18n', 'ui-layout', 'ui-sidebar', 'ui-conversation', 'ui-trajectory'] +const UI_PLUGIN_DIRS = ['connection', 'runtime', 'ui-theme', 'i18n', 'ui-layout', 'ui-sidebar', 'ui-conversation', 'ui-question', 'ui-trajectory'] const notReady = UI_PLUGIN_DIRS.filter((dir) => { const bundle = join(REPO_ROOT, 'packages/client', dir, 'lib/client.js') return !existsSync(bundle) || !readFileSync(bundle, 'utf8').includes('exports.apply') diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 730ef09965..8f50113ee3 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -1743,6 +1743,7 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co - `@deepseek-ai/dsh-client-runtime` ([`packages/client/runtime/src/index.ts`](../packages/client/runtime/src/index.ts)) - `@deepseek-ai/dsh-client-ui-conversation` ([`packages/client/ui-conversation/src/index.ts`](../packages/client/ui-conversation/src/index.ts)) - `@deepseek-ai/dsh-client-ui-layout` ([`packages/client/ui-layout/src/index.ts`](../packages/client/ui-layout/src/index.ts)) +- `@deepseek-ai/dsh-client-ui-question` — requires `tools` · `userInteraction` ([`packages/client/ui-question/src/index.ts`](../packages/client/ui-question/src/index.ts)) - `@deepseek-ai/dsh-client-ui-sidebar` ([`packages/client/ui-sidebar/src/index.ts`](../packages/client/ui-sidebar/src/index.ts)) - `@deepseek-ai/dsh-client-ui-theme` ([`packages/client/ui-theme/src/index.ts`](../packages/client/ui-theme/src/index.ts)) - `@deepseek-ai/dsh-client-ui-trajectory` ([`packages/client/ui-trajectory/src/index.ts`](../packages/client/ui-trajectory/src/index.ts)) diff --git a/docs/core-data-structures/user-interaction.md b/docs/core-data-structures/user-interaction.md index 46e17f3f83..a65d08e1aa 100644 --- a/docs/core-data-structures/user-interaction.md +++ b/docs/core-data-structures/user-interaction.md @@ -56,14 +56,14 @@ interface AskUserQuestionRequest { ## Answer -Providers return one answer per answered question id. `selected` contains selected option labels, and `custom` carries a free-form "Other" answer when the user typed one. When `custom` is present, `selected` is empty; custom text is an answer override, not a supplement to selected choices. +Providers return one answer item per question id. `selected` contains selected option labels, and `custom` carries a free-form "Other" answer when the user typed one. When `custom` is present, `selected` is empty; custom text is an answer override, not a supplement to selected choices. A UI may also use an item with empty `selected` and no `custom` to preserve a skipped question in an otherwise completed batch. ```ts type-equiv /** Answer to one question. */ interface AskUserQuestionAnswerItem { /** The answered question id. */ id: string - /** Selected option labels. Empty when the answer is purely custom text. */ + /** Selected option labels. Empty for custom or unanswered choices. */ selected: string[] /** Optional free-text "Other" answer. */ custom?: string diff --git a/docs/module-graph.md b/docs/module-graph.md index fd0fe09a12..4188572941 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -133,6 +133,7 @@ flowchart TD pkg_client_ui_conversation["client-ui-conversation"] pkg_client_ui_layout["client-ui-layout"] pkg_client_ui_primitives["client-ui-primitives"] + pkg_client_ui_question["client-ui-question"] pkg_client_ui_sidebar["client-ui-sidebar"] pkg_client_ui_slots["client-ui-slots"] pkg_client_ui_theme["client-ui-theme"] @@ -207,6 +208,7 @@ flowchart TD pkg_client_ui_conversation --> pkg_invariants pkg_client_ui_layout --> pkg_invariants pkg_client_ui_primitives --> pkg_invariants + pkg_client_ui_question --> pkg_invariants pkg_client_ui_sidebar --> pkg_invariants pkg_client_ui_slots --> pkg_invariants pkg_client_ui_theme --> pkg_invariants @@ -706,6 +708,7 @@ flowchart TD | [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | [`invariants`](../packages/support/invariants) | | [`client-ui-layout`](../packages/client/ui-layout) | `client` | [`invariants`](../packages/support/invariants) | | [`client-ui-primitives`](../packages/client/ui-primitives) | `client` | [`invariants`](../packages/support/invariants) | +| [`client-ui-question`](../packages/client/ui-question) | `client` | [`invariants`](../packages/support/invariants) | | [`client-ui-sidebar`](../packages/client/ui-sidebar) | `client` | [`invariants`](../packages/support/invariants) | | [`client-ui-slots`](../packages/client/ui-slots) | `client` | [`invariants`](../packages/support/invariants) | | [`client-ui-theme`](../packages/client/ui-theme) | `client` | [`invariants`](../packages/support/invariants) | diff --git a/packages/client/connection/src/client/fixture.ts b/packages/client/connection/src/client/fixture.ts index 7d4a93e888..aa96bf09a2 100644 --- a/packages/client/connection/src/client/fixture.ts +++ b/packages/client/connection/src/client/fixture.ts @@ -2,8 +2,8 @@ // RpcRequest<P> and returns RpcResponse<T> (echoing the rpcId); streams yield RpcRequest<frame> // (the fixture IS the fake server, so it mints frame rpcIds); root respond takes ClientResponse // and returns RpcReceipt. fx-alpha carries a hand-built history script (60 turns, pageable); -// prompt triggers a chunked streaming replay; cancel stops the replay; one resident pending -// approval (placeholder-card material, subscribed-baseline-replay semantics: stable rpcId reuse). +// prompt triggers a chunked streaming replay; cancel stops the replay; resident pending +// approval/question requests exercise replay and composer takeover with stable rpcIds. import type { ContentBlock } from '@deepseek-ai/dsh-llm/types' import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session/types' @@ -249,6 +249,40 @@ export function createFixtureApi(): ApiProxy { const mint = (): ReturnType<typeof RpcId> => RpcId(`fx-rpc-${nextRpc++}`) /** Resident pending approval (stable rpcId: every mux open replays the same id, matching host replay semantics). */ const pendingApprovalRpcId = mint() + const pendingQuestionRpcId = mint() + let questionPending = true + const fixtureQuestions: Extract<MuxFrame, { type: 'question/requested' }>['questions'] = [ + { + id: 'harness-profile', + header: '偏好', + question: '你现在更想招哪类 Agent/Harness 候选人?', + options: [ + { label: '工程落地型 (Recommended)', description: '更看重能直接做 runtime、tool executor、sandbox、trace 和线上问题排查。' }, + { label: '研究潜力型', description: '更看重 Agent 理解、训练评测思路和长期成长空间。' }, + { label: '均衡型', description: '同时要求工程能力和 Agent 认知,但可能筛选门槛更高。' }, + ], + }, + { + id: 'work-mode', + header: '方式', + question: '你希望候选人优先展示哪种工作方式?', + options: [ + { label: '先做小型原型 (Recommended)', description: '用可运行结果尽快验证关键假设。' }, + { label: '先写完整设计', description: '先收敛边界、协议和风险,再开始实现。' }, + ], + }, + { + id: 'signals', + header: '信号', + question: '哪些面试信号最重要?', + multiSelect: true, + options: [ + { label: '系统设计' }, + { label: '代码质量' }, + { label: 'Agent 产品判断' }, + ], + }, + ] const muxConns = new Set<StreamConn<MuxFrame>>() const hostConns = new Set<StreamConn<HostFrame>>() @@ -429,7 +463,7 @@ export function createFixtureApi(): ApiProxy { muxConns.add(conn) const breakNow = (): void => { conn.breakNow() } streamBreakers.add(breakNow) - // Open baseline: subscribed for attached (running) sessions + pending approval replay (stable rpcId). + // Open baseline: subscribed sessions + pending interactions replayed with stable rpcIds. for (const s of sessions) { if (!s.running) continue conn.push({ rpcId: mint(), payload: { type: 'session/subscribed', sessionId: s.sessionId, lastSeq: (logs.get(s.sessionId)?.length ?? 0) - 1 } }) @@ -442,6 +476,14 @@ export function createFixtureApi(): ApiProxy { toolName: 'dangerous_tool', reason: 'fixture 常驻占位审批(可见不可答)', }, }) + if (questionPending) { + conn.push({ + rpcId: pendingQuestionRpcId, + payload: { + type: 'question/requested', sessionId: sid('fx-alpha'), questions: fixtureQuestions, + }, + }) + } try { yield* conn.drain(signal) } finally { @@ -471,9 +513,16 @@ export function createFixtureApi(): ApiProxy { }, }, respond(message: ClientResponse): Promise<RpcReceipt> { - // The v1 UI never answers (PendingCard is visible but not answerable); implemented for type completeness, always not-pending. - void message - return Promise.resolve({ accepted: false, reason: 'not-pending' }) + if (!questionPending || message.rpcId !== pendingQuestionRpcId) { + return Promise.resolve({ accepted: false, reason: 'not-pending' }) + } + questionPending = false + emitMux({ + type: 'question/resolved', sessionId: sid('fx-alpha'), + questionRpcId: pendingQuestionRpcId, + outcome: message.result.ok ? 'answered' : 'cancelled', + }) + return Promise.resolve({ accepted: true }) }, } } diff --git a/packages/client/connection/tests/fixture.spec.ts b/packages/client/connection/tests/fixture.spec.ts index c50921a44d..b7f5919785 100644 --- a/packages/client/connection/tests/fixture.spec.ts +++ b/packages/client/connection/tests/fixture.spec.ts @@ -148,14 +148,14 @@ describe('createFixtureApi', () => { expect(types.at(-1)).toBe('turn/end') // steer did not restart the turn }) - it('mux open replays the baseline: subscribed for running sessions + the resident approval with a stable rpcId', async () => { + it('mux open replays subscribed sessions and resident interactions with stable rpcIds', async () => { const api = createFixtureApi() const openOnce = async (): Promise<RpcRequest<MuxFrame>[]> => { const abort = new AbortController() const envelopes: RpcRequest<MuxFrame>[] = [] for await (const envelope of api.events.mux(req({}), abort.signal)) { envelopes.push(envelope) - if (envelopes.length >= 2) abort.abort() + if (envelopes.length >= 3) abort.abort() } return envelopes } @@ -165,6 +165,8 @@ describe('createFixtureApi', () => { expect((first[0]?.payload as { lastSeq: number }).lastSeq).toBeGreaterThan(0) expect(first[1]?.payload).toMatchObject({ type: 'approval/requested', toolName: 'dangerous_tool' }) expect(second[1]?.rpcId).toBe(first[1]?.rpcId) // stable rpcId across replays (host replay semantics) + expect(first[2]?.payload).toMatchObject({ type: 'question/requested', sessionId: 'fx-alpha' }) + expect(second[2]?.rpcId).toBe(first[2]?.rpcId) }) it('steer with no replay in flight falls through to a fresh queued turn; non-text blocks stringify empty', async () => { @@ -217,9 +219,38 @@ describe('createFixtureApi', () => { } }) - it('respond is a typed stub: always not-pending', async () => { + it('respond resolves the resident question once and rejects duplicate or unrelated ids', async () => { const api = createFixtureApi() expect(await api.respond({ type: 'client-response', rpcId: RpcId('x'), result: { ok: true, value: {} } })).toEqual({ accepted: false, reason: 'not-pending' }) + const abort = new AbortController() + let question: RpcRequest<MuxFrame> | undefined + for await (const envelope of api.events.mux(req({}), abort.signal)) { + if (envelope.payload.type !== 'question/requested') continue + question = envelope + abort.abort() + } + if (question === undefined) throw new Error('fixture question missing') + const response = { type: 'client-response' as const, rpcId: question.rpcId, result: { ok: true as const, value: {} } } + expect(await api.respond(response)).toEqual({ accepted: true }) + expect(await api.respond(response)).toEqual({ accepted: false, reason: 'not-pending' }) + + const replayAbort = new AbortController() + const replayed = await collect(api.events.mux(req({}), replayAbort.signal), replayAbort, frames => frames.length === 2) + expect(replayed.every(frame => frame.type !== 'question/requested')).toBe(true) + + const cancelledApi = createFixtureApi() + const cancelAbort = new AbortController() + let cancelQuestion: RpcRequest<MuxFrame> | undefined + for await (const envelope of cancelledApi.events.mux(req({}), cancelAbort.signal)) { + if (envelope.payload.type !== 'question/requested') continue + cancelQuestion = envelope + cancelAbort.abort() + } + if (cancelQuestion === undefined) throw new Error('fixture cancellation question missing') + expect(await cancelledApi.respond({ + type: 'client-response', rpcId: cancelQuestion.rpcId, + result: { ok: false, error: { code: 'cancelled', message: 'skip', details: {} } }, + })).toEqual({ accepted: true }) }) it('describe answers the fixture identity', async () => { diff --git a/packages/client/runtime/src/client/sessions/conversation.ts b/packages/client/runtime/src/client/sessions/conversation.ts index 18c5501972..4feb4c1894 100644 --- a/packages/client/runtime/src/client/sessions/conversation.ts +++ b/packages/client/runtime/src/client/sessions/conversation.ts @@ -4,7 +4,7 @@ // string here (narrow to real brands when convenient). import type { ContentBlock } from '@deepseek-ai/dsh-llm/types' -import type { RpcError, RpcId, SessionId, ToolCallView, ToolResultView } from '@deepseek-ai/dsh-client-connection/client' +import type { MuxFrame, RpcError, RpcId, SessionId, ToolCallView, ToolResultView } from '@deepseek-ai/dsh-client-connection/client' /** Assistant content blocks sorted by what the UI cares about * (text body / collapsible reasoning / tool-call card head / other fallback). */ @@ -121,11 +121,14 @@ export interface RunningToolCall { callView: ToolCallView | null } -/** Approval/question placeholder cards (visible, not answerable; - * rpcId = the requested frame's envelope id, the future respond backfill key). */ +/** Approval/question pending state; rpcId is the requested frame's response-backfill key. */ export type PendingInteraction = | { kind: 'approval'; rpcId: RpcId; approvalId: string; toolName: string; callId?: string; reason?: string } - | { kind: 'question'; rpcId: RpcId; questions: readonly unknown[] } + | { + kind: 'question' + rpcId: RpcId + questions: readonly Extract<MuxFrame, { type: 'question/requested' }>['questions'][number][] + } /** In-progress assistant output (chunk accumulator product). */ export interface PartialAssistant { diff --git a/packages/client/runtime/src/client/sessions/session.ts b/packages/client/runtime/src/client/sessions/session.ts index 0934118bd1..b13a1a5bee 100644 --- a/packages/client/runtime/src/client/sessions/session.ts +++ b/packages/client/runtime/src/client/sessions/session.ts @@ -5,7 +5,10 @@ import type { ContentBlock } from '@deepseek-ai/dsh-llm/types' import type { SessionEvent } from '@deepseek-ai/dsh-session/types' -import type { HistoryEntry, IApiClient, MuxFrame, RpcError, RpcId, RpcResult, SessionId, ToolEventView } from '@deepseek-ai/dsh-client-connection/client' +import type { + HistoryEntry, IApiClient, MuxFrame, QuestionResponsePayload, RpcError, RpcId, RpcReceipt, RpcResult, + SessionId, ToolEventView, +} from '@deepseek-ai/dsh-client-connection/client' import { transportError } from '@deepseek-ai/dsh-client-connection/client' import type { ObservableSnapshot, SnapshotSelectorHook } from '@deepseek-ai/dsh-client-web-react' import { bindSnapshotSelector } from '@deepseek-ai/dsh-client-web-react' @@ -120,6 +123,34 @@ export class Session implements ObservableSnapshot<ConversationSnapshot> { return result } + /** + * Answer one host-owned question wait; pending clears only on the authoritative resolved frame. + * @param rpcId - Stable id from the requested frame. + * @param answer - Complete structured answer batch. + * @returns Carrier receipt; rejection leaves pending state unchanged. + */ + answerQuestion(rpcId: RpcId, answer: QuestionResponsePayload['answer']): Promise<RpcReceipt> { + return this.api.respond({ + type: 'client-response', rpcId, + result: { ok: true, value: { sessionId: this.sessionId, answer } }, + }) + } + + /** + * Cancel one host-owned question wait without encoding closure as skipped answers. + * @param rpcId - Stable id from the requested frame. + * @returns Carrier receipt; rejection leaves pending state unchanged. + */ + cancelQuestion(rpcId: RpcId): Promise<RpcReceipt> { + return this.api.respond({ + type: 'client-response', rpcId, + result: { + ok: false, + error: { code: 'cancelled', message: 'the user closed this question request', details: {} }, + }, + }) + } + /** First open: pull the tail page (idempotent — in-flight/already-open returns the existing promise). */ open(): Promise<void> { if (this.openState === 'open') return Promise.resolve() diff --git a/packages/client/runtime/tests/fake-api.ts b/packages/client/runtime/tests/fake-api.ts index c13ef09fcb..839cf2a447 100644 --- a/packages/client/runtime/tests/fake-api.ts +++ b/packages/client/runtime/tests/fake-api.ts @@ -2,7 +2,7 @@ // data source on a real clock; behavior tests need per-case responses and // deferred-controlled timing). Streams are hand pumps: pushMux/pushHost. import type { - HostFrame, IApiClient, MuxFrame, RpcError, RpcRequest, RpcResponse, SessionId, + ClientResponse, HostFrame, IApiClient, MuxFrame, RpcError, RpcReceipt, RpcRequest, RpcResponse, SessionId, } from '@deepseek-ai/dsh-client-connection/client' import { RpcId } from '@deepseek-ai/dsh-client-connection/client' @@ -54,6 +54,7 @@ export class FakeApiClient implements IApiClient { onCancel: (payload: unknown) => Promise<RpcResponse<{ accepted: true }>> = () => Promise.resolve(ok({ accepted: true as const })) onDescribe: (payload: unknown) => Promise<RpcResponse<{ version: string; cwd: string; attachedSessions: number }>> = () => Promise.resolve(ok({ version: '0-fake', cwd: '/f', attachedSessions: 0 })) + onRespond: (message: ClientResponse) => Promise<RpcReceipt> = () => Promise.resolve({ accepted: true }) private readonly muxConns: StreamConn<MuxFrame>[] = [] private readonly hostConns: StreamConn<HostFrame>[] = [] @@ -93,8 +94,8 @@ export class FakeApiClient implements IApiClient { host: (_payload: unknown, signal: AbortSignal, onOpen?: () => void) => this.openStream(this.hostConns, signal, onOpen), } - respond(): Promise<{ accepted: false; reason: 'not-pending' }> { - return Promise.resolve({ accepted: false, reason: 'not-pending' }) + respond(message: ClientResponse): Promise<RpcReceipt> { + return this.record('respond', message, this.onRespond(message)) } /** Push one mux frame to every open mux stream (rpcId minted unless pinned by the case). */ diff --git a/packages/client/runtime/tests/session.spec.ts b/packages/client/runtime/tests/session.spec.ts index 149f73c1fc..b5309c8e8c 100644 --- a/packages/client/runtime/tests/session.spec.ts +++ b/packages/client/runtime/tests/session.spec.ts @@ -251,6 +251,30 @@ describe('pending interactions', () => { session.handleMuxEnvelope('ry' as never, { type: 'question/resolved', sessionId: SID, questionRpcId: 'rq' as never, outcome: 'answered' }) expect(session.getSnapshot().pending).toEqual([]) }) + + it('backfills the requested rpcId for structured answers and explicit cancellation', async () => { + const { api, session } = makeSession() + await session.answerQuestion('rq-answer' as never, { + answers: [{ id: 'mode', selected: ['Fast'] }], + }) + await session.cancelQuestion('rq-cancel' as never) + expect(api.callsOf('respond')).toEqual([ + { + type: 'client-response', rpcId: 'rq-answer', + result: { + ok: true, + value: { sessionId: SID, answer: { answers: [{ id: 'mode', selected: ['Fast'] }] } }, + }, + }, + { + type: 'client-response', rpcId: 'rq-cancel', + result: { + ok: false, + error: { code: 'cancelled', message: 'the user closed this question request', details: {} }, + }, + }, + ]) + }) }) describe('remaining branches', () => { diff --git a/packages/client/ui-conversation/README.md b/packages/client/ui-conversation/README.md index c75077d11d..67af7c07b1 100644 --- a/packages/client/ui-conversation/README.md +++ b/packages/client/ui-conversation/README.md @@ -1,6 +1,6 @@ # @deepseek-ai/dsh-client-ui-conversation -Conversation domain: skeleton (header/tabs/composer/empty state), chat view (grouped step-summary flow, streaming tail isolation), ctx.toolviews named registry with bash samples, minimal details panel, scope-addressed ConversationService. Contract: api-contracts v3 §7. +Conversation domain: skeleton (header/tabs/composer/empty state), chat view (grouped step-summary flow, streaming tail isolation), ctx.toolviews named registry with bash samples, minimal details panel, scope-addressed ConversationService. The keyed `conversation.composer` slot lets pending interaction features replace InputBar without moving interaction state into the skeleton. Contract: api-contracts v3 §7. `src/client/` is organized for the future package split: `contract/` is the sole inter-domain shared face (`slots.ts` composed slot props, `views.ts` view ring, `toolview.ts` tool ring, `tool-call-model.ts`); the `skeleton/`, `chat/`, and `toolviews/` domain directories import contract files and never each other; `apply.ts` is the only assembly point allowed to import all three domains. @@ -18,5 +18,5 @@ None; this package neither assembles nor sends a provider request. - **Details panel is the minimal form** — selected call args/result raw display; the Input/Output/Metadata switch, Prev/Next stepping, and See-in-trajectory deep link are deferred. - **Assistant footer extensions (IconActions row, per-message paging) are reserved slots** — drawn in the design, not implemented. - **The sparkle icon for the others tool row is a hand-drawn approximation** — the design glyph's vector geometry is not exportable locally; promotion into ui-primitives waits on an exact export. -- **Approval/question cards are display-only placeholders** — web-side answering (composer takeover panel) is the P-II approvals project. +- **Approval cards are display-only placeholders** — question requests use the composer slot, while Web approval answering remains deferred. - **Module-level toolview caches are single-bundle state** — the inject cache and registry maps must reach cross-bundle consumers through the package export surface and loader module table, never by a second bundle copy. diff --git a/packages/client/ui-conversation/src/client/apply.ts b/packages/client/ui-conversation/src/client/apply.ts index a600789a20..8153034497 100644 --- a/packages/client/ui-conversation/src/client/apply.ts +++ b/packages/client/ui-conversation/src/client/apply.ts @@ -62,6 +62,8 @@ export function apply(ctx: Context): void { const layout = need<LayoutService>(ctx, 'layout') const i18n = need<I18nService>(ctx, 'i18n') const slots = need<SlotsService>(ctx, 'slots') + slots.define('conversation.composer', { kind: 'keyed', scope: 'session' }) + const composerSlots = scopedSlots(slots.core, 'conversation.composer') const conversation = new ConversationService(ctx) const toolviews = new ToolViewRegistry() @@ -153,6 +155,7 @@ export function apply(ctx: Context): void { } return createElement(Fragment, null, ...children) }, + slots: composerSlots, } return injected } diff --git a/packages/client/ui-conversation/src/client/chat/ChatView.tsx b/packages/client/ui-conversation/src/client/chat/ChatView.tsx index b8ea969829..faa6323656 100644 --- a/packages/client/ui-conversation/src/client/chat/ChatView.tsx +++ b/packages/client/ui-conversation/src/client/chat/ChatView.tsx @@ -270,7 +270,9 @@ export function createChatView(deps: ChatViewDeps): FC<ConvViewProps> { ))} </div> )} - {pending.map((item) => <PendingCard key={item.rpcId} item={item} />)} + {pending.map((item) => item.kind === 'approval' + ? <PendingCard key={item.rpcId} item={item} /> + : null)} </div> </div> {!atBottom && ( diff --git a/packages/client/ui-conversation/src/client/chat/PendingCard.tsx b/packages/client/ui-conversation/src/client/chat/PendingCard.tsx index 56b886c9ad..408faa7ddf 100644 --- a/packages/client/ui-conversation/src/client/chat/PendingCard.tsx +++ b/packages/client/ui-conversation/src/client/chat/PendingCard.tsx @@ -1,30 +1,18 @@ -// PendingCard: approval/question placeholder card (visible, not answerable — -// the composer-takeover approval panel is a P-II item; wire pending semantics -// already exist so the flow must show them). +// PendingCard: approval placeholder card. Questions take over the composer. import { memo } from 'react' import type { PendingInteraction } from '@deepseek-ai/dsh-client-runtime/client' -import { JsonBlock } from '@deepseek-ai/dsh-client-ui-primitives' import css from './PendingCard.module.css' export interface PendingCardProps { - item: PendingInteraction + item: Extract<PendingInteraction, { kind: 'approval' }> } export const PendingCard = memo(function PendingCard({ item }: PendingCardProps) { return ( <div className={css.card}> - {item.kind === 'approval' ? ( - <> - <div className={css.title}>等待审批:<span className={css.mono}>{item.toolName}</span></div> - {item.reason !== undefined && <div className={css.reason}>{item.reason}</div>} - </> - ) : ( - <> - <div className={css.title}>等待回答({item.questions.length} 题)</div> - <JsonBlock label="问题内容" payload={item.questions} /> - </> - )} + <div className={css.title}>等待审批:<span className={css.mono}>{item.toolName}</span></div> + {item.reason !== undefined && <div className={css.reason}>{item.reason}</div>} <div className={css.hint}>请在原客户端处理(web 端作答后续里程碑提供)</div> </div> ) diff --git a/packages/client/ui-conversation/src/client/contract/slots.ts b/packages/client/ui-conversation/src/client/contract/slots.ts index 276ae1ec30..d05c7f319b 100644 --- a/packages/client/ui-conversation/src/client/contract/slots.ts +++ b/packages/client/ui-conversation/src/client/contract/slots.ts @@ -8,7 +8,8 @@ * standard share & own injected share. */ import type { ReactNode } from 'react' -import type { SessionId, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' +import type { PendingInteraction, SessionId, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' +import type { ScopedSlots } from '@deepseek-ai/dsh-client-ui-slots' import type { SnapshotSelectorHook, UseSession } from '@deepseek-ai/dsh-client-web-react' import type { ConvOwnerProps, DetailsOwnerProps, EmptyOwnerProps } from '@deepseek-ai/dsh-client-ui-layout/client' import type { SelectionTarget, ViewEntry, ViewId } from './views.ts' @@ -38,6 +39,13 @@ export interface ConversationInjected { } /** Renders the active view's body (the owner closes over ConvViewProps assembly). */ renderView: (entry: ViewEntry) => ReactNode + /** Feature-owned composer replacements, dispatched by pending interaction kind. */ + slots: ScopedSlots<'conversation.composer'> +} + +/** Question-composer owner share supplied by ConversationRoot. */ +export interface QuestionComposerOwnerProps { + interaction: Extract<PendingInteraction, { kind: 'question' }> } /** Full conversation-slot component props: owner share & standard share & injected share. */ diff --git a/packages/client/ui-conversation/src/client/index.ts b/packages/client/ui-conversation/src/client/index.ts index 17e9ed88a8..d3b20775a8 100644 --- a/packages/client/ui-conversation/src/client/index.ts +++ b/packages/client/ui-conversation/src/client/index.ts @@ -8,6 +8,7 @@ */ import type { ConversationService } from './service.ts' import type { ToolViewRegistry } from './toolviews/registry.ts' +import type { QuestionComposerOwnerProps } from './contract/slots.ts' export { apply, inject } from './apply.ts' export { ConversationService } from './service.ts' @@ -22,7 +23,7 @@ export type { } from './contract/toolview.ts' export type { ConversationInjected, ConversationSlotProps, DetailsInjected, DetailsSlotProps, - EmptyStateInjected, EmptyStateSlotProps, + EmptyStateInjected, EmptyStateSlotProps, QuestionComposerOwnerProps, } from './contract/slots.ts' export { ConversationRoot } from './skeleton/ConversationRoot.tsx' @@ -40,3 +41,13 @@ declare module 'cordis' { toolviews: ToolViewRegistry } } + +declare module '@deepseek-ai/dsh-client-ui-slots' { + interface SlotMap { + 'conversation.composer': { + kind: 'keyed' + scope: 'session' + owner: QuestionComposerOwnerProps + } + } +} diff --git a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx index 540b76bda7..8f548e54b4 100644 --- a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx +++ b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx @@ -7,6 +7,7 @@ import { useSyncExternalStore } from 'react' import clsx from 'clsx' +import type { PendingInteraction } from '@deepseek-ai/dsh-client-runtime/client' import type { ConversationSlotProps } from '../contract/slots.ts' import { InputBar } from './InputBar.tsx' import type { InputBarError } from './InputBar.tsx' @@ -20,7 +21,7 @@ import css from './ConversationRoot.module.css' export type ConversationRootProps = ConversationSlotProps export function ConversationRoot({ - sessionId, useSession, useAncestry, views, useActiveView, composer, actions, renderView, + sessionId, useSession, useAncestry, views, useActiveView, composer, actions, renderView, slots, }: ConversationRootProps) { useSyncExternalStore(views.subscribe, views.version) const list = views.list() @@ -33,6 +34,9 @@ export function ConversationRoot({ const removed = useSession(s => (s as { removed: boolean }).removed) const promptError = useSession(s => (s as { promptError: { op: 'send' | 'stop'; error: { message: string; code: string } } | null }).promptError) const turns = useSession(s => countTurns(s as { nodes: readonly { kind: string }[] })) + const question = useSession(s => ( + s as { pending: readonly PendingInteraction[] } + ).pending.find(item => item.kind === 'question')) const error: InputBarError | null = promptError === null ? null @@ -87,20 +91,37 @@ export function ConversationRoot({ {active !== undefined && renderView(active)} </div> - <InputBar - draft={draft} - running={running} - disabled={removed} - error={error} - variant="composer" - onDraftChange={composer.setDraft} - onSend={composer.send} - onStop={composer.stop} - /> + {question?.kind === 'question' + ? slots.renderSlot('conversation.composer', { interaction: question }, { + entryKey: 'question', + fallback: <ComposerInput {...{ draft, running, removed, error, composer }} />, + }) + : <ComposerInput {...{ draft, running, removed, error, composer }} />} </div> ) } +function ComposerInput({ draft, running, removed, error, composer }: { + draft: string + running: boolean + removed: boolean + error: InputBarError | null + composer: ConversationSlotProps['composer'] +}) { + return ( + <InputBar + draft={draft} + running={running} + disabled={removed} + error={error} + variant="composer" + onDraftChange={composer.setDraft} + onSend={composer.send} + onStop={composer.stop} + /> + ) +} + /** Turn count = user message nodes in the window (display meta; exact host count deferred). */ function countTurns(s: { nodes: readonly { kind: string }[] }): number { let n = 0 diff --git a/packages/client/ui-conversation/tests/chat-view.spec.tsx b/packages/client/ui-conversation/tests/chat-view.spec.tsx index af4f80c0b4..9364979d42 100644 --- a/packages/client/ui-conversation/tests/chat-view.spec.tsx +++ b/packages/client/ui-conversation/tests/chat-view.spec.tsx @@ -295,11 +295,18 @@ describe('ChatView', () => { expect(lv.getByText('载入历史…')).toBeTruthy() }) - it('pending interactions render placeholder cards', () => { + it('renders approval cards while questions stay in the composer', () => { const h = makeHarness({ - pending: [{ kind: 'approval', rpcId: 'r1' as never, approvalId: 'ap1', toolName: 'bash' }], + pending: [ + { kind: 'approval', rpcId: 'r1' as never, approvalId: 'ap1', toolName: 'bash' }, + { + kind: 'question', rpcId: 'r2' as never, + questions: [{ id: 'mode', question: 'Composer only?', options: [{ label: 'Yes' }] }], + }, + ], }) const view = render(<h.ChatView {...h.props} />) expect(view.getByText(/等待审批/)).toBeTruthy() + expect(view.queryByText('Composer only?')).toBeNull() }) }) diff --git a/packages/client/ui-conversation/tests/coverage-tails.spec.tsx b/packages/client/ui-conversation/tests/coverage-tails.spec.tsx index 2bdcb52902..bc829314eb 100644 --- a/packages/client/ui-conversation/tests/coverage-tails.spec.tsx +++ b/packages/client/ui-conversation/tests/coverage-tails.spec.tsx @@ -1,20 +1,18 @@ // @vitest-environment jsdom // Branch tails the acceptance specs do not reach: ToolRow stopped-state dot, -// PendingCard question arm, bash sample error pill, registry disposer +// Bash sample error pill and registry disposer // idempotence re-entry, register.ts explicit bashSampleScope override, the // node-half empty apply, and AssistantMarkdown reasoning/unknown block arms. import { afterEach, describe, expect, it, vi } from 'vitest' import { cleanup, render } from '@testing-library/react' import type { ToolResultNode } from '@deepseek-ai/dsh-client-runtime/client' -import type { RpcId } from '@deepseek-ai/dsh-client-connection/client' import type { UseSession } from '@deepseek-ai/dsh-client-web-react' import { ToolViewRegistry } from '@deepseek-ai/dsh-client-ui-conversation/client' import type { ConversationService, Translate, ToolViewProps } from '@deepseek-ai/dsh-client-ui-conversation/client' import { apply as nodeApply } from '../src/index.ts' import { GenericToolCard } from '../src/client/chat/GenericToolCard.tsx' import { ToolRow } from '../src/client/chat/ToolRow.tsx' -import { PendingCard } from '../src/client/chat/PendingCard.tsx' import { AssistantMarkdown } from '../src/client/chat/AssistantMarkdown.tsx' import { BashRow } from '../src/client/toolviews/bash-sample.tsx' import { registerChat } from '../src/client/chat/register.ts' @@ -34,13 +32,6 @@ describe('tails', () => { expect(view.container.querySelector('[data-state="stopped"]')).not.toBeNull() }) - it('PendingCard renders the question arm with its count', () => { - const view = render( - <PendingCard item={{ kind: 'question', rpcId: 'r1' as RpcId, questions: [{}, {}] }} />, - ) - expect(view.getByText(/等待回答(2 题)/)).toBeTruthy() - }) - it('AssistantMarkdown renders reasoning as a Think row and unknown blocks as JSON fallback', () => { const view = render( <AssistantMarkdown diff --git a/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx b/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx index 25808e17c5..bd2a5e397c 100644 --- a/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx +++ b/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx @@ -10,11 +10,14 @@ import { bindSnapshotSelector } from '@deepseek-ai/dsh-client-web-react' import type { UseSession } from '@deepseek-ai/dsh-client-web-react' import type { ConversationSnapshot, SessionId, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' import { ConversationRoot, DetailsPanel, EmptyState } from '@deepseek-ai/dsh-client-ui-conversation/client' -import type { SelectionTarget, ViewEntry } from '@deepseek-ai/dsh-client-ui-conversation/client' +import type { ConversationInjected, SelectionTarget, ViewEntry } from '@deepseek-ai/dsh-client-ui-conversation/client' afterEach(cleanup) const SID = 's1' as SessionId +const fallbackSlots: ConversationInjected['slots'] = { + renderSlot: (_key, _props, opts) => opts?.fallback ?? null, +} function snapshotBase(): ConversationSnapshot { return { @@ -55,6 +58,7 @@ describe('ConversationRoot branches', () => { composer={{ useDraft: () => '', setDraft: vi.fn(), send: vi.fn(), stop: vi.fn() }} actions={{ openView: vi.fn(), open }} renderView={() => <div data-testid="view-body" />} + slots={fallbackSlots} />, ) return { view, open } @@ -99,6 +103,7 @@ describe('ConversationRoot branches', () => { composer={{ useDraft: () => '', setDraft: vi.fn(), send: vi.fn(), stop: vi.fn() }} actions={{ openView: vi.fn(), open: vi.fn() }} renderView={(entry) => <div data-testid={`body-${entry.id}`} />} + slots={fallbackSlots} />, ) expect(view.getByTestId('body-chat')).toBeTruthy() diff --git a/packages/client/ui-conversation/tests/skeleton.spec.tsx b/packages/client/ui-conversation/tests/skeleton.spec.tsx index ab23a64389..cf172353f4 100644 --- a/packages/client/ui-conversation/tests/skeleton.spec.tsx +++ b/packages/client/ui-conversation/tests/skeleton.spec.tsx @@ -11,11 +11,11 @@ import { afterEach, describe, expect, it, vi } from 'vitest' import type { FC } from 'react' import { bindSnapshotSelector, createSnapshotStore } from '@deepseek-ai/dsh-client-web-react' import type { UseSession } from '@deepseek-ai/dsh-client-web-react' -import type { SessionId, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' +import type { PendingInteraction, SessionId, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' import { ConversationRoot, DetailsPanel, EmptyState, } from '@deepseek-ai/dsh-client-ui-conversation/client' -import type { SelectionTarget, ViewEntry, ViewId } from '@deepseek-ai/dsh-client-ui-conversation/client' +import type { ConversationInjected, SelectionTarget, ViewEntry, ViewId } from '@deepseek-ai/dsh-client-ui-conversation/client' const sid = (s: string): SessionId => s as SessionId @@ -28,11 +28,12 @@ interface FakeSnapshot { running: boolean removed: boolean promptError: { op: 'send' | 'stop'; error: { message: string; code: string } } | null + pending: readonly PendingInteraction[] } function fakeSession(init: Partial<FakeSnapshot> = {}) { const store = createSnapshotStore<FakeSnapshot>({ - nodes: [], runningCalls: [], running: false, removed: false, promptError: null, ...init, + nodes: [], runningCalls: [], running: false, removed: false, promptError: null, pending: [], ...init, }) return { store, useSession: bindSnapshotSelector(store) as unknown as UseSession } } @@ -67,8 +68,11 @@ describe('EmptyState', () => { }) describe('ConversationRoot', () => { - function bench(views: ViewEntry[], active?: string) { - const { useSession } = fakeSession({ nodes: [{ kind: 'user' }, { kind: 'user' }] }) + function bench( + views: ViewEntry[], active?: string, init: Partial<FakeSnapshot> = {}, + renderSlot?: ConversationInjected['slots']['renderSlot'], + ) { + const { useSession } = fakeSession({ nodes: [{ kind: 'user' }, { kind: 'user' }], ...init }) const activeStore = createSnapshotStore<string | undefined>(active) const openView = vi.fn((v: string) => { activeStore.set(v) }) const open = vi.fn() @@ -98,6 +102,7 @@ describe('ConversationRoot', () => { }} actions={{ openView: openView as (v: never) => void, open }} renderView={(entry) => { rendered.push(entry.id); return <div data-testid={`view-${entry.id}`} /> }} + slots={{ renderSlot: renderSlot ?? ((_key, _props, opts) => opts?.fallback ?? null) } as ConversationInjected['slots']} />) return { ui, openView, open, rendered, send, drafts } } @@ -133,6 +138,23 @@ describe('ConversationRoot', () => { fireEvent.keyDown(box, { key: 'Enter' }) expect(send).toHaveBeenCalledWith('queue') }) + + it('dispatches a pending question to the composer slot instead of rendering InputBar', () => { + const renderSlot = vi.fn(() => <div>question takeover</div>) as unknown as ConversationInjected['slots']['renderSlot'] + bench([view('chat', 'Chat')], undefined, { + pending: [{ + kind: 'question', rpcId: 'rq' as never, + questions: [{ id: 'mode', question: 'Choose?', options: [{ label: 'Fast' }] }], + }], + }, renderSlot) + expect(screen.getByText('question takeover')).toBeTruthy() + expect(screen.queryByPlaceholderText(/输入消息/)).toBeNull() + expect(renderSlot).toHaveBeenCalledWith( + 'conversation.composer', + expect.objectContaining({ interaction: expect.objectContaining({ rpcId: 'rq' }) }), + expect.objectContaining({ entryKey: 'question' }), + ) + }) }) describe('DetailsPanel', () => { diff --git a/packages/client/ui-question/README.md b/packages/client/ui-question/README.md new file mode 100644 index 0000000000..a02c85d54c --- /dev/null +++ b/packages/client/ui-question/README.md @@ -0,0 +1,20 @@ +# @deepseek-ai/dsh-client-ui-question + +Web `ask_user_question` feature plugin. Its host half mounts `dsh-tool-ask-user` only when the Web feature is selected; its browser half registers the `question` entry in the conversation-owned `conversation.composer` keyed slot. + +The component renders one question at a time with progress navigation, single- and multi-select choices, recommendation badges derived from label suffixes, and custom answers. Single-select choices advance immediately, and Enter submits once every question is answered or skipped; Enter during IME composition confirms the input candidate without advancing. It submits one structured answer batch for the whole request: “Skip this question” retains other drafts and emits the existing blank `{ selected: [] }` shape for that item, while close rejects the whole wait as `ASK_CANCELLED`. + +Selection state is local to a component keyed by the request rpcId. A replay with the same id preserves a still-mounted draft, while `question/resolved` from the host removes the composer. The host remains authoritative: successful HTTP delivery does not remove pending state locally. + +## Model Experience + +Indirectly, through `dsh-tool-ask-user`; that package owns the model-visible tool schema and structured result. + +#### KV Cache effect + +No direct invalidation; `dsh-tool-ask-user` owns the model-visible tool call and result. + +## Known Limitations and Deferred Work + +- **Unsubmitted drafts are not durable** — reconnect resync or a full page reload restores the host-owned pending request with the same rpcId, but a composer unmount resets local option and custom-text drafts. +- **One request owns the composer at a time** — later pending requests remain in the session snapshot and become visible after the earlier request resolves. diff --git a/packages/client/ui-question/package.json b/packages/client/ui-question/package.json new file mode 100644 index 0000000000..d144ecf1d1 --- /dev/null +++ b/packages/client/ui-question/package.json @@ -0,0 +1,66 @@ +{ + "name": "@deepseek-ai/dsh-client-ui-question", + "description": "Web ask_user_question feature: host tool mount plus composer-takeover question UI", + "version": "0.0.1", + "private": true, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./client": { + "types": "./lib/types/client/index.d.ts", + "default": "./lib/client.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "dshClient": { + "inject": [ + "@deepseek-ai/dsh-client-ui-conversation" + ], + "platform": "web" + }, + "scripts": { + "bundle": "tsdown", + "watch": "tsdown --watch" + }, + "license": "BSD-3-Clause", + "dependencies": { + "@deepseek-ai/dsh-client-connection": "workspace:^", + "@deepseek-ai/dsh-client-runtime": "workspace:^", + "@deepseek-ai/dsh-client-ui-conversation": "workspace:^", + "@deepseek-ai/dsh-client-ui-primitives": "workspace:^", + "@deepseek-ai/dsh-tool-ask-user": "workspace:^", + "clsx": "^2.0.0", + "react": "^18.2.0" + }, + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.0.1", + "cordis": "^4.0.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/dsh-agent": "workspace:^", + "@deepseek-ai/dsh-invariants": "workspace:^", + "@deepseek-ai/dsh-system-prompt": "workspace:^", + "@deepseek-ai/dsh-tools": "workspace:^", + "@deepseek-ai/dsh-user-interaction": "workspace:^", + "@types/react": "~18.3.1", + "cordis": "^4.0.0-rc.7" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/client.js", + "lib/types/**/*.d.ts", + "lib/types/**/*.d.ts.map", + "src" + ] +} diff --git a/packages/client/ui-question/src/client/QuestionComposer.module.css b/packages/client/ui-question/src/client/QuestionComposer.module.css new file mode 100644 index 0000000000..21cd664ee3 --- /dev/null +++ b/packages/client/ui-question/src/client/QuestionComposer.module.css @@ -0,0 +1,329 @@ +.frame { + display: flex; + justify-content: center; + padding: 6px 24px 10px; +} + +.card { + width: 100%; + max-width: 720px; + padding: 14px 16px 12px; + border: 1px solid var(--dsw-alias-border-l2-darkmode-thin); + border-radius: 18px; + background: var(--dsw-specific-input-major); + box-shadow: var(--dsw-shadow-lv1-blur); + color: var(--dsw-alias-label-primary); +} + +.card, +.card * { + box-sizing: border-box; +} + +.header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16px; + margin-bottom: 8px; +} + +.headingBlock { + min-width: 0; + padding: 1px 2px; +} + +.eyebrow { + margin-bottom: 2px; + color: var(--dsw-alias-label-tertiary); + font-size: 11px; + line-height: 16px; +} + +.title { + display: flex; + align-items: baseline; + flex-wrap: wrap; + gap: 6px; + margin: 0; + font-size: 16px; + line-height: 22px; + font-weight: 600; +} + +.multiSelectHint { + color: var(--dsw-alias-label-tertiary); + font-size: 14px; + line-height: 20px; + font-weight: 400; + white-space: nowrap; +} + +.headerActions, +.footerActions { + display: flex; + align-items: center; + gap: 4px; + flex-shrink: 0; +} + +.progress { + padding: 0 6px; + color: var(--dsw-alias-label-tertiary); + font-size: 12px; + line-height: 24px; + white-space: nowrap; +} + +.iconButton { + display: grid; + place-items: center; + width: 24px; + height: 24px; + padding: 0; + border: none; + border-radius: 999px; + background: transparent; + color: var(--dsw-alias-label-tertiary); + cursor: pointer; +} + +.iconButton:hover:not(:disabled) { + background: var(--dsw-alias-interactive-bg-hover); + color: var(--dsw-alias-label-primary); +} + +.iconButton:disabled { + color: var(--dsw-alias-label-dimmed); + cursor: default; +} + +.options { + display: flex; + flex-direction: column; + gap: 4px; +} + +.option { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + min-height: 42px; + padding: 5px 8px; + border: 1px solid transparent; + border-radius: 12px; + background: transparent; + color: inherit; + text-align: left; + cursor: pointer; + transition: background-color 120ms ease, border-color 120ms ease; +} + +.option:hover:not(:disabled), +.optionSelected { + background: var(--dsw-alias-interactive-bg-hover); +} + +.optionSelected { + border-color: var(--dsw-alias-border-l2); +} + +.option:disabled, +.customTrigger:disabled { + cursor: default; +} + +.number { + display: grid; + place-items: center; + flex: 0 0 28px; + width: 28px; + height: 28px; + border: 1px solid var(--dsw-alias-border-l2); + border-radius: 999px; + background: var(--dsw-alias-bg-module-platform); + color: var(--dsw-alias-label-tertiary); + font-size: 12px; + line-height: 18px; +} + +.optionCopy { + min-width: 0; + flex: 1; +} + +.optionLine { + display: flex; + align-items: baseline; + flex-wrap: wrap; + gap: 2px 6px; +} + +.optionLabel { + font-size: 14px; + line-height: 20px; + font-weight: 600; +} + +.badge { + padding: 0 6px; + border-radius: 999px; + background: var(--dsw-alias-bg-module-platform); + color: var(--dsw-alias-label-secondary); + font-size: 11px; + line-height: 18px; +} + +.description { + color: var(--dsw-alias-label-tertiary); + font-size: 13px; + line-height: 20px; + font-weight: 400; +} + +.choiceIcon { + display: grid; + place-items: center; + width: 20px; + color: var(--dsw-alias-label-tertiary); +} + +.custom { + border: 1px solid transparent; + border-radius: 12px; +} + +.customOpen { + border-color: var(--dsw-alias-border-l2); + background: var(--dsw-alias-bg-module-platform); +} + +.customOptionless { + border: none; + background: transparent; +} + +.customTrigger { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + min-height: 42px; + padding: 5px 8px; + border: none; + background: transparent; + color: var(--dsw-alias-label-tertiary); + font-size: 14px; + line-height: 20px; + text-align: left; + cursor: pointer; +} + +.customTrigger:hover:not(:disabled) { + color: var(--dsw-alias-label-primary); +} + +.customInput { + display: block; + width: calc(100% - 20px); + min-height: 54px; + max-height: 140px; + margin: 0 10px 10px; + padding: 7px 10px; + resize: vertical; + border: 1px solid var(--dsw-alias-border-l2); + border-radius: 10px; + outline: none; + background: var(--dsw-specific-input-major); + color: var(--dsw-alias-label-primary); + caret-color: var(--dsw-alias-state-business-primary); + font: inherit; + font-size: 13px; + line-height: 20px; +} + +.customInput:focus { + border-color: var(--dsw-alias-state-business-primary); +} + +.customInput::placeholder { + color: var(--dsw-alias-label-caption); +} + +.customOptionless .customInput { + width: 100%; + min-height: 58px; + margin: 0; + background: var(--dsw-alias-bg-module-platform); +} + +.footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-top: 8px; + padding: 0 2px; +} + +.feedback { + min-height: 16px; + color: var(--dsw-alias-state-error-primary); + font-size: 11px; + line-height: 16px; +} + +@media (max-width: 720px) { + .frame { + padding: 6px 10px 10px; + } + + .card { + padding: 12px 10px 10px; + border-radius: 16px; + } + + .header { + display: block; + } + + .headerActions { + justify-content: flex-end; + margin-top: 8px; + } + + .headingBlock { + padding: 0 2px; + } + + .title { + font-size: 15px; + line-height: 21px; + } + + .option, + .customTrigger { + align-items: flex-start; + gap: 8px; + padding: 6px; + } + + .choiceIcon { + margin-top: 3px; + } + + .footer { + align-items: flex-end; + } + + .footerActions { + flex-shrink: 0; + } +} + +@media (prefers-reduced-motion: reduce) { + .option { + transition: none; + } +} diff --git a/packages/client/ui-question/src/client/QuestionComposer.tsx b/packages/client/ui-question/src/client/QuestionComposer.tsx new file mode 100644 index 0000000000..49f74ce7f7 --- /dev/null +++ b/packages/client/ui-question/src/client/QuestionComposer.tsx @@ -0,0 +1,308 @@ +import { useState, type KeyboardEvent } from 'react' +import clsx from 'clsx' +import type { QuestionResponsePayload } from '@deepseek-ai/dsh-client-connection/client' +import type { PendingInteraction } from '@deepseek-ai/dsh-client-runtime/client' +import { + Button, IconCheckOutline16, IconChevronLeftOutline14, IconChevronRightOutline14, + IconCloseOutline16, IconEditOutline16, +} from '@deepseek-ai/dsh-client-ui-primitives' +import type { QuestionComposerOwnerProps } from '@deepseek-ai/dsh-client-ui-conversation/client' +import css from './QuestionComposer.module.css' + +type QuestionInteraction = Extract<PendingInteraction, { kind: 'question' }> +type Answer = QuestionResponsePayload['answer'] + +interface DraftAnswer { + selected: string[] + custom: string + customOpen: boolean + skipped: boolean +} + +/** Actions assembled from the session object layer. */ +export interface QuestionComposerInjected { + actions: { + answer(interaction: QuestionInteraction, answer: Answer): Promise<void> + cancel(interaction: QuestionInteraction): Promise<void> + } +} + +/** Full question-composer props. */ +export type QuestionComposerProps = QuestionComposerOwnerProps & QuestionComposerInjected + +/** + * Split the conventional recommendation suffix without changing the answer value. + * @param label - Original option label returned if selected. + * @returns Display label plus recommendation state. + */ +export function parseRecommendedLabel(label: string): { label: string; recommended: boolean } { + const suffix = /\s*(?:\((?:recommended|推荐)\)|((?:recommended|推荐)))\s*$/i + return suffix.test(label) + ? { label: label.replace(suffix, ''), recommended: true } + : { label, recommended: false } +} + +/** + * Remove a conventional multi-select suffix so the hint can be styled separately. + * @param title - Question title supplied by the interaction request. + * @returns Question title without a trailing multi-select marker. + */ +export function parseQuestionTitle(title: string): string { + return title.replace(/\s*[((]可多选[))]\s*$/, '') +} + +/** Return whether a textarea key event belongs to an active IME composition. */ +function isComposing(event: KeyboardEvent<HTMLTextAreaElement>): boolean { + return event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229 +} + +/** + * Composer takeover boundary; rpcId keys local drafts while same-id replay preserves them. + * @param props - Pending interaction and scoped answer/cancel actions. + * @returns The question flow for this request. + */ +export function QuestionComposer(props: QuestionComposerProps) { + return <QuestionFlow key={props.interaction.rpcId} {...props} /> +} + +function QuestionFlow({ interaction, actions }: QuestionComposerProps) { + const questions = interaction.questions + const [index, setIndex] = useState(0) + const [drafts, setDrafts] = useState<DraftAnswer[]>(() => questions.map(question => ({ + selected: [], custom: '', customOpen: (question.options?.length ?? 0) === 0, skipped: false, + }))) + const [busy, setBusy] = useState<'answer' | 'cancel' | null>(null) + const [error, setError] = useState<string | null>(null) + const question = questions[index]! + const draft = drafts[index]! + const hasOptions = (question.options?.length ?? 0) > 0 + + const cancelFlow = (): void => { + setBusy('cancel') + setError(null) + void actions.cancel(interaction).catch((cause: unknown) => { + setBusy(null) + setError(cause instanceof Error ? cause.message : String(cause)) + }) + } + + const updateDraft = (update: (current: DraftAnswer) => DraftAnswer): void => { + setDrafts(current => current.map((item, itemIndex) => itemIndex === index ? update(item) : item)) + setError(null) + } + + const choose = (label: string): void => { + updateDraft((current) => { + const selected = question.multiSelect === true + ? current.selected.includes(label) + ? current.selected.filter(item => item !== label) + : [...current.selected, label] + : [label] + return { selected, custom: '', customOpen: false, skipped: false } + }) + if (question.multiSelect !== true && index < questions.length - 1) { + setIndex(current => current + 1) + } + } + + const openCustom = (): void => { + updateDraft(current => ({ ...current, selected: [], customOpen: true, skipped: false })) + } + + const answered = (item: DraftAnswer): boolean => + item.selected.length > 0 || item.custom.trim() !== '' + + const completed = (item: DraftAnswer): boolean => answered(item) || item.skipped + + const submitDrafts = (values: DraftAnswer[]): void => { + const missing = values.findIndex(item => !completed(item)) + if (missing >= 0) { + setIndex(missing) + setError('请先完成这道问题。') + return + } + const answer: Answer = { + answers: questions.map((item, itemIndex) => { + const value = values[itemIndex] as DraftAnswer + if (value.skipped) return { id: item.id, selected: [] } + const custom = value.custom.trim() + return { + id: item.id, + selected: custom === '' ? value.selected : [], + ...(custom === '' ? {} : { custom }), + } + }), + } + setBusy('answer') + setError(null) + void actions.answer(interaction, answer).catch((cause: unknown) => { + setBusy(null) + setError(cause instanceof Error ? cause.message : String(cause)) + }) + } + + const continueFlow = (): void => { + if (!answered(draft)) { + setError('请选择一个选项或填写自定义答案。') + return + } + if (index < questions.length - 1) { + setIndex(current => current + 1) + setError(null) + return + } + submitDrafts(drafts) + } + + const skipQuestion = (): void => { + const nextDrafts = drafts.map((item, itemIndex) => itemIndex === index + ? { + selected: [], custom: '', + customOpen: (question.options?.length ?? 0) === 0, + skipped: true, + } + : item) + setDrafts(nextDrafts) + setError(null) + if (index < questions.length - 1) { + setIndex(current => current + 1) + return + } + submitDrafts(nextDrafts) + } + + return ( + <div className={css.frame} data-question-rpc-id={interaction.rpcId}> + <section className={css.card} aria-labelledby={`question-${interaction.rpcId}-${String(index)}`}> + <header className={css.header}> + <div className={css.headingBlock}> + {question.header !== undefined && <div className={css.eyebrow}>{question.header}</div>} + <h2 className={css.title} id={`question-${interaction.rpcId}-${String(index)}`}> + <span>{question.multiSelect === true + ? parseQuestionTitle(question.question) + : question.question}</span> + {question.multiSelect === true && <span className={css.multiSelectHint}>可多选</span>} + </h2> + </div> + <div className={css.headerActions}> + <span className={css.progress}>{index + 1} / {questions.length}</span> + <button + type="button" className={css.iconButton} aria-label="上一题" + disabled={index === 0 || busy !== null} + onClick={() => { setIndex(index - 1); setError(null) }} + > + <IconChevronLeftOutline14 /> + </button> + <button + type="button" className={css.iconButton} aria-label="下一题" + disabled={index === questions.length - 1 || busy !== null} + onClick={() => { setIndex(index + 1); setError(null) }} + > + <IconChevronRightOutline14 /> + </button> + <button + type="button" className={css.iconButton} aria-label="放弃整组问题" + title="放弃整组问题" + disabled={busy !== null} onClick={cancelFlow} + > + <IconCloseOutline16 /> + </button> + </div> + </header> + + <div className={css.options} role={question.multiSelect === true ? 'group' : 'radiogroup'}> + {(question.options ?? []).map((option, optionIndex) => { + const selected = draft.selected.includes(option.label) + const display = parseRecommendedLabel(option.label) + return ( + <button + type="button" key={`${option.label}-${String(optionIndex)}`} + className={clsx(css.option, selected && css.optionSelected)} + role={question.multiSelect === true ? 'checkbox' : 'radio'} + aria-checked={selected} + aria-label={display.label} + disabled={busy !== null} + onClick={() => { choose(option.label) }} + onKeyDown={(event) => { + if (event.key !== 'Enter' || !drafts.every(completed)) return + event.preventDefault() + submitDrafts(drafts) + }} + > + <span className={css.number}>{optionIndex + 1}</span> + <span className={css.optionCopy}> + <span className={css.optionLine}> + <span className={css.optionLabel}>{display.label}</span> + {display.recommended && <span className={css.badge}>推荐</span>} + {option.description !== undefined && ( + <span className={css.description}>{option.description}</span> + )} + </span> + </span> + <span className={css.choiceIcon}> + {selected ? <IconCheckOutline16 /> : <IconChevronRightOutline14 />} + </span> + </button> + ) + })} + + <div className={clsx( + css.custom, + draft.customOpen && css.customOpen, + !hasOptions && css.customOptionless, + )}> + {hasOptions && ( + <button + type="button" className={css.customTrigger} + disabled={busy !== null} onClick={openCustom} + aria-expanded={draft.customOpen} + > + <span className={css.number}><IconEditOutline16 /></span> + <span>其他,请填写自定义答案</span> + </button> + )} + {draft.customOpen && ( + <textarea + autoFocus + className={css.customInput} + value={draft.custom} + disabled={busy !== null} + rows={2} + placeholder="输入你的答案" + onChange={(event) => { + const value = event.target.value + updateDraft(current => ({ + ...current, selected: [], custom: value, customOpen: true, skipped: false, + })) + }} + onKeyDown={(event) => { + if (event.key === 'Enter' && !event.shiftKey && !isComposing(event)) { + event.preventDefault() + continueFlow() + } + }} + /> + )} + </div> + </div> + + <footer className={css.footer}> + <div className={css.feedback} role="status">{error}</div> + <div className={css.footerActions}> + <Button variant="ghost" size="sm" disabled={busy !== null} onClick={skipQuestion}> + 跳过本题 + </Button> + <Button + variant="primary" size="sm" + disabled={busy !== null || !answered(draft)} onClick={continueFlow} + > + {busy === 'answer' + ? '正在提交…' + : index === questions.length - 1 ? '提交' : '下一题'} + </Button> + </div> + </footer> + </section> + </div> + ) +} diff --git a/packages/client/ui-question/src/client/index.ts b/packages/client/ui-question/src/client/index.ts new file mode 100644 index 0000000000..7f3214dd92 --- /dev/null +++ b/packages/client/ui-question/src/client/index.ts @@ -0,0 +1,47 @@ +/** + * Web question plugin, browser half: registers a composer replacement for + * pending ask_user_question requests. + */ +import type { Context } from 'cordis' +import type { SessionId, SessionsService } from '@deepseek-ai/dsh-client-runtime/client' +import { QuestionComposer, type QuestionComposerInjected } from './QuestionComposer.tsx' + +export { QuestionComposer, parseRecommendedLabel } from './QuestionComposer.tsx' +export type { QuestionComposerInjected, QuestionComposerProps } from './QuestionComposer.tsx' + +/** Required browser services. */ +export const inject = ['slots', 'sessions'] + +/** + * Register the question composer into the conversation-owned keyed slot. + * @param ctx - Browser plugin context carrying slots and sessions. + */ +export function apply(ctx: Context): void { + const slots = ctx.get('slots') + const sessions = ctx.get('sessions') as SessionsService | undefined + if (slots === undefined || sessions === undefined) { + throw new Error('ui-question: slots and sessions services are required') + } + slots.register<'conversation.composer', QuestionComposerInjected>('conversation.composer', QuestionComposer, { + key: 'question', + inject(binding): QuestionComposerInjected { + const session = sessions.manager.get(binding.sessionId as SessionId) + return { + actions: { + async answer(interaction, answer) { + const receipt = await session.answerQuestion(interaction.rpcId, answer) + if (!receipt.accepted) { + throw new Error(`question response rejected: ${receipt.reason}`) + } + }, + async cancel(interaction) { + const receipt = await session.cancelQuestion(interaction.rpcId) + if (!receipt.accepted) { + throw new Error(`question cancellation rejected: ${receipt.reason}`) + } + }, + }, + } + }, + }) +} diff --git a/packages/client/ui-question/src/css-modules.d.ts b/packages/client/ui-question/src/css-modules.d.ts new file mode 100644 index 0000000000..24a27bda3f --- /dev/null +++ b/packages/client/ui-question/src/css-modules.d.ts @@ -0,0 +1,4 @@ +declare module '*.module.css' { + const classes: Readonly<Record<string, string>> + export default classes +} diff --git a/packages/client/ui-question/src/index.ts b/packages/client/ui-question/src/index.ts new file mode 100644 index 0000000000..901e832c14 --- /dev/null +++ b/packages/client/ui-question/src/index.ts @@ -0,0 +1,17 @@ +/** + * Web question plugin, node half: enabling this UI feature also exposes the + * model-facing ask_user_question tool on the host composition. + */ +import type { Context } from 'cordis' +import * as toolAskUser from '@deepseek-ai/dsh-tool-ask-user' + +/** Host services required by the model-facing tool. */ +export const inject = ['tools', 'userInteraction'] + +/** + * Mount ask_user_question for hosts that selected the Web question plugin. + * @param ctx - Host plugin context carrying tools and userInteraction. + */ +export function apply(ctx: Context): void { + toolAskUser.apply(ctx) +} diff --git a/packages/client/ui-question/src/invariant.ts b/packages/client/ui-question/src/invariant.ts new file mode 100644 index 0000000000..6a6e7ebb90 --- /dev/null +++ b/packages/client/ui-question/src/invariant.ts @@ -0,0 +1,31 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-client-ui-question`. + * @module @deepseek-ai/dsh-client-ui-question/invariant + */ + +/* jscpd:ignore-start */ +import type { Context } from 'cordis' +import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants' + +const PACKAGE_NAME = '@deepseek-ai/dsh-client-ui-question' + +/** Cordis companion plugin name. */ +export const name = 'client-ui-question-invariant' +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants'] + +/** + * No runtime invariant: tool and slot registrations are effects + * owned and observed by their respective registries; the host pending table is + * exercised through the public wire protocol. + */ +const install: InvariantInstaller = () => {} + +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns The installed registration's disposer after setup succeeds. + */ +export const apply = (ctx: Context): Promise<() => void> => + Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)) +/* jscpd:ignore-end */ diff --git a/packages/client/ui-question/tests/browser-plugin.spec.ts b/packages/client/ui-question/tests/browser-plugin.spec.ts new file mode 100644 index 0000000000..572a1f5f44 --- /dev/null +++ b/packages/client/ui-question/tests/browser-plugin.spec.ts @@ -0,0 +1,58 @@ +import { Context } from 'cordis' +import { describe, expect, it, vi } from 'vitest' +import { RpcId } from '@deepseek-ai/dsh-client-connection/client' +import type { PendingInteraction, SessionId } from '@deepseek-ai/dsh-client-runtime/client' +import { SlotsService } from '@deepseek-ai/dsh-client-runtime/client' +import { apply, inject } from '../src/client/index.ts' + +type QuestionInteraction = Extract<PendingInteraction, { kind: 'question' }> + +function interaction(): QuestionInteraction { + return { + kind: 'question', rpcId: RpcId('question-1'), + questions: [{ id: 'mode', question: 'Choose?', options: [{ label: 'Fast' }] }], + } +} + +describe('ui-question browser plugin', () => { + it('declares its services and fails loud without them', () => { + expect(inject).toEqual(['slots', 'sessions']) + expect(() => { apply(new Context()) }).toThrow(/slots and sessions services are required/) + }) + + it('registers scoped answer and cancel actions, including rejected receipts', async () => { + const ctx = new Context() + await ctx.plugin(SlotsService).await() + const answerQuestion = vi.fn() + .mockResolvedValueOnce({ accepted: true }) + .mockResolvedValueOnce({ accepted: false, reason: 'not-pending' }) + const cancelQuestion = vi.fn() + .mockResolvedValueOnce({ accepted: true }) + .mockResolvedValueOnce({ accepted: false, reason: 'bad-response' }) + ctx.provide('sessions', { + manager: { get: vi.fn(() => ({ answerQuestion, cancelQuestion })) }, + }) + const slots = ctx.get('slots') as SlotsService + slots.define('conversation.composer', { kind: 'keyed', scope: 'session' }) + const fiber = ctx.plugin({ inject: [...inject], apply }) + await fiber.await() + + const entry = slots.entries('conversation.composer')[0] as unknown as { + options: { inject(binding: { sessionId: SessionId }): { actions: { + answer: (item: QuestionInteraction, answer: { answers: { id: string; selected: string[] }[] }) => Promise<void> + cancel: (item: QuestionInteraction) => Promise<void> + } } } + } + const actions = entry.options.inject({ sessionId: 'session-1' as SessionId }).actions + const item = interaction() + const answer = { answers: [{ id: 'mode', selected: ['Fast'] }] } + + await expect(actions.answer(item, answer)).resolves.toBeUndefined() + await expect(actions.answer(item, answer)).rejects.toThrow(/not-pending/) + await expect(actions.cancel(item)).resolves.toBeUndefined() + await expect(actions.cancel(item)).rejects.toThrow(/bad-response/) + expect(answerQuestion).toHaveBeenCalledWith(item.rpcId, answer) + expect(cancelQuestion).toHaveBeenCalledWith(item.rpcId) + await ctx.fiber.dispose() + }) +}) diff --git a/packages/client/ui-question/tests/node-plugin.spec.ts b/packages/client/ui-question/tests/node-plugin.spec.ts new file mode 100644 index 0000000000..9bc34e9599 --- /dev/null +++ b/packages/client/ui-question/tests/node-plugin.spec.ts @@ -0,0 +1,28 @@ +import { Context } from 'cordis' +import { afterEach, describe, expect, it } from 'vitest' +import ToolRegistry from '@deepseek-ai/dsh-tools' +import SystemPrompt from '@deepseek-ai/dsh-system-prompt' +import UserInteractionService from '@deepseek-ai/dsh-user-interaction' +import { apply, inject } from '../src/index.ts' + +let ctx: Context | undefined + +afterEach(async () => { + await ctx?.fiber.dispose() + ctx = undefined +}) + +describe('ui-question node plugin', () => { + it('exposes ask_user_question only for the selected Web feature lifecycle', async () => { + ctx = new Context() + await ctx.plugin(SystemPrompt) + await ctx.plugin(ToolRegistry) + await ctx.plugin(UserInteractionService) + const feature = ctx.plugin({ inject: [...inject], apply }) + await feature.await() + expect(ctx.tools.get('ask_user_question')).toBeDefined() + + await feature.dispose() + expect(ctx.tools.get('ask_user_question')).toBeUndefined() + }) +}) diff --git a/packages/client/ui-question/tests/question-composer.spec.tsx b/packages/client/ui-question/tests/question-composer.spec.tsx new file mode 100644 index 0000000000..feb6be1d0f --- /dev/null +++ b/packages/client/ui-question/tests/question-composer.spec.tsx @@ -0,0 +1,198 @@ +// @vitest-environment jsdom +import { afterEach, describe, expect, it, vi } from 'vitest' +import { cleanup, fireEvent, render, screen } from '@testing-library/react' +import type { PendingInteraction } from '@deepseek-ai/dsh-client-runtime/client' +import { RpcId } from '@deepseek-ai/dsh-client-connection/client' +import { + QuestionComposer, parseQuestionTitle, parseRecommendedLabel, +} from '../src/client/QuestionComposer.tsx' + +afterEach(cleanup) + +type Interaction = Extract<PendingInteraction, { kind: 'question' }> + +function interaction(rpcId = 'question-1'): Interaction { + return { + kind: 'question', + rpcId: RpcId(rpcId), + questions: [ + { + id: 'profile', header: '偏好', question: '选择候选人类型', + options: [ + { label: '工程落地型 (Recommended)', description: '优先工程交付。' }, + { label: '研究潜力型', description: '优先研究能力。' }, + ], + }, + { + id: 'detail', question: '补充你的要求', + }, + { + id: 'signals', question: '选择重要信号(可多选)', multiSelect: true, + options: [{ label: '系统设计' }, { label: '代码质量' }, { label: '产品判断' }], + }, + ], + } +} + +describe('QuestionComposer', () => { + it('collects single, custom, and multi-select answers before one batch submit', () => { + const answer = vi.fn(() => Promise.resolve()) + const cancel = vi.fn(() => Promise.resolve()) + render(<QuestionComposer interaction={interaction()} actions={{ answer, cancel }} />) + + expect(screen.getByText('1 / 3')).toBeTruthy() + expect(screen.getByText('推荐')).toBeTruthy() + expect(screen.getByText('工程落地型')).toBeTruthy() + fireEvent.keyDown(screen.getByRole('radio', { name: /工程落地型/ }), { key: 'Enter' }) + expect(answer).not.toHaveBeenCalled() + fireEvent.click(screen.getByRole('radio', { name: /工程落地型/ })) + + expect(screen.getByText('2 / 3')).toBeTruthy() + expect(screen.queryByRole('button', { name: '填写答案' })).toBeNull() + const custom = screen.getByPlaceholderText('输入你的答案') + fireEvent.change(custom, { target: { value: '要能独立排查线上问题' } }) + fireEvent.keyDown(custom, { key: 'Enter' }) + + expect(screen.getByText('3 / 3')).toBeTruthy() + expect(screen.getByText('选择重要信号')).toBeTruthy() + expect(screen.getByText('可多选')).toBeTruthy() + expect(screen.queryByText('(可多选)')).toBeNull() + fireEvent.click(screen.getByRole('checkbox', { name: '系统设计' })) + fireEvent.click(screen.getByRole('checkbox', { name: '系统设计' })) + fireEvent.click(screen.getByRole('checkbox', { name: '系统设计' })) + fireEvent.click(screen.getByRole('checkbox', { name: '代码质量' })) + fireEvent.keyDown(screen.getByRole('checkbox', { name: '代码质量' }), { key: 'Enter' }) + + expect(answer).toHaveBeenCalledWith(interaction(), { + answers: [ + { id: 'profile', selected: ['工程落地型 (Recommended)'] }, + { id: 'detail', selected: [], custom: '要能独立排查线上问题' }, + { id: 'signals', selected: ['系统设计', '代码质量'] }, + ], + }) + expect((screen.getByRole('button', { name: '正在提交…' }) as HTMLButtonElement).disabled).toBe(true) + }) + + it('skips individual questions without discarding earlier answers', () => { + const answer = vi.fn(() => Promise.resolve()) + const cancel = vi.fn(() => Promise.resolve()) + render(<QuestionComposer interaction={interaction()} actions={{ answer, cancel }} />) + + expect((screen.getByText('下一题').closest('button') as HTMLButtonElement).disabled).toBe(true) + fireEvent.click(screen.getByRole('radio', { name: '研究潜力型' })) + expect(screen.getByText('2 / 3')).toBeTruthy() + fireEvent.click(screen.getByRole('button', { name: '跳过本题' })) + expect(screen.getByText('3 / 3')).toBeTruthy() + fireEvent.click(screen.getByRole('button', { name: '跳过本题' })) + + expect(cancel).not.toHaveBeenCalled() + expect(answer).toHaveBeenCalledWith(interaction(), { + answers: [ + { id: 'profile', selected: ['研究潜力型'] }, + { id: 'detail', selected: [] }, + { id: 'signals', selected: [] }, + ], + }) + }) + + it('keeps IME Enter inside the custom input until composition finishes', () => { + const answer = vi.fn(() => Promise.resolve()) + const cancel = vi.fn(() => Promise.resolve()) + render(<QuestionComposer interaction={interaction()} actions={{ answer, cancel }} />) + + fireEvent.click(screen.getByRole('radio', { name: '研究潜力型' })) + const custom = screen.getByPlaceholderText('输入你的答案') + fireEvent.change(custom, { target: { value: '中文输入' } }) + + fireEvent.keyDown(custom, { key: 'Enter', isComposing: true }) + expect(screen.getByText('2 / 3')).toBeTruthy() + expect(answer).not.toHaveBeenCalled() + + fireEvent.keyDown(custom, { key: 'Enter', keyCode: 229 }) + expect(screen.getByText('2 / 3')).toBeTruthy() + expect(answer).not.toHaveBeenCalled() + + fireEvent.keyDown(custom, { key: 'Enter' }) + expect(screen.getByText('3 / 3')).toBeTruthy() + }) + + it('opens custom input, reports missing skipped answers, and supports header navigation', () => { + const answer = vi.fn(() => Promise.resolve()) + const cancel = vi.fn(() => Promise.resolve()) + render(<QuestionComposer interaction={interaction()} actions={{ answer, cancel }} />) + + fireEvent.click(screen.getByRole('button', { name: '其他,请填写自定义答案' })) + expect(screen.getByPlaceholderText('输入你的答案')).toBeTruthy() + fireEvent.click(screen.getByRole('radio', { name: '工程落地型' })) + const emptyCustom = screen.getByPlaceholderText('输入你的答案') + fireEvent.keyDown(emptyCustom, { key: 'Enter', shiftKey: true }) + expect(screen.getByText('2 / 3')).toBeTruthy() + fireEvent.keyDown(emptyCustom, { key: 'Enter' }) + expect(screen.getByText('请选择一个选项或填写自定义答案。')).toBeTruthy() + + fireEvent.click(screen.getByLabelText('下一题')) + fireEvent.click(screen.getByRole('checkbox', { name: '产品判断' })) + fireEvent.click(screen.getByRole('button', { name: '提交' })) + expect(screen.getByText('请先完成这道问题。')).toBeTruthy() + expect(screen.getByText('2 / 3')).toBeTruthy() + fireEvent.click(screen.getByLabelText('上一题')) + expect(screen.getByText('1 / 3')).toBeTruthy() + expect(answer).not.toHaveBeenCalled() + }) + + it('surfaces explicit cancellation rejection', async () => { + const answer = vi.fn(() => Promise.resolve()) + const cancel = vi.fn(() => Promise.reject('取消请求失败')) + render(<QuestionComposer interaction={interaction()} actions={{ answer, cancel }} />) + + fireEvent.click(screen.getByRole('button', { name: '放弃整组问题' })) + expect(await screen.findByText('取消请求失败')).toBeTruthy() + expect((screen.getByRole('button', { name: '跳过本题' }) as HTMLButtonElement).disabled).toBe(false) + + cancel.mockRejectedValueOnce(new Error('第二次取消失败')) + fireEvent.click(screen.getByRole('button', { name: '放弃整组问题' })) + expect(await screen.findByText('第二次取消失败')).toBeTruthy() + }) + + it('surfaces transport rejection and resets local drafts for a different rpcId', async () => { + const answer = vi.fn(() => Promise.reject(new Error('网络中断'))) + const cancel = vi.fn(() => Promise.resolve()) + const first = interaction('first') + const view = render(<QuestionComposer interaction={first} actions={{ answer, cancel }} />) + + fireEvent.click(screen.getByRole('radio', { name: /研究潜力型/ })) + expect(screen.getByText('2 / 3')).toBeTruthy() + view.rerender(<QuestionComposer interaction={interaction('second')} actions={{ answer, cancel }} />) + expect(screen.getByRole('radio', { name: /研究潜力型/ }).getAttribute('aria-checked')).toBe('false') + + fireEvent.click(screen.getByRole('radio', { name: /工程落地型/ })) + const custom = screen.getByPlaceholderText('输入你的答案') + fireEvent.change(custom, { target: { value: 'x' } }) + fireEvent.keyDown(custom, { key: 'Enter' }) + fireEvent.click(screen.getByRole('checkbox', { name: '系统设计' })) + fireEvent.click(screen.getByRole('button', { name: '提交' })) + expect(await screen.findByText('网络中断')).toBeTruthy() + expect((screen.getByRole('button', { name: '提交' }) as HTMLButtonElement).disabled).toBe(false) + + answer.mockRejectedValueOnce('字符串错误') + fireEvent.click(screen.getByRole('button', { name: '提交' })) + expect(await screen.findByText('字符串错误')).toBeTruthy() + }) +}) + +describe('parseRecommendedLabel', () => { + it('recognizes English and Chinese suffixes without changing ordinary labels', () => { + expect(parseRecommendedLabel('Fast (Recommended)')).toEqual({ label: 'Fast', recommended: true }) + expect(parseRecommendedLabel('稳妥(推荐)')).toEqual({ label: '稳妥', recommended: true }) + expect(parseRecommendedLabel('稳妥 (推荐)')).toEqual({ label: '稳妥', recommended: true }) + expect(parseRecommendedLabel('Plain')).toEqual({ label: 'Plain', recommended: false }) + }) +}) + +describe('parseQuestionTitle', () => { + it('removes Chinese and ASCII multi-select suffixes', () => { + expect(parseQuestionTitle('选择信号(可多选)')).toBe('选择信号') + expect(parseQuestionTitle('选择信号 (可多选)')).toBe('选择信号') + expect(parseQuestionTitle('选择信号')).toBe('选择信号') + }) +}) diff --git a/packages/client/ui-question/tsconfig.json b/packages/client/ui-question/tsconfig.json new file mode 100644 index 0000000000..87bbb331b5 --- /dev/null +++ b/packages/client/ui-question/tsconfig.json @@ -0,0 +1,43 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib/types", + "jsx": "react-jsx", + "lib": [ + "ES2024", + "DOM", + "DOM.Iterable" + ], + "types": [] + }, + "include": [ + "src" + ], + "references": [ + { + "path": "../../../vendor/cordis" + }, + { + "path": "../runtime" + }, + { + "path": "../ui-conversation" + }, + { + "path": "../ui-primitives" + }, + { + "path": "../ui-slots" + }, + { + "path": "../web-react" + }, + { + "path": "../../ui/tool-ask-user" + }, + { + "path": "../../support/invariants" + } + ] +} diff --git a/packages/client/ui-question/tsdown.config.ts b/packages/client/ui-question/tsdown.config.ts new file mode 100644 index 0000000000..0af4afb3ed --- /dev/null +++ b/packages/client/ui-question/tsdown.config.ts @@ -0,0 +1,3 @@ +import { clientBundle } from '../tsdown.client.ts' + +export default clientBundle('@deepseek-ai/dsh-client-ui-question', ['lib/types/index.js', 'lib/types/invariant.js']) diff --git a/packages/client/ui-trajectory/tests/views.spec.tsx b/packages/client/ui-trajectory/tests/views.spec.tsx index 41a3c0c95b..2f7ec79844 100644 --- a/packages/client/ui-trajectory/tests/views.spec.tsx +++ b/packages/client/ui-trajectory/tests/views.spec.tsx @@ -14,13 +14,16 @@ import { bindSnapshotSelector, createSnapshotStore } from '@deepseek-ai/dsh-clie import type { UseSession } from '@deepseek-ai/dsh-client-web-react' import type { ConversationSnapshot, SessionId, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' import { ConversationRoot, ConversationService } from '@deepseek-ai/dsh-client-ui-conversation/client' -import type { ConvViewProps, ViewEntry, ViewId } from '@deepseek-ai/dsh-client-ui-conversation/client' +import type { ConversationInjected, ConvViewProps, ViewEntry, ViewId } from '@deepseek-ai/dsh-client-ui-conversation/client' import { apply, deriveSpans, deriveSpanStats, inject, TrajectoryStatsHeader, TrajectoryView, WaterfallView, } from '@deepseek-ai/dsh-client-ui-trajectory/client' import { apply as nodeApply } from '@deepseek-ai/dsh-client-ui-trajectory' const SID = 's1' as SessionId +const fallbackSlots: ConversationInjected['slots'] = { + renderSlot: (_key, _props, opts) => opts?.fallback ?? null, +} afterEach(cleanup) @@ -70,8 +73,14 @@ function mount(svc: ConversationService, nodes: ConversationSnapshot['nodes'] = } return createElement(Fragment, null, children) } - const sessionSnapshot = createSnapshotStore<{ running: boolean; removed: boolean; promptError: null; nodes: ConversationSnapshot['nodes'] }>({ - running: false, removed: false, promptError: null, nodes, + const sessionSnapshot = createSnapshotStore<{ + running: boolean + removed: boolean + promptError: null + nodes: ConversationSnapshot['nodes'] + pending: ConversationSnapshot['pending'] + }>({ + running: false, removed: false, promptError: null, nodes, pending: [], }) return render( <ConversationRoot @@ -87,6 +96,7 @@ function mount(svc: ConversationService, nodes: ConversationSnapshot['nodes'] = composer={{ useDraft: () => '', setDraft: vi.fn(), send: vi.fn(), stop: vi.fn() }} actions={{ openView: ((v: string) => { activeStore.set(v) }) as (v: never) => void, open: vi.fn() }} renderView={renderView} + slots={fallbackSlots} />, ) } diff --git a/packages/host/apiproxy/src/api/rpc.schema.ts b/packages/host/apiproxy/src/api/rpc.schema.ts index d993e763b7..20ef251cd6 100644 --- a/packages/host/apiproxy/src/api/rpc.schema.ts +++ b/packages/host/apiproxy/src/api/rpc.schema.ts @@ -33,6 +33,7 @@ export const rpcIdSchema = z.string() as unknown as z.ZodType<RpcId> /** Error body: discriminated by code, per-branch details aligned to RpcErrorDetailsMap; details is required. */ export const rpcErrorSchema: z.ZodType<RpcError> = z.discriminatedUnion('code', [ z.object({ code: z.literal('bad-request'), message: z.string(), details: z.object({ issues: z.array(z.custom<ZodIssue>()) }) }), + z.object({ code: z.literal('cancelled'), message: z.string(), details: z.object({}) }), z.object({ code: z.literal('session-not-found'), message: z.string(), details: z.object({ sessionId: z.string() }) }), z.object({ code: z.literal('agent-busy'), message: z.string(), details: z.object({ reason: z.string() }) }), z.object({ code: z.literal('internal'), message: z.string(), details: z.object({}) }), diff --git a/packages/host/apiproxy/src/api/rpc.ts b/packages/host/apiproxy/src/api/rpc.ts index 46f737817c..4503d1fb6d 100644 --- a/packages/host/apiproxy/src/api/rpc.ts +++ b/packages/host/apiproxy/src/api/rpc.ts @@ -30,6 +30,7 @@ export function RpcId(id: string): RpcId { /** Error code → details type map (a second table isomorphic to RpcMethodMap). New code = one row here + one branch in the error schema. */ export interface RpcErrorDetailsMap { 'bad-request': { issues: ZodIssue[] } + 'cancelled': {} 'session-not-found': { sessionId: SessionId } 'agent-busy': { reason: string } 'internal': {} diff --git a/packages/host/apiproxy/tests/rpc-schemas.spec.ts b/packages/host/apiproxy/tests/rpc-schemas.spec.ts index 764c9673b9..4d2325a789 100644 --- a/packages/host/apiproxy/tests/rpc-schemas.spec.ts +++ b/packages/host/apiproxy/tests/rpc-schemas.spec.ts @@ -29,6 +29,7 @@ describe('RpcId', () => { describe('rpcErrorSchema', () => { it('accepts every code branch with its required details', () => { expect(rpcErrorSchema.parse({ code: 'bad-request', message: 'm', details: { issues: [] } }).code).toBe('bad-request') + expect(rpcErrorSchema.parse({ code: 'cancelled', message: 'm', details: {} }).code).toBe('cancelled') expect(rpcErrorSchema.parse({ code: 'session-not-found', message: 'm', details: { sessionId: 's' } }).code).toBe('session-not-found') expect(rpcErrorSchema.parse({ code: 'agent-busy', message: 'm', details: { reason: 'r' } }).code).toBe('agent-busy') expect(rpcErrorSchema.parse({ code: 'internal', message: 'm', details: {} }).code).toBe('internal') diff --git a/packages/host/runtime/README.md b/packages/host/runtime/README.md index 39f9888180..d63ab029a7 100644 --- a/packages/host/runtime/README.md +++ b/packages/host/runtime/README.md @@ -1,6 +1,6 @@ # @deepseek-ai/dsh-host-runtime -Host runtime assembly for `dsc`: `bootHost` composes the core plugin spine (LLM service + DeepSeek adapter, sessions with JSONL persistence, system prompt, tools, agents, agent loop, local bash), `createApiProxy` implements the [`dsh-host-apiproxy`](../apiproxy/README.md) contract over that composition, and `startHost` is the one-step shell seam returning `{ api, handler, defaults, ctx, dispose }`. +Host runtime assembly for `dsh`: `bootHost` composes the core plugin spine (LLM service + DeepSeek adapter, sessions with JSONL persistence, system prompt, tools, agents, agent loop, local bash, and the provider-neutral user-interaction service), `createApiProxy` implements the [`dsh-host-apiproxy`](../apiproxy/README.md) contract over that composition, and `startHost` is the one-step shell seam returning `{ api, handler, defaults, ctx, dispose }`. Which plugins mount and with what defaults is decided only here — shells must not `ctx.plugin` to alter the assembly. `RunningHost.ctx` is a formal seam with exactly two sanctioned uses: mounting protocol front-door plugins (e.g. a future `dsh acp`) and headless session-event subscription; consuming clients must not bypass `api` through it. @@ -14,7 +14,7 @@ Which plugins mount and with what defaults is decided only here — shells must ## ApiProxy implementation notes -Unary methods take the narrow `RpcRequest<P>` and echo `request.rpcId`; a prompt's rpcId rides `MessageSource` into the `user/message` event so clients can promote optimistic echoes. `history`/`prompt` on a cold session implicitly resume it, deduplicating concurrent calls through an in-flight table; `history` paginates backwards on message boundaries (never mid-message). The mux stream replays a `session/subscribed` baseline per attached session on open; the host stream carries session lifecycle, running flips, and `agent/error` as the only outlet for live failures with no turn position. +Unary methods take the narrow `RpcRequest<P>` and echo `request.rpcId`; a prompt's rpcId rides `MessageSource` into the `user/message` event so clients can promote optimistic echoes. `history`/`prompt` on a cold session implicitly resume it, deduplicating concurrent calls through an in-flight table; `history` paginates backwards on message boundaries (never mid-message). The mux stream replays a `session/subscribed` baseline per attached session and every still-pending question with its original rpcId. Question responses, including blank per-item answers, are validated against the owning session and exact request before an atomic first-wins claim; answer, whole-request cancellation, owner abort, and provider disposal broadcast `question/resolved`. The host stream carries session lifecycle, running flips, and `agent/error` as the only outlet for live failures with no turn position. ## Model Experience @@ -26,6 +26,6 @@ No direct invalidation; the mounted model-facing plugins own their request-prefi ## Known Limitations and Deferred Work -- **`respond` is a stub** — it always returns `not-pending`; the approval/question pending registry (stable-rpcId mint on accept, baseline replay on stream reopen, wire answerer) is the next host-side step. -- **`session.list` covers live sessions only** — cold sessions in the persistence directory are not yet merged into the listing; `host.describe.version` is a placeholder rather than the `apps/cli` package version. +- **Question waits are process-memory state** — browser reconnects recover them, but a host process restart aborts the owning tool call instead of restoring the wait from persistence. +- **`host.describe.version` is a placeholder** — it does not yet read the `apps/cli` package version. - **The assembly is fixed** — per-deployment plugin selection (user profile, log sinks, alternative persistence) has a documented home here but no configuration surface yet. diff --git a/packages/host/runtime/package.json b/packages/host/runtime/package.json index ea32040012..59710ee8e7 100644 --- a/packages/host/runtime/package.json +++ b/packages/host/runtime/package.json @@ -36,6 +36,7 @@ "@deepseek-ai/dsh-client-i18n": "workspace:^", "@deepseek-ai/dsh-client-runtime": "workspace:^", "@deepseek-ai/dsh-client-ui-conversation": "workspace:^", + "@deepseek-ai/dsh-client-ui-question": "workspace:^", "@deepseek-ai/dsh-client-ui-layout": "workspace:^", "@deepseek-ai/dsh-client-ui-sidebar": "workspace:^", "@deepseek-ai/dsh-client-ui-theme": "workspace:^", @@ -69,6 +70,7 @@ "@deepseek-ai/dsh-tool-todo": "workspace:^", "@deepseek-ai/dsh-tool-workflow": "workspace:^", "@deepseek-ai/dsh-tools": "workspace:^", + "@deepseek-ai/dsh-user-interaction": "workspace:^", "@deepseek-ai/dsh-workflow-workerthread": "workspace:^" }, "peerDependencies": { diff --git a/packages/host/runtime/src/api-proxy.ts b/packages/host/runtime/src/api-proxy.ts index 0621fbecb9..576a37e5df 100644 --- a/packages/host/runtime/src/api-proxy.ts +++ b/packages/host/runtime/src/api-proxy.ts @@ -1,8 +1,6 @@ /** - * Host-side ApiProxy implementation (minimal-first — - * describe/list/create/history/prompt/cancel and both streams are real, - * respond is a stub). Signature discipline: unary takes the narrow - * RpcRequest<P> and echoes request.rpcId on the RpcResponse<T>. + * Host-side ApiProxy implementation. Signature discipline: unary takes the + * narrow RpcRequest<P> and echoes request.rpcId on the RpcResponse<T>. */ import { randomUUID } from 'node:crypto' @@ -12,9 +10,16 @@ import type { Agent, AgentStatus } from '@deepseek-ai/dsh-agent' import type { ContentBlock, MessageSource } from '@deepseek-ai/dsh-llm' import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session' import type { SessionPersistence } from '@deepseek-ai/dsh-session-persistence' -import type { ApiProxy, HistoryEntry, HostFrame, MuxFrame, SessionSummary, ToolEventView } from '@deepseek-ai/dsh-host-apiproxy/api' +import type { + ApiProxy, HistoryEntry, HostFrame, MuxFrame, QuestionResponsePayload, SessionSummary, ToolEventView, +} from '@deepseek-ai/dsh-host-apiproxy/api' +import { questionResponsePayloadSchema } from '@deepseek-ai/dsh-host-apiproxy/api/questions.schema' import type { ClientResponse, RpcError, RpcReceipt, RpcRequest, RpcResponse } from '@deepseek-ai/dsh-host-apiproxy/api/rpc' import { RpcId } from '@deepseek-ai/dsh-host-apiproxy/api/rpc' +import type { + AskUserQuestionAnswer, AskUserQuestionItem, AskUserQuestionRequest, +} from '@deepseek-ai/dsh-user-interaction' +import { UserInteractionError } from '@deepseek-ai/dsh-user-interaction' /** Page size when history is called without maxMessages. */ const DEFAULT_MAX_MESSAGES = 50 @@ -155,6 +160,35 @@ interface ToolCallData { callId: string; name: string; arguments: string } /** The tool/result payload fields the presenter path reads. */ interface ToolResultData { callId: string; content: ContentBlock[]; isError: boolean; meta?: unknown } +/** One host-owned question wait, addressed by the stable server-request id. */ +interface PendingQuestion { + rpcId: RpcId + sessionId: SessionId + questions: AskUserQuestionItem[] + resolve: (answer: AskUserQuestionAnswer) => void + reject: (error: UserInteractionError) => void + signal?: AbortSignal + onAbort?: () => void +} + +/** Validate one answer batch against the exact question request it resolves. */ +function matchesQuestions(payload: QuestionResponsePayload, pending: PendingQuestion): boolean { + if (payload.sessionId !== pending.sessionId) return false + const answers = payload.answer.answers + if (answers.length !== pending.questions.length) return false + return answers.every((answer, index) => { + const question = pending.questions[index] as AskUserQuestionItem + if (answer.id !== question.id) return false + if (new Set(answer.selected).size !== answer.selected.length) return false + const custom = answer.custom?.trim() + if (custom !== undefined && custom === '') return false + if (custom !== undefined && answer.selected.length > 0) return false + if (question.multiSelect !== true && answer.selected.length > 1) return false + const labels = new Set(question.options?.map(option => option.label) ?? []) + return answer.selected.every(label => labels.has(label)) + }) +} + /** * Compute the render intent for a tool/call or tool/result event through the * presenters registered at this moment; every other event type gets none. A @@ -219,12 +253,70 @@ class SessionNotFound extends Error {} * @param ctx - the root context returned by bootHost (sessions/agents services mounted). * @param defaults - host-level default provider/model: injected as * agentOptions on create/resume, reported by describe from the same source. - * @returns the ApiProxy implementation (minimal-first; stubs noted per method). + * @returns the ApiProxy implementation. */ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiProxy { const agentOptions = { provider: defaults.provider, model: defaults.model } /** Implicit resume of cold sessions, deduplicating concurrent calls (follows the jsonrpc sessionCreations precedent). */ const resumes = new Map<SessionId, Promise<Agent>>() + const pendingQuestions = new Map<RpcId, PendingQuestion>() + const muxQueues = new Set<FrameQueue<RpcRequest<MuxFrame>>>() + + /** Send one transient frame to every connected mux consumer. */ + function broadcast(payload: MuxFrame): void { + const envelope = frame(payload) + for (const queue of muxQueues) queue.push(envelope) + } + + /** Remove a wait before settling it: synchronous deletion makes the first claimant win. */ + function claimQuestion(pending: PendingQuestion, outcome: 'answered' | 'cancelled'): void { + pendingQuestions.delete(pending.rpcId) + if (pending.signal !== undefined && pending.onAbort !== undefined) { + pending.signal.removeEventListener('abort', pending.onAbort) + } + broadcast({ + type: 'question/resolved', sessionId: pending.sessionId, + questionRpcId: pending.rpcId, outcome, + }) + } + + const disposeProvider = ctx.userInteraction.registerProvider({ + ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer> { + const sessionId = request.agent?.id + if (sessionId === undefined) { + return Promise.reject(new UserInteractionError( + 'web user interaction requires an agent-owned session', 'ASK_MISSING_AGENT')) + } + return new Promise<AskUserQuestionAnswer>((resolve, reject) => { + const rpcId = RpcId(randomUUID()) + const pending: PendingQuestion = { + rpcId, sessionId, questions: request.questions, resolve, reject, + ...(request.signal === undefined ? {} : { signal: request.signal }), + } + const onAbort = (): void => { + claimQuestion(pending, 'cancelled') + reject(new UserInteractionError( + 'ask_user_question was aborted before the user answered', 'ASK_ABORTED')) + } + pending.onAbort = onAbort + pendingQuestions.set(rpcId, pending) + request.signal?.addEventListener('abort', onAbort, { once: true }) + const envelope: RpcRequest<MuxFrame> = { + rpcId, + payload: { type: 'question/requested', sessionId, questions: request.questions }, + } + for (const queue of muxQueues) queue.push(envelope) + }) + }, + }) + ctx.effect(() => () => { + disposeProvider() + for (const pending of [...pendingQuestions.values()]) { + claimQuestion(pending, 'cancelled') + pending.reject(new UserInteractionError( + 'web user-interaction provider was disposed', 'ASK_ABORTED')) + } + }, 'api-proxy: user-interaction provider') /** * Gate the cold path on the store: an id absent from it, or naming a legacy @@ -361,9 +453,19 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro events: { mux(_request, signal) { const queue = new FrameQueue<RpcRequest<MuxFrame>>() + muxQueues.add(queue) for (const session of ctx.sessions.list()) { queue.push(frame({ type: 'session/subscribed', sessionId: session.id, lastSeq: session.seq - 1 })) } + for (const pending of pendingQuestions.values()) { + queue.push({ + rpcId: pending.rpcId, + payload: { + type: 'question/requested', sessionId: pending.sessionId, + questions: pending.questions, + }, + }) + } // Per-session open-call table for result-view pairing. Bounded by the // per-turn call count: entries clear on turn/end; a table miss (stream // opened mid-turn) backscans the session's in-memory events instead. @@ -393,7 +495,10 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro openCalls.delete(session.id) }), ] - return queue.iterate(signal, () => { for (const dispose of disposers) dispose() }) + return queue.iterate(signal, () => { + muxQueues.delete(queue) + for (const dispose of disposers) dispose() + }) }, host(_request, signal) { @@ -421,9 +526,38 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro }, }, - // TODO(step2): approval/question pending registry (wire answerer + proxy provider). - respond(_message: ClientResponse): Promise<RpcReceipt> { - return Promise.resolve({ accepted: false, reason: 'not-pending' }) + respond(message: ClientResponse): Promise<RpcReceipt> { + const pending = pendingQuestions.get(message.rpcId) + if (pending === undefined) return Promise.resolve({ accepted: false, reason: 'not-pending' }) + if (!message.result.ok) { + if (message.result.error.code !== 'cancelled') { + return Promise.resolve({ accepted: false, reason: 'bad-response' }) + } + claimQuestion(pending, 'cancelled') + pending.reject(new UserInteractionError( + 'the user cancelled ask_user_question', 'ASK_CANCELLED')) + return Promise.resolve({ accepted: true }) + } + const parsed = questionResponsePayloadSchema.safeParse(message.result.value) + if (!parsed.success) { + return Promise.resolve({ accepted: false, reason: 'bad-response' }) + } + const payload: QuestionResponsePayload = { + sessionId: parsed.data.sessionId, + answer: { + answers: parsed.data.answer.answers.map(answer => ({ + id: answer.id, + selected: answer.selected, + ...(answer.custom === undefined ? {} : { custom: answer.custom }), + })), + }, + } + if (!matchesQuestions(payload, pending)) { + return Promise.resolve({ accepted: false, reason: 'bad-response' }) + } + claimQuestion(pending, 'answered') + pending.resolve(payload.answer) + return Promise.resolve({ accepted: true }) }, } } diff --git a/packages/host/runtime/src/boot.ts b/packages/host/runtime/src/boot.ts index ca40b9f8b3..f89b8afafe 100644 --- a/packages/host/runtime/src/boot.ts +++ b/packages/host/runtime/src/boot.ts @@ -37,6 +37,7 @@ import * as toolWorkflow from '@deepseek-ai/dsh-tool-workflow' import * as timeoutPolicy from '@deepseek-ai/dsh-timeout-policy' import SpillLocal from '@deepseek-ai/dsh-spill-local' import * as spillPolicy from '@deepseek-ai/dsh-spill-policy' +import UserInteractionService from '@deepseek-ai/dsh-user-interaction' /** Options for bootHost — the assembly-layer composition knobs. */ export interface BootHostOptions { @@ -91,6 +92,7 @@ export async function bootHost(options: BootHostOptions): Promise<HostHandle> { await ctx.plugin(SessionStore) await ctx.plugin(SystemPrompt, { persona: '' }) await ctx.plugin(ToolRegistry) + await ctx.plugin(UserInteractionService) await ctx.plugin(AgentRegistry) await ctx.plugin(TaskService) await ctx.plugin(AgentLoop, { agents: [] }) diff --git a/packages/host/runtime/src/web-plugins.ts b/packages/host/runtime/src/web-plugins.ts index 26ce5b3396..0967be8c3e 100644 --- a/packages/host/runtime/src/web-plugins.ts +++ b/packages/host/runtime/src/web-plugins.ts @@ -1,16 +1,16 @@ /** * Web UI plugin assembly: mounts @cordisjs/plugin-loader with an in-memory - * entry tree listing the eight UI plugin packages (the P-I config-source bar — + * entry tree listing the nine UI plugin packages (the P-I config-source bar — * a cordis.yml file form comes later; install/remove currently means editing * this list and restarting). The web plugin registry discovers the entries by - * their package.json dshClient declarations; node halves are empty applies, - * so mounting them here costs nothing beyond Loader governance. + * their package.json dshClient declarations; feature packages may also mount + * their interface-specific host half through the same lifecycle. */ import { createRequire } from 'node:module' import type { Context } from 'cordis' import Loader from '@cordisjs/plugin-loader' -/** The eight UI plugin packages served to the browser (order = manifest order). */ +/** The nine UI plugin packages served to the browser (order = manifest order). */ export const WEB_UI_PLUGINS = [ '@deepseek-ai/dsh-client-connection', '@deepseek-ai/dsh-client-runtime', @@ -19,6 +19,7 @@ export const WEB_UI_PLUGINS = [ '@deepseek-ai/dsh-client-ui-layout', '@deepseek-ai/dsh-client-ui-sidebar', '@deepseek-ai/dsh-client-ui-conversation', + '@deepseek-ai/dsh-client-ui-question', '@deepseek-ai/dsh-client-ui-trajectory', ] as const @@ -41,7 +42,7 @@ export interface MountedWebPlugins { export async function mountWebPlugins(ctx: Context): Promise<MountedWebPlugins> { // The Loader resolves bare specifiers against ctx.baseUrl; without one the // import silently fails and every entry stays fiber-less. This package - // depends on all eight UI plugins, so its own URL is the right anchor. + // depends on all nine UI plugins, so its own URL is the right anchor. ctx.baseUrl ??= import.meta.url if (ctx.get('loader') === undefined) await ctx.plugin(Loader) const existing = new Set([...ctx.loader.entries()].map(entry => entry.options.name)) diff --git a/packages/host/runtime/tests/api-proxy-cold.spec.ts b/packages/host/runtime/tests/api-proxy-cold.spec.ts index 01f1da7d17..3d4ba8e15a 100644 --- a/packages/host/runtime/tests/api-proxy-cold.spec.ts +++ b/packages/host/runtime/tests/api-proxy-cold.spec.ts @@ -12,6 +12,7 @@ import { describe, expect, it } from 'vitest' import { Context } from 'cordis' import SessionStore from '@deepseek-ai/dsh-session' import AgentRegistry from '@deepseek-ai/dsh-agent' +import UserInteractionService from '@deepseek-ai/dsh-user-interaction' import type { SessionHeader, SessionId } from '@deepseek-ai/dsh-session' import type { RpcRequest } from '@deepseek-ai/dsh-host-apiproxy/api/rpc' import { RpcId } from '@deepseek-ai/dsh-host-apiproxy/api/rpc' @@ -32,6 +33,7 @@ describe('sessions.list cold merge', () => { it('summarizes unattached sessions: log mtime, locate-less and vanished-log createdAt fallbacks, lineage', async () => { const ctx = new Context() await ctx.plugin(SessionStore) + await ctx.plugin(UserInteractionService) const root = mkdtempSync(join(tmpdir(), 'dsh-cold-')) const logPath = join(root, 'a.log') writeFileSync(logPath, 'log-bytes') @@ -76,6 +78,7 @@ describe('degenerate composition (no persistence, no factory)', () => { const ctx = new Context() await ctx.plugin(SessionStore) await ctx.plugin(AgentRegistry) + await ctx.plugin(UserInteractionService) const api = createApiProxy(ctx, { provider: 'p', model: 'm', cwd: '/tmp' }) const listed = await api.sessions.list(request({})) diff --git a/packages/host/runtime/tests/api-proxy-view.spec.ts b/packages/host/runtime/tests/api-proxy-view.spec.ts index d000742262..e1bd751c72 100644 --- a/packages/host/runtime/tests/api-proxy-view.spec.ts +++ b/packages/host/runtime/tests/api-proxy-view.spec.ts @@ -17,6 +17,7 @@ import type { ContentBlock } from '@deepseek-ai/dsh-llm' import { CallId } from '@deepseek-ai/dsh-llm' import type { Session, SessionId } from '@deepseek-ai/dsh-session' import type { ToolDefinition } from '@deepseek-ai/dsh-tools' +import UserInteractionService from '@deepseek-ai/dsh-user-interaction' import type { MuxFrame, RpcRequest } from '@deepseek-ai/dsh-host-apiproxy/api' import { RpcId } from '@deepseek-ai/dsh-host-apiproxy/api/rpc' import { createApiProxy } from '../src/api-proxy.ts' @@ -38,6 +39,7 @@ async function harness(): Promise<{ ctx: Context }> { await ctx.plugin(SessionStore) await ctx.plugin(SystemPrompt, { persona: '' }) await ctx.plugin(ToolRegistry) + await ctx.plugin(UserInteractionService) await ctx.plugin(AgentRegistry) ctx.tools.register(tool('gen', { presentCall: () => ({ card: 'generic', title: 'gen call' }), diff --git a/packages/host/runtime/tests/host-runtime.spec.ts b/packages/host/runtime/tests/host-runtime.spec.ts index f3a2dc9a82..d5b91da8b1 100644 --- a/packages/host/runtime/tests/host-runtime.spec.ts +++ b/packages/host/runtime/tests/host-runtime.spec.ts @@ -358,10 +358,175 @@ describe('events streams', () => { }) }) -describe('respond stub', () => { - it('always reports not-pending (step2 registry pending)', async () => { - const { api } = await boot() - const receipt = await api.respond({ type: 'client-response', rpcId: RpcId('r'), result: { ok: true, value: null } }) - expect(receipt).toEqual({ accepted: false, reason: 'not-pending' }) +describe('question request / response', () => { + const questions = [{ + id: 'mode', question: 'Choose a mode', + options: [ + { label: 'Fast (Recommended)', description: 'Move quickly.' }, + { label: 'Careful', description: 'Review first.' }, + ], + }] + + it('waits, replays the same rpcId on reconnect, validates, and resolves first-wins', async () => { + const running = await boot() + const { api, ctx } = running + const { sessionId } = expectOk(await api.sessions.create(request({}))) + const agent = ctx.agents.get(sessionId) as Agent + const ac = new AbortController() + const stream = api.events.mux(request({}), ac.signal)[Symbol.asyncIterator]() + await stream.next() // subscribed baseline starts the generator and installs the queue + + const answerPromise = ctx.userInteraction.ask({ questions, agent }) + const requested = (await stream.next()).value as RpcRequest<MuxFrame> + expect(requested.payload).toMatchObject({ type: 'question/requested', sessionId, questions }) + + const wrongSession = await api.respond({ + type: 'client-response', rpcId: requested.rpcId, + result: { + ok: true, + value: { sessionId: 'session-other', answer: { answers: [{ id: 'mode', selected: ['Fast (Recommended)'] }] } }, + }, + }) + expect(wrongSession).toEqual({ accepted: false, reason: 'bad-response' }) + const badChoice = await api.respond({ + type: 'client-response', rpcId: requested.rpcId, + result: { + ok: true, + value: { sessionId, answer: { answers: [{ id: 'mode', selected: ['Unknown'] }] } }, + }, + }) + expect(badChoice).toEqual({ accepted: false, reason: 'bad-response' }) + const invalidResults = [ + { ok: true as const, value: null }, + { ok: true as const, value: { sessionId, answer: { answers: [] } } }, + { ok: true as const, value: { sessionId, answer: { answers: [{ id: 'wrong', selected: ['Fast (Recommended)'] }] } } }, + { ok: true as const, value: { sessionId, answer: { answers: [{ id: 'mode', selected: ['Fast (Recommended)', 'Fast (Recommended)'] }] } } }, + { ok: true as const, value: { sessionId, answer: { answers: [{ id: 'mode', selected: ['Fast (Recommended)', 'Careful'] }] } } }, + { ok: true as const, value: { sessionId, answer: { answers: [{ id: 'mode', selected: [], custom: ' ' }] } } }, + { ok: true as const, value: { sessionId, answer: { answers: [{ id: 'mode', selected: ['Careful'], custom: 'Other' }] } } }, + { ok: false as const, error: { code: 'internal' as const, message: 'wrong error', details: {} } }, + ] + for (const result of invalidResults) { + expect(await api.respond({ + type: 'client-response', rpcId: requested.rpcId, result, + })).toEqual({ accepted: false, reason: 'bad-response' }) + } + + const reconnectAbort = new AbortController() + const replay = api.events.mux(request({}), reconnectAbort.signal)[Symbol.asyncIterator]() + await replay.next() + const replayed = (await replay.next()).value as RpcRequest<MuxFrame> + expect(replayed.rpcId).toBe(requested.rpcId) + expect(replayed.payload).toEqual(requested.payload) + + const response = { + type: 'client-response' as const, + rpcId: requested.rpcId, + result: { + ok: true as const, + value: { sessionId, answer: { answers: [{ id: 'mode', selected: ['Fast (Recommended)'] }] } }, + }, + } + const [first, duplicate] = await Promise.all([api.respond(response), api.respond(response)]) + expect([first, duplicate]).toContainEqual({ accepted: true }) + expect([first, duplicate]).toContainEqual({ accepted: false, reason: 'not-pending' }) + await expect(answerPromise).resolves.toEqual({ + answers: [{ id: 'mode', selected: ['Fast (Recommended)'] }], + }) + + const resolved = (await stream.next()).value as RpcRequest<MuxFrame> + expect(resolved.payload).toMatchObject({ + type: 'question/resolved', sessionId, questionRpcId: requested.rpcId, outcome: 'answered', + }) + expect(await api.respond(response)).toEqual({ accepted: false, reason: 'not-pending' }) + + const customQuestions = [{ id: 'detail', question: 'What else?' }] + const customAnswer = ctx.userInteraction.ask({ questions: customQuestions, agent }) + const customRequested = (await stream.next()).value as RpcRequest<MuxFrame> + expect(await api.respond({ + type: 'client-response', rpcId: customRequested.rpcId, + result: { + ok: true, + value: { sessionId, answer: { answers: [{ id: 'detail', selected: [], custom: 'Keep traces' }] } }, + }, + })).toEqual({ accepted: true }) + await expect(customAnswer).resolves.toEqual({ + answers: [{ id: 'detail', selected: [], custom: 'Keep traces' }], + }) + expect(((await stream.next()).value as RpcRequest<MuxFrame>).payload).toMatchObject({ + type: 'question/resolved', questionRpcId: customRequested.rpcId, outcome: 'answered', + }) + + const blankAnswer = ctx.userInteraction.ask({ questions, agent }) + const blankRequested = (await stream.next()).value as RpcRequest<MuxFrame> + expect(await api.respond({ + type: 'client-response', rpcId: blankRequested.rpcId, + result: { + ok: true, + value: { sessionId, answer: { answers: [{ id: 'mode', selected: [] }] } }, + }, + })).toEqual({ accepted: true }) + await expect(blankAnswer).resolves.toEqual({ + answers: [{ id: 'mode', selected: [] }], + }) + expect(((await stream.next()).value as RpcRequest<MuxFrame>).payload).toMatchObject({ + type: 'question/resolved', questionRpcId: blankRequested.rpcId, outcome: 'answered', + }) + ac.abort() + reconnectAbort.abort() + }) + + it('distinguishes user cancellation from owner abort and rejects late responses', async () => { + const running = await boot() + const { api, ctx } = running + const { sessionId } = expectOk(await api.sessions.create(request({}))) + const agent = ctx.agents.get(sessionId) as Agent + const streamAbort = new AbortController() + const stream = api.events.mux(request({}), streamAbort.signal)[Symbol.asyncIterator]() + await stream.next() + + const cancelled = ctx.userInteraction.ask({ questions, agent }).catch((error: unknown) => error) + const requested = (await stream.next()).value as RpcRequest<MuxFrame> + expect(await api.respond({ + type: 'client-response', rpcId: requested.rpcId, + result: { ok: false, error: { code: 'cancelled', message: 'skip', details: {} } }, + })).toEqual({ accepted: true }) + await expect(cancelled).resolves.toMatchObject({ code: 'ASK_CANCELLED' }) + expect(((await stream.next()).value as RpcRequest<MuxFrame>).payload).toMatchObject({ + type: 'question/resolved', outcome: 'cancelled', + }) + + const ownerAbort = new AbortController() + const aborted = ctx.userInteraction.ask({ questions, agent, signal: ownerAbort.signal }) + .catch((error: unknown) => error) + const abortRequest = (await stream.next()).value as RpcRequest<MuxFrame> + ownerAbort.abort() + await expect(aborted).resolves.toMatchObject({ code: 'ASK_ABORTED' }) + expect(((await stream.next()).value as RpcRequest<MuxFrame>).payload).toMatchObject({ + type: 'question/resolved', questionRpcId: abortRequest.rpcId, outcome: 'cancelled', + }) + expect(await api.respond({ + type: 'client-response', rpcId: abortRequest.rpcId, + result: { ok: false, error: { code: 'cancelled', message: 'late', details: {} } }, + })).toEqual({ accepted: false, reason: 'not-pending' }) + streamAbort.abort() + }) + + it('rejects missing routing and pre-abort, then aborts outstanding waits on disposal', async () => { + const running = await boot() + const { ctx } = running + await expect(ctx.userInteraction.ask({ questions })).rejects.toMatchObject({ code: 'ASK_MISSING_AGENT' }) + const { sessionId } = expectOk(await running.api.sessions.create(request({}))) + const agent = ctx.agents.get(sessionId) as Agent + const alreadyAborted = new AbortController() + alreadyAborted.abort() + await expect(ctx.userInteraction.ask({ questions, agent, signal: alreadyAborted.signal })) + .rejects.toMatchObject({ code: 'ASK_ABORTED' }) + + const outstanding = ctx.userInteraction.ask({ questions, agent }) + const disposed = running.dispose() + host = undefined + await expect(outstanding).rejects.toMatchObject({ code: 'ASK_ABORTED' }) + await disposed }) }) diff --git a/packages/host/runtime/tests/web-plugins.e2e.ts b/packages/host/runtime/tests/web-plugins.e2e.ts index 45034dfa22..8bf551b57e 100644 --- a/packages/host/runtime/tests/web-plugins.e2e.ts +++ b/packages/host/runtime/tests/web-plugins.e2e.ts @@ -1,5 +1,5 @@ /** - * Web UI plugin assembly: the in-memory Loader tree mounts all eight UI + * Web UI plugin assembly: the in-memory Loader tree mounts all nine UI * packages (node halves), and the webserver registry built over it yields the * full __DSH_BOOT__ manifest — the P-I config-source bar end to end. * @@ -10,6 +10,9 @@ import { existsSync } from 'node:fs' import { createRequire } from 'node:module' import { Context } from 'cordis' +import ToolRegistry from '@deepseek-ai/dsh-tools' +import SystemPrompt from '@deepseek-ai/dsh-system-prompt' +import UserInteractionService from '@deepseek-ai/dsh-user-interaction' import { afterEach, describe, expect, it } from 'vitest' import { createHostWebPluginRegistry } from '@deepseek-ai/dsh-host-webserver' import { WEB_UI_PLUGINS, mountWebPlugins } from '../src/web-plugins.ts' @@ -31,8 +34,16 @@ afterEach(async () => { }) describe.skipIf(!built)('mountWebPlugins + registry', () => { - it('mounts the eight-package in-memory Loader tree and projects the boot manifest', async () => { + async function rootWithHostServices(): Promise<Context> { root = new Context() + await root.plugin(SystemPrompt) + await root.plugin(ToolRegistry) + await root.plugin(UserInteractionService) + return root + } + + it('mounts the nine-package in-memory Loader tree and projects the boot manifest', async () => { + root = await rootWithHostServices() const mounted = await mountWebPlugins(root) const registry = createHostWebPluginRegistry({ ctx: root, @@ -59,7 +70,7 @@ describe.skipIf(!built)('mountWebPlugins + registry', () => { }) it('is idempotent: a second mount reuses the loader and creates no duplicate entries', async () => { - root = new Context() + root = await rootWithHostServices() await mountWebPlugins(root) const second = await mountWebPlugins(root) // ctx.loader hands out a fresh traced proxy per access, so loader identity diff --git a/packages/host/runtime/tests/web-plugins.spec.ts b/packages/host/runtime/tests/web-plugins.spec.ts index 6c6a996517..4f9c4fcfe9 100644 --- a/packages/host/runtime/tests/web-plugins.spec.ts +++ b/packages/host/runtime/tests/web-plugins.spec.ts @@ -1,5 +1,5 @@ /** - * mountWebPlugins unit coverage (keyless; the real eight-package walk is the + * mountWebPlugins unit coverage (keyless; the real nine-package walk is the * built-artifact e2e). The Loader-facing behavior — baseUrl anchoring, entry * creation with idempotent reuse, the fiber-less fail-loud sweep, and the * resolver seam — is exercised against a stubbed loader service so it runs @@ -85,7 +85,7 @@ describe('mountWebPlugins (stubbed loader)', () => { it('mounts the real Loader when none is present (the ctx.plugin(Loader) branch)', async () => { root = new Context() - // Environment-dependent outcome: with built lib/ the eight imports load + // Environment-dependent outcome: with built lib/ the nine imports load // and the mount resolves; without them every entry stays fiber-less and // the sweep throws its loud list. Either way the branch under test is the // Loader auto-mount. Manual try/catch keeps cordis-traced proxies out of @@ -100,7 +100,7 @@ describe('mountWebPlugins (stubbed loader)', () => { } expect(outcome === 'resolved' || /UI plugin\(s\) failed to load/.test(outcome)).toBe(true) expect(root.get('loader') !== undefined).toBe(true) - }, 30_000) // built-env run imports eight real plugin packages through the Loader + }, 30_000) // built-env run imports nine real plugin packages through the Loader it('keeps a caller-set baseUrl (anchors only when absent)', async () => { const entriesList: FakeEntry[] = [] diff --git a/packages/host/runtime/tsconfig.json b/packages/host/runtime/tsconfig.json index 9836e0b5fd..4a9ed315c2 100644 --- a/packages/host/runtime/tsconfig.json +++ b/packages/host/runtime/tsconfig.json @@ -137,6 +137,9 @@ { "path": "../../client/ui-conversation" }, + { + "path": "../../client/ui-question" + }, { "path": "../../client/ui-trajectory" } diff --git a/packages/ui/user-interaction/README.md b/packages/ui/user-interaction/README.md index c026ff0395..72b1d73790 100644 --- a/packages/ui/user-interaction/README.md +++ b/packages/ui/user-interaction/README.md @@ -17,7 +17,7 @@ Abstract user-interaction seam. It owns `ctx.userInteraction`, the service a mod - `UserInteractionProvider` — UI implementation with `ask(request)`. - `UserInteractionError` — `HarnessError` subclass with codes such as `EMPTY_QUESTIONS`, `NO_PROVIDER`, `DUPLICATE_PROVIDER`, and `ASK_ABORTED`. -When an answer includes `custom`, `selected` is empty; custom text is an override rather than a supplement to selected choices. +When an answer includes `custom`, `selected` is empty; custom text is an override rather than a supplement to selected choices. A UI may preserve a skipped item as `{ id, selected: [] }`, keeping the existing answer shape while retaining other answers in the batch. ## Role diff --git a/packages/ui/user-interaction/src/types.ts b/packages/ui/user-interaction/src/types.ts index 2ebb4503ce..1d5960e03e 100644 --- a/packages/ui/user-interaction/src/types.ts +++ b/packages/ui/user-interaction/src/types.ts @@ -31,7 +31,7 @@ export interface AskUserQuestionItem { export interface AskUserQuestionAnswerItem { /** The answered question id. */ id: string - /** Selected option labels. Empty when the answer is purely custom text. */ + /** Selected option labels. Empty for custom or unanswered choices. */ selected: string[] /** Optional free-text "Other" answer. */ custom?: string diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf971067c5..e9f40158e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -607,6 +607,52 @@ importers: specifier: ^4.0.0-rc.7 version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5) + packages/client/ui-question: + dependencies: + '@deepseek-ai/dsh-client-connection': + specifier: workspace:^ + version: link:../connection + '@deepseek-ai/dsh-client-runtime': + specifier: workspace:^ + version: link:../runtime + '@deepseek-ai/dsh-client-ui-conversation': + specifier: workspace:^ + version: link:../ui-conversation + '@deepseek-ai/dsh-client-ui-primitives': + specifier: workspace:^ + version: link:../ui-primitives + '@deepseek-ai/dsh-tool-ask-user': + specifier: workspace:^ + version: link:../../ui/tool-ask-user + clsx: + specifier: ^2.0.0 + version: 2.1.1 + react: + specifier: ^18.2.0 + version: 18.3.1 + devDependencies: + '@deepseek-ai/dsh-agent': + specifier: workspace:^ + version: link:../../core/agent + '@deepseek-ai/dsh-invariants': + specifier: workspace:^ + version: link:../../support/invariants + '@deepseek-ai/dsh-system-prompt': + specifier: workspace:^ + version: link:../../core/system-prompt + '@deepseek-ai/dsh-tools': + specifier: workspace:^ + version: link:../../core/tools + '@deepseek-ai/dsh-user-interaction': + specifier: workspace:^ + version: link:../../ui/user-interaction + '@types/react': + specifier: ~18.3.1 + version: 18.3.31 + cordis: + specifier: ^4.0.0-rc.7 + version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5) + packages/client/ui-sidebar: dependencies: '@deepseek-ai/dsh-client-runtime': @@ -1899,6 +1945,9 @@ importers: '@deepseek-ai/dsh-client-ui-layout': specifier: workspace:^ version: link:../../client/ui-layout + '@deepseek-ai/dsh-client-ui-question': + specifier: workspace:^ + version: link:../../client/ui-question '@deepseek-ai/dsh-client-ui-sidebar': specifier: workspace:^ version: link:../../client/ui-sidebar @@ -1995,6 +2044,9 @@ importers: '@deepseek-ai/dsh-tools': specifier: workspace:^ version: link:../../core/tools + '@deepseek-ai/dsh-user-interaction': + specifier: workspace:^ + version: link:../../ui/user-interaction '@deepseek-ai/dsh-workflow-workerthread': specifier: workspace:^ version: link:../../workflow/workflow-workerthread diff --git a/scripts/verify-package-readme-model-experience.ts b/scripts/verify-package-readme-model-experience.ts index 6fc46dbdb8..1432ee6b8b 100644 --- a/scripts/verify-package-readme-model-experience.ts +++ b/scripts/verify-package-readme-model-experience.ts @@ -53,6 +53,7 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly<Record<string, SentenceContract>> = { 'packages/client/ui-layout': { kind: 'none', reason: 'Browser-side UI plugin layer; registers no model surface.' }, 'packages/client/ui-sidebar': { kind: 'none', reason: 'Browser-side UI plugin layer; registers no model surface.' }, 'packages/client/ui-conversation': { kind: 'none', reason: 'Browser-side UI plugin layer; registers no model surface.' }, + 'packages/client/ui-question': { kind: 'indirect', reason: 'The package mounts dsh-tool-ask-user; that tool owns the model-visible schema and answer rendering.' }, 'packages/client/ui-trajectory': { kind: 'none', reason: 'Browser-side UI plugin layer; registers no model surface.' }, 'packages/client/ui-theme': { kind: 'none', reason: 'Browser-side UI plugin layer; registers no model surface.' }, 'packages/client/i18n': { kind: 'none', reason: 'Browser-side UI plugin layer; registers no model surface.' }, diff --git a/tsconfig.base.json b/tsconfig.base.json index a44f5fe7b3..0281019d0a 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -103,6 +103,7 @@ "@deepseek-ai/dsh-client-ui-layout": ["./packages/client/ui-layout/src"], "@deepseek-ai/dsh-client-ui-sidebar": ["./packages/client/ui-sidebar/src"], "@deepseek-ai/dsh-client-ui-conversation": ["./packages/client/ui-conversation/src"], + "@deepseek-ai/dsh-client-ui-question": ["./packages/client/ui-question/src"], "@deepseek-ai/dsh-client-ui-trajectory": ["./packages/client/ui-trajectory/src"], "@deepseek-ai/dsh-client-ui-theme": ["./packages/client/ui-theme/src"], "@deepseek-ai/dsh-client-i18n": ["./packages/client/i18n/src"], diff --git a/tsconfig.build.json b/tsconfig.build.json index 9800433ecb..675237b313 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -119,6 +119,7 @@ { "path": "./packages/client/ui-layout" }, { "path": "./packages/client/ui-sidebar" }, { "path": "./packages/client/ui-conversation" }, + { "path": "./packages/client/ui-question" }, { "path": "./packages/client/ui-trajectory" }, { "path": "./packages/client/ui-theme" }, { "path": "./packages/client/i18n" }, diff --git a/tsconfig.client.json b/tsconfig.client.json index ceb498a1a9..d61e24c210 100644 --- a/tsconfig.client.json +++ b/tsconfig.client.json @@ -33,6 +33,7 @@ { "path": "./packages/client/ui-layout" }, { "path": "./packages/client/ui-sidebar" }, { "path": "./packages/client/ui-conversation" }, + { "path": "./packages/client/ui-question" }, { "path": "./packages/client/ui-trajectory" }, { "path": "./packages/client/ui-theme" }, { "path": "./packages/client/i18n" }, From a9ea193e31adba8dfc3418bb1ee0822300c37dfc Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:43:53 +0800 Subject: [PATCH 102/368] feat(web): render durable session titles --- apps/web/tests/session-title.snapshot.ts | 114 ++++++++++++++++++ apps/web/tests/snapshots/session-title.json | 12 ++ knip.json | 2 +- .../client/connection/src/client/fixture.ts | 34 +++++- .../client/connection/tests/fixture.spec.ts | 13 +- .../runtime/src/client/sessions/lineage.ts | 18 ++- .../runtime/src/client/sessions/manager.ts | 33 ++++- .../runtime/src/client/sessions/service.ts | 15 ++- packages/client/runtime/tests/manager.spec.ts | 30 +++++ .../runtime/tests/sessions-service.spec.ts | 18 ++- .../src/client/skeleton/ConversationRoot.tsx | 2 +- .../tests/apply-inject.spec.tsx | 4 +- .../ui-conversation/tests/chat-apply.spec.tsx | 4 +- .../tests/chat-stats-bash-sample.spec.tsx | 4 +- .../tests/gate-branch-tails.spec.tsx | 6 +- .../tests/selection-survival.spec.ts | 12 +- .../tests/skeleton-branches.spec.tsx | 2 +- .../ui-conversation/tests/skeleton.spec.tsx | 4 +- .../client/ui-layout/tests/service.spec.ts | 2 +- packages/client/ui-sidebar/src/client/tree.ts | 8 +- .../client/ui-sidebar/tests/apply.spec.tsx | 4 +- .../ui-sidebar/tests/sidebar-root.spec.tsx | 1 + .../client/ui-sidebar/tests/store.spec.ts | 1 + packages/client/ui-sidebar/tests/tree.spec.ts | 13 +- .../client/ui-trajectory/tests/views.spec.tsx | 2 +- packages/client/web/src/DocumentTitle.tsx | 22 ++++ packages/client/web/src/app.tsx | 7 ++ packages/client/web/src/index.ts | 1 + packages/client/web/tests/boot.spec.tsx | 8 +- .../client/web/tests/document-title.spec.tsx | 28 +++++ .../host/apiproxy/src/api/events.schema.ts | 1 + packages/host/apiproxy/src/api/events.ts | 6 +- .../host/apiproxy/tests/rpc-schemas.spec.ts | 8 ++ packages/host/runtime/package.json | 1 + packages/host/runtime/src/api-proxy.ts | 31 ++++- .../host/runtime/tests/host-runtime.spec.ts | 60 +++++++++ packages/host/runtime/tsconfig.json | 3 + pnpm-lock.yaml | 3 + vitest.snapshot.config.ts | 1 + 39 files changed, 481 insertions(+), 57 deletions(-) create mode 100644 apps/web/tests/session-title.snapshot.ts create mode 100644 apps/web/tests/snapshots/session-title.json create mode 100644 packages/client/web/src/DocumentTitle.tsx create mode 100644 packages/client/web/tests/document-title.spec.tsx diff --git a/apps/web/tests/session-title.snapshot.ts b/apps/web/tests/session-title.snapshot.ts new file mode 100644 index 0000000000..a1b5f45839 --- /dev/null +++ b/apps/web/tests/session-title.snapshot.ts @@ -0,0 +1,114 @@ +// @vitest-environment jsdom +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { act, cleanup, fireEvent, screen, waitFor, within } from '@testing-library/react' +import { afterEach, beforeEach, expect, it, vi } from 'vitest' +import type { BootPluginEntry } from '@deepseek-ai/dsh-client-runtime/client' +import { bootWebShell } from '@deepseek-ai/dsh-client-web' + +const PLUGINS: readonly (BootPluginEntry & { dir: string })[] = [ + { id: '@deepseek-ai/dsh-client-connection', dir: 'connection', url: '/plugins/connection.js', inject: [], immediately: true }, + { id: '@deepseek-ai/dsh-client-runtime', dir: 'runtime', url: '/plugins/runtime.js', inject: ['@deepseek-ai/dsh-client-connection'], immediately: true }, + { id: '@deepseek-ai/dsh-client-ui-theme', dir: 'ui-theme', url: '/plugins/ui-theme.js', inject: [], immediately: true }, + { id: '@deepseek-ai/dsh-client-i18n', dir: 'i18n', url: '/plugins/i18n.js', inject: [], immediately: true }, + { id: '@deepseek-ai/dsh-client-ui-layout', dir: 'ui-layout', url: '/plugins/ui-layout.js', inject: ['@deepseek-ai/dsh-client-runtime'] }, + { id: '@deepseek-ai/dsh-client-ui-sidebar', dir: 'ui-sidebar', url: '/plugins/ui-sidebar.js', inject: ['@deepseek-ai/dsh-client-ui-layout'] }, + { id: '@deepseek-ai/dsh-client-ui-conversation', dir: 'ui-conversation', url: '/plugins/ui-conversation.js', inject: ['@deepseek-ai/dsh-client-ui-layout'] }, + { id: '@deepseek-ai/dsh-client-ui-trajectory', dir: 'ui-trajectory', url: '/plugins/ui-trajectory.js', inject: ['@deepseek-ai/dsh-client-ui-conversation'] }, +] + +const bundles = new Map(PLUGINS.map(plugin => [ + plugin.url, + readFileSync(join(process.cwd(), 'packages/client', plugin.dir, 'lib/client.js'), 'utf8'), +])) + +interface FixtureTiming { + appendTitle(id: string, title: string): void +} + +interface FixtureWindow extends Window { + __DSH_BOOT__?: { plugins: BootPluginEntry[] } + DSHClientProxy?: unknown +} + +class ResizeObserverStub { + observe(): void {} + disconnect(): void {} + unobserve(): void {} +} + +const win = window as FixtureWindow +let unmount: (() => void) | undefined + +beforeEach(() => { + localStorage.clear() + history.replaceState(null, '', '/?fixture') + document.title = 'DeepSeek Harness' + const root = document.createElement('div') + root.id = 'root' + document.body.appendChild(root) + vi.stubGlobal('ResizeObserver', ResizeObserverStub) + vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) => + setTimeout(() => { callback(0) }, 0) as unknown as number) + vi.stubGlobal('cancelAnimationFrame', (id: number) => { clearTimeout(id) }) + win.__DSH_BOOT__ = { plugins: PLUGINS.map(({ dir: _dir, ...plugin }) => plugin) } +}) + +afterEach(() => { + act(() => { unmount?.() }) + unmount = undefined + cleanup() + delete win.__DSH_BOOT__ + delete win.DSHClientProxy + delete (globalThis as Record<string, unknown>).__fxTiming + document.body.innerHTML = '' + document.head.querySelectorAll('style[data-plugin]').forEach((style) => { style.remove() }) + document.title = '' + history.replaceState(null, '', '/') + vi.unstubAllGlobals() +}) + +/** Read only the stable, user-facing title surfaces from the assembled app. */ +function titleSurfaces(label: string): { sidebar: string; breadcrumb: string; documentTitle: string } { + const tree = screen.getByRole('tree', { name: 'Sessions' }) + const sidebar = within(tree).getByText(label).textContent ?? '' + const breadcrumb = within(screen.getByRole('navigation', { name: '会话层级' })) + .getByRole('button', { name: label }).textContent ?? '' + return { sidebar, breadcrumb, documentTitle: document.title } +} + +it('projects initial and revised durable titles through the built eight-plugin fixture app', async () => { + const root = document.querySelector<HTMLElement>('#root') + if (root === null) throw new Error('snapshot root missing') + act(() => { + unmount = bootWebShell(root, { + fetchBundle: (url) => { + const code = bundles.get(url) + return code === undefined ? Promise.reject(new Error(`missing built bundle ${url}`)) : Promise.resolve(code) + }, + executeBundle: (code) => { (0, eval)(code) }, + }) + }) + + const projectLabel = await screen.findByText('fixture', {}, { timeout: 10_000 }) + const projectRow = projectLabel.closest<HTMLElement>('[role="treeitem"]') + if (projectRow === null) throw new Error('fixture project row missing') + fireEvent.click(projectRow) + + const initialLabel = 'Fixture 历史会话' + const initialRowLabel = await screen.findByText(initialLabel) + const initialRow = initialRowLabel.closest<HTMLElement>('[role="treeitem"]') + if (initialRow === null) throw new Error('fixture session row missing') + fireEvent.click(initialRow) + await waitFor(() => { expect(document.title).toBe(`${initialLabel} — DeepSeek Harness`) }) + const initial = titleSurfaces(initialLabel) + + const revisedLabel = 'Fixture 修订标题' + const timing = (globalThis as Record<string, unknown>).__fxTiming as FixtureTiming + act(() => { timing.appendTitle('fx-alpha', revisedLabel) }) + await waitFor(() => { expect(document.title).toBe(`${revisedLabel} — DeepSeek Harness`) }) + const revised = titleSurfaces(revisedLabel) + + await expect(`${JSON.stringify({ initial, revised }, null, 2)}\n`) + .toMatchFileSnapshot('./snapshots/session-title.json') +}) diff --git a/apps/web/tests/snapshots/session-title.json b/apps/web/tests/snapshots/session-title.json new file mode 100644 index 0000000000..2063036803 --- /dev/null +++ b/apps/web/tests/snapshots/session-title.json @@ -0,0 +1,12 @@ +{ + "initial": { + "sidebar": "Fixture 历史会话", + "breadcrumb": "Fixture 历史会话", + "documentTitle": "Fixture 历史会话 — DeepSeek Harness" + }, + "revised": { + "sidebar": "Fixture 修订标题", + "breadcrumb": "Fixture 修订标题", + "documentTitle": "Fixture 修订标题 — DeepSeek Harness" + } +} diff --git a/knip.json b/knip.json index dbc1e585de..e89f1908fe 100644 --- a/knip.json +++ b/knip.json @@ -545,6 +545,7 @@ "apps/web": { "entry": [ "tests/**/*.e2e.ts", + "tests/**/*.snapshot.ts", "tests/support.ts" ], "project": [ @@ -552,7 +553,6 @@ "tests/**/*.ts" ], "ignoreDependencies": [ - "@deepseek-ai/dsh-client-runtime", "@deepseek-ai/dsh-client-ui-primitives", "@deepseek-ai/dsh-client-ui-slots", "@deepseek-ai/dsh-client-web-react", diff --git a/packages/client/connection/src/client/fixture.ts b/packages/client/connection/src/client/fixture.ts index 7d4a93e888..f831519e25 100644 --- a/packages/client/connection/src/client/fixture.ts +++ b/packages/client/connection/src/client/fixture.ts @@ -40,7 +40,13 @@ function buildAlphaLog(): SessionEvent[] { } for (let turn = 0; turn < 60; turn++) { push({ type: 'turn/start', data: { turn, trigger: { kind: 'message', source: { kind: 'user' } } } }) - push({ type: 'user/message', surfaceOp: 'append', data: { content: text(`问题 ${turn}:fixture 历史消息,用于翻页与渲染验收。`), source: { kind: 'user' } } }) + const userSeq = push({ type: 'user/message', surfaceOp: 'append', data: { content: text(`问题 ${turn}:fixture 历史消息,用于翻页与渲染验收。`), source: { kind: 'user' } } }) + if (turn === 0) { + push({ + type: 'session/title', + data: { title: 'Fixture 历史会话', messageSeqs: [userSeq], source: { kind: 'fallback' } }, + }) + } if (turn % 9 === 4) { push({ type: 'context/message', surfaceOp: 'append', data: { content: text(`[fixture] 上下文注入(turn ${turn})`), source: { kind: 'plugin', plugin: 'fixture' } } }) } @@ -155,6 +161,20 @@ function viewFor(event: SessionEvent, log: readonly SessionEvent[]): ToolEventVi return undefined } +/** Fold the latest fixture title into the host's control-frame projection. */ +function titleFrameOf(id: SessionId, log: readonly SessionEvent[]): Extract<MuxFrame, { type: 'session/title' }> | undefined { + const event = log.findLast(item => (item as { type: string }).type === 'session/title') + if (event === undefined) return undefined + const titleEvent = event as unknown as { seq: number; time: number; data: { title: string } } + return { + type: 'session/title', + sessionId: id, + title: titleEvent.data.title, + eventSeq: titleEvent.seq, + updatedAt: titleEvent.time, + } +} + /** * Message-boundary paging (mirrors the host's paging contract): count * maxMessages messages @@ -294,6 +314,10 @@ export function createFixtureApi(): ApiProxy { emitMux(view === undefined ? { type: 'session/event', sessionId: id, event } : { type: 'session/event', sessionId: id, event, view }) + if ((event as { type: string }).type === 'session/title') { + // The raw title is already in this log, so the latest-title fold must find it. + emitMux(titleFrameOf(id, log) as Extract<MuxFrame, { type: 'session/title' }>) + } } /** At most one in-flight replay per session; cancel clears it. */ @@ -322,6 +346,12 @@ export function createFixtureApi(): ApiProxy { appendUser(id: string, msg: string): void { append(sid(id), { type: 'user/message', surfaceOp: 'append', data: { content: text(msg), source: { kind: 'user' } } }) }, + /** Append a later durable title revision through the normal raw-event + control-frame path. */ + appendTitle(id: string, title: string): void { + const log = logOf(sid(id)) + const messageSeqs = log.filter(event => event.type === 'user/message').map(event => event.seq) + append(sid(id), { type: 'session/title', data: { title, messageSeqs, source: { kind: 'provider', provider: 'fixture' } } }) + }, /** Log append WITHOUT the mux emit: a frame lost in transit — history still serves it, the client must repull. */ appendSilent(id: string, msg: string): void { const log = logOf(sid(id)) @@ -433,6 +463,8 @@ export function createFixtureApi(): ApiProxy { for (const s of sessions) { if (!s.running) continue conn.push({ rpcId: mint(), payload: { type: 'session/subscribed', sessionId: s.sessionId, lastSeq: (logs.get(s.sessionId)?.length ?? 0) - 1 } }) + const title = titleFrameOf(s.sessionId, logs.get(s.sessionId) ?? []) + if (title !== undefined) conn.push({ rpcId: mint(), payload: title }) } conn.push({ rpcId: pendingApprovalRpcId, diff --git a/packages/client/connection/tests/fixture.spec.ts b/packages/client/connection/tests/fixture.spec.ts index c50921a44d..440c90fc05 100644 --- a/packages/client/connection/tests/fixture.spec.ts +++ b/packages/client/connection/tests/fixture.spec.ts @@ -18,6 +18,7 @@ interface TimingHooks { setHistoryDelay(ms: number): void failNextHistory(): void appendUser(id: string, msg: string): void + appendTitle(id: string, title: string): void appendSilent(id: string, msg: string): void breakStreams(): void } @@ -155,7 +156,7 @@ describe('createFixtureApi', () => { const envelopes: RpcRequest<MuxFrame>[] = [] for await (const envelope of api.events.mux(req({}), abort.signal)) { envelopes.push(envelope) - if (envelopes.length >= 2) abort.abort() + if (envelopes.length >= 3) abort.abort() } return envelopes } @@ -163,8 +164,9 @@ describe('createFixtureApi', () => { const second = await openOnce() expect(first[0]?.payload).toMatchObject({ type: 'session/subscribed', sessionId: 'fx-alpha' }) expect((first[0]?.payload as { lastSeq: number }).lastSeq).toBeGreaterThan(0) - expect(first[1]?.payload).toMatchObject({ type: 'approval/requested', toolName: 'dangerous_tool' }) - expect(second[1]?.rpcId).toBe(first[1]?.rpcId) // stable rpcId across replays (host replay semantics) + expect(first[1]?.payload).toMatchObject({ type: 'session/title', sessionId: 'fx-alpha', title: 'Fixture 历史会话' }) + expect(first[2]?.payload).toMatchObject({ type: 'approval/requested', toolName: 'dangerous_tool' }) + expect(second[2]?.rpcId).toBe(first[2]?.rpcId) // stable rpcId across replays (host replay semantics) }) it('steer with no replay in flight falls through to a fresh queued turn; non-text blocks stringify empty', async () => { @@ -248,10 +250,15 @@ describe('createFixtureApi', () => { await new Promise(resolve => setTimeout(resolve, 10)) hooks.appendSilent('fx-alpha', '静默丢帧') hooks.appendUser('fx-alpha', '正常直播') + hooks.appendTitle('fx-alpha', 'Fixture 修订标题') await vi.waitFor(() => { expect(seen.some(f => f.type === 'session/event' && JSON.stringify(f.event.data).includes('正常直播'))).toBe(true) + expect(seen.some(f => f.type === 'session/title' && f.title === 'Fixture 修订标题')).toBe(true) }) expect(seen.some(f => f.type === 'session/event' && JSON.stringify(f.event.data).includes('静默丢帧'))).toBe(false) + const rawTitleIndex = seen.findIndex(f => f.type === 'session/event' && (f.event as { type: string }).type === 'session/title') + const titleControlIndex = seen.findIndex(f => f.type === 'session/title' && f.title === 'Fixture 修订标题') + expect(titleControlIndex).toBe(rawTitleIndex + 1) // But history serves the silent event (the client's repull finds it). const repull = await api.sessions.history(req({ sessionId: sid('fx-alpha'), maxMessages: 5 })) if (!repull.result.ok) throw new Error('repull failed') diff --git a/packages/client/runtime/src/client/sessions/lineage.ts b/packages/client/runtime/src/client/sessions/lineage.ts index 4f67f33343..c6bd572ea7 100644 --- a/packages/client/runtime/src/client/sessions/lineage.ts +++ b/packages/client/runtime/src/client/sessions/lineage.ts @@ -4,9 +4,15 @@ import type { SessionId, SessionSummary } from '@deepseek-ai/dsh-client-connection/client' +/** Host list summary enriched with the latest mux-projected durable title. */ +export interface TitledSessionSummary extends SessionSummary { + title?: string +} + /** One flattened session-list row (summary + lineage indent depth). */ export interface SessionListEntry { sessionId: SessionId + title?: string updatedAt: number running: boolean parentSessionId?: SessionId @@ -21,12 +27,12 @@ export interface SessionListEntry { * @param summaries - the host's session.list items. * @returns display rows in render order. */ -export function flattenLineage(summaries: readonly SessionSummary[]): SessionListEntry[] { - const byId = new Map<SessionId, SessionSummary>() +export function flattenLineage(summaries: readonly TitledSessionSummary[]): SessionListEntry[] { + const byId = new Map<SessionId, TitledSessionSummary>() for (const s of summaries) byId.set(s.sessionId, s) - const children = new Map<SessionId, SessionSummary[]>() - const roots: SessionSummary[] = [] + const children = new Map<SessionId, TitledSessionSummary[]>() + const roots: TitledSessionSummary[] = [] for (const s of summaries) { if (s.parentSessionId !== undefined && byId.has(s.parentSessionId)) { const list = children.get(s.parentSessionId) ?? [] @@ -37,12 +43,12 @@ export function flattenLineage(summaries: readonly SessionSummary[]): SessionLis } } - const byUpdatedDesc = (a: SessionSummary, b: SessionSummary): number => b.updatedAt - a.updatedAt + const byUpdatedDesc = (a: TitledSessionSummary, b: TitledSessionSummary): number => b.updatedAt - a.updatedAt roots.sort(byUpdatedDesc) const out: SessionListEntry[] = [] const visited = new Set<SessionId>() - const walk = (s: SessionSummary, depth: number): void => { + const walk = (s: TitledSessionSummary, depth: number): void => { if (visited.has(s.sessionId)) { console.warn(`[web-runtime] lineage cycle at ${s.sessionId}; emitting as root`) return diff --git a/packages/client/runtime/src/client/sessions/manager.ts b/packages/client/runtime/src/client/sessions/manager.ts index 2881fea468..950b03b517 100644 --- a/packages/client/runtime/src/client/sessions/manager.ts +++ b/packages/client/runtime/src/client/sessions/manager.ts @@ -4,7 +4,7 @@ import type { IApiClient, HostFrame, MuxFrame, RpcError, RpcRequest, RpcResult, SessionId, SessionSummary } from '@deepseek-ai/dsh-client-connection/client' import { transportError } from '@deepseek-ai/dsh-client-connection/client' -import type { SessionListEntry } from './lineage.ts' +import type { SessionListEntry, TitledSessionSummary } from './lineage.ts' import { flattenLineage } from './lineage.ts' import { Notifier } from './notifier.ts' import { Session } from './session.ts' @@ -19,6 +19,13 @@ export interface SessionListSnapshot { /** Per-session cap for pre-instantiation approval/question buffering (low-frequency frames; a few dozen covers any real backlog). */ const PENDING_BUFFER_CAP = 32 +/** Latest title control snapshot retained independently of list/instance arrival. */ +interface SessionTitleSnapshot { + title: string + eventSeq: number + updatedAt: number +} + /** Instance cluster + frame entry + the session list (see the web client architecture RFC). */ export class SessionManager { private readonly sessions = new Map<SessionId, Session>() @@ -27,6 +34,7 @@ export class SessionManager { * drop-and-backfill path; replayed and cleared on instantiation. Bounded per session (these * frames are low-frequency; overflow drops oldest) and dropped on session-removed (audit S7). */ private readonly pendingBuffers = new Map<SessionId, RpcRequest<MuxFrame>[]>() + private readonly titleSnapshots = new Map<SessionId, SessionTitleSnapshot>() private summaries: SessionSummary[] = [] private listState: 'idle' | 'loading' | 'error' = 'idle' private listError: RpcError | null = null @@ -158,6 +166,17 @@ export class SessionManager { handleMuxEnvelope(envelope: RpcRequest<MuxFrame>): void { const frame = envelope.payload if (frame.type === 'stream/error') return // Controller already treats this as stream failure + if (frame.type === 'session/title') { + const current = this.titleSnapshots.get(frame.sessionId) + if (current !== undefined && current.eventSeq >= frame.eventSeq) return + this.titleSnapshots.set(frame.sessionId, { + title: frame.title, + eventSeq: frame.eventSeq, + updatedAt: frame.updatedAt, + }) + this.notifier.markDirty() + return + } const session = this.sessions.get(frame.sessionId) if (session === undefined) { // Approval/question frames never hit history: buffer for replay on instantiation; @@ -204,6 +223,7 @@ export class SessionManager { this.summaries = this.summaries.filter(s => s.sessionId !== frame.sessionId) this.sessions.get(frame.sessionId)?.handleRemoved() // instance survives (resident-instance rule), only flagged in the snapshot this.pendingBuffers.delete(frame.sessionId) // a removed session's buffered frames must not replay on a future instantiation + this.titleSnapshots.delete(frame.sessionId) this.notifier.markDirty() return } @@ -230,12 +250,19 @@ export class SessionManager { } private buildListSnapshot(): SessionListSnapshot { - const fresh = flattenLineage(this.summaries) + const merged: TitledSessionSummary[] = this.summaries.map((summary) => { + const title = this.titleSnapshots.get(summary.sessionId) + return title === undefined + ? summary + : { ...summary, title: title.title, updatedAt: Math.max(summary.updatedAt, title.updatedAt) } + }) + const fresh = flattenLineage(merged) const items = fresh.map((entry) => { const prev = this.entryCache.get(entry.sessionId) if ( prev !== undefined && prev.updatedAt === entry.updatedAt && prev.running === entry.running - && prev.parentSessionId === entry.parentSessionId && prev.cwd === entry.cwd && prev.depth === entry.depth + && prev.parentSessionId === entry.parentSessionId && prev.cwd === entry.cwd + && prev.title === entry.title && prev.depth === entry.depth ) return prev this.entryCache.set(entry.sessionId, entry) return entry diff --git a/packages/client/runtime/src/client/sessions/service.ts b/packages/client/runtime/src/client/sessions/service.ts index 2b4cf9677e..25c6579c3f 100644 --- a/packages/client/runtime/src/client/sessions/service.ts +++ b/packages/client/runtime/src/client/sessions/service.ts @@ -21,7 +21,10 @@ import type { Session } from './session.ts' /** Session list row projected from the host list RPC plus live stream increments. */ export interface SessionSummary { id: SessionId - title: string + /** Latest durable log-backed title, absent until the host projects one. */ + title?: string + /** Human-facing label: durable title, project basename, then session id. */ + displayTitle: string cwd?: string parentId?: SessionId running: boolean @@ -54,10 +57,11 @@ export function scopeOf(ctx: Context): SessionId | undefined { function sessionScope(): void {} /** - * Display title projection. The wire summary carries no title yet (P-I - * ledger): the project directory's basename stands in, then the raw id. + * Display title projection: durable title, project directory basename, then + * the raw id. */ -function titleOf(cwd: string | undefined, id: SessionId): string { +function displayTitleOf(title: string | undefined, cwd: string | undefined, id: SessionId): string { + if (title !== undefined) return title if (cwd !== undefined && cwd !== '') { const base = cwd.replace(/[/\\]+$/, '').split(/[/\\]/).pop() if (base !== undefined && base !== '') return base @@ -176,9 +180,10 @@ export class SessionsService { ids.push(entry.sessionId) byId[entry.sessionId] = { id: entry.sessionId, - title: titleOf(entry.cwd, entry.sessionId), + displayTitle: displayTitleOf(entry.title, entry.cwd, entry.sessionId), running: entry.running, updatedAt: entry.updatedAt, + ...(entry.title !== undefined ? { title: entry.title } : {}), ...(entry.cwd !== undefined ? { cwd: entry.cwd } : {}), ...(entry.parentSessionId !== undefined ? { parentId: entry.parentSessionId } : {}), } diff --git a/packages/client/runtime/tests/manager.spec.ts b/packages/client/runtime/tests/manager.spec.ts index af7bc60fd2..edf326bd31 100644 --- a/packages/client/runtime/tests/manager.spec.ts +++ b/packages/client/runtime/tests/manager.spec.ts @@ -89,6 +89,36 @@ describe('list lifecycle', () => { expect(result).toMatchObject({ ok: true, value: { sessionId: S2 } }) expect(manager.getListSnapshot().items.map(i => i.sessionId)).toEqual([S2]) }) + + it('retains monotonic title snapshots before list arrival, merges recency, and clears them on removal', async () => { + const api = new FakeApiClient() + const manager = new SessionManager(api) + manager.handleMuxEnvelope({ + rpcId: 'title-new' as never, + payload: { type: 'session/title', sessionId: S1, title: 'Newest', eventSeq: 4, updatedAt: 300 }, + }) + manager.handleMuxEnvelope({ + rpcId: 'title-stale' as never, + payload: { type: 'session/title', sessionId: S1, title: 'Stale', eventSeq: 3, updatedAt: 900 }, + }) + manager.handleMuxEnvelope({ + rpcId: 'title-equal' as never, + payload: { type: 'session/title', sessionId: S1, title: 'Equal', eventSeq: 4, updatedAt: 901 }, + }) + api.onList = () => Promise.resolve(ok({ + items: [summary(S1), summary(S2, { updatedAt: 200 })] as never[], + })) + await manager.refreshList() + + const titled = manager.getListSnapshot() + expect(titled.items.map(item => item.sessionId)).toEqual([S1, S2]) + expect(titled.items[0]).toMatchObject({ title: 'Newest', updatedAt: 300 }) + expect(titled.items[1]?.title).toBeUndefined() + + manager.handleHostEnvelope({ rpcId: 'removed' as never, payload: { type: 'host/session-removed', sessionId: S1 } }) + manager.handleHostEnvelope({ rpcId: 'readded' as never, payload: { type: 'host/session-added', sessionId: S1 } }) + expect(manager.getListSnapshot().items.find(item => item.sessionId === S1)?.title).toBeUndefined() + }) }) describe('host frame routing', () => { diff --git a/packages/client/runtime/tests/sessions-service.spec.ts b/packages/client/runtime/tests/sessions-service.spec.ts index f3989c4532..4a8b68ed73 100644 --- a/packages/client/runtime/tests/sessions-service.spec.ts +++ b/packages/client/runtime/tests/sessions-service.spec.ts @@ -38,16 +38,21 @@ async function feedList(b: Bench, rows: { id: string; cwd?: string; parentId?: s } describe('list store projection', () => { - it('projects ids/byId with cwd-basename titles (id fallback) and parent links', async () => { + it('projects durable titles separately from cwd/id display fallbacks and parent links', async () => { const b = bench() + b.svc.manager.handleMuxEnvelope({ + rpcId: 'title' as never, + payload: { type: 'session/title', sessionId: sid('s1'), title: 'Durable title', eventSeq: 2, updatedAt: 3 }, + }) await feedList(b, [ { id: 's1', cwd: '/home/u/proj-a/' }, { id: 's2', parentId: 's1', running: true }, ]) const state = b.svc.list.getSnapshot() expect(state.ids).toEqual(['s1', 's2']) - expect(state.byId[sid('s1')]).toMatchObject({ title: 'proj-a', cwd: '/home/u/proj-a/' }) - expect(state.byId[sid('s2')]).toMatchObject({ title: 's2', parentId: 's1', running: true }) + expect(state.byId[sid('s1')]).toMatchObject({ title: 'Durable title', displayTitle: 'Durable title', cwd: '/home/u/proj-a/' }) + expect(state.byId[sid('s2')]).toMatchObject({ displayTitle: 's2', parentId: 's1', running: true }) + expect(state.byId[sid('s2')]?.title).toBeUndefined() }) it('reflects live increments (host stream via manager) into the store', async () => { @@ -141,12 +146,13 @@ describe('create', () => { }) describe('coverage tails (branch duals)', () => { - it('titleOf falls back to the id for empty and separator-only cwd', async () => { + it('displayTitleOf falls back to the id for empty and separator-only cwd', async () => { const b = bench() await feedList(b, [{ id: 'no-base', cwd: '///' }, { id: 'empty-cwd', cwd: '' }]) const { byId } = b.svc.list.getSnapshot() - expect(byId[sid('no-base')]?.title).toBe('no-base') - expect(byId[sid('empty-cwd')]?.title).toBe('empty-cwd') + expect(byId[sid('no-base')]?.displayTitle).toBe('no-base') + expect(byId[sid('empty-cwd')]?.displayTitle).toBe('empty-cwd') + expect(byId[sid('no-base')]?.title).toBeUndefined() }) it('binding for an unknown session returns undefined without moving the watch', async () => { diff --git a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx index 540b76bda7..3f9aaf8bf1 100644 --- a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx +++ b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx @@ -54,7 +54,7 @@ export function ConversationRoot({ disabled={last} onClick={() => { actions.open(s.id) }} > - {s.title} + {s.displayTitle} </button> </span> ) diff --git a/packages/client/ui-conversation/tests/apply-inject.spec.tsx b/packages/client/ui-conversation/tests/apply-inject.spec.tsx index 2c0166c7de..b343cf1bca 100644 --- a/packages/client/ui-conversation/tests/apply-inject.spec.tsx +++ b/packages/client/ui-conversation/tests/apply-inject.spec.tsx @@ -50,7 +50,7 @@ async function bench() { const listStore = createSnapshotStore<SessionListState>({ ids: [ROOT], - byId: { [ROOT]: { id: ROOT, title: 'R', cwd: '/proj', running: false, updatedAt: 1 } }, + byId: { [ROOT]: { id: ROOT, title: 'R', displayTitle: 'R', cwd: '/proj', running: false, updatedAt: 1 } }, }) const snap = snapshotBase() const sessionFake = { @@ -208,7 +208,7 @@ describe('conversation slot inject surface', () => { // Ancestry and draft/active-view hooks execute inside a component tree. const HookProbe = () => { const injected2 = b.entryOf('conversation').options.inject(b.binding) as { - useAncestry: () => readonly { title: string }[] + useAncestry: () => readonly { displayTitle: string }[] useActiveView: () => string | undefined composer: { useDraft: () => string } } diff --git a/packages/client/ui-conversation/tests/chat-apply.spec.tsx b/packages/client/ui-conversation/tests/chat-apply.spec.tsx index e6ce83edc5..72d31560b9 100644 --- a/packages/client/ui-conversation/tests/chat-apply.spec.tsx +++ b/packages/client/ui-conversation/tests/chat-apply.spec.tsx @@ -26,8 +26,8 @@ async function bench() { const listStore = createSnapshotStore<SessionListState>({ ids: [ROOT, CHILD], byId: { - [ROOT]: { id: ROOT, title: 'R', running: false, updatedAt: 1 }, - [CHILD]: { id: CHILD, title: 'C', parentId: ROOT, running: false, updatedAt: 2 }, + [ROOT]: { id: ROOT, title: 'R', displayTitle: 'R', running: false, updatedAt: 1 }, + [CHILD]: { id: CHILD, title: 'C', displayTitle: 'C', parentId: ROOT, running: false, updatedAt: 2 }, }, }) const sessionsFake = { diff --git a/packages/client/ui-conversation/tests/chat-stats-bash-sample.spec.tsx b/packages/client/ui-conversation/tests/chat-stats-bash-sample.spec.tsx index 63b76c86df..3870e7eb09 100644 --- a/packages/client/ui-conversation/tests/chat-stats-bash-sample.spec.tsx +++ b/packages/client/ui-conversation/tests/chat-stats-bash-sample.spec.tsx @@ -155,8 +155,8 @@ describe('bash toolview samples', () => { getSnapshot: () => ({ ids: [root, child], byId: { - [root]: { id: root, title: 'r', running: false, updatedAt: 0 }, - [child]: { id: child, title: 'c', parentId: root, running: false, updatedAt: 0 }, + [root]: { id: root, title: 'r', displayTitle: 'r', running: false, updatedAt: 0 }, + [child]: { id: child, title: 'c', displayTitle: 'c', parentId: root, running: false, updatedAt: 0 }, }, }), }) diff --git a/packages/client/ui-conversation/tests/gate-branch-tails.spec.tsx b/packages/client/ui-conversation/tests/gate-branch-tails.spec.tsx index 3ff148f5d6..61aa499b5b 100644 --- a/packages/client/ui-conversation/tests/gate-branch-tails.spec.tsx +++ b/packages/client/ui-conversation/tests/gate-branch-tails.spec.tsx @@ -49,9 +49,9 @@ describe('apply need() and cwd cache', () => { const listStore = createSnapshotStore<SessionListState>({ ids: [SID, 'x2' as SessionId, 'x3' as SessionId], byId: { - [SID]: { id: SID, title: 'a', cwd: '/proj', running: false, updatedAt: 1 }, - ['x2' as SessionId]: { id: 'x2' as SessionId, title: 'b', cwd: '', running: false, updatedAt: 1 }, - ['x3' as SessionId]: { id: 'x3' as SessionId, title: 'c', running: false, updatedAt: 1 }, + [SID]: { id: SID, title: 'a', displayTitle: 'a', cwd: '/proj', running: false, updatedAt: 1 }, + ['x2' as SessionId]: { id: 'x2' as SessionId, title: 'b', displayTitle: 'b', cwd: '', running: false, updatedAt: 1 }, + ['x3' as SessionId]: { id: 'x3' as SessionId, title: 'c', displayTitle: 'c', running: false, updatedAt: 1 }, }, }) ctx.provide('sessions', { list: listStore, manager: { get: vi.fn() }, ancestry: () => [], scope: () => undefined, create: vi.fn() }) diff --git a/packages/client/ui-conversation/tests/selection-survival.spec.ts b/packages/client/ui-conversation/tests/selection-survival.spec.ts index f12cb63617..c1a5846d48 100644 --- a/packages/client/ui-conversation/tests/selection-survival.spec.ts +++ b/packages/client/ui-conversation/tests/selection-survival.spec.ts @@ -49,13 +49,14 @@ function feed(b: Bench, rows: { id: string; cwd?: string; running?: boolean }[]) } describe('selection survives list refreshes (M1a)', () => { - it('create → select → title-upgrading refresh keeps scope, binding, store and value', async () => { + it('create → select → display-title-upgrading refresh keeps scope, binding, store and value', async () => { const b = bench() // First-send shape: client-side create inserts the row without cwd (title = bare id). b.api.onCreate = () => Promise.resolve(ok({ sessionId: sid('s1') })) const id = await b.sessions.create({}) await flush() - expect(b.sessions.list.getSnapshot().byId[id]?.title).toBe('s1') + expect(b.sessions.list.getSnapshot().byId[id]).toMatchObject({ displayTitle: 's1' }) + expect(b.sessions.list.getSnapshot().byId[id]?.title).toBeUndefined() const binding = b.sessions.binding(id) expect(binding).toBeDefined() @@ -63,11 +64,12 @@ describe('selection survives list refreshes (M1a)', () => { const store = (scoped.get('conversation') as ConversationService).selection store.set({ turnSeq: 3, callId: 'c1' }) - // The late list refresh lands (host knows the cwd → formal title). + // The late list refresh lands (host knows the cwd → better fallback label). feed(b, [{ id: 's1', cwd: '/w/proj-a' }]) await b.sessions.manager.refreshList() await flush() - expect(b.sessions.list.getSnapshot().byId[id]?.title).toBe('proj-a') + expect(b.sessions.list.getSnapshot().byId[id]).toMatchObject({ displayTitle: 'proj-a' }) + expect(b.sessions.list.getSnapshot().byId[id]?.title).toBeUndefined() // Scope, binding and the selection account must all be identity-stable. expect(b.sessions.scope(id)).toBe(scoped) @@ -87,7 +89,7 @@ describe('selection survives list refreshes (M1a)', () => { const store = (scoped.get('conversation') as ConversationService).selection store.set({ turnSeq: 1, callId: 'c9' }) - // Reconnect generation: title upgrade arrives with the re-pull. + // Reconnect generation: display-title fallback upgrade arrives with the re-pull. feed(b, [{ id: 's1', cwd: '/w/proj-a', running: true }]) b.sessions.manager.handleConnected() await flush() diff --git a/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx b/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx index 25808e17c5..e7db208c17 100644 --- a/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx +++ b/packages/client/ui-conversation/tests/skeleton-branches.spec.tsx @@ -33,7 +33,7 @@ function sessionSource(over?: Partial<ConversationSnapshot>) { } const summary = (id: string, title: string): SessionSummary => - ({ id: id as SessionId, title, running: false, updatedAt: 1 }) + ({ id: id as SessionId, title: `durable ${title}`, displayTitle: title, running: false, updatedAt: 1 }) describe('ConversationRoot branches', () => { const chatEntry: ViewEntry = { diff --git a/packages/client/ui-conversation/tests/skeleton.spec.tsx b/packages/client/ui-conversation/tests/skeleton.spec.tsx index ab23a64389..d480744a0d 100644 --- a/packages/client/ui-conversation/tests/skeleton.spec.tsx +++ b/packages/client/ui-conversation/tests/skeleton.spec.tsx @@ -76,8 +76,8 @@ describe('ConversationRoot', () => { const send = vi.fn() const stop = vi.fn() const ancestry: SessionSummary[] = [ - { id: sid('root'), title: 'proj', running: false, updatedAt: 1 }, - { id: sid('s1'), title: 'child', running: false, updatedAt: 1, parentId: sid('root') }, + { id: sid('root'), title: 'proj', displayTitle: 'proj', running: false, updatedAt: 1 }, + { id: sid('s1'), title: 'child', displayTitle: 'child', running: false, updatedAt: 1, parentId: sid('root') }, ] const rendered: string[] = [] const ui = render( diff --git a/packages/client/ui-layout/tests/service.spec.ts b/packages/client/ui-layout/tests/service.spec.ts index 85d458cf7b..1e1d13b80c 100644 --- a/packages/client/ui-layout/tests/service.spec.ts +++ b/packages/client/ui-layout/tests/service.spec.ts @@ -20,7 +20,7 @@ function makeCtx() { /** Test-side brand: specs mint ids the wire would normally brand. */ const sid = (s: string): SessionId => s as SessionId -const summary = (id: SessionId) => ({ id, title: id as string, running: false, updatedAt: 1 }) +const summary = (id: SessionId) => ({ id, title: id as string, displayTitle: id as string, running: false, updatedAt: 1 }) beforeEach(() => { localStorage.clear() }) diff --git a/packages/client/ui-sidebar/src/client/tree.ts b/packages/client/ui-sidebar/src/client/tree.ts index 1858643d43..5b855005aa 100644 --- a/packages/client/ui-sidebar/src/client/tree.ts +++ b/packages/client/ui-sidebar/src/client/tree.ts @@ -153,7 +153,7 @@ function sessionRow(g: Group, s: SessionSummary, depth: number, hasChildren: boo type: 'session', id: s.id, groupKey: g.key, - title: s.title, + title: s.displayTitle, depth, hasChildren, expanded, @@ -182,7 +182,7 @@ function flattenVisible(g: Group, expandedSessions: ReadonlySet<string>, rows: S function searchVisible(g: Group, q: string): Set<SessionId> { const visible = new Set<SessionId>() for (const m of g.summaries.values()) { - if (!m.title.toLowerCase().includes(q)) continue + if (!m.displayTitle.toLowerCase().includes(q)) continue let cur: SessionSummary | undefined = m while (cur !== undefined && !visible.has(cur.id)) { visible.add(cur.id) @@ -212,9 +212,9 @@ function flattenSearch(g: Group, visible: ReadonlySet<SessionId>, rows: SidebarR * * Normal mode: every project row shows; sessions show under expanded * projects, descending only into expanded sessions. Search mode (non-blank - * query, case-insensitive title substring): expansion state is ignored — + * query, case-insensitive display-title substring): expansion state is ignored — * matched sessions and their ancestor chains are forced visible, groups - * without a title or label hit are dropped, and a label-only hit keeps the + * without a display-title or label hit are dropped, and a label-only hit keeps the * bare project row. * @param list - sessions list snapshot. * @param view - expansion sets and search query. diff --git a/packages/client/ui-sidebar/tests/apply.spec.tsx b/packages/client/ui-sidebar/tests/apply.spec.tsx index ea029c6709..9e57771a27 100644 --- a/packages/client/ui-sidebar/tests/apply.spec.tsx +++ b/packages/client/ui-sidebar/tests/apply.spec.tsx @@ -28,7 +28,7 @@ async function bench() { await ctx.plugin(SlotsService).await() const list = createSnapshotStore<SessionListState>({ ids: [sid('a')], - byId: { [sid('a')]: { id: sid('a'), title: 'alpha', cwd: '/proj', running: false, updatedAt: 1 } }, + byId: { [sid('a')]: { id: sid('a'), title: 'alpha', displayTitle: 'alpha', cwd: '/proj', running: false, updatedAt: 1 } }, }) const sessions = { list, create: vi.fn(async () => sid('minted')) } const layout = { @@ -132,7 +132,7 @@ describe('apply', () => { sessions.list.update((draft) => { draft.ids.push(sid('kid')) draft.byId[sid('kid')] = { - id: sid('kid'), title: 'child', cwd: '/proj', parentId: sid('a'), running: false, updatedAt: 2, + id: sid('kid'), title: 'child', displayTitle: 'child', cwd: '/proj', parentId: sid('a'), running: false, updatedAt: 2, } }) await ctx.plugin({ inject: [...inject], apply }).await() diff --git a/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx b/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx index db03c672dd..077cdc9c56 100644 --- a/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx +++ b/packages/client/ui-sidebar/tests/sidebar-root.spec.tsx @@ -31,6 +31,7 @@ function summary(init: SummaryInit): SessionSummary { const s: SessionSummary = { id: sid(init.id), title: init.title ?? init.id, + displayTitle: init.title ?? init.id, running: init.running ?? false, updatedAt: init.updatedAt ?? 0, } diff --git a/packages/client/ui-sidebar/tests/store.spec.ts b/packages/client/ui-sidebar/tests/store.spec.ts index d0bb3b386b..fbdb64c993 100644 --- a/packages/client/ui-sidebar/tests/store.spec.ts +++ b/packages/client/ui-sidebar/tests/store.spec.ts @@ -19,6 +19,7 @@ function summary(init: SummaryInit): SessionSummary { const s: SessionSummary = { id: sid(init.id), title: init.title ?? init.id, + displayTitle: init.title ?? init.id, running: init.running ?? false, updatedAt: init.updatedAt ?? 0, } diff --git a/packages/client/ui-sidebar/tests/tree.spec.ts b/packages/client/ui-sidebar/tests/tree.spec.ts index 1b29d460cf..ece5c769c6 100644 --- a/packages/client/ui-sidebar/tests/tree.spec.ts +++ b/packages/client/ui-sidebar/tests/tree.spec.ts @@ -11,6 +11,7 @@ const sid = (s: string) => s as SessionId interface SummaryInit { id: string title?: string + displayTitle?: string cwd?: string parentId?: string running?: boolean @@ -20,10 +21,11 @@ interface SummaryInit { function summary(init: SummaryInit): SessionSummary { const s: SessionSummary = { id: sid(init.id), - title: init.title ?? init.id, + displayTitle: init.displayTitle ?? init.title ?? init.id, running: init.running ?? false, updatedAt: init.updatedAt ?? 0, } + if (init.title !== undefined) s.title = init.title if (init.cwd !== undefined) s.cwd = init.cwd if (init.parentId !== undefined) s.parentId = sid(init.parentId) return s @@ -211,6 +213,15 @@ describe('deriveRows search', () => { const rows = deriveRows(list, view({ query: ' ' })) expect(rows.every(r => r.type === 'project')).toBe(true) }) + + it('matches the effective display title when no durable title is available', () => { + const fallback = listOf(summary({ id: 'raw-id', displayTitle: 'project fallback', cwd: '/elsewhere' })) + const rows = deriveRows(fallback, view({ query: 'fallback' })) + expect(rows).toEqual([ + expect.objectContaining({ type: 'project', key: '/elsewhere' }), + expect.objectContaining({ type: 'session', id: 'raw-id', title: 'project fallback' }), + ]) + }) }) describe('formatRelativeTime', () => { diff --git a/packages/client/ui-trajectory/tests/views.spec.tsx b/packages/client/ui-trajectory/tests/views.spec.tsx index 41a3c0c95b..a020431698 100644 --- a/packages/client/ui-trajectory/tests/views.spec.tsx +++ b/packages/client/ui-trajectory/tests/views.spec.tsx @@ -52,7 +52,7 @@ async function bench() { function mount(svc: ConversationService, nodes: ConversationSnapshot['nodes'] = NODES) { const { useSession } = fakeSession(nodes) const activeStore = createSnapshotStore<string | undefined>(undefined) - const ancestry: SessionSummary[] = [{ id: SID, title: 'self', running: false, updatedAt: 1 }] + const ancestry: SessionSummary[] = [{ id: SID, title: 'self', displayTitle: 'self', running: false, updatedAt: 1 }] const viewProps = { sessionId: SID, useSession, useSelection: () => null, diff --git a/packages/client/web/src/DocumentTitle.tsx b/packages/client/web/src/DocumentTitle.tsx new file mode 100644 index 0000000000..608f97497d --- /dev/null +++ b/packages/client/web/src/DocumentTitle.tsx @@ -0,0 +1,22 @@ +import { useEffect, useRef } from 'react' + +/** Props for the shell-owned browser title projection. */ +export interface DocumentTitleProps { + /** Durable title of the selected session, or undefined for the product title. */ + title?: string +} + +/** + * Project the selected durable session title into the browser title and + * restore the shell's original product title when unmounted. + * @param props - selected session title projection. + * @returns no rendered content. + */ +export function DocumentTitle({ title }: DocumentTitleProps): null { + const original = useRef(document.title) + useEffect(() => { + document.title = title === undefined ? original.current : `${title} — ${original.current}` + return () => { document.title = original.current } + }, [title]) + return null +} diff --git a/packages/client/web/src/app.tsx b/packages/client/web/src/app.tsx index e8c25acc3d..581cd4c98f 100644 --- a/packages/client/web/src/app.tsx +++ b/packages/client/web/src/app.tsx @@ -11,6 +11,7 @@ import { createSessionProvider, RootBindingProvider, scopedSlots, } from '@deepseek-ai/dsh-client-web-react' import type { SessionId, SessionsService } from '@deepseek-ai/dsh-client-runtime/client' +import { DocumentTitle } from './DocumentTitle.tsx' type LayoutExports = typeof import('@deepseek-ai/dsh-client-ui-layout/client') @@ -47,6 +48,11 @@ export function buildRenderApp(deps: AssemblyDeps): () => ReactNode { const useDetails = layout.details.useSelector const setSidebarWidth = (px: number): void => { layout.setSidebarWidth(px) } const setDetailsWidth = (px: number): void => { layout.setDetailsWidth(px) } + const SessionDocumentTitle = (): ReactNode => { + const id = useCurrent() + const title = sessions.list.useSelector(state => id === undefined ? undefined : state.byId[id]?.title) + return <DocumentTitle {...title === undefined ? {} : { title }} /> + } const renderBody = (id: SessionId): ReactNode => ( <> @@ -75,6 +81,7 @@ export function buildRenderApp(deps: AssemblyDeps): () => ReactNode { return () => ( <RootBindingProvider value={rootBinding}> + <SessionDocumentTitle /> <AppFrame useSidebar={useSidebar} useDetails={useDetails} diff --git a/packages/client/web/src/index.ts b/packages/client/web/src/index.ts index 4ea9ad46a7..6649ab3270 100644 --- a/packages/client/web/src/index.ts +++ b/packages/client/web/src/index.ts @@ -8,4 +8,5 @@ export { bootWebShell } from './boot.tsx' export { AppRoot, type AppRootProps } from './AppRoot.tsx' export { buildRenderApp, type AssemblyDeps } from './app.tsx' +export { DocumentTitle, type DocumentTitleProps } from './DocumentTitle.tsx' export { seedModules } from './seed.ts' diff --git a/packages/client/web/tests/boot.spec.tsx b/packages/client/web/tests/boot.spec.tsx index 8c05f0abb2..a9ce5db03d 100644 --- a/packages/client/web/tests/boot.spec.tsx +++ b/packages/client/web/tests/boot.spec.tsx @@ -38,7 +38,7 @@ window.DSHClientProxy.loadPlugin({ ctx, } ctx.provide('sessions', { - list: createSnapshotStore({ ids: ['s1'], byId: { s1: { id: 's1', title: 'S1', running: false, updatedAt: 1 } } }), + list: createSnapshotStore({ ids: ['s1'], byId: { s1: { id: 's1', title: 'S1', displayTitle: 'S1', running: false, updatedAt: 1 } } }), binding: (id) => (id === 's1' ? binding : undefined), }) }, @@ -119,6 +119,7 @@ afterEach(() => { delete win.__TEST_NAV__ document.body.innerHTML = '' document.head.querySelectorAll('script').forEach((s) => { s.remove() }) + document.title = '' }) describe('bootWebShell (real loader + real script execution)', () => { @@ -130,6 +131,7 @@ describe('bootWebShell (real loader + real script execution)', () => { ], } const el = mountPoint() + document.title = 'DeepSeek Harness' let unmount: (() => void) | undefined const s = seams({ '/plugins/fake-runtime.js': RUNTIME_STUB, @@ -145,9 +147,11 @@ describe('bootWebShell (real loader + real script execution)', () => { // Selected session: SessionProvider resolved the binding and renderBody // mounted the conversation slot content into the center column. expect(el.querySelector('[data-testid="conv-body"]')).not.toBeNull() + expect(document.title).toBe('S1 — DeepSeek Harness') act(() => { unmount!() }) expect(el.childElementCount).toBe(0) + expect(document.title).toBe('DeepSeek Harness') }) it('no selected session: renderEmpty keeps the grid and forwards width setters', async () => { @@ -159,6 +163,7 @@ describe('bootWebShell (real loader + real script execution)', () => { ], } const el = mountPoint() + document.title = 'DeepSeek Harness' const s = seams({ '/plugins/fake-runtime.js': RUNTIME_STUB, '/plugins/fake-layout.js': LAYOUT_STUB.replace("id: 'fake-layout'", `id: '${LAYOUT_ID}'`), @@ -169,6 +174,7 @@ describe('bootWebShell (real loader + real script execution)', () => { expect(frame).not.toBeNull() // Empty path: no conversation body (nothing registered into conversation.empty → fallback null). expect(el.querySelector('[data-testid="conv-body"]')).toBeNull() + expect(document.title).toBe('DeepSeek Harness') // Width setter/selector pass-through (assembly closures over ctx.layout). expect((frame as HTMLElement).dataset['widths']).toBe('300x360') act(() => { (frame as HTMLElement).click() }) diff --git a/packages/client/web/tests/document-title.spec.tsx b/packages/client/web/tests/document-title.spec.tsx new file mode 100644 index 0000000000..ed336a1ccc --- /dev/null +++ b/packages/client/web/tests/document-title.spec.tsx @@ -0,0 +1,28 @@ +// @vitest-environment jsdom +import { afterEach, describe, expect, it } from 'vitest' +import { cleanup, render } from '@testing-library/react' +import { DocumentTitle } from '../src/DocumentTitle.tsx' + +afterEach(() => { + cleanup() + document.title = '' +}) + +describe('DocumentTitle', () => { + it('preserves the product title without a durable title and restores it on unmount', () => { + document.title = 'DeepSeek Harness' + const mounted = render(<DocumentTitle />) + expect(document.title).toBe('DeepSeek Harness') + + mounted.rerender(<DocumentTitle title="First title" />) + expect(document.title).toBe('First title — DeepSeek Harness') + + mounted.rerender(<DocumentTitle title="Revised title" />) + expect(document.title).toBe('Revised title — DeepSeek Harness') + + mounted.rerender(<DocumentTitle />) + expect(document.title).toBe('DeepSeek Harness') + mounted.unmount() + expect(document.title).toBe('DeepSeek Harness') + }) +}) diff --git a/packages/host/apiproxy/src/api/events.schema.ts b/packages/host/apiproxy/src/api/events.schema.ts index a46cdfe09e..050063d5e9 100644 --- a/packages/host/apiproxy/src/api/events.schema.ts +++ b/packages/host/apiproxy/src/api/events.schema.ts @@ -25,6 +25,7 @@ export const askUserQuestionItemSchema = z.object({ export const muxFrameSchema = z.discriminatedUnion('type', [ z.object({ type: z.literal('session/event'), sessionId: sessionIdSchema, event: sessionEventSchema, view: toolEventViewSchema.optional() }), z.object({ type: z.literal('session/subscribed'), sessionId: sessionIdSchema, lastSeq: z.number().int() }), + z.object({ type: z.literal('session/title'), sessionId: sessionIdSchema, title: z.string().min(1), eventSeq: z.number().int().nonnegative(), updatedAt: z.number() }), z.object({ type: z.literal('approval/requested'), sessionId: sessionIdSchema, approvalId: approvalRequestIdSchema, toolName: z.string(), callId: z.string().optional(), reason: z.string().optional() }), z.object({ type: z.literal('approval/resolved'), sessionId: sessionIdSchema, approvalId: approvalRequestIdSchema, outcome: z.union([z.literal('allowed-once'), z.literal('rejected'), z.literal('cancelled'), z.literal('unavailable')]) }), z.object({ type: z.literal('question/requested'), sessionId: sessionIdSchema, questions: z.array(askUserQuestionItemSchema) }), diff --git a/packages/host/apiproxy/src/api/events.ts b/packages/host/apiproxy/src/api/events.ts index eac4f0e65c..c03877c31d 100644 --- a/packages/host/apiproxy/src/api/events.ts +++ b/packages/host/apiproxy/src/api/events.ts @@ -33,8 +33,9 @@ export type ToolEventView = export interface EventsApi { /** * All-session aggregated mux stream. On open, emits a subscribed control frame for every - * attached session and replays each session's still-pending approval/question requested - * frames (rpcId reused verbatim — the refresh-recovery baseline). + * attached session followed by its optional latest title snapshot, then replays each + * session's still-pending approval/question requested frames (rpcId reused verbatim — the + * refresh-recovery baseline). * since: resume seam, unimplemented in v1 (ignored if passed); reconnection = reopen the * stream + refetch history. */ @@ -54,6 +55,7 @@ export interface EventsApi { export type MuxFrame = | { type: 'session/event'; sessionId: SessionId; event: SessionEvent; view?: ToolEventView } | { type: 'session/subscribed'; sessionId: SessionId; lastSeq: number } + | { type: 'session/title'; sessionId: SessionId; title: string; eventSeq: number; updatedAt: number } | { type: 'approval/requested'; sessionId: SessionId; approvalId: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string } | { type: 'approval/resolved'; sessionId: SessionId; approvalId: ApprovalRequestId; outcome: ApprovalOutcome } | { type: 'question/requested'; sessionId: SessionId; questions: AskUserQuestionItem[] } diff --git a/packages/host/apiproxy/tests/rpc-schemas.spec.ts b/packages/host/apiproxy/tests/rpc-schemas.spec.ts index 764c9673b9..23cda690ec 100644 --- a/packages/host/apiproxy/tests/rpc-schemas.spec.ts +++ b/packages/host/apiproxy/tests/rpc-schemas.spec.ts @@ -123,6 +123,7 @@ describe('events frame schemas', () => { const frames = [ { type: 'session/event', sessionId: 's', event: { type: 't', seq: 0, time: 1, data: null } }, { type: 'session/subscribed', sessionId: 's', lastSeq: -1 }, + { type: 'session/title', sessionId: 's', title: 'Durable title', eventSeq: 2, updatedAt: 3 }, { type: 'approval/requested', sessionId: 's', approvalId: 'a', toolName: 'bash', callId: 'c', reason: 'r' }, { type: 'approval/resolved', sessionId: 's', approvalId: 'a', outcome: 'allowed-once' }, { type: 'question/requested', sessionId: 's', questions: [{ id: 'q', question: 'Q?', options: [{ label: 'L' }], multiSelect: true }] }, @@ -131,6 +132,13 @@ describe('events frame schemas', () => { ] for (const frame of frames) expect(muxFrameSchema.parse(frame)).toMatchObject({ type: frame.type }) expect(() => muxFrameSchema.parse({ type: 'unknown/frame' })).toThrow() + for (const invalid of [ + { type: 'session/title', sessionId: 's', title: '', eventSeq: 0, updatedAt: 1 }, + { type: 'session/title', sessionId: 's', title: 'x', eventSeq: -1, updatedAt: 1 }, + { type: 'session/title', sessionId: 's', title: 'x', eventSeq: 0.5, updatedAt: 1 }, + { type: 'session/title', sessionId: 's', title: 'x', eventSeq: 0, updatedAt: 'now' }, + { type: 'session/title', sessionId: 's', title: 'x', eventSeq: 0, updatedAt: Number.NaN }, + ]) expect(() => muxFrameSchema.parse(invalid)).toThrow() expect(askUserQuestionItemSchema.parse({ id: 'q', question: 'Q?' }).id).toBe('q') }) diff --git a/packages/host/runtime/package.json b/packages/host/runtime/package.json index ea32040012..62e19f6635 100644 --- a/packages/host/runtime/package.json +++ b/packages/host/runtime/package.json @@ -49,6 +49,7 @@ "@deepseek-ai/dsh-session": "workspace:^", "@deepseek-ai/dsh-session-persistence": "workspace:^", "@deepseek-ai/dsh-session-persistence-jsonl": "workspace:^", + "@deepseek-ai/dsh-session-title": "workspace:^", "@deepseek-ai/dsh-skill": "workspace:^", "@deepseek-ai/dsh-skill-local": "workspace:^", "@deepseek-ai/dsh-spill-local": "workspace:^", diff --git a/packages/host/runtime/src/api-proxy.ts b/packages/host/runtime/src/api-proxy.ts index 0621fbecb9..901e74dcf5 100644 --- a/packages/host/runtime/src/api-proxy.ts +++ b/packages/host/runtime/src/api-proxy.ts @@ -12,6 +12,7 @@ import type { Agent, AgentStatus } from '@deepseek-ai/dsh-agent' import type { ContentBlock, MessageSource } from '@deepseek-ai/dsh-llm' import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session' import type { SessionPersistence } from '@deepseek-ai/dsh-session-persistence' +import { foldSessionTitle } from '@deepseek-ai/dsh-session-title' import type { ApiProxy, HistoryEntry, HostFrame, MuxFrame, SessionSummary, ToolEventView } from '@deepseek-ai/dsh-host-apiproxy/api' import type { ClientResponse, RpcError, RpcReceipt, RpcRequest, RpcResponse } from '@deepseek-ai/dsh-host-apiproxy/api/rpc' import { RpcId } from '@deepseek-ai/dsh-host-apiproxy/api/rpc' @@ -104,6 +105,28 @@ function frame<F>(payload: F): RpcRequest<F> { return { rpcId: RpcId(randomUUID()), payload } } +type SessionTitleFrame = Extract<MuxFrame, { type: 'session/title' }> + +/** Project the latest durable title without exposing title-generation policy. */ +function titleFrame(session: Session): SessionTitleFrame | undefined { + const title = foldSessionTitle(session.events) + if (title === undefined) return undefined + return { + type: 'session/title', + sessionId: session.id, + title: title.title, + eventSeq: title.eventSeq, + updatedAt: title.updatedAt, + } +} + +/** Queue the subscription baseline followed by its optional title snapshot. */ +function subscribeSession(queue: FrameQueue<RpcRequest<MuxFrame>>, session: Session): void { + queue.push(frame({ type: 'session/subscribed', sessionId: session.id, lastSeq: session.seq - 1 })) + const title = titleFrame(session) + if (title !== undefined) queue.push(frame(title)) +} + /** SessionSummary projection for attached (in-memory) sessions. */ function summarize(session: Session, running: boolean): SessionSummary { return { @@ -362,7 +385,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro mux(_request, signal) { const queue = new FrameQueue<RpcRequest<MuxFrame>>() for (const session of ctx.sessions.list()) { - queue.push(frame({ type: 'session/subscribed', sessionId: session.id, lastSeq: session.seq - 1 })) + subscribeSession(queue, session) } // Per-session open-call table for result-view pairing. Bounded by the // per-turn call count: entries clear on turn/end; a table miss (stream @@ -385,9 +408,13 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro const view = viewFor(ctx, event, callId => openCalls.get(session.id)?.get(callId) ?? backscanArgs(session.events, callId)) queue.push(frame({ type: 'session/event', sessionId: session.id, event, ...view === undefined ? {} : { view } })) + if (event.type === 'session/title') { + // The accepted raw event is already in session.events, so the fold must find it. + queue.push(frame(titleFrame(session) as SessionTitleFrame)) + } }), ctx.on('session/created', (session: Session) => { - queue.push(frame({ type: 'session/subscribed', sessionId: session.id, lastSeq: session.seq - 1 })) + subscribeSession(queue, session) }), ctx.on('session/disposed', (session: Session) => { openCalls.delete(session.id) diff --git a/packages/host/runtime/tests/host-runtime.spec.ts b/packages/host/runtime/tests/host-runtime.spec.ts index f3a2dc9a82..81bc4fc009 100644 --- a/packages/host/runtime/tests/host-runtime.spec.ts +++ b/packages/host/runtime/tests/host-runtime.spec.ts @@ -65,6 +65,21 @@ function expectOk<T>(response: RpcResponse<T>): T { return response.result.value } +async function nextMux(iterator: AsyncIterator<RpcRequest<MuxFrame>>): Promise<RpcRequest<MuxFrame>> { + const next = await iterator.next() + if (next.done === true) throw new Error('mux ended before the expected frame') + return next.value +} + +/** Durably append a title event without mounting title-generation policy. */ +function appendTitle(ctx: Context, agent: Agent, title: string) { + return ctx.sessions.appendOutOfBand(agent.session, 'session/title', { + title, + messageSeqs: [1], + source: { kind: 'fallback' }, + }, { kind: 'session-title' }) +} + let host: RunningHost | undefined beforeEach(() => { @@ -203,11 +218,14 @@ describe('sessions.history', () => { const idle = waitForIdle(first.ctx, agent) agent.send([{ type: 'text', text: 'save me' }]) await idle + const titleEvent = await appendTitle(first.ctx, agent, 'Persisted title') await first.dispose() host = await startHost({ boot: { persistenceRoot, provider: 'scripted', model: 'test-model' } }) host.ctx.llm.registerAdapter(['scripted'], new ScriptedAdapter([])) expect(host.ctx.agents.get(sessionId)).toBeUndefined() + const abort = new AbortController() + const mux = host.api.events.mux(request({}), abort.signal)[Symbol.asyncIterator]() const [a, b] = await Promise.all([ host.api.sessions.history(request({ sessionId })), host.api.sessions.history(request({ sessionId })), @@ -218,6 +236,11 @@ describe('sessions.history', () => { } expect(host.ctx.agents.get(sessionId)).toBeDefined() expect(host.ctx.agents.list()).toHaveLength(1) + expect((await nextMux(mux)).payload).toMatchObject({ type: 'session/subscribed', sessionId }) + expect((await nextMux(mux)).payload).toEqual(expect.objectContaining({ + type: 'session/title', sessionId, title: 'Persisted title', eventSeq: titleEvent.seq, + })) + abort.abort() }) it('errors session-not-found when resume fails, deduplicating concurrent resumes', async () => { @@ -325,6 +348,43 @@ describe('events streams', () => { expect((await stream.next()).done).toBe(true) }) + it('mux: projects durable titles after open baselines and immediately after live raw events', async () => { + const running = await boot() + const { api, ctx } = running + const { sessionId } = expectOk(await api.sessions.create(request({}))) + const agent = ctx.agents.get(sessionId) as Agent + const initial = await appendTitle(ctx, agent, 'Initial title') + + const ac = new AbortController() + const stream = api.events.mux(request({}), ac.signal)[Symbol.asyncIterator]() + expect((await nextMux(stream)).payload).toMatchObject({ type: 'session/subscribed', sessionId }) + expect((await nextMux(stream)).payload).toEqual(expect.objectContaining({ + type: 'session/title', sessionId, title: 'Initial title', eventSeq: initial.seq, updatedAt: initial.time, + })) + + const revised = await appendTitle(ctx, agent, 'Revised title') + let raw: RpcRequest<MuxFrame> + do raw = await nextMux(stream) + while (!(raw.payload.type === 'session/event' && raw.payload.event.type === 'session/title')) + expect(raw.payload).toMatchObject({ type: 'session/event', sessionId, event: { seq: revised.seq } }) + expect((await nextMux(stream)).payload).toEqual(expect.objectContaining({ + type: 'session/title', sessionId, title: 'Revised title', eventSeq: revised.seq, updatedAt: revised.time, + })) + ac.abort() + }) + + it('mux: emits no title control for untitled subscriptions', async () => { + const { api } = await boot() + const first = expectOk(await api.sessions.create(request({}))).sessionId + const ac = new AbortController() + const stream = api.events.mux(request({}), ac.signal)[Symbol.asyncIterator]() + expect((await nextMux(stream)).payload).toMatchObject({ type: 'session/subscribed', sessionId: first }) + + const second = expectOk(await api.sessions.create(request({}))).sessionId + expect((await nextMux(stream)).payload).toMatchObject({ type: 'session/subscribed', sessionId: second }) + ac.abort() + }) + it('host: session lifecycle, status flips (disposed suppressed), and agent errors', async () => { const running = await boot([textResponse('x')]) const { api, ctx } = running diff --git a/packages/host/runtime/tsconfig.json b/packages/host/runtime/tsconfig.json index 9836e0b5fd..72789891fb 100644 --- a/packages/host/runtime/tsconfig.json +++ b/packages/host/runtime/tsconfig.json @@ -23,6 +23,9 @@ { "path": "../../core/session" }, + { + "path": "../../session-title/session-title" + }, { "path": "../../core/system-prompt" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 968891f28d..28ee8bfebd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2032,6 +2032,9 @@ importers: '@deepseek-ai/dsh-session-persistence-jsonl': specifier: workspace:^ version: link:../../session-persistence/session-persistence-jsonl + '@deepseek-ai/dsh-session-title': + specifier: workspace:^ + version: link:../../session-title/session-title '@deepseek-ai/dsh-skill': specifier: workspace:^ version: link:../../skill/skill diff --git a/vitest.snapshot.config.ts b/vitest.snapshot.config.ts index 142528e604..858a3fd9a1 100644 --- a/vitest.snapshot.config.ts +++ b/vitest.snapshot.config.ts @@ -41,6 +41,7 @@ export default defineConfig({ test: { setupFiles: ['./scripts/test-invariants.ts'], include: [ + 'apps/web/tests/**/*.snapshot.ts', 'examples/*/tests/**/*.snapshot.ts', 'packages/sdk/*/tests/**/*.snapshot.ts', 'packages/ui/tui/tests/**/*.snapshot.ts', From 2e91db9271f953c6dde8f0b18e31f0cce5eb79ad Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:44:16 +0800 Subject: [PATCH 103/368] docs(web): describe session title projection --- ...026-07-21-log-backed-session-titles.i18n.yaml | 4 ++-- .../2026-07-21-log-backed-session-titles.md | 3 ++- .../2026-07-21-log-backed-session-titles.zh.md | 3 ++- .../2026-07-20-gui-testing-system.i18n.yaml | 4 ++-- .../process/2026-07-20-gui-testing-system.md | 16 ++++++++-------- .../process/2026-07-20-gui-testing-system.zh.md | 16 ++++++++-------- packages/client/runtime/README.md | 5 ++++- packages/client/web/README.md | 2 ++ packages/host/apiproxy/README.md | 2 ++ 9 files changed, 32 insertions(+), 23 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.i18n.yaml b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.i18n.yaml index 32b0b3a218..17f4515c1d 100644 --- a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.i18n.yaml @@ -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 -2026-07-21-log-backed-session-titles.md: cd0d2a4bab9b6504c65e942c0e03bce79488364e -2026-07-21-log-backed-session-titles.zh.md: b90ac6c59677e6542733210b91de38ef1169c760 +2026-07-21-log-backed-session-titles.md: 494187a73c58fb2313d802825c3ec9f9994d6f2b +2026-07-21-log-backed-session-titles.zh.md: cae51cca920fad748cb1944d35cc1b80850eb6ee diff --git a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md index cd0d2a4bab..494187a73c 100644 --- a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md +++ b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.md @@ -40,7 +40,7 @@ Automatic provider failures are nonfatal warnings and retain the latest title. E A fork inherits seed title events unchanged, like the rest of its source log. The first-message provider does not automatically retitle a fork. The all-messages provider may append a child-owned revision after a later child prompt, using inherited and new eligible messages. -`ctx.sessionQuery.readTitle()` folds one live-preferred or persisted log without loading titles during `listSessions()`. ACP maps the event to `session_info_update` during both live streaming and load replay, using the event timestamp for `updatedAt`. The TUI uses the latest title as its header subtitle and sets the terminal window title to `<session title> — <configured product title>` after terminal-safe rendering. A synthetic title turn remains a completed durability boundary for the metadata write; consumers reporting agent completion use the core `findLastMessageTurnEnd()` fold so a later title, injection, or other plugin-owned turn cannot replace the preceding message-triggered outcome. +`ctx.sessionQuery.readTitle()` folds one live-preferred or persisted log without loading titles during `listSessions()`. ACP maps the event to `session_info_update` during both live streaming and load replay, using the event timestamp for `updatedAt`. The TUI uses the latest title as its header subtitle and sets the terminal window title to `<session title> — <configured product title>` after terminal-safe rendering. The Web host folds the same log state into a validated mux control frame after each attached-session subscription baseline and immediately after forwarding a live raw title event. The browser retains only newer title event seqs even when the control frame precedes list or session-instance creation; sidebar labels, search, breadcrumbs, and the browser title then react to the projected revision. `session.list` remains metadata-only, so a cold persisted session uses the cwd basename or id until opening or resuming it attaches the log. The browser title uses `<session title> — <existing HTML title>` only for a selected titled session and otherwise preserves the product title. A synthetic title turn remains a completed durability boundary for the metadata write; consumers reporting agent completion use the core `findLastMessageTurnEnd()` fold so a later title, injection, or other plugin-owned turn cannot replace the preceding message-triggered outcome. ## Alternatives considered @@ -54,6 +54,7 @@ A fork inherits seed title events unchanged, like the rest of its source log. Th ## Consequences - Titles survive JSONL and SQLite persistence, replay through ACP, and follow fork inheritance without a separate mutable record. +- Web title delivery stays incremental and log-backed without a title index or persisted-list scan; cold list rows improve after attach. - A fallback appears without an auxiliary call; deployments choose whether better titles justify model cost and whether later prompts should retitle a session. - Auxiliary request records and late accepted titles consume event seqs and may create balanced zero-step turns, so persistence exposes both attempted dispatches and accepted updates even though model history and KV-cache identity do not change. - One provider and monotonic per-session revisions make disposal, supersession, and stale-result rejection explicit, at the cost of leaving multi-strategy precedence to a composite provider. diff --git a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.zh.md b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.zh.md index b90ac6c596..cae51cca92 100644 --- a/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.zh.md +++ b/.agents/notes/implemented/feature/2026-07-21-log-backed-session-titles.zh.md @@ -40,7 +40,7 @@ Status: implemented 与源日志的其他部分相同,fork 会原样继承作为种子的标题事件。首消息提供方不会自动为 fork 重新生成标题。全部消息提供方可以在子会话出现后续提示词后追加一项归子会话所有的修订,并使用继承的合格消息和新增的合格消息。 -`ctx.sessionQuery.readTitle()` 会折叠一份实时优先或已持久化的日志,而不会在 `listSessions()` 期间加载标题。ACP(Agent Client Protocol)会在实时流式输出和加载回放期间把该事件映射到 `session_info_update`,并使用事件时间戳作为 `updatedAt`。TUI 使用最新标题作为其标题栏副标题,并在完成终端安全渲染后,将终端窗口标题设置为 `<session title> — <configured product title>`。合成标题轮次本身仍会完成,并作为元数据写入的持久性边界;报告 agent 完成情况的消费方使用核心的 `findLastMessageTurnEnd()` 折叠逻辑,因此后续的标题轮次、注入轮次或其他归插件所有的轮次无法取代此前由消息触发的结果。 +`ctx.sessionQuery.readTitle()` 会折叠一份实时优先或已持久化的日志,而不会在 `listSessions()` 期间加载标题。ACP(Agent Client Protocol)会在实时流式输出和加载回放期间把该事件映射到 `session_info_update`,并使用事件时间戳作为 `updatedAt`。TUI 使用最新标题作为其标题栏副标题,并在完成终端安全渲染后,将终端窗口标题设置为 `<session title> — <configured product title>`。Web host 会在每个已附加会话的订阅基线之后,以及转发实时原始标题事件后立即,将同一份日志状态折叠为经过校验的 mux 控制帧。即使控制帧先于列表或会话实例创建抵达,浏览器也只保留标题事件 seq 较新的版本;侧边栏标签、搜索、面包屑和浏览器标题会随投影后的修订更新。`session.list` 仍只包含元数据,因此尚未打开的持久化会话会继续以 cwd 基名或 id 作为回退,直至打开或恢复会话时附加其日志。浏览器仅在选中已有标题的会话时将标题设置为 `<session title> — <existing HTML title>`,否则保留产品标题。合成标题轮次本身仍会完成,并作为元数据写入的持久性边界;报告 agent 完成情况的消费方使用核心的 `findLastMessageTurnEnd()` 折叠逻辑,因此后续的标题轮次、注入轮次或其他归插件所有的轮次无法取代此前由消息触发的结果。 ## 考虑过的替代方案 @@ -54,6 +54,7 @@ Status: implemented ## 后果 - 标题可以在 JSONL 和 SQLite 持久化中存续,通过 ACP 回放,并遵循 fork 继承语义,而无需单独的可变记录。 +- Web 标题仍以增量方式从日志交付,无需标题索引或扫描持久化列表;冷启动列表项会在会话附加后改用标题。 - 回退标题无需辅助调用即可出现;部署方可以自行决定更优标题是否值得模型成本,以及后续提示词是否需要重新生成会话标题。 - 辅助请求记录和延迟接受的标题会占用事件 seq,并可能创建平衡的零步骤轮次,因此持久化会同时呈现尝试发起的调用与已接受的更新,尽管模型历史和 KV 缓存标识保持不变。 - 单个提供方和每会话单调递增的修订号让释放、取代和陈旧结果拒绝行为明确可见,但多策略优先级必须由复合提供方负责。 diff --git a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.i18n.yaml b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.i18n.yaml index 6b2f1de1e0..9c7fff8b8b 100644 --- a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.i18n.yaml @@ -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 -2026-07-20-gui-testing-system.md: db1b47566f5aa089ffcb10d130ecde1851b93112 -2026-07-20-gui-testing-system.zh.md: 691c6baf50c1025a09461effd28ac0f1650fb933 +2026-07-20-gui-testing-system.md: 28652f97d5c8d4968e2beef0ccffa7a39dcd7359 +2026-07-20-gui-testing-system.zh.md: e07d23ded9613251b71808d56e05365120d9c0a7 diff --git a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.md b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.md index db1b47566f..28652f97d5 100644 --- a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.md +++ b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.md @@ -19,24 +19,24 @@ Cut along the architecture's natural test seams into three tiers, bottom-up: | Tier | Under test | Key technique | File location | |---|---|---|---| | 1 Protocol isomorphism | `AbstractApiClient` + `toFetchHandler` (bidirectional data / rpcId / zod types / SSE streams / batching / timeouts) | **The full chain at the isomorphic point**: `InProcessApiClient(toFetchHandler(脚本化 impl))` skips the network but genuinely runs the wire serialization — zero browser, pure node env | `packages/host/apiproxy/tests/client-handler.spec.ts` | -| 2 Object-layer orchestration | `Session`/`SessionManager`/`ConnectionController` (state machines and timing: stitching / dedup / paging / optimistic draft clearing / pendingBuffers / reconnect / backoff) | **The "event sequence in → snapshot out" golden path**: programmable fakes + deferreds controlling timing + fake timers controlling backoff | `packages/client/web-runtime/tests/{session,manager,connection,…}.spec.ts` | -| 3 Browser smoke | Build artifacts × a real browser (the page boots, one conversation round-trips) | Bare playwright library (chromium headless, no @playwright/test framework), minimal pass-through; fixture level + real-host level (self-skips without a key) | `apps/web/tests/smoke-{fixture,real}.e2e.ts` | +| 2 Object-layer orchestration | `Session`/`SessionManager`/`ConnectionController` (state machines and timing: stitching / dedup / paging / optimistic draft clearing / pendingBuffers / reconnect / backoff) | **The "event sequence in → snapshot out" golden path**: programmable fakes + deferreds controlling timing + fake timers controlling backoff | `packages/client/{runtime,connection}/tests/` | +| 3 Assembled presentation | Built artifacts × the real client loader and plugin composition | App-owned semantic snapshots boot all eight built client plugins under jsdom for deterministic cross-plugin state changes; bare Playwright smoke separately proves the real browser/carrier boundary, with real-host cases self-skipping without a key | `apps/web/tests/*.snapshot.ts`, `apps/web/tests/smoke-{fixture,real}.e2e.ts` | -Inter-tier discipline: **each tier tests its own layer, upper tiers never re-test lower ones** — smoke only proves the wiring is alive (the fixture level asserts zero `/api` requests and zero pageerror), interaction detail belongs to the verify scripts (see the lane map), wire semantics to tier 1, data semantics to tier 2. Pure-function layers (lineage/partial/notifier/fold-adapter) are tested directly with zero fakes in the same package's tests/ alongside tier 2. +Inter-tier discipline: **each tier tests its own layer, upper tiers never re-test lower ones** — an app semantic snapshot pins only user-visible projection across the assembled plugin boundary, while Playwright smoke proves browser and carrier liveness; wire semantics belong to tier 1 and data semantics to tier 2. Pure-function layers (lineage/partial/notifier/fold-adapter) are tested directly with zero fakes in the same package's tests/ alongside tier 2. -- **Host side** (apiproxy/runtime/webserver): under the repo-wide `test:coverage` gate, per-file 100%. -- **Client side**: web-runtime **is already under the per-file 100% gate** (12 defensive unreachable arms carry reasoned `/* v8 ignore */` comments); the `vitest.config.ts` coverage.exclude is down to `packages/client/web-ui/src/**` (temporary — lifted progressively as component specs fill in after the component redo); tests still run, the exclusion only keeps web-ui src out of the thresholds. web-ui takes the **jsdom route (landed)**: jsdom + @testing-library/react entered root devDependencies (dev-only), first spec `web-ui/tests/utils.spec.tsx` (utils pure functions + component RTL render + hook uSES probe); the environment uses the per-file `// @vitest-environment jsdom` pragma, zero impact on the other node-env packages. -- The exclusion is an **explicitly annotated ruling**, not a silent waiver; the lift path = delete the exclude line + add a justified exclusion or the missing tests. +- **Host and client source** are under the repo-wide per-file 100% coverage gate except the narrow browser-grade exclusions annotated in `vitest.config.ts`; component suites use per-file jsdom pragmas and Testing Library without changing Node suites. +- **App-owned semantic snapshots** read built client bundles, execute them through the real loader, and drive only deterministic fixture hooks. They own stable visible state such as sidebar labels, breadcrumbs, and `document.title`, not CSS pixels or lower-layer state-machine details. ## Lane map | Scenario | Command | Content | When to run | |---|---|---|---| | Baseline | `pnpm run test:gui` | Tier 1+2 vitest (`packages/client packages/host`), seconds-fast, no browser, no server | Casually, after touching any GUI source | +| Semantic snapshot | `DSH_EXAMPLE_MODE=lib pnpm run test:snapshot` | Keyless assembled-application semantics plus the repo's transport-specific expected outputs | After a human-visible GUI change; before delivery | | Browser end-to-end | `pnpm run test:web` | Rebuilds the front-end dist first, then runs the tier-3 two-level smoke (fixture level + real-host level self-skip) | After touching the build surface/boot/carriage; before delivery | | Gate | `pnpm run test:coverage` | The repo-wide gate (host-side GUI packages included, client side excluded) | The PR window | -**Division of labor between the verify scripts and vitest**: verify owns browser black-box regression (sequential steps = a user-operation script, one shared browser session, streaming PASS/FAIL output for the agent to locate the break), vitest owns first-class data-layer semantic assertions (reference stability `toBe`, state-machine timing, wire shapes). The two lanes complement each other, neither absorbs the other — scripts do not migrate to vitest (tearing apart an ordered script is a net loss); promoting one means wrapping a spawn shell hooked into the e2e lane, never rewriting the script body. +**Division of labor between the browser scripts and vitest**: Playwright owns browser/carrier black-box regression and long sequential user journeys; ordinary vitest owns data-layer semantics such as reference stability, timing, and wire shapes; snapshot vitest owns stable app-level semantic output through the built composition. These lanes complement each other rather than duplicating assertions. ## Anti-regression discipline @@ -46,7 +46,7 @@ Inter-tier discipline: **each tier tests its own layer, upper tiers never re-tes ## Consequences -Each lane tests its own tier: touching any GUI source gets seconds-fast `test:gui` feedback, wire/object-layer semantics assert in milliseconds in node env, and the browser carries only wiring-liveness smoke. On the gate surface, the host side is fully under per-file 100%; on the client side web-runtime is under the gate while web-ui waits behind the explicitly annotated exclude. The accepted cost: the inter-tier discipline (upper tiers never re-test lower ones) is upheld by review rather than a machine gate, and web-ui's coverage gap persists until component specs fill in after the component redo. +Each lane tests its own tier: touching any GUI source gets seconds-fast `test:gui` feedback, wire/object-layer semantics assert in milliseconds in Node, built-composition snapshots pin deterministic user-visible projection, and the browser carries wiring and carrier acceptance. The accepted cost is that inter-tier discipline is upheld by review rather than a machine gate and every new app snapshot must avoid unstable layout or clock output. ## Alternatives considered diff --git a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.zh.md b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.zh.md index 691c6baf50..e07d23ded9 100644 --- a/.agents/notes/implemented/process/2026-07-20-gui-testing-system.zh.md +++ b/.agents/notes/implemented/process/2026-07-20-gui-testing-system.zh.md @@ -19,24 +19,24 @@ GUI 栈需要考虑多种应用形态,同应用形态内的不同运行环境 | 层 | 被测物 | 关键手段 | 文件落点 | |---|---|---|---| | 1 协议同构层 | `AbstractApiClient` + `toFetchHandler`(双向数据/rpcId/ZOD类型/SSE 流/合批/超时) | **同构点全链**:`InProcessApiClient(toFetchHandler(脚本化 impl))` 不过网络但真跑 wire 序列化——零浏览器、纯 node env | `packages/host/apiproxy/tests/client-handler.spec.ts` | -| 2 对象层编排 | `Session`/`SessionManager`/`ConnectionController`(状态机与时序:缝合/去重/翻页/乐观清稿/pendingBuffers/重连/退避) | **「事件序列进→快照出」黄金路径**:可编程假体 + deferred 控时序 + fake timers 控退避 | `packages/client/web-runtime/tests/{session,manager,connection,…}.spec.ts` | -| 3 浏览器 smoke | 构建产物 × 真浏览器(页面起得来、一轮对话跑得通) | playwright 裸库(chromium headless,无 @playwright/test 框架)最简跑通;fixture 级 + 真 host 级(无 key self-skip) | `apps/web/tests/smoke-{fixture,real}.e2e.ts` | +| 2 对象层编排 | `Session`/`SessionManager`/`ConnectionController`(状态机与时序:缝合/去重/翻页/乐观清稿/pendingBuffers/重连/退避) | **「事件序列进→快照出」黄金路径**:可编程假体 + deferred 控时序 + fake timers 控退避 | `packages/client/{runtime,connection}/tests/` | +| 3 组装呈现层 | 构建产物 × 真实 client loader 与插件组合 | 归应用所有的语义快照会在 jsdom 下启动全部 8 个已构建的 client 插件,以固定确定性的跨插件状态变化;独立使用 Playwright 裸库的冒烟测试负责验证真实浏览器/承载层边界,真 host 用例在无密钥时自行跳过 | `apps/web/tests/*.snapshot.ts`、`apps/web/tests/smoke-{fixture,real}.e2e.ts` | -层间纪律:**下层各测各的,上层不重测下层**——smoke 只证接线活着(fixture 级断零 `/api` 请求、零 pageerror),交互细节归 verify 脚本(见车道地图),wire 语义归 1 层,数据语义归 2 层。纯函数层(lineage/partial/notifier/fold-adapter)随 2 层同包 tests/ 零假体直测。 +层间纪律:**下层各测各的,上层不重测下层**:应用语义快照只固定组装后插件边界上的用户可见投影,Playwright 冒烟测试负责验证浏览器与承载层是否存活;wire 语义归 1 层,数据语义归 2 层。纯函数层(lineage/partial/notifier/fold-adapter)随 2 层同包 tests/ 零假体直测。 -- **host 侧**(apiproxy/runtime/webserver):进全仓 `test:coverage` 门禁,per-file 100%。 -- **client 侧**:web-runtime **已进 per-file 100% 门禁**(12 处防御性不可达臂带理由 `/* v8 ignore */` 注释);`vitest.config.ts` coverage.exclude 只剩 `packages/client/web-ui/src/**`(暂时——组件重做后随组件 specs 铺满逐步解除),测试照跑,只是不拉 web-ui src 进阈值。web-ui 走 **jsdom 路线(已落地)**:jsdom + @testing-library/react 入 root devDeps(dev-only),首个 spec `web-ui/tests/utils.spec.tsx`(utils 纯函数 + 组件 RTL render + hook uSES 探针);环境用 per-file `// @vitest-environment jsdom` pragma,node env 的其他包零影响。 -- 排除是**显式注释的裁决**不是静默豁免;解除路径=删 exclude 行 + 补 justified 排除或补测。 +- **host 与 client 源码**均纳入全仓 per-file 100% 覆盖率门禁,仅排除 `vitest.config.ts` 中带注释的少量浏览器级例外;组件套件通过逐文件 jsdom pragma 和 Testing Library 运行,不会改变 Node 套件。 +- **归应用所有的语义快照**读取已构建的 client bundle,通过真实 loader 执行它们,并且只驱动确定性的 fixture 钩子。它们负责固定侧边栏标签、面包屑和 `document.title` 等稳定可见状态,而不固定 CSS 像素或下层状态机细节。 ## 车道地图 | 场景 | 命令 | 内容 | 何时跑 | |---|---|---|---| | 基础 | `pnpm run test:gui` | 1+2 层 vitest(`packages/client packages/host`),秒级、无浏览器无 server | 改 GUI 任意源码后随手跑 | +| 语义快照 | `DSH_EXAMPLE_MODE=lib pnpm run test:snapshot` | 无需密钥的组装应用语义,以及仓库按传输形态划分的预期输出 | 用户可见的 GUI 变更后;交付前 | | 浏览器端到端 | `pnpm run test:web` | 先重建前端 dist,再跑 3 层双级 smoke(fixture 级 + 真 host 级 self-skip) | 改构建面/boot/承载后;交付前 | | 门禁 | `pnpm run test:coverage` | 全仓 gate(host 侧 GUI 包在内,client 侧 excluded) | PR 窗口 | -**verify 脚本与 vitest 的分工**:verify 管浏览器黑盒回归(顺序步骤=用户操作剧本,共享一次浏览器会话,PASS/FAIL 流式输出供 agent 定位断点),vitest 管数据层语义一等断言(引用稳定性 `toBe`、状态机时序、wire 形)。两车道互补不收编——脚本不迁 vitest(拆散有序剧本是负收益),转正时包一层 spawn 壳挂 e2e 车道即可,脚本本体不改写。 +**浏览器脚本与 vitest 的分工**:Playwright 负责浏览器/承载层黑盒回归和较长的连续用户操作流程;普通 vitest 负责引用稳定性、时序和 wire 结构等数据层语义;快照 vitest 通过构建后的组合负责稳定的应用层语义输出。这些车道彼此互补,而不重复断言。 ## 防回归纪律 @@ -46,7 +46,7 @@ GUI 栈需要考虑多种应用形态,同应用形态内的不同运行环境 ## Consequences -各车道各测各层:改任意 GUI 源码有秒级 `test:gui` 反馈,wire/对象层语义在 node env 毫秒级断言,浏览器只承担接线存活冒烟。门禁面上 host 侧全量进 per-file 100%;client 侧 web-runtime 已进门,web-ui 暂留显式注释的 exclude 之后。接受的代价:层间纪律(上层不重测下层)靠 review 而非机器门禁维持;web-ui 的覆盖缺口持续到组件重做后组件 specs 铺满为止。 +各车道各测各层:改动任意 GUI 源码后都能获得秒级 `test:gui` 反馈,wire/对象层语义在 Node 环境中进行毫秒级断言,基于构建后组合的快照固定确定性的用户可见投影,浏览器负责接线与承载层验收。接受的代价是层间纪律由评审而非机器门禁维持,而且每个新的应用快照都必须避开不稳定的布局或时钟输出。 ## Alternatives considered diff --git a/packages/client/runtime/README.md b/packages/client/runtime/README.md index 01c4172902..7c200ad202 100644 --- a/packages/client/runtime/README.md +++ b/packages/client/runtime/README.md @@ -2,6 +2,10 @@ Client cordis boot + core services: SlotsService (Service wrapper over SlotCore + 'slots/changed' bridge), SessionsService (list store projection, scope tree, bindings, ancestry), Session object layer, ClientLoader (`./loader` subpath, statically held by the shell). Contract: api-contracts v3 §4. +## Session title projection + +`SessionManager` retains the latest validated `session/title` control snapshot independently of list and session-instance arrival. Newer event seqs replace older snapshots, title timestamps contribute to list recency, and explicit session removal clears the retained title. The client-facing `SessionSummary.title` is therefore only the actual durable title; `displayTitle` is always present and falls back through the cwd basename and session id. A cold persisted session keeps that fallback until opening or resuming it causes the host to fold and project its log-backed title. + ## Model Experience None, as the client runtime hosts browser-side services and the session object layer; nothing here reaches a model request. @@ -15,4 +19,3 @@ None; this package neither assembles nor sends a provider request. - **`loader.unload` is a stub (throws not-implemented)** — the full chain (fiber dispose → registration cascade → style removal) lands with the HMR project. - **Scope teardown is watch-approximated** — the most recently resolved binding stands in for "who is watching"; a removed-while-watched session's scope survives until the watch moves away, not until true observer count reaches zero. - **Value imports of this package from plugin bundles must use the `/client` subpath** — the bare package name is not in the loader externals table and inlines a second module instance, whose private scope-tag Symbol never matches (the empty-state P0 postmortem). -- **`SessionSummary.title` is a display projection** — the wire summary carries no title yet; the cwd basename stands in, then the raw id. diff --git a/packages/client/web/README.md b/packages/client/web/README.md index 0501cb0384..c405aca3bc 100644 --- a/packages/client/web/README.md +++ b/packages/client/web/README.md @@ -4,6 +4,8 @@ Web shell library: `bootWebShell(el, seams?)` mounts the whole client — loader The optional `seams` parameter forwards the client loader's `fetchBundle`/`executeBundle` transport overrides (`BootSeams`); production callers omit it — it exists for test environments where `<script>` execution cannot reach the page context (jsdom). +The shell owns browser-title projection. With a selected session carrying a durable title, it renders `<session title> — <existing HTML title>` and reacts to later title revisions; no selection or a selected untitled session preserves the existing title, and shell unmount restores it. The existing HTML title remains the configurable product suffix. + ## Model Experience None, as the entry shell boots the browser plugin tree; nothing here reaches a model request. diff --git a/packages/host/apiproxy/README.md b/packages/host/apiproxy/README.md index 5ca6b9b8ca..1badfe65e8 100644 --- a/packages/host/apiproxy/README.md +++ b/packages/host/apiproxy/README.md @@ -8,6 +8,8 @@ Wire messages form a four-quadrant discriminated union — who initiates × requ The layering/protocol decisions are recorded in the [GUI layering and RPC protocol RFC](../../../.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md); the browser-side consumption architecture in the [web client architecture RFC](../../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md). +The mux stream projects the latest log-backed title as a validated `session/title` control frame after each attached-session subscription baseline and immediately after the corresponding live raw title event. This projection does not add titles to `session.list`; cold sessions remain metadata-only there until opening or resuming attaches their logs. + ## Carrier layer (`/client` + root) `AbstractApiClient` holds every protocol invariant — rpcId minting, envelope wrap/unwrap, zod parsing, SSE frame decoding, unary timeout, microtask-batched envelope observation (`subscribeEnvelopes`) — while platform subclasses supply only the `doFetch` transport aspect. `InProcessApiClient` over `toFetchHandler(api)` is the isomorphic point: the full wire serialization/validation path with no network, used by `dsh -p` headless. From 306681b53bf1d670e444bb71e3842c05fa2f6584 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:54:59 +0800 Subject: [PATCH 104/368] fix(pty): preserve startup cancellation and zombie cleanup --- .../2026-07-16-persistent-pty-sessions.i18n.yaml | 4 ++-- .../feature/2026-07-16-persistent-pty-sessions.md | 8 ++++---- .../2026-07-16-persistent-pty-sessions.zh.md | 8 ++++---- packages/pty/pty-local/README.md | 4 ++-- packages/pty/pty-local/src/process-inspector.ts | 11 ++++++++--- packages/pty/pty-local/src/session.ts | 3 +++ .../pty/pty-local/tests/process-inspector.spec.ts | 12 +++++++++--- packages/pty/pty-local/tests/session.spec.ts | 15 +++++++++++++++ 8 files changed, 47 insertions(+), 18 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index 627e46ace5..f7998a7615 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml @@ -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 -2026-07-16-persistent-pty-sessions.md: 8d279fea2e606894e4e8856a706113c0ea173e98 -2026-07-16-persistent-pty-sessions.zh.md: 9e81cad7357bc37856dc74ed5654744d70981a06 +2026-07-16-persistent-pty-sessions.md: afa6f1771931ed437d8c2c34204ad4a59d02248e +2026-07-16-persistent-pty-sessions.zh.md: 2af97c3d126f8639e6b52685fb7fea1292343c9b diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index 8d279fea2e..afa6f17719 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -72,7 +72,7 @@ With `run_in_background: true`, `dsh-tool-pty` registers the in-flight send on ` ### Local readiness detection -The local backend first recognizes a private OSC prompt marker emitted by its controlled bash startup, then requires printable prompt text after that marker before declaring prompt readiness and runs three bounded fallback tiers. Carrying that state across data callbacks covers macOS delivery where the OSC marker and `PS1` arrive separately; the marker alone can no longer publish an empty MOTD. The marker is removed before output reaches the model and avoids a fixed silence delay for ordinary shell commands on both platforms. Unpublished startup does not accept zero-output silence as readiness; timeout rejects the spawn. All timings are validated config fields: `pollIntervalMs`, `exactProbeAfterMs`, `idleSilenceMs`, and `timeoutMs`. +The local backend first recognizes a private OSC prompt marker emitted by its controlled bash startup, then requires printable prompt text after that marker before declaring prompt readiness and runs three bounded fallback tiers. Carrying that state across data callbacks covers macOS delivery where the OSC marker and `PS1` arrive separately; the marker alone can no longer publish an empty MOTD. The marker is removed before output reaches the model and avoids a fixed silence delay for ordinary shell commands on both platforms. Unpublished startup does not accept zero-output silence as readiness; timeout rejects the spawn. If caller cancellation wins during startup, the backend closes the private session and propagates the exact `AbortSignal.reason`; a foreground PGID that is not observable yet cannot replace cancellation with a lookup error. All timings are validated config fields: `pollIntervalMs`, `exactProbeAfterMs`, `idleSilenceMs`, and `timeoutMs`. On Linux, the inspector reads the shell's terminal foreground PGID from `/proc/<shellPid>/stat`, enumerates every process and thread in that process group, and probes their current syscalls. A positive Tier 1 result requires an observed stdin wait: direct `read(0)`, a permitted read of a `select`/`pselect6` or `poll`/`ppoll` argument containing fd 0, or an epoll interest list containing fd 0. Unreadable process memory and unrecognized syscalls are misses, never positive guesses. Architecture tables contain only syscall numbers defined by the corresponding Linux UAPI; unsupported architectures skip Tier 1. @@ -90,9 +90,9 @@ Background sends use the existing task completion notice and `task_output` resul ### Process-tree teardown -The top-level `node-pty` child is the ownership anchor. On close, the backend stops callbacks, snapshots its transitive descendants by parent PID in children-first order, sends `SIGTERM`, waits, rescans for children forked during shutdown, sends `SIGKILL` to the remaining descendant tree, and verifies that every descendant left the process table while the shell is still alive to reap it. Only then does it stop the shell with its own TERM/grace/KILL sequence. Every captured PID includes process-start identity so reuse cannot redirect escalation. +The top-level `node-pty` child is the ownership anchor. On close, the backend stops callbacks, snapshots its transitive descendants by parent PID in children-first order, sends `SIGTERM`, waits, rescans for children forked during shutdown, sends `SIGKILL` to the remaining descendant tree, and verifies that every non-zombie descendant left the process table while the shell is still alive. A matching Linux zombie has no executable work and therefore counts as quiescent, allowing shell shutdown to reap or reparent it. Only then does the backend stop the shell with its own TERM/grace/KILL sequence. Every captured PID includes process-start identity so reuse cannot redirect escalation. -Teardown reports root exit and survivor cleanup independently. It does not claim success merely because the shell exited; disposal resolves only after no captured tree member remains or returns a cleanup failure naming the survivors. A failed close is not cached forever: the registry and local session retain their closing fence but allow a later close to retry after the external survivor condition changes. Service disposal still clears its backend, reservation, and owner-detacher registries when a close fails. It never broadens ownership to every member of the root PID's POSIX session. +Teardown reports root exit and survivor cleanup independently. It does not claim success merely because the shell exited; disposal resolves only after no captured non-quiescent tree member remains or returns a cleanup failure naming the survivors. A failed close is not cached forever: the registry and local session retain their closing fence but allow a later close to retry after the external survivor condition changes. Service disposal still clears its backend, reservation, and owner-detacher registries when a close fails. It never broadens ownership to every member of the root PID's POSIX session. ### Composition and rollout @@ -153,7 +153,7 @@ The package ships concise tool guidance explaining persistent state, owner isola ## Verification - Per-file coverage pins owner fencing, concurrent reservations, sandbox-mode change rejection, retriable lifecycle cleanup, readiness tiers, sanitizer carry state, complete UTF-8 bounds, task integration, schemas, and exact render intents. -- Linux process fixtures cover non-leader and non-main-thread stdin waits, unreadable process state, supported syscall tables, unsupported architectures, and false-positive rejection; macOS inspector logic is injected into the same unit suite. +- Linux process fixtures cover non-leader and non-main-thread stdin waits, zombie quiescence, unreadable process state, supported syscall tables, unsupported architectures, and false-positive rejection; macOS inspector logic is injected into the same unit suite. - Real `node-pty` tests exercise shell state, shared sandbox policy, environment scrubbing, raw-mode foreground `SIGINT`, a TERM-ignoring descendant, and immediate post-disposal quiescence on supported hosts. - A Loader-driven `cordis.yml` test mounts the real three-package composition, while ACP and headless snapshots pin the six schemas, bounded results, error rendering, and terminal/generic cards through opt-in overlays. - Package contracts, the architecture map, core data structures, generated catalogs, and the website API describe the same shipped surface. diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index 9e81cad735..2af97c3d12 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -72,7 +72,7 @@ ACP 渲染契约精确且不携带位置信息。`terminal_send` 只为前台发 ### 本地就绪检测 -本地后端先识别受控 bash 启动时发出的私有 OSC prompt marker,并且只有在该 marker 后出现可打印的 prompt 文本时才据此声明 prompt 就绪;除此之外,它还运行 3 个有界 fallback 层级。在 data callback 之间保留这项状态,可以适配 macOS 分开交付 OSC marker 与 `PS1` 的情况;单独的 marker 不会发布空 MOTD。marker 在输出到达模型前被移除,使两个平台上的普通 shell 命令都无需固定等待静默阈值。尚未发布的 startup 不会把零输出静默视为就绪;timeout 会拒绝 spawn。所有时间参数都是经校验的配置字段:`pollIntervalMs`、`exactProbeAfterMs`、`idleSilenceMs` 和 `timeoutMs`。 +本地后端先识别受控 bash 启动时发出的私有 OSC prompt marker,并且只有在该 marker 后出现可打印的 prompt 文本时才据此声明 prompt 就绪;除此之外,它还运行 3 个有界 fallback 层级。在 data callback 之间保留这项状态,可以适配 macOS 分开交付 OSC marker 与 `PS1` 的情况;单独的 marker 不会发布空 MOTD。marker 在输出到达模型前被移除,使两个平台上的普通 shell 命令都无需固定等待静默阈值。尚未发布的 startup 不会把零输出静默视为就绪;timeout 会拒绝 spawn。若调用方取消在 startup 期间胜出,后端会关闭私有会话并原样抛出 `AbortSignal.reason`;尚不可观察的前台 PGID 不会再用查找错误覆盖取消原因。所有时间参数都是经校验的配置字段:`pollIntervalMs`、`exactProbeAfterMs`、`idleSilenceMs` 和 `timeoutMs`。 在 Linux 上,检查器从 `/proc/<shellPid>/stat` 读取 shell 的终端前台 PGID,枚举该进程组中的每个进程与线程,并检查它们当前的 syscall。Tier 1 只有观察到 stdin 等待才返回正结果:直接 `read(0)`、获准读取且含 fd 0 的 `select`/`pselect6` 或 `poll`/`ppoll` 参数,或者含 fd 0 的 epoll interest list。无法读取的进程内存和未识别的 syscall 都是 miss,绝不作为正向猜测。架构表只包含对应 Linux UAPI 定义的 syscall number;不支持的架构跳过 Tier 1。 @@ -90,9 +90,9 @@ Tier 2 在持续 `idleSilenceMs` 没有输出后返回 `inferred_idle`,因此 ### 进程树 teardown -顶层 `node-pty` 子进程是所有权锚点。关闭时,后端先停止 callback,再按父 PID 以子进程优先顺序捕获其传递子进程、发送 `SIGTERM` 并等待,然后重新扫描关停期间 fork 出的子进程,向剩余子孙进程树发送 `SIGKILL`,并在 shell 仍存活、可以回收这些进程时,验证每个子孙进程都已离开进程表。完成这些步骤后,后端才用 shell 自身的 TERM、宽限等待、KILL 序列停止 shell。每个捕获的 PID 都包含进程启动身份,避免 PID 复用把升级信号发给无关进程。 +顶层 `node-pty` 子进程是所有权锚点。关闭时,后端先停止 callback,再按父 PID 以子进程优先顺序捕获其传递子进程、发送 `SIGTERM` 并等待,然后重新扫描关停期间 fork 出的子进程,向剩余子孙进程树发送 `SIGKILL`,并在 shell 仍存活时验证每个非僵尸子孙进程都已离开进程表。身份匹配的 Linux 僵尸进程已无可执行工作,因此视为静止;shell 关闭时会回收它或将其重新挂接给负责回收的父进程。完成这些步骤后,后端才用 shell 自身的 TERM、宽限等待、KILL 序列停止 shell。每个捕获的 PID 都包含进程启动身份,避免 PID 复用把升级信号发给无关进程。 -teardown 独立报告根进程退出与存活进程清理。它不会只因 shell 退出就声称成功;dispose 只有在已捕获的进程树成员全部消失后才完成,否则返回清理失败并列出存活者。失败的 close 不会永久缓存:注册表与本地会话会保留关闭围栏,但在外部存活进程状态改变后允许后续 close 重试。即使某个 close 失败,服务 dispose 仍会清空其后端、预留与 owner detacher 注册表。所有权绝不会扩大到根 PID 所属 POSIX 会话的全部成员。 +teardown 独立报告根进程退出与存活进程清理。它不会只因 shell 退出就声称成功;dispose 只有在已捕获的进程树中不再存在非静止成员后才完成,否则返回清理失败并列出存活者。失败的 close 不会永久缓存:注册表与本地会话会保留关闭围栏,但在外部存活进程状态改变后允许后续 close 重试。即使某个 close 失败,服务 dispose 仍会清空其后端、预留与 owner detacher 注册表。所有权绝不会扩大到根 PID 所属 POSIX 会话的全部成员。 ### 组合与推行 @@ -153,7 +153,7 @@ plugins: ## 验证 - 每文件覆盖率固定 owner 隔离、并发预留、沙箱模式变更拒绝、可重试的生命周期清理、就绪层级、sanitizer carry state、完整 UTF-8 结果上限、task 集成、schema 和精确 render intent。 -- Linux 进程 fixture 覆盖非 leader 与非主线程的 stdin 等待、不可读进程状态、受支持的 syscall 表、不支持的架构和误报拒绝;同一单元测试套件通过注入覆盖 macOS 检查器逻辑。 +- Linux 进程 fixture 覆盖非 leader 与非主线程的 stdin 等待、僵尸进程静止性、不可读进程状态、受支持的 syscall 表、不支持的架构和误报拒绝;同一单元测试套件通过注入覆盖 macOS 检查器逻辑。 - 真实 `node-pty` 测试在受支持宿主上覆盖 shell 状态、共享沙箱策略、环境清洗、raw mode 下的前台 `SIGINT`、忽略 `SIGTERM` 的子进程,以及 dispose 返回后立即静默。 - Loader 驱动的 `cordis.yml` 测试挂载真实三包组合;ACP 与 headless 快照通过 opt-in overlay 固定 6 个 schema、有界结果、错误渲染和 terminal/generic card。 - 包契约、架构图、核心数据结构、生成目录和 website API 描述同一个已发布接口。 diff --git a/packages/pty/pty-local/README.md b/packages/pty/pty-local/README.md index 34e3beadec..dd83b61c07 100644 --- a/packages/pty/pty-local/README.md +++ b/packages/pty/pty-local/README.md @@ -6,9 +6,9 @@ Local `node-pty` backend for `ctx.pty`. It starts an interactive shell under the The plugin injects `pty`, `sandbox`, and `sandboxPolicy`, then registers the configured backend type (`shell`). `danger-full-access` starts the shell directly; confined modes wrap the exact shell argv through `ctx.sandbox`. The effective session mode is resolved at spawn. A change to a different effective mode is rejected before its `sandbox/mode` event commits while that owner has an open PTY or a spawn in progress; the fence is attached to the exact owner and therefore outlives a local-provider reload that retains existing sessions. Wait for creation to settle and close the sessions before changing modes, so a terminal opened with wider access cannot survive a downgrade. -Linux readiness combines a foreground-verified private bash prompt marker, foreground-process-group syscall inspection, silence fallback, and absolute timeout. macOS uses the verified prompt marker plus silence/timeout because it has no `/proc` syscall surface. A marker is not ready until printable prompt text arrives, including when the OSC marker and `PS1` are split across data callbacks. Unrecognized or unreadable process state is never a positive exact-idle signal. During unpublished startup, a fallback requires observed output; zero-output silence cannot publish an empty session, and timeout rejects the spawn. Incomplete terminal-control sequences are bounded by `maxReadBytes` and discarded through their terminator after crossing that limit; a trailing carriage return is carried across callbacks so split CRLF becomes one newline. +Linux readiness combines a foreground-verified private bash prompt marker, foreground-process-group syscall inspection, silence fallback, and absolute timeout. macOS uses the verified prompt marker plus silence/timeout because it has no `/proc` syscall surface. A marker is not ready until printable prompt text arrives, including when the OSC marker and `PS1` are split across data callbacks. Unrecognized or unreadable process state is never a positive exact-idle signal. During unpublished startup, a fallback requires observed output; zero-output silence cannot publish an empty session, and timeout rejects the spawn. Cancellation closes the unpublished shell and rejects with the caller's exact abort reason even when its foreground process group is not observable yet. Incomplete terminal-control sequences are bounded by `maxReadBytes` and discarded through their terminator after crossing that limit; a trailing carriage return is carried across callbacks so split CRLF becomes one newline. -Send cancellation resolves the current foreground process group and delivers a real `SIGINT`; it never emulates interruption by writing `\x03`, so raw-mode programs remain cancellable. Close sends `SIGTERM` to descendants, waits, then sends `SIGKILL` to the union of captured survivors and newly scanned descendants so reparenting cannot hide a process from teardown. It verifies that every retained identity left the process table while the shell can still reap it and only then stops the shell. A survivor failure does not cache a permanently rejected close; a later close retries the teardown. +Send cancellation resolves the current foreground process group and delivers a real `SIGINT`; it never emulates interruption by writing `\x03`, so raw-mode programs remain cancellable. Close sends `SIGTERM` to descendants, waits, then sends `SIGKILL` to the union of captured survivors and newly scanned descendants so reparenting cannot hide a process from teardown. It verifies that every retained identity is gone or, on Linux, a non-executing zombie before stopping the shell; zombie entries are quiescent and are reaped as the shell exits. A survivor failure does not cache a permanently rejected close; a later close retries the teardown. ## Model Experience diff --git a/packages/pty/pty-local/src/process-inspector.ts b/packages/pty/pty-local/src/process-inspector.ts index 1115f6613d..5be25a224a 100644 --- a/packages/pty/pty-local/src/process-inspector.ts +++ b/packages/pty/pty-local/src/process-inspector.ts @@ -16,6 +16,7 @@ export interface ProcessInspector { isStdinWaiting(pgid: number): boolean /** Return the root and its current transitive descendants, children first. */ processTree(rootPid: number): ProcessIdentity[] + /** Return whether the exact identity remains a non-quiescent process. */ isAlive(identity: ProcessIdentity): boolean signalGroup(pgid: number, signal: PtySignal): void signalProcess(identity: ProcessIdentity, signal: 'SIGTERM' | 'SIGKILL'): void @@ -49,6 +50,7 @@ interface ProcStat { parentPid: number pgrp: number session: number + state: string tpgid: number started: string } @@ -64,13 +66,15 @@ export function parseProcStat(text: string): ProcStat | undefined { if (open <= 0 || close <= open) return undefined const pid = Number(text.slice(0, open).trim()) const rest = text.slice(close + 2).trim().split(/\s+/) + const state = rest[0] || '' const parentPid = Number(rest[1]) const pgrp = Number(rest[2]) const session = Number(rest[3]) const tpgid = Number(rest[5]) const started = rest[19] - if (![pid, parentPid, pgrp, session, tpgid].every(Number.isSafeInteger) || started === undefined) return undefined - return { pid, parentPid, pgrp, session, tpgid, started } + if (![pid, parentPid, pgrp, session, tpgid].every(Number.isSafeInteger) + || state.length !== 1 || started === undefined) return undefined + return { pid, parentPid, pgrp, session, state, tpgid, started } } function readLinuxStat(internals: ProcessInspectorInternals, pid: number): ProcStat | undefined { @@ -269,7 +273,8 @@ class LinuxProcessInspector extends PosixProcessInspector { } isAlive(identity: ProcessIdentity): boolean { - return readLinuxStat(this.internals, identity.pid)?.started === identity.started + const stat = readLinuxStat(this.internals, identity.pid) + return stat?.started === identity.started && !/^[ZXx]$/.test(stat.state) } } diff --git a/packages/pty/pty-local/src/session.ts b/packages/pty/pty-local/src/session.ts index 99bf142174..20cd013dcf 100644 --- a/packages/pty/pty-local/src/session.ts +++ b/packages/pty/pty-local/src/session.ts @@ -186,6 +186,9 @@ export class LocalPtySession implements PtyBackendSession { if (result.waitReason === 'session_exit') throw new Error('PTY shell exited during startup') if (result.waitReason === 'timeout') throw new Error('PTY shell did not reach readiness before startup timeout') this.motd = result.viewport + } catch (error: unknown) { + signal?.throwIfAborted() + throw error } finally { this.initializing = false } diff --git a/packages/pty/pty-local/tests/process-inspector.spec.ts b/packages/pty/pty-local/tests/process-inspector.spec.ts index 5ddefd34b3..218a3d77fe 100644 --- a/packages/pty/pty-local/tests/process-inspector.spec.ts +++ b/packages/pty/pty-local/tests/process-inspector.spec.ts @@ -2,8 +2,8 @@ import { describe, expect, it } from 'vitest' import { createProcessInspector, parseProcStat } from '@deepseek-ai/dsh-pty-local/src/process-inspector.ts' import type { ProcessInspectorInternals } from '@deepseek-ai/dsh-pty-local/src/process-inspector.ts' -function stat(pid: number, pgrp: number, session: number, tpgid: number, started: string, parentPid = 1): string { - const rest = ['S', String(parentPid), String(pgrp), String(session), '99', String(tpgid)] +function stat(pid: number, pgrp: number, session: number, tpgid: number, started: string, parentPid = 1, state = 'S'): string { + const rest = [state, String(parentPid), String(pgrp), String(session), '99', String(tpgid)] while (rest.length < 19) rest.push('0') rest.push(started) return `${pid} (command with space) ${rest.join(' ')}` @@ -65,8 +65,10 @@ function fakeInternals() { describe('Linux process inspector', () => { it('parses stat safely, captures only the rooted process tree, and signals identities', () => { expect(parseProcStat('bad')).toBeUndefined() + expect(parseProcStat('1 () ')).toBeUndefined() expect(parseProcStat('1 () S')).toBeUndefined() - expect(parseProcStat(stat(10, 20, 30, 40, '500'))).toEqual({ pid: 10, parentPid: 1, pgrp: 20, session: 30, tpgid: 40, started: '500' }) + expect(parseProcStat(stat(10, 20, 30, 40, '500', 1, 'SS'))).toBeUndefined() + expect(parseProcStat(stat(10, 20, 30, 40, '500'))).toEqual({ pid: 10, parentPid: 1, pgrp: 20, session: 30, state: 'S', tpgid: 40, started: '500' }) const fake = fakeInternals() fake.dirs.set('/proc', ['x', '10', '11', '12', '13', '14']) @@ -90,6 +92,10 @@ describe('Linux process inspector', () => { inspector.signalProcess({ pid: 10, started: '500' }, 'SIGTERM') inspector.signalProcess({ pid: 10, started: 'old' }, 'SIGKILL') expect(fake.kills).toEqual([[-40, 'SIGINT'], [10, 'SIGTERM']]) + fake.files.set('/proc/10/stat', stat(10, 20, 30, 40, '500', 1, 'Z')) + expect(inspector.isAlive({ pid: 10, started: '500' })).toBe(false) + inspector.signalProcess({ pid: 10, started: '500' }, 'SIGKILL') + expect(fake.kills).toEqual([[-40, 'SIGINT'], [10, 'SIGTERM']]) }) it('detects read, select, poll, and epoll waits across non-leader threads', () => { diff --git a/packages/pty/pty-local/tests/session.spec.ts b/packages/pty/pty-local/tests/session.spec.ts index b3a536696d..6f7144f409 100644 --- a/packages/pty/pty-local/tests/session.spec.ts +++ b/packages/pty/pty-local/tests/session.spec.ts @@ -254,6 +254,21 @@ describe('LocalPtySession readiness and output', () => { await timedOut }) + it('preserves the caller abort reason when startup cannot resolve a foreground group', async () => { + const terminal = new FakeTerminal() + const inspector = new FakeInspector() + inspector.pgid = undefined + const session = new LocalPtySession(terminal.asPty(), inspector, config()) + const controller = new AbortController() + const reason = new Error('startup cancelled') + + const initializing = session.initialize(controller.signal) + const rejected = expect(initializing).rejects.toBe(reason) + controller.abort(reason) + + await rejected + }) + it('waits for printable prompt text when the startup marker is split from PS1', async () => { vi.useFakeTimers() const terminal = new FakeTerminal() From 25d0ef5c6c1a6570ae8eddb6141bc616da2397a2 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:58:39 +0800 Subject: [PATCH 105/368] test(code-mode): cover terminal output types --- packages/pty/tool-pty/tests/tools.spec.ts | 86 ++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/packages/pty/tool-pty/tests/tools.spec.ts b/packages/pty/tool-pty/tests/tools.spec.ts index b054a7be90..34bc29d14c 100644 --- a/packages/pty/tool-pty/tests/tools.spec.ts +++ b/packages/pty/tool-pty/tests/tools.spec.ts @@ -5,7 +5,8 @@ import { Session, SessionId } from '@deepseek-ai/dsh-session' import AgentRegistry from '@deepseek-ai/dsh-agent' import type { Agent } from '@deepseek-ai/dsh-agent' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' -import ToolRegistry from '@deepseek-ai/dsh-tools' +import ToolRegistry, { renderToolsSdk } from '@deepseek-ai/dsh-tools' +import type { ToolSdkSchema } from '@deepseek-ai/dsh-tools/src/ts-types.ts' import PtyService, { PtySessionId } from '@deepseek-ai/dsh-pty' import type { PtyBackend, PtyBackendSession, PtySendOperation, PtySendRequest, PtySessionStatus, PtySignal } from '@deepseek-ai/dsh-pty' import TaskService from '@deepseek-ai/dsh-tasks' @@ -104,6 +105,7 @@ async function setup(tasks: boolean) { } let callNumber = 0 +const TOOL_NAMES = ['terminal_open', 'terminal_send', 'terminal_read', 'terminal_signal', 'terminal_close', 'terminal_list'] as const const testToolSignal = new AbortController().signal function call(ctx: Context, name: string, args: unknown, agent?: Agent) { return ctx.tools.execute({ signal: testToolSignal, callId: CallId(`pty-call-${++callNumber}`), name, arguments: args, ...agent ? { agent } : {} }) @@ -120,7 +122,7 @@ function text(result: { content: { type: string; text?: string }[] }): string { describe('tool-pty foreground surface', () => { it('registers exactly six schemas and drives the full owner-scoped lifecycle', async () => { const { ctx, agent } = await setup(false) - expect(['terminal_open', 'terminal_send', 'terminal_read', 'terminal_signal', 'terminal_close', 'terminal_list'].every(name => ctx.tools.get(name) !== undefined)).toBe(true) + expect(TOOL_NAMES.every(name => ctx.tools.get(name) !== undefined)).toBe(true) const spawned = await call(ctx, 'terminal_open', { type: 'stub', name: 'main' }, agent) expect(text(spawned)).toContain('started terminal session pty-1 (main)') @@ -170,6 +172,86 @@ describe('tool-pty foreground surface', () => { expect(empty).toMatchObject({ isError: false, value: [] }) }) + it('projects every terminal DTO into the generated Code Mode output map', async () => { + const { ctx } = await setup(false) + const schemas = TOOL_NAMES.map((toolName): ToolSdkSchema => { + const definition = ctx.tools.get(toolName) + if (definition === undefined) throw new Error(`missing terminal tool ${toolName}`) + return { + name: definition.name, + description: definition.description, + parameters: definition.parameters, + output: definition.output.schema, + } + }) + const sdk = renderToolsSdk(schemas) + const outputMapStart = sdk.indexOf('interface ToolOutputMap') + const outputMapEnd = sdk.indexOf('\n\ntype ToolName', outputMapStart) + + expect(sdk.slice(outputMapStart, outputMapEnd)).toMatchInlineSnapshot(` + "interface ToolOutputMap { + terminal_close: { + sessionId: string; + outcome: "closed" | "already-closing"; + }; + terminal_list: ({ + sessionId: string; + name?: string; + type: string; + pid?: number; + status: { + kind: "running"; + } | { + kind: "exited"; + exitCode: number | null; + signal: string | null; + }; + })[]; + terminal_open: { + sessionId: string; + name?: string; + type: string; + pid?: number; + status: { + kind: "running"; + } | { + kind: "exited"; + exitCode: number | null; + signal: string | null; + }; + motd: string; + }; + terminal_read: { + text: string; + totalLines: number; + lineBegin: number; + lineEnd: number; + truncated: boolean; + }; + terminal_send: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + viewport: string; + waitReason: "stdin_read" | "inferred_idle" | "timeout" | "session_exit"; + sessionStatus: { + kind: "running"; + } | { + kind: "exited"; + exitCode: number | null; + signal: string | null; + }; + truncated: boolean; + }; + terminal_signal: { + delivered: true; + targetPgid: number; + }; + }" + `) + }) + it('fails without an initiating agent and rejects background before writing', async () => { const { ctx, agent, stub } = await setup(false) expect((await call(ctx, 'terminal_open', { type: 'stub' })).isError).toBe(true) From 744d65d63c4f39853b9c29071758d4a1e912b32a Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:10:53 +0800 Subject: [PATCH 106/368] docs(i18n): refresh Agent Note translations after merge --- ...6-06-11-content-block-vocabulary.i18n.yaml | 4 +- .../2026-06-11-content-block-vocabulary.zh.md | 10 +- .../2026-06-11-custom-schema-dsl.i18n.yaml | 4 +- .../2026-06-11-custom-schema-dsl.zh.md | 2 +- ...ev-invariants-over-deep-readonly.i18n.yaml | 4 +- ...11-dev-invariants-over-deep-readonly.zh.md | 12 +- ...026-06-11-event-sourced-sessions.i18n.yaml | 4 +- .../2026-06-11-event-sourced-sessions.zh.md | 2 +- ...06-11-microkernel-event-taxonomy.i18n.yaml | 4 +- ...026-06-11-microkernel-event-taxonomy.zh.md | 8 +- ...026-06-11-runtime-arg-validation.i18n.yaml | 4 +- .../2026-06-11-runtime-arg-validation.zh.md | 4 +- ...-06-11-structured-error-taxonomy.i18n.yaml | 4 +- ...2026-06-11-structured-error-taxonomy.zh.md | 8 +- ...-tool-schemas-in-prompt-assembly.i18n.yaml | 4 +- ...6-11-tool-schemas-in-prompt-assembly.zh.md | 2 +- .../2026-06-13-capability-seams.i18n.yaml | 4 +- .../2026-06-13-capability-seams.zh.md | 12 +- .../2026-06-13-twin-llm-adapters.i18n.yaml | 4 +- .../2026-06-13-twin-llm-adapters.zh.md | 4 +- .../2026-06-14-session-persistence.i18n.yaml | 4 +- .../2026-06-14-session-persistence.zh.md | 14 +- ...6-06-15-turn-enclosure-invariant.i18n.yaml | 4 +- .../2026-06-15-turn-enclosure-invariant.zh.md | 6 +- ...06-17-filesystem-capability-seam.i18n.yaml | 4 +- ...026-06-17-filesystem-capability-seam.zh.md | 18 +-- ...nt-lifecycle-and-ownership-seams.i18n.yaml | 4 +- ...-18-agent-lifecycle-and-ownership-seams.md | 2 + ...-agent-lifecycle-and-ownership-seams.zh.md | 26 ++-- .../2026-06-18-session-surface.i18n.yaml | 4 +- .../2026-06-18-session-surface.md | 2 + .../2026-06-18-session-surface.zh.md | 24 ++-- ...ed-persistence-write-coordinator.i18n.yaml | 4 +- ...shared-persistence-write-coordinator.zh.md | 12 +- .../2026-06-20-branded-ids.i18n.yaml | 4 +- .../architecture/2026-06-20-branded-ids.md | 2 + .../architecture/2026-06-20-branded-ids.zh.md | 34 ++--- ...-20-extract-example-app-packages.i18n.yaml | 4 +- ...6-06-20-extract-example-app-packages.zh.md | 22 +-- ...eneric-long-running-tool-runtime.i18n.yaml | 4 +- ...06-20-generic-long-running-tool-runtime.md | 2 + ...20-generic-long-running-tool-runtime.zh.md | 135 ++++++++++++++---- .../2026-06-20-package-hierarchy.i18n.yaml | 4 +- .../2026-06-20-package-hierarchy.md | 2 + .../2026-06-20-package-hierarchy.zh.md | 4 +- ...andatory-app-attribution-headers.i18n.yaml | 4 +- ...21-mandatory-app-attribution-headers.zh.md | 20 +-- .../2026-06-24-web-capability-seam.i18n.yaml | 4 +- .../2026-06-24-web-capability-seam.md | 8 +- .../2026-06-24-web-capability-seam.zh.md | 16 ++- ...06-26-file-context-as-event-gate.i18n.yaml | 4 +- ...026-06-26-file-context-as-event-gate.zh.md | 30 ++-- ...stdin-env-trusted-plugin-surface.i18n.yaml | 4 +- ...ash-stdin-env-trusted-plugin-surface.zh.md | 12 +- ...026-06-30-event-domain-semantics.i18n.yaml | 4 +- .../2026-06-30-event-domain-semantics.zh.md | 10 +- .../2026-07-02-fs-per-session-cwd.i18n.yaml | 4 +- .../2026-07-02-fs-per-session-cwd.md | 2 + .../2026-07-02-fs-per-session-cwd.zh.md | 15 +- ...2-result-time-applied-hunk-diffs.i18n.yaml | 4 +- ...07-02-result-time-applied-hunk-diffs.zh.md | 8 +- ...6-07-02-tool-render-intent-union.i18n.yaml | 4 +- .../2026-07-02-tool-render-intent-union.zh.md | 10 +- ...ilesystem-directory-listing-seam.i18n.yaml | 4 +- ...03-filesystem-directory-listing-seam.zh.md | 2 +- ...bles-and-tool-guidance-ownership.i18n.yaml | 4 +- ...ariables-and-tool-guidance-ownership.zh.md | 24 ++-- ...6-07-05-reconstructable-requests.i18n.yaml | 4 +- .../2026-07-05-reconstructable-requests.zh.md | 29 ++-- ...bagent-provider-lifecycle-events.i18n.yaml | 4 +- ...5-subagent-provider-lifecycle-events.zh.md | 12 +- ...6-07-06-timeout-deadline-library.i18n.yaml | 4 +- .../2026-07-06-timeout-deadline-library.zh.md | 27 +++- ...6-07-07-tool-call-timeout-policy.i18n.yaml | 4 +- .../2026-07-07-tool-call-timeout-policy.zh.md | 18 +-- .../2026-07-08-agent-scope-contexts.i18n.yaml | 4 +- .../2026-07-08-agent-scope-contexts.zh.md | 11 +- ...07-12-agent-scope-runtime-design.i18n.yaml | 4 +- ...026-07-12-agent-scope-runtime-design.zh.md | 24 ++-- ...-06-14-acp-agent-client-protocol.i18n.yaml | 4 +- ...2026-06-14-acp-agent-client-protocol.zh.md | 4 +- .../2026-06-14-acp-multi-session.i18n.yaml | 4 +- .../2026-06-14-acp-multi-session.zh.md | 14 +- .../feature/2026-06-15-code-mode.i18n.yaml | 4 +- .../feature/2026-06-15-code-mode.zh.md | 30 ++-- ...26-06-17-filesystem-tool-schemas.i18n.yaml | 4 +- .../2026-06-17-filesystem-tool-schemas.zh.md | 10 +- ...-acp-terminal-and-tool-rendering.i18n.yaml | 4 +- ...6-18-acp-terminal-and-tool-rendering.zh.md | 6 +- ...06-18-compaction-capability-seam.i18n.yaml | 4 +- .../2026-06-18-compaction-capability-seam.md | 2 + ...026-06-18-compaction-capability-seam.zh.md | 80 ++++++----- ...6-06-21-subagent-capability-seam.i18n.yaml | 4 +- .../2026-06-21-subagent-capability-seam.md | 2 + .../2026-06-21-subagent-capability-seam.zh.md | 17 ++- .../2026-06-22-acp-subagent-backend.i18n.yaml | 4 +- .../2026-06-22-acp-subagent-backend.zh.md | 15 +- .../2026-06-25-ask-user-question.i18n.yaml | 4 +- .../2026-06-25-ask-user-question.zh.md | 10 +- .../2026-06-29-todo-write-tool.i18n.yaml | 4 +- .../feature/2026-06-29-todo-write-tool.zh.md | 6 +- .../feature/2026-06-30-hook-bridges.i18n.yaml | 4 +- .../feature/2026-06-30-hook-bridges.zh.md | 16 +-- .../2026-06-30-hook-protocol-lib.i18n.yaml | 4 +- .../2026-06-30-hook-protocol-lib.zh.md | 8 +- .../2026-06-30-interception-seams.i18n.yaml | 4 +- .../2026-06-30-interception-seams.zh.md | 22 +-- ...026-06-30-session-store-fork-api.i18n.yaml | 4 +- .../2026-06-30-session-store-fork-api.zh.md | 6 +- ...26-06-30-subagent-observe-enrich.i18n.yaml | 4 +- .../2026-06-30-subagent-observe-enrich.zh.md | 12 +- .../2026-07-05-dynamic-workflows.i18n.yaml | 4 +- .../2026-07-05-dynamic-workflows.zh.md | 8 +- .../feature/2026-07-05-skill-system.i18n.yaml | 4 +- .../feature/2026-07-05-skill-system.zh.md | 6 +- .../2026-07-06-approval-seam.i18n.yaml | 4 +- .../feature/2026-07-06-approval-seam.zh.md | 57 ++++---- .../2026-07-06-explicit-tool-order.i18n.yaml | 4 +- .../2026-07-06-explicit-tool-order.zh.md | 11 +- .../feature/2026-07-06-sandbox.i18n.yaml | 4 +- .../feature/2026-07-06-sandbox.zh.md | 53 ++++--- .../2026-07-07-mcp-client-plugin.i18n.yaml | 4 +- .../2026-07-07-mcp-client-plugin.zh.md | 22 +-- .../2026-07-07-session-prefix.i18n.yaml | 4 +- .../feature/2026-07-07-session-prefix.md | 2 + .../feature/2026-07-07-session-prefix.zh.md | 25 ++-- .../2026-07-08-repeat-tool-guard.i18n.yaml | 4 +- .../2026-07-08-repeat-tool-guard.zh.md | 18 +-- ...-self-referential-cordis-toolset.i18n.yaml | 4 +- ...7-08-self-referential-cordis-toolset.zh.md | 18 +-- ...2026-07-10-session-query-service.i18n.yaml | 4 +- .../2026-07-10-session-query-service.zh.md | 15 +- ...nt-persona-tool-filter-and-depth.i18n.yaml | 4 +- ...bagent-persona-tool-filter-and-depth.zh.md | 12 +- .../2026-06-11-doc-sync-enforcement.i18n.yaml | 4 +- .../2026-06-11-doc-sync-enforcement.zh.md | 10 +- .../2026-06-11-quality-gates.i18n.yaml | 4 +- .../process/2026-06-11-quality-gates.md | 2 + .../process/2026-06-11-quality-gates.zh.md | 12 +- .../2026-06-11-tsdown-over-dumble.i18n.yaml | 4 +- .../2026-06-11-tsdown-over-dumble.zh.md | 6 +- ...26-06-11-vendor-cordis-as-source.i18n.yaml | 4 +- .../2026-06-11-vendor-cordis-as-source.zh.md | 2 +- .../2026-06-16-pnpm-over-yarn.i18n.yaml | 4 +- .../process/2026-06-16-pnpm-over-yarn.zh.md | 6 +- .../2026-06-17-ts-build-config.i18n.yaml | 4 +- .../process/2026-06-17-ts-build-config.zh.md | 3 +- ...6-06-18-markdown-cross-link-lint.i18n.yaml | 4 +- .../2026-06-18-markdown-cross-link-lint.zh.md | 10 +- ...-06-20-agent-note-classification.i18n.yaml | 4 +- .../2026-06-20-agent-note-classification.md | 2 + ...2026-06-20-agent-note-classification.zh.md | 26 ++-- ...-20-core-data-structures-catalog.i18n.yaml | 4 +- ...6-06-20-core-data-structures-catalog.zh.md | 22 +-- ...6-06-20-generated-cordis-catalog.i18n.yaml | 4 +- .../2026-06-20-generated-cordis-catalog.zh.md | 16 +-- .../2026-07-02-tool-schema-catalog.i18n.yaml | 4 +- .../2026-07-02-tool-schema-catalog.zh.md | 10 +- ...-07-03-documentation-graph-atlas.i18n.yaml | 4 +- ...2026-07-03-documentation-graph-atlas.zh.md | 27 ++-- ...4-cordis-jsdoc-completeness-gate.i18n.yaml | 4 +- ...07-04-cordis-jsdoc-completeness-gate.zh.md | 12 +- ...2026-07-04-doc-tiers-and-budgets.i18n.yaml | 4 +- .../2026-07-04-doc-tiers-and-budgets.zh.md | 10 +- ...26-07-04-persistence-log-catalog.i18n.yaml | 4 +- .../2026-07-04-persistence-log-catalog.zh.md | 14 +- ...-07-05-uniform-agent-note-format.i18n.yaml | 4 +- .../2026-07-05-uniform-agent-note-format.md | 2 + ...2026-07-05-uniform-agent-note-format.zh.md | 22 +-- ...-07-06-export-surface-jsdoc-gate.i18n.yaml | 4 +- ...2026-07-06-export-surface-jsdoc-gate.zh.md | 6 +- ...6-07-06-generated-config-catalog.i18n.yaml | 4 +- .../2026-07-06-generated-config-catalog.zh.md | 6 +- .../2026-07-06-node-engine-floor.i18n.yaml | 4 +- .../2026-07-06-node-engine-floor.zh.md | 6 +- ...6-07-06-parallel-github-ci-gates.i18n.yaml | 4 +- .../2026-07-06-parallel-github-ci-gates.md | 2 + .../2026-07-06-parallel-github-ci-gates.zh.md | 45 +++--- ...26-07-06-parallel-pre-push-gates.i18n.yaml | 4 +- .../2026-07-06-parallel-pre-push-gates.md | 2 + .../2026-07-06-parallel-pre-push-gates.zh.md | 37 ++--- ...10-readme-known-limitations-gate.i18n.yaml | 4 +- ...-07-10-readme-known-limitations-gate.zh.md | 8 +- ...ackage-model-experience-contract.i18n.yaml | 4 +- ...07-12-package-model-experience-contract.md | 2 + ...12-package-model-experience-contract.zh.md | 18 +-- ...-19-drop-mutable-session-summary.i18n.yaml | 4 +- ...6-06-19-drop-mutable-session-summary.zh.md | 8 +- ...llapse-trace-only-session-events.i18n.yaml | 4 +- ...0-collapse-trace-only-session-events.zh.md | 4 +- ...onsumed-llm-adapter-change-event.i18n.yaml | 4 +- ...-unconsumed-llm-adapter-change-event.zh.md | 10 +- ...nconsumed-llm-assembled-surfaces.i18n.yaml | 4 +- ...op-unconsumed-llm-assembled-surfaces.zh.md | 6 +- ...26-06-20-prune-dead-seam-methods.i18n.yaml | 4 +- .../2026-06-20-prune-dead-seam-methods.md | 2 + .../2026-06-20-prune-dead-seam-methods.zh.md | 12 +- ...-06-20-public-agent-stop-surface.i18n.yaml | 4 +- ...2026-06-20-public-agent-stop-surface.zh.md | 12 +- ...ove-agent-boundary-mirror-events.i18n.yaml | 4 +- ...-20-remove-agent-boundary-mirror-events.md | 2 + ...-remove-agent-boundary-mirror-events.zh.md | 31 ++-- ...06-20-unify-agent-and-session-id.i18n.yaml | 4 +- .../2026-06-20-unify-agent-and-session-id.md | 2 + ...026-06-20-unify-agent-and-session-id.zh.md | 38 +++-- .../2026-06-26-fsspec-style-fs-seam.i18n.yaml | 4 +- .../2026-06-26-fsspec-style-fs-seam.zh.md | 20 +-- ...07-02-remove-stream-chunk-mirror.i18n.yaml | 4 +- ...026-07-02-remove-stream-chunk-mirror.zh.md | 12 +- ...6-07-04-drop-image-content-block.i18n.yaml | 4 +- .../2026-07-04-drop-image-content-block.zh.md | 6 +- ...6-07-04-drop-inert-request-knobs.i18n.yaml | 4 +- .../2026-07-04-drop-inert-request-knobs.zh.md | 8 +- ...consumed-web-observation-surface.i18n.yaml | 4 +- ...p-unconsumed-web-observation-surface.zh.md | 10 +- .../2026-07-04-fold-stdio-ui-helper.i18n.yaml | 4 +- .../2026-07-04-fold-stdio-ui-helper.md | 2 + .../2026-07-04-fold-stdio-ui-helper.zh.md | 10 +- ...producerless-vocabulary-variants.i18n.yaml | 4 +- ...-prune-producerless-vocabulary-variants.md | 2 + ...une-producerless-vocabulary-variants.zh.md | 14 +- ...7-04-prune-write-only-fs-surface.i18n.yaml | 4 +- ...26-07-04-prune-write-only-fs-surface.zh.md | 6 +- ...-04-remove-agent-steering-mirror.i18n.yaml | 4 +- ...6-07-04-remove-agent-steering-mirror.zh.md | 12 +- ...26-07-04-share-app-bin-boot-glue.i18n.yaml | 4 +- .../2026-07-04-share-app-bin-boot-glue.zh.md | 8 +- ...4-tighten-hook-protocol-contract.i18n.yaml | 4 +- ...07-04-tighten-hook-protocol-contract.zh.md | 8 +- ...m-acp-bridge-unreachable-surface.i18n.yaml | 4 +- ...-trim-acp-bridge-unreachable-surface.zh.md | 4 +- ...unconsumed-skill-provider-events.i18n.yaml | 4 +- ...rop-unconsumed-skill-provider-events.zh.md | 4 +- ...-12-prune-unused-web-seam-fields.i18n.yaml | 4 +- ...6-07-12-prune-unused-web-seam-fields.zh.md | 4 +- ...plify-session-log-representation.i18n.yaml | 4 +- ...-12-simplify-session-log-representation.md | 2 + ...-simplify-session-log-representation.zh.md | 27 ++-- ...026-06-11-property-based-testing.i18n.yaml | 4 +- .../2026-06-11-property-based-testing.zh.md | 6 +- .../2026-06-19-acp-snapshot-tests.i18n.yaml | 4 +- .../2026-06-19-acp-snapshot-tests.zh.md | 36 ++--- .../2026-06-19-real-api-e2e-ci.i18n.yaml | 4 +- .../testing/2026-06-19-real-api-e2e-ci.zh.md | 12 +- ...ant-snapshot-log-expected-output.i18n.yaml | 4 +- ...-redundant-snapshot-log-expected-output.md | 2 + ...dundant-snapshot-log-expected-output.zh.md | 16 +-- ...-fork-child-replay-seed-boundary.i18n.yaml | 4 +- ...6-22-fork-child-replay-seed-boundary.zh.md | 4 +- ...26-06-22-fork-snapshot-scenarios.i18n.yaml | 4 +- .../2026-06-22-fork-snapshot-scenarios.zh.md | 12 +- ...6-06-22-subagent-snapshot-replay.i18n.yaml | 4 +- .../2026-06-22-subagent-snapshot-replay.zh.md | 10 +- .../2026-07-04-hook-snapshot-matrix.i18n.yaml | 4 +- .../2026-07-04-hook-snapshot-matrix.zh.md | 18 +-- ...-single-source-acp-replay-config.i18n.yaml | 4 +- ...7-04-single-source-acp-replay-config.zh.md | 6 +- ...t-header-content-in-one-scenario.i18n.yaml | 4 +- ...quest-header-content-in-one-scenario.zh.md | 12 +- ...7-08-shared-acp-snapshot-package.i18n.yaml | 4 +- .../2026-07-08-shared-acp-snapshot-package.md | 2 + ...26-07-08-shared-acp-snapshot-package.zh.md | 20 +-- .../2026-06-16-typed-event-schemas.i18n.yaml | 4 +- .../2026-06-16-typed-event-schemas.zh.md | 18 +-- ...026-06-30-pre-tool-input-rewrite.i18n.yaml | 4 +- .../2026-06-30-pre-tool-input-rewrite.zh.md | 4 +- ...code-and-codex-subagent-backends.i18n.yaml | 4 +- ...ude-code-and-codex-subagent-backends.zh.md | 28 ++-- ...-07-08-interactive-side-sessions.i18n.yaml | 4 +- ...2026-07-08-interactive-side-sessions.zh.md | 6 +- ...10-sqlite-session-query-provider.i18n.yaml | 4 +- ...-07-10-sqlite-session-query-provider.zh.md | 10 +- ...flow-progress-through-tool-calls.i18n.yaml | 4 +- ...workflow-progress-through-tool-calls.zh.md | 2 +- ...2026-06-11-api-extractor-reports.i18n.yaml | 4 +- .../2026-06-11-api-extractor-reports.md | 2 + .../2026-06-11-api-extractor-reports.zh.md | 4 +- ...-06-11-architectural-conformance.i18n.yaml | 4 +- ...2026-06-11-architectural-conformance.zh.md | 10 +- ...11-supply-chain-and-vendor-drift.i18n.yaml | 4 +- ...-06-11-supply-chain-and-vendor-drift.zh.md | 8 +- ...06-20-discover-package-inventory.i18n.yaml | 4 +- ...026-06-20-discover-package-inventory.zh.md | 13 +- ...04-prune-dead-core-spine-surface.i18n.yaml | 4 +- ...-07-04-prune-dead-core-spine-surface.zh.md | 23 +-- ...deterministic-and-stress-testing.i18n.yaml | 4 +- ...-11-deterministic-and-stress-testing.zh.md | 8 +- .../2026-06-11-mutation-testing.i18n.yaml | 4 +- .../testing/2026-06-11-mutation-testing.zh.md | 10 +- ...-06-11-immutable-public-surfaces.i18n.yaml | 4 +- ...2026-06-11-immutable-public-surfaces.zh.md | 4 +- ...-06-20-providerless-example-base.i18n.yaml | 4 +- ...2026-06-20-providerless-example-base.zh.md | 6 +- ...generate-agent-note-index-tables.i18n.yaml | 4 +- ...-07-04-generate-agent-note-index-tables.md | 2 + ...-04-generate-agent-note-index-tables.zh.md | 34 +++-- ...ssembled-assistant-messages-only.i18n.yaml | 4 +- ...20-assembled-assistant-messages-only.zh.md | 16 +-- ...2026-06-20-drop-acp-session-load.i18n.yaml | 4 +- .../2026-06-20-drop-acp-session-load.zh.md | 10 +- ...026-06-20-drop-acp-terminal-meta.i18n.yaml | 4 +- .../2026-06-20-drop-acp-terminal-meta.zh.md | 8 +- ...-20-drop-bash-output-spill-files.i18n.yaml | 4 +- ...6-06-20-drop-bash-output-spill-files.zh.md | 8 +- ...-20-drop-durable-step-boundaries.i18n.yaml | 4 +- ...6-06-20-drop-durable-step-boundaries.zh.md | 10 +- ...6-20-drop-unused-session-lineage.i18n.yaml | 4 +- ...26-06-20-drop-unused-session-lineage.zh.md | 6 +- ...ld-session-persistence-interface.i18n.yaml | 4 +- ...0-fold-session-persistence-interface.zh.md | 4 +- ...026-06-20-generic-tool-rendering.i18n.yaml | 4 +- .../2026-06-20-generic-tool-rendering.zh.md | 6 +- ...6-06-20-retire-mid-turn-steering.i18n.yaml | 4 +- .../2026-06-20-retire-mid-turn-steering.zh.md | 6 +- ...-06-20-single-session-acp-bridge.i18n.yaml | 4 +- ...2026-06-20-single-session-acp-bridge.zh.md | 8 +- ...06-20-truncate-interrupted-turns.i18n.yaml | 4 +- ...026-06-20-truncate-interrupted-turns.zh.md | 8 +- ...nimplemented-subagent-vocabulary.i18n.yaml | 4 +- ...prune-unimplemented-subagent-vocabulary.md | 2 + ...ne-unimplemented-subagent-vocabulary.zh.md | 18 +-- ...apse-workflow-to-foreground-core.i18n.yaml | 4 +- ...collapse-workflow-to-foreground-core.zh.md | 8 +- ...ne-unused-skill-registry-surface.i18n.yaml | 4 +- ...-prune-unused-skill-registry-surface.zh.md | 8 +- 325 files changed, 1535 insertions(+), 1321 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml index fb029f04fe..cc77840694 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml @@ -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 -2026-06-11-content-block-vocabulary.md: 6a90813ec90c6522a88a09d3536ce0cef8250238 -2026-06-11-content-block-vocabulary.zh.md: c9c65ae7e556cdf4eced0d45051862ff87fcd0fe +2026-06-11-content-block-vocabulary.md: 9aad01cee6083b1f380be66869af3137a07d9f1f +2026-06-11-content-block-vocabulary.zh.md: 123ca87f55be5129855a330efbfe0818d7cdbc0c diff --git a/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md b/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md index c9c65ae7e5..123ca87f55 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md @@ -1,4 +1,4 @@ -# RFC: 由 dsh-llm 拥有的提供方无关内容块词汇 +# Agent Note: 由 dsh-llm 拥有的提供方无关内容块词汇 Status: implemented @@ -12,7 +12,7 @@ harness 需要一套统一的内部消息语言,供 agent loop(智能体循 自主拥有词汇:消息是类型化内容块的数组(`text`、`reasoning`、`tool-call`、`tool-result`),其联合类型派生自可合并扩展的 `ContentBlockMap`,插件通过声明合并添加新的块类型。同一可合并扩展映射模式为所有「字符串化」字段提供类型(`MessageSource`、`FinishReason`、`TurnTrigger`、`TurnEndReason`)。流式输出采用原始分片协议;`BlockAssembler` 是唯一的共享组装实现。适配器负责转换为提供方的协议格式(wire format)——映射成本留在适配器中,正是它该在的地方。 -会话内上下文注入(`context/message`、`steering/message`)渲染为带标签的 user-role 信封(system-reminder 模式),而非引入新角色,因此适配器无需承担额外负担。实际适配器验证已确认此渲染方式符合当前 DeepSeek 的行为;如果未来某提供方出现不兼容,应在该适配器内处理,而非引入新的规范角色。 +会话内上下文注入(`context/message`)和轮次中途 steering(`steering/message`)最初渲染为带标签的 user-role 信封(system-reminder 模式),而非引入新角色,因此适配器无需承担额外负担。如今两者都投影为无包装的普通用户内容;见[注入内容信封 Agent Note](../simplification/2026-07-20-unwrap-injected-content-envelopes.md)。实际适配器验证已确认此渲染方式符合当前 DeepSeek 的行为;如果未来某提供方出现不兼容,应在该适配器内处理,而非引入新的规范角色。 ## 曾考虑的替代方案 @@ -22,7 +22,7 @@ harness 需要一套统一的内部消息语言,供 agent loop(智能体循 ## 后果 - 推理(reasoning)在核心层有了归属,无需依赖提供方特有的结构。 -- 多模态块只有在适配器、UI 和上下文压缩(context compaction)三方协同支持后才会回归;见 [drop-image RFC](../simplification/2026-07-04-drop-image-content-block.md)。 -- 缓存提示与 assistant prefill 在有实际适配器能兑现之前保持缺席;见 [producer-less variants](../simplification/2026-07-04-prune-producerless-vocabulary-variants.md) 与 [inert request knobs](../simplification/2026-07-04-drop-inert-request-knobs.md) RFC。 +- 多模态块只有在适配器、UI 和上下文压缩(context compaction)三方协同支持后才会回归;见 [drop-image Agent Note](../simplification/2026-07-04-drop-image-content-block.md)。 +- 缓存提示与 assistant prefill 在有实际适配器能兑现之前保持缺席;见 [producer-less variants](../simplification/2026-07-04-prune-producerless-vocabulary-variants.md) 与 [inert request knobs](../simplification/2026-07-04-drop-inert-request-knobs.md) Agent Note。 - 每个适配器都需承担翻译成本;首批真实适配器已验证了流式输出协议,新适配器应继续在适配器本地测试中验证其提供方特有的映射。 -- 跨包(package)边界的 ID 使用品牌类型(`CallId`、`SessionId`、`AgentId`)——零运行时开销的名义类型。 +- 跨包(package)边界的 ID 使用品牌类型(`CallId`、agent 与 session 共享的 `SessionId`)——零运行时开销的名义类型。 diff --git a/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml index c08b4133de..cf2b48bfdb 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.i18n.yaml @@ -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 -2026-06-11-custom-schema-dsl.md: 34c018b779d45c5eadb7337cb060c43b6f8d09b1 -2026-06-11-custom-schema-dsl.zh.md: 674a6b1a0b67617ffb4ab919899aa108c646a489 +2026-06-11-custom-schema-dsl.md: 9cef4175e4c4a2e6d2ea034d3522d8a8ddd1f5cb +2026-06-11-custom-schema-dsl.zh.md: 8b1241edea4c591e428fbaa15916437a3de42061 diff --git a/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md b/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md index 674a6b1a0b..8b1241edea 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-11-custom-schema-dsl.zh.md @@ -1,4 +1,4 @@ -# RFC: 使用自定义类型化 tool-schema DSL 替代 schemastery +# Agent Note: 使用自定义类型化 tool-schema DSL 替代 schemastery Status: implemented diff --git a/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml index 2df4576e59..a3029832c5 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.i18n.yaml @@ -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 -2026-06-11-dev-invariants-over-deep-readonly.md: 01a9e45fac77d2513924e78566a44a6059dd9d28 -2026-06-11-dev-invariants-over-deep-readonly.zh.md: 8f8db9f5bb095b8fc9c600b741c16d630a6c8167 +2026-06-11-dev-invariants-over-deep-readonly.md: 8f0e79f15af82ce3125b1f6f767d4ea727aa6d29 +2026-06-11-dev-invariants-over-deep-readonly.zh.md: 9998ddd784f956e3497a0bb9d8f5096047f14a70 diff --git a/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md b/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md index 8f8db9f5bb..9998ddd784 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.zh.md @@ -1,4 +1,4 @@ -# RFC: 源端拥有的会话不可变性与开发模式不变式 +# Agent Note: 源端拥有的会话不可变性与开发模式不变式 Status: implemented @@ -30,11 +30,11 @@ TypeScript readonly 类型不是充分的运行时边界。它们在程序运行 `deriveMessages()` 将已记录的表面事件投影为分离的、深度冻结的 `Message` 对象,并返回一份新的数组快照。因此请求组装可以将派生历史与其他输入组合,而不会暴露一条回到日志的路径。缓存复用安全的不可变投影,而非为每次模型调用重新克隆完整历史。 -### 不变式插件检查关系 +### 包拥有的不变式配套插件检查关系 -`dsh-invariants` 是一个纯监听器的开发插件。它不冻结记录,没有配置;dispose(资源释放)仅移除其断言。它检查需要跟踪状态或观察另一个 seam 的规则,包括单调递增的序列号、轮次与步骤嵌套、工具调用/结果配对、合法的 agent(智能体)状态转换、主体正确的作用域分发,以及循环构建的请求与从其会话日志前缀重建的请求之间的等价性。 +`dsh-invariants` 注册可配置的 `ctx.invariants` 服务,本身不包含产品检查。每个包发布一个 `./invariant` 所有权配套插件;`dsh-session`、`dsh-agent`、`dsh-scope` 和 `dsh-agent-loop` 目前添加需要 trace 状态或观察另一个 seam 的规则:单调递增的序列号、轮次与步骤嵌套、工具调用/结果配对、合法的 agent(智能体)状态转换、主体正确的作用域分发,以及循环构建的请求与从其会话日志前缀重建的请求之间的等价性。全局启用和包名 regex 过滤器归该服务所有(见[包拥有的不变式服务](2026-07-19-package-owned-invariant-service.md))。 -当插件附加到已有或已播种的会话时,它回放不可变日志以重建跟踪状态。这使得在轮次中途热重载是安全的,同时不赋予插件对会话存储的所有权。 +当 session 配套插件附加到已有或已播种的会话时,它回放不可变日志以重建跟踪状态。服务为每项贡献提供一个可 dispose(资源释放)的子 fiber,因此轮次中途热重载是安全的,同时不赋予诊断逻辑对会话存储的所有权。 ## 曾考虑的替代方案 @@ -55,6 +55,6 @@ TypeScript readonly 类型不是充分的运行时边界。它们在程序运行 - 每个被接受的实时或种子会话事件在任何观察者接收之前,都已从调用方拥有的输入中分离并深度不可变。 - `session.events` 暴露稳定的不可变快照,而非私有的增长数组。 - 请求侧的修改无法通过派生消息触及已存储的历史。 -- 开发构建可以启用关系断言而不改变存储行为;dispose 或省略该插件不会削弱日志不可变性。 -- `dsh-invariants` 没有 `Config` 表面,因为它没有可调节的行为。 +- 开发构建可以启用关系断言而不改变存储行为;dispose 或过滤一个配套插件不会削弱日志不可变性。 +- `dsh-invariants` 配置全局启用状态以及包 allow/block regex 列表;每项检查仍由其产品包拥有并测试。 - 运行时边界对每个被接受的事件产生一次递归快照与冻结的开销;后续读取者和缓存投影复用已拥有的不可变记录。 diff --git a/.agents/notes/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml index 747bbf3ab0..3ea1c711c4 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-11-event-sourced-sessions.i18n.yaml @@ -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 -2026-06-11-event-sourced-sessions.md: c1460b84c5928a53537a5f6a51f41c4d5b101a12 -2026-06-11-event-sourced-sessions.zh.md: 938404524cd23a5a5b3d6d0b7fd5020df3d35a51 +2026-06-11-event-sourced-sessions.md: 15ba7b23d5eae48e7dee2328b5924493d54aeeb0 +2026-06-11-event-sourced-sessions.zh.md: fc900b0dc43b18ba2016b4dd57584cf15707b016 diff --git a/.agents/notes/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md b/.agents/notes/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md index 938404524c..fc900b0dc4 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-11-event-sourced-sessions.zh.md @@ -1,4 +1,4 @@ -# RFC: 事件溯源的会话与派生消息历史 +# Agent Note: 事件溯源的会话与派生消息历史 Status: implemented diff --git a/.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml index 107aab3c75..a15ebcfddf 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.i18n.yaml @@ -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 -2026-06-11-microkernel-event-taxonomy.md: 47e363f949b506756d9b20ee7dc53ca81e3f5e4d -2026-06-11-microkernel-event-taxonomy.zh.md: 3b0aa54108bf8737e6fe341c7b0797a554d328ec +2026-06-11-microkernel-event-taxonomy.md: 8bf05b7deba5f054d4ec8ecf104c3b8798e42d4e +2026-06-11-microkernel-event-taxonomy.zh.md: 4ff2ab632ca02e98137a15f19a7996a740a519b0 diff --git a/.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md b/.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md index 3b0aa54108..4ff2ab632c 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md @@ -1,4 +1,4 @@ -# RFC: 微内核——通过 Cordis 事件分类体系实现扩展,唯一具体循环 +# Agent Note: 微内核——通过 Cordis 事件分类体系实现扩展,唯一具体循环 Status: implemented @@ -12,8 +12,8 @@ Status: implemented 纯 Cordis 事件分类体系。agent loop(智能体循环)的扩展 seam 是带类型的事件,具有明确的分发模式: -- **waterfall(瀑布式事件)**(around-middleware):插件可变换、否决或包装:`agent/prompt-submit`、`agent/request`、`agent/step-result`、`agent/turn-continuation`、`tools/pre-execute`、`tools/execute`、`tools/post-execute`、`llm/stream`、`system-prompt/assemble`。 -- **serial**(按监听器顺序依次 await;bail 值会阻止后续监听器执行):用于有序检查点。所有 `agent/pre-step` 监听器在全部弃权时才继续运行,而 `agent/turn-stop` 返回的第一个 stop 值即为最终的终止决策。 +- **waterfall(瀑布式事件)**(around-middleware):插件可变换、否决、恢复或包装:`agent/prompt-submit`、`agent/request`、`agent/request-error`、`agent/step-result`、`agent/turn-continuation`、`tools/pre-execute`、`tools/execute`、`tools/post-execute`、`llm/stream`、`system-prompt/assemble`。 +- **serial**(按监听器顺序依次 await;bail 值会阻止后续监听器执行):用于有序检查点。所有 `agent/pre-step` 和 `agent/post-step` 监听器在全部弃权时才继续运行,而 `agent/turn-stop` 返回的第一个 stop 值即为最终的终止决策。 - **parallel**(await 扇出):每个监听器都必须获得独立执行的机会:`session/flush` 持久性检查点。 - **emit**(同步 fire-and-forget):用于通知:轮次/步骤边界、流分片、生命周期、错误,以及包含不可变 `tools/result` 观测的事件。 @@ -25,7 +25,7 @@ Status: implemented ## 后果 -- 每个 MVP 功能都映射到一个监听器([功能→机制映射](../../../cookbook/extension-cookbook.md#the-feature--mechanism-map)是证明义务,保持更新)。 +- 每个 MVP 功能都映射到一个监听器([功能→机制映射](../../../../docs/cookbook/extension-cookbook.md#the-feature--mechanism-map)是证明义务,保持更新)。 - HMR 与 dispose 无需额外工作:监听器和注册均为 Cordis effect。 - waterfall 语义(调用 `next()` 或短路)不直观,需要教学——在 AGENTS.md 中记录,并由组合测试覆盖。 - 循环必须具备防御性:插件异常在轮次级别被隔离,任何 seam 发出的 steering(中途引导)永远不会被搁置(有回归测试保障)。 diff --git a/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml index 0fa22e5594..46b8dad11a 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.i18n.yaml @@ -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 -2026-06-11-runtime-arg-validation.md: 82d01263225ce719e80631d1890f0a6cc328119d -2026-06-11-runtime-arg-validation.zh.md: 4bd6720f7ec87fcef028ba94f445a5210f1b0d7a +2026-06-11-runtime-arg-validation.md: 6ac2a2ab475c9813dbfbb09e45da71821489d6cd +2026-06-11-runtime-arg-validation.zh.md: 119f738dbb3aaee4786aa58d5495ab5e012e206e diff --git a/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md b/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md index 4bd6720f7e..119f738dbb 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-11-runtime-arg-validation.zh.md @@ -1,4 +1,4 @@ -# RFC: 模型边界处的运行时参数校验 +# Agent Note: 模型边界处的运行时参数校验 Status: implemented @@ -21,4 +21,4 @@ Status: implemented - `ToolArgsError` 目前是带 `code` 字段的普通 `Error`;如果日后引入 harness 级别的错误分类体系,它将变为子类,但不影响读取 `.message` 的调用方。 - 校验开销相对于一次模型调用可忽略不计。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml index 4a381ba271..b886be0e38 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-11-structured-error-taxonomy.i18n.yaml @@ -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 -2026-06-11-structured-error-taxonomy.md: 5a5f75038b6124457d2d4d08cbe0bec80415a387 -2026-06-11-structured-error-taxonomy.zh.md: d5a45a447ca00d48cb8366911a10f34c584d915c +2026-06-11-structured-error-taxonomy.md: 9122193b3d01cf5a4c315e6f7a7218153fd4a60a +2026-06-11-structured-error-taxonomy.zh.md: cb29503314edf248c90f2eecd54e01f5b203b99c diff --git a/.agents/notes/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md b/.agents/notes/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md index d5a45a447c..cb29503314 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-11-structured-error-taxonomy.zh.md @@ -1,4 +1,4 @@ -# RFC: 结构化错误分类体系 +# Agent Note: 结构化错误分类体系 Status: implemented @@ -12,7 +12,7 @@ Status: implemented 在 `dsh-llm`(叶子包,所有其他包都已依赖它,不引入新的依赖边)中引入一个 `HarnessError extends Error` 基类:稳定的 `code`(与 `message` 分离)、通过 `ErrorOptions` 进行 `cause` 链接、`name` 默认为子类名。`isHarnessError` 在 seam 处做类型收窄。 -- `LlmError`、`ToolArgsError`(dsh-tools)和 `InvariantError`(dsh-invariants)现在继承该基类,保留各自既有的 code。 +- `LlmError` 和 `ToolArgsError`(dsh-tools)继承该基类,保留各自既有的 code。 - `ToolExecutionResult` 新增可选字段 `error: { name, code }`,在注册表的 catch 中当抛出值为 `HarnessError` 时填充。agent loop 将其转发到 `tool/result` 会话事件(该事件也新增了同一可选字段),使结构化的失败信息存活到日志中,供重试/沙箱插件和回放使用。面向模型的文本块保持不变。 - agent loop 的 `toError` 将非 Error 的 throw 包装为 `HarnessError`(`code: 'UNKNOWN'`,原始值作为 `cause` 链接),而非裸 `Error`;这样即使是不规范的 throw 也能携带可路由的 code 进入会话的 `error` 事件(该事件此前已暴露 `code`)。 @@ -21,6 +21,6 @@ Status: implemented - 错误端到端可机器路由:插件可以基于 `error.code` 分支,而无需对 message 做子串匹配。 - 一个基类被广泛导入,但它位于所有包已经依赖的包中,代价仅是一条 import 语句,而非新的依赖边。 - `deriveMessages` 不会将 `error` 暴露到模型历史中——模型仍然看到文本块;结构化字段服务于代码和回放。 -- 参数校验与开发不变式保留各自既有的 code 和行为;共享基类增加了跨 seam 的路由元数据,不改变面向模型的文本。 +- 参数校验保留其既有的 code 和行为;包自有的诊断不变式独立携带稳定 code,使不变式注册表无需导入产品包。共享基类增加了跨 seam 的路由元数据,不改变面向模型的文本。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml index 57fe989a5d..61b72fe101 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.i18n.yaml @@ -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 -2026-06-11-tool-schemas-in-prompt-assembly.md: 260d56ffab054d874e13eb34eac029bf59b381fc -2026-06-11-tool-schemas-in-prompt-assembly.zh.md: 5ae98dfac676574d00f34580ec079bb6a8f2331f +2026-06-11-tool-schemas-in-prompt-assembly.md: 3643ac3d61be08f629ef0cd0424fef5cb9696c3a +2026-06-11-tool-schemas-in-prompt-assembly.zh.md: 645b829627674e5ccd1507002309b7e8364ac59f diff --git a/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md b/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md index 5ae98dfac6..645b829627 100644 --- a/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-11-tool-schemas-in-prompt-assembly.zh.md @@ -1,4 +1,4 @@ -# RFC: 工具 schema 是系统提示词组装的一部分 +# Agent Note: 工具 schema 是系统提示词组装的一部分 Status: implemented diff --git a/.agents/notes/implemented/architecture/2026-06-13-capability-seams.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-13-capability-seams.i18n.yaml index fcdc63390f..3cdeabed71 100644 --- a/.agents/notes/implemented/architecture/2026-06-13-capability-seams.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-13-capability-seams.i18n.yaml @@ -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 -2026-06-13-capability-seams.md: f10182737347fc54ff3fd06edb299e569397773d -2026-06-13-capability-seams.zh.md: e65d2f31eb80ce80e92b3e4bbb4d5b8948185c44 +2026-06-13-capability-seams.md: 7c755dced7825d2831acc0901f6412b8e5afe95a +2026-06-13-capability-seams.zh.md: f3aa1ebdee3a16bf095f317b86d01e00b6bbf0c7 diff --git a/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md b/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md index e65d2f31eb..f3aa1ebdee 100644 --- a/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md @@ -1,4 +1,4 @@ -# RFC: 能力 seam——接口/实现/消费方三分 +# Agent Note: 能力 seam——接口/实现/消费方三分 Status: implemented @@ -8,15 +8,15 @@ Status: implemented harness 具有可替换的能力:当前是 bash 执行,未来会有沙箱化/远程执行器和替代模型提供方。一项能力涉及三个关注点,它们以不同速率、因不同原因变化:*契约*(这项能力是什么)、*实现*(它如何运行)、*消费方接口*(模型和其他插件面向什么编程)。将三者捆绑在一个包(package)中会耦合这些变化速率——把本地执行器换成沙箱化执行器时,模型看到的工具 schema 也会被搅动,尽管面向模型的契约从未改变。 -这与「谁在运行时提供、谁需要一项能力」是不同的问题,后者 Cordis 已通过 service + `inject` 解决(提供方注册 `ctx.bash`;消费方声明 `inject: ['bash']`,其 fiber 挂起直到服务存在)。该机制是必要的,但不决定包的边界;本 RFC 决定的是包的边界。 +这与「谁在运行时提供、谁需要一项能力」是不同的问题,后者 Cordis 已通过 service + `inject` 解决(提供方注册 `ctx.bash`;消费方声明 `inject: ['bash']`,其 fiber 挂起直到服务存在)。该机制是必要的,但不决定包的边界;本 Agent Note 决定的是包的边界。 ## 决策 一项可替换的能力由**三个包**构成: -1. **接口**——一个抽象服务加词汇类型,拥有 `ctx.<key>`,仅依赖 cordis(例如 `dsh-bash`:`BashExecutor`、`BashRunResult`、`BashTask`)。 +1. **接口**——一个抽象服务加词汇类型,拥有 `ctx.<key>`,仅依赖其词汇依赖(例如 `dsh-bash`:`BashExecutor`、`BashRunResult`、`BashProcess`)。 2. **实现**——一个具体子类,以插件形式加载(例如 `dsh-bash-local`:子进程、进程组 kill、溢出文件截断)。沙箱化/远程后端是实现同一接口的兄弟包。 -3. **消费方**——模型和插件看到的内容(例如 `dsh-tool-bash`:`bash`/`bash_output`/`bash_kill` 工具 schema)。消费方 `inject` 接口键,从不导入实现类型。 +3. **消费方**——模型和插件看到的内容(例如 `dsh-tool-bash`:`bash` schema,后台句柄注册到通用任务运行时)。消费方 `inject` 接口键,从不导入实现类型。 实现与消费方由此独立演进:沙箱化执行器替换 `dsh-bash-local` 时无需触碰任何工具 schema。 @@ -25,8 +25,8 @@ harness 具有可替换的能力:当前是 bash 执行,未来会有沙箱化 ## 曾考虑的替代方案 - **单一合并包**:否决。因为它重新耦合了三分设计本要分离的三种变化速率(这正是拆分的意义所在)。 -- **`@cordisjs/plugin-capability`**:这是完全不同的维度。它是一个权限/能力*安全*服务(具名权限加继承,通过 `ctx.capability.test` 对会话进行检测),是延后的权限/沙箱工作(`tools/pre-execute` deny/ask seam)的候选方案,不是替换实现的机制。混淆这两个「能力」概念正是本 RFC 所指出的陷阱。 +- **`@cordisjs/plugin-capability`**:这是完全不同的维度。它是一个权限/能力*安全*服务(具名权限加继承,通过 `ctx.capability.test` 对会话进行检测),是延后的权限/沙箱工作(`tools/pre-execute` deny/ask seam)的候选方案,不是替换实现的机制。混淆这两个「能力」概念正是本 Agent Note 所指出的陷阱。 ## 后果 -每项能力需要更多包和更多样板代码(一组 `package.json`/`tsconfig`/README,加上 inject 接线)。换来的是:实现与消费方独立发布和版本管理,新后端永远不会波及面向模型的契约。该规则记录在 [AGENTS.md](../../../../AGENTS.md) § Conventions("Capability seams are three packages")和 [architecture.md](../../../architecture.md) § "Capability seams" 中;bash 三件套是参考模板。何时合并、何时拆分是一个判断问题,架构文档对此有详细说明——本 RFC 记录的是*为什么*默认选择拆分。 +每项能力需要更多包和更多样板代码(一组 `package.json`/`tsconfig`/README,加上 inject 接线)。换来的是:实现与消费方独立发布和版本管理,新后端永远不会波及面向模型的契约。该规则记录在 [AGENTS.md](../../../../AGENTS.md) § Conventions(「Capability seams are three packages」)和 [architecture.md](../../../../docs/architecture.md) §「Capability seams」中;bash 三件套是参考模板。何时合并、何时拆分是一个判断问题,架构文档对此有详细说明——本 Agent Note 记录的是*为什么*默认选择拆分。 diff --git a/.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml index 545aae3758..f1d2fe1a90 100644 --- a/.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.i18n.yaml @@ -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 -2026-06-13-twin-llm-adapters.md: edd7080e2a16e9f1af2ebd56a4265040dc970c17 -2026-06-13-twin-llm-adapters.zh.md: 2087d498f65326fa0a2cb74be409a926a5e343f5 +2026-06-13-twin-llm-adapters.md: 5c3308b281ce71407002e95dd6e794da2a421fa8 +2026-06-13-twin-llm-adapters.zh.md: 93b084973bccaeb802508e4e939a259c281f2608 diff --git a/.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md b/.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md index 2087d498f6..93b084973b 100644 --- a/.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.zh.md @@ -1,4 +1,4 @@ -# RFC: 以两个 LLM 适配器作为设计验证孪生体 +# Agent Note: 以两个 LLM 适配器作为设计验证孪生体 Status: implemented @@ -24,4 +24,4 @@ Status: implemented ## 后果 -孪生体使适配器和需要密钥的 e2e 维护量翻倍——两者都覆盖 V4 Flash 和 Pro 在各代表性推理(reasoning)模式下的行为——换来的是持续的 seam 中立性验证和第二份实现示例。两个适配器均使用 `apiKey`、`baseURL` 和 `models`;手写适配器暴露 `thinking`/`reasoningEffort`,pi-ai 适配器暴露一个 `reasoning` 级别。未来如果有一致性测试套件,可以通过后续 RFC 论证退役其中一个适配器。 +孪生体使适配器和需要密钥的 e2e 维护量翻倍——两者都覆盖 V4 Flash 和 Pro 在各代表性推理(reasoning)模式下的行为——换来的是持续的 seam 中立性验证和第二份实现示例。两个适配器均使用 `apiKey`、`baseURL` 和 `models`;手写适配器暴露 `thinking`/`reasoningEffort`,pi-ai 适配器暴露一个 `reasoning` 级别。未来如果有一致性测试套件,可以通过后续 Agent Note 论证退役其中一个适配器。 diff --git a/.agents/notes/implemented/architecture/2026-06-14-session-persistence.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-14-session-persistence.i18n.yaml index aa7fe88f24..35b81801d0 100644 --- a/.agents/notes/implemented/architecture/2026-06-14-session-persistence.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-14-session-persistence.i18n.yaml @@ -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 -2026-06-14-session-persistence.md: a50c076746981892239304266194d1e8e309574f -2026-06-14-session-persistence.zh.md: d609e663bd9e36f74bf34404c021a30f54d3bd76 +2026-06-14-session-persistence.md: 1122a52471c6279eff7454cfd31692f05a7bba76 +2026-06-14-session-persistence.zh.md: 0f2bcd4948a3c95cd0497cfa63ef4454630635c7 diff --git a/.agents/notes/implemented/architecture/2026-06-14-session-persistence.zh.md b/.agents/notes/implemented/architecture/2026-06-14-session-persistence.zh.md index d609e663bd..0f2bcd4948 100644 --- a/.agents/notes/implemented/architecture/2026-06-14-session-persistence.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-14-session-persistence.zh.md @@ -1,4 +1,4 @@ -# RFC: 会话持久化作为基于现有 `SessionEvent` 的抽象服务 +# Agent Note: 会话持久化作为基于现有 `SessionEvent` 的抽象服务 Status: implemented @@ -6,24 +6,24 @@ Status: implemented ## 问题 -会话此前仅存在于内存中。示例插件 `session-jsonl.ts`(在两个示例中逐字节重复)是只写的遥测:它缓冲 `session/event` 并追加 JSON 行,没有读取/回放路径,没有崩溃安全性(无 fsync、无原子写入、fire-and-forget 的 dispose 排空),没有列表功能,也没有格式版本控制。没有任何机制能将磁盘上的历史会话重新注入到活跃的 agent(智能体)中,因此持久恢复("继续昨天的任务")、持久 fork 以及 ACP(Agent Client Protocol)的 `session/load` 方法([ACP 支持](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md))都无法实现。 +会话此前仅存在于内存中。示例插件 `session-jsonl.ts`(在两个示例中逐字节重复)是只写的遥测:它缓冲 `session/event` 并追加 JSON 行,没有读取/回放路径,没有崩溃安全性(无 fsync、无原子写入、fire-and-forget 的 dispose 排空),没有列表功能,也没有格式版本控制。没有任何机制能将磁盘上的历史会话重新注入到活跃的 agent(智能体)中,因此持久恢复(「继续昨天的任务」)、持久 fork 以及 ACP(Agent Client Protocol)的 `session/load` 方法([ACP 支持](../feature/2026-06-14-acp-agent-client-protocol.md))都无法实现。 -[事件溯源模型](2026-06-11-event-sourced-sessions.md)将仅追加日志作为唯一真源,并从中派生 LLM(大语言模型)历史。持久化必须忠实于这一设计:直接持久化现有的 `SessionEvent`,不引入需要来回转换的并行"持久化消息"类型。后端也必须可替换——当前用文件存储,以后用数据库存储——统一在一个接口之后。 +[事件溯源模型](2026-06-11-event-sourced-sessions.md)将仅追加日志作为唯一真源,并从中派生 LLM(大语言模型)历史。持久化必须忠实于这一设计:直接持久化现有的 `SessionEvent`,不引入需要来回转换的并行「持久化消息」类型。后端也必须可替换——当前用文件存储,以后用数据库存储——统一在一个接口之后。 ## 决策 持久化是一个抽象的**能力 seam**([能力 seam](2026-06-13-capability-seams.md),`dsh-bash` 模板),而非循环或核心逻辑: 1. **接口**(`dsh-session-persistence`,`ctx.sessionPersistence`):一个抽象的 `SessionPersistence` 服务,提供 `create`/`append`/`load`/`list`。其持久化单元就是现有的 `SessionEvent`(`{ type, seq, time, data }`),原样复用,无转换类型。 -2. **实现**(`dsh-session-persistence-jsonl`):每个会话一个仅追加的 JSONL 日志(一行 `SessionHeader`,之后每行一个 `SessionEvent`,逐字节保留,**包括 `assistant/chunk`**)。 +2. **实现**(`dsh-session-persistence-jsonl`):每个会话一个仅追加的逻辑 JSONL 日志(一行 `SessionHeader`,之后每行一个 `SessionEvent`,逐字节保留,**包括 `assistant/chunk`**),默认编码为[带校验和的 Zstandard 帧](2026-07-19-zstandard-jsonl-session-logs.md),也可通过配置使用原始行。 以下关键选择记录于此,因为它们是持久性的、有争议的、且出人意料的: - **规范的持久日志逐字节保留每个 `SessionEvent`,包括 `assistant/chunk`。** `deriveMessages()` 跳过 chunk,而过滤 chunk 的方案(Codex 的 `policy.rs`)很有吸引力,但 `seq = log.length` 以及加载验证 `events[i].seq === i` 要求日志是*连续*的;过滤掉 chunk 会留下空洞,同时破坏契约和恢复功能。基于 chunk 过滤的投影可以作为派生视图在后续实现(带有自己的重新编号),但它不是规范日志。 -- **仅追加;崩溃的轮次被关闭,而非截断。** 已刷写到 `turn/end` 的事件永不被重写,且循环仅在轮次结束时刷写。由于一个被中断的轮次可能包含大量有效工作,`load` 保留其连续、可解析的事件,并为未应答的工具调用追加错误结果、补一个缺失的 `step/end`,以及带 `{ kind: 'interrupted' }` 的 `turn/end`。合成的结果保证恢复后的 provider transcript(文本记录)仍然有效。只有不完整的最后一条记录会被丢弃;在最后一个真实 `turn/end` 处或之前出现解析错误或序号间隙,属于数据损坏,会使该会话不可加载。 +- **仅追加;崩溃的轮次被关闭,而非截断。** 已刷写的事件永不被重写。[语义检查点策略](../bug-fix/2026-07-21-semantic-session-checkpoints.md)会在模型分发前排空请求、在工具分发前排空已记录的顶层调用,并在步骤结束后排空完整的响应/结果批次;循环则排空最终轮次边界。由于一个被中断的轮次可能包含大量有效工作,`load` 保留其连续、可解析的事件,并为未应答的 assistant 调用追加按风险分类的错误结果、补一个缺失的 `step/end`,以及带 `{ kind: 'interrupted' }` 的 `turn/end`。合成的结果保证恢复后的 provider transcript(文本记录)仍然有效。只有不完整的最后一条记录会被丢弃;在最后一个真实 `turn/end` 处或之前出现解析错误或序号间隙,属于数据损坏,会使该会话不可加载。 - **文件后端为规范实现,数据库后端为经过验证的直接替换。** `SessionEvent` 1:1 映射到一行 `(session_id, seq, type, time, data)`:`append` 是 INSERT(在一个断言连续 seq 契约的事务中),`load` 是 SELECT … ORDER BY seq。`dsh-session-persistence-sqlite` 正是如此:一个 `SessionPersistence` 子类,接口无变化(opencode 在 SQLite/WAL 上运行的正是这个形状),且通过与 JSONL 后端相同的 `runPersistenceContract` 测试套件。该契约以相同的语义约束两个后端(惰性物化、加载时关闭中断轮次、连续 seq),一次表达在文件字节上,一次表达在数据库行上。 - **元数据在日志之外。** 格式版本、cwd 和谱系是存储关注点,不是可回放的对话状态,因此它们存放在 `dsh-session` 拥有的 `SessionHeader` 中,并通过新的只读属性 `session.header` 附加到 `Session` 上——永远不进入 `SessionEventMap`,永远不到达 `deriveMessages()`。替代方案(一个可合并扩展的 `session/meta` 事件作为日志第 0 行)被否决:日志内事件会随 seed/fork 的会话免费携带,但元数据不是可回放状态,因此显式的日志外 header seam 是更干净的代价。(header 最初被拆分为不可变的 `SessionHeader` 加可变的 `SessionSummary`,二者的联合类型为 `SessionMeta`;可变 summary 后来因属于死状态而被移除——见 [移除可变会话摘要](../simplification/2026-06-19-drop-mutable-session-summary.md)。) -- **`ctx.agents.create()` 和 `ctx.agents.resume()` 是异步工厂;resume 还跨越持久化边界。** `ctx.agents.resume({ resumeSessionId })` 等待 `ctx.sessionPersistence.load`,用加载的事件重建活跃会话(使 `lastTurnNumber`/`deriveMessages` 得以延续),并在恢复的 id 上启动一个新 agent(不是 `${agentId}-session`)。agent loop(智能体循环)不会硬注入 `sessionPersistence`(那样会让非持久化的演示永远挂起);当它不存在时,`resume` 以明确的错误拒绝。 +- **`ctx.agents.create()` 和 `ctx.agents.resume()` 是异步工厂;resume 还跨越持久化边界。** `ctx.agents.resume({ resumeSessionId })` 等待 `ctx.sessionPersistence.load`,用加载的事件重建活跃会话(使 `lastTurnNumber`/`deriveMessages` 得以延续),并以原样恢复的 id 注册新 agent。agent loop(智能体循环)不会硬注入 `sessionPersistence`(那样会让非持久化的演示永远挂起);当它不存在时,`resume` 以明确的错误拒绝。 ## 曾考虑的替代方案 @@ -33,4 +33,4 @@ Status: implemented ## 后果 -新增两个包(package),以及 `dsh-session` 中的元数据 seam(`session.header`,`create(id?, options?)` 签名)。收益:持久恢复/fork、读取/回放路径、崩溃容忍,以及 ACP `session/load`([ACP 支持](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md))所需的基础——全部基于现有的事件溯源日志,后端在一个接口之后可替换。可复用的 `runPersistenceContract` 测试套件以相同的仅追加、连续 seq、惰性物化与可序列化语义约束每个后端。持久化完整日志还确定了事件保真度:`assistant/chunk` 保持逐字节不变。 +新增两个包(package),以及 `dsh-session` 中的元数据 seam(`session.header`,`create(id?, options?)` 签名)。收益:持久恢复/fork、读取/回放路径、崩溃容忍,以及 ACP `session/load`([ACP 支持](../feature/2026-06-14-acp-agent-client-protocol.md))所需的基础——全部基于现有的事件溯源日志,后端在一个接口之后可替换。可复用的 `runPersistenceContract` 测试套件以相同的仅追加、连续 seq、惰性物化与可序列化语义约束每个后端。持久化完整日志还确定了事件保真度:`assistant/chunk` 保持逐字节不变。 diff --git a/.agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml index cf8898285a..46cb7aaa20 100644 --- a/.agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.i18n.yaml @@ -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 -2026-06-15-turn-enclosure-invariant.md: 26ae1890e481288b3be17f97db14c332f69be4b8 -2026-06-15-turn-enclosure-invariant.zh.md: 1946f829100e39afed826b8cf3ba82d22058c27d +2026-06-15-turn-enclosure-invariant.md: 6e2abd1716f8efc08c06d5ff8faec38282f2a17f +2026-06-15-turn-enclosure-invariant.zh.md: 0921c2574dc171e887664d8a2ea840a4e81f1531 diff --git a/.agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md b/.agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md index 1946f82910..0921c2574d 100644 --- a/.agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-15-turn-enclosure-invariant.zh.md @@ -1,4 +1,4 @@ -# RFC: 每个会话事件都封闭在一个轮次内 +# Agent Note: 每个会话事件都封闭在一个轮次内 Status: implemented @@ -20,10 +20,10 @@ Status: implemented **每个会话事件都位于一个轮次内部**:在 `turn/start` 与其匹配的 `turn/end` 之间。具体而言: - agent loop 在 `turn/start` **之后**(轮次内部)追加排队的 `user/message` 事件,而非之前。因此,一旦这些消息被记录,就欠下一个 `turn/end`,既有的 finalizer 保证它被写入。 -- agent **运行中**调用 `agent.inject()` 时,`context/message` 追加到已打开的轮次中(行为不变)。 +- agent **运行中**调用 `agent.inject()` 时,它会加入已打开的轮次。当前步骤执行 assistant 工具调用期间,已接受的上下文按到达顺序等待该批次结算,随后在每个已记录结果之后追加;即使执行中断,也会在轮次关闭前写入。 - agent **空闲时**调用 `agent.inject()`,则将 `context/message` 包裹在一个一次性轮次中:`turn/start{trigger:{kind:'injection'}}` → `context/message` → `turn/end{completed}`。一个新的 `injection` 变体加入可合并扩展的 `TurnTriggerMap`。 - agent loop 每次迭代从日志推导下一个轮次编号(`lastTurnNumber(session) + 1`),而不是维护一个私有计数器,这样空闲注入的一次性轮次不会与下一个真实轮次的编号冲突。 -- `dsh-invariants` 插件在开发环境中**强制执行**该不变式:在没有打开轮次的情况下追加 `user/message` / `context/message` / `steering/message` 会抛出 `InvariantError`。 +- `dsh-session/invariant` companion 将该检查注册到 `ctx.invariants`:选中后,在没有打开轮次的情况下追加 `user/message` / `context/message` / `steering/message` 会抛出归因于 `@deepseek-ai/dsh-session` 的 `InvariantError`。 可序列化性不变式在同一源码边界处强制执行(`Session.append` 对不可 JSON 序列化的数据抛出异常),因此「什么可以进入日志」现在由一个位置统一管控,而非由下游碰巧在监听的某个后端各自发现。 diff --git a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml index 62ab944e40..8b36d4bdd1 100644 --- a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.i18n.yaml @@ -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 -2026-06-17-filesystem-capability-seam.md: c87c8a44d2e956a9613039378d26f72e8ee97ee7 -2026-06-17-filesystem-capability-seam.zh.md: 4864e77ced5c078fc8c1e970a2ff88c78a37af2a +2026-06-17-filesystem-capability-seam.md: cd8f8572730b1833ed1d7dbe1861d516c2d32925 +2026-06-17-filesystem-capability-seam.zh.md: a7a8d4cbc48c473b1f0669a95c5fbe25eecf94f4 diff --git a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md index 4864e77ced..a7a8d4cbc4 100644 --- a/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-17-filesystem-capability-seam.zh.md @@ -1,4 +1,4 @@ -# RFC: 文件系统能力 seam——ctx.fs、本地后端与面向模型的文件系统工具 +# Agent Note: 文件系统能力 seam——ctx.fs、本地后端与面向模型的文件系统工具 Status: implemented @@ -20,7 +20,7 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` ## 决策 -文件系统访问是一个一等的能力 seam,遵循[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md): +文件系统访问是一个一等的能力 seam,遵循[能力 seam Agent Note](2026-06-13-capability-seams.md): 1. `@deepseek-ai/dsh-fs`(`packages/fs/fs`)拥有抽象的 `ctx.fs` 服务、文件系统词汇类型,以及 `fs/*` 策略事件词汇。 2. `@deepseek-ai/dsh-fs-local`(`packages/fs/fs-local`)提供第一个实现,以本地文件系统为后端。 @@ -28,7 +28,7 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 消费方包仅依赖接口包,从不依赖 `dsh-fs-local`。需要不同后端的部署只需为 `ctx.fs` 加载不同的提供方,无需改动工具 schema 或面向模型的提示词引导。 -读后写/编辑与观测状态策略是第四个包 `@deepseek-ai/dsh-fs-policy`(`packages/fs/fs-policy`),通过 `fs/*` 事件门控贡献,而非挂在 `ctx.fs` 上;加载 `dsh-tool-fs` 的部署同时加载 `dsh-fs-policy` 以获得读后写/编辑能力。本 RFC 确立了由三个包构成的 seam;策略从提供方基类拆出的决策由 [split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 做出,其以事件门控插件(而非方法服务)实现的方式由 [event-gate RFC](2026-06-26-file-context-as-event-gate.md) 做出。本文已更新为描述最终落地的四包形态。 +读后写/编辑与观测状态策略是第四个包 `@deepseek-ai/dsh-fs-policy`(`packages/fs/fs-policy`),通过 `fs/*` 事件门控贡献,而非挂在 `ctx.fs` 上;加载 `dsh-tool-fs` 的部署同时加载 `dsh-fs-policy` 以获得读后写/编辑能力。本 Agent Note 确立了由三个包构成的 seam;策略从提供方基类拆出的决策由 [split-fs-seam Agent Note](../simplification/2026-06-26-fsspec-style-fs-seam.md) 做出,其以事件门控插件(而非方法服务)实现的方式由 [event-gate Agent Note](2026-06-26-file-context-as-event-gate.md) 做出。本文已更新为描述最终落地的四包形态。 第一个后端有意仅限本地:`dsh-fs-local` 基于宿主文件系统实现 `ctx.fs`。未来的兄弟后端可在同一接口之后提供沙箱、远程、虚拟或项目作用域的文件系统。 @@ -36,7 +36,7 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` 文件系统权限和沙箱并非此拆分所隐含。本地后端从其配置的基目录解析相对路径,但隔离策略是独立的决策:要么由更严格的 `ctx.fs` 实现强制执行,要么由权限/沙箱插件包装 `tools/execute` 并在调用到达消费方之前否决。 -读后写/编辑与观测状态属于 `dsh-fs-policy`,而非 `ctx.fs`。通过 `fs/*` 事件门控,策略按不透明 actor 记录版本,并提供可选的变更期望;提供方原子性地强制新鲜度。`dsh-tool-fs` 发出事件但不依赖策略。见 [split-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](2026-06-26-file-context-as-event-gate.md) RFC。 +读后写/编辑与观测状态属于 `dsh-fs-policy`,而非 `ctx.fs`。通过 `fs/*` 事件门控,策略按不透明 actor 记录版本,并提供可选的变更期望;提供方原子性地强制新鲜度。`dsh-tool-fs` 发出事件但不依赖策略。见 [split-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](2026-06-26-file-context-as-event-gate.md) Agent Note。 ## 包拓扑 @@ -73,7 +73,7 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` - `writeText`/`editText` 接受一个可选的版本期望:省略它表示无条件的裸提供方变更;提供它则在后端的原子临界区内守护变更。 - `dsh-fs-policy` 插件在 `fs/write-intent`/`fs/edit-intent` 上决定该期望,并在 `fs/observed` 上记录观测版本,以它从不透明事件 actor 推导出的 owner 为键(通常是 `exec.agent.session`)。 -授权基于版本新鲜度,而非完整/部分视图的区分:任何读取都会记录目标的版本,后续的写入/编辑只要文件仍处于该版本就被授权——因此对第 100-150 行的窗口化读取可以授权对第 120 行的编辑。观测状态存储是 `dsh-fs-policy` 内部的 `WeakMap<owner, Map<targetKey, version>>`;`dsh-fs` 不持有任何此类数据,并将 actor 视为不透明。(本 RFC 最初建模了一个带 `full`/`partial` 视图的 `FileState` 缓存放在 `ctx.fs` 上;split-fs-seam 和 event-gate RFC 将其替换为此处描述的基于新鲜度的策略插件。) +授权基于版本新鲜度,而非完整/部分视图的区分:任何读取都会记录目标的版本,后续的写入/编辑只要文件仍处于该版本就被授权——因此对第 100-150 行的窗口化读取可以授权对第 120 行的编辑。观测状态存储是 `dsh-fs-policy` 内部的 `WeakMap<owner, Map<targetKey, version>>`;`dsh-fs` 不持有任何此类数据,并将 actor 视为不透明。(本 Agent Note 最初建模了一个带 `full`/`partial` 视图的 `FileState` 缓存放在 `ctx.fs` 上;split-fs-seam 和 event-gate Agent Note 将其替换为此处描述的基于新鲜度的策略插件。) 路径解析是显式的,允许异步。本地解析可能只做路径规范化,但沙箱/远程/项目作用域的后端可能需要 I/O 才能将用户提供的路径解析为稳定的目标标识。 @@ -83,7 +83,7 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` - 不透明的 `targetKey`,用于陈旧守护和文件状态查找。本地后端可能使用类似 realpath 的键;远程后端可能使用工作区 URI 或文件 id。消费方禁止解析或假设它是本地绝对路径。 - `displayPath`,用于面向模型/UI 的输出。根据后端不同,它可能是本地绝对路径、工作区相对路径或远程 URI。 -读取和变更结果必须包含不透明的文件 `version`。本地后端可以使用 mtime/size 或类似 hash 的令牌;远程后端可以使用 revision id。`dsh-fs-policy` 插件记录版本用于陈旧检查;消费方可以展示相关元数据但禁止解释版本令牌。 +读取和变更结果必须包含不透明的文件 `version`。本地后端从 bigint stat 元数据(`dev`、`ino`、`size`、`mtimeNs` 和 `ctimeNs`)派生令牌,因此同大小重写和 inode 替换都会可靠地使消费方失效;远程后端可以使用 revision id 或类似 hash 的令牌。`dsh-fs-policy` 插件记录版本用于陈旧检查;消费方可以展示相关元数据但禁止解释版本令牌。 提供方返回已解码的文本:`readText` 返回整个常规文本文件,`streamText` 为大文件流式传输相同的文本语义。两者负责常规文件检查;有界的行/输出处理不是它们的职责——行窗口化、带行号渲染和总行数统计位于执行器(`dsh-tool-fs`)中,执行器通过 `ctx.fs` 读取并渲染面向模型的窗口。提供方负责 UTF-8 解码和二进制/NUL 拒绝;它不知道行窗口或视图。 @@ -137,7 +137,7 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` - **面向模型的工具直接基于 `node:fs`**:工具包将同时承担执行策略、路径解析、原子写入、文本解码和编辑语义,耦合问题部分所列的三个独立变化的关注点,且任何后端替换都会搅动 schema。 - **单一合并包 `dsh-fs-tools`**:seam 之前的形态;以与 bash 相同的接口/实现/消费方拆分理由否决,且合并名称从未成为公开接口。 -- **观测状态放在 `ctx.fs` 上**:本 RFC 最初落地的形态;被 [split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate RFC](2026-06-26-file-context-as-event-gate.md) 取代:沙箱/远程后端不应继承面向模型的观测策略,因此提供方只保留版本令牌和可选的版本守护变更。 +- **观测状态放在 `ctx.fs` 上**:本 Agent Note 最初落地的形态;被 [split-fs-seam Agent Note](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate Agent Note](2026-06-26-file-context-as-event-gate.md) 取代:沙箱/远程后端不应继承面向模型的观测策略,因此提供方只保留版本令牌和可选的版本守护变更。 ## 后果 @@ -145,11 +145,11 @@ harness 已有一个具体的 `bash` 能力 seam(`dsh-bash` / `dsh-bash-local` **接口可能变得过于本地化。** 如果 `ctx.fs` 返回 `absolutePath` 之类的字段,远程、沙箱或虚拟后端会变得尴尬。契约应暴露显示元数据,而不要求消费方理解宿主路径。 -**接口可能变得过于薄。** 如果 `ctx.fs` 只镜像 `node:fs` 原语,`tool-fs` 将重新实现二进制检测、分页、原子写入和编辑语义,重新制造本 RFC 试图避免的耦合。 +**接口可能变得过于薄。** 如果 `ctx.fs` 只镜像 `node:fs` 原语,`tool-fs` 将重新实现二进制检测、分页、原子写入和编辑语义,重新制造本 Agent Note 试图避免的耦合。 **编辑语义天然易受竞争影响。** 字面编辑是读-改-写操作;守护手段是后端的原子变更临界区加上可选的版本期望,因此并发编辑确定性地收敛——一个赢,另一个得到 `FS_STALE_VERSION`。 -**观测状态不属于 `ctx.fs`。** 记录执行上下文看到了什么是工作流策略,而非原始文件系统 I/O。本 RFC 最初将其放在文件系统 seam 内部;split-fs-seam RFC 随后确立了沙箱/远程后端不应继承面向模型的观测策略,并将其移入 `dsh-fs-policy` 插件。提供方 seam 只保留写入/编辑安全在存储层真正需要的东西——后端铸造的版本令牌和可选的版本守护变更——而策略插件拥有 owner 推导、观测状态和基于 `fs/*` 事件的读后编辑门控。 +**观测状态不属于 `ctx.fs`。** 记录执行上下文看到了什么是工作流策略,而非原始文件系统 I/O。本 Agent Note 最初将其放在文件系统 seam 内部;split-fs-seam Agent Note 随后确立了沙箱/远程后端不应继承面向模型的观测策略,并将其移入 `dsh-fs-policy` 插件。提供方 seam 只保留写入/编辑安全在存储层真正需要的东西——后端铸造的版本令牌和可选的版本守护变更——而策略插件拥有 owner 推导、观测状态和基于 `fs/*` 事件的读后编辑门控。 **`resolve` 然后操作的形态每次调用多一次往返。** 每个工具可能先将路径解析为 `FsTarget`,再以单独的 `ctx.fs` 调用发起读取/写入/编辑。对本地后端来说这可以忽略(解析是内存中的路径规范化),但远程/沙箱后端可能将每步变成独立请求,使单次 `read` 变为两次网络往返。往返开销重要的后端可以在内部缓存或折叠解析,同时保持可观测契约不变。 diff --git a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml index 34098ed665..a0ab7d1c83 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.i18n.yaml @@ -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 -2026-06-18-agent-lifecycle-and-ownership-seams.md: c37578020366dd40250c061e34a86d2de6907e19 -2026-06-18-agent-lifecycle-and-ownership-seams.zh.md: 1f3cb609da5508d22046f445e08a75dc5a7901cd +2026-06-18-agent-lifecycle-and-ownership-seams.md: 70ebf1c6de97cb14e27377ec1f9bac18fc0766a6 +2026-06-18-agent-lifecycle-and-ownership-seams.zh.md: 2091182b663dfbd1ac306550de60c1f00d12656f diff --git a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md index 3d84c8074b..70ebf1c6de 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md +++ b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-18-agent-lifecycle-and-ownership-seams.zh.md) + ## Problem Several ACP and tool-bash limitations were symptoms of the same missing seam: plugins could create or resume agents through `ctx.agents`, but they could not own and dispose one agent independently, and long-running bash tasks carried no stable owner in the executor itself. ACP aborted and awaited agents on disconnect but could not unregister just that session's agent; `session/cancel` could not cancel queued-but-not-yet-started work; and `tool-bash` kept task ownership in a plugin-local `Map`, so an HMR reload could make an old task look unowned. diff --git a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md index 1f3cb609da..2091182b66 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-18-agent-lifecycle-and-ownership-seams.zh.md @@ -1,4 +1,4 @@ -# RFC: Agent 生命周期与所有权 seam +# Agent Note: Agent 生命周期与所有权 seam Status: implemented @@ -12,36 +12,38 @@ ACP(Agent Client Protocol)与 tool-bash 的若干限制是同一个缺失 se 三个 seam:队列感知的 cancel、`AgentHandle` 释放器,以及 bash 所有者令牌。 -### 1. 队列感知的 `Agent.cancel(reason?)` +### 1. 队列感知的 `Agent.cancel(cause?)` -`cancel()` 是唯一的公开停止原语。它清除已入队和 steering(中途引导)输入、中止正在进行的步骤,并设置一个在每个轮次边界检查的轮次作用域标记。因此,已入队的 prompt 在取消后无法启动,也无法吸收后续输入。`whenIdle()` 等待取消后的静默状态,ACP 的 `session/cancel` 映射到此方法。对空闲状态的 cancel 不设置标记。 +`Agent` 接口新增 `cancel()` 动词——唯一的公开停止原语。(它最初与范围更窄、仅作用于步骤的 `abort()` 一同交付;后者后来因无人使用而移除,使 `cancel()` 成为唯一公开的停止工作方式。)它清空 inbox 的 queued + steering FIFO,在存在活跃轮次时中止它,并保留一个不带 cause 的 pre-run 标记,使在取得所有权前被取消的 prompt 永不运行,而后来的 prompt 仍保持独立。有效调用会在清空或中止前发出 `agent/cancel-requested`,携带类型化的 `user | parent` cause;空闲取消不发出任何事件,也不会使下一条 prompt 搁浅。`whenIdle()` 会到达取消后的静默状态,ACP 的 `session/cancel` 映射到 `user`。[显式轮次取消决策](2026-07-16-explicit-turn-cancellation.md)拥有当前的 cause、signal 生命周期与协作式结算契约。 ### 2. `AgentHandle` 异步释放器 -`ctx.agents.create`/`resume` 和 `AgentFactory` 返回 `AgentHandle = { agent, dispose() }`。释放是消费方的能力;仅持有 `Agent` 的观察者无法将其拆除。调用方 fiber 和 factory 提供方也拥有该实例,所有路径共享一个 memoize 的拆除过程:停止循环、等待静默与刷写完成、分离 agent 和会话,然后解除其 scope。ID 在注册表条目分离后变为可复用。由配置创建的 agent 归 loop fiber 所有;ACP 存储并 dispose 每个会话的 handle。 +`ctx.agents.create`/`resume`(以及 `AgentFactory` 接口)返回 `AgentHandle = { agent: Agent; dispose(): Promise<void> }`。释放器是一种**消费方能力**——仅持有裸 `Agent` 的注册表观察者无法将其拆除。调用方 fiber 和已注册的 factory 提供方是结构上的共同所有者:调用方卸载强制结构化所有权,而提供方卸载必须停止旧实例,因为其实例作用域的依赖 surface 通过该提供方解析。三条路径都会进入同一个 memoize 的拆除过程:停止循环、等待其退出与空闲刷写完成(真正的静默,而非仅把状态翻转为 `disposed`)、分离 agent、分离其会话,然后解除其 scope。每个公开 ID 在其精确注册表条目分离时变得可复用;不存在独立的保留释放阶段。由配置创建的 agent 已归 `AgentLoop` fiber 所有(handle 被丢弃)。ACP 在其 `SessionRecord` 中保存每个会话的释放器,并在断连/拆除时运行它,因此单纯的客户端断连不会留下已注册 agent 或 session-store 条目——即使 `session/load` 与拆除竞争(刚恢复的 handle 会在 closed-guard 抛出前释放)。 -拆除顺序对持久性至关重要。会话生命周期与循环共享一个复合 Cordis effect,因此 LIFO 释放会先停止循环并等待 `agent.done`,然后再分离会话。若使用兄弟 effect,则会并发释放,可能在关闭刷写之前就移除 append 钩子。释放通知被隔离,不会中断拆除链。 +**拆除顺序对持久性至关重要**,实现将会话生命周期折叠进 agent 的单个复合 Cordis effect(`SessionStore.prepare`/`enter`/`announce`,取代兄弟 effect 拆分)。fiber 卸载会并发释放兄弟 effect(`Promise.all`),这会让 session store 的 append 发布钩子移除与循环关闭时的 `session/flush` 竞争,从而丢失关闭的 `turn/end`;在一个 effect 内,释放器作为有序的 LIFO 链运行(停止循环 + `await agent.done` 在会话分离之前),因此无论 handle 的 `dispose()` 还是 fiber 卸载,都会捕获循环的最终刷写。被隔离的 `agent/disposed` 和 `session/disposed` 通知无法拒绝该链或跳过后续拆除。 ### 3. Bash seam 中的所有者令牌 -后台任务的所有权属于执行器。`BashExecSpec.owner` 携带一个可选的不透明令牌,`ownerOf(id)` 读取它,`dsh-tool-bash` 在启动时盖上调用方的会话令牌。`bash_output` 和 `bash_kill` 拒绝不匹配的调用方;完成通知通过注册表按会话令牌定位存活的 agent。将所有权保存在任务上,使得这道隔离在工具插件重载后依然有效。完成监听器仍然是 effect 作用域的,因此在重载间隙到达的通知仍可能被丢弃。 +后台任务所有权从 `tool-bash` 插件本地的 `Map<string, Agent>` 移入执行器。`BashExecRequest` 新增可选的 `owner?: string`;解析后的 `BashExecSpec` 将其作为必需但可空的 `owner: string | undefined` 携带(被遗忘的 owner 是可见的 `undefined`,而非静默缺失的属性)。执行器把 token 存在任务上,并通过新的 `BashExecutor.ownerOf(id): string | undefined` seam 暴露它(不放在公开的 `BashTask` 上——只有一条读取路径,没有冗余 API)。`tool-bash` 完全删除其 `Map`:它在 `start` 时将 `exec.agent?.id`(共享的注册表/会话 id)盖章为 owner,`bash_output`/`bash_kill` 则以 `!== undefined` 语义把 `ctx.bash.ownerOf(id)` 与调用方 token 比较(空字符串 token 仍是真实 owner)。完成通知通过扫描 `ctx.get('agents')?.list()` 查找 `agent.id === ownerToken` 的存活 agent(经 `ctx.get` 读取——`onTaskDone` 运行在 bash fiber 这一外部 fiber 上,直接使用 `ctx.agents` proxy 会抛异常)。由于所有权现在存活在执行器的任务上(随 `dsh-bash` fiber dispose),它能跨越 `tool-bash` HMR 重载,关闭旧的 `XXX(tool-bash-owner-hmr)` 缺口。(`onTaskDone` 监听器仍受 `tool-bash` 的 `apply` effect 约束,因此落在重载间隙的完成仍会丢失一条通知——既有的重载间隙丢失——但所有权隔离本身已经不受 HMR 影响。) ## 验证 -- ACP 断连或会话关闭后,不留下任何已注册的 agent 或 session-store 条目,包括 `session/load` 与拆除竞争的情况。 -- 在已入队的 prompt 启动前取消,能阻止该 prompt 运行或吸收下一条 prompt。 -- 重载 `dsh-tool-bash` 不会让另一个会话读取或终止已有的后台任务,因为所有权保留在执行器上。 -- 由配置创建的 agent 仍归 loop fiber 所有,因此非 ACP 演示无需显式管理 handle。 +以下不变式已经成立,并由测试固定: + +- ACP 断连/会话关闭后,不留下该会话的任何已注册 agent 或 session-store 条目,即使 `session/load` 与拆除竞争。 +- 已入队的 prompt 启动前执行 `session/cancel`,能阻止该 prompt 运行;后来接受的 prompt 仍是独立的已入队轮次。 +- `tool-bash` HMR 重载不会使另一个会话能够读取或终止已有的后台任务(所有权保留在执行器上)。 +- 既有的非 ACP 演示无需显式管理 handle 仍能工作;由配置创建的 agent 仍归 `AgentLoop` 插件 fiber 所有。 ## 会话所有者令牌在存活 agent 中唯一 -bash 所有者令牌依赖 `session.header.id` 在存活 agent 中的唯一性。并发的同 ID 操作可以私下准备,但 `SessionStore.enter()` 拒绝重复发布,失败的事务回滚。`tool-bash` 拥有比较策略;bash seam 存储一个不透明的 `owner` 字符串,不对其做解释。 +bash 所有者 token 比较依赖共享的 `Agent.id`/`SessionId` 在存活 agent 中唯一。并发的同 ID 操作可以都私下准备,但发布会依次进入 session 和 agent;`SessionStore.enter()` 拒绝重复的存活 session id,每个失败事务都回滚自己的私有状态。因此程序化调用方无法发布两个共享同一会话 token 的存活 agent。访问*策略*(token 比较)留在消费方 `tool-bash`;bash seam 只存储不透明的 `owner` 字符串且从不解释它——这是正确的接口/实现/消费方拆分。 ## 曾考虑的替代方案 - **公开的 `BashTask.owner` 字段**而非 `BashExecutor.ownerOf(id)` seam:否决。一条读取路径即可,无需冗余 API。 - **为 agent 的会话生命周期使用兄弟 Cordis effect**:否决。fiber 卸载时并发释放兄弟 effect(`Promise.all`),store 拥有的 append 发布钩子的移除与循环的关闭 `session/flush` 产生竞争;单一复合 effect 的有序 LIFO 链才能在两条释放路径上都捕获关闭的 `turn/end`。 -- **在 `cancel()` 之外另设一个仅中止步骤的 `abort()`**:最初发布过,后因无人使用而移除;`cancel()` 是唯一的公开停止原语(见[公开停止接口 RFC](../simplification/2026-06-20-public-agent-stop-surface.md))。 +- **在 `cancel()` 之外另设一个仅中止步骤的 `abort()`**:最初发布过,后因无人使用而移除;`cancel()` 是唯一的公开停止原语(见[公开停止接口 Agent Note](../simplification/2026-06-20-public-agent-stop-surface.md))。 ## 后果 diff --git a/.agents/notes/implemented/architecture/2026-06-18-session-surface.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-18-session-surface.i18n.yaml index c319a372fe..578187d1aa 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-session-surface.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-18-session-surface.i18n.yaml @@ -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 -2026-06-18-session-surface.md: bcad236eaa2bead3c140e7a12772729710d43f83 -2026-06-18-session-surface.zh.md: 2ec60501c183d1bdab22ceb67b7f6aa0040ae82b +2026-06-18-session-surface.md: 80034881d0112076759a68737b5931c8ff659d15 +2026-06-18-session-surface.zh.md: 49303c87aa87569bcc61f215642c9b7f0c408dbf diff --git a/.agents/notes/implemented/architecture/2026-06-18-session-surface.md b/.agents/notes/implemented/architecture/2026-06-18-session-surface.md index f1297b1f05..80034881d0 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-session-surface.md +++ b/.agents/notes/implemented/architecture/2026-06-18-session-surface.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-18-session-surface.zh.md) + ## Problem The event log is authoritative, but history manipulation had no durable shared mechanism. Plugins such as compaction would otherwise rewrite derived requests through order-sensitive listeners, leave no provenance, and require repeated changes to `deriveMessages()`. diff --git a/.agents/notes/implemented/architecture/2026-06-18-session-surface.zh.md b/.agents/notes/implemented/architecture/2026-06-18-session-surface.zh.md index 2ec60501c1..49303c87aa 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-session-surface.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-18-session-surface.zh.md @@ -1,4 +1,4 @@ -# RFC: 会话 surface——基于事件日志的链表,用于 LLM 消息派生 +# Agent Note: 会话 surface:事件日志上的有序投影 Status: implemented @@ -10,13 +10,13 @@ Status: implemented ## 决策 -新增一个 **surface**:一条派生的、缓存的链表,由「surface 节点」(事件中产出 LLM(大语言模型)消息的子集)组成,通过事件日志中的 `surfaceOp` 标记维护。 +新增一个 **surface**:事件 seq 的派生、缓存有序投影(即产出 LLM(大语言模型)消息的事件子集),通过事件日志中的 `surfaceOp` 标记维护。 ### `SessionEvent` 新增两个顶层字段 每个 `SessionEvent` 获得两个可选字段(结构性元数据,与 `seq`/`time` 同级): -- **`sourceEventSeqs?: number[]`**:作为溯源来源的事件 seq 编号(例如构成 `assistant/message` 的各 `assistant/chunk` 的 seq,或被压缩标记遮蔽的 surface 节点)。溯源是核心设计原则;没有它,replace-range 操作在回放时无法被验证。 +- **`sourceEventSeqs?: number[]`**:作为溯源来源的事件 seq 编号(例如构成 `assistant/message` 的各 `assistant/chunk` 的 seq,或被压缩标记遮蔽的 surface 节点)。出现的 `[]` 只在 `assistant/message` 上有效,表示已知为空的提供方流;在该事件上省略字段表示旧数据或未记录的溯源。其他 surface 事件一旦出现此字段,就必须是非空列表。溯源是核心设计原则;没有它,replace-range 操作在回放时无法被验证。 - **`surfaceOp?: SurfaceOp`**:该事件如何进入 surface。非 surface 事件不携带此字段。 ### SurfaceOp:两种操作 @@ -27,13 +27,13 @@ export type SurfaceOp = | { op: 'replace'; start: number; end: number } // shadow [start, end] inclusive ``` -1. **Append**:在尾部追加一个新节点。`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message` 使用此操作。agent loop(智能体循环)在所有此类追加上传入 `surfaceOp: 'append'`,并在适用时附带 `sourceEventSeqs`(例如 `assistant/message` 记录其 `assistant/chunk` 来源;`tool/result` 记录其 `tool/call` 来源)。 +1. **Append**:在尾部追加新事件的 seq。`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message` 使用此操作。agent loop(智能体循环)在所有此类追加上传入 `surfaceOp: 'append'`,并在适用时记录 `sourceEventSeqs`:每个成功的 `assistant/message` 都记录完整的 `assistant/chunk` 来源集合(包括 `[]`),而 `tool/result` 记录其 `tool/call` 来源。 -2. **Replace**:移除从 `start` 到 `end`(两端包含)的节点,并在其位置插入一个新节点。`start` 和 `end` 都必须是当前 surface 上有效的 surface 节点 seq;`start === end` 表示替换单个节点。该节点的 `sourceEventSeqs` 必须包含所有被遮蔽的 surface 节点。被遮蔽的事件仍留在日志中,但不再出现在 surface 上。 +2. **Replace**:移除从 `start` 到 `end`(两端包含)的条目,并在其位置插入新事件的 seq。`start` 和 `end` 都必须存在于当前 surface;`start === end` 表示替换单个条目。该事件的 `sourceEventSeqs` 必须包含所有被遮蔽的 surface seq。被遮蔽的事件仍留在日志中,但不再出现在 surface 上。 ### SurfaceManager:基于增量,而非全量重建 -`SurfaceManager` 类(`Session` 私有)维护缓存的链表。它跟踪 `_lastProcessedSeq`,仅处理**增量**(自上次访问以来的新事件),而非重新扫描整个日志。由于日志是仅追加的,先前的事件不会改变;种子日志只是在首次访问时折叠的初始增量。 +一个 `Session` 拥有一个 `SurfaceManager`,后者维护事件 seq 的有序 `number[]`。管理器会在提交前校验每个种子或追加候选项而不应用它,然后只处理上次同步之后已经提交的事件,而不重新扫描整个日志。`Session.surface` 通过只读的 `SessionSurface` 契约暴露同一个管理器,因此接纳、派生历史、压缩与工作区上下文共享同一份增量状态。Replace 按数组位置找到两端都包含的端点,并把替换 seq splice 到该范围;不会用第二个管理器、链接对象或 seq 到节点的 map 来重复表达顺序。 无新事件时增量处理为 O(1),有新事件到达时为 O(新事件数)。 @@ -49,23 +49,25 @@ export type SurfaceOp = ### 不变式 -开发模式下的不变式插件验证:`sourceEventSeqs` 引用(非空、无重复、引用更早的事件、引用已知 seq)以及 `surfaceOp`(replace 的 `start ≤ end`、两个端点都在被跟踪的 surface 上、范围在 surface 位置上不反转、`sourceEventSeqs` 包含该范围遮蔽的每个节点)。 +`Session` 在始终启用的 seed/append 边界校验 `sourceEventSeqs` 与 `surfaceOp`:只有 `assistant/message` 可以使用空的溯源列表;引用必须唯一、更早且已知;替换端点必须存在于 surface 顺序中;溯源必须覆盖每个被遮蔽的节点。这些是单记录接纳与存储投影规则,不是可选的不变式服务贡献。 每个 surface 可达事件都必须携带 `surfaceOp`,否则它将从派生历史中消失。类型化的 `append` 重载对字面事件类型强制执行此规则;`append` 和种子构造函数中的运行时检查覆盖宽化联合类型和加载的日志。按照预发布格式策略,无效的种子被拒绝而非升级。 ## 曾考虑的替代方案 - **逐插件的 `agent/request` 包装**(surface 之前的历史操纵模式):监听器排序脆弱、无法持久记录改动内容,且每种新操纵都迫使核心 `deriveMessages()` 再次修改。 -- **半开区间 `[start, endExclusive)` 的 replace 范围**:否决。surface 是双向链表,端点自然以节点 seq 命名,单节点替换(`start === end`)在闭区间语义下读起来更自然。 +- **半开区间 `[start, endExclusive)` 的 replace 范围**:否决。端点由 surface 事件 seq 命名,单条目替换(`start === end`)在闭区间语义下读起来更自然。 +- **链接节点对象加 seq map**:否决。生产代码不读取前驱链接,唯一的后继用途就是数组中的下一个位置,而替换本来就需要线性 `indexOf` 查找。单个 seq 数组在保留相同渐进复杂度的同时,只留下一个需要校验的表示。 - **脏标记后全量重建**替代增量处理:在会话生命周期内为 O(N²),每次单事件追加都要重新扫描所有先前事件。 ## 后果 -- **`packages/core/session`**:新增 `surface.ts`(`SurfaceManager`)、新类型(`SurfaceOp`、`SurfaceIntent`)、`SessionEvent` 新字段、修改 `append()`(第三个必选参数 `SurfaceIntent`)、重构 `deriveMessages()`(以 surface 遍历作为唯一派生路径)、surface 感知的 `repair.ts`。种子构造函数拒绝缺少 `surfaceOp` 标记的 surface 可达种子事件(见「不变式」一节)。 +- **`packages/core/session`**:`surface.ts`(`SurfaceManager`)维护一个用于候选接纳和实时投影的有序 seq 数组;`SessionSurface` 是其只读公共视图。`SurfaceOp`/`SurfaceIntent` 与顶层会话事件字段记录条目如何加入它。`append()` 要求 surface 事件携带 `SurfaceIntent`,`deriveMessages()` 以遍历 surface 作为唯一派生路径,`repair.ts` 则发出 surface 感知的闭合事件。种子构造函数拒绝缺少 `surfaceOp` 标记的 surface 可达种子事件(见「不变式」一节)。 - **`packages/core/agent-loop`**:所有 surface 可达的追加操作传入 surface 选项。收集 chunk seq 用于 `assistant/message` 溯源;捕获 `tool/call` seq 用于 `tool/result` 溯源。 - **`packages/session-persistence/session-persistence-sqlite`**:`events` 表新增两个可空 TEXT 列(`source_event_seqs`、`surface_op`);`SCHEMA_VERSION` 递增(bump-and-reject,无迁移)。 -- **`packages/support/invariants`**:surface 相关验证规则。 - **`packages/session-persistence/session-persistence-jsonl`**:无需改动。 - **`packages/session-persistence/session-persistence`**:抽象接口不变。 -Surface 是未来历史操纵的基础。压缩或 tool-result-prune 插件追加一个既有的消息产出事件类型(例如一条携带摘要的 `user/message`),附带 `surfaceOp: { op: 'replace', start, end }` 和覆盖被遮蔽节点的 `sourceEventSeqs`——新节点在 surface 上取代该范围的位置,而插件自身的 trace 事件(如 `compaction/start`、`compaction/end`)不进入 surface。回放以确定性方式保留该决策。 +Surface 是未来历史操纵的基础。压缩或 tool-result-prune 插件追加一个既有的消息产出事件类型(例如一条携带摘要的 `user/message`),附带 `surfaceOp: { op: 'replace', start, end }` 和覆盖被遮蔽条目的 `sourceEventSeqs`——新事件在 surface 上取代该范围的位置,而插件自身的 trace 事件(如 `compaction/start`、`compaction/end`)不进入 surface。回放以确定性方式保留该决策。 + +一次 `tool/result` 替换只能改写当前的一个 `tool/result`,并且必须保留除 `content` 以外的每个数据字段。Session 接纳会与位置范围和溯源校验一起强制这条规则,不依赖可选的诊断插件。 diff --git a/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml index e960781d12..8d572c486f 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml @@ -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 -2026-06-18-shared-persistence-write-coordinator.md: 7648c6f8e43fb8c78f881838aa4d476aba209dca -2026-06-18-shared-persistence-write-coordinator.zh.md: 19f583c2f3d78fcdac1378cfe00e49c0be943eb1 +2026-06-18-shared-persistence-write-coordinator.md: 12800b118bd2fd1189319d0edf37cace3d916a9c +2026-06-18-shared-persistence-write-coordinator.zh.md: 23d6c66989880369c4e26c38145559c198ea1033 diff --git a/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md b/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md index 19f583c2f3..23d6c66989 100644 --- a/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.zh.md @@ -1,4 +1,4 @@ -# RFC: 共享持久化写入协调器 +# Agent Note: 共享持久化写入协调器 Status: implemented @@ -12,7 +12,9 @@ Status: implemented 将一个后端无关的 `PersistenceCoordinator` 提取到 `dsh-session-persistence` 中。协调器统一拥有编排逻辑;每个第一方后端组合一个协调器实例(`new PersistenceCoordinator(ctx, this)`),实现一个小型 `PersistenceBackend` 钩子接口,并将其四个公开服务方法(`create`/`append`/`load`/`list`)委托给协调器。 -组合,而非继承。协调器是后端持有的具体类,不是后端继承的基类。本 RFC 的风险——「协调器不得让非常规后端与继承层级作斗争」——由此规避:后端只暴露钩子;它无法触及协调器的私有编排状态,且公开的 `SessionPersistence` 服务形状不变,因此第三方后端仍然可以完全不使用协调器、直接实现抽象服务。 +组合,而非继承。协调器是后端持有的具体类,不是后端继承的基类。本 Agent Note 的风险——「协调器不得让非常规后端与继承层级作斗争」——由此规避:后端只暴露钩子;它无法触及协调器的私有编排状态,且公开的 `SessionPersistence` 服务形状不变,因此第三方后端仍然可以完全不使用协调器、直接实现抽象服务。 + +协调器通过每个存活会话的 `session/disposed` 通知将其退役:等待该 Session 对象自身的初始化,串行执行最后一次排空,随后移除其拥有的状态、缓冲区和初始化条目。排空失败时保留缓冲区,供后端 teardown(拆除)重试。每个 id 的已结算链尾仅在其仍是当前链尾时才移除自身,因此旧操作完成后不会抹除同一 id 的新操作。后端 teardown 会先注销写入路径监听器,再等待所有已准入的退役、剩余缓冲区和链,最后关闭后端。 ### 钩子接口(`PersistenceBackend<TornMarker>`) @@ -28,11 +30,11 @@ Status: implemented ### 不透明的 torn marker -保持 seam 整洁的唯一设计选择:崩溃修复中「损坏尾部在哪里」的 token 对协调器是不透明的。协调器计算合成 closers(它拥有来自 `dsh-session` 的 `interruptedTurnClosers`),但它只测试 `tornMarker !== undefined` 并将值原样传回 `commitRepair`——从不检视其内容。每个后端选择自己的 marker 类型:JSONL 使用要截断到的字节偏移,SQLite 使用要从其开始删除的 seq(两者恰好都是 `number`)。JSONL 后端将其 `committedBytes < buffer.byteLength` 比较折叠在钩子内部,因此返回的 marker 已经是 `number | undefined`;如果不做这层折叠,协调器就必须了解字节长度。 +保持 seam 整洁的唯一设计选择:崩溃修复中「损坏尾部在哪里」的 token 对协调器是不透明的。协调器计算合成 closers(它拥有来自 `dsh-session` 的 `interruptedTurnClosers`),但它只测试 `tornMarker !== undefined` 并将值原样传回 `commitRepair`——从不检视其内容。每个后端选择自己的 marker 类型:JSONL 携带要截断到的字节偏移,以及从不完整最终帧中解码出的任何完整事件;SQLite 则携带要从其开始删除的 seq。协调器因此既不了解字节长度,也不了解帧恢复状态。 ## 测试 -共享的 `runPersistenceContract`(公开 API 契约)继续为每个后端运行。新增的 `runCoordinatorContract`(`tests/coordinator-contract.ts`)覆盖写入路径编排——接管、HMR、碰撞、dispose 排空、崩溃尾部修复——通过 `CoordinatorFixture`(内存参考实现 + jsonl + sqlite)为每个后端运行一次。各后端自身的测试规格缩减为仅覆盖存储机制(JSONL:路径安全、fsync 回滚、bucket 列举;SQLite:schema 版本、`scanRows`、事务回滚)。每个真实后端有一个经由协调器的 torn-tail→load→`commitRepair` 测试(通过 `corruptTail` fixture(测试前置数据)钩子),确保协调器的 torn-marker 修复分支在 100% per-file 门禁下被覆盖——契约崩溃测试只产生合成 closers 而不产生 torn marker,因此无法触达该分支。 +共享的 `runPersistenceContract`(公开 API 契约)继续为每个后端运行。`runCoordinatorContract`(`tests/coordinator-contract.ts`)覆盖写入路径编排——接管、HMR、碰撞、会话与后端 dispose 排空,以及崩溃尾部修复——通过 `CoordinatorFixture`(内存参考实现 + jsonl + sqlite)为每个后端运行一次。协调器专属测试固定退役 map 清理、同 id 链尾竞态、排空失败后的重试,以及关闭顺序。各后端自身的测试规格只保留存储机制(JSONL:路径安全、fsync 回滚、bucket 列举;SQLite:schema 版本、`scanRows`、事务回滚)。每个真实后端有一个经由协调器的 torn-tail→load→`commitRepair` 测试(通过 `corruptTail` fixture(测试前置数据)钩子),确保协调器的 torn-marker 修复分支在 100% per-file 门禁下被覆盖——契约崩溃测试只产生合成 closers 而不产生 torn marker,因此无法触达该分支。 ## 曾考虑的替代方案 @@ -41,4 +43,4 @@ Status: implemented ## 后果 -协调器增加了一层间接和一个不透明的 torn marker,但将此前每个后端重复的、对正确性要求很高的编排逻辑集中到一处。其钩子面保持窄小:碰撞检查复用 `loadStored`,物化保持在 `appendBatch` 内原子完成,列举绕过协调器。新后端只需实现存储原语,而无需复制事件-缓冲区-flush 生命周期。 +协调器增加了一层间接、一个不透明的 torn marker 和脱离会话生命周期的退役任务,但将此前每个后端重复的、对正确性要求很高的编排逻辑集中到一处。会话 dispose 仍是仅观察事件,因此会话所有者不会等待持久化退役;协调器会收容失败、保留未提交的缓冲区,并以后端 teardown 为静止状态边界。其钩子面保持窄小:碰撞检查复用 `loadStored`,物化保持在 `appendBatch` 内原子完成,列举绕过协调器。新后端只需实现存储原语,而无需复制事件-缓冲区-flush 生命周期。 diff --git a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml index 7d33e94f0a..29c4f4724d 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.i18n.yaml @@ -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 -2026-06-20-branded-ids.md: aab47a1413451edb707ae797e5b99cda6e34efad -2026-06-20-branded-ids.zh.md: 1ccfda3282069510bcdbfbddf4546305fd0923a5 +2026-06-20-branded-ids.md: 93bab1d47c793cc4dd1f1d19fa3af22d1721be29 +2026-06-20-branded-ids.zh.md: f45f39cc3a49f7abf116e77f1ace2db74fc3de67 diff --git a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.md b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.md index e7a3110fce..93bab1d47c 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.md +++ b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-20-branded-ids.zh.md) + ## Problem The harness brands `CallId` (`packages/llm/llm/src/brand.ts`) and the shared agent/session `SessionId` (`packages/core/session/src/types.ts`) using the `Branded<B> = string & { readonly [BRAND]: B }` machinery (owned by the type-only `@deepseek-ai/dsh-brand` package at `packages/util/brand/` — see its [README](../../../../packages/util/brand/README.md)) and a zero-cost cast factory per type. `dsh-brand` also states the governing policy: *"Branding is for ids that cross package boundaries and could plausibly be confused; not every string needs a brand."* That policy is right; the problem is that it is only half-applied. Two gaps let a structurally-identical-but-semantically-wrong string slip through the type checker today. diff --git a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md index 1ccfda3282..f45f39cc3a 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-20-branded-ids.zh.md @@ -1,4 +1,4 @@ -# RFC: 在所有应有之处使用 branded ID +# Agent Note: 在所有应有之处使用 branded ID Status: implemented @@ -6,23 +6,23 @@ Status: implemented ## 问题 -harness 已经为三个标识符做了 brand 处理:`CallId`(`packages/llm/llm/src/brand.ts`)、`SessionId`(`packages/core/session/src/types.ts`)和 `AgentId`(`packages/core/agent/src/types.ts`),使用 `Branded<B> = string & { readonly [BRAND]: B }` 机制(由纯类型包(package) `@deepseek-ai/dsh-brand` 拥有,位于 `packages/util/brand/`,见其 [README](../../../../packages/util/brand/README.md)),并为每个类型提供零开销的 cast 工厂。`dsh-brand` 还声明了治理策略:*"Branding 用于跨包边界且可能被混淆的 id;不是每个 string 都需要 brand。"* 这条策略是正确的;问题在于它只落实了一半。两处缺口使得结构相同但语义错误的 string 今天仍能通过类型检查器。 +harness 使用 `Branded<B> = string & { readonly [BRAND]: B }` 机制,为 `CallId`(`packages/llm/llm/src/brand.ts`)和共享的 agent/session `SessionId`(`packages/core/session/src/types.ts`)做 brand 处理;该机制由纯类型包(package) `@deepseek-ai/dsh-brand` 拥有,位于 `packages/util/brand/`,见其 [README](../../../../packages/util/brand/README.md),并为每个类型提供零开销的 cast 工厂。`dsh-brand` 还声明了治理策略:*「Branding 用于跨包边界且可能被混淆的 id;不是每个 string 都需要 brand。」* 这条策略是正确的;问题在于它只落实了一半。两处缺口使得结构相同但语义错误的 string 今天仍能通过类型检查器。 -**缺口 1:bash seam 中未 brand 的 ID。** `BashTask.id` 以及所有执行器/工具边界使用裸 `string`,尽管生成的值与默认 session id 具有相同的 `name-N` 形状。模型还通过 `task_id` 返回该值,因此混淆 task id 和 session id 既类型正确又可达。 +**缺口 1:bash seam 中未 brand 的跨边界 ID。** 后台任务 id 是普通 `string`:`BashTask.id: string`(`packages/bash/bash/src/types.ts`),作为 `string` 贯穿整个执行器 seam(`packages/bash/bash/src/index.ts` 中的 `BashExecutor.get`/`ownerOf`/`readOutput`/`kill(id: string)`),再由面向模型的工具以 `string` 校验并传递(`validateTaskId`、`assertTaskAccess`、`packages/bash/tool-bash/src/index.ts` 中 `task_id` 的 schema 参数)。它由每执行器计数器生成——`packages/bash/bash-local/src/index.ts` 中的 `` `bash-${this.nextTaskId++}` ``——其形状与 `SessionId` 的默认值**完全相同,都是 `name-N`**(`packages/core/session/src/index.ts` 中的 `` `session-${++counter}` ``)。bash task id 和 session id 在调用点轻易就能互换,而编译器毫无反应。这是用户询问的核心案例,并且它是面向模型的 id(模型会把 `task_id` 传回 `bash_output`/`bash_kill`),所以该混淆可由不受信任的输入触达。 -bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 和 `BashExecSpec.owner: string | undefined`(`packages/bash/bash/src/types.ts`)被文档描述为刻意*不透明*的隔离键,但在所有实际调用方中,该值就是所属 agent(智能体)的 `session.header.id`(`callerToken = (exec) => exec.agent?.session.header.id`,位于 `packages/bash/tool-bash/src/index.ts`),即一个穿着 `string` 外衣的 `SessionId`。它被用于访问控制比较(`owner !== callerToken(exec)`),因此一个不匹配但类型正确的 string 在此处就是一个跨会话隔离 bug,而当前类型系统无法捕获。这正是 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案所称的以 `session.header.id` 作为 owner 的别名缺口("bash owner-token alias hole")。 +bash **owner token** 是相关的子情形:`BashExecRequest.owner?: string` 和 `BashExecSpec.owner: string | undefined`(`packages/bash/bash/src/types.ts`)被文档描述为刻意*不透明*的隔离键,但在所有实际调用方中,该值就是所属 agent(智能体)共享的 `Agent.id`/`SessionId`(`callerToken = (exec) => exec.agent?.id`,位于 `packages/bash/tool-bash/src/index.ts`),只是披着另一个 seam 本地名称。它被用于访问控制比较(`owner !== callerToken(exec)`),因此一个不匹配但类型正确的 string 在此处就是跨会话隔离 bug,而当前类型系统无法捕获。这正是[统一 agent/session 标识决策](../simplification/2026-06-20-unify-agent-and-session-id.md)覆盖的共享 id 别名。 -**缺口 2:既有 brand 的侵蚀。** `CallId`、`SessionId` 和 `AgentId` 在注册表 map、公开查找参数、ACP 会话跟踪和持久化协调器中退化为裸 string。在查找边界丢弃 brand 会使其主要保护失效。 +**缺口 2:*已经 brand* 的 ID 在 seam 处被侵蚀。** 就连 `CallId` 和 `SessionId` 也恰好在最容易混淆的地方退化为裸 `string`:注册表/store 键类型和公开方法参数。代表性位置包括 session store、agent 注册表(二者都以共享的 `SessionId` 为键)、`ToolPresenter` 的 call-id map、ACP 的 session-id 记录和 loading set,以及持久化协调器。在集合键处丢弃 brand,会让既有 brand 在查找时毫无价值;它们的价值只实现了一部分。 ## 决策 -纯类型变更。Brand 是零开销 cast;运行时行为、序列化、比较和协议格式(wire format)均不变。工作分三部分,全部遵循既有的"不是每个 string 都需要"策略。 +纯类型变更。Brand 是零开销 cast;运行时行为、序列化、比较和协议格式(wire format)均不变。工作分三部分,全部遵循既有的「不是每个 string 都需要」策略。 -- **为 bash task id 加 brand。** 在 `packages/bash/bash/src/types.ts`(*拥有*该 id 的包)中添加 `BashTaskId = Branded<'BashTaskId'>` 及其同名工厂,从 `@deepseek-ai/dsh-brand` 导入 `Branded`,方式与 `SessionId`/`AgentId` 完全一致。brand 原语位于无依赖的 `dsh-brand` 工具包中,正是为了让 `dsh-bash` 仅依赖它就能为自己的 id 加 brand,而无需引入 `dsh-llm`(或 `dsh-session`)来获取 `Branded`。将其贯穿 `BashTask.id`、`BashExecutor` seam 方法(`get`/`ownerOf`/`readOutput`/`kill`)、`dsh-bash-local` 中的生成点(在创建时对计数器输出做一次 brand),以及 `dsh-tool-bash` 的校验/访问面(`validateTaskId` 返回 `BashTaskId`;`task_id` 在模型 string 到达的工具边界处被 brand)。 +- **为 bash task id 加 brand。** 在 `packages/bash/bash/src/types.ts`(*拥有*该 id 的包)中添加 `BashTaskId = Branded<'BashTaskId'>` 及其同名工厂,从 `@deepseek-ai/dsh-brand` 导入 `Branded`,方式与 `SessionId` 完全一致。brand 原语位于无依赖的 `dsh-brand` 工具包中,正是为了让 `dsh-bash` 仅依赖它就能为自己的 id 加 brand,而无需引入 `dsh-llm`(或 `dsh-session`)来获取 `Branded`。将其贯穿 `BashTask.id`、`BashExecutor` seam 方法(`get`/`ownerOf`/`readOutput`/`kill`)、`dsh-bash-local` 中的生成点(在创建时对计数器输出做一次 brand),以及 `dsh-tool-bash` 的校验/访问面(`validateTaskId` 返回 `BashTaskId`;`task_id` 在模型 string 到达的工具边界处被 brand)。 -- **铸造独立的 `OwnerToken` brand。** 在 `packages/bash/bash/src/types.ts` 中添加 `OwnerToken = Branded<'OwnerToken'>`;将 `BashExecRequest.owner` / `BashExecSpec.owner` / `BashExecutor.ownerOf` 的类型标注为 `OwnerToken | undefined`。`dsh-tool-bash` 消费方在边界处将 agent 的 `session.header.id`(一个 `SessionId`)cast 为 `OwnerToken`——这是两套词汇唯一交汇的地方。bash seam 从不导入 `dsh-session`。(理由见下一节。) +- **铸造独立的 `OwnerToken` brand。** 在 `packages/bash/bash/src/types.ts` 中添加 `OwnerToken = Branded<'OwnerToken'>`;将 `BashExecRequest.owner` / `BashExecSpec.owner` / `BashExecutor.ownerOf` 的类型标注为 `OwnerToken | undefined`。`dsh-tool-bash` 消费方在边界处将 agent 共享的 `id`(`SessionId`)cast 为 `OwnerToken`——这是两套词汇唯一交汇的地方。bash seam 从不导入 `dsh-session`。(理由见下一节。) -- **阻止 brand 侵蚀。** 将既有 brand 传播到缺口 2 列出的 `Map` 键类型和公开方法参数中:`Map<SessionId, Session>`、`get(id: SessionId)`、`Map<AgentId, Agent>`、`Map<CallId, …>`、ACP 的 `SessionRecord.sessionId: SessionId` 接口、协调器的 `Map<SessionId, …>`。这是 diff 中机械量最大的部分,也是让*既有* brand 在查找处真正发挥作用(而不仅仅标注在结构体字段上)的关键。 +- **阻止 brand 侵蚀。** 将既有 brand 传播到缺口 2 列出的 `Map` 键类型和公开方法参数中:`Map<SessionId, Session>`、`Map<SessionId, Agent>`、`get(id: SessionId)`、`Map<CallId, …>`、ACP 的 `SessionId` surface、协调器的 `Map<SessionId, …>`。这是 diff 中机械量最大的部分,也是让*既有* brand 在查找处真正发挥作用(而不仅仅标注在结构体字段上)的关键。 示意形状(工厂模式与已有的三个 brand 完全一致): @@ -46,24 +46,24 @@ export function OwnerToken(id: string): OwnerToken { ### 为什么不把 `owner` 类型标注为 `SessionId`? -执行器将 ownership 视为不透明的,不应依赖 session 模型。独立的 `OwnerToken` 保留了这一边界,同时防止裸 string 或 task id 被当作 owner 传入。`dsh-tool-bash` 拥有访问策略,由它执行来自 `SessionId` 的唯一转换。 +显而易见的捷径是直接把 `owner` 类型标注为 `SessionId`——它确实*总是*一个 session id。我们否决这个方案。bash 执行器 seam 是能力 seam(接口 `dsh-bash`、实现 `dsh-bash-local`、消费方 `dsh-tool-bash`),其 owner token 被*明确记录为刻意不透明*:执行器「从不解释它(seam 中没有访问策略——那是消费方的职责)」(`packages/bash/bash/src/types.ts`)。把 seam 字段类型标注为 `SessionId`,会把 `dsh-session` 的词汇引入一个不应知道 owner token *含义*的包——这会让通用执行后端耦合 session 模型,并违背不透明 token 的设计。取代 `dsh-bash-local` 的沙箱或远程执行器不应继承 session 依赖。独立的 `OwnerToken` brand 使 seam 保持解耦:`dsh-bash` 只知道「owner 是某种带 brand 的不透明 token」,而已经决定访问策略的 `dsh-tool-bash` 消费方,是把其 `SessionId` cast 为 `OwnerToken` 的唯一边界。该 brand 仍带来安全收益(不能把 `BashTaskId` 或裸 string 传到 owner 位置),且不引入耦合。 ## 不在范围内 / 可能的扩展 -遵循"不是每个 string 都需要 brand"的策略,刻意保持窄范围。以下每项都是合理的未来 brand 候选,附带推迟理由而非承诺: +遵循「不是每个 string 都需要 brand」的策略,刻意保持窄范围。以下每项都是合理的未来 brand 候选,附带推迟理由而非承诺: -- **`ModelId`**(`GenerateOptions.model`,`LlmService` 适配器注册表的键):一个真正的跨包查找键(config → agent → llm → adapter);合理的下一个 brand,仅为控制本 RFC 的影响范围而暂不纳入。 +- **`ModelId`**(`GenerateOptions.model`,`LlmService` 适配器注册表的键):一个真正的跨包查找键(config → agent → llm → adapter);合理的下一个 brand,仅为控制本 Agent Note 的影响范围而暂不纳入。 - **`ToolName`**(`ToolRegistry` 的键):由作者定义、人类可读,且很少与其他 id 混淆;最弱的候选,可能不值得加 brand。 - **`ErrorCode`**(`HarnessError.code`):一个封闭词汇(`ABORTED`、`NO_ADAPTER`……),不是逐实例的 id;如果要做,string 字面量联合类型比 brand 更合适。 - **数值序号**:轮次号、步骤号和事件 `seq` 是 `number` 而非 `string`,`Branded<string>` 不适用;可以用并行的 `number & { readonly [BRAND]: B }` 变体来 brand 它们,但它们是位置序号、很少跨边界传递,收益较低。 -- **带校验的构造**:brand 工厂是纯 cast,无运行时检查,且每个边界(ACP `sessionId`、提供方签发的 `call.id`、`dsh-llm-deepseek` 中的空字符串回退)今天都信任裸 string。一个在边界处对格式错误的输入抛异常的 `SessionId.parse()` / `isValid()` 配套工具确实是缺口,但它是*运行时行为*变更,有自己的设计问题(什么算"格式错误"?失败时怎么办?),应在独立 RFC 中处理,不应捆绑进这次纯类型变更。 +- **带校验的构造**:brand 工厂是纯 cast,无运行时检查,且每个边界(ACP `sessionId`、提供方签发的 `call.id`、`dsh-llm-deepseek` 中的空字符串回退)今天都信任裸 string。一个在边界处对格式错误的输入抛异常的 `SessionId.parse()` / `isValid()` 配套工具确实是缺口,但它是*运行时行为*变更,有自己的设计问题(什么算「格式错误」?失败时怎么办?),应在独立 Agent Note 中处理,不应捆绑进这次纯类型变更。 ## 验证 -`BashTaskId` 和 `OwnerToken` 定义在 `dsh-bash` 中,贯穿执行器、本地实现和面向模型的工具,且未添加 `dsh-session` 依赖。集合、公开参数和导出签名对 `CallId`、`SessionId`、`AgentId` 或 `BashTaskId` 使用相应的 brand 而非裸 `string`;来自提供方、ACP 和模型的原始输入通过 brand 工厂进入,而非散落的 cast。 +已落地的不变式:`BashTaskId` 和 `OwnerToken` 定义在 `dsh-bash` 中,并端到端贯穿执行器 seam、`dsh-bash-local` 生成点与 `dsh-tool-bash` 面向模型的 surface,且 `dsh-bash` 未添加对 `dsh-session` 的依赖;没有任何以范围内 brand id(`CallId`/`SessionId`/`BashTaskId`)为键的集合使用裸 `string`;公开方法参数和导出签名保留 brand;每个原始 string 进入的边界(提供方 call id、ACP session id、模型提供的 `task_id`)都通过 cast 工厂构造 brand,而不是散落的 `as` cast。 ## 后果 -- **两个接口面的机械性改动。** 传播 brand 涉及 bash seam(接口 + 实现 + 消费方)以及 ACP session-id 接口和持久化协调器。改动面广但严重度低:遗漏的位置是编译错误而非静默 bug。变更可观察地为纯类型变更——无快照或 e2e 行为差异。它与 [unify-the-agent-id-and-the-session-id](../../proposed/simplification/2026-06-20-unify-agent-and-session-id.md) 提案相邻(两者都触及 session-id / owner-token 边界);如果该提案落地,`OwnerToken` 出于上述解耦理由仍与统一后的 id 保持独立。 -- **Brand 不做校验。** Brand 是混淆防护,不是正确性证明:一个*错误的* session id 只要仍是合法的 string,就和以前一样能通过类型检查器。本 RFC 不关闭这个缺口(见"不在范围内")——它只阻止这类*类别*错误:传入错误*种类*的 id。 -- **"在哪里停下"仍是判断题。** 为 `BashTaskId` 加 brand 但不为 `ToolName` 加,为 `OwnerToken` 加但不为 `ModelId` 加,是对哪些 string"可能被混淆"的品味判断。合理的评审者可能想要更多或更少;`brand.ts` 中的策略是裁决依据,本 RFC 倾向于面向模型或用于访问控制的 id。 +- **两个接口面的机械性改动。** 传播 brand 涉及 bash seam(接口 + 实现 + 消费方)以及 ACP session-id 接口和持久化协调器。改动面广但严重度低:遗漏的位置是编译错误而非静默 bug。变更可观察地为纯类型变更——无快照或 e2e 行为差异。它与[统一 agent/session 标识决策](../simplification/2026-06-20-unify-agent-and-session-id.md)相邻,因为二者都触及 session-id / owner-token 边界;`OwnerToken` 出于上述解耦理由仍与统一后的 id 保持独立。 +- **Brand 不做校验。** Brand 是混淆防护,不是正确性证明:一个*错误的* session id 只要仍是合法的 string,就和以前一样能通过类型检查器。本 Agent Note 不关闭这个缺口(见「不在范围内」)——它只阻止这类*类别*错误:传入错误*种类*的 id。 +- **「在哪里停下」仍是判断题。** 为 `BashTaskId` 加 brand 但不为 `ToolName` 加,为 `OwnerToken` 加但不为 `ModelId` 加,是对哪些 string「可能被混淆」的品味判断。合理的评审者可能想要更多或更少;`brand.ts` 中的策略是裁决依据,本 Agent Note 倾向于面向模型或用于访问控制的 id。 diff --git a/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml index 602102a219..419c158b01 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.i18n.yaml @@ -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 -2026-06-20-extract-example-app-packages.md: b0dd1fe32b2389578d3f3bd3672435923eb1a5d1 -2026-06-20-extract-example-app-packages.zh.md: 9f47c98c9c54357a304490e3d4075fad6cea855a +2026-06-20-extract-example-app-packages.md: b757a0099382a648a4efda4639e275ae6e6a02d1 +2026-06-20-extract-example-app-packages.zh.md: 5814704f0426707ef255a67a7aed9b79cae4aa24 diff --git a/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md b/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md index 9f47c98c9c..5814704f04 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.zh.md @@ -1,4 +1,4 @@ -# RFC: 将示例应用提取为独立包 +# Agent Note: 将示例应用提取为独立包 Status: implemented @@ -8,29 +8,28 @@ Status: implemented 示例目录本应是*精简的*——只包含演示的可变接线,而非演示的基础设施。在此次变更之前,它是臃肿的。每个示例都携带一份手写的 `start.ts` 启动引导、一段基础设施前导(`timer`,以及 stdio 演示所需的 `logger` + `hmr`(热模块替换))、三个共享 YAML 片段的嵌套引用(`base.yml` / `base-core.yml` / `acp-agent/acp-tail.yml`),还有各示例自身的 `agent-loop`/persistence/system-prompt 配置。真正的应用——每个 agent(智能体)都需要的服务主干——散落在叶子配置和那些 include 中。 -叶子配置还拥有一个耦合的前门。ACP(Agent Client Protocol)要求 stdout 纯净,并通过 `session/new` 创建 agent;stdio 则需要一个控制台 logger 和一个预创建的 `main`。防止错误组合的唯一屏障是文档中的文字警告,而三个 `start.ts` 文件重复着 Loader 引导和生命周期代码。 +叶子配置还拥有耦合的前门。ACP(Agent Client Protocol)要求 stdout 纯净,并通过 `session/new` 创建 agent;终端应用和 Headless 应用则预创建 `main`,但进程 I/O 契约不同。防止错误组合的唯一屏障是文档中的文字警告,而三个 `start.ts` 文件重复着 Loader 引导和生命周期代码。 ## 决策 每个示例现在**主要是对一个应用包(package)的调用**,沿着既有的[接口 / 实现 / 消费方 seam](2026-06-13-capability-seams.md) 拆分接线:**应用包拥有组合**,叶子 `cordis.yml` 只拥有**可替换的选择**(哪个 LLM(大语言模型)适配器、哪个 bash 执行器、模型、提示词、持久化根目录)。 - **`@deepseek-ai/dsh-agent-spine-demo`**([packages/examples/agent-spine-demo](../../../../packages/examples/agent-spine-demo))组合了不含 provider、不含执行器、不含 UI 的主干,并转发 agent loop(智能体循环)的 agent 列表配置。它对具体 loop 的依赖是有意为之,因为该包组合的是主干而非扩展主干;替换 loop 意味着提供另一个 bundle。 -- **`@deepseek-ai/dsh-stdio-demo`**([packages/examples/stdio-demo](../../../../packages/examples/stdio-demo))和 **`@deepseek-ai/dsh-acp-demo`**([packages/examples/acp-demo](../../../../packages/examples/acp-demo))各自内置了前门。Stdio 包含 `ui-stdio`、控制台 logger 和 `main`;ACP 包含 bridge 和 JSONL 持久化,但不含 stdout logger 或预创建的 agent。叶子可以添加插件,但安全的组合现在是默认产物。 -- **`start.ts` 已移除。** 每个应用包暴露一个 `bin`(`dsh-stdio-demo` / `dsh-acp-demo`);`demo:*` 脚本调用它(例如 `dsh-stdio-demo ./cordis.yml`)。Loader 引导尾部、`.env` 加载和快速失败守卫位于共享的 [`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot) 包(在逐文件覆盖率门禁下有单元测试——见[共享应用 bin 的启动胶水](../simplification/2026-07-04-share-app-bin-boot-glue.md));每个 bin 是一个精简的自执行组合,基于这些辅助函数加上其应用特有的生命周期逻辑(ACP bin:快照模式选择与 stdin-dispose)。`bin.ts` 文件本身仍被排除在覆盖率之外(自执行 CLI(命令行界面)入口,与旧的 `start.ts` 性质相同),由 keyless 的 Loader 路径测试驱动。 -- **每个叶子 `cordis.yml` 精简为**后端 + 配置:LLM 适配器(带 apiKey/models 的 `llm-deepseek`,或 `llm-replay`)、bash 执行器(`bash-local`)、stdio 演示的 `hmr`(见下方修正),以及一个承载应用配置的 app 条目(模型、系统提示词、持久化根目录——以应用包自身的 `Config` 形式暴露,由它将各值路由到应用接线的目标位置:stdio 路由到预创建的 agent,acp 路由到 bridge 插件)。 -- **echo-agent 折叠到 `dsh-stdio-demo` 上**,将 LLM 后端替换为本地的 `mock-llm`,并在叶子层添加本地的 `echo-tool`(加上 `bash-local`,由主干的 `tool-bash` 注入)——这是「替换后端、保留应用」的干净示范。`mock-llm.ts` / `echo-tool.ts` 作为示例本地的教学插件保留。 +- **`@deepseek-ai/dsh-tui-demo`**、**`@deepseek-ai/dsh-cli-demo`** 和 **`@deepseek-ai/dsh-acp-demo`** 各自内置其进程角色。TUI 包含全屏 UI 和预创建的 `main`;Headless 包含 one-shot driver 和预创建的 `main`;ACP 包含 bridge 且不预创建 agent。三者都包含 JSONL 持久化,并省略 stdout logger。 +- **`start.ts` 已移除。** 每个应用包都暴露一个 bin;`demo:*` 脚本调用它。Loader 引导、`.env` 加载和快速失败守卫位于共享的 [`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot) 包(在逐文件覆盖率门禁下有单元测试——见[共享应用 bin 的启动胶水](../simplification/2026-07-04-share-app-bin-boot-glue.md));精简的自执行入口由 keyless 的 Loader 路径测试驱动。 +- **每个叶子 `cordis.yml` 精简为**后端、可选产品工具,以及一个承载应用配置的 app 条目。TUI 和 Headless 把模型/会话选择路由到预创建的 agent;ACP 把初始提供方/模型路由到 bridge。 - **`base.yml`、`base-core.yml` 和 `acp-agent/acp-tail.yml` 已退役**——它们共享的主干现在位于 `dsh-agent-spine-demo` 中。 `bash-local` 和 LLM 适配器仍然是**叶子选择**:bundle 提供 `tool-bash`(消费方 schema),叶子选择执行器实现,因此沙箱执行器或回放适配器无需触碰应用即可替换。 ### 实现修正:`hmr` 保留为叶子条目 -提案最初将 `hmr` 列入 stdio 应用内置的前门集群。对照代码验证后发现,将 `hmr` 内置到 `dsh-stdio-demo` 包中会在两个方面与 Cordis 冲突,因此改为作为**叶子 `cordis.yml` 条目**交付: +提案最初将 `hmr` 列入交互式应用内置的前门集群。对照代码验证后发现,将 `hmr` 内置到应用包中会在两个方面与 Cordis 冲突,因此改为作为**叶子 `cordis.yml` 条目**交付: 1. `@cordisjs/plugin-hmr` 是一个仅限 Loader、仅限子进程的开发插件——其构造函数在没有 `node --expose-internals` 和活跃的 `loader` 服务时会抛出异常,因此只能在真实的 `demo:*`/bin 子进程中运行,不能在进程内的单元/覆盖率测试层运行。 2. 进程内测试层(vitest)甚至无法*导入* vendor 的 `hmr` 模块(其 class-decorator `@Inject` 形式在 Vite 的 transform 下会失败),因此一个 `apply` 静态导入了它的包永远无法满足其主函数的逐文件 100% 覆盖率门禁。 -关键在于,`hmr` **不是**像控制台 logger 那样的 stdout 纯净隐患:ACP 配置中误加 `hmr` 不会破坏 JSON-RPC 帧,因此将它留在叶子层不会损失耦合论证所关注的安全性。**logger**(真正的耦合点)保持内置:stdio 应用包含它,ACP 应用省略它。 +关键在于,`hmr` 不是 stdout 纯净隐患:ACP 配置中误加该条目不会破坏 JSON-RPC 帧。所有已交付应用都省略 stdout 控制台 logger;stdout 只归应用或协议 driver 所有。 ## 曾考虑的替代方案 @@ -41,13 +40,13 @@ Status: implemented ## 验证 - 示例目录只包含配置、README 和测试:`start.ts`、基础设施前导和共享 YAML include 已移除。 -- `demo:echo`、`demo:repl` 和 `demo:acp` 调用应用包的 bin。 -- 每个新包都有 README 和逐文件 100% 覆盖率;每个应用包还有一个 keyless 的真实 Loader 路径 bin 冒烟测试,用于捕获[事后分析 0001](../../../postmortem/0001-acp-default-export-drops-inject.md) 中描述的导出形状故障。 +- `demo:tui`、`demo:headless` 和 `demo:acp` 调用应用包的 bin。 +- 每个新包都有 README 和逐文件 100% 覆盖率;每个应用包还有一个 keyless 的真实 Loader 路径 bin 冒烟测试,用于捕获[事后分析 0001](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md) 中描述的导出形状故障。 - ACP 回放 transcript(文本记录)保持不变,因为插件集合和加载顺序未改变。 ## 后果 -- **裸插件树的教学性。** echo-agent 内联的 `cordis.yml` 曾一次展示所有插件;主干现在隐藏在 bundle 之后,查看完整树意味着打开 `dsh-agent-spine-demo`。应用包的 README 承担了这份教学职责。 +- **裸插件树的教学性。** 主干现在隐藏在 bundle 之后,查看完整树意味着打开 `dsh-agent-spine-demo`。应用包的 README 承担了这份教学职责。 - **多了一层间接。**「这个演示加载了什么?」从扫描单个 YAML 变成了阅读一个包。 ## 相关 @@ -55,3 +54,4 @@ Status: implemented - 取代 [Make the shared example base providerless](../../rejected/architecture/2026-06-20-providerless-example-base.md):一旦主干移入 `dsh-agent-spine-demo` 且 `base*.yml` 文件被删除,将 `base.yml` 重命名为无 provider 核心便不再有意义。 - 基于 [capability-seams](2026-06-13-capability-seams.md) 的接口/实现/消费方拆分——后端和展示层保持为叶子选择;主干是共享 bundle。 - 与 [Reorganize packages into a modular hierarchy](2026-06-20-package-hierarchy.md) 互补:新的 app/core 包按该层级结构归入既有分组(`core` 放可复用的主干 bundle,`ui` 放应用特有的前门)。 +- 后续的[冗余 agent 移除](../simplification/2026-07-20-remove-stdio-and-echo-agents.md)拥有最终的 TUI/Headless 拆分,并移除行式与仅 mock 的叶子。 diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml index b98f0fa227..af587f2c25 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.i18n.yaml @@ -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 -2026-06-20-generic-long-running-tool-runtime.md: 9b83a4443d6d654cda75c72fba3369a16be078e2 -2026-06-20-generic-long-running-tool-runtime.zh.md: c1684be4fd5c1c3c9d913e063f4ba66bb6064459 +2026-06-20-generic-long-running-tool-runtime.md: c28236d194ae839f88d900f0fc52707b2c9e53e2 +2026-06-20-generic-long-running-tool-runtime.zh.md: 911c4288fff6e4235b9c88efeaaa882910e559b0 diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md index 4db0d78910..c28236d194 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-20-generic-long-running-tool-runtime.zh.md) + ## Problem Background bash originally combined two responsibilities: the bash executor ran processes and also managed task ids, ownership, incremental reads, cancellation, completion listeners, and model-facing control tools. Adding background subagents required the same lifecycle and interaction contract. Implementing that contract independently for every long-running capability would duplicate isolation, cleanup, notification, and prompt behavior while teaching the model a different collect-and-stop protocol for each producer. diff --git a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md index c1684be4fd..911c4288ff 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md @@ -1,43 +1,130 @@ -# RFC: 提取通用的长时间运行工具运行时 +# Agent Note: 后台任务运行时(`ctx.tasks`)与通用任务控制工具 -Status: proposed +Status: implemented [English](2026-06-20-generic-long-running-tool-runtime.md) | 中文 ## 问题 -bash 能力 seam 同时支持前台命令和长时间运行的后台任务。后台支持体量不小:抽象执行器暴露 `start`、`get`、`ownerOf`、`list`、`readOutput`、`kill` 和 `onTaskDone`;本地执行器负责跟踪任务、增量读取、owner token、进程清理和完成监听;模型侧看到三个工具(`bash`、`bash_output`、`bash_kill`);工具插件将完成通知注入回所属 agent(智能体)的会话。本地执行器用 owner token 隔离任务访问,因为可预测的全局 task id 会带来跨会话的读取/终止风险。 +后台 bash 原本兼有两项职责:bash 执行器既运行进程,又管理 task id、所有权、增量读取、取消、完成监听器和面向模型的控制工具。新增后台 subagent 需要相同的生命周期与交互契约。如果每种长时间运行能力都独立实现该契约,就会重复隔离、清理、通知和提示词行为,还会让模型为每种生产方学习不同的收集与停止协议。 -[工具实操手册](../../../cookbook/adding-a-tool.md)已经指出了真正的设计异味:后台 bash 本质上是寄居在单个工具内部的通用长时间运行工具基础设施。如果未来的工具也需要后台执行、轮询、终止、所有权和完成通知,这些语义不应藏在 `dsh-bash` 里。 +任务注册表、控制工具与完成通知共同构成一项 harness 功能。bash 和 subagent 只提供执行专属的钩子,不拥有通用任务行为。 -## 提案 +## 决策 -将长时间运行任务的语义从 bash 上移到一个与工具无关的运行时中。bash 仍然能运行后台命令,但不再拥有 task id、ownership token、轮询、取消、完成通知以及模型侧「读取/终止此任务」命令等通用概念。 +`tasks/` 包组拥有后台任务语义: -该运行时应拥有: +- `@deepseek-ai/dsh-tasks` 将运行中的工作注册为 `ctx.tasks`,并拥有 task id、授权、快照、读取、取消、等待、完成监听器与清理。 +- `@deepseek-ai/dsh-tool-tasks` 暴露 `task_output`、`task_list` 和 `task_kill`,注入完成通知,并提供后台任务的系统提示词指导。 -- 稳定的 task id 和 owner token,按调用方的会话/agent 做键。 -- 注册一个长时间运行任务,附带增量输出的生产者和一个完成 promise。 -- 通用的 read/cancel/list 操作,对所有工具使用相同的跨会话授权规则。 -- 向所属会话注入完成通知。 -- 针对 pending/running/completed 任务状态的展示钩子,bash 只提供命令特有的标签和输出格式化。 +长时间运行工具是生产方。`dsh-tool-bash` 将 `BashProcess` 适配为增量输出与进程取消;`dsh-tool-subagent` 将子运行适配为最终输出与子运行释放。执行 seam 保持独立,不依赖会话或任务注册表。 -`dsh-bash` 保留 bash 特有的执行契约:将请求解析为命令规格、运行前台命令,或启动进程并将其流/进程句柄交给通用运行时。`dsh-tool-bash` 保留模型侧的命令工具,但后续操作变为通用的长时间运行工具操作,或者 bash 向其注册的共享工具,而不是专属的 `bash_output`/`bash_kill` 管道。 +`TaskService` 是一个具体的进程内服务。TODO(task-service-backend):当第二个后端明确所需生命周期后,将其公共契约与实现分离;systemd 驱动的运行时是一种可能方案,但本 PR(Pull Request)不臆测其持久性、重连、所有权或观察语义。 -## 当前 seam 消费情况 +## 运行时契约 -当前消费方划分清晰:`dsh-tool-bash` 使用完整的前台/后台 seam,而钩子桥接层只使用前台的 `resolve` 和 `run`(带受信的 `stdin` 和 `env`)。`get` 和 `list` 仅在测试中使用;`BashTask.done` 仅在实现内部用于 dispose(资源释放),生产环境的完成通知使用 `onTaskDone`。提取出的运行时应暴露一个公开的完成机制,保留钩子所需的简单前台路径,并决定后台的 `timeoutMs` 是否属于 `start`。如果它拥有进程 spawn 的职责,还应集中处理目前重复的凭证清洗逻辑。 +字面类型见[任务数据结构目录](../../../../docs/core-data-structures/tasks.md)。生产方调用 `ctx.tasks.start()`,传入 kind、label、可选的所属 `Agent` 与一个 `run()` 函数。运行时会在调用 `run()` 前完成所有可能失败的预检工作,并且只调用一次。`run()` 返回钩子后,注册过程不会再执行可能失败的步骤而直接提交;生产方无法启动没有可收集 task id 的工作。 -## 验收标准 +生产方钩子定义三项职责: -- bash 特有的包(package)不再定义通用的任务注册表、owner-token 授权、轮询、取消或完成通知机制。 -- 一个共享的长时间运行任务服务或工具层拥有这些语义,并被文档化为未来任何具备后台能力的工具的接入路径。 -- bash 后台行为仍可通过共享层使用,测试证明跨会话隔离依然成立。 -- ACP 和快照 fixture(测试前置数据)通过共享任务词汇渲染后台 bash,而非通过 bash 专属的生命周期语义。 -- [工具实操手册](../../../cookbook/adding-a-tool.md)将长时间运行工具指向共享运行时,而不是让每个工具自行发明任务协议。 +- `cancel(reason?)` 同步请求终止,具备幂等性,并且必须使 `done` 完成。 +- `done` 从不拒绝,并且仅在生产方释放任务资源后完成。 +- 可选的 `readOutput()` 返回下一个消费式输出增量。省略该钩子即声明这是最终输出任务,其终止结果来自 `TaskOutcome.output`。 -## 风险 +状态包括 `running`、`stopping`、`completed`、`killed` 和 `failed`。退出码或停止原因等生产方专属信息放在 `detail` 中,注册表不解释这些信息。任务 kind 构成可合并扩展的字符串联合;task id 带品牌,并按 `<kind>-N` 生成,每个 kind 各有一个计数器。 -bash 包失去了对一个已经可用的后台任务实现的本地所有权,实现 PR(Pull Request)可能暂时搅动模型侧的工具名称或 transcript(文本记录)展示。如果最终结果是留下一份后台任务契约,而不是让每个未来的长时间运行工具克隆 bash 的私有协议,这种搅动是值得的。 +运行时为 `done` 附加一个 continuation,记录第一个终止结果、解决等待方,并逐个调用完成监听器,同时隔离每个监听器的错误。首次结果优先的结算在资源销毁期间至关重要:如果 `cancel` 抛出,运行时会强制将记录标为失败,并警告工作可能遗留,而不是永远等待一个可能永不完成的 promise。后续生产方结果不能覆盖该诊断,也不能重复通知。`cancel` 返回后如果最终未使 `done` 完成,仍会阻塞资源销毁,因为运行时无法区分这种情况与缓慢但有效的停止。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +任务注册不是生产方工具 fiber 的 effect。因此,重新加载工具或控制接口插件不会终止由 agent(智能体)和后端拥有的工作。任务服务自身释放时会取消所有实时任务,并等待遵守契约的生产方。 + +## 授权与所有者生命周期 + +task id 在运行时全局可见且可预测,因此注册表会授权每次访问。`get`、`read`、`wait` 和 `kill` 接受调用方 `Agent`;`list` 仅返回该调用方可见的任务。有所有者的任务仅允许对应的确切会话访问。无所有者任务向非 agent 调用方开放,并随任务服务一起终止。 + +快照存储所有者的品牌化 `SessionId` 以供授权,生命周期操作则保留确切的实时 `Agent` 实例。这两种身份用途不同:会话相等性授予访问权,精确对象身份决定清理和完成通知的接收方。复用 agent 或会话 id,不能将旧作用域的清理或通知重定向到替代实例。 + +某个所有者的第一个任务会向 `owner.ctx` 附加一个异步 effect。agent 作用域释放时会取消该所有者的实时任务、等待其终止记录,并移除其快照。该 effect 可跨生产方重载存续,并加入 agent 现有的停稳边界。任务服务保留 effect disposer,使服务重载可以在全局资源销毁后,从仍然存活的 agent 作用域中分离回调。 + +对于遵守契约的生产方,`AgentHandle.dispose()` 只在所属后台工作停止后解决。需要比 agent 存活更久的工作必须以无所有者方式启动;要跨运行时重启存续,则需另行设计持久任务。 + +## 服务接口 + +`TaskService` 提供: + +- `start(spec)`:经过预检的原子注册。 +- `get(id, caller?)` 和 `list(caller?)`:非消费式快照。 +- `read(id, caller?)`:消费式流增量或幂等的最终结果。 +- `kill(id, caller?, reason?)`:取消。 +- `wait(id, timeoutMs, caller?, signal?)`:有界的终止等待。 +- `onTaskDone(listener)`:effect 作用域内的观察,具有精确所有者投递和监听器隔离。 +- `attachSurface(name)`:控制接口可用性防线。 + +`wait` 在任务完成时返回终止快照,在等待超时时返回实时快照。中止一次等待只取消该次等待。如果结算已经将终止投递分配给该等待方,终止快照仍然优先。等待方在中止时同步注销,因此同一 tick 内的结算无法代表一个什么也未收到的读取方压制完成通知。 + +如果生产方加载时没有任何控制接口,调用方就能启动无法收集或停止的工作。因此,`dsh-tool-tasks` 在其整个生命周期内调用 `attachSurface()`;没有附加接口时,`start()` 会在生产方开始执行前失败。该检查发生在启动时而非插件加载时,因为兄弟插件可能并发激活。自定义的非模型接口可以自行附加,无需让注册表了解工具名称。 + +## 面向模型的控制接口 + +`dsh-tool-tasks` 注册三个与 kind 无关的工具,并使用通用 ACP 卡片: + +- `task_output(task_id, wait?, timeout_ms?)` 读取输出,并始终追加 `[status: ...]`。流式任务只返回上次读取以来的输出;最终输出任务在结算后返回结果。除非指定 `wait: true`,否则读取不会阻塞;等待超时由插件配置提供默认值并限定上限。等待超时会报告仍在运行的状态,不会停止任务。 +- `task_list()` 将调用方可见的任务返回为 `<id> [<kind>] <status> — <label>`,没有任务时返回 `(no background tasks)`。 +- `task_kill(task_id, reason?)` 立即请求取消。可选的已记录原因会转发给生产方。终止任务报告现有状态;生产方的取消操作若抛出,调用便会失败,任务保持运行。 + +流式读取共享一个任务作用域内的消费游标,因为所属模型是预期读取方。UI 或多个独立读取方需要单独的非消费式观察 API;共享该游标会让读取方彼此消费对方的输出。 + +系统提示词要求模型保留 task id、在后台工作运行时继续处理独立工作而非忙轮询或重复启动同一任务、在给出最终答案前收集相关任务,并终止不再重要的工作。完成时,系统会向确切所有者的会话注入一条已记录的 `context/message`;它会成为下一个请求的持久上下文,但不会唤醒空闲的 agent。 + +当读取或等待交付终止任务、实时等待方在结算时认领了投递,或模型显式终止任务时,运行时将终止任务标为 `reported`。已报告的任务不会注入冗余的完成通知。监听器失败会独立记录,不会阻止后续监听器,也不会被等待方或资源销毁过程等待。 + +## 生产方显式启用 + +每个生产方通过带默认值的配置,自行决定其 schema 是否暴露 `run_in_background`。`dsh-tool-bash` 和每个 `dsh-tool-subagent` 实例都使用 `enableRunInBackground`,默认值为 true。禁用的实例会省略该参数;由于通用参数校验器允许未声明的键,它还会在执行时拒绝强制传入的后台参数。省略 schema 用于声明能力不可用;执行检查负责强制该约束。 + +`ctx.tasks` 不改写生产方 schema。bundle 只转发其所拥有生产方的配置。如果后台调用在没有附加接口的情况下到达 `start()`,运行时防线会在执行前使其失败。 + +## 生产方集成 + +bash seam 暴露 `resolve`、`run` 和 `start`。`start(spec)` 返回一个 `BashProcess`,提供增量读取、取消、退出事实以及不拒绝的停稳 promise。本地执行器只为自身释放时能终止并等待进程而保留实时句柄。前台调用方继续直接使用 `resolve` 和 `run`。 + +对于后台 bash,`dsh-tool-bash` 将调用方 agent 注册为所有者。其钩子将 `kill()` 映射为取消,将 `done` 映射为 completed 或 killed 的 `TaskOutcome`,并将 `readOutput()` 映射为进程的有界增量输出,以及溢出文件与沙箱通知。通用任务工具拥有 id、状态行、列表、等待和完成通知。 + +对于后台 subagent,`dsh-tool-subagent` 创建由任务拥有的 `AbortController`,并在任务 starter 内启动提供方。无论提供方就绪前后,取消都会中止同一个 signal。`done` 同时等待子运行结果和子运行释放,将已完成输出映射为最终结果,将中止映射为 `killed`,并将其他停止原因或基础设施失败映射为 `failed`。中间子历史保留在子会话中,不通过 `readOutput()` 暴露。 + +## 备选方案 + +### 按功能划分控制工具 + +为 bash 与 subagent 分别提供输出/停止工具,会重复 id、隔离、清理、通知和指导,并增加模型的 schema 与协议负担。统一运行时将执行专属行为保留在生产方中,而无需复制任务生命周期。 + +### 立即抽象任务运行时后端 + +当前 `TaskStart.run()` 契约传入进程内回调与确切的 `Agent` 对象。持久化后端会改变身份、重启、所有权与观察语义,因此在第二种实现出现前抽取接口,会固化错误的边界。 + +### 由消费方负责授权或清理事件 + +由消费方负责检查,会使每个新接口的隔离实现不一致或遗漏。广播清理事件会迫使每个监听器过滤所有 agent,且不提供注册 disposer。集中授权加一个所有者作用域内的 effect,为每个消费方提供相同防线,以及可等待、可移除的生命周期钩子。 + +### 阻塞输出或单独的等待工具 + +默认阻塞会在后台工作运行时串行化父任务。只等待而不读取会增加一次不返回有用信息的模型调用和 schema。`task_output(wait: true)` 显式表达阻塞,并将其与结果交付合并。 + +等待使用共享的 deadline 原语,而不使用通用工具超时策略。等待超时是一次成功的观察,会返回 `[status: running]`;通用策略会将它替换为超时错误。任务返回 task id 后,没有任何工具调用超时会控制任务生命周期。 + +### 由运行时拥有输出接收端 + +推送式接收端可以集中缓冲,但 bash 已经在执行器 seam 后拥有有界缓冲、截断与溢出文件。拉取格式化增量能够保留这一所有权。拥有存储的持久化后端可能足以支持重新审视生产方接口。 + +### 随机 id、提升或生命周期会话事件 + +授权而非不可猜测性才是访问边界,并且 id 不用于派生文件系统路径;顺序生成的品牌化 id 可保持 transcript(文本记录)易读。将前台任务提升为后台任务需要 SDK 并未规定的用户交互契约。启动、读取和通知已作为工具与上下文事件记录,因此专用任务会话事件会重复面向模型的事实。 + +## 测试 + +单元覆盖固定预检原子性、按 kind 分配的 id、流式与最终读取、等待超时与中止竞态、取消、首次结果优先的结算、监听器隔离、通知压制、所有者隔离、陈旧的所有者实例、所有者清理、服务资源销毁和无接口防线。生产方测试覆盖 bash 进程映射、subagent 启动取消、终止映射与释放。快照覆盖固定控制工具 schema 与提示词指导。 + +## 后果 + +bash 命令与 subagent 共享一套 id 词汇、列表、通知格式、提示词习惯和控制工具。新的长时间运行生产方只需实现执行钩子,而不必再实现一套注册表与工具族。[工具实操手册](../../../../docs/cookbook/adding-a-tool.md)将生产方指向本契约。 + +有所属后台 bash 会随其 agent 一起停止,不再比 agent 存活更久。后台进程没有执行器超时;调用方必须终止无关工作,或依赖所有者/服务释放。流式读取只支持一个消费方,完成通知不会唤醒空闲 agent;生产方的 `cancel` 返回后如果未使 `done` 完成,仍可能阻塞资源销毁。持久任务、独立观察游标和前台提升仍属于单独设计。 diff --git a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml index 05549751eb..bc70afb74c 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.i18n.yaml @@ -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 -2026-06-20-package-hierarchy.md: a06e963d118d895cc55a0f5e378bbf12678f3491 -2026-06-20-package-hierarchy.zh.md: a136f15a4197645b06fa0a68564a9e0464af1cba +2026-06-20-package-hierarchy.md: aba5fb56176ecab9dd92c61a72cb91d501a442d8 +2026-06-20-package-hierarchy.zh.md: 304bf1da3631187d09b229fb14beb54d4e9a46cc diff --git a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md index 85c62b7e17..aba5fb5617 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md +++ b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-20-package-hierarchy.zh.md) + The later [fold-stdio-helper](../simplification/2026-07-04-fold-stdio-ui-helper.md) decision superseded the original `support/ui-stdio` placement, and the [redundant-agent removal](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) subsequently removed that surface entirely. The uniform depth-two hierarchy remains the decision owned here. ## Problem diff --git a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md index a136f15a41..304bf1da36 100644 --- a/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.zh.md @@ -1,9 +1,11 @@ -# RFC: 将包重组为模块化层级结构 +# Agent Note: 将包重组为模块化层级结构 Status: implemented [English](2026-06-20-package-hierarchy.md) | 中文 +后续的 [fold-stdio-helper](../simplification/2026-07-04-fold-stdio-ui-helper.md) 决策取代了最初的 `support/ui-stdio` 放置方式,[冗余 agent 移除](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) 随后又彻底移除了该接口。这里拥有的决策仍是统一的二层目录深度。 + ## 问题 `packages/` 原先是扁平的:18 个包(package)全部位于 `packages/<name>/`,从路径上完全看不出一个包属于核心产品 API、可替换的能力 seam、提供方适配器、产品集成,还是示例/测试支撑。包的 README 带着 `FIXME(package-hierarchy)`,`scripts/publint-all.ts` 带着 `TODO(package-inventory)`,标记的正是这个问题。核心包、提供方集成、能力 seam、示例 UI 支撑和仅用于快照的回放支撑看起来同样基础。 diff --git a/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml index decd9cec05..32fb4fe9a9 100644 --- a/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.i18n.yaml @@ -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 -2026-06-21-mandatory-app-attribution-headers.md: 132c827b48693af85fde67cf9d2d71cc84e853c6 -2026-06-21-mandatory-app-attribution-headers.zh.md: 9bba6d912b0b9bb33174c1ebb51a84dfdb47af0f +2026-06-21-mandatory-app-attribution-headers.md: a8ffe91c431cdc7907626bbc3eaf8096035777de +2026-06-21-mandatory-app-attribution-headers.zh.md: 724a828ce6a9907bec5615d1b2c3a53f2603e388 diff --git a/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md b/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md index 9bba6d912b..724a828ce6 100644 --- a/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.zh.md @@ -1,4 +1,4 @@ -# RFC: 对提供方请求强制携带 `User-Agent` 归属标识 +# Agent Note: 对提供方请求强制携带 `User-Agent` 归属标识 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -LLM(大语言模型)提供方请求应当标识发出请求的产品。这对提供方侧的技术支持、滥用调查、兼容性调试和流量分析都有价值。在本 RFC 之前,harness 只做了部分工作:手写的 DeepSeek 适配器发送了一个手动复制的 `User-Agent` 常量(`packages/llm/llm-deepseek/src/adapter.ts`),而基于 pi-ai 的孪生适配器则完全不发送 harness 自有的头部(`packages/llm/llm-pi-ai/src/adapter.ts`)。因此新适配器可以悄无声息地省略归属标识,而基于库的适配器也可能与手写适配器产生偏差——尽管[孪生适配器 RFC](2026-06-13-twin-llm-adapters.md) 的存在正是为了让两种实现在提供方 seam 上保持诚实。 +LLM(大语言模型)提供方请求应当标识发出请求的产品。这对提供方侧的技术支持、滥用调查、兼容性调试和流量分析都有价值。在本 Agent Note 之前,harness 只做了部分工作:手写的 DeepSeek 适配器发送了一个手动复制的 `User-Agent` 常量(`packages/llm/llm-deepseek/src/adapter.ts`),而基于 pi-ai 的孪生适配器则完全不发送 harness 自有的头部(`packages/llm/llm-pi-ai/src/adapter.ts`)。因此新适配器可以悄无声息地省略归属标识,而基于库的适配器也可能与手写适配器产生偏差——尽管[孪生适配器 Agent Note](2026-06-13-twin-llm-adapters.md) 的存在正是为了让两种实现在提供方 seam 上保持诚实。 直接触发因素来自 OpenRouter 的 [App Attribution](https://openrouter.ai/docs/app-attribution) 文档。OpenRouter 根据 `HTTP-Referer` 加上 display/category 头部来创建应用页面和排名。这有价值,但它不是 HTTP 标准中的应用身份机制。风险在于:把 OpenRouter 的精确头部集当作通用标准来采纳,然后将提供方特有的头部泄漏到直连 DeepSeek 的请求、未来的 OpenAI/Anthropic/Vertex 适配器、测试服务器或无限期记录未知字段的代理中。 @@ -26,11 +26,11 @@ LLM(大语言模型)提供方请求应当标识发出请求的产品。这 在 LLM 适配器边界,提供方请求归属是强制的,且仅使用标准 `User-Agent` 头部。规则:每个生产 LLM 适配器在每个提供方 HTTP 请求上发送一个静态、非机密的应用身份,且每个适配器都有测试证明 `User-Agent` 到达了线路(mock 服务器断言收到的头部;对于基于库的适配器,通过库的头部钩子馈入同一个 mock 服务器断言)。 -本 RFC **不**实现 OpenRouter 应用归属。`HTTP-Referer`、`X-OpenRouter-Title`、`X-Title` 和 `X-OpenRouter-Categories` 是 OpenRouter 特有的产品展示头部,不是提供方无关的模型请求归属。它们可以后续由 OpenRouter 适配器或显式 OpenRouter 模式提出,附带自己的隐私/产品决策、测试和文档。在此之前,即使请求指向 OpenRouter,也只发送本 RFC 定义的共享 `User-Agent` 归属。 +本 Agent Note **不**实现 OpenRouter 应用归属。`HTTP-Referer`、`X-OpenRouter-Title`、`X-Title` 和 `X-OpenRouter-Categories` 是 OpenRouter 特有的产品展示头部,不是提供方无关的模型请求归属。它们可以后续由 OpenRouter 适配器或显式 OpenRouter 模式提出,附带自己的隐私/产品决策、测试和文档。在此之前,即使请求指向 OpenRouter,也只发送本 Agent Note 定义的共享 `User-Agent` 归属。 提供方无关的身份由 `dsh-llm`(`packages/llm/llm/src/attribution.ts`)拥有,而非各适配器。`AppIdentity` 仅包含构建 `User-Agent` 所需的公开产品事实,默认的 `APP_IDENTITY` 确定了提案中留待决定的值: -- `User-Agent` 的产品 token:`deepseek-harness`(与 RFC 之前的线路值及仓库/组织身份保持连续性) +- `User-Agent` 的产品 token:`deepseek-harness`(与 Agent Note 之前的线路值及仓库/组织身份保持连续性) - 版本:通过 `createRequire` 从所属包的 manifest 读取,绝不手动复制常量 - 应用 URL:`https://github.com/deepseek-ai/deepseek-harness-sdk`——计划中的公开主页;`attribution.ts` 中的 `FIXME` 标记在该仓库实际存在之前阻塞发布 @@ -42,10 +42,10 @@ LLM(大语言模型)提供方请求应当标识发出请求的产品。这 |---|---| | 所有基于 HTTP 的适配器 | `User-Agent: {product}/{version} (+{url})`——括号中的 `+url` 注释符合 RFC 9110 保守的 product/comment 语法。 | | 直连 DeepSeek 端点 | `User-Agent`;除非 DeepSeek 文档化了等效契约,否则不发送 OpenRouter 特有头部。 | -| OpenRouter 端点 | 目前仅 `User-Agent`。本 RFC 下不发送 `HTTP-Referer`、`X-OpenRouter-Title`、`X-Title` 或 `X-OpenRouter-Categories`。 | -| 未来提供方 | 仅 `User-Agent`,除非后续提供方特有的 RFC 接受额外头部。不要类比复用 `HTTP-Referer`。 | +| OpenRouter 端点 | 目前仅 `User-Agent`。本 Agent Note 下不发送 `HTTP-Referer`、`X-OpenRouter-Title`、`X-Title` 或 `X-OpenRouter-Categories`。 | +| 未来提供方 | 仅 `User-Agent`,除非后续提供方特有的 Agent Note 接受额外头部。不要类比复用 `HTTP-Referer`。 | -端点检测不在本 RFC 范围内,因为此处不接受任何端点特有的映射。如果后续支持 OpenRouter,检测必须是显式的:要么是专门的 OpenRouter 提供方包,要么是显式的 `provider: 'openrouter'` / `attributionTarget: 'openrouter'` 配置,而非任意路径片段或模型名称。 +端点检测不在本 Agent Note 范围内,因为此处不接受任何端点特有的映射。如果后续支持 OpenRouter,检测必须是显式的:要么是专门的 OpenRouter 提供方包,要么是显式的 `provider: 'openrouter'` / `attributionTarget: 'openrouter'` 配置,而非任意路径片段或模型名称。 ## 验证 @@ -55,19 +55,19 @@ LLM(大语言模型)提供方请求应当标识发出请求的产品。这 - 共享辅助函数(`attributionHeaders` / `userAgent`)从包元数据构建应用身份和标准 `User-Agent` 值,适配器无需手动复制版本常量。 - `dsh-llm-deepseek` 在每个请求上发送共享的 `User-Agent`,其 mock 服务器套件断言精确值。 - `dsh-llm-pi-ai` 通过 pi-ai 的 `StreamOptions.headers` 钩子发送相同的 `User-Agent`,其 mock 服务器套件断言精确值。 -- 本 RFC 下没有适配器发送 OpenRouter 特有的归属头部(`HTTP-Referer`、`X-OpenRouter-Title`、`X-Title`、`X-OpenRouter-Categories`)。 +- 本 Agent Note 下没有适配器发送 OpenRouter 特有的归属头部(`HTTP-Referer`、`X-OpenRouter-Title`、`X-Title`、`X-OpenRouter-Categories`)。 - 没有应用归属字段携带机密、本地路径、会话 id、提示词文本、模型输出、用户邮箱或逐用户的稳定标识符。 - 适配器 README 声明了 `User-Agent` 归属策略,并明确避免将 OpenRouter 应用归属记录为已实现的行为。 ## 曾考虑的替代方案 -**现在就实现 OpenRouter 应用归属。** 本 RFC 否决。发送 `HTTP-Referer` 加 `X-OpenRouter-Title` 可以满足 OpenRouter 排名,但这些头部是提供方特有的产品功能,不是本 RFC 试图标准化的提供方无关的模型请求归属。支持它们应当是后续显式的 OpenRouter 适配器/模式决策,而非隐藏在首个共享归属辅助函数中。 +**现在就实现 OpenRouter 应用归属。** 本 Agent Note 否决。发送 `HTTP-Referer` 加 `X-OpenRouter-Title` 可以满足 OpenRouter 排名,但这些头部是提供方特有的产品功能,不是本 Agent Note 试图标准化的提供方无关的模型请求归属。支持它们应当是后续显式的 OpenRouter 适配器/模式决策,而非隐藏在首个共享归属辅助函数中。 **向所有提供方发送 OpenRouter 头部。** 否决。这会把一份自定义的 OpenRouter 契约当作通用标准,并向未要求这些字段的提供方发送语义误导的头部。还有风险将 `HTTP-Referer` 当作通用应用 URL 字段使用,尽管标准 HTTP 已有 `User-Agent` 用于产品身份、`Referer` 用于不同的浏览上下文概念。 **仅使用提供方账户/项目身份。** 否决。组织/项目头部、API key、云账户和计费项目标识的是谁付费或谁拥有请求,而非哪个应用在发送流量。它们也不暴露公开的应用标题/类别,无法帮助 OpenRouter 等网关构建应用排名。 -**终端用户 `user`/`metadata` 字段。** 本 RFC 否决。这些对滥用监控和客户支持有价值,但描述的是请求背后的人或租户。应用归属必须是静态的产品身份,且可安全地在每个请求上发送。 +**终端用户 `user`/`metadata` 字段。** 本 Agent Note 否决。这些对滥用监控和客户支持有价值,但描述的是请求背后的人或租户。应用归属必须是静态的产品身份,且可安全地在每个请求上发送。 **仅配置启用的归属。** 否决。默认关闭的设置正是适配器不断漂移的原因。策略是强制默认归属加可覆盖的公开值,而非可选归属。 diff --git a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml index b164c4c0f7..15dc1acece 100644 --- a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.i18n.yaml @@ -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 -2026-06-24-web-capability-seam.md: fdb611be9efbf29717e41ffa2db86c55258ebe2e -2026-06-24-web-capability-seam.zh.md: f5db538f0565c4fc5667dcbec0791579246d238d +2026-06-24-web-capability-seam.md: 4f4e821fec9494fe9ea96894267707d9dd202e4d +2026-06-24-web-capability-seam.zh.md: 1d81d06d7ff0202174f4348146117e22ea1de038 diff --git a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md index 6d3cf3e8c3..4f4e821fec 100644 --- a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md +++ b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md @@ -77,6 +77,8 @@ Provider packages depend only on `dsh-web` and Cordis. They own credentials, end `ctx.web` is a provider registry plus a provider-selecting execution surface. The registry half stays close to `LlmService`: a `Map<id, provider>` per capability kind, `registerSearchProvider` / `registerFetchProvider` methods that return disposers, duplicate ids that throw `WebError`, and execution-time resolution that throws when the selected provider is absent or unusable. The authoritative signatures live in `packages/web/web/src/types.ts`; the seam's shape: ```ts +import type { WebFetchRequest, WebFetchResult, WebSearchRequest, WebSearchResult } from '@deepseek-ai/dsh-web' + interface WebSearchProvider { readonly id: string available(): boolean @@ -208,18 +210,18 @@ The seam request deliberately does not include a per-call timeout, `format`, `pr HTTP status is part of the fetched resource state, not automatically a tool failure. A successful network fetch of a `404` or `500` response returns `WebFetchResult` with the status code and a bounded decoded body when the content type is supported. `WebError` is for failures to safely retrieve or represent the resource: invalid or blocked URL, redirect policy violation, timeout, abort, response too large, unsupported content type, provider failure, or network failure. ```ts -interface WebFetchRequest { +export interface WebFetchRequest { readonly url: string } -interface WebFetchResult { +export interface WebFetchResult { readonly url: string readonly statusCode: number readonly body: WebFetchBody readonly truncated: boolean } -type WebFetchBody = +export type WebFetchBody = | { readonly kind: 'html'; readonly content: string } | { readonly kind: 'text'; readonly content: string } ``` diff --git a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md index f5db538f05..1d81d06d7f 100644 --- a/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md @@ -1,4 +1,4 @@ -# RFC: Web 能力 seam——稳定的工具覆盖多个提供方 +# Agent Note: Web 能力 seam——稳定的工具覆盖多个提供方 Status: implemented @@ -16,7 +16,7 @@ harness 需要面向模型的 web 工具,但不能将模型契约绑定到某 ## 决策 -Web 访问是一个一等能力 seam,遵循[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md): +Web 访问是一个一等能力 seam,遵循[能力 seam Agent Note](2026-06-13-capability-seams.md): 1. `@deepseek-ai/dsh-web`(`packages/web/web`)拥有 `ctx.web`、提供方注册、提供方选择、共享的请求/结果词汇,以及 web 特有的错误。 2. 提供方包实现具体后端并向 `ctx.web` 注册能力,例如 `@deepseek-ai/dsh-web-search-exa`、`@deepseek-ai/dsh-web-search-perplexity`、`@deepseek-ai/dsh-web-search-deepseek` 和 `@deepseek-ai/dsh-web-fetch-local`。 @@ -34,7 +34,7 @@ Web 访问是一个一等能力 seam,遵循[能力 seam RFC](../../implemented 这使模型 schema 保持稳定,而不将插件加载顺序、凭证状态或 HMR(热模块替换)时序纳入面向模型的契约。如果 web 搜索已启用但不存在可用的搜索提供方,`web_search` 仍然可见,执行时以结构化的 `WebError`(如 `WEB_PROVIDER_UNAVAILABLE` 或 `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`)失败。如果某个提供方在 `dsh-tool-web` 之后出现,下一次执行即可使用它而无需更改 schema。如果某个提供方在调用过程中消失,执行以结构化的 `WebError` 失败,而不是静默选择另一个提供方或回退到 `UNKNOWN_TOOL`。 -该 seam 刻意不暴露任何观察面——没有注册表变更事件,也没有聚合的能力状态查询。不可用性是调用方通过执行观察到的事实:`search()`/`fetch()` 在调用时解析提供方,并抛出命名了失败原因的结构化 `WebError`。[观察面 RFC](../simplification/2026-07-04-drop-unconsumed-web-observation-surface.md) 记录了这一判断:基于调用的派生选择与基于启用的注册使得没有消费方需要变更信号或独立于执行和错误路由的可用性探测;未来的提供方状态面板会重新引入它实际消费的最小信号或查询。 +该 seam 刻意不暴露任何观察面——没有注册表变更事件,也没有聚合的能力状态查询。不可用性是调用方通过执行观察到的事实:`search()`/`fetch()` 在调用时解析提供方,并抛出命名了失败原因的结构化 `WebError`。[观察面 Agent Note](../simplification/2026-07-04-drop-unconsumed-web-observation-surface.md) 记录了这一判断:基于调用的派生选择与基于启用的注册使得没有消费方需要变更信号或独立于执行和错误路由的可用性探测;未来的提供方状态面板会重新引入它实际消费的最小信号或查询。 ## 包拓扑 @@ -77,6 +77,8 @@ flowchart LR `ctx.web` 是一个提供方注册表加上一个带提供方选择的执行面。注册表部分与 `LlmService` 保持接近:每种能力类别一个 `Map<id, provider>`,`registerSearchProvider`/`registerFetchProvider` 方法返回 disposer,重复 id 抛出 `WebError`,执行时解析在选定提供方缺失或不可用时抛出异常。权威签名见 `packages/web/web/src/types.ts`;seam 的形状: ```ts +import type { WebFetchRequest, WebFetchResult, WebSearchRequest, WebSearchResult } from '@deepseek-ai/dsh-web' + interface WebSearchProvider { readonly id: string available(): boolean @@ -208,18 +210,18 @@ seam 请求刻意不包含逐调用超时、`format`、`prompt` 或提供方特 HTTP 状态码是已获取资源状态的一部分,不自动构成工具失败。成功的网络获取一个 `404` 或 `500` 响应会返回带有状态码和有界解码正文(当内容类型受支持时)的 `WebFetchResult`。`WebError` 用于无法安全获取或表示资源的失败:无效或被阻断的 URL、重定向策略违规、超时、abort、响应过大、不支持的内容类型、提供方失败或网络失败。 ```ts -interface WebFetchRequest { +export interface WebFetchRequest { readonly url: string } -interface WebFetchResult { +export interface WebFetchResult { readonly url: string readonly statusCode: number readonly body: WebFetchBody readonly truncated: boolean } -type WebFetchBody = +export type WebFetchBody = | { readonly kind: 'html'; readonly content: string } | { readonly kind: 'text'; readonly content: string } ``` @@ -278,7 +280,7 @@ prompt 引导解释了语义分工——`web_search` 用于发现和获取当前 ## 测试 -每一层在自己的 seam 处固定:`dsh-web` 中的注册/选择/截断/abort 契约与 `WebError` 码;每个提供方基于录制的 fixture(测试前置数据)的请求/响应映射(Perplexity fixture 包含纯 URL 引用,以保持可选 source 字段的诚实性),加上每个真实提供方的自跳过带密钥冒烟测试;`web-fetch-local` 中的真实本地 HTTP 行为;`dsh-tool-web` 中通过真实工具注册表的启用驱动注册、结构化执行错误和结果格式化。一个真实 Loader 冒烟测试守护两种导出形状([事后分析 0001](../../../postmortem/0001-acp-default-export-drops-inject.md)):`dsh-web` 是默认导出的服务,而提供方和 `tool-web` 是命名空间插件,误加 `export default` 会丢失 `inject`。 +每一层在自己的 seam 处固定:`dsh-web` 中的注册/选择/截断/abort 契约与 `WebError` 码;每个提供方基于录制的 fixture(测试前置数据)的请求/响应映射(Perplexity fixture 包含纯 URL 引用,以保持可选 source 字段的诚实性),加上每个真实提供方的自跳过带密钥冒烟测试;`web-fetch-local` 中的真实本地 HTTP 行为;`dsh-tool-web` 中通过真实工具注册表的启用驱动注册、结构化执行错误和结果格式化。一个真实 Loader 冒烟测试守护两种导出形状([事后分析 0001](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md)):`dsh-web` 是默认导出的服务,而提供方和 `tool-web` 是命名空间插件,误加 `export default` 会丢失 `inject`。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml index 609b27aa6a..8f3276b131 100644 --- a/.agents/notes/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-26-file-context-as-event-gate.i18n.yaml @@ -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 -2026-06-26-file-context-as-event-gate.md: ac9a8bcbc5bfda2b35cae4993497273608abf35b -2026-06-26-file-context-as-event-gate.zh.md: eda637f9adf8346779c70d59575863bf7e1162c9 +2026-06-26-file-context-as-event-gate.md: 4700222aa2e0f91d9f355495c228e2eb92825f55 +2026-06-26-file-context-as-event-gate.zh.md: cf490c9f59f1914f1d5d6bdd9fdf4c08711db91e diff --git a/.agents/notes/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md b/.agents/notes/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md index eda637f9ad..cf490c9f59 100644 --- a/.agents/notes/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-26-file-context-as-event-gate.zh.md @@ -1,4 +1,4 @@ -# RFC: 将 `dsh-fs-policy` 改为事件门控插件,而非方法接口 +# Agent Note: 将 `dsh-fs-policy` 改为事件门控插件,而非方法接口 Status: implemented @@ -6,12 +6,12 @@ Status: implemented ## 问题 -[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 在面向模型的工具与 `ctx.fs` 提供方之间放置了 `ctx.fileContext`:`dsh-tool-fs` 注入 `fileContext`,并将每次 `read`/`write`/`edit` 路由到它的方法。这使得 `fileContext` **位于关键路径上且不可省略**。工具不经过它就无法访问 `ctx.fs`,策略层掌控着 fs I/O 和读取窗口,而一个不需要观测状态策略的部署也无法简单地移除该包——`dsh-tool-fs` 会因无法解析 `ctx.fileContext` 而失败。 +[split-fs-seam Agent Note](../simplification/2026-06-26-fsspec-style-fs-seam.md) 在面向模型的工具与 `ctx.fs` 提供方之间放置了 `ctx.fileContext`:`dsh-tool-fs` 注入 `fileContext`,并将每次 `read`/`write`/`edit` 路由到它的方法。这使得 `fileContext` **位于关键路径上且不可省略**。工具不经过它就无法访问 `ctx.fs`,策略层掌控着 fs I/O 和读取窗口,而一个不需要观测状态策略的部署也无法简单地移除该包——`dsh-tool-fs` 会因无法解析 `ctx.fileContext` 而失败。 这把三件本应可分离的事情耦合在了一起: 1. **工具做什么**——解析路径、读取窗口、写入/编辑文件。这是工具的职责,只需要 `ctx.fs`。 -2. **新鲜度/观测策略**——"编辑前必须先读"、"写入/编辑必须基于你读到的版本"。这是 `dsh-fs-policy` 插件的职责。 +2. **新鲜度/观测策略**——「编辑前必须先读」、「写入/编辑必须基于你读到的版本」。这是 `dsh-fs-policy` 插件的职责。 3. **观测状态的记录**——一个副作用,永远不应阻止工具正常运行。 由于工具调用的是 `fileContext` 方法,移除策略层就是一个破坏性变更,而非优雅地失去一个*附加*能力。策略层对工具的运行是承重性的,而非可选的收紧。 @@ -37,12 +37,12 @@ provider dsh-fs-local local implementation of ctx.fs ## 策略由提供方 CAS 强制执行,而非 `dsh-fs-policy` 的 stat -`dsh-fs-policy` 强制执行"你必须基于你读到的版本来写入/编辑",**自身从不调用 `stat` 或比较版本**。它将观测到的版本作为 CAS 基准提供,让提供方的 mutation 临界区检测陈旧性: +`dsh-fs-policy` 强制执行「你必须基于你读到的版本来写入/编辑」,**自身从不调用 `stat` 或比较版本**。它将观测到的版本作为 CAS 基准提供,让提供方的 mutation 临界区检测陈旧性: -- "你读过这个文件吗?"是 `dsh-fs-policy` 在本地决定的唯一事项——一次 `WeakMap` 查找,无 I/O。无记录 ⇒ `FS_NOT_OBSERVED`。 -- "你读到的版本是否仍为最新?"由 **`ctx.fs.editText`/`writeText` 内部**决定,在执行 read-match-rename 的同一个原子锁中完成。`dsh-fs-policy` 将 `vObserved` 作为期望值传入;如果文件已变更,提供方抛出 `FS_STALE_VERSION`。 +- 「你读过这个文件吗?」是 `dsh-fs-policy` 在本地决定的唯一事项——一次 `WeakMap` 查找,无 I/O。无记录 ⇒ `FS_NOT_OBSERVED`。 +- 「你读到的版本是否仍为最新?」由 **`ctx.fs.editText`/`writeText` 内部**决定,在执行 read-match-rename 的同一个原子锁中完成。`dsh-fs-policy` 将 `vObserved` 作为期望值传入;如果文件已变更,提供方抛出 `FS_STALE_VERSION`。 -这是有意为之的。如果 `dsh-fs-policy` 在其 waterfall(瀑布式事件)处理器中 stat 并比较版本,该检查与工具实际写入之间会存在 TOCTOU 间隙——文件可能在此期间变化,因此该检查只是一个虚假保证,提供方的锁无论如何都要兜底。将版本检查放在提供方的临界区中既无竞态又无额外 `stat`。所以 `dsh-fs-policy` **不做**任何文件系统 I/O;"必须基于最近一次读取"的保证由 CAS *实现*,`dsh-fs-policy` 只负责选择基准(`vObserved`)并对先前观测进行门控。 +这是有意为之的。如果 `dsh-fs-policy` 在其 waterfall(瀑布式事件)处理器中 stat 并比较版本,该检查与工具实际写入之间会存在 TOCTOU 间隙——文件可能在此期间变化,因此该检查只是一个虚假保证,提供方的锁无论如何都要兜底。将版本检查放在提供方的临界区中既无竞态又无额外 `stat`。所以 `dsh-fs-policy` **不做**任何文件系统 I/O;「必须基于最近一次读取」的保证由 CAS *实现*,`dsh-fs-policy` 只负责选择基准(`vObserved`)并对先前观测进行门控。 ## 提供方契约变更:版本守卫变为可选 @@ -62,7 +62,7 @@ editText(target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion // { version } → edit only at that version, else FS_STALE_VERSION (the current behavior) ``` -`FsWriteIntent` 联合类型本身不变——第三种"无条件"状态通过*省略* `expected` 来表达,因此两个 mutation 共享同一种对称形状(`expected?`:省略 = 无守卫,传入 = 有守卫)。这对 `dsh-fs-policy` 使用的有守卫路径保持完全向后兼容;只有之前不可能出现的"无守卫"情况是新增的,且它是裸提供方的默认行为。无论哪种情况,mutation 仍在后端的 per-target 锁内运行,因此无条件写入/编辑仍是原子的(不会产生撕裂文件);"无条件"去掉的是*版本*前置条件,而非原子性。`editText` 在有守卫和无守卫路径上都将缺失目标报告为 `FS_STALE_VERSION`,保持一个统一的编辑失败码表示"此刻无法编辑该目标"。 +`FsWriteIntent` 联合类型本身不变——第三种「无条件」状态通过*省略* `expected` 来表达,因此两个 mutation 共享同一种对称形状(`expected?`:省略 = 无守卫,传入 = 有守卫)。这对 `dsh-fs-policy` 使用的有守卫路径保持完全向后兼容;只有之前不可能出现的「无守卫」情况是新增的,且它是裸提供方的默认行为。无论哪种情况,mutation 仍在后端的 per-target 锁内运行,因此无条件写入/编辑仍是原子的(不会产生撕裂文件);「无条件」去掉的是*版本*前置条件,而非原子性。`editText` 在有守卫和无守卫路径上都将缺失目标报告为 `FS_STALE_VERSION`,保持一个统一的编辑失败码表示「此刻无法编辑该目标」。 ## 事件词汇(由 `dsh-fs` 拥有) @@ -110,7 +110,7 @@ interface Events { ## 工具契约(`dsh-tool-fs`) -工具保留其面向模型的 schema(`read`/`write`/`edit`,逐字节不变)和 prompt 段落。prompt 引导仍以策略优先,因为加载 fs 工具的部署预期也会加载 `dsh-fs-policy`:模型仍被告知在覆写或编辑前先读取,任何声称"后端"要求如此的措辞应修正为 fs-policy 插件要求如此。裸提供方回退不改变 prompt 立场。 +工具保留其面向模型的 schema(`read`/`write`/`edit`,逐字节不变)和 prompt 段落。prompt 引导仍以策略优先,因为加载 fs 工具的部署预期也会加载 `dsh-fs-policy`:模型仍被告知在覆写或编辑前先读取,任何声称「后端」要求如此的措辞应修正为 fs-policy 插件要求如此。裸提供方回退不改变 prompt 立场。 `dsh-tool-fs` 获得从旧 `fileContext` 方法服务迁移来的执行器职责,包括**读取渲染**(`read-render.ts`:`buildWindow` + `formatReadOutput`、`READ_MAX_BYTES`、`READ_MAX_LINE_LENGTH`、`FileReadOutcome`/`FileTextLine`,以及 `read.ts` 中的 `STREAM_MIN_SIZE`),这些现在是工具的渲染细节,因为读取已由工具拥有。这些读取渲染类型和辅助函数移入 `dsh-tool-fs`;策略插件不得继续作为工具的类型依赖。 @@ -134,7 +134,7 @@ interface Events { - `fs/edit-intent` 监听器:`prior = getObserved(owner, key)`;如果无 `owner` 或无 `prior`,抛出 `FS_NOT_OBSERVED`;否则返回 `{ version: prior.version }`。同样不调用 `next()`。 - `fs/observed` 监听器:`record(owner, key, version)`。 -一条观测状态条目是**先前观测记录**:成功的 `read`、`write` 或 `edit` 都会 emit `fs/observed` 并记录 `{ version }`,因此条目的存在意味着"此 owner 在此版本观测过此目标",而非狭义的"已读取过"。这使得 create-then-edit 或 edit-then-edit 序列无需中间重新读取即可工作:mutation 将记录的版本刷新为自身的结果,因此下一次编辑的基准就是它刚产出的版本。`FS_NOT_OBSERVED` 只拒绝完全没有任何先前观测的编辑。owner 从 `{ agent?: { session? } }` 结构化推导;dispose 时丢弃所有状态(HMR 安全)。 +一条观测状态条目是**先前观测记录**:成功的 `read`、`write` 或 `edit` 都会 emit `fs/observed` 并记录 `{ version }`,因此条目的存在意味着「此 owner 在此版本观测过此目标」,而非狭义的「已读取过」。这使得 create-then-edit 或 edit-then-edit 序列无需中间重新读取即可工作:mutation 将记录的版本刷新为自身的结果,因此下一次编辑的基准就是它刚产出的版本。`FS_NOT_OBSERVED` 只拒绝完全没有任何先前观测的编辑。owner 从 `{ agent?: { session? } }` 结构化推导;dispose 时丢弃所有状态(HMR 安全)。 `dsh-fs-policy` 现在是一个纯策略/记录插件,没有服务面——它只通过事件 seam 影响外界。这正是移除 `dsh-tool-fs` 方法耦合的关键。 @@ -144,13 +144,13 @@ interface Events { - **read** 行为不变(它从不需要策略;只是 emit 了一个现在无人监听的 `fs/observed`)。 - **write** 无条件 create-or-overwrite:`expected` 为 `undefined`,因此 `writeText` 无论文件是否存在、无论当前版本如何都直接写入。无先读要求,无版本检查。 -- **edit** 无条件替换文件当前内容中的字面文本:`expected` 为 `undefined`,因此 `editText` 无版本守卫、无先读要求地匹配并重写(`FS_EDIT_NOT_FOUND`/`FS_AMBIGUOUS_EDIT` 仍适用——它们关乎字面匹配,而非新鲜度)。缺失目标仍报告 `FS_STALE_VERSION`,与有守卫编辑路径的"此刻无法编辑该目标"错误码一致。 +- **edit** 无条件替换文件当前内容中的字面文本:`expected` 为 `undefined`,因此 `editText` 无版本守卫、无先读要求地匹配并重写(`FS_EDIT_NOT_FOUND`/`FS_AMBIGUOUS_EDIT` 仍适用——它们关乎字面匹配,而非新鲜度)。缺失目标仍报告 `FS_STALE_VERSION`,与有守卫编辑路径的「此刻无法编辑该目标」错误码一致。 两个 mutation 仍是原子的(后端的 per-target 锁是无条件的)。仅仅是*不存在*(而非丢失)的是 `dsh-fs-policy` 本会叠加的策略:观测状态、先读后编辑和版本守卫的写入/编辑。加载 `dsh-fs-policy` 后,其监听器返回有守卫的 `expected` 值而非 `undefined`,从而叠加这些约束;裸提供方本身无需任何变更。 ## 取代关系 -本 RFC 修正——而非推翻——[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md)。四层拆分、提供方契约和新鲜度*策略*均保留。变更的是**工具与策略层之间的耦合方式**:强制性方法服务变为插件拥有的事件门控,fs I/O + 读取窗口从 `fileContext` 上移至 `dsh-tool-fs`。split-fs-seam RFC 中关于 `dsh-tool-fs` 注入 `fileContext` 以及 `fileContext` 拥有 `read`/`write`/`edit` 的描述已在同一变更中更新。 +本 Agent Note 修正——而非推翻——[split-fs-seam Agent Note](../simplification/2026-06-26-fsspec-style-fs-seam.md)。四层拆分、提供方契约和新鲜度*策略*均保留。变更的是**工具与策略层之间的耦合方式**:强制性方法服务变为插件拥有的事件门控,fs I/O + 读取窗口从 `fileContext` 上移至 `dsh-tool-fs`。split-fs-seam Agent Note 中关于 `dsh-tool-fs` 注入 `fileContext` 以及 `fileContext` 拥有 `read`/`write`/`edit` 的描述已在同一变更中更新。 ## 验证 @@ -158,14 +158,14 @@ interface Events { ## 曾考虑的替代方案 -- **保留 `ctx.fileContext` 作为关键路径上的方法服务**——[split-fs-seam RFC](../simplification/2026-06-26-fsspec-style-fs-seam.md) 最初落地的形态;否决,因为工具无法在没有策略层的情况下运行,使策略对基本操作是承重性的,而非可选的收紧。 +- **保留 `ctx.fileContext` 作为关键路径上的方法服务**——[split-fs-seam Agent Note](../simplification/2026-06-26-fsspec-style-fs-seam.md) 最初落地的形态;否决,因为工具无法在没有策略层的情况下运行,使策略对基本操作是承重性的,而非可选的收紧。 - **策略侧版本检查**(`dsh-fs-policy` 在其 waterfall 处理器中 stat 并比较版本)——否决,因为该检查与工具实际写入之间存在 TOCTOU 间隙;提供方的 mutation 临界区是唯一无竞态的位置,因此策略只选择 CAS 基准并对先前观测进行门控。 - **每工具 `/read`/`/write`/`/edit` 子路径插件**——实现时放弃:没有消费方需要单工具部署,且子路径发布迫使引入兄弟工具包都不需要的定制 `tsdown`/`tsconfig`/`files`/workspace-constraint 处理;每工具的注册辅助函数仍作为根插件组合的内部模块保留。 ## 后果 - **事件间接层取代方法调用。** 一次 waterfall + emit 不如 `await ctx.fileContext.edit(...)` 直接。收益是移除了工具到策略的方法依赖,同时保留默认策略插件;代价是多一套事件词汇需要学习。通过保持三个事件的窄小范围并在每个事件上记录 default-thunk 语义来缓解。 -- **策略事件位于存储 seam 中。** `dsh-fs` 增加了两个版本决策事件和一个记录事件,尽管它"只是存储"。这是解耦的代价(发射方不能依赖策略插件)。这些事件只携带 `dsh-fs` 词汇加一个不透明的 `object` actor,不携带面向模型的概念,因此 seam 不沾染行窗口/观测策略类型,也不沾染 agent/session owner 结构。 -- **单一策略占位者,按约定先到先得。** `fs/write-intent`/`fs/edit-intent` 槽位恰好容纳一个决策者;先注册(或 `prepend`)的监听器获胜,其余被短路。`dsh-fs-policy` 占据该槽位是部署约定,而非事件系统强制的不变式——一个先注册的第二决策者会绕过它。这是可接受的,因为第二个 fs 版本策略决策者是配置错误,而非功能。如果未来出现*分层* fs 版本策略的需求,那是一个新 RFC(可组合的值传递 seam),而非在这些事件上静默添加第二个监听器。分层的权限/审计/沙箱拦截已有其归属:`tools/execute`。 +- **策略事件位于存储 seam 中。** `dsh-fs` 增加了两个版本决策事件和一个记录事件,尽管它「只是存储」。这是解耦的代价(发射方不能依赖策略插件)。这些事件只携带 `dsh-fs` 词汇加一个不透明的 `object` actor,不携带面向模型的概念,因此 seam 不沾染行窗口/观测策略类型,也不沾染 agent/session owner 结构。 +- **单一策略占位者,按约定先到先得。** `fs/write-intent`/`fs/edit-intent` 槽位恰好容纳一个决策者;先注册(或 `prepend`)的监听器获胜,其余被短路。`dsh-fs-policy` 占据该槽位是部署约定,而非事件系统强制的不变式——一个先注册的第二决策者会绕过它。这是可接受的,因为第二个 fs 版本策略决策者是配置错误,而非功能。如果未来出现*分层* fs 版本策略的需求,那是一个新 Agent Note(可组合的值传递 seam),而非在这些事件上静默添加第二个监听器。分层的权限/审计/沙箱拦截已有其归属:`tools/execute`。 - **移除读后确认 stat** 使后续*有守卫*的编辑在 read/write 竞争下偶尔快速失败(`FS_STALE_VERSION` → 重新读取)。这是丢失的 UX 便利,绝非正确性漏洞;提供方锁仍阻止基于错误版本的写入。 - **裸提供方不做先读后写/编辑,也不做版本检查。** 没有 `dsh-fs-policy` 的部署允许模型无条件覆写或编辑任何已有文件。这正是保持工具独立于策略服务的有意含义:安全纪律存在于 `dsh-fs-policy` 插件中。省略它的部署是有意选择无约束的文件系统;对于发布 fs 工具的配置而言,这不是预期的姿态。 diff --git a/.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml index d4d7cb2482..51d0eb9a78 100644 --- a/.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.i18n.yaml @@ -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 -2026-06-30-bash-stdin-env-trusted-plugin-surface.md: 712c17532bc1e6b95479aec5b544bc7e296952ec -2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md: db50f08dae30aa0c43e741a4f27f948f712954e0 +2026-06-30-bash-stdin-env-trusted-plugin-surface.md: 284cd45a66294dbc9e8207a1e00e9642d32d4e58 +2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md: 9486f8c35c5060150b072fb673acca5d4167ec1a diff --git a/.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md b/.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md index db50f08dae..9486f8c35c 100644 --- a/.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.zh.md @@ -1,4 +1,4 @@ -# RFC: 在 bash seam 上支持 stdin 与额外 env +# Agent Note: 在 bash seam 上支持 stdin 与额外 env Status: implemented @@ -6,9 +6,9 @@ Status: implemented ## 问题 -钩子子系统以 Claude Code 和 Codex 的方式运行外部钩子命令:钩子是一条 shell 命令,通过 **stdin 上的 JSON** 接收事件载荷,并从若干**环境变量**(`CLAUDE_PROJECT_DIR`、`CLAUDE_PLUGIN_ROOT`、`PLUGIN_ROOT`……)读取上下文。harness 已经在 `ctx.bash` 能力 seam 后面有一个完善的命令执行器([dsh-bash](../../../../packages/bash/bash) → [dsh-bash-local](../../../../packages/bash/bash-local)),具备进程组终止、输出截断/溢出处理和凭证擦除功能。复用它来执行钩子意味着钩子桥接层无需重新实现子进程管道——但该 seam 此前无法写入 stdin 或设置额外 env。本 RFC 添加这两个输入。 +钩子子系统以 Claude Code 和 Codex 的方式运行外部钩子命令:钩子是一条 shell 命令,通过 **stdin 上的 JSON** 接收事件载荷,并从若干**环境变量**(`CLAUDE_PROJECT_DIR`、`CLAUDE_PLUGIN_ROOT`、`PLUGIN_ROOT`……)读取上下文。harness 已经在 `ctx.bash` 能力 seam 后面有一个完善的命令执行器([dsh-bash](../../../../packages/bash/bash) → [dsh-bash-local](../../../../packages/bash/bash-local)),具备进程组终止、输出截断/溢出处理和凭证擦除功能。复用它来执行钩子意味着钩子桥接层无需重新实现子进程管道——但该 seam 此前无法写入 stdin 或设置额外 env。本 Agent Note 添加这两个输入。 -`stdin` 和 `env` 不构成新的模型能力,因为普通 shell 语法已经能提供两者。环境凭证由 `dsh-bash-local` 的子环境擦除机制保护,而非靠隐藏这些 seam 字段;模型工具参数是静态 JSON,不会展开 shell 变量。因此这些字段服务于受信的进程内调用方(如钩子桥接层),它们需要传递结构化输入和 `CLAUDE_*` 变量,而不必将其嵌入模型可见的 shell 文本。环境变量规则见 [defensive-patterns.md](../../../defensive-patterns.md)。 +`stdin` 和 `env` 不构成新的模型能力,因为普通 shell 语法已经能提供两者。环境凭证由 `dsh-bash-local` 的子环境擦除机制保护,而非靠隐藏这些 seam 字段;模型工具参数是静态 JSON,不会展开 shell 变量。因此这些字段服务于受信的进程内调用方(如钩子桥接层),它们需要传递结构化输入和 `CLAUDE_*` 变量,而不必将其嵌入模型可见的 shell 文本。环境变量规则见 [defensive-patterns.md](../../../../docs/defensive-patterns.md)。 ## 决策 @@ -16,9 +16,9 @@ Status: implemented 三个有意为之的选择: -1. **模型侧工具不暴露 `stdin` 和 `env`。** Shell 语法已覆盖这些需求,重复参数只会增加接口面而不带来权限隔离。工具仅从声明的模型参数、signal 和 owner 构建请求;受信的进程内调用方可以直接设置 seam 字段。 +1. **模型侧工具不暴露 `stdin` 和 `env`。** Shell 语法已覆盖这些需求,重复参数只会增加接口面而不带来权限隔离。工具仅从声明的模型参数、signal 和 owner 构建请求;受信的进程内调用方可以直接设置 seam 字段。harness 自有变量使用[托管环境决策](../feature/2026-07-10-agent-session-identity-and-log-location.md)规定的独立 `dshEnv` 通道,因此普通 `env` 无法替换它们。 -2. **`env` 在凭证擦除之后合并,因此调用方显式设置的条目总是胜出**——即使键名与凭证同形。这是正确的,因为擦除的职责很窄:阻止 harness 的*环境* `process.env` 凭证泄漏到被 spawn 的命令中。调用方显式设置一个变量时,它命名的是自己已持有的值(而非环境中的秘密),因此擦除不构成对它的约束。`childEnv(extra?)` 按 `scrub(process.env)` → `ENV_OVERRIDES`(对模型友好的 `TERM=dumb` 等)→ `extra` 的顺序分层,后者优先。 +2. **`env` 在凭证擦除之后合并,因此调用方显式设置的条目即使具有凭证形态的名称也会胜出。** 后续的托管命名空间决策保留 `DSH_*`:环境条目会被移除,普通 `env` 无法设置它们,受信的 `dshEnv` 最后合并。完整顺序为 `scrub(process.env, including DSH_*)` → `ENV_OVERRIDES` → 普通 `env` → `dshEnv`。 3. **`stdin`/`env` 在已解析 spec 上是 required-absent-OK(普通 optional),而非像 `owner` 那样 required-but-nullable。** `owner` 之所以是 required-but-nullable,是因为*静默*缺失的 owner 会产生一个无主、跨会话可读的任务——一个安全隐患,显式的 `undefined` 可以防范。`stdin`/`env` 没有这种风险:缺失意味着「无 stdin / 无额外 env」,这是安全的常规情况(所有模型驱动的调用都如此)。因此它们保持普通 optional,与 `signal` 一致。 @@ -30,4 +30,4 @@ Status: implemented ## 后果 -钩子桥接层通过既有的 bash seam 传递 JSON 载荷和钩子特定变量,保留其进程组终止、截断和溢出行为。模型接口面不变,bash 工具仍是模型调用请求构建的唯一所有者。相关词汇定义见 [bash 数据结构参考](../../../core-data-structures/bash.md)。 +钩子桥接层通过既有的 bash seam 传递 JSON 载荷和钩子特定变量,保留其进程组终止、截断和溢出行为。模型接口面不变,bash 工具仍是模型调用请求构建的唯一所有者。相关词汇定义见 [bash 数据结构参考](../../../../docs/core-data-structures/bash.md)。 diff --git a/.agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml b/.agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml index 1b064ea80a..b68aef5fd2 100644 --- a/.agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.i18n.yaml @@ -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 -2026-06-30-event-domain-semantics.md: a9d33a7bfb549e1ec2102c23af78f91d9ae4b904 -2026-06-30-event-domain-semantics.zh.md: dc7390e3d2e1cda3469fa77389d0d6ad39b7a713 +2026-06-30-event-domain-semantics.md: 7310840088d4ff77ddf83c5c16753b4d46256692 +2026-06-30-event-domain-semantics.zh.md: b082fdfda36968e1946ba6325f2315a970cd445b diff --git a/.agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.zh.md b/.agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.zh.md index dc7390e3d2..b082fdfda3 100644 --- a/.agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.zh.md +++ b/.agents/notes/implemented/architecture/2026-06-30-event-domain-semantics.zh.md @@ -1,4 +1,4 @@ -# RFC: 事件域语义——session 是事实日志,agent 是运行时表面 +# Agent Note: 事件域语义——session 是事实日志,agent 是运行时表面 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环)(见[微内核事件分类体系 RFC](2026-06-11-microkernel-event-taxonomy.md))。随着该分类体系的增长,三个事件域之间的界限变得模糊: +harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环)(见[微内核事件分类体系 Agent Note](2026-06-11-microkernel-event-taxonomy.md))。随着该分类体系的增长,三个事件域之间的界限变得模糊: - `session/*` 承载持久的、事件溯源的日志(`SessionEventMap`)。 - `agent/*` 承载运行时实时信号,向插件传递 `Agent` 句柄。 @@ -26,14 +26,14 @@ harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环) **边界规则:** 持久的、可回放的事实是 `SessionEvent`;实时拦截或瞬态/活对象信号是 `agent`/`tools` Cordis 事件。轮次或步骤边界是持久事实,因此存在于 session 日志中并从 `session/event` 源读取——不会被镜像为 `agent/*` emit。 -**将规则应用于边界镜像:** 全部四个边界镜像——`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`——被**移除**。没有生产消费方需要在边界处获取活的 `Agent`:ACP 桥接从 `session/event` 的 `turn/end` 加 `agent/status` 结算;唯一的 turn 镜像消费方(`dsh-ui-stdio`,一个一次性测试 REPL)已迁移为从 `session/event` 渲染边界,通过 `agent/created`→id 映射恢复简短的 agent 标签。step 镜像先被移除(它们完全没有消费方);turn 镜像在 ui-stdio 迁移后随之移除,见[移除边界镜像事件 RFC](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md),该决策由它负责。移除 emit 也简化了循环的 `closeStep`/`closeTurn`(各只需一次 append,无需配对 emit)。 +**将规则应用于边界镜像:** 全部四个边界镜像——`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`——被**移除**。没有生产消费方需要在边界处获取活的 `Agent`:ACP 桥接从 `session/event` 的 `turn/end` 加 `agent/status` 结算;唯一的 turn 镜像消费方(`dsh-ui-stdio`,一个一次性测试 REPL)从 `session/event` 渲染边界,同时保留其实时目标对象用于固定的 `main` 标签。step 镜像先被移除(它们完全没有消费方);turn 镜像在 ui-stdio 迁移后随之移除,见[移除边界镜像事件 Agent Note](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md),该决策由它负责。移除 emit 也简化了循环的 `closeStep`/`closeTurn`(各只需一次 append,无需配对 emit)。 ## 后果 - 循环不再 emit 任何边界镜像;`closeStep` 仅追加 `step/end`,`closeTurn` 仅追加 `turn/end`。`Session.append` 负责 post-commit observer 隔离,因此抛出异常的边界 observer 无法改变轮次结果或饿死后续消费方;接受或内部校验失败仍会在边界进入日志之前逃逸。 - 之前通过已移除 emit 观察边界的测试,现在观察持久的 `turn/start`/`turn/end`/`step/start`/`step/end` session 事件——它们固定的行为(边界顺序、步骤计数)不变;只是读取的源移到了规范源。那些测试*抛出异常的 turn 边界 emit 监听器*的用例被删除,因为该代码路径不再存在(没有 emit 可供抛出)。按照 [AGENTS.md「测试记录行为,而非黄金真相」](../../../../AGENTS.md),行为与其测试一同迁移(或一同消亡)。 - 循环仅在 `append('step/start')` 返回后才标记步骤已打开(`stepOpen = true`)。内部分发校验在日志推入之前运行,可能在不打开步骤的情况下拒绝;post-commit `session/event` observer 的失败被隔离在 `Session.append` 内部。因此该标记精确表示已提交的、欠一个后续 `step/end` 的边界。 -- 完整实现见[简化 RFC「停止将持久边界镜像为 agent 事件」](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md):全部四个边界镜像被移除,所有消费方从 `session/event` 读取边界。`agent/steering`(不是边界镜像)不在该 RFC 范围内,由其后续 RFC [移除 `agent/steering` 镜像 emit](../simplification/2026-07-04-remove-agent-steering-mirror.md) 单独移除——它镜像的是持久的 `steering/message`。 +- 完整实现见[简化 Agent Note「停止将持久边界镜像为 agent 事件」](../simplification/2026-06-20-remove-agent-boundary-mirror-events.md):全部四个边界镜像被移除,所有消费方从 `session/event` 读取边界。`agent/steering`(不是边界镜像)不在该 Agent Note 范围内,由其后续 Agent Note [移除 `agent/steering` 镜像 emit](../simplification/2026-07-04-remove-agent-steering-mirror.md) 单独移除——它镜像的是持久的 `steering/message`。 - Cordis 事件目录(`docs/cordis-catalog/events.md`)重新生成以移除镜像事件。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml index 1af8dd8fe3..fb07c3c828 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.i18n.yaml @@ -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 -2026-07-02-fs-per-session-cwd.md: 2513294d6bc991ee39155bbf20869829cca1a188 -2026-07-02-fs-per-session-cwd.zh.md: 2c3957113642fe2bf7b3a4f2b6186246b32aff3f +2026-07-02-fs-per-session-cwd.md: aeb17e0a235720bee277f6533468dbdb6cae82dc +2026-07-02-fs-per-session-cwd.zh.md: 34b868761112b3dab31699cd7c945a64e22b7d59 diff --git a/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.md b/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.md index 0a6d9b85b1..aeb17e0a23 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.md +++ b/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-07-02-fs-per-session-cwd.zh.md) + ## Problem The ACP bridge gives every session its own workspace: `session/new` records the editor's project directory as `SessionHeader.cwd`, and `dsh-tool-bash` defaults each bash call's `workdir` to the calling agent's `session.header.cwd` (see [the per-session cwd Agent Note work in `packages/ui/acp`](../../../../packages/ui/acp) and `resolveWorkdir` in `dsh-tool-bash`). So a bash command in session A runs in A's project, and in session B runs in B's — one server process, N workspaces. diff --git a/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md b/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md index 2c39571136..34b8687611 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-02-fs-per-session-cwd.zh.md @@ -1,4 +1,4 @@ -# RFC: 相对文件系统路径按调用方的会话 cwd 解析 +# Agent Note: 相对文件系统路径按调用方的会话 cwd 解析 Status: implemented @@ -6,17 +6,21 @@ Status: implemented ## 问题 -ACP(Agent Client Protocol)桥接层为每个会话提供独立的工作区:`session/new` 将编辑器的项目目录记录为 `SessionHeader.cwd`,`dsh-tool-bash` 将每次 bash 调用的 `workdir` 默认设为调用方 agent(智能体)的 `session.header.cwd`(见 [`packages/ui/acp`](../../../../packages/ui/acp) 中的 per-session cwd RFC 工作与 `dsh-tool-bash` 中的 `resolveWorkdir`)。因此会话 A 中的 bash 命令在 A 的项目目录执行,会话 B 中的在 B 的项目目录执行——一个服务器进程,N 个工作区。 +ACP(Agent Client Protocol)桥接层为每个会话提供独立的工作区:`session/new` 将编辑器的项目目录记录为 `SessionHeader.cwd`,`dsh-tool-bash` 将每次 bash 调用的 `workdir` 默认设为调用方 agent(智能体)的 `session.header.cwd`(见 [`packages/ui/acp`](../../../../packages/ui/acp) 中的 per-session cwd Agent Note 工作与 `dsh-tool-bash` 中的 `resolveWorkdir`)。因此会话 A 中的 bash 命令在 A 的项目目录执行,会话 B 中的在 B 的项目目录执行——一个服务器进程,N 个工作区。 文件系统解析使用的是插件加载时的 cwd,而 bash 使用的是会话的项目目录。因此,当编辑器项目目录与服务器启动目录不同时,相对路径的解析结果就会不一致;快照测试因为让这两个路径相同而掩盖了这个 bug。 +一个有效的绝对 cwd 本身可能看起来有两个父目录:当它包含 `symlink/..` 时,文件系统查找会先跟随符号链接再应用 `..`,而 `path.resolve()` 会从词法上抹掉这两个组件。如果用词法解析沙箱策略却从原始 cwd 启动 bash,就会把权限授予无关的词法父目录、拒绝真实工作区内的写入,并让文件系统工具把相对路径解析进错误目录。 + +普通的符号链接 cwd 在请求的相对路径包含 `..` 时也暴露同一区别:进程从符号链接的物理目标开始遍历,`path.resolve(cwd, path)` 却从其词法拼写开始遍历。因此,对于同一个模型提供的路径,read 会选择与 bash 或沙箱化 mutation 不同的文件。 + ## 决策 -将调用方的会话 cwd 传入路径解析,与 `dsh-tool-bash` 对 `workdir` 的处理方式完全一致。**调用方**(即工具)提供 cwd;提供方不读取会话或 agent。 +将调用方的会话 cwd 传入路径解析,与 `dsh-tool-bash` 对 `workdir` 的处理方式完全一致。当 cwd 或请求路径任一包含父目录段时,在任何词法 join 之前把 cwd 解析为原生文件系统标识;没有遍历会使标识可观察时,则保留普通 cwd 拼写以供展示。mutation 和沙箱化 bash 调用复用解析后的沙箱策略根目录,使一次调用只有一个工作区标识。**调用方**(即工具)提供 cwd;提供方不读取会话或 agent。 -- `FileSystem.resolve` 扩展为 `resolve(path: string, opts?: { cwd?: string }): Promise<FsTarget>`。`opts.cwd` 是相对 `path` 解析时的基准目录;绝对 `path` 忽略它;省略 `opts.cwd` 则使用后端自身的默认值。采用 options 对象(而非位置参数 `cwd?`)为将来的解析提示留出空间,无需再次变更签名。 +- `FileSystem.resolve` 接受 `resolve(path: string, opts?: { cwd?: string; signal?: AbortSignal }): Promise<FsTarget>`。`opts.cwd` 是相对 `path` 解析时的基准目录;绝对 `path` 忽略它;省略 `opts.cwd` 则使用后端自身的默认值。后端执行 I/O 时,`opts.signal` 可以取消解析。options 对象把调用方拥有的两个解析控制项放在一起,避免位置参数继续增长。 - `dsh-fs-local.resolve` 使用 `resolveLocalTarget(opts?.cwd ?? this.config.cwd, path)`。`config.cwd` 仍作为调用方未提供 cwd 时的默认值(非 ACP/无会话场景,以及 `process.cwd()` 本身就是工作区的单会话 stdio 演示)。 -- `dsh-tool-fs` 的 `read`/`write`/`edit` 通过共享的 `sessionCwd(exec)` 辅助函数(`exec.agent?.session.header.cwd`,与 bash 的 `resolveWorkdir` 对应)获取会话 cwd,并传给 `resolve`。非 agent/无 header 的调用方得到 `undefined`,后端因此应用其默认值。 +- `dsh-tool-fs` 的 `read`/`write`/`edit` 通过共享的 `sessionCwd(exec, requestedPath)` 辅助函数(`exec.agent?.session.header.cwd`,与 bash 的 `resolveWorkdir` 对应)获取会话 cwd,并传给 `resolve`。只要任一值中的父目录段可能跨越符号链接,该辅助函数就使用原生 realpath 语义,否则保留普通拼写;沙箱化 mutation 复用完整策略的 `workspaceRoot`;非 agent/无 header 的调用方得到 `undefined`,后端因此应用其默认值。 ## 曾考虑的替代方案 @@ -29,6 +33,7 @@ ACP(Agent Client Protocol)桥接层为每个会话提供独立的工作区 ## 后果 - 在 ACP 演示中,fs 工具与 bash 现在对每个会话的工作区达成一致;编辑器可以打开任意项目目录,两类工具都在该目录下操作。 +- 对于包含 `symlink/..` 的会话 cwd,或普通符号链接 cwd 搭配含父目录遍历的相对路径,bash、文件系统工具和沙箱授权都会从同一个物理工作区解析;词法父目录不会获得授权。 - `FsTarget` 的标识不变:`targetKey` 仍为解析后绝对路径的 realpath,因此 observed-state 键控与符号链接标识不受影响——正确的 per-session cwd 产生与 bash 目标相同的 key。 - 向后兼容:所有现有的 `resolve(path)` 调用(均在测试中)继续正常工作;新参数是可选的。 - 单会话 stdio 演示不受影响:它不提供会话 cwd(其 agent 的会话没有 `cwd`),因此解析回退到 `config.cwd = process.cwd()`,即工作区本身。 diff --git a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml index d05c13ff78..a2f2379e84 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.i18n.yaml @@ -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 -2026-07-02-result-time-applied-hunk-diffs.md: fd02951f21319be2933bf3ffaddeb96bc2a6819c -2026-07-02-result-time-applied-hunk-diffs.zh.md: 4ed9a29bb023343cab28b8114453d17408bc429a +2026-07-02-result-time-applied-hunk-diffs.md: b1e1884f2264f17f6fff17569d79d8352e3fc709 +2026-07-02-result-time-applied-hunk-diffs.zh.md: 091bbb6b9752238348c594a4abe39944b005755d diff --git a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md b/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md index 4ed9a29bb0..091bbb6b97 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.zh.md @@ -1,4 +1,4 @@ -# RFC: 结果时刻的 applied-hunk diff 用于文件变更 +# Agent Note: 结果时刻的 applied-hunk diff 用于文件变更 Status: implemented @@ -8,7 +8,7 @@ Status: implemented [tagged render-intent union](2026-07-02-tool-render-intent-union.md) 为 `dsh-tool-fs` 的 write/edit 在调用时刻提供了 `card:'diff'`,纯粹从工具参数推导:write ⇒ `{oldText:null, newText:content}`(整个新文件),edit ⇒ `{oldText:old_string, newText:new_string}`(裸替换片段)。编辑器将其渲染为行内 diff,但这是一个**无上下文**的 diff:裸的 `old_string`→`new_string` 没有周围行,而一次触及五个分散位置的 `replace_all` 仍然渲染为一对片段。 -在对接 `claude-agent-acp` 自身的 ACP(Agent Client Protocol) bridge 时可以看到完整编辑器 diff 的样子:变更应用后,它发出第二个 `tool_call_update`,其 diff 是**带 ±3 行上下文的 applied hunk**(`replace_all` 的每个变更位置各一个 hunk),由工具的 `structuredPatch` 重建。这个结果时刻的 hunk 正是让 Zed 在文件中*原位*显示变更(而非浮动片段)的关键。我们的工具止步于调用时刻的片段;完成后的结果只携带纯文本 "updated successfully",没有 diff。 +在对接 `claude-agent-acp` 自身的 ACP(Agent Client Protocol) bridge 时可以看到完整编辑器 diff 的样子:变更应用后,它发出第二个 `tool_call_update`,其 diff 是**带 ±3 行上下文的 applied hunk**(`replace_all` 的每个变更位置各一个 hunk),由工具的 `structuredPatch` 重建。这个结果时刻的 hunk 正是让 Zed 在文件中*原位*显示变更(而非浮动片段)的关键。我们的工具止步于调用时刻的片段;完成后的结果只携带纯文本「updated successfully」,没有 diff。 障碍在于一个 seam 边界:`presentResult(args, result)` 是 **`args` + 面向模型的 `result`(`{content, isError}`)的纯函数**——它在实时流式输出和会话日志回放中都会运行,因此必须具备回放确定性且不能做 I/O。它看不到文件的前后内容,而 `FsEditOutcome`/`FsWriteOutcome` 只携带替换计数和版本号,没有文本。因此无法计算——甚至无法携带——applied hunk 给 presenter。 @@ -26,7 +26,7 @@ type ToolExecuteReturn = ContentBlock[] | { content: ContentBlock[]; meta?: unkn `meta` 是工具自有的 `unknown`,core 持久化但不解释。`Session.append` 拒绝非 JSON 值,回放时将存储的载荷回传给 `presentResult`;因此展示无需 I/O 或重新计算即可复现。运行时校验避免了向 tools core 添加共享的 serializable-value 依赖。 -这是通用形态("工具附加持久化的结果展示"),而非 fs 特有的——任何工具都可以使用。 +这是通用形态(「工具附加持久化的结果展示」),而非 fs 特有的——任何工具都可以使用。 ### 2. 工具计算 hunk;后端返回 before/after(fs) @@ -56,6 +56,6 @@ type ToolExecuteReturn = ContentBlock[] | { content: ContentBlock[]; meta?: unkn ## 相关 -- 补全了 [Tagged render-intent union](2026-07-02-tool-render-intent-union.md) 中作为非目标列出的最后一项表示差异——该 RFC 的「非目标」一节已更新,记录 applied-hunk diff 在此处交付。 +- 补全了 [Tagged render-intent union](2026-07-02-tool-render-intent-union.md) 中作为非目标列出的最后一项表示差异——该 Agent Note 的「非目标」一节已更新,记录 applied-hunk diff 在此处交付。 - 基于[文件系统 capability seam](2026-06-17-filesystem-capability-seam.md)(before/after 是后端返回的存储事实)和[事件溯源会话](2026-06-11-event-sourced-sessions.md)(`meta` 载荷持久化在 `tool/result` 事件上,因此回放可复现卡片)。 - `meta` 通道有意设计为通用的:未来的工具(结构化搜索、数据表结果)可以附加自己的持久化结果展示而无需再改 core。 diff --git a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml index 607ff343ce..6f93853732 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.i18n.yaml @@ -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 -2026-07-02-tool-render-intent-union.md: 6b828c32fb79f43c0f974f2c9f032e11430de5b4 -2026-07-02-tool-render-intent-union.zh.md: 8c44178ca3e8986579e7ed696aec2f900705e9ad +2026-07-02-tool-render-intent-union.md: c7adf8f405000ec7940f82e1e1e2406d86253461 +2026-07-02-tool-render-intent-union.zh.md: c77455b2d8c47add16e36f1b8a8ac3bb12f02707 diff --git a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md index 8c44178ca3..c77455b2d8 100644 --- a/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md @@ -1,4 +1,4 @@ -# RFC: 用于工具调用展示的带标签 render-intent 联合类型 +# Agent Note: 用于工具调用展示的带标签 render-intent 联合类型 Status: implemented @@ -12,7 +12,7 @@ Status: implemented - 哪些组合是*合法的*没有文档说明:一个设置了 `content` 的 `terminal` 调用意味着「卡片上方的描述」;一个设置了 `terminal` 的 generic 调用毫无意义但类型上可表达。类型允许无意义的状态存在。 - 无法表达编辑器最需要的文件工具能力:**diff 卡片**(`{path, oldText, newText}`,Zed 将其渲染为内联 diff / 新文件预览)。`ToolCallPresentation.content` 使用的是 *LLM(大语言模型)* 的 `ContentBlock[]` 词汇(text/image),工具根本无法请求 diff 展示。 -`packages/core/tools/src/index.ts` 中已有的 `FIXME(tool-presentation)` 指出了修复方向:「重新设计类型,让工具一次性声明其渲染意图(例如按卡片种类的带标签联合类型),而非一堆由 bridge 拼接的可选字段。」被否决的 RFC [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) 明确推迟了此事:富渲染「应当在至少有两个真实工具和两个真实消费方验证词汇之后,以带标签 render-intent 联合类型的形式回归。」该条件现已满足:两个生产者族(`dsh-tool-bash`、`dsh-tool-fs`)和两个消费方(ACP bridge 实时路径 + snapshot-golden 回放路径)。 +`packages/core/tools/src/index.ts` 中已有的 `FIXME(tool-presentation)` 指出了修复方向:「重新设计类型,让工具一次性声明其渲染意图(例如按卡片种类的带标签联合类型),而非一堆由 bridge 拼接的可选字段。」被否决的 Agent Note [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md) 明确推迟了此事:富渲染「应当在至少有两个真实工具和两个真实消费方验证词汇之后,以带标签 render-intent 联合类型的形式回归。」该条件现已满足:两个生产者族(`dsh-tool-bash`、`dsh-tool-fs`)和两个消费方(ACP bridge 实时路径 + snapshot 回放路径)。 ## 决策 @@ -45,7 +45,7 @@ interface TerminalResultView { card: 'terminal'; title?: string; output?: string ### 生产者映射 - `dsh-tool-fs` read → `generic`(`kind:'read'`,附带一个 follow-along `location`);write → `diff`(`oldText:null`);edit → `diff`(`oldText:old_string || null`,`newText:new_string ?? ''`)。这与 `claude-agent-acp` 的 `toolInfoFromToolUse` 中 Read/Write/Edit 各分支逐字段对应。 -- `dsh-tool-bash` foreground → `terminal` 调用 + `terminal` 结果;`run_in_background` 和 `bash_output`/`bash_kill` → `generic`。 +- `dsh-tool-bash` foreground → `terminal` 调用 + `terminal` 结果;`run_in_background` → `generic`。通用 `task_*` 控制工具拥有各自的 generic 卡片。 - `dsh-tool-todo` → `generic`。 ### 终端回退的归属 @@ -72,11 +72,11 @@ interface TerminalResultView { card: 'terminal'; title?: string; output?: string ## 非目标 -- **实时增量 `terminal_output_delta` 流式输出**与**命令分类**:终端渲染 RFC 自身推迟的后续工作,本 RFC 不涉及。 +- **实时增量 `terminal_output_delta` 流式输出**与**命令分类**:终端渲染 Agent Note 自身推迟的后续工作,本 Agent Note 不涉及。 ## 相关 -- 取代 [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md)(已否决——「等两个真实工具和两个真实消费方,然后做带标签 render-intent 联合类型」)中的推迟决定。该条件现已满足;本 RFC 即为那个联合类型。 +- 取代 [Collapse tool-owned UI presentation](../../rejected/simplification/2026-06-20-generic-tool-rendering.md)(已否决——「等两个真实工具和两个真实消费方,然后做带标签 render-intent 联合类型」)中的推迟决定。该条件现已满足;本 Agent Note 即为那个联合类型。 - 被 [Result-time applied-hunk diffs](2026-07-02-result-time-applied-hunk-diffs.md) 扩展:后者添加了一个持久化的 `meta` 通道,使 write/edit 在结果时输出 `DiffResultView`(应用后的变更:带上下文行的 contextual hunk / 每个 `replace_all` 位点一个,或创建时的整文件 diff),叠加在本联合类型的调用时 diff 卡片之上。 - 将 `ToolTerminal` 折入 [ACP terminal and tool-call rendering](../feature/2026-06-18-acp-terminal-and-tool-rendering.md) 所描述的 `terminal` view(`_meta` terminal 卡片约定和能力门控不变;仅 harness 侧的展示类型改变)。 - ACP SDK 的 `Diff` / `ToolCallContent` 类型支撑新的 `diff` 卡片。 diff --git a/.agents/notes/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml index b28a70da27..1f09f82d11 100644 --- a/.agents/notes/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.i18n.yaml @@ -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 -2026-07-03-filesystem-directory-listing-seam.md: 8920e54993eb1402bd310d6ce78fb9866de628c9 -2026-07-03-filesystem-directory-listing-seam.zh.md: 5ca9b195d4bf5c1450c60451dd469a19dd54166f +2026-07-03-filesystem-directory-listing-seam.md: c7db576ff3c7a56622f90a4400bd9297c9591bef +2026-07-03-filesystem-directory-listing-seam.zh.md: 44996d4c680bb2a0c3e880a120e0f9bd420493cd diff --git a/.agents/notes/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md b/.agents/notes/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md index 5ca9b195d4..44996d4c68 100644 --- a/.agents/notes/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-03-filesystem-directory-listing-seam.zh.md @@ -1,4 +1,4 @@ -# RFC: 为文件系统 seam 添加直接目录列举能力 +# Agent Note: 为文件系统 seam 添加直接目录列举能力 Status: implemented diff --git a/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml index 1ea6573424..87ead153fa 100644 --- a/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.i18n.yaml @@ -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 -2026-07-05-prompt-variables-and-tool-guidance-ownership.md: 1819a730b214270304a8feb103a7f26e9c8d6e6e -2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 4211241b1b24fd461f5341bf8d777007a7a36482 +2026-07-05-prompt-variables-and-tool-guidance-ownership.md: 94f5fa409e7b539b48750d12576c7a342a30c9ba +2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md: 2342b89ab666a7987f78cfeabe6fa90ce9dd0cad diff --git a/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md b/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md index 4211241b1b..2342b89ab6 100644 --- a/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.zh.md @@ -1,4 +1,4 @@ -# RFC: Prompt 变量与工具指导归属 +# Agent Note: Prompt 变量与工具指导归属 Status: implemented @@ -10,11 +10,11 @@ Status: implemented **模型无法知道自己的名字。** `AgentOptions.model` 驱动每个请求,但没有任何 prompt 文本携带它——也不可能携带:`dsh-system-prompt` 中的 section 是上下文全局的,而模型名称是 per-agent 的,`assemble()` 根本不接受任何 per-agent 输入。 -**工具指导是 leaf YAML 中的手写行文。** bash/subagent/todo_write 的使用指导存放在 `examples/coding-agent/cordis.yml` 和 `examples/acp-agent/cordis.yml` 的 `systemPrompt` 字符串里——两份漂移的副本(ACP 那份已经被删减)——而 `dsh-tool-fs` 和 `dsh-tool-web` 则通过 `ctx.systemPrompt.section()` 贡献各自的指导。加载或卸载一个工具插件意味着手动编辑每个部署的 persona;两份 YAML 都带着一条 `FIXME(config-comments)` 为这种分裂的症状道歉,stdio 的欢迎横幅也手动枚举了工具集。 +**工具指导是 leaf YAML 中的手写行文。** bash/subagent/todo_write 的使用指导存放在 coding-agent 和 ACP persona 字符串里——两份漂移的副本(ACP 那份已经被删减)——而 `dsh-tool-fs` 和 `dsh-tool-web` 则通过 `ctx.systemPrompt.section()` 贡献各自的指导。加载或卸载一个工具插件意味着手动编辑每个部署的 persona;两份 YAML 都带着一条 `FIXME(config-comments)` 为这种分裂的症状道歉,旧终端欢迎横幅也手动枚举了工具集。 -**Persona 渲染在工具指导之后。** agent loop(智能体循环)将 `agent.options.systemPrompt` 字符串拼接在已组装的 section 之后,于是模型先读到「Use the read tool…」再读到「You are coding-agent」——与 identity-first 约定(Claude Code、Codex)相反,且是 section 流水线之外的第二条组合路径。 +**Persona 渲染在工具指导之后。** agent loop(智能体循环)将 `agent.options.systemPrompt` 字符串拼接在已组装的 section 之后,于是模型先读到「Use the read tool…」再读到「You are a coding agent」——与 identity-first 约定(Claude Code、Codex)相反,且是 section 流水线之外的第二条组合路径。 -**Fork 工具的描述是假的。** `dsh-tool-subagent` 硬编码了一段为 spawn 语义编写的描述——"a separate agent that works in its own context … it does not see this conversation"——而 `subagent_fork` 实例(其子 agent 继承父级已完成的轮次)拿到了同样的措辞;YAML 行文在带外纠正了这个谎言。小问题:`PromptSection.name` 文档标注为 "(diagnostics / dedup)",但重复项被静默接受。 +**Fork 工具的描述是假的。** `dsh-tool-subagent` 硬编码了一段为 spawn 语义编写的描述——「a separate agent that works in its own context … it does not see this conversation」——而 `subagent_fork` 实例(其子 agent 继承父级已完成的轮次)拿到了同样的措辞;YAML 行文在带外纠正了这个谎言。小问题:`PromptSection.name` 文档标注为「(diagnostics / dedup)」,但重复项被静默接受。 ## 决策 @@ -32,7 +32,7 @@ Status: implemented ### Persona 作为 order-0 section -`dsh-system-prompt` 拥有 order 为 `-100` 的 `harness:identity` 和 order 为 0 的配置 `deployment:persona`,因此两者在循环被替换时仍然存活。prompt 渲染只有一条路径 `renderPrompt(assembly)`,`agent/pre-step` 因此测量的正是用于压缩(compaction)的确切 prompt。agent 作用域的 `deployment:persona` 遮蔽全局默认值,允许 subagent provider 在发布前安装 persona。约定的 order 区间为:identity `-100`、persona `0`、工具指导 `100–199`。 +`dsh-system-prompt` 拥有 order 为 `-100` 的 `harness:identity` 和 order 为 0 的配置 `deployment:persona`,因此两者在循环被替换时仍然存活。prompt 渲染只有一条路径 `renderPrompt(assembly)`,已路由请求 header 因此会记录准确的 prompt,稍后由 `ctx.tokenMeter` 为压缩压力回放。agent 作用域的 `deployment:persona` 遮蔽全局默认值,允许 subagent provider 在发布前安装 persona。约定的 order 区间为:identity `-100`、persona `0`、工具指导 `100–199`。 ### 工具指导归属 @@ -40,25 +40,25 @@ Status: implemented ### Subagent 对话历史描述符 -`SubagentProvider.inheritsParentContext` 描述的是对话种子,而非作用域、服务、工具或权限。spawn 和 ACP 将其设为 `false`;fork 设为 `true`。`dsh-tool-subagent` 根据该标志派生工具和 prompt 参数的描述,包括 fork 继承已完成轮次但不继承进行中轮次这一点。provider 生命周期事件使该措辞与响应式 provider 注册保持同步;其设计动机见 [provider-lifecycle-events RFC](2026-07-05-subagent-provider-lifecycle-events.md)。 +`SubagentProvider.inheritsParentContext` 描述的是对话种子,而非作用域、服务、工具或权限。spawn 和 ACP 将其设为 `false`;fork 设为 `true`。`dsh-tool-subagent` 根据该标志派生工具和 prompt 参数的描述,包括 fork 继承已完成轮次但不继承进行中轮次这一点。provider 生命周期事件使该措辞与响应式 provider 注册保持同步;其设计动机见 [provider-lifecycle-events Agent Note](2026-07-05-subagent-provider-lifecycle-events.md)。 ## 曾考虑的替代方案 -- **循环自行组合一行 identity 文本**:在必须保持精简的那个包("用插件,不改循环")中硬编码面向模型的行文,且在 section 流水线之外构成第二条组合路径。(identity 确实以代码字面量交付——但作为 `dsh-system-prompt` 注册的普通 section,其 `system-prompt/assemble` waterfall 仍是部署需要移除它时的逃生阀。) -- **通过 `agent/request` waterfall 注入模型名称**:prompt 文本在两处组合,且 `agent/pre-step` 的 `fullSystemPrompt` 会遗漏它,导致 compaction 测量的 prompt 与模型实际看到的不一致。 -- **在每个 persona 中手写模型名称**:与上方一行的 `model:` 键重复,配置修改后静默失实;正是本 RFC 要治愈的病症。 +- **循环自行组合一行 identity 文本**:在必须保持精简的那个包(「用插件,不改循环」)中硬编码面向模型的行文,且在 section 流水线之外构成第二条组合路径。(identity 确实以代码字面量交付——但作为 `dsh-system-prompt` 注册的普通 section,其 `system-prompt/assemble` waterfall 仍是部署需要移除它时的逃生阀。) +- **通过 `agent/request` waterfall 注入模型名称**:prompt 文本会在两处组合,更早渲染的 persona 也可能与最终已路由 header 不一致。拥有延迟路由的请求插件还必须拥有该模型在 prompt 中更早出现的声明。 +- **在每个 persona 中手写模型名称**:与上方一行的 `model:` 键重复,配置修改后静默失实;正是本 Agent Note 要治愈的病症。 - **宽松插值(未知引用保留原样或替换为空)**:一个拼写错误 `{{modle}}`(或一个空洞)会被发送给模型,直到 transcript(文本记录)审查时才会被发现。 - **在配置中为每个 subagent 实例编写措辞**:面向模型的行文回到每个部署 × 实例中,重蹈 P2 病症。**根据 provider 名称选择措辞**:`providerName` 本身是配置,重命名 provider 后会静默获得错误的措辞。 -- **在 `apply` 时解析 provider(加载顺序要求)** 与 **仅用 section 承载 subagent 措辞(在 assemble 时惰性解析)**:provider 生命周期事件的替代方案;两者均在 [provider-lifecycle-events RFC](2026-07-05-subagent-provider-lifecycle-events.md) 中被否决。 +- **在 `apply` 时解析 provider(加载顺序要求)** 与 **仅用 section 承载 subagent 措辞(在 assemble 时惰性解析)**:provider 生命周期事件的替代方案;两者均在 [provider-lifecycle-events Agent Note](2026-07-05-subagent-provider-lifecycle-events.md)中被否决。 ## 不在范围内 -- 更多变量(`date`、platform、git 状态):注册表使每个变量成为拥有该事实的插件的一行贡献;本 RFC 不认领任何一个。 +- 更多变量(`date`、platform、git 状态):注册表使每个变量成为拥有该事实的插件的一行贡献;本 Agent Note 不认领任何一个。 - 为预创建的 stdio agent 提供配置 `cwd`(可让 stdio persona 使用 `{{cwd}}` 并按真实路径分区持久化):推迟到 session-cwd 方案重新讨论时。 ## 交付的不变式 -- coding-agent 的 prompt 通过一条组装路径依次渲染 identity、带插值模型名的 persona,然后是 fs/bash/web 指导。 +- tui-agent 的 prompt 通过一条组装路径依次渲染 identity、带插值模型名的 persona,然后是 fs/bash/web 指导。 - fork 和 fresh subagent 的描述反映 provider 是否继承已完成的对话轮次;工具随 provider 生命周期变化而出现、消失和重新措辞。 - 未知、无值、格式错误或不平衡的变量引用会指明 section 名称并抛出异常;重复的 section、变量和工具注册同样抛出异常。 - 快照回放与 prompt 无关:它按轮次和步骤索引已记录的 chunk 流,不比较发出的请求。 diff --git a/.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml index 11d51bfef5..7f8ecda72d 100644 --- a/.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml @@ -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 -2026-07-05-reconstructable-requests.md: b07dbceaf6f3ecad64a464df6b97ee2a32284768 -2026-07-05-reconstructable-requests.zh.md: cb57d0915547b8a38b6afde7e36bec36c86e19c3 +2026-07-05-reconstructable-requests.md: 153d37a2faf2265134d5ff9e88f0bbfa275328e0 +2026-07-05-reconstructable-requests.zh.md: c14738f8a2bc8fd25b66a3b3f82b650dd52231c1 diff --git a/.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.zh.md b/.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.zh.md index cb57d09155..c14738f8a2 100644 --- a/.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.zh.md @@ -1,4 +1,4 @@ -# RFC: 每个 LLM(大语言模型)请求都可从会话日志重建 +# Agent Note: 每个 LLM(大语言模型)请求都可从会话日志重建 Status: implemented @@ -8,27 +8,27 @@ Status: implemented 请求流水线未能保证前缀稳定性以利用提供方缓存,会话日志也无法重建模型实际看到的内容。日志遗漏了 model、系统提示词和工具 schema,同时允许逐次调用的请求改写。因此缓存行为和回放等价性取决于碰巧加载了哪些插件。 -快乐路径的参考形态是 MiniCode 的 `LLMClient`:一个有状态的对话客户端,随对话推进只做追加而不重建,仅在系统提示词、工具集或压缩(compaction)真正改变了模型需要看到的内容时才重置。本 RFC 回答的设计问题是:如何在不放弃事件溯源的前提下获得这种纪律。 +快乐路径的参考形态是 MiniCode 的 `LLMClient`:一个有状态的对话客户端,随对话推进只做追加而不重建,仅在系统提示词、工具集或压缩(compaction)真正改变了模型需要看到的内容时才重置。本 Agent Note 回答的设计问题是:如何在不放弃事件溯源的前提下获得这种纪律。 ## 决策 ### 原则 -**模型可见 ⟺ 已记录。** 凡到达模型请求的内容都必须记录在会话日志中。可检查的推论:**循环发出的每个对话请求都是会话日志的纯函数**——任何人持有日志即可逐字节重建请求。精确的范围声明:该保证覆盖循环构建的 `GenerateOptions`;提供方协议格式(wire format)字节由此推导而来,因为两个适配器的序列化在固定代码版本下都是逐消息的纯函数;直接的一次性调用(压缩的 summarize 调用)记录其信封标量(`compact/summary.{model, maxTokens}`),其输入是对日志区域的确定性代码运算——可从日志加代码重建,通过 unfrozen-request 标记排除在不变式之外。 +**模型可见 ⟺ 已记录。** 凡到达模型请求的内容都必须记录在会话日志中。可检查的推论:**循环发出的每个对话请求都是会话日志的纯函数**——任何人持有日志即可逐字节重建请求。精确的范围声明:该保证覆盖循环构建的 `GenerateOptions`;提供方协议格式(wire format)字节由此推导而来,因为两个适配器的序列化在固定代码版本下都是逐消息的纯函数;直接的一次性调用(压缩的 summarize 调用)记录其信封标量(`compact/summary.{provider, model, maxTokens}`),其输入是对日志区域的确定性代码运算——可从日志加代码重建,因为只有循环会标记请求归属,所以它们不在不变式内。 前缀缓存稳定性是推论 #1,而非标题:一个仅追加的日志经逐节点纯函数投影,在 header 不变时自然产出前一请求的追加扩展——稳定性是涌现的,不是管理出来的。字节精确的审计/回放是推论 #2;带*可归因*漂移的恢复与 fork 是推论 #3。 ### 机制 -**消息。** `Session.deriveMessages()` 带缓存:每个 surface 节点在首次出现时通过公开的逐节点函数 `deriveEventMessage(event)` 精确投影一次;surface 重写(压缩的 `replace`,即 `SurfaceManager.replaceGeneration`)触发重建。调用方每次获得一个新数组,底层是共享的深度冻结消息:通过投影变异已记录的历史是不可表达的(会抛异常),取代了旧的逐次调用克隆隔离。外部重建器对日志前缀折叠同一个公开函数,因此不可能有两条路径产生分歧。 +**消息。** `Session.deriveMessages()` 带缓存:每个 surface 条目在首次出现时通过公开的逐事件函数 `deriveEventMessage(event)` 精确投影一次;surface 重写(压缩的 `replace`,即 `SurfaceManager.replaceGeneration`)触发重建。调用方每次获得一个新数组,底层是共享的深度冻结消息:通过投影变异已记录的历史是不可表达的(会抛异常),取代了旧的逐次调用克隆隔离。外部重建器对日志前缀折叠同一个公开函数,因此不可能有两条路径产生分歧。 -`EpochHeader` 记录请求的非历史状态:调用配置、渲染后的系统提示词、工具 schema 和会话前缀,空值规范化为缺失。`request/header` 写入完整的初始、恢复或回退快照。`request/header-delta` 通过公共前缀/后缀行裁剪编码系统变更,通过按名称键控的增/删/改编码工具变更,通过完整替换编码配置或前缀变更。`foldRequestHeader`、`diffHeader` 和 `applyHeaderDelta` 是纯编解码器。每个循环实例在首次请求时写入一个快照以锚定进程边界。delta 只是优化:写入方验证往返等价性,对无法表达的变更(如纯工具重排序)回退到完整快照。 +`EpochHeader` 记录请求的非历史状态:调用配置、渲染后的系统提示词、工具 schema 和会话前缀,空值规范化为缺失。`request/header` 始终写入完整快照:首个循环实例使用 reason `initial`,后续实例使用 `resume`,实例内变更使用 `change`。`foldRequestHeader` 选择最新快照。旧的 `request/header-delta` 事件和已移除的 `fallback` reason 在追加或加载时都会被拒绝。 -每个步骤重建 prompt 组装。在实例的首个步骤中,`agent/session-prefix` 以一个冻结的空种子为基础,用仅限请求的开场消息进行扩展;结果被冻结并缓存于该循环实例。`agent/pre-step` 随后接收组合后的前缀,消息在 `step/start` 之前立即被快照。首次调用配置从显式的 `AgentOptions` 出发,保留 fork 覆盖和恢复重配置;后续调用从折叠后的 header 出发。`agent/request` 只能替换那个冻结的配置种子,模型可见内容通过已记录的通道进入。循环记录欠下的 header 事件(前缀唯一的持久归宿),从前缀、快照和 header 构建 `GenerateOptions`,对其深度冻结但保持 `AbortSignal` 活跃。每实例状态仅有缓存的前缀和锚定快照是否已写入。 +每个步骤重建 prompt 组装。在实例的首个步骤中,`agent/session-prefix` 以一个冻结的空种子为基础,用仅限请求的开场消息进行扩展;结果在通用 `agent/pre-step` 检查点与边界快照之前被冻结并缓存于该循环实例。首次调用配置从显式的 `AgentOptions` 出发,保留 fork 覆盖和恢复重配置;后续调用从折叠后的 header 出发。`agent/request` 只能替换那个冻结的配置种子,模型可见内容通过已记录的通道进入。循环记录欠下的 header 事件(前缀唯一的持久归宿),从前缀、快照和 header 构建 `GenerateOptions`,对其深度冻结但保持 `AbortSignal` 活跃。每实例状态仅有缓存的前缀和锚定快照是否已写入。 -**`step/start` 是重建边界。** 一个步骤从该序列之前的事件推导消息。快照之后的注入加入下一次请求,事件发布期间的重入追加被拒绝。`agent/pre-step` 是当前请求所需内容的 seam。header 重建通过该步骤自身的 `request/header*` 事件折叠,或在无新 header 写入时沿用前一次折叠结果。 +**`step/start` 是重建边界。** 一个步骤从该序列之前的事件推导消息。快照之后的注入加入下一次请求,事件发布期间的重入追加被拒绝。`agent/pre-step(agent, turn, step, signal)` 仍是当前请求所需内容的通用 seam。header 重建选择该步骤的 `request/header`,或在无新 header 写入时沿用前一个快照。 -**强制执行。** 在开发环境中,`dsh-invariants` 通过一个全新的 `Session` 独立重建每个循环请求,使活跃缓存无法为自身背书,然后在 `llm/stream` 处比较消息和折叠后的 header 字段。循环请求通过其冻结形状和 session id 识别;直接的一次性调用被排除。正确性依赖于序列有界的重建,而非监听器顺序。带密钥的 e2e 要求首次请求之后有正值的 cache-read token;逐步骤用量是生产信号,header 变更或压缩表现为下一步骤的 cache-read 下降。 +**强制执行。** `dsh-agent-loop/invariant` 配套插件向 `ctx.invariants` 注册,并在被选用时通过一个全新的 `Session` 独立重建每个循环请求,使活跃缓存无法为自身背书,然后在 `llm/stream` 处比较消息和折叠后的 header 字段。循环通过 `dsh-llm` 的 `markAgentLoopRequest()` 记录精确的冻结请求;这一进程内标识让配套插件和其他请求观察者识别对话工作,而直接的一次性调用无论其冻结形状或 session id 如何都保持排除。正确性依赖于序列有界的重建,而非监听器顺序。带密钥的 e2e 要求首次请求之后有正值的 cache-read token;逐步骤用量是生产信号,header 变更或压缩表现为下一步骤的 cache-read 下降。 ### MiniCode 形态:采纳,但溯源箭头反转 @@ -41,15 +41,16 @@ Status: implemented - **逐次调用的请求标量**(一个可自由变异的配置传给每次 `agent/request` 分发):监听器可以零记账地逐次切换 model,悄然放弃本设计旨在保护的提供方缓存。配置是逐对话的已记录状态;waterfall(瀑布式事件)提议,日志记录。 - **检测并报告**(比较连续请求,发散时告警):事后捕获违规;违规请求仍可构造并发出。因接口层面的不可表达性而否决。 - **事件驱动组装**(仅在变更信号时重新渲染):存在漏信号的 bug 类别——会话中途注册的工具发出 `tools/change` 而非 `system-prompt/change`,第三方提供方可能什么都不发。逐步骤渲染加值比较在零信号纪律下即可稳健工作。 -- **Header 事件上的叙事字段**(delta 上的 `reason`/`changed` 列表):可通过 diff 连续事件推导——每个事实只有一个归宿;快照携带 reason 是因为锚点的成因无法从数据推导。 +- **自定义 header-delta 编解码器**(系统行编辑、按名称键控的工具编辑、完整配置/前缀替换):减少了重复字节,却复制了表示及其 diff/apply/fallback 机制。完整快照只保留一种回放表示。 +- **Header 快照上的叙事性变更字段列表**:可以通过比较连续快照推导。`reason` 仍保留,因为实例边界无法从快照值推导。 ## 后果 - 一个日志无法解释的请求不可能被意外构造——无论是循环还是监听器;变异已构建的请求会抛异常;每个 header 变更都是持久的、可 diff 的日志事件。 -- 在建议性通道之间做选择是变更频率的决策,而本设计使稳定的那个在结构上成为默认:`agent/session-prefix` 的贡献在每个循环实例中只组合一次并逐字复用,因此以零边际成本扩展可缓存前缀,且不可能在会话中途击穿提供方缓存;会话中途变化的内容通过仅追加的历史通道流入——`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——每条都是持久的 `context/message`,付出一次代价后即被前缀缓存,代价是在历史和日志中累积。将会话冻结的开场内容路由到前缀,将变更通知路由到历史通道;逐步骤的仅限请求尾部槽位被有意放弃(无消费方,且持久追加覆盖了当前所有更新模式)。 -- 在提供方处仍需全价计算的内容是固有的且已记录的:压缩(其 `compact/*` 事件和 replace 节点)、真正的 prompt/工具变更(`request/header-delta`)、配置切换(同上)、带漂移的进程边界(`'resume'` 快照与前一快照不同)。提供方自身的 reasoning-content 排除由服务端管理。 +- 在建议性通道之间做选择是变更频率的决策,而本设计使稳定的那个在结构上成为默认:`agent/session-prefix` 的贡献在每个循环实例中只组合一次并逐字复用,因此以零边际成本扩展可缓存前缀,且不可能在会话中途击穿提供方缓存;会话中途变化的内容通过仅追加的历史通道流入——`agent.inject()` 以及工具/prompt-submit 的 `additionalContexts`——每条都是持久的 `context/message`,付出一次代价后即被前缀缓存,代价是在历史和日志中累积。将会话冻结的开场内容路由到前缀,将变更通知路由到历史通道;逐步骤的仅限请求尾部槽位被有意放弃(无消费方,且持久追加覆盖了当前所有更新模式)。 +- 在提供方处仍需全价计算的内容是固有的且已记录的:压缩(其 `compact/*` 事件和替换条目)、真正的 prompt、工具或配置变更(reason 为 `change` 的 `request/header`),或带漂移的进程边界(不同的 `resume` 快照)。提供方自身的 reasoning-content 排除由服务端管理。 - `step/start` 监听器行为变更(见上文)是对插件唯一可观察的语义变更;`agent/pre-step` 是当前请求的 seam。 -- 工具结果裁剪(计划中)无需新机制:一个已记录的单节点 surface replace(`start === end`),携带同一 `callId` 下裁剪后的 `tool/result`——属压缩家族,回放正确,缓存击穿由相同的压力逻辑批量处理。 -- 会话日志每个对话增长一个 `request/header` 快照(系统提示词 + 工具 schema:主导项),加上真正变更时的 delta——相对 `assistant/chunk` 的体量很小;`SESSION_FORMAT_VERSION` 保持 `0`(预发布期间的变动被吸收,后端拒绝而非迁移)。 -- 快照 golden 文件变更一次(每个 transcript(文本记录)增加其 header 事件);写入文件系统的 fixture(测试前置数据)以规范化的撰写形式存储,工具参数使用 cwd 相对路径,因为回放只对 cwd 无关的参数路径做往返。 +- 工具结果裁剪(计划中)无需新机制:一个已记录的单条目 surface replace(`start === end`),携带同一 `callId` 下裁剪后的 `tool/result`——属压缩家族,回放正确,缓存击穿由相同的压力逻辑批量处理。 +- 会话日志每个循环实例增长一个 `request/header` 快照,并在真正变更时增加快照。它比 delta 编解码器更大,但相对 chunk 密集型日志仍然很小,并只保留一种回放表示。`SESSION_FORMAT_VERSION` 保持 `0`;旧的 delta 事件被拒绝而非迁移。 +- 快照 expected output 变更一次(每个 transcript(文本记录)增加其 header 事件);写入文件系统的 fixture(测试前置数据)以规范化的撰写形式存储,工具参数使用 cwd 相对路径,因为回放只对 cwd 无关的参数路径做往返。 - FIXME(call-config-shape):重新审视 `LlmCallConfig` 的确切字段集——哪些字段对缓存而言真正属于 epoch 级别(`model` 毫无疑问;采样标量出于谨慎放在那里),以及当适配器需要时,提供方特定的额外项(reasoning 选项、额外 body 参数)应归属何处。 diff --git a/.agents/notes/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml index 1de1e4c13d..8f73ac8dbe 100644 --- a/.agents/notes/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.i18n.yaml @@ -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 -2026-07-05-subagent-provider-lifecycle-events.md: b5300706ce4c53a6d348a86803d221a4dcca9632 -2026-07-05-subagent-provider-lifecycle-events.zh.md: 8694612e5e3d4d65117896e337c170f47b31abb0 +2026-07-05-subagent-provider-lifecycle-events.md: afd45027e8b56cbf1d17e6dec749d8602c81124d +2026-07-05-subagent-provider-lifecycle-events.zh.md: be94de29d8fadafb08acc95f1eb15e2fb931b3bb diff --git a/.agents/notes/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md b/.agents/notes/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md index 8694612e5e..be94de29d8 100644 --- a/.agents/notes/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-05-subagent-provider-lifecycle-events.zh.md @@ -1,4 +1,4 @@ -# RFC: Subagent 提供方生命周期事件——`subagent/provider-added` / `subagent/provider-removed` +# Agent Note: Subagent 提供方生命周期事件——`subagent/provider-added` / `subagent/provider-removed` Status: implemented @@ -6,9 +6,9 @@ Status: implemented ## 问题 -[prompt-variables RFC](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) 让 `dsh-tool-subagent` 从其提供方派生面向模型的措辞:`SubagentProvider.inheritsParentContext`(spawn/ACP 为 `false`,fork 为 `true`)同时驱动工具描述和 `prompt` 参数描述(`providerWording`),使 fork 工具不再在上下文继承问题上对模型撒谎。这一修复引入了跨 fiber 的数据依赖:工具描述在工具注册时固定(这是有意为之——描述是 tool-choice 引导所在之处),但提供方在自己的插件 fiber 上到达,时机不确定。 +[prompt-variables Agent Note](2026-07-05-prompt-variables-and-tool-guidance-ownership.md) 让 `dsh-tool-subagent` 从其提供方派生面向模型的措辞:`SubagentProvider.inheritsParentContext`(spawn/ACP 为 `false`,fork 为 `true`)同时驱动工具描述和 `prompt` 参数描述,使 fork 工具不再在上下文继承问题上对模型撒谎。这一修复引入了跨 fiber 的数据依赖:工具描述在工具注册时固定(这是有意为之——描述是 tool-choice 引导所在之处),但提供方在自己的插件 fiber 上到达,时机不确定。 -如果在工具插件的 `apply` 时刻解析提供方,就会产生一个隐式的加载顺序要求("在 cordis.yml 中把后端列在工具前面")。这个要求不成立,因为 Cordis Loader 并发启动同级条目,且 `Entry.init()` 不会等待激活完成:延迟到达的后端即使列在前面,也可能让工具 fiber 失败。Loader 不提供同级顺序保证——"异步状态不是同步状态"(见[防御性模式](../../../defensive-patterns.md))。 +如果在工具插件的 `apply` 时刻解析提供方,就会产生一个隐式的加载顺序要求(「在 cordis.yml 中把后端列在工具前面」)。这个要求不成立,因为 Cordis Loader 并发启动同级条目,且 `Entry.init()` 不会等待激活完成:延迟到达的后端即使列在前面,也可能让工具 fiber 失败。Loader 不提供同级顺序保证——「异步状态不是同步状态」(见[防御性模式](../../../../docs/defensive-patterns.md))。 ## 决策 @@ -23,14 +23,14 @@ Status: implemented ## 曾考虑的替代方案 -- **在 `apply` 时解析提供方,不存在则抛异常**:否决。"先列后端"这一要求声称了 Loader 并不存在的顺序保证。 +- **在 `apply` 时解析提供方,不存在则抛异常**:否决。「先列后端」这一要求声称了 Loader 并不存在的顺序保证。 - **重试查找(轮询直到提供方出现)**:最终能收敛,但在框架已有的机制(effect 注册 + disposal)之外发明了一套私有就绪协议;它也无法感知提供方离开,因此 HMR 会遗留一个措辞描述已 dispose 后端的工具。 -- **仅在 section 中放置 subagent 措辞,在组装时惰性解析**:同样能容忍任意加载顺序,但将 tool-choice 引导移出了描述,与 prompt-variables RFC 建立的所有权规则相矛盾(每个工具的语义和何时使用属于描述)。响应式注册既保持描述的权威性,又不依赖顺序。 +- **仅在 section 中放置 subagent 措辞,在组装时惰性解析**:同样能容忍任意加载顺序,但将 tool-choice 引导移出了描述,与 prompt-variables Agent Note 建立的所有权规则相矛盾(每个工具的语义和何时使用属于描述)。响应式注册既保持描述的权威性,又不依赖顺序。 - **根据提供方名称而非提供方对象确定措辞**:`providerName` 本身是配置,重命名后的提供方会静默获得错误的措辞;从已解析提供方自身的 `inheritsParentContext` 派生则不会漂移。 ## 后果 - 从命名提供方派生状态的消费方响应 `subagent/provider-added`/`-removed` 事件,而非在 `apply` 时读取注册表;`dsh-tool-subagent` 是参考实现。 -- **添加时大声失败;移除时按监听器隔离。** 添加监听器可以回滚注册。移除在 disposal 期间运行,因此单个监听器抛异常只会被记录日志,不会饿死后续镜像或干扰拆解流程。`start()` 仍在每次运行时按名称解析提供方,防止陈旧工具调用已移除的后端。见[事件目录](../../../cordis-catalog/events.md)与[生产者/消费者映射](../../../event-producer-consumer.md)。 +- **添加时大声失败;移除时按监听器隔离。** 添加监听器可以回滚注册。移除在 disposal 期间运行,因此单个监听器抛异常只会被记录日志,不会饿死后续镜像或干扰拆解流程。`start()` 仍在每次运行时按名称解析提供方,防止陈旧工具调用已移除的后端。见[事件目录](../../../../docs/cordis-catalog/events.md)与[生产者/消费者映射](../../../../docs/event-producer-consumer.md)。 - **工具不存在的窗口期。** 在后端 disposal 与重新注册之间(HMR 重载期间),模型看不到 subagent 工具。这是诚实的状态——替代方案是一个向空处分发的工具——工具注册表的 `tools/change` 事件发出会保持 prompt 组装的时效性。 - **两个等待中的 fiber 共享同一 `toolName` 是无效配置,被延迟捕获。** 如果两个 `dsh-tool-subagent` 加载实例命名了不同的提供方但相同的 `toolName`,两者都会等待,先到达的提供方先注册;第二次注册仅在其提供方到达时才抛异常。插件中的 `TODO(subagent-dup-toolname)` 记录了这一影响范围;工具注册表的重名拒绝机制仍是最终防线。 diff --git a/.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml index 57b6fca44e..fe015dff1b 100644 --- a/.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.i18n.yaml @@ -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 -2026-07-06-timeout-deadline-library.md: e8a688fbd5285c5e177eca5339bb204e2e4b01bc -2026-07-06-timeout-deadline-library.zh.md: 427aa4e10fe90a69b8773ed739d92e37754a4998 +2026-07-06-timeout-deadline-library.md: 11d4b8cd48dd345d2324b63e01bd726f12d846b4 +2026-07-06-timeout-deadline-library.zh.md: c6e5706e9a62877dc71d56951e82bc892b02a75e diff --git a/.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md b/.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md index 427aa4e10f..c6e5706e9a 100644 --- a/.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.zh.md @@ -1,4 +1,4 @@ -# RFC: 共享的超时/截止时间原语,硬终止留给各能力自行实现 +# Agent Note: 共享的超时/截止时间原语,硬终止留给各能力自行实现 Status: implemented @@ -20,7 +20,7 @@ Status: implemented ### 库的对外接口 -三个函数加一个 reason 类型: +四个函数、一个 watchdog 接口加一个 reason 类型: ```ts ignore-check /** The internal reason attached to a timeout abort, so consumers can classify it after the fact. */ @@ -53,19 +53,34 @@ export function deadline( code: string, ): { signal: AbortSignal; [Symbol.dispose](): void } +/** A stable signal plus one-at-a-time, timer-guarded async-iterator demand. */ +export interface IdleWatchdog { + readonly signal: AbortSignal + next<T>(iterator: AsyncIterator<T>): Promise<IteratorResult<T>> + [Symbol.dispose](): void +} + +/** Arm only while one iterator `next()` is outstanding, then rearm on later demand. */ +export function idleWatchdog( + upstream: AbortSignal | undefined, + timeoutMs: number, + code: string, +): IdleWatchdog + /** Recover the TimeoutReason from an aborted signal (or error); `code` scopes the match to this deadline's timer. */ export function timeoutOf(x: AbortSignal | { reason?: unknown }, code?: string): TimeoutReason | undefined ``` -`deadline` 通过 `AbortSignal.any` 将上游信号与定时器融合,附加一个类型化的 `TimeoutReason`,并暴露可 dispose(资源释放)的定时器清理。非正数超时是内部的「无超时」哨兵,用于后端拥有的后台任务;外部提示经过 `clampTimeout`,必须为正有限值。既无定时器也无上游信号时,函数返回一个永不中止的信号,具有相同的 disposal 形状。提供方将超时原因转译为 seam 特定的结果。`timeoutOf(signal, code)` 限定分类范围,使外层嵌套的 deadline 被视为上游取消而非内层能力自身的超时。 +`deadline` 通过 `AbortSignal.any` 将上游信号与一次性定时器融合,附加一个类型化的 `TimeoutReason`,并暴露可 dispose(资源释放)的定时器清理。非正数超时是内部的「无超时」哨兵,用于后端拥有的后台任务;外部提示经过 `clampTimeout`,必须为正有限值。既无定时器也无上游信号时,函数返回一个永不中止的信号,具有相同的 disposal 形状。`idleWatchdog` 则要求正有限的间隔,在整个流期间保持一个稳定的融合信号,并且只在一个迭代器 `next()` 尚未结算时启动定时器;结算会解除定时器,后续 demand 会重新启动,并发 demand 会失败,dispose 会清除当前 arm。提供方将超时原因转译为 seam 特定的结果。`timeoutOf(signal, code)` 限定分类范围,使外层嵌套的 deadline 被视为上游取消而非内层能力自身的超时。 ### 职责划分 | 关注点 | 负责方 | |---|---| | 校验请求提示并钳位默认值/最大值 | `dsh-timeout`(`clampTimeout`):纯算术加共享的正有限请求契约 | -| 启动定时器、到期中止、携带 reason、与上游取消融合 | `dsh-timeout`(`deadline`) | -| 清除定时器 | `dsh-timeout`(`[Symbol.dispose]`) | +| 启动一次性定时器、到期中止、携带 reason、与上游取消融合 | `dsh-timeout`(`deadline`) | +| 仅围绕未结算的迭代器 demand 启动和重启 | `dsh-timeout`(`idleWatchdog`) | +| 清除定时器 | `dsh-timeout`(任一原语的 `[Symbol.dispose]`) | | 中止后对首个 abort reason 进行分类 | `dsh-timeout`(`timeoutOf`) | | **实际终止工作** | 各能力的实现 | | 默认值/最大值*数值* | 各能力的配置 | @@ -77,6 +92,7 @@ export function timeoutOf(x: AbortSignal | { reason?: unknown }, code?: string): - **web_fetch**:工具层保持校验并转发;提供方手写的 controller + `setTimeout` + 手动监听器 + `finally` + `signal.reason` 恢复被替换为提供方自有的 `deadline`/`timeoutOf`。已预先中止的上游信号仍然立即抛出 `WEB_ABORTED`;否则 `fetch` 使用融合后的 `d.signal` 运行,`translateAbortOrNetwork` 根据信号分类抛出的错误(`timeoutOf` → `WEB_FETCH_TIMEOUT`,否则已中止 → `WEB_ABORTED`,否则网络错误 → `WEB_PROVIDER_ERROR`)。公开的错误码契约不变,`TimeoutReason` 永远不会作为公开错误跨越 web seam。 - **bash**:`resolve()` 将请求钳位为显式规格。前台 `run()` 创建 deadline 并将其信号传给进程执行,后者既有的 abort 监听器执行进程组 kill。执行器将首个 abort 分类为超时或取消。后台启动保持无超时,仅转发上游取消。 +- **LLM 适配器**:`dsh-llm-deepseek` 和 `dsh-llm-pi-ai` 用 `idleWatchdog` 包装实际的传输迭代。配置的五分钟间隔只覆盖尚未结算的提供方 demand,不包括下游消费方在 chunk 之间花费的时间。稳定信号在整个调用期间传给 `fetch` 或 SDK,因此超时会关闭底层请求并映射为 `TIMEOUT`,而更早的调用方中止映射为 `ABORTED`。 ## 后果 @@ -84,6 +100,7 @@ export function timeoutOf(x: AbortSignal | { reason?: unknown }, code?: string): - `SpawnSpec.timeoutMs` 和 `SpawnOutcome.timedOut`/`aborted` 被移除,而非作为始终为零/始终为 false 的残余保留:由于 `runBash` 不再拥有定时器且执行器负责分类,这些字段无处被读取。这是与字面提案形状(向 `runBash` 传入 `timeoutMs: 0`)的唯一偏差;一个始终为 0 且无处读取的字段在逐文件覆盖率门禁下属于死代码。 - web_fetch 去除了其定制的 controller/timer/listener/reason-recovery;分类器现在基于 deadline 信号(`timeoutOf` + `aborted`)而非抛出错误的形状来判断,这在请求阶段的 reject-with-reason 和读取阶段的裸 `AbortError` 两种情况下都是健壮的。 - `AbortSignal.any` 和 `using`/`Symbol.dispose` 在此首次进入本仓库(Node ≥ 24 基线,已满足)。 +- 模型流现在共享一个可重启的定时器契约,不会把滑动的空闲间隔变成总调用截止时间,也不会计入消费方思考时间。该原语仍然只做通知;适配器测试证明其传输观察到稳定信号并终止。 以下内容不在本次范围内,列出以标明边界:`web_search` 可以在其 tool-schema/snapshot 覆盖率规划就绪后获得可选的面向模型的 `timeout_ms`;未来基于 ripgrep 的文件系统发现工具可以在存在后消费同样的提供方自有 deadline 形状;`tools/execute` waterfall(瀑布式事件)中间件可以通过驱动 `exec.signal` 为每次工具调用设置默认 deadline——那将是一个*消费*本库的插件,仍然只做通知,硬终止仍是各能力自己的事。 diff --git a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml index 1d65850a78..f98cd104aa 100644 --- a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.i18n.yaml @@ -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 -2026-07-07-tool-call-timeout-policy.md: 20e0b5d70166404e034c0d0ece75cec61cab0df9 -2026-07-07-tool-call-timeout-policy.zh.md: 00b85ce9e2e7ae4ba31a9770beefce9c2eb8c319 +2026-07-07-tool-call-timeout-policy.md: 538225b197f7dd62b4798c037b72bf3cfc40648a +2026-07-07-tool-call-timeout-policy.zh.md: e37c8099a7780a8aa44f3154ceaf7ffa772f1e3b diff --git a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md index 00b85ce9e2..e37c8099a7 100644 --- a/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-07-tool-call-timeout-policy.zh.md @@ -1,4 +1,4 @@ -# RFC: 工具调用超时策略作为插件 +# Agent Note: 工具调用超时策略作为插件 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -[超时/截止时间 RFC](2026-07-06-timeout-deadline-library.md) 将计时与分类原语提取到了 `@deepseek-ai/dsh-timeout`,但超时策略仍然附着在各个能力和面向模型的 schema 上。`bash` 暴露了 `timeoutMs`;`web_fetch` 暴露了 `timeout_ms`;`web_search` 没有面向模型的超时参数,尽管提供方已经遵循 `exec.signal`;未来的 grep/glob 工具要么直接导入超时库,要么自行发明超时策略。对于一个插件 SDK 来说,这是错误的编写范式:工具作者通常只需将 `exec.signal` 转发给其调用的实现,而部署策略来决定预算。 +[超时/截止时间 Agent Note](2026-07-06-timeout-deadline-library.md) 将计时与分类原语提取到了 `@deepseek-ai/dsh-timeout`,但超时策略仍然附着在各个能力和面向模型的 schema 上。`bash` 暴露了 `timeoutMs`;`web_fetch` 暴露了 `timeout_ms`;`web_search` 没有面向模型的超时参数,尽管提供方已经遵循 `exec.signal`;未来的 grep/glob 工具要么直接导入超时库,要么自行发明超时策略。对于一个插件 SDK 来说,这是错误的编写范式:工具作者通常只需将 `exec.signal` 转发给其调用的实现,而部署策略来决定预算。 与此同时,仓库中并非所有超时都是面向模型的工具调用预算。钩子通过直接调用 `ctx.bash` 执行命令钩子,而非通过 `ctx.tools.execute()`;`bash` 模型工具通过同一个后端复用前台执行、后台启动、后台轮询和钩子调用。一步到位地将所有超时移入工具插件会混淆这些路径,并有破坏钩子超时语义的风险。 @@ -52,9 +52,9 @@ catch 是基础 `next`(而非 waterfall 之外的东西)这一点至关重 searchTimeoutMs: 30000 ``` -超时放在工具定义上而非自由文本名称映射中,消除了拼错名称导致策略不生效的问题。`defineTool` 校验预算为正有限数。分发期间,执行器派生截止信号,之后恢复调用方信号,并将自身的超时转换为 `TOOL_TIMEOUT`;没有预算的工具原样通过。 +超时放在工具定义上而非自由文本名称映射中,消除了拼错名称导致策略不生效的问题。`defineTool` 校验预算为正有限数。分发期间,执行器派生截止信号并将其赋给 `exec.signal`;注册表依据[工具取消契约](2026-07-19-cooperative-tool-cancellation.md),在执行工具体之前将该截止信号与调用方的原始信号融合。执行器随后恢复调用方信号,并将自身的超时转换为 `TOOL_TIMEOUT`;没有预算的工具原样通过。 -信号替换采用**就地修改 `exec.signal`** 的方式,而非向 `next()` 传递新对象。Cordis 的 waterfall `next()` 忽略传入的任何参数,并以共享的 payload 数组重新调用下游监听器(`vendor/cordis/src/events.ts`),因此 Cordis 的惯用方式——修改共享对象再委托——是唯一能到达分发的机制。插件在 `finally` 中将 `exec.signal` 恢复为调用方的原始值,使 `tools/post-execute` 永远不会看到本插件的(可能已中止的)截止信号。 +信号替换采用**就地修改 `exec.signal`** 的方式,而非向 `next()` 传递新对象。Cordis 的 waterfall `next()` 忽略传入的任何参数,并以共享的 payload 数组重新调用下游监听器(`vendor/cordis/src/events.ts`),因此修改共享对象是包装器向注册表提供截止信号的方式。注册表会在进入工具体前再次融合已捕获的调用方信号;插件则在 `finally` 中将 `exec.signal` 恢复为调用方的原始值,使 `tools/post-execute` 永远不会看到本插件的截止信号。 `timeout-policy` 拥有 `TOOL_TIMEOUT` 代码的两种用途:传递给 `deadline()`/`timeoutOf()` 的内部截止代码(有作用域,使嵌套的外层截止读为普通取消)和结构化工具结果错误代码。其替换结果为: @@ -80,13 +80,13 @@ function toolTimeoutResult(timeoutMs: number): ToolExecutionResult { `bash` 保持当前的后端超时路径。`dsh-tool-bash` 继续暴露 `timeoutMs` 和 `run_in_background`;`dsh-bash-local` 继续使用 `@deepseek-ai/dsh-timeout` 处理 `BASH_TIMEOUT`;钩子桥接继续调用 `runHook()` 并通过 `ctx.bash` 传递 `timeoutMs`。这保持了前台/后台/钩子行为的稳定。 -`read`、`write`、`edit`、`todo_write`、`bash_output` 和 `bash_kill` 不加入工具调用超时:它们是本地文件系统或短暂的注册表/会话操作,截止时间对它们而言要么只能尽力而为,要么没有必要。 +`read`、`write`、`edit`、`todo_write`、`task_list` 和 `task_kill` 不加入工具调用超时。`task_output` 自己拥有有界等待,因为等待超时是成功的实时状态结果,而非工具失败。 未来面向模型的 grep/glob 工具可以基于 `ctx.bash` 实现而无需导入 `@deepseek-ai/dsh-timeout`:它将 `exec.signal` 转发给 `ctx.bash`,并声明自己的 `timeoutMs`(来自其插件配置)供执行器应用。如果 bash-local 的后端超时对这类工具造成问题,bash seam 可以后续添加调用方自有截止模式;这不在本次范围内。 ## 曾考虑的替代方案 -**将插件命名为 `tool-timeout`。** 字面的 RFC 名称匹配了 `gen-tool-catalog` 完整性守卫的 `packages/*/tool-*` glob,该 glob 要求每个匹配项注册一个面向模型的工具。本插件不注册任何工具——它是一个 `tools/execute` 包装器——因此 `tool-*` 名称要么导致 `verify-tool-catalog` 失败,要么强制产生一个误导性的启动条目。包(package)为 `@deepseek-ai/dsh-timeout-policy`,位于新的 `packages/timeout/` 组;cordis.yml 的 `id` 仍可为 `timeout-policy`。 +**将插件命名为 `tool-timeout`。** 字面的 Agent Note 名称匹配了 `gen-tool-catalog` 完整性守卫的 `packages/*/tool-*` glob,该 glob 要求每个匹配项注册一个面向模型的工具。本插件不注册任何工具——它是一个 `tools/execute` 包装器——因此 `tool-*` 名称要么导致 `verify-tool-catalog` 失败,要么强制产生一个误导性的启动条目。包(package)为 `@deepseek-ai/dsh-timeout-policy`,位于新的 `packages/timeout/` 组;cordis.yml 的 `id` 仍可为 `timeout-policy`。 **仅保留逐工具的超时处理。** 这是 `bash` 和 `web_fetch` 的既有形态,也与 Claude Code 和 Codex 对 shell 命令的做法一致。它对 web 类工具不利,因为每个新的支持超时的工具都必须自行选择校验方式、上限语义、文档、快照和分类。插件集中了策略和分类,让每个工具的 schema 专注于业务输入。 @@ -100,12 +100,12 @@ function toolTimeoutResult(timeoutMs: number): ToolExecutionResult { **使用 `tools/pre-execute` 加 `tools/post-execute` 代替新的环绕 seam。** pre 监听器可以启动截止时间并修改 `exec.signal`;post 监听器可以分类并替换。这样做的问题是截止时间的生命周期会跨越两个独立的 waterfall:需要 call-id 映射、在每条 pre-deny/tool-throw/post-throw/dispose 路径上清理,以及与其他监听器的排序规则。`tools/pre-execute` 也是允许/拒绝门禁,而非执行包装器。`tools/execute` 给超时一个词法作用域:启动、委托、分类、释放。 -**使用 `Promise.race` 对非协作工具强制超时。** 与超时库 RFC 相同的理由否决:它在底层进程、fetch 或提供方操作可能仍在运行时就将控制权返回给调用方。插件只发送信号;终止仍是实现方的责任。 +**使用 `Promise.race` 对非协作工具强制超时。** 与超时库 Agent Note 相同的理由否决:它在底层进程、fetch 或提供方操作可能仍在运行时就将控制权返回给调用方。插件只发送信号;终止仍是实现方的责任。 ## 后果 - `@deepseek-ai/dsh-tools` 在有意拆分 pre/post 工具钩子的拦截 seam 之后,获得了一个环绕分发的表面。其契约是狭窄的——包装注册表分发,而非替代 pre 门禁或 post 结果策略——且基础 `next()` 是带规范化的分发,因此包装器永远不会看到原始的工具抛出。 - 多个 `tools/execute` 监听器按普通 Cordis waterfall 顺序组合:调用 `next()` 的监听器包装下游监听器加分发;不调用 `next()` 直接返回的监听器短路它们。一个同时组合超时与未来重试/沙箱/指标包装器的部署通过注册顺序选择语义(「超时覆盖整个重试」vs「超时覆盖每次尝试」)。 -- 按声明加入是一个有意的误配置风险:工具可以声明 `timeoutMs` 但不遵循 `exec.signal`,这样的工具在超时时不会停止。插件契约声明:声明预算意味着协作;web 工具在已转发信号的工具上验证了这一模式。 +- 按声明加入是一个有意的误配置风险:工具可以声明 `timeoutMs` 但不遵循 `exec.signal`,这样的工具在超时时不会停止。注册表会等待这一未达静止状态的工具体,而不是竞速它;同时插件契约声明:声明预算意味着协作;web 工具在已转发信号的工具上验证了这一模式。 - 过渡期间 `bash` 和已迁移的 web 工具有意使用不同的超时路径:`TOOL_TIMEOUT` 是面向模型的工具调用预算,而 `BASH_TIMEOUT` 仍是 bash 和钩子使用的 bash 后端超时。 -- 与字面提案的偏差,按 implemented-RFC 规则记录:插件包为 `@deepseek-ai/dsh-timeout-policy`(而非 `tool-timeout`);信号替换是在 `next()` 之前就地修改 `exec.signal`(而非 `next({ ...exec, signal })`,Cordis 会忽略后者);逐工具预算声明在 `ToolDefinition` 上(`timeoutMs`,由拥有该工具的插件从其配置中设置),而非在本插件配置中按工具名映射——因此执行器是零配置的,拼错工具名不可能发生。以上三点均在上文 `## Decision` 中描述。 +- 与字面提案的偏差,按 implemented-Agent Note 规则记录:插件包为 `@deepseek-ai/dsh-timeout-policy`(而非 `tool-timeout`);信号替换是在 `next()` 之前就地修改 `exec.signal`(而非 `next({ ...exec, signal })`,Cordis 会忽略后者);逐工具预算声明在 `ToolDefinition` 上(`timeoutMs`,由拥有该工具的插件从其配置中设置),而非在本插件配置中按工具名映射——因此执行器是零配置的,拼错工具名不可能发生。以上三点均在上文 `## Decision` 中描述。 diff --git a/.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml index fda6a0406b..63e93dd74a 100644 --- a/.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.i18n.yaml @@ -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 -2026-07-08-agent-scope-contexts.md: b67d51f06f74f0460f76e9fc4b45699d00b7db46 -2026-07-08-agent-scope-contexts.zh.md: e37ea60418095cb34d354150aed79a937b1b3552 +2026-07-08-agent-scope-contexts.md: e4c076189a8e8a438b561232d3779ad1f6ab0d08 +2026-07-08-agent-scope-contexts.zh.md: ff8243ebdd541e4a7821d9c4ff99217a8060c2b4 diff --git a/.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md b/.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md index e37ea60418..ff8243ebdd 100644 --- a/.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md @@ -1,4 +1,4 @@ -# RFC: agent 即注册作用域 +# Agent Note: agent 即注册作用域 Status: implemented @@ -16,7 +16,7 @@ Status: implemented 每个存活的 agent 拥有一个扁平的注册层,通过 `agent.ctx` 暴露。代码通过拥有某项贡献的 context 进行注册;具备作用域感知的服务将部署全局注册与恰好一个匹配的 agent 层合并;操作从其真实 agent 选择该层;该层在 agent 的完整发布生命周期内存在。 -Cordis 是 SDK 底层的插件框架。Cordis **context** 是插件用来访问服务和注册效果的对象,效果的清理跟随该 context。[Cordis 入门](../../../cordis-primer.md)对该框架有更详细的说明。 +Cordis 是 SDK 底层的插件框架。Cordis **context** 是插件用来访问服务和注册效果的对象,效果的清理跟随该 context。[Cordis 入门](../../../../docs/cordis-primer.md)对该框架有更详细的说明。 对大多数贡献者而言,完整契约是四条规则: @@ -45,7 +45,7 @@ flowchart LR 缺失的交叉边即隔离规则:Agent A 的本地注册不会进入 Agent B 的视图,父级的注册也不会仅因父级拥有子级的生命周期就进入子级。 -配套的[运行时设计 RFC](2026-07-12-agent-scope-runtime-design.md) 阐述了实现与正确性推理。[subagent 组合控制 RFC](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 负责独立的 `persona`、`toolFilter` 和 `maxDepth` 功能。 +配套的[运行时设计 Agent Note](2026-07-12-agent-scope-runtime-design.md) 阐述了实现与正确性推理。[subagent 组合控制 Agent Note](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 负责独立的 `persona`、`toolFilter` 和 `maxDepth` 功能。 ### 注册来源决定可见性与清理 @@ -62,8 +62,7 @@ flowchart LR ```js const handle = await ctx.agents.create({ - agentId: AgentId('reviewer'), - sessionId: SessionId('reviewer-session'), + sessionId: SessionId('reviewer'), agentOptions: { model: 'model-name' }, setup(agentCtx) { agentCtx.systemPrompt.section({ @@ -105,7 +104,7 @@ setup 接收一个完整的受信 Cordis context,因此可以组合普通插 在 Cordis 层面,`Scoped<T>` 是一个不透明的路由接收器。它携带用于选择监听器的过滤器,但本身不是领域对象。因此事件签名将真实的 `Agent`、工具执行、审批请求或其他主体作为显式参数保留,供监听器检查。 -以 `{ global: true }` 注册的监听器有意绕过上下文受众过滤,但其清理仍跟随注册 context。注册表成员变更通知保持不过滤,因为它们描述的是共享注册表状态而非某个 agent 的操作。生成的[事件目录](../../../cordis-catalog/events.md)是详尽的事件参考。 +以 `{ global: true }` 注册的监听器有意绕过上下文受众过滤,但其清理仍跟随注册 context。注册表成员变更通知保持不过滤,因为它们描述的是共享注册表状态而非某个 agent 的操作。生成的[事件目录](../../../../docs/cordis-catalog/events.md)是详尽的事件参考。 ### 创建最后发布,dispose 最后撤销 diff --git a/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml index c2a5189641..2de6e74661 100644 --- a/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.i18n.yaml @@ -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 -2026-07-12-agent-scope-runtime-design.md: 1940423db9364f56ab8a13e4d636f492f97f2d54 -2026-07-12-agent-scope-runtime-design.zh.md: bbfb06db7eb886f7bc34cdb8607729fb892cf5ba +2026-07-12-agent-scope-runtime-design.md: ff7fba1e6f8d496080acbceddb06691c8cddc5f5 +2026-07-12-agent-scope-runtime-design.zh.md: 0a101e796658dd48bc76425fb39362f35e7e345e diff --git a/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md b/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md index bbfb06db7e..0a101e7966 100644 --- a/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md @@ -1,4 +1,4 @@ -# RFC: Agent 作用域运行时设计与正确性 +# Agent Note: Agent 作用域运行时设计与正确性 Status: implemented @@ -14,13 +14,13 @@ Status: implemented ## 决策 -运行时对每个独立事实使用一种机制。作用域路由有一个不透明载体;每个活跃的注册表对象有一条入口记录;每个创建或恢复操作有一个事务;类型化的同进程调用借用 readonly 值;真实数据边界只物化一次;协作式 prompt 组装的结果即为权威;worker/进程代码仅在不同所有者确实可能竞争时才保留独立的终止态和静默态。 +运行时对每个独立事实使用一种机制。作用域路由有一个不透明载体与共享 layer store;每个活跃的注册表对象有一条入口记录;每个创建或恢复操作有一个事务;类型化的同进程调用借用 readonly 值;真实数据边界只物化一次;协作式 prompt 组装的结果即为权威;worker/进程代码仅在不同所有者确实可能竞争时才保留独立的终止态和静默态。 该设计可概括为七项选择: | 问题 | 权威机制 | |---|---| -| 选择全局加某个 agent 的注册 | 不透明作用域键与路由载体 | +| 选择全局加某个 agent 的注册 | 不透明作用域键、路由载体与共享 layer store | | 拥有一个活跃的 agent 或会话 | 由其 disposer 捕获的单条注册表入口 | | 协调创建/恢复 | 单个 `AgentCreationTransaction` | | 保护持久化、队列、模型或协议格式数据 | 在该边界处一次性物化 | @@ -28,9 +28,9 @@ Status: implemented | 组合模型可见的 prompt 与工具表面 | 单个共享工具视图加权威的 assembly-waterfall 结果 | | 协调 subagent、worker 和进程关闭 | 单个取消信号加该边界独立的终止态/静默态事实 | -本 RFC 余下部分按依赖顺序展开这些选择:Cordis 机制、作用域路由、创建与会话提交、工具与 prompt、subagent 与工作流,最后是可执行检查。 +本 Agent Note 余下部分按依赖顺序展开这些选择:Cordis 机制、作用域路由、创建与会话提交、工具与 prompt、subagent 与工作流,最后是可执行检查。 -[7 月 8 日 RFC](2026-07-08-agent-scope-contexts.md) 仍然是贡献者契约。独立的 [subagent 组合控制 RFC](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) 拥有 `persona`、`toolFilter` 和 `maxDepth`;本文仅讨论它们的 setup 如何融入生命周期。 +[7 月 8 日 Agent Note](2026-07-08-agent-scope-contexts.md)仍然是贡献者契约。独立的 [subagent 组合控制 Agent Note](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md)拥有 `persona`、`toolFilter` 和 `maxDepth`;本文仅讨论它们的 setup 如何融入生命周期。 ## Cordis 模型:context、fiber、effect、receiver 与 waterfall @@ -70,11 +70,11 @@ scope 包实现了 Cordis 路由所需的最小对象。其载体仅持有一个 Receiver 是一个小型载体而非领域对象的透明代理。需要 agent 的代码接收显式的事件参数;需要注册所有权的代码接收 `agent.ctx`。 -### 注册表读取叠加一个精确映射 +### 注册表读取叠加一个精确 layer -作用域感知的注册表将全局贡献与按标识键索引的局部贡献分开存储。读取解析全局层和至多一个局部层;它从不遍历父级链。 +作用域感知的注册表使用 `ScopedLayers`,拥有一个即时创建的全局 aggregate 和按标识键惰性创建的 aggregate。读取解析全局 layer 和至多一个精确局部 layer;它不创建状态,也从不遍历父级链。注册可见性与 Cordis effect 所有权都从同一个 context 派生,而回收会等待具体 layer 的完整 aggregate 变空(见[决策](2026-07-12-scoped-layers-store.md))。 -每个服务保留其领域规则。命名 prompt 值和工具使用局部遮蔽,工具限制在添加局部工具之前过滤全局,事件选择监听器受众而非注册数据。Scope 提供标识和所有权,而非通用的合并算法。 +每个服务保留其领域规则。命名 command 和 prompt 视图使用共享的、保持插入顺序的 shadow merge;工具保留更丰富的 resolver,因为限制会在加入局部工具前过滤全局工具,保留的 Code Mode transport 则单独插入。Prompt 变量和工具 guard 保持实时迭代,而工具提供方成员关系按每次 assembly 物化。Scope 提供存储生命周期和命名遮蔽,而非通用的注册表视图。 ### 融合 dispatch 辅助函数防止主体漂移 @@ -208,7 +208,7 @@ Session 头部、种子和追加的事件是无损 JSON 数据。Session 构造 私有解析器应用当前展示模式、活跃的全局限制、精确的局部叠加和局部遮蔽。Schema、查找、执行、Code Mode SDK 生成和限制验证都使用该解析器或其限制前的全局名称视图。 -[subagent 组合控制 RFC](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md#tool-filtering-is-one-live-global-view-rule) 拥有用户可见的 allow/deny 语义。实现要求是一致性:被过滤掉的全局工具不能通过另一条查找路径仍可执行,局部遮蔽的定义就是被展示和执行的同一个定义。 +[subagent 组合控制 Agent Note](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md#tool-filtering-is-one-live-global-view-rule)拥有用户可见的 allow/deny 语义。实现要求是一致性:被过滤掉的全局工具不能通过另一条查找路径仍可执行,局部遮蔽的定义就是被展示和执行的同一个定义。 `ToolRestriction` 接受 readonly 的 allow/deny 名称并将其编译为内部集合。多个限制取交集。公开的 `visible()` 和 `knownNames()` 方法是不必要的,因为只有注册表需要中间视图。 @@ -324,19 +324,19 @@ TypeScript 无法管控 JavaScript 强制转换、直接 Cordis dispatch、进 ### 运行时不变式覆盖跨服务事实 -不变式插件验证每个声明的作用域事件使用带标记的载体,以及暴露主体的事件族使用匹配的键。Session trace 验证在追加提交前暂存,并在同一事件提交后推进。 +`dsh-scope/invariant` 配套插件在被选用时验证每个声明的作用域事件使用带标记的载体,以及暴露主体的事件族使用匹配的键。独立的 `dsh-session/invariant` 贡献在追加提交前暂存 trace 验证,并在同一事件提交后推进;二者都通过 `ctx.invariants` 注册。 该插件不通过扫描注册表来管控可信 setup,也不拒绝通过强制转换构造的 prompt assembly 对象。这些检查会将组合契约变成推测性的运行时机制,却不保护真实的外部边界。 ### 生成的产物使公开契约保持对齐 -事件目录、服务目录、生产者/消费者矩阵、配置目录、模块图、工具目录、type-equiv 块和作用域事件解析器映射都是从源码生成或受新鲜度门禁约束的。[TypeScript 语义门禁 RFC](../process/2026-07-14-typescript-program-backed-semantic-gates.md) 拥有 Program 构造、语义事件发现和解析器生成规则。 +事件目录、服务目录、生产者/消费者矩阵、配置目录、模块图、工具目录、type-equiv 块和作用域事件解析器映射都是从源码生成或受新鲜度门禁约束的。[TypeScript 语义门禁 Agent Note](../process/2026-07-14-typescript-program-backed-semantic-gates.md)拥有 Program 构造、语义事件发现和解析器生成规则。 行为测试固定了作用域路由和 dispose、最终入口碰撞清理、发布回滚、有序静默、持久化前/后提交行为、跨展示和执行的活跃工具过滤、协作式 prompt 组装、原生和 Code Mode 中的结构化输出提交、异步 subagent 启动和信号取消、worker 终端仲裁、ACP 结算和进程拆除。 ## 曾考虑的替代方案 -[7 月 8 日 RFC](2026-07-08-agent-scope-contexts.md#alternatives-considered) 拥有公开扁平作用域契约的替代方案。此处的替代方案关注实现形态。 +[7 月 8 日 Agent Note](2026-07-08-agent-scope-contexts.md#alternatives-considered)拥有公开扁平作用域契约的替代方案。此处的替代方案关注实现形态。 ### 使用透明代理作为作用域载体 diff --git a/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml b/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml index f42c8c462e..5d47778692 100644 --- a/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.i18n.yaml @@ -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 -2026-06-14-acp-agent-client-protocol.md: 50ad2620de1dada78c4a20101b631cc5b0e9f3d1 -2026-06-14-acp-agent-client-protocol.zh.md: c4b73c00083d63e5c024953cd8c9d8dbd94d6b0a +2026-06-14-acp-agent-client-protocol.md: c6976ed28a254684fca62e2d309cdde7ea90340d +2026-06-14-acp-agent-client-protocol.zh.md: 711e8c2a7f7146494fa208942523e2ebfa1808a5 diff --git a/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md b/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md index c4b73c0008..711e8c2a7f 100644 --- a/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md +++ b/.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.zh.md @@ -1,4 +1,4 @@ -# RFC: Agent Client Protocol(ACP)支持——从外部编辑器驱动编码 agent +# Agent Note: Agent Client Protocol(ACP)支持——从外部编辑器驱动编码 agent Status: implemented @@ -50,7 +50,7 @@ harness 最初仅通过 readline 循环暴露 agent。该接口能传输文本 编辑器可以通过一条 ACP 连接创建、加载、提交 prompt、取消、渲染、询问和重新配置多个 harness 会话,无需依赖特定的循环实现。会话事件日志仍是回放、prompt 结算、cwd 与每会话配置的持久真源。工具展示与人工回答通道仍是可扩展的插件契约,而非 ACP 专属行为。 -桥接层有意不实现会话列表/删除/恢复/关闭能力、MCP 透传、附加目录、图片/音频/嵌入资源 prompt、运行时模型选择、plan、斜杠命令、用量更新、编辑器文件系统委托或 ACP 终端执行子协议。功能清单将这些记录为不支持,而非静默接受。 +桥接层有意不实现会话列表/删除/恢复/关闭能力、MCP 透传、附加目录、图片/音频/嵌入资源 prompt、plan、斜杠命令、用量更新、编辑器文件系统委托或 ACP 终端执行子协议。后续已通过标准会话配置选项加入运行时模型选择,见 [LLM 目录与 ACP 选择 Agent Note](../architecture/2026-07-15-llm-model-catalog-and-acp-selection.md)。 空闲时的配置选择在实时响应中是真实的,但在下一次 `agent/prompt-submit` 将其锚定到开放轮次之前不具持久性。在该边界之前崩溃会丢失待定选择;这是保持会话事件封闭于轮次内且回放安全的代价。 diff --git a/.agents/notes/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml b/.agents/notes/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml index 5a79faa4da..0b5380e4d4 100644 --- a/.agents/notes/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-14-acp-multi-session.i18n.yaml @@ -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 -2026-06-14-acp-multi-session.md: a71f2d3d2daff3c8fae460e414d1f50facd5538f -2026-06-14-acp-multi-session.zh.md: 8b5ba46e949480d450f13aadad3ea82e0e048161 +2026-06-14-acp-multi-session.md: 43aa32a43fef7aa69f5efd45d4c8176da9f459cd +2026-06-14-acp-multi-session.zh.md: 012752273b469295fcf8338f809dca252fc377ac diff --git a/.agents/notes/implemented/feature/2026-06-14-acp-multi-session.zh.md b/.agents/notes/implemented/feature/2026-06-14-acp-multi-session.zh.md index 8b5ba46e94..012752273b 100644 --- a/.agents/notes/implemented/feature/2026-06-14-acp-multi-session.zh.md +++ b/.agents/notes/implemented/feature/2026-06-14-acp-multi-session.zh.md @@ -1,4 +1,4 @@ -# RFC: 在单个连接上多路复用并发 ACP 会话 +# Agent Note: 在单个连接上多路复用并发 ACP 会话 Status: implemented @@ -10,16 +10,24 @@ Status: implemented ## 决策 -ACP 桥接层将活跃会话存储在 `Map<SessionId, SessionRecord>` 中,并维护一个 `WeakMap<Agent, SessionId>` 反向索引,用于 agent 作用域的回调。一条记录拥有其 agent 句柄、进行中的 prompt、活跃的工具调用展示状态、待处理的空闲配置切换、会话 cwd 以及客户端能力快照。一个独立的 loading-id 集合在异步恢复之前预留每个 id,使两个流水线化的加载请求无法构造出重复的 agent;不同 id 可以并发加载。 +ACP 桥接层将活跃会话存储在 `Map<SessionId, SessionRecord>` 中。agent 作用域的回调使用 `ownedRecord`:在正向 map 中查找 `agent.session.id`,且仅当该记录拥有精确的 agent 对象时才接纳它,使外部的同 id 对象无法冒领会话。一条记录拥有其 agent 句柄、进行中的 prompt、活跃的工具调用展示状态、待处理的空闲配置切换、会话 cwd 以及客户端能力快照。一个独立的 loading-id 集合在异步恢复之前预留每个 id,使两个流水线化的加载请求无法构造出重复的 agent;不同 id 可以并发加载。 每个 `session/event` 和 `agent/status` 回调在发送或结算任何内容之前,先解析出所属记录。每个会话独立允许一个进行中的 prompt。prompt 记录一个日志水位线,捕获自己的 `turn/start`,并仅在匹配的 `turn/end` 到达时结算;来自已取消的前一轮次的迟到 end 不能 resolve 更新的 prompt。`session/cancel` 定位到一条记录,只调用该 agent 的队列感知取消路径。 -权限归属使用同一个反向索引。ACP `approval/request` 应答器只向拥有发起请求的 agent 的编辑器会话发起提示,并将外部请求委托出去。用户交互引出同样按 agent 归属路由。每会话的沙箱和审批配置值只折叠该会话自身的事件,待处理的空闲切换存储在该记录上,直到下一轮次将其锚定。 +权限归属使用对正向 map 的同一精确 agent 检查。ACP `approval/request` 应答器只向拥有发起请求的 agent 的编辑器会话发起提示,并将外部请求委托出去。用户交互引出同样按 agent 归属路由。每会话的沙箱和审批配置值只折叠该会话自身的事件,待处理的空闲切换存储在该记录上,直到下一轮次将其锚定。 后台 bash 任务携带一个不透明的 owner token,其值等于所属会话 id。`bash_output` 和 `bash_kill` 在读取或终止之前,将调用方的 token 与执行器的任务归属进行比较;仅凭可预测的 task id 不能获得访问权。归属信息与执行器任务一起存储,因此工具插件重载不会擦除它。 连接拆除时清空活跃 map,将每个待处理的 prompt 以取消状态结算,并并行 dispose(资源释放)所有 `AgentHandle`。每个句柄停止并等待其循环完成、在仍然附着时刷新会话、注销 agent 并移除会话。拆除操作被 memoize 化,由客户端断连和插件 dispose 共享。 +## 协议与工作区作用域 + +[ACP v1 明确允许一个连接上存在多个并发会话](https://github.com/agentclientprotocol/agent-client-protocol/blob/01beb5fb5eec60e9f516a80d85eb03594bac61e3/docs/get-started/architecture.mdx#L16-L24),每个新会话都携带自己的主 `cwd`。本桥实现该会话级多路复用,其中包括[按会话 cwd 决策](../architecture/2026-07-02-fs-per-session-cwd.md)所记录的不同主工作区;它不会为每个会话创建一个 agent 子进程。 + +一个会话内部的多根项目是另一项可选能力:ACP 把[有效根目录定义为主 `cwd` 加 `additionalDirectories`](https://github.com/agentclientprotocol/agent-client-protocol/blob/01beb5fb5eec60e9f516a80d85eb03594bac61e3/docs/protocol/v1/session-setup.mdx#L313-L367)。[Zed 仅在 agent 公布该能力时发送其余项目工作目录](https://github.com/zed-industries/zed/blob/ea77ca2818f3e059a2b61ecc7e63b67e01e1cec5/crates/agent_servers/src/acp.rs#L1139-L1145),否则会[从会话请求中丢弃这些目录](https://github.com/zed-industries/zed/blob/ea77ca2818f3e059a2b61ecc7e63b67e01e1cec5/crates/agent_servers/src/acp.rs#L1454-L1472)。如其[已知限制](../../../../packages/ui/acp/README.md#known-limitations-and-deferred-work)所记录,桥不公布该能力,并拒绝非空值,因此当前 Zed 多根项目到达桥时只携带第一个工作目录。 + +[标准传输是每个 stdio 连接一个由编辑器启动的 agent 子进程](https://github.com/agentclientprotocol/agent-client-protocol/blob/01beb5fb5eec60e9f516a80d85eb03594bac61e3/docs/protocol/v1/transports.mdx#L17-L42);多个编辑器连接因此需要多个子进程或自定义传输,而本决策保证的是一个连接内部存在多个会话。在该连接内,`ctx.sandboxPolicy` 把每个会话的 `cwd` 解析为其自己的 `workspace-write` 根目录,因此共享的 bash 和文件系统服务可以服务并发项目而不授予跨项目写入。这不会添加 ACP `additionalDirectories`;它只是从已经支持的「每会话一个主根目录」路径中移除了进程级根目录限制。 + ## 曾考虑的替代方案 **每连接单活跃会话**:否决。增加进程开销,与目标客户端的多会话形态相矛盾,且并未消除编辑器端的多路复用需求。 diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml b/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml index 6beb8d876f..97e09d562e 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml @@ -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 -2026-06-15-code-mode.md: fb95f3010121fa432b3ac24e6aa477b1205a0ba7 -2026-06-15-code-mode.zh.md: 2da6628c1842bfd507c62d4b66a91f323e6fd0e7 +2026-06-15-code-mode.md: f403e87601aad0fda5d53ec5b94ba44452e79b49 +2026-06-15-code-mode.zh.md: b4b432a6ce2206ea4920f89275d431ed2d3d0c44 diff --git a/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md b/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md index 2da6628c18..b4b432a6ce 100644 --- a/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md +++ b/.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md @@ -1,4 +1,4 @@ -# RFC: Code Mode——模型针对工具注册表编写 TypeScript +# Agent Note: Code Mode——模型针对工具注册表编写 TypeScript Status: implemented @@ -6,20 +6,20 @@ Status: implemented ## 问题 -在注册表的原生呈现方式下,agent loop(智能体循环)将每个可见能力以 JSON Schema 函数定义的形式通告给模型。`ToolRegistry` 将其 schema 贡献给系统提示词组装,组装结果中的 `tools` 落到协议格式(wire format)上(也记录在请求头日志中),模型每步调用一个 `tool-call` 块,循环通过 `ctx.tools.execute()` **逐个**分发每次调用(并行工具执行是 `dsh-tools` 和 [docs/architecture.md](../../../architecture.md) 中明确标注的 open TODO),且**每一个**中间 `tool-result` 都会在下一次请求时重新进入模型上下文。 +在注册表的原生呈现方式下,agent loop(智能体循环)将每个可见能力以 JSON Schema 函数定义的形式通告给模型。`ToolRegistry` 将其 schema 贡献给系统提示词组装,组装结果中的 `tools` 落到协议格式(wire format)上(也记录在请求头日志中),模型每步调用一个 `tool-call` 块,循环通过 `ctx.tools.execute()` **逐个**分发每次调用(并行工具执行是 `dsh-tools` 和 [docs/architecture.md](../../../../docs/architecture.md) 中明确标注的 open TODO),且**每一个**中间 `tool-result` 都会在下一次请求时重新进入模型上下文。 对于多步工具操作,这种方式 token 开销大且串行。模型无法组合工具——遍历结果集、根据中间值分支、扇出、后处理——每次调用都需要一次完整的模型往返,而每次往返都会把完整的中间结果拖回上下文,不管模型是否需要。 Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一种替代方案,基于一个简单的观察:LLM(大语言模型)编写代码的能力优于发出工具调用,因为它们见过数百万行真实代码,而人为构造的工具调用 trace 相对很少。模型不再每步发出一次工具调用,而是针对工具生成的 API 编写一段 TypeScript 程序,程序在沙箱运行时中执行,模型只策展返回的内容——仅限它 print 或 return 的部分——而非所有中间结果。 -工具呈现属于掌管工具可见性的注册表:如果把第二种呈现方式实现为事后的 waterfall(瀑布式事件)变换,正确性将依赖监听器顺序,并与[可重建请求](../../implemented/architecture/2026-07-05-reconstructable-requests.md)冲突。执行基底同样属于基础设施而非占位实现:Node `worker_threads` 提供独立 isolate、空环境、堆上限以及对热同步循环的终止能力,同时契合 harness 既有的信任模型(§信任姿态)。 +工具呈现属于掌管工具可见性的注册表:如果把第二种呈现方式实现为事后的 waterfall(瀑布式事件)变换,正确性将依赖监听器顺序,并与[可重建请求](../architecture/2026-07-05-reconstructable-requests.md)冲突。执行基底同样属于基础设施而非占位实现:Node `worker_threads` 提供独立 isolate、空环境、堆上限以及对热同步循环的终止能力,同时契合 harness 既有的信任模型(§信任姿态)。 ## 决策 三项决策,各自在下方独立小节中展开: 1. **Code Mode 是 `ToolRegistry`(`dsh-tools`)的一等呈现模式**,通过经校验的 `mode` 配置选择:`'native'`(默认,贡献可见能力 schema)、`'code'`(注册表仅贡献其保留的 `run_code` 传输通道加一份生成的 SDK `.d.ts` 到系统提示词中)或 `'both'`(原生 schema 加传输通道 + SDK)。注册表在源头塑造其权威贡献;协作式 prompt 组装的结果仍具权威性,记录在日志中的请求头精确反映该返回的呈现。 -2. **代码执行是一个能力 seam**——`packages/code-runtime/` 包含接口包 `@deepseek-ai/dsh-code-runtime`,拥有 `ctx.codeRuntime`([能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md);消费方 = `dsh-tools`,core 消费 seam 的先例见 `agent-loop` → `dsh-llm`)。运行时对工具一无所知:它接收一段程序和命名的异步绑定,执行程序,报告 `{ value, logs, error? }`。语言和基底是后端属性,因此未来的 Python 或容器后端只是另一个实现包,而非重新设计。 +2. **代码执行是一个能力 seam**——`packages/code-runtime/` 包含接口包 `@deepseek-ai/dsh-code-runtime`,拥有 `ctx.codeRuntime`([能力 seam](../architecture/2026-06-13-capability-seams.md);消费方 = `dsh-tools`,core 消费 seam 的先例见 `agent-loop` → `dsh-llm`)。运行时对工具一无所知:它接收一段程序和命名的异步绑定,执行程序,报告 `{ value, logs, error? }`。语言和基底是后端属性,因此未来的 Python 或容器后端只是另一个实现包,而非重新设计。 3. **交付的实现是 `@deepseek-ai/dsh-code-runtime-worker`**:每次运行 spawn 一个全新的 Node worker 线程,对模型的 TypeScript 进行 type-strip 后执行,绑定通过 message port 桥接,环境为空,堆/输出/时间上限可配置,并支持硬终止。其信任姿态在设计上等同于 bash——无需 unsafe-acknowledgement flag——因为 harness 已经交付了 `dsh-bash-local`,后者以严格*更高*的环境权限执行模型编写的任意 shell 命令。 ### 注册表拥有模式 @@ -40,15 +40,15 @@ Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一 在 `'code'` 和 `'both'` 下,注册表拥有 `run_code` 作为保留的呈现传输通道,带一个必需参数 `{ code: string }`。它由一个正常的 `ToolDefinition` 表示以供分发,但位于可过滤的能力层之外,因此限制规则不会意外移除 Code Mode 的唯一入口。调用遍历完整的工具流水线——`tools/pre-execute` → 单调守卫 → `tools/execute` 包裹分发 → `tools/post-execute` → 不可变的 `tools/result` 通知——与原生调用完全一致;权限插件可以在程序运行前检查程序文本,最终结果观察者看到的是规范化的外层结果。其 `execute(args, exec)`: -1. **构建绑定。** 一个 run 级别的 signal 跟随外层取消,并在 run 结算时被 abort。每个可见工具绑定对参数做 JSON 规范化——在分发前拒绝有损值——等待序列化队列,以确定性的 call id 和外层 token 作为 `parent` 执行,并记录 `tool/code-dispatch`。成功的文本变为字符串,非文本块变为占位符;工具错误使绑定 promise reject。每个子调用保留自己不可变的执行标识,并遍历完整的工具流水线。 +1. **构建绑定。** 一个 run 级别的 signal 跟随外层取消,并在 run 结算时被 abort。每个可见工具绑定对参数做 JSON 规范化——在分发前拒绝有损值——等待序列化队列,以确定性的 call id 和外层 token 作为 `parent` 执行,通过外层 execution 延后返回的上下文,并记录 `tool/code-dispatch`。成功的文本变为字符串,非文本块变为占位符;工具错误使绑定 promise reject。每个子调用保留自己不可变的执行标识,并遍历完整的工具流水线。 2. **运行程序**:`ctx.codeRuntime.run({ program: args.code, bindings: [{ global: 'tools', functions }], signal: runController.signal })`。运行时接收的是 run 级别的 signal 而非仅调用方的外层 signal,因此外层 run 以任何方式结算都会同时 abort 运行时内部的工作。 3. **静默后结算。** 运行时结算后,桥 abort 未完成的工作并排空分发队列后再返回。成功时返回捕获的输出和呈现元数据。运行时失败变为 `CodeRunFailedError`;后端拒绝使用注册表的正常错误边界。两者都产生结构化的错误结果,且 `run_code` 结算后不允许子调用追加。 -**子调用的 `additionalContext` 被省略。** 在 `run_code` 期间注入它会破坏父调用/结果的相邻性,而一个程序可以产生多个 context。支持它需要一个复数通道或循环级别的子分发缓冲区。 +**子调用上下文通过父调用延后。** 在 `run_code` 内部注入会破坏父调用/结果的相邻性,因此 `ToolRunContext.deferContext()` 按分发顺序收集每个子结果的 `additionalContexts` 条目。即使程序后来抛出异常,注册表仍携带该数组;循环只在外层结果与步骤中所有兄弟结果之后追加每个条目。外层 post-execute block 会丢弃工具延后的条目,只暴露阻止 decision 显式附加的上下文。 **并发被序列化。** 每次 run 拥有一个分发队列,因此即使 `Promise.all` 也按提交顺序执行工具调用。结算时放弃尚未开始的排队调用。并行化需要每个工具的并发安全元数据。 -**呈现。** `run_code` 的 render intent 按 [render-intent RFC](../../implemented/architecture/2026-07-02-tool-render-intent-union.md) 在此决定:`presentCall` → 一个 `generic` 卡片,`kind: 'execute'`,title = 程序文本,`rawInput` = 同一程序文本;`presentResult` → 一个 `generic` 卡片,content 为捕获的输出(来自 `meta`)。程序作为 title 是因为 ACP execute 卡片可靠地渲染该字段,而某些客户端会省略 body 和 raw-input 内容。这不是 `terminal` 卡片:该卡片的语义是「工作目录中的 shell 命令」,程序不是。 +**呈现。** `run_code` 的 render intent 按 [render-intent Agent Note](../architecture/2026-07-02-tool-render-intent-union.md) 在此决定:`presentCall` → 一个 `generic` 卡片,`kind: 'execute'`,title = 程序文本,`rawInput` = 同一程序文本;`presentResult` → 一个 `generic` 卡片,content 为捕获的输出(来自 `meta`)。程序作为 title 是因为 ACP execute 卡片可靠地渲染该字段,而某些客户端会省略 body 和 raw-input 内容。这不是 `terminal` 卡片:该卡片的语义是「工作目录中的 shell 命令」,程序不是。 ### 可观测性:`tool/code-dispatch` @@ -62,7 +62,7 @@ Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一 - `CodeBindingNamespace = { global: string; functions: Record<string, (args: unknown) => Promise<unknown>> }`——运行时将每个命名空间作为程序内部的全局异步函数对象暴露;绑定参数和解析值必须是 structured-cloneable 的(运行时可能跨越序列化边界;我们的实现确实如此)。 - `CodeRunResult = { value?: unknown; logs: CodeLogEntry[]; error?: CodeRunFailure }`——程序执行结果,包括异常、超时、abort 和 worker 退出,都解析为 `error` 字段。`run()` 仅在调用方/seam 误用时才 reject(例如重复的绑定命名空间);消费方仍在自己的错误边界处理不合规的后端拒绝。 - `CodeLogEntry = { source: 'console' | 'stdout' | 'stderr'; level?: 'log' | 'info' | 'warn' | 'error' | 'debug'; text: string }` -- `CodeRunFailure = { kind: 'exception' | 'timeout' | 'abort' | 'worker-exit'; message: string }`——按[防御性模式](../../../defensive-patterns.md)独立报告的正交结果;超时的 run 不是异常,abort 不是超时。 +- `CodeRunFailure = { kind: 'exception' | 'timeout' | 'abort' | 'worker-exit'; message: string }`——按[防御性模式](../../../../docs/defensive-patterns.md)独立报告的正交结果;超时的 run 不是异常,abort 不是超时。 - 两个只读的后端描述符,仅供信息参考而非门禁判定:`language`(程序必须使用的语言——交付的后端为 `'typescript'`;Python 后端会声明自己,并在呈现侧配对自己的 SDK 生成器)和 `isolation`(交付的后端为 `'worker-thread'`;未来可为 `'process'`、`'container'` 等)。`dsh-tools` 在 MVP 中要求 `language === 'typescript'`——其代码生成输出 TS——否则组装会大声失败,与 `toolOrder` 违规时的配置错误惯用法相同(如 `mode` 为非 native 但根本没有加载 `ctx.codeRuntime`)。 请求包含所有运行时输入;实现方拥有经校验的超时和上限默认值。注册表仅在组装 Code Mode 时查找可选的运行时,因此 native 模式不依赖它。缺失或语言不兼容的运行时会大声失败。替代基底或语言可以在同一 seam 背后替换实现,配对相应的 SDK 生成器。 @@ -76,7 +76,7 @@ Cloudflare 的 [Code Mode](https://blog.cloudflare.com/code-mode/) 提出了一 3. **在 bootstrap 中执行**:剥离后的程序成为一个 `AsyncFunction` 的函数体,其参数是绑定全局变量和一个捕获式 `console` shim,因此顶层 `await` 和 `return` 可用,程序的完成值即为 run 的 `value`(structured-cloneable 值原样跨越;其他值被替换为其 `util.inspect` 渲染,已文档化)。 4. **通过 message port 桥接绑定**:worker 中的每个绑定函数发送 `{ id, global, name, args }` 并等待回复;宿主根据请求的绑定校验名称、调用、并回复 `{ id, ok, value }` 或 `{ id, ok: false, message }`(宿主侧绑定拒绝变为程序侧 rejection)。worker 侧的命名空间对象通过 `defineProperty` 构建为 null-prototype,因此名为 `__proto__`、`constructor` 或 `toString` 的绑定是普通自有属性,而非原型链碰撞。未知名称、重复 id 和结算后消息被拒绝或忽略——端口协议假设对端是恶意的,因为对端运行的是模型代码。 5. **强制独立预算。** `computeMs` 计量 worker 忙碌时间,允许慢速的 awaited 工具而不放过热循环。`maxWallMs` 约束总经过时间,包括未解析的等待。到期、取消和完成都终止 worker。堆退出和截断被显式报告;compute、wall、heap、log 和返回值上限是经校验的配置。 -6. **dispose 至静默**:服务自身的 dispose(资源释放)终止进行中的 worker 并*等待*其退出后再 resolve,遵循[防御性模式](../../../defensive-patterns.md)。 +6. **dispose 至静默**:服务自身的 dispose(资源释放)终止进行中的 worker 并*等待*其退出后再 resolve,遵循[防御性模式](../../../../docs/defensive-patterns.md)。 ### 信任姿态 @@ -88,18 +88,18 @@ SDK 指示模型编写一个异步的可擦除 TypeScript 函数体,通过 `aw ## 后果 -切换到 `'code'` 的部署必须更新任何仅限 native 的 `toolOrder`。组装监听器有责任维护任何被重写的协议面的完整性。子分发保持序列化,桥不传播每次调用的 `additionalContext`,直到为 Code Mode 设计好这些契约。 +切换到 `'code'` 的部署必须更新任何仅限 native 的 `toolOrder`。组装监听器有责任维护任何被重写的协议面的完整性。子分发保持序列化,而每次调用的上下文会通过外层结果保留其 source、信封与元数据。 ## 测试 - **Worker 运行时:** 真实 worker 测试覆盖输出和值捕获、失败类型、compute 和 wall 预算、恶意绑定流量、空环境、structured-clone 回退、输出上限和 dispose 至静默。一个构建后包测试在纯 Node 下运行 worker 入口。 -- **注册表集成:** 测试覆盖代码生成、所有呈现模式、保留名称和限制规则、scoped 可见性、权威组装重写、`toolOrder`、运行时兼容性失败、完整流水线子分发、parent-token 关联、序列化、取消和队列排空、JSON 规范化、错误传播、日志事件、省略的 `additionalContext` 和 HMR(热模块替换)清理。 -- **带密钥 e2e:** 真实模型在一个程序中组合两次 bash 调用;测试验证折叠的请求头、关联的分发事件、结果文件和策展后的回答。 -- **快照:** `code-mode-turn` 和 `both-mode-turn` fixture(测试前置数据)固定 SDK 段、请求头工具列表、分发事件和结果卡片。 +- **注册表集成:** 测试覆盖代码生成、所有呈现模式、保留名称和限制规则、scoped 可见性、权威组装重写、`toolOrder`、运行时兼容性失败、完整流水线子分发、parent-token 关联、序列化、取消和队列排空、JSON 规范化、错误传播、日志事件、成功与失败程序中的有序上下文延后、外层 block 抑制以及 HMR(热模块替换)清理。 +- **带密钥 e2e:** 真实模型在一个程序中组合两次 bash 调用;另一个模型通过 Code Mode fs 分发发现嵌套的工作区指令。测试验证折叠的请求头、关联的分发事件、结果文件、延后上下文和模型行为。 +- **快照:** `code-mode-turn`、`both-mode-turn` 和 `code-mode-workspace-context` fixture(测试前置数据)固定 SDK 文本、请求头工具列表、分发事件、延后上下文和结果卡片。 ## 曾考虑的替代方案 -**一个零核心改动的附加消费方插件。** 否决,因为 `agent/request` 在[可重建请求](../../implemented/architecture/2026-07-05-reconstructable-requests.md)下仅限 call-config,而变换已组装的工具列表需要在不拥有其配置的情况下撤销 `toolOrder` 规范化,并依赖监听器顺序。向模型提供哪些工具、以何种表示形式提供,是注册表的单一关注点:原生 schema 和 SDK 是同一个可见存储的两种投影。 +**一个零核心改动的附加消费方插件。** 否决,因为 `agent/request` 在[可重建请求](../architecture/2026-07-05-reconstructable-requests.md)下仅限 call-config,而变换已组装的工具列表需要在不拥有其配置的情况下撤销 `toolOrder` 规范化,并依赖监听器顺序。向模型提供哪些工具、以何种表示形式提供,是注册表的单一关注点:原生 schema 和 SDK 是同一个可见存储的两种投影。 **`node:vm` 作为参考运行时,加固推迟。** 否决:`node:vm` 不是隔离(原型链逃逸可达宿主 realm)且无法中断热循环。worker 线程提供独立 isolate、空环境、`resourceLimits` 和可靠的 `terminate()`,信任等级等同于 bash,因此参考实现和生产实现是同一个包,无需 unsafe-acknowledgement 仪式。 @@ -121,7 +121,7 @@ SDK 指示模型编写一个异步的可擦除 TypeScript 函数体,通过 `aw **`stripTypeScriptTypes` 标记为 experimental。** 它与 Node 自身原生 `.ts` 执行背后的引擎(amaro/swc)相同,在本仓库的整个引擎范围内作为 API 暴露。缓解措施:运行时的单元测试套件固定了所依赖的行为(位置保持、可擦除限制的拒绝消息形状宽松匹配),调用位于一个私有函数之后,且 `amaro`/`sucrase` 是 API 变化时的直接替代品。仅可擦除子集是面向模型的契约线,错误路径是一个可工作的反馈循环,而非死胡同。 -**SDK 的 prompt 成本,尤其在 `'both'` 下。** `.d.ts` 可能与它补充的原生 schema 体量相当;`'both'` 携带两种表示。前缀稳定性 + 提供方缓存摊销了每会话成本;mode 是每部署的;本 RFC 不做无条件节省的声明。何时优先使用哪种模式的量化指导明确属于上线后学习。 +**SDK 的 prompt 成本,尤其在 `'both'` 下。** `.d.ts` 可能与它补充的原生 schema 体量相当;`'both'` 携带两种表示。前缀稳定性 + 提供方缓存摊销了每会话成本;mode 是每部署的;本 Agent Note 不做无条件节省的声明。何时优先使用哪种模式的量化指导明确属于上线后学习。 **注册表 scope 增长。** `dsh-tools` 吸收了代码生成、一个工具、一个桥和一个事件。通过包内的模块边界(`ts-types.ts`、`code-mode.ts` 与 `schema.ts`/`json-schema.ts`/`presentation.ts` 并列)和 seam 约束:所有基底相关的内容都在 `ctx.codeRuntime` 之后。 diff --git a/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml b/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml index b3ed1ae8ee..35f14a2678 100644 --- a/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.i18n.yaml @@ -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 -2026-06-17-filesystem-tool-schemas.md: dba96157a0df548e4f153a0e233238af7400c087 -2026-06-17-filesystem-tool-schemas.zh.md: 3c135de9fa81fb333abc5fa6001a7ce7d7525a9d +2026-06-17-filesystem-tool-schemas.md: fa23dccc7ae98a9c25b9c474a75dc1e2f8e5ff21 +2026-06-17-filesystem-tool-schemas.zh.md: 30acf26a9bb2858a9f786591b6e01626593713d0 diff --git a/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md b/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md index 3c135de9fa..30acf26a9b 100644 --- a/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md +++ b/.agents/notes/implemented/feature/2026-06-17-filesystem-tool-schemas.zh.md @@ -1,4 +1,4 @@ -# RFC: 文件系统工具 schema——面向模型的读/写/编辑接口形状 +# Agent Note: 文件系统工具 schema——面向模型的读/写/编辑接口形状 Status: implemented @@ -6,9 +6,9 @@ Status: implemented ## 问题 -[文件系统能力 seam RFC](../architecture/2026-06-17-filesystem-capability-seam.md) 定义了文件系统能力 seam(`ctx.fs`)、包(package)拆分(`dsh-fs`、`dsh-fs-local`、`dsh-tool-fs`,加上 `dsh-fs-policy` 策略插件),以及针对 read-before-write/edit 检查的 observed-file/stale-version 策略——[split-fs-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](../architecture/2026-06-26-file-context-as-event-gate.md) RFC 后来将其从 `ctx.fs` 移至 `dsh-fs-policy` 插件的 `fs/*` 事件门上。首次文件系统工具交付剩余的决策是面向模型的 schema 接口:模型在 `read`、`write` 和 `edit` 中看到哪些参数。 +[文件系统能力 seam Agent Note](../architecture/2026-06-17-filesystem-capability-seam.md) 定义了文件系统能力 seam(`ctx.fs`)、包(package)拆分(`dsh-fs`、`dsh-fs-local`、`dsh-tool-fs`,加上 `dsh-fs-policy` 策略插件),以及针对 read-before-write/edit 检查的 observed-file/stale-version 策略——[split-fs-seam](../simplification/2026-06-26-fsspec-style-fs-seam.md) 和 [event-gate](../architecture/2026-06-26-file-context-as-event-gate.md) Agent Note 后来将其从 `ctx.fs` 移至 `dsh-fs-policy` 插件的 `fs/*` 事件门上。首次文件系统工具交付剩余的决策是面向模型的 schema 接口:模型在 `read`、`write` 和 `edit` 中看到哪些参数。 -该 schema 应足够小,以便在 `dsh-tool-fs` 的首次实现中完成,但又足够稳定,使未来的本地/远程/沙箱文件系统后端不需要改动面向模型的接口。同时应避免从参考系统中照搬所有选项。Claude Code 和 OpenCode 暴露了类似的核心文件工具,但在命名风格和额外 flag 上有所不同;本 RFC 为原型选择最小的共有接口。 +该 schema 应足够小,以便在 `dsh-tool-fs` 的首次实现中完成,但又足够稳定,使未来的本地/远程/沙箱文件系统后端不需要改动面向模型的接口。同时应避免从参考系统中照搬所有选项。Claude Code 和 OpenCode 暴露了类似的核心文件工具,但在命名风格和额外 flag 上有所不同;本 Agent Note 为原型选择最小的共有接口。 ## 决策 @@ -105,8 +105,8 @@ schema 测试固定每个工具的必填/可选参数集、空 `old_string` 拒 ## 后果 -**首版 schema 有意小于 Claude Code 的。** 去掉 PDF pages、多模态 read、丰富的 grep/list flag 和 expected hash 字段使实现保持聚焦,但用户可能很快就会提出这些需求。它们将以独立 RFC 或聚焦的后续工作形式到来,而非对初始 schema 的重载。 +**首版 schema 有意小于 Claude Code 的。** 去掉 PDF pages、多模态 read、丰富的 grep/list flag 和 expected hash 字段使实现保持聚焦,但用户可能很快就会提出这些需求。它们将以独立 Agent Note 或聚焦的后续工作形式到来,而非对初始 schema 的重载。 **v1 中没有显式的面向模型的 stale guard。** schema 不要求模型提供 expected hash/version。这是有意为之:陈旧检查来自后端产生的版本和 `dsh-fs-policy` 插件的观测状态,而非模型复制的脆弱令牌。文件系统安全失败通过 `dsh-fs` 拥有的结构化 `FsError` 代码浮现,而非模型提供的版本字段。 -**命名成为公开接口。** 一旦发布,将 `file_path` 改为 `filePath` 或 `old_string` 改为 `oldString` 会搅动提示词、示例和下游客户端。本 RFC 预先选择 snake_case,并将其视为稳定的面向模型的契约。 +**命名成为公开接口。** 一旦发布,将 `file_path` 改为 `filePath` 或 `old_string` 改为 `oldString` 会搅动提示词、示例和下游客户端。本 Agent Note 预先选择 snake_case,并将其视为稳定的面向模型的契约。 diff --git a/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml b/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml index b25f0bf18b..5ca5a1e59d 100644 --- a/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.i18n.yaml @@ -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 -2026-06-18-acp-terminal-and-tool-rendering.md: 9bcb65a1e0b316d0b596a80816647d46ccfca782 -2026-06-18-acp-terminal-and-tool-rendering.zh.md: 3899e3ed21b386b1652736bc3de41d338efaa30e +2026-06-18-acp-terminal-and-tool-rendering.md: 166e52f8e659a78b1347279c61956ca1001e4939 +2026-06-18-acp-terminal-and-tool-rendering.zh.md: 924ea9fb50a77314748d4826b5c408d5243b32f9 diff --git a/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md b/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md index 3899e3ed21..924ea9fb50 100644 --- a/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md +++ b/.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.zh.md @@ -1,4 +1,4 @@ -# RFC: 富 ACP bash 渲染——通过 `_meta` 约定实现终端卡片 +# Agent Note: 富 ACP bash 渲染——通过 `_meta` 约定实现终端卡片 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -ACP(Agent Client Protocol)桥接层允许每个工具通过 `presentCall`/`presentResult` 自行控制调用渲染(见 [tool-call UI presentation](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md) 与 `packages/core/tools`)。对于 `bash`,我们将确切命令作为 `tool_call` 标题呈现,模型的 `description` 作为一个内容文本块,`kind: 'execute'`,完成后的输出包裹在 ` ```console ` 围栏文本块中。 +ACP(Agent Client Protocol)桥接层允许每个工具通过 `presentCall`/`presentResult` 自行控制调用渲染(见 [tool-call UI presentation](2026-06-14-acp-agent-client-protocol.md) 与 `packages/core/tools`)。对于 `bash`,我们将确切命令作为 `tool_call` 标题呈现,模型的 `description` 作为一个内容文本块,`kind: 'execute'`,完成后的输出包裹在 ` ```console ` 围栏文本块中。 参考编辑器将终端元数据渲染为一张专用卡片,包含 cwd、命令、实时风格的输出和退出状态;纯文本则丢失了这些结构。命令之所以作为标题,是因为执行卡片隐藏原始输入,而人类可读的描述保留为卡片上方的独立块。 @@ -45,4 +45,4 @@ Zed 侧(`crates/agent_servers/src/acp.rs`,已验证):收到 `ToolCall` ## 超出范围 / 非目标 -文本块基线仍为无能力声明时的默认行为。以下两项后续工作有意不在此处构建,各自需要单独的 RFC:**实时增量流式传输**(在分片到达时发出 `_meta.terminal_output_delta`,需要在 `dsh-bash` 上新增增量输出 seam);**命令分类**(将 `cat`/`sed` 解析为带文件位置的 `read` 卡片,将 `grep` 解析为 `search`,回退到终端卡片——仅展示,绝不改变实际执行内容)。 +文本块基线仍为无能力声明时的默认行为。以下两项后续工作有意不在此处构建,各自需要单独的 Agent Note:**实时增量流式传输**(在分片到达时发出 `_meta.terminal_output_delta`,需要在 `dsh-bash` 上新增增量输出 seam);**命令分类**(将 `cat`/`sed` 解析为带文件位置的 `read` 卡片,将 `grep` 解析为 `search`,回退到终端卡片——仅展示,绝不改变实际执行内容)。 diff --git a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml index d99478bc53..4edec28660 100644 --- a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.i18n.yaml @@ -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 -2026-06-18-compaction-capability-seam.md: e88b3fd8267f65bba136398df9c439e371237912 -2026-06-18-compaction-capability-seam.zh.md: 75049079a2d85e27301e53b891228c1cbc87fac3 +2026-06-18-compaction-capability-seam.md: 07da796fdabffb8a43950ad501f5623d4474923a +2026-06-18-compaction-capability-seam.zh.md: 18ef9a8d833bdaa924324867d522399c0ad48243 diff --git a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md index f609473a9c..07da796fda 100644 --- a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md +++ b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-18-compaction-capability-seam.zh.md) + ## Problem A long-running agent conversation grows without bound. As the event log accumulates turns, the derived message history eventually approaches the model's context window — the model then truncates mid-response (`max-tokens`) or degrades. **Compaction** is the mitigation: replace a run of older history with a concise summary, keeping recent context intact. diff --git a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md index 75049079a2..18ef9a8d83 100644 --- a/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md +++ b/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.zh.md @@ -1,4 +1,4 @@ -# RFC: 压缩作为能力 seam(抽象契约 + 基础后端) +# Agent Note: 压缩作为能力 seam(抽象契约 + 基础后端) Status: implemented @@ -8,57 +8,58 @@ Status: implemented 长时间运行的 agent(智能体)对话会无限增长。随着事件日志不断累积轮次,派生出的消息历史最终逼近模型的上下文窗口,模型随即截断响应(`max-tokens`)或性能退化。**上下文压缩(context compaction)** 是对此的缓解手段:用一段简洁的摘要替换一批较早的历史,保持近期上下文完整。 -[session surface](../../implemented/architecture/2026-06-18-session-surface.md) 正是为此而构建的基础设施:一条建立在事件日志之上的链表,带有专门设计的 `surfaceOp: { op: 'replace', start, end }` 操作,用于遮蔽一段节点并插入替换内容,`sourceEventSeqs` 记录来源以便决策可确定性地回放。剩下的是那个*决定压缩什么、并产出摘要*的插件。 +[session surface](../architecture/2026-06-18-session-surface.md) 正是为此而构建的基础设施:一份建立在事件日志之上的有序投影,带有专门设计的 `surfaceOp: { op: 'replace', start, end }` 操作,用于遮蔽一段条目并插入替换内容,`sourceEventSeqs` 记录溯源信息以便决策可确定性地回放。剩下的是那个*决定压缩什么、并产出摘要*的插件。 -两股力量塑造了设计。第一,压缩是**可替换的**:token 计数可以是 char/4 启发式或真实 tokenizer,摘要生成可以是模型调用、模板或远程服务——它们独立于*何时*以及*压缩哪段范围*而变化。第二,`SurfaceEventType` 封闭为五种事件类型(`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`);只有这些类型可以携带 `surfaceOp`。因此一个专用的 `compaction/*` 事件**不能**出现在 surface 上——编译器拒绝在其上附加 `surfaceOp`,invariants 插件在运行时也会拒绝。 +两股力量塑造了设计。第一,压缩策略与可复用的 token 测量独立变化:测量归 LLM 系列的 [`ctx.tokenMeter` 服务](../architecture/2026-07-15-replay-token-meter-service.md)所有,摘要生成则可以使用模型调用、模板或远程服务。第二,`SurfaceEventType` 封闭为五种事件类型(`user/message`、`assistant/message`、`tool/result`、`context/message`、`steering/message`);只有这些类型可以携带 `surfaceOp`。因此一个专用的 `compaction/*` 事件**不能**出现在 surface 上,编译器与 Session 始终启用的 append/seed 边界都会拒绝在其上附加 `surfaceOp`。 ## 决策 ### 压缩是一个能力 seam,接口与实现分离 -遵循[能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md),压缩以独立包(package)发布,使契约、算法和(后续的)消费方 surface 各自独立演进: +遵循[能力 seam Agent Note(agent 决策记录)](../architecture/2026-06-13-capability-seams.md),压缩以独立包(package)发布,使契约、算法和(后续的)消费方 surface 各自独立演进: 1. **接口** — `@deepseek-ai/dsh-compact`:抽象 `CompactService`,拥有 `ctx.compact` 键、`CompactionResult` 词汇以及 `compact/*` 会话事件。它将 `compactIfNeeded()` 和 `compactRegion()` 声明为**抽象方法**——契约说明压缩*做什么*,而非*怎么做*。 -2. **实现** — `@deepseek-ai/dsh-compact-basic`:具体的 `BasicCompactService`,拥有完整算法——token 估算(每 token 字符数,即 `charsPerToken` 配置,默认 4,加上每块开销)、尾→头保留遍历、通过 `ctx.llm.stream()` 进行摘要生成、surface 替换、锁,以及 `agent/pre-step` 自动压缩监听器。基于 tokenizer 或模板的后端是同级包(或覆盖两个 protected 估算/摘要钩子的子类)。 -3. **消费方** — 推迟。一个 `/compact` 工具和斜杠命令将 `inject: ['compact']` 并调用契约;它们被有意排除在本 RFC 范围之外,以便 seam 先稳定下来。 +2. **实现** — `@deepseek-ai/dsh-compact-basic`:具体的 `BasicCompactService`,消费 `ctx.tokenMeter`,并拥有尾→头保留遍历、通过 `ctx.llm.stream()` 生成摘要、surface 替换、锁、步骤后压力处理和规范的上下文溢出恢复。`summarize()` 是其唯一的子类钩子;计价与回放仍归 meter 所有。 +3. **无模型配套服务** — `@deepseek-ai/dsh-compact-tool-result-prune`:一个具体的可选服务,在后端选择摘要范围之前,重写当前过大的 `tool/result` 节点。它不是第二种压缩实现,也不实现 `CompactService`。 +4. **消费方** — 推迟。一个 `/compact` 工具和斜杠命令将 `inject: ['compact']` 并调用契约;它们被有意排除在本 Agent Note 范围之外,以便 seam 先稳定下来。 ### 契约依赖 `dsh-session` 和 `dsh-llm`——有意为之的偏离 -能力 seam RFC 规定接口包"仅依赖 cordis"(对 `dsh-bash` 成立,因为其词汇是自包含的)。压缩**无法**遵守这一点:它的动词定义*在* `Session` 之上(`compactRegion(session, start, end)`),其输出*就是*内容词汇(`CompactionResult.summary: ContentBlock[]`)。不引用 `Session`/`SessionEvent`(来自 `dsh-session`)和 `ContentBlock`(来自 `dsh-llm`),契约就无法表达。 +能力 seam Agent Note 规定接口包「仅依赖 cordis」(对 `dsh-bash` 成立,因为其词汇是自包含的)。压缩**无法**遵守这一点:它的动词作用于 agent 所有的 `Session`(`compactRegion(start, end, agent)`),其输出使用内容词汇(`CompactionResult.summary: ContentBlock[]`)。不引用 `Session`/`SessionEvent`(来自 `dsh-session`)和 `ContentBlock`(来自 `dsh-llm`),契约就无法表达。 -这不是耦合异味,而是契约的领域所在。"仅 cordis"的指导原则一直是"接口仅依赖契约真正需要命名的东西,绝不依赖实现"的简写。`dsh-session` 和 `dsh-llm` 本身是接口/词汇包,不是实现;`dsh-compact` 仍然不导入任何后端。seam 的真正不变式——*消费方和实现在抽象服务背后独立演进*——完好无损。 +这不是耦合异味,而是契约的领域所在。「仅 cordis」的指导原则一直是「接口仅依赖契约真正需要命名的东西,绝不依赖实现」的简写。`dsh-session` 和 `dsh-llm` 本身是接口/词汇包,不是实现;`dsh-compact` 仍然不导入任何后端。seam 的真正不变式——*消费方和实现在抽象服务背后独立演进*——完好无损。 ### 抽象 `compactIfNeeded` / `compactRegion`,算法在后端 -早期草案将完整算法(保留遍历、token 求和、文本提取)作为接口上的具体方法,仅 `estimateContentTokens()` 和 `summarize()` 为抽象。这会将契约重新耦合到一种策略:想要不同保留策略或不同事件排序的后端必须与继承来的具体代码对抗。将两个核心方法都设为抽象,把所有*怎么做*的决策放在后端——它本该在那里——并让接口保持为纯粹的*做什么*声明。后端内部仍有分层——`estimateContentTokens()` 和 `summarize()` 是 `protected` 钩子,子后端可以覆盖而无需重新实现遍历——但那是后端的私有关注点,不是契约的。 +早期草案将完整算法(保留遍历、token 求和、文本提取)作为接口上的具体方法。这会将契约重新耦合到一种策略:想要不同保留策略或事件排序的后端必须与继承来的具体代码对抗。将两个核心方法都设为抽象,把所有*怎么做*的决策放在后端,并让接口保持为*做什么*的声明。token 测量根本不是压缩钩子;单例服务使多个消费方能够共享逐会话的回放折叠。 -`compactIfNeeded(agent, turn, step, fullSystemPrompt, signal)` 接收**必需**参数(而非最初的全可选形式)。自动压缩 seam(见下文)总是提供 agent、生命周期上下文、组装好的系统提示词(计入估算)和轮次的 abort signal,因此可选性只会在 seam 处引入隐藏的默认值。被压缩的会话来自 agent 上下文。`compactRegion(session, start, end, agent, turn, step, signal?)` 保留可选的 signal(手动调用方可以省略)。传递生命周期上下文而非具体模型,使路由 agent 保持诚实:后端的摘要请求可以走 `agent/request`,模型路由插件在那里已经选择了实际模型。 +`compactIfNeeded(agent, trigger, signal)` 接受显式的 `'pressure' | 'context-overflow'` 触发原因与取消信号。它只读取最新的持久化已路由请求;没有 header 就不执行工作,任何已路由的提供方/模型目标都使用单例估算器。`compactRegion(start, end, agent, signal?)` 将 `agent.session` 作为唯一会话身份,并为手动调用方保留可选 signal。默认摘要器依次从显式配置、最新记录的已路由目标和 agent 选项解析目标,并在任何 `llm/stream` 路由后记录提供方/模型对。它回放已路由请求的前缀,并将压缩指令追加为尾部 user 消息,从而复用提供方的热 KV cache;见[摘要前缀缓存 Agent Note](../bug-fix/2026-07-21-compaction-summary-prefix-cache-reuse.md)。该调用将提供方无关的 `GenerateOptions.purpose` 设为 `compaction`;适配器可以将此用途映射为对模型隐藏的传输元数据,DeepSeek 适配器会发送 `x-deepseek-harness-compact: 1`。 -### 自动压缩在 `agent/pre-step` 运行——一个专用的 surface 变更 seam +### 成功的持久步骤工作完成后运行自动压力检查 -压缩会变更 session surface,因此在步骤开启之前、消息派生之前运行。`agent/request` 保持为调用配置变换,无需在 surface 变更后重建历史。 +成功调用的压力检查不能在步骤前运行,因为最终的 `agent/request` 路由、提供方输出、工具结果、缓冲上下文与 steering 当时尚不存在。串行的 `agent/post-step(agent, turn, step, signal)` 会在这些事实持久化后、`step/end` 之前触发。`dsh-compact-basic` 通过 `ctx.tokenMeter` 测量规范的已记录请求,因此下一个请求无需推测性覆盖信封即可看到任何替换。压力达到条件后,可选的 `ctx.toolResultPrune` 重写在摘要范围选择前运行;compact-basic 重新测量持久 surface,如果修剪恢复到安全压力便跳过摘要生成。 -解决方案是一个专用的循环 seam:**`agent/pre-step`**(`@mode serial`),由循环在系统组装*之后*、步骤开启(`step/start`)*之前*触发: +规范的提供方上下文溢出走另一条路径。失败步骤先关闭,`agent/request-error` 接收原始请求错误与连续重试次数,compact-basic 在强制执行一次有效且平衡的缩减前先修剪。仅当 `session.surface.replaceGeneration` 增加时,它才返回 retry;这包括没有摘要范围时仅修剪取得的进展。随后循环开启新的编号步骤,并从持久日志重建请求。没有替换、任何替换前的恢复失败、取消、耗尽的上限或无关错误都会保留原始提供方失败。如果修剪已经推进 generation,而后续摘要工作失败,恢复会从该持久的已修剪 surface 重试,除非取消或资源释放胜出。完整生命周期决策见[调用后恢复 Agent Note](../architecture/2026-07-10-after-call-compaction-pressure-and-overflow-recovery.md)。 ``` -assembly = ctx.systemPrompt.assemble() -await ctx.serial('agent/pre-step', agent, turn, step, system, signal) ⟵ compaction mutates the surface here -session('step/start') ⟵ the step opens AFTER the seam -messages = session.deriveMessages() ⟵ single derive, reflects the compaction -request = waterfall agent/request ⟵ pure request transform (hooks, model switch) -``` +assistant/message → tool/result/context/steering +await serial agent/post-step ⟵ pressure compaction inside the successful step +step/end -循环在 `agent/pre-step` 之后派生一次消息。在 `step/start` 之前运行,使压缩记录位于任何半开步骤之外,简化崩溃修复。该 seam 是 awaited 且串行的,因此 surface 变更不会交错;监听器返回 `void`,不使用 Cordis bail 值作为否决。 +provider overflow → step/end +await waterfall agent/request-error ⟵ forced compaction between attempts +retry → next numbered step/start ⟵ derives from the replacement surface +``` ### 保留是轮次无关的;工具配对平衡是唯一的结构守卫 -自动压缩在**每个**步骤之前触发,而非每轮一次。这对**失控轮次存活至关重要**:工具密集型的 ReAct 轮次每步追加一个 `assistant/message` + 一个 `tool/result`,因此 surface 在*一轮之内*就会增长。单独一轮就可能超出窗口("失控轮次"),而在下一次模型调用溢出之前唯一能挽救的时机是下一步的 `pre-step` 检查点。如果将压缩限制在轮次的第一步(或者更糟,逐字保留整个进行中的轮次),恰好重新打开了压缩存在的意义所要堵住的缺口:harness 会在最需要压缩时崩溃。 +自动压缩在**每个成功的**步骤之后检查,而非每轮一次。这对失控轮次存活至关重要:工具密集型的 ReAct 轮次每步追加一个 `assistant/message` + 一个 `tool/result`,因此 surface 会在一轮之内增长。步骤后检查可以在后续步骤开启前压缩早期已关闭的工具对;如果请求率先越过限制,由提供方确认的溢出仍是兜底机制。 -`compactIfNeeded` 保留估算大小达到 `retainTokens` 的最小完整 surface 单元尾部,压缩更早的节点。一个单元是一个完整的已关闭步骤或一条无步骤消息。如果 token 截断点落在步骤内部,保留范围会扩展直到切割点满足工具配对平衡。平衡按 surface 顺序检查,而非日志序号,因为替换摘要在旧的 surface 位置拥有新的序号。`compactRegion` 拒绝将工具调用与其结果拆分的边界。进行中的轮次不享受特殊保留。 +`compactIfNeeded` 保留估算大小达到解析后保留 token 预算的最小完整 surface 单元尾部,压缩更早的节点。一个单元是一个完整的已关闭步骤或一条无步骤消息。如果 token 截断点落在步骤内部,保留范围会扩展直到切割点满足工具配对平衡。平衡按 surface 顺序检查,而非日志序号,因为替换摘要在旧的 surface 位置拥有新的序号。`dsh-compact` 导出前后边缘辅助函数;只要 `replaceGeneration` 不变,其逐会话缓存就只折叠新增的 surface 尾部节点,面对仅日志增长时不读取事件,并在替换后重建当前成员关系与平衡。`compactRegion` 拒绝将工具调用与其结果拆分的边界。进行中的轮次不享受特殊保留。 因此失控轮次的压缩方式与其他历史完全相同:其早期*已关闭*步骤被摘要,近期步骤保持原样。当唯一可压缩的内容只剩一个不可拆分的开放尾部步骤(其工具调用尚无结果)时,压缩拒绝执行(返回 `null`)并在该步骤关闭后重试。 -**单单元溢出不在范围内,这是有意为之。** 如果单个被保留的单元——一个已关闭步骤,或一个大型自由节点(如粘贴的 `user/message`)——*单独*超出预算,压缩无能为力,下一次模型调用可能超预算发出。限制单个单元的大小是另一个关注点(输出截断),在别处处理;压缩对此不作承诺,而没有这种机制的 harness 仍然可能在单个超大单元上崩溃。这里诚实地指出这一点,而非掩盖。 +**部分单单元溢出仍不在范围内。** 摘要范围选择无法拆分不可分割的单元。当可移除的文本型工具结果内容占据大部分空间,且修剪后的余量能够容纳时,可选修剪器可以修复一个已关闭的工具对。仅信封压力、粘贴的 `user/message` 等不可分割的超大非工具节点,以及不可修剪余量仍然过大的工具单元,依旧不属于压缩范围;限制这些单元是另一个关注点。 ### 头部锚定:一个自动检查点,始终在头部 @@ -66,11 +67,11 @@ request = waterfall agent/request ⟵ pure request transform (hooks, model s ### 近似收敛不变式 -`resolveConfig` 校验数值参数,但不基于虚构的摘要长度不变式来拒绝。收敛是动态的:提供方的输出上限可能被隐藏或显式的推理 token 消耗,模型可能生成不可预测大小的摘要。`maxTokens` 仅是摘要调用的提供方侧生成上限;推理块在检查点存储前被剥离。如果压缩后的 surface 仍超阈值,`compactIfNeeded()` 最多额外重压缩头部检查点 `compactionRetries` 次,但每次提交的摘要必须小于其遮蔽的内容。唯一的残余情况是上述单单元溢出(一个向后取整的超大步骤可能将保留尾部推过预算),这恰好是上述范围外的关注点,而非抖动 bug。 +`resolveConfig` 提供可用默认值:阈值比例 `0.8`、保留尾部比例 `0.16`、空的摘要提供方/模型覆盖、`maxTokens: 8192`、`compactionRetries: 1`、`maxOverflowRetries: 1` 以及 `auto: true`。可选的精确提供方/模型策略会部分覆盖顶层默认值;压力根据拥有该路由的 LLM 适配器所报告容量缩放比例,而 `retainTokens` 可以替代按比例保留。保留量必须低于最终阈值。收敛仍然是动态的,因为提供方输出上限可能被隐藏或显式的推理 token 消耗,摘要大小也不可预测。如果压力仍高于阈值,`compactIfNeeded()` 会按配置的重试次数再次压缩头部检查点,但每次提交的摘要必须小于其遮蔽的内容。溢出不需要容量元数据,并会绕过阈值和保留尾部策略,执行一次最大且平衡的头部缩减,留下最新的不可分割单元。所有权划分由[已路由模型上下文与压缩策略 Agent Note](../architecture/2026-07-20-routed-model-context-and-compaction-policy.md)规定。 ### Surface 替换:`compact/*` 事件仅存在于日志;一条 `user/message` 承载摘要 -由于 `SurfaceEventType` 是封闭的,摘要不能搭载在 `compact/*` 事件上。后端改为追加一条**单独的 `user/message`**,带有 `surfaceOp: { op: 'replace', start, end }`,其 `content` 是(带框架的)摘要,`sourceEventSeqs` 覆盖被遮蔽的节点*和*簿记事件。`compact/*` 事件是纯日志记录(锁 + 来源)。surface 变更位于锁**内部**——`compact/end` 是最后追加的事件: +由于 `SurfaceEventType` 是封闭的,摘要不能搭载在 `compact/*` 事件上。后端改为追加一条**单独的 `user/message`**,带有 `surfaceOp: { op: 'replace', start, end }`,其 `content` 是(带框架的)摘要,`sourceEventSeqs` 覆盖被遮蔽的条目*和*簿记事件。`compact/*` 事件是纯日志记录(锁 + 溯源信息)。surface 变更位于锁**内部**,`compact/end` 是最后追加的事件: ``` compact/start → log-only. Acquires the lock. @@ -81,7 +82,7 @@ user/message → surfaceOp { op:'replace', start, end }. THE surface mutatio compact/end → log-only. Releases the lock (carries `error` on a recoverable failure). ``` -`deriveMessages()` 随后产出 `[summary_as_user_message, ...retained_nodes]`。复用 `user/message` 是诚实的而非变通:摘要确实*是* user 角色的上下文。 +`deriveMessages()` 随后产出 `[summary_as_user_message, ...retained_entries]`。复用 `user/message` 是诚实的而非变通:摘要确实*是* user 角色的上下文。 ### 检查点框架 + 增量合并(后端私有) @@ -92,12 +93,14 @@ compact/end → log-only. Releases the lock (carries `error` on a recoverab `compact/start … compact/end` 括号的存在理由,按当前实际承担的职责排序: 1. **可检测的崩溃孤儿 + 来源追溯**(首要)。摘要生成是一次慢速模型调用,持久化在 `compact/start` *之后*。摘要生成中途崩溃会留下一个没有匹配 `compact/end` 的 `compact/start`——一个可检测的孤儿。最后释放锁(而非最先)将崩溃窗口从*静默损坏*转变为可检测的孤儿。 -2. **防止并发压缩。** 如果当前轮次持有未匹配的 `compact/start`,`compactRegion` 拒绝启动。(循环在 awaited 的 `pre-step` 上是单线程的,因此这也是重入绊线——抛出"already in progress"表示真正的 bug。) +2. **防止并发压缩。** 如果当前轮次持有未匹配的 `compact/start`,`compactRegion` 拒绝启动。(循环在任一 awaited 自动 seam 上都是单线程的,因此这也是重入绊线——抛出「already in progress」表示真正的 bug。) + +该锁只排除另一项压缩,不排除无关的仅日志事实。基础后端会在 `compact/start` 之后对 token meter 的 surface 节点取快照,并在异步摘要后再次比较;任何 surface 变更都会使替换前的检查失败,而标题或其他仅日志追加不会使已选范围失效。 两种失败路径,均有文档记录: -- **崩溃**(循环在摘要生成中途死亡):悬空的 `compact/start`,无关闭事件。由于 `compact/*` 是**仅日志**事件,孤儿是**惰性的**——surface 替换从未落地,因此完整的未压缩历史正确派生。通用轮次修复(`interruptedTurnClosers`)用合成的 `turn/end` 关闭轮次;孤儿位于该 `turn/end` *之前*,因此轮次范围内的进行中检查永远看不到它,崩溃不会卡住未来的压缩。压缩在下一个 `pre-step` 简单地重新尝试。 -- **可恢复**(摘要生成抛出异常但循环存活):后端追加带有 **`error`** 字段的 `compact/end`,surface 保持不变,模型调用以完整历史继续。 +- **崩溃**(循环在摘要生成中途死亡):悬空的 `compact/start`,无关闭事件。由于 `compact/*` 是**仅日志**事件,孤儿是**惰性的**,不会落地摘要替换。派生 surface 保持为 `compact/start` 时已经持久化的 surface:如果修剪未产生替换,就是完整历史;如果已经修剪,就是已修剪历史。通用轮次修复(`interruptedTurnClosers`)用合成的 `turn/end` 关闭轮次;孤儿位于该 `turn/end` *之前*,因此轮次范围内的进行中检查永远看不到它,崩溃不会卡住未来的压缩。 +- **可恢复**(摘要生成抛出异常但循环存活):后端追加设置了 **`error`** 字段的 `compact/end`,但不落地摘要替换。步骤后压力处理发出警告,并从最新的持久 surface 继续:如果尝试前没有替换,就是完整历史;如果修剪已经落地,就是已修剪 surface。溢出恢复只会在没有任何替换前委托;先前修剪带来的 generation 进展允许从该持久 surface 重试,除非取消或资源释放胜出。 `compact/end` 保留其 `error?` 字段(与 `tool/result` 的自包含错误一致——一个事件即可区分成功与失败,无需关联兄弟事件)。没有单独的 `compact/error` 事件。 @@ -105,23 +108,24 @@ compact/end → log-only. Releases the lock (carries `error` on a recoverab ## 曾考虑的替代方案 -- **完整算法作为接口的具体方法**(仅估算/摘要为抽象)——早期草案;否决,因为它将契约重新耦合到一种保留策略。两个核心方法都是抽象的;`protected` 的估算/摘要钩子是后端的私有分层,不是契约的。 -- **在 `agent/request` waterfall(瀑布式事件)上执行压缩**——早期方案;否决,因为它强制双重派生,且将监听器上下文交给了结构上无法压缩的对象。专用的 `agent/pre-step` seam 从构造上使分层正确。 +- **完整算法作为接口的具体方法**——否决,因为它将契约重新耦合到一种保留策略。两个核心方法都是抽象的;可复用测量属于单独的 LLM 系列服务,`summarize()` 是 basic 唯一的钩子。 +- **在 `agent/request` 或临时 `agent/pre-step` 输入上执行压缩**——否决,因为两者都无法证明最终的持久请求,而且都会将通用生命周期耦合到压缩专属的信封数据。步骤后回放与规范溢出恢复同时覆盖成功和被拒绝的调用。 +- **`compact` 布尔值或无类型的请求元数据 map**——否决,因为多个辅助调用种类会变成互斥标志,而开放 map 会丢弃由编译器检查的词汇。一个类型化的 `purpose` 判别字段可以扩展其他调用种类,而无需再为 `GenerateOptions` 添加字段。 - **单独的 `compact/error` 事件**——否决:`compact/end` 保留 `error?` 字段,与 `tool/result` 的自包含错误一致——一个事件即可区分成功与失败,无需关联兄弟事件。 - **教导核心轮次修复识别 `compact/*`**——否决:仅日志的孤儿是惰性的,为每个未来的 `xxx/start … xxx/end` 插件对修补核心模块恰好是能力 seam 架构存在的意义所要避免的耦合。 ## 后果 -- **新包**:`packages/compact/compact`(接口)和同级的 `compact-basic`(后端),位于 `packages/compact/` 下,接入根 tsconfig。消费方层推迟。 -- **新循环 seam**:`agent/pre-step`(`@mode serial`),在 `dsh-agent` 中声明,由 `dsh-agent-loop` 在系统组装之后、`step/start` 之前触发。这是对循环的文档化变更——`docs/architecture.md` 记录了它,生成的 cordis catalog 携带其签名。 +- **包**:`packages/compact/compact` 提供接口,`compact-basic` 提供后端,`compact-tool-result-prune` 提供可选的确定性重写。`packages/llm/token-meter` 独立拥有回放感知的测量。消费方层推迟。 +- **自动 seam**:`agent/post-step`(`@mode serial`)处理成功调用的压力,`agent/request-error`(`@mode waterfall`)处理失败步骤关闭后的最终请求失败。通用 `agent/pre-step` 保持为四参数检查点,不携带压缩专属的提示词/前缀 payload。 - **`SessionEventMap`** 通过声明合并(merge-extensible)获得 `compact/start` / `compact/summary` / `compact/end`;`SurfaceEventType` **未被**触及。这些是会话事件,不是 cordis `Events`,因此事件分类门禁无需新增条目。 -- **`dsh-session`** 获得工具配对平衡谓词(`isToolPairingBalanced`,位于 `tool-pairing.ts`,从包索引导出),`compactRegion`/`compactIfNeeded` 用它确保折叠区域不会拆分步骤的工具调用/结果对。surface 的 `replace` 操作和 surface 元数据运行时守卫已经存在并被复用。 -- **`dsh-invariants`** 移除其 `surface replace: start must be <= end` 断言:头部锚定的压缩将高序号替换节点放在较旧范围的*位置*上,因此 `start > end` 在数值上是正常且有效的(范围是位置性的,由 surface 的 `indexOf` 检查验证,这些检查保持不变)。轮次封闭不变式原样复用。 -- **接线**:`dsh-compact-basic` 在 `examples/coding-agent` 的 `cordis.yml` 中加载,使 seam 在真实演示中生效(此前它未被任何地方加载)。 +- **`dsh-compact`** 拥有 `toolPairingBalancedBefore(session, seq)` 与 `toolPairingBalancedAfter(session, seq)`;这些带缓存的 surface 边缘检查由 `compactRegion` 和 `compactIfNeeded` 用来避免拆分工具调用/结果对。缓存按 seq 校验当前成员关系,并从每个切割点的一条平衡序列回答两侧边缘;陈旧或缺失的 seq 以及孤立结果都会被拒绝。 +- **`dsh-session`** 通过唯一的 surface 管理器校验位置替换、完整溯源信息和仅内容的单节点 `tool/result` 重写。其不变式配套插件将新追加的工具结果视为执行,要求存在已打开的步骤与待处理调用;已校验的替换仍是位于轮次内的重写。 +- **接线**:`examples/tui-agent/cordis.yml` 依次加载零配置的 `dsh-token-meter`、`dsh-compact-tool-result-prune` 和 `dsh-compact-basic`;服务级默认值使组合无需重复数值策略即可使用。 ## 测试 -- **单元测试:** 使用真实 Loader 和 invariant 插件覆盖完整单元保留、收敛失败、`compact/end` 的两种结果、头部锚定、开放尾部拒绝、惰性崩溃孤儿,以及在一个超大开放轮次内压缩已关闭步骤。 -- **循环测试:** 测试固定每步在 `turn/start` 与 `step/start` 之间有一次 awaited 的 `agent/pre-step`;在该处的 surface 变更落在步骤之外,并出现在单次派生的请求中。 +- **单元测试:** 使用真实 Loader 和 invariant 插件覆盖完整单元保留、修剪配置与回放、富块顺序、元数据保留、收敛、`compact/end` 的两种结果、开放尾部拒绝、仅修剪与带摘要的溢出恢复、generation 证明、上限和原始错误保留。 +- **循环测试:** 测试固定步骤后处理发生在持久工具结果之后、`step/end` 之前,使用实际 `agent/request` 路由,关闭失败步骤,分配新的重试编号,并覆盖完整的抛出/带内溢出 → 压缩 → 重建重试组合。 - **带密钥 e2e:** 真实模型和 bash 会话在降低的限制下触发压缩,记录完整的 `compact/start…end` 对,缩小 surface,并完成任务。 - **快照缺口:** 失控轮次压缩尚无法回放,因为摘要调用未记录 `assistant/chunk` 事件或 `sessionId`;交错摘要调用的回放仍是后续工作。 diff --git a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml index 20172e4369..35b3e3032b 100644 --- a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.i18n.yaml @@ -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 -2026-06-21-subagent-capability-seam.md: ff8ca7d6292055715d94b3878860bffafb8a8057 -2026-06-21-subagent-capability-seam.zh.md: c11623531c753cd454621f450f33cff5edbbf815 +2026-06-21-subagent-capability-seam.md: 9c17a93751de209e5e4e5a0ca7d7b1d8e5656a47 +2026-06-21-subagent-capability-seam.zh.md: 9cab992e86120dd32cedea05b63c777b8678d409 diff --git a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md index 3ed2090b22..9c17a93751 100644 --- a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md +++ b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-21-subagent-capability-seam.zh.md) + > The full seam is shipped: the `dsh-subagent` interface and `dsh-tool-subagent` consumer; the two in-process backends (`dsh-subagent-spawn`, `dsh-subagent-fork`); the nested-agent snapshot infrastructure ([per-session snapshot replay](../testing/2026-06-22-subagent-snapshot-replay.md)); and the out-of-process `dsh-subagent-acp` backend ([its Agent Note](2026-06-22-acp-subagent-backend.md)). ## Problem diff --git a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md index c11623531c..9cab992e86 100644 --- a/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md +++ b/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md @@ -1,18 +1,18 @@ -# RFC: Subagent 能力 seam +# Agent Note: Subagent 能力 seam Status: implemented [English](2026-06-21-subagent-capability-seam.md) | 中文 -> 完整 seam 已交付:`dsh-subagent` 接口、`dsh-subagent-mock` 测试后端与 `dsh-tool-subagent` 消费方;两个进程内后端(`dsh-subagent-spawn`、`dsh-subagent-fork`);嵌套 agent 快照基础设施([逐会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md));以及进程外后端 `dsh-subagent-acp`([其 RFC](2026-06-22-acp-subagent-backend.md))。 +> 完整 seam 已交付:`dsh-subagent` 接口与 `dsh-tool-subagent` 消费方;两个进程内后端(`dsh-subagent-spawn`、`dsh-subagent-fork`);嵌套 agent 快照基础设施([逐会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md));以及进程外后端 `dsh-subagent-acp`([其 Agent Note](2026-06-22-acp-subagent-backend.md))。 ## 问题 -harness 有一个长期搁置的 seam 用于 **subagent**:一个 agent(智能体)将工作委派给另一个 agent。这一意图在 `Agent`/`AgentLoop` 接口中已有草案([packages/core/agent/src/types.ts](../../../../packages/core/agent/src/types.ts)、[packages/core/agent-loop/src/index.ts](../../../../packages/core/agent-loop/src/index.ts)):一个创建选项引用父 agent(fork = 用父会话的事件日志初始化子会话;spawn = 全新会话),子 agent 以 `Agent` 句柄返回,使 steering(中途引导)和事件订阅可以统一工作。本 RFC 实现了这个 seam;上方横幅列出了已交付的内容。 +harness 有一个长期搁置的 seam 用于 **subagent**:一个 agent(智能体)将工作委派给另一个 agent。这一意图在 `Agent`/`AgentLoop` 接口中已有草案([packages/core/agent/src/types.ts](../../../../packages/core/agent/src/types.ts)、[packages/core/agent-loop/src/index.ts](../../../../packages/core/agent-loop/src/index.ts)):一个创建选项引用父 agent(fork = 用父会话的事件日志初始化子会话;spawn = 全新会话),子 agent 以 `Agent` 句柄返回,使 steering(中途引导)和事件订阅可以统一工作。本 Agent Note 实现了这个 seam;上方横幅列出了已交付的内容。 决定整体设计走向的核心需求是:**多种 subagent 实现必须在运行时共存**。一个父 agent 可能在同一个会话中既需要一个廉价的进程内子 agent 处理有限范围的子任务,又需要一个隔离的进程外子 agent(通过 ACP(Agent Client Protocol))。我们预见的传输方式: -- **进程内**:在同一个 `Context` 上创建子 `ReactLoopAgent`(最廉价,且鉴于现有 agent 工厂几乎零成本); +- **进程内**:在同一个 `Context` 上创建一个具体的子 `Agent`(最廉价,且鉴于现有 agent 工厂几乎零成本); - **ACP**:作为 ACP *客户端*驱动另一个 agent 进程(可以是自身的另一个实例); - 后续:**A2A**、**Codex app-server** 与 **Claude Code Agent SDK**——每种都与 ACP 后端相同的进程外形状:「启动子 agent、发送提示词、流式接收更新、取消」。 @@ -20,7 +20,7 @@ harness 有一个长期搁置的 seam 用于 **subagent**:一个 agent(智 ### 为何不采用 bash seam 的形状 -bash seam([能力 seam](../../implemented/architecture/2026-06-13-capability-seams.md))在每个 context 中只注册恰好一个 `BashExecutor`;加载第二个会抛异常。这对 bash 是正确的(一台机器、一种执行命令的方式),但对这里是错误的:共存才是需求。因此 subagent 服务是一个**命名提供方注册表**——每个实现以唯一名称注册,调用方按名称选择——镜像 **LLM(大语言模型)适配器注册表**(`LlmService.registerAdapter`),而非单服务的 bash 执行器。seam 仍然是由三个包构成的结构(接口 / 实现 / 消费方);只是「一个 vs. 多个实现」这个维度不同。 +bash seam([能力 seam](../architecture/2026-06-13-capability-seams.md))在每个 context 中只注册恰好一个 `BashExecutor`;加载第二个会抛异常。这对 bash 是正确的(一台机器、一种执行命令的方式),但对这里是错误的:共存才是需求。因此 subagent 服务是一个**命名提供方注册表**——每个实现以唯一名称注册,调用方按名称选择——镜像 **LLM(大语言模型)适配器注册表**(`LlmService.registerAdapter`),而非单服务的 bash 执行器。seam 仍然是由三个包构成的结构(接口 / 实现 / 消费方);只是「一个 vs. 多个实现」这个维度不同。 ## 决策 @@ -34,7 +34,6 @@ bash seam([能力 seam](../../implemented/architecture/2026-06-13-capability-s | `@deepseek-ai/dsh-subagent-spawn` | 实现:通过 `ctx.agents.create` 创建全新的进程内子 agent | | `@deepseek-ai/dsh-subagent-fork` | 实现:用父 agent 日志快照初始化的进程内子 agent | | `@deepseek-ai/dsh-subagent-acp` | 实现:作为 ACP 客户端驱动已配置的子进程 | -| `@deepseek-ai/dsh-subagent-mock` | 辅助:用于通过真实加载路径测试 seam 的脚本化提供方 | | `@deepseek-ai/dsh-tool-subagent` | 消费方:基于 `ctx.subagents` 的面向模型的 `subagent` 工具 | ### 原语:异步 `start → SubagentRun` @@ -64,11 +63,11 @@ bash seam([能力 seam](../../implemented/architecture/2026-06-13-capability-s ## 测试 -seam 通过真实的 Cordis Loader/export 路径测试,这能捕获[事后分析 0001](../../../postmortem/0001-acp-default-export-drops-inject.md) 中描述的 export 形状错误。注册表测试覆盖重载安全性、重名和启动时能力拒绝;嵌套 agent 场景通过[逐会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md)进行无密钥回放;进程内后端还有真实循环的单元测试和带密钥的 e2e 测试。 +注册表与工具测试仅用包内脚本化提供方替换非确定性的子进程边界,同时运行真实的 `SubagentService`、生命周期、任务集成和面向模型的工具。提供方与消费方的 export 形状仍保留 Loader 回归覆盖,以防止[事后分析 0001](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md) 中描述的失败。注册表测试覆盖重载安全性、重名和启动时能力拒绝;嵌套 agent 场景通过[逐会话快照回放](../testing/2026-06-22-subagent-snapshot-replay.md)进行无密钥回放;进程内后端还有真实循环的单元测试和带密钥的 e2e 测试。 ## 后果 -- **递归。** 如果不设限制,进程内子 agent 能看到委派工具并递归调用。进程内后端实现了可选的绝对深度限制和有作用域的实时全局 `toolFilter`;ACP 声明这两项能力为关闭状态,并拒绝此类请求。[subagent 组合控制 RFC](2026-07-12-subagent-persona-tool-filter-and-depth.md) 负责定义它们的确切语义和安全边界。 -- **阻塞父轮次。** 同步收集在子 agent 的整个持续时间内保持父 agent 的 `runStep` 打开。这对首版是可接受的;**后台 / 轮询 / 溢出语义推迟到未来的重新设计,该设计将统一 subagent 和 bash 的长时间运行工具处理**(一个 subagent 和一个长时间运行的 `bash` 后台任务面临相同的问题——「模型启动了一个慢操作,之后如何收集结果」——应共享一套机制,而非各自发明)。 +- **递归。** 如果不设限制,进程内子 agent 能看到委派工具并递归调用。进程内后端实现了可选的绝对深度限制和有作用域的实时全局 `toolFilter`;ACP 声明这两项能力为关闭状态,并拒绝此类请求。[subagent 组合控制 Agent Note](2026-07-12-subagent-persona-tool-filter-and-depth.md) 负责定义它们的确切语义和安全边界。 +- **阻塞父轮次。** 前台收集在子 agent 的整个持续时间内保持父 agent 的步骤打开。后台委派使用共享的 `ctx.tasks` 运行时与通用 `task_*` 工具,与后台 bash 共用同一套收集机制;subagent seam 本身仍不感知任务。 - **实时进度。** 本版仅暴露生命周期事件与最终结果;逐分片的子→父更新流推迟到后台重新设计时一并处理。 - **ACP 客户端接口。** 将 ACP 子 agent 的 `fs`/`terminal` 代理回父 agent(共享工作区模式)是后续工作;首版不声明这两项能力,子 agent 在自己的进程中自行服务。 diff --git a/.agents/notes/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml b/.agents/notes/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml index 99c3a2b5e9..6132be4521 100644 --- a/.agents/notes/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-22-acp-subagent-backend.i18n.yaml @@ -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 -2026-06-22-acp-subagent-backend.md: c02b027177ae96d75ff0d3dcac227145fe71b340 -2026-06-22-acp-subagent-backend.zh.md: 2b4db4e20fd872d21ffb72b1c2a4432c6f0103a9 +2026-06-22-acp-subagent-backend.md: a45ce5e34873249969bbe4dabb87a89d10246b3d +2026-06-22-acp-subagent-backend.zh.md: f313c11b22dc6aae6d1d1e72fce2381a572ded8d diff --git a/.agents/notes/implemented/feature/2026-06-22-acp-subagent-backend.zh.md b/.agents/notes/implemented/feature/2026-06-22-acp-subagent-backend.zh.md index 2b4db4e20f..f313c11b22 100644 --- a/.agents/notes/implemented/feature/2026-06-22-acp-subagent-backend.zh.md +++ b/.agents/notes/implemented/feature/2026-06-22-acp-subagent-backend.zh.md @@ -1,4 +1,4 @@ -# RFC: ACP subagent 后端(进程外委派) +# Agent Note: ACP subagent 后端(进程外委派) Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -subagent seam([seam RFC](2026-06-21-subagent-capability-seam.md))的设计使多个后端可以按名称共存于 `ctx.subagents`。进程内后端(`-spawn`/`-fork`)将子 agent(智能体)作为第二个 `Agent` 运行在同一个 Cordis 上下文上:开销低,但子 agent 与父 agent 共享进程、模型客户端和工具。seam 的核心意义在于同时支持通过协议到达的进程外子 agent,以证明该抽象能跨越进程边界泛化。本 RFC 添加第一个此类后端:一个 ACP(Agent Client Protocol)客户端。 +subagent seam([seam Agent Note](2026-06-21-subagent-capability-seam.md))的设计使多个后端可以按名称共存于 `ctx.subagents`。进程内后端(`-spawn`/`-fork`)将子 agent(智能体)作为第二个 `Agent` 运行在同一个 Cordis 上下文上:开销低,但子 agent 与父 agent 共享进程、模型客户端和工具。seam 的核心意义在于同时支持通过协议到达的进程外子 agent,以证明该抽象能跨越进程边界泛化。本 Agent Note 添加第一个此类后端:一个 ACP(Agent Client Protocol)客户端。 ## 决策 @@ -18,11 +18,15 @@ subagent seam([seam RFC](2026-06-21-subagent-capability-seam.md))的设计 ### 最小化客户端桩 -客户端不声明任何可选能力(无 `fs`、无 `terminal`):子 agent 在自己的进程中自行处理文件/终端访问。`session/update` 通知被消费:后端将 `agent_message_chunk` 文本累积为结果输出,在本阶段忽略其余内容(思考、工具调用卡片),仅暴露子 agent 的最终回答。`session/request_permission` 由配置的策略自动应答(`reject` 拒绝所有提示,`allow` 通过第一个允许形态的选项批准)——本阶段不向人类暴露任何权限提示。将 `fs`/`terminal` 代理回父进程(共享工作区模式)仍为后续工作,如 seam RFC 所述。 +客户端不声明任何可选能力(无 `fs`、无 `terminal`):子 agent 在自己的进程中自行处理文件/终端访问。`session/update` 通知被消费:后端将 `agent_message_chunk` 文本累积为结果输出,在本阶段忽略其余内容(思考、工具调用卡片),仅暴露子 agent 的最终回答。`session/request_permission` 由配置的策略自动应答(`reject` 拒绝所有提示,`allow` 通过第一个允许形态的选项批准)——本阶段不向人类暴露任何权限提示。将 `fs`/`terminal` 代理回父进程(共享工作区模式)仍为后续工作,如 seam Agent Note 所述。 ### 无启动时能力 -提供方的 `capabilities` 全部为 `false`。进程外子 agent 无法遵守父 agent 的 `maxDepth`(它无权访问 `parent.options.subagentDepth`)或 `toolFilter`(它拥有自己的工具注册表),本阶段也未实现 `outputSchema`。如果请求需要其中任何一项,服务在 `start` 运行前即拒绝。后端仅注入 `subagents`(而非 `ctx.agents`),并忽略 `request.parent`。 +提供方的 `capabilities` 全部为 `false`。进程外子 agent 无法遵守父 agent 的 `maxDepth`(它无权访问 `parent.options.subagentDepth`)或 `toolFilter`(它拥有自己的工具注册表),本阶段也未实现 `outputSchema`。如果请求需要其中任何一项,服务在 `start` 运行前即拒绝。后端仅注入 `subagents`(而非 `ctx.agents`);它从 `request.parent` 读取的唯一内容是会话 header 的 cwd(见下方工作区解析)——对话上下文、深度和工具状态都不会跨越进程边界。 + +### 工作区 cwd 解析 + +子进程工作目录来自显式解析,绝不使用 harness 进程的 cwd:若已配置部署 `cwd` 覆盖,则相对于启动目录将其转为绝对路径并在加载时验证;否则使用父会话 header 的 cwd 并在启动时验证;如果两者都不存在,则在生成任何进程前大声拒绝。一个 ACP 服务端进程会服务来自多个工作区的会话,因此 `process.cwd()` 不能代替会话工作区——旧的隐式回退会让子进程在服务端启动目录中运行。候选路径必须是 harness 可以进入的绝对目录(要求 `X_OK`;仅 `statSync().isDirectory()` 会接受 mode-600 的目录,而 spawn 会因 EACCES 失败);解析出的同一路径同时用作子进程 cwd 与 ACP `session/new` 工作区。 ### StopReason 映射 @@ -35,6 +39,7 @@ ACP `StopReason` → harness `SubagentStopReason`:`end_turn`→`completed`、` ## 测试 - **无需密钥的单元/集成测试:** 一个脚本化的 ACP 子进程通过真实 stdio 测试 prompt/output 流、所有 stop-reason 映射、信号与 dispose 取消(包括 pre-abort、pre-session 竞态和管道断裂场景)、两种权限策略、被忽略的非消息更新、命令缺失时的清理、提供方重载以及命名空间导出。 +- **无需密钥的 Loader 组合测试:** 仅用于测试的 cordis.yml 通过真实 Loader 启动 stdio 应用,并省略后端的 `cwd`;脚本化模型委派一次,脚本化子进程则证明它在父会话工作区中运行,且 ACP 也对外公布了该工作区,从而端到端覆盖 cwd 继承分支。 - **需要密钥的 e2e 测试:** 后端 spawn 真实的 ACP 示例;其模型回答 `PONG`,写入 `proof.txt`,父进程验证该文件。 - **快照缺口:** 每个 ACP 子 agent 是独立进程,拥有自己的回放会话,不同于进程内的按会话回放。确定性 mock 服务器覆盖率已具备;`TODO(acp-subagent-replay)` 跟踪父进程对回放中子 agent 的回放支持。 @@ -54,4 +59,4 @@ ACP `StopReason` → harness `SubagentStopReason`:`end_turn`→`completed`、` ## 后续提供方 -同样的进程外 spawn/prompt/stream/cancel 形态可泛化到 seam RFC 中列出的其他传输方式——A2A、Codex app-server 和 Claude Code Agent SDK——每个都是按名称注册的兄弟提供方。ACP 后端证明了 seam 支持跨进程边界;其余在机制上类似。 +同样的进程外 spawn/prompt/stream/cancel 形态可泛化到 seam Agent Note 中列出的其他传输方式——A2A、Codex app-server 和 Claude Code Agent SDK——每个都是按名称注册的兄弟提供方。ACP 后端证明了 seam 支持跨进程边界;其余在机制上类似。 diff --git a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.i18n.yaml b/.agents/notes/implemented/feature/2026-06-25-ask-user-question.i18n.yaml index 1feca9e724..4495d29887 100644 --- a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-25-ask-user-question.i18n.yaml @@ -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 -2026-06-25-ask-user-question.md: e28d34e7b13eb8920db1eb77f4cc66aec58c3525 -2026-06-25-ask-user-question.zh.md: 86194b4eeca2761b0af412f1510a688ef48b0422 +2026-06-25-ask-user-question.md: 97bb6c29c7c0677a9c0c2c9fe3007dd28e31adee +2026-06-25-ask-user-question.zh.md: 1ed916e39b3460d32e7e308c8ac89b8e09b763ac diff --git a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.zh.md b/.agents/notes/implemented/feature/2026-06-25-ask-user-question.zh.md index 86194b4eec..1ed916e39b 100644 --- a/.agents/notes/implemented/feature/2026-06-25-ask-user-question.zh.md +++ b/.agents/notes/implemented/feature/2026-06-25-ask-user-question.zh.md @@ -1,4 +1,4 @@ -# RFC: ask-user 提问能力 +# Agent Note: ask-user 提问能力 Status: implemented @@ -22,9 +22,9 @@ Provider 返回 `{ answers: [{ id, selected, custom? }] }`。`selected` 始终 ## UI 映射 -`dsh-stdio-demo` 的包内 readline 模块渲染每个问题,在下一行显示每个选项的 `description`,支持以逗号/空格分隔的数字选择 `multi_select`,接受自由格式的自定义答案,并在中止、provider dispose(资源释放)或 stdin EOF 时拒绝待处理的问题。批量请求按顺序询问,作为一个答案对象整体解析。stdio provider 通过内部队列序列化并发请求,确保同一时刻只有一个提示占用 stdin。 +`dsh-tui` 将每个问题渲染为键盘叠层,展示选项描述,支持单选、多选和自由格式自定义答案,并在中止、provider dispose(资源释放)或终端关闭时拒绝待处理的问题。批量请求和并发请求都会排队,确保同一时刻只有一个叠层占用键盘焦点。 -`dsh-acp` 为 ACP 会话提供同一 seam。它通过 bridge 的 `agent→sessionId` 反向映射将调用方 `Agent` 的 ask 请求路由出去,并为每个问题调用 ACP `unstable_createElicitation`(附带会话范围的表单)。单选选项变为 `choice` 字符串枚举;`multi_select` 选项变为 `choice` 数组枚举;无选项的问题使用必填的 `custom` 文本字段。如果客户端同时返回 `choice` 和非空 `custom`,以 custom 答案为准。ACP `decline`/`cancel`、缺失答案、缺失会话以及客户端不支持 elicitation,都会转为结构化的 `UserInteractionError`。 +`dsh-acp` 为 ACP 会话提供同一 seam。它通过 `ownedRecord` 解析调用方 `Agent`,要求位于 `agent.session.id` 的正向会话 map 记录拥有该精确 agent 对象,并为每个问题调用 ACP `unstable_createElicitation`(附带会话范围的表单)。单选选项变为 `choice` 字符串枚举;`multi_select` 选项变为 `choice` 数组枚举;无选项的问题使用必填的 `custom` 文本字段。如果客户端同时返回 `choice` 和非空 `custom`,以 custom 答案为准。ACP `decline`/`cancel`、缺失答案、缺失会话以及客户端不支持 elicitation,都会转为结构化的 `UserInteractionError`。 ACP 映射有意使用 elicitation 而非 `session/request_permission`。`request_permission` 仍保留给独立的权限门禁:它是围绕工具执行的 yes/no 或策略式授权协议。`ask_user_question` 是一个通用的信息收集工具,支持可选的自由格式答案,因此 ACP 表单 elicitation 是更贴合的协议。bridge 的会话路由与未来的权限门禁共享,但用户意图不同。 @@ -44,8 +44,8 @@ ACP elicitation 目前在 SDK 中标记为 unstable。回退仍然是结构化 该功能赋予模型一个强大的暂停原语,因此 prompt 引导很重要。工具描述告诉模型:提问要简洁,尽可能使用选项。产品策略后续可以包装 `tools/execute` 来限制工具何时可用,但循环不应对其做特殊处理。 -`dsh-user-interaction` 和 `dsh-tool-ask-user` 都位于 `packages/ui`,因为它们共同构成一个面向产品的人机交互能力。`agent-core` 不加载工具或 provider。`stdio-agent` 选择性加载 seam、其 readline provider 和面向模型的工具。`acp-agent` 默认只保留 `userInteraction` seam/provider:ACP elicitation 支持仍取决于客户端,因此 ACP 叶节点必须在其客户端能完成 elicitation 请求后才有意加载面向模型的工具。 +`dsh-user-interaction` 和 `dsh-tool-ask-user` 都位于 `packages/ui`,因为它们共同构成一个面向产品的人机交互能力。`agent-core` 不加载工具或 provider。`dsh-tui-demo` 选择性加载 seam、TUI provider 和面向模型的工具。`acp-agent` 默认只保留 `userInteraction` seam/provider:ACP elicitation 支持仍取决于客户端,因此 ACP 叶节点必须在其客户端能完成 elicitation 请求后才有意加载面向模型的工具。 ## 测试 -单元覆盖率固定了以下场景:provider 注册/释放、重复 provider 拒绝、provider 就绪前中止、空问题拒绝、通过 `ctx.tools.execute()` 传出的结构化工具错误、批量答案、多选答案、自定义答案,以及模型 schema(包括移除 `value`、`recommended`、`allow_custom` 和 `desc`)。`dsh-stdio-demo` 测试覆盖选项描述、排队请求、EOF/中止清理、无选项自由格式输入、无效选项重新提示、重复多选编号和批量问题流。ACP bridge 测试驱动一个真实的内存 ACP 连接(使用真实的 `ask_user_question` 工具),验证选中选项、custom 覆盖 choice、多选和无选项自由格式 elicitation 路径能继续 agent loop。 +单元覆盖率固定了以下场景:provider 注册/释放、重复 provider 拒绝、provider 就绪前中止、空问题拒绝、通过 `ctx.tools.execute()` 传出的结构化工具错误、批量答案、多选答案、自定义答案,以及模型 schema(包括移除 `value`、`recommended`、`allow_custom` 和 `desc`)。TUI 测试覆盖选项描述、排队请求、关闭/中止清理、无选项自由格式输入、无效选择、重复多选和批量问题流。ACP bridge 测试驱动一个真实的内存 ACP 连接(使用真实的 `ask_user_question` 工具),验证选中选项、custom 覆盖 choice、多选和无选项自由格式 elicitation 路径能继续 agent loop。 diff --git a/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml b/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml index cacdff7448..b44e8db0db 100644 --- a/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml @@ -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 -2026-06-29-todo-write-tool.md: 7147440ec0cdb0b53093c371828d1987c17aabb0 -2026-06-29-todo-write-tool.zh.md: 7602ac8434963c84f089fe99a6f1e973c05e5bef +2026-06-29-todo-write-tool.md: bf5fceaafd475224914212beb460fdbc42e3dd68 +2026-06-29-todo-write-tool.zh.md: 565db37b1bf36c2aa33109870df4b36a82a57bdc diff --git a/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.zh.md b/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.zh.md index 7602ac8434..565db37b1b 100644 --- a/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.zh.md +++ b/.agents/notes/implemented/feature/2026-06-29-todo-write-tool.zh.md @@ -1,4 +1,4 @@ -# RFC: `todo_write` 工具——将模型任务列表作为事件溯源的会话状态 +# Agent Note: `todo_write` 工具——将模型任务列表作为事件溯源的会话状态 Status: implemented @@ -22,7 +22,7 @@ harness 为模型提供了 bash 和 subagent 工具,却没有办法记录结 ### 不是 surface 事件 -`todo/write` 被有意排除在 `SurfaceEventType` 之外。surface 是产出 LLM 消息历史(`deriveMessages()`)的投影;todo write 不产生对话消息。因此它不携带 `surfaceOp`,不加入 surface 链表,不进入 `deriveMessages()`——它是持久、可回放的 *UI* 状态,与对话并行传输但不属于对话的一部分。(dev-mode 不变式仍要求它位于一个打开的轮次内,而它始终如此:它在工具调用的步骤中途追加。) +`todo/write` 被有意排除在 `SurfaceEventType` 之外。surface 是产出 LLM 消息历史(`deriveMessages()`)的投影;todo write 不产生对话消息。因此它不携带 `surfaceOp`,不加入有序 surface,不进入 `deriveMessages()`——它是持久、可回放的 *UI* 状态,与对话并行传输但不属于对话的一部分。(dev-mode 不变式仍要求它位于一个打开的轮次内,而它始终如此:它在工具调用的步骤中途追加。) ### Priority 仅在 ACP 边界合成 @@ -51,7 +51,7 @@ schema 强制 type/required/enum。在此之上,`execute` 拒绝为空或重 - **真实 Loader 路径**——插件通过 `Loader.unwrapExports` 运行,断言命名空间导出形状存活(它有 `inject`,因此一个意外的 default 导出会在加载时崩溃——postmortem/0001)。 - **全循环集成**——一个脚本化的 mock 模型通过真实 agent loop(智能体循环)调用 `todo_write`;`todo/write` 事件落地,第二次调用替换它。 - **`session/load` 回放**——持久化的 `todo/write` 在新的 ACP bridge 加载会话时重新发出 `plan` 更新。 -- **带密钥 e2e + 快照**——真实 prompt 诱导一次 `todo_write`;快照 golden 获得 `plan` 通知和日志事件。 +- **带密钥 e2e + 快照**——真实 prompt 诱导一次 `todo_write`;快照预期输出获得 `plan` 通知和日志事件。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/feature/2026-06-30-hook-bridges.i18n.yaml b/.agents/notes/implemented/feature/2026-06-30-hook-bridges.i18n.yaml index fe4a29a063..02ea526412 100644 --- a/.agents/notes/implemented/feature/2026-06-30-hook-bridges.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-30-hook-bridges.i18n.yaml @@ -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 -2026-06-30-hook-bridges.md: c3b268bb4062c3e31acc6cdfc7641b0d1a24c47a -2026-06-30-hook-bridges.zh.md: 57ccfae2f75858254352838049516aca3668d083 +2026-06-30-hook-bridges.md: b6b0894e5551563187b1631e8c641e326fa166b0 +2026-06-30-hook-bridges.zh.md: 9b4ebfc0afaeed6e599f587d32ad2d2af43b6b68 diff --git a/.agents/notes/implemented/feature/2026-06-30-hook-bridges.zh.md b/.agents/notes/implemented/feature/2026-06-30-hook-bridges.zh.md index 57ccfae2f7..9b4ebfc0af 100644 --- a/.agents/notes/implemented/feature/2026-06-30-hook-bridges.zh.md +++ b/.agents/notes/implemented/feature/2026-06-30-hook-bridges.zh.md @@ -1,4 +1,4 @@ -# RFC: dsh-hooks-claude + dsh-hooks-codex —— Claude Code / Codex 钩子桥接插件 +# Agent Note: dsh-hooks-claude + dsh-hooks-codex —— Claude Code / Codex 钩子桥接插件 Status: implemented @@ -6,16 +6,16 @@ Status: implemented ## 问题 -harness 的扩展面是其类型化的拦截 seam(见[拦截 seam RFC](2026-06-30-interception-seams.md)):所谓「原生钩子」不过是一个普通的 Cordis 插件,订阅 `agent/session-start`、`agent/prompt-submit`、`tools/pre-execute`、`tools/post-execute`、`agent/turn-continuation`、`subagent/start`、`subagent/end`。但用户带着**既有的** Claude Code(CC)和 Codex 钩子配置到来,一个 `hooks.json`(或 settings 文件中的 `hooks` 键)里满是 shell 命令钩子,并希望它们原样运行。本 RFC 引入两个**桥接插件**,将外部 shell 钩子协议翻译到类型化 seam 上,构建于共享的协议格式(wire format)库之上(见 [hook-protocol-lib RFC](2026-06-30-hook-protocol-lib.md))。 +harness 的扩展面是其类型化的拦截 seam(见[拦截 seam Agent Note](2026-06-30-interception-seams.md)):所谓「原生钩子」不过是一个普通的 Cordis 插件,订阅 `agent/session-start`、`agent/prompt-submit`、`tools/pre-execute`、`tools/post-execute`、`agent/turn-continuation`、`subagent/start`、`subagent/end`。但用户带着**既有的** Claude Code(CC)和 Codex 钩子配置到来,一个 `hooks.json`(或 settings 文件中的 `hooks` 键)里满是 shell 命令钩子,并希望它们原样运行。本 Agent Note 引入两个**桥接插件**,将外部 shell 钩子协议翻译到类型化 seam 上,构建于共享的协议格式(wire format)库之上(见 [hook-protocol-lib Agent Note](2026-06-30-hook-protocol-lib.md))。 贯穿整个设计的定位:**桥接是兼容性适配器,不是高级工具。** 桥接能做的事(阻止工具、注入上下文、强制继续、观察 subagent),原生 Cordis 插件都能做得更强——类型化返回值、完整 `ctx`、无序列化边界。桥接存在的理由是运行外部 CC/Codex 命令钩子中被明确支持的子集。这使每个桥接保持精简:解析配置、选择匹配模式、构建每事件的 payload、调用共享库的 `runHook` + `mergeHookOutputs`,再将中性结果映射为 seam Decision。各 package 的 README 维护着当前不支持的事件和部分字段的完整清单,以官方协议为参照。 ## 决策 -`packages/hooks/` 组下两个独立插件,各为 function/namespace 插件(`name`/`inject`/`Config`/`apply`,无 default export——见 [postmortem 0001](../../../postmortem/0001-acp-default-export-drops-inject.md)),仅注入 `bash`: +`packages/hooks/` 组下两个独立插件,各为 function/namespace 插件(`name`/`inject`/`Config`/`apply`,无 default export——见 [postmortem 0001](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md)),仅注入 `bash`: -- **`dsh-hooks-claude`**——CC 方言。Claude Code 当前七个钩子点中的七个:`SessionStart`、`UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`Stop`、`SubagentStart` 和 `SubagentStop`。拥有 CC 形态的每事件 stdin payload(基础字段 `session_id`/`cwd`/`hook_event_name` 加每事件字段)、`CLAUDE_PROJECT_DIR` 环境变量加 `${CLAUDE_PLUGIN_ROOT}`/`${CLAUDE_PROJECT_DIR}` 替换,以及字面量或正则的匹配模式。CC 钩子的 stdin 带有**尾部换行**。 -- **`dsh-hooks-codex`**——Codex 当前五个钩子点中的五个:`PreToolUse`、`PostToolUse`、`SessionStart`、`UserPromptSubmit` 和 `Stop`。使用始终为正则的匹配模式、Codex 形态的 snake_case payload(含 `turn_id`/`model`/`permission_mode` 额外字段),写入时不带尾部换行,不注入 Codex 插件环境变量,不做配置时占位符替换,也没有 pre-tool 审批或重写路径。工具调用的 payload 在桥接精简后的 `tool_input: { command }` 形态中携带真实的 `tool_name`。 +- **`dsh-hooks-claude`**——CC 方言。Claude Code 当前七个钩子点中的七个:`SessionStart`、`UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`Stop`、`SubagentStart` 和 `SubagentStop`。拥有 CC 形态的每事件 stdin payload(基础字段 `session_id`/`transcript_path`/`cwd`/`hook_event_name` 加每事件字段)、`CLAUDE_PROJECT_DIR` 环境变量加 `${CLAUDE_PLUGIN_ROOT}`/`${CLAUDE_PROJECT_DIR}` 替换,以及字面量或正则的匹配模式。`transcript_path` 是持久化定位器结果或 `''`;stdin 带有**尾部换行**。 +- **`dsh-hooks-codex`**——Codex 当前五个钩子点中的五个:`PreToolUse`、`PostToolUse`、`SessionStart`、`UserPromptSubmit` 和 `Stop`。使用始终为正则的匹配模式、Codex 形态的 snake_case payload(含 `turn_id`/`model`/`permission_mode` 额外字段),写入时不带尾部换行,不注入 Codex 插件环境变量,不做配置时占位符替换,也没有 pre-tool 审批或重写路径。`transcript_path` 是同一定位器结果或 `null`;工具 payload 在精简后的 `tool_input: { command }` 形态中携带真实的 `tool_name`。 ### Outcome → Decision 映射 @@ -37,9 +37,9 @@ CC 桥接的 `ask` 结果是一条真正的权限路径,而非终态桥接决 `agent.inject()` 在缺少 `MessageSource` 时默认为 `{ kind: 'user' }`,因此每个桥接的 `inject()` 和 `HookContext` 都传入 `{ kind: 'plugin', plugin: 'hooks-claude' | 'hooks-codex' }`。单元测试覆盖率固定验证结果中的 `context/message.source` 为插件而非用户。 -### 添加上下文不是否决——先 delegate,再 fold +### 添加上下文不是否决——先 delegate,再 prepend -仅含上下文的钩子必须调用 `next()` 然后将其 `additionalContext` 折叠进下游决策;直接返回 allow 或 accept 会绕过后续策略监听器。Post-tool 的 block 和 accept 决策都保留已添加的上下文。Prompt allow 保留上下文,而 prompt block 丢弃上下文,因为提示词从未到达模型。只有显式的钩子 denial 或 block 才会短路 waterfall(瀑布式事件)。 +仅附加 `additionalContext`(没有 block/deny)的钩子并不是桥接可以独自返回的决策:在 waterfall 监听器中不调用 `next()` 就返回 `allow`/`accept`,会短路其后的每个 `agent/prompt-submit` / `tools/post-execute` 监听器,使注册在桥接之后的策略/沙箱插件看不到该提示词。因此,每个桥接都会先通过 `next()` 委托,再将自身上下文加入下游决策。两个 seam 都携带有序的 `additionalContexts` 数组,因此桥接会在保留所有下游来源、信封和元数据字段的同时,前置加入其独立来源的条目;下游 prompt block 仍会丢弃所有上下文,因为提示词从未到达模型,而 post-tool block 语义可以显式保留上下文。Code Mode 会通过外层 `run_code` 结果转送同一数组。只有钩子本身真正返回 `deny`/`block` 才会短路。测试断言:上下文钩子允许后,较晚的监听器仍能阻止提示词,且保留的 prompt 和 post-tool 上下文仍彼此分离。 ### CLAUDE_PROJECT_DIR 默认为会话工作区 @@ -55,7 +55,7 @@ Claude Code 始终导出 `CLAUDE_PROJECT_DIR`,常见的未修改钩子引用 ` ## 推迟的兼容性缺口 -- **工具输入重写。** CC/Codex 的 `updatedInput` 被记录日志并发出警告,但不予执行——输入重写是一个推迟的一致性设计问题(见 [pre-tool-input-rewrite RFC](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)),因为 pre-execution 参数被 `tool/call` 审计、`assistant/message` 历史和 ACP/tool-bash 展示共同读取,诚实的重写是一个设计单元,而非一个字段。 +- **工具输入重写。** CC/Codex 的 `updatedInput` 被记录日志并发出警告,但不予执行——输入重写是一个推迟的一致性设计问题(见 [pre-tool-input-rewrite Agent Note](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md)),因为 pre-execution 参数被 `tool/call` 审计、`assistant/message` 历史和 ACP/tool-bash 展示共同读取,诚实的重写是一个设计单元,而非一个字段。 - **Stop 循环防护**(`TODO(stop-loop-guard)`)。Claude Code 提供 `stop_hook_active` 并在连续八次阻塞后覆盖钩子;Codex 提供 `stop_hook_active` 但未记录等效上限。两个桥接始终报告 `false`,因此一个无条件阻塞的 Stop 钩子会在每一步强制继续——在状态追踪落地之前,钩子作者必须自行限制。 - **钩子 `continue:false`(硬停止)。** 钩子可以请求终止整个运行(CC/Codex `continue:false`);共享合并将其折叠为 `MergedHookOutcome.stop`/`stopReason`,但没有桥接对其采取行动(`TODO(hook-continue-false)`)——拦截 seam 尚无「硬停止 agent」原语(Decision 阻塞/引导的是单个点,而非整个运行)。与循环防护工作一同推迟;停止请求记录在 `hook/result` 日志中,钩子在此期间保留其逐点效果(决策/上下文)。 - **配置发现。** 路径在 `cordis.yml` 中显式指定且为进程级(见上文);完整的多层 CC/Codex 优先级遍历、按会话的项目本地发现以及信任/hash 模型未被重新实现(`TODO(per-session-hook-config)`)。 diff --git a/.agents/notes/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml b/.agents/notes/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml index f745911340..760767565d 100644 --- a/.agents/notes/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-30-hook-protocol-lib.i18n.yaml @@ -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 -2026-06-30-hook-protocol-lib.md: bd00c35ee2a1a1075ecae936af21508004f606b8 -2026-06-30-hook-protocol-lib.zh.md: 59b473e2a4e6f2dd95fa7bb7046848b036e5466a +2026-06-30-hook-protocol-lib.md: 19a69119befde99417b736edf38923ec6ac5fa7c +2026-06-30-hook-protocol-lib.zh.md: 48592b6c4af1bde9daf843692272e556a5d8b206 diff --git a/.agents/notes/implemented/feature/2026-06-30-hook-protocol-lib.zh.md b/.agents/notes/implemented/feature/2026-06-30-hook-protocol-lib.zh.md index 59b473e2a4..48592b6c4a 100644 --- a/.agents/notes/implemented/feature/2026-06-30-hook-protocol-lib.zh.md +++ b/.agents/notes/implemented/feature/2026-06-30-hook-protocol-lib.zh.md @@ -1,4 +1,4 @@ -# RFC: dsh-hook-protocol——Claude Code / Codex 钩子协议格式共享核心库 +# Agent Note: dsh-hook-protocol——Claude Code / Codex 钩子协议格式共享核心库 Status: implemented @@ -6,9 +6,9 @@ Status: implemented ## 问题 -hooks 子系统提供两个桥接插件:一个运行用户既有的 Claude Code(CC)钩子,另一个运行 Codex 钩子。研究参考实现(`~/repos/refs/claude-code`、`~/repos/refs/codex`)后发现一个决定性事实:**Codex 有意重新实现了 CC 钩子协议的一个子集。** 它的引擎读取相同的 `hooks.json`,使用相同的 matcher-group 形状、相同的 exit-code/structured-stdout 输出契约,以及相同的 command-hook 执行模型。Codex 的源码甚至以 Claude 的引擎命名,并在注释中标注了"有意偏离"之处。因此,如果不做抽取,两个桥接插件将大量重复协议逻辑。 +hooks 子系统提供两个桥接插件:一个运行用户既有的 Claude Code(CC)钩子,另一个运行 Codex 钩子。研究参考实现(`~/repos/refs/claude-code`、`~/repos/refs/codex`)后发现一个决定性事实:**Codex 有意重新实现了 CC 钩子协议的一个子集。** 它的引擎读取相同的 `hooks.json`,使用相同的 matcher-group 形状、相同的 exit-code/structured-stdout 输出契约,以及相同的 command-hook 执行模型。Codex 的源码甚至以 Claude 的引擎命名,并在注释中标注了「有意偏离」之处。因此,如果不做抽取,两个桥接插件将大量重复协议逻辑。 -本 RFC 引入 `@deepseek-ai/dsh-hook-protocol`,一个**库**(不是插件——它不注册也不注入任何东西),持有两个桥接插件共同依赖的真正相同的原语。共享与方言专属之间的分界是本设计的重心。 +本 Agent Note 引入 `@deepseek-ai/dsh-hook-protocol`,一个**库**(不是插件——它不注册也不注入任何东西),持有两个桥接插件共同依赖的真正相同的原语。共享与方言专属之间的分界是本设计的重心。 ## 决策 @@ -17,7 +17,7 @@ hooks 子系统提供两个桥接插件:一个运行用户既有的 Claude Cod **共享(本库):** - **Matcher** — `matchesMatcher(pattern, query, mode)`。两种方言唯一不同的轴被收敛为 `mode` 参数:`claude` 将纯 `[A-Za-z0-9_|]+` 模式视为字面量(管道符 = 精确匹配的多选),其余视为正则;`codex` 始终是无锚定正则。缺省/`''`/`'*'` 匹配一切;无效正则匹配空集(绝不向 agent loop(智能体循环)抛异常)。 - **Execution** — `runHook(bash, hook, options)`。通过 `ctx.bash` seam 而非自建 `spawn` 运行 command hook:执行器已提供清洗但可覆盖的 env、进程组 kill 和超时,正是协议所需的能力;`dsh-bash` 的 `stdin`/`env` 字段(正是为此添加的)是进程内桥接插件被允许使用的受信插件接口。它将桥接插件构建的 payload 序列化到 stdin(CC 时追加尾部换行),遵守钩子的 `timeoutSec`(否则使用 `DEFAULT_HOOK_TIMEOUT_MS`,即两种方言共享的 10 分钟参考默认值),且从不抛异常(执行器拒绝变为 non-blocking-error 的 `HookOutput`)。 -- **Decode** — `parseHookOutput(exit, stdout, stderr)`,exit-code + structured-stdout 编解码器,产出方言无关的 `HookOutput`。Exit `0` → 宽松 JSON 解析 stdout;exit `2` → blocking error,`stderr` 为原因(以 `decision: 'block'` 呈现,调用方无需单独处理 exit-code 分支);其他 → non-blocking error。解析 CC structured-stdout 中在某条路径上有消费方的字段(`continue`/`stopReason`/`decision`/`hookSpecificOutput.{permissionDecision,additionalContext,updatedInput}`/`systemMessage`);桥接插件只采纳对其方言有意义的子集。在任何路径上都没有消费方的字段不予解析(CC 的 `suppressOutput`——钩子 stdout 在此处从不进入 transcript(文本记录),因此无需抑制;见 [tighten-hook-protocol-contract RFC](../simplification/2026-07-04-tighten-hook-protocol-contract.md))。 +- **Decode** — `parseHookOutput(exit, stdout, stderr)`,exit-code + structured-stdout 编解码器,产出方言无关的 `HookOutput`。Exit `0` → 宽松 JSON 解析 stdout;exit `2` → blocking error,`stderr` 为原因(以 `decision: 'block'` 呈现,调用方无需单独处理 exit-code 分支);其他 → non-blocking error。解析 CC structured-stdout 中在某条路径上有消费方的字段(`continue`/`stopReason`/`decision`/`hookSpecificOutput.{permissionDecision,additionalContext,updatedInput}`/`systemMessage`);桥接插件只采纳对其方言有意义的子集。在任何路径上都没有消费方的字段不予解析(CC 的 `suppressOutput`——钩子 stdout 在此处从不进入 transcript(文本记录),因此无需抑制;见 [tighten-hook-protocol-contract Agent Note](../simplification/2026-07-04-tighten-hook-protocol-contract.md))。 - **Merge** — `mergeHookOutputs(outputs)`,将多个匹配钩子的输出折叠为一个最严格的 `MergedHookOutcome`:权限优先级 **deny > ask > allow**,halt 在首个 `continue:false` 时粘滞,block reason 以 `\n\n` 拼接,context/system-messages 按序累积。 - **`hook/*` 会话事件** — `hook/invoked` / `hook/result`,declaration-merge 进 `SessionEventMap`(仅日志,如 `compact/*`——不是 `SurfaceEventType`),配有 `appendHookInvoked`/`appendHookResult` 辅助函数,确保 invoked/result 配对与 turn 包含关系在各桥接插件间保持一致。`appendHookResult` 还拥有持久化记录的语义:decision 字符串(钩子解析出的 decision,否则 `continue:false` 时为 `'stop'`,否则为 `'pass'`)和 500 字符的 `stderrSummary` 截断均从本库的 `HookOutput` 派生,而非各桥接插件各自实现。 diff --git a/.agents/notes/implemented/feature/2026-06-30-interception-seams.i18n.yaml b/.agents/notes/implemented/feature/2026-06-30-interception-seams.i18n.yaml index 1079a59599..ba845de777 100644 --- a/.agents/notes/implemented/feature/2026-06-30-interception-seams.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-30-interception-seams.i18n.yaml @@ -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 -2026-06-30-interception-seams.md: 66e1c2374936c794bd5f791547c283f0fb59fb23 -2026-06-30-interception-seams.zh.md: fb2f1528a8e72a2f6b8b07679c8631b1b0a4f2d8 +2026-06-30-interception-seams.md: af78672c8c6426aa3992355b23b191c3409dcac2 +2026-06-30-interception-seams.zh.md: 61cb0bf5404c72ef7736783ffe2015556375c873 diff --git a/.agents/notes/implemented/feature/2026-06-30-interception-seams.zh.md b/.agents/notes/implemented/feature/2026-06-30-interception-seams.zh.md index fb2f1528a8..61cb0bf540 100644 --- a/.agents/notes/implemented/feature/2026-06-30-interception-seams.zh.md +++ b/.agents/notes/implemented/feature/2026-06-30-interception-seams.zh.md @@ -1,4 +1,4 @@ -# RFC: 拦截 seam——钩子编程所面对的类型化 Decision 表面 +# Agent Note: 拦截 seam——钩子编程所面对的类型化 Decision 表面 Status: implemented @@ -6,9 +6,9 @@ Status: implemented ## 问题 -harness 需要一套钩子子系统:用户像 Claude Code(CC)和 Codex 那样在生命周期节点扩展或管控 agent(智能体)。驱动本设计的关键视角转换是:**"原生钩子"不是一个包**——原生钩子只是一个普通的 Cordis 插件,订阅规范的生命周期事件。因此真正的产品是一个*强大、类型完备的规范事件表面*;CC/Codex 桥接(`dsh-hooks-claude` / `dsh-hooks-codex` 包)只是将外部 shell-hook 协议映射到同一表面的翻译层。桥接能做的事,普通插件可以直接做——而且更强大(无序列化边界、完整 `ctx`、类型化返回值)。 +harness 需要一套钩子子系统:用户像 Claude Code(CC)和 Codex 那样在生命周期节点扩展或管控 agent(智能体)。驱动本设计的关键视角转换是:**「原生钩子」不是一个包**——原生钩子只是一个普通的 Cordis 插件,订阅规范的生命周期事件。因此真正的产品是一个*强大、类型完备的规范事件表面*;CC/Codex 桥接(`dsh-hooks-claude` / `dsh-hooks-codex` 包)只是将外部 shell-hook 协议映射到同一表面的翻译层。桥接能做的事,普通插件可以直接做——而且更强大(无序列化边界、完整 `ctx`、类型化返回值)。 -该表面需要为以下场景提供各自独立的契约:逐 prompt 策略(CC 的 `UserPromptSubmit`)、会话启动观测(CC 的 `SessionStart`)、工具执行前策略、环绕调度控制、工具执行后变换、最终结果观测,以及携带面向模型的原因的继续执行。如果把这些阶段混为一谈,插件就会获得不需要的 mutation 通道,而终结性将依赖监听器的注册顺序。[事件域语义 RFC](../architecture/2026-06-30-event-domain-semantics.md) 提供了三域规则与类型化 Decision 惯用法;本 RFC 将其应用于生命周期 seam。 +该表面需要为以下场景提供各自独立的契约:逐 prompt 策略(CC 的 `UserPromptSubmit`)、会话启动观测(CC 的 `SessionStart`)、工具执行前策略、环绕调度控制、工具执行后变换、最终结果观测,以及携带面向模型的原因的继续执行。如果把这些阶段混为一谈,插件就会获得不需要的 mutation 通道,而终结性将依赖监听器的注册顺序。[事件域语义 Agent Note](../architecture/2026-06-30-event-domain-semantics.md)提供了三域规则与类型化 Decision 惯用法;本 Agent Note 将其应用于生命周期 seam。 ## 决策 @@ -16,9 +16,9 @@ harness 需要一套钩子子系统:用户像 Claude Code(CC)和 Codex 那 **Agent 事件**(`dsh-agent`): - `agent/session-start(agent, source)` ——emit,在第 1 轮次之前触发一次,携带 `SessionStartSource`(`startup` 表示全新/fork 创建,`resume` 表示重新加载的持久化会话;`clear`/`compact` 保留)。纯通知,不能阻塞启动(这是有意的空白:桥接可以记录/注入,但不管控启动)。监听器通过 `agent.inject()` 注入上下文。 -- `agent/prompt-submit(agent, content, source, next) → PromptDecision` ——waterfall,在已开启的轮次内、`user/message` 追加之前,对每条出队的排队消息触发。`allow`(可选地重写 prompt `content` 或附加 `additionalContext`)或 `block`(丢弃该 prompt;循环在其位置追加一条持久的 `prompt/blocked`——见下方调度说明)。 +- `agent/prompt-submit(agent, content, source, signal, next) → PromptDecision` ——waterfall,在轮次唯一取得所有权的排队消息追加为 `user/message` 之前触发。显式轮次 signal 位于最后的 `next` 之前;`allow` 可以重写 prompt `content` 或附加来源各自独立的 `additionalContexts[]`,而 `block` 会追加一条持久的 `prompt/blocked`,并拒绝这个零步骤轮次。 -**`agent/turn-continuation`** 接收并返回一个 `ContinuationDecision`。`{action:'continue', reason?}` 可携带面向模型的上下文,记录为同一轮次内的下一步 steering(中途引导)——与 `/goal` step-end-steer 模式互为类型化孪生。 +**`agent/turn-continuation`** 接收并返回一个 `ContinuationDecision`。`{action:'continue', reason?}` 可携带面向模型的内容和来源,记录为同一轮次内的下一步 steering(中途引导)——与 `/goal` step-end-steer 模式互为类型化孪生。它不是 `context/message`,因此其类型不提供持久上下文元数据。 ### 工具流水线为每个阶段赋予一种权限 @@ -26,19 +26,19 @@ harness 需要一套钩子子系统:用户像 Claude Code(CC)和 Codex 那 - **`tools/pre-execute`** 是可扩展的 waterfall 门禁。其 `PreToolDecision` 允许、拒绝或询问。拒绝跳过 `tools/execute` 与核心调度。询问通过可选的审批 seam 解析:只有 `allowed-once` 继续通过 guards 和调度;拒绝、取消、通道不可用、审批服务缺失或无 agent 调用均规范化为拒绝。每种结果仍会到达后策略与最终观测者。 - **`ctx.tools.guard()`** 在整个 pre-execute waterfall 之后安装同步的、作用域感知的策略。guard 可以拒绝或弃权,永远不能强制允许,因此监听器顺序无法复活一个被最终不变式禁止的操作。 -- **`tools/execute`** 是用于超时、重试和指标插件的环绕调度 waterfall。包装层通过 `next()` 委托给核心调度,在此之前只能添加、替换或移除 `exec.signal`,并接收已规范化的抛出或未知工具结果;返回自己的有效结果则短路调度。 -- **`tools/post-execute`** 是检查/变换 waterfall。其 `PostToolDecision` 接受、以反馈阻止、可选地替换内容,或附加 `additionalContext`;对结果的原地 mutation 不是变换通道,因为注册表从受保护的快照加上返回的 decision 重建结果。 +- **`tools/execute`** 是用于超时、重试和指标插件的环绕调度 waterfall。包装层通过 `next()` 委托给核心调度,在此之前可以替换并恢复必需的 `exec.signal`,但不能移除它;包装层接收已规范化的抛出或未知工具结果,返回自己的有效结果则短路调度。 +- **`tools/post-execute`** 是检查/变换 waterfall。其 `PostToolDecision` 接受、以反馈阻止、可选地替换内容,或附加 `additionalContexts`。返回的 decision 是受支持的变换通道;waterfall 结束后,注册表会在最终观测前一次性实体化完整结果。 - **`tools/result`** 是在所有变换、无损 JSON 实体化和外层错误边界之后的同步封闭通知。它接收相同的冻结执行身份和权威结果的不可变快照;观测者的失败按监听器隔离,无法改变或拒绝 `ToolRegistry.execute()` 返回的结果。 核心调度与工具体位于规范化边界内部,因此工具、监听器、格式错误的结果、非 JSON 结果和身份形状错误均解析为 JSON 安全的 `isError` 结果,而非逃逸出轮次。post-execute 监听器因此可以检查一个抛出异常的工具,最终观测者看到的正是调用方收到的、会话日志可以持久化的内容。 -**`TurnEndReason.rejected`**(`dsh-session`):整批 prompt 均被 `prompt-submit` 阻止的轮次。 +**`TurnEndReason.rejected`**(`dsh-session`):取得所有权的 prompt 被 `prompt-submit` 阻止的零步骤轮次。 ### 三个承重的循环决策 -1. **在 prompt 策略之前开启轮次。** 全部被阻止的批次成为零步骤的 `rejected` 轮次,保持封闭性并为 ACP(Agent Client Protocol)提供持久的终结事件。每次否决还记录 `prompt/blocked`(含原始 prompt 和原因),因此混合批次保留被阻止的输入。允许的 `additionalContext` 注入到已开启的轮次中。 +1. **在 prompt 策略之前开启轮次。** 被阻止的 prompt 成为零步骤的 `rejected` 轮次,保持封闭性并为 ACP(Agent Client Protocol)提供持久的终结事件。否决记录 `prompt/blocked`(含原始 prompt 和原因),而每个允许的 `additionalContexts` 条目都注入到已开启的轮次中。依照[一次 send 对应一个 turn 的简化](../simplification/2026-07-17-one-send-one-turn.md),每个取得所有权的 ordinary-send 条目都是其轮次中的唯一消息;启动前丢弃不会创建轮次。 -2. **Post-tool `additionalContext` 被缓冲,在所有 `tool/result` 之后追加。** `content`/`feedback` 塑造 `execute()` 返回的结果,但 `additionalContext` 是一条独立的 `context/message`,而单个步骤可以携带多个工具调用。如果在每个结果之后立即追加上下文,会产生 `result(c1) → context → result(c2)` 的交错,破坏工具调用/结果的邻接性。因此 `execute()` 将 `additionalContext` 暴露在其 `ToolExecutionResult` 上,循环为该步骤的每次调用缓冲上下文,仅在所有 `tool/result` 追加完毕后才以 `context/message` 形式追加。 +2. **Post-tool `additionalContexts` 与异步注入进入活跃批次 FIFO,并在该批次结算时追加。** `content`/`feedback` 塑造 `execute()` 返回的结果,但每项上下文都是独立的 `context/message`,而单个步骤或组合工具可以产生许多上下文。立即追加上下文会产生 `result(c1) → context → result(c2)` 的交错,或把嵌套上下文放在外层结果之前,破坏工具调用/结果邻接性。因此 `ToolRunContext.deferContext()` 会在失败路径上也收集嵌套调度上下文,`execute()` 在 `ToolExecutionResult` 上暴露有序数组,循环再把它接纳到与执行期间 `agent.inject()` 调用相同的 FIFO 中。FIFO 在批次结算时,于每个已记录结果之后追加,其中也包括被中断轮次关闭之前。被接受的外层调用将 deferred contexts 保留在 decision contexts 之前;被外层阻止时则丢弃 deferred contexts,只暴露阻止 decision 显式提供的上下文。 3. **强制 `continue` 的 `reason` 通过 steering 通道入队**,使得下一步骤在循环顶部排空时将其记录为当前轮次的 steering——同一轮次内的下一*步骤* steering,而非下一*轮次*的 prompt(与现有的 `hasSteering` 强制继续覆盖一致)。 @@ -57,4 +57,4 @@ seam 包**不**声明 `hook/*` 会话事件(持久的钩子调用日志); ## 后果 -规范拦截表面具有统一的类型化,同时不给每个扩展相同的权力:钩子返回 decision,执行包装层做包装,终结 guard 只能拒绝,最终观测者只能观测。循环负责 session-start、prompt-submit、post-tool 上下文缓冲和 continuation;`dsh-tools` 负责身份封存与五阶段执行流水线。它们的契约记录在 [architecture.md](../../../architecture.md)、各 package README、[核心拦截 decision](../../../core-data-structures/core.md#interception-decisions) 与[工具结构](../../../core-data-structures/tools.md)中。ACP 桥接将 `rejected` 轮次映射为其 `cancelled` 编解码值,而钩子驱动的快照端到端验证可观测的桥接行为。 +规范拦截表面具有统一的类型化,同时不给每个扩展相同的权力:钩子返回 decision,执行包装层做包装,终结 guard 只能拒绝,最终观测者只能观测。循环负责 session-start、prompt-submit、post-tool 上下文缓冲和 continuation;`dsh-tools` 负责身份封存与五阶段执行流水线。它们的契约记录在 [architecture.md](../../../../docs/architecture.md)、各 package README、[核心拦截 decision](../../../../docs/core-data-structures/core.md#interception-decisions) 与[工具结构](../../../../docs/core-data-structures/tools.md)中。ACP 桥接将 `rejected` 轮次映射为其 `cancelled` 编解码值,而钩子驱动的快照端到端验证可观测的桥接行为。 diff --git a/.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml b/.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml index b06ccc29d9..d96961bf0e 100644 --- a/.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.i18n.yaml @@ -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 -2026-06-30-session-store-fork-api.md: c5359a30124aabf0f9f809ffe899c6ad5fca8051 -2026-06-30-session-store-fork-api.zh.md: 62f399df41488143a66069fdd5a36ddb3e62421f +2026-06-30-session-store-fork-api.md: 4e4ea7f1d3aa3290bdb21999a292dbdfd016302e +2026-06-30-session-store-fork-api.zh.md: d21a2a233d60bd788b79eb39f0f358b8e5b90cae diff --git a/.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.zh.md b/.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.zh.md index 62f399df41..d21a2a233d 100644 --- a/.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.zh.md +++ b/.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.zh.md @@ -1,4 +1,4 @@ -# RFC: SessionStore fork API +# Agent Note: SessionStore fork API Status: implemented @@ -8,7 +8,7 @@ Status: implemented 事件溯源的会话日志已经具备 fork 所需的原语:创建一个带有种子事件前缀的新会话,然后像回放一样从该种子日志推导模型历史。这个原语有意保持底层:`ctx.sessions.create(id, { seed, meta })` 接受任何合法种子,但常规的活跃会话分支需要围绕以下问题制定策略:哪些前缀可以被复制、子会话应打上哪些元数据、以及错误如何分类。 -语义上的风险在于 fork 边界。一个合法的用户可见 fork 种子必须是连续的且封闭在轮次内。如果在一个活跃轮次内部 fork,会复制一个未关闭的 `turn/start`、可能还有一个未关闭的 `step/start`,以及可能悬空的工具调用。这违反了轮次封闭性与 provider-transcript 不变式,并且会创建一段误导性的子历史——看起来子会话参与了父会话中一个尚未完成的轮次。现有的 [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 有意解决的是另一个问题:工具触发的 subagent fork 通常发生在父轮次仍然打开时,因此 `dsh-subagent-fork` 会将种子裁剪到父会话最后一个已完成轮次的前缀。通用的会话 fork 不应静默裁剪;它应当要么在请求的边界处 fork,要么拒绝请求。 +语义上的风险在于 fork 边界。一个合法的用户可见 fork 种子必须是连续的且封闭在轮次内。如果在一个活跃轮次内部 fork,会复制一个未关闭的 `turn/start`、可能还有一个未关闭的 `step/start`,以及可能悬空的工具调用。这违反了轮次封闭性与 provider-transcript 不变式,并且会创建一段误导性的子历史——看起来子会话参与了父会话中一个尚未完成的轮次。现有的 [subagent seam](2026-06-21-subagent-capability-seam.md) 有意解决的是另一个问题:工具触发的 subagent fork 通常发生在父轮次仍然打开时,因此 `dsh-subagent-fork` 会将种子裁剪到父会话最后一个已完成轮次的前缀。通用的会话 fork 不应静默裁剪;它应当要么在请求的边界处 fork,要么拒绝请求。 ## 决策 @@ -40,4 +40,4 @@ class SessionStore extends Service { 公开接口保持精简且易于发现:活跃会话分支是 `ctx.sessions` 的一部分,紧邻 `create({ seed })`,而非一个独立服务或一对两步辅助函数。持久化继续通过现有的 `session/created` 和 `session/flush` 行为运作:fork 出的子会话以种子事件开始生命,因此现有后端只需持久化该种子一次,并在 header 中保存 `parentSession`/`seedLength`。 -v1 范围仍然排除 ACP(Agent Client Protocol) `session/fork`、对未加载的已持久化会话的 fork、面向模型的工具,以及 subagent 重构。如果未来添加 ACP 方法,应在具备 transcript(文本记录)/快照覆盖后才广播该能力;本 RFC 不添加面向编辑器的更新,因此当前不需要 ACP 快照。fork 子会话的回放仍由现有的[种子边界测试 RFC](../../implemented/testing/2026-06-22-fork-child-replay-seed-boundary.md) 覆盖,而本 API 则获得专门的 `dsh-session` 单元测试加 JSONL 持久化覆盖。 +v1 范围仍然排除 ACP(Agent Client Protocol) `session/fork`、对未加载的已持久化会话的 fork、面向模型的工具,以及 subagent 重构。如果未来添加 ACP 方法,应在具备 transcript(文本记录)/快照覆盖后才广播该能力;本 Agent Note 不添加面向编辑器的更新,因此当前不需要 ACP 快照。fork 子会话的回放仍由现有的[种子边界测试 Agent Note](../testing/2026-06-22-fork-child-replay-seed-boundary.md) 覆盖,而本 API 则获得专门的 `dsh-session` 单元测试加 JSONL 持久化覆盖。 diff --git a/.agents/notes/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml b/.agents/notes/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml index cb9c05d033..c775a6113b 100644 --- a/.agents/notes/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-06-30-subagent-observe-enrich.i18n.yaml @@ -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 -2026-06-30-subagent-observe-enrich.md: 1e20ddff5473a23f3ed560246fbd06f8090852ae -2026-06-30-subagent-observe-enrich.zh.md: 6bc00c9a8f1d3656fbbfc482e3e6b66020298dd9 +2026-06-30-subagent-observe-enrich.md: a07cef95630689d1ca8cacd3eb7c50e691cb304a +2026-06-30-subagent-observe-enrich.zh.md: ce8374b4f046e97c1366256c5c6626013aa8c73f diff --git a/.agents/notes/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md b/.agents/notes/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md index 6bc00c9a8f..ce8374b4f0 100644 --- a/.agents/notes/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md +++ b/.agents/notes/implemented/feature/2026-06-30-subagent-observe-enrich.zh.md @@ -1,4 +1,4 @@ -# RFC: Subagent 生命周期丰富化——lastAssistantMessage(仅观察) +# Agent Note: Subagent 生命周期丰富化——lastAssistantMessage(仅观察) Status: implemented @@ -6,9 +6,9 @@ Status: implemented ## 问题 -钩子子系统([拦截 seam RFC](2026-06-30-interception-seams.md))允许插件在生命周期节点观察和拦截 agent(智能体)。Claude Code 和 Codex 都暴露了 **SubagentStart / SubagentStop** 钩子,且 CC 的钩子携带 subagent 的最终消息。harness 已经发出 `subagent/start` 和 `subagent/end` 生命周期事件([subagent 能力 seam](2026-06-21-subagent-capability-seam.md)),但其载荷极为精简(`provider`、`id`,以及 end 时的 `stopReason`),不足以让钩子桥接层在不单独访问活跃 run 的情况下报告 subagent 产出了什么。 +钩子子系统([拦截 seam Agent Note](2026-06-30-interception-seams.md))允许插件在生命周期节点观察和拦截 agent(智能体)。Claude Code 和 Codex 都暴露了 **SubagentStart / SubagentStop** 钩子,且 CC 的钩子携带 subagent 的最终消息。harness 已经发出 `subagent/start` 和 `subagent/end` 生命周期事件([subagent 能力 seam](2026-06-21-subagent-capability-seam.md)),但其载荷极为精简(`provider`、`id`,以及 end 时的 `stopReason`),不足以让钩子桥接层在不单独访问活跃 run 的情况下报告 subagent 产出了什么。 -本 RFC 丰富 end 载荷。它刻意限定为**仅观察**:不改变控制流,不引入 waterfall(瀑布式事件)。影响 run 的 subagent-stop 决策(续行、改变 run 的注入)属于另一个更大的重设计,不在本 RFC 范围内。 +本 Agent Note 丰富 end 载荷。它刻意限定为**仅观察**:不改变控制流,不引入 waterfall(瀑布式事件)。影响 run 的 subagent-stop 决策(续行、改变 run 的注入)属于另一个更大的重设计,不在本 Agent Note 范围内。 ## 决策 @@ -18,14 +18,14 @@ Status: implemented ## 曾考虑的替代方案 -**`agentType` subagent 类别标签**(CC 的 `subagent_type` 在 harness 中的对应物),放在请求与两个生命周期载荷上。早期草案曾包含它;评审中移除,因为它是 Claude Code 的概念,不适合我们自己的 seam(此处没有任何逻辑解释它,唯一消费方是 CC 方言桥接层)。CC 桥接层改为直接为其 SubagentStart/Stop 的 `agent_type` matcher 填入 Claude Code 自身的默认值 `"general-purpose"`,因此本 RFC 只交付一项丰富化:`lastAssistantMessage`。 +**`agentType` subagent 类别标签**(CC 的 `subagent_type` 在 harness 中的对应物),放在请求与两个生命周期载荷上。早期草案曾包含它;评审中移除,因为它是 Claude Code 的概念,不适合我们自己的 seam(此处没有任何逻辑解释它,唯一消费方是 CC 方言桥接层)。CC 桥接层改为直接为其 SubagentStart/Stop 的 `agent_type` matcher 填入 Claude Code 自身的默认值 `"general-purpose"`,因此本 Agent Note 只交付一项丰富化:`lastAssistantMessage`。 **控制流式 `subagent/end`**:推迟;见下文。 ## 为何仅观察,以及推迟了什么 -控制流式 `subagent/end`(一个被 await 的 waterfall,返回停止/继续决策,与其他拦截 seam 一致)需要:将 `subagent/end` 从 emit 改为 waterfall、重构 `SubagentService.start` 使其在结算前 await 监听方、在进程内 provider 中实现 `resume` 能力以便「继续」能真正重新运行子 agent。这属于[能力 seam RFC](2026-06-21-subagent-capability-seam.md) 已推迟的后台/steering(中途引导)subagent 重设计(同一个重设计还将统一 subagent 与 bash 之间的长时间运行工具处理)。本 RFC 交付钩子桥接层当前所需的仅观察丰富化;`FIXME(subagent-continuation)` / `TODO` 锚点标记了控制流版本在重设计发生时的落点。 +控制流式 `subagent/end`(一个被 await 的 waterfall,返回停止/继续决策,与其他拦截 seam 一致)需要:将 `subagent/end` 从 emit 改为 waterfall、重构 `SubagentService.start` 使其在结算前 await 监听方、在进程内 provider 中实现 `resume` 能力以便「继续」能真正重新运行子 agent。这属于[能力 seam Agent Note](2026-06-21-subagent-capability-seam.md) 已推迟的后台/steering(中途引导)subagent 重设计(同一个重设计还将统一 subagent 与 bash 之间的长时间运行工具处理)。本 Agent Note 交付钩子桥接层当前所需的仅观察丰富化;`FIXME(subagent-continuation)` / `TODO` 锚点标记了控制流版本在重设计发生时的落点。 ## 后果 -钩子桥接层(或原生插件)现在可以通过订阅既有 emit 将子 agent 的 `lastAssistantMessage` 转发给 SubagentStop 处理器,无需新的控制流接口。词汇新增记录在 [docs/core-data-structures/subagent.md](../../../core-data-structures/subagent.md)(事件行文部分)与两个 subagent README 中;catalog 已重新生成。生产行为无变化——事件触发方式与之前完全一致,end 载荷上多了一个可选字段——因此无需更新快照或 e2e 测试。 +钩子桥接层(或原生插件)现在可以通过订阅既有 emit 将子 agent 的 `lastAssistantMessage` 转发给 SubagentStop 处理器,无需新的控制流接口。词汇新增记录在 [docs/core-data-structures/subagent.md](../../../../docs/core-data-structures/subagent.md)(事件行文部分)与两个 subagent README 中;catalog 已重新生成。生产行为无变化——事件触发方式与之前完全一致,end 载荷上多了一个可选字段——因此无需更新快照或 e2e 测试。 diff --git a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml index bcf9d40b91..17679363d0 100644 --- a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.i18n.yaml @@ -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 -2026-07-05-dynamic-workflows.md: e6f2ab9a4fc5f5403a7739495be7d82ebce3ec0d -2026-07-05-dynamic-workflows.zh.md: 82234c2405f972f2c42c58be6772f55eda500455 +2026-07-05-dynamic-workflows.md: 353ab56aaac2d0d7624ff35f03cc7073e50a1a7d +2026-07-05-dynamic-workflows.zh.md: aeb1f736c9674b37fcd249529e0f7dc4dac89cbb diff --git a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md index 82234c2405..aeb1f736c9 100644 --- a/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md +++ b/.agents/notes/implemented/feature/2026-07-05-dynamic-workflows.zh.md @@ -1,4 +1,4 @@ -# RFC: 动态工作流——脚本驱动的多 agent 编排 seam +# Agent Note: 动态工作流——脚本驱动的多 agent 编排 seam Status: implemented @@ -20,7 +20,7 @@ harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`) ### seam(dsh-workflow) -`ctx.workflows` 是 bash 形态的抽象 `WorkflowService`——每个上下文一个引擎,无命名提供方注册表(引擎是部署级替换,不是共存者)。`start(request)` 对无法启动的脚本同步抛出;返回的 `WorkflowRun` 的 `result` 永不 reject(失败解析为 `stopReason: 'error' | 'cancelled'`)。`workflow/*` 事件是仅观察的 emit,携带数据快照(id + meta;`workflow/end` 省略 result 值),按监听器隔离,与 `subagent/start`/`subagent/end` 对称——控制权留在 run 的持有者手中。词汇详情见 [core-data-structures/workflow.md](../../../core-data-structures/workflow.md)。 +`ctx.workflows` 是 bash 形态的抽象 `WorkflowService`——每个上下文一个引擎,无命名提供方注册表(引擎是部署级替换,不是共存者)。`start(request)` 对无法启动的脚本同步抛出;返回的 `WorkflowRun` 的 `result` 永不 reject(失败解析为 `stopReason: 'error' | 'cancelled'`)。`workflow/*` 事件是仅观察的 emit,携带数据快照(id + meta;`workflow/end` 省略 result 值),按监听器隔离,与 `subagent/start`/`subagent/end` 对称——控制权留在 run 的持有者手中。词汇详情见 [core-data-structures/workflow.md](../../../../docs/core-data-structures/workflow.md)。 ### 引擎(dsh-workflow-workerthread):每次运行一个 worker 线程 @@ -28,7 +28,7 @@ harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`) **为何选择 `node:worker_threads`**:每次运行获得一个非池化的 worker。vm 上下文限制了文档化的脚本表面,而 message-port RPC 将 `agent()` 桥接到宿主侧的子循环。worker 防止脚本的同步工作阻塞宿主,提供序列化边界,并允许取消后强制终止。`isolated-vm` 因其维护状态和部署要求被否决。 -宿主在发布前校验元数据并解析正文。私有枚举键 payload 映射定义协议格式;待启动记录、已发布子记录、单一取消信号、worker 死亡回收、结果优先级与 dispose 静默,在此协议上保持 subagent run 契约。这些竞态算法归 [agent-scope runtime-design RFC](../architecture/2026-07-12-agent-scope-runtime-design.md#workflow-children-are-pending-starts-or-published-records) 所有。 +宿主在发布前校验元数据并解析正文。私有枚举键 payload 映射定义协议格式;待启动记录、已发布子记录、单一取消信号、worker 死亡回收、结果优先级与 dispose 静默,在此协议上保持 subagent run 契约。这些竞态算法归 [agent-scope runtime-design Agent Note](../architecture/2026-07-12-agent-scope-runtime-design.md#workflow-children-are-pending-starts-or-published-records) 所有。 引擎暴露一条进程内 `MessageChannel` 测试路径,因为主进程 V8 覆盖率无法观测 worker 执行。 @@ -46,7 +46,7 @@ harness 可以将一个任务委派给一个子 agent(`dsh-tool-subagent`) 输出 schema 使一次 schema 有效的已提交捕获成为子 agent 成功完成的必要条件。作用域运行时呈现捕获工具和指令,仅提交成功的最终结果(包括 SDK 调用时外层 `run_code` 的结果),在捕获变为 pending 后拒绝后续副作用,并在提交后不再进行模型步骤即停止子 agent。校验失败仍是可重试的工具错误;没有已提交捕获的正常完成以错误结算。 -`StructuredOutputSchema` 是 `dsh-tools` 中可强制执行的原始 JSON-Schema 子集(单字符串 `type`、`properties`/`required`/`additionalProperties`、`items`、标量 `enum`/`const`),不支持的关键字会大声失败,因为该协议数据会逐字成为捕获工具的 parameters。组装、提交、守卫和终止停止的正确性算法归 [agent-scope runtime-design RFC](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes) 所有。 +`StructuredOutputSchema` 是 `dsh-tools` 中可强制执行的原始 JSON-Schema 子集(单字符串 `type`、`properties`/`required`/`additionalProperties`、`items`、标量 `enum`/`const`),不支持的关键字会大声失败,因为该协议数据会逐字成为捕获工具的 parameters。组装、提交、守卫和终止停止的正确性算法归 [agent-scope runtime-design Agent Note](../architecture/2026-07-12-agent-scope-runtime-design.md#structured-output-commits-only-authoritative-outcomes) 所有。 ## 测试 diff --git a/.agents/notes/implemented/feature/2026-07-05-skill-system.i18n.yaml b/.agents/notes/implemented/feature/2026-07-05-skill-system.i18n.yaml index 31fb9e006f..b5882ad5ea 100644 --- a/.agents/notes/implemented/feature/2026-07-05-skill-system.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-05-skill-system.i18n.yaml @@ -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 -2026-07-05-skill-system.md: f39b5f5766eadf7c0a7bfd3f887aca60f69477af -2026-07-05-skill-system.zh.md: 0aff262792a6f8a38a02475d6975510d5aae5da5 +2026-07-05-skill-system.md: 3c328adf09ab0f6ad3388a01bac3661d45c9247e +2026-07-05-skill-system.zh.md: ba30a3735b73b00afb46baa24f969fd687a759b5 diff --git a/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md b/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md index 0aff262792..ba30a3735b 100644 --- a/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md +++ b/.agents/notes/implemented/feature/2026-07-05-skill-system.zh.md @@ -1,4 +1,4 @@ -# RFC: Skill 系统——面向 agent 的渐进式指令披露 +# Agent Note: Skill 系统——面向 agent 的渐进式指令披露 Status: implemented @@ -26,7 +26,7 @@ DeepSeek Harness 使用同一原语,使项目特定的评审、插件编写和 `skill({ name })` 工具为当前 agent cwd 加载一个完整 skill,返回包含 `<skill_content name="...">`、`<skill_resources>` 和 `<skill_instructions>` 的工具结果。`resourceBase` 提供一个目录、URL 或不透明的提供方管理的基路径,用于显式引用的脚本、参考资料和资产;资源仅按需加载,不进行目录枚举。无法解析的名称报告该 skill 未知或不再可用;无效名称和标记了 `disableModelInvocation` 的 skill 保留不同的工具错误。工具结果是面向模型的可见披露路径。 -数据结构与目录/工具契约记录在 [skills.md](../../../core-data-structures/skills.md) 中,服务签名见生成的[服务目录](../../../cordis-catalog/services.md)。 +数据结构与目录/工具契约记录在 [skills.md](../../../../docs/core-data-structures/skills.md) 中,服务签名见生成的[服务目录](../../../../docs/cordis-catalog/services.md)。 ## 曾考虑的替代方案 @@ -52,4 +52,4 @@ agent-core 主干包含一个 session-prefix 贡献者、一个本地提供方 ## 延后 -Fork 的 skill 上下文(`context: fork`)、直接用户/斜杠调用(`user-invocable`)、参数声明与提示(`arguments` 和 `argument-hint`)、以及逐 skill 的工具约束(`allowed-tools` 和 `disallowed-tools`)不在已交付的契约范围内。注册表、本地提供方和面向模型的工具不解析、不广播、也不执行这些字段。 +Fork 的 skill 上下文(`context: fork`)、参数声明与提示(`arguments` 和 `argument-hint`)、以及逐 skill 的工具约束(`allowed-tools` 和 `disallowed-tools`)不在已交付的契约范围内。注册表、本地提供方和面向模型的工具不解析、不广播、也不执行这些字段,`user-invocable` frontmatter 字段同样不会被解析。直接用户调用本身则作为消费方层面的能力交付:TUI 前门基于注册表现有的 `list()` 与 `get()` 方法提供手动 `/skill:<name>` 命令,无需变更注册表、提供方或工具契约——见 [TUI skill 斜杠命令](2026-07-21-tui-skill-slash-command.md)。 diff --git a/.agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml b/.agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml index fe71c00352..ec785c65c4 100644 --- a/.agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml @@ -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 -2026-07-06-approval-seam.md: dedcc2022382af7a614023e4354b77f1c15cd92f -2026-07-06-approval-seam.zh.md: 193461a2e5c3c14efe4b1565656cc38baab11fcb +2026-07-06-approval-seam.md: e28587e0185530164f300562f7dd5e57255ac515 +2026-07-06-approval-seam.zh.md: 94ffb330cd36ae88975e8ae9d579b3b4606a5c25 diff --git a/.agents/notes/implemented/feature/2026-07-06-approval-seam.zh.md b/.agents/notes/implemented/feature/2026-07-06-approval-seam.zh.md index 193461a2e5..94ffb330cd 100644 --- a/.agents/notes/implemented/feature/2026-07-06-approval-seam.zh.md +++ b/.agents/notes/implemented/feature/2026-07-06-approval-seam.zh.md @@ -1,4 +1,4 @@ -# RFC: 审批 seam——基于 waterfall(瀑布式事件)应答者的一次性权限决策 +# Agent Note: 审批 seam——基于 waterfall(瀑布式事件)应答者的一次性权限决策 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -两个调用方需要向人类提出同一个问题——「这个具体操作可以继续吗?」:`tools/pre-execute` 的 `ask` 决策(包括 Claude-Code 钩子桥的 `permissionDecision: ask`)以及[沙箱 RFC](2026-07-06-sandbox.md) 中拒绝后的一次性升级重试。一个共享的 seam 使它们无需各自发明独立的结果词汇、UI 路由、取消机制和审计轨迹,同时保证没有 UI 的部署永远不会批准一个无法应答的请求。 +两个调用方需要向人类提出同一个问题——「这个具体操作可以继续吗?」:`tools/pre-execute` 的 `ask` 决策(包括 Claude-Code 钩子桥的 `permissionDecision: ask`)以及[沙箱 Agent Note](2026-07-06-sandbox.md) 中拒绝后的一次性升级重试。一个共享的 seam 使它们无需各自发明独立的结果词汇、UI 路由、取消机制和审计轨迹,同时保证没有 UI 的部署永远不会批准一个无法应答的请求。 路由问题的核心是归属:审批提示必须到达拥有发起请求的 agent(智能体)的编辑器会话(ACP(Agent Client Protocol)桥在一条连接上多路复用 N 个会话),对无人拥有的 agent(进程内 subagent、测试)失败关闭,并且不侵入没有组合 UI 的部署(headless、CI)。 @@ -27,7 +27,7 @@ Status: implemented 仅有这条条目只提供机制,不提供通道:没有组合应答者时,每次 ask 都解析为 `unavailable`,发起请求的工具调用被拒绝——失败关闭无需配置。组合 ACP 应用(`@deepseek-ai/dsh-acp-demo`,如 [acp-agent 示例的默认树](../../../../examples/acp-agent/README.md))即可闭环:其桥注册一个应答者,通过 `session/request_permission` 向拥有该会话的编辑器发出提示,于是钩子的 `ask` 或升级请求会以一次性 Allow/Reject 提示的形式呈现,附着在已流式输出的工具调用上。`policy: never` 是无人值守姿态:每次 ask 确定性地自动拒绝,在系统提示词中声明,无人类参与。`policy` 在插件加载时对照封闭列表校验;非法值直接抛异常。 -组合部署的可观测行为:`allowed-once` 仅允许该次调用继续;拒绝、关闭和通道缺失以三种不同原因拒绝,模型可以区分;每次 ask 在发起请求的 agent 的会话日志上落一对持久的 `approval/asked`/`approval/decided` 事件;授权不会在发起请求的调用结束后继续存在。 +组合部署的可观测行为:`allowed-once` 仅允许该次调用继续;拒绝、关闭和通道缺失以三种不同原因拒绝,模型可以区分;轮次内成功的请求会在发起请求的 agent 的会话日志上落一对持久的 `approval/asked`/`approval/decided` 事件;授权不会在发起请求的调用结束后继续存在。空闲时的请求或审计追加失败会拒绝,而不会返回未经审计的决策。 以下是该组合下的一次 ask,逐字取自沙箱示例录制的 `escalation-approved` 场景——模型请求沙箱升级,门禁发起 ask,桥向拥有该会话的编辑器发出提示,用户点击 Allow once: @@ -51,45 +51,44 @@ tool/result "escalated" — this one call ran under the wider mode; the gra #### seam:机制与策略分离 -经过校验并追加 `approval/asked` 后,`request()` 解析为 `allowed-once`、`rejected`、`cancelled` 或 `unavailable`。服务借用只读请求,运行应答者 waterfall,与取消竞速,并将抛出异常或无效应答规范化为 `unavailable`。然后追加匹配的 `approval/decided`,以 `ApprovalRequestId` 配对。 +经过校验并成功追加 `approval/asked` 后,服务将 `approval/request` waterfall 解析为 `allowed-once`、`rejected`、`cancelled` 或 `unavailable`。服务借用只读的请求标识和 signal,将中止视为 `cancelled`,把应答者失败和无效返回容纳为 `unavailable`,丢弃迟到的应答,并追加配对的 `approval/decided` 事件。提交前的审计失败会拒绝;追加后的观察者失败无法撤销权威事件。`allowed-once` 仅授权所询问的操作,而 `request()` 会拒绝打开轮次之外的调用,以保证审计对留在持久提交边界内。 -两个审计事件都必须在一个打开的轮次内;接受或预提交追加失败会拒绝该请求。提交后的观察者由会话容纳。`allowed-once` 仅授权所请求的操作,服务不保留任何授权状态。 +应答者是 `approval/request` waterfall 监听器。零监听器会一路委派至 `unavailable`;识别该 agent 的监听器占用先到先得的决策槽,而不识别的监听器必须调用 `next()` 委派。监听器随其 fiber dispose,因此卸载通道会失败关闭。由于兄弟插件的注册顺序不确定,部署应组合一个终端应答者,并保留 `prepend` 给「决策或委派」门禁。 -应答者是 `approval/request` waterfall 监听器。监听器为它拥有的 agent 返回结果,否则调用 `next()`。没有应答者时默认为 `unavailable`;因此卸载 UI 即失败关闭,不会留下悬空通道。由于兄弟插件的注册顺序不确定,部署应组合一个终端应答者,仅对「先决策或委派」门禁使用 `prepend`。 - -`ApprovalRequest` 携带 agent、工具名、可选的 `callId`、原因和 signal。agent 同时路由提示和审计事件。请求使用 `dsh-llm` 的 `CallId` 而不导入 `dsh-tools`,避免包循环。工具参数被省略,因为 UI 应答者附着在已渲染的调用上。 +`ApprovalRequest` 携带发起请求的 `agent`、`toolName`、可选的精确 `callId`、人类可读的 `reason` 和可选的 `signal`。它使用 `CallId` brand 而不导入依赖本 seam 的 `dsh-tools`。工具参数仍留在 UI 通过 `callId` 引用的、已流式输出的调用上。 #### dsh-tools 中的 Ask 路由 -`ToolRegistry.execute()` 在进入拒绝路径之前,将 `ask` 发送到审批 seam。只有 `allowed-once` 才继续执行;拒绝、取消和通道不可用产生三种模型可见的不同原因。注册表按调用查找可选服务,因此服务缺失或未加载时失败关闭,不会阻塞注册表 fiber。无 agent 的执行同样失败关闭,因为无法路由或审计。 +`ToolRegistry.execute()` 在派发前解析 `ask`:`allowed-once` 继续执行,而拒绝、取消和通道不可用产生三种不同的拒绝原因。机会性消费 `ctx.get('approval')`,让缺失或未挂载的服务失败关闭而不阻塞注册表 fiber。无 agent 的执行同样失败关闭,因为它既没有审计会话,也没有 UI 所有者。 #### 每会话策略层 -seam 拥有会话策略 `'ask' | 'never'`,遵循[沙箱 RFC](2026-07-06-sandbox.md) 中的切换契约。生效的会话或配置策略在应答者之前应用:`'never'` 在 `request()` 内部直接拒绝,`'ask'` 则派发请求,无人应答时降级为 `unavailable`。提示词仅声明确定性的 `'never'`;叙述者报告切换,每个请求仍收到其审计对。 +seam 还拥有[沙箱 Agent Note](2026-07-06-sandbox.md) 所描述的会话级 `'ask' | 'never'` 策略。生效策略由日志中记录的切换在部署默认值之上折叠而成。`'never'` 会在任何应答者运行之前,于 `request()` 内部解析为 `rejected`;`'ask'` 则派发请求,否则一路委派至 `unavailable`。提示词仅声明确定性的 `'never'`,切换叙述会被合并,每个请求仍记录审计对。 #### ACP 应答者 -ACP 桥找到拥有该会话的编辑器,为该 `callId` 发送 `session/request_permission`,并将一次性 allow、reject、cancel 响应映射到 seam 词汇。未知选项永远不授权。外部 agent 和没有 `callId` 的请求通过 `next()` 委派;RPC 失败变为 `unavailable`。桥应答请求,但不决定哪些调用需要审批。 +ACP 桥只应答其正向会话映射所拥有的精确 agent 对象。它把 `session/request_permission` 附着到既有 `callId`,声明一次性的 allow/reject 选项,单独映射取消,并且绝不批准未知选项。外部或无调用标识的请求会委派;客户端 RPC 失败变为 `unavailable`。钩子和 `tools/pre-execute` 决定一次调用是否需要询问。 -应答者通过 [ACP 支持 RFC](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md) 描述的桥反向映射归属 seam 进行路由,实现了[多会话 RFC](../../implemented/feature/2026-06-14-acp-multi-session.md) 要求的每会话权限归属。 +应答者通过 [ACP 支持 Agent Note](2026-06-14-acp-agent-client-protocol.md) 描述的桥精确 agent 归属检查进行路由,实现了[多会话 Agent Note](2026-06-14-acp-multi-session.md) 要求的每会话权限归属。 #### 审计,以及模型看到什么 -`approval/asked` 和 `approval/decided` 是持久的仅日志事件。模型只看到发起方派生的已记录 `tool/result`。每个被接受的请求追加一条匹配的决策,包括取消和被容纳的应答者失败。 +`approval/asked` 和 `approval/decided` 是持久的仅日志事件;模型只看到从结果派生出的普通工具结果。成功完成时,每个 `asked` 都提交一个 `decided`,包括取消和被容纳的应答者失败。空闲时的请求不追加任何事件;提交前失败会拒绝,而第二次追加失败可能留下一个已经提交但未匹配的 `asked`。 #### 实体与依赖 -`dsh-user-approval` 拥有固定的派发与审计机制;`dsh-tools` 发起请求,`dsh-acp` 应答。可替换的应答者作为监听器留在其通道拥有者插件中,因此三包能力拆分只会多出一个空的实现层。沙箱执行器仍然只负责传输,静态能力授权与交互式审批保持分离。 +`dsh-user-approval` 依赖 Cordis,以及会话、agent 和带 brand 的调用契约;`dsh-tools` 与 `dsh-acp` 消费它。沙箱执行器保持独立,因为升级请求归 `dsh-tool-bash` 所有。固定的派发与审计服务仍是一个包;可替换的应答者留在各自的通道所有者中。静态能力授权和 `subagent-acp` 子侧权限应答仍是独立关注点。 ### 测试 -- **单元/集成测试:** 覆盖先到先得的委派、失败关闭默认值、畸形和抛异常的应答者、取消竞速与迟到应答丢弃、观察者失败时的审计配对、不可绕过的 `'never'`、不同的工具拒绝原因,以及 ACP 每会话路由/结果映射。 -- **快照测试:** 对沙箱升级的两个分支编排权限应答并固定 `'never'` 提示词加策略切换通知。无组合应答者时钩子产生的 ask 仍作为失败关闭拒绝被覆盖。 +单元测试固定结果、先到先得的委派、错误容纳、取消、作用域路由、审计配对、不可绕过的 `'never'` 策略、工具拒绝原因,以及通过真实脚本化桥实现的 ACP 归属/结果映射。 + +快照记录通过 `session/request_permission` 批准和拒绝沙箱升级,以及 `'never'` 提示词与策略切换通知。没有脚本化应答的权限提示会取消并失败关闭。 ## 延后 -- **`allow_always` 授权存储**:兑现持久授权意味着设计存储、作用域标识(调用?路径?前缀?会话?时间窗口?)和撤销;在设计完成之前,只展示一次性选项([沙箱 RFC](2026-07-06-sandbox.md) § Escalation 记录了开放的作用域问题)。 -- **有组合应答者时录制的钩子产生的 ask**:升级场景录制了人类提示的协议格式(wire format),而当前钩子 fixture(测试前置数据)固定的是无服务拒绝;二者组合的生产者/应答者路径仍由单元测试覆盖。 +- **`allow_always` 授权存储**:兑现持久授权意味着设计存储、作用域标识(调用?路径?前缀?会话?时间窗口?)和撤销;在设计完成之前,只展示一次性选项([沙箱 Agent Note](2026-07-06-sandbox.md) § Escalation 记录了开放的作用域问题)。 +- **通过组合应答者录制由钩子驱动的 `ask`**:人类提示协议格式已通过沙箱示例的升级分支录制。钩子矩阵中的 `hook-cc-pretool-ask` 固定无 ApprovalService 时的后备拒绝,而钩子生产者与应答者的组合仍留在单元测试层。 - **将子 agent 的审批路由到父会话**:`subagent-acp` 的子侧自动应答自己的 `permission` 请求;将其呈现给父会话的编辑器是独立的设计。 ## 曾考虑的替代方案 @@ -103,16 +102,18 @@ ACP 桥找到拥有该会话的编辑器,为该 `callId` 发送 `session/reque ## 后果 -- 只有 `allowed-once` 才会派发被询问的操作;缺失、拒绝、取消或应答失败的路径一律拒绝。 -- 会话归属路由提示、策略和审计事件,不跨越编辑器会话。 -- 被接受的请求追加一对持久审计事件;模型只看到最终的工具结果。 -- 没有该服务的部署不产生审批提示或审计事件,在工具边界拒绝每一个 `ask`。 +实现后的契约由「测试」一节所列套件固定: + +- `allowed-once` 派发一次操作;其他所有结果都以不同原因拒绝,而 `'never'` 会在提示前拒绝。 +- 缺失、外部、无 agent、抛异常、无效或断开连接的应答路径都会失败关闭。 +- 成功的请求按精确 agent 归属路由,并追加一对可回放、对模型不可见的审计事件;空闲时和提交前失败的请求会拒绝。 +- ACP 归属把提示限制在其会话内,而没有该服务的部署不产生提示或审计事件。 代价与已接受的局限: - **两个急于决策的应答者竞争同一槽位。** 兄弟插件的监听器顺序不确定,seam 无法仲裁竞争的终端应答者。通过约定缓解(每个部署一个终端应答者;仅对「先决策或委派」门禁使用 `prepend`),而非事件总线不具备的优先级机制。 - **生产环境验证依赖单一组合。** `ask` 有两个生产者家族——钩子桥通过 `tools/pre-execute`,沙箱升级通过自己的门禁——协议格式录制在沙箱示例的快照套件中;因此在更多部署组合它之前,seam 的真实覆盖面就是这一种组合。 -- **归属以 `Agent` 对象标识为键。** 应答者通过桥已有的 WeakMap 解析会话;当前所有路径在 loop 和各 seam 之间传递同一对象,但未来如果某个边界克隆或代理了 agent,桥会委派并失败关闭——安全,但静默无 UI——届时需要改用 session-id 匹配。 +- **归属以 `Agent` 对象标识为键。** 应答者先在 `agent.session.id` 处解析正向会话映射记录,再要求该记录拥有精确的 agent 对象;当前所有路径在 loop 和各 seam 之间传递同一对象,但未来如果某个边界克隆或代理了 agent,桥会委派并失败关闭——安全,但静默无 UI——届时需要另一种归属契约。 ## FAQ @@ -120,10 +121,10 @@ ACP 桥找到拥有该会话的编辑器,为该 `callId` 发送 `session/reque - **授权能持久化吗——「始终允许」?** 不能。`allowed-once` 仅授权单次被询问的操作,服务在请求之间不存储任何内容;`allow_always` 在授权存储设计完成之前刻意不展示(§ 延后)。 - **模型看到审批的什么?** 只看到发起方从结果派生的工具结果——审计对永远不进入 transcript(文本记录)。三种非授权原因各不相同,模型可以区分人类说「不」、提示被关闭、通道缺失。 - **谁决定一次调用是否需要 ask?** 策略生产者:返回 `permissionDecision: ask` 的钩子、任何 `tools/pre-execute` 监听器、或沙箱升级门禁。seam 和桥只负责路由和应答;二者都不注入自己对「什么值得弹出提示」的判断。 -- **用户关闭提示或轮次在 ask 进行中中止时会发生什么?** 关闭映射为 `cancelled` 并携带自己的拒绝文本。已中止的 signal 直接结算为 `cancelled` 而不派发;ask 进行中的中止丢弃迟到的应答——无论哪种情况都恰好一对审计事件,绝不会两对。 +- **用户关闭提示或轮次在 ask 进行中中止时会发生什么?** 关闭映射为 `cancelled` 并携带自己的拒绝文本。已中止的 signal 直接结算为 `cancelled` 而不派发;ask 进行中的中止丢弃迟到的应答。当两个审计追加都提交时,任一路径都记录恰好一对事件,绝不会两对。 - **如果客户端以 harness 从未提供的选项应答呢?** 除已提供的 `allow_once` 之外的任何选项都映射为 `rejected`——来自不合规客户端的未知 optionId 永远不能授权。 - **subagent 的审批如何路由?** 没有应答者拥有的 agent 穿过整个 waterfall 委派并失败关闭——进程内 subagent 被刻意设计为不可应答。`subagent-acp` 的子侧自动应答是独立的;将子 agent 的 ask 路由到父会话的编辑器已延后(§ 延后)。 -- **`policy: 'never'` 在运行时实际改变了什么?** 服务在派发任何应答者之前,将该会话的每次 ask 解析为 `rejected`(在服务内部,因此没有注册顺序能绕过它);系统提示词声明该策略;切换在边界处被叙述;每次自动拒绝仍落一对审计事件。 +- **`policy: 'never'` 在运行时实际改变了什么?** 服务在派发任何应答者之前,将该会话的每次 ask 解析为 `rejected`(在服务内部,因此没有注册顺序能绕过它);系统提示词声明该策略;切换在边界处被叙述;每次成功的自动拒绝都会记录审计对。 - **热重载或 UI 插件在会话中途卸载时会发生什么?** 应答者随其拥有的 fiber 一起 dispose,因此下一次 ask 降级为 `unavailable` 而非挂在死通道上;重新挂载会重新注册应答者,无需追赶状态。 - **用户在哪里看到自己在批准什么?** 在工具调用本身:提示通过 `callId` 附着在已流式输出的调用上(包含参数),并添加发起方的人类可读 `reason`;请求本身不携带参数副本。 @@ -132,7 +133,7 @@ ACP 桥找到拥有该会话的编辑器,为该 `callId` 发送 `session/reque 本设计复用或对照的仓库内先例: - `fs/write-intent` 门禁(`packages/fs/fs/`)——文档化的单占用决策槽 waterfall 语义(先到先得,通过 `next()` 委派),应答者契约复用了它。 -- `hook/invoked`/`hook/result`——仅日志审计对先例,`approval/asked`/`approval/decided` 沿用了它;[钩子桥 RFC](2026-06-30-hook-bridges.md) 交付了 `permissionDecision: ask`,即第一个生产者。 -- [拦截 seam RFC](2026-06-30-interception-seams.md)——`tools/pre-execute` 的 `allow`/`deny`/`ask` 词汇,本 seam 服务其中的 `ask`。 -- [ACP 支持 RFC](../../implemented/feature/2026-06-14-acp-agent-client-protocol.md)——应答者路由所经过的 `WeakMap<Agent, sessionId>` 归属 seam;[多会话 RFC](../../implemented/feature/2026-06-14-acp-multi-session.md)——本设计实现的每会话权限归属阻塞项。 +- `hook/invoked`/`hook/result`——仅日志审计对先例,`approval/asked`/`approval/decided` 沿用了它;[钩子桥 Agent Note](2026-06-30-hook-bridges.md) 交付了 `permissionDecision: ask`,即第一个生产者。 +- [拦截 seam Agent Note](2026-06-30-interception-seams.md)——`tools/pre-execute` 的 `allow`/`deny`/`ask` 词汇,本 seam 服务其中的 `ask`。 +- [ACP 支持 Agent Note](2026-06-14-acp-agent-client-protocol.md)——应答者路由时对正向会话映射执行的精确 agent 归属检查;[多会话 Agent Note](2026-06-14-acp-multi-session.md)——本设计实现的每会话权限归属阻塞项。 - 机会性 `ctx.get()` 消费模式(`tool-bash` 的 owner-token 查找、loop 的持久化探测)——`dsh-tools` 消费该 seam 而不阻塞其 fiber 的方式。 diff --git a/.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml b/.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml index 53215fce5e..d232083e19 100644 --- a/.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.i18n.yaml @@ -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 -2026-07-06-explicit-tool-order.md: b5f37239efc856866f08d93ab80eba91145a34db -2026-07-06-explicit-tool-order.zh.md: eca75499c2505c9cac0135ddb2ffc8cdd989b100 +2026-07-06-explicit-tool-order.md: bd6d0a04aa470ca33e618957ae1f08c1ef15fcfe +2026-07-06-explicit-tool-order.zh.md: b5600b54537319763e2bf7d54748f5c637461cbd diff --git a/.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.zh.md b/.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.zh.md index eca75499c2..b5600b5453 100644 --- a/.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.zh.md +++ b/.agents/notes/implemented/feature/2026-07-06-explicit-tool-order.zh.md @@ -1,4 +1,4 @@ -# RFC: 显式的模型侧工具顺序 +# Agent Note: 显式的模型侧工具顺序 Status: implemented @@ -21,9 +21,9 @@ Status: implemented `assemble()` 在 `system-prompt/assemble` waterfall(瀑布式事件)之前对提供方工具进行规范化排序,从源头消除注册顺序的差异。waterfall 从这个确定性列表开始;不变的顺序随后流入请求头、冻结的请求和重建检查,无需 loop 特有的排序逻辑。 -范围刻意收窄:本 RFC 修复的是注册顺序竞态,而非插件行为。`system-prompt/assemble` 的监听器仍然可以添加、移除或重排工具——正如它可以在 section 排序之后编辑 section——并对自身输出的确定性负责;waterfall 契约已经要求监听器是确定性的(可重建性不变式会捕获在构建与回放之间行为不一致的监听器)。 +范围刻意收窄:本 Agent Note 修复的是注册顺序竞态,而非插件行为。`system-prompt/assemble` 的监听器仍然可以添加、移除或重排工具——正如它可以在 section 排序之后编辑 section——并对自身输出的确定性负责;waterfall 契约已经要求监听器是确定性的(可重建性不变式会捕获在构建与回放之间行为不一致的监听器)。 -配置传递沿用 `persona` 的先例,`toolOrder` 与之并列:应用配置(`dsh-stdio-demo`、`dsh-acp-demo`)接受该键,并通过 `dsh-agent-spine-demo`(其 schema 是各所有者 schema 的交集)转发给 `SystemPrompt` 子服务。有一个 schemastery 细节至关重要:schemastery 数组默认为 `[]`,但省略的 `toolOrder` 必须保持 ABSENT(= 字典序),而不是变成一个显式配置的空列表(无效——缺少 rest 条目),因此链路上每个 schema 都将默认值强制为 `undefined`。 +配置传递沿用 `persona` 的先例,`toolOrder` 与之并列:TUI、Headless 和 ACP 应用配置接受该键,并通过 `dsh-agent-spine-demo`(其 schema 是各所有者 schema 的交集)转发给 `SystemPrompt` 子服务。有一个 schemastery 细节至关重要:schemastery 数组默认为 `[]`,但省略的 `toolOrder` 必须保持 ABSENT(= 字典序),而不是变成一个显式配置的空列表(无效——缺少 rest 条目),因此链路上每个 schema 都将默认值强制为 `undefined`。 ## 曾考虑的替代方案 @@ -34,13 +34,14 @@ Status: implemented - **在 `LlmService` 上加配置 + `orderTools()` 方法,由 loop 在记录 header 前调用**:可行,但仅为在远处应用一个策略就增加了一个公开服务方法和一处 loop 改动;每个未来的请求组合者都必须记得调用。在列表诞生处进行规范化使得无序列表不可表示,且零新增接口。 - **在 `llm.stream()` 内部规范化**:在 header 事件已记录之后才运行(抖动仍然存在),且需要重建深度冻结的信封,静默地解除了重建不变式。 - **穷举列表(无 rest 条目)**:每个新加载的工具插件都会导致启动失败;强制的 rest 条目使未列出的工具保持确定性,且其位置是显式的。 -- **启动时校验(由 `dsh-app-boot` 在 `loader.await()` 之后调用 `SystemPrompt.assertToolOrderSatisfied()`)**:能将错误配置变为启动时死亡而非首轮次失败,但代价是一个公开服务方法加上通用启动胶水对单个服务的结构耦合,且无法替代组装时检查(嵌入式调用者从不运行 app boot;注册在 boot 之后仍会变化)。也没有现成事件可以承载该检查:Cordis v4 没有 ready 类事件,`loader/entry-init`/`internal/status` 在加载中途触发(与工具注册存在竞态——正是本 RFC 要消除的熵源),而 agent 生命周期事件不会早于组装。在 `assemble()` 设置单一执行点被判定值得接受较晚的失败时刻。 +- **启动时校验(由 `dsh-app-boot` 在 `loader.await()` 之后调用 `SystemPrompt.assertToolOrderSatisfied()`)**:能将错误配置变为启动时死亡而非首轮次失败,但代价是一个公开服务方法加上通用启动胶水对单个服务的结构耦合,且无法替代组装时检查(嵌入式调用者从不运行 app boot;注册在 boot 之后仍会变化)。也没有现成事件可以承载该检查:Cordis v4 没有 ready 类事件,`loader/entry-init`/`internal/status` 在加载中途触发(与工具注册存在竞态——正是本 Agent Note 要消除的熵源),而 agent 生命周期事件不会早于组装。在 `assemble()` 设置单一执行点被判定值得接受较晚的失败时刻。 ## 后果 - 每个由注册表构建的组装在任何宿主上都以确定性工具顺序开始;在没有专家监听器刻意改变的情况下,每个 `request/header` 事件和模型请求都继承该顺序。CI 与本地之间的注册顺序翻转从结构上被消除,默认为字典序。 - 初始 `PromptAssembly.tools` 是权威的,因此 waterfall 监听器从模型侧顺序开始;提供方注册顺序在该协作 seam 之前无处可观测。 -- 步骤之间的纯工具重排只能表示为 `request/header` 的 `'fallback'` 快照(按名称索引的 `ToolsDelta` 无法表达它);在稳定的权威顺序下,这种重排在实践中不再发生,因此 fallback 路径仅作为安全阀存在。 +- 快照套件中唯一固定请求头的 fixture(`text-turn`)携带新的权威工具顺序;按照固定请求头设计,其他 ACP 快照仍将大块 header 清洗为 `{{system}}`/`{{tools}}`。 +- 步骤之间的纯工具重排与其他 header 变更一样记录:一份原因是 `'change'` 的完整 `request/header` 快照。稳定的权威顺序会防止注册时序在普通路径上制造这类变化。 - `toolOrder` 键沿 app → `agent-core` → `SystemPrompt` 的转发链传递,因此部署时将其放在 app 配置中 `persona` 旁边即可;`dsh-llm` 和 agent loop 无需改动。 - `toolOrder` 中拼错或未加载的工具名称在 prompt 组装时使轮次失败,而非启动时:loop 在轮次内部组装(`turn/start` 之后、`step/start` 之前),因此拒绝到达轮次的外层 catch——轮次以 `error` 原因平衡关闭并携带错误消息,`agent/error` 镜像该消息,不打开步骤,不记录 `request/header`,不向适配器发出请求,agent 回到空闲状态。每个轮次都以相同方式失败,直到配置被修正;进程本身保持运行(符合仓库规则:显式配置引用不得被静默忽略——执行点是组装,因为不存在更早的通用时刻)。 - 工具提供方返回保留的 rest 条目名称时,其 prompt 组装失败形态与未知的已列名称相同。这防止哨兵值变成一个歧义的真实工具,并保持「从不丢弃工具」的排序契约。 diff --git a/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml b/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml index 87137ea20f..9257bc6041 100644 --- a/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml @@ -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 -2026-07-06-sandbox.md: 0df97717c9166d5160189c840b108acecd3d3291 -2026-07-06-sandbox.zh.md: 164e44f6b7c84d8f279b0146cc3c74299a51d1fa +2026-07-06-sandbox.md: 738a1796b047561b861fc237154210659515bd6f +2026-07-06-sandbox.zh.md: 6843ef96413c00a12a2d1c6b70d2c5b90c6e02f7 diff --git a/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md b/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md index 164e44f6b7..6843ef9641 100644 --- a/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md +++ b/.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md @@ -1,4 +1,4 @@ -# RFC: 子进程沙箱——约束 seam、原生 runner、升级机制与按会话模式 +# Agent Note: 子进程沙箱——约束 seam、原生 runner、升级机制与按会话模式 Status: implemented @@ -14,7 +14,7 @@ harness 是一个 SDK,因此约束必须是开发者可组合的能力:是 ## 决策 -一个 seam、一条按平台的本地后端链、一个消费方,加上两个上层杠杆:按调用的升级路径与按会话的运行时模式。以下所有内容均从叶子 `cordis.yml` 组合而来;不触及 `agent-loop`。范围有意限定:本 RFC 命名但不设计的阶段——按会话工作区根目录、跨工具族 fs 强制、`subagent-acp` 消费方、更多环境、Windows 链——列在 § 延迟阶段,各自是后续设计,而非配置旋钮。 +一个 seam、一条按平台的本地后端链、一个消费方,加上两个上层杠杆:按调用的升级路径与按会话的运行时模式。以下所有内容均从叶子 `cordis.yml` 组合而来;不触及 `agent-loop`。跨工具族 fs 强制与按会话工作区根目录已经作为后续设计落到同一策略载体上;剩余阶段——`subagent-acp` 消费方、更多环境与 Windows 链——仍列在 § 延迟阶段。 ### 部署方式 @@ -29,7 +29,7 @@ harness 是一个 SDK,因此约束必须是开发者可组合的能力:是 mode: workspace-write # the deployment default every session starts from workspaceRoot: !!js process.cwd() # the boundary workspace-write may write under - id: approval - name: '@deepseek-ai/dsh-user-approval' # the escalation gate's channel (the approval RFC) + name: '@deepseek-ai/dsh-user-approval' # the escalation gate's channel (the approval Agent Note) config: policy: ask - id: permission @@ -50,7 +50,7 @@ OS 子进程约束适用于 bash 执行器(包括钩子命令),后续还 #### seam:`ctx.sandbox` -`dsh-sandbox` 拥有词汇和 `SandboxProvider` 契约:`confine(argv, policy)` 返回调用方应当 spawn 的替代 argv(经过包装,使进程及其所有子进程在约束下运行),加上所选后端达到的 `enforcement` 完整度、其拒绝方言(`denialSignatures`,该后端内核在拒绝文件操作时打印到 stderr 的子串)、以及其 runner 失败方言(`runnerFailureSignatures`,runner 本身失败——因而命令从未运行——时的自我标识方式);没有可用后端时抛出失败关闭的 `SANDBOX_UNAVAILABLE` 错误,绝不静默放行。词汇:`SandboxMode`(`read-only` / `workspace-write` / `danger-full-access`,仅限文件操作——不声称覆盖网络和进程可见性)、`SandboxEnforcement`(`full` / `partial`)、`SandboxPolicy`(mode + workspace root)。 +`dsh-sandbox` 拥有词汇和 `SandboxProvider` 契约:`confine(argv, policy)` 返回调用方应当 spawn 的替代 argv(经过包装,使进程及其所有子进程在约束下运行),加上所选后端达到的 `enforcement` 完整度、其拒绝方言(`denialSignatures`,该后端内核在拒绝文件操作时打印到 stderr 的子串)、以及其 runner 失败方言(`runnerFailureSignatures`,runner 本身失败——因而命令从未运行——时的自我标识方式);没有可用后端时抛出失败关闭的 `SANDBOX_UNAVAILABLE` 错误,绝不静默放行。词汇:`SandboxMode`(`read-only` / `workspace-write` / `danger-full-access`,仅限文件操作——不声称覆盖网络和进程可见性)、`SandboxEnforcement`(`full` / `partial`)、`SandboxExecutionPolicy`(每次能力调用的完整 mode + workspace root)以及 `SandboxPolicy`(提供给约束后端的子集)。 策略随每次调用而非提供方携带:两个消费方可以在同一时刻以不同策略约束(bash 在 `read-only` 下运行,而一个受约束的子 agent 保持其状态目录可写),且经批准的升级重试是一次带有更宽策略的新调用——在配置固定的提供方模式下无法表达。 @@ -64,29 +64,27 @@ OS 子进程约束适用于 bash 执行器(包括钩子命令),后续还 launcher 是一个约 300 行的 C 程序(纯 C11,直接使用 Landlock UAPI——除静态链接的 musl 外无其他库,因此审计面仅为该文件加内核的稳定 syscall 契约):`--ro <path>` / `--rw <path>` 授权,`--`,被包装的 argv;它在自身上安装规则集并 `exec`(规则集跨 `execve` 继承,且它在限制前设置 `no_new_privs`);`--probe` 在一个短生命周期子进程中强制最大规则集,仅当内核确实强制时才以 0 退出;launcher 失败以 125 退出且不 exec。 -Landlock launcher 通过 [`node-addon-landlock-run`](https://www.npmjs.com/package/node-addon-landlock-run) 交付,平台二进制由 npm 选择。该包(package)拥有路径解析、探测和 CLI flag;harness 将沙箱模式映射为授权。将入口点与其二进制一起版本化,使探测解析和启动语法保持对齐。 - -FIXME: Revisit the separate-repository boundary and try to maintain the launcher source and its platform package family inside this monorepo, so the native release surface and harness contract evolve together. +Landlock launcher 源码和包工作区位于 `native/landlock-run`,与 harness 消费方同仓。独立的 [`node-addon-landlock-run`](https://github.com/deepseek-harness/node-addon-landlock-run) 仓库是用于打包并发布 npm 包族的发布镜像;导出流程归 `native/README.md` 所有。平台二进制由 npm 选择,入口包拥有路径解析、探测和 CLI flag,而 harness 将沙箱模式映射为授权。将入口点与其二进制一起版本化,使探测解析和启动语法保持对齐。 后端 profile 共享模式契约但在必要的主机授权上有所不同。Landlock 和 Seatbelt 在 read-only 模式下仅允许 `/dev/null`;workspace-write 还允许各自所需的主机临时目录根。每次包装携带后端特定的拒绝签名。Landlock 在较旧的 ABI 无法管控所有操作时报告 partial enforcement,而成功的 bwrap 和 Seatbelt profile 报告 full enforcement。 #### bash 消费方 -`dsh-bash-sandbox` 复用本地进程执行,并请求 `ctx.sandbox` 包装确切的 bash argv。内核拒绝是独立于退出状态的结果事实,仅从所选包装的 stderr 方言推断。Runner 失败优先于拒绝,因为它意味着命令从未运行:前台调用抛出 `SANDBOX_UNAVAILABLE`,而已结算的后台任务为 `bash_output` 设置 `sandbox.runnerFailed`。这使损坏的约束与任务失败和强制拒绝保持区分。 +`dsh-bash-sandbox` 扩展 `LocalBashExecutor`,并把即将 spawn 的确切 `['bash', '-c', command]` argv 交给 `ctx.sandbox`。拒绝是与其他结果正交的事实,依据当前 runner 的 stderr 方言保守分类。Runner 失败优先于拒绝:前台执行抛出 `SANDBOX_UNAVAILABLE`;结算后的 `BashProcess` 会盖章 `sandbox.runnerFailed`,bash 生产者再通过通用 `task_output` 渲染它。 模型看到的仅是结果事实:静态工具描述解释拒绝标记(`[sandbox: file access denied under <mode> mode]`),鼓励尝试可能被拒绝的命令,并禁止绕过拒绝重试;当升级字段被公布时,被拒绝的结果还额外携带升级提示本身,使被认可的同轮次重试在决策点被提示,而非依赖模型回忆描述(§ 升级机制)。没有提示词段落声明沙箱模式(§ 按会话模式)。 #### 升级机制:拒绝后一次经批准的更宽重试 -`BashExecRequest.sandboxMode` 是可选的按调用输入;解析后的 spec 使该字段显式。`BashExecutor.sandboxMode` 公布已挂载的执行器能否兑现它,因此只有约束组合才暴露升级。seam 接受任何显式模式;工具拥有「仅更宽」的升级规则。非沙箱执行器诚实地保持无约束。 +`BashExecRequest.sandboxPolicy` 是可选的完整按调用输入;解析后的 spec 使该字段显式。`BashExecutor.sandboxMode` 仍是公布已挂载执行器能否兑现该策略的能力事实,因此只有约束组合才暴露升级。seam 接受任何显式策略;工具拥有会话解析和「仅更宽」的升级规则。非沙箱执行器诚实地保持无约束。 -`SandboxBashExecutor.resolve()` 盖章有效模式——升级授权 > 会话覆盖 > 配置默认——使 `run()`/`start()` 读取 spec 而非配置。`danger-full-access` 分支、confine 调用和结果事实都以 spec 的模式为键,且按任务的事实 map 携带每个任务的模式及其包装事实(`notifyTaskDone()` 从 map 条目盖章):一次升级调用——前台或后台——报告它实际运行的模式,而每个邻居保持自己的。 +`ctx.sandboxPolicy.resolve()` 在执行器运行前盖章完整执行策略——显式升级模式 > 会话覆盖 > 配置默认值,且 `SessionHeader.cwd` > 配置的后备根目录。`SandboxBashExecutor.resolve()` 在 spec 上保留该策略,或为直接的无 agent 调用方提供部署后备值,使 `run()`/`start()` 永不读取可变会话状态。每进程包装事实以返回的 `BashProcess` 为键;`onProcessDone()` 在 `done` 结算前分类 stderr 并给该句柄盖章,因此重叠进程各自保留自己的模式和 runner 方言。 当约束执行器被挂载时,`bash` 公布配对的 `sandbox_permissions` 和 `justification` 字段。schema 暴露完整的封闭升级词汇,因为有效模式是按会话的;执行拒绝任何不严格宽于该调用有效模式的目标。批准在执行之前解析。`allowed-once` 仅将授权模式盖章到该请求上,而 `rejected`、`cancelled`、`unavailable`、缺失的 approval 服务或缺失的 agent 都以各自不同的结果文本失败关闭。授权不持久化。 升级是对被拒绝命令的同轮次重试,使用最窄的足够 `sandbox_permissions` 和一个 `justification`;批准提示是同意步骤。它必须基于实际的拒绝,除非会话已观察到相同的被拒绝访问;禁用或被拒绝的批准终结该命令。重试、批准决策和结果使用既有的工具和批准事件。`dsh-tool-bash` 拥有请求动作,因为执行器 seam 既没有 agent 也没有用户交互所需的 call id。 -留待后续阶段处理:授权的范围标识超出沙箱模式之外是什么——确切的调用、路径、命令前缀、会话、时间窗口——这是 `allow_always` 授权存储在该选项可被公布之前必须回答的问题;以及如何为通过 `bash_output` 延迟到达的 `run_in_background` 拒绝定义升级。 +仍未决定:持久授权超出沙箱模式之外的作用域标识是什么——确切调用、路径、命令前缀、会话或时间窗口——这是公布 `allow_always` 选项之前必须回答的问题。 #### 按会话模式:会话日志即存储 @@ -100,12 +98,12 @@ effective(session) = findLast(the session's own knob events)?.value ?? the compo ```ts interface SessionEventMap { - 'bash/sandbox-mode': { mode: 'read-only' | 'workspace-write' | 'danger-full-access' } + 'sandbox/mode': { mode: 'read-only' | 'workspace-write' | 'danger-full-access' } 'approval/policy': { policy: 'ask' | 'never' } } ``` -每个拥有者导出相同的三件套:事件声明、纯 fold(`effectiveSandboxMode(events)` / `effectiveApprovalPolicy(events)`——一个 `findLast`,类型化到领域的封闭联合),以及唯一的写入路径(`setSandboxMode(session, mode)` / `setApprovalPolicy(session, policy)`——切换即其事件;没有任何东西在带外修改状态)。无共享拥有者服务、无通用 facts map、无注册表:第三个旋钮只需将约 40 行模式复制到自己的包中。执行在两侧都遵循 fold——bash 工具的按调用盖章将其作为 § 升级机制优先级链的中间层读取,approval seam 的 `'never'` 门控是[批准 RFC](2026-07-06-approval-seam.md) 同一模式的另一侧。 +每个拥有者导出相同的三件套:事件声明、纯 fold(`effectiveSandboxMode(events)` / `effectiveApprovalPolicy(events)`——一个 `findLast`,类型化到领域的封闭联合),以及唯一的写入路径(`setSandboxMode(session, mode)` / `setApprovalPolicy(session, policy)`——切换即其事件;没有任何东西在带外修改状态)。无共享拥有者服务、无通用 facts map、无注册表:第三个旋钮只需将约 40 行模式复制到自己的包中。执行在两侧都遵循 fold——bash 工具的按调用盖章将其作为 § 升级机制优先级链的中间层读取,approval seam 的 `'never'` 门控是[批准 Agent Note](2026-07-06-approval-seam.md) 同一模式的另一侧。 沙箱模式不在提示词中叙述;拒绝结果在需要时报告模式,避免基于常驻标签的预防性拒绝。批准策略不同:只有 `'never'` 被声明,因为自动拒绝在行为上与用户的「不」无法区分。策略变更通知被合并,由下一个 pre-step 递送,重启后有基于日志的回退。通知来源从事件位置推断:最后一个 request header 之后的旋钮事件是用户驱动的;未记录的漂移是运维人员或配置驱动的。 @@ -115,23 +113,19 @@ interface SessionEventMap { #### 进程内工具 -fs/web/todo 在进程内执行,因此它们的沙箱语义是各自 seam 层面的策略:fs 意图门控按共享模式词汇决策(§ 延迟阶段,跨工具族),使 `read-only` 成为真正的边界而非仅限 bash 的近似——在此之前契约诚实地如此声明。没有通用的按工具沙箱运行时:主机中介的工具仅通过返回主机验证的声明式效果来离开进程,那是一次重写而非包装。 - -FIXME: Revisit this tool-local boundary. The follow-up design needs to determine whether sandboxing becomes a global harness capability that applies uniformly to every tool, instead of expressing in-process enforcement independently at each tool seam. +fs/web/todo 在进程内执行,因此它们的沙箱语义是各自 seam 层面的策略。fs seam 现在通过沙箱提供方强制共享模式词汇(`dsh-fs-sandbox` 按模式限制 write/edit;见[跨工具族 fs 沙箱 Agent Note](2026-07-14-cross-family-fs-sandbox.md)),因此 `read-only`/`workspace-write` 对文件系统工具也是真实边界,而非仅限 bash 的近似。web/todo 仍不受限制(web 的唯一效果是网络,不在文件效果模式词汇内)。没有通用的按工具沙箱运行时:主机中介的工具仅通过返回主机验证的声明式效果来离开进程,那是一次重写而非包装——后续设计选择了一个共享策略归属 `ctx.sandboxPolicy`,由各 seam 强制,而不是统一包装器。 ### 测试 -- **单元测试:** 固定平台选择和 profile、失败关闭的 runner 分类、按调用事实、升级验证和结果、permission preset fold 和写入透传、叙述器合并、ACP 公布和验证、轮次封闭的配置写入。 -- **Keyless 真实 runner:** 在提供方和 bash 消费方层面对 bwrap、Landlock 和 Seatbelt 执行真实文件系统效果测试;packed-install 覆盖率证明注册表 launcher 保持可执行。真实 ACP 组合固定 permission 切换并拒绝未知 preset。CI 拒绝静默全跳过。 +- **单元测试:** 固定平台选择和 profile、失败关闭的 runner 分类、按调用的模式/根目录解析、按进程事实、升级验证和结果、permission preset fold 和写入透传、叙述器合并、ACP 公布和验证、轮次封闭的配置写入。 +- **Keyless 真实 runner:** 在提供方和 bash 消费方层面对 bwrap、Landlock 和 Seatbelt 执行真实文件系统效果测试;一个真实 Cordis 上下文通过已交付的 bash 和 fs 工具并发驱动两个项目会话,证明在自身根目录写入成功、在兄弟根目录写入被拒绝。Packed-install 覆盖率证明注册表 launcher 保持可执行。真实 ACP 组合固定 permission 切换并拒绝未知 preset。CI 拒绝静默全跳过。 - **With-key:** 驱动真实模型、runner、bridge 应答器和磁盘效果通过授权和拒绝的升级;不可用的凭证或 runner 自动跳过。 -- **快照:** 固定 permission config-option 协议格式(wire format)、preset 和旋钮事件、prompt delta 和通知、以及两个脚本化的 approval 分支。快照模式以无约束启动,使无关 fixture(测试前置数据)保持平台无关;策略场景显式切换。真实拒绝 stderr 留在平台测试中,因为其方言是 runner 特定的。 +- **快照:** 固定 permission config-option 协议格式(wire format)、preset 和旋钮事件、prompt delta 和通知、以及两个脚本化的 approval 分支。一个真实 ACP 示例场景把会话放在用户主目录下,同时让部署后备根目录指向 `/tmp`,然后固定一次成功的 workspace-write 变更;这能区分会话根目录解析与进程后备值,而不依赖 runner 特定的拒绝文本。其他快照以无约束启动,使无关 fixture(测试前置数据)保持平台无关;策略场景显式切换。 ## 延迟阶段 每个阶段在被拾起时获得完整设计,对照当时的代码验证,并在其涉及的层级带上单元测试、真实 API e2e 和快照覆盖率落地。 -- **按会话工作区根目录**——执行器的写入边界在其生命周期内保持配置固定,而每个 ACP 会话有自己的 cwd;按会话根目录一旦设计完成即搭载同一个按调用策略载体。 -- **跨工具族边界**——fs 意图门控按共享模式决策,使 `read-only`/`workspace-write` 成为 bash 之外的真正边界。 - **第二个消费方**——`subagent-acp` 可选地约束子 agent(按调用策略;默认无约束——子 agent 必须写入自己的持久化)。 - **更多环境**——环境一致的能力组示例(如 bash+fs 对一个容器)。 - **Windows 链**——`PLATFORM_CHAINS.win32` 保留为空(失败关闭);填充它意味着来自 AppContainer/restricted-token 家族的约束 runner,从其自己的仓库按 `node-addon-landlock-run` 模板交付,加上其 profile 方言和拒绝/runner 失败签名。 @@ -157,7 +151,7 @@ FIXME: Revisit this tool-local boundary. The follow-up design needs to determine - **通用 `env/state` facts map 加拥有者服务**:否决。approval 和 sandbox 独立组合,因此任何一方的状态都不应拖入第三个包;单键 fold 各自是一个 `findLast`,拥有者服务自然消解;没有跨旋钮的不变式,因此原子多键补丁无收益。 - **通过 `agent/user-message` + 总线事件叙述**:否决。它预设了一个不存在的轮次入口 seam(真正的 seam 是 `agent/prompt-submit`),而 pre-step 的位置以一个监听器同时服务合并的轮次入口通知和轮中即时性约束。 - **提示词中常驻声明沙箱模式(+ 切换叙述器)**:先交付后移除,基于实际证据:当每个请求中都有 `Bash commands run under the "read-only" file sandbox.` 时,模型拒绝尝试被拒绝后可升级的工作(首次手动会话中十二个轮次有五个以零工具调用结束),将沙箱变成了软锁定。拒绝标记在需要时命名模式,升级字段承载恢复路径;批准旋钮保留其声明,因为自动拒绝在行为上与人的「不」无法区分。 -- **用专门的簿记事件追踪「上次告知」**:否决。`request/header*` fold 已记录模型看到的确切 prompt;将封闭的候选句子解析回来替代了第二条簿记流——事件仅在它们本身即为存储时才需要。 +- **用专门的簿记事件追踪「上次告知」**:否决。`request/header` fold 已记录模型看到的确切 prompt;将封闭的候选句子解析回来替代了第二条簿记流——事件仅在它们本身即为存储时才需要。 - **ACP session modes 而非 config options**:否决。preset 已经是一个部署定义的 config-option 选择器,且 modes 计划在 ACP v2 中移除。 ## 后果 @@ -170,12 +164,13 @@ FIXME: Revisit this tool-local boundary. The follow-up design needs to determine - N 次空闲切换每个旋钮最多产生一个锚定事件(净零序列不锚定任何事件——客户端回显当前选择的无操作推送不记录任何内容);批准策略切换最多以一条合并通知叙述;轮中沙箱切换由下一次调用的盖章兑现。 - 恢复的会话的覆盖生效并报告给编辑器,无需特殊处理;进程停止期间变更的默认值在会话的首个新请求前被叙述,归因于运维人员。 - 两个并发会话永远看不到彼此的状态、通知或配置选项。 +- 同一个 Cordis 上下文中的两个并发项目会话解析各自独立的工作区根目录;bash 和 fs 写入在调用方会话的 cwd 内成功,对其相邻会话的 cwd 则失败。 - `agent-loop` 未被触及——一切搭载 `systemPrompt.section`、`SessionEventMap` 合并、`agent.inject()`、`agent/pre-step`、`agent/prompt-submit` 和 ACP handler 表面。 代价与已接受的限制: - **单一包装的幻觉被有意放弃。**`tools/pre-execute` 包装加 prompt 约定无法解决沙箱批准——正确的设计需要结构化拒绝、原生 runner 探测、按调用策略承载和一致的跨工具族强制,本设计为此付出了代价。 -- **`read-only` 尚不是跨工具族边界。** 在 fs 意图门控按共享模式决策之前,该声明仅对 bash 成立;契约诚实地如此声明(§ 进程内工具)。 +- **`read-only` 通过后续设计成为跨工具族边界。** 本 Agent Note 最初只交付 bash 强制;[跨工具族 fs 沙箱 Agent Note](2026-07-14-cross-family-fs-sandbox.md) 通过沙箱化的 `ctx.fs` 提供方把同一模式词汇扩展到文件系统工具,并将 mode/root 配置和 `sandbox/mode` 覆盖迁移到 `ctx.sandboxPolicy`(§ 进程内工具)。 - **Windows 没有后端。** 其链槽保留为空——失败关闭,绝不穿透;填充它是延迟阶段。 - **Seatbelt 层级依赖 Apple 已弃用但仍交付的 `sandbox-exec` CLI。** 作为 darwin 的唯一候选,它无需探测即被选中,因此未来移除会在执行时作为 runner 失败分类浮现——重新抛出 `SANDBOX_UNAVAILABLE`,命令从未运行;失败关闭,绝不开放。 - **Landlock 约束的完整度取决于运行内核的 ABI。** 报告为 `enforcement: 'partial'` 而非拒绝——这是有意的权衡,使备选在旧内核主机上仍可用。 @@ -195,8 +190,8 @@ FIXME: Revisit this tool-local boundary. The follow-up design needs to determine - **在没有后端的平台上会发生什么——今天的 Windows?** `confine()` 抛出失败关闭的 `SANDBOX_UNAVAILABLE`,命令永不 spawn;`win32` 是保留的空链,由测试固定为同样失败关闭,直到 Windows runner 填充它(§ 延迟阶段)。 - **`bwrap` 已安装在我的主机上但不可用(禁用了非特权 userns、LSM 拒绝 `mount`)——会发生什么?** 链探测是功能性的——它构建并强制一个真实 profile 而非检查 `--version`——因此存在但不可用的 `bwrap` 探测失败,选择落到注册表安装的 Landlock launcher,结论在提供方生命周期内缓存。 - **沙箱限制网络或进程可见性吗?** 不——`SandboxMode` 仅声称文件操作;bwrap profile 刻意不 unshare pid,没有后端声称网络。网络限制是否成为自己的旋钮留在 § seam 中开放。 -- **哪些工具实际在约束下运行?** 通过 `ctx.bash` 的 OS 子进程——bash 工具,以及传递性的钩子命令。fs/web/todo 在进程内执行,`execve` 包装对它们机械上毫无意义;它们的 `read-only` 语义随跨工具族延迟阶段到来,在此之前契约诚实地声明仅限 bash。 -- **授权的升级会持久化吗?或覆盖后台任务吗?** 都不会:授权被请求它的那次调用(前台或后台)消耗,该次调用报告它实际运行的模式,而每个邻居保持自己的。如何为通过 `bash_output` 延迟浮现的后台拒绝定义升级,留在 § 升级机制中开放。 +- **哪些工具实际在约束下运行?** 通过 `ctx.bash` 的 OS 子进程——bash 工具及传递性的钩子命令——再加上通过沙箱化 `ctx.fs` 提供方运行的文件系统工具(`read`/`write`/`edit`,见[跨工具族 fs 沙箱 Agent Note](2026-07-14-cross-family-fs-sandbox.md)):bash 通过 OS runner 约束,fs 通过进程内路径围栏约束,二者都以同一个 `ctx.sandboxPolicy` 模式为键。web/todo 仍在进程内且不受限制(web 的唯一效果是网络,不在文件效果模式词汇内)。 +- **授权的升级会持久化吗?** 不会。授权由发起请求的确切前台或后台调用消费;每个相邻调用保留自己的有效模式。后续的后台拒绝通过 `task_output` 呈现,并且可以作为一次新的精确命令重试的依据。 - **编辑器的模式切换何时生效?** 轮中:立即追加,由下一次调用的盖章兑现。空闲:保持在 bridge 的会话记录上,在下一次 `agent/prompt-submit` 时锚定到其开放轮次中,N 次切换合并为最多一个事件(净零则无);锚定前崩溃回退它,`session/load` 报告真实状态。模型不被告知——其下一个命令直接在新模式下运行。 - **重启后什么存活——如果运维人员在进程停止期间改了配置默认值呢?** 覆盖从会话日志回放(`effective = fold ?? config`),因此恢复的会话以零追赶机制保持其模式;离线漂移的默认值以与切换相同的方式改变行为(批准策略因被声明,还额外以运维人员/配置归因叙述)。 - **结果上的 `enforcement: 'partial'` 是什么意思?** 所选后端强制其内核 ABI 管控的子集——例如 ABI v3 之前的 Landlock 不管控路径 truncate——并以结构化方式如此声明而非拒绝主机;探测的报告行区分各种情况。bwrap 和 Seatbelt profile 构造上管控所有承诺的文件操作,因此始终报告 `full`。 @@ -205,8 +200,8 @@ FIXME: Revisit this tool-local boundary. The follow-up design needs to determine 本设计复制或对比的仓库内先例: -- [能力 seam RFC](../architecture/2026-06-13-capability-seams.md)——接口/实现/消费方拆分与「不要过早拆分」的时机规则(第二个消费方满足了该规则)。 -- `dsh-bash` 的 request/spec 拆分及其 `owner` 字段([bash 词汇目录](../../../core-data-structures/bash.md))——`sandboxMode` 搭载的按调用载体模板,以及显式 `resolve()` 默认约定。 -- [批准 seam RFC](2026-07-06-approval-seam.md)——升级请求通过的通道;其应答器 waterfall(瀑布式事件)、审计对和单包理由记录在那里。 +- [能力 seam Agent Note](../architecture/2026-06-13-capability-seams.md)——接口/实现/消费方拆分与「不要过早拆分」的时机规则(第二个消费方满足了该规则)。 +- `dsh-bash` 的 request/spec 拆分([bash 词汇目录](../../../../docs/core-data-structures/bash.md))——完整的 `sandboxPolicy` 搭载其按调用载体,以及显式 `resolve()` 默认约定。 +- [批准 seam Agent Note](2026-07-06-approval-seam.md)——升级请求通过的通道;其应答器 waterfall(瀑布式事件)、审计对和单包理由记录在那里。 - [事件溯源会话](../architecture/2026-06-11-event-sourced-sessions.md)与[轮次封闭不变式](../architecture/2026-06-15-turn-enclosure-invariant.md)——按会话模式 fold 所依赖的日志即存储基础,以及锚定设计遵守的提交边界。 -- [拦截 seam RFC](2026-06-30-interception-seams.md)——`tools/pre-execute` 词汇,升级门控刻意不复用它(升级调用没有自己的 pre-execute 时刻)。 +- [拦截 seam Agent Note](2026-06-30-interception-seams.md)——`tools/pre-execute` 词汇,升级门控刻意不复用它(升级调用没有自己的 pre-execute 时刻)。 diff --git a/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml b/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml index 360ea648dc..6d5a63b85f 100644 --- a/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.i18n.yaml @@ -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 -2026-07-07-mcp-client-plugin.md: 99159d6ac31fb8ef74b28a7048392d0e22124b5a -2026-07-07-mcp-client-plugin.zh.md: e4c61f173956a928c4030fc53796324b924f32d9 +2026-07-07-mcp-client-plugin.md: 90c43383882034954f33b79459fac273e60b9e0e +2026-07-07-mcp-client-plugin.zh.md: 49cce88547eb731ae5b5bf168a7a0a4a785efe94 diff --git a/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.zh.md b/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.zh.md index e4c61f1739..49cce88547 100644 --- a/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.zh.md +++ b/.agents/notes/implemented/feature/2026-07-07-mcp-client-plugin.zh.md @@ -1,4 +1,4 @@ -# RFC: MCP 客户端插件——连接外部 MCP 服务器并桥接其工具 +# Agent Note: MCP 客户端插件——连接外部 MCP 服务器并桥接其工具 Status: implemented @@ -8,13 +8,13 @@ Status: implemented harness 此前无法消费 MCP(Model Context Protocol)生态中的工具。MCP 是工具服务器的新兴标准——GitHub、文件系统、数据库、代码搜索以及数百个社区服务器都通过 MCP 暴露工具。用户希望将 harness 指向一个或多个 MCP 服务器,让其工具以原生的模型可见工具形式出现,而无需为每个服务器编写胶水代码。 -`ToolRegistry` 已经接受原始 JSON Schema 工具定义(`dsh-tools` README 中有记录:"Raw JSON-Schema tool definitions (from MCP servers) are still accepted by `ToolRegistry.register()` directly"),扩展实操手册(cookbook)也勾勒了预期模式("MCP | one plugin per server: discover tools → `ctx.tools.register()`")。基础设施已就绪,缺的是桥接插件。 +`ToolRegistry` 已经接受原始 JSON Schema 工具定义(`dsh-tools` README 中有记录:「Raw JSON-Schema tool definitions (from MCP servers) are still accepted by `ToolRegistry.register()` directly」),扩展实操手册(cookbook)也勾勒了预期模式(「MCP | one plugin per server: discover tools → `ctx.tools.register()`」)。基础设施已就绪,缺的是桥接插件。 ## 决策 ### 包 -单个包(package) `@deepseek-ai/dsh-mcp-client`,位于 `packages/mcp/mcp-client/`。不做能力 seam 的三包拆分——可预见范围内不会有第二种 MCP 客户端实现,且约定是"不要预防性拆分"([能力 seam RFC](../../implemented/architecture/2026-06-13-capability-seams.md))。 +单个包(package) `@deepseek-ai/dsh-mcp-client`,位于 `packages/mcp/mcp-client/`。不做能力 seam 的三包拆分——可预见范围内不会有第二种 MCP 客户端实现,且约定是「不要预防性拆分」([能力 seam Agent Note](../architecture/2026-06-13-capability-seams.md))。 ### SDK @@ -22,7 +22,7 @@ harness 此前无法消费 MCP(Model Context Protocol)生态中的工具。M ### 范围 -仅 MCP Client(不含 server 端——ACP 已承担"将 harness 暴露为 agent"的角色)。仅桥接 **Tools**——Resources 和 Prompts 延后处理(它们需要 harness 侧尚不存在的消费机制,且设计空间较大)。 +仅 MCP Client(不含 server 端——ACP 已承担「将 harness 暴露为 agent」的角色)。仅桥接 **Tools**——Resources 和 Prompts 延后处理(它们需要 harness 侧尚不存在的消费机制,且设计空间较大)。 ### 插件形态 @@ -100,7 +100,7 @@ type Config = StdioConfig | StreamableHttpConfig 2. 监听 `notifications/tools/list_changed` → 重新执行同步(dispose 上一代、注册新一代)。确定性命名意味着未变化的工具在重新同步后保持原名。 3. 执行器闭包持有 `rawName`;公开名称永远不发送给服务器,也永远不被解析以还原原始名称。 4. 无 `presentCall`/`presentResult`——ACP 桥接的通用卡片兜底负责渲染。 -5. 工具在系统提示词中是透明的——除名称本身外不附加 "[via MCP]" 标注。 +5. 工具在系统提示词中是透明的——除名称本身外不附加「[via MCP]」标注。 ### 公开名称规范化 @@ -143,7 +143,7 @@ MCP 仅保证工具名在[单个服务器内](https://modelcontextprotocol.io/sp 1. 解析 `rawName`(执行器闭包持有它),以配置的超时时间调用 `client.callTool({ name: rawName, arguments }, { signal: exec.signal })`——公开名称永远不发送给服务器。 2. 映射结果: - 多个 `text` 内容块 → 以 `'\n'` 连接为单个 `TextBlock`(必要原因:`flattenText` 使用 `join('')` 无分隔符,多块会丢失块间边界)。 - - `image` 内容块 → 丢弃并 `ctx.logger.warn`(harness 没有图片内容块类型;[drop-image RFC](../../implemented/simplification/2026-07-04-drop-image-content-block.md))。 + - `image` 内容块 → 丢弃并 `ctx.logger.warn`(harness 没有图片内容块类型;[drop-image Agent Note](../simplification/2026-07-04-drop-image-content-block.md))。 - `isError: true` → 映射到 harness 的 `isError` 结果路径(`{ content: [...], isError: true }`)。 3. 取消:`exec.signal`(来自 agent loop(智能体循环)的取消)透传给 MCP SDK 的 `callTool`,后者向服务器发送 `$/cancelRequest`。 @@ -159,7 +159,7 @@ MCP 仅保证工具名在[单个服务器内](https://modelcontextprotocol.io/sp 2. 后续模型对这些工具的调用 → `ToolNotFoundError` → `isError: true`。 3. 恢复:用户编辑 `cordis.yml`(触发 HMR 重载)或重启 harness。 -这与 ACP subagent 模式一致:"崩溃即终态,报告错误,清理资源,不重试。" +这与 ACP subagent 模式一致:「崩溃即终态,报告错误,清理资源,不重试。」 ## 曾考虑的替代方案 @@ -169,7 +169,7 @@ MCP 仅保证工具名在[单个服务器内](https://modelcontextprotocol.io/sp ### 能力 seam 三包拆分(interface / impl / consumer) -否决。可预见范围内不会有替代的 MCP 客户端实现——MCP 只有一个协议、一个 SDK。约定是"不要预防性拆分",直到出现第二种实现。 +否决。可预见范围内不会有替代的 MCP 客户端实现——MCP 只有一个协议、一个 SDK。约定是「不要预防性拆分」,直到出现第二种实现。 ### 指数退避自动重连 @@ -177,11 +177,11 @@ v1 否决。引入复杂性(工具已注册但暂时不可用的部分可用 ### 桥接 Resources 和 Prompts -延后。Resources 需要 harness 侧的机制来决定何时注入内容(系统提示词?按需?模型触发?)。Prompts 需要 harness 尚不具备的"提示词模板"概念。两者都需要独立设计;Tools 是高价值、低风险的起点。 +延后。Resources 需要 harness 侧的机制来决定何时注入内容(系统提示词?按需?模型触发?)。Prompts 需要 harness 尚不具备的「提示词模板」概念。两者都需要独立设计;Tools 是高价值、低风险的起点。 ### 原始模型可见工具名加可选 `toolPrefix` -否决。这是最初的提案,基于"大多数 MCP 服务器已在工具名中使用语义前缀(如 `github_create_issue`)"这一前提。该前提不成立:官方 GitHub 服务器发布的是 `create_issue`,参考文件系统服务器发布 `read_file`,Sentry 发布 `search_issues`——且上述微软调查表明冲突在生态规模下很常见。冲突时再加前缀(或 warn-and-skip)还会使可用工具集取决于插件加载顺序,且添加不相关服务器时工具可能被静默重命名——在对话中途使会话历史和权限规则失效。所有被调研的多服务器 agent 产品都不使用裸名。 +否决。这是最初的提案,基于「大多数 MCP 服务器已在工具名中使用语义前缀(如 `github_create_issue`)」这一前提。该前提不成立:官方 GitHub 服务器发布的是 `create_issue`,参考文件系统服务器发布 `read_file`,Sentry 发布 `search_issues`——且上述微软调查表明冲突在生态规模下很常见。冲突时再加前缀(或 warn-and-skip)还会使可用工具集取决于插件加载顺序,且添加不相关服务器时工具可能被静默重命名——在对话中途使会话历史和权限规则失效。所有被调研的多服务器 agent 产品都不使用裸名。 ### 仅服务器命名空间(`github__create_issue`,无 `mcp__` 前缀) @@ -201,7 +201,7 @@ v1 否决。它能防止跨服务器冲突,但无法将 MCP 注册与原生 ha - **单元测试**(`tests/mcp-client.spec.ts`、`tests/apply.spec.ts`,mock MCP SDK):`publicToolName` 算法(干净名称、规范化、截断加 hash、确定性、不同标识的分离)、raw 与 public 的协议纪律、跨服务器与原生工具共存、重复 `serverName` 加载失败与预留释放、无效工具列表拒绝、代切换/回滚、重新同步失败时的保留、结果映射、取消、配置 schema 校验。100% 逐文件覆盖率门禁约束该包。 - **E2E**(`tests/mcp-client.e2e.ts`,无需密钥):使用真实 MCP 协议对接仓库内的 fixture(测试前置数据)服务器、`@modelcontextprotocol/server-everything` 和 `@modelcontextprotocol/server-filesystem`(stdio 传输),以及进程内 `StreamableHTTPServerTransport` 服务器(Streamable HTTP 传输)——命名空间下的发现、带点号名称的端到端规范化、执行往返、重复 `serverName` 拒绝、dispose。 -- **快照**:刻意不做。MCP 工具不引入新的 transcript(文本记录)呈现面——它们以原始 `ToolDefinition` 注册,通过 ACP 桥接的通用卡片兜底渲染,该兜底已由桥接的单元测试套件固定(`packages/ui/acp/tests/stream-update.spec.ts`)。将 MCP 服务器添加到快照示例的 `cordis.yml` 会改变已固定的 `text-turn` 系统提示词 fixture(迫使每条录制的 golden 都需要带密钥重新录制),且使每次回放依赖于 spawn 外部 MCP 服务器进程——而新增渲染行为为零。如果后续变更为 MCP 工具引入专属渲染意图,该变更届时自行声明快照覆盖。 +- **快照**:刻意不做。MCP 工具不引入新的 transcript(文本记录)呈现面——它们以原始 `ToolDefinition` 注册,通过 ACP 桥接的通用卡片兜底渲染,该兜底已由桥接的单元测试套件固定(`packages/ui/acp/tests/stream-update.spec.ts`)。将 MCP 服务器添加到快照示例的 `cordis.yml` 会改变已固定的 `text-turn` 系统提示词 fixture(迫使每条录制的预期输出都需要带密钥重新录制),且使每次回放依赖于 spawn 外部 MCP 服务器进程——而新增渲染行为为零。如果后续变更为 MCP 工具引入专属渲染意图,该变更届时自行声明快照覆盖。 ## 后果 diff --git a/.agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml b/.agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml index 02d6f23514..546f331412 100644 --- a/.agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-07-session-prefix.i18n.yaml @@ -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 -2026-07-07-session-prefix.md: 81868c5b0c17c03aa1ebad788c8604dd30d1ce17 -2026-07-07-session-prefix.zh.md: 7d93d8190ce51fcbdc1b67e20fbdb4f4ea8e14c8 +2026-07-07-session-prefix.md: 322413f541706244a8a9a9113c0b79693fe54ccd +2026-07-07-session-prefix.zh.md: ee5e826b18466b20675746aef17fbd67df8cf37e diff --git a/.agents/notes/implemented/feature/2026-07-07-session-prefix.md b/.agents/notes/implemented/feature/2026-07-07-session-prefix.md index 7faf80cf80..322413f541 100644 --- a/.agents/notes/implemented/feature/2026-07-07-session-prefix.md +++ b/.agents/notes/implemented/feature/2026-07-07-session-prefix.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-07-07-session-prefix.zh.md) + ## Problem A plugin often owns a session-stable opener the model must always see — a skills catalog, an AGENTS.md digest, a workspace baseline. Before this seam the harness offered two homes, and both are wrong for that content. The system prompt is one rendered string: message-shaped content (a user-role `<system-reminder>` envelope, a multi-message primer) does not fit it, and providers weight conversation messages differently from system text. Durable history (`agent.inject()`, a `context/message` at session start) makes the opener permanent: every `deriveMessages()` consumer replays it, the compaction retention walk owns it, forks bake it in stale, and a resume cannot refresh it — a catalog captured at session birth outlives the world it described. diff --git a/.agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md b/.agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md index 7d93d8190c..ee5e826b18 100644 --- a/.agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md +++ b/.agents/notes/implemented/feature/2026-07-07-session-prefix.zh.md @@ -1,4 +1,4 @@ -# RFC: 会话前缀——派生历史之前的仅请求消息 +# Agent Note: 会话前缀——派生历史之前的仅请求消息 Status: implemented @@ -8,37 +8,36 @@ Status: implemented 插件经常拥有一段会话级别稳定的开场内容,模型必须始终看到它:技能目录、AGENTS.md 摘要、工作区基线。在引入本 seam 之前,harness 为这类内容提供了两个归属位置,但两者都不合适。系统提示词是一个渲染后的单一字符串:消息形态的内容(user 角色的 `<system-reminder>` 信封、多消息引导序列)放不进去,而且提供方对会话消息和系统文本的权重处理不同。持久化历史(`agent.inject()`、会话启动时的 `context/message`)使开场内容变为永久:每个 `deriveMessages()` 消费方都会回放它,压缩(compaction)的保留遍历拥有它,fork 会将其以陈旧状态固化,resume 也无法刷新它——会话诞生时捕获的目录会比它所描述的世界活得更久。 -显而易见的第三种选项——让插件在请求发出途中编辑 `messages`——被[可重建请求 RFC](../architecture/2026-07-05-reconstructable-requests.md) 禁止:每个由循环构建的请求都是会话日志的纯函数,因此无论哪个通道承载开场内容,都必须精确记录它所发送的内容。缺失的是一个带有持久记录的仅请求消息通道。 +显而易见的第三种选项——让插件在请求发出途中编辑 `messages`——被[可重建请求 Agent Note](../architecture/2026-07-05-reconstructable-requests.md)禁止:每个由循环构建的请求都是会话日志的纯函数,因此无论哪个通道承载开场内容,都必须精确记录它所发送的内容。缺失的是一个带有持久记录的仅请求消息通道。 ## 决策 -`agent/session-prefix` 是 agent 事件映射上的一个 waterfall(瀑布式事件)([`packages/core/agent/src/types.ts`](../../../../packages/core/agent/src/types.ts)):监听器接收一个冻结的空种子并返回扩展(规范的贡献方式是前置插入 `[mine, ...await next()]`,在协议格式上产生注册顺序)。agent loop(智能体循环)([`packages/core/agent-loop/src/loop.ts`](../../../../packages/core/agent-loop/src/loop.ts))在每个循环实例中触发一次,惰性地在实例首次 `agent/pre-step` 之前执行;组合后的列表被深拷贝、深冻结、缓存在实例上,并在该实例发出的每个请求中置于整个派生历史之前——紧接在提供方的 system 槽位之后([协议格式顺序](../../../core-data-structures/core.md#the-request-envelope-llmcallconfig-and-the-logged-header))。 +`agent/session-prefix` 是 agent 事件映射上的一个 waterfall(瀑布式事件)([`packages/core/agent/src/types.ts`](../../../../packages/core/agent/src/types.ts)):监听器接收一个冻结的空种子并返回扩展(规范的贡献方式是前置插入 `[mine, ...await next()]`,在协议格式上产生注册顺序)。agent loop(智能体循环)([`packages/core/agent-loop/src/loop.ts`](../../../../packages/core/agent-loop/src/loop.ts))在每个循环实例中触发一次,惰性地在实例首次 `agent/pre-step` 之前执行;组合后的列表被深拷贝、深冻结、缓存在实例上,并在该实例发出的每个请求中置于整个派生历史之前——紧接在提供方的 system 槽位之后([协议格式顺序](../../../../docs/core-data-structures/core.md#the-request-envelope-llmcallconfig-and-the-logged-header))。 三个属性承载了这一设计: -- **仅请求,记录在 header 中。** `deriveMessages()` 从不返回前缀;它唯一的持久记录是实例锚定的 `request/header` 快照上的 `EpochHeader.messagePrefix`——可重建请求 RFC 已为请求的非历史部分拥有的通道,因此不引入新的会话事件。开发不变式([dsh-invariants](../../../../packages/support/invariants/src/index.ts))对每个循环构建的请求重新计算 `messagePrefix + boundary derivation`;未记录的前缀无法到达协议格式。 -- **按实例冻结。** 复用是结构性的,而非靠纪律保证:缓存的产物在会话中途不可变,因此提供方的 prompt 缓存从构造上成立,前缀以每步零边际成本扩展了可缓存区域。进程重启或 `ctx.agents.resume()` 产生新实例:它重新组合,任何漂移都可追溯地落在 `'resume'` header 快照上。这就是本 seam 创建的路由规则:会话冻结的开场内容走前缀;会话中途变化的内容走仅追加历史通道(`agent.inject()`、`tools/post-execute` 决策的 `additionalContext`、prompt-submit 的 `additionalContext`——[拦截 seam RFC](2026-06-30-interception-seams.md)),每条都是一次性支付的持久 `context/message`,之后被前缀缓存覆盖。 -- **在压力门禁之前组合。** 组合先于实例的首次 `agent/pre-step`,且 seam 将组合值透传:`agent/pre-step` 携带 `sessionPrefix` 参数,`CompactService.compactIfNeeded(agent, fullSystemPrompt, sessionPrefix, signal)` 将其计入 token 压力估算。如果改为让门禁读取上一个实例折叠后的前缀,则在 resume 或 fork 后的实例中(贡献者可能已增长),门禁会低估压力、跳过压缩,发出超窗口的首个请求。在首次 pre-step 之前组合并将活值透传给 seam,使估算在每一步都精确。被 cancel/dispose 中断的组合(中断落在 waterfall 内部)会被丢弃,永不缓存:感知中止的监听器的降级回退不会泄漏到后续请求中,下一轮次在活信号下重新组合。 +- **仅请求,记录在 header 中。** `deriveMessages()` 从不返回前缀;它唯一的持久记录是实例锚定的 `request/header` 快照上的 `EpochHeader.messagePrefix`——可重建请求 Agent Note 已为请求的非历史部分拥有的通道,因此不引入新的会话事件。配套的 [`dsh-agent-loop/invariant`](../../../../packages/core/agent-loop/src/invariant.ts)对每个循环构建的请求重新计算 `messagePrefix + boundary derivation`;启用该贡献时,未记录的前缀无法到达协议格式。 +- **按实例冻结。** 复用是结构性的,而非靠纪律保证:缓存的产物在会话中途不可变,因此提供方的 prompt 缓存从构造上成立,前缀以每步零边际成本扩展了可缓存区域。进程重启或 `ctx.agents.resume()` 产生新实例:它重新组合,任何漂移都可追溯地落在 `'resume'` header 快照上。这就是本 seam 创建的路由规则:会话冻结的开场内容走前缀;会话中途变化的内容走仅追加历史通道(`agent.inject()` 或工具/prompt-submit 的 `additionalContexts`——[拦截 seam Agent Note](2026-06-30-interception-seams.md)),每条都是一次性支付的持久 `context/message`,之后被前缀缓存覆盖。 +- **在持久请求信封中保持精确。** 组合先于实例的首次 `agent/pre-step` 和请求边界。第一个已路由请求会把当前前缀记录在其 header 上,因此步骤后的 token 压力会将精确前缀与实际 prompt、工具和已路由模型一起读取;通用 pre-step seam 不携带压缩专属参数。被 cancel/dispose 中断的组合会被丢弃,永不缓存:感知中止的监听器的降级回退不会泄漏到后续请求中,下一轮次在活信号下重新组合。 由于组合在边界快照之前运行,组合监听器的会话追加会加入当前请求的派生历史。压缩在结构上不可能触及前缀(或系统提示词):它重写的是表面节点,而 header 状态从不进入表面。 ## 测试 -[拦截测试](../../../../packages/core/agent-loop/tests/interception.spec.ts)固定了以下行为:无 header delta 时的组合一次复用、前置插入顺序、空前缀省略、不可变性,以及组合先于 pre-step;[取消测试](../../../../packages/core/agent-loop/tests/cancel.spec.ts)固定了丢弃与重新组合。会话编解码器、不变式和压缩测试覆盖 header 往返、请求重建与前缀感知的压力核算。快照归一化保留前缀计数,[固定 header 场景](../testing/2026-07-06-pin-request-header-content-in-one-scenario.md)拥有内容,默认示例保持无前缀。无需前缀专属的 e2e 测试,因为该 seam 是确定性的且与提供方无关;带密钥的 [request-cache e2e](../../../../packages/core/agent-loop/tests/request-cache.e2e.ts) 覆盖了其缓存经济性。 +[拦截测试](../../../../packages/core/agent-loop/tests/interception.spec.ts)固定了以下行为:没有变更 header 时的组合一次复用、前置插入顺序、空前缀省略、不可变性、组合先于 pre-step,以及已路由 header 上的前缀;[取消测试](../../../../packages/core/agent-loop/tests/cancel.spec.ts)固定了丢弃与重新组合。Session、不变式、token-meter 和压缩测试覆盖 header 往返、请求重建与持久前缀感知的压力核算。快照归一化保留前缀计数,[固定 header 场景](../testing/2026-07-06-pin-request-header-content-in-one-scenario.md)拥有内容,默认示例保持无前缀。与提供方无关的 seam 无需专门 e2e;带密钥的 [request-cache e2e](../../../../packages/core/agent-loop/tests/request-cache.e2e.ts) 覆盖了其缓存经济性。 ## 曾考虑的替代方案 -- **每请求 `before`/`after` 槽位,每步重新计算**(最初提出的形态:一个每请求触发的 waterfall,贡献冻结的 `before` 消息置于历史之前、新鲜的 `after` 消息置于历史之后):否决。每步重新组合 `before` 会引入静默漂移——除非每步记录一个 header delta,否则没有东西将其锚定到日志;`after` 槽位位于不断增长的历史之后,其 token 在每个请求中重复支付,且其后的所有内容不可缓存。对照各替代方案衡量,当前所有更新模式都能通过持久追加更廉价地满足(支付一次,此后缓存读取),而唯一没有归属的内容是会话稳定的开场——它需要的是冻结,而非重新计算。 -- **系统提示词分段**(`system-prompt/assemble`):对此类内容否决。assembly 渲染为单一 `system` 字符串,消息形态的开场放不进去;且系统提示词被设计为每步重新组装(变化时带 header delta),而开场内容需要按实例冻结的语义。 +- **每请求 `before`/`after` 槽位,每步重新计算**(最初提出的形态:一个每请求触发的 waterfall,贡献冻结的 `before` 消息置于历史之前、新鲜的 `after` 消息置于历史之后):否决。每步重新组合 `before` 会引入漂移,必须记录为完整的变更 header;`after` 槽位位于不断增长的历史之后,其 token 在每个请求中重复支付,且其后的所有内容不可缓存。对照各替代方案衡量,当前所有更新模式都能通过持久追加更廉价地满足(支付一次,此后缓存读取),而唯一没有归属的内容是会话稳定的开场——它需要的是冻结,而非重新计算。 +- **系统提示词分段**(`system-prompt/assemble`):对此类内容否决。assembly 渲染为单一 `system` 字符串,消息形态的开场放不进去;且系统提示词被设计为每步重新组装(变化时带完整的变更 header),而开场内容需要按实例冻结的语义。 - **持久化历史开场**(会话启动时 `inject()`):否决。永久历史正是问题陈述中的失败模式——到处被回放、可被压缩、跨 resume 陈旧。 -- **按轮次组合而非按实例组合**:否决。轮次边界的重新组合要么与日志静默失同步,要么强制每次变化都产生 header delta;且它每次触发都会破坏提供方缓存。合理的刷新点是实例边界,`'resume'` 快照已在那里可追溯地记录漂移。 -- **在首次请求时惰性组合,让压缩读取折叠后的 header**(最初合并时的形态):评审中被取代。折叠值仅从实例的第二个请求起才与活前缀匹配,因此在 resume/fork 后的实例首步,压力门禁读取的是上一个实例的前缀,可能低估压力。在首次 pre-step 之前组合并将活值透传给 seam,使估算在每一步都精确。 +- **按轮次组合而非按实例组合**:否决。轮次边界的重新组合要么与日志静默失同步,要么强制产生变更 header;且它每次触发都会破坏提供方缓存。合理的刷新点是实例边界,`'resume'` 快照已在那里可追溯地记录漂移。 +- **通过 `agent/pre-step` 携带 prompt/prefix,用于临时压力估算**:否决,因为它把通用生命周期 seam 耦合到一个消费方,而且仍会遗漏更晚的请求路由和工具;步骤后的回放会从持久的已路由 header 读取请求信封的每个字段。 - **专用会话事件承载前缀**:否决。header 事件按设计就是请求的非历史记录;第二个事件会为同一事实提供第二个归属,并多出一个需要保持完整的编解码器。 ## 后果 -- `agent/pre-step` 与 `CompactService.compactIfNeeded` 携带 `sessionPrefix` 参数:每个 pre-step 监听器和压缩后端都能看到真实的按实例值(所有仓库内实现在同一个变更中更新,遵循预发布立场)。 +- `agent/pre-step` 保持通用的 `(agent, turn, step, signal)` 检查点。压缩不接收 prefix 参数;`ctx.tokenMeter` 在步骤后从规范的已路由 header 折叠前缀。 - 贡献者的内容在会话中途变化时,直到下一个实例才会被重新读取——这是设计意图。需要会话中途目录更新的部署,应将变更通知路由到仅追加历史通道,支付一条持久 `context/message`。 - 被放弃的 `after` 槽位意味着请求尾部附近没有仅请求通道;仓库中没有任何功能需要它,且恢复它会重新引入本设计旨在避免的每步重复支付成本。 -- `request/header-delta` 的 `messagePrefix` 分支(整数组替换,空数组编码向缺失的过渡)为编解码器完整性而存在;循环从不触发它,因为缓存的前缀在实例内不可变。 - 空组合即为规范缺失:无贡献者的部署不记录额外的 header 字节,其请求就是裸派生。 diff --git a/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml b/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml index 0daf9b2490..48e142e853 100644 --- a/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.i18n.yaml @@ -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 -2026-07-08-repeat-tool-guard.md: e422ae70f61b6c77bf6517bc5eb840afc171d82c -2026-07-08-repeat-tool-guard.zh.md: eedb36f448bbca220e023a7609e1d9666fadb8e9 +2026-07-08-repeat-tool-guard.md: 67ec29c6c9fa38bf1d5935c469f3f71b1119dc3a +2026-07-08-repeat-tool-guard.zh.md: 597a51c3a9b160f0447d22e8197917f59cd9ce11 diff --git a/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.zh.md b/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.zh.md index eedb36f448..597a51c3a9 100644 --- a/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.zh.md +++ b/.agents/notes/implemented/feature/2026-07-08-repeat-tool-guard.zh.md @@ -1,4 +1,4 @@ -# RFC: 重复工具调用守卫插件 +# Agent Note: 重复工具调用守卫插件 Status: implemented @@ -8,17 +8,16 @@ Status: implemented 模型陷入循环时,会以字节级相同的参数反复发起同一个工具调用——重新运行一条失败的 grep、重新读取一个未变化的文件、轮询一条已经给出答案的命令——每一轮往返都消耗 token、挂钟时间以及(对付费 API 而言)金钱,却不带来新信息。harness 目前没有任何机制能察觉这一点:循环没有步骤预算,没有插件追踪调用重复,模型只有在碰巧改变自身行为时才能跳出。这种失败模式真实存在且检测成本极低——[pi-repeat-tool-guard](https://github.com/Kingwl/pi-repeat-tool-guard) 正是以 pi coding-agent 扩展的形式提供了这一功能:统计连续相同调用次数,超过阈值后追加一条 `<system-reminder>` 告诉模型停止重复并换个方向。 -harness 已经具备 pi 扩展所使用的全部 seam,而且更好:[拦截 seam RFC](2026-06-30-interception-seams.md) 赋予 `tools/post-execute` 一种经过认可的方式,将面向模型的上下文附加到已完成的调用上;循环缓冲并注入该上下文,同时保持调用/结果的邻接关系;注入的上下文是一条已记录的 `context/message`——因此原生守卫无需新增会话事件即可满足「模型可见 ⟺ 已记录」规则。缺少的只是插件本身。 +harness 已经具备 pi 扩展所使用的全部 seam,而且更好:[拦截 seam Agent Note](2026-06-30-interception-seams.md)赋予 `tools/post-execute` 一种经过认可的方式,将面向模型的上下文附加到已完成的调用上;循环缓冲并注入该上下文,同时保持调用/结果的邻接关系;注入的上下文是一条已记录的 `context/message`——因此原生守卫无需新增会话事件即可满足「模型可见 ⟺ 已记录」规则。缺少的只是插件本身。 ## 决策 该守卫是一个循环卫生插件,而非面向模型的工具。它统计对同一工具以相同规范化参数发起的连续调用次数,并在配置的阈值处注入建议性提醒。它从不延迟、阻止或改写调用;模型自行决定是换种方式重试还是结束。 -插件为 `@deepseek-ai/dsh-repeat-tool-guard`,位于 `packages/guard/repeat-tool-guard/`,开辟 `guard/` 分组用于循环卫生插件(单包(package)分组有先例:[todo-write RFC](2026-06-29-todo-write-tool.md) 发布了 `todo/tool-todo`)。它注册三个监听器,所有状态保存在以 `AgentId` 为键的插件局部 map 中——工具注册表是 context 级别的单例,其 waterfall(瀑布式事件)交错所有 agent(智能体)的调用(subagent 运行在同一个 context 上),因此按 agent 分键是正确性要求,而非锦上添花。 +插件为 `@deepseek-ai/dsh-repeat-tool-guard`,位于 `packages/guard/repeat-tool-guard/`,开辟 `guard/` 分组用于循环卫生插件(单包(package)分组有先例:[todo-write Agent Note](2026-06-29-todo-write-tool.md)发布了 `todo/tool-todo`)。它注册两个监听器,将状态保存在以存活 `Agent` 对象为键的 `WeakMap` 中——工具注册表是 context 级别的单例,其 waterfall(瀑布式事件)交错所有 agent(智能体)的调用(subagent 运行在同一个 context 上),因此按 agent 分键是正确性要求,而非锦上添花;弱对象键还使得纯清理用途的 disposal 监听器不再必要。 -- **`tools/post-execute`(waterfall)**——唯一的检测点。监听器同时接收 `(exec, result)`,因此计数和提醒投递无需跨事件的 pending map(pi 扩展需要它,仅因为其 `tool_call`/`tool_result` 钩子是分开的事件)。它始终通过 `next()` 委托,当命中阈值时,将提醒折叠到下游决策的 `additionalContext` 上——这正是[钩子桥接](2026-06-30-hook-bridges.md)已采用的「观察并丰富」姿态,遵守 waterfall 契约。计数放在此处而非 `tools/pre-execute`,因为 post-execute 也会为被拒绝的调用触发(`ToolRegistry.execute` 将 deny 路由到同一条流水线),而模型反复敲击一个被拒绝的调用恰恰是值得打破的循环。 +- **`tools/post-execute`(waterfall)**——唯一的检测点。监听器同时接收 `(exec, result)`,因此计数和提醒投递无需跨事件的 pending map(pi 扩展需要它,仅因为其 `tool_call`/`tool_result` 钩子是分开的事件)。它始终通过 `next()` 委托,当命中阈值时,将提醒前置到下游决策的 `additionalContexts`——这正是[钩子桥接](2026-06-30-hook-bridges.md)已采用的「观察并丰富」姿态,遵守 waterfall 契约。计数放在此处而非 `tools/pre-execute`,因为 post-execute 也会为被拒绝的调用触发(`ToolRegistry.execute` 将 deny 路由到同一条流水线),而模型反复敲击一个被拒绝的调用恰恰是值得打破的循环。 - **`agent/prompt-submit`(waterfall)**——纯重置钩子:通过 `next()` 委托,清除提交 agent 的链。用户介入改变了上下文;跨越介入的重复不是循环。 -- **`agent/status`(emit)**——在 `disposed` 时丢弃该 agent 的状态,使 map 在 harness 生命周期内有界。 ### 检测语义 @@ -27,11 +26,11 @@ harness 已经具备 pi 扩展所使用的全部 seam,而且更好:[拦截 s 两条刻意的规则,均记录在[包 README](../../../../packages/guard/repeat-tool-guard/README.md) 中,因为它们是读者否则只能猜测的行为: - **未追踪的调用对链透明。** 被 `include`/`exclude` 排除的调用既不递增也不重置计数器,因此 `grep X → todo_write → grep X` 在 `todo_write` 被排除时仍计为两次连续的 `grep X`。这正是排除功能有用的原因——穿插在循环中的簿记工具不得为循环洗白——也是 pi 扩展的(未文档化的)语义,有意保留并明确写下。 -- **没有 agent 的调用被忽略。** 直接调用 `ctx.tools.execute()` 的调用方(测试、非循环消费方)没有可提醒的模型,也没有可作键的 `AgentId`。 +- **没有 agent 的调用被忽略。** 直接调用 `ctx.tools.execute()` 的调用方(测试、非循环消费方)没有可提醒的模型,也没有可作键的存活 agent 对象。 ### 提醒投递 -提醒使用带插件 source 的 `additionalContext`,保留原始 `tool/result`。第一个阈值发出简短提示;后续阈值包含工具名、计数和有界的参数预览,而比较仍使用完整的规范化字符串。已有的下游上下文在守卫的 source 下拼接,因为 `HookContext` 只支持一个 source。 +提醒作为独立条目搭载在 `additionalContexts` 上(source 为 `{kind: 'plugin', plugin: 'repeat-tool-guard'}`——依照 `HookContext`,该标签承载语义),绝不替换 `content`:`tool/result` 事件仍是工具自身的审计输出,循环则在步骤结果之后把缓冲的上下文追加为 `context/message`,session 将其渲染为带标签的合成 user 信封,并由派生历史回放。阈值逐级升级:第一个配置阈值获得简短的「你正在重复自己,请分析先前结果」提示;后续各阈值获得详细形式,包含工具、重复计数和规范参数(在头部截断到 `argumentsPreviewChars`,默认 500——循环中的 `write` 级 payload 不得无界地进入下一次请求;链键始终比较完整规范字符串),并说明这些调用没有取得进展。pi 原版把温和文本硬编码为字面计数 3;本守卫以 `thresholds[0]` 为键,修复了移植中的这一 bug。下游钩子桥贡献仍是独立数组条目,因此两个插件都保留各自的 source、信封与元数据。 ### 配置 @@ -55,7 +54,7 @@ harness 已经具备 pi 扩展所使用的全部 seam,而且更好:[拦截 s ## 曾考虑的替代方案 -- **将提醒追加到工具结果中**(以替换 `content` 的方式 `accept`——pi 扩展的机制,它修补结果内容是因为那是其 API 提供的唯一通道):否决。这会让已记录的 `tool/result` 对工具实际返回的内容撒谎,而 `additionalContext` 的存在正是作为 post-execute 评注的独立认可通道,循环级缓冲保持了调用/结果的邻接关系。 +- **将提醒追加到工具结果中**(以替换 `content` 的方式 `accept`——pi 扩展的机制,它修补结果内容是因为那是其 API 提供的唯一通道):否决。这会让已记录的 `tool/result` 对工具实际返回的内容撒谎,而 `additionalContexts` 是 post-execute 评注的独立认可通道,循环级缓冲保持了调用/结果的邻接关系。 - **在 `tools/pre-execute` 中计数并使用 pending-reminder map**(pi 的两阶段形态):否决。post-execute 单独就能同时看到 `(exec, result)` 且也为被拒绝的调用触发,因此一个监听器、无跨事件状态即可以更少的机制覆盖严格更多的尝试。 - **在最高阈值升级为 `block`**:在初始范围内否决。阻止调用会惩罚合法的相同重复(轮询长时间运行的终端、重新检查 agent 预期会变化的文件),而建议性提醒让模型保持控制权。待有证据后重新审视;决策形状(`PostToolDecision`)已支持此选项。 - **通过 CC/Codex 桥接的逐部署外部钩子**(一个 `PostToolUse` 脚本):否决作为最终答案。它对单个部署有效,但一个已发布、有单元测试、可通过 `cordis.yml` 配置的插件才是 harness 原生的形式,且没有逐调用的子进程开销。 @@ -67,7 +66,8 @@ harness 已经具备 pi 扩展所使用的全部 seam,而且更好:[拦截 s - 提醒在设计上是建议性的:有意重复相同调用的幂等轮询模式仍会在超过阈值后收到提示,减压阀是配置(`thresholds`、`exclude`)加上明确允许「在已收集足够证据时结束」的提醒文本。每次触发在下一次请求中增加提醒 token 的开销;阈值限制了触发频率。 - 链状态仅存于内存:从持久化恢复的会话以全新的链开始,因此跨越恢复的循环比实时循环更晚收到提醒——可以接受,守卫是启发式提示而非已记录的不变式,持久化计数器状态带来的收益不值得其复杂度。 -- 当多个 post-execute 生产者在同一次调用上附加上下文时,折叠在守卫的 `source` 下拼接;插件间的顺序遵循监听器注册顺序。该 seam 无法表示混合来源——这是继承自 `HookContext` 的限制,不归本插件所有。 +- 当多个 post-execute 生产者在同一次调用上附加上下文时,每项贡献保持为独立的 `HookContext`;顺序遵循 waterfall 嵌套关系,每个条目保留自己的溯源信息。 +- 实现快照层时暴露了 suite kit 的一项隐藏假设:fixture guard 把「撰写的模型场景」等同于「由 override 驱动」。`Scenario` 表现在携带显式的 `overridden` 标志,并且 sidecar 是否存在会以双向方式与其核对(未注册的游离 sidecar 会静默替换派生脚本)——suite kit 比本插件出现前更严格。 ## 延后事项 diff --git a/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml b/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml index 45ea89f234..f7e6c2af07 100644 --- a/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.i18n.yaml @@ -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 -2026-07-08-self-referential-cordis-toolset.md: c79bc09dde85d79adc5435f3e08c702cab1369d9 -2026-07-08-self-referential-cordis-toolset.zh.md: e6cada0530652cfb40e7ea1edadf1b12e0f07e77 +2026-07-08-self-referential-cordis-toolset.md: 73d394c24100af8f506cea5b8f43b96d260de160 +2026-07-08-self-referential-cordis-toolset.zh.md: ba0b6ae761ba1e560075177f5867ee634dcbfee8 diff --git a/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md b/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md index e6cada0530..ba0b6ae761 100644 --- a/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md +++ b/.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md @@ -1,4 +1,4 @@ -# RFC: 自引用 cordis 工具集 +# Agent Note: 自引用 cordis 工具集 Status: implemented @@ -20,11 +20,11 @@ vm 隔离了意外的全局污染,上下文门面隐藏了框架内部细节 | 工具 | 契约 | |---|---| -| `cordis_inspect` | 对活跃运行时的只读报告,每个 `what` 值对应一个 Markdown 段落(省略 `what` 则输出全部段落)。从不产生变更。 | +| `cordis_inspect` | 对活跃运行时的只读报告,每个 `what` 值对应一个 Markdown 段落(省略 `what` 则输出全部段落)。精确的 `name` 搭配 `what: "api"` 或 `what: "events"` 可收窄到一个带源码文档的目标。从不产生变更。 | | `cordis_mount` | 在 `node:vm` 沙箱中执行 `code`(一个异步 JavaScript 函数的函数体);代码必须 `return` 一个 cordis 插件,该插件作为 `cordis-dynamic` 分组 fiber 的子节点挂载,并以一个新 id(`dyn-1`、`dyn-2`……)跟踪。 | | `cordis_unmount` | 按 id 释放一个动态挂载,并等到释放达到静止状态后才返回——该插件所做的每一项注册都被撤销,而不仅仅是请求停止。 | -`cordis_inspect` 的段落:`services`(每个已提供的 ctx 服务及其所属 fiber,非活跃的所有者会被标记)、`plugins`(来自 `ctx.registry` 的所有已加载插件的扁平列表及其生命周期状态——展示加载了哪些能力,刻意不展示树形结构)、`tools`(模型可调用的工具)、`dynamic`(挂载表:id、名称、状态、提供的服务、等待的服务)、`api`(来自生成目录的活跃服务签名及其引用的类型形状)和 `events`(harness 事件及其分发模式和签名)。面向模型的工具描述携带了模型在调用时所需的操作规则;[生成的工具目录](../../../tool-catalog.md)是其完整呈现。 +`cordis_inspect` 的段落:`services`(每个已提供的 ctx 服务及其所属 fiber,非活跃的所有者会被标记)、`plugins`(来自 `ctx.registry` 的所有已加载插件的扁平列表及其生命周期状态——展示加载了哪些能力,刻意不展示树形结构)、`tools`(模型可调用的工具)、`dynamic`(挂载表:id、名称、状态、提供的服务、等待的服务)、`api`(来自生成目录的活跃服务签名及其引用的类型形状)和 `events`(harness 事件及其分发模式和签名)。宽泛的 `api` 和 `events` 报告省略完整 JSDoc 以保持紧凑;精确 `name` 会返回一个服务或事件,以及其原始方法/声明 JSDoc。其他段落不能搭配 name,未知目标会失败,而 API 目标必须处于活跃状态。面向模型的工具描述携带了模型在调用时所需的操作规则;[生成的工具目录](../../../../docs/tool-catalog.md)是其完整呈现。 ### 沙箱语义 @@ -46,15 +46,15 @@ vm 隔离了意外的全局污染,上下文门面隐藏了框架内部细节 ### 生成的 API 目录 -`cordis_inspect` 从生成的目录提供 API 和事件数据,而非维护一份重复的表格。生成器复用 Cordis 目录的 AST 扫描,输出服务摘要、签名、事件模式、引用的类型声明以及继承的 context 接口面。有歧义的类型名被省略,过大的声明被标记为截断。 +`cordis_inspect` 从生成的目录提供 API 和事件数据,而非维护一份重复的表格。生成器复用 Cordis 目录的 AST 扫描,输出服务摘要、签名、原始服务方法与事件 JSDoc、事件模式、引用的类型声明以及继承的 context 接口面。有歧义的类型名被省略,过大的声明被标记为截断。 -新鲜度像所有生成产物一样受门禁约束:`pnpm run verify-cordis-api`(在 `doc-sync` 中)在内存中重新生成并在有任何 diff 时失败,因此修改了公开签名的 JSDoc 变更如果不重新生成模型读取的目录就无法合入。运行时 inspect 工具将目录与活跃运行时取交集而非直接转储:有目录条目的活跃服务渲染摘要 + 签名,没有目录条目的活跃服务(挂载提供的)渲染名称 + 所属 fiber,有目录条目但无活跃提供方的服务简要列出,引用的类型形状随后附上。 +新鲜度像所有生成产物一样受门禁约束:`pnpm run verify-cordis-api`(在 `doc-sync` 中)在内存中重新生成并在有任何 diff 时失败,因此 JSDoc 或公开签名变更如果不重新生成模型读取的目录就无法合入。运行时 inspect 工具将目录与活跃运行时取交集而非直接转储:宽泛报告把有目录条目的活跃服务渲染为摘要 + 签名,把没有目录条目的活跃服务(挂载提供的)渲染为名称 + 所属 fiber,简要列出有目录条目但无活跃提供方的服务,再附上引用的类型形状。精确名称报告渲染一个活跃服务或事件,并把原始 JSDoc 紧靠在每个签名之前;让该细节按需出现,避免探索性列表承担其 token 成本。 ### 配置、渲染与可观测性 -该插件暴露一个配置字段,由 schemastery 校验并记录在[配置目录](../../../config-catalog.md)中:`vmTimeoutMs`(默认 5000),挂载代码同步执行部分的毫秒上限。工具名、`cordis-dynamic` 分组名和 `dyn-` id 前缀是结构性词汇,保持固定。三个工具均按[工具实操手册](../../../cookbook/adding-a-tool.md)渲染为 `generic` 卡片(`cordis_inspect` 为 `read`,`cordis_mount` 为 `execute` 并将代码作为 `rawInput` 携带,`cordis_unmount` 为 `delete`),不覆盖 `presentResult`。 +该插件暴露一个配置字段,由 schemastery 校验并记录在[配置目录](../../../../docs/config-catalog.md)中:`vmTimeoutMs`(默认 5000),挂载代码同步执行部分的毫秒上限。工具名、`cordis-dynamic` 分组名和 `dyn-` id 前缀是结构性词汇,保持固定。三个工具均按[工具实操手册](../../../../docs/cookbook/adding-a-tool.md)渲染为 `generic` 卡片(`cordis_inspect` 为 `read`,`cordis_mount` 为 `execute` 并将代码作为 `rawInput` 携带,`cordis_unmount` 为 `delete`),不覆盖 `presentResult`。 -「模型可见 ⟺ 已记录」成立,且无需新的会话事件类型:挂载或卸载仅通过其自身的 `tool/call` / `tool/result` 对可见(循环会记录它们),而挂载引起的工具集变化由循环在 schema 在步骤间发生变化时已有的 request-header delta 记录。刻意不设 `cordis/mount` 溯源事件——它只会重复工具调用对已记录的内容。动态挂载是进程生命周期的,不是会话状态:恢复一个持久化的会话会重建对话,但不会重新挂载插件。 +「模型可见 ⟺ 已记录」成立,且无需新的会话事件类型:挂载或卸载仅通过其自身的 `tool/call` / `tool/result` 对可见(循环会记录它们),而挂载引起的工具集变化由循环在 schema 在步骤间发生变化时发出的完整变更 request header 记录。刻意不设 `cordis/mount` 溯源事件——它只会重复工具调用对已记录的内容。动态挂载是进程生命周期的,不是会话状态:恢复一个持久化的会话会重建对话,但不会重新挂载插件。 ## 曾考虑的替代方案 @@ -73,10 +73,10 @@ vm 隔离了意外的全局污染,上下文门面隐藏了框架内部细节 **在工具中手工维护服务/事件参考。** inspect 工具的第一版携带了一份手写的服务方法签名表。它被生成的 `api-catalog.ts` 取代,因为手写表在签名变化的瞬间就会与 JSDoc 脱节且没有门禁约束这种漂移,而生成产物的新鲜度由文档使用的同一套 AST 检查。 -**新增 `cordis/mount` 会话事件。** 一个持久的溯源事件记录每次挂载(源码、名称)有明确先例(`hook/invoked`、`compact/start`)。v1 中予以否决:挂载和卸载已经作为 `tool/call` / `tool/result` 对可见,工具集变化已经作为 request-header delta 被记录,因此专用事件只会重复记录。如果审计用例需要将挂载溯源从工具调用中分离出来,日后仍可添加。 +**新增 `cordis/mount` 会话事件。** 一个持久的溯源事件记录每次挂载(源码、名称)有明确先例(`hook/invoked`、`compact/start`)。v1 中予以否决:挂载和卸载已经作为 `tool/call` / `tool/result` 对可见,工具集变化已经作为完整的变更 request header 被记录,因此专用事件只会重复记录。如果审计用例需要将挂载溯源从工具调用中分离出来,日后仍可添加。 **加固的/能力受限的沙箱。** 对 Node 内置模块设陷阱并向挂载代码提供白名单门面而非原始 context,可能暗示意图是为安全而沙箱化。这里明确不是:陷阱和门面收窄的是挂载代码所见的*接口面*——将其引导至 cordis 服务、远离易泄漏的 Node 内置模块和框架内部——目的是正确性和封堵未受保护的 context 逃逸,但门面暴露的能力(`ctx.bash`、`ctx.fs`、`ctx.web`)触及真实运行时,因此它不是安全边界。真正的安全边界(独立进程、权限提示)超出了一个开发/显式启用工具集的范围,且会与其核心目的——将活跃运行时交给模型——相冲突。 ## 后果 -该工具集是刻意的显式启用设计,具有完全特权的 `ctx`,因此部署方采用它的意识程度应与 bash 工具相当。以下几个事实由工具描述直接告知模型:一个 waterfall(瀑布式事件)监听器(如 `tools/pre-execute`)如果不调用 `next()` 就返回,会否决整条链,因此一个挂载的监听器可以瘫痪 agent 自身的工具分发([waterfall 语义](../../../cordis-primer.md#cordis-waterfall-semantics));挂载代码在当前轮次的工具调用内运行,因此 await 任何只在该轮次结束后才 resolve 的东西会导致死锁;`vmTimeoutMs` 仅约束同步执行;挂载不会在会话恢复后存活。 +该工具集是刻意的显式启用设计,具有完全特权的 `ctx`,因此部署方采用它的意识程度应与 bash 工具相当。以下几个事实由工具描述直接告知模型:一个 waterfall(瀑布式事件)监听器(如 `tools/pre-execute`)如果不调用 `next()` 就返回,会否决整条链,因此一个挂载的监听器可以瘫痪 agent 自身的工具分发([waterfall 语义](../../../../docs/cordis-primer.md#cordis-waterfall-semantics));挂载代码在当前轮次的工具调用内运行,因此 await 任何只在该轮次结束后才 resolve 的东西会导致死锁;`vmTimeoutMs` 仅约束同步执行;挂载不会在会话恢复后存活。 diff --git a/.agents/notes/implemented/feature/2026-07-10-session-query-service.i18n.yaml b/.agents/notes/implemented/feature/2026-07-10-session-query-service.i18n.yaml index 30fa8ab09e..3100e8abae 100644 --- a/.agents/notes/implemented/feature/2026-07-10-session-query-service.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-10-session-query-service.i18n.yaml @@ -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 -2026-07-10-session-query-service.md: 8c990f4407d91c0be1fc01046e34aa3e76076ed4 -2026-07-10-session-query-service.zh.md: ea0d2d52668fb40b97621884f635cb03dea6f663 +2026-07-10-session-query-service.md: b6581d0bfcdce912a2983f3ebf0c90a2b4c3cf14 +2026-07-10-session-query-service.zh.md: 9d42caa33c860170771fd678fd69d4c43bcf6160 diff --git a/.agents/notes/implemented/feature/2026-07-10-session-query-service.zh.md b/.agents/notes/implemented/feature/2026-07-10-session-query-service.zh.md index ea0d2d5266..9d42caa33c 100644 --- a/.agents/notes/implemented/feature/2026-07-10-session-query-service.zh.md +++ b/.agents/notes/implemented/feature/2026-07-10-session-query-service.zh.md @@ -1,4 +1,4 @@ -# RFC: 精确会话查询服务 +# Agent Note: 精确会话查询服务 Status: implemented @@ -6,13 +6,13 @@ Status: implemented ## 问题 -会话历史存在于两处:当前的 `SessionStore` 对象与可选的持久化后端。需要精确检查的消费方若无统一服务,就不得不各自重复实现活跃/持久化优先级判定、持久化生命周期处理、原始事件的 surface 分类以及防御性克隆。在检查点之间,持久化状态可能落后于活跃日志,因此仅靠持久化并非当前状态的可靠来源。 +会话历史存在于两处:当前的 `SessionStore` 对象与可选的持久化后端。需要精确检查的消费方若无统一服务,就不得不各自重复实现活跃/持久化优先级判定、持久化生命周期处理、原始事件的 surface 分类、关系追踪以及防御性克隆。在检查点之间,持久化状态可能落后于活跃日志,因此仅靠持久化并非当前状态的可靠来源。 全文搜索与此相关,但规模大得多。在真实后端尚不存在时就设计提供方注册、提取、同步、失效、排序和游标契约,会产生两个投机性的状态机:一个在接口服务中,另一个在最终的数据库包(package)中。 ## 决策 -`@deepseek-ai/dsh-session-query` 拥有 `ctx.sessionQuery`,这是一个小型的、受信任的精确读取服务,面向单一逻辑语料库。它暴露 `listSessions()`、`listEvents(sessionId)` 和有界的 `readEvent(request)`。它不暴露过滤器、血缘或溯源遍历、文本提取器、搜索请求、提供方注册或派生索引同步。 +`@deepseek-ai/dsh-session-query` 拥有 `ctx.sessionQuery`,这是一个小型的、受信任的精确检查服务,面向单一逻辑语料库。它暴露 `listSessions()`、`listEvents(sessionId)`、有界的 `readEvent(request)`、`traceSession(sessionId)` 和 `traceEvent(request)`。它不暴露过滤器、文本提取器、搜索请求、提供方注册或派生索引同步。独立的[追踪决策](2026-07-13-session-query-tracing.md)拥有血缘与事件关系语义。 该服务动态观察可选的 `ctx.sessionPersistence` 绑定,但不保留持久化缓存或失效监听器。每次跨语料库列表操作向活跃后端请求权威元数据,然后叠加一份新鲜的活跃 store 列表。id 匹配的条目合并为一条 `SessionRecord`:活跃 header 优先,`live`/`persisted` 各自独立报告来源可用性。不可变 header 不一致时产生 `SESSION_QUERY_SOURCE_CONFLICT`。 @@ -20,13 +20,13 @@ Status: implemented ## Surface 语义 -`dsh-session` 导出 `foldSurface(events)`,`SurfaceManager` 使用相同的转换函数维护其增量缓存。fold 返回分离的当前节点以及每次替换实际移除的 seq。`listEvents()` 利用该结果将每个原始事件分类为 `current`、`shadowed` 或 `log-only`,使检查结果不会在位置替换语义上与 model-history 推导产生分歧。 +`dsh-session` 导出 `foldSurface(events)`,`SurfaceManager` 使用相同的转换函数维护其增量缓存。fold 返回分离的当前事件 seq 以及每次替换实际移除的 seq。`listEvents()` 和 `traceEvent()` 利用该结果为每个原始事件分类,使检查结果不会在位置替换语义上与 model-history 推导产生分歧。 `readEvent()` 返回完整的目标加上按连续 seq 排列的原始相邻事件。`before` 和 `after` 默认为零,各自受 `readWindowMax`(默认 50)约束。结果携带克隆的 `SessionHeader` 而非来源可用性记录,因为判断活跃目标的 persisted 标志会违反「活跃精确读取不依赖持久化健康状态」这一保证。 ## 安全边界 -该服务是上下文级别的受信任基础设施,而非授权层。未来面向模型的历史工具或人类 UI 将施加显式的调用方/会话范围。本阶段不添加面向模型的工具,也不改变 transcript(文本记录)或快照的 surface。 +该服务是上下文级别的受信任基础设施,而非授权层。未来面向模型的历史工具或人类 UI 将施加显式的调用方/会话范围。该服务不添加面向模型的工具,也不改变 transcript(文本记录)或快照的 surface。 ## 曾考虑的替代方案 @@ -34,10 +34,9 @@ Status: implemented - **仅查询持久化**:否决。检查点可能落后于当前活跃日志。 - **缓存持久化元数据并监听写入/删除**:否决。精确读取可以直接询问权威来源,而缓存失效在规模尚未要求时就引入了生命周期与并发状态。 - **现在就定义提供方无关的搜索协议**:否决。目前没有提供方消费它。第一个 SQLite FTS 包应自行拥有一个协调/事务状态机;只有当第二个实现证明了边界时,才提取更小的共享 seam。 -- **在第一阶段就包含血缘、溯源和通用过滤器**:否决。当前没有消费方需要它们,且规范日志足以在日后有证据时再行添加。 ## 后果 -第一阶段只有一个来源解析状态变量:当前挂载的持久化服务。没有提供方队列、指纹、提取器注册表、观察代次或派生索引更新。精确读取在纯活跃部署中仍然可用,在持久化存在时具有确定性。 +该服务只有一个来源解析状态变量:当前挂载的持久化服务。没有提供方队列、指纹、提取器注册表、观察代次或派生索引更新。精确读取和事件追踪在纯活跃部署中仍然可用,在持久化存在时具有确定性。 -跨语料库列表与持久化精确读取在每次调用时执行后端 I/O。这是有意为之:正确性来自当前权威状态,面向规模的搜索属于第二阶段的数据库。在该包定义并实现其完整契约之前,全文搜索不可用。 +跨语料库列表、血缘追踪和持久化事件操作在每次调用时执行后端 I/O。这是有意为之:正确性来自当前权威状态,面向规模的搜索属于提议中的数据库包。在该包定义并实现其完整契约之前,全文搜索不可用。 diff --git a/.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml b/.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml index 65e180d55d..276ea90554 100644 --- a/.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.i18n.yaml @@ -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 -2026-07-12-subagent-persona-tool-filter-and-depth.md: c88695d4444008bff69fcb10e3cf33c7b8820b9b -2026-07-12-subagent-persona-tool-filter-and-depth.zh.md: 1efbbce57274c11b2811ebe844c9cd80f81f407f +2026-07-12-subagent-persona-tool-filter-and-depth.md: c690f4701a54272205eedf719fbfe0863bac566c +2026-07-12-subagent-persona-tool-filter-and-depth.zh.md: ec18becb9c3f446138e7b3573582f3ff2fbb891a diff --git a/.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md b/.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md index 1efbbce572..ec18becb9c 100644 --- a/.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md +++ b/.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.zh.md @@ -1,4 +1,4 @@ -# RFC: 配置 subagent 的人设、工具可见性与深度 +# Agent Note: 配置 subagent 的人设、工具可见性与深度 Status: implemented @@ -51,9 +51,11 @@ subagent 启动有三个独立的组合控制:`persona`、`toolFilter` 和 `ma 深度限制独立于工具可见性来约束递归委派。顶层 agent 深度为零;进程内子 agent 的深度为其父级已验证深度加一。`maxDepth` 是一个绝对的非负安全整数,当推导出的子 agent 深度大于上限时,启动在子 agent 所有权开始之前即被拒绝。 -每个公开入口都自行验证值域,而非依赖单一的面向模型配置路径。负值、小数、负零、非有限值、不安全整数、格式错误的存储父级深度以及推导溢出均被拒绝。省略上限时,此机制不约束深度。 +有效父级深度取持久 `SessionHeader.delegationDepth` 与运行时 `AgentOptions.subagentDepth` 中的较大值。进程内子 agent 把推导出的深度记录在 session header 中,resume 会恢复该 header,因此重启无法降低递归计数。 -部署可以组合深度与过滤。例如,可以在深度一时保持委派工具可见但设置 `maxDepth: 1`,或在子 agent 中完全 deny 委派工具。两种选择都不改变提供方的对话历史行为。 +每个公开入口都自行验证值域,而非依赖单一的面向模型配置路径。负值、小数、负零、非有限值、不安全整数、格式错误的存储父级深度以及推导溢出均被拒绝。直接的 `SubagentStartRequest` 可以省略上限,让此机制不约束深度;经 Loader 解析的 `dsh-tool-subagent` 配置则默认值为 `3`、接受数值覆盖,并使用显式的 `'provider-managed'` 来省略由进程外提供方部署拥有递归预算时的上限。三是一个较小的有限默认值,仍允许 root 加三代后代:[SDK 辅助函数生成的 subagent 条目](../../../../packages/sdk/helper/src/features/builtin/index.ts)和 [JSON-RPC 示例](../../../../examples/jsonrpc-agent/cordis.yml)采用这项通用策略,而已交付的交互式 ACP、headless 和 REPL 示例固定为一。提供方缺少 `depthLimit` 时,数值工具上限会在提供方挂载阶段失败。 + +部署可以组合深度与过滤,但数值上限不会合成过滤器。委派工具在上限处仍然可见,因为授权可能依赖运行时状态;每次尝试启动都会检查调用方 agent 当前的持久与运行时深度,被拒绝的启动返回错误工具结果,且不发布子 agent。可见性策略固定的部署可以另外在子 agent 中 deny 委派工具。两种选择都不改变提供方的对话历史行为。 ### 能力门控保持提供方诚实 @@ -85,10 +87,10 @@ subagent 启动有三个独立的组合控制:`persona`、`toolFilter` 和 `ma **仅隐藏工具 schema。** 仅呈现层的过滤让模型可以通过 Code Mode 或伪造调用执行一个 prompt 声称不存在的工具。改为由一个解析器同时管控呈现和执行。 -**仅用工具过滤来阻止递归。** 移除委派工具有用但依赖特定提供方,且不保护直接服务调用方或替代委派工具。绝对深度是独立的结构性约束。 +**把深度上限编码为自动工具过滤器。** 创建时过滤器会快照一个可能依赖运行时状态的决策,只影响一个已配置工具名,且不保护直接服务调用方或替代委派工具。提供方改为在每次启动时强制绝对上限。 ## 后果 贡献者可以配置子 agent 的角色、可见全局工具和递归深度,而无需定义新的提供方。能力检查在所有权开始之前失败,未发布设置使第一次请求一致,单一工具解析器防止呈现/执行漂移。 -代价是部署方必须理解活跃的 allow/deny 行为以及可见性与授权的区别。提供方作者必须准确声明每个受支持的控制,进程内提供方必须在发布前安装所有请求的贡献。这些控制有意不解决安全隔离或父到子的不可升级问题。 +代价是部署方必须理解活跃的 allow/deny 行为以及可见性与授权的区别。当前深度策略禁止再创建子 agent 后,模型仍可能调用可见的委派工具并收到错误。提供方作者必须准确声明每个受支持的控制,进程内提供方必须在发布前安装所有请求的贡献。这些控制有意不解决安全隔离或父到子的不可升级问题。 diff --git a/.agents/notes/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml b/.agents/notes/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml index 1e877bfba3..9a7213863f 100644 --- a/.agents/notes/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-11-doc-sync-enforcement.i18n.yaml @@ -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 -2026-06-11-doc-sync-enforcement.md: cb238291f9ff5ba5d6333cdf2fe75a43fe3e8eea -2026-06-11-doc-sync-enforcement.zh.md: a443cfcd6f9bd17ae1512683ff8cd82411fb8590 +2026-06-11-doc-sync-enforcement.md: 375059312c312dff7b5ddcb95ea5b82ac8cd4d06 +2026-06-11-doc-sync-enforcement.zh.md: 7d0e812c7a4b0ec64113cd272b2fcbdfb6055f18 diff --git a/.agents/notes/implemented/process/2026-06-11-doc-sync-enforcement.zh.md b/.agents/notes/implemented/process/2026-06-11-doc-sync-enforcement.zh.md index a443cfcd6f..7d0e812c7a 100644 --- a/.agents/notes/implemented/process/2026-06-11-doc-sync-enforcement.zh.md +++ b/.agents/notes/implemented/process/2026-06-11-doc-sync-enforcement.zh.md @@ -1,4 +1,4 @@ -# RFC: Doc-sync 强制 +# Agent Note: Doc-sync 强制 Status: implemented @@ -13,20 +13,20 @@ AGENTS.md 承诺文档与代码严格同步,但这一承诺此前仅靠人眼 两道门禁,沿用既有的 `scripts/` 风格(tsx ESM,每个脚本一项职责): 1. **`doc-typecheck`** 从 `README.md`、`docs/**` 和 `packages/*/README.md` 中提取所有 ` ```ts ` 围栏代码块,写入一个继承根 `tsconfig.json` 的临时项目,然后用 `tsc -b` 编译。临时项目复用源码的 `paths` 映射和根 project references,因此文档示例能看到源码,而 vendor 代码仍在其自身的 tsconfig 设置下被检查。刻意作为草图的代码块可通过显式的 ` ```ts ignore-check ` 信息字符串来 opt-out;脚本会报告 opt-out 比例,超过一半即失败,防止该豁免机制悄然成为常态。 -2. **`verify-event-taxonomy`** 从 `packages/*/src` 中的 `interface Events` 块和 `docs/architecture.md` 中的分类体系表分别提取事件名称,断言两个集合完全一致。只校验,不生成:表格保留手写的 Mode/Purpose 列,仅检查名称集合。(落地此门禁时发现了表格遗漏的三个事件:`tools/change`、`llm/adapter-change`、`system-prompt/change`。)**已被取代**:由[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)取代。此门禁及其 `architecture.md` 表格已退役,取而代之的是完全生成的 `docs/cordis-catalog/events.md` + `docs/cordis-catalog/services.md` 及其 `verify-cordis-catalog` 新鲜度门禁。本 RFC 中的其他门禁(`doc-typecheck` 以及下文修订中的 `verify-md-wrap`)不受影响。 +2. **`verify-event-taxonomy`** 从 `packages/*/src` 中的 `interface Events` 块和 `docs/architecture.md` 中的分类体系表分别提取事件名称,断言两个集合完全一致。只校验,不生成:表格保留手写的 Mode/Purpose 列,仅检查名称集合。(落地此门禁时发现了表格遗漏的三个事件:`tools/change`、`llm/adapter-change`、`system-prompt/change`。)**已被取代**:由[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)取代。此门禁及其 `architecture.md` 表格已退役,取而代之的是完全生成的 `docs/cordis-catalog/events.md` + `docs/cordis-catalog/services.md` 及其 `verify-cordis-catalog` 新鲜度门禁。本 Agent Note(agent 决策记录)中的其他门禁(`doc-typecheck` 以及下文修订中的 `verify-md-wrap`)不受影响。 -两者通过一个共享的 `doc-sync`(文档同步门禁)package.json 脚本运行,lefthook pre-push 钩子和 CI 都调用它([机械质量门禁](2026-06-11-quality-gates.md):钩子与 CI 调用相同脚本,因此门禁在推送前就在本地触发,而非仅在推送后)。它们在 `pnpm run typecheck` 之后运行,后者校验 doc-typecheck 所引用的 package/vendor 构建图。 +两者都通过 package.json 中共享的 `doc-sync` 脚本运行;贡献者在相关文档变更中调用它,CI 则执行完整检查。[快速本地 Git 钩子](2026-07-22-fast-local-git-hooks.md)决策使这类按变更面选择的工作不进入 commit 和 push 钩子。 **修订(2026-06-17):** 第三道门禁 **`verify-md-wrap`** 随后被纳入 `doc-sync`。它使用 `mdast-util-from-markdown` + GFM 解析范围内的每个 Markdown 文件(`README.md`、`docs/**`、`packages/*/README.md`,加上 `AGENTS.md` / `packages/AGENTS.md`),如果任何 `paragraph` 节点跨越多个源码行则失败,从而强制执行 docs/AGENTS.md 中「一个段落一个物理行」的写作规则。同样遵循只校验不生成的原则:它报告硬换行但从不重写,因此不会引入格式化噪音。`doc-sync` 现在包含三道门禁。 ## 曾考虑的替代方案 -- **API-extractor 金标报告**([已推迟的提案](../../proposed/process/2026-06-11-api-extractor-reports.md)):有意推迟。对于评审者已能直接看到源码 diff 的内部 monorepo 而言价值有限,且依赖重、配置繁琐。 +- **API-extractor 基准报告**([已推迟的提案](../../proposed/process/2026-06-11-api-extractor-reports.md)):有意推迟。对于评审者已能直接看到源码 diff 的内部 monorepo 而言价值有限,且依赖重、配置繁琐。 - **从源码生成分类体系表**而非仅校验名称:否决,机制比问题本身更重;表格保留了手写的 Mode/Purpose 列,直到[生成式 Cordis 目录](2026-06-20-generated-cordis-catalog.md)完全取代了这项检查。 ## 后果 -- 可检查类别的文档漂移现在会让 pre-push 钩子和 CI 失败,而非等待评审者发现。这是「机械门禁优于行文约定」原则的一个实例。 +- 可检查类别中的文档漂移会直接使 `doc-sync` 和 CI 失败,而不是等评审人发现。这是「机械门禁优于行文规范」原则的具体应用。 - 让文档代码片段可编译需要少量 stub import/`declare`;`ignore-check` 比例必须保持低位,否则门禁形同虚设(比例守卫强制执行此约束)。 - 分类体系检查仅限名称——Mode 或 Purpose 列的错误仍需人工评审。 - 如果 package 未来对外发布,API 报告方案仍可重新考虑。 diff --git a/.agents/notes/implemented/process/2026-06-11-quality-gates.i18n.yaml b/.agents/notes/implemented/process/2026-06-11-quality-gates.i18n.yaml index be4c70583e..0e84de0e10 100644 --- a/.agents/notes/implemented/process/2026-06-11-quality-gates.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-11-quality-gates.i18n.yaml @@ -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 -2026-06-11-quality-gates.md: 2d6b6815e80a728cb61a86e9f7a488340fe06fc9 -2026-06-11-quality-gates.zh.md: f5088811f8562f5103740d39b48bd14c6d1da00c +2026-06-11-quality-gates.md: e1af110387936d644208dc1829fde4a4fdf8a3f9 +2026-06-11-quality-gates.zh.md: eaae458e3eac6a45e0c16ec0b8fb950aa1b70619 diff --git a/.agents/notes/implemented/process/2026-06-11-quality-gates.md b/.agents/notes/implemented/process/2026-06-11-quality-gates.md index 5e1db16e52..e1af110387 100644 --- a/.agents/notes/implemented/process/2026-06-11-quality-gates.md +++ b/.agents/notes/implemented/process/2026-06-11-quality-gates.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-11-quality-gates.zh.md) + The hook/CI symmetry in this record is superseded by [Fast local Git hooks](2026-07-22-fast-local-git-hooks.md); CI remains the exhaustive enforcement path. ## Problem diff --git a/.agents/notes/implemented/process/2026-06-11-quality-gates.zh.md b/.agents/notes/implemented/process/2026-06-11-quality-gates.zh.md index f5088811f8..eaae458e3e 100644 --- a/.agents/notes/implemented/process/2026-06-11-quality-gates.zh.md +++ b/.agents/notes/implemented/process/2026-06-11-quality-gates.zh.md @@ -1,28 +1,30 @@ -# RFC: 以机械质量门禁取代行文约定 +# Agent Note: 以机械质量门禁取代行文约定 Status: implemented [English](2026-06-11-quality-gates.md) | 中文 +本记录中的钩子/CI 对称设计已由[快速本地 Git 钩子](2026-07-22-fast-local-git-hooks.md)取代;CI 仍是执行完整检查的路径。 + ## 问题 本代码库主要由 coding agent(智能体)开发。相比行文约定,agent 遵守强制门禁的可靠性远高得多;而当劳动由 agent 承担时,「工作量大」不构成成本论据。早期证据:未通过类型检查的测试被提交(vitest 不做类型检查),仅在评审中才被发现。 ## 决策 -AGENTS.md 中的每一条承诺都对应一个以非零退出码表示失败的命令,通过 git 钩子和 CI 调用同一套 package.json 脚本来执行: +每条可机械检查的 AGENTS.md 承诺都有一个以非零状态退出的命令。CI 执行完整集合,而 Git 钩子将延迟预算留给可低成本发现的本地缺陷: - 最严格的 TypeScript 配置(`noUncheckedIndexedAccess`、`exactOptionalPropertyTypes` 等);示例、测试和脚本通过根目录的 no-emit `tsconfig.json` 在 CI 中进行类型检查,而 package/vendor 代码保持在各自 project-reference 边界之后。 - ESLint strict-type-checked + @stylistic(作为强制执行的统一代码风格),包括文件内重复逻辑检查;vendor 代码排除在外。 - jscpd 检测 package 生产 TypeScript 与仓库脚本中的跨文件克隆;窄范围的源码区间例外用于记录有意为之的并行实现。 - `packages/*/*/src` 下按文件 100% 覆盖率(v8);不可达的防御性守卫使用 `/* v8 ignore */ ` 并注明理由,而非删除。 - knip(死代码/依赖)、publint(包(package)正确性)、workspace 约束(workspace 规则:private、cordis peer+dev、统一版本、ESM),以及对构建出的包声明文件进行 NodeNext 消费方类型检查。 -- lefthook pre-commit(lint 暂存文件、类型检查、vendor manifest(元数据清单)守卫)和 pre-push(测试、hygiene);CI 在 Node 22.19/24/26 上运行完整矩阵,外加一个驱动 echo-agent 端到端的演示冒烟测试。 +- lefthook pre-commit 修复已暂存文件的 lint 问题、拒绝已暂存的空白问题并检查 vendor manifest;pre-push 运行增量类型检查。CI 在 Node 22.19/24/26 上运行完整矩阵,并对 Headless、TUI、ACP(Agent Client Protocol)、JSON-RPC、工作流和代码运行时入口路径执行已构建应用的冒烟测试。 ## 后果 -- 约定在 agent 更替中得以存续;违规在本地快速失败。 +- 约定不会因 agent 更替而失效;可低成本发现的 commit/push 缺陷在本地失败,其余完整规则违规在 CI 中失败。 - 门禁本身也是需要维护的代码;配置变更与其他变更一样需要评审。 - 100% 覆盖率的压力可能催生无断言的测试——变异测试是计划中的对策(见[变异测试提案](../../proposed/testing/2026-06-11-mutation-testing.md))。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml b/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml index bb496d19e3..85dd3e2652 100644 --- a/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.i18n.yaml @@ -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 -2026-06-11-tsdown-over-dumble.md: b1ce354b9b2baa042d8aa1be2a8de171ed4adfef -2026-06-11-tsdown-over-dumble.zh.md: 4bdd9939901ef376f2f6ccded609b644a4698495 +2026-06-11-tsdown-over-dumble.md: 5d7593d689e2404bede0fa51b41c5d8eec397a03 +2026-06-11-tsdown-over-dumble.zh.md: 080ee4c3fb9894049716fd5aec3ddd7b3d62d547 diff --git a/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.zh.md b/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.zh.md index 4bdd993990..080ee4c3fb 100644 --- a/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.zh.md +++ b/.agents/notes/implemented/process/2026-06-11-tsdown-over-dumble.zh.md @@ -1,4 +1,4 @@ -# RFC: 使用 tsdown 替代 dumble 进行 JS 打包 +# Agent Note: 使用 tsdown 替代 dumble 进行 JS 打包 Status: implemented @@ -15,7 +15,7 @@ Status: implemented 用 **tsdown**(基于 rolldown,每周约 250 万次下载,VoidZero 支持,活跃发布)替代 dumble: - 根目录 `tsdown.config.ts`,配置 `workspace: ['vendor/*', 'packages/*/*']`(显式 glob 将打包范围限定在 vendor 的 Cordis 与 TypeScript 包目录树内;`workspace: true` 还会发现示例 manifest 和不需要打包的 workspace 成员)。 -- 共享形态:入口 `lib/types/index.js`,`outDir: 'lib'`,ESM,`platform: node`,`target: es2024`,`fixedExtension: false`(为 `"type": "module"` 的包保持 `.js` 扩展名),`dts: false`(声明文件由 tsc -b 负责),`clean: false`(lib/ 同时存放 TSC 的 `lib/types` 中间产物树)。入口最初是 `src/index.ts`;[TSC 优先构建 RFC](2026-06-17-ts-build-config.md) 后来将 tsdown 改为打包 TSC 输出的 JS,使 TypeScript 转换行为统一来自一个编译器。 +- 共享形状:入口为 `lib/types/index.js`,`outDir: 'lib'`,ESM,`platform: node`,`target: es2024`,`fixedExtension: false`(为 `"type": "module"` 包保留 `.js`),`dts: false`(声明归 tsc -b 所有),`clean: false`(lib/ 还保存 TSC 的 `lib/types` 中间树)。入口最初是 `src/index.ts`;[TSC 优先构建 Agent Note(agent 决策记录)](2026-06-17-ts-build-config.md)随后将 tsdown 改为打包 TSC 输出的 JS,使 TypeScript 转换行为统一由一个编译器提供。 - vendor/ 中有两个按包覆盖的配置(属于我们自己的修改,与重新生成的 tsconfig 类似;记录在 vendor/README.md 中):schemastery(通过 `outExtensions` 输出双格式 `.mjs`/`.cjs`)、logger-console(两次单入口 pass,使共享基类被内联到每个入口而非生成哈希命名的 chunk,与上游发布形态一致)。 - `scripts/build.ts` 删除;`pnpm run build` = `tsc -b tsconfig.build.json && tsdown`。 @@ -27,4 +27,4 @@ Status: implemented ## 后果 -运行时打包产物仍遵循 dumble 时代的公开入口形态(`lib/index.js`,以及按包特定的变体,如 `schemastery` 的 `lib/index.mjs`/`lib/index.cjs` 和 `logger-console` 的 `lib/browser.js`);声明文件现在位于 `lib/types` 下,见 [TSC 优先构建 RFC](2026-06-17-ts-build-config.md)。外部依赖仍来自各包的 dependencies/peerDependencies。我们放弃了 dumble 的 exports 字段推断功能:新增的非默认形态的包需要编写按包的 `tsdown.config.ts`,而不能仅靠 package.json 字段。未来可选方向:如果 `tsc -b` 成为瓶颈,tsdown 还可以接管声明文件打包(isolatedDeclarations);那将是一个新的 RFC。 +运行时 bundle 输出仍沿用 dumble 时代的公开入口形状(`lib/index.js`,以及包特有的变体,例如 `schemastery` 的 `lib/index.mjs`/`lib/index.cjs` 与 `logger-console` 的 `lib/browser.js`);根据 [TSC 优先构建 Agent Note](2026-06-17-ts-build-config.md),声明现位于 `lib/types` 下。External 仍来自各包的 dependencies/peerDependencies。我们放弃了 dumble 的 exports 字段推断:采用非默认形状的新包需要逐包提供 `tsdown.config.ts`,不能只依赖 package.json 字段。未来如果 `tsc -b` 成为瓶颈,tsdown 也可以接管声明打包(isolatedDeclarations);这需要另写一份 Agent Note。 diff --git a/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml b/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml index 339d733f07..0e0c6693a2 100644 --- a/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.i18n.yaml @@ -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 -2026-06-11-vendor-cordis-as-source.md: 6e1af616785411a20496334fb35e0c7a3bc41b43 -2026-06-11-vendor-cordis-as-source.zh.md: bb9413fbba34e9a7040fd2e0a1bbcff1ba2345ff +2026-06-11-vendor-cordis-as-source.md: ae6f5438c5817c61a549d9edb2041d538fbcebe6 +2026-06-11-vendor-cordis-as-source.zh.md: 8d6f0e39d53e1c85eaaa50c4c4bf1d9ef648d953 diff --git a/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md b/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md index bb9413fbba..8d6f0e39d5 100644 --- a/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md +++ b/.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.zh.md @@ -1,4 +1,4 @@ -# RFC: 将 Cordis 以源码形式收录,而非作为 npm 依赖 +# Agent Note: 将 Cordis 以源码形式收录,而非作为 npm 依赖 Status: implemented diff --git a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml index 41084092d0..cb31fe2ed1 100644 --- a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.i18n.yaml @@ -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 -2026-06-16-pnpm-over-yarn.md: f5787dc3019f2c474761972afb11deb42f3950e0 -2026-06-16-pnpm-over-yarn.zh.md: 0f5acd13f6f113a569fbe4e7b92df62309c76537 +2026-06-16-pnpm-over-yarn.md: 9dee405f509897e2a173399e466d574c518fa9ab +2026-06-16-pnpm-over-yarn.zh.md: ef34e6ba5d6e22037668c9aa3507dfd0f5438ad4 diff --git a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.zh.md b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.zh.md index 0f5acd13f6..ef34e6ba5d 100644 --- a/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.zh.md +++ b/.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.zh.md @@ -1,4 +1,4 @@ -# RFC: 使用 pnpm 替代 Yarn 4 作为包管理器 +# Agent Note: 使用 pnpm 替代 Yarn 4 作为包管理器 Status: implemented @@ -8,7 +8,7 @@ Status: implemented 本仓库最初使用 **Yarn 4** 搭配 `node-modules` 链接器启动。这是一个刻意保守的选择:行为类似 npm 的扁平布局,同时享有 Yarn 的 workspaces 和 `yarn constraints`。它能正常工作。但 Yarn 4 源自 Plug'n'Play 的血统,使得 `node-modules` 链接器成为非主流模式;而更广泛的 JS 生态——工具默认值、CI action、Corepack 示例、贡献者的熟悉度——正日益以 pnpm 为中心。对于一个主要由 agent(智能体)构建、偶尔有人类贡献者阅读的仓库而言,「大多数工具和人所期望的包管理器」具有实际价值:更少的意外、更成熟的故障路径、更多可直接复用的解答。 -切换成本目前处于最低点。本仓库尚无任何包(package)发布(每个包都是 `private: true`);开发/测试/演示全部通过 tsx **未构建**运行,因此包管理器只需做到:(a) 解析并链接 `node_modules`,(b) 运行 workspace 脚本,(c) 强制执行 workspace 约束。唯一的 Yarn 特有资产是 `yarn.config.cjs`(`@yarnpkg/types` 约束引擎),体量小且可机械地重新表达。这与 [tsdown 决策](2026-06-11-tsdown-over-dumble.md)的逻辑一致:在爆炸半径尚小时,将承重工具换为生态更健康的选项。 +切换成本目前处于最低点。本仓库尚无任何包(package)发布(每个包都是 `private: true`);开发/测试/演示全部通过 tsx **未构建**运行,因此包管理器只需做到:(a)解析并链接 `node_modules`,(b)运行 workspace 脚本,(c)强制执行 workspace 约束。唯一的 Yarn 特有资产是 `yarn.config.cjs`(`@yarnpkg/types` 约束引擎),体量小且可机械地重新表达。这与 [tsdown 决策](2026-06-11-tsdown-over-dumble.md)的逻辑一致:在爆炸半径尚小时,将承重工具换为生态更健康的选项。 ## 决策 @@ -40,4 +40,4 @@ Status: implemented 在快速本地磁盘上,pnpm 的内容寻址 store 通常在冷/热安装中胜出,尤其在多个检出之间的**磁盘占用**方面优势明显(一个全局 store 通过硬链接接入每个 `node_modules`,而 Yarn 每个 worktree 复制约 279 MB——部分开发者经常为本仓库保持约 10 个或更多 worktree)。该去重优势在上述迁移时数据中**未能**体现,因为测试 store 和 `node_modules` 位于不同文件系统,硬链接失效;在单文件系统的开发机或 CI 缓存上则适用。诚实的总结:在我们的 NFS 开发文件系统上,安装速度在噪声范围内不分伯仲;迁移的理由是生态对齐、幻影依赖安全性和跨检出磁盘去重,而非原始安装时间的胜出。 -所有质量门禁(constraints、typecheck、lint、doc-sync、test:coverage 100%、build、knip、publint、echo-agent 演示冒烟测试)在 pnpm 上原样通过,这是链接器切换未引入幻影依赖破坏的正确性证明。 +所有质量门禁(constraints、类型检查、lint、doc-sync、达到 100% 的 test:coverage、构建、knip、publint 以及已构建应用的冒烟测试)均在 pnpm 下通过,证明更换 linker 没有引入幽灵依赖故障。 diff --git a/.agents/notes/implemented/process/2026-06-17-ts-build-config.i18n.yaml b/.agents/notes/implemented/process/2026-06-17-ts-build-config.i18n.yaml index 413c51c906..687332576e 100644 --- a/.agents/notes/implemented/process/2026-06-17-ts-build-config.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-17-ts-build-config.i18n.yaml @@ -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 -2026-06-17-ts-build-config.md: 9a75bcc3f043576f1cb793c38e0166aa0a010f68 -2026-06-17-ts-build-config.zh.md: c0f6bd40f3f0b06e79b9dc9f9c7812481413374c +2026-06-17-ts-build-config.md: b82e5cae6dbfaae68d3a834162085e3f7b2c0c72 +2026-06-17-ts-build-config.zh.md: e6cec899e521ee2c8325c7562329455141da8af5 diff --git a/.agents/notes/implemented/process/2026-06-17-ts-build-config.zh.md b/.agents/notes/implemented/process/2026-06-17-ts-build-config.zh.md index c0f6bd40f3..e6cec899e5 100644 --- a/.agents/notes/implemented/process/2026-06-17-ts-build-config.zh.md +++ b/.agents/notes/implemented/process/2026-06-17-ts-build-config.zh.md @@ -1,4 +1,4 @@ -# RFC: TSC 优先的构建与单一 tsconfig +# Agent Note: TSC 优先的构建与单一 tsconfig Status: implemented @@ -23,6 +23,7 @@ Status: implemented - 在根目录严格配置下直接对 `vendor/*/src` 做类型检查,会触发大量不属于本项目所有权范围的类型错误。 - `packages/*/*` 对 `vendor` 的包依赖解析到 `vendor/*/lib`,以适应不同的 tsconfig 严格度。 + ## 决策 包内相对导入使用显式 `.ts` 说明符。 diff --git a/.agents/notes/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml b/.agents/notes/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml index 0f0677a911..601a077189 100644 --- a/.agents/notes/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-18-markdown-cross-link-lint.i18n.yaml @@ -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 -2026-06-18-markdown-cross-link-lint.md: f7ab6a4fd2b2c5cadaeabd5ef0c89f1097b5b44d -2026-06-18-markdown-cross-link-lint.zh.md: 61187042a3a0d3535479ffe3a796b6c1fdb82f5e +2026-06-18-markdown-cross-link-lint.md: 2e3b0f1fcd03f244756b0030f2da758c516a2bbb +2026-06-18-markdown-cross-link-lint.zh.md: cfe973ae939eceb50d6381ecf35c80df508907c3 diff --git a/.agents/notes/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md b/.agents/notes/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md index 61187042a3..cfe973ae93 100644 --- a/.agents/notes/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md +++ b/.agents/notes/implemented/process/2026-06-18-markdown-cross-link-lint.zh.md @@ -1,4 +1,4 @@ -# RFC: Markdown 交叉链接有效性检查 +# Agent Note: Markdown 交叉链接有效性检查 Status: implemented @@ -8,7 +8,7 @@ Status: implemented 本仓库的文档通过相对路径互相链接:`[topic](../implemented/2026-…-….md)`、`[the cookbook](adding-a-tool.md)`、`[architecture.md](../../architecture.md)`。此前没有任何机制验证这些目标是否存在。重命名或移动文件会静默破坏所有指向它的链接,且在读者点击之前不可见。[Doc-sync 强制](2026-06-11-doc-sync-enforcement.md)已经将两类文档漂移机械化(无法编译的代码块、陈旧的事件分类表),[verify-md-wrap](2026-06-11-doc-sync-enforcement.md) 覆盖了第三类(硬换行的段落),但死链是第四类同样可机械检查、却仍靠肉眼验证的问题。 -触发本门禁的直接案例是引入它的那次 RFC 目录重组:将 `docs/adr/` + `docs/rfc/` 统一为一个 `docs/rfc/`,下设 `proposed/`/`implemented/`/`rejected/` 子目录,手动改写了约四十条文档间链接。任何一个手误路径都会让一条死链随代码入库,而没有任何东西能拦住它。 +引入这道门禁的直接动因是 Agent Note(agent 决策记录)目录树重组:将 `docs/adr/` 与 `.agents/notes/` 统一到同一个 `.agents/notes/` 下,并设置 `proposed/`、`implemented/`、`rejected/` 子目录,需要手工重命名约 40 条文档间链接。只要有一处路径输入错误,就会在没有任何检查拦截的情况下交付断链。 ## 决策 @@ -18,7 +18,7 @@ Status: implemented - 仅当目标是**相对路径**时才检查。跳过带协议的 URL(`https:`、`mailto:` 等)、协议相对路径(`//host`)、根绝对路径(`/path`,在检出目录中没有稳定基准)以及纯页内锚点(`#section`)。剥除 `#fragment`/`?query`,相对于链接所在文件的目录解析路径,并断言目标在磁盘上存在。 - 只报告、不改写;发现第一条死链即以非零状态退出。 -范围与其他门禁一致,另外加上 AGENTS.md 对和 `.agents/skills/` 下仓库自有的 agent skill Markdown(这些 skill 文件交叉链接到 docs 目录,因此本次重组也改写了其中的链接):`README.md`、`docs/**/*.md`、`packages/*/README.md`、`AGENTS.md`、`packages/AGENTS.md`、`.agents/skills/**/*.md`,按真实路径去重(`CLAUDE.md` 符号链接解析到 AGENTS.md 文件)。它接入 lefthook pre-push 钩子和 CI 都会运行的 `doc-sync` 脚本,因此死链在推送前就会在本地失败——与[机械化质量门禁](2026-06-11-quality-gates.md)一致。 +检查范围与其他门禁一致,并额外包含 AGENTS.md 文件对以及 `.agents/skills/` 下仓库自有的 agent-skill(技能)Markdown(这些 skill 文件会交叉链接到 docs 目录树,因此本次重组也改写了其中的链接):`README.md`、`docs/**/*.md`、`packages/*/README.md`、`AGENTS.md`、`packages/AGENTS.md`、`.agents/skills/**/*.md`。系统按真实路径去重(`CLAUDE.md` symlink 会解析到 AGENTS.md 文件)。该检查接入 `doc-sync`,因此相关文档变更与 CI 执行同一套断链检查。 本门禁检查的是*文件存在性*,而非锚点有效性:指向一个真实文件但带有 `#wrong-heading` 片段的链接仍会通过(文件可解析;片段被剥除)。 @@ -28,6 +28,6 @@ Status: implemented ## 后果 -- 重命名或移动文件导致交叉链接悬空时,现在会在 pre-push 钩子和 CI 中失败,而不是等读者点击死链才发现。这使得引入本门禁的 RFC 重组具备自验证能力:改写四十条链接的同一个 PR 也添加了证明无一悬空的检查。 +- 造成交叉链接失效的重命名与移动会直接使 `doc-sync` 和 CI 失败,而不是等读者点击死链才暴露。由此,引入该门禁的 Agent Note 重组具备自校验能力:同一个 PR(Pull Request)在改写 40 条链接的同时,也添加了证明这些链接均未悬空的检查。 - `doc-sync` 链中多了一个快速 tsx 脚本;无新增依赖(mdast/GFM 技术栈已作为 `verify-md-wrap` 的 devDependencies 存在)。 -- 本门禁强制的约定——通过可机械检查的相对链接引用文档,而非裸文本或编号——记录在 [docs/AGENTS.md](../../../AGENTS.md) 中,让作者知晓门禁的存在与原因。 +- 该门禁强制执行的约定是:文档交叉引用必须使用可机械检查的相对链接,绝不能只写纯文本或编号。[docs/AGENTS.md](../../../../docs/AGENTS.md)记录了这项约定,使作者了解该门禁及其理由。 diff --git a/.agents/notes/implemented/process/2026-06-20-agent-note-classification.i18n.yaml b/.agents/notes/implemented/process/2026-06-20-agent-note-classification.i18n.yaml index c9a4c3a6e9..cc0a877084 100644 --- a/.agents/notes/implemented/process/2026-06-20-agent-note-classification.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-20-agent-note-classification.i18n.yaml @@ -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 -2026-06-20-rfc-classification.md: 6975b74dbaa9ca9379f23b537133323cb694958a -2026-06-20-rfc-classification.zh.md: 423d5c87eb9e2cb07ed18834f4c15ffa1ac1983e +2026-06-20-agent-note-classification.md: 094233ed108e35e390cdc66b419179249c2d9173 +2026-06-20-agent-note-classification.zh.md: b424b07e051507a894c8f5961feb5fe24a9da3c6 diff --git a/.agents/notes/implemented/process/2026-06-20-agent-note-classification.md b/.agents/notes/implemented/process/2026-06-20-agent-note-classification.md index 750a3586e0..094233ed10 100644 --- a/.agents/notes/implemented/process/2026-06-20-agent-note-classification.md +++ b/.agents/notes/implemented/process/2026-06-20-agent-note-classification.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-20-agent-note-classification.zh.md) + ## Problem A lifecycle-only Agent Note tree — `proposed/` / `implemented/` / `rejected/` — does not record what *kind* of decision each file contains. A reader browsing one lifecycle cannot distinguish a new capability from a removal or a tooling-policy change without opening each file. diff --git a/.agents/notes/implemented/process/2026-06-20-agent-note-classification.zh.md b/.agents/notes/implemented/process/2026-06-20-agent-note-classification.zh.md index 423d5c87eb..b424b07e05 100644 --- a/.agents/notes/implemented/process/2026-06-20-agent-note-classification.zh.md +++ b/.agents/notes/implemented/process/2026-06-20-agent-note-classification.zh.md @@ -1,48 +1,48 @@ -# RFC: 通过路径编码的子目录对 RFC 进行分类 +# Agent Note: 通过路径编码的子目录对 Agent Note 进行分类 Status: implemented -[English](2026-06-20-rfc-classification.md) | 中文 +[English](2026-06-20-agent-note-classification.md) | 中文 ## 问题 -`docs/rfc/` 过去仅按**生命周期**分组 RFC:`proposed/`/`implemented/`/`rejected/`。没有任何机制记录每个 RFC 属于哪一*类*决策。索引在每个生命周期下只是一个扁平列表,无法按需筛选「所有简化类」或「所有测试策略类」决策。一批简化类 RFC 在同一天落地后,这个缺口变得具体:浏览 `proposed/` 的读者无法在不逐一打开文件的情况下区分新能力、移除和工具策略变更。 +仅按生命周期组织的 Agent Note(agent 决策记录)目录树(`proposed/` / `implemented/` / `rejected/`)无法记录每个文件包含哪一*类*决策。读者浏览某个生命周期时,如果不逐一打开文件,就无法区分新功能、移除项或工具策略变更。 本仓库一贯的倾向是[机械质量门禁优于行文规范](2026-06-11-quality-gates.md):不被机器检查的约定终将腐烂。因此这里的分类方案必须可强制执行,而非靠自觉的文件头。 ## 决策 -增加第二个维度——RFC 的**类别**——并将其编码在路径中:`{lifecycle}/{class}/yyyy-mm-dd-topic.md`。文件夹本身*就是*标签。文件的位置声明其类别,封闭集合是「这些文件夹且仅限这些」,而既有的 [verify-md-links](2026-06-18-markdown-cross-link-lint.md) 门禁已经保护了移动文件所需的路径重写。 +增加第二个维度,即 Agent Note 的**类别**,并将其编码在路径中:`{lifecycle}/{class}/yyyy-mm-dd-topic.md`。文件夹*就是*标签。文件位置声明其类别;封闭集合限定为「这些文件夹且仅限这些」;既有的 [verify-md-links](2026-06-18-markdown-cross-link-lint.md) 门禁已经保护移动文件所需的路径改写。 ### 六个类别的封闭集合 | 类别 | 涵盖范围 | |---|---| -| `feature` | 面向用户或模型的新能力。 | +| `feature` | 面向用户或模型的新功能。 | | `bug-fix` | 修正缺陷或填补事后复盘暴露的空白。 | -| `simplification` | 移除代码、行为或对外表面积,不引入新能力。 | +| `simplification` | 移除代码、行为或对外表面积,不引入新功能。 | | `architecture` | 关于**交付源码**的结构性决策——包(package)之间的关系、运行时词汇。 | | `process` | **围绕**代码的工具、策略或工作流,而非运行时行为。 | | `testing` | 测试基础设施与策略。 | -`architecture` 与 `process` 的分界线:**architecture** 关乎我们交付的源码;**process** 关乎围绕源码的工具与工作流。本 RFC 本身是一个 `process` 决策——它改变的是仓库的组织方式和门禁,而非 harness 的运行时行为——因此它位于 `implemented/process/` 下。 +`architecture` 与 `process` 的分界是:**architecture** 关乎我们交付的源码;**process** 关乎源码周边的工具与工作流。本 Agent Note 本身属于 `process` 决策:它改变仓库的组织方式与门禁,而不是 harness 的运行时行为,因此位于 `implemented/process/` 下。 ### 两道门禁 两者都是 `doc-sync`(文档同步门禁)的成员,风格与 `verify-md-wrap` 一致(tsx ESM,只校验不生成,首个违规即以非零退出码退出): -- **`scripts/verify-rfc-classification.ts`**——封闭集合与索引新鲜度。它断言生命周期文件夹下的每个文件都位于规范集合中的某个类别文件夹内(生命周期根目录下的散落 `.md` 或未知类别文件夹均判定失败),并断言生成的 [INDEX.md](../../INDEX.md) 与从目录树重新渲染的结果逐字节一致(见[生成 RFC 索引表](2026-07-04-generate-rfc-index-tables.md))。规范类别集合以 `const` 形式定义在 `scripts/rfc-index.ts` 中——这是与生成器共享的机器真源——而 [README](../../README.md) 以行文形式记录它;类别*描述*保持手写,索引由机器生成。 -- **`scripts/verify-doc-refs.ts`**——源码注释中的文档引用。RFC 路径不仅被 Markdown 引用,也被 TypeScript 文档注释引用(以仓库根为起点的路径,如 `docs/rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md`)。`verify-md-links` 从未扫描过这些引用,因此重组可能使它们静默失效。此门禁扫描 `packages/**` 和 `examples/**` 下仓库自有的 `.ts` 文件(排除构建产物 `lib/` 和 `vendor/`),查找 `docs/….md` 形式的 token,将每个以仓库根为起点的路径解析并断言其存在。它要求 `.md` 扩展名,因此无扩展名的行文引用(`docs/postmortem/0001`、`docs/architecture.md § Extending The Harness`)不受影响。 +- **`scripts/verify-agent-note-classification.ts`**:定义封闭的生命周期与类别集合。它断言生命周期文件夹下的每个文件都位于规范集合中的类别文件夹内(生命周期根目录下散落的 `.md` 或未知类别文件夹都会失败),并拒绝集中式 `INDEX.md`。规范集合位于 `scripts/agent-note-tree.ts` 中,[README](../../README.md)则以行文记录每个类别。 +- **`scripts/verify-doc-refs.ts`**:检查引用文档的源码注释。Agent Note 路径不仅出现在 Markdown 中,也出现在 TypeScript 文档注释中(例如以仓库根为起点的 `.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md`)。`verify-md-links` 看不到这些引用,因此目录重组可能静默留下失效引用。该门禁扫描 `packages/**` 与 `examples/**` 下仓库自有的 `.ts` 文件(排除已构建的 `lib/` 与 `vendor/`),查找 `docs/….md` 和 `.agents/notes/….md` token,解析每个以仓库根为起点的路径并断言其存在。它要求使用 `.md` 扩展名,因此不处理无扩展名的行文。 ## 曾考虑的替代方案 - **在每个文件中添加 `Classification:` 行文行**(紧邻 `Status:`),由门禁解析。可行,但它将路径已能承载的事实重复到文件中,且行内容可能与所在文件夹不一致。路径编码使标签与其存储合二为一,没有需要保持同步的东西。 - **设立 `refactor` 类别。** 与 `simplification` 几乎完全重叠;唯一有人试图用来区分的标准是「可观察行为是否改变?」,而 `simplification` 已经编码了这一点(它不改变)。一个类别即可,无需两个。 -- **从文件系统自动生成索引。** 此处最初否决,以保持索引手写;后被[生成 RFC 索引表](2026-07-04-generate-rfc-index-tables.md)取代——当堆叠的提案潮使手写表格成为仓库中冲突最频繁的文档区域后,列表改为完全生成的 [INDEX.md](../../INDEX.md),而 README 行文保持人工维护。 +- **生成或手工维护的语料索引。** 不予采纳:生命周期/类别目录树才是权威结构;集中式清单会制造合并热点,却没有提供目录树导航或仓库搜索无法实现的发现能力。单独的[索引提案](../../rejected/process/2026-07-04-generate-agent-note-index-tables.md)记录了被放弃的生成形状。 ## 后果 -- 每个 RFC 现在都位于一个类别文件夹下,索引在每个生命周期内按类别分组。读者只需扫一个标题即可看到所有简化类或所有测试类决策。 +- 每份 Agent Note 都位于一个类别文件夹下。读者浏览单个文件夹,即可查看某个生命周期内的全部简化或测试决策。 - `doc-sync` 链中多了两个快速 tsx 脚本;无新依赖(mdast/GFM 栈已因 `verify-md-wrap`/`verify-md-links` 而存在)。 -- 新增类别是一个刻意的动作:修改 `scripts/rfc-index.ts` 中的 `const` 和 [Classification 章节](../../README.md#classification),而非仅仅 `mkdir` 一个文件夹。门禁拒绝未知文件夹,因此临时类别无法悄悄混入。 -- 源码注释中的文档引用现在也受门禁保护——一个被移动或重命名的文档如果被 `.ts` 注释引用,pre-push 钩子就会失败,堵住了 `verify-md-links` 在结构上无法看到的一类漂移。 +- 新增类别必须是显式决策:修改 `scripts/agent-note-tree.ts` 中的 `const` 与 [Classification 章节](../../README.md#classification),而不是只用 `mkdir` 创建文件夹。门禁会拒绝未知文件夹,因此临时类别无法悄然混入。 +- 源码注释中的文档引用同样受门禁约束:被 `.ts` 注释引用的文档一旦移动或重命名,`doc-sync` 与 CI 中的 `verify-doc-refs` 就会失败,从而堵住 `verify-md-links` 在结构上无法发现的一类漂移。 diff --git a/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml b/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml index 7b498b0a81..ca85bc0c2f 100644 --- a/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.i18n.yaml @@ -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 -2026-06-20-core-data-structures-catalog.md: 933844d0f442306af238bfc459372b1c97414f87 -2026-06-20-core-data-structures-catalog.zh.md: 620457b28d6b4aa36ec139da7bcd892ed78e2673 +2026-06-20-core-data-structures-catalog.md: a2f5e0e7b06e34cb361e4944bbfa3692355a2cbe +2026-06-20-core-data-structures-catalog.zh.md: ee740fd1fb7e5c335bf80e57e27d0a4651be49bd diff --git a/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.zh.md b/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.zh.md index 620457b28d..ee740fd1fb 100644 --- a/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.zh.md +++ b/.agents/notes/implemented/process/2026-06-20-core-data-structures-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC: 核心数据结构目录与 `ts type-equiv` 漂移门禁 +# Agent Note: 核心数据结构目录与 `ts type-equiv` 漂移门禁 Status: implemented @@ -6,13 +6,13 @@ Status: implemented ## 问题 -一位想要理解 harness 的读者,可以在 [architecture.md](../../../architecture.md) 中找到它的*行为*(服务映射、session/turn/step 生命周期、事件分类体系),但没有一个集中的地方描述它的*词汇*——即行为所操作的数据结构。类型形状只存在于源码中,分散在各个 `packages/*/src/types.ts` 里,因此要理解「什么是 `Message`、`SessionEvent`、`StreamChunk`」就得直接阅读声明。一份行文目录会有帮助,但如果目录是对类型定义的转述或粘贴复制,那么字段一改它就会腐烂——而失去同步的类型文档比没有更糟,因为读者会信任它。 +试图理解 harness 的读者可以在 [architecture.md](../../../../docs/architecture.md) 中找到它的*行为*(服务图、session/turn/step 生命周期、事件分类),却找不到一个统一描述其*词汇*的地方,也就是这些行为所传递的数据结构。类型形状只存在于源码中,散落在 `packages/*/src/types.ts` 各处,因此要理解“什么是 `Message`、`SessionEvent`、`StreamChunk`”,就必须直接阅读声明。文字目录会有所帮助,但复述或复制粘贴类型定义的目录会在字段发生变化时立即腐化,而不同步的类型文档比没有文档更糟,因为读者会信任它。 -因此这项工作包含两个交织的问题:**这样的目录应当收录什么**(范围界定问题——一个 harness 有数十个跨包类型,全部堆上去对谁都没帮助),以及**如何防止粘贴的类型定义漂移**(持久性问题)。本 RFC 记录两项决策。它的姊妹篇 [生成式 Cordis 事件 + 服务目录](2026-06-20-generated-cordis-catalog.md) 是*接线*轴的补充:本篇编目数据结构,那篇编目传递数据结构的事件与服务。 +因此,这项工作有两个相互交织的问题:**这样的目录应包含什么**(范围问题——harness 有数十个跨包类型,把它们全部倾倒进来对谁都没有帮助),以及**如何避免粘贴的类型定义发生漂移**(持久性问题)。本 Agent Note(agent 决策记录)记下了这两项决策。与它配套的[生成式 Cordis 事件与服务目录](2026-06-20-generated-cordis-catalog.md)从*接线*维度形成补充:本文对数据结构编目,另一篇则对传递这些结构的事件和服务编目。 ## 决策 -新建 `docs/core-data-structures/` 文件夹编目词汇,并新增 `verify-type-equiv` doc-sync(文档同步门禁)门禁,确保每处粘贴的类型定义与源码逐字节一致。 +新增的 `docs/core-data-structures/` 目录对这些词汇编目,并配有新的 `verify-type-equiv` 文档同步门禁,使每个粘贴的类型声明及其 JSDoc 与源码保持同步。 ### 何为"核心"——主干与 seam 的分界线 @@ -29,12 +29,12 @@ Status: implemented ### `ts type-equiv` 机制——既逐字又防漂移 -持久性需求很具体:文档应当展示**当前类型定义的原文**(让读者看到真实形状,而非转述),**并且**机械地保证与源码一致。仓库已经能编译围栏 ` ```ts ` 块(`doc-typecheck`),但一个真正可编译的块需要 import 噪音,且只证明*可赋值性*而非*字节相等*——一个类型相同但改了名的字段会通过。因此: +持久性要求很具体:文档展示当前类型声明与原始 JSDoc 的**逐字**内容(让读者看到真实形状和源码契约,而非复述),**并且**以机械方式保证其与源码匹配。仓库已经会编译 ` ```ts ` 围栏块(`doc-typecheck`),但真正接受类型检查的块需要导入噪音,而且只能证明*可赋值性*——字段改名或 JSDoc 变化仍可能通过。因此: -- 类型定义逐字粘贴到专用的 ` ```ts type-equiv ` 围栏中。`doc-typecheck` 识别该围栏并跳过它(裸定义不能独立编译),且**将其排除在 opt-out 比例之外**——它是一个独立检查的类别,而非未检查的草稿。 -- 新增的 `scripts/verify-type-equiv.ts` 通过 TypeScript 解析器提取每个块,并断言其与声明的符号**逐字节匹配源码**——之所以选择这种方式而非编译式 `_Check` 可赋值性断言,正是因为我们需要的属性是字节相等,而非可赋值性。 +- 完整的类型声明及其 JSDoc 会逐字粘贴到专用的 ` ```ts type-equiv ` 围栏中。简洁的 ` ```ts public-api ` 围栏承载与源码等价的类环境投影,用于实现体不应进入目录的类。`doc-typecheck` 会识别并跳过这两种围栏(裸声明无法独立编译),并且**将它们排除在退出检查比例之外**——它们是单独受检的类别,而不是未经检查的草图。 +- 新增的 `scripts/verify-type-equiv.ts` 通过 TypeScript 解析器提取每个块,并断言其声明结构和每条 JSDoc 注释都与所声明的符号匹配,只忽略格式空白和非 JSDoc 注释。普通块保留完整声明。`public-api` 投影保留类的公共字段、构造函数、访问器和方法及其原始 JSDoc,同时移除实现体以及私有或受保护成员。之所以选择它而非编译式 `_Check` 断言,是因为目录所保留的是源码名称与文档一致性,而不是可赋值性。 - 来源信息存放在集中的 `scripts/type-equiv.manifest.json`(`{ doc, symbol, source }` 条目)中,**而非**行文中的指令注释。脚本强制执行 **1:1 对应**:每个 type-equiv 块恰好有一条 manifest 条目,反之亦然;因此一个块永远不会被静默漏检,一条条目也永远不会腐烂。 -- 接入 `doc-sync`,因此与其他文档门禁在同一条 lefthook pre-push 和 CI 路径中运行。 +- 接入 `doc-sync`,因此相关文档变更会在本地运行它,CI 也会与其他文档检查一起运行它。 ### 维护是作者的职责,门禁作为兜底 @@ -43,18 +43,18 @@ Status: implemented ## 曾考虑的替代方案 - **平铺罗列所有跨包词汇**:`BashExecRequest` 测试案例否决了它。如果 seam 词汇算"核心",目录对谁都没帮助;分层的主干与 seam 结构胜出。 -- **编译式 `_Check` 可赋值性断言**替代逐字节源码匹配:否决,因为我们需要的属性是字节相等而非可赋值性——一个类型相同但改了名的字段会通过可赋值性检查。 +- **用编译式 `_Check` 可赋值性断言**代替源码匹配:否决。可赋值性不会保留名称或 JSDoc;同类型字段改名或契约注释变化仍会通过。 - **来源信息作为行文中的指令注释**:否决,改用集中 manifest;其强制的 1:1 对应确保一个块永远不会被静默漏检,一条条目也永远不会腐烂。 ## 验证教训 主干与 seam 规则在采纳前经过了 `BashExecRequest`、工具 schema 与定义、schema DSL、展示类型以及 session/persistence 拆分的逐一测试。 -`verify-type-equiv` 必须扫描完整的 Markdown 范围,而不仅仅是 manifest 中列出的文档。否则一个未登记的 `type-equiv` 块会逃脱所声称的一对一检查。因此门禁将此类块报告为遗留块。本 RFC 将这条快速失败的扫描规则与主干-seam 分界线和逐字节匹配决策一并记录;生成式 Cordis 目录在[其 RFC](2026-06-20-generated-cordis-catalog.md) 中有对称的设计记录。 +`verify-type-equiv` 必须扫描完整的 Markdown 范围,而不仅是清单点名的文档。否则,未列入清单的 `type-equiv` 块就会逃过所宣称的一一检查。因此,门禁会将此类块报告为孤儿。本 Agent Note 将这条失败关闭扫描规则与主干/接缝、逐字匹配决策一并记录;生成式 Cordis 目录在[其 Agent Note](2026-06-20-generated-cordis-catalog.md) 中有对称的设计记录。 ## 后果 -- 词汇现在有了一个**不会静默漂移**的唯一归属:源码中的字段重命名会在 pre-push 钩子和 CI 中导致 `verify-type-equiv` 失败,直到粘贴内容被刷新。 +- 这些词汇现在有一个**无法悄然漂移**的唯一归属:源码中的字段或公共类成员发生变化后,`doc-sync` 和 CI 中的 `verify-type-equiv` 会持续失败,直至粘贴内容刷新。Cordis 服务方法仍由生成式服务目录负责,而不会在此重复。 - 主干与 seam 分界线是一个可复用的范围界定工具,而非一次性的:同一条「你编写/持有/接收的东西是核心;为其提供类型推导/渲染/持久化的机制是细节」规则,后来也被用于界定事件/服务目录的 harness 层与继承层分层。 - `ts type-equiv` 围栏是继 ` ```ts `(编译)和 ` ```ts ignore-check `(草稿)之后的第三种文档块类别。后续的姊妹门禁又增加了第四种 ` ```ts cordis-catalog `(生成签名),复用了相同的跳过并排除处理。 - 添加或重塑核心类型现在附带一项文档义务,作者必须履行(门禁无法检测缺失的*新*类型),由 `dsh-code-review` 检查清单兜底。 diff --git a/.agents/notes/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml b/.agents/notes/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml index 13f31c3ebe..3182edd49f 100644 --- a/.agents/notes/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml +++ b/.agents/notes/implemented/process/2026-06-20-generated-cordis-catalog.i18n.yaml @@ -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 -2026-06-20-generated-cordis-catalog.md: 8b979764c1ae6693b77817fc84381e40e56f8d36 -2026-06-20-generated-cordis-catalog.zh.md: 608ab3e0429fab43abec634ce0955f46306d8529 +2026-06-20-generated-cordis-catalog.md: b5957cf06a9316447aae70183de462024bb24be3 +2026-06-20-generated-cordis-catalog.zh.md: 33983d7693e1c67ac210b3ce23d28e7d46571ff9 diff --git a/.agents/notes/implemented/process/2026-06-20-generated-cordis-catalog.zh.md b/.agents/notes/implemented/process/2026-06-20-generated-cordis-catalog.zh.md index 608ab3e042..33983d7693 100644 --- a/.agents/notes/implemented/process/2026-06-20-generated-cordis-catalog.zh.md +++ b/.agents/notes/implemented/process/2026-06-20-generated-cordis-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC: 生成式 Cordis 事件与服务目录 +# Agent Note: 生成式 Cordis 事件与服务目录 Status: implemented @@ -8,13 +8,13 @@ Status: implemented 插件作者需要两个参考面,而此前没有任何单一文档能提供:他们可以监听的每一个 Cordis **事件**(含精确签名与分发模式),以及他们可以调用的每一个 `ctx.<key>` **服务**(含精确接口)。相关信息虽然存在,但散落各处:`docs/architecture.md` 中一张手工维护的事件分类*表格*(名称 + 行文描述的 Mode/Purpose,由 `verify-event-taxonomy` 做名称集合校验)、一张服务映射表(8 行角色描述),以及 `interface Events` / `interface Context` 声明本身。分类表格还有一个盲区:它无法捕获全新的*未记录*事件——名称集合校验器只检查两侧已有的名称。 -这是 [core-data-structures 目录](../../../core-data-structures/core.md)([其 RFC](2026-06-20-core-data-structures-catalog.md))在连线轴上的补充:后者编目的是 agent loop(智能体循环)流转的*数据结构*(经校验的手工粘贴);本 RFC 编目的是移动这些数据结构的*事件与服务*。 +这是对[核心数据结构目录](../../../../docs/core-data-structures/core.md)([其 Agent Note(agent 决策记录)](2026-06-20-core-data-structures-catalog.md))在接线维度上的补充:前者对循环传递的*数据结构*编目(经验证的手工粘贴),本文则对传递它们的*事件和服务*编目。 ## 决策 从源码生成目录,取代手工维护表格并校验子集的方式。 -`scripts/gen-cordis-catalog.ts` 使用 TypeScript 编译器 API,从声明和源码 JSDoc 分别输出事件参考与服务参考。事件包含分发模式;服务包含公开签名。确定性的 `--write` 和 `--check` 模式使两个页面成为生成产物,新鲜度由 `doc-sync`(文档同步门禁)强制保障。 +`scripts/gen-cordis-catalog.ts` 使用 TypeScript 编译器 API,根据声明和源码 JSDoc 分别生成事件与服务参考。事件包含分派模式及其原始成员 JSDoc;服务包含公共签名及各方法的原始 JSDoc。确定性的 `--write` 和 `--check` 模式使两个页面成为生成产物,并由 `doc-sync` 强制检查新鲜度。 纯生成在此处是正确的,因为代码库足够规范,AST 就是全部事实:每个事件/服务名称都是字符串字面量,可以往返映射到静态声明——不存在动态命名的事件,也不存在仅运行时的服务。因此生成的文档不可能出错,且从结构上消除了未记录事件的缺口(生成器枚举源码,而非校验手写子集)。 @@ -22,8 +22,8 @@ Status: implemented - **`@mode` 标签,交叉校验。** 每个 harness 事件的 JSDoc 携带一个显式的 `@mode emit|waterfall|parallel|serial` 标签;缺少标签时生成器直接报错。当签名形状具有决定性时——尾部参数为 `next: () => …` 在结构上即为 waterfall(瀑布式事件)——生成器断言标签与之一致,矛盾时直接报错。emit/parallel/serial 的区别在结构上不可见(`session/flush` 返回 `Promise<void> | void` 且无 `next`,有序的 `agent/pre-step` 检查点亦然),因此信任标签。编写规则见 [AGENTS.md](../../../../AGENTS.md)。 - **分层范围。** harness 层(8 个 `@deepseek-ai/dsh-*` 服务及其事件)从源码完整渲染。继承层(cordis-core 的 `ctx.on/emit/effect/provide/…` + `internal/*` 事件 + loader/hmr/timer)是插件同样可见的固定 vendor 源码;它从生成器中一张人工维护的表格简洁渲染(名称 + 一行描述 + 源码指针),而非遍历 vendor AST。原因是 cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段(`root`、`baseUrl`、`logger`),且 vendor 接口面仅在有意的 vendor 同步时才变化。 -- **交叉链接到数据结构目录。** 签名中的类型名(`GenerateOptions`、`StreamChunk`、`ToolDefinition` 等)链接到记录该类型的 core-data-structures 页面。映射是生成器中一个小型的人工维护常量,而非 `type-equiv.manifest.json`——后者记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 -- **专用围栏。** 签名块使用 ` ```ts cordis-catalog ` 信息字符串,`doc-typecheck` 识别后跳过(裸签名片段不能独立编译),并排除在 opt-out 比例之外——与 `type-equiv` 块获得相同待遇。 +- **指向数据结构目录的交叉链接。** 签名中由仓库拥有的每个类型名(`GenerateOptions`、`StreamChunk`、`ToolDefinition`……)都会通过人工维护的映射链接到其主要核心数据结构页面。AST 遍历采用失败关闭策略:每个参数、泛型约束/默认值和返回类型引用都必须已映射、是签名自身的类型参数、是点名的 TypeScript/Cordis 基础类型,或带有点名的例外及其非目录文档归属。违规会连同源码位置汇总报告,并点明相应的归属列表。该映射不会复用 `type-equiv.manifest.json`,因为后者记录 `…Map` 符号,而签名引用派生的联合类型名,并且会在多个页面列出某些符号。 +- **专用围栏。** 签名块使用 ` ```ts cordis-catalog ` 信息字符串,并把原始事件或公共方法 JSDoc 直接放在其声明之前。`doc-typecheck` 会识别并跳过这些裸片段,将其排除在退出检查比例之外——与 `type-equiv` 块的处理相同。 本决策**取代** [doc-sync 强制](2026-06-11-doc-sync-enforcement.md)中事件分类的那一半:`verify-event-taxonomy` 及其 `docs/architecture.md` 表格退役(architecture.md 的标题保留,正文改为指向目录;服务映射的角色表格作为人工行文保留)。doc-typecheck、verify-md-wrap、verify-md-links 和 verify-type-equiv 不受影响。 @@ -31,11 +31,11 @@ Status: implemented - **校验而非生成(退役的分类检查所做的事)**:*仅对本参考面*反转了这一策略。此处的数据可以机械地完整获取,因此生成严格强于对手工表格做名称集合校验(完整签名、不会漂移、能捕获未记录事件)。 - **遍历 vendor AST 以获取继承层**:否决,改用人工维护表格。cordis-core 的 `Context` 混合了真正的 ctx 成员与非服务字段,且固定的 vendor 接口面仅在有意同步时才变化。 -- **复用 `type-equiv.manifest.json` 作为签名交叉链接映射**:否决,改用小型人工维护常量。manifest 记录的是 `…Map` 符号,而签名引用的是派生联合类型名,且有少数符号出现在两个页面上。 +- **复用 `type-equiv.manifest.json` 作为签名交叉链接映射**:否决,改用完整的人工维护常量和失败关闭覆盖。清单记录 `…Map` 符号,而签名引用派生的联合类型名,并且会在多个页面列出某些符号。显式映射让每个渲染目标和每个非目录例外都成为可评审的决策。 ## 后果 -- 目录不会漂移:源码变更而已提交文件未反映时,`verify-cordis-catalog` 在 pre-push 钩子和 CI 中失败。新事件缺少 `@mode` 标签,或标签与签名矛盾,生成器直接报错。 -- 事件的行文描述现在有了唯一归属地——声明处的 JSDoc。JSDoc 写得单薄,目录条目就单薄,这迫使作者在源码处做好文档(生成器是 AGENTS.md「每个导出都有语义 JSDoc」规则的强制函数)。 +- 目录不会发生漂移:提交文件未反映的源码变化会使 `doc-sync` 和 CI 中的 `verify-cordis-catalog` 失败。新事件缺少 `@mode` 标签、标签与其签名冲突,或签名类型未分类,都会直接使生成器失败。 +- 事件与服务方法契约只有一个归属——声明处的 JSDoc。目录会在生成的签名块中重复该原始 JSDoc,并使用其描述部分作为条目正文,因此单薄的源码文档只会生成单薄的目录条目。 - 继承层是手工摘要,因此 vendor 同步若新增或重命名了 cordis-core 事件或 `ctx` 成员,需要同步编辑 `gen-cordis-catalog.ts` 中的人工维护表格。这是不遍历固定 vendor 源码的有意代价;它很少变化,且在生成器中有明确标注。 - `verify-event-taxonomy.ts` 被删除,`docs/architecture.md` 的事件表格也已移除;之前链接到特定表格行的人现在会落在生成目录上。 diff --git a/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml b/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml index 80865d0269..b64d63b3ff 100644 --- a/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.i18n.yaml @@ -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 -2026-07-02-tool-schema-catalog.md: fe7ec47ac89c157482f612a374ca8773d7d0867f -2026-07-02-tool-schema-catalog.zh.md: 1567ff5dd5c53da501a86412d0e29127d33d29f6 +2026-07-02-tool-schema-catalog.md: c8cc69df428f6eee0f66ed976865afe2a0702448 +2026-07-02-tool-schema-catalog.zh.md: 7caa9e8747d8fd09806342035d185e664f7be7b7 diff --git a/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.zh.md b/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.zh.md index 1567ff5dd5..7caa9e8747 100644 --- a/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.zh.md +++ b/.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC: 生成式工具 schema 目录(启动并采集) +# Agent Note: 生成式工具 schema 目录(启动并采集) Status: implemented @@ -10,7 +10,7 @@ Status: implemented ## 决策 -通过**启动每个工具插件并读取其注册的 schema** 来生成目录,而非解析源码。`scripts/gen-tool-catalog.ts` 将每个已发布的工具包(package)挂载到一个新的 Cordis `Context`(带 `SystemPrompt` + `ToolRegistry` 以及插件 `apply` 所读取的注入 seam),调用 `ctx.tools.schemas()`(即发送给模型的 `ToolSchema[]`),dispose(资源释放)该 context,然后为每个包渲染一个 `## <package>` 小节,每个工具一个 ` ```json ` 的 `parameters` 块。它与 `gen-cordis-catalog` / `gen-module-graph` 的 CLI(命令行界面)形态一致:默认 `--write` 重新生成,`--check` 在已提交副本陈旧时失败,输出是确定性的(按 manifest(元数据清单)排序,工具按名称排序)。`verify-tool-catalog`(即 `--check`)在 `doc-sync`(文档同步门禁)内运行,因此新鲜度门禁在 lefthook pre-push 和 CI 路径中与其他文档门禁一同触发。 +目录通过**启动每个工具插件并读取其已注册 schema** 来生成,而不是解析源码。`scripts/gen-tool-catalog.ts` 在全新的 Cordis `Context` 上挂载每个已发布工具包(带有 `SystemPrompt`、`ToolRegistry` 以及插件 `apply` 所读取的注入接缝),调用 `ctx.tools.schemas()`——也就是发送给模型的确切 `ToolSchema[]`——随后释放上下文,并为每个包渲染一个 `## <package>` 章节,每个工具附带一个 ` ```json ` `parameters` 块。它与 `gen-cordis-catalog` / `gen-module-graph` 的 CLI 形状一致:默认 `--write` 重新生成;提交副本陈旧时 `--check` 失败;输出具有确定性(按清单排序,工具按名称排序)。`verify-tool-catalog`(即 `--check`)在 `doc-sync` 内运行,因此相关文档变更和 CI 会执行同一项新鲜度检查。 ### 为何启动而非解析(核心要点) @@ -21,7 +21,7 @@ Cordis 目录是纯 TypeScript AST 遍历,因为每个事件/服务名都是 - `tool-subagent` 的工具名是 `config.toolName ?? 'subagent'`——加载时选定,并非字面量。 - MCP 插件可以通过 `ctx.tools.register()` 直接注册**原始 JSON Schema**,完全不经过 `defineTool`,因此结构化枚举 `defineTool(` 调用点会遗漏。 -唯一忠实的真源是插件加载后注册表实际持有的 schema。启动是[测试策略](../../../testing.md)中「验证世界,而非自我报告」这一原则在文档生成器上的应用:读取已发布的产物,而非对它的再推导。 +唯一忠实的事实来源,是插件加载后注册表实际持有的 schema。启动插件是把[测试策略](../../../../docs/testing.md)中“验证现实,而非自我报告”的准则应用到文档生成器:读取已发布产物,而非重新推导一份。 ### 恢复「不会静默遗漏」的保证 @@ -33,7 +33,7 @@ Cordis 目录是纯 TypeScript AST 遍历,因为每个事件/服务名都是 ### 范围 -`packages/*/tool-*` 下已发布的产品工具包,每个以默认配置启动:`dsh-tool-bash`(`bash`、`bash_output`、`bash_kill`)、`dsh-tool-todo`(`todo_write`)、`dsh-tool-subagent`(`subagent`)。`examples/` 下的演示工具(`echo`)被排除,与 Cordis 目录仅覆盖 packages 的范围一致——演示工具不属于读者所查阅的产品接口。 +`packages/*/tool-*` 下已发布的产品工具包,每个都使用默认配置启动,包括 `dsh-tool-bash`(`bash`)、`dsh-tool-tasks`(`task_output`、`task_list`、`task_kill`)和 `dsh-tool-subagent`(`subagent`)。仅供示例使用的工具不在范围内。 目录的单位是包,而非每个配置化的工具实例。每个包以默认配置启动一次;加载时的别名(如 `subagent_fork`)会注明,但不枚举所有部署排列。部署清单是一个独立的、无界的接口。 @@ -49,7 +49,7 @@ schema 块使用 ` ```json `,而非自定义的 `ts` 系围栏。`doc-typechec ## 后果 -- 目录不会漂移:工具 schema 变更而已提交文件未反映,`verify-tool-catalog` 会在 pre-push 钩子和 CI 中失败。新 `tool-*` 包未加入 manifest 则完整性守卫直接报错。 +- 目录不会发生漂移:提交文件未反映的工具 schema 变化会使 `doc-sync` 和 CI 中的 `verify-tool-catalog` 失败。新增的 `tool-*` 包若未加入清单,会直接使完整性守卫失败。 - 工具描述文本有唯一归属——源码中 `defineTool` 的 `description`——生成的条目质量取决于它,与 Cordis 目录对事件 JSDoc 施加的强制力相同。 - 生成器导入并执行工作区包(这是仓库中第一个这样做的脚本;其他脚本只读文本)。它通过根 `tsconfig` 的 `paths` 映射在 `tsx` 下运行,使用与演示和测试相同的未构建源码路径,因此不需要构建步骤。 - 未来某个工具背后新增一个能力 seam,意味着 manifest 中需要新增一条配方条目(声明要挂载哪些 seam)。这正是上文指出的有意为之的手写成本;仅在新增工具包时才需变更。 diff --git a/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml b/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml index d5ad8c6180..bd5dda5aa4 100644 --- a/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.i18n.yaml @@ -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 -2026-07-03-documentation-graph-atlas.md: 3cb8e685452a5b013798d0c3f661fca218b3d69d -2026-07-03-documentation-graph-atlas.zh.md: f03268c63c6d834c59af6cf831a34e5a5eaf40d7 +2026-07-03-documentation-graph-atlas.md: 9a30b13f9db6ceb2715517230e349cbe083850ec +2026-07-03-documentation-graph-atlas.zh.md: 438f1e6de696712d8dd2f1b503d15d1b42506cf9 diff --git a/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.zh.md b/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.zh.md index f03268c63c..438f1e6de6 100644 --- a/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.zh.md +++ b/.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.zh.md @@ -1,4 +1,4 @@ -# RFC: 面向维护者与 SDK 用户的文档关系图索引 +# Agent Note: 面向维护者与 SDK 用户的文档关系图索引 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -仓库已有若干高可信度的文档面,各自覆盖不同维度:[module-graph.md](../../../module-graph.md) 由包(package)的 `peerDependencies` 生成;生成的 [Cordis events](../../../cordis-catalog/events.md) 与 [services](../../../cordis-catalog/services.md) 目录由 Cordis 的 `Events` 和 `Context` 声明生成;[tool-catalog.md](../../../tool-catalog.md) 通过启动已发布的 tool 插件生成;[core-data-structures/](../../../core-data-structures/core.md) 使用 `ts type-equiv` 块保持粘贴的类型定义与源码同步。 +仓库已经有若干高可信文档表面,各自覆盖不同维度:[module-graph.md](../../../../docs/module-graph.md) 根据包的 `peerDependencies` 生成;生成式 [Cordis 事件](../../../../docs/cordis-catalog/events.md)和[服务](../../../../docs/cordis-catalog/services.md)目录根据 Cordis `Events` 和 `Context` 声明生成;[tool-catalog.md](../../../../docs/tool-catalog.md) 通过启动已发布工具插件生成;[core-data-structures/](../../../../docs/core-data-structures/core.md) 则使用 `ts type-equiv` 块使粘贴的类型定义与源码保持同步。 这些参考文档是准确的,但大多是目录式的。维护者仍需自行综合关系:哪些包构成一个能力 seam、哪个应用组装了具体的主干、哪些事件是持久的而哪些是实时的、钩子或策略插件在哪里可以拦截工作、以及哪个面向模型的工具依赖哪个服务。SDK 用户从另一个角度面临同样的问题:「我想要某种行为,应该安装或加载哪个包?应该扩展哪个事件/服务/工具?」 @@ -14,7 +14,7 @@ Status: implemented ## 决策 -新增生成的关系图文档,索引位于 [docs/graph-atlas.md](../../../graph-atlas.md),由专用生成器产出,并通过 `pnpm run verify-doc-graphs` 及既有的目录新鲜度检查(作为 `doc-sync` 的一环)进行验证。 +新增生成式关系图文档,由聚焦的生成器产出并在 [docs/graph-atlas.md](../../../../docs/graph-atlas.md) 建立索引;作为 `doc-sync` 的一部分,通过 `pnpm run verify-doc-graphs` / 现有目录新鲜度检查进行验证。 该索引是既有目录之上的关系层。它不取代精确的参考文档,而是链接到它们并解释各部分如何组合在一起。 @@ -28,20 +28,21 @@ Status: implemented ### 首批发布的索引 -首批索引链接十个关系面。包拓扑与工具-包能力映射位于已有的生成目录中(这些目录已拥有相应事实);其余聚焦图表由 `scripts/gen-doc-graphs.ts` 生成。 +该索引链接十一种关系表面。包拓扑和工具包所提供的功能位于已经拥有这些事实的现有生成式目录中;其余聚焦图表由 `scripts/gen-doc-graphs.ts` 生成。 | 关系图 | 维护模式 | 真源 | |---|---|---| -| [模块依赖图](../../../module-graph.md) | generated | `packages/*/*/package.json` 的 peer dependencies 加包分组路径 | -| [工具 schema 目录与包映射](../../../tool-catalog.md) | generated | 启动收集的工具 schema 加工具-包的服务/副作用元数据 | -| [能力 seam 与核心服务](../../../capability-seams.md) | hybrid generated | Cordis 服务声明加 `gen-doc-graphs.ts` 中的角色 manifest | -| [echo-agent 应用组合](../../../../examples/echo-agent/composition.md) | hybrid generated | `examples/echo-agent/cordis.yml` 插件列表加人工策划的应用/bundle 展开 | -| [coding-agent 应用组合](../../../../examples/coding-agent/composition.md) | hybrid generated | `examples/coding-agent/cordis.yml` 插件列表加人工策划的应用/bundle 展开 | +| [模块依赖图](../../../../docs/module-graph.md) | 生成式 | `packages/*/*/package.json` 的 peer dependency 与包分组路径 | +| [工具 schema 目录与包映射](../../../../docs/tool-catalog.md) | 生成式 | 启动后采集的工具 schema,以及工具包服务/效应元数据 | +| [能力接缝与核心服务](../../../../docs/capability-seams.md) | 混合生成式 | Cordis 服务声明,以及 `gen-doc-graphs.ts` 中的角色清单 | +| [tui-agent 应用组合](../../../../examples/tui-agent/composition.md) | 混合生成式 | `examples/tui-agent/cordis.yml` 插件列表,以及人工维护的应用/bundle 展开 | +| [headless-agent 应用组合](../../../../examples/headless-agent/composition.md) | 混合生成式 | `examples/headless-agent/cordis.yml` 插件列表,以及人工维护的应用/bundle 展开 | +| [cordis-agent 应用组合](../../../../examples/cordis-agent/composition.md) | 混合生成式 | `examples/cordis-agent/cordis.yml` 插件列表,以及人工维护的应用/bundle 展开 | | [acp-agent 应用组合](../../../../examples/acp-agent/composition.md) | hybrid generated | `examples/acp-agent/cordis.yml` 插件列表加人工策划的应用/bundle 展开 | -| [事件生产者/消费者矩阵](../../../event-producer-consumer.md) | hybrid generated | Cordis 事件声明、AST 扫描的 `ctx.on/emit/parallel/serial/waterfall` 调用点,以及显式的动态分发覆盖 | -| [agent 轮次与步骤生命周期](../../../agent-lifecycle.md) | curated | architecture.md 的循环生命周期、Cordis 目录链接与会话事件语义 | -| [工具执行流水线](../../../tool-execution-pipeline.md) | curated | 工具流水线语义与 `tools/execute` waterfall(瀑布式事件) | -| [ACP 快照回放](../../../../packages/ui/acp/snapshot-replay.md) | curated | 快照 harness 行为 | +| [事件生产者/消费者矩阵](../../../../docs/event-producer-consumer.md) | 混合生成式 | Cordis 事件声明、经 AST 扫描的 `ctx.on/emit/parallel/serial/waterfall` 位置,以及显式动态分派覆盖 | +| [agent turn 与 step 生命周期](../../../../docs/agent-lifecycle.md) | 人工维护 | architecture.md 循环生命周期、Cordis 目录链接,以及 session 事件语义 | +| [工具执行管线](../../../../docs/tool-execution-pipeline.md) | 人工维护 | 工具管线语义与 `tools/execute` waterfall(瀑布式事件)| +| [ACP(Agent Client Protocol)快照回放](../../../../packages/ui/acp/snapshot-replay.md) | curated | 快照 harness 行为 | ### 为什么由生成器拥有文档 diff --git a/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml b/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml index 520426ca4b..21465703e1 100644 --- a/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.i18n.yaml @@ -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 -2026-07-04-cordis-jsdoc-completeness-gate.md: 8eaa997eb734b32e7e4a45d96def15dc541af1d5 -2026-07-04-cordis-jsdoc-completeness-gate.zh.md: a49189b3162fbd0eba9e043c683f0fc56d0bf7d6 +2026-07-04-cordis-jsdoc-completeness-gate.md: c7c39986414437ce4d0d4c64f9e25f47485fdf5c +2026-07-04-cordis-jsdoc-completeness-gate.zh.md: f1e7ec824ebae119c1cb27ca4dd9f0d8330dde1a diff --git a/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md b/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md index a49189b316..f1e7ec824e 100644 --- a/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md +++ b/.agents/notes/implemented/process/2026-07-04-cordis-jsdoc-completeness-gate.zh.md @@ -1,4 +1,4 @@ -# RFC: 针对 Cordis 对外服务接口的 JSDoc 完整性门禁 +# Agent Note: 针对 Cordis 对外服务接口的 JSDoc 完整性门禁 Status: implemented @@ -12,7 +12,7 @@ AGENTS.md 中的规则(「每个导出都有解释语义的 JSDoc」)只能 ## 决策 -扩展 `scripts/gen-cordis-catalog.ts`(同一次遍历、同一个 `@mode` 先例),对其编目的所有内容强制 JSDoc 完整性。`verify-cordis-catalog` 在 `doc-sync`(文档同步门禁)内运行,CI 和 lefthook pre-push 钩子都已执行该命令,因此门禁无需新增任何接线(质量门禁原则:单一真源)。 +扩展 `scripts/gen-cordis-catalog.ts`——复用同一次遍历和同一套 `@mode` 先例——对它编目的所有内容强制执行 JSDoc 完整性要求。`verify-cordis-catalog` 在 `doc-sync` 内运行,因此相关文档变更和 CI 会执行同一门禁,无需另行接线。 契约如下: @@ -22,20 +22,20 @@ AGENTS.md 中的规则(「每个导出都有解释语义的 JSDoc」)只能 - **遍历可检查的显式性**:门禁是纯 AST 遍历(不使用类型检查器),因此服务方法必须显式标注返回类型(推断的返回类型无法分类),接口参数必须是简单标识符(解构模式没有名称供 `@param` 匹配)。 - **违规聚合**为一条错误信息,列出所有违规项——修复时一次看到完整清单。此前快速失败的 `@mode` 检查也移入同一份聚合报告,消息文本不变。 -这些标签**仅用于强制检查**:`parseJsDoc` 现在在遇到第一个块标签时截止描述性文字(标准 JSDoc 语义,同时也防止多行标签描述泄漏到目录中充当正文),因此 `@param`/`@returns` 不会改变渲染出的目录。 +生成器保留同一源码注释的两种视图:`parseJsDoc` 在第一个块标签处结束条目正文,而 `ts cordis-catalog` 签名块包含原始 JSDoc,并完整保留 `@param`、`@returns` 和 `@mode`。因此,读者可以看到完整的源码契约,而块标签文本不会泄漏到周围正文中。 `packages/core/agent/tests/gen-cordis-catalog.spec.ts` 中的负路径测试对合成 fixture(测试前置数据)运行 `collectEvents`/`collectServices`,验证每条守卫都会触发且免检规则成立。撰写规则写在根 [AGENTS.md](../../../../AGENTS.md) 的约定条目中,与 `@mode` 规则并列。 ## 曾考虑的替代方案 - **ESLint 规则**:无法看到该范围的机器定义(哪些 `interface Events` 成员、哪些 `ctx.<key>` 类构成 Cordis 对外服务接口);目录生成器在每次运行时恰好计算这层映射,因此门禁放在那里。 -- **将标签渲染到目录中**:曾考虑将服务部分重构为逐方法条目,但有意推迟:方法文档的消费场景是源码 JSDoc 加 IDE 悬停,目录保持索引定位。 +- **将每个方法展开为单独的正文小节**:否决。目录保留一个服务章节和一个签名块,以维持可扫读性;附着于每个声明的 JSDoc 则在原处保留完整的方法契约。 - **逃逸标签**:不设。该接口面小且经过策展(采纳时 12 个服务、57 个方法、27 个事件),要点在于检查不可豁免。 ## 后果 -- 新增事件或服务方法时,若参数或返回值未写文档则无法落地:生成器拒绝重新生成,`verify-cordis-catalog` 在 pre-push 和 CI 中失败。采纳时发现的约 139 处缺口在同一个变更中补齐,门禁以绿色状态落地。 +- 新事件或服务方法不能带着未记录的参数或结果落地:生成器会拒绝重新生成,`verify-cordis-catalog` 也会使 `doc-sync` 和 CI 失败。采纳时发现的约 139 处缺口已在同一变更中补齐,因此门禁以绿色状态落地。 - 服务接口必须显式标注返回类型并使用标识符参数。两项约束在采纳时均未构成限制(所有方法已有标注;不存在解构的 seam 参数);但二者现在是承重要求,违反时会被机械检测到。 - AGENTS.md 中通用的 JSDoc 规则(「一行能说清就用一行」)在此接口上获得了更严格的特例:仅当方法无参数且返回 void 时,一行摘要才足够。 - 为 `next` 或 `this` 写 `@param` 合法但不检查——这是有意的不对称:门禁强制载荷契约,拒绝要求样板代码。 -- 渲染出的目录不受这些标签影响(正文在第一个块标签处截止)。如果后续需要方法级渲染,那是一个独立的目录设计决策,而非本门禁的缺口。 +- 每个生成的事件或方法片段都带有其原始 JSDoc,而正文摘要不含标签。因此,源码编辑会同时刷新可读索引和签名旁展示的确切契约。 diff --git a/.agents/notes/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml b/.agents/notes/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml index 15039922c5..529c94c930 100644 --- a/.agents/notes/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-04-doc-tiers-and-budgets.i18n.yaml @@ -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 -2026-07-04-doc-tiers-and-budgets.md: ddbce540c68b9b35bb7e6a48b8db8abbc3a7a398 -2026-07-04-doc-tiers-and-budgets.zh.md: d3f08d337af34b5def41792232330180123dd585 +2026-07-04-doc-tiers-and-budgets.md: 9993eda6b0c7f1f8e5908dbd85fcfb4e5c6b3d1d +2026-07-04-doc-tiers-and-budgets.zh.md: d708919217a086928951c4acfed57985194301c4 diff --git a/.agents/notes/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md b/.agents/notes/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md index d3f08d337a..d708919217 100644 --- a/.agents/notes/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md +++ b/.agents/notes/implemented/process/2026-07-04-doc-tiers-and-budgets.zh.md @@ -1,4 +1,4 @@ -# RFC: 文档分层、预算与上限门禁 +# Agent Note: 文档分层、预算与上限门禁 Status: implemented @@ -6,14 +6,14 @@ Status: implemented ## 问题 -尽管已有写作指导,常设文档仍然积累了重复的规则、重述的事故、重复的包(package)映射和陈旧的 RFC 摘要。仅靠评审无法阻止这种膨胀,因此仓库需要在文档分类体系之外增加一道机械化的预算约束。 +尽管已有写作指导,常设文档仍不断累积重复规则、反复讲述的事件、重复的包映射,以及陈旧的 Agent Note(agent 决策记录)摘要。仅靠评审无法阻止这种增长,因此仓库需要在文档分类之外再配一套机械预算。 ## 决策 -- **分层分类体系,每条事实只有一个归属地。** [docs/AGENTS.md](../../../AGENTS.md) 是文档标准:它为每个 Markdown 层级指定唯一职责(常设指令、系统地图、类型目录、决策记录、事故叙事、实操手册、逐包契约、生成目录、工作流),禁止在归属层级之外重述事实(应以链接代替),并附带一份在撰写或评审任何文档时使用的冗余检查清单。 -- **窄范围、硬约束的预算门禁。** [scripts/verify-doc-budgets.ts](../../../../scripts/verify-doc-budgets.ts) 加入 `doc-sync`(文档同步门禁):[scripts/doc-budgets.manifest.json](../../../../scripts/doc-budgets.manifest.json) 中列出的每篇文档都必须低于其字数上限(`wc -w` 语义,整个文件),且受预算约束的文件如果缺失也会导致门禁失败,防止重命名后预算被静默遗留。范围刻意限定为容易膨胀的常设文档:根目录和子树的 `AGENTS.md`、`architecture.md`、`packages/README.md`,以及它们将内容分流到的常设策略文档(`docs/testing.md`、`docs/defensive-patterns.md`)。参考文档、RFC 和 package README 不设预算:当每一行都是事实时,长度是合理的,由评审加冗余检查清单来管控。 +- **每项事实只归属一处的层级分类。**[docs/AGENTS.md](../../../../docs/AGENTS.md) 是文档标准:它为每种 Markdown 层级分配单一职责(常设指令、系统图、类型目录、决策记录、事件故事、操作指南、各包契约、生成式目录、工作流),禁止在事实归属层级之外重复陈述(应改为链接),并包含编写或评审任何文档时使用的赘余检查清单。 +- **范围窄且严格的预算门禁。**[scripts/verify-doc-budgets.ts](../../../../scripts/verify-doc-budgets.ts) 接入 `doc-sync`:[scripts/doc-budgets.manifest.json](../../../../scripts/doc-budgets.manifest.json) 列出的每份文档都必须低于其字数上限(采用 `wc -w` 语义,统计整个文件);预算内文件缺失也会使门禁失败,使重命名无法悄然遗落其预算。范围刻意只涵盖容易膨胀的常设文档——根目录和子树中的 `AGENTS.md` 文件、`architecture.md`、`packages/README.md`,以及它们将内容移入的常设策略文档(`docs/testing.md`、`docs/defensive-patterns.md`)。参考文档、Agent Note 和包 README 不设预算:只要每一行都是事实,长度在这些位置就是合理的;评审和赘余检查清单负责约束它们。 - **上限是只进不退的执行红线。** 上限设定为文档当前字数的至少 105%(留出工作余量,使日常措辞调整能通过,而真正的膨胀仍会触发门禁),并随着文档被精简到目标预算而同步下调、保持该余量(根 `AGENTS.md` ≤ 1,500 词;`architecture.md` ≤ 1,800;子树 `AGENTS.md` ≤ 600;`packages/README.md` ≤ 600)。推进机制与[翻译配对的 `required` 清单](2026-07-02-bilingual-docs-and-pairing-gate.md)相同。门禁变红时,修复方式是按分类体系迁移或压缩内容;只有在 PR(Pull Request)描述中给出明确理由时才允许提高上限,manifest(元数据清单)的 diff 本身即为可评审的动作。 -- **轻量工作流 skill(技能),契约在文档中。** [.agents/skills/dsh-doc-standards](../../../../.agents/skills/dsh-doc-standards/SKILL.md) 承载放置/审计/红灯修复工作流,并将文档标准作为真源,与 [dsh-translate-docs](../../../../.agents/skills/dsh-translate-docs/SKILL.md) 对 i18n 契约的分工方式一致。 +- **精简的工作流 skill(技能),契约归文档。**[.agents/skills/dsh-doc-standards](../../../skills/dsh-doc-standards/SKILL.md) 承载放置/审计/红灯门禁工作流,并以文档标准为事实来源,与 [dsh-translate-docs](../../../skills/dsh-translate-docs/SKILL.md) 和 i18n 契约之间的分工相同。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml b/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml index 7aba38dbc9..7582c5e480 100644 --- a/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.i18n.yaml @@ -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 -2026-07-04-persistence-log-catalog.md: d92666fc8bafcf42542940fe399d9a3ece20c173 -2026-07-04-persistence-log-catalog.zh.md: a3524b251522050567be240f28944872e725a24e +2026-07-04-persistence-log-catalog.md: 1529f41b485c1bc8ca029c0a9264574fa7a886a0 +2026-07-04-persistence-log-catalog.zh.md: 24ac6caf8331c579828e707e289f28827caa072f diff --git a/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.zh.md b/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.zh.md index a3524b2515..24ac6caf83 100644 --- a/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.zh.md +++ b/.agents/notes/implemented/process/2026-07-04-persistence-log-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC: 生成式持久化日志事件目录 +# Agent Note: 生成式持久化日志事件目录 Status: implemented @@ -6,19 +6,19 @@ Status: implemented ## 问题 -`SessionEventMap` 是磁盘上的词汇,但其声明分散在拥有它的 session 包(package)与声明合并中。生成式持久化目录是所有事件与 payload 的唯一参考;手工维护的表格会漂移,已被移除。这些记录不是 Cordis 事件,观察者通过单一的 `session/event` 总线事件接收它们,因此 Cordis 目录无法覆盖。生成器发现所有声明,doc-sync(文档同步门禁)的新鲜度门禁拒绝遗漏或陈旧的输出。 +`SessionEventMap` 是磁盘格式的词汇,但其声明分散在所属 session 包和声明合并中。生成式持久化目录是所有事件、各自完整 payload 声明与源码 JSDoc,以及共享 `SessionEvent` 信封的唯一参考;手工维护的表格会发生漂移,因此被移除。这些记录不是 Cordis 事件——观察者通过唯一的 `session/event` 总线事件接收它们——所以 Cordis 目录无法覆盖。生成器会发现所有声明,文档同步新鲜度门禁会拒绝遗漏或陈旧输出。 ## 决策 从源码生成 `docs/persistence-catalog.md`,配合新鲜度门禁,作为第四个参考面:持久化会话日志可以包含的*记录*,与 Cordis 目录(接线)、核心数据结构(词汇)和工具目录(工具)互补。 -`gen-persistence-catalog.ts` 使用 TypeScript AST 扫描所有拥有方与声明合并的 `SessionEventMap`。它渲染源码 JSDoc、payload 类型、派生的 surface 徽章、参考链接与源码位置。doc-sync 新鲜度检查会拒绝任何词汇变更后未重新生成目录的情况。 +`gen-persistence-catalog.ts` 使用 TypeScript AST 扫描每个所属及声明合并的 `SessionEventMap`。它从前置 JSDoc 开始渲染每个成员,直至完整的 payload 类型,保留嵌套属性注释且只移除其容器缩进;同时粘贴构成持久化信封的所属 `SessionEventType`、`SurfaceEventType`、`SurfaceOp` 和 `SessionEvent` 声明。派生的 surface 徽章、参考链接和源码位置仍位于声明块之外。文档同步新鲜度检查会拒绝目录尚未重新生成的词汇或信封变更。 具体选择: -- **JSDoc 完整性,强制执行。** 每个成员必须带有描述性文字——JSDoc 即为目录条目,与 Cordis 目录对总线事件施加的强制机制相同。成员上的 `@mode` 标签是硬错误:dispatch mode 属于 Cordis 总线事件,日志事件没有 mode,该标签会被误读为「此事件以模式 X 在总线上触发」。违规项聚合为一条错误,列出所有违规者。 +- **强制保证 JSDoc 完整性。** 每个成员和渲染出的信封类型都必须带有描述正文,完整的源码 JSDoc 会在目录中保持附着于其声明。`@mode` 标签是硬错误:分派模式属于 Cordis 总线事件,持久化记录没有这种模式。所有违规会汇总为一条错误,列出每个违规项。 - **surface 徽章由派生得出,而非手工列举。** `SurfaceEventType`(产生 LLM(大语言模型)消息且可能携带 `surfaceOp` 的子集)从拥有方包中的 union 声明解析;如果 union 成员命名了一个未声明的事件,则为硬错误(否则陈旧的 union 成员会静默地不标注任何内容)。其余一律渲染为 **log-only**。 -- **专用围栏。** payload 块使用 ` ```ts persistence-catalog ` 信息字符串,`doc-typecheck` 识别并跳过它,不计入 opt-out 比例——与 `ts cordis-catalog` 的处理方式相同(裸 payload 片段无法独立编译)。 +- **专用围栏。** 声明块使用 ` ```ts persistence-catalog ` 信息字符串,`doc-typecheck` 会识别并跳过这些块,将其排除在退出检查比例之外——处理方式与 `ts cordis-catalog` 相同(这些声明引用所属模块中的类型,无法独立编译)。 - **仓库范围。** 目录枚举本仓库中的包,与兄弟文档的 packages-only 范围一致;下游插件可以合并更多事件类型,它们在设计上不在目录范围内。遍历过程用硬错误保护自身假设:拥有方的顶层 `interface SessionEventMap` 必须是 `@deepseek-ai/dsh-session` 中唯一的导出声明(无关的、局部的或同名重复的接口不能被当作磁盘词汇编入目录);任何声明不得携带 `extends`(继承的键会加入 `keyof SessionEventMap` 却没有对应的目录行);每个成员必须是带有显式 payload 类型的属性签名(方法形式的成员会加入 `keyof` 却在静默遍历中被漏过);跨声明的重复成员也会失败。 本方案取代了手工副本:session.md 的 `hook/*` 表格、精简版 README 的事件表格、hook-protocol README 的 payload 条目列表,以及 session README 的名称列表现在链接到目录,而不再重述 payload(周围的语义说明文字保留原位)。hook-protocol 合并成员上的两个误加的 `@mode emit` 标签已被移除——新门禁将它们作为类别错误拒绝。 @@ -30,7 +30,7 @@ Status: implemented ## 后果 -- 目录不会漂移:词汇变更若未反映在已提交的文件中,`verify-persistence-catalog` 会在 pre-push 钩子和 CI 中失败;新合并的事件若缺少 JSDoc,生成器直接报错——插件不再能添加未文档化的磁盘记录类型。 -- 事件描述有唯一归属地,即声明处的 JSDoc;JSDoc 写得单薄,目录条目就单薄,这迫使作者在源头做好文档。 +- 目录不会发生漂移:提交文件未反映的词汇或信封变化会使 `doc-sync` 和 CI 中的 `verify-persistence-catalog` 失败,而没有 JSDoc 的新增合并事件会直接使生成器失败——插件不能再添加未记录的磁盘记录类型。 +- 事件正文只有一个归属,即声明处的 JSDoc;目录会保留该 JSDoc 和所有嵌套字段注释,不会将其扁平化或复述。 - `SurfaceEventType` union 现在对文档具有结构性承载作用:重命名事件而不更新 union(或反过来)会导致生成器失败,而不仅仅是编译器失败。 - 徽章派生假设 union 始终是一组封闭的字符串字面量且只有一个拥有方;如果重构偏离了这一形状,必须在同一个变更中更新生成器。 diff --git a/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.i18n.yaml b/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.i18n.yaml index 188ebf1019..ddd9099b22 100644 --- a/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.i18n.yaml @@ -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 -2026-07-05-uniform-rfc-format.md: 9688ad6566e88372508bbfd8d032ab6d02568716 -2026-07-05-uniform-rfc-format.zh.md: eab2505e64b813f698b4356bc52a796cbd66b948 +2026-07-05-uniform-agent-note-format.md: 06082251c1b96c90ed470d84224662e00e29791b +2026-07-05-uniform-agent-note-format.zh.md: 61ade75f179d64fa73390dc85bcd47c30deb112a diff --git a/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.md b/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.md index 1a6aa40477..06082251c1 100644 --- a/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.md +++ b/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-07-05-uniform-agent-note-format.zh.md) + ## Problem Agent Note paths encoded lifecycle and class, but file contents still mixed headings, status formats, ADR and proposal templates, and proposal-era sections in implemented records. Authors copied whichever neighbor they found, and lifecycle moves could skip the required rewrite because no gate enforced an in-file contract. diff --git a/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.zh.md b/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.zh.md index eab2505e64..61ade75f17 100644 --- a/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.zh.md +++ b/.agents/notes/implemented/process/2026-07-05-uniform-agent-note-format.zh.md @@ -1,30 +1,30 @@ -# RFC: RFC 的统一受门禁约束的文件内格式 +# Agent Note: Agent Note 的统一受门禁约束的文件内格式 Status: implemented -[English](2026-07-05-uniform-rfc-format.md) | 中文 +[English](2026-07-05-uniform-agent-note-format.md) | 中文 ## 问题 -RFC 的路径已经编码了生命周期和分类,但文件内容仍然混杂着不同的标题风格、状态格式、ADR 与 proposal 模板,以及已实现记录中残留的 proposal 时期的章节。作者随手复制找到的任何邻近文件,生命周期迁移时可以跳过必要的改写,因为没有门禁强制执行文件内契约。 +Agent Note(agent 决策记录)的路径编码了生命周期和类别,但文件内容仍混杂着不同标题、状态格式、ADR 与提案模板,以及已实现记录中的提案阶段章节。作者会复制随手找到的相邻文件,而生命周期迁移可能跳过必要的改写,因为没有门禁强制执行文件内契约。 ## 决策 -[README.md § The file format](../../README.md#the-file-format) 即文件内契约:头部块(`# RFC: <title>` 加上无日期、与所在文件夹一致的 `Status:` 枚举,唯一的正文内容是 rejection reason);按生命周期区分的正文骨架(所有阶段都以 `Problem` 开头;`proposed/` 中为 `Proposal`/`Acceptance criteria`/`Risks`;`implemented/` 中为现在时态的 `Decision`/`Consequences` 且禁止 proposal 时期的标题;`rejected/` 中冻结 proposal 形态);必须包含 `Alternatives considered` 章节;以及规范的章节词汇表,其间的自定义技术章节保持自由形式。`pnpm run verify-rfc-format`([scripts/verify-rfc-format.ts](../../../../scripts/verify-rfc-format.ts))作为 `doc-sync`(文档同步门禁)的一环强制执行每条机械化条款,因此生命周期迁移时跳过改写现在会让 CI 失败,而不是依赖评审者的记忆。 +[README.md § 文件格式](../../README.md#the-file-format)是文件内契约——头部块(`# Agent Note: <title>`,加上无日期且与文件夹一致的 `Status:` 枚举,其中只有拒绝原因可作为额外内容)、各生命周期的正文骨架(所有文件均以 `Problem` 开篇;`proposed/` 使用 `Proposal`/`Acceptance criteria`/`Risks`;`implemented/` 使用现在时的 `Decision`/`Consequences`,并禁止提案阶段标题;`rejected/` 冻结提案形状)、强制的 `Alternatives considered` 章节,以及规范章节词汇;定制技术章节可在这些规范章节之间保持自由形式。`pnpm run verify-agent-note-format`([scripts/verify-agent-note-format.ts](../../../../scripts/verify-agent-note-format.ts))作为 `doc-sync` 的一部分强制执行每项机械规则,因此跳过改写的生命周期迁移现在会使 CI 失败,而不再依赖评审者记忆。 -整个语料库在定义格式的同一个变更中完成了规范化,这是预发布阶段的立场:没有过渡期,不容忍双格式并存。唯一的祖父条款针对内容而非格式:替代方案是记录下来的,不是凭空编造的;因此如果一篇格式定义前的 RFC 的替代方案无法从记录中重建,它会携带 `rfc-format: alternatives-not-recorded` 这条精确注释,门禁仅对日期早于本 RFC 的文件接受该注释。 +定义该格式的同一变更规范化了整个语料库——遵循预发布立场:不设过渡期,不容忍双格式。唯一受既有条款豁免的是内容,而非格式:替代方案只能记录、不能杜撰,因此若某份格式制定前的 Agent Note 无法从记录中还原替代方案,就会携带确切的 `agent-note-format: alternatives-not-recorded` 注释;门禁只对日期早于本文的文件接受该注释。 ## 曾考虑的替代方案 -- **完全刚性的模板**(每个生命周期一个固定章节序列,所有 RFC 重构以适配):否决。大型设计 RFC 包含八到十五个自定义技术章节(包拓扑、协议格式契约、schema),这些是承重内容而非漂移;刚性序列会立即强制破坏性改写,并永远带来与模板的对抗。 +- **完整的刚性模板**(每个生命周期使用固定章节顺序,重构每份 Agent Note 以适配):否决。大型设计 Agent Note 包含八到十五个定制技术章节(包拓扑、线协议、schema),它们是承载设计的内容,而非漂移;刚性顺序会迫使我们现在进行破坏性改写,并永远与模板较劲。 - **仅规范化头部**(H1 和 Status,正文不动):否决。债务标记指出的是*正文*的体裁分裂,让 `Context`/`Decision` 与 `Problem`/`Proposal` 无限期并存什么也解决不了。 -- **不设 Status 行**(文件夹本身就是状态;格式定义前最新的三篇 RFC(以及其中一篇的中文对侧文件)省略了该行):否决,保留自描述文件。省略 Status 行的动机是防止漂移,而将该行与文件夹做门禁校验即可消除漂移风险。 +- **不设 Status 行**(文件夹已经表示状态;格式制定前最新的三份 Agent Note 及其中一份的中文对应文件省略了该行):否决,保留文件的自描述性。通过门禁校验该行与文件夹一致,消除了原本促使我们删除它的漂移风险。 - **带日期的 Status**(`Status: implemented (accepted YYYY-MM-DD)`):否决。接受日期属于叙述性历史,写作规则将其排除在文档之外;文件名承载首次提出日期,git 承载其余信息;门禁能检查日期格式,但永远无法检查其真实性。 -- **裸 `# <title>` H1**:否决。`RFC: ` 前缀是语料库中的多数形式,且在文件脱离目录树被阅读时能自描述体裁;索引生成器会剥离前缀,因此索引行无论哪种写法都一样。 -- **`## What we give up` 作为 implemented 的结尾章节**(README 自身对 RFC 记录内容的措辞):否决。它只命名了代价,而诚实的后果章节同样记录这笔权衡换来了什么。 +- **裸 `# <title>` H1**:否决。文件脱离目录树单独阅读时,`Agent Note: ` 前缀能自描述其体裁,而格式门禁可防止它漂移。 +- **以 `## What we give up` 作为已实现记录的结尾**(README 对 Agent Note 所记录内容的原有表述):否决。它只点出成本,而诚实的后果章节也会记录取舍换来了什么。 - **只有约定没有门禁**(写下契约,靠评审强制执行):否决。slop checklist 已经通过约定禁止在 `implemented/` 中使用 spec 语气,而十九个文件展示了仅靠约定在此处能达到什么效果。 -- **独立的 `FORMAT.md` 契约文件**:最初的落地位置;在生成索引迁出到 [INDEX.md](../../INDEX.md) 之后折入 README.md:表格移走后 README 重新有了空间,一个前门同时承载布局、分类和格式,优于将契约拆分到两个文件。 +- **独立的 `FORMAT.md` 契约文件**:否决。由一个入口同时承载布局、分类和格式,比维护两个契约文件更易发现和维护。 ## 后果 -每篇 RFC 现在需要略多一些结构,而必须包含 `Alternatives considered` 章节是刻意的摩擦:一个没有记录被否决方案的决策,会招致 RFC 本来就是为了防止的重新争论。格式定义前的 RFC 如果替代方案无法重建,则永久携带祖父条款注释,这是记录上的诚实缺口,而非编造的理由。`doc-sync` 增加一道门禁,将 RFC 在生命周期文件夹之间迁移现在是迁移时的实际工作(即迁移本就欠下的正文改写),而非无人追踪的延后清理。三十九个债务标记已全部消除,由它们等待的模板所解决。 +现在每份 Agent Note 都需要稍多一些结构,而强制的 `Alternatives considered` 章节是有意设置的阻力:记录决策却不记录它胜过什么,会招致 Agent Note 本应防止的重新争论。无法还原替代方案的格式制定前 Agent Note 会永久保留既有条款注释——这是记录中诚实的缺口,而不是杜撰的理由。`doc-sync` 增加一道门禁;在生命周期文件夹之间移动 Agent Note 时,现在必须当场完成真正的工作(迁移本就应包含的正文改写),而不是推迟为无人跟踪的清理任务。三十九个债务标记已经消失,由它们一直等待的模板解决。 diff --git a/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml b/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml index ed24da934e..966ac24d13 100644 --- a/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.i18n.yaml @@ -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 -2026-07-06-export-surface-jsdoc-gate.md: c2543fe50320da70c9d75bb4a16df3b110b50c47 -2026-07-06-export-surface-jsdoc-gate.zh.md: 98cb057cc1a661d2f51b8215609fc280d549c103 +2026-07-06-export-surface-jsdoc-gate.md: 93d8a41fc2ffb235de5c56ffeb5569bc95249392 +2026-07-06-export-surface-jsdoc-gate.zh.md: 64b4bcc620046f2c94a2ce3fbeb67e59ada888d4 diff --git a/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md b/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md index 98cb057cc1..64b4bcc620 100644 --- a/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md +++ b/.agents/notes/implemented/process/2026-07-06-export-surface-jsdoc-gate.zh.md @@ -1,4 +1,4 @@ -# RFC: 导出表面 JSDoc 门禁 +# Agent Note: 导出表面 JSDoc 门禁 Status: implemented @@ -28,7 +28,7 @@ Status: implemented - **插件协议槽位。** 顶层的 `name`/`inject`/`reusable`/`Config` 常量和 `apply` 入口,以及插件类上的同名静态成员,属于框架协议:其形状由 Cordis 固定,模块文档注释加 `interface Config` 承载插件的真实语义。 - **构造函数**,与 Cordis 门禁一致:插件类由框架构造,类文档承载全部说明。 -`collectExportJsdocViolations()` 返回违规列表(CLI 在非空时以 1 退出),因此 `packages/core/agent/tests/verify-export-jsdoc.spec.ts` 中的负路径测试直接断言发现项,通过 fixture(测试前置数据)包驱动每一种拒绝和每一种豁免。 +`collectExportJsdocViolations()` 返回违规列表(CLI(命令行界面)在非空时以 1 退出),因此 `packages/core/agent/tests/verify-export-jsdoc.spec.ts` 中的负路径测试直接断言发现项,通过 fixture(测试前置数据)包驱动每一种拒绝和每一种豁免。 ## 曾考虑的替代方案 @@ -38,7 +38,7 @@ Status: implemented ## 后果 -- 新增导出不能在无文档的情况下合入:`verify-export-jsdoc` 使 `doc-sync` 失败,而 pre-push 和 CI 已运行该门禁。采纳时发现的 203 处缺口在同一个变更中补齐,门禁以绿色状态落地。 +- 新导出不能在缺少文档的情况下落地:`verify-export-jsdoc` 会使 `doc-sync` 和 CI 失败。采纳时发现的 203 处缺口已在同一变更中补齐,因此门禁以绿色状态落地。 - 导出函数必须标注返回类型(采纳时已全面满足,现在成为门禁依赖),并在 `@param` 需要命名参数时使用标识符参数。 - seam 文档是权威的:实现从其继承链继承文档,值得保留在实现上的行为说明是补充,而非必需。 - 门禁构建一个 `ts.Program`(约 6 秒)——唯一需要类型解析的文档门禁;在已编译文档片段的 `doc-sync` 内可以接受。 diff --git a/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml b/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml index 18aecd24ad..728dd62166 100644 --- a/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.i18n.yaml @@ -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 -2026-07-06-generated-config-catalog.md: 77c2007d4b5cd28efcfe391c2de712db3b5c107e -2026-07-06-generated-config-catalog.zh.md: 4d9b190b770432111287cedee5992d5822197feb +2026-07-06-generated-config-catalog.md: f39f5138526d3278e839ee0053d5051bb8bc1c36 +2026-07-06-generated-config-catalog.zh.md: 8f08a7791916351df508c89f0c783dee2db17bae diff --git a/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.zh.md b/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.zh.md index 4d9b190b77..8f08a77919 100644 --- a/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.zh.md +++ b/.agents/notes/implemented/process/2026-07-06-generated-config-catalog.zh.md @@ -1,4 +1,4 @@ -# RFC: 生成式插件配置目录 +# Agent Note: 生成式插件配置目录 Status: implemented @@ -10,7 +10,7 @@ Status: implemented ## 决策 -`scripts/gen-config-catalog.ts` 从每个插件声明的配置类型与 JSDoc 生成 [docs/config-catalog.md](../../../config-catalog.md),包含注入要求、引用类型链接和源码指针。包内局部类型被传递性地包含;workspace 和外部类型以链接或名称形式引用。确定性的 `--write` 和 `--check` 模式使提交到仓库的页面成为一个生成产物。 +`scripts/gen-config-catalog.ts` 根据各插件声明的 config 类型和 JSDoc 生成 [docs/config-catalog.md](../../../../docs/config-catalog.md),并包含注入要求、被引用类型的链接和源码位置。包内类型会以传递方式纳入;workspace 类型和外部类型则会链接或点名。确定性的 `--write` 和 `--check` 模式使提交页面成为生成产物。 此处采用纯 AST 生成是正确的,原因与 events/services catalog 相同,而与 tool catalog 不同:配置类型是静态声明,仓库中每个 schemastery schema 都是静态的 `z.object`/`z.intersect` 字面量,因此源码即全部真相——配置表面没有任何部分是运行时组合的。 @@ -34,7 +34,7 @@ Status: implemented ## 后果 -- catalog 不会漂移:源码变更而提交的文件未反映时,`verify-config-catalog` 在 pre-push 和 CI 中报错。未文档化的配置字段、无法解析的引用类型名、或 schema 键在配置类型中缺失,都会直接导致生成器报错。 +- 目录不会发生漂移:提交文件未反映的源码变化会使 `doc-sync` 和 CI 中的 `verify-config-catalog` 失败。config 字段未记录、被引用类型名无法解析,或 schema 键未出现在 config 类型中,都会直接使生成器失败。 - 配置行文现在有了声明处的强制函数:编写新配置字段意味着编写其 JSDoc,而该 JSDoc 将逐字成为 catalog 条目。 - 生成器对无法静态遍历的形状直接报错——别名化的包内配置导入、非 `object`/`intersect` 组合构建的 schema、未列入的全局类型名。引入此类形状时必须同时教会生成器(否则该形状不能进入仓库),这正是设计意图:catalog 始终是全部真相。 - `gen-cordis-catalog.ts` 导出其 JSDoc/指针辅助函数与 `LINK_MAP` 供复用,因此两个 catalog 以相同方式交叉链接类型,新增一条 link-map 条目同时服务于两者。 diff --git a/.agents/notes/implemented/process/2026-07-06-node-engine-floor.i18n.yaml b/.agents/notes/implemented/process/2026-07-06-node-engine-floor.i18n.yaml index e324b52b3f..bb788d803d 100644 --- a/.agents/notes/implemented/process/2026-07-06-node-engine-floor.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-06-node-engine-floor.i18n.yaml @@ -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 -2026-07-06-node-engine-floor.md: f7764c408374a329c9390635e1b92ae9a4fd9dee -2026-07-06-node-engine-floor.zh.md: c46bf5168007b97878319e5f333b5bb1ab1d8f2a +2026-07-06-node-engine-floor.md: f1754ea7ca32452a04c6cd8a0599568f602e47dd +2026-07-06-node-engine-floor.zh.md: 18e878bdfcc32938125ee46e742a42499e0b58ab diff --git a/.agents/notes/implemented/process/2026-07-06-node-engine-floor.zh.md b/.agents/notes/implemented/process/2026-07-06-node-engine-floor.zh.md index c46bf51680..18e878bdfc 100644 --- a/.agents/notes/implemented/process/2026-07-06-node-engine-floor.zh.md +++ b/.agents/notes/implemented/process/2026-07-06-node-engine-floor.zh.md @@ -1,4 +1,4 @@ -# RFC: 将 Node LTS 引擎下限提升至 22.19 +# Agent Note: 将 Node LTS 引擎下限提升至 22.19 Status: implemented @@ -15,7 +15,7 @@ Status: implemented 两个 Node 特性决定了源码运行时的门槛: - **`node:sqlite`**:`packages/session-persistence/session-persistence-sqlite` 在顶层执行 `import { DatabaseSync } from 'node:sqlite'`。该模块在 **22.13**(LTS)和 **23.4**(Current)取消了 `--experimental-sqlite` 标志要求;在此之前,导入它会在加载时抛出异常。 -- **原生 TypeScript 类型剥离**:`packages/examples/stdio-demo/tests/built-bin.e2e.ts` 冒烟测试在纯 `node`(不用 tsx)下启动已发布的 `lib/bin.js`,并加载示例的 `.ts` 插件(`mock-llm.ts`、`echo-tool.ts`)。类型剥离从 **22.18**(LTS)和 **23.6**(Current)起成为默认行为;在此之前需要 `--experimental-strip-types`。 +- **原生 TypeScript 类型剥离**——构建模式的 `examples/headless-agent/tests/keyless-smoke.e2e.ts` 冒烟测试使用纯 `node`(无 tsx)启动 `dsh-cli-demo` 已发布的 `lib/bin.js`,并加载示例的 `.ts` 测试适配器(`cli-mock-llm.ts`)。类型剥离从 **22.18**(LTS)和 **23.6**(Current)起成为默认行为;更早版本需要 `--experimental-strip-types`。 这些源码特性在 22.x 线上于 **22.18** 全部就绪,但已安装的 Pi 适配器依赖将宣传的 LTS 下限进一步提高。`@deepseek-ai/dsh-llm-pi-ai` 依赖 `@earendil-works/pi-ai@0.79.3`,后者的 package 声明 `engines.node >=22.19.0`,因此 LTS 下限为 **22.19**。24.x 分支保持 `>=24.0.0`。该不相交范围完全排除了 Node 23:Node 23.0–23.5 至少还有一个源码特性需要标志,而 23 线是非 LTS/已 EOL 的,宣传 `>=23.6` 会增加一条已终止的发布线和一条 CI 分支,而没有任何部署应当使用它。 @@ -26,7 +26,7 @@ Status: implemented - 宣传的 LTS 分支不再低于 Pi 适配器依赖的下限。 - CI 通过 Node 22.19 直接验证 Node 22 LTS 下限,Node 24 分支保持 `node: 24`,Node 26 用于下一个偶数线;每条分支都对源码图执行类型检查,并实际启动未构建的工作流 worker。 - built-bin 冒烟测试无需版本条件标志:在 22.19 上类型剥离已是默认行为,因此测试保持其文档所述的纯 `node lib/bin.js` 路径。 -- 未来如果有依赖或源码 API 提高运行时下限,必须在同一个变更中同步修改 `engines.node`、兼容性矩阵和本 RFC。 +- 未来若依赖或源码 API 提高运行时下限,必须在同一变更中同步调整 `engines.node`、兼容性矩阵和本 Agent Note(agent 决策记录)。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml b/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml index 40132b2b97..d8ebe51c67 100644 --- a/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.i18n.yaml @@ -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 -2026-07-06-parallel-github-ci-gates.md: 6a9bd339304c8efac7a29bdbe745270ab9661396 -2026-07-06-parallel-github-ci-gates.zh.md: 24fdf27822aac7640fbeaf602fa8dd84277083fa +2026-07-06-parallel-github-ci-gates.md: 5c276f6a75936021369bc5ad9494c9aa6e4e3fc3 +2026-07-06-parallel-github-ci-gates.zh.md: f96606ba2b58b856b3833e758853e9fa3a62bff3 diff --git a/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.md b/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.md index fef5852153..5c276f6a75 100644 --- a/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.md +++ b/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-07-06-parallel-github-ci-gates.zh.md) + ## Problem The keyless GitHub CI gates are mostly orthogonal: typecheck, lint, documentation freshness, coverage, snapshot replay, build, package-publication hygiene, demo smoke, and built-bin smoke fail for different reasons and do not need each other's runtime state. Running them as one ordered command chain makes the workflow wall clock equal the sum of those gates, while splitting every short leaf into its own GitHub job repeats checkout, Node setup, pnpm restore, and install work until orchestration overhead becomes the bottleneck. diff --git a/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md b/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md index 24fdf27822..f96606ba2b 100644 --- a/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md +++ b/.agents/notes/implemented/process/2026-07-06-parallel-github-ci-gates.zh.md @@ -1,4 +1,4 @@ -# RFC: 并行 GitHub CI 门禁 +# Agent Note: 并行 GitHub CI 门禁 Status: implemented @@ -6,36 +6,45 @@ Status: implemented ## 问题 -keyless GitHub CI 门禁大多相互正交:类型检查、lint、文档新鲜度、覆盖率、快照回放、构建、包发布卫生检查、demo 冒烟测试与 built-bin 冒烟测试各自因不同原因失败,彼此不需要对方的运行时状态。将它们串成一条有序命令链,工作流的挂钟时间等于所有门禁之和;而把每个叶子门禁拆成独立的 GitHub job,则会重复 checkout、Node 设置、pnpm restore 和 install 工作,直到编排开销本身成为瓶颈。 +无密钥 GitHub CI 门禁大多相互正交:类型检查、lint、文档新鲜度、覆盖率、快照重放、构建、包发布卫生、demo 冒烟和已构建二进制冒烟会因不同原因失败,也不需要彼此的运行时状态。将它们作为一条有序命令链运行,会使工作流墙钟时间等于所有门禁耗时之和;而把每个短小叶子拆成独立 GitHub job,又会反复执行 checkout、Node 设置、pnpm 恢复和安装,直到编排开销成为瓶颈。 -难点在于产物边界。`publint`、`verify-node-next-types` 和 built-bin 冒烟测试需要构建出的 `lib/` 输出,而大多数门禁只需要源码和依赖。盲目扇出要么让这些产物消费方在 `pnpm run build` 输出声明文件和 bundle 之前就开始竞跑,要么在每个依赖产物的 job 中重复构建。 +随着 workspace 增长,原有的宽车道拆分不再满足这一平衡。PR(Pull Request)#404 合并时,Linux 的静态、覆盖率、快照和产物 job 分别耗时 148、195、94 和 230 秒;Windows 的静态和产物 job 分别耗时 251 和 482 秒。每个包都调用一次包管理器打包,主导了两个产物验证器的耗时;覆盖率在仅运行源码的套件前无谓地重建输出;CPU 密集型门禁则在静态与覆盖率车道内争用资源。 + +产物边界仍然承载关键约束。`publint`、`verify-node-next-types`、已编译不变量加载和已构建二进制冒烟测试都需要生成的 `lib/` 输出。分片不能让这些消费者抢在构建前运行,也不能用源码执行取代它们对已发布产物的信号。 ## 决策 -[CI](../../../../.github/workflows/ci.yml) 将 keyless 检查分组为若干宽粒度的主运行时 lane,外加一个兼容性矩阵。工作流文件拥有当前 lane 和运行时清单的定义权。 +下述生产拓扑已经成为历史,并由[基于证据采用更大的托管 runner](2026-07-22-evidence-based-larger-hosted-runners.md) 取代。更大 runner 的决策移除了其分片选择器和工作流 job;本文保留早期拓扑为何被实现的记录。 -每个 lane 委托给 [scripts/run-gates.ts](../../../../scripts/run-gates.ts),该脚本以有界并发调度独立门禁,并为每个门禁打印一个可归因的结果块。产物消费方依赖其所在 lane 内的一次 build,而兼容性 job 将类型检查与一次真实的未构建 worker 启动结合,以覆盖运行时特定的 loader 行为。 +[CI](../../../../.github/workflows/ci.yml) 将非 Windows job 的一分钟和 Windows job 的三分钟视为观测所得的性能目标,而非取消截止时间。托管 runner 的波动应留下完整计时证据和有用的失败日志,而不是取消本来正确的门禁。[串行跨平台 CI 参考](2026-07-21-serial-cross-platform-ci-reference.md)会在 Linux、macOS 和 Windows 上独立运行完整、未分片的主 Node 聚合,使优化后的车道清单不会成为自身完整性的唯一判据。 -生成的 `.sessions/` 日志和 `.doc-typecheck-*` 临时目录被 lint 忽略。聚合的本地 CI 模式仍在 lint 之后运行 demo 冒烟测试,而拆分后的 GitHub static lane 可以直接运行 demo 冒烟测试,因为 lint 已隔离在自己的 lane 中。 +在该拓扑中,[scripts/run-gates.ts](../../../../scripts/run-gates.ts) 是通用的有界调度器,GitHub 则为昂贵的门禁族提供显式分片名称。`scripts/static-shards.ts` 将静态门禁划分为基础、文档类型、API 契约、目录、正文、文档投影和文档构建等归属,并拒绝缺失或重复的门禁分配。Linux lint 使用互不重叠的 A-C、D-M、N-S、T-Z 包源码和包测试车道,Windows 则使用完整的包源码与包测试车道;两者都包含从 `.` 开始的仓库补集,使新增顶层目标无法消失在分片之间,并负责唯一一次跨文件重复检查。`scripts/coverage-shards.ts` 把每个 workspace 包恰好分配给一个源码覆盖率车道。目录过滤器保留尾部分隔符,因为 Vitest 位置过滤器按子字符串匹配,否则会纳入具有同名前缀的相邻项。每个覆盖率车道只包含其拥有的源码文件,重复运行穷尽式伴随拓扑测试,并且不先执行构建,因为从删除了所有生成式 `lib/` 的树开始,完整覆盖率套件仍可通过。 -构建输出在 Node 24 的产物 lane 中只生成一次。产物消费方(`publint`、`verify-node-next-types` 和 built-bin 冒烟测试)声明对 `build` 的依赖,因此没有 upload/download 交接,消费方也不可能在声明文件或 bundle 就绪之前抢跑。CI 覆盖率报告仅输出文本,本地覆盖率则保留 HTML 报告。 +快照重放使用两个显式多文件车道,以及大型 ACP(Agent Client Protocol)文件的八个场景分区。`scripts/snapshot-shards.ts` 拥有该清单,其测试会发现快照配置允许的每个文件。每个快照 job 在其 Linux runner 准备 Bubblewrap 的同时安装依赖,随后构建已发布运行时,并且只运行分配给它的重放表面。该套件保留五个子进程的有界并发,因为重放的大部分时间都在等待子进程协议 I/O。fixture(测试前置数据)守卫仍会在每个分区中检查完整 ACP 场景表。 -两个工作流都缓存 pnpm store。真实 API 工作流使用共享的有界 Vitest 文件池,而非为每组测试单独开一个 job。 +冷启动的独立文档类型检查会重建完整的项目引用图,因此专用文档类型车道只构建一次,再用这些声明检查 Markdown 块。Linux 文档车道使用 VitePress 的 MPA 构建,在观测所得的非 Windows 目标内保留页面渲染与死链接验证;单独的阻塞式 Windows 构建和生产站点车道保留已生成包与已发布站点检查,同时避免把两条关键路径放进同一个 job。 + +产物使用两个车道:一个元数据车道负责 `publint`、NodeNext 声明和已编译不变量加载,另一个负责已构建二进制冒烟。每个车道都会在其消费者之前自行构建。重复短时构建会消耗 runner 分钟数,但避免了上传/下载依赖,并使每个 job 的关键路径保持有界。 + +[scripts/publint-all.ts](../../../../scripts/publint-all.ts) 在进程内针对内存发布视图调用 publint 支持的 API;该视图由每份清单声明的文件和 npm 强制元数据文件构成。这样无需生成 103 次包管理器打包命令,也能保留 workspace 文件与已发布文件之间的区别。[scripts/verify-built-package-invariants.mjs](../../../../scripts/verify-built-package-invariants.mjs) 在真实包下暂存这些经过结构验证、由清单声明的 `lib/` 文件,再通过纯 Node 和 Cordis Loader 规范化导入已编译的自引用。若伴随项触及未声明的运行时 chunk,仍会失败。 + +兼容性车道会在每条声明支持的 Node 版本线上运行源码 worker 和 Zstandard 运行时冒烟。TypeScript 在专用的主 Node 24 车道中只检查一次源码图;在运行时兼容性 job 中重复同一编译器分析只会增加耗时,不会提供运行时特有信号。 + +工作流缓存 pnpm store,将每个不可变 ESLint 缓存的键绑定到其所属 lint 分片,为 Windows 测量保留原生 PowerShell,并保留一个聚合的 `all checks passed` 状态用于分支保护。Windows 复用三个穷尽式 lint 分区,并在共享 runner 设置后组合基础/目录/正文门禁与文档类型/API 契约门禁;只有调度方式与 Linux 分区不同。Windows 构建和生产站点验证继续阻塞,而更广泛的 Windows 静态、lint 和产物矩阵仍为观察性检查。 ## 曾考虑的替代方案 -- **在 Node 矩阵中保留完整串行链**:最容易推理,但会重复执行不产生 Node 版本特定信号的仓库级门禁,且让每个 PR 等待所有门禁的总和。 -- **每个门禁作为独立 GitHub job 运行**:最大化 GitHub 可见的扇出,但产生过多 check,且对运行时间短于 runner 准备时间的门禁而言,重复的 setup/install 开销得不偿失。 -- **将构建产物上传给依赖产物的 job**:在多 job 间保持正确性,但增加了 artifact upload/download 时间,且当产物消费方可以在主 job 内通过本地依赖排序运行时,工作流仍然过宽。 -- **并发运行 `typecheck` 与 `build`**:向调度器暴露更多工作,但两个命令都调用 `tsc -b`;在它们之间共享增量构建状态是一场不必要的竞争,换来的挂钟收益很小。 -- **使用无界的真实 API e2e 并行度**:否决。该套件包含大量真实模型/工具场景;worker 池需要一个显式的 `DSH_E2E_MAX_WORKERS` 上限,使 CI 和本地运行都能扇出,同时不会把配额或资源问题隐藏在不稳定的限流失败背后。 +- **保留宽车道**:最大限度减少工作流 YAML,但会保留观测到的数分钟反馈周期。 +- **让每个叶子门禁分别成为 GitHub job**:最大化扇出,但短小的生成器和正文检查准备 runner 的时间会超过检查仓库的时间。 +- **向产物消费者上传一次构建**:避免重复编译,但上传/下载和依赖调度会延长墙钟时间;干净构建足够短,可以在有界车道内重复。 +- **在两个发布门禁中保留包管理器打包**:把清单选择委托给 pnpm,但会重复启动 200 多个包管理器进程。清单结构门禁加发布视图 fixture 使优化后的清单契约显式化,并会在存在磁盘上有但未发布的依赖时失败。 +- **在覆盖率前保留构建**:提供源码套件已不再消费的生成输出;干净树覆盖率证明表明这只是纯粹的延迟。 +- **在每个 Node 版本上执行类型检查**:重复编译器工作,而兼容性冒烟已经验证实际的 Node 特有加载与压缩行为。 ## 后果 -PR 反馈以少量 GitHub check 的形式呈现,每个宽粒度 job 内部包含结构化的逐门禁日志块。这将 runner 设置开销控制在有限范围内,并保持 Actions UI 紧凑,代价是失去了每个叶子门禁独立的状态标记。 +上述分片清单和矩阵 job 不属于当前仓库契约。取而代之的更大 runner 决策在单个进程中保留完整主清单,并以串行套件作为独立完整性判据。 -宽 lane 拆分比单一主 job 更频繁地重复 checkout、setup 和 install。这一设置开销是有意为之的:在 GitHub 托管 runner 上,将 lint、覆盖率和快照回放放在同一个进程池中运行会严重超额占用 CPU,以至于单 job 的关键路径比重复设置还要长。 +优化后的发布验证器依赖由 `verify-package-invariants` 强制执行的清单 `files` 契约。如果发布规则超出该契约,结构门禁和两个暂存视图必须一起变化。 -这种拆分引入了一项维护义务:当 `package.json` 新增或移除一个应纳入 CI 的门禁时,[scripts/run-gates.ts](../../../../scripts/run-gates.ts) 需要添加或删除对应的叶子。这一义务是有意为之的,因为该 runner 是同一套门禁词汇的并行执行计划,而非独立的质量策略。 - -兼容性信号比主 Node 24 信号更窄。它证明源码图在每个声明支持的运行时上都能通过类型检查,且真实的未构建 workflow-worker 启动路径能够执行,而不必重复文档、覆盖率、发布、快照回放以及那些不因 Node 版本而异的无关冒烟测试。 +兼容性 job 不再声称 TypeScript 本身已在每个 Node 运行时下执行。它们证明 Node 22、24 和 26 上对运行时敏感的源码加载,而主运行时负责唯一一次源码图类型检查。 diff --git a/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml b/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml index e3e1c0d234..b228a3a455 100644 --- a/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.i18n.yaml @@ -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 -2026-07-06-parallel-pre-push-gates.md: cf032f8dfedd88a7d6be87999fd9786a9efbb2e8 -2026-07-06-parallel-pre-push-gates.zh.md: 776faf1f46c6490f1935727612225414dd258aa3 +2026-07-06-parallel-pre-push-gates.md: f2e8f0054e595be20a320ec7095f0fe674eb93c6 +2026-07-06-parallel-pre-push-gates.zh.md: 06cd2fc41ca9a2cc2546fe85de82c8198f9573c3 diff --git a/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.md b/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.md index 87b1c0847b..f2e8f0054e 100644 --- a/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.md +++ b/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-07-06-parallel-pre-push-gates.zh.md) + The local-hook portion of this record is superseded by [Fast local Git hooks](2026-07-22-fast-local-git-hooks.md). The bounded gate scheduler and package-level `publint` parallelism remain in force for CI, `doc-sync`, and explicit local commands. ## Problem diff --git a/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md b/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md index 776faf1f46..06cd2fc41c 100644 --- a/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md +++ b/.agents/notes/implemented/process/2026-07-06-parallel-pre-push-gates.zh.md @@ -1,42 +1,33 @@ -# RFC: 并行 pre-push 门禁 +# Agent Note: 并行 pre-push 门禁 Status: implemented [English](2026-07-06-parallel-pre-push-gates.md) | 中文 +本记录中的本地 hook 部分已由[快速本地 Git hook](2026-07-22-fast-local-git-hooks.md) 取代。有界门禁调度器和包级 `publint` 并行机制仍用于 CI、`doc-sync` 和显式本地命令。 + ## 问题 -pre-push 钩子是分支离开本地机器前的最后一道检查点,因此它的挂钟时间直接影响贡献者是否愿意保持启用并信任其信号。Lefthook 已经能并行运行顶层 job,但 `pnpm run hygiene` 和 `pnpm run doc-sync` 等聚合 job 在单个 job 内部隐藏了长串的顺序执行链。钩子因此可能在配置上看似并行,实际仍在等待那些成员彼此独立却串行执行的子命令。 - -将这些成员直接展平到 `lefthook.yml` 只能解决本地钩子的问题。CI 面临同样的调度问题,而在 YAML 中复制一长串叶子列表会让未来的脚本改动有两处可能漂移。 - -`publint` 在更低一层也有同样的形态。每个包(package)独立地根据自身 manifest(元数据清单)和构建产物做 lint,但 runner 按顺序遍历所有包。在本仓库中,这意味着一个包发布门禁的耗时与包的数量成正比,尽管各检查之间并不共享可变状态。 +文档同步等聚合 job 隐藏了很长的串行链,其成员只读且相互独立。在工作流 YAML 中重复这些叶子清单,会使未来脚本变更有多个位置可以发生漂移;而串行运行包发布检查,会使一道门禁的耗时与包数量成正比。 ## 决策 -[lefthook.yml](../../../../lefthook.yml) 保留一个名为 `full check` 的 pre-push job,运行 `pnpm run check:pre-push`。该 package 脚本委托给 [scripts/run-gates.ts](../../../../scripts/run-gates.ts),即 CI 使用的同一个有界调度器。 +[scripts/run-gates.ts](../../../../scripts/run-gates.ts) 拥有 CI、`doc-sync` 和选择启用的 `check:all` 命令所使用的有界调度器。它将具名模式展开为叶子门禁,遵守产物依赖,缓冲可归因的输出,并在调用方需要不同 worker 上限时接受 `DSH_GATE_CONCURRENCY`。 -`pre-push` 模式展开为以下叶子门禁:单元测试套件、快照测试套件、构建、`hygiene` 成员、`doc-sync` 成员,以及 module-graph 新鲜度。叶子列表保持与 package 脚本相同的门禁词汇,包括 RFC 分类和 RFC 格式,同时 runner 并发调度独立检查,并为每个门禁打印一个计时/输出块。 +[scripts/publint-all.ts](../../../../scripts/publint-all.ts) 从 `packages/<group>/<pkg>` 发现包,并以根据 `availableParallelism()` 确定大小的 worker 池运行 `publint`。`DSH_PUBLINT_CONCURRENCY` 可以针对资源配置不同的本地机器和 CI runner 限制或提高 worker 数量。结果按包缓冲,并按确定性的包顺序打印,因此并行执行不会打乱各包的日志块。 -构建门禁使钩子在干净的 worktree 上也能自足运行。`publint` 和 `verify-node-next-types` 等待构建产物就绪,而仅依赖源码的门禁继续并行执行。 - -[scripts/publint-all.ts](../../../../scripts/publint-all.ts) 从 `packages/<group>/<pkg>` 发现包列表,并使用大小取自 `availableParallelism()` 的 worker 池运行 `publint`。`DSH_PUBLINT_CONCURRENCY` 可为资源配置不同的本地机器和 CI runner 设定或提高 worker 数量上限。结果按包缓冲,并以确定性的包顺序打印,因此并行执行不会打乱各包的日志块。 - -聚合 package 脚本仍然是临时本地运行的真源。调度器是对其成员门禁的并行执行计划,而非替代词汇。 +各门禁的包脚本仍是临时本地运行所用的词汇。`hygiene` 继续作为聚合 `&&` 链,而 `doc-sync` 在调度器中拥有其成员列表([通过门禁调度器运行 doc-sync](2026-07-21-doc-sync-through-gate-scheduler.md))。 ## 曾考虑的替代方案 -- **在钩子中保留聚合的 `hygiene` 和 `doc-sync` job**:配置更简单,但 pre-push 的大部分挂钟时间仍然消耗在 lefthook 看不到也无法调度的串行命令链内部。 -- **为每个叶子门禁声明一个 lefthook job**:通过 lefthook 原生 job 模型暴露并行性,但会让钩子文件承载一长串成员列表,CI 无法复用。 -- **要求开发者在推送前手动构建**:可以省去一个钩子门禁,但会导致 `publint` 在干净 worktree 上失败,并把最后的本地检查点从可运行的检查降级为一种约定。 -- **在 shell 脚本中使用后台子命令**:能并行化工作,但会丢失 lefthook 的 job 名称、逐 job 计时和失败分组,且信号处理更难推理。 -- **为每个包声明一个 publint lefthook job**:暴露最大并行度,但会让钩子变成一份手动维护的包清单,恰好在新增包时漂移。 -- **以无界并发运行 publint**:仅在小型机器上以赌注方式最小化耗时,代价是进程数、内存压力、包 tarball 创建和日志可读性的风险。 +- **保持聚合 job 串行**:执行更简单,但墙钟时间等于各独立检查之和,并重复启动命令包装器。 +- **每个叶子门禁声明一个 CI job**:暴露最大工作流并行度,但会重复 checkout、设置和安装开销,并在 YAML 中复制调度器清单。 +- **在 shell 脚本内后台运行子命令**:可以并行处理,但会失去各门禁计时、确定性的失败分组和直接的信号处理。 +- **每个包声明一个 `publint` job**:暴露最大包级并行度,但会创建手工维护的包清单,包发生变化时就会漂移。 +- **以无界并发运行 `publint`**:只有通过拿进程数、内存压力、包 tarball 创建和可读日志冒险,才能最大限度缩短小型仓库的耗时。 ## 后果 -钩子的关键路径变为最慢的单个真实门禁,而非隐藏门禁链的总和。Lefthook 报告一个 `full check` job,runner 在该 job 内部报告逐门禁计时,因此本地检查点偏慢时仍能指向主导耗时的那个门禁。 +由调度器支持的命令耗时取最慢依赖链,而非各独立门禁之和,并会报告主导耗时的门禁。代价是维护一个具有显式模式清单的定制调度器。 -钩子文件保持简短,重复的成员列表集中在 [scripts/run-gates.ts](../../../../scripts/run-gates.ts) 中,CI 和 pre-push 可以共享。代价是引入一个自定义调度器脚本(而非纯 lefthook 配置),外加本地 pre-push 路径中的一次构建。 - -`publint-all.ts` 变为异步代码,缓冲命令输出而非实时继承 stdio。收益是包级别的并行性、稳定的输出顺序,以及一个用于资源调优的环境变量。 +`publint-all.ts` 采用异步执行并缓冲命令输出,而不是实时继承 stdio。换来的是具有稳定输出顺序的包级并行,以及用于资源调节的单一环境变量。 diff --git a/.agents/notes/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml b/.agents/notes/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml index 69cfd7e0db..4234c01a0c 100644 --- a/.agents/notes/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-10-readme-known-limitations-gate.i18n.yaml @@ -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 -2026-07-10-readme-known-limitations-gate.md: 1aad1d40285f295833c2b1bd7d5c2e71bb780f34 -2026-07-10-readme-known-limitations-gate.zh.md: 4b3904fac3f980f9d005907775618cd28778a6fe +2026-07-10-readme-known-limitations-gate.md: 2ca1168d795692730d17b6ab23dd113e8be277e5 +2026-07-10-readme-known-limitations-gate.zh.md: 7968a30b996b931169bbe2678ec1500ff86ef577 diff --git a/.agents/notes/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md b/.agents/notes/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md index 4b3904fac3..7968a30b99 100644 --- a/.agents/notes/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md +++ b/.agents/notes/implemented/process/2026-07-10-readme-known-limitations-gate.zh.md @@ -1,4 +1,4 @@ -# RFC: 在每个 package README 中设置受门禁保护的 Known Limitations 章节 +# Agent Note: 在每个 package README 中设置受门禁保护的 Known Limitations 章节 Status: implemented @@ -6,15 +6,15 @@ Status: implemented ## 问题 -[文档标准](../../../AGENTS.md)将限制事项指定在 package README 中记录。如果没有统一的格式,缺失的章节无法区分「经审计确认无此内容」与「忘了写文档」,而标题写法不一致也会妨碍全仓库搜索。 +[文档标准](../../../../docs/AGENTS.md)规定限制项归属包 README。没有共享形状时,缺少章节无法区分“经审计确认没有限制”与“忘记编写文档”,不同的标题还会妨碍全仓库搜索。 ## 决策 -`packages/<group>/<pkg>/package.json` 下的每个包(package)manifest(元数据清单)都有一个同目录的 README,其中包含规范的 `## Known Limitations and Deferred Work` 章节。该章节的条目记录该包拥有的持久性消费方缺口与非显而易见的维护者约束;常规清理工作仍留在源码 TODO 或所属 RFC 中。[`verify-package-readme-limitations` 门禁](../../../../scripts/verify-package-readme-limitations.ts)从 manifest 推导包集合,拒绝缺少 README 的情况,并要求恰好有一个规范的 h2 标题且至少包含一个顶级条目。近似标题(如 "Limitations"、"Deferred"、"What is NOT here" 或 "Non-goals")会导致失败。 +`packages/<group>/<pkg>/package.json` 下的每份包清单都有一个同级 README,其中包含规范的 `## Known Limitations and Deferred Work` 章节。其项目符号记录由该包拥有的持久消费者缺口和不明显的维护者约束;普通清理仍留在源码 TODO 或所属 Agent Note(agent 决策记录)中。[`verify-package-readme-limitations` 门禁](../../../../scripts/verify-package-readme-limitations.ts)从清单推导包集合,拒绝缺失 README,并要求恰好一个规范 h2 且至少包含一个顶层项目符号。“Limitations”“Deferred”“What is NOT here”或“Non-goals”等近似标题都会失败。 如果一个包确实没有需要声明的限制事项,则将其列入 `NO_LIMITATIONS` 并省略该章节。新增限制事项时须移除该条目;重命名或移除条目会失败,因为每个条目都必须对应一个被扫描的包。 -门禁检查的是存在性、格式与白名单。覆盖面和准确性由文档标准与 [prose 标准](../../../../.agents/skills/dsh-prose-standard/SKILL.md)下的评审负责。常设规则见 [packages/AGENTS.md](../../../../packages/AGENTS.md)。 +门禁检查存在性、形状和允许列表。按照文档与[正文](../../../skills/dsh-prose-standard/SKILL.md)标准进行的评审负责覆盖面和准确性。常设规则位于 [packages/AGENTS.md](../../../../packages/AGENTS.md)。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml b/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml index 4a0af0834e..903114914c 100644 --- a/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.i18n.yaml @@ -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 -2026-07-12-package-model-experience-contract.md: 28a1c75ca6f451b4ca2f6da6abf36f72c5d43b31 -2026-07-12-package-model-experience-contract.zh.md: 77fa7a67847ed186b65db57b6dda378a93b94d92 +2026-07-12-package-model-experience-contract.md: 92a8e5a1a81d00dae085e4af89456896373058e6 +2026-07-12-package-model-experience-contract.zh.md: d81e87f1cb52cc77800ad5e6256796aa389f3215 diff --git a/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.md b/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.md index dd986f3661..92a8e5a1a8 100644 --- a/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.md +++ b/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-07-12-package-model-experience-contract.zh.md) + ## Problem A package README can explain APIs and runtime mechanics without answering the questions that dominate an agent harness's behavior and cost: what from this package reaches a model request, under which conditions, how long those tokens remain, and whether later requests preserve a reusable KV-cache prefix. The omission is especially hard to audit in a plugin architecture. A consumer may turn a backend result into a tool message, a policy plugin may replace success with an error, compaction may remove old history, and an agent-scoped registration may change one agent's prompt or schemas while leaving every other agent unchanged. Reading only the nominally model-facing packages therefore misses real context effects, while reading source across every dependency is too expensive for routine review. diff --git a/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.zh.md b/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.zh.md index 77fa7a6784..d81e87f1cb 100644 --- a/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.zh.md +++ b/.agents/notes/implemented/process/2026-07-12-package-model-experience-contract.zh.md @@ -1,4 +1,4 @@ -# RFC: Package Model Experience 契约 +# Agent Note: Package Model Experience 契约 Status: implemented @@ -6,28 +6,28 @@ Status: implemented ## 问题 -一个 package(包)的 README 可以解释 API 和运行时机制,却不回答那个主导 agent harness(智能体框架)行为与成本的问题:本 package 中有什么内容会进入模型请求、在什么条件下进入、以及这些 token 会保留多久。在插件架构中,这一缺失尤其难以审计。消费方可能把后端结果转为工具消息,策略插件可能把成功替换为错误,上下文压缩(context compaction)可能移除旧历史,agent 作用域的注册可能改变某个 agent 的提示词或 schema 而其他 agent 不受影响。因此,只阅读名义上面向模型的 package 会遗漏真实的上下文影响,而跨所有依赖阅读源码对日常评审来说又太昂贵。 +包 README 可以解释 API 和运行时机制,却不回答主导 agent harness(智能体框架)行为与成本的问题:该包的哪些内容会进入模型请求、在什么条件下进入、这些 token 会保留多久,以及后续请求是否会保留可复用的 KV cache 前缀。在插件架构中,这种遗漏尤其难以审计。消费者可能把后端结果转为工具消息,策略插件可能以错误取代成功结果,压缩可能移除旧历史,而 agent 范围的注册可能改变某个 agent 的 prompt 或 schema,却不影响其他 agent。因此,只阅读名义上面向模型的包会遗漏真实的上下文效应,而在每次常规评审中跨所有依赖阅读源码又成本过高。 ## 决策 -每个具有面向模型或模型相邻契约的 workspace package README,在末尾、`## Known Limitations and Deferred Work` 之前放置规范的 [Model Experience 章节](../../../cookbook/adding-a-package.md#4-write-the-package-readme);位于 no-limitations 允许列表上的 package 以 Model Experience 本身作为末尾章节。经审计确认为模型无关的通用 package 通过 `NO_MODEL_EXPERIENCE_SECTION` 省略该章节。 +每个具有面向模型或邻近模型契约的 workspace 包 README 都以规范的[模型体验章节](../../../../docs/cookbook/adding-a-package.md#4-write-the-package-readme)收尾,位置紧邻 `## Known Limitations and Deferred Work` 之前;位于“无限制项”允许列表中的包则以模型体验本身结尾。经审计确认与模型无关的通用包通过 `NO_MODEL_EXPERIENCE_SECTION` 省略该章节。 -具有直接、条件性、有上限、生命周期性、多表面或辅助模型效应的 package,每个上下文表面使用一个 H3。每个 H3 说明相关模型接收到什么内容以及何时接收,然后对 token 效应进行分类。由 package 拥有的稳定文本逐字引用:系统提示词行文和其他长字面量使用嵌套 H4 加 `markdown` 围栏,短字面量则以行内形式呈现并使用命名插值占位符。工具 schema 表面链接到生成的[工具目录](../../../tool-catalog.md)中对应的锚定章节,仅说明组合或配置差异;仅在运行时定义的工具则解释为何目录中未收录。数据依赖和提供方拥有的文本以摘要形式描述。agent 作用域的可见性须显式说明;当作用域可以隐藏其中一个而不影响另一个时,提示词表面与 schema 表面保持分开。 +具有直接、条件式、有上限、全生命周期、多表面或辅助模型效应的包,为每个上下文表面使用一个 H3。每个表面包含三个有序 H4 字段——`What the model sees`、`Token effect` 和 `KV Cache effect`——每个字段都以一个正文段落开头。cache 字段区分仅追加增长、稳定重复前缀、替换先前 token,以及独立模型请求;它点明由包拥有、且能在新内容追加前改变请求的每项配置、范围、生命周期、压缩或路由变化。“Does not invalidate”表示该包保留一个已经可复用的前缀,并非承诺 provider 一定命中 cache 或保留某段时间。由包拥有的稳定文本按原文精确引用:system prompt 正文和其他长字面量在引入它们的字段下使用带标题的 H5 加 `markdown` 围栏,通常位于 `What the model sees`;短字面量则以内联形式保留,并点名插值占位符。工具 schema 表面链接生成式[工具目录](../../../../docs/tool-catalog.md)中带锚点的章节,并且只陈述组合或配置增量;仅运行时定义解释目录为何省略它们。依赖数据和由 provider 拥有的文本采用摘要。agent 范围的可见性须显式说明;当范围可隐藏 prompt 与 schema 中的一者而不影响另一者时,两种表面保持分离。 -没有模型上下文效应的 package,或其路径完全由另一个 package 渲染的 package,使用验证器审计过的单句形式:`None, as ` 或 `Indirectly, through `。纯传输和无密钥的测试支持 package 在不创建模型绑定内容时使用 none 形式。提供方后端即使对数据进行上限或过滤,也使用 indirect 形式;组装 bundle 在命名子 package 拥有全部效应时同样使用 indirect 形式。这些句子定位贡献所在,而不重述消费方的内容。结构化章节同样只记录 package 自身拥有的输入、变换和差异。 +没有模型上下文效应的包,或某条路径完全由另一个包渲染的包,使用验证器审计过的短格式:一句以 `None, as ` 或 `Indirectly, through ` 开头的句子,随后是一个 `KV Cache effect` H4 和一个正文段落。纯传输包和无密钥测试支持包若不创建任何进入模型的内容,就使用 none 格式。provider 后端即使会限制或过滤数据也使用 indirect 格式;具名子项拥有全部效应时,接线 bundle 也使用该格式。这些章节定位贡献并声明不会直接使 cache 失效,同时不重复陈述消费者。结构化章节同样只记录由包拥有的输入、变换和增量。 -`verify-package-readme-model-experience` 发现 package manifest(元数据清单)并验证三种分类、规范的末尾章节顺序、必填字段、具体字面量证据、嵌套逐字块和锚定的工具目录链接。它在 `doc-sync`(文档同步门禁)和并行门禁运行器中执行。覆盖面、链接相关性和事实准确性仍由评审把关。 +`verify-package-readme-model-experience` 发现包清单,并验证三种分类、规范末尾章节顺序、确切字段标题深度与顺序、非空字段段落、逐字块的 H5 归属、具体字面量证据,以及带锚点的工具目录链接。它在 `doc-sync` 和并行门禁 runner 中运行。评审仍负责覆盖面、链接相关性和事实准确性。 ## 曾考虑的替代方案 - **只记录注册提示词或工具的 package**:否决。后端、策略插件、适配器、持久化、作用域和压缩都会改变 token 的内容或生命周期,却不拥有面向模型的 schema。 - **从源码生成一份集中式上下文成本目录**:否决。AST 能找到注册点,但无法推断语义条件,如历史保留、输出截断、父子可见性或辅助模型边界。package README 是实现本地的契约;集中副本会增加又一个漂移面。 - **要求给出精确 token 数**:否决。精确数量取决于所选模型的 tokenizer、适配器序列化方式、配置和运行时数据。稳定的契约是增长形状:每请求固定、每调用条件性、保留、替换、有上限或零直接影响。 -- **使用三列表格**:否决。精确的源文本和条件性结果形状使单元格密集且难以扫读。重复的子章节为每个上下文表面提供可读的纵向空间,同时保留相同的字段。 +- **使用表格**:否决。精确源码文本和条件式结果形状会使单元格密集而难以扫读。重复的小节在保留相同字段的同时,为每个上下文表面提供易读的纵向空间。 - **允许所有零影响 package 省略该章节**:否决。无约束的缺失在「经审计的零影响」和「忘记写文档」之间有歧义。省略仅限于在验证器中以理由命名的模型无关通用 package;模型相邻的零影响 package 保留一句显式说明。 -- **对审计过的零影响或简单间接 package 也要求完整结构化形式**:否决。围绕一个事实重复标签没有意义。受门禁约束的单句保留了显式覆盖而无需繁文缛节。 +- **要求经审计的零效应包或简单间接包使用完整结构化格式**:否决。它会围绕一个事实重复标签。受门禁约束的句子加 cache 字段既保留显式覆盖,又没有多余仪式。 - **只有约定而无门禁**:否决。仓库级契约必须覆盖未来的每个 package;评审者的记忆无法可靠地检测到遗漏的 README 章节。 ## 后果 -评审者可以从任何面向模型或模型相邻的 package 出发,直接看到它对会话模型、子模型和辅助调用的贡献,无需重建完整的插件图。token 预算工作可以区分每次请求的重复开销与数据依赖的历史,agent 作用域的变更有了显式的文档检查点。package 作者在模型可见行为变更时维护一个或多个紧凑的上下文表面块或一句分类说明;经审计的通用 package 不承载无关的模型样板文字。结构化字段不承诺提供方精确的 token 数;测量仍然是模型和负载特定的,而文档化的增长与可见性契约保持稳定。 +评审者可以从任何面向模型或邻近模型的包开始,看到它对对话模型、子模型和辅助调用的贡献,无需重建完整插件图。token 预算工作可以区分重复请求开销和依赖数据的历史,而 cache 敏感工作可以识别仅追加路径,以及最早由包引起的前缀变更。agent 范围变更有明确的文档检查点。每当模型可见行为发生变化时,包作者都要维护一个或多个紧凑的上下文表面块,或一种已分类的短格式;经审计的通用包不携带无关的模型样板。结构化字段不承诺 provider 精确的 token 数或 cache 命中;测量仍取决于模型、provider 和工作负载,而所记录的增长、可见性和前缀稳定性契约保持稳定。 diff --git a/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml index d94f825076..aeda386ff4 100644 --- a/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.i18n.yaml @@ -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 -2026-06-19-drop-mutable-session-summary.md: 0f005a78045869d62eb141c9bce8af037671b687 -2026-06-19-drop-mutable-session-summary.zh.md: a33b057c2177258e0e3e2c0c3f78176835acb070 +2026-06-19-drop-mutable-session-summary.md: 80fe043e365352b17d2a5b3efa1ab8d396d311c4 +2026-06-19-drop-mutable-session-summary.zh.md: ec98c19093369400b9b42a5c1a0590b5c6913ab9 diff --git a/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md b/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md index a33b057c21..ec98c19093 100644 --- a/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-19-drop-mutable-session-summary.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除可变的会话摘要 +# Agent Note: 移除可变的会话摘要 Status: implemented @@ -12,7 +12,7 @@ Status: implemented - `SessionPersistence.update()` **零个生产调用方**(所有 `.update(` 匹配都是 `createHash().update()` 或测试代码)。 - `firstPrompt` 在生产代码中**从未被读取**。 -- `title` *确实*在 ACP 桥接层被读取过,但读的是工具调用的 **presenter**(`present.title`),从未读取存储的会话元数据。 +- `title` *确实*在 ACP(Agent Client Protocol)桥接层被读取过,但读的是工具调用的 **presenter**(`present.title`),从未读取存储的会话元数据。 - `updatedAt` **没有消费方**:`list()` 唯一的生产调用方读取的是 `meta.cwd`(`SessionHeader` 字段),用于在 `session/load` 时校验工作区;恢复会话读取的是 `createdAt`/`cwd`/`parentSession`——全是 header 字段。 - 决定性的一点:活跃的 `Session.header` 类型本来就是 `SessionHeader` 而非 `SessionMeta`——摘要从未存在于活跃会话对象上;它只存在于持久化层,除了自身的契约测试外无人写入、无人读取。 @@ -22,7 +22,7 @@ Status: implemented 摘要原本要提供的一切,在消费方真正需要时都**可从仅追加日志中派生**(`firstPrompt` = 第一条 `user/message`;近期度 = 最后一个事件的 `time` 或文件 mtime),或者已经存在于不可变 header 中(`createdAt`、`cwd`)。唯一*不可*派生的是用户*手动编辑*的标题,但它从未实现,纯属 YAGNI;如果未来真有功能需要,它可以作为独立的日志事件或 header 字段回归。 -将此记录为决策,原因有三:**持久性**(它收窄了一个公开服务契约和跨两个后端的磁盘格式)、**争议性**(摘要是有意的前瞻性设计,而非意外产物)、**意外性**(未来读者看到 `SessionHeader` 而原始 RFC 描述的是 `SessionMeta`,否则会疑惑摘要为何消失)。它还为 [shared persistence write coordinator](../architecture/2026-06-18-shared-persistence-write-coordinator.md) 扫清了障碍:没有可变摘要后,协调器的钩子接口无需 `updateSummary` 钩子,JSONL 伴随文件与 SQLite 列之间的持久性分歧也随之消失,两个后端的写入路径得以统一。 +这被记录为一项决策,因为它具有**持久性**(它同时收窄两个后端的公共服务契约和磁盘格式)、**争议性**(summary 是有意为未来设计的结果,而非意外),也具有**意外性**(未来读者在原 Agent Note(agent 决策记录)描述 `SessionMeta` 的位置发现 `SessionHeader`,否则会追问 summary 为何消失)。它还为[共享持久化写入协调器](../architecture/2026-06-18-shared-persistence-write-coordinator.md)扫清障碍:不再有可变 summary 后,协调器的 hook 接口不需要 `updateSummary` hook,JSONL sidecar 与 SQLite 列之间的持久性分歧也随之消失,使两个后端的写入路径趋于一致。 ## 无需迁移 @@ -32,4 +32,4 @@ Status: implemented 未来的会话选择器现在必须从日志派生预览/排序信息(或重新引入一个类型化字段),而不能直接读取现成的摘要行。这是正确的代价:为一个尚不存在的功能维护缓存,是每个后端都要付出维护成本、每个契约测试都要付出断言成本的死重。这一原则——**通过的测试固定的是当前行为,不一定是正确行为;行为可能是过去妥协的产物**——现已作为独立约定记录在[根 AGENTS.md](../../../../AGENTS.md) 中,本次变更即为其实例。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml index 784b07f47b..1240ee061a 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-20-collapse-trace-only-session-events.i18n.yaml @@ -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 -2026-06-20-collapse-trace-only-session-events.md: c446f43d887088fcf562305fcc2dad37465fb124 -2026-06-20-collapse-trace-only-session-events.zh.md: eda7f738abbaced393f2588867f9dcd8e86e2386 +2026-06-20-collapse-trace-only-session-events.md: fce5c48ef6fcb1abc6e2fbb95dc7e83d22956660 +2026-06-20-collapse-trace-only-session-events.zh.md: 4302646b78ea0b22b479c7068f0f6259bf79edec diff --git a/.agents/notes/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md b/.agents/notes/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md index eda7f738ab..4302646b78 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-20-collapse-trace-only-session-events.zh.md @@ -1,4 +1,4 @@ -# RFC: 将仅用于追踪的会话事实折叠进承载性事件 +# Agent Note: 将仅用于追踪的会话事实折叠进承载性事件 Status: implemented @@ -35,7 +35,7 @@ Status: implemented ## 实现说明 -按提案交付,有一处范围细化(遵循 AGENTS.md「RFC 是提案,不是金科玉律」): +按提案落地,但有一处范围细化(遵循 AGENTS.md 所述“Agent Note(agent 决策记录)是提案,而非绝对真理”): - **空内容 `assistant/message` 承载 usage,无数据丢失。** 提案要求的证明(不会有已持久化的 usage 分片无处安放)落在 max-tokens 路径上:一个被截断的步骤有 usage 但内容为空(例如只有一个被丢弃的工具调用),以前会发出独立的 `usage`。现在它记录一个空内容的 `assistant/message { content: [], usage }`。为防止这向 provider transcript 注入一个无内容的虚假 assistant 轮次,`deriveMessages()` 跳过空内容的 `assistant/message` 事件。回归测试断言 usage 仍被表示,且派生历史未被破坏。 diff --git a/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml index 7534bcc2da..012f47ae00 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.i18n.yaml @@ -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 -2026-06-20-drop-unconsumed-llm-adapter-change-event.md: 657e5f08c02e1e03eedeccf8a30b8bc851201615 -2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md: fbc2248c8357dbff3f5f5008647c14c23a66d5b0 +2026-06-20-drop-unconsumed-llm-adapter-change-event.md: a3c7c089d7dfa1a4cd6a891c416bf270dc7eff3d +2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md: 8839a4c263462f2bae75d8698b20007e8348d903 diff --git a/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md b/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md index fbc2248c83..8839a4c263 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除未被消费的 `llm/adapter-change` 事件 +# Agent Note: 移除未被消费的 `llm/adapter-change` 事件 Status: implemented @@ -8,25 +8,25 @@ Status: implemented `LlmService.registerAdapter()` 在注册和 dispose(资源释放)时发出 `llm/adapter-change` 事件([packages/llm/llm/src/index.ts](../../../../packages/llm/llm/src/index.ts))。在 `packages/*/src` 和 `examples/*/src` 中搜索 `llm/adapter-change`,只能找到声明、emit 站点、文档和测试;没有任何生产环境的监听器订阅它。 -这与 `tools/change` 和 `system-prompt/change` 不同。后两个事件目前同样未被消费,但它们是合理的注册表变更信号,未来可能服务于实时工具/提示词 UI。LLM(大语言模型)适配器注册更接近启动时的实现细节:适配器不是用户可见的面板,真正的模型调用拦截 seam 是 `llm/stream`。保留一个没有监听器的 adapter-change 事件,是在更小规模上重复 [drop-the-dead-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 的模式。 +这与 `tools/change` 和 `system-prompt/change` 不同。如今这两个事件同样没有消费者,但它们有望成为未来实时工具/prompt UI 的注册表变更信号。LLM(大语言模型)adapter 注册更像是启动时的实现细节:adapter 不是用户可见的选项面板,真正的模型调用拦截接缝是 `llm/stream`。保留一个没有监听器的 adapter 变更事件,只是在更小范围内重复[删除无用 summary](2026-06-19-drop-mutable-session-summary.md) 的模式。 这个事件并非零成本。`registerAdapter()` 在发出 `llm/adapter-change` 之前先 yield 回滚 disposer,这样抛出异常的监听器会回退变更而非泄漏适配器条目;包内还有针对该监听器抛出路径的测试。这种防御性排序保护的是一个只有测试才能触发的失败模式。 ## 决策 -仅移除 `llm/adapter-change`:`dsh-llm` 的 `interface Events` 中的声明、`ctx.emit('llm/adapter-change')` 调用,以及 `LlmService.registerAdapter` JSDoc 中的 "Emits `llm/adapter-change` on registration and disposal" 语句。`registerAdapter()` 的 effect generator 保留变更与回滚 disposer 以支持 HMR(热模块替换)/dispose,但去掉了仅为已移除事件而存在的监听器抛出回滚排序。适配器 disposer 测试断言返回的 disposer 能移除适配器,而不再订阅该事件;监听器抛出回滚测试随其主题一同移除。[docs/architecture.md](../../../architecture.md) 和 [packages/llm/llm/README.md](../../../../packages/llm/llm/README.md) 中的事件分类体系在同一个变更中更新。 +只移除 `llm/adapter-change`:包括 `dsh-llm` 的 `interface Events` 中的声明、`ctx.emit('llm/adapter-change')` 调用,以及 `LlmService.registerAdapter` JSDoc 中“在注册和释放时发出 `llm/adapter-change`”的句子。`registerAdapter()` 的效应生成器为 HMR(热模块替换)/释放保留变更与回滚 disposer,但移除仅因该事件而存在的监听器抛错回滚顺序。adapter disposer 测试断言返回的 disposer 会移除 adapter,不再订阅事件;监听器抛错回滚测试则随其测试对象一起消失。[docs/architecture.md](../../../../docs/architecture.md) 和 [packages/llm/llm/README.md](../../../../packages/llm/llm/README.md) 中的事件分类也在同一变更中更新。 ## 曾考虑的替代方案 ### 为什么不移除所有注册表变更事件? -一个注册表主动广播变更的微内核是一种自洽的约定。`tools/change` 和 `system-prompt/change` 在 UI 能实时刷新可用工具或提示词段落时可能变得有用。本 RFC 保留该约定中有合理的面向用户消费方的部分,仅裁掉当前和可预见未来消费方都不明确的 adapter-change 事件。 +由注册表通告变更的微内核是一种一致的约定。当 UI 能够实时刷新可用工具或 prompt 章节时,`tools/change` 和 `system-prompt/change` 可能会有用。本 Agent Note(agent 决策记录)在存在合理用户侧消费者的位置保留该约定,只删除当前及可能的未来消费者都不明确的 adapter 变更事件。 如果将来需要 LLM 适配器浏览器或动态模型选择器用到此信号,届时再连同消费方一起重新引入,并提供比「something changed」更清晰的 payload。 ## 验证 -`llm/adapter-change` 及其 emit 已移除,重新生成的 cordis catalog 是最新的;HMR 安全性保持(dispose 一个贡献 fiber 会移除对应适配器);`tools/change` 和 `system-prompt/change` 仍有文档和测试;没有任何生产路径的可观察行为发生变化——ACP(Agent Client Protocol)快照 golden 和 echo-agent 冒烟测试逐字节未变。 +`llm/adapter-change` 及其 emit 已消失,重新生成的 Cordis 目录保持新鲜;HMR 安全性仍成立(释放贡献该 adapter 的 fiber 会移除它);`tools/change` 和 `system-prompt/change` 仍有文档与测试;ACP(Agent Client Protocol)快照和无密钥 Headless Loader 冒烟则固定了未变的生产路径。 ## 后果 diff --git a/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml index f9986e5608..0fdd9342a5 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.i18n.yaml @@ -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 -2026-06-20-drop-unconsumed-llm-assembled-surfaces.md: ead3a8c094b0fc0b4bd01671bd4a1165dd555ea2 -2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md: 16704b511151c329622e58c3b5f6b2cff330f366 +2026-06-20-drop-unconsumed-llm-assembled-surfaces.md: b6b596e822b4bd6fd1bd891c336c622ad675ad45 +2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md: 5a4e378958f5fb594345305804a3b90e493f0560 diff --git a/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md b/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md index 16704b5111..5a4e378958 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-assembled-surfaces.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除未被消费的 LLM 组装便捷接口 +# Agent Note: 移除未被消费的 LLM 组装便捷接口 Status: implemented @@ -14,7 +14,7 @@ Status: implemented LLM(大语言模型)服务唯一的生产消费方是 agent loop(智能体循环),它只使用 `stream()`:将原始分片送入自己的 `BlockAssembler`,以便在并行组装的同时记录分片,保证回放保真度([packages/core/agent-loop/src/loop.ts](../../../../packages/core/agent-loop/src/loop.ts),`ctx.llm.stream(req)` 步骤)。在 `packages/*/src` 和 `examples/*/src` 中 grep `streamBlocks` 与 `ctx.llm.generate`,找不到任何生产调用方。仅有的引用来自服务方法定义、文档和测试;适配器测试用 `generate()` 作为便捷驱动,但它们完全可以通过同一个 assembler 辅助函数手动消费 `stream()`,无需为此保留一个公开的生产 API。 -这与 [drop-mutable-session-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 是同一模式:拥有经过测试的契约的组装视图 API,消费方却只有测试而非生产代码。它们是为「不关心 token 级增量」的消费方预设的,但唯一的真实消费方恰恰需要增量,以便持久化高保真回放数据。 +这属于[删除可变 session summary](2026-06-19-drop-mutable-session-summary.md) 的同类模式:带有受测契约的组装视图 API,由测试而非生产代码消费。它们是为不关心 token 级增量的消费者推测性构建的,但唯一的真实消费者恰恰关心增量,以便持久化高保真重放数据。 `streamBlocks()` 拖带了 `BlockAssembler` 的一块专用逻辑:`flushReady()` 与 `flushRemaining()`([packages/llm/llm/src/assembler.ts:138-168](../../../../packages/llm/llm/src/assembler.ts))以及 `flushed` 游标字段,仅为支持按序增量产出而存在。`generate()` 拖带了 `GenerateResult`、`BlockAssembler.result()` 以及 `llm/generate` waterfall——在同一底层流之上的第二个拦截面。agent loop 对 assembler 的使用仅限于 `push()` / `message()` / `usage` / `finish`,不涉及流式 flush 或一次性服务组装。 @@ -28,7 +28,7 @@ LLM(大语言模型)服务唯一的生产消费方是 agent loop(智能体 ## 验证 -`streamBlocks`、`generate`、`llm/generate` 及其独占的 assembler 辅助方法已移除,无新增死导出;两个真实适配器通过 `stream()` 和共享 assembler 得到验证;agent loop 行为不变(ACP 快照 golden 文件无变化);README、架构文档与模块文档中不再提及已移除的接口。 +`streamBlocks`、`generate`、`llm/generate` 及仅供它们使用的 assembler 辅助函数均已移除,且未产生新的无用导出;两个真实 adapter 都通过 `stream()` 和共享 assembler 接受测试;循环行为保持一致(ACP(Agent Client Protocol)快照预期输出未变);README、架构文档和模块文档也不再提及已删除表面。 ## 后果 diff --git a/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml index b777318d66..a2d0e004e3 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.i18n.yaml @@ -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 -2026-06-20-prune-dead-seam-methods.md: fc656f4fc46837a75fa6c34c2de18cffde954ef3 -2026-06-20-prune-dead-seam-methods.zh.md: 2b8b2afea97aa28d32d55a9def217a593e9dbc7d +2026-06-20-prune-dead-seam-methods.md: bb91194ed0483ca4c43acdde8370e7152ac876ea +2026-06-20-prune-dead-seam-methods.zh.md: d64e9b5b6d40fbb0f52705a3385123b072360607 diff --git a/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.md b/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.md index 782ffe891e..bb91194ed0 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.md +++ b/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-20-prune-dead-seam-methods.zh.md) + > **Implementation note:** Only `SessionPersistence.has()` and `.delete()` were removed. `BashExecutor.get()` and `.list()` remain because removing their one-line lookup surface required substantially more completion-tracking machinery in consumers. Their id branding is covered by the [branded-ids Agent Note](../architecture/2026-06-20-branded-ids.md). ## Problem diff --git a/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md b/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md index 2b8b2afea9..d64e9b5b6d 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-20-prune-dead-seam-methods.zh.md @@ -1,27 +1,27 @@ -# RFC: 从 persistence seam 中移除无用方法 +# Agent Note: 从 persistence seam 中移除无用方法 Status: implemented [English](2026-06-20-prune-dead-seam-methods.md) | 中文 -> **实现说明:** 最终只移除了 `SessionPersistence.has()` 和 `.delete()`。`BashExecutor.get()` 和 `.list()` 保留,因为移除它们的单行查询接口需要在消费方引入大量额外的完成状态追踪机制。它们的 id 品牌化由 [branded-ids RFC](../architecture/2026-06-20-branded-ids.md) 覆盖。 +> **实现说明:** 仅移除了 `SessionPersistence.has()` 和 `.delete()`。`BashExecutor.get()` 和 `.list()` 仍然保留,因为删除它们的单行查找表面会要求消费者增加显著更多的完成跟踪机制。其 id 品牌化由[品牌化 id Agent Note(agent 决策记录)](../architecture/2026-06-20-branded-ids.md)负责。 ## 问题 -一个能力 seam([接口/实现/消费方](../../implemented/architecture/2026-06-13-capability-seams.md))承载着没有任何消费方调用的抽象方法。seam 的存在是为了让实现与消费方独立演进,但一个没有消费方编程依赖的方法不是 seam,而是每个实现仍须实现和测试的投机性接口面。 +能力接缝([接口 / 实现 / 消费者](../architecture/2026-06-13-capability-seams.md))承载了没有消费者调用的抽象方法。接缝的存在是为了让实现和消费者独立演进——但没有消费者以之编程的方法不是接缝,而是每个实现仍必须实现和测试的推测性表面。 ### `SessionPersistence.has()` 与 `.delete()` 该抽象服务在 create/append 之外声明了更多操作:`load`、`list`、`has`、`delete`。`ctx.sessionPersistence` 的生产消费方只用了两个:agent loop(智能体循环)的恢复路径调用 `load()`([packages/core/agent-loop/src/index.ts:176](../../../../packages/core/agent-loop/src/index.ts)),ACP(Agent Client Protocol)桥接层为 `session/list` 调用 `list()`([packages/ui/acp/src/index.ts:494](../../../../packages/ui/acp/src/index.ts))。在 `packages/*/src` 和 `examples/` 中 grep 所有 `sessionPersistence.*` / `persistence.*` 的使用,找不到对该服务的 `has(` 或 `delete(` 调用。`packages/ui/acp/src/index.ts` 中的 `.has(`/`.delete(` 调用作用于内存中的 `SessionStore` 和一个本地的 loading id `Set`,而非 persistence。`has`/`delete` 的唯一调用者是契约测试套件和各后端的 spec。 -`has()` 不仅是未使用——它还是共享协调器中最复杂的分支:一个 tracked-vs-untracked 双探测(`loadLive(id, cwd)` 用于活跃追踪的会话,`loadStored(id)` 用于未追踪的会话),附带多行注释说明理由。`delete()` 则拖带了 `deleteStored` 后端钩子,每个后端都必须实现它。这与 [drop-mutable-session-summary](../../implemented/simplification/2026-06-19-drop-mutable-session-summary.md) 是同一模式:契约测试覆盖了两者,但没有任何发布代码会问「这个会话是否已持久化?」或删除一个会话。 +`has()` 不仅没有被使用——它还是共享协调器中最复杂的分支:带有多行理由说明的“已跟踪/未跟踪”双重探测(对实时跟踪的 session 使用 `loadLive(id, cwd)`,对未跟踪 session 使用 `loadStored(id)`)。`delete()` 则拖入每个后端都必须实现的 `deleteStored` 后端 hook。这属于[删除可变 session summary](2026-06-19-drop-mutable-session-summary.md) 的同类模式:契约测试覆盖了两者,但已发布代码从不会询问“这个 session 是否已持久化?”或删除某个 session。 ## 决策 没有消费方使用的方法被移除——从抽象 seam、实现,以及仅为覆盖它们而存在的契约/spec 测试套件中移除: -- `SessionPersistence.has()` / `.delete()` 已移除:抽象声明、协调器的 `has`/`delete`/`deleteCore`,以及 `PersistenceBackend.deleteStored` 钩子(jsonl 和 sqlite 各自实现 `deleteStored` 仅为满足该钩子——这些实现也一并移除)。后端属于[双后端](../../implemented/architecture/2026-06-14-session-persistence.md)设计,本身不在本次范围内;移除它们为无消费方实现的钩子是移除钩子的一部分,而非后端重新设计。 -- 所有文档和源码注释中的引用都已更新为存留的四方法、仅含 `list()` 的契约——不仅是字面的 `has(`/`delete(`/`deleteStored` 拼写,还包括 `{@link has}`/`{@link delete}` JSDoc 链接和「六个公开方法」之类的计数——涉及 seam 和后端 README、[docs/architecture.md](../../../architecture.md)、[session-persistence](../../implemented/architecture/2026-06-14-session-persistence.md) 和 [write-coordinator](../../implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md) RFC,以及协调器/后端的 JSDoc。 +- `SessionPersistence.has()` / `.delete()` 已移除:抽象声明、协调器的 `has`/`delete`/`deleteCore`,以及 `PersistenceBackend.deleteStored` hook 均消失(jsonl 和 sqlite 都只是为了满足该 hook 才实现 `deleteStored`,这些实现也一并移除)。后端属于[双后端](../architecture/2026-06-14-session-persistence.md)设计,其他方面不在范围内;删除它们为没有消费者的 hook 所做的实现,是删除 hook 的一部分,而非重新设计后端。 +- 所有文档和源码注释引用都已更新为保留下来的四方法、仅含 `list()` 的契约——不仅包括字面上的 `has(`/`delete(`/`deleteStored` 拼写,还包括 `{@link has}`/`{@link delete}` JSDoc 链接和“六个公共方法”的计数——涉及接缝和后端 README、[docs/architecture.md](../../../../docs/architecture.md)、[session persistence](../architecture/2026-06-14-session-persistence.md) 与[写入协调器](../architecture/2026-06-18-shared-persistence-write-coordinator.md) Agent Note,以及协调器/后端 JSDoc。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml index eec7c0f05d..925bfbb43e 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.i18n.yaml @@ -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 -2026-06-20-public-agent-stop-surface.md: d34f21be66892e261f1435070aaf9b478c8dc7cd -2026-06-20-public-agent-stop-surface.zh.md: a510d39044048637c2462fd1d97eb3474931761a +2026-06-20-public-agent-stop-surface.md: 81a21de30bfbc25688069efbffb21647889b1bdb +2026-06-20-public-agent-stop-surface.zh.md: 4ad4b6b0beb01bc55f10c046023c7851558ecb20 diff --git a/.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md b/.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md index a510d39044..4ad4b6b0be 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-20-public-agent-stop-surface.zh.md @@ -1,4 +1,4 @@ -# RFC: 保留单一公开停止原语 +# Agent Note: 保留单一公开停止原语 Status: implemented @@ -8,19 +8,19 @@ Status: implemented ## 问题 -公开的 `Agent` 句柄暴露了两种重叠的方式来停止进行中的工作:`abort(reason?)` 和 `cancel(reason?)`。`abort()` 仅终止当前步骤,不影响队列中的工作;`cancel()` 清除队列中的工作和 steering(中途引导)工作、中止正在运行的步骤,并处理步骤前竞态。在生产环境中,ACP(Agent Client Protocol)使用 `cancel()` 实现 `session/cancel`,而生命周期所有者通过 `AgentHandle.dispose()` 销毁 agent(智能体)。没有生产调用方需要裸 `abort()`。 +公共 `Agent` handle 暴露了两种相互重叠的在途工作停止方式:仅针对 step 的 `abort()` 和感知队列的 `cancel()`。前者保留已排队输入,后者则清除已排队和 steering(中途引导)工作,并中止活动 turn。在生产中,ACP(Agent Client Protocol)对 `session/cancel` 使用 `cancel()`,生命周期拥有者则通过 `AgentHandle.dispose()` 拆除 agent(智能体)。没有生产调用方需要一个裸的、仅针对 step 的 abort。 -`abort()`/`cancel()` 的区别是真实存在的:`abort()` 保留队列中的提示词和 steering,而 `cancel()` 丢弃它们。但没有任何已上线的代码调用过公开的 `abort()` 动词。循环自身的停止路径(`cancel()` 和 disposal)直接中止当前 `AbortController`,而不经由 `Agent.abort()` 路由。大多数调用 `abort()` 的测试中断的是空队列,可以改用 `cancel(reason)`;那个刻意依赖队列保留的 steering 重投递测试则直接驱动进行中的 `AbortController`,因为 `cancel()` 会丢弃它试图证明在步骤中止后仍存活的已排队 steering。无参 `abort()` 的默认原因(`'aborted'`)随该动词一起删除,而非被意外保留;`cancel()` 保留自己的 `'cancelled'` 默认值。 +行为差异确实存在,但已发布代码不需要较窄的操作。AgentLoop 改为为整个 turn 拥有一个私有取消 holder。`cancel(cause?)` 携带类型化的 `user` 或 `parent` 原因,默认为 `user`,并丢弃待处理输入;释放仍是单独的生命周期中断。完整的归属与传播契约位于[显式 turn 取消 Agent Note(agent 决策记录)](../architecture/2026-07-16-explicit-turn-cancellation.md)。 多余的公开接口使得循环不得不承载一个本质上属于内部拆卸的公开动词:`abort()` 必须被文档描述为有别于队列感知的取消,尽管 UI 取消几乎总是需要更广泛的操作。 ## 决策 -`cancel()` 是 `Agent` 上唯一的公开*停止*原语。生命周期所有者使用 `AgentHandle.dispose()` 停止并注销 agent;非所有者使用 `cancel()` 放弃当前和队列中的工作。实现内部保留一个私有的 abort controller,但它不属于面向插件的 `Agent` 契约。 +`cancel()` 是 `Agent` 上唯一的公共*停止*原语。生命周期拥有者使用 `AgentHandle.dispose()` 停止并注销 agent;非拥有者使用 `cancel()` 放弃当前和已排队工作。实现保留一个私有 turn 取消 holder,但它不属于面向插件的 `Agent` 契约。 `whenIdle()` **保留**为公开的静默观测原语(agent 从 `running` 状态稳定后 resolve,已处于 idle 时立即 resolve,dispose 后等待循环退出)。它不是停止动词;它是非所有者在不 dispose agent 的前提下观测停止*完成*的方式。它的活跃消费方是 ACP 和通过此公开 seam 等待结算的 agent 测试(`packages/ui/acp/tests`、`packages/core/agent-loop/tests`);生产环境的 ACP 桥接层拥有其 agent 并通过 `AgentHandle.dispose()` 销毁它们,因此 `packages/ui/acp/src` 本身没有 `whenIdle()` 调用。 -公开的 `abort()` 被删除,连同将其作为独立 API 测试的用例以及将步骤级中止描述为嵌入特性的文档。空队列中止测试迁移到 `cancel(reason)`,仍然验证取消行为;以循环内部 `AbortController` 为测试对象的用例通过包内类型转换直接驱动该 controller 的私有字段;仅固定已移除的无参 `abort()` 默认值的测试随方法一起删除。disposer 仍为异步,仍等待循环停止。 +公共 `abort()` 已不存在,disposer 仍为异步并等待循环停止。测试通过公共类型化原因和显式 signal 接缝验证取消,而不会伸入 holder 内部。 ## 曾考虑的替代方案 @@ -36,4 +36,4 @@ Status: implemented ## 相关 -本 RFC 仅移除冗余的停止动词。中途 steering 仍是有意保留的消息路径;静默观测仍通过 `whenIdle()` 提供。最终的公开接口为 `send()`、`steer()`、`inject()`、`cancel()`、`whenIdle()`、status、options、session 和 identity。 +本 Agent Note 只移除冗余的停止动词。turn 中途 steering 仍是一条有意保留的消息路径;静止观察仍通过 `whenIdle()` 完成。最终公共表面包括 `send()`、`steer()`、`inject()`、`cancel()`、`whenIdle()`、status、options、session 和 identity。 diff --git a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml index 16911f7c70..64c80eedcc 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.i18n.yaml @@ -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 -2026-06-20-remove-agent-boundary-mirror-events.md: 0ea8512ca6b66b2e8ab8cf2746bdc65d79caa9d4 -2026-06-20-remove-agent-boundary-mirror-events.zh.md: 30632bf223cb41c18f62c18a544ff42f70af1136 +2026-06-20-remove-agent-boundary-mirror-events.md: 8c5bb74f2347fe0269cbb9c6504137de761ab919 +2026-06-20-remove-agent-boundary-mirror-events.zh.md: feed8239b6a07c2e27866f72954cfb95830541f4 diff --git a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md index 910eb46e92..8c5bb74f23 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md +++ b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-20-remove-agent-boundary-mirror-events.zh.md) + <!-- Shipped in AMENDED, narrowed form: the four turn/step BOUNDARY mirrors are removed; `agent/steering` and `agent/stream-chunk` were RETAINED here (they are not durable-boundary mirrors — see "Scope: what is and isn't removed"). diff --git a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md index 30632bf223..feed8239b6 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-20-remove-agent-boundary-mirror-events.zh.md @@ -1,12 +1,21 @@ -# RFC: 停止将持久化边界镜像为 agent 事件 +# Agent Note: 停止将持久化边界镜像为 agent 事件 Status: implemented [English](2026-06-20-remove-agent-boundary-mirror-events.md) | 中文 +<!-- 以修订、收窄后的形式落地: + 移除了四个 turn/step 边界镜像;此处保留了 `agent/steering` 和 + `agent/stream-chunk`(它们不是持久边界镜像——参见 + “范围:移除什么、不移除什么”)。原始提案将 `agent/steering` 与其他项一并 + 移除;把它排除在外,使本 Agent Note 的范围保持在边界上。后来每个保留事件 + 都由各自的决策移除——参见 + [停止将 token 流镜像为 agent 事件](2026-07-02-remove-stream-chunk-mirror.md) + 和[移除 `agent/steering` 镜像 emit](2026-07-04-remove-agent-steering-mirror.md)。 --> + ## 问题 -agent loop(智能体循环)通过可回放的 `SessionEvent` 日志和实时 `agent/*` 镜像两条路径暴露持久化的轮次与步骤边界。消费方不得不在同一事实的两个来源之间做选择,并协调二者的时序。ACP(Agent Client Protocol)和持久化层已经使用日志;stdio UI 是唯一仍在消费镜像的组件,而它已经从 `session/event` 渲染工具调用和工具结果。 +循环在 `SessionEvent` 中记录规范 transcript(文本记录),同时还发出一组并行的实时 `agent/*` 边界镜像事件:`agent/turn-start`、`agent/turn-end`、`agent/step-start` 和 `agent/step-end`。这些镜像迫使消费者在同一持久事实的两个事实来源之间做选择。ACP(Agent Client Protocol)已经为面向编辑器的 transcript 选择 session log,因为它是唯一持久、可重放的记录;消费实时镜像需要把它的时序与日志中已经存储的边界进行调和。stdio UI 是唯一仍从镜像事件渲染 turn 边界的生产消费者;它已经从 `session/event` 渲染工具调用和结果。 这种重复并非零成本。每次生命周期变更都需要同时更新会话事件、镜像事件、文档、不变式、测试和快照预期。重复的边界事件还使失败排序变得微妙:一个轮次可能在实时 `agent/turn-end` 监听器运行之前就已被持久化关闭,因此边界之后的监听器失败在日志中已没有合法位置可以插入,只能带外上报。 @@ -14,19 +23,25 @@ agent loop(智能体循环)通过可回放的 `SessionEvent` 日志和实时 将 `session/event` 作为唯一的实时边界/transcript(文本记录)流。需要渲染轮次、工具调用、工具结果、助手消息和持久化边界的消费方统一订阅 `session/event`,从持久化层使用的同一套事件词汇中派生 UI。 -移除 `agent/turn-start`、`agent/turn-end`、`agent/step-start` 和 `agent/step-end`。边界消费方改为订阅 `session/event`。如果 UI 需要 agent 标签,则通过 `agent/created` 和 `agent/disposed` 维护一份 session 到 agent 的映射,因为持久化的 `turn/start` 携带轮次编号但不携带 agent id。 +四个持久边界镜像——`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`——已从 agent(智能体)事件分类中移除。希望在边界处取得 agent handle 的 UI 会保留来自 `agent/created`/`agent/disposed` 的实时目标对象,并直接比较其 session;`dsh-ui-stdio` 据此为应用拥有的 agent 标记 `[main turn N]` 头部,其他 session 则渲染其持久 id。规范记录仍是事件溯源 session log。 -步骤镜像已无消费方,由 [event-domain-semantics RFC](../architecture/2026-06-30-event-domain-semantics.md) 先行移除。该决策保留了轮次镜像供 stdio UI 使用;本 RFC 在将测试 REPL 迁移到 `session/event` 加 id 映射之后,将轮次镜像也一并移除。 +step 镜像(完全没有消费者)最先在[事件域语义 Agent Note(agent 决策记录)](../architecture/2026-06-30-event-domain-semantics.md) 中移除;该 Agent Note 当时以 stdio UI 需要在 turn 边界取得 `Agent` handle 为由,保留了 turn 镜像。本 Agent Note 完成余下工作:`dsh-ui-stdio` 是可随时丢弃的测试 REPL,其渲染可以自由变化,因此“ui-stdio 需要它”并不是保留镜像的理由——它读取 `session/event`,只保留自己的实时目标对象。 ## 范围:移除什么、不移除什么 -本决策仅涉及持久化的轮次与步骤边界。`agent/steering` 镜像的是一条控制记录,`agent/stream-chunk` 镜像的是 token 流,因此各自单独处理:[steering](2026-07-04-remove-agent-steering-mirror.md) 与 [stream chunks](2026-07-02-remove-stream-chunk-mirror.md)。`agent/created`、`agent/disposed`、`agent/status`、`agent/error` 和 `agent/queued` 仍作为实时生命周期或控制事件保留,而非 transcript 镜像;排队中的输入可能在任何持久化事件产生之前就被取消。 +已移除(持久边界镜像——每项都以 session log 为权威):`agent/turn-start`、`agent/turn-end`、`agent/step-start`、`agent/step-end`。 + +保留——不是持久边界镜像,因此不在本决策范围内: + +- `agent/steering`——不是边界,因此不在本决策范围内(原始提案将其一并移除;在此会造成范围蔓延)。它镜像持久的 `steering/message` 控制记录,而非边界,后来由自己的后续决策移除:[移除 `agent/steering` 镜像 emit](2026-07-04-remove-agent-steering-mirror.md)。 +- `agent/stream-chunk`——实时 token 流。不在本决策范围内(它镜像持久的 `assistant/chunk`,而非边界),后来由自己的后续决策移除:[停止将 token 流镜像为 agent 事件](2026-07-02-remove-stream-chunk-mirror.md)。 +- `agent/created`、`agent/disposed`、`agent/status`、`agent/error`、`agent/queued`——不属于 transcript 数据的生命周期/控制事件。尤其是 `agent/queued`,它是在任何持久事件存在之前触发的 inbox 确认(取消的排队工作可能永远不会进入日志),所以有意只保留为实时事件。 ## 曾考虑的替代方案 -- **在同一个变更中一并移除 `agent/steering`**:否决,因为它是控制记录的镜像而非边界镜像。 -- **为 stdio UI 保留轮次镜像**:否决,因为 UI 可以渲染 `session/event` 并通过 id 映射恢复 agent 标签。 +- **将 `agent/steering` 一并移除**——原始提案的形状;作为范围蔓延被排除:它镜像持久的 `steering/message` 控制记录,而非边界,后来由[自己的决策](2026-07-04-remove-agent-steering-mirror.md)移除(`agent/stream-chunk` 也由 [stream chunk 镜像 Agent Note](2026-07-02-remove-stream-chunk-mirror.md) 移除)。 +- **为 stdio UI 保留 turn 镜像**——[事件域语义 Agent Note](../architecture/2026-06-30-event-domain-semantics.md) 的原始立场;在此否决,因为 `dsh-ui-stdio` 是可随时丢弃的测试 REPL,而非承载关键约束的消费者,并且它改为根据 `session/event` 加自己的实时目标对象渲染边界。 ## 后果 -插件不再能从便捷的 `Agent` 优先事件中观察轮次/步骤边界,必须订阅 `session/event` 或自行维护 session 到 agent 的关联。这是可接受的取舍:边界消费方不应依赖一条可能与持久化日志产生漂移的第二事件源。 +插件不能再从便捷的 `Agent` 优先事件观察 turn/step 边界。它需要订阅 `session/event`;如果需要实时对象,则通过 `ctx.agents` 解析共享 id,或保留自己已经拥有的对象。这是可以接受的取舍:边界消费者不应依赖可能与持久日志发生漂移的第二条事件 feed。 diff --git a/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml index 1c1c0eb757..f52f1e62c4 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.i18n.yaml @@ -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 -2026-06-20-unify-agent-and-session-id.md: 9cec898a2df9418b3533c776779c88fc50bc7dcb -2026-06-20-unify-agent-and-session-id.zh.md: 39e78db0b886d1e0b13afe2337697a184af478ed +2026-06-20-unify-agent-and-session-id.md: c55152f4f13fe0acb530503e84f465799007cff7 +2026-06-20-unify-agent-and-session-id.zh.md: 46e786a8f65b33e071fe689922ab396be90a184a diff --git a/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.md b/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.md index a8a2c375b5..c55152f4f1 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.md +++ b/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-20-unify-agent-and-session-id.zh.md) + ## Problem A live agent/session pair needs one identity for registry routing, event sourcing, and persistence. Giving the factory independent `agentId` and `sessionId` inputs would permit pairings no production path can use, while forcing every consumer to choose or translate between two names for the same lifecycle. diff --git a/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.zh.md b/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.zh.md index 39e78db0b8..46e786a8f6 100644 --- a/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-20-unify-agent-and-session-id.zh.md @@ -1,42 +1,40 @@ -# RFC: 统一 agent id 与 session id +# Agent Note: 统一 agent id 与 session id -Status: proposed +Status: implemented [English](2026-06-20-unify-agent-and-session-id.md) | 中文 ## 问题 -agent 工厂为每个活跃的 agent/session 对维护两个 id:`agentId`(`AgentRegistry` 的路由句柄)和 `sessionId`(事件溯源与持久化日志的标识)。`CreateAgentOptions` 接收两者;`ResumeAgentOptions` 接收 `agentId` 加 `resumeSessionId`;进程内 subagent 各自铸造两个独立的 UUID,尽管血缘关系另行记录。 +一个实时 agent(智能体)/session 对需要使用同一 identity 完成注册表路由、事件溯源和持久化。让 factory 接受相互独立的 `agentId` 和 `sessionId` 输入,会允许任何生产路径都无法使用的配对,同时迫使每个消费者为同一生命周期在两个名称之间选择或转换。 -ACP(Agent Client Protocol)已经对这两个标识使用同一个值。它们在配置创建的 agent(智能体)、恢复的会话和进程内子 agent 中才出现分歧,但没有任何生产路径会把一个活跃 agent 重新关联到多个会话,或让一个会话经过多个 agent id。Stdio 保留 `labelBySession` 仅仅是为了从会话事件中恢复 agent 标签,而钩子同时暴露两个值让使用者自行调和。 +ACP(Agent Client Protocol)对两种 identity 使用相同值。Stdio 和 hook 也在 session 事件流上工作,并且直接需要对应的实时 agent;没有生产路径会把一个实时 agent 对象重新附着到多个 session,或通过多个 agent id 驱动一个 session。 -[agent-scope 运行时](../../implemented/architecture/2026-07-12-agent-scope-runtime-design.md)没有与标识相关的保留状态:创建和恢复使用同一个 `AgentCreationTransaction`,两个注册表条目都使用相同的 final-entry 碰撞规则。分离的 id 并不会使活跃性、回滚或静默机制产生重复。统一后删除一个调用方提供的 id、每个进程内子 agent 的一个 UUID 以及剩余的转换路径,而不改变事务生命周期;同时使活跃 agent 注册表强制执行后台任务所有权所使用的会话标识。 +[agent 范围运行时](../architecture/2026-07-12-agent-scope-runtime-design.md)使用同一个 `AgentCreationTransaction` 执行创建和恢复,agent/session 条目共享相同的最终条目冲突规则。第二个 identity 并不代表单独的存活性、回滚或静止状态;它只会围绕同一事务增加 API 与转换状态。 -`Session` 另外同时暴露 `Session.id` 和 `Session.header.id`,尽管构造时要求二者必须一致。持久化边界必须校验这个重复值,消费方必须在同一事实的两个归属位置之间做选择。 +Session identity 同样只有一个归属,即 `Session.header.id`;`Session.id` 是派生访问器,而非需要重复验证的独立状态。 -## 提案 +## 决策 -对 agent 注册表条目和 `session.header.id` 使用同一个 id。`CreateAgentOptions` 为两个最终条目接收一个标识;恢复操作以被恢复的 session id 注册 agent;subagent 创建铸造一个合并后的 id;`Session` 只保留一个标识归属位置。保留当前的事务、final-entry 碰撞检查、exact-entry 摘除、回滚与静默机制;仅移除唯一职责是在两个 id 之间做转换的 map 和字段。 +agent 的注册表 id 等于其 session id。`CreateAgentOptions` 接受一个 `sessionId`,同时用于两个最终注册表条目;恢复时以 `resumeSessionId` 注册 agent;进程内 subagent 创建使用子 session id;`Session.id` 则派生自 `header.id`。远程 ACP 运行没有本地 agent/session 对:它保留一个由父项铸造的生命周期 id,而子服务器线协议内的 session id 仅用于 ACP 调用。现有创建事务、最终条目冲突检查和精确条目分离语义保持不变;唯一职责是在本地 id 之间转换的 map 与字段已经消失。 -配置驱动的路径必须先确定其恢复还是创建的策略。当前它使用一个稳定的 agent 标签加一个带 UUID 后缀的新 session id,以避免在下次运行时与已有的持久化日志碰撞。统一后,它必须明确选择:恢复一个固定 id、铸造一个新的合并 id,还是将该策略暴露出来;实现不得默默做出选择。 +配置驱动路径保留 `agents[].id` 作为稳定配置标签,而非实时路由 identity。普通的全新启动会铸造组合 id `${label}-session-${randomUUID()}`,使持久重启不会冲突。耦合应用可以预先铸造并传入精确的 `sessionId`:首次使用时创建它,而当持久化服务已经存在时,AgentLoop 重新挂载会在同一 identity 下恢复已物化历史。`resumeSessionId` 则要求已有的持久化 identity。两个精确 id 输入互斥。Stdio 使用“恢复或创建”形式,使配置创建的 agent 和 UI 在循环重载之间共享一个不透明 identity,而不是根据前缀猜测。日志可以使用稳定标签,而所有实时与持久查找都使用同一个 `SessionId`。 -`agent/created` 和 `agent/disposed` 不在本提案范围内。它们是发布生命周期事件而非标识别名;移除它们需要单独的生产方-消费方审计与决策。 +`agent/created` 和 `agent/disposed` 保留。它们是成对的发布生命周期事件,而非 identity 别名;以后若发现没有消费者并要移除,必须先重新搜索,再提出独立提案。 ## 曾考虑的替代方案 -**保留分离的路由标识与日志标识。** 一个稳定的配置 agent 标签配合一个新的对话,是这种区分的真实用途。如果确实需要该显示或路由标识,请否决本提案,转而显式强制 session id 唯一性,而不是把转换隐藏在另一个 map 中。 +**保持路由与日志 identity 分离。** 稳定的配置标签加全新的持久对话确实有用,但不需要两个实时 identity:标签可以继续作为配置/显示元数据,而每次运行的组合 `SessionId` 负责路由和持久化。保留两个 id 会让转换 map 持续存在,允许不可能的配对,却不会增加生命周期功能。 -## 验收标准 +## 验证 -- agent 创建/恢复与 subagent 创建只携带一个标识;`Session` 将其存储在一个位置。 -- 创建事务在不依赖标识相关生命周期状态的前提下,保留 final-entry 碰撞、exact-entry 摘除、回滚与静默保证。 -- ACP、stdio、钩子、bash 所有权、持久化与血缘关系无需进行 agent/session id 转换。 +- Agent 创建/恢复和 subagent 创建只携带一个 identity,`Session` 也只在一个位置存储它。 +- 创建事务继续覆盖最终条目冲突、精确条目分离、回滚和静止状态,无需 identity 特有的生命周期状态。 +- ACP、stdio、hook、bash 归属、持久化和 lineage 直接使用共享 `SessionId`。ACP subagent 后端在父命名空间中铸造其生命周期 id,因为子服务器返回的 session id 仅在服务器本地有效;ACP bridge 根据正向 session map 验证精确的 `Agent` 归属;JSON-RPC 只转发生命周期事件中由服务快照保存的 `local` 标记为 true 的事件,从带范围的事件 carrier 取得委托父项,并且不保留子 identity 或 lineage cache。 - 配置驱动的恢复还是创建策略是显式的,并在持久化重启场景下得到覆盖。 -- `agent/created` 和 `agent/disposed` 仅在单独的生产方-消费方审计之后才变更。 +- 生产监听器搜索确认保留 `agent/created`/`agent/disposed` 及其发布语义。 - 类型检查、覆盖率、快照、doc-sync、module-graph 校验、构建与 hygiene 全部通过。 -## 风险 +## 后果 -统一后将无法再拥有一个跨多个会话日志的稳定 actor 标识,包括未来可能出现的、在保留 actor 的同时切换会话的 handoff 或 fork 场景。重新引入该设计将需要一个新的显式 actor 标识。统一还使一个持久化的、可能由客户端选定的 session id 成为注册表句柄,并改变每个创建/恢复的调用点与 fixture(测试前置数据)。 - -配置重启策略是阻塞性的设计决策:固定的合并 id 可能与已有日志碰撞,而每次运行生成新 id 则放弃了稳定的配置标签。如果确实需要独立的 actor 标识或稳定标签/新会话的配对,请否决本提案,保留分离的 id 并加上显式的唯一性守卫。 +这排除了潜在的多 session actor 和 session 交接设计,并使由客户端选择、已持久化的 session identity 成为注册表 identity。如果独立路由 identity 成为真实需求,就需要显式的生命周期设计,而不是由调用方提供一对不受约束的值。 diff --git a/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml b/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml index f1fa61c3c2..cc7da6603e 100644 --- a/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.i18n.yaml @@ -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 -2026-06-26-fsspec-style-fs-seam.md: 7b5e61481eeca9556de58cf3d6f8fe935b2eefb5 -2026-06-26-fsspec-style-fs-seam.zh.md: 72d37c196df99d110ea59c5108dc9de084669c8b +2026-06-26-fsspec-style-fs-seam.md: d496f273e2635624e0ab8e70e06c8729563c5466 +2026-06-26-fsspec-style-fs-seam.zh.md: d6217e768fe4a11a7f6aacf8a17bb2e9e232a44d diff --git a/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md b/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md index 72d37c196d..d6217e768f 100644 --- a/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md +++ b/.agents/notes/implemented/simplification/2026-06-26-fsspec-style-fs-seam.zh.md @@ -1,4 +1,4 @@ -# RFC: 拆分文件系统 seam——提供方文本变更操作与 `dsh-fs-policy` 插件 +# Agent Note: 拆分文件系统 seam——提供方文本变更操作与 `dsh-fs-policy` 插件 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -[filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) 中引入的文件系统能力目前让一个抽象的 `FileSystem` 服务承担两类不同的职责: +[文件系统能力接缝](../architecture/2026-06-17-filesystem-capability-seam.md)中的文件系统能力目前让一个抽象 `FileSystem` 服务同时负责两项不同工作: 1. **提供方操作**——解析目标、stat/版本元数据、文本读取/流式读取、原子写入,以及受保护的字面编辑。 2. **面向 agent(智能体)的策略**——行窗口、字面编辑语义,以及读后写/编辑的观测状态。 @@ -15,7 +15,7 @@ Status: implemented 这还造成了一个真实的用户体验死胡同:窗口化读取记录 `view: partial`,而 partial 视图无法授权 `edit`。一个模型读取了大文件的第 100-150 行,如果想编辑第 120 行,就必须先获取一次 `full` 读取,而对于超过读取上限的文件这可能做不到。字面编辑实际上只需要新鲜度:被匹配的字节仍然来自模型所读取的那个版本即可。 -旧 RFC 已经推迟了独立的 `@deepseek-ai/dsh-fs-policy` 包(package)。本 RFC 构建该层,并让 `ctx.fs` 贴近 fsspec 风格的存储原语(`info`/`cat`/`open`),但不将其变成完整的 fsspec。 +旧 Agent Note(agent 决策记录)已经推迟了独立的 `@deepseek-ai/dsh-fs-policy` 包。本 Agent Note 构建该层,使 `ctx.fs` 保持接近 fsspec 风格的存储原语(`info`/`cat`/`open`),但不把它变成完整的 fsspec。 ## 决策 @@ -30,14 +30,14 @@ provider dsh-fs-local local implementation of ctx.fs `dsh-tool-fs` 保持相同的面向模型的 `read`/`write`/`edit` schema。它是执行器:注入 `fs`(不是策略服务)并直接访问 `ctx.fs`,拥有读取窗口化逻辑,并分发 `fs/*` 事件以便 `dsh-fs-policy` 进行门控和记录。 -本 RFC 决定了四层拆分、提供方契约和新鲜度策略。工具↔策略的耦合方式随后由[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 细化:`dsh-fs-policy` 是一个门控插件,通过 `fs/*` 事件参与而非提供 `ctx.fileContext` 方法服务,因此工具不与它产生方法耦合,读取窗口化与 fs I/O 留在 `dsh-tool-fs` 中。本文描述的是最终落地的事件门控形态;提供方的版本守卫是可选的(省略 = 无条件裸提供方)。 +本 Agent Note 决定了四层拆分、provider 契约和新鲜度策略。随后,[事件门禁 Agent Note](../architecture/2026-06-26-file-context-as-event-gate.md) 细化了工具↔策略耦合:`dsh-fs-policy` 是通过 `fs/*` 事件参与的门禁插件,而非 `ctx.fileContext` 方法服务,因此工具不会在方法层与其耦合;读取窗口和 fs I/O 位于 `dsh-tool-fs`。本文描述已经落地的事件门禁形状;provider 的版本守卫可选(省略即无条件裸 provider)。 ## 提供方契约 `@deepseek-ai/dsh-fs` 收缩为提供方文本 IO 加受保护的文本变更: ```ts ignore-check -abstract resolve(path: string): Promise<FsTarget> +abstract resolve(path: string, opts?: { cwd?: string; signal?: AbortSignal }): Promise<FsTarget> abstract stat(target: FsTarget, signal?: AbortSignal): Promise<FsInfo | undefined> abstract readText(target: FsTarget, signal?: AbortSignal): Promise<string> abstract streamText(target: FsTarget, signal?: AbortSignal): Promise<AsyncIterable<string>> @@ -65,11 +65,11 @@ type FsWriteIntent = 这是一个*文本存储* seam,刻意比字节级 fsspec(`cat`/`open` 返回原始字节)高半个层次。UTF-8 解码、二进制/NUL 拒绝、受保护的全文件写入和受保护的字面文本编辑都在提供方内完成,因此策略层从不接触原始字节、不重新实现跨分片解码、也不将陈旧检查与变更临界区分离。面向模型的概念仍然不下沉到提供方:行窗口、带行号的行、渲染的页脚、观测状态存储都不会泄漏下去。 -从 `dsh-fs` 中删除的内容:`readPage`、`FsExpectation`、`FsView`、`FsStateSource`、`FsReadRequest`、`FsTextLine`、行/窗口常量、`formatReadBody`,以及观测状态 `WeakMap`。`applyEdit` 被更窄的提供方原语 `editText` 取代,后者的契约是版本守卫的字面文本变更,而非策略层的读取授权。`FS_PARTIAL_OBSERVATION` 错误码也从 `FsErrorCode` 分类体系中移除:新鲜度授权没有 partial/full 之分,因此没有什么能触发它。`FsTargetKey` 和 `FsVersion` 按照既有的 [branded-ids RFC](../../implemented/architecture/2026-06-20-branded-ids.md) 成为品牌化的不透明 id。 +从 `dsh-fs` 删除:`readPage`、`FsExpectation`、`FsView`、`FsStateSource`、`FsReadRequest`、`FsTextLine`、行/窗口常量、`formatReadBody` 和 observed-state `WeakMap`。`applyEdit` 由更窄的 provider 原语 `editText` 取代,其契约是带版本守卫的字面文本变更,而非策略层读取授权。`FS_PARTIAL_OBSERVATION` code 也从 `FsErrorCode` 分类中移除:新鲜度授权没有部分/完整之分,因此没有任何路径会抛出它。`FsTargetKey` 和 `FsVersion` 按现有[品牌化 id Agent Note](../architecture/2026-06-20-branded-ids.md) 成为品牌化不透明 id。 ## 策略契约 -`@deepseek-ai/dsh-fs-policy` 是一个插件,不是服务:它不注册任何 `ctx.*` 键,也不注入任何东西。它拥有写入/编辑新鲜度策略和观测状态,这些不属于 `FileSystem` 提供方基类(否则沙箱/远程后端会继承它无需承载的面向模型的观测策略)。它通过执行器分发的 `fs/*` 事件门控贡献该策略。(本 RFC 最初提出了一个具体的 `ctx.fileContext` 方法服务,带有 `read`/`write`/`edit` 方法;[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 将其改造为此处描述的门控插件,使工具从不与策略产生方法耦合。) +`@deepseek-ai/dsh-fs-policy` 是插件,而非服务:它不注册任何 `ctx.*` 键,也不注入任何内容。它拥有不应位于 `FileSystem` provider 基类上的写入/编辑新鲜度策略和 observed state(否则 sandbox/远程后端会继承不该由其承载的面向模型观察策略)。它通过 executor 分派的 `fs/*` 事件门禁贡献该策略。(本 Agent Note 最初提议带有 `read`/`write`/`edit` 方法的具体 `ctx.fileContext` 服务;[事件门禁 Agent Note](../architecture/2026-06-26-file-context-as-event-gate.md) 将其细化为本文所述插件,使工具永远不会在方法层与策略耦合。) 观测状态以 `WeakMap<owner, Map<targetKey, FsVersion>>` 的形式存放于此。当且仅当 owner 读取、写入或编辑过该目标时,条目才存在(每次成功都会发出 `fs/observed`),因此条目的存在*本身就是*先前观测的记录——没有单独的 `hasRead` 标志。owner 从不透明的事件 actor(`{ agent?: { session? } }`)结构化派生,该形状定义在 `dsh-fs-policy` 中而非 `dsh-fs` 中。 @@ -99,7 +99,7 @@ type FsWriteIntent = ## 取代 -本 RFC 逆转了 [filesystem-capability-seam](../../implemented/architecture/2026-06-17-filesystem-capability-seam.md) 中的两项决策,并收窄了第三项: +本 Agent Note 推翻[文件系统能力接缝](../architecture/2026-06-17-filesystem-capability-seam.md)中的两项决策,并收窄第三项: - 读后写/编辑策略从 `ctx.fs` 移出,进入 `dsh-fs-policy` 插件(通过 `fs/*` 事件门控)。 - 文本读取不再返回后端编号的行记录或 `full`/`partial` 视图;授权基于版本新鲜度,因此窗口化读取在文件未变时即可授权编辑。 @@ -113,12 +113,12 @@ type FsWriteIntent = ## 后续扩展 -该 seam 后来由 [Add direct directory listing to the filesystem seam](../architecture/2026-07-03-filesystem-directory-listing-seam.md) 扩展了直接目录列表功能。该后续工作单独跟踪,以使本 RFC 的验收标准继续描述最初交付的 fsspec 风格重构。 +后来,[为文件系统接缝添加直接目录列表](../architecture/2026-07-03-filesystem-directory-listing-seam.md)进一步扩展了该接缝。该后续工作单独跟踪,使本 Agent Note 的验收标准继续描述最初落地的 fsspec 风格改造。 ## 曾考虑的替代方案 - **字节级 fsspec(`cat`/`open` 返回原始字节)**:否决。该 seam 刻意定位为文本存储,比字节级高半个层次,这样 UTF-8 解码、二进制/NUL 拒绝和受保护的文本变更只在提供方实现一次,策略层从不接触原始字节,也不将陈旧检查与变更临界区分离。 -- **具体的 `ctx.fileContext` 方法服务**:本 RFC 最初的策略形态;被[事件门控 RFC](../architecture/2026-06-26-file-context-as-event-gate.md) 改造为门控插件,使工具从不与策略产生方法耦合。 +- **具体的 `ctx.fileContext` 方法服务**——本 Agent Note 最初的策略形状;[事件门禁 Agent Note](../architecture/2026-06-26-file-context-as-event-gate.md) 将其重做为门禁插件,使工具永远不会在方法层与策略耦合。 - **在提供方保留 `readPage` 和 `full`/`partial` 视图授权**:「取代」一节所逆转的重构前形态。视图完整性不是编辑安全所需的,版本新鲜度才是;而视图规则使超过读取上限的大文件无法编辑。 ## 后果 diff --git a/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml index 99d356c3e8..6b26f18d77 100644 --- a/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.i18n.yaml @@ -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 -2026-07-02-remove-stream-chunk-mirror.md: 74843cf49c043d46d44266a7bb0d8c953a749b6f -2026-07-02-remove-stream-chunk-mirror.zh.md: 1b460b4600442535d2572770449ce4dbcc836fe8 +2026-07-02-remove-stream-chunk-mirror.md: 5dd816940a4b2c2b63980e01f1bd4e0aac53a3e2 +2026-07-02-remove-stream-chunk-mirror.zh.md: d4bfe540ecb3f938721f2b387f302caf163b0f94 diff --git a/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md b/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md index 1b460b4600..d4bfe540ec 100644 --- a/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-02-remove-stream-chunk-mirror.zh.md @@ -1,4 +1,4 @@ -# RFC: 停止将 token 流镜像为 agent 事件 +# Agent Note: 停止将 token 流镜像为 agent 事件 Status: implemented @@ -19,7 +19,7 @@ ctx.emit('agent/stream-chunk', agent, turn, step, chunk) // ← the mirror 实时发射相比会话事件唯一多出的东西是实时的 `Agent` 句柄,而唯一的消费方直接丢弃了它(其处理函数签名为 `(_agent, _turn, _step, chunk)`)。 -这与[边界镜像移除](2026-06-20-remove-agent-boundary-mirror-events.md)为 turn/step 边界消除的重复如出一辙:消费方对同一个持久事实有两个真源,每次变更都要同时修改两处。那份 RFC 将 chunk 流推迟处理(「`assistant/chunk` 的持久化仍然是承重的,因此 chunk 流后续可以作为镜像来评估,但那是一个独立决策」),而非一并纳入。本 RFC 即是那个独立决策。 +这与[移除边界镜像](2026-06-20-remove-agent-boundary-mirror-events.md)为 turn/step 边界消除的重复相同:消费者面对同一持久事实的两个事实来源,每次变更都必须同时触及两者。该 Agent Note(agent 决策记录)没有把 chunk 流一并纳入,而是推迟处理(“`assistant/chunk` 持久化仍承载关键约束,所以以后可以将 chunk 流作为镜像评估,但那是一项独立决策”)。本 Agent Note 就是那项独立决策。 推迟所依赖的前提已经明确:chunk 持久化是权威的,且将保留。停止持久化 chunk、仅保留瞬态实时流事件的提案已被[否决](../../rejected/simplification/2026-06-20-assembled-assistant-messages-only.md)——高保真回放、部分失败的流以及快照回放都依赖持久化的 `assistant/chunk` 序列。因此 `session/event` 上的 `assistant/chunk` 是持久的、承重的 token 流,而 `agent/stream-chunk` 是它的纯冗余镜像。 @@ -27,15 +27,15 @@ ctx.emit('agent/stream-chunk', agent, turn, step, chunk) // ← the mirror 从 agent 事件分类体系中移除 `agent/stream-chunk`。token 流通过 `session/event` 以 `assistant/chunk` 的形式读取——持久化与回放已经使用的正是同一个序列。`session/event` 是唯一的实时 transcript(文本记录)流(assistant chunk、turn/step 边界、工具活动、todo)。 -**消费方。** 唯一重要的生产消费方——ACP 桥接(`dsh-acp`,面向编辑器的真实流式输出接口)——已经从 `session/event` 渲染 `assistant/chunk`,从未使用 `agent/stream-chunk`,因此不受影响。stdio UI(`dsh-ui-stdio`,一个一次性的测试 REPL)是唯一的实时消费方;它在边界迁移时已经有了 `session/event` 监听器,因此其 chunk 渲染被折叠进该监听器作为 `assistant/chunk` 分支。合并为一个监听器还消除了一个潜在隐患:`inReasoning` dim-SGR 标志此前在两个独立监听器(`agent/stream-chunk` 和 `session/event`)之间共享,chunk 与边界在该标志上竞争时没有确定的顺序;单一监听器按追加顺序处理,使交错变为确定性的。 +**消费方。** 唯一重要的生产消费方——ACP(Agent Client Protocol)桥接(`dsh-acp`,面向编辑器的真实流式输出接口)——已经从 `session/event` 渲染 `assistant/chunk`,从未使用 `agent/stream-chunk`,因此不受影响。stdio UI(`dsh-ui-stdio`,一个一次性的测试 REPL)是唯一的实时消费方;它在边界迁移时已经有了 `session/event` 监听器,因此其 chunk 渲染被折叠进该监听器作为 `assistant/chunk` 分支。合并为一个监听器还消除了一个潜在隐患:`inReasoning` dim-SGR 标志此前在两个独立监听器(`agent/stream-chunk` 和 `session/event`)之间共享,chunk 与边界在该标志上竞争时没有确定的顺序;单一监听器按追加顺序处理,使交错变为确定性的。 ## 范围 移除:`agent/stream-chunk`。 未触及: -- `assistant/chunk`(持久会话事件)——权威的 token 流,原样保留。本 RFC 移除的是实时镜像,而非持久化(持久化移除提案已被单独否决,见上文)。 -- `agent/steering`——本决策未触及(它是控制信号,不是 token 流)。其持久孪生事件是 `steering/message`,镜像发射由其自身的后续 RFC 移除:[移除 `agent/steering` 镜像发射](2026-07-04-remove-agent-steering-mirror.md)。 +- `assistant/chunk`(持久 session 事件)——权威 token 流,原样保留。本 Agent Note 移除的是实时镜像,而非持久化(移除持久化的提案已单独遭到拒绝——见上文)。 +- `agent/steering`——本决策未触及(它是控制信号,不是 token 流)。其持久孪生事件是 `steering/message`,镜像发射由其自身的后续 Agent Note 移除:[移除 `agent/steering` 镜像发射](2026-07-04-remove-agent-steering-mirror.md)。 - `agent/status`、`agent/error`、`agent/created`/`agent/disposed`、`agent/queued`、`agent/session-start`——生命周期/控制事件,不是 transcript 数据,也没有持久副本。 ## 曾考虑的替代方案 @@ -44,4 +44,4 @@ ctx.emit('agent/stream-chunk', agent, turn, step, chunk) // ← the mirror ## 后果 -插件不再能通过以 `Agent` 为首参的事件观察 token delta。它需要订阅 `session/event` 并过滤 `assistant/chunk`(如需 `Agent` 句柄,可通过 `agent/created`/`agent/disposed` 构建的 session-id→agent 映射恢复,与边界消费方已有的做法完全一致)。没有任何生产消费方在 chunk 时需要实时的 `Agent`;这与边界镜像移除所做的权衡相同,是可接受的。 +插件不能再从 `Agent` 优先事件观察 token 增量。它需要订阅 `session/event`、过滤 `assistant/chunk`,并在需要时通过 `ctx.agents.get(session.id)` 直接查找对应的实时 handle。没有生产消费者需要在 chunk 时刻取得实时 `Agent`;这与移除边界镜像所作的取舍相同,均可接受。 diff --git a/.agents/notes/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml index 8a31f5ee11..cf67ddfcd5 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-drop-image-content-block.i18n.yaml @@ -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 -2026-07-04-drop-image-content-block.md: 145f805cbe335d3b8275bef6a2bb1fcbe1bd3df3 -2026-07-04-drop-image-content-block.zh.md: ba77caeba4cb1fdd3ff95f4cd498c87cdf1aa227 +2026-07-04-drop-image-content-block.md: 566803ab5b9f213b7dc87fcf779ed7a963d988fd +2026-07-04-drop-image-content-block.zh.md: 27282bbf8768cafaf3fff696559b81756af5a45e diff --git a/.agents/notes/implemented/simplification/2026-07-04-drop-image-content-block.zh.md b/.agents/notes/implemented/simplification/2026-07-04-drop-image-content-block.zh.md index ba77caeba4..27282bbf87 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-drop-image-content-block.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-drop-image-content-block.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除 `image` 内容块,直到有路径能真正处理它 +# Agent Note: 移除 `image` 内容块,直到有路径能真正处理它 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -`ImageBlock`(`packages/llm/llm/src/types.ts`)没有任何生产环境的生产者,而每条路径上的每个消费方都将其丢弃:deepseek 适配器的序列化器跳过 image 块(这是文档中注明的 MVP 限制);pi-ai 转换器因无法表示而跳过;ACP 编解码器既不宣告 image prompt 能力、也不向外转发 image 块,并且会拒绝入站的 image prompt 内容;压缩(compaction)估算器对其收取一个固定 token 常量并渲染为 `[image]`。此时构造的 `ImageBlock` 会在协议格式(wire format)上静默消失——词汇宣告了一种没有任何路径兑现的能力,这正是 AGENTS.md 防御性模式所警告的静默数据丢失形态。唯一的构造调用出现在测试中,用于覆盖 skip/drop/estimate 分支。 +`ImageBlock`(`packages/llm/llm/src/types.ts`)没有任何生产环境的生产者,而每条路径上的每个消费方都将其丢弃:deepseek 适配器的序列化器跳过 image 块(这是文档中注明的 MVP 限制);pi-ai 转换器因无法表示而跳过;ACP(Agent Client Protocol)编解码器既不宣告 image prompt 能力、也不向外转发 image 块,并且会拒绝入站的 image prompt 内容;压缩(compaction)估算器对其收取一个固定 token 常量并渲染为 `[image]`。此时构造的 `ImageBlock` 会在协议格式(wire format)上静默消失——词汇宣告了一种没有任何路径兑现的能力,这正是 AGENTS.md 防御性模式所警告的静默数据丢失形态。唯一的构造调用出现在测试中,用于覆盖 skip/drop/estimate 分支。 ## 决策 @@ -22,7 +22,7 @@ Status: implemented ## 验证 -RFC 记录之外没有任何地方构造 harness 的 `ImageBlock`。ACP 独立的入站 image 拒绝仍有测试覆盖,适配器、编解码器和压缩的默认分支则通过插件定义的块类型来覆盖。 +除 Agent Note(agent 决策记录)之外,没有任何地方构造 harness `ImageBlock`。ACP 独立的入站图像拒绝路径仍有测试;adapter、codec 和压缩的默认分支则使用插件定义的块类型覆盖。 ## 后果 diff --git a/.agents/notes/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml index 429e5ae268..f55ba68808 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-drop-inert-request-knobs.i18n.yaml @@ -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 -2026-07-04-drop-inert-request-knobs.md: 86d0dfefe1bdfb0c49b5b9080935441d16dd2223 -2026-07-04-drop-inert-request-knobs.zh.md: f7d969378af7e070ecee82e8ea1a569c61208208 +2026-07-04-drop-inert-request-knobs.md: 06fa6c1c539f9ff0cfabf76bc41c53800bd46c8c +2026-07-04-drop-inert-request-knobs.zh.md: 69a8b0ca498f9fe11df5eb1f3207d88f66a7b70b diff --git a/.agents/notes/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md b/.agents/notes/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md index f7d969378a..69a8b0ca49 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-drop-inert-request-knobs.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除 `GenerateOptions.prefill` 与 `ToolSchema.strict`——无端到端可用路径的请求旋钮 +# Agent Note: 移除 `GenerateOptions.prefill` 与 `ToolSchema.strict`——无端到端可用路径的请求旋钮 Status: implemented @@ -15,10 +15,10 @@ Status: implemented ## 决策 -- 从 `GenerateOptions` 中移除 `prefill`,同时移除两个适配器的 UNSUPPORTED 守卫、固定这些 throw 的测试、[core.md](../../../core-data-structures/core.md) 中的粘贴行,以及适配器 README 中记录拒绝行为的行。实操手册(cookbook)中的 UNSUPPORTED 指引([adding-an-llm-adapter.md](../../../cookbook/adding-an-llm-adapter.md))改为泛化表述——你的 provider 无法兑现的 `GenerateOptions` 字段应抛出 `LlmError(..., 'UNSUPPORTED')`——而不再以 prefill 为例。[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的后果部分将 prefill 记录为「受 producer 门控」而非「已有归属」,依据 [implemented/AGENTS.md](../AGENTS.md)。 +- 从 `GenerateOptions` 中移除 `prefill`,同时移除两个 adapter 的 UNSUPPORTED 守卫、固定抛错行为的测试、[core.md](../../../../docs/core-data-structures/core.md) 中的粘贴行,以及记录该拒绝行为的 adapter README 表格行。cookbook 中的 UNSUPPORTED 指导([adding-an-llm-adapter.md](../../../../docs/cookbook/adding-an-llm-adapter.md))改为通用表述规则——provider 无法遵守的 `GenerateOptions` 字段应抛出 `LlmError(..., 'UNSUPPORTED')`——而不再以 prefill 为例。[内容块词汇 Agent Note(agent 决策记录)](../architecture/2026-06-11-content-block-vocabulary.md)的后果按照 [implemented/AGENTS.md](../AGENTS.md),将 prefill 记录为由生产者门控,而不是已有归属。 - 从 `ToolSchema`、`DefineToolOptions`、`defineTool`、`schemas()` 允许列表、deepseek 序列化分支及其 wire-type 字段,以及 tool-catalog 渲染器的 `Strict:` 行中移除 `strict`。pi-ai 的 payload 修补逻辑简化为对 pi-ai 自身逐工具 strict 默认值的无条件清除(pi-ai 在每个序列化的工具上打 `strict: false`;手写的孪生适配器不发送此字段,因此清除逻辑为保持协议格式对等而保留,由其序列化器测试固定)。setter 测试和 core.md 粘贴行已移除;`GenerateOptions` 与 `ToolSchema` 在 `scripts/type-equiv.manifest.json` 中保留各自的行,因为两个类型只是少了一个字段,本身仍然存在。 -本 RFC 有意不触碰 `temperature`、`stop` 或 `maxTokens`:它们在两个适配器中都被端到端地兑现,是 `agent/request` 上请求变更钩子插件的自然首选目标。 +本 Agent Note 刻意不触及 `temperature`、`stop` 或 `maxTokens`:两个 adapter 都会端到端遵守它们,而且它们自然是 `agent/request` 上修改请求的 hook 插件首批目标。 ## 曾考虑的替代方案 @@ -28,7 +28,7 @@ Status: implemented ## 验证 -`rg prefill` 仅返回 RFC 记录(本 RFC 与[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 中 producer-gated 的后果);在 tool-schema 范围内执行 `rg strict` 仅返回本 RFC、保留的 pi-ai 清除逻辑,以及 `strictEqual` 等无关文本。两个适配器的契约测试在移除守卫后通过,pi-ai 修补逻辑仍然清除库的 strict 默认值——协议格式对等由其序列化器测试固定。 +`rg prefill` 只返回 Agent Note 记录(本文及[内容块词汇 Agent Note](../architecture/2026-06-11-content-block-vocabulary.md)中由生产者门控的后果);限定在工具 schema 范围内的 `rg strict` 只返回本 Agent Note、保留下来的 pi-ai 清理逻辑,以及 `strictEqual` 等无关正文。两个 adapter 的契约测试都能在没有守卫的情况下通过,pi-ai 修正仍会清理库的 strict 默认值——其 serializer 测试固定了线协议一致性。 ## 后果 diff --git a/.agents/notes/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml index d86354d68a..5344a28971 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.i18n.yaml @@ -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 -2026-07-04-drop-unconsumed-web-observation-surface.md: ba97076eef385cd218517f233ed44f86d3f7eb7a -2026-07-04-drop-unconsumed-web-observation-surface.zh.md: 83c2e786d4edde7b7c94cf2c028b14e20da842b4 +2026-07-04-drop-unconsumed-web-observation-surface.md: 5b1cb1307c63ef7c298200ee1655119026b9ebf5 +2026-07-04-drop-unconsumed-web-observation-surface.zh.md: a48e74eeb0f718c3511e2b1ad8e2dcde635350e1 diff --git a/.agents/notes/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md b/.agents/notes/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md index 83c2e786d4..a48e74eeb0 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除未被消费的 web 观测接口——`providers-change` 事件与 status 方法 +# Agent Note: 移除未被消费的 web 观测接口——`providers-change` 事件与 status 方法 Status: implemented @@ -9,11 +9,11 @@ Status: implemented `WebService` 暴露了一组没有任何生产代码观测的观测接口: - **`web/providers-change`**(`packages/web/web/src/index.ts`)在每次 provider 注册和 dispose(资源释放)时声明并发出,且每个注册 effect 的回滚 yield 被刻意排在 emit 之前,唯一目的是让抛出异常的 change listener 能回退注册。在该包自身的两个单元测试之外没有任何 listener(其中一个测试的存在仅仅是为了固定那个回滚顺序)。 -- **`searchStatus()` / `fetchStatus()` 与 `WebCapabilityStatus` 联合类型**(同一个包)没有任何生产调用方:`dsh-tool-web` 通过 `ctx.web.search()`/`fetch()` 直接执行,并将不可用性表现为 seam 在执行时抛出的结构化 `WebError` 错误码(`packages/web/tool-web/src/search.ts`、`packages/web/tool-web/src/fetch.ts`);唯一的 status 调用方是 web 包自身的测试。`packages/web/tool-web/README.md` 和 [architecture.md](../../../architecture.md) 中的行文声称该工具「只读取聚合的 `searchStatus()`/`fetchStatus()`」——这是一处漂移,仅因没有机制检查行文与调用点的一致性而幸存。 +- **`searchStatus()` / `fetchStatus()` 与 `WebCapabilityStatus` 联合类型**(同一包)没有生产调用方:`dsh-tool-web` 直接通过 `ctx.web.search()`/`fetch()` 执行,并把不可用性呈现为接缝在执行时抛出的结构化 `WebError` code(`packages/web/tool-web/src/search.ts`、`packages/web/tool-web/src/fetch.ts`);唯一的 status 调用方是 web 包自己的测试。`packages/web/tool-web/README.md` 和 [architecture.md](../../../../docs/architecture.md) 中的正文声称工具“只读取聚合的 `searchStatus()`/`fetchStatus()`”——这种漂移之所以存续,只是因为没有机制对照调用位置检查正文。 seam 自身的设计使这两个接口天然没有消费方:工具注册跟随产品 ENABLEMENT 而非 provider 可用性(`packages/web/tool-web/src/index.ts`),provider 选择在执行时解析且从不缓存——因此没有需要失效的缓存、没有需要重算的注册集合、也没有调用方需要一个有别于「执行并路由结构化错误」的可用性探测。HMR(热模块替换)清理由 effect disposer 自身承载。 -这与 [移除未被消费的 `llm/adapter-change` 事件](../../implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md) 如出一辙:那个 RFC 从 `LlmService` 中移除了相同的通知形态、相同的 rollback-before-emit 机制和相同的 listener-throw 测试。该 RFC 的保留/裁剪判据——为 `tools/change` 保留其合理的面向用户的工具列表消费方,裁剪启动时的后端注册表信号——将 web provider 注册表明确归入裁剪一侧;status 方法是同一判断应用于 pull 接口而非 push 接口。 +这与[删除无人消费的 `llm/adapter-change` 事件](2026-06-20-drop-unconsumed-llm-adapter-change-event.md)相呼应;后者从 `LlmService` 移除了相同的通知形状、相同的 emit 前回滚机制和相同的监听器抛错测试。该 Agent Note(agent 决策记录)的保留/删除标准是:为可能面向用户的工具列表消费者保留 `tools/change`,删除启动时后端注册表信号。按这一标准,web provider 注册表明确属于删除一侧;status 方法则是把同一判断应用于拉取表面,而非推送表面。 ## 决策 @@ -23,11 +23,11 @@ seam 自身的设计使这两个接口天然没有消费方:工具注册跟随 ### 为什么不保留? -web seam RFC 有意指定了两者——事件作为最小的 HMR 可见性信号,status 方法作为工具的聚合诊断——且未来的 provider 状态面板是可以想象的。但同一 RFC 的其他设计选择使它们失去了消费方:按需派生的选择与基于 enablement 的注册使得没有消费方能需要这两者;已交付的工具展示了真实模式(执行并路由结构化错误);漂移的 README 语句表明承诺的消费方从未实现。按 AGENTS.md「RFC 是提案,不是金科玉律」的原则,这些是该提案中代码已证明过度设计的部分;未来的观测者按其实际消费的需求重新引入最小的信号或查询,由该消费方塑造其形态。 +web 接缝 Agent Note 刻意规定了两者——事件作为最小 HMR 可见性信号,status 方法作为工具的聚合诊断——未来也可以设想 provider 状态面板。但同一 Agent Note 的其他选择让它们失去了生存条件:调用时派生选择和基于启用状态的注册,使任何消费者都不可能需要其中任一项;已发布工具展示了真实模式(执行并路由结构化错误);发生漂移的 README 句子则表明承诺中的消费者从未出现。按照 AGENTS.md 所述“Agent Note 是提案,而非绝对真理”,代码后来证明提案中的这些部分超出了需要;未来的观察者应根据真实消费者的形状,重新引入它实际消费的最小信号或查询。 ## 验证 -在 RFC 历史之外不再有 `providers-change`、`searchStatus`、`fetchStatus` 或 `WebCapabilityStatus` 的拼写残留;catalog 是最新的(`verify-cordis-catalog` 绿色);注册/释放的 HMR 安全测试通过执行行为证明清理正确;tool-web README 与 architecture 段落描述了工具实际拥有的执行时错误路由契约。 +除 Agent Note 历史外,不再存在 `providers-change`、`searchStatus`、`fetchStatus` 或 `WebCapabilityStatus` 拼写;目录保持新鲜(`verify-cordis-catalog` 为绿色);注册/释放 HMR 安全性测试通过执行行为证明清理;tool-web README 和架构段落也描述了工具实际拥有的执行时错误路由契约。 ## 后果 diff --git a/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml index a43d663e93..b2361b71d4 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.i18n.yaml @@ -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 -2026-07-04-fold-stdio-ui-helper.md: ab42f1d131f6c657edf078d953c646b7970e9782 -2026-07-04-fold-stdio-ui-helper.zh.md: 2ad6abf3d5fb5ae6cdd852f8b5ec7e061e62b8ed +2026-07-04-fold-stdio-ui-helper.md: 01165df19942e8e0adf84ede3a371f53ad12e464 +2026-07-04-fold-stdio-ui-helper.zh.md: 5efaf47694092b4ba02208330dccf6b9bb086fca diff --git a/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md b/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md index b05dd22357..01165df199 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md +++ b/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-07-04-fold-stdio-ui-helper.zh.md) + The later [redundant-agent removal](2026-07-20-remove-stdio-and-echo-agents.md) supersedes this package-placement decision and removes the folded package, app, and line-oriented surface entirely. ## Problem diff --git a/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md b/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md index 2ad6abf3d5..5efaf47694 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.zh.md @@ -1,9 +1,11 @@ -# RFC: 将 stdio UI 辅助模块折入 stdio 应用 +# Agent Note: 将 stdio UI 辅助模块折入 stdio 应用 Status: implemented [English](2026-07-04-fold-stdio-ui-helper.md) | 中文 +后来的[冗余 agent(智能体)移除](2026-07-20-remove-stdio-and-echo-agents.md)取代了这项包放置决策,并完整移除合并后的包、应用和面向行的表面。 + ## 问题 readline UI 曾是一个完整的包(`packages/support/` 下的 `@deepseek-ai/dsh-ui-stdio`),其唯一的运行时导入方是应用包 `@deepseek-ai/dsh-stdio-demo`。示例通过加载应用来使用 readline UI,从不自行组合该辅助模块;仓库中所有其他引用都是因为包边界存在而存在的机械性或描述性表面:manifest(元数据清单)与 tsconfig 条目、生成的 module-graph 行、依赖图与 README 行,以及命名该包的文档注释。ui 组 README 记录了 support 放置的理由("主要为示例和覆盖率门禁而存在,`ui/` 保留给作为产品交付的界面"),这留下了一个持续的张力:一个已交付的产品应用依赖一个被明确标注为非产品表面的 support 包。 @@ -12,15 +14,15 @@ readline UI 曾是一个完整的包(`packages/support/` 下的 `@deepseek-ai/ ## 决策 -该辅助模块作为终端通道插件存放在 `@deepseek-ai/dsh-stdio` 中(`packages/ui/stdio/src/index.ts`):`createStdioChat`、其 `StdioRuntime` 测试 seam 及单元测试(`packages/ui/stdio/tests/stdio.spec.ts`、`readline.spec.ts`)一并迁入,因此 EOF 处理、渲染、dispose(资源释放)以及管道/TTY 行为在按文件覆盖率门禁下仍有单元测试覆盖,且无需劫持进程全局对象。该模块保留具名的 `name`/`inject`/`Config`/`apply` 导出形状——即应用的 `ctx.plugin(uiStdio, …)` 挂载所消费的契约——而 `examples/echo-agent` 与 `examples/coding-agent` 中的 keyless Loader 路径冒烟测试继续证明组合树能通过真实 Loader 启动(stdio 包的插件形状单元测试套件固定了显式的 `unwrapExports` 断言,因为缺少 `inject` 的 bundle 会跳过一个意外的 default 导出而不是崩溃)。 +当时,该辅助函数移入 `@deepseek-ai/dsh-stdio`,成为终端通道插件。`createStdioChat`、其 `StdioRuntime` 测试接缝和单元测试随之一同迁移,使 EOF 处理、渲染、释放以及管道/TTY 行为继续受逐文件覆盖率门禁约束,而不会劫持进程全局量。该模块保留应用挂载所消费的具名 `name`/`inject`/`Config`/`apply` 导出形状;当时的 Echo 和 REPL Loader 冒烟证明组合树,插件形状套件则固定显式 `unwrapExports` 行为。上方取代本文的移除记录负责当前包和示例状态。 -`packages/support/ui-stdio` 包已移除:manifest、tsconfig 引用、module-graph 行与 README 行均已删除;曾命名该包的文档注释(示例 e2e 模块文档、`packages/README.md`、support 与 todo README、[ui 组 README](../../../../packages/ui/README.md))现在描述的是包内模块。 +早期的支持辅助包已移除:其清单、tsconfig 引用、模块图行和 README 行均已消失,其余文档改为描述包内模块。 ## 曾考虑的替代方案 ### 为什么不将其提升到 `ui/` 而是折入? -提升可以解决 support 与 product 之间的错位,同时保留边界——只有在 readline UI 是一个可独立替换的集成或有第二个组合方时才是正确选择,而消费方普查表明两者皆非。结构化的 ACP 桥接保留为独立包,因为它是具有自身契约和快照层级的产品协议表面;readline 辅助模块只是一个应用前门的脚手架。在发布前重新拆分成本很低:如果将来有第二个产品应用需要 readline UI,届时再拆出来,由那个消费方来塑造包契约。 +提升可以解决 support 与 product 之间的错位,同时保留边界——只有在 readline UI 是一个可独立替换的集成或有第二个组合方时才是正确选择,而消费方普查表明两者皆非。结构化的 ACP(Agent Client Protocol)桥接保留为独立包,因为它是具有自身契约和快照层级的产品协议表面;readline 辅助模块只是一个应用前门的脚手架。在发布前重新拆分成本很低:如果将来有第二个产品应用需要 readline UI,届时再拆出来,由那个消费方来塑造包契约。 ## 后果 diff --git a/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml index 1d12fb892b..1c00f9b991 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.i18n.yaml @@ -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 -2026-07-04-prune-producerless-vocabulary-variants.md: f1b80e35b9004e40fb0ffdd08310310848912d09 -2026-07-04-prune-producerless-vocabulary-variants.zh.md: 9e7b55256ba5bda0474fd9056eea9a96beaf8096 +2026-07-04-prune-producerless-vocabulary-variants.md: 34492e6906cd2d795f880310b1bcd120e3953fcf +2026-07-04-prune-producerless-vocabulary-variants.zh.md: 710f64d7e848bcabb8a1bc0c0c8be9af7b2ca1b0 diff --git a/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md b/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md index aa61e859d2..34492e6906 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md +++ b/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-07-04-prune-producerless-vocabulary-variants.zh.md) + ## Problem The merge-extensible vocabulary maps are designed to grow by declaration merging, and the codebase already states the admission policy on `TurnEndReasonMap` (`packages/core/session/src/types.ts`): a variant like `refusal` is "deliberately omitted until" an adapter or loop first emits it. Three declared vocabulary items violated that policy — each had no producer and no consumer, and two had not even a test: diff --git a/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md b/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md index 9e7b55256b..710f64d7e8 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-prune-producerless-vocabulary-variants.zh.md @@ -1,4 +1,4 @@ -# RFC: 裁剪无生产者的词汇变体(块缓存提示、`agent` 消息来源、`continuation` 轮次触发器) +# Agent Note: 裁剪无生产者的词汇变体(块缓存提示、`agent` 消息来源、`continuation` 轮次触发器) Status: implemented @@ -8,13 +8,13 @@ Status: implemented 可合并扩展的词汇映射表设计上通过声明合并来增长,代码库已在 `TurnEndReasonMap`(`packages/core/session/src/types.ts`)上明确了准入策略:像 `refusal` 这样的变体「在适配器或循环首次发出它之前,有意不纳入」。三个已声明的词汇项违反了该策略——每个都既无生产者也无消费方,其中两个甚至没有测试: -- **`CacheHint` 及其 `cache?: CacheHint` 块字段**,位于 `TextBlock`/`ToolResultBlock`(`packages/llm/llm/src/types.ts`;image block 上还有第三个同类字段,已随 image block 一起移除——见[移除 image block 的 RFC](2026-07-04-drop-image-content-block.md))。没有任何地方构造过带 `cache:` 的块——src、测试和文档粘贴全部搜索为空——两个适配器也都不读 `.cache`:DeepSeek 的 prompt 缓存是自动的,适配器只从响应中映射出 `prompt_cache_hit_tokens`,从不向请求中发送提示。这是 Anthropic 风格的 `cache_control` 接口面,却没有能兑现它的提供方。 +- **`TextBlock`/`ToolResultBlock` 上的 `CacheHint` 及其 `cache?: CacheHint` 块字段**(`packages/llm/llm/src/types.ts`;图像块曾有第三个此类字段,已随图像块一同移除——参见[删除图像 Agent Note(agent 决策记录)](2026-07-04-drop-image-content-block.md))。任何地方都没有构造带 `cache:` 的块——src、测试和文档粘贴均为空——两个 adapter 也都不读取 `.cache`:DeepSeek prompt caching 是自动的,因此 adapter 会从响应中映射出 `prompt_cache_hit_tokens`,却从不向请求中发送 hint。这是没有任何 provider 能够遵守的 Anthropic 风格 `cache_control` 表面。 - **`MessageSourceMap.agent`**(`{ kind: 'agent'; agentId: string }`,同一文件)。零个构造点,包括测试在内。它预期的生产者在实现时并未使用它:subagent 后端将父级的 prompt 发送给子级时不带 `source`,因此记录为 `{ kind: 'user' }`,通用信封渲染器在插值 `source.kind` 时也从未对其做路由。 -- **`TurnTriggerMap.continuation`**(`packages/core/session/src/types.ts`)。agent loop(智能体循环)在结构上不可能发出它——continuation 发生在一个轮次*内部*作为后续步骤,而非作为新轮次——循环只构造 `message` 和 `injection` 触发器。唯一的写入者是一个手工构建的测试 fixture(测试前置数据),它只需要一个任意的非 message 触发器(`packages/support/llm-replay/tests/llm-replay.spec.ts`),`injection` 触发器同样满足需求;唯一的生产环境触发器读取方 ACP 桥接层只过滤 `kind === 'message'`。 +- **`TurnTriggerMap.continuation`**(`packages/core/session/src/types.ts`)。agent loop(智能体循环)在结构上不可能发出它——continuation 发生在一个轮次*内部*作为后续步骤,而非作为新轮次——循环只构造 `message` 和 `injection` 触发器。唯一的写入者是一个手工构建的测试 fixture(测试前置数据),它只需要一个任意的非 message 触发器(`packages/support/llm-replay/tests/llm-replay.spec.ts`),`injection` 触发器同样满足需求;唯一的生产环境触发器读取方 ACP(Agent Client Protocol)桥接层只过滤 `kind === 'message'`。 ## 决策 -删除 `CacheHint`、其 `cache?` 块字段、`agent` 消息来源变体与 `continuation` 轮次触发器变体:发布的词汇表不再包含它们。llm-replay fixture 改用 `injection` 触发器(任何非 `message` 触发器均满足其用途)。[core.md](../../../core-data-structures/core.md) 和 [session.md](../../../core-data-structures/session.md) 中的 type-equiv 粘贴与裁剪后的映射表一致——两个符号保留在 `scripts/type-equiv.manifest.json` 中,因为每个映射表本身仍然存在,只是少了一个成员——[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 的后果部分将缓存提示记录为「受生产者门控」而非「已有归属」,依照 [implemented/AGENTS.md](../AGENTS.md)。 +`CacheHint`、其 `cache?` 块字段、`agent` 消息来源变体和 `continuation` turn 触发器变体均已删除:已发布词汇不再携带它们。llm-replay fixture 使用 `injection` 触发器(任何非 `message` 触发器都能满足其用途)。[core.md](../../../../docs/core-data-structures/core.md) 和 [session.md](../../../../docs/core-data-structures/session.md) 中的 type-equiv 粘贴与裁剪后的 map 匹配——两个符号仍保留在 `scripts/type-equiv.manifest.json` 中的行,因为每个 map 都只是少了一个成员而继续存在——并且[内容块词汇 Agent Note](../architecture/2026-06-11-content-block-vocabulary.md)的后果按照 [implemented/AGENTS.md](../AGENTS.md),将 cache hint 记录为由生产者门控,而不是已有归属。 每个变体在获得真正的生产者之日回归,这正是映射表设计的增长方式:缓存功能连同传输它的适配器一起重新添加 `cache`;subagent 归属连同打标的后端和路由它的消费方一起重新添加 `agent`;真正启动新轮次的自动续行功能连同发出它的插件一起重新添加 `continuation`。 @@ -22,12 +22,12 @@ Status: implemented ### 为什么不保留它们? -[内容块词汇 RFC](../architecture/2026-06-11-content-block-vocabulary.md) 将「缓存提示……已有归属」列为设计后果,预留槽位确实能表达意图。但一个空槽位是每个实现和消费方都必须考虑的契约面(我的适配器需要兑现 `cache` 吗?我的渲染器需要路由 `agent` 来源吗?),而同族映射表自身的 JSDoc 已经拒绝了「无发出者的预留」——`refusal` 和 `max_turn_requests` 被明确标注为*当某物首次发出它们时*再添加的变体,而非提前声明。对已声明但无生命的变体施加同样的标准,使词汇表具有实际意义:如果它在映射表中,就一定有东西在生产它。 +[内容块词汇 Agent Note](../architecture/2026-06-11-content-block-vocabulary.md)曾把“cache hint……有了归属”列为设计后果,预留槽位也确实能表明意图。但空槽位是每个实现和消费者都必须考虑的契约表面(我的 adapter 是否必须遵守 `cache`?我的 renderer 是否必须路由 `agent` 来源?),而相邻 map 自身的 JSDoc 已经拒绝“无 emitter 先预留”——`refusal` 和 `max_turn_requests` 被点名为*首次有内容发出它们时*再添加的变体,而不是提前声明。让已经声明但无用的变体遵守同一标准,才能使词汇真正有意义:只要它位于 map 中,就必须有内容生产它。 ## 验证 -对 `CacheHint`、`agent` 消息来源拼写和 `continuation` 触发器拼写执行 `rg` 搜索,结果仅返回 RFC 记录(本文,以及[移除 image block 的 RFC](2026-07-04-drop-image-content-block.md) 中关于 image block 自身 `cache` 字段的说明);llm-replay fixture 使用 `injection` 触发器断言了相同的回放行为;core-data-structures 粘贴与 type-equiv manifest 保持同步。 +对 `CacheHint`、`agent` 消息来源拼写和 `continuation` 触发器拼写运行 `rg`,只会返回 Agent Note 记录(本文,以及[删除图像 Agent Note](2026-07-04-drop-image-content-block.md)对图像块自身 `cache` 字段的说明);llm-replay fixture 使用 `injection` 触发器断言相同的重放行为;核心数据结构粘贴和 type-equiv 清单保持同步。 ## 后果 -没有任何运行时行为改变——本来就没有东西能构造这些值。镜像事件的移除([boundary-mirror RFC](2026-06-20-remove-agent-boundary-mirror-events.md)、[stream-chunk RFC](2026-07-02-remove-stream-chunk-mirror.md))只涉及瞬态的 `agent/*` 事件,从不涉及持久词汇,因此不存在冲突。其他地方准入策略已经成立:`rejected`、`prompt/blocked` 和 `hook/invoked`/`hook/result` 各自都有活跃的生产者——本 RFC 将同一标准延伸到缺少生产者的三个变体。image block 自身的 `cache?` 字段属于[移除 image block 的 RFC](2026-07-04-drop-image-content-block.md),已随该块一起移除;本 RFC 覆盖的是留存块类型上的两个字段。 +操作行为没有变化——原本就没有内容能够构造这些值。镜像事件移除([边界镜像 Agent Note](2026-06-20-remove-agent-boundary-mirror-events.md)、[stream chunk Agent Note](2026-07-02-remove-stream-chunk-mirror.md))只触及瞬态 `agent/*` 事件,从不触及持久词汇,因此不存在冲突。其他位置已经遵守准入策略:`rejected`、`prompt/blocked` 和 `hook/invoked`/`hook/result` 都有实时生产者——本 Agent Note 将同一门槛扩展到缺少生产者的三个变体。图像块自身的 `cache?` 字段归属[删除图像 Agent Note](2026-07-04-drop-image-content-block.md),后者将其与该块一同移除;本 Agent Note 覆盖剩余块类型上的两个字段。 diff --git a/.agents/notes/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml index a595aef18a..e7aabd9dc2 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-prune-write-only-fs-surface.i18n.yaml @@ -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 -2026-07-04-prune-write-only-fs-surface.md: f41619ecde1bbf2a1d6d8f8d769409f624fc22c7 -2026-07-04-prune-write-only-fs-surface.zh.md: afcf1aad28db056997930162539a57bb08bbe815 +2026-07-04-prune-write-only-fs-surface.md: 6cfd5d9ab8a2fc6322814d384fba735c06681976 +2026-07-04-prune-write-only-fs-surface.zh.md: cb7494b5e958c8ed86ffa3ba8ffbe82748d1db03 diff --git a/.agents/notes/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md b/.agents/notes/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md index afcf1aad28..cb7494b5e9 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-prune-write-only-fs-surface.zh.md @@ -1,4 +1,4 @@ -# RFC: 从 fs seam 中移除只写字段与一个无效的路由旋钮 +# Agent Note: 从 fs seam 中移除只写字段与一个无效的路由旋钮 Status: implemented @@ -15,7 +15,7 @@ Status: implemented ## 决策 -删除 fs-local 的常量及其重导出,以及 `streamMinSize` 旋钮(`FsIoInternals` 中剩余的旋钮确实被原子写入测试使用);从 `FsTarget` 中移除 `inputPath`;将 `FsEditOutcome` 精简为 `{ version, before, after }`,并将 `replaceAll` 从解析后的参数传入 `formatEditOutput`;从 `FileReadOutcome` 中移除 `limit`/`version`。[filesystem.md](../../../core-data-structures/filesystem.md) 中的粘贴内容、`packages/fs/fs/README.md`,以及那些不得不为已移除字段编造值的测试 mock,都随类型一起缩减。 +删除 fs-local 常量、其再导出和 `streamMinSize` 配置项(其余 `FsIoInternals` 配置项确实由原子写入测试使用);从 `FsTarget` 删除 `inputPath`;将 `FsEditOutcome` 收窄为 `{ version, before, after }`,并把解析参数中的 `replaceAll` 传给 `formatEditOutput`;从 `FileReadOutcome` 删除 `limit`/`version`。[filesystem.md](../../../../docs/core-data-structures/filesystem.md) 中的粘贴、`packages/fs/fs/README.md`,以及不得不虚构已删除字段的测试 fake 都随类型一同收窄。 ## 曾考虑的替代方案 @@ -25,7 +25,7 @@ Status: implemented ## 验证 -被移除的接口已消失——`dsh-fs-local` 中的 `STREAM_MIN_SIZE`/`streamMinSize`、`FsTarget.inputPath`、`FsEditOutcome.replacements`/`.replaceAll`,以及 `FileReadOutcome.limit`/`.version`——而请求侧的 `replaceAll`(`FsEditRequest`)和其他 outcome 类型上的 version 字段未受影响;测试 mock 随类型一起缩减。`formatEditOutput` 在 `replace_all` 两个分支下输出的文本不变,因此没有快照黄金文件被搅动。 +已删除表面不复存在——`dsh-fs-local` 中的 `STREAM_MIN_SIZE`/`streamMinSize`、`FsTarget.inputPath`、`FsEditOutcome.replacements`/`.replaceAll`,以及 `FileReadOutcome.limit`/`.version`——而请求侧 `replaceAll`(`FsEditRequest`)和其他 outcome 类型上的版本字段保持不变;测试 fake 随类型一同收窄。`formatEditOutput` 在两个 `replace_all` 分支中生成的文本都没有变化,因此没有快照预期输出发生改动。 ## 后果 diff --git a/.agents/notes/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml index ca0bd62294..c676902cfc 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-remove-agent-steering-mirror.i18n.yaml @@ -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 -2026-07-04-remove-agent-steering-mirror.md: fbd13b3d43b0052bcdeffd7f94caa341e1f636c5 -2026-07-04-remove-agent-steering-mirror.zh.md: 185cc5601a7406e0d801afd877e9d97eaaa12a0c +2026-07-04-remove-agent-steering-mirror.md: 9f7cd5abe968ff216cbd7012163ea1c04dc00599 +2026-07-04-remove-agent-steering-mirror.zh.md: b498f473941b69eb5eab66e2e3034976da75e62c diff --git a/.agents/notes/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md b/.agents/notes/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md index 185cc5601a..b498f47394 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-remove-agent-steering-mirror.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除 `agent/steering` 镜像 emit +# Agent Note: 移除 `agent/steering` 镜像 emit Status: implemented @@ -10,23 +10,23 @@ Status: implemented `agent/steering` 以相同的 payload 重复了紧接其前的持久事件 `steering/message`。`agent/queued` 仍保留为纯瞬态信号,因为它在持久化之前触发,覆盖了可能在进入日志前被取消的工作。 -steering 承载着真实的生产流量:hook bridge 的轮次续行决策通过 `inbox.steer()` 注入理由,落地为持久的 `steering/message` 事件,hook-matrix 的 golden 文件对此进行固定——所有这些消费方观察的都是持久事件。没有任何消费方观察镜像事件。 +Steering 承载真实生产流量——hook bridge 的 turn 延续决策通过 `inbox.steer()` 注入其理由,最终成为由 hook 矩阵预期输出固定的持久 `steering/message` 事件——而这些消费者无一例外都观察持久事件。没有任何内容观察镜像。 ## 决策 -`agent/steering` 从 agent 事件分类体系中移除:`packages/core/agent/src/types.ts` 中的声明(及其在 live-events JSDoc 列表中的提及)、`drainSteering` 中的 emit(随之移除的还有当时已无用的 `ctx` 参数)、`packages/core/agent/README.md` 中的对应行,以及 loop 伪代码块中的 emit 行(`packages/core/agent-loop/src/loop.ts` 模块文档与 [architecture.md](../../../architecture.md));Cordis catalog 重新生成后不再包含它。唯一的回归测试改为在持久事件 `steering/message` 上固定 source 保持性——它所固定的事实存在于日志中。 +`agent/steering` 已从 agent 事件分类中移除:包括 `packages/core/agent/src/types.ts` 中的声明(以及其中实时事件 JSDoc 列表对它的提及)、`drainSteering` 中的 emit(当时已无用的 `ctx` 参数也随之移除)、`packages/core/agent/README.md` 中的表格行,以及循环伪代码块(`packages/core/agent-loop/src/loop.ts` 模块文档和 [architecture.md](../../../../docs/architecture.md))中的 emit 行;Cordis 目录重新生成后不再包含它。唯一的回归测试改为在持久 `steering/message` 事件上固定来源保留行为——所固定的事实存在于日志上。 -三份已实施的 RFC 曾声明保留该事件,每份均按 [implemented/AGENTS.md](../AGENTS.md) 的要求修订,指向本 RFC 作为移除记录:[boundary RFC](2026-06-20-remove-agent-boundary-mirror-events.md) 的保留列表条目、[stream-chunk RFC](2026-07-02-remove-stream-chunk-mirror.md) 的范围条款,以及 [event-domain-semantics RFC](../architecture/2026-06-30-event-domain-semantics.md) 的瞬态 emit 枚举。 +三份已实现 Agent Note(agent 决策记录)曾说明保留该事件;按照 [implemented/AGENTS.md](../AGENTS.md),每份记录都已修改并指向本文作为移除记录:包括[边界 Agent Note](2026-06-20-remove-agent-boundary-mirror-events.md) 的保留列表条目、[stream chunk Agent Note](2026-07-02-remove-stream-chunk-mirror.md) 的范围条款,以及[事件域语义 Agent Note](../architecture/2026-06-30-event-domain-semantics.md) 的瞬态 emit 枚举。 ## 曾考虑的替代方案 ### 为什么不保留? -"它是控制信号,不是边界事件"——但分类体系的操作性区分是「镜像 vs. 纯瞬态」,而非「控制 vs. 边界」,而这个事件属于镜像。需要入队时通知的消费方有 `agent/queued`(带 steering flag);需要 drain 时通知的消费方,本质上是在请求 `steering/message` 被追加的那一刻,而 `session/event` 以相同 payload 加上持久性提供了这一通知。被否决的 [retire-mid-turn-steering RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md) 捍卫的是 steering *能力*——`steer()`、持久事件、续行强制——本次移除对这些全部保持不变。 +“它是控制信号,不是边界”——但该分类的实际区分是镜像/仅实时,而非控制/边界,并且该事件确实是镜像。希望在入队时收到通知的消费者可以使用 `agent/queued`(及其 steering 标记);希望在排空时收到通知的消费者,本质上是在要求获知 `steering/message` 被追加的时刻,而 `session/event` 会交付相同 payload 并附带持久性。遭拒绝的[退役 turn 中途 steering Agent Note](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md)所捍卫的是 steering *功能*——`steer()`、持久事件、强制延续——本次移除不会触及其中任何一项。 ## 验证 -`agent/steering` 这一拼写仅存于 RFC 行文中(本 RFC、上述三份修订的 RFC,以及冻结的[被否决的 steering 能力 RFC](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md),其文本记录了它所拒绝的提案);catalog 已重新生成;重定向后的测试在 `steering/message` 上固定 source 保持性。 +`agent/steering` 拼写只存在于 Agent Note 正文中(本 Agent Note、上方三份已修改 Agent Note,以及已冻结的[遭拒绝 steering 功能 Agent Note](../../rejected/simplification/2026-06-20-retire-mid-turn-steering.md),其正文记录了它所否决的提案);目录已重新生成;重新定向的测试在 `steering/message` 上固定来源保留行为。 ## 后果 diff --git a/.agents/notes/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml index 788e1735b5..32517c2c50 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-share-app-bin-boot-glue.i18n.yaml @@ -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 -2026-07-04-share-app-bin-boot-glue.md: 31666e74bb0bb0086de85e6a3afafbc2f73a6e52 -2026-07-04-share-app-bin-boot-glue.zh.md: d18f83be0f76774e39a1e54f1ea2db3c1c1b7688 +2026-07-04-share-app-bin-boot-glue.md: 7a763eba8a229ec5017387edb54657a5c367105b +2026-07-04-share-app-bin-boot-glue.zh.md: d65a6613f7b05cdea0f99529808c992aff4256e9 diff --git a/.agents/notes/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md b/.agents/notes/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md index d18f83be0f..d65a6613f7 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-share-app-bin-boot-glue.zh.md @@ -1,4 +1,4 @@ -# RFC: 共享应用 bin 的启动胶水代码,而非维护两份副本 +# Agent Note: 共享应用 bin 的启动胶水代码,而非维护两份副本 Status: implemented @@ -6,19 +6,19 @@ Status: implemented ## 问题 -stdio 和 ACP 两个 bin 各自重复了环境加载、fail-loud 处理、入口校验与启动逻辑,包括微妙的 Loader 失败行为。两份副本已经发生漂移,且位于自执行文件中、被排除在单元测试覆盖率之外,导致其导出的辅助函数无法被复用。 +stdio 和 ACP(Agent Client Protocol)两个 bin 各自重复了环境加载、fail-loud 处理、入口校验与启动逻辑,包括微妙的 Loader 失败行为。两份副本已经发生漂移,且位于自执行文件中、被排除在单元测试覆盖率之外,导致其导出的辅助函数无法被复用。 ## 决策 辅助函数只存在一处:[`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot)(`packages/ui/app-boot`,归入 `ui` 分组,因为 bin 是已发布产物,其运行时依赖本身也必须是已发布的包,而非 `support/`)。包含:`resolveConfigPath`(快照感知,两个 bin 共用的唯一路径解析器)、`loadEnv`、`installFailLoud`、`assertEntriesLoaded` 与 `boot`,每个函数都通过 bin 的诊断前缀参数化,并在其副作用 seam(warn sink、process slice)处支持注入,使单元测试套件能覆盖每个分支——包括 `boot()` 在进程内驱动真实 Loader、使用相对路径 specifier 配置的场景,既覆盖已稳定树的正常路径,也覆盖无 fiber 入口的拒绝路径。该包启用逐文件 100% 覆盖率门禁;Loader 失败的相关知识只有一个归属地。 -每个 `bin.ts` 是一个精简的自执行组合,基于共享辅助函数加上各自特有的应用生命周期(ACP bin:replay 模式下跳过 env 加载与 stdin-EOF dispose;stdio bin:无额外逻辑)。bin 文件仍被排除在覆盖率之外且不导出任何内容;已发布产物的守卫不变——built-bin 冒烟测试仍在 node_modules 形状的临时目录中以原生 node 运行每个 bin(现在也符号链接了 `ui/app-boot`),并仍断言缺少配置时的非零退出码,遵循「真实入口路径即已发布产物」的防御模式。[extract-example-app-packages RFC](../architecture/2026-06-20-extract-example-app-packages.md) 中关于 bin 归属的事实已相应修订。 +每个 `bin.ts` 都是在共享辅助函数之上加应用特有生命周期的精简自执行组合(ACP bin:重放模式环境变量跳过和 stdin EOF 释放;stdio bin:没有额外逻辑)。这些 bin 仍排除在覆盖率之外且不导出任何内容;已发布产物守卫保持不变——按照“真实入口路径即已发布产物”的防御模式,已构建 bin 冒烟仍在具有 node_modules 形状的临时目录中用纯 node 运行每个 bin(现在也会符号链接 `ui/app-boot`),并继续断言缺失配置时以非零状态退出。[提取示例应用包 Agent Note(agent 决策记录)](../architecture/2026-06-20-extract-example-app-packages.md)中的 bin 归属事实已据此修改。 ## 曾考虑的替代方案 ### 为何不保留重复? -bin 被定位为独立拥有的已发布产物,而新增一个包(package)带来的固定开销(manifest(元数据清单)、README、tsconfig reference、publint 表面积)与去重的代码行数相当。但创建 bin 的那份 RFC 从未权衡过应用间共享的可能——它将三份示例 `start.ts` 副本合并进 bin 后便止步了;漂移是已观察到的事实;而覆盖率缺口的论据独立于去重论据:这是仓库中唯一免于逐文件 100% 门禁的非平凡运行时逻辑。记录在案的备选方案(仅将纯逻辑提取为各应用自己的模块)虽能终结豁免,但会保留两个知识归属地。 +这些 bin 当时被定位为归属相互独立的已发布产物,而新包会带来固定开销(清单、README、tsconfig 引用、publint 表面),与去重的行数相当。但创建 bin 的 Agent Note 从未权衡应用间共享——它把三份示例 `start.ts` 副本合并进 bin 后便止步于此;漂移是已经观察到的事实;覆盖率缺口的理由也独立于去重理由:这是仓库中唯一免受逐文件 100% 门禁约束的非平凡运行时逻辑。记录的后备方案(只将纯逻辑提取到各应用模块)会结束豁免,但会继续让相关知识拥有两个归属。 ## 后果 diff --git a/.agents/notes/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml index b2926299df..a438839d3a 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.i18n.yaml @@ -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 -2026-07-04-tighten-hook-protocol-contract.md: 92ed629edaa0364d88955458f39f6280322e79c7 -2026-07-04-tighten-hook-protocol-contract.zh.md: 9b5b19d7ad522fdf74eb330c259d8dee03bee604 +2026-07-04-tighten-hook-protocol-contract.md: a1972ee8ef486982268ba8886b2413f3557061b4 +2026-07-04-tighten-hook-protocol-contract.zh.md: 51d11b4c2d79bd79b608ea5aa49b677653c3ac41 diff --git a/.agents/notes/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md b/.agents/notes/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md index 9b5b19d7ad..51d11b4c2d 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-tighten-hook-protocol-contract.zh.md @@ -1,4 +1,4 @@ -# RFC: 收紧 hook-protocol 契约——dialect、废弃字段、双重默认值与 lib 拥有的 `hook/result` 语义 +# Agent Note: 收紧 hook-protocol 契约——dialect、废弃字段、双重默认值与 lib 拥有的 `hook/result` 语义 Status: implemented @@ -6,9 +6,9 @@ Status: implemented ## 问题 -`dsh-hook-protocol`/bridge 契约中有四处遗漏了 [subagent-observe-enrich RFC](../feature/2026-06-30-subagent-observe-enrich.md) 所记录的纪律——该 RFC 因缺乏消费方而移除了 `agentType` 生命周期字段,以下四处未通过同样的检验: +`dsh-hook-protocol`/bridge 契约中有四部分没有遵守 [subagent observe/enrich Agent Note(agent 决策记录)](../feature/2026-06-30-subagent-observe-enrich.md)记下的准则——后者因缺少消费者而删除 `agentType` 生命周期字段,以下各项没有通过同一检验: -1. **`HookDialect` 的 `'native'` 变体**(`packages/hooks/hook-protocol/src/types.ts`)没有任何生产者——bridge 只会标记 `'claude'` 和 `'codex'`;唯一构造 `'native'` 的地方是 lib 自身的单元测试。该字段的 JSDoc 将 `dialect` 定义为「运行它的 bridge」,而 native 并非 bridge:[interception-seams RFC](../feature/2026-06-30-interception-seams.md) 记录了 native hook 不是一个 package,且「native 插件已经可以直接使用类型化的 Decisions」而无需持久化 hook 日志;旗舰 native-plugin 示例也正是如此断言的(完全没有 `hook/*` 事件)。 +1. **`HookDialect` 的 `'native'` 变体**(`packages/hooks/hook-protocol/src/types.ts`)没有生产者——bridge 会标记 `'claude'` 和 `'codex'`;所有位置中唯一构造 `'native'` 的是该库自己的单元测试。字段自身的 JSDoc 将 `dialect` 定义为“运行它的 bridge”,而 native 不是 bridge:[拦截接缝 Agent Note](../feature/2026-06-30-interception-seams.md) 记载 native hook 不是一个包,并且“native 插件无需持久 hook 日志即可使用类型化 Decision”;旗舰 native 插件实践示例恰好断言了这一点(完全没有 `hook/*` 事件)。 2. **`HookOutput.suppressOutput`**(同一文件)被 codec 解析后在所有路径上均被丢弃:没有 bridge 分支处理它、没有 merge fold、没有 warn、没有 deferred-list 行——在所有「被解析但未兑现」的同类字段中它是唯一没有明确延期声明的(`updatedInput` → 一条 warn 日志加 [pre-tool-input-rewrite 提案](../../proposed/feature/2026-06-30-pre-tool-input-rewrite.md);`systemMessage` → 一条 warn 日志加 README deferred 行;`continue`/`stopReason` → 一个 `TODO(hook-continue-false)` 锚点加 `'stop'` decision 记录)。从结构上看根本无物可抑制:hook stdout 从不进入任何 transcript(文本记录)(上下文仅通过 `additionalContext` 流入;日志只记录 `decision`/`stderrSummary`),因此 hook 作者设置 `suppressOutput: true` 得到的是无声的空操作,且无任何警告。 3. **`defaultTimeoutMs` 在两个 bridge 配置中以浮动字面量双重默认**——schema 的 `.default(600_000)` 加上一个 `?? 600_000` 回退(`packages/hooks/hooks-claude/src/index.ts`、`packages/hooks/hooks-codex/src/index.ts`),一个协议级常量在每个 bridge 中有两个归属地,两个 bridge 可能在共享默认值上悄然分歧。*提案最初的补救措施是彻底删除该旋钮,但被 no-hardcoded-tunables 审计所取代:审计保留了该旋钮作为 bridge 拥有的显式配置(并在旁边新增了 `stderrSummaryMaxChars`);剩下要修的是字面量的归属地。* 4. **`hook/result` 的语义存在于两个 bridge 中(各一份),而非拥有该事件的 lib。** `summarize()`——stderr 截断规则——在 `packages/hooks/hooks-claude/src/index.ts` 与 `packages/hooks/hooks-codex/src/index.ts` 中逐字节相同;decision 字符串规则 `output.decision ?? (output.continue === false ? 'stop' : 'pass')` 同样如此。然而 `dsh-hook-protocol` 声明了 `hook/result`、在文档中将 `stderrSummary` 描述为「已截断」却不拥有截断逻辑,记录了 decision 值却不拥有映射逻辑。如果某个 bridge 漂移(不同的上限、不同的回退),共享持久化事件的语义就会悄然分叉。 @@ -29,4 +29,4 @@ Status: implemented ## 后果 -`dialect`、`suppressOutput`、可调参数与语义的变更在协议格式(wire format)和 golden 文件中均不可见。代价是 `dsh-hook-protocol` 与两个 bridge 的代码变动——在预发布阶段这很廉价,且比让持久化事件语义的两份副本各自老化要廉价得多。 +`dialect`、`suppressOutput`、可调参数和语义变更在线协议和预期输出中均不可见。代价是 `dsh-hook-protocol` 和两个 bridge 中的改动——在预发布立场下成本很低,也比让一项持久事件语义的两个副本各自老化更便宜。 diff --git a/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml index f0afae419b..9de0d532bc 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.i18n.yaml @@ -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 -2026-07-04-trim-acp-bridge-unreachable-surface.md: 05a62c92ec1553e6eb0b14adc86f8aa1b89827e5 -2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: 851198eee0559013429ef4eb5491cd7f97217c46 +2026-07-04-trim-acp-bridge-unreachable-surface.md: ce0c623930192d02c8347c3956c497ee13048904 +2026-07-04-trim-acp-bridge-unreachable-surface.zh.md: ea94f28b4802c18394cc3f6e6d4bdfa8702dae2b diff --git a/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md b/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md index 851198eee0..ea94f28b48 100644 --- a/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.zh.md @@ -1,4 +1,4 @@ -# RFC: 裁剪不可达的 ACP 桥接层表面——品牌配置项与 kind 嗅探回退 +# Agent Note: 裁剪不可达的 ACP 桥接层表面——品牌配置项与 kind 嗅探回退 Status: implemented @@ -8,7 +8,7 @@ Status: implemented `dsh-acp` 有两处对外表面在任何已交付的配置中都不可达: -1. **`AcpConfig.agentName` / `agentVersion`**(`packages/ui/acp/src/index.ts`)。已交付的 app 包(`packages/examples/acp-demo/src/index.ts`)只向桥接层传递 `{ model }`,因此没有任何叶子 `cordis.yml`(唯一的生产配置表面)能设置这两个配置项;它们只有通过直接挂载桥接层才能设置,而只有单元测试这样做。所有快照 golden(包括 hook-matrix 场景)都固定了 schema 默认值(`deepseek-harness-acp` / `0.0.1`)。这对字段还带着一个活跃的 `TODO(double-default)`:字面量存在两份(schema 的 `.default(...)` 加 `??` 回退),TODO 要求选定一个归属。 +1. **`AcpConfig.agentName` / `agentVersion`**(`packages/ui/acp/src/index.ts`)。已发布应用包只向 bridge 传递 `{ model }`(`packages/examples/acp-demo/src/index.ts`),因此没有任何叶子 `cordis.yml`——唯一的生产配置表面——能够设置这些配置项;只有直接挂载 bridge 才能设置它们,而这种做法只存在于一个单元测试中。每份快照预期输出——包括 hook 矩阵场景——都固定 schema 默认值(`deepseek-harness-acp` / `0.0.1`)。这对配置项还带有一个尚未解决的 `TODO(double-default)`:字面量存在两次(schema `.default(...)` 加 `??` 后备值),TODO 要求为它们选择一个归属。 2. **`toolKindFor` 名称启发式**(同一文件)在通用回退路径中对 `bash*`/`read*`/`write`/`edit*` 工具名做了特殊处理。自 [render-intent union](../architecture/2026-07-02-tool-render-intent-union.md) 以来,这些分支匹配到的每个第一方工具都自带 `presentCall` 并携带其 kind,而没有 presenter 的生产工具(`subagent`、`subagent_fork`)本来就落入 `other`。这些分支只有在工具拒绝自行呈现调用时才在生产中可达:`presentCall` 抛出异常(容错回退),或模型参数未通过工具 schema 导致 `defineTool` 的 `presentCall` 包装层返回 `undefined`(例如 `bash` 调用缺少必需的 `description`)。而桥接层自身的模块文档明确声明了该启发式所违反的设计规则:"桥接层绝不对工具名做特殊处理"。 ## 决策 diff --git a/.agents/notes/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml index 3644236c38..fa6148d1e6 100644 --- a/.agents/notes/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.i18n.yaml @@ -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 -2026-07-12-drop-unconsumed-skill-provider-events.md: 90157c03e5df05c98b992ce1dbefea26f4865ce7 -2026-07-12-drop-unconsumed-skill-provider-events.zh.md: 19fec4b827b89b4127b749a9c77715baf39dd00a +2026-07-12-drop-unconsumed-skill-provider-events.md: b0ed7585882328b6abdcf57974200053d9c26048 +2026-07-12-drop-unconsumed-skill-provider-events.zh.md: 557e7ee2155969530a109280d9324b2525e3144a diff --git a/.agents/notes/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md b/.agents/notes/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md index 19fec4b827..557e7ee215 100644 --- a/.agents/notes/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除无消费方的 skill 提供方事件 +# Agent Note: 移除无消费方的 skill 提供方事件 Status: implemented @@ -16,7 +16,7 @@ skill 发现按需读取当前的提供方映射表,提供方注册时同步 skill 注册表不再声明和 emit 提供方成员变更事件。提供方的注册与 dispose(资源释放)仍为 effect 所有的直接状态变更,同步使已完成的 catalog 失效;查找与发现按需读取当前提供方映射表。测试通过提供方查找和收集到的输出来观察清理行为,而非依赖生命周期通知。 -生成的事件 catalog、API catalog 与生产者/消费方矩阵不再包含已删除的通知。skill 系统 RFC 与包文档通过 effect 所有的直接状态及缓存失效契约来描述注册行为。 +生成式事件目录、API 目录和生产者/消费者矩阵均不再包含已删除通知。skill system Agent Note(agent 决策记录)和包文档改为通过其由 effect 直接拥有的状态与 cache 失效契约描述注册。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml index 703539b152..1f8a055362 100644 --- a/.agents/notes/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.i18n.yaml @@ -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 -2026-07-12-prune-unused-web-seam-fields.md: 9fd05da282c22d78dc98e232ef2c23cd6e9c4ea3 -2026-07-12-prune-unused-web-seam-fields.zh.md: 650b6b74c808c719bcea9783c60064936427ffee +2026-07-12-prune-unused-web-seam-fields.md: c50bf44161579a44b09113fc501f3d67fb5d6855 +2026-07-12-prune-unused-web-seam-fields.zh.md: 401bdd0c812175cffc572e722141d2829a3fc2d5 diff --git a/.agents/notes/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md b/.agents/notes/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md index 650b6b74c8..401bdd0c81 100644 --- a/.agents/notes/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-12-prune-unused-web-seam-fields.zh.md @@ -1,4 +1,4 @@ -# RFC: 裁剪 web seam 中未使用的字段 +# Agent Note: 裁剪 web seam 中未使用的字段 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -web 能力携带的 request/result/status 值,虽然每个已交付的实现都会填充,但没有任何生产环境的消费方读取它们。`WebSearchResult.providerId`、`query`与 `WebFetchResult.providerId` 是结果回显;`tool-web` 只格式化 content/sources/truncation 或最终 URL/status/body/truncation,没有其他运行时读取这些字段。搜索提供方返回 `WebProviderStatus.reason`,但可用性检查只看 `available`,并有意输出一条通用的不可用诊断信息。 +web 能力携带的 request/result/status 值,虽然每个已交付的实现都会填充,但没有任何生产环境的消费方读取它们。`WebSearchResult.providerId`、`query` 与 `WebFetchResult.providerId` 是结果回显;`tool-web` 只格式化 content/sources/truncation 或最终 URL/status/body/truncation,没有其他运行时读取这些字段。搜索提供方返回 `WebProviderStatus.reason`,但可用性检查只看 `available`,并有意输出一条通用的不可用诊断信息。 `WebFetchRequest.timeoutMs` 同样从未被生产调用方设置。`tool-web` 只提供 URL,使用工具定义的 timeout 加 `exec.signal` 作为调用方截止时间,并依赖本地提供方的配置默认值作为兜底。这个未使用的逐请求覆盖迫使 `web-fetch-local` 暴露 `maxTimeoutMs`、对两个 timeout 来源做 clamp,并为没有任何产品路径能选中的优先级规则编写文档和测试。`WebExecContext` 则是另一个单字段包装层:每个调用方分配 `{ signal }`,每个提供方立即解包 `exec?.signal`;不存在第二个执行控制字段。 diff --git a/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml b/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml index ff2ae238ba..50343fef96 100644 --- a/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml +++ b/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.i18n.yaml @@ -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 -2026-07-12-simplify-session-log-representation.md: dd8e7f319098bcdca9a844f5665583a3aa25ae80 -2026-07-12-simplify-session-log-representation.zh.md: c759b87bbb13903744a8f6bbb139ab71e1c0f39b +2026-07-12-simplify-session-log-representation.md: a40f4013a97a9c940012dbb37d59beb2faf8fb22 +2026-07-12-simplify-session-log-representation.zh.md: a880a74cf41ca7d06f2278792e1abb4ea46ea969 diff --git a/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.md b/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.md index 97a89e5be7..a40f4013a9 100644 --- a/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.md +++ b/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-07-12-simplify-session-log-representation.zh.md) + ## Problem The session log maintains two representations that cost more machinery than their consumers require: a pseudo-linked surface and custom request-header deltas. diff --git a/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.zh.md b/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.zh.md index c759b87bbb..a880a74cf4 100644 --- a/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.zh.md +++ b/.agents/notes/implemented/simplification/2026-07-12-simplify-session-log-representation.zh.md @@ -1,6 +1,6 @@ -# RFC: 简化会话日志表示 +# Agent Note: 简化会话日志表示 -Status: proposed +Status: implemented [English](2026-07-12-simplify-session-log-representation.md) | 中文 @@ -8,31 +8,28 @@ Status: proposed 会话日志维护着两种表示,其机制复杂度超出了消费方的实际需求:一个伪链表 surface 和自定义的请求头增量。 -`SurfaceManager` 用一个数组、一个 seq 映射和可变的 `prev`/`next` 链接存储相同的顺序。生产代码从不读取 `prev`;压缩(compaction)唯一的 `next` 读取是取数组位置的后继。替换操作已经使用 `indexOf`,因此链接并未让其主要操作达到常数时间。一个 seq 数组加线性替换查找具有相同的渐近替换开销,且只有一种表示需要验证。 +`SurfaceManager` 同时在数组、seq map 和可变 `prev`/`next` 链接中存储相同顺序。生产代码从不读取任一链接:compact 的工具配对 balance 根据按 surface 顺序缓存的每个切点 balance 作答。替换已经使用 `indexOf`,因此链接并未使其主导操作成为常数时间。使用线性替换查找的 seq 数组具有相同的渐近替换成本,却只有一种表示需要验证。 请求头子系统实现了一套自定义的 system/tool 增量编解码器和传输决策层,尽管其契约声明增量只是编码优化,而非可重建性要求。在每个 agent loop(智能体循环)实例边界保留初始/恢复的完整快照,然后在该实例的组装头发生变化时写入一条规范的完整 `request/header`,即可保留回放能力,同时删除 `SystemDelta`、`ToolsDelta`、往返回退逻辑以及持久化的 `request/header-delta` 变体。编解码器专属的词汇随编解码器一起消失,并非因为其各分支本身无效。 -本提案有意保留追加和替换的 `sourceEventSeqs`、崩溃恢复来源信息以及所有 `SessionStartSource` 变体:已实施的 RFC 赋予这些字段审计/拦截角色,零当前读者这一事实不足以推翻它们。 +实现保留追加与替换 `sourceEventSeqs`、崩溃修复 provenance,以及所有 `SessionStartSource` 变体,因为这些字段承担审计/拦截职责,当前没有读取方并不能推翻这一点。 -## 提案 +## 决策 -将 `SurfaceManager.nodes` 改为事件序列号的 `readonly number[]`,移除公开的 `SurfaceNode` 形状。保留内部的替换代信号;更新 tool 配对平衡和压缩调用方,使其通过数组值/索引获取前驱、后继和替换范围,移除节点链接和 seq-to-node 映射。用规范的完整变更头快照替代锚点后的头增量,移除增量编解码器/事件/测试;初始和恢复锚点即使折叠后的头未变也仍为完整快照。 +`SurfaceManager.nodes` 是由事件序号组成的 `readonly number[]`;公共 `SurfaceNode` 形状、node 链接和 seq-to-node map 均已移除。内部替换 generation 信号保留。session-query 使用的完整 `foldSurface()` 读取会返回相同的数字数组表示和替换元数据,而无需让增量 manager 保留历史。工具配对 balance 和压缩使用事件序号与 surface 位置;由 compact 拥有的每切点 balance cache 不依赖 node 链接。 -修订 session-surface 和 reconstructable-request RFC 中描述已移除编码的部分。更新事件类型/不变式、请求日志/回放、持久化 fixture(测试前置数据)、生成的 catalog、包文档和快照。将编解码器专属的 `fallback` 原因替换为锚点后完整快照的显式 `change` 原因,使其与保留的 `initial` 和 `resume` 锚点区分开来。 +请求头只使用规范的完整快照。初始与恢复锚点即使没有变化也仍是完整快照;实例内变化会追加另一个完整 `request/header`,reason 为 `change`。delta 事件、codec 类型、diff/apply 辅助函数,以及仅供 codec 使用的 `fallback` reason 均已移除。请求重建选择最新快照。 -`SESSION_FORMAT_VERSION` 有意保持在 `0`,因此一份包含 `request/header-delta` 的旧 v0 日志在增量折叠被删除后,本会通过版本检查并静默丢失头变更。seed/load 校验必须在格式边界处拒绝该遗留事件并显式报错;不添加兼容性折叠或迁移。 +`SESSION_FORMAT_VERSION` 仍固定为 `0`,因此 seed、追加和持久化加载验证会显式拒绝旧 v0 `request/header-delta` 事件,以及携带已删除 `fallback` reason 的完整快照。不存在兼容性 fold 或迁移。JSONL 与 SQLite 测试固定了这一响亮失败边界;ACP(Agent Client Protocol)快照 harness 则把合法的 session 中途变更表示为完整固定请求头和完整可读 prompt。 ## 曾考虑的替代方案 **保留链表节点和紧凑增量以备未来扩展。** 链接可能有助于未来的游标 API,增量在大型工具 schema 仅有少量变化时可以缩减日志。但没有已发布的游标使用这些链接,而完整快照以磁盘空间换取了显著更简单的正确性。如果头部体积确实成为问题,可以基于真实 trace 设计压缩方案或经过度量的规范增量方案。 -## 验收标准 +## 验证 -- `SurfaceManager.nodes` 是一个有序 seq 数组,没有 `SurfaceNode`、链接字段或 seq-to-node 映射;增量追加处理和内部替换代信号保留。 -- 回放完整变更头快照能重建出完全相同的请求;不再存在任何 header-delta 事件/类型/编解码器。 -- 包含遗留 `request/header-delta` 的 v0 seed 或持久化日志在回放前被拒绝,JSONL 和 SQLite 加载路径均有覆盖率。 -- 新形状的 v0 JSONL/SQLite 回放、来源信息、崩溃恢复、压缩、快照、不变式、类型检查、覆盖率、doc-sync 和 hygiene 全部通过。 +单元覆盖率固定有序 surface 的追加/替换行为、工具配对、压缩、完整请求头 fold/记录、请求重建和开发不变量。Seed 验证以及 JSONL、SQLite 加载测试会在重放前拒绝旧事件。无密钥 ACP 套件以新形状覆盖记录、刷新、重放、变化请求头固定,以及 sandbox 模式切换 fixture(测试前置数据)。 -## 风险 +## 后果 -完整头会增加日志体积,线性替换查找在非常大的 surface 上可能更慢。替换操作已经是线性的,因为实现调用了 `indexOf`;只有当真实 trace 表明更简单的数组成为瓶颈时才应添加基准测试。由于格式版本保持为 `0`,如果遗漏了对遗留事件的显式拒绝,后果将是静默数据损坏而非类型错误;因此显式报错的加载测试是本提案的组成部分,而非可选的清理工作。 +完整请求头会增加日志体积,线性替换查找在极大 surface 上也可能较慢。由于先前实现调用 `indexOf`,替换原本就是线性的;benchmark 推迟到真实 trace 表明更简单的数组成为瓶颈时再进行。格式版本仍为 `0`,因此显式拒绝旧事件是预发布格式边界的永久组成部分。作为交换,surface 顺序和请求头状态现在各自只有一种表示,删除了链接维护、map、codec 分支、往返 fallback 和感知 delta 的快照规范化。 diff --git a/.agents/notes/implemented/testing/2026-06-11-property-based-testing.i18n.yaml b/.agents/notes/implemented/testing/2026-06-11-property-based-testing.i18n.yaml index 22d74d7424..6b78fa480b 100644 --- a/.agents/notes/implemented/testing/2026-06-11-property-based-testing.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-06-11-property-based-testing.i18n.yaml @@ -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 -2026-06-11-property-based-testing.md: 153584d3a2b77c8f2d103db02646f18a9d424b57 -2026-06-11-property-based-testing.zh.md: e11d11f7db9eee97ab81bc678afab5d0fea36bf9 +2026-06-11-property-based-testing.md: ac35591cb76c1d4243ecba153e8e143290716926 +2026-06-11-property-based-testing.zh.md: 4a0def2d28ef828fd68b78e4c1e100ce7f85d4f0 diff --git a/.agents/notes/implemented/testing/2026-06-11-property-based-testing.zh.md b/.agents/notes/implemented/testing/2026-06-11-property-based-testing.zh.md index e11d11f7db..4a0def2d28 100644 --- a/.agents/notes/implemented/testing/2026-06-11-property-based-testing.zh.md +++ b/.agents/notes/implemented/testing/2026-06-11-property-based-testing.zh.md @@ -1,4 +1,4 @@ -# RFC: 对协议形态代码进行基于属性的测试 +# Agent Note: 对协议形态代码进行基于属性的测试 Status: implemented @@ -22,8 +22,8 @@ Status: implemented ## 后果 - 生成器质量是价值杠杆——生成器偏向小索引池和短字符串,使碰撞与交错频繁发生。 -- **已经产出回报:** BlockAssembler 流测试发现了一个真实 bug——同一索引的重复 `block-end` 覆盖了已刷出的块,导致流式前缀与最终 `blocks()` 不一致。已修复(首次关闭生效,与既有的滞后分片规则一致),并附带一个专门的回归测试。 +- **它已经带来回报:** BlockAssembler 流发现了一个真实 bug——同一索引处重复的 `block-end` 会改写已经完成的块。现已修复(首次关闭优先,与现有迟到项规则一致),并加入专用回归测试。 - 属性测试因超时而 flake 是一个发现,不应通过重试消除。循环属性测试在设计上是确定性的(通过 `agent/status` settle),因此挂起即为真实缺陷。 - 属性测试是对示例测试的补充而非替代;示例测试固定特定分支,服务于 100% 覆盖率门禁。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml b/.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml index 10573d8e31..c068706aeb 100644 --- a/.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.i18n.yaml @@ -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 -2026-06-19-acp-snapshot-tests.md: c336b4864b73b8db29c0a8bb983d974348a9515a -2026-06-19-acp-snapshot-tests.zh.md: bc9488562b0698b172ccffff74815a893acf722d +2026-06-19-acp-snapshot-tests.md: 43900632c4e5e3904c2d0e3b75f2a3fe3b3a50cc +2026-06-19-acp-snapshot-tests.zh.md: 9d9e49cf799ccc07fb9fbc4b13261b7d305d68dc diff --git a/.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md b/.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md index bc9488562b..9d9e49cf79 100644 --- a/.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md +++ b/.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md @@ -1,4 +1,4 @@ -# RFC: ACP 快照测试——一次录制 / 确定性回放 +# Agent Note: ACP 快照测试——一次录制 / 确定性回放 Status: implemented @@ -6,19 +6,21 @@ Status: implemented ## 问题 -单元测试无法覆盖完整的 ACP(Agent Client Protocol)子进程 transcript(文本记录),而真实 API 测试既不确定又需要密钥。因此,面向编辑器的 `session/update` 输出可能在单元覆盖率全绿的情况下发生回归,正如 [default-export 事后分析](../../../postmortem/0001-acp-default-export-drops-inject.md)所揭示的那样。 +单元测试不会覆盖完整的 ACP(Agent Client Protocol)子进程 transcript(文本记录),而真实 API 测试不具确定性且受密钥门控。因此,即使单元覆盖率为绿色,面向编辑器的 `session/update` 输出仍可能回归,[默认导出事后分析](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md)已经证明了这一点。 -全 transcript 测试的阻塞因素在于模型:agent 的输出由非确定性的 LLM(大语言模型)驱动,而每次运行都命中真实 API 的密钥门控测试既不确定也无法在 CI 中运行。我们需要真实运行的保真度与 fixture(测试前置数据)的确定性兼得。 +全 transcript 测试的阻塞因素在于模型:agent(智能体)的输出由非确定性的 LLM(大语言模型)驱动,而每次运行都命中真实 API 的密钥门控测试既不确定也无法在 CI 中运行。我们需要真实运行的保真度与 fixture(测试前置数据)的确定性兼得。 -本 RFC 记录了新增第三层测试——**快照测试**——的决策,以及使其具备确定性、CI 中无需密钥、维护成本低的设计选择。 +本 Agent Note(agent 决策记录)记下了新增第三层测试——**快照测试**——的决策,以及让它具备确定性、在 CI 中无需密钥、且维护成本低廉的设计选择。 ## 决策 -快照测试启动真实的 ACP 示例,通过确定性脚本驱动其 stdio 协议,并将归一化后的输出与已提交的 golden 文件比对。一次从真实 API 录制的会话日志为后续所有模型流提供数据。fixture 就是产品正常持久化的 JSONL。 +快照测试会启动真实 ACP 示例,通过确定性脚本驱动其 stdio 协议,并将规范化输出与已提交的预期输出比较。从真实 API 一次记录的 session log 为后续所有模型流提供数据。fixture 就是产品普通的持久化 JSONL。 ### fixture 即持久化的会话 JSONL -每个场景的 `session.jsonl` 从一次真实运行中采集。`assistant/chunk` 事件重现模型流;tool、message 和 boundary 事件捕获 harness 行为。一份普通的会话产物因此同时充当回放源和行为 golden。 +每个场景的 `session.jsonl` 都从真实运行中采集。`assistant/chunk` 事件复现模型流;工具、消息和边界事件捕获 harness 行为。因此,一份普通 session 产物同时充当重放来源和行为预期输出。 + +当场景固定另一种物理存储布局时,其 fixture 会从真实的未打包对应项机械派生。场景测试要求包含每一种预期存储行类型,并在解码后逐事件精确相等;随后,普通重放与日志比较才会证明组合后的进程能够消费并复现该布局。 ### 回放从日志推导模型脚本 @@ -30,7 +32,7 @@ Status: implemented ``` { kind: 'chunks', chunks: StreamChunk[] } -| { kind: 'throw', chunks: StreamChunk[], message: string, code: string, status?: number } +| { kind: 'throw', chunks: StreamChunk[], message: string, code: string } | { kind: 'hang' } ``` @@ -42,24 +44,24 @@ Status: implemented ### 录制采集日志;无密钥回放需要无提供方的配置 -录制使用真实的 `llm-deepseek` 适配器和 JSONL 持久化后端运行场景,然后将产出的 `.jsonl` 复制到场景目录。逐事件追加是持久的,但 harness 在采集前会优雅关闭子进程(关闭 stdin → `await ctx.dispose()`),确保最终事件已刷盘。`llm-replay` 本身不做录制,它只负责回放。 +记录模式使用真实 `llm-deepseek` adapter 和配置为 `persistenceCompression: 'none'` 的 JSONL 持久化后端运行场景,再把生成的 `.jsonl` 复制到场景目录。显式 raw 模式让已提交重放 fixture 保持逐行可读,而普通部署使用后端的压缩默认值。逐事件追加具有持久性,但 harness 会在采集前优雅关闭子进程(关闭 stdin → `await ctx.dispose()`),以确保最终事件已刷出。`llm-replay` 本身不执行记录——它只负责重放。 -回放使用 `cordis.snapshot.yml` 覆盖配置,将真实适配器替换为 `llm-replay`,同时保留活跃的组合。录制使用普通配置和 harness 提供的持久化根目录。回放模式跳过 `.env` 加载,因此一个意外存在的 API key 不会触发真实调用。见[单源配置 RFC](2026-07-04-single-source-acp-replay-config.md)。 +重放使用 `cordis.snapshot.yml` overlay,以 `llm-replay` 替换真实 adapter,同时保留实时组合。记录使用普通配置和由 harness 提供的持久化根目录。重放模式跳过 `.env` 加载,因此意外存在的 API 密钥不会触发实时调用。参见[单一来源配置 Agent Note](2026-07-04-single-source-acp-replay-config.md)。 ### 两个表面:归一化后比对 快照运行断言**两个**归一化后的表面,因为 harness 的外部表面是不同的: -1. **stdout transcript**——编辑器看到的带帧 `session/update` JSON-RPC。捕获 ACP bridge 事件→update 转换(`streamSessionEventUpdate`)中的回归。与已提交的 `stdout.golden.jsonl` 比对。 -2. **重新持久化的会话 JSONL**,归一化后与 `session.jsonl` 比对。同一份 fixture 既是回放源也是预期日志。提示词文本被擦除;每个 header 类别一个场景固定可读的 prompt 和 tool 内容,见 [header-pinning RFC](2026-07-06-pin-request-header-content-in-one-scenario.md)。覆盖场景的模型行为完全来自其伴随文件。 +1. **stdout transcript**——编辑器看到的、经过 framing 的 `session/update` JSON-RPC。用于捕获 ACP bridge 中事件→更新转换(`streamSessionEventUpdate`)的回归。与已提交的 `stdout.expected.jsonl` 比较。 +2. **重新持久化的 session JSONL**,经过规范化后与 `session.jsonl` 比较。同一 fixture 同时作为重放来源和预期日志。Prompt 文本会被清理;按照[请求头固定 Agent Note](2026-07-06-pin-request-header-content-in-one-scenario.md)所述,每种请求头类别由一个场景固定可读 prompt 与工具内容。Override 场景仅从其 sidecar 派生模型行为。 两个表面互补:stdout 覆盖 bridge 投影,JSONL 覆盖投影所省略的 loop、tool 和 boundary 结构。 -归一化替换 session、cwd、protocol-id、时间戳、路径和进程相关的易变值,同时保留确定性序列号。场景将真实 bash 使用限制在稳定命令范围内。stdout golden 保持协议格式(wire format)的 JSONL,每一行原始数据必须可解析为 JSON。Vitest 只更新 stdout golden;归一化后的会话相等性检查从不覆盖回放 fixture。 +规范化会替换 session、cwd、协议 id、时间戳、路径和进程易变值,同时保留确定性序号。场景把真实 bash 使用限制在稳定命令上。stdout 预期输出仍是线协议形状的 JSONL,每个原始行都必须可解析为 JSON。Vitest 只更新 stdout 预期输出;规范化 session 相等性检查从不覆盖重放 fixture。 ### 隔离:当前靠归一化,后续可加沙箱 -工具的确定性来自临时 cwd、擦除的环境变量、全新的非登录 shell、受限命令和归一化。它不声称具备操作系统级隔离。如果需要更强的隔离层级,可通过既有的[能力 seam](../architecture/2026-06-13-capability-seams.md) 将沙箱执行器替换本地后端。 +工具确定性来自生成的 cwd、清理后的环境、全新的非登录 shell、受限命令和规范化。cwd 默认为平台临时目录;当临时目录是始终可写的策略根,而行为需要独立项目位置时,场景可以改为提供其父目录。并发重放运行各自拥有独立 cwd、持久化目录和由定长场景键区分的 spill 根目录,因此一个场景的拆除无法删除另一个场景仍在进行的完整输出恢复,同时真实路径预览预算保持稳定。该层不声称提供 OS 级隔离。如果需要更强层级,sandbox executor 可以通过现有[能力接缝](../architecture/2026-06-13-capability-seams.md)替换本地后端。 ### 回放插件是独立的包 @@ -67,16 +69,16 @@ Status: implemented ### 两个子命令,回放在默认门禁中 -`pnpm run test:snapshot` 无需密钥地回放已提交的 fixture;`test:snapshot:record` 使用真实 API 并重写采集到的会话日志和 stdout golden。fixture 缺失时立即报错。每个场景携带 `input.json`、`stdout.golden.jsonl` 和 `session.jsonl`;无模型场景使用仅含 header 的日志。`replay.override.json` 仅在标记为 `overridden` 的场景中必需,因为它的存在会替换推导出的回放。fixture 守卫拒绝缺失、不匹配和遗留的文件。两个命令均接受场景过滤器。 +`pnpm run test:snapshot` 无需密钥即可重放已提交 fixture;`test:snapshot:record` 使用真实 API,并重写采集的 session log 与 stdout 预期输出。缺少 fixture 时会响亮失败。每个场景都包含 `input.json`、`stdout.expected.jsonl` 和 `session.jsonl`;不调用模型的情况使用仅有请求头的日志。只有标记为 `overridden` 的场景才需要 `replay.override.json`,因为它一旦存在就会取代派生重放。Fixture 守卫会拒绝缺失、不匹配和孤立文件。两个命令都接受场景过滤器。 ## 曾考虑的替代方案 -- **手工编写的模型 chunk `llm.json`**:早期草案的做法。复用真实会话日志使 fixture 成为系统的真实产物而非手工构建的 mock,并兼作行为 golden。 +- **手工编写包含模型 chunk 的 `llm.json`**——早期草案;复用真实 session log,使 fixture 成为系统的真实产物而非手工构建的 mock,并让它同时充当行为预期输出。 - **字节级 HTTP 录制库(Polly/nock/MSW)**:否决。与适配器耦合,处理流式 SSE(Server-Sent Events)时笨拙,且层级低于被测对象。 - **从 `turn/end {kind:'error'|'aborted'}` 合成 throw/cancel 条目**:否决。这会将 `llm-replay` 耦合到 loop 内部的轮次关闭语义,且 `turn/end` 原因是有损的(无法区分抛出的 401 与 finish-error);显式的 `replay.override.json` 伴随文件是更清晰的 seam。 ## 后果 -新测试层为每个场景增加了经评审的 input、session、stdout、可选 override 和可选 workspace fixture。workspace 种子在录制和回放时都会被复制到临时 cwd。作为回报,该层通过真实的 Loader 和 tool 组合提供确定性的无密钥 transcript 覆盖。子进程、input、workspace、归一化和回放 harness 可以支持 ACP 之外的示例。 +新测试层为每个场景增加经过评审的输入、session、stdout、可选 override 和可选 workspace fixture。记录与重放都会把 workspace seed 复制到生成的 cwd。作为回报,该层通过真实 Loader 和工具组合提供确定性的无密钥 transcript 覆盖。子进程、输入、workspace、规范化和重放 harness 也可以支持 ACP 之外的示例。 -本 RFC 与[拟议的确定性 RFC](../../proposed/testing/2026-06-11-deterministic-and-stress-testing.md) 相关但不取代它:该提案的「通用回放 fixture」在每次测试后重新推导会话的*消息历史*(一项内部一致性不变式),而快照测试固定的是*外部协议输出*。二者互补:一个守护事件溯源不变式,另一个守护面向编辑器的契约。 +本 Agent Note 与[拟议的确定性 Agent Note](../../proposed/testing/2026-06-11-deterministic-and-stress-testing.md)相关,但不取代它:该提案的“通用重放 fixture”在每次测试后重新派生 session *消息历史*(内部一致性不变量),而快照测试固定*外部协议输出*。两者相互补充——一个守护事件溯源不变量,另一个守护面向编辑器的契约。 diff --git a/.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml b/.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml index bb98e02fd7..4a14127a76 100644 --- a/.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.i18n.yaml @@ -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 -2026-06-19-real-api-e2e-ci.md: cc3e14e2d411dfa4cc68132f649f4ed26ab1de1d -2026-06-19-real-api-e2e-ci.zh.md: 58a2a87541fd5b73b8272aa729f9dd09a429e4b4 +2026-06-19-real-api-e2e-ci.md: a9289980ada8ab6390b5daa488f07ec258db1bd5 +2026-06-19-real-api-e2e-ci.zh.md: 2e8f9fff5cdbada2b1ebfd45c4b3ebbc10630f09 diff --git a/.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md b/.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md index 58a2a87541..2e8f9fff5c 100644 --- a/.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md +++ b/.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md @@ -1,4 +1,4 @@ -# RFC: 在 CI 中对外部 DeepSeek API 运行真实 API e2e 测试 +# Agent Note: 在 CI 中对外部 DeepSeek API 运行真实 API e2e 测试 Status: implemented @@ -6,11 +6,11 @@ Status: implemented ## 问题 -按照策略,harness 高度依赖真实 API 测试:[docs/testing.md](../../../testing.md) 论证了无密钥套件只能验证管道连通性而非产品本身,[ACP inject 事后分析](../../../postmortem/0001-acp-default-export-drops-inject.md)是现成的证据——178 个无密钥测试全绿,而真实编辑器会话一启动就崩溃。真实 API e2e 套件(`pnpm run test:e2e`,即 `*.e2e.ts` 文件)正是为弥合这一差距而存在的:它驱动 agent(智能体)对接实时 DeepSeek API——真实模型调用、真实 bash 工具、多轮次对话、恢复、ACP-over-stdio。 +根据策略,harness 高度依赖真实 API 测试:[docs/testing.md](../../../../docs/testing.md) 指出,无密钥套件证明的是管线,而非产品;[ACP(Agent Client Protocol)inject 事后分析](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md)则是常设证据——178 项无密钥测试保持绿色时,真实编辑器 session 却立即崩溃。真实 API e2e 套件(`pnpm run test:e2e`,即 `*.e2e.ts` 文件)的存在正是为了弥合这一缺口:它针对实时 DeepSeek API 驱动 agent(智能体)——真实模型调用、真实 bash 工具、多 turn、恢复、ACP-over-stdio。 默认门禁([.github/workflows/ci.yml](../../../../.github/workflows/ci.yml))刻意无密钥:不携带 secret,可供 fork 运行。`test:e2e` 在无密钥时自动跳过(`describe.skipIf(!process.env.DEEPSEEK_API_KEY)`),因此将其加入该工作流只会报绿而不会真正执行真实套件。要让真实 API 覆盖率成为合并信号,需要一个独立的、携带 secret 的工作流。 -本 RFC 记录的决策是:添加一个**第二个、消费 secret 的工作流**来在 CI 中运行真实 API 套件。由于这是向一个未来可能公开的仓库引入首个 CI secret,属于安全/隔离决策,本文同时记录其依赖的威胁模型以及仓库公开后的变化。 +本 Agent Note(agent 决策记录)记下了新增**第二条消费 secret 的工作流**以在 CI 中运行真实 API 套件的决策;由于向未来可能公开的仓库引入第一个 CI secret 属于安全/隔离决策,本文也记录其依赖的威胁模型,以及仓库公开时需要做出的变更。 ## 决策 @@ -22,7 +22,7 @@ ci.yml 的价值在于它无密钥、可 fork、始终为绿:任何贡献者 ### 约束不是成本,而是可靠性 -内部推理(inference)成本不是限制因素,因此工作流以覆盖率和信号为优化目标。它在多个触发条件和每个可信 PR(Pull Request)上运行所有匹配的 `*.e2e.ts` 文件,落实 [docs/testing.md](../../../testing.md) 的有密钥策略。 +内部推理成本不是限制因素,因此工作流针对覆盖面和信号优化。它会在多种触发条件和每个受信任 PR(Pull Request)上运行所有匹配的 `*.e2e.ts` 文件,以落实 [docs/testing.md](../../../../docs/testing.md) 的有密钥策略。 ### 触发条件:仅限可信事件 @@ -58,6 +58,8 @@ repo secret 命名为 `DEEPSEEK_API_KEY_EXTERNAL`;映射到适配器和测试 job 仅在 Node 24 上运行 `test:e2e`;无密钥门禁和版本兼容性属于主 CI 工作流。测试通过 workspace paths 映射以未构建形式运行,使用有界的可配置 worker 池、逐测试重试和 job 超时。被取代的 PR 运行会被取消,而 push 和 schedule 运行完整执行以提供合并后信号。 +DeepSeek 原生 `web_search` 探测已注册但会跳过。实时 Anthropic 兼容端点可能返回成功响应却没有结构化来源块,因此对来源存在性的正向断言不是可靠的合并信号;单元覆盖率仍会固定响应解析,但 CI 不会证明实时来源块的线协议形状。 + ## 安全性 仓库的首个 CI secret 需要一份记录在案的威胁模型,因为同仓库 PR、fork PR 和 Dependabot PR 的访问权限各不相同,且仓库公开后会发生变化。 @@ -95,6 +97,6 @@ job 仅在 Node 24 上运行 `test:e2e`;无密钥门禁和版本兼容性属 新增一个 CI 工作流和仓库的首个需要维护的 secret。真实 API 套件现在作为合并门禁(可信 PR 上的合并前门禁、主分支上的合并后门禁)并每夜运行,因此 agent 与外部 API 交互中的真实故障会在 CI 中浮现,而非仅在开发者的本地运行中出现——代价是每个可信 PR 和合并都会产生真实的(但内部免费的)API 调用。preflight 使 secret 配置错误变为自我通告而非静默禁用安全网。 -本设计携带一个记录在案的约束面:`pull_request` 触发器的密钥暴露权衡(移除以加固)、`if:` 门禁对基于作者的 Dependabot 判断的依赖,以及对 `pull_request_target` 的硬性禁止。上述公开清单是运维伴侣——本 RFC 是未来维护者在更改触发器集合或翻转仓库可见性之前应重读的地方,而非从头重新推导 fork/secret 模型。 +该设计带有已记录的约束表面:`pull_request` 触发器在密钥暴露方面的取舍(删除它可加强防护)、`if:` 门禁对基于作者的 Dependabot 检查的依赖,以及对 `pull_request_target` 的严格禁止。上方公开仓库检查清单是操作配套——未来维护者在更改触发器集合或切换仓库可见性之前,应重新阅读本 Agent Note,而不是从头推导 fork/secret 模型。 schedule 触发器在仓库不活跃 60 天后会自动禁用(GitHub 行为);push/PR/dispatch 是后备,活跃的 monorepo 不会触及此限制。假设 runner 对 `https://api.deepseek.com` 有出站连通性——GitHub 托管的 `ubuntu-latest` 具备此条件;受出站限制的自托管 runner 需要在依赖每夜运行之前确认连通性。 diff --git a/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.i18n.yaml b/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.i18n.yaml index 5f59fbacf1..e01a578a83 100644 --- a/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.i18n.yaml @@ -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 -2026-06-20-remove-redundant-snapshot-log-goldens.md: 18d0a4491eb10a3b4dc56d3d63285c219ba6a00a -2026-06-20-remove-redundant-snapshot-log-goldens.zh.md: 5675c69862b6052ed3f3e4710461cc1478b9fa7d +2026-06-20-remove-redundant-snapshot-log-expected-output.md: c2452f971d3cb76dceb766072dbc0a5c81465e78 +2026-06-20-remove-redundant-snapshot-log-expected-output.zh.md: b584bfa0154c71c1bbb683c3041dc7baf7a3548e diff --git a/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.md b/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.md index b17ecad098..c2452f971d 100644 --- a/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.md +++ b/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-06-20-remove-redundant-snapshot-log-expected-output.zh.md) + ## Problem Model-driving ACP snapshot scenarios ship both `session.jsonl` and `session.expected.jsonl`. For normal recorded scenarios, `session.jsonl` is the replay fixture harvested from a real run, and the replay test normalizes the newly persisted log and compares it to `session.expected.jsonl`. In the current fixtures, the two normalized logs are identical for ordinary recorded scenarios. diff --git a/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.zh.md b/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.zh.md index 5675c69862..b584bfa015 100644 --- a/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.zh.md +++ b/.agents/notes/implemented/testing/2026-06-20-remove-redundant-snapshot-log-expected-output.zh.md @@ -1,24 +1,24 @@ -# RFC: 使用 `session.jsonl` 作为唯一的快照会话日志产物 +# Agent Note: 使用 `session.jsonl` 作为唯一的快照会话日志产物 Status: implemented -[English](2026-06-20-remove-redundant-snapshot-log-goldens.md) | 中文 +[English](2026-06-20-remove-redundant-snapshot-log-expected-output.md) | 中文 ## 问题 -模型驱动的 ACP(Agent Client Protocol)快照场景同时包含 `session.jsonl` 和 `session.golden.jsonl`。对于普通录制场景,`session.jsonl` 是从真实运行中采集的回放 fixture(测试前置数据),回放测试对新持久化的日志做归一化后与 `session.golden.jsonl` 比较。在当前 fixture 中,普通录制场景的归一化录制日志与归一化 golden 完全一致。 +驱动模型的 ACP(Agent Client Protocol)快照场景同时包含 `session.jsonl` 和 `session.expected.jsonl`。对于普通记录场景,`session.jsonl` 是从真实运行采集的重放 fixture(测试前置数据);重放测试会规范化新持久化的日志,并将其与 `session.expected.jsonl` 比较。在当前 fixture 中,普通记录场景的两份规范化日志完全相同。 -手工编写的覆盖场景(`error-finish`、`cancel`)目前使用 `replay.override.json` 驱动模型行为,并保留 `session.jsonl` 作为最小占位 fixture,而 `session.golden.jsonl` 存放预期的持久化日志。覆盖文件是一个 `ReplayEntry` 对象的 JSON 数组:`{ "kind": "chunks", "chunks": StreamChunk[] }`、`{ "kind": "throw", "chunks": StreamChunk[], "message": string, "code": string, "status"?: number }` 或 `{ "kind": "hang" }`。这种拆分同样是多余的:当覆盖 sidecar 存在时,`llm-replay` 会替换派生脚本,不需要从 `session.jsonl` 获取模型分片,因此 `session.jsonl` 仍可作为该场景的预期会话日志产物。 +手工编写的 override 场景(`error-finish`、`cancel`)目前使用 `replay.override.json` 驱动模型行为,并把 `session.jsonl` 保留为最小 dummy fixture,而 `session.expected.jsonl` 存放预期的持久化日志。override 文件是由 `ReplayEntry` 对象组成的 JSON 数组:`{ "kind": "chunks", "chunks": StreamChunk[] }`、`{ "kind": "throw", "chunks": StreamChunk[], "message": string, "code": string }` 或 `{ "kind": "hang" }`。这种拆分同样没有必要:override sidecar 存在时,`llm-replay` 会替换派生脚本,不需要从 `session.jsonl` 取得模型 chunk,因此 `session.jsonl` 仍可作为场景的预期 session log 产物。 ## 决策 -彻底移除 `session.golden.jsonl` 概念。每个场景最多只有一个提交到仓库的会话日志产物,即 `session.jsonl`: +彻底移除 `session.expected.jsonl` 概念。每个场景最多只有一个已提交 session log 产物,即 `session.jsonl`: - 对于录制场景,`session.jsonl` 仍是原始采集的日志。回放仍从中派生模型分片,快照测试将回放运行归一化后的持久化日志与归一化后的 `session.jsonl` 进行比较。 - 对于手工编写的覆盖场景,`replay.override.json` 驱动模型行为,`session.jsonl` 存放预期产出的会话日志。当覆盖文件存在时,回放适配器不从 fixture 获取模型分片,因此同一个文件既可作为预期日志,又不影响回放行为。 - 对于无模型场景,`session.jsonl` 可保留为引导 `llm-replay` 所需的最小 fixture;除非场景创建了持久化会话,否则无需进行会话日志比较。 -stdout golden 保持不变;它们是面向编辑器的投影,与会话 fixture 不构成冗余。 +Stdout 预期输出保持不变;它们是面向编辑器的投影,与 session fixture 并不重复。 ## 曾考虑的替代方案 @@ -26,11 +26,11 @@ stdout golden 保持不变;它们是面向编辑器的投影,与会话 fixtu ## 验证 -`session.golden.jsonl` 在快照 harness、fixture、遗留文件守卫和文档中均不再出现;快照测试对每个模型场景都从 `session.jsonl` 派生预期会话日志;手工编写的 sidecar 场景将预期产出的日志作为 `session.jsonl` 提交,并以 `replay.override.json` 作为模型行为覆盖;遗留 fixture 守卫知道每种场景类型需要哪些文件。[ACP 快照测试 RFC](../../implemented/testing/2026-06-19-acp-snapshot-tests.md) 描述了精简后的 fixture 集合。 +快照 harness、fixture、孤立项守卫和文档中都不再出现 `session.expected.jsonl`;对于每个模型场景,快照测试都从 `session.jsonl` 派生预期 session log;手工编写 sidecar 的场景把预期生成日志提交为 `session.jsonl`,并以 `replay.override.json` 覆盖模型行为;孤立 fixture 守卫知道每种场景类型所需的文件。[ACP 快照测试 Agent Note(agent 决策记录)](2026-06-19-acp-snapshot-tests.md)描述了精简后的 fixture 集合。 ## 后果 -评审者失去了一个让预期持久化日志在视觉上与回放 fixture 分离的产物名称。stdout golden 仍保护编辑器 transcript(文本记录),将回放输出与 `session.jsonl` 比较则在不重复文件的前提下保留了循环/持久化的回归检查。 +评审者失去了一个能在视觉上区分预期持久化日志与重放 fixture 的产物名。stdout 预期输出仍然保护编辑器 transcript(文本记录),而将重放输出与 `session.jsonl` 比较,无需复制文件即可保留循环/持久化回归检查。 ## 实现说明 diff --git a/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml b/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml index cfae43ecf0..3ad2200f26 100644 --- a/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.i18n.yaml @@ -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 -2026-06-22-fork-child-replay-seed-boundary.md: 28ce76309da2dca7076dd11211229a0631d11db3 -2026-06-22-fork-child-replay-seed-boundary.zh.md: 92b60589b4cfe9668a1542405693cec8d29eceaf +2026-06-22-fork-child-replay-seed-boundary.md: d3cbbb1dae1d64a10973bd5895ccc47d877eba28 +2026-06-22-fork-child-replay-seed-boundary.zh.md: 7137256f0e1f34a2da928b966d170d054f18ddde diff --git a/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md b/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md index 92b60589b4..7137256f0e 100644 --- a/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md +++ b/.agents/notes/implemented/testing/2026-06-22-fork-child-replay-seed-boundary.zh.md @@ -1,4 +1,4 @@ -# RFC: 持久化 seed 边界以确保 fork 子会话回放正确路由 +# Agent Note: 持久化 seed 边界以确保 fork 子会话回放正确路由 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -[逐会话快照回放 RFC](2026-06-22-subagent-snapshot-replay.md) 让快照层表达了嵌套 agent(智能体)的形状:一个父会话加上每个进程内 subagent 各一份已录制的日志,各自作为独立脚本回放、以调用方会话为键。该 RFC 指出(§ Scope 末尾条目)fork 快照是「一个平凡的后续补充,不是键控方案的缺口」。这对 fork 子会话而言是错的——问题不在键控,而在*脚本推导*。 +[逐 session 快照重放 Agent Note(agent 决策记录)](2026-06-22-subagent-snapshot-replay.md)使快照层能够表达嵌套 agent 形状:一个父项加上每个进程内 subagent 的一份记录日志,每份日志都按调用 session 作为键,以独立脚本重放。它曾指出(§ 范围,最后一个项目符号),fork 快照“只是未来很容易添加的一项,并非键控缺口”。这一判断对 fork 子项而言是错误的——问题不在键控,而在*脚本派生*。 subagent 脚本由 [`deriveReplayScript`](../../../../packages/support/llm-replay) 从已录制的会话日志推导:它按 `(turn, step)` 对日志中的 `assistant/chunk` 事件分组,每次 `stream()` 调用对应一条回放条目。对 **spawn** 子会话而言这是正确的,因为其日志只包含自身的模型调用。 diff --git a/.agents/notes/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml b/.agents/notes/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml index e487e40249..fd59b8dff8 100644 --- a/.agents/notes/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-06-22-fork-snapshot-scenarios.i18n.yaml @@ -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 -2026-06-22-fork-snapshot-scenarios.md: a5324cbfa13b79c0ea60b74b689f1b19db99a725 -2026-06-22-fork-snapshot-scenarios.zh.md: 543382db86eb50b5f278a99de74586a13bff9eb7 +2026-06-22-fork-snapshot-scenarios.md: 46c688a4095a1d8af32b3b99887929f71a1526ce +2026-06-22-fork-snapshot-scenarios.zh.md: afeb495e480a601656fc551a478e0e40c579cfd5 diff --git a/.agents/notes/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md b/.agents/notes/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md index 543382db86..afeb495e48 100644 --- a/.agents/notes/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md +++ b/.agents/notes/implemented/testing/2026-06-22-fork-snapshot-scenarios.zh.md @@ -1,4 +1,4 @@ -# RFC: 记录 fork 与混合 spawn+fork 快照场景 +# Agent Note: 记录 fork 与混合 spawn+fork 快照场景 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -[seed-boundary RFC](2026-06-22-fork-child-replay-seed-boundary.md) 使 fork 子会话的回放路由正确运作:`dsh-llm-replay` 从子会话持久化的 `seedLength` 边界处或之后的事件推导出子会话的脚本,因此 fork 子会话继承的父会话前缀不会被当作子会话自身的模型调用来回放。但该 RFC 交付时**没有记录 fork 场景**——该切片仅由 `llm-replay` 的单元测试(一个合成的子会话 fixture(测试前置数据))和一个持久化往返测试覆盖。全 transcript(文本记录)快照层(即启动真实 `acp-agent` 并回放端到端嵌套 transcript 的那张网)只有 spawn 子会话(`subagent-spawn`、`subagent-multi`)。如果一个 fork 路由回归让单元测试保持绿色,它仍然会逃过专为捕获 transcript 回归而建的那一层。 +[seed 边界 Agent Note(agent 决策记录)](2026-06-22-fork-child-replay-seed-boundary.md)让 fork 子项重放能够正确路由:`dsh-llm-replay` 根据持久化 `seedLength` 边界处及其后的事件派生子项脚本,因此 fork 子项继承的父前缀不会作为子项自身的模型调用重放。但落地时**没有记录式 fork 场景**——slice 只由 `llm-replay` 单元测试(合成子项 fixture(测试前置数据))和持久化往返测试覆盖。完整 transcript(文本记录)快照层——会启动真实 `acp-agent` 并重放端到端嵌套 transcript 的那张网——只有 spawn 子项(`subagent-spawn`、`subagent-multi`)。如果 fork 路由回归没有让单元测试变红,它仍会逃过专为捕获 transcript 回归而构建的这一层。 表达 fork 场景所需的快照基础设施已经就位:两个进程内后端都在 `cordis.yml` / `cordis.snapshot.yml` 中以两个面向模型的工具接入(`subagent` → spawn、`subagent_fork` → fork),harness 会收集每个子会话的日志,回放按 `seedLength` 为键转发各子会话的 fixture。缺少的是一个*已记录的场景*来驱动 fork 子会话走完这条路径。 @@ -15,17 +15,17 @@ Status: implemented 针对真实 API 记录两个场景,均在默认门禁中以无密钥方式回放: - **`subagent-fork`**:父会话完成一个轮次以建立一个事实,然后通过 `subagent_fork` 委派一个子任务。fork 子会话继承对话(其日志携带非零 `seedLength`),因此可以从父会话的上下文中作答。这是聚焦的回归守卫:子会话 fixture 的 `seedLength` 就是回放切片所依赖的边界,来自真实 fork 的记录而非手工合成。 -- **`subagent-mixed`**:父会话完成一个轮次,然后在同一个 transcript 中分别通过 `subagent`(全新的 spawn 子会话,`seedLength` 为 0)和 `subagent_fork`(fork 子会话,`seedLength` 非零)各委派一次。这是 seed-boundary 和 per-session-replay 两份 RFC 都列为后续补充的混合 spawn+fork 场景:一个 transcript 同时覆盖两种传输方式和切片的两个分支(`seedLength` 0 = 无操作,`seedLength > 0` = 裁剪继承的前缀),两个子会话按 `createdAt` 排序为先 spawn 后 fork。 +- **`subagent-mixed`**——父项完成一个 turn,随后在同一 transcript 中通过 `subagent` 委托一次(全新 spawn 子项,`seedLength` 为 0),再通过 `subagent_fork` 委托一次(fork 子项,`seedLength` 非零)。这是 seed 边界与逐 session 重放 Agent Note 都点名作为未来新增项的 spawn+fork 混合场景:一份 transcript 覆盖两种传输方式和 slice 的两个分支(`seedLength` 为 0 = 无操作,`seedLength > 0` = 裁剪继承前缀),两个子项按 `createdAt` 排列为先 spawn、后 fork。 ### 为什么需要一个已完成的第一轮次 -fork 后端用父会话的**已完成轮次的平衡前缀**([`completedTurnPrefix`](../../../../packages/subagent/subagent-fork))来初始化子会话。如果父会话在第一轮次就 fork,则没有已完成的轮次可继承,seed 为空(等价于全新 spawn,`seedLength` 为 0),这不会覆盖切片逻辑。因此两个场景都使用双 prompt 输入:第一个 prompt 完成一个轮次(建立一个 codeword,子会话稍后被要求回忆它),第二个 prompt 委派 fork。子会话 transcript 中回忆出的 codeword 只是模型行为的附带产物;真正承载验证的产物是子会话 fixture 中记录的 `seedLength`,回放切片消费的正是它。 +fork 后端使用父项的**已配平完整 turn 前缀**为子项提供 seed。父项若在第一个 turn 就执行 fork,没有已完成 turn 可供继承,因此 seed 为空(≡ 全新 spawn,`seedLength` 为 0)——这不会覆盖 slice。因此,两个场景都使用双 prompt 输入:第一个 prompt 完成一个 turn(建立稍后要求子项回忆的 codeword),第二个 prompt 委托 fork。子项 transcript 中回忆出的 codeword 只是模型行为的附带结果;承载关键约束的产物是子项 fixture 中记录、由重放 slice 消费的 `seedLength`。 ## 后果 - fork 路由切片现在由全 transcript 层守卫,而不仅仅是单元测试。移除 `slice(seedLength)`(回放整个子会话日志)会让**两个**新场景变红——fork 子会话收到的是父会话记录的 chunk 而非自己的——证明守卫确实生效(场景落地时已验证红→绿)。 - `subagent-mixed` 是第一个在同一个 transcript 中驱动两种*不同* subagent 后端的快照场景,同时覆盖了跨 spawn 和 fork 子会话的 per-session 回放键控。 -- 进程外(ACP)subagent 回放形态不同(每个子会话是独立进程、有自己的回放),仍以 `TODO(acp-subagent-replay)` 跟踪——本文场景仅限进程内。 +- 进程外(ACP(Agent Client Protocol))subagent 回放形态不同(每个子会话是独立进程、有自己的回放),仍以 `TODO(acp-subagent-replay)` 跟踪——本文场景仅限进程内。 - 重新录制(`pnpm run test:snapshot:record`)会从真实 API 重新生成全部四个 fork/spawn fixture;两个新场景在无密钥时自动跳过,与所有已录制场景一致。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml b/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml index c8d42599e1..479d521c97 100644 --- a/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.i18n.yaml @@ -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 -2026-06-22-subagent-snapshot-replay.md: 89fc4e8d4d267fd4df373a7fd82b8c6e742be6ea -2026-06-22-subagent-snapshot-replay.zh.md: 7dc234ab9c6e3bb1facd78e98aad15005d158325 +2026-06-22-subagent-snapshot-replay.md: 4aad8b6ddd3e4f8b8ad5565e10b263953d81ea31 +2026-06-22-subagent-snapshot-replay.zh.md: 9d31e4d7f8e65b8442a94dee154ff1d3a5631651 diff --git a/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md b/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md index 7dc234ab9c..9d31e4d7f8 100644 --- a/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md +++ b/.agents/notes/implemented/testing/2026-06-22-subagent-snapshot-replay.zh.md @@ -1,4 +1,4 @@ -# RFC: 嵌套 agent 的逐会话快照回放 +# Agent Note: 嵌套 agent 的逐会话快照回放 Status: implemented @@ -6,14 +6,14 @@ Status: implemented ## 问题 -快照测试层(`pnpm run test:snapshot`)启动真实的 `acp-agent` 子进程,通过 [`dsh-llm-replay`](../../../../packages/support/llm-replay) 回放录制的会话,并将归一化后的 stdout transcript(文本记录)与重新持久化的会话日志对已提交的金标文件做 diff。这是唯一一个端到端验证完整编辑器侧 transcript 的测试层。 +快照层(`pnpm run test:snapshot`)会启动真实 `acp-agent` 子进程,通过 [`dsh-llm-replay`](../../../../packages/support/llm-replay) 重放已记录 session,并将规范化 stdout transcript(文本记录)+ 重新持久化的 session log 与已提交预期输出进行 diff。它是唯一端到端覆盖完整面向编辑器 transcript 的测试层。 该层最初为每个进程只有一个会话而构建,这一假设硬编码在两处: -- **`dsh-llm-replay` 没有做任何键控。** 它用一个全局游标,将第 N 次 `llm/stream` 调用对应到单一录制序列的第 N 条。当父 agent 和一个进程内 subagent 在同一个上下文上同时流式输出时,调用交错,单一游标会把子 agent 的脚本发给父 agent(反之亦然)。 +- **`dsh-llm-replay` 没有做任何键控。** 它用一个全局游标,将第 N 次 `llm/stream` 调用对应到单一录制序列的第 N 条。当父 agent(智能体)和一个进程内 subagent 在同一个上下文上同时流式输出时,调用交错,单一游标会把子 agent 的脚本发给父 agent(反之亦然)。 - **harness 只收集一份日志。** `findSessionLog` 遍历 sessions 根目录,返回找到的第一个 `.jsonl`。subagent 作为第二个 `Session` 运行,在同一个 cwd bucket 下有自己的日志,因此子 agent 的 transcript 被静默丢弃。 -这就是 [subagent seam RFC](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 中记录的 `TODO(subagent-snapshots)` 延期项:进程内后端(PR2)已有单元测试和 e2e 覆盖,但全 transcript 快照层在本基础设施就绪之前无法表达嵌套 agent 的形态。本 RFC 即为该堆叠后续。 +这就是 [subagent 接缝 Agent Note(agent 决策记录)](../feature/2026-06-21-subagent-capability-seam.md)中通过 `TODO(subagent-snapshots)` 推迟的工作:进程内后端(PR2)落地时已有单元 + e2e 覆盖,但在这套基础设施落地前,完整 transcript 快照层无法表达嵌套 agent 形状。本 Agent Note 就是该堆叠式后续工作。 ## 决策 @@ -55,4 +55,4 @@ Status: implemented - `TODO(subagent-snapshots)` 延期项已解决:嵌套 agent 的 transcript 现在是快照层的一等形态。 - `GenerateOptions.sessionId` 是一个小而诚实的 core-seam 新增,在回放之外同样有用(遥测、请求路由)。 - `subagent` 工具绑定到单一提供方,因此 `subagent-multi` 中的两个子 agent 都是 spawn(全新创建)。键控按会话路由而非按后端路由,因此对 fork 同样正确。但脚本*派生*逻辑此前不正确:fork 子会话的日志以种子化的父前缀(父会话的 `assistant/chunk` 事件)开头,如果从完整日志派生脚本,就会把父 agent 的响应当作子 agent 的来回放。这一正确性缺口通过持久化种子边界来弥合——见 [Persist the seed boundary so fork-child replay routes correctly](2026-06-22-fork-child-replay-seed-boundary.md)——录制的 fork 与混合 spawn+fork 场景现在通过一份 transcript 同时验证两种传输方式(见 [Record fork and mixed spawn+fork snapshot scenarios](2026-06-22-fork-snapshot-scenarios.md))。 -- 进程外(ACP)subagent 是完全不同的回放形态(每个子 agent 是自己的进程、有自己的回放),作为 `TODO(acp-subagent-replay)` 记录在 PR3 计划中。 +- 进程外(ACP(Agent Client Protocol))subagent 是完全不同的回放形态(每个子 agent 是自己的进程、有自己的回放),作为 `TODO(acp-subagent-replay)` 记录在 PR3 计划中。 diff --git a/.agents/notes/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml b/.agents/notes/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml index 8c06af4e98..fd07ac1419 100644 --- a/.agents/notes/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-07-04-hook-snapshot-matrix.i18n.yaml @@ -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 -2026-07-04-hook-snapshot-matrix.md: b365992c01e081e5698e81a9ff9682e9b8166ce6 -2026-07-04-hook-snapshot-matrix.zh.md: bcb8e5ba55a14dd0c299dac161146a19f18201eb +2026-07-04-hook-snapshot-matrix.md: ceb91a70e1f9582cf2a7cb4cec0ba8aaf5699b8e +2026-07-04-hook-snapshot-matrix.zh.md: 0e2318d48dbd0200c04dd35decf8046ed6ecce9f diff --git a/.agents/notes/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md b/.agents/notes/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md index bcb8e5ba55..0e2318d48d 100644 --- a/.agents/notes/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md +++ b/.agents/notes/implemented/testing/2026-07-04-hook-snapshot-matrix.zh.md @@ -1,4 +1,4 @@ -# RFC: Hook 快照矩阵——覆盖两种 bridge 的端到端 golden 测试 +# Agent Note: Hook 快照矩阵——覆盖两种 bridge 的端到端 预期输出 测试 Status: implemented @@ -6,7 +6,7 @@ Status: implemented ## 问题 -hook bridge——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude)(7 个 Claude Code hook 点)和 [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex)(5 个 Codex 点)——将外部 hook 命令映射到 harness 的拦截 seam 上。它们拥有深度的单元测试和 coverage-spec 覆盖率(每个决策分支、每种 payload 方言,均对 mock 的 seam 驱动),外加一个需要密钥的 e2e 测试(`hooks.e2e.ts`,一次真实的 `PreToolUse` 拦截)。但完整 transcript(文本记录)快照层:那张真正启动 `acp-agent` 子进程、无密钥回放录制会话、并将规范化的 ACP stdout 与重新持久化的日志与已提交 golden 做 diff 的网,只覆盖了一个 hook:Claude 的 `UserPromptSubmit` 拦截(`hook-cc-promptsubmit-block`)。 +hook bridge——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude)(7 个 Claude Code hook 点)和 [`dsh-hooks-codex`](../../../../packages/hooks/hooks-codex)(5 个 Codex 点)——把外部 hook 命令映射到 harness 拦截接缝。它们有深入的单元与覆盖率规格覆盖(每个决策分支、每种 payload dialect,针对 mock 接缝驱动),外加一个受密钥门控的 e2e(`hooks.e2e.ts`,实时 `PreToolUse` 阻止)。但完整 transcript(文本记录)快照层——会启动真实 `acp-agent` 子进程、无需密钥重放已记录 session,并将规范化 ACP(Agent Client Protocol)stdout + 重新持久化日志与已提交预期输出进行 diff 的那张网——只覆盖了一个 hook:Claude `UserPromptSubmit` 阻止(`hook-cc-promptsubmit-block`)。 这正是 mock 单元测试在结构上无法替代的层级:它验证的是真实 bridge 将真实 hook 进程的结果翻译到真实 seam 决策,再到真实 agent loop(智能体循环)的反应,渲染结果与编辑器看到的完全一致。一个 bridge 翻译或 loop 结构的回归,即使让所有单元测试保持绿色,也会在除那一个 hook 点之外的所有点上逃逸;而对于 Codex bridge,ACP 示例甚至没有加载它,因此没有任何 Codex hook 能端到端触发。 @@ -31,20 +31,22 @@ hook bridge——[`dsh-hooks-claude`](../../../../packages/hooks/hooks-claude) 每个 hook 命令只输出固定字面量字符串(无时间戳/pid/`$RANDOM`/cwd 回显);快照规范化器擦除 `hook/result` 携带的唯一不稳定字段(`durationMs`)。`Stop` 场景通过标记文件(`.stop_fired`)自限,使 force-continue 不会循环——`stop_hook_active` 循环守卫仍是 bridge 的一个 `TODO`,因此无条件的 Stop hook 会在每一步都 force-continue。 +`PostToolUse` 阻止场景会在其证明的机制处自行限制。Claude hook 在首次拒绝后持久化一个 workspace 标记,因此允许一次恢复调用;Codex prompt 发起一次调用并报告注入结果。每份预期输出固定一次遭阻止调用,不会重复阻止/重试循环。 + ### 三个 hook 点被有意排除在快照之外 在构建矩阵过程中发现,记录于此是因为这些遗漏是决策而非疏忽: -- **`SessionStart` 与 `SubagentStart`** 通过一个分离的、尽力而为的 `void runPoint(...).then(agent.inject())` 注入上下文,没有轮次绑定。由此产生的 `context/message` 与它所先于的工作(首次模型请求/子 agent 的首轮)存在竞争,落在日志中的位置不确定。录制的 golden 甚至无法在自身回放中复现——10 次回放稳定性检查对两者均 10/10 失败。它们留在 bridge 的单元覆盖率中,单元测试直接驱动 seam 而无时序竞争。(如果注入将来变为轮次绑定且确定性的——`TODO(session-start-gating)` 所指的方向——它们就可以纳入快照。) -- **`SubagentStop`** 是纯观察性的:其 `subagent/end` 处理器不传递轮次(因此无 `hook/*` 日志事件)、不做注入。它对 transcript 不写入任何内容,因此 golden 与无 hook 运行逐字节一致,永远无法被证明失败——一道永远不会触发的守卫。它留在单元覆盖率中(`bridge.spec.ts` 已断言了纯观察调用)。 +- **`SessionStart` 和 `SubagentStart`** 通过脱离且尽力而为的 `void runPoint(...).then(agent.inject())` 注入上下文,没有 turn 绑定。由此产生的 `context/message` 会与它应先于的工作(首次模型请求 / 子项的第一个 turn)竞速,并落在不确定的日志位置。记录的预期输出甚至无法在自己的重放中复现——对两者执行 10 次重放稳定性检查,结果均为 10/10 次失败。它们继续留在 bridge 的单元覆盖率中,那里会直接驱动接缝而不存在时序竞速。(如果注入未来改为绑定 turn 且具备确定性——`TODO(session-start-gating)` 所指方向——它们就能接受快照测试。) +- **`SubagentStop`** 只观察:其 `subagent/end` handler 不传递 turn(因此没有 `hook/*` 日志事件),也不执行注入。它不会向 transcript 写入任何内容,因此预期输出会与无 hook 运行逐字节相同,永远无法证明失败——一道咬不住问题的守卫。它继续由单元覆盖率负责(`bridge.spec.ts` 已断言仅观察调用)。 因此,该矩阵覆盖了所有具有确定性、可观测 transcript 足迹的 hook 点,涵盖两种方言。 ## 后果 -- 每个具有可观测 transcript 的 bridge seam 映射现在都在完整 transcript 层级、在真实应用中、对两种方言受到守护——包括此前完全没有端到端覆盖率的 Codex bridge。录制的 golden 捕获了模型对 deny/block/force-continue 轮次的真实反应,这是手工编写的 transcript 只能猜测的。 -- block 场景无需密钥(无模型轮次);其余场景从录制的 fixture(测试前置数据)无密钥回放。`pnpm run test:snapshot:record` 从真实 API 重新生成录制的 fixture,无密钥时自动跳过,与所有录制场景一致。 -- prove-red 纪律成立:篡改 hook 配置的输出(例如修改 deny 原因)会使其场景在回放时变红——hook 进程在回放期间真实运行(只有模型被回放),因此 golden 守护的是实际的 hook→seam→loop 路径,而非它的 mock。 +- 现在,两种 dialect 中每个具有可观察 transcript 的 bridge 接缝映射,都在真实应用的完整 transcript 层受到守护——包括此前完全没有端到端覆盖的 Codex bridge。记录的预期输出捕获模型对遭拒绝/遭阻止/强制继续 turn 的真实反应,而手工编写的 transcript 只能猜测这种反应。 +- `UserPromptSubmit` 阻止场景无需密钥即可编写(没有模型 turn);其余场景从已记录 fixture(测试前置数据)无需密钥重放。`pnpm run test:snapshot:record` 从实时 API 重新生成记录式 fixture,并像所有记录场景一样在缺少密钥时自行跳过。 +- 证明会变红的准则仍成立:篡改 hook 配置输出(例如改变拒绝理由)会让相应场景在重放时变红——hook 进程在重放期间真实运行(只有模型被重放),因此预期输出守护的是实际 hook→接缝→循环路径,而非其 mock。 - `acp-agent` 演示现在加载了一个通常会无操作的 Codex bridge(典型项目中没有 `codex-hooks.json`),这正是预期的柔性失败行为,而非代价。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml b/.agents/notes/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml index 733f3a2115..719884e56c 100644 --- a/.agents/notes/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-07-04-single-source-acp-replay-config.i18n.yaml @@ -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 -2026-07-04-single-source-acp-replay-config.md: 51cbd54d45408df1548c9cc2522b07b5ffaac110 -2026-07-04-single-source-acp-replay-config.zh.md: 2aec0e0e46007be243c0386fc0fca92065ce3c9e +2026-07-04-single-source-acp-replay-config.md: f270d70feca184217503c472c1cb7c536187a249 +2026-07-04-single-source-acp-replay-config.zh.md: 86eb2d3e15c4939d1de3a78150cd0536d46e10f6 diff --git a/.agents/notes/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md b/.agents/notes/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md index 2aec0e0e46..86eb2d3e15 100644 --- a/.agents/notes/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md +++ b/.agents/notes/implemented/testing/2026-07-04-single-source-acp-replay-config.zh.md @@ -1,4 +1,4 @@ -# RFC: 将 acp-agent 回放配置改为单一来源 +# Agent Note: 将 acp-agent 回放配置改为单一来源 Status: implemented @@ -6,13 +6,13 @@ Status: implemented ## 问题 -`examples/acp-agent` 曾维护两份手写配置:`cordis.yml`(正式运行树)和 `cordis.snapshot.yml`(逐条镜像前者,仅替换 LLM(大语言模型)后端)。去掉注释后,全部差异只是八行的 `llm-deepseek` 段落换成两行的 `llm-replay` 段落。每次应用结构变更都要改两遍,且没有门禁保障对称性:一旦两份副本漂移,快照层就会悄悄测试一个与实际交付不同的应用——正是快照层本要消除的["单元测试全绿、产品却坏了"这类缺口](../../../postmortem/0001-acp-default-export-drops-inject.md),在上一层被重新引入,唯一的防线是评审者的警觉。 +`examples/acp-agent` 发布了两份手工维护的配置:`cordis.yml`(实时树)和逐条镜像它、只替换 llm 后端的 `cordis.snapshot.yml`——去除注释后,两者的全部差异就是八行 `llm-deepseek` stanza 与两行 `llm-replay` stanza。每次应用形状变化都必须修改两遍,也没有任何机制约束对称性:如果副本发生漂移,快照层会悄然覆盖与已发布应用不同的应用——快照层本就是为了弥合[“单元测试绿色,产品损坏”这类缺口](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md),如今同类缺口在上一层重新出现,只能依靠评审者警惕。 ## 决策 `cordis.snapshot.yml` include 正式配置,通过 id 和 name 禁用指定的 DeepSeek 适配器,并插入回放适配器。其余所有条目因此来自正式运行树。回放时选择 overlay;录制仍然启动 `cordis.yml`,加载守卫允许被有意禁用的条目。 -overlay 依赖一个 vendor 插件的事实,这是有意为之:include 在加载文件时应用 `patches`,其 `refresh()`/`internal/update` 路径重读时不会重新打补丁。这恰好满足一次性回放启动的需要(回放应用不加载 `hmr`,也没有东西在运行中改写配置)。快照套件即为证明:所有场景在 overlay 上原样通过,包括逐字节一致的 golden 文件。 +overlay 有意依赖一项 vendored 插件事实:include 加载文件时会应用 `patches`,而其 `refresh()`/`internal/update` 路径会重新读取但不重新打补丁——这恰好足以满足一次性重放启动(重放应用不加载 `hmr`,运行中也没有内容重写配置)。快照套件就是证明:所有场景都能在 overlay 上原样通过,包括逐字节相同的预期输出。 ## 曾考虑的替代方案 diff --git a/.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml b/.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml index dfb09d507a..0aba628ae2 100644 --- a/.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.i18n.yaml @@ -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 -2026-07-06-pin-request-header-content-in-one-scenario.md: 0166b459fbb8d883f07fb195bdd5e025d70349de -2026-07-06-pin-request-header-content-in-one-scenario.zh.md: 1ca7df68fc743b919c6769ae8fa40ea16eb3d88a +2026-07-06-pin-request-header-content-in-one-scenario.md: bca6d9eb943e758d68efaf3a76ec367179cd15fd +2026-07-06-pin-request-header-content-in-one-scenario.zh.md: 9637602aca34977bee7c0efd5dc57b848ed93e2c diff --git a/.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md b/.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md index 1ca7df68fc..9637602aca 100644 --- a/.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md +++ b/.agents/notes/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.zh.md @@ -1,4 +1,4 @@ -# RFC: 在单个快照场景中固定请求头内容 +# Agent Note: 在单个快照场景中固定请求头内容 Status: implemented @@ -10,11 +10,11 @@ Status: implemented ## 决策 -每个 header 组合类别恰好有一个场景被标记为 `pinsHeader`。其目录按评审格式拆分固定内容:`system-prompt.golden.md` 以普通 Markdown 存放归一化后的组合提示词,`tool-schemas.golden.json` 以结构化 JSON 存放完整的初始 schema 及后续 schema 变更,而 `session.jsonl` 保留 config、reason 及任何模型可见的前缀,同时将 `header.system` 和 `header.tools` 存为 `"{{system}}"` / `"{{tools}}"`。其余所有 JSONL 使用相同的提示词和工具 token,并同样对会话前缀内容做 token 化处理。固定机制实现在 [`dsh-acp-snapshot`](../../../../packages/support/acp-snapshot/README.md) 中,其套件工厂强制每个类别只有一个固定场景。 +每种请求头组合类别恰好有一个场景标记为 `pinsHeader`。其目录按评审格式拆分固定内容:`system-prompt.expected.md` 以普通 Markdown 包含规范化的完整 prompt 序列;`tool-schemas.expected.json` 以结构化 JSON 包含对应的完整 schema 序列;`session.jsonl` 保留 config、reason 和所有模型可见前缀,同时将 `header.system` 与 `header.tools` 存为 `"{{system}}"` / `"{{tools}}"`。其他每份 JSONL 都使用相同的 prompt 与工具 token,并同样将 session 前缀内容 token 化。固定机制位于 [`dsh-acp-snapshot`](../../../../packages/support/acp-snapshot/README.md),其套件 factory 强制每种类别恰好有一个固定场景。 -纯粹的 `scrubSystemPrompts` 和 `scrubToolSchemas` 归一化器应用于每个存储的会话 fixture(测试前置数据),独立地对初始 header 内容和 header-delta 批量内容做 token 化。`scrubRequestHeaders` 还为非固定场景的会话前缀内容做 token 化,同时保留结构性事实:system-delta 的位置与数量、新增/移除/变更的工具名称、前缀消息数量、字段存在性、config 和 reason。record 与 refresh 的回写操作在写入 JSONL 前应用相应的 scrub,并从归一化后的实时 header 和 delta 重新生成两个 sidecar 文件,因此两条路径都不会把提示词/schema 批量内容重新引入 JSONL,也不会让评审产物变陈旧。 +纯 `scrubSystemPrompts` 和 `scrubToolSchemas` 规范化器会分别将每个已存储完整请求头 token 化。`scrubRequestHeaders` 还会为非固定场景把 session 前缀内容 token 化,同时保留请求头数量、字段存在性、config、reason 和前缀消息数量。记录与刷新写回会在写入 JSONL 前应用适当清理,并根据规范化的实时完整请求头序列重新生成两个 sidecar,因此两条路径都无法把大段 prompt/schema 重新引入 JSONL,也不会留下陈旧的评审产物。 -守卫机制使这一拆分自我强制。在磁盘上:每个 `session*.jsonl` 都是提示词和 schema 两个 scrubber 的不动点;只有非固定 fixture 还必须是完整 header scrub 的不动点;两个 sidecar 文件恰好存在于固定 fixture 旁边,采用规范的换行终止格式;每个类别有且仅有一个固定场景。在运行时:由 parent、spawn 子会话、fork 子会话、初始请求或 resume 产生的每个 `request/header`,在经过易变值归一化后必须与重建的固定内容匹配;固定运行的提示词和 schema delta 也必须与其 sidecar 匹配。如果 header 没有字符串类型的 prompt、没有数组类型的工具列表,或包含未声明的 `request/header-delta`,则立即失败并报错。 +守卫使这种拆分能够自我强制。在磁盘上,每个 `session*.jsonl` 都是 prompt 和 schema 清理器的固定点;只有非固定 fixture(测试前置数据)必须是完整请求头清理的固定点;两个 sidecar 恰好位于固定 fixture 旁,并采用规范、以换行符结尾的格式;每种类别都有一个固定场景。在实时运行中,由父项、spawn 子项、fork 子项、初始请求、恢复或实例内变化产生的每个 `request/header`,都必须在易变值规范化后与重建的类别序列匹配。请求头若没有字符串 prompt、没有数组值工具列表,或超过固定场景声明的变更请求头数量,就会响亮失败。 一个固定场景覆盖整个套件,因为每个会话(parent、spawn 子会话、fork 子会话)组合出的工具列表完全相同、提示词除 cwd 外完全相同,而一致性守卫会在这一前提不再成立时立即使套件失败。如果 header 组合将来在设计上变为会话相关的(例如受限的 subagent 工具集),那么分歧的形态将获得自己的固定场景。 @@ -24,11 +24,11 @@ Status: implemented - **仅在比较时 scrub,fixture 保持原始内容**:比较能通过,但已提交的 fixture 保留着陈旧的重复内容,下次录制时会整体重写。存储 token 诚实地表明每个 JSONL 没有固定什么。 - **全部 scrub,不做任何固定**:丢失了组合 header 实际发送内容(提示词组装、已注册工具顺序、完整 schema)的唯一端到端记录。生成的工具目录只孤立地记录每个工具;只有真实 fixture 才能固定组合后的完整集合。 - **将完整固定内容全部保留在 JSONL 中**:消除了套件范围的重复,但提示词和 schema 变更仍然是一行转义文本。Markdown 和结构化 JSON 为每种内容提供其自然的评审格式,同时不削弱重建 header 的断言。 -- **精简会话日志本身(记录内容摘要,将 header 存放在别处)**:违反可重建性契约:产品日志必须逐位重现每个请求([可重建请求 RFC](../architecture/2026-07-05-reconstructable-requests.md))。header 体积是测试产物的问题,在测试归一化中解决;线上日志不受影响。 +- **收窄 session log 本身(记录内容 digest,把请求头存到其他位置)**——违反可重建性契约:产品日志必须逐 bit 复现每个请求([可重建请求 Agent Note(agent 决策记录)](../architecture/2026-07-05-reconstructable-requests.md))。请求头体积是测试产物问题,应在测试规范化中解决;实时日志保持不变。 ## 验证 -套件针对拆分后的固定内容回放每个场景。单元测试覆盖率涵盖独立 scrubber 和完整 scrubber、两种 sidecar 格式、record/refresh 重新生成、归一化提示词/schema 提取、不动点强制、必需文件对称性、重建 header 一致性以及 delta 拒绝。 +该套件针对拆分后的固定内容重放每个场景。单元覆盖率会覆盖独立与完整清理器、两种完整请求头 sidecar 格式、记录/刷新重新生成、规范化 prompt/schema 提取、固定点强制、必需文件对称性、重建请求头一致性,以及变更请求头数量拒绝。 ## 后果 diff --git a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml b/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml index e8c8a129b8..7eaf1b2cc5 100644 --- a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.i18n.yaml @@ -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 -2026-07-08-shared-acp-snapshot-package.md: c378222804251761a1b04f59c35799a97a1525f1 -2026-07-08-shared-acp-snapshot-package.zh.md: cda7a578d4643800736ff159a6427d3a0e3e0fae +2026-07-08-shared-acp-snapshot-package.md: 3e5a2b12114d535490a17361128862f6d1c09a73 +2026-07-08-shared-acp-snapshot-package.zh.md: 63daf0bd8b18a5afb44161b1621ab16ff7285ba2 diff --git a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.md b/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.md index 8d6032d1cc..3e5a2b1211 100644 --- a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.md +++ b/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.md @@ -2,6 +2,8 @@ Status: implemented +English | [中文](2026-07-08-shared-acp-snapshot-package.zh.md) + ## Problem The ACP snapshot tier ([snapshot Agent Note](2026-06-19-acp-snapshot-tests.md)) was built from three modules living inside one example's test directory: `snapshot-harness.ts` (boot the real bin subprocess, drive it over ACP JSON-RPC, harvest the persisted logs), `snapshot-normalize.ts` (the pure expected-output normalizers), and the ~150-line scenario body plus fixture guards in `acp.snapshot.ts` (record/replay modes, the stdout expected-output and log comparisons, the pinned-header uniformity guard, the orphan/required-file/single-pin meta-tests). diff --git a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md b/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md index cda7a578d4..63daf0bd8b 100644 --- a/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md +++ b/.agents/notes/implemented/testing/2026-07-08-shared-acp-snapshot-package.zh.md @@ -1,4 +1,4 @@ -# RFC: 将 ACP 快照套件提取为支持包 +# Agent Note: 将 ACP 快照套件提取为支持包 Status: implemented @@ -6,33 +6,35 @@ Status: implemented ## 问题 -ACP 快照层([快照 RFC](2026-06-19-acp-snapshot-tests.md))由位于某个示例测试目录中的三个模块构成:`snapshot-harness.ts`(启动真实 bin 子进程,通过 ACP JSON-RPC 驱动它,收集持久化日志)、`snapshot-normalize.ts`(纯粹的 golden 规范化器),以及 `acp.snapshot.ts` 中约 150 行的场景主体加 fixture(测试前置数据)守卫(record/replay 模式、stdout-golden 与日志比对、pinned-header 一致性守卫、orphan/required-file/single-pin 元测试)。 +ACP(Agent Client Protocol)快照层([快照 Agent Note(agent 决策记录)](2026-06-19-acp-snapshot-tests.md))由位于一个示例测试目录内的三个模块构建:`snapshot-harness.ts`(启动真实 bin 子进程,通过 ACP JSON-RPC 驱动它,采集持久化日志)、`snapshot-normalize.ts`(纯预期输出规范化器),以及 `acp.snapshot.ts` 中约 150 行的场景主体与 fixture(测试前置数据)守卫(记录/重放模式、stdout 预期输出与日志比较、固定请求头一致性守卫、孤立项/必需文件/单一固定项元测试)。 -第二个 ACP 示例只能复制 record、规范化和收集逻辑,而这些逻辑必须保持一致。`examples/` 下的代码也不在包(package)覆盖率门禁范围内,且原始 harness 只能取消权限请求。共享包使这些机制纳入度量,并允许场景脚本化地提供审批答案。 +第二个希望获得快照覆盖的 ACP 示例——直接消费者是 sandbox/approval 组合——只能复制这些模块,恰好分叉了绝不能漂移的逻辑:记录写回、请求头清理、子 session 采集顺序。spawn/client 胶水也在 `acp.e2e.ts`、`hooks.e2e.ts` 和 harness 中重复三份。文件位置决定了测试严格度:逐文件 100% 覆盖率门禁只测量 `packages/*/*/src`,因此这些机制完全未被测量——正是同一种缺口,曾推动 `dsh-llm-replay` 从 `examples/` 移入 [packages/support](../../../../packages/support/README.md)。此外,harness 的 ACP client 硬编码 `requestPermission → cancelled`,因此 approval 往返——sandbox 组合的主打行为——完全无法在快照层表达。 ## 决策 这些机制位于 [`packages/support/acp-snapshot`](../../../../packages/support/acp-snapshot/README.md)(`@deepseek-ai/dsh-acp-snapshot`);示例的 `*.snapshot.ts` 只包含场景表、agent 路径和一次工厂调用,依赖自己的 `snapshots/` fixture 与 `cordis.snapshot.yml` overlay([单源 replay 配置](2026-07-04-single-source-acp-replay-config.md))。读取 `DSH_SNAPSHOT` 留在边缘层——库接收的是已解析的 `mode`。 -**`src/harness.ts`** 提供 `runScenario` 及其脚本/结果类型,以 agent 的 bin 和配置路径为参数。权限答案构成一个 FIFO 队列,以稳定的 option kind(而非随机的 option id)为键。缺少答案时取消该请求;不可用的 kind 取消 agent 请求并使场景失败。 +**`src/launcher.ts`**——`launchAcpTestAgent` 拥有通用的未构建进程边界:绝对 tsx loader 解析、`TSX_TSCONFIG_PATH`、隔离的 harness home、stdio 接线、原始字节 stdout tee、stderr 与更新捕获、失败关闭的权限后备、更新 waiter,以及优雅或信号式关闭。快照场景和普通 e2e 套件提供相同的 `AgentUnderTest`(`binScript`、`configPath`、`tsconfigPath`);扮演用户的测试只提供其权限 handler。ACP 与 hook e2e 套件以及 sandbox/approval e2e 套件都使用该 launcher,而不再重新构建 SDK client 边界。 + +**`src/harness.ts`**——`runScenario` 和输入脚本/结果类型在 launcher 之上叠加确定性步骤、临时 workspace、快照环境和持久化日志采集。其 `session/request_permission` handler 消费可选的 `InputScript.permissionAnswers` FIFO 队列,每个条目按选项**类型**进行选择(id 是 agent 生成的随机值,已提交脚本无法预知;类型是 ACP 稳定词汇,会在回答时映射到已提供的 `optionId`);队列不存在或耗尽时回答 `cancelled`,若请求从未提供某种类型则拒绝该次运行——agent 自身收到的回答是 `cancelled`,因此场景 bug 会使 harness 失败,而不会被吸收为 agent 侧拒绝。由此,approval 套件可以根据 `input.json` 确定性地驱动允许/拒绝往返。 **`src/normalize.ts`** 是纯规范化器,按策略不含钩子:当未来某个事件携带新的易变字段(例如审批耗时),共享规范化器在同一个变更中学会它,保持「规范化」的含义只有一个归属,而非各套件各自扩展清洗逻辑。 -**`src/suite.ts`** 提供 `Scenario` 类型与 `defineAcpSnapshotSuite(options)`,注册逐场景比对、record/refresh 的 fixture 回写、header pin 及其实时一致性守卫,以及 fixture 守卫块(无 orphan 场景目录、必需文件齐全、每个 class 恰好一个 pin、每个 JSONL 是 `scrubSystemPrompts` 的不动点、非 pinning fixture 也是 `scrubRequestHeaders` 的不动点)。pinned-header 契约([pinned-header RFC](2026-07-06-pin-request-header-content-in-one-scenario.md))按套件划分:每个 header class 恰好标记一个 `pinsHeader` 场景,其 `system-prompt.golden.md` 与 JSONL 工具列表将组合后的 header 拆分为可评审的产物;一致性守卫将二者与该 class 中每个实时 header 进行比对。纯辅助函数(`childFixturePaths`、`fixtureContext`、`normalizedHeaders`、`normalizedSystemPrompts`、`formatSystemPromptSnapshot`、`headerDeltaCount`)从模块导出,以便直接进行单元覆盖。 +**`src/suite.ts`**——包含 `Scenario` 类型和 `defineAcpSnapshotSuite(options)`,注册各场景比较、记录/刷新 fixture 写回、带实时一致性守卫的请求头固定项,以及 fixture 守卫块(没有孤立场景目录、必需文件存在、每种类别恰好一个固定项、每份 JSONL 都是 `scrubSystemPrompts` 固定点、非固定 fixture 同时也是 `scrubRequestHeaders` 固定点)。刷新会先展开打包的计时信封,再对齐现有易变事件时间,因此在打包与未打包布局之间切换不会移动后续记录;全新的 chunk fragment 数组仍为权威,因为其边界属于重放行为。场景目录中的 `session.jsonl` 加连续的 `session.<n>.jsonl` 同级文件构成有序主项/子项清单,因此场景表可以声明策略而不重复子项数量。固定请求头契约([固定请求头 Agent Note](2026-07-06-pin-request-header-content-in-one-scenario.md))按套件生效:每种请求头类别恰好标记一个 `pinsHeader` 场景,其 `system-prompt.expected.md` 和 JSONL 工具列表把组合请求头拆成可评审产物;一致性守卫会将两者与该类别的每个实时请求头比较。固定场景可以声明任何合法的变更请求头数量,其 Markdown 产物记录每个完整的已变 prompt。纯辅助函数(`sessionFixtureNames`、`fixtureContext`、`normalizedHeaders`、`normalizedSystemPrompts`、`formatSystemPromptSnapshot`、`headerChangeCount`)从模块导出,以便直接进行单元覆盖。 ## 曾考虑的替代方案 -- **将模块复制到每个示例中**:正是本 RFC 要防止的 fork。record/守卫逻辑恰恰是必须在各套件间保持逐字节一致的代码,而示例不在覆盖率门禁范围内,因此每份副本也无法被度量。 +- **把模块复制到每个示例中**——这正是本 Agent Note 要防止的分叉:记录/守卫逻辑恰好是必须在各套件间保持逐字节相同的代码,而示例位于覆盖率门禁之外,所以每份副本也都无法测量。 - **在 `examples/` 下建共享模块目录**:代码仍在覆盖率门禁之外,且需要跨示例边界的相对导入,违反包名导入约定;`examples/` 的叶子节点按设计应保持轻薄。 - **`dsh-acp-demo` 的 `/testing` 子路径导出**:将测试基础设施耦合到产品包的对外服务接口与依赖集中;`packages/support/` 的存在正是为了真实但兼容性承诺较低的开发/测试包,`dsh-llm-replay` 是先例,本包与之配套。 - **导出原始测试体函数而非套件工厂**:每个示例将重新拥有 `describe`/`it` 骨架(每套件约 80 行注册样板),却无灵活性收益;工厂使消费方只需一张场景表加一次调用,而导出的纯辅助函数在工厂设计内保留了可单元测试性。 -- **可注入的 ACP `Client` 工厂,而非声明式 `permissionAnswers`**:灵活性最大,但将 SDK 客户端构造泄露给每个消费方,并在正被统一的层面重新引入逐示例漂移;声明式队列使 `input.json` 成为唯一的脚本化界面,且可被 golden 规范化。 +- **使用可注入 ACP `Client` factory 代替声明式 `permissionAnswers`**——灵活性最大,但会把 SDK client 构造泄漏给每个消费者,并恰好在正在统一的层重新引入逐示例漂移;声明式队列让 `input.json` 保持为唯一脚本表面,并与预期输出规范化兼容。 - **泛化到 ACP 之外(传输无关的快照 harness)**:不存在第二种传输方式;harness 端到端都是 ACP 形态(SDK 客户端、JSON-RPC 帧、`session/update` 等待器),推测性的抽象将是一个超前于任何消费方的 seam 拆分。 ## 测试 -提取保留了所有既有 ACP golden 字节。包的 `src/` 通过脚本化的 ACP 子进程达到逐文件 100% 覆盖率:harness 测试覆盖每个步骤操作、两条预期错误分支、权限选择/回退/不可能选项、环境变量转发、workspace 种子注入、收集排序/噪声/回退;suite 测试对已提交的合成 fixture 执行 replay,并对临时副本执行 record,同时覆盖纯辅助函数。两个结构上不可达的守卫保留了有理由的覆盖率排除。fake agent 将 `session/new` 的 cwd 替换到日志中,包括 Darwin 的 `/var` realpath 行为,与真实 bin 一致。 +提取一致性得到机械证明:迁移后,`pnpm run test:snapshot` 的结果与基准提交匹配,`examples/acp-agent/tests/snapshots/` 下没有任何字节变化。包的 `src/` 在门禁单元运行中保持逐文件 100% 语句/分支/函数/行覆盖,并通过脚本化 fake ACP bin(`tests/fixtures/fake-acp-agent.ts`,每个场景由 fixture 旁的 `behavior.json` 编排行为)经过真实 launcher 驱动:`harness.spec.ts` 直接覆盖 launcher 默认值、捕获、更新等待、关闭以及环境/配置变体,随后覆盖每种场景 step 操作、两个 expect-error 分支、权限队列(选择、后备、不可能点击)、workspace seed,以及采集顺序/噪音/后备分支;`suite.spec.ts` 在收集时真实运行 factory——一个针对已提交合成 fixture 的重放套件和一个针对临时副本的记录套件(写回从不触及已提交树;`ACP_SNAPSHOT_SPEC_BOOTSTRAP=1` 会重新引导它)——并包含纯辅助函数的直接用例。fake bin 会把 `session/new` cwd 而非 `process.cwd()` 代入脚本化日志,与真实 bin 请求头携带的内容一致(darwin 会将 `/var/folders/…` realpath 为 `/private/var/folders/…`)。 ## 后果 -新示例只需一张场景表加 fixture 即可获得完整快照层——sandbox 分支从 master 合入后添加自己的套件(自己的 pin 场景、自己的 overlay、通过 `test:snapshot:record` 生成 fixture、通过 `permissionAnswers` 提供审批答案)。代价:`suite.ts` 导入 vitest,因此该包只能在 vitest 运行中导入——这是其他包没有的形态,已在其 README 中声明;每个套件 pin 自己约 8 KB 的 header fixture(真正不同的组合值得拥有自己的 pin;相同的组合会被该套件的一致性守卫捕获);e2e launcher 的重复仍然存在(`TODO(acp-test-harness)`)——当该迁移落地时,harness 即为提取目标。 +新示例通过场景表加 fixture 即可获得完整快照层,普通 ACP e2e 则通过一次 launcher 调用获得同一条经过测试的进程/client 边界。代价是:`suite.ts` 导入 vitest,因此包入口只能在 vitest 运行中导入——其他包都没有这种形状,其 README 已说明;每个套件还要固定自己的约 8 KB 请求头 fixture(真正不同的组合理应拥有自己的固定项;相同组合则会被该套件的一致性守卫捕获)。 diff --git a/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml b/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml index b355adb77d..dd6683aaa3 100644 --- a/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml +++ b/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.i18n.yaml @@ -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 -2026-06-16-typed-event-schemas.md: 93e470218e810c9c9370dd1c7cae5420c93fa7bf -2026-06-16-typed-event-schemas.zh.md: bca4265527507750abe5b8c114f14508cee91cb9 +2026-06-16-typed-event-schemas.md: 97a7d0c3787eb5556696e25a6c8b1bb75642aba9 +2026-06-16-typed-event-schemas.zh.md: f79a607eaa723c00b00e984e1a6983d24d99c127 diff --git a/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.zh.md b/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.zh.md index bca4265527..f79a607eaa 100644 --- a/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.zh.md +++ b/.agents/notes/proposed/architecture/2026-06-16-typed-event-schemas.zh.md @@ -1,4 +1,4 @@ -# RFC: 事件词汇的运行时 schema(Zod 与 merge-extensible-map 模式之辩) +# Agent Note: 事件词汇的运行时 schema(Zod 与 merge-extensible-map 模式之辩) Status: proposed @@ -6,7 +6,7 @@ Status: proposed ## 问题 -harness 将其核心词汇——内容块、消息来源、结束原因、轮次触发器、轮次结束原因与会话事件——建模为 **merge-extensible map**:一个 TypeScript `interface`(如 `SessionEventMap`、`ContentBlockMap`),插件通过声明合并对其扩展,公开联合类型则以 `Map[keyof Map]` 派生。这是本仓库的通用扩展模式,记录在 [docs/architecture.md](../../../architecture.md) 中("The same merge-extensible-map pattern is used for `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`"),`defineTool` 的 `InferArgs` DSL 和 `assertNever` 穷举约定都依赖于它。 +harness 将其核心词汇——内容块、消息来源、结束原因、轮次触发器、轮次结束原因与会话事件——建模为 **merge-extensible map**:一个 TypeScript `interface`(如 `SessionEventMap`、`ContentBlockMap`),插件通过声明合并对其扩展,公开联合类型则以 `Map[keyof Map]` 派生。这是本仓库的通用扩展模式,记录在 [docs/architecture.md](../../../../docs/architecture.md) 中(「The same merge-extensible-map pattern is used for `MessageSource`, `FinishReason`, `TurnTrigger`, and `TurnEndReason`」),`defineTool` 的 `InferArgs` DSL 和 `assertNever` 穷举约定都依赖于它。 该模式**仅存在于编译期**。类型在运行时消失:没有 schema 对象可供校验传入值、解析不可信输入或在运行时枚举变体。[会话持久化契约](../../implemented/architecture/2026-06-14-session-persistence.md)暴露了两个后果: @@ -15,7 +15,7 @@ harness 将其核心词汇——内容块、消息来源、结束原因、轮次 由此引出问题:事件词汇是否应迁移到 **Zod** 或其他运行时 schema 库,使持久化和插件边界拥有运行时 schema 而非被擦除的类型。 -本 RFC 界定该问题的范围,不提出具体实现。 +本 Agent Note 界定该问题的范围,不提出具体实现。 ## 为什么这不是一个持久化层的改动 @@ -30,16 +30,16 @@ harness 将其核心词汇——内容块、消息来源、结束原因、轮次 - **六个 merge-extensible map**(约 370 行核心类型):`ContentBlockMap`、`MessageSourceMap`、`FinishReasonMap`(位于 `dsh-llm`);`TurnTriggerMap`、`TurnEndReasonMap`、`SessionEventMap`(位于 `dsh-session`)。 - **约 10 处 `declare module` 扩展点**,分布在 `dsh-agent`、`dsh-agent-loop`、`dsh-bash`、`dsh-llm`、`dsh-session`、`dsh-session-persistence`、`dsh-system-prompt`、`dsh-tools` 各包中——每处都将从声明合并改为运行时 `register()` 调用。 - **事件生产者**——agent loop(智能体循环)中 16 处 `session.append(...)` 调用——形状不变,但现在在边界处被校验。 -- **约 7 个 switch 消费方**,对这些联合类型进行分支:`deriveMessages`(`dsh-session`)、`BlockAssembler`(`dsh-llm`)、`dsh-invariants` 插件、两个 LLM(大语言模型)适配器(`dsh-llm-deepseek`、`dsh-llm-pi-ai`)以及工具 schema 层(`dsh-tools`)。`assertNever` 对封闭联合类型的穷举 vs 对可扩展联合类型的 fall-through 约定(一条已记录的 lint 规则)需要重新考量——运行时变体在静态层面不可穷举。 +- **约 7 个 switch 消费方**,对这些联合类型进行分支:`deriveMessages` 与包自有的不变式 companion(`dsh-session`)、`BlockAssembler`(`dsh-llm`)、两个 LLM(大语言模型)适配器(`dsh-llm-deepseek`、`dsh-llm-pi-ai`)以及工具 schema 层(`dsh-tools`)。`assertNever` 对封闭联合类型的穷举 vs 对可扩展联合类型的 fall-through 约定(一条已记录的 lint 规则)需要重新考量——运行时变体在静态层面不可穷举。 - **`defineTool` 的 `InferArgs` DSL**(`dsh-tools`),它从编译期 schema 规范派生出零类型转换的 `execute` 参数类型——这是当前方案的标杆用例。 -- **文档**:architecture.md(该模式被描述为基础性的)、[dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md),以及所有引用该模式的 RFC。 +- **文档**:architecture.md(该模式被描述为基础性的)、[dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md),以及所有引用该模式的 Agent Note。 这是一次仓库级别的词汇重新设计,而非持久化的实现细节。 ## 曾考虑的替代方案 ### A. 维持现状——merge-extensible 类型 + 持久化边界处 `isJsonValue` -保留编译期模式。持久化继续使用不透明 JSON + 可序列化性守卫。插件通过声明合并扩展;事件*形状*的正确性由生产者负责,编译期由 TypeScript 保证,开发模式下由 `dsh-invariants` 插件的结构检查保证。 +保留编译期模式。持久化继续使用不透明 JSON + 可序列化性守卫。插件通过声明合并扩展;事件*形状*的正确性由生产者负责,并由 TypeScript 在编译期保证。启用包自有的不变式 companion 后,它们会检查选定的跨记录关系,但不提供通用运行时形状 schema。 - **优点**:零变动;插件扩展只需一行 `interface` 增补,享有完整类型推断,无需运行时注册仪式;无新运行时依赖;`defineTool` DSL 与 `assertNever` 穷举继续工作。 - **缺点**:持久化边界和插件 seam 处无运行时结构校验;格式错误但仍为合法 JSON 的数据被延迟捕获。 @@ -58,11 +58,11 @@ harness 将其核心词汇——内容块、消息来源、结束原因、轮次 ## 提案 -推迟。如果需要在持久化边界做运行时校验,**方案 B**(对封闭的头部和元数据形状使用 schemastery)是现有约定下的适度步骤。**方案 C** 是一个架构决策,需要自己的实现 RFC,其中包括 Zod 与 schemastery 之间的选择。 +推迟。如果需要在持久化边界做运行时校验,**方案 B**(对封闭的头部和元数据形状使用 schemastery)是现有约定下的适度步骤。**方案 C** 是一个架构决策,需要自己的实现 Agent Note,其中包括 Zod 与 schemastery 之间的选择。 ## 验收标准 -- 方案 C 只能通过自己的实现 RFC 推进,绝不能作为持久化的附带改动。 +- 方案 C 只能通过自己的实现 Agent Note 推进,绝不能作为持久化的附带改动。 - 如果采纳方案 B,封闭的头部/元数据形状(JSONL 的 `isHeaderLine` 守卫及同类)改用 schemastery 校验,替代手写守卫,merge-extensible map 保持不动。 ## 风险 @@ -74,4 +74,4 @@ harness 将其核心词汇——内容块、消息来源、结束原因、轮次 - 如果采用注册表,库选 **schemastery**(已在仓库中,已作为配置 schema 库)还是 **Zod**(生态更丰富,目前仅为传递依赖)?同时维护两个 schema 库本身就是一种成本。 - 能否采用混合方案:保留编译期推断(使 `defineTool` 和插件开发体验不受影响),同时为每个变体添加*可选*的运行时 schema,仅在持久化/协议边界校验,而非每次进程内 append 都校验? -- `dsh-invariants` 插件在开发模式下是否已覆盖了足够多的运行时形状缺口,使得边界校验仅在面对真正不可信输入(重新加载外部修改过的日志)时才有必要? +- `ctx.invariants` 服务启用后是否已覆盖了足够多的运行时形状缺口,使得边界校验仅在面对真正不可信输入(重新加载外部修改过的日志)时才有必要? diff --git a/.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml b/.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml index 3412d91229..1f6a7ec184 100644 --- a/.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml +++ b/.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.i18n.yaml @@ -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 -2026-06-30-pre-tool-input-rewrite.md: 85ece78f3bf188b3b702b1af539256747c1cfab2 -2026-06-30-pre-tool-input-rewrite.zh.md: 6a5c2b52627d21476b96448dc120155eab7f2223 +2026-06-30-pre-tool-input-rewrite.md: 5de605e7edf63046b14a125d53072aab9bb5d37e +2026-06-30-pre-tool-input-rewrite.zh.md: 7105fadd5b42c73b0493443935a9db1e37e525ab diff --git a/.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md b/.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md index 6a5c2b5262..7105fadd5b 100644 --- a/.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md +++ b/.agents/notes/proposed/feature/2026-06-30-pre-tool-input-rewrite.zh.md @@ -1,4 +1,4 @@ -# RFC: 工具执行前输入重写——一致性设计 +# Agent Note: 工具执行前输入重写——一致性设计 Status: proposed @@ -6,7 +6,7 @@ Status: proposed ## 问题 -[拦截 seam RFC](../../implemented/feature/2026-06-30-interception-seams.md) 将 `tools/pre-execute` 定义为一道针对执行的允许/拒绝/询问门禁,此时执行的身份标识已受保护、参数已被深度冻结。Claude Code 的 `PreToolUse` 钩子还提供了 `updatedInput`,因此忠实的桥接需要一个显式的重写机制。重写不能是对现有执行对象的可变逃逸口:它必须保持持久化历史、审计记录、展示层与实际执行值之间的一致性。 +[拦截 seam Agent Note](../../implemented/feature/2026-06-30-interception-seams.md) 将 `tools/pre-execute` 定义为一道针对执行的允许/拒绝/询问门禁,此时执行的身份标识已受保护、参数已被深度冻结。Claude Code 的 `PreToolUse` 钩子还提供了 `updatedInput`,因此忠实的桥接需要一个显式的重写机制。重写不能是对现有执行对象的可变逃逸口:它必须保持持久化历史、审计记录、展示层与实际执行值之间的一致性。 ## 问题本质:执行前参数的三个读取方 diff --git a/.agents/notes/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml b/.agents/notes/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml index e3ec2ad677..5cabc005db 100644 --- a/.agents/notes/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml +++ b/.agents/notes/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.i18n.yaml @@ -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 -2026-07-07-claude-code-and-codex-subagent-backends.md: 5585ea30a5ba1b4200f096069a28ccf1c3cef727 -2026-07-07-claude-code-and-codex-subagent-backends.zh.md: 2a6dd2cdea34cb777df5455f0bc12dc7073ff2a2 +2026-07-07-claude-code-and-codex-subagent-backends.md: ee8576f97a9fdef8c88dcad3a73f28b63ca3ebe1 +2026-07-07-claude-code-and-codex-subagent-backends.zh.md: 893d6a3cbac5293d6fdf2d6fa4d7ad00f856c61d diff --git a/.agents/notes/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md b/.agents/notes/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md index 2a6dd2cdea..893d6a3cba 100644 --- a/.agents/notes/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md +++ b/.agents/notes/proposed/feature/2026-07-07-claude-code-and-codex-subagent-backends.zh.md @@ -1,4 +1,4 @@ -# RFC: Claude Code 与 Codex subagent 后端(向外部编码 agent 的进程外委派) +# Agent Note: Claude Code 与 Codex subagent 后端(向外部编码 agent 的进程外委派) Status: proposed @@ -6,23 +6,23 @@ Status: proposed ## 问题 -为 Claude Code 和 Codex 添加隔离的 subagent 提供方。既有的[命名提供方 seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 和 [ACP 后端](../../implemented/feature/2026-06-22-acp-subagent-backend.md)已确立了进程边界的形状。harness 的一个轮次应能将一个自包含任务委派给上述任一产品,并接收其最终答案,同时不暴露父进程的密钥,也不继承来自 `~/.claude` 或 `~/.codex` 的宿主配置。 +subagent seam([seam Agent Note](../../implemented/feature/2026-06-21-subagent-capability-seam.md))在 `ctx.subagents` 上托管多个命名提供方,ACP 后端([ACP 后端 Agent Note](../../implemented/feature/2026-06-22-acp-subagent-backend.md))证明了该 seam 能跨越进程边界泛化;其「未来提供方」一节明确将 Codex app-server 与 Claude Code Agent SDK 列为机械上相似的兄弟。如今真正值得委派的就是这两个引擎:harness 的一个轮次应能把一个自包含任务交给真实的 Claude Code 或真实的 Codex——一个拥有自身模型、工具与沙箱的独立产品——并取回一个最终答案,同时父部署不向子进程泄漏密钥,子进程行为也不静默依赖宿主机上碰巧存在的 `~/.claude` / `~/.codex` 状态。 ## 提案 两个兄弟提供方包(ACP 后端的结构变体),加一次提取: -- `@deepseek-ai/dsh-subagent-claude-code`:通过 `@anthropic-ai/claude-agent-sdk` 的 `query()` 驱动一个 Claude Code 子进程(SDK 在父进程中运行,并将其内置的 `claude` CLI 作为子进程 spawn)。提供方名称为 `claude-code`:子进程是 Claude Code 这个*产品*,而非 Anthropic 模型适配器——"claude" 保留给未来的 `dsh-llm` 适配器。 +- `@deepseek-ai/dsh-subagent-claude-code`:通过 `@anthropic-ai/claude-agent-sdk` 的 `query()` 驱动一个 Claude Code 子进程(SDK 在父进程中运行,并将其内置的 `claude` CLI 作为子进程 spawn)。提供方名称为 `claude-code`:子进程是 Claude Code 这个*产品*,而非 Anthropic 模型适配器——「claude」保留给未来的 `dsh-llm` 适配器。 - `@deepseek-ai/dsh-subagent-codex`:spawn `codex app-server`,通过其 JSON-RPC-over-stdio 协议驱动一个 thread/turn,使用包内一个手写的换行 JSON 客户端(约 200–300 行)。 -- `@deepseek-ai/dsh-subagent-process`:纯库(沿用 `subagent-inprocess` 的先例),提取 `dsh-subagent-acp` 已有且两个新后端都需要的内容:凭证环境清洗(`SENSITIVE_ENV_PATTERN`/`buildChildEnv`)、EOF → SIGTERM → SIGKILL 的 dispose 阶梯,以及新的隔离配置目录辅助函数(`mkdtemp` 创建、尽力删除)。ACP 后端迁移到该库上;`bash-local` 的兄弟副本保持不动以限制变更范围。 +- `@deepseek-ai/dsh-subagent-process`:纯库(沿用 `subagent-inprocess` 的先例),提取 `dsh-subagent-acp` 已有且两个新后端都需要的内容:凭证环境清洗(`buildChildEnv`)、EOF → SIGTERM → SIGKILL 的 dispose 阶梯,以及新的隔离配置目录辅助函数(`mkdtemp` 创建、尽力删除)。ACP 后端迁移到该库上;`bash-local` 的兄弟副本保持不动以限制变更范围。 -两个提供方遵循 ACP 后端契约:每次 `start` 创建一个全新子进程、一次 prompt 往返、不继承父上下文也不声明可选能力、忽略 `request.parent` 和 `request.agentOptions`、使用随机的品牌化 agent id。`result` 从不 reject;子进程失败映射为 stop reason,原始错误送入 logger。每个提供方以不同的工具名挂载 `dsh-tool-subagent`。工具结果是唯一新增的模型可见产物,因此无需新的会话事件;工作区变更仍是 transcript(文本记录)回放之外的环境副作用。 +两个提供方逐字复制 ACP 后端的 seam 姿态:每次 `start` 创建全新子进程、恰好一次 prompt 往返、所有能力均为 `false`、`inheritsParentContext: false`、忽略 `request.parent`/`request.agentOptions`、`id = SessionId(randomUUID())`,且 `result` 从不 reject——子进程级失败扁平化为 stop reason,原始错误则通过 `onError` spec 回调送到 `ctx.logger`。模型暴露无需新代码:每个提供方各加载一次 `dsh-tool-subagent`,使用不同的 `toolName`(`subagent_claude_code`、`subagent_codex`)。无需新的会话事件——唯一的模型可见产物是工具结果,因此可重建性与 ACP 完全相同。明确边界:会话日志重建模型可见的 transcript(文本记录),而不是工作区变更历史——获准写入的子进程将文件作为日志之外的环境副作用进行修改,与 bash 工具和 ACP 后端现有行为完全一致;回放复现请求,而非磁盘。 ## 已验证的接口事实(固定版本) 两个集成面在本提案之前均已针对固定版本进行了验证——阅读类型与打包源码、运行无需密钥的 spike——而非仅依赖厂商文档。固定版本是验证基线,不是运行时契约:后端不执行运行时版本探测(无 `codex --version` 门禁、无 SDK 版本嗅探)。兼容性在开发时强制执行——每次依赖升级都会针对真实加载路径重跑无密钥套件——在运行时则通过大声失败来保障:协议层面的意外通过 `onError` 结算为 `error`,绝不静默异常。 -**`@anthropic-ai/claude-agent-sdk` 0.3.202。** `options.env` 会替换子进程环境(不与 `process.env` 合并),恰好满足清洗需求。`settingSources` 默认加载所有文件系统设置——隔离要求显式传入 `[]`。结果子类型为 `success` | `error_during_execution` | `error_max_turns` | `error_max_budget_usd` | `error_max_structured_output_retries`。中止时 SDK 自行升级 CLI 子进程:立即关闭 stdin,约 2 秒后若子进程未退出则发送 SIGTERM(已观察到;无残留进程)——无需自定义 kill 回退。`outputFormat: {type: 'json_schema'}` 和 `agents` 选项已存在,为 seam 的 `outputSchema` 能力和命名 subagent 类型提供了未来着陆点;两者均不在本 RFC 范围内。 +**`@anthropic-ai/claude-agent-sdk` 0.3.202。** `options.env` 会替换子进程环境(不与 `process.env` 合并),恰好满足清洗需求。`settingSources` 默认加载所有文件系统设置——隔离要求显式传入 `[]`。结果子类型为 `success` | `error_during_execution` | `error_max_turns` | `error_max_budget_usd` | `error_max_structured_output_retries`。中止时 SDK 自行升级 CLI 子进程:立即关闭 stdin,约 2 秒后若子进程未退出则发送 SIGTERM(已观察到;无残留进程)——无需自定义 kill 回退。`outputFormat: {type: 'json_schema'}` 和 `agents` 选项已存在,为 seam 的 `outputSchema` 能力和命名 subagent 类型提供了未来着陆点;两者均不在本 Agent Note 范围内。 **codex CLI 0.142.5,`codex app-server`(v2 词汇)。** LF 分隔的 JSON,JSON-RPC 2.0 形状但省略 `"jsonrpc"` 头。 @@ -33,11 +33,11 @@ Status: proposed ## 隔离与凭证 -认证方式仅限 API key。每次运行使用一个全新的配置目录(Claude Code 用 `CLAUDE_CONFIG_DIR` 配合 `settingSources: []`,Codex 用 `CODEX_HOME`),dispose 时尽力删除;配置也可以选择一个持久目录。共享的子进程环境辅助函数转发 `PATH`、`HOME`、`TMPDIR`、locale 和代理设置等普通值,移除凭证形态的名称,并叠加显式的 `config.env`。Claude Code 通过该叠加接收 API key,而 Codex 通过 `account/login/start` 接收,而非手写认证文件。 +部署只使用 API key 认证,子进程不得看到宿主用户的 Claude Code / Codex 配置:行为必须只由 `cordis.yml` 决定。每次运行获得一个全新的 `mkdtemp` 配置目录——Claude Code 使用 `CLAUDE_CONFIG_DIR`(并显式设置 `settingSources: []`),Codex 使用 `CODEX_HOME`——dispose 时尽力删除;配置字段也可以固定一个持久目录。子进程环境通过提取逐字复用 ACP 后端的 `buildChildEnv` 语义:转发环境变量,但移除凭证形态的变量(`/KEY|SECRET|TOKEN/i`),再叠加 `config.env`——因此 `PATH`、`HOME`、`TMPDIR`、locale 和代理变量保留,CLI 正常运行;只有环境中的凭证形态变量被清洗(Claude Code 的 `ANTHROPIC_API_KEY` 通过 `config.env` 显式进入),Codex key 则通过 `account/login/start` RPC 进入隔离的 `CODEX_HOME`,而非手写 `auth.json`。 ## 权限与审批策略 -每个后端暴露其引擎原生的策略词汇。Claude Code 默认 `permissionMode: default` 配合 `permission: reject`;Codex 默认 `sandboxMode: read-only`、`approvalPolicy: never`,以及相同的拒绝回退。示例可选择启用 `acceptEdits` 或 `workspace-write`。已知的审批、用户输入和 elicitation 请求接收配置的应答;未知方法接收 method-not-found,未知通知被消费。没有 prompt 到达人类,子进程也不会因等待不可用的输入而无限挂起。 +每个后端不压缩为 ACP 单一的 `permission: allow|reject` 旋钮,而把引擎原生词汇作为配置暴露,并采用保守默认值:Claude Code 获得 `permissionMode`(默认 `default`)以及 `permission: allow|reject`(默认 `reject`),后者作为所有漏过请求的 `canUseTool` 自动应答;Codex 获得 `sandboxMode`(默认 `read-only`)和 `approvalPolicy`(默认 `never`),以及同一个 `permission` 后备值,用来应答仍然到达的审批请求。默认值刻意做到不造成损害(开箱即用的子进程无法写文件);示例演示如何开放权限(`acceptEdits` / `workspace-write`)。机械规则是:每一个服务端发起的请求都由程序迅速结算——枚举出的审批/用户输入/elicitation 请求按配置策略应答,未知请求方法用 JSON-RPC method-not-found 错误响应(绝不保持 pending),未知通知被消费——因此任何子进程请求都不会因等待永远不会到来的应答而卡住轮次。这一版中 prompt 不会到达人类,与 ACP 一致。 ## StopReason 映射 @@ -47,11 +47,11 @@ Claude Code:`success` → `completed`;`error_max_turns`、`error_during_exec ## 测试 -每个适用层级都要求覆盖: +依照根 AGENTS.md 规则在每个层级明确命名,并预先消除风险: -- **无密钥单元/集成测试:** 通过真实 SDK 驱动一个假 Claude CLI,通过真实协议客户端驱动一个脚本化的 Codex app-server。在逐文件 100% 覆盖率下,验证往返、每种 stop 映射、两条取消路径及预中止、权限策略、未知消息、spawn 失败、reload 清理、导出形状、清洗后的环境、临时目录删除,以及 Codex 认证预检失败。 -- **有密钥 e2e 测试:** 每个真实引擎在 `acceptEdits` 或 `workspace-write` 下执行文件操作;跳过时命名缺失的二进制或密钥,并断言无残留子进程。 -- **快照测试:** 标记为 `TODO(claude-code-subagent-replay)` 和 `TODO(codex-subagent-replay)` 推迟,等待 [subagent 回放 RFC](../../implemented/testing/2026-06-22-subagent-snapshot-replay.md) 描述的进程特定回放形状。 +- **无密钥单元/集成测试**:每个后端都镜像 ACP spec 清单(往返和输出累积、每种 stop 映射、两条取消路径、已中止、两种策略下的权限自动应答、未知消息容错、错误命令的 spawn 失败、HMR 提供方清理、导出形状、子进程环境隔离断言和临时目录删除;Codex 另加认证预检失败路径)。Claude Code harness 是通过 `pathToClaudeCodeExecutable` 接入真实 SDK 的脚本化假 `claude` 可执行文件——一个 spike 已在 24ms 内完成端到端无密钥验证(假 CLI 应答一次 `control_request/initialize`,并讲 plain stream-json,约 40 行)。Codex harness 是讲已验证协议格式的脚本化 mock app-server 子进程,沿用 `mock-acp-server.ts` 形状。 +- **有密钥 e2e 测试**:每个后端的真实引擎执行并由磁盘验证真实文件工作,固定使用开放后的配置,以免验收与不造成损害的默认值冲突——Claude Code 使用 `permissionMode: 'acceptEdits'`,Codex 使用 `sandboxMode: 'workspace-write'` + `approvalPolicy: 'never'`;自跳过会准确报告缺失的是二进制还是 key。CI 没有密钥,因此依照有密钥策略在本地运行。 +- **快照测试**:以 `TODO(claude-code-subagent-replay)` / `TODO(codex-subagent-replay)` 推迟——即 ACP 后端也推迟的独立回放形状([按会话回放 Agent Note](../../implemented/testing/2026-06-22-subagent-snapshot-replay.md));在此期间由无密钥套件提供确定性覆盖。 ## 曾考虑的替代方案 @@ -61,7 +61,7 @@ dispose 阶梯和环境清洗要求拥有子进程(spawn 参数、env、信号 ### 为什么不用模型可见的 `subagent_type` 参数(单一 Task 风格工具)? -Claude Code 自身的 Task 工具将 subagent 类型放在模型可见的 schema 中,选择一个 prompt + 工具集人格。这里的选择是在执行引擎之间做出的,而只有部署者知道哪些引擎配置了凭证——因此选择留在部署配置层,保持 `dsh-tool-subagent` 文档中的「一个提供方对应一个工具」契约。人格风格的类型选择器应是针对工具的另一个 RFC,而非针对后端。 +Claude Code 自身的 Task 工具将 subagent 类型放在模型可见的 schema 中,选择一个 prompt + 工具集人格。这里的选择是在执行引擎之间做出的,而只有部署者知道哪些引擎配置了凭证——因此选择留在部署配置层,保持 `dsh-tool-subagent` 文档中的「一个提供方对应一个工具」契约。人格风格的类型选择器应是针对工具的另一个 Agent Note,而非针对后端。 ### 为什么不用登录态凭证和用户自身的配置? @@ -73,7 +73,7 @@ Claude Code 自身的 Task 工具将 subagent 类型放在模型可见的 schema ### 为什么不用 ACP 适配器(如 `claude-code-acp`)复用既有后端? -社区 shim 将两个引擎包装为 ACP,这会使它们在 `dsh-subagent-acp` 上变成「仅配置」。但这在 harness 与引擎之间插入了一个非官方的第三方层,抹去了本 RFC 暴露的原生控制面(permissionMode、sandboxMode/approvalPolicy、配置目录隔离、apiKey RPC),并以 shim 的发布节奏替换了第一方协议的稳定性。第一方接口——Agent SDK 和 app-server——才是受支持的集成点。 +社区 shim 将两个引擎包装为 ACP,这会使它们在 `dsh-subagent-acp` 上变成「仅配置」。但这在 harness 与引擎之间插入了一个非官方的第三方层,抹去了本 Agent Note 暴露的原生控制面(permissionMode、sandboxMode/approvalPolicy、配置目录隔离、apiKey RPC),并以 shim 的发布节奏替换了第一方协议的稳定性。第一方接口——Agent SDK 和 app-server——才是受支持的集成点。 ## 验收标准 diff --git a/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml b/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml index b7300fc7f3..08f5e8380e 100644 --- a/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml +++ b/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.i18n.yaml @@ -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 -2026-07-08-interactive-side-sessions.md: ac29f80b31492ce79512cc4d08e33480e0ac6258 -2026-07-08-interactive-side-sessions.zh.md: 5d0ef101dc23febefec881b12fcbb5ba4dcf8be9 +2026-07-08-interactive-side-sessions.md: dfd325babe215782c9c1cbec3fd9f874783af7ab +2026-07-08-interactive-side-sessions.zh.md: d545f65a821c6057b062300f31c415a2d7f63860 diff --git a/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.zh.md b/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.zh.md index 5d0ef101dc..d545f65a82 100644 --- a/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.zh.md +++ b/.agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.zh.md @@ -1,4 +1,4 @@ -# RFC: 交互式侧会话与合并回写 +# Agent Note: 交互式侧会话与合并回写 Status: proposed @@ -15,9 +15,9 @@ Status: proposed - **Fork 并绑定:** 以父会话的平衡已完成轮次前缀创建子会话,并在其元数据中标记 `parentSession` 与 `seedLength`。这组合了 `ctx.agents.create({ seed, meta })`;不新增核心服务或 session-store 方法。 - **顾问定位:** 创建后注入一条插件来源的 `context/message`,告知子会话只做解释,不执行变更或继续任务。保持系统提示词逐字节一致,可在继承的历史上保留提供方的前缀缓存。 - **合并回写:** 向子会话请求一条有长度上限的 handback,然后向父会话注入一条插件来源的 `context/message`。父会话的下一次请求在其日志位置看到该消息,保持回放与[请求可重建性](../../implemented/architecture/2026-07-05-reconstructable-requests.md),无需新增会话事件。 -- **呈现:** 调用方式、会话切换与 handback 渲染属于首个客户端拥有的界面。本 RFC 仅规定与界面无关的机制。 +- **呈现:** 调用方式、会话切换与 handback 渲染属于首个客户端拥有的界面。本 Agent Note 仅规定与界面无关的机制。 -回退产品化、会话树视图、面向模型的侧会话工具,以及 `forkName`/`mergedInto` 元数据均不在本 RFC 范围内。一次 live-adapter spike 已验证了源日志隔离、继承上下文、多轮子会话交互,以及合并回写在父会话下一轮次中的可见性。 +回退产品化、会话树视图、面向模型的侧会话工具,以及 `forkName`/`mergedInto` 元数据均不在本 Agent Note 范围内。一次 live-adapter spike 已验证了源日志隔离、继承上下文、多轮子会话交互,以及合并回写在父会话下一轮次中的可见性。 ## 曾考虑的替代方案 diff --git a/.agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml b/.agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml index 5a09704cff..f5f7b73ecb 100644 --- a/.agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml +++ b/.agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.i18n.yaml @@ -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 -2026-07-10-sqlite-session-query-provider.md: d1901ab0e37e8f92af322facac0cb48988d1ffe7 -2026-07-10-sqlite-session-query-provider.zh.md: 7a86d7294183eec57c3495a182f1403f84c27363 +2026-07-10-sqlite-session-query-provider.md: 828d73938e8b9de1a69d021cb10f86aa7b5cd576 +2026-07-10-sqlite-session-query-provider.zh.md: 2cb32238d388e3a1751451fe0bb2036dbac57809 diff --git a/.agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md b/.agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md index 7a86d72941..2cb32238d3 100644 --- a/.agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md +++ b/.agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.zh.md @@ -1,4 +1,4 @@ -# RFC: SQLite FTS5 会话搜索 +# Agent Note: SQLite FTS5 会话搜索 Status: proposed @@ -6,7 +6,7 @@ Status: proposed ## 问题 -精确读取的 `ctx.sessionQuery` 服务有意不维护派生索引。大规模持久化的历史记录需要全文搜索,而不是每次查询都扫描全部事件;当前的活跃会话则需要一个比上一次持久性检查点更新的覆盖层。搜索还需要具体的排序、摘要片段、过滤、分页、取消以及重建行为。 +精确读取的 `ctx.sessionQuery` 服务有意不维护派生索引。大规模持久化的历史记录需要全文搜索,而不是每次查询都扫描全部事件;当前的活跃会话则需要一个比上一次持久性检查点更新的覆盖层。搜索还需要具体的排序、摘要片段、分页、取消以及重建行为。 如果把这些关注点拆分到一个推测性的 provider 协调器和一个数据库实现之间,会产生两个耦合的协调状态机。第一个真实实现应当将源观察、提取、SQLite 事务、generation 管理和查询作为一个完整的生命周期来拥有。 @@ -22,7 +22,7 @@ Status: proposed 实现必须从可执行的用例出发定义跨会话和会话内两种搜索范围。每个可搜索事件是一个文档,包含会话元数据、事件元数据、surface 分类、归一化的语义文本和有界的纯文本摘要片段。会话级结果按其最强匹配事件分组;数值化的后端分数保持私有。 -过滤器在排序之前编译为参数化 SQL。查询语法被视为数据。排序包含稳定的平局字段。不透明游标绑定到归一化的请求形状和最小相关 generation;不相关的会话变更不应使会话内游标失效。取消操作必须停止调用方等待,并在运行时允许的范围内中断 SQLite 工作。 +搜索返回承载内容的结果记录,而非仅含元数据的 header。可链式过滤器作用于这一精确结果形状,并与搜索 API 一同设计和实现,而不会变成 provider 特有的预排序契约。查询语法被视为数据。排序包含稳定的平局字段。不透明游标绑定到归一化的请求形状和最小相关 generation;不相关的会话变更不应使会话内游标失效。取消操作必须停止调用方等待,并在运行时允许的范围内中断 SQLite 工作。 分词器选择仍是实现层面的实验。FTS5 trigram 支持子串召回,但会拒绝短于三个字符的有用词项并增大索引体积;提案在将其写入契约之前,必须对该权衡与默认 Unicode 分词器进行基准测试。 @@ -43,10 +43,10 @@ Status: proposed - 重启测试覆盖未变更、新增、变更和删除的持久化会话,且不重建整个索引。 - 重新打开时保留持久化行并移除活跃行;活跃行先遮蔽、后显露其持久化基础。 -- 测试覆盖两种搜索范围、元数据过滤、surface 默认值、摘要片段、转义、确定性平局、分页、范围内的陈旧游标、取消、动态持久化挂载/卸载,以及事务失败后的恢复。 +- 测试覆盖两种搜索范围、承载内容的结果、可链式结果过滤器、surface 默认值、摘要片段、转义、确定性平局、分页、范围内的陈旧游标、取消、动态持久化挂载/卸载,以及事务失败后的恢复。 - schema 不匹配只重置派生数据库。 - 一个 keyless 的端到端测试将真实的持久化后端与真实的 SQLite 搜索包组合使用。 -- 在移至 `implemented/` 之前,本 RFC 须修订为实际实现的分词器和公开 API。 +- 在移至 `implemented/` 之前,本 Agent Note 须修订为实际实现的分词器和公开 API。 ## 风险 diff --git a/.agents/notes/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml b/.agents/notes/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml index 802373dd50..1ad844cdb9 100644 --- a/.agents/notes/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml +++ b/.agents/notes/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.i18n.yaml @@ -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 -2026-07-13-stream-workflow-progress-through-tool-calls.md: c4fe68974bf774306038e3bd2ba3e29e06de3492 -2026-07-13-stream-workflow-progress-through-tool-calls.zh.md: b6a3ccbc89bebaae92641a10aea9a9a05b38a293 +2026-07-13-stream-workflow-progress-through-tool-calls.md: 668d38b38cab90f6ee9b613d1101d4d44302aa8a +2026-07-13-stream-workflow-progress-through-tool-calls.zh.md: a6d9540eb8c20d785d1395951a131feecd8ba39f diff --git a/.agents/notes/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md b/.agents/notes/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md index b6a3ccbc89..a6d9540eb8 100644 --- a/.agents/notes/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md +++ b/.agents/notes/proposed/feature/2026-07-13-stream-workflow-progress-through-tool-calls.zh.md @@ -1,4 +1,4 @@ -# RFC: 通过工具调用流式传输工作流进度 +# Agent Note: 通过工具调用流式传输工作流进度 Status: proposed diff --git a/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml b/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml index f7f98a72bb..8f00d8b537 100644 --- a/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml +++ b/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.i18n.yaml @@ -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 -2026-06-11-api-extractor-reports.md: 26562267d188ab2427075c6fccf0ee4b24d63d99 -2026-06-11-api-extractor-reports.zh.md: 33e80abc6e9689cf90f3c851039144a53418137e +2026-06-11-api-extractor-reports.md: f110bfe3353e65442f218336aca3e9d492ac2341 +2026-06-11-api-extractor-reports.zh.md: 8cb7353e10a8811b20ccd539de15f8e06b76e6ae diff --git a/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.md b/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.md index b32dc7e2af..f110bfe335 100644 --- a/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.md +++ b/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.md @@ -2,6 +2,8 @@ Status: proposed +English | [中文](2026-06-11-api-extractor-reports.zh.md) + > Split out from the original "Doc-sync and API reports" Agent Note (2026-06-11). Parts 1-2 (doc-block typechecking, event-taxonomy verification) shipped — see [doc-sync enforcement](../../implemented/process/2026-06-11-doc-sync-enforcement.md). This is the deferred part 3, kept as a standalone proposal. ## Problem diff --git a/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.zh.md b/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.zh.md index 33e80abc6e..8cb7353e10 100644 --- a/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.zh.md +++ b/.agents/notes/proposed/process/2026-06-11-api-extractor-reports.zh.md @@ -1,10 +1,10 @@ -# RFC: API extractor 报告 +# Agent Note: API extractor 报告 Status: proposed [English](2026-06-11-api-extractor-reports.md) | 中文 -> 从最初的「Doc-sync 与 API 报告」RFC(2026-06-11)中拆出。第 1–2 部分(文档块类型检查、事件分类体系校验)已交付,见 [doc-sync 强制](../../implemented/process/2026-06-11-doc-sync-enforcement.md)。本文是被推迟的第 3 部分,作为独立提案保留。 +> 从最初的「doc-sync(文档同步门禁)与 API 报告」Agent Note(agent 决策记录)中拆出(首次提出于 2026-06-11)。第 1 至第 2 部分(文档块类型检查、事件分类体系校验)已交付,见 [doc-sync 强制](../../implemented/process/2026-06-11-doc-sync-enforcement.md)。本文是被推迟的第 3 部分,作为独立提案保留。 ## 问题 diff --git a/.agents/notes/proposed/process/2026-06-11-architectural-conformance.i18n.yaml b/.agents/notes/proposed/process/2026-06-11-architectural-conformance.i18n.yaml index b358826e19..624b671a37 100644 --- a/.agents/notes/proposed/process/2026-06-11-architectural-conformance.i18n.yaml +++ b/.agents/notes/proposed/process/2026-06-11-architectural-conformance.i18n.yaml @@ -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 -2026-06-11-architectural-conformance.md: aad11b9e4bcbd31465cb0c4a507654971e24e843 -2026-06-11-architectural-conformance.zh.md: 59684bd01a133755a3d7efd90832f6f268037920 +2026-06-11-architectural-conformance.md: f7cb0d7397d4e03df225f68417da43b1fec8de62 +2026-06-11-architectural-conformance.zh.md: aa25ef6d2772642885ef268bd548fc6dad40d3cf diff --git a/.agents/notes/proposed/process/2026-06-11-architectural-conformance.zh.md b/.agents/notes/proposed/process/2026-06-11-architectural-conformance.zh.md index 59684bd01a..aa25ef6d27 100644 --- a/.agents/notes/proposed/process/2026-06-11-architectural-conformance.zh.md +++ b/.agents/notes/proposed/process/2026-06-11-architectural-conformance.zh.md @@ -1,4 +1,4 @@ -# RFC: 架构一致性——依赖规则与适配器套件 +# Agent Note: 架构一致性——依赖规则与适配器套件 Status: proposed @@ -6,19 +6,19 @@ Status: proposed ## 问题 -目前有两项架构保证仅存在于行文中:(1)没有任何东西依赖具体的 loop 包([微内核承诺](../../implemented/architecture/2026-06-11-microkernel-event-taxonomy.md));(2)每个 LlmAdapter 都正确地遵循 chunk 协议。二者都应当是机械化的([质量门禁原则](../../implemented/process/2026-06-11-quality-gates.md))。 +目前有两项架构保证仅存在于行文中:(1)没有任何组件依赖具体的 loop 包(package)([微内核承诺](../../implemented/architecture/2026-06-11-microkernel-event-taxonomy.md));(2)每个 LlmAdapter 都正确遵循分片协议。二者都应由机制强制执行([质量门禁原则](../../implemented/process/2026-06-11-quality-gates.md))。 ## 提案 **dependency-cruiser** 配合以下规则: -- `packages/*`(除 agent-loop 自身的 tests 和 examples/ 外)禁止导入 `@deepseek-ai/dsh-agent-loop`。 +- `packages/*`(除 agent-loop(智能体循环)自身的 tests 和 examples/ 外)禁止导入 `@deepseek-ai/dsh-agent-loop`。 - 禁止跨包深层导入(`@deepseek-ai/dsh-*/src/...` 路径)——只允许使用公开入口点。 - packages/ 内禁止导入循环。 - `vendor/*` 禁止从 `packages/*` 导入。 - 分层:dsh-llm 不导入其他 dsh 包;dsh-session 仅导入 dsh-llm;以此类推(packages/README.md 中的依赖表,强制执行)。 -**适配器一致性套件**位于 dsh-llm(`@deepseek-ai/dsh-llm/conformance`):一个可复用的 vitest 套件,以适配器工厂为参数,断言 chunk 协议契约——每个 block 内 index 单调递增、`block-end` 之后该 index 不再有 delta、恰好一个 `finish`、usage 至多出现一次、每个 `tool-call-delta` 携带 call id、abort 被及时响应。当前对 mock 运行;DeepSeek V4 适配器从第一天起继承该套件。可选地提供一个 dev 模式的 `strictAdapter()` 包装层,在 debug flag 下于运行时强制执行相同规则(与 [dev 模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md) 配对)。 +**适配器一致性套件**位于 dsh-llm(`@deepseek-ai/dsh-llm/conformance`):一个以适配器工厂为参数的可复用 vitest 套件,用于断言分片协议契约,包括每个块内的索引单调递增、某个索引出现 `block-end` 后不再接收增量、恰好出现一个 `finish`、用量至多出现一次、每个 `tool-call-delta` 都携带调用 id,并且及时响应 abort。当前先对 mock 运行;DeepSeek V4 适配器从第一天起继承该套件。还可以选择提供开发模式下的 `strictAdapter()` 包装层,在调试标志开启时于运行时强制执行相同规则(与 [开发模式不变式](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md) 配对)。 ## 计划 @@ -33,4 +33,4 @@ Status: proposed 随着包的增加,dep-cruiser 规则需要维护——规则应基于模式(`dsh-*`)而非逐一枚举。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml b/.agents/notes/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml index 7e89d07146..bf98665195 100644 --- a/.agents/notes/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml +++ b/.agents/notes/proposed/process/2026-06-11-supply-chain-and-vendor-drift.i18n.yaml @@ -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 -2026-06-11-supply-chain-and-vendor-drift.md: 97f5a3f999936faf81a67fe69c91f773400cb447 -2026-06-11-supply-chain-and-vendor-drift.zh.md: 0a8441c104ca4779a79b36361ea5d84f5cd09aca +2026-06-11-supply-chain-and-vendor-drift.md: a27ae64556dc7366279824f1480e5681b1e86bf1 +2026-06-11-supply-chain-and-vendor-drift.zh.md: 25c27650709faf1a462ce9779ee6f0a909746311 diff --git a/.agents/notes/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md b/.agents/notes/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md index 0a8441c104..25c2765070 100644 --- a/.agents/notes/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md +++ b/.agents/notes/proposed/process/2026-06-11-supply-chain-and-vendor-drift.zh.md @@ -1,4 +1,4 @@ -# RFC: 供应链检查与 vendor 漂移验证 +# Agent Note: 供应链检查与 vendor 漂移验证 Status: proposed @@ -10,10 +10,10 @@ vendor manifest(元数据清单)(见[引入 vendor 的决策](../../implem ## 提案 -1. **Vendor 漂移检查**(夜间 CI):以 manifest 中记录的 SHA 浅克隆上游仓库,复制对应的 package 源码,与 `vendor/*/src` 做 diff。除非 diff 与已记录的本地修改一致(每项修改以签入的 patch 文件保存——日志条目从行文描述变为可验证的产物),否则任务失败。 -2. **依赖安全公告**:对 lockfile 运行 osv-scanner(或 `pnpm audit`),按计划定期执行,并在涉及 lockfile 变更的 PR 上触发。 +1. **Vendor 漂移检查**(夜间 CI):以 manifest 中记录的 SHA 浅克隆上游仓库,复制对应的包(package)源码,与 `vendor/*/src` 做 diff。除非 diff 与已记录的本地修改一致(每项修改以签入的 patch 文件保存——日志条目从行文描述变为可验证的产物),否则任务失败。 +2. **依赖安全公告**:对 lockfile 运行 osv-scanner(或 `pnpm audit`),按计划定期执行,并在涉及 lockfile 变更的 PR(Pull Request)上触发。 3. **许可证清单**:一个脚本断言每个 vendor 包都携带其 LICENSE 文件,且 package.json 的 `license` 字段与 vendor/README.md 中的清单一致(我们混合了 vendor 的 MIT 与自有的 BSD-3)——作为 CI 步骤运行。 -4. **Renovate**(或定时 agent 任务)以小 PR 的形式提议 npm 依赖更新,这些 PR 走完整门禁套件;vendor 包不在其列(它们的更新遵循 manifest 同步流程,理想情况下是半自动化的 agent 工作流:拉取上游、重新应用 patch、运行门禁、以更新后的 manifest 表格开 PR)。 +4. **Renovate**(或定时 agent(智能体)任务)以小 PR 的形式提议 npm 依赖更新,这些 PR 走完整门禁套件;vendor 包不在其列(它们的更新遵循 manifest 同步流程,理想情况下是半自动化的 agent 工作流:拉取上游、重新应用 patch、运行门禁、以更新后的 manifest 表格开 PR)。 ## 计划 diff --git a/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml b/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml index 678dcb4abe..e909f748a5 100644 --- a/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml +++ b/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.i18n.yaml @@ -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 -2026-06-20-discover-package-inventory.md: 6729b8ea4386b1595139a2827a95cf3b072e8c94 -2026-06-20-discover-package-inventory.zh.md: 71a6fdf97255932dcff11b574ef7c67ef5a39313 +2026-06-20-discover-package-inventory.md: f2724a9512f88fccd7026db12de0a76f4d815048 +2026-06-20-discover-package-inventory.zh.md: d1a67849fd617cab0712a7c14d18ad7c7190f3c4 diff --git a/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.zh.md b/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.zh.md index 71a6fdf972..d1a67849fd 100644 --- a/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.zh.md +++ b/.agents/notes/proposed/process/2026-06-20-discover-package-inventory.zh.md @@ -1,4 +1,4 @@ -# RFC: 通过发现机制获取包清单,而非维护静态列表 +# Agent Note: 通过发现机制获取包清单,而非维护静态列表 Status: proposed @@ -6,7 +6,7 @@ Status: proposed ## 问题 -包(package)与门禁清单在 TypeScript project references、包文档、CI 描述、Knip 覆盖项以及快照场景元数据中反复出现。大多数只是重述包布局、manifest 数据、聚合命令内容或 fixture(测试前置数据)文件。因此每新增一个包或场景都会产生本可避免的同步点。 +包(package)与门禁清单在 TypeScript project references、包文档、CI 描述和 Knip 覆盖项中反复出现。大多数只是重述包布局、manifest(元数据清单)数据或聚合命令内容。因此每新增一个包都会产生本可避免的同步点。 [包层级结构](../../implemented/architecture/2026-06-20-package-hierarchy.md)已经手动消除了其中若干:`scripts/publint-all.ts` 现在从 `packages/<group>/<pkg>` 布局推导列表,两份 `tsconfig` 的 `paths` 映射也合并为一个 `@deepseek-ai/dsh-*` 通配符。剩下的是无法用 glob 消除的清单,主要是 `tsconfig.build.json` 的 project `references`——TypeScript 要求它是显式数组(没有通配符形式)。 @@ -14,11 +14,11 @@ Status: proposed ## 提案 -让剩余的包/门禁清单可被发现。一个唯一的权威来源——`packages/<group>/<pkg>` 层级结构加上包 manifest(元数据清单)——应当驱动 `tsconfig.build.json` 的 `references`、模块图以及任何全量包列表,并配合一个生成加校验步骤(沿用现有的 `gen-module-graph` / `gen-cordis-catalog` 模式:生成器写出产物,`hygiene`/`doc-sync`(文档同步门禁)中的 `--check` 模式在提交副本陈旧时报错)。模块图生成已经在读取包 manifest。`doc-sync` 应当成为定义并打印其子门禁的唯一命令,文档链接到该命令而非重述第二份列表。 +让剩余的包与门禁清单可被发现。一个唯一的权威来源,即 `packages/<group>/<pkg>` 层级结构加上包 manifest,应当驱动 `tsconfig.build.json` 的 `references`、模块图以及任何全量包列表,并配合一个生成加校验步骤(沿用现有的 `gen-module-graph` / `gen-cordis-catalog` 模式:生成器写出产物,`--check` 模式在 `hygiene` / `doc-sync`(文档同步门禁)中发现已提交副本陈旧时失败)。模块图生成已经在读取包 manifest。`doc-sync` 应当成为定义并打印其子门禁的唯一命令,文档链接到该命令,而非重述第二份列表。 层级结构不需要编码关于包的所有事实,但应当编码宽泛的维护策略:core/product 包、集成包、能力 seam 包与 support/test/example 包不应在脚本能区分它们之前先要求一份手工维护的例外列表。 -有两类编目项根本不需要生成器:将 e2e 入口 glob 折入 knip 的默认配置段即可直接删除逐包的重复声明;`childSessions` 可从每个场景的 fixture 目录发现,使场景表只需声明策略(`recorded`、`hasModelTurn`、`comparesLog`)。而且即便是这些策略字段,今天也在追踪可从 fixture 推导的事实(`comparesLog` ⟺ 已提交的日志在头行之后还有条目;`recorded` ⟺ `hasModelTurn` 且没有 `replay.override.json` 兄弟文件),因此每个新场景类都在不断添加 fixture 目录本身已经能回答的开关。 +有一项已编目的内容根本不需要生成器:将 e2e 入口 glob 折入 Knip 的默认配置段,即可直接删除逐包的重复声明。 ## 验收标准 @@ -27,10 +27,9 @@ Status: proposed - 文档描述真源,而非重复生成的清单。 - CI 调用聚合命令,由这些命令自行管理其子门禁列表。 - `knip.json` 仅在编码真实信息(额外入口文件、被忽略的依赖)时才携带逐包覆盖项,绝不重述默认配置段。 -- 快照场景只声明策略,不声明可从其 fixture 目录发现的事实。 ## 风险 -发现脚本可能变得过于精巧。实现应当保持朴素:读取 manifest、按显式字段过滤、打印解析后的列表、出错时大声报错。收益在于消除手工清单的漂移,而非发明一套构建系统。 +发现脚本可能变得过于精巧。实现应当保持朴素:读取 manifest、按显式字段过滤、打印解析后的列表,并在出错时明确失败。收益在于消除手工清单的漂移,而非发明一套构建系统。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml b/.agents/notes/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml index d828a634b5..3affcaabfa 100644 --- a/.agents/notes/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml +++ b/.agents/notes/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.i18n.yaml @@ -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 -2026-07-04-prune-dead-core-spine-surface.md: 59bbfa181a08b998c52ef63afbc63fd5226294a6 -2026-07-04-prune-dead-core-spine-surface.zh.md: 953cb3bc7b30affd505564ac427632732dd9374e +2026-07-04-prune-dead-core-spine-surface.md: 432aaa848540fe7d1db3039399345a02afed5bd3 +2026-07-04-prune-dead-core-spine-surface.zh.md: 6352e2ea1ec6ef4459fc07472e5dbdb6cfb648a5 diff --git a/.agents/notes/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md b/.agents/notes/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md index 953cb3bc7b..6352e2ea1e 100644 --- a/.agents/notes/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md +++ b/.agents/notes/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.zh.md @@ -1,4 +1,4 @@ -# RFC: 裁剪无用的公开与结果接口 +# Agent Note: 裁剪无用的公开与结果接口 Status: proposed @@ -6,29 +6,30 @@ Status: proposed ## 问题 -若干包根导出、结果字段和便利方法没有生产消费方。它们之所以存活,要么是因为测试通过公开入口导入了内部实现,要么是因为某个类型预期了一个从未出现的调用者。每一项单独看都很小,但合在一起,它们扩大了 SDK 契约、生成的 catalog、文档和回归矩阵,却没有支撑任何已交付的路径。 +若干包(package)根导出、结果字段和便利方法没有生产消费方。它们之所以存活,要么是因为测试通过公开入口导入了内部实现,要么是因为某个类型预期了一个从未出现的调用者。每一项单独看都很小,但合在一起,它们扩大了 SDK 契约、生成的 catalog、文档和回归矩阵,却没有支撑任何已交付的路径。 -生产语料库是 `packages/*/*/src`、示例源码/配置和运行时脚本。测试、包(package) README 和 RFC 行文是发布的证据,但不是固定调用者。`cordis_inspect` 使 `packages/cordis/tool-cordis/src/api-catalog.ts` 对模型可见,`cordis_mount` 可以通过受保护的真实服务代理调用注入的服务,因此 catalog 中的服务方法和返回形状是真正的动态产品接口。下表因此区分「没有固定的仓库调用者」与「不可达」:涉及 catalog 词汇的行有意收缩模型编写的 mount 能发现和调用的内容,而包根实现辅助函数并不通过该服务门面可达。精确符号搜索得出以下清单: +生产语料库是 `packages/*/*/src`、示例源码/配置和运行时脚本。测试、包 README 和 Agent Note(agent 决策记录)行文是发布的证据,但不是固定调用者。`cordis_inspect` 使 `packages/cordis/tool-cordis/src/api-catalog.ts` 对模型可见,`cordis_mount` 可以通过受保护的真实服务代理调用注入的服务,因此 catalog 中的服务方法和返回形状是真正的动态产品接口。下表因此区分「没有固定的仓库调用者」与「不可达」:涉及 catalog 词汇的行有意收缩模型编写的 mount 能发现和调用的内容,而包根实现辅助函数并不通过该服务门面可达。精确符号搜索得出以下清单: | 接口 | 生产证据 | 简化方式 | | --- | --- | --- | | `SurfaceManager.invalidate()` | 只有其单元测试调用它;seeding 在惰性创建的 manager 存在之前就已完成,且会话从不替换其日志引用。 | 删除它及其不可能触发的整体替换契约。 | | `ToolExecutionResult.callId` | 每个钩子已经接收不可变的 `ToolExecution`;循环和 ACP(Agent Client Protocol)通过 call/session 事件关联。没有消费方读取这个重复的结果字段。 | 移除该字段、复制/不匹配守卫,以及证明该重复不可能不一致的测试。 | | `ReactLoopAgent` 根导出 | 包外的命名导入都是测试;生产代码面向 `Agent` 编程,通过 `ctx.agents` 创建/恢复。 | 返回/接口类型为 `Agent`,将具体循环类改为包内部;保留有意设计的同步、仅配置的 `AgentLoop.create()` 路径。 | -| `workflow-workerthread` 的 protocol/runtime/session 再导出与命名的 `WorkerWorkflowEngine` | 每个包名消费方都使用默认引擎;workflow RFC 已将 worker 协议格式(wire format)定义为私有。 | 保留默认插件类/配置契约;移除重复的命名类导出,将协议模块保持为源码私有。 | +| `workflow-workerthread` 的 protocol/runtime/session 再导出与命名的 `WorkerWorkflowEngine` | 每个包名消费方都使用默认引擎;workflow Agent Note 已将 worker 协议格式(wire format)定义为私有。 | 保留默认插件类/配置契约;移除重复的命名类导出,将协议模块保持为源码私有。 | | `code-runtime-worker` 的 protocol/bootstrap 再导出 | 包外的生产/e2e 消费方使用 `WorkerCodeRuntime` 和配置,而非 `BootstrapPort`、`PatchableStream` 或 worker 消息/启动类型。 | 保留运行时类/配置契约,将其协议格式/bootstrap 词汇改为源码私有。 | | ACP 的 translation/presenter 根导出 | `agentOptions`、`streamSessionEventUpdate`、`todosToPlan`、`ToolPresenter`、`nullToolPresenter` 和 `TerminalRendering` 只有同文件或 ACP 测试消费方;唯一的包外生产消费方挂载的是插件命名空间。 | 保留 `name`、`inject`、`Config`、`AcpConfig` 和 `apply`;将 translation/presentation 辅助函数改为源码私有,在包内测试。 | -| `providerWording` 与 `completedTurnPrefix` 根导出 | 各有一个同包生产调用者;只有 balanced-prefix 辅助函数有一个同包白盒测试。 | 改为源码私有,测试 provider 行为。 | +| `providerWording` 与 `completedTurnPrefix` 根导出 | 各有一个同包生产调用者;只有 balanced-prefix 辅助函数有一个同包白盒测试。 | 改为源码私有,测试提供方行为。 | | `depthOf`、`SubagentDepthError`、`SENSITIVE_ENV_PATTERN`、`waitForExit` 与 `exitsWithin` 根导出 | 生产 subagent 后端消费的是进程内 runner 和子进程构造/dispose(资源释放)辅助函数,而非这些强制/测试内部实现。 | 保留深度/环境/退出行为,但将辅助函数和 error/regex 改为源码私有;通过 spawn 和 dispose 测试。 | | `PersistenceCoordinator.inits`、后端 `inits` 访问器、`seedCoversPrefix` 与 `assertSerializable` | 访问器为白盒测试而存在;`seedCoversPrefix` 没有包外生产导入者;`assertSerializable` 没有生产调用者,且与 coordinator append 边界的无损快照重复。 | 通过 `session/flush` 观察初始化,将 `seedCoversPrefix` 改为源码私有,删除 `assertSerializable`。保留两个后端、`SessionHeader` 和 SQLite 的版本契约。 | | `LlmError.status` 与 replay status | 适配器/replay 填充它,但生产分支基于稳定的 error code/message 判断,从不读取原始 status。 | 移除未读字段和 replay 管道,保留错误分类。 | | `BlockAssembler.push()` 返回值 | 两个生产调用者都忽略返回的已完成块。 | 返回 `void`;保留有意公开的 `blocks()`/`message()` 契约。 | | `compactRegion` 的独立 `session` 参数 | 固定调用者传入的对象与 `agent.session` 上已有的是同一个;模型可见的 mount API 也能调用该方法,但接受两个身份允许挂载的插件提供不一致的配对。 | 保留手动 region seam,同时有意将其收窄为以 `agent.session` 为唯一真源。 | | `CompactionResult.startSeq`、`summarySeq`、`endSeq` 与 `summary` | 生产消费方只读取 shadowed range/seq/token 统计;持久日志拥有 summary 和事件标识。 | 移除四个结果回显,保留两个共享的 transcript(文本记录)渲染器。 | -| `BasicCompactService` 的 estimation/summarization 可见性 | 没有包外生产调用者调用这五个方法;已实现的 RFC 只将 `estimateContentTokens()` 和 `summarize()` 命名为子类钩子。 | 将这两个方法改为 `protected`,其余三个编排专用的估算器改为 private。 | +| `BasicCompactService` 的 estimation/summarization 可见性 | 没有包外生产调用者调用这五个方法;已实现的 Agent Note 只将 `estimateContentTokens()` 和 `summarize()` 命名为子类钩子。 | 将这两个方法改为 `protected`,其余三个编排专用的估算器改为 private。 | | `CodeLogEntry.source`/`level` 与 `RunCodeMeta.dispatches` | 每个生产消费方都将日志映射为文本;没有 presenter/模型路径读取其他字段或持久化的 dispatch 计数。 | 将 code-runtime 日志改为字符串(或纯文本条目),移除 result-meta 的 dispatch 管道;保留用于生成确定性 dispatch id 的本地计数器。 | +| `CodeRuntime.language` 与 `CodeRuntime.isolation` | worker 后端提供唯一的生产值,而 Code Mode 及其他所有生产调用方只调用 `run()`。 | 移除未读描述符,同时保留 worker 的语言、隔离、预算、取消与资源释放行为。 | | `ToolNotFoundError.toolName`、`SystemPrompt.config` 与 `BashTask.command` | 每个存储的公开值都没有生产读取者。 | 移除未读字段,保留错误消息、已解析的配置行为和任务生命周期。 | -| 后端包根实现辅助函数 | 下方精确清单仅通过相对路径的同包导入调用。生产命名空间导入挂载的是保留的插件契约,不读取这些属性;命名根消费方都是测试。 | 保留每个适配器/provider/服务及其配置/错误契约;停止在包根导出所列辅助函数/常量。 | +| 后端包根实现辅助函数 | 下方精确清单仅通过相对路径的同包导入调用。生产命名空间导入挂载的是保留的插件契约,不读取这些属性;命名根消费方都是测试。 | 保留每个适配器/提供方/服务及其配置/错误契约;停止在包根导出所列辅助函数/常量。 | | 消费方包根实现辅助函数 | 下方精确清单只有同包生产调用者。生产命名空间导入挂载的是插件契约,不读取辅助属性;命名根消费方都是测试。 | 保留插件契约和稳定的错误码;将测试迁移到包内模块或公开行为,停止在包根导出所列辅助函数。 | ### 分组辅助导出清单 @@ -48,14 +49,14 @@ Status: proposed **保留测试便利函数和自包含的结果字段为公开。** 公开辅助函数可以让白盒测试更方便,自包含的结果字段看起来更符合人体工学,未来的嵌入者可能需要具体循环类或枚举方法。这些好处是假设性的;当前它们让每处实现和文档都要解释没有已交付调用者能观察到的状态。真正的消费方可以引入它所需的最小契约,其所有权和失败语义明确。 -**保留所有 catalog 成员以供模型编写的 mount 使用。** 自引用工具集是一条真实的通用消费路径,而非生成文档的噪音。然而,它的价值来自准确、可组合的服务接口,而非无限期保留重复字段或不一致的参数对;上述每一项 catalog 收缩都移除了在同一 execution、agent 或 result 上其他位置已可获得的事实,并在同一变更中更新 API 参考。 +**保留所有 catalog 成员以供模型编写的 mount 使用。** 自引用工具集是一条真实的通用消费路径,而非生成文档的噪音。然而,它的价值来自准确、可组合的服务接口,而非无限期保留重复字段或不一致的参数对;上述每一项 catalog 收缩都移除了在同一 execution、agent(智能体)或 result 上其他位置已可获得的事实,并在同一变更中更新 API 参考。 ## 验收标准 -- 精确符号搜索显示:在本 RFC 及任何已实现 RFC 修正之外,没有被移除的接口。 -- 本 RFC 列出的每个接口均按指定方式缺失或降级;清单之外有意保留的扩展/测试契约不变。 +- 精确符号搜索显示:在本 Agent Note 及任何已实现 Agent Note 修正之外,没有被移除的接口。 +- 本 Agent Note 列出的每个接口均按指定方式缺失或降级;清单之外有意保留的扩展/测试契约不变。 - 工具执行、上下文压缩(context compaction)、两个 LLM 适配器、两个持久化后端、workflow 隔离以及 agent 创建/恢复保持其已交付行为。 -- 类型检查、覆盖率、快照、doc-sync、module-graph 校验、构建和 hygiene 通过。 +- 类型检查、覆盖率、快照、doc-sync(文档同步门禁)、module-graph 校验、构建和 hygiene 通过。 ## 风险 diff --git a/.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml b/.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml index 4c6aa9f685..aa9ff3e5ac 100644 --- a/.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml +++ b/.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml @@ -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 -2026-06-11-deterministic-and-stress-testing.md: c629567fd16158a0bd081e7e7850fb3e6d5f1631 -2026-06-11-deterministic-and-stress-testing.zh.md: aaa170725f9d3d2457d6f418dce7bc53feda2ab7 +2026-06-11-deterministic-and-stress-testing.md: d9977be835af05f9ee303b63ec6015bc9e153170 +2026-06-11-deterministic-and-stress-testing.zh.md: 8aed4ad6f277c1e567d91e3a8e2fef1c350ab89c diff --git a/.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md b/.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md index aaa170725f..8aed4ad6f2 100644 --- a/.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md +++ b/.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md @@ -1,4 +1,4 @@ -# RFC: 确定性测试、回放不变式 fixture 与竞态压力测试 +# Agent Note: 确定性测试、回放不变式 fixture 与竞态压力测试 Status: proposed @@ -12,7 +12,7 @@ Status: proposed 三项措施: -1. **测试中禁止挂钟睡眠。** 将 `setTimeout(N)` 等待替换为事件驱动等待(既有的 `waitForIdle` 模式,扩展为 `waitForStatus`、`waitForEvent(n)`),或在需要测试时间本身时使用 vitest 的 fake timer。通过 lint 规则强制执行:禁止在 `packages/*/tests` 中使用 `setTimeout`,白名单辅助模块除外。 +1. **测试中禁止挂钟睡眠。** 将 `setTimeout(N)` 等待替换为事件驱动等待(既有的 `waitForIdle` 模式,扩展为 `waitForStatus`、`waitForEvent(n)`),或在需要测试时间本身时使用 vitest 的 fake timer。通过 lint 规则禁止 `setTimeout`,适用范围是 `packages/*/tests`,白名单辅助模块除外。 2. **通用回放 fixture(测试前置数据)。** 一个共享测试辅助函数包装 agent loop harness,使每个测试结束后,agent 的会话日志被回放到一个全新的 Session 中,并自动断言 `deriveMessages()` 相等。这样该不变式在每次 CI 运行中会被套件产生的所有场景检查数百次,而非仅两次。 3. **夜间竞态压力测试。** 一个 CI job 以 `vitest --repeat=200`(加 `--shuffle`)运行 agent-loop 和 inbox 套件,以暴露调度依赖的失败;发现的任何不稳定测试都视为 bug 修复,绝不靠重试掩盖。 @@ -22,7 +22,7 @@ Status: proposed ## 验收标准 -- `packages/*/tests` 中不再有 `setTimeout`(白名单辅助模块除外),由 lint 规则强制执行。 +- 不再使用 `setTimeout`;lint 规则在 `packages/*/tests` 中强制执行,白名单辅助模块除外。 - 共享 harness 将每个测试的会话日志回放到全新的 `Session` 中,并自动断言 `deriveMessages()` 相等,覆盖整个套件。 - 夜间 job 以 `--repeat` 和 `--shuffle` 运行 agent-loop 和 inbox 套件;发现的不稳定测试作为 bug 分诊,绝不靠重试掩盖。 @@ -30,4 +30,4 @@ Status: proposed Fake timer 与 agent loop 中的 Promise 调度存在微妙交互——优先使用事件驱动等待;仅在测试 timer 服务行为本身时才使用 fake timer。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/proposed/testing/2026-06-11-mutation-testing.i18n.yaml b/.agents/notes/proposed/testing/2026-06-11-mutation-testing.i18n.yaml index ce9a12799f..d593656c04 100644 --- a/.agents/notes/proposed/testing/2026-06-11-mutation-testing.i18n.yaml +++ b/.agents/notes/proposed/testing/2026-06-11-mutation-testing.i18n.yaml @@ -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 -2026-06-11-mutation-testing.md: 20b24de385b944c27f4bdc0fc70f335d827f50a0 -2026-06-11-mutation-testing.zh.md: 780d3417cce48ee19ac8e3dc3b74d78b8e2a4c0f +2026-06-11-mutation-testing.md: 591d9012644a19ee2c67a916b63092d79f78db1f +2026-06-11-mutation-testing.zh.md: 9c22ed2f42e5c44e6be98f132614886bbdb188fd diff --git a/.agents/notes/proposed/testing/2026-06-11-mutation-testing.zh.md b/.agents/notes/proposed/testing/2026-06-11-mutation-testing.zh.md index 780d3417cc..9c22ed2f42 100644 --- a/.agents/notes/proposed/testing/2026-06-11-mutation-testing.zh.md +++ b/.agents/notes/proposed/testing/2026-06-11-mutation-testing.zh.md @@ -1,4 +1,4 @@ -# RFC: 变异测试作为覆盖率的制衡手段 +# Agent Note: 变异测试作为覆盖率的制衡手段 Status: proposed @@ -10,16 +10,16 @@ Status: proposed ## 提案 -在 `packages/*/src` 上运行 Stryker(`@stryker-mutator/vitest-runner`): +使用 Stryker(`@stryker-mutator/vitest-runner`)对 `packages/*/src` 运行变异测试: -- **PR 范围的增量运行**(仅变更文件),作为一个 CI job。调优后速度足以作为合并门禁。 +- **PR(Pull Request)范围的增量运行**(仅变更文件),作为一个 CI job。调优后速度足以作为合并门禁。 - **每夜全量运行**,跟踪变异分数;先记录基线,再将阈值设为观测到的基线并只升不降(与覆盖率策略一致:阈值只收紧)。 - 存活的变异体是待办项:agent 选取一个存活体、编写杀死它的测试、循环往复——一个形态良好的自主循环。 - 等价变异体(可证明不改变行为的)加注释排除并附理由,与 `/* v8 ignore */` 策略一致。 ## 计划 -1. 添加 Stryker 配置,范围限定在一个包(llm:最小、最具算法性),测量运行时间。 +1. 添加 Stryker 配置,范围限定在一个包(package),即 llm(最小、最具算法性),并测量运行时间。 2. 扩展到所有包;在配置中记录基线分数。 3. 接入每夜 job;运行时间可接受后再添加 PR 范围的增量 job。 @@ -33,4 +33,4 @@ Status: proposed 运行时间:变异测试开销大;逐文件 100% 覆盖率有所帮助(每个变异体至少会被执行到)。如果 PR 范围的运行始终过慢,则保持仅每夜运行,依赖分数只升不降的机制。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml index 31b046d91a..89414acd96 100644 --- a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml +++ b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.i18n.yaml @@ -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 -2026-06-11-immutable-public-surfaces.md: c807b036bb57bd5e64290fd59bf422c4732e9080 -2026-06-11-immutable-public-surfaces.zh.md: 9ff40436915e194848ba163ed80fefe84a1b3da4 +2026-06-11-immutable-public-surfaces.md: c9009ad923720efaecb25e2017ceab6e3eb0dbf4 +2026-06-11-immutable-public-surfaces.zh.md: 2516450c61eab399b2cb64862af164289eb87fbe diff --git a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md index 9ff4043691..2516450c61 100644 --- a/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md +++ b/.agents/notes/rejected/architecture/2026-06-11-immutable-public-surfaces.zh.md @@ -1,4 +1,4 @@ -# RFC: 深度只读的公开接口 +# Agent Note: 深度只读的公开接口 Status: rejected — the pervasive `DeepReadonly<T>` type flip is replaced by source-owned runtime immutability in `Session` plus relational development assertions. See [source-owned session immutability and dev-mode invariants](../../implemented/architecture/2026-06-11-dev-invariants-over-deep-readonly.md). @@ -26,4 +26,4 @@ Status: rejected — the pervasive `DeepReadonly<T>` type flip is replaced by so `DeepReadonly` 类型在 waterfall 边界处(突变本身就是 API 的地方)可能产生噪音较大的错误。应将可变/只读边界精确地划在「已记录 vs 进行中」,并在 session README 中加以说明。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml b/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml index e4d9370aa8..c19ca144a0 100644 --- a/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml +++ b/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.i18n.yaml @@ -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 -2026-06-20-providerless-example-base.md: ca9d391172067aca980b5b0fbc17141320c6839e -2026-06-20-providerless-example-base.zh.md: fb64e4a0b5295e0d56e7cd598c230f56219ba77e +2026-06-20-providerless-example-base.md: 2f41476a487775e6f9da2f113efe566e44786ff3 +2026-06-20-providerless-example-base.zh.md: 61d9f819b530fa9a15e8ed5b9d3f13f945e10b82 diff --git a/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.zh.md b/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.zh.md index fb64e4a0b5..61d9f819b5 100644 --- a/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.zh.md +++ b/.agents/notes/rejected/architecture/2026-06-20-providerless-example-base.zh.md @@ -1,4 +1,4 @@ -# RFC: 使共享示例基础配置与提供方无关 +# Agent Note: 使共享示例基础配置与提供方无关 Status: rejected — superseded by [Extract example apps into packages](../../implemented/architecture/2026-06-20-extract-example-app-packages.md), which moves the spine into a `dsh-agent-spine-demo` bundle and deletes the `base*.yml` files, so there is no shared base YAML left to rename. @@ -22,10 +22,10 @@ Status: rejected — superseded by [Extract example apps into packages](../../im - `examples/base-core.yml` 已删除。 - 真实演示配置显式添加 DeepSeek 适配器。 - 快照回放配置 include 同一个与提供方无关的基础,并加入其回放适配器。 -- [examples README](../../../../examples/README.md)、各示例 README 及 RFC 引用不再解释「base = base-core 加适配器」。 +- [examples README](../../../../examples/README.md)、各示例 README 及 Agent Note 引用不再解释「base = base-core 加适配器」。 ## 放弃了什么 真实演示失去了一层便利:每个演示都必须显式引入适配器。对于示例而言这是正确的默认行为,因为适配器选择是可变部分,而与提供方无关的接线才是共享的产品核心。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.i18n.yaml b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.i18n.yaml index da8988c6ea..306dac3774 100644 --- a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.i18n.yaml +++ b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.i18n.yaml @@ -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 -2026-07-04-generate-rfc-index-tables.md: 5d5ae258583e0fae7dcb44a23c4b41446bd233d2 -2026-07-04-generate-rfc-index-tables.zh.md: fa611e4337075501fe097fe8fc68a878a855a7c0 +2026-07-04-generate-agent-note-index-tables.md: 6e5221f018942a0629f30b6e6f22cedfb9f4145e +2026-07-04-generate-agent-note-index-tables.zh.md: f299fc5c2df25064a2712fa177fdbe5b73ffc7ca diff --git a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.md b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.md index 90c942411d..6e5221f018 100644 --- a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.md +++ b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.md @@ -2,6 +2,8 @@ Status: rejected — a centralized generated list is merge-prone and adds little discovery value +English | [中文](2026-07-04-generate-agent-note-index-tables.zh.md) + ## Problem Per-lifecycle/per-class tables would list facts that are fully derivable: an Agent Note's path encodes lifecycle and class, its filename encodes the first-proposed date, and its H1 carries the title. A hand-maintained copy of those facts would also be a high-contention docs hotspot because concurrent Agent Note branches append rows to the same few lines. [The classification Agent Note](../../implemented/process/2026-06-20-agent-note-classification.md) makes the tree itself authoritative. diff --git a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.zh.md b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.zh.md index fa611e4337..f299fc5c2d 100644 --- a/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.zh.md +++ b/.agents/notes/rejected/process/2026-07-04-generate-agent-note-index-tables.zh.md @@ -1,34 +1,38 @@ -# RFC: 生成 RFC 索引表 +# Agent Note: 生成 Agent Note 索引表 -Status: implemented +Status: rejected — a centralized generated list is merge-prone and adds little discovery value -[English](2026-07-04-generate-rfc-index-tables.md) | 中文 +[English](2026-07-04-generate-agent-note-index-tables.md) | 中文 ## 问题 -RFC 索引中按生命周期/按分类的表格所列信息完全可以推导:RFC 的路径编码了生命周期与分类,文件名编码了首次提出日期,H1 标题承载了标题文本。这些信息的手工维护副本也是仓库中冲突最频繁的文档热点:每一波提案都在同几行后追加新行,因此并发的 RFC 分支恰好在此处冲突,而其他地方完全一致;每次冲突都要手工合并那些文件系统本已知晓的行。[分类 RFC](2026-06-20-rfc-classification.md) 最初为了可策展性而保留手写索引,但 README 中真正需要策展的是行文,而行文从不冲突;冲突的只有机械表格。 +按生命周期和分类划分的表格只会列出完全可推导的事实:Agent Note(agent 决策记录)的路径编码其生命周期和分类,文件名编码首次提出日期,H1 承载标题。手工维护这些事实的副本还会成为高冲突文档热点,因为并发的 Agent Note 分支会向相同的几行追加条目。[分类 Agent Note](../../implemented/process/2026-06-20-agent-note-classification.md) 将目录树本身定为权威来源。 -## 决策 +## 提案 -保留策展行文;生成列表。表格位于 [`docs/rfc/INDEX.md`](../../INDEX.md),是一个**完全生成的文件**——策展行文留在 README.md 中,README.md 不包含任何索引行。[`scripts/rfc-index.ts`](../../../../scripts/rfc-index.ts) 是共享的真源:树遍历器(拥有封闭的生命周期/分类集合与结构规则,包括对可解析 H1 的要求)和渲染器(行来自 H1 标题并去掉 `RFC: ` 前缀,加上文件名日期,按日期再按文件名排序,以 `### {Class}` 分节、按规范分类顺序分组)。两个轻量消费方共享它: +保留策展文本,并将列表生成为完全生成的 `.agents/notes/INDEX.md`。共享的 `scripts/agent-note-index.ts` 模块将同时负责目录树遍历器和渲染器。两个轻量消费方会共用它: -- [`scripts/gen-rfc-index.ts`](../../../../scripts/gen-rfc-index.ts)(`pnpm run gen-rfc-index`)从目录树完整重写 INDEX.md。 -- [`scripts/verify-rfc-classification.ts`](../../../../scripts/verify-rfc-classification.ts)(`doc-sync`(文档同步门禁)的一个成员)检查结构,断言已提交的 INDEX.md 与新鲜渲染结果逐字节一致(`gen-cordis-catalog`/`verify-cordis-catalog` 模式),并拒绝在策展 README 中出现索引格式的行。新鲜度检查涵盖了索引完整性检查:从磁盘生成的表格在定义上就是完整的、标题正确的。 +- `scripts/gen-agent-note-index.ts`(`pnpm run gen-agent-note-index`)将根据目录树完整重写 INDEX.md。 +- `scripts/verify-agent-note-classification.ts` 将检查结构,并断言已提交的 INDEX.md 与新鲜渲染结果逐字节一致。 -添加、移动或删除一个 RFC 只需编辑 RFC 文件本身并运行生成器;分类 RFC 的「已否决替代方案」记录中带有替代关系的交叉链接。 +添加、移动或删除 Agent Note 时,只需编辑 Agent Note 文件并运行生成器。 ## 曾考虑的替代方案 -### 为什么不在 README.md 内使用标记分隔区域? +### 为什么不在 README.md 中使用标记分隔区域? -最初落地的形态是:生成器将表格拼接到 README.md 中 `gen-rfc-index` 标记注释之间、各 `## {Lifecycle}` 标题之下。在 README 同时吸收了文件内格式契约([统一格式 RFC](2026-07-05-uniform-rfc-format.md))之后,被整文件 INDEX.md 方案取代:一个门面 README 承载数百行生成内容会淹没其策展行文,而拼接机制(标记对、标题检查、区域外行检测)的存在仅仅是为了保护策展文本——专用的生成文件根本不包含这类文本。 +README.md 中由标记分隔的表格会混合生成内容与策展文本,因而需要拼接机制并保护周围的契约。专用生成文件至少能将这些关注点分开。 ### 为什么不采用纯校验器模式? -校验器能捕获错误,但每次提案编辑仍然要在手工维护的表格中触碰共享热点;对于纯机械的行,校验器失败比生成器更令人烦恼:作者已经命名并放置了文件,索引副本不增加任何信息。这与 [package-inventory 提案](../../proposed/process/2026-06-20-discover-package-inventory.md) 对 tsconfig references 和 knip stanzas 所做的手写列表与推导之间的判断一致——应用于这张确实会冲突的列表。 +它能捕获错误,但每次提案编辑仍然要在手工维护的表格中触碰共享热点。作者已经命名并放置了文件,因此索引副本不增加任何信息。这与[包清单提案](../../proposed/process/2026-06-20-discover-package-inventory.md)对 tsconfig 引用和 knip 配置段所做的手写列表与推导之间的判断相同。 ## 后果 -- 生成文件是显式的:其横幅标注了生成器名称,文件内没有需要保护的策展区域,且生成器在目录树结构无效时拒绝运行。 -- 格式错误或缺失的 H1 在生成器和门禁中都是硬错误——H1 现在是索引标题的承重来源。 -- 并发的 RFC 分支通过重新运行生成器解决索引冲突,从不手工合并行。 +- 生成文件将是显式的,且不包含任何策展区域。 +- H1 格式错误或缺失将是硬错误,因为 H1 为每一行提供标题。 +- 即使可以通过重新运行生成器解决冲突,并发分支仍会修改同一个已提交产物。 + +## 相关 + +已落地的[不建立索引决策](../../implemented/process/2026-07-19-remove-generated-agent-note-index.md)保留目录树和仓库搜索作为发现机制。 diff --git a/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml index c203585372..adeb1b14f9 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.i18n.yaml @@ -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 -2026-06-20-assembled-assistant-messages-only.md: 48f45ba08f77e2efd79bd999e262afad313bbdfe -2026-06-20-assembled-assistant-messages-only.zh.md: 44d94b3bc3d9c9f0f6c3bb8a2554664c4f5f5c59 +2026-06-20-assembled-assistant-messages-only.md: ba8135a3d63f292cfedd23de8b4b9d43b4455e8c +2026-06-20-assembled-assistant-messages-only.zh.md: 963d807afef29a3f7d8f0f57fc89ef7f6f3187c4 diff --git a/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md b/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md index 44d94b3bc3..963d807afe 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-assembled-assistant-messages-only.zh.md @@ -1,4 +1,4 @@ -# RFC: 仅持久化组装后的 assistant 消息,不存储流式分片 +# Agent Note: 仅持久化组装后的 assistant 消息,不存储流式分片 Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement. @@ -6,23 +6,23 @@ Status: rejected — high-fidelity chunk replay, partial failed streams, and sna ## 问题 -当前的规范会话日志会持久化模型流式输出的每一个 `assistant/chunk`。[会话持久化 RFC](../../implemented/architecture/2026-06-14-session-persistence.md) 选择这一方案是为了 token 级别的回放保真度和连续的 `seq`,但其代价日益增长:JSONL fixture(测试前置数据)被大量微小的 delta 记录占据,快照场景通过分组 chunk 事件来回放模型,ACP(Agent Client Protocol)加载时从 chunk 重建先前的 assistant 输出,而任何未来的日志读取方都必须区分持久的消息历史与 token 级别的追踪。 +当前的规范会话日志会持久化模型流式输出的每一个 `assistant/chunk`。[会话持久化 Agent Note(agent 决策记录)](../../implemented/architecture/2026-06-14-session-persistence.md)选择这一方案是为了 token 级别的回放保真度和连续的 `seq`,但其代价日益增长:JSONL fixture(测试前置数据)被大量微小的 delta 记录占据,快照场景通过对分片事件分组来回放模型,ACP(Agent Client Protocol)加载时从分片重建先前的 assistant 输出,而任何未来的日志读取方都必须区分持久的消息历史与 token 级别的追踪。 -对于成功组装出完整内容的步骤,agent loop(智能体循环)已经追加了一条 `assistant/message`。这正是 `deriveMessages()` 用来构造下一次模型请求的事件。换言之,正常的可恢复会话状态无需 chunk 即已具备;chunk 是实时渲染和确定性测试的产物,不是必需的会话历史。失败或中止的流则不同:部分 assistant 输出可能仅以 chunk 形式存在,而空的 max-token 步骤可能根本不产生 `assistant/message`。 +对于成功组装出完整内容的步骤,agent loop(智能体循环)已经追加了一条 `assistant/message`。这正是 `deriveMessages()` 用来构造下一次模型请求的事件。换言之,正常的可恢复会话状态无需分片即已具备;分片是实时渲染和确定性测试的产物,不是必需的会话历史。失败或中止的流则不同:部分 assistant 输出可能仅以分片形式存在,而空的 max-token 步骤可能根本不产生 `assistant/message`。 ## 提案 停止在规范会话日志中存储 `assistant/chunk`。持久日志保留 `assistant/message`、`tool/call`、`tool/result`、`usage`(如保留)以及轮次边界。实时 UI 仍可通过一个刻意设计为瞬态的流事件接收 token 增量。快照回放应将其模型脚本移入显式的 fixture 伴随文件,或从记录的适配器产物中派生,而非将规范的用户会话当作 token 磁带。需要部分失败流输出的场景必须在回放 fixture 中记录该输出。 -ACP `session/load` 可以将先前的 assistant 消息作为完整内容块回放,而非模拟原始的 token 流。加载后的 transcript(文本记录)无需重现每一个历史 delta;它必须展示相同的已完成 assistant 内容,并以有效的 provider 历史恢复运行。 +ACP `session/load` 可以将先前的 assistant 消息作为完整内容块回放,而非模拟原始的 token 流。加载后的 transcript(文本记录)无需重现每一个历史 delta;它必须展示相同的已完成 assistant 内容,并以有效的提供方历史恢复运行。 ## 验收标准 - `SessionEventMap` 移除 `assistant/chunk`,或在需要过渡性实时事件时将其标记为非持久化。 - [会话持久化文档](../../../../packages/session-persistence/session-persistence/README.md)不再要求逐字存储每个流式分片。 -- `llm-replay` 和 ACP 快照使用显式的回放 fixture 格式或伴随文件来存储模型 chunk。 +- `llm-replay` 和 ACP 快照使用显式的回放 fixture 格式或伴随文件来存储模型分片。 - `session/load` 从 `assistant/message` 渲染已完成的 assistant 消息。 -- 存储的日志大幅缩小,且在没有 chunk 空洞的情况下保持 `seq` 连续。 +- 存储的日志大幅缩小,且在没有分片缺口的情况下保持 `seq` 连续。 - 会话格式版本与已记录的 fixture 一并刷新;按预发布格式策略拒绝非当前版本的存储日志。 ## 放弃了什么 @@ -31,6 +31,6 @@ ACP `session/load` 可以将先前的 assistant 消息作为完整内容块回 ## 相关 -本 RFC 取代 [会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md) 中关于 chunk 持久化的决策,并影响 [ACP 快照测试](../../implemented/testing/2026-06-19-acp-snapshot-tests.md)——其当前的回放插件从 `assistant/chunk` 事件派生脚本。 +本 Agent Note 取代 [会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md) 中关于分片持久化的决策,并影响 [ACP 快照测试](../../implemented/testing/2026-06-19-acp-snapshot-tests.md)——其当前的回放插件从 `assistant/chunk` 事件派生脚本。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml index 764ea5f4e9..052b380049 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.i18n.yaml @@ -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 -2026-06-20-drop-acp-session-load.md: 93a2791d10b589cfdee5ecc48922722fe27c1c8a -2026-06-20-drop-acp-session-load.zh.md: 94de0a5aa0436dbee8e78fc2dd6de72c98216768 +2026-06-20-drop-acp-session-load.md: 2b6edf173506929f2d64e910b47aa70fb4f1d854 +2026-06-20-drop-acp-session-load.zh.md: 8e7a4ed6d7d1ccc89da3340907c11d1cf35505bd diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md index 94de0a5aa0..8e7a4ed6d7 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-session-load.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除 ACP session/load,直到 resume 具备产品形态 +# Agent Note: 移除 ACP session/load,直到恢复具备产品形态 Status: rejected — Zed is the current target ACP client, advertises and exercises load-capable sessions, and keeps pending-load state for concurrent `session/load`. The bridge should keep `session/load` and make the resume contract solid. @@ -8,15 +8,15 @@ Status: rejected — Zed is the current target ACP client, advertises and exerci ACP(Agent Client Protocol)声明 `loadSession: true` 并实现 `session/load`:向 bridge 注入持久化能力、校验 cwd 与存储元数据的一致性、从持久化日志重建 agent(智能体),并向客户端回放先前的 transcript(文本记录)更新。该路径有自己的竞态处理、loading-id 守卫、回放展示逻辑和测试。它还依赖规范日志保留足够的 UI 数据,以重建旧的分片和工具展示。 -持久化仍然是基础能力,但编辑器可见的 resume 尚未经过产品流程设计。目前没有会话选择器、没有标题/预览元数据,也没有明确的加载失败或部分加载的用户体验。bridge 正在为一个仅被测试、文档和当前目标客户端的会话模型所使用的功能付出复杂度代价。 +持久化仍然是基础能力,但编辑器可见的恢复尚未经过产品流程设计。目前没有会话选择器、没有标题/预览元数据,也没有明确的加载失败或部分加载的用户体验。bridge 正在为一个仅被测试、文档和当前目标客户端的会话模型所使用的功能付出复杂度代价。 ## 提案 -当前阶段,ACP 仅启动全新会话。`initialize` 声明 `loadSession: false` 或省略该能力,`session/load` 不予支持。持久化仍可供 agent loop(智能体循环)和测试使用;如果其他消费方需要,resume 仍可作为底层工厂存在。编辑器 bridge 应在具备真正的会话选择 UX 和稳定的 load transcript 契约后,再重新引入 `session/load`。 +当前阶段,ACP 仅启动全新会话。`initialize` 声明 `loadSession: false` 或省略该能力,`session/load` 不予支持。持久化仍可供 agent loop(智能体循环)和测试使用;如果其他消费方需要,恢复仍可作为底层工厂存在。编辑器 bridge 应在具备真正的会话选择 UX 和稳定的 load transcript 契约后,再重新引入 `session/load`。 ## 验收标准 -- ACP 不再仅为 `session/load` 注入 `sessionPersistence`。 +- ACP 不再注入 `sessionPersistence`;它原本仅供 `session/load` 使用。 - `initialize` 不再声明 load 支持。 - `session/load` handler、loading-id 追踪、已加载会话的 cwd 预检以及 load 回放测试均被移除。 - 快照 fixture(测试前置数据)不再依赖 load 回放展示。 @@ -26,4 +26,4 @@ ACP(Agent Client Protocol)声明 `loadSession: true` 并实现 `session/load 编辑器无法通过 ACP 重新打开先前持久化的会话。这确实是一项产品功能,但当前实现超前于 UX 设计,且将 bridge 绑定到 token 级别的日志回放。保留持久化但移除编辑器 load,可将 bridge 收窄到它当前能干净呈现的工作流。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml index 81bb11c433..6ead85178e 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.i18n.yaml @@ -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 -2026-06-20-drop-acp-terminal-meta.md: e52187d9786ed44ef4b60aedf5396c19a2e8e872 -2026-06-20-drop-acp-terminal-meta.zh.md: a5f4d7bc1f9d3d050c23990e89610d3eaed5bf70 +2026-06-20-drop-acp-terminal-meta.md: 79da387ac1a7a0e6767e3bf24baa6039e39ef90d +2026-06-20-drop-acp-terminal-meta.zh.md: 5aa455959c403d7e03b36be0d4336fdc5389c52e diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md index a5f4d7bc1f..5aa455959c 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-acp-terminal-meta.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除 ACP 终端 `_meta` 渲染 +# Agent Note: 移除 ACP 终端 `_meta` 渲染 Status: rejected — Zed is the current target client, and the terminal `_meta` convention is intentional Zed UX with a plain ACP fallback for other clients. @@ -6,7 +6,7 @@ Status: rejected — Zed is the current target client, and the terminal `_meta` ## 问题 -ACP 桥接层通过 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit` 实现了一套 Zed 特有的终端卡片约定。已实现的[富 ACP bash 渲染 RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 刻意回避了 ACP 客户端侧的 `terminal/create`(因为 bash 执行属于 harness 职责),但仍采用了参考 agent(智能体)的纯展示 `_meta` 约定。这在 Zed 中带来了更好的卡片效果,代价是桥接状态、能力协商、终端 id、特殊的 update 映射、文本回退测试,以及 `dsh-tool-bash` 中的 exit-pill 解析。 +ACP(Agent Client Protocol)桥接层通过 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.terminal_exit` 实现了一套 Zed 特有的终端卡片约定。已实现的[富 ACP bash 渲染 Agent Note(agent 决策记录)](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md)刻意回避了 ACP 客户端侧的 `terminal/create`(因为 bash 执行属于 harness 职责),但仍采用了参考 agent(智能体)的纯展示 `_meta` 约定。这在 Zed 中带来了更好的卡片效果,代价是桥接状态、能力协商、终端 id、特殊的 update 映射、文本回退测试,以及 `dsh-tool-bash` 中的 exit-pill 解析。 回退路径已经存在:将工具调用和完成输出渲染为普通 ACP 内容块。非 Zed 客户端本来就依赖这条路径,但 Zed 终端卡片是当前目标客户端的功能特性,而非推测性装饰。 @@ -22,10 +22,10 @@ ACP 桥接层通过 `_meta.terminal_info`、`_meta.terminal_output` 和 `_meta.t - `TerminalRendering`、终端 id、终端 cwd 解析与 `_meta.terminal_*` update 映射从 `@deepseek-ai/dsh-acp` 中消失。 - `ToolTerminal` 从 `@deepseek-ai/dsh-tools` 中消失,或在展示清理中因未使用而删除。 - Bash 结果展示不再为终端 pill 解析退出状态。 -- 已实现的[富 ACP bash 渲染 RFC](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 作为已交付历史保留在 `implemented/` 中;如被本提案取代,则加上交叉链接。 +- 已实现的[富 ACP bash 渲染 Agent Note](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) 作为已交付历史保留在 `implemented/` 中;如被本提案取代,则加上交叉链接。 ## 放弃的内容 Zed 用户将失去专用终端卡片:没有 cwd 头部、终端展示或 exit pill。他们仍能以纯内容形式看到命令和输出。在 ACP 桥接层尚未发布、`_meta` 键只是约定而非标准的阶段,这是合理的简化。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml index 304c4a62ac..676d14dd4e 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.i18n.yaml @@ -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 -2026-06-20-drop-bash-output-spill-files.md: 939f99072eace71405ae96e270d5438e75713c1c -2026-06-20-drop-bash-output-spill-files.zh.md: 4a868b1971dc3abcb4a9d0442ffc6e74f5246d00 +2026-06-20-drop-bash-output-spill-files.md: b2bd1a04ee1524bab29814ffa7c22712a83ee5f7 +2026-06-20-drop-bash-output-spill-files.zh.md: c8c0df30eda2ab6800d1e8f814d05f8f15103fd2 diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md b/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md index 4a868b1971..c8c0df30ed 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-bash-output-spill-files.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除 bash 完整输出溢出文件 +# Agent Note: 移除 bash 完整输出溢出文件 Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output. @@ -14,7 +14,7 @@ Status: rejected — full-output recovery is a real bash behavior. A future arti 保留尾部截断,移除完整输出溢出文件。bash 结果包含有界的尾部内容加一个明确的截断标记;不输出路径。如果用户需要恢复完整输出,则添加一个通用的产物/blob 服务(具有明确的所有权、清理和 UI 渲染),然后让 bash 将大体量输出附加到该服务。 -本提案可以独立于[通用长时间运行工具运行时](../../proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md)落地。如果后台任务保留,`bash_output` 仍应报告输出已被丢弃,但不再提供溢出路径。 +本提案可以独立于[通用长时间运行工具运行时](../../implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md)落地。如果后台任务保留,`bash_output` 仍应报告输出已被丢弃,但不再提供溢出路径。 ## 验收标准 @@ -22,10 +22,10 @@ Status: rejected — full-output recovery is a real bash behavior. A future arti - `OutputCollector` 仅保留有界缓冲区,删除临时文件机制。 - `renderResult()` 报告截断时不包含文件系统路径。 - 测试覆盖尾部截断,不再断言完整输出文件的内容。 -- [docs/defensive-patterns.md](../../../defensive-patterns.md) 中的安全指导不再将私有溢出文件视为面向模型的接口。 +- [docs/defensive-patterns.md](../../../../docs/defensive-patterns.md) 中的安全指导不再将私有溢出文件视为面向模型的接口。 ## 放弃的能力 模型或用户无法再从临时文件恢复大体量命令输出中被省略的前缀。在真正的产物服务出现之前,这是可以接受的。当前的溢出路径为一个生命周期和权限均未经设计的功能引入了过多的定制机制。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml index 131544ab6d..d91be8381f 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.i18n.yaml @@ -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 -2026-06-20-drop-durable-step-boundaries.md: 16fdf17c3bc8907745df17e8a105d7978eafb274 -2026-06-20-drop-durable-step-boundaries.zh.md: 5613a84d5f1b5cf87109a2e04a4cb350ffd650a8 +2026-06-20-drop-durable-step-boundaries.md: c5c4f269a378e334c4dc509d1288146d77d9a520 +2026-06-20-drop-durable-step-boundaries.zh.md: 7724a8f6c2c51650eb9ea0a6675ece7c24a211d8 diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md b/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md index 5613a84d5f..7724a8f6c2 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-durable-step-boundaries.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除持久化的步骤边界事件 +# Agent Note: 移除持久化的步骤边界事件 Status: rejected — `step/end` is the durable indication that a model step finished, and keeping the symmetric `step/start` / `step/end` pair makes crash repair, invariants, and transcript inspection clearer than inferring completion from adjacent step-scoped events. @@ -6,13 +6,13 @@ Status: rejected — `step/end` is the durable indication that a model step fini ## 问题 -会话日志存储了 `step/start` 和 `step/end` 事件,尽管每个步骤作用域的事件本身已经携带 `{ turn, step }`:assistant 分片、assistant 消息、工具调用、工具结果、用量和错误。`deriveMessages()` 忽略步骤边界,ACP(Agent Client Protocol)在 UI 层面也忽略它们,主要消费方是不变式检查、测试、快照 golden 文件和崩溃恢复。 +会话日志存储了 `step/start` 和 `step/end` 事件,尽管每个步骤作用域的事件本身已经携带 `{ turn, step }`:assistant 分片、assistant 消息、工具调用、工具结果、用量和错误。`deriveMessages()` 忽略步骤边界,ACP(Agent Client Protocol)在 UI 层面也忽略它们,主要消费方是不变式检查、测试、快照预期输出和崩溃恢复。 被否决的论点是:边界事件使日志更像仪式而非信息。实际上,`step/end` 是具体信息:读者无需从下一个事件推导状态,就能判断一次模型请求是已完成、已崩溃还是正在修复。同样,一个孤立的 `step/start` 对于「模型请求已发起但在产生任何分片之前就失败了」的场景也有价值。 ## 提案 -将轮次作为唯一的持久化边界。从 `SessionEventMap` 中移除 `step/start` 和 `step/end`;在需要分组的事件上保留数值型 `step` 字段。agent loop(智能体循环)递增步骤计数器并以该编号记录步骤作用域的事件,但不再追加开/关边界事件。消费方通过共享 `(turn, step)` 的连续事件推断步骤分组。 +将轮次作为唯一的持久化边界。`step/start` 和 `step/end` 将从 `SessionEventMap` 中移除;在需要分组的事件上保留数值型 `step` 字段。agent loop(智能体循环)递增步骤计数器并以该编号记录步骤作用域的事件,但不再追加开/关边界事件。消费方通过共享 `(turn, step)` 的连续事件推断步骤分组。 不变式插件应当强制步骤作用域的事件在一个已打开的轮次内具有有效的正整数步骤编号,而非要求独立的边界记录包围它们。崩溃恢复不应合成 `step/end`;如果一个被中断的轮次被保留,修复路径仍然可以关闭该轮次而无需捏造步骤边界记录。 @@ -22,11 +22,11 @@ Status: rejected — `step/end` is the durable indication that a model step fini - agent loop 中不再有 `closeStep()` 终结路径。 - ACP 快照和持久化契约 fixture(测试前置数据)不再期望步骤边界行。 - `deriveMessages()` 和回放从步骤作用域的事件推导出相同的消息历史。 -- [事件分类体系文档](../../../architecture.md)将轮次描述为持久化边界,将步骤描述为步骤作用域记录上的一个字段。 +- [事件分类体系文档](../../../../docs/architecture.md)将轮次描述为持久化边界,将步骤描述为步骤作用域记录上的一个字段。 - 会话格式版本和已记录的 fixture 被刷新;按预发布格式策略,非当前版本的已存储日志被拒绝。 ## 放弃了什么 日志不再将「一次模型请求已发起但进程死亡前未产生任何事件」记录为持久化事实,也不再有显式的「此步骤已完成」标记。在会话日志仍是持久化回放与审计表面的当下,这一损失不可接受。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml index 3302d9bef1..c65ced3c8b 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.i18n.yaml @@ -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 -2026-06-20-drop-unused-session-lineage.md: 5f76baf33fa50fc1aff9a0ab43262f063aa8e51b -2026-06-20-drop-unused-session-lineage.zh.md: 79decbb40d93f0798189d4a131197db132549f1c +2026-06-20-drop-unused-session-lineage.md: 605f1949999435b24404e0c5a72320416303ae52 +2026-06-20-drop-unused-session-lineage.zh.md: 5d37a287fe1cb2d3cf196a6779dc11702826fa4a diff --git a/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md b/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md index 79decbb40d..5d37a287fe 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-drop-unused-session-lineage.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除未使用的会话血缘元数据 +# Agent Note: 移除未使用的会话血缘元数据 Status: rejected — `parentSession` is part of the documented fork/sub-agent seam and is already preserved by the agent/session resume path. The field is future-facing, but it is not accidental dead state. @@ -12,7 +12,7 @@ Status: rejected — `parentSession` is part of the documented fork/sub-agent se ## 提案 -从 `SessionHeader` 中移除 `parentSession`,直到真正的 fork/恢复功能需要血缘信息时再引入。如果存在相应 API,fork 仍然可以用先前事件来初始化新会话,但持久化的父指针应当与读取它的功能和解释它的 UX 一同引入。 +移除 `parentSession`,使其不再属于 `SessionHeader`,直到真正的 fork/恢复功能需要血缘信息时再引入。如果存在相应 API,fork 仍然可以用先前事件来初始化新会话,但持久化的父指针应当与读取它的功能和解释它的 UX 一同引入。 如果血缘信息回归,届时再决定它应放在不可变 header 中、会话图索引中,还是作为一等事件。当前字段不应预先锁定那个设计。 @@ -28,4 +28,4 @@ Status: rejected — `parentSession` is part of the documented fork/sub-agent se 代码库失去了一个为未来 fork/subagent UX 预备的现成血缘钩子。这是有意为之。该字段在功能存在时很容易重新引入,而未发布的立场允许格式变更无需迁移。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml index adb3407f9f..1cea1f5177 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.i18n.yaml @@ -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 -2026-06-20-fold-session-persistence-interface.md: 3e9bb277ccd0b6319081cd1aac289db764f41e58 -2026-06-20-fold-session-persistence-interface.zh.md: 13a8945fcaa5529f6d4dc156b0dc1016ab6da62d +2026-06-20-fold-session-persistence-interface.md: 895b868b2a80d8655284bae1364a85e19e174da7 +2026-06-20-fold-session-persistence-interface.zh.md: 12c710d2235ff25c2c961cfdac31c0c01c3afdda diff --git a/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md b/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md index 13a8945fca..12c710d223 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-fold-session-persistence-interface.zh.md @@ -1,4 +1,4 @@ -# RFC: 将持久化接口合并进 dsh-session +# Agent Note: 将持久化接口合并进 dsh-session Status: rejected — the separate persistence interface package is the intended modular capability seam for durable backends. Folding it into `dsh-session` would reduce package count at the cost of a cleaner backend boundary. @@ -28,4 +28,4 @@ Status: rejected — the separate persistence interface package is the intended `dsh-session` 变得更重:它同时拥有内存日志和持久化接口。这就是代价。如果第三方持久化后端已经形成公开生态,独立的接口包会是更清晰的 SDK 边界;但在预发布阶段,在尚无外部消费方时,多出的包看起来更像是过早的抽象。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml index 83244e5741..8001c0937f 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.i18n.yaml @@ -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 -2026-06-20-generic-tool-rendering.md: 77d06968a24211835d1ff5db2541efdeb8227878 -2026-06-20-generic-tool-rendering.zh.md: ab032864a5304d6781d990d1f805fe9d280c1655 +2026-06-20-generic-tool-rendering.md: 6fc610546da04e7d1e16fc17ada87483a142aa3c +2026-06-20-generic-tool-rendering.zh.md: e19907b71dcb93d325f94695c05bda23fca254cc diff --git a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md index ab032864a5..e19907b71d 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-generic-tool-rendering.zh.md @@ -1,4 +1,4 @@ -# RFC: 收拢工具自有的 UI 展示逻辑 +# Agent Note: 收拢工具自有的 UI 展示逻辑 Status: rejected — tool-owned presentation should wait for more real tools before being generalized or deleted. Bash and ACP currently need the existing richer presentation path. @@ -24,7 +24,7 @@ Status: rejected — tool-owned presentation should wait for more real tools bef - `ToolCallPresentation`、`ToolResultPresentation`、`ToolTerminal` 和 `ToolCallKind` 消失,除非一个最小的通用 UI 类型仍需要其中之一。 - ACP 不再维护 presenter pending 状态,也不再在实时流式输出/加载回放期间调用工具回调。 - `dsh-tool-bash` 不再解析渲染文本来恢复退出状态以供 UI pill 使用。 -- 快照 golden 文件展示通用工具卡片和文本结果。 +- 快照预期输出展示通用工具卡片和文本结果。 ## 放弃了什么 @@ -32,4 +32,4 @@ Bash 失去其自定义的终端风格卡片和模型生成描述的放置位置 ## 相关 -这是[移除 ACP terminal 元数据](2026-06-20-drop-acp-terminal-meta.md)的宽泛版本。如果本 RFC 被接受,那个更窄的 RFC 就不再必要。 +这是[移除 ACP terminal 元数据](2026-06-20-drop-acp-terminal-meta.md)的宽泛版本。如果本 Agent Note(agent 决策记录)被接受,那个更窄的 Agent Note 就不再必要。 diff --git a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml index 96425f0390..73df65d34f 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.i18n.yaml @@ -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 -2026-06-20-retire-mid-turn-steering.md: 2c4d686942d2bfa8016bb60d55624dc59a933c1a -2026-06-20-retire-mid-turn-steering.zh.md: 2196d7d1d1f1bff39e8e0f03cf9910ab41434d2a +2026-06-20-retire-mid-turn-steering.md: a8812b3222739244d77f4d4dab60cf7c0cd6907d +2026-06-20-retire-mid-turn-steering.zh.md: 6beb00a646fd16b7bd9d987fb28429771145d6fc diff --git a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md index 2196d7d1d1..6beb00a646 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-retire-mid-turn-steering.zh.md @@ -1,4 +1,4 @@ -# RFC: 移除轮次中途引导 +# Agent Note: 移除轮次中途引导 Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`. @@ -14,7 +14,7 @@ agent(智能体)暴露了两条用户消息路径,外观相近但生命周 暂时删除轮次中途的用户 steering。`Agent.send()` 成为提交用户内容的唯一公开方式;当 agent 正在运行时,内容等待下一个轮次。循环仅因工具调用而在轮次内继续,不因用户在某个步骤运行期间输入内容而继续。调用方若要中断当前轮次,使用 `cancel()` 后再 `send()`。 -移除 `Agent.steer()`、steering FIFO、`steering/message`、`agent/steering`、由 steering 驱动的续行逻辑,以及取消操作中区分排队消息与 steering 消息的逻辑。除非实现 PR 发现了生产级监听器,否则在同一变更中一并移除 `agent/turn-continuation`;没有 steering 后,当前仓库不再有具体的续行消费方。如果将来真正的预算或目标插件需要强制续行,应以该插件为具体消费方重新引入一个更窄的 seam。 +移除 `Agent.steer()`、steering FIFO、`steering/message`、`agent/steering`、由 steering 驱动的续行逻辑,以及取消操作中区分排队消息与 steering 消息的逻辑。除非实现 PR(Pull Request)发现了生产级监听器,否则在同一变更中一并移除 `agent/turn-continuation`;没有 steering 后,当前仓库不再有具体的续行消费方。如果将来真正的预算或目标插件需要强制续行,应以该插件为具体消费方重新引入一个更窄的 seam。 ## 验收标准 @@ -34,4 +34,4 @@ agent(智能体)暴露了两条用户消息路径,外观相近但生命周 本提案与[移除持久化步骤边界](2026-06-20-drop-durable-step-boundaries.md)天然配对,因为移除同轮次 steering 和 `agent/turn-continuation` 后,工具调用成为一个轮次包含多个模型步骤的唯一原因。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml index b3e62c79cd..c4b40325a3 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.i18n.yaml @@ -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 -2026-06-20-single-session-acp-bridge.md: 8aa8f5d605154f697086dd5d432bbe9bd79c5dcd -2026-06-20-single-session-acp-bridge.zh.md: a056bc5acfab9d48259670170a964e8358df866c +2026-06-20-single-session-acp-bridge.md: e99de76854390a0979d1b66866d1d48aacbc0036 +2026-06-20-single-session-acp-bridge.zh.md: 1db5484c014178dfedceab20221a3d317877c35f diff --git a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md index a056bc5acf..1db5484c01 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-single-session-acp-bridge.zh.md @@ -1,4 +1,4 @@ -# RFC: 将 ACP 桥接恢复为每连接一个活跃会话 +# Agent Note: 将 ACP 桥接恢复为每连接一个活跃会话 Status: rejected — Zed is the current target ACP client and its ACP implementation is explicitly multi-session: it stores live sessions in a `HashMap<SessionId, AcpSession>`, tracks `pending_sessions`, joins concurrent loads for the same id, and tests close-during-load behavior. @@ -6,7 +6,7 @@ Status: rejected — Zed is the current target ACP client and its ACP implementa ## 问题 -ACP(Agent Client Protocol)桥接现在支持在一条 JSON-RPC 连接上承载多个活跃会话。这一能力带来了多条目会话映射、反向会话/agent(智能体)查找、逐会话的 prompt 状态、加载中 id、每条事件的解复用、跨会话拆除,以及未来权限提示与后台任务的隔离问题。较早的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)仍在追踪未完成的权限归属部分;本 RFC 是与之竞争的简化路径。 +ACP(Agent Client Protocol)桥接现在支持在一条 JSON-RPC 连接上承载多个活跃会话。这一能力带来了多条目会话映射、反向会话/agent(智能体)查找、逐会话的提示词状态、加载中 id、每条事件的解复用、跨会话拆除,以及未来权限提示与后台任务的隔离问题。较早的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)仍在追踪未完成的权限归属部分;本 Agent Note(agent 决策记录)是与之竞争的简化路径。 产品目标已经证明它需要在一个 harness 进程上承载并发的编辑器对话:Zed 的 ACP 连接拥有多个会话和加载状态。快照回放层仍然避免并发模型流,因为其回放条目是位置相关的;这是测试 fixture(测试前置数据)的局限,而非移除桥接多路复用的理由。 @@ -22,10 +22,10 @@ ACP(Agent Client Protocol)桥接现在支持在一条 JSON-RPC 连接上承 - 当该记录存在时,`session/new` 和 `session/load` 拒绝请求。 - 事件处理器不再在 `Map<sessionId, record>` 上做解复用。 - 多会话测试被移除,或移至继续支持多路复用的提案下。 -- 既有的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)更新为链接本 RFC,并继续作为当前方向。 +- 既有的[多会话 ACP 提案](../../implemented/feature/2026-06-14-acp-multi-session.md)更新为链接本 Agent Note,并继续作为当前方向。 ## 放弃了什么 ACP 客户端无法在一个服务器进程上承载多个并发对话。这是一项有实质意义的能力削减。对于一个尚未发布的 harness 而言,更简单的模型仍然合理:一个编辑器对话对应一个 agent 进程,跨会话的权限/后台任务隔离不再是活跃的正确性负担。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml b/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml index 1c341c252c..eae5710a9a 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.i18n.yaml @@ -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 -2026-06-20-truncate-interrupted-turns.md: dd8475771fcd9fdd0910bd37480a50679e87911c -2026-06-20-truncate-interrupted-turns.zh.md: 7fcd7292c8c53ebf4d784cdb79a1be58960f763c +2026-06-20-truncate-interrupted-turns.md: af18618ad4c41af125e37c51b9fd971dd8eae64e +2026-06-20-truncate-interrupted-turns.zh.md: 4deebfcc7417dd860c655813230d3a79b2d98c50 diff --git a/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md b/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md index 7fcd7292c8..4deebfcc74 100644 --- a/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md +++ b/.agents/notes/rejected/simplification/2026-06-20-truncate-interrupted-turns.zh.md @@ -1,4 +1,4 @@ -# RFC: 加载时截断被中断的最终轮次 +# Agent Note: 加载时截断被中断的最终轮次 Status: rejected — a single turn can contain substantial real work, including many steps and large tool output. Preserving interrupted turns is preferable to silently dropping that tail on load. @@ -8,13 +8,13 @@ Status: rejected — a single turn can contain substantial real work, including 当前的持久化契约会保留已持久写入但从未关闭的最终轮次。加载时,`interruptedTurnClosers()` 扫描尾部,为未应答的工具调用合成 error `tool/result` 事件,在 step 处于打开状态时追加 `step/end`,追加 `turn/end { kind: 'interrupted' }`,并要求后端持久提交这次修复。协调器、JSONL 后端、SQLite 后端、会话事件词汇、不变式、文档和测试都对这条合成关闭路径进行了建模。 -这是一套庞大的机制,只为保留上次崩溃轮次中的部分工作。它还会凭空创造从未发生过的事件。合成的工具结果虽然有用(因为它使 provider 历史保持合法),但也意味着恢复后的日志中包含了模型可见、却并非任何工具产出的文本。当前设计在尚无已发布产品、也没有真实恢复 UX 来证明部分轮次恢复确有价值的情况下,就优化了最大化尾部保留。 +这是一套庞大的机制,只为保留上次崩溃轮次中的部分工作。它还会凭空创造从未发生过的事件。合成的工具结果虽然有用(因为它使提供方历史保持合法),但也意味着恢复后的日志中包含了模型可见、却并非任何工具产出的文本。当前设计在尚无已发布产品、也没有真实恢复 UX 来证明部分轮次恢复确有价值的情况下,就优化了最大化尾部保留。 ## 提案 加载时只保留最后一个已完成的轮次。后端仍然容忍并截断撕裂的最终记录,但如果解析出的持久前缀止于一个打开的 `turn/start` 之后,规范的修复方式是丢弃上一个 `turn/end` 之后的所有事件。不合成 `tool/result`,不合成 `step/end`,不追加 `turn/end { interrupted }`,也不引入 `interrupted` 轮次结束原因。 -这使持久化的轮次边界变得简单:一个已完成的 `turn/end` 就是检查点。最后一个检查点之后的内容都是崩溃尾部。下一次 prompt 从最后一个已知合法的 provider transcript(文本记录)恢复,而不是从部分重建的最终轮次恢复。 +这使持久化的轮次边界变得简单:一个已完成的 `turn/end` 就是检查点。最后一个检查点之后的内容都是崩溃尾部。下一次提示词从最后一个已知合法的提供方 transcript(文本记录)恢复,而不是从部分重建的最终轮次恢复。 ## 验收标准 @@ -33,4 +33,4 @@ Status: rejected — a single turn can contain substantial real work, including 本提案是对[会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md)与[轮次封闭不变式](../../implemented/architecture/2026-06-15-turn-enclosure-invariant.md)的直接简化。它还移除了持久化 step 边界事件的大部分动机,使[移除持久化 step 边界事件](2026-06-20-drop-durable-step-boundaries.md)的改动更小。 -<!-- rfc-format: alternatives-not-recorded (pre-format RFC) --> +<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) --> diff --git a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml index cd0677dac6..fa0ab68ede 100644 --- a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.i18n.yaml @@ -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 -2026-07-04-prune-unimplemented-subagent-vocabulary.md: 1621bc1feee8bf98478242f002d9d1dca16878f5 -2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: b26ffee4764cd5a5937ef0436fa30c7c0eeba87a +2026-07-04-prune-unimplemented-subagent-vocabulary.md: f99a33163b48735f9634b5bb3dcac5c24eb893f8 +2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md: a1a2f35ad31a0c40d82cff00df582a488619c241 diff --git a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md index 582673f185..f99a33163b 100644 --- a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md +++ b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.md @@ -2,6 +2,8 @@ Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below records the decision-time state. +English | [中文](2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md) + ## Problem The [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) shipped a two-tier capability design: start-time capability flags checked by the service, and optional runtime methods on `SubagentRun`. Three start-time features and both optional runtime methods have zero implementations and zero callers: diff --git a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md index b26ffee476..a1a2f35ad3 100644 --- a/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md +++ b/.agents/notes/rejected/simplification/2026-07-04-prune-unimplemented-subagent-vocabulary.zh.md @@ -1,6 +1,6 @@ -# RFC: 裁剪未实现的 subagent seam 词汇 +# Agent Note: 裁剪未实现的 subagent seam 词汇 -Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below stands as the record of what is currently unimplemented. +Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below records the decision-time state. [English](2026-07-04-prune-unimplemented-subagent-vocabulary.md) | 中文 @@ -8,18 +8,18 @@ Status: rejected — the deferred capability vocabulary (`outputSchema`/`structu [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) 交付了一套两层能力设计:启动时由服务检查的能力 flag,以及 `SubagentRun` 上的可选运行时方法。三个启动时特性和两个可选运行时方法的实现数与调用数均为零: -- **`outputSchema`/`structured` 与 `toolFilter`**(`SubagentCapabilities`、`SubagentStartRequest`、`SubagentResult`,位于 `packages/subagent/subagent/src/types.ts`):每个真实提供方都声明 `outputSchema: false, toolFilter: false`(`packages/subagent/subagent-spawn/src/index.ts`、`packages/subagent/subagent-fork/src/index.ts`、`packages/subagent/subagent-acp/src/index.ts`);唯一的生产环境 `ctx.subagents.start` 调用方(`packages/subagent/tool-subagent/src/index.ts`)构造 `{ prompt, parent, signal?, agentOptions? }`,结构上无法设置这两个字段;`structured` 仅由测试 mock(`packages/support/subagent-mock`)为其自身 spec 产出。服务的能力检查包含两行 assert,其唯一执行者是拒绝测试。 +- **`outputSchema`/`structured` 与 `toolFilter`**(`SubagentCapabilities`、`SubagentStartRequest`、`SubagentResult`,位于 `packages/subagent/subagent/src/types.ts`):在作出决策时,每个真实提供方都声明 `outputSchema: false, toolFilter: false`(`packages/subagent/subagent-spawn/src/index.ts`、`packages/subagent/subagent-fork/src/index.ts`、`packages/subagent/subagent-acp/src/index.ts`);唯一的生产环境 `ctx.subagents.start` 调用方(`packages/subagent/tool-subagent/src/index.ts`)构造 `{ prompt, parent, signal?, agentOptions? }`,结构上无法设置这两个字段;`structured` 仅出现在脚本化测试 fixture(测试前置数据)中。服务的能力检查包含两行 assert,其唯一执行者是拒绝测试。 - **`SubagentRun.sendMessage` / `SubagentRun.resume`**(同一文件):没有任何提供方实现——包括 mock 也没有;spawn spec 断言的正是它们的*缺失*。 `dsh-subagent` 依赖 `dsh-tools` 的唯一原因是 `outputSchema` 的 `SchemaSpec` 类型。三个后续 subagent 工作流(per-session 快照回放、fork seed 边界、ACP(Agent Client Protocol) 后端)都围绕这块接口面落地,却没有增长出哪怕一个消费方。 ## 提案 -从 seam 中移除 `outputSchema`/`structured`、`toolFilter`、`sendMessage` 与 `resume`;将 `SubagentCapabilities` 缩减为 `{ depthLimit }`;删除两行能力 assert、三个提供方上的 all-false flag、mock 的 structured 分支及其 `capabilities`/`structured` 配置项,以及为固定被移除接口面而存在的测试(两行拒绝测试、spawn 缺失测试、mock structured spec)。从 `packages/subagent/subagent/package.json` 中删除 `dsh-tools` 的 peer/dev 依赖。更新 [subagent.md](../../../core-data-structures/subagent.md) 中的粘贴内容与 type-equiv manifest(元数据清单),以及 `packages/subagent/subagent`、`packages/subagent/subagent-spawn`、`packages/subagent/subagent-fork` 和 `packages/support/subagent-mock` 的 README 相关行。实现 PR(Pull Request)按照 [implemented/AGENTS.md](../../implemented/AGENTS.md) 修订 seam RFC 的能力目录。 +从 seam 中移除 `outputSchema`/`structured`、`toolFilter`、`sendMessage` 与 `resume`;将 `SubagentCapabilities` 缩减为 `{ depthLimit }`;删除两行能力 assert、三个提供方上的 all-false flag、脚本化 fixture 的 structured 分支和能力旋钮,以及为固定被移除接口面而存在的测试。`dsh-tools` 的 peer/dev 依赖应从 `packages/subagent/subagent/package.json` 中删除。更新 [subagent.md](../../../../docs/core-data-structures/subagent.md) 中的粘贴内容与 type-equiv manifest(元数据清单),以及受影响的提供方 README。实现 PR(Pull Request)按照 [implemented/AGENTS.md](../../implemented/AGENTS.md) 修订 seam Agent Note(agent 决策记录)的能力目录。 -**保留** `depthLimit`/`maxDepth` 与能力检查。进程内后端已强制执行该限制,尽管当前发布的 tool 尚未设置它。递归是已知的 seam 风险,因此恰当的后续工作是提供一个 tool 默认值,而非删除正在工作的强制逻辑。 +**保留** `depthLimit`/`maxDepth` 与能力检查。进程内后端已强制执行该限制,尽管当前发布的工具尚未设置它。递归是已知的 seam 风险,因此恰当的后续工作是提供一个工具默认值,而非删除正在工作的强制逻辑。 -审视过但有意不动的相邻接口面:`SubagentService.getProvider()`/`list()` 仅有测试 harness 消费方,但 [prune-dead-seam-methods 实现说明](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md) 恰好记录了这种形态从 bash executor 中被移除后又被回退的经过——对于一个基于已跟踪 map 的单行访问器而言,测试 harness 就是消费方。`SubagentRunEndInfo.lastAssistantMessage` 是一个已记录的保留项([subagent-observe-enrich RFC](../../implemented/feature/2026-06-30-subagent-observe-enrich.md) 的评审删除了 `agentType` 但有意保留了它,因为它是进程外子 agent(智能体)唯一的最终消息通道);它当前未接通的桥接转发是一个待补的缺口或待记录的消费方,不是本 RFC 要裁剪的接口面。 +审视过但有意不动的相邻接口面:`SubagentService.getProvider()`/`list()` 仅有测试 harness 消费方,但 [prune-dead-seam-methods 实现说明](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md) 恰好记录了这种形态从 bash executor 中被移除后又被回退的经过——对于一个基于已跟踪 map 的单行访问器而言,测试 harness 就是消费方。`SubagentRunEndInfo.lastAssistantMessage` 是一个已记录的保留项([subagent-observe-enrich Agent Note](../../implemented/feature/2026-06-30-subagent-observe-enrich.md) 的评审删除了 `agentType` 但有意保留了它,因为它是进程外子 agent(智能体)唯一的最终消息通道);它当前未接通的桥接转发是一个待补的缺口或待记录的消费方,不是本 Agent Note 要裁剪的接口面。 这是[从持久化 seam 裁剪死方法](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md)在 seam 词汇层面的回响:每个实现都必须为无人声明的成员,甚至更弱,因为这里连一个实现都没有。 @@ -27,13 +27,13 @@ Status: rejected — the deferred capability vocabulary (`outputSchema`/`structu ### 为什么不保留? -两类能力的设计是 seam RFC 的核心亮点,日后重新添加 `outputSchema` 会涉及多个文件。但该设计以 `depthLimit` 作为活跃示例、以 RFC 作为记录仍然成立;而且 seam RFC 本身承认已交付的 `toolFilter` 形态是错误的(真正的强制需要在子 agent 上下文中实施 `tools/pre-execute` deny,而非 schema 过滤)——该 deny 原语已存在于拦截 seam 上,因此基于真实实现提供方重新添加时,将固定出一份比当前推测性契约更好的契约。 +两类能力的设计是 seam Agent Note 的核心亮点,日后重新添加 `outputSchema` 会涉及多个文件。但该设计以 `depthLimit` 作为活跃示例、以 Agent Note 作为记录仍然成立;而且 seam Agent Note 本身承认已交付的 `toolFilter` 形态是错误的(真正的强制需要在子 agent 上下文中实施 `tools/pre-execute` deny,而非 schema 过滤)——该 deny 原语已存在于拦截 seam 上,因此基于真实实现提供方重新添加时,将固定出一份比当前推测性契约更好的契约。 ## 验收标准 -- 被移除的拼写仅出现在本 RFC 和修订后的 seam RFC 中;`SubagentCapabilities` 为 `{ depthLimit: boolean }`;`dsh-tools` 依赖边已消除(`hygiene` 绿色)。 +- 被移除的拼写仅出现在本 Agent Note 和修订后的 seam Agent Note 中;`SubagentCapabilities` 为 `{ depthLimit: boolean }`;`dsh-tools` 依赖边已消除(`hygiene` 绿色)。 - 深度强制测试不变且绿色。 ## 风险 -subagent 生命周期事件在结束载荷上携带 `lastAssistantMessage`——该增强位于服务模块中,不在本 RFC 缩减的 seam 词汇范围内;observe-enrich RFC 记录了因缺少消费方而删除 `agentType` 兄弟字段的判断,本 RFC 延续了这一判断。CC hooks 桥接是这些生命周期事件的第一个外部消费方,它只读取事件载荷,不涉及本文移除的任何接口面;observe-enrich RFC 推迟的控制流重设计将实现 `resume` 列为自身的未来工作——恰好是本 RFC 模式所预期的重新添加触发点。 +subagent 生命周期事件在结束载荷上携带 `lastAssistantMessage`——该增强位于服务模块中,不在本 Agent Note 缩减的 seam 词汇范围内;observe-enrich Agent Note 记录了因缺少消费方而删除 `agentType` 兄弟字段的判断,本 Agent Note 延续了这一判断。CC hooks 桥接是这些生命周期事件的第一个外部消费方,它只读取事件载荷,不涉及本文移除的任何接口面;observe-enrich Agent Note 推迟的控制流重设计将实现 `resume` 列为自身的未来工作——恰好是本 Agent Note 模式所预期的重新添加触发点。 diff --git a/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml b/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml index b6d3903ddd..34f8bdb0c9 100644 --- a/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.i18n.yaml @@ -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 -2026-07-12-collapse-workflow-to-foreground-core.md: eaf8a4a22766e06b743a7b91d2a607eb6c8e67d9 -2026-07-12-collapse-workflow-to-foreground-core.zh.md: 4b1f4ebbec852386ca4577a38a9bd41b7529e500 +2026-07-12-collapse-workflow-to-foreground-core.md: 629e2140523c3ae7caf533de99821206d05f1b8e +2026-07-12-collapse-workflow-to-foreground-core.zh.md: 3cdaeebe42ca799a48c5321b70c07e6151d8f98d diff --git a/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md b/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md index 4b1f4ebbec..3cdaeebe42 100644 --- a/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md +++ b/.agents/notes/rejected/simplification/2026-07-12-collapse-workflow-to-foreground-core.zh.md @@ -1,4 +1,4 @@ -# RFC: 将工作流收缩至已使用的前台核心 +# Agent Note: 将工作流收缩至已使用的前台核心 Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it. @@ -6,7 +6,7 @@ Status: rejected — Workflow progress is an intentional observation surface; ma ## 问题 -工作流能力执行前台 JavaScript 来编排 subagent,但它同时携带了一套无人消费的进度观测系统。没有任何生产环境的监听器订阅六个 `workflow/*` 事件中的任何一个;监听器仅存在于工作流测试中。尽管如此,seam 定义了 run/phase/agent outcome 载荷,worker 发送 phase/log/agent 生命周期协议消息,host 通过一个 `liveAgents` 配对账本转发它们,引擎维护 run id 仅仅是为了关联这些通知。 +工作流能力执行前台 JavaScript 来编排 subagent,但它同时携带了一套无人消费的进度观测系统。没有任何生产环境的监听器订阅六个 `workflow/*` 事件中的任何一个;监听器仅存在于工作流测试中。尽管如此,seam 定义了 run/phase/agent(智能体) outcome 载荷,worker 发送 phase/log/agent 生命周期协议消息,host 通过一个 `liveAgents` 配对账本转发它们,引擎维护 run id 仅仅是为了关联这些通知。 这套进度词汇不仅仅是未被使用;它在不经重新设计的情况下也无法服务于其唯一已命名的未来消费方。`WorkflowRunInfo` 包含 `{id, meta}` 但没有父 agent(智能体)、会话或工具调用标识,而面向模型的工具也从不暴露 run id。一个全局 ACP(Agent Client Protocol)监听器无法将事件路由到正确的客户端会话。`meta.phases` 从未被查询,`phase(title)` 不对其做校验,phase 的 `detail`/`model` 和 agent 的 `label`/`phase` 仅供事件消费,`whenToUse` 被校验和复制但从未被渲染或用于选择。`phase()` 和 `log()` 仍然跨越 worker 边界,尽管没有接收方。 @@ -20,7 +20,7 @@ live handle 在观测者消失后仍重复事件时代的数据。`WorkflowRun.i 保留已使用的核心:`agent(prompt, { schema, model })`、`parallel`、`pipeline`、`args`、并发/agent 上限、取消、有界 dispose(资源释放)、结构化结果、worker 隔离与前台工具收集。移除所有 `workflow/*` 事件及其仅供事件使用的 info/outcome 类型;移除 `phase()`、`log()`、agent 的 `label`/`phase`、phase 声明、`whenToUse` 及其 worker 消息/host 观测者;将工作流元数据收缩为工具实际使用的 name;移除仅供事件使用的 run id/meta 快照与合成的 agent-end 账本。将 `WorkflowRun` 收缩为 `result`、`cancel()` 和 `dispose()`;工具渲染请求方持有的 name。移除 `WorkflowStartRequest.signal` 及 worker host 的 input-signal listener/disarm 状态,保留调用方从其 abort signal 到 `run.cancel()` 的桥接。将 `WorkflowError` 变为单一的 fatal 错误类,不再有布尔模式或 `isFatalWorkflowError()` 辅助函数。 -修订已实施的 dynamic-workflow RFC,并更新 seam/tool/worker README、工具 schema、生成的 catalog 与 package 依赖图、worker type-equiv 记录、单元测试以及工作流快照/header fixture(测试前置数据)。如果进度 UI 工作被立项,应从一份命名了父 agent/会话/工具调用的关联契约出发,而非原样复活这套协议。 +修订已实施的 dynamic-workflow Agent Note(agent 决策记录),并更新 seam/工具/worker README、工具 schema、生成的 catalog 与包(package)依赖图、worker type-equiv 记录、单元测试以及工作流快照/header fixture(测试前置数据)。如果进度 UI 工作被立项,应从一份命名了父 agent/会话/工具调用的关联契约出发,而非原样复活这套协议。 ## 曾考虑的替代方案 @@ -32,7 +32,7 @@ live handle 在观测者消失后仍重复事件时代的数据。`WorkflowRun.i - 不再保留任何工作流事件、phase/log 协议消息、run-id 生成器、仅供进度使用的元数据、host 配对账本或 fatal 模式分支。 - run handle 不再有 id/meta 回显,取消在同步 `start()` 返回后只有一条持有者拥有的通道。 - parallel/pipeline 行为、上限、取消静默、worker 隔离、结构化输出与面向模型的工作流场景保持测试覆盖。 -- 类型检查、覆盖率、快照、doc-sync、module-graph 校验、构建与 hygiene 全部通过。 +- 类型检查、覆盖率、快照、doc-sync(文档同步门禁)、module-graph 校验、构建与 hygiene 全部通过。 ## 风险 diff --git a/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml b/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml index 0c7d9feb75..d1a52c0efb 100644 --- a/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml +++ b/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.i18n.yaml @@ -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 -2026-07-12-prune-unused-skill-registry-surface.md: 5b90deca8681373b2cc2befa3ab341084f924a3d -2026-07-12-prune-unused-skill-registry-surface.zh.md: 7b0e24f49688ed61f2ac4bff93b4c3f85117a170 +2026-07-12-prune-unused-skill-registry-surface.md: 5a13effa04a6cd9954741a0a33ebc6fc3512fab8 +2026-07-12-prune-unused-skill-registry-surface.zh.md: 4b25c03d740f4fda1696629d56b88057a055f0af diff --git a/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md b/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md index 7b0e24f496..4b25c03d74 100644 --- a/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md +++ b/.agents/notes/rejected/simplification/2026-07-12-prune-unused-skill-registry-surface.zh.md @@ -1,4 +1,4 @@ -# RFC: 裁剪 skill 注册表中未使用的接口 +# Agent Note: 裁剪 skill 注册表中未使用的接口 Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins. @@ -10,13 +10,13 @@ skill(技能)服务的嵌入式运行时子系统中,`ctx.skills.register( ## 提案 -移除 `SkillService.register()`、`SkillRegistration`、运行时伪提供方及保留名称规则、运行时 revision/缓存分支,以及仅用于运行时的 source/rank 规范化逻辑。需要嵌入式 skill 的测试改为注册一个小型真实提供方。保留 `providerRevision` 作为进行中的发现 epoch,但已完成的目录缓存仅以 cwd 为键:每次提供方变更同步清除缓存,await 之后的 revision 比较已能阻止插入陈旧结果。从 skill 契约和 local-provider 副本中移除 `whenToUse`、`SkillCandidate.path` 与 `SkillDefinition.path`,同时保留提供方的 locator/root 路径;保留 `metadata`、`disableModelInvocation`、`source`、`provider`、`locator` 和 `resourceBase`,因为它们要么是有意开放的扩展词汇,要么是生产消费的字段。 +移除 `SkillService.register()`、`SkillRegistration`、运行时伪提供方及保留名称规则、运行时 revision/缓存分支,以及仅用于运行时的 source/rank 规范化逻辑。需要嵌入式 skill 的测试改为注册一个小型真实提供方。保留 `providerRevision` 作为进行中的发现 epoch,但已完成的目录缓存仅以 cwd 为键:每次提供方变更同步清除缓存,await 之后的 revision 比较已能阻止插入陈旧结果。从 skill 契约和本地提供方副本中移除 `whenToUse`、`SkillCandidate.path` 与 `SkillDefinition.path`,同时保留提供方的 locator/root 路径;保留 `metadata`、`disableModelInvocation`、`source`、`provider`、`locator` 和 `resourceBase`,因为它们要么是有意开放的扩展词汇,要么是生产消费的字段。 -同步修订 skill 系统 RFC、README、JSDoc、目录文件与测试。agent(智能体)作用域的系统提示词段、工具提供方和变量明确不在本提案范围内:[agent 作用域贡献者契约](../../implemented/architecture/2026-07-08-agent-scope-contexts.md)有意允许在 `setup(agentCtx)` 期间通过 agent 拥有的上下文注册这三者,因此仓库内没有固定的作用域注册并不能证明它们未被使用。 +同步修订 skill 系统 Agent Note(agent 决策记录)、README、JSDoc、目录文件与测试。agent(智能体)作用域的系统提示词段、工具提供方和变量明确不在本提案范围内:[agent 作用域贡献者契约](../../implemented/architecture/2026-07-08-agent-scope-contexts.md)有意允许在 `setup(agentCtx)` 期间通过 agent 拥有的上下文注册这三者,因此仓库内没有固定的作用域注册并不能证明它们未被使用。 ## 曾考虑的替代方案 -**保留面向嵌入方的运行时 skill 注册。** 这是已实现的 skill RFC 中有意提供的同步直接定义便利接口。一个小型提供方包装层可以在 effect 拥有的生命周期下暴露相同的嵌入数据,但它必须实现异步 `list()`/`get()`、携带提供方身份,并接受提供方的重复语义。本提案选择只保留一条统一的提供方路径,而非维护第二套排序、校验、缓存失效与查找路径。 +**保留面向嵌入方的运行时 skill 注册。** 这是已实现的 skill Agent Note 中有意提供的同步直接定义便利接口。一个小型提供方包装层可以在 effect 拥有的生命周期下暴露相同的嵌入数据,但它必须实现异步 `list()`/`get()`、携带提供方身份,并接受提供方的重复语义。本提案选择只保留一条统一的提供方路径,而非维护第二套排序、校验、缓存失效与查找路径。 ## 验收标准 From 672f2e5ec5c0bc339b97337f8fdffca6381e58fc Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:11:20 +0800 Subject: [PATCH 107/368] fix(pty): await unpublished spawn teardown --- ...26-07-16-persistent-pty-sessions.i18n.yaml | 4 +- .../2026-07-16-persistent-pty-sessions.md | 4 +- .../2026-07-16-persistent-pty-sessions.zh.md | 4 +- packages/pty/pty/README.md | 1 + packages/pty/pty/src/index.ts | 70 ++++++++++++++---- packages/pty/pty/tests/service.spec.ts | 74 +++++++++++++++++-- 6 files changed, 130 insertions(+), 27 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml index f7998a7615..96d1e06bbe 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml @@ -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 -2026-07-16-persistent-pty-sessions.md: afa6f1771931ed437d8c2c34204ad4a59d02248e -2026-07-16-persistent-pty-sessions.zh.md: 2af97c3d126f8639e6b52685fb7fea1292343c9b +2026-07-16-persistent-pty-sessions.md: a73b8d0247243cc0d9cc93f27d84a8540b3b271d +2026-07-16-persistent-pty-sessions.zh.md: b0dc4010f69206b7aaeab4164199ffd935165955 diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md index afa6f17719..a73b8d0247 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md @@ -34,7 +34,7 @@ Idle detection is backend behavior, not a second public seam. A remote or contai There are no plugin-load auto-start sessions. `terminal_open` creates a session only during an agent tool call, when ownership and the owning event-sourced session are known. A future declarative startup feature must compose through unpublished agent setup rather than create shared global terminals. -Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. +Agent-scope disposal closes registrations first, then awaits quiescent teardown of every owned PTY. Unpublished backend setup is a tracked lifecycle operation: owner or service disposal aborts its service-owned signal, waits for backend settlement and rollback, and only then returns. Caller cancellation retains its exact `AbortSignal.reason` even when the backend rejects in response. Backend or tool-plugin reload does not orphan sessions: ownership lives in `PtyService` until the agent ends, following the same service-owned-record pattern as [`ctx.tasks`](../../../../packages/tasks/tasks/README.md). The service reserves the session synchronously for one active send before returning its operation, including before a background task id becomes visible; a second send fails with `SEND_ACTIVE`, so output and cancellation cannot cross operation ownership. ### Security and process boundary @@ -152,7 +152,7 @@ The package ships concise tool guidance explaining persistent state, owner isola ## Verification -- Per-file coverage pins owner fencing, concurrent reservations, sandbox-mode change rejection, retriable lifecycle cleanup, readiness tiers, sanitizer carry state, complete UTF-8 bounds, task integration, schemas, and exact render intents. +- Per-file coverage pins owner fencing, concurrent reservations, unpublished-spawn cancellation and awaited teardown, sandbox-mode change rejection, retriable lifecycle cleanup, readiness tiers, sanitizer carry state, complete UTF-8 bounds, task integration, schemas, and exact render intents. - Linux process fixtures cover non-leader and non-main-thread stdin waits, zombie quiescence, unreadable process state, supported syscall tables, unsupported architectures, and false-positive rejection; macOS inspector logic is injected into the same unit suite. - Real `node-pty` tests exercise shell state, shared sandbox policy, environment scrubbing, raw-mode foreground `SIGINT`, a TERM-ignoring descendant, and immediate post-disposal quiescence on supported hosts. - A Loader-driven `cordis.yml` test mounts the real three-package composition, while ACP and headless snapshots pin the six schemas, bounded results, error rendering, and terminal/generic cards through opt-in overlays. diff --git a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md index 2af97c3d12..b0dc4010f6 100644 --- a/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md +++ b/.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.zh.md @@ -34,7 +34,7 @@ idle 检测属于后端行为,不是第二条公共 seam。远程或容器后 实现不提供插件加载期 auto-start 会话。`terminal_open` 只在 agent 工具调用期间创建会话,此时所有权和所属的事件溯源会话都已确定。未来的声明式启动功能必须通过尚未发布的 agent setup 组合,而不能创建全局共享终端。 -agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 +agent scope dispose 时先关闭注册,再等待全部所属 PTY 静默退出。未发布的后端 setup 同样是受追踪的生命周期操作:owner 或服务 dispose 会中止服务自有的 signal,等待后端结算与回滚完成后才返回。即使后端响应取消而 reject,调用方取消仍原样保留其 `AbortSignal.reason`。后端或工具插件 reload 不会遗留会话:所有权持续存放在 `PtyService` 中,直到 agent 结束,与 [`ctx.tasks`](../../../../packages/tasks/tasks/README.md) 的服务持有记录模式一致。服务会先同步把会话预留给一次活跃发送,再返回该操作;后台发送同样会在 task id 对外可见前完成预留。第二次发送会以 `SEND_ACTIVE` 失败,因此输出与取消无法跨越操作所有权。 ### 安全与进程边界 @@ -152,7 +152,7 @@ plugins: ## 验证 -- 每文件覆盖率固定 owner 隔离、并发预留、沙箱模式变更拒绝、可重试的生命周期清理、就绪层级、sanitizer carry state、完整 UTF-8 结果上限、task 集成、schema 和精确 render intent。 +- 每文件覆盖率固定 owner 隔离、并发预留、未发布 spawn 的取消与等待式 teardown、沙箱模式变更拒绝、可重试的生命周期清理、就绪层级、sanitizer carry state、完整 UTF-8 结果上限、task 集成、schema 和精确 render intent。 - Linux 进程 fixture 覆盖非 leader 与非主线程的 stdin 等待、僵尸进程静止性、不可读进程状态、受支持的 syscall 表、不支持的架构和误报拒绝;同一单元测试套件通过注入覆盖 macOS 检查器逻辑。 - 真实 `node-pty` 测试在受支持宿主上覆盖 shell 状态、共享沙箱策略、环境清洗、raw mode 下的前台 `SIGINT`、忽略 `SIGTERM` 的子进程,以及 dispose 返回后立即静默。 - Loader 驱动的 `cordis.yml` 测试挂载真实三包组合;ACP 与 headless 快照通过 opt-in overlay 固定 6 个 schema、有界结果、错误渲染和 terminal/generic card。 diff --git a/packages/pty/pty/README.md b/packages/pty/pty/README.md index 6916a4ef82..624b771164 100644 --- a/packages/pty/pty/README.md +++ b/packages/pty/pty/README.md @@ -6,6 +6,7 @@ Owner-scoped persistent PTY seam. `PtyService` registers as `ctx.pty`, mints opa - Backends register one stable `type` and return an unpublished `PtyBackendSession`; failed or cancelled setup must clean partial resources. - Spawn cancellation preserves the caller's exact abort reason. Service disposal and owner loss remain distinct machine-routable failures after backend setup. +- Owner and service disposal abort unpublished setup through a service-owned signal and await backend settlement plus rollback before returning. - `hasOwnerActivity(owner)` spans unpublished setup through final close, so lifecycle policy can fence the exact owner without a publication race. - A successful spawn publishes one `PtySessionId`. The optional `name` is owner-local display metadata, never authority. - One session accepts at most one live send operation. Reads and signals may observe it; another send fails until the operation settles. diff --git a/packages/pty/pty/src/index.ts b/packages/pty/pty/src/index.ts index e809f50e3e..1b937b9dff 100644 --- a/packages/pty/pty/src/index.ts +++ b/packages/pty/pty/src/index.ts @@ -87,12 +87,22 @@ interface SessionRecord { closing: Promise<void> | undefined } +interface PendingSpawn { + readonly controller: AbortController + readonly settled: Promise<void> +} + +interface SpawnReservation { + readonly signal: AbortSignal + release(): void +} + /** In-process registry for replaceable PTY backends and exact-Agent sessions. */ export class PtyService extends Service { private readonly backends = new Map<string, PtyBackend>() private readonly sessions = new Map<PtySessionId, SessionRecord>() private readonly reservedNames = new Map<Agent, Set<string>>() - private readonly pendingSpawns = new Map<Agent, number>() + private readonly pendingSpawns = new Map<Agent, Set<PendingSpawn>>() private readonly ownerCleanups = new Map<Agent, () => Promise<void> | void>() private readonly disposedOwners = new WeakSet<Agent>() private nextId = 0 @@ -145,7 +155,10 @@ export class PtyService extends Service { if (backend === undefined) throw new PtyError(`no PTY backend registered for "${request.type}"`, 'NO_BACKEND') if (request.name !== undefined && request.name.length === 0) throw new Error('PTY session name must be non-empty') const releaseName = this.reserveName(owner, request.name) - const releaseSpawn = this.reserveSpawn(owner) + const spawnReservation = this.reserveSpawn(owner) + const backendSignal = signal === undefined + ? spawnReservation.signal + : AbortSignal.any([signal, spawnReservation.signal]) const sessionId = PtySessionId(`pty-${++this.nextId}`) let session: PtyBackendSession | undefined try { @@ -155,7 +168,7 @@ export class PtyService extends Service { type: request.type, ...request.name !== undefined ? { name: request.name } : {}, ...request.cwd !== undefined ? { cwd: request.cwd } : {}, - ...signal !== undefined ? { signal } : {}, + signal: backendSignal, }) signal?.throwIfAborted() if (this.disposing) { @@ -176,16 +189,27 @@ export class PtyService extends Service { this.sessions.set(sessionId, record) return this.snapshot(record, session.motd) } catch (error) { + let rollbackFailure: { error: unknown } | undefined if (session !== undefined && !this.sessions.has(sessionId)) { try { await session.close('PTY spawn rolled back') } catch (closeError: unknown) { - throw new AggregateError([error, closeError], 'PTY spawn and rollback both failed') + rollbackFailure = { error: closeError } } } - throw error + let failure: unknown = error + try { + signal?.throwIfAborted() + spawnReservation.signal.throwIfAborted() + } catch (cancellation: unknown) { + failure = cancellation + } + if (rollbackFailure !== undefined) { + throw new AggregateError([failure, rollbackFailure.error], 'PTY spawn and rollback both failed') + } + throw failure } finally { - releaseSpawn() + spawnReservation.release() releaseName() } } @@ -196,7 +220,7 @@ export class PtyService extends Service { * @returns true across the entire spawn-to-close interval, with no publication gap. */ hasOwnerActivity(owner: Agent): boolean { - return (this.pendingSpawns.get(owner) ?? 0) > 0 + return (this.pendingSpawns.get(owner)?.size ?? 0) > 0 || [...this.sessions.values()].some(record => record.owner === owner) } @@ -314,15 +338,31 @@ export class PtyService extends Service { } } - private reserveSpawn(owner: Agent): () => void { - this.pendingSpawns.set(owner, (this.pendingSpawns.get(owner) ?? 0) + 1) - return () => { - const remaining = (this.pendingSpawns.get(owner) ?? 1) - 1 - if (remaining === 0) this.pendingSpawns.delete(owner) - else this.pendingSpawns.set(owner, remaining) + private reserveSpawn(owner: Agent): SpawnReservation { + const controller = new AbortController() + const settlement = Promise.withResolvers<void>() + const pending: PendingSpawn = { controller, settled: settlement.promise } + const owned = this.pendingSpawns.get(owner) ?? new Set<PendingSpawn>() + owned.add(pending) + this.pendingSpawns.set(owner, owned) + return { + signal: controller.signal, + release: () => { + owned.delete(pending) + if (owned.size === 0) this.pendingSpawns.delete(owner) + settlement.resolve() + }, } } + private async abortPendingSpawns(owner: Agent | undefined, reason: PtyError): Promise<void> { + const pending = owner === undefined + ? [...this.pendingSpawns.values()].flatMap(owned => [...owned]) + : [...(this.pendingSpawns.get(owner) ?? [])] + for (const spawn of pending) spawn.controller.abort(reason) + await Promise.all(pending.map(spawn => spawn.settled)) + } + private expectOwned(owner: Agent, id: PtySessionId): SessionRecord { const record = this.sessions.get(id) if (record === undefined) throw new PtyError(`unknown PTY session ${id}`, 'NO_SESSION') @@ -344,6 +384,7 @@ export class PtyService extends Service { } private async disposeOwned(owner: Agent): Promise<void> { + await this.abortPendingSpawns(owner, new PtyError('PTY owner is no longer live', 'OWNER_NOT_LIVE')) const owned = [...this.sessions.values()].filter(record => record.owner === owner) await this.closeRecords(owned, 'PTY owner disposed') this.reservedNames.delete(owner) @@ -351,11 +392,12 @@ export class PtyService extends Service { private async disposeAll(): Promise<void> { this.disposing = true - const records = [...this.sessions.values()] // Teardown is best-effort: a close failure still clears registries and runs // owner cleanups before the aggregated error propagates, so one stuck // session cannot orphan backends, reservations, or owner detachers. try { + await this.abortPendingSpawns(undefined, new PtyError('PTY service is disposing', 'SERVICE_DISPOSING')) + const records = [...this.sessions.values()] await this.closeRecords(records, 'PTY service disposed') } finally { this.backends.clear() diff --git a/packages/pty/pty/tests/service.spec.ts b/packages/pty/pty/tests/service.spec.ts index 21587163f6..52d22bd4b3 100644 --- a/packages/pty/pty/tests/service.spec.ts +++ b/packages/pty/pty/tests/service.spec.ts @@ -206,9 +206,10 @@ describe('PtyService ownership and lifecycle', () => { ctx.agents.register(owner) const pending = ctx.pty.spawn(owner, { type: 'slow', name: 'main' }) await expect(ctx.pty.spawn(owner, { type: 'slow', name: 'main' })).rejects.toMatchObject({ code: 'DUPLICATE_NAME' }) - await disposeAgentScope(owner) + const disposal = disposeAgentScope(owner) gate.resolve(session) await expect(pending).rejects.toMatchObject({ code: 'OWNER_NOT_LIVE' }) + await disposal expect(session.closed).toEqual(['PTY spawn rolled back']) }) @@ -231,19 +232,70 @@ describe('PtyService ownership and lifecycle', () => { expect(ctx.agents.get(owner.id)).toBe(owner) }) - it('rolls back an unpublished backend session when service disposal wins', async () => { + it('preserves caller cancellation when a backend rejects in response to it', async () => { + const ctx = await harness() + const started = Promise.withResolvers<undefined>() + const backendFailure = new Error('backend observed cancellation') + ctx.pty.registerBackend({ + type: 'abortable', + spawn: ({ signal }) => new Promise((_resolve, reject) => { + if (signal === undefined) throw new Error('missing spawn signal') + started.resolve(undefined) + signal.addEventListener('abort', () => { reject(backendFailure) }, { once: true }) + }), + }) + const owner = stubAgent(ctx, 'owner') + ctx.agents.register(owner) + const controller = new AbortController() + const reason = new Error('cancelled by caller') + + const pending = ctx.pty.spawn(owner, { type: 'abortable' }, controller.signal) + await started.promise + controller.abort(reason) + + await expect(pending).rejects.toBe(reason) + }) + + it.each([ + { scope: 'owner', code: 'OWNER_NOT_LIVE' }, + { scope: 'service', code: 'SERVICE_DISPOSING' }, + ] as const)('$scope disposal aborts and awaits unpublished backend setup', async ({ scope, code }) => { const ctx = await harness() const gate = Promise.withResolvers<PtyBackendSession>() + const started = Promise.withResolvers<undefined>() const session = new StubSession() - ctx.pty.registerBackend({ type: 'slow', spawn: () => gate.promise }) + let backendSignal: AbortSignal | undefined + ctx.pty.registerBackend({ + type: 'slow', + spawn: (spec) => { + backendSignal = spec.signal + started.resolve(undefined) + return gate.promise + }, + }) const owner = stubAgent(ctx, 'owner') ctx.agents.register(owner) const pending = ctx.pty.spawn(owner, { type: 'slow' }) - await disposePtyService(ctx) + const pendingFailure = pending.then( + () => { throw new Error('pending spawn unexpectedly succeeded') }, + (error: unknown) => error, + ) + await started.promise + let disposalSettled = false + const disposal = (scope === 'owner' ? disposeAgentScope(owner) : disposePtyService(ctx)) + .then(() => { disposalSettled = true }) + await new Promise(resolve => setTimeout(resolve, 0)) + const signalAbortedBeforeRelease = backendSignal?.aborted ?? false + const signalReasonBeforeRelease = backendSignal?.reason as unknown + const disposalSettledBeforeRelease = disposalSettled gate.resolve(session) - await expect(pending).rejects.toMatchObject({ code: 'SERVICE_DISPOSING' }) + expect(await pendingFailure).toMatchObject({ code }) + await disposal + expect(signalAbortedBeforeRelease).toBe(true) + expect(signalReasonBeforeRelease).toMatchObject({ code }) + expect(disposalSettledBeforeRelease).toBe(false) expect(session.closed).toEqual(['PTY spawn rolled back']) }) @@ -290,14 +342,22 @@ describe('PtyService ownership and lifecycle', () => { ctx.agents.register(owner) const failedSpawn = new StubSession() failedSpawn.rejectClose = true + let ownerDisposal = Promise.resolve() ctx.pty.registerBackend({ type: 'bad-spawn', - async spawn() { - await disposeAgentScope(owner) + async spawn({ signal }) { + if (signal === undefined) throw new Error('missing spawn signal') + ownerDisposal = disposeAgentScope(owner) + if (!signal.aborted) { + await new Promise<undefined>((resolve) => { + signal.addEventListener('abort', () => { resolve(undefined) }, { once: true }) + }) + } return failedSpawn }, }) await expect(ctx.pty.spawn(owner, { type: 'bad-spawn' })).rejects.toThrow('spawn and rollback both failed') + await ownerDisposal const nextOwner = stubAgent(ctx, 'next') ctx.agents.register(nextOwner) From 590115448e9475f805c6bc5104ee1003bb119f28 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:15:21 +0800 Subject: [PATCH 108/368] docs: refresh PTY service catalog --- docs/cordis-catalog/services.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index e85be21c1d..ab739db024 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -841,7 +841,7 @@ list(owner: Agent): PtySessionSnapshot[] Types: [Agent](../core-data-structures/core.md) · [PtyBackend](../core-data-structures/pty.md) · [PtyReadRequest](../core-data-structures/pty.md) · [PtyReadResult](../core-data-structures/pty.md) · [PtySendOperation](../core-data-structures/pty.md) · [PtySendRequest](../core-data-structures/pty.md) · [PtySessionId](../core-data-structures/pty.md) · [PtySessionSnapshot](../core-data-structures/pty.md) · [PtySignal](../core-data-structures/pty.md) · [PtySignalResult](../core-data-structures/pty.md) · [PtySpawnRequest](../core-data-structures/pty.md) · [PtySpawnResult](../core-data-structures/pty.md) -Source: [`packages/pty/pty/src/index.ts:91`](../../packages/pty/pty/src/index.ts) +Source: [`packages/pty/pty/src/index.ts:101`](../../packages/pty/pty/src/index.ts) ## `ctx.sandbox` — `SandboxProvider` (abstract seam) From ef325b02fafe1d6046482a15e1be3909fb81eb63 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:15:44 +0800 Subject: [PATCH 109/368] docs: make the top-level README product-first --- ...-07-22-product-first-root-readme.i18n.yaml | 6 + .../2026-07-22-product-first-root-readme.md | 29 +++ ...2026-07-22-product-first-root-readme.zh.md | 29 +++ .agents/skills/dsh-arch-diagram/SKILL.md | 158 ------------- .../dsh-arch-diagram/harness-arch-en.html | 66 ------ .../dsh-arch-diagram/harness-arch-zh.html | 66 ------ .../skills/dsh-arch-diagram/harness-arch.css | 220 ------------------ .agents/skills/dsh-arch-diagram/render.sh | 97 -------- README.i18n.yaml | 4 +- README.md | 64 +++-- README.zh.md | 68 ++++-- assets/arch-en.png | Bin 681579 -> 0 bytes assets/arch-zh.png | Bin 677426 -> 0 bytes assets/demo-acp.mp4 | Bin 4675786 -> 0 bytes 14 files changed, 172 insertions(+), 635 deletions(-) create mode 100644 .agents/notes/implemented/process/2026-07-22-product-first-root-readme.i18n.yaml create mode 100644 .agents/notes/implemented/process/2026-07-22-product-first-root-readme.md create mode 100644 .agents/notes/implemented/process/2026-07-22-product-first-root-readme.zh.md delete mode 100644 .agents/skills/dsh-arch-diagram/SKILL.md delete mode 100644 .agents/skills/dsh-arch-diagram/harness-arch-en.html delete mode 100644 .agents/skills/dsh-arch-diagram/harness-arch-zh.html delete mode 100644 .agents/skills/dsh-arch-diagram/harness-arch.css delete mode 100755 .agents/skills/dsh-arch-diagram/render.sh delete mode 100644 assets/arch-en.png delete mode 100644 assets/arch-zh.png delete mode 100644 assets/demo-acp.mp4 diff --git a/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.i18n.yaml b/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.i18n.yaml new file mode 100644 index 0000000000..5647413ef0 --- /dev/null +++ b/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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 +2026-07-22-product-first-root-readme.md: 3d295d39119e9dd70af53cef68948d928a69120a +2026-07-22-product-first-root-readme.zh.md: ebfa0904536fe409873afa5dc88b76d4f7ee9dc7 diff --git a/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.md b/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.md new file mode 100644 index 0000000000..3d295d3911 --- /dev/null +++ b/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.md @@ -0,0 +1,29 @@ +# Agent Note: Product-first root README + +Status: implemented + +English | [中文](2026-07-22-product-first-root-readme.zh.md) + +## Problem + +The root README is the first page for people evaluating DeepSeek Harness, but SDK-first contributor detail competes with the shortest path from product identity to installation and launch. Exhaustive package inventories, architecture diagrams, demos, and duplicated technical explanations also age faster than the interfaces they describe. + +## Decision + +The root README presents DeepSeek Harness as an installable coding agent first. It names the SDK foundation, keeps the supported one-line installer, and puts the Web UI, TUI, and headless entry points before architecture and contributor material. + +The capability overview stays compact: it identifies the familiar built-in coding capabilities, makes plugin extensibility the distinguishing design, and presents Code Mode and the self-referential Cordis tools as explicit opt-ins. Detailed contracts remain at their owning documentation and are linked instead of copied into the root README. + +The English and Chinese READMEs share the product, installation, capability, development, and license structure. Their community sections intentionally follow the primary channel for each language audience: Twitter in English and the WeChat community QR code in Chinese. The QR code is the only retained README media because it is a functional entry point rather than product decoration. + +## Alternatives considered + +**Keep an SDK-first contributor README.** This makes the repository architecture visible immediately, but it delays the answer to what the product is and how to run it. Contributor orientation remains available through the development and architecture links. + +**Adopt a full marketing page with badges, screenshots, an architecture diagram, a package catalog, and tutorials.** This provides more material on the landing page, but duplicates fast-moving facts and creates media maintenance work before the product surface is stable. + +**Use the same community channel in both languages.** Exact channel symmetry is simpler, but it is less useful when the two language audiences gather in different places. The technical content remains paired while the community destination is audience-specific. + +## Consequences + +A new reader reaches a runnable interface quickly and can follow stable links for deeper SDK details. The root README stays small enough to update whenever the installer or CLI surface changes. Rich media, package inventories, and long-form tutorials remain outside this entry point until they have a durable owner and maintenance path. diff --git a/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.zh.md b/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.zh.md new file mode 100644 index 0000000000..ebfa090453 --- /dev/null +++ b/.agents/notes/implemented/process/2026-07-22-product-first-root-readme.zh.md @@ -0,0 +1,29 @@ +# Agent Note: 以产品为先的根 README + +Status: implemented + +[English](2026-07-22-product-first-root-readme.md) | 中文 + +## 问题 + +根 README 是评估 DeepSeek Harness 的读者最先看到的页面,但以 SDK 为先的贡献者信息会挤占从产品定位直达安装与启动的最短路径。详尽的包(package)清单、架构图、演示以及重复的技术说明,也比其描述的接口更快失效。 + +## 决策 + +根 README 首先将 DeepSeek Harness 呈现为一款可安装的 coding agent(编程智能体)。它说明产品基于 SDK,保留受支持的单行安装命令,并将 Web UI、TUI 和 Headless 入口置于架构与贡献者资料之前。 + +功能概览保持简洁:它说明常见的内置编程功能,突出插件扩展性这一差异化设计,并明确 Code Mode 和自指 Cordis 工具都需显式启用。详细契约留在各自的权威文档中;根 README 只提供链接,不复制内容。 + +中英文 README 采用相同的产品、安装、功能、开发和许可证结构。社区章节则有意采用各语言读者的主要渠道:英文版指向 Twitter,中文版提供微信社区二维码。二维码是 README 中唯一保留的媒体,因为它是实际入口,而非产品装饰。 + +## 备选方案 + +**保留以 SDK 为先的贡献者 README。** 这能让读者立即看到仓库架构,却延后了“产品是什么、如何运行”这两个答案。贡献者仍可通过开发与架构链接获得所需指引。 + +**采用包含徽章、截图、架构图、包清单和教程的完整营销页面。** 这会让落地页承载更多材料,却会重复易变事实,并在产品接口稳定前增加媒体维护工作。 + +**两种语言采用同一个社区渠道。** 渠道完全对称更简单,但当两种语言的读者聚集在不同平台时,这种做法实用性更低。技术内容保持配对,社区目的地则按读者群体选择。 + +## 影响 + +新读者可以快速进入可运行的界面,并通过稳定链接了解更深入的 SDK 细节。根 README 足够精简,可在安装器或 CLI 接口变化时及时更新。在富媒体、包清单和长篇教程拥有持久的负责方与维护路径之前,它们不进入这个产品入口。 diff --git a/.agents/skills/dsh-arch-diagram/SKILL.md b/.agents/skills/dsh-arch-diagram/SKILL.md deleted file mode 100644 index 86306a3faf..0000000000 --- a/.agents/skills/dsh-arch-diagram/SKILL.md +++ /dev/null @@ -1,158 +0,0 @@ ---- -name: dsh-arch-diagram -description: Regenerate the DeepSeek Harness "System overview" architecture PNGs (English + Chinese) that the top-level README embeds. Reflects the current state of packages/* and docs/architecture.md. Use when the codebase adds/removes/renames services and the README diagram must be refreshed. ---- - -# dsh-arch-diagram - -Produces `assets/arch-en.png` and `assets/arch-zh.png` in this repo — the two hero images embedded at the top of `README.md` and `README.zh.md`. - -The pipeline is HTML + Chrome headless, so text quality, layout, and connector geometry are **deterministic** — every rerun produces the same output regardless of model. - -Aesthetic is locked to the DeepSeek brand: light blue gradient background, brand-blue Cordis bar, sans-serif everywhere, no serif / no italic / no hand-drawn feel. - ---- - -## When to use - -- User asks to "regenerate" or "refresh" the Harness architecture diagram -- User points out `packages/` has changed (new services, renames) and the README diagram is stale -- User just added a new `packages/<family>/` or a new `ctx.*` service and wants the diagram to reflect it - -## When NOT to use - -- User wants a different diagram (Code Mode, Workflow fanout, agent lifecycle) — those belong in `docs/` and need their own skill -- User wants a different visual aesthetic (dark mode, hand-drawn, editorial-serif) — this skill is locked to DeepSeek brand - ---- - -## Workflow - -### 1. Enumerate current services from the repo - -The diagram is grounded in two lists that live in the docs: - -- **Default Services** — from `packages/core/*` and `docs/architecture.md`'s "Default Services" table. As of last refresh: `ctx.sessions`, `ctx.systemPrompt`, `ctx.tools`, `ctx.agents`, `ctx.agentLoop`. -- **Capability Services** — from the non-core capability packages and `docs/architecture.md`'s "Capability Services" table. As of last refresh: `ctx.llm`, `ctx.bash`, `ctx.sandbox`, `ctx.codeRuntime`, `ctx.fs`, `ctx.skills`, `ctx.web`, `ctx.compact`, `ctx.subagents`, `ctx.workflows`, `ctx.sessionPersistence`, `ctx.sessionQuery`. - -**Do this**: - -1. Read `docs/architecture.md` -2. Extract the two `ctx.*` tables verbatim -3. Cross-check against `packages/`: services live under `packages/core/*` (defaults) or under `packages/<family>/<package>/` (capabilities). The inner package dir mirrors the npm name without the `@deepseek-ai/dsh-` prefix — e.g. `packages/session-query/session-query/` publishes `@deepseek-ai/dsh-session-query`. Never assume the inner dir carries a `dsh-` prefix. - -### 2. Diff against the current HTML templates - -Read `harness-arch-en.html` and `harness-arch-zh.html` in this skill directory. Pull out the currently-rendered `ctx.*` names. Report the diff: - -``` -Default services: no change -Capability services: + ctx.<new>, − ctx.<removed>, ↻ ctx.<renamed> -``` - -### 3. Update the templates - -If there are changes, edit both HTML files in place. Each card is one line: - -```html -<div class="card"><span class="name">ctx.something</span><span class="desc">short description</span></div> -``` - -For a **new** service: -- Description is **short** — 2–4 words (EN), 3–6 chars (ZH) -- Ground the description in what the package's README or its `ctx.<name>.register()` **actually** does. Do NOT paraphrase from an abstract or invent capabilities the code doesn't have. -- Add the card in **both** languages, in docs order. - -For a **removed** service: delete the card in both files. - -For a **renamed** service: update the `.name` span in both files. - -**Do not touch the layout**. Rows are: -- Top row (`row top`): exactly 5 default-service cards -- Bottom row (`row bottom`): 12 capability-service cards - -If the capability count grows past ~13, the row gets visually tight. Stop and ask the user before shrinking fonts or wrapping to two rows. - -### 4. Render to PNG - -```bash -bash .agents/skills/dsh-arch-diagram/render.sh -``` - -Default output: `<repo>/assets/arch-en.png` and `<repo>/assets/arch-zh.png` — the paths that `README.md` and `README.zh.md` already reference. - -Pass an alternate directory as `$1` to write elsewhere. `CHROME` and `PORT` env vars override the browser path and http.server port. - -The script: -- Spins up a temporary `python3 -m http.server` on `127.0.0.1` (needed so Google Fonts CDN loads reliably in Chrome headless) -- Runs Chrome headless twice at `--force-device-scale-factor=2 --window-size=1536,580` -- Writes two 3072×1160 PNGs (~600 KB each) -- Tears down the server - -### 5. Verify by eye — mandatory, do not skip - -After rendering, **open each PNG and visually check every item** in this list. Do not report the diagram as done without going through it. - -- [ ] Top-row card count matches the Default Services list you extracted in §1, every name rendered in full (no truncation on the longest, e.g. `ctx.systemPrompt` / `ctx.agentLoop`) -- [ ] Bottom-row card count matches the Capability Services list you extracted in §1, every name in full (especially the longest, e.g. `ctx.sessionPersistence`) -- [ ] Every card has a description underneath, and the description matches what the code does (not made up) -- [ ] Bar reads `Cordis · microkernel (vendored)` (EN) / `Cordis · 微内核 (vendored)` (ZH) -- [ ] Number of vertical connector lines equals (top-row cards + bottom-row cards) from §1. All straight vertical, all parallel, each reaching the horizontal center of its card -- [ ] `cordis.yml` sidebar visible on the right; dashed arrow points left into the bar -- [ ] `deployment leaf` / `部署清单` and `picks which plugins load` / `决定哪些插件加载` are readable and NOT crossed through by any connector line -- [ ] Chinese descriptions render as CJK glyphs, not `□` tofu boxes (means fonts loaded) -- [ ] No large empty gradient area at the bottom of the image — if there is, tune `--window-size` in `render.sh` - -If any check fails: fix the CSS or template, re-run `render.sh`, re-check. Do not report "done" on first render without visually confirming. - ---- - -## Design system (locked — do not modify without explicit user request) - -Colors: -- Background: `linear-gradient(135deg, #ffffff 0%, #e8effc 100%)` -- Brand blue (Cordis bar + connectors): `#4a6ef5` -- Ink text: `#1a1a1a` -- Muted text: `#8a8f9c` -- Card border: `#dde3ef` -- Card fill: `#ffffff` - -Typography (**sans-serif only** — never serif, never italic): -- English title & body: **Inter** (Google Fonts) -- Chinese title & body: **Noto Sans SC** (Google Fonts) with `PingFang SC` local fallback -- Code labels (`ctx.*`, `cordis.yml`, `vendored`): **JetBrains Mono** (Google Fonts) - -Layout: -- `.page` max-width 1560 px, centered -- `.bus-row`, `.row.top`, `.row.bottom` all 96% width, centered -- Top row: `flex: 1` on each card (equal widths) -- Bottom row: `justify-content: space-between` + `flex: 0 0 auto` on each card — cards keep their intrinsic (nowrap) width and adjacent card backgrounds cannot clip a description -- Bus: `#4a6ef5` filled, 60 px tall, 8 px radius -- `cordis.yml` sidebar `position: absolute` at `left: calc(100% + 20px)` of `.bus-row`, width 130 px -- All connectors: CSS `::before` / `::after` pseudo-elements, 2 px wide, 40 px tall, `#4a6ef5`, centered via `left: 50%; transform: translateX(-50%)` — this is what guarantees pixel-perfect vertical parallel lines regardless of card content - -Rendering: -- Chrome headless `--force-device-scale-factor=2` -- `--window-size=1820,580` → output is 3640×1160 (aspect ~3.14:1, wider than square-ish so a 12-card capability row fits without truncation) -- Local http.server on `127.0.0.1` so CDN fonts load cleanly - ---- - -## Files in this skill - -- `SKILL.md` — this file -- `harness-arch.css` — shared design system (colors, fonts, layout, connectors) -- `harness-arch-en.html` — English template -- `harness-arch-zh.html` — Chinese template -- `render.sh` — Chrome headless renderer - -Templates are self-contained. Fonts load from Google Fonts CDN; no local font files. - ---- - -## Rules I keep breaking (and shouldn't) - -1. **Verify the output by looking at it.** Don't report "done" and move on — actually inspect each PNG and check every item in §5. -2. **Ground service descriptions in the code, not the docs' abstract, not the marketing copy.** If unsure what a package does, read its `src/` or the `ctx.<name>.register()` block. -3. **Don't touch layout unless asked.** 96% row/bar width, 40 px connector height, and 60 px bar height are all tuned. Card counts grow one at a time; once the bottom row starts to visibly overflow again (adjacent card backgrounds clipping a description, or the `cordis.yml` sidebar falling outside the render viewport), stop and ask before shrinking fonts, widening the viewport further, or wrapping to two rows. -4. **Never introduce a serif font or italic.** Not for titles, not for annotations, not "to make it feel editorial." This diagram is DeepSeek brand: sans-serif, upright, only. diff --git a/.agents/skills/dsh-arch-diagram/harness-arch-en.html b/.agents/skills/dsh-arch-diagram/harness-arch-en.html deleted file mode 100644 index 117f606e97..0000000000 --- a/.agents/skills/dsh-arch-diagram/harness-arch-en.html +++ /dev/null @@ -1,66 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=1536, initial-scale=1.0"> - <title>DeepSeek Harness · Architecture - - - -

    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 z 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%0Dd~I%67*dKIdo_F)vO_mhe3f0% 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%0DhST1no*WlEJRPukH5MZL(0<46PDmcP{& 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

    F}ja9(9yacf~oH=aiLdF@2ItL4E5qAGH0 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≈;EXO(=xYpaB+3@GU)MF;$VW9$yG|?t% zrkJSLH$bb#Z{U9D{h1c`vFPRSXK`JS)jzF>R4JL@0xo<)LEXK!Eq#7eAaB2QJUwc< zi=vT~{I;aQp3LKVP;4LVim~mUu^6hXp9pl;P8**Cn2`t6yzBfcG--hI3?W& zLlEvRqR=R5O_s42v5C;@1QqB^CIt+MA*IL`%X!q_9!7+q=>%Jqg;!=dcH7hQy^36E zm5H0On!_q{dP9@GFj9F-t{Lgy%kVsQ#XhKCijyFy4p$s;V~z?~UXK-c?mi%bA!KTA zJ<_`LgFhSjI(Oj7QN3F9==8>iI#bLKT?aMG8L^FWE;rnuJ9@3h`3{#*pi)s;e_iNv z#N?kKrv<8ov)t4_ChWyJ5bNz^oM9f~mq*5|c$}$U3==IS1rbSpY%+^MtkFw^lzLT# zY6la~OMtS{49Q5G%%#`fu%|7j>cv2>G@PG*UG2AJF?H^j{xwt3<8k&SoBu!hfY@<^ zS*I%d9LXGJ`z%4tI^;bA)vQC3sp#Ms$@#<7hQ94*yO$Ppsc4fZSBoz zz}F^zU!oO-11RHU^_v?vhSbt`l}M1d27K0(>@M;WkR%v$p1TTdHN#a5WzPLymzbAM zl`=YMB#sP8T$@)aHA7~UO1*zJ+U7JbwK-h`>P7%2DedDo@<10Xc2K1|RZZo|a;?BS zZ3fZi9PV0F!m>BcDOaFhY6gmQ1Xx}rN+34S=1@9=Gg4UMVB=2g!%AaZ@C(B@SK%*5PIXl>YbVT|4;0={ zb=HSjAcpu(y=<`0UU4ULd3b@0`m#H~G%W#hQ;K()bT=He6wvCK-0M-~a}qo-h~;_$ zg7cLdFgm;7JWVsxEx=eZDDs^CymWJyklZ#D*HRfe8}Jg6Iud35W~YK9J=0*DEJavd zS>wA*c;|?YHlM`SrAn^uSRG6}p6mz)3^3}nIN4piKfV14%9Z`JU<#A9$l$5>i^}?^ zaW7KD_&lZMSj2 z+xEU8O0=%>sbkG`4uv9(tKaaPz9j()>%boXr-SGZeaA0ze5|t2UD`Fc>NYq`3==!_ z|6!wPYs(ADN&jPwt{l*iMw?OZ5$mT6gTu9Yk%hjjTP4P7su?Vig5xy(a;{Ofgg@}& zlfp?ag~`Pi@q-?NKv4&bgaXN$DrM39|P#iptz^ITL(1FC|$waT%akfbT2 zq)p?R&$Pe^Cv-&=%M1;#WVnK>`5HT5_4Zv}aYwSs0gH&&Q!!BiIFh`?Ljmlq1+lk* zN4^%l5)Bim1eBTD<5GqFMG-jNv>9Vjm893vT+d7{&g6Kro!yiKMWqtr9&gboR1nlV z9y5fG3Bcn?YxU$m;m7qoe2G9Uz>uOZHy^M;)MFMFA6Uj0};tGr_5V_7OEwL zK_bDi(iqCh1uJRSs`QpBmrovY;9H!qRKaZp5q|77M{BFi|Logd{;j#Yw8l(5e-G`S zFJ_@QC|epd5n;JBf%yMazsu=DWrhV#k;%Fb>M?mcGFy2{+6Ae>lpGcj%YUDp29IOf z?W#ql3tAbgSCH$9zb3xMgA(T5c_ZzAZMDv?pGLnqv?yW<5&1!lp<~2e$YZPt@azx0 z@*Vh8&O)TP_0t~&uh}R~Ny|*ap(-yc=Ys}6lW++Wl?xWc ziTiosMxTA>e|Fkzmf@;#SH%!Y2j^*ZG+c-=$Z>ImG&{X@c1Bal^LKz9gy8H1wfTIa z=P0D`6HQA6ep=iP#e2kCL_t$k*=Y!+OeDBr=|D&WEs@LSw5h}o?9fg&>##*0PH|PO z0fT5xW&38hSNSNKfNfze?y6*H8WvA$^bNghOr#RC6vki*$+r z0oyn>QB(6gann_Sx-*s);&bprM4CUE{tt=y4!kI{A=}8M%k``oxgH(*IeVA|WhnU? z6_IIpnE=-Y*T!Umi?!7;WIiD^PQa%=xVCvO2Rmq zZ3$ZuILI&nGeFG05jDetuqDbirNgj?86UASpARNN+}|ZcY*9G@vIy_WmyeeZG;JCT z&TUBW73Z~Zi`)FI6*UpU1TY0R79ztWi{9)S)s(f9)v9o5J>Kgf>H++JywVUbPjR+^MYi`DLs^eQG zE?V8Hny)QsWa=GDytL zx_%WF5Of(45e^-Q!hnK^_w{R?W^k8C2rHfeQd!F~z*Z(-{rz)s22`ltTyI``L&MOk zD9~TIuzi?5b)1q&P~s^Es&F1+)1-WsAS^>c+(spppS>fK5-DW2*=p!Km*6I0)-K#?Wn-!Ox!N03?dvCC|Q|PZu z2+q_d`w^A&jRv6&KO87`hMT{cvYh`~;EJBlHAZce`U7SpAZ49xC3(@~!~es`HNI=% z+6LsaKc6|4s?=sKk;Nm<9Dhv)cV2IRH-K`n50j;PvO~(6_Q@f(R>8voK z0r`CRd+y0)*JgtxdlDHj1{$uhbQf(iqEusto`eFWsG-_9ajVcjf zg?}if^REQPiFCUEm8sr(kqGF2^Iaw3L2!^1RUU#xB>Y`=pf@n74zlC2z(mIHo z+9@1j!W2a(%L&GnGbP~-m1CF~MH^)M->WZ{o#L{pCf)ziZ8hYC@>8KhqdmvdZq~v7 zQEJl%0!leYqx1Dhu3AA)c6ZPRi@$D7v_+S5D-mu2d*iusfK_I3`Z){O+MffTa8^1H zZ-w*F-GRpV@8B@?gUR0&ZW&xIo>S;+qFWGUVe6ai0OiT^iGTvda=Cbwl*+vRnue$^ zR#ib}(>ruV8!f8d_VBD+qz{fAR7pZxOo3c!MuBHDO^i$7 zA#cU7s#-=E@1ktK9X%Ls$__vej?_;m4S)pEQ=Gflm~)}>Q|j^l(DAP&|M0jmTS|F* zTxzwXIbdumG2f&z;+K?0)}@LCa_~ZdDQb7)TRA;$numQ@UT)!z_dMCO!*Kx!6;3y7 zEIz5Ou#p?QP-g6ke2hxDWKXoN<4|*E952nM9BH{6j-CQrzXZ|D`O{0AukMvl zhOA1N(DBG_PX(s+onVTeH{*P=Ovf$-5Adv@-6@x>d{u_F@@!SNIrTN5??DytAYL1! zL=58LC$YJyr|thw8puH#roqXa$~J2pQt%E?vCa37S-7PUZ6-COmDs_YJ%^?9dYprW z9cUYw$~i zQreEn!dRnGMDm7hDhBtb3siFs3Pc$8Qba?ukXdj%#Q(WKAUrh_KEHRYo$%8nr)6&l zlTB>bDLQaq@P4zIA3Lv~@Lcy9J2+ z*gDccJD-=nq7tC;hM zja-#6%*`ZJ$=zdS=7VxB^#qb<^+dyLe+y5~4Biz8-H5%PR9tld&%}hXf2qp=*%=It zLQX^;g<}u_CaOvRAg~5KFS5U`J5d%dedri;( zPWr2bSt$3m@>W4?v7L_h+{^joM084P#NMP2DEBVVwby@}cByPF+*CGOs1wQ^XJ;*H zRHr`ZpA|tj?WKAy0*eW9`S4_Ik2T}WNp{8KzGW>@ww!g51ptrb{EvI(@+k zuxotuGYVihLOQ`sMRCzV4+>}7B-`gg3A83+=h&S-VuI2XNvz8xPM_hyM23z^WKa9A z+-Gh6Eq=;SQkILc2}JSm^1Pg+M_F6UB)H5am%$rsj>=pOfTFKohl5Q_Laj=UpS_-k z%1n^vT$XI&nME106&P|ET?p)QbQC!4W4UsyM)L%3UAk{S(0&8DBm1> zT_3NcvV7e6c;f)KBdI5Kt(%lJA2u<;iio|ar*VK6)W)rO<|NO zR7j?vPJSfciXbuy!7DGz=U-s@DscCJpM{n;%@^AzJvV-Gcor;3SD+O?Ww%^fwdvan zSO$*pJ5~A~ZZV@D$d=I?UiOAmA} zsfG5f@tnL>lj5b~^{=Hl{bl7zR@f?pE^`ZdpuljbN@(#4+hQ!;UW3>jfrY&V_A|e8 z3&!xAUzFQkNTsyr!M5T@5SO?|&8gLmL(xb7jxj=gcU{!AmiOpJ^v(6wDl=U1I&WuP zyDRs@+mwRhwr%anl_}eMj7|8}ZPsaR9b#dhuqyn;U#cBvWDL-Bg}>(BERPOO2^t~& zpDW}t|3L&OL`)&&On$R8>winS1E=4>QE1tUQ3DG_6S2877JHViY~E+XAL!qN6j;sn zv;ROMeo0%yAu+$m#a7o!%7mBTh@vh&a~;N*6FA8IP*Kxa6|m2j8BTmy=a;33-ZE!CnR4CoH%WsYiZ+kPyXgs8-EANCPUmYu3Lr~2#m*uk zwBUaBf<{yR?nnHTr&6%1_D#Nh0RTSTEfWPwm2^w0z(MJk9VrzxASR@$aqY1!kN5)2 z-2dLl@n*OsWKX{tooZO~e+S1La5d}Yn-KFo+*kDj99g;vi0(Q!B0P`7NhcLbsCA7f zp_cK2E&Hu(^2$R^ng9oX8MzK{?*QyzB zV}&JpbD;Gm0--Pl{gUImcq}|foB*vM#PepWGtPjV|Ec@DP}H-&q{TnzuRE~kNFSX% zH$1$1Aj&14nGc=bO2Z>Kdk_nE8ZBnO^OPxe->Rk`Bn2eb^S0Aq<{g7r8R9Q=nUVnp zQv-5gkr8^Ci3o+oPla88qkp=ZLL2!pkYtsFw8HzV+SkKcjbz+b|ib@73j7yqx49QU!H};&^=dZ0zv}^^yNd-_d z1{N(3RciW$42K@iwsj?-xSmCK?eHo8J6PEWKUC8aNC%XeJe^nobzqAap|O}2FBSbT zw33pexqMsEPofqSAkq}x9?T4g;+c}qQH1awiP$fH1UjTeY~TzDUE-68EN_<9{wql# zT}h8g=)HQfM}aI_&rBBGF6Z?3c-8(b5dj|OSfru3&fVU)VbwEhNJctDIXc|Ee-Pom zMkeYXO-i=!Gh$tW^%)%=xLm^W19m?apubCP`QOEFWr#t~3ZMdElb_ytNgb4b=S zBcAcLgMt1t;j@lmGJp+4;*?|0L%7ZU)INxEEyWZV267Wv)p+)XEUATbUct#?Uz>lR z0!~eQo8U(%l<&{khR$JyGl`{~8f?zgZLDeEUUxar9DTIB1<8e8l<}BwnN#&U0DI_E zfQ0d6a^)&xX1D0UYdgmCQfK*04hbJ}d6A_3MgkgXT4aN?$y4+>fiX-ymW=mrh20az zkwPfKrLw-Vb?bnas(JM5Ha}<3X-gwdU6>q@Xv3amjAt}*+R@tYC=~{_wNfUJHyt_k z-oxq*G6cCNEARXFcbje1(83Y7_6D+1{31_6(_eBh1U|>nL}Irw(S<|Qm55;Mqu88` zo07lmnv8PSas)H`7a$-Z#;^RrKdJvFXyQ5hQ&rB=kHPAoDj}r|*zf+)?b^`SI#rCp zL)x-Aedk*x+8Tv8iJZ>Sg>NoL;nnybj)V^aoasWIu}R}^Sv?jmooabL5;!=MPL<0x zpz(P^XLJRoR4Nrt{g|@KmCpv|M3%tS^nx6m=;;o-;Wom%a|2`zOag~;5MzbU(&T%v zX2-5@@P+L5f-D3Zlf1d@D9BUuJ;p(Gek)kC0v~YTJnI2Yoa}gRTdb&MXqM_o1~tVc z0-aTR&7o@GKbhzz5Cn!Q!fwGWl*wdv^rGRUz#i0O$Ui)d*gA$Wi83N z-D6snwE}cz9~?tvNQ>P&AYaP`x}AIP;9^{b+iE}cvW|W>yiR;1JDuSb-%s_} zsPiP_aXHhC6946ju|f?UH6u7{Z+gG_LUfI>SZqN_1m&*;fb4p?GU`>6Y)1LP&EkX7 zTAYHlw;>f^O99g?wF48EdH+n20>G1nTMMa=+&9roOG_@+o-ZeDp6>!pGU5IaM!XcW zi+p*5Ut0x~fwbMBUIW~Pe{z$LID#Oh|KKIe!h*K>w`26xe}-_DEc^2Z8|h|jk)9+6 zow-Cz(D?QedIa(v@tsF(3Zzh9YHovpQZY+^pFkZSDmTN0Egc*L^r1a0nP@h_pwLQe zm`Y?0ERQE?U_tfwSs^R-^$LOTQP@H7JfPUEY~%u*_qAxx1~B#g|8FNxdI>?!bLGe*+bqzMpUQi?0TA~TDu`3#L(s# z$A^2JxFY*{tb)_=(|u|so=&4M@%R0CD{@uW6;_EZ)~T}s=%(zTIulu%;I}BC;eh@o z-iG9O0b^3n@15sIKI>`zPt3 z7@eLL=s76@ioV+ke%aaMoK&%=i_<8sMt5f8T`Wn%DZzinZYtT>BNyE>*UmGrwWMMS z^G4mbZa?5`(__k!d6j=M|EoE3y47#TjZ1TjxiQdJELi z4zJJViKvZ==DzunAiK>>|7REmBpXs65fWp`(Y>o!cMUIkINb2zbB5}s|E_MdL+ZrRug@#Q4C(u!tN()&dEq?fWb`F_*zU%Beir%wZI`29mFgG{Ny1*QQgtgl&ppULMXs5 z=E@u!6`1<=zy4`tA!x8NLn_ON6Eu`_SQV5PB$wjD%iO(o`Z=+f5}ABEb@`C-R?V2t zxCjE}N<^_aCpau$FOSZI%S8@r04s>dU`g^E)^$vzxbJ)SaMzl2x@*!4M5U5Vd|-Ll zrXupw+RUXE_W_f$_LO2uNNS+1Y%*H;MwwN5h2SWh3M4L4GEl&I5Ovm{M&je9R6t{! z;Qfl}n37$0&S;u5W;!mI-Bw97O!<*sjEVYjIP34!Q1%-xT(om1(-(3MV$f=Ax>*ho z)WrzX8v*h(CUVgNtt=_)1|#~_R+ds9;Eu*~kixfS+yJx_Fh$CW`%+fRlDfA;;YH-^ zn{Ly7#HKabTIj)8=K|~*d?KKo13hErVbnO$sTcE@5q4;Vc(CgE6>&VYd3Kyhxui;x zkY$<_wyx@X+qn~UXLvdKkhPT11=DMWFKCvA_uOZO>;>dLq5B>UlsFohQjkdOA?3Mt znX4#HZ3c5b1s?iH<#QCa3j>Mp8ON-eH@ux@d@y&}jZZ+A%EA0m>YcYlQYSrkW`&xL z0`D<04pT0KITVi*2lge;gdYtLW+NWwgOnqOV@Px={KEsxR2H+61UHIqu!2~fA&`1jJz>neo_mq90G5?!z$ttIyL5}phV_Na%KtHXYc~(3LbHLO*G7o}*#GoLI4o~c z?E`46?&?}mYN3T#%axihQJvU%XJXj>Hho$q70=cKX%P=EQ22PVu227|2GNdk3d0!3 z69KkWQlws*{iWhkjv=PNzw63{!-JyZTF#37gnc$&zGsL&nFpdv8$f-M;$_62qo9x4h`GH1LNs^OP8W3E^4<*E;Xp#>Ru&3}>vM(WNF>xaF!qGB zT#6WEg(>Gb=dhJGWvh@yK|f79>C#F@U6Hr>;ySs!fi0;;=k7Cb{>pGQc~XnQf`#mQ z-`xTZBdpNbUv&z;spMG;PH3{Oh%E#?dpYoaQT*?3Fw8CB!Ab!Q`f}+tU99=BVO2BF zGx;3bzjk|X&nhj4dOtSeyq#~7o8sU`9{B&mhxR*w{U0^1u6i+54hH_!A0*7(7?d}t z|4zs|Cyrqfu#DQa8PK#m*>7vGs#&T5lv;^$<}K#O(N>08?|@mLS|5v{3v3q)*1}Ui zxnr1P{sO0b%Pa>*bk{N@vKA_JzIuWQQS)TkUjU*joJbZ3z8?ZJShys#dO!+A& zdi^++w~Sg-3`>j!HVURrGWpVj8J3hTX?}iVeq8+(}K$SmrAyPCJn!2$?aJ*ht8qtHf0M z>45BS=1TQ;Gh#2uvVn^T3hPV+0GNE;B`Nj>ZYX6s0m&woAU4f`@~{5=FHiSU3?MrS z^(dLCgtrDd>))xZ5Si%LF}wAONYkM))Cl+>;Nc$#pT2k7+TaY1KrY}&bC=(jewnYh z@N1dD3<7m-x?i8rt2-?VSjeb-NM9uYVX9d~Uy2 zb#JnhSrTO82NQDcWQn3U*)i@wsQXjcclb; zi7X@NRhaw6X)jFeG$HxHE$vUr!I+xMdPaUAkBZB{BLlLTzg~MTLX)Jra+)gvy4sc* z{vxIkj@@+x(0Ga2H@aw3DVfvYwjJGXAtEJryJj`73oq|F^`;RtN@9<|>fjJQUwRF*Mskw5C^@drZ+Q~_&AY>7DD z^0;{qv!+5i38#1RPmSF=843n=sa+dDE7aT}j#k_+QVV@sw9K4(D2e$6+7u>JS2TKA zI@;sSZ+w@J&4kGfzo@7+dD9272$qP%pq3I%AtxGRgRxB+&E|4 z2uOMmc`9Q?rd5A+&9M(OcMVR@@1+u)<(wLjz2TpUT-IodUkna+eJxyPw@bElmcE$C z2hxBN=a~hDy2jL;#wt2MogMQ-4~UuXp>dH^)}CccJU{L?;iPa&v&HOCjZj1-pvl<4 zx$qQ(-Z{PleK6IxvCCM^>N7lUCk}=)6m5NjP!27!mjz?)379PmUE-)_$)DD;ig?m)B6+ z1rIB2+OX+&>>>4!#K|OLB*vvh%K_b**q=2PzZlgU&8{m9fkF>oNM1!TrE(2@c2}LN zY>EE6s{a@FUv$dFOo z{0k=ApB0~_l&co_`=rfYx^Ov^@3AmJmwXpYZ%Lv%6f3iy$`+*HddrWz5NmxdAYXd^ zeo3T*Q-`E?R4Rv7;IPFEe7xZ$A?siQb7;go4&7I}Lx%4Zw;~{7n~sdIhfyG$?cf}t z`R8jY8>VN#z9*a~{Myi~4sTF`_K3jgqc=r}{WYv4;TUtjz{q|~ZBlC(eBHLw{v4$f z4b8DEvMtdHm8rG=mND#&28|;|&{f4%M3FW9TPCGsjgWMOaAcg5818dZp?Ob#RI&}q zxRQb@=K0rawLwXoUZ$HQNY1$i;azL673<*)7;X6J#;S6P>*EvWvf@Lfc^{a*3;r;R z5AeDJL8`--k<^$Y*B(7xOwRvEMoF}vx#H{kZGiwsOL^Hn3417-fhRO|UeK67VNLD? z;1N^`D=-9D2BxcD_R&U^cFz;lfU&I61D;a4J0|hIlc>%M%)>f@KVuy;SAgUds5|8Y zMh?fZM@dBYpB{=Fps8m-Sc;|$?2n55_w8U*DId+IC-n8(^k7kC12iE!+aVkjlenfl zrO}%3fY|M=p2i{!9{Pi+h6gBVP>@}OW2p~8cao72&4pV1+zz*{eaams6C1F<0ax`^ z4HDIu!mH@i)-xEj(^56*q;iwtqK|=U2_9&}Y(>j%0`~a=fmEXoaD%2LU$Cx_cr2T| z(~Z6|q7|m86u=>cvIkB6|J2)ZpM3;~!2SYd&za9!vFO_ZHd4mu@ox?fGJ2+#V4(>- z3U^;`l~gfm+I6i+rIweIwSlMAh;b1WX@}2!5FLoU8%#@#bBrgwm_Q{r^FC4o_oN7y zTPg*afCW=6b3el)ua>2iu+9p(*;5-f?e`T$gyoj-Jea^!)JW76+F_%lehh*b!HuLf zx+nYh27Cz`az@c!-bgSTkyqhxZkOdoc-Y@?T)D%+Dao@ZRR=q=c4ftWA5yo@fp>*? zN!`lNxhA^dX3}Xk*blTkSi2b&!PNnNX zGFA0VE~x@@ulPoP$5iqy<&y7-ZasRPH#-iEEXaX+3?aLMvtgVpa!?1I5;VvM1^h(9 z7u-dR3eNcQsT@=bv#Bk!={d;fhj0={u7mZ5Z`a5GDb-&ecH;YwKof2FeeH=$y;;O;7VcPq$YC5Vs+fNY==h zu0E8quKA~FXw-h$OM8>=?~xBqEHVM$J?Tfo_oSp@OJ!qy^^I;GZIeN5|`yq1;IP*1etXnm%xUEx(; z7xO(Ecr4Hl8{-7pjZb6TOYR!=9};CVBEKo`; z$FCM4R>{OVU&urAi@SW%^!bxXHv=5geX#m4o#@Fq;-e-aF zK~q*Ak||_g2t>yW1Zw#~Al!cNLgQ2+4bO(S-`r<*tjCPKMC`~AlYS5nu`eld_5Oc^ zG`sEXM#qdZ0I#}w?y*V)$f&4uAYeRjgJ5Fu~Hl zOf<#!1PWbv$MZv!G`_rVehnUt30{yLH`mXG3WtgR13O@qvwKYaz%g`{9Dq&mk;af# zp+f!TB!v>hL^ub12e}^)z$>oKSwS!BN?|D#*Q%TVt6yQOY`r#m95Wg8k2`DKKBL}H zjMQufV-k1c_l(WBSbh;WI;x{%7mmCDxVO}3$lgzXr#bJkns$W_6rz=U#?;9i1~JhT zoqWJ0S!cHZ)MI6-O*gVru-pRVcFLmv1R`OKS4?4l7eS_3EEc%y#E#Q+L)!4jV>^*$hxVsImx9p7c~E z5BbFvn6W0caUQfEP2s>{59>(ocd%H0xR*oje>u#Qi9V^Zfy9{35sLhll9mnG&<8QD zH9kt4szZdtXj3&ufU4rfIe#IeQ>CnvjAVsMww>r!Phz_o%+>e9$QH_9dLYY7yXjP} ziB;0m<8I1DlOjml!u|{X!e?A)0HkUBg7w_*^K+I?G;du@FPufTiiOOFlSv@QDuG<{ z?vom&MbJyL1ruI82bkB><(0Kkf=se;8dtX#Rr}^`YT(jRR0!)!KQ^-VGD+ z$ty)4EIc2)Ls96M^3(f>!L{HTzP2r}UVO^;5z6IwNN^9;d# z%3=WyRd!98$hHOEJD2-P6G5$a>9#-?S#u`PAmuuM`6C4zQjuFoLw$XpQCUr;d|N*Vc*C}*8TuNTfi~Yn}T(Q3H@XTo?F`@ z#PLwq$Q+qVfOl_+3XsP%0sa|V1Hpj~fFc!Hu@0Yy zDk>Ndd?Kv2P@-hX;F6)5WrIdxrmrBJ^ysaHR8#{D8q6<-yw{KZj?)v#>0$B0IN&bpuvPa%BaF z_`_+|PKBLU=PCxeGDafY?Xga9$DS=3s&B@d!PW%X%c?Md$$kPmUgMa{ipde=y;E%n z)>gF)!aG^?^K{V_$p{cp#a)4ENS>f6+Q=^vKw{ZRUB9^%ZAtEa44>-RlZFrU8V=kU z!~XFFS*69Pm}vWLE0SLrHXE+p5!{3N6Spr9^j9G%XtFW=7M~(t7ubu|)RMhaN!}BI z1VGPxcSG`Y11eyOwnvUb2&lS6>xJ|SLtWscoo`9^vnH$bA=F!h=kO$*Peb5teabY; zQYLbM`EZ>hFEm_X$3b|Ku^o&|pZJU3NX;n4<=eAA-`2bW8|{hgbD7UcU(w%g^ zU|r1LT+F*moqd+wxv)I)oXA()r}f2+4NI!vkxDV#4rLnP_-aEDWoU+=$E*xxB_@Wt zc)8&6G^ptap7yUple%55ZuX99k(XYYv9Xo~c}Y}_%tV*s4ewji{cujH3`%&&y2*m3 zOqI6woT%gOV?X<_nB8}Who*e*5H+hwXArf%8zg=Z+V|IgHRkH9!FoFTiI%{*>PPl2 znu)aEGFg9W1XN~`PP=QE?aFX(%VnwH(&BCc`1;->fUm_d*{(l12?9^U-(S#NXbB=p zC%wl?^O?Y`8(5(@L>m54WdCYJgLbRvm~D2?_3vt(Gl~~G>tNX-)KCl`a#yZ{pmaLS zuu>H@&tt$_&j=v?2#Q=g$%F4lYruk}gNXrwY_`KLJODou^!=~^EhF{%sWuX@Zlp7F zg_yn3V}1TVOB@To!zHQ`JEN$-{tI&fJ7XpHO%Dw6UWh;h=v745ExO*T_jry{qbA_X zl~U6ZK}T>mEr5~S$HiK3(0#U^DG%PsS<8s$2^A?=2%n<=aVKchmY=K6m8g7(LS!TR z%7M$-Ht`m-0J04MZx}%bnRkN=(>$~xDNn)Tt8cZnqB1(j1WJ8#hEBtQ*!0QS-3t#w zNV%m6cD=QQV96NIY&ZWOeIo2j3%`48WbnsLZHM_yj^d1yBG!tI=yMq85;=>;K3`3@ z$R+)mJlh>s_F-nMU*I{i8nVd~-<`;tc?!F*t|dk&9nx9a!gJc+dT=vBW10oJpQc{S zOLBS&Ve5_PGB+yQd6kEP+^7OsSQ5<#mE1o?sGcZ(N24pY{ zolw1p&%RJH<08`$T%J{E(=D`kwBcRO0K%&&S~4PExQGjBXU#t{d)~`BUiyyDAHQv_ zVYnQ6VdwRus8g0uZBfGB?kxeD?D*R z#Qu~I&yLO5f{s;Dl)&xPn_5DtpkmY>ie^HaJ34|jgs5hmuSHy~Q=v8_y;03knX9yo zHUbRWL_}N;AfHbml4!%}dygG;pkD=RVv5-wxTE2*)V0;jq-k^@#tAu3O);sahmNV{ znFij^#rXP=2hS70B2Zk1W;YKBZwS{nBL+ zH8O3=!rr2!3)WW)`RRPm4y7Eenr%+xd0)C%uGy0QDMn|MxR5b?@|;()_PKm zyHdZC0%Ui%c(y^^dKtjz?!Cu7Dt5ks5a}&Nde!C*SpH!8fi%4V@od*Vq((eM*Nagu z+z{rI?TFccHdjz`+jVw>j9y1GHhHxz+Fx0r@P5G=vfrHlmDV*qG@OlU@uIy{hT~Ph{)F1gr*AutR^L!rB5S7 ztU;szj?ni=wzwHAiaRZqk?#a~`bUf=hav16?-g^X&R28M*0_l(v5Sok(Q*V{LL+S- z;4!i>aMF*()w%2?cQ$A4>&+sQ0L{CLnDa-lD{L6JNO5-hkE{Q+zW(*TR zq^A2+R>N0_=mZvEyft`HWx4r?4h>!tk_mIhGNC-+nPzsqb9uG6+OsH%+t6M>`4~=Q z0txFjj@L#wMcwzexxX4Wr#Am&$QhZ3VDUO1uG?LuL**g-xL1X%sL9FaHjIR_h z`VZ2nCzJ>SA;DVsSY=ZA*%64+N<1Yy2-DY53*sy-_a`;>tEEhju!)feVZ1)KGL#%w z@!jldJ{7Jz>1a~#Vxb7kr>vNC_F_shi|gbEVBnn zMFpBT+#SYOX8KN7vAU?O%G{&>ao;eWT!^hNTmsP0t_Z|Ry^&WWxwVdF>*$U8SDqIg zpma}}I*KZLH_ofMe>L@eKOjSagvz{VwJ{{`9dC94{ErczrZw4STyhrb$*iiT`dk!p zUE^HntfS!K3_>((d5NG=S|5WL`kol~F{x{wCmOF`2lWbppDtE5gOl~y!{W@UqYFVE zRbssR8HkWsi~#f|FBfgb9q_0h>s!}8@Hr=Ar-Xs@iow$!JkFSmqd>xZIZ_6pPaw$4 z`R7e7=%j7jhvd6w5Rrf_&jXz+Ba@iIW@7<5<^`uA!lTNS{5E=qTAk#3G@st+#KGp% zpjX_H%3EIz31p9_yfrGk_`S1YEvf-hhN&qE&R! zUhmBt+%1F=yyj!P6UR1^0PF_32Tp;V^X!Wd%u8xxFJli-VGt1m14g65Jr|AK+|`d) z@)1n!zRa0PDBq^eDsM2{^i}9bgF6%oX|sXffx77*T!V8;z^&6X@A+ac-0R1gLwRVZ zM?xS6k_X@xj2g~$$U~B=0F}N6v4Ppd5hExqmiG|$(@JKn?WHbr<22vNNxl0JNh;gos4=yKa`3OFbTy+ z6S6VO(?@UCVW8!dQJ(g%av{ATOj~^tMEv$c+5A*6^&*r9xRIP~-})%!z(SDJE52+y zN|RmBaxu?Dz538Ch=5uojT}5Gk=!CurAD9YK2%-{fu2WqY?s(~KnfYQRwg`5MzVj4 za5R-3Xtwo$_SfjdbicMosK71}*~2eC!Y0cREvKliAXnFu47hDt&s7}W=o_DgFu2{4 zFttA*tCOWc9qkZ1XoG`o=T+R-9Bd~snU~4XFmV^WPfbG*FI--n(G(#>Wf(p@ccbIW z=J_u;4?9=7@{?iPE)zmo#Dez}26o#2W-5A{=wqWieJ*ky6f}juH`C!j zso?$0_=q*kiIgVKyPCg!eWOSmU}t{@OsA0E$dd(fi&ue&KBRc-jVvd=J&hkO`dnvb9p9 z?&Q$+v^vX6(8+dM@4B@CQNh%Ax4I)+*tMzN^(+_QJ0zw=Y0*=~?5FyX@S@vS&R4Gk zMJpO#dZJHJe70W+u2H;K!gjSBs2Sw85GY#j6UG(vn)oe-(;J7+#hJQ6{g}F*H@DRL z;C0Onx7a}IF!9%kLM5nU7U+VEw&eO0+_nd5k(0U?D303ay7BJ;D+#gKC|RpxLQmnb z!T8;wKt~Hu7olYlbHQBSHq)Ovi%uU&2=!5$laHcO#gY!#>ezV&;KK6Pxbc)_2C(^* z>b?&sSHbQUpI|WAhaDGRRcZqU?l36mYOll<+Oz7XXw8A6b}GL+hfv*VWxRhgzH1{Y zN7+tr$|f&pqjZf)64+%SpQL!}= z0TE`@EshZIR7U*uGIY}K%~kGtaMq?^r#s)%U0(4JN$uq26K#?;gc^MnXz{%2$yA*% zH#Qi3s*j$W={U1OU+jxNO0s4?Z@8!m72K|7e+HT^NAA1IMqRJS5DED#c^{?xaSLL{ z%(L6-L>>9Uv$vbm4sXk{=cp>qqXQJ?G}XiB!e^S~TL=7cv@x$|N9=jv>HPRgPKc*< ze`P~Ry?5}t2#6J*b1G1cnk=mCIOT-O`&mTG#s29b%r#UNqIGgJn`P5Co<*biZKj-% zswTFYH!rj5zTo3t+XJ!0W*>@P^+~4){tqhy7mv(ZdH{xnqZ9%$?#7ttDglH{A#vj@ zuTXF;Gc1NfI{_Mc%zR&leapTi!$|%NAS=v?Zm85IrQ9)nO>bzL*1``&tJ|)2CQ~(+ zQyK_BRbkX^J7h8(_maP19iIgt?x~7h?6yBwAV}$xI9(FXE*3N8!jd|P(w-&XmU*B{ zu}S8?VuO+>kCT*8UGi9aH9!|i7-=~&OQ6;T`__7L;R|56AjbW|H8|yI*m77D+%gxm zM;7NY2F`|U$r48A^+_Yahf1SA|8)y^UD{9(Ma&>7fEL1;)wBu;wT}+a7ke{6eiZ83 zvL$Ef*{9QYVCr|m#nRz~r7a*EZXUas{>?9KQI812el0~Ku7CvO+D~OKw|jFdIG(`T zrxEK>^fy8|1Fd)nRmH+6xaqNJCFbn_P6KzfR=!;$rYiRSd zAvLDp%4)GZrtN{1W(-*|>lQ>YD1Q@SwFMqTYt;7wQH(^}*x{;b2;_uy@VR9jL1G1Z z#Zn?VGB5XrFo8L=N$7JYAj4iP88__5mU}9{eKN55d0C1-42MZ_j!op(K_GMuW}L894i~h^dh#!a5l~ z7&;|ldIbJ*f+GW-Jg*n*&S)y~1Ef8;L|CW>!3;aL$Kr*|#g*u4mH_?}sE20`79By! zESVPCoblerkhzl94aIr;0++Z{J5C*`s5gupt!sSKZBVU6<<((NF1qvM$(XMim$tD@ z{!cyH>So~Fz_?L^a3FJNCai9YBFT5Lbft13f8uDFyWhnq+iai7>si^@oX}D{ywHSo z%pm|Ne`HpI_ysv_ygg6wu;|fdZZ$<4>poKD-8tnqRmM(VO3oItp(YmG(TPK#zIUK^ zEj(b4RSI`rdl5Zs@>-UVe;pHc!J*KxBNXb6upZNmg(u_oia1z_Hp5ncS}Tn@r!$8O zv%S!Xv_Ufcl4r?Ad2^`9Nszw)limbv_J!4US5>1+6ZtiIP!w^MVatp&ax5@TP5105 zSgi-@Nafx~Z&~V*eBzUet+>@oyO~l7zZ5J1a!{7^s?3CY)d^(RAH4NFQmHNf-TqSz-?53L2RvW=fj1_<@P*h;mZxeVUt#hz<@9PzAe?pgv{gA|s$)0s7 zJ;jc=|1?4gpP{EjLj)vog+d<0t)*W}W-?L;78J0(aqJx$)ni1@B^hXj7jv9cBh&96U_p#t8bzJ3XW-F(O}d zc+B;O8kCV~x06Tw={>W3h!ce%n@NhQx`|_xl28AnC{tZ?rrIzfuH*CKFl6lYYVvXl zvO($|C*qEw(u-2nlSAuw?)#Nm{o(7A#0R(n;DaXCpRs1pZ;}DB=0F%bdzTk5U4dp~ z4A;x($fbT%iqEs~IEQNpl;TEM>00w$wwr9Dh*B&{y(tK6@{r+0XJPf4Xkv~q!q`Ta z)9zUVD?wXIq|xU^b%eSALqNR0LT;FI!!etb;K{MkG_~?4wlU z;`l`*y51yB-ppE}6?i(ue?48g4rik^$gaiFikEJ)XP=8TKNxDLHJovO zH;R2sSh7@W$HU!>zY+Jo8s(vaIdOmL)q0mFNbx=QTyAL?ceN9~SFv^A#7b(iSGP8Q z(1JXz3NW-K|Hh0j(+C63oRa^QZ#rvN?UxY7{vwH!ecMacjI7v6Yy}`q-Gy|_Z;^IB_1oOS-pCE8!@XBu^~a7hAmcFD8c*S0P*Q6@DVDA zU@EnZ57P(>N5i5_{hO>HNNv2!#L5@V?RAxsHH-8Zgl;u=+K7%@L5a-Lu8dE4y8j0A z6|rl_1xgqvbJol%7g3){$AnvzgdXgmWR`8`LDe!dfZYPi*8#lydq1e&{AJD4R!eX) z5Wo!NFZ9`263pM@B*u4BpCq&V0mS-ioAj!f^S+EQv z0Q|);3$2d&m|NyheC0%PN(L#%+8CKrY%ybna&i@aWWA`d%tg`ucG3(NSJ_e5ig1=k ze&u(S3$7HM$s9cz6|5HIRH7m@Wg1W;o7nkqF+mUU2W`8FF6MLS(LA;a+SgVOCOO8f zj8$XvZS}8wU}2x8&Uwn&s_#=V#UN*!u5~YPXxdN`S{elNC z45h}7vTXCMVND2&p|nGrw;8X_5FwndJtVB4eNw#)FJ`te1df(VNx=S0&UE%GlPIwY54ZIxhO5Tv0lai!@F{hm)#+N#?z|^46 z2ROY{#k;5Srj71mwH*}W*EZ0Oe(lU5qxVEGl-AO);Ij!F(qOuQpWWkwJtN*1%=~1` zIIXtU8aXO*)D9QmkgHwDBo@v&?V;G9__I}ya}7nGOXBU|)?5G$#|@p^^{s)#^f%p$ zit%k1gz_KGQ5~Iu&f%_fz%azvlSr`^w6s4SmM|o)M>cbzEnVKP?bGRHQo3<-f^T6& z#||#?0c0YZ{`8`8L~ub|o$Q0o;16?*!z?4-%KN!qif4aIy9kSJAhJFNugh|H!s~Qr zH=ekPk8-PjrtOK@WW4E-EqS!JXfYouUS5qg)<9Ilz6RtbBP@5X9meLVK!*x=w22#; zcpYQV=cRC#_ZQ-fz9p|{q&T@iUFs$?)J456G0;tLL_-y_@Yg`&3zu2BmUuYn5IR`^QR}}!Fr^eLPPfh=PH0IMo_VAV z^@&+q;zp#R&HqoGJ zO$MqA{wKn1OJ6G5q1GE0i6rgm^VTz*8Lx`Q!=#yW5|LXJgi7?@G6^6sHL5!)#?psG z`Q_-hR+T=^DHKnVgvYSEO6YF+uJE399p+1*A~k7`jVxNPT_L)C%D)5#eC@3p4kET_ z9oQ5gKcGbk4R<=y*( zjxU{WutEh#-EAcV5&{7aVgVLc`k>Ih)+eQhwo}zDb2S|Zmfezm`|Bu;Y9j^*V+`;> z;|?SPBS)%dB<#O;S#1h(zc#f7i3ISBrOGCKSiQHGg)`#LhRPSg4XR(AK6}-*rB)6A zilIh03_e=!lyNk@h^z?8+zFOQF? zz;LqBL?`h(H#ga{9Fy!$N~3mzz;u!UeRKE1RgbPAuecO#tWjM z#&3MnR(w0LTKMS&$hpCK)=9(UCdGR;{HnN#le6G+exZp(_AQlh<&k-%H(6EUdCT!2QZvc+tIK+AsD$kxhi>Qa zoF2phQwNa<-;6YL_9vyyhETW=t};rynE|~$W@x=}6-M?Y+AT%I5s5A`RI8#z2p^sv zU3JWcgW)%Ppg?xfQ-*zhc**aPuRzZ_&Xd23v;iX)6V=wmbZ2D+@rZw+&xwUY!2M5R zAVyIFtmG&gjtrj!UWh}faUx^tHxi5eUw~SmCyCGSG~g8?foc%d7faCZ|1*lgIO3O< zEy~8buoe}>IF9Bc0U*F*4g=}Nwb1&0o z^2*X-U1U+pz`uQX0%z7G*@Wm!wIiRxS86es-rF@A)?=jXnP$6WI@BE^R-i;`EqSr1 zZ`Fx$cr668{)0N*JRs1882%^5TMt!xWpt9T~VWpKfwRv4@WI2a2WkVJCsU z2UV%`>`Ob|ycv`D{7zcuzx!o35g!H}X@rsjiYw}Nn8{SVGe&zJDT9lcgr);)LXh?a zg?4a=tt&qU0~w;De=H|nsQ$bxe5n!TG@^1&hlxPqPmfM@XAo8Coexbw(&0vQsl(28 zfJ;$uwEX+@%~v|w4LXH?p9#lCVJNrCJ)9_wH5Gac-=3fl8@F{OFKqs@tFjbrbX|LG zE=lM<0GNh<9IHNwE2$*u07O>#`W+pC4Us+5$jBZ0Ge0?vBPnc$plzSqBS3CEqE@k} z^l)vZi)-sy;cQ2qTk`6Dj0E3X;D$#P!>BByL3vRorRm6$2A;R@)*nscZ@PJ;#7sST4ks z1$wt$%~QrLIt5>~#sd*kxk7+}w=|cT&I*2KhqZm;oSb&vz)P}gb;%cP4bWl2oZvy6 zmyR);R}nV3xu_Cku8=_nV77U_a5k-7>O^}w8MQwHg>lQ4o@2-lcztdmJ$ryDjsV!A zm~tMC8%E3O@4b+%uD?w+_kUE+v*MLF(+sgKe3e=*-f%vw3SDC&w=ZPkq~amHm|k3u zJp3FrmneOUbyQs z^sv6{wd)^)=P+fAJAIFjwT0%SY=#2M7!k~Jj?!9<#Pvb;AfR0`@42g*$fl@*O1WMo zu&z_|rBC53NpujnMb;Rz1iE&!JcrcbPJ<8JkuG46%FX-H(qgLur0y2ePl7_6)&*^U zZ3T+2V8d2$qST*KHeUSD22;|^OLWu%OqBGBraheNVoh(oVhvi3h-hIUYFD2#?KbMadhZ1C%maLN&q->K{ zz%_-^@ZQMB8D^zf&Yrx?YTrDv_IV<2b@dHL$H1GJa*Sf+@w${XZ#CP#@IkdVY%l61 z;@1C5k=MjYeTWS=rCW%7emgqkDhO7TY0fO=YG7vL>H&4AF;d7ufPs5cNRY-iQ)HT{ zy5w(Bv$^7i?^s(>jyW$f|1-+a0H~OAIqbYIqM^!8g`z$z8vEooeLEjEIJ1sa>FznF z+ba^gKaeW#C3c+U)=O@hk=0?lb3xJ?dvCRK<_cOaNt$Ox9ywfyG3@5tIIt)`Q@%If zst7Oe`0di+dhZf+*i}#IGTaya-)w>|DPB z$8rkqB3&|G_5;6Nb4d$vDTu1hyB&XT1>bYdZm%lyiQh< zO6X(PAGzQ#JE{?X5DD5GO_{XXY;?0oac=^Z>!>FD+({H=L2Sy1%xp4^96B#1yCYt} zt3e1v{y8Djd9Yfgwzv~Xpw@?ubKH84x483F<)($V*FV@c>6{KkmM^22Yzwcavg4K} zBr$!Pf)V_w@-uVFK_3rN?-XtsviKZ@T<}ke#?9QX_wQ#Gqp(NI9;>|&NB8V0?Rmr}+O`dVX(*qg znPY2D*F(K9Anq1bDv(3HJhd7r`}s`;Y9Zwr=SKveBzEEj@H6W#@F1vW(DC3Kj&x6W z%@~>I=B|M0+PLj&CDz}G(wdXkAq~!&pg78ys8G6_uLur!0uf^T7%QZ|uT;vR2NV&P z8xuo!&&bTMQ;UK<5pX(tqsQNQcaDYw&MDImn49ipWCC4MDnO*zggpL=&KE00lDNk| zHS2D(*_=q+G0R^*E>-U3QLui4aaE5`wP$7l*%htB$^*X8R@0RZ7;(a5QFV~2TNw9J znVspJ#oJ0$T~xni6GMH!n^xP|;~3o@r9WkOZ6(d?Nngt#Ed}X z$nL)U@-T#+(k&bh^0w&K_e=1M(KsSFyFHZVirtxPA$__^F)#$u-fBqE=hd#t+vhcg zG3;s%PGgTO-w7JqcJOI7?SCwR{&Ca;G?>dUH~L7Ry+D)JBg$>$=ZmYBdl_AAW8J1w z5#YBFby{Jt^Z(_0`!qQ9gMgdrJKopYhB?17v-pb|Z?F5Lo@Jodb1M}vL>V-9t-!s_k@P4*~f$sdCwqeJ+S_zI*Au!?1N`YZ!^#Hi7lWe%fh zOh}F3DhgC^WvhccQ*8Q;EeRFLdVwK;Q+wsMijSqTTe8cn5F;hH_r%$vwGe>#3JEIx zu$y;0&M}G)xk!iKst8e=GQEYYjB{Ia{=6lHu#_5!2Oy69Ik*K9bD z+O5!uhW4IjzX&k3SDmLlS8kLg;V2Vgq_#b3|JwbvEii*_eM8Egejll*_JdCm zjvWU!H-B{9LtB4h=!~PGcI?{k=-p~E_dJ|AafDjy*@-ZlfU(qsxI$N2bZ#A97 z)on>NQ5FRL*^e0eH!PC9dN==hgxD|~Fb|7QvHC|16ZGg_N1d)`6)K%@wl}65F&28(nYeihCQoU*MEJ*fNxJotAN8p(yv#L z)nq$oeqlEU9#YHspwzLYy?lGz{y#G*)irMz&o&obB^VP#;hW{{^sA$fn`*ERp)Ls_ z-@7ARcG<{cN{L&CEX(U&4P8kV!Px}ua7WGaZql(^(t#*!6NO|fEaAl?UPyDHm-1T< z$r}eRV|gTXD-vxy4&D!VH1-%{;zPgoaOdpAkaGo|u)&L#i!?%YA71z$;V=sPfI>&b zrCB|YY)k$p(}|-HNLV(v2QSA5T-$YLr{d{7jsk#zY2Ix|8?rzIWJ%HIn8R$>zJYe# zXs5Sl;M_B&=HhTU^fOc(XDUFJ#`(n^ZL!FpcoUPTAd|`8-tB0b0Z~2c0}@bfq?ucl zlqiNiuh9aVReUhw{fVUW!o#s|Y&hiMmSkCQ`1<+cy&I*U4kL(;@B$j)x9H~?gPp6j z+X)7E>;%Sp029A4*@3tXzslK|2~cx@jqKc{2rYzf=;nM4K0=r%32u*hXT}JlP^!NJ zn!D!f`x3kii|T9jKldO`TX7>2OpXQB)=dcjt~Y8%v5>F0g~%}~M~VC^x?oc9Uqyp! zux(^?3nu!021-fj@iF!#nHF&7lKa^hDr7E_+NdVew^@4s_1hHf8Q9r*upxAiFz^Z- z@6{86t-2`e6p>=LpWK!B{otZIQ7`tZmKQsMSGm!71%ap?c}MS3JdC@4} zKQ)nKC+aCFa|;l^E8)0DdnTkg1zvNdu`)H{;7&TiZ?>t=OIx zNa9GjZ~xwulaQH09!M=sEwqMIagI!f;e+zvIK%7+{=^Oqod z9hg|m;t`>doMrAUniWO*u;PGQ<5weOR2p*1ORb{B6E_}mUH!6an*cju zicQ+|gQ!t)Pwqpo+Xfu)tDX_z!SnnqZs`$a$ZENl-SLJ;aan<(bAmF5GVn5X{v$fv zhE4~V_#YWk2&+@tz)X>wnA(vkU-k2TH=T(7tsW&cGi*=iRGGGmI9xi``P8_%)<|6P z%w&ZRx1PQs{H^LG;~m6$@mPN`Z3yQtm3Fh>`kb-DbT=^(Ds{DW@ALkFafo1TVy=c5E(5tm6mPIp!#;v+rbnTD+uVCgecYmc9M?y@YP;4JEWD z6$)Q3cM#F^-L8afV&BQcit+P6 zi;`CldL}6xaIt$SE*;Z=iCw!ZDy?~Ib`RA~(!1+-M83afhf0T9(yQvCu@jKAFC(!8 zZoN77)pN#UUsoZT8?^B^a&}YLmF%C7!i(H zy<3kIlRW`ZZP|EZa4D!8TT@E@i8r{cz_qCx!WeP;W?H%8%Fw%%rCTQzQ_1zV%3f=@ z?Y&>>;z*9jLK(oJ_P-d9#1+{a7K5jE#6K=~c$TR8kRhQ!ktZ6jdDN0togDnZ!g$Zn^2)yGq83 zl&+%9Tt|rk;kuE@Y0yA8F%cI$`B2ATaCS`R9nIm9z~iI;ymTE5CIwv|n0x5% zyp6CU>?)4~Nv%Q5NKTpS@~h~xQbYimfCV9(&sl00j5kVL?zT7!86xr^9C{+T)^Yj) z?!?=tx}DMRsCWKY#+0%Z%dm;154C!qfqnm9_2%}$7ikM47_9=ZKjSdQ8tY=Og1ojd zXj_)&F8oO9;pPu+9a|=|4E7kerI#a|? z75iV?jD=Mq-(?QbMZ#Hqjs5ojUWKR@2|N7d!lHRW%TkwAke#vNE4{rvG8eq)00PT? zA@|%vzm5jK1yQIu_mw=ec7_2jyTo6&u#2v1K6M2EBHC(MOYn5-#*P9IFUNhTsqQT; zKZd{WQ6JPXeHc3`%r$qmzu={!GSEk1YbF&ikV4a21Y4)v%2er`aO6YQ>q{@>TSQTw z#*}FSQ228&QdjKuNEWS!qKh&pm5!c8DJGw@&-VJ0IVJ0i|GgQ(SN@qbov2gAFttSp z&JQKOr|>)4yb4hB;5ti&0&@fuGZuj;W`Ubow!swZSY`D1!-&gjg;HHtgxiS%fN~D1 zk%uiqHJ5(Tl!{mJt~T#YuD{F|i|>%fO~&!V`Bh_c#FMncwDsI{Et&n7oRe*ry}Rsf)s%SxnT znSW1-Z21|d6|um zFuhePHdPeG#=*dv$3cjiE~d*2>~70aFDotVCjU1;m|YNWXtFloW+e{6- zRgqE&{#tA{dMko>7-Nsmy~p*>yl9id#h<&T6(&h5%O(LSWfZY^Ct&YEySHGBLOPn_JZspq_)H=hb75Zf@@S%OqW#T9zN9E|{ zg5|Qz@ca}y_=z9D^L(hjAF-BpUJ1J$t$V$ph)-N+wvWJVuo7sOXb&|5&ct{r=BbuK zDd<09r}4&_1!N2mmC4^Rn-%xB5B-6UT0rt>B+U`fmgcy&REI0$T8=oGh3nz$DZ?V~ z6|)>jP$@|n;JwM(K;5273fa*{<%omD{4q;wZ-b^I<75U5nQ)QT#|#3rNmf>*OexEl z$3?F*VoJCdp2`(K}T<0m5ver{k>EnrcbRhTOqR#He6(^!gEk6N(^E)qOT7VvWS` zPADG>IENTcQf@nvslRBAup2Wk@jNuF73HAmod@CHueF?4oP9axp~N=+)xkn@>5|Sf ziZg0Y!Z4<$e21lg20`5e6i^Y;+a1HJkTadlq5&EUyTmw?L2oMw7{*n!emL-L1~(~; zp#5c0Q`SBi=w`4yh%-BNbaDd2ZN<~ZK`-xqY7r>1ir)n z>X&elw>(iW;T2{_J)32sn}*Ep{qvR=syjb=!)D8xEDJ%@g6b~XuMm2QLa&%vDY4|2 zRKHc2a8KnYCt<@^);LEU7U8{7Dh(68rsDk=H_X4?d&#+!!N3D6I4Uu$*-QS!WTXZK z(|XNsl)b}}thI?Ct~%!fY0CTEyKb?T*$8X;2@7Lyz@o+blPDxrHg9-4*J>LnB>qRI z)oT18`S|vLFf6Jk8${A%ralquPl<62PrW31Mi>j?a`41uE6@tX5)&P%&gRzEiZUledflYuT6t{=rw)t)JzJ zmwApZMEl5i_ay8W-<+Fo>P5z6w!0gAZzXuninCXe*WHJ8#wi@=*E9RA*8E*;1XA}% z{CvbQ+LR9pwC{xRnf=SBiHP2@<@L_ug{C2%O^;q&e+Meww;-TKb?HpDTV}4Chv6Vkio3Fd_t$rXl^v;lzzl2TJR#U5kH0Ts;pQ?F$ z-jD_o-NdzgXH?c|R~I%sw6D6NiHal^CD5)@=Z+l^4wCqVM@#}p_v0&C}2vG#u*Zxa>X2n3EFQ2pL&zHw1i1t4oIn7^FYMd-h; zTUq>a*%iEw8d6N&7MFah-jfm~oa|xbLCEVXO~f_pA#SoEW+W#BWiXuCS6ImpnkV{x z4TEaN%LT~~mEI~xiwo^x?nZlVTtK|tK10>q#Zeh0x-pSpkn1m=;M`th>GmJ&_uD)= z1OIwnFEctJf{mN<*>2k>&ImSrnXYs3HdSq#>CP!qOeZjsL0;yrl*$_8jFKcGm zWe1(e9l~hoBWrf}kVOM*f#ZlVPXzSCg2{u0+s~Tsx5~Wj-VqzH($Azqm!gi3`NG`I zHpT2w@iH>U@F>vEXL{CuDNcYAZ8mIMYccs)(pZnPXT{eEgR9VJxVDs-K>r&`%MWx7 zrnz^2Xn#B_0MP|0SAQIr`KxN>((xzxX}}dw|E4P*XF?diW3>gRR@FP!k?4~OG+&AD z11)|s>RKyC{6vlT2&=>66}GFE)yXGv;$p-I^a-YGC2~oRVoVf`6`PT*Fi^CM%tFf*jRBd=#riYH&*q(!YAGdj4=BRxzxs&r&w$yXE zmRF0cyF3J?3~@p;Z&Y`J$_q)XzU*1nOFlL=I&UfkMjV27n5lU6hXk}cvGw)0*tO(9 z##+;6c7VnVz)Rxerg{|U8w)rr4DybpGcnyk)HNyQnAUIfka2Fy^fxgSN zFdxfBc(`bPuO-|u^HZ!MQg&D2^O!d z&78D?tgwjqnD&%1)N$)mE^YsKRp2TS^kMh5he3>JRjZ!E#x&ZdCvyMnpuY9xU9WY` z&)w{ewUnh~*dga|Depo+C5Iy^_(y^d1a?|BaS!C5M8cyFK(K^b7M^_xO5XH-gn+sn zN$2{#a&+&LB-&53vA_uYy@5p$?yPCV;Q`cH?nX!Mw#4ImPQym=h@3W>n5KdiSX@>0 z4k22BUWa<}g2UaID#U?EHdhB@fi42oMmK=J5iMyk;5FE(47pJJFKU8!fQh{77J4}| z)x-u{gH#65SR<3ELtP(@(j@GJDl15#@U(YUPtHb7&?JUQG1qkWFG`8}K*Z^$gSR%M zM%FiznBI;@j{SPNO}A0hYs&@XbW~Pv#SOW36}Z^~0OpM;5hj@GM~O+ds7Iaw;I zPoL8e-R731ae%SZ>uoDF-vXa2XaCpWgd%X1y^R!1+kpkt$P1wl+3Z)N@gDJGQ$H=J zA)GNUwg=3Uhg;=6GSzs^*qv3-0nfOtg$2|!Ncf)MOjE!F1OhS}=PN9e7Es)mC^i7O zq4*VGccy6#i3g%hN5{a2AWt~e(@8}T!rRbhVysfvCIA^-L|-Q0bte?5Z8+is&DhQ$ z*6ef%+9kLhIw#aSJM7XlTZ#(**fa?+B}_fGmjWW4G#VQbs>k_;GtHhU0ysi8rkh8J zgL`n&FMnSmLV59RmdWZyf9tZ0sD?BP7he&!+RPekEYA=9boJ-u7E^wKh0HiBIZ=)&cDJ*?`$cz46FI| zb7$6*9Y?VliA{lRXdc}6+4C^j#zh%_GPi7kQvK?PS?YAyULKG`^WOdL(o}c+Gc(8R zV*}Bp<-|!LrXdj`I`^uu_&>C9qG4%LED0bs&20*zyH_U7jz2FSrD*(5%@wo8L8aC~ zb|=p&%3fLh@_!Jj=TsS4YZdzrq3Jvwpv{fRNF}OdR-XXxYIv%YnCD&FBgR35c)dnF zsdtPHA}&C_k|kFOS`Ubnejvf@wa#+sHULK@_$StFxFBs``X>-i>uM|Ibf>IqxyYl>&y_(=8T!#}V?xH*ISKQ2j7SA9w1* zH~t3v2IcU8;!|`5N1F`xyBjlEE0uYw%D`7So)ZuUJ0>IPXxm?0M^}yVd0Cml1ueAc z+*#_ve1#IQU>bgAO1(h=QVkTs^gj4y+&$yYLWQL*J74f>XQDOV%;=w9vu%6VgwccF z!vp?s8pdxB0>n7#)QASQDhh|y=j6Bl{#Ho?P?&wDdAFS`C?=L9-7T6RBE`;lyWEMD6sKe#V z#^jPFXsD9sGw>~A*jDw3ry~$#@~#}TU^T9DVjsR0YOn}aT4Rdz^g#mJFDVTVf|X+< zLoHvuUrsU0dI&E&z}=jW5?EOpKUMp5M`5YJq6kGbPi+1Da!Ix-Pkq* z+SsP~z(dzR^(Uxn1pjmktX#0=x|6Zj1`#j!{}w?Qo)mh&P9%d2xy=780$4AES>K?Y zZQ;r6hB5!hQL2fd+@Q>P!*&Nt^s^>sK=j9aqA{OFl%9#|RA^R+9+DX~9 zD7h&f0YyNbeZ<<(u`_#hVC^}kOui6N|_iD+09ple~tv7 ztjf7g<2wm-O)CL%a@zB{LiS5d|wAlFkf02U=r=HjzEj zoF374e$eI%x_$}X({-jPr+9w)KtP`nyr|_%`+U>)knXKlliaM!`%ifs69CT{FSh)U z-K+_rrc3dd`hxyQmqKh91M{$e)<{jHmWlvcnf?xuO@39pZ1xXlX2av+66u2{DKsN( z3w1$=c3UWAIDYTwrQ*nXq_hk;o7CswX>It{(tZ6NzS+~JTW-ME+W)>N7YQ);5*Z%QC)`{w+gDOaDPZ-eSwnMNn8 z=1KIXfBIKLKDHuZWyqTdASdk-;>3)&RFkJ}%rmp~uH+;h?nI9$HcA&t<`aD;f6P_$)^`>k+TQA~NH z#Dihj?oOE{7p>J>^2NR;@7*#dn_U4&|^>_nxk8QMX9K>H(KNmr`v%+B!Tj?3oJ zxI(N`b^PnYfYMk+C8tpe@pf;_mjvA&br==PlSR~vd&5~9Mh-o^rx1+l(2GUn%F%Tr zbOML?xrV4>PG?=W84$fpl8f3Jms0zK;&*I6feRrn`R&SF(=1;RbrBU&bT)E3u^8!bAf$x_8i&*+#S-uq>Dw$(PHdu$8A5lispk?-_5T ztjuJ2TzS!pgW(VfhYEtH{E-fG-1iNWfJ4=}=ug|P@C|DAAyDg=Vot8^5C@H%&vgP_ zMmmBzdkFgtBmMv6)&~dc`GeGXEFRe_Z2&rTEIBm!zs`%Q#E;N2X!MowPuDHMa!C9P zm1XT%sHJgkyO#6TpRa`Omn#kJ1&wz1Sv9QL{QqRv_4cP2vgtV#j)S-p0cVsBuyhou ztXAQexUS9YgK@7S?Nt!)q5?%rE`L0gN2?OLrrwmXNw7bG`*F3t(x_QiG)IEhBvJa+ zRdR#Vnt?X~?j!-7%yNnBYI-u$JdiWjO=q3Vi*;I>=>XriK$zr^gjMuy0jqz_^y<*N zvSfxZk*X;(W>rRY0?>U>y8T=tYol+jk{5hk)vDCMbb%0 zdSYc1r9pk>hKC|V^T`&C#SYPV#8lG*z%)vh0CS}e7``su-xBf3+NuEvi=*VCG;E`u z&Ww{Hu)H|UQ2bbkc?~N9$of;~j&c%|S&Cwuc^$9(aw^DRrD`^Ks1i^Su{E9l|Nkp$ zyh5(zV~M>f6Mgu4jFh$++=(Ak@n1j>#BX4}beGNvwO;#E%0c8&1HXx~Zj*-r9N_Nz zdOg~Y8S~JSD@_txhH2lI3At{R!r$Q%n@yHv%J_j~_AA{m)>oykl%sA?tdAF2<@5Em zdzJIK;j*k`$^?rsbHq)(JEnsI7^f;i{jc4Ew9ZzXtS=Vpr{kn8jXrkHMD6X*{dM|b z4*_t_v6VGu#YnWv^ACA6Y)vLWk~y^l@Yow-j+o4b`!DngbhvOANP9>Kth3_jQAAtb7rGO?$AHMpMPE=UG z)1}7YsOPq8_$=wCD{RL5yfU*!&}7swAQbGNm=~k}cl_vy7|dhNuXFHD+C}yFDV-H% zBg<>E`C!+7Sh-!*&vSS6;04HI!V_4|nntc8g5lo)!XW1K?EPUO1saasyo2k+${z6{auX?v5z>+Q0-#u zUCR<`n9(95g94E?aI_xc^r?W{XDq$IwjeaA0#TgL^8Z?&ljsGA#dw2eaAg4==j2I#lny(Ct*Co@!N=`!0s8^N-cAyZVM3ybtx@#b#?8&VHEz0l+f zY?hQ)L}2Vor(SGTfd(4t<$euBYBFymK^Zq`U>Le_JcCzYa;zDQ|2dc7FG1w86j}Ak z*So&vn4C*HX2i0pQF;d{%h=$Zfw~6vrTaB%A2}-t3JJG}gQT6iP_6*k-(A=HmNiLS z4Qq|(xa2f7RV~E=)n8w2p9wv>K<1=B^MO9!Np}xa_9x{zT1YRt#q_Kj{9x(zU zTQIYro%>QUGvqtgtB{G=Oz6)MM4-5*`=Jf4;~90N`7DjKe<~b+YxHeiBq|Z<6j?(E z0hGDda!+aK(25qcYcV6RXa{i1O-5sd0a zNl|pcfZ_S}wLJ;ozdU!2BoU0;PI999WLFl$K1JVUFLhitYEWO@FxNOUrL{lZQLs}RjjaKMy z8N}^`EFeZf-D?(z)@>@p*jZ8cq-&#j3Vt79P*%crI46QrCn#{}3$ToBv#NR0EY#aD z)fo~X+ugQnbB~Vmu0sIoHby1sm)4P3x%omyqm$vX+YQu?`B^s=W>DAJSDi6xJsjU> zILHrC$qd4?pd7zc*QeNSa?{sL`hhA39Tr4687gk3E1XUP^IKQxfZA#tO)E$LB`w5T zfCwea=cvFWtlGKq<%jF|2cWf@Vo!4d`?31qKS4_XX+!&@DShf4nR0;A5O|m5m2QqS z@PSYuEV3|45s8Y&RA{mU#Qn_`oUl4hmalh_`JesGd?HyDx!-le<$^fun`Y3-b{*eK zl)kPq&+t&ABtA&0?oL3jMN0RrwF&Awi+s&$Hv=35*IYx}{nl3)GHNa*tn}-$!M60XM-K$qMYwI-d9~4yZCn5GqVWKei8%6)z%oxa!g* z{f5_n{GF72iv1Uu;q$K^!s|^mVRz6(^csjZZs3*% zYX;D7OjnlPrwFQmVtf^`^~SakmvcMRC#8H<#NYqKV1fQ``W1ual7E@OR${kS!=f?f z`hNuj|NP~3Xch0g$IYZ1pJczu{L`po0luMwz($a0#Dg8qltRVjDaO&ESv(Dx?+jXK zw>FUUe{rI>(Ls`jWp3t_Dd(1y3~`$J8=a4cEX<6ukITAo1FoXK8lJYR;|OS0FXBIz ziegWX5S?N*|Kec@3PMH^kRe}_?D>m+n>ASX*vpE@IY46P|ZVJ}_^FaRI%z@i5n}RFk|rFn~Lof9Znf;{hDLL;BN} z1&>FIW!bYV>v@?MWodL4BKwEv5`nwuo(auF?shc-9XyzQS1l``#_xVYrv>qDoAEbI zq8X6-lqMbP;%{%>qY(<{={BkERkgR#g(TlC)eP{CQLBSj0J#Lt&?=0Skqu!bAbXV( z(}hGQ?_NKh7gti780v_!IfQx$_?Tv>{W<`LBWM7{3AZPm4|yUwTyAYHgaK3Wu}NBg zpnJThxG`SxxQ8!b9gBi}bZU@fdU^~vQ}v2C@xVfrkMKEg>ND%QDD%K$ zSl!oyiIw<3BsYdLw__Z@l2lDFVzxT+@~sJzQY$u>;Ku+#8awAwOe1Dvi_qW8l7O89 zJvlvX`+hdc-I@phn7@|#%!T9^X_B6cg9UrXoZ_!u*uWKe%j7uT1Ks6Ts`5X_<{1*# zpV`?Hh@oA-=kozbf(N|M$^mTW*WQ>~2A?tFF^L}@@dAR3iS)YZtk&E@j#Xl8OekXQ z)vHQ9o`0e2J@K$4U`en_V~%iOg4r}DiFyWBlr1D+<1qyTfk)70M2=(y9zFh6P-BqD zwK8@&j?EusP;40}fsopL-MbIoxN#{(gWl=In==}fdh z&%(6;5n(iTeR$|~rXl`Zaiyj8y?kov_}Tw4ZVT!J;>-%b3MD262`c}oUE?VYc6#5r*jnBH zi{kw_3iX!VL6obnO{utG(gagN$eQ%`X_QnLDhRRp&us%~fb}SH738)i#{h75Ahrc= zTOv*j66|1&PN={CQCde)ma(9jYjY{NsxZ=O|Ne^DNstnHf)OJc>Fx0p;(td0jBe`f z?IZe;;Nb9?L;?Kizz@cm|BJ`m<%H;c2{ZG9zC87EgVCYnao0pS-7*KW9zLJKLxsH3{lYppFgy;p4iIC&HCD z595amZIMOKZwx%9nn%%OAps!oN^PgDA5~BB;EH3M#xDop1usg;w zHB9WT;3yxXQ0F&YengA6$<+RcSK%4y9B>`GMf2hq6lHt-fjL_P%1aX^H~94*eV*)> zLQ8UBu*cCe@^+|he&h5%$WZ^chA9h^olu0%gJDaLZA}gHzP$hE2l~&fxoNzZ!`%O$ zZax1vjqI{GN{B~QXfOZg{|si`5pN(wFhu6XNHm~(5jk9y)jW{PXZ4K}Da$OzeJDh3 zB(#$Y$Wn1v+)M<_kB?Yp22y)=Cj89)1vIg`)tiLWY15A0jt0kMm%5uK|sF09H)a@J7lbb7-l2Yq1))UQ zl|ycL#wYeU7Me*5(nd{7iVT7Om;mm9ra2~bK&noo)#9n|39RhLyBn1N$XBs`IlmNN zx-febW`)gG@4$E&C#wr&^#_J_tIBJ%Gg=c zLL*B?tbl0dKoZ1zIWkp4LGvDS_DCmjhBe8G%4L`U+*tFgMXh`)H0rj)8`gT?Hd&L) zU9GV@n_$sRN`s3q&YivrT3UAj&Wie8d255G;wKb(@Y(E9>5>M2X(Y<;4rEGX5@8j; z$2QFFIbE_;2~(UEB%p$S!!0Fv0nTp2o3}?RgO4oRKph;1@V?WwK}2y#>Uhk6d$cq1 zd2kYFb)HkgG^4MqZ0_tI(d@A9ocz5mh)sc_7*HbB`_{d@DNMN6`nCJV6a5S+}i)%+R~GTU*K!wPRN&Kar-kjD*gM=+|?Ue&d;Bb za@#rzc}B-%P{if3z%1iVdOA-GM;krMA2$u%7geRIXq6Zhy!aGzk-QvPedvJ^8gXSI z3~}J<>$&1Qgor<=@*R9o=Qsl}m4y+00WPqZc2AMtUtXGC*=u}XsHy@G?Se(3 z;W3km8|VeDs1?oqLYXeG}6R{C&GX1>V^Ep{T9; zVA1&litqXGkZZv|DUn2v5<%w@eLPZ#{gl4fz3l_GSMZ$L- zIz%lU+Lz8f-uJU54su}WOkrh*vYRnA1A~ODq6;V58FD3KNlj?q>_dWeH;2`~G6>Y?Q~(QB)cii&|2G}wYjkG)`LNUM2_^fB%lt5;%pTOtL_UqESo2h7Vtrvu)b zfZKjH@~*@jnEA@zZ?PW{5l*NOz}_m;k}|Z25*o`f0mZxCj0 zoAA%Cz%2`^?Z_EAh(p20(ivm?d{$g`9lTCjEsr;ykZr^E*wNz8FWFU(8d0|7j-vsS zfN%B~Vr~Bl%ekr+8xePt@JPIL0^m_1BgEdl2mNn`9|F@Pz<8W^)016!*drWSlHJ63Q@pR%gxW!#gnn@1jlGi>cAn2>FDLE&*PJJ zK-`onI56CARQJ%6K_nEkOR96^kxGp$Jgjf$28b?fgbzG5%mF|u%9g~ggJCCBZAGlrUinX+lDxiWwhFNvsIe4+)Jb9#JR)_ zsIB+qGXt$9lX3tXLY$gdsik3j#Ny3J?==LjoMZ)CwbT3=?lKcBdk#qT1kaV<;3%IJ z+2kn79GX3jC)i9oD|2%MC{%eixC*}a2YoXlP63nB!ggr6J*K7nxpF?}e`Eo9Uu-@i zFF|i2q8tXNNq#$$o?6a6%G!P_a=AiK%sTo~QB)9OzXix?QZK@|_quAtykt1z_96x#ZcAZsATx0nQ< z3K13MT1#@0Nx$odu{mCv8gyG)+OU?M4H;DR*=HSvYQz>*c)^A-S>#|`_7~FI4O#2HJJ8GE`uO6WQ~DO&H)kZ}m=*!Hu9S{$b+QCa|F zU64R}9MmcK;_&MV7iS&NV02*++YNlkM=4xrSQAkMe4Ub-MFADxl)3uC?%m(-R+}LA z>FjC5>V7p8BzY%LJCw}ltbw-xD+Om4=&^LKp8kS9MTtKniyO=@^oPiLxBjnJ<_jmh z(ZyPKbh_et0CBSP1AM)slr6LauXJPastK`rE&3t&jPZokk&j&%7KtG!3~fD1%(4+` zNDrNOQZLvhh7a=uTv8JP_|0&}t-=9i)A}fDb{1Jh6BXUv>)uiLhJ)nkA~kZ!Y9qCEdn9Z)R>hnN zQe#C^)gyE;tz~v^hUOvpK79%%F!=gJiqJkt>u=#mv*is=6a{y5^+nr>&E?584$cN! zZ^!{2MM*HxX7<1*TT(D4y$GGbIvQ*n6tTx4zP6Mt!XhBB2TAU$1x`V|&_>_=L|X@1 zYWO?d#JJZGf@{U96y+D#uQXY&413Q(d1_>#GPr3wjg0 zw&xfvT>rc7=DFh+>>me+05VcMHflmRG@(Lpi7|C!Xc)Xeui55B2<4t#*KcqE+B?r# zbk?NNJzJwLQ1i4NvvKml^CP*bXVPIQSps>m8RFF=e(z>@bZpOmbCAB4Mb8?ftY!LW zlPXVQ8NPP}#$GQ;=NnK=l*=?G9)O{nE>YzeksWuYBI3Sy4cHzqr3Cqsn$xRO(zm)b z>3LW+amFt1?F}Q+XFa8JG=x#^s7m#bqHif3CC4f{ZOsKiW03+871f&5&~6nbjH0s5=Plv41nPSsI|sLZAUNMI*r0VWq%6ePN3rSbvs z2uOG)T3223uTA+6e9_xP3&v`+fRCdVAWf!`1gXpPbH(X@eNEF037U@f zgQ_H@!Zusfk(nGAsn)09YJzKX)O2JG-iZwTJwUEXf<4+MnDxdOCRr6- z!H;-1AOM;Jw$9ssD#XgYsi}rd^z7;X|NGk7QJ?(xnkWDN`-tigVr?iWW6wsC;%0HQ zA#ntYhYxsxoX)g^&QwH#@e1ecER9aLdlP4e=@E%5Bts|GcWZ85vH0ddbyY*NNnKve zxDfTiD2vF9TW&r3rLyFUBkja~>J{I7XTecxhOLyn;YzyLj(>#n`q!8ZHVBsOHvifz z2N8Fg&-!ouDNeyfZp6+(mnbp2sn2@;-*XEs74fTxW+G-9jzv=r~ZcD)19$(ZL(ea*c)j4w<4RrLh^u5WM3bZB3yja#99|9x#l%U1rK zp(habV|$ZE#-}q^BD1zpCYLUWOuIUcKG0iwjMTX_r@8)zS3Hp!Qr1R6cbH^M{f?W;bdY{vH$&uazqg_;>)yOPS%PU zcz|*W!70>>c!qX;UNTYv@-^mWz2fEn#zJGQ3e?&5&`P|ka}9_Xj`*VcEF^v&gOMMs z5umSyd~e~{2_pJX7q@kZQa-Oj#gLoqz8GiMvs4Sr>FD2jI`9Qq zQ6Ye$C5>2vl z6fX8lLOAJ3y`U!nF*os_E>8kAxD#x7!Uan_s!L^%*I6@iIFC}E5$)$2`BRYHsIg}c zmP8?Kijb>!wHmqPq;1@eteSI1wf-Cn#>vC(*np0Eo&}$;6;NxSTa5+N4fUkhJ#~=v zAW2}HPhJDF$CQ_pN1sljCn%G3tZIq&O1JItrej5CiC4QZw=Ievf(*ll@`JD! z`!vX~bCwM3BYa0f?MU{~`M;}bKcQ9h`)xT*I9aDOZ0fsKethTkF>TRsfcV?9KixOH znk5lj3#V``cyw;Uj0h6A?aFrU&?WJ~7r&S!6?Zn`%4Z}x42T#9g%x+(8haZ5=O*_%?P{X}B@H%Gj zSpQmFgV6%DeMMqffku&;Q7`*p-xd9?jEstT9kGXFh?}YET1wXl>)Gj5t^T!70}UP_ zF0%GC11f?;_f_Xz0=$JwZh&SA=JO3v-}Cq32m#pEB|KrNgE{_-AFhVK@h`` zZLof0$nSSD0D%iWod$Grs@E2X)xkd)Y!!2&^gpnY=&8omC)}`n&DS#h=g>xrP|dI@ zCgI5m;BIP}E8O^`nHS@j%bn-Z!=G?r-Yzk>XiPqdX^qn&6Dn%nZKR3^#ErFU=+`i0 z2%8v#qJ8@EZ5Ts!VIOItSJ(OyryYj7{! zvt7XsekH#hIei6e{OfJe^oZzV)xtU)vAwA;A?XcaJGA9yU^@UB;bh~{&T(AC)O9Ix z8-w6T{qmA&QawFZoFxzFzDrU@SVmKc^rkrVg74Ef?+&l5SIeGjp*;ZnNH-@V3_$Rc zDg>Od4nO{ivltP&Mlp|dC9wQhBBEH@uM$m=26nIdeIN&iHJi{izp<*uhmPEl1$=rE zWh|um)~3)VJXq&NO&Oy{A1{SQLlvd8Li4T|W4|?;@s|2_2wRV;D+E1hX^Tpb_($n& z#x?!;3KE{j^x!DO=uu$$Cz-c7E&$&z5stU?7*s7J@idleQe6QDozEU!^M9DPpT-y8 z;sxKi(D&U9Gu#*bV(uM`bCc8+#f5XS(m&=AW~;rgH+TTH3_(oNp6n5x_AJbGt{ZEM zv~`9T1n41JI#_q*Fc|!oG#%7gU4*2b0MwKO%{H}=!I(vxIk?V;Hl+(47j=shCE`YJ4ABK3G?rnus2K&2#TGGo%@Irns0Wvd8 z=Xec-u7+2GQ$ik`-HsI1N>Gs;R#pC2*rdB#i`XMwd+nYfg}Ag`M~)E`cJNOqRFwKo zI6ynJ%Jo`+hHf1Yst3mBj#LlulzeT%GYoz~(=(Nte4E6OMPym*{l3%w)uE%Um@RiM zS~ucsBp*j4nh^O7Tnc_>t?2;;E# zN-v>4>%}egu@pO>TLN1Gns2)CFCm9wG?3L^r=q8oQ5E%0>D~%?<*)btK41P>KMNYF zI?9mYdU%2F40cNP3WPGR7^R@ofTLz8x;Zdt|7l+J*porHOPQq;kf6@W7?d219#&$7 zT`mhrs3{lAINyRD#p9wpOn=BvEs~`w*4X#NOvKnxWlsw&sh^m-$j(mz^V*7Ofxbv| z_8jl8R8pN7~U_&d|7S$yD9~K5` zexn4;Dicc+Qnn{=4J4(iyIh~4|AYQC?%Fq|zYzF^#E;SrUST}2)FQrN_%hNgE=)M{ zSC{w%P3P-_XOukND*yFqxS*qd6fc(N zTm7{0bH<%sBY6QceTfJ;NC{05|9*X4rr)$9n2i+dl+#(;vQSnscGsjeKf|NhA^LDl zQ2l~V+ga5MK(j$OSN*f^berXtT@#QJjVEQt3i*mUh%^nYf+FxfPq`))qYNom%(5F6 zPIdY1l{)@&hJVDkuNql-*Il259L0JfrP*spj!N9EEqdD!eCEYEuNjV@zv6AAJ*o@x zyo*#bKc4lxUf0+0FtXJ+#cLz=*guMbJcTY!fGH-Ety3?QrT9psdzY1lFQsfC+`6^p z)SOu}&}&{^i!mutSm>Pm#Tu)owllT9fNr8Jvh?5lQOh)OaW1~!*$?>CK)-yXO(UIT z+uiDQeSM{j%N>>h4yf0DMU#EEGExBB$Ey${0}DPu4ZEHoJ@h63fHi2m^2|rn1K{r- z-ZFcn;u$m2B@t7xKh(NiyFE@poZ`pd$YNR8#pt`Tgqzwh=6g>ZEv=^I*A|zJjZtl1 zE60v4G2iuBov#(oF*OSV*_{+e+^qs|;qvbEWg>a&ec5m-%eY#CoZ%4+ODDfc?!4TA z;@N-B$&*_#BjlA>|3>+%ofLsNlszpkudeKXuCk*G*v10|!&fS>#%P!0O78#daVL>a zp7=8qC<+)m(WCw(kmXPByX7}ti{N~GzbLl0y($@o7I#Lc+6F3ketw_0*pT|9s9c0} zXlW&j-s7CP?)Dr6T}Y;(ng~b}1w70J-|#c{D$EzgxL77jZxJya@9$fYZVQ*Hzf;V9 z)3BL<-NVvvLsX~9YXMOzY!kRY)%(s(O+0?SlnDo^Ka-K-9;A@7HjXSg-g8Cjcao(Y@{ zHJQR(NB=6kpwK>WSQ?KO zUE!}8FZ4Zp;}&=8`~))t;n_$C8ON2(#)z_4f}A3FJfB&0B$f{t4PZodD(8hS6u?ErRhb`ER~nu~y9 z3)kDpXOI3ZrOR?*dXe-KD`Cr3&;$ zWFUB2aRP>BSe2m2m1feN(OiN^R6WzkKFT}|?f7rQ)RCcv;b&#v!nVJTA&terZa05l zTh^F~;Tz!p);rlrjzp6*rF!XY={Va|0vBC4#nu1z?XjtE4HTg4p0A0XY!yy5L~LRNda= z0za2PrD1GIy|&4f-%=u#+$BOPC`s%`=cl8JKoXHmv5b#3a6W!({!;w=lKC@v zju(@mP)u?PMM;~lVI*pCtUOnZQP6A&*zdNe_WNtVg@3na!DbDRFAr?WuwsY_a15Z> z?5auASSgKULlOO98`VeOwm==x5JY)fG6%~6M?9aOigxS4*#R6Riv`BG0pN;Cbl360 zYNIBF!rE$gAWRtq0NP)67b8xkR~aJ3ewiC!NC4F4-72PGrDGrcFWV$_9W$D*POILM z1Wci(fBzq(+>^oCcrwhrQnU)f11JT7;$C%bUcXP235;qBXScV4VV)SGb9Z`LpD*5r zpS1u>covaHYbkMBDCinEprw|Yi=dM}p+*d-hCNU(shdND`~KuPma0P!Yk|nFD)9C5 zRm2)^jF^NH385|I$rk4>H|Fzt;!CfBct}{loq<3ZAKPF4{X<^9GSXLzi*tJY6wYiq z)wB{11nCv+!n12yTYq(bV-2@RCv=ukS`^~4BYe~`jYkAk^1wrlm!&EJg$>BKNa*A+ zvpbn29}}%0U%nbJKVpCaqWY1gb;M+qBR)HVd{VhtQ2|krJxm~^H>J0jq|Nl@UR@1@(Xo&`nOJI5r6HkoY(v&vzNk7*?C?!R8^hI+{!rQdmLP*hE z9oe%CF;8S?P`dz|M52k|Fc_sZ*gGj3YBhDyJB=O4+T)9Hv@fOWX)LY|izkKG~BPJ^X?xY3XoW zuI0a#LW&xtO$8GyWZH0K&SDWiO`nMgYbNIhnz-F!0mQF3%C0^YN^`Z``L7dq(P0S% z-stfR$!6|3aSQpKIJe>4TlYl(FRN&Q9b*0S9cl}r=zF)if2H8LAJSPJBLs>}CNpDM zgf9=&g80?dM~H+&bCSHVsrjP+K7MBC{o&;qk)(e0q&IL3#92j6!&=tRAcH=;P^Z41 zNRtDBzCS~VsdE6JHqC2mpCBdDW|R$+9y6N2GmfA@61J$zE4jC2wuR?be164drA#xo z!}q&Ex)=M^zHtBIaRkvST*fFtp?DL1eP{)1h~=JWcZX?t-hDL3c7>M3isr8jt-x~K zU?~5KeSH>JabVYOr|ouX$5T}2*at|PWw36$l$pKvXT^`};wYkeX zq%LA5bg4FSW<^K|!;_FhlTsP{wGeO57;9(Lzo|G&={lz9Q+#4|1(E2Didz{1lJ z;*9H{yw3HU5b|1oN^YF#-)_nlen3o=z7lYIq`rL~WnBrJu|I(~_?(`DgdF%qapjwO z_F1rmLF-)rl6p@x1%yL%5)Q|efO!w;8RC3Th^8PPA};VmaP_f&EP3QaO60!nWtbBk_=?8tEtoniu{q+*q7cl*Qdq}@PE znxBONLU~uyD0*d(uZ;joIl5r-ZFv2LO!?RMhn({M-`yCM)2eUT#SltsL$rnDbfs4x zkT*}s7f`woiu#Um&d1=xZ3qMu`bV&8U&*s`CT6YG*yaMYc~QYpRx=XE7821mn-J2p2X;N)&4^IK$l zQ-Msq!@6&UNJO`-oo_T_Tkye;jw4W6?7vjzkZz%_o)8Xo79r=V!$VYn_|vuF@)+ob zOD;+O|B3K658`J_yKMzqXVI7aIwhM@VYIhQx{2Kw13pArzY_l9 z^LoB*332NPhblC@md-QsIsQk&j+cXWfP>!2g}d0T_-D8@5mf#^3Doj>XgLR^^w-vd zLC1C}QRvivTU+A1Y2oeRwdhwlHWq->Yo|a(HxPQF7z_DG)S_jULLJ$frM7cnm4vMlQjg- zN<-gxPWXwRtn2!=G{paQAvoo)pG1|=eb_A8Hh85qW;QlX>8{*EJ`m;?wmDgnu6oxO z_e@()2~VCDy)@HK`d&QZ+i$+n-ADo|V7sB~-m*=uq}Y3wcLD>-(u9L78{C*{;hYvz=Bll-{IQDJlS|K{P+ zx`Vjs^MsiC5rFfg%Uk@~3T5XMw}PY%u0M%4oceK7#&|Z?4?UB%`U%yk3D;qru-5C| zOpenh-Hr7i=jhHg{*E^=9iz8^ux{*>G}H*B_;cq3%C89q!~nUVV#3RJsjt4w2iFFC zW?-fd=_+U^ho~EADu@4!fAJfDg=+%t6drpmM8YbN4GgjhLwUT=uv1P)le#x|+-C*Q z@!DJ54|iwZymF^EX!=KCR9n#4C7G+*Hl@K^uUCTvR?~UORPNDxT- zoa#1XV>;9V73#uSwk>Uk)h$4nfb*A{tWl$DXfp~eNVf;kk@gz=Shb(AmVXaT(%mk!Ve@li9loTe8Ce0z$!n< z3Z8?dI{>dTF1^!iyku{I@!OX(w>-c+z+B))lC(m|8z9w^Q{yrLvz)6Q(_hek(H1>ODhR|;^S;DZV4*;@0mC7Zs*dy zGEk*9w(gxOn-c(n#gtG&<3B5b zMy88VNpe0n(h})DUSnROq}Bo3?`JLtXi@9XODE?Lx%r3#J$bEiV^RtGbF|BVXR|JD z2KpaDQy^PRNNKBjzvcadLFyAHov>SFPre znW|)f1RY0~9D#p{ao)NkzttlVA*_5Rk-9PxZLK7BdH$!-TL=zrp;8sBFMtY%cI^}1 zc_+hvmFdI!GE~kk79vcb^EnlLm|w1crbiz@z7g(;D0s&)Qv;xsY+=4=P*KtXImabz z8T(x}WmBj*urL;&3TZe-@rW<<^si$*gccLrSm5#>o@c3F)~VU#f)Uo+oN+euR3Aw- z%hr-&=j}IBYz<{eHkKhCZ71j%hUh1gh>v~i zbTau;Vs&B3W=GdMc6XY9>`Vt?1pM@Sl1s^^a7U=-Euc95JbkIb4|^8btfbm{N>dz&Wr z|FA#LtaVndQJ??B;rjUh|NsB+VC^+rK?VQs3*Ay_73sUYr9~`H3cBNyZY3Gn8#4r! z&;QR9Rth`{rztKwIV)*?s4+#mGivH#$2ad_pMrH!UNK*4yRT zQ8DpWx^L55Ho8%g`Z;r(P4h7WUTNd>lG3=Hw^=X+8GDP+j>B8v4-#`$e6R9;K^x>jQi2x8YaHV9t}Gw~v(XVZY51h=B!>^K5gPls5}* za_j#e>}i|Znl0B84*qiy3jyK3f}|hLspjIa?}~MiIYIb(LQ-36s$HB#zL;dmTk`t| z4BZjhfIFLmCy|3aTTLx$UiO523xJJeuvFTKvk%9SUbb@g;rsj^6Y9#nWh_i3d7TPp zqwm{6-E|j@m0hj}>Jp+vAy1xkn|tZZ%>c<4Kuu6al(OPVgzN3_UZhXZ5XL633Nf!V z$X>g@F=&8rgDULL2zmxPK%j&yOx)w5Z~$0rz<+=0J_Dl0H&#lKw(YJoh&9CzwA%DG zEHICgobl&#%iW7`axW0b;aQR=UpLt}*SD4UufqzVj=KIHEQ#jd`u-e+&@JOEe*Iu9 zXBwnZcy5DgP&0f+301u^vaZ)P!XVid1^`OHSUutnP(Q~HQ!Ee9S7OAC?}v`CIgI`RGs)s-vXJ0`E? z;^)p63Xe6eIoZ&#&WVN8JSXg7P6VQ%30fhxGBO;W(K`dYPdvcHlXs%%3f1cb0BPs} z#}S%MRf;~tgw_utawpWkTr-d&Hi^YZGk@aNaT-${Z2LT{H|^R1lQps9UR=oFd9gBb zs~ha%BoU62qf=a6+6;a+ijxO`iD`-5LVx_C1?rsvsP$!8o|)zhW-Gv11d9QgR46bZ z)59hjfLQwT^lpNrZHx}0vCJI3!nguB7tsE}T!*(U#+-gRi(>?zvNNxkmA>cNQ z4cuwt_6Jv&LJJZ(E}yURLTt28R&8tEIF+amw2lpe2Hj+xCrkTm3VYC9D>#~%_{3Qc z#R@_hrx;w_d}@1Mf&c&QNkIj2HnrNAg&3Y&ytK7mDSnPw0qPsZKB6R6ODX{#Ypy*9 zN_xCjqq`2atdYMM64QKVq1lMgtu(P=Xeu*-Z6Ehl3L=UoH7+0Iy93mis=v!_3F<~V z+GRVB&(m9KUS+SAqBUKq02`I~m(_N)ys6(L;@(80Go{HLoB|C$5GM!R45Y(_Sc8(3 zmEtEgAf3_Qlf=Ka;nzY>0jL)sOe0C1>g#(ab5d@G1R-o){zVJW5=ZXK4WNsfdNgbK-^>>`LgnDV@ z%=8fT-6FU@_Vs(#u1P>VED5Cu9?u3*2OUnnkQYdf8TUi5*q69^9JE7N zssx^A;ISkQ1&u=r##9Rp1OdMxPgdM*>k2s&wewuY^rrq}3%pf4(J&Ba55B(`#3S6L z4>4WnO>U*-%yUh{e{@sL!Xw+Dot1T;l3yNp`2@p{Uyvhq3j3?pzB&g2{fN3@eU(1v z)}QyLKGZ*-4W|6~ZOUaQK6xne)PSv1KmSX&?QxB0%t;TkKhxQlG3q3WYzE(G+*MP; zZ;$Gy>pAN`raMTg6hp z_XDf@UtqHHW6U;+=DcB4p@NSJ0*BASlzTJ1oz0SPm78A{-s7BG?BGU;HFOQEQW4`n z(1=}s{lFpkMJ$WtkDiDaHW|yjKXDWDQ{MvKji#ytd4jp(o94u7ep6O_IB7h#Fj`Su zvqtdb!L61#84V8D|NoQQE2I(gb7MV1vh8;?8SV;3Dp$LOnvduNg^yV(F4LYmd&bZI z*pz-QQggcSPG&!*F{uhg-pMZDKMcUG#o;fhAR-`o+d6S|_3hVAQl99n)Y~bzH?Z6b zkPXVl%tDWA`Tg`^e!jN*ch`Xy?lN`pTbf9A|26502z(OBspcNd5E>K)Tz-5ZK7-_+ z@{GFYpuMtDl3%NvK&tz2wYDK7%~UoAn77itz_kk2cEeP_fr#c}L&vFjNlKN?I+~BJ zc-r#^x!k>Jx6%VFY+SvVfCov&N)P0iFzdsJE<7CB_%N|%VKBat>dU0H5r^H1t|x`= z_j^@7pba+|Enj55Y^$rsY4ieR|22L0V2f>u+7wo%4a%nI+rarB1>)ric~VgMf?d- ze^xRaa%M;7o>Qqe9qZPnGDesoa2Hg18jU|nBpbnv$|3RP!407NRGRLYJM-AL_|H;k z@i2etT21H#?v(zKxXqW9WJWPkpWv~~Q+=VUwJ&rRm8f*UjdO&qJVBm2TLj{_8R=U7XEeb7(6;HEB2gbV_;B?P(%zO+mFht(I>ziIkyptU|d`jy^g zlYL3ENytOM7JLi$RG>hJjI~==krRW_VKm?%;IFTw(gvmcEXVop+>Mhl z#}8)wdlp&{@z{B>8Qc&mv;Xz&neD*s&9X>!;_#?TW46RXxu$dh<1#fF^QWmIcWK;{ zI-z(8shr~mYQV`phV18a-^wa}+R#{`pO_C&8xEJjxJ087-el8mFn{46^%C^Cp*6&3+Fi}Sjz^QgV>DCi z+);SuF{uhDy!qP;Jagg3Dvq&XEbNx>S{N>wfXrZF&)d&H+2cK2FY=LY&0tuZA2?gc zspvw=&ey=R!cYxG4BJovc=xiK7-Rls1f7yy1WD6}*Ysnij~_$}h)2gjiw_T!Um+qd zFrMhFOEijXq_AAbT8)z>06MOsrXMwN!gr#}PsnrZk{uBgC11fT7{mq;Z z-tuDG(d<3axxPfd9n5k98`2^+SZf6>Z(L?CAKeql*Ntz5Br{?GH=SKx8da4OdWUJc zslJlH$%jLaVnpW5&HeG_HF1dQoCN`fv9Jc1JQx*K)mFu1v#-3s&<)x|N)$ z%nFrkI44sRGLUr4&ye8xkYtlnU|`!w2d9q(4_;VN{d^1!PqCH#{et+EOf(7z-tzv* zmCKST!er`cwbEPidbsV^*o$Q=qMLyltE1}%%BzYdf~FRNJHsZfIL^|D+W$HdKZ=&@ zzE#Ty@dC}M18s@^Mpx{iZ%=92WlBf1dloXOIA;;Z=Z#kNy<&T=S6}!@n1h9`@rGw02o!HXI$xVJOU){@jyV=+CEgxNgHG z-_pLdfz@v3-=R*y{dGKZXUY9o=EMzCCwi^IDOB|Gv0wxv)_!a_BO2z0h?lddsOar2 zY`mOY6xVnU&y;Mya2w$O4g9G!3#U>{sjU#r6D8V2BPD zUc!$iLI3@Sx2i>!IyIewWtl_&y#KYTqW}+|HUC$S8g@f2#k%XWxsZ*~#LDM9_06A) zdNR>@F(LqRBcf6Vv0$G5Jb3+hQ|I%P-QHfhKbMi_4ey@8%L+K3%+}zAroOQ`Y!+$8 z=lbB310uA=0UEVs!9<}!{NsX0{7Fm9sC5 zdONLrnqPoJf#RLz#{XJnVj@S$_53vo24~Y!p9k+*d;@e-wG+D6O|r$Lw*6EmJUDTl zoi1iI636$9)~xJjIhgp*fn+kr%!D%`UEcr0vaq*O6VTp&T+(>W~jf7jojCf0Vo@vB)dtZvHmH?{y>74vdoH=Sx_cxa`o;`>eyZ2eRo zN`gWo91N5EpzYB(4sj5qrrNlmP3n)1* z9w$7ckA;?(4eh^JgAh2C&lkiirN z?4S5f+vVVA;no`^)U$((Y4Bx1gDk8Io}`9a*I0??_>(LRw1A`Hu&@w{phZC!&nN#; zmr5YH=rmV83b5kbR&{ek9I07~OkU)^MCtHrTfm0JeMtsy@ww?1*lF(QRPJ9?>@g4n z=OGp2$pF1*XC9rZR+ZXogkH%&3YHYQk&2&h05@FC#gTq{H>cn*YDN8eG;F^~ac%ju z_FufT_~V;PE3ArpHk0?-EQ=S~Cnik8Z4R;%l!sY;rARtB7V$ADT5a7&sqDe)FTCq= z{8={c!*e;uonPSO6=oj)8zH%wTeZDSB<;>yFayW5Y0_b4>==9%=ty~c*Ma^^0R-Kb z-G%|(u69VijYp53PIb;n7?)MTpenOm7?70M^eYh!tLZbV6D=iaH)?bIa>o&bFc_j^ zK<=(x&PD8qq{kfngG%e#&~pK&2qnO(F55W%5p)W@mns?}Vr#wDA|<(xnuAbFXcQ&Y;_N*)^?O&@?LRb6Ab4c`jk+)`yAIW$BZrrBfp}o{Rs_;2`I7Wk{e&n#jRdT&Wr1rdD7tTKS?v&rE+5X z+y>W{$QA<;wGr!RAPZYPgEU0EI%vR0MzuGR6hY_Adkc65*ZghY;G?D)vBBzyotvfX z^41P(pj!M*YN}%zK}pN2C|opkk#PQ!aqsl++>C{ZF^NHB0{lMjQL*D>N|f z+8ofe5~$X%Kpo_8g8|5ZmbT?FisbB(9a$U@z#;$CXeyZp;o5UasYnlIX_7F{Rp2b~ z!>g9%GwFLFw>P98W$b9NMURvwt46V8}RezpGLnp?|<2>k5}u8 z!VR<}e>l2e)8>j}m!G5(;*kPL?M-aLWeO|I4yn@yU>U!)$saD=#hi-dK5k}ZoO=z1 z$XqQHG5E+pPR|B~5`h{Y?3kNl$oITi=f=UL?J6KUI8`2k?bZ$uYMS;L0#NTmnhVVP zA)Y-YuZ{f^=^}P4eGDL*mhZQhGe(*m(0#>9017qF&=*+@wR4Js@6v66mb=xIgm6+W zy>Z9w_%$Sy*rXUr=O6w>c&t%RtN!LyEZ?Yi)XIUOMt<7UH@2uz?V#GGFIu1iHr71i$PBoQo{0L)ToP@sp0PLe+WvcJj=zG zh2i_Je~+*Xgw%yY-b?C5H=De>sAnm55fVO5H9FKl07D#qA)rh9_e=;~c!W6W@&8oi z`@yF{d=LK?+gVKzrcUtl7{_|PxXV2CWeFHKp3GD3EU+-Sx0w{q^aSjAqB}QlK($lV z@en+}{<6oPfH`;V!K5V3Ufql`$}e3NZz!XAPDYvsrzQlo?Y$Gg?seS9gw+O;!Sx6-p8RW`4UOc#ves!?VQHX5!W5WjU6xU?|4&Jj=K!KMvB8C!~;4 zB4=s-s{IN;U8Q~OZ}U4aWsc6bB{>37=gqc>U>{`qCa7F5KWGZ748PoP)D8gzmzKSM zmil0(g{5D+&=HkU-DHQlxp}z|JPBxMg{_QBVdl4HH>Y6W1ZI2{)op9m3-ZuhA5O^K zT%V3R>*rXuZJjO?Il&9j09nHTL`b#B?d@GFse2WyDbmsZO7Uo+eqw%rZt(y1w>*L2 zp#eGs^l_~b?uXJPo!&QPI1ND`nR{Z4tW=bp@$ z34ef-(3Ho3z_ko`Zt9pC-YMz7zX6|!n67mj@3e^=2!nXvQ|@~5(}*GHAVE{xt|+l= zSg*0+uIYKqI{;lkqQ98b*Qh?Mk|4mKt3vwrXQd!;us$gqc|@wpXni{(NeClh`%V22 zG`t8tZhnhI7A)#uM>>4O3Bg4h;t`(u$5NJ7^<&@b3EQB^BIcg*;IU%hd^fi zcfJNxCv)snbi%-T_<`ctZjbH8C4ag)HBLWWG%^x{_}_R8>|y1)5?MpwDjrKGfD?X= z3Ao2JS{7Ys7JMlK`;_t(0pPy?gC!)elCCfFarZV{=Cc?*OhbY=w=`F#Q#x|ws$_Z3c3~x-ZyV2L!NxW6Z(Yf9J>588p=YUSvQzcn#t(QXvaw}-1d4xv-Gn8K+3j;DDp{#$kzu3QP< zb#jM?6qVKIVL~L4Gb3_Maa>#u)qV&^N{7z3 zT3;w|WjJl!H^rr?&SRV0aLszu8=-@!jw>EsK8}=Gs^a6Kgmpcu9J%$0bk686)v-z3 z(6Zgg|NPJDi4i-iWahM_=!(r>QrF7L8#U zKoPzupbi}YPf4TivsWXsGJRfk;}{^!5_VPi@1T|htcaf(v7Wg^{a<1wA0up&1!!*)}p&&Cu;F%MI?1g<8;R|o(G!0M1&dg4%MGm4&kkF;oD47}i!`+S2rRkwucE~Lqm~(ZN zKwTDih_WEVK*R-EhtA$W<|)7cPXf0~{hJ1sf=}d>L;iJOTX#DN$2*iqN+~%g^N14h zt$S1sz3ibM_{)#IRYhi}o!}f=zx`o#}=&_*={vubc_qr!&(CUum1rA z$k_sZ*4$iM)N2302X#yLE%jta1kDXf#B>GlvqTezCd-9M0@x>bv6UpnvU_x31?=Fc z6a+nv`77Kim#Ih2TM2wp!PP#vSAVMz&inK=Uk;?!DfHgQCNxTa6Zt)<_vLTU@?vZ- z*Gy9Fmf|1eGtADgWk4qpj-dkIZ$!+gO0E;hMigeysT&EVp+jeu6m@SLluLP{Z1j2} zy2~{s-lyWgL#-4%`#Ql;pt>>30KGD2W1G0>aQv;MNxEl}{C1>8ns(qBi@B&?u&*0FLxw*%>P6tdF>ZAY>zoLN66P;?nLOUZ8HHT zf7dud4Fm()`BkW!=)I31zuqfv@t0umxVL^QsHvE&RO%4<2l-0rh}2JBLH9Hn!sUvb zzpume_PFN=p3&~SM2>3nEcPLDGgmmXL0h=~yo;y8SF)fgv~^!jWf#};)U5OPC;JS6 zPko%xq|swcaOu79mk*-%KZ$5DWD?!hwbyfI)?IQcqAHP}2Y?Oi1e`o$Z77K<8zNUz z_dPm7wBeGvJg|kgvB&Db{-GSlO=03RZ{9n|fB*mg{0YpRT;uNK6h!&)99;`lL%iJP zUq1at(VzeT0|5>A16cWtG+SQ(42M4e|3u70`wE^ZIg~qi=aN>Ugn*l~{^1#d&wLm@ zK$uN_Op;i4FE9W4JYW2zill*9hC~&0{gl2|r{Sn*QvdwZKkvRXQ4cDxZ+mPy%WPZ@ z!>2&7PS0Ip>bQLV5tH$oe!&k>R?A}O3@92I#Uc6B;iMS#l)<>3=S~liSzf`bt@F=JEa5Giv^Dp0E3Y4f*%uQ4$6n344%b zvcUS!uSg&S3@z-`d9pF6x0(NL9+b*Muq!adez_hxlIyCl1rmm)*4hbC;o2EhhD>Pd z(cTCWw4=0GP`p@zV>PX@NAhVJ`e|{9v!wV$ac!X<@rFyLyI^?xk#$BB2kX2d3`^P6 zIOvtCBubbmF^ZoY>=q)-jsE*Rf2hZ&f7(^bYARAJOD^y=N+KLoRzvRegZB_Z2r^fFiZ>JxqREPCA>GHz zoNWOW$OzYbE?6#<6k4x+JU}b-=)Yoz?m1~ z)bB40H4Gf`@(1%tYA{SP2_P}uzNq>lNZ>@|QUwQF-Ljemv3hqRvmfKNDuH_GkEJ(B z$1#9YQcvJP+0FCA8AjEwRY`{kL|~OsngDUPCTm_{qwQm?pjt~MT;H=AqZ(=I<05Be zXeNjOzAIV$@RH{#2w=LRjnP-JPX*m`L2iZB13H0*ppHYgQ%}W) z_#{Z-^yEqzLCA&cM_-P@*aKBF%g&|*Zd$I*jwh|hpN=FAQD|0}yxH4K6Ha7PPR1_v ztLeKew-sGbC4Dd!izl?R3hzE~5g=$-9KKdOeo)o|x-fB#AjNhH%Y7Or6cyeGm(~d7 z6Drj(y>6`)1R=8$se5{}6~Yhwau%v+SRXx~?uEau55T?FV0s+%E}vC5c};t-;_w_Z zsm^I1(ZQWAEWUJUksCuZ1c&GG%C8pV*Cy0O=0`6I@fZe?c^3{0@T#ts6z0P6`?0_O z?7d^T-xqmBaxf=Wm8i8@VRY*G!w5Y(2;V zUx-+^zkAYrjkBgmEZqJk?<>1=#56qd&czg- z@6kil)!}tDAySeX!&;o_CwwylMLayw(6LKQU1|{GeDwzS74dR+Ro=X`Sudl1z^1Gy z^yxjRzby}LjCa-{T+U_R3B|ST<1X*Ykk}2d|AiYqcuAd`zGhVv25C&jeo*1`JUekT2Y z>sRM4&iYybi{oM?aCC}r`Np5XPv(1m<%k1TSyMu5T zn#&=vtQ@QHD;eJ4!ST(wW>?5S^${jR-9$7z@5KSfEx9uWtnQ>F{GJAdnZr$qr{yGDYf7xMsezCDu> z1=Zx9*8#ok!>J!f4>Ei(0k0y>cG8Y9D+tKSgL&-X+&PlHs5$7!dx-NYiCCUlGM-qu z%)!*DYDOGfm^m-_$$EG9&IvxE{>%Xw@vrQjnAzAxMmL{mpe$~K@D3zZR*oZ4A3t+6 zRn-MTMAo3ow(O~q#W29j5VWiBh@9n1fSzcA^Nd~;h0Co1Wab&swmlSta26WzFQsy( z87|KX3tc^li}Us!gN&Yz%?!@Hpnhtm0I?xJcwj zpE93u)>O}bqP$^KruTd!4l%agS_a^3owBQL=5gKA-8!I=QsYmJoBgf>su1*^f>{m-!3(7zn>9u)mFuC(&EynH()}VwO+a{PAN4dh zgwcNV;CsZ^B{LY6nfeb?l*#9-q?iY$TuKgwU<%&&s`jL|1RJ>&7uF#d! zi_4z-~6Z-8IP za|Hd6>B0mN;M!}A#kSpZB?L0k%Rr{;!#QW^Dy+#${Ho31cVAjJb$OnYX{|4M(S$7w zHGK}+Q#g^HAI3c)^6m%!_RF+X9jq5M5g_0mBc{Y@Jzjc&V0$rBwGsGqKD)_C_$n-} zgtw4($OU{sO;nKRX&w)yf`67#(WSdM%S6z=m7Li!+Oy#sLDP*J-Lz}vxX|4BuwX7W zY#O5do#_pCU~6Ztsh3*g?G@K?-FO{!dt1S^bg##%WAhkUgXOi;Gb%VGBcW6@SMHQu zx38F9tw$n1?qVpqHi+iu=?ws<802E8H9x|YH|tTs5nl-l<&%woo(j{2n&CT9Fcw8Vpzj^ZD&?ItXO2AzAU614THjY4CIPB1`)S1^sIZ>BRfSY zlyDDx(Q3o$j?ZR*V=i5=FweZ@_>9VwqUeeU-n``#pbm_Tw|fnRN5+ykn}tdAn-0h{ zW2Ug?^(dCY{hd;?^hMTX0YvL7@ExJMk+`Y`Lpxmq5FZwQO@+X;fm#*!pa#8-+r_I| z1O)3A9XkeQHG;RA6Pn5|g2JnTA+mpY?!Yt zM)|h4CEni&&rza~Y03OIgjqWpFRhD%(9Y~x=PIm_6F9tr>@Q*gNsR^KKa~`RH?8l~g+``-8A}-&R8;m#V z;Y(}f;364gl;58HoM*Do$q@`+D{L{w7CI1dln+J7I zq2+x`LLLDprr*uOG@s;5jD%ic8@-~T6x55R0Y zq!-_MKHb4)IiRH2%??53y!K7uAf6_4#95Q*)9AjxVTaLTU#!#HsL4Qy!fQ(UY~AD+ zSK^tpq9!)%JQ;V=q|8v1mMt)15U(#h5Wiir_ z36A^{+}BfGmXD5Hc_zOKGs1vQpW1IZ$= zi=B!|e(Gmi=EcFq)Wlzn*f#AP`?a8wynZ%b#$3aD3cFR@9O);@!FviXNu(Ec4o}ME@7`6gg_IWEta8&r>CKQ8v#gEVnx$|kl!0eK1?a( znXAMnK`{?Z3rty_4Qa^qkGl)RPt*VLb(@ehI-xDdZuEN?9fL6!CA&y_0!u;s6heRu zx!CltJA-r*=+P>$?lWf2Z#6pPzJlB^Y&^9A`)=NInX)B)MCc`d|2B~Q34v8mmRs}x z{iK^V>3eJ55JnnSbPo0JoB#j+VT0L0{oh3)dtkCH?UzUZE5iG4EpAP@7C=d+?*Jv(mEPX4jDXz1!o}tro;}e9hBJLX3eQn87Yd-Zug`GVl8!;a*ib{- zcWDkB{5i%a?s9bX!NNBB`z!KRJJP6Y>|w3}zWk`}^|9@+7bo!3UyQ42mu!6rpUYwypdt==^<2Mnj-TNx z5hS<(v$T?kx`+~Jw3eqd2h8}((3V&+*g6tx zsoF<^XW()#UznD+%#KAH+81xHIXy`|Wh-xK7 zSO5S600xM#PzwKu$?0%l+!AuVZUijZMpJ%LsDeydt>~C?Jh>a z`9bso^labr)Bg+Wav~#{f7Zy>m#~f!g8%#`xP|#WhY>zuU}CtFD4$WI8t3!WKCu{g zG7HNBk?AlM5_BMEzx?L=Y|fy+UQSibfH!(^p{WqO0_3b=ykXg?eJ>XqQ-GK)SGaV< zrQtfIYwUVy{b3klT1Vw6oYrIUwY=f5sr5u0k0hSi!}C>C2gOEHNG>DLJZT?NuIUtf zbriX3q@q z27~R=ijta#zT1pEXTNL7PyjXBm;XQjfdi;(_Q%5Xw`1QYWl)y_VA}Wopa2`mV7M15 z_^8p;wiJ^VC2#UV@4T>%UIy( z761^mhMd$zwZIdYX~g#0}k$ro`&ou{A)L!h2_6tf=YA9~ObMN=qJ! z1xmXwDsnQQ`Y++8x8N|MdZAO5++dzXWU~z+@uY5(38oT9AYv^2UT08R`QkgQL zB_V(6c55yEIGCR%EAh2rTFKk^x2GI9_UnAr8DYY{fHu_gwtwi zI&#;K8b1lslRVccaQZpXx+d?EmS|}yaGkBF#pQ7W9xxL%uyFV=ltlYqcK;_{O_c6r z)pL%sAppw%hH}RA$}T_jD)Hh(*F<}M2lFK0cZ^m!%MGDW49cx;X2l0~g%Asn5VB62 zP42!BSyaZg?!cKW&~Nw8dy+sM#`eeMvpLt)Hy@HyozW}ebQ9@aDUj__VF6m!>E|uC zQk_J@rlq-bP2p$2F{9xej9dLklaEFmt z5V}D}&T<$9OYJ9*0NMOi=rZ<8qPFAw-s2?Dq!-UziXxEjS#5mep*5hy%-J}( z_Q)&wYVap%`b-Dyrpv!Ih@wEW0zBoYfX^GmEx)1a%mr*o%!YF%A_)bhC;;ju`?-|{ z)|ux{v=ork;&$%YCi}Em#h?HF{v~(d^kL~xKuI>LWz{nTCW4%HL=d*tR3v8{J8e|# zBuuB+Rg+Jkm#o0e6IFiUFuY>5J1-KKfAO*Opz-j{5E%otaO_#cZyy4W{Li#ZTP%_r zVmcgHRK32$U6N1F9B?3b8O(;}dA=ttGBTsC>>t0U2`n6w`0b`SSLkVarlIkaWjZ9` z(SHgOa`#v2qKgTHx2oxvaMOJD4p5QAUCO%DSduedhhw93$x&;*s2)IYo~!|DhnvRi zewMV$lWX$=@L!(V=bkhN4fvb4P)A1cdr=4XZBU({7Z?2%`I?ZoRN^e%c1;zQXCda6 zyHK6Rj(>mH%F3T&m8<5D;OTh;tIVwka_ifgZ-n%x5DiMBz#EylR&O~!SHsrlH?et* z%`4xZ3E^Of5q&ahxy-;>$fbwNa%96e-z!0O(apD~guFVco^4-V!Dmdy3xc{&^w;;N)sv^ztpe+Z7Jw6~MYD(k?K(#!vYqcYR~plB{B4w9E-;-i<%} za)ncI4ppMg0@M|4W!x9F#rkejpNStmyl zBp-zHke+an{G1_`IiY?Ege*TmzWB8BzlVQjHoAqLx=zQ?5q2mO}3#;L-ryJ=&Tdu(xuDhJ&gL!#a$K*;#J%3jM3Zdh)+^X?yP&1IZ} z{?+JaLsUVT*J^?Q*>J74-AA4pXMzXKMZ)&&wxRMz%R$ofR(-g~CS(XT!4sSP9aqRj zi;Rx;cF@?sXjoWJ&|KObnEHYq7AaAGzsq0xSVm}jG4kb)Isac0F6kps;{CcNI;$#u zi^V{DBTWl{jD=F_f=Re9JrQ=&W_(pk*DY~8A;dXDs`sn1-oj=L%$J+-kS_#-La~SUw#_QCb+W zrga0+$4G!z(?^j+iXmp@WZf$fKKzB6G4LPtTCak%plj#QCN43x|2yFRq;7m%sf<`| zpXO?kCl@c%=ewO&3p)Db4SB0aJ4)9B=q6++uv%^-yxb0>u%u!PIeX)D!`jRz=xER90y{E$0N*EM+ZGySxbjgWhO3nku0 zXI1|p=oMo=g^k8QmQY?rkR@mk5l`6_vqd*grB@*eH{iq|x>jKUd!Isdsf;}q*5*RM zk$P<#bt9$xvnVPY2%ez16SA~>L9|mTE>Hc{|F=Z`x-0w0aQrE{BNg%>pYHD^2 zvq2TsthKLE3j2q>Q}Z{jwulD(3SUf{Ew-n!&}N#-ja_7$(syzEn9ZS95o?f;fe&K_|^C=S+KYnAN3 zb_K5vGH1MxR*bZ$&o$sDf4HvrC?vzbf_TUi_R0Trj$HK&G3hp2GC#732DjwaW!?VP zw&_m?iDvqG3KlvqFqi|{j<)tP#?sel8_X+akBRFVDMRfs z+6T|K4{&&$xW8~zwE6sQ*&7gNB8~v36%w9!l7Ok+=29hz=Xj$(BrDeg?)>O+6NR40d`Anmdj?3w16-BwM|{XY&_`Tfbr@`*pJ*{7La zsava+D@r*Q9X*wOMB*1yPc~!|lu)3?4t|=8v zV!EsfAKjw3k`IplQR>1sEe%P1#0^ry$EZ#6ij8lE?3P}&6RbaC_p;*@CA%~%(Oqv5 zp`Vxj0!|Qmh3y42EGN<-&`jYMvoqecjJw0uj#D+s&k!9oD?R8|WBMLBu!p@?V~mh| z!spm`G!>s#<<2QaRm1As{#CsQz0{`Q606H6B_Qx=SRZgVpJ#;CGNZ93zRIct>aXln zK#4~<8#ed~NQ-=?F~+&$GF0m$a{%I0cklG^Ihl>$4|Q$3$PeTM1PzET*7qzL^BAca z3%wO^!!$eKEaUgDkwZk&5?O~sx�a=i)qUh5kQt(5w&*#kmw6 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

  • j_oHGH6cb2hQPmeDrf6 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%0DaC!z#X=d7-;3 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∈OMehY2wKZQ2H>#^-J(Ozwe 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 z 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